xref: /reactos/drivers/usb/usbstor/descriptor.c (revision c2c66aff)
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 #define NDEBUG
15 #include <debug.h>
16 
17 NTSTATUS
18 NTAPI
19 USBSTOR_GetDescriptor(
20     IN PDEVICE_OBJECT DeviceObject,
21     IN UCHAR DescriptorType,
22     IN ULONG DescriptorLength,
23     IN UCHAR DescriptorIndex,
24     IN LANGID LanguageId,
25     OUT PVOID *OutDescriptor)
26 {
27     PURB Urb;
28     NTSTATUS Status;
29     PVOID Descriptor;
30 
31     //
32     // sanity checks
33     //
34     ASSERT(DeviceObject);
35     ASSERT(OutDescriptor);
36     ASSERT(DescriptorLength);
37 
38     //
39     // first allocate descriptor buffer
40     //
41     Descriptor = AllocateItem(NonPagedPool, DescriptorLength);
42     if (!Descriptor)
43     {
44         //
45         // no memory
46         //
47         return STATUS_INSUFFICIENT_RESOURCES;
48     }
49 
50     //
51     // allocate urb
52     //
53     Urb = (PURB) AllocateItem(NonPagedPool, sizeof(URB));
54     if (!Urb)
55     {
56         //
57         // no memory
58         //
59         FreeItem(Descriptor);
60         return STATUS_INSUFFICIENT_RESOURCES;
61     }
62 
63     //
64     // initialize urb
65     //
66     UsbBuildGetDescriptorRequest(Urb,
67                                  sizeof(Urb->UrbControlDescriptorRequest),
68                                  DescriptorType,
69                                  DescriptorIndex,
70                                  LanguageId,
71                                  Descriptor,
72                                  NULL,
73                                  DescriptorLength,
74                                  NULL);
75 
76     //
77     // submit urb
78     //
79     Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
80 
81     //
82     // free urb
83     //
84     FreeItem(Urb);
85 
86     if (NT_SUCCESS(Status))
87     {
88         //
89         // store result
90         //
91         *OutDescriptor = Descriptor;
92     }
93 
94     //
95     // done
96     //
97     return Status;
98 }
99 
100 
101 NTSTATUS
102 USBSTOR_GetDescriptors(
103     IN PDEVICE_OBJECT DeviceObject)
104 {
105     NTSTATUS Status;
106     PFDO_DEVICE_EXTENSION DeviceExtension;
107     USHORT DescriptorLength;
108 
109     //
110     // get device extension
111     //
112     DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
113 
114      //
115      // first get device descriptor
116      //
117      Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_DEVICE_DESCRIPTOR_TYPE, sizeof(USB_DEVICE_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->DeviceDescriptor);
118      if (!NT_SUCCESS(Status))
119      {
120          //
121          // failed to get device descriptor
122          //
123          DeviceExtension->DeviceDescriptor = NULL;
124          return Status;
125      }
126 
127      //
128      // now get basic configuration descriptor
129      //
130      Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, sizeof(USB_CONFIGURATION_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
131      if (!NT_SUCCESS(Status))
132      {
133          //
134          // failed to get configuration descriptor
135          //
136          FreeItem(DeviceExtension->DeviceDescriptor);
137          DeviceExtension->DeviceDescriptor = NULL;
138          return Status;
139      }
140 
141      //
142      // backup length
143      //
144      DescriptorLength = DeviceExtension->ConfigurationDescriptor->wTotalLength;
145 
146      //
147      // release basic descriptor
148      //
149      FreeItem(DeviceExtension->ConfigurationDescriptor);
150      DeviceExtension->ConfigurationDescriptor = NULL;
151 
152      //
153      // allocate full descriptor
154      //
155      Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, DescriptorLength, 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
156      if (!NT_SUCCESS(Status))
157      {
158          //
159          // failed to get configuration descriptor
160          //
161          FreeItem(DeviceExtension->DeviceDescriptor);
162          DeviceExtension->DeviceDescriptor = NULL;
163          return Status;
164      }
165 
166      //
167      // check if there is a serial number provided
168      //
169      if (DeviceExtension->DeviceDescriptor->iSerialNumber)
170      {
171          //
172          // get serial number
173          //
174          Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_STRING_DESCRIPTOR_TYPE, 100 * sizeof(WCHAR), DeviceExtension->DeviceDescriptor->iSerialNumber, 0x0409, (PVOID*)&DeviceExtension->SerialNumber);
175          if (!NT_SUCCESS(Status))
176          {
177              //
178              // failed to get serial number descriptor, free device descriptor
179              //
180              FreeItem(DeviceExtension->DeviceDescriptor);
181              DeviceExtension->DeviceDescriptor = NULL;
182 
183              //
184              // free configuration descriptor
185              //
186              FreeItem(DeviceExtension->ConfigurationDescriptor);
187              DeviceExtension->ConfigurationDescriptor = NULL;
188 
189              //
190              // set serial number to zero
191              //
192              DeviceExtension->SerialNumber = NULL;
193              return Status;
194           }
195      }
196 
197      return Status;
198 }
199 
200 NTSTATUS
201 NTAPI
202 USBSTOR_ScanConfigurationDescriptor(
203     IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
204     OUT PUSB_INTERFACE_DESCRIPTOR * OutInterfaceDescriptor,
205     OUT PUSB_ENDPOINT_DESCRIPTOR  * InEndpointDescriptor,
206     OUT PUSB_ENDPOINT_DESCRIPTOR  * OutEndpointDescriptor)
207 {
208     PUSB_CONFIGURATION_DESCRIPTOR CurrentDescriptor;
209     PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
210 
211     //
212     // sanity checks
213     //
214     ASSERT(ConfigurationDescriptor);
215     ASSERT(OutInterfaceDescriptor);
216     ASSERT(InEndpointDescriptor);
217     ASSERT(OutEndpointDescriptor);
218 
219     //
220     // nullify pointers
221     //
222     *OutInterfaceDescriptor = NULL;
223     *InEndpointDescriptor = NULL;
224     *OutEndpointDescriptor = NULL;
225 
226     //
227     // start scanning
228     //
229     CurrentDescriptor = ConfigurationDescriptor;
230 
231     do
232     {
233         //
234         // check current descriptor type
235         //
236         if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
237         {
238             //
239             // found interface descriptor
240             //
241             if (*OutInterfaceDescriptor)
242             {
243                 //
244                 // we only process the first interface descriptor as ms does -> see documentation
245                 //
246                 break;
247             }
248 
249             //
250             // store interface descriptor
251             //
252             *OutInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)CurrentDescriptor;
253         }
254         else if (CurrentDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
255         {
256             //
257             // convert to endpoint descriptor
258             //
259             EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)CurrentDescriptor;
260 
261             //
262             // sanity check
263             //
264             ASSERT(*OutInterfaceDescriptor);
265 
266             //
267             // get endpoint type
268             //
269             if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK)
270             {
271                  //
272                  // bulk endpoint type
273                  //
274                  if (USB_ENDPOINT_DIRECTION_IN(EndpointDescriptor->bEndpointAddress))
275                  {
276                      //
277                      // bulk in
278                      //
279                      *InEndpointDescriptor = EndpointDescriptor;
280                  }
281                  else
282                  {
283                      //
284                      // bulk out
285                      //
286                      *OutEndpointDescriptor = EndpointDescriptor;
287                  }
288             }
289             else if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT)
290             {
291                  //
292                  // interrupt endpoint type
293                  //
294                  UNIMPLEMENTED;
295             }
296         }
297 
298         //
299         // move to next descriptor
300         //
301         CurrentDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)CurrentDescriptor + CurrentDescriptor->bLength);
302 
303         //
304         // was it the last descriptor
305         //
306         if ((ULONG_PTR)CurrentDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
307         {
308             //
309             // reached last descriptor
310             //
311             break;
312         }
313 
314     }while(TRUE);
315 
316     //
317     // check if everything has been found
318     //
319     if (*OutInterfaceDescriptor == NULL || *InEndpointDescriptor == NULL || *OutEndpointDescriptor == NULL)
320     {
321         //
322         // failed to find interface / endpoint descriptor
323         //
324         DPRINT1("USBSTOR_ScanConfigurationDescriptor: Failed to find InterfaceDescriptor %p InEndpointDescriptor %p OutEndpointDescriptor %p\n", *OutInterfaceDescriptor, *InEndpointDescriptor, *OutEndpointDescriptor);
325         return STATUS_UNSUCCESSFUL;
326     }
327 
328     //
329     // completed successfully
330     //
331     return STATUS_SUCCESS;
332 }
333 
334 VOID
335 DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
336 {
337     DPRINT1("Dumping ConfigurationDescriptor %p\n", ConfigurationDescriptor);
338     DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength);
339     DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
340     DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
341     DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
342     DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
343     DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
344     DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
345     DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
346 }
347 
348 NTSTATUS
349 USBSTOR_SelectConfigurationAndInterface(
350     IN PDEVICE_OBJECT DeviceObject,
351     IN PFDO_DEVICE_EXTENSION DeviceExtension)
352 {
353     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
354     PUSB_ENDPOINT_DESCRIPTOR InEndpointDescriptor, OutEndpointDescriptor;
355     NTSTATUS Status;
356     PURB Urb;
357     PUSBD_INTERFACE_LIST_ENTRY InterfaceList;
358 
359     //
360     // now scan configuration descriptors
361     //
362     Status = USBSTOR_ScanConfigurationDescriptor(DeviceExtension->ConfigurationDescriptor, &InterfaceDescriptor, &InEndpointDescriptor, &OutEndpointDescriptor);
363     if (!NT_SUCCESS(Status))
364     {
365         //
366         // failed to scan
367         //
368         return Status;
369     }
370 
371     //
372     // now allocate one interface entry and terminating null entry
373     //
374     InterfaceList = (PUSBD_INTERFACE_LIST_ENTRY)AllocateItem(PagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * 2);
375     if (!InterfaceList)
376     {
377         //
378         // no memory
379         //
380         return STATUS_INSUFFICIENT_RESOURCES;
381     }
382 
383     //
384     // initialize interface list entry
385     //
386     InterfaceList[0].InterfaceDescriptor = InterfaceDescriptor;
387 
388     //
389     // now allocate the urb
390     //
391     Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, InterfaceList);
392     if (!Urb)
393     {
394         //
395         // no memory
396         //
397         FreeItem(InterfaceList);
398         return STATUS_INSUFFICIENT_RESOURCES;
399     }
400 
401     //
402     // sanity check
403     //
404     ASSERT(InterfaceList[0].Interface);
405 
406     //
407     // submit urb
408     //
409     Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb);
410     if (!NT_SUCCESS(Status))
411     {
412         //
413         // failed to set configuration
414         //
415         DPRINT1("USBSTOR_SelectConfiguration failed to set interface %x\n", Status);
416         FreeItem(InterfaceList);
417         ExFreePoolWithTag(Urb, 0);
418         return Status;
419     }
420 
421     //
422     // backup interface information
423     //
424     DeviceExtension->InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)AllocateItem(NonPagedPool, Urb->UrbSelectConfiguration.Interface.Length);
425     if (!DeviceExtension->InterfaceInformation)
426     {
427         //
428         // failed to allocate interface information structure
429         //
430         FreeItem(InterfaceList);
431         ExFreePoolWithTag(Urb, 0);
432         return STATUS_INSUFFICIENT_RESOURCES;
433     }
434 
435     //
436     // copy interface information
437     //
438     RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectConfiguration.Interface, Urb->UrbSelectConfiguration.Interface.Length);
439 
440     //
441     // store pipe handle
442     //
443     DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
444 
445     //
446     // now prepare interface urb
447     //
448     UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
449 
450     //
451     // copy interface information structure back - as offset for SelectConfiguration / SelectInterface request do differ
452     //
453     RtlCopyMemory(&Urb->UrbSelectInterface.Interface, DeviceExtension->InterfaceInformation, DeviceExtension->InterfaceInformation->Length);
454 
455     //
456     // now select the interface
457     //
458     Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb);
459 
460     //
461     // did it succeed
462     //
463     if (NT_SUCCESS(Status))
464     {
465         //
466         // update configuration info
467         //
468         ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceInformation->Length);
469         RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
470     }
471 
472     //
473     // free interface list & urb
474     //
475     FreeItem(InterfaceList);
476     ExFreePoolWithTag(Urb, 0);
477 
478     //
479     // done
480     //
481     return Status;
482 }
483 
484 NTSTATUS
485 USBSTOR_GetPipeHandles(
486     IN PFDO_DEVICE_EXTENSION DeviceExtension)
487 {
488     ULONG Index;
489     BOOLEAN BulkInFound = FALSE, BulkOutFound = FALSE;
490 
491     //
492     // no enumerate all pipes and extract bulk-in / bulk-out pipe handle
493     //
494     for(Index = 0; Index < DeviceExtension->InterfaceInformation->NumberOfPipes; Index++)
495     {
496         //
497         // check pipe type
498         //
499         if (DeviceExtension->InterfaceInformation->Pipes[Index].PipeType == UsbdPipeTypeBulk)
500         {
501             //
502             // check direction
503             //
504             if (USB_ENDPOINT_DIRECTION_IN(DeviceExtension->InterfaceInformation->Pipes[Index].EndpointAddress))
505             {
506                 //
507                 // bulk in pipe
508                 //
509                 DeviceExtension->BulkInPipeIndex = Index;
510 
511                 //
512                 // there should not be another bulk in pipe
513                 //
514                 ASSERT(BulkInFound == FALSE);
515                 BulkInFound = TRUE;
516             }
517             else
518             {
519                 //
520                 // bulk out pipe
521                 //
522                 DeviceExtension->BulkOutPipeIndex = Index;
523 
524                 //
525                 // there should not be another bulk out pipe
526                 //
527                 ASSERT(BulkOutFound == FALSE);
528                 BulkOutFound = TRUE;
529             }
530         }
531     }
532 
533     //
534     // check if both bulk pipes have been found
535     //
536     if (!BulkInFound || !BulkOutFound)
537     {
538         //
539         // WTF? usb port driver does not give us bulk pipe access
540         //
541         DPRINT1("USBSTOR_GetPipeHandles> BulkInFound %c BulkOutFound %c missing!!!\n", BulkInFound, BulkOutFound);
542         return STATUS_DEVICE_CONFIGURATION_ERROR;
543     }
544 
545     //
546     // device is configured
547     //
548     return STATUS_SUCCESS;
549 }
550