Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1627 lines
52 KiB

  1. /*
  2. *************************************************************************
  3. * File: PARENT.C
  4. *
  5. * Module: USBCCGP.SYS
  6. * USB Common Class Generic Parent driver.
  7. *
  8. * Copyright (c) 1998 Microsoft Corporation
  9. *
  10. *
  11. * Author: ervinp
  12. *
  13. *************************************************************************
  14. */
  15. #include <wdm.h>
  16. #include <usbdi.h>
  17. #include <usbdlib.h>
  18. #include <usbioctl.h>
  19. #include <ntddstor.h>
  20. #include "usbccgp.h"
  21. #include "security.h"
  22. #include "debug.h"
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(PAGE, GetInterfaceList)
  25. #pragma alloc_text(PAGE, GetConfigDescriptor)
  26. #pragma alloc_text(PAGE, TryGetConfigDescriptor)
  27. #pragma alloc_text(PAGE, GetDeviceDescriptor)
  28. #pragma alloc_text(PAGE, GetParentFdoCapabilities)
  29. #pragma alloc_text(PAGE, StartParentFdo)
  30. #pragma alloc_text(PAGE, QueryParentDeviceRelations)
  31. #endif
  32. /*
  33. ********************************************************************************
  34. * SubmitUrb
  35. ********************************************************************************
  36. *
  37. *
  38. * Send the URB to the USB device.
  39. * If synchronous is TRUE,
  40. * ignore the completion info and synchonize the IRP;
  41. * otherwise, don't synchronize and set the provided completion
  42. * routine for the IRP.
  43. */
  44. NTSTATUS SubmitUrb( PPARENT_FDO_EXT parentFdoExt,
  45. PURB urb,
  46. BOOLEAN synchronous,
  47. PVOID completionRoutine,
  48. PVOID completionContext)
  49. {
  50. PIRP irp;
  51. NTSTATUS status;
  52. /*
  53. * Allocate the IRP to send the buffer down the USB stack.
  54. *
  55. * Don't use IoBuildDeviceIoControlRequest (because it queues
  56. * the IRP on the current thread's irp list and may
  57. * cause the calling process to hang if the IopCompleteRequest APC
  58. * does not fire and dequeue the IRP).
  59. */
  60. irp = IoAllocateIrp(parentFdoExt->topDevObj->StackSize, FALSE);
  61. if (irp){
  62. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  63. nextSp->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  64. nextSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
  65. /*
  66. * Attach the URB to this IRP.
  67. */
  68. nextSp->Parameters.Others.Argument1 = urb;
  69. if (synchronous){
  70. status = CallNextDriverSync(parentFdoExt, irp);
  71. IoFreeIrp(irp);
  72. }
  73. else {
  74. /*
  75. * Caller's completion routine will free the irp when it completes.
  76. * It will also decrement the pendingActionCount.
  77. */
  78. ASSERT(completionRoutine);
  79. ASSERT(completionContext);
  80. IoSetCompletionRoutine( irp,
  81. completionRoutine,
  82. completionContext,
  83. TRUE, TRUE, TRUE);
  84. IncrementPendingActionCount(parentFdoExt);
  85. status = IoCallDriver(parentFdoExt->topDevObj, irp);
  86. }
  87. }
  88. else {
  89. status = STATUS_INSUFFICIENT_RESOURCES;
  90. }
  91. return status;
  92. }
  93. /*
  94. * GetInterfaceList
  95. *
  96. *
  97. */
  98. PUSBD_INTERFACE_LIST_ENTRY GetInterfaceList(
  99. PPARENT_FDO_EXT parentFdoExt,
  100. PUSB_CONFIGURATION_DESCRIPTOR configDesc)
  101. {
  102. PUSBD_INTERFACE_LIST_ENTRY interfaceList;
  103. PAGED_CODE();
  104. if (configDesc->bNumInterfaces > 0){
  105. interfaceList = ALLOCPOOL( NonPagedPool,
  106. (configDesc->bNumInterfaces+1) * sizeof(USBD_INTERFACE_LIST_ENTRY));
  107. if (interfaceList){
  108. ULONG i;
  109. /*
  110. * Parse out the interface descriptors
  111. */
  112. for (i = 0; i < configDesc->bNumInterfaces; i++){
  113. PUSB_INTERFACE_DESCRIPTOR interfaceDesc;
  114. interfaceDesc = USBD_ParseConfigurationDescriptorEx(
  115. configDesc,
  116. configDesc,
  117. i,
  118. 0,
  119. -1,
  120. -1,
  121. -1);
  122. ASSERT(interfaceDesc);
  123. interfaceList[i].InterfaceDescriptor = interfaceDesc;
  124. /*
  125. * The .Interface field will be filled in when we do the SELECT_CONFIG.
  126. */
  127. interfaceList[i].Interface = BAD_POINTER;
  128. }
  129. /*
  130. * Terminate the list.
  131. */
  132. interfaceList[i].InterfaceDescriptor = NULL;
  133. interfaceList[i].Interface = NULL;
  134. }
  135. else {
  136. TRAP("Memory allocation failed");
  137. }
  138. }
  139. else {
  140. ASSERT(configDesc->bNumInterfaces > 0);
  141. interfaceList = NULL;
  142. }
  143. ASSERT(interfaceList);
  144. return interfaceList;
  145. }
  146. VOID FreeInterfaceList(PPARENT_FDO_EXT parentFdoExt, BOOLEAN freeListItself)
  147. {
  148. if (ISPTR(parentFdoExt->interfaceList)){
  149. ULONG i;
  150. for (i = 0; i < parentFdoExt->configDesc->bNumInterfaces; i++){
  151. if (ISPTR(parentFdoExt->interfaceList[i].Interface)){
  152. PUSBD_INTERFACE_LIST_ENTRY iface = &parentFdoExt->interfaceList[i];
  153. ASSERT(iface->Interface->Length >= FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes));
  154. FREEPOOL(iface->Interface);
  155. iface->Interface = BAD_POINTER;
  156. }
  157. }
  158. if (freeListItself){
  159. FREEPOOL(parentFdoExt->interfaceList);
  160. parentFdoExt->interfaceList = BAD_POINTER;
  161. }
  162. }
  163. }
  164. NTSTATUS ParentSelectConfiguration( PPARENT_FDO_EXT parentFdoExt,
  165. PUSB_CONFIGURATION_DESCRIPTOR configDesc,
  166. PUSBD_INTERFACE_LIST_ENTRY interfaceList)
  167. {
  168. NTSTATUS status;
  169. PURB urb;
  170. /*
  171. * Use USBD_CreateConfigurationRequestEx to allocate
  172. * an URB of the right size (including the appended
  173. * interface and pipe info we'll get back from
  174. * the URB_FUNCTION_SELECT_CONFIGURATION urb).
  175. */
  176. urb = USBD_CreateConfigurationRequestEx(configDesc, interfaceList);
  177. if (urb){
  178. status = SubmitUrb(parentFdoExt, urb, TRUE, NULL, NULL);
  179. if (NT_SUCCESS(status)){
  180. ULONG i;
  181. /*
  182. * This new SELECT_CONFIGURATION URB call caused
  183. * USBD_SelectConfiguration to close the current
  184. * configuration handle. So we need to update
  185. * our handles.
  186. */
  187. parentFdoExt->selectedConfigHandle = urb->UrbSelectConfiguration.ConfigurationHandle;
  188. /*
  189. * Each interfaceList's Interface pointer points
  190. * to a part of the URB's buffer. So copy these
  191. * out before freeing the urb.
  192. */
  193. for (i = 0; i < configDesc->bNumInterfaces; i++){
  194. PVOID ifaceInfo = interfaceList[i].Interface;
  195. if (ifaceInfo){
  196. ULONG len = interfaceList[i].Interface->Length;
  197. ASSERT(len >= FIELD_OFFSET(USBD_INTERFACE_INFORMATION, Pipes));
  198. interfaceList[i].Interface = ALLOCPOOL(NonPagedPool, len);
  199. if (interfaceList[i].Interface){
  200. RtlCopyMemory(interfaceList[i].Interface, ifaceInfo, len);
  201. }
  202. else {
  203. status = STATUS_INSUFFICIENT_RESOURCES;
  204. break;
  205. }
  206. }
  207. else {
  208. ASSERT(ifaceInfo);
  209. status = STATUS_UNSUCCESSFUL;
  210. break;
  211. }
  212. }
  213. }
  214. else {
  215. DBGWARN(("URB_FUNCTION_SELECT_CONFIGURATION failed with %xh", status));
  216. }
  217. FREEPOOL(urb);
  218. }
  219. else {
  220. DBGERR(("USBD_CreateConfigurationRequest... failed"));
  221. status = STATUS_INSUFFICIENT_RESOURCES;
  222. }
  223. return status;
  224. }
  225. VOID ParentCloseConfiguration(PPARENT_FDO_EXT parentFdoExt)
  226. {
  227. URB urb;
  228. NTSTATUS status;
  229. urb.UrbHeader.Length = sizeof(struct _URB_SELECT_CONFIGURATION);
  230. urb.UrbHeader.Function = URB_FUNCTION_SELECT_CONFIGURATION;
  231. urb.UrbSelectConfiguration.ConfigurationDescriptor = NULL;
  232. status = SubmitUrb(parentFdoExt, &urb, TRUE, NULL, NULL);
  233. ASSERT(NT_SUCCESS(status));
  234. }
  235. /*
  236. * TryGetConfigDescriptor
  237. *
  238. * Try to get configuration descriptor for device .
  239. *
  240. *
  241. */
  242. NTSTATUS TryGetConfigDescriptor(PPARENT_FDO_EXT parentFdoExt)
  243. {
  244. URB urb;
  245. NTSTATUS status;
  246. USB_CONFIGURATION_DESCRIPTOR configDescBase = {0};
  247. PAGED_CODE();
  248. /*
  249. * Get the first part of the configuration descriptor.
  250. * It will tell us the size of the full configuration descriptor,
  251. * including all the following interface descriptors, etc.
  252. */
  253. UsbBuildGetDescriptorRequest(&urb,
  254. (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  255. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  256. 0,
  257. 0,
  258. (PVOID)&configDescBase,
  259. NULL,
  260. sizeof(USB_CONFIGURATION_DESCRIPTOR),
  261. NULL);
  262. status = SubmitUrb(parentFdoExt, &urb, TRUE, NULL, NULL);
  263. if (NT_SUCCESS(status)){
  264. ULONG configDescLen = configDescBase.wTotalLength;
  265. /*
  266. * Now allocate the right-sized buffer for the full configuration descriptor.
  267. */
  268. ASSERT(configDescLen < 0x1000);
  269. parentFdoExt->configDesc = ALLOCPOOL(NonPagedPool, configDescLen);
  270. if (parentFdoExt->configDesc){
  271. RtlZeroMemory(parentFdoExt->configDesc, configDescLen);
  272. UsbBuildGetDescriptorRequest(&urb,
  273. (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  274. USB_CONFIGURATION_DESCRIPTOR_TYPE,
  275. 0,
  276. 0,
  277. parentFdoExt->configDesc,
  278. NULL,
  279. configDescLen,
  280. NULL);
  281. status = SubmitUrb(parentFdoExt, &urb, TRUE, NULL, NULL);
  282. if (NT_SUCCESS(status)){
  283. ASSERT(urb.UrbControlDescriptorRequest.TransferBufferLength == configDescLen);
  284. ASSERT(parentFdoExt->configDesc->wTotalLength == configDescLen);
  285. DBGDUMPBYTES("Got config desc", parentFdoExt->configDesc, parentFdoExt->configDesc->wTotalLength);
  286. parentFdoExt->selectedConfigDesc = parentFdoExt->configDesc;
  287. parentFdoExt->selectedConfigHandle = urb.UrbSelectConfiguration.ConfigurationHandle;
  288. } else {
  289. /*
  290. * Deallocate the configDesc buffer if URB submission failed.
  291. */
  292. FREEPOOL(parentFdoExt->configDesc);
  293. parentFdoExt->configDesc = NULL;
  294. }
  295. }
  296. else {
  297. status = STATUS_INSUFFICIENT_RESOURCES;
  298. }
  299. }
  300. return status;
  301. }
  302. /*
  303. * GetConfigDescriptor
  304. *
  305. * Get configuration descriptor for device.
  306. * Some devices (expecially speakers, which can have huge config descriptors)
  307. * are flaky returning their config descriptors. So we try up to 3 times.
  308. */
  309. NTSTATUS GetConfigDescriptor(PPARENT_FDO_EXT parentFdoExt)
  310. {
  311. const ULONG numAttempts = 3;
  312. NTSTATUS status;
  313. ULONG i;
  314. PAGED_CODE();
  315. for (i = 1; i <= numAttempts; i++){
  316. status = TryGetConfigDescriptor(parentFdoExt);
  317. if (NT_SUCCESS(status)){
  318. if (i != 1) DBGOUT(("GetConfigDescriptor: got config descriptor on retry (@ %ph)", parentFdoExt->configDesc));
  319. break;
  320. }
  321. else {
  322. if (i < numAttempts){
  323. DBGWARN(("GetConfigDescriptor: failed with %xh (attempt #%d).", status, i));
  324. }
  325. else {
  326. DBGWARN(("GetConfigDescriptor: failed %d times (status = %xh).", numAttempts, status));
  327. }
  328. }
  329. }
  330. return status;
  331. }
  332. NTSTATUS GetDeviceDescriptor(PPARENT_FDO_EXT parentFdoExt)
  333. {
  334. URB urb;
  335. NTSTATUS status;
  336. PAGED_CODE();
  337. RtlZeroMemory(&parentFdoExt->deviceDesc, sizeof(parentFdoExt->deviceDesc));
  338. UsbBuildGetDescriptorRequest(&urb,
  339. (USHORT) sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  340. USB_DEVICE_DESCRIPTOR_TYPE,
  341. 0,
  342. 0,
  343. (PVOID)&parentFdoExt->deviceDesc,
  344. NULL,
  345. sizeof(parentFdoExt->deviceDesc),
  346. NULL);
  347. status = SubmitUrb(parentFdoExt, &urb, TRUE, NULL, NULL);
  348. if (NT_SUCCESS(status)){
  349. DBGVERBOSE(("Got device desc @ %ph, len=%xh (should be %xh).", (PVOID)&parentFdoExt->deviceDesc, urb.UrbControlDescriptorRequest.TransferBufferLength, sizeof(parentFdoExt->deviceDesc)));
  350. }
  351. return status;
  352. }
  353. VOID PrepareParentFDOForRemove(PPARENT_FDO_EXT parentFdoExt)
  354. {
  355. enum deviceState oldState;
  356. KIRQL oldIrql;
  357. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  358. oldState = parentFdoExt->state;
  359. parentFdoExt->state = STATE_REMOVING;
  360. /*
  361. * Careful, we may not have allocated the deviceRelations if the previous start failed.
  362. */
  363. if (ISPTR(parentFdoExt->deviceRelations)){
  364. DBGVERBOSE(("PrepareParentFDOForRemove: removing %d child PDOs.", parentFdoExt->deviceRelations->Count));
  365. while (parentFdoExt->deviceRelations->Count > 0){
  366. PDEVICE_OBJECT devObj;
  367. PDEVEXT devExt;
  368. PFUNCTION_PDO_EXT functionPdoExt;
  369. /*
  370. * Remove the last child pdo from the parent's deviceRelations.
  371. */
  372. parentFdoExt->deviceRelations->Count--;
  373. devObj = parentFdoExt->deviceRelations->Objects[parentFdoExt->deviceRelations->Count];
  374. parentFdoExt->deviceRelations->Objects[parentFdoExt->deviceRelations->Count] = BAD_POINTER;
  375. ASSERT(devObj->Type == IO_TYPE_DEVICE);
  376. devExt = devObj->DeviceExtension;
  377. ASSERT(!devExt->isParentFdo);
  378. functionPdoExt = &devExt->functionPdoExt;
  379. /*
  380. * Free this child pdo. Must drop spinlock around call outside driver.
  381. */
  382. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  383. FreeFunctionPDOResources(functionPdoExt);
  384. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  385. }
  386. }
  387. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  388. if ((oldState != STATE_REMOVING) && (oldState != STATE_REMOVED)){
  389. /*
  390. * Do an extra decrement on the pendingActionCount.
  391. * This will cause the count to eventually go to -1
  392. * (once all IO completes),
  393. * at which time we'll continue.
  394. */
  395. DecrementPendingActionCount(parentFdoExt);
  396. KeWaitForSingleObject( &parentFdoExt->removeEvent,
  397. Executive,
  398. KernelMode,
  399. FALSE,
  400. NULL );
  401. }
  402. }
  403. VOID FreeParentFDOResources(PPARENT_FDO_EXT parentFdoExt)
  404. {
  405. parentFdoExt->state = STATE_REMOVED;
  406. FreeInterfaceList(parentFdoExt, TRUE);
  407. // It is possible that after a failed start, the deviceRelations
  408. // and configDesc buffers will not have been allocated.
  409. if (ISPTR(parentFdoExt->deviceRelations)){
  410. FREEPOOL(parentFdoExt->deviceRelations);
  411. }
  412. parentFdoExt->deviceRelations = BAD_POINTER;
  413. if (ISPTR(parentFdoExt->configDesc)){
  414. FREEPOOL(parentFdoExt->configDesc);
  415. }
  416. parentFdoExt->configDesc = BAD_POINTER;
  417. parentFdoExt->selectedConfigDesc = BAD_POINTER;
  418. if (ISPTR(parentFdoExt->msExtConfigDesc)){
  419. FREEPOOL(parentFdoExt->msExtConfigDesc);
  420. }
  421. parentFdoExt->msExtConfigDesc = BAD_POINTER;
  422. /*
  423. * Delete the device object. This will also delete the device extension.
  424. */
  425. IoDeleteDevice(parentFdoExt->fdo);
  426. }
  427. /*
  428. * GetParentFdoCapabilities
  429. *
  430. */
  431. NTSTATUS GetParentFdoCapabilities(PPARENT_FDO_EXT parentFdoExt)
  432. {
  433. NTSTATUS status;
  434. PIRP irp;
  435. PAGED_CODE();
  436. irp = IoAllocateIrp(parentFdoExt->pdo->StackSize, FALSE);
  437. if (irp){
  438. PIO_STACK_LOCATION nextSp = IoGetNextIrpStackLocation(irp);
  439. nextSp->MajorFunction= IRP_MJ_PNP;
  440. nextSp->MinorFunction= IRP_MN_QUERY_CAPABILITIES;
  441. RtlZeroMemory(&parentFdoExt->deviceCapabilities, sizeof(DEVICE_CAPABILITIES));
  442. parentFdoExt->deviceCapabilities.Size = sizeof(DEVICE_CAPABILITIES);
  443. parentFdoExt->deviceCapabilities.Version = 1;
  444. parentFdoExt->deviceCapabilities.Address = -1;
  445. parentFdoExt->deviceCapabilities.UINumber = -1;
  446. nextSp->Parameters.DeviceCapabilities.Capabilities = &parentFdoExt->deviceCapabilities;
  447. irp->IoStatus.Status = STATUS_NOT_SUPPORTED; // default status for PNP irps is STATUS_NOT_SUPPORTED
  448. status = CallDriverSync(parentFdoExt->topDevObj, irp);
  449. IoFreeIrp(irp);
  450. }
  451. else {
  452. status = STATUS_INSUFFICIENT_RESOURCES;
  453. }
  454. ASSERT(NT_SUCCESS(status));
  455. return status;
  456. }
  457. /*
  458. ************************************************************
  459. * StartParentFdo
  460. ************************************************************
  461. *
  462. */
  463. NTSTATUS StartParentFdo(PPARENT_FDO_EXT parentFdoExt, PIRP irp)
  464. {
  465. NTSTATUS status;
  466. BOOLEAN resumingFromStop;
  467. PAGED_CODE();
  468. resumingFromStop = ((parentFdoExt->state == STATE_STOPPING) || (parentFdoExt->state == STATE_STOPPED));
  469. parentFdoExt->state = STATE_STARTING;
  470. /*
  471. * Chain the call down the stack synchronously first
  472. * (have to start the lower stack before sending other calls to it).
  473. */
  474. IoCopyCurrentIrpStackLocationToNext(irp);
  475. status = CallDriverSync(parentFdoExt->topDevObj, irp);
  476. if (NT_SUCCESS(status)){
  477. if (resumingFromStop){
  478. /*
  479. * If we're resuming from a STOP, we don't need to get descriptors, etc., again.
  480. * All we have to do is a SELECT_CONFIGURATION.
  481. * The function PDOs are presumably already created and are already
  482. * pointing into the parent's interfaceList.
  483. *
  484. * ** This call will change the .Interface fields inside each element
  485. * of the parent's interfaceList; when we're done, the interfaceList
  486. * AND the function PDOs' pointers into that list will be valid.
  487. */
  488. status = ParentSelectConfiguration( parentFdoExt,
  489. parentFdoExt->selectedConfigDesc,
  490. parentFdoExt->interfaceList);
  491. }
  492. else {
  493. status = GetDeviceDescriptor(parentFdoExt);
  494. if (NT_SUCCESS(status)){
  495. status = GetConfigDescriptor(parentFdoExt);
  496. if (NT_SUCCESS(status)){
  497. status = GetParentFdoCapabilities(parentFdoExt);
  498. if (NT_SUCCESS(status)){
  499. if (NT_SUCCESS(status)){
  500. parentFdoExt->interfaceList = GetInterfaceList(parentFdoExt, parentFdoExt->selectedConfigDesc);
  501. if (parentFdoExt->interfaceList){
  502. status = ParentSelectConfiguration( parentFdoExt,
  503. parentFdoExt->selectedConfigDesc,
  504. parentFdoExt->interfaceList);
  505. GetMsExtendedConfigDescriptor(parentFdoExt);
  506. if (NT_SUCCESS(status)){
  507. status = CreateStaticFunctionPDOs(parentFdoExt);
  508. if (NT_SUCCESS(status)){
  509. /*
  510. * Alert the system that we are creating
  511. * new PDOs. The kernel should respond by
  512. * sending us the
  513. * IRP_MN_QUERY_DEVICE_RELATIONS PnP IRP.
  514. */
  515. IoInvalidateDeviceRelations(parentFdoExt->pdo, BusRelations);
  516. }
  517. else {
  518. if (parentFdoExt->deviceRelations) {
  519. FREEPOOL(parentFdoExt->deviceRelations);
  520. }
  521. parentFdoExt->deviceRelations = BAD_POINTER;
  522. }
  523. }
  524. if (!NT_SUCCESS(status)){
  525. FREEPOOL(parentFdoExt->interfaceList);
  526. parentFdoExt->interfaceList = BAD_POINTER;
  527. }
  528. }
  529. else {
  530. status = STATUS_DEVICE_DATA_ERROR;
  531. }
  532. }
  533. }
  534. }
  535. }
  536. }
  537. }
  538. else {
  539. DBGWARN(("Chained start irp failed with %xh.", status));
  540. }
  541. if (NT_SUCCESS(status)){
  542. parentFdoExt->state = STATE_STARTED;
  543. }
  544. else {
  545. DBGWARN(("StartParentFdo failed with %xh.", status));
  546. parentFdoExt->state = STATE_START_FAILED;
  547. }
  548. return status;
  549. }
  550. /*
  551. ********************************************************************************
  552. * QueryParentDeviceRelations
  553. ********************************************************************************
  554. *
  555. *
  556. */
  557. NTSTATUS QueryParentDeviceRelations(PPARENT_FDO_EXT parentFdoExt, PIRP irp)
  558. {
  559. PIO_STACK_LOCATION irpSp;
  560. NTSTATUS status;
  561. PAGED_CODE();
  562. irpSp = IoGetCurrentIrpStackLocation(irp);
  563. if (irpSp->Parameters.QueryDeviceRelations.Type == BusRelations){
  564. if (parentFdoExt->deviceRelations){
  565. /*
  566. * NTKERN expects a new pointer each time it calls QUERY_DEVICE_RELATIONS;
  567. * it then FREES THE POINTER.
  568. * So we have to return a new pointer each time, whether or not we actually
  569. * created our copy of the device relations for this call.
  570. */
  571. irp->IoStatus.Information = (ULONG_PTR)CopyDeviceRelations(parentFdoExt->deviceRelations);
  572. if (irp->IoStatus.Information){
  573. ULONG i;
  574. /*
  575. * The kernel dereferences each device object
  576. * in the device relations list after each call.
  577. * So for each call, add an extra reference.
  578. */
  579. for (i = 0; i < parentFdoExt->deviceRelations->Count; i++){
  580. ObReferenceObject(parentFdoExt->deviceRelations->Objects[i]);
  581. parentFdoExt->deviceRelations->Objects[i]->Flags &= ~DO_DEVICE_INITIALIZING;
  582. }
  583. DBGVERBOSE(("Parent returned %d child PDOs", parentFdoExt->deviceRelations->Count));
  584. /*
  585. * If we are succeeding this PnP IRP, then we pass it down
  586. * the stack but change its default status to success.
  587. */
  588. irp->IoStatus.Status = STATUS_SUCCESS;
  589. status = NO_STATUS;
  590. }
  591. else {
  592. status = STATUS_INSUFFICIENT_RESOURCES;
  593. }
  594. }
  595. else {
  596. ASSERT(parentFdoExt->deviceRelations);
  597. status = STATUS_DEVICE_DATA_ERROR;
  598. }
  599. }
  600. else {
  601. /*
  602. * Pass this IRP down to the next driver.
  603. */
  604. status = NO_STATUS;
  605. }
  606. if (!NT_SUCCESS(status) && (status != NO_STATUS)) {
  607. DBGWARN(("QueryParentDeviceRelations: failed with %xh.", status));
  608. }
  609. return status;
  610. }
  611. /*
  612. ********************************************************************************
  613. * ParentPowerRequestCompletion
  614. ********************************************************************************
  615. *
  616. *
  617. */
  618. VOID ParentPowerRequestCompletion(
  619. IN PDEVICE_OBJECT devObj,
  620. IN UCHAR minorFunction,
  621. IN POWER_STATE powerState,
  622. IN PVOID context,
  623. IN PIO_STATUS_BLOCK ioStatus)
  624. {
  625. PPARENT_FDO_EXT parentFdoExt = (PPARENT_FDO_EXT)context;
  626. PIRP parentSetPowerIrp;
  627. ASSERT(parentFdoExt->currentSetPowerIrp->Type == IO_TYPE_IRP);
  628. parentSetPowerIrp = parentFdoExt->currentSetPowerIrp;
  629. parentFdoExt->currentSetPowerIrp = NULL;
  630. /*
  631. * This is the completion routine for the device-state power
  632. * Irp which we've requested. Complete the original system-state
  633. * power Irp with the result of the device-state power Irp.
  634. */
  635. ASSERT(devObj->Type == IO_TYPE_DEVICE);
  636. ASSERT(NT_SUCCESS(ioStatus->Status));
  637. parentSetPowerIrp->IoStatus.Status = ioStatus->Status;
  638. PoStartNextPowerIrp(parentSetPowerIrp);
  639. if (NT_SUCCESS(ioStatus->Status)){
  640. IoCopyCurrentIrpStackLocationToNext(parentSetPowerIrp);
  641. IoSetCompletionRoutine(parentSetPowerIrp, ParentPdoPowerCompletion, (PVOID)parentFdoExt, TRUE, TRUE, TRUE);
  642. PoCallDriver(parentFdoExt->topDevObj, parentSetPowerIrp);
  643. }
  644. else {
  645. IoCompleteRequest(parentSetPowerIrp, IO_NO_INCREMENT);
  646. }
  647. }
  648. /*
  649. ********************************************************************************
  650. * ParentPdoPowerCompletion
  651. ********************************************************************************
  652. *
  653. *
  654. */
  655. NTSTATUS ParentPdoPowerCompletion(IN PDEVICE_OBJECT devObj, IN PIRP irp, IN PVOID context)
  656. {
  657. PIO_STACK_LOCATION irpSp;
  658. PPARENT_FDO_EXT parentFdoExt = (PPARENT_FDO_EXT)context;
  659. ASSERT(parentFdoExt);
  660. irpSp = IoGetCurrentIrpStackLocation(irp);
  661. ASSERT(irpSp->MajorFunction == IRP_MJ_POWER);
  662. if (NT_SUCCESS(irp->IoStatus.Status)){
  663. switch (irpSp->MinorFunction){
  664. case IRP_MN_SET_POWER:
  665. switch (irpSp->Parameters.Power.Type){
  666. case DevicePowerState:
  667. switch (irpSp->Parameters.Power.State.DeviceState){
  668. case PowerDeviceD0:
  669. if (parentFdoExt->state == STATE_SUSPENDED){
  670. parentFdoExt->state = STATE_STARTED;
  671. CompleteAllFunctionWaitWakeIrps(parentFdoExt, STATUS_SUCCESS);
  672. CompleteAllFunctionIdleIrps(parentFdoExt, STATUS_SUCCESS);
  673. }
  674. break;
  675. }
  676. break;
  677. }
  678. break;
  679. }
  680. }
  681. /*
  682. * Must propagate the pending bit if a lower driver returned pending.
  683. */
  684. if (irp->PendingReturned){
  685. IoMarkIrpPending(irp);
  686. }
  687. return STATUS_SUCCESS;
  688. }
  689. /*
  690. * HandleParentFdoPower
  691. *
  692. *
  693. */
  694. NTSTATUS HandleParentFdoPower(PPARENT_FDO_EXT parentFdoExt, PIRP irp)
  695. {
  696. PIO_STACK_LOCATION irpSp;
  697. BOOLEAN completeIrpHere = FALSE;
  698. BOOLEAN justReturnPending = FALSE;
  699. NTSTATUS status = NO_STATUS;
  700. KIRQL oldIrql;
  701. irpSp = IoGetCurrentIrpStackLocation(irp);
  702. if ((parentFdoExt->state == STATE_REMOVING) ||
  703. (parentFdoExt->state == STATE_REMOVED)){
  704. status = STATUS_DEVICE_NOT_CONNECTED;
  705. completeIrpHere = TRUE;
  706. }
  707. else {
  708. switch (irpSp->MinorFunction){
  709. case IRP_MN_SET_POWER:
  710. switch (irpSp->Parameters.Power.Type){
  711. case SystemPowerState:
  712. {
  713. SYSTEM_POWER_STATE systemState = irpSp->Parameters.Power.State.SystemState;
  714. ASSERT((ULONG)systemState < PowerSystemMaximum);
  715. if (systemState <= PowerSystemHibernate){
  716. /*
  717. * For the 'regular' system power states,
  718. * we convert to a device power state
  719. * and request a callback with the device power state.
  720. */
  721. POWER_STATE powerState;
  722. ASSERT(!parentFdoExt->currentSetPowerIrp);
  723. parentFdoExt->currentSetPowerIrp = irp;
  724. if (systemState == PowerSystemWorking) {
  725. powerState.DeviceState = PowerDeviceD0;
  726. } else if (parentFdoExt->isWaitWakePending) {
  727. powerState.DeviceState = parentFdoExt->deviceCapabilities.DeviceState[systemState];
  728. ASSERT(PowerDeviceUnspecified != powerState.DeviceState);
  729. } else {
  730. powerState.DeviceState = PowerDeviceD3;
  731. }
  732. IoMarkIrpPending(irp);
  733. status = irp->IoStatus.Status = STATUS_PENDING;
  734. PoRequestPowerIrp( parentFdoExt->pdo,
  735. IRP_MN_SET_POWER,
  736. powerState,
  737. ParentPowerRequestCompletion,
  738. parentFdoExt, // context
  739. NULL);
  740. /*
  741. * We want to complete the system-state power Irp
  742. * with the result of the device-state power Irp.
  743. * We'll complete the system-state power Irp when
  744. * the device-state power Irp completes.
  745. *
  746. * Note: this may have ALREADY happened, so don't
  747. * touch the original Irp anymore.
  748. */
  749. justReturnPending = TRUE;
  750. }
  751. else {
  752. /*
  753. * For the remaining system power states,
  754. * just pass down the IRP.
  755. */
  756. }
  757. }
  758. break;
  759. case DevicePowerState:
  760. switch (irpSp->Parameters.Power.State.DeviceState) {
  761. case PowerDeviceD0:
  762. /*
  763. * Resume from APM Suspend
  764. *
  765. * Do nothing here; Send down the read IRPs in the
  766. * completion routine for this (the power) IRP.
  767. */
  768. break;
  769. case PowerDeviceD1:
  770. case PowerDeviceD2:
  771. case PowerDeviceD3:
  772. /*
  773. * Suspend
  774. */
  775. if (parentFdoExt->state == STATE_STARTED){
  776. parentFdoExt->state = STATE_SUSPENDED;
  777. }
  778. break;
  779. }
  780. break;
  781. }
  782. break;
  783. case IRP_MN_WAIT_WAKE:
  784. /*
  785. * This is the WaitWake IRP that we requested for ourselves
  786. * via PoRequestPowerIrp. Send it down to the parent,
  787. * but record it in case we have to cancel it later.
  788. */
  789. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  790. ASSERT(parentFdoExt->isWaitWakePending);
  791. ASSERT(!parentFdoExt->parentWaitWakeIrp);
  792. parentFdoExt->parentWaitWakeIrp = irp;
  793. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  794. break;
  795. }
  796. }
  797. if (!justReturnPending){
  798. /*
  799. * Whether we are completing or relaying this power IRP,
  800. * we must call PoStartNextPowerIrp on Windows NT.
  801. */
  802. PoStartNextPowerIrp(irp);
  803. /*
  804. * If this is a call for a collection-PDO, we complete it ourselves here.
  805. * Otherwise, we pass it to the minidriver stack for more processing.
  806. */
  807. if (completeIrpHere){
  808. ASSERT(status != NO_STATUS);
  809. irp->IoStatus.Status = status;
  810. IoCompleteRequest(irp, IO_NO_INCREMENT);
  811. }
  812. else {
  813. /*
  814. * Call the parent driver with this Irp.
  815. */
  816. IoCopyCurrentIrpStackLocationToNext(irp);
  817. IoSetCompletionRoutine(irp, ParentPdoPowerCompletion, (PVOID)parentFdoExt, TRUE, TRUE, TRUE);
  818. status = PoCallDriver(parentFdoExt->topDevObj, irp);
  819. }
  820. }
  821. return status;
  822. }
  823. NTSTATUS ParentResetOrCyclePort(PPARENT_FDO_EXT parentFdoExt, PIRP irp, ULONG ioControlCode)
  824. {
  825. NTSTATUS status;
  826. KIRQL oldIrql;
  827. BOOLEAN proceed;
  828. PBOOLEAN actionInProgress;
  829. PLIST_ENTRY pendingIrpQueue;
  830. if (ioControlCode == IOCTL_INTERNAL_USB_CYCLE_PORT) {
  831. actionInProgress = &parentFdoExt->cyclePortInProgress;
  832. pendingIrpQueue = &parentFdoExt->pendingCyclePortIrpQueue;
  833. } else {
  834. /*
  835. * IOCTL_INTERNAL_USB_RESET_PORT
  836. */
  837. actionInProgress = &parentFdoExt->resetPortInProgress;
  838. pendingIrpQueue = &parentFdoExt->pendingResetPortIrpQueue;
  839. }
  840. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  841. if (*actionInProgress){
  842. /*
  843. * This is an overlapped RESET or CYCLE irp on the same parent.
  844. * Queue the irp and return pending; we'll complete it
  845. * _AFTER_ the first reset irp completes.
  846. * (No need for a cancel routine here since RESET is quick).
  847. */
  848. DBGWARN(("ParentInternalDeviceControl: queuing overlapping reset/cycle port call on parent"));
  849. /*
  850. * Need to mark the IRP pending if we are returning STATUS_PENDING.
  851. * Failure to do so results in the IRP's completion routine not
  852. * being called when the IRP is later completed asynchronously,
  853. * and this results in a system hang if there is a thread waiting
  854. * on that completion routine.
  855. */
  856. IoMarkIrpPending(irp);
  857. status = STATUS_PENDING;
  858. InsertTailList(pendingIrpQueue, &irp->Tail.Overlay.ListEntry);
  859. proceed = FALSE;
  860. }
  861. else {
  862. *actionInProgress = TRUE;
  863. proceed = TRUE;
  864. }
  865. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  866. if (proceed){
  867. LIST_ENTRY irpsToComplete;
  868. PLIST_ENTRY listEntry;
  869. IoCopyCurrentIrpStackLocationToNext(irp);
  870. status = CallNextDriverSync(parentFdoExt, irp);
  871. /*
  872. * Some redundant RESET or CYCLE irps may have been sent while we
  873. * were processing this one, and gotten queued.
  874. * We'll complete these now that the parent has been reset.
  875. */
  876. InitializeListHead(&irpsToComplete);
  877. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  878. ASSERT(*actionInProgress);
  879. *actionInProgress = FALSE;
  880. /*
  881. * Move the irps to a local queue with spinlock held.
  882. * Then complete them after dropping the spinlock.
  883. */
  884. while (!IsListEmpty(pendingIrpQueue)){
  885. listEntry = RemoveHeadList(pendingIrpQueue);
  886. InsertTailList(&irpsToComplete, listEntry);
  887. }
  888. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  889. /*
  890. * Complete the dequeued irps _after_ dropping the spinlock.
  891. */
  892. while (!IsListEmpty(&irpsToComplete)){
  893. PIRP dequeuedIrp;
  894. listEntry = RemoveHeadList(&irpsToComplete);
  895. dequeuedIrp = CONTAINING_RECORD(listEntry, IRP, Tail.Overlay.ListEntry);
  896. dequeuedIrp->IoStatus.Status = status;
  897. IoCompleteRequest(dequeuedIrp, IO_NO_INCREMENT);
  898. }
  899. }
  900. return status;
  901. }
  902. NTSTATUS ParentDeviceControl(PPARENT_FDO_EXT parentFdoExt, PIRP irp)
  903. {
  904. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
  905. ULONG ioControlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
  906. NTSTATUS status = NO_STATUS;
  907. if (parentFdoExt->state == STATE_SUSPENDED ||
  908. parentFdoExt->pendingIdleIrp) {
  909. ParentSetD0(parentFdoExt);
  910. }
  911. switch (ioControlCode){
  912. case IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER:
  913. if (parentFdoExt->haveCSInterface){
  914. status = GetMediaSerialNumber(parentFdoExt, irp);
  915. }
  916. else {
  917. DBGWARN(("ParentDeviceControl - passing IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER to parent because no Content Security interface on device"));
  918. }
  919. break;
  920. }
  921. if (status == NO_STATUS){
  922. IoSkipCurrentIrpStackLocation(irp);
  923. status = IoCallDriver(parentFdoExt->topDevObj, irp);
  924. }
  925. else {
  926. irp->IoStatus.Status = status;
  927. IoCompleteRequest(irp, IO_NO_INCREMENT);
  928. }
  929. return status;
  930. }
  931. NTSTATUS ParentInternalDeviceControl(PPARENT_FDO_EXT parentFdoExt, PIRP irp)
  932. {
  933. PIO_STACK_LOCATION irpSp = IoGetCurrentIrpStackLocation(irp);
  934. ULONG ioControlCode = irpSp->Parameters.DeviceIoControl.IoControlCode;
  935. PURB urb;
  936. NTSTATUS status = NO_STATUS;
  937. switch (ioControlCode){
  938. case IOCTL_INTERNAL_USB_RESET_PORT:
  939. case IOCTL_INTERNAL_USB_CYCLE_PORT:
  940. if (parentFdoExt->state == STATE_STARTED){
  941. status = ParentResetOrCyclePort(parentFdoExt, irp, ioControlCode);
  942. }
  943. else {
  944. DBGERR(("ParentInternalDeviceControl (IOCTL_INTERNAL_USB_RESET_PORT): BAD PNP state! - parent has state %xh.", parentFdoExt->state));
  945. status = STATUS_DEVICE_NOT_READY;
  946. }
  947. break;
  948. case IOCTL_INTERNAL_USB_SUBMIT_URB:
  949. urb = irpSp->Parameters.Others.Argument1;
  950. ASSERT(urb);
  951. DBG_LOG_URB(urb);
  952. if (parentFdoExt->state == STATE_STARTED){
  953. /*
  954. * Send the URB down to the parent.
  955. * It's ok to not synchronize URB_FUNCTION_ABORT_PIPE
  956. * and URB_FUNCTION_RESET_PIPE because they only effect
  957. * the resources of one function.
  958. */
  959. }
  960. else {
  961. DBGERR(("ParentInternalDeviceControl (abort/reset): BAD PNP state! - parent has state %xh.", parentFdoExt->state));
  962. status = STATUS_DEVICE_NOT_READY;
  963. }
  964. break;
  965. }
  966. if (status == NO_STATUS){
  967. /*
  968. * Pass this irp to the parent driver.
  969. */
  970. IoSkipCurrentIrpStackLocation(irp);
  971. status = IoCallDriver(parentFdoExt->topDevObj, irp);
  972. }
  973. else if (status == STATUS_PENDING){
  974. }
  975. else {
  976. irp->IoStatus.Status = status;
  977. IoCompleteRequest(irp, IO_NO_INCREMENT);
  978. }
  979. return status;
  980. }
  981. VOID ParentIdleNotificationCallback(PPARENT_FDO_EXT parentFdoExt)
  982. {
  983. PIRP idleIrp;
  984. PIRP parentIdleIrpToCancel = FALSE;
  985. KIRQL oldIrql;
  986. POWER_STATE powerState;
  987. NTSTATUS ntStatus;
  988. ULONG i;
  989. BOOLEAN bIdleOk = TRUE;
  990. DBGVERBOSE(("Parent %x going idle!", parentFdoExt));
  991. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  992. ASSERT(parentFdoExt->deviceRelations);
  993. for (i = 0; i < parentFdoExt->deviceRelations->Count; i++){
  994. PDEVICE_OBJECT devObj = parentFdoExt->deviceRelations->Objects[i];
  995. PDEVEXT devExt;
  996. PFUNCTION_PDO_EXT thisFuncPdoExt;
  997. ASSERT(devObj);
  998. devExt = devObj->DeviceExtension;
  999. ASSERT(devExt);
  1000. ASSERT(devExt->signature == USBCCGP_TAG);
  1001. ASSERT(!devExt->isParentFdo);
  1002. thisFuncPdoExt = &devExt->functionPdoExt;
  1003. idleIrp = thisFuncPdoExt->idleNotificationIrp;
  1004. ASSERT(idleIrp);
  1005. if (idleIrp) {
  1006. PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
  1007. idleCallbackInfo = (PUSB_IDLE_CALLBACK_INFO)
  1008. IoGetCurrentIrpStackLocation(idleIrp)->\
  1009. Parameters.DeviceIoControl.Type3InputBuffer;
  1010. ASSERT(idleCallbackInfo && idleCallbackInfo->IdleCallback);
  1011. if (idleCallbackInfo && idleCallbackInfo->IdleCallback) {
  1012. // Here we actually call the driver's callback routine,
  1013. // telling the driver that it is OK to suspend their
  1014. // device now.
  1015. DBGVERBOSE(("ParentIdleNotificationCallback: Calling driver's idle callback routine! %x %x",
  1016. idleCallbackInfo, idleCallbackInfo->IdleCallback));
  1017. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  1018. idleCallbackInfo->IdleCallback(idleCallbackInfo->IdleContext);
  1019. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  1020. // Be sure that the child actually powered down.
  1021. // Abort if the child aborted.
  1022. if (thisFuncPdoExt->state != STATE_SUSPENDED) {
  1023. bIdleOk = FALSE;
  1024. break;
  1025. }
  1026. } else {
  1027. // No callback
  1028. bIdleOk = FALSE;
  1029. break;
  1030. }
  1031. } else {
  1032. // No Idle IRP
  1033. bIdleOk = FALSE;
  1034. break;
  1035. }
  1036. }
  1037. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  1038. if (bIdleOk) {
  1039. // If all the child function PDOs have been powered down,
  1040. // it is time to power down the parent.
  1041. powerState.DeviceState = PowerDeviceD2; // DeviceWake
  1042. PoRequestPowerIrp(parentFdoExt->topDevObj,
  1043. IRP_MN_SET_POWER,
  1044. powerState,
  1045. NULL,
  1046. NULL,
  1047. NULL);
  1048. } else {
  1049. // One or more of the child function PDOs did not have an Idle IRP
  1050. // (i.e. it was just cancelled), or the Idle IRP did not have a
  1051. // callback function pointer. Abort this Idle procedure and cancel
  1052. // the Idle IRP to the parent.
  1053. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  1054. if (parentFdoExt->pendingIdleIrp){
  1055. parentIdleIrpToCancel = parentFdoExt->pendingIdleIrp;
  1056. parentFdoExt->pendingIdleIrp = NULL;
  1057. }
  1058. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  1059. if (parentIdleIrpToCancel){
  1060. IoCancelIrp(parentIdleIrpToCancel);
  1061. }
  1062. }
  1063. }
  1064. NTSTATUS ParentIdleNotificationRequestComplete(PDEVICE_OBJECT DeviceObject, PIRP Irp, PPARENT_FDO_EXT parentFdoExt)
  1065. {
  1066. NTSTATUS ntStatus;
  1067. KIRQL oldIrql;
  1068. //
  1069. // DeviceObject is NULL because we sent the irp
  1070. //
  1071. UNREFERENCED_PARAMETER(DeviceObject);
  1072. DBGVERBOSE(("Idle notification IRP for parent %x completed %x\n", parentFdoExt, Irp->IoStatus.Status));
  1073. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  1074. parentFdoExt->pendingIdleIrp = NULL;
  1075. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  1076. ntStatus = Irp->IoStatus.Status;
  1077. /*
  1078. * If parent Idle IRP failed, fail all function Idle IRPs.
  1079. */
  1080. if (!NT_SUCCESS(ntStatus)){
  1081. if (parentFdoExt->state == STATE_SUSPENDED ||
  1082. parentFdoExt->pendingIdleIrp) {
  1083. ParentSetD0(parentFdoExt);
  1084. }
  1085. CompleteAllFunctionIdleIrps(parentFdoExt, ntStatus);
  1086. }
  1087. /* Since we allocated the IRP we must free it, but return
  1088. * STATUS_MORE_PROCESSING_REQUIRED so the kernel does not try to touch
  1089. * the IRP after we've freed it.
  1090. */
  1091. IoFreeIrp(Irp);
  1092. return STATUS_MORE_PROCESSING_REQUIRED;
  1093. }
  1094. NTSTATUS SubmitParentIdleRequestIrp(PPARENT_FDO_EXT parentFdoExt)
  1095. {
  1096. PIRP irp = NULL;
  1097. PIO_STACK_LOCATION nextStack;
  1098. NTSTATUS ntStatus;
  1099. KIRQL oldIrql;
  1100. DBGVERBOSE(("SubmitParentIdleRequestIrp %x", parentFdoExt));
  1101. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  1102. if (parentFdoExt->pendingIdleIrp){
  1103. ntStatus = STATUS_DEVICE_BUSY;
  1104. }
  1105. else {
  1106. parentFdoExt->idleCallbackInfo.IdleCallback = ParentIdleNotificationCallback;
  1107. parentFdoExt->idleCallbackInfo.IdleContext = (PVOID)parentFdoExt;
  1108. irp = IoAllocateIrp(parentFdoExt->pdo->StackSize, FALSE);
  1109. if (irp){
  1110. /*
  1111. * Set pendingIdleIrp with lock held so that we don't
  1112. * send down more than one.
  1113. * Then send this one down after dropping the lock.
  1114. */
  1115. parentFdoExt->pendingIdleIrp = irp;
  1116. }
  1117. else {
  1118. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  1119. }
  1120. }
  1121. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  1122. if (irp){
  1123. nextStack = IoGetNextIrpStackLocation(irp);
  1124. nextStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
  1125. nextStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION;
  1126. nextStack->Parameters.DeviceIoControl.Type3InputBuffer = &parentFdoExt->idleCallbackInfo;
  1127. nextStack->Parameters.DeviceIoControl.InputBufferLength = sizeof(struct _USB_IDLE_CALLBACK_INFO);
  1128. IoSetCompletionRoutine(irp,
  1129. ParentIdleNotificationRequestComplete,
  1130. parentFdoExt,
  1131. TRUE,
  1132. TRUE,
  1133. TRUE);
  1134. ntStatus = IoCallDriver(parentFdoExt->topDevObj, irp);
  1135. ASSERT(ntStatus == STATUS_PENDING);
  1136. }
  1137. return ntStatus;
  1138. }
  1139. /*
  1140. * CheckParentIdle
  1141. *
  1142. *
  1143. * This function determines if a composite device is ready to be idled out,
  1144. * and does so if ready.
  1145. *
  1146. */
  1147. VOID CheckParentIdle(PPARENT_FDO_EXT parentFdoExt)
  1148. {
  1149. PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
  1150. KIRQL oldIrql;
  1151. BOOLEAN bAllIdle;
  1152. ULONG i;
  1153. DBGVERBOSE(("Check Parent Idle %x", parentFdoExt));
  1154. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  1155. bAllIdle = TRUE; // Assume that everyone wants to idle.
  1156. ASSERT(parentFdoExt->deviceRelations);
  1157. for (i = 0; i < parentFdoExt->deviceRelations->Count; i++) {
  1158. PDEVICE_OBJECT devObj = parentFdoExt->deviceRelations->Objects[i];
  1159. PDEVEXT devExt;
  1160. PFUNCTION_PDO_EXT thisFuncPdoExt;
  1161. ASSERT(devObj);
  1162. devExt = devObj->DeviceExtension;
  1163. ASSERT(devExt);
  1164. ASSERT(devExt->signature == USBCCGP_TAG);
  1165. ASSERT(!devExt->isParentFdo);
  1166. thisFuncPdoExt = &devExt->functionPdoExt;
  1167. if (!thisFuncPdoExt->idleNotificationIrp){
  1168. bAllIdle = FALSE;
  1169. break;
  1170. }
  1171. }
  1172. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  1173. /*
  1174. * If all functions have received an idle request,
  1175. * then submit an idle request for the parent.
  1176. */
  1177. if (bAllIdle ) {
  1178. DBGVERBOSE(("CheckParentIdle: All function PDOs on parent %x idle!", parentFdoExt));
  1179. SubmitParentIdleRequestIrp(parentFdoExt);
  1180. }
  1181. }
  1182. NTSTATUS SubmitParentWaitWakeIrp(PPARENT_FDO_EXT parentFdoExt)
  1183. {
  1184. NTSTATUS status;
  1185. POWER_STATE powerState;
  1186. PIRP dummyIrp;
  1187. ASSERT(parentFdoExt->isWaitWakePending);
  1188. powerState.SystemState = PowerSystemWorking;
  1189. status = PoRequestPowerIrp( parentFdoExt->topDevObj,
  1190. IRP_MN_WAIT_WAKE,
  1191. powerState,
  1192. ParentWaitWakeComplete,
  1193. parentFdoExt, // context
  1194. &dummyIrp);
  1195. ASSERT(NT_SUCCESS(status));
  1196. return status;
  1197. }
  1198. /*
  1199. ********************************************************************************
  1200. * ParentWaitWakePowerRequestCompletion
  1201. ********************************************************************************
  1202. *
  1203. *
  1204. */
  1205. NTSTATUS ParentWaitWakePowerRequestCompletion(
  1206. IN PDEVICE_OBJECT devObj,
  1207. IN UCHAR minorFunction,
  1208. IN POWER_STATE powerState,
  1209. IN PVOID context,
  1210. IN PIO_STATUS_BLOCK ioStatus)
  1211. {
  1212. PPARENT_FDO_EXT parentFdoExt = (PPARENT_FDO_EXT)context;
  1213. NTSTATUS status;
  1214. status = ioStatus->Status;
  1215. CompleteAllFunctionWaitWakeIrps(parentFdoExt, STATUS_SUCCESS);
  1216. return status;
  1217. }
  1218. /*
  1219. ********************************************************************************
  1220. * ParentWaitWakeComplete
  1221. ********************************************************************************
  1222. *
  1223. */
  1224. NTSTATUS ParentWaitWakeComplete(
  1225. IN PDEVICE_OBJECT deviceObject,
  1226. IN UCHAR minorFunction,
  1227. IN POWER_STATE powerState,
  1228. IN PVOID context,
  1229. IN PIO_STATUS_BLOCK ioStatus)
  1230. {
  1231. PPARENT_FDO_EXT parentFdoExt = (PPARENT_FDO_EXT)context;
  1232. NTSTATUS status;
  1233. KIRQL oldIrql;
  1234. POWER_STATE pwrState;
  1235. status = ioStatus->Status;
  1236. KeAcquireSpinLock(&parentFdoExt->parentFdoExtSpinLock, &oldIrql);
  1237. ASSERT(parentFdoExt->isWaitWakePending);
  1238. parentFdoExt->isWaitWakePending = FALSE;
  1239. parentFdoExt->parentWaitWakeIrp = NULL;
  1240. KeReleaseSpinLock(&parentFdoExt->parentFdoExtSpinLock, oldIrql);
  1241. if (NT_SUCCESS(status) && (parentFdoExt->state == STATE_SUSPENDED)){
  1242. /*
  1243. * Per the DDK: if parent is suspended,
  1244. * do not complete the function PDOs' WaitWake irps here;
  1245. * wait for the parent to get the D0 irp.
  1246. */
  1247. pwrState.DeviceState = PowerDeviceD0;
  1248. PoRequestPowerIrp( parentFdoExt->pdo,
  1249. IRP_MN_SET_POWER,
  1250. pwrState,
  1251. ParentWaitWakePowerRequestCompletion,
  1252. parentFdoExt, // context
  1253. NULL);
  1254. }
  1255. else {
  1256. CompleteAllFunctionWaitWakeIrps(parentFdoExt, status);
  1257. }
  1258. return STATUS_SUCCESS;
  1259. }
  1260. /*
  1261. ********************************************************************************
  1262. * ParentSetD0Completion
  1263. ********************************************************************************
  1264. *
  1265. */
  1266. NTSTATUS ParentSetD0Completion(
  1267. IN PDEVICE_OBJECT DeviceObject,
  1268. IN UCHAR MinorFunction,
  1269. IN POWER_STATE PowerState,
  1270. IN PVOID Context,
  1271. IN PIO_STATUS_BLOCK IoStatus
  1272. )
  1273. {
  1274. NTSTATUS ntStatus;
  1275. PKEVENT pEvent = Context;
  1276. KeSetEvent(pEvent, 1, FALSE);
  1277. ntStatus = IoStatus->Status;
  1278. return ntStatus;
  1279. }
  1280. /*
  1281. ********************************************************************************
  1282. * ParentSetD0
  1283. ********************************************************************************
  1284. *
  1285. */
  1286. NTSTATUS ParentSetD0(IN PPARENT_FDO_EXT parentFdoExt)
  1287. {
  1288. KEVENT event;
  1289. POWER_STATE powerState;
  1290. NTSTATUS ntStatus;
  1291. PAGED_CODE();
  1292. DBGVERBOSE(("ParentSetD0, power up devext %x\n", parentFdoExt));
  1293. KeInitializeEvent(&event, NotificationEvent, FALSE);
  1294. powerState.DeviceState = PowerDeviceD0;
  1295. // Power up the device.
  1296. ntStatus = PoRequestPowerIrp(parentFdoExt->topDevObj,
  1297. IRP_MN_SET_POWER,
  1298. powerState,
  1299. ParentSetD0Completion,
  1300. &event,
  1301. NULL);
  1302. ASSERT(ntStatus == STATUS_PENDING);
  1303. if (ntStatus == STATUS_PENDING) {
  1304. ntStatus = KeWaitForSingleObject(&event,
  1305. Suspended,
  1306. KernelMode,
  1307. FALSE,
  1308. NULL);
  1309. }
  1310. return ntStatus;
  1311. }