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.

786 lines
16 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. vector.c
  5. Abstract:
  6. This module is how external drivers add / remove hooks to deal with
  7. ACPI Gpe Events
  8. Author:
  9. Stephane Plante
  10. Environment:
  11. NT Kernel Mode Driver Only
  12. --*/
  13. #include "pch.h"
  14. //
  15. // Table for installed GPE handlers
  16. //
  17. PGPE_VECTOR_ENTRY GpeVectorTable = NULL;
  18. UCHAR GpeVectorFree = 0;
  19. ULONG GpeVectorTableSize = 0;
  20. VOID
  21. ACPIVectorBuildVectorMasks(
  22. VOID
  23. )
  24. /*++
  25. Routine Description:
  26. This routine is called to walk the GPE Vector Table and properly
  27. enable all the events that we think should be enabled.
  28. This routine is typically called after we have loaded a new set
  29. of tables or we have unloaded an existing set of tables.
  30. We have to call this routine because at the start of the operation,
  31. we clear out all the knowledge of these additional vectors.
  32. This routine is called with GPEs disabled and the GPE Table locked
  33. acquired.
  34. Arguments:
  35. None
  36. Return Value:
  37. None
  38. --*/
  39. {
  40. BOOLEAN installed;
  41. ULONG i;
  42. ULONG mode;
  43. //
  44. // Walk all the elements in the table
  45. //
  46. for (i = 0; i < GpeVectorTableSize; i++) {
  47. //
  48. // Does this entry point to a vector object?
  49. //
  50. if (GpeVectorTable[i].GpeVectorObject == NULL) {
  51. continue;
  52. }
  53. if (GpeVectorTable[i].GpeVectorObject->Mode == LevelSensitive) {
  54. mode = ACPI_GPE_LEVEL_INSTALL;
  55. } else {
  56. mode = ACPI_GPE_EDGE_INSTALL;
  57. }
  58. //
  59. // Install the GPE into bit-maps. This validates the GPE number.
  60. //
  61. installed = ACPIGpeInstallRemoveIndex(
  62. GpeVectorTable[i].GpeVectorObject->Vector,
  63. mode,
  64. ACPI_GPE_HANDLER,
  65. &(GpeVectorTable[i].GpeVectorObject->HasControlMethod)
  66. );
  67. if (!installed) {
  68. ACPIPrint( (
  69. ACPI_PRINT_CRITICAL,
  70. "ACPIVectorBuildVectorMasks: Could not reenable Vector Object %d\n",
  71. i
  72. ) );
  73. }
  74. }
  75. }
  76. NTSTATUS
  77. ACPIVectorClear(
  78. PDEVICE_OBJECT AcpiDeviceObject,
  79. PVOID GpeVectorObject
  80. )
  81. /*++
  82. Routine Description:
  83. Clear the GPE_STS (status) bit associated with a vector object
  84. Arguments:
  85. AcpiDeviceObject - The ACPI device object
  86. GpeVectorObject - Pointer to the vector object returned by
  87. ACPIGpeConnectVector
  88. Return Value
  89. Returns status
  90. --*/
  91. {
  92. PGPE_VECTOR_OBJECT localVectorObject = GpeVectorObject;
  93. ULONG gpeIndex;
  94. ULONG bitOffset;
  95. ULONG i;
  96. ASSERT( localVectorObject );
  97. //
  98. // What is the GPE index for this vector?
  99. //
  100. gpeIndex = localVectorObject->Vector;
  101. //
  102. // Calculate the proper mask to use
  103. //
  104. bitOffset = gpeIndex % 8;
  105. //
  106. // Calculate the offset for the register
  107. //
  108. i = ACPIGpeIndexToGpeRegister (gpeIndex);
  109. //
  110. // Clear the register
  111. //
  112. ACPIWriteGpeStatusRegister (i, (UCHAR) (1 << bitOffset));
  113. return STATUS_SUCCESS;
  114. }
  115. NTSTATUS
  116. ACPIVectorConnect(
  117. PDEVICE_OBJECT AcpiDeviceObject,
  118. ULONG GpeVector,
  119. KINTERRUPT_MODE GpeMode,
  120. BOOLEAN Sharable,
  121. PGPE_SERVICE_ROUTINE ServiceRoutine,
  122. PVOID ServiceContext,
  123. PVOID *GpeVectorObject
  124. )
  125. /*++
  126. Routine Description:
  127. Connects a handler to a general-purpose event.
  128. Arguments:
  129. AcpiDeviceObject - The ACPI object
  130. GpeVector - The event number to connect to
  131. GpeMode - Level or edge interrupt
  132. Sharable - Can this level be shared?
  133. ServiceRoutine - Address of the handler
  134. ServiceContext - Context object to be passed to the handler
  135. *GpeVectorObject - Pointer to where the vector object is returned
  136. Return Value
  137. Returns status
  138. --*/
  139. {
  140. BOOLEAN installed;
  141. KIRQL oldIrql;
  142. NTSTATUS status;
  143. PGPE_VECTOR_OBJECT localVectorObject;
  144. ULONG mode;
  145. ASSERT( GpeVectorObject );
  146. ACPIPrint( (
  147. ACPI_PRINT_INFO,
  148. "ACPIVectorConnect: Attach GPE handler\n"
  149. ) );
  150. status = STATUS_SUCCESS;
  151. *GpeVectorObject = NULL;
  152. //
  153. // Do GPEs exist on this machine?
  154. //
  155. if (AcpiInformation->GpeSize == 0) {
  156. return STATUS_UNSUCCESSFUL;
  157. }
  158. //
  159. // Validate the vector number (GPE number)
  160. //
  161. if ( !ACPIGpeValidIndex(GpeVector) ) {
  162. return STATUS_INVALID_PARAMETER_2;
  163. }
  164. //
  165. // Create and initialize a vector object
  166. //
  167. localVectorObject = ExAllocatePoolWithTag (
  168. NonPagedPool,
  169. sizeof(GPE_VECTOR_OBJECT),
  170. ACPI_SHARED_GPE_POOLTAG
  171. );
  172. if (localVectorObject == NULL) {
  173. return STATUS_INSUFFICIENT_RESOURCES;
  174. }
  175. RtlZeroMemory( localVectorObject, sizeof(GPE_VECTOR_OBJECT) );
  176. localVectorObject->Vector = GpeVector;
  177. localVectorObject->Handler = ServiceRoutine;
  178. localVectorObject->Context = ServiceContext;
  179. localVectorObject->Mode = GpeMode;
  180. //
  181. // We don't implement anything other than sharable...
  182. //
  183. localVectorObject->Sharable = Sharable;
  184. //
  185. // Level/Edge mode for ACPIGpeInstallRemoveIndex()
  186. //
  187. if (GpeMode == LevelSensitive) {
  188. mode = ACPI_GPE_LEVEL_INSTALL;
  189. } else {
  190. mode = ACPI_GPE_EDGE_INSTALL;
  191. }
  192. //
  193. // Lock the global tables
  194. //
  195. KeAcquireSpinLock (&GpeTableLock, &oldIrql);
  196. //
  197. // Disable GPEs while we are installing the handler
  198. //
  199. ACPIGpeEnableDisableEvents(FALSE);
  200. //
  201. // Install the GPE into bit-maps. This validates the GPE number.
  202. //
  203. installed = ACPIGpeInstallRemoveIndex(
  204. GpeVector,
  205. mode,
  206. ACPI_GPE_HANDLER,
  207. &(localVectorObject->HasControlMethod)
  208. );
  209. if (!installed) {
  210. status = STATUS_UNSUCCESSFUL;
  211. } else {
  212. //
  213. // Install GPE handler into vector table.
  214. //
  215. installed = ACPIVectorInstall(
  216. GpeVector,
  217. localVectorObject
  218. );
  219. if (!installed) {
  220. ACPIGpeInstallRemoveIndex(
  221. GpeVector,
  222. ACPI_GPE_REMOVE,
  223. 0,
  224. &localVectorObject->HasControlMethod
  225. );
  226. status = STATUS_UNSUCCESSFUL;
  227. }
  228. }
  229. if (!NT_SUCCESS(status)) {
  230. ExFreePool (localVectorObject);
  231. } else {
  232. *GpeVectorObject = localVectorObject;
  233. }
  234. //
  235. // Update hardware to match us
  236. //
  237. ACPIGpeEnableDisableEvents (TRUE);
  238. //
  239. // Unlock tables and return status
  240. //
  241. KeReleaseSpinLock (&GpeTableLock, oldIrql);
  242. return status;
  243. }
  244. NTSTATUS
  245. ACPIVectorDisable(
  246. PDEVICE_OBJECT AcpiDeviceObject,
  247. PVOID GpeVectorObject
  248. )
  249. /*++
  250. Routine Description:
  251. Temporarily disable a GPE that is already attached to a handler.
  252. Arguments:
  253. AcpiDeviceObject - The ACPI device object
  254. GpeVectorObject - Pointer to the vector object returned by ACPIGpeConnectVector
  255. Return Value
  256. Returns status
  257. --*/
  258. {
  259. PGPE_VECTOR_OBJECT localVectorObject = GpeVectorObject;
  260. KIRQL oldIrql;
  261. ULONG gpeIndex;
  262. ULONG bit;
  263. ULONG i;
  264. //
  265. // The GPE index was validated when the handler was attached
  266. //
  267. gpeIndex = localVectorObject->Vector;
  268. //
  269. // Calculate the mask and index
  270. //
  271. bit = (1 << (gpeIndex % 8));
  272. i = ACPIGpeIndexToGpeRegister (gpeIndex);
  273. //
  274. // Lock the global tables
  275. //
  276. KeAcquireSpinLock (&GpeTableLock, &oldIrql);
  277. //
  278. // Disable GPEs while we are fussing with the enable bits
  279. //
  280. ACPIGpeEnableDisableEvents(FALSE);
  281. //
  282. // Remove the GPE from the enable bit-maps. This event will be completely disabled,
  283. // but the handler has not been removed.
  284. //
  285. GpeEnable [i] &= ~bit;
  286. GpeCurEnable [i] &= ~bit;
  287. ASSERT(!(GpeWakeEnable[i] & bit));
  288. //
  289. // Update hardware to match us
  290. //
  291. ACPIGpeEnableDisableEvents (TRUE);
  292. //
  293. // Unlock tables and return status
  294. //
  295. KeReleaseSpinLock (&GpeTableLock, oldIrql);
  296. ACPIPrint( (
  297. ACPI_PRINT_RESOURCES_2,
  298. "ACPIVectorDisable: GPE %x disabled\n",
  299. gpeIndex
  300. ) );
  301. return STATUS_SUCCESS;
  302. }
  303. NTSTATUS
  304. ACPIVectorDisconnect(
  305. PVOID GpeVectorObject
  306. )
  307. /*++
  308. Routine Description:
  309. Disconnects a handler from a general-purpose event.
  310. Arguments:
  311. GpeVectorObject - Pointer to the vector object returned by
  312. ACPIGpeConnectVector
  313. Return Value
  314. Returns status
  315. --*/
  316. {
  317. BOOLEAN removed;
  318. KIRQL oldIrql;
  319. NTSTATUS status = STATUS_SUCCESS;
  320. PGPE_VECTOR_OBJECT gpeVectorObj = GpeVectorObject;
  321. ACPIPrint( (
  322. ACPI_PRINT_INFO,
  323. "ACPIVectorDisconnect: Detach GPE handler\n"
  324. ) );
  325. //
  326. // Lock the global tables
  327. //
  328. KeAcquireSpinLock (&GpeTableLock, &oldIrql);
  329. //
  330. // Disable GPEs while we are removing the handler
  331. //
  332. ACPIGpeEnableDisableEvents (FALSE);
  333. //
  334. // Remove GPE handler From vector table.
  335. //
  336. ACPIVectorRemove(gpeVectorObj->Vector);
  337. //
  338. // Remove the GPE from the bit-maps. Fall back to using control method
  339. // if available.
  340. //
  341. removed = ACPIGpeInstallRemoveIndex(
  342. gpeVectorObj->Vector,
  343. ACPI_GPE_REMOVE,
  344. 0,
  345. &(gpeVectorObj->HasControlMethod)
  346. );
  347. if (!removed) {
  348. status = STATUS_UNSUCCESSFUL;
  349. }
  350. //
  351. // Update hardware to match us
  352. //
  353. ACPIGpeEnableDisableEvents(TRUE);
  354. //
  355. // Unlock tables and return status
  356. //
  357. KeReleaseSpinLock (&GpeTableLock, oldIrql);
  358. //
  359. // Free the vector object, it's purpose is done.
  360. //
  361. if (status == STATUS_SUCCESS) {
  362. ExFreePool (GpeVectorObject);
  363. }
  364. return status;
  365. }
  366. NTSTATUS
  367. ACPIVectorEnable(
  368. PDEVICE_OBJECT AcpiDeviceObject,
  369. PVOID GpeVectorObject
  370. )
  371. /*++
  372. Routine Description:
  373. Enable (a previously disabled) GPE that is already attached to a handler.
  374. Arguments:
  375. AcpiDeviceObject - The ACPI device object
  376. GpeVectorObject - Pointer to the vector object returned by ACPIGpeConnectVector
  377. Return Value
  378. Returns status
  379. --*/
  380. {
  381. KIRQL oldIrql;
  382. PGPE_VECTOR_OBJECT localVectorObject = GpeVectorObject;
  383. ULONG bit;
  384. ULONG gpeIndex;
  385. ULONG gpeRegister;
  386. //
  387. // The GPE index was validated when the handler was attached
  388. //
  389. gpeIndex = localVectorObject->Vector;
  390. bit = (1 << (gpeIndex % 8));
  391. gpeRegister = ACPIGpeIndexToGpeRegister (gpeIndex);
  392. //
  393. // Lock the global tables
  394. //
  395. KeAcquireSpinLock (&GpeTableLock, &oldIrql);
  396. //
  397. // Disable GPEs while we are fussing with the enable bits
  398. //
  399. ACPIGpeEnableDisableEvents (FALSE);
  400. //
  401. // Enable the GPE in the bit maps.
  402. //
  403. GpeEnable [gpeRegister] |= bit;
  404. GpeCurEnable [gpeRegister] |= bit;
  405. //
  406. // Update hardware to match us
  407. //
  408. ACPIGpeEnableDisableEvents (TRUE);
  409. //
  410. // Unlock tables and return status
  411. //
  412. KeReleaseSpinLock (&GpeTableLock, oldIrql);
  413. ACPIPrint( (
  414. ACPI_PRINT_RESOURCES_2,
  415. "ACPIVectorEnable: GPE %x enabled\n",
  416. gpeIndex
  417. ) );
  418. return STATUS_SUCCESS;
  419. }
  420. VOID
  421. ACPIVectorFreeEntry (
  422. ULONG TableIndex
  423. )
  424. /*++
  425. Routine Description:
  426. Free a GPE vector table entry.
  427. NOTE: Should be called with the global GpeVectorTable locked.
  428. Arguments:
  429. TableIndex - Index into GPE vector table of entry to be freed
  430. Return Value:
  431. NONE
  432. --*/
  433. {
  434. //
  435. // Put onto free list
  436. //
  437. GpeVectorTable[TableIndex].Next = GpeVectorFree;
  438. GpeVectorFree = (UCHAR) TableIndex;
  439. }
  440. BOOLEAN
  441. ACPIVectorGetEntry (
  442. PULONG TableIndex
  443. )
  444. /*++
  445. Routine Description:
  446. Get a new vector entry from the GPE vector table.
  447. NOTE: Should be called with the global GpeVectorTable locked.
  448. Arguments:
  449. TableIndex - Pointer to where the vector table index of the entry is returned
  450. Return Value:
  451. TRUE - Success
  452. FALSE - Failure
  453. --*/
  454. {
  455. PGPE_VECTOR_ENTRY Vector;
  456. ULONG i, j;
  457. #define NEW_TABLE_ENTRIES 4
  458. if (!GpeVectorFree) {
  459. //
  460. // No free entries on vector table, make some
  461. //
  462. i = GpeVectorTableSize;
  463. Vector = ExAllocatePoolWithTag (
  464. NonPagedPool,
  465. sizeof (GPE_VECTOR_ENTRY) * (i + NEW_TABLE_ENTRIES),
  466. ACPI_SHARED_GPE_POOLTAG
  467. );
  468. if (Vector == NULL) {
  469. return FALSE;
  470. }
  471. //
  472. // Make sure that its in a known state
  473. //
  474. RtlZeroMemory(
  475. Vector,
  476. (sizeof(GPE_VECTOR_ENTRY) * (i + NEW_TABLE_ENTRIES) )
  477. );
  478. //
  479. // Copy old table to new
  480. //
  481. if (GpeVectorTable) {
  482. RtlCopyMemory(
  483. Vector,
  484. GpeVectorTable,
  485. sizeof (GPE_VECTOR_ENTRY) * i
  486. );
  487. ExFreePool (GpeVectorTable);
  488. }
  489. GpeVectorTableSize += NEW_TABLE_ENTRIES;
  490. GpeVectorTable = Vector;
  491. //
  492. // Link new entries
  493. //
  494. for (j=0; j < NEW_TABLE_ENTRIES; j++) {
  495. GpeVectorTable[i+j].Next = (UCHAR) (i+j+1);
  496. }
  497. //
  498. // The last entry in the list gets pointed to 0, because we then
  499. // want to grow this list again
  500. //
  501. GpeVectorTable[i+j-1].Next = 0;
  502. //
  503. // The next free vector the head of the list that we just allocated
  504. //
  505. GpeVectorFree = (UCHAR) i;
  506. }
  507. *TableIndex = GpeVectorFree;
  508. Vector = &GpeVectorTable[GpeVectorFree];
  509. GpeVectorFree = Vector->Next;
  510. return TRUE;
  511. }
  512. BOOLEAN
  513. ACPIVectorInstall(
  514. ULONG GpeIndex,
  515. PGPE_VECTOR_OBJECT GpeVectorObject
  516. )
  517. /*++
  518. Routine Description:
  519. Install a GPE handler into the Map and Vector tables
  520. NOTE: Should be called with the global GpeVectorTable locked, and GPEs disabled
  521. Arguments:
  522. Return Value:
  523. TRUE - Success
  524. FALSE - Failure
  525. --*/
  526. {
  527. ULONG byteIndex;
  528. ULONG tableIndex;
  529. //
  530. // Get an entry in the global vector table
  531. //
  532. if (ACPIVectorGetEntry (&tableIndex)) {
  533. //
  534. // Install the entry into the map table
  535. //
  536. byteIndex = ACPIGpeIndexToByteIndex (GpeIndex);
  537. GpeMap [byteIndex] = (UCHAR) tableIndex;
  538. //
  539. // Install the vector object in the vector table entry
  540. //
  541. GpeVectorTable [tableIndex].GpeVectorObject = GpeVectorObject;
  542. return TRUE;
  543. }
  544. return FALSE;
  545. }
  546. BOOLEAN
  547. ACPIVectorRemove(
  548. ULONG GpeIndex
  549. )
  550. /*++
  551. Routine Description:
  552. Remove a GPE handler from the Map and Vector tables
  553. NOTE: Should be called with the global GpeVectorTable locked,
  554. and GPEs disabled
  555. Arguments:
  556. Return Value:
  557. TRUE - Success
  558. FALSE - Failure
  559. --*/
  560. {
  561. ULONG byteIndex;
  562. ULONG tableIndex;
  563. //
  564. // Get the table index from the map table
  565. //
  566. byteIndex = ACPIGpeIndexToByteIndex (GpeIndex);
  567. tableIndex = GpeMap [byteIndex];
  568. //
  569. // Bounds check
  570. //
  571. if (tableIndex >= GpeVectorTableSize) {
  572. return FALSE;
  573. }
  574. //
  575. // Remember that we don't have this GpeVectorObject anymore
  576. //
  577. GpeVectorTable[tableIndex].GpeVectorObject = NULL;
  578. //
  579. // Free the slot in the master vector table
  580. //
  581. ACPIVectorFreeEntry (tableIndex);
  582. return TRUE;
  583. }