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.

648 lines
15 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. #if DEBUG
  155. UNICODE_STRING unicodeString;
  156. #endif
  157. PDEVICE_OBJECT deviceObject;
  158. NTSTATUS Status;
  159. PECDATA EcData;
  160. PAGED_CODE();
  161. EcPrint(EC_LOW, ("AcpiEcCreateFdo: Entry\n") );
  162. #if DEBUG
  163. RtlInitUnicodeString(&unicodeString, L"\\Device\\ACPIEC");
  164. #endif
  165. Status = IoCreateDevice(
  166. DriverObject,
  167. sizeof (ECDATA),
  168. #if DEBUG
  169. &unicodeString,
  170. #else
  171. NULL,
  172. #endif
  173. FILE_DEVICE_UNKNOWN, // DeviceType
  174. FILE_DEVICE_SECURE_OPEN,
  175. FALSE,
  176. &deviceObject
  177. );
  178. if (Status != STATUS_SUCCESS) {
  179. EcPrint(EC_LOW, ("AcpiEcCreateFdo: unable to create device object: %X\n", Status));
  180. return(Status);
  181. }
  182. deviceObject->Flags |= DO_BUFFERED_IO;
  183. deviceObject->StackSize = 1;
  184. //
  185. // Initialize EC device extension data
  186. //
  187. EcData = (PECDATA) deviceObject->DeviceExtension;
  188. EcData->DeviceObject = deviceObject;
  189. EcData->DeviceState = EC_DEVICE_WORKING;
  190. EcData->QueryState = EC_QUERY_IDLE;
  191. EcData->IoState = EC_IO_NONE;
  192. EcData->IsStarted = FALSE;
  193. EcData->MaxBurstStall = 50;
  194. EcData->MaxNonBurstStall = 10;
  195. EcData->InterruptEnabled = TRUE;
  196. EcData->ConsecutiveFailures = 0;
  197. KeQueryPerformanceCounter (&EcData->PerformanceFrequency);
  198. RtlFillMemory (EcData->RecentActions, ACPIEC_ACTION_COUNT * sizeof(ACPIEC_ACTION), 0);
  199. //
  200. // Initialize EC global synchronization objects
  201. //
  202. InitializeListHead (&EcData->WorkQueue);
  203. KeInitializeEvent (&EcData->Unload, NotificationEvent, FALSE);
  204. KeInitializeSpinLock (&EcData->Lock);
  205. *NewDeviceObject = deviceObject;
  206. return STATUS_SUCCESS;
  207. }
  208. NTSTATUS
  209. AcpiEcPnpDispatch(
  210. IN PDEVICE_OBJECT DeviceObject,
  211. IN PIRP Irp
  212. )
  213. /*++
  214. Routine Description:
  215. This routine is the dispatch routine for plug and play requests.
  216. Arguments:
  217. DeviceObject - Pointer to class device object.
  218. Irp - Pointer to the request packet.
  219. Return Value:
  220. Status is returned.
  221. --*/
  222. {
  223. PIO_STACK_LOCATION irpStack;
  224. PECDATA EcData;
  225. NTSTATUS status;
  226. PAGED_CODE();
  227. //
  228. // Get a pointer to the current parameters for this request. The
  229. // information is contained in the current stack location.
  230. //
  231. irpStack = IoGetCurrentIrpStackLocation(Irp);
  232. EcData = DeviceObject->DeviceExtension;
  233. EcPrint (EC_NOTE, ("AcpiEcPnpDispatch: PnP dispatch, minor = %d\n",
  234. irpStack->MinorFunction));
  235. //
  236. // Dispatch minor function
  237. //
  238. switch (irpStack->MinorFunction) {
  239. case IRP_MN_START_DEVICE: {
  240. status = AcpiEcStartDevice (DeviceObject, Irp);
  241. Irp->IoStatus.Status = status;
  242. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  243. break;
  244. }
  245. //
  246. // We will never allow the EC driver to stop once it is started.
  247. //
  248. // Note: Stop and remove device should be implemented so that the driver
  249. // can be unloaded without reboot. Even if the device can't be removed, it
  250. // will get an IRP_MN_REMOVE_DEVICE if somthing goes wrong trying to start
  251. // the device.
  252. //
  253. case IRP_MN_QUERY_STOP_DEVICE:
  254. case IRP_MN_QUERY_REMOVE_DEVICE:
  255. case IRP_MN_STOP_DEVICE:
  256. case IRP_MN_REMOVE_DEVICE:
  257. status = Irp->IoStatus.Status = STATUS_INVALID_DEVICE_REQUEST;
  258. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  259. break;
  260. case IRP_MN_CANCEL_STOP_DEVICE:
  261. case IRP_MN_CANCEL_REMOVE_DEVICE:
  262. case IRP_MN_SURPRISE_REMOVAL:
  263. Irp->IoStatus.Status = STATUS_SUCCESS;
  264. AcpiEcCallLowerDriver(status, EcData->LowerDeviceObject, Irp);
  265. break;
  266. #if 0
  267. case IRP_MN_STOP_DEVICE: {
  268. status = AcpiEcStopDevice(DeviceObject, Irp);
  269. Irp->IoStatus.Status = status;
  270. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  271. break;
  272. }
  273. #endif
  274. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  275. EcPrint(EC_LOW, ("AcpiEcPnp: IRP_MJ_QUERY_DEVICE_RELATIONS Type: %d\n",
  276. irpStack->Parameters.QueryDeviceRelations.Type));
  277. //
  278. // Just pass it down to ACPI
  279. //
  280. AcpiEcCallLowerDriver(status, EcData->LowerDeviceObject, Irp);
  281. break;
  282. }
  283. default: {
  284. //
  285. // Unimplemented minor, Pass this down to ACPI
  286. //
  287. EcPrint(EC_LOW, ("AcpiEcPnp: Unimplemented PNP minor code %d, forwarding\n",
  288. irpStack->MinorFunction));
  289. AcpiEcCallLowerDriver(status, EcData->LowerDeviceObject, Irp);
  290. break;
  291. }
  292. }
  293. return status;
  294. }
  295. NTSTATUS
  296. AcpiEcGetResources(
  297. IN PCM_RESOURCE_LIST ResourceList,
  298. IN PECDATA EcData
  299. )
  300. /*++
  301. Routine Description:
  302. Get the resources already allocated and pointed to by the PDO.
  303. Arguments:
  304. ResourceList - Pointer to the resource list.
  305. EcData - Pointer to the extension.
  306. Return Value:
  307. Status is returned.
  308. --*/
  309. {
  310. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
  311. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  312. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDesc;
  313. ULONG i;
  314. PUCHAR port[2] = {NULL, NULL};
  315. PAGED_CODE();
  316. if (ResourceList == NULL) {
  317. EcPrint(EC_LOW, ("AcpiEcGetResources: Null resource pointer\n"));
  318. return STATUS_NO_MORE_ENTRIES;
  319. }
  320. if (ResourceList->Count <= 0 ) {
  321. return STATUS_UNSUCCESSFUL;
  322. }
  323. //
  324. // Traverse the resource list
  325. //
  326. fullResourceDesc=&ResourceList->List[0];
  327. partialResourceList = &fullResourceDesc->PartialResourceList;
  328. partialResourceDesc = partialResourceList->PartialDescriptors;
  329. for (i=0; i<partialResourceList->Count; i++, partialResourceDesc++) {
  330. if (partialResourceDesc->Type == CmResourceTypePort) {
  331. port[i] = (PUCHAR)((ULONG_PTR)partialResourceDesc->u.Port.Start.LowPart);
  332. }
  333. }
  334. //
  335. // Get the important things
  336. //
  337. EcData->StatusPort = port[1]; // Status port same as Command port
  338. EcData->CommandPort = port[1];
  339. EcData->DataPort = port[0];
  340. EcPrint(EC_LOW, ("AcpiEcGetResources: Status/Command port %x, Data port %x\n", port[1], port[0]));
  341. return STATUS_SUCCESS;
  342. }
  343. NTSTATUS
  344. AcpiEcStartDevice(
  345. IN PDEVICE_OBJECT Fdo,
  346. IN PIRP Irp
  347. )
  348. /*++
  349. Routine Description:
  350. Start a device
  351. Arguments:
  352. Fdo - Pointer to the Functional Device Object.
  353. Irp - Pointer to the request packet.
  354. Return Value:
  355. Status is returned.
  356. --*/
  357. {
  358. NTSTATUS status;
  359. PECDATA EcData = Fdo->DeviceExtension;
  360. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  361. EcPrint(EC_LOW, ("AcpiEcStartDevice: Entered with fdo %x\n", Fdo));
  362. //
  363. // Always send this down to the PDO first
  364. //
  365. status = AcpiEcForwardIrpAndWait (EcData, Irp);
  366. if (!NT_SUCCESS(status)) {
  367. return status;
  368. }
  369. if (EcData->IsStarted) {
  370. //
  371. // Device is already started
  372. //
  373. EcPrint(EC_WARN, ("AcpiEcStartDevice: Fdo %x already started\n", Fdo));
  374. return STATUS_SUCCESS;
  375. }
  376. //
  377. // Parse AllocatedResources.
  378. //
  379. status = AcpiEcGetResources (irpStack->Parameters.StartDevice.AllocatedResources, EcData);
  380. if (!NT_SUCCESS(status)) {
  381. EcPrint(EC_ERROR, ("AcpiEcStartDevice: Could not get resources, status = %x\n", status));
  382. return status;
  383. }
  384. //
  385. // Connect to the dedicated embedded controller GPE
  386. //
  387. status = AcpiEcConnectGpeVector (EcData);
  388. if (!NT_SUCCESS(status)) {
  389. EcPrint(EC_ERROR, ("AcpiEcStartDevice: Could not attach to GPE vector, status = %Lx\n", status));
  390. return status;
  391. }
  392. EcPrint(EC_NOTE, ("AcpiEcStartDevice: Attached to GPE vector %d\n", EcData->GpeVector));
  393. //
  394. // Install the Operation Region handler
  395. //
  396. status = AcpiEcInstallOpRegionHandler (EcData);
  397. if (!NT_SUCCESS(status)) {
  398. EcPrint(EC_ERROR, ("AcpiEcStartDevice: Could not install Op region handler, status = %Lx\n", status));
  399. return status;
  400. }
  401. EcData->IsStarted = TRUE;
  402. return STATUS_SUCCESS;
  403. }
  404. NTSTATUS
  405. AcpiEcStopDevice(
  406. IN PDEVICE_OBJECT Fdo,
  407. IN PIRP Irp
  408. )
  409. /*++
  410. Routine Description:
  411. Stop a device
  412. Arguments:
  413. Fdo - Pointer to the Functional Device Object.
  414. Irp - Pointer to the request packet.
  415. Return Value:
  416. Status is returned.
  417. --*/
  418. {
  419. PECDATA EcData = Fdo->DeviceExtension;
  420. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  421. NTSTATUS status;
  422. EcPrint(EC_LOW, ("AcpiEcStopDevice: Entered with fdo %x\n", Fdo));
  423. //
  424. // Always send this down to the PDO
  425. //
  426. status = AcpiEcForwardIrpAndWait (EcData, Irp);
  427. if (!NT_SUCCESS(status)) {
  428. return status;
  429. }
  430. if (!EcData->IsStarted) {
  431. //
  432. // Already stopped
  433. //
  434. return STATUS_SUCCESS;
  435. }
  436. //
  437. // Must disconnect from GPE
  438. //
  439. status = AcpiEcDisconnectGpeVector (EcData);
  440. if (!NT_SUCCESS(status)) {
  441. return status;
  442. }
  443. //
  444. // Must de-install Operation Region Handler
  445. //
  446. status = AcpiEcRemoveOpRegionHandler (EcData);
  447. if (!NT_SUCCESS(status)) {
  448. return status;
  449. }
  450. EcPrint(EC_LOW, ("AcpiEcStopDevice: Detached from GPE and Op Region\n"));
  451. //
  452. // Now the device is stopped.
  453. //
  454. EcData->IsStarted = FALSE; // Mark device stopped
  455. return status;
  456. }