Source code of Windows XP (NT5)
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.

2481 lines
69 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1997 - 1999
  6. //
  7. // File: ctlrfdo.c
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "pciidex.h"
  11. #ifdef ALLOC_PRAGMA
  12. #pragma alloc_text(PAGE, ControllerAddDevice)
  13. #pragma alloc_text(PAGE, ControllerStartDevice)
  14. #pragma alloc_text(PAGE, ControllerStopDevice)
  15. #pragma alloc_text(PAGE, ControllerStopController)
  16. #pragma alloc_text(PAGE, ControllerSurpriseRemoveDevice)
  17. #pragma alloc_text(PAGE, ControllerRemoveDevice)
  18. #pragma alloc_text(PAGE, ControllerQueryDeviceRelations)
  19. #pragma alloc_text(PAGE, ControllerQueryInterface)
  20. #pragma alloc_text(PAGE, AnalyzeResourceList)
  21. #pragma alloc_text(PAGE, ControllerOpMode)
  22. #pragma alloc_text(PAGE, PciIdeChannelEnabled)
  23. #pragma alloc_text(PAGE, PciIdeCreateTimingTable)
  24. #pragma alloc_text(PAGE, PciIdeInitControllerProperties)
  25. #pragma alloc_text(PAGE, ControllerUsageNotification)
  26. #pragma alloc_text(PAGE, PciIdeGetBusStandardInterface)
  27. #pragma alloc_text(PAGE, ControllerQueryPnPDeviceState)
  28. #pragma alloc_text(NONPAGE, EnablePCIBusMastering)
  29. #pragma alloc_text(NONPAGE, ControllerUsageNotificationCompletionRoutine)
  30. #pragma alloc_text(NONPAGE, ControllerRemoveDeviceCompletionRoutine)
  31. #pragma alloc_text(NONPAGE, ControllerStartDeviceCompletionRoutine)
  32. #endif // ALLOC_PRAGMA
  33. //
  34. // Must match mshdc.inf
  35. //
  36. static PWCHAR ChannelEnableMaskName[MAX_IDE_CHANNEL] = {
  37. L"MasterOnMask",
  38. L"SlaveOnMask"
  39. };
  40. static PWCHAR ChannelEnablePciConfigOffsetName[MAX_IDE_CHANNEL] = {
  41. L"MasterOnConfigOffset",
  42. L"SlaveOnConfigOffset"
  43. };
  44. static ULONG PciIdeXNextControllerNumber = 0;
  45. static ULONG PciIdeXNextChannelNumber = 0;
  46. NTSTATUS
  47. ControllerAddDevice(
  48. IN PDRIVER_OBJECT DriverObject,
  49. IN PDEVICE_OBJECT PhysicalDeviceObject
  50. )
  51. {
  52. PDEVICE_OBJECT deviceObject;
  53. PCTRLFDO_EXTENSION fdoExtension;
  54. NTSTATUS status;
  55. PDRIVER_OBJECT_EXTENSION driverObjectExtension;
  56. ULONG deviceExtensionSize;
  57. UNICODE_STRING deviceName;
  58. WCHAR deviceNameBuffer[64];
  59. ULONG controllerNumber;
  60. PAGED_CODE();
  61. driverObjectExtension =
  62. (PDRIVER_OBJECT_EXTENSION) IoGetDriverObjectExtension(
  63. DriverObject,
  64. DRIVER_OBJECT_EXTENSION_ID
  65. );
  66. ASSERT (driverObjectExtension);
  67. //
  68. // devobj name
  69. //
  70. controllerNumber = InterlockedIncrement(&PciIdeXNextControllerNumber) - 1;
  71. swprintf(deviceNameBuffer, DEVICE_OJBECT_BASE_NAME L"\\PciIde%d", controllerNumber);
  72. RtlInitUnicodeString(&deviceName, deviceNameBuffer);
  73. deviceExtensionSize = sizeof(CTRLFDO_EXTENSION) +
  74. driverObjectExtension->ExtensionSize;
  75. //
  76. // We've been given the PhysicalDeviceObject for an IDE controller. Create the
  77. // FunctionalDeviceObject. Our FDO will be nameless.
  78. //
  79. status = IoCreateDevice(
  80. DriverObject, // our driver object
  81. deviceExtensionSize, // size of our extension
  82. &deviceName, // our name
  83. FILE_DEVICE_BUS_EXTENDER, // device type
  84. FILE_DEVICE_SECURE_OPEN, // device characteristics
  85. FALSE, // not exclusive
  86. &deviceObject // store new device object here
  87. );
  88. if( !NT_SUCCESS( status )){
  89. return status;
  90. }
  91. fdoExtension = (PCTRLFDO_EXTENSION)deviceObject->DeviceExtension;
  92. RtlZeroMemory (fdoExtension, deviceExtensionSize);
  93. //
  94. // We have our FunctionalDeviceObject, initialize it.
  95. //
  96. fdoExtension->AttacheePdo = PhysicalDeviceObject;
  97. fdoExtension->DeviceObject = deviceObject;
  98. fdoExtension->DriverObject = DriverObject;
  99. fdoExtension->ControllerNumber = controllerNumber;
  100. fdoExtension->VendorSpecificDeviceEntension = fdoExtension + 1;
  101. // Dispatch Table
  102. fdoExtension->DefaultDispatch = PassDownToNextDriver;
  103. fdoExtension->PnPDispatchTable = FdoPnpDispatchTable;
  104. fdoExtension->PowerDispatchTable = FdoPowerDispatchTable;
  105. fdoExtension->WmiDispatchTable = FdoWmiDispatchTable;
  106. //
  107. // Get the Device Control Flags out of the registry
  108. //
  109. fdoExtension->DeviceControlsFlags = 0;
  110. status = PciIdeXGetDeviceParameter (
  111. fdoExtension->AttacheePdo,
  112. L"DeviceControlFlags",
  113. &fdoExtension->DeviceControlsFlags
  114. );
  115. if (!NT_SUCCESS(status)) {
  116. DebugPrint ((1, "PciIdeX: Unable to get DeviceControlFlags from the registry\n"));
  117. //
  118. // this is not a serious error...continue to load
  119. //
  120. status = STATUS_SUCCESS;
  121. }
  122. //
  123. // Now attach to the PDO we were given.
  124. //
  125. fdoExtension->AttacheeDeviceObject = IoAttachDeviceToDeviceStack (
  126. deviceObject,
  127. PhysicalDeviceObject
  128. );
  129. if (fdoExtension->AttacheeDeviceObject == NULL){
  130. //
  131. // Couldn't attach. Delete the FDO.
  132. //
  133. IoDeleteDevice (deviceObject);
  134. } else {
  135. //
  136. // fix up alignment requirement
  137. //
  138. deviceObject->AlignmentRequirement = fdoExtension->AttacheeDeviceObject->AlignmentRequirement;
  139. if (deviceObject->AlignmentRequirement < 1) {
  140. deviceObject->AlignmentRequirement = 1;
  141. }
  142. //
  143. // get the standard bus interface
  144. // (for READ_CONFIG/WRITE_CONFIG
  145. //
  146. status = PciIdeGetBusStandardInterface(fdoExtension);
  147. if (!NT_SUCCESS(status)) {
  148. IoDetachDevice (fdoExtension->AttacheeDeviceObject);
  149. IoDeleteDevice (deviceObject);
  150. return status;
  151. }
  152. //
  153. // Init operating mode (native or legacy)
  154. //
  155. ControllerOpMode (fdoExtension);
  156. #ifdef ENABLE_NATIVE_MODE
  157. if (IsNativeMode(fdoExtension)) {
  158. NTSTATUS interfaceStatus = PciIdeGetNativeModeInterface(fdoExtension);
  159. //
  160. // bad pci.sys.
  161. // we should still work. However, the window where an interrupt fires before
  162. // we are ready to dismiss it would not be closed. Can't do much at this point.
  163. //
  164. //ASSERT(NT_SUCCESS(interfaceStatus));
  165. }
  166. #endif
  167. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  168. }
  169. return status;
  170. } // ControllerAddDevice
  171. NTSTATUS
  172. ControllerStartDevice (
  173. IN PDEVICE_OBJECT DeviceObject,
  174. IN OUT PIRP Irp
  175. )
  176. {
  177. PIO_STACK_LOCATION thisIrpSp;
  178. NTSTATUS status;
  179. PCTRLFDO_EXTENSION fdoExtension;
  180. PCM_RESOURCE_LIST resourceList;
  181. PCM_PARTIAL_RESOURCE_DESCRIPTOR irqPartialDescriptors;
  182. ULONG i;
  183. KEVENT event;
  184. POWER_STATE powerState;
  185. PAGED_CODE();
  186. thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
  187. fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
  188. resourceList = thisIrpSp->Parameters.StartDevice.AllocatedResourcesTranslated;
  189. if (!resourceList) {
  190. DebugPrint ((1, "PciIde: Starting with no resource\n"));
  191. }
  192. #ifdef ENABLE_NATIVE_MODE
  193. //
  194. // Let PCI know that we will manage the decodes
  195. //
  196. if (IsNativeMode(fdoExtension)) {
  197. ControllerDisableInterrupt(fdoExtension);
  198. }
  199. #endif
  200. //
  201. // Call the lower level drivers with a the Irp
  202. //
  203. KeInitializeEvent(&event,
  204. SynchronizationEvent,
  205. FALSE);
  206. IoCopyCurrentIrpStackLocationToNext (Irp);
  207. Irp->IoStatus.Status = STATUS_SUCCESS;
  208. IoSetCompletionRoutine(
  209. Irp,
  210. ControllerStartDeviceCompletionRoutine,
  211. &event,
  212. TRUE,
  213. TRUE,
  214. TRUE
  215. );
  216. //
  217. // Pass the irp along
  218. //
  219. status = IoCallDriver(fdoExtension->AttacheeDeviceObject, Irp);
  220. //
  221. // Wait for it to come back...
  222. //
  223. if (status == STATUS_PENDING) {
  224. KeWaitForSingleObject(
  225. &event,
  226. Executive,
  227. KernelMode,
  228. FALSE,
  229. NULL
  230. );
  231. //
  232. // Grab back the 'real' status
  233. //
  234. status = Irp->IoStatus.Status;
  235. }
  236. if (!NT_SUCCESS(status)) {
  237. goto GetOut;
  238. }
  239. powerState.SystemState = PowerSystemWorking;
  240. status = PciIdeIssueSetPowerState (
  241. fdoExtension,
  242. SystemPowerState,
  243. powerState,
  244. TRUE
  245. );
  246. if (status == STATUS_INVALID_DEVICE_REQUEST) {
  247. //
  248. // The DeviceObject below us does not support power irp,
  249. // we will assume we are powered up
  250. //
  251. fdoExtension->SystemPowerState = PowerSystemWorking;
  252. } else if (!NT_SUCCESS(status)) {
  253. goto GetOut;
  254. }
  255. powerState.DeviceState = PowerDeviceD0;
  256. status= PciIdeIssueSetPowerState (
  257. fdoExtension,
  258. DevicePowerState,
  259. powerState,
  260. TRUE
  261. );
  262. if (status == STATUS_INVALID_DEVICE_REQUEST) {
  263. //
  264. // The DeviceObject Below us does not support power irp,
  265. // pretend we are powered up
  266. //
  267. fdoExtension->DevicePowerState = PowerDeviceD0;
  268. } else if (!NT_SUCCESS(status)) {
  269. goto GetOut;
  270. }
  271. #ifdef ENABLE_NATIVE_MODE
  272. if (!IsNativeMode(fdoExtension)) {
  273. #endif
  274. //
  275. // Turn on PCI busmastering
  276. //
  277. EnablePCIBusMastering (
  278. fdoExtension
  279. );
  280. #ifdef ENABLE_NATIVE_MODE
  281. }
  282. #endif
  283. //
  284. // Initialize a fast mutex for later use
  285. //
  286. KeInitializeSpinLock(
  287. &fdoExtension->PciConfigDataLock
  288. );
  289. if (!NT_SUCCESS(status)) {
  290. goto GetOut;
  291. }
  292. //
  293. // Analyze the resources
  294. //
  295. status = AnalyzeResourceList (fdoExtension, resourceList);
  296. if (!NT_SUCCESS(status)) {
  297. goto GetOut;
  298. }
  299. //
  300. // Initialize controller properties. We need the resources
  301. // at this point for Native mode IDE controllers
  302. //
  303. PciIdeInitControllerProperties (
  304. fdoExtension
  305. );
  306. #ifdef ENABLE_NATIVE_MODE
  307. if (IsNativeMode(fdoExtension)) {
  308. IDE_CHANNEL_STATE channelState;
  309. #if DBG
  310. {
  311. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
  312. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  313. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
  314. ULONG resourceListSize;
  315. ULONG i;
  316. ULONG j;
  317. fullResourceList = resourceList->List;
  318. resourceListSize = 0;
  319. DebugPrint ((1, "Pciidex: Starting native mode device: FDOe\n", fdoExtension));
  320. for (i=0; i<resourceList->Count; i++) {
  321. partialResourceList = &(fullResourceList->PartialResourceList);
  322. partialDescriptors = fullResourceList->PartialResourceList.PartialDescriptors;
  323. for (j=0; j<partialResourceList->Count; j++) {
  324. if (partialDescriptors[j].Type == CmResourceTypePort) {
  325. DebugPrint ((1, "pciidex: IO Port = 0x%x. Lenght = 0x%x\n", partialDescriptors[j].u.Port.Start.LowPart, partialDescriptors[j].u.Port.Length));
  326. } else if (partialDescriptors[j].Type == CmResourceTypeInterrupt) {
  327. DebugPrint ((1, "pciidex: Int Level = 0x%x. Int Vector = 0x%x\n", partialDescriptors[j].u.Interrupt.Level, partialDescriptors[j].u.Interrupt.Vector));
  328. } else {
  329. DebugPrint ((1, "pciidex: Unknown resource\n"));
  330. }
  331. }
  332. fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + j);
  333. }
  334. }
  335. #endif // DBG
  336. fdoExtension->ControllerIsrInstalled = FALSE;
  337. for (i=0; i< MAX_IDE_CHANNEL; i++) {
  338. //
  339. // Analyze the resources we are getting
  340. //
  341. status = DigestResourceList(
  342. &fdoExtension->IdeResource,
  343. fdoExtension->PdoResourceList[i],
  344. &fdoExtension->IrqPartialDescriptors[i]
  345. );
  346. if (!NT_SUCCESS(status) ) {
  347. goto GetOut;
  348. }
  349. if (!fdoExtension->IrqPartialDescriptors[i]) {
  350. status = STATUS_INSUFFICIENT_RESOURCES;
  351. goto GetOut;
  352. }
  353. DebugPrint((1,
  354. "Pciidex: Connecting interrupt for channel %x interrupt vector 0x%x\n",
  355. i,
  356. fdoExtension->IrqPartialDescriptors[i]->u.Interrupt.Vector
  357. ));
  358. channelState = PciIdeChannelEnabled (fdoExtension, i);
  359. if (channelState != ChannelDisabled) {
  360. //
  361. // Build io address structure.
  362. //
  363. AtapiBuildIoAddress(
  364. fdoExtension->IdeResource.TranslatedCommandBaseAddress,
  365. fdoExtension->IdeResource.TranslatedControlBaseAddress,
  366. &fdoExtension->BaseIoAddress1[i],
  367. &fdoExtension->BaseIoAddress2[i],
  368. &fdoExtension->BaseIoAddress1Length[i],
  369. &fdoExtension->BaseIoAddress2Length[i],
  370. &fdoExtension->MaxIdeDevice[i],
  371. NULL);
  372. //
  373. // Install the ISR
  374. //
  375. status = ControllerInterruptControl(fdoExtension, i, 0);
  376. if (!NT_SUCCESS(status)) {
  377. break;
  378. }
  379. }
  380. }
  381. if (!NT_SUCCESS(status)) {
  382. goto GetOut;
  383. }
  384. //
  385. // This flag is needed for the ISR to enable interrupts.
  386. //
  387. fdoExtension->ControllerIsrInstalled = TRUE;
  388. //
  389. // Enable the interrupt in both the channels
  390. //
  391. ControllerEnableInterrupt(fdoExtension);
  392. fdoExtension->NativeInterruptEnabled = TRUE;
  393. //
  394. // See the comments in the ISR regarding these flags
  395. //
  396. ASSERT(fdoExtension->ControllerIsrInstalled == TRUE);
  397. ASSERT(fdoExtension->NativeInterruptEnabled == TRUE);
  398. //
  399. // Turn on PCI busmastering
  400. //
  401. EnablePCIBusMastering (
  402. fdoExtension
  403. );
  404. for (i=0; i< MAX_IDE_CHANNEL; i++) {
  405. PIDE_BUS_MASTER_REGISTERS bmRegister;
  406. //
  407. // Check the bus master registers
  408. //
  409. bmRegister = (PIDE_BUS_MASTER_REGISTERS)(((PUCHAR)fdoExtension->TranslatedBusMasterBaseAddress) + i*8);
  410. if (READ_PORT_UCHAR (&bmRegister->Status) & BUSMASTER_ZERO_BITS) {
  411. fdoExtension->NoBusMaster[i] = TRUE;
  412. }
  413. }
  414. }
  415. #endif
  416. status = PciIdeCreateSyncChildAccess (fdoExtension);
  417. if (!NT_SUCCESS(status)) {
  418. goto GetOut;
  419. }
  420. status = PciIdeCreateTimingTable(fdoExtension);
  421. if (!NT_SUCCESS(status)) {
  422. goto GetOut;
  423. }
  424. GetOut:
  425. if (NT_SUCCESS(status)) {
  426. #if DBG
  427. {
  428. PCM_RESOURCE_LIST resourceList;
  429. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
  430. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  431. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
  432. ULONG i;
  433. ULONG j;
  434. ULONG k;
  435. DebugPrint ((1, "PciIdeX: Starting device:\n"));
  436. for (k=0; k <MAX_IDE_CHANNEL + 1; k++) {
  437. if (k == MAX_IDE_CHANNEL) {
  438. DebugPrint ((1, "PciIdeX: Busmaster resources:\n"));
  439. resourceList = fdoExtension->BmResourceList;
  440. } else {
  441. DebugPrint ((1, "PciIdeX: PDO %d resources:\n", k));
  442. resourceList = fdoExtension->PdoResourceList[k];
  443. }
  444. if (resourceList) {
  445. fullResourceList = resourceList->List;
  446. for (i=0; i<resourceList->Count; i++) {
  447. partialResourceList = &(fullResourceList->PartialResourceList);
  448. partialDescriptors = fullResourceList->PartialResourceList.PartialDescriptors;
  449. for (j=0; j<partialResourceList->Count; j++) {
  450. if (partialDescriptors[j].Type == CmResourceTypePort) {
  451. DebugPrint ((1, "IdePort: IO Port = 0x%x. Lenght = 0x%x\n", partialDescriptors[j].u.Port.Start.LowPart, partialDescriptors[j].u.Port.Length));
  452. } else if (partialDescriptors[j].Type == CmResourceTypeMemory) {
  453. DebugPrint ((1, "IdePort: Memory Port = 0x%x. Lenght = 0x%x\n", partialDescriptors[j].u.Memory.Start.LowPart, partialDescriptors[j].u.Memory.Length));
  454. } else if (partialDescriptors[j].Type == CmResourceTypeInterrupt) {
  455. DebugPrint ((1, "IdePort: Int Level = 0x%x. Int Vector = 0x%x\n", partialDescriptors[j].u.Interrupt.Level, partialDescriptors[j].u.Interrupt.Vector));
  456. } else {
  457. DebugPrint ((1, "IdePort: Unknown resource\n"));
  458. }
  459. }
  460. fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + j);
  461. }
  462. }
  463. }
  464. }
  465. #endif // DBG
  466. }
  467. Irp->IoStatus.Status = status;
  468. Irp->IoStatus.Information = 0;
  469. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  470. return status;
  471. } // ControllerStartDevice
  472. NTSTATUS
  473. ControllerStartDeviceCompletionRoutine(
  474. IN PDEVICE_OBJECT DeviceObject,
  475. IN OUT PIRP Irp,
  476. IN OUT PVOID Context
  477. )
  478. {
  479. PKEVENT event = (PKEVENT) Context;
  480. //
  481. // Signal the event
  482. //
  483. KeSetEvent( event, IO_NO_INCREMENT, FALSE );
  484. //
  485. // Always return MORE_PROCESSING_REQUIRED
  486. // will complete it later
  487. //
  488. return STATUS_MORE_PROCESSING_REQUIRED;
  489. } // ControllerStartDeviceCompletionRoutine
  490. NTSTATUS
  491. ControllerStopDevice (
  492. IN PDEVICE_OBJECT DeviceObject,
  493. IN OUT PIRP Irp
  494. )
  495. {
  496. PCTRLFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  497. NTSTATUS status;
  498. PAGED_CODE();
  499. status = ControllerStopController (
  500. fdoExtension
  501. );
  502. ASSERT (NT_SUCCESS(status));
  503. Irp->IoStatus.Status = STATUS_SUCCESS;
  504. IoSkipCurrentIrpStackLocation(Irp);
  505. return IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
  506. } // ControllerStopDevice
  507. NTSTATUS
  508. ControllerStopController (
  509. IN PCTRLFDO_EXTENSION FdoExtension
  510. )
  511. {
  512. ULONG i;
  513. PAGED_CODE();
  514. if (FdoExtension->BmResourceList) {
  515. ExFreePool (FdoExtension->BmResourceList);
  516. FdoExtension->BmResourceList = NULL;
  517. }
  518. for (i=0; i<MAX_IDE_CHANNEL; i++) {
  519. if (FdoExtension->PdoResourceList[i]) {
  520. ExFreePool (FdoExtension->PdoResourceList[i]);
  521. FdoExtension->PdoResourceList[i] = NULL;
  522. }
  523. }
  524. #ifdef ENABLE_NATIVE_MODE
  525. //
  526. // We need to reset the flags in this order. Otherwise an interrupt would
  527. // result in the decodes to be enabled by the ISR. See the comments in the ISR
  528. //
  529. FdoExtension->ControllerIsrInstalled = FALSE;
  530. ControllerDisableInterrupt(FdoExtension);
  531. FdoExtension->NativeInterruptEnabled = FALSE;
  532. for (i=0; i< MAX_IDE_CHANNEL; i++) {
  533. NTSTATUS status;
  534. DebugPrint((1, "Pciidex: DisConnecting interrupt for channel %x\n", i));
  535. //
  536. // Disconnect the ISR
  537. //
  538. status = ControllerInterruptControl(FdoExtension, i, 1 );
  539. ASSERT(NT_SUCCESS(status));
  540. }
  541. ASSERT(FdoExtension->ControllerIsrInstalled == FALSE);
  542. ASSERT(FdoExtension->NativeInterruptEnabled == FALSE);
  543. #endif
  544. PciIdeDeleteSyncChildAccess (FdoExtension);
  545. return STATUS_SUCCESS;
  546. } // ControllerStopController
  547. NTSTATUS
  548. ControllerSurpriseRemoveDevice (
  549. IN PDEVICE_OBJECT DeviceObject,
  550. IN OUT PIRP Irp
  551. )
  552. {
  553. PCTRLFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  554. NTSTATUS status;
  555. ULONG i;
  556. PAGED_CODE();
  557. #if DBG
  558. //
  559. // make sure all the children are removed or surprise removed
  560. //
  561. for (i=0; i<MAX_IDE_CHANNEL; i++) {
  562. PCHANPDO_EXTENSION pdoExtension;
  563. pdoExtension = fdoExtension->ChildDeviceExtension[i];
  564. if (pdoExtension) {
  565. ASSERT (pdoExtension->PdoState & (PDOS_SURPRISE_REMOVED | PDOS_REMOVED));
  566. }
  567. }
  568. #endif // DBG
  569. status = ControllerStopController (fdoExtension);
  570. ASSERT (NT_SUCCESS(status));
  571. Irp->IoStatus.Status = STATUS_SUCCESS;
  572. IoSkipCurrentIrpStackLocation ( Irp );
  573. return IoCallDriver(fdoExtension->AttacheeDeviceObject, Irp);
  574. } // ControllerSurpriseRemoveDevice
  575. NTSTATUS
  576. ControllerRemoveDevice (
  577. IN PDEVICE_OBJECT DeviceObject,
  578. IN OUT PIRP Irp
  579. )
  580. {
  581. PCTRLFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  582. NTSTATUS status;
  583. KEVENT event;
  584. ULONG i;
  585. PAGED_CODE();
  586. //
  587. // Kill all the children if any
  588. //
  589. for (i=0; i<MAX_IDE_CHANNEL; i++) {
  590. PCHANPDO_EXTENSION pdoExtension;
  591. pdoExtension = fdoExtension->ChildDeviceExtension[i];
  592. if (pdoExtension) {
  593. status = ChannelStopChannel (pdoExtension);
  594. ASSERT (NT_SUCCESS(status));
  595. //
  596. // mark this device invalid
  597. //
  598. ChannelUpdatePdoState (
  599. pdoExtension,
  600. PDOS_DEADMEAT | PDOS_REMOVED,
  601. 0
  602. );
  603. IoDeleteDevice (pdoExtension->DeviceObject);
  604. fdoExtension->ChildDeviceExtension[i] = NULL;
  605. }
  606. }
  607. status = ControllerStopController (fdoExtension);
  608. ASSERT (NT_SUCCESS(status));
  609. if (fdoExtension->TransferModeTimingTable) {
  610. ExFreePool(fdoExtension->TransferModeTimingTable);
  611. fdoExtension->TransferModeTimingTable = NULL;
  612. fdoExtension->TransferModeTableLength = 0;
  613. }
  614. KeInitializeEvent(&event, SynchronizationEvent, FALSE);
  615. IoCopyCurrentIrpStackLocationToNext (Irp);
  616. IoSetCompletionRoutine(
  617. Irp,
  618. ControllerRemoveDeviceCompletionRoutine,
  619. &event,
  620. TRUE,
  621. TRUE,
  622. TRUE
  623. );
  624. status = IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
  625. if (status == STATUS_PENDING) {
  626. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  627. }
  628. IoDetachDevice (fdoExtension->AttacheeDeviceObject);
  629. IoDeleteDevice (DeviceObject);
  630. //return STATUS_SUCCESS;
  631. return status;
  632. } // ControllerRemoveDevice
  633. NTSTATUS
  634. ControllerRemoveDeviceCompletionRoutine (
  635. IN PDEVICE_OBJECT DeviceObject,
  636. IN PIRP Irp,
  637. IN PVOID Context
  638. )
  639. {
  640. PKEVENT event = Context;
  641. KeSetEvent(event, 0, FALSE);
  642. return STATUS_SUCCESS;
  643. } // ControllerRemoveDeviceCompletionRoutine
  644. NTSTATUS
  645. ControllerQueryDeviceRelations (
  646. IN PDEVICE_OBJECT DeviceObject,
  647. IN OUT PIRP Irp
  648. )
  649. {
  650. PIO_STACK_LOCATION thisIrpSp;
  651. PCTRLFDO_EXTENSION fdoExtension;
  652. PDEVICE_RELATIONS deviceRelations;
  653. NTSTATUS status;
  654. ULONG deviceRelationsSize;
  655. ULONG channel;
  656. PCONFIGURATION_INFORMATION configurationInformation = IoGetConfigurationInformation();
  657. ULONG nextUniqueNumber;
  658. PAGED_CODE();
  659. thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
  660. fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
  661. status = STATUS_SUCCESS;
  662. switch (thisIrpSp->Parameters.QueryDeviceRelations.Type) {
  663. case BusRelations:
  664. DebugPrint ((3, "ControllerQueryDeviceRelations: bus relations\n"));
  665. deviceRelationsSize = FIELD_OFFSET (DEVICE_RELATIONS, Objects) +
  666. MAX_IDE_CHANNEL * sizeof(PDEVICE_OBJECT);
  667. deviceRelations = ExAllocatePool (PagedPool, deviceRelationsSize);
  668. if(!deviceRelations) {
  669. DebugPrint ((1,
  670. "IdeQueryDeviceRelations: Unable to allocate DeviceRelations structures\n"));
  671. status = STATUS_INSUFFICIENT_RESOURCES;
  672. }
  673. if (NT_SUCCESS(status)) {
  674. LARGE_INTEGER tickCount;
  675. ULONG newBusScanTime;
  676. ULONG newBusScanTimeDelta;
  677. BOOLEAN reportUnknownAsNewChild;
  678. //
  679. // determine if we should return unknown child as new child
  680. // unknown child is IDE channel which we don't know
  681. // it is enabled or not unless we pnp start the channel
  682. // and poke at it to find out.
  683. //
  684. // since we don't want to go into an infinite cycle of
  685. // starting and failing start on a unknown child, we will
  686. // limit our frequency
  687. //
  688. KeQueryTickCount(&tickCount);
  689. newBusScanTime = (ULONG) ((tickCount.QuadPart *
  690. ((ULONGLONG) KeQueryTimeIncrement())) / ((ULONGLONG) 10000000));
  691. newBusScanTimeDelta = newBusScanTime - fdoExtension->LastBusScanTime;
  692. DebugPrint ((1, "PCIIDEX: Last rescan was %d seconds ago.\n", newBusScanTimeDelta));
  693. if ((newBusScanTimeDelta < MIN_BUS_SCAN_PERIOD_IN_SEC) &&
  694. (fdoExtension->LastBusScanTime != 0)) {
  695. reportUnknownAsNewChild = FALSE;
  696. } else {
  697. reportUnknownAsNewChild = TRUE;
  698. }
  699. fdoExtension->LastBusScanTime = newBusScanTime;
  700. RtlZeroMemory (deviceRelations, deviceRelationsSize);
  701. for (channel = 0; channel < MAX_IDE_CHANNEL; channel++) {
  702. PDEVICE_OBJECT deviceObject;
  703. PCHANPDO_EXTENSION pdoExtension;
  704. UNICODE_STRING deviceName;
  705. WCHAR deviceNameBuffer[256];
  706. PDEVICE_OBJECT deviceObjectToReturn;
  707. IDE_CHANNEL_STATE channelState;
  708. deviceObjectToReturn = NULL;
  709. pdoExtension = fdoExtension->ChildDeviceExtension[channel];
  710. channelState = PciIdeChannelEnabled (fdoExtension, channel);
  711. if (pdoExtension) {
  712. //
  713. // already got a DeviceObject for this channel
  714. //
  715. if (channelState == ChannelDisabled) {
  716. ULONG pdoState;
  717. pdoState = ChannelUpdatePdoState (
  718. pdoExtension,
  719. PDOS_DEADMEAT,
  720. 0
  721. );
  722. } else {
  723. deviceObjectToReturn = pdoExtension->DeviceObject;
  724. }
  725. } else if ((channelState == ChannelEnabled) ||
  726. ((channelState == ChannelStateUnknown) && reportUnknownAsNewChild)) {
  727. if (!fdoExtension->NativeMode[channel]) {
  728. if (channel == 0) {
  729. configurationInformation->AtDiskPrimaryAddressClaimed = TRUE;
  730. } else {
  731. configurationInformation->AtDiskSecondaryAddressClaimed = TRUE;
  732. }
  733. }
  734. //
  735. // Remove this when pnp mgr can deal with pdo with no names
  736. //
  737. nextUniqueNumber = InterlockedIncrement(&PciIdeXNextChannelNumber) - 1;
  738. swprintf(deviceNameBuffer, DEVICE_OJBECT_BASE_NAME L"\\PciIde%dChannel%d-%x", fdoExtension->ControllerNumber, channel, nextUniqueNumber);
  739. RtlInitUnicodeString (&deviceName, deviceNameBuffer);
  740. status = IoCreateDevice(
  741. fdoExtension->DriverObject, // our driver object
  742. sizeof(CHANPDO_EXTENSION), // size of our extension
  743. &deviceName, // our name
  744. FILE_DEVICE_CONTROLLER, // device type
  745. FILE_DEVICE_SECURE_OPEN, // device characteristics
  746. FALSE, // not exclusive
  747. &deviceObject // store new device object here
  748. );
  749. if (NT_SUCCESS(status)) {
  750. pdoExtension = (PCHANPDO_EXTENSION) deviceObject->DeviceExtension;
  751. RtlZeroMemory (pdoExtension, sizeof(CHANPDO_EXTENSION));
  752. pdoExtension->DeviceObject = deviceObject;
  753. pdoExtension->DriverObject = fdoExtension->DriverObject;
  754. pdoExtension->ParentDeviceExtension = fdoExtension;
  755. pdoExtension->ChannelNumber = channel;
  756. //
  757. // Dispatch Table
  758. //
  759. pdoExtension->DefaultDispatch = NoSupportIrp;
  760. pdoExtension->PnPDispatchTable = PdoPnpDispatchTable;
  761. pdoExtension->PowerDispatchTable = PdoPowerDispatchTable;
  762. pdoExtension->WmiDispatchTable = PdoWmiDispatchTable;
  763. KeInitializeSpinLock(&pdoExtension->SpinLock);
  764. fdoExtension->ChildDeviceExtension[channel] = pdoExtension;
  765. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  766. fdoExtension->NumberOfChildren++;
  767. InterlockedIncrement(&fdoExtension->NumberOfChildrenPowerUp);
  768. //
  769. // fix up alignment requirement
  770. // check with the miniport also
  771. //
  772. deviceObject->AlignmentRequirement = fdoExtension->ControllerProperties.AlignmentRequirement;
  773. if (deviceObject->AlignmentRequirement < fdoExtension->AttacheeDeviceObject->AlignmentRequirement) {
  774. deviceObject->AlignmentRequirement =
  775. fdoExtension->DeviceObject->AlignmentRequirement;
  776. }
  777. if (deviceObject->AlignmentRequirement < 1) {
  778. deviceObject->AlignmentRequirement = 1;
  779. }
  780. //
  781. // return this new DeviceObject
  782. //
  783. deviceObjectToReturn = deviceObject;
  784. }
  785. }
  786. if (deviceObjectToReturn) {
  787. deviceRelations->Objects[(deviceRelations)->Count] = deviceObjectToReturn;
  788. ObReferenceObjectByPointer(deviceObjectToReturn,
  789. 0,
  790. 0,
  791. KernelMode);
  792. deviceRelations->Count++;
  793. }
  794. }
  795. }
  796. Irp->IoStatus.Information = (ULONG_PTR) deviceRelations;
  797. Irp->IoStatus.Status = status;
  798. break;
  799. default:
  800. status=STATUS_SUCCESS;
  801. DebugPrint ((1, "PciIdeQueryDeviceRelations: Unsupported device relation\n"));
  802. break;
  803. }
  804. if (NT_SUCCESS(status)) {
  805. IoSkipCurrentIrpStackLocation ( Irp );
  806. return IoCallDriver(fdoExtension->AttacheeDeviceObject, Irp);
  807. } else {
  808. //
  809. //Complete the request
  810. //
  811. IoCompleteRequest( Irp, IO_NO_INCREMENT );
  812. return status;
  813. }
  814. } // ControllerQueryDeviceRelations
  815. NTSTATUS
  816. ControllerQueryInterface (
  817. IN PDEVICE_OBJECT DeviceObject,
  818. IN OUT PIRP Irp
  819. )
  820. {
  821. PIO_STACK_LOCATION thisIrpSp;
  822. PCTRLFDO_EXTENSION fdoExtension;
  823. NTSTATUS status;
  824. PTRANSLATOR_INTERFACE translator;
  825. ULONG busNumber;
  826. PAGED_CODE();
  827. thisIrpSp = IoGetCurrentIrpStackLocation( Irp );
  828. fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
  829. status = Irp->IoStatus.Status;
  830. if (RtlEqualMemory(&GUID_TRANSLATOR_INTERFACE_STANDARD,
  831. thisIrpSp->Parameters.QueryInterface.InterfaceType,
  832. sizeof(GUID))
  833. && (thisIrpSp->Parameters.QueryInterface.Size >=
  834. sizeof(TRANSLATOR_INTERFACE))
  835. && (PtrToUlong(thisIrpSp->Parameters.QueryInterface.InterfaceSpecificData) ==
  836. CmResourceTypeInterrupt)) {
  837. if (!fdoExtension->NativeMode[0] && !fdoExtension->NativeMode[1]) {
  838. //
  839. // we only return a translator only if we are legacy controller
  840. //
  841. status = HalGetInterruptTranslator(
  842. PCIBus,
  843. 0,
  844. InterfaceTypeUndefined, // special "IDE" cookie
  845. thisIrpSp->Parameters.QueryInterface.Size,
  846. thisIrpSp->Parameters.QueryInterface.Version,
  847. (PTRANSLATOR_INTERFACE) thisIrpSp->Parameters.QueryInterface.Interface,
  848. &busNumber
  849. );
  850. }
  851. }
  852. //
  853. // Pass down.
  854. //
  855. Irp->IoStatus.Status = status;
  856. IoSkipCurrentIrpStackLocation ( Irp );
  857. return IoCallDriver(fdoExtension->AttacheeDeviceObject, Irp);
  858. } // ControllerQueryInterface
  859. //
  860. // initialize PCTRLFDO_EXTENSION->PCM_PARTIAL_RESOURCE_DESCRIPTOR(s)
  861. //
  862. NTSTATUS
  863. AnalyzeResourceList (
  864. PCTRLFDO_EXTENSION FdoExtension,
  865. PCM_RESOURCE_LIST ResourceList
  866. )
  867. {
  868. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceList;
  869. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  870. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialDescriptors;
  871. ULONG i;
  872. ULONG j;
  873. ULONG k;
  874. ULONG cmdChannel;
  875. ULONG ctrlChannel;
  876. ULONG intrChannel;
  877. ULONG bmAddr;
  878. ULONG pdoResourceListSize;
  879. PCM_RESOURCE_LIST pdoResourceList[MAX_IDE_CHANNEL];
  880. PCM_FULL_RESOURCE_DESCRIPTOR pdoFullResourceList[MAX_IDE_CHANNEL];
  881. PCM_PARTIAL_RESOURCE_LIST pdoPartialResourceList[MAX_IDE_CHANNEL];
  882. PCM_PARTIAL_RESOURCE_DESCRIPTOR pdoPartialDescriptors[MAX_IDE_CHANNEL];
  883. ULONG bmResourceListSize;
  884. PCM_RESOURCE_LIST bmResourceList;
  885. PCM_FULL_RESOURCE_DESCRIPTOR bmFullResourceList;
  886. PCM_PARTIAL_RESOURCE_LIST bmPartialResourceList;
  887. PCM_PARTIAL_RESOURCE_DESCRIPTOR bmPartialDescriptors;
  888. NTSTATUS status;
  889. PAGED_CODE();
  890. if (!ResourceList) {
  891. return STATUS_SUCCESS;
  892. }
  893. bmResourceListSize =
  894. sizeof (CM_RESOURCE_LIST) * ResourceList->Count; // This will have one CM_PARTIAL_RESOURCE_LIST
  895. bmResourceList = (PCM_RESOURCE_LIST) ExAllocatePool (NonPagedPool, bmResourceListSize);
  896. if (bmResourceList == NULL) {
  897. return STATUS_NO_MEMORY;
  898. }
  899. RtlZeroMemory (bmResourceList, bmResourceListSize);
  900. pdoResourceListSize =
  901. sizeof (CM_RESOURCE_LIST) * ResourceList->Count + // This will have one CM_PARTIAL_RESOURCE_LIST
  902. sizeof (CM_PARTIAL_RESOURCE_LIST) * 2;
  903. for (i=0; i<MAX_IDE_CHANNEL; i++) {
  904. pdoResourceList[i] = (PCM_RESOURCE_LIST) ExAllocatePool (NonPagedPool, pdoResourceListSize);
  905. if (pdoResourceList[i] == NULL) {
  906. DebugPrint ((0, "Unable to allocate resourceList for PDOs\n"));
  907. for (j=0; j<i; j++) {
  908. ExFreePool (pdoResourceList[j]);
  909. }
  910. ExFreePool (bmResourceList);
  911. return STATUS_NO_MEMORY;
  912. }
  913. RtlZeroMemory (pdoResourceList[i], pdoResourceListSize);
  914. }
  915. fullResourceList = ResourceList->List;
  916. bmResourceList->Count = 0;
  917. bmFullResourceList = bmResourceList->List;
  918. for (k=0; k<MAX_IDE_CHANNEL; k++) {
  919. pdoResourceList[k]->Count = 0;
  920. pdoFullResourceList[k] = pdoResourceList[k]->List;
  921. }
  922. cmdChannel = ctrlChannel = intrChannel = bmAddr = 0;
  923. for (j=0; j<ResourceList->Count; j++) {
  924. partialResourceList = &(fullResourceList->PartialResourceList);
  925. partialDescriptors = partialResourceList->PartialDescriptors;
  926. RtlCopyMemory (
  927. bmFullResourceList,
  928. fullResourceList,
  929. FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
  930. );
  931. bmPartialResourceList = &(bmFullResourceList->PartialResourceList);
  932. bmPartialResourceList->Count = 0;
  933. bmPartialDescriptors = bmPartialResourceList->PartialDescriptors;
  934. for (k=0; k<MAX_IDE_CHANNEL; k++) {
  935. RtlCopyMemory (
  936. pdoFullResourceList[k],
  937. fullResourceList,
  938. FIELD_OFFSET(CM_FULL_RESOURCE_DESCRIPTOR, PartialResourceList.PartialDescriptors)
  939. );
  940. pdoPartialResourceList[k] = &(pdoFullResourceList[k]->PartialResourceList);
  941. pdoPartialResourceList[k]->Count = 0;
  942. pdoPartialDescriptors[k] = pdoPartialResourceList[k]->PartialDescriptors;
  943. }
  944. for (i=0; i<partialResourceList->Count; i++) {
  945. if (((partialDescriptors[j].Type == CmResourceTypePort) ||
  946. (partialDescriptors[j].Type == CmResourceTypeMemory)) &&
  947. (partialDescriptors[i].u.Port.Length == 8) &&
  948. (cmdChannel < MAX_IDE_CHANNEL)) {
  949. ASSERT (cmdChannel < MAX_IDE_CHANNEL);
  950. RtlCopyMemory (
  951. pdoPartialDescriptors[cmdChannel] + pdoPartialResourceList[cmdChannel]->Count,
  952. partialDescriptors + i,
  953. sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR)
  954. );
  955. pdoPartialResourceList[cmdChannel]->Count++;
  956. cmdChannel++;
  957. } else if (((partialDescriptors[j].Type == CmResourceTypePort) ||
  958. (partialDescriptors[j].Type == CmResourceTypeMemory)) &&
  959. (partialDescriptors[i].u.Port.Length == 4) &&
  960. (ctrlChannel < MAX_IDE_CHANNEL)) {
  961. ASSERT (ctrlChannel < MAX_IDE_CHANNEL);
  962. RtlCopyMemory (
  963. pdoPartialDescriptors[ctrlChannel] + pdoPartialResourceList[ctrlChannel]->Count,
  964. partialDescriptors + i,
  965. sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR)
  966. );
  967. pdoPartialResourceList[ctrlChannel]->Count++;
  968. ctrlChannel++;
  969. } else if (((partialDescriptors[j].Type == CmResourceTypePort) ||
  970. (partialDescriptors[j].Type == CmResourceTypeMemory)) &&
  971. (partialDescriptors[i].u.Port.Length == 16) &&
  972. (bmAddr < 1)) {
  973. ASSERT (bmAddr < 1);
  974. RtlCopyMemory (
  975. bmPartialDescriptors + bmPartialResourceList->Count,
  976. partialDescriptors + i,
  977. sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR)
  978. );
  979. bmPartialResourceList->Count++;
  980. bmAddr++;
  981. } else if ((partialDescriptors[i].Type == CmResourceTypeInterrupt) &&
  982. (intrChannel < MAX_IDE_CHANNEL)) {
  983. ASSERT (intrChannel < MAX_IDE_CHANNEL);
  984. RtlCopyMemory (
  985. pdoPartialDescriptors[intrChannel] + pdoPartialResourceList[intrChannel]->Count,
  986. partialDescriptors + i,
  987. sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR)
  988. );
  989. pdoPartialResourceList[intrChannel]->Count++;
  990. if (intrChannel == 0) {
  991. if (FdoExtension->NativeMode[1]) {
  992. intrChannel++;
  993. //
  994. // ISSUE: 08/30/2000
  995. // do I need to mark it sharable?
  996. // this needs to be revisited. (there are more issues)
  997. //
  998. RtlCopyMemory (
  999. pdoPartialDescriptors[intrChannel] + pdoPartialResourceList[intrChannel]->Count,
  1000. partialDescriptors + i,
  1001. sizeof (CM_PARTIAL_RESOURCE_DESCRIPTOR)
  1002. );
  1003. pdoPartialResourceList[intrChannel]->Count++;
  1004. }
  1005. }
  1006. intrChannel++;
  1007. } else if (partialDescriptors[i].Type == CmResourceTypeDeviceSpecific) {
  1008. partialDescriptors += partialDescriptors[i].u.DeviceSpecificData.DataSize;
  1009. }
  1010. }
  1011. if (bmPartialResourceList->Count) {
  1012. bmResourceList->Count++;
  1013. bmFullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR)
  1014. (bmPartialDescriptors + bmPartialResourceList->Count);
  1015. }
  1016. for (k=0; k<MAX_IDE_CHANNEL; k++) {
  1017. if (pdoPartialResourceList[k]->Count) {
  1018. pdoResourceList[k]->Count++;
  1019. pdoFullResourceList[k] = (PCM_FULL_RESOURCE_DESCRIPTOR)
  1020. (pdoPartialDescriptors[k] + pdoPartialResourceList[k]->Count);
  1021. }
  1022. }
  1023. fullResourceList = (PCM_FULL_RESOURCE_DESCRIPTOR) (partialDescriptors + i);
  1024. }
  1025. status = STATUS_SUCCESS;
  1026. for (k=0; k<MAX_IDE_CHANNEL; k++) {
  1027. if (FdoExtension->NativeMode[k]) {
  1028. //
  1029. // If the controller is in native mode, we should have all the resources
  1030. //
  1031. if ((k < cmdChannel) &&
  1032. (k < ctrlChannel) &&
  1033. (k < intrChannel)) {
  1034. //
  1035. // This is good
  1036. //
  1037. } else {
  1038. cmdChannel = 0;
  1039. ctrlChannel = 0;
  1040. intrChannel = 0;
  1041. bmAddr = 0;
  1042. status = STATUS_INSUFFICIENT_RESOURCES;
  1043. }
  1044. }
  1045. }
  1046. //
  1047. // If the controller is in legacy mode, we should not have any resources
  1048. //
  1049. if (!FdoExtension->NativeMode[0] && !FdoExtension->NativeMode[1]) {
  1050. //
  1051. // both channels in legacy mode
  1052. //
  1053. cmdChannel = 0;
  1054. ctrlChannel = 0;
  1055. intrChannel = 0;
  1056. }
  1057. FdoExtension->TranslatedBusMasterBaseAddress = NULL;
  1058. if (0 < bmAddr) {
  1059. FdoExtension->BmResourceList = bmResourceList;
  1060. FdoExtension->BmResourceListSize = (ULONG)(((PUCHAR)bmFullResourceList) - ((PUCHAR)bmResourceList));
  1061. if (FdoExtension->BmResourceList->List[0].PartialResourceList.PartialDescriptors->Type == CmResourceTypePort) {
  1062. //
  1063. // address is in i/o space
  1064. //
  1065. FdoExtension->TranslatedBusMasterBaseAddress =
  1066. (PIDE_BUS_MASTER_REGISTERS) (ULONG_PTR)FdoExtension->BmResourceList->List[0].PartialResourceList.PartialDescriptors->u.Port.Start.QuadPart;
  1067. FdoExtension->BusMasterBaseAddressSpace = IO_SPACE;
  1068. } else if (FdoExtension->BmResourceList->List[0].PartialResourceList.PartialDescriptors->Type == CmResourceTypeMemory) {
  1069. //
  1070. // address is in memory space
  1071. //
  1072. FdoExtension->TranslatedBusMasterBaseAddress =
  1073. (PIDE_BUS_MASTER_REGISTERS) MmMapIoSpace(
  1074. FdoExtension->BmResourceList->List[0].PartialResourceList.PartialDescriptors->u.Port.Start,
  1075. 16,
  1076. FALSE);
  1077. ASSERT (FdoExtension->TranslatedBusMasterBaseAddress);
  1078. // free mapped io resouces in stop/remove device
  1079. // unmapiospace doesn't do anything. it is ok not to call it
  1080. FdoExtension->BusMasterBaseAddressSpace = MEMORY_SPACE;
  1081. } else {
  1082. FdoExtension->TranslatedBusMasterBaseAddress = NULL;
  1083. ASSERT (FALSE);
  1084. }
  1085. }
  1086. if (FdoExtension->TranslatedBusMasterBaseAddress == NULL) {
  1087. ExFreePool (bmResourceList);
  1088. FdoExtension->BmResourceList = bmResourceList = NULL;
  1089. }
  1090. for (k=0; k<MAX_IDE_CHANNEL; k++) {
  1091. if ((k < cmdChannel) ||
  1092. (k < ctrlChannel) ||
  1093. (k < intrChannel)) {
  1094. FdoExtension->PdoResourceList[k] = pdoResourceList[k];
  1095. FdoExtension->PdoResourceListSize[k] = (ULONG)(((PUCHAR)pdoFullResourceList[k]) - ((PUCHAR)pdoResourceList[k]));
  1096. if (k < cmdChannel) {
  1097. FdoExtension->PdoCmdRegResourceFound[k] = TRUE;
  1098. }
  1099. if (k < ctrlChannel) {
  1100. FdoExtension->PdoCtrlRegResourceFound[k] = TRUE;
  1101. }
  1102. if (k < intrChannel) {
  1103. FdoExtension->PdoInterruptResourceFound[k] = TRUE;
  1104. }
  1105. } else {
  1106. ExFreePool (pdoResourceList[k]);
  1107. FdoExtension->PdoResourceList[k] =
  1108. pdoResourceList[k] = NULL;
  1109. }
  1110. }
  1111. return status;
  1112. } // AnalyzeResourceList
  1113. VOID
  1114. ControllerOpMode (
  1115. IN PCTRLFDO_EXTENSION FdoExtension
  1116. )
  1117. {
  1118. NTSTATUS status;
  1119. PCIIDE_CONFIG_HEADER pciIdeConfigHeader;
  1120. PAGED_CODE();
  1121. status = PciIdeBusData(
  1122. FdoExtension,
  1123. &pciIdeConfigHeader,
  1124. 0,
  1125. sizeof (pciIdeConfigHeader),
  1126. TRUE
  1127. );
  1128. FdoExtension->NativeMode[0] = FALSE;
  1129. FdoExtension->NativeMode[1] = FALSE;
  1130. if (NT_SUCCESS(status)) {
  1131. //
  1132. // ISSUE: 02/05/01: This should be removed. In pci we check for sublclass = 0x1
  1133. //
  1134. if ((pciIdeConfigHeader.BaseClass == PCI_CLASS_MASS_STORAGE_CTLR) &&
  1135. (pciIdeConfigHeader.SubClass == PCI_SUBCLASS_MSC_RAID_CTLR)) {
  1136. //
  1137. // We have a Promise Technology IDE "raid" controller
  1138. //
  1139. FdoExtension->NativeMode[0] = TRUE;
  1140. FdoExtension->NativeMode[1] = TRUE;
  1141. } else {
  1142. if ((pciIdeConfigHeader.Chan0OpMode) &&
  1143. (pciIdeConfigHeader.Chan1OpMode)) {
  1144. //
  1145. // we can't support a channel being legacy
  1146. // and the other is in native because
  1147. // we don't know what irq is for the native
  1148. // channel
  1149. //
  1150. FdoExtension->NativeMode[0] = TRUE;
  1151. FdoExtension->NativeMode[1] = TRUE;
  1152. }
  1153. }
  1154. //
  1155. // Have to be both TRUE or both FALSE
  1156. //
  1157. ASSERT ((FdoExtension->NativeMode[0] == FALSE) == (FdoExtension->NativeMode[1] == FALSE));
  1158. }
  1159. return;
  1160. } // ControllerOpMode
  1161. VOID
  1162. EnablePCIBusMastering (
  1163. IN PCTRLFDO_EXTENSION FdoExtension
  1164. )
  1165. {
  1166. NTSTATUS status;
  1167. PCIIDE_CONFIG_HEADER pciIdeConfigHeader;
  1168. status = PciIdeBusData(
  1169. FdoExtension,
  1170. &pciIdeConfigHeader,
  1171. 0,
  1172. sizeof (PCIIDE_CONFIG_HEADER),
  1173. TRUE
  1174. );
  1175. //
  1176. // pci bus master disabled?
  1177. //
  1178. if (NT_SUCCESS(status) &&
  1179. pciIdeConfigHeader.MasterIde &&
  1180. !pciIdeConfigHeader.Command.b.MasterEnable) {
  1181. //
  1182. // Try to turn on pci bus mastering
  1183. //
  1184. pciIdeConfigHeader.Command.b.MasterEnable = 1;
  1185. status = PciIdeBusData(
  1186. FdoExtension,
  1187. &pciIdeConfigHeader.Command.w,
  1188. FIELD_OFFSET (PCIIDE_CONFIG_HEADER, Command),
  1189. sizeof (pciIdeConfigHeader.Command.w),
  1190. FALSE
  1191. );
  1192. }
  1193. return;
  1194. } // EnablePCIBusMastering
  1195. #ifdef DBG
  1196. ULONG PciIdeXDebugFakeMissingChild = 0;
  1197. #endif // DBG
  1198. IDE_CHANNEL_STATE
  1199. PciIdeChannelEnabled (
  1200. IN PCTRLFDO_EXTENSION FdoExtension,
  1201. IN ULONG Channel
  1202. )
  1203. {
  1204. NTSTATUS status;
  1205. ULONG longMask;
  1206. UCHAR channelEnableMask;
  1207. ULONG channelEnablePciConfigOffset;
  1208. UCHAR pciConfigData;
  1209. PAGED_CODE();
  1210. #if DBG
  1211. if (PciIdeXDebugFakeMissingChild & 0xff000000) {
  1212. DebugPrint ((0, "PciIdeXDebugFakeMissingChild: fake missing channel 0x%x\n", Channel));
  1213. if ((PciIdeXDebugFakeMissingChild & 0x0000ff) == Channel) {
  1214. PciIdeXDebugFakeMissingChild = 0;
  1215. return ChannelDisabled;
  1216. }
  1217. }
  1218. #endif
  1219. longMask = 0;
  1220. status = PciIdeXGetDeviceParameter (
  1221. FdoExtension->AttacheePdo,
  1222. ChannelEnableMaskName[Channel],
  1223. &longMask
  1224. );
  1225. channelEnableMask = (UCHAR) longMask;
  1226. #if defined(_AMD64_SIMULATOR_)
  1227. //
  1228. // Use default values for an Intel controller which
  1229. // is what the simulator is providing.
  1230. //
  1231. if (!NT_SUCCESS(status)) {
  1232. channelEnableMask = 0x80;
  1233. status = STATUS_SUCCESS;
  1234. }
  1235. #endif
  1236. if (!NT_SUCCESS(status)) {
  1237. DebugPrint ((1, "PciIdeX: Unable to get ChannelEnableMask from the registry\n"));
  1238. } else {
  1239. channelEnablePciConfigOffset = 0;
  1240. status = PciIdeXGetDeviceParameter (
  1241. FdoExtension->AttacheePdo,
  1242. ChannelEnablePciConfigOffsetName[Channel],
  1243. &channelEnablePciConfigOffset
  1244. );
  1245. #if defined(_AMD64_SIMULATOR_)
  1246. //
  1247. // See above
  1248. //
  1249. if (!NT_SUCCESS(status)) {
  1250. if (Channel == 0) {
  1251. channelEnablePciConfigOffset = 0x41;
  1252. } else {
  1253. channelEnablePciConfigOffset = 0x43;
  1254. }
  1255. status = STATUS_SUCCESS;
  1256. }
  1257. #endif
  1258. if (!NT_SUCCESS(status)) {
  1259. DebugPrint ((1, "PciIdeX: Unable to get ChannelEnablePciConfigOffset from the registry\n"));
  1260. } else {
  1261. status = PciIdeBusData(
  1262. FdoExtension,
  1263. &pciConfigData,
  1264. channelEnablePciConfigOffset,
  1265. sizeof (pciConfigData),
  1266. TRUE // Read
  1267. );
  1268. if (NT_SUCCESS(status)) {
  1269. return (pciConfigData & channelEnableMask) ? ChannelEnabled : ChannelDisabled;
  1270. }
  1271. }
  1272. }
  1273. //
  1274. // couldn't figure out whether is channel enabled
  1275. // try the miniport port
  1276. //
  1277. if (FdoExtension->ControllerProperties.PciIdeChannelEnabled) {
  1278. return FdoExtension->ControllerProperties.PciIdeChannelEnabled (
  1279. FdoExtension->VendorSpecificDeviceEntension,
  1280. Channel
  1281. );
  1282. }
  1283. return ChannelStateUnknown;
  1284. } // PciIdeChannelEnabled
  1285. NTSTATUS
  1286. PciIdeCreateTimingTable (
  1287. IN PCTRLFDO_EXTENSION FdoExtension
  1288. )
  1289. {
  1290. PULONG timingTable;
  1291. PWSTR regTimingList = NULL;
  1292. ULONG i;
  1293. ULONG temp;
  1294. ULONG length = 0;
  1295. NTSTATUS status;
  1296. PAGED_CODE();
  1297. //
  1298. // Try to procure the timing table from the registry
  1299. //
  1300. status = PciIdeXGetDeviceParameterEx (
  1301. FdoExtension->AttacheePdo,
  1302. L"TransferModeTiming",
  1303. &(regTimingList)
  1304. );
  1305. //
  1306. // Fill in the table entries
  1307. //
  1308. if (NT_SUCCESS(status) && regTimingList) {
  1309. PWSTR string = regTimingList;
  1310. UNICODE_STRING unicodeString;
  1311. i=0;
  1312. while (string[0]) {
  1313. RtlInitUnicodeString(
  1314. &unicodeString,
  1315. string
  1316. );
  1317. RtlUnicodeStringToInteger(&unicodeString,10, &temp);
  1318. //
  1319. // The first entry is the length of the table
  1320. //
  1321. if (i==0) {
  1322. length = temp;
  1323. ASSERT(length <=31);
  1324. if (length > 31) {
  1325. length=temp=31;
  1326. }
  1327. //
  1328. // The table should atleast be MAX_XFER_MODE long.
  1329. // if not fill it up with 0s
  1330. //
  1331. if (temp < MAX_XFER_MODE) {
  1332. temp=MAX_XFER_MODE;
  1333. }
  1334. timingTable = ExAllocatePool(NonPagedPool, temp*sizeof(ULONG));
  1335. if (timingTable == NULL) {
  1336. length = 0;
  1337. status = STATUS_INSUFFICIENT_RESOURCES;
  1338. break;
  1339. } else {
  1340. ULONG j;
  1341. //
  1342. // Initialize the known xferModes (default)
  1343. //
  1344. SetDefaultTiming(timingTable, j);
  1345. for (j=MAX_XFER_MODE; j<temp;j++) {
  1346. timingTable[j]=timingTable[MAX_XFER_MODE-1];
  1347. }
  1348. }
  1349. } else {
  1350. if (i > length) {
  1351. DebugPrint((0, "Pciidex: Timing table overflow\n"));
  1352. break;
  1353. }
  1354. //
  1355. // The timings (PIO0-...)
  1356. // Use the default values if the cycletime is 0.
  1357. //
  1358. if (temp) {
  1359. timingTable[i-1]=temp;
  1360. }
  1361. }
  1362. i++;
  1363. string += (unicodeString.Length / sizeof(WCHAR)) + 1;
  1364. }
  1365. if (length < MAX_XFER_MODE) {
  1366. length = MAX_XFER_MODE;
  1367. }
  1368. ExFreePool(regTimingList);
  1369. } else {
  1370. DebugPrint((1, "Pciidex: Unsuccessful regop status %x, regTimingList %x\n",
  1371. status, regTimingList));
  1372. //
  1373. // Nothing in the registry. Fill in the table with known transfer mode
  1374. // timings.
  1375. //
  1376. status = STATUS_SUCCESS;
  1377. timingTable=ExAllocatePool(NonPagedPool, MAX_XFER_MODE*sizeof(ULONG));
  1378. if (timingTable == NULL) {
  1379. length =0;
  1380. status = STATUS_INSUFFICIENT_RESOURCES;
  1381. } else {
  1382. SetDefaultTiming(timingTable, length);
  1383. }
  1384. }
  1385. FdoExtension->TransferModeTimingTable=timingTable;
  1386. FdoExtension->TransferModeTableLength= length;
  1387. /*
  1388. for (i=0;i<FdoExtension->TransferModeTableLength;i++) {
  1389. DebugPrint((0, "Table[%d]=%d\n",
  1390. i,
  1391. FdoExtension->TransferModeTimingTable[i]));
  1392. }
  1393. */
  1394. return status;
  1395. }
  1396. VOID
  1397. PciIdeInitControllerProperties (
  1398. IN PCTRLFDO_EXTENSION FdoExtension
  1399. )
  1400. {
  1401. #if 1
  1402. NTSTATUS status;
  1403. PDRIVER_OBJECT_EXTENSION driverObjectExtension;
  1404. ULONG i, j;
  1405. PAGED_CODE();
  1406. driverObjectExtension =
  1407. (PDRIVER_OBJECT_EXTENSION) IoGetDriverObjectExtension(
  1408. FdoExtension->DriverObject,
  1409. DRIVER_OBJECT_EXTENSION_ID
  1410. );
  1411. ASSERT (driverObjectExtension);
  1412. FdoExtension->ControllerProperties.Size = sizeof (IDE_CONTROLLER_PROPERTIES);
  1413. FdoExtension->ControllerProperties.DefaultPIO = 0;
  1414. status = (*driverObjectExtension->PciIdeGetControllerProperties) (
  1415. FdoExtension->VendorSpecificDeviceEntension,
  1416. &FdoExtension->ControllerProperties
  1417. );
  1418. //
  1419. // Look in the registry to determine whether
  1420. // UDMA 66 should be enabled for INTEL chipsets
  1421. //
  1422. FdoExtension->EnableUDMA66 = 0;
  1423. status = PciIdeXGetDeviceParameter (
  1424. FdoExtension->AttacheePdo,
  1425. L"EnableUDMA66",
  1426. &(FdoExtension->EnableUDMA66)
  1427. );
  1428. #else
  1429. NTSTATUS status;
  1430. PCIIDE_CONFIG_HEADER pciHeader;
  1431. ULONG ultraDmaSupport;
  1432. ULONG xferMode;
  1433. ULONG i;
  1434. ULONG j;
  1435. PAGED_CODE();
  1436. //
  1437. // grab ultra dma flag from the registry
  1438. //
  1439. ultraDmaSupport = 0;
  1440. status = PciIdeXGetDeviceParameter (
  1441. FdoExtension,
  1442. UltraDmaSupport,
  1443. &ultraDmaSupport
  1444. );
  1445. //
  1446. // grab ultra dma flag from the registry
  1447. //
  1448. status = PciIdeXGetBusData (
  1449. FdoExtension,
  1450. &pciHeader,
  1451. 0,
  1452. sizeof (pciHeader)
  1453. );
  1454. if (!NT_SUCCESS(status)) {
  1455. //
  1456. // could get the pci config data, fake it
  1457. //
  1458. pciHeader.MasterIde = 0;
  1459. pciHeader.Command.b.MasterEnable = 0;
  1460. }
  1461. xferMode = PIO_SUPPORT;
  1462. if (pciHeader.MasterIde && pciHeader.Command.b.MasterEnable) {
  1463. xferMode |= SWDMA_SUPPORT | MWDMA_SUPPORT;
  1464. if (ultraDmaSupport) {
  1465. xferMode |= UDMA_SUPPORT;
  1466. }
  1467. }
  1468. for (i=0; i<MAX_IDE_CHANNEL; i++) {
  1469. for (i=0; i<MAX_IDE_DEVICE; i++) {
  1470. FdoExtension->ControllerProperties.SupportedTransferMode[i][j] = xferMode;
  1471. }
  1472. }
  1473. #endif
  1474. } // PciIdeInitControllerProperties
  1475. NTSTATUS
  1476. ControllerUsageNotification (
  1477. IN PDEVICE_OBJECT DeviceObject,
  1478. IN OUT PIRP Irp
  1479. )
  1480. {
  1481. PCTRLFDO_EXTENSION fdoExtension;
  1482. PIO_STACK_LOCATION irpSp;
  1483. PULONG deviceUsageCount;
  1484. ASSERT (DeviceObject);
  1485. ASSERT (Irp);
  1486. PAGED_CODE();
  1487. fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
  1488. ASSERT (fdoExtension);
  1489. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1490. if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypePaging) {
  1491. //
  1492. // Adjust the paging path count for this device.
  1493. //
  1494. deviceUsageCount = &fdoExtension->PagingPathCount;
  1495. } else if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeHibernation) {
  1496. //
  1497. // Adjust the paging path count for this device.
  1498. //
  1499. deviceUsageCount = &fdoExtension->HiberPathCount;
  1500. } else if (irpSp->Parameters.UsageNotification.Type == DeviceUsageTypeDumpFile) {
  1501. //
  1502. // Adjust the paging path count for this device.
  1503. //
  1504. deviceUsageCount = &fdoExtension->CrashDumpPathCount;
  1505. } else {
  1506. deviceUsageCount = NULL;
  1507. DebugPrint ((0,
  1508. "PCIIDEX: Unknown IRP_MN_DEVICE_USAGE_NOTIFICATION type: 0x%x\n",
  1509. irpSp->Parameters.UsageNotification.Type));
  1510. }
  1511. IoCopyCurrentIrpStackLocationToNext (Irp);
  1512. IoSetCompletionRoutine (
  1513. Irp,
  1514. ControllerUsageNotificationCompletionRoutine,
  1515. deviceUsageCount,
  1516. TRUE,
  1517. TRUE,
  1518. TRUE);
  1519. ASSERT(fdoExtension->AttacheeDeviceObject);
  1520. return IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
  1521. } // ControllerUsageNotification
  1522. NTSTATUS
  1523. ControllerUsageNotificationCompletionRoutine (
  1524. IN PDEVICE_OBJECT DeviceObject,
  1525. IN PIRP Irp,
  1526. IN PVOID Context
  1527. )
  1528. {
  1529. PCTRLFDO_EXTENSION fdoExtension;
  1530. PIO_STACK_LOCATION irpSp;
  1531. PULONG deviceUsageCount = Context;
  1532. fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
  1533. ASSERT (fdoExtension);
  1534. irpSp = IoGetCurrentIrpStackLocation(Irp);
  1535. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  1536. if (deviceUsageCount) {
  1537. IoAdjustPagingPathCount (
  1538. deviceUsageCount,
  1539. irpSp->Parameters.UsageNotification.InPath
  1540. );
  1541. }
  1542. }
  1543. return Irp->IoStatus.Status;
  1544. } // ControllerUsageNotificationCompletionRoutine
  1545. NTSTATUS
  1546. PciIdeGetBusStandardInterface(
  1547. IN PCTRLFDO_EXTENSION FdoExtension
  1548. )
  1549. /*++
  1550. Routine Description:
  1551. This routine gets the bus iterface standard information from the PDO.
  1552. Arguments:
  1553. Return Value:
  1554. NT status.
  1555. --*/
  1556. {
  1557. KEVENT event;
  1558. NTSTATUS status;
  1559. PIRP irp;
  1560. IO_STATUS_BLOCK ioStatusBlock;
  1561. PIO_STACK_LOCATION irpStack;
  1562. KeInitializeEvent( &event, NotificationEvent, FALSE );
  1563. irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
  1564. FdoExtension->AttacheeDeviceObject,
  1565. NULL,
  1566. 0,
  1567. NULL,
  1568. &event,
  1569. &ioStatusBlock );
  1570. if (irp == NULL) {
  1571. return STATUS_INSUFFICIENT_RESOURCES;
  1572. }
  1573. irpStack = IoGetNextIrpStackLocation( irp );
  1574. irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  1575. irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_BUS_INTERFACE_STANDARD;
  1576. irpStack->Parameters.QueryInterface.Size = sizeof( BUS_INTERFACE_STANDARD );
  1577. irpStack->Parameters.QueryInterface.Version = 1;
  1578. irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->BusInterface;
  1579. irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  1580. //
  1581. // Initialize the status to error in case the ACPI driver decides not to
  1582. // set it correctly.
  1583. //
  1584. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1585. status = IoCallDriver(FdoExtension->AttacheeDeviceObject, irp);
  1586. if (!NT_SUCCESS( status)) {
  1587. return status;
  1588. }
  1589. if (status == STATUS_PENDING) {
  1590. KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
  1591. }
  1592. if (NT_SUCCESS(ioStatusBlock.Status)) {
  1593. ASSERT (FdoExtension->BusInterface.SetBusData);
  1594. ASSERT (FdoExtension->BusInterface.GetBusData);
  1595. }
  1596. return ioStatusBlock.Status;
  1597. }
  1598. NTSTATUS
  1599. ControllerQueryPnPDeviceState (
  1600. IN PDEVICE_OBJECT DeviceObject,
  1601. IN OUT PIRP Irp
  1602. )
  1603. {
  1604. PCTRLFDO_EXTENSION fdoExtension;
  1605. PPNP_DEVICE_STATE deviceState;
  1606. fdoExtension = (PCTRLFDO_EXTENSION) DeviceObject->DeviceExtension;
  1607. DebugPrint((2, "QUERY_DEVICE_STATE for FDOE 0x%x\n", fdoExtension));
  1608. if(fdoExtension->PagingPathCount != 0) {
  1609. deviceState = (PPNP_DEVICE_STATE) &(Irp->IoStatus.Information);
  1610. SETMASK((*deviceState), PNP_DEVICE_NOT_DISABLEABLE);
  1611. }
  1612. Irp->IoStatus.Status = STATUS_SUCCESS;
  1613. IoSkipCurrentIrpStackLocation (Irp);
  1614. return IoCallDriver (fdoExtension->AttacheeDeviceObject, Irp);
  1615. } // ControllerQueryPnPDeviceState
  1616. #ifdef ENABLE_NATIVE_MODE
  1617. NTSTATUS
  1618. ControllerInterruptControl (
  1619. IN PCTRLFDO_EXTENSION FdoExtension,
  1620. IN ULONG Channel,
  1621. IN ULONG Disconnect
  1622. )
  1623. {
  1624. NTSTATUS status;
  1625. PCM_PARTIAL_RESOURCE_DESCRIPTOR irqPartialDescriptors;
  1626. PCM_RESOURCE_LIST resourceListForKeep = NULL;
  1627. ULONG i;
  1628. status = STATUS_SUCCESS;
  1629. if (Disconnect) {
  1630. DebugPrint((1, "PciIdex: Interrupt control for %x - disconnect\n", Channel));
  1631. //
  1632. // Disconnect the ISR
  1633. //
  1634. if ( (FdoExtension->InterruptObject[Channel])) {
  1635. IoDisconnectInterrupt (
  1636. FdoExtension->InterruptObject[Channel]
  1637. );
  1638. FdoExtension->InterruptObject[Channel] = 0;
  1639. }
  1640. } else {
  1641. //
  1642. // connect the ISR
  1643. //
  1644. PPCIIDE_INTERRUPT_CONTEXT context;
  1645. DebugPrint((1, "PciIdex: Interrupt control for %x - reconnect\n", Channel));
  1646. irqPartialDescriptors = FdoExtension->IrqPartialDescriptors[Channel];
  1647. if (!irqPartialDescriptors) {
  1648. return STATUS_UNSUCCESSFUL;
  1649. }
  1650. //
  1651. // Fill in the context
  1652. //
  1653. context = (PPCIIDE_INTERRUPT_CONTEXT) &(FdoExtension->InterruptContext[Channel]);
  1654. context->DeviceExtension = (PVOID)FdoExtension;
  1655. context->ChannelNumber = Channel;
  1656. status = IoConnectInterrupt(&FdoExtension->InterruptObject[Channel],
  1657. (PKSERVICE_ROUTINE) ControllerInterrupt,
  1658. (PVOID) context,
  1659. (PKSPIN_LOCK) NULL,
  1660. irqPartialDescriptors->u.Interrupt.Vector,
  1661. (KIRQL) irqPartialDescriptors->u.Interrupt.Level,
  1662. (KIRQL) irqPartialDescriptors->u.Interrupt.Level,
  1663. irqPartialDescriptors->Flags & CM_RESOURCE_INTERRUPT_LATCHED ? Latched : LevelSensitive,
  1664. (BOOLEAN) (irqPartialDescriptors->ShareDisposition == CmResourceShareShared),
  1665. irqPartialDescriptors->u.Interrupt.Affinity,
  1666. FALSE);
  1667. if (!NT_SUCCESS(status)) {
  1668. DebugPrint((1,
  1669. "PciIde: Can't connect interrupt %d\n",
  1670. irqPartialDescriptors->u.Interrupt.Vector));
  1671. FdoExtension->InterruptObject[Channel] = NULL;
  1672. }
  1673. }
  1674. return status;
  1675. }
  1676. #define SelectDevice(BaseIoAddress, deviceNumber, additional) \
  1677. WRITE_PORT_UCHAR ((BaseIoAddress)->DriveSelect, (UCHAR)((((deviceNumber) & 0x1) << 4) | 0xA0 | additional))
  1678. BOOLEAN
  1679. ControllerInterrupt(
  1680. IN PKINTERRUPT Interrupt,
  1681. PVOID Context
  1682. )
  1683. {
  1684. UCHAR statusByte;
  1685. PPCIIDE_INTERRUPT_CONTEXT context = Context;
  1686. PCTRLFDO_EXTENSION fdoExtension = context->DeviceExtension;
  1687. ULONG channel = context->ChannelNumber;
  1688. PIDE_REGISTERS_1 baseIoAddress1 = &(fdoExtension->BaseIoAddress1[channel]);
  1689. BOOLEAN interruptCleared = FALSE;
  1690. DebugPrint((1, "Pciidex: ISR called for channel %d\n", channel));
  1691. //
  1692. // Check if the interrupts are enabled.
  1693. // Don't enable the interrupts if both the isrs are not installed
  1694. //
  1695. if (!fdoExtension->NativeInterruptEnabled) {
  1696. if (fdoExtension->ControllerIsrInstalled) {
  1697. //
  1698. // we have just connected the ISRs. At this point we don't know whether
  1699. // we actually enabled the decodes or not. So enable the decodes and set the
  1700. // flag
  1701. //
  1702. //
  1703. // if this fails we already bugchecked.
  1704. //
  1705. ControllerEnableInterrupt(fdoExtension);
  1706. fdoExtension->NativeInterruptEnabled = TRUE;
  1707. } else {
  1708. //
  1709. // cannot be us
  1710. //
  1711. return FALSE;
  1712. }
  1713. } else {
  1714. if (!fdoExtension->ControllerIsrInstalled) {
  1715. //
  1716. // At this point we don't know whether the decodes are disabled or not. We should
  1717. // enable them.
  1718. //
  1719. //
  1720. // if this fails we already bugchecked.
  1721. //
  1722. ControllerEnableInterrupt(fdoExtension);
  1723. //
  1724. // Now fall thru and determine whether it is our interrupt.
  1725. // we will disable the decodes after that.
  1726. //
  1727. } else {
  1728. //
  1729. // all is well. Go process the interrupt.
  1730. //
  1731. }
  1732. }
  1733. //
  1734. // Both the ISRs should be installed and the interrupts should
  1735. // be enabled at this point
  1736. //
  1737. ASSERT(fdoExtension->NativeInterruptEnabled);
  1738. // ControllerIsrInstalled need not be set.
  1739. // if we get called, then it means that we are still connected
  1740. // however, if the flag ControllerIsrInstalled is not set, then it is
  1741. // safe to assume that we are in the process of stopping the controller.
  1742. // Just dismiss the interrupt, the normal way. We are yet to turn off the decodes.
  1743. //
  1744. //
  1745. // Clear interrupt by reading status.
  1746. //
  1747. GetStatus(baseIoAddress1, statusByte);
  1748. //
  1749. // Check the Bus master registers
  1750. //
  1751. if (!fdoExtension->NoBusMaster[channel]) {
  1752. BMSTATUS bmStatus;
  1753. PIDE_BUS_MASTER_REGISTERS bmRegister;
  1754. //
  1755. // Get the correct bus master register
  1756. //
  1757. bmRegister = (PIDE_BUS_MASTER_REGISTERS)(((PUCHAR)fdoExtension->TranslatedBusMasterBaseAddress) + channel*8);
  1758. bmStatus = READ_PORT_UCHAR (&bmRegister->Status);
  1759. DebugPrint((1, "BmStatus = 0x%x\n", bmStatus));
  1760. //
  1761. // is Interrupt bit set?
  1762. //
  1763. if (bmStatus & BMSTATUS_INTERRUPT) {
  1764. WRITE_PORT_UCHAR (&bmRegister->Command, 0x0); // disable BM
  1765. WRITE_PORT_UCHAR (&bmRegister->Status, BUSMASTER_INTERRUPT); // clear interrupt BM
  1766. interruptCleared = TRUE;
  1767. }
  1768. }
  1769. DebugPrint((1, "ISR for %d returning %d\n", channel, interruptCleared?1:0));
  1770. //
  1771. // NativeInterruptEnabled should be set at this point
  1772. //
  1773. if (!fdoExtension->ControllerIsrInstalled) {
  1774. // we are in the stop or remove code path where this flag has been cleared and
  1775. // we are about to disconnect the ISR. Disable the decodes.
  1776. //
  1777. ControllerDisableInterrupt(fdoExtension);
  1778. //
  1779. // we have dismissed our interrupt. Now clear the interruptEnabled flag.
  1780. //
  1781. fdoExtension->NativeInterruptEnabled = FALSE;
  1782. //
  1783. // return InterruptCleared.
  1784. //
  1785. }
  1786. return interruptCleared;
  1787. }
  1788. /***
  1789. NTSTATUS
  1790. ControllerEnableDecode(
  1791. IN PCTRLFDO_EXTENSION FdoExtension,
  1792. IN BOOLEAN Enable
  1793. )
  1794. {
  1795. USHORT cmd;
  1796. NTSTATUS status;
  1797. PCIIDE_CONFIG_HEADER pciIdeConfigHeader;
  1798. status = PciIdeBusData(
  1799. FdoExtension,
  1800. &pciIdeConfigHeader,
  1801. 0,
  1802. sizeof (PCIIDE_CONFIG_HEADER),
  1803. TRUE
  1804. );
  1805. //
  1806. // get pci command register
  1807. //
  1808. if (!NT_SUCCESS(status)) {
  1809. return status;
  1810. }
  1811. cmd = pciIdeConfigHeader.Command.w;
  1812. cmd &= ~(PCI_ENABLE_IO_SPACE |
  1813. PCI_ENABLE_MEMORY_SPACE |
  1814. PCI_ENABLE_BUS_MASTER);
  1815. if (Enable) {
  1816. //
  1817. // Set enables
  1818. //
  1819. cmd |= (PCI_ENABLE_IO_SPACE | PCI_ENABLE_MEMORY_SPACE | PCI_ENABLE_BUS_MASTER);
  1820. }
  1821. //
  1822. // Set the new command register into the device.
  1823. //
  1824. status = PciIdeBusData(
  1825. FdoExtension,
  1826. &cmd,
  1827. FIELD_OFFSET (PCIIDE_CONFIG_HEADER, Command),
  1828. sizeof (pciIdeConfigHeader.Command.w),
  1829. FALSE
  1830. );
  1831. return status;
  1832. }
  1833. **/
  1834. NTSTATUS
  1835. PciIdeGetNativeModeInterface(
  1836. IN PCTRLFDO_EXTENSION FdoExtension
  1837. )
  1838. /*++
  1839. Routine Description:
  1840. This routine gets the native ide iterface information from the PDO.
  1841. Arguments:
  1842. Return Value:
  1843. NT status.
  1844. --*/
  1845. {
  1846. KEVENT event;
  1847. NTSTATUS status;
  1848. PIRP irp;
  1849. IO_STATUS_BLOCK ioStatusBlock;
  1850. PIO_STACK_LOCATION irpStack;
  1851. KeInitializeEvent( &event, NotificationEvent, FALSE );
  1852. irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
  1853. FdoExtension->AttacheeDeviceObject,
  1854. NULL,
  1855. 0,
  1856. NULL,
  1857. &event,
  1858. &ioStatusBlock );
  1859. if (irp == NULL) {
  1860. return STATUS_INSUFFICIENT_RESOURCES;
  1861. }
  1862. irpStack = IoGetNextIrpStackLocation( irp );
  1863. irpStack->MinorFunction = IRP_MN_QUERY_INTERFACE;
  1864. irpStack->Parameters.QueryInterface.InterfaceType = (LPGUID) &GUID_PCI_NATIVE_IDE_INTERFACE;
  1865. irpStack->Parameters.QueryInterface.Size = sizeof( PCI_NATIVE_IDE_INTERFACE );
  1866. irpStack->Parameters.QueryInterface.Version = 1;
  1867. irpStack->Parameters.QueryInterface.Interface = (PINTERFACE) &FdoExtension->NativeIdeInterface;
  1868. irpStack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
  1869. //
  1870. // Initialize the status to error in case the ACPI driver decides not to
  1871. // set it correctly.
  1872. //
  1873. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  1874. status = IoCallDriver(FdoExtension->AttacheeDeviceObject, irp);
  1875. if (!NT_SUCCESS( status)) {
  1876. return status;
  1877. }
  1878. if (status == STATUS_PENDING) {
  1879. KeWaitForSingleObject( &event, Executive, KernelMode, FALSE, NULL );
  1880. }
  1881. if (NT_SUCCESS(ioStatusBlock.Status)) {
  1882. ASSERT (FdoExtension->NativeIdeInterface.InterruptControl);
  1883. }
  1884. return ioStatusBlock.Status;
  1885. }
  1886. #endif