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.

3971 lines
107 KiB

  1. /*++
  2. Copyright (c) 1998 Microsoft Corporation
  3. Module Name:
  4. DBCLASS.C
  5. Abstract:
  6. class driver for device bay controllers
  7. This module implements the code to function as
  8. the Device Bay controller class driver
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include <wdm.h>
  15. #include "stdarg.h"
  16. #include "stdio.h"
  17. #include "dbci.h"
  18. #include "dbclass.h" //private data strutures
  19. #include "dbfilter.h"
  20. #include "usbioctl.h"
  21. #include "1394.h"
  22. #include <initguid.h>
  23. #include <wdmguid.h>
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text(PAGE, DBCLASS_SyncSubmitDrb)
  26. #pragma alloc_text(PAGE, DBCLASS_SyncGetSubsystemDescriptor)
  27. #pragma alloc_text(PAGE, DBCLASS_SyncGetBayDescriptor)
  28. #pragma alloc_text(PAGE, DBCLASS_SyncGetAllBayDescriptors)
  29. #pragma alloc_text(PAGE, DBCLASS_SyncBayFeatureRequest)
  30. #pragma alloc_text(PAGE, DBCLASS_SyncGetBayStatus)
  31. #endif
  32. /*
  33. Global Data Structures
  34. */
  35. PDBC_CONTEXT DBCLASS_ControllerList;
  36. KSPIN_LOCK DBCLASS_ControllerListSpin;
  37. // Internal list of Device PDOs
  38. LIST_ENTRY DBCLASS_DevicePdoList;
  39. //Internal list of Bus filter MDOs
  40. LIST_ENTRY DBCLASS_BusFilterMdoList;
  41. //
  42. // We currently only allow one USB hub to be associated with
  43. // an ACPI Device Bay Controller.
  44. // This hub may be the root hub or a real hub connected to one of
  45. // the root hub ports (ie Tier 1 only)
  46. //
  47. // We use the following global variable (since we only support
  48. // one ACPI DBC) to indicate the upstream port for the hub
  49. // 0 indicates the hub is the root hub
  50. // -1 indicates no ACPI DBC present
  51. //
  52. LONG DBCLASS_AcpiDBCHubParentPort = -1;
  53. // set up the debug variables
  54. #if DBG
  55. ULONG DBCLASS_TotalHeapSace = 0;
  56. ULONG DBCLASS_BreakOn = 0;
  57. // #define DEBUG3
  58. #ifdef DEBUG1
  59. ULONG DBCLASS_Debug_Trace_Level = 1;
  60. #else
  61. #ifdef DEBUG2
  62. ULONG DBCLASS_Debug_Trace_Level = 2;
  63. #else
  64. #ifdef DEBUG3
  65. ULONG DBCLASS_Debug_Trace_Level = 3;
  66. #else
  67. ULONG DBCLASS_Debug_Trace_Level = 0;
  68. #endif /* DEBUG 3 */
  69. #endif /* DEBUG2 */
  70. #endif /* DEBUG1 */
  71. #endif /* DBG */
  72. VOID
  73. DBCLASS_Wait(
  74. IN ULONG MilliSeconds
  75. )
  76. /* ++
  77. *
  78. * Descriptor:
  79. *
  80. * This causes the thread execution delayed for MiliSeconds.
  81. *
  82. * Argument:
  83. *
  84. * Mili-seconds to delay.
  85. *
  86. * Return:
  87. *
  88. * VOID
  89. *
  90. * -- */
  91. {
  92. LARGE_INTEGER time;
  93. ULONG timerIncerent;
  94. DBCLASS_KdPrint((2,"'Wait for %d ms\n", MilliSeconds));
  95. //
  96. // work only when LowPart is not overflown.
  97. //
  98. DBCLASS_ASSERT(21474 > MilliSeconds);
  99. //
  100. // wait ulMiliSeconds( 10000 100ns unit)
  101. //
  102. timerIncerent = KeQueryTimeIncrement() - 1;
  103. time.HighPart = -1;
  104. // round up to the next highest timer increment
  105. time.LowPart = -1 * (10000 * MilliSeconds + timerIncerent);
  106. KeDelayExecutionThread(KernelMode, FALSE, &time);
  107. return;
  108. }
  109. BOOLEAN
  110. IsBitSet(
  111. PVOID Bitmap,
  112. ULONG BitNumber
  113. )
  114. /* ++
  115. *
  116. * Description:
  117. *
  118. * Check if a bit is set given a string of bytes.
  119. *
  120. * Arguments:
  121. *
  122. *
  123. *
  124. * Return:
  125. *
  126. * TRUE - if the corresponding bit is set. FALSE - otherwise
  127. *
  128. * -- */
  129. {
  130. ULONG dwordOffset;
  131. ULONG bitOffset;
  132. PULONG l = (PULONG) Bitmap;
  133. dwordOffset = BitNumber / 32;
  134. bitOffset = BitNumber % 32;
  135. return ((l[dwordOffset] & (1 << bitOffset)) ? TRUE : FALSE);
  136. }
  137. LONG
  138. DBCLASS_DecrementIoCount(
  139. IN PDBC_CONTEXT DbcContext
  140. )
  141. /*++
  142. Routine Description:
  143. Arguments:
  144. Return Value:
  145. --*/
  146. {
  147. LONG ioCount;
  148. ioCount = InterlockedDecrement(&DbcContext->PendingIoCount);
  149. LOGENTRY(LOG_MISC, 'ioc-', DbcContext->PendingIoCount, ioCount, 0);
  150. DBCLASS_KdPrint ((2, "'Dec Pending io count = %x\n", ioCount));
  151. if (ioCount==0) {
  152. LOGENTRY(LOG_MISC, 'wRMe', DbcContext, 0, 0);
  153. KeSetEvent(&DbcContext->RemoveEvent,
  154. 1,
  155. FALSE);
  156. }
  157. return ioCount;
  158. }
  159. VOID
  160. DBCLASS_IncrementIoCount(
  161. IN PDBC_CONTEXT DbcContext
  162. )
  163. /*++
  164. Routine Description:
  165. Arguments:
  166. Return Value:
  167. --*/
  168. {
  169. InterlockedIncrement(&DbcContext->PendingIoCount);
  170. LOGENTRY(LOG_MISC, 'ioc+', DbcContext->PendingIoCount, 0, 0);
  171. }
  172. #if 0
  173. VOID
  174. SetBit(
  175. PVOID Bitmap,
  176. ULONG BitNumber
  177. )
  178. /* ++
  179. *
  180. * Description:
  181. *
  182. * Set a bit in a given a string of bytes.
  183. *
  184. * Arguments:
  185. *
  186. * Return:
  187. *
  188. * -- */
  189. {
  190. ULONG dwordOffset;
  191. ULONG bitOffset;
  192. PULONG l = (PULONG) Bitmap;
  193. dwordOffset = BitNumber / 32;
  194. bitOffset = BitNumber % 32;
  195. l[dwordOffset] | =(1 << bitOffset);
  196. }
  197. #endif
  198. NTSTATUS
  199. DBCLASS_SyncSubmitDrb(
  200. IN PDBC_CONTEXT DbcContext,
  201. IN PDEVICE_OBJECT DeviceObject,
  202. IN PDRB Drb
  203. )
  204. /* ++
  205. *
  206. * Routine Description:
  207. *
  208. * Passes a DRB to the DB Port Driver, and waits for return.
  209. *
  210. * Arguments:
  211. *
  212. * DeviceObject - Device object of the to of the port driver
  213. * stack
  214. *
  215. * Return Value:
  216. *
  217. * STATUS_SUCCESS if successful
  218. *
  219. * -- */
  220. {
  221. NTSTATUS ntStatus, status;
  222. PIRP irp;
  223. KEVENT event;
  224. IO_STATUS_BLOCK ioStatus;
  225. PIO_STACK_LOCATION nextStack;
  226. #ifdef DEADMAN_TIMER
  227. BOOLEAN haveTimer = FALSE;
  228. KDPC timeoutDpc;
  229. KTIMER timeoutTimer;
  230. #endif
  231. PAGED_CODE();
  232. DBCLASS_BEGIN_SERIALIZED_DRB(DbcContext);
  233. KeInitializeEvent(&event, NotificationEvent, FALSE);
  234. irp = IoBuildDeviceIoControlRequest(IOCTL_INTERNAL_DBC_SUBMIT_DRB,
  235. DeviceObject,
  236. NULL,
  237. 0,
  238. NULL,
  239. 0,
  240. TRUE, // INTERNAL
  241. &event,
  242. &ioStatus);
  243. if (NULL == irp) {
  244. DBCLASS_KdPrint((0, "'could not allocate an irp!\n"));
  245. TRAP();
  246. return STATUS_INSUFFICIENT_RESOURCES;
  247. }
  248. //
  249. // Call the port driver to perform the operation. If the returned
  250. // status
  251. // is PENDING, wait for the request to complete.
  252. //
  253. nextStack = IoGetNextIrpStackLocation(irp);
  254. //
  255. // pass the DRB
  256. //
  257. nextStack->Parameters.Others.Argument1 = Drb;
  258. ntStatus = IoCallDriver(DeviceObject, irp);
  259. if (ntStatus == STATUS_PENDING) {
  260. #ifdef DEADMAN_TIMER
  261. LARGE_INTEGER dueTime;
  262. KeInitializeTimer(&timeoutTimer);
  263. KeInitializeDpc(&timeoutDpc,
  264. UsbhTimeoutDPC,
  265. irp);
  266. dueTime.QuadPart = -10000 * DEADMAN_TIMEOUT;
  267. KeSetTimer(&timeoutTimer,
  268. dueTime,
  269. &timeoutDpc);
  270. haveTimer = TRUE;
  271. #endif
  272. status = KeWaitForSingleObject(&event,
  273. Suspended,
  274. KernelMode,
  275. FALSE,
  276. NULL);
  277. } else {
  278. ioStatus.Status = ntStatus;
  279. }
  280. #ifdef DEADMAN_TIMER
  281. //
  282. // remove our timeoutDPC from the queue
  283. //
  284. if (haveTimer) {
  285. KeCancelTimer(&timeoutTimer);
  286. }
  287. #endif /* DEADMAN_TIMER */
  288. DBCLASS_END_SERIALIZED_DRB(DbcContext);
  289. ntStatus = ioStatus.Status;
  290. DBCLASS_KdPrint((2,"'DBCLASS_SyncSubmitDrb (%x)\n", ntStatus));
  291. return ntStatus;
  292. }
  293. NTSTATUS
  294. DBCLASS_StartController(
  295. IN PDBC_CONTEXT DbcContext,
  296. IN PIRP Irp,
  297. IN PBOOLEAN HandledByClass
  298. )
  299. /*++
  300. Routine Description:
  301. This routine starts the DBC note that we should never set
  302. HandledByClass to TRUE because the port driver always completes
  303. this request (if we get an error we just need to set the
  304. ntStatus code)
  305. Arguments:
  306. DbcContext - context for controller
  307. Irp -
  308. HandledByClass - not used
  309. Return Value:
  310. STATUS_SUCCESS if successful
  311. --*/
  312. {
  313. NTSTATUS ntStatus = STATUS_SUCCESS;
  314. USHORT bay;
  315. CHAR stackSize;
  316. BOOLEAN Device1394IsPresent = FALSE;
  317. DBCLASS_KdPrint((1, "'Starting DBC\n"));
  318. BRK_ON_TRAP();
  319. LOGENTRY(LOG_MISC, 'STRd', DbcContext, 0, 0);
  320. INITIALIZE_DRB_SERIALIZATION(DbcContext);
  321. KeInitializeSpinLock(&DbcContext->FlagsSpin);
  322. KeInitializeEvent(&DbcContext->RemoveEvent, NotificationEvent, FALSE);
  323. DbcContext->PendingIoCount = 0;
  324. DbcContext->Flags = 0;
  325. // this will be set when the filter registers
  326. DbcContext->BusFilterMdo1394 = NULL;
  327. DbcContext->BusFilterMdoUSB = NULL;
  328. stackSize = DbcContext->TopOfStack->StackSize;
  329. DbcContext->ChangeIrp = IoAllocateIrp(stackSize, FALSE);
  330. DbcContext->Bus1394PortInfo = NULL;
  331. DbcContext->LinkDeviceObject = NULL;
  332. if (NULL == DbcContext->ChangeIrp ) {
  333. DBCLASS_KdPrint((0, "'could not allocate an irp!\n"));
  334. TRAP();
  335. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  336. }
  337. if (NT_SUCCESS(ntStatus)) {
  338. // get the susbsystem descriptor
  339. ntStatus = DBCLASS_SyncGetSubsystemDescriptor(DbcContext);
  340. }
  341. if (NT_SUCCESS(ntStatus)) {
  342. ntStatus = DBCLASS_SyncGetAllBayDescriptors(DbcContext);
  343. }
  344. //
  345. // if this is a USBDBC then write the approptiate info
  346. // to the registry
  347. //
  348. if (NT_SUCCESS(ntStatus)) {
  349. if (DbcContext->ControllerSig == DBC_USB_CONTROLLER_SIG) {
  350. // this will set the registry keys for the hub
  351. // the USBDBC is attached to -- marking it as a
  352. // DBC associated hub
  353. ntStatus = DBCLASS_SetupUSB_DBC(DbcContext);
  354. } else {
  355. // controller is ACPI therefore the 1394 bus guid is the
  356. // same as the 1394 guid reported by the DBC -- ie there
  357. // is no extra Link Phy for an ACPI DBC.
  358. // get the ACPIDBC Hub register now from the
  359. // registry
  360. DBCLASS_GetRegistryKeyValueForPdo(DbcContext->ControllerPdo,
  361. FALSE,
  362. ACPI_HUB_KEY,
  363. sizeof(ACPI_HUB_KEY),
  364. &DBCLASS_AcpiDBCHubParentPort,
  365. sizeof(DBCLASS_AcpiDBCHubParentPort));
  366. DBCLASS_KdPrint((1, "'ACPI USB Parent Port: %d\n",
  367. DBCLASS_AcpiDBCHubParentPort));
  368. #if DBG
  369. if (DBCLASS_AcpiDBCHubParentPort == -1) {
  370. DBCLASS_KdPrint((0, "'ACPI USB Parent Port not set!\n"));
  371. TEST_TRAP();
  372. }
  373. #endif
  374. RtlCopyMemory(&DbcContext->Guid1394Bus[0],
  375. &DbcContext->SubsystemDescriptor.guid1394Link[0],
  376. 8);
  377. }
  378. }
  379. //
  380. // initialize per bay structures
  381. //
  382. DbcContext->BayInformation[0].DeviceFilterObject = (PVOID) -1;
  383. for (bay=1; bay <=NUMBER_OF_BAYS(DbcContext); bay++) {
  384. PDBC_BAY_DESCRIPTOR bayDescriptor;
  385. bayDescriptor =
  386. &DbcContext->BayInformation[bay].BayDescriptor;
  387. // initilaize current status to 'empty'
  388. DbcContext->BayInformation[bay].LastBayStatus.us = 0;
  389. DbcContext->BayInformation[bay].DeviceFilterObject = NULL;
  390. // set the hub port number based on what the
  391. // controller reported
  392. DbcContext->BayInformation[bay].UsbHubPort =
  393. bayDescriptor->bHubPortNumber;
  394. #if DBG
  395. DBCLASS_KdPrint((1,"'>BAY[%d].BayDescriptor.bBayNumber %d\n",
  396. bay, bayDescriptor->bBayNumber));
  397. DBCLASS_KdPrint((1,"'>BAY[%d].BayDescriptor.bHubPortNumber %d\n",
  398. bay, bayDescriptor->bHubPortNumber));
  399. DBCLASS_KdPrint((1,"'>BAY[%d].BayDescriptor.bPHYPortNumber %d\n",
  400. bay, bayDescriptor->bPHYPortNumber));
  401. DBCLASS_KdPrint((1,"'>BAY[%d].BayDescriptor.bFormFactor %d\n",
  402. bay, bayDescriptor->bFormFactor));
  403. #endif
  404. }
  405. // now post a notification
  406. if (NT_SUCCESS(ntStatus)) {
  407. DBCLASS_PostChangeRequest(DbcContext);
  408. }
  409. if (NT_SUCCESS(ntStatus)) {
  410. // Bays initialized:
  411. //
  412. // Enable change indications for all bays, we post a change irp
  413. // in case we start getting notifications right away
  414. //
  415. for (bay=1; bay <= NUMBER_OF_BAYS(DbcContext); bay++) {
  416. DBCLASS_SyncBayFeatureRequest(DbcContext,
  417. DRB_FUNCTION_SET_BAY_FEATURE,
  418. bay,
  419. DEVICE_STATUS_CHANGE_ENABLE);
  420. DBCLASS_SyncBayFeatureRequest(DbcContext,
  421. DRB_FUNCTION_SET_BAY_FEATURE,
  422. bay,
  423. REMOVAL_REQUEST_ENABLE);
  424. }
  425. //
  426. // check the initial state of the bays
  427. //
  428. // see if any devices are present
  429. //
  430. DBCLASS_KdPrint((1,"'STARTCONTROLLER: Checking Bays\n"));
  431. for (bay=1; bay <= NUMBER_OF_BAYS(DbcContext); bay++) {
  432. NTSTATUS status;
  433. BAY_STATUS bayStatus;
  434. status = DBCLASS_SyncGetBayStatus(DbcContext,
  435. bay,
  436. &bayStatus);
  437. if (NT_SUCCESS(status)) {
  438. DBCLASS_KdPrint((1,"'STARTCONTROLLER: init state - bay[%d] %x\n",
  439. bay, bayStatus.us));
  440. //
  441. if (bayStatus.DeviceUsbIsPresent ||
  442. bayStatus.Device1394IsPresent) {
  443. if(bayStatus.Device1394IsPresent)
  444. Device1394IsPresent = TRUE;
  445. // we have a device in the bay
  446. DBCLASS_KdPrint((1,"'STARTCONTROLLER: detected device in bay[%d] %x\n",
  447. bay));
  448. switch(bayStatus.CurrentBayState) {
  449. case BAY_STATE_EMPTY:
  450. case BAY_STATE_DEVICE_ENABLED:
  451. // note:
  452. // on the TI dbc if the bay state is enabled the device does
  453. // not appear on the native bus
  454. case BAY_STATE_DEVICE_INSERTED:
  455. // note:
  456. // on the TI dbc if the bay state is inserted the device does
  457. // not appear on the native bus
  458. DBCLASS_KdPrint((1,"'STARTCONTROLLER: setting bay %d to inserted state\n", bay));
  459. DBCLASS_SyncBayFeatureRequest(DbcContext,
  460. DRB_FUNCTION_SET_BAY_FEATURE,
  461. bay,
  462. REQUEST_DEVICE_INSERTED_STATE);
  463. // get the new status and process it
  464. status = DBCLASS_SyncGetBayStatus(DbcContext,
  465. bay,
  466. &bayStatus);
  467. if (NT_SUCCESS(status)) {
  468. DBCLASS_ProcessCurrentBayState(DbcContext,
  469. bayStatus,
  470. bay,
  471. NULL);
  472. }
  473. break;
  474. default:
  475. break;
  476. } /* switch bayStatus.CurrentBayState */
  477. }
  478. }
  479. }
  480. } /* nt_success */
  481. if (NT_SUCCESS(ntStatus)) {
  482. // get registry controled features
  483. {
  484. NTSTATUS status;
  485. ULONG release_on_shutdown = 0;
  486. // check unlock on shutdown, the default is on
  487. status = DBCLASS_GetRegistryKeyValueForPdo(
  488. DbcContext->ControllerPdo,
  489. TRUE,
  490. RELEASE_ON_SHUTDOWN,
  491. sizeof(RELEASE_ON_SHUTDOWN),
  492. &release_on_shutdown,
  493. sizeof(release_on_shutdown));
  494. DBCLASS_KdPrint((1,"'STARTCONTROLLER: release_on_shutdown = %d\n",
  495. release_on_shutdown));
  496. if (release_on_shutdown) {
  497. DbcContext->Flags |= DBCLASS_FLAG_RELEASE_ON_SHUTDOWN;
  498. }
  499. }
  500. //
  501. // consider ourselves started
  502. // note: if we return an error stopcontroller
  503. // will not be called
  504. //
  505. DbcContext->Stopped = FALSE;
  506. // set our current power state to 'D0' ie ON
  507. DbcContext->CurrentDevicePowerState = PowerDeviceD0;
  508. // in order for the DBC to be linked to a 1394 bus
  509. // we need to do an IoInvalidateDeviceRelations on
  510. // all 1394 busses
  511. if(Device1394IsPresent)
  512. DBCLASS_Refresh1394();
  513. }
  514. // transition to zero signals stop/remove
  515. //
  516. // since we will get a stop even if we return
  517. // an error we alaways increment
  518. DBCLASS_IncrementIoCount(DbcContext);
  519. DBCLASS_KdPrint((1,"'STARTCONTROLLER: ntStatus = %x\n", ntStatus));
  520. LOGENTRY(LOG_MISC, 'STRT', DbcContext, 0, ntStatus);
  521. return ntStatus;
  522. }
  523. NTSTATUS
  524. DBCLASS_CleanupController(
  525. IN PDBC_CONTEXT DbcContext
  526. )
  527. /*++
  528. Routine Description:
  529. cleans up the DBC on stop or remove
  530. Arguments:
  531. DbcContext - context for controller
  532. Return Value:
  533. STATUS_SUCCESS if successful
  534. --*/
  535. {
  536. NTSTATUS ntStatus;
  537. LOGENTRY(LOG_MISC, 'clUP', DbcContext, 0, 0);
  538. ntStatus = STATUS_SUCCESS;
  539. return ntStatus;
  540. }
  541. NTSTATUS
  542. DBCLASS_StopController(
  543. IN PDBC_CONTEXT DbcContext,
  544. IN PIRP Irp,
  545. IN PBOOLEAN HandledByClass
  546. )
  547. /*++
  548. Routine Description:
  549. Stops the DBC
  550. Arguments:
  551. DbcContext - context for controller
  552. Irp -
  553. HandledByClass - set to true if we need to complete the Irp
  554. Return Value:
  555. STATUS_SUCCESS if successful
  556. --*/
  557. {
  558. NTSTATUS ntStatus = STATUS_SUCCESS;
  559. KIRQL irql;
  560. BOOLEAN needCancel;
  561. DBCLASS_KdPrint((1, "'Stopping DBC\n"));
  562. LOGENTRY(LOG_MISC, 'STP>', DbcContext, 0, 0);
  563. // disable bay locks here
  564. if (DbcContext->Flags |= DBCLASS_FLAG_RELEASE_ON_SHUTDOWN)
  565. {
  566. USHORT bay;
  567. for (bay = 1; bay <= NUMBER_OF_BAYS(DbcContext); bay++)
  568. {
  569. PDRB drb;
  570. //
  571. // notify filter of a stop
  572. // note that the filter may not veto the stop
  573. //
  574. drb = DbcExAllocatePool(NonPagedPool,
  575. sizeof(struct _DRB_START_DEVICE_IN_BAY));
  576. if (drb)
  577. {
  578. drb->DrbHeader.Length = sizeof(struct _DRB_STOP_DEVICE_IN_BAY);
  579. drb->DrbHeader.Function = DRB_FUNCTION_STOP_DEVICE_IN_BAY;
  580. drb->DrbHeader.Flags = 0;
  581. drb->DrbStartDeviceInBay.BayNumber = bay;
  582. // make the request
  583. ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
  584. DbcContext->TopOfStack,
  585. drb);
  586. DbcExFreePool(drb);
  587. }
  588. }
  589. }
  590. // cancel any pending notification Irps
  591. KeAcquireSpinLock(&DbcContext->FlagsSpin, &irql);
  592. DbcContext->Flags |= DBCLASS_FLAG_STOPPING;
  593. needCancel = (BOOLEAN) (DbcContext->Flags & DBCLASS_FLAG_REQ_PENDING);
  594. KeReleaseSpinLock(&DbcContext->FlagsSpin, irql);
  595. DBCLASS_DecrementIoCount(DbcContext);
  596. if (needCancel) {
  597. LOGENTRY(LOG_MISC, 'kIRP', DbcContext, DbcContext->ChangeIrp, 0);
  598. IoCancelIrp(DbcContext->ChangeIrp);
  599. }
  600. {
  601. NTSTATUS status;
  602. // wait for any io request pending in our driver to
  603. // complete for finishing the remove
  604. LOGENTRY(LOG_MISC, 'STwt', DbcContext, 0, 0);
  605. status = KeWaitForSingleObject(
  606. &DbcContext->RemoveEvent,
  607. Suspended,
  608. KernelMode,
  609. FALSE,
  610. NULL);
  611. LOGENTRY(LOG_MISC, 'STwd', DbcContext, 0, 0);
  612. }
  613. LOGENTRY(LOG_MISC, 'STP<', DbcContext, 0, ntStatus);
  614. return ntStatus;
  615. }
  616. PDBC_CONTEXT
  617. DBCLASS_GetDbcContext(
  618. IN PDEVICE_OBJECT ControllerFdo
  619. )
  620. /*++
  621. Routine Description:
  622. Stops the DBC
  623. Arguments:
  624. Return Value:
  625. STATUS_SUCCESS if successful
  626. --*/
  627. {
  628. PDBC_CONTEXT dbcContext;
  629. KIRQL irql;
  630. // search our list if we find the TopOfStack device
  631. // object then this must be a filter driver, otherwise
  632. // allocate a new context structure for this controller
  633. KeAcquireSpinLock(&DBCLASS_ControllerListSpin, &irql);
  634. dbcContext = DBCLASS_ControllerList;
  635. while (dbcContext) {
  636. if (dbcContext->ControllerFdo == ControllerFdo) {
  637. break;
  638. }
  639. dbcContext = dbcContext->Next;
  640. }
  641. KeReleaseSpinLock(&DBCLASS_ControllerListSpin, irql);
  642. return dbcContext;
  643. }
  644. NTSTATUS
  645. DBCLASS_SyncGetSubsystemDescriptor(
  646. IN PDBC_CONTEXT DbcContext
  647. )
  648. /* ++
  649. *
  650. * Description:
  651. *
  652. * fetch the susbsystem descriptor from the port driver, and allocate
  653. * a structure for the bay information
  654. *
  655. * Arguments:
  656. *
  657. * Return:
  658. *
  659. * -- */
  660. {
  661. NTSTATUS ntStatus;
  662. PDRB drb;
  663. PAGED_CODE();
  664. //
  665. // Allocate Drb from the non-paged pool
  666. //
  667. drb = DbcExAllocatePool(NonPagedPool,
  668. sizeof(struct _DRB_GET_SUBSYSTEM_DESCRIPTOR));
  669. if (drb) {
  670. drb->DrbHeader.Length = sizeof(struct _DRB_GET_SUBSYSTEM_DESCRIPTOR);
  671. drb->DrbHeader.Function = DRB_FUNCTION_GET_SUBSYSTEM_DESCRIPTOR;
  672. drb->DrbHeader.Flags = 0;
  673. // make the request
  674. ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
  675. DbcContext->TopOfStack,
  676. drb);
  677. if (NT_SUCCESS(ntStatus)) {
  678. RtlCopyMemory(&DbcContext->SubsystemDescriptor,
  679. &drb->DrbGetSubsystemDescriptor.SubsystemDescriptor,
  680. sizeof(DbcContext->SubsystemDescriptor));
  681. // dump susbsystem descriptor to debugger
  682. DBCLASS_KdPrint((1, "'DBC Susbsystem Descriptor:\n"));
  683. DBCLASS_KdPrint((1, "'>bLength = (%08X)\n",
  684. DbcContext->SubsystemDescriptor.bLength));
  685. DBCLASS_KdPrint((1, "'>bDescriptorType = (%08X)\n",
  686. DbcContext->SubsystemDescriptor.bDescriptorType));
  687. DBCLASS_KdPrint((1, "'>SUBSYSTEM_DESCR = (%08X)\n",
  688. DbcContext->SubsystemDescriptor.bmAttributes));
  689. DBCLASS_KdPrint((1, "'>>SUBSYSTEM_DESCR.BayCount = (%08X)\n",
  690. DbcContext->SubsystemDescriptor.bmAttributes.BayCount));
  691. DBCLASS_KdPrint((1, "'>>SUBSYSTEM_DESCR.HasSecurityLock = (%08X)\n",
  692. DbcContext->SubsystemDescriptor.bmAttributes.HasSecurityLock));
  693. DBCLASS_KdPrint((1, "'>>SUBSYSTEM_DESCR.LinkGuid\n"));
  694. #if DBG
  695. DBCLASS_KdPrintGuid(1,
  696. &DbcContext->SubsystemDescriptor.guid1394Link[0]);
  697. #endif
  698. }
  699. DbcExFreePool(drb);
  700. } else {
  701. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  702. }
  703. return ntStatus;
  704. }
  705. NTSTATUS
  706. DBCLASS_SyncGetBayDescriptor(
  707. IN PDBC_CONTEXT DbcContext,
  708. IN USHORT BayNumber,
  709. IN PDBC_BAY_DESCRIPTOR BayDescriptor
  710. )
  711. /* ++
  712. *
  713. * Description:
  714. *
  715. * fetch the bay descriptor from the port driver,
  716. *
  717. * Arguments:
  718. *
  719. * Return:
  720. *
  721. * -- */
  722. {
  723. NTSTATUS ntStatus;
  724. PDRB drb;
  725. PAGED_CODE();
  726. //
  727. // Allocate Drb from the non-paged pool
  728. //
  729. drb = DbcExAllocatePool(NonPagedPool,
  730. sizeof(struct _DRB_GET_BAY_DESCRIPTOR));
  731. if (drb) {
  732. drb->DrbHeader.Length = sizeof(struct _DRB_GET_BAY_DESCRIPTOR);
  733. drb->DrbHeader.Function = DRB_FUNCTION_GET_BAY_DESCRIPTOR;
  734. drb->DrbHeader.Flags = 0;
  735. drb->DrbGetBayDescriptor.BayNumber = BayNumber;
  736. // make the request
  737. ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
  738. DbcContext->TopOfStack,
  739. drb);
  740. if (NT_SUCCESS(ntStatus)) {
  741. RtlCopyMemory(BayDescriptor,
  742. &drb->DrbGetBayDescriptor.BayDescriptor,
  743. sizeof(*BayDescriptor));
  744. }
  745. DbcExFreePool(drb);
  746. } else {
  747. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  748. }
  749. return ntStatus;
  750. }
  751. NTSTATUS
  752. DBCLASS_SyncGetControllerStatus(
  753. IN PDBC_CONTEXT DbcContext
  754. )
  755. /* ++
  756. *
  757. * Description:
  758. *
  759. * Arguments:
  760. *
  761. * Return:
  762. *
  763. * -- */
  764. {
  765. NTSTATUS ntStatus;
  766. PDRB drb;
  767. PAGED_CODE();
  768. //
  769. // Allocate Drb from the non-paged pool
  770. //
  771. drb = DbcExAllocatePool(NonPagedPool,
  772. sizeof(struct _DRB_GET_CONTROLLER_STATUS));
  773. if (drb) {
  774. drb->DrbHeader.Length = sizeof(struct _DRB_GET_CONTROLLER_STATUS);
  775. drb->DrbHeader.Function = DRB_FUNCTION_GET_CONTROLLER_STATUS;
  776. // make the request
  777. ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
  778. DbcContext->TopOfStack,
  779. drb);
  780. DbcExFreePool(drb);
  781. } else {
  782. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  783. }
  784. return ntStatus;
  785. }
  786. NTSTATUS
  787. DBCLASS_SyncGetAllBayDescriptors(
  788. IN PDBC_CONTEXT DbcContext
  789. )
  790. /* ++
  791. *
  792. * Description:
  793. *
  794. * fetch the susbsystem descriptor from the port driver, and allocate
  795. * a structure for the bay information
  796. *
  797. * Arguments:
  798. *
  799. * Return:
  800. *
  801. * -- */
  802. {
  803. NTSTATUS ntStatus = STATUS_SUCCESS;
  804. USHORT bay;
  805. PAGED_CODE();
  806. for (bay=1; bay <= NUMBER_OF_BAYS(DbcContext); bay++) {
  807. ntStatus = DBCLASS_SyncGetBayDescriptor(DbcContext,
  808. bay,
  809. &DbcContext->BayInformation[bay].BayDescriptor);
  810. }
  811. return ntStatus;
  812. }
  813. NTSTATUS
  814. DBCLASS_SyncBayFeatureRequest(
  815. IN PDBC_CONTEXT DbcContext,
  816. IN USHORT Op,
  817. IN USHORT BayNumber,
  818. IN USHORT FeatureSelector
  819. )
  820. /* ++
  821. *
  822. * Description:
  823. *
  824. * fetch the susbsystem descriptor from the port driver, and allocate
  825. * a structure for the bay information
  826. *
  827. * Arguments:
  828. *
  829. * Return:
  830. *
  831. * -- */
  832. {
  833. NTSTATUS ntStatus;
  834. PDRB drb;
  835. PAGED_CODE();
  836. //
  837. // Allocate Drb from the non-paged pool
  838. //
  839. DBCLASS_ASSERT(BayNumber != 0);
  840. DBCLASS_ASSERT(BayNumber <= MAX_BAY_NUMBER);
  841. drb = DbcExAllocatePool(NonPagedPool,
  842. sizeof(struct _DRB_BAY_FEATURE_REQUEST));
  843. if (drb) {
  844. drb->DrbHeader.Length = sizeof(struct _DRB_BAY_FEATURE_REQUEST);
  845. drb->DrbHeader.Function = Op;
  846. drb->DrbHeader.Flags = 0;
  847. drb->DrbBayFeatureRequest.BayNumber = BayNumber;
  848. drb->DrbBayFeatureRequest.FeatureSelector = FeatureSelector;
  849. // make the request
  850. ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
  851. DbcContext->TopOfStack,
  852. drb);
  853. DbcExFreePool(drb);
  854. } else {
  855. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  856. }
  857. return ntStatus;
  858. }
  859. NTSTATUS
  860. DBCLASS_SyncGetBayStatus(
  861. IN PDBC_CONTEXT DbcContext,
  862. IN USHORT BayNumber,
  863. IN PBAY_STATUS BayStatus
  864. )
  865. /* ++
  866. *
  867. * Description:
  868. *
  869. * fetch the susbsystem descriptor from the port driver, and allocate
  870. * a structure for the bay information
  871. *
  872. * Arguments:
  873. *
  874. * Return:
  875. *
  876. * -- */
  877. {
  878. NTSTATUS ntStatus;
  879. PDRB drb;
  880. PAGED_CODE();
  881. //
  882. // Allocate Drb from the non-paged pool
  883. //
  884. DBCLASS_ASSERT(BayNumber != 0);
  885. DBCLASS_ASSERT(BayNumber <= MAX_BAY_NUMBER);
  886. drb = DbcExAllocatePool(NonPagedPool,
  887. sizeof(struct _DRB_GET_BAY_STATUS));
  888. if (drb) {
  889. drb->DrbHeader.Length = sizeof(struct _DRB_GET_BAY_STATUS);
  890. drb->DrbHeader.Function = DRB_FUNCTION_GET_BAY_STATUS;
  891. drb->DrbHeader.Flags = 0;
  892. drb->DrbGetBayStatus.BayNumber = BayNumber;
  893. // make the request
  894. ntStatus = DBCLASS_SyncSubmitDrb(DbcContext,
  895. DbcContext->TopOfStack,
  896. drb);
  897. if (NT_SUCCESS(ntStatus)) {
  898. BayStatus->us = drb->DrbGetBayStatus.BayStatus.us;
  899. // dump status to debugger
  900. DBCLASS_KdPrint((2, "'status for bay (%d) 0x%0x:\n", BayNumber,
  901. drb->DrbGetBayStatus.BayStatus.us));
  902. DBCLASS_KdPrint((2, "'>VidEnabled = (%08X)\n",
  903. BayStatus->VidEnabled));
  904. DBCLASS_KdPrint((2, "'>RemovalWakeupEnabled = (%08X)\n",
  905. BayStatus->RemovalWakeupEnabled));
  906. DBCLASS_KdPrint((2, "'>DeviceStatusChangeEnabled = (%08X)\n",
  907. BayStatus->DeviceStatusChangeEnabled));
  908. DBCLASS_KdPrint((2, "'>RemovalRequestEnabled = (%08X)\n",
  909. BayStatus->RemovalRequestEnabled));
  910. DBCLASS_KdPrint((2, "'>LastBayStateRequested = (%08X)\n",
  911. BayStatus->LastBayStateRequested));
  912. DBCLASS_KdPrint((2, "'>InterlockEngaged = (%08X)\n",
  913. BayStatus->InterlockEngaged));
  914. DBCLASS_KdPrint((2, "'>DeviceUsbIsPresent = (%08X)\n",
  915. BayStatus->DeviceUsbIsPresent));
  916. DBCLASS_KdPrint((2, "'>Device1394IsPresent = (%08X)\n",
  917. BayStatus->Device1394IsPresent));
  918. DBCLASS_KdPrint((2, "'>DeviceStatusChange = (%08X)\n",
  919. BayStatus->DeviceStatusChange));
  920. DBCLASS_KdPrint((2, "'>RemovalRequestChange = (%08X)\n",
  921. BayStatus->RemovalRequestChange));
  922. DBCLASS_KdPrint((2, "'>CurrentBayState = (%08X)\n",
  923. BayStatus->CurrentBayState));
  924. DBCLASS_KdPrint((2, "'>SecurityLockEngaged = (%08X)\n",
  925. BayStatus->SecurityLockEngaged));
  926. }
  927. DbcExFreePool(drb);
  928. } else {
  929. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  930. }
  931. return ntStatus;
  932. }
  933. NTSTATUS
  934. DBCLASS_ChangeIndication(
  935. IN PDEVICE_OBJECT PNull,
  936. IN PIRP Irp,
  937. IN PVOID Context
  938. )
  939. /* ++
  940. *
  941. * Description:
  942. *
  943. * Arguments:
  944. *
  945. * Return:
  946. *
  947. * -- */
  948. {
  949. PDBC_CONTEXT dbcContext = Context;
  950. KIRQL irql;
  951. BOOLEAN stopping;
  952. PDBCLASS_WORKITEM workItem;
  953. // status change
  954. //
  955. // we should not get here unless something really has
  956. // changed
  957. KeAcquireSpinLock(&dbcContext->FlagsSpin, &irql);
  958. dbcContext->Flags &= ~DBCLASS_FLAG_REQ_PENDING;
  959. stopping = (BOOLEAN) (dbcContext->Flags & DBCLASS_FLAG_STOPPING);
  960. KeReleaseSpinLock(&dbcContext->FlagsSpin, irql);
  961. LOGENTRY(LOG_MISC, 'CHid', dbcContext, 0, Irp->IoStatus.Status);
  962. BRK_ON_TRAP();
  963. if (!stopping) {
  964. //
  965. // we have a legitimate change
  966. //
  967. // schedule a workitem to process the change
  968. LOGENTRY(LOG_MISC, 'QCH>', dbcContext, 0, 0);
  969. workItem = DbcExAllocatePool(NonPagedPool, sizeof(DBCLASS_WORKITEM));
  970. if (workItem) {
  971. DBCLASS_KdPrint((1, "'Schedule Workitem for Change Request\n"));
  972. LOGENTRY(LOG_MISC, 'qITM', dbcContext,
  973. workItem, 0);
  974. workItem->Sig = DBC_WORKITEM_SIG;
  975. workItem->DbcContext = dbcContext;
  976. workItem->IrpStatus = Irp->IoStatus.Status;
  977. ExInitializeWorkItem(&workItem->WorkQueueItem,
  978. DBCLASS_ChangeIndicationWorker,
  979. workItem);
  980. ExQueueWorkItem(&workItem->WorkQueueItem,
  981. DelayedWorkQueue);
  982. } else {
  983. DBCLASS_DecrementIoCount(dbcContext);
  984. DBCLASS_KdPrint((0, "'No Memory for workitem!\n"));
  985. TRAP();
  986. }
  987. } else {
  988. DBCLASS_DecrementIoCount(dbcContext);
  989. }
  990. return STATUS_MORE_PROCESSING_REQUIRED;
  991. }
  992. NTSTATUS
  993. DBCLASS_ProcessCurrentBayState(
  994. IN PDBC_CONTEXT DbcContext,
  995. IN BAY_STATUS BayStatus,
  996. IN USHORT Bay,
  997. IN PBOOLEAN PostChangeRequest
  998. )
  999. /* ++
  1000. *
  1001. * Description:
  1002. *
  1003. * Arguments:
  1004. *
  1005. * Return:
  1006. *
  1007. * -- */
  1008. {
  1009. ULONG last,current;
  1010. NTSTATUS ntStatus = STATUS_SUCCESS;
  1011. current = BayStatus.CurrentBayState;
  1012. last = DbcContext->BayInformation[Bay].LastBayStatus.CurrentBayState;
  1013. DBCLASS_KdPrint((0, "'>PBS - current bay state: %x\n", current));
  1014. DBCLASS_KdPrint((0, "'>last bay state: %x\n", last));
  1015. // figure out what current state of the bay is and deal with it
  1016. if (current == last) {
  1017. DBCLASS_KdPrint((0, "'>>no changes detected %x\n", current));
  1018. } else {
  1019. switch (current) {
  1020. case BAY_STATE_DEVICE_INSERTED:
  1021. LOGENTRY(LOG_MISC, 'byIN', DbcContext, ntStatus, Bay);
  1022. // engage the interlock, lock that baby in to the bay
  1023. ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
  1024. DRB_FUNCTION_SET_BAY_FEATURE,
  1025. Bay,
  1026. LOCK_CTL);
  1027. DBCLASS_Wait(1000);
  1028. // enable Vid so the device will appear on the native bus
  1029. ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
  1030. DRB_FUNCTION_SET_BAY_FEATURE,
  1031. Bay,
  1032. ENABLE_VID_POWER);
  1033. DBCLASS_Wait(1000);
  1034. //
  1035. // The device will now appear on the native bus
  1036. // allowing the OS to load appropriate drivers
  1037. //
  1038. DBCLASS_KdPrint((0, "'>>Bay Vid Power Enabled\n"));
  1039. // *PostChangeRequest = FALSE;
  1040. /* remove when filter is ready */
  1041. ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
  1042. DRB_FUNCTION_SET_BAY_FEATURE,
  1043. Bay,
  1044. REQUEST_DEVICE_ENABLED_STATE);
  1045. DBCLASS_SyncGetBayStatus(DbcContext, Bay, &BayStatus);
  1046. DbcContext->BayInformation[Bay].LastBayStatus = BayStatus;
  1047. /**/
  1048. break;
  1049. case BAY_STATE_DEVICE_REMOVAL_REQUESTED:
  1050. {
  1051. PIO_STACK_LOCATION nextStack;
  1052. PDRB drb;
  1053. CHAR stackSize;
  1054. PIRP irp;
  1055. PEJECT_CONTEXT ejectContext;
  1056. PUCHAR pch;
  1057. DBCLASS_KdPrint((0, "'>>Request Device Eject BAY[%d]\n", Bay));
  1058. // need to OK the eject
  1059. pch = DbcExAllocatePool(NonPagedPool,
  1060. sizeof(struct _DRB_START_DEVICE_IN_BAY) + sizeof(EJECT_CONTEXT));
  1061. ejectContext = (PEJECT_CONTEXT) pch;
  1062. drb = (PDRB) (pch + sizeof(EJECT_CONTEXT));
  1063. if (pch) {
  1064. ejectContext->Bay = Bay;
  1065. ejectContext->DbcContext = DbcContext;
  1066. drb->DrbHeader.Length = sizeof(struct _DRB_EJECT_DEVICE_IN_BAY);
  1067. drb->DrbHeader.Function = DRB_FUNCTION_EJECT_DEVICE_IN_BAY;
  1068. drb->DrbHeader.Flags = 0;
  1069. drb->DrbEjectDeviceInBay.BayNumber = Bay;
  1070. // deviceExtensionPdoFilter =
  1071. // DbcContext->BayInformation[Bay].DeviceFilterObject->DeviceExtension;
  1072. // make the request asynchronously
  1073. //
  1074. // normally this request is just completed by the port
  1075. // driver but we make the request so that the oem filter
  1076. // may intervene in the removal process
  1077. stackSize = DbcContext->TopOfStack->StackSize;
  1078. irp = IoAllocateIrp(stackSize, FALSE);
  1079. if (NULL == irp) {
  1080. DBCLASS_KdPrint((0, "'could not allocate an irp!\n"));
  1081. if (PostChangeRequest) {
  1082. *PostChangeRequest = TRUE;
  1083. }
  1084. TRAP();
  1085. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1086. } else {
  1087. //
  1088. // Call the port driver to perform the operation. If the returned
  1089. //
  1090. nextStack = IoGetNextIrpStackLocation(irp);
  1091. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1092. nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_DBC_SUBMIT_DRB;
  1093. nextStack->Parameters.Others.Argument1 = drb;
  1094. //
  1095. // pass the DRB
  1096. //
  1097. IoSetCompletionRoutine(irp,
  1098. DBCLASS_EjectBayComplete,
  1099. ejectContext,
  1100. TRUE,
  1101. TRUE,
  1102. TRUE);
  1103. ntStatus = IoCallDriver(DbcContext->TopOfStack, irp);
  1104. if (PostChangeRequest) {
  1105. *PostChangeRequest = FALSE;
  1106. }
  1107. }
  1108. } else {
  1109. // no memory for drb, re-post the change request and
  1110. // try again
  1111. DBCLASS_KdPrint((0, "'could not allocate an drb!\n"));
  1112. if (PostChangeRequest) {
  1113. *PostChangeRequest = TRUE;
  1114. }
  1115. TRAP();
  1116. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1117. }
  1118. }
  1119. break;
  1120. case BAY_STATE_EMPTY:
  1121. //
  1122. // we should have no PDO if the bay is empty
  1123. //
  1124. // DBCLASS_ASSERT(
  1125. // DbcContext->BayInformation[Bay].DeviceFilterObject == NULL);
  1126. DBCLASS_KdPrint((0, "'>>Found Bay empty\n"));
  1127. break;
  1128. case BAY_STATE_DEVICE_ENABLED:
  1129. //
  1130. // we may get here because the bay was enabled at boot
  1131. // in this case we have nothing to do
  1132. //
  1133. DBCLASS_KdPrint((0, "'>>Found Bay enabled\n"));
  1134. break;
  1135. default:
  1136. DBCLASS_KdPrint((0, "'>>Bay State not handled\n"));
  1137. TRAP();
  1138. break;
  1139. } /* switch */
  1140. }
  1141. return ntStatus;
  1142. }
  1143. VOID
  1144. DBCLASS_ChangeIndicationWorker(
  1145. IN PVOID Context
  1146. )
  1147. /* ++
  1148. *
  1149. * Description:
  1150. *
  1151. * Arguments:
  1152. *
  1153. * Return:
  1154. *
  1155. * NTSTATUS
  1156. *
  1157. * -- */
  1158. {
  1159. PDBCLASS_WORKITEM workItem = Context;
  1160. PDBC_CONTEXT dbcContext = workItem->DbcContext;
  1161. BAY_STATUS bayStatus;
  1162. USHORT bay;
  1163. NTSTATUS ntStatus, irpStatus;
  1164. BOOLEAN found = FALSE;
  1165. BOOLEAN postChangeRequest = TRUE;
  1166. LOGENTRY(LOG_MISC, 'cWK+', 0, Context, 0);
  1167. irpStatus = workItem->IrpStatus;
  1168. DbcExFreePool(workItem);
  1169. if (!NT_SUCCESS(irpStatus)) {
  1170. // we got an error
  1171. // get the controller status
  1172. NTSTATUS status;
  1173. status = DBCLASS_SyncGetControllerStatus(dbcContext);
  1174. LOGENTRY(LOG_MISC, 'cERR', dbcContext, status, irpStatus);
  1175. if (status == STATUS_DEVICE_NOT_CONNECTED) {
  1176. // controller was removed, don't
  1177. // re-post the request
  1178. postChangeRequest = FALSE;
  1179. }
  1180. // problem may be temporary
  1181. goto DBCLASS_ChangeIndicationWorker_Done;
  1182. }
  1183. // find out which bay changed
  1184. // find out what changed
  1185. // clear the change, note that we only
  1186. // clear the change that we process
  1187. for (bay = 0; bay <= MAX_BAY_NUMBER; bay++) {
  1188. if (IsBitSet(&dbcContext->ChangeDrb.BayChange, bay)) {
  1189. found = TRUE;
  1190. break;
  1191. }
  1192. }
  1193. // no change?
  1194. if (!found) {
  1195. DBCLASS_KdPrint((0, "'no bay indicated! -- bug in port driver\n", bay));
  1196. bay = 0;
  1197. TRAP();
  1198. }
  1199. DBCLASS_KdPrint((0, "'Process status change, bay = (%d)\n", bay));
  1200. if (bay > 0) {
  1201. ntStatus = DBCLASS_SyncGetBayStatus(dbcContext, bay, &bayStatus);
  1202. if (NT_SUCCESS(ntStatus)) {
  1203. // acknowlege any status change bits now
  1204. //
  1205. // NOTE that the status change bits are redundent
  1206. // we process the change base on the current state
  1207. // of the bay compared to the last known state
  1208. //
  1209. if (bayStatus.DeviceStatusChange) {
  1210. DBCLASS_KdPrint((0, "'>>device status change bit set\n"));
  1211. DBCLASS_SyncBayFeatureRequest(dbcContext,
  1212. DRB_FUNCTION_CLEAR_BAY_FEATURE,
  1213. bay,
  1214. C_DEVICE_STATUS_CHANGE);
  1215. DBCLASS_KdPrint((0, "'>>>cleared\n"));
  1216. }
  1217. if (bayStatus.RemovalRequestChange) {
  1218. DBCLASS_KdPrint((0, "'>>remove request change bit set\n"));
  1219. DBCLASS_SyncBayFeatureRequest(dbcContext,
  1220. DRB_FUNCTION_CLEAR_BAY_FEATURE,
  1221. bay,
  1222. C_REMOVE_REQUEST);
  1223. DBCLASS_KdPrint((0, "'>>>cleared\n"));
  1224. }
  1225. ntStatus = DBCLASS_ProcessCurrentBayState(dbcContext,
  1226. bayStatus,
  1227. bay,
  1228. &postChangeRequest);
  1229. }
  1230. } else {
  1231. DBCLASS_KdPrint((0, "'Global status change on DB subsystem\n"));
  1232. TEST_TRAP();
  1233. }
  1234. DBCLASS_ChangeIndicationWorker_Done:
  1235. LOGENTRY(LOG_MISC, 'chDN', dbcContext, ntStatus, bay);
  1236. // finished with this request, dec the count
  1237. DBCLASS_DecrementIoCount(dbcContext);
  1238. if (postChangeRequest) {
  1239. LOGENTRY(LOG_MISC, 'chPS', dbcContext, ntStatus, bay);
  1240. DBCLASS_PostChangeRequest(dbcContext);
  1241. }
  1242. return;
  1243. }
  1244. VOID
  1245. DBCLASS_PostChangeRequest(
  1246. IN PDBC_CONTEXT DbcContext
  1247. )
  1248. /* ++
  1249. *
  1250. * Description:
  1251. *
  1252. * fetch the bay descriptor from the port driver,
  1253. *
  1254. * Arguments:
  1255. *
  1256. * Return:
  1257. * This routine never fails
  1258. *
  1259. * -- */
  1260. {
  1261. PDRB drb;
  1262. PIRP irp;
  1263. KIRQL irql;
  1264. CHAR stackSize;
  1265. PIO_STACK_LOCATION nextStack;
  1266. PAGED_CODE();
  1267. // Drb and irp are pre-allocated
  1268. drb = (PDRB) &DbcContext->ChangeDrb;
  1269. irp = DbcContext->ChangeIrp;
  1270. stackSize = DbcContext->TopOfStack->StackSize;
  1271. drb->DrbHeader.Length = sizeof(struct _DRB_CHANGE_REQUEST);
  1272. drb->DrbHeader.Function = DRB_FUNCTION_CHANGE_REQUEST ;
  1273. drb->DrbHeader.Flags = 0;
  1274. drb->DrbChangeRequest.BayChange = 0;
  1275. IoInitializeIrp(irp,
  1276. (USHORT) (sizeof(IRP) + stackSize * sizeof(IO_STACK_LOCATION)),
  1277. (CCHAR) stackSize);
  1278. nextStack = IoGetNextIrpStackLocation(irp);
  1279. nextStack->Parameters.Others.Argument1 = drb;
  1280. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1281. nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_DBC_SUBMIT_DRB;
  1282. IoSetCompletionRoutine(irp, // Irp
  1283. DBCLASS_ChangeIndication,
  1284. DbcContext, // context
  1285. TRUE, // invoke on success
  1286. TRUE, // invoke on error
  1287. TRUE); // invoke on cancel
  1288. //
  1289. // Call the port driver
  1290. //
  1291. KeAcquireSpinLock(&DbcContext->FlagsSpin, &irql);
  1292. if (DbcContext->Flags & DBCLASS_FLAG_STOPPING) {
  1293. LOGENTRY(LOG_MISC, 'stpX', DbcContext, 0, 0);
  1294. KeReleaseSpinLock(&DbcContext->FlagsSpin, irql);
  1295. } else {
  1296. DbcContext->Flags |= DBCLASS_FLAG_REQ_PENDING;
  1297. KeReleaseSpinLock(&DbcContext->FlagsSpin, irql);
  1298. DBCLASS_IncrementIoCount(DbcContext);
  1299. DBCLASS_BEGIN_SERIALIZED_DRB(DbcContext);
  1300. DBCLASS_KdPrint((1, "'Post Change Request\n"));
  1301. LOGENTRY(LOG_MISC, 'post', DbcContext, 0, irp);
  1302. // let the completion routine handle any errors
  1303. IoCallDriver(DbcContext->TopOfStack, irp);
  1304. DBCLASS_END_SERIALIZED_DRB(DbcContext);
  1305. }
  1306. return;
  1307. }
  1308. #if 0
  1309. USHORT
  1310. DBCLASS_GetBayNumber(
  1311. IN PDEVICE_OBJECT DeviceFilterObject
  1312. )
  1313. /* ++
  1314. *
  1315. * Description:
  1316. *
  1317. * given a device filter object, find the bay with this device
  1318. *
  1319. * Arguments:
  1320. *
  1321. * Return:
  1322. * This routine never fails
  1323. *
  1324. * -- */
  1325. {
  1326. PDBC_CONTEXT dbcContext;
  1327. USHORT bay;
  1328. PDEVICE_EXTENSION deviceExtension;
  1329. DBCLASS_ASSERT(DeviceFilterObject);
  1330. deviceExtension =
  1331. DeviceFilterObject->DeviceExtension;
  1332. if(deviceExtension)
  1333. {
  1334. dbcContext = deviceExtension->DbcContext;
  1335. LOGENTRY(LOG_MISC, 'GBNn', dbcContext, DeviceFilterObject, 0);
  1336. if(dbcContext)
  1337. {
  1338. for (bay=1; bay <=NUMBER_OF_BAYS(dbcContext); bay++)
  1339. {
  1340. if (dbcContext->BayInformation[bay].DeviceFilterObject == DeviceFilterObject) {
  1341. LOGENTRY(LOG_MISC, 'GBNr', dbcContext, DeviceFilterObject, bay);
  1342. return bay;
  1343. }
  1344. }
  1345. }
  1346. }
  1347. return 0;
  1348. }
  1349. #endif
  1350. #if 0
  1351. NTSTATUS
  1352. DBCLASS_EnableDevice(
  1353. IN PDEVICE_OBJECT DeviceFilterObject
  1354. )
  1355. /* ++
  1356. *
  1357. * Description:
  1358. *
  1359. * given a device filter object, eject the device in the bay
  1360. *
  1361. * Arguments:
  1362. *
  1363. * Return:
  1364. * This routine never fails
  1365. *
  1366. * -- */
  1367. {
  1368. PDBC_CONTEXT dbcContext;
  1369. PDEVICE_EXTENSION deviceExtension;
  1370. USHORT bay;
  1371. BAY_STATUS bayStatus;
  1372. NTSTATUS ntStatus = STATUS_SUCCESS;
  1373. DBCLASS_ASSERT(DeviceFilterObject);
  1374. deviceExtension =
  1375. DeviceFilterObject->DeviceExtension;
  1376. dbcContext = deviceExtension->DbcContext;
  1377. bay = DBCLASS_GetBayNumber(DeviceFilterObject);
  1378. DBCLASS_KdPrint((0, "'>>Bay to Enabled state\n"));
  1379. ntStatus = DBCLASS_SyncBayFeatureRequest(dbcContext,
  1380. DRB_FUNCTION_SET_BAY_FEATURE,
  1381. bay,
  1382. REQUEST_DEVICE_ENABLED_STATE);
  1383. DBCLASS_SyncGetBayStatus(dbcContext, bay, &bayStatus);
  1384. dbcContext->BayInformation[bay].LastBayStatus = bayStatus;
  1385. DBCLASS_DecrementIoCount(dbcContext);
  1386. DBCLASS_PostChangeRequest(dbcContext);
  1387. return STATUS_SUCCESS;
  1388. }
  1389. #endif
  1390. NTSTATUS
  1391. DBCLASS_EjectPdo(
  1392. IN PDEVICE_OBJECT DeviceFilterObject
  1393. )
  1394. /* ++
  1395. *
  1396. * Description:
  1397. *
  1398. * given a device filter object, eject the device in the bay by Pdo
  1399. *
  1400. * Arguments:
  1401. *
  1402. * Return:
  1403. * This routine never fails
  1404. *
  1405. * -- */
  1406. {
  1407. PDBC_CONTEXT dbcContext;
  1408. PDEVICE_EXTENSION deviceExtension =
  1409. DeviceFilterObject->DeviceExtension;
  1410. NTSTATUS ntStatus = STATUS_SUCCESS;
  1411. dbcContext = deviceExtension->DbcContext;
  1412. ntStatus = DBCLASS_EjectBay(dbcContext,
  1413. deviceExtension->Bay);
  1414. DBCLASS_DecrementIoCount(dbcContext);
  1415. DBCLASS_PostChangeRequest(dbcContext);
  1416. return ntStatus;
  1417. }
  1418. NTSTATUS
  1419. DBCLASS_EjectBay(
  1420. IN PDBC_CONTEXT DbcContext,
  1421. IN USHORT Bay
  1422. )
  1423. /* ++
  1424. *
  1425. * Description:
  1426. *
  1427. * given a bay, eject the device in it
  1428. *
  1429. * Arguments:
  1430. *
  1431. * Return:
  1432. * This routine never fails
  1433. *
  1434. * -- */
  1435. {
  1436. BAY_STATUS bayStatus;
  1437. NTSTATUS ntStatus = STATUS_SUCCESS;
  1438. DBCLASS_KdPrint((0, "'>EJECT Bay[%d]\n", Bay));
  1439. // disengage the interlock
  1440. DBCLASS_KdPrint((0, "'>>disable VID\n"));
  1441. ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
  1442. DRB_FUNCTION_CLEAR_BAY_FEATURE,
  1443. Bay,
  1444. ENABLE_VID_POWER);
  1445. DBCLASS_KdPrint((0, "'>>disengage interlock\n"));
  1446. ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
  1447. DRB_FUNCTION_CLEAR_BAY_FEATURE,
  1448. Bay,
  1449. LOCK_CTL);
  1450. DBCLASS_KdPrint((0, "'>>Bay to Removal allowed state\n"));
  1451. ntStatus = DBCLASS_SyncBayFeatureRequest(DbcContext,
  1452. DRB_FUNCTION_SET_BAY_FEATURE,
  1453. Bay,
  1454. REQUEST_REMOVAL_ALLOWED_STATE);
  1455. DBCLASS_SyncGetBayStatus(DbcContext, Bay, &bayStatus);
  1456. DbcContext->BayInformation[Bay].LastBayStatus = bayStatus;
  1457. return ntStatus;
  1458. }
  1459. NTSTATUS
  1460. DBCLASS_AddDevicePDOToList(
  1461. IN PDEVICE_OBJECT FilterDeviceObject,
  1462. IN PDEVICE_OBJECT PdoDeviceObject
  1463. )
  1464. /*++
  1465. Routine Description:
  1466. Adds a bus emumerated PDO to our list of PDOs
  1467. Currently we only track 1394 PDOs
  1468. Arguments:
  1469. FilterDeviceObject - filter MDO for the 1394 bus this device is on
  1470. PdoDeviceObject - 1394 Enumerated PDO
  1471. Return Value:
  1472. STATUS_INSUFFICIENT_RESOURCES if a buffer could not be allocated
  1473. STATUS_SUCCESS otherwise
  1474. --*/
  1475. {
  1476. PDBCLASS_PDO_LIST newEntry;
  1477. newEntry = ExAllocatePool(NonPagedPool, sizeof(DBCLASS_PDO_LIST));
  1478. if (newEntry == NULL) {
  1479. TRAP();
  1480. return STATUS_INSUFFICIENT_RESOURCES;
  1481. }
  1482. // Fill in fields in new entry
  1483. newEntry->FilterDeviceObject = FilterDeviceObject;
  1484. newEntry->PdoDeviceObject = PdoDeviceObject;
  1485. // Add new entry to end of list
  1486. InsertTailList(&DBCLASS_DevicePdoList, &newEntry->ListEntry);
  1487. return STATUS_SUCCESS;
  1488. }
  1489. VOID
  1490. DBCLASS_RemoveDevicePDOFromList(
  1491. IN PDEVICE_OBJECT PdoDeviceObject
  1492. )
  1493. /*++
  1494. Routine Description:
  1495. Removes a 1394 emumerated PDO to our list of 1394 PDOs
  1496. Arguments:
  1497. PdoDeviceObject - 1394 Enumerated PDO to remove from list
  1498. Return Value:
  1499. VOID
  1500. --*/
  1501. {
  1502. PDBCLASS_PDO_LIST entry;
  1503. PLIST_ENTRY listEntry;
  1504. listEntry = &DBCLASS_DevicePdoList;
  1505. if (!IsListEmpty(listEntry)) {
  1506. listEntry = DBCLASS_DevicePdoList.Flink;
  1507. }
  1508. while (listEntry != &DBCLASS_DevicePdoList) {
  1509. entry = CONTAINING_RECORD(listEntry,
  1510. DBCLASS_PDO_LIST,
  1511. ListEntry);
  1512. DBCLASS_ASSERT(entry);
  1513. if (entry->PdoDeviceObject == PdoDeviceObject) {
  1514. break;
  1515. }
  1516. listEntry = entry->ListEntry.Flink;
  1517. }
  1518. // we should always find it
  1519. DBCLASS_ASSERT(listEntry != &DBCLASS_DevicePdoList);
  1520. RemoveEntryList(listEntry);
  1521. ExFreePool(entry);
  1522. }
  1523. PDEVICE_OBJECT
  1524. DBCLASS_FindDevicePdo(
  1525. PDEVICE_OBJECT PdoDeviceObject
  1526. )
  1527. /*++
  1528. Routine Description:
  1529. find a device PDO -- return tru if we know about it
  1530. Arguments:
  1531. Return Value:
  1532. NTSTATUS
  1533. --*/
  1534. {
  1535. PDBCLASS_PDO_LIST entry;
  1536. PLIST_ENTRY listEntry;
  1537. // we keep a global list of PDOs we know about
  1538. listEntry = &DBCLASS_DevicePdoList;
  1539. if (!IsListEmpty(listEntry)) {
  1540. listEntry = DBCLASS_DevicePdoList.Flink;
  1541. }
  1542. while (listEntry != &DBCLASS_DevicePdoList) {
  1543. entry = CONTAINING_RECORD(listEntry,
  1544. DBCLASS_PDO_LIST,
  1545. ListEntry);
  1546. DBCLASS_ASSERT(entry);
  1547. if (entry->PdoDeviceObject == PdoDeviceObject) {
  1548. return entry->FilterDeviceObject;
  1549. }
  1550. listEntry = entry->ListEntry.Flink;
  1551. }
  1552. return NULL;
  1553. }
  1554. PDBC_CONTEXT
  1555. DBCLASS_FindControllerACPI(
  1556. PDRIVER_OBJECT FilterDriverObject,
  1557. PDEVICE_OBJECT FilterMdo
  1558. )
  1559. /*++
  1560. Routine Description:
  1561. find the DBC controller in our list for a given Filter MDO
  1562. if found the filter MDO is linked to the controller
  1563. This routine searches the list for an ACPI DBC
  1564. currently we support only one.
  1565. Arguments:
  1566. Return Value:
  1567. Controller Context
  1568. --*/
  1569. {
  1570. PDBC_CONTEXT dbcContext = NULL;
  1571. PDEVICE_EXTENSION deviceExtension;
  1572. deviceExtension = FilterMdo->DeviceExtension;
  1573. dbcContext = DBCLASS_ControllerList;
  1574. //
  1575. // NOTE: We support only one ACPI DBC controller
  1576. //
  1577. while (dbcContext) {
  1578. if (dbcContext->ControllerSig == DBC_ACPI_CONTROLLER_SIG) {
  1579. if (deviceExtension->FdoType == DB_FDO_USBHUB_BUS) {
  1580. dbcContext->BusFilterMdoUSB = FilterMdo;
  1581. } else if (deviceExtension->FdoType == DB_FDO_1394_BUS) {
  1582. dbcContext->BusFilterMdo1394 = FilterMdo;
  1583. } else {
  1584. TRAP();
  1585. }
  1586. dbcContext->BusFilterDriverObject = FilterDriverObject;
  1587. break;
  1588. }
  1589. dbcContext = dbcContext->Next;
  1590. }
  1591. LOGENTRY(LOG_MISC, 'FIN1', dbcContext, 0, 0);
  1592. #if DBG
  1593. if (dbcContext == NULL) {
  1594. DBCLASS_KdPrint((0, "'ACPI Controller not Found\n"));
  1595. }
  1596. #endif
  1597. return dbcContext;
  1598. }
  1599. PDBC_CONTEXT
  1600. DBCLASS_FindControllerUSB(
  1601. PDRIVER_OBJECT FilterDriverObject,
  1602. PDEVICE_OBJECT FilterMdo,
  1603. PDEVICE_OBJECT UsbHubPdo
  1604. )
  1605. /*++
  1606. Routine Description:
  1607. find the DBC controller in our list for a given Filter MDO
  1608. if found the filter MDO is linked to the controller
  1609. This routine will query the hub to see if an DBC controller
  1610. is attached.
  1611. Arguments:
  1612. Return Value:
  1613. Controller Context
  1614. --*/
  1615. {
  1616. UCHAR dbcGuid[8];
  1617. NTSTATUS ntStatus;
  1618. PDBC_CONTEXT dbcContext = NULL;
  1619. PDEVICE_EXTENSION deviceExtension;
  1620. deviceExtension = FilterMdo->DeviceExtension;
  1621. // first get the guid for this hub
  1622. ntStatus = DBCLASS_GetHubDBCGuid(FilterMdo,
  1623. dbcGuid);
  1624. dbcContext = DBCLASS_ControllerList;
  1625. while (dbcContext) {
  1626. if (RtlCompareMemory(&dbcContext->SubsystemDescriptor.guid1394Link[0],
  1627. &dbcGuid[0], 8) == 8) {
  1628. if (deviceExtension->FdoType == DB_FDO_USBHUB_BUS) {
  1629. dbcContext->BusFilterMdoUSB = FilterMdo;
  1630. } else if (deviceExtension->FdoType == DB_FDO_1394_BUS) {
  1631. dbcContext->BusFilterMdo1394 = FilterMdo;
  1632. } else {
  1633. TRAP();
  1634. }
  1635. dbcContext->BusFilterDriverObject = FilterDriverObject;
  1636. break;
  1637. }
  1638. dbcContext = dbcContext->Next;
  1639. }
  1640. return dbcContext;
  1641. }
  1642. NTSTATUS
  1643. DBCLASS_Find1394DbcLinks(
  1644. PDEVICE_OBJECT DevicePdo1394
  1645. )
  1646. /*++
  1647. Routine Description:
  1648. find the DBC controller in our list for a given Filter MDO
  1649. if found the filter MDO is linked to the controller
  1650. Given the 1394 device PDO and the bus guid we try to find the
  1651. appropriate controller
  1652. Arguments:
  1653. Return Value:
  1654. Controller Context
  1655. --*/
  1656. {
  1657. PDBC_CONTEXT dbcContext;
  1658. DBCLASS_KdPrint((1, "'Find DBC Links\n"));
  1659. dbcContext = DBCLASS_ControllerList;
  1660. while (dbcContext) {
  1661. if (DBCLASS_IsLinkDeviceObject(dbcContext,
  1662. DevicePdo1394)) {
  1663. DBCLASS_KdPrint((1, "'1394 PDO is DBC Link\n"));
  1664. // set the bus guid for the context
  1665. DBCLASS_1394GetBusGuid(DevicePdo1394,
  1666. &dbcContext->Guid1394Bus[0]);
  1667. }
  1668. dbcContext = dbcContext->Next;
  1669. }
  1670. return STATUS_SUCCESS;
  1671. }
  1672. PDBC_CONTEXT
  1673. DBCLASS_FindController1394DevicePdo(
  1674. PDRIVER_OBJECT FilterDriverObject,
  1675. PDEVICE_OBJECT FilterMdo,
  1676. PDEVICE_OBJECT DevicePdo1394,
  1677. PUCHAR BusGuid
  1678. )
  1679. /*++
  1680. Routine Description:
  1681. find the DBC controller in our list for a given Filter MDO
  1682. if found the filter MDO is linked to the controller
  1683. Given the 1394 device PDO and the bus guid we try to find the
  1684. appropriate DB controller
  1685. busguid is the 1394 controller guid for the bus this device is on
  1686. Arguments:
  1687. Return Value:
  1688. Controller Context
  1689. --*/
  1690. {
  1691. PDBC_CONTEXT dbcContext = NULL;
  1692. PDBC_CONTEXT foundDbcContext = NULL;
  1693. // if a DBC reports the magic guid then we match on that
  1694. UCHAR magicGuid[8] = {0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
  1695. DBCLASS_KdPrint((1, "'>Find Controller -> 1394 DEV PDO (%x)\n", DevicePdo1394));
  1696. DBCLASS_KdPrint((1, "'>>1394 CONTROLLER (BUS) GUID\n"));
  1697. DBCLASS_KdPrintGuid(1,
  1698. BusGuid);
  1699. BRK_ON_TRAP();
  1700. //
  1701. // first loop through controllers
  1702. // checking to see if this is a PDO
  1703. // for a link, if so we mark the context as NULL
  1704. // ie not a DB device
  1705. //
  1706. dbcContext = DBCLASS_ControllerList;
  1707. while (dbcContext) {
  1708. if (DBCLASS_IsLinkDeviceObject(dbcContext,
  1709. DevicePdo1394)) {
  1710. DBCLASS_KdPrint((1, "'>>>1394 PDO is DBC Link\n"));
  1711. return NULL;
  1712. }
  1713. dbcContext = dbcContext->Next;
  1714. }
  1715. //
  1716. // loop through the controllers, checking each one
  1717. // until we have a match
  1718. dbcContext = DBCLASS_ControllerList;
  1719. while (dbcContext && foundDbcContext == NULL) {
  1720. NTSTATUS status;
  1721. DBCLASS_KdPrint((2, "'Checking DBC (%x)\n", dbcContext));
  1722. DBCLASS_KdPrint((2, "'BUS GUID (%x)\n", dbcContext));
  1723. DBCLASS_KdPrintGuid(2,
  1724. &dbcContext->Guid1394Bus[0]);
  1725. // only look at controllers on the same bus
  1726. if (
  1727. (RtlCompareMemory(&dbcContext->Guid1394Bus[0],
  1728. BusGuid, 8) == 8) ||
  1729. (RtlCompareMemory(&dbcContext->Guid1394Bus[0],
  1730. &magicGuid[0], 8) == 8)
  1731. ) {
  1732. // OK we found a match, now see if this PDO is part of
  1733. // this controller
  1734. status = DBCLASS_Check1394DevicePDO(FilterMdo,
  1735. dbcContext,
  1736. DevicePdo1394);
  1737. if (NT_SUCCESS(status)) {
  1738. foundDbcContext = dbcContext;
  1739. dbcContext->BusFilterMdo1394 = FilterMdo;
  1740. dbcContext->BusFilterDriverObject = FilterDriverObject;
  1741. }
  1742. }
  1743. dbcContext = dbcContext->Next;
  1744. }
  1745. #if DBG
  1746. if (foundDbcContext) {
  1747. DBCLASS_KdPrint((1, "'>>>>Found DBC (%x)\n", foundDbcContext));
  1748. } else {
  1749. DBCLASS_KdPrint((1, "'>>>>DBC not found\n"));
  1750. }
  1751. #endif
  1752. return foundDbcContext;
  1753. }
  1754. NTSTATUS
  1755. DBCLASS_PdoSetLockComplete(
  1756. IN PDEVICE_OBJECT DeviceObject,
  1757. IN PIRP Irp,
  1758. IN PVOID Context
  1759. )
  1760. /*++
  1761. Routine Description:
  1762. Arguments:
  1763. DeviceObject - a pointer to the device object
  1764. Irp - a pointer to the irp
  1765. Context - NULL ptr
  1766. Return Value:
  1767. STATUS_SUCCESS
  1768. --*/
  1769. {
  1770. Irp->IoStatus.Status = STATUS_SUCCESS;
  1771. LOGENTRY(LOG_MISC, 'LOKc', 0, 0, 0);
  1772. return STATUS_SUCCESS;
  1773. }
  1774. #define IS_1394_DEVICE(de) ((de)->FdoType == DB_FDO_1394_DEVICE)
  1775. NTSTATUS
  1776. DBCLASS_PdoFilterDispatch(
  1777. PDEVICE_OBJECT DeviceObject,
  1778. PIRP Irp,
  1779. PBOOLEAN Handled
  1780. )
  1781. /*++
  1782. Routine Description:
  1783. Common filter function for both 1394 and USB PDOs
  1784. Arguments:
  1785. Return Value:
  1786. NTSTATUS
  1787. --*/
  1788. {
  1789. PIO_STACK_LOCATION irpStack;
  1790. NTSTATUS ntStatus;
  1791. PDEVICE_EXTENSION deviceExtensionPdoFilter;
  1792. deviceExtensionPdoFilter = DeviceObject->DeviceExtension;
  1793. ntStatus = Irp->IoStatus.Status;
  1794. *Handled = FALSE;
  1795. irpStack = IoGetCurrentIrpStackLocation (Irp);
  1796. LOGENTRY(LOG_MISC, 'pdo>', 0, DeviceObject, Irp);
  1797. DBCLASS_KdPrint((1, "'(dbfilter)(device)(%x)IRP_MJ_ (%08X) IRP_MN_ (%08X)\n",
  1798. DeviceObject, irpStack->MajorFunction, irpStack->MinorFunction));
  1799. switch (irpStack->MajorFunction)
  1800. {
  1801. case IRP_MJ_PNP:
  1802. switch (irpStack->MinorFunction)
  1803. {
  1804. case IRP_MN_START_DEVICE:
  1805. {
  1806. PDBC_CONTEXT dbcContext;
  1807. USHORT bay = 0;
  1808. KEVENT event;
  1809. DBCLASS_KdPrint((1, "'(dbfilter)(device)(%x)IRP_MN_START_DEVICE\n",
  1810. deviceExtensionPdoFilter->PhysicalDeviceObject));
  1811. *Handled = TRUE;
  1812. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1813. IoCopyCurrentIrpStackLocationToNext(Irp);
  1814. IoSetCompletionRoutine(Irp,
  1815. DBCLASS_DeferIrpCompletion,
  1816. &event,
  1817. TRUE,
  1818. TRUE,
  1819. TRUE);
  1820. //
  1821. // send the request down the stack before we eject
  1822. //
  1823. ntStatus = IoCallDriver(deviceExtensionPdoFilter->TopOfStackDeviceObject,
  1824. Irp);
  1825. if (ntStatus == STATUS_PENDING)
  1826. {
  1827. // wait for irp to complete
  1828. KeWaitForSingleObject(
  1829. &event,
  1830. Suspended,
  1831. KernelMode,
  1832. FALSE,
  1833. NULL);
  1834. }
  1835. // started a 1394 device, figure out what bay it is in
  1836. if (IS_1394_DEVICE(deviceExtensionPdoFilter))
  1837. {
  1838. DBCLASS_KdPrint((1, "'**> Starting 1394 PDO (%x)\n",
  1839. deviceExtensionPdoFilter->PhysicalDeviceObject));
  1840. bay = deviceExtensionPdoFilter->Bay;
  1841. dbcContext = deviceExtensionPdoFilter->DbcContext;
  1842. }
  1843. // we have no USB device bay devices
  1844. #if 0
  1845. else
  1846. {
  1847. dbcContext = deviceExtensionPdoFilter->DbcContext;
  1848. DBCLASS_KdPrint((0, "'**> Starting USB PDO (%08X) Filter DevObj (%08X) DbcContext (%08X)\n",
  1849. deviceExtensionPdoFilter->PhysicalDeviceObject, DeviceObject, dbcContext));
  1850. if (dbcContext != NULL)
  1851. {
  1852. bay = DBCLASS_GetBayForUSBPdo(
  1853. dbcContext,
  1854. deviceExtensionPdoFilter->PhysicalDeviceObject);
  1855. if (bay == 0)
  1856. {
  1857. // ignore this PDO from now on
  1858. deviceExtensionPdoFilter->FdoType = DB_FDO_BUS_IGNORE;
  1859. DBCLASS_KdPrint((1,
  1860. "'>>>> USB PDO(%x) is not a DB device <<<<\n",
  1861. deviceExtensionPdoFilter->PhysicalDeviceObject));
  1862. }
  1863. else
  1864. {
  1865. DBCLASS_KdPrint((1,
  1866. "'>>>> USB PDO(%x) is in BAY[%d] <<<<\n",
  1867. deviceExtensionPdoFilter->PhysicalDeviceObject,
  1868. bay));
  1869. }
  1870. }
  1871. else
  1872. {
  1873. // no controller yet -- can't be a device bay device
  1874. bay = 0;
  1875. DBCLASS_KdPrint((1, "'No Controller Available\n"));
  1876. }
  1877. //TEST_TRAP();
  1878. }
  1879. #endif
  1880. // keep track of the bay we are in in case
  1881. // we get an eject irp
  1882. deviceExtensionPdoFilter->Bay = bay;
  1883. if (bay)
  1884. {
  1885. DBCLASS_KdPrint((1,
  1886. "'**>> PDO is in Bay %d\n", bay));
  1887. DBCLASS_ASSERT(dbcContext != NULL);
  1888. if(dbcContext)
  1889. {
  1890. dbcContext->BayInformation[bay].DeviceFilterObject =
  1891. DeviceObject;
  1892. if (DeviceObject) {
  1893. // need to OK the start
  1894. PDRB drb;
  1895. drb = DbcExAllocatePool(NonPagedPool,
  1896. sizeof(struct _DRB_START_DEVICE_IN_BAY));
  1897. if (drb) {
  1898. drb->DrbHeader.Length = sizeof(struct _DRB_START_DEVICE_IN_BAY);
  1899. drb->DrbHeader.Function = DRB_FUNCTION_START_DEVICE_IN_BAY;
  1900. drb->DrbHeader.Flags = 0;
  1901. drb->DrbStartDeviceInBay.BayNumber = bay;
  1902. drb->DrbStartDeviceInBay.PdoDeviceObject1394 =
  1903. drb->DrbStartDeviceInBay.PdoDeviceObjectUsb = NULL;
  1904. if (IS_1394_DEVICE(deviceExtensionPdoFilter)) {
  1905. drb->DrbStartDeviceInBay.PdoDeviceObject1394 =
  1906. DeviceObject;
  1907. } else {
  1908. drb->DrbStartDeviceInBay.PdoDeviceObjectUsb =
  1909. DeviceObject;
  1910. }
  1911. // make the request
  1912. ntStatus = DBCLASS_SyncSubmitDrb(dbcContext,
  1913. dbcContext->TopOfStack,
  1914. drb);
  1915. } else {
  1916. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1917. }
  1918. }
  1919. }
  1920. // report that this PDO must be removed it the
  1921. // db controller is removed.
  1922. // note: we invalidate on the DBC PDO
  1923. // this should trigger a QBR for the device bay controller
  1924. } else {
  1925. DBCLASS_KdPrint((1,
  1926. "'**>> PDO is not for a device bay device\n"));
  1927. // detach and delete our MDO here if possible
  1928. // otherwise mark as ignore
  1929. BRK_ON_TRAP();
  1930. }
  1931. Irp->IoStatus.Status = ntStatus;
  1932. //
  1933. // detach and delete ourselves now
  1934. //
  1935. IoCompleteRequest(Irp,
  1936. IO_NO_INCREMENT);
  1937. }
  1938. break;
  1939. case IRP_MN_STOP_DEVICE:
  1940. case IRP_MN_REMOVE_DEVICE:
  1941. if (irpStack->MinorFunction == IRP_MN_STOP_DEVICE) {
  1942. DBCLASS_KdPrint((1,
  1943. "'(dbfilter)(device)(%x)IRP_MN_STOP_DEVICE\n",
  1944. deviceExtensionPdoFilter->PhysicalDeviceObject));
  1945. } else {
  1946. DBCLASS_KdPrint((1,
  1947. "'(dbfilter)(device)(%x)IRP_MN_REMOVE_DEVICE\n",
  1948. deviceExtensionPdoFilter->PhysicalDeviceObject));
  1949. }
  1950. // set the device filter object to NULL
  1951. // this will allow the dbc to eject the device if requested
  1952. {
  1953. USHORT bay = 0;
  1954. PDBC_CONTEXT dbcContext;
  1955. dbcContext = deviceExtensionPdoFilter->DbcContext;
  1956. // bay = DBCLASS_GetBayNumber(DeviceObject);
  1957. if (bay) {
  1958. PDRB drb;
  1959. DBCLASS_KdPrint((1,
  1960. "'(dbfilter)(device)REMOVE/STOP, Bay[%d]\n", bay));
  1961. //
  1962. // notify filter of a stop
  1963. // note that the filter may not veto the stop
  1964. //
  1965. drb = DbcExAllocatePool(NonPagedPool,
  1966. sizeof(struct _DRB_START_DEVICE_IN_BAY));
  1967. if (drb) {
  1968. drb->DrbHeader.Length = sizeof(struct _DRB_STOP_DEVICE_IN_BAY);
  1969. drb->DrbHeader.Function = DRB_FUNCTION_STOP_DEVICE_IN_BAY;
  1970. drb->DrbHeader.Flags = 0;
  1971. drb->DrbStartDeviceInBay.BayNumber = bay;
  1972. // make the request
  1973. ntStatus = DBCLASS_SyncSubmitDrb(dbcContext,
  1974. dbcContext->TopOfStack,
  1975. drb);
  1976. DBCLASS_KdPrint((1,
  1977. "'OK to stop <%x>\n", ntStatus));
  1978. DbcExFreePool(drb);
  1979. } else {
  1980. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1981. }
  1982. dbcContext->BayInformation[bay].DeviceFilterObject = NULL;
  1983. }
  1984. deviceExtensionPdoFilter->DbcContext = NULL;
  1985. }
  1986. break;
  1987. #if 0
  1988. case IRP_MN_QUERY_REMOVE_DEVICE:
  1989. case IRP_MN_QUERY_STOP_DEVICE:
  1990. {
  1991. USHORT bay;
  1992. bay = DBCLASS_GetBayNumber(DeviceObject);
  1993. DBCLASS_KdPrint((1,
  1994. "'(dbfilter)(device)(%x)Q_REMOVE/STOP, Bay[%d]\n",
  1995. deviceExtensionPdoFilter->PhysicalDeviceObject, bay));
  1996. }
  1997. break;
  1998. #endif
  1999. case IRP_MN_EJECT:
  2000. {
  2001. KEVENT event;
  2002. USHORT bay;
  2003. PDBC_CONTEXT dbcContext;
  2004. dbcContext = deviceExtensionPdoFilter->DbcContext;
  2005. DBCLASS_KdPrint((1, "'(dbfilter)(device)(%x)IRP_MN_EJECT, Bay[%d]\n",
  2006. deviceExtensionPdoFilter->PhysicalDeviceObject,
  2007. deviceExtensionPdoFilter->Bay));
  2008. *Handled = TRUE;
  2009. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2010. IoCopyCurrentIrpStackLocationToNext(Irp);
  2011. IoSetCompletionRoutine(Irp,
  2012. DBCLASS_DeferIrpCompletion,
  2013. &event,
  2014. TRUE,
  2015. TRUE,
  2016. TRUE);
  2017. //
  2018. // send the request down the stack before we eject
  2019. //
  2020. ntStatus = IoCallDriver(deviceExtensionPdoFilter->TopOfStackDeviceObject,
  2021. Irp);
  2022. if (ntStatus == STATUS_PENDING) {
  2023. // wait for irp to complete
  2024. // TEST_TRAP(); // first time we hit this
  2025. KeWaitForSingleObject(
  2026. &event,
  2027. Suspended,
  2028. KernelMode,
  2029. FALSE,
  2030. NULL);
  2031. }
  2032. IoDetachDevice(deviceExtensionPdoFilter->TopOfStackDeviceObject);
  2033. //
  2034. // ounce we eject the device will disappear from the
  2035. // native bus.
  2036. //
  2037. ntStatus = Irp->IoStatus.Status;
  2038. // TEST_TRAP();
  2039. // if (NT_SUCCESS(ntStatus)) {
  2040. bay = deviceExtensionPdoFilter->Bay;
  2041. if (bay) {
  2042. ntStatus = DBCLASS_EjectPdo(DeviceObject);
  2043. DBCLASS_ASSERT(dbcContext->BayInformation[bay].DeviceFilterObject
  2044. == NULL);
  2045. }
  2046. #if DBG
  2047. else {
  2048. DBCLASS_KdPrint((1, "'No Bay to EJECT (%x)\n", ntStatus));
  2049. // TEST_TRAP();
  2050. ntStatus = STATUS_SUCCESS;
  2051. }
  2052. #endif
  2053. // }
  2054. Irp->IoStatus.Status = STATUS_SUCCESS;
  2055. //
  2056. // delete ourselves now
  2057. //
  2058. IoCompleteRequest(Irp,
  2059. IO_NO_INCREMENT);
  2060. deviceExtensionPdoFilter->DbcContext = NULL;
  2061. // remove PDO from our internal list
  2062. DBCLASS_RemoveDevicePDOFromList(
  2063. deviceExtensionPdoFilter->PhysicalDeviceObject);
  2064. // free our device object
  2065. IoDeleteDevice (DeviceObject);
  2066. }
  2067. break;
  2068. case IRP_MN_SET_LOCK:
  2069. DBCLASS_KdPrint((1, "'(dbfilter)(device)IRP_MN_SET_LOCK, Bay[%x]\n",
  2070. deviceExtensionPdoFilter->Bay));
  2071. if (irpStack->Parameters.SetLock.Lock) {
  2072. DBCLASS_KdPrint((1, "'Request to LOCK device\n"));
  2073. DBCLASS_KdPrint((1, "'NOT ENABLING BAY ON LOCK!\n"));
  2074. LOGENTRY(LOG_MISC, 'LOCK', 0, 0, 0);
  2075. //ntStatus = DBCLASS_EnableDevice(DeviceObject);
  2076. } else {
  2077. //
  2078. // cancel the eject timeout
  2079. // if we get here no one vetoed the remove
  2080. //
  2081. DBCLASS_CancelEjectTimeout(DeviceObject);
  2082. DBCLASS_KdPrint((1, "' Request to UNLOCK device\n"));
  2083. LOGENTRY(LOG_MISC, 'ULOC', 0, 0, 0);
  2084. }
  2085. *Handled = TRUE;
  2086. IoCopyCurrentIrpStackLocationToNext(Irp);
  2087. // Set up a completion routine to handle marking the IRP.
  2088. IoSetCompletionRoutine(Irp,
  2089. DBCLASS_PdoSetLockComplete,
  2090. DeviceObject,
  2091. TRUE,
  2092. TRUE,
  2093. TRUE);
  2094. // Now Pass down the IRP
  2095. ntStatus = IoCallDriver(deviceExtensionPdoFilter->TopOfStackDeviceObject, Irp);
  2096. LOGENTRY(LOG_MISC, 'sLOC', ntStatus, 0, 0);
  2097. break;
  2098. case IRP_MN_CANCEL_REMOVE_DEVICE:
  2099. DBCLASS_KdPrint((1, "'(dbfilter)(device)IRP_MN_CANCEL_REMOVE_DEVICE\n"));
  2100. // TEST_TRAP();
  2101. break;
  2102. case IRP_MN_QUERY_CAPABILITIES:
  2103. DBCLASS_KdPrint((1,
  2104. "'(dbfilter)(device)(%x)IRP_MN_QUERY_CAPABILITIES\n",
  2105. deviceExtensionPdoFilter->PhysicalDeviceObject));
  2106. //
  2107. // Do this for all 1394 PDOs regardless of if they are device bay
  2108. // PDOs
  2109. // if (deviceExtensionPdoFilter->DbcContext &&
  2110. // deviceExtensionPdoFilter->Bay) {
  2111. *Handled = TRUE;
  2112. DBCLASS_KdPrint((1,"'>>QCAPS 1394/USB Device Bay PDO\n"));
  2113. IoCopyCurrentIrpStackLocationToNext(Irp);
  2114. // Set up a completion routine to handle marking the IRP.
  2115. IoSetCompletionRoutine(Irp,
  2116. DBCLASS_DevicePdoQCapsComplete,
  2117. DeviceObject,
  2118. TRUE,
  2119. TRUE,
  2120. TRUE);
  2121. // Now Pass down the IRP
  2122. ntStatus = IoCallDriver(deviceExtensionPdoFilter->TopOfStackDeviceObject, Irp);
  2123. // }
  2124. break;
  2125. } /* irpStack->MinorFunction */
  2126. break;
  2127. } /* irpStack->MajorFunction */
  2128. LOGENTRY(LOG_MISC, 'pdo<', 0, DeviceObject, ntStatus);
  2129. return ntStatus;
  2130. }
  2131. NTSTATUS
  2132. DBCLASS_SyncGetFdoType(
  2133. IN PDEVICE_OBJECT FilterDeviceObject,
  2134. IN PULONG FdoType
  2135. )
  2136. /*++
  2137. Routine Description:
  2138. This gets the bus type for this PDO (1394 or USB)
  2139. The goal of this function is to identify the stack the
  2140. filter is sitting on.
  2141. It is either:
  2142. 1. The USB root bus
  2143. 2. The 1394 HC
  2144. 3. A USB hub (bus)
  2145. 4. A USB Device
  2146. 5. A 1394 Device
  2147. The filter sits above the FDO (upperfilter) for the
  2148. respective PDO -- it is loaded as a class filter for
  2149. USB and 1394.
  2150. We do not need to identify USB devices and 1394 devices (4,5)
  2151. since we attach sapartely to these when we hook QBRelations.
  2152. Arguments:
  2153. DeviceObject - Physical DeviceObject for the bus.
  2154. FdoType - set to DB_FDO_USBHUB_FILTER or
  2155. DB_FDO_1394_FILTER or
  2156. 0 if bus type is neither
  2157. Return Value:
  2158. None.
  2159. --*/
  2160. {
  2161. PIO_STACK_LOCATION nextStack;
  2162. PIRP irp;
  2163. NTSTATUS ntStatus = STATUS_SUCCESS;
  2164. KEVENT event;
  2165. PPNP_BUS_INFORMATION busInfo;
  2166. PDEVICE_EXTENSION deviceExtension;
  2167. PDEVICE_OBJECT pdoDeviceObject;
  2168. PDEVICE_OBJECT topDeviceObject;
  2169. PULONG Tag;
  2170. PAGED_CODE();
  2171. deviceExtension = FilterDeviceObject->DeviceExtension;
  2172. pdoDeviceObject = deviceExtension->PhysicalDeviceObject;
  2173. topDeviceObject = deviceExtension->TopOfStackDeviceObject;
  2174. DBCLASS_KdPrint((1, "'*>Filter -> QUERY BUS TYPE filter do %x\n",
  2175. FilterDeviceObject));
  2176. DBCLASS_KdPrint((1, "'*>Filter -> QUERY BUS TYPE pdo %x\n",
  2177. pdoDeviceObject));
  2178. DBCLASS_KdPrint((1, "'*>Filter -> QUERY BUS TYPE top %x\n",
  2179. topDeviceObject));
  2180. irp = IoAllocateIrp(FilterDeviceObject->StackSize, FALSE);
  2181. if (!irp) {
  2182. TRAP(); //"failed to allocate Irp
  2183. return STATUS_INSUFFICIENT_RESOURCES;
  2184. }
  2185. nextStack = IoGetNextIrpStackLocation(irp);
  2186. ASSERT(nextStack != NULL);
  2187. nextStack->MajorFunction= IRP_MJ_PNP;
  2188. nextStack->MinorFunction= IRP_MN_QUERY_BUS_INFORMATION;
  2189. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  2190. irp->IoStatus.Information = 0;
  2191. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2192. IoSetCompletionRoutine(irp,
  2193. DBCLASS_DeferIrpCompletion,
  2194. &event,
  2195. TRUE,
  2196. TRUE,
  2197. TRUE);
  2198. ntStatus = IoCallDriver(FilterDeviceObject,
  2199. irp);
  2200. if (ntStatus == STATUS_PENDING) {
  2201. // wait for irp to complete
  2202. KeWaitForSingleObject(
  2203. &event,
  2204. Suspended,
  2205. KernelMode,
  2206. FALSE,
  2207. NULL);
  2208. }
  2209. busInfo = (PPNP_BUS_INFORMATION) irp->IoStatus.Information;
  2210. *FdoType = DB_FDO_BUS_UNKNOWN;
  2211. Tag = (PULONG) topDeviceObject->DeviceExtension;
  2212. // see if this is a 1394 bus
  2213. if(*Tag == PORT_EXTENSION_TAG)
  2214. {
  2215. DBCLASS_KdPrint((1, "'1394 Device\n"));
  2216. *FdoType = DB_FDO_1394_BUS;
  2217. return STATUS_SUCCESS;
  2218. }
  2219. DBCLASS_KdPrint((1, "'Tag (%08X) DevExt (%08X) DevObj(%08X)\n", *Tag, Tag, topDeviceObject));
  2220. DBCLASS_KdPrint((1, "'Status (%08X) Information (%08X)\n", irp->IoStatus.Status, irp->IoStatus.Information));
  2221. if (busInfo) {
  2222. #if DBG
  2223. DBCLASS_KdPrint((1, "'USB GUID\n"));
  2224. DBCLASS_KdPrintGuid(1, (PUCHAR) &GUID_BUS_TYPE_USB);
  2225. DBCLASS_KdPrint((1, "'RETURNED GUID\n"));
  2226. DBCLASS_KdPrintGuid(1, (PUCHAR) &busInfo->BusTypeGuid);
  2227. #endif
  2228. if (RtlCompareMemory(&busInfo->BusTypeGuid,
  2229. &GUID_BUS_TYPE_USB,
  2230. sizeof(GUID)) == sizeof(GUID)) {
  2231. *FdoType = DB_FDO_USBHUB_BUS;
  2232. DBCLASS_KdPrint((1, "'*>>Filter is for USB HUB\n"));
  2233. }
  2234. ExFreePool(busInfo);
  2235. } else {
  2236. DBCLASS_KdPrint((2, "'no busInfo returned\n"));
  2237. // this is either the 1394 or USB root bus
  2238. // send down an private IOCTL to see if it is USB
  2239. nextStack = IoGetNextIrpStackLocation(irp);
  2240. ASSERT(nextStack != NULL);
  2241. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  2242. nextStack->Parameters.DeviceIoControl.IoControlCode =
  2243. IOCTL_INTERNAL_USB_GET_BUSGUID_INFO;
  2244. irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
  2245. irp->IoStatus.Information = 0;
  2246. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2247. IoSetCompletionRoutine(irp,
  2248. DBCLASS_DeferIrpCompletion,
  2249. &event,
  2250. TRUE,
  2251. TRUE,
  2252. TRUE);
  2253. ntStatus = IoCallDriver(FilterDeviceObject,
  2254. irp);
  2255. if (ntStatus == STATUS_PENDING) {
  2256. // wait for irp to complete
  2257. KeWaitForSingleObject(
  2258. &event,
  2259. Suspended,
  2260. KernelMode,
  2261. FALSE,
  2262. NULL);
  2263. }
  2264. busInfo = (PPNP_BUS_INFORMATION) irp->IoStatus.Information;
  2265. DBCLASS_KdPrint((1, "'Status (%08X) Information (%08X)\n", irp->IoStatus.Status, irp->IoStatus.Information));
  2266. if (busInfo) {
  2267. #if DBG
  2268. DBCLASS_KdPrint((1, "'USB GUID\n"));
  2269. DBCLASS_KdPrintGuid(1, (PUCHAR) &GUID_BUS_TYPE_USB);
  2270. DBCLASS_KdPrint((1, "'RETURNED GUID\n"));
  2271. DBCLASS_KdPrintGuid(1, (PUCHAR) &busInfo->BusTypeGuid);
  2272. #endif
  2273. if (RtlCompareMemory(&busInfo->BusTypeGuid,
  2274. &GUID_BUS_TYPE_USB,
  2275. sizeof(GUID)) == sizeof(GUID)) {
  2276. *FdoType = DB_FDO_BUS_IGNORE;
  2277. DBCLASS_KdPrint((1, "'*>>Filter is for USB HC\n"));
  2278. }
  2279. ExFreePool(busInfo);
  2280. }
  2281. else{
  2282. // see if this is a 1394 bus
  2283. if(*Tag == PORT_EXTENSION_TAG){
  2284. DBCLASS_KdPrint((1, "'1394 Device\n"));
  2285. *FdoType = DB_FDO_1394_BUS;
  2286. }
  2287. }
  2288. }
  2289. ntStatus = STATUS_SUCCESS;
  2290. IoFreeIrp(irp);
  2291. #if DBG
  2292. switch(*FdoType) {
  2293. case DB_FDO_BUS_IGNORE:
  2294. DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_BUS_IGNORE\n"));
  2295. break;
  2296. case DB_FDO_BUS_UNKNOWN:
  2297. DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_BUS_UNKNOWN\n"));
  2298. break;
  2299. case DB_FDO_USB_DEVICE:
  2300. DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_USB_DEVICE\n"));
  2301. break;
  2302. case DB_FDO_USBHUB_BUS:
  2303. DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_USBHUB_BUS\n"));
  2304. break;
  2305. case DB_FDO_1394_BUS:
  2306. DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_1394_BUS\n"));
  2307. break;
  2308. case DB_FDO_1394_DEVICE:
  2309. DBCLASS_KdPrint((1, "'*>>>FdoType: DB_FDO_1394_DEVICE\n"));
  2310. break;
  2311. }
  2312. #endif
  2313. BRK_ON_TRAP();
  2314. return ntStatus;
  2315. }
  2316. NTSTATUS
  2317. DBCLASS_BusFilterDispatch(
  2318. PDEVICE_OBJECT DeviceObject,
  2319. PIRP Irp,
  2320. PBOOLEAN Handled
  2321. )
  2322. /*++
  2323. Routine Description:
  2324. Arguments:
  2325. DeviceObject - Device bay Filter FDO
  2326. Return Value:
  2327. NTSTATUS
  2328. --*/
  2329. {
  2330. PIO_STACK_LOCATION irpStack;
  2331. NTSTATUS ntStatus;
  2332. PDEVICE_EXTENSION deviceExtension;
  2333. deviceExtension = DeviceObject->DeviceExtension;
  2334. ntStatus = Irp->IoStatus.Status;
  2335. *Handled = FALSE;
  2336. irpStack = IoGetCurrentIrpStackLocation (Irp);
  2337. LOGENTRY(LOG_MISC, 'dbf>', 0, DeviceObject, Irp);
  2338. DBCLASS_KdPrint((1, "'(dbfilter)(bus)(%08X)IRP_MJ_ (%08X) IRP_MN_ (%08X)\n",
  2339. DeviceObject, irpStack->MajorFunction, irpStack->MinorFunction));
  2340. switch (irpStack->MajorFunction) {
  2341. case IRP_MJ_PNP:
  2342. switch (irpStack->MinorFunction) {
  2343. case IRP_MN_START_DEVICE:
  2344. // see if we can id the bus we are on
  2345. ntStatus =
  2346. DBCLASS_SyncGetFdoType(DeviceObject,
  2347. &deviceExtension->FdoType);
  2348. if (deviceExtension->FdoType == DB_FDO_USBHUB_BUS) {
  2349. // filter is sitting on a USB HUB
  2350. // null context indicates that this hub is not
  2351. // part of a DBC
  2352. deviceExtension->DbcContext = NULL;
  2353. if (DBCLASS_IsHubPartOfACPI_DBC(DeviceObject)) {
  2354. deviceExtension->DbcContext =
  2355. DBCLASS_FindControllerACPI(deviceExtension->DriverObject,
  2356. DeviceObject);
  2357. if (deviceExtension->DbcContext) {
  2358. USHORT bay;
  2359. // set the dbContext to point at this
  2360. // hub
  2361. // may need to handle multiple hubs
  2362. // currently we do not
  2363. DBCLASS_KdPrint(
  2364. (1, "'** Found ACPI DBC controller, linked to USBHUB\n"));
  2365. for (bay=1; bay <=NUMBER_OF_BAYS(deviceExtension->DbcContext); bay++) {
  2366. deviceExtension->DbcContext->BayInformation[bay].UsbHubPdo =
  2367. deviceExtension->PhysicalDeviceObject;
  2368. }
  2369. }
  2370. #if DBG
  2371. else {
  2372. DBCLASS_KdPrint(
  2373. (0, "'** Could not find an ACPI DBC controller\n"));
  2374. }
  2375. #endif
  2376. } else {
  2377. // hub is not part of DBC (for now)
  2378. // if is part of USB dbc we will need to
  2379. // wait for Q_BUS_RELATIONS
  2380. deviceExtension->DbcContext = NULL;
  2381. }
  2382. }
  2383. DBCLASS_KdPrint((1, "'(dbfilter)(bus)(%08X)IRP_MN_START_DEVICE\n", DeviceObject));
  2384. break;
  2385. case IRP_MN_STOP_DEVICE:
  2386. DBCLASS_KdPrint((1, "'(dbfilter)(bus)(%08X)IRP_MN_STOP_DEVICE\n", DeviceObject));
  2387. break;
  2388. case IRP_MN_REMOVE_DEVICE:
  2389. DBCLASS_KdPrint((1, "'(dbfilter)(bus)(%08X)IRP_MN_REMOVE_DEVICE\n", DeviceObject));
  2390. DBCLASS_RemoveBusFilterMDOFromList(DeviceObject);
  2391. IoDetachDevice(deviceExtension->TopOfStackDeviceObject);
  2392. IoDeleteDevice(DeviceObject);
  2393. break;
  2394. break;
  2395. } /* irpStack->MinorFunction */
  2396. } /* irpStack->MajorFunction */
  2397. LOGENTRY(LOG_MISC, 'dbf<', 0, DeviceObject, 0);
  2398. return ntStatus;
  2399. }
  2400. NTSTATUS
  2401. DBCLASS_GetRegistryKeyValueForPdo(
  2402. IN PDEVICE_OBJECT PhysicalDeviceObject,
  2403. IN BOOLEAN SoftwareBranch,
  2404. IN PWCHAR KeyNameString,
  2405. IN ULONG KeyNameStringLength,
  2406. IN PVOID Data,
  2407. IN ULONG DataLength
  2408. )
  2409. /*++
  2410. Routine Description:
  2411. Arguments:
  2412. Return Value:
  2413. --*/
  2414. {
  2415. NTSTATUS ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2416. UNICODE_STRING keyNameUnicodeString;
  2417. ULONG length;
  2418. PKEY_VALUE_FULL_INFORMATION fullInfo;
  2419. HANDLE handle;
  2420. PAGED_CODE();
  2421. if (SoftwareBranch) {
  2422. ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  2423. PLUGPLAY_REGKEY_DRIVER,
  2424. STANDARD_RIGHTS_ALL,
  2425. &handle);
  2426. } else {
  2427. ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  2428. PLUGPLAY_REGKEY_DEVICE,
  2429. STANDARD_RIGHTS_ALL,
  2430. &handle);
  2431. }
  2432. if (NT_SUCCESS(ntStatus)) {
  2433. RtlInitUnicodeString(&keyNameUnicodeString, KeyNameString);
  2434. length = sizeof(KEY_VALUE_FULL_INFORMATION) +
  2435. KeyNameStringLength + DataLength;
  2436. fullInfo = ExAllocatePoolWithTag(PagedPool, length, DBC_TAG);
  2437. DBCLASS_KdPrint((2,"' DBCLASS_GetRegistryKeyValueForPdo buffer = (%08X)\n", fullInfo));
  2438. if (fullInfo) {
  2439. ntStatus = ZwQueryValueKey(handle,
  2440. &keyNameUnicodeString,
  2441. KeyValueFullInformation,
  2442. fullInfo,
  2443. length,
  2444. &length);
  2445. if (NT_SUCCESS(ntStatus)){
  2446. DBCLASS_ASSERT(DataLength == fullInfo->DataLength);
  2447. RtlCopyMemory(Data, ((PUCHAR) fullInfo) + fullInfo->DataOffset, DataLength);
  2448. }
  2449. ExFreePool(fullInfo);
  2450. }
  2451. }
  2452. return ntStatus;
  2453. }
  2454. NTSTATUS
  2455. DBCLASS_SetRegistryKeyValueForPdo(
  2456. IN PDEVICE_OBJECT PhysicalDeviceObject,
  2457. IN BOOLEAN SoftwareBranch,
  2458. IN ULONG Type,
  2459. IN PWCHAR KeyNameString,
  2460. IN ULONG KeyNameStringLength,
  2461. IN PVOID Data,
  2462. IN ULONG DataLength
  2463. )
  2464. /*++
  2465. Routine Description:
  2466. Arguments:
  2467. Return Value:
  2468. --*/
  2469. {
  2470. NTSTATUS ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2471. UNICODE_STRING keyNameUnicodeString;
  2472. HANDLE handle;
  2473. PAGED_CODE();
  2474. if (SoftwareBranch) {
  2475. ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  2476. PLUGPLAY_REGKEY_DRIVER,
  2477. STANDARD_RIGHTS_ALL,
  2478. &handle);
  2479. } else {
  2480. ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  2481. PLUGPLAY_REGKEY_DEVICE,
  2482. STANDARD_RIGHTS_ALL,
  2483. &handle);
  2484. }
  2485. if (NT_SUCCESS(ntStatus)) {
  2486. RtlInitUnicodeString(&keyNameUnicodeString, KeyNameString);
  2487. ntStatus = ZwSetValueKey(handle,
  2488. &keyNameUnicodeString,
  2489. 0,
  2490. Type,
  2491. Data,
  2492. DataLength);
  2493. }
  2494. return ntStatus;
  2495. }
  2496. NTSTATUS
  2497. DBCLASS_DevicePdoQCapsComplete(
  2498. IN PDEVICE_OBJECT DeviceObject,
  2499. IN PIRP Irp,
  2500. IN PVOID Context
  2501. )
  2502. /*++
  2503. Routine Description:
  2504. Arguments:
  2505. DeviceObject - a pointer to the device object
  2506. Irp - a pointer to the irp
  2507. Context - NULL ptr
  2508. Return Value:
  2509. STATUS_SUCCESS
  2510. --*/
  2511. {
  2512. PDEVICE_OBJECT deviceFilterObject = Context;
  2513. PDEVICE_EXTENSION deviceExtension;
  2514. PDBC_CONTEXT dbcContext;
  2515. PDEVICE_CAPABILITIES deviceCapabilities;
  2516. PIO_STACK_LOCATION ioStack;
  2517. BOOLEAN linkDeviceObject = FALSE;
  2518. deviceExtension = deviceFilterObject->DeviceExtension;
  2519. dbcContext = deviceExtension->DbcContext;
  2520. ioStack = IoGetCurrentIrpStackLocation(Irp);
  2521. #if DBG
  2522. if (deviceExtension->Bay)
  2523. {
  2524. DBCLASS_KdPrint((1, "'>QCAPS cmplt 1394/USB PDO %x -- Bay[%d]\n",
  2525. deviceExtension->PhysicalDeviceObject,
  2526. deviceExtension->Bay));
  2527. }
  2528. else
  2529. {
  2530. DBCLASS_KdPrint((1, "'>QCAPS cmplt 1394/USB PDO %x -- No Bay\n",
  2531. deviceExtension->PhysicalDeviceObject));
  2532. }
  2533. #endif
  2534. deviceCapabilities = ioStack->
  2535. Parameters.DeviceCapabilities.Capabilities;
  2536. dbcContext = DBCLASS_ControllerList;
  2537. while(dbcContext)
  2538. {
  2539. if (DBCLASS_IsLinkDeviceObject(dbcContext,
  2540. deviceExtension->PhysicalDeviceObject))
  2541. {
  2542. DBCLASS_KdPrint((1, "'>>>1394 PDO is DBC Link, set suprise remove\n"));
  2543. linkDeviceObject = TRUE;
  2544. break;
  2545. }
  2546. dbcContext = dbcContext->Next;
  2547. }
  2548. if(linkDeviceObject)
  2549. {
  2550. // set surprise remove O.K. for device bay phy/link
  2551. deviceCapabilities->SurpriseRemovalOK = TRUE;
  2552. }
  2553. else
  2554. {
  2555. // indicate eject is supported for regular devices
  2556. deviceCapabilities->EjectSupported = 1;
  2557. deviceCapabilities->LockSupported = 1;
  2558. }
  2559. #if DBG
  2560. {
  2561. ULONG i;
  2562. DBCLASS_KdPrint((1, "'DEVICE PDO: Device Caps\n"));
  2563. DBCLASS_KdPrint(
  2564. (1, "'>>\n LockSupported = %d\n EjectSupported = %d \n Removable = %d \n DockDevice = %x\n",
  2565. deviceCapabilities->LockSupported,
  2566. deviceCapabilities->EjectSupported,
  2567. deviceCapabilities->Removable,
  2568. deviceCapabilities->DockDevice));
  2569. DBCLASS_KdPrint(
  2570. (1, "'>>\n UniqueId = %d\n SilentInstall = %d \n RawDeviceOK = %d \n SurpriseRemovalOK = %x\n",
  2571. deviceCapabilities->UniqueID,
  2572. deviceCapabilities->SilentInstall,
  2573. deviceCapabilities->RawDeviceOK,
  2574. deviceCapabilities->SurpriseRemovalOK));
  2575. DBCLASS_KdPrint((1, "'Device State Map:\n"));
  2576. for (i=0; i< PowerSystemHibernate; i++) {
  2577. DBCLASS_KdPrint((1, "'-->S%d = D%d\n", i-1,
  2578. deviceCapabilities->DeviceState[i]-1));
  2579. }
  2580. }
  2581. #endif
  2582. return STATUS_SUCCESS;
  2583. }
  2584. VOID
  2585. DBCLASS_EjectCancelWorker(
  2586. IN PVOID Context
  2587. )
  2588. /* ++
  2589. *
  2590. * Description:
  2591. *
  2592. * Arguments:
  2593. *
  2594. * Return:
  2595. *
  2596. * NTSTATUS
  2597. *
  2598. * -- */
  2599. {
  2600. PDBCLASS_WORKITEM workItem = Context;
  2601. PDBC_CONTEXT dbcContext = workItem->DbcContext;
  2602. PDBC_EJECT_TIMEOUT_CONTEXT timeoutContext =
  2603. workItem->TimeoutContext;
  2604. PDEVICE_EXTENSION deviceExtension;
  2605. LOGENTRY(LOG_MISC, 'eWK+', dbcContext, Context, timeoutContext);
  2606. DbcExFreePool(workItem);
  2607. // make sure the bay was mapped correctly before setting time out context
  2608. if(dbcContext->BayInformation[timeoutContext->BayNumber].DeviceFilterObject)
  2609. {
  2610. deviceExtension =
  2611. dbcContext->BayInformation[
  2612. timeoutContext->BayNumber].DeviceFilterObject->DeviceExtension;
  2613. deviceExtension->TimeoutContext = NULL;
  2614. }
  2615. DBCLASS_SyncBayFeatureRequest(dbcContext,
  2616. DRB_FUNCTION_SET_BAY_FEATURE,
  2617. timeoutContext->BayNumber,
  2618. REQUEST_DEVICE_ENABLED_STATE);
  2619. DBCLASS_DecrementIoCount(dbcContext);
  2620. DBCLASS_PostChangeRequest(dbcContext);
  2621. DbcExFreePool(timeoutContext);
  2622. LOGENTRY(LOG_MISC, 'eWK-', 0, Context, 0);
  2623. return;
  2624. }
  2625. VOID
  2626. DBCLASS_EjectTimeoutDPC(
  2627. IN PKDPC Dpc,
  2628. IN PVOID DeferredContext,
  2629. IN PVOID SystemArgument1,
  2630. IN PVOID SystemArgument2
  2631. )
  2632. /*++
  2633. Routine Description:
  2634. This routine runs at DISPATCH_LEVEL IRQL.
  2635. Arguments:
  2636. Dpc - Pointer to the DPC object.
  2637. DeferredContext -
  2638. SystemArgument1 - not used.
  2639. SystemArgument2 - not used.
  2640. Return Value:
  2641. None.
  2642. --*/
  2643. {
  2644. PDBC_EJECT_TIMEOUT_CONTEXT
  2645. timeoutContext = DeferredContext;
  2646. PDBCLASS_WORKITEM workItem;
  2647. LOGENTRY(LOG_MISC, 'EJCo', 0, 0, timeoutContext);
  2648. DBCLASS_KdPrint((1, "'**>Eject Timeout for Bay[%d]\n",
  2649. timeoutContext->BayNumber));
  2650. workItem = DbcExAllocatePool(NonPagedPool, sizeof(DBCLASS_WORKITEM));
  2651. if (workItem) {
  2652. LOGENTRY(LOG_MISC, 'qETM', 0,
  2653. workItem, 0);
  2654. workItem->Sig = DBC_WORKITEM_SIG;
  2655. workItem->DbcContext = timeoutContext->DbcContext;
  2656. workItem->TimeoutContext = timeoutContext;
  2657. //workItem->IrpStatus = Irp->IoStatus.Status;
  2658. ExInitializeWorkItem(&workItem->WorkQueueItem,
  2659. DBCLASS_EjectCancelWorker,
  2660. workItem);
  2661. DBCLASS_IncrementIoCount(timeoutContext->DbcContext);
  2662. ExQueueWorkItem(&workItem->WorkQueueItem,
  2663. DelayedWorkQueue);
  2664. } else {
  2665. TRAP();
  2666. DbcExFreePool(timeoutContext);
  2667. }
  2668. }
  2669. NTSTATUS
  2670. DBCLASS_SetEjectTimeout(
  2671. PDEVICE_OBJECT DeviceFilterMDO
  2672. )
  2673. /*++
  2674. Routine Description:
  2675. for a given device PDO set the eject timeout for it
  2676. Arguments:
  2677. Return Value:
  2678. None.
  2679. --*/
  2680. {
  2681. NTSTATUS ntStatus = STATUS_SUCCESS;
  2682. PDBC_EJECT_TIMEOUT_CONTEXT timeoutContext;
  2683. PDEVICE_EXTENSION deviceExtension;
  2684. timeoutContext = DbcExAllocatePool(NonPagedPool,
  2685. sizeof(DBC_EJECT_TIMEOUT_CONTEXT));
  2686. // extension for the device filter PDO
  2687. deviceExtension = DeviceFilterMDO->DeviceExtension;
  2688. if (timeoutContext) {
  2689. LARGE_INTEGER dueTime;
  2690. LOGENTRY(LOG_MISC, 'EJCs', deviceExtension->Bay, 0, timeoutContext);
  2691. timeoutContext->BayNumber =
  2692. deviceExtension->Bay;
  2693. timeoutContext->DbcContext =
  2694. deviceExtension->DbcContext;
  2695. DBCLASS_KdPrint((1, "'**>Set Eject Timeout for Bay[%d]\n",
  2696. timeoutContext->BayNumber));
  2697. // DBCLASS_ASSERT(deviceExtension->TimeoutContext == NULL);
  2698. deviceExtension->TimeoutContext =
  2699. timeoutContext;
  2700. KeInitializeTimer(&timeoutContext->TimeoutTimer);
  2701. KeInitializeDpc(&timeoutContext->TimeoutDpc,
  2702. DBCLASS_EjectTimeoutDPC,
  2703. timeoutContext);
  2704. dueTime.QuadPart = -10000 * DBCLASS_EJECT_TIMEOUT;
  2705. KeSetTimer(&timeoutContext->TimeoutTimer,
  2706. dueTime,
  2707. &timeoutContext->TimeoutDpc);
  2708. } else {
  2709. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2710. }
  2711. return ntStatus;
  2712. }
  2713. NTSTATUS
  2714. DBCLASS_CancelEjectTimeout(
  2715. PDEVICE_OBJECT DeviceFilterMDO
  2716. )
  2717. /*++
  2718. Routine Description:
  2719. for a given device PDO set the eject timeout for it
  2720. Arguments:
  2721. Return Value:
  2722. None.
  2723. --*/
  2724. {
  2725. PDBC_EJECT_TIMEOUT_CONTEXT timeoutContext;
  2726. NTSTATUS ntStatus = STATUS_UNSUCCESSFUL;
  2727. PDEVICE_EXTENSION deviceExtension;
  2728. deviceExtension = DeviceFilterMDO->DeviceExtension;
  2729. timeoutContext = deviceExtension->TimeoutContext;
  2730. deviceExtension->TimeoutContext = NULL;
  2731. LOGENTRY(LOG_MISC, 'EJCc', 0, 0, timeoutContext);
  2732. if (timeoutContext) {
  2733. if (KeCancelTimer(&timeoutContext->TimeoutTimer)) {
  2734. // timer was pulled out of the queue
  2735. DBCLASS_KdPrint((1, "'**>Canceled Eject Timeout for Bay[%d]\n",
  2736. timeoutContext->BayNumber));
  2737. LOGENTRY(LOG_MISC, 'EJCk', 0, 0, timeoutContext);
  2738. DbcExFreePool(timeoutContext);
  2739. }
  2740. } else {
  2741. DBCLASS_KdPrint((1, "'**>Cancel Eject Timeout, No Timeout\n"));
  2742. }
  2743. ntStatus = STATUS_SUCCESS;
  2744. return ntStatus;
  2745. }
  2746. NTSTATUS
  2747. DBCLASS_CheckPhyLink(
  2748. PDEVICE_OBJECT DevicePdo1394
  2749. )
  2750. /*++
  2751. Routine Description:
  2752. Given a 1394 PDO see if it is the phy/link for any of our DBC
  2753. controllers
  2754. Arguments:
  2755. Return Value:
  2756. STATUS_SUCCESS
  2757. --*/
  2758. {
  2759. PDBC_CONTEXT dbcContext;
  2760. dbcContext = DBCLASS_ControllerList;
  2761. while (dbcContext) {
  2762. LOGENTRY(LOG_MISC, 'FINl', dbcContext, 0, DevicePdo1394);
  2763. if (DBCLASS_IsLinkDeviceObject(dbcContext, DevicePdo1394))
  2764. {
  2765. dbcContext->LinkDeviceObject = DevicePdo1394;
  2766. DBCLASS_KdPrint((1, "'>PDO is DBC Link \n"));
  2767. DBCLASS_KdPrint((1, "'>LinkDevObj (%08x) \n", dbcContext->LinkDeviceObject));
  2768. }
  2769. dbcContext = dbcContext->Next;
  2770. }
  2771. return STATUS_SUCCESS;
  2772. }
  2773. NTSTATUS
  2774. DBCLASS_GetConfigValue(
  2775. IN PWSTR ValueName,
  2776. IN ULONG ValueType,
  2777. IN PVOID ValueData,
  2778. IN ULONG ValueLength,
  2779. IN PVOID Context,
  2780. IN PVOID EntryContext
  2781. )
  2782. /*++
  2783. Routine Description:
  2784. This routine is a callback routine for RtlQueryRegistryValues
  2785. It is called for each entry in the Parameters
  2786. node to set the config values. The table is set up
  2787. so that this function will be called with correct default
  2788. values for keys that are not present.
  2789. Arguments:
  2790. ValueName - The name of the value (ignored).
  2791. ValueType - The type of the value
  2792. ValueData - The data for the value.
  2793. ValueLength - The length of ValueData.
  2794. Context - A pointer to the CONFIG structure.
  2795. EntryContext - The index in Config->Parameters to save the value.
  2796. Return Value:
  2797. --*/
  2798. {
  2799. NTSTATUS ntStatus = STATUS_SUCCESS;
  2800. DBCLASS_KdPrint((2, "'Type (%08X), Length (%08X)\n", ValueType, ValueLength));
  2801. switch (ValueType) {
  2802. case REG_DWORD:
  2803. *(PVOID*)EntryContext = *(PVOID*)ValueData;
  2804. break;
  2805. case REG_BINARY:
  2806. // we are only set up to read a byte
  2807. RtlCopyMemory(EntryContext, ValueData, 1);
  2808. break;
  2809. default:
  2810. ntStatus = STATUS_INVALID_PARAMETER;
  2811. }
  2812. return ntStatus;
  2813. }
  2814. #if 0
  2815. NTSTATUS
  2816. DBCLASS_GetClassGlobalRegistryParameters(
  2817. )
  2818. /*++
  2819. Routine Description:
  2820. Arguments:
  2821. Return Value:
  2822. --*/
  2823. {
  2824. NTSTATUS ntStatus;
  2825. RTL_QUERY_REGISTRY_TABLE QueryTable[2];
  2826. PWCHAR usb = L"class\\dbc";
  2827. PAGED_CODE();
  2828. //
  2829. // Set up QueryTable to do the following:
  2830. //
  2831. // spew level
  2832. QueryTable[0].QueryRoutine = DBCLASS_GetConfigValue;
  2833. QueryTable[0].Flags = 0;
  2834. QueryTable[0].Name = ACPI_HUB_KEY;
  2835. QueryTable[0].EntryContext = &DBCLASS_AcpiDBCHubParentPort;
  2836. QueryTable[0].DefaultType = REG_DWORD;
  2837. QueryTable[0].DefaultData = &DBCLASS_AcpiDBCHubParentPort;
  2838. QueryTable[0].DefaultLength = sizeof(DBCLASS_AcpiDBCHubParentPort);
  2839. //
  2840. // Stop
  2841. //
  2842. QueryTable[1].QueryRoutine = NULL;
  2843. QueryTable[1].Flags = 0;
  2844. QueryTable[1].Name = NULL;
  2845. ntStatus = RtlQueryRegistryValues(
  2846. RTL_REGISTRY_SERVICES,
  2847. usb,
  2848. QueryTable, // QueryTable
  2849. NULL, // Context
  2850. NULL); // Environment
  2851. if (NT_SUCCESS(ntStatus)) {
  2852. DBCLASS_KdPrint((1, "'AcpiDBCHubParentPort Set: (%d)\n",
  2853. DBCLASS_AcpiDBCHubParentPort));
  2854. }
  2855. if ( STATUS_OBJECT_NAME_NOT_FOUND == ntStatus ) {
  2856. ntStatus = STATUS_SUCCESS;
  2857. }
  2858. return ntStatus;
  2859. }
  2860. #endif
  2861. NTSTATUS
  2862. DBCLASS_EjectBayComplete(
  2863. IN PDEVICE_OBJECT DeviceObject,
  2864. IN PIRP Irp,
  2865. IN PVOID Context
  2866. )
  2867. /*++
  2868. Routine Description:
  2869. Arguments:
  2870. DeviceObject - a pointer to the device object
  2871. Irp - a pointer to the irp
  2872. Context - NULL ptr
  2873. Return Value:
  2874. STATUS_SUCCESS
  2875. --*/
  2876. {
  2877. PEJECT_CONTEXT ejectContext = Context;
  2878. PDEVICE_EXTENSION deviceExtension;
  2879. PDBC_CONTEXT dbcContext;
  2880. USHORT bay;
  2881. NTSTATUS ntStatus;
  2882. bay = ejectContext->Bay;
  2883. dbcContext = ejectContext->DbcContext;
  2884. DbcExFreePool(ejectContext);
  2885. ntStatus = Irp->IoStatus.Status;
  2886. DBCLASS_KdPrint((0, "'>>Request Device Eject BAY[%d] complete Status (%08X)\n",
  2887. bay, ntStatus));
  2888. // set a timeout for the eject
  2889. // if the request failed the timeout will kick in and
  2890. // re-post the chage request for us
  2891. if (NT_SUCCESS(ntStatus)) {
  2892. // check and see if the bay is locked
  2893. if((!dbcContext->SubsystemDescriptor.bmAttributes.HasSecurityLock) ||
  2894. (dbcContext->SubsystemDescriptor.bmAttributes.HasSecurityLock &&
  2895. !dbcContext->BayInformation[bay].LastBayStatus.SecurityLockEngaged))
  2896. {
  2897. #if 0
  2898. if (dbcContext->BayInformation[bay].DeviceFilterObject) {
  2899. DBCLASS_ASSERT(dbcContext->BayInformation[bay].DeviceFilterObject);
  2900. DBCLASS_SetEjectTimeout(dbcContext->BayInformation[bay].DeviceFilterObject);
  2901. deviceExtension =
  2902. dbcContext->BayInformation[bay].DeviceFilterObject->DeviceExtension;
  2903. DBCLASS_KdPrint((0, "'>>>Ejecting Filter %x PDO %x\n",
  2904. dbcContext->BayInformation[bay].DeviceFilterObject,
  2905. deviceExtension->PhysicalDeviceObject));
  2906. LOGENTRY(LOG_MISC, 'EJE+', 0, 0, deviceExtension->PhysicalDeviceObject);
  2907. IoRequestDeviceEject(deviceExtension->PhysicalDeviceObject);
  2908. } else {
  2909. #endif
  2910. DBCLASS_KdPrint((0, "'>>>No PDO for this bay\n"));
  2911. #if 0
  2912. if (dbcContext->BusFilterMdo1394 != NULL ||
  2913. dbcContext->BusFilterMdoUSB != NULL)
  2914. #endif
  2915. {
  2916. PDRB drb;
  2917. //
  2918. // notify filter of a stop
  2919. // note that the filter may not veto the stop
  2920. //
  2921. drb = DbcExAllocatePool(NonPagedPool,
  2922. sizeof(struct _DRB_START_DEVICE_IN_BAY));
  2923. if (drb)
  2924. {
  2925. drb->DrbHeader.Length = sizeof(struct _DRB_STOP_DEVICE_IN_BAY);
  2926. drb->DrbHeader.Function = DRB_FUNCTION_STOP_DEVICE_IN_BAY;
  2927. drb->DrbHeader.Flags = 0;
  2928. drb->DrbStartDeviceInBay.BayNumber = bay;
  2929. // make the request
  2930. ntStatus = DBCLASS_SyncSubmitDrb(dbcContext,
  2931. dbcContext->TopOfStack,
  2932. drb);
  2933. DbcExFreePool(drb);
  2934. }
  2935. // just pop out the device --
  2936. // surprise remove is OK at this point
  2937. DBCLASS_EjectBay(dbcContext, bay);
  2938. DBCLASS_PostChangeRequest(dbcContext);
  2939. }
  2940. #if 0
  2941. #if DBG
  2942. else {
  2943. DBCLASS_KdPrint((0, "'>>Filter has not registered\n"));
  2944. TRAP();
  2945. }
  2946. #endif
  2947. #endif
  2948. #if 0
  2949. }
  2950. #endif
  2951. }
  2952. }
  2953. IoFreeIrp(Irp);
  2954. return STATUS_MORE_PROCESSING_REQUIRED;
  2955. }