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