[USB]
[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
98 NTSTATUS
99 USBCCGP_GetDescriptors(
100 IN PDEVICE_OBJECT DeviceObject)
101 {
102 NTSTATUS Status;
103 PFDO_DEVICE_EXTENSION DeviceExtension;
104 USHORT DescriptorLength;
105
106 //
107 // get device extension
108 //
109 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
110
111 //
112 // first get device descriptor
113 //
114 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_DEVICE_DESCRIPTOR_TYPE, sizeof(USB_DEVICE_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->DeviceDescriptor);
115 if (!NT_SUCCESS(Status))
116 {
117 //
118 // failed to get device descriptor
119 //
120 DeviceExtension->DeviceDescriptor = NULL;
121 return Status;
122 }
123
124 //
125 // now get basic configuration descriptor
126 //
127 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, sizeof(USB_CONFIGURATION_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
128 if (!NT_SUCCESS(Status))
129 {
130 //
131 // failed to get configuration descriptor
132 //
133 FreeItem(DeviceExtension->DeviceDescriptor);
134 DeviceExtension->DeviceDescriptor = NULL;
135 return Status;
136 }
137
138 //
139 // backup length
140 //
141 DescriptorLength = DeviceExtension->ConfigurationDescriptor->wTotalLength;
142
143 //
144 // release basic descriptor
145 //
146 FreeItem(DeviceExtension->ConfigurationDescriptor);
147 DeviceExtension->ConfigurationDescriptor = NULL;
148
149 //
150 // allocate full descriptor
151 //
152 Status = USBCCGP_GetDescriptor(DeviceExtension->NextDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, DescriptorLength, 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
153 if (!NT_SUCCESS(Status))
154 {
155 //
156 // failed to get configuration descriptor
157 //
158 FreeItem(DeviceExtension->DeviceDescriptor);
159 DeviceExtension->DeviceDescriptor = NULL;
160 return Status;
161 }
162 return Status;
163 }
164
165 ULONG
166 CountInterfaceDescriptors(
167 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
168 {
169 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
170 PVOID CurrentPosition;
171 ULONG Count = 0;
172
173 //
174 // enumerate all interfaces
175 //
176 CurrentPosition = ConfigurationDescriptor;
177 do
178 {
179 //
180 // find next descriptor
181 //
182 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, CurrentPosition, -1, -1, -1, -1, -1);
183 if (!InterfaceDescriptor)
184 break;
185
186 //
187 // advance to next descriptor
188 //
189 CurrentPosition = (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
190
191 //
192 // increment descriptor count
193 //
194 Count++;
195
196 }while(TRUE);
197
198 //
199 // done
200 //
201 return Count;
202 }
203
204 NTSTATUS
205 AllocateInterfaceDescriptorsArray(
206 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
207 OUT PUSB_INTERFACE_DESCRIPTOR **OutArray)
208 {
209 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
210 PVOID CurrentPosition;
211 ULONG Count = 0;
212 PUSB_INTERFACE_DESCRIPTOR *Array;
213
214 Count = CountInterfaceDescriptors(ConfigurationDescriptor);
215 ASSERT(Count);
216
217 //
218 // allocate array
219 //
220 Array = AllocateItem(NonPagedPool, sizeof(PUSB_INTERFACE_DESCRIPTOR) * Count);
221 if (!Array)
222 return STATUS_INSUFFICIENT_RESOURCES;
223
224 //
225 // enumerate all interfaces
226 //
227 CurrentPosition = ConfigurationDescriptor;
228 Count = 0;
229 do
230 {
231 //
232 // find next descriptor
233 //
234 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, CurrentPosition, -1, -1, -1, -1, -1);
235 if (!InterfaceDescriptor)
236 break;
237
238 //
239 // store descriptor
240 //
241 Array[Count] = InterfaceDescriptor;
242 Count++;
243
244 //
245 // advance to next descriptor
246 //
247 CurrentPosition = (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
248
249 }while(TRUE);
250
251 //
252 // store result
253 //
254 *OutArray = Array;
255
256 //
257 // done
258 //
259 return STATUS_SUCCESS;
260 }
261
262 NTSTATUS
263 NTAPI
264 USBCCGP_ScanConfigurationDescriptor(
265 IN OUT PFDO_DEVICE_EXTENSION FDODeviceExtension,
266 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
267 {
268 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
269 ULONG InterfaceIndex = 0;
270 PVOID CurrentPosition;
271 ULONG DescriptorCount;
272
273 //
274 // sanity checks
275 //
276 ASSERT(ConfigurationDescriptor);
277 ASSERT(ConfigurationDescriptor->bNumInterfaces);
278
279 //
280 // count all interface descriptors
281 //
282 DescriptorCount = ConfigurationDescriptor->bNumInterfaces;
283
284 //
285 // allocate array holding the interface descriptors
286 //
287 FDODeviceExtension->InterfaceList = AllocateItem(NonPagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * (DescriptorCount + 1));
288 if (!FDODeviceExtension->InterfaceList)
289 {
290 //
291 // no memory
292 //
293 return STATUS_INSUFFICIENT_RESOURCES;
294 }
295
296 CurrentPosition = ConfigurationDescriptor;
297 do
298 {
299 //
300 // parse configuration descriptor
301 //
302 InterfaceDescriptor = USBD_ParseConfigurationDescriptorEx(ConfigurationDescriptor, ConfigurationDescriptor, InterfaceIndex, -1, -1, -1, -1);
303 ASSERT(InterfaceDescriptor);
304 if (InterfaceDescriptor)
305 {
306 //
307 // store in interface list
308 //
309 FDODeviceExtension->InterfaceList[FDODeviceExtension->InterfaceListCount].InterfaceDescriptor = InterfaceDescriptor;
310 FDODeviceExtension->InterfaceListCount++;
311 CurrentPosition = (PVOID)((ULONG_PTR)InterfaceDescriptor + InterfaceDescriptor->bLength);
312 }
313
314 //
315 // move to next interface
316 //
317 InterfaceIndex++;
318
319 }while(InterfaceIndex < DescriptorCount);
320
321 //
322 // sanity check
323 //
324 ASSERT(FDODeviceExtension->InterfaceListCount);
325
326 //
327 // done
328 //
329 return STATUS_SUCCESS;
330 }
331
332 VOID
333 DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
334 {
335 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor);
336 DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength);
337 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
338 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
339 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
340 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
341 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
342 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
343 DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
344 }
345
346 NTSTATUS
347 USBCCGP_SelectInterface(
348 IN PDEVICE_OBJECT DeviceObject,
349 IN PFDO_DEVICE_EXTENSION DeviceExtension,
350 IN ULONG InterfaceIndex)
351 {
352 NTSTATUS Status;
353 PURB Urb;
354
355 //
356 // allocate urb
357 //
358 Urb = AllocateItem(NonPagedPool, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints));
359 if (!Urb)
360 {
361 //
362 // no memory
363 //
364 return STATUS_INSUFFICIENT_RESOURCES;
365 }
366
367 //
368 // now prepare interface urb
369 //
370 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bInterfaceNumber, DeviceExtension->InterfaceList[InterfaceIndex].InterfaceDescriptor->bAlternateSetting);
371
372 //
373 // now select the interface
374 //
375 Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb);
376
377 //
378 // did it succeeed
379 //
380 if (NT_SUCCESS(Status))
381 {
382 //
383 // update configuration info
384 //
385 ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceList[InterfaceIndex].Interface->Length);
386 RtlCopyMemory(DeviceExtension->InterfaceList[InterfaceIndex].Interface, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
387 }
388
389 //
390 // free urb
391 //
392 FreeItem(Urb);
393
394 //
395 // done
396 //
397 return Status;
398 }
399
400 NTSTATUS
401 USBCCGP_SelectConfiguration(
402 IN PDEVICE_OBJECT DeviceObject,
403 IN PFDO_DEVICE_EXTENSION DeviceExtension)
404 {
405 PUSBD_INTERFACE_INFORMATION InterfaceInformation;
406 NTSTATUS Status;
407 PURB Urb;
408 ULONG Index;
409
410 //
411 // now scan configuration descriptors
412 //
413 Status = USBCCGP_ScanConfigurationDescriptor(DeviceExtension, DeviceExtension->ConfigurationDescriptor);
414 if (!NT_SUCCESS(Status))
415 {
416 //
417 // failed to scan
418 //
419 return Status;
420 }
421
422 //
423 // now allocate the urb
424 //
425 Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, DeviceExtension->InterfaceList);
426 if (!Urb)
427 {
428 //
429 // no memory
430 //
431 return STATUS_INSUFFICIENT_RESOURCES;
432 }
433
434 //
435 // submit urb
436 //
437 Status = USBCCGP_SyncUrbRequest(DeviceExtension->NextDeviceObject, Urb);
438 if (!NT_SUCCESS(Status))
439 {
440 //
441 // failed to set configuration
442 //
443 DPRINT1("USBCCGP_SyncUrbRequest failed to set interface %x\n", Status);
444 ExFreePool(Urb);
445 return Status;
446 }
447
448 //
449 // get interface information
450 //
451 InterfaceInformation = &Urb->UrbSelectConfiguration.Interface;
452 for(Index = 0; Index < DeviceExtension->InterfaceListCount; Index++)
453 {
454 //
455 // allocate buffer to store interface information
456 //
457 DeviceExtension->InterfaceList[Index].Interface = AllocateItem(NonPagedPool, InterfaceInformation->Length);
458 if (!DeviceExtension->InterfaceList[Index].Interface)
459 {
460 //
461 // no memory
462 //
463 return STATUS_INSUFFICIENT_RESOURCES;
464 }
465
466 //
467 // copy interface information
468 //
469 RtlCopyMemory(DeviceExtension->InterfaceList[Index].Interface, InterfaceInformation, InterfaceInformation->Length);
470
471 //
472 // move to next interface
473 //
474 InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)((ULONG_PTR)InterfaceInformation + InterfaceInformation->Length);
475 }
476
477
478 //
479 // store pipe handle
480 //
481 DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
482
483 //
484 // free interface list & urb
485 //
486 ExFreePool(Urb);
487
488 //
489 // done
490 //
491 return Status;
492 }
493