Leaked source code of windows server 2003
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.

1178 lines
36 KiB

  1. /*++
  2. Copyright (c) 1997-2000 Microsoft Corporation
  3. Module Name:
  4. fdopnp.c
  5. Abstract:
  6. This module contains the code that handles PNP irps for sd bus driver
  7. targeted towards the FDO's (for the sd controller object)
  8. Author:
  9. Neil Sandlin (neilsa) Jan 1 2002
  10. Environment:
  11. Kernel mode
  12. Revision History :
  13. --*/
  14. #include "pch.h"
  15. //
  16. // Internal References
  17. //
  18. NTSTATUS
  19. SdbusGetPciControllerType(
  20. IN PDEVICE_OBJECT Pdo,
  21. IN PDEVICE_OBJECT Fdo
  22. );
  23. NTSTATUS
  24. SdbusFdoStartDevice(
  25. IN PDEVICE_OBJECT Fdo,
  26. IN PIRP Irp
  27. );
  28. NTSTATUS
  29. SdbusFdoStopDevice(
  30. IN PDEVICE_OBJECT Fdo,
  31. IN PIRP Irp
  32. );
  33. NTSTATUS
  34. SdbusFdoRemoveDevice(
  35. IN PDEVICE_OBJECT Fdo,
  36. IN PIRP Irp
  37. );
  38. NTSTATUS
  39. SdbusFdoDeviceCapabilities(
  40. IN PDEVICE_OBJECT Fdo,
  41. IN PIRP Irp
  42. );
  43. NTSTATUS
  44. SdbusDeviceRelations(
  45. IN PDEVICE_OBJECT Fdo,
  46. IN PIRP Irp,
  47. IN DEVICE_RELATION_TYPE RelationType,
  48. OUT PDEVICE_RELATIONS *DeviceRelations
  49. );
  50. PUNICODE_STRING DriverRegistryPath;
  51. #ifdef ALLOC_PRAGMA
  52. #pragma alloc_text(PAGE, SdbusFdoPnpDispatch)
  53. #pragma alloc_text(PAGE, SdbusFdoStartDevice)
  54. #pragma alloc_text(PAGE, SdbusFdoStopDevice)
  55. #pragma alloc_text(PAGE, SdbusFdoRemoveDevice)
  56. #pragma alloc_text(PAGE, SdbusFdoDeviceCapabilities)
  57. #pragma alloc_text(PAGE, SdbusAddDevice)
  58. #pragma alloc_text(PAGE, SdbusGetPciControllerType)
  59. #pragma alloc_text(PAGE, SdbusDeviceRelations)
  60. #endif
  61. NTSTATUS
  62. SdbusFdoPnpDispatch (
  63. IN PDEVICE_OBJECT DeviceObject,
  64. IN PIRP Irp
  65. )
  66. /*++
  67. Routine Description:
  68. PNP/Power IRPs dispatch routine for the sd bus controller
  69. Arguments:
  70. DeviceObject - Pointer to the device object.
  71. Irp - Pointer to the IRP
  72. Return Value:
  73. Status
  74. --*/
  75. {
  76. PIO_STACK_LOCATION nextIrpStack;
  77. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  78. PFDO_EXTENSION fdoExtension = DeviceObject->DeviceExtension;
  79. NTSTATUS status = Irp->IoStatus.Status;
  80. PAGED_CODE();
  81. ASSERT (fdoExtension->LowerDevice != NULL);
  82. #if DBG
  83. if (irpStack->MinorFunction > IRP_MN_PNP_MAXIMUM_FUNCTION) {
  84. DebugPrint((SDBUS_DEBUG_PNP, "fdo %08x irp %08x - Unknown PNP irp\n",
  85. DeviceObject, irpStack->MinorFunction));
  86. } else {
  87. DebugPrint((SDBUS_DEBUG_PNP, "fdo %08x irp %08x --> %s\n",
  88. DeviceObject, Irp, PNP_IRP_STRING(irpStack->MinorFunction)));
  89. }
  90. #endif
  91. switch (irpStack->MinorFunction) {
  92. case IRP_MN_START_DEVICE: {
  93. status = SdbusFdoStartDevice(DeviceObject, Irp);
  94. break;
  95. }
  96. case IRP_MN_QUERY_STOP_DEVICE: {
  97. Irp->IoStatus.Status = STATUS_SUCCESS;
  98. status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  99. break;
  100. }
  101. case IRP_MN_CANCEL_STOP_DEVICE: {
  102. Irp->IoStatus.Status = STATUS_SUCCESS;
  103. status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  104. break;
  105. }
  106. case IRP_MN_STOP_DEVICE: {
  107. status = SdbusFdoStopDevice(DeviceObject, Irp);
  108. break;
  109. }
  110. case IRP_MN_QUERY_DEVICE_RELATIONS: {
  111. //
  112. // Return the list of devices on the bus
  113. //
  114. status = SdbusDeviceRelations(DeviceObject,
  115. Irp,
  116. irpStack->Parameters.QueryDeviceRelations.Type,
  117. (PDEVICE_RELATIONS *) &Irp->IoStatus.Information);
  118. Irp->IoStatus.Status = status;
  119. status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  120. break;
  121. }
  122. case IRP_MN_QUERY_REMOVE_DEVICE: {
  123. Irp->IoStatus.Status = STATUS_SUCCESS;
  124. status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  125. break;
  126. }
  127. case IRP_MN_CANCEL_REMOVE_DEVICE: {
  128. Irp->IoStatus.Status = STATUS_SUCCESS;
  129. status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  130. break;
  131. }
  132. case IRP_MN_REMOVE_DEVICE:{
  133. status = SdbusFdoRemoveDevice(DeviceObject, Irp);
  134. break;
  135. }
  136. case IRP_MN_SURPRISE_REMOVAL: {
  137. SdbusFdoStopDevice(DeviceObject, NULL);
  138. Irp->IoStatus.Status = STATUS_SUCCESS;
  139. status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  140. break;
  141. }
  142. case IRP_MN_QUERY_CAPABILITIES: {
  143. status = SdbusFdoDeviceCapabilities(DeviceObject, Irp);
  144. break;
  145. }
  146. default: {
  147. DebugPrint((SDBUS_DEBUG_PNP, "fdo %08x irp %08x - Skipping unsupported irp\n", DeviceObject, Irp));
  148. status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  149. break;
  150. }
  151. }
  152. //
  153. // Set the IRP status only if we set it to something other than
  154. // STATUS_NOT_SUPPORTED.
  155. //
  156. if (status != STATUS_NOT_SUPPORTED) {
  157. Irp->IoStatus.Status = status ;
  158. }
  159. status = Irp->IoStatus.Status;
  160. DebugPrint((SDBUS_DEBUG_PNP, "fdo %08x irp %08x comp %s %08x\n",
  161. DeviceObject, Irp, STATUS_STRING(status), status));
  162. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  163. return status;
  164. }
  165. NTSTATUS
  166. SdbusAddDevice(
  167. IN PDRIVER_OBJECT DriverObject,
  168. IN PDEVICE_OBJECT Pdo
  169. )
  170. /*++
  171. Routine Description:
  172. This routine creates functional device objects for each SD controller in the
  173. system and attaches them to the physical device objects for the controllers
  174. Arguments:
  175. DriverObject - a pointer to the object for this driver
  176. PhysicalDeviceObject - a pointer to the physical object we need to attach to
  177. Return Value:
  178. Status from device creation and initialization
  179. --*/
  180. {
  181. PDEVICE_OBJECT fdo = NULL;
  182. PDEVICE_OBJECT lowerDevice = NULL;
  183. PFDO_EXTENSION deviceExtension;
  184. ULONG resultLength;
  185. NTSTATUS status;
  186. PAGED_CODE();
  187. DebugPrint((SDBUS_DEBUG_PNP, "AddDevice Entered with pdo %x\n", Pdo));
  188. if (Pdo == NULL) {
  189. //
  190. // Have we been asked to do detection on our own?
  191. // if so just return no more devices
  192. //
  193. DebugPrint((SDBUS_DEBUG_FAIL, "SdbusAddDevice - asked to do detection\n"));
  194. return STATUS_NO_MORE_ENTRIES;
  195. }
  196. //
  197. // create and initialize the new functional device object
  198. //
  199. status = IoCreateDevice(DriverObject,
  200. sizeof(FDO_EXTENSION),
  201. NULL,
  202. FILE_DEVICE_CONTROLLER,
  203. 0L,
  204. FALSE,
  205. &fdo);
  206. if (!NT_SUCCESS(status)) {
  207. DebugPrint((SDBUS_DEBUG_FAIL, "SdbusAddDevice - error creating Fdo [%#08lx]\n", status));
  208. return status;
  209. }
  210. try {
  211. deviceExtension = fdo->DeviceExtension;
  212. RtlZeroMemory(deviceExtension, sizeof(FDO_EXTENSION));
  213. //
  214. // Set up the device extension.
  215. //
  216. deviceExtension->Signature = SDBUS_FDO_EXTENSION_SIGNATURE;
  217. deviceExtension->DeviceObject = fdo;
  218. deviceExtension->RegistryPath = DriverRegistryPath;
  219. deviceExtension->DriverObject = DriverObject;
  220. deviceExtension->Flags = SDBUS_FDO_OFFLINE;
  221. deviceExtension->WaitWakeState= WAKESTATE_DISARMED;
  222. KeInitializeTimer(&deviceExtension->WorkerTimer);
  223. KeInitializeDpc(&deviceExtension->WorkerTimeoutDpc, SdbusWorkerTimeoutDpc, deviceExtension);
  224. KeInitializeDpc(&deviceExtension->WorkerDpc, SdbusWorkerDpc, deviceExtension);
  225. KeInitializeSpinLock(&deviceExtension->WorkerSpinLock);
  226. InitializeListHead(&deviceExtension->IoWorkPacketQueue);
  227. InitializeListHead(&deviceExtension->SystemWorkPacketQueue);
  228. IoInitializeRemoveLock(&deviceExtension->RemoveLock, 'Sdbu', 1, 100);
  229. //
  230. // card events we are interested in
  231. //
  232. deviceExtension->CardEvents = SDBUS_EVENT_CARD_RW_END |
  233. SDBUS_EVENT_BUFFER_EMPTY |
  234. SDBUS_EVENT_BUFFER_FULL |
  235. SDBUS_EVENT_CARD_RESPONSE;
  236. //
  237. // Layer our FDO on top of the PDO
  238. //
  239. //
  240. lowerDevice = IoAttachDeviceToDeviceStack(fdo,Pdo);
  241. //
  242. // No status. Do the best we can.
  243. //
  244. if (lowerDevice == NULL) {
  245. status = STATUS_INSUFFICIENT_RESOURCES;
  246. leave;
  247. };
  248. deviceExtension->LowerDevice = lowerDevice;
  249. deviceExtension->Pdo = Pdo;
  250. status = IoGetDeviceProperty(Pdo,
  251. DevicePropertyLegacyBusType,
  252. sizeof(INTERFACE_TYPE),
  253. (PVOID)&deviceExtension->InterfaceType,
  254. &resultLength);
  255. if (!NT_SUCCESS(status)) {
  256. leave;
  257. }
  258. //
  259. // Get our controller type
  260. //
  261. status = SdbusGetPciControllerType(Pdo, fdo);
  262. if (!NT_SUCCESS(status)) {
  263. leave;
  264. }
  265. //
  266. // Get the pci interface for reading/writing to config header space
  267. //
  268. status = SdbusGetInterface(Pdo,
  269. &GUID_BUS_INTERFACE_STANDARD,
  270. sizeof(BUS_INTERFACE_STANDARD),
  271. (PINTERFACE) &deviceExtension->PciBusInterface);
  272. if (!NT_SUCCESS(status)) {
  273. leave;
  274. }
  275. //
  276. // Link this fdo to the list of fdo's managed by the driver
  277. //
  278. DebugPrint((SDBUS_DEBUG_PNP, "FDO %08X now linked to fdolist by AddDevice\n", fdo));
  279. deviceExtension->NextFdo = FdoList;
  280. FdoList = fdo;
  281. fdo->Flags &= ~DO_DEVICE_INITIALIZING;
  282. } finally {
  283. if (!NT_SUCCESS(status)) {
  284. MarkDeviceDeleted(deviceExtension);
  285. //
  286. // Cannot support a controller without knowing its type etc.
  287. //
  288. if (deviceExtension->LowerDevice) {
  289. IoDetachDevice(deviceExtension->LowerDevice);
  290. }
  291. IoDeleteDevice(fdo);
  292. }
  293. }
  294. return status;
  295. }
  296. NTSTATUS
  297. SdbusGetPciControllerType(
  298. IN PDEVICE_OBJECT Pdo,
  299. IN PDEVICE_OBJECT Fdo
  300. )
  301. /*++
  302. Routine Description:
  303. Look at the PCI hardware ID to see if it is already a device we know about. If so,
  304. set the appropriate controller type in the fdoExtension.
  305. Arguments:
  306. Pdo - Physical Device object for the Sdbus controller owned by the PCI driver
  307. Fdo - Functional Device object for the sd controller owned by this driver, whose
  308. extension will store the relevant controller information upon exit from this routine.
  309. Return Value:
  310. STATUS_SUCCESS Things are fine and information obtained
  311. STATUS_NOT_SUPPORTED This is actually a healthy status for this routine: all it means
  312. is that this PDO is not on a PCI bus, so no information needs to be
  313. obtained anyways.
  314. Any other status Failure. Caller probably needs to back out & not support this controller
  315. --*/
  316. {
  317. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  318. PIRP irp;
  319. IO_STATUS_BLOCK statusBlock;
  320. PIO_STACK_LOCATION irpSp;
  321. PCI_COMMON_CONFIG pciConfig;
  322. PPCI_CONTROLLER_INFORMATION id;
  323. PPCI_VENDOR_INFORMATION vid;
  324. KEVENT event;
  325. NTSTATUS status;
  326. BOOLEAN foundController = FALSE;
  327. PAGED_CODE();
  328. //
  329. // Allocate & initialize an Irp (IRP_MN_READ_CONFIG) to be sent down
  330. // to the PCI bus driver to get config. header for this controller
  331. //
  332. // Following is all standard stuff to send an IRP down - needs no documentation
  333. //
  334. // Fresh PDO. No need to jump through hoops to get attached devices
  335. //
  336. KeInitializeEvent (&event, NotificationEvent, FALSE);
  337. irp = IoBuildSynchronousFsdRequest( IRP_MJ_PNP,
  338. Pdo,
  339. NULL,
  340. 0,
  341. 0,
  342. &event,
  343. &statusBlock
  344. );
  345. if (irp == NULL) {
  346. return STATUS_INSUFFICIENT_RESOURCES;
  347. }
  348. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  349. irp->IoStatus.Information = 0;
  350. irpSp = IoGetNextIrpStackLocation(irp);
  351. irpSp->MinorFunction = IRP_MN_READ_CONFIG;
  352. irpSp->Parameters.ReadWriteConfig.WhichSpace = PCI_WHICHSPACE_CONFIG;
  353. irpSp->Parameters.ReadWriteConfig.Buffer = &pciConfig;
  354. irpSp->Parameters.ReadWriteConfig.Offset = 0;
  355. irpSp->Parameters.ReadWriteConfig.Length = sizeof(pciConfig);
  356. status = IoCallDriver(Pdo, irp);
  357. if (status == STATUS_PENDING) {
  358. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  359. status = statusBlock.Status;
  360. }
  361. if (!NT_SUCCESS(status)) {
  362. return status;
  363. }
  364. //
  365. // Now weed out the critical information from the config header and
  366. // store it away in the fdo's extension
  367. //
  368. //
  369. // Look up the PCI device id in our table
  370. //
  371. #if 0
  372. for (id = (PPCI_CONTROLLER_INFORMATION) PciControllerInformation;id->VendorID != PCI_INVALID_VENDORID; id++) {
  373. if ((id->VendorID == pciConfig.VendorID) && (id->DeviceID == pciConfig.DeviceID)) {
  374. SdbusSetControllerType(fdoExtension, id->ControllerType);
  375. foundController = TRUE;
  376. break;
  377. }
  378. }
  379. #endif
  380. //
  381. // Didn't find a specific vendor/device id, try to just base it on the vendor id
  382. //
  383. if (!foundController) {
  384. for (vid = (PPCI_VENDOR_INFORMATION) PciVendorInformation;vid->VendorID != PCI_INVALID_VENDORID; vid++) {
  385. if (vid->VendorID == pciConfig.VendorID) {
  386. fdoExtension->FunctionBlock = vid->FunctionBlock;
  387. break;
  388. }
  389. }
  390. }
  391. return STATUS_SUCCESS;
  392. }
  393. NTSTATUS
  394. SdbusFdoDeviceCapabilities(
  395. IN PDEVICE_OBJECT Fdo,
  396. IN PIRP Irp
  397. )
  398. /*++
  399. Routine Description
  400. Records the device capabilities of this sd controller,
  401. so 1. they can be used in the power management for the controller
  402. and 2. they can be used for determining the capabilities of the
  403. child pc-card PDO's of this sd controller.
  404. Arguments
  405. Fdo - Pointer to functional device object of the sd
  406. controller
  407. Irp - Pointer to the i/o request packet
  408. Return Value
  409. STATUS_SUCCESS Capabilities returned
  410. STATUS_INSUFFICIENT_RESOURCES Could not allocate memory to cache the capabilities
  411. --*/
  412. {
  413. PFDO_EXTENSION fdoExtension;
  414. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  415. PDEVICE_CAPABILITIES capabilities;
  416. NTSTATUS status;
  417. PAGED_CODE();
  418. capabilities = irpStack->Parameters.DeviceCapabilities.Capabilities;
  419. fdoExtension = Fdo->DeviceExtension;
  420. //
  421. // Send this down the stack to obtain the capabilities
  422. //
  423. status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  424. if (NT_SUCCESS(status)) {
  425. //
  426. // Cache the device capabilities in the device extension
  427. // for this sd controller.
  428. //
  429. RtlCopyMemory(&fdoExtension->DeviceCapabilities,
  430. capabilities,
  431. sizeof(DEVICE_CAPABILITIES));
  432. } else {
  433. RtlZeroMemory(&fdoExtension->DeviceCapabilities, sizeof(DEVICE_CAPABILITIES));
  434. }
  435. return status;
  436. }
  437. NTSTATUS
  438. SdbusFdoStartDevice(
  439. IN PDEVICE_OBJECT Fdo,
  440. IN PIRP Irp
  441. )
  442. /*++
  443. Routine Description:
  444. This routine will start the sd controller with the supplied
  445. resources. The IRP is sent down to the pdo first, so PCI
  446. or whoever sits underneath gets a chance to program the controller
  447. to decode the resources.
  448. Arguments:
  449. Fdo - Functional device object of the sd controller
  450. Irp - Pointer to the i/o request packet
  451. PassedDown - Contains FALSE on entry, which means caller must
  452. complete or pass down irp based on status. If set
  453. to TRUE, Irp may need to be re-completed...
  454. NeedsRecompletion - ...In which case this parameter will be checked
  455. Return value:
  456. Status
  457. --*/
  458. {
  459. NTSTATUS status;
  460. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  461. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  462. PAGED_CODE();
  463. //
  464. // Send this down to the PDO first
  465. //
  466. status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  467. if (!NT_SUCCESS(status)) {
  468. return status;
  469. }
  470. //
  471. // Give the hardware some time to settle after returning from the pdo
  472. //
  473. SdbusWait(256);
  474. try {
  475. PCM_RESOURCE_LIST ResourceList = irpStack->Parameters.StartDevice.AllocatedResources;
  476. PCM_RESOURCE_LIST TranslatedResourceList = irpStack->Parameters.StartDevice.AllocatedResourcesTranslated;
  477. PCM_FULL_RESOURCE_DESCRIPTOR fullResourceDesc;
  478. PCM_PARTIAL_RESOURCE_LIST partialResourceList;
  479. PCM_PARTIAL_RESOURCE_DESCRIPTOR partialResourceDesc;
  480. ULONG i;
  481. BOOLEAN sharedInterrupt;
  482. KINTERRUPT_MODE interruptMode;
  483. INTERFACE_TYPE interfaceType;
  484. if (fdoExtension->Flags & SDBUS_DEVICE_STARTED) {
  485. //
  486. // Start to already started device
  487. //
  488. DebugPrint((SDBUS_DEBUG_INFO,"SdbusFdoStartDevice: Fdo %x already started\n", Fdo));
  489. status = STATUS_SUCCESS;
  490. leave;
  491. }
  492. //
  493. // Parse AllocatedResources & get IoPort/AttributeMemoryBase/IRQ info.
  494. //
  495. if ((ResourceList == NULL) || (ResourceList->Count <=0) ) {
  496. status = STATUS_UNSUCCESSFUL;
  497. leave;
  498. }
  499. fullResourceDesc=&TranslatedResourceList->List[0];
  500. partialResourceList = &fullResourceDesc->PartialResourceList;
  501. partialResourceDesc = partialResourceList->PartialDescriptors;
  502. //
  503. // The memory resource is the host register base.
  504. //
  505. for (i=0; (i < partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeMemory);
  506. i++, partialResourceDesc++);
  507. if (i >= partialResourceList->Count) {
  508. status = STATUS_UNSUCCESSFUL;
  509. leave;
  510. };
  511. //
  512. // This is memory. We need to map it
  513. //
  514. fdoExtension->HostRegisterBase = MmMapIoSpace(partialResourceDesc->u.Memory.Start,
  515. partialResourceDesc->u.Memory.Length,
  516. FALSE);
  517. fdoExtension->HostRegisterSize = partialResourceDesc->u.Memory.Length;
  518. fdoExtension->Flags |= SDBUS_HOST_REGISTER_BASE_MAPPED;
  519. DebugPrint((SDBUS_DEBUG_INFO, "SdbusGetAssignedResources: Host Register Base at %x, size %x\n",
  520. fdoExtension->HostRegisterBase, fdoExtension->HostRegisterSize));
  521. //
  522. // Finally see if an IRQ is assigned
  523. //
  524. for (i = 0, partialResourceDesc = partialResourceList->PartialDescriptors;
  525. (i < partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeInterrupt);
  526. i++,partialResourceDesc++);
  527. if (i < partialResourceList->Count) {
  528. //
  529. // We have an interrupt to used for CSC
  530. //
  531. DebugPrint((SDBUS_DEBUG_INFO, "SdbusGetAssignedResources: Interrupt resource assigned\n"));
  532. fdoExtension->TranslatedInterrupt = *partialResourceDesc;
  533. //
  534. // Get the raw interrupt resource - needed to enable the interrupt on the controller
  535. //
  536. fullResourceDesc=&ResourceList->List[0];
  537. partialResourceList = &fullResourceDesc->PartialResourceList;
  538. partialResourceDesc = partialResourceList->PartialDescriptors;
  539. for (i=0; (i< partialResourceList->Count) && (partialResourceDesc->Type != CmResourceTypeInterrupt);
  540. i++, partialResourceDesc++);
  541. if (i < partialResourceList->Count) {
  542. fdoExtension->Interrupt = *partialResourceDesc;
  543. } else {
  544. //
  545. // Should not happen.. translated descriptor was present, but raw is missing!
  546. // Just reset the translated interrupt and pretend no interrupt was assigned
  547. //
  548. RtlZeroMemory(&fdoExtension->TranslatedInterrupt, sizeof(CM_PARTIAL_RESOURCE_DESCRIPTOR));
  549. }
  550. }
  551. //
  552. // do vendor-specific init of controller
  553. //
  554. (*(fdoExtension->FunctionBlock->InitController))(fdoExtension);
  555. //
  556. // Now the controller registers should be accessible
  557. //
  558. fdoExtension->Flags &= ~SDBUS_FDO_OFFLINE;
  559. fdoExtension->SystemPowerState = PowerSystemWorking;
  560. fdoExtension->DevicePowerState = PowerDeviceD0;
  561. //
  562. // Initialize our DpcForIsr
  563. //
  564. IoInitializeDpcRequest(Fdo, SdbusInterruptDpc);
  565. if (fdoExtension->Interrupt.u.Interrupt.Level == 0) {
  566. status = STATUS_UNSUCCESSFUL;
  567. leave;
  568. }
  569. fdoExtension->IoWorkItem = IoAllocateWorkItem(Fdo);
  570. //
  571. // Hook up the controller interrupt for detecting pc-card plug ins/outs
  572. //
  573. interruptMode=((fdoExtension->Interrupt.Flags & CM_RESOURCE_INTERRUPT_LATCHED) == CM_RESOURCE_INTERRUPT_LATCHED) ? Latched:LevelSensitive;
  574. sharedInterrupt=(fdoExtension->Interrupt.ShareDisposition == CmResourceShareShared)?
  575. TRUE:FALSE;
  576. status = IoConnectInterrupt(&(fdoExtension->SdbusInterruptObject),
  577. (PKSERVICE_ROUTINE) SdbusInterrupt,
  578. (PVOID) Fdo,
  579. NULL,
  580. fdoExtension->TranslatedInterrupt.u.Interrupt.Vector,
  581. (KIRQL) fdoExtension->TranslatedInterrupt.u.Interrupt.Level,
  582. (KIRQL) fdoExtension->TranslatedInterrupt.u.Interrupt.Level,
  583. interruptMode,
  584. sharedInterrupt,
  585. (KAFFINITY) fdoExtension->TranslatedInterrupt.u.Interrupt.Affinity,
  586. FALSE);
  587. if (!NT_SUCCESS(status)) {
  588. DebugPrint((SDBUS_DEBUG_FAIL, "Unable to connect interrupt\n"));
  589. leave;
  590. }
  591. (*(fdoExtension->FunctionBlock->EnableEvent))(fdoExtension, (SDBUS_EVENT_INSERTION | SDBUS_EVENT_REMOVAL));
  592. //
  593. // Activate socket will power up and ready the card
  594. //
  595. SdbusActivateSocket(Fdo, NULL, NULL);
  596. } finally {
  597. if (NT_SUCCESS(status)) {
  598. fdoExtension->Flags |= SDBUS_DEVICE_STARTED;
  599. } else {
  600. //
  601. // Failure
  602. //
  603. if (fdoExtension->Flags & SDBUS_HOST_REGISTER_BASE_MAPPED) {
  604. MmUnmapIoSpace(fdoExtension->HostRegisterBase,
  605. fdoExtension->HostRegisterSize);
  606. fdoExtension->Flags &= ~SDBUS_HOST_REGISTER_BASE_MAPPED;
  607. fdoExtension->HostRegisterBase = 0;
  608. fdoExtension->HostRegisterSize = 0;
  609. }
  610. if (fdoExtension->IoWorkItem) {
  611. IoFreeWorkItem(fdoExtension->IoWorkItem);
  612. fdoExtension->IoWorkItem = NULL;
  613. }
  614. }
  615. }
  616. return status;
  617. }
  618. NTSTATUS
  619. SdbusFdoStopDevice(
  620. IN PDEVICE_OBJECT Fdo,
  621. IN PIRP Irp OPTIONAL
  622. )
  623. /*++
  624. Routine Description:
  625. IRP_MN_STOP_DEVICE handler for the given sd controller.
  626. If Irp is present, it'll send it down first to the PDO.
  627. Unhooks the interrupt/cancels poll timer etc.
  628. Arguments:
  629. Fdo - Pointer to functional device object for the sd
  630. controller
  631. Irp - If present it's the pointer to the stop Irp initiated
  632. by PnP
  633. Return value:
  634. STATUS_SUCCESS - Sdbus controller successfully stopped
  635. Other - Stop failed
  636. --*/
  637. {
  638. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  639. NTSTATUS status;
  640. SdbusFdoDisarmWake(fdoExtension);
  641. //
  642. // Disable the interrupt
  643. //
  644. (*(fdoExtension->FunctionBlock->DisableEvent))(fdoExtension, SDBUS_EVENT_ALL);
  645. // (*(socket->SocketFnPtr->PCBEnableDisableWakeupEvent))(socket, NULL, FALSE);
  646. //
  647. // the bus driver below us will make us go offline
  648. //
  649. fdoExtension->Flags |= SDBUS_FDO_OFFLINE;
  650. //
  651. // clear pending event
  652. // ISSUE: NEED TO IMPLEMENT : drain worker timer before OK'ing stop
  653. KeCancelTimer(&fdoExtension->WorkerTimer);
  654. //
  655. // Send this down to the PDO
  656. //
  657. if (ARGUMENT_PRESENT(Irp)) {
  658. status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  659. if (!NT_SUCCESS(status)) {
  660. return status;
  661. }
  662. }
  663. if (!(fdoExtension->Flags & SDBUS_DEVICE_STARTED)) {
  664. //
  665. // Already stopped
  666. //
  667. return STATUS_SUCCESS;
  668. }
  669. if (fdoExtension->SdbusInterruptObject) {
  670. //
  671. // unhook the interrupt
  672. //
  673. IoDisconnectInterrupt(fdoExtension->SdbusInterruptObject);
  674. fdoExtension->SdbusInterruptObject = NULL;
  675. }
  676. //
  677. // Unmap any i/o space or memory we might have mapped
  678. //
  679. if (fdoExtension->Flags & SDBUS_HOST_REGISTER_BASE_MAPPED) {
  680. MmUnmapIoSpace(fdoExtension->HostRegisterBase,
  681. fdoExtension->HostRegisterSize);
  682. fdoExtension->Flags &= ~SDBUS_HOST_REGISTER_BASE_MAPPED;
  683. fdoExtension->HostRegisterBase = 0;
  684. fdoExtension->HostRegisterSize = 0;
  685. }
  686. if (fdoExtension->IoWorkItem) {
  687. IoFreeWorkItem(fdoExtension->IoWorkItem);
  688. fdoExtension->IoWorkItem = NULL;
  689. }
  690. fdoExtension->Flags &= ~SDBUS_DEVICE_STARTED;
  691. return STATUS_SUCCESS;
  692. }
  693. NTSTATUS
  694. SdbusFdoRemoveDevice(
  695. IN PDEVICE_OBJECT Fdo,
  696. IN PIRP Irp
  697. )
  698. /*++
  699. Routine Description:
  700. Handles IRP_MN_REMOVE for the sd controller.
  701. Stops the adapter if it isn't already, sends the IRP
  702. to the PDO first & cleans up the Fdo for this controller
  703. and detaches & deletes the device object.
  704. Arguments:
  705. Fdo - Pointer to functional device object for the controller
  706. to be removed
  707. Return value:
  708. Status
  709. --*/
  710. {
  711. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  712. PDEVICE_OBJECT pdo, nextPdo, fdo, prevFdo;
  713. PPDO_EXTENSION pdoExtension;
  714. NTSTATUS status;
  715. if (fdoExtension->Flags & SDBUS_DEVICE_STARTED) {
  716. //
  717. // Stop the fdo first.
  718. //
  719. SdbusFdoStopDevice(Fdo, NULL);
  720. }
  721. //
  722. // Send this down to the PDO
  723. //
  724. status = SdbusIoCallDriverSynchronous(fdoExtension->LowerDevice, Irp);
  725. if (!NT_SUCCESS(status)) {
  726. return status;
  727. }
  728. //
  729. // If the PdoList in the fdoExtension is non-empty it means:
  730. // that the PDOs in the list were not physically removed, but
  731. // a soft REMOVE was issued, hence they are still hanging on
  732. // and now this controller itself is being REMOVED.
  733. // Hence we dispose of those PDOs now
  734. //
  735. for (pdo = fdoExtension->PdoList; pdo != NULL ; pdo = nextPdo) {
  736. DebugPrint((SDBUS_DEBUG_INFO,
  737. "RemoveDevice: pdo %x child of fdo %x was not removed before fdo\n",
  738. pdo, Fdo));
  739. pdoExtension = pdo->DeviceExtension;
  740. ASSERT (!IsDevicePhysicallyRemoved(pdoExtension));
  741. //
  742. // It's possible for this bit to be on, if the device was added,
  743. // but never started (because of some other error.
  744. //ASSERT (!IsDeviceAlive(pdoExtension));
  745. nextPdo = pdoExtension->NextPdoInFdoChain;
  746. if (!IsDeviceDeleted(pdoExtension)) {
  747. MarkDeviceDeleted(pdoExtension);
  748. SdbusCleanupPdo(pdo);
  749. IoDeleteDevice(pdo);
  750. }
  751. }
  752. MarkDeviceDeleted(fdoExtension);
  753. //
  754. // Remove this from the fdo list..
  755. //
  756. prevFdo = NULL;
  757. for (fdo = FdoList; fdo != NULL; prevFdo = fdo, fdo = fdoExtension->NextFdo) {
  758. fdoExtension = fdo->DeviceExtension;
  759. if (fdo == Fdo) {
  760. if (prevFdo) {
  761. //
  762. // Delink this fdo
  763. //
  764. ((PFDO_EXTENSION)prevFdo->DeviceExtension)->NextFdo
  765. = fdoExtension->NextFdo;
  766. } else {
  767. FdoList = fdoExtension->NextFdo;
  768. }
  769. break;
  770. }
  771. }
  772. DebugPrint((SDBUS_DEBUG_PNP, "fdo %08x Remove detach & delete\n", Fdo));
  773. IoDetachDevice(((PFDO_EXTENSION)Fdo->DeviceExtension)->LowerDevice);
  774. IoDeleteDevice(Fdo);
  775. return STATUS_SUCCESS;
  776. }
  777. NTSTATUS
  778. SdbusDeviceRelations(
  779. IN PDEVICE_OBJECT Fdo,
  780. IN PIRP Irp,
  781. IN DEVICE_RELATION_TYPE RelationType,
  782. OUT PDEVICE_RELATIONS *DeviceRelations
  783. )
  784. /*++
  785. Routine Description:
  786. This routine will force enumeration of the sd controller represented by Fdo,
  787. allocate a device relations structure and fill in the count and object array with
  788. referenced object pointers to the valid PDOs which are created during enumeration
  789. Arguments:
  790. Fdo - a pointer to the functional device object being enumerated
  791. Irp - pointer to the Irp
  792. RelationType - Type of relationship to be retrieved
  793. DeviceRelations - Structure to store the device relations
  794. --*/
  795. {
  796. PDEVICE_OBJECT currentPdo;
  797. PPDO_EXTENSION currentPdoExtension;
  798. PFDO_EXTENSION fdoExtension = Fdo->DeviceExtension;
  799. ULONG newRelationsSize, oldRelationsSize = 0;
  800. PDEVICE_RELATIONS deviceRelations = NULL, oldDeviceRelations;
  801. ULONG i;
  802. ULONG count;
  803. NTSTATUS status;
  804. PAGED_CODE();
  805. //
  806. // Handle only bus, ejection & removal relations for now
  807. //
  808. if (RelationType != BusRelations &&
  809. RelationType != RemovalRelations) {
  810. DebugPrint((SDBUS_DEBUG_INFO,
  811. "SdbusDeviceRelations: RelationType %d, not handled\n",
  812. (USHORT) RelationType));
  813. return STATUS_NOT_SUPPORTED;
  814. }
  815. //
  816. // Need reenumeration only if bus relations are required
  817. // We need to save the pointer to the old device relations
  818. // before we call SdbusReenumerateDevices, as it might trample
  819. // on it
  820. //
  821. oldDeviceRelations = (PDEVICE_RELATIONS) Irp->IoStatus.Information;
  822. // I don't understand how this can be non-null, so I added this
  823. // assert to find out.
  824. ASSERT(oldDeviceRelations == NULL);
  825. if (RelationType == BusRelations) {
  826. status = SdbusEnumerateDevices(Fdo, Irp);
  827. if (!NT_SUCCESS(status)) {
  828. return status;
  829. }
  830. }
  831. if ((fdoExtension->LivePdoCount == 0) ||
  832. (RelationType == RemovalRelations)) {
  833. //
  834. // No PDO's to report, we can return early.
  835. // If no device_relations structure has yet been allocated, however,
  836. // we need to allocate one & set the count to zero. This will ensure
  837. // that regardless of whether we pass this IRP down or not, the IO
  838. // subsystem won't barf.
  839. //
  840. if (oldDeviceRelations == NULL) {
  841. *DeviceRelations = ExAllocatePool(PagedPool, sizeof(DEVICE_RELATIONS));
  842. if (*DeviceRelations == NULL) {
  843. return STATUS_INSUFFICIENT_RESOURCES;
  844. }
  845. (*DeviceRelations)->Count = 0;
  846. (*DeviceRelations)->Objects[0] = NULL;
  847. }
  848. return STATUS_SUCCESS;
  849. }
  850. if (!(oldDeviceRelations) || (oldDeviceRelations->Count == 0)) {
  851. newRelationsSize = sizeof(DEVICE_RELATIONS)+(fdoExtension->LivePdoCount - 1)
  852. * sizeof(PDEVICE_OBJECT);
  853. } else {
  854. oldRelationsSize = sizeof(DEVICE_RELATIONS) +
  855. (oldDeviceRelations->Count-1) * sizeof(PDEVICE_OBJECT);
  856. newRelationsSize = oldRelationsSize + fdoExtension->LivePdoCount
  857. * sizeof(PDEVICE_OBJECT);
  858. }
  859. deviceRelations = ExAllocatePool(PagedPool, newRelationsSize);
  860. if (deviceRelations == NULL) {
  861. DebugPrint((SDBUS_DEBUG_FAIL,
  862. "SdbusDeviceRelations: unable to allocate %d bytes for device relations\n",
  863. newRelationsSize));
  864. return STATUS_INSUFFICIENT_RESOURCES;
  865. }
  866. if (oldDeviceRelations) {
  867. if ((oldDeviceRelations)->Count > 0) {
  868. RtlCopyMemory(deviceRelations, oldDeviceRelations, oldRelationsSize);
  869. }
  870. count = oldDeviceRelations->Count; // May be zero
  871. ExFreePool (oldDeviceRelations);
  872. } else {
  873. count = 0;
  874. }
  875. //
  876. // Copy the object pointers into the structure
  877. //
  878. for (currentPdo = fdoExtension->PdoList ;currentPdo != NULL;
  879. currentPdo = currentPdoExtension->NextPdoInFdoChain) {
  880. currentPdoExtension = currentPdo->DeviceExtension;
  881. if (!IsDevicePhysicallyRemoved(currentPdoExtension)) {
  882. //
  883. // Devices have to be referenced by the bus driver
  884. // before returning them to PNP
  885. //
  886. deviceRelations->Objects[count++] = currentPdo;
  887. status = ObReferenceObjectByPointer(currentPdo,
  888. 0,
  889. NULL,
  890. KernelMode);
  891. if (!NT_SUCCESS(status)) {
  892. DebugPrint((SDBUS_DEBUG_FAIL, "SdbusDeviceRelations: status %#08lx "
  893. "while referencing object %#08lx\n",
  894. status,
  895. currentPdo));
  896. }
  897. }
  898. }
  899. deviceRelations->Count = count;
  900. *DeviceRelations = deviceRelations;
  901. return STATUS_SUCCESS;
  902. }