/* ++ Copyright (c) 1999-2000 Microsoft Corporation Module Name: USBUTILS.C Abstract: USB configuration utility functions. These functions are called in the context of PNP_START_DEVICE. In order to mark them pageable we don't use a spinlock, which is OK because of the context. We do not use look-aside lists to manage pool allocs here since they are one-shot. If the allocs fail then the load will fail. Environment: kernel mode only Revision History: 07-14-99 : created Authors: Jeff Midkiff (jeffmi) -- */ #include #include #include #include #include #include #include "wceusbsh.h" NTSTATUS UsbSelectInterface( IN PDEVICE_OBJECT PDevObj, IN PUSB_CONFIGURATION_DESCRIPTOR PConfigDesc, IN UCHAR AlternateSetting ); #ifdef ALLOC_PRAGMA #pragma alloc_text(PAGEWCE1, UsbGetDeviceDescriptor) #pragma alloc_text(PAGEWCE1, UsbSelectInterface) #pragma alloc_text(PAGEWCE1, UsbConfigureDevice) #endif /* Sample dump for the Anchor EZ-Link (AN2720) cable: WCEUSBSH(0): DeviceDescriptor: fbfa8fe8 WCEUSBSH(0): Length 12 WCEUSBSH(0): WCEUSBSH(0): Device Descriptor WCEUSBSH(0): ------------------------ WCEUSBSH(0): bLength 12 WCEUSBSH(0): bDescriptorType 1 WCEUSBSH(0): bcdUSB 100 WCEUSBSH(0): bDeviceClass ff WCEUSBSH(0): bDeviceSubClass ff WCEUSBSH(0): bDeviceProtocol ff WCEUSBSH(0): bMaxPacketSize0 8 WCEUSBSH(0): idVendor 547 WCEUSBSH(0): idProduct 2720 WCEUSBSH(0): bcdDevice 0 WCEUSBSH(0): iManufacturer 0 WCEUSBSH(0): iProduct 0 WCEUSBSH(0): iSerialNumber 0 WCEUSBSH(0): bNumConfigs 1 WCEUSBSH(0): ------------------------ WCEUSBSH(0): WCEUSBSH(0): Configuration Descriptor WCEUSBSH(0): ---------------- WCEUSBSH(0): bLength 9 WCEUSBSH(0): bDescriptorType 2 WCEUSBSH(0): wTotalLength d0 WCEUSBSH(0): bNumInterfaces 1 WCEUSBSH(0): bConfigurationValue 1 WCEUSBSH(0): iConfiguration 0 WCEUSBSH(0): bmAttributes a0 WCEUSBSH(0): MaxPower 32 WCEUSBSH(0): ---------------- WCEUSBSH(0): WCEUSBSH(0): Interface Descriptor(0) WCEUSBSH(0): ------------------------ WCEUSBSH(0): bLength 9 WCEUSBSH(0): bDescriptorType 4 WCEUSBSH(0): bInterfaceNumber 0 WCEUSBSH(0): bAlternateSetting 0 WCEUSBSH(0): bNumEndpoints 2 WCEUSBSH(0): bInterfaceClass ff WCEUSBSH(0): bInterfaceSubClass ff WCEUSBSH(0): bInterfaceProtocol ff WCEUSBSH(0): iInterface 0 WCEUSBSH(0): ------------------------ WCEUSBSH(0): WCEUSBSH(0): Interface Definition WCEUSBSH(0): ------------------------ WCEUSBSH(0): Number of pipes 2 WCEUSBSH(0): Length 38 WCEUSBSH(0): Alt Setting 0 WCEUSBSH(0): Interface Number 0 WCEUSBSH(0): Class ff WCEUSBSH(0): Subclass ff WCEUSBSH(0): Protocol ff WCEUSBSH(0): ------------------------ WCEUSBSH(0): 'COMM' Device Found at Index:0 InterfaceNumber:0 AlternateSetting: 0 WCEUSBSH(0): WCEUSBSH(0): Pipe Information (0) WCEUSBSH(0): ---------------- WCEUSBSH(0): Pipe Type 2 WCEUSBSH(0): Endpoint Addr 82 WCEUSBSH(0): MaxPacketSize 40 WCEUSBSH(0): Interval 0 WCEUSBSH(0): Handle fbfcef90 WCEUSBSH(0): MaxTransSize 1ffff WCEUSBSH(0): ---------------- WCEUSBSH(0): WCEUSBSH(0): Pipe Information (1) WCEUSBSH(0): ---------------- WCEUSBSH(0): Pipe Type 2 WCEUSBSH(0): Endpoint Addr 2 WCEUSBSH(0): MaxPacketSize 40 WCEUSBSH(0): Interval 0 WCEUSBSH(0): Handle fbfcefac WCEUSBSH(0): MaxTransSize 1ffff WCEUSBSH(0): ---------------- WCEUSBSH(0): IntPipe: 0 DataOutPipe: fbfcefac DataInPipe: fbfcef90 */ NTSTATUS UsbGetDeviceDescriptor( IN PDEVICE_OBJECT PDevObj ) { PDEVICE_EXTENSION pDevExt = PDevObj->DeviceExtension; NTSTATUS status; ULONG descSize; ULONG urbCDRSize; PURB pUrb; DbgDump(DBG_USB, (">UsbGetDeviceDescriptor\n")); PAGED_CODE(); urbCDRSize = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST); pUrb = ExAllocatePool(NonPagedPool, urbCDRSize); if (pUrb != NULL) { descSize = sizeof(USB_DEVICE_DESCRIPTOR); RtlZeroMemory(&pDevExt->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR)); UsbBuildGetDescriptorRequest(pUrb, (USHORT)urbCDRSize, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0, &pDevExt->DeviceDescriptor, NULL, descSize, NULL ); status = UsbSubmitSyncUrb( PDevObj, pUrb, TRUE, DEFAULT_CTRL_TIMEOUT ); if (STATUS_SUCCESS == status) { #if DBG if (DebugLevel & DBG_USB) { DbgDump(DBG_USB, ("Device Descriptor\n")); DbgDump(DBG_USB, ("------------------------\n")); DbgDump(DBG_USB, ("bLength 0x%x\n", pDevExt->DeviceDescriptor.bLength)); DbgDump(DBG_USB, ("bDescriptorType 0x%x\n", pDevExt->DeviceDescriptor.bDescriptorType)); DbgDump(DBG_USB, ("bcdUSB 0x%x\n", pDevExt->DeviceDescriptor.bcdUSB)); DbgDump(DBG_USB, ("bDeviceClass 0x%x\n", pDevExt->DeviceDescriptor.bDeviceClass)); DbgDump(DBG_USB, ("bDeviceSubClass 0x%x\n", pDevExt->DeviceDescriptor.bDeviceSubClass)); DbgDump(DBG_USB, ("bDeviceProtocol 0x%x\n", pDevExt->DeviceDescriptor.bDeviceProtocol)); DbgDump(DBG_USB, ("bMaxPacketSize0 0x%x\n", pDevExt->DeviceDescriptor.bMaxPacketSize0)); DbgDump(DBG_USB, ("idVendor 0x%x\n", pDevExt->DeviceDescriptor.idVendor)); DbgDump(DBG_USB, ("idProduct 0x%x\n", pDevExt->DeviceDescriptor.idProduct)); DbgDump(DBG_USB, ("bcdDevice 0x%x\n", pDevExt->DeviceDescriptor.bcdDevice)); DbgDump(DBG_USB, ("iManufacturer 0x%x\n", pDevExt->DeviceDescriptor.iManufacturer)); DbgDump(DBG_USB, ("iProduct 0x%x\n", pDevExt->DeviceDescriptor.iProduct)); DbgDump(DBG_USB, ("iSerialNumber 0x%x\n", pDevExt->DeviceDescriptor.iSerialNumber)); DbgDump(DBG_USB, ("bNumConfigs 0x%x\n", pDevExt->DeviceDescriptor.bNumConfigurations)); DbgDump(DBG_USB, ("------------------------\n")); } #endif } else { DbgDump(DBG_ERR, ("UsbSubmitSyncUrb error: 0x%x\n", status)); RtlZeroMemory(&pDevExt->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR)); } ExFreePool(pUrb); } else { status = STATUS_INSUFFICIENT_RESOURCES; DbgDump(DBG_ERR, ("UsbGetDeviceDescriptor 0x%x\n", status)); } if (STATUS_INSUFFICIENT_RESOURCES == status) { LogError( NULL, PDevObj, 0, 0, 0, ERR_GET_DEVICE_DESCRIPTOR, status, SERIAL_INSUFFICIENT_RESOURCES, pDevExt->DeviceName.Length + sizeof(WCHAR), pDevExt->DeviceName.Buffer, 0, NULL ); } else if (STATUS_SUCCESS != status ) { // handles all other failures LogError( NULL, PDevObj, 0, 0, 0, ERR_GET_DEVICE_DESCRIPTOR, status, SERIAL_HARDWARE_FAILURE, pDevExt->DeviceName.Length + sizeof(WCHAR), pDevExt->DeviceName.Buffer, 0, NULL ); } DbgDump(DBG_USB, ("DeviceExtension; NTSTATUS status = STATUS_SUCCESS; PURB pUrb = NULL; ULONG pipe; ULONG index = 0; UCHAR interfaceNumber = 0; PUSBD_INTERFACE_INFORMATION pInterfaceInfo = NULL; BOOLEAN foundCommDevice = FALSE; USBD_INTERFACE_LIST_ENTRY interfaceList[2] = {0, 0}; DbgDump(DBG_USB, (">UsbSelectInterface %d\n", AlternateSetting)); PAGED_CODE(); if ( !PDevObj || !PConfigDesc ) { status = STATUS_INVALID_PARAMETER; DbgDump(DBG_ERR, ("UsbSelectInterface 0x%x\n", status)); goto SelectInterfaceError; } interfaceList[0].InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx( PConfigDesc, PConfigDesc, -1, AlternateSetting, -1, -1, -1 ); if (interfaceList[0].InterfaceDescriptor) { // interfaceList[1].InterfaceDescriptor = NULL; DbgDump(DBG_USB, ("\n")); DbgDump(DBG_USB, ("Interface Descriptor(%d)\n", interfaceNumber )); DbgDump(DBG_USB, ("------------------------\n")); DbgDump(DBG_USB, ("bLength 0x%x\n", interfaceList[0].InterfaceDescriptor->bLength )); DbgDump(DBG_USB, ("bDescriptorType 0x%x\n", interfaceList[0].InterfaceDescriptor->bDescriptorType)); DbgDump(DBG_USB, ("bInterfaceNumber 0x%x\n", interfaceList[0].InterfaceDescriptor->bInterfaceNumber )); DbgDump(DBG_USB, ("bAlternateSetting 0x%x\n", interfaceList[0].InterfaceDescriptor->bAlternateSetting )); DbgDump(DBG_USB, ("bNumEndpoints 0x%x\n", interfaceList[0].InterfaceDescriptor->bNumEndpoints )); DbgDump(DBG_USB, ("bInterfaceClass 0x%x\n", interfaceList[0].InterfaceDescriptor->bInterfaceClass )); DbgDump(DBG_USB, ("bInterfaceSubClass 0x%x\n", interfaceList[0].InterfaceDescriptor->bInterfaceSubClass )); DbgDump(DBG_USB, ("bInterfaceProtocol 0x%x\n", interfaceList[0].InterfaceDescriptor->bInterfaceProtocol )); DbgDump(DBG_USB, ("iInterface 0x%x\n", interfaceList[0].InterfaceDescriptor->iInterface )); DbgDump(DBG_USB, ("------------------------\n")); pUrb = USBD_CreateConfigurationRequestEx( PConfigDesc, &interfaceList[0]); if ( pUrb ) { // // perform any pipe initialization here // PUSBD_INTERFACE_INFORMATION pInitInterfaceInfo = &pUrb->UrbSelectConfiguration.Interface; for ( index = 0; index < interfaceList[0].InterfaceDescriptor->bNumEndpoints; index++) { pInitInterfaceInfo->Pipes[index].MaximumTransferSize = pDevExt->MaximumTransferSize; pInitInterfaceInfo->Pipes[index].PipeFlags = 0; } status = UsbSubmitSyncUrb(PDevObj, pUrb, TRUE, DEFAULT_CTRL_TIMEOUT ); if (STATUS_SUCCESS == status) { pDevExt->ConfigurationHandle = pUrb->UrbSelectConfiguration.ConfigurationHandle; pInterfaceInfo = &pUrb->UrbSelectConfiguration.Interface; DbgDump(DBG_USB, ("Interface Definition\n" )); DbgDump(DBG_USB, ("------------------------\n")); DbgDump(DBG_USB, ("Number of pipes 0x%x\n", pInterfaceInfo->NumberOfPipes)); DbgDump(DBG_USB, ("Length 0x%x\n", pInterfaceInfo->Length)); DbgDump(DBG_USB, ("Alt Setting 0x%x\n", pInterfaceInfo->AlternateSetting)); DbgDump(DBG_USB, ("Interface Number 0x%x\n", pInterfaceInfo->InterfaceNumber)); DbgDump(DBG_USB, ("Class 0x%x\n", pInterfaceInfo->Class)); DbgDump(DBG_USB, ("Subclass 0x%x\n", pInterfaceInfo->SubClass)); DbgDump(DBG_USB, ("Protocol 0x%x\n", pInterfaceInfo->Protocol)); DbgDump(DBG_USB, ("------------------------\n")); if ( (pInterfaceInfo->Class == USB_NULL_MODEM_CLASS) && (pInterfaceInfo->AlternateSetting == AlternateSetting) && (pInterfaceInfo->NumberOfPipes)) { foundCommDevice = TRUE; pDevExt->UsbInterfaceNumber = pInterfaceInfo->InterfaceNumber; } else { status = STATUS_NO_SUCH_DEVICE; DbgDump(DBG_ERR, ("UsbSelectInterface 0x%x\n", status)); goto SelectInterfaceError; } } else { DbgDump(DBG_ERR, ("UsbSubmitSyncUrb 0x%x\n", status)); goto SelectInterfaceError; } } else { status = STATUS_INSUFFICIENT_RESOURCES; DbgDump(DBG_ERR, ("USBD_CreateConfigurationRequestEx 0x%x\n", status)); goto SelectInterfaceError; } DbgDump(DBG_USB, ("\n")); DbgDump(DBG_USB, ("Function Device Found at Index:0x%x InterfaceNumber:0x%x AlternateSetting: 0x%x\n", interfaceNumber, pDevExt->UsbInterfaceNumber, AlternateSetting)); // // We found the interface we want, now discover the pipes // The standard interface is defined to contain 1 bulk read, 1 bulk write, and an optional INT pipe // BUGBUG: if there are more endpoints then they will overwrite the previous with this code. // ASSERT( pInterfaceInfo ); for ( pipe = 0; pipe < pInterfaceInfo->NumberOfPipes; pipe++) { PUSBD_PIPE_INFORMATION pPipeInfo; pPipeInfo = &pInterfaceInfo->Pipes[pipe]; DbgDump(DBG_USB, ("\n")); DbgDump(DBG_USB, ("Pipe Information (%d)\n", pipe)); DbgDump(DBG_USB, ("----------------\n")); DbgDump(DBG_USB, ("Pipe Type 0x%x\n", pPipeInfo->PipeType)); DbgDump(DBG_USB, ("Endpoint Addr 0x%x\n", pPipeInfo->EndpointAddress)); DbgDump(DBG_USB, ("MaxPacketSize 0x%x\n", pPipeInfo->MaximumPacketSize)); DbgDump(DBG_USB, ("Interval 0x%x\n", pPipeInfo->Interval)); DbgDump(DBG_USB, ("Handle 0x%x\n", pPipeInfo->PipeHandle)); DbgDump(DBG_USB, ("MaxTransSize 0x%x\n", pPipeInfo->MaximumTransferSize)); DbgDump(DBG_USB, ("----------------\n")); // // save pipe info in our device extension // if ( USB_ENDPOINT_DIRECTION_IN( pPipeInfo->EndpointAddress ) ) { // // Bulk Data In pipe // if ( USB_ENDPOINT_TYPE_BULK == pPipeInfo->PipeType) { // // Bulk IN pipe // pDevExt->ReadPipe.wIndex = pPipeInfo->EndpointAddress; pDevExt->ReadPipe.hPipe = pPipeInfo->PipeHandle; pDevExt->ReadPipe.MaxPacketSize = pPipeInfo->MaximumPacketSize; } else if ( USB_ENDPOINT_TYPE_INTERRUPT == pPipeInfo->PipeType ) { // // INT Pipe - alloc a notify buffer for 1 packet // PVOID pOldBuff = NULL; PVOID pNewBuff = NULL; pDevExt->IntPipe.MaxPacketSize = pPipeInfo->MaximumPacketSize; if ( pDevExt->IntPipe.MaxPacketSize ) { pNewBuff = ExAllocatePool( NonPagedPool, pDevExt->IntPipe.MaxPacketSize ); if ( !pNewBuff ) { status = STATUS_INSUFFICIENT_RESOURCES; DbgDump(DBG_ERR, ("ExAllocatePool: 0x%x\n", status)); goto SelectInterfaceError; } } else { DbgDump(DBG_ERR, ("No INT MaximumPacketSize\n")); status = STATUS_NO_SUCH_DEVICE; goto SelectInterfaceError; } if (pDevExt->IntBuff) { pOldBuff = pDevExt->IntBuff; ExFreePool(pOldBuff); } pDevExt->IntBuff = pNewBuff; pDevExt->IntPipe.hPipe = pPipeInfo->PipeHandle; pDevExt->IntPipe.wIndex = pPipeInfo->EndpointAddress; pDevExt->IntReadTimeOut.QuadPart = MILLISEC_TO_100NANOSEC( g_lIntTimout ); } else { DbgDump(DBG_ERR, ("Invalid IN PipeType")); status = STATUS_NO_SUCH_DEVICE; goto SelectInterfaceError; } } else if ( USB_ENDPOINT_DIRECTION_OUT( pPipeInfo->EndpointAddress ) ) { // // OUT EPs // if ( USB_ENDPOINT_TYPE_BULK == pPipeInfo->PipeType ) { // // Bulk OUT Pipe // pDevExt->WritePipe.hPipe = pPipeInfo->PipeHandle; pDevExt->WritePipe.wIndex = pPipeInfo->EndpointAddress; pDevExt->WritePipe.MaxPacketSize = pPipeInfo->MaximumPacketSize; } else { DbgDump(DBG_ERR, ("Invalid OUT PipeType")); status = STATUS_NO_SUCH_DEVICE; goto SelectInterfaceError; } } else { DbgDump(DBG_ERR, ("Invalid EndpointAddress")); status = STATUS_NO_SUCH_DEVICE; goto SelectInterfaceError; } } DbgDump(DBG_USB, ("\n")); DbgDump(DBG_USB, ("INT Pipe: %p\t OUT Pipe: %p\t IN Pipe: %p\n", pDevExt->IntPipe.hPipe, pDevExt->WritePipe.hPipe, pDevExt->ReadPipe.hPipe )); } else { DbgDump(DBG_ERR, ("USBD_ParseConfigurationDescriptorEx: No match not found\n")); status = STATUS_NO_SUCH_DEVICE; goto SelectInterfaceError; } // // did we find all of our pipes? // SelectInterfaceError: if ( !foundCommDevice || !pDevExt->ReadPipe.hPipe || !pDevExt->WritePipe.hPipe || (STATUS_SUCCESS != status) ) { LogError( NULL, PDevObj, 0, 0, 0, ERR_SELECT_INTERFACE, status, (status == STATUS_INSUFFICIENT_RESOURCES) ? SERIAL_INSUFFICIENT_RESOURCES : SERIAL_HARDWARE_FAILURE, pDevExt->DeviceName.Length + sizeof(WCHAR), pDevExt->DeviceName.Buffer, 0, NULL ); } if ( pUrb ) { ExFreePool(pUrb); } DbgDump(DBG_USB, ("DeviceExtension; PUSB_CONFIGURATION_DESCRIPTOR pConDesc = NULL; NTSTATUS status = STATUS_UNSUCCESSFUL; PURB pUrb = NULL; ULONG size; ULONG urbCDRSize; ULONG numConfigs; UCHAR config; DbgDump(DBG_USB, (">UsbConfigureDevice\n")); PAGED_CODE(); urbCDRSize = sizeof(struct _URB_CONTROL_DESCRIPTOR_REQUEST); // configure the device pUrb = ExAllocatePool(NonPagedPool, urbCDRSize); if (pUrb == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; DbgDump(DBG_ERR, ("UsbConfigureDevice ERROR: 0x%x\n", status)); goto ConfigureDeviceError; } // // there may be problems with the 82930 chip, so make this buffer bigger // to prevent choking // size = sizeof(USB_CONFIGURATION_DESCRIPTOR) + 256; // // get the number of configurations // numConfigs = pDevExt->DeviceDescriptor.bNumConfigurations; // // walk all of the configurations looking for a CDC device // for (config = 0; config < numConfigs; config++) { // // we will probably only do this once, maybe twice // while (TRUE) { pConDesc = ExAllocatePool(NonPagedPool, size); if (pConDesc == NULL) { status = STATUS_INSUFFICIENT_RESOURCES; DbgDump(DBG_ERR, ("ExAllocatePool: 0x%x\n", status)); goto ConfigureDeviceError; } // // Get descriptor information from the host controller driver (HCD). // All interface, endpoint, class-specific, and vendor-specific descriptors // for the configuration also are retrieved // UsbBuildGetDescriptorRequest( pUrb, (USHORT)urbCDRSize, USB_CONFIGURATION_DESCRIPTOR_TYPE, config, // Index 0, // LanguageId pConDesc,// TransferBuffer NULL, // TransferBufferMdl size, // TransferBufferLength NULL); // Link status = UsbSubmitSyncUrb( PDevObj, pUrb, TRUE, DEFAULT_CTRL_TIMEOUT ); if (status != STATUS_SUCCESS) { DbgDump(DBG_ERR, ("UsbSubmitSyncUrb: 0x%x\n", status)); goto ConfigureDeviceError; } // // see if we got enough data, we may get an error in URB because of // buffer overrun // if ((pUrb->UrbControlDescriptorRequest.TransferBufferLength > 0) && (pConDesc->wTotalLength > size)) { // // size of data exceeds current buffer size, so allocate correct // size // size = pConDesc->wTotalLength; ExFreePool(pConDesc); pConDesc = NULL; } else { break; } } #if DBG DbgDump(DBG_USB, ("\n")); DbgDump(DBG_USB, ("Configuration Descriptor\n" )); DbgDump(DBG_USB, ("----------------\n")); DbgDump(DBG_USB, ("bLength 0x%x\n", pConDesc->bLength )); DbgDump(DBG_USB, ("bDescriptorType 0x%x\n", pConDesc->bDescriptorType )); DbgDump(DBG_USB, ("wTotalLength 0x%x\n", pConDesc->wTotalLength )); DbgDump(DBG_USB, ("bNumInterfaces 0x%x\n", pConDesc->bNumInterfaces )); DbgDump(DBG_USB, ("bConfigurationValue 0x%x\n", pConDesc->bConfigurationValue )); DbgDump(DBG_USB, ("iConfiguration 0x%x\n", pConDesc->iConfiguration )); DbgDump(DBG_USB, ("bmAttributes 0x%x\n", pConDesc->bmAttributes )); DbgDump(DBG_USB, ("MaxPower 0x%x\n", pConDesc->MaxPower )); DbgDump(DBG_USB, ("----------------\n")); DbgDump(DBG_USB, ("\n")); #endif status = UsbSelectInterface(PDevObj, pConDesc, (UCHAR)g_ulAlternateSetting); ExFreePool(pConDesc); pConDesc = NULL; // // found a config we like // if (status == STATUS_SUCCESS) break; } // config ConfigureDeviceError: if (pUrb != NULL) { ExFreePool(pUrb); } if (pConDesc != NULL) { ExFreePool(pConDesc); } if (STATUS_INSUFFICIENT_RESOURCES == status) { LogError( NULL, PDevObj, 0, 0, 0, ERR_CONFIG_DEVICE, status, SERIAL_INSUFFICIENT_RESOURCES, pDevExt->DeviceName.Length + sizeof(WCHAR), pDevExt->DeviceName.Buffer, 0, NULL ); } else if (STATUS_SUCCESS != status ) { // handles all other failures LogError( NULL, PDevObj, 0, 0, 0, ERR_CONFIG_DEVICE, status, SERIAL_HARDWARE_FAILURE, pDevExt->DeviceName.Length + sizeof(WCHAR), pDevExt->DeviceName.Buffer, 0, NULL ); } DbgDump(DBG_USB, ("