Sync with trunk r63502.
[reactos.git] / drivers / usb / usbccgp / descriptor.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Enhanced Host Controller Interface
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbccgp/descriptor.c
5 * PURPOSE: USB device driver.
6 * PROGRAMMERS:
7 * Michael Martin (michael.martin@reactos.org)
8 * Johannes Anderwald (johannes.anderwald@reactos.org)
9 * Cameron Gutman
10 */
11
12 #include "usbccgp.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 NTSTATUS
18 NTAPI
19 USBCCGP_GetDescriptor(
20 IN PDEVICE_OBJECT DeviceObject,
21 IN UCHAR DescriptorType,
22 IN ULONG DescriptorLength,
23 IN UCHAR DescriptorIndex,
24 IN LANGID LanguageId,
25 OUT PVOID *OutDescriptor)
26 {
27 PURB Urb;
28 NTSTATUS Status;
29 PVOID Descriptor;
30
31 //
32 // sanity checks
33 //
34 ASSERT(DeviceObject);
35 ASSERT(OutDescriptor);
36 ASSERT(DescriptorLength);
37
38 //
39 // first allocate descriptor buffer
40 //
41 Descriptor = AllocateItem(NonPagedPool, DescriptorLength);
42 if (!Descriptor)
43 {
44 //
45 // no memory
46 //
47 return STATUS_INSUFFICIENT_RESOURCES;
48 }
49
50 //
51 // allocate urb
52 //
53 Urb = (PURB) AllocateItem(NonPagedPool, sizeof(URB));
54 if (!Urb)
55 {
56 //
57 // no memory
58 //
59 FreeItem(Descriptor);
60 return STATUS_INSUFFICIENT_RESOURCES;
61 }
62
63 //
64 // initialize urb
65 //
66 UsbBuildGetDescriptorRequest(Urb,
67 sizeof(Urb->UrbControlDescriptorRequest),
68 DescriptorType,
69 DescriptorIndex,
70 LanguageId,
71 Descriptor,
72 NULL,
73 DescriptorLength,
74 NULL);
75
76 //
77 // submit urb
78 //
79 Status = USBCCGP_SyncUrbRequest(DeviceObject, Urb);
80
81 //
82 // free urb
83 //
84 FreeItem(Urb);
85
86 if (NT_SUCCESS(Status))
87 {
88 //
89 // store result
90 //
91 *OutDescriptor = Descriptor;
92 }
93
94 //
95 // done
96 //
97 return Status;
98 }
99
100 NTSTATUS
101 NTAPI
102 USBCCGP_GetStringDescriptor(
103 IN PDEVICE_OBJECT DeviceObject,
104 IN ULONG DescriptorLength,
105 IN UCHAR DescriptorIndex,
106 IN LANGID LanguageId,
107 OUT PVOID *OutDescriptor)
108 {
109 NTSTATUS Status;
110 PUSB_STRING_DESCRIPTOR StringDescriptor;
111 ULONG Size;
112 PVOID Buffer;
113
114 // retrieve descriptor
115 Status = USBCCGP_GetDescriptor(DeviceObject, USB_STRING_DESCRIPTOR_TYPE, DescriptorLength, DescriptorIndex, LanguageId, OutDescriptor);
116 if (!NT_SUCCESS(Status))
117 {
118 // failed
119 return Status;
120 }
121
122 // get descriptor structure
123 StringDescriptor = (PUSB_STRING_DESCRIPTOR)*OutDescriptor;
124
125 // sanity check
126 ASSERT(StringDescriptor->bLength < DescriptorLength - 2);
127
128 if (StringDescriptor->bLength == 2)
129 {
130 // invalid descriptor
131 FreeItem(StringDescriptor);
132 return STATUS_DEVICE_DATA_ERROR;
133 }
134
135 // calculate size
136 Size = StringDescriptor->bLength + sizeof(WCHAR);
137
138 // allocate buffer
139 Buffer = AllocateItem(NonPagedPool, Size);
140 if (!Buffer)
141 {
142 // no memory
143 FreeItem(StringDescriptor);
144 return STATUS_INSUFFICIENT_RESOURCES;
145 }
146
147 // copy result
148 RtlCopyMemory(Buffer, StringDescriptor->bString, Size - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString));
149
150 // free buffer
151 FreeItem(StringDescriptor);
152
153 // store result
154 *OutDescriptor = (PVOID)Buffer;
155 return STATUS_SUCCESS;
156 }
157
158
159 NTSTATUS
160 USBCCGP_GetDescriptors(
161 IN PDEVICE_OBJECT DeviceObject)
162 {
163 NTSTATUS Status;
164 PFDO_DEVICE_EXTENSION DeviceExtension;
165 USHORT DescriptorLength;
166
167 //
168 // get device extension
169 //
170 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
171
172 //
173 // first get device descriptor
174 //
175 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_DEVICE_DESCRIPTOR_TYPE, sizeof(USB_DEVICE_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->DeviceDescriptor);
176 if (!NT_SUCCESS(Status))
177 {
178 //
179 // failed to get device descriptor
180 //
181 DeviceExtension->DeviceDescriptor = NULL;
182 return Status;
183 }
184
185 //
186 // now get basic configuration descriptor
187 //
188 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, sizeof(USB_CONFIGURATION_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
189 if (!NT_SUCCESS(Status))
190 {
191 //
192 // failed to get configuration descriptor
193 //
194 FreeItem(DeviceExtension->DeviceDescriptor);
195 DeviceExtension->DeviceDescriptor = NULL;
196 return Status;
197 }
198
199 //
200 // backup length
201 //
202 DescriptorLength = DeviceExtension->ConfigurationDescriptor->wTotalLength;
203
204 //
205 // release basic descriptor
206 //
207 FreeItem(DeviceExtension->ConfigurationDescriptor);
208 DeviceExtension->ConfigurationDescriptor = NULL;
209
210 //
211 // allocate full descriptor
212 //
213 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, DescriptorLength, 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
214 if (!NT_SUCCESS(Status))
215 {
216 //
217 // failed to get configuration descriptor
218 //
219 FreeItem(DeviceExtension->DeviceDescriptor);
220 DeviceExtension->DeviceDescriptor = NULL;
221 return Status;
222 }
223 return Status;
224 }
225
226 NTSTATUS
227 AllocateInterfaceDescriptorsArray(
228 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
229 OUT PUSB_INTERFACE_DESCRIPTOR **OutArray)
230 {
231 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
232 ULONG Count = 0;
233 PUSB_INTERFACE_DESCRIPTOR *Array;
234
235 //
236 // allocate array
237 //
238 Array = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR) * ConfigurationDescriptor->bNumInterfaces);
239 if (!Array)
240 return STATUS_INSUFFICIENT_RESOURCES;
241
242 //
243 // enumerate all interfaces
244 //
245 Count = 0;
246 do
247 {
248 //
249 // find next descriptor
250 //
251 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, Count, 0, -1, -1, -1);
252 if (!InterfaceDescriptor)
253 break;
254
255 //
256 // store descriptor
257 //
258 Array[Count] = InterfaceDescriptor;
259 Count++;
260
261 }while(TRUE);
262
263 //
264 // store result
265 //
266 *OutArray = Array;
267
268 //
269 // done
270 //
271 return STATUS_SUCCESS;
272 }
273
274 VOID
275 DumpFullConfigurationDescriptor(
276 IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
277 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
278 {
279 PUSB_COMMON_DESCRIPTOR Descriptor;
280
281 Descriptor = (PUSB_COMMON_DESCRIPTOR)ConfigurationDescriptor;
282
283 DbgPrint("Bogus ConfigurationDescriptor Found\n");
284 DbgPrint("InterfaceCount %x\n", ConfigurationDescriptor->bNumInterfaces);
285
286 do
287 {
288 if (((ULONG_PTR)Descriptor) >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
289 break;
290
291 DbgPrint("Descriptor Type %x Length %lu Offset %lu\n", Descriptor->bDescriptorType, Descriptor->bLength, ((ULONG_PTR)Descriptor - (ULONG_PTR)ConfigurationDescriptor));
292
293 // check for invalid descriptors
294 if (!Descriptor->bLength)
295 {
296 DbgPrint("Bogus Descriptor!!!\n");
297 break;
298 }
299
300 // advance to next descriptor
301 Descriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength);
302
303 }while(TRUE);
304
305
306 }
307
308
309 NTSTATUS
310 NTAPI
311 USBCCGP_ScanConfigurationDescriptor(
312 IN OUT PFDO_DEVICE_EXTENSION FDODeviceExtension,
313 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
314 {
315 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
316 ULONG InterfaceIndex = 0;
317 ULONG DescriptorCount;
318
319 //
320 // sanity checks
321 //
322 ASSERT(ConfigurationDescriptor);
323 ASSERT(ConfigurationDescriptor->bNumInterfaces);
324
325 //
326 // count all interface descriptors
327 //
328 DescriptorCount = ConfigurationDescriptor->bNumInterfaces;
329
330 //
331 // allocate array holding the interface descriptors
332 //
333 FDODeviceExtension->InterfaceList = AllocateItem(NonPagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (DescriptorCount + 1));
334 if (!FDODeviceExtension->InterfaceList)
335 {
336 //
337 // no memory
338 //
339 return STATUS_INSUFFICIENT_RESOURCES;
340 }
341
342 do
343 {
344 //
345 // parse configuration descriptor
346 //
347 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, InterfaceIndex, -1, -1, -1, -1);
348 if (InterfaceDescriptor)
349 {
350 //
351 // store in interface list
352 //
353 FDODeviceExtension->InterfaceList[FDODeviceExtension->InterfaceListCount].InterfaceDescriptor = InterfaceDescriptor;
354 FDODeviceExtension->InterfaceListCount++;
355 }
356 else
357 {
358 DumpConfigurationDescriptor(ConfigurationDescriptor);
359 DumpFullConfigurationDescriptor(FDODeviceExtension, ConfigurationDescriptor);
360
361 //
362 // see issue
363 // CORE-6574 Test 3 (USB Web Cam)
364 //
365 if (FDODeviceExtension->DeviceDescriptor && FDODeviceExtension->DeviceDescriptor->idVendor == 0x0458 && FDODeviceExtension->DeviceDescriptor->idProduct == 0x705f)
366 ASSERT(FALSE);
367 }
368
369 //
370 // move to next interface
371 //
372 InterfaceIndex++;
373
374 }while(InterfaceIndex < DescriptorCount);
375
376 //
377 // sanity check
378 //
379 ASSERT(FDODeviceExtension->InterfaceListCount);
380
381 //
382 // done
383 //
384 return STATUS_SUCCESS;
385 }
386
387 VOID
388 DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
389 {
390 DbgPrint("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor);
391 DbgPrint("bLength %x\n", ConfigurationDescriptor->bLength);
392 DbgPrint("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
393 DbgPrint("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
394 DbgPrint("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
395 DbgPrint("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
396 DbgPrint("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
397 DbgPrint("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
398 DbgPrint("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
399 }
400
401 NTSTATUS
402 USBCCGP_SelectInterface(
403 IN PDEVICE_OBJECT DeviceObject,
404 IN PFDO_DEVICE_EXTENSION DeviceExtension,
405 IN ULONG InterfaceIndex)
406 {
407 NTSTATUS Status;
408 PURB Urb;
409
410 //
411 // allocate urb
412 //
413 Urb = AllocateItem(NonPagedPool, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints));
414 if (!Urb)
415 {
416 //
417 // no memory
418 //
419 return STATUS_INSUFFICIENT_RESOURCES;
420 }
421
422 //
423 // now prepare interface urb
424 //
425 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bInterfaceNumber, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bAlternateSetting);
426
427 //
428 // now select the interface
429 //
430 Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb);
431
432 //
433 // did it succeeed
434 //
435 if (NT_SUCCESS(Status))
436 {
437 //
438 // update configuration info
439 //
440 ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceList[InterfaceIndex].Interface->Length);
441 RtlCopyMemory(DeviceExtension->InterfaceList[InterfaceIndex].Interface, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
442 }
443
444 //
445 // free urb
446 //
447 FreeItem(Urb);
448
449 //
450 // done
451 //
452 return Status;
453 }
454
455 NTSTATUS
456 USBCCGP_SelectConfiguration(
457 IN PDEVICE_OBJECT DeviceObject,
458 IN PFDO_DEVICE_EXTENSION DeviceExtension)
459 {
460 PUSBD_INTERFACE_INFORMATION InterfaceInformation;
461 NTSTATUS Status;
462 PURB Urb;
463 ULONG Index;
464
465 //
466 // now scan configuration descriptors
467 //
468 Status = USBCCGP_ScanConfigurationDescriptor(DeviceExtension, DeviceExtension->ConfigurationDescriptor);
469 if (!NT_SUCCESS(Status))
470 {
471 //
472 // failed to scan
473 //
474 return Status;
475 }
476
477 //
478 // now allocate the urb
479 //
480 Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, DeviceExtension->InterfaceList);
481 if (!Urb)
482 {
483 //
484 // no memory
485 //
486 return STATUS_INSUFFICIENT_RESOURCES;
487 }
488
489 //
490 // submit urb
491 //
492 Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb);
493 if (!NT_SUCCESS(Status))
494 {
495 //
496 // failed to set configuration
497 //
498 DPRINT1("USBCCGP_SyncUrbRequest failed to set interface %x\n", Status);
499 ExFreePool(Urb);
500 return Status;
501 }
502
503 //
504 // get interface information
505 //
506 InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
507 for(Index = 0; Index < DeviceExtension->InterfaceListCount; Index++)
508 {
509 //
510 // allocate buffer to store interface information
511 //
512 DeviceExtension->InterfaceList[Index].Interface = AllocateItem(NonPagedPool, InterfaceInformation->Length);
513 if (!DeviceExtension->InterfaceList[Index].Interface)
514 {
515 //
516 // no memory
517 //
518 return STATUS_INSUFFICIENT_RESOURCES;
519 }
520
521 //
522 // copy interface information
523 //
524 RtlCopyMemory(DeviceExtension->InterfaceList[Index].Interface, InterfaceInformation, InterfaceInformation->Length);
525
526 //
527 // move to next interface
528 //
529 InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + InterfaceInformation->Length);
530 }
531
532
533 //
534 // store pipe handle
535 //
536 DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
537
538 //
539 // free interface list & urb
540 //
541 ExFreePool(Urb);
542
543 //
544 // done
545 //
546 return Status;
547 }