[USBOHCI]
[reactos.git] / drivers / usb / usbstor / descriptor.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbstor/descriptor.c
5 * PURPOSE: USB block storage device driver.
6 * PROGRAMMERS:
7 * James Tabor
8 * Michael Martin (michael.martin@reactos.org)
9 * Johannes Anderwald (johannes.anderwald@reactos.org)
10 */
11
12 #include "usbstor.h"
13
14 NTSTATUS
15 NTAPI
16 USBSTOR_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 = USBSTOR_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 USBSTOR_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 = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, 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 = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, 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 = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, 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
163 //
164 // check if there is a serial number provided
165 //
166 if (DeviceExtension->DeviceDescriptor->iSerialNumber)
167 {
168 //
169 // get serial number
170 //
171 Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_STRING_DESCRIPTOR_TYPE, 100 * sizeof(WCHAR), DeviceExtension->DeviceDescriptor->iSerialNumber, 0x0409, (PVOID*)&DeviceExtension->SerialNumber);
172 if (!NT_SUCCESS(Status))
173 {
174 //
175 // failed to get serial number descriptor, free device descriptor
176 //
177 FreeItem(DeviceExtension->DeviceDescriptor);
178 DeviceExtension->DeviceDescriptor = NULL;
179
180 //
181 // free configuration descriptor
182 //
183 FreeItem(DeviceExtension->ConfigurationDescriptor);
184 DeviceExtension->ConfigurationDescriptor = NULL;
185
186 //
187 // set serial number to zero
188 //
189 DeviceExtension->SerialNumber = NULL;
190 return Status;
191 }
192 }
193
194 return Status;
195 }
196
197 NTSTATUS
198 NTAPI
199 USBSTOR_ScanConfigurationDescriptor(
200 IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
201 OUT PUSB_INTERFACE_DESCRIPTOR * OutInterfaceDescriptor,
202 OUT PUSB_ENDPOINT_DESCRIPTOR * InEndpointDescriptor,
203 OUT PUSB_ENDPOINT_DESCRIPTOR * OutEndpointDescriptor)
204 {
205 PUSB_CONFIGURATION_DESCRIPTOR CurrentDescriptor;
206 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
207
208 //
209 // sanity checks
210 //
211 ASSERT(ConfigurationDescriptor);
212 ASSERT(OutInterfaceDescriptor);
213 ASSERT(InEndpointDescriptor);
214 ASSERT(OutEndpointDescriptor);
215
216 //
217 // nullify pointers
218 //
219 *OutInterfaceDescriptor = NULL;
220 *InEndpointDescriptor = NULL;
221 *OutEndpointDescriptor = NULL;
222
223 //
224 // start scanning
225 //
226 CurrentDescriptor = ConfigurationDescriptor;
227
228 do
229 {
230 //
231 // check current descriptor type
232 //
233 if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
234 {
235 //
236 // found interface descriptor
237 //
238 if (*OutInterfaceDescriptor)
239 {
240 //
241 // we only process the first interface descriptor as ms does -> see documentation
242 //
243 break;
244 }
245
246 //
247 // store interface descriptor
248 //
249 *OutInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)CurrentDescriptor;
250 }
251 else if (CurrentDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
252 {
253 //
254 // convert to endpoint descriptor
255 //
256 EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)CurrentDescriptor;
257
258 //
259 // sanity check
260 //
261 ASSERT(*OutInterfaceDescriptor);
262
263 //
264 // get endpoint type
265 //
266 if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK)
267 {
268 //
269 // bulk endpoint type
270 //
271 if (USB_ENDPOINT_DIRECTION_IN(EndpointDescriptor->bEndpointAddress))
272 {
273 //
274 // bulk in
275 //
276 *InEndpointDescriptor = EndpointDescriptor;
277 }
278 else
279 {
280 //
281 // bulk out
282 //
283 *OutEndpointDescriptor = EndpointDescriptor;
284 }
285 }
286 else if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT)
287 {
288 //
289 // interrupt endpoint type
290 //
291 UNIMPLEMENTED
292 }
293 }
294
295 //
296 // move to next descriptor
297 //
298 CurrentDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)CurrentDescriptor + CurrentDescriptor->bLength);
299
300 //
301 // was it the last descriptor
302 //
303 if ((ULONG_PTR)CurrentDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
304 {
305 //
306 // reached last descriptor
307 //
308 break;
309 }
310
311 }while(TRUE);
312
313 //
314 // check if everything has been found
315 //
316 if (*OutInterfaceDescriptor == NULL || *InEndpointDescriptor == NULL || *OutEndpointDescriptor == NULL)
317 {
318 //
319 // failed to find interface / endpoint descriptor
320 //
321 DPRINT1("USBSTOR_ScanConfigurationDescriptor: Failed to find InterfaceDescriptor %p InEndpointDescriptor %p OutEndpointDescriptor %p\n", *OutInterfaceDescriptor, *InEndpointDescriptor, *OutEndpointDescriptor);
322 return STATUS_UNSUCCESSFUL;
323 }
324
325 //
326 // completed successfully
327 //
328 return STATUS_SUCCESS;
329 }
330
331 VOID
332 DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
333 {
334 DPRINT1("Dumping ConfigurationDescriptor %x\n", ConfigurationDescriptor);
335 DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength);
336 DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
337 DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
338 DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
339 DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
340 DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
341 DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
342 DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
343 }
344
345 NTSTATUS
346 USBSTOR_SelectConfigurationAndInterface(
347 IN PDEVICE_OBJECT DeviceObject,
348 IN PFDO_DEVICE_EXTENSION DeviceExtension)
349 {
350 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
351 PUSB_ENDPOINT_DESCRIPTOR InEndpointDescriptor, OutEndpointDescriptor;
352 NTSTATUS Status;
353 PURB Urb;
354 PUSBD_INTERFACE_LIST_ENTRY InterfaceList;
355
356 //
357 // now scan configuration descriptors
358 //
359 Status = USBSTOR_ScanConfigurationDescriptor(DeviceExtension->ConfigurationDescriptor, &InterfaceDescriptor, &InEndpointDescriptor, &OutEndpointDescriptor);
360 if (!NT_SUCCESS(Status))
361 {
362 //
363 // failed to scan
364 //
365 return Status;
366 }
367
368 //
369 // now allocate one interface entry and terminating null entry
370 //
371 InterfaceList = (PUSBD_INTERFACE_LIST_ENTRY)AllocateItem(PagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * 2);
372 if (!InterfaceList)
373 {
374 //
375 // no memory
376 //
377 return STATUS_INSUFFICIENT_RESOURCES;
378 }
379
380 //
381 // initialize interface list entry
382 //
383 InterfaceList[0].InterfaceDescriptor = InterfaceDescriptor;
384
385 //
386 // now allocate the urb
387 //
388 Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, InterfaceList);
389 if (!Urb)
390 {
391 //
392 // no memory
393 //
394 FreeItem(InterfaceList);
395 return STATUS_INSUFFICIENT_RESOURCES;
396 }
397
398 //
399 // sanity check
400 //
401 ASSERT(InterfaceList[0].Interface);
402
403 //
404 // submit urb
405 //
406 Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb);
407 if (!NT_SUCCESS(Status))
408 {
409 //
410 // failed to set configuration
411 //
412 DPRINT1("USBSTOR_SelectConfiguration failed to set interface %x\n", Status);
413 FreeItem(InterfaceList);
414 ExFreePool(Urb);
415 return Status;
416 }
417
418 //
419 // backup interface information
420 //
421 DeviceExtension->InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)AllocateItem(NonPagedPool, Urb->UrbSelectConfiguration.Interface.Length);
422 if (!NT_SUCCESS(Status))
423 {
424 //
425 // failed to allocate interface information structure
426 //
427 FreeItem(InterfaceList);
428 ExFreePool(Urb);
429 return Status;
430 }
431
432 //
433 // copy interface information
434 //
435 RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectConfiguration.Interface, Urb->UrbSelectConfiguration.Interface.Length);
436
437 //
438 // store pipe handle
439 //
440 DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
441
442 //
443 // now prepare interface urb
444 //
445 UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
446
447 //
448 // copy interface information structure back - as offset for SelectConfiguration / SelectInterface request do differ
449 //
450 RtlCopyMemory(&Urb->UrbSelectInterface.Interface, DeviceExtension->InterfaceInformation, DeviceExtension->InterfaceInformation->Length);
451
452 //
453 // now select the interface
454 //
455 Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb);
456
457 //
458 // did it succeeed
459 //
460 if (NT_SUCCESS(Status))
461 {
462 //
463 // update configuration info
464 //
465 ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceInformation->Length);
466 RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
467 }
468
469 //
470 // free interface list & urb
471 //
472 FreeItem(InterfaceList);
473 ExFreePool(Urb);
474
475 //
476 // done
477 //
478 return Status;
479 }
480
481 NTSTATUS
482 USBSTOR_GetPipeHandles(
483 IN PFDO_DEVICE_EXTENSION DeviceExtension)
484 {
485 ULONG Index;
486 BOOLEAN BulkInFound = FALSE, BulkOutFound = FALSE;
487
488 //
489 // no enumerate all pipes and extract bulk-in / bulk-out pipe handle
490 //
491 for(Index = 0; Index < DeviceExtension->InterfaceInformation->NumberOfPipes; Index++)
492 {
493 //
494 // check pipe type
495 //
496 if (DeviceExtension->InterfaceInformation->Pipes[Index].PipeType == UsbdPipeTypeBulk)
497 {
498 //
499 // check direction
500 //
501 if (USB_ENDPOINT_DIRECTION_IN(DeviceExtension->InterfaceInformation->Pipes[Index].EndpointAddress))
502 {
503 //
504 // bulk in pipe
505 //
506 DeviceExtension->BulkInPipeIndex = Index;
507
508 //
509 // there should not be another bulk in pipe
510 //
511 ASSERT(BulkInFound == FALSE);
512 BulkInFound = TRUE;
513 }
514 else
515 {
516 //
517 // bulk out pipe
518 //
519 DeviceExtension->BulkOutPipeIndex = Index;
520
521 //
522 // there should not be another bulk out pipe
523 //
524 ASSERT(BulkOutFound == FALSE);
525 BulkOutFound = TRUE;
526 }
527 }
528 }
529
530 //
531 // check if both bulk pipes have been found
532 //
533 if (!BulkInFound || !BulkOutFound)
534 {
535 //
536 // WTF? usb port driver does not give us bulk pipe access
537 //
538 DPRINT1("USBSTOR_GetPipeHandles> BulkInFound %d BulkOutFound %d missing!!!\n", BulkInFound, BulkOutFound);
539 return STATUS_DEVICE_CONFIGURATION_ERROR;
540 }
541
542 //
543 // device is configured
544 //
545 return STATUS_SUCCESS;
546 }