mirror of
https://github.com/reactos/reactos.git
synced 2024-09-12 13:54:41 +00:00
1095 lines
32 KiB
C
1095 lines
32 KiB
C
/*
|
|
* PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: drivers/usb/usbccgp/pdo.c
|
|
* PURPOSE: USB device driver.
|
|
* PROGRAMMERS:
|
|
* Michael Martin (michael.martin@reactos.org)
|
|
* Johannes Anderwald (johannes.anderwald@reactos.org)
|
|
* Cameron Gutman
|
|
*/
|
|
|
|
#include "usbccgp.h"
|
|
|
|
#include <ntddk.h>
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
NTSTATUS
|
|
USBCCGP_PdoHandleQueryDeviceText(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp)
|
|
{
|
|
LPWSTR Buffer;
|
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
|
LPWSTR GenericString = L"Composite USB Device";
|
|
//
|
|
// get device extension
|
|
//
|
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// is there a device description
|
|
//
|
|
if (PDODeviceExtension->FunctionDescriptor->FunctionDescription.Length)
|
|
{
|
|
//
|
|
// allocate buffer
|
|
//
|
|
Buffer = AllocateItem(NonPagedPool, PDODeviceExtension->FunctionDescriptor->FunctionDescription.Length + sizeof(WCHAR));
|
|
if (!Buffer)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// copy buffer
|
|
//
|
|
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
|
|
RtlCopyMemory(Buffer, PDODeviceExtension->FunctionDescriptor->FunctionDescription.Buffer, PDODeviceExtension->FunctionDescriptor->FunctionDescription.Length);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
//
|
|
// FIXME use GenericCompositeUSBDeviceString
|
|
//
|
|
UNIMPLEMENTED;
|
|
Buffer = AllocateItem(PagedPool, (wcslen(GenericString) + 1) * sizeof(WCHAR));
|
|
if (!Buffer)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
RtlCopyMemory(Buffer, GenericString, (wcslen(GenericString) + 1) * sizeof(WCHAR));
|
|
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USBCCGP_PdoHandleDeviceRelations(
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN OUT PIRP Irp)
|
|
{
|
|
PDEVICE_RELATIONS DeviceRelations;
|
|
PIO_STACK_LOCATION IoStack;
|
|
|
|
DPRINT("USBCCGP_PdoHandleDeviceRelations\n");
|
|
|
|
//
|
|
// get current irp stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// check if relation type is BusRelations
|
|
//
|
|
if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
|
|
{
|
|
//
|
|
// PDO handles only target device relation
|
|
//
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
//
|
|
// allocate device relations
|
|
//
|
|
DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
|
|
if (!DeviceRelations)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// initialize device relations
|
|
//
|
|
DeviceRelations->Count = 1;
|
|
DeviceRelations->Objects[0] = DeviceObject;
|
|
ObReferenceObject(DeviceObject);
|
|
|
|
//
|
|
// store result
|
|
//
|
|
Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
|
|
|
|
//
|
|
// completed successfully
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USBCCGP_PdoAppendInterfaceNumber(
|
|
IN LPWSTR DeviceId,
|
|
IN ULONG InterfaceNumber,
|
|
OUT LPWSTR *OutString)
|
|
{
|
|
ULONG Length = 0, StringLength;
|
|
LPWSTR String;
|
|
|
|
//
|
|
// count length of string
|
|
//
|
|
String = DeviceId;
|
|
while (*String)
|
|
{
|
|
StringLength = wcslen(String) + 1;
|
|
Length += StringLength;
|
|
Length += 6; //&MI_XX
|
|
String += StringLength;
|
|
}
|
|
|
|
//
|
|
// now allocate the buffer
|
|
//
|
|
String = AllocateItem(NonPagedPool, (Length + 2) * sizeof(WCHAR));
|
|
if (!String)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// store result
|
|
//
|
|
*OutString = String;
|
|
|
|
while (*DeviceId)
|
|
{
|
|
StringLength = swprintf(String, L"%s&MI_%02x", DeviceId, InterfaceNumber) + 1;
|
|
Length = wcslen(DeviceId) + 1;
|
|
DPRINT("String %p\n", String);
|
|
|
|
//
|
|
// next string
|
|
//
|
|
String += StringLength;
|
|
DeviceId += Length;
|
|
}
|
|
|
|
//
|
|
// success
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
USBCCGP_PdoHandleQueryId(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PUNICODE_STRING DeviceString = NULL;
|
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
|
NTSTATUS Status;
|
|
LPWSTR Buffer;
|
|
|
|
//
|
|
// get current irp stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
|
|
if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
|
|
{
|
|
//
|
|
// handle query device id
|
|
//
|
|
Status = USBCCGP_SyncForwardIrp(PDODeviceExtension->NextDeviceObject, Irp);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// allocate buffer
|
|
//
|
|
Buffer = AllocateItem(NonPagedPool, (wcslen((LPWSTR)Irp->IoStatus.Information) + 7) * sizeof(WCHAR));
|
|
if (Buffer)
|
|
{
|
|
//
|
|
// append interface number
|
|
//
|
|
ASSERT(Irp->IoStatus.Information);
|
|
swprintf(Buffer, L"%s&MI_%02x", (LPWSTR)Irp->IoStatus.Information, PDODeviceExtension->FunctionDescriptor->FunctionNumber);
|
|
DPRINT("BusQueryDeviceID %S\n", Buffer);
|
|
|
|
ExFreePool((PVOID)Irp->IoStatus.Information);
|
|
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
Status = STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
}
|
|
return Status;
|
|
}
|
|
else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
|
|
{
|
|
//
|
|
// handle instance id
|
|
//
|
|
DeviceString = &PDODeviceExtension->FunctionDescriptor->HardwareId;
|
|
}
|
|
else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
|
|
{
|
|
//
|
|
// handle instance id
|
|
//
|
|
Buffer = AllocateItem(NonPagedPool, 5 * sizeof(WCHAR));
|
|
if (!Buffer)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// use function number
|
|
//
|
|
swprintf(Buffer, L"%04x", PDODeviceExtension->FunctionDescriptor->FunctionNumber);
|
|
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
|
|
{
|
|
//
|
|
// handle instance id
|
|
//
|
|
DeviceString = &PDODeviceExtension->FunctionDescriptor->CompatibleId;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// unsupported query
|
|
//
|
|
return Irp->IoStatus.Status;
|
|
}
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
ASSERT(DeviceString != NULL);
|
|
|
|
//
|
|
// allocate buffer
|
|
//
|
|
Buffer = AllocateItem(NonPagedPool, DeviceString->Length + sizeof(WCHAR));
|
|
if (!Buffer)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// copy buffer
|
|
//
|
|
RtlCopyMemory(Buffer, DeviceString->Buffer, DeviceString->Length);
|
|
Buffer[DeviceString->Length / sizeof(WCHAR)] = UNICODE_NULL;
|
|
Irp->IoStatus.Information = (ULONG_PTR)Buffer;
|
|
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PDO_HandlePnp(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
|
NTSTATUS Status;
|
|
ULONG Index, bFound;
|
|
|
|
//
|
|
// get current stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
ASSERT(PDODeviceExtension->Common.IsFDO == FALSE);
|
|
|
|
switch(IoStack->MinorFunction)
|
|
{
|
|
case IRP_MN_QUERY_DEVICE_RELATIONS:
|
|
{
|
|
//
|
|
// handle device relations
|
|
//
|
|
Status = USBCCGP_PdoHandleDeviceRelations(DeviceObject, Irp);
|
|
break;
|
|
}
|
|
case IRP_MN_QUERY_DEVICE_TEXT:
|
|
{
|
|
//
|
|
// handle query device text
|
|
//
|
|
Status = USBCCGP_PdoHandleQueryDeviceText(DeviceObject, Irp);
|
|
break;
|
|
}
|
|
case IRP_MN_QUERY_ID:
|
|
{
|
|
//
|
|
// handle request
|
|
//
|
|
Status = USBCCGP_PdoHandleQueryId(DeviceObject, Irp);
|
|
break;
|
|
}
|
|
case IRP_MN_REMOVE_DEVICE:
|
|
{
|
|
//
|
|
// remove us from the fdo's pdo list
|
|
//
|
|
bFound = FALSE;
|
|
for(Index = 0; Index < PDODeviceExtension->FDODeviceExtension->FunctionDescriptorCount; Index++)
|
|
{
|
|
if (PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] == DeviceObject)
|
|
{
|
|
//
|
|
// remove us
|
|
//
|
|
PDODeviceExtension->FDODeviceExtension->ChildPDO[Index] = NULL;
|
|
bFound = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Complete the IRP
|
|
//
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
|
|
if (bFound)
|
|
{
|
|
//
|
|
// Delete the device object
|
|
//
|
|
IoDeleteDevice(DeviceObject);
|
|
}
|
|
return STATUS_SUCCESS;
|
|
}
|
|
case IRP_MN_QUERY_CAPABILITIES:
|
|
{
|
|
//
|
|
// copy device capabilities
|
|
//
|
|
RtlCopyMemory(IoStack->Parameters.DeviceCapabilities.Capabilities, &PDODeviceExtension->Capabilities, sizeof(DEVICE_CAPABILITIES));
|
|
|
|
/* Complete the IRP */
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
case IRP_MN_QUERY_REMOVE_DEVICE:
|
|
case IRP_MN_QUERY_STOP_DEVICE:
|
|
{
|
|
//
|
|
// sure
|
|
//
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
case IRP_MN_START_DEVICE:
|
|
{
|
|
//
|
|
// no-op for PDO
|
|
//
|
|
DPRINT("[USBCCGP] PDO IRP_MN_START\n");
|
|
Status = STATUS_SUCCESS;
|
|
break;
|
|
}
|
|
case IRP_MN_QUERY_INTERFACE:
|
|
{
|
|
//
|
|
// forward to lower device object
|
|
//
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
return IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
|
|
}
|
|
default:
|
|
{
|
|
//
|
|
// do nothing
|
|
//
|
|
Status = Irp->IoStatus.Status;
|
|
break;
|
|
}
|
|
}
|
|
|
|
//
|
|
// complete request
|
|
//
|
|
if (Status != STATUS_PENDING)
|
|
{
|
|
//
|
|
// store result
|
|
//
|
|
Irp->IoStatus.Status = Status;
|
|
|
|
//
|
|
// complete request
|
|
//
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
}
|
|
|
|
//
|
|
// done processing
|
|
//
|
|
return Status;
|
|
|
|
}
|
|
|
|
NTSTATUS
|
|
USBCCGP_BuildConfigurationDescriptor(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
|
PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor;
|
|
PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
|
|
ULONG TotalSize, Index;
|
|
ULONG Size;
|
|
PURB Urb;
|
|
PVOID Buffer;
|
|
PUCHAR BufferPtr;
|
|
UCHAR InterfaceNumber;
|
|
|
|
//
|
|
// get current stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
DPRINT("USBCCGP_BuildConfigurationDescriptor\n");
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// get configuration descriptor
|
|
//
|
|
ConfigurationDescriptor = PDODeviceExtension->ConfigurationDescriptor;
|
|
|
|
//
|
|
// calculate size of configuration descriptor
|
|
//
|
|
TotalSize = sizeof(USB_CONFIGURATION_DESCRIPTOR);
|
|
|
|
for (Index = 0; Index < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; Index++)
|
|
{
|
|
//
|
|
// get current interface descriptor
|
|
//
|
|
InterfaceDescriptor = PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[Index];
|
|
InterfaceNumber = InterfaceDescriptor->bInterfaceNumber;
|
|
|
|
//
|
|
// add to size and move to next descriptor
|
|
//
|
|
TotalSize += InterfaceDescriptor->bLength;
|
|
InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
|
|
|
|
do
|
|
{
|
|
if ((ULONG_PTR)InterfaceDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
|
|
{
|
|
//
|
|
// reached end of configuration descriptor
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// association descriptors are removed
|
|
//
|
|
if (InterfaceDescriptor->bDescriptorType != USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
|
|
{
|
|
if (InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
|
|
{
|
|
if (InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
|
|
{
|
|
//
|
|
// reached next descriptor
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// include alternate descriptor
|
|
//
|
|
}
|
|
|
|
//
|
|
// append size
|
|
//
|
|
TotalSize += InterfaceDescriptor->bLength;
|
|
}
|
|
|
|
//
|
|
// move to next descriptor
|
|
//
|
|
InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
|
|
} while(TRUE);
|
|
}
|
|
|
|
//
|
|
// now allocate temporary buffer for the configuration descriptor
|
|
//
|
|
Buffer = AllocateItem(NonPagedPool, TotalSize);
|
|
if (!Buffer)
|
|
{
|
|
//
|
|
// failed to allocate buffer
|
|
//
|
|
DPRINT1("[USBCCGP] Failed to allocate %lu Bytes\n", TotalSize);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// first copy the configuration descriptor
|
|
//
|
|
RtlCopyMemory(Buffer, ConfigurationDescriptor, sizeof(USB_CONFIGURATION_DESCRIPTOR));
|
|
BufferPtr = (PUCHAR)((ULONG_PTR)Buffer + ConfigurationDescriptor->bLength);
|
|
|
|
for (Index = 0; Index < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; Index++)
|
|
{
|
|
//
|
|
// get current interface descriptor
|
|
//
|
|
InterfaceDescriptor = PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[Index];
|
|
InterfaceNumber = InterfaceDescriptor->bInterfaceNumber;
|
|
|
|
//
|
|
// copy descriptor and move to next descriptor
|
|
//
|
|
RtlCopyMemory(BufferPtr, InterfaceDescriptor, InterfaceDescriptor->bLength);
|
|
BufferPtr += InterfaceDescriptor->bLength;
|
|
InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
|
|
|
|
do
|
|
{
|
|
if ((ULONG_PTR)InterfaceDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
|
|
{
|
|
//
|
|
// reached end of configuration descriptor
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// association descriptors are removed
|
|
//
|
|
if (InterfaceDescriptor->bDescriptorType != USB_INTERFACE_ASSOCIATION_DESCRIPTOR_TYPE)
|
|
{
|
|
if (InterfaceDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
|
|
{
|
|
if (InterfaceNumber != InterfaceDescriptor->bInterfaceNumber)
|
|
{
|
|
//
|
|
// reached next descriptor
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// include alternate descriptor
|
|
//
|
|
DPRINT("InterfaceDescriptor %p Alternate %x InterfaceNumber %x\n", InterfaceDescriptor, InterfaceDescriptor->bAlternateSetting, InterfaceDescriptor->bInterfaceNumber);
|
|
}
|
|
|
|
//
|
|
// copy descriptor
|
|
//
|
|
RtlCopyMemory(BufferPtr, InterfaceDescriptor, InterfaceDescriptor->bLength);
|
|
BufferPtr += InterfaceDescriptor->bLength;
|
|
}
|
|
|
|
//
|
|
// move to next descriptor
|
|
//
|
|
InterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
|
|
} while(TRUE);
|
|
}
|
|
|
|
//
|
|
// modify configuration descriptor
|
|
//
|
|
ConfigurationDescriptor = Buffer;
|
|
ConfigurationDescriptor->wTotalLength = (USHORT)TotalSize;
|
|
ConfigurationDescriptor->bNumInterfaces = PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces;
|
|
|
|
//
|
|
// get urb
|
|
//
|
|
Urb = (PURB)IoStack->Parameters.Others.Argument1;
|
|
ASSERT(Urb);
|
|
|
|
//
|
|
// copy descriptor
|
|
//
|
|
Size = min(TotalSize, Urb->UrbControlDescriptorRequest.TransferBufferLength);
|
|
RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, Buffer, Size);
|
|
|
|
//
|
|
// store final size
|
|
//
|
|
Urb->UrbControlDescriptorRequest.TransferBufferLength = Size;
|
|
|
|
//
|
|
// free buffer
|
|
//
|
|
FreeItem(Buffer);
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
USBCCGP_PDOSelectConfiguration(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
|
PURB Urb, NewUrb;
|
|
PUSBD_INTERFACE_INFORMATION InterfaceInformation;
|
|
ULONG InterfaceIndex, Length;
|
|
PUSBD_INTERFACE_LIST_ENTRY Entry;
|
|
ULONG NeedSelect, FoundInterface;
|
|
NTSTATUS Status;
|
|
|
|
//
|
|
// get current stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
//
|
|
// get urb
|
|
//
|
|
Urb = (PURB)IoStack->Parameters.Others.Argument1;
|
|
ASSERT(Urb);
|
|
|
|
//
|
|
// is there already an configuration handle
|
|
//
|
|
if (Urb->UrbSelectConfiguration.ConfigurationHandle)
|
|
{
|
|
//
|
|
// nothing to do
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
// sanity checks
|
|
//C_ASSERT(sizeof(struct _URB_HEADER) == 16);
|
|
//C_ASSERT(FIELD_OFFSET(struct _URB_SELECT_CONFIGURATION, Interface.Length) == 24);
|
|
//C_ASSERT(sizeof(USBD_INTERFACE_INFORMATION) == 36);
|
|
//C_ASSERT(sizeof(struct _URB_SELECT_CONFIGURATION) == 0x3C);
|
|
|
|
// available buffer length
|
|
Length = Urb->UrbSelectConfiguration.Hdr.Length - FIELD_OFFSET(struct _URB_SELECT_CONFIGURATION, Interface.Length);
|
|
|
|
//
|
|
// check all interfaces
|
|
//
|
|
InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
|
|
|
|
Entry = NULL;
|
|
do
|
|
{
|
|
DPRINT1("[USBCCGP] SelectConfiguration Function %x InterfaceNumber %x Alternative %x Length %lu InterfaceInformation->Length %lu\n", PDODeviceExtension->FunctionDescriptor->FunctionNumber, InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting, Length, InterfaceInformation->Length);
|
|
ASSERT(InterfaceInformation->Length);
|
|
//
|
|
// search for the interface in the local interface list
|
|
//
|
|
FoundInterface = FALSE;
|
|
for (InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->FunctionDescriptor->NumberOfInterfaces; InterfaceIndex++)
|
|
{
|
|
if (PDODeviceExtension->FunctionDescriptor->InterfaceDescriptorList[InterfaceIndex]->bInterfaceNumber == InterfaceInformation->InterfaceNumber)
|
|
{
|
|
// found interface entry
|
|
FoundInterface = TRUE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!FoundInterface)
|
|
{
|
|
//
|
|
// invalid parameter
|
|
//
|
|
DPRINT1("InterfaceInformation InterfaceNumber %x Alternative %x NumberOfPipes %x not found\n", InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting, InterfaceInformation->NumberOfPipes);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
|
|
//
|
|
// now query the total interface list
|
|
//
|
|
Entry = NULL;
|
|
for (InterfaceIndex = 0; InterfaceIndex < PDODeviceExtension->InterfaceListCount; InterfaceIndex++)
|
|
{
|
|
if (PDODeviceExtension->InterfaceList[InterfaceIndex].Interface->InterfaceNumber == InterfaceInformation->InterfaceNumber)
|
|
{
|
|
//
|
|
// found entry
|
|
//
|
|
Entry = &PDODeviceExtension->InterfaceList[InterfaceIndex];
|
|
}
|
|
}
|
|
|
|
//
|
|
// sanity check
|
|
//
|
|
ASSERT(Entry);
|
|
if (!Entry)
|
|
{
|
|
//
|
|
// corruption detected
|
|
//
|
|
KeBugCheck(0);
|
|
}
|
|
|
|
NeedSelect = FALSE;
|
|
if (Entry->InterfaceDescriptor->bAlternateSetting == InterfaceInformation->AlternateSetting)
|
|
{
|
|
for(InterfaceIndex = 0; InterfaceIndex < InterfaceInformation->NumberOfPipes; InterfaceIndex++)
|
|
{
|
|
if (InterfaceInformation->Pipes[InterfaceIndex].MaximumTransferSize != Entry->Interface->Pipes[InterfaceIndex].MaximumTransferSize)
|
|
{
|
|
//
|
|
// changed interface
|
|
//
|
|
NeedSelect = TRUE;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// need select as the interface number differ
|
|
//
|
|
NeedSelect = TRUE;
|
|
}
|
|
|
|
if (!NeedSelect)
|
|
{
|
|
//
|
|
// interface is already selected
|
|
//
|
|
ASSERT(Length >= Entry->Interface->Length);
|
|
RtlCopyMemory(InterfaceInformation, Entry->Interface, Entry->Interface->Length);
|
|
|
|
//
|
|
// adjust remaining buffer size
|
|
//
|
|
ASSERT(Entry->Interface->Length);
|
|
Length -= Entry->Interface->Length;
|
|
|
|
//
|
|
// move to next output interface information
|
|
//
|
|
InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + Entry->Interface->Length);
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// select interface
|
|
//
|
|
DPRINT1("Selecting InterfaceIndex %lu AlternateSetting %lu NumberOfPipes %lu\n", InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting, InterfaceInformation->NumberOfPipes);
|
|
ASSERT(InterfaceInformation->Length == Entry->Interface->Length);
|
|
|
|
//
|
|
// build urb
|
|
//
|
|
NewUrb = AllocateItem(NonPagedPool, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceInformation->NumberOfPipes));
|
|
if (!NewUrb)
|
|
{
|
|
//
|
|
// no memory
|
|
//
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
//
|
|
// now prepare interface urb
|
|
//
|
|
UsbBuildSelectInterfaceRequest(NewUrb, (USHORT)GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceInformation->NumberOfPipes), PDODeviceExtension->ConfigurationHandle, InterfaceInformation->InterfaceNumber, InterfaceInformation->AlternateSetting);
|
|
|
|
//
|
|
// now select the interface
|
|
//
|
|
Status = USBCCGP_SyncUrbRequest(PDODeviceExtension->NextDeviceObject, NewUrb);
|
|
DPRINT1("SelectInterface Status %x\n", Status);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
//
|
|
// failed
|
|
//
|
|
break;
|
|
}
|
|
|
|
//
|
|
// update configuration info
|
|
//
|
|
ASSERT(Entry->Interface->Length >= NewUrb->UrbSelectInterface.Interface.Length);
|
|
ASSERT(Length >= NewUrb->UrbSelectInterface.Interface.Length);
|
|
RtlCopyMemory(Entry->Interface, &NewUrb->UrbSelectInterface.Interface, NewUrb->UrbSelectInterface.Interface.Length);
|
|
|
|
//
|
|
// update provided interface information
|
|
//
|
|
ASSERT(Length >= Entry->Interface->Length);
|
|
RtlCopyMemory(InterfaceInformation, Entry->Interface, Entry->Interface->Length);
|
|
|
|
//
|
|
// decrement remaining buffer size
|
|
//
|
|
ASSERT(Entry->Interface->Length);
|
|
Length -= Entry->Interface->Length;
|
|
|
|
//
|
|
// adjust output buffer offset
|
|
//
|
|
InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + Entry->Interface->Length);
|
|
|
|
//
|
|
// free urb
|
|
//
|
|
FreeItem(NewUrb);
|
|
}
|
|
|
|
} while(Length);
|
|
|
|
//
|
|
// store configuration handle
|
|
//
|
|
Urb->UrbSelectConfiguration.ConfigurationHandle = PDODeviceExtension->ConfigurationHandle;
|
|
|
|
DPRINT1("[USBCCGP] SelectConfiguration Function %x Completed\n", PDODeviceExtension->FunctionDescriptor->FunctionNumber);
|
|
|
|
//
|
|
// done
|
|
//
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
PDO_HandleInternalDeviceControl(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
PPDO_DEVICE_EXTENSION PDODeviceExtension;
|
|
NTSTATUS Status;
|
|
PURB Urb;
|
|
|
|
//
|
|
// get current stack location
|
|
//
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
//
|
|
// get device extension
|
|
//
|
|
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
|
|
|
|
if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_SUBMIT_URB)
|
|
{
|
|
//
|
|
// get urb
|
|
//
|
|
Urb = (PURB)IoStack->Parameters.Others.Argument1;
|
|
ASSERT(Urb);
|
|
DPRINT("IOCTL_INTERNAL_USB_SUBMIT_URB Function %x\n", Urb->UrbHeader.Function);
|
|
|
|
if (Urb->UrbHeader.Function == URB_FUNCTION_SELECT_CONFIGURATION)
|
|
{
|
|
//
|
|
// select configuration
|
|
//
|
|
Status = USBCCGP_PDOSelectConfiguration(DeviceObject, Irp);
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|
|
else if (Urb->UrbHeader.Function == URB_FUNCTION_GET_DESCRIPTOR_FROM_DEVICE)
|
|
{
|
|
if (Urb->UrbControlDescriptorRequest.DescriptorType == USB_DEVICE_DESCRIPTOR_TYPE)
|
|
{
|
|
//
|
|
// is the buffer big enough
|
|
//
|
|
if (Urb->UrbControlDescriptorRequest.TransferBufferLength < sizeof(USB_DEVICE_DESCRIPTOR))
|
|
{
|
|
//
|
|
// invalid buffer size
|
|
//
|
|
DPRINT1("[USBCCGP] invalid device descriptor size %lu\n", Urb->UrbControlDescriptorRequest.TransferBufferLength);
|
|
Urb->UrbControlDescriptorRequest.TransferBufferLength = sizeof(USB_DEVICE_DESCRIPTOR);
|
|
Irp->IoStatus.Status = STATUS_INVALID_BUFFER_SIZE;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_INVALID_BUFFER_SIZE;
|
|
}
|
|
|
|
//
|
|
// copy device descriptor
|
|
//
|
|
ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
|
|
RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer, &PDODeviceExtension->DeviceDescriptor, sizeof(USB_DEVICE_DESCRIPTOR));
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
else if (Urb->UrbControlDescriptorRequest.DescriptorType == USB_CONFIGURATION_DESCRIPTOR_TYPE)
|
|
{
|
|
//
|
|
// build configuration descriptor
|
|
//
|
|
Status = USBCCGP_BuildConfigurationDescriptor(DeviceObject, Irp);
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|
|
else if (Urb->UrbControlDescriptorRequest.DescriptorType == USB_STRING_DESCRIPTOR_TYPE)
|
|
{
|
|
PUSB_STRING_DESCRIPTOR StringDescriptor;
|
|
|
|
//
|
|
// get the requested string descriptor
|
|
//
|
|
ASSERT(Urb->UrbControlDescriptorRequest.TransferBuffer);
|
|
Status = USBCCGP_GetDescriptor(PDODeviceExtension->FDODeviceExtension->NextDeviceObject,
|
|
USB_STRING_DESCRIPTOR_TYPE,
|
|
Urb->UrbControlDescriptorRequest.TransferBufferLength,
|
|
Urb->UrbControlDescriptorRequest.Index,
|
|
Urb->UrbControlDescriptorRequest.LanguageId,
|
|
(PVOID*)&StringDescriptor);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
if (StringDescriptor->bLength == 2)
|
|
{
|
|
FreeItem(StringDescriptor);
|
|
Status = STATUS_DEVICE_DATA_ERROR;
|
|
}
|
|
else
|
|
{
|
|
RtlCopyMemory(Urb->UrbControlDescriptorRequest.TransferBuffer,
|
|
StringDescriptor->bString,
|
|
StringDescriptor->bLength + sizeof(WCHAR));
|
|
FreeItem(StringDescriptor);
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
Irp->IoStatus.Status = Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
|
|
return Status;
|
|
}
|
|
}
|
|
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_GET_PORT_STATUS)
|
|
{
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
|
|
return Status;
|
|
}
|
|
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_RESET_PORT)
|
|
{
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
|
|
return Status;
|
|
}
|
|
else if (IoStack->Parameters.DeviceIoControl.IoControlCode == IOCTL_INTERNAL_USB_CYCLE_PORT)
|
|
{
|
|
IoSkipCurrentIrpStackLocation(Irp);
|
|
Status = IoCallDriver(PDODeviceExtension->NextDeviceObject, Irp);
|
|
return Status;
|
|
}
|
|
|
|
DPRINT1("IOCTL %x\n", IoStack->Parameters.DeviceIoControl.IoControlCode);
|
|
DPRINT1("InputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.InputBufferLength);
|
|
DPRINT1("OutputBufferLength %lu\n", IoStack->Parameters.DeviceIoControl.OutputBufferLength);
|
|
DPRINT1("Type3InputBuffer %p\n", IoStack->Parameters.DeviceIoControl.Type3InputBuffer);
|
|
|
|
ASSERT(FALSE);
|
|
|
|
Irp->IoStatus.Status = STATUS_NOT_IMPLEMENTED;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
PDO_Dispatch(
|
|
PDEVICE_OBJECT DeviceObject,
|
|
PIRP Irp)
|
|
{
|
|
PIO_STACK_LOCATION IoStack;
|
|
NTSTATUS Status;
|
|
|
|
/* get stack location */
|
|
IoStack = IoGetCurrentIrpStackLocation(Irp);
|
|
|
|
switch(IoStack->MajorFunction)
|
|
{
|
|
case IRP_MJ_PNP:
|
|
return PDO_HandlePnp(DeviceObject, Irp);
|
|
case IRP_MJ_INTERNAL_DEVICE_CONTROL:
|
|
return PDO_HandleInternalDeviceControl(DeviceObject, Irp);
|
|
case IRP_MJ_POWER:
|
|
PoStartNextPowerIrp(Irp);
|
|
Irp->IoStatus.Status = STATUS_SUCCESS;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return STATUS_SUCCESS;
|
|
default:
|
|
DPRINT1("PDO_Dispatch Function %x not implemented\n", IoStack->MajorFunction);
|
|
Status = Irp->IoStatus.Status;
|
|
IoCompleteRequest(Irp, IO_NO_INCREMENT);
|
|
return Status;
|
|
}
|
|
}
|