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.

1131 lines
32 KiB

  1. /*
  2. *************************************************************************
  3. * File: UTIL.C
  4. *
  5. * Module: USBCCGP.SYS
  6. * USB Common Class Generic Parent driver.
  7. *
  8. * Copyright (c) 1998 Microsoft Corporation
  9. *
  10. *
  11. * Author: ervinp
  12. *
  13. *************************************************************************
  14. */
  15. #include <wdm.h>
  16. #include <stdio.h>
  17. #include <usb.h>
  18. #include <usbdlib.h>
  19. #include <usbioctl.h>
  20. #include "usbccgp.h"
  21. #include "security.h"
  22. #include "debug.h"
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(PAGE, AppendInterfaceNumber)
  25. #pragma alloc_text(PAGE, CopyDeviceRelations)
  26. #pragma alloc_text(PAGE, GetFunctionInterfaceListBase)
  27. #pragma alloc_text(PAGE, CallDriverSync)
  28. #pragma alloc_text(PAGE, CallNextDriverSync)
  29. #pragma alloc_text(PAGE, SetPdoRegistryParameter)
  30. #pragma alloc_text(PAGE, GetPdoRegistryParameter)
  31. #pragma alloc_text(PAGE, GetMsOsFeatureDescriptor)
  32. #endif
  33. #define USB_REQUEST_TIMEOUT 5000 // Timeout in ms (5 sec)
  34. NTSTATUS CallNextDriverSync(PPARENT_FDO_EXT parentFdoExt, PIRP irp)
  35. /*++
  36. Routine Description:
  37. Pass the IRP down to the next device object in the stack
  38. synchronously, and bump the pendingActionCount around
  39. the call to prevent the current device object from getting
  40. removed before the IRP completes.
  41. Arguments:
  42. parentFdoExt - device extension of one of our device objects
  43. irp - Io Request Packet
  44. Return Value:
  45. NT status code, indicates result returned by lower driver for this IRP.
  46. --*/
  47. {
  48. NTSTATUS status;
  49. PAGED_CODE();
  50. IncrementPendingActionCount(parentFdoExt);
  51. status = CallDriverSync(parentFdoExt->topDevObj, irp);
  52. DecrementPendingActionCount(parentFdoExt);
  53. return status;
  54. }
  55. VOID IncrementPendingActionCount(PPARENT_FDO_EXT parentFdoExt)
  56. /*++
  57. Routine Description:
  58. Increment the pendingActionCount for a device object.
  59. This keeps the device object from getting freed before
  60. the action is completed.
  61. Arguments:
  62. devExt - device extension of device object
  63. Return Value:
  64. VOID
  65. --*/
  66. {
  67. ASSERT(parentFdoExt->pendingActionCount >= 0);
  68. InterlockedIncrement(&parentFdoExt->pendingActionCount);
  69. }
  70. VOID DecrementPendingActionCount(PPARENT_FDO_EXT parentFdoExt)
  71. /*++
  72. Routine Description:
  73. Decrement the pendingActionCount for a device object.
  74. This is called when an asynchronous action is completed
  75. AND ALSO when we get the REMOVE_DEVICE IRP.
  76. If the pendingActionCount goes to -1, that means that all
  77. actions are completed and we've gotten the REMOVE_DEVICE IRP;
  78. in this case, set the removeEvent event so we can finish
  79. unloading.
  80. Arguments:
  81. devExt - device extension of device object
  82. Return Value:
  83. VOID
  84. --*/
  85. {
  86. ASSERT(parentFdoExt->pendingActionCount >= 0);
  87. InterlockedDecrement(&parentFdoExt->pendingActionCount);
  88. if (parentFdoExt->pendingActionCount < 0){
  89. /*
  90. * All pending actions have completed and we've gotten
  91. * the REMOVE_DEVICE IRP.
  92. * Set the removeEvent so we'll stop waiting on REMOVE_DEVICE.
  93. */
  94. ASSERT((parentFdoExt->state == STATE_REMOVING) ||
  95. (parentFdoExt->state == STATE_REMOVED));
  96. KeSetEvent(&parentFdoExt->removeEvent, 0, FALSE);
  97. }
  98. }
  99. /*
  100. ********************************************************************************
  101. * CallDriverSyncCompletion
  102. ********************************************************************************
  103. *
  104. *
  105. */
  106. NTSTATUS CallDriverSyncCompletion(IN PDEVICE_OBJECT devObjOrNULL, IN PIRP irp, IN PVOID Context)
  107. /*++
  108. Routine Description:
  109. Completion routine for CallDriverSync.
  110. Arguments:
  111. devObjOrNULL -
  112. Usually, this is this driver's device object.
  113. However, if this driver created the IRP,
  114. there is no stack location in the IRP for this driver;
  115. so the kernel has no place to store the device object;
  116. ** so devObj will be NULL in this case **.
  117. irp - completed Io Request Packet
  118. context - context passed to IoSetCompletionRoutine by CallDriverSync.
  119. Return Value:
  120. NT status code, indicates result returned by lower driver for this IRP.
  121. --*/
  122. {
  123. PUSB_REQUEST_TIMEOUT_CONTEXT timeoutContext = Context;
  124. PKEVENT event = timeoutContext->event;
  125. PLONG lock = timeoutContext->lock;
  126. ASSERT(irp->IoStatus.Status != STATUS_IO_TIMEOUT);
  127. KeSetEvent(event, 0, FALSE);
  128. InterlockedExchange(lock, 3);
  129. return STATUS_MORE_PROCESSING_REQUIRED;
  130. }
  131. NTSTATUS CallDriverSync(IN PDEVICE_OBJECT devObj, IN OUT PIRP irp)
  132. /*++
  133. Routine Description:
  134. Call IoCallDriver to send the irp to the device object;
  135. then, synchronize with the completion routine.
  136. When CallDriverSync returns, the action has completed
  137. and the irp again belongs to the current driver.
  138. NOTE: In order to keep the device object from getting freed
  139. while this IRP is pending, you should call
  140. IncrementPendingActionCount() and
  141. DecrementPendingActionCount()
  142. around the CallDriverSync call.
  143. Arguments:
  144. devObj - targetted device object
  145. irp - Io Request Packet
  146. Return Value:
  147. NT status code, indicates result returned by lower driver for this IRP.
  148. --*/
  149. {
  150. PUSB_REQUEST_TIMEOUT_CONTEXT timeoutContext;
  151. KEVENT event;
  152. LONG lock;
  153. LARGE_INTEGER dueTime;
  154. PIO_STACK_LOCATION irpStack;
  155. ULONG majorFunction;
  156. ULONG minorFunction;
  157. NTSTATUS status;
  158. PAGED_CODE();
  159. irpStack = IoGetNextIrpStackLocation(irp);
  160. majorFunction = irpStack->MajorFunction;
  161. minorFunction = irpStack->MinorFunction;
  162. KeInitializeEvent(&event, NotificationEvent, FALSE);
  163. lock = 0;
  164. timeoutContext = ALLOCPOOL(NonPagedPool, sizeof(USB_REQUEST_TIMEOUT_CONTEXT));
  165. if (timeoutContext) {
  166. timeoutContext->event = &event;
  167. timeoutContext->lock = &lock;
  168. IoSetCompletionRoutine( irp,
  169. CallDriverSyncCompletion, // context
  170. timeoutContext,
  171. TRUE, TRUE, TRUE);
  172. status = IoCallDriver(devObj, irp);
  173. if (status == STATUS_PENDING) {
  174. dueTime.QuadPart = -10000 * USB_REQUEST_TIMEOUT;
  175. status = KeWaitForSingleObject(
  176. &event,
  177. Executive, // wait reason
  178. KernelMode,
  179. FALSE, // not alertable
  180. &dueTime);
  181. if (status == STATUS_TIMEOUT) {
  182. DBGWARN(("CallDriverSync timed out!\n"));
  183. if (InterlockedExchange(&lock, 1) == 0) {
  184. //
  185. // We got it to the IRP before it was completed. We can cancel
  186. // the IRP without fear of losing it, as the completion routine
  187. // won't let go of the IRP until we say so.
  188. //
  189. IoCancelIrp(irp);
  190. //
  191. // Release the completion routine. If it already got there,
  192. // then we need to complete it ourselves. Otherwise we got
  193. // through IoCancelIrp before the IRP completed entirely.
  194. //
  195. if (InterlockedExchange(&lock, 2) == 3) {
  196. //
  197. // Mark it pending because we switched threads.
  198. //
  199. IoMarkIrpPending(irp);
  200. IoCompleteRequest(irp, IO_NO_INCREMENT);
  201. }
  202. }
  203. KeWaitForSingleObject(&event, Executive, KernelMode, FALSE, NULL);
  204. // Return an error code because STATUS_TIMEOUT is a successful
  205. // code.
  206. irp->IoStatus.Status = STATUS_DEVICE_DATA_ERROR;
  207. }
  208. }
  209. FREEPOOL(timeoutContext);
  210. status = irp->IoStatus.Status;
  211. } else {
  212. status = STATUS_INSUFFICIENT_RESOURCES;
  213. }
  214. if (!NT_SUCCESS(status)){
  215. DBGVERBOSE(("IRP 0x%02X/0x%02X failed in CallDriverSync w/ status %xh.",
  216. majorFunction, minorFunction, status));
  217. }
  218. return status;
  219. }
  220. /*
  221. ********************************************************************************
  222. * AppendInterfaceNumber
  223. ********************************************************************************
  224. *
  225. * oldIDs is a multi-String of hardware IDs.
  226. * Return a new string with '&MI_xx' appended to each id,
  227. * where 'xx' is the interface number of the first interface in that function.
  228. */
  229. PWCHAR AppendInterfaceNumber(PWCHAR oldIDs, ULONG interfaceNum)
  230. {
  231. ULONG newIdLen;
  232. PWCHAR id, newIDs;
  233. WCHAR suffix[] = L"&MI_xx";
  234. PAGED_CODE();
  235. /*
  236. * Calculate the length of the final multi-string.
  237. */
  238. for (id = oldIDs, newIdLen = 0; *id; ){
  239. ULONG thisIdLen = WStrLen(id);
  240. newIdLen += thisIdLen + 1 + sizeof(suffix);
  241. id += thisIdLen + 1;
  242. }
  243. /*
  244. * Add one for the extra NULL at the end of the multi-string.
  245. */
  246. newIdLen++;
  247. newIDs = ALLOCPOOL(NonPagedPool, newIdLen*sizeof(WCHAR));
  248. if (newIDs){
  249. ULONG oldIdOff, newIdOff;
  250. /*
  251. * Copy each string in the multi-string, replacing the bus name.
  252. */
  253. for (oldIdOff = newIdOff = 0; oldIDs[oldIdOff]; ){
  254. ULONG thisIdLen = WStrLen(oldIDs+oldIdOff);
  255. swprintf(suffix, L"&MI_%02x", interfaceNum);
  256. /*
  257. * Copy the new bus name to the new string.
  258. */
  259. newIdOff += WStrCpy(newIDs+newIdOff, oldIDs+oldIdOff);
  260. newIdOff += WStrCpy(newIDs+newIdOff, (PWSTR)suffix) + 1;
  261. oldIdOff += thisIdLen + 1;
  262. }
  263. /*
  264. * Add extra NULL to terminate multi-string.
  265. */
  266. newIDs[newIdOff] = UNICODE_NULL;
  267. }
  268. return newIDs;
  269. }
  270. /*
  271. ********************************************************************************
  272. * CopyDeviceRelations
  273. ********************************************************************************
  274. *
  275. *
  276. */
  277. PDEVICE_RELATIONS CopyDeviceRelations(PDEVICE_RELATIONS deviceRelations)
  278. {
  279. PDEVICE_RELATIONS newDeviceRelations;
  280. PAGED_CODE();
  281. if (deviceRelations){
  282. ULONG size = sizeof(DEVICE_RELATIONS) + (deviceRelations->Count*sizeof(PDEVICE_OBJECT));
  283. newDeviceRelations = MemDup(deviceRelations, size);
  284. }
  285. else {
  286. newDeviceRelations = NULL;
  287. }
  288. return newDeviceRelations;
  289. }
  290. PUSBD_INTERFACE_LIST_ENTRY GetFunctionInterfaceListBase(
  291. PPARENT_FDO_EXT parentFdoExt,
  292. ULONG functionIndex,
  293. PULONG numFunctionInterfaces)
  294. {
  295. PUSBD_INTERFACE_LIST_ENTRY iface = NULL;
  296. PUSB_CONFIGURATION_DESCRIPTOR configDesc;
  297. ULONG i, func;
  298. UCHAR ifaceClass;
  299. ULONG audFuncBaseIndex = -1;
  300. PAGED_CODE();
  301. configDesc = parentFdoExt->selectedConfigDesc;
  302. ASSERT(configDesc->bNumInterfaces);
  303. for (func = 0, i = 0; i < (ULONG)configDesc->bNumInterfaces-1; i++){
  304. ifaceClass = parentFdoExt->interfaceList[i].InterfaceDescriptor->bInterfaceClass;
  305. if (ifaceClass == USB_DEVICE_CLASS_CONTENT_SECURITY){
  306. /*
  307. * We don't expose the CS interface(s).
  308. */
  309. continue;
  310. }
  311. if (func == functionIndex){
  312. break;
  313. }
  314. switch (ifaceClass){
  315. case USB_DEVICE_CLASS_AUDIO:
  316. /*
  317. * For USB_DEVICE_CLASS_AUDIO, we return groups of interfaces
  318. * with common class as functions.
  319. *
  320. * BUT, only while the interface subclass is different than the
  321. * first one in this grouping. If the subclass is the same,
  322. * then this is a different function.
  323. * Note that it is conceivable that a device could be created
  324. * where a second audio function starts with an interface with
  325. * a different subclass than the previous audio interface, but
  326. * this is how USBHUB's generic parent driver works and thus we
  327. * are bug-compatible with the older driver.
  328. */
  329. if (audFuncBaseIndex == -1){
  330. audFuncBaseIndex = i;
  331. }
  332. if ((parentFdoExt->interfaceList[i+1].InterfaceDescriptor->bInterfaceClass !=
  333. USB_DEVICE_CLASS_AUDIO) ||
  334. (parentFdoExt->interfaceList[audFuncBaseIndex].InterfaceDescriptor->bInterfaceSubClass ==
  335. parentFdoExt->interfaceList[i+1].InterfaceDescriptor->bInterfaceSubClass)) {
  336. func++;
  337. audFuncBaseIndex = -1; // Reset base index for next audio function.
  338. }
  339. break;
  340. default:
  341. audFuncBaseIndex = -1; // Reset base index for next audio function.
  342. /*
  343. * For other classes, each interface is a function.
  344. * Count alternate interfaces as part of the same function.
  345. */
  346. ASSERT(parentFdoExt->interfaceList[i+1].InterfaceDescriptor->bAlternateSetting == 0);
  347. if (parentFdoExt->interfaceList[i+1].InterfaceDescriptor->bAlternateSetting == 0){
  348. func++;
  349. }
  350. break;
  351. }
  352. }
  353. // note: need this redundant check outside in case bNumInterfaces == 1
  354. if (func == functionIndex){
  355. iface = &parentFdoExt->interfaceList[i];
  356. ifaceClass = iface->InterfaceDescriptor->bInterfaceClass;
  357. *numFunctionInterfaces = 1;
  358. if (ifaceClass == USB_DEVICE_CLASS_CONTENT_SECURITY){
  359. /*
  360. * The CS interface was the last interface on the device.
  361. * Don't return it as a function.
  362. */
  363. iface = NULL;
  364. }
  365. else if (ifaceClass == USB_DEVICE_CLASS_AUDIO){
  366. for (i = i + 1; i < (ULONG)configDesc->bNumInterfaces; i++){
  367. if ((parentFdoExt->interfaceList[i].InterfaceDescriptor->bInterfaceClass ==
  368. iface->InterfaceDescriptor->bInterfaceClass) &&
  369. (parentFdoExt->interfaceList[i].InterfaceDescriptor->bInterfaceSubClass !=
  370. iface->InterfaceDescriptor->bInterfaceSubClass)){
  371. (*numFunctionInterfaces)++;
  372. }
  373. else {
  374. break;
  375. }
  376. }
  377. }
  378. }
  379. else {
  380. *numFunctionInterfaces = 0;
  381. }
  382. return iface;
  383. }
  384. /*
  385. ********************************************************************************
  386. * GetStringDescriptor
  387. ********************************************************************************
  388. *
  389. *
  390. *
  391. */
  392. NTSTATUS GetStringDescriptor( PPARENT_FDO_EXT parentFdoExt,
  393. UCHAR stringIndex,
  394. LANGID langId,
  395. PUSB_STRING_DESCRIPTOR stringDesc,
  396. ULONG bufferLen)
  397. {
  398. NTSTATUS status;
  399. URB urb;
  400. UsbBuildGetDescriptorRequest(&urb,
  401. (USHORT)sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST),
  402. USB_STRING_DESCRIPTOR_TYPE,
  403. stringIndex,
  404. langId,
  405. stringDesc,
  406. NULL,
  407. bufferLen,
  408. NULL);
  409. status = SubmitUrb(parentFdoExt, &urb, TRUE, NULL, NULL);
  410. return status;
  411. }
  412. /*
  413. ********************************************************************************
  414. * SetPdoRegistryParameter
  415. ********************************************************************************
  416. *
  417. *
  418. *
  419. */
  420. NTSTATUS SetPdoRegistryParameter (
  421. IN PDEVICE_OBJECT PhysicalDeviceObject,
  422. IN PWCHAR KeyName,
  423. IN PVOID Data,
  424. IN ULONG DataLength,
  425. IN ULONG KeyType,
  426. IN ULONG DevInstKeyType
  427. )
  428. {
  429. UNICODE_STRING keyNameUnicodeString;
  430. HANDLE handle;
  431. NTSTATUS ntStatus;
  432. PAGED_CODE();
  433. RtlInitUnicodeString(&keyNameUnicodeString, KeyName);
  434. ntStatus = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  435. DevInstKeyType,
  436. STANDARD_RIGHTS_ALL,
  437. &handle);
  438. if (NT_SUCCESS(ntStatus))
  439. {
  440. ntStatus = ZwSetValueKey(handle,
  441. &keyNameUnicodeString,
  442. 0,
  443. KeyType,
  444. Data,
  445. DataLength);
  446. ZwClose(handle);
  447. }
  448. DBGVERBOSE(("SetPdoRegistryParameter status 0x%x\n", ntStatus));
  449. return ntStatus;
  450. }
  451. /*
  452. ********************************************************************************
  453. * GetPdoRegistryParameter
  454. ********************************************************************************
  455. *
  456. *
  457. *
  458. */
  459. NTSTATUS GetPdoRegistryParameter (
  460. IN PDEVICE_OBJECT PhysicalDeviceObject,
  461. IN PWCHAR ValueName,
  462. OUT PVOID Data,
  463. IN ULONG DataLength,
  464. OUT PULONG Type,
  465. OUT PULONG ActualDataLength
  466. )
  467. /*++
  468. Routine Description:
  469. This routines queries the data for a registry value entry associated
  470. with the device instance specific registry key for the PDO.
  471. The registry value entry would be found under this registry key:
  472. HKLM\System\CCS\Enum\<DeviceID>\<InstanceID>\Device Parameters
  473. Arguments:
  474. PhysicalDeviceObject - Yep, the PDO
  475. ValueName - Name of the registry value entry for which the data is requested
  476. Data - Buffer in which the requested data is returned
  477. DataLength - Length of the data buffer
  478. Type - (optional) The data type (e.g. REG_SZ, REG_DWORD) is returned here
  479. ActualDataLength - (optional) The actual length of the data is returned here
  480. If this is larger than DataLength then not all of the
  481. value data has been returned.
  482. Return Value:
  483. --*/
  484. {
  485. HANDLE handle;
  486. NTSTATUS ntStatus;
  487. PAGED_CODE();
  488. ntStatus = IoOpenDeviceRegistryKey(PhysicalDeviceObject,
  489. PLUGPLAY_REGKEY_DEVICE,
  490. STANDARD_RIGHTS_ALL,
  491. &handle);
  492. if (NT_SUCCESS(ntStatus))
  493. {
  494. PKEY_VALUE_PARTIAL_INFORMATION partialInfo;
  495. UNICODE_STRING valueName;
  496. ULONG length;
  497. ULONG resultLength;
  498. RtlInitUnicodeString(&valueName, ValueName);
  499. // Size and allocate a KEY_VALUE_PARTIAL_INFORMATION structure,
  500. // including room for the returned value data.
  501. //
  502. length = FIELD_OFFSET(KEY_VALUE_PARTIAL_INFORMATION, Data) +
  503. DataLength;
  504. partialInfo = ALLOCPOOL(PagedPool, length);
  505. if (partialInfo)
  506. {
  507. // Query the value data.
  508. //
  509. ntStatus = ZwQueryValueKey(handle,
  510. &valueName,
  511. KeyValuePartialInformation,
  512. partialInfo,
  513. length,
  514. &resultLength);
  515. // If we got any data that is good enough
  516. //
  517. if (ntStatus == STATUS_BUFFER_OVERFLOW)
  518. {
  519. ntStatus = STATUS_SUCCESS;
  520. }
  521. if (NT_SUCCESS(ntStatus))
  522. {
  523. // Only copy the smaller of the the requested data length or
  524. // the actual data length.
  525. //
  526. RtlCopyMemory(Data,
  527. partialInfo->Data,
  528. DataLength < partialInfo->DataLength ?
  529. DataLength :
  530. partialInfo->DataLength);
  531. // Return the value data type and actual length, if requested.
  532. //
  533. if (Type)
  534. {
  535. *Type = partialInfo->Type;
  536. }
  537. if (ActualDataLength)
  538. {
  539. *ActualDataLength = partialInfo->DataLength;
  540. }
  541. }
  542. FREEPOOL(partialInfo);
  543. }
  544. else
  545. {
  546. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  547. }
  548. ZwClose(handle);
  549. }
  550. return ntStatus;
  551. }
  552. /*
  553. ********************************************************************************
  554. * GetMsOsFeatureDescriptor
  555. ********************************************************************************
  556. *
  557. *
  558. *
  559. */
  560. NTSTATUS GetMsOsFeatureDescriptor (
  561. PPARENT_FDO_EXT ParentFdoExt,
  562. UCHAR Recipient,
  563. UCHAR InterfaceNumber,
  564. USHORT Index,
  565. PVOID DataBuffer,
  566. ULONG DataBufferLength,
  567. PULONG BytesReturned
  568. )
  569. {
  570. struct _URB_OS_FEATURE_DESCRIPTOR_REQUEST *urb;
  571. NTSTATUS ntStatus;
  572. PAGED_CODE();
  573. if (BytesReturned)
  574. {
  575. *BytesReturned = 0;
  576. }
  577. urb = ALLOCPOOL(NonPagedPool, sizeof(struct _URB_OS_FEATURE_DESCRIPTOR_REQUEST));
  578. if (urb != NULL)
  579. {
  580. // Initialize the URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR request
  581. //
  582. RtlZeroMemory(urb, sizeof(struct _URB_OS_FEATURE_DESCRIPTOR_REQUEST));
  583. urb->Hdr.Function = URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR;
  584. urb->Hdr.Length = sizeof(struct _URB_OS_FEATURE_DESCRIPTOR_REQUEST);
  585. urb->TransferBufferLength = DataBufferLength;
  586. urb->TransferBuffer = DataBuffer;
  587. urb->Recipient = Recipient;
  588. urb->InterfaceNumber = InterfaceNumber;
  589. urb->MS_FeatureDescriptorIndex = Index;
  590. // Submit the URB_FUNCTION_GET_MS_FEATURE_DESCRIPTOR request
  591. //
  592. ntStatus = SubmitUrb(ParentFdoExt, (PURB)urb, TRUE, NULL, NULL);
  593. if (NT_SUCCESS(ntStatus) &&
  594. BytesReturned)
  595. {
  596. *BytesReturned = urb->TransferBufferLength;
  597. }
  598. FREEPOOL(urb);
  599. }
  600. else
  601. {
  602. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  603. }
  604. return ntStatus;
  605. }
  606. /*
  607. ********************************************************************************
  608. * GetMsExtendedConfigDescriptor
  609. ********************************************************************************
  610. *
  611. *
  612. *
  613. */
  614. NTSTATUS
  615. GetMsExtendedConfigDescriptor (
  616. IN PPARENT_FDO_EXT ParentFdoExt
  617. )
  618. /*++
  619. Routine Description:
  620. This routines queries a device for an Extended Configuration Descriptor.
  621. Arguments:
  622. ParentFdoExt - The device extension of the parent FDO
  623. Return Value:
  624. If successful, a pointer to the Extended Configuration Descriptor, which the
  625. caller must free, else NULL.
  626. --*/
  627. {
  628. MS_EXT_CONFIG_DESC_HEADER msExtConfigDescHeader;
  629. PMS_EXT_CONFIG_DESC pMsExtConfigDesc;
  630. ULONG bytesReturned;
  631. NTSTATUS ntStatus;
  632. PAGED_CODE();
  633. ntStatus = STATUS_NOT_SUPPORTED;
  634. pMsExtConfigDesc = NULL;
  635. RtlZeroMemory(&msExtConfigDescHeader, sizeof(MS_EXT_CONFIG_DESC_HEADER));
  636. // Request just the header of the MS Extended Configuration Descriptor
  637. //
  638. ntStatus = GetMsOsFeatureDescriptor(
  639. ParentFdoExt,
  640. 0, // Recipient Device
  641. 0, // Interface
  642. MS_EXT_CONFIG_DESCRIPTOR_INDEX,
  643. &msExtConfigDescHeader,
  644. sizeof(MS_EXT_CONFIG_DESC_HEADER),
  645. &bytesReturned);
  646. // Make sure the MS Extended Configuration Descriptor header looks ok
  647. //
  648. if (NT_SUCCESS(ntStatus) &&
  649. bytesReturned == sizeof(MS_EXT_CONFIG_DESC_HEADER) &&
  650. msExtConfigDescHeader.bcdVersion == MS_EXT_CONFIG_DESC_VER &&
  651. msExtConfigDescHeader.wIndex == MS_EXT_CONFIG_DESCRIPTOR_INDEX &&
  652. msExtConfigDescHeader.bCount > 0 &&
  653. msExtConfigDescHeader.dwLength == sizeof(MS_EXT_CONFIG_DESC_HEADER) +
  654. msExtConfigDescHeader.bCount * sizeof(MS_EXT_CONFIG_DESC_FUNCTION))
  655. {
  656. // Allocate a buffer large enough for the entire descriptor
  657. //
  658. pMsExtConfigDesc = ALLOCPOOL(NonPagedPool,
  659. msExtConfigDescHeader.dwLength);
  660. if (pMsExtConfigDesc)
  661. {
  662. RtlZeroMemory(pMsExtConfigDesc, msExtConfigDescHeader.dwLength);
  663. // Request the entire MS Extended Configuration Descriptor
  664. //
  665. ntStatus = GetMsOsFeatureDescriptor(
  666. ParentFdoExt,
  667. 0, // Recipient Device
  668. 0, // Interface
  669. MS_EXT_CONFIG_DESCRIPTOR_INDEX,
  670. pMsExtConfigDesc,
  671. msExtConfigDescHeader.dwLength,
  672. &bytesReturned);
  673. if (!( NT_SUCCESS(ntStatus) &&
  674. bytesReturned == msExtConfigDescHeader.dwLength &&
  675. RtlCompareMemory(&msExtConfigDescHeader,
  676. pMsExtConfigDesc,
  677. sizeof(MS_EXT_CONFIG_DESC_HEADER)) ==
  678. sizeof(MS_EXT_CONFIG_DESC_HEADER) &&
  679. ValidateMsExtendedConfigDescriptor(
  680. pMsExtConfigDesc,
  681. ParentFdoExt->selectedConfigDesc) ))
  682. {
  683. // Something went wrong retrieving the MS Extended Configuration
  684. // Descriptor, or it doesn't look valid. Free the buffer.
  685. //
  686. FREEPOOL(pMsExtConfigDesc);
  687. pMsExtConfigDesc = NULL;
  688. }
  689. else
  690. {
  691. ntStatus = STATUS_SUCCESS;
  692. }
  693. }
  694. else
  695. {
  696. ntStatus = STATUS_INSUFFICIENT_RESOURCES;
  697. }
  698. }
  699. ASSERT(!ISPTR(ParentFdoExt->msExtConfigDesc));
  700. ParentFdoExt->msExtConfigDesc = pMsExtConfigDesc;
  701. return ntStatus;
  702. }
  703. /*
  704. ********************************************************************************
  705. * ValidateMsExtendedConfigDescriptor
  706. ********************************************************************************
  707. *
  708. *
  709. *
  710. */
  711. BOOLEAN
  712. ValidateMsExtendedConfigDescriptor (
  713. IN PMS_EXT_CONFIG_DESC MsExtConfigDesc,
  714. IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
  715. )
  716. /*++
  717. Routine Description:
  718. This routines validates an Extended Configuration Descriptor.
  719. Arguments:
  720. MsExtConfigDesc - The Extended Configuration Descriptor to be validated.
  721. It is assumed that the header of this descriptor has
  722. already been validated.
  723. ConfigurationDescriptor - Configuration Descriptor, assumed to already
  724. validated.
  725. Return Value:
  726. TRUE if the Extended Configuration Descriptor appears to be valid,
  727. else FALSE.
  728. --*/
  729. {
  730. UCHAR interfacesRemaining;
  731. ULONG i;
  732. ULONG j;
  733. UCHAR c;
  734. BOOLEAN gotNull;
  735. PAGED_CODE();
  736. interfacesRemaining = ConfigurationDescriptor->bNumInterfaces;
  737. for (i = 0; i < MsExtConfigDesc->Header.bCount; i++)
  738. {
  739. // Make sure that there is at least one interface in this function.
  740. //
  741. if (MsExtConfigDesc->Function[i].bInterfaceCount == 0)
  742. {
  743. return FALSE;
  744. }
  745. // Make sure that there are not too many interfaces in this function.
  746. //
  747. if (MsExtConfigDesc->Function[i].bInterfaceCount > interfacesRemaining)
  748. {
  749. return FALSE;
  750. }
  751. interfacesRemaining -= MsExtConfigDesc->Function[i].bInterfaceCount;
  752. // Make sure the no interfaces were skipped between the interfaces
  753. // of the previous function and the interfaces of this function.
  754. //
  755. if (i &&
  756. MsExtConfigDesc->Function[i-1].bFirstInterfaceNumber +
  757. MsExtConfigDesc->Function[i-1].bInterfaceCount !=
  758. MsExtConfigDesc->Function[i].bFirstInterfaceNumber)
  759. {
  760. return FALSE;
  761. }
  762. // Make sure that the CompatibleID is valid.
  763. // Valid characters are 'A' through 'Z', '0' through '9', and '_"
  764. // and null padded to the the right end of the array, but not
  765. // necessarily null terminated.
  766. //
  767. for (j = 0, gotNull = FALSE;
  768. j < sizeof(MsExtConfigDesc->Function[i].CompatibleID);
  769. j++)
  770. {
  771. c = MsExtConfigDesc->Function[i].CompatibleID[j];
  772. if (c == 0)
  773. {
  774. gotNull = TRUE;
  775. }
  776. else
  777. {
  778. if (gotNull ||
  779. !((c >= 'A' && c <= 'Z') ||
  780. (c >= '0' && c <= '9') ||
  781. (c == '_')))
  782. {
  783. return FALSE;
  784. }
  785. }
  786. }
  787. // Make sure that the SubCompatibleID is valid.
  788. // Valid characters are 'A' through 'Z', '0' through '9', and '_"
  789. // and null padded to the the right end of the array, but not
  790. // necessarily null terminated.
  791. //
  792. for (j = 0, gotNull = FALSE;
  793. j < sizeof(MsExtConfigDesc->Function[i].SubCompatibleID);
  794. j++)
  795. {
  796. c = MsExtConfigDesc->Function[i].SubCompatibleID[j];
  797. if (c == 0)
  798. {
  799. gotNull = TRUE;
  800. }
  801. else
  802. {
  803. if (gotNull ||
  804. !((c >= 'A' && c <= 'Z') ||
  805. (c >= '0' && c <= '9') ||
  806. (c == '_')))
  807. {
  808. return FALSE;
  809. }
  810. }
  811. }
  812. // Make sure that if the SubCompatibleID is non-null then the
  813. // CompatibleID is also non-null.
  814. //
  815. if (MsExtConfigDesc->Function[i].SubCompatibleID[0] != 0 &&
  816. MsExtConfigDesc->Function[i].CompatibleID[0] == 0)
  817. {
  818. return FALSE;
  819. }
  820. }
  821. // Make sure that all of the interfaces were consumed by functions.
  822. //
  823. if (interfacesRemaining > 0)
  824. {
  825. return FALSE;
  826. }
  827. return TRUE;
  828. }
  829. /*
  830. ********************************************************************************
  831. * MemDup
  832. ********************************************************************************
  833. *
  834. * Return a fresh copy of the argument.
  835. *
  836. */
  837. PVOID MemDup(PVOID dataPtr, ULONG length)
  838. {
  839. PVOID newPtr;
  840. newPtr = (PVOID)ALLOCPOOL(NonPagedPool, length);
  841. if (newPtr){
  842. RtlCopyMemory(newPtr, dataPtr, length);
  843. }
  844. else {
  845. DBGWARN(("MemDup: Memory allocation (size %xh) failed -- not a bug if verifier pool failures enabled.", length));
  846. }
  847. return newPtr;
  848. }
  849. /*
  850. ********************************************************************************
  851. * WStrLen
  852. ********************************************************************************
  853. *
  854. */
  855. ULONG WStrLen(PWCHAR str)
  856. {
  857. ULONG result = 0;
  858. while (*str++ != UNICODE_NULL){
  859. result++;
  860. }
  861. return result;
  862. }
  863. /*
  864. ********************************************************************************
  865. * WStrCpy
  866. ********************************************************************************
  867. *
  868. */
  869. ULONG WStrCpy(PWCHAR dest, PWCHAR src)
  870. {
  871. ULONG result = 0;
  872. while (*dest++ = *src++){
  873. result++;
  874. }
  875. return result;
  876. }
  877. BOOLEAN WStrCompareN(PWCHAR str1, PWCHAR str2, ULONG maxChars)
  878. {
  879. while ((maxChars > 0) && *str1 && (*str1 == *str2)){
  880. maxChars--;
  881. str1++;
  882. str2++;
  883. }
  884. return (BOOLEAN)((maxChars == 0) || (!*str1 && !*str2));
  885. }