/* * Copyright (C) 2010 Damjan Jovanovic * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include <stdarg.h> #define NONAMELESSUNION #include "ntstatus.h" #define WIN32_NO_STATUS #include "windef.h" #include "winbase.h" #include "winternl.h" #include "ddk/wdm.h" #include "ddk/usb.h" #include "ddk/usbdlib.h" #include "wine/debug.h" WINE_DEFAULT_DEBUG_CHANNEL(usbd); PURB WINAPI USBD_CreateConfigurationRequest( PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, PUSHORT Siz ) { URB *urb = NULL; USBD_INTERFACE_LIST_ENTRY *interfaceList; ULONG interfaceListSize; USB_INTERFACE_DESCRIPTOR *interfaceDesc; int i; TRACE( "(%p, %p)\n", ConfigurationDescriptor, Siz ); /* http://www.microsoft.com/whdc/archive/usbfaq.mspx * claims USBD_CreateConfigurationRequest doesn't support > 1 interface, * but is this on Windows 98 only or all versions? */ *Siz = 0; interfaceListSize = (ConfigurationDescriptor->bNumInterfaces + 1) * sizeof(USBD_INTERFACE_LIST_ENTRY); interfaceList = ExAllocatePool( NonPagedPool, interfaceListSize ); if (interfaceList) { RtlZeroMemory( interfaceList, interfaceListSize ); interfaceDesc = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors( ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, ConfigurationDescriptor, USB_INTERFACE_DESCRIPTOR_TYPE ); for (i = 0; i < ConfigurationDescriptor->bNumInterfaces && interfaceDesc != NULL; i++) { interfaceList[i].InterfaceDescriptor = interfaceDesc; interfaceDesc = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors( ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, interfaceDesc + 1, USB_INTERFACE_DESCRIPTOR_TYPE ); } urb = USBD_CreateConfigurationRequestEx( ConfigurationDescriptor, interfaceList ); if (urb) *Siz = urb->u.UrbHeader.Length; ExFreePool( interfaceList ); } return urb; } PURB WINAPI USBD_CreateConfigurationRequestEx( PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, PUSBD_INTERFACE_LIST_ENTRY InterfaceList ) { URB *urb; ULONG size = 0; USBD_INTERFACE_LIST_ENTRY *interfaceEntry; ULONG interfaceCount = 0; TRACE( "(%p, %p)\n", ConfigurationDescriptor, InterfaceList ); size = sizeof(struct _URB_SELECT_CONFIGURATION); for (interfaceEntry = InterfaceList; interfaceEntry->InterfaceDescriptor; interfaceEntry++) { ++interfaceCount; size += (interfaceEntry->InterfaceDescriptor->bNumEndpoints - 1) * sizeof(USBD_PIPE_INFORMATION); } size += (interfaceCount - 1) * sizeof(USBD_INTERFACE_INFORMATION); urb = ExAllocatePool( NonPagedPool, size ); if (urb) { USBD_INTERFACE_INFORMATION *interfaceInfo; RtlZeroMemory( urb, size ); urb->u.UrbSelectConfiguration.Hdr.Length = size; urb->u.UrbSelectConfiguration.Hdr.Function = URB_FUNCTION_SELECT_CONFIGURATION; urb->u.UrbSelectConfiguration.ConfigurationDescriptor = ConfigurationDescriptor; interfaceInfo = &urb->u.UrbSelectConfiguration.Interface; for (interfaceEntry = InterfaceList; interfaceEntry->InterfaceDescriptor; interfaceEntry++) { ULONG i; USB_INTERFACE_DESCRIPTOR *currentInterface; USB_ENDPOINT_DESCRIPTOR *endpointDescriptor; interfaceInfo->InterfaceNumber = interfaceEntry->InterfaceDescriptor->bInterfaceNumber; interfaceInfo->AlternateSetting = interfaceEntry->InterfaceDescriptor->bAlternateSetting; interfaceInfo->Class = interfaceEntry->InterfaceDescriptor->bInterfaceClass; interfaceInfo->SubClass = interfaceEntry->InterfaceDescriptor->bInterfaceSubClass; interfaceInfo->Protocol = interfaceEntry->InterfaceDescriptor->bInterfaceProtocol; interfaceInfo->NumberOfPipes = interfaceEntry->InterfaceDescriptor->bNumEndpoints; currentInterface = USBD_ParseConfigurationDescriptorEx( ConfigurationDescriptor, ConfigurationDescriptor, interfaceEntry->InterfaceDescriptor->bInterfaceNumber, -1, -1, -1, -1 ); endpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) USBD_ParseDescriptors( ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, currentInterface, USB_ENDPOINT_DESCRIPTOR_TYPE ); for (i = 0; i < interfaceInfo->NumberOfPipes && endpointDescriptor; i++) { interfaceInfo->Pipes[i].MaximumPacketSize = endpointDescriptor->wMaxPacketSize; interfaceInfo->Pipes[i].EndpointAddress = endpointDescriptor->bEndpointAddress; interfaceInfo->Pipes[i].Interval = endpointDescriptor->bInterval; switch (endpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) { case USB_ENDPOINT_TYPE_CONTROL: interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeControl; break; case USB_ENDPOINT_TYPE_BULK: interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeBulk; break; case USB_ENDPOINT_TYPE_INTERRUPT: interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeInterrupt; break; case USB_ENDPOINT_TYPE_ISOCHRONOUS: interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeIsochronous; break; } endpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) USBD_ParseDescriptors( ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, endpointDescriptor + 1, USB_ENDPOINT_DESCRIPTOR_TYPE ); } interfaceInfo->Length = sizeof(USBD_INTERFACE_INFORMATION) + (i - 1) * sizeof(USBD_PIPE_INFORMATION); interfaceEntry->Interface = interfaceInfo; interfaceInfo = (USBD_INTERFACE_INFORMATION*)(((char*)interfaceInfo)+interfaceInfo->Length); } } return urb; } VOID WINAPI USBD_GetUSBDIVersion( PUSBD_VERSION_INFORMATION VersionInformation ) { TRACE( "(%p)\n", VersionInformation ); /* Emulate Windows 2000 (= 0x300) for now */ VersionInformation->USBDI_Version = 0x300; VersionInformation->Supported_USB_Version = 0x200; } PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptorEx( PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, PVOID StartPosition, LONG InterfaceNumber, LONG AlternateSetting, LONG InterfaceClass, LONG InterfaceSubClass, LONG InterfaceProtocol ) { /* http://blogs.msdn.com/usbcoreblog/archive/2009/12/12/ * what-is-the-right-way-to-validate-and-parse-configuration-descriptors.aspx */ PUSB_INTERFACE_DESCRIPTOR interface; TRACE( "(%p, %p, %d, %d, %d, %d, %d)\n", ConfigurationDescriptor, StartPosition, InterfaceNumber, AlternateSetting, InterfaceClass, InterfaceSubClass, InterfaceProtocol ); interface = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors( ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, StartPosition, USB_INTERFACE_DESCRIPTOR_TYPE ); while (interface != NULL) { if ((InterfaceNumber == -1 || interface->bInterfaceNumber == InterfaceNumber) && (AlternateSetting == -1 || interface->bAlternateSetting == AlternateSetting) && (InterfaceClass == -1 || interface->bInterfaceClass == InterfaceClass) && (InterfaceSubClass == -1 || interface->bInterfaceSubClass == InterfaceSubClass) && (InterfaceProtocol == -1 || interface->bInterfaceProtocol == InterfaceProtocol)) { return interface; } interface = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors( ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength, interface + 1, USB_INTERFACE_DESCRIPTOR_TYPE ); } return NULL; } PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptor( PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, UCHAR InterfaceNumber, UCHAR AlternateSetting ) { TRACE( "(%p, %u, %u)\n", ConfigurationDescriptor, InterfaceNumber, AlternateSetting ); return USBD_ParseConfigurationDescriptorEx( ConfigurationDescriptor, ConfigurationDescriptor, InterfaceNumber, AlternateSetting, -1, -1, -1 ); } PUSB_COMMON_DESCRIPTOR WINAPI USBD_ParseDescriptors( PVOID DescriptorBuffer, ULONG TotalLength, PVOID StartPosition, LONG DescriptorType ) { PUSB_COMMON_DESCRIPTOR common; TRACE( "(%p, %u, %p, %d)\n", DescriptorBuffer, TotalLength, StartPosition, DescriptorType ); for (common = (PUSB_COMMON_DESCRIPTOR)DescriptorBuffer; ((char*)common) + sizeof(USB_COMMON_DESCRIPTOR) <= ((char*)DescriptorBuffer) + TotalLength; common = (PUSB_COMMON_DESCRIPTOR)(((char*)common) + common->bLength)) { if (StartPosition <= (PVOID)common && common->bDescriptorType == DescriptorType) return common; } return NULL; } USBD_STATUS WINAPI USBD_ValidateConfigurationDescriptor( PUSB_CONFIGURATION_DESCRIPTOR descr, ULONG length, USHORT level, PUCHAR *offset, ULONG tag ) { FIXME( "(%p, %u, %u, %p, %u) partial stub!\n", descr, length, level, offset, tag ); if (offset) *offset = 0; if (!descr || length < sizeof(USB_CONFIGURATION_DESCRIPTOR) || descr->bLength < sizeof(USB_CONFIGURATION_DESCRIPTOR) || descr->wTotalLength < descr->bNumInterfaces * sizeof(USB_CONFIGURATION_DESCRIPTOR) ) return USBD_STATUS_ERROR; return USBD_STATUS_SUCCESS; } ULONG WINAPI USBD_GetInterfaceLength( PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor, PUCHAR BufferEnd ) { PUSB_COMMON_DESCRIPTOR common; ULONG total = InterfaceDescriptor->bLength; TRACE( "(%p, %p)\n", InterfaceDescriptor, BufferEnd ); for (common = (PUSB_COMMON_DESCRIPTOR)(InterfaceDescriptor + 1); (((PUCHAR)common) + sizeof(USB_COMMON_DESCRIPTOR)) <= BufferEnd && common->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE; common = (PUSB_COMMON_DESCRIPTOR)(((char*)common) + common->bLength)) { total += common->bLength; } return total; } NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path ) { TRACE( "(%p, %s)\n", driver, debugstr_w(path->Buffer) ); return STATUS_SUCCESS; }