reactos/drivers/usb/usbccgp/pdo.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;
}
}