687 lines
23 KiB
C
687 lines
23 KiB
C
/* ++
|
||
|
||
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 <wdm.h>
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <usbdi.h>
|
||
#include <usbdlib.h>
|
||
#include <ntddser.h>
|
||
|
||
#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, ("<UsbGetDeviceDescriptor 0x%x\n", status));
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
//
|
||
// BUGBUG: currently assumes 1 interface
|
||
//
|
||
|
||
NTSTATUS
|
||
UsbSelectInterface(
|
||
IN PDEVICE_OBJECT PDevObj,
|
||
IN PUSB_CONFIGURATION_DESCRIPTOR PConfigDesc,
|
||
IN UCHAR AlternateSetting
|
||
)
|
||
{
|
||
PDEVICE_EXTENSION pDevExt = PDevObj->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, ("<UsbSelectInterface 0x%x\n", status));
|
||
|
||
return status;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
UsbConfigureDevice(
|
||
IN PDEVICE_OBJECT PDevObj
|
||
)
|
||
{
|
||
PDEVICE_EXTENSION pDevExt = PDevObj->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, ("<UsbConfigureDevice (0x%x)\n", status));
|
||
|
||
return status;
|
||
}
|
||
|
||
// EOF
|