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

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