oprgnos.c 42 KB

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