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.

640 lines
14 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. ecpnp.c
  5. Abstract:
  6. ACPI Embedded Controller Driver, Plug and Play support
  7. Author:
  8. Bob Moore (Intel)
  9. Environment:
  10. Kernel mode
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include "ecp.h"
  15. //
  16. // List of FDOs managed by this driver
  17. //
  18. extern PDEVICE_OBJECT FdoList;
  19. //
  20. // Table of direct-call interfaces into the ACPI driver
  21. //
  22. ACPI_INTERFACE_STANDARD AcpiInterfaces;
  23. NTSTATUS
  24. AcpiEcIoCompletion(
  25. IN PDEVICE_OBJECT DeviceObject,
  26. IN PIRP Irp,
  27. IN PKEVENT pdoIoCompletedEvent
  28. )
  29. /*++
  30. Routine Description:
  31. Completion function for synchronous IRPs sent be this driver.
  32. Context is the event to set.
  33. --*/
  34. {
  35. KeSetEvent(pdoIoCompletedEvent, IO_NO_INCREMENT, FALSE);
  36. return STATUS_MORE_PROCESSING_REQUIRED;
  37. }
  38. NTSTATUS
  39. AcpiEcAddDevice(
  40. IN PDRIVER_OBJECT DriverObject,
  41. IN PDEVICE_OBJECT Pdo
  42. )
  43. /*++
  44. Routine Description:
  45. This routine creates functional device objects for each AcpiEc controller in the
  46. system and attaches them to the physical device objects for the controllers
  47. Arguments:
  48. DriverObject - a pointer to the object for this driver
  49. NewDeviceObject - a pointer to where the FDO is placed
  50. Return Value:
  51. Status from device creation and initialization
  52. --*/
  53. {
  54. PDEVICE_OBJECT fdo = NULL;
  55. PDEVICE_OBJECT ownerDevice = NULL;
  56. PDEVICE_OBJECT lowerDevice = NULL;
  57. PECDATA EcData;
  58. NTSTATUS status;
  59. PAGED_CODE();
  60. EcPrint(EC_LOW, ("AcpiEcAddDevice: Entered with pdo %x\n", Pdo));
  61. if (Pdo == NULL) {
  62. //
  63. // Have we been asked to do detection on our own?
  64. // if so just return no more devices
  65. //
  66. EcPrint(EC_LOW, ("AcpiEcAddDevice - asked to do detection\n"));
  67. return STATUS_NO_MORE_ENTRIES;
  68. }
  69. //
  70. // Create and initialize the new functional device object
  71. //
  72. status = AcpiEcCreateFdo(DriverObject, &fdo);
  73. if (!NT_SUCCESS(status)) {
  74. EcPrint(EC_LOW, ("AcpiEcAddDevice - error creating Fdo\n"));
  75. return status;
  76. }
  77. //
  78. // Layer our FDO on top of the PDO
  79. //
  80. lowerDevice = IoAttachDeviceToDeviceStack(fdo,Pdo);
  81. //
  82. // No status. Do the best we can.
  83. //
  84. ASSERT(lowerDevice);
  85. EcData = fdo->DeviceExtension;
  86. EcData->LowerDeviceObject = lowerDevice;
  87. EcData->Pdo = Pdo;
  88. //
  89. // Allocate and hold an IRP for Query notifications and miscellaneous
  90. //
  91. EcData->QueryRequest = IoAllocateIrp (EcData->LowerDeviceObject->StackSize, FALSE);
  92. EcData->MiscRequest = IoAllocateIrp (EcData->LowerDeviceObject->StackSize, FALSE);
  93. if ((!EcData->QueryRequest) || (!EcData->MiscRequest)) {
  94. //
  95. // NOTE: This failure case and other failure cases below should do
  96. // cleanup of all previous allocations, etc performed in this function.
  97. //
  98. EcPrint(EC_ERROR, ("AcpiEcAddDevice: Couldn't allocate Irp\n"));
  99. return STATUS_INSUFFICIENT_RESOURCES;
  100. }
  101. //
  102. // Link this fdo to the list of fdo's managed by the driver
  103. // (Probably overkill since there will be only one FDO)
  104. //
  105. //
  106. EcPrint(EC_LOW, ("AcpiEcAddDevice: linking fdo to list\n"));
  107. EcData->NextFdo = FdoList;
  108. InterlockedExchangePointer((PVOID *) &FdoList, fdo);
  109. //
  110. // Initialize the Timeout DPC
  111. //
  112. KeInitializeTimer(&EcData->WatchdogTimer);
  113. KeInitializeDpc(&EcData->WatchdogDpc, AcpiEcWatchdogDpc, EcData);
  114. //
  115. // Get the GPE vector assigned to this device
  116. //
  117. status = AcpiEcGetGpeVector (EcData);
  118. if (!NT_SUCCESS(status)) {
  119. EcPrint(EC_LOW, ("AcpiEcAddDevice: Could not get GPE vector, status = %Lx\n", status));
  120. return status;
  121. }
  122. //
  123. // Get the direct-call ACPI interfaces.
  124. //
  125. status = AcpiEcGetAcpiInterfaces (EcData);
  126. if (!NT_SUCCESS(status)) {
  127. EcPrint(EC_LOW, ("AcpiEcAddDevice: Could not get ACPI driver interfaces, status = %Lx\n", status));
  128. return status;
  129. }
  130. //
  131. // Final flags
  132. //
  133. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
  134. fdo->Flags |= DO_POWER_PAGABLE; // Don't want power Irps at irql 2
  135. return STATUS_SUCCESS;
  136. }
  137. NTSTATUS
  138. AcpiEcCreateFdo(
  139. IN PDRIVER_OBJECT DriverObject,
  140. OUT PDEVICE_OBJECT *NewDeviceObject
  141. )
  142. /*++
  143. Routine Description:
  144. This routine will create and initialize a functional device object to
  145. be attached to a Embedded controller PDO.
  146. Arguments:
  147. DriverObject - a pointer to the driver object this is created under
  148. DeviceObject - a location to store the pointer to the new device object
  149. Return Value:
  150. STATUS_SUCCESS if everything was successful
  151. reason for failure otherwise
  152. --*/
  153. {
  154. UNICODE_STRING unicodeString;
  155. PDEVICE_OBJECT deviceObject;
  156. NTSTATUS Status;
  157. PECDATA EcData;
  158. PAGED_CODE();
  159. EcPrint(EC_LOW, ("AcpiEcCreateFdo: Entry\n") );
  160. RtlInitUnicodeString(&unicodeString, L"\\Device\\ACPIEC");
  161. Status = IoCreateDevice(
  162. DriverObject,
  163. sizeof (ECDATA),
  164. &unicodeString,
  165. FILE_DEVICE_UNKNOWN, // DeviceType
  166. 0,
  167. FALSE,
  168. &deviceObject
  169. );
  170. if (Status != STATUS_SUCCESS) {
  171. EcPrint(EC_LOW, ("AcpiEcCreateFdo: unable to create device object: %X\n", Status));
  172. return(Status);
  173. }
  174. deviceObject->Flags |= DO_BUFFERED_IO;
  175. deviceObject->StackSize = 1;
  176. //
  177. // Initialize EC device extension data
  178. //
  179. EcData = (PECDATA) deviceObject->DeviceExtension;
  180. EcData->DeviceObject = deviceObject;
  181. EcData->DeviceState = EC_DEVICE_WORKING;
  182. EcData->QueryState = EC_QUERY_IDLE;
  183. EcData->IoState = EC_IO_NONE;
  184. EcData->IsStarted = FALSE;
  185. EcData->MaxBurstStall = 50;
  186. EcData->MaxNonBurstStall = 10;
  187. EcData->InterruptEnabled = TRUE;
  188. EcData->ConsecutiveFailures = 0;
  189. KeQueryPerformanceCounter (&EcData->PerformanceFrequency);
  190. RtlFillMemory (EcData->RecentActions, ACPIEC_ACTION_COUNT * sizeof(ACPIEC_ACTION), 0);
  191. //
  192. // Initialize EC global synchronization objects
  193. //
  194. InitializeListHead (&EcData->WorkQueue);
  195. KeInitializeEvent (&EcData->Unload, NotificationEvent, FALSE);
  196. KeInitializeSpinLock (&EcData->Lock);
  197. *NewDeviceObject = deviceObject;
  198. return STATUS_SUCCESS;
  199. }
  200. NTSTATUS
  201. AcpiEcPnpDispatch(
  202. IN PDEVICE_OBJECT DeviceObject,
  203. IN PIRP Irp
  204. )
  205. /*++
  206. Routine Description:
  207. This routine is the dispatch routine for plug and play requests.
  208. Arguments:
  209. DeviceObject - Pointer to class device object.
  210. Irp - Pointer to the request packet.
  211. Return Value:
  212. Status is returned.
  213. --*/
  214. {
  215. PIO_STACK_LOCATION irpStack;
  216. PECDATA EcData;
  217. NTSTATUS status;
  218. PAGED_CODE();
  219. //
  220. // Get a pointer to the current parameters for this request. The
  221. // information is contained in the current stack location.
  222. //
  223. irpStack = IoGetCurrentIrpStackLocation(Irp);
  224. EcData = DeviceObject->DeviceExtension;
  225. EcPrint (EC_NOTE, ("AcpiEcPnpDispatch: PnP dispatch, minor = %d\n",
  226. irpStack->MinorFunction));
  227. //
  228. // Dispatch minor function
  229. //
  230. switch (irpStack->MinorFunction) {
  231. case IRP_MN_START_DEVICE: {
  232. status = AcpiEcStartDevice (DeviceObject, Irp);
  233. Irp->IoStatus.Status = status;
  234. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  235. break;
  236. }
  237. //
  238. // We will never allow the EC driver to stop once it is started.
  239. //
  240. // Note: Stop and remove device should be implemented so that the driver
  241. // can be unloaded without reboot. Even if the device can't be removed, it
  242. // will get an IRP_MN_REMOVE_DEVICE if somthing goes wrong trying to start
  243. // the device.
  244. //
  245. case IRP_MN_QUERY_STOP_DEVICE:
  246. case IRP_MN_QUERY_REMOVE_DEVICE:
  247. case IRP_MN_STOP_DEVICE:
  248. case IRP_MN_REMOVE_DEVICE:
  249. status = Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  250. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  251. break;
  252. case IRP_MN_CANCEL_STOP_DEVICE:
  253. case IRP_MN_CANCEL_REMOVE_DEVICE:
  254. case IRP_MN_SURPRISE_REMOVAL:
  255. Irp->IoStatus.Status = STATUS_SUCCESS;
  256. AcpiEcCallLowerDriver(status, EcData->LowerDeviceObject, Irp);
  257. break;
  258. #if 0
  259. case IRP_MN_STOP_DEVICE: {
  260. status = AcpiEcStopDevice(DeviceObject, Irp);
  261. Irp->IoStatus.Status = status;
  262. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  263. break;
  264. }
  265. #endif
  266. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  267. EcPrint(EC_LOW, ("AcpiEcPnp: IRP_MJ_QUERY_DEVICE_RELATIONS Type: %d\n",
  268. irpStack->Parameters.QueryDeviceRelations.Type));
  269. //
  270. // Just pass it down to ACPI
  271. //
  272. AcpiEcCallLowerDriver(status, EcData->LowerDeviceObject, Irp);
  273. break;
  274. }
  275. default: {
  276. //
  277. // Unimplemented minor, Pass this down to ACPI
  278. //
  279. EcPrint(EC_LOW, ("AcpiEcPnp: Unimplemented PNP minor code %d, forwarding\n",
  280. irpStack->MinorFunction));
  281. AcpiEcCallLowerDriver(status, EcData->LowerDeviceObject, Irp);
  282. break;
  283. }
  284. }
  285. return status;
  286. }
  287. NTSTATUS
  288. AcpiEcGetResources(
  289. IN PCM_RESOURCE_LIST ResourceList,
  290. IN PECDATA EcData
  291. )
  292. /*++
  293. Routine Description:
  294. Get the resources already allocated and pointed to by the PDO.
  295. Arguments:
  296. ResourceList - Pointer to the resource list.
  297. EcData - Pointer to the extension.
  298. Return Value:
  299. Status is returned.
  300. --*/
  301. {
  302. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
  303. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  304. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDesc;
  305. ULONG i;
  306. PUCHAR port[2] = {NULL, NULL};
  307. PAGED_CODE();
  308. if (ResourceList == NULL) {
  309. EcPrint(EC_LOW, ("AcpiEcGetResources: Null resource pointer\n"));
  310. return STATUS_NO_MORE_ENTRIES;
  311. }
  312. if (ResourceList->Count <= 0 ) {
  313. return STATUS_UNSUCCESSFUL;
  314. }
  315. //
  316. // Traverse the resource list
  317. //
  318. fullResourceDesc=&ResourceList->List[0];
  319. partialResourceList = &fullResourceDesc->PartialResourceList;
  320. partialResourceDesc = partialResourceList->PartialDescriptors;
  321. for (i=0; i<partialResourceList->Count; i++, partialResourceDesc++) {
  322. if (partialResourceDesc->Type == CmResourceTypePort) {
  323. port[i] = (PUCHAR)((ULONG_PTR)partialResourceDesc->u.Port.Start.LowPart);
  324. }
  325. }
  326. //
  327. // Get the important things
  328. //
  329. EcData->StatusPort = port[1]; // Status port same as Command port
  330. EcData->CommandPort = port[1];
  331. EcData->DataPort = port[0];
  332. EcPrint(EC_LOW, ("AcpiEcGetResources: Status/Command port %x, Data port %x\n", port[1], port[0]));
  333. return STATUS_SUCCESS;
  334. }
  335. NTSTATUS
  336. AcpiEcStartDevice(
  337. IN PDEVICE_OBJECT Fdo,
  338. IN PIRP Irp
  339. )
  340. /*++
  341. Routine Description:
  342. Start a device
  343. Arguments:
  344. Fdo - Pointer to the Functional Device Object.
  345. Irp - Pointer to the request packet.
  346. Return Value:
  347. Status is returned.
  348. --*/
  349. {
  350. NTSTATUS status;
  351. PECDATA EcData = Fdo->DeviceExtension;
  352. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  353. EcPrint(EC_LOW, ("AcpiEcStartDevice: Entered with fdo %x\n", Fdo));
  354. //
  355. // Always send this down to the PDO first
  356. //
  357. status = AcpiEcForwardIrpAndWait (EcData, Irp);
  358. if (!NT_SUCCESS(status)) {
  359. return status;
  360. }
  361. if (EcData->IsStarted) {
  362. //
  363. // Device is already started
  364. //
  365. EcPrint(EC_WARN, ("AcpiEcStartDevice: Fdo %x already started\n", Fdo));
  366. return STATUS_SUCCESS;
  367. }
  368. //
  369. // Parse AllocatedResources.
  370. //
  371. status = AcpiEcGetResources (irpStack->Parameters.StartDevice.AllocatedResources, EcData);
  372. if (!NT_SUCCESS(status)) {
  373. EcPrint(EC_ERROR, ("AcpiEcStartDevice: Could not get resources, status = %x\n", status));
  374. return status;
  375. }
  376. //
  377. // Connect to the dedicated embedded controller GPE
  378. //
  379. status = AcpiEcConnectGpeVector (EcData);
  380. if (!NT_SUCCESS(status)) {
  381. EcPrint(EC_ERROR, ("AcpiEcStartDevice: Could not attach to GPE vector, status = %Lx\n", status));
  382. return status;
  383. }
  384. EcPrint(EC_NOTE, ("AcpiEcStartDevice: Attached to GPE vector %d\n", EcData->GpeVector));
  385. //
  386. // Install the Operation Region handler
  387. //
  388. status = AcpiEcInstallOpRegionHandler (EcData);
  389. if (!NT_SUCCESS(status)) {
  390. EcPrint(EC_ERROR, ("AcpiEcStartDevice: Could not install Op region handler, status = %Lx\n", status));
  391. return status;
  392. }
  393. EcData->IsStarted = TRUE;
  394. return STATUS_SUCCESS;
  395. }
  396. NTSTATUS
  397. AcpiEcStopDevice(
  398. IN PDEVICE_OBJECT Fdo,
  399. IN PIRP Irp
  400. )
  401. /*++
  402. Routine Description:
  403. Stop a device
  404. Arguments:
  405. Fdo - Pointer to the Functional Device Object.
  406. Irp - Pointer to the request packet.
  407. Return Value:
  408. Status is returned.
  409. --*/
  410. {
  411. PECDATA EcData = Fdo->DeviceExtension;
  412. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  413. NTSTATUS status;
  414. EcPrint(EC_LOW, ("AcpiEcStopDevice: Entered with fdo %x\n", Fdo));
  415. //
  416. // Always send this down to the PDO
  417. //
  418. status = AcpiEcForwardIrpAndWait (EcData, Irp);
  419. if (!NT_SUCCESS(status)) {
  420. return status;
  421. }
  422. if (!EcData->IsStarted) {
  423. //
  424. // Already stopped
  425. //
  426. return STATUS_SUCCESS;
  427. }
  428. //
  429. // Must disconnect from GPE
  430. //
  431. status = AcpiEcDisconnectGpeVector (EcData);
  432. if (!NT_SUCCESS(status)) {
  433. return status;
  434. }
  435. //
  436. // Must de-install Operation Region Handler
  437. //
  438. status = AcpiEcRemoveOpRegionHandler (EcData);
  439. if (!NT_SUCCESS(status)) {
  440. return status;
  441. }
  442. EcPrint(EC_LOW, ("AcpiEcStopDevice: Detached from GPE and Op Region\n"));
  443. //
  444. // Now the device is stopped.
  445. //
  446. EcData->IsStarted = FALSE; // Mark device stopped
  447. return status;
  448. }