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