|  | /* | 
|  | * 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 | 
|  | #define NONAMELESSSTRUCT | 
|  |  | 
|  | #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++) | 
|  | { | 
|  | int 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_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; | 
|  | } | 
|  |  | 
|  | 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; | 
|  | } |