2a9e4953887676d9d72ca1802360c1254246b329
[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 ULONG
224 CountInterfaceDescriptors(
225 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
226 {
227 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
228 PVOID CurrentPosition;
229 ULONG Count = 0;
230
231 //
232 // enumerate all interfaces
233 //
234 CurrentPosition = ConfigurationDescriptor;
235 do
236 {
237 //
238 // find next descriptor
239 //
240 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, CurrentPosition, -1, -1, -1, -1, -1);
241 if (!InterfaceDescriptor)
242 break;
243
244 //
245 // advance to next descriptor
246 //
247 CurrentPosition = (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
248
249 //
250 // increment descriptor count
251 //
252 Count++;
253
254 }while(TRUE);
255
256 //
257 // done
258 //
259 return Count;
260 }
261
262 NTSTATUS
263 AllocateInterfaceDescriptorsArray(
264 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
265 OUT PUSB_INTERFACE_DESCRIPTOR **OutArray)
266 {
267 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
268 PVOID CurrentPosition;
269 ULONG Count = 0;
270 PUSB_INTERFACE_DESCRIPTOR *Array;
271
272 Count = CountInterfaceDescriptors(ConfigurationDescriptor);
273 ASSERT(Count);
274
275 //
276 // allocate array
277 //
278 Array = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR) * Count);
279 if (!Array)
280 return STATUS_INSUFFICIENT_RESOURCES;
281
282 //
283 // enumerate all interfaces
284 //
285 CurrentPosition = ConfigurationDescriptor;
286 Count = 0;
287 do
288 {
289 //
290 // find next descriptor
291 //
292 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, CurrentPosition, -1, -1, -1, -1, -1);
293 if (!InterfaceDescriptor)
294 break;
295
296 //
297 // store descriptor
298 //
299 Array[Count] = InterfaceDescriptor;
300 Count++;
301
302 //
303 // advance to next descriptor
304 //
305 CurrentPosition = (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
306
307 }while(TRUE);
308
309 //
310 // store result
311 //
312 *OutArray = Array;
313
314 //
315 // done
316 //
317 return STATUS_SUCCESS;
318 }
319
320 NTSTATUS
321 NTAPI
322 USBCCGP_ScanConfigurationDescriptor(
323 IN OUT PFDO_DEVICE_EXTENSION FDODeviceExtension,
324 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
325 {
326 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
327 ULONG InterfaceIndex = 0;
328 PVOID CurrentPosition;
329 ULONG DescriptorCount;
330
331 //
332 // sanity checks
333 //
334 ASSERT(ConfigurationDescriptor);
335 ASSERT(ConfigurationDescriptor->bNumInterfaces);
336
337 //
338 // count all interface descriptors
339 //
340 DescriptorCount = ConfigurationDescriptor->bNumInterfaces;
341
342 //
343 // allocate array holding the interface descriptors
344 //
345 FDODeviceExtension->InterfaceList = AllocateItem(NonPagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (DescriptorCount + 1));
346 if (!FDODeviceExtension->InterfaceList)
347 {
348 //
349 // no memory
350 //
351 return STATUS_INSUFFICIENT_RESOURCES;
352 }
353
354 CurrentPosition = ConfigurationDescriptor;
355 do
356 {
357 //
358 // parse configuration descriptor
359 //
360 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, InterfaceIndex, -1, -1, -1, -1);
361 ASSERT(InterfaceDescriptor);
362 if (InterfaceDescriptor)
363 {
364 //
365 // store in interface list
366 //
367 FDODeviceExtension->InterfaceList[FDODeviceExtension->InterfaceListCount].InterfaceDescriptor = InterfaceDescriptor;
368 FDODeviceExtension->InterfaceListCount++;
369 CurrentPosition = (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
370 }
371
372 //
373 // move to next interface
374 //
375 InterfaceIndex++;
376
377 }while(InterfaceIndex < DescriptorCount);
378
379 //
380 // sanity check
381 //
382 ASSERT(FDODeviceExtension->InterfaceListCount);
383
384 //
385 // done
386 //
387 return STATUS_SUCCESS;
388 }
389
390 VOID
391 DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
392 {
393 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor);
394 DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength);
395 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
396 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
397 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
398 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
399 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
400 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
401 DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
402 }
403
404 NTSTATUS
405 USBCCGP_SelectInterface(
406 IN PDEVICE_OBJECT DeviceObject,
407 IN PFDO_DEVICE_EXTENSION DeviceExtension,
408 IN ULONG InterfaceIndex)
409 {
410 NTSTATUS Status;
411 PURB Urb;
412
413 //
414 // allocate urb
415 //
416 Urb = AllocateItem(NonPagedPool, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints));
417 if (!Urb)
418 {
419 //
420 // no memory
421 //
422 return STATUS_INSUFFICIENT_RESOURCES;
423 }
424
425 //
426 // now prepare interface urb
427 //
428 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bInterfaceNumber, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bAlternateSetting);
429
430 //
431 // now select the interface
432 //
433 Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb);
434
435 //
436 // did it succeeed
437 //
438 if (NT_SUCCESS(Status))
439 {
440 //
441 // update configuration info
442 //
443 ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceList[InterfaceIndex].Interface->Length);
444 RtlCopyMemory(DeviceExtension->InterfaceList[InterfaceIndex].Interface, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
445 }
446
447 //
448 // free urb
449 //
450 FreeItem(Urb);
451
452 //
453 // done
454 //
455 return Status;
456 }
457
458 NTSTATUS
459 USBCCGP_SelectConfiguration(
460 IN PDEVICE_OBJECT DeviceObject,
461 IN PFDO_DEVICE_EXTENSION DeviceExtension)
462 {
463 PUSBD_INTERFACE_INFORMATION InterfaceInformation;
464 NTSTATUS Status;
465 PURB Urb;
466 ULONG Index;
467
468 //
469 // now scan configuration descriptors
470 //
471 Status = USBCCGP_ScanConfigurationDescriptor(DeviceExtension, DeviceExtension->ConfigurationDescriptor);
472 if (!NT_SUCCESS(Status))
473 {
474 //
475 // failed to scan
476 //
477 return Status;
478 }
479
480 //
481 // now allocate the urb
482 //
483 Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, DeviceExtension->InterfaceList);
484 if (!Urb)
485 {
486 //
487 // no memory
488 //
489 return STATUS_INSUFFICIENT_RESOURCES;
490 }
491
492 //
493 // submit urb
494 //
495 Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb);
496 if (!NT_SUCCESS(Status))
497 {
498 //
499 // failed to set configuration
500 //
501 DPRINT1("USBCCGP_SyncUrbRequest failed to set interface %x\n", Status);
502 ExFreePool(Urb);
503 return Status;
504 }
505
506 //
507 // get interface information
508 //
509 InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
510 for(Index = 0; Index < DeviceExtension->InterfaceListCount; Index++)
511 {
512 //
513 // allocate buffer to store interface information
514 //
515 DeviceExtension->InterfaceList[Index].Interface = AllocateItem(NonPagedPool, InterfaceInformation->Length);
516 if (!DeviceExtension->InterfaceList[Index].Interface)
517 {
518 //
519 // no memory
520 //
521 return STATUS_INSUFFICIENT_RESOURCES;
522 }
523
524 //
525 // copy interface information
526 //
527 RtlCopyMemory(DeviceExtension->InterfaceList[Index].Interface, InterfaceInformation, InterfaceInformation->Length);
528
529 //
530 // move to next interface
531 //
532 InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + InterfaceInformation->Length);
533 }
534
535
536 //
537 // store pipe handle
538 //
539 DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
540
541 //
542 // free interface list & urb
543 //
544 ExFreePool(Urb);
545
546 //
547 // done
548 //
549 return Status;
550 }
551