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.

6661 lines
202 KiB

  1. /*++
  2. Copyright (c) 1996 Microsoft Corporation
  3. Module Name:
  4. PNPPOWER.C
  5. Abstract:
  6. This module contains functions to access registry.
  7. Author:
  8. John Lee
  9. Environment:
  10. kernel mode only
  11. Notes:
  12. Revision History:
  13. 4-2-96 : created
  14. --*/
  15. #include <wdm.h>
  16. #include <windef.h>
  17. #include <unknown.h>
  18. #ifdef DRM_SUPPORT
  19. #include <ks.h>
  20. #include <ksmedia.h>
  21. #include <drmk.h>
  22. #include <ksdrmhlp.h>
  23. #endif
  24. #ifdef WMI_SUPPORT
  25. #include <wmilib.h>
  26. #endif /* WMI_SUPPORT */
  27. #include <initguid.h>
  28. #include <wdmguid.h>
  29. #include <ntddstor.h> // Needed for IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER
  30. #include "usbhub.h"
  31. #define BANDWIDTH_TIMEOUT 1000 // Timeout in ms (1 sec)
  32. #ifdef PAGE_CODE
  33. #ifdef ALLOC_PRAGMA
  34. #pragma alloc_text(PAGE, USBH_BuildDeviceID)
  35. #pragma alloc_text(PAGE, USBH_BuildHardwareIDs)
  36. #pragma alloc_text(PAGE, USBH_BuildCompatibleIDs)
  37. #pragma alloc_text(PAGE, USBH_BuildInstanceID)
  38. #pragma alloc_text(PAGE, USBH_ProcessDeviceInformation)
  39. #pragma alloc_text(PAGE, USBH_ValidateSerialNumberString)
  40. #pragma alloc_text(PAGE, USBH_CreateDevice)
  41. #pragma alloc_text(PAGE, USBH_PdoQueryId)
  42. #pragma alloc_text(PAGE, USBH_PdoPnP)
  43. #pragma alloc_text(PAGE, USBH_PdoQueryCapabilities)
  44. #pragma alloc_text(PAGE, USBH_PdoQueryDeviceText)
  45. #pragma alloc_text(PAGE, USBH_CheckDeviceIDUnique)
  46. #pragma alloc_text(PAGE, USBH_GetPdoRegistryParameter)
  47. #pragma alloc_text(PAGE, USBH_OsVendorCodeQueryRoutine)
  48. #pragma alloc_text(PAGE, USBH_GetMsOsVendorCode)
  49. #pragma alloc_text(PAGE, USBH_GetMsOsFeatureDescriptor)
  50. #pragma alloc_text(PAGE, USBH_InstallExtPropDesc)
  51. #pragma alloc_text(PAGE, USBH_InstallExtPropDescSections)
  52. #pragma alloc_text(PAGE, USBH_GetExtConfigDesc)
  53. #pragma alloc_text(PAGE, USBH_ValidateExtConfigDesc)
  54. #ifdef DRM_SUPPORT
  55. #pragma alloc_text(PAGE, USBH_PdoSetContentId)
  56. #endif
  57. #endif
  58. #endif
  59. //
  60. // The macro and the array make conversion from hex to strings easy for building DeviceId etc.
  61. //
  62. #define NibbleToHex( byte ) ((UCHAR)Nibble[byte])
  63. CHAR Nibble[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
  64. #define NibbleToHexW( byte ) (NibbleW[byte])
  65. WCHAR NibbleW[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
  66. #ifdef WMI_SUPPORT
  67. #define NUM_PORT_WMI_SUPPORTED_GUIDS 1
  68. WMIGUIDREGINFO USB_PortWmiGuidList[NUM_PORT_WMI_SUPPORTED_GUIDS];
  69. #endif /* WMI_SUPPORT */
  70. WCHAR VidPidRevString[] = L"USB\\Vid_nnnn&Pid_nnnn&Rev_nnnn&Mi_nn";
  71. WCHAR VidPidString[] = L"USB\\Vid_nnnn&Pid_nnnn&Mi_nn";
  72. USB_CONNECTION_STATUS
  73. UsbhGetConnectionStatus(
  74. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort
  75. )
  76. /*
  77. * Description:
  78. *
  79. * returns the connection status for a PDO
  80. *
  81. * Arguments:
  82. *
  83. * Return:
  84. *
  85. * NTSTATUS
  86. *
  87. * -- */
  88. {
  89. PDEVICE_EXTENSION_HUB deviceExtensionHub;
  90. deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub;
  91. if (DeviceExtensionPort->PortPdoFlags &
  92. PORTPDO_DEVICE_ENUM_ERROR) {
  93. return DeviceFailedEnumeration;
  94. } else if (DeviceExtensionPort->PortPdoFlags &
  95. PORTPDO_NOT_ENOUGH_POWER) {
  96. return DeviceNotEnoughPower;
  97. } else if (DeviceExtensionPort->PortPdoFlags &
  98. PORTPDO_DEVICE_FAILED) {
  99. return DeviceGeneralFailure;
  100. } else if (DeviceExtensionPort->PortPdoFlags &
  101. PORTPDO_OVERCURRENT) {
  102. return DeviceCausedOvercurrent;
  103. } else if (DeviceExtensionPort->PortPdoFlags &
  104. PORTPDO_NO_BANDWIDTH) {
  105. return DeviceNotEnoughBandwidth;
  106. } else if (DeviceExtensionPort->PortPdoFlags &
  107. PORTPDO_USB20_DEVICE_IN_LEGACY_HUB) {
  108. return DeviceInLegacyHub;
  109. }
  110. // otherwise just return "device connected"
  111. return DeviceConnected;
  112. }
  113. VOID
  114. USBH_BandwidthTimeoutWorker(
  115. IN PVOID Context)
  116. /* ++
  117. *
  118. * Description:
  119. *
  120. * Work item scheduled to handle a bandwidth timeout.
  121. *
  122. *
  123. * Arguments:
  124. *
  125. * Return:
  126. *
  127. * -- */
  128. {
  129. PUSBH_BANDWIDTH_TIMEOUT_WORK_ITEM workItemBandwidthTimeout;
  130. PDEVICE_EXTENSION_PORT deviceExtensionPort;
  131. PDEVICE_EXTENSION_HUB deHub;
  132. workItemBandwidthTimeout = Context;
  133. deviceExtensionPort = workItemBandwidthTimeout->DeviceExtensionPort;
  134. USBH_KdPrint((2,"'Bandwidth timeout\n"));
  135. // note that deHub may be null if the bandwidth error occurs
  136. // during device start. We introduced a bug when we nulled out
  137. // the baclpointer to the hub. The 'fix' is to use the hubExtsave pointer
  138. // the backpointer that is always set even after soft remove.
  139. //
  140. // However this code is still broken in that it references a hub that
  141. // may or may not be there. All we are doing here is restoring the
  142. // original 'brokeness'.
  143. deHub = deviceExtensionPort->DeviceExtensionHub;
  144. if (deHub == NULL) {
  145. // use alternate pointer
  146. deHub = deviceExtensionPort->HubExtSave;
  147. }
  148. USBH_PdoEvent(deHub,
  149. deviceExtensionPort->PortNumber);
  150. UsbhExFreePool(workItemBandwidthTimeout);
  151. }
  152. VOID
  153. USBH_PortTimeoutDPC(
  154. IN PKDPC Dpc,
  155. IN PVOID DeferredContext,
  156. IN PVOID SystemArgument1,
  157. IN PVOID SystemArgument2
  158. )
  159. /*++
  160. Routine Description:
  161. This routine runs at DISPATCH_LEVEL IRQL.
  162. Arguments:
  163. Dpc - Pointer to the DPC object.
  164. DeferredContext -
  165. SystemArgument1 - not used.
  166. SystemArgument2 - not used.
  167. Return Value:
  168. None.
  169. --*/
  170. {
  171. PPORT_TIMEOUT_CONTEXT portTimeoutContext = DeferredContext;
  172. PDEVICE_EXTENSION_PORT deviceExtensionPort =
  173. portTimeoutContext->DeviceExtensionPort;
  174. BOOLEAN cancelFlag;
  175. PUSBH_BANDWIDTH_TIMEOUT_WORK_ITEM workItemBandwidthTimeout;
  176. USBH_KdPrint((2,"'BANDWIDTH_TIMEOUT\n"));
  177. // Take SpinLock here so that main routine won't write CancelFlag
  178. // in the timeout context while we free the timeout context.
  179. KeAcquireSpinLockAtDpcLevel(&deviceExtensionPort->PortSpinLock);
  180. cancelFlag = portTimeoutContext->CancelFlag;
  181. deviceExtensionPort->PortTimeoutContext = NULL;
  182. KeReleaseSpinLockFromDpcLevel(&deviceExtensionPort->PortSpinLock);
  183. UsbhExFreePool(portTimeoutContext);
  184. if (!cancelFlag) {
  185. //
  186. // Schedule a work item to process this.
  187. //
  188. workItemBandwidthTimeout = UsbhExAllocatePool(NonPagedPool,
  189. sizeof(USBH_BANDWIDTH_TIMEOUT_WORK_ITEM));
  190. if (workItemBandwidthTimeout) {
  191. workItemBandwidthTimeout->DeviceExtensionPort = deviceExtensionPort;
  192. ExInitializeWorkItem(&workItemBandwidthTimeout->WorkQueueItem,
  193. USBH_BandwidthTimeoutWorker,
  194. workItemBandwidthTimeout);
  195. LOGENTRY(LOG_PNP, "bERR", deviceExtensionPort,
  196. &workItemBandwidthTimeout->WorkQueueItem, 0);
  197. ExQueueWorkItem(&workItemBandwidthTimeout->WorkQueueItem,
  198. DelayedWorkQueue);
  199. // The WorkItem is freed by USBH_BandwidthTimeoutWorker()
  200. // Don't try to access the WorkItem after it is queued.
  201. }
  202. }
  203. }
  204. NTSTATUS
  205. USBH_SelectConfigOrInterface_Complete(
  206. IN PDEVICE_OBJECT PNull,
  207. IN PIRP Irp,
  208. IN PVOID Context
  209. )
  210. /* ++
  211. *
  212. * Description:
  213. *
  214. * Take some action based on change
  215. *
  216. * Arguments:
  217. *
  218. * Return:
  219. *
  220. *
  221. * -- */
  222. {
  223. PDEVICE_EXTENSION_PORT deviceExtensionPort = Context;
  224. PDEVICE_EXTENSION_HUB deviceExtensionHub = NULL;
  225. PPORT_DATA portData = NULL;
  226. NTSTATUS ntStatus;
  227. PURB urb;
  228. PIO_STACK_LOCATION ioStackLocation;
  229. PPORT_TIMEOUT_CONTEXT portTimeoutContext = NULL;
  230. LARGE_INTEGER dueTime;
  231. KIRQL irql;
  232. if (Irp->PendingReturned) {
  233. IoMarkIrpPending(Irp);
  234. }
  235. deviceExtensionHub = deviceExtensionPort->DeviceExtensionHub;
  236. if (deviceExtensionHub) {
  237. portData = &deviceExtensionHub->PortData[deviceExtensionPort->PortNumber - 1];
  238. }
  239. ntStatus = Irp->IoStatus.Status;
  240. if (ntStatus == STATUS_SUCCESS) {
  241. //
  242. // "Cancel" timer.
  243. //
  244. // Take SpinLock here so that DPC routine won't free
  245. // the timeout context while we write the CancelFlag
  246. // in the timeout context.
  247. //
  248. KeAcquireSpinLock(&deviceExtensionPort->PortSpinLock, &irql);
  249. if (deviceExtensionPort->PortTimeoutContext) {
  250. USBH_KdPrint((2,"'Bandwidth allocation successful, cancelling timeout\n"));
  251. portTimeoutContext = deviceExtensionPort->PortTimeoutContext;
  252. portTimeoutContext->CancelFlag = TRUE;
  253. if (KeCancelTimer(&portTimeoutContext->TimeoutTimer)) {
  254. //
  255. // We cancelled the timer before it could run. Free the context.
  256. //
  257. UsbhExFreePool(portTimeoutContext);
  258. deviceExtensionPort->PortTimeoutContext = NULL;
  259. }
  260. }
  261. KeReleaseSpinLock(&deviceExtensionPort->PortSpinLock, irql);
  262. // clear the error
  263. deviceExtensionPort->PortPdoFlags &=
  264. ~(PORTPDO_DEVICE_FAILED | PORTPDO_NO_BANDWIDTH);
  265. // Don't stomp connection status for a hub that is nested too
  266. // deeply.
  267. if (portData &&
  268. portData->ConnectionStatus != DeviceHubNestedTooDeeply) {
  269. portData->ConnectionStatus = DeviceConnected;
  270. }
  271. } else {
  272. // extract the URB
  273. ioStackLocation = IoGetCurrentIrpStackLocation(Irp);
  274. urb = ioStackLocation->Parameters.Others.Argument1;
  275. if (urb->UrbHeader.Status == USBD_STATUS_NO_BANDWIDTH) {
  276. deviceExtensionPort->RequestedBandwidth = 0;
  277. if (urb->UrbHeader.Function == URB_FUNCTION_SELECT_INTERFACE) {
  278. USBH_CalculateInterfaceBandwidth(
  279. deviceExtensionPort,
  280. &urb->UrbSelectInterface.Interface,
  281. &deviceExtensionPort->RequestedBandwidth);
  282. } else if (urb->UrbHeader.Function ==
  283. URB_FUNCTION_SELECT_CONFIGURATION){
  284. // we need to walk through the config
  285. // and get all the interfcaces
  286. PUCHAR pch, end;
  287. PUSBD_INTERFACE_INFORMATION iface;
  288. end = (PUCHAR) urb;
  289. end += urb->UrbHeader.Length;
  290. pch = (PUCHAR) &urb->UrbSelectConfiguration.Interface;
  291. iface = (PUSBD_INTERFACE_INFORMATION) pch;
  292. while (pch < end) {
  293. USBH_CalculateInterfaceBandwidth(
  294. deviceExtensionPort,
  295. iface,
  296. &deviceExtensionPort->RequestedBandwidth);
  297. pch += iface->Length;
  298. iface = (PUSBD_INTERFACE_INFORMATION) pch;
  299. }
  300. } else {
  301. // did we miss something?
  302. TEST_TRAP();
  303. }
  304. deviceExtensionPort->PortPdoFlags |=
  305. PORTPDO_NO_BANDWIDTH;
  306. if (portData) {
  307. portData->ConnectionStatus = DeviceNotEnoughBandwidth;
  308. }
  309. if (!deviceExtensionPort->PortTimeoutContext) {
  310. USBH_KdPrint((2,"'Start bandwidth timeout\n"));
  311. portTimeoutContext = UsbhExAllocatePool(NonPagedPool,
  312. sizeof(*portTimeoutContext));
  313. if (portTimeoutContext) {
  314. portTimeoutContext->CancelFlag = FALSE;
  315. // Maintain links between the device extension and the
  316. // timeout context.
  317. deviceExtensionPort->PortTimeoutContext = portTimeoutContext;
  318. portTimeoutContext->DeviceExtensionPort = deviceExtensionPort;
  319. KeInitializeTimer(&portTimeoutContext->TimeoutTimer);
  320. KeInitializeDpc(&portTimeoutContext->TimeoutDpc,
  321. USBH_PortTimeoutDPC,
  322. portTimeoutContext);
  323. }
  324. }
  325. #if DBG
  326. else {
  327. USBH_KdPrint((2,"'Reset bandwidth timeout\n"));
  328. }
  329. #endif
  330. dueTime.QuadPart = -10000 * BANDWIDTH_TIMEOUT;
  331. // Take spinlock here in case DPC routine fires and deallocates
  332. // the timer context before we have had the chance to reset the
  333. // timer (in the case where we are resetting an existing timer).
  334. KeAcquireSpinLock(&deviceExtensionPort->PortSpinLock, &irql);
  335. portTimeoutContext = deviceExtensionPort->PortTimeoutContext;
  336. if (portTimeoutContext) {
  337. KeSetTimer(&portTimeoutContext->TimeoutTimer,
  338. dueTime,
  339. &portTimeoutContext->TimeoutDpc);
  340. }
  341. KeReleaseSpinLock(&deviceExtensionPort->PortSpinLock, irql);
  342. }
  343. }
  344. return ntStatus;
  345. }
  346. NTSTATUS
  347. USBH_PdoUrbFilter(
  348. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  349. IN PIRP Irp
  350. )
  351. /*
  352. * Description:
  353. *
  354. * Arguments:
  355. *
  356. * Return:
  357. *
  358. * NTSTATUS
  359. *
  360. * -- */
  361. {
  362. NTSTATUS ntStatus = STATUS_SUCCESS;
  363. PIO_STACK_LOCATION ioStackLocation; // our stack location
  364. PDEVICE_EXTENSION_HUB deviceExtensionHub;
  365. PURB urb;
  366. USHORT function;
  367. PDEVICE_OBJECT deviceObject;
  368. PPORT_DATA portData;
  369. USBH_KdPrint((2,"'USBH_PdoUrbFilter DeviceExtension %x Irp %x\n",
  370. DeviceExtensionPort, Irp));
  371. deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub;
  372. LOGENTRY(LOG_PNP, "pURB", DeviceExtensionPort, deviceExtensionHub,
  373. deviceExtensionHub->HubFlags);
  374. portData = &deviceExtensionHub->PortData[DeviceExtensionPort->PortNumber - 1];
  375. deviceObject = DeviceExtensionPort->PortPhysicalDeviceObject;
  376. ioStackLocation = IoGetCurrentIrpStackLocation(Irp);
  377. urb = ioStackLocation->Parameters.Others.Argument1;
  378. #if DBG
  379. if (!(DeviceExtensionPort->PortPdoFlags & PORTPDO_STARTED) &&
  380. (DeviceExtensionPort->PortPdoFlags & PORTPDO_NEED_RESET)) {
  381. UsbhWarning(DeviceExtensionPort,
  382. "Device Driver is sending requests before passing start irp\n, Please rev your driver.\n",
  383. TRUE);
  384. }
  385. #endif
  386. //
  387. // in some cases we will need to fail bus requests here.
  388. //
  389. // if (DeviceExtensionPort->DeviceState != PowerDeviceD0) {
  390. // // fail any call that is sent to a PDO for a suspended device
  391. // UsbhWarning(DeviceExtensionPort,
  392. // "Device Driver is sending requests while in low power state!\n",
  393. // TRUE);
  394. // ntStatus = STATUS_INVALID_PARAMETER;
  395. // }
  396. #if DBG
  397. if (DeviceExtensionPort->DeviceState != PowerDeviceD0) {
  398. USBH_KdPrint((1, "'URB request, device not in D0\n"));
  399. }
  400. #endif
  401. if (DeviceExtensionPort->PortPdoFlags & (PORTPDO_DEVICE_FAILED | PORTPDO_RESET_PENDING)) {
  402. USBH_KdPrint((1, "'failing request to failed PDO\n"));
  403. ntStatus = STATUS_INVALID_PARAMETER;
  404. }
  405. // check for error, if we have one, bail
  406. if (!NT_SUCCESS(ntStatus)) {
  407. urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
  408. USBH_CompleteIrp(Irp, ntStatus);
  409. goto USBH_PdoUrbFilter_Done;
  410. }
  411. // check the command code code the URB
  412. function = urb->UrbHeader.Function;
  413. LOGENTRY(LOG_PNP, "URB+", DeviceExtensionPort,
  414. function,
  415. urb);
  416. switch(function) {
  417. case URB_FUNCTION_SELECT_CONFIGURATION:
  418. if (urb->UrbSelectConfiguration.ConfigurationDescriptor != NULL) {
  419. LONG powerRequired;
  420. // validate the descriptor passed to us before we
  421. // attempt to refernce it
  422. {
  423. PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor;
  424. USBD_STATUS usbdStatus;
  425. configurationDescriptor =
  426. urb->UrbSelectConfiguration.ConfigurationDescriptor;
  427. if (!USBH_ValidateConfigurationDescriptor(
  428. configurationDescriptor,
  429. &usbdStatus)) {
  430. urb->UrbHeader.Status =
  431. usbdStatus;
  432. ntStatus = STATUS_INVALID_PARAMETER;
  433. USBH_CompleteIrp(Irp, ntStatus);
  434. goto USBH_PdoUrbFilter_Done;
  435. }
  436. }
  437. //
  438. // make sure there is enough power on this port
  439. //
  440. DeviceExtensionPort->PowerRequested =
  441. powerRequired =
  442. ((LONG)urb->UrbSelectConfiguration.ConfigurationDescriptor->MaxPower)*2;
  443. #if DBG
  444. if (UsbhPnpTest & PNP_TEST_FAIL_DEV_POWER) {
  445. powerRequired = 99999;
  446. }
  447. #endif
  448. USBH_KdPrint((2,"'request power: avail = %d Need = %d\n",
  449. deviceExtensionHub->MaximumPowerPerPort, powerRequired));
  450. if (deviceExtensionHub->MaximumPowerPerPort < powerRequired) {
  451. USBH_KdPrint((1, "'**insufficient power for device\n"));
  452. // not enough power for this device
  453. // mark the PDO
  454. DeviceExtensionPort->PortPdoFlags |=
  455. PORTPDO_NOT_ENOUGH_POWER;
  456. USBH_InvalidatePortDeviceState(
  457. deviceExtensionHub,
  458. UsbhGetConnectionStatus(DeviceExtensionPort),
  459. DeviceExtensionPort->PortNumber);
  460. ntStatus = STATUS_INVALID_PARAMETER;
  461. USBH_CompleteIrp(Irp, ntStatus);
  462. goto USBH_PdoUrbFilter_Done;
  463. }
  464. }
  465. // check for BW failure
  466. IoCopyCurrentIrpStackLocationToNext(Irp);
  467. IoSetCompletionRoutine(Irp,
  468. USBH_SelectConfigOrInterface_Complete,
  469. // always pass FDO to completion routine
  470. DeviceExtensionPort,
  471. TRUE,
  472. TRUE,
  473. TRUE);
  474. ntStatus = IoCallDriver(deviceExtensionHub->TopOfHcdStackDeviceObject, Irp);
  475. goto USBH_PdoUrbFilter_Done;
  476. break;
  477. case URB_FUNCTION_SELECT_INTERFACE:
  478. IoCopyCurrentIrpStackLocationToNext(Irp);
  479. IoSetCompletionRoutine(Irp,
  480. USBH_SelectConfigOrInterface_Complete,
  481. // always pass FDO to completion routine
  482. DeviceExtensionPort,
  483. TRUE,
  484. TRUE,
  485. TRUE);
  486. ntStatus = IoCallDriver(deviceExtensionHub->TopOfHcdStackDeviceObject, Irp);
  487. goto USBH_PdoUrbFilter_Done;
  488. break;
  489. //
  490. // we could fail everything provided we abort
  491. // all the drivers pipes.
  492. //
  493. // fail any transfers if delete is pending
  494. case URB_FUNCTION_CONTROL_TRANSFER:
  495. case URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER:
  496. case URB_FUNCTION_ISOCH_TRANSFER:
  497. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DELETE_PENDING) {
  498. USBH_KdPrint((2,"'failing request with STATUS_DELETE_PENDING\n"));
  499. ntStatus = STATUS_DELETE_PENDING;
  500. urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
  501. USBH_CompleteIrp(Irp, ntStatus);
  502. goto USBH_PdoUrbFilter_Done;
  503. }
  504. break;
  505. case URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR:
  506. LOGENTRY(LOG_PNP, "MSOS", DeviceExtensionPort,
  507. DeviceExtensionPort->PortPdoFlags, 0);
  508. USBH_KdPrint((1,"'URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR\n"));
  509. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DELETE_PENDING) {
  510. USBH_KdPrint((1,"'GET_MS_FEATURE_DESC: failing request with STATUS_DELETE_PENDING\n"));
  511. ntStatus = STATUS_DELETE_PENDING;
  512. urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
  513. USBH_CompleteIrp(Irp, ntStatus);
  514. goto USBH_PdoUrbFilter_Done;
  515. }
  516. #ifndef USBHUB20
  517. ntStatus = USBH_GetMsOsFeatureDescriptor(
  518. deviceObject,
  519. urb->UrbOSFeatureDescriptorRequest.Recipient,
  520. urb->UrbOSFeatureDescriptorRequest.InterfaceNumber,
  521. urb->UrbOSFeatureDescriptorRequest.MS_FeatureDescriptorIndex,
  522. urb->UrbOSFeatureDescriptorRequest.TransferBuffer,
  523. urb->UrbOSFeatureDescriptorRequest.TransferBufferLength,
  524. &urb->UrbOSFeatureDescriptorRequest.TransferBufferLength);
  525. #endif
  526. if (NT_SUCCESS(ntStatus))
  527. {
  528. urb->UrbHeader.Status = USBD_STATUS_SUCCESS;
  529. }
  530. else
  531. {
  532. // arbitrary URB error status...
  533. //
  534. urb->UrbHeader.Status = USBD_STATUS_INVALID_PARAMETER;
  535. }
  536. USBH_CompleteIrp(Irp, ntStatus);
  537. goto USBH_PdoUrbFilter_Done;
  538. break;
  539. default:
  540. // just pass thru
  541. break;
  542. }
  543. ntStatus = USBH_PassIrp(Irp,
  544. deviceExtensionHub->TopOfHcdStackDeviceObject);
  545. USBH_PdoUrbFilter_Done:
  546. return ntStatus;
  547. }
  548. PWCHAR
  549. USBH_BuildDeviceID(
  550. IN USHORT IdVendor,
  551. IN USHORT IdProduct,
  552. IN LONG MiId,
  553. IN BOOLEAN IsHubClass
  554. )
  555. /* ++
  556. *
  557. * Descrioption:
  558. *
  559. * This function build bus Id wide string for the PDO based on the Vendor Id
  560. * and Product Id. We allocate memory for the string which will be attached
  561. * to the PDO. L"USB\\Vid_nnnn&Pid_nnnn(&Mi_nn)\0"
  562. *
  563. * Arguments:
  564. *
  565. * DeviceExtensionPort - the PDO
  566. *
  567. * Return:
  568. *
  569. * the pointer to the wide string if successful NULL - otherwise
  570. *
  571. * -- */
  572. {
  573. PWCHAR pwch, p, vid, pid, mi;
  574. ULONG need;
  575. PAGED_CODE();
  576. #ifdef USBHUB20
  577. if (IsHubClass) {
  578. return USBH_BuildHubDeviceID(IdVendor,
  579. IdProduct,
  580. MiId);
  581. }
  582. #endif
  583. USBH_KdPrint((2,"'DeviceId VendorId %04x ProductId %04x interface %04x\n",
  584. IdVendor, IdProduct, MiId));
  585. // allow for extra NULL
  586. need = sizeof(VidPidString) + 2;
  587. USBH_KdPrint((2,"'allocate %d bytes for device id string\n", need));
  588. //
  589. // Must use ExAllocatePool directly here because the OS
  590. // will free the buffer
  591. //
  592. pwch = ExAllocatePoolWithTag(PagedPool, need, USBHUB_HEAP_TAG);
  593. if (NULL == pwch)
  594. return NULL;
  595. RtlZeroMemory(pwch, need);
  596. p = pwch;
  597. // BUILD
  598. // USB\\Vid_nnnn&Pid_nnnn(&Mi_nn){NULL}
  599. RtlCopyMemory(p, VidPidString, sizeof(VidPidString));
  600. // now update the id fields
  601. vid = p + 8;
  602. pid = p + 17;
  603. mi = p + 25;
  604. *vid = NibbleToHex(IdVendor >> 12);
  605. *(vid+1) = NibbleToHex((IdVendor >> 8) & 0x000f);
  606. *(vid+2) = NibbleToHex((IdVendor >> 4) & 0x000f);
  607. *(vid+3) = NibbleToHex(IdVendor & 0x000f);
  608. *pid = NibbleToHex(IdProduct >> 12);
  609. *(pid+1) = NibbleToHex((IdProduct >> 8) & 0x000f);
  610. *(pid+2) = NibbleToHex((IdProduct >> 4) & 0x000f);
  611. *(pid+3) = NibbleToHex(IdProduct & 0x000f);
  612. if (MiId == -1) {
  613. p = p + 21;
  614. *p = (WCHAR)NULL;
  615. p++;
  616. *p = (WCHAR)NULL;
  617. } else {
  618. *mi = NibbleToHex(MiId >> 4);
  619. *(mi+1) = NibbleToHex(MiId & 0x000f);
  620. }
  621. USBH_KdPrint((2,"'Device id string = 0x%x\n", pwch));
  622. return pwch;
  623. }
  624. PWCHAR
  625. USBH_BuildHardwareIDs(
  626. IN USHORT IdVendor,
  627. IN USHORT IdProduct,
  628. IN USHORT BcdDevice,
  629. IN LONG MiId,
  630. IN BOOLEAN IsHubClass
  631. )
  632. /* ++
  633. *
  634. * Description:
  635. *
  636. * This function build HardwareIDs wide multi-string for the PDO based on the
  637. * Vendor Id, Product Id and Revision Id. We allocate memory for the
  638. * multi-string which will be attached to the PDO.
  639. * L"USB\\Vid_nnnn&Pid_nnnn&Rev_nnnn\0USB\\Vid_nnnn&Pid_nnnn\0\0"
  640. *
  641. * Arguments:
  642. *
  643. * DeviceExtensionPort - the PDO
  644. *
  645. * Return:
  646. *
  647. * the pointer to the wide multi-string if successful NULL - otherwise
  648. *
  649. * -- */
  650. {
  651. PWCHAR pwch, p, vid, pid, rev, mi;
  652. ULONG need;
  653. PAGED_CODE();
  654. #ifdef USBHUB20
  655. if (IsHubClass) {
  656. return USBH_BuildHubHardwareIDs(
  657. IdVendor,
  658. IdProduct,
  659. BcdDevice,
  660. MiId);
  661. }
  662. #endif // USBHUB20
  663. USBH_KdPrint((2,"'HardwareIDs VendorId %04x ProductId %04x Revision %04x interface %04x\n",
  664. IdVendor, IdProduct, BcdDevice, MiId));
  665. // allow for extra NULL
  666. need = sizeof(VidPidRevString) + sizeof(VidPidString) + 2;
  667. USBH_KdPrint((2,"'allocate %d bytes for id string\n", need));
  668. //
  669. // Must use ExAllocatePool directly here because the OS
  670. // will free the buffer
  671. //
  672. pwch = ExAllocatePoolWithTag(PagedPool, need, USBHUB_HEAP_TAG);
  673. if (NULL == pwch)
  674. return NULL;
  675. RtlZeroMemory(pwch, need);
  676. // build two strings in to buffer:
  677. // USB\\Vid_nnnn&Pid_nnnn&Rev_nnnn&Mi_nn{NULL}
  678. // USB\\Vid_nnnn&Pid_nnnn&Mi_nn{NULL}{NULL}
  679. // BUILD
  680. // USB\\Vid_nnnn&Pid_nnnn&Rev_nnnn&(Mi_nn){NULL}
  681. RtlCopyMemory(pwch, VidPidRevString, sizeof(VidPidRevString));
  682. p = pwch;
  683. // now update the id fields
  684. vid = p + 8;
  685. pid = p + 17;
  686. rev = p + 26;
  687. mi = p + 34;
  688. *vid = NibbleToHex(IdVendor >> 12);
  689. *(vid+1) = NibbleToHex((IdVendor >> 8) & 0x000f);
  690. *(vid+2) = NibbleToHex((IdVendor >> 4) & 0x000f);
  691. *(vid+3) = NibbleToHex(IdVendor & 0x000f);
  692. *pid = NibbleToHex(IdProduct >> 12);
  693. *(pid+1) = NibbleToHex((IdProduct >> 8) & 0x000f);
  694. *(pid+2) = NibbleToHex((IdProduct >> 4) & 0x000f);
  695. *(pid+3) = NibbleToHex(IdProduct & 0x000f);
  696. *rev = BcdNibbleToAscii(BcdDevice >> 12);
  697. *(rev+1) = BcdNibbleToAscii((BcdDevice >> 8) & 0x000f);
  698. *(rev+2) = BcdNibbleToAscii((BcdDevice >> 4) & 0x000f);
  699. *(rev+3) = BcdNibbleToAscii(BcdDevice & 0x000f);
  700. if (MiId == -1) {
  701. p = p + 30;
  702. *p = (WCHAR)NULL;
  703. p++;
  704. } else {
  705. p = p + 37;
  706. *mi = NibbleToHex(MiId >> 4);
  707. *(mi+1) = NibbleToHex(MiId & 0x000f);
  708. }
  709. // BUILD
  710. // USB\\Vid_nnnn&Pid_nnnn(&Mi_nn){NULL}
  711. RtlCopyMemory(p, VidPidString, sizeof(VidPidString));
  712. // now update the id fields
  713. vid = p + 8;
  714. pid = p + 17;
  715. mi = p + 25;
  716. *vid = NibbleToHex(IdVendor >> 12);
  717. *(vid+1) = NibbleToHex((IdVendor >> 8) & 0x000f);
  718. *(vid+2) = NibbleToHex((IdVendor >> 4) & 0x000f);
  719. *(vid+3) = NibbleToHex(IdVendor & 0x000f);
  720. *pid = NibbleToHex(IdProduct >> 12);
  721. *(pid+1) = NibbleToHex((IdProduct >> 8) & 0x000f);
  722. *(pid+2) = NibbleToHex((IdProduct >> 4) & 0x000f);
  723. *(pid+3) = NibbleToHex(IdProduct & 0x000f);
  724. if (MiId == -1) {
  725. p = p + 21;
  726. *p = (WCHAR)NULL;
  727. p++;
  728. *p = (WCHAR)NULL;
  729. } else {
  730. *mi = NibbleToHex(MiId >> 4);
  731. *(mi+1) = NibbleToHex(MiId & 0x000f);
  732. }
  733. USBH_KdPrint((2,"'HW id string = 0x%x\n", pwch));
  734. return pwch;
  735. }
  736. #if 0
  737. PWCHAR
  738. USBH_BuildCompatibleIDs(
  739. IN UCHAR Class,
  740. IN UCHAR SubClass,
  741. IN UCHAR Protocol,
  742. IN BOOLEAN DeviceClass,
  743. IN BOOLEAN DeviceIsHighSpeed
  744. )
  745. /* ++
  746. *
  747. * Descrioption:
  748. *
  749. * This function build compatible Ids wide multi-string for the PDO based on
  750. * the Class and Subclass Ids. We allocate memory for the string which will
  751. * be attached to the PDO.
  752. * L"USB\\Class_nn&SubClass_nn&Prot_nn\0"
  753. * L"USB\\Class_nn&SubClass_nn\0"
  754. * L"USB\Class_nn\0"
  755. * L"USB\COMPOSITE\0"
  756. * L"\0"
  757. *
  758. * Arguments:
  759. *
  760. * DeviceExtensionPort - the PDO
  761. *
  762. * Return:
  763. *
  764. * the pointer to the multi-string if successful NULL - otherwise
  765. *
  766. *
  767. * -- */
  768. {
  769. PWCHAR pwch, pwch1;
  770. ULONG ulBytes;
  771. ULONG ulTotal;
  772. BOOLEAN ControlerIsHS = FALSE;
  773. PAGED_CODE();
  774. USBH_KdPrint((2,"'Enter BuildCompatibleIDs\n"));
  775. #ifdef USBHUB20
  776. ControlerIsHS = TRUE;
  777. #endif
  778. // if this is a high speed controller (USB2) then we must
  779. // generate a different set of compat ids to be backward
  780. // compatible with the goatpack
  781. if (Class == USB_DEVICE_CLASS_HUB &&
  782. ControlerIsHS) {
  783. return USBH_BuildHubCompatibleIDs(
  784. Class,
  785. SubClass,
  786. Protocol,
  787. DeviceClass,
  788. DeviceIsHighSpeed);
  789. }
  790. //#endif
  791. STRLEN(ulBytes, pwchUsbSlash);
  792. ulTotal = ulBytes * 3; // 3 sets of L"USB\\"
  793. if (DeviceClass) {
  794. STRLEN(ulBytes, pwchDevClass);
  795. ulTotal += ulBytes * 3; // 3 sets of L"DevClass_"
  796. STRLEN(ulBytes, pwchComposite);
  797. ulTotal += ulBytes; // "USB\COMPOSITE"
  798. } else {
  799. STRLEN(ulBytes, pwchClass);
  800. ulTotal += ulBytes * 3; // 3 sets of L"Class_"
  801. }
  802. STRLEN(ulBytes, pwchSubClass);
  803. ulTotal += ulBytes * 2; // 2 sets of L"SubClass_"
  804. STRLEN(ulBytes, pwchProt);
  805. ulTotal += ulBytes; // 1 set of L"Prot_"
  806. ulTotal += sizeof(WCHAR) * (2 * 6 + 3 + 5); // 6 sets of 2 digits, 3 '&'s,
  807. // and 5 nulls
  808. //
  809. // Must use ExAllocatePool directly here because the OS
  810. // will free the buffer
  811. //
  812. pwch = ExAllocatePoolWithTag(PagedPool, ulTotal, USBHUB_HEAP_TAG);
  813. if (NULL == pwch)
  814. return NULL;
  815. USBH_KdPrint((2,"'Interface Class %02x SubClass %02x Protocol %02x\n",
  816. Class, SubClass, Protocol));
  817. //
  818. // First string
  819. //
  820. STRCPY(pwch, pwchUsbSlash);
  821. //
  822. // ClassId
  823. //
  824. if (DeviceClass) {
  825. STRCAT(pwch, pwchDevClass);
  826. } else {
  827. STRCAT(pwch, pwchClass);
  828. }
  829. APPEND(pwch, NibbleToHex((Class) >> 4));
  830. APPEND(pwch, NibbleToHex((Class) & 0x0f));
  831. APPEND(pwch, '&');
  832. //
  833. // SubClassId
  834. //
  835. STRCAT(pwch, pwchSubClass);
  836. APPEND(pwch, NibbleToHex((SubClass) >> 4));
  837. APPEND(pwch, NibbleToHex((SubClass) & 0x0f));
  838. APPEND(pwch, '&');
  839. //
  840. // DeviceProtocol
  841. //
  842. STRCAT(pwch, pwchProt);
  843. APPEND(pwch, NibbleToHex((Protocol) >> 4));
  844. APPEND(pwch, NibbleToHex((Protocol) & 0x0f));
  845. //
  846. // Second string
  847. //
  848. STRLEN(ulBytes, pwch);
  849. pwch1 = &pwch[ulBytes / 2 + 1]; // second string
  850. STRCPY(pwch1, pwchUsbSlash);
  851. //
  852. // ClassId
  853. //
  854. if (DeviceClass) {
  855. STRCAT(pwch1, pwchDevClass);
  856. } else {
  857. STRCAT(pwch1, pwchClass);
  858. }
  859. APPEND(pwch1, NibbleToHex((Class) >> 4));
  860. APPEND(pwch1, NibbleToHex((Class) & 0x0f));
  861. APPEND(pwch1, '&');
  862. //
  863. // SubClassId
  864. //
  865. STRCAT(pwch1, pwchSubClass);
  866. APPEND(pwch1, NibbleToHex((SubClass) >> 4));
  867. APPEND(pwch1, NibbleToHex((SubClass) & 0x0f));
  868. //
  869. // Third string USB\Class_nn
  870. //
  871. STRLEN(ulBytes, pwch1);
  872. pwch1 = &pwch1[ulBytes / 2 + 1]; // third string
  873. STRCPY(pwch1, pwchUsbSlash);
  874. //
  875. // Class Id
  876. //
  877. if (DeviceClass) {
  878. STRCAT(pwch1, pwchDevClass);
  879. } else {
  880. STRCAT(pwch1, pwchClass);
  881. }
  882. APPEND(pwch1, NibbleToHex((Class) >> 4));
  883. APPEND(pwch1, NibbleToHex((Class) & 0x0f));
  884. //
  885. // Third string
  886. //
  887. // STRLEN( ulBytes, pwch1 );
  888. // pwch1 = &pwch1[ulBytes /2 + 1]; // third string
  889. // STRCPY( pwch1, pwchUsbSlash );
  890. //
  891. // ClassId
  892. //
  893. // APPEND( pwch1, NibbleToHex((pDeviceDescriptor->bDeviceClass)>>4));
  894. // APPEND( pwch1, NibbleToHex((pDeviceDescriptor->bDeviceClass) & 0x0f));
  895. //
  896. // SubClassId
  897. //
  898. // APPEND( pwch1, NibbleToHex((pDeviceDescriptor->bDeviceSubClass) >>
  899. // 4));
  900. // APPEND( pwch1, NibbleToHex((pDeviceDescriptor->bDeviceSubClass)
  901. // &0x0f));
  902. if (DeviceClass) {
  903. STRLEN(ulBytes, pwch1);
  904. pwch1 = &pwch1[ulBytes / 2 + 1];
  905. STRCPY(pwch1, pwchComposite);
  906. }
  907. //
  908. // double null termination
  909. //
  910. APPEND(pwch1, 0);
  911. return pwch;
  912. }
  913. #else
  914. typedef struct _DEVCLASS_COMAPTIBLE_IDS
  915. {
  916. // L"USB\\DevClass_nn&SubClass_nn&Prot_nn\0"
  917. //
  918. WCHAR ClassStr1[sizeof(L"USB\\DevClass_")/sizeof(WCHAR)-1];
  919. WCHAR ClassHex1[2];
  920. WCHAR SubClassStr1[sizeof(L"&SubClass_")/sizeof(WCHAR)-1];
  921. WCHAR SubClassHex1[2];
  922. WCHAR Prot1[sizeof(L"&Prot_")/sizeof(WCHAR)-1];
  923. WCHAR ProtHex1[2];
  924. WCHAR Null1[1];
  925. // L"USB\\DevClass_nn&SubClass_nn\0"
  926. //
  927. WCHAR DevClassStr2[sizeof(L"USB\\DevClass_")/sizeof(WCHAR)-1];
  928. WCHAR ClassHex2[2];
  929. WCHAR SubClassStr2[sizeof(L"&SubClass_")/sizeof(WCHAR)-1];
  930. WCHAR SubClassHex2[2];
  931. WCHAR Null2[1];
  932. // L"USB\\DevClass_nn&SubClass_nn\0"
  933. //
  934. WCHAR ClassStr3[sizeof(L"USB\\DevClass_")/sizeof(WCHAR)-1];
  935. WCHAR ClassHex3[2];
  936. WCHAR Null3[1];
  937. // L"USB\\COMPOSITE\0"
  938. //
  939. WCHAR CompositeStr[sizeof(L"USB\\COMPOSITE")/sizeof(WCHAR)-1];
  940. WCHAR Null4[1];
  941. WCHAR DoubleNull[1];
  942. } DEVCLASS_COMAPTIBLE_IDS, *PDEVCLASS_COMAPTIBLE_IDS;
  943. typedef struct _CLASS_COMAPTIBLE_IDS
  944. {
  945. // L"USB\\Class_nn&SubClass_nn&Prot_nn\0"
  946. //
  947. WCHAR ClassStr1[sizeof(L"USB\\Class_")/sizeof(WCHAR)-1];
  948. WCHAR ClassHex1[2];
  949. WCHAR SubClassStr1[sizeof(L"&SubClass_")/sizeof(WCHAR)-1];
  950. WCHAR SubClassHex1[2];
  951. WCHAR Prot1[sizeof(L"&Prot_")/sizeof(WCHAR)-1];
  952. WCHAR ProtHex1[2];
  953. WCHAR Null1[1];
  954. // L"USB\\Class_nn&SubClass_nn\0"
  955. //
  956. WCHAR ClassStr2[sizeof(L"USB\\Class_")/sizeof(WCHAR)-1];
  957. WCHAR ClassHex2[2];
  958. WCHAR SubClassStr2[sizeof(L"&SubClass_")/sizeof(WCHAR)-1];
  959. WCHAR SubClassHex2[2];
  960. WCHAR Null2[1];
  961. // L"USB\\Class_nn&SubClass_nn\0"
  962. //
  963. WCHAR ClassStr3[sizeof(L"USB\\Class_")/sizeof(WCHAR)-1];
  964. WCHAR ClassHex3[2];
  965. WCHAR Null3[1];
  966. WCHAR DoubleNull[1];
  967. } CLASS_COMAPTIBLE_IDS, *PCLASS_COMAPTIBLE_IDS;
  968. static DEVCLASS_COMAPTIBLE_IDS DevClassCompatibleIDs =
  969. {
  970. // L"USB\\DevClass_nn&SubClass_nn&Prot_nn\0"
  971. //
  972. {'U','S','B','\\','D','e','v','C','l','a','s','s','_'},
  973. {'n','n'},
  974. {'&','S','u','b','C','l','a','s','s','_'},
  975. {'n','n'},
  976. {'&','P','r','o','t','_'},
  977. {'n','n'},
  978. {0},
  979. // L"USB\\DevClass_nn&SubClass_nn\0"
  980. //
  981. {'U','S','B','\\','D','e','v','C','l','a','s','s','_'},
  982. {'n','n'},
  983. {'&','S','u','b','C','l','a','s','s','_'},
  984. {'n','n'},
  985. {0},
  986. // L"USB\\DevClass_nn\0"
  987. //
  988. {'U','S','B','\\','D','e','v','C','l','a','s','s','_'},
  989. {'n','n'},
  990. {0},
  991. // L"USB\\COMPOSITE\0"
  992. //
  993. {'U','S','B','\\','C','O','M','P','O','S','I','T','E'},
  994. {0},
  995. {0}
  996. };
  997. static CLASS_COMAPTIBLE_IDS ClassCompatibleIDs =
  998. {
  999. // L"USB\\Class_nn&SubClass_nn&Prot_nn\0"
  1000. //
  1001. {'U','S','B','\\','C','l','a','s','s','_'},
  1002. {'n','n'},
  1003. {'&','S','u','b','C','l','a','s','s','_'},
  1004. {'n','n'},
  1005. {'&','P','r','o','t','_'},
  1006. {'n','n'},
  1007. {0},
  1008. // L"USB\\Class_nn&SubClass_nn\0"
  1009. //
  1010. {'U','S','B','\\','C','l','a','s','s','_'},
  1011. {'n','n'},
  1012. {'&','S','u','b','C','l','a','s','s','_'},
  1013. {'n','n'},
  1014. {0},
  1015. // L"USB\\Class_nn\0"
  1016. //
  1017. {'U','S','B','\\','C','l','a','s','s','_'},
  1018. {'n','n'},
  1019. {0},
  1020. {0}
  1021. };
  1022. PWCHAR
  1023. USBH_BuildCompatibleIDs(
  1024. IN PUCHAR CompatibleID,
  1025. IN PUCHAR SubCompatibleID,
  1026. IN UCHAR Class,
  1027. IN UCHAR SubClass,
  1028. IN UCHAR Protocol,
  1029. IN BOOLEAN DeviceClass,
  1030. IN BOOLEAN DeviceIsHighSpeed
  1031. )
  1032. {
  1033. ULONG ulTotal;
  1034. PWCHAR pwch;
  1035. WCHAR ClassHi = NibbleToHexW((Class) >> 4);
  1036. WCHAR ClassLo = NibbleToHexW((Class) & 0x0f);
  1037. WCHAR SubClassHi = NibbleToHexW((SubClass) >> 4);
  1038. WCHAR SubClassLo = NibbleToHexW((SubClass) & 0x0f);
  1039. WCHAR ProtocolHi = NibbleToHexW((Protocol) >> 4);
  1040. WCHAR ProtocolLo = NibbleToHexW((Protocol) & 0x0f);
  1041. BOOLEAN ControlerIsHS = FALSE;
  1042. PAGED_CODE();
  1043. #ifdef USBHUB20
  1044. ControlerIsHS = TRUE;
  1045. #endif
  1046. // if this is a high speed controller (USB2) then we must
  1047. // generate a different set of compat ids to be backward
  1048. // compatible with the goatpack
  1049. if (Class == USB_DEVICE_CLASS_HUB &&
  1050. ControlerIsHS) {
  1051. return USBH_BuildHubCompatibleIDs(
  1052. Class,
  1053. SubClass,
  1054. Protocol,
  1055. DeviceClass,
  1056. DeviceIsHighSpeed);
  1057. }
  1058. //#endif
  1059. if (DeviceClass)
  1060. {
  1061. ulTotal = sizeof(DEVCLASS_COMAPTIBLE_IDS);
  1062. }
  1063. else
  1064. {
  1065. ulTotal = sizeof(CLASS_COMAPTIBLE_IDS);
  1066. if (SubCompatibleID[0] != 0)
  1067. {
  1068. ulTotal += sizeof(L"USB\\MS_COMP_xxxxxxxx&MS_SUBCOMP_xxxxxxxx");
  1069. }
  1070. if (CompatibleID[0] != 0)
  1071. {
  1072. ulTotal += sizeof(L"USB\\MS_COMP_xxxxxxxx");
  1073. }
  1074. }
  1075. pwch = ExAllocatePoolWithTag(PagedPool, ulTotal, USBHUB_HEAP_TAG);
  1076. if (pwch)
  1077. {
  1078. if (DeviceClass)
  1079. {
  1080. PDEVCLASS_COMAPTIBLE_IDS pDevClassIds;
  1081. pDevClassIds = (PDEVCLASS_COMAPTIBLE_IDS)pwch;
  1082. // Copy over the constant set of strings:
  1083. // L"USB\\DevClass_nn&SubClass_nn&Prot_nn\0"
  1084. // L"USB\\DevClass_nn&SubClass_nn\0"
  1085. // L"USB\\DevClass_nn&SubClass_nn\0"
  1086. // L"USB\\COMPOSITE\0"
  1087. //
  1088. RtlCopyMemory(pDevClassIds,
  1089. &DevClassCompatibleIDs,
  1090. sizeof(DEVCLASS_COMAPTIBLE_IDS));
  1091. // Fill in the 'nn' blanks
  1092. //
  1093. pDevClassIds->ClassHex1[0] =
  1094. pDevClassIds->ClassHex2[0] =
  1095. pDevClassIds->ClassHex3[0] = ClassHi;
  1096. pDevClassIds->ClassHex1[1] =
  1097. pDevClassIds->ClassHex2[1] =
  1098. pDevClassIds->ClassHex3[1] = ClassLo;
  1099. pDevClassIds->SubClassHex1[0] =
  1100. pDevClassIds->SubClassHex2[0] = SubClassHi;
  1101. pDevClassIds->SubClassHex1[1] =
  1102. pDevClassIds->SubClassHex2[1] = SubClassLo;
  1103. pDevClassIds->ProtHex1[0] = ProtocolHi;
  1104. pDevClassIds->ProtHex1[1] = ProtocolLo;
  1105. }
  1106. else
  1107. {
  1108. PCLASS_COMAPTIBLE_IDS pClassIds;
  1109. PWCHAR pwchTmp;
  1110. ULONG i;
  1111. pwchTmp = pwch;
  1112. if (SubCompatibleID[0] != 0)
  1113. {
  1114. RtlCopyMemory(pwchTmp,
  1115. L"USB\\MS_COMP_",
  1116. sizeof(L"USB\\MS_COMP_")-sizeof(WCHAR));
  1117. (PUCHAR)pwchTmp += sizeof(L"USB\\MS_COMP_")-sizeof(WCHAR);
  1118. for (i = 0; i < 8 && CompatibleID[i] != 0; i++)
  1119. {
  1120. *pwchTmp++ = (WCHAR)CompatibleID[i];
  1121. }
  1122. RtlCopyMemory(pwchTmp,
  1123. L"&MS_SUBCOMP_",
  1124. sizeof(L"&MS_SUBCOMP_")-sizeof(WCHAR));
  1125. (PUCHAR)pwchTmp += sizeof(L"&MS_SUBCOMP_")-sizeof(WCHAR);
  1126. for (i = 0; i < 8 && SubCompatibleID[i] != 0; i++)
  1127. {
  1128. *pwchTmp++ = (WCHAR)SubCompatibleID[i];
  1129. }
  1130. *pwchTmp++ = '\0';
  1131. }
  1132. if (CompatibleID[0] != 0)
  1133. {
  1134. RtlCopyMemory(pwchTmp,
  1135. L"USB\\MS_COMP_",
  1136. sizeof(L"USB\\MS_COMP_")-sizeof(WCHAR));
  1137. (PUCHAR)pwchTmp += sizeof(L"USB\\MS_COMP_")-sizeof(WCHAR);
  1138. for (i = 0; i < 8 && CompatibleID[i] != 0; i++)
  1139. {
  1140. *pwchTmp++ = (WCHAR)CompatibleID[i];
  1141. }
  1142. *pwchTmp++ = '\0';
  1143. }
  1144. pClassIds = (PCLASS_COMAPTIBLE_IDS)pwchTmp;
  1145. // Copy over the constant set of strings:
  1146. // L"USB\\Class_nn&SubClass_nn&Prot_nn\0"
  1147. // L"USB\\Class_nn&SubClass_nn\0"
  1148. // L"USB\\Class_nn\0"
  1149. //
  1150. RtlCopyMemory(pClassIds,
  1151. &ClassCompatibleIDs,
  1152. sizeof(CLASS_COMAPTIBLE_IDS));
  1153. // Fill in the 'nn' blanks
  1154. //
  1155. pClassIds->ClassHex1[0] =
  1156. pClassIds->ClassHex2[0] =
  1157. pClassIds->ClassHex3[0] = ClassHi;
  1158. pClassIds->ClassHex1[1] =
  1159. pClassIds->ClassHex2[1] =
  1160. pClassIds->ClassHex3[1] = ClassLo;
  1161. pClassIds->SubClassHex1[0] =
  1162. pClassIds->SubClassHex2[0] = SubClassHi;
  1163. pClassIds->SubClassHex1[1] =
  1164. pClassIds->SubClassHex2[1] = SubClassLo;
  1165. pClassIds->ProtHex1[0] = ProtocolHi;
  1166. pClassIds->ProtHex1[1] = ProtocolLo;
  1167. }
  1168. }
  1169. return pwch;
  1170. }
  1171. #endif
  1172. PWCHAR
  1173. USB_MakeId(
  1174. PWCHAR IdString,
  1175. PWCHAR Buffer,
  1176. PULONG Length,
  1177. USHORT NullCount,
  1178. USHORT Digits,
  1179. USHORT HexId
  1180. )
  1181. /*
  1182. given a wide Id string like "FOOnnnn\0"
  1183. add the HexId value to nnnn as hex
  1184. this string is appended to the buffer passed in
  1185. eg
  1186. in : FOOnnnn\0 , 0x123A
  1187. out : FOO123A\0
  1188. */
  1189. {
  1190. #define NIBBLE_TO_HEX( byte ) ((WCHAR)Nibble[byte])
  1191. const UCHAR Nibble[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
  1192. 'B', 'C', 'D', 'E', 'F'};
  1193. PWCHAR tmp, id;
  1194. PUCHAR p;
  1195. SIZE_T siz, idLen;
  1196. idLen = wcslen(IdString)*sizeof(WCHAR);
  1197. siz = idLen+(USHORT)*Length+(NullCount*sizeof(WCHAR));
  1198. tmp = ExAllocatePoolWithTag(PagedPool, siz, USBHUB_HEAP_TAG);
  1199. if (tmp == NULL) {
  1200. *Length = 0;
  1201. } else {
  1202. // this takes care of the nulls
  1203. RtlZeroMemory(tmp, siz);
  1204. RtlCopyMemory(tmp, Buffer, *Length);
  1205. p = (PUCHAR) tmp;
  1206. p += *Length;
  1207. RtlCopyMemory(p, IdString, idLen);
  1208. id = (PWCHAR) p;
  1209. *Length = (ULONG)siz;
  1210. // now convert the vaules
  1211. while (*id != (WCHAR)'n' && Digits) {
  1212. id++;
  1213. }
  1214. switch(Digits) {
  1215. case 2:
  1216. *(id) = NIBBLE_TO_HEX((HexId >> 4) & 0x000f);
  1217. *(id+1) = NIBBLE_TO_HEX(HexId & 0x000f);
  1218. break;
  1219. case 4:
  1220. *(id) = NIBBLE_TO_HEX(HexId >> 12);
  1221. *(id+1) = NIBBLE_TO_HEX((HexId >> 8) & 0x000f);
  1222. *(id+2) = NIBBLE_TO_HEX((HexId >> 4) & 0x000f);
  1223. *(id+3) = NIBBLE_TO_HEX(HexId & 0x000f);
  1224. break;
  1225. }
  1226. }
  1227. if (Buffer != NULL) {
  1228. ExFreePool(Buffer);
  1229. }
  1230. return tmp;
  1231. }
  1232. PWCHAR
  1233. USBH_BuildHubDeviceID(
  1234. IN USHORT IdVendor,
  1235. IN USHORT IdProduct,
  1236. IN LONG MiId
  1237. )
  1238. /* ++
  1239. *
  1240. * Descrioption:
  1241. *
  1242. * This function build bus Id wide string for the PDO based on the Vendor Id
  1243. *
  1244. USB\HUB_Vid_nnnn&Pid_nnnn\0
  1245. *
  1246. *
  1247. * -- */
  1248. {
  1249. PWCHAR id;
  1250. ULONG length;
  1251. id = NULL;
  1252. length = 0;
  1253. id = USB_MakeId(
  1254. L"USB\\HUB_VID_nnnn\0",
  1255. id,
  1256. &length,
  1257. 0,
  1258. 4, // 4 digits
  1259. IdVendor);
  1260. id = USB_MakeId(
  1261. L"&PID_nnnn\0",
  1262. id,
  1263. &length,
  1264. 1, // add a null
  1265. 4, // 4 digits
  1266. IdProduct);
  1267. return(id);
  1268. }
  1269. PWCHAR
  1270. USBH_BuildHubHardwareIDs(
  1271. IN USHORT IdVendor,
  1272. IN USHORT IdProduct,
  1273. IN USHORT BcdDevice,
  1274. IN LONG MiId
  1275. )
  1276. /* ++
  1277. *
  1278. * Description:
  1279. *
  1280. * This function build HardwareIDs wide multi-string for the PDO based on the
  1281. * Vendor Id, Product Id and Revision Id.
  1282. *
  1283. USB\HUB_Vid_nnnn&Pid_nnnn&Rev_nnnn\0
  1284. USB\HUB_Vid_nnnn&Pid_nnnn\0
  1285. \0
  1286. * -- */
  1287. {
  1288. PWCHAR id;
  1289. ULONG length;
  1290. id = NULL;
  1291. length = 0;
  1292. // USB\HUB_VID_nnnn&PID_nnnn&REV_nnnn\0
  1293. id = USB_MakeId(
  1294. L"USB\\HUB_VID_nnnn\0",
  1295. id,
  1296. &length,
  1297. 0,
  1298. 4, // 4 digits
  1299. IdVendor);
  1300. id = USB_MakeId(
  1301. L"&PID_nnnn\0",
  1302. id,
  1303. &length,
  1304. 0,
  1305. 4,
  1306. IdProduct);
  1307. id = USB_MakeId(
  1308. L"&REV_nnnn\0",
  1309. id,
  1310. &length,
  1311. 1, // add a null
  1312. 4,
  1313. BcdDevice);
  1314. // USB\HUB_VID_nnnn&PID_nnnn\0
  1315. id = USB_MakeId(
  1316. L"USB\\HUB_VID_nnnn\0",
  1317. id,
  1318. &length,
  1319. 0,
  1320. 4, // 4 digits
  1321. IdVendor);
  1322. id = USB_MakeId(
  1323. L"&PID_nnnn\0",
  1324. id,
  1325. &length,
  1326. 2, // 2 nulls
  1327. 4,
  1328. IdProduct);
  1329. return(id);
  1330. }
  1331. PWCHAR
  1332. USBH_BuildHubCompatibleIDs(
  1333. IN UCHAR Class,
  1334. IN UCHAR SubClass,
  1335. IN UCHAR Protocol,
  1336. IN BOOLEAN DeviceClass,
  1337. IN BOOLEAN DeviceIsHighSpeed
  1338. )
  1339. /* ++
  1340. *
  1341. * Descrioption:
  1342. *
  1343. * This function build compatible Ids wide multi-string for the PDO based on
  1344. * the Class and Subclass Ids.
  1345. *
  1346. * This function builds the compatible ids specifically for s USB hub attached
  1347. * to a USB 2.0 host controller
  1348. // build the following set of ids
  1349. L"USB\\HubClass&SubClass_nn&Prot_nn\0"
  1350. L"USB\\HubClass&SubClass_nn\0"
  1351. L"USB\\HubClass\0"
  1352. L"\0"
  1353. * -- */
  1354. {
  1355. PWCHAR id;
  1356. ULONG length;
  1357. id = NULL;
  1358. length = 0;
  1359. // "USB\\HubClass&SubClass_nn&Prot_nn\0"
  1360. id = USB_MakeId(
  1361. L"USB\\HubClass&SubClass_nn\0",
  1362. id,
  1363. &length,
  1364. 0,
  1365. 2, // 2 digits
  1366. SubClass);
  1367. id = USB_MakeId(
  1368. L"&Prot_nn\0",
  1369. id,
  1370. &length,
  1371. 1, // add null
  1372. 2, // 2 digits
  1373. Protocol);
  1374. // "USB\\HubClass&SubClass_nn\0"
  1375. id = USB_MakeId(
  1376. L"USB\\HubClass&SubClass_nn\0",
  1377. id,
  1378. &length,
  1379. 1,
  1380. 2, // 2 digits
  1381. SubClass);
  1382. // "USB\\HubClass\0\0"
  1383. id = USB_MakeId(
  1384. L"USB\\HubClass\0",
  1385. id,
  1386. &length,
  1387. 2, // 2 nulls
  1388. 0,
  1389. 0);
  1390. return(id);
  1391. }
  1392. //#endif //USB2_BP
  1393. PWCHAR
  1394. USBH_BuildInstanceID(
  1395. IN PWCHAR UniqueIdString,
  1396. IN ULONG Length
  1397. )
  1398. /* ++
  1399. *
  1400. * Description:
  1401. *
  1402. * Arguments:
  1403. *
  1404. * Return:
  1405. *
  1406. * returns a pointer to a copy of our unicode unique id string
  1407. * or NULL if error.
  1408. *
  1409. *
  1410. * -- */
  1411. {
  1412. PWCHAR uniqueIdString;
  1413. PAGED_CODE();
  1414. USBH_KdPrint((2,"'BuildInstanceID %x\n",
  1415. UniqueIdString));
  1416. //
  1417. // Must use ExAllocatePool directly here because the OS
  1418. // will free the buffer
  1419. //
  1420. uniqueIdString = ExAllocatePoolWithTag(PagedPool,
  1421. Length,
  1422. USBHUB_HEAP_TAG);
  1423. if (NULL != uniqueIdString) {
  1424. RtlCopyMemory(uniqueIdString,
  1425. UniqueIdString,
  1426. Length);
  1427. }
  1428. return uniqueIdString;
  1429. }
  1430. NTSTATUS
  1431. USBH_ProcessDeviceInformation(
  1432. IN OUT PDEVICE_EXTENSION_PORT DeviceExtensionPort
  1433. )
  1434. /* ++
  1435. *
  1436. * Description:
  1437. *
  1438. * Arguments:
  1439. *
  1440. * Return:
  1441. *
  1442. * NTSTATUS
  1443. *
  1444. * -- */
  1445. {
  1446. NTSTATUS ntStatus;
  1447. PUSB_CONFIGURATION_DESCRIPTOR configurationDescriptor = NULL;
  1448. PUSB_INTERFACE_DESCRIPTOR interfaceDescriptor;
  1449. BOOLEAN multiConfig = FALSE;
  1450. PAGED_CODE();
  1451. USBH_KdPrint((2,"'enter USBH_ProcessDeviceInformation\n"));
  1452. USBH_ASSERT(EXTENSION_TYPE_PORT == DeviceExtensionPort->ExtensionType);
  1453. RtlZeroMemory(&DeviceExtensionPort->InterfaceDescriptor,
  1454. sizeof(DeviceExtensionPort->InterfaceDescriptor));
  1455. USBH_KdPrint((2,"'numConfigs = %d\n",
  1456. DeviceExtensionPort->DeviceDescriptor.bNumConfigurations));
  1457. USBH_KdPrint((2,"'vendor id = %x\n",
  1458. DeviceExtensionPort->DeviceDescriptor.idVendor));
  1459. USBH_KdPrint((2,"'product id = %x\n",
  1460. DeviceExtensionPort->DeviceDescriptor.idProduct));
  1461. USBH_KdPrint((2,"'revision id = %x\n",
  1462. DeviceExtensionPort->DeviceDescriptor.bcdDevice));
  1463. //
  1464. // assume the device is not a hub
  1465. //
  1466. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_DEVICE_IS_HUB;
  1467. if (DeviceExtensionPort->DeviceDescriptor.bNumConfigurations > 1) {
  1468. //
  1469. // Multi config device, ignore muktiple interfaces
  1470. // ie don't load the generic parent
  1471. //
  1472. // we get the wakeup caps from the first config
  1473. //
  1474. USBH_KdPrint((0,"Detected multiple configurations\n"));
  1475. multiConfig = TRUE;
  1476. }
  1477. //
  1478. // we need to get the whole configuration descriptor and parse it
  1479. //
  1480. ntStatus =
  1481. USBH_GetConfigurationDescriptor(DeviceExtensionPort->PortPhysicalDeviceObject,
  1482. &configurationDescriptor);
  1483. if (NT_SUCCESS(ntStatus)) {
  1484. // now parse out the config
  1485. USBH_ASSERT(configurationDescriptor);
  1486. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_REMOTE_WAKEUP_SUPPORTED;
  1487. if (configurationDescriptor->bmAttributes &
  1488. USB_CONFIG_REMOTE_WAKEUP) {
  1489. DeviceExtensionPort->PortPdoFlags |=
  1490. PORTPDO_REMOTE_WAKEUP_SUPPORTED;
  1491. }
  1492. #ifndef MULTI_FUNCTION_SUPPORT
  1493. //
  1494. // In Detroit we only support one interface
  1495. //
  1496. configurationDescriptor->bNumInterfaces = 1;
  1497. #endif
  1498. if ((configurationDescriptor->bNumInterfaces > 1) &&
  1499. !multiConfig &&
  1500. (DeviceExtensionPort->DeviceDescriptor.bDeviceClass == 0)) {
  1501. //
  1502. // device has multiple interfaces
  1503. // for now we use the first one we find
  1504. //
  1505. // set up the interface descriptor for this
  1506. // port to be the generic parent driver
  1507. DeviceExtensionPort->PortPdoFlags |= PORTPDO_DEVICE_IS_PARENT;
  1508. USBH_KdBreak(("USB device has Multiple Interfaces\n"));
  1509. } else {
  1510. //
  1511. // not a composite device
  1512. // call USBD to locate the interface descriptor
  1513. //
  1514. // there can be only one.
  1515. interfaceDescriptor =
  1516. USBD_ParseConfigurationDescriptorEx(
  1517. configurationDescriptor,
  1518. configurationDescriptor,
  1519. -1, //interface, don't care
  1520. -1, //alt setting, don't care
  1521. -1, // class don'care
  1522. -1, // subclass, don't care
  1523. -1); // protocol, don't care
  1524. if (interfaceDescriptor) {
  1525. DeviceExtensionPort->InterfaceDescriptor = *interfaceDescriptor;
  1526. //
  1527. // see if this is a hub
  1528. //
  1529. if (interfaceDescriptor->bInterfaceClass ==
  1530. USB_DEVICE_CLASS_HUB) {
  1531. DeviceExtensionPort->PortPdoFlags |= PORTPDO_DEVICE_IS_HUB;
  1532. // all hubs must support remote wakeup (ie at least propigate
  1533. // resume signalling
  1534. DeviceExtensionPort->PortPdoFlags |=
  1535. PORTPDO_REMOTE_WAKEUP_SUPPORTED;
  1536. }
  1537. } else {
  1538. ntStatus = STATUS_UNSUCCESSFUL;
  1539. }
  1540. }
  1541. }
  1542. if (configurationDescriptor) {
  1543. UsbhExFreePool(configurationDescriptor);
  1544. }
  1545. return ntStatus;
  1546. }
  1547. BOOLEAN
  1548. USBH_ValidateSerialNumberString(
  1549. PWCHAR DeviceId
  1550. )
  1551. /*++
  1552. Routine Description:
  1553. This routine stolen from ntos\io\pnpenum.c, IopFixupDeviceId, and modified
  1554. accordingly.
  1555. Invalid characters are:
  1556. c <= 0x20 (' ')
  1557. c > 0x7F
  1558. c == 0x2C (',')
  1559. Arguments:
  1560. DeviceId - specifies a device instance string (or part of one), must be
  1561. null-terminated.
  1562. Return Value:
  1563. None.
  1564. --*/
  1565. {
  1566. PWCHAR p;
  1567. PAGED_CODE();
  1568. for (p = DeviceId; *p; p++) {
  1569. if ((*p < L' ') || (*p > (WCHAR)0x7F) || (*p == L',')) {
  1570. return FALSE;
  1571. }
  1572. }
  1573. return TRUE;
  1574. }
  1575. BOOLEAN
  1576. USBH_CheckDeviceIDUnique(
  1577. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1578. IN USHORT IDVendor,
  1579. IN USHORT IDProduct,
  1580. IN PWCHAR SerialNumberBuffer,
  1581. IN USHORT SerialNumberBufferLength
  1582. )
  1583. /* ++
  1584. *
  1585. * Description:
  1586. *
  1587. * This function determines if the ID for a device on a hub is unique.
  1588. *
  1589. * Arguments:
  1590. *
  1591. * DeviceExtensionHub
  1592. *
  1593. * IDVendor
  1594. * IDProduct
  1595. * SerialNumberBuffer
  1596. * SerialNumberBufferLength
  1597. *
  1598. * Return:
  1599. *
  1600. * BOOLEAN indicating whether device ID is unique or not.
  1601. *
  1602. * -- */
  1603. {
  1604. PDEVICE_EXTENSION_PORT childDeviceExtensionPort;
  1605. BOOLEAN bDeviceIDUnique = TRUE;
  1606. ULONG i;
  1607. PAGED_CODE();
  1608. for (i = 0; i < DeviceExtensionHub->HubDescriptor->bNumberOfPorts; i++) {
  1609. if (DeviceExtensionHub->PortData[i].DeviceObject) {
  1610. childDeviceExtensionPort = DeviceExtensionHub->PortData[i].DeviceObject->DeviceExtension;
  1611. if (childDeviceExtensionPort->DeviceDescriptor.idVendor == IDVendor &&
  1612. childDeviceExtensionPort->DeviceDescriptor.idProduct == IDProduct &&
  1613. childDeviceExtensionPort->SerialNumberBufferLength == SerialNumberBufferLength &&
  1614. childDeviceExtensionPort->SerialNumberBuffer != NULL &&
  1615. RtlCompareMemory(childDeviceExtensionPort->SerialNumberBuffer,
  1616. SerialNumberBuffer,
  1617. SerialNumberBufferLength) == SerialNumberBufferLength) {
  1618. bDeviceIDUnique = FALSE;
  1619. break;
  1620. }
  1621. }
  1622. }
  1623. return bDeviceIDUnique;
  1624. }
  1625. NTSTATUS
  1626. USBH_CreateDevice(
  1627. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  1628. IN USHORT PortNumber,
  1629. IN USHORT PortStatus,
  1630. IN ULONG RetryIteration
  1631. )
  1632. /* ++
  1633. *
  1634. * Description:
  1635. *
  1636. * This is called when there is a new deviced connected, and enabled(via
  1637. * reset). We will call USBD_CreateDevice and USBD_InitializDevice so that
  1638. * it get an address and Device Descriptor. A PDO s also created for this
  1639. * connected device and to record some relevant information such as
  1640. * pDeviceData, puchPath and DeviceDescriptor.
  1641. *
  1642. * Arguments:
  1643. *
  1644. * pDeviceExtensionHub - the hub FDO extension that has a new connected port
  1645. * ulPortNumber - the port that has a device connected. IsLowSpeed - to
  1646. * indicate if the attached device is a low speed one
  1647. *
  1648. * Return:
  1649. *
  1650. * NtStatus
  1651. *
  1652. * -- */
  1653. {
  1654. NTSTATUS ntStatus, status;
  1655. PDEVICE_OBJECT deviceObjectPort = NULL; // Initialize to NULL in case
  1656. // USBD_MakePdoName fails.
  1657. PDEVICE_EXTENSION_PORT deviceExtensionPort = NULL;
  1658. BOOLEAN fNeedResetBeforeSetAddress = TRUE;
  1659. UNICODE_STRING uniqueIdUnicodeString;
  1660. ULONG nameIndex = 0;
  1661. UNICODE_STRING pdoNameUnicodeString;
  1662. BOOLEAN bDiagnosticMode = FALSE;
  1663. BOOLEAN bIgnoreHWSerialNumber = FALSE;
  1664. PWCHAR sernumbuf = NULL;
  1665. BOOLEAN isLowSpeed, isHighSpeed;
  1666. PVOID deviceData;
  1667. PAGED_CODE();
  1668. USBH_KdPrint((2,"'CreateDevice for port %x\n", PortNumber));
  1669. isLowSpeed = (PortStatus & PORT_STATUS_LOW_SPEED) ? TRUE : FALSE;
  1670. isHighSpeed = (PortStatus & PORT_STATUS_HIGH_SPEED) ? TRUE : FALSE;
  1671. //
  1672. // First create a PDO for the connected device
  1673. //
  1674. do {
  1675. #ifdef USB2
  1676. ntStatus = USBD_MakePdoNameEx(DeviceExtensionHub,
  1677. &pdoNameUnicodeString,
  1678. nameIndex);
  1679. #else
  1680. ntStatus = USBD_MakePdoName(&pdoNameUnicodeString,
  1681. nameIndex);
  1682. #endif
  1683. if (NT_SUCCESS(ntStatus)) {
  1684. ntStatus = IoCreateDevice(UsbhDriverObject, // Driver Object
  1685. sizeof(DEVICE_EXTENSION_PORT), // Device Extension size
  1686. //NULL, // Device name
  1687. &pdoNameUnicodeString,
  1688. FILE_DEVICE_UNKNOWN, // Device Type
  1689. // should look device
  1690. // class
  1691. 0,// Device Chars
  1692. FALSE, // Exclusive
  1693. &deviceObjectPort); // Bus Device Object
  1694. if (!NT_SUCCESS(ntStatus)) {
  1695. RtlFreeUnicodeString(&pdoNameUnicodeString);
  1696. }
  1697. }
  1698. nameIndex++;
  1699. } while (ntStatus == STATUS_OBJECT_NAME_COLLISION);
  1700. if (!NT_SUCCESS(ntStatus)) {
  1701. USBH_KdPrint((2,"'IoCreateDevice for port %x fail\n", PortNumber));
  1702. USBH_ASSERT(deviceObjectPort == NULL);
  1703. goto USBH_CreateDevice_Done;
  1704. }
  1705. // use the stack size from the top of the HCD stack
  1706. deviceObjectPort->StackSize = DeviceExtensionHub->TopOfHcdStackDeviceObject->StackSize;
  1707. USBH_KdPrint((2,"'CreatePdo StackSize=%d\n", deviceObjectPort->StackSize));
  1708. //
  1709. // Init port extension fields
  1710. //
  1711. deviceExtensionPort = (PDEVICE_EXTENSION_PORT) deviceObjectPort->DeviceExtension;
  1712. RtlZeroMemory(deviceExtensionPort, sizeof(DEVICE_EXTENSION_PORT));
  1713. //
  1714. // Init port extension fields
  1715. //
  1716. // don't need the name anymore
  1717. RtlFreeUnicodeString(&pdoNameUnicodeString);
  1718. deviceExtensionPort->ExtensionType = EXTENSION_TYPE_PORT;
  1719. deviceExtensionPort->PortPhysicalDeviceObject = deviceObjectPort;
  1720. deviceExtensionPort->HubExtSave =
  1721. deviceExtensionPort->DeviceExtensionHub = DeviceExtensionHub;
  1722. deviceExtensionPort->PortNumber = PortNumber;
  1723. deviceExtensionPort->DeviceState = PowerDeviceD0;
  1724. if (isLowSpeed) {
  1725. deviceExtensionPort->PortPdoFlags = PORTPDO_LOW_SPEED_DEVICE;
  1726. USBH_ASSERT(isHighSpeed == FALSE);
  1727. } else if (isHighSpeed) {
  1728. deviceExtensionPort->PortPdoFlags = PORTPDO_HIGH_SPEED_DEVICE;
  1729. USBH_ASSERT(isLowSpeed == FALSE);
  1730. }
  1731. KeInitializeSpinLock(&deviceExtensionPort->PortSpinLock);
  1732. //
  1733. // Build a unicode unique id
  1734. //
  1735. USBH_ASSERT(PortNumber < 1000 && PortNumber > 0);
  1736. RtlInitUnicodeString(&uniqueIdUnicodeString,
  1737. &deviceExtensionPort->UniqueIdString[0]);
  1738. uniqueIdUnicodeString.MaximumLength =
  1739. sizeof(deviceExtensionPort->UniqueIdString);
  1740. ntStatus = RtlIntegerToUnicodeString((ULONG) PortNumber,
  1741. 10,
  1742. &uniqueIdUnicodeString);
  1743. deviceObjectPort->Flags |= DO_POWER_PAGABLE;
  1744. deviceObjectPort->Flags &= ~DO_DEVICE_INITIALIZING;
  1745. if (!NT_SUCCESS(ntStatus)) {
  1746. USBH_KdBreak(("AddDevice for port %x fail %x -- failed to create unique id\n", PortNumber, ntStatus));
  1747. goto USBH_CreateDevice_Done;
  1748. }
  1749. //
  1750. // call usbd to create device for this connection
  1751. //
  1752. #ifdef USB2
  1753. ntStatus = USBD_CreateDeviceEx(DeviceExtensionHub,
  1754. &deviceExtensionPort->DeviceData,
  1755. deviceObjectPort,
  1756. DeviceExtensionHub->RootHubPdo,
  1757. 0, // optional default endpoint0 max packet
  1758. // size
  1759. &deviceExtensionPort->DeviceHackFlags,
  1760. PortStatus,
  1761. PortNumber);
  1762. #else
  1763. ntStatus = USBD_CreateDevice(&deviceExtensionPort->DeviceData,
  1764. DeviceExtensionHub->RootHubPdo,
  1765. isLowSpeed,
  1766. 0, // optional default endpoint0 max packet
  1767. // size
  1768. &deviceExtensionPort->DeviceHackFlags);
  1769. // flag to indicate if
  1770. // we need a second
  1771. // reset
  1772. #endif
  1773. if (!NT_SUCCESS(ntStatus)) {
  1774. ENUMLOG(&DeviceExtensionHub->UsbdiBusIf,
  1775. USBDTAG_HUB, 'cdf!', ntStatus, 0);
  1776. USBH_KdBreak(("AddDevice for port %x fail %x\n", PortNumber, ntStatus));
  1777. goto USBH_CreateDevice_Done;
  1778. }
  1779. //
  1780. // some early versions of USB firmware could not handle the premature
  1781. // termination of a control command.
  1782. //
  1783. if (fNeedResetBeforeSetAddress) {
  1784. USBH_KdPrint((2,"'NeedResetBeforeSetAddress\n"));
  1785. ntStatus = USBH_SyncResetPort(DeviceExtensionHub, PortNumber);
  1786. if (!NT_SUCCESS(ntStatus)) {
  1787. USBH_KdBreak(("Failure on second reset %x fail %x\n", PortNumber, ntStatus));
  1788. goto USBH_CreateDevice_Done;
  1789. }
  1790. // For some reason, the amount of time between the GetDescriptor request
  1791. // and the SetAddress request decreased when we switched from the older
  1792. // monolithic UHCD.SYS to the new USBUHCI.SYS miniport. And apparently,
  1793. // there have been found at least two devices that were dependent on
  1794. // the longer delay. According to GlenS who looked at one of these
  1795. // devices on the CATC, delta time was ~80ms with UHCD.SYS and ~35ms
  1796. // with USBUHCI.SYS. So, Glen found that by inserting a 50ms delay
  1797. // here, it allows at least one of these devices to now enumerate
  1798. // properly. For performance reasons, we have decided to only insert
  1799. // this delay if a previous enumeration retry has failed, so as not
  1800. // to impact the enumeration time of all devices.
  1801. if (RetryIteration) {
  1802. UsbhWait(50);
  1803. }
  1804. }
  1805. #ifdef USB2
  1806. ntStatus = USBD_InitializeDeviceEx(DeviceExtensionHub,
  1807. deviceExtensionPort->DeviceData,
  1808. DeviceExtensionHub->RootHubPdo,
  1809. &deviceExtensionPort->DeviceDescriptor,
  1810. sizeof(USB_DEVICE_DESCRIPTOR),
  1811. &deviceExtensionPort->ConfigDescriptor,
  1812. sizeof(USB_CONFIGURATION_DESCRIPTOR)
  1813. );
  1814. #else
  1815. ntStatus = USBD_InitializeDevice(deviceExtensionPort->DeviceData,
  1816. DeviceExtensionHub->RootHubPdo,
  1817. &deviceExtensionPort->DeviceDescriptor,
  1818. sizeof(USB_DEVICE_DESCRIPTOR),
  1819. &deviceExtensionPort->ConfigDescriptor,
  1820. sizeof(USB_CONFIGURATION_DESCRIPTOR)
  1821. );
  1822. #endif
  1823. if (!NT_SUCCESS(ntStatus)) {
  1824. USBH_KdPrint((2,"'InitDevice for port %x fail %x\n", PortNumber, ntStatus));
  1825. // InitializeDevice frees the DeviceData structure on failure
  1826. deviceExtensionPort->DeviceData = NULL;
  1827. goto USBH_CreateDevice_Done;
  1828. }
  1829. // See if we are supposed to ignore the hardware serial number for
  1830. // this device.
  1831. status = USBH_RegQueryDeviceIgnoreHWSerNumFlag(
  1832. deviceExtensionPort->DeviceDescriptor.idVendor,
  1833. deviceExtensionPort->DeviceDescriptor.idProduct,
  1834. &bIgnoreHWSerialNumber);
  1835. if (status == STATUS_OBJECT_NAME_NOT_FOUND) {
  1836. // Flag was not there, don't ignore hardware serial number.
  1837. bIgnoreHWSerialNumber = FALSE;
  1838. }
  1839. if (bIgnoreHWSerialNumber) {
  1840. USBH_KdPrint((1,"'Ignoring HW serial number for device Vid_%04x/Pid_%04x\n",
  1841. deviceExtensionPort->DeviceDescriptor.idVendor,
  1842. deviceExtensionPort->DeviceDescriptor.idProduct));
  1843. // Use the same flag that USBD gives us. According to JD, though,
  1844. // USBD uses this flag globally (e.g. set for all devices).
  1845. deviceExtensionPort->DeviceHackFlags |= USBD_DEVHACK_DISABLE_SN;
  1846. }
  1847. // if we can get the core spec changed to stipulate that this serial number
  1848. // to the device then we can use it instead of the port number.
  1849. //
  1850. // see if we have a serial number
  1851. //
  1852. if (deviceExtensionPort->DeviceDescriptor.iSerialNumber &&
  1853. !(deviceExtensionPort->DeviceHackFlags & USBD_DEVHACK_DISABLE_SN)) {
  1854. #if DBG
  1855. NTSTATUS localStatus;
  1856. #endif
  1857. //
  1858. // Wow, we have a device with a serial number
  1859. // we will attempt to get the string and use it for a
  1860. // unique id
  1861. //
  1862. USBH_KdPrint((1, "'Device is reporting a serial number string\n"));
  1863. //
  1864. // lets get that serial number
  1865. //
  1866. InterlockedExchangePointer(&deviceExtensionPort->SerialNumberBuffer,
  1867. NULL);
  1868. #if DBG
  1869. localStatus =
  1870. #endif
  1871. // For now we always look for the serial number in English.
  1872. USBH_GetSerialNumberString(deviceExtensionPort->PortPhysicalDeviceObject,
  1873. &sernumbuf,
  1874. &deviceExtensionPort->SerialNumberBufferLength,
  1875. 0x0409, // good'ol american english
  1876. deviceExtensionPort->DeviceDescriptor.iSerialNumber);
  1877. if (sernumbuf == NULL) {
  1878. USBH_ASSERT(localStatus != STATUS_SUCCESS);
  1879. UsbhWarning(deviceExtensionPort,
  1880. "Device reported a serial number string but failed the request for it\n",
  1881. FALSE);
  1882. } else if (!USBH_ValidateSerialNumberString(sernumbuf)) {
  1883. // Sigh. The "Visioneer Strobe Pro USB" returns a bogus serial #
  1884. // string so we need to check for that here. If we return this
  1885. // bogus string to PnP we blue screen.
  1886. UsbhWarning(deviceExtensionPort,
  1887. "Device reported an invalid serial number string!\n",
  1888. FALSE);
  1889. UsbhExFreePool(sernumbuf);
  1890. sernumbuf = NULL;
  1891. }
  1892. // Check for like devices with duplicate serial numbers connected
  1893. // to the same hub.
  1894. if (sernumbuf &&
  1895. !USBH_CheckDeviceIDUnique(
  1896. DeviceExtensionHub,
  1897. deviceExtensionPort->DeviceDescriptor.idVendor,
  1898. deviceExtensionPort->DeviceDescriptor.idProduct,
  1899. sernumbuf,
  1900. deviceExtensionPort->SerialNumberBufferLength)) {
  1901. UsbhWarning(deviceExtensionPort,
  1902. "Like devices with identical serial numbers connected to same hub!\n",
  1903. TRUE);
  1904. UsbhExFreePool(sernumbuf);
  1905. sernumbuf = NULL;
  1906. }
  1907. InterlockedExchangePointer(&deviceExtensionPort->SerialNumberBuffer,
  1908. sernumbuf);
  1909. }
  1910. //
  1911. // Skip serial number generation if we are in diagnostic mode.
  1912. // (e.g. The Vid and Pid are each 0xFFFF.)
  1913. //
  1914. bDiagnosticMode =
  1915. (deviceExtensionPort->DeviceDescriptor.idVendor == 0xFFFF &&
  1916. deviceExtensionPort->DeviceDescriptor.idProduct == 0xFFFF) ? TRUE : FALSE;
  1917. // **
  1918. //
  1919. // Query the device
  1920. // 1. check for multiple interfaces (ie composite device)
  1921. // 2. check for multiple configs (ie need configuring parent)
  1922. // 3. check single interface device -- ie just load driver
  1923. //
  1924. if (NT_SUCCESS(ntStatus)) {
  1925. ntStatus = USBH_ProcessDeviceInformation(deviceExtensionPort);
  1926. // compute our capabilities we will retiurn to PnP
  1927. USBH_PdoSetCapabilities(deviceExtensionPort);
  1928. }
  1929. //#ifdef MAX_DEBUG
  1930. // ntStatus = STATUS_DEVICE_DATA_ERROR;
  1931. //#endif
  1932. //
  1933. // Note: Device will be removed when REMOVE MESSAGE is sent to the PDO
  1934. //
  1935. //ntStatus = STATUS_DEVICE_DATA_ERROR;
  1936. #if DBG
  1937. if (!NT_SUCCESS(ntStatus)) {
  1938. // error occurred querying the device config descriptor
  1939. USBH_KdBreak(("Get Config Descriptors Failed %x\n", ntStatus));
  1940. }
  1941. #endif
  1942. USBH_CreateDevice_Done:
  1943. #if DBG
  1944. if (UsbhPnpTest & PNP_TEST_FAIL_ENUM) {
  1945. ntStatus = STATUS_UNSUCCESSFUL;
  1946. }
  1947. #endif
  1948. #ifdef TEST_2X_UI
  1949. if (deviceExtensionPort->DeviceDescriptor.idVendor == 0x045E) {
  1950. // Set the 2.x device flag for MS devices when testing the UI.
  1951. deviceExtensionPort->PortPdoFlags |= PORTPDO_HIGH_SPEED_DEVICE;
  1952. }
  1953. #endif
  1954. if (!NT_SUCCESS(ntStatus) && deviceExtensionPort) {
  1955. #ifdef MAX_DEBUG
  1956. TEST_TRAP();
  1957. #endif
  1958. deviceExtensionPort->PortPdoFlags |= PORTPDO_DEVICE_ENUM_ERROR;
  1959. // remove the deviceData structure now
  1960. deviceData = InterlockedExchangePointer(
  1961. &deviceExtensionPort->DeviceData,
  1962. NULL);
  1963. if (deviceData) {
  1964. #ifdef USB2
  1965. USBD_RemoveDeviceEx(DeviceExtensionHub,
  1966. deviceData,
  1967. DeviceExtensionHub->RootHubPdo,
  1968. 0);
  1969. #else
  1970. USBD_RemoveDevice(deviceData,
  1971. DeviceExtensionHub->RootHubPdo,
  1972. 0);
  1973. #endif
  1974. }
  1975. sernumbuf = InterlockedExchangePointer(
  1976. &deviceExtensionPort->SerialNumberBuffer, NULL);
  1977. if (sernumbuf) {
  1978. UsbhExFreePool(sernumbuf);
  1979. }
  1980. }
  1981. //
  1982. // Note that we keep the PDO until the
  1983. // device is physically disconnected
  1984. // from the bus.
  1985. //
  1986. // According to NT pnp spec this pdo should remain
  1987. USBH_ASSERT(DeviceExtensionHub->PortData[PortNumber - 1].DeviceObject == NULL);
  1988. DeviceExtensionHub->PortData[PortNumber - 1].DeviceObject = deviceObjectPort;
  1989. USBH_KdPrint((2,"'Exit CreateDevice PDO=%x\n", deviceObjectPort));
  1990. return ntStatus;
  1991. }
  1992. PWCHAR
  1993. GetString(PWCHAR pwc, BOOLEAN MultiSZ)
  1994. {
  1995. PWCHAR psz, p;
  1996. ULONG Size;
  1997. psz=pwc;
  1998. while (*psz!='\0' || (MultiSZ && *(psz+1)!='\0')) {
  1999. psz++;
  2000. }
  2001. Size=(ULONG)((psz-pwc+1+(MultiSZ ? 1: 0))*sizeof(*pwc));
  2002. // We use pool here because these pointers are passed
  2003. // to the PnP code who is responsible for freeing them
  2004. if ((p=ExAllocatePoolWithTag(PagedPool, Size, USBHUB_HEAP_TAG))!=NULL) {
  2005. RtlCopyMemory(p, pwc, Size);
  2006. }
  2007. return(p);
  2008. }
  2009. NTSTATUS
  2010. USBH_PdoQueryId(
  2011. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  2012. IN PIRP Irp
  2013. )
  2014. /* ++
  2015. *
  2016. * Description:
  2017. *
  2018. * This function responds to IRP_MJ_PNP, IRP_MN_QUERY_ID.
  2019. *
  2020. * Arguments:
  2021. *
  2022. * DeviceExtensionPort - should be the PDO we created for the port device Irp
  2023. * - the Irp
  2024. *
  2025. * Return:
  2026. *
  2027. * NtStatus
  2028. *
  2029. * -- */
  2030. {
  2031. PIO_STACK_LOCATION ioStack;
  2032. NTSTATUS ntStatus = STATUS_SUCCESS;
  2033. PAGED_CODE();
  2034. ioStack = IoGetCurrentIrpStackLocation(Irp);
  2035. USBH_KdPrint((2,"'IRP_MN_QUERY_ID Pdo extension=%x\n", DeviceExtensionPort));
  2036. //
  2037. // It should be physical device object.
  2038. //
  2039. USBH_ASSERT(EXTENSION_TYPE_PORT == DeviceExtensionPort->ExtensionType);
  2040. #ifndef USBHUB20
  2041. // Do the MS OS Descriptor stuff the first time around
  2042. //
  2043. if (!(DeviceExtensionPort->PortPdoFlags & PORTPDO_OS_STRING_DESC_REQUESTED))
  2044. {
  2045. PMS_EXT_CONFIG_DESC msExtConfigDesc;
  2046. msExtConfigDesc = NULL;
  2047. // Try to get the MS OS Descriptor Vendor Code from the device. Do
  2048. // this before any MS OS Descriptor requests.
  2049. //
  2050. USBH_GetMsOsVendorCode(DeviceExtensionPort->PortPhysicalDeviceObject);
  2051. // Don't do the MS OS Descriptor stuff the next time around
  2052. //
  2053. DeviceExtensionPort->PortPdoFlags |= PORTPDO_OS_STRING_DESC_REQUESTED;
  2054. // Try to get an Extended Configuration Descriptor from the device.
  2055. //
  2056. msExtConfigDesc = USBH_GetExtConfigDesc(DeviceExtensionPort->PortPhysicalDeviceObject);
  2057. // If we got an Extended Configuration Descriptor from the device, make
  2058. // sure it is valid.
  2059. //
  2060. if (msExtConfigDesc &&
  2061. USBH_ValidateExtConfigDesc(msExtConfigDesc,
  2062. &DeviceExtensionPort->ConfigDescriptor)) {
  2063. // If the Extended Configuration Descriptor contains a single
  2064. // function which spans the all of the interfaces of the device,
  2065. // then do not treat the device as a composite device and use the
  2066. // Compatible and SubCompatible IDs optionally contained in the
  2067. // descriptor.
  2068. //
  2069. if (msExtConfigDesc->Header.bCount == 1 &&
  2070. msExtConfigDesc->Function[0].bFirstInterfaceNumber == 0 &&
  2071. msExtConfigDesc->Function[0].bInterfaceCount ==
  2072. DeviceExtensionPort->ConfigDescriptor.bNumInterfaces)
  2073. {
  2074. RtlCopyMemory(DeviceExtensionPort->CompatibleID,
  2075. msExtConfigDesc->Function[0].CompatibleID,
  2076. sizeof(DeviceExtensionPort->CompatibleID));
  2077. RtlCopyMemory(DeviceExtensionPort->SubCompatibleID,
  2078. msExtConfigDesc->Function[0].SubCompatibleID,
  2079. sizeof(DeviceExtensionPort->SubCompatibleID));
  2080. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_DEVICE_IS_PARENT;
  2081. }
  2082. }
  2083. if (msExtConfigDesc)
  2084. {
  2085. UsbhExFreePool(msExtConfigDesc);
  2086. }
  2087. }
  2088. #endif
  2089. switch (ioStack->Parameters.QueryId.IdType) {
  2090. case BusQueryDeviceID:
  2091. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_ENUM_ERROR) {
  2092. Irp->IoStatus.Information=
  2093. (ULONG_PTR)
  2094. USBH_BuildDeviceID(0,
  2095. 0,
  2096. -1,
  2097. FALSE);
  2098. } else {
  2099. Irp->IoStatus.Information =
  2100. (ULONG_PTR)
  2101. USBH_BuildDeviceID(DeviceExtensionPort->DeviceDescriptor.idVendor,
  2102. DeviceExtensionPort->DeviceDescriptor.idProduct,
  2103. -1,
  2104. DeviceExtensionPort->DeviceDescriptor.bDeviceClass
  2105. == USB_DEVICE_CLASS_HUB ? TRUE : FALSE);
  2106. }
  2107. break;
  2108. case BusQueryHardwareIDs:
  2109. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_ENUM_ERROR) {
  2110. Irp->IoStatus.Information=(ULONG_PTR)GetString(L"USB\\UNKNOWN\0", TRUE);
  2111. } else {
  2112. Irp->IoStatus.Information =
  2113. (ULONG_PTR)
  2114. USBH_BuildHardwareIDs(DeviceExtensionPort->DeviceDescriptor.idVendor,
  2115. DeviceExtensionPort->DeviceDescriptor.idProduct,
  2116. DeviceExtensionPort->DeviceDescriptor.bcdDevice,
  2117. -1,
  2118. DeviceExtensionPort->DeviceDescriptor.bDeviceClass
  2119. == USB_DEVICE_CLASS_HUB ? TRUE : FALSE);
  2120. }
  2121. break;
  2122. case BusQueryCompatibleIDs:
  2123. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_ENUM_ERROR) {
  2124. Irp->IoStatus.Information=(ULONG_PTR)GetString(L"USB\\UNKNOWN\0", TRUE);
  2125. } else if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_IS_PARENT) {
  2126. //Irp->IoStatus.Information=(ULONG)GetString(L"USB\\COMPOSITE\0", TRUE);
  2127. Irp->IoStatus.Information =
  2128. (ULONG_PTR) USBH_BuildCompatibleIDs(
  2129. DeviceExtensionPort->CompatibleID,
  2130. DeviceExtensionPort->SubCompatibleID,
  2131. DeviceExtensionPort->InterfaceDescriptor.bInterfaceClass,
  2132. DeviceExtensionPort->InterfaceDescriptor.bInterfaceSubClass,
  2133. DeviceExtensionPort->InterfaceDescriptor.bInterfaceProtocol,
  2134. TRUE,
  2135. DeviceExtensionPort->PortPdoFlags & PORTPDO_HIGH_SPEED_DEVICE ?
  2136. TRUE : FALSE);
  2137. } else {
  2138. Irp->IoStatus.Information =
  2139. (ULONG_PTR) USBH_BuildCompatibleIDs(
  2140. DeviceExtensionPort->CompatibleID,
  2141. DeviceExtensionPort->SubCompatibleID,
  2142. DeviceExtensionPort->InterfaceDescriptor.bInterfaceClass,
  2143. DeviceExtensionPort->InterfaceDescriptor.bInterfaceSubClass,
  2144. DeviceExtensionPort->InterfaceDescriptor.bInterfaceProtocol,
  2145. FALSE,
  2146. DeviceExtensionPort->PortPdoFlags & PORTPDO_HIGH_SPEED_DEVICE ?
  2147. TRUE : FALSE);
  2148. }
  2149. break;
  2150. case BusQueryInstanceID:
  2151. if (DeviceExtensionPort->SerialNumberBuffer) {
  2152. PWCHAR tmp;
  2153. ULONG length;
  2154. //
  2155. // allocate a buffer and copy the string to it
  2156. //
  2157. // NOTE: must use stock alloc function because
  2158. // PnP frees this string.
  2159. length = DeviceExtensionPort->SerialNumberBufferLength;
  2160. tmp = ExAllocatePoolWithTag(PagedPool, length, USBHUB_HEAP_TAG);
  2161. if (tmp) {
  2162. RtlCopyMemory(tmp,
  2163. DeviceExtensionPort->SerialNumberBuffer,
  2164. length);
  2165. }
  2166. Irp->IoStatus.Information = (ULONG_PTR) tmp;
  2167. #if DBG
  2168. {
  2169. PUCHAR pch, sn;
  2170. PWCHAR pwch;
  2171. pch = sn = ExAllocatePoolWithTag(PagedPool, 500, USBHUB_HEAP_TAG);
  2172. if (sn) {
  2173. pwch = (PWCHAR) tmp;
  2174. while(*pwch) {
  2175. *pch = (UCHAR) *pwch;
  2176. pch++;
  2177. pwch++;
  2178. if (pch-sn > 499) {
  2179. break;
  2180. }
  2181. }
  2182. *pch='\0';
  2183. USBH_KdPrint((1, "'using device supplied serial number\n"));
  2184. USBH_KdPrint((1, "'SN = :%s:\n", sn));
  2185. ExFreePool(sn);
  2186. }
  2187. }
  2188. #endif
  2189. } else {
  2190. Irp->IoStatus.Information =
  2191. (ULONG_PTR) USBH_BuildInstanceID(&DeviceExtensionPort->UniqueIdString[0],
  2192. sizeof(DeviceExtensionPort->UniqueIdString));
  2193. }
  2194. break;
  2195. default:
  2196. USBH_KdBreak(("PdoBusExtension Unknown BusQueryId\n"));
  2197. // IrpAssert: Must not change Irp->IoStatus.Status for bogus IdTypes,
  2198. // so return original status here.
  2199. return Irp->IoStatus.Status;
  2200. }
  2201. if (Irp->IoStatus.Information == 0) {
  2202. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  2203. }
  2204. return ntStatus;
  2205. }
  2206. NTSTATUS
  2207. USBH_PdoStopDevice(
  2208. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  2209. IN PIRP Irp
  2210. )
  2211. /* ++
  2212. *
  2213. * Description:
  2214. *
  2215. * Argument:
  2216. *
  2217. * Return:
  2218. *
  2219. * STATUS_SUCCESS
  2220. *
  2221. *
  2222. * -- */
  2223. {
  2224. NTSTATUS ntStatus = STATUS_SUCCESS;
  2225. KIRQL irql;
  2226. PIRP idleIrp = NULL;
  2227. PIRP waitWakeIrp = NULL;
  2228. PVOID deviceData;
  2229. USBH_KdPrint((1,
  2230. "'Stopping PDO %x\n",
  2231. DeviceExtensionPort->PortPhysicalDeviceObject));
  2232. LOGENTRY(LOG_PNP, "Spdo", DeviceExtensionPort,
  2233. DeviceExtensionPort->PortPhysicalDeviceObject,
  2234. DeviceExtensionPort->PortPdoFlags);
  2235. IoAcquireCancelSpinLock(&irql);
  2236. if (DeviceExtensionPort->IdleNotificationIrp) {
  2237. idleIrp = DeviceExtensionPort->IdleNotificationIrp;
  2238. DeviceExtensionPort->IdleNotificationIrp = NULL;
  2239. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_IDLE_NOTIFIED;
  2240. if (idleIrp->Cancel) {
  2241. idleIrp = NULL;
  2242. }
  2243. if (idleIrp) {
  2244. IoSetCancelRoutine(idleIrp, NULL);
  2245. }
  2246. LOGENTRY(LOG_PNP, "IdSX", 0, DeviceExtensionPort, idleIrp);
  2247. USBH_KdPrint((1,"'PDO %x stopping, failing idle notification request IRP %x\n",
  2248. DeviceExtensionPort->PortPhysicalDeviceObject, idleIrp));
  2249. }
  2250. if (DeviceExtensionPort->WaitWakeIrp) {
  2251. waitWakeIrp = DeviceExtensionPort->WaitWakeIrp;
  2252. DeviceExtensionPort->WaitWakeIrp = NULL;
  2253. DeviceExtensionPort->PortPdoFlags &=
  2254. ~PORTPDO_REMOTE_WAKEUP_ENABLED;
  2255. if (waitWakeIrp->Cancel || IoSetCancelRoutine(waitWakeIrp, NULL) == NULL) {
  2256. waitWakeIrp = NULL;
  2257. // Must decrement pending request count here because
  2258. // we don't complete the IRP below and USBH_WaitWakeCancel
  2259. // won't either because we have cleared the IRP pointer
  2260. // in the device extension above.
  2261. USBH_DEC_PENDING_IO_COUNT(DeviceExtensionPort->DeviceExtensionHub);
  2262. }
  2263. USBH_KdPrint((1,
  2264. "'Completing Wake Irp for PDO %x with STATUS_CANCELLED\n",
  2265. DeviceExtensionPort->PortPhysicalDeviceObject));
  2266. LOGENTRY(LOG_PNP, "kilW", DeviceExtensionPort,
  2267. DeviceExtensionPort->PortPhysicalDeviceObject,
  2268. DeviceExtensionPort->PortPdoFlags);
  2269. // JOES: Should we decrement portwakeirps for the hub and cancel
  2270. // hub's WW IRP if zero?
  2271. }
  2272. //
  2273. // Finally, release the cancel spin lock
  2274. //
  2275. IoReleaseCancelSpinLock(irql);
  2276. if (idleIrp) {
  2277. idleIrp->IoStatus.Status = STATUS_CANCELLED;
  2278. IoCompleteRequest(idleIrp, IO_NO_INCREMENT);
  2279. }
  2280. if (waitWakeIrp) {
  2281. USBH_ASSERT(DeviceExtensionPort->DeviceExtensionHub);
  2282. USBH_CompletePowerIrp(DeviceExtensionPort->DeviceExtensionHub,
  2283. waitWakeIrp,
  2284. STATUS_CANCELLED);
  2285. }
  2286. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_STARTED;
  2287. //
  2288. // indicate that we will need a reset if we start up again.
  2289. //
  2290. DeviceExtensionPort->PortPdoFlags |= PORTPDO_NEED_RESET;
  2291. RtlCopyMemory(&DeviceExtensionPort->OldDeviceDescriptor,
  2292. &DeviceExtensionPort->DeviceDescriptor,
  2293. sizeof(DeviceExtensionPort->DeviceDescriptor));
  2294. //
  2295. // remove the device data now to free
  2296. // up the bus resources
  2297. //
  2298. deviceData = InterlockedExchangePointer(
  2299. &DeviceExtensionPort->DeviceData,
  2300. NULL);
  2301. if (deviceData) {
  2302. #ifdef USB2
  2303. ntStatus = USBD_RemoveDeviceEx(DeviceExtensionPort->DeviceExtensionHub,
  2304. deviceData,
  2305. DeviceExtensionPort->DeviceExtensionHub->RootHubPdo,
  2306. 0);
  2307. #else
  2308. ntStatus = USBD_RemoveDevice(deviceData,
  2309. DeviceExtensionPort->DeviceExtensionHub->RootHubPdo,
  2310. 0);
  2311. #endif
  2312. USBH_SyncDisablePort(DeviceExtensionPort->DeviceExtensionHub,
  2313. DeviceExtensionPort->PortNumber);
  2314. }
  2315. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_SYM_LINK) {
  2316. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_SYM_LINK;
  2317. ntStatus = USBH_SymbolicLink(FALSE,
  2318. DeviceExtensionPort,
  2319. NULL);
  2320. #if DBG
  2321. if (!NT_SUCCESS(ntStatus)) {
  2322. USBH_KdBreak(("StopDevice USBH_SymbolicLink failed = %x\n",
  2323. ntStatus));
  2324. }
  2325. #endif
  2326. }
  2327. return ntStatus;
  2328. }
  2329. NTSTATUS
  2330. USBH_PdoStartDevice(
  2331. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  2332. IN PIRP Irp
  2333. )
  2334. /* ++
  2335. *
  2336. * Description:
  2337. *
  2338. * Argument:
  2339. *
  2340. * Return:
  2341. *
  2342. * STATUS_SUCCESS
  2343. *
  2344. *
  2345. * -- */
  2346. {
  2347. NTSTATUS ntStatus;
  2348. PDEVICE_OBJECT deviceObject;
  2349. PIO_STACK_LOCATION irpStack;
  2350. LPGUID lpGuid;
  2351. PDEVICE_EXTENSION_HUB deviceExtensionHub;
  2352. irpStack = IoGetCurrentIrpStackLocation(Irp);
  2353. deviceObject = DeviceExtensionPort->PortPhysicalDeviceObject;
  2354. USBH_KdPrint((1,
  2355. "'Starting PDO %x VID %x PID %x\n", deviceObject,
  2356. DeviceExtensionPort->DeviceDescriptor.idVendor,
  2357. DeviceExtensionPort->DeviceDescriptor.idProduct));
  2358. LOGENTRY(LOG_PNP, "Tpdo", DeviceExtensionPort,
  2359. DeviceExtensionPort->PortPhysicalDeviceObject,
  2360. 0);
  2361. if (DeviceExtensionPort->DeviceExtensionHub == NULL &&
  2362. DeviceExtensionPort->PortPdoFlags & PORTPDO_NEED_RESET) {
  2363. // if DeviceExtensionHub is NULL then this is a
  2364. // restart after remove we need to reset the
  2365. // backpointer to the owning hub in this case
  2366. DeviceExtensionPort->DeviceExtensionHub =
  2367. DeviceExtensionPort->HubExtSave;
  2368. }
  2369. deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub;
  2370. if (deviceExtensionHub) {
  2371. ENUMLOG(&deviceExtensionHub->UsbdiBusIf,
  2372. USBDTAG_HUB, 'pdoS',
  2373. (ULONG_PTR) DeviceExtensionPort->PortPhysicalDeviceObject,
  2374. DeviceExtensionPort->PortNumber);
  2375. USBHUB_SetDeviceHandleData(deviceExtensionHub,
  2376. DeviceExtensionPort->PortPhysicalDeviceObject,
  2377. DeviceExtensionPort->DeviceData);
  2378. }
  2379. #if DBG
  2380. if (USBH_Debug_Flags & USBH_DEBUGFLAG_BREAK_PDO_START) {
  2381. TEST_TRAP();
  2382. }
  2383. #endif
  2384. //
  2385. // create a symbolic link
  2386. //
  2387. ntStatus = STATUS_SUCCESS;
  2388. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_IS_HUB) {
  2389. lpGuid = (LPGUID)&GUID_CLASS_USBHUB;
  2390. } else {
  2391. lpGuid = (LPGUID)&GUID_CLASS_USB_DEVICE;
  2392. }
  2393. ntStatus = USBH_SymbolicLink(TRUE,
  2394. DeviceExtensionPort,
  2395. lpGuid);
  2396. if (NT_SUCCESS(ntStatus)) {
  2397. DeviceExtensionPort->PortPdoFlags |= PORTPDO_SYM_LINK;
  2398. }
  2399. #if DBG
  2400. else {
  2401. USBH_KdBreak(("StartDevice USBH_SymbolicLink failed = %x\n",
  2402. ntStatus));
  2403. }
  2404. #endif
  2405. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_NEED_RESET) {
  2406. ntStatus = USBH_RestoreDevice(DeviceExtensionPort, FALSE);
  2407. //
  2408. // note: we will fail the start if we could not
  2409. // restore the device.
  2410. //
  2411. }
  2412. DeviceExtensionPort->DeviceState = PowerDeviceD0;
  2413. DeviceExtensionPort->PortPdoFlags |= PORTPDO_STARTED;
  2414. #ifdef WMI_SUPPORT
  2415. if (NT_SUCCESS(ntStatus) &&
  2416. !(DeviceExtensionPort->PortPdoFlags & PORTPDO_WMI_REGISTERED)) {
  2417. PWMILIB_CONTEXT wmiLibInfo;
  2418. wmiLibInfo = &DeviceExtensionPort->WmiLibInfo;
  2419. wmiLibInfo->GuidCount = sizeof (USB_PortWmiGuidList) /
  2420. sizeof (WMIGUIDREGINFO);
  2421. ASSERT(NUM_PORT_WMI_SUPPORTED_GUIDS == wmiLibInfo->GuidCount);
  2422. wmiLibInfo->GuidList = USB_PortWmiGuidList;
  2423. wmiLibInfo->QueryWmiRegInfo = USBH_PortQueryWmiRegInfo;
  2424. wmiLibInfo->QueryWmiDataBlock = USBH_PortQueryWmiDataBlock;
  2425. wmiLibInfo->SetWmiDataBlock = NULL;
  2426. wmiLibInfo->SetWmiDataItem = NULL;
  2427. wmiLibInfo->ExecuteWmiMethod = NULL;
  2428. wmiLibInfo->WmiFunctionControl = NULL;
  2429. IoWMIRegistrationControl(DeviceExtensionPort->PortPhysicalDeviceObject,
  2430. WMIREG_ACTION_REGISTER
  2431. );
  2432. DeviceExtensionPort->PortPdoFlags |= PORTPDO_WMI_REGISTERED;
  2433. }
  2434. #endif
  2435. return ntStatus;
  2436. }
  2437. NTSTATUS
  2438. USBH_PdoRemoveDevice(
  2439. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  2440. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  2441. IN PIRP Irp
  2442. )
  2443. /* ++
  2444. *
  2445. * Description:
  2446. *
  2447. * Argument:
  2448. *
  2449. * Return:
  2450. *
  2451. * STATUS_SUCCESS
  2452. *
  2453. *
  2454. * -- */
  2455. {
  2456. PDEVICE_OBJECT deviceObject;
  2457. NTSTATUS ntStatus = STATUS_SUCCESS;
  2458. PWCHAR sernumbuf;
  2459. KIRQL irql;
  2460. PIRP idleIrp = NULL;
  2461. PIRP waitWakeIrp = NULL;
  2462. PVOID deviceData;
  2463. deviceObject = DeviceExtensionPort->PortPhysicalDeviceObject;
  2464. USBH_KdPrint((1,
  2465. "'Removing PDO %x\n",
  2466. DeviceExtensionPort->PortPhysicalDeviceObject));
  2467. LOGENTRY(LOG_PNP, "Rpdo", DeviceExtensionPort,
  2468. DeviceExtensionPort->PortPhysicalDeviceObject,
  2469. DeviceExtensionPort->PortPdoFlags);
  2470. // **
  2471. // no references to hub after first remove is processed
  2472. // if we have access to the parent at the time of
  2473. // remove this is passed to us as a parameter
  2474. DeviceExtensionPort->DeviceExtensionHub = NULL;
  2475. if (DeviceExtensionHub) {
  2476. ENUMLOG(&DeviceExtensionHub->UsbdiBusIf,
  2477. USBDTAG_HUB, 'pdoR',
  2478. (ULONG_PTR) DeviceExtensionPort->PortPhysicalDeviceObject,
  2479. DeviceExtensionPort->PortNumber);
  2480. }
  2481. // **
  2482. // if we have access to the hub and it is not in D0 then we will
  2483. // power it.
  2484. //
  2485. // In the case where a device was removed with handles still open,
  2486. // we will receive the remove request at a later time. Be sure that
  2487. // the hub is not selectively suspended in this case.
  2488. if (DeviceExtensionHub &&
  2489. DeviceExtensionHub->CurrentPowerState != PowerDeviceD0 &&
  2490. (DeviceExtensionHub->HubFlags & HUBFLAG_NEED_CLEANUP)) {
  2491. USBH_HubSetD0(DeviceExtensionHub);
  2492. }
  2493. // ***
  2494. // **
  2495. // cancel any notifocation irp that may be pending
  2496. IoAcquireCancelSpinLock(&irql);
  2497. if (DeviceExtensionPort->IdleNotificationIrp) {
  2498. idleIrp = DeviceExtensionPort->IdleNotificationIrp;
  2499. DeviceExtensionPort->IdleNotificationIrp = NULL;
  2500. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_IDLE_NOTIFIED;
  2501. if (idleIrp->Cancel) {
  2502. idleIrp = NULL;
  2503. }
  2504. if (idleIrp) {
  2505. IoSetCancelRoutine(idleIrp, NULL);
  2506. }
  2507. LOGENTRY(LOG_PNP, "IdRX", 0, DeviceExtensionPort, idleIrp);
  2508. USBH_KdPrint((1,"'PDO %x being removed, failing idle notification request IRP %x\n",
  2509. DeviceExtensionPort->PortPhysicalDeviceObject, idleIrp));
  2510. }
  2511. // **
  2512. // Kill any wake irps for this PDO now
  2513. if (DeviceExtensionPort->WaitWakeIrp) {
  2514. waitWakeIrp = DeviceExtensionPort->WaitWakeIrp;
  2515. DeviceExtensionPort->WaitWakeIrp = NULL;
  2516. DeviceExtensionPort->PortPdoFlags &=
  2517. ~PORTPDO_REMOTE_WAKEUP_ENABLED;
  2518. if (waitWakeIrp->Cancel || IoSetCancelRoutine(waitWakeIrp, NULL) == NULL) {
  2519. waitWakeIrp = NULL;
  2520. USBH_ASSERT(DeviceExtensionHub);
  2521. // Must decrement pending request count here because
  2522. // we don't complete the IRP below and USBH_WaitWakeCancel
  2523. // won't either because we have cleared the IRP pointer
  2524. // in the device extension above.
  2525. USBH_DEC_PENDING_IO_COUNT(DeviceExtensionHub);
  2526. }
  2527. USBH_KdPrint((1,
  2528. "'Completing Wake Irp for PDO %x with STATUS_CANCELLED\n",
  2529. DeviceExtensionPort->PortPhysicalDeviceObject));
  2530. LOGENTRY(LOG_PNP, "kilR", DeviceExtensionPort,
  2531. DeviceExtensionPort->PortPhysicalDeviceObject,
  2532. DeviceExtensionPort->PortPdoFlags);
  2533. // JOES: Should we decrement portwakeirps for the hub and cancel
  2534. // hub's WW IRP if zero?
  2535. }
  2536. //
  2537. // Finally, release the cancel spin lock
  2538. //
  2539. IoReleaseCancelSpinLock(irql);
  2540. //***
  2541. if (idleIrp) {
  2542. idleIrp->IoStatus.Status = STATUS_CANCELLED;
  2543. IoCompleteRequest(idleIrp, IO_NO_INCREMENT);
  2544. }
  2545. if (waitWakeIrp) {
  2546. USBH_ASSERT(DeviceExtensionHub);
  2547. USBH_CompletePowerIrp(DeviceExtensionHub,
  2548. waitWakeIrp,
  2549. STATUS_CANCELLED);
  2550. }
  2551. //
  2552. // This PDO will need reset if this is a soft-remove from
  2553. // device manager. In this case the PDO will not actually
  2554. // be deleted.
  2555. //
  2556. DeviceExtensionPort->PortPdoFlags |= PORTPDO_NEED_RESET;
  2557. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_SYM_LINK) {
  2558. ntStatus = USBH_SymbolicLink(FALSE,
  2559. DeviceExtensionPort,
  2560. NULL);
  2561. if (NT_SUCCESS(ntStatus)) {
  2562. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_SYM_LINK;
  2563. }
  2564. #if DBG
  2565. else {
  2566. USBH_KdBreak(("RemoveDevice USBH_SymbolicLink failed = %x\n",
  2567. ntStatus));
  2568. }
  2569. #endif
  2570. }
  2571. deviceData = InterlockedExchangePointer(
  2572. &DeviceExtensionPort->DeviceData,
  2573. NULL);
  2574. LOGENTRY(LOG_PNP, "RMdd", DeviceExtensionPort,
  2575. deviceData, DeviceExtensionHub);
  2576. if (deviceData) {
  2577. //
  2578. // DeviceData should have been deleted when the hub was removed
  2579. //
  2580. USBH_ASSERT(DeviceExtensionHub != NULL);
  2581. #ifdef USB2
  2582. ntStatus = USBD_RemoveDeviceEx(DeviceExtensionHub,
  2583. deviceData,
  2584. DeviceExtensionHub->RootHubPdo,
  2585. 0);
  2586. #else
  2587. ntStatus = USBD_RemoveDevice(deviceData,
  2588. DeviceExtensionHub->RootHubPdo,
  2589. 0);
  2590. #endif
  2591. // note the special case:
  2592. // if our port data structure still points to this PDO then
  2593. // we need to disable the port (the device is still listening on
  2594. // the address we just freed.
  2595. // otherwise we just leave the port alone -- the device has been
  2596. // replaced with another one.
  2597. if (DeviceExtensionHub->PortData != NULL &&
  2598. (DeviceExtensionHub->PortData[
  2599. DeviceExtensionPort->PortNumber - 1].DeviceObject == deviceObject)) {
  2600. USBH_SyncDisablePort(DeviceExtensionHub,
  2601. DeviceExtensionPort->PortNumber);
  2602. }
  2603. }
  2604. // Failure cases:
  2605. // USBD_RemoveDevice
  2606. // USBH_SymbolicLink
  2607. // Do we really want to leak a devobj here?
  2608. LOGENTRY(LOG_PNP, "RRR", deviceObject, 0, ntStatus);
  2609. if (NT_SUCCESS(ntStatus)) {
  2610. PPORT_DATA portData = NULL;
  2611. //
  2612. // update our record in the Hub extension
  2613. //
  2614. LOGENTRY(LOG_PNP, "rpdo", deviceObject, 0, 0);
  2615. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_STARTED;
  2616. if (DeviceExtensionHub &&
  2617. DeviceExtensionHub->PortData != NULL) {
  2618. portData =
  2619. &DeviceExtensionHub->PortData[DeviceExtensionPort->PortNumber - 1];
  2620. // port data should be valid for this port
  2621. USBH_ASSERT(portData);
  2622. // jdunn vinma
  2623. // legacy 'ESD' flag
  2624. //
  2625. // We get here if the PDO is removed either because the FDO is
  2626. // removed or the device was reported gone.
  2627. //
  2628. // if this flag is set the hub will loose its reference to this
  2629. // PDO
  2630. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DELETE_PENDING) {
  2631. PDEVICE_OBJECT pdo;
  2632. pdo = portData->DeviceObject;
  2633. LOGENTRY(LOG_PNP, "pd1", pdo, 0, 0);
  2634. // do we still have a reference to the PDO in the hub?
  2635. // if so loose it now.
  2636. // This cannot happen in the FDO remove case because we delete
  2637. // the PDO reference from port data. This only happens in the
  2638. // case where PNP removes the device.
  2639. if (pdo) {
  2640. portData->DeviceObject = NULL;
  2641. portData->ConnectionStatus = NoDeviceConnected;
  2642. // two cases to be concerned with, either PNP knows about
  2643. // this PDO or it does not
  2644. if (PDO_EXT(pdo)->PnPFlags & PDO_PNPFLAG_DEVICE_PRESENT) {
  2645. // PnP still knows about this device, ie it thinks it
  2646. // is present and is sending a non-remove remove. We
  2647. // will need to notify PnP that it is gone.
  2648. //
  2649. InsertTailList(&DeviceExtensionHub->DeletePdoList,
  2650. &PDO_EXT(pdo)->DeletePdoLink);
  2651. } else {
  2652. // we should only get here in the case where we have
  2653. // told PNP the device is gone but for some reason
  2654. // we kept a ref to the PDO. This should probably be
  2655. // investigated.
  2656. TEST_TRAP();
  2657. }
  2658. }
  2659. }
  2660. }
  2661. // When is a remove really a remove?
  2662. // We must determine if deleting the PDO is the approprite
  2663. //
  2664. // if PnP thinks the device is gone then we can delete it
  2665. if (!(DeviceExtensionPort->PnPFlags & PDO_PNPFLAG_DEVICE_PRESENT)) {
  2666. LOGENTRY(LOG_PNP, "Dpdo",
  2667. deviceObject, portData, 0);
  2668. // we should only delete one time, this flag indicates the
  2669. // 'deleted' state so that we can process other irps approriatly
  2670. USBH_ASSERT(!(DeviceExtensionPort->PortPdoFlags & PORTPDO_DELETED_PDO));
  2671. DeviceExtensionPort->PortPdoFlags |= PORTPDO_DELETED_PDO;
  2672. // perform one time delete operations
  2673. //
  2674. // Free the device serial number string. Only do this if we
  2675. // are deleting the device.
  2676. //
  2677. sernumbuf = InterlockedExchangePointer(
  2678. &DeviceExtensionPort->SerialNumberBuffer,
  2679. NULL);
  2680. if (sernumbuf) {
  2681. UsbhExFreePool(sernumbuf);
  2682. }
  2683. #ifdef WMI_SUPPORT
  2684. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_WMI_REGISTERED) {
  2685. // de-register with WMI
  2686. IoWMIRegistrationControl(deviceObject,
  2687. WMIREG_ACTION_DEREGISTER);
  2688. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_WMI_REGISTERED;
  2689. }
  2690. #endif
  2691. // this is the last step of a successful removal, any transfers
  2692. // that may be pening will be flushed out by this routine. After
  2693. // this point the driver may unload.
  2694. if (DeviceExtensionHub) {
  2695. USBHUB_FlushAllTransfers(DeviceExtensionHub);
  2696. }
  2697. USBH_KdPrint((1,
  2698. "'Deleting PDO %x\n",
  2699. deviceObject));
  2700. LOGENTRY(LOG_PNP, "Xpdo",
  2701. deviceObject, 0, 0);
  2702. IoDeleteDevice(deviceObject);
  2703. // jdunn vinma.
  2704. // The hub driver should have no references to this object.
  2705. }
  2706. }
  2707. if (DeviceExtensionHub) {
  2708. USBH_CheckHubIdle(DeviceExtensionHub);
  2709. }
  2710. return ntStatus;
  2711. }
  2712. VOID
  2713. USBH_PdoSetCapabilities(
  2714. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort
  2715. )
  2716. /* ++
  2717. *
  2718. * Description:
  2719. *
  2720. * Init the internal capabilities structure for the PDO that we
  2721. * will return on a query capabilities IRP.
  2722. * Argument:
  2723. *
  2724. * Return:
  2725. *
  2726. * none
  2727. *
  2728. * -- */
  2729. {
  2730. PDEVICE_CAPABILITIES deviceCapabilities;
  2731. PDEVICE_EXTENSION_HUB deviceExtensionHub;
  2732. SYSTEM_POWER_STATE i;
  2733. PAGED_CODE();
  2734. deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub;
  2735. USBH_ASSERT(deviceExtensionHub);
  2736. USBH_KdPrint((2,"'PdoQueryCapabilities \n"));
  2737. //
  2738. // Get the packet.
  2739. //
  2740. deviceCapabilities = &DeviceExtensionPort->DevCaps;
  2741. //
  2742. // Set the capabilities.
  2743. //
  2744. deviceCapabilities->Size = sizeof(DEVICE_CAPABILITIES);
  2745. deviceCapabilities->Version = 1;
  2746. deviceCapabilities->Address = DeviceExtensionPort->PortNumber;
  2747. deviceCapabilities->Removable = TRUE;
  2748. if (DeviceExtensionPort->SerialNumberBuffer) {
  2749. deviceCapabilities->UniqueID = TRUE;
  2750. } else {
  2751. deviceCapabilities->UniqueID = FALSE;
  2752. }
  2753. deviceCapabilities->RawDeviceOK = FALSE;
  2754. //
  2755. // fill in the the device state capabilities from the
  2756. // table we saved from the pdo.
  2757. //
  2758. RtlCopyMemory(&deviceCapabilities->DeviceState[0],
  2759. &deviceExtensionHub->DeviceState[0],
  2760. sizeof(deviceExtensionHub->DeviceState));
  2761. deviceCapabilities->SystemWake = deviceExtensionHub->SystemWake;
  2762. deviceCapabilities->DeviceWake = deviceExtensionHub->DeviceWake;
  2763. deviceCapabilities->DeviceState[PowerSystemWorking] = PowerDeviceD0;
  2764. //
  2765. // deepest device state we can wake up the system with,
  2766. // set to PowerDeviceD0 if wakeup not supported
  2767. // by the device
  2768. //
  2769. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_REMOTE_WAKEUP_SUPPORTED) {
  2770. deviceCapabilities->DeviceWake = PowerDeviceD2;
  2771. deviceCapabilities->WakeFromD2 = TRUE;
  2772. deviceCapabilities->WakeFromD1 = TRUE;
  2773. deviceCapabilities->WakeFromD0 = TRUE;
  2774. deviceCapabilities->DeviceD2 = TRUE;
  2775. deviceCapabilities->DeviceD1 = TRUE;
  2776. for (i=PowerSystemSleeping1; i<=PowerSystemHibernate; i++) {
  2777. if (i > deviceCapabilities->SystemWake) {
  2778. deviceCapabilities->DeviceState[i] = PowerDeviceD3;
  2779. } else {
  2780. deviceCapabilities->DeviceState[i] = PowerDeviceD2;
  2781. }
  2782. }
  2783. } else {
  2784. deviceCapabilities->DeviceWake = PowerDeviceD0;
  2785. for (i=PowerSystemSleeping1; i<=PowerSystemHibernate; i++) {
  2786. deviceCapabilities->DeviceState[i] = PowerDeviceD3;
  2787. }
  2788. }
  2789. return;
  2790. }
  2791. NTSTATUS
  2792. USBH_PdoQueryCapabilities(
  2793. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  2794. IN PIRP Irp
  2795. )
  2796. /* ++
  2797. *
  2798. * Description:
  2799. *
  2800. * This routine is called by PnP via (IRP_MJ_PNP, IRP_MN_QUERY_CAPABILITIES).
  2801. * Supposedly, this is a message forwarded by port device Fdo.
  2802. *
  2803. * Argument:
  2804. *
  2805. * DeviceExtensionPort - This is a a Pdo extension we created for the port
  2806. * device. Irp - the request
  2807. *
  2808. * Return:
  2809. *
  2810. * STATUS_SUCCESS
  2811. *
  2812. *
  2813. * -- */
  2814. {
  2815. PDEVICE_OBJECT deviceObject;
  2816. PDEVICE_CAPABILITIES deviceCapabilities;
  2817. PIO_STACK_LOCATION ioStack;
  2818. SYSTEM_POWER_STATE i;
  2819. USHORT sizeSave;
  2820. USHORT versionSave;
  2821. PAGED_CODE();
  2822. deviceObject = DeviceExtensionPort->PortPhysicalDeviceObject;
  2823. ioStack = IoGetCurrentIrpStackLocation(Irp);
  2824. USBH_KdPrint((2,"'PdoQueryCapabilities Pdo %x\n", deviceObject));
  2825. //
  2826. // Get the packet.
  2827. //
  2828. deviceCapabilities = ioStack->
  2829. Parameters.DeviceCapabilities.Capabilities;
  2830. // size and length are passed in
  2831. // we should not modify these, all
  2832. // others we set as appropriate for
  2833. // USB (see DDK)
  2834. // save values pased in
  2835. sizeSave = deviceCapabilities->Size;
  2836. versionSave = deviceCapabilities->Version;
  2837. //
  2838. // Set the capabilities.
  2839. //
  2840. RtlCopyMemory(deviceCapabilities,
  2841. &DeviceExtensionPort->DevCaps,
  2842. sizeof(*deviceCapabilities));
  2843. // restore saved values
  2844. deviceCapabilities->Size = sizeSave;
  2845. deviceCapabilities->Version = versionSave;
  2846. #if DBG
  2847. if (deviceCapabilities->SurpriseRemovalOK) {
  2848. UsbhWarning(DeviceExtensionPort,
  2849. "QUERY_CAPS called with SurpriseRemovalOK = TRUE\n",
  2850. FALSE);
  2851. }
  2852. #endif
  2853. #if DBG
  2854. {
  2855. ULONG i;
  2856. USBH_KdPrint((1, "'HUB PDO: Device Caps\n"));
  2857. USBH_KdPrint(
  2858. (1, "'UniqueId = %d Removable = %d SurpriseOK = %d RawDeviceOK = %x\n",
  2859. deviceCapabilities->UniqueID,
  2860. deviceCapabilities->Removable,
  2861. deviceCapabilities->SurpriseRemovalOK,
  2862. deviceCapabilities->RawDeviceOK));
  2863. USBH_KdPrint((1, "'Device State Map:\n"));
  2864. for (i=0; i< PowerSystemHibernate; i++) {
  2865. USBH_KdPrint((1, "'-->S%d = D%d\n", i-1,
  2866. deviceCapabilities->DeviceState[i]-1));
  2867. }
  2868. }
  2869. #endif
  2870. return (STATUS_SUCCESS);
  2871. }
  2872. NTSTATUS
  2873. USBH_PdoPnP(
  2874. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  2875. IN PIRP Irp,
  2876. IN UCHAR MinorFunction,
  2877. IN PBOOLEAN CompleteIrp
  2878. )
  2879. /* ++
  2880. *
  2881. * Description:
  2882. *
  2883. * This function responds to IoControl PnPPower for the PDO. This function is
  2884. * synchronous.
  2885. *
  2886. * Arguments:
  2887. *
  2888. * DeviceExtensionPort - the PDO extension Irp - the request packet
  2889. * uchMinorFunction - the minor function of the PnP Power request.
  2890. *
  2891. * Return:
  2892. *
  2893. * NTSTATUS
  2894. *
  2895. * -- */
  2896. {
  2897. NTSTATUS ntStatus;
  2898. PDEVICE_OBJECT deviceObject;
  2899. PIO_STACK_LOCATION irpStack;
  2900. LPGUID lpGuid;
  2901. PDEVICE_EXTENSION_HUB deviceExtensionHub;
  2902. PAGED_CODE();
  2903. // this flag will cause the request to be complete,
  2904. // if we wish to pass it on the we set the flag to FALSE.
  2905. *CompleteIrp = TRUE;
  2906. irpStack = IoGetCurrentIrpStackLocation(Irp);
  2907. deviceObject = DeviceExtensionPort->PortPhysicalDeviceObject;
  2908. USBH_KdPrint((2,"'PnP Power Pdo %x minor %x\n", deviceObject, MinorFunction));
  2909. switch (MinorFunction) {
  2910. case IRP_MN_START_DEVICE:
  2911. USBH_KdPrint((2,"'IRP_MN_START_DEVICE Pdo %x", deviceObject));
  2912. ntStatus = USBH_PdoStartDevice(DeviceExtensionPort, Irp);
  2913. #if 0
  2914. USBH_PdoStartDevice
  2915. USBH_KdPrint((1,
  2916. "'Starting PDO %x VID %x PID %x\n", deviceObject,
  2917. DeviceExtensionPort->DeviceDescriptor.idVendor,
  2918. DeviceExtensionPort->DeviceDescriptor.idProduct));
  2919. LOGENTRY(LOG_PNP, "Tpdo", DeviceExtensionPort,
  2920. DeviceExtensionPort->PortPhysicalDeviceObject,
  2921. 0);
  2922. if (DeviceExtensionPort->DeviceExtensionHub == NULL &&
  2923. DeviceExtensionPort->PortPdoFlags & PORTPDO_NEED_RESET) {
  2924. // if DeviceExtensionHub is NULL then this is a
  2925. // restart after remove we need to reset the
  2926. // backpointer to the owning hub in this case
  2927. DeviceExtensionPort->DeviceExtensionHub =
  2928. DeviceExtensionPort->HubExtSave;
  2929. }
  2930. deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub;
  2931. if (deviceExtensionHub) {
  2932. ENUMLOG(&deviceExtensionHub->UsbdiBusIf,
  2933. USBDTAG_HUB, 'pdoS',
  2934. (ULONG_PTR) DeviceExtensionPort->PortPhysicalDeviceObject,
  2935. DeviceExtensionPort->PortNumber);
  2936. }
  2937. #if DBG
  2938. if (USBH_Debug_Flags & USBH_DEBUGFLAG_BREAK_PDO_START) {
  2939. TEST_TRAP();
  2940. }
  2941. #endif
  2942. //
  2943. // create a symbolic link
  2944. //
  2945. ntStatus = STATUS_SUCCESS;
  2946. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_IS_HUB) {
  2947. lpGuid = (LPGUID)&GUID_CLASS_USBHUB;
  2948. } else {
  2949. lpGuid = (LPGUID)&GUID_CLASS_USB_DEVICE;
  2950. }
  2951. ntStatus = USBH_SymbolicLink(TRUE,
  2952. DeviceExtensionPort,
  2953. lpGuid);
  2954. if (NT_SUCCESS(ntStatus)) {
  2955. DeviceExtensionPort->PortPdoFlags |= PORTPDO_SYM_LINK;
  2956. }
  2957. #if DBG
  2958. else {
  2959. USBH_KdBreak(("StartDevice USBH_SymbolicLink failed = %x\n",
  2960. ntStatus));
  2961. }
  2962. #endif
  2963. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_NEED_RESET) {
  2964. ntStatus = USBH_RestoreDevice(DeviceExtensionPort, FALSE);
  2965. //
  2966. // note: we will fail the start if we could not
  2967. // restore the device.
  2968. //
  2969. }
  2970. DeviceExtensionPort->DeviceState = PowerDeviceD0;
  2971. DeviceExtensionPort->PortPdoFlags |= PORTPDO_STARTED;
  2972. #ifdef WMI_SUPPORT
  2973. if (NT_SUCCESS(ntStatus) &&
  2974. !(DeviceExtensionPort->PortPdoFlags & PORTPDO_WMI_REGISTERED)) {
  2975. PWMILIB_CONTEXT wmiLibInfo;
  2976. wmiLibInfo = &DeviceExtensionPort->WmiLibInfo;
  2977. wmiLibInfo->GuidCount = sizeof (USB_PortWmiGuidList) /
  2978. sizeof (WMIGUIDREGINFO);
  2979. ASSERT(NUM_PORT_WMI_SUPPORTED_GUIDS == wmiLibInfo->GuidCount);
  2980. wmiLibInfo->GuidList = USB_PortWmiGuidList;
  2981. wmiLibInfo->QueryWmiRegInfo = USBH_PortQueryWmiRegInfo;
  2982. wmiLibInfo->QueryWmiDataBlock = USBH_PortQueryWmiDataBlock;
  2983. wmiLibInfo->SetWmiDataBlock = NULL;
  2984. wmiLibInfo->SetWmiDataItem = NULL;
  2985. wmiLibInfo->ExecuteWmiMethod = NULL;
  2986. wmiLibInfo->WmiFunctionControl = NULL;
  2987. IoWMIRegistrationControl(DeviceExtensionPort->PortPhysicalDeviceObject,
  2988. WMIREG_ACTION_REGISTER
  2989. );
  2990. DeviceExtensionPort->PortPdoFlags |= PORTPDO_WMI_REGISTERED;
  2991. }
  2992. #endif
  2993. #endif
  2994. break;
  2995. case IRP_MN_STOP_DEVICE:
  2996. USBH_KdPrint((2,"'IRP_MN_STOP_DEVICE Pdo %x", deviceObject));
  2997. ntStatus = USBH_PdoStopDevice(DeviceExtensionPort, Irp);
  2998. break;
  2999. case IRP_MN_REMOVE_DEVICE:
  3000. USBH_KdPrint((2,"'IRP_MN_REMOVE_DEVICE Pdo %x", deviceObject));
  3001. // pass the backref to the hub, if this is the fisrt remove
  3002. // then it will be valid. If it is a second remove the hub
  3003. // is potentially gone
  3004. ntStatus = USBH_PdoRemoveDevice(DeviceExtensionPort,
  3005. DeviceExtensionPort->DeviceExtensionHub,
  3006. Irp);
  3007. break;
  3008. case IRP_MN_QUERY_STOP_DEVICE:
  3009. USBH_KdPrint((2,"'IRP_MN_QUERY_STOP_DEVICE Pdo %x\n", deviceObject));
  3010. ntStatus = STATUS_SUCCESS;
  3011. break;
  3012. case IRP_MN_CANCEL_STOP_DEVICE:
  3013. USBH_KdPrint((2,"'IRP_MN_CANCEL_STOP_DEVICE Pdo %x\n", deviceObject));
  3014. ntStatus = STATUS_SUCCESS;
  3015. break;
  3016. case IRP_MN_QUERY_REMOVE_DEVICE:
  3017. USBH_KdPrint((2,"'IRP_MN_QUERY_REMOVE_DEVICE Pdo %x\n", deviceObject));
  3018. ntStatus = STATUS_SUCCESS;
  3019. break;
  3020. case IRP_MN_CANCEL_REMOVE_DEVICE:
  3021. USBH_KdPrint((2,"'IRP_MN_CANCEL_REMOVE_DEVICE Pdo %x\n", deviceObject));
  3022. ntStatus = STATUS_SUCCESS;
  3023. break;
  3024. case IRP_MN_SURPRISE_REMOVAL:
  3025. USBH_KdPrint((1,"'IRP_MN_SURPRISE_REMOVAL Pdo %x\n", deviceObject));
  3026. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_SYM_LINK) {
  3027. ntStatus = USBH_SymbolicLink(FALSE,
  3028. DeviceExtensionPort,
  3029. NULL);
  3030. if (NT_SUCCESS(ntStatus)) {
  3031. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_SYM_LINK;
  3032. }
  3033. #if DBG
  3034. else {
  3035. USBH_KdBreak(("SurpriseRemove: USBH_SymbolicLink failed = %x\n",
  3036. ntStatus));
  3037. }
  3038. #endif
  3039. }
  3040. ntStatus = STATUS_SUCCESS;
  3041. break;
  3042. case IRP_MN_QUERY_PNP_DEVICE_STATE:
  3043. USBH_KdPrint((1,"'IRP_MN_QUERY_PNP_DEVICE_STATE Pdo %x\n", deviceObject));
  3044. if (DeviceExtensionPort->PortPdoFlags &
  3045. (PORTPDO_DEVICE_ENUM_ERROR |
  3046. PORTPDO_DEVICE_FAILED |
  3047. PORTPDO_NOT_ENOUGH_POWER |
  3048. PORTPDO_OVERCURRENT)) {
  3049. Irp->IoStatus.Information
  3050. |= PNP_DEVICE_FAILED;
  3051. }
  3052. LOGENTRY(LOG_PNP, "pnpS", DeviceExtensionPort,
  3053. DeviceExtensionPort->PortPhysicalDeviceObject,
  3054. Irp->IoStatus.Information);
  3055. USBH_KdPrint((1,"'IRP_MN_QUERY_PNP_DEVICE_STATE Pdo %x -- state: %x\n",
  3056. deviceObject,
  3057. Irp->IoStatus.Information));
  3058. ntStatus = STATUS_SUCCESS;
  3059. break;
  3060. case IRP_MN_QUERY_CAPABILITIES:
  3061. USBH_KdPrint((2,"'IRP_MN_QUERY_CAPABILITIES Pdo %x\n", deviceObject));
  3062. ntStatus = USBH_PdoQueryCapabilities(DeviceExtensionPort, Irp);
  3063. break;
  3064. case IRP_MN_QUERY_DEVICE_TEXT:
  3065. USBH_KdPrint((2,"'IRP_MN_QUERY_DEVICE_TEXT Pdo %x\n", deviceObject));
  3066. ntStatus = USBH_PdoQueryDeviceText(DeviceExtensionPort, Irp);
  3067. break;
  3068. case IRP_MN_QUERY_ID:
  3069. USBH_KdPrint((2,"'IRP_MN_QUERY_ID Pdo %x\n", deviceObject));
  3070. ntStatus = USBH_PdoQueryId(DeviceExtensionPort, Irp);
  3071. break;
  3072. case IRP_MN_QUERY_RESOURCE_REQUIREMENTS:
  3073. // Adrian says that once PnP sends this IRP, the PDO is valid for
  3074. // PnP functions like IoGetDeviceProperty, etc.
  3075. DeviceExtensionPort->PortPdoFlags |= PORTPDO_VALID_FOR_PNP_FUNCTION;
  3076. #ifndef USBHUB20
  3077. // And since we know that the PDO is valid and the DevNode now exists,
  3078. // this would also be a good time to handle the MS ExtPropDesc.
  3079. //
  3080. USBH_InstallExtPropDesc(deviceObject);
  3081. #endif
  3082. ntStatus = STATUS_SUCCESS;
  3083. break;
  3084. case IRP_MN_QUERY_INTERFACE:
  3085. // forward the Q_INTERFACE to the root hub PDO
  3086. {
  3087. PIO_STACK_LOCATION irpStack;
  3088. *CompleteIrp = FALSE;
  3089. // set the Interface specific data to the device handle
  3090. irpStack = IoGetCurrentIrpStackLocation(Irp);
  3091. if (RtlCompareMemory(irpStack->Parameters.QueryInterface.InterfaceType,
  3092. &USB_BUS_INTERFACE_USBDI_GUID,
  3093. sizeof(GUID)) == sizeof(GUID)) {
  3094. irpStack->Parameters.QueryInterface.InterfaceSpecificData =
  3095. DeviceExtensionPort->DeviceData;
  3096. }
  3097. ntStatus = USBH_PassIrp(Irp,
  3098. DeviceExtensionPort->DeviceExtensionHub->RootHubPdo);
  3099. }
  3100. break;
  3101. case IRP_MN_QUERY_BUS_INFORMATION:
  3102. {
  3103. // return the standard USB GUID
  3104. PPNP_BUS_INFORMATION busInfo;
  3105. USBH_KdPrint((1,"'IRP_MN_QUERY_BUS_INFORMATION Pdo %x\n", deviceObject));
  3106. busInfo = ExAllocatePoolWithTag(PagedPool, sizeof(PNP_BUS_INFORMATION), USBHUB_HEAP_TAG);
  3107. if (busInfo == NULL) {
  3108. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  3109. } else {
  3110. busInfo->BusTypeGuid = GUID_BUS_TYPE_USB;
  3111. busInfo->LegacyBusType = PNPBus;
  3112. busInfo->BusNumber = 0;
  3113. Irp->IoStatus.Information = (ULONG_PTR) busInfo;
  3114. ntStatus = STATUS_SUCCESS;
  3115. }
  3116. }
  3117. break;
  3118. case IRP_MN_QUERY_DEVICE_RELATIONS:
  3119. // this is a leaf node, we return the status passed
  3120. // to us unless it is a call to TargetRelations
  3121. USBH_KdPrint((2,"'IRP_MN_QUERY_DEVICE_RELATIONS Pdo %x type = %d\n",
  3122. deviceObject,irpStack->Parameters.QueryDeviceRelations.Type));
  3123. if (irpStack->Parameters.QueryDeviceRelations.Type ==
  3124. TargetDeviceRelation) {
  3125. PDEVICE_RELATIONS deviceRelations = NULL;
  3126. deviceRelations = ExAllocatePoolWithTag(PagedPool,
  3127. sizeof(*deviceRelations), USBHUB_HEAP_TAG);
  3128. if (deviceRelations == NULL) {
  3129. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  3130. } else {
  3131. ObReferenceObject(DeviceExtensionPort->PortPhysicalDeviceObject);
  3132. deviceRelations->Count = 1;
  3133. deviceRelations->Objects[0] =
  3134. DeviceExtensionPort->PortPhysicalDeviceObject;
  3135. ntStatus = STATUS_SUCCESS;
  3136. }
  3137. Irp->IoStatus.Information=(ULONG_PTR) deviceRelations;
  3138. USBH_KdPrint((1, "'Query Relations, TargetDeviceRelation (PDO) %x complete\n",
  3139. DeviceExtensionPort->PortPhysicalDeviceObject));
  3140. } else {
  3141. ntStatus = Irp->IoStatus.Status;
  3142. }
  3143. break;
  3144. default:
  3145. USBH_KdBreak(("PdoPnP unknown (%d) PnP message Pdo %x\n",
  3146. MinorFunction, deviceObject));
  3147. //
  3148. // return the original status passed to us
  3149. //
  3150. ntStatus = Irp->IoStatus.Status;
  3151. }
  3152. USBH_KdPrint((2,"'PdoPnP exit %x\n", ntStatus));
  3153. return ntStatus;
  3154. }
  3155. VOID
  3156. USBH_ResetPortWorker(
  3157. IN PVOID Context)
  3158. /* ++
  3159. *
  3160. * Description:
  3161. *
  3162. * Work item scheduled to process a port reset.
  3163. *
  3164. *
  3165. * Arguments:
  3166. *
  3167. * Return:
  3168. *
  3169. * -- */
  3170. {
  3171. PUSBH_RESET_WORK_ITEM workItemReset;
  3172. workItemReset = Context;
  3173. USBH_PdoIoctlResetPort(workItemReset->DeviceExtensionPort,
  3174. workItemReset->Irp);
  3175. workItemReset->DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_DEVICE_FAILED;
  3176. UsbhExFreePool(workItemReset);
  3177. }
  3178. BOOLEAN
  3179. USBH_DoesHubNeedWaitWake(
  3180. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub
  3181. )
  3182. /* ++
  3183. *
  3184. * Description:
  3185. *
  3186. * This function determines if a hub needs a WW IRP posted (i.e. children
  3187. * have WW IRP's posted).
  3188. *
  3189. * Arguments:
  3190. *
  3191. * DeviceExtensionHub
  3192. *
  3193. * Return:
  3194. *
  3195. * BOOLEAN indicating whether the hub needs a WW IRP posted or not.
  3196. *
  3197. * NTSTATUS
  3198. *
  3199. * -- */
  3200. {
  3201. PDEVICE_EXTENSION_PORT childDeviceExtensionPort;
  3202. KIRQL irql;
  3203. BOOLEAN bHubNeedsWaitWake;
  3204. ULONG i;
  3205. // Ensure that child port configuration does not change while in this
  3206. // function, i.e. don't allow QBR.
  3207. USBH_KdPrint((2,"'***WAIT reset device mutex %x\n", DeviceExtensionHub));
  3208. USBH_INC_PENDING_IO_COUNT(DeviceExtensionHub);
  3209. KeWaitForSingleObject(&DeviceExtensionHub->ResetDeviceMutex,
  3210. Executive,
  3211. KernelMode,
  3212. FALSE,
  3213. NULL);
  3214. USBH_KdPrint((2,"'***WAIT reset device mutex done %x\n", DeviceExtensionHub));
  3215. IoAcquireCancelSpinLock(&irql);
  3216. bHubNeedsWaitWake = FALSE; // Assume that the hub does not need a WW IRP.
  3217. for (i = 0; i < DeviceExtensionHub->HubDescriptor->bNumberOfPorts; i++) {
  3218. if (DeviceExtensionHub->PortData[i].DeviceObject) {
  3219. childDeviceExtensionPort = DeviceExtensionHub->PortData[i].DeviceObject->DeviceExtension;
  3220. if (childDeviceExtensionPort->PortPdoFlags &
  3221. PORTPDO_REMOTE_WAKEUP_ENABLED) {
  3222. bHubNeedsWaitWake = TRUE;
  3223. break;
  3224. }
  3225. }
  3226. }
  3227. IoReleaseCancelSpinLock(irql);
  3228. USBH_KdPrint((2,"'***RELEASE reset device mutex %x\n", DeviceExtensionHub));
  3229. KeReleaseSemaphore(&DeviceExtensionHub->ResetDeviceMutex,
  3230. LOW_REALTIME_PRIORITY,
  3231. 1,
  3232. FALSE);
  3233. USBH_DEC_PENDING_IO_COUNT(DeviceExtensionHub);
  3234. return bHubNeedsWaitWake;
  3235. }
  3236. VOID
  3237. USBH_CheckHubIdle(
  3238. IN PDEVICE_EXTENSION_HUB DeviceExtensionHub
  3239. )
  3240. /* ++
  3241. *
  3242. * Description:
  3243. *
  3244. * This function determines if a hub is ready to be idled out, and does so
  3245. * if ready.
  3246. *
  3247. * Arguments:
  3248. *
  3249. * DeviceExtensionHub
  3250. *
  3251. * Return:
  3252. *
  3253. * NTSTATUS
  3254. *
  3255. * -- */
  3256. {
  3257. PDEVICE_EXTENSION_HUB rootHubDevExt;
  3258. PDEVICE_EXTENSION_PORT childDeviceExtensionPort;
  3259. KIRQL irql;
  3260. BOOLEAN bAllIdle, submitIdle = FALSE;
  3261. ULONG i;
  3262. LOGENTRY(LOG_PNP, "hCkI", DeviceExtensionHub, DeviceExtensionHub->HubFlags,
  3263. DeviceExtensionHub->CurrentPowerState);
  3264. USBH_KdPrint((1,"'Hub Check Idle %x\n", DeviceExtensionHub));
  3265. KeAcquireSpinLock(&DeviceExtensionHub->CheckIdleSpinLock, &irql);
  3266. if (DeviceExtensionHub->HubFlags & HUBFLAG_IN_IDLE_CHECK) {
  3267. KeReleaseSpinLock(&DeviceExtensionHub->CheckIdleSpinLock, irql);
  3268. return;
  3269. }
  3270. DeviceExtensionHub->HubFlags |= HUBFLAG_IN_IDLE_CHECK;
  3271. KeReleaseSpinLock(&DeviceExtensionHub->CheckIdleSpinLock, irql);
  3272. rootHubDevExt = USBH_GetRootHubDevExt(DeviceExtensionHub);
  3273. if (rootHubDevExt->CurrentSystemPowerState != PowerSystemWorking) {
  3274. LOGENTRY(LOG_PNP, "hCkS", DeviceExtensionHub, DeviceExtensionHub->HubFlags,
  3275. rootHubDevExt->CurrentSystemPowerState);
  3276. USBH_KdPrint((1,"'CheckHubIdle: System not at S0, fail\n"));
  3277. goto USBH_CheckHubIdleDone;
  3278. }
  3279. #ifdef NEW_START
  3280. if (!(DeviceExtensionHub->HubFlags & HUBFLAG_OK_TO_ENUMERATE)) {
  3281. USBH_KdPrint((1,"'Defer idle\n"));
  3282. goto USBH_CheckHubIdleDone;
  3283. }
  3284. #endif
  3285. if (!(DeviceExtensionHub->HubFlags & HUBFLAG_NEED_CLEANUP) ||
  3286. (DeviceExtensionHub->HubFlags &
  3287. (HUBFLAG_DEVICE_STOPPING |
  3288. HUBFLAG_HUB_GONE |
  3289. HUBFLAG_HUB_FAILURE |
  3290. HUBFLAG_CHILD_DELETES_PENDING |
  3291. HUBFLAG_WW_SET_D0_PENDING |
  3292. HUBFLAG_POST_ESD_ENUM_PENDING |
  3293. HUBFLAG_HUB_HAS_LOST_BRAINS))) {
  3294. LOGENTRY(LOG_PNP, "hCkN", DeviceExtensionHub, DeviceExtensionHub->HubFlags, 0);
  3295. USBH_KdPrint((1,"'CheckHubIdle: Hub not started, stopping, removed, failed, powering up, or delete pending, fail\n"));
  3296. goto USBH_CheckHubIdleDone;
  3297. }
  3298. if (DeviceExtensionHub->ChangeIndicationWorkitemPending) {
  3299. DeviceExtensionHub->HubFlags |= HUBFLAG_NEED_IDLE_CHECK;
  3300. LOGENTRY(LOG_PNP, "hCkP", DeviceExtensionHub, DeviceExtensionHub->HubFlags, 0);
  3301. USBH_KdPrint((1,"'CheckHubIdle: ChangeIndication workitem pending, skip\n"));
  3302. goto USBH_CheckHubIdleDone;
  3303. }
  3304. DeviceExtensionHub->HubFlags &= ~HUBFLAG_NEED_IDLE_CHECK;
  3305. // Ensure that child port configuration does not change while in this
  3306. // function, i.e. don't allow QBR.
  3307. USBH_KdPrint((2,"'***WAIT reset device mutex %x\n", DeviceExtensionHub));
  3308. USBH_INC_PENDING_IO_COUNT(DeviceExtensionHub);
  3309. KeWaitForSingleObject(&DeviceExtensionHub->ResetDeviceMutex,
  3310. Executive,
  3311. KernelMode,
  3312. FALSE,
  3313. NULL);
  3314. USBH_KdPrint((2,"'***WAIT reset device mutex done %x\n", DeviceExtensionHub));
  3315. IoAcquireCancelSpinLock(&irql);
  3316. bAllIdle = TRUE; // Assume that everyone wants to idle.
  3317. for (i = 0; i < DeviceExtensionHub->HubDescriptor->bNumberOfPorts; i++) {
  3318. if (DeviceExtensionHub->PortData[i].DeviceObject) {
  3319. childDeviceExtensionPort = DeviceExtensionHub->PortData[i].DeviceObject->DeviceExtension;
  3320. if (!childDeviceExtensionPort->IdleNotificationIrp) {
  3321. bAllIdle = FALSE;
  3322. break;
  3323. }
  3324. }
  3325. }
  3326. if (bAllIdle &&
  3327. !(DeviceExtensionHub->HubFlags & HUBFLAG_PENDING_IDLE_IRP)) {
  3328. // We're gonna submit the idle irp once we release the spin lock.
  3329. DeviceExtensionHub->HubFlags |= HUBFLAG_PENDING_IDLE_IRP;
  3330. KeResetEvent(&DeviceExtensionHub->SubmitIdleEvent);
  3331. submitIdle = TRUE;
  3332. }
  3333. IoReleaseCancelSpinLock(irql);
  3334. USBH_KdPrint((2,"'***RELEASE reset device mutex %x\n", DeviceExtensionHub));
  3335. KeReleaseSemaphore(&DeviceExtensionHub->ResetDeviceMutex,
  3336. LOW_REALTIME_PRIORITY,
  3337. 1,
  3338. FALSE);
  3339. USBH_DEC_PENDING_IO_COUNT(DeviceExtensionHub);
  3340. if (bAllIdle) {
  3341. LOGENTRY(LOG_PNP, "hCkA", DeviceExtensionHub, 0, 0);
  3342. USBH_KdPrint((1,"'CheckHubIdle: All devices on hub %x idle!\n",
  3343. DeviceExtensionHub));
  3344. // And when all the child PDO's have been idled, we can now idle
  3345. // the hub itself.
  3346. //
  3347. // BUGBUG: What do we do if this fails? Do we even care?
  3348. if (submitIdle) {
  3349. USBH_FdoSubmitIdleRequestIrp(DeviceExtensionHub);
  3350. }
  3351. }
  3352. USBH_CheckHubIdleDone:
  3353. KeAcquireSpinLock(&DeviceExtensionHub->CheckIdleSpinLock, &irql);
  3354. DeviceExtensionHub->HubFlags &= ~HUBFLAG_IN_IDLE_CHECK;
  3355. KeReleaseSpinLock(&DeviceExtensionHub->CheckIdleSpinLock, irql);
  3356. ;
  3357. }
  3358. NTSTATUS
  3359. USBH_PortIdleNotificationRequest(
  3360. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  3361. IN PIRP Irp
  3362. )
  3363. /* ++
  3364. *
  3365. * Description:
  3366. *
  3367. * This function handles a request by a USB client driver to tell us
  3368. * that the device wants to idle (selective suspend).
  3369. *
  3370. * Arguments:
  3371. *
  3372. * DeviceExtensionPort - the PDO extension
  3373. * Irp - the request packet
  3374. *
  3375. * Return:
  3376. *
  3377. * NTSTATUS
  3378. *
  3379. * -- */
  3380. {
  3381. PUSB_IDLE_CALLBACK_INFO idleCallbackInfo;
  3382. PDEVICE_EXTENSION_HUB deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub;
  3383. PDRIVER_CANCEL oldCancelRoutine;
  3384. NTSTATUS ntStatus = STATUS_PENDING;
  3385. KIRQL irql;
  3386. LOGENTRY(LOG_PNP, "IdlP", DeviceExtensionPort, Irp, 0);
  3387. USBH_KdPrint((1,"'Idle request %x, IRP %x\n", DeviceExtensionPort, Irp));
  3388. IoAcquireCancelSpinLock(&irql);
  3389. if (DeviceExtensionPort->IdleNotificationIrp != NULL) {
  3390. IoReleaseCancelSpinLock(irql);
  3391. LOGENTRY(LOG_PNP, "Idl2", DeviceExtensionPort, Irp, 0);
  3392. UsbhWarning(DeviceExtensionPort,
  3393. "Idle IRP submitted while already one pending\n",
  3394. TRUE);
  3395. Irp->IoStatus.Status = STATUS_DEVICE_BUSY;
  3396. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3397. return STATUS_DEVICE_BUSY;
  3398. }
  3399. idleCallbackInfo = (PUSB_IDLE_CALLBACK_INFO)
  3400. IoGetCurrentIrpStackLocation(Irp)->\
  3401. Parameters.DeviceIoControl.Type3InputBuffer;
  3402. if (!idleCallbackInfo || !idleCallbackInfo->IdleCallback) {
  3403. LOGENTRY(LOG_PNP, "Idl4", DeviceExtensionPort, Irp, 0);
  3404. USBH_KdPrint((1,"'Idle request: No callback provided with idle IRP!\n"));
  3405. IoReleaseCancelSpinLock(irql);
  3406. Irp->IoStatus.Status = STATUS_NO_CALLBACK_ACTIVE;
  3407. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3408. return STATUS_NO_CALLBACK_ACTIVE;
  3409. }
  3410. //
  3411. // Must set cancel routine before checking Cancel flag.
  3412. //
  3413. oldCancelRoutine = IoSetCancelRoutine(Irp, USBH_PortIdleNotificationCancelRoutine);
  3414. USBH_ASSERT(!oldCancelRoutine);
  3415. if (Irp->Cancel) {
  3416. //
  3417. // Irp was cancelled. Check whether cancel routine was called.
  3418. //
  3419. oldCancelRoutine = IoSetCancelRoutine(Irp, NULL);
  3420. if (oldCancelRoutine) {
  3421. //
  3422. // Cancel routine was NOT called. So complete the irp here.
  3423. //
  3424. LOGENTRY(LOG_PNP, "Idl3", DeviceExtensionPort, Irp, 0);
  3425. USBH_KdPrint((1,"'Idle request: Idle IRP already cancelled, complete it here!\n"));
  3426. IoReleaseCancelSpinLock(irql);
  3427. Irp->IoStatus.Status = STATUS_CANCELLED;
  3428. IoCompleteRequest(Irp, IO_NO_INCREMENT);
  3429. ntStatus = STATUS_CANCELLED;
  3430. } else {
  3431. //
  3432. // Cancel routine was called, and it will complete the IRP
  3433. // as soon as we drop the spinlock.
  3434. // Return STATUS_PENDING so we don't touch the IRP.
  3435. //
  3436. LOGENTRY(LOG_PNP, "Idl5", DeviceExtensionPort, Irp, 0);
  3437. USBH_KdPrint((1,"'Idle request: Idle IRP already cancelled, don't complete here!\n"));
  3438. IoMarkIrpPending(Irp);
  3439. IoReleaseCancelSpinLock(irql);
  3440. ntStatus = STATUS_PENDING;
  3441. }
  3442. } else {
  3443. // IRP was not cancelled, so keep it.
  3444. DeviceExtensionPort->IdleNotificationIrp = Irp;
  3445. DeviceExtensionPort->PortPdoFlags |= PORTPDO_IDLE_NOTIFIED;
  3446. IoMarkIrpPending(Irp);
  3447. IoReleaseCancelSpinLock(irql);
  3448. ntStatus = STATUS_PENDING;
  3449. // See if we are ready to idle out this hub.
  3450. USBH_CheckHubIdle(deviceExtensionHub);
  3451. }
  3452. return ntStatus;
  3453. }
  3454. #ifdef DRM_SUPPORT
  3455. NTSTATUS
  3456. USBH_PdoSetContentId
  3457. (
  3458. IN PIRP irp,
  3459. IN PKSP_DRMAUDIOSTREAM_CONTENTID pKsProperty,
  3460. IN PKSDRMAUDIOSTREAM_CONTENTID pvData
  3461. )
  3462. /* ++
  3463. *
  3464. * Description:
  3465. *
  3466. *
  3467. * Arguments:
  3468. *
  3469. * Return:
  3470. *
  3471. * -- */
  3472. {
  3473. ULONG ContentId;
  3474. PIO_STACK_LOCATION ioStackLocation;
  3475. PDEVICE_EXTENSION_PORT deviceExtensionPort;
  3476. PDEVICE_OBJECT forwardDeviceObject;
  3477. USBD_PIPE_HANDLE hPipe;
  3478. NTSTATUS ntStatus;
  3479. PAGED_CODE();
  3480. ASSERT(irp);
  3481. ASSERT(pKsProperty);
  3482. ASSERT(pvData);
  3483. ioStackLocation = IoGetCurrentIrpStackLocation(irp);
  3484. deviceExtensionPort = ioStackLocation->DeviceObject->DeviceExtension;
  3485. forwardDeviceObject = deviceExtensionPort->DeviceExtensionHub->TopOfHcdStackDeviceObject;
  3486. hPipe = pKsProperty->Context;
  3487. ContentId = pvData->ContentId;
  3488. return pKsProperty->DrmForwardContentToDeviceObject(ContentId, forwardDeviceObject, hPipe);
  3489. }
  3490. #endif
  3491. NTSTATUS
  3492. USBH_PdoDispatch(
  3493. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  3494. IN PIRP Irp)
  3495. /*
  3496. * Description:
  3497. *
  3498. * This function handles calls to PDOs we have created
  3499. * since we are the bottom driver for the PDO it is up
  3500. * to us to complete the irp -- with one exception.
  3501. *
  3502. * api calls to the USB stack are forwarded directly
  3503. * to the PDO for the root hub which is owned by the USB
  3504. * HC.
  3505. *
  3506. * Arguments:
  3507. *
  3508. * Return:
  3509. *
  3510. * NTSTATUS
  3511. *
  3512. * -- */
  3513. {
  3514. NTSTATUS ntStatus;
  3515. PIO_STACK_LOCATION ioStackLocation; // our stack location
  3516. PDEVICE_OBJECT deviceObject;
  3517. PDEVICE_EXTENSION_HUB deviceExtensionHub;
  3518. PURB urb;
  3519. USBH_KdPrint((2,"'PdoDispatch DeviceExtension %x Irp %x\n", DeviceExtensionPort, Irp));
  3520. deviceObject = DeviceExtensionPort->PortPhysicalDeviceObject;
  3521. deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub;
  3522. //
  3523. // Get a pointer to IoStackLocation so we can retrieve parameters.
  3524. //
  3525. ioStackLocation = IoGetCurrentIrpStackLocation(Irp);
  3526. switch (ioStackLocation->MajorFunction) {
  3527. case IRP_MJ_CREATE:
  3528. USBH_KdPrint((2,"'HUB PDO IRP_MJ_CREATE\n"));
  3529. ntStatus = STATUS_SUCCESS;
  3530. USBH_CompleteIrp(Irp, ntStatus);
  3531. break;
  3532. case IRP_MJ_CLOSE:
  3533. USBH_KdPrint((2,"'HUB PDO IRP_MJ_CLOSE\n"));
  3534. ntStatus = STATUS_SUCCESS;
  3535. USBH_CompleteIrp(Irp, ntStatus);
  3536. break;
  3537. case IRP_MJ_INTERNAL_DEVICE_CONTROL:
  3538. {
  3539. ULONG ioControlCode;
  3540. USBH_KdPrint((2,"'Internal Device Control\n"));
  3541. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DELETED_PDO) {
  3542. #if DBG
  3543. UsbhWarning(DeviceExtensionPort,
  3544. "Client Device Driver is sending requests to a device that has been removed.\n",
  3545. (BOOLEAN)((USBH_Debug_Trace_Level > 0) ? TRUE : FALSE));
  3546. #endif
  3547. ntStatus = STATUS_DEVICE_NOT_CONNECTED;
  3548. USBH_CompleteIrp(Irp, ntStatus);
  3549. break;
  3550. }
  3551. // Take this out. This breaks SyncDisablePort, AbortInterruptPipe.
  3552. //
  3553. // if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DELETE_PENDING) {
  3554. // ntStatus = STATUS_DELETE_PENDING;
  3555. // USBH_CompleteIrp(Irp, ntStatus);
  3556. // break;
  3557. // }
  3558. if (DeviceExtensionPort->DeviceState != PowerDeviceD0) {
  3559. #if DBG
  3560. UsbhWarning(DeviceExtensionPort,
  3561. "Client Device Driver is sending requests to a device in a low power state.\n",
  3562. (BOOLEAN)((USBH_Debug_Trace_Level > 0) ? TRUE : FALSE));
  3563. #endif
  3564. // Must use an error code here that can be mapped to Win32 in
  3565. // rtl\generr.c
  3566. ntStatus = STATUS_DEVICE_POWERED_OFF;
  3567. USBH_CompleteIrp(Irp, ntStatus);
  3568. break;
  3569. }
  3570. ioControlCode =
  3571. ioStackLocation->Parameters.DeviceIoControl.IoControlCode;
  3572. //
  3573. // old comments:
  3574. // **
  3575. // The following code used to check for HUBFLAG_HUB_GONE,
  3576. // HUBFLAG_DEVICE_STOPPING, and HUBFLAG_HUB_HAS_LOST_BRAINS also,
  3577. // but doing so breaks the case where a hub with a downstream
  3578. // device is disconnected or powered off and the driver for the
  3579. // child device sends an AbortPipe request, but the driver hangs
  3580. // waiting for the pending requests to complete which never do
  3581. // because the USBPORT never saw the AbortPipe request.
  3582. // **
  3583. //
  3584. //
  3585. // jd new comments:
  3586. //
  3587. // the backref to the parent is always removed when the PDO processes
  3588. // the remove irp so it is safe to fail APIs when DevExtHub is NULL.
  3589. // The device handle is gone at this point so there should be no traffic
  3590. // pending is usbport.
  3591. //
  3592. // there is one execption -- the GET_RRO_HUB_PDO api. we need to let
  3593. // this one thru since the hub driver will call it from add device
  3594. if (IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO == ioControlCode) {
  3595. deviceExtensionHub = DeviceExtensionPort->HubExtSave;
  3596. }
  3597. if (!deviceExtensionHub) {
  3598. ntStatus = STATUS_DEVICE_BUSY;
  3599. USBH_CompleteIrp(Irp, ntStatus);
  3600. break;
  3601. }
  3602. USBH_ASSERT(deviceExtensionHub);
  3603. switch (ioControlCode) {
  3604. case IOCTL_INTERNAL_USB_GET_HUB_COUNT:
  3605. //
  3606. // This PDO belongs to a hub, bump the count and pass
  3607. // on to the parent hub that this hub is connected to
  3608. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_IS_HUB) {
  3609. PULONG count;
  3610. //
  3611. // bump the count and pass on to our PDO
  3612. //
  3613. count = ioStackLocation->Parameters.Others.Argument1;
  3614. (*count)++;
  3615. // bump the count for this hub and pass on to next PDO
  3616. ntStatus = USBH_SyncGetRootHubPdo(deviceExtensionHub->TopOfStackDeviceObject,
  3617. NULL,
  3618. NULL,
  3619. count);
  3620. USBH_CompleteIrp(Irp, ntStatus);
  3621. } else {
  3622. ntStatus = STATUS_INVALID_PARAMETER;
  3623. USBH_CompleteIrp(Irp, ntStatus);
  3624. }
  3625. break;
  3626. case IOCTL_INTERNAL_USB_GET_CONTROLLER_NAME:
  3627. {
  3628. PUSB_HUB_NAME hubName;
  3629. ULONG length;
  3630. length = PtrToUlong( ioStackLocation->Parameters.Others.Argument2 );
  3631. hubName = ioStackLocation->Parameters.Others.Argument1;
  3632. ntStatus = USBHUB_GetControllerName(deviceExtensionHub,
  3633. hubName,
  3634. length);
  3635. }
  3636. USBH_CompleteIrp(Irp, ntStatus);
  3637. break;
  3638. case IOCTL_INTERNAL_USB_GET_BUS_INFO:
  3639. //ntStatus = USBH_PassIrp(Irp,
  3640. // deviceExtensionHub->RootHubPdo);
  3641. {
  3642. PUSB_BUS_NOTIFICATION busInfo;
  3643. busInfo = ioStackLocation->Parameters.Others.Argument1;
  3644. ntStatus = USBHUB_GetBusInfoDevice(deviceExtensionHub,
  3645. DeviceExtensionPort,
  3646. busInfo);
  3647. }
  3648. USBH_CompleteIrp(Irp, ntStatus);
  3649. break;
  3650. case IOCTL_INTERNAL_USB_GET_ROOTHUB_PDO:
  3651. if (DeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_IS_HUB) {
  3652. ntStatus = USBH_PassIrp(Irp,
  3653. deviceExtensionHub->RootHubPdo);
  3654. } else {
  3655. //
  3656. // if this is not a hub return NULL for the root hub pdo
  3657. // so that the hub driver will act as parent
  3658. //
  3659. PDEVICE_OBJECT *rootHubPdo;
  3660. rootHubPdo = ioStackLocation ->Parameters.Others.Argument1;
  3661. *rootHubPdo = NULL;
  3662. ntStatus = STATUS_SUCCESS;
  3663. USBH_CompleteIrp(Irp, ntStatus);
  3664. }
  3665. break;
  3666. case IOCTL_INTERNAL_USB_SUBMIT_URB:
  3667. //
  3668. // note: we forward apis on from here in case a filter driver
  3669. // was inserted above the PDO for the device.
  3670. //
  3671. urb = ioStackLocation->Parameters.Others.Argument1;
  3672. urb->UrbHeader.UsbdDeviceHandle = DeviceExtensionPort->DeviceData;
  3673. if (DeviceExtensionPort->DeviceData == NULL) {
  3674. //ntStatus = STATUS_DEVICE_NOT_CONNECTED;
  3675. //USBH_CompleteIrp(Irp, ntStatus);
  3676. ENUMLOG(&deviceExtensionHub->UsbdiBusIf,
  3677. USBDTAG_HUB, 'dev!', 0, DeviceExtensionPort->PortNumber);
  3678. urb->UrbHeader.UsbdDeviceHandle = (PVOID) (-1);
  3679. ntStatus = USBH_PassIrp(Irp,
  3680. deviceExtensionHub->TopOfHcdStackDeviceObject);
  3681. } else {
  3682. ntStatus = USBH_PdoUrbFilter(DeviceExtensionPort,
  3683. Irp);
  3684. }
  3685. break;
  3686. case IOCTL_INTERNAL_USB_GET_PORT_STATUS:
  3687. ntStatus = USBH_PdoIoctlGetPortStatus(DeviceExtensionPort,
  3688. Irp);
  3689. break;
  3690. case IOCTL_INTERNAL_USB_GET_DEVICE_HANDLE:
  3691. {
  3692. PUSB_DEVICE_HANDLE *p;
  3693. p = ioStackLocation->Parameters.Others.Argument1;
  3694. *p = DeviceExtensionPort->DeviceData;
  3695. ntStatus = STATUS_SUCCESS;
  3696. }
  3697. USBH_CompleteIrp(Irp, ntStatus);
  3698. break;
  3699. case IOCTL_INTERNAL_USB_RESET_PORT:
  3700. if (DeviceExtensionPort->PortPdoFlags & (PORTPDO_RESET_PENDING |
  3701. PORTPDO_CYCLED)) {
  3702. ntStatus = STATUS_UNSUCCESSFUL;
  3703. USBH_CompleteIrp(Irp, ntStatus);
  3704. } else {
  3705. PUSBH_RESET_WORK_ITEM workItemReset;
  3706. //
  3707. // Schedule a work item to process this reset.
  3708. //
  3709. workItemReset = UsbhExAllocatePool(NonPagedPool,
  3710. sizeof(USBH_RESET_WORK_ITEM));
  3711. if (workItemReset) {
  3712. DeviceExtensionPort->PortPdoFlags |= PORTPDO_RESET_PENDING;
  3713. workItemReset->DeviceExtensionPort = DeviceExtensionPort;
  3714. workItemReset->Irp = Irp;
  3715. ntStatus = STATUS_PENDING;
  3716. IoMarkIrpPending(Irp);
  3717. ExInitializeWorkItem(&workItemReset->WorkQueueItem,
  3718. USBH_ResetPortWorker,
  3719. workItemReset);
  3720. LOGENTRY(LOG_PNP, "rITM", DeviceExtensionPort,
  3721. &workItemReset->WorkQueueItem, 0);
  3722. ExQueueWorkItem(&workItemReset->WorkQueueItem,
  3723. DelayedWorkQueue);
  3724. // The WorkItem is freed by USBH_ResetPortWorker()
  3725. // Don't try to access the WorkItem after it is queued.
  3726. } else {
  3727. //
  3728. // could not queue the work item
  3729. // re-
  3730. // in case the condition is temporary
  3731. TEST_TRAP();
  3732. ntStatus = STATUS_UNSUCCESSFUL;
  3733. USBH_CompleteIrp(Irp, ntStatus);
  3734. }
  3735. }
  3736. break;
  3737. case IOCTL_INTERNAL_USB_ENABLE_PORT:
  3738. ntStatus = USBH_PdoIoctlEnablePort(DeviceExtensionPort,
  3739. Irp);
  3740. break;
  3741. case IOCTL_INTERNAL_USB_CYCLE_PORT:
  3742. ntStatus = USBH_PdoIoctlCyclePort(DeviceExtensionPort,
  3743. Irp);
  3744. break;
  3745. case IOCTL_INTERNAL_USB_GET_HUB_NAME:
  3746. ntStatus = USBH_IoctlHubSymbolicName(DeviceExtensionPort,
  3747. Irp);
  3748. break;
  3749. case IOCTL_INTERNAL_USB_GET_PARENT_HUB_INFO:
  3750. {
  3751. PDEVICE_OBJECT *parent;
  3752. PULONG portNumber;
  3753. PDEVICE_OBJECT *rootHubPdo;
  3754. // return Parents PDO
  3755. parent = ioStackLocation->Parameters.Others.Argument1;
  3756. if (parent) {
  3757. *parent = deviceExtensionHub->PhysicalDeviceObject;
  3758. }
  3759. // return port number
  3760. portNumber = ioStackLocation->Parameters.Others.Argument2;
  3761. if (portNumber) {
  3762. *portNumber = DeviceExtensionPort->PortNumber;
  3763. }
  3764. // return bus context (root hub pdo)
  3765. rootHubPdo = ioStackLocation->Parameters.Others.Argument4;
  3766. if (rootHubPdo) {
  3767. *rootHubPdo = deviceExtensionHub->RootHubPdo;
  3768. }
  3769. ntStatus = STATUS_SUCCESS;
  3770. USBH_CompleteIrp(Irp, ntStatus);
  3771. }
  3772. break;
  3773. case IOCTL_INTERNAL_USB_SUBMIT_IDLE_NOTIFICATION:
  3774. ntStatus = USBH_PortIdleNotificationRequest(DeviceExtensionPort, Irp);
  3775. break;
  3776. default:
  3777. USBH_KdPrint((2,"'InternalDeviceControl IOCTL unknown\n"));
  3778. ntStatus = Irp->IoStatus.Status;
  3779. USBH_CompleteIrp(Irp, ntStatus);
  3780. }
  3781. break;
  3782. }
  3783. case IRP_MJ_DEVICE_CONTROL:
  3784. {
  3785. ULONG ioControlCode = ioStackLocation->Parameters.DeviceIoControl.IoControlCode;
  3786. switch (ioControlCode) {
  3787. #ifdef DRM_SUPPORT
  3788. case IOCTL_KS_PROPERTY:
  3789. ntStatus = KsPropertyHandleDrmSetContentId(Irp, USBH_PdoSetContentId);
  3790. USBH_CompleteIrp(Irp, ntStatus);
  3791. break;
  3792. #endif
  3793. case IOCTL_STORAGE_GET_MEDIA_SERIAL_NUMBER:
  3794. ntStatus = STATUS_NOT_SUPPORTED;
  3795. USBH_CompleteIrp(Irp, ntStatus);
  3796. break;
  3797. default:
  3798. // Unknown Irp, shouldn't be here.
  3799. USBH_KdBreak(("Unhandled IOCTL for Pdo %x IoControlCode %x\n",
  3800. deviceObject, ioControlCode));
  3801. ntStatus = Irp->IoStatus.Status;
  3802. USBH_CompleteIrp(Irp, ntStatus);
  3803. break;
  3804. }
  3805. break;
  3806. }
  3807. case IRP_MJ_PNP:
  3808. {
  3809. BOOLEAN completeIrp;
  3810. USBH_KdPrint((2,"'IRP_MJ_PNP\n"));
  3811. ntStatus =
  3812. USBH_PdoPnP(DeviceExtensionPort,
  3813. Irp,
  3814. ioStackLocation->MinorFunction,
  3815. &completeIrp);
  3816. if (completeIrp) {
  3817. USBH_CompleteIrp(Irp, ntStatus);
  3818. }
  3819. }
  3820. break;
  3821. case IRP_MJ_POWER:
  3822. USBH_KdPrint((2,"'IRP_MJ_POWER\n"));
  3823. ntStatus = USBH_PdoPower(DeviceExtensionPort, Irp, ioStackLocation->MinorFunction);
  3824. //
  3825. // power routines handle irp completion
  3826. //
  3827. break;
  3828. #ifdef WMI_SUPPORT
  3829. case IRP_MJ_SYSTEM_CONTROL:
  3830. USBH_KdPrint((2,"'PDO IRP_MJ_SYSTEM_CONTROL\n"));
  3831. ntStatus =
  3832. USBH_PortSystemControl(DeviceExtensionPort, Irp);
  3833. break;
  3834. #endif
  3835. default:
  3836. USBH_KdBreak(("Unhandled Irp for Pdo %x Irp_Mj %x\n",
  3837. deviceObject, ioStackLocation->MajorFunction));
  3838. //
  3839. // return the original status passed to us
  3840. //
  3841. ntStatus = Irp->IoStatus.Status;
  3842. USBH_CompleteIrp(Irp, ntStatus);
  3843. break;
  3844. }
  3845. USBH_KdPrint((2,"' exit USBH_PdoDispatch Object %x Status %x\n",
  3846. deviceObject, ntStatus));
  3847. return ntStatus;
  3848. }
  3849. NTSTATUS
  3850. USBH_ResetDevice(
  3851. IN OUT PDEVICE_EXTENSION_HUB DeviceExtensionHub,
  3852. IN USHORT PortNumber,
  3853. IN BOOLEAN KeepConfiguration,
  3854. IN ULONG RetryIteration
  3855. )
  3856. /* ++
  3857. *
  3858. * Description:
  3859. *
  3860. * Given a port device object re-create the USB device attached to it
  3861. *
  3862. * Arguments:
  3863. *
  3864. * DeviceExtensionHub - the hub FDO extension that has a new connected port
  3865. * PortNumber - the port that has a device connected. IsLowSpeed - to
  3866. * indicate if the attached device is a low speed one
  3867. *
  3868. * Return:
  3869. *
  3870. * this function returns an error if the device could not be created or
  3871. * if the device is different from the previous device.
  3872. *
  3873. * -- */
  3874. {
  3875. NTSTATUS ntStatus = STATUS_SUCCESS;
  3876. PDEVICE_OBJECT deviceObjectPort;
  3877. PDEVICE_EXTENSION_PORT deviceExtensionPort = NULL;
  3878. BOOLEAN fNeedResetBeforeSetAddress = TRUE;
  3879. PPORT_DATA portData;
  3880. BOOLEAN isLowSpeed;
  3881. PVOID deviceData, oldDeviceData = NULL;
  3882. PORT_STATE portState;
  3883. USHORT portStatus;
  3884. PAGED_CODE();
  3885. USBH_KdPrint((2,"'ResetDevice for port %x\n", PortNumber));
  3886. LOGENTRY(LOG_PNP, "rst1",
  3887. DeviceExtensionHub,
  3888. PortNumber,
  3889. 0);
  3890. // validate that there is actually a device still conected
  3891. ntStatus = USBH_SyncGetPortStatus(DeviceExtensionHub,
  3892. PortNumber,
  3893. (PUCHAR) &portState,
  3894. sizeof(portState));
  3895. if (!(NT_SUCCESS(ntStatus) &&
  3896. (portState.PortStatus & PORT_STATUS_CONNECT))) {
  3897. // error or no device connected
  3898. LOGENTRY(LOG_PNP, "rstx",
  3899. DeviceExtensionHub,
  3900. PortNumber,
  3901. ntStatus);
  3902. return STATUS_UNSUCCESSFUL;
  3903. }
  3904. // Don't allow QBR while we are resetting this device because QBR will
  3905. // toss any PDO for a port that does not have the connect bit set,
  3906. // and this will be the case for this device after we have reset the port
  3907. // until we have finished resetting it.
  3908. USBH_KdPrint((2,"'***WAIT reset device mutex %x\n", DeviceExtensionHub));
  3909. USBH_INC_PENDING_IO_COUNT(DeviceExtensionHub);
  3910. KeWaitForSingleObject(&DeviceExtensionHub->ResetDeviceMutex,
  3911. Executive,
  3912. KernelMode,
  3913. FALSE,
  3914. NULL);
  3915. USBH_KdPrint((2,"'***WAIT reset device mutex done %x\n", DeviceExtensionHub));
  3916. oldDeviceData = NULL;
  3917. LOGENTRY(LOG_PNP, "resD", DeviceExtensionHub,
  3918. PortNumber,
  3919. KeepConfiguration);
  3920. //
  3921. // First get the PDO for the connected device
  3922. //
  3923. portData = &DeviceExtensionHub->PortData[PortNumber - 1];
  3924. deviceObjectPort = portData->DeviceObject;
  3925. if (!deviceObjectPort) {
  3926. ntStatus = STATUS_INVALID_PARAMETER;
  3927. goto USBH_ResetDevice_Done;
  3928. }
  3929. deviceExtensionPort =
  3930. (PDEVICE_EXTENSION_PORT) deviceObjectPort->DeviceExtension;
  3931. portStatus = portData->PortState.PortStatus;
  3932. isLowSpeed = (portData->PortState.PortStatus &
  3933. PORT_STATUS_LOW_SPEED) ? TRUE : FALSE;
  3934. LOGENTRY(LOG_PNP, "resP", DeviceExtensionHub,
  3935. deviceObjectPort,
  3936. deviceExtensionPort->DeviceData);
  3937. #if DBG
  3938. if (KeepConfiguration) {
  3939. USBH_ASSERT(deviceExtensionPort->DeviceData != NULL);
  3940. }
  3941. #endif
  3942. deviceData = InterlockedExchangePointer(
  3943. &deviceExtensionPort->DeviceData,
  3944. NULL);
  3945. if (deviceData == NULL) {
  3946. // device data is null if we are restoring a device associated
  3947. // with an existing pdo (ie remove-refresh)
  3948. oldDeviceData = NULL;
  3949. LOGENTRY(LOG_PNP, "rstn", ntStatus, PortNumber, oldDeviceData);
  3950. } else {
  3951. if (deviceExtensionPort->PortPdoFlags & PORTPDO_DD_REMOVED) {
  3952. oldDeviceData = deviceData;
  3953. LOGENTRY(LOG_PNP, "rst0", ntStatus, PortNumber, oldDeviceData);
  3954. } else {
  3955. #ifdef USB2
  3956. ntStatus = USBD_RemoveDeviceEx(DeviceExtensionHub,
  3957. deviceData,
  3958. DeviceExtensionHub->RootHubPdo,
  3959. (UCHAR) (KeepConfiguration ?
  3960. USBD_KEEP_DEVICE_DATA : 0));
  3961. #else
  3962. ntStatus = USBD_RemoveDevice(deviceData,
  3963. DeviceExtensionHub->RootHubPdo,
  3964. (UCHAR) (KeepConfiguration ?
  3965. USBD_KEEP_DEVICE_DATA : 0));
  3966. #endif
  3967. oldDeviceData = deviceData;
  3968. LOGENTRY(LOG_PNP, "rst2", ntStatus, PortNumber, oldDeviceData);
  3969. deviceExtensionPort->PortPdoFlags |= PORTPDO_DD_REMOVED;
  3970. }
  3971. }
  3972. //
  3973. // reset the port
  3974. //
  3975. if (NT_SUCCESS(ntStatus)) {
  3976. ntStatus = USBH_SyncResetPort(DeviceExtensionHub, PortNumber);
  3977. LOGENTRY(LOG_PNP, "rst3", ntStatus, PortNumber, oldDeviceData);
  3978. }
  3979. // for USB 2 we won't know if the device is high speed until after reset
  3980. // refresh status now
  3981. if (NT_SUCCESS(ntStatus)) {
  3982. ntStatus = USBH_SyncGetPortStatus(DeviceExtensionHub,
  3983. PortNumber,
  3984. (PUCHAR) &portData->PortState,
  3985. sizeof(portData->PortState));
  3986. portStatus = portData->PortState.PortStatus;
  3987. }
  3988. if (NT_SUCCESS(ntStatus)) {
  3989. //
  3990. // call usbd to create device for this connection
  3991. //
  3992. #ifdef USB2
  3993. ntStatus = USBD_CreateDeviceEx(DeviceExtensionHub,
  3994. &deviceExtensionPort->DeviceData,
  3995. deviceObjectPort,
  3996. DeviceExtensionHub->RootHubPdo,
  3997. 0, // optional default endpoint0 max packet
  3998. // size
  3999. &deviceExtensionPort->DeviceHackFlags,
  4000. portStatus,
  4001. PortNumber);
  4002. #else
  4003. ntStatus = USBD_CreateDevice(&deviceExtensionPort->DeviceData,
  4004. DeviceExtensionHub->RootHubPdo,
  4005. isLowSpeed,
  4006. 0, // optional default endpoint0 max packet
  4007. // size
  4008. &deviceExtensionPort->DeviceHackFlags);
  4009. // flag to indicate if
  4010. // we need a second
  4011. // reset
  4012. #endif
  4013. #if DBG
  4014. if (UsbhPnpTest & PNP_TEST_FAIL_RESTORE) {
  4015. ntStatus = STATUS_UNSUCCESSFUL;
  4016. }
  4017. #endif
  4018. LOGENTRY(LOG_PNP, "rst4", ntStatus, PortNumber,
  4019. deviceExtensionPort->DeviceData);
  4020. }
  4021. //
  4022. // some early versions of USB firmware could not handle the premature
  4023. // termination of a control command.
  4024. //
  4025. if (fNeedResetBeforeSetAddress && NT_SUCCESS(ntStatus)) {
  4026. USBH_KdPrint((2,"'NeedResetBeforeSetAddress\n"));
  4027. ntStatus = USBH_SyncResetPort(DeviceExtensionHub, PortNumber);
  4028. #if DBG
  4029. if (!NT_SUCCESS(ntStatus)) {
  4030. USBH_KdBreak(("Failure on second reset %x fail %x\n", PortNumber, ntStatus));
  4031. }
  4032. #endif
  4033. // For some reason, the amount of time between the GetDescriptor request
  4034. // and the SetAddress request decreased when we switched from the older
  4035. // monolithic UHCD.SYS to the new USBUHCI.SYS miniport. And apparently,
  4036. // there have been found at least two devices that were dependent on
  4037. // the longer delay. According to GlenS who looked at one of these
  4038. // devices on the CATC, delta time was ~80ms with UHCD.SYS and ~35ms
  4039. // with USBUHCI.SYS. So, Glen found that by inserting a 50ms delay
  4040. // here, it allows at least one of these devices to now enumerate
  4041. // properly. For performance reasons, we have decided to only insert
  4042. // this delay if a previous enumeration retry has failed, so as not
  4043. // to impact the enumeration time of all devices.
  4044. if (RetryIteration) {
  4045. UsbhWait(50);
  4046. }
  4047. LOGENTRY(LOG_PNP, "rst5", ntStatus, PortNumber,
  4048. deviceExtensionPort->DeviceData);
  4049. }
  4050. if (NT_SUCCESS(ntStatus)) {
  4051. #ifdef USB2
  4052. ntStatus = USBD_InitializeDeviceEx(DeviceExtensionHub,
  4053. deviceExtensionPort->DeviceData,
  4054. DeviceExtensionHub->RootHubPdo,
  4055. &deviceExtensionPort->DeviceDescriptor,
  4056. sizeof(USB_DEVICE_DESCRIPTOR),
  4057. &deviceExtensionPort->ConfigDescriptor,
  4058. sizeof(USB_CONFIGURATION_DESCRIPTOR));
  4059. #else
  4060. ntStatus = USBD_InitializeDevice(deviceExtensionPort->DeviceData,
  4061. DeviceExtensionHub->RootHubPdo,
  4062. &deviceExtensionPort->DeviceDescriptor,
  4063. sizeof(USB_DEVICE_DESCRIPTOR),
  4064. &deviceExtensionPort->ConfigDescriptor,
  4065. sizeof(USB_CONFIGURATION_DESCRIPTOR));
  4066. #endif
  4067. if (!NT_SUCCESS(ntStatus)) {
  4068. // InitializeDevice frees the DeviceData structure on failure
  4069. deviceExtensionPort->DeviceData = NULL;
  4070. }
  4071. LOGENTRY(LOG_PNP, "rst6", ntStatus, PortNumber,
  4072. deviceExtensionPort->DeviceData);
  4073. }
  4074. if (NT_SUCCESS(ntStatus) && KeepConfiguration) {
  4075. // device is now addressed, restore the old config if possible
  4076. #ifdef USB2
  4077. ntStatus = USBD_RestoreDeviceEx(DeviceExtensionHub,
  4078. oldDeviceData,
  4079. deviceExtensionPort->DeviceData,
  4080. DeviceExtensionHub->RootHubPdo);
  4081. #else
  4082. ntStatus = USBD_RestoreDevice(oldDeviceData,
  4083. deviceExtensionPort->DeviceData,
  4084. DeviceExtensionHub->RootHubPdo);
  4085. #endif
  4086. LOGENTRY(LOG_PNP, "rst7", ntStatus, PortNumber,
  4087. oldDeviceData);
  4088. if (!NT_SUCCESS(ntStatus)) {
  4089. // if we fail here remove the newly created device
  4090. deviceData = InterlockedExchangePointer(
  4091. &deviceExtensionPort->DeviceData,
  4092. NULL);
  4093. #ifdef USB2
  4094. USBD_RemoveDeviceEx(DeviceExtensionHub,
  4095. deviceData,
  4096. DeviceExtensionHub->RootHubPdo,
  4097. 0);
  4098. #else
  4099. USBD_RemoveDevice(deviceData,
  4100. DeviceExtensionHub->RootHubPdo,
  4101. 0);
  4102. #endif
  4103. LOGENTRY(LOG_PNP, "rst8", ntStatus, PortNumber,
  4104. oldDeviceData);
  4105. USBH_SyncDisablePort(DeviceExtensionHub,
  4106. PortNumber);
  4107. ntStatus = STATUS_NO_SUCH_DEVICE;
  4108. goto USBH_ResetDevice_Done;
  4109. }
  4110. }
  4111. if (!NT_SUCCESS(ntStatus)) {
  4112. //
  4113. // we have a failure, device data should be freed
  4114. //
  4115. USBH_KdPrint((2,"'InitDevice (reset) for port %x failed %x\n",
  4116. PortNumber, ntStatus));
  4117. LOGENTRY(LOG_PNP, "rst!", ntStatus, PortNumber,
  4118. oldDeviceData);
  4119. //
  4120. // note: oldDeviceData may be null
  4121. //
  4122. deviceData = InterlockedExchangePointer(
  4123. &deviceExtensionPort->DeviceData,
  4124. oldDeviceData);
  4125. if (deviceData != NULL) {
  4126. //
  4127. // we need to remove the device data we created in the restore
  4128. // attempt
  4129. //
  4130. #ifdef USB2
  4131. ntStatus = USBD_RemoveDeviceEx(DeviceExtensionHub,
  4132. deviceData,
  4133. DeviceExtensionHub->RootHubPdo,
  4134. 0);
  4135. #else
  4136. ntStatus = USBD_RemoveDevice(deviceData,
  4137. DeviceExtensionHub->RootHubPdo,
  4138. FALSE);
  4139. #endif
  4140. LOGENTRY(LOG_PNP, "rst9", ntStatus, PortNumber,
  4141. oldDeviceData);
  4142. }
  4143. //
  4144. // disable the port, device is in a bad state
  4145. //
  4146. // NOTE: we don't disable the port on failed reset here
  4147. // in case we need to retry
  4148. //USBH_SyncDisablePort(DeviceExtensionHub,
  4149. // PortNumber);
  4150. // possibly signal the device has been removed
  4151. //
  4152. USBH_KdPrint((0,"'Warning: device/port reset failed\n"));
  4153. } else {
  4154. deviceExtensionPort->PortPdoFlags &= ~PORTPDO_DD_REMOVED;
  4155. LOGENTRY(LOG_PNP, "rsOK", ntStatus, PortNumber,
  4156. oldDeviceData);
  4157. }
  4158. USBH_ResetDevice_Done:
  4159. USBH_KdPrint((2,"'Exit Reset PDO=%x\n", deviceObjectPort));
  4160. USBH_KdPrint((2,"'***RELEASE reset device mutex %x\n", DeviceExtensionHub));
  4161. KeReleaseSemaphore(&DeviceExtensionHub->ResetDeviceMutex,
  4162. LOW_REALTIME_PRIORITY,
  4163. 1,
  4164. FALSE);
  4165. USBH_DEC_PENDING_IO_COUNT(DeviceExtensionHub);
  4166. return ntStatus;
  4167. }
  4168. NTSTATUS
  4169. USBH_RestoreDevice(
  4170. IN OUT PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  4171. IN BOOLEAN KeepConfiguration
  4172. )
  4173. /* ++
  4174. *
  4175. * Description:
  4176. *
  4177. * Arguments:
  4178. *
  4179. * DeviceExtensionHub - the hub FDO extension that has a new connected port
  4180. *
  4181. * Return:
  4182. *
  4183. * this function returns an error if the device could not be created or
  4184. * if the device is different from the previous device.
  4185. *
  4186. * -- */
  4187. {
  4188. NTSTATUS ntStatus = STATUS_SUCCESS;
  4189. PPORT_DATA portData;
  4190. PDEVICE_EXTENSION_HUB deviceExtensionHub;
  4191. ULONG count = 0;
  4192. deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub;
  4193. ASSERT_HUB(deviceExtensionHub);
  4194. if (!deviceExtensionHub) {
  4195. return STATUS_UNSUCCESSFUL;
  4196. }
  4197. portData = &deviceExtensionHub->PortData[
  4198. DeviceExtensionPort->PortNumber - 1];
  4199. LOGENTRY(LOG_PNP, "RSdv", DeviceExtensionPort,
  4200. deviceExtensionHub,
  4201. DeviceExtensionPort->PortNumber);
  4202. //
  4203. // doule check that this device did not disaaper on us
  4204. //
  4205. LOGENTRY(LOG_PNP, "chkD",
  4206. DeviceExtensionPort->PortPhysicalDeviceObject,
  4207. portData->DeviceObject,
  4208. 0);
  4209. if (DeviceExtensionPort->PortPhysicalDeviceObject !=
  4210. portData->DeviceObject) {
  4211. TEST_TRAP();
  4212. return STATUS_UNSUCCESSFUL;
  4213. }
  4214. //
  4215. // we need to refresh the port data since it was lost on the stop
  4216. //
  4217. ntStatus = USBH_SyncGetPortStatus(deviceExtensionHub,
  4218. DeviceExtensionPort->PortNumber,
  4219. (PUCHAR) &portData->PortState,
  4220. sizeof(portData->PortState));
  4221. USBH_ASSERT(DeviceExtensionPort->PortPdoFlags & PORTPDO_NEED_RESET);
  4222. // try the reset three times
  4223. if (NT_SUCCESS(ntStatus)) {
  4224. do {
  4225. LOGENTRY(LOG_PNP, "tryR", count, ntStatus, 0);
  4226. ntStatus = USBH_ResetDevice(deviceExtensionHub,
  4227. DeviceExtensionPort->PortNumber,
  4228. KeepConfiguration,
  4229. count);
  4230. count++;
  4231. if (NT_SUCCESS(ntStatus) || ntStatus == STATUS_NO_SUCH_DEVICE) {
  4232. break;
  4233. }
  4234. #if DBG
  4235. if (count == 1) {
  4236. UsbhWarning(NULL,
  4237. "USB device failed first reset attempt in USBH_RestoreDevice\n",
  4238. (BOOLEAN)((USBH_Debug_Trace_Level >= 3) ? TRUE : FALSE));
  4239. }
  4240. #endif
  4241. //
  4242. // Sometimes the MS USB speakers need a little more time.
  4243. //
  4244. UsbhWait(1000);
  4245. } while (count < USBH_MAX_ENUMERATION_ATTEMPTS);
  4246. }
  4247. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_NEED_RESET;
  4248. //
  4249. // If the device could not be properly restored then do not allow any
  4250. // requests to it.
  4251. //
  4252. if (ntStatus != STATUS_SUCCESS) {
  4253. USBH_KdPrint((0,"'Warning: device/port restore failed\n"));
  4254. LOGENTRY(LOG_PNP, "RSd!", DeviceExtensionPort,
  4255. deviceExtensionHub,
  4256. DeviceExtensionPort->PortNumber);
  4257. DeviceExtensionPort->PortPdoFlags |= PORTPDO_DEVICE_FAILED;
  4258. DeviceExtensionPort->PortPdoFlags |= PORTPDO_DEVICE_ENUM_ERROR;
  4259. // Generate a WMI event so UI can inform the user.
  4260. USBH_PdoEvent(deviceExtensionHub, DeviceExtensionPort->PortNumber);
  4261. } else {
  4262. DeviceExtensionPort->PortPdoFlags &= ~PORTPDO_DEVICE_FAILED;
  4263. }
  4264. USBH_KdBreak(("'USBH_RestoreDevice = %x\n", ntStatus));
  4265. return ntStatus;
  4266. }
  4267. NTSTATUS
  4268. USBH_PdoQueryDeviceText(
  4269. IN PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  4270. IN PIRP Irp
  4271. )
  4272. /* ++
  4273. *
  4274. * Description:
  4275. *
  4276. * This routine is called by PnP via (IRP_MJ_PNP, IRP_MN_QUERY_CAPABILITIES).
  4277. * Supposedly, this is a message forwarded by port device Fdo.
  4278. *
  4279. * Argument:
  4280. *
  4281. * DeviceExtensionPort - This is a a Pdo extension we created for the port
  4282. * device. Irp - the request
  4283. *
  4284. * Return:
  4285. *
  4286. * STATUS_SUCCESS
  4287. *
  4288. *
  4289. * -- */
  4290. {
  4291. PDEVICE_OBJECT deviceObject;
  4292. PIO_STACK_LOCATION ioStack;
  4293. PDEVICE_EXTENSION_HUB deviceExtensionHub;
  4294. DEVICE_TEXT_TYPE deviceTextType;
  4295. LANGID languageId;
  4296. NTSTATUS ntStatus = STATUS_SUCCESS;
  4297. PUSB_STRING_DESCRIPTOR usbString;
  4298. PWCHAR deviceText;
  4299. ULONG ulBytes = 0;
  4300. PAGED_CODE();
  4301. deviceObject = DeviceExtensionPort->PortPhysicalDeviceObject;
  4302. ioStack = IoGetCurrentIrpStackLocation(Irp);
  4303. deviceExtensionHub = DeviceExtensionPort->DeviceExtensionHub;
  4304. deviceTextType = ioStack->
  4305. Parameters.QueryDeviceText.DeviceTextType;
  4306. // Validate DeviceTextType for IrpAssert
  4307. if (deviceTextType != DeviceTextDescription &&
  4308. deviceTextType != DeviceTextLocationInformation) {
  4309. USBH_KdPrint((2, "'PdoQueryDeviceText called with bogus DeviceTextType\n"));
  4310. //
  4311. // return the original status passed to us
  4312. //
  4313. ntStatus = Irp->IoStatus.Status;
  4314. goto USBH_PdoQueryDeviceTextDone;
  4315. }
  4316. languageId = (LANGID)(ioStack->Parameters.QueryDeviceText.LocaleId >> 16);
  4317. USBH_KdPrint((2,"'PdoQueryDeviceText Pdo %x type = %x, lang = %x locale %x\n",
  4318. deviceObject, deviceTextType, languageId, ioStack->Parameters.QueryDeviceText.LocaleId));
  4319. if (!languageId) {
  4320. languageId = 0x0409; // Use English if no language ID.
  4321. }
  4322. //
  4323. // See if the device supports strings. For non compliant device mode
  4324. // we won't even try.
  4325. //
  4326. if (DeviceExtensionPort->DeviceData == NULL ||
  4327. DeviceExtensionPort->DeviceDescriptor.iProduct == 0 ||
  4328. (DeviceExtensionPort->DeviceHackFlags & USBD_DEVHACK_DISABLE_SN) ||
  4329. (DeviceExtensionPort->PortPdoFlags & PORTPDO_DEVICE_ENUM_ERROR)) {
  4330. // string descriptor
  4331. USBH_KdBreak(("no product string\n", deviceObject));
  4332. ntStatus = STATUS_NOT_SUPPORTED;
  4333. }
  4334. if (NT_SUCCESS(ntStatus)) {
  4335. usbString = UsbhExAllocatePool(NonPagedPool, MAXIMUM_USB_STRING_LENGTH);
  4336. if (usbString) {
  4337. QDT_Retry:
  4338. ntStatus = USBH_CheckDeviceLanguage(deviceObject,
  4339. languageId);
  4340. if (NT_SUCCESS(ntStatus)) {
  4341. //
  4342. // Device supports our language, get the string.
  4343. //
  4344. ntStatus = USBH_SyncGetStringDescriptor(deviceObject,
  4345. DeviceExtensionPort->DeviceDescriptor.iProduct, //index
  4346. languageId, //langid
  4347. usbString,
  4348. MAXIMUM_USB_STRING_LENGTH,
  4349. NULL,
  4350. TRUE);
  4351. if (!NT_SUCCESS(ntStatus) && languageId != 0x409) {
  4352. // We are running a non-English flavor of the OS, but the
  4353. // attached USB device does not contain device text in
  4354. // the requested language. Let's try again for English.
  4355. languageId = 0x0409;
  4356. goto QDT_Retry;
  4357. }
  4358. if (NT_SUCCESS(ntStatus) &&
  4359. usbString->bLength <= sizeof(UNICODE_NULL)) {
  4360. ntStatus = STATUS_UNSUCCESSFUL;
  4361. }
  4362. if (NT_SUCCESS(ntStatus)) {
  4363. //
  4364. // return the string
  4365. //
  4366. //
  4367. // must use stock alloc function because the caller frees the
  4368. // buffer
  4369. //
  4370. // note: the descriptor header is the same size as
  4371. // a unicode NULL so we don't have to adjust the size
  4372. //
  4373. deviceText = ExAllocatePoolWithTag(PagedPool, usbString->bLength, USBHUB_HEAP_TAG);
  4374. if (deviceText) {
  4375. RtlZeroMemory(deviceText, usbString->bLength);
  4376. RtlCopyMemory(deviceText, &usbString->bString[0],
  4377. usbString->bLength - sizeof(UNICODE_NULL));
  4378. Irp->IoStatus.Information = (ULONG_PTR) deviceText;
  4379. USBH_KdBreak(("Returning Device Text %x\n", deviceText));
  4380. } else {
  4381. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  4382. }
  4383. }
  4384. } else if (languageId != 0x409) {
  4385. // We are running a non-English flavor of the OS, but the
  4386. // attached USB device does support the requested language.
  4387. // Let's try again for English.
  4388. languageId = 0x0409;
  4389. goto QDT_Retry;
  4390. }
  4391. UsbhExFreePool(usbString);
  4392. } else {
  4393. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  4394. }
  4395. }
  4396. if (!NT_SUCCESS(ntStatus) && GenericUSBDeviceString) {
  4397. USBH_KdPrint((2, "'No product string for devobj (%x), returning generic string\n", deviceObject));
  4398. STRLEN(ulBytes, GenericUSBDeviceString);
  4399. ulBytes += sizeof(UNICODE_NULL);
  4400. deviceText = ExAllocatePoolWithTag(PagedPool, ulBytes, USBHUB_HEAP_TAG);
  4401. if (deviceText) {
  4402. RtlZeroMemory(deviceText, ulBytes);
  4403. RtlCopyMemory(deviceText,
  4404. GenericUSBDeviceString,
  4405. ulBytes);
  4406. Irp->IoStatus.Information = (ULONG_PTR) deviceText;
  4407. ntStatus = STATUS_SUCCESS;
  4408. } else {
  4409. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  4410. }
  4411. }
  4412. USBH_PdoQueryDeviceTextDone:
  4413. return ntStatus;
  4414. }
  4415. #ifdef _WIN64
  4416. #define BAD_POINTER ((PVOID)0xFFFFFFFFFFFFFFFE)
  4417. #else
  4418. #define BAD_POINTER ((PVOID)0xFFFFFFFE)
  4419. #endif
  4420. #define ISPTR(ptr) ((ptr) && ((ptr) != BAD_POINTER))
  4421. NTSTATUS
  4422. USBH_SymbolicLink(
  4423. BOOLEAN CreateFlag,
  4424. PDEVICE_EXTENSION_PORT DeviceExtensionPort,
  4425. LPGUID lpGuid
  4426. )
  4427. {
  4428. NTSTATUS ntStatus = STATUS_SUCCESS;
  4429. if (CreateFlag){
  4430. /*
  4431. * Create the symbolic link
  4432. */
  4433. ntStatus = IoRegisterDeviceInterface(
  4434. DeviceExtensionPort->PortPhysicalDeviceObject,
  4435. lpGuid,
  4436. NULL,
  4437. &DeviceExtensionPort->SymbolicLinkName);
  4438. if (NT_SUCCESS(ntStatus)) {
  4439. /*
  4440. * Now set the symbolic link for the association and store it..
  4441. */
  4442. //USBH_ASSERT(ISPTR(pdoExt->name));
  4443. //
  4444. // (lonnym): Previously, the following call was being made with
  4445. // &DeviceExtensionPort->PdoName passed as the second parameter.
  4446. // Code review this change, to see whether or not you still need to keep
  4447. // this information around.
  4448. //
  4449. // write the symbolic name to the registry
  4450. {
  4451. WCHAR hubNameKey[] = L"SymbolicName";
  4452. USBH_SetPdoRegistryParameter (
  4453. DeviceExtensionPort->PortPhysicalDeviceObject,
  4454. &hubNameKey[0],
  4455. sizeof(hubNameKey),
  4456. &DeviceExtensionPort->SymbolicLinkName.Buffer[0],
  4457. DeviceExtensionPort->SymbolicLinkName.Length,
  4458. REG_SZ,
  4459. PLUGPLAY_REGKEY_DEVICE);
  4460. }
  4461. ntStatus = IoSetDeviceInterfaceState(&DeviceExtensionPort->SymbolicLinkName, TRUE);
  4462. }
  4463. } else {
  4464. /*
  4465. * Disable the symbolic link
  4466. */
  4467. if (ISPTR(DeviceExtensionPort->SymbolicLinkName.Buffer)) {
  4468. ntStatus = IoSetDeviceInterfaceState(&DeviceExtensionPort->SymbolicLinkName, FALSE);
  4469. ExFreePool( DeviceExtensionPort->SymbolicLinkName.Buffer );
  4470. DeviceExtensionPort->SymbolicLinkName.Buffer = BAD_POINTER;
  4471. }
  4472. }
  4473. return ntStatus;
  4474. }
  4475. NTSTATUS
  4476. USBH_SetPdoRegistryParameter (
  4477. IN PDEVICE_OBJECT PhysicalDeviceObject,
  4478. IN PWCHAR KeyName,
  4479. IN ULONG KeyNameLength,
  4480. IN PVOID Data,
  4481. IN ULONG DataLength,
  4482. IN ULONG KeyType,
  4483. IN ULONG DevInstKeyType
  4484. )
  4485. /*++
  4486. Routine Description:
  4487. Arguments:
  4488. Return Value:
  4489. --*/
  4490. {
  4491. NTSTATUS ntStatus;
  4492. HANDLE handle;
  4493. UNICODE_STRING keyNameUnicodeString;
  4494. PAGED_CODE();
  4495. RtlInitUnicodeString(&keyNameUnicodeString, KeyName);
  4496. ntStatus=IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  4497. DevInstKeyType,
  4498. STANDARD_RIGHTS_ALL,
  4499. &handle);
  4500. if (NT_SUCCESS(ntStatus)) {
  4501. /*
  4502. RtlInitUnicodeString(&keyName, L"DeviceFoo");
  4503. ZwSetValueKey(handle,
  4504. &keyName,
  4505. 0,
  4506. REG_DWORD,
  4507. ComplienceFlags,
  4508. sizeof(*ComplienceFlags));
  4509. */
  4510. USBH_SetRegistryKeyValue(handle,
  4511. &keyNameUnicodeString,
  4512. Data,
  4513. DataLength,
  4514. KeyType);
  4515. ZwClose(handle);
  4516. }
  4517. USBH_KdPrint((3,"'USBH_SetPdoRegistryParameter status 0x%x\n", ntStatus));
  4518. return ntStatus;
  4519. }
  4520. NTSTATUS
  4521. USBH_SetRegistryKeyValue (
  4522. IN HANDLE Handle,
  4523. IN PUNICODE_STRING KeyNameUnicodeString,
  4524. IN PVOID Data,
  4525. IN ULONG DataLength,
  4526. IN ULONG KeyType
  4527. )
  4528. /*++
  4529. Routine Description:
  4530. Arguments:
  4531. Return Value:
  4532. --*/
  4533. {
  4534. NTSTATUS ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  4535. PAGED_CODE();
  4536. // InitializeObjectAttributes( &objectAttributes,
  4537. // KeyNameString,
  4538. // OBJ_CASE_INSENSITIVE,
  4539. // Handle,
  4540. // (PSECURITY_DESCRIPTOR) NULL );
  4541. //
  4542. // Create the key or open it, as appropriate based on the caller's
  4543. // wishes.
  4544. //
  4545. #if 0
  4546. ntStatus = ZwCreateKey( Handle,
  4547. DesiredAccess,
  4548. &objectAttributes,
  4549. 0,
  4550. (PUNICODE_STRING) NULL,
  4551. REG_OPTION_VOLATILE,
  4552. &disposition );
  4553. #endif
  4554. ntStatus = ZwSetValueKey(Handle,
  4555. KeyNameUnicodeString,
  4556. 0,
  4557. KeyType,
  4558. Data,
  4559. DataLength);
  4560. USBH_KdPrint((2,"' ZwSetKeyValue = 0x%x\n", ntStatus));
  4561. return ntStatus;
  4562. }
  4563. NTSTATUS
  4564. USBH_GetPdoRegistryParameter(
  4565. IN PDEVICE_OBJECT PhysicalDeviceObject,
  4566. IN PWCHAR ValueName,
  4567. OUT PVOID Data,
  4568. IN ULONG DataLength,
  4569. OUT PULONG Type,
  4570. OUT PULONG ActualDataLength
  4571. )
  4572. /*++
  4573. Routine Description:
  4574. This routines queries the data for a registry value entry associated
  4575. with the device instance specific registry key for the PDO.
  4576. The registry value entry would be found under this registry key:
  4577. HKLM\System\CCS\Enum\<DeviceID>\<InstanceID>\Device Parameters
  4578. Arguments:
  4579. PhysicalDeviceObject - Yep, the PDO
  4580. ValueName - Name of the registry value entry for which the data is requested
  4581. Data - Buffer in which the requested data is returned
  4582. DataLength - Length of the data buffer
  4583. Type - (optional) The data type (e.g. REG_SZ, REG_DWORD) is returned here
  4584. ActualDataLength - (optional) The actual length of the data is returned here
  4585. If this is larger than DataLength then not all of the
  4586. value data has been returned.
  4587. Return Value:
  4588. --*/
  4589. {
  4590. HANDLE handle;
  4591. NTSTATUS ntStatus;
  4592. PAGED_CODE();
  4593. ntStatus = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  4594. PLUGPLAY_REGKEY_DEVICE,
  4595. STANDARD_RIGHTS_ALL,
  4596. &handle);
  4597. if (NT_SUCCESS(ntStatus))
  4598. {
  4599. PKEY_VALUE_PARTIAL_INFORMATION partialInfo;
  4600. UNICODE_STRING valueName;
  4601. ULONG length;
  4602. ULONG resultLength;
  4603. RtlInitUnicodeString(&valueName, ValueName);
  4604. // Size and allocate a KEY_VALUE_PARTIAL_INFORMATION structure,
  4605. // including room for the returned value data.
  4606. //
  4607. length = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) +
  4608. DataLength;
  4609. partialInfo = UsbhExAllocatePool(PagedPool, length);
  4610. if (partialInfo)
  4611. {
  4612. // Query the value data.
  4613. //
  4614. ntStatus = ZwQueryValueKey(handle,
  4615. &valueName,
  4616. KeyValuePartialInformation,
  4617. partialInfo,
  4618. length,
  4619. &resultLength);
  4620. // If we got any data that is good enough
  4621. //
  4622. if (ntStatus == STATUS_BUFFER_OVERFLOW)
  4623. {
  4624. ntStatus = STATUS_SUCCESS;
  4625. }
  4626. if (NT_SUCCESS(ntStatus))
  4627. {
  4628. // Only copy the smaller of the the requested data length or
  4629. // the actual data length.
  4630. //
  4631. RtlCopyMemory(Data,
  4632. partialInfo->Data,
  4633. DataLength < partialInfo->DataLength ?
  4634. DataLength :
  4635. partialInfo->DataLength);
  4636. // Return the value data type and actual length, if requested.
  4637. //
  4638. if (Type)
  4639. {
  4640. *Type = partialInfo->Type;
  4641. }
  4642. if (ActualDataLength)
  4643. {
  4644. *ActualDataLength = partialInfo->DataLength;
  4645. }
  4646. }
  4647. UsbhExFreePool(partialInfo);
  4648. }
  4649. else
  4650. {
  4651. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  4652. }
  4653. ZwClose(handle);
  4654. }
  4655. return ntStatus;
  4656. }
  4657. NTSTATUS
  4658. USBH_OsVendorCodeQueryRoutine(
  4659. IN PWSTR ValueName,
  4660. IN ULONG ValueType,
  4661. IN PVOID ValueData,
  4662. IN ULONG ValueLength,
  4663. IN PVOID Context,
  4664. IN PVOID EntryContext
  4665. )
  4666. {
  4667. PAGED_CODE();
  4668. if (ValueType != REG_BINARY ||
  4669. ValueLength != 2 * sizeof(UCHAR))
  4670. {
  4671. return STATUS_INVALID_PARAMETER;
  4672. }
  4673. ((PUCHAR)EntryContext)[0] = ((PUCHAR)ValueData)[0];
  4674. ((PUCHAR)EntryContext)[1] = ((PUCHAR)ValueData)[1];
  4675. return STATUS_SUCCESS;
  4676. }
  4677. #ifndef USBHUB20
  4678. VOID
  4679. USBH_GetMsOsVendorCode(
  4680. IN PDEVICE_OBJECT DeviceObject
  4681. )
  4682. {
  4683. PDEVICE_EXTENSION_PORT deviceExtensionPort;
  4684. WCHAR path[] = L"usbflags\\vvvvpppprrrr";
  4685. USHORT idVendor;
  4686. USHORT idProduct;
  4687. USHORT bcdDevice;
  4688. ULONG i;
  4689. RTL_QUERY_REGISTRY_TABLE paramTable[2];
  4690. UCHAR osvc[2];
  4691. NTSTATUS ntStatus;
  4692. PAGED_CODE();
  4693. deviceExtensionPort = DeviceObject->DeviceExtension;
  4694. USBH_ASSERT(EXTENSION_TYPE_PORT == deviceExtensionPort->ExtensionType);
  4695. // Build the registry path string for the device
  4696. //
  4697. idVendor = deviceExtensionPort->DeviceDescriptor.idVendor,
  4698. idProduct = deviceExtensionPort->DeviceDescriptor.idProduct,
  4699. bcdDevice = deviceExtensionPort->DeviceDescriptor.bcdDevice,
  4700. i = sizeof("usbflags\\") - 1;
  4701. path[i++] = NibbleToHexW(idVendor >> 12);
  4702. path[i++] = NibbleToHexW((idVendor >> 8) & 0x000f);
  4703. path[i++] = NibbleToHexW((idVendor >> 4) & 0x000f);
  4704. path[i++] = NibbleToHexW(idVendor & 0x000f);
  4705. path[i++] = NibbleToHexW(idProduct >> 12);
  4706. path[i++] = NibbleToHexW((idProduct >> 8) & 0x000f);
  4707. path[i++] = NibbleToHexW((idProduct >> 4) & 0x000f);
  4708. path[i++] = NibbleToHexW(idProduct & 0x000f);
  4709. path[i++] = NibbleToHexW(bcdDevice >> 12);
  4710. path[i++] = NibbleToHexW((bcdDevice >> 8) & 0x000f);
  4711. path[i++] = NibbleToHexW((bcdDevice >> 4) & 0x000f);
  4712. path[i++] = NibbleToHexW(bcdDevice & 0x000f);
  4713. // Check if MsOsVendorCode is already set in the registry.
  4714. //
  4715. RtlZeroMemory (&paramTable[0], sizeof(paramTable));
  4716. paramTable[0].QueryRoutine = USBH_OsVendorCodeQueryRoutine;
  4717. paramTable[0].Flags = RTL_QUERY_REGISTRY_REQUIRED;
  4718. paramTable[0].Name = L"osvc";
  4719. paramTable[0].EntryContext = &osvc;
  4720. ntStatus = RtlQueryRegistryValues(RTL_REGISTRY_CONTROL,
  4721. path,
  4722. &paramTable[0],
  4723. NULL, // Context
  4724. NULL); // Environment
  4725. // If the MsOsVendorCode value in the registry is valid, it indicates
  4726. // whether or not the device supports the MS OS Descriptor request, and if
  4727. // does, what the Vendor Code is.
  4728. //
  4729. if (NT_SUCCESS(ntStatus))
  4730. {
  4731. if (osvc[0] == 1)
  4732. {
  4733. deviceExtensionPort->FeatureDescVendorCode = osvc[1];
  4734. deviceExtensionPort->PortPdoFlags |= PORTPDO_MS_VENDOR_CODE_VALID;
  4735. }
  4736. return;
  4737. }
  4738. // If we have not asked the device for the MS OS String Descriptor yet
  4739. // do that now, but only if the device indicates that it has some other
  4740. // string descriptors.
  4741. //
  4742. if (deviceExtensionPort->DeviceDescriptor.idVendor != 0 ||
  4743. deviceExtensionPort->DeviceDescriptor.iProduct != 0 ||
  4744. deviceExtensionPort->DeviceDescriptor.iSerialNumber != 0)
  4745. {
  4746. OS_STRING osString;
  4747. ULONG bytesReturned;
  4748. // Try to retrieve the MS OS String Descriptor from the device.
  4749. //
  4750. ntStatus = USBH_SyncGetStringDescriptor(
  4751. DeviceObject,
  4752. OS_STRING_DESCRIPTOR_INDEX,
  4753. 0,
  4754. (PUSB_STRING_DESCRIPTOR)&osString,
  4755. sizeof(OS_STRING),
  4756. &bytesReturned,
  4757. TRUE);
  4758. if (NT_SUCCESS(ntStatus) &&
  4759. (bytesReturned == sizeof(OS_STRING)) &&
  4760. (RtlCompareMemory(&osString.MicrosoftString,
  4761. MS_OS_STRING_SIGNATURE,
  4762. sizeof(osString.MicrosoftString)) ==
  4763. sizeof(osString.MicrosoftString)))
  4764. {
  4765. // This device has a valid MS OS String Descriptor.
  4766. // Let's pluck out the corresponding Vendor Code and
  4767. // save that away in the device extension.
  4768. //
  4769. deviceExtensionPort->FeatureDescVendorCode = osString.bVendorCode;
  4770. deviceExtensionPort->PortPdoFlags |= PORTPDO_MS_VENDOR_CODE_VALID;
  4771. }
  4772. else
  4773. {
  4774. // Maybe we've wedged the device by sending it our questionable
  4775. // proprietary request. Reset the device for good measure.
  4776. //
  4777. USBH_SyncResetDevice(DeviceObject);
  4778. }
  4779. }
  4780. // Write the MsOsVendorCode value to the registry. It indicates whether
  4781. // or not the device supports the MS OS Descriptor request, and if
  4782. // does, what the Vendor Code is.
  4783. //
  4784. if (deviceExtensionPort->PortPdoFlags & PORTPDO_MS_VENDOR_CODE_VALID)
  4785. {
  4786. osvc[0] = 1;
  4787. osvc[1] = deviceExtensionPort->FeatureDescVendorCode;
  4788. }
  4789. else
  4790. {
  4791. osvc[0] = 0;
  4792. osvc[1] = 0;
  4793. }
  4794. ntStatus = RtlWriteRegistryValue(RTL_REGISTRY_CONTROL,
  4795. path,
  4796. L"osvc",
  4797. REG_BINARY,
  4798. &osvc[0],
  4799. sizeof(osvc));
  4800. }
  4801. NTSTATUS
  4802. USBH_GetMsOsFeatureDescriptor(
  4803. IN PDEVICE_OBJECT DeviceObject,
  4804. IN UCHAR Recipient,
  4805. IN UCHAR Interface,
  4806. IN USHORT Index,
  4807. IN OUT PVOID DataBuffer,
  4808. IN ULONG DataBufferLength,
  4809. OUT PULONG BytesReturned
  4810. )
  4811. /* ++
  4812. *
  4813. * Description:
  4814. *
  4815. * Return:
  4816. *
  4817. * NTSTATUS
  4818. *
  4819. * -- */
  4820. {
  4821. PDEVICE_EXTENSION_PORT deviceExtensionPort;
  4822. USHORT function;
  4823. struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST *urb;
  4824. NTSTATUS ntStatus;
  4825. PAGED_CODE();
  4826. deviceExtensionPort = DeviceObject->DeviceExtension;
  4827. USBH_ASSERT(EXTENSION_TYPE_PORT == deviceExtensionPort->ExtensionType);
  4828. *BytesReturned = 0;
  4829. // Make sure the device supports the MS OS Descriptor request
  4830. //
  4831. if (!(deviceExtensionPort->PortPdoFlags & PORTPDO_MS_VENDOR_CODE_VALID))
  4832. {
  4833. return STATUS_INVALID_DEVICE_REQUEST;
  4834. }
  4835. // Device, Endpoint, or Interface request?
  4836. //
  4837. switch (Recipient)
  4838. {
  4839. case 0:
  4840. function = URB_FUNCTION_VENDOR_DEVICE;
  4841. break;
  4842. case 1:
  4843. function = URB_FUNCTION_VENDOR_INTERFACE;
  4844. break;
  4845. case 2:
  4846. function = URB_FUNCTION_VENDOR_ENDPOINT;
  4847. break;
  4848. default:
  4849. return STATUS_INVALID_PARAMETER;
  4850. }
  4851. // Make sure the requested buffer length is valid
  4852. //
  4853. if (DataBufferLength == 0 ||
  4854. DataBufferLength > 0xFF * 0xFFFF)
  4855. {
  4856. return STATUS_INVALID_PARAMETER;
  4857. }
  4858. // Allocate a URB for the request
  4859. //
  4860. urb = UsbhExAllocatePool(NonPagedPool, sizeof(*urb));
  4861. if (NULL == urb)
  4862. {
  4863. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  4864. }
  4865. else
  4866. {
  4867. ULONG bytesReturned;
  4868. UCHAR pageNumber;
  4869. bytesReturned = 0;
  4870. pageNumber = 0;
  4871. while (1)
  4872. {
  4873. // Initialize the URB for the current page
  4874. //
  4875. RtlZeroMemory(urb, sizeof(*urb));
  4876. urb->Hdr.Length = sizeof(*urb);
  4877. urb->Hdr.Function = function;
  4878. urb->TransferFlags = USBD_TRANSFER_DIRECTION_IN;
  4879. urb->TransferBufferLength = DataBufferLength < 0xFFFF ?
  4880. DataBufferLength :
  4881. 0xFFFF;
  4882. urb->TransferBuffer = DataBuffer;
  4883. urb->Request = deviceExtensionPort->FeatureDescVendorCode;
  4884. urb->Value = (Interface << 8) | pageNumber;
  4885. urb->Index = Index;
  4886. // Send down the URB for the current page
  4887. //
  4888. ntStatus = USBH_SyncSubmitUrb(DeviceObject, (PURB)urb);
  4889. // If the request failed then we are done.
  4890. //
  4891. if (!NT_SUCCESS(ntStatus))
  4892. {
  4893. break;
  4894. }
  4895. (PUCHAR)DataBuffer += urb->TransferBufferLength;
  4896. DataBufferLength -= urb->TransferBufferLength;
  4897. bytesReturned += urb->TransferBufferLength;
  4898. pageNumber++;
  4899. // If the result was less than the max page size or there are
  4900. // no more bytes remaining then we are done.
  4901. //
  4902. if (urb->TransferBufferLength < 0xFFFF ||
  4903. DataBufferLength == 0)
  4904. {
  4905. *BytesReturned = bytesReturned;
  4906. break;
  4907. }
  4908. }
  4909. // Done with the URB now, free it
  4910. //
  4911. UsbhExFreePool(urb);
  4912. }
  4913. return ntStatus;
  4914. }
  4915. VOID
  4916. USBH_InstallExtPropDesc (
  4917. IN PDEVICE_OBJECT DeviceObject
  4918. )
  4919. /*++
  4920. Routine Description:
  4921. This routines queries a device for an Extended Properties Descriptor, but
  4922. only once the very first time for a given instance of a device.
  4923. If the Extended Properties Descriptor and all of the Custom Property
  4924. Sections appear valid then each Custom Property section <ValueName,
  4925. ValueData> pair is installed in the device instance specific registry key
  4926. for the PDO.
  4927. The registry value entries would be found under this registry key:
  4928. HKLM\System\CCS\Enum\<DeviceID>\<InstanceID>\Device Parameters
  4929. Arguments:
  4930. DeviceObject - The PDO
  4931. Return Value:
  4932. None
  4933. --*/
  4934. {
  4935. PDEVICE_EXTENSION_PORT deviceExtensionPort;
  4936. static WCHAR USBH_DidExtPropDescKey[] = L"ExtPropDescSemaphore";
  4937. ULONG didExtPropDesc;
  4938. MS_EXT_PROP_DESC_HEADER msExtPropDescHeader;
  4939. PMS_EXT_PROP_DESC pMsExtPropDesc;
  4940. ULONG bytesReturned;
  4941. NTSTATUS ntStatus;
  4942. PAGED_CODE();
  4943. deviceExtensionPort = DeviceObject->DeviceExtension;
  4944. // Check if the semaphore value is already set in the registry. We only
  4945. // care whether or not it already exists, not what data it has.
  4946. //
  4947. ntStatus = USBH_GetPdoRegistryParameter(DeviceObject,
  4948. USBH_DidExtPropDescKey,
  4949. NULL,
  4950. 0,
  4951. NULL,
  4952. NULL);
  4953. if (NT_SUCCESS(ntStatus))
  4954. {
  4955. // Already did this once for this device instance. Don't do it again.
  4956. //
  4957. return;
  4958. }
  4959. // Set the semaphore key in the registry so that we only run the following
  4960. // code once per device.
  4961. didExtPropDesc = 1;
  4962. USBH_SetPdoRegistryParameter(DeviceObject,
  4963. USBH_DidExtPropDescKey,
  4964. sizeof(USBH_DidExtPropDescKey),
  4965. &didExtPropDesc,
  4966. sizeof(didExtPropDesc),
  4967. REG_DWORD,
  4968. PLUGPLAY_REGKEY_DEVICE);
  4969. RtlZeroMemory(&msExtPropDescHeader, sizeof(MS_EXT_PROP_DESC_HEADER));
  4970. // Request just the header of the MS Extended Property Descriptor
  4971. //
  4972. ntStatus = USBH_GetMsOsFeatureDescriptor(
  4973. DeviceObject,
  4974. 1, // Recipient Interface
  4975. 0, // Interface
  4976. MS_EXT_PROP_DESCRIPTOR_INDEX,
  4977. &msExtPropDescHeader,
  4978. sizeof(MS_EXT_PROP_DESC_HEADER),
  4979. &bytesReturned);
  4980. // Make sure the MS Extended Property Descriptor header looks ok
  4981. //
  4982. if (NT_SUCCESS(ntStatus) &&
  4983. bytesReturned == sizeof(MS_EXT_PROP_DESC_HEADER) &&
  4984. msExtPropDescHeader.dwLength >= sizeof(MS_EXT_PROP_DESC_HEADER) &&
  4985. msExtPropDescHeader.bcdVersion == MS_EXT_PROP_DESC_VER &&
  4986. msExtPropDescHeader.wIndex == MS_EXT_PROP_DESCRIPTOR_INDEX &&
  4987. msExtPropDescHeader.wCount > 0)
  4988. {
  4989. // Allocate a buffer large enough for the entire descriptor
  4990. //
  4991. pMsExtPropDesc = UsbhExAllocatePool(NonPagedPool,
  4992. msExtPropDescHeader.dwLength);
  4993. if (pMsExtPropDesc)
  4994. {
  4995. RtlZeroMemory(pMsExtPropDesc, msExtPropDescHeader.dwLength);
  4996. // Request the entire MS Extended Property Descriptor
  4997. //
  4998. ntStatus = USBH_GetMsOsFeatureDescriptor(
  4999. DeviceObject,
  5000. 1, // Recipient Interface
  5001. 0, // Interface
  5002. MS_EXT_PROP_DESCRIPTOR_INDEX,
  5003. pMsExtPropDesc,
  5004. msExtPropDescHeader.dwLength,
  5005. &bytesReturned);
  5006. if (NT_SUCCESS(ntStatus) &&
  5007. bytesReturned == msExtPropDescHeader.dwLength &&
  5008. RtlCompareMemory(&msExtPropDescHeader,
  5009. pMsExtPropDesc,
  5010. sizeof(MS_EXT_PROP_DESC_HEADER)) ==
  5011. sizeof(MS_EXT_PROP_DESC_HEADER))
  5012. {
  5013. // MS Extended Property Descriptor retrieved ok, parse and
  5014. // install each Custom Property Section it contains.
  5015. //
  5016. USBH_InstallExtPropDescSections(DeviceObject,
  5017. pMsExtPropDesc);
  5018. }
  5019. // Done with the MS Extended Property Descriptor buffer, free it
  5020. //
  5021. UsbhExFreePool(pMsExtPropDesc);
  5022. }
  5023. }
  5024. }
  5025. VOID
  5026. USBH_InstallExtPropDescSections (
  5027. PDEVICE_OBJECT DeviceObject,
  5028. PMS_EXT_PROP_DESC pMsExtPropDesc
  5029. )
  5030. /*++
  5031. Routine Description:
  5032. This routines parses an Extended Properties Descriptor and validates each
  5033. Custom Property Section contained in the Extended Properties Descriptor.
  5034. If all of the Custom Property Sections appear valid then each Custom
  5035. Property section <ValueName, ValueData> pair is installed in the device
  5036. instance specific registry key for the PDO.
  5037. The registry value entries would be found under this registry key:
  5038. HKLM\System\CCS\Enum\<DeviceID>\<InstanceID>\Device Parameters
  5039. Arguments:
  5040. DeviceObject - The PDO
  5041. pMsExtPropDesc - Pointer to an Extended Properties Descriptor buffer.
  5042. It is assumed that the header of this descriptor has
  5043. already been validated.
  5044. Return Value:
  5045. None
  5046. --*/
  5047. {
  5048. PUCHAR p;
  5049. PUCHAR end;
  5050. ULONG pass;
  5051. ULONG i;
  5052. ULONG dwSize;
  5053. ULONG dwPropertyDataType;
  5054. USHORT wPropertyNameLength;
  5055. PWCHAR bPropertyName;
  5056. ULONG dwPropertyDataLength;
  5057. PVOID bPropertyData;
  5058. NTSTATUS ntStatus;
  5059. PAGED_CODE();
  5060. // Get a pointer to the end of the entire Extended Properties Descriptor
  5061. //
  5062. end = (PUCHAR)pMsExtPropDesc + pMsExtPropDesc->Header.dwLength;
  5063. // First pass: Validate each Custom Property Section
  5064. // Second pass: Install each Custom Property Section (if first pass ok)
  5065. //
  5066. for (pass = 0; pass < 2; pass++)
  5067. {
  5068. // Get a pointer to the first Custom Property Section
  5069. //
  5070. p = (PUCHAR)&pMsExtPropDesc->CustomSection[0];
  5071. // Iterate over all of the Custom Property Sections
  5072. //
  5073. for (i = 0; i < pMsExtPropDesc->Header.wCount; i++)
  5074. {
  5075. ULONG offset;
  5076. // Make sure the dwSize field is in bounds
  5077. //
  5078. if (p + sizeof(ULONG) > end)
  5079. {
  5080. break;
  5081. }
  5082. // Extract the dwSize field and advance running offset
  5083. //
  5084. dwSize = *((PULONG)p);
  5085. offset = sizeof(ULONG);
  5086. // Make sure the entire structure is in bounds
  5087. //
  5088. if (p + dwSize > end)
  5089. {
  5090. break;
  5091. }
  5092. // Make sure the dwPropertyDataType field is in bounds
  5093. if (dwSize < offset + sizeof(ULONG))
  5094. {
  5095. break;
  5096. }
  5097. // Extract the dwPropertyDataType field and advance running offset
  5098. //
  5099. dwPropertyDataType = *((PULONG)(p + offset));
  5100. offset += sizeof(ULONG);
  5101. // Make sure the wPropertyNameLength field is in bounds
  5102. //
  5103. if (dwSize < offset + sizeof(USHORT))
  5104. {
  5105. break;
  5106. }
  5107. // Extract the wPropertyNameLength field and advance running offset
  5108. //
  5109. wPropertyNameLength = *((PUSHORT)(p + offset));
  5110. offset += sizeof(USHORT);
  5111. // Make sure the bPropertyName field is in bounds
  5112. //
  5113. if (dwSize < offset + wPropertyNameLength)
  5114. {
  5115. break;
  5116. }
  5117. // Set the bPropertyName pointer and advance running offset
  5118. //
  5119. bPropertyName = (PWCHAR)(p + offset);
  5120. offset += wPropertyNameLength;
  5121. // Make sure the dwPropertyDataLength field is in bounds
  5122. if (dwSize < offset + sizeof(ULONG))
  5123. {
  5124. break;
  5125. }
  5126. // Extract the dwPropertyDataLength field and advance running offset
  5127. //
  5128. dwPropertyDataLength = *((ULONG UNALIGNED*)(p + offset));
  5129. offset += sizeof(ULONG);
  5130. // Make sure the bPropertyData field is in bounds
  5131. //
  5132. if (dwSize < offset + dwPropertyDataLength)
  5133. {
  5134. break;
  5135. }
  5136. // Set the bPropertyData pointer and advance running offset
  5137. //
  5138. bPropertyData = p + offset;
  5139. offset += wPropertyNameLength;
  5140. // Make sure the dwPropertyDataType is valid
  5141. //
  5142. if (dwPropertyDataType < REG_SZ ||
  5143. dwPropertyDataType > REG_MULTI_SZ)
  5144. {
  5145. break;
  5146. }
  5147. // Make sure the wPropertyNameLength is valid
  5148. //
  5149. if (wPropertyNameLength == 0 ||
  5150. (wPropertyNameLength % sizeof(WCHAR)) != 0)
  5151. {
  5152. break;
  5153. }
  5154. // Make sure bPropertyName is NULL terminated
  5155. //
  5156. if (bPropertyName[(wPropertyNameLength / sizeof(WCHAR)) - 1] !=
  5157. UNICODE_NULL)
  5158. {
  5159. break;
  5160. }
  5161. // Everything looks ok,
  5162. //
  5163. if (pass > 0)
  5164. {
  5165. ntStatus = USBH_SetPdoRegistryParameter(
  5166. DeviceObject,
  5167. bPropertyName,
  5168. wPropertyNameLength,
  5169. bPropertyData,
  5170. dwPropertyDataLength,
  5171. dwPropertyDataType,
  5172. PLUGPLAY_REGKEY_DEVICE);
  5173. }
  5174. }
  5175. // Skip the second pass if we bailed out of the first pass
  5176. //
  5177. if (i < pMsExtPropDesc->Header.wCount)
  5178. {
  5179. break;
  5180. }
  5181. }
  5182. }
  5183. PMS_EXT_CONFIG_DESC
  5184. USBH_GetExtConfigDesc (
  5185. IN PDEVICE_OBJECT DeviceObject
  5186. )
  5187. /*++
  5188. Routine Description:
  5189. This routines queries a device for an Extended Configuration Descriptor.
  5190. Arguments:
  5191. DeviceObject - The PDO
  5192. Return Value:
  5193. If successful, a pointer to the Extended Configuration Descriptor, which the
  5194. caller must free, else NULL.
  5195. --*/
  5196. {
  5197. MS_EXT_CONFIG_DESC_HEADER msExtConfigDescHeader;
  5198. PMS_EXT_CONFIG_DESC pMsExtConfigDesc;
  5199. ULONG bytesReturned;
  5200. NTSTATUS ntStatus;
  5201. PAGED_CODE();
  5202. pMsExtConfigDesc = NULL;
  5203. RtlZeroMemory(&msExtConfigDescHeader, sizeof(MS_EXT_CONFIG_DESC_HEADER));
  5204. // Request just the header of the MS Extended Configuration Descriptor
  5205. //
  5206. ntStatus = USBH_GetMsOsFeatureDescriptor(
  5207. DeviceObject,
  5208. 0, // Recipient Device
  5209. 0, // Interface
  5210. MS_EXT_CONFIG_DESCRIPTOR_INDEX,
  5211. &msExtConfigDescHeader,
  5212. sizeof(MS_EXT_CONFIG_DESC_HEADER),
  5213. &bytesReturned);
  5214. // Make sure the MS Extended Configuration Descriptor header looks ok
  5215. //
  5216. if (NT_SUCCESS(ntStatus) &&
  5217. bytesReturned == sizeof(MS_EXT_CONFIG_DESC_HEADER) &&
  5218. msExtConfigDescHeader.bcdVersion == MS_EXT_CONFIG_DESC_VER &&
  5219. msExtConfigDescHeader.wIndex == MS_EXT_CONFIG_DESCRIPTOR_INDEX &&
  5220. msExtConfigDescHeader.bCount > 0 &&
  5221. msExtConfigDescHeader.dwLength == sizeof(MS_EXT_CONFIG_DESC_HEADER) +
  5222. msExtConfigDescHeader.bCount * sizeof(MS_EXT_CONFIG_DESC_FUNCTION))
  5223. {
  5224. // Allocate a buffer large enough for the entire descriptor
  5225. //
  5226. pMsExtConfigDesc = UsbhExAllocatePool(NonPagedPool,
  5227. msExtConfigDescHeader.dwLength);
  5228. if (pMsExtConfigDesc)
  5229. {
  5230. RtlZeroMemory(pMsExtConfigDesc, msExtConfigDescHeader.dwLength);
  5231. // Request the entire MS Extended Configuration Descriptor
  5232. //
  5233. ntStatus = USBH_GetMsOsFeatureDescriptor(
  5234. DeviceObject,
  5235. 0, // Recipient Device
  5236. 0, // Interface
  5237. MS_EXT_CONFIG_DESCRIPTOR_INDEX,
  5238. pMsExtConfigDesc,
  5239. msExtConfigDescHeader.dwLength,
  5240. &bytesReturned);
  5241. if (!(NT_SUCCESS(ntStatus) &&
  5242. bytesReturned == msExtConfigDescHeader.dwLength &&
  5243. RtlCompareMemory(&msExtConfigDescHeader,
  5244. pMsExtConfigDesc,
  5245. sizeof(MS_EXT_CONFIG_DESC_HEADER)) ==
  5246. sizeof(MS_EXT_CONFIG_DESC_HEADER)))
  5247. {
  5248. // Something went wrong retrieving the MS Extended Configuration
  5249. // Descriptor. Free the buffer.
  5250. UsbhExFreePool(pMsExtConfigDesc);
  5251. pMsExtConfigDesc = NULL;
  5252. }
  5253. }
  5254. }
  5255. return pMsExtConfigDesc;
  5256. }
  5257. BOOLEAN
  5258. USBH_ValidateExtConfigDesc (
  5259. IN PMS_EXT_CONFIG_DESC MsExtConfigDesc,
  5260. IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
  5261. )
  5262. /*++
  5263. Routine Description:
  5264. This routines validates an Extended Configuration Descriptor.
  5265. Arguments:
  5266. MsExtConfigDesc - The Extended Configuration Descriptor to be validated.
  5267. It is assumed that the header of this descriptor has
  5268. already been validated.
  5269. ConfigurationDescriptor - Configuration Descriptor, assumed to already
  5270. validated.
  5271. Return Value:
  5272. TRUE if the Extended Configuration Descriptor appears to be valid,
  5273. else FALSE.
  5274. --*/
  5275. {
  5276. UCHAR interfacesRemaining;
  5277. ULONG i;
  5278. ULONG j;
  5279. UCHAR c;
  5280. BOOLEAN gotNull;
  5281. PAGED_CODE();
  5282. interfacesRemaining = ConfigurationDescriptor->bNumInterfaces;
  5283. for (i = 0; i < MsExtConfigDesc->Header.bCount; i++)
  5284. {
  5285. // Make sure that there is at least one interface in this function.
  5286. //
  5287. if (MsExtConfigDesc->Function[i].bInterfaceCount == 0)
  5288. {
  5289. return FALSE;
  5290. }
  5291. // Make sure that there are not too many interfaces in this function.
  5292. //
  5293. if (MsExtConfigDesc->Function[i].bInterfaceCount > interfacesRemaining)
  5294. {
  5295. return FALSE;
  5296. }
  5297. interfacesRemaining -= MsExtConfigDesc->Function[i].bInterfaceCount;
  5298. // Make sure the no interfaces were skipped between the interfaces
  5299. // of the previous function and the interfaces of this function.
  5300. //
  5301. if (i &&
  5302. MsExtConfigDesc->Function[i-1].bFirstInterfaceNumber +
  5303. MsExtConfigDesc->Function[i-1].bInterfaceCount !=
  5304. MsExtConfigDesc->Function[i].bFirstInterfaceNumber)
  5305. {
  5306. return FALSE;
  5307. }
  5308. // Make sure that the CompatibleID is valid.
  5309. // Valid characters are 'A' through 'Z', '0' through '9', and '_"
  5310. // and null padded to the the right end of the array, but not
  5311. // necessarily null terminated.
  5312. //
  5313. for (j = 0, gotNull = FALSE;
  5314. j < sizeof(MsExtConfigDesc->Function[i].CompatibleID);
  5315. j++)
  5316. {
  5317. c = MsExtConfigDesc->Function[i].CompatibleID[j];
  5318. if (c == 0)
  5319. {
  5320. gotNull = TRUE;
  5321. }
  5322. else
  5323. {
  5324. if (gotNull ||
  5325. !((c >= 'A' && c <= 'Z') ||
  5326. (c >= '0' && c <= '9') ||
  5327. (c == '_')))
  5328. {
  5329. return FALSE;
  5330. }
  5331. }
  5332. }
  5333. // Make sure that the SubCompatibleID is valid.
  5334. // Valid characters are 'A' through 'Z', '0' through '9', and '_"
  5335. // and null padded to the the right end of the array, but not
  5336. // necessarily null terminated.
  5337. //
  5338. for (j = 0, gotNull = FALSE;
  5339. j < sizeof(MsExtConfigDesc->Function[i].SubCompatibleID);
  5340. j++)
  5341. {
  5342. c = MsExtConfigDesc->Function[i].SubCompatibleID[j];
  5343. if (c == 0)
  5344. {
  5345. gotNull = TRUE;
  5346. }
  5347. else
  5348. {
  5349. if (gotNull ||
  5350. !((c >= 'A' && c <= 'Z') ||
  5351. (c >= '0' && c <= '9') ||
  5352. (c == '_')))
  5353. {
  5354. return FALSE;
  5355. }
  5356. }
  5357. }
  5358. // Make sure that if the SubCompatibleID is non-null then the
  5359. // CompatibleID is also non-null.
  5360. //
  5361. if (MsExtConfigDesc->Function[i].SubCompatibleID[0] != 0 &&
  5362. MsExtConfigDesc->Function[i].CompatibleID[0] == 0)
  5363. {
  5364. return FALSE;
  5365. }
  5366. }
  5367. // Make sure that all of the interfaces were consumed by functions.
  5368. //
  5369. if (interfacesRemaining > 0)
  5370. {
  5371. return FALSE;
  5372. }
  5373. return TRUE;
  5374. }
  5375. #endif