atl80: Added AtlComModuleRegisterServer implementation (based on AtlModuleRegisterSer...
[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                 switch (endpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK)
129                 {
130                 case USB_ENDPOINT_TYPE_CONTROL:
131                     interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeControl;
132                     break;
133                 case USB_ENDPOINT_TYPE_BULK:
134                     interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeBulk;
135                     break;
136                 case USB_ENDPOINT_TYPE_INTERRUPT:
137                     interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeInterrupt;
138                     break;
139                 case USB_ENDPOINT_TYPE_ISOCHRONOUS:
140                     interfaceInfo->Pipes[i].PipeType = UsbdPipeTypeIsochronous;
141                     break;
142                 }
143                 endpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR) USBD_ParseDescriptors(
144                     ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength,
145                     endpointDescriptor + 1, USB_ENDPOINT_DESCRIPTOR_TYPE );
146             }
147             interfaceInfo->Length = sizeof(USBD_INTERFACE_INFORMATION) +
148                 (i - 1) * sizeof(USBD_PIPE_INFORMATION);
149             interfaceEntry->Interface = interfaceInfo;
150             interfaceInfo = (USBD_INTERFACE_INFORMATION*)(((char*)interfaceInfo)+interfaceInfo->Length);
151         }
152     }
153     return urb;
154 }
155
156 VOID WINAPI USBD_GetUSBDIVersion(
157         PUSBD_VERSION_INFORMATION VersionInformation )
158 {
159     TRACE( "(%p)\n", VersionInformation );
160     /* Emulate Windows 2000 (= 0x300) for now */
161     VersionInformation->USBDI_Version = 0x300;
162     VersionInformation->Supported_USB_Version = 0x200;
163 }
164
165 PUSB_INTERFACE_DESCRIPTOR WINAPI USBD_ParseConfigurationDescriptorEx(
166         PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
167         PVOID StartPosition, LONG InterfaceNumber,
168         LONG AlternateSetting, LONG InterfaceClass,
169         LONG InterfaceSubClass, LONG InterfaceProtocol )
170 {
171     /* http://blogs.msdn.com/usbcoreblog/archive/2009/12/12/
172      *        what-is-the-right-way-to-validate-and-parse-configuration-descriptors.aspx
173      */
174
175     PUSB_INTERFACE_DESCRIPTOR interface;
176
177     TRACE( "(%p, %p, %d, %d, %d, %d, %d)\n", ConfigurationDescriptor,
178             StartPosition, InterfaceNumber, AlternateSetting,
179             InterfaceClass, InterfaceSubClass, InterfaceProtocol );
180
181     interface = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors(
182         ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength,
183         StartPosition, USB_INTERFACE_DESCRIPTOR_TYPE );
184     while (interface != NULL)
185     {
186         if ((InterfaceNumber == -1 || interface->bInterfaceNumber == InterfaceNumber) &&
187             (AlternateSetting == -1 || interface->bAlternateSetting == AlternateSetting) &&
188             (InterfaceClass == -1 || interface->bInterfaceClass == InterfaceClass) &&
189             (InterfaceSubClass == -1 || interface->bInterfaceSubClass == InterfaceSubClass) &&
190             (InterfaceProtocol == -1 || interface->bInterfaceProtocol == InterfaceProtocol))
191         {
192             return interface;
193         }
194         interface = (PUSB_INTERFACE_DESCRIPTOR) USBD_ParseDescriptors(
195             ConfigurationDescriptor, ConfigurationDescriptor->wTotalLength,
196             interface + 1, USB_INTERFACE_DESCRIPTOR_TYPE );
197     }
198     return NULL;
199 }
200
201 PUSB_COMMON_DESCRIPTOR WINAPI USBD_ParseDescriptors(
202         PVOID DescriptorBuffer,
203         ULONG TotalLength,
204         PVOID StartPosition,
205         LONG DescriptorType )
206 {
207     PUSB_COMMON_DESCRIPTOR common;
208
209     TRACE( "(%p, %u, %p, %d)\n", DescriptorBuffer, TotalLength, StartPosition, DescriptorType );
210
211     for (common = (PUSB_COMMON_DESCRIPTOR)DescriptorBuffer;
212          ((char*)common) + sizeof(USB_COMMON_DESCRIPTOR) <= ((char*)DescriptorBuffer) + TotalLength;
213          common = (PUSB_COMMON_DESCRIPTOR)(((char*)common) + common->bLength))
214     {
215         if (StartPosition <= (PVOID)common && common->bDescriptorType == DescriptorType)
216             return common;
217     }
218     return NULL;
219 }
220
221 USBD_STATUS WINAPI USBD_ValidateConfigurationDescriptor(
222         PUSB_CONFIGURATION_DESCRIPTOR descr,
223         ULONG length,
224         USHORT level,
225         PUCHAR *offset,
226         ULONG tag )
227 {
228     FIXME( "(%p, %u, %u, %p, %u) partial stub!\n", descr, length, level, offset, tag );
229
230     if (offset) *offset = 0;
231
232     if (!descr ||
233         length < sizeof(USB_CONFIGURATION_DESCRIPTOR) ||
234         descr->bLength < sizeof(USB_CONFIGURATION_DESCRIPTOR) ||
235         descr->wTotalLength < descr->bNumInterfaces * sizeof(USB_CONFIGURATION_DESCRIPTOR)
236        ) return USBD_STATUS_ERROR;
237
238     return USBD_STATUS_SUCCESS;
239 }
240
241 ULONG WINAPI USBD_GetInterfaceLength(
242         PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor,
243         PUCHAR BufferEnd )
244 {
245     PUSB_COMMON_DESCRIPTOR common;
246     ULONG total = InterfaceDescriptor->bLength;
247
248     TRACE( "(%p, %p)\n", InterfaceDescriptor, BufferEnd );
249
250     for (common = (PUSB_COMMON_DESCRIPTOR)(InterfaceDescriptor + 1);
251          (((PUCHAR)common) + sizeof(USB_COMMON_DESCRIPTOR)) <= BufferEnd &&
252              common->bDescriptorType != USB_INTERFACE_DESCRIPTOR_TYPE;
253          common = (PUSB_COMMON_DESCRIPTOR)(((char*)common) + common->bLength))
254     {
255         total += common->bLength;
256     }
257     return total;
258 }
259
260 NTSTATUS WINAPI DriverEntry( DRIVER_OBJECT *driver, UNICODE_STRING *path )
261 {
262     TRACE( "(%p, %s)\n", driver, debugstr_w(path->Buffer) );
263     return STATUS_SUCCESS;
264 }