Leaked source code of windows server 2003
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.

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