|
|
/*++
Copyright (c) 1990 Microsoft Corporation
Module Name:
smbcsrv.c
Abstract:
SMBus class driver service functions
Author:
Ken Reneris
Environment:
Notes:
Revision History:
--*/
#include "smbc.h"
VOID SmbCCheckAlarmDelete ( IN PSMBDATA Smb, IN PSMB_ALARM SmbAlarm );
#ifdef ALLOC_PRAGMA
#pragma alloc_text(PAGE,SmbCCheckAlarmDelete)
#pragma alloc_text(PAGE,SmbCRegisterAlarm)
#pragma alloc_text(PAGE,SmbCDeregisterAlarm)
#endif
UCHAR gHexDigits [] = "0123456789ABCDEF";
NTSTATUS SmbCRunAlarmMethodCompletionRoutine ( IN PDEVICE_OBJECT DeviceObject, IN PIRP Irp, IN PVOID Context ) { SmbPrint(SMB_ALARMS, ("SmbCRunAlarmMethodCompletionRoutine: Done running Control Method. Status=0x%08x\n", Irp->IoStatus.Status)); ExFreePool (Irp->AssociatedIrp.SystemBuffer); IoFreeIrp(Irp);
return STATUS_MORE_PROCESSING_REQUIRED; }
VOID SmbCRunAlarmMethod ( IN PSMB_CLASS SmbClass, IN UCHAR Address, IN USHORT Data ) /*++
Routine Description:
Run _Rxx for the alarm
--*/ { PIRP irp; PIO_STACK_LOCATION irpSp; PACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER inputBuffer;
SmbPrint(SMB_ALARMS, ("SmbCRunAlarmMethod: Running Control method _R%02x\n", Address)); inputBuffer = ExAllocatePoolWithTag ( NonPagedPool, sizeof (ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER), 'AbmS' ); if (!inputBuffer) { return; }
RtlZeroMemory( inputBuffer, sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER) ); inputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE; inputBuffer->MethodNameAsUlong = '00Q_'; inputBuffer->MethodName[2] = gHexDigits[ Address / 16]; inputBuffer->MethodName[3] = gHexDigits[ Address % 16]; inputBuffer->IntegerArgument = Data;
irp = IoAllocateIrp (SmbClass->LowerDeviceObject->StackSize, FALSE); if (!irp) { ExFreePool (inputBuffer); return; } irp->AssociatedIrp.SystemBuffer = inputBuffer;
ASSERT ((IOCTL_ACPI_ASYNC_EVAL_METHOD & 0x3) == METHOD_BUFFERED); irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION; irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
irpSp = IoGetNextIrpStackLocation( irp );
irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL; irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0; irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER); irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_ACPI_ASYNC_EVAL_METHOD;
irp->UserBuffer = NULL;
IoSetCompletionRoutine( irp, SmbCRunAlarmMethodCompletionRoutine, NULL, // No Context This just frees the IRP
TRUE, TRUE, TRUE );
IoCallDriver(SmbClass->LowerDeviceObject, irp);
}
VOID SmbClassAlarm ( IN PSMB_CLASS SmbClass, IN UCHAR Address, IN USHORT Data ) /*++
Routine Description:
Miniport has an alarm input
--*/ { PSMBDATA Smb; PSMB_ALARM SmbAlarm; PLIST_ENTRY Entry, NextEntry; BOOLEAN AlarmRegistered = FALSE;
Smb = CONTAINING_RECORD (SmbClass, SMBDATA, Class); ASSERT_DEVICE_LOCKED (Smb);
Entry = Smb->Alarms.Flink; while (Entry != &Smb->Alarms) { SmbAlarm = CONTAINING_RECORD (Entry, SMB_ALARM, Link);
//
// If notification is for this address, issue it
//
if (Address >= SmbAlarm->MinAddress && Address <= SmbAlarm->MaxAddress) {
//
// A driver has registered for this notification. Don't call the BIOS.
//
AlarmRegistered = TRUE;
//
// Raise reference count before calling notifcation function
//
SmbAlarm->Reference += 1; ASSERT (SmbAlarm->Reference != 0); SmbClassUnlockDevice (SmbClass);
//
// Issue notification
//
SmbAlarm->NotifyFunction (SmbAlarm->NotifyContext, Address, Data);
//
// Continue
//
SmbClassLockDevice (SmbClass); SmbAlarm->Reference -= 1; }
//
// Get next entry
//
NextEntry = Entry->Flink;
//
// If entry is pending delete, hand it to deleting thread
//
if (SmbAlarm->Flag & SMBC_ALARM_DELETE_PENDING) { SmbCCheckAlarmDelete (Smb, SmbAlarm);
}
//
// Move on
//
Entry = NextEntry; }
//
// If no one registered for this alarm, call the _Rxx control method
//
if (!AlarmRegistered) { SmbCRunAlarmMethod (SmbClass, Address, Data);
} }
VOID SmbCCheckAlarmDelete ( IN PSMBDATA Smb, IN PSMB_ALARM SmbAlarm ) { //
// If alarm structure is referenced, wait somemore
//
if (SmbAlarm->Reference) { return ; }
//
// Time to free it. Remove it from the notification list, clear
// the pending flag and set the event to let waiting threads know
// that some entry was removed
//
RemoveEntryList (&SmbAlarm->Link); SmbAlarm->Flag &= ~SMBC_ALARM_DELETE_PENDING; KeSetEvent (&Smb->AlarmEvent, 0, FALSE); }
NTSTATUS SmbCRegisterAlarm ( PSMBDATA Smb, PIRP Irp ) /*++
Routine Description:
Called to register for an alarm event
--*/ { PVOID LockPtr; PSMB_ALARM SmbAlarm, *Result; PSMB_REGISTER_ALARM RegAlarm; PIO_STACK_LOCATION IrpSp;
PAGED_CODE();
IrpSp = IoGetCurrentIrpStackLocation(Irp); if (ExGetPreviousMode() != KernelMode || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SMB_REGISTER_ALARM) || IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PSMB_ALARM) ) {
return STATUS_INVALID_PARAMETER; }
RegAlarm = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; SmbAlarm = ExAllocatePoolWithTag ( NonPagedPool, sizeof (SMB_ALARM), 'AbmS' );
if (!SmbAlarm) { return STATUS_INSUFFICIENT_RESOURCES; }
SmbAlarm->Flag = 0; SmbAlarm->Reference = 0; SmbAlarm->MinAddress = RegAlarm->MinAddress; SmbAlarm->MaxAddress = RegAlarm->MaxAddress; SmbAlarm->NotifyFunction = RegAlarm->NotifyFunction; SmbAlarm->NotifyContext = RegAlarm->NotifyContext;
//
// Add it to the alarm notification list
//
LockPtr = MmLockPagableCodeSection(SmbCRegisterAlarm); SmbClassLockDevice (&Smb->Class); InsertTailList (&Smb->Alarms, &SmbAlarm->Link); SmbClassUnlockDevice (&Smb->Class); MmUnlockPagableImageSection(LockPtr);
//
// Return value caller needs to deregister with
//
Result = (PSMB_ALARM *) Irp->UserBuffer; *Result = SmbAlarm; Irp->IoStatus.Information = sizeof(PSMB_ALARM);
return STATUS_SUCCESS; }
NTSTATUS SmbCDeregisterAlarm ( PSMBDATA Smb, PIRP Irp ) /*++
Routine Description:
Called to register for an alarm event
--*/ { PVOID LockPtr; PSMB_ALARM SmbAlarm; PIO_STACK_LOCATION IrpSp;
PAGED_CODE();
IrpSp = IoGetCurrentIrpStackLocation(Irp); if (ExGetPreviousMode() != KernelMode || IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PSMB_ALARM) ) { return STATUS_INVALID_PARAMETER; }
SmbAlarm = * (PSMB_ALARM *) IrpSp->Parameters.DeviceIoControl.Type3InputBuffer; LockPtr = MmLockPagableCodeSection(SmbCDeregisterAlarm); SmbClassLockDevice (&Smb->Class);
//
// Flag alarm structure as delete pending
//
SmbAlarm->Flag |= SMBC_ALARM_DELETE_PENDING;
//
// While delete is pending wait
//
while (SmbAlarm->Flag & SMBC_ALARM_DELETE_PENDING) {
//
// Issue bogus alarm to generate freeing
//
KeResetEvent (&Smb->AlarmEvent); SmbClassAlarm (&Smb->Class, 0xFF, 0);
//
// Wait for alarm structure to get freed, then check if it
// was ours
//
SmbClassUnlockDevice (&Smb->Class); KeWaitForSingleObject ( &Smb->AlarmEvent, Executive, KernelMode, FALSE, NULL );
SmbClassLockDevice (&Smb->Class); }
//
// It's been removed, free the memory
//
SmbClassUnlockDevice (&Smb->Class); MmUnlockPagableImageSection(LockPtr);
ExFreePool (SmbAlarm); return STATUS_SUCCESS; }
|