oprgnos.c 42 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786
  1. /*++
  2. Copyright (c) 2012 Minoca Corp. All Rights Reserved
  3. Module Name:
  4. oprgnos.c
  5. Abstract:
  6. This module implements operating system specific support for ACPI Operation
  7. Regions.
  8. Author:
  9. Evan Green 17-Nov-2012
  10. Environment:
  11. Kernel
  12. --*/
  13. //
  14. // ------------------------------------------------------------------- Includes
  15. //
  16. #include <minoca/kernel/driver.h>
  17. #include <minoca/intrface/pci.h>
  18. #include "acpip.h"
  19. #include "namespce.h"
  20. #include "amlos.h"
  21. #include "earlypci.h"
  22. //
  23. // ---------------------------------------------------------------- Definitions
  24. //
  25. //
  26. // ------------------------------------------------------ Data Type Definitions
  27. //
  28. /*++
  29. Structure Description:
  30. This structure describes an Memory Operation Region.
  31. Members:
  32. PhysicalAddress - Stores the physical address of the Operation Region.
  33. Length - Stores the length of the Operation Region, in bytes.
  34. VirtualAddress - Stores the virtual address of the Operation Region.
  35. Offset - Stores the offset (in bytes) to add before accessing the Operation
  36. Region.
  37. --*/
  38. typedef struct _MEMORY_OPERATION_REGION {
  39. PHYSICAL_ADDRESS PhysicalAddress;
  40. ULONGLONG Length;
  41. PVOID VirtualAddress;
  42. ULONG Offset;
  43. } MEMORY_OPERATION_REGION, *PMEMORY_OPERATION_REGION;
  44. /*++
  45. Structure Description:
  46. This structure describes an I/O Port Operation Region.
  47. Members:
  48. Offset - Stores the first I/O port address in this operation region.
  49. Length - Stores the length, in bytes, of the Operation Region.
  50. --*/
  51. typedef struct _IO_PORT_OPERATION_REGION {
  52. USHORT Offset;
  53. USHORT Length;
  54. } IO_PORT_OPERATION_REGION, *PIO_PORT_OPERATION_REGION;
  55. /*++
  56. Structure Description:
  57. This structure describes a PCI Configuration space Operation Region.
  58. Members:
  59. U - Stores a union of the two different interface access methods. Only
  60. one of these methods is used at a time, depending on whether the
  61. device that owns the operation region is started when the operation
  62. region is first accessed.
  63. Access - Stores the PCI configuration access interface.
  64. SpecificAccess - Stores the specific PCI configuration access interface.
  65. UsingSpecificAccess - Stores a boolean indicating whether specific access
  66. is in use or not.
  67. BusNumber - Stores the bus number of the device that owns the Operation
  68. Region. This is only used with specific access.
  69. DeviceNumber - Stores the device number of the device that owns the
  70. Operation Region. This is only used with specific access.
  71. FunctionNumber - Stores the function number of the device that owns the
  72. Operation Region. This is only used with specific access.
  73. Offset - Stores the offset from the beginning of PCI Config space for this
  74. device to the beginning of the Operation Region.
  75. Length - Stores the length, in bytes, of the Operation Region.
  76. AcpiObject - Stores a pointer to the ACPI object that represents the
  77. Operation Region.
  78. Configured - Stores a boolean indicating whether or not the region is
  79. configured and ready for access.
  80. --*/
  81. typedef struct _PCI_CONFIG_OPERATION_REGION {
  82. union {
  83. INTERFACE_PCI_CONFIG_ACCESS Access;
  84. INTERFACE_SPECIFIC_PCI_CONFIG_ACCESS SpecificAccess;
  85. } U;
  86. BOOL UsingSpecificAccess;
  87. ULONG BusNumber;
  88. ULONG DeviceNumber;
  89. ULONG FunctionNumber;
  90. ULONG Offset;
  91. ULONG Length;
  92. PACPI_OBJECT AcpiObject;
  93. BOOL Configured;
  94. } PCI_CONFIG_OPERATION_REGION, *PPCI_CONFIG_OPERATION_REGION;
  95. //
  96. // ----------------------------------------------- Internal Function Prototypes
  97. //
  98. KSTATUS
  99. AcpipCreateUnsupportedOperationRegion (
  100. PVOID AcpiObject,
  101. ULONGLONG Offset,
  102. ULONGLONG Length,
  103. PVOID *OsContext
  104. );
  105. VOID
  106. AcpipDestroyUnsupportedOperationRegion (
  107. PVOID OsContext
  108. );
  109. KSTATUS
  110. AcpipReadUnsupportedOperationRegion (
  111. PVOID OsContext,
  112. ULONGLONG Offset,
  113. ULONG Size,
  114. PVOID Value
  115. );
  116. KSTATUS
  117. AcpipWriteUnsupportedOperationRegion (
  118. PVOID OsContext,
  119. ULONGLONG Offset,
  120. ULONG Size,
  121. PVOID Value
  122. );
  123. KSTATUS
  124. AcpipCreateMemoryOperationRegion (
  125. PVOID AcpiObject,
  126. ULONGLONG Offset,
  127. ULONGLONG Length,
  128. PVOID *OsContext
  129. );
  130. VOID
  131. AcpipDestroyMemoryOperationRegion (
  132. PVOID OsContext
  133. );
  134. KSTATUS
  135. AcpipReadMemoryOperationRegion (
  136. PVOID OsContext,
  137. ULONGLONG Offset,
  138. ULONG Size,
  139. PVOID Value
  140. );
  141. KSTATUS
  142. AcpipWriteMemoryOperationRegion (
  143. PVOID OsContext,
  144. ULONGLONG Offset,
  145. ULONG Size,
  146. PVOID Value
  147. );
  148. KSTATUS
  149. AcpipCreateIoPortOperationRegion (
  150. PVOID AcpiObject,
  151. ULONGLONG Offset,
  152. ULONGLONG Length,
  153. PVOID *OsContext
  154. );
  155. VOID
  156. AcpipDestroyIoPortOperationRegion (
  157. PVOID OsContext
  158. );
  159. KSTATUS
  160. AcpipReadIoPortOperationRegion (
  161. PVOID OsContext,
  162. ULONGLONG Offset,
  163. ULONG Size,
  164. PVOID Value
  165. );
  166. KSTATUS
  167. AcpipWriteIoPortOperationRegion (
  168. PVOID OsContext,
  169. ULONGLONG Offset,
  170. ULONG Size,
  171. PVOID Value
  172. );
  173. KSTATUS
  174. AcpipCreatePciConfigOperationRegion (
  175. PVOID AcpiObject,
  176. ULONGLONG Offset,
  177. ULONGLONG Length,
  178. PVOID *OsContext
  179. );
  180. VOID
  181. AcpipDestroyPciConfigOperationRegion (
  182. PVOID OsContext
  183. );
  184. KSTATUS
  185. AcpipReadPciConfigOperationRegion (
  186. PVOID OsContext,
  187. ULONGLONG Offset,
  188. ULONG Size,
  189. PVOID Value
  190. );
  191. KSTATUS
  192. AcpipWritePciConfigOperationRegion (
  193. PVOID OsContext,
  194. ULONGLONG Offset,
  195. ULONG Size,
  196. PVOID Value
  197. );
  198. KSTATUS
  199. AcpipConfigurePciConfigOperationRegion (
  200. PPCI_CONFIG_OPERATION_REGION OperationRegion
  201. );
  202. //
  203. // -------------------------------------------------------------------- Globals
  204. //
  205. //
  206. // Define an operation region function table for system memory.
  207. //
  208. ACPI_OPERATION_REGION_FUNCTION_TABLE AcpiMemoryOperationRegionTable = {
  209. AcpipCreateMemoryOperationRegion,
  210. AcpipDestroyMemoryOperationRegion,
  211. AcpipReadMemoryOperationRegion,
  212. AcpipWriteMemoryOperationRegion
  213. };
  214. //
  215. // Define an operation region function table for system IO.
  216. //
  217. ACPI_OPERATION_REGION_FUNCTION_TABLE AcpiIoOperationRegionTable = {
  218. AcpipCreateIoPortOperationRegion,
  219. AcpipDestroyIoPortOperationRegion,
  220. AcpipReadIoPortOperationRegion,
  221. AcpipWriteIoPortOperationRegion
  222. };
  223. //
  224. // Define an operation region function table for PCI Configuration Space.
  225. //
  226. ACPI_OPERATION_REGION_FUNCTION_TABLE AcpiPciConfigOperationRegionTable = {
  227. AcpipCreatePciConfigOperationRegion,
  228. AcpipDestroyPciConfigOperationRegion,
  229. AcpipReadPciConfigOperationRegion,
  230. AcpipWritePciConfigOperationRegion
  231. };
  232. //
  233. // Define an operation region function table for the ACPI Embedded Controller.
  234. //
  235. ACPI_OPERATION_REGION_FUNCTION_TABLE AcpiEmbeddedControlOperationRegionTable = {
  236. AcpipCreateUnsupportedOperationRegion,
  237. AcpipDestroyUnsupportedOperationRegion,
  238. AcpipReadUnsupportedOperationRegion,
  239. AcpipWriteUnsupportedOperationRegion
  240. };
  241. //
  242. // Define an operation region function table for SMBus.
  243. //
  244. ACPI_OPERATION_REGION_FUNCTION_TABLE AcpiSmBusOperationRegionTable = {
  245. AcpipCreateUnsupportedOperationRegion,
  246. AcpipDestroyUnsupportedOperationRegion,
  247. AcpipReadUnsupportedOperationRegion,
  248. AcpipWriteUnsupportedOperationRegion
  249. };
  250. //
  251. // Define an operation region function table for CMOS.
  252. //
  253. ACPI_OPERATION_REGION_FUNCTION_TABLE AcpiCmosOperationRegionTable = {
  254. AcpipCreateUnsupportedOperationRegion,
  255. AcpipDestroyUnsupportedOperationRegion,
  256. AcpipReadUnsupportedOperationRegion,
  257. AcpipWriteUnsupportedOperationRegion
  258. };
  259. //
  260. // Define an operation region function table for PCI Base Address Register
  261. // targets.
  262. //
  263. ACPI_OPERATION_REGION_FUNCTION_TABLE AcpiPciBarTargetOperationRegionTable = {
  264. AcpipCreateUnsupportedOperationRegion,
  265. AcpipDestroyUnsupportedOperationRegion,
  266. AcpipReadUnsupportedOperationRegion,
  267. AcpipWriteUnsupportedOperationRegion
  268. };
  269. //
  270. // Define an operation region function table for IPMI.
  271. //
  272. ACPI_OPERATION_REGION_FUNCTION_TABLE AcpiIpmiOperationRegionTable = {
  273. AcpipCreateUnsupportedOperationRegion,
  274. AcpipDestroyUnsupportedOperationRegion,
  275. AcpipReadUnsupportedOperationRegion,
  276. AcpipWriteUnsupportedOperationRegion
  277. };
  278. //
  279. // Define the global operation region access array.
  280. //
  281. PACPI_OPERATION_REGION_FUNCTION_TABLE
  282. AcpiOperationRegionFunctionTable[OperationRegionCount] = {
  283. &AcpiMemoryOperationRegionTable,
  284. &AcpiIoOperationRegionTable,
  285. &AcpiPciConfigOperationRegionTable,
  286. &AcpiEmbeddedControlOperationRegionTable,
  287. &AcpiSmBusOperationRegionTable,
  288. &AcpiCmosOperationRegionTable,
  289. &AcpiPciBarTargetOperationRegionTable,
  290. &AcpiIpmiOperationRegionTable
  291. };
  292. //
  293. // Store the interface UUID of PCI config space accesses.
  294. //
  295. UUID AcpiPciConfigUuid = UUID_PCI_CONFIG_ACCESS;
  296. //
  297. // Store the interface UUID of specific PCI config space accesses.
  298. //
  299. UUID AcpiSpecificPciConfigUuid = UUID_PCI_CONFIG_ACCESS_SPECIFIC;
  300. //
  301. // ------------------------------------------------------------------ Functions
  302. //
  303. //
  304. // --------------------------------------------------------- Internal Functions
  305. //
  306. //
  307. // Dummy functions for unsupported Operation Region types.
  308. //
  309. KSTATUS
  310. AcpipCreateUnsupportedOperationRegion (
  311. PVOID AcpiObject,
  312. ULONGLONG Offset,
  313. ULONGLONG Length,
  314. PVOID *OsContext
  315. )
  316. /*++
  317. Routine Description:
  318. This routine implements a dummy routine for creating an Operation Region
  319. of an unsupported type.
  320. Arguments:
  321. AcpiObject - Supplies a pointer to the ACPI object that represents the new
  322. operation region.
  323. Offset - Supplies an offset in the given address space to start the
  324. Operation Region.
  325. Length - Supplies the length, in bytes, of the Operation Region.
  326. OsContext - Supplies a pointer where an opaque pointer will be returned by
  327. the OS support routines on success. This pointer will be passed to the
  328. OS Operation Region access and destruction routines, and can store
  329. any OS-specific context related to the Operation Region.
  330. Return Value:
  331. STATUS_SUCCESS on success.
  332. Other error codes on failure.
  333. --*/
  334. {
  335. //
  336. // Allow creation so the loading of definition blocks doesn't barf, but
  337. // freak out if these regions are ever accessed.
  338. //
  339. *OsContext = NULL;
  340. return STATUS_SUCCESS;
  341. }
  342. VOID
  343. AcpipDestroyUnsupportedOperationRegion (
  344. PVOID OsContext
  345. )
  346. /*++
  347. Routine Description:
  348. This routine tears down OS support for an ACPI Operation Region of an
  349. unsupported type.
  350. Arguments:
  351. OsContext - Supplies the context pointer supplied by the OS when the
  352. Operation Region was created.
  353. Return Value:
  354. None. No further accesses to the given operation region will be made.
  355. --*/
  356. {
  357. ASSERT(OsContext == NULL);
  358. return;
  359. }
  360. KSTATUS
  361. AcpipReadUnsupportedOperationRegion (
  362. PVOID OsContext,
  363. ULONGLONG Offset,
  364. ULONG Size,
  365. PVOID Value
  366. )
  367. /*++
  368. Routine Description:
  369. This routine performs a read from an unsupported Operation Region. This
  370. code should never execute.
  371. Arguments:
  372. OsContext - Supplies the context pointer supplied by the OS when the
  373. Operation Region was created.
  374. Offset - Supplies the byte offset within the operation region to read from.
  375. Size - Supplies the size of the read to perform. Valid values are 8, 16,
  376. 32, and 64. Other values are considered invalid.
  377. Value - Supplies a pointer where the value from the read will be returned
  378. on success.
  379. Return Value:
  380. STATUS_SUCCESS on success.
  381. Other error codes on failure.
  382. --*/
  383. {
  384. ASSERT(FALSE);
  385. return STATUS_NOT_SUPPORTED;
  386. }
  387. KSTATUS
  388. AcpipWriteUnsupportedOperationRegion (
  389. PVOID OsContext,
  390. ULONGLONG Offset,
  391. ULONG Size,
  392. PVOID Value
  393. )
  394. /*++
  395. Routine Description:
  396. This routine performs a write to an unsupported Operation Region. This code
  397. should never execute.
  398. Arguments:
  399. OsContext - Supplies the context pointer supplied by the OS when the
  400. Operation Region was created.
  401. Offset - Supplies the byte offset within the operation region to write to.
  402. Size - Supplies the size of the write to perform. Valid values are 8, 16,
  403. 32, and 64. Other values are considered invalid.
  404. Value - Supplies the value to write.
  405. Return Value:
  406. STATUS_SUCCESS on success.
  407. Other error codes on failure.
  408. --*/
  409. {
  410. ASSERT(FALSE);
  411. return STATUS_NOT_SUPPORTED;
  412. }
  413. //
  414. // Memory space Operation Region handlers.
  415. //
  416. KSTATUS
  417. AcpipCreateMemoryOperationRegion (
  418. PVOID AcpiObject,
  419. ULONGLONG Offset,
  420. ULONGLONG Length,
  421. PVOID *OsContext
  422. )
  423. /*++
  424. Routine Description:
  425. This routine creates an ACPI Operation Region to physical address space.
  426. Arguments:
  427. AcpiObject - Supplies a pointer to the ACPI object that represents the new
  428. operation region.
  429. Offset - Supplies an offset in the given address space to start the
  430. Operation Region.
  431. Length - Supplies the length, in bytes, of the Operation Region.
  432. OsContext - Supplies a pointer where an opaque pointer will be returned by
  433. the OS support routines on success. This pointer will be passed to the
  434. OS Operation Region access and destruction routines, and can store
  435. any OS-specific context related to the Operation Region.
  436. Return Value:
  437. STATUS_SUCCESS on success.
  438. Other error codes on failure.
  439. --*/
  440. {
  441. PMEMORY_OPERATION_REGION OperationRegion;
  442. ULONG PageSize;
  443. KSTATUS Status;
  444. PageSize = MmPageSize();
  445. //
  446. // Allocate space for the operation region.
  447. //
  448. OperationRegion = MmAllocatePagedPool(sizeof(MEMORY_OPERATION_REGION),
  449. ACPI_OS_ALLOCATION_TAG);
  450. if (OperationRegion == NULL) {
  451. Status = STATUS_INSUFFICIENT_RESOURCES;
  452. goto CreateMemoryOperationRegionEnd;
  453. }
  454. RtlZeroMemory(OperationRegion, sizeof(MEMORY_OPERATION_REGION));
  455. OperationRegion->Offset = Offset - ALIGN_RANGE_DOWN(Offset, PageSize);
  456. OperationRegion->PhysicalAddress = Offset;
  457. OperationRegion->Length = Length;
  458. //
  459. // Map the address as uncached memory.
  460. //
  461. Offset -= OperationRegion->Offset;
  462. Length += OperationRegion->Offset;
  463. OperationRegion->VirtualAddress = MmMapPhysicalAddress(Offset,
  464. Length,
  465. TRUE,
  466. FALSE,
  467. TRUE);
  468. if (OperationRegion->VirtualAddress == NULL) {
  469. RtlDebugPrint("ACPI: Failed to create Memory OpRegion at %I64x, "
  470. "Size %I64x.\n",
  471. Offset,
  472. Length);
  473. ASSERT(FALSE);
  474. Status = STATUS_UNSUCCESSFUL;
  475. goto CreateMemoryOperationRegionEnd;
  476. }
  477. Status = STATUS_SUCCESS;
  478. CreateMemoryOperationRegionEnd:
  479. if (!KSUCCESS(Status)) {
  480. if (OperationRegion != NULL) {
  481. MmFreePagedPool(OperationRegion);
  482. OperationRegion = NULL;
  483. }
  484. }
  485. *OsContext = OperationRegion;
  486. return STATUS_SUCCESS;
  487. }
  488. VOID
  489. AcpipDestroyMemoryOperationRegion (
  490. PVOID OsContext
  491. )
  492. /*++
  493. Routine Description:
  494. This routine tears down OS support for an Memory Operation Region.
  495. Arguments:
  496. OsContext - Supplies the context pointer supplied by the OS when the
  497. Operation Region was created.
  498. Return Value:
  499. None. No further accesses to the given operation region will be made.
  500. --*/
  501. {
  502. PMEMORY_OPERATION_REGION OperationRegion;
  503. ASSERT(OsContext != NULL);
  504. OperationRegion = (PMEMORY_OPERATION_REGION)OsContext;
  505. ASSERT(OperationRegion->VirtualAddress != NULL);
  506. MmUnmapAddress(OperationRegion->VirtualAddress,
  507. OperationRegion->Length + OperationRegion->Offset);
  508. OperationRegion->VirtualAddress = NULL;
  509. MmFreePagedPool(OperationRegion);
  510. return;
  511. }
  512. KSTATUS
  513. AcpipReadMemoryOperationRegion (
  514. PVOID OsContext,
  515. ULONGLONG Offset,
  516. ULONG Size,
  517. PVOID Value
  518. )
  519. /*++
  520. Routine Description:
  521. This routine performs a read from a Memory Operation Region.
  522. Arguments:
  523. OsContext - Supplies the context pointer supplied by the OS when the
  524. Operation Region was created.
  525. Offset - Supplies the byte offset within the operation region to read from.
  526. Size - Supplies the size of the read to perform. Valid values are 8, 16,
  527. 32, and 64. Other values are considered invalid.
  528. Value - Supplies a pointer where the value from the read will be returned
  529. on success.
  530. Return Value:
  531. STATUS_SUCCESS on success.
  532. Other error codes on failure.
  533. --*/
  534. {
  535. PVOID DataPointer;
  536. PMEMORY_OPERATION_REGION OperationRegion;
  537. KSTATUS Status;
  538. ASSERT(OsContext != NULL);
  539. OperationRegion = (PMEMORY_OPERATION_REGION)OsContext;
  540. //
  541. // Check the range.
  542. //
  543. if ((Offset >= OperationRegion->Length) ||
  544. (Offset + (Size / BITS_PER_BYTE) > OperationRegion->Length) ||
  545. (Offset >= Offset + (Size / BITS_PER_BYTE))) {
  546. Status = STATUS_OUT_OF_BOUNDS;
  547. goto ReadMemoryOperationRegionEnd;
  548. }
  549. //
  550. // Perform the read.
  551. //
  552. DataPointer = OperationRegion->VirtualAddress + OperationRegion->Offset +
  553. Offset;
  554. switch (Size) {
  555. case 8:
  556. *((PUCHAR)Value) = *((PUCHAR)DataPointer);
  557. break;
  558. case 16:
  559. *((PUSHORT)Value) = *((PUSHORT)DataPointer);
  560. break;
  561. case 32:
  562. *((PULONG)Value) = *((PULONG)DataPointer);
  563. break;
  564. case 64:
  565. *((PULONGLONG)Value) = *((PULONGLONG)DataPointer);
  566. break;
  567. //
  568. // Allow arbitrary reads on a memory op-region to accomodate the Load
  569. // instruction.
  570. //
  571. default:
  572. ASSERT(IS_ALIGNED(Size, BITS_PER_BYTE));
  573. RtlCopyMemory(Value, DataPointer, Size / BITS_PER_BYTE);
  574. break;
  575. }
  576. Status = STATUS_SUCCESS;
  577. ReadMemoryOperationRegionEnd:
  578. return Status;
  579. }
  580. KSTATUS
  581. AcpipWriteMemoryOperationRegion (
  582. PVOID OsContext,
  583. ULONGLONG Offset,
  584. ULONG Size,
  585. PVOID Value
  586. )
  587. /*++
  588. Routine Description:
  589. This routine performs a write to a Memory Operation Region.
  590. Arguments:
  591. OsContext - Supplies the context pointer supplied by the OS when the
  592. Operation Region was created.
  593. Offset - Supplies the byte offset within the operation region to write to.
  594. Size - Supplies the size of the write to perform. Valid values are 8, 16,
  595. 32, and 64. Other values are considered invalid.
  596. Value - Supplies the value to write.
  597. Return Value:
  598. STATUS_SUCCESS on success.
  599. Other error codes on failure.
  600. --*/
  601. {
  602. PVOID DataPointer;
  603. PMEMORY_OPERATION_REGION OperationRegion;
  604. KSTATUS Status;
  605. ASSERT(OsContext != NULL);
  606. OperationRegion = (PMEMORY_OPERATION_REGION)OsContext;
  607. //
  608. // Check the range.
  609. //
  610. if ((Offset >= OperationRegion->Length) ||
  611. (Offset + (Size / BITS_PER_BYTE) > OperationRegion->Length) ||
  612. (Offset >= Offset + (Size / BITS_PER_BYTE))) {
  613. Status = STATUS_OUT_OF_BOUNDS;
  614. goto WriteMemoryOperationRegionEnd;
  615. }
  616. //
  617. // Perform the write.
  618. //
  619. DataPointer = OperationRegion->VirtualAddress + OperationRegion->Offset +
  620. Offset;
  621. switch (Size) {
  622. case 8:
  623. *((PUCHAR)DataPointer) = *((PUCHAR)Value);
  624. break;
  625. case 16:
  626. *((PUSHORT)DataPointer) = *((PUSHORT)Value);
  627. break;
  628. case 32:
  629. *((PULONG)DataPointer) = *((PULONG)Value);
  630. break;
  631. case 64:
  632. *((PULONGLONG)DataPointer) = *((PULONGLONG)Value);
  633. break;
  634. default:
  635. Status = STATUS_INVALID_PARAMETER;
  636. goto WriteMemoryOperationRegionEnd;
  637. }
  638. Status = STATUS_SUCCESS;
  639. WriteMemoryOperationRegionEnd:
  640. return Status;
  641. }
  642. //
  643. // I/O space Operation Region handlers.
  644. //
  645. KSTATUS
  646. AcpipCreateIoPortOperationRegion (
  647. PVOID AcpiObject,
  648. ULONGLONG Offset,
  649. ULONGLONG Length,
  650. PVOID *OsContext
  651. )
  652. /*++
  653. Routine Description:
  654. This routine creates an ACPI Operation Region to system I/O ports.
  655. Arguments:
  656. AcpiObject - Supplies a pointer to the ACPI object that represents the new
  657. operation region.
  658. Offset - Supplies an offset in the given address space to start the
  659. Operation Region.
  660. Length - Supplies the length, in bytes, of the Operation Region.
  661. OsContext - Supplies a pointer where an opaque pointer will be returned by
  662. the OS support routines on success. This pointer will be passed to the
  663. OS Operation Region access and destruction routines, and can store
  664. any OS-specific context related to the Operation Region.
  665. Return Value:
  666. STATUS_SUCCESS on success.
  667. Other error codes on failure.
  668. --*/
  669. {
  670. PIO_PORT_OPERATION_REGION OperationRegion;
  671. KSTATUS Status;
  672. //
  673. // Allocate space for the operation region.
  674. //
  675. OperationRegion = MmAllocatePagedPool(sizeof(IO_PORT_OPERATION_REGION),
  676. ACPI_OS_ALLOCATION_TAG);
  677. if (OperationRegion == NULL) {
  678. Status = STATUS_INSUFFICIENT_RESOURCES;
  679. goto CreateIoPortOperationRegionEnd;
  680. }
  681. RtlZeroMemory(OperationRegion, sizeof(IO_PORT_OPERATION_REGION));
  682. OperationRegion->Offset = (USHORT)Offset;
  683. OperationRegion->Length = (USHORT)Length;
  684. Status = STATUS_SUCCESS;
  685. CreateIoPortOperationRegionEnd:
  686. if (!KSUCCESS(Status)) {
  687. if (OperationRegion != NULL) {
  688. MmFreePagedPool(OperationRegion);
  689. OperationRegion = NULL;
  690. }
  691. }
  692. *OsContext = OperationRegion;
  693. return STATUS_SUCCESS;
  694. }
  695. VOID
  696. AcpipDestroyIoPortOperationRegion (
  697. PVOID OsContext
  698. )
  699. /*++
  700. Routine Description:
  701. This routine tears down OS support for an I/O Port Operation Region.
  702. Arguments:
  703. OsContext - Supplies the context pointer supplied by the OS when the
  704. Operation Region was created.
  705. Return Value:
  706. None. No further accesses to the given operation region will be made.
  707. --*/
  708. {
  709. PIO_PORT_OPERATION_REGION OperationRegion;
  710. ASSERT(OsContext != NULL);
  711. OperationRegion = (PIO_PORT_OPERATION_REGION)OsContext;
  712. MmFreePagedPool(OperationRegion);
  713. return;
  714. }
  715. KSTATUS
  716. AcpipReadIoPortOperationRegion (
  717. PVOID OsContext,
  718. ULONGLONG Offset,
  719. ULONG Size,
  720. PVOID Value
  721. )
  722. /*++
  723. Routine Description:
  724. This routine performs a read from an I/O port Operation Region.
  725. Arguments:
  726. OsContext - Supplies the context pointer supplied by the OS when the
  727. Operation Region was created.
  728. Offset - Supplies the byte offset within the operation region to read from.
  729. Size - Supplies the size of the read to perform. Valid values are 8, 16,
  730. 32, and 64. Other values are considered invalid.
  731. Value - Supplies a pointer where the value from the read will be returned
  732. on success.
  733. Return Value:
  734. STATUS_SUCCESS on success.
  735. Other error codes on failure.
  736. --*/
  737. {
  738. USHORT ActualOffset;
  739. PIO_PORT_OPERATION_REGION OperationRegion;
  740. KSTATUS Status;
  741. ASSERT(OsContext != NULL);
  742. OperationRegion = (PIO_PORT_OPERATION_REGION)OsContext;
  743. //
  744. // Check the range.
  745. //
  746. if ((Offset >= OperationRegion->Length) ||
  747. (Offset + (Size / BITS_PER_BYTE) > OperationRegion->Length) ||
  748. (Offset >= Offset + (Size / BITS_PER_BYTE))) {
  749. Status = STATUS_OUT_OF_BOUNDS;
  750. goto ReadIoPortOperationRegionEnd;
  751. }
  752. //
  753. // Perform the read.
  754. //
  755. ActualOffset = OperationRegion->Offset + (USHORT)Offset;
  756. switch (Size) {
  757. case 8:
  758. *((PUCHAR)Value) = HlIoPortInByte(ActualOffset);
  759. break;
  760. case 16:
  761. *((PUSHORT)Value) = HlIoPortInShort(ActualOffset);
  762. break;
  763. case 32:
  764. *((PULONG)Value) = HlIoPortInLong(ActualOffset);
  765. break;
  766. case 64:
  767. *((PULONG)Value) = HlIoPortInLong(ActualOffset);
  768. *((PULONG)Value + 1) = HlIoPortInLong(ActualOffset + sizeof(ULONG));
  769. break;
  770. default:
  771. Status = STATUS_INVALID_PARAMETER;
  772. goto ReadIoPortOperationRegionEnd;
  773. }
  774. Status = STATUS_SUCCESS;
  775. ReadIoPortOperationRegionEnd:
  776. return Status;
  777. }
  778. KSTATUS
  779. AcpipWriteIoPortOperationRegion (
  780. PVOID OsContext,
  781. ULONGLONG Offset,
  782. ULONG Size,
  783. PVOID Value
  784. )
  785. /*++
  786. Routine Description:
  787. This routine performs a write to an I/O Port Operation Region.
  788. Arguments:
  789. OsContext - Supplies the context pointer supplied by the OS when the
  790. Operation Region was created.
  791. Offset - Supplies the byte offset within the operation region to write to.
  792. Size - Supplies the size of the write to perform. Valid values are 8, 16,
  793. 32, and 64. Other values are considered invalid.
  794. Value - Supplies the value to write.
  795. Return Value:
  796. STATUS_SUCCESS on success.
  797. Other error codes on failure.
  798. --*/
  799. {
  800. USHORT ActualOffset;
  801. PIO_PORT_OPERATION_REGION OperationRegion;
  802. KSTATUS Status;
  803. ASSERT(OsContext != NULL);
  804. OperationRegion = (PIO_PORT_OPERATION_REGION)OsContext;
  805. //
  806. // Check the range.
  807. //
  808. if ((Offset >= OperationRegion->Length) ||
  809. (Offset + (Size / BITS_PER_BYTE) > OperationRegion->Length) ||
  810. (Offset >= Offset + (Size / BITS_PER_BYTE))) {
  811. Status = STATUS_OUT_OF_BOUNDS;
  812. goto WriteIoPortOperationRegionEnd;
  813. }
  814. //
  815. // Perform the write.
  816. //
  817. ActualOffset = OperationRegion->Offset + (USHORT)Offset;
  818. switch (Size) {
  819. case 8:
  820. HlIoPortOutByte(ActualOffset, *((PUCHAR)Value));
  821. break;
  822. case 16:
  823. HlIoPortOutShort(ActualOffset, *((PUSHORT)Value));
  824. break;
  825. case 32:
  826. HlIoPortOutLong(ActualOffset, *((PULONG)Value));
  827. break;
  828. case 64:
  829. HlIoPortOutLong(ActualOffset, *((PULONG)Value));
  830. HlIoPortOutLong(ActualOffset, *((PULONG)Value + 1));
  831. break;
  832. default:
  833. Status = STATUS_INVALID_PARAMETER;
  834. goto WriteIoPortOperationRegionEnd;
  835. }
  836. Status = STATUS_SUCCESS;
  837. WriteIoPortOperationRegionEnd:
  838. return Status;
  839. }
  840. //
  841. // PCI Configuration space Operation Region handlers.
  842. //
  843. KSTATUS
  844. AcpipCreatePciConfigOperationRegion (
  845. PVOID AcpiObject,
  846. ULONGLONG Offset,
  847. ULONGLONG Length,
  848. PVOID *OsContext
  849. )
  850. /*++
  851. Routine Description:
  852. This routine creates an ACPI Operation Region to PCI Configuration space.
  853. Arguments:
  854. AcpiObject - Supplies a pointer to the ACPI object that represents the new
  855. operation region.
  856. Offset - Supplies an offset in the given address space to start the
  857. Operation Region.
  858. Length - Supplies the length, in bytes, of the Operation Region.
  859. OsContext - Supplies a pointer where an opaque pointer will be returned by
  860. the OS support routines on success. This pointer will be passed to the
  861. OS Operation Region access and destruction routines, and can store
  862. any OS-specific context related to the Operation Region.
  863. Return Value:
  864. STATUS_SUCCESS on success.
  865. Other error codes on failure.
  866. --*/
  867. {
  868. PPCI_CONFIG_OPERATION_REGION OperationRegion;
  869. KSTATUS Status;
  870. //
  871. // Allocate space for the operation region.
  872. //
  873. OperationRegion = MmAllocatePagedPool(sizeof(PCI_CONFIG_OPERATION_REGION),
  874. ACPI_OS_ALLOCATION_TAG);
  875. if (OperationRegion == NULL) {
  876. Status = STATUS_INSUFFICIENT_RESOURCES;
  877. goto CreatePciConfigOperationRegionEnd;
  878. }
  879. RtlZeroMemory(OperationRegion, sizeof(PCI_CONFIG_OPERATION_REGION));
  880. OperationRegion->Offset = Offset;
  881. OperationRegion->Length = Length;
  882. OperationRegion->AcpiObject = (PACPI_OBJECT)AcpiObject;
  883. Status = STATUS_SUCCESS;
  884. CreatePciConfigOperationRegionEnd:
  885. if (!KSUCCESS(Status)) {
  886. if (OperationRegion != NULL) {
  887. MmFreePagedPool(OperationRegion);
  888. OperationRegion = NULL;
  889. }
  890. }
  891. *OsContext = OperationRegion;
  892. return STATUS_SUCCESS;
  893. }
  894. VOID
  895. AcpipDestroyPciConfigOperationRegion (
  896. PVOID OsContext
  897. )
  898. /*++
  899. Routine Description:
  900. This routine tears down OS support for a PCI Configuration space Operation
  901. Region.
  902. Arguments:
  903. OsContext - Supplies the context pointer supplied by the OS when the
  904. Operation Region was created.
  905. Return Value:
  906. None. No further accesses to the given operation region will be made.
  907. --*/
  908. {
  909. PPCI_CONFIG_OPERATION_REGION OperationRegion;
  910. ASSERT(OsContext != NULL);
  911. OperationRegion = (PPCI_CONFIG_OPERATION_REGION)OsContext;
  912. MmFreePagedPool(OperationRegion);
  913. return;
  914. }
  915. KSTATUS
  916. AcpipReadPciConfigOperationRegion (
  917. PVOID OsContext,
  918. ULONGLONG Offset,
  919. ULONG Size,
  920. PVOID Value
  921. )
  922. /*++
  923. Routine Description:
  924. This routine performs a read from a PCI Configuration space Operation
  925. Region.
  926. Arguments:
  927. OsContext - Supplies the context pointer supplied by the OS when the
  928. Operation Region was created.
  929. Offset - Supplies the byte offset within the operation region to read from.
  930. Size - Supplies the size of the read to perform. Valid values are 8, 16,
  931. 32, and 64. Other values are considered invalid.
  932. Value - Supplies a pointer where the value from the read will be returned
  933. on success.
  934. Return Value:
  935. STATUS_SUCCESS on success.
  936. Other error codes on failure.
  937. --*/
  938. {
  939. ULONG ActualOffset;
  940. PVOID DeviceToken;
  941. PPCI_CONFIG_OPERATION_REGION OperationRegion;
  942. BOOL PciLockHeld;
  943. ULONGLONG ReadValue;
  944. KSTATUS Status;
  945. ASSERT(OsContext != NULL);
  946. PciLockHeld = FALSE;
  947. OperationRegion = (PPCI_CONFIG_OPERATION_REGION)OsContext;
  948. if (OperationRegion->Configured == FALSE) {
  949. //
  950. // Acquire the lock to prevent the PCI driver from coming online during
  951. // this early access.
  952. //
  953. AcpipAcquirePciLock();
  954. Status = AcpipConfigurePciConfigOperationRegion(OperationRegion);
  955. //
  956. // Let the lock go now if the region was configured, otherwise, keep it
  957. // through the duration of the access.
  958. //
  959. if (OperationRegion->Configured != FALSE) {
  960. AcpipReleasePciLock();
  961. } else {
  962. PciLockHeld = TRUE;
  963. }
  964. if (!KSUCCESS(Status)) {
  965. goto ReadPciConfigOperationRegionEnd;
  966. }
  967. }
  968. //
  969. // Check the range.
  970. //
  971. if ((Offset >= OperationRegion->Length) ||
  972. (Offset + (Size / BITS_PER_BYTE) > OperationRegion->Length) ||
  973. (Offset >= Offset + (Size / BITS_PER_BYTE))) {
  974. Status = STATUS_OUT_OF_BOUNDS;
  975. goto ReadPciConfigOperationRegionEnd;
  976. }
  977. ActualOffset = OperationRegion->Offset + (ULONG)Offset;
  978. //
  979. // Use the built in early access methods if the region is still not
  980. // configured due to no PCI devices being alive yet.
  981. //
  982. if (OperationRegion->Configured == FALSE) {
  983. ReadValue = AcpipEarlyReadPciConfigurationSpace(
  984. (UCHAR)OperationRegion->BusNumber,
  985. (UCHAR)OperationRegion->DeviceNumber,
  986. (UCHAR)OperationRegion->FunctionNumber,
  987. ActualOffset,
  988. Size / BITS_PER_BYTE);
  989. } else {
  990. //
  991. // Perform the read using normal access or specific access.
  992. //
  993. if (OperationRegion->UsingSpecificAccess == FALSE) {
  994. DeviceToken = OperationRegion->U.Access.DeviceToken;
  995. Status = OperationRegion->U.Access.ReadPciConfig(
  996. DeviceToken,
  997. ActualOffset,
  998. Size / BITS_PER_BYTE,
  999. &ReadValue);
  1000. if (!KSUCCESS(Status)) {
  1001. goto ReadPciConfigOperationRegionEnd;
  1002. }
  1003. } else {
  1004. DeviceToken = OperationRegion->U.SpecificAccess.DeviceToken;
  1005. Status = OperationRegion->U.SpecificAccess.ReadPciConfig(
  1006. DeviceToken,
  1007. OperationRegion->BusNumber,
  1008. OperationRegion->DeviceNumber,
  1009. OperationRegion->FunctionNumber,
  1010. ActualOffset,
  1011. Size / BITS_PER_BYTE,
  1012. &ReadValue);
  1013. if (!KSUCCESS(Status)) {
  1014. goto ReadPciConfigOperationRegionEnd;
  1015. }
  1016. }
  1017. }
  1018. RtlCopyMemory(Value, &ReadValue, Size / BITS_PER_BYTE);
  1019. Status = STATUS_SUCCESS;
  1020. ReadPciConfigOperationRegionEnd:
  1021. if (PciLockHeld != FALSE) {
  1022. AcpipReleasePciLock();
  1023. }
  1024. return Status;
  1025. }
  1026. KSTATUS
  1027. AcpipWritePciConfigOperationRegion (
  1028. PVOID OsContext,
  1029. ULONGLONG Offset,
  1030. ULONG Size,
  1031. PVOID Value
  1032. )
  1033. /*++
  1034. Routine Description:
  1035. This routine performs a write to a PCI Configuration space Operation Region.
  1036. Arguments:
  1037. OsContext - Supplies the context pointer supplied by the OS when the
  1038. Operation Region was created.
  1039. Offset - Supplies the byte offset within the operation region to write to.
  1040. Size - Supplies the size of the write to perform. Valid values are 8, 16,
  1041. 32, and 64. Other values are considered invalid.
  1042. Value - Supplies the value to write.
  1043. Return Value:
  1044. STATUS_SUCCESS on success.
  1045. Other error codes on failure.
  1046. --*/
  1047. {
  1048. ULONG ActualOffset;
  1049. PVOID DeviceToken;
  1050. PPCI_CONFIG_OPERATION_REGION OperationRegion;
  1051. BOOL PciLockHeld;
  1052. KSTATUS Status;
  1053. ULONGLONG WriteValue;
  1054. ASSERT(OsContext != NULL);
  1055. PciLockHeld = FALSE;
  1056. OperationRegion = (PPCI_CONFIG_OPERATION_REGION)OsContext;
  1057. if (OperationRegion->Configured == FALSE) {
  1058. //
  1059. // Acquire the lock to prevent the PCI driver from coming online during
  1060. // this early access.
  1061. //
  1062. AcpipAcquirePciLock();
  1063. Status = AcpipConfigurePciConfigOperationRegion(OperationRegion);
  1064. //
  1065. // Let the lock go now if the region was configured, otherwise, keep it
  1066. // through the duration of the access.
  1067. //
  1068. if (OperationRegion->Configured != FALSE) {
  1069. AcpipReleasePciLock();
  1070. } else {
  1071. PciLockHeld = TRUE;
  1072. }
  1073. if (!KSUCCESS(Status)) {
  1074. goto WritePciConfigOperationRegionEnd;
  1075. }
  1076. }
  1077. //
  1078. // Check the range.
  1079. //
  1080. if ((Offset >= OperationRegion->Length) ||
  1081. (Offset + (Size / BITS_PER_BYTE) > OperationRegion->Length) ||
  1082. (Offset >= Offset + (Size / BITS_PER_BYTE))) {
  1083. Status = STATUS_OUT_OF_BOUNDS;
  1084. goto WritePciConfigOperationRegionEnd;
  1085. }
  1086. //
  1087. // Perform the configuration space write.
  1088. //
  1089. ActualOffset = OperationRegion->Offset + (ULONG)Offset;
  1090. WriteValue = 0;
  1091. RtlCopyMemory(&WriteValue, Value, Size / BITS_PER_BYTE);
  1092. //
  1093. // Use the built in early access methods if the region is still not
  1094. // configured due to no PCI devices being alive yet.
  1095. //
  1096. if (OperationRegion->Configured == FALSE) {
  1097. AcpipEarlyWritePciConfigurationSpace(
  1098. (UCHAR)OperationRegion->BusNumber,
  1099. (UCHAR)OperationRegion->DeviceNumber,
  1100. (UCHAR)OperationRegion->FunctionNumber,
  1101. ActualOffset,
  1102. Size / BITS_PER_BYTE,
  1103. WriteValue);
  1104. } else {
  1105. //
  1106. // Perform the read using normal access or specific access.
  1107. //
  1108. if (OperationRegion->UsingSpecificAccess == FALSE) {
  1109. DeviceToken = OperationRegion->U.Access.DeviceToken;
  1110. Status = OperationRegion->U.Access.WritePciConfig(
  1111. DeviceToken,
  1112. ActualOffset,
  1113. Size / BITS_PER_BYTE,
  1114. WriteValue);
  1115. if (!KSUCCESS(Status)) {
  1116. goto WritePciConfigOperationRegionEnd;
  1117. }
  1118. } else {
  1119. DeviceToken = OperationRegion->U.SpecificAccess.DeviceToken;
  1120. Status = OperationRegion->U.SpecificAccess.WritePciConfig(
  1121. DeviceToken,
  1122. OperationRegion->BusNumber,
  1123. OperationRegion->DeviceNumber,
  1124. OperationRegion->FunctionNumber,
  1125. ActualOffset,
  1126. Size / BITS_PER_BYTE,
  1127. WriteValue);
  1128. if (!KSUCCESS(Status)) {
  1129. goto WritePciConfigOperationRegionEnd;
  1130. }
  1131. }
  1132. }
  1133. Status = STATUS_SUCCESS;
  1134. WritePciConfigOperationRegionEnd:
  1135. if (PciLockHeld != FALSE) {
  1136. AcpipReleasePciLock();
  1137. }
  1138. return Status;
  1139. }
  1140. KSTATUS
  1141. AcpipConfigurePciConfigOperationRegion (
  1142. PPCI_CONFIG_OPERATION_REGION OperationRegion
  1143. )
  1144. /*++
  1145. Routine Description:
  1146. This routine attempts to set up a PCI operation region for immediate use.
  1147. Arguments:
  1148. OperationRegion - Supplies a pointer to the operation region to configure.
  1149. Return Value:
  1150. Status code.
  1151. --*/
  1152. {
  1153. ULONGLONG BusAddress;
  1154. PACPI_OBJECT Device;
  1155. BOOL FirstTime;
  1156. PDEVICE OperationRegionDevice;
  1157. PIRP QueryInterfaceIrp;
  1158. PACPI_OBJECT RootDevice;
  1159. KSTATUS Status;
  1160. BOOL UseSpecificAccess;
  1161. UseSpecificAccess = FALSE;
  1162. ASSERT(OperationRegion->Configured == FALSE);
  1163. //
  1164. // Attempt to find the device associated with this PCI config operation
  1165. // region.
  1166. //
  1167. Device = OperationRegion->AcpiObject;
  1168. FirstTime = TRUE;
  1169. while (TRUE) {
  1170. if (FirstTime == FALSE) {
  1171. Device = Device->Parent;
  1172. }
  1173. FirstTime = FALSE;
  1174. while (Device != NULL) {
  1175. if (Device->Type == AcpiObjectDevice) {
  1176. break;
  1177. }
  1178. Device = Device->Parent;
  1179. }
  1180. //
  1181. // If there is no parent device, this is not a valid operation region.
  1182. //
  1183. if (Device == NULL) {
  1184. Status = STATUS_NO_ELIGIBLE_DEVICES;
  1185. goto ConfigurePciConfigOperationRegionEnd;
  1186. }
  1187. //
  1188. // If there is no OS device for the operation region's destination,
  1189. // then this device is not currently ready to be queried for PCI
  1190. // configuration space access.
  1191. //
  1192. OperationRegionDevice = Device->U.Device.OsDevice;
  1193. if (OperationRegionDevice == NULL) {
  1194. //
  1195. // Get the bus address of the namespace object. If this device has
  1196. // no bus address, look up for the next one.
  1197. //
  1198. Status = AcpipGetDeviceBusAddress(Device, &BusAddress);
  1199. if (!KSUCCESS(Status)) {
  1200. continue;
  1201. }
  1202. OperationRegion->BusNumber = 0;
  1203. OperationRegion->DeviceNumber = (ULONG)(BusAddress >> 16);
  1204. OperationRegion->FunctionNumber = (ULONG)(BusAddress & 0xFFFF);
  1205. //
  1206. // Go up the chain looking for a PCI bus or bridge that's set up.
  1207. //
  1208. RootDevice = AcpipGetSystemBusRoot();
  1209. Device = Device->Parent;
  1210. while (Device != RootDevice) {
  1211. if ((Device->Type == AcpiObjectDevice) &&
  1212. (Device->U.Device.IsPciBus != FALSE) &&
  1213. (Device->U.Device.IsDeviceStarted != FALSE)) {
  1214. UseSpecificAccess = TRUE;
  1215. break;
  1216. }
  1217. Device = Device->Parent;
  1218. }
  1219. //
  1220. // If nothing is ready or configured, then use the "early" PCI
  1221. // config access routines.
  1222. //
  1223. if (Device == RootDevice) {
  1224. Status = STATUS_SUCCESS;
  1225. goto ConfigurePciConfigOperationRegionEnd;
  1226. }
  1227. OperationRegionDevice = Device->U.Device.OsDevice;
  1228. }
  1229. //
  1230. // Allocate and send an IRP to the bus driver requesting access
  1231. // to the device's PCI config space.
  1232. //
  1233. QueryInterfaceIrp = IoCreateIrp(OperationRegionDevice,
  1234. IrpMajorStateChange,
  1235. 0);
  1236. if (QueryInterfaceIrp == NULL) {
  1237. Status = STATUS_INSUFFICIENT_RESOURCES;
  1238. goto ConfigurePciConfigOperationRegionEnd;
  1239. }
  1240. QueryInterfaceIrp->MinorCode = IrpMinorQueryInterface;
  1241. //
  1242. // Request configuration space access from the device directly if
  1243. // possible, or request specific access to the device from the bus if
  1244. // the device is not yet started.
  1245. //
  1246. if (UseSpecificAccess != FALSE) {
  1247. QueryInterfaceIrp->U.QueryInterface.Interface =
  1248. &AcpiSpecificPciConfigUuid;
  1249. QueryInterfaceIrp->U.QueryInterface.InterfaceBuffer =
  1250. &(OperationRegion->U.SpecificAccess);
  1251. QueryInterfaceIrp->U.QueryInterface.InterfaceBufferSize =
  1252. sizeof(INTERFACE_SPECIFIC_PCI_CONFIG_ACCESS);
  1253. } else {
  1254. QueryInterfaceIrp->U.QueryInterface.Interface = &AcpiPciConfigUuid;
  1255. QueryInterfaceIrp->U.QueryInterface.InterfaceBuffer =
  1256. &(OperationRegion->U.Access);
  1257. QueryInterfaceIrp->U.QueryInterface.InterfaceBufferSize =
  1258. sizeof(INTERFACE_PCI_CONFIG_ACCESS);
  1259. }
  1260. Status = IoSendSynchronousIrp(QueryInterfaceIrp);
  1261. if (!KSUCCESS(Status)) {
  1262. IoDestroyIrp(QueryInterfaceIrp);
  1263. continue;
  1264. }
  1265. if (!KSUCCESS(IoGetIrpStatus(QueryInterfaceIrp))) {
  1266. IoDestroyIrp(QueryInterfaceIrp);
  1267. continue;
  1268. }
  1269. OperationRegion->UsingSpecificAccess = UseSpecificAccess;
  1270. OperationRegion->Configured = TRUE;
  1271. IoDestroyIrp(QueryInterfaceIrp);
  1272. break;
  1273. }
  1274. ConfigurePciConfigOperationRegionEnd:
  1275. return Status;
  1276. }