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.

544 lines
11 KiB

4 years ago
  1. /*++
  2. Copyright (c) 1995 Microsoft Corporation
  3. Module Name:
  4. misc.c
  5. Abstract:
  6. Author:
  7. Ken Reneris (kenr) March-13-1885
  8. Environment:
  9. Kernel mode only.
  10. Revision History:
  11. --*/
  12. #include "pciport.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE,PcipReadConfig)
  15. #pragma alloc_text(PAGE,PcipPowerDownSlot)
  16. #endif
  17. NTSTATUS
  18. PcipPowerDownSlot (
  19. PBUS_HANDLER Handler,
  20. PDEVICE_DATA DeviceData
  21. )
  22. /*++
  23. Routine Description:
  24. This function is called to power down a particular slot.
  25. Arguments:
  26. Return Value:
  27. returns once the slot has powered down
  28. --*/
  29. {
  30. USHORT Command;
  31. PPCIBUSDATA PciBusData;
  32. PCI_SLOT_NUMBER SlotNumber;
  33. PAGED_CODE();
  34. PciBusData = (PPCIBUSDATA) (Handler->BusData);
  35. SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData);
  36. //
  37. // If already powered down, do nothing
  38. //
  39. if (!DeviceData->Power) {
  40. return STATUS_SUCCESS;
  41. }
  42. DebugPrint ((2, "PCI: Powering down device - slot %d\n", SlotNumber ));
  43. //
  44. // Allocate buffer to save current device configuration
  45. //
  46. ASSERT (DeviceData->CurrentConfig == NULL);
  47. DeviceData->CurrentConfig = (PPCI_COMMON_CONFIG)
  48. ExAllocatePoolWithTag (NonPagedPool, PCI_COMMON_HDR_LENGTH, 'cICP');
  49. if (!DeviceData->CurrentConfig) {
  50. return STATUS_INSUFFICIENT_RESOURCES;
  51. }
  52. //
  53. // Read the current configuration
  54. //
  55. PciBusData->ReadConfig (
  56. Handler,
  57. SlotNumber,
  58. DeviceData->CurrentConfig,
  59. 0,
  60. PCI_COMMON_HDR_LENGTH
  61. );
  62. //
  63. // Power down the device
  64. //
  65. DeviceData->Power = FALSE;
  66. // BUGBUG: should pass this request on
  67. //
  68. // Emulate a powered down device by turning off the device decodes
  69. //
  70. Command = DeviceData->CurrentConfig->Command;
  71. Command &= ~(PCI_ENABLE_IO_SPACE |
  72. PCI_ENABLE_MEMORY_SPACE |
  73. PCI_ENABLE_BUS_MASTER);
  74. PciBusData->WriteConfig (
  75. Handler,
  76. SlotNumber,
  77. &Command,
  78. FIELD_OFFSET (PCI_COMMON_CONFIG, Command),
  79. sizeof (Command)
  80. );
  81. DebugPrint ((2, "PCI: Powerdown complete - Slot %x, Status %x\n",
  82. SlotNumber, STATUS_SUCCESS));
  83. return STATUS_SUCCESS;
  84. }
  85. NTSTATUS
  86. PcipPowerUpSlot (
  87. PBUS_HANDLER Handler,
  88. PDEVICE_DATA DeviceData
  89. )
  90. /*++
  91. Routine Description:
  92. This function is called to power down a particular slot.
  93. Arguments:
  94. Return Value:
  95. returns once the slot has powered down
  96. --*/
  97. {
  98. //
  99. // If already powered up, do nothing
  100. //
  101. if (!DeviceData->Power) {
  102. return STATUS_SUCCESS;
  103. }
  104. //
  105. // Power up the device
  106. //
  107. DebugPrint ((2, "PCI: Powering up device - slot %d\n", DeviceDataSlot(DeviceData) ));
  108. DeviceData->Power = TRUE;
  109. // BUGBUG: should pass this request on
  110. }
  111. VOID
  112. PcipReadConfig (
  113. IN PBUS_HANDLER Handler,
  114. IN PDEVICE_DATA DeviceData,
  115. OUT PPCI_COMMON_CONFIG PciData
  116. )
  117. /*++
  118. Routine Description:
  119. This function returns the current PCI_COMMON_HDR for the device.
  120. If the device is powered off, then the pci_common_hdr is returned
  121. from it's memory image; otherwise, it is read from the device.
  122. Arguments:
  123. Return Value:
  124. --*/
  125. {
  126. PPCIBUSDATA PciBusData;
  127. PCI_SLOT_NUMBER SlotNumber;
  128. PAGED_CODE();
  129. PciBusData = (PPCIBUSDATA) (Handler->BusData);
  130. SlotNumber.u.AsULONG = DeviceDataSlot (DeviceData);
  131. if (!DeviceData->Power) {
  132. //
  133. // The slot is powered down, return the devices
  134. // current configuration from memory
  135. //
  136. RtlCopyMemory (PciData, DeviceData->CurrentConfig, PCI_COMMON_HDR_LENGTH);
  137. return ;
  138. }
  139. //
  140. // Read the devices current configuration from the device
  141. //
  142. PciBusData->ReadConfig (
  143. Handler,
  144. SlotNumber,
  145. PciData,
  146. 0,
  147. PCI_COMMON_HDR_LENGTH
  148. );
  149. }
  150. NTSTATUS
  151. PcipFlushConfig (
  152. IN PBUS_HANDLER Handler,
  153. IN PDEVICE_DATA DeviceData
  154. )
  155. /*++
  156. Routine Description:
  157. This function flushes the cached configuration to the PCI device.
  158. It properly handles disabling & enabling of the memory & io decodes,
  159. and verifies the new base address register settings. If the device
  160. does not take the new settings, if the original settings are known
  161. they are put back into the device.
  162. Arguments:
  163. Return Value:
  164. --*/
  165. {
  166. PPCIBUSDATA PciBusData;
  167. USHORT HoldCommand;
  168. PPCI_COMMON_CONFIG PciData, PciData2;
  169. UCHAR buffer[PCI_COMMON_HDR_LENGTH];
  170. NTSTATUS Status;
  171. PCI_SLOT_NUMBER SlotNumber;
  172. PciBusData = (PPCIBUSDATA) (Handler->BusData);
  173. PciData2 = (PPCI_COMMON_CONFIG) buffer;
  174. PciData = DeviceData->CurrentConfig;
  175. SlotNumber.u.AsULONG = DeviceDataSlot(DeviceData);
  176. //
  177. // To flush the settings, the device must be in the powered on state
  178. //
  179. ASSERT (DeviceData->Power);
  180. //
  181. // Read what is currently in the device
  182. //
  183. PciBusData->ReadConfig (
  184. Handler,
  185. SlotNumber,
  186. PciData2,
  187. 0,
  188. PCI_COMMON_HDR_LENGTH
  189. );
  190. //
  191. // Had better be correct device
  192. //
  193. ASSERT (PciData->VendorID == PciData2->VendorID);
  194. ASSERT (PciData->DeviceID == PciData2->DeviceID);
  195. //
  196. // If decodes aren't the same, then clear decode enables before
  197. // performing initial set
  198. //
  199. HoldCommand = DeviceData->CurrentConfig->Command;
  200. if (!PcipCompareDecodes (DeviceData, PciData, PciData2)) {
  201. PciData->Command &= ~(PCI_ENABLE_IO_SPACE |
  202. PCI_ENABLE_MEMORY_SPACE |
  203. PCI_ENABLE_BUS_MASTER);
  204. }
  205. //
  206. // Write the current device condifuragtion
  207. //
  208. PciBusData->WriteConfig (
  209. Handler,
  210. SlotNumber,
  211. DeviceData->CurrentConfig,
  212. 0,
  213. PCI_COMMON_HDR_LENGTH
  214. );
  215. //
  216. // Read back the configuration and verify it took
  217. //
  218. PciBusData->ReadConfig (
  219. Handler,
  220. SlotNumber,
  221. PciData2,
  222. 0,
  223. PCI_COMMON_HDR_LENGTH
  224. );
  225. //
  226. // See if configuration matches
  227. //
  228. if (!PcipCompareDecodes (DeviceData, PciData, PciData2)) {
  229. //
  230. // The CurrentConfig did not get successfully set
  231. //
  232. DebugPrint ((1, "PCI: defective device - slot %d\n", SlotNumber));
  233. DeviceData->BrokenDevice = TRUE;
  234. Status = STATUS_DEVICE_PROTOCOL_ERROR;
  235. } else {
  236. //
  237. // Settings are fine - write final decode enable bits
  238. //
  239. PciBusData->WriteConfig (
  240. Handler,
  241. SlotNumber,
  242. &HoldCommand,
  243. FIELD_OFFSET (PCI_COMMON_CONFIG, Command),
  244. sizeof (HoldCommand)
  245. );
  246. Status = STATUS_SUCCESS;
  247. }
  248. //
  249. // Current config now flushed to the device. Free memory.
  250. //
  251. if (DeviceData->CurrentConfig) {
  252. ExFreePool (DeviceData->CurrentConfig);
  253. DeviceData->CurrentConfig = NULL;
  254. }
  255. return Status;
  256. }
  257. BOOLEAN
  258. PcipCompareDecodes (
  259. IN PDEVICE_DATA DeviceData,
  260. IN PPCI_COMMON_CONFIG PciData,
  261. IN PPCI_COMMON_CONFIG PciData2
  262. )
  263. /*++
  264. Routine Description:
  265. This function compares the base address registers of PciData and PciData2.
  266. Arguments:
  267. Return Value:
  268. --*/
  269. {
  270. PULONG BaseAddress[PCI_TYPE0_ADDRESSES + 1];
  271. PULONG BaseAddress2[PCI_TYPE0_ADDRESSES + 1];
  272. ULONG NoBaseAddress, RomIndex;
  273. ULONG NoBaseAddress2, RomIndex2;
  274. ULONG i, j;
  275. BOOLEAN Match;
  276. //
  277. // Initialize base addresses base on configuration data type
  278. //
  279. PcipCalcBaseAddrPointers (
  280. DeviceData,
  281. PciData,
  282. BaseAddress,
  283. &NoBaseAddress,
  284. &RomIndex
  285. );
  286. PcipCalcBaseAddrPointers (
  287. DeviceData,
  288. PciData2,
  289. BaseAddress2,
  290. &NoBaseAddress2,
  291. &RomIndex2
  292. );
  293. if (NoBaseAddress != NoBaseAddress2 ||
  294. RomIndex != RomIndex2) {
  295. return FALSE;
  296. }
  297. Match = TRUE;
  298. if (PciData->u.type0.InterruptLine != PciData2->u.type0.InterruptLine ||
  299. PciData->u.type0.InterruptPin != PciData2->u.type0.InterruptPin ||
  300. PciData->u.type0.ROMBaseAddress != PciData2->u.type0.ROMBaseAddress) {
  301. Match = FALSE;
  302. }
  303. for (j=0; j < NoBaseAddress; j++) {
  304. if (*BaseAddress[j]) {
  305. if (*BaseAddress[j] & PCI_ADDRESS_IO_SPACE) {
  306. i = (ULONG) ~0x3;
  307. } else {
  308. i = (ULONG) ~0xF;
  309. }
  310. if ((*BaseAddress[j] & i) != (*BaseAddress2[j] & i)) {
  311. Match = FALSE;
  312. }
  313. if (Is64BitBaseAddress(*BaseAddress[j])) {
  314. j++;
  315. if ((*BaseAddress[j] & i) != (*BaseAddress2[j] & i)) {
  316. Match = FALSE;
  317. }
  318. }
  319. }
  320. }
  321. return Match;
  322. }
  323. BOOLEAN
  324. PcipCalcBaseAddrPointers (
  325. IN PDEVICE_DATA DeviceData,
  326. IN PPCI_COMMON_CONFIG PciData,
  327. OUT PULONG *BaseAddress,
  328. OUT PULONG NoBaseAddress,
  329. OUT PULONG RomIndex
  330. )
  331. /*++
  332. Routine Description:
  333. This function returns the an array of BaseAddress pointers
  334. in PciData.
  335. Arguments:
  336. Return Value:
  337. --*/
  338. {
  339. ULONG j;
  340. BOOLEAN RomEnabled;
  341. switch (PCI_CONFIG_TYPE(PciData)) {
  342. case PCI_DEVICE_TYPE:
  343. *NoBaseAddress = PCI_TYPE0_ADDRESSES+1;
  344. for (j=0; j < PCI_TYPE0_ADDRESSES; j++) {
  345. BaseAddress[j] = &PciData->u.type0.BaseAddresses[j];
  346. }
  347. BaseAddress[j] = &PciData->u.type0.ROMBaseAddress;
  348. *RomIndex = j;
  349. break;
  350. case PCI_BRIDGE_TYPE:
  351. *NoBaseAddress = PCI_TYPE1_ADDRESSES+1;
  352. for (j=0; j < PCI_TYPE1_ADDRESSES; j++) {
  353. BaseAddress[j] = &PciData->u.type1.BaseAddresses[j];
  354. }
  355. BaseAddress[j] = &PciData->u.type1.ROMBaseAddress;
  356. *RomIndex = j;
  357. break;
  358. default:
  359. // BUGBUG: unkown type
  360. *NoBaseAddress = 0;
  361. ASSERT (*NoBaseAddress);
  362. }
  363. RomEnabled = (*BaseAddress[*RomIndex] & PCI_ROMADDRESS_ENABLED) ? TRUE : FALSE;
  364. //
  365. // The device's Rom Base Address register is only enabled if it
  366. // was originaly found that way.
  367. //
  368. // Clear ROM reserved bits
  369. *BaseAddress[*RomIndex] &= ~0x7FF;
  370. if (!DeviceData->EnableRom) {
  371. ASSERT (*RomIndex+1 == *NoBaseAddress);
  372. *NoBaseAddress -= 1;
  373. }
  374. return RomEnabled;
  375. }
  376. #if DBG
  377. ULONG ApmDebug = 9;
  378. VOID
  379. PciDebugPrint (
  380. ULONG Level,
  381. PCCHAR DebugMessage,
  382. ...
  383. )
  384. {
  385. UCHAR Buffer[256];
  386. va_list ap;
  387. va_start(ap, DebugMessage);
  388. if (Level <= ApmDebug) {
  389. vsprintf(Buffer, DebugMessage, ap);
  390. DbgPrint(Buffer);
  391. }
  392. va_end(ap);
  393. }
  394. #endif
  395. NTSTATUS
  396. BugBugSubclass (
  397. VOID
  398. )
  399. {
  400. DbgPrint ("PCI: BUGBUG SUBCLASS\n");
  401. return STATUS_SUCCESS;
  402. }