Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

386 lines
8.4 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. smbcsrv.c
  5. Abstract:
  6. SMBus class driver service functions
  7. Author:
  8. Ken Reneris
  9. Environment:
  10. Notes:
  11. Revision History:
  12. --*/
  13. #include "smbc.h"
  14. VOID
  15. SmbCCheckAlarmDelete (
  16. IN PSMBDATA Smb,
  17. IN PSMB_ALARM SmbAlarm
  18. );
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text(PAGE,SmbCCheckAlarmDelete)
  21. #pragma alloc_text(PAGE,SmbCRegisterAlarm)
  22. #pragma alloc_text(PAGE,SmbCDeregisterAlarm)
  23. #endif
  24. UCHAR gHexDigits [] = "0123456789ABCDEF";
  25. NTSTATUS
  26. SmbCRunAlarmMethodCompletionRoutine (
  27. IN PDEVICE_OBJECT DeviceObject,
  28. IN PIRP Irp,
  29. IN PVOID Context
  30. )
  31. {
  32. SmbPrint(SMB_ALARMS, ("SmbCRunAlarmMethodCompletionRoutine: Done running Control Method. Status=0x%08x\n", Irp->IoStatus.Status));
  33. ExFreePool (Irp->AssociatedIrp.SystemBuffer);
  34. IoFreeIrp(Irp);
  35. return STATUS_MORE_PROCESSING_REQUIRED;
  36. }
  37. VOID
  38. SmbCRunAlarmMethod (
  39. IN PSMB_CLASS SmbClass,
  40. IN UCHAR Address,
  41. IN USHORT Data
  42. )
  43. /*++
  44. Routine Description:
  45. Run _Rxx for the alarm
  46. --*/
  47. {
  48. PIRP irp;
  49. PIO_STACK_LOCATION irpSp;
  50. PACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER inputBuffer;
  51. SmbPrint(SMB_ALARMS, ("SmbCRunAlarmMethod: Running Control method _R%02x\n", Address));
  52. inputBuffer = ExAllocatePoolWithTag (
  53. NonPagedPool,
  54. sizeof (ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER),
  55. 'AbmS'
  56. );
  57. RtlZeroMemory( inputBuffer, sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER) );
  58. inputBuffer->Signature = ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER_SIGNATURE;
  59. inputBuffer->MethodNameAsUlong = '00Q_';
  60. inputBuffer->MethodName[2] = gHexDigits[ Address / 16];
  61. inputBuffer->MethodName[3] = gHexDigits[ Address % 16];
  62. inputBuffer->IntegerArgument = Data;
  63. irp = IoAllocateIrp (SmbClass->LowerDeviceObject->StackSize, FALSE);
  64. if (!irp) {
  65. return;
  66. }
  67. irp->AssociatedIrp.SystemBuffer = inputBuffer;
  68. ASSERT ((IOCTL_ACPI_ASYNC_EVAL_METHOD & 0x3) == METHOD_BUFFERED);
  69. irp->Flags = IRP_BUFFERED_IO | IRP_INPUT_OPERATION;
  70. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  71. irpSp = IoGetNextIrpStackLocation( irp );
  72. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  73. irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  74. irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(ACPI_EVAL_INPUT_BUFFER_SIMPLE_INTEGER);
  75. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_ACPI_ASYNC_EVAL_METHOD;
  76. irp->UserBuffer = NULL;
  77. IoSetCompletionRoutine(
  78. irp,
  79. SmbCRunAlarmMethodCompletionRoutine,
  80. NULL, // No Context This just frees the IRP
  81. TRUE,
  82. TRUE,
  83. TRUE
  84. );
  85. IoCallDriver(SmbClass->LowerDeviceObject, irp);
  86. }
  87. VOID
  88. SmbClassAlarm (
  89. IN PSMB_CLASS SmbClass,
  90. IN UCHAR Address,
  91. IN USHORT Data
  92. )
  93. /*++
  94. Routine Description:
  95. Miniport has an alarm input
  96. --*/
  97. {
  98. PSMBDATA Smb;
  99. PSMB_ALARM SmbAlarm;
  100. PLIST_ENTRY Entry, NextEntry;
  101. BOOLEAN AlarmRegistered = FALSE;
  102. Smb = CONTAINING_RECORD (SmbClass, SMBDATA, Class);
  103. ASSERT_DEVICE_LOCKED (Smb);
  104. Entry = Smb->Alarms.Flink;
  105. while (Entry != &Smb->Alarms) {
  106. SmbAlarm = CONTAINING_RECORD (Entry, SMB_ALARM, Link);
  107. //
  108. // If notification is for this address, issue it
  109. //
  110. if (Address >= SmbAlarm->MinAddress && Address <= SmbAlarm->MaxAddress) {
  111. //
  112. // A driver has registered for this notification. Don't call the BIOS.
  113. //
  114. AlarmRegistered = TRUE;
  115. //
  116. // Raise reference count before calling notifcation function
  117. //
  118. SmbAlarm->Reference += 1;
  119. ASSERT (SmbAlarm->Reference != 0);
  120. SmbClassUnlockDevice (SmbClass);
  121. //
  122. // Issue notification
  123. //
  124. SmbAlarm->NotifyFunction (SmbAlarm->NotifyContext, Address, Data);
  125. //
  126. // Continue
  127. //
  128. SmbClassLockDevice (SmbClass);
  129. SmbAlarm->Reference -= 1;
  130. }
  131. //
  132. // Get next entry
  133. //
  134. NextEntry = Entry->Flink;
  135. //
  136. // If entry is pending delete, hand it to deleting thread
  137. //
  138. if (SmbAlarm->Flag & SMBC_ALARM_DELETE_PENDING) {
  139. SmbCCheckAlarmDelete (Smb, SmbAlarm);
  140. }
  141. //
  142. // Move on
  143. //
  144. Entry = NextEntry;
  145. }
  146. //
  147. // If no one registered for this alarm, call the _Rxx control method
  148. //
  149. if (!AlarmRegistered) {
  150. SmbCRunAlarmMethod (SmbClass, Address, Data);
  151. }
  152. }
  153. VOID
  154. SmbCCheckAlarmDelete (
  155. IN PSMBDATA Smb,
  156. IN PSMB_ALARM SmbAlarm
  157. )
  158. {
  159. //
  160. // If alarm structure is referenced, wait somemore
  161. //
  162. if (SmbAlarm->Reference) {
  163. return ;
  164. }
  165. //
  166. // Time to free it. Remove it from the notification list, clear
  167. // the pending flag and set the event to let waiting threads know
  168. // that some entry was removed
  169. //
  170. RemoveEntryList (&SmbAlarm->Link);
  171. SmbAlarm->Flag &= ~SMBC_ALARM_DELETE_PENDING;
  172. KeSetEvent (&Smb->AlarmEvent, 0, FALSE);
  173. }
  174. NTSTATUS
  175. SmbCRegisterAlarm (
  176. PSMBDATA Smb,
  177. PIRP Irp
  178. )
  179. /*++
  180. Routine Description:
  181. Called to register for an alarm event
  182. --*/
  183. {
  184. PVOID LockPtr;
  185. PSMB_ALARM SmbAlarm, *Result;
  186. PSMB_REGISTER_ALARM RegAlarm;
  187. PIO_STACK_LOCATION IrpSp;
  188. PAGED_CODE();
  189. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  190. if (ExGetPreviousMode() != KernelMode ||
  191. IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(SMB_REGISTER_ALARM) ||
  192. IrpSp->Parameters.DeviceIoControl.OutputBufferLength < sizeof(PSMB_ALARM) ) {
  193. return STATUS_INVALID_PARAMETER;
  194. }
  195. RegAlarm = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  196. SmbAlarm = ExAllocatePoolWithTag (
  197. NonPagedPool,
  198. sizeof (SMB_ALARM),
  199. 'AbmS'
  200. );
  201. if (!SmbAlarm) {
  202. return STATUS_INSUFFICIENT_RESOURCES;
  203. }
  204. SmbAlarm->Flag = 0;
  205. SmbAlarm->Reference = 0;
  206. SmbAlarm->MinAddress = RegAlarm->MinAddress;
  207. SmbAlarm->MaxAddress = RegAlarm->MaxAddress;
  208. SmbAlarm->NotifyFunction = RegAlarm->NotifyFunction;
  209. SmbAlarm->NotifyContext = RegAlarm->NotifyContext;
  210. //
  211. // Add it to the alarm notification list
  212. //
  213. LockPtr = MmLockPagableCodeSection(SmbCRegisterAlarm);
  214. SmbClassLockDevice (&Smb->Class);
  215. InsertTailList (&Smb->Alarms, &SmbAlarm->Link);
  216. SmbClassUnlockDevice (&Smb->Class);
  217. MmUnlockPagableImageSection(LockPtr);
  218. //
  219. // Return value caller needs to deregister with
  220. //
  221. Result = (PSMB_ALARM *) Irp->UserBuffer;
  222. *Result = SmbAlarm;
  223. Irp->IoStatus.Information = sizeof(PSMB_ALARM);
  224. return STATUS_SUCCESS;
  225. }
  226. NTSTATUS
  227. SmbCDeregisterAlarm (
  228. PSMBDATA Smb,
  229. PIRP Irp
  230. )
  231. /*++
  232. Routine Description:
  233. Called to register for an alarm event
  234. --*/
  235. {
  236. PVOID LockPtr;
  237. PSMB_ALARM SmbAlarm;
  238. PIO_STACK_LOCATION IrpSp;
  239. PAGED_CODE();
  240. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  241. if (ExGetPreviousMode() != KernelMode ||
  242. IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(PSMB_ALARM) ) {
  243. return STATUS_INVALID_PARAMETER;
  244. }
  245. SmbAlarm = * (PSMB_ALARM *) IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  246. LockPtr = MmLockPagableCodeSection(SmbCDeregisterAlarm);
  247. SmbClassLockDevice (&Smb->Class);
  248. //
  249. // Flag alarm structure as delete pending
  250. //
  251. SmbAlarm->Flag |= SMBC_ALARM_DELETE_PENDING;
  252. //
  253. // While delete is pending wait
  254. //
  255. while (SmbAlarm->Flag & SMBC_ALARM_DELETE_PENDING) {
  256. //
  257. // Issue bogus alarm to generate freeing
  258. //
  259. KeResetEvent (&Smb->AlarmEvent);
  260. SmbClassAlarm (&Smb->Class, 0xFF, 0);
  261. //
  262. // Wait for alarm structure to get freed, then check if it
  263. // was ours
  264. //
  265. SmbClassUnlockDevice (&Smb->Class);
  266. KeWaitForSingleObject (
  267. &Smb->AlarmEvent,
  268. Executive,
  269. KernelMode,
  270. FALSE,
  271. NULL
  272. );
  273. SmbClassLockDevice (&Smb->Class);
  274. }
  275. //
  276. // It's been removed, free the memory
  277. //
  278. SmbClassUnlockDevice (&Smb->Class);
  279. MmUnlockPagableImageSection(LockPtr);
  280. ExFreePool (SmbAlarm);
  281. return STATUS_SUCCESS;
  282. }