Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1139 lines
31 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. devres.c
  5. Abstract:
  6. Device Resources
  7. Author:
  8. Ken Reneris (kenr) March-13-1885
  9. Environment:
  10. Kernel mode only.
  11. Revision History:
  12. --*/
  13. #include "pciport.h"
  14. NTSTATUS
  15. PcipQueryResourceRequirements (
  16. PDEVICE_DATA DeviceData,
  17. PHAL_DEVICE_CONTROL_CONTEXT Context,
  18. PIO_RESOURCE_REQUIREMENTS_LIST *ResourceList
  19. );
  20. NTSTATUS
  21. PcipSetResources (
  22. PDEVICE_DATA DeviceData,
  23. PHAL_DEVICE_CONTROL_CONTEXT Context,
  24. PCM_RESOURCE_LIST ResourceList,
  25. ULONG ListSize
  26. );
  27. #pragma alloc_text(PAGE,PciCtlQueryDeviceId)
  28. #pragma alloc_text(PAGE,PciCtlQueryDeviceUniqueId)
  29. #pragma alloc_text(PAGE,PciCtlQueryDeviceResources)
  30. #pragma alloc_text(PAGE,PciCtlQueryDeviceResourceRequirements)
  31. #pragma alloc_text(PAGE,PciCtlSetDeviceResources)
  32. #pragma alloc_text(PAGE,PciCtlAssignSlotResources)
  33. #pragma alloc_text(PAGE,PcipQueryResourceRequirements)
  34. #pragma alloc_text(PAGE,PcipSetResources)
  35. VOID
  36. PciCtlQueryDeviceId (
  37. PDEVICE_DATA DeviceData,
  38. PHAL_DEVICE_CONTROL_CONTEXT Context
  39. )
  40. /*++
  41. Routine Description:
  42. This function returns the device id for the particular slot.
  43. Arguments:
  44. DeviceData - Slot data information for the specificied slot
  45. Context - Slot control context of the request
  46. Return Value:
  47. The slot control is completed
  48. --*/
  49. {
  50. NTSTATUS Status;
  51. PPCI_COMMON_CONFIG PciData;
  52. PWCHAR DeviceID;
  53. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  54. ULONG length;
  55. ULONG IDNumber;
  56. PAGED_CODE();
  57. //
  58. // Read the PCI device's info
  59. //
  60. PciData = (PPCI_COMMON_CONFIG) buffer;
  61. PcipReadConfig (Context->Handler, DeviceData, PciData);
  62. //
  63. // Determine which device ID the caller wants back
  64. //
  65. IDNumber = *((PULONG) Context->DeviceControl.Buffer);
  66. //
  67. // For PCI devices:
  68. // ID #0 is the specific PCI device ID.
  69. // ID #1 is the compatible device ID based on the BaseClass & SubClass fields
  70. //
  71. Status = STATUS_NO_MORE_ENTRIES;
  72. DeviceID = (PWCHAR) Context->DeviceControl.Buffer;
  73. if (IDNumber == 0) {
  74. //
  75. // Return the PCI device ID
  76. //
  77. swprintf (DeviceID, PCI_ID, PciData->VendorID, PciData->DeviceID);
  78. Status = STATUS_SUCCESS;
  79. }
  80. if (IDNumber == 1) {
  81. //
  82. // Return the first compatible device id for the device
  83. //
  84. if ( (PciData->BaseClass == 0 &&
  85. PciData->SubClass == 1 &&
  86. PciData->ProgIf == 0) ||
  87. (PciData->BaseClass == 3 &&
  88. PciData->SubClass == 0 &&
  89. PciData->ProgIf == 0) ) {
  90. //
  91. // This is an industry standard VGA controller
  92. //
  93. swprintf (DeviceID, PNP_VGA);
  94. Status = STATUS_SUCCESS;
  95. }
  96. if (PciData->BaseClass == 1 &&
  97. PciData->SubClass == 0 &&
  98. PciData->ProgIf == 0) {
  99. //
  100. // This is an industry standard IDE controller
  101. //
  102. swprintf (DeviceID, PNP_IDE);
  103. Status = STATUS_SUCCESS;
  104. }
  105. }
  106. PcipCompleteDeviceControl (Status, Context, DeviceData);
  107. }
  108. VOID
  109. PciCtlQueryDeviceUniqueId (
  110. PDEVICE_DATA DeviceData,
  111. PHAL_DEVICE_CONTROL_CONTEXT Context
  112. )
  113. /*++
  114. Routine Description:
  115. This function returns a unique device id for the particular slot.
  116. The id is a sequence of numbers separated by dots ('.'). The first
  117. number is the bus number of the root of the heirarchy of PCI buses
  118. that the slot belongs to. The last number in the sequence is the
  119. slot number in question. A possibly empty set of numbers in between
  120. these two, represents the slot numbers of intermediate PCI-PCI bridges
  121. in the hierarchy between the root bus and the slot.
  122. For example, L"0.1.2.3":
  123. 0 PCI bus number of the root of the heirarchy.
  124. 1 Slot number within PCI bus 0 were a PCI-PCI bridge is
  125. located, the secondary bus that it bridges to is PCI bus X.
  126. 2 Slot number within PCI bus X were a PCI-PCI bridge is
  127. located, the secondary bus that it bridges to is PCI bus Y.
  128. 3 Slot number within PCI bus Y for which we are wanting to
  129. obtain the unique id (i.e. the targer of this control operation).
  130. Arguments:
  131. DeviceData - Slot data information for the specificied slot
  132. Context - Slot control context of the request
  133. Return Value:
  134. The slot control is completed
  135. --*/
  136. {
  137. NTSTATUS Status;
  138. PBUS_HANDLER BusHandler;
  139. PBUS_HANDLER ParentHandler;
  140. PWCHAR UniqueDeviceId;
  141. PWCHAR UniqueDeviceIdEnd;
  142. PDEVICE_HANDLER_OBJECT DeviceHandler;
  143. BOOLEAN Done;
  144. UCHAR UidComponent;
  145. PPCIBUSDATA PciBusData;
  146. PWCHAR DelimiterPointer;
  147. WCHAR Delimiter;
  148. PAGED_CODE();
  149. //
  150. // Set [UniqueDeviceId, UniqueDeviceIdEnd) to the range of
  151. // wide characters for which the caller provided storage.
  152. //
  153. Status = STATUS_SUCCESS;
  154. UniqueDeviceId = (PWCHAR) Context->DeviceControl.Buffer;
  155. UniqueDeviceIdEnd = UniqueDeviceId
  156. + *Context->DeviceControl.BufferLength / sizeof(WCHAR);
  157. DeviceHandler = DeviceData2DeviceHandler(DeviceData);
  158. //
  159. // Determine the memory required for the unique id.
  160. // Note that this loop exits in the middle and that it will
  161. // always be executed at least 1.5 times. If there are PCI-PCI
  162. // bridges between the slot's bus and the root bus of the PCI
  163. // hierarchy, then an extra iteration of the loop will be done
  164. // for each one of them.
  165. //
  166. // The bus hierarchy is being walked backwards (from leaf to root).
  167. // Finally, note that the rightmost uid component is the slot's
  168. // number (set before we enter the loop).
  169. //
  170. BusHandler = DeviceHandler->BusHandler;
  171. UidComponent = (UCHAR) DeviceHandler->SlotNumber;
  172. Done = FALSE;
  173. for (;;) {
  174. //
  175. // On each iteration, given the value of one of the components of
  176. // the unique id, determine how much memory the swprintf would use
  177. // for it (note that the 2, 3 & 4 below include a +1, which is
  178. // for the nul terminator or for the '.' delimiter between two
  179. // unique id components.
  180. //
  181. if (UidComponent <= 9) {
  182. UniqueDeviceId += 2;
  183. } else if (UidComponent <= 99) {
  184. UniqueDeviceId += 3;
  185. } else {
  186. UniqueDeviceId += 4;
  187. }
  188. if (Done) {
  189. break;
  190. }
  191. //
  192. // If there is no parent bus handler for the current bus,
  193. // or if it is not a PCI bus, then we are at the root of
  194. // this hierarchy of PCI buses. In this case the unique id
  195. // component is the bus number (instead of a slot number),
  196. // furthermore, we are almost done (just account for the
  197. // space required in the unique id for it).
  198. //
  199. // Otherwise, the current bus is a PCI-PCI bridge and its
  200. // unique id component is the slot number of the bridge
  201. // within its parent bus.
  202. //
  203. ParentHandler = BusHandler->ParentHandler;
  204. if (!ParentHandler || ParentHandler->InterfaceType != PCIBus) {
  205. UidComponent = (UCHAR) BusHandler->BusNumber;
  206. Done = TRUE;
  207. } else {
  208. PciBusData = (PPCIBUSDATA) BusHandler->BusData;
  209. UidComponent = (UCHAR) PciBusData->ParentSlot.u.AsULONG;
  210. BusHandler = ParentHandler;
  211. }
  212. }
  213. //
  214. // If there is not enough space for the unique id, fail
  215. // and return the size required.
  216. //
  217. if (UniqueDeviceId > UniqueDeviceIdEnd) {
  218. *Context->DeviceControl.BufferLength = (UniqueDeviceIdEnd
  219. - (PWCHAR) Context->DeviceControl.Buffer) * sizeof(WCHAR);
  220. Status = STATUS_BUFFER_TOO_SMALL;
  221. } else {
  222. //
  223. // Otherwise, traverse the bus heirarchy again (just like
  224. // above), except that this time we decrement the UniqueDeviceId
  225. // on each iteration and swprintf the uid component. Note that
  226. // for all components except for the right most one we store
  227. // a delimiter after it (i.e. a '.').
  228. //
  229. BusHandler = DeviceHandler->BusHandler;
  230. UidComponent = (UCHAR) DeviceHandler->SlotNumber;
  231. Done = FALSE;
  232. Delimiter = L'\0';
  233. for (;;) {
  234. DelimiterPointer = UniqueDeviceId;
  235. if (UidComponent <= 9) {
  236. UniqueDeviceId -= 2;
  237. } else if (UidComponent <= 99) {
  238. UniqueDeviceId -= 3;
  239. } else {
  240. UniqueDeviceId -= 4;
  241. }
  242. swprintf(UniqueDeviceId, L"%d", UidComponent);
  243. DelimiterPointer[-1] = Delimiter;
  244. Delimiter = L'.';
  245. if (Done) {
  246. break;
  247. }
  248. ParentHandler = BusHandler->ParentHandler;
  249. if (!ParentHandler || ParentHandler->InterfaceType != PCIBus) {
  250. UidComponent = (UCHAR) BusHandler->BusNumber;
  251. Done = TRUE;
  252. } else {
  253. PciBusData = (PPCIBUSDATA) BusHandler->BusData;
  254. UidComponent = (UCHAR) PciBusData->ParentSlot.u.AsULONG;
  255. BusHandler = ParentHandler;
  256. }
  257. }
  258. }
  259. PcipCompleteDeviceControl(Status, Context, DeviceData);
  260. }
  261. VOID
  262. PciCtlQueryDeviceResources (
  263. PDEVICE_DATA DeviceData,
  264. PHAL_DEVICE_CONTROL_CONTEXT Context
  265. )
  266. /*++
  267. Routine Description:
  268. This function completes the QUERY_DEVICE_RESOURCES DeviceControl
  269. which returns the bus resources being used by the specified device
  270. Arguments:
  271. DeviceData - Slot data information for the specificied slot
  272. Context - Slot control context of the request
  273. Return Value:
  274. The slot control is completed
  275. --*/
  276. {
  277. PPCIBUSDATA PciBusData;
  278. PPCI_COMMON_CONFIG PciData;
  279. ULONG NoBaseAddress, RomIndex;
  280. PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1];
  281. ULONG i, j;
  282. PCM_RESOURCE_LIST CompleteList;
  283. PCM_PARTIAL_RESOURCE_LIST PartialList;
  284. PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor;
  285. LONGLONG base, length, max;
  286. NTSTATUS Status;
  287. PUCHAR WorkingPool;
  288. PCI_SLOT_NUMBER SlotNumber;
  289. PAGED_CODE();
  290. // BUGBUG if the device is a pci-2-pci bus controller, then
  291. // this function should return the addresses which are bridged
  292. //
  293. // Allocate some pool for working space
  294. //
  295. i = sizeof (CM_RESOURCE_LIST) +
  296. sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) +
  297. PCI_COMMON_HDR_LENGTH;
  298. WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i);
  299. if (!WorkingPool) {
  300. PcipCompleteDeviceControl (STATUS_INSUFFICIENT_RESOURCES, Context, DeviceData);
  301. return ;
  302. }
  303. //
  304. // Zero initialize pool, and get pointers into memory
  305. //
  306. RtlZeroMemory (WorkingPool, i);
  307. CompleteList = (PCM_RESOURCE_LIST) WorkingPool;
  308. PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH);
  309. SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData);
  310. //
  311. // Read the PCI device's info
  312. //
  313. PciBusData = (PPCIBUSDATA) (Context->Handler->BusData);
  314. PcipReadConfig (Context->Handler, DeviceData, PciData);
  315. //
  316. // Initialize base addresses base on configuration data type
  317. //
  318. PcipCalcBaseAddrPointers (
  319. DeviceData,
  320. PciData,
  321. BaseAddress,
  322. &NoBaseAddress,
  323. &RomIndex
  324. );
  325. //
  326. // Build a CM_RESOURCE_LIST for the PCI device
  327. //
  328. CompleteList->Count = 1;
  329. CompleteList->List[0].InterfaceType = Context->RootHandler->InterfaceType;
  330. CompleteList->List[0].BusNumber = Context->RootHandler->BusNumber;
  331. PartialList = &CompleteList->List[0].PartialResourceList;
  332. Descriptor = PartialList->PartialDescriptors;
  333. //
  334. // If PCI device has an interrupt resource, add it
  335. //
  336. if (PciData->u.type0.InterruptPin) {
  337. Descriptor->Type = CmResourceTypeInterrupt;
  338. Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  339. Descriptor->ShareDisposition = CmResourceShareShared;
  340. PciBusData->Pin2Line (
  341. Context->Handler,
  342. Context->RootHandler,
  343. SlotNumber,
  344. PciData
  345. );
  346. Descriptor->u.Interrupt.Level = PciData->u.type0.InterruptLine;
  347. Descriptor->u.Interrupt.Vector = PciData->u.type0.InterruptLine;
  348. Descriptor->u.Interrupt.Affinity = 0xFFFFFFFF;
  349. PartialList->Count++;
  350. Descriptor++;
  351. }
  352. //
  353. // Add any memory / port resources being used
  354. //
  355. for (j=0; j < NoBaseAddress; j++) {
  356. if (*BaseAddress[j]) {
  357. ASSERT (DeviceData->BARBitsSet);
  358. PcipCrackBAR (BaseAddress, DeviceData->BARBits, &j, &base, &length, &max);
  359. if (base & PCI_ADDRESS_IO_SPACE) {
  360. if (PciData->Command & PCI_ENABLE_IO_SPACE) {
  361. Descriptor->Type = CmResourceTypePort;
  362. Descriptor->Flags = CM_RESOURCE_PORT_IO;
  363. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  364. Descriptor->u.Port.Start.QuadPart = base & ~0x3;
  365. ASSERT (length <= 0xFFFFFFFF);
  366. Descriptor->u.Port.Length = (ULONG) length;
  367. }
  368. } else {
  369. if (PciData->Command & PCI_ENABLE_MEMORY_SPACE) {
  370. Descriptor->Type = CmResourceTypeMemory;
  371. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  372. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  373. if (j == RomIndex) {
  374. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
  375. }
  376. if (base & PCI_ADDRESS_MEMORY_PREFETCHABLE) {
  377. Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
  378. }
  379. Descriptor->u.Memory.Start.QuadPart = base & ~0xF;
  380. ASSERT (length < 0xFFFFFFFF);
  381. Descriptor->u.Memory.Length = (ULONG) length;
  382. }
  383. }
  384. PartialList->Count++;
  385. Descriptor++;
  386. }
  387. }
  388. //
  389. // Return results
  390. //
  391. i = (ULONG) ((PUCHAR) Descriptor - (PUCHAR) CompleteList);
  392. if (i > *Context->DeviceControl.BufferLength) {
  393. Status = STATUS_BUFFER_TOO_SMALL;
  394. } else {
  395. RtlCopyMemory (Context->DeviceControl.Buffer, CompleteList, i);
  396. Status = STATUS_SUCCESS;
  397. }
  398. *Context->DeviceControl.BufferLength = i;
  399. ExFreePool (WorkingPool);
  400. PcipCompleteDeviceControl (Status, Context, DeviceData);
  401. }
  402. VOID
  403. PciCtlQueryDeviceResourceRequirements (
  404. PDEVICE_DATA DeviceData,
  405. PHAL_DEVICE_CONTROL_CONTEXT Context
  406. )
  407. /*++
  408. Routine Description:
  409. This function completes the QUERY_DEVICE_RESOURCE_REQUIREMENTS DeviceControl
  410. which returns the possible bus resources that this device may be
  411. satisfied with.
  412. Arguments:
  413. DeviceData - Slot data information for the specificied slot
  414. Context - Slot control context of the request
  415. Return Value:
  416. The slot control is completed
  417. --*/
  418. {
  419. PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
  420. NTSTATUS Status;
  421. PAGED_CODE();
  422. //
  423. // Get the resource requirements list for the device
  424. //
  425. Status = PcipQueryResourceRequirements (DeviceData, Context, &ResourceList);
  426. if (NT_SUCCESS(Status)) {
  427. //
  428. // Return results
  429. //
  430. if (ResourceList->ListSize > *Context->DeviceControl.BufferLength) {
  431. Status = STATUS_BUFFER_TOO_SMALL;
  432. } else {
  433. RtlCopyMemory (Context->DeviceControl.Buffer, ResourceList, ResourceList->ListSize);
  434. Status = STATUS_SUCCESS;
  435. }
  436. *Context->DeviceControl.BufferLength = ResourceList->ListSize;
  437. }
  438. if (ResourceList) {
  439. ExFreePool (ResourceList);
  440. }
  441. PcipCompleteDeviceControl (Status, Context, DeviceData);
  442. }
  443. NTSTATUS
  444. PcipQueryResourceRequirements (
  445. PDEVICE_DATA DeviceData,
  446. PHAL_DEVICE_CONTROL_CONTEXT Context,
  447. PIO_RESOURCE_REQUIREMENTS_LIST *ResourceList
  448. )
  449. /*++
  450. Routine Description:
  451. This function allocates and returns the specified devices
  452. IO_RESOURCE_REQUIREMENTS_LIST
  453. Arguments:
  454. DeviceData - Slot data information for the specificied slot
  455. Context - Slot control context of the request
  456. Return Value:
  457. The slot control is completed
  458. --*/
  459. {
  460. PPCIBUSDATA PciBusData;
  461. PPCI_COMMON_CONFIG PciData;
  462. ULONG NoBaseAddress, RomIndex;
  463. PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1];
  464. ULONG i, j;
  465. PIO_RESOURCE_REQUIREMENTS_LIST CompleteList;
  466. PIO_RESOURCE_DESCRIPTOR Descriptor;
  467. LONGLONG base, length, max;
  468. NTSTATUS Status;
  469. PUCHAR WorkingPool;
  470. PAGED_CODE();
  471. //
  472. // Allocate some pool for working space
  473. //
  474. i = sizeof (IO_RESOURCE_REQUIREMENTS_LIST) +
  475. sizeof (IO_RESOURCE_DESCRIPTOR) * (PCI_TYPE0_ADDRESSES + 2) * 2 +
  476. PCI_COMMON_HDR_LENGTH;
  477. WorkingPool = (PUCHAR) ExAllocatePool (PagedPool, i);
  478. *ResourceList = (PIO_RESOURCE_REQUIREMENTS_LIST) WorkingPool;
  479. if (!*ResourceList) {
  480. return STATUS_INSUFFICIENT_RESOURCES;
  481. }
  482. //
  483. // Zero initialize pool, and get pointers into memory
  484. //
  485. RtlZeroMemory (WorkingPool, i);
  486. CompleteList = (PIO_RESOURCE_REQUIREMENTS_LIST) WorkingPool;
  487. PciData = (PPCI_COMMON_CONFIG) (WorkingPool + i - PCI_COMMON_HDR_LENGTH);
  488. //
  489. // Read the PCI device's info
  490. //
  491. PciBusData = (PPCIBUSDATA) (Context->Handler->BusData);
  492. PcipReadConfig (Context->Handler, DeviceData, PciData);
  493. //
  494. // Initialize base addresses base on configuration data type
  495. //
  496. PcipCalcBaseAddrPointers (
  497. DeviceData,
  498. PciData,
  499. BaseAddress,
  500. &NoBaseAddress,
  501. &RomIndex
  502. );
  503. //
  504. // Build an IO_RESOURCE_REQUIREMENTS_LIST for the PCI device
  505. //
  506. CompleteList->InterfaceType = Context->RootHandler->InterfaceType;
  507. CompleteList->BusNumber = Context->RootHandler->BusNumber;
  508. CompleteList->SlotNumber = DeviceDataSlot(DeviceData);
  509. CompleteList->AlternativeLists = 1;
  510. CompleteList->List[0].Version = 1;
  511. CompleteList->List[0].Revision = 1;
  512. Descriptor = CompleteList->List[0].Descriptors;
  513. //
  514. // If PCI device has an interrupt resource, add it
  515. //
  516. if (PciData->u.type0.InterruptPin) {
  517. Descriptor->Type = CmResourceTypeInterrupt;
  518. Descriptor->Flags = CM_RESOURCE_INTERRUPT_LEVEL_SENSITIVE;
  519. Descriptor->ShareDisposition = CmResourceShareShared;
  520. // BUGBUG: this is not correct
  521. Descriptor->u.Interrupt.MinimumVector = 0;
  522. Descriptor->u.Interrupt.MaximumVector = 0xff;
  523. CompleteList->List[0].Count++;
  524. Descriptor++;
  525. }
  526. //
  527. // Add any memory / port resources being used
  528. //
  529. for (j=0; j < NoBaseAddress; j++) {
  530. if (*BaseAddress[j]) {
  531. PcipCrackBAR (BaseAddress, DeviceData->BARBits, &j, &base, &length, &max);
  532. //
  533. // Add a descriptor for this address
  534. //
  535. Descriptor->Option = 0;
  536. if (base & PCI_ADDRESS_IO_SPACE) {
  537. Descriptor->Type = CmResourceTypePort;
  538. Descriptor->Flags = CM_RESOURCE_PORT_IO;
  539. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  540. ASSERT (length <= 0xFFFFFFFF);
  541. Descriptor->u.Port.Alignment = (ULONG) length;
  542. Descriptor->u.Port.Length = (ULONG) length;
  543. Descriptor->u.Port.MinimumAddress.QuadPart = 0;
  544. Descriptor->u.Port.MaximumAddress.QuadPart = max;
  545. } else {
  546. Descriptor->Type = CmResourceTypeMemory;
  547. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_WRITE;
  548. Descriptor->ShareDisposition = CmResourceShareDeviceExclusive;
  549. if (j == RomIndex) {
  550. // this is a ROM address
  551. Descriptor->Flags = CM_RESOURCE_MEMORY_READ_ONLY;
  552. }
  553. if (base & PCI_ADDRESS_MEMORY_PREFETCHABLE) {
  554. Descriptor->Flags |= CM_RESOURCE_MEMORY_PREFETCHABLE;
  555. }
  556. ASSERT (length <= 0xFFFFFFFF);
  557. Descriptor->u.Memory.Alignment = (ULONG) length;
  558. Descriptor->u.Memory.Length = (ULONG) length;
  559. Descriptor->u.Memory.MinimumAddress.QuadPart = 0;
  560. Descriptor->u.Memory.MaximumAddress.QuadPart = max;
  561. }
  562. CompleteList->List[0].Count++;
  563. Descriptor++;
  564. }
  565. }
  566. if (DeviceData->BrokenDevice) {
  567. //
  568. // This device has something wrong with its base address register implementation
  569. //
  570. ExFreePool (WorkingPool);
  571. return STATUS_DEVICE_PROTOCOL_ERROR;
  572. }
  573. //
  574. // Return results
  575. //
  576. CompleteList->ListSize = (ULONG) ((PUCHAR) Descriptor - (PUCHAR) CompleteList);
  577. *ResourceList = CompleteList;
  578. return STATUS_SUCCESS;
  579. }
  580. VOID
  581. PciCtlSetDeviceResources (
  582. PDEVICE_DATA DeviceData,
  583. PHAL_DEVICE_CONTROL_CONTEXT Context
  584. )
  585. /*++
  586. Routine Description:
  587. This function completes the SET_DEVICE_RESOURCES DeviceControl
  588. which configures the device to the specified device setttings
  589. Arguments:
  590. DeviceData - Slot data information for the specificied slot
  591. Context - Slot control context of the request
  592. Return Value:
  593. The slot control is completed
  594. --*/
  595. {
  596. NTSTATUS Status;
  597. PAGED_CODE();
  598. //
  599. // Get the resource requirements list for the device
  600. //
  601. Status = PcipSetResources (
  602. DeviceData,
  603. Context,
  604. (PCM_RESOURCE_LIST) Context->DeviceControl.Buffer,
  605. *Context->DeviceControl.BufferLength
  606. );
  607. PcipCompleteDeviceControl (Status, Context, DeviceData);
  608. }
  609. NTSTATUS
  610. PcipSetResources (
  611. PDEVICE_DATA DeviceData,
  612. PHAL_DEVICE_CONTROL_CONTEXT Context,
  613. PCM_RESOURCE_LIST ResourceList,
  614. ULONG ListSize
  615. )
  616. /*++
  617. Routine Description:
  618. This function set the specified device to the CM_RESOURCE_LIST
  619. Arguments:
  620. Return Value:
  621. The slot control is completed
  622. --*/
  623. {
  624. PPCIBUSDATA PciBusData;
  625. PPCI_COMMON_CONFIG PciData, PciOrigData;
  626. ULONG NoBaseAddress, RomIndex;
  627. PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1];
  628. ULONG i, j;
  629. PCM_PARTIAL_RESOURCE_DESCRIPTOR CmDescriptor;
  630. LONGLONG base, length;
  631. NTSTATUS Status;
  632. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  633. PCI_SLOT_NUMBER SlotNumber;
  634. PAGED_CODE();
  635. PciBusData = (PPCIBUSDATA) (Context->Handler->BusData);
  636. SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData);
  637. //
  638. // If BARBits haven't been deteremined, go do it now
  639. //
  640. Status = PcipVerifyBarBits (DeviceData, Context->Handler);
  641. if (!NT_SUCCESS(Status)) {
  642. return Status;
  643. }
  644. //
  645. // Get current device configuration
  646. //
  647. if (DeviceData->Power) {
  648. ASSERT (DeviceData->CurrentConfig == NULL);
  649. DeviceData->CurrentConfig = (PPCI_COMMON_CONFIG)
  650. ExAllocatePool (NonPagedPool, PCI_COMMON_HDR_LENGTH);
  651. if (!DeviceData->CurrentConfig) {
  652. return STATUS_INSUFFICIENT_RESOURCES;
  653. }
  654. }
  655. //
  656. // Read the PCI device's info
  657. //
  658. PciData = DeviceData->CurrentConfig;
  659. PciOrigData = (PPCI_COMMON_CONFIG) buffer;
  660. PcipReadConfig (Context->Handler, DeviceData, PciData);
  661. //
  662. // Save current config
  663. //
  664. RtlCopyMemory (PciOrigData, PciData, PCI_COMMON_HDR_LENGTH);
  665. //
  666. // Initialize base addresses base on configuration data type
  667. //
  668. PcipCalcBaseAddrPointers (
  669. DeviceData,
  670. PciData,
  671. BaseAddress,
  672. &NoBaseAddress,
  673. &RomIndex
  674. );
  675. //
  676. // Slurp the assigments back into the PciData structure and
  677. // perform them
  678. //
  679. CmDescriptor = ResourceList->List[0].PartialResourceList.PartialDescriptors;
  680. //
  681. // If PCI device has an interrupt resource then that was
  682. // passed in as the first requested resource
  683. //
  684. if (PciData->u.type0.InterruptPin) {
  685. //
  686. // Assign the interrupt line
  687. //
  688. if (CmDescriptor->Type != CmResourceTypeInterrupt) {
  689. Status = STATUS_INVALID_PARAMETER;
  690. goto CleanUp;
  691. }
  692. PciData->u.type0.InterruptLine = (UCHAR) CmDescriptor->u.Interrupt.Vector;
  693. PciBusData->Pin2Line (
  694. Context->Handler,
  695. Context->RootHandler,
  696. SlotNumber,
  697. PciData
  698. );
  699. CmDescriptor++;
  700. }
  701. for (j=0; j < NoBaseAddress; j++) {
  702. base = *BaseAddress[j];
  703. if (base) {
  704. //
  705. // Set 32bits and mask
  706. //
  707. if (base & PCI_ADDRESS_IO_SPACE) {
  708. if (CmDescriptor->Type != CmResourceTypePort) {
  709. Status = STATUS_INVALID_PARAMETER;
  710. goto CleanUp;
  711. }
  712. *BaseAddress[j] = CmDescriptor->u.Port.Start.LowPart;
  713. } else {
  714. if (CmDescriptor->Type != CmResourceTypeMemory) {
  715. Status = STATUS_INVALID_PARAMETER;
  716. goto CleanUp;
  717. }
  718. *BaseAddress[j] = CmDescriptor->u.Memory.Start.LowPart;
  719. }
  720. if (Is64BitBaseAddress(base)) {
  721. //
  722. // Set upper 32bits
  723. //
  724. if (base & PCI_ADDRESS_IO_SPACE) {
  725. *BaseAddress[j+1] = CmDescriptor->u.Port.Start.HighPart;
  726. } else {
  727. *BaseAddress[j+1] = CmDescriptor->u.Memory.Start.HighPart;
  728. }
  729. j++;
  730. }
  731. CmDescriptor++;
  732. }
  733. }
  734. //
  735. // Enabel decodes and set the new addresses
  736. //
  737. if (DeviceData->EnableRom && *BaseAddress[RomIndex]) {
  738. // a rom address was allocated and should be enabled
  739. *BaseAddress[RomIndex] |= PCI_ROMADDRESS_ENABLED;
  740. }
  741. PciData->Command |= PCI_ENABLE_IO_SPACE |
  742. PCI_ENABLE_MEMORY_SPACE |
  743. PCI_ENABLE_BUS_MASTER;
  744. //
  745. // If the device is powered on, flush the cached config information
  746. // to the device; otherwise, leave the new configuration in memory -
  747. // it will get flushed to the device when it's powered on
  748. //
  749. Status = STATUS_SUCCESS;
  750. if (DeviceData->Power) {
  751. Status = PcipFlushConfig (Context->Handler, DeviceData);
  752. }
  753. CleanUp:
  754. //
  755. // If there was an error, and the device still has a cached current
  756. // config, put the configuration back as it was when we found it
  757. //
  758. if (!NT_SUCCESS (Status) && DeviceData->CurrentConfig) {
  759. RtlCopyMemory (DeviceData->CurrentConfig, PciOrigData, PCI_COMMON_HDR_LENGTH);
  760. }
  761. return Status;
  762. }
  763. VOID
  764. PciCtlAssignSlotResources (
  765. PDEVICE_DATA DeviceData,
  766. PHAL_DEVICE_CONTROL_CONTEXT Context
  767. )
  768. /*++
  769. Routine Description:
  770. This function completes the internal AssignSlotResources DeviceControl
  771. Arguments:
  772. DeviceData - Slot data information for the specificied slot
  773. Context - Slot control context of the request
  774. Return Value:
  775. The slot control is completed
  776. --*/
  777. {
  778. PIO_RESOURCE_REQUIREMENTS_LIST ResourceList;
  779. PCTL_ASSIGN_RESOURCES AssignResources;
  780. PCM_RESOURCE_LIST AllocatedResources;
  781. NTSTATUS Status;
  782. ULONG l;
  783. POWER_STATE PowerControl;
  784. PAGED_CODE();
  785. ResourceList = NULL;
  786. AllocatedResources = NULL;
  787. AssignResources = (PCTL_ASSIGN_RESOURCES) Context->DeviceControl.Buffer;
  788. //
  789. // If BARBits haven't been deteremined, go do it now
  790. //
  791. Status = PcipVerifyBarBits (DeviceData, Context->Handler);
  792. if (!NT_SUCCESS(Status)) {
  793. goto CleanUp;
  794. }
  795. //
  796. // Get the resource requirements list for the device
  797. //
  798. Status = PcipQueryResourceRequirements (DeviceData, Context, &ResourceList);
  799. if (!NT_SUCCESS(Status)) {
  800. goto CleanUp;
  801. }
  802. //
  803. // Get device settings from IO
  804. //
  805. Status = IoAssignResources (
  806. AssignResources->RegistryPath,
  807. AssignResources->DriverClassName,
  808. AssignResources->DriverObject,
  809. Context->DeviceControl.DeviceObject,
  810. ResourceList,
  811. &AllocatedResources
  812. );
  813. if (!NT_SUCCESS(Status)) {
  814. goto CleanUp;
  815. }
  816. //
  817. // Set the resources into the device
  818. //
  819. Status = PcipSetResources (DeviceData, Context, AllocatedResources, 0xFFFFFFFF);
  820. if (!NT_SUCCESS(Status)) {
  821. goto CleanUp;
  822. }
  823. //
  824. // Turn the device on
  825. //
  826. PowerControl = PowerUp;
  827. l = sizeof (PowerControl);
  828. Status = HalDeviceControl (
  829. Context->DeviceControl.DeviceHandler,
  830. Context->DeviceControl.DeviceObject,
  831. BCTL_SET_POWER,
  832. &PowerControl,
  833. &l,
  834. NULL,
  835. NULL
  836. );
  837. CleanUp:
  838. *AssignResources->AllocatedResources = AllocatedResources;
  839. if (!NT_SUCCESS(Status)) {
  840. //
  841. // Failure, if there are any allocated resources free them
  842. //
  843. if (AllocatedResources) {
  844. IoAssignResources (
  845. AssignResources->RegistryPath,
  846. AssignResources->DriverClassName,
  847. AssignResources->DriverObject,
  848. Context->DeviceControl.DeviceObject,
  849. NULL,
  850. NULL
  851. );
  852. ExFreePool (AllocatedResources);
  853. *AssignResources->AllocatedResources = NULL;
  854. }
  855. }
  856. if (ResourceList) {
  857. ExFreePool (ResourceList);
  858. }
  859. PcipCompleteDeviceControl (Status, Context, DeviceData);
  860. }