mmdevapi: Add support for IAudioRenderClient.
[wine] / dlls / usbd.sys / usbd.c
1 /*
2  * Copyright (C) 2010 Damjan Jovanovic
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include <stdarg.h>
20
21 #define NONAMELESSUNION
22 #define NONAMELESSSTRUCT
23
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winternl.h"
29 #include "ddk/wdm.h"
30 #include "ddk/usb.h"
31 #include "ddk/usbdlib.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(usbd);
35
36 PURB WINAPI USBD_CreateConfigurationRequest(
37         PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor, PUSHORT Siz )
38 {
39     URB *urb = NULL;
40     USBD_INTERFACE_LIST_ENTRY *interfaceList;
41     ULONG interfaceListSize;
42     USB_INTERFACE_DESCRIPTOR *interfaceDesc;
43     int i;
44
45     TRACE( "(%p, %p)\n", ConfigurationDescriptor, Siz );
46
47     /* http://www.microsoft.com/whdc/archive/usbfaq.mspx
48      * claims USBD_CreateConfigurationRequest doesn't support > 1 interface,
49      * but is this on Windows 98 only or all versions?
50      */
51
52     *Siz = 0;
53     interfaceListSize = (ConfigurationDescriptor->bNumInterfaces + 1) * sizeof(USBD_INTERFACE_LIST_ENTRY);
54     interfaceList = ExAllocatePool( NonPagedPool, interfaceListSize );
55     if (interfaceList)
56     {
57         RtlZeroMemory( interfaceList,  interfaceListSize );
58         interfaceDesc = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors(
59             ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength,
60             ConfigurationDescriptor, USB_INTERFACE_DESCRIPTOR_TYPE );
61         for (i = 0; i < ConfigurationDescriptor->bNumInterfaces && interfaceDesc != NULL; i++)
62         {
63             interfaceList[i].InterfaceDescriptor = interfaceDesc;
64             interfaceDesc = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors(
65                 ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength,
66                 interfaceDesc + 1, USB_INTERFACE_DESCRIPTOR_TYPE );
67         }
68         urb = USBD_CreateConfigurationRequestEx( ConfigurationDescriptor, interfaceList );
69         if (urb)
70             *Siz = urb->u.UrbHeader.Length;
71         ExFreePool( interfaceList );
72     }
73     return urb;
74 }
75
76 PURB WINAPI USBD_CreateConfigurationRequestEx(
77         PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
78         PUSBD_INTERFACE_LIST_ENTRY InterfaceList )
79 {
80     URB *urb;
81     ULONG size = 0;
82     USBD_INTERFACE_LIST_ENTRY *interfaceEntry;
83     ULONG interfaceCount = 0;
84
85     TRACE( "(%p, %p)\n", ConfigurationDescriptor, InterfaceList );
86
87     size = sizeof(struct _URB_SELECT_CONFIGURATION);
88     for (interfaceEntry = InterfaceList; interfaceEntry->InterfaceDescriptor; interfaceEntry++)
89     {
90         ++interfaceCount;
91         size += (interfaceEntry->InterfaceDescriptor->bNumEndpoints - 1) *
92             sizeof(USBD_PIPE_INFORMATION);
93     }
94     size += (interfaceCount - 1) * sizeof(USBD_INTERFACE_INFORMATION);
95
96     urb = ExAllocatePool( NonPagedPool, size );
97     if (urb)
98     {
99         USBD_INTERFACE_INFORMATION *interfaceInfo;
100
101         RtlZeroMemory( urb, size );
102         urb->u.UrbSelectConfiguration.Hdr.Length = size;
103         urb->u.UrbSelectConfiguration.Hdr.Function = URB_FUNCTION_SELECT_CONFIGURATION;
104         urb->u.UrbSelectConfiguration.ConfigurationDescriptor = ConfigurationDescriptor;
105         interfaceInfo = &urb->u.UrbSelectConfiguration.Interface;
106         for (interfaceEntry = InterfaceList; interfaceEntry->InterfaceDescriptor; interfaceEntry++)
107         {
108             int i;
109             USB_INTERFACE_DESCRIPTOR *currentInterface;
110             USB_ENDPOINT_DESCRIPTOR *endpointDescriptor;
111             interfaceInfo->InterfaceNumber = interfaceEntry->InterfaceDescriptor->bInterfaceNumber;
112             interfaceInfo->AlternateSetting = interfaceEntry->InterfaceDescriptor->bAlternateSetting;
113             interfaceInfo->Class = interfaceEntry->InterfaceDescriptor->bInterfaceClass;
114             interfaceInfo->SubClass = interfaceEntry->InterfaceDescriptor->bInterfaceSubClass;
115             interfaceInfo->Protocol = interfaceEntry->InterfaceDescriptor->bInterfaceProtocol;
116             interfaceInfo->NumberOfPipes = interfaceEntry->InterfaceDescriptor->bNumEndpoints;
117             currentInterface = USBD_ParseConfigurationDescriptorEx(
118                 ConfigurationDescriptor, ConfigurationDescriptor,
119                 interfaceEntry->InterfaceDescriptor->bInterfaceNumber, -1, -1, -1, -1 );
120             endpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) USBD_ParseDescriptors(
121                 ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength,
122                 currentInterface, USB_ENDPOINT_DESCRIPTOR_TYPE );
123             for (i = 0; i < interfaceInfo->NumberOfPipes && endpointDescriptor; i++)
124             {
125                 interfaceInfo->Pipes[i].MaximumPacketSize = endpointDescriptor->wMaxPacketSize;
126                 interfaceInfo->Pipes[i].EndpointAddress = endpointDescriptor->bEndpointAddress;
127                 interfaceInfo->Pipes[i].Interval = endpointDescriptor->bInterval;
128                 if (endpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_CONTROL)
129                     interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeControl;
130                 else if (endpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_BULK)
131                     interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeBulk;
132                 else if (endpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_INTERRUPT)
133                     interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeInterrupt;
134                 else if (endpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_ISOCHRONOUS)
135                     interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeIsochronous;
136                 endpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) USBD_ParseDescriptors(
137                     ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength,
138                     endpointDescriptor + 1, USB_ENDPOINT_DESCRIPTOR_TYPE );
139             }
140             interfaceInfo->Length = sizeof(USBD_INTERFACE_INFORMATION) +
141                 (i - 1) * sizeof(USBD_PIPE_INFORMATION);
142             interfaceEntry->Interface = interfaceInfo;
143             interfaceInfo = (USBD_INTERFACE_INFORMATION*)(((char*)interfaceInfo)+interfaceInfo->Length);
144         }
145     }
146     return urb;
147 }
148
149 VOID WINAPI USBD_GetUSBDIVersion(
150         PUSBD_VERSION_INFORMATION VersionInformation )
151 {
152     TRACE( "(%p)\n", VersionInformation );
153     /* Emulate Windows 2000 (= 0x300) for now */
154     VersionInformation->USBDI_Version = 0x300;
155     VersionInformation->Supported_USB_Version = 0x200;
156 }
157
158 PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptorEx(
159         PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
160         PVOID StartPosition, LONG InterfaceNumber,
161         LONG AlternateSetting, LONG InterfaceClass,
162         LONG InterfaceSubClass, LONG InterfaceProtocol )
163 {
164     /* http://blogs.msdn.com/usbcoreblog/archive/2009/12/12/
165      *        what-is-the-right-way-to-validate-and-parse-configuration-descriptors.aspx
166      */
167
168     PUSB_INTERFACE_DESCRIPTOR interface;
169
170     TRACE( "(%p, %p, %d, %d, %d, %d, %d)\n", ConfigurationDescriptor,
171             StartPosition, InterfaceNumber, AlternateSetting,
172             InterfaceClass, InterfaceSubClass, InterfaceProtocol );
173
174     interface = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors(
175         ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength,
176         StartPosition, USB_INTERFACE_DESCRIPTOR_TYPE );
177     while (interface != NULL)
178     {
179         if ((InterfaceNumber == -1 || interface->bInterfaceNumber == InterfaceNumber) &&
180             (AlternateSetting == -1 || interface->bAlternateSetting == AlternateSetting) &&
181             (InterfaceClass == -1 || interface->bInterfaceClass == InterfaceClass) &&
182             (InterfaceSubClass == -1 || interface->bInterfaceSubClass == InterfaceSubClass) &&
183             (InterfaceProtocol == -1 || interface->bInterfaceProtocol == InterfaceProtocol))
184         {
185             return interface;
186         }
187         interface = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors(
188             ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength,
189             interface + 1, USB_INTERFACE_DESCRIPTOR_TYPE );
190     }
191     return NULL;
192 }
193
194 PUSB_COMMON_DESCRIPTOR WINAPI USBD_ParseDescriptors(
195         PVOID DescriptorBuffer,
196         ULONG TotalLength,
197         PVOID StartPosition,
198         LONG DescriptorType )
199 {
200     PUSB_COMMON_DESCRIPTOR common;
201
202     TRACE( "(%p, %u, %p, %d)\n", DescriptorBuffer, TotalLength, StartPosition, DescriptorType );
203
204     for (common = (PUSB_COMMON_DESCRIPTOR)DescriptorBuffer;
205          ((char*)common) + sizeof(USB_COMMON_DESCRIPTOR) <= ((char*)DescriptorBuffer) + TotalLength;
206          common = (PUSB_COMMON_DESCRIPTOR)(((char*)common) + common->bLength))
207     {
208         if (StartPosition <= (PVOID)common && common->bDescriptorType == DescriptorType)
209             return common;
210     }
211     return NULL;
212 }
213
214 ULONG WINAPI USBD_GetInterfaceLength(
215         PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
216         PUCHAR BufferEnd )
217 {
218     PUSB_COMMON_DESCRIPTOR common;
219     ULONG total = InterfaceDescriptor->bLength;
220
221     TRACE( "(%p, %p)\n", InterfaceDescriptor, BufferEnd );
222
223     for (common = (PUSB_COMMON_DESCRIPTOR)(InterfaceDescriptor + 1);
224          (((PUCHAR)common) + sizeof(USB_COMMON_DESCRIPTOR)) <= BufferEnd &&
225              common->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE;
226          common = (PUSB_COMMON_DESCRIPTOR)(((char*)common) + common->bLength))
227     {
228         total += common->bLength;
229     }
230     return total;
231 }
232
233 NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
234 {
235     TRACE( "(%p, %s)\n", driver, debugstr_w(path->Buffer) );
236     return STATUS_SUCCESS;
237 }