[USBPORT] Start implementation USB2_DeallocateEndpointBudget().
[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 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 }