5841dd31d927f0ac40b03582ac9cc310b0727a65
[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 NTSTATUS
272 NTAPI
273 USBCCGP_ScanConfigurationDescriptor(
274 IN OUT PFDO_DEVICE_EXTENSION FDODeviceExtension,
275 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
276 {
277 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
278 ULONG InterfaceIndex = 0;
279 PVOID CurrentPosition;
280 ULONG DescriptorCount;
281
282 //
283 // sanity checks
284 //
285 ASSERT(ConfigurationDescriptor);
286 ASSERT(ConfigurationDescriptor->bNumInterfaces);
287
288 //
289 // count all interface descriptors
290 //
291 DescriptorCount = ConfigurationDescriptor->bNumInterfaces;
292
293 //
294 // allocate array holding the interface descriptors
295 //
296 FDODeviceExtension->InterfaceList = AllocateItem(NonPagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (DescriptorCount + 1));
297 if (!FDODeviceExtension->InterfaceList)
298 {
299 //
300 // no memory
301 //
302 return STATUS_INSUFFICIENT_RESOURCES;
303 }
304
305 CurrentPosition = ConfigurationDescriptor;
306 do
307 {
308 //
309 // parse configuration descriptor
310 //
311 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, InterfaceIndex, -1, -1, -1, -1);
312 ASSERT(InterfaceDescriptor);
313 if (InterfaceDescriptor)
314 {
315 //
316 // store in interface list
317 //
318 FDODeviceExtension->InterfaceList[FDODeviceExtension->InterfaceListCount].InterfaceDescriptor = InterfaceDescriptor;
319 FDODeviceExtension->InterfaceListCount++;
320 CurrentPosition = (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
321 }
322
323 //
324 // move to next interface
325 //
326 InterfaceIndex++;
327
328 }while(InterfaceIndex < DescriptorCount);
329
330 //
331 // sanity check
332 //
333 ASSERT(FDODeviceExtension->InterfaceListCount);
334
335 //
336 // done
337 //
338 return STATUS_SUCCESS;
339 }
340
341 VOID
342 DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
343 {
344 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor);
345 DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength);
346 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
347 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
348 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
349 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
350 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
351 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
352 DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
353 }
354
355 NTSTATUS
356 USBCCGP_SelectInterface(
357 IN PDEVICE_OBJECT DeviceObject,
358 IN PFDO_DEVICE_EXTENSION DeviceExtension,
359 IN ULONG InterfaceIndex)
360 {
361 NTSTATUS Status;
362 PURB Urb;
363
364 //
365 // allocate urb
366 //
367 Urb = AllocateItem(NonPagedPool, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints));
368 if (!Urb)
369 {
370 //
371 // no memory
372 //
373 return STATUS_INSUFFICIENT_RESOURCES;
374 }
375
376 //
377 // now prepare interface urb
378 //
379 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bInterfaceNumber, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bAlternateSetting);
380
381 //
382 // now select the interface
383 //
384 Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb);
385
386 //
387 // did it succeeed
388 //
389 if (NT_SUCCESS(Status))
390 {
391 //
392 // update configuration info
393 //
394 ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceList[InterfaceIndex].Interface->Length);
395 RtlCopyMemory(DeviceExtension->InterfaceList[InterfaceIndex].Interface, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
396 }
397
398 //
399 // free urb
400 //
401 FreeItem(Urb);
402
403 //
404 // done
405 //
406 return Status;
407 }
408
409 NTSTATUS
410 USBCCGP_SelectConfiguration(
411 IN PDEVICE_OBJECT DeviceObject,
412 IN PFDO_DEVICE_EXTENSION DeviceExtension)
413 {
414 PUSBD_INTERFACE_INFORMATION InterfaceInformation;
415 NTSTATUS Status;
416 PURB Urb;
417 ULONG Index;
418
419 //
420 // now scan configuration descriptors
421 //
422 Status = USBCCGP_ScanConfigurationDescriptor(DeviceExtension, DeviceExtension->ConfigurationDescriptor);
423 if (!NT_SUCCESS(Status))
424 {
425 //
426 // failed to scan
427 //
428 return Status;
429 }
430
431 //
432 // now allocate the urb
433 //
434 Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, DeviceExtension->InterfaceList);
435 if (!Urb)
436 {
437 //
438 // no memory
439 //
440 return STATUS_INSUFFICIENT_RESOURCES;
441 }
442
443 //
444 // submit urb
445 //
446 Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb);
447 if (!NT_SUCCESS(Status))
448 {
449 //
450 // failed to set configuration
451 //
452 DPRINT1("USBCCGP_SyncUrbRequest failed to set interface %x\n", Status);
453 ExFreePool(Urb);
454 return Status;
455 }
456
457 //
458 // get interface information
459 //
460 InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
461 for(Index = 0; Index < DeviceExtension->InterfaceListCount; Index++)
462 {
463 //
464 // allocate buffer to store interface information
465 //
466 DeviceExtension->InterfaceList[Index].Interface = AllocateItem(NonPagedPool, InterfaceInformation->Length);
467 if (!DeviceExtension->InterfaceList[Index].Interface)
468 {
469 //
470 // no memory
471 //
472 return STATUS_INSUFFICIENT_RESOURCES;
473 }
474
475 //
476 // copy interface information
477 //
478 RtlCopyMemory(DeviceExtension->InterfaceList[Index].Interface, InterfaceInformation, InterfaceInformation->Length);
479
480 //
481 // move to next interface
482 //
483 InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + InterfaceInformation->Length);
484 }
485
486
487 //
488 // store pipe handle
489 //
490 DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
491
492 //
493 // free interface list & urb
494 //
495 ExFreePool(Urb);
496
497 //
498 // done
499 //
500 return Status;
501 }
502