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
|