xref: /reactos/drivers/usb/usbccgp/descriptor.c (revision 40462c92)
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     if (DescriptorCount == 0)
330     {
331         DPRINT1("[USBCCGP] DescriptorCount is zero\n");
332         return STATUS_INVALID_PARAMETER;
333     }
334 
335     //
336     // allocate array holding the interface descriptors
337     //
338     FDODeviceExtension->InterfaceList = AllocateItem(NonPagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (DescriptorCount + 1));
339     if (!FDODeviceExtension->InterfaceList)
340     {
341         //
342         // no memory
343         //
344         return STATUS_INSUFFICIENT_RESOURCES;
345     }
346 
347     //
348     // reset interface list count
349     //
350     FDODeviceExtension->InterfaceListCount = 0;
351 
352     do
353     {
354         //
355         // parse configuration descriptor
356         //
357         InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, InterfaceIndex, -1, -1, -1, -1);
358         if (InterfaceDescriptor)
359         {
360             //
361             // store in interface list
362             //
363             ASSERT(FDODeviceExtension->InterfaceListCount < DescriptorCount);
364             FDODeviceExtension->InterfaceList[FDODeviceExtension->InterfaceListCount].InterfaceDescriptor = InterfaceDescriptor;
365             FDODeviceExtension->InterfaceListCount++;
366         }
367         else
368         {
369             DumpConfigurationDescriptor(ConfigurationDescriptor);
370             DumpFullConfigurationDescriptor(FDODeviceExtension, ConfigurationDescriptor);
371 
372             //
373             // see issue
374             // CORE-6574 Test 3 (USB Web Cam)
375             //
376             if (FDODeviceExtension->DeviceDescriptor && FDODeviceExtension->DeviceDescriptor->idVendor == 0x0458 && FDODeviceExtension->DeviceDescriptor->idProduct == 0x705f)
377                 ASSERT(FALSE);
378         }
379 
380         //
381         // move to next interface
382         //
383         InterfaceIndex++;
384 
385     }while(InterfaceIndex < DescriptorCount);
386 
387     //
388     // sanity check
389     //
390     ASSERT(FDODeviceExtension->InterfaceListCount);
391 
392     //
393     // done
394     //
395     return STATUS_SUCCESS;
396 }
397 
398 VOID
399 DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
400 {
401     DbgPrint("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor);
402     DbgPrint("bLength %x\n", ConfigurationDescriptor->bLength);
403     DbgPrint("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
404     DbgPrint("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
405     DbgPrint("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
406     DbgPrint("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
407     DbgPrint("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
408     DbgPrint("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
409     DbgPrint("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
410 }
411 
412 NTSTATUS
413 USBCCGP_SelectInterface(
414     IN PDEVICE_OBJECT DeviceObject,
415     IN PFDO_DEVICE_EXTENSION DeviceExtension,
416     IN ULONG InterfaceIndex)
417 {
418     NTSTATUS Status;
419     PURB Urb;
420 
421     //
422     // allocate urb
423     //
424     Urb = AllocateItem(NonPagedPool, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints));
425     if (!Urb)
426     {
427         //
428         // no memory
429         //
430         return STATUS_INSUFFICIENT_RESOURCES;
431     }
432 
433     //
434     // now prepare interface urb
435     //
436     UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bInterfaceNumber, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bAlternateSetting);
437 
438     //
439     // now select the interface
440     //
441     Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb);
442 
443     //
444     // did it succeed
445     //
446     if (NT_SUCCESS(Status))
447     {
448         //
449         // update configuration info
450         //
451         ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceList[InterfaceIndex].Interface->Length);
452         RtlCopyMemory(DeviceExtension->InterfaceList[InterfaceIndex].Interface, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
453     }
454 
455     //
456     // free urb
457     //
458     FreeItem(Urb);
459 
460     //
461     // done
462     //
463     return Status;
464 }
465 
466 NTSTATUS
467 USBCCGP_SelectConfiguration(
468     IN PDEVICE_OBJECT DeviceObject,
469     IN PFDO_DEVICE_EXTENSION DeviceExtension)
470 {
471     PUSBD_INTERFACE_INFORMATION InterfaceInformation;
472     NTSTATUS Status;
473     PURB Urb;
474     ULONG Index;
475 
476     //
477     // now scan configuration descriptors
478     //
479     Status = USBCCGP_ScanConfigurationDescriptor(DeviceExtension, DeviceExtension->ConfigurationDescriptor);
480     if (!NT_SUCCESS(Status))
481     {
482         //
483         // failed to scan
484         //
485         return Status;
486     }
487 
488     //
489     // now allocate the urb
490     //
491     Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, DeviceExtension->InterfaceList);
492     if (!Urb)
493     {
494         //
495         // no memory
496         //
497         return STATUS_INSUFFICIENT_RESOURCES;
498     }
499 
500     //
501     // submit urb
502     //
503     Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb);
504     if (!NT_SUCCESS(Status))
505     {
506         //
507         // failed to set configuration
508         //
509         DPRINT1("USBCCGP_SyncUrbRequest failed to set interface %x\n", Status);
510         ExFreePool(Urb);
511         return Status;
512     }
513 
514     //
515     // get interface information
516     //
517     InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
518     for(Index = 0; Index < DeviceExtension->InterfaceListCount; Index++)
519     {
520         //
521         // allocate buffer to store interface information
522         //
523         DeviceExtension->InterfaceList[Index].Interface = AllocateItem(NonPagedPool, InterfaceInformation->Length);
524         if (!DeviceExtension->InterfaceList[Index].Interface)
525         {
526             //
527             // no memory
528             //
529             return STATUS_INSUFFICIENT_RESOURCES;
530         }
531 
532         //
533         // copy interface information
534         //
535         RtlCopyMemory(DeviceExtension->InterfaceList[Index].Interface, InterfaceInformation, InterfaceInformation->Length);
536 
537         //
538         // move to next interface
539         //
540         InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + InterfaceInformation->Length);
541     }
542 
543 
544     //
545     // store pipe handle
546     //
547     DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
548 
549     //
550     // free interface list & urb
551     //
552     ExFreePool(Urb);
553 
554     //
555     // done
556     //
557     return Status;
558 }
559