reactos/drivers/usb/usbhub/fdo.c
Timo Kreuzer 6afbc8f483 Hopefully create a branch and not destroy the svn repository.
svn path=/branches/reactos-yarotows/; revision=45219
2010-01-23 23:25:04 +00:00

503 lines
16 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: USB hub driver
* FILE: drivers/usb/cromwell/hub/fdo.c
* PURPOSE: IRP_MJ_PNP operations for FDOs
*
* PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.com)
*/
#define INITGUID
#define NDEBUG
#include "usbhub.h"
#define IO_METHOD_FROM_CTL_CODE(ctlCode) (ctlCode&0x00000003)
static VOID
UsbhubGetUserBuffers(
IN PIRP Irp,
IN ULONG IoControlCode,
OUT PVOID* BufferIn,
OUT PVOID* BufferOut)
{
ASSERT(Irp);
ASSERT(BufferIn);
ASSERT(BufferOut);
switch (IO_METHOD_FROM_CTL_CODE(IoControlCode))
{
case METHOD_BUFFERED:
*BufferIn = *BufferOut = Irp->AssociatedIrp.SystemBuffer;
break;
case METHOD_IN_DIRECT:
case METHOD_OUT_DIRECT:
*BufferIn = Irp->AssociatedIrp.SystemBuffer;
*BufferOut = MmGetSystemAddressForMdl(Irp->MdlAddress);
break;
case METHOD_NEITHER:
*BufferIn = IoGetCurrentIrpStackLocation(Irp)->Parameters.DeviceIoControl.Type3InputBuffer;
*BufferOut = Irp->UserBuffer;
break;
default:
/* Should never happen */
*BufferIn = NULL;
*BufferOut = NULL;
break;
}
}
static NTSTATUS
UsbhubFdoQueryBusRelations(
IN PDEVICE_OBJECT DeviceObject,
OUT PDEVICE_RELATIONS* pDeviceRelations)
{
PHUB_DEVICE_EXTENSION DeviceExtension;
PDEVICE_RELATIONS DeviceRelations;
PDEVICE_OBJECT Pdo;
PHUB_DEVICE_EXTENSION PdoExtension;
struct usb_device* dev;
ULONG i;
ULONG Children = 0;
ULONG NeededSize;
NTSTATUS Status;
CHAR Buffer[3][40];
DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
dev = DeviceExtension->dev;
/* Create PDOs that are missing */
for (i = 0; i < dev->maxchild; i++)
{
if (dev->children[i] == NULL)
{
/* No child device at this place */
continue;
}
Children++;
if (DeviceExtension->Children[i] != NULL)
{
/* PDO already exists */
continue;
}
/* Need to create the PDO */
Status = IoCreateDevice(
DeviceObject->DriverObject,
sizeof(HUB_DEVICE_EXTENSION),
NULL, /* Device name */
FILE_DEVICE_CONTROLLER,
FILE_AUTOGENERATED_DEVICE_NAME,
FALSE,
&DeviceExtension->Children[i]);
if (!NT_SUCCESS(Status))
{
DPRINT("Usbhub: IoCreateDevice() failed with status 0x%08lx\n", Status);
return Status;
}
Pdo = DeviceExtension->Children[i];
Pdo->Flags |= DO_BUS_ENUMERATED_DEVICE;
PdoExtension = Pdo->DeviceExtension;
RtlZeroMemory(PdoExtension, sizeof(HUB_DEVICE_EXTENSION));
PdoExtension->IsFDO = FALSE;
PdoExtension->dev = dev->children[i];
sprintf(Buffer[0], "%lu", i);
Status = UsbhubInitMultiSzString(
&PdoExtension->InstanceId,
Buffer[0], NULL);
if (!NT_SUCCESS(Status))
goto ByeBye;
DPRINT1("child #%lu: USB\\Vid_%04x&Pid_%04x&Rev_%04x\n",
i,
PdoExtension->dev->descriptor.idVendor,
PdoExtension->dev->descriptor.idProduct,
PdoExtension->dev->descriptor.bcdDevice);
sprintf(Buffer[0], "USB\\Vid_%04x&Pid_%04x&Rev_%04x",
PdoExtension->dev->descriptor.idVendor,
PdoExtension->dev->descriptor.idProduct,
PdoExtension->dev->descriptor.bcdDevice);
sprintf(Buffer[1], "USB\\Vid_%04x&Pid_%04x",
PdoExtension->dev->descriptor.idVendor,
PdoExtension->dev->descriptor.idProduct);
Status = UsbhubInitMultiSzString(
&PdoExtension->HardwareIds,
Buffer[0], Buffer[1], NULL);
if (!NT_SUCCESS(Status))
goto ByeBye;
Status = UsbhubInitMultiSzString(
&PdoExtension->DeviceId,
Buffer[1], NULL);
if (!NT_SUCCESS(Status))
goto ByeBye;
if (PdoExtension->dev->actconfig->desc.bNumInterfaces == 1)
{
/* Single-interface USB device */
if (PdoExtension->dev->descriptor.bDeviceClass != 0)
{
/* Use these values for device class/sub class/protocol */
sprintf(Buffer[0], "USB\\Class_%02x&SubClass_%02x&Prot_%02x",
PdoExtension->dev->descriptor.bDeviceClass,
PdoExtension->dev->descriptor.bDeviceSubClass,
PdoExtension->dev->descriptor.bDeviceProtocol);
sprintf(Buffer[1], "USB\\Class_%02x&SubClass_%02x",
PdoExtension->dev->descriptor.bDeviceClass,
PdoExtension->dev->descriptor.bDeviceSubClass);
sprintf(Buffer[2], "USB\\Class_%02x",
PdoExtension->dev->descriptor.bDeviceClass);
}
else
{
/* Use values specified in the interface descriptor */
struct usb_host_interface *itf = PdoExtension->dev->actconfig->interface->altsetting;
sprintf(Buffer[0], "USB\\Class_%02x&SubClass_%02x&Prot_%02x",
itf->desc.bInterfaceClass,
itf->desc.bInterfaceSubClass,
itf->desc.bInterfaceProtocol);
sprintf(Buffer[1], "USB\\Class_%02x&SubClass_%02x",
itf->desc.bInterfaceClass,
itf->desc.bInterfaceSubClass);
sprintf(Buffer[2], "USB\\Class_%02x",
itf->desc.bInterfaceClass);
}
Status = UsbhubInitMultiSzString(
&PdoExtension->CompatibleIds,
Buffer[0], Buffer[1], Buffer[2], NULL);
}
else
{
/* Multiple-interface USB device */
sprintf(Buffer[0], "USB\\DevClass_%02x&SubClass_%02x&Prot_%02x",
PdoExtension->dev->descriptor.bDeviceClass,
PdoExtension->dev->descriptor.bDeviceSubClass,
PdoExtension->dev->descriptor.bDeviceProtocol);
sprintf(Buffer[1], "USB\\DevClass_%02x&SubClass_%02x",
PdoExtension->dev->descriptor.bDeviceClass,
PdoExtension->dev->descriptor.bDeviceSubClass);
sprintf(Buffer[2], "USB\\DevClass_%02x",
PdoExtension->dev->descriptor.bDeviceClass);
Status = UsbhubInitMultiSzString(
&PdoExtension->CompatibleIds,
Buffer[0], Buffer[1], Buffer[2], "USB\\COMPOSITE", NULL);
}
if (!NT_SUCCESS(Status))
goto ByeBye;
Pdo->Flags &= ~DO_DEVICE_INITIALIZING;
}
/* Fill returned structure */
NeededSize = sizeof(DEVICE_RELATIONS);
if (Children > 1)
NeededSize += (Children - 1) * sizeof(PDEVICE_OBJECT);
DeviceRelations = (PDEVICE_RELATIONS)ExAllocatePool(
PagedPool,
NeededSize);
if (!DeviceRelations)
return STATUS_INSUFFICIENT_RESOURCES;
DeviceRelations->Count = Children;
Children = 0;
for (i = 0; i < USB_MAXCHILDREN; i++)
{
if (DeviceExtension->Children[i])
{
ObReferenceObject(DeviceExtension->Children[i]);
DeviceRelations->Objects[Children++] = DeviceExtension->Children[i];
}
}
ASSERT(Children == DeviceRelations->Count);
*pDeviceRelations = DeviceRelations;
return STATUS_SUCCESS;
ByeBye:
RtlFreeUnicodeString(&PdoExtension->DeviceId);
RtlFreeUnicodeString(&PdoExtension->InstanceId);
RtlFreeUnicodeString(&PdoExtension->HardwareIds);
RtlFreeUnicodeString(&PdoExtension->CompatibleIds);
IoDeleteDevice(Pdo);
return Status;
}
NTSTATUS NTAPI
UsbhubPnpFdo(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION IrpSp;
NTSTATUS Status;
ULONG MinorFunction;
ULONG_PTR Information = 0;
IrpSp = IoGetCurrentIrpStackLocation(Irp);
MinorFunction = IrpSp->MinorFunction;
switch (MinorFunction)
{
case IRP_MN_START_DEVICE: /* 0x0 */
{
DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_START_DEVICE\n");
Status = ForwardIrpAndWait(DeviceObject, Irp);
break;
}
case IRP_MN_QUERY_DEVICE_RELATIONS: /* (optional) 0x7 */
{
switch (IrpSp->Parameters.QueryDeviceRelations.Type)
{
case BusRelations:
{
PDEVICE_RELATIONS DeviceRelations = NULL;
DPRINT("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / BusRelations\n");
Status = UsbhubFdoQueryBusRelations(DeviceObject, &DeviceRelations);
Information = (ULONG_PTR)DeviceRelations;
break;
}
case RemovalRelations:
{
DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / RemovalRelations\n");
return ForwardIrpAndForget(DeviceObject, Irp);
}
default:
DPRINT1("Usbhub: IRP_MJ_PNP / IRP_MN_QUERY_DEVICE_RELATIONS / Unknown type 0x%lx\n",
IrpSp->Parameters.QueryDeviceRelations.Type);
return ForwardIrpAndForget(DeviceObject, Irp);
}
break;
}
default:
{
DPRINT1("Usbhub: IRP_MJ_PNP / unknown minor function 0x%lx\n", MinorFunction);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
Irp->IoStatus.Information = Information;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}
NTSTATUS
UsbhubDeviceControlFdo(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PIO_STACK_LOCATION Stack;
ULONG IoControlCode;
PHUB_DEVICE_EXTENSION DeviceExtension;
ULONG LengthIn, LengthOut;
ULONG_PTR Information = 0;
PVOID BufferIn, BufferOut;
NTSTATUS Status;
Stack = IoGetCurrentIrpStackLocation(Irp);
LengthIn = Stack->Parameters.DeviceIoControl.InputBufferLength;
LengthOut = Stack->Parameters.DeviceIoControl.OutputBufferLength;
DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
IoControlCode = Stack->Parameters.DeviceIoControl.IoControlCode;
UsbhubGetUserBuffers(Irp, IoControlCode, &BufferIn, &BufferOut);
switch (IoControlCode)
{
case IOCTL_USB_GET_NODE_INFORMATION:
{
PUSB_NODE_INFORMATION NodeInformation;
struct usb_device* dev;
DPRINT("Usbhub: IOCTL_USB_GET_NODE_INFORMATION\n");
if (LengthOut < sizeof(USB_NODE_INFORMATION))
Status = STATUS_BUFFER_TOO_SMALL;
else if (BufferOut == NULL)
Status = STATUS_INVALID_PARAMETER;
else
{
NodeInformation = (PUSB_NODE_INFORMATION)BufferOut;
dev = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->dev;
NodeInformation->NodeType = UsbHub;
RtlCopyMemory(
&NodeInformation->u.HubInformation.HubDescriptor,
((struct usb_hub *)usb_get_intfdata(to_usb_interface(&dev->actconfig->interface[0].dev)))->descriptor,
sizeof(USB_HUB_DESCRIPTOR));
NodeInformation->u.HubInformation.HubIsBusPowered = dev->actconfig->desc.bmAttributes & 0x80;
Information = sizeof(USB_NODE_INFORMATION);
Status = STATUS_SUCCESS;
}
break;
}
case IOCTL_USB_GET_NODE_CONNECTION_NAME:
{
PHUB_DEVICE_EXTENSION DeviceExtension;
PUSB_NODE_CONNECTION_NAME ConnectionName;
DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
ConnectionName = (PUSB_NODE_CONNECTION_NAME)BufferOut;
DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_NAME\n");
if (LengthOut < sizeof(USB_NODE_CONNECTION_NAME))
Status = STATUS_BUFFER_TOO_SMALL;
else if (BufferOut == NULL)
Status = STATUS_INVALID_PARAMETER;
else if (ConnectionName->ConnectionIndex < 1
|| ConnectionName->ConnectionIndex > USB_MAXCHILDREN)
Status = STATUS_INVALID_PARAMETER;
else if (DeviceExtension->Children[ConnectionName->ConnectionIndex - 1] == NULL)
Status = STATUS_INVALID_PARAMETER;
else
{
ULONG NeededStructureSize;
DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceExtension->Children[ConnectionName->ConnectionIndex - 1]->DeviceExtension;
NeededStructureSize = DeviceExtension->SymbolicLinkName.Length + sizeof(UNICODE_NULL) + FIELD_OFFSET(USB_NODE_CONNECTION_NAME, NodeName);
if (ConnectionName->ActualLength < NeededStructureSize / sizeof(WCHAR)
|| LengthOut < NeededStructureSize)
{
/* Buffer too small */
ConnectionName->ActualLength = NeededStructureSize / sizeof(WCHAR);
Information = sizeof(USB_NODE_CONNECTION_NAME);
Status = STATUS_BUFFER_TOO_SMALL;
}
else
{
RtlCopyMemory(
ConnectionName->NodeName,
DeviceExtension->SymbolicLinkName.Buffer,
DeviceExtension->SymbolicLinkName.Length);
ConnectionName->NodeName[DeviceExtension->SymbolicLinkName.Length / sizeof(WCHAR)] = UNICODE_NULL;
DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_NAME returns '%S'\n", ConnectionName->NodeName);
ConnectionName->ActualLength = NeededStructureSize / sizeof(WCHAR);
Information = NeededStructureSize;
Status = STATUS_SUCCESS;
}
Information = LengthOut;
}
break;
}
case IOCTL_USB_GET_NODE_CONNECTION_INFORMATION:
{
PUSB_NODE_CONNECTION_INFORMATION ConnectionInformation;
ULONG i, j, k;
struct usb_device* dev;
ULONG NumberOfOpenPipes = 0;
ULONG SizeOfOpenPipesArray;
ConnectionInformation = (PUSB_NODE_CONNECTION_INFORMATION)BufferOut;
DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_INFORMATION\n");
if (LengthOut < sizeof(USB_NODE_CONNECTION_INFORMATION))
Status = STATUS_BUFFER_TOO_SMALL;
else if (BufferOut == NULL)
Status = STATUS_INVALID_PARAMETER;
else if (ConnectionInformation->ConnectionIndex < 1
|| ConnectionInformation->ConnectionIndex > USB_MAXCHILDREN)
Status = STATUS_INVALID_PARAMETER;
else
{
dev = ((PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension)->dev;
dev = dev->children[ConnectionInformation->ConnectionIndex - 1];
if (dev == NULL)
{
/* No device connected to this port */
RtlZeroMemory(
&ConnectionInformation->DeviceDescriptor,
sizeof(USB_NODE_CONNECTION_INFORMATION) - FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION, DeviceDescriptor));
ConnectionInformation->ConnectionStatus = NoDeviceConnected;
Information = sizeof(USB_NODE_CONNECTION_INFORMATION);
Status = STATUS_SUCCESS;
break;
}
SizeOfOpenPipesArray = (LengthOut - FIELD_OFFSET(USB_NODE_CONNECTION_INFORMATION, PipeList)) / sizeof(USB_PIPE_INFO);
RtlCopyMemory(
&ConnectionInformation->DeviceDescriptor,
&dev->descriptor,
sizeof(USB_DEVICE_DESCRIPTOR));
ConnectionInformation->CurrentConfigurationValue = dev->actconfig->desc.bConfigurationValue;
ConnectionInformation->LowSpeed = dev->speed == USB_SPEED_LOW || dev->speed == USB_SPEED_FULL;
ConnectionInformation->DeviceIsHub = dev->descriptor.bDeviceClass == USB_CLASS_HUB;
ConnectionInformation->DeviceAddress = dev->devnum;
ConnectionInformation->ConnectionStatus = DeviceConnected;
for (i = 0; i < dev->actconfig->desc.bNumInterfaces; i++)
for (j = 0; j < dev->actconfig->interface[i].num_altsetting; j++)
for (k = 0; k < dev->actconfig->interface[i].altsetting[j].desc.bNumEndpoints; k++)
{
if (NumberOfOpenPipes < SizeOfOpenPipesArray)
{
PUSB_PIPE_INFO Pipe = &ConnectionInformation->PipeList[NumberOfOpenPipes];
struct usb_host_endpoint* endpoint = &dev->actconfig->interface[i].altsetting[j].endpoint[k];
RtlCopyMemory(
&Pipe->EndpointDescriptor,
&endpoint->desc,
endpoint->desc.bLength);
Pipe->ScheduleOffset = 0; /* FIXME */
}
NumberOfOpenPipes++;
}
ConnectionInformation->NumberOfOpenPipes = NumberOfOpenPipes;
Information = sizeof(USB_NODE_CONNECTION_INFORMATION);
if (NumberOfOpenPipes <= SizeOfOpenPipesArray)
Status = STATUS_SUCCESS;
else
Status = STATUS_BUFFER_OVERFLOW;
}
break;
}
case IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION:
{
//PUSB_DESCRIPTOR_REQUEST Descriptor;
DPRINT("Usbhub: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION\n");
DPRINT1("Usbhub: IOCTL_USB_GET_DESCRIPTOR_FROM_NODE_CONNECTION unimplemented\n");
Information = 0;
Status = STATUS_NOT_IMPLEMENTED;
break;
}
case IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME:
{
PHUB_DEVICE_EXTENSION DeviceExtension;
PUSB_NODE_CONNECTION_DRIVERKEY_NAME StringDescriptor;
DPRINT("Usbhub: IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME\n");
DeviceExtension = (PHUB_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
StringDescriptor = (PUSB_NODE_CONNECTION_DRIVERKEY_NAME)BufferOut;
if (LengthOut < sizeof(USB_NODE_CONNECTION_DRIVERKEY_NAME))
Status = STATUS_BUFFER_TOO_SMALL;
else if (StringDescriptor == NULL)
Status = STATUS_INVALID_PARAMETER;
else if (StringDescriptor->ConnectionIndex < 1
|| StringDescriptor->ConnectionIndex > USB_MAXCHILDREN)
Status = STATUS_INVALID_PARAMETER;
else if (DeviceExtension->Children[StringDescriptor->ConnectionIndex - 1] == NULL)
Status = STATUS_INVALID_PARAMETER;
else
{
ULONG StringSize;
Status = IoGetDeviceProperty(
DeviceExtension->Children[StringDescriptor->ConnectionIndex - 1],
DevicePropertyDriverKeyName,
LengthOut - FIELD_OFFSET(USB_NODE_CONNECTION_DRIVERKEY_NAME, DriverKeyName),
StringDescriptor->DriverKeyName,
&StringSize);
if (NT_SUCCESS(Status) || Status == STATUS_BUFFER_TOO_SMALL)
{
StringDescriptor->ActualLength = StringSize + FIELD_OFFSET(USB_NODE_CONNECTION_DRIVERKEY_NAME, DriverKeyName);
Information = LengthOut;
Status = STATUS_SUCCESS;
}
}
break;
}
default:
{
/* Pass Irp to lower driver */
DPRINT1("Usbhub: Unknown IOCTL code 0x%lx\n", Stack->Parameters.DeviceIoControl.IoControlCode);
return ForwardIrpAndForget(DeviceObject, Irp);
}
}
Irp->IoStatus.Information = Information;
Irp->IoStatus.Status = Status;
IoCompleteRequest(Irp, IO_NO_INCREMENT);
return Status;
}