Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3500 lines
107 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. PARENT.C
  5. Abstract:
  6. This module contains code that manages composite devices on USB.
  7. Author:
  8. jdunn
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. --*/
  14. #include <wdm.h>
  15. #ifdef WMI_SUPPORT
  16. #include <wmilib.h>
  17. #endif /* WMI_SUPPORT */
  18. #include <wdmguid.h>
  19. #include "usbhub.h"
  20. #define COMP_RESET_TIMEOUT 3000 // Timeout in ms (3 sec)
  21. #ifdef PAGE_CODE
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGE, USBH_ParentFdoStopDevice)
  24. #pragma alloc_text(PAGE, USBH_ParentFdoRemoveDevice)
  25. #pragma alloc_text(PAGE, UsbhParentFdoCleanup)
  26. #pragma alloc_text(PAGE, USBH_ParentQueryBusRelations)
  27. #pragma alloc_text(PAGE, USBH_ParentFdoStartDevice)
  28. #pragma alloc_text(PAGE, USBH_FunctionPdoQueryId)
  29. #pragma alloc_text(PAGE, USBH_FunctionPdoQueryDeviceText)
  30. #pragma alloc_text(PAGE, USBH_FunctionPdoPnP)
  31. #pragma alloc_text(PAGE, USBH_ParentCreateFunctionList)
  32. #endif
  33. #endif
  34. VOID
  35. UsbhParentFdoCleanup(
  36. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent
  37. )
  38. /* ++
  39. *
  40. * Description:
  41. *
  42. * This routine is called to shut down the hub.
  43. *
  44. * Argument:
  45. *
  46. * Return:
  47. *
  48. * STATUS_SUCCESS
  49. *
  50. * -- */
  51. {
  52. PDEVICE_OBJECT deviceObject;
  53. PSINGLE_LIST_ENTRY listEntry;
  54. ULONG i;
  55. PDEVICE_EXTENSION_FUNCTION deviceExtensionFunction;
  56. KIRQL irql;
  57. PIRP wWIrp;
  58. USBH_KdPrint((2,"'UsbhParentFdoCleanup Fdo extension %x\n",
  59. DeviceExtensionParent));
  60. LOGENTRY(LOG_PNP, "pfdc", DeviceExtensionParent,
  61. DeviceExtensionParent->PendingWakeIrp,
  62. 0);
  63. //
  64. // dump our wake request
  65. //
  66. IoAcquireCancelSpinLock(&irql);
  67. if (DeviceExtensionParent->PendingWakeIrp) {
  68. USBH_ASSERT(DeviceExtensionParent->ParentFlags & HUBFLAG_PENDING_WAKE_IRP);
  69. wWIrp = DeviceExtensionParent->PendingWakeIrp;
  70. IoSetCancelRoutine(wWIrp, NULL);
  71. DeviceExtensionParent->PendingWakeIrp = NULL;
  72. IoReleaseCancelSpinLock(irql);
  73. IoCancelIrp(wWIrp);
  74. } else {
  75. IoReleaseCancelSpinLock(irql);
  76. }
  77. if (DeviceExtensionParent->ConfigurationDescriptor) {
  78. UsbhExFreePool(DeviceExtensionParent->ConfigurationDescriptor);
  79. DeviceExtensionParent->ConfigurationDescriptor = NULL;
  80. }
  81. USBH_ParentCompleteFunctionWakeIrps (DeviceExtensionParent,
  82. STATUS_DELETE_PENDING);
  83. do {
  84. listEntry = PopEntryList(&DeviceExtensionParent->FunctionList);
  85. LOGENTRY(LOG_PNP, "dFU1", 0, listEntry, 0);
  86. if (listEntry != NULL) {
  87. deviceExtensionFunction =
  88. CONTAINING_RECORD(listEntry,
  89. DEVICE_EXTENSION_FUNCTION,
  90. ListEntry);
  91. ASSERT_FUNCTION(deviceExtensionFunction);
  92. LOGENTRY(LOG_PNP, "dFUN", deviceExtensionFunction, 0, 0);
  93. for (i=0; i< deviceExtensionFunction->InterfaceCount; i++) {
  94. LOGENTRY(LOG_PNP, "dFUi", deviceExtensionFunction,
  95. deviceExtensionFunction->FunctionInterfaceList[i].InterfaceInformation,
  96. 0);
  97. UsbhExFreePool(deviceExtensionFunction->FunctionInterfaceList[i].InterfaceInformation);
  98. }
  99. //
  100. // Sometimes the FunctionPhysicalDeviceObject == deviceExtensionFunction.
  101. // In other words the device object about to be deleted is the
  102. // same one being used. So do not use the extions after it has been
  103. // deleted.
  104. //
  105. deviceObject = deviceExtensionFunction->FunctionPhysicalDeviceObject;
  106. deviceExtensionFunction->FunctionPhysicalDeviceObject = NULL;
  107. LOGENTRY(LOG_PNP, "dFUo", deviceExtensionFunction,
  108. deviceObject,
  109. 0);
  110. IoDeleteDevice(deviceObject);
  111. }
  112. } while (listEntry != NULL);
  113. DeviceExtensionParent->NeedCleanup = FALSE;
  114. USBH_KdPrint((2,"'UsbhParentFdoCleanup done Fdo extension %x\n",
  115. DeviceExtensionParent));
  116. return;
  117. }
  118. NTSTATUS
  119. USBH_ParentFdoRemoveDevice(
  120. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent,
  121. IN PIRP Irp
  122. )
  123. /* ++
  124. *
  125. * Description:
  126. *
  127. * Argument:
  128. *
  129. * Return:
  130. *
  131. * STATUS_SUCCESS
  132. *
  133. * -- */
  134. {
  135. PDEVICE_OBJECT deviceObject;
  136. NTSTATUS ntStatus;
  137. PAGED_CODE();
  138. deviceObject = DeviceExtensionParent->FunctionalDeviceObject;
  139. USBH_KdPrint((2,"'ParentFdoRemoveDevice Fdo %x\n", deviceObject));
  140. DeviceExtensionParent->ParentFlags |= HUBFLAG_DEVICE_STOPPING;
  141. //
  142. // see if we need cleanup
  143. //
  144. if (DeviceExtensionParent->NeedCleanup) {
  145. UsbhParentFdoCleanup(DeviceExtensionParent);
  146. }
  147. #ifdef WMI_SUPPORT
  148. // de-register with WMI
  149. IoWMIRegistrationControl(deviceObject,
  150. WMIREG_ACTION_DEREGISTER);
  151. #endif
  152. //
  153. // And we need to pass this message on to lower level driver
  154. //
  155. // IrpAssert: Set IRP status before passing on.
  156. Irp->IoStatus.Status = STATUS_SUCCESS;
  157. ntStatus = USBH_PassIrp(Irp, DeviceExtensionParent->TopOfStackDeviceObject);
  158. //
  159. // Detach FDO from PDO
  160. //
  161. IoDetachDevice(DeviceExtensionParent->TopOfStackDeviceObject);
  162. // delete FDO of the parent
  163. IoDeleteDevice(deviceObject);
  164. return ntStatus;
  165. }
  166. NTSTATUS
  167. USBH_ParentCreateFunctionList(
  168. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent,
  169. IN PUSBD_INTERFACE_LIST_ENTRY InterfaceList,
  170. IN PURB Urb
  171. )
  172. /* ++
  173. *
  174. * Description:
  175. *
  176. * Argument:
  177. *
  178. * Return:
  179. *
  180. * STATUS_SUCCESS
  181. *
  182. * -- */
  183. {
  184. PDEVICE_OBJECT deviceObject;
  185. PUSBD_INTERFACE_LIST_ENTRY interfaceList, tmp, baseInterface;
  186. PDEVICE_EXTENSION_FUNCTION deviceExtensionFunction;
  187. ULONG nameIndex = 0, numberOfInterfacesThisFunction, k;
  188. NTSTATUS ntStatus = STATUS_SUCCESS;
  189. PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
  190. UNICODE_STRING uniqueIdUnicodeString;
  191. PAGED_CODE();
  192. DeviceExtensionParent->FunctionCount = 0;
  193. tmp = interfaceList = InterfaceList;
  194. DeviceExtensionParent->FunctionList.Next = NULL;
  195. configurationDescriptor = DeviceExtensionParent->ConfigurationDescriptor;
  196. for (;;) {
  197. nameIndex = 0;
  198. if (interfaceList->InterfaceDescriptor) {
  199. //
  200. // interfaceList contains all the interfaces on the device
  201. // in sequential order.
  202. //
  203. //
  204. // We will create nodes based on the following criteria:
  205. //
  206. // For each interface create one function (node)
  207. //
  208. //
  209. // For Each group of class/subclass interface create one
  210. // node iff the class is audio
  211. //
  212. // This means:
  213. // **
  214. // Class=1
  215. // subclass=0
  216. // Class=1
  217. // subclass=0
  218. // creates 2 nodes
  219. //
  220. // ** we will only do this for the audio class
  221. // **
  222. // Class=1
  223. // subclass=0
  224. // Class=2
  225. // subclass=1
  226. // creates 2 nodes
  227. //
  228. // **
  229. // Class=1
  230. // subclass=0
  231. // Class=1
  232. // subclass=1
  233. // creates 1 node
  234. //
  235. // Create the node to represent this device
  236. //
  237. do {
  238. if (NT_SUCCESS(ntStatus)) {
  239. ntStatus = IoCreateDevice(UsbhDriverObject, // Driver Object
  240. sizeof(DEVICE_EXTENSION_FUNCTION), // Device Extension size
  241. NULL, // Device name
  242. FILE_DEVICE_UNKNOWN, // Device Type
  243. // should look device
  244. // class
  245. FILE_AUTOGENERATED_DEVICE_NAME,// Device Chars
  246. FALSE, // Exclusive
  247. &deviceObject); // Bus Device Object
  248. }
  249. nameIndex++;
  250. } while (ntStatus == STATUS_OBJECT_NAME_COLLISION);
  251. if (!NT_SUCCESS(ntStatus)) {
  252. USBH_KdTrap(("IoCreateDevice for function fail\n"));
  253. USBH_ASSERT(deviceObject == NULL);
  254. deviceExtensionFunction = NULL;
  255. // bail on whole node
  256. break;
  257. }
  258. deviceObject->StackSize =
  259. DeviceExtensionParent->TopOfStackDeviceObject->StackSize + 1;
  260. USBH_KdPrint((2,"'CreateFunctionPdo StackSize=%d\n", deviceObject->StackSize));
  261. deviceExtensionFunction =
  262. (PDEVICE_EXTENSION_FUNCTION) deviceObject->DeviceExtension;
  263. RtlFillMemory(deviceExtensionFunction,
  264. sizeof(PDEVICE_EXTENSION_FUNCTION),
  265. 0);
  266. //
  267. // initialize this function extension
  268. //
  269. deviceExtensionFunction->ConfigurationHandle =
  270. Urb->UrbSelectConfiguration.ConfigurationHandle;
  271. deviceExtensionFunction->FunctionPhysicalDeviceObject =
  272. deviceObject;
  273. deviceExtensionFunction->ExtensionType =
  274. EXTENSION_TYPE_FUNCTION;
  275. deviceExtensionFunction->DeviceExtensionParent =
  276. DeviceExtensionParent;
  277. //
  278. // remember the base interface for this function
  279. //
  280. baseInterface = interfaceList;
  281. USBH_KdPrint((2,"baseInterface = %x config descr = %x\n",
  282. baseInterface, configurationDescriptor));
  283. //
  284. // now compile the group of interfaces that will make up
  285. // this function.
  286. //
  287. {
  288. PUSBD_INTERFACE_LIST_ENTRY interface;
  289. interface = interfaceList;
  290. interface++;
  291. numberOfInterfacesThisFunction = 1;
  292. while (interface->InterfaceDescriptor) {
  293. if ((interface->InterfaceDescriptor->bInterfaceClass !=
  294. baseInterface->InterfaceDescriptor->bInterfaceClass) ||
  295. (interface->InterfaceDescriptor->bInterfaceSubClass ==
  296. baseInterface->InterfaceDescriptor->bInterfaceSubClass) ||
  297. (interface->InterfaceDescriptor->bInterfaceClass !=
  298. USB_DEVICE_CLASS_AUDIO)) {
  299. break;
  300. }
  301. numberOfInterfacesThisFunction++;
  302. interface++;
  303. }
  304. USBH_ASSERT(numberOfInterfacesThisFunction <=
  305. USBH_MAX_FUNCTION_INTERFACES);
  306. }
  307. //
  308. // now we know how many interfaces we are dealing with
  309. //
  310. deviceExtensionFunction->InterfaceCount = 0;
  311. for (k=0; k< numberOfInterfacesThisFunction; k++) {
  312. PFUNCTION_INTERFACE functionInterface;
  313. functionInterface =
  314. &deviceExtensionFunction->FunctionInterfaceList[deviceExtensionFunction->InterfaceCount];
  315. if (functionInterface->InterfaceInformation =
  316. UsbhExAllocatePool(NonPagedPool,
  317. interfaceList->Interface->Length)) {
  318. RtlCopyMemory(functionInterface->InterfaceInformation,
  319. interfaceList->Interface,
  320. interfaceList->Interface->Length);
  321. functionInterface->InterfaceDescriptor
  322. = interfaceList->InterfaceDescriptor;
  323. //
  324. // calculate the length of this interface now
  325. //
  326. // the length of the descriptor is the difference
  327. // between the start of this interface and the
  328. // start of the next one.
  329. //
  330. {
  331. PUCHAR start, end;
  332. PUSBD_INTERFACE_LIST_ENTRY tmp;
  333. tmp = interfaceList;
  334. tmp++;
  335. end = (PUCHAR) configurationDescriptor;
  336. end += configurationDescriptor->wTotalLength;
  337. start = (PUCHAR) functionInterface->InterfaceDescriptor;
  338. if (tmp->InterfaceDescriptor) {
  339. end = (PUCHAR) tmp->InterfaceDescriptor;
  340. }
  341. USBH_ASSERT(end > start);
  342. functionInterface->InterfaceDescriptorLength =
  343. (ULONG)(end - start);
  344. }
  345. USBH_KdPrint((2,"functionInterface = %x\n",
  346. functionInterface));
  347. deviceExtensionFunction->InterfaceCount++;
  348. } else {
  349. USBH_KdTrap(("failure to create function interface\n"));
  350. }
  351. interfaceList++;
  352. }
  353. //
  354. // use the interface number from our 'base' interface
  355. // for the unique id
  356. //
  357. RtlInitUnicodeString(&uniqueIdUnicodeString,
  358. &deviceExtensionFunction->UniqueIdString[0]);
  359. uniqueIdUnicodeString.MaximumLength =
  360. sizeof(deviceExtensionFunction->UniqueIdString);
  361. ntStatus = RtlIntegerToUnicodeString(
  362. (ULONG) baseInterface->InterfaceDescriptor->bInterfaceNumber,
  363. 10,
  364. &uniqueIdUnicodeString);
  365. //
  366. // add this function to the list
  367. //
  368. DeviceExtensionParent->FunctionCount++;
  369. PushEntryList(&DeviceExtensionParent->FunctionList,
  370. &deviceExtensionFunction->ListEntry);
  371. USBH_KdPrint((2,"deviceExtensionFunction = %x\n", deviceExtensionFunction));
  372. deviceObject->Flags |= DO_POWER_PAGABLE;
  373. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  374. } else {
  375. // end of interface list
  376. break;
  377. }
  378. } /* for */
  379. return STATUS_SUCCESS;
  380. }
  381. NTSTATUS
  382. USBH_ParentFdoStopDevice(
  383. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent,
  384. IN PIRP Irp
  385. )
  386. /* ++
  387. *
  388. * Description:
  389. *
  390. * Argument:
  391. *
  392. * Return:
  393. *
  394. * STATUS_SUCCESS
  395. *
  396. * -- */
  397. {
  398. PDEVICE_OBJECT deviceObject;
  399. NTSTATUS ntStatus;
  400. PAGED_CODE();
  401. deviceObject = DeviceExtensionParent->FunctionalDeviceObject;
  402. USBH_KdPrint((2,"'ParentFdoStopDevice Fdo %x\n", deviceObject));
  403. //
  404. // set the device to the unconfigured state
  405. //
  406. ntStatus = USBH_CloseConfiguration((PDEVICE_EXTENSION_FDO) DeviceExtensionParent);
  407. //
  408. // And we need to pass this message on to lower level driver
  409. //
  410. ntStatus = USBH_PassIrp(Irp, DeviceExtensionParent->TopOfStackDeviceObject);
  411. return ntStatus;
  412. }
  413. NTSTATUS
  414. USBH_ParentFdoStartDevice(
  415. IN OUT PDEVICE_EXTENSION_PARENT DeviceExtensionParent,
  416. IN PIRP Irp,
  417. IN BOOLEAN NewList
  418. )
  419. /* ++ Description:
  420. *
  421. * Argument:
  422. *
  423. * Return:
  424. *
  425. * STATUS_SUCCESS - if successful STATUS_UNSUCCESSFUL - otherwise
  426. *
  427. * -- */
  428. {
  429. NTSTATUS ntStatus;
  430. PURB urb = NULL;
  431. PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
  432. PUSBD_INTERFACE_LIST_ENTRY interfaceList, tmp;
  433. LONG numberOfInterfaces, interfaceNumber, i;
  434. PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
  435. ULONG nameIndex = 0;
  436. DEVICE_CAPABILITIES deviceCapabilities;
  437. PAGED_CODE();
  438. USBH_KdPrint((2,"'Enter Parent StartDevice\n"));
  439. USBH_ASSERT(EXTENSION_TYPE_PARENT == DeviceExtensionParent->ExtensionType);
  440. KeInitializeEvent(&DeviceExtensionParent->PnpStartEvent, NotificationEvent, FALSE);
  441. USBH_KdPrint((2,"'Set PnPIrp Completion Routine\n"));
  442. IoCopyCurrentIrpStackLocationToNext(Irp);
  443. IoSetCompletionRoutine(Irp,
  444. USBH_PnPIrp_Complete,
  445. // always pass FDO to completion routine
  446. DeviceExtensionParent,
  447. TRUE,
  448. TRUE,
  449. TRUE);
  450. IoCallDriver(DeviceExtensionParent->TopOfStackDeviceObject,
  451. Irp);
  452. KeWaitForSingleObject(&DeviceExtensionParent->PnpStartEvent,
  453. Suspended,
  454. KernelMode,
  455. FALSE,
  456. NULL);
  457. DeviceExtensionParent->NeedCleanup = FALSE;
  458. // WARN STARTS OF OLD GENERIC PARENT
  459. UsbhWarning(NULL,
  460. "This device is using obsolete USB Generic Parent!\nPlease fix your INF file.\n",
  461. TRUE);
  462. // ntStatus = STATUS_DEVICE_CONFIGURATION_ERROR;
  463. // goto USBH_ParentFdoStartDevice_Done;
  464. // END WARN STARTS OF OLD GENERIC PARENT
  465. //
  466. // configure the device
  467. //
  468. // Initialize DeviceCapabilities structure in case USBH_QueryCapabilities
  469. // is unsuccessful.
  470. RtlZeroMemory(&deviceCapabilities, sizeof(DEVICE_CAPABILITIES));
  471. USBH_QueryCapabilities(DeviceExtensionParent->TopOfStackDeviceObject,
  472. &deviceCapabilities);
  473. //
  474. // save the system state mapping
  475. //
  476. RtlCopyMemory(&DeviceExtensionParent->DeviceState[0],
  477. &deviceCapabilities.DeviceState[0],
  478. sizeof(DeviceExtensionParent->DeviceState));
  479. // always enabled for wakeup
  480. DeviceExtensionParent->ParentFlags |= HUBFLAG_ENABLED_FOR_WAKEUP;
  481. DeviceExtensionParent->DeviceWake = deviceCapabilities.DeviceWake;
  482. DeviceExtensionParent->SystemWake = deviceCapabilities.SystemWake;
  483. DeviceExtensionParent->CurrentPowerState = PowerDeviceD0;
  484. KeInitializeSemaphore(&DeviceExtensionParent->ParentMutex, 1, 1);
  485. ntStatus = USBH_GetDeviceDescriptor(DeviceExtensionParent->FunctionalDeviceObject,
  486. &DeviceExtensionParent->DeviceDescriptor);
  487. if (!NT_SUCCESS(ntStatus)) {
  488. goto USBH_ParentFdoStartDevice_Done;
  489. }
  490. if (NewList) {
  491. ntStatus =
  492. USBH_GetConfigurationDescriptor(DeviceExtensionParent->FunctionalDeviceObject,
  493. &configurationDescriptor);
  494. } else {
  495. //
  496. // use the old config descriptor if this is a re-start
  497. // the reason is that our interface structures in the function
  498. // extension point in to this same buffer.
  499. configurationDescriptor =
  500. DeviceExtensionParent->ConfigurationDescriptor;
  501. }
  502. if (!NT_SUCCESS(ntStatus)) {
  503. goto USBH_ParentFdoStartDevice_Done;
  504. }
  505. DeviceExtensionParent->ConfigurationDescriptor =
  506. configurationDescriptor;
  507. // we will likely define some registry keys to guide us
  508. // in the configuration of the device -- the default will
  509. // be to select the first congiguration and the first
  510. // alternate interface for each interface.
  511. //
  512. USBH_KdPrint((2,"' Parent StartDevice cd = %x\n",
  513. configurationDescriptor));
  514. DeviceExtensionParent->CurrentConfig =
  515. configurationDescriptor->bConfigurationValue;
  516. //
  517. // Build an interface list structure, this is an array
  518. // of strucutres for each interface on the device.
  519. // We keep a pointer to the interface descriptor for each interface
  520. // within the configuration descriptor
  521. //
  522. numberOfInterfaces = configurationDescriptor->bNumInterfaces;
  523. tmp = interfaceList =
  524. UsbhExAllocatePool(PagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) *
  525. (numberOfInterfaces+1));
  526. if (tmp == NULL) {
  527. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  528. goto USBH_ParentFdoStartDevice_Done;
  529. }
  530. //
  531. // just grab the first alt setting we find for each interface
  532. //
  533. i = interfaceNumber = 0;
  534. while (i< numberOfInterfaces) {
  535. interfaceDescriptor = USBD_ParseConfigurationDescriptorEx(
  536. configurationDescriptor,
  537. configurationDescriptor,
  538. interfaceNumber,
  539. 0, // assume alt setting zero here
  540. -1,
  541. -1,
  542. -1);
  543. if (interfaceDescriptor) {
  544. interfaceList->InterfaceDescriptor =
  545. interfaceDescriptor;
  546. interfaceList++;
  547. i++;
  548. }
  549. interfaceNumber++;
  550. }
  551. //
  552. // terminate the list
  553. //
  554. interfaceList->InterfaceDescriptor = NULL;
  555. urb = USBD_CreateConfigurationRequestEx(configurationDescriptor,
  556. tmp);
  557. if (urb) {
  558. ntStatus = USBH_FdoSyncSubmitUrb(DeviceExtensionParent->FunctionalDeviceObject, urb);
  559. if (NT_SUCCESS(ntStatus)) {
  560. if (NewList) {
  561. //
  562. // first time create our function list
  563. //
  564. ntStatus = USBH_ParentCreateFunctionList(
  565. DeviceExtensionParent,
  566. tmp,
  567. urb);
  568. } else {
  569. //
  570. // update our function list with the new handles
  571. //
  572. PDEVICE_OBJECT deviceObject;
  573. PSINGLE_LIST_ENTRY listEntry;
  574. SINGLE_LIST_ENTRY tempList;
  575. ULONG i;
  576. PDEVICE_EXTENSION_FUNCTION deviceExtensionFunction;
  577. USBH_KdBreak(("re-init function list %x\n",
  578. DeviceExtensionParent));
  579. deviceObject = DeviceExtensionParent->FunctionalDeviceObject;
  580. tempList.Next = NULL;
  581. //
  582. // process all entries in the function list
  583. //
  584. do {
  585. listEntry = PopEntryList(&DeviceExtensionParent->FunctionList);
  586. if (listEntry != NULL) {
  587. PushEntryList(&tempList, listEntry);
  588. deviceExtensionFunction =
  589. CONTAINING_RECORD(listEntry,
  590. DEVICE_EXTENSION_FUNCTION,
  591. ListEntry);
  592. USBH_KdPrint((2,"'re-init function %x\n",
  593. deviceExtensionFunction));
  594. deviceExtensionFunction->ConfigurationHandle =
  595. urb->UrbSelectConfiguration.ConfigurationHandle;
  596. for (i=0; i< deviceExtensionFunction->InterfaceCount; i++) {
  597. //
  598. // now we need to find the matching interface
  599. // information from the new configuration request
  600. // and attach it to the function
  601. {
  602. PUSBD_INTERFACE_INFORMATION interfaceInformation;
  603. interfaceInformation =
  604. deviceExtensionFunction->FunctionInterfaceList[i].InterfaceInformation;
  605. interfaceList = tmp;
  606. while (interfaceList->InterfaceDescriptor) {
  607. PFUNCTION_INTERFACE functionInterface;
  608. functionInterface =
  609. &deviceExtensionFunction->FunctionInterfaceList[i];
  610. if (interfaceList->InterfaceDescriptor->bInterfaceNumber
  611. == interfaceInformation->InterfaceNumber) {
  612. USBH_KdPrint((2,
  613. "'re-init matched interface %d %x %x\n",
  614. interfaceInformation->InterfaceNumber,
  615. interfaceList,
  616. interfaceInformation));
  617. if (interfaceList->InterfaceDescriptor->bAlternateSetting !=
  618. interfaceInformation->AlternateSetting) {
  619. USBH_KdPrint((2,
  620. "'re-init no match alt interface %d %x %x\n",
  621. interfaceInformation->InterfaceNumber,
  622. interfaceList,
  623. interfaceInformation));
  624. // we have a different alt setting
  625. // switch our info to match the new
  626. // setting
  627. UsbhExFreePool(interfaceInformation);
  628. interfaceInformation =
  629. functionInterface ->InterfaceInformation =
  630. UsbhExAllocatePool(NonPagedPool,
  631. interfaceList->Interface->Length);
  632. if (interfaceInformation) {
  633. RtlCopyMemory(interfaceInformation,
  634. interfaceList->Interface,
  635. interfaceList->Interface->Length);
  636. functionInterface->InterfaceDescriptor =
  637. interfaceList->InterfaceDescriptor;
  638. }
  639. } else {
  640. USBH_KdPrint((2,
  641. "'re-init matched alt interface %d %x %x\n",
  642. interfaceInformation->InterfaceNumber,
  643. interfaceList,
  644. interfaceInformation));
  645. USBH_ASSERT(interfaceList->Interface->Length ==
  646. interfaceInformation->Length);
  647. RtlCopyMemory(interfaceInformation,
  648. interfaceList->Interface,
  649. interfaceList->Interface->Length);
  650. }
  651. break;
  652. }
  653. interfaceList++;
  654. }
  655. }
  656. }
  657. }
  658. } while (listEntry != NULL);
  659. // now put the entries back
  660. do {
  661. listEntry = PopEntryList(&tempList);
  662. if (listEntry != NULL) {
  663. PushEntryList(&DeviceExtensionParent->FunctionList, listEntry);
  664. }
  665. } while (listEntry != NULL);
  666. }
  667. }
  668. ExFreePool(urb);
  669. //
  670. // Tell the OS that this PDO can have kids.
  671. //
  672. //
  673. // Workaround for PnP bug #406381 - RC3SS: Bluescreen failure when
  674. // installing/deinstalling communication ports
  675. //
  676. //===== Assigned by santoshj on 09/23/99 10:27:20 to kenray =====
  677. // This is a race condition between IopInitializeSystemDrivers and
  678. // IoInvalidateDeviceRelations. The real fix is too big a change at this
  679. // stage of the product and has potential of exposing other problems. This
  680. // problem can be solved if USBHUB does not invalidate device relations on
  681. // every start which is redundant anyway (and also exposes this bug).
  682. //
  683. // USBH_IoInvalidateDeviceRelations(DeviceExtensionParent->PhysicalDeviceObject,
  684. // BusRelations);
  685. DeviceExtensionParent->NeedCleanup = TRUE;
  686. } else {
  687. // failed to allocate URB
  688. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  689. }
  690. UsbhExFreePool(tmp);
  691. USBH_ParentFdoStartDevice_Done:
  692. //
  693. // complete the start Irp now since we pended it with
  694. // our completion handler.
  695. //
  696. USBH_CompleteIrp(Irp, ntStatus);
  697. return ntStatus;
  698. }
  699. NTSTATUS
  700. USBH_ParentQueryBusRelations(
  701. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent,
  702. IN PIRP Irp
  703. )
  704. /* ++
  705. *
  706. * Description:
  707. *
  708. * This function responds to Bus_Reference_Next_Device, Bus_Query_Bus_Check,
  709. * //Bus_Query_Id: Bus_Id, HardwareIDs, CompatibleIDs and InstanceID.
  710. *
  711. * Arguments:
  712. *
  713. * Return:
  714. *
  715. * NtStatus
  716. *
  717. * -- */
  718. {
  719. PIO_STACK_LOCATION ioStack;
  720. NTSTATUS ntStatus = STATUS_SUCCESS;
  721. PDEVICE_RELATIONS deviceRelations;
  722. PDEVICE_OBJECT deviceObject;
  723. PSINGLE_LIST_ENTRY listEntry;
  724. PDEVICE_EXTENSION_FUNCTION deviceExtensionFunction;
  725. PAGED_CODE();
  726. USBH_KdPrint((1, "'Query Bus Relations (PAR) %x\n",
  727. DeviceExtensionParent->PhysicalDeviceObject));
  728. //
  729. // Get a pointer to the current location in the Irp. This is where
  730. // the function codes and parameters are located.
  731. //
  732. ioStack = IoGetCurrentIrpStackLocation(Irp);
  733. USBH_KdPrint((2,"'QueryBusRelations (parent) ext = %x\n", DeviceExtensionParent));
  734. USBH_KdPrint((2,"'QueryBusRelations (parent) %x\n", ioStack->Parameters.QueryDeviceRelations.Type));
  735. USBH_ASSERT(ioStack->Parameters.QueryDeviceRelations.Type == BusRelations);
  736. USBH_KdPrint((2,"'ParentQueryBusRelations enumerate device\n"));
  737. //
  738. // It should be Function device object.
  739. //
  740. USBH_ASSERT(EXTENSION_TYPE_PARENT == DeviceExtensionParent->ExtensionType);
  741. //
  742. // Must use ExAllocatePool directly here because the OS
  743. // will free the buffer
  744. //
  745. deviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(*deviceRelations) +
  746. (DeviceExtensionParent->FunctionCount - 1) * sizeof(PDEVICE_OBJECT),
  747. USBHUB_HEAP_TAG);
  748. if (deviceRelations == NULL) {
  749. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  750. goto USBH_ParentQueryBusRelations_Done;
  751. }
  752. deviceRelations->Count = 0;
  753. //
  754. // Functions on a composite device are always present
  755. // we just need to return the PDO
  756. //
  757. listEntry = DeviceExtensionParent->FunctionList.Next;
  758. while (listEntry) {
  759. deviceExtensionFunction =
  760. CONTAINING_RECORD(listEntry,
  761. DEVICE_EXTENSION_FUNCTION,
  762. ListEntry);
  763. USBH_KdPrint((2,"'deviceExtensionFunction = %x\n", deviceExtensionFunction));
  764. deviceObject = deviceExtensionFunction->FunctionPhysicalDeviceObject;
  765. ObReferenceObject(deviceObject);
  766. deviceObject->Flags |= DO_POWER_PAGABLE;
  767. deviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
  768. deviceRelations->Objects[deviceRelations->Count] = deviceObject;
  769. deviceRelations->Count++;
  770. listEntry = listEntry->Next;
  771. }
  772. USBH_ParentQueryBusRelations_Done:
  773. Irp->IoStatus.Information=(ULONG_PTR) deviceRelations;
  774. Irp->IoStatus.Status = STATUS_SUCCESS;
  775. USBH_KdPrint((1, "'Query Bus Relations (PAR) %x pass on\n",
  776. DeviceExtensionParent->PhysicalDeviceObject));
  777. ntStatus = USBH_PassIrp(Irp,
  778. DeviceExtensionParent->TopOfStackDeviceObject);
  779. return ntStatus;
  780. }
  781. NTSTATUS
  782. USBH_FunctionPdoQueryId(
  783. IN PDEVICE_EXTENSION_FUNCTION DeviceExtensionFunction,
  784. IN PIRP Irp
  785. )
  786. /* ++
  787. *
  788. * Description:
  789. *
  790. * This function responds to IRP_MJ_PNP, IRP_MN_QUERY_ID.
  791. *
  792. * Arguments:
  793. *
  794. * DeviceExtensionPort - should be the PDO we created for the port device Irp
  795. * - the Irp
  796. *
  797. * Return:
  798. *
  799. * NtStatus
  800. *
  801. * -- */
  802. {
  803. PIO_STACK_LOCATION ioStack;
  804. PDEVICE_EXTENSION_PARENT deviceExtensionParent;
  805. PDEVICE_EXTENSION_PORT deviceExtensionPort;
  806. PDEVICE_EXTENSION_HUB deviceExtensionHub;
  807. #ifdef USB2
  808. // ULONG diagnosticFlags;
  809. #else
  810. PUSBD_EXTENSION deviceExtensionUsbd;
  811. #endif
  812. USHORT idVendor;
  813. USHORT idProduct;
  814. LONG miId;
  815. NTSTATUS ntStatus = STATUS_SUCCESS;
  816. BOOLEAN diagnosticMode;
  817. PAGED_CODE();
  818. deviceExtensionParent = DeviceExtensionFunction->DeviceExtensionParent;
  819. ioStack = IoGetCurrentIrpStackLocation(Irp);
  820. USBH_KdPrint((2,"'IRP_MN_QUERY_ID function Pdo extension=%x\n", DeviceExtensionFunction));
  821. //
  822. // It should be physical device object.
  823. //
  824. USBH_ASSERT(EXTENSION_TYPE_FUNCTION == DeviceExtensionFunction->ExtensionType);
  825. // It might not be too clean to reach into the RootHubPdo USBD extension,
  826. // but there doesn't seem to be any other easy way to determine if diag
  827. // mode is on. If diagnostic mode is on, report the VID & PID as 0xFFFF
  828. // so that the diagnostic driver gets loaded for each interface of the
  829. // device.
  830. //
  831. deviceExtensionPort = (PDEVICE_EXTENSION_PORT)deviceExtensionParent->PhysicalDeviceObject->DeviceExtension;
  832. deviceExtensionHub = deviceExtensionPort->DeviceExtensionHub;
  833. #ifdef USB2
  834. // diagnosticFlags = USBD_GetHackFlags(deviceExtensionHub);
  835. // diagnosticMode = (BOOLEAN)(USBD_DEVHACK_SET_DIAG_ID & diagnosticFlags);
  836. diagnosticMode = FALSE;
  837. #else
  838. deviceExtensionUsbd = ((PUSBD_EXTENSION)deviceExtensionHub->RootHubPdo->DeviceExtension)->TrueDeviceExtension;
  839. diagnosticMode = deviceExtensionUsbd->DiagnosticMode;
  840. #endif
  841. if (diagnosticMode)
  842. {
  843. idVendor = 0xFFFF;
  844. idProduct = 0xFFFF;
  845. miId = -1;
  846. }
  847. else
  848. {
  849. idVendor = deviceExtensionParent->DeviceDescriptor.idVendor;
  850. idProduct = deviceExtensionParent->DeviceDescriptor.idProduct;
  851. miId = DeviceExtensionFunction->FunctionInterfaceList[0].InterfaceInformation->InterfaceNumber;
  852. }
  853. switch (ioStack->Parameters.QueryId.IdType) {
  854. case BusQueryDeviceID:
  855. Irp->IoStatus.Information =
  856. (ULONG_PTR)
  857. USBH_BuildDeviceID(idVendor,
  858. idProduct,
  859. miId,
  860. FALSE);
  861. break;
  862. case BusQueryHardwareIDs:
  863. Irp->IoStatus.Information =
  864. (ULONG_PTR)
  865. USBH_BuildHardwareIDs(idVendor,
  866. idProduct,
  867. deviceExtensionParent->DeviceDescriptor.bcdDevice,
  868. miId,
  869. FALSE);
  870. break;
  871. case BusQueryCompatibleIDs:
  872. //
  873. // always use first interface
  874. //
  875. Irp->IoStatus.Information =
  876. (ULONG_PTR) USBH_BuildCompatibleIDs(
  877. "",
  878. "",
  879. DeviceExtensionFunction->FunctionInterfaceList[0].InterfaceInformation->Class,
  880. DeviceExtensionFunction->FunctionInterfaceList[0].InterfaceInformation->SubClass,
  881. DeviceExtensionFunction->FunctionInterfaceList[0].InterfaceInformation->Protocol,
  882. FALSE,
  883. FALSE);
  884. break;
  885. case BusQueryInstanceID:
  886. Irp->IoStatus.Information =
  887. (ULONG_PTR) USBH_BuildInstanceID(&DeviceExtensionFunction->UniqueIdString[0],
  888. sizeof(DeviceExtensionFunction->UniqueIdString));
  889. break;
  890. default:
  891. USBH_KdBreak(("PdoBusExtension Unknown BusQueryId\n"));
  892. // IrpAssert: Must not change Irp->IoStatus.Status for bogus IdTypes,
  893. // so return original status here.
  894. return Irp->IoStatus.Status;
  895. }
  896. if (Irp->IoStatus.Information == 0) {
  897. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  898. }
  899. return ntStatus;
  900. }
  901. NTSTATUS
  902. USBH_FunctionPdoQueryDeviceText(
  903. IN PDEVICE_EXTENSION_FUNCTION DeviceExtensionFunction,
  904. IN PIRP Irp
  905. )
  906. /* ++
  907. *
  908. * Description:
  909. *
  910. * This routine is called by PnP via (IRP_MJ_PNP, IRP_MN_QUERY_CAPABILITIES).
  911. * Supposedly, this is a message forwarded by port device Fdo.
  912. *
  913. * Argument:
  914. *
  915. * DeviceExtensionPort - This is a a Pdo extension we created for the port
  916. * device. Irp - the request
  917. *
  918. * Return:
  919. *
  920. * STATUS_SUCCESS
  921. *
  922. *
  923. * -- */
  924. {
  925. PDEVICE_OBJECT deviceObject;
  926. PIO_STACK_LOCATION ioStack;
  927. PDEVICE_EXTENSION_PARENT deviceExtensionParent;
  928. PDEVICE_EXTENSION_PORT deviceExtensionPort;
  929. PDEVICE_EXTENSION_HUB deviceExtensionHub;
  930. DEVICE_TEXT_TYPE deviceTextType;
  931. LANGID languageId;
  932. NTSTATUS ntStatus = STATUS_SUCCESS;
  933. PUSB_STRING_DESCRIPTOR usbString;
  934. PWCHAR deviceText;
  935. PAGED_CODE();
  936. deviceExtensionParent = DeviceExtensionFunction->DeviceExtensionParent;
  937. deviceExtensionPort = (PDEVICE_EXTENSION_PORT)deviceExtensionParent->PhysicalDeviceObject->DeviceExtension;
  938. deviceObject = deviceExtensionPort->PortPhysicalDeviceObject;
  939. ioStack = IoGetCurrentIrpStackLocation(Irp);
  940. deviceExtensionHub = deviceExtensionPort->DeviceExtensionHub;
  941. deviceTextType = ioStack->
  942. Parameters.QueryDeviceText.DeviceTextType;
  943. // Validate DeviceTextType for IrpAssert
  944. if (deviceTextType != DeviceTextDescription &&
  945. deviceTextType != DeviceTextLocationInformation) {
  946. USBH_KdPrint((2, "'PdoQueryDeviceText called with bogus DeviceTextType\n"));
  947. //
  948. // return the original status passed to us
  949. //
  950. ntStatus = Irp->IoStatus.Status;
  951. goto USBH_FunctionPdoQueryDeviceTextDone;
  952. }
  953. // we don't care about the hiword
  954. //languageId = (USHORT) (ioStack->Parameters.QueryDeviceText.LocaleId >>16);
  955. // always specify english for now.
  956. languageId = 0x0409;
  957. USBH_KdPrint((2,"'PdoQueryDeviceText Pdo %x type = %x, lang = %x locale %x\n",
  958. deviceObject, deviceTextType, languageId, ioStack->Parameters.QueryDeviceText.LocaleId));
  959. //
  960. // see if the device supports strings, for non complient device mode
  961. // we won't even try
  962. //
  963. if (deviceExtensionPort->DeviceData == NULL ||
  964. deviceExtensionPort->DeviceDescriptor.iProduct == 0 ||
  965. (deviceExtensionPort->DeviceHackFlags & USBD_DEVHACK_DISABLE_SN) ||
  966. (deviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_ENUM_ERROR)) {
  967. // string descriptor
  968. USBH_KdBreak(("no product string\n", deviceObject));
  969. ntStatus = STATUS_NOT_SUPPORTED;
  970. }
  971. if (NT_SUCCESS(ntStatus)) {
  972. usbString = UsbhExAllocatePool(NonPagedPool, MAXIMUM_USB_STRING_LENGTH);
  973. if (usbString) {
  974. ntStatus = USBH_CheckDeviceLanguage(deviceObject,
  975. languageId);
  976. if (NT_SUCCESS(ntStatus)) {
  977. //
  978. // device supports are language, get the string
  979. //
  980. ntStatus = USBH_SyncGetStringDescriptor(deviceObject,
  981. deviceExtensionPort->DeviceDescriptor.iProduct, //index
  982. languageId, //langid
  983. usbString,
  984. MAXIMUM_USB_STRING_LENGTH,
  985. NULL,
  986. TRUE);
  987. if (NT_SUCCESS(ntStatus) &&
  988. usbString->bLength <= sizeof(UNICODE_NULL)) {
  989. ntStatus = STATUS_UNSUCCESSFUL;
  990. }
  991. if (NT_SUCCESS(ntStatus)) {
  992. //
  993. // return the string
  994. //
  995. //
  996. // must use stock alloc function because the caller frees the
  997. // buffer
  998. //
  999. // note: the descriptor header is the same size as
  1000. // a unicode NULL so we don't have to adjust the size
  1001. //
  1002. deviceText = ExAllocatePoolWithTag(PagedPool, usbString->bLength, USBHUB_HEAP_TAG);
  1003. if (deviceText) {
  1004. RtlZeroMemory(deviceText, usbString->bLength);
  1005. RtlCopyMemory(deviceText, &usbString->bString[0],
  1006. usbString->bLength - sizeof(UNICODE_NULL));
  1007. Irp->IoStatus.Information = (ULONG_PTR) deviceText;
  1008. USBH_KdBreak(("Returning Device Text %x\n", deviceText));
  1009. } else {
  1010. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1011. }
  1012. }
  1013. }
  1014. UsbhExFreePool(usbString);
  1015. } else {
  1016. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1017. }
  1018. }
  1019. USBH_FunctionPdoQueryDeviceTextDone:
  1020. return ntStatus;
  1021. }
  1022. NTSTATUS
  1023. USBH_FunctionPdoPnP(
  1024. IN PDEVICE_EXTENSION_FUNCTION DeviceExtensionFunction,
  1025. IN PIRP Irp,
  1026. IN UCHAR MinorFunction,
  1027. IN OUT PBOOLEAN IrpNeedsCompletion
  1028. )
  1029. /* ++
  1030. *
  1031. * Description:
  1032. *
  1033. * This function responds to IoControl PnPPower for the PDO. This function is
  1034. * synchronous.
  1035. *
  1036. * Arguments:
  1037. *
  1038. * DeviceExtensionPort - the PDO extension Irp - the request packet
  1039. * uchMinorFunction - the minor function of the PnP Power request.
  1040. *
  1041. * Return:
  1042. *
  1043. * NTSTATUS
  1044. *
  1045. * -- */
  1046. {
  1047. NTSTATUS ntStatus;
  1048. #if DBG
  1049. PDEVICE_OBJECT deviceObject = DeviceExtensionFunction->FunctionPhysicalDeviceObject;
  1050. #endif
  1051. PDEVICE_EXTENSION_PARENT deviceExtensionParent;
  1052. PIO_STACK_LOCATION irpStack;
  1053. PAGED_CODE();
  1054. *IrpNeedsCompletion = TRUE;
  1055. deviceExtensionParent = DeviceExtensionFunction->DeviceExtensionParent;
  1056. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1057. USBH_KdPrint((2,"'PnP Power Pdo %x minor %x\n", deviceObject, MinorFunction));
  1058. switch (MinorFunction) {
  1059. case IRP_MN_QUERY_STOP_DEVICE:
  1060. case IRP_MN_CANCEL_STOP_DEVICE:
  1061. case IRP_MN_QUERY_REMOVE_DEVICE:
  1062. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1063. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  1064. // Ken says take this out
  1065. // case IRP_MN_SURPRISE_REMOVAL:
  1066. ntStatus = STATUS_SUCCESS;
  1067. break;
  1068. case IRP_MN_START_DEVICE:
  1069. USBH_KdPrint((1,
  1070. "'Starting composite PDO %x\n",
  1071. DeviceExtensionFunction->FunctionPhysicalDeviceObject));
  1072. ntStatus = STATUS_SUCCESS;
  1073. break;
  1074. case IRP_MN_STOP_DEVICE:
  1075. USBH_KdPrint((1,
  1076. "'Stopping composite PDO %x\n",
  1077. DeviceExtensionFunction->FunctionPhysicalDeviceObject));
  1078. ntStatus = STATUS_SUCCESS;
  1079. break;
  1080. case IRP_MN_REMOVE_DEVICE:
  1081. USBH_KdPrint((1,
  1082. "'Removing composite PDO %x\n",
  1083. DeviceExtensionFunction->FunctionPhysicalDeviceObject));
  1084. ntStatus = STATUS_SUCCESS;
  1085. break;
  1086. case IRP_MN_QUERY_CAPABILITIES:
  1087. {
  1088. PDEVICE_CAPABILITIES deviceCapabilities;
  1089. PIO_STACK_LOCATION ioStack;
  1090. USBH_KdPrint((2,"'IRP_MN_QUERY_CAPABILITIES Function Pdo %x\n", deviceObject));
  1091. ntStatus = STATUS_SUCCESS;
  1092. ioStack = IoGetCurrentIrpStackLocation(Irp);
  1093. deviceCapabilities = ioStack->
  1094. Parameters.DeviceCapabilities.Capabilities;
  1095. //
  1096. // clone the capabilities for the parent
  1097. //
  1098. //
  1099. // fill in the the device state capabilities from the
  1100. // table we saved from the pdo.
  1101. //
  1102. RtlCopyMemory(&deviceCapabilities->DeviceState[0],
  1103. &deviceExtensionParent->DeviceState[0],
  1104. sizeof(deviceExtensionParent->DeviceState));
  1105. //
  1106. // clone the device wake capabilities for children
  1107. // from the parent.
  1108. //
  1109. deviceCapabilities->DeviceWake =
  1110. deviceExtensionParent->DeviceWake;
  1111. deviceCapabilities->SystemWake =
  1112. deviceExtensionParent->SystemWake;
  1113. //
  1114. // we will need to modify these based on information
  1115. // returned in the power descriptor
  1116. //
  1117. deviceCapabilities->Removable = FALSE;
  1118. deviceCapabilities->UniqueID = FALSE;
  1119. // SurpriseRemovalOK is FALSE by default, and some clients (NDIS)
  1120. // set it to true on the way down, in accordance with the DDK.
  1121. // deviceCapabilities->SurpriseRemovalOK = FALSE;
  1122. deviceCapabilities->RawDeviceOK = FALSE;
  1123. }
  1124. break;
  1125. case IRP_MN_QUERY_ID:
  1126. USBH_KdPrint((2,"'IRP_MN_QUERY_ID Pdo %x\n", deviceObject));
  1127. ntStatus = USBH_FunctionPdoQueryId(DeviceExtensionFunction, Irp);
  1128. break;
  1129. case IRP_MN_QUERY_DEVICE_TEXT:
  1130. USBH_KdPrint((2,"'IRP_MN_QUERY_DEVICE_TEXT Pdo %x\n", deviceObject));
  1131. ntStatus = USBH_FunctionPdoQueryDeviceText(DeviceExtensionFunction, Irp);
  1132. break;
  1133. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1134. // this is a leaf node, we return the status passed
  1135. // to us unless it is a call to TargetRelations
  1136. if (irpStack->Parameters.QueryDeviceRelations.Type ==
  1137. TargetDeviceRelation) {
  1138. PDEVICE_RELATIONS deviceRelations = NULL;
  1139. deviceRelations = ExAllocatePoolWithTag(PagedPool,
  1140. sizeof(*deviceRelations), USBHUB_HEAP_TAG);
  1141. if (deviceRelations == NULL) {
  1142. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1143. } else {
  1144. ObReferenceObject(
  1145. DeviceExtensionFunction->FunctionPhysicalDeviceObject);
  1146. deviceRelations->Count = 1;
  1147. deviceRelations->Objects[0] =
  1148. DeviceExtensionFunction->FunctionPhysicalDeviceObject;
  1149. ntStatus = STATUS_SUCCESS;
  1150. }
  1151. USBH_KdPrint((1, "'Query Target Relations (FUN) PDO %x complt\n",
  1152. DeviceExtensionFunction->FunctionPhysicalDeviceObject));
  1153. Irp->IoStatus.Information=(ULONG_PTR) deviceRelations;
  1154. } else {
  1155. ntStatus = Irp->IoStatus.Status;
  1156. }
  1157. break;
  1158. case IRP_MN_QUERY_INTERFACE:
  1159. USBH_KdPrint((1,"'IRP_MN_QUERY_INTERFACE, xface type: %x\n",
  1160. irpStack->Parameters.QueryInterface.InterfaceType));
  1161. // Pass this on to the parent.
  1162. ntStatus = USBH_PassIrp(Irp, deviceExtensionParent->FunctionalDeviceObject);
  1163. *IrpNeedsCompletion = FALSE;
  1164. break;
  1165. default:
  1166. USBH_KdBreak(("PdoPnP unknown (%d) PnP message Pdo %x\n",
  1167. MinorFunction, deviceObject));
  1168. ntStatus = Irp->IoStatus.Status;
  1169. }
  1170. USBH_KdPrint((2,"'FunctionPdoPnP exit %x\n", ntStatus));
  1171. return ntStatus;
  1172. }
  1173. VOID
  1174. USBH_ParentWaitWakeCancel(
  1175. IN PDEVICE_OBJECT DeviceObject,
  1176. IN PIRP Irp
  1177. )
  1178. /*++
  1179. Routine Description:
  1180. Arguments:
  1181. Return Value:
  1182. NT status code.
  1183. --*/
  1184. {
  1185. PDEVICE_EXTENSION_HEADER devExtHeader;
  1186. PDEVICE_EXTENSION_FUNCTION function;
  1187. PDEVICE_EXTENSION_PARENT parent;
  1188. NTSTATUS ntStatus = STATUS_CANCELLED;
  1189. LONG pendingChildWWs;
  1190. PIRP parentWaitWake = NULL;
  1191. USBH_KdPrint((1,"'Function WaitWake Irp %x cancelled\n", Irp));
  1192. USBH_ASSERT(DeviceObject);
  1193. devExtHeader = (PDEVICE_EXTENSION_HEADER) DeviceObject->DeviceExtension;
  1194. USBH_ASSERT(devExtHeader->ExtensionType == EXTENSION_TYPE_FUNCTION);
  1195. function = (PDEVICE_EXTENSION_FUNCTION) devExtHeader;
  1196. parent = function->DeviceExtensionParent;
  1197. if (Irp != function->WaitWakeIrp) {
  1198. //
  1199. // Nothing to do
  1200. // This Irp has already been taken care of.
  1201. // We are in the process of completing this IRP in
  1202. // USBH_ParentCompleteFunctionWakeIrps.
  1203. //
  1204. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1205. } else {
  1206. function->WaitWakeIrp = NULL;
  1207. IoSetCancelRoutine(Irp, NULL);
  1208. pendingChildWWs = InterlockedDecrement (&parent->NumberFunctionWakeIrps);
  1209. parentWaitWake = parent->PendingWakeIrp;
  1210. if (0 == pendingChildWWs) {
  1211. // Set PendingWakeIrp to NULL since we cancel it below.
  1212. parent->PendingWakeIrp = NULL;
  1213. parent->ParentFlags &= ~HUBFLAG_PENDING_WAKE_IRP;
  1214. }
  1215. IoReleaseCancelSpinLock(Irp->CancelIrql);
  1216. PoStartNextPowerIrp(Irp);
  1217. Irp->IoStatus.Status = STATUS_CANCELLED;
  1218. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1219. //
  1220. // If there are no more outstanding WW irps, we need to cancel the WW
  1221. // to our parent.
  1222. //
  1223. if (0 == pendingChildWWs) {
  1224. IoCancelIrp (parentWaitWake);
  1225. } else {
  1226. ASSERT (0 < pendingChildWWs);
  1227. }
  1228. }
  1229. }
  1230. NTSTATUS
  1231. USBH_FunctionPdoPower(
  1232. IN PDEVICE_EXTENSION_FUNCTION DeviceExtensionFunction,
  1233. IN PIRP Irp,
  1234. IN UCHAR MinorFunction
  1235. )
  1236. /* ++
  1237. *
  1238. * Description:
  1239. *
  1240. * This function responds to IoControl Power for the PDO. This function is
  1241. * synchronous.
  1242. *
  1243. * Arguments:
  1244. *
  1245. * DeviceExtensionPort - the PDO extension Irp - the request packet
  1246. * uchMinorFunction - the minor function of the PnP Power request.
  1247. *
  1248. * Return:
  1249. *
  1250. * NTSTATUS
  1251. *
  1252. * -- */
  1253. {
  1254. NTSTATUS ntStatus;
  1255. #if DBG
  1256. PDEVICE_OBJECT deviceObject = DeviceExtensionFunction->FunctionPhysicalDeviceObject;
  1257. #endif
  1258. PIO_STACK_LOCATION irpStack;
  1259. USHORT feature;
  1260. KIRQL irql;
  1261. PIRP wWIrp;
  1262. PIRP parentWaitWake;
  1263. LONG pendingFunctionWWs;
  1264. PDEVICE_EXTENSION_PARENT deviceExtensionParent;
  1265. PDRIVER_CANCEL oldCancel;
  1266. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1267. USBH_KdPrint((2,"'Power Pdo %x minor %x\n", deviceObject, MinorFunction));
  1268. deviceExtensionParent = DeviceExtensionFunction->DeviceExtensionParent;
  1269. switch (MinorFunction) {
  1270. case IRP_MN_SET_POWER:
  1271. USBH_KdPrint((2,"'IRP_MN_SET_POWER\n"));
  1272. //
  1273. // we just return success here, pnp will make sure
  1274. // all children have entred the low power state
  1275. // before putting the parent in a low power state
  1276. //
  1277. //
  1278. // send the setpower feature request here if the device
  1279. // wants it
  1280. //
  1281. ntStatus = STATUS_SUCCESS;
  1282. switch (irpStack->Parameters.Power.Type) {
  1283. case SystemPowerState:
  1284. USBH_KdPrint(
  1285. (1, "'IRP_MJ_POWER PA pdo(%x) MN_SET_POWER(SystemPowerState) complt\n",
  1286. DeviceExtensionFunction->FunctionPhysicalDeviceObject));
  1287. ntStatus = STATUS_SUCCESS;
  1288. break;
  1289. case DevicePowerState:
  1290. ntStatus = STATUS_SUCCESS;
  1291. USBH_KdPrint(
  1292. (1, "'IRP_MJ_POWER PA pdo(%x) MN_SET_POWER(DevicePowerState) complt\n",
  1293. DeviceExtensionFunction->FunctionPhysicalDeviceObject));
  1294. break;
  1295. } // switch irpStack->Parameters.Power.Type
  1296. break; //IRP_MN_SET_POWER
  1297. case IRP_MN_QUERY_POWER:
  1298. ntStatus = STATUS_SUCCESS;
  1299. USBH_KdPrint(
  1300. (1, "'IRP_MJ_POWER PA pdo(%x) MN_QUERY_POWER, status = %x complt\n",
  1301. DeviceExtensionFunction->FunctionPhysicalDeviceObject, ntStatus));
  1302. break;
  1303. case IRP_MN_WAIT_WAKE:
  1304. USBH_KdPrint(
  1305. (1, "'enabling remote wakeup for USB child PDO (%x)\n",
  1306. DeviceExtensionFunction->FunctionPhysicalDeviceObject));
  1307. if (deviceExtensionParent->CurrentPowerState != PowerDeviceD0 ||
  1308. deviceExtensionParent->ParentFlags & HUBFLAG_DEVICE_STOPPING) {
  1309. LOGENTRY(LOG_PNP, "!WWp", deviceExtensionParent, 0, 0);
  1310. UsbhWarning(NULL,
  1311. "Client driver should not be submitting WW IRPs at this time.\n",
  1312. TRUE);
  1313. ntStatus = STATUS_INVALID_DEVICE_STATE;
  1314. break;
  1315. }
  1316. IoAcquireCancelSpinLock(&irql);
  1317. if (DeviceExtensionFunction->WaitWakeIrp != NULL) {
  1318. ntStatus = STATUS_DEVICE_BUSY;
  1319. IoReleaseCancelSpinLock(irql);
  1320. } else {
  1321. // set a cancel routine
  1322. oldCancel = IoSetCancelRoutine(Irp, USBH_ParentWaitWakeCancel);
  1323. USBH_ASSERT (NULL == oldCancel);
  1324. if (Irp->Cancel) {
  1325. TEST_TRAP();
  1326. IoSetCancelRoutine (Irp, NULL);
  1327. IoReleaseCancelSpinLock(irql);
  1328. ntStatus = STATUS_CANCELLED;
  1329. } else {
  1330. // flag this device as "enabled for wakeup"
  1331. DeviceExtensionFunction->WaitWakeIrp = Irp;
  1332. pendingFunctionWWs =
  1333. InterlockedIncrement (&deviceExtensionParent->NumberFunctionWakeIrps);
  1334. IoMarkIrpPending(Irp);
  1335. IoReleaseCancelSpinLock(irql);
  1336. //
  1337. // now we must enable the parent PDO for wakeup
  1338. //
  1339. if (1 == pendingFunctionWWs) {
  1340. // What if this fails?
  1341. ntStatus = USBH_ParentSubmitWaitWakeIrp(deviceExtensionParent);
  1342. } else {
  1343. ntStatus = STATUS_PENDING;
  1344. }
  1345. ntStatus = STATUS_PENDING;
  1346. goto USBH_FunctionPdoPower_Done;
  1347. }
  1348. }
  1349. break;
  1350. default:
  1351. USBH_KdBreak(("PdoPnP unknown (%d) PnP message Pdo %x\n",
  1352. MinorFunction, deviceObject));
  1353. //
  1354. // return the original status passed to us
  1355. //
  1356. ntStatus = Irp->IoStatus.Status;
  1357. }
  1358. USBH_KdPrint((2,"'FunctionPdoPower exit %x\n", ntStatus));
  1359. PoStartNextPowerIrp(Irp);
  1360. Irp->IoStatus.Status = ntStatus;
  1361. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  1362. USBH_FunctionPdoPower_Done:
  1363. return ntStatus;
  1364. }
  1365. NTSTATUS
  1366. USBH_ParentQCapsComplete(
  1367. IN PDEVICE_OBJECT DeviceObject,
  1368. IN PIRP Irp,
  1369. IN PVOID Context
  1370. )
  1371. /*++
  1372. Routine Description:
  1373. Called when lower device completes Q_CAPS.
  1374. This gives us a chance to mark the device as SurpriseRemovalOK.
  1375. Arguments:
  1376. DeviceObject - a pointer to the device object
  1377. Irp - a pointer to the irp
  1378. Context - NULL ptr
  1379. Return Value:
  1380. STATUS_SUCCESS
  1381. --*/
  1382. {
  1383. PIO_STACK_LOCATION irpStack = IoGetCurrentIrpStackLocation(Irp);
  1384. PDEVICE_CAPABILITIES pDevCaps = irpStack->Parameters.DeviceCapabilities.Capabilities;
  1385. NTSTATUS ntStatus;
  1386. USBH_KdPrint((1, "'USBH_ParentQCapsComplete\n"));
  1387. ntStatus = Irp->IoStatus.Status;
  1388. if (Irp->PendingReturned) {
  1389. IoMarkIrpPending(Irp);
  1390. }
  1391. //
  1392. // Set SurpriseRemoval flag to TRUE
  1393. //
  1394. pDevCaps->SurpriseRemovalOK = TRUE;
  1395. return ntStatus;
  1396. }
  1397. NTSTATUS
  1398. USBH_ParentPnP(
  1399. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent,
  1400. IN PIRP Irp,
  1401. IN UCHAR MinorFunction
  1402. )
  1403. /* ++
  1404. *
  1405. * Description:
  1406. *
  1407. * This function responds to IoControl PnP for the FDO. This function is
  1408. * synchronous.
  1409. *
  1410. * Arguments:
  1411. *
  1412. * DeviceExtensionParent - the FDO extension pIrp - the request packet
  1413. * MinorFunction - the minor function of the PnP Power request.
  1414. *
  1415. * Return:
  1416. *
  1417. * NTSTATUS
  1418. *
  1419. * -- */
  1420. {
  1421. NTSTATUS ntStatus;
  1422. PDEVICE_OBJECT deviceObject;
  1423. PIO_STACK_LOCATION irpStack;
  1424. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1425. deviceObject = DeviceExtensionParent->FunctionalDeviceObject;
  1426. USBH_KdPrint((2,"'PnP Fdo %x minor %x\n", deviceObject, MinorFunction));
  1427. switch (MinorFunction) {
  1428. case IRP_MN_START_DEVICE:
  1429. USBH_KdBreak(("'IRP_MN_START_DEVICE Parent Fdo %x\n", deviceObject));
  1430. // we get here as a result of re-start.
  1431. // note: our parent hub already checked to see if the device is the same.
  1432. Irp->IoStatus.Status = STATUS_SUCCESS;
  1433. ntStatus = USBH_ParentFdoStartDevice(DeviceExtensionParent, Irp, FALSE);
  1434. break;
  1435. case IRP_MN_STOP_DEVICE:
  1436. USBH_KdPrint((2,"'IRP_MN_STOP_DEVICE Fdo %x\n", deviceObject));
  1437. Irp->IoStatus.Status = STATUS_SUCCESS;
  1438. ntStatus = USBH_ParentFdoStopDevice(DeviceExtensionParent, Irp);
  1439. break;
  1440. case IRP_MN_REMOVE_DEVICE:
  1441. USBH_KdPrint((2,"'IRP_MN_REMOVE_DEVICE Fdo %x\n", deviceObject));
  1442. Irp->IoStatus.Status = STATUS_SUCCESS;
  1443. ntStatus = USBH_ParentFdoRemoveDevice(DeviceExtensionParent, Irp);
  1444. break;
  1445. //
  1446. // This one should be passed down. Let the default case handle it.
  1447. //
  1448. // case IRP_MN_QUERY_PNP_DEVICE_STATE:
  1449. // USBH_KdPrint((2,"IRP_MN_QUERY_PNP_DEVICE_STATE Pdo %x\n", deviceObject));
  1450. // ntStatus = STATUS_SUCCESS;
  1451. // break;
  1452. case IRP_MN_QUERY_DEVICE_RELATIONS:
  1453. switch (irpStack->Parameters.QueryDeviceRelations.Type) {
  1454. case BusRelations:
  1455. ntStatus = USBH_ParentQueryBusRelations(DeviceExtensionParent, Irp);
  1456. break;
  1457. case TargetDeviceRelation:
  1458. //
  1459. // this one gets passed on
  1460. //
  1461. USBH_KdPrint((1, "'Query Relations, TargetRelations (PAR) %x\n",
  1462. DeviceExtensionParent->PhysicalDeviceObject));
  1463. ntStatus = USBH_PassIrp(Irp,
  1464. DeviceExtensionParent->TopOfStackDeviceObject);
  1465. break;
  1466. default:
  1467. USBH_KdPrint((1, "'Query Relations (?) (PAR) %x pass on\n",
  1468. DeviceExtensionParent->PhysicalDeviceObject));
  1469. ntStatus = USBH_PassIrp(Irp,
  1470. DeviceExtensionParent->TopOfStackDeviceObject);
  1471. }
  1472. break;
  1473. case IRP_MN_QUERY_CAPABILITIES:
  1474. USBH_KdPrint((1, "'Query Capabilities (PAR) %x\n",
  1475. DeviceExtensionParent->PhysicalDeviceObject));
  1476. IoCopyCurrentIrpStackLocationToNext(Irp);
  1477. // Set up a completion routine to handle marking the IRP.
  1478. IoSetCompletionRoutine(Irp,
  1479. USBH_ParentQCapsComplete,
  1480. DeviceExtensionParent,
  1481. TRUE,
  1482. TRUE,
  1483. TRUE);
  1484. // Now pass down the IRP.
  1485. ntStatus = IoCallDriver(DeviceExtensionParent->TopOfStackDeviceObject, Irp);
  1486. break;
  1487. case IRP_MN_QUERY_STOP_DEVICE:
  1488. case IRP_MN_CANCEL_STOP_DEVICE:
  1489. case IRP_MN_QUERY_REMOVE_DEVICE:
  1490. case IRP_MN_CANCEL_REMOVE_DEVICE:
  1491. // Ken says take this out
  1492. // case IRP_MN_SURPRISE_REMOVAL:
  1493. case IRP_MN_DEVICE_USAGE_NOTIFICATION:
  1494. // IrpAssert: Must set IRP status before passing IRP down.
  1495. Irp->IoStatus.Status = STATUS_SUCCESS;
  1496. // fall through
  1497. //
  1498. // Pass it down to Pdo to handle all other MN functions
  1499. //
  1500. default:
  1501. USBH_KdPrint((2,"'Query/Cancel/Power request on parent fdo %x %x\n",
  1502. deviceObject, MinorFunction));
  1503. ntStatus = USBH_PassIrp(Irp,
  1504. DeviceExtensionParent->TopOfStackDeviceObject);
  1505. break;
  1506. }
  1507. USBH_KdPrint((2,"'ParentPnP exit %x\n", ntStatus));
  1508. return ntStatus;
  1509. }
  1510. NTSTATUS
  1511. USBH_ParentPower(
  1512. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent,
  1513. IN PIRP Irp,
  1514. IN UCHAR MinorFunction
  1515. )
  1516. /* ++
  1517. *
  1518. * Description:
  1519. *
  1520. * This function responds to IoControl Power for the FDO. This function is
  1521. * synchronous.
  1522. *
  1523. * Arguments:
  1524. *
  1525. * DeviceExtensionParent - the FDO extension pIrp - the request packet
  1526. * MinorFunction - the minor function of the PnP Power request.
  1527. *
  1528. * Return:
  1529. *
  1530. * NTSTATUS
  1531. *
  1532. * -- */
  1533. {
  1534. NTSTATUS ntStatus;
  1535. PDEVICE_OBJECT deviceObject;
  1536. PIO_STACK_LOCATION irpStack;
  1537. irpStack = IoGetCurrentIrpStackLocation(Irp);
  1538. deviceObject = DeviceExtensionParent->FunctionalDeviceObject;
  1539. USBH_KdPrint((2,"'Power Fdo %x minor %x\n", deviceObject, MinorFunction));
  1540. switch (MinorFunction) {
  1541. case IRP_MN_QUERY_POWER:
  1542. USBH_KdPrint(
  1543. (1, "'IRP_MJ_POWER PA fdo(%x) MN_QUERY_POWER\n",
  1544. DeviceExtensionParent->FunctionalDeviceObject));
  1545. IoCopyCurrentIrpStackLocationToNext(Irp);
  1546. PoStartNextPowerIrp(Irp);
  1547. //
  1548. // must pass this on to our PDO
  1549. //
  1550. ntStatus = PoCallDriver(DeviceExtensionParent->TopOfStackDeviceObject,
  1551. Irp);
  1552. break;
  1553. case IRP_MN_SET_POWER:
  1554. USBH_KdPrint(
  1555. (1, "'IRP_MJ_POWER PA fdo(%x) MN_QUERY_POWER\n",
  1556. DeviceExtensionParent->FunctionalDeviceObject));
  1557. switch (irpStack->Parameters.Power.Type) {
  1558. case SystemPowerState:
  1559. {
  1560. POWER_STATE powerState;
  1561. USBH_KdPrint(
  1562. (1, "IRP_MJ_POWER PA fdo(%x) MN_SET_POWER(SystemPowerState)\n",
  1563. DeviceExtensionParent->FunctionalDeviceObject));
  1564. if (irpStack->Parameters.Power.State.SystemState ==
  1565. PowerSystemWorking) {
  1566. powerState.DeviceState = PowerDeviceD0;
  1567. } else if (DeviceExtensionParent->ParentFlags &
  1568. HUBFLAG_ENABLED_FOR_WAKEUP) {
  1569. //
  1570. // based on the system power state
  1571. // request a setting to the appropriate
  1572. // Dx state.
  1573. //
  1574. powerState.DeviceState =
  1575. DeviceExtensionParent->DeviceState[irpStack->Parameters.Power.State.SystemState];
  1576. //
  1577. // These tables should have already been fixed up by the root hub
  1578. // (usbd.sys) to not contain an entry of unspecified.
  1579. //
  1580. ASSERT (PowerDeviceUnspecified != powerState.DeviceState);
  1581. USBH_KdPrint((2,"'Parent System state maps to device state 0x%x\n",
  1582. powerState.DeviceState));
  1583. } else {
  1584. TEST_TRAP();
  1585. powerState.DeviceState = PowerDeviceD3;
  1586. } // irpStack->Parameters.Power.State.SystemState
  1587. //
  1588. // only make the request if it is for a differnt power
  1589. // state then the one we are in.
  1590. //
  1591. if (powerState.DeviceState !=
  1592. DeviceExtensionParent->CurrentPowerState) {
  1593. DeviceExtensionParent->PowerIrp = Irp;
  1594. ntStatus = PoRequestPowerIrp(DeviceExtensionParent->PhysicalDeviceObject,
  1595. IRP_MN_SET_POWER,
  1596. powerState,
  1597. USBH_FdoDeferPoRequestCompletion,
  1598. DeviceExtensionParent,
  1599. NULL);
  1600. } else {
  1601. IoCopyCurrentIrpStackLocationToNext(Irp);
  1602. PoStartNextPowerIrp(Irp);
  1603. ntStatus = PoCallDriver(DeviceExtensionParent->TopOfStackDeviceObject,
  1604. Irp);
  1605. }
  1606. }
  1607. break;
  1608. case DevicePowerState:
  1609. USBH_KdPrint(
  1610. (1, "IRP_MJ_POWER PA fdo(%x) MN_SET_POWER(DevicePowerState)\n",
  1611. DeviceExtensionParent->FunctionalDeviceObject));
  1612. DeviceExtensionParent->CurrentPowerState =
  1613. irpStack->Parameters.Power.State.DeviceState;
  1614. LOGENTRY(LOG_PNP, "prD>", DeviceExtensionParent, DeviceExtensionParent->CurrentPowerState , 0);
  1615. //
  1616. // all of our pdos need to be at or below the
  1617. // expected D-state
  1618. //
  1619. IoCopyCurrentIrpStackLocationToNext(Irp);
  1620. PoStartNextPowerIrp(Irp);
  1621. ntStatus = PoCallDriver(DeviceExtensionParent->TopOfStackDeviceObject,
  1622. Irp);
  1623. USBH_KdPrint((2,"'Parent Device Power State PoCallDriver() = %x\n",
  1624. ntStatus));
  1625. break;
  1626. }
  1627. break; // MN_SET_POWER
  1628. default:
  1629. USBH_KdPrint((2,"'Power request on parent not handled, fdo %x %x\n",
  1630. deviceObject, MinorFunction));
  1631. IoCopyCurrentIrpStackLocationToNext(Irp);
  1632. PoStartNextPowerIrp(Irp);
  1633. ntStatus = PoCallDriver(DeviceExtensionParent->TopOfStackDeviceObject,
  1634. Irp);
  1635. break;
  1636. }
  1637. USBH_KdPrint((2,"'ParentPnP exit %x\n", ntStatus));
  1638. return ntStatus;
  1639. }
  1640. NTSTATUS
  1641. USBH_ParentDispatch(
  1642. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent,
  1643. IN PIRP Irp
  1644. )
  1645. /* ++
  1646. *
  1647. * Description:
  1648. *
  1649. * Handles calls to a FDO associated with a composite device
  1650. *
  1651. * Arguments:
  1652. *
  1653. * Return:
  1654. *
  1655. * NTSTATUS
  1656. *
  1657. * -- */
  1658. {
  1659. NTSTATUS ntStatus = STATUS_SUCCESS;
  1660. PIO_STACK_LOCATION ioStackLocation; // our stack location
  1661. PDEVICE_OBJECT deviceObject;
  1662. USBH_KdPrint((2,"'FdoDispatch DeviceExtension %x Irp %x\n",
  1663. DeviceExtensionParent, Irp));
  1664. deviceObject = DeviceExtensionParent->FunctionalDeviceObject;
  1665. //
  1666. // Get a pointer to IoStackLocation so we can retrieve parameters.
  1667. //
  1668. ioStackLocation = IoGetCurrentIrpStackLocation(Irp);
  1669. //
  1670. // the called functions will complete the irp if necessary
  1671. //
  1672. switch (ioStackLocation->MajorFunction) {
  1673. case IRP_MJ_CREATE:
  1674. USBH_KdPrint((2,"'IRP_MJ_CREATE\n"));
  1675. USBH_CompleteIrp(Irp, STATUS_SUCCESS);
  1676. break;
  1677. case IRP_MJ_CLOSE:
  1678. USBH_KdPrint((2,"'IRP_MJ_CLOSE\n"));
  1679. USBH_CompleteIrp(Irp, STATUS_SUCCESS);
  1680. break;
  1681. case IRP_MJ_DEVICE_CONTROL:
  1682. //
  1683. // Note: if we ever do find a reason to handle this, be sure to
  1684. // not forward IOCTL_KS_PROPERTY / KSPROPSETID_DrmAudioStream /
  1685. // KSPROPERTY_DRMAUDIOSTREAM_SETCONTENTID to next driver! Otherwise
  1686. // this might not be DRM compliant.
  1687. //
  1688. USBH_KdPrint((2,"'IRP_MJ_DEVICE_CONTROL\n"));
  1689. UsbhWarning(NULL,"Should not be hitting this code\n", FALSE);
  1690. ntStatus = STATUS_UNSUCCESSFUL;
  1691. USBH_CompleteIrp(Irp, ntStatus);
  1692. break;
  1693. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  1694. USBH_KdPrint((2,"'InternlDeviceControl IOCTL unknown pass on\n"));
  1695. UsbhWarning(NULL,"Should not be hitting this code\n", FALSE);
  1696. ntStatus = STATUS_UNSUCCESSFUL;
  1697. USBH_CompleteIrp(Irp, ntStatus);
  1698. break;
  1699. case IRP_MJ_PNP:
  1700. USBH_KdPrint((2,"'IRP_MJ_PNP\n"));
  1701. ntStatus = USBH_ParentPnP(DeviceExtensionParent, Irp, ioStackLocation->MinorFunction);
  1702. break;
  1703. case IRP_MJ_POWER:
  1704. USBH_KdPrint((2,"'IRP_MJ_POWER\n"));
  1705. ntStatus = USBH_ParentPower(DeviceExtensionParent, Irp, ioStackLocation->MinorFunction);
  1706. break;
  1707. case IRP_MJ_SYSTEM_CONTROL:
  1708. USBH_KdPrint((2,"'IRP_MJ_SYSTEM_CONTROL\n"));
  1709. #ifdef WMI_SUPPORT
  1710. ntStatus =
  1711. USBH_SystemControl ((PDEVICE_EXTENSION_FDO) DeviceExtensionParent, Irp);
  1712. #else
  1713. ntStatus = USBH_PassIrp(Irp,
  1714. DeviceExtensionParent->TopOfStackDeviceObject);
  1715. #endif
  1716. break;
  1717. default:
  1718. //
  1719. // Unknown Irp -- complete with error
  1720. //
  1721. USBH_KdBreak(("Unknown Irp for Fdo %x Irp_Mj %x\n",
  1722. deviceObject, ioStackLocation->MajorFunction));
  1723. ntStatus = STATUS_NOT_IMPLEMENTED;
  1724. USBH_CompleteIrp(Irp, ntStatus);
  1725. break;
  1726. }
  1727. USBH_KdPrint((2,"' exit USBH_ParentDispatch Object %x Status %x\n",
  1728. deviceObject, ntStatus));
  1729. //
  1730. // always return a status code
  1731. //
  1732. return ntStatus;
  1733. }
  1734. NTSTATUS
  1735. USBH_FunctionUrbFilter(
  1736. IN PDEVICE_EXTENSION_FUNCTION DeviceExtensionFunction,
  1737. IN PIRP Irp
  1738. )
  1739. /*
  1740. * Description:
  1741. *
  1742. * Arguments:
  1743. *
  1744. * Return:
  1745. *
  1746. * NTSTATUS
  1747. *
  1748. * -- */
  1749. {
  1750. NTSTATUS ntStatus;
  1751. PIO_STACK_LOCATION ioStackLocation; // our stack location
  1752. PDEVICE_EXTENSION_PARENT deviceExtensionParent;
  1753. PURB urb;
  1754. USHORT function;
  1755. USBH_KdPrint((2,"'USBH_FunctionUrbFilter DeviceExtension %x Irp %x\n",
  1756. DeviceExtensionFunction, Irp));
  1757. deviceExtensionParent = DeviceExtensionFunction->DeviceExtensionParent;
  1758. LOGENTRY(LOG_PNP, "fURB", DeviceExtensionFunction, deviceExtensionParent,
  1759. deviceExtensionParent->ParentFlags);
  1760. ioStackLocation = IoGetCurrentIrpStackLocation(Irp);
  1761. urb = ioStackLocation->Parameters.Others.Argument1;
  1762. // check the command code code the URB
  1763. function = urb->UrbHeader.Function;
  1764. if (deviceExtensionParent->CurrentPowerState !=
  1765. PowerDeviceD0) {
  1766. // the child devices should not be passing in urbs
  1767. // unless th eparent is in D0
  1768. UsbhWarning(NULL,
  1769. "Parent Not in D0.\n",
  1770. TRUE);
  1771. }
  1772. switch(function) {
  1773. case URB_FUNCTION_SELECT_CONFIGURATION:
  1774. {
  1775. //
  1776. // if the requested config matches the current config
  1777. // then go ahead and return the current interface
  1778. // information for all interfaces requested.
  1779. //
  1780. PUSBD_INTERFACE_INFORMATION interface;
  1781. if (urb->UrbSelectConfiguration.ConfigurationDescriptor == NULL) {
  1782. USBH_KdBreak(("closing config on a composite device\n"));
  1783. //
  1784. // closing the configuration,
  1785. // just return success.
  1786. //
  1787. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  1788. ntStatus = STATUS_SUCCESS;
  1789. } else {
  1790. ULONG i;
  1791. //
  1792. // Normally the URB will contain only one interface.
  1793. // the special case is audio which may contain two
  1794. // so we have to have a check to handle this.
  1795. //
  1796. interface = &urb->UrbSelectConfiguration.Interface;
  1797. USBH_FunctionUrbFilter_Next:
  1798. USBH_KdPrint((2,"'interface = %x\n",
  1799. interface));
  1800. //
  1801. // should validate the requested interface against the
  1802. // current config.
  1803. //
  1804. USBH_KdBreak(("need some validation here!\n"));
  1805. USBH_ASSERT(urb->UrbSelectConfiguration.ConfigurationDescriptor->bConfigurationValue
  1806. == deviceExtensionParent->CurrentConfig);
  1807. // find the interface we are interested in
  1808. for (i=0; i< DeviceExtensionFunction->InterfaceCount; i++) {
  1809. PFUNCTION_INTERFACE functionInterface;
  1810. functionInterface =
  1811. &DeviceExtensionFunction->FunctionInterfaceList[i];
  1812. USBH_KdPrint((2,"'functionInterface = %x, %x\n",
  1813. functionInterface, functionInterface->InterfaceInformation));
  1814. if (functionInterface->InterfaceInformation->InterfaceNumber ==
  1815. interface->InterfaceNumber) {
  1816. break;
  1817. }
  1818. }
  1819. if (i < DeviceExtensionFunction->InterfaceCount) {
  1820. PFUNCTION_INTERFACE functionInterface;
  1821. functionInterface =
  1822. &DeviceExtensionFunction->FunctionInterfaceList[i];
  1823. if (functionInterface->InterfaceInformation->AlternateSetting !=
  1824. interface->AlternateSetting) {
  1825. PURB iUrb;
  1826. NTSTATUS localStatus;
  1827. PUSBD_INTERFACE_INFORMATION localInterface;
  1828. USHORT siz;
  1829. // client is requesting a different alternate setting
  1830. // we need to do a select_interface
  1831. siz =
  1832. (USHORT)(GET_SELECT_INTERFACE_REQUEST_SIZE(interface->NumberOfPipes));
  1833. iUrb = UsbhExAllocatePool(NonPagedPool, siz);
  1834. if (iUrb) {
  1835. localInterface = &iUrb->UrbSelectInterface.Interface;
  1836. iUrb->UrbSelectInterface.Hdr.Function =
  1837. URB_FUNCTION_SELECT_INTERFACE;
  1838. iUrb->UrbSelectInterface.Hdr.Length = siz;
  1839. iUrb->UrbSelectInterface.ConfigurationHandle =
  1840. DeviceExtensionFunction->ConfigurationHandle;
  1841. USBH_KdPrint((2,"'localInterface = %x\n",
  1842. localInterface));
  1843. RtlCopyMemory(localInterface,
  1844. interface,
  1845. interface->Length);
  1846. localStatus = USBH_SyncSubmitUrb(
  1847. deviceExtensionParent->TopOfStackDeviceObject,
  1848. iUrb);
  1849. UsbhExFreePool(functionInterface->InterfaceInformation);
  1850. functionInterface->InterfaceInformation =
  1851. UsbhExAllocatePool(NonPagedPool,
  1852. interface->Length);
  1853. RtlCopyMemory(functionInterface->InterfaceInformation,
  1854. localInterface,
  1855. localInterface->Length);
  1856. UsbhExFreePool(iUrb);
  1857. iUrb = NULL;
  1858. }
  1859. }
  1860. USBH_ASSERT(interface->Length ==
  1861. functionInterface->InterfaceInformation->Length);
  1862. RtlCopyMemory(interface,
  1863. functionInterface->InterfaceInformation,
  1864. functionInterface->InterfaceInformation->Length);
  1865. urb->UrbSelectConfiguration.ConfigurationHandle =
  1866. DeviceExtensionFunction->ConfigurationHandle;
  1867. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  1868. ntStatus = STATUS_SUCCESS;
  1869. } else {
  1870. ntStatus = STATUS_INVALID_PARAMETER;
  1871. }
  1872. //
  1873. // check for multiple interfaces e.g. audio
  1874. //
  1875. if (DeviceExtensionFunction->InterfaceCount > 1) {
  1876. interface = (PUSBD_INTERFACE_INFORMATION)
  1877. (((PUCHAR) interface) + interface->Length);
  1878. if ((PUCHAR)interface < (((PUCHAR) urb) +
  1879. urb->UrbSelectConfiguration.Hdr.Length)) {
  1880. goto USBH_FunctionUrbFilter_Next;
  1881. }
  1882. }
  1883. }
  1884. USBH_CompleteIrp(Irp, ntStatus);
  1885. }
  1886. break;
  1887. case URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE:
  1888. {
  1889. PUCHAR userBuffer = NULL;
  1890. ULONG bytesReturned;
  1891. //
  1892. // if we requesting the configuration descriptor then we
  1893. // will return it based on the information in our extension.
  1894. //
  1895. if (urb->UrbControlDescriptorRequest.DescriptorType ==
  1896. USB_CONFIGURATION_DESCRIPTOR_TYPE) {
  1897. if (urb->UrbControlDescriptorRequest.TransferBufferMDL) {
  1898. ntStatus = STATUS_INVALID_PARAMETER;
  1899. } else {
  1900. userBuffer =
  1901. urb->UrbControlDescriptorRequest.TransferBuffer;
  1902. ntStatus = USBH_BuildFunctionConfigurationDescriptor(
  1903. DeviceExtensionFunction,
  1904. userBuffer,
  1905. urb->UrbControlDescriptorRequest.TransferBufferLength,
  1906. &bytesReturned);
  1907. urb->UrbControlDescriptorRequest.TransferBufferLength =
  1908. bytesReturned;
  1909. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  1910. }
  1911. USBH_CompleteIrp(Irp, ntStatus);
  1912. } else {
  1913. ntStatus = USBH_PassIrp(Irp,
  1914. deviceExtensionParent->TopOfStackDeviceObject);
  1915. }
  1916. }
  1917. break;
  1918. default:
  1919. //
  1920. // forward the request to the parents PDO
  1921. //
  1922. ntStatus = USBH_PassIrp(Irp,
  1923. deviceExtensionParent->TopOfStackDeviceObject);
  1924. break;
  1925. }
  1926. return ntStatus;
  1927. }
  1928. VOID
  1929. USBH_CancelAllIrpsInList(
  1930. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent
  1931. )
  1932. /*
  1933. * Description:
  1934. *
  1935. * This function walks the list of devices and cancels all the queued
  1936. * ResetIrps in the list.
  1937. *
  1938. * Arguments:
  1939. *
  1940. * Return:
  1941. *
  1942. *
  1943. * -- */
  1944. {
  1945. PSINGLE_LIST_ENTRY listEntry;
  1946. PDEVICE_EXTENSION_FUNCTION deviceExtensionFunction;
  1947. listEntry = DeviceExtensionParent->FunctionList.Next;
  1948. while (listEntry) {
  1949. deviceExtensionFunction =
  1950. CONTAINING_RECORD(listEntry,
  1951. DEVICE_EXTENSION_FUNCTION,
  1952. ListEntry);
  1953. ASSERT_FUNCTION(deviceExtensionFunction);
  1954. if (deviceExtensionFunction->ResetIrp) {
  1955. USBH_CompleteIrp(deviceExtensionFunction->ResetIrp, STATUS_UNSUCCESSFUL);
  1956. deviceExtensionFunction->ResetIrp = NULL;
  1957. }
  1958. listEntry = listEntry->Next;
  1959. }
  1960. }
  1961. VOID
  1962. USBH_CompResetTimeoutWorker(
  1963. IN PVOID Context)
  1964. /* ++
  1965. *
  1966. * Description:
  1967. *
  1968. * Work item scheduled to handle a composite reset timeout.
  1969. *
  1970. *
  1971. * Arguments:
  1972. *
  1973. * Return:
  1974. *
  1975. * -- */
  1976. {
  1977. PUSBH_COMP_RESET_TIMEOUT_WORK_ITEM workItemCompResetTimeout;
  1978. PDEVICE_EXTENSION_PARENT deviceExtensionParent;
  1979. workItemCompResetTimeout = Context;
  1980. deviceExtensionParent = workItemCompResetTimeout->DeviceExtensionParent;
  1981. USBH_KdPrint((2,"'CompReset timeout\n"));
  1982. LOGENTRY(LOG_PNP, "CRTO", deviceExtensionParent, 0, 0);
  1983. USBH_KdPrint((2,"'*** (CRTW) WAIT parent mutex %x\n", deviceExtensionParent));
  1984. KeWaitForSingleObject(&deviceExtensionParent->ParentMutex,
  1985. Executive,
  1986. KernelMode,
  1987. FALSE,
  1988. NULL);
  1989. USBH_KdPrint((2,"'*** (CRTW) WAIT parent mutex done %x\n", deviceExtensionParent));
  1990. USBH_CancelAllIrpsInList(deviceExtensionParent);
  1991. USBH_KdPrint((2,"'*** (CRTW) RELEASE parent mutex %x\n", deviceExtensionParent));
  1992. KeReleaseSemaphore(&deviceExtensionParent->ParentMutex,
  1993. LOW_REALTIME_PRIORITY,
  1994. 1,
  1995. FALSE);
  1996. UsbhExFreePool(workItemCompResetTimeout);
  1997. }
  1998. VOID
  1999. USBH_CompResetTimeoutDPC(
  2000. IN PKDPC Dpc,
  2001. IN PVOID DeferredContext,
  2002. IN PVOID SystemArgument1,
  2003. IN PVOID SystemArgument2
  2004. )
  2005. /*++
  2006. Routine Description:
  2007. This routine runs at DISPATCH_LEVEL IRQL.
  2008. Arguments:
  2009. Dpc - Pointer to the DPC object.
  2010. DeferredContext -
  2011. SystemArgument1 - not used.
  2012. SystemArgument2 - not used.
  2013. Return Value:
  2014. None.
  2015. --*/
  2016. {
  2017. PCOMP_RESET_TIMEOUT_CONTEXT compResetTimeoutContext = DeferredContext;
  2018. PDEVICE_EXTENSION_PARENT deviceExtensionParent =
  2019. compResetTimeoutContext->DeviceExtensionParent;
  2020. BOOLEAN cancelFlag;
  2021. PUSBH_COMP_RESET_TIMEOUT_WORK_ITEM workItemCompResetTimeout;
  2022. USBH_KdPrint((2,"'COMP_RESET_TIMEOUT\n"));
  2023. // Take SpinLock here so that main routine won't write CancelFlag
  2024. // in the timeout context while we free the timeout context.
  2025. KeAcquireSpinLockAtDpcLevel(&deviceExtensionParent->ParentSpinLock);
  2026. cancelFlag = compResetTimeoutContext->CancelFlag;
  2027. deviceExtensionParent->CompResetTimeoutContext = NULL;
  2028. KeReleaseSpinLockFromDpcLevel(&deviceExtensionParent->ParentSpinLock);
  2029. UsbhExFreePool(compResetTimeoutContext);
  2030. if (!cancelFlag) {
  2031. //
  2032. // Schedule a work item to process this.
  2033. //
  2034. workItemCompResetTimeout = UsbhExAllocatePool(NonPagedPool,
  2035. sizeof(USBH_COMP_RESET_TIMEOUT_WORK_ITEM));
  2036. if (workItemCompResetTimeout) {
  2037. workItemCompResetTimeout->DeviceExtensionParent = deviceExtensionParent;
  2038. ExInitializeWorkItem(&workItemCompResetTimeout->WorkQueueItem,
  2039. USBH_CompResetTimeoutWorker,
  2040. workItemCompResetTimeout);
  2041. LOGENTRY(LOG_PNP, "crER", deviceExtensionParent,
  2042. &workItemCompResetTimeout->WorkQueueItem, 0);
  2043. ExQueueWorkItem(&workItemCompResetTimeout->WorkQueueItem,
  2044. DelayedWorkQueue);
  2045. // The WorkItem is freed by USBH_CompResetTimeoutWorker()
  2046. // Don't try to access the WorkItem after it is queued.
  2047. }
  2048. }
  2049. }
  2050. BOOLEAN
  2051. USBH_ListReadyForReset(
  2052. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent
  2053. )
  2054. /*
  2055. * Description:
  2056. *
  2057. * This function walks the list of devices to see if we are ready
  2058. * to do the actual reset.
  2059. *
  2060. * Arguments:
  2061. *
  2062. * Return:
  2063. *
  2064. * TRUE if we're ready, FALSE if we're not.
  2065. *
  2066. * -- */
  2067. {
  2068. PSINGLE_LIST_ENTRY listEntry;
  2069. PDEVICE_EXTENSION_FUNCTION deviceExtensionFunction;
  2070. listEntry = DeviceExtensionParent->FunctionList.Next;
  2071. while (listEntry) {
  2072. deviceExtensionFunction =
  2073. CONTAINING_RECORD(listEntry,
  2074. DEVICE_EXTENSION_FUNCTION,
  2075. ListEntry);
  2076. ASSERT_FUNCTION(deviceExtensionFunction);
  2077. if (!deviceExtensionFunction->ResetIrp)
  2078. return FALSE;
  2079. listEntry = listEntry->Next;
  2080. }
  2081. return TRUE;
  2082. }
  2083. NTSTATUS
  2084. USBH_ResetParentPort(
  2085. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent
  2086. )
  2087. /*++
  2088. Routine Description:
  2089. Calls the parent device to reset its port.
  2090. Arguments:
  2091. Return Value:
  2092. NTSTATUS
  2093. --*/
  2094. {
  2095. NTSTATUS ntStatus, status = STATUS_SUCCESS;
  2096. PIRP irp;
  2097. KEVENT event;
  2098. IO_STATUS_BLOCK ioStatus;
  2099. USBH_KdPrint((2,"'CompReset parent port\n"));
  2100. LOGENTRY(LOG_PNP, "CRPP", DeviceExtensionParent, 0, 0);
  2101. //
  2102. // issue a synchronous request
  2103. //
  2104. KeInitializeEvent(&event, NotificationEvent, FALSE);
  2105. irp = IoBuildDeviceIoControlRequest(
  2106. IOCTL_INTERNAL_USB_RESET_PORT,
  2107. DeviceExtensionParent->TopOfStackDeviceObject,
  2108. NULL,
  2109. 0,
  2110. NULL,
  2111. 0,
  2112. TRUE, /* INTERNAL */
  2113. &event,
  2114. &ioStatus);
  2115. if (irp == NULL) {
  2116. return STATUS_INSUFFICIENT_RESOURCES;
  2117. }
  2118. //
  2119. // Call the class driver to perform the operation. If the returned status
  2120. // is PENDING, wait for the request to complete.
  2121. //
  2122. ntStatus = IoCallDriver(DeviceExtensionParent->TopOfStackDeviceObject,
  2123. irp);
  2124. if (ntStatus == STATUS_PENDING) {
  2125. status = KeWaitForSingleObject(
  2126. &event,
  2127. Suspended,
  2128. KernelMode,
  2129. FALSE,
  2130. NULL);
  2131. } else {
  2132. ioStatus.Status = ntStatus;
  2133. }
  2134. ntStatus = ioStatus.Status;
  2135. return ntStatus;
  2136. }
  2137. VOID
  2138. USBH_CompositeResetPortWorker(
  2139. IN PVOID Context)
  2140. /* ++
  2141. *
  2142. * Description:
  2143. *
  2144. * Work item scheduled to process a composite port reset.
  2145. *
  2146. *
  2147. * Arguments:
  2148. *
  2149. * Return:
  2150. *
  2151. * -- */
  2152. {
  2153. PUSBH_COMP_RESET_WORK_ITEM workItemCompReset;
  2154. PSINGLE_LIST_ENTRY listEntry;
  2155. PDEVICE_EXTENSION_PARENT deviceExtensionParent;
  2156. PDEVICE_EXTENSION_FUNCTION deviceExtensionFunction;
  2157. USBH_KdPrint((2,"'Composite Reset Executing!\n"));
  2158. workItemCompReset = Context;
  2159. deviceExtensionParent = workItemCompReset->DeviceExtensionParent;
  2160. LOGENTRY(LOG_PNP, "CRW_", deviceExtensionParent, 0, 0);
  2161. // Send reset to parent (IoCallDriver)
  2162. USBH_ResetParentPort(deviceExtensionParent);
  2163. // Now, complete all Irps in list and set the Irps in the list to NULL.
  2164. USBH_KdPrint((2,"'*** (CRW) WAIT parent mutex %x\n", deviceExtensionParent));
  2165. KeWaitForSingleObject(&deviceExtensionParent->ParentMutex,
  2166. Executive,
  2167. KernelMode,
  2168. FALSE,
  2169. NULL);
  2170. USBH_KdPrint((2,"'*** (CRW) WAIT parent mutex done %x\n", deviceExtensionParent));
  2171. listEntry = deviceExtensionParent->FunctionList.Next;
  2172. while (listEntry) {
  2173. deviceExtensionFunction =
  2174. CONTAINING_RECORD(listEntry,
  2175. DEVICE_EXTENSION_FUNCTION,
  2176. ListEntry);
  2177. ASSERT_FUNCTION(deviceExtensionFunction);
  2178. // Although ResetIrp should usually be set here, we check anyway in
  2179. // case it had already been completed in USBH_CompleteAllIrpsInList.
  2180. //
  2181. if (deviceExtensionFunction->ResetIrp) {
  2182. USBH_CompleteIrp(deviceExtensionFunction->ResetIrp, STATUS_SUCCESS);
  2183. deviceExtensionFunction->ResetIrp = NULL;
  2184. }
  2185. listEntry = listEntry->Next;
  2186. }
  2187. USBH_KdPrint((2,"'*** (CRW) RELEASE parent mutex %x\n", deviceExtensionParent));
  2188. KeReleaseSemaphore(&deviceExtensionParent->ParentMutex,
  2189. LOW_REALTIME_PRIORITY,
  2190. 1,
  2191. FALSE);
  2192. UsbhExFreePool(workItemCompReset);
  2193. }
  2194. NTSTATUS
  2195. USBH_FunctionPdoDispatch(
  2196. IN PDEVICE_EXTENSION_FUNCTION DeviceExtensionFunction,
  2197. IN PIRP Irp
  2198. )
  2199. /*
  2200. * Description:
  2201. *
  2202. * This function handles calls to PDOs we have created
  2203. * since we are the bottom driver for the PDO it is up
  2204. * to us to complete the irp -- with one exception.
  2205. *
  2206. * api calls to the USB stack are forwarded directly
  2207. * to the PDO for the root hub which is owned by the USB
  2208. * HC.
  2209. *
  2210. * Arguments:
  2211. *
  2212. * Return:
  2213. *
  2214. * NTSTATUS
  2215. *
  2216. * -- */
  2217. {
  2218. NTSTATUS ntStatus = STATUS_SUCCESS;
  2219. PIO_STACK_LOCATION ioStackLocation; // our stack location
  2220. PDEVICE_OBJECT deviceObject;
  2221. PDEVICE_EXTENSION_PARENT deviceExtensionParent;
  2222. PCOMP_RESET_TIMEOUT_CONTEXT compResetTimeoutContext = NULL;
  2223. LARGE_INTEGER dueTime;
  2224. KIRQL irql;
  2225. BOOLEAN bCompleteIrp;
  2226. USBH_KdPrint((2,"'FunctionPdoDispatch DeviceExtension %x Irp %x\n",
  2227. DeviceExtensionFunction, Irp));
  2228. deviceObject = DeviceExtensionFunction->FunctionPhysicalDeviceObject;
  2229. deviceExtensionParent = DeviceExtensionFunction->DeviceExtensionParent;
  2230. //
  2231. // Get a pointer to IoStackLocation so we can retrieve parameters.
  2232. //
  2233. ioStackLocation = IoGetCurrentIrpStackLocation(Irp);
  2234. switch (ioStackLocation->MajorFunction) {
  2235. case IRP_MJ_CREATE:
  2236. USBH_KdPrint((2,"'PARENT PDO IRP_MJ_CREATE\n"));
  2237. ntStatus = STATUS_SUCCESS;
  2238. USBH_CompleteIrp(Irp, ntStatus);
  2239. break;
  2240. case IRP_MJ_CLOSE:
  2241. USBH_KdPrint((2,"'PARENT PDO IRP_MJ_CLOSE\n"));
  2242. ntStatus = STATUS_SUCCESS;
  2243. USBH_CompleteIrp(Irp, ntStatus);
  2244. break;
  2245. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  2246. {
  2247. ULONG ioControlCode;
  2248. USBH_KdPrint((2,"'Internal Device Control\n"));
  2249. if (deviceExtensionParent->ParentFlags & HUBFLAG_DEVICE_STOPPING) {
  2250. UsbhWarning(NULL,
  2251. "Client Device Driver is sending requests to a device that has been removed.\n",
  2252. FALSE);
  2253. ntStatus = STATUS_DEVICE_REMOVED;
  2254. USBH_CompleteIrp(Irp, ntStatus);
  2255. break;
  2256. }
  2257. ioControlCode = ioStackLocation->Parameters.DeviceIoControl.IoControlCode;
  2258. switch (ioControlCode) {
  2259. case IOCTL_INTERNAL_USB_GET_PORT_STATUS:
  2260. USBH_KdPrint((2,"'Composite GetPortStatus, pass on\n"));
  2261. ntStatus = USBH_PassIrp(Irp, deviceExtensionParent->TopOfStackDeviceObject);
  2262. break;
  2263. case IOCTL_INTERNAL_USB_RESET_PORT:
  2264. LOGENTRY(LOG_PNP, "fRES", deviceExtensionParent, 0, 0);
  2265. USBH_KdPrint((2,"'Composite Reset Requested\n"));
  2266. if (deviceExtensionParent->CurrentPowerState !=
  2267. PowerDeviceD0) {
  2268. // the child devices should not be resetting
  2269. // unless the parent is in D0
  2270. UsbhWarning(NULL,
  2271. "Parent Not in D0.\n",
  2272. TRUE);
  2273. }
  2274. if (DeviceExtensionFunction->ResetIrp) {
  2275. ntStatus = STATUS_UNSUCCESSFUL;
  2276. USBH_CompleteIrp(Irp, ntStatus);
  2277. } else {
  2278. ntStatus = STATUS_PENDING;
  2279. USBH_KdPrint((2,"'***WAIT parent mutex %x\n", deviceExtensionParent));
  2280. KeWaitForSingleObject(&deviceExtensionParent->ParentMutex,
  2281. Executive,
  2282. KernelMode,
  2283. FALSE,
  2284. NULL);
  2285. USBH_KdPrint((2,"'***WAIT parent mutex done %x\n", deviceExtensionParent));
  2286. DeviceExtensionFunction->ResetIrp = Irp;
  2287. if (USBH_ListReadyForReset(deviceExtensionParent)) {
  2288. PUSBH_COMP_RESET_WORK_ITEM workItemCompReset;
  2289. //
  2290. // "Cancel" watchdog timer.
  2291. //
  2292. // Take SpinLock here so that DPC routine won't free
  2293. // the timeout context while we write the CancelFlag
  2294. // in the timeout context.
  2295. //
  2296. KeAcquireSpinLock(&deviceExtensionParent->ParentSpinLock,
  2297. &irql);
  2298. if (deviceExtensionParent->CompResetTimeoutContext) {
  2299. compResetTimeoutContext = deviceExtensionParent->CompResetTimeoutContext;
  2300. compResetTimeoutContext->CancelFlag = TRUE;
  2301. if (KeCancelTimer(&compResetTimeoutContext->TimeoutTimer)) {
  2302. //
  2303. // We cancelled the timer before it could run. Free the context.
  2304. //
  2305. deviceExtensionParent->CompResetTimeoutContext = NULL;
  2306. UsbhExFreePool(compResetTimeoutContext);
  2307. }
  2308. }
  2309. KeReleaseSpinLock(&deviceExtensionParent->ParentSpinLock,
  2310. irql);
  2311. //
  2312. // Schedule a work item to process this reset.
  2313. //
  2314. workItemCompReset = UsbhExAllocatePool(NonPagedPool,
  2315. sizeof(USBH_COMP_RESET_WORK_ITEM));
  2316. USBH_ASSERT(workItemCompReset);
  2317. if (workItemCompReset) {
  2318. workItemCompReset->DeviceExtensionParent = deviceExtensionParent;
  2319. ExInitializeWorkItem(&workItemCompReset->WorkQueueItem,
  2320. USBH_CompositeResetPortWorker,
  2321. workItemCompReset);
  2322. LOGENTRY(LOG_PNP, "rCMP", deviceExtensionParent,
  2323. &workItemCompReset->WorkQueueItem, 0);
  2324. ExQueueWorkItem(&workItemCompReset->WorkQueueItem,
  2325. DelayedWorkQueue);
  2326. // The WorkItem is freed by USBH_CompositeResetPortWorker()
  2327. // Don't try to access the WorkItem after it is queued.
  2328. } else {
  2329. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2330. }
  2331. } else if (!deviceExtensionParent->CompResetTimeoutContext) {
  2332. // Start watchdog timer if not already started.
  2333. //
  2334. // When timer expires, timer routine should
  2335. // complete all Irps in the list with an error
  2336. // and clear the Irps in the list.
  2337. USBH_KdPrint((2,"'Start composite port reset timeout\n"));
  2338. compResetTimeoutContext = UsbhExAllocatePool(NonPagedPool,
  2339. sizeof(*compResetTimeoutContext));
  2340. USBH_ASSERT(compResetTimeoutContext);
  2341. if (compResetTimeoutContext) {
  2342. compResetTimeoutContext->CancelFlag = FALSE;
  2343. // Maintain links between the device extension and the
  2344. // timeout context.
  2345. deviceExtensionParent->CompResetTimeoutContext = compResetTimeoutContext;
  2346. compResetTimeoutContext->DeviceExtensionParent = deviceExtensionParent;
  2347. KeInitializeTimer(&compResetTimeoutContext->TimeoutTimer);
  2348. KeInitializeDpc(&compResetTimeoutContext->TimeoutDpc,
  2349. USBH_CompResetTimeoutDPC,
  2350. compResetTimeoutContext);
  2351. dueTime.QuadPart = -10000 * COMP_RESET_TIMEOUT;
  2352. KeSetTimer(&compResetTimeoutContext->TimeoutTimer,
  2353. dueTime,
  2354. &compResetTimeoutContext->TimeoutDpc);
  2355. } else {
  2356. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2357. }
  2358. }
  2359. if (ntStatus == STATUS_PENDING) {
  2360. IoMarkIrpPending(Irp);
  2361. } else {
  2362. USBH_CompleteIrp(Irp, ntStatus);
  2363. }
  2364. USBH_KdPrint((2,"'***RELEASE parent mutex %x\n", deviceExtensionParent));
  2365. KeReleaseSemaphore(&deviceExtensionParent->ParentMutex,
  2366. LOW_REALTIME_PRIORITY,
  2367. 1,
  2368. FALSE);
  2369. }
  2370. break;
  2371. case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO:
  2372. TEST_TRAP(); //shouldn't see this
  2373. break;
  2374. case IOCTL_INTERNAL_USB_SUBMIT_URB:
  2375. ntStatus = USBH_FunctionUrbFilter(DeviceExtensionFunction, Irp);
  2376. break;
  2377. case IOCTL_INTERNAL_USB_GET_BUS_INFO:
  2378. // this api returns some BW info that drivers
  2379. // may need -- pass it on
  2380. ntStatus = USBH_PassIrp(Irp, deviceExtensionParent->TopOfStackDeviceObject);
  2381. break;
  2382. default:
  2383. USBH_KdPrint((2,"'InternalDeviceControl IOCTL unknown pass on\n"));
  2384. ntStatus = STATUS_INVALID_PARAMETER;
  2385. USBH_CompleteIrp(Irp, ntStatus);
  2386. }
  2387. break;
  2388. }
  2389. case IRP_MJ_PNP:
  2390. USBH_KdPrint((2,"'IRP_MJ_PNP\n"));
  2391. ntStatus = USBH_FunctionPdoPnP(DeviceExtensionFunction, Irp,
  2392. ioStackLocation->MinorFunction, &bCompleteIrp);
  2393. if (bCompleteIrp) {
  2394. USBH_CompleteIrp(Irp, ntStatus);
  2395. }
  2396. break;
  2397. case IRP_MJ_POWER:
  2398. USBH_KdPrint((2,"'IRP_MJ_POWER\n"));
  2399. ntStatus = USBH_FunctionPdoPower(DeviceExtensionFunction, Irp, ioStackLocation->MinorFunction);
  2400. break;
  2401. case IRP_MJ_SYSTEM_CONTROL:
  2402. USBH_KdPrint((2,"'IRP_MJ_SYSTEM_CONTROL\n"));
  2403. ntStatus = STATUS_NOT_SUPPORTED;
  2404. USBH_CompleteIrp(Irp, ntStatus);
  2405. break;
  2406. case IRP_MJ_DEVICE_CONTROL:
  2407. //
  2408. // Note: if we ever do find a reason to handle this, be sure to
  2409. // not forward IOCTL_KS_PROPERTY / KSPROPSETID_DrmAudioStream /
  2410. // KSPROPERTY_DRMAUDIOSTREAM_SETCONTENTID to next driver! Otherwise
  2411. // this might not be DRM compliant.
  2412. //
  2413. USBH_KdBreak(("Unhandled IRP_MJ_DEVICE_CONTROL for Pdo %x Irp_Mj %x\n",
  2414. deviceObject, ioStackLocation->MajorFunction));
  2415. ntStatus = STATUS_INVALID_PARAMETER;
  2416. USBH_CompleteIrp(Irp, ntStatus);
  2417. break;
  2418. default:
  2419. // Unknown Irp, shouldn't be here.
  2420. USBH_KdBreak(("Unhandled Irp for Pdo %x Irp_Mj %x\n",
  2421. deviceObject, ioStackLocation->MajorFunction));
  2422. ntStatus = STATUS_INVALID_PARAMETER;
  2423. USBH_CompleteIrp(Irp, ntStatus);
  2424. break;
  2425. }
  2426. USBH_KdPrint((2,"' exit USBH_FunctionPdoDispatch Object %x -- Status %x\n",
  2427. deviceObject, ntStatus));
  2428. return ntStatus;
  2429. }
  2430. NTSTATUS
  2431. USBH_BuildFunctionConfigurationDescriptor(
  2432. IN PDEVICE_EXTENSION_FUNCTION DeviceExtensionFunction,
  2433. IN OUT PUCHAR Buffer,
  2434. IN ULONG BufferLength,
  2435. OUT PULONG BytesReturned
  2436. )
  2437. /*
  2438. * Description:
  2439. *
  2440. * This function creates a configuration descriptor (with all interface &
  2441. * endpoints) for a give function.
  2442. *
  2443. * Arguments:
  2444. *
  2445. * Buffer - buffer to put descriptor in
  2446. *
  2447. * BufferLength - max size of this buffer.
  2448. *
  2449. * Return:
  2450. *
  2451. * NTSTATUS
  2452. *
  2453. * -- */
  2454. {
  2455. NTSTATUS ntStatus = STATUS_SUCCESS;
  2456. PDEVICE_EXTENSION_PARENT deviceExtensionParent;
  2457. PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
  2458. PVOID scratch;
  2459. ULONG length, i;
  2460. PUCHAR pch;
  2461. USBH_KdPrint((2,"'USBH_BuildFunctionConfigurationDescriptor\n"));
  2462. deviceExtensionParent = DeviceExtensionFunction->DeviceExtensionParent;
  2463. //
  2464. // scratch area to build descriptor in
  2465. //
  2466. *BytesReturned = 0;
  2467. configurationDescriptor = deviceExtensionParent->ConfigurationDescriptor;
  2468. if (!configurationDescriptor || !configurationDescriptor->wTotalLength) {
  2469. return STATUS_INVALID_PARAMETER;
  2470. }
  2471. scratch = UsbhExAllocatePool(PagedPool, configurationDescriptor->
  2472. wTotalLength);
  2473. if (scratch) {
  2474. configurationDescriptor = scratch;
  2475. pch = scratch;
  2476. length = sizeof(USB_CONFIGURATION_DESCRIPTOR);
  2477. RtlCopyMemory(pch,
  2478. deviceExtensionParent->ConfigurationDescriptor,
  2479. length);
  2480. pch+=length;
  2481. //
  2482. // now copy the interfaces
  2483. //
  2484. for (i=0; i< DeviceExtensionFunction->InterfaceCount; i++) {
  2485. PFUNCTION_INTERFACE functionInterface;
  2486. functionInterface =
  2487. &DeviceExtensionFunction->FunctionInterfaceList[i];
  2488. RtlCopyMemory(pch,
  2489. functionInterface->InterfaceDescriptor,
  2490. functionInterface->InterfaceDescriptorLength);
  2491. pch+=functionInterface->InterfaceDescriptorLength;
  2492. length+=functionInterface->InterfaceDescriptorLength;
  2493. }
  2494. configurationDescriptor->bNumInterfaces = (UCHAR) DeviceExtensionFunction->InterfaceCount;
  2495. configurationDescriptor->wTotalLength = (USHORT) length;
  2496. //
  2497. // now copy what we can in to the user buffer
  2498. //
  2499. if (BufferLength >= configurationDescriptor->wTotalLength) {
  2500. *BytesReturned = configurationDescriptor->wTotalLength;
  2501. } else {
  2502. *BytesReturned = BufferLength;
  2503. }
  2504. RtlCopyMemory(Buffer,
  2505. scratch,
  2506. *BytesReturned);
  2507. USBH_KdBreak(("'USBH_BuildFunctionConfigurationDescriptor, buffer = %x scratch = %x\n",
  2508. Buffer, scratch));
  2509. UsbhExFreePool(scratch);
  2510. } else {
  2511. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2512. }
  2513. return ntStatus;
  2514. }
  2515. VOID
  2516. USBH_ParentCompleteFunctionWakeIrps(
  2517. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent,
  2518. IN NTSTATUS NtStatus
  2519. )
  2520. /*++
  2521. Routine Description:
  2522. Called when a wake irp completes for a hub
  2523. Propagates the wake irp completion to all the function (children).
  2524. Arguments:
  2525. DeviceObject - Pointer to the device object for the class device.
  2526. Return Value:
  2527. The function value is the final status from the operation.
  2528. --*/
  2529. {
  2530. PDEVICE_EXTENSION_FUNCTION deviceExtensionFunction;
  2531. PSINGLE_LIST_ENTRY listEntry;
  2532. PIRP irp;
  2533. KIRQL irql;
  2534. LONG pendingFunctionWWs;
  2535. ULONG i;
  2536. PIRP irpArray[128]; // Limited to 127 functions in the list.
  2537. LOGENTRY(LOG_PNP, "fWWc", DeviceExtensionParent, NtStatus, 0);
  2538. //
  2539. // Here we are walking the list of child PDOs, which should never change.
  2540. // (The number of interfaces on a USB device is fixed so long as the parent
  2541. // is here the number of children stay constant.)
  2542. //
  2543. // Therefore we need no protection for parent->FunctionList.
  2544. //
  2545. // Wrongo! The list may not change, but the WW IRPs attributed to the
  2546. // list can, so we must take the spinlock here.
  2547. IoAcquireCancelSpinLock(&irql);
  2548. listEntry = DeviceExtensionParent->FunctionList.Next;
  2549. i = 0;
  2550. while (listEntry) {
  2551. deviceExtensionFunction =
  2552. CONTAINING_RECORD(listEntry,
  2553. DEVICE_EXTENSION_FUNCTION,
  2554. ListEntry);
  2555. irp = deviceExtensionFunction->WaitWakeIrp;
  2556. deviceExtensionFunction->WaitWakeIrp = NULL;
  2557. if (irp) {
  2558. IoSetCancelRoutine(irp, NULL);
  2559. pendingFunctionWWs =
  2560. InterlockedDecrement(&DeviceExtensionParent->NumberFunctionWakeIrps);
  2561. if (0 == pendingFunctionWWs) {
  2562. LOGENTRY(LOG_PNP, "fWWx", DeviceExtensionParent,
  2563. DeviceExtensionParent->PendingWakeIrp, 0);
  2564. DeviceExtensionParent->PendingWakeIrp = NULL;
  2565. DeviceExtensionParent->ParentFlags &= ~HUBFLAG_PENDING_WAKE_IRP;
  2566. }
  2567. irpArray[i++] = irp;
  2568. }
  2569. listEntry = listEntry->Next;
  2570. }
  2571. irpArray[i] = NULL; // Terminate array
  2572. IoReleaseCancelSpinLock(irql);
  2573. USBH_ASSERT(DeviceExtensionParent->PendingWakeIrp == NULL);
  2574. // Ok, we have queued all the function wake IRPs and have released the
  2575. // cancel spinlock. Let's complete all the IRPs.
  2576. i = 0;
  2577. while (irpArray[i]) {
  2578. USBH_KdPrint((1,"'completing function WaitWake irp(%x) for PARENT VID %x, PID %x\n\n",
  2579. NtStatus,
  2580. DeviceExtensionParent->DeviceDescriptor.idVendor, \
  2581. DeviceExtensionParent->DeviceDescriptor.idProduct));
  2582. irpArray[i]->IoStatus.Status = NtStatus;
  2583. PoStartNextPowerIrp(irpArray[i]);
  2584. IoCompleteRequest(irpArray[i], IO_NO_INCREMENT);
  2585. i++;
  2586. }
  2587. }
  2588. NTSTATUS
  2589. USBH_ParentPoRequestD0Completion(
  2590. IN PDEVICE_OBJECT DeviceObject,
  2591. IN UCHAR MinorFunction,
  2592. IN POWER_STATE PowerState,
  2593. IN PVOID Context,
  2594. IN PIO_STATUS_BLOCK IoStatus
  2595. )
  2596. /*++
  2597. Routine Description:
  2598. Called when a wake irp completes for a hub
  2599. Arguments:
  2600. DeviceObject - Pointer to the device object for the class device.
  2601. Irp - Irp completed.
  2602. Context - Driver defined context.
  2603. Return Value:
  2604. The function value is the final status from the operation.
  2605. --*/
  2606. {
  2607. NTSTATUS ntStatus;
  2608. PDEVICE_EXTENSION_PARENT deviceExtensionParent = Context;
  2609. ntStatus = IoStatus->Status;
  2610. USBH_KdPrint((1,"'WaitWake D0 completion(%x) for PARENT VID %x, PID %x\n",
  2611. ntStatus,
  2612. deviceExtensionParent->DeviceDescriptor.idVendor, \
  2613. deviceExtensionParent->DeviceDescriptor.idProduct));
  2614. LOGENTRY(LOG_PNP, "pWD0", deviceExtensionParent,
  2615. deviceExtensionParent->PendingWakeIrp,
  2616. 0);
  2617. //
  2618. // Device has been powered on. Now we must complete the function that
  2619. // caused the parent to awake.
  2620. //
  2621. // Since of course we cannot tell them apart we must complete all function
  2622. // WW Irps.
  2623. //
  2624. USBH_ParentCompleteFunctionWakeIrps(deviceExtensionParent, STATUS_SUCCESS);
  2625. return ntStatus;
  2626. }
  2627. NTSTATUS
  2628. USBH_ParentWaitWakeIrpCompletion(
  2629. IN PDEVICE_OBJECT DeviceObject,
  2630. IN UCHAR MinorFunction,
  2631. IN POWER_STATE PowerState,
  2632. IN PVOID Context,
  2633. IN PIO_STATUS_BLOCK IoStatus
  2634. )
  2635. /*++
  2636. Routine Description:
  2637. Called when a wake irp completes for a composite device
  2638. Arguments:
  2639. DeviceObject - Pointer to the device object for the class device.
  2640. Irp - Irp completed.
  2641. Context - Driver defined context.
  2642. Return Value:
  2643. The function value is the final status from the operation.
  2644. --*/
  2645. {
  2646. NTSTATUS ntStatus;
  2647. PDEVICE_EXTENSION_PARENT deviceExtensionParent = Context;
  2648. POWER_STATE powerState;
  2649. ntStatus = IoStatus->Status;
  2650. USBH_KdPrint((1,"'WaitWake completion(%x) for PARENT VID %x, PID %x\n",
  2651. ntStatus,
  2652. deviceExtensionParent->DeviceDescriptor.idVendor, \
  2653. deviceExtensionParent->DeviceDescriptor.idProduct));
  2654. LOGENTRY(LOG_PNP, "pWWc", deviceExtensionParent,
  2655. ntStatus,
  2656. 0);
  2657. // first we power our device back on
  2658. if (NT_SUCCESS(ntStatus)) {
  2659. powerState.DeviceState = PowerDeviceD0;
  2660. PoRequestPowerIrp(deviceExtensionParent->PhysicalDeviceObject,
  2661. IRP_MN_SET_POWER,
  2662. powerState,
  2663. USBH_ParentPoRequestD0Completion,
  2664. deviceExtensionParent,
  2665. NULL);
  2666. // USBH_ParentPoRequestD0Completion must complete the
  2667. // wake irp
  2668. ntStatus = STATUS_SUCCESS;
  2669. } else {
  2670. // complete the child wake requests with an error
  2671. USBH_ParentCompleteFunctionWakeIrps(deviceExtensionParent,
  2672. ntStatus);
  2673. }
  2674. return ntStatus;
  2675. }
  2676. NTSTATUS
  2677. USBH_ParentSubmitWaitWakeIrp(
  2678. IN PDEVICE_EXTENSION_PARENT DeviceExtensionParent
  2679. )
  2680. /*++
  2681. Routine Description:
  2682. called when a child Pdo is enabled for wakeup, this
  2683. function allocates a wait wake irp and passes it to
  2684. the parents PDO.
  2685. Arguments:
  2686. Return Value:
  2687. --*/
  2688. {
  2689. PIRP irp;
  2690. NTSTATUS ntStatus;
  2691. POWER_STATE powerState;
  2692. USBH_ASSERT (NULL == DeviceExtensionParent->PendingWakeIrp);
  2693. LOGENTRY(LOG_PNP, "prWI", DeviceExtensionParent,
  2694. 0,
  2695. 0);
  2696. USBH_ASSERT(DeviceExtensionParent->PendingWakeIrp == NULL);
  2697. DeviceExtensionParent->ParentFlags |= HUBFLAG_PENDING_WAKE_IRP;
  2698. powerState.DeviceState = DeviceExtensionParent->SystemWake;
  2699. ntStatus = PoRequestPowerIrp(DeviceExtensionParent->PhysicalDeviceObject,
  2700. IRP_MN_WAIT_WAKE,
  2701. powerState,
  2702. USBH_ParentWaitWakeIrpCompletion,
  2703. DeviceExtensionParent,
  2704. &irp);
  2705. if (ntStatus == STATUS_PENDING) {
  2706. if (DeviceExtensionParent->ParentFlags & HUBFLAG_PENDING_WAKE_IRP) {
  2707. DeviceExtensionParent->PendingWakeIrp = irp;
  2708. }
  2709. }
  2710. USBH_KdPrint((2,
  2711. "'ntStatus from PoRequestPowerIrp for wait_wake to parent PDO = 0x%x\n", ntStatus));
  2712. return ntStatus;
  2713. }