/* * 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; }