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) 1990 Microsoft Corporation
  3. Module Name:
  4. query.c
  5. Abstract:
  6. ACPI Embedded Controller Driver - query dispatching
  7. Author:
  8. Ken Reneris
  9. Environment:
  10. Notes:
  11. Revision History:
  12. --*/
  13. #include "ecp.h"
  14. NTSTATUS
  15. AcpiEcCompleteQueryMethod (
  16. IN PDEVICE_OBJECT DeviceObject,
  17. IN PIRP Irp,
  18. IN PVOID Context
  19. );
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text(PAGE,AcpiEcUnloadPending)
  22. #pragma alloc_text(PAGE,AcpiEcConnectHandler)
  23. #pragma alloc_text(PAGE,AcpiEcDisconnectHandler)
  24. #endif
  25. UCHAR rgHexDigit[] = "0123456789ABCDEF";
  26. NTSTATUS
  27. AcpiEcRunQueryMethod (
  28. IN PECDATA EcData,
  29. IN ULONG QueryIndex
  30. )
  31. /*++
  32. Routine Description:
  33. This routine runs the query control method that corresponds to the QueryIndex.
  34. Arguments:
  35. EcData - Pointer to the EC extension
  36. QueryIndex - The query to run
  37. Return Value:
  38. Status
  39. --*/
  40. {
  41. ACPI_EVAL_INPUT_BUFFER inputBuffer;
  42. NTSTATUS status;
  43. PIO_STACK_LOCATION irpSp;
  44. PIRP irp;
  45. ASSERT (QueryIndex <= MAX_QUERY);
  46. //
  47. // Note: because the ACPI control method is using INPUT data only and
  48. // this information is grabbed before STATUS_PENDING is returned, it is
  49. // safe to allocate the storage for this data on the stack.
  50. //
  51. // However, because this is a method that can be called at DISPATCH_LEVEL
  52. // and because we want to reuse the same irp over and over again, it is not
  53. // safe to call IoBuildDeviceIoControlRequest for this request
  54. //
  55. //
  56. // Initialize the input data
  57. //
  58. RtlZeroMemory( &inputBuffer, sizeof(ACPI_EVAL_INPUT_BUFFER) );
  59. inputBuffer.Signature = ACPI_EVAL_INPUT_BUFFER_SIGNATURE;
  60. inputBuffer.MethodNameAsUlong = '00Q_';
  61. inputBuffer.MethodName[2] = rgHexDigit[ QueryIndex / 16];
  62. inputBuffer.MethodName[3] = rgHexDigit[ QueryIndex % 16];
  63. EcPrint(
  64. EC_NOTE,
  65. ("AcpiEcRunQueryMethod: Running query control method %.4s\n",
  66. inputBuffer.MethodName )
  67. );
  68. //
  69. // Setup the (pre-allocated) Irp
  70. //
  71. irp = EcData->QueryRequest;
  72. irpSp = IoGetNextIrpStackLocation(irp);
  73. //
  74. // Setup the call
  75. //
  76. irpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
  77. irpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_ACPI_ASYNC_EVAL_METHOD;
  78. irpSp->Parameters.DeviceIoControl.InputBufferLength = sizeof(ACPI_EVAL_INPUT_BUFFER);
  79. irpSp->Parameters.DeviceIoControl.OutputBufferLength = 0;
  80. irp->AssociatedIrp.SystemBuffer = &inputBuffer;
  81. //
  82. // only matters if it is buffered
  83. //
  84. irp->Flags |= IRP_INPUT_OPERATION;
  85. //
  86. // We want to reuse this irp, so we need to set a completion routine.
  87. // This will also let us know when the irp is done
  88. //
  89. IoSetCompletionRoutine(
  90. irp,
  91. AcpiEcCompleteQueryMethod,
  92. EcData,
  93. TRUE,
  94. TRUE,
  95. TRUE
  96. );
  97. //
  98. // Pass request to Pdo (ACPI driver). This is an asynchronous request
  99. //
  100. status = IoCallDriver(EcData->Pdo, irp);
  101. //
  102. // What happened?
  103. //
  104. if (!NT_SUCCESS(status)) {
  105. EcPrint(
  106. EC_LOW,
  107. ("AcpiEcRunQueryMethod: Query Control Method failed, status = %Lx\n",
  108. status )
  109. );
  110. }
  111. //
  112. // Done
  113. //
  114. return status;
  115. }
  116. NTSTATUS
  117. AcpiEcCompleteQueryMethod (
  118. IN PDEVICE_OBJECT DeviceObject,
  119. IN PIRP Irp,
  120. IN PVOID Context
  121. )
  122. /*++
  123. Routine Description:
  124. This is the routine that is called after the ACPI driver has finished
  125. running the _Qxx method. This routine is here so that we can do the
  126. 'correct' thing after the method is complete.
  127. Note: We cannot touch Irp->AssociatedIrp.SystemBuffer here because the
  128. stack that it might have been on has probably been reclaimed. If it becomes
  129. important to touch this data, then we must allocate the parameters as
  130. part of non-paged pool
  131. Arguments:
  132. DeviceObject - Us
  133. Irp - Request that was completed
  134. Context - EcData;
  135. --*/
  136. {
  137. KIRQL OldIrql;
  138. PECDATA EcData = (PECDATA) Context;
  139. BOOLEAN ProcessQuery;
  140. #if DEBUG
  141. //
  142. // What happened to the irp?
  143. //
  144. if (!NT_SUCCESS(Irp->IoStatus.Status)) {
  145. EcPrint(
  146. EC_LOW,
  147. ("AcpiEcCompleteQueryMethod: Query Method failed, status = %08x\n",
  148. Irp->IoStatus.Status )
  149. );
  150. } else {
  151. EcPrint(
  152. EC_NOTE,
  153. ("AcpiEcCompleteQueryMethod: QueryMethod succeeded.\n")
  154. );
  155. }
  156. #endif
  157. ProcessQuery = FALSE;
  158. KeAcquireSpinLock (&EcData->Lock, &OldIrql);
  159. switch (EcData->QueryState) {
  160. case EC_QUERY_DISPATCH:
  161. EcData->QueryState = EC_QUERY_DISPATCH_COMPLETE;
  162. break;
  163. case EC_QUERY_DISPATCH_WAITING:
  164. EcData->QueryState = EC_QUERY_IDLE;
  165. ProcessQuery = TRUE;
  166. break;
  167. default:
  168. // internal error
  169. ASSERT (FALSE);
  170. break;
  171. }
  172. KeReleaseSpinLock (&EcData->Lock, OldIrql);
  173. if (ProcessQuery) {
  174. AcpiEcDispatchQueries(EcData);
  175. }
  176. return STATUS_MORE_PROCESSING_REQUIRED;
  177. }
  178. VOID
  179. AcpiEcDispatchQueries (
  180. IN PECDATA EcData
  181. )
  182. {
  183. KIRQL OldIrql;
  184. ULONG i, j;
  185. ULONG Id, Vector;
  186. PVECTOR_HANDLER Handler;
  187. PVOID Context;
  188. KeAcquireSpinLock (&EcData->Lock, &OldIrql);
  189. //
  190. // Run the vector pending list
  191. //
  192. while (EcData->VectorHead) {
  193. Id = EcData->VectorHead;
  194. Vector = EcData->VectorTable[Id].Vector;
  195. i = Vector / BITS_PER_ULONG;
  196. j = 1 << (Vector % BITS_PER_ULONG);
  197. //
  198. // Remove vector from list
  199. //
  200. EcData->QuerySet[i] &= ~j;
  201. EcData->VectorHead = EcData->VectorTable[Id].Next;
  202. //
  203. // Dispatch it
  204. //
  205. Handler = EcData->VectorTable[Id].Handler;
  206. Context = EcData->VectorTable[Id].Context;
  207. KeReleaseSpinLock (&EcData->Lock, OldIrql);
  208. Handler (Vector, Context);
  209. KeAcquireSpinLock (&EcData->Lock, &OldIrql);
  210. }
  211. //
  212. // If QueryState is idle, start dispatching
  213. //
  214. if (EcData->QueryState == EC_QUERY_IDLE) {
  215. //
  216. // Run query pending list
  217. //
  218. while (EcData->QueryHead) {
  219. Id = EcData->QueryHead;
  220. i = Id / BITS_PER_ULONG;
  221. j = 1 << (Id % BITS_PER_ULONG);
  222. //
  223. // Remove query from list
  224. //
  225. EcData->QuerySet[i] &= ~j;
  226. EcData->QueryHead = EcData->QueryMap[Id];
  227. EcData->QueryState = EC_QUERY_DISPATCH;
  228. KeReleaseSpinLock (&EcData->Lock, OldIrql);
  229. //
  230. // Run control method for this event
  231. //
  232. EcPrint(EC_NOTE, ("AcpiEcDispatchQueries: Query %x\n", Id));
  233. AcpiEcRunQueryMethod (EcData, Id);
  234. //
  235. // If irp is complete the state will be dispatch_complete, loop
  236. // and process the next bit. Else, wait for irp to return
  237. //
  238. KeAcquireSpinLock (&EcData->Lock, &OldIrql);
  239. if (EcData->QueryState == EC_QUERY_DISPATCH) {
  240. //
  241. // It's not complete, wait for it to complete
  242. //
  243. EcData->QueryState = EC_QUERY_DISPATCH_WAITING;
  244. KeReleaseSpinLock (&EcData->Lock, OldIrql);
  245. return ;
  246. }
  247. }
  248. //
  249. // No longer dispatching query events
  250. //
  251. EcData->QueryState = EC_QUERY_IDLE;
  252. //
  253. // If unload is pending, check to see if the device can be unloaded now
  254. //
  255. if (EcData->DeviceState == EC_DEVICE_UNLOAD_PENDING) {
  256. AcpiEcUnloadPending (EcData);
  257. }
  258. }
  259. KeReleaseSpinLock (&EcData->Lock, OldIrql);
  260. }
  261. VOID
  262. AcpiEcUnloadPending (
  263. IN PECDATA EcData
  264. )
  265. /*++
  266. Routine Description:
  267. Called when state is unload pending and some portion of the state
  268. has gone idle. If the entire device state is idle, the unload is
  269. stated.
  270. Arguments:
  271. EcData - Pointer to embedded controller to service.
  272. Return Value:
  273. --*/
  274. {
  275. ASSERT (EcData->DeviceState == EC_DEVICE_UNLOAD_PENDING);
  276. //
  277. // Check if device is idle for unload operation
  278. //
  279. if (EcData->QueryState == EC_QUERY_IDLE &&
  280. EcData->InService == FALSE &&
  281. EcData->IoState == EC_IO_NONE) {
  282. //
  283. // Promote unloading device state to next step (which
  284. // is to clean up the fake ISR timer)
  285. //
  286. EcData->DeviceState = EC_DEVICE_UNLOAD_CANCEL_TIMER;
  287. }
  288. }
  289. NTSTATUS
  290. AcpiEcConnectHandler (
  291. IN PECDATA EcData,
  292. IN PIRP Irp
  293. )
  294. /*++
  295. Routine Description:
  296. This functions connects a specific handled to an Ec query vector
  297. Arguments:
  298. EcData - Pointer to embedded controller to service.
  299. Irp - IOCTL conntain connect request
  300. Return Value:
  301. --*/
  302. {
  303. KIRQL OldIrql;
  304. PVOID LockPtr;
  305. NTSTATUS Status;
  306. PIO_STACK_LOCATION IrpSp;
  307. PEC_HANDLER_REQUEST Req;
  308. PVECTOR_TABLE Vector;
  309. ULONG by, bi, i, j;
  310. ULONG TableIndex;
  311. PAGED_CODE ();
  312. //
  313. // Get request
  314. //
  315. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  316. Req = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  317. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(EC_HANDLER_REQUEST)) {
  318. return STATUS_BUFFER_TOO_SMALL;
  319. }
  320. //
  321. // Setup data concerning request
  322. //
  323. by = Req->Vector / BITS_PER_ULONG;
  324. bi = 1 << (Req->Vector % BITS_PER_ULONG);
  325. //
  326. // Lock device
  327. //
  328. LockPtr = MmLockPagableCodeSection(AcpiEcConnectHandler);
  329. KeAcquireSpinLock (&EcData->Lock, &OldIrql);
  330. //
  331. // If device handler already set, then fail the request
  332. //
  333. Status = STATUS_UNSUCCESSFUL;
  334. if (!(EcData->QueryType[by] & bi)) {
  335. //
  336. // No handler set, allocate vector entry for it
  337. //
  338. EcData->QueryType[by] |= bi;
  339. if (!EcData->VectorFree) {
  340. //
  341. // No free entries on vector table, make some
  342. //
  343. i = EcData->VectorTableSize;
  344. Vector = ExAllocatePoolWithTag (
  345. NonPagedPool,
  346. sizeof (VECTOR_TABLE) * (i + 4),
  347. 'V_CE'
  348. );
  349. if (!Vector) {
  350. Status = STATUS_INSUFFICIENT_RESOURCES;
  351. goto AcpiEcConnectHandlerExit;
  352. }
  353. if (EcData->VectorTable) {
  354. memcpy (Vector, EcData->VectorTable, sizeof (VECTOR_TABLE) * i);
  355. ExFreePool (EcData->VectorTable);
  356. }
  357. EcData->VectorTableSize += 4;
  358. EcData->VectorTable = Vector;
  359. for (j=0; j < 4; j++) {
  360. EcData->VectorTable[i+j].Next = EcData->VectorFree;
  361. EcData->VectorFree = (UCHAR) (i+j);
  362. }
  363. }
  364. TableIndex = EcData->VectorFree;
  365. Vector = &EcData->VectorTable[TableIndex];
  366. EcData->VectorFree = Vector->Next;
  367. //
  368. // Build mapping for the vector
  369. //
  370. if (EcData->QueryMap[Req->Vector]) {
  371. //
  372. // Vector is in query pending list, remove it
  373. //
  374. EcData->QuerySet[by] &= ~bi;
  375. for (i = EcData->QueryHead; i; i = EcData->QueryMap[i]) {
  376. if (EcData->QueryMap[i] == Req->Vector) {
  377. EcData->QueryMap[i] = EcData->QueryMap[Req->Vector];
  378. break;
  379. }
  380. }
  381. }
  382. EcData->QueryMap[Req->Vector] = (UCHAR) TableIndex;
  383. //
  384. // Initialize vector handler
  385. //
  386. Vector->Next = 0;
  387. Vector->Vector = (UCHAR) Req->Vector;
  388. Vector->Handler = Req->Handler;
  389. Vector->Context = Req->Context;
  390. Req->AllocationHandle = (PVOID)((ULONG_PTR)TableIndex);
  391. Status = STATUS_SUCCESS;
  392. }
  393. AcpiEcConnectHandlerExit:
  394. //
  395. // Unlock device and return status
  396. //
  397. KeReleaseSpinLock (&EcData->Lock, OldIrql);
  398. MmUnlockPagableImageSection(LockPtr);
  399. return Status;
  400. }
  401. NTSTATUS
  402. AcpiEcDisconnectHandler (
  403. IN PECDATA EcData,
  404. IN PIRP Irp
  405. )
  406. /*++
  407. Routine Description:
  408. This functions disconnects a specific handled to an Ec query vector
  409. Arguments:
  410. EcData - Pointer to embedded controller to service.
  411. Irp - IOCTL conntain connect request
  412. Return Value:
  413. --*/
  414. {
  415. KIRQL OldIrql;
  416. PVOID LockPtr;
  417. NTSTATUS Status;
  418. PIO_STACK_LOCATION IrpSp;
  419. PEC_HANDLER_REQUEST Req;
  420. ULONG by, bi, i;
  421. ULONG TableIndex;
  422. PAGED_CODE ();
  423. //
  424. // Get request
  425. //
  426. IrpSp = IoGetCurrentIrpStackLocation(Irp);
  427. Req = IrpSp->Parameters.DeviceIoControl.Type3InputBuffer;
  428. if (IrpSp->Parameters.DeviceIoControl.InputBufferLength < sizeof(EC_HANDLER_REQUEST)) {
  429. return STATUS_BUFFER_TOO_SMALL;
  430. }
  431. //
  432. // Setup data concerning request
  433. //
  434. by = Req->Vector / BITS_PER_ULONG;
  435. bi = 1 << (Req->Vector % BITS_PER_ULONG);
  436. //
  437. // Lock device
  438. //
  439. LockPtr = MmLockPagableCodeSection(AcpiEcDisconnectHandler);
  440. KeAcquireSpinLock (&EcData->Lock, &OldIrql);
  441. //
  442. // If device handler already set, then fail the request
  443. //
  444. Status = STATUS_UNSUCCESSFUL;
  445. if (EcData->QueryType[by] & bi) {
  446. //
  447. // Clear handler
  448. //
  449. EcData->QueryType[by] &= ~bi;
  450. TableIndex = EcData->QueryMap[Req->Vector];
  451. ASSERT (Req->AllocationHandle == (PVOID)((ULONG_PTR)TableIndex));
  452. //
  453. // If pending, drop it
  454. //
  455. if (EcData->QuerySet[by] & bi) {
  456. EcData->QuerySet[by] &= ~bi;
  457. for (i = EcData->VectorHead; i; i = EcData->VectorTable[i].Next) {
  458. if (EcData->VectorTable[i].Next == TableIndex) {
  459. EcData->VectorTable[i].Next = EcData->VectorTable[TableIndex].Next;
  460. break;
  461. }
  462. }
  463. }
  464. //
  465. // Put onto free list
  466. //
  467. EcData->VectorTable[TableIndex].Next = EcData->VectorFree;
  468. EcData->VectorFree = (UCHAR) TableIndex;
  469. Status = STATUS_SUCCESS;
  470. }
  471. //
  472. // Unlock device and return status
  473. //
  474. KeReleaseSpinLock (&EcData->Lock, OldIrql);
  475. MmUnlockPagableImageSection(LockPtr);
  476. return Status;
  477. }