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.

520 lines
11 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. acpiec.c
  5. Abstract:
  6. ACPI Embedded Controller Driver
  7. Author:
  8. Ken Reneris
  9. Environment:
  10. Kernel mode
  11. Notes:
  12. Revision History:
  13. 13-Feb-97
  14. PnP/Power support - Bob Moore
  15. --*/
  16. #include "ecp.h"
  17. //
  18. // List of FDOs managed by this driver
  19. //
  20. PDEVICE_OBJECT FdoList = NULL;
  21. #if DEBUG
  22. ULONG ECDebug = EC_ERRORS;
  23. #endif
  24. //
  25. // Prototypes
  26. //
  27. NTSTATUS
  28. DriverEntry(
  29. IN PDRIVER_OBJECT DriverObject,
  30. IN PUNICODE_STRING RegistryPath
  31. );
  32. NTSTATUS
  33. AcpiEcPnpDispatch(
  34. IN PDEVICE_OBJECT DeviceObject,
  35. IN PIRP Irp
  36. );
  37. NTSTATUS
  38. AcpiEcPowerDispatch(
  39. IN PDEVICE_OBJECT DeviceObject,
  40. IN PIRP Irp
  41. );
  42. NTSTATUS
  43. AcpiEcAddDevice(
  44. IN PDRIVER_OBJECT DriverObject,
  45. IN PDEVICE_OBJECT Pdo
  46. );
  47. //
  48. // ReadWrite and PowerDispatch should stay resident
  49. //
  50. #ifdef ALLOC_PRAGMA
  51. #pragma alloc_text(INIT,DriverEntry)
  52. #pragma alloc_text(PAGE,AcpiEcUnload)
  53. #pragma alloc_text(PAGE,AcpiEcOpenClose)
  54. #pragma alloc_text(PAGE,AcpiEcInternalControl)
  55. #endif
  56. NTSTATUS
  57. DriverEntry(
  58. IN PDRIVER_OBJECT DriverObject,
  59. IN PUNICODE_STRING RegistryPath
  60. )
  61. /*++
  62. Routine Description:
  63. This routine initializes the ACPI Embedded Controller Driver
  64. Arguments:
  65. DriverObject - Pointer to driver object created by system.
  66. RegistryPath - Pointer to the Unicode name of the registry path for this driver.
  67. Return Value:
  68. The function value is the final status from the initialization operation.
  69. --*/
  70. {
  71. //
  72. // Set up the device driver entry points.
  73. //
  74. DriverObject->MajorFunction[IRP_MJ_CREATE] = AcpiEcOpenClose;
  75. DriverObject->MajorFunction[IRP_MJ_CLOSE] = AcpiEcOpenClose;
  76. DriverObject->MajorFunction[IRP_MJ_READ] = AcpiEcReadWrite;
  77. DriverObject->MajorFunction[IRP_MJ_WRITE] = AcpiEcReadWrite;
  78. DriverObject->MajorFunction[IRP_MJ_POWER] = AcpiEcPowerDispatch;
  79. DriverObject->MajorFunction[IRP_MJ_PNP] = AcpiEcPnpDispatch;
  80. DriverObject->MajorFunction[IRP_MJ_DEVICE_CONTROL] = AcpiEcForwardRequest;
  81. DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = AcpiEcInternalControl;
  82. DriverObject->MajorFunction[IRP_MJ_SYSTEM_CONTROL] = AcpiEcForwardRequest;
  83. DriverObject->DriverExtension->AddDevice = AcpiEcAddDevice;
  84. DriverObject->DriverUnload = AcpiEcUnload;
  85. return STATUS_SUCCESS;
  86. }
  87. VOID
  88. AcpiEcUnload(
  89. IN PDRIVER_OBJECT DriverObject
  90. )
  91. /*++
  92. Routine Description:
  93. This routine unloads the ACPI Embedded Controller Driver
  94. Note: The driver should be already disconnected from the GPE by this time.
  95. Arguments:
  96. DriverObject - Pointer to driver object created by system.
  97. Return Value:
  98. None.
  99. --*/
  100. {
  101. PVOID LockPtr;
  102. KIRQL OldIrql;
  103. PECDATA EcData;
  104. EcPrint(EC_LOW, ("AcpiEcUnload: Entering\n" ));
  105. LockPtr = MmLockPagableCodeSection(AcpiEcUnload);
  106. while (DriverObject->DeviceObject) {
  107. EcData = DriverObject->DeviceObject->DeviceExtension;
  108. //
  109. // Device can only be active if initialization was completed
  110. //
  111. if (EcData->IsStarted) {
  112. //
  113. // Set state to determine when unload can occur, and issue a device service
  114. // call to get it unloaded now of the device is idle
  115. //
  116. ASSERT (EcData->DeviceState == EC_DEVICE_WORKING);
  117. EcData->DeviceState = EC_DEVICE_UNLOAD_PENDING;
  118. AcpiEcServiceDevice (EcData);
  119. //
  120. // Wait for device to cleanup
  121. //
  122. while (EcData->DeviceState != EC_DEVICE_UNLOAD_COMPLETE) {
  123. KeWaitForSingleObject (&EcData->Unload, Suspended, KernelMode, FALSE, NULL);
  124. }
  125. }
  126. //
  127. // Make sure caller signalling the unload is done
  128. //
  129. KeAcquireSpinLock (&EcData->Lock, &OldIrql);
  130. KeReleaseSpinLock (&EcData->Lock, OldIrql);
  131. //
  132. // Free resources
  133. //
  134. IoFreeIrp (EcData->QueryRequest);
  135. IoFreeIrp (EcData->MiscRequest);
  136. if (EcData->VectorTable) {
  137. ExFreePool (EcData->VectorTable);
  138. }
  139. IoDeleteDevice (EcData->DeviceObject);
  140. }
  141. //
  142. // Done
  143. //
  144. MmUnlockPagableImageSection(LockPtr);
  145. EcPrint(EC_LOW, ("AcpiEcUnload: Driver Unloaded\n"));
  146. }
  147. NTSTATUS
  148. AcpiEcOpenClose(
  149. IN PDEVICE_OBJECT DeviceObject,
  150. IN PIRP Irp
  151. )
  152. {
  153. PAGED_CODE();
  154. //
  155. // Complete the request and return status.
  156. //
  157. Irp->IoStatus.Status = STATUS_SUCCESS;
  158. Irp->IoStatus.Information = 0;
  159. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  160. return(STATUS_SUCCESS);
  161. }
  162. NTSTATUS
  163. AcpiEcReadWrite(
  164. IN PDEVICE_OBJECT DeviceObject,
  165. IN PIRP Irp
  166. )
  167. /*++
  168. Routine Description:
  169. This routine is the dispatch routine for read & write requests.
  170. Arguments:
  171. DeviceObject - Pointer to class device object.
  172. Irp - Pointer to the request packet.
  173. Return Value:
  174. Status is returned.
  175. --*/
  176. {
  177. PIO_STACK_LOCATION irpSp;
  178. PECDATA EcData;
  179. KIRQL OldIrql;
  180. BOOLEAN StartIo;
  181. NTSTATUS Status;
  182. #if DEBUG
  183. UCHAR i;
  184. #endif
  185. Status = STATUS_INVALID_PARAMETER;
  186. Irp->IoStatus.Information = 0;
  187. Irp->IoStatus.Status = Status;
  188. //
  189. // Get a pointer to the current parameters for this request. The
  190. // information is contained in the current stack location.
  191. //
  192. irpSp = IoGetCurrentIrpStackLocation(Irp);
  193. EcData = DeviceObject->DeviceExtension;
  194. //
  195. // Verify offset is within Embedded Controller range
  196. //
  197. if (irpSp->Parameters.Read.ByteOffset.HighPart ||
  198. irpSp->Parameters.Read.ByteOffset.LowPart > 255 ||
  199. irpSp->Parameters.Read.ByteOffset.LowPart + irpSp->Parameters.Read.Length > 256) {
  200. Status = STATUS_END_OF_FILE;
  201. Irp->IoStatus.Status = Status;
  202. } else {
  203. //
  204. // Queue the transfer up
  205. //
  206. KeAcquireSpinLock (&EcData->Lock, &OldIrql);
  207. if (EcData->DeviceState > EC_DEVICE_UNLOAD_PENDING) {
  208. //
  209. // Device is unloading
  210. //
  211. Status = STATUS_NO_SUCH_DEVICE;
  212. Irp->IoStatus.Status = Status;
  213. } else {
  214. #if DEBUG
  215. if ((irpSp->MajorFunction == IRP_MJ_WRITE) && (ECDebug & EC_TRANSACTION)) {
  216. EcPrint (EC_TRANSACTION, ("AcpiEcReadWrite: Write ("));
  217. for (i=0; i < irpSp->Parameters.Write.Length; i++) {
  218. EcPrint (EC_TRANSACTION, ("%02x ",
  219. ((PUCHAR)Irp->AssociatedIrp.SystemBuffer) [i]));
  220. }
  221. EcPrint (EC_TRANSACTION, (") to %02x length %02x\n",
  222. (UCHAR)irpSp->Parameters.Write.ByteOffset.LowPart,
  223. (UCHAR)irpSp->Parameters.Write.Length));
  224. }
  225. #endif
  226. Status = STATUS_PENDING;
  227. Irp->IoStatus.Status = Status;
  228. IoMarkIrpPending (Irp);
  229. InsertTailList (&EcData->WorkQueue, &Irp->Tail.Overlay.ListEntry);
  230. StartIo = DeviceObject->CurrentIrp == NULL;
  231. AcpiEcLogAction (EcData, EC_ACTION_QUEUED_IO, StartIo);
  232. }
  233. KeReleaseSpinLock (&EcData->Lock, OldIrql);
  234. }
  235. //
  236. // Handle status
  237. //
  238. if (Status == STATUS_PENDING) {
  239. //
  240. // IO is queued, if device is not busy start it
  241. //
  242. if (StartIo) {
  243. AcpiEcServiceDevice (EcData);
  244. }
  245. } else {
  246. //
  247. // For opregion requests, there is no way to fail the request, so return -1
  248. //
  249. RtlFillMemory (Irp->AssociatedIrp.SystemBuffer, irpSp->Parameters.Read.Length, 0xff);
  250. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  251. }
  252. return Status;
  253. }
  254. NTSTATUS
  255. AcpiEcPowerDispatch(
  256. IN PDEVICE_OBJECT DeviceObject,
  257. IN PIRP Irp
  258. )
  259. /*++
  260. Routine Description:
  261. This routine is the dispatch routine for power requests.
  262. Arguments:
  263. DeviceObject - Pointer to class device object.
  264. Irp - Pointer to the request packet.
  265. Return Value:
  266. Status is returned.
  267. --*/
  268. {
  269. NTSTATUS status;
  270. PECDATA ecData = DeviceObject->DeviceExtension;
  271. //
  272. // Start the next power irp
  273. //
  274. PoStartNextPowerIrp( Irp );
  275. //
  276. // Handle the irp
  277. //
  278. if (ecData->LowerDeviceObject != NULL) {
  279. IoSkipCurrentIrpStackLocation( Irp );
  280. status = PoCallDriver( ecData->LowerDeviceObject, Irp );
  281. } else {
  282. //
  283. // Complete irp with the current code;
  284. status = Irp->IoStatus.Status;
  285. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  286. }
  287. return status;
  288. }
  289. NTSTATUS
  290. AcpiEcInternalControl(
  291. IN PDEVICE_OBJECT DeviceObject,
  292. IN PIRP Irp
  293. )
  294. /*++
  295. Routine Description:
  296. Internal IOCTL dispatch routine
  297. Arguments:
  298. DeviceObject - Pointer to class device object.
  299. Irp - Pointer to the request packet.
  300. Return Value:
  301. Status is returned.
  302. --*/
  303. {
  304. PIO_STACK_LOCATION IrpSp;
  305. PECDATA EcData;
  306. NTSTATUS Status;
  307. PAGED_CODE();
  308. Status = STATUS_INVALID_PARAMETER;
  309. Irp->IoStatus.Information = 0;
  310. //
  311. // Get a pointer to the current parameters for this request. The
  312. // information is contained in the current stack location.
  313. //
  314. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  315. EcData = DeviceObject->DeviceExtension;
  316. EcPrint (EC_NOTE, ("AcpiEcInternalControl: dispatch, code = %d\n",
  317. IrpSp->Parameters.DeviceIoControl.IoControlCode));
  318. Status = STATUS_INVALID_PARAMETER;
  319. switch (IrpSp->Parameters.DeviceIoControl.IoControlCode) {
  320. case EC_CONNECT_QUERY_HANDLER:
  321. Status = AcpiEcConnectHandler (EcData, Irp);
  322. break;
  323. case EC_DISCONNECT_QUERY_HANDLER:
  324. Status = AcpiEcDisconnectHandler (EcData, Irp);
  325. break;
  326. }
  327. if (Status != STATUS_PENDING) {
  328. Irp->IoStatus.Status = Status;
  329. IoCompleteRequest (Irp, IO_NO_INCREMENT);
  330. }
  331. return Status;
  332. }
  333. NTSTATUS
  334. AcpiEcForwardRequest(
  335. IN PDEVICE_OBJECT DeviceObject,
  336. IN PIRP Irp
  337. )
  338. /*++
  339. Routine Description:
  340. This routine forwards the irp down the stack
  341. Arguments:
  342. DeviceObject - The target
  343. Irp - The request
  344. Return Value:
  345. NTSTATUS
  346. --*/
  347. {
  348. NTSTATUS status;
  349. PECDATA ecData = DeviceObject->DeviceExtension;
  350. if (ecData->LowerDeviceObject != NULL) {
  351. IoSkipCurrentIrpStackLocation( Irp );
  352. status = IoCallDriver( ecData->LowerDeviceObject, Irp );
  353. } else {
  354. status = Irp->IoStatus.Status;
  355. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  356. }
  357. return status;
  358. }