Sync with trunk r58740.
[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 NTSTATUS
15 NTAPI
16 USBCCGP_GetDescriptor(
17 IN PDEVICE_OBJECT DeviceObject,
18 IN UCHAR DescriptorType,
19 IN ULONG DescriptorLength,
20 IN UCHAR DescriptorIndex,
21 IN LANGID LanguageId,
22 OUT PVOID *OutDescriptor)
23 {
24 PURB Urb;
25 NTSTATUS Status;
26 PVOID Descriptor;
27
28 //
29 // sanity checks
30 //
31 ASSERT(DeviceObject);
32 ASSERT(OutDescriptor);
33 ASSERT(DescriptorLength);
34
35 //
36 // first allocate descriptor buffer
37 //
38 Descriptor = AllocateItem(NonPagedPool, DescriptorLength);
39 if (!Descriptor)
40 {
41 //
42 // no memory
43 //
44 return STATUS_INSUFFICIENT_RESOURCES;
45 }
46
47 //
48 // allocate urb
49 //
50 Urb = (PURB) AllocateItem(NonPagedPool, sizeof(URB));
51 if (!Urb)
52 {
53 //
54 // no memory
55 //
56 FreeItem(Descriptor);
57 return STATUS_INSUFFICIENT_RESOURCES;
58 }
59
60 //
61 // initialize urb
62 //
63 UsbBuildGetDescriptorRequest(Urb,
64 sizeof(Urb->UrbControlDescriptorRequest),
65 DescriptorType,
66 DescriptorIndex,
67 LanguageId,
68 Descriptor,
69 NULL,
70 DescriptorLength,
71 NULL);
72
73 //
74 // submit urb
75 //
76 Status = USBCCGP_SyncUrbRequest(DeviceObject, Urb);
77
78 //
79 // free urb
80 //
81 FreeItem(Urb);
82
83 if (NT_SUCCESS(Status))
84 {
85 //
86 // store result
87 //
88 *OutDescriptor = Descriptor;
89 }
90
91 //
92 // done
93 //
94 return Status;
95 }
96
97 NTSTATUS
98 NTAPI
99 USBCCGP_GetStringDescriptor(
100 IN PDEVICE_OBJECT DeviceObject,
101 IN ULONG DescriptorLength,
102 IN UCHAR DescriptorIndex,
103 IN LANGID LanguageId,
104 OUT PVOID *OutDescriptor)
105 {
106 NTSTATUS Status;
107 PUSB_STRING_DESCRIPTOR StringDescriptor;
108 ULONG Size;
109 PVOID Buffer;
110
111 // retrieve descriptor
112 Status = USBCCGP_GetDescriptor(DeviceObject, USB_STRING_DESCRIPTOR_TYPE, DescriptorLength, DescriptorIndex, LanguageId, OutDescriptor);
113 if (!NT_SUCCESS(Status))
114 {
115 // failed
116 return Status;
117 }
118
119 // get descriptor structure
120 StringDescriptor = (PUSB_STRING_DESCRIPTOR)*OutDescriptor;
121
122 // sanity check
123 ASSERT(StringDescriptor->bLength < DescriptorLength - 2);
124
125 if (StringDescriptor->bLength == 2)
126 {
127 // invalid descriptor
128 FreeItem(StringDescriptor);
129 return STATUS_DEVICE_DATA_ERROR;
130 }
131
132 // calculate size
133 Size = StringDescriptor->bLength + sizeof(WCHAR);
134
135 // allocate buffer
136 Buffer = AllocateItem(NonPagedPool, Size);
137 if (!Buffer)
138 {
139 // no memory
140 FreeItem(StringDescriptor);
141 return STATUS_INSUFFICIENT_RESOURCES;
142 }
143
144 // copy result
145 RtlCopyMemory(Buffer, StringDescriptor->bString, Size - FIELD_OFFSET(USB_STRING_DESCRIPTOR, bString));
146
147 // free buffer
148 FreeItem(StringDescriptor);
149
150 // store result
151 *OutDescriptor = (PVOID)Buffer;
152 return STATUS_SUCCESS;
153 }
154
155
156 NTSTATUS
157 USBCCGP_GetDescriptors(
158 IN PDEVICE_OBJECT DeviceObject)
159 {
160 NTSTATUS Status;
161 PFDO_DEVICE_EXTENSION DeviceExtension;
162 USHORT DescriptorLength;
163
164 //
165 // get device extension
166 //
167 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
168
169 //
170 // first get device descriptor
171 //
172 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_DEVICE_DESCRIPTOR_TYPE, sizeof(USB_DEVICE_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->DeviceDescriptor);
173 if (!NT_SUCCESS(Status))
174 {
175 //
176 // failed to get device descriptor
177 //
178 DeviceExtension->DeviceDescriptor = NULL;
179 return Status;
180 }
181
182 //
183 // now get basic configuration descriptor
184 //
185 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, sizeof(USB_CONFIGURATION_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
186 if (!NT_SUCCESS(Status))
187 {
188 //
189 // failed to get configuration descriptor
190 //
191 FreeItem(DeviceExtension->DeviceDescriptor);
192 DeviceExtension->DeviceDescriptor = NULL;
193 return Status;
194 }
195
196 //
197 // backup length
198 //
199 DescriptorLength = DeviceExtension->ConfigurationDescriptor->wTotalLength;
200
201 //
202 // release basic descriptor
203 //
204 FreeItem(DeviceExtension->ConfigurationDescriptor);
205 DeviceExtension->ConfigurationDescriptor = NULL;
206
207 //
208 // allocate full descriptor
209 //
210 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, DescriptorLength, 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
211 if (!NT_SUCCESS(Status))
212 {
213 //
214 // failed to get configuration descriptor
215 //
216 FreeItem(DeviceExtension->DeviceDescriptor);
217 DeviceExtension->DeviceDescriptor = NULL;
218 return Status;
219 }
220 return Status;
221 }
222
223 NTSTATUS
224 AllocateInterfaceDescriptorsArray(
225 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
226 OUT PUSB_INTERFACE_DESCRIPTOR **OutArray)
227 {
228 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
229 ULONG Count = 0;
230 PUSB_INTERFACE_DESCRIPTOR *Array;
231
232 //
233 // allocate array
234 //
235 Array = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR) * ConfigurationDescriptor->bNumInterfaces);
236 if (!Array)
237 return STATUS_INSUFFICIENT_RESOURCES;
238
239 //
240 // enumerate all interfaces
241 //
242 Count = 0;
243 do
244 {
245 //
246 // find next descriptor
247 //
248 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, Count, 0, -1, -1, -1);
249 if (!InterfaceDescriptor)
250 break;
251
252 //
253 // store descriptor
254 //
255 Array[Count] = InterfaceDescriptor;
256 Count++;
257
258 }while(TRUE);
259
260 //
261 // store result
262 //
263 *OutArray = Array;
264
265 //
266 // done
267 //
268 return STATUS_SUCCESS;
269 }
270
271 VOID
272 DumpFullConfigurationDescriptor(
273 IN PFDO_DEVICE_EXTENSION FDODeviceExtension,
274 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
275 {
276 PUSB_COMMON_DESCRIPTOR Descriptor;
277
278 Descriptor = (PUSB_COMMON_DESCRIPTOR)ConfigurationDescriptor;
279
280 DbgPrint("Bogus ConfigurationDescriptor Found\n");
281 DbgPrint("InterfaceCount %x\n", ConfigurationDescriptor->bNumInterfaces);
282
283 do
284 {
285 if (((ULONG_PTR)Descriptor) >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
286 break;
287
288 DbgPrint("Descriptor Type %x Length %lu Offset %lu\n", Descriptor->bDescriptorType, Descriptor->bLength, ((ULONG_PTR)Descriptor - (ULONG_PTR)ConfigurationDescriptor));
289
290 // check for invalid descriptors
291 if (!Descriptor->bLength)
292 {
293 DbgPrint("Bogus Descriptor!!!\n");
294 break;
295 }
296
297 // advance to next descriptor
298 Descriptor = (PUSB_COMMON_DESCRIPTOR)((ULONG_PTR)Descriptor + Descriptor->bLength);
299
300 }while(TRUE);
301
302
303 }
304
305
306 NTSTATUS
307 NTAPI
308 USBCCGP_ScanConfigurationDescriptor(
309 IN OUT PFDO_DEVICE_EXTENSION FDODeviceExtension,
310 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
311 {
312 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
313 ULONG InterfaceIndex = 0;
314 PVOID CurrentPosition;
315 ULONG DescriptorCount;
316
317 //
318 // sanity checks
319 //
320 ASSERT(ConfigurationDescriptor);
321 ASSERT(ConfigurationDescriptor->bNumInterfaces);
322
323 //
324 // count all interface descriptors
325 //
326 DescriptorCount = ConfigurationDescriptor->bNumInterfaces;
327
328 //
329 // allocate array holding the interface descriptors
330 //
331 FDODeviceExtension->InterfaceList = AllocateItem(NonPagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (DescriptorCount + 1));
332 if (!FDODeviceExtension->InterfaceList)
333 {
334 //
335 // no memory
336 //
337 return STATUS_INSUFFICIENT_RESOURCES;
338 }
339
340 CurrentPosition = ConfigurationDescriptor;
341 do
342 {
343 //
344 // parse configuration descriptor
345 //
346 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, InterfaceIndex, -1, -1, -1, -1);
347 if (InterfaceDescriptor)
348 {
349 //
350 // store in interface list
351 //
352 FDODeviceExtension->InterfaceList[FDODeviceExtension->InterfaceListCount].InterfaceDescriptor = InterfaceDescriptor;
353 FDODeviceExtension->InterfaceListCount++;
354 CurrentPosition = (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
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 }
548