xref: /reactos/drivers/usb/usbstor/descriptor.c (revision d6eebaa4)
1 /*
2  * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     USB block storage device driver.
5  * COPYRIGHT:   2005-2006 James Tabor
6  *              2011-2012 Michael Martin (michael.martin@reactos.org)
7  *              2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org)
8  */
9 
10 #include "usbstor.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 
16 NTSTATUS
17 NTAPI
18 USBSTOR_GetDescriptor(
19     IN PDEVICE_OBJECT DeviceObject,
20     IN UCHAR DescriptorType,
21     IN ULONG DescriptorLength,
22     IN UCHAR DescriptorIndex,
23     IN LANGID LanguageId,
24     OUT PVOID *OutDescriptor)
25 {
26     PURB Urb;
27     NTSTATUS Status;
28     PVOID Descriptor;
29 
30     ASSERT(DeviceObject);
31     ASSERT(OutDescriptor);
32     ASSERT(DescriptorLength);
33 
34     // first allocate descriptor buffer
35     Descriptor = AllocateItem(NonPagedPool, DescriptorLength);
36     if (!Descriptor)
37     {
38         // no memory
39         return STATUS_INSUFFICIENT_RESOURCES;
40     }
41 
42     Urb = (PURB) AllocateItem(NonPagedPool, sizeof(URB));
43     if (!Urb)
44     {
45         // no memory
46         FreeItem(Descriptor);
47         return STATUS_INSUFFICIENT_RESOURCES;
48     }
49 
50     // initialize urb
51     UsbBuildGetDescriptorRequest(Urb,
52                                  sizeof(Urb->UrbControlDescriptorRequest),
53                                  DescriptorType,
54                                  DescriptorIndex,
55                                  LanguageId,
56                                  Descriptor,
57                                  NULL,
58                                  DescriptorLength,
59                                  NULL);
60 
61     // submit urb
62     Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
63 
64     FreeItem(Urb);
65 
66     if (NT_SUCCESS(Status))
67     {
68         *OutDescriptor = Descriptor;
69     }
70 
71     return Status;
72 }
73 
74 NTSTATUS
75 USBSTOR_GetDescriptors(
76     IN PDEVICE_OBJECT DeviceObject)
77 {
78     NTSTATUS Status;
79     PFDO_DEVICE_EXTENSION DeviceExtension;
80     USHORT DescriptorLength;
81 
82     DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
83 
84      // first get device descriptor
85      Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_DEVICE_DESCRIPTOR_TYPE, sizeof(USB_DEVICE_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->DeviceDescriptor);
86      if (!NT_SUCCESS(Status))
87      {
88          DeviceExtension->DeviceDescriptor = NULL;
89          return Status;
90      }
91 
92      // now get basic configuration descriptor
93      Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, sizeof(USB_CONFIGURATION_DESCRIPTOR), 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
94      if (!NT_SUCCESS(Status))
95      {
96          FreeItem(DeviceExtension->DeviceDescriptor);
97          DeviceExtension->DeviceDescriptor = NULL;
98          return Status;
99      }
100 
101      // backup length
102      DescriptorLength = DeviceExtension->ConfigurationDescriptor->wTotalLength;
103 
104      // release basic descriptor
105      FreeItem(DeviceExtension->ConfigurationDescriptor);
106      DeviceExtension->ConfigurationDescriptor = NULL;
107 
108      // allocate full descriptor
109      Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_CONFIGURATION_DESCRIPTOR_TYPE, DescriptorLength, 0, 0, (PVOID*)&DeviceExtension->ConfigurationDescriptor);
110      if (!NT_SUCCESS(Status))
111      {
112          FreeItem(DeviceExtension->DeviceDescriptor);
113          DeviceExtension->DeviceDescriptor = NULL;
114          return Status;
115      }
116 
117      // check if there is a serial number provided
118      if (DeviceExtension->DeviceDescriptor->iSerialNumber)
119      {
120          // get serial number
121          Status = USBSTOR_GetDescriptor(DeviceExtension->LowerDeviceObject, USB_STRING_DESCRIPTOR_TYPE, MAXIMUM_USB_STRING_LENGTH, DeviceExtension->DeviceDescriptor->iSerialNumber, 0x0409, (PVOID*)&DeviceExtension->SerialNumber);
122          if (!NT_SUCCESS(Status))
123          {
124              FreeItem(DeviceExtension->DeviceDescriptor);
125              DeviceExtension->DeviceDescriptor = NULL;
126 
127              FreeItem(DeviceExtension->ConfigurationDescriptor);
128              DeviceExtension->ConfigurationDescriptor = NULL;
129 
130              DeviceExtension->SerialNumber = NULL;
131              return Status;
132           }
133      }
134 
135      return Status;
136 }
137 
138 NTSTATUS
139 NTAPI
140 USBSTOR_ScanConfigurationDescriptor(
141     IN PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor,
142     OUT PUSB_INTERFACE_DESCRIPTOR *OutInterfaceDescriptor,
143     OUT PUSB_ENDPOINT_DESCRIPTOR  *InEndpointDescriptor,
144     OUT PUSB_ENDPOINT_DESCRIPTOR  *OutEndpointDescriptor)
145 {
146     PUSB_CONFIGURATION_DESCRIPTOR CurrentDescriptor;
147     PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor;
148 
149     ASSERT(ConfigurationDescriptor);
150     ASSERT(OutInterfaceDescriptor);
151     ASSERT(InEndpointDescriptor);
152     ASSERT(OutEndpointDescriptor);
153 
154     *OutInterfaceDescriptor = NULL;
155     *InEndpointDescriptor = NULL;
156     *OutEndpointDescriptor = NULL;
157 
158     // start scanning
159     CurrentDescriptor = ConfigurationDescriptor;
160 
161     do
162     {
163         if (CurrentDescriptor->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE)
164         {
165             if (*OutInterfaceDescriptor)
166             {
167                 // we only process the first interface descriptor as ms does -> see documentation
168                 break;
169             }
170 
171             // store interface descriptor
172             *OutInterfaceDescriptor = (PUSB_INTERFACE_DESCRIPTOR)CurrentDescriptor;
173         }
174         else if (CurrentDescriptor->bDescriptorType == USB_ENDPOINT_DESCRIPTOR_TYPE)
175         {
176             EndpointDescriptor = (PUSB_ENDPOINT_DESCRIPTOR)CurrentDescriptor;
177 
178             ASSERT(*OutInterfaceDescriptor);
179 
180             // get endpoint type
181             if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_BULK)
182             {
183                 if (USB_ENDPOINT_DIRECTION_IN(EndpointDescriptor->bEndpointAddress))
184                 {
185                     *InEndpointDescriptor = EndpointDescriptor;
186                 }
187                 else
188                 {
189                     *OutEndpointDescriptor = EndpointDescriptor;
190                 }
191             }
192             else if ((EndpointDescriptor->bmAttributes & USB_ENDPOINT_TYPE_MASK) == USB_ENDPOINT_TYPE_INTERRUPT)
193             {
194                 UNIMPLEMENTED;
195             }
196         }
197 
198         // move to next descriptor
199         CurrentDescriptor = (PUSB_CONFIGURATION_DESCRIPTOR)((ULONG_PTR)CurrentDescriptor + CurrentDescriptor->bLength);
200 
201         // was it the last descriptor
202         if ((ULONG_PTR)CurrentDescriptor >= ((ULONG_PTR)ConfigurationDescriptor + ConfigurationDescriptor->wTotalLength))
203         {
204             break;
205         }
206 
207     } while(TRUE);
208 
209     // check if everything has been found
210     if (*OutInterfaceDescriptor == NULL || *InEndpointDescriptor == NULL || *OutEndpointDescriptor == NULL)
211     {
212         DPRINT1("USBSTOR_ScanConfigurationDescriptor: Failed to find InterfaceDescriptor %p InEndpointDescriptor %p OutEndpointDescriptor %p\n", *OutInterfaceDescriptor, *InEndpointDescriptor, *OutEndpointDescriptor);
213         return STATUS_UNSUCCESSFUL;
214     }
215 
216     return STATUS_SUCCESS;
217 }
218 
219 VOID
220 DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor)
221 {
222     DPRINT1("Dumping ConfigurationDescriptor %p\n", ConfigurationDescriptor);
223     DPRINT1("bLength %x\n", ConfigurationDescriptor->bLength);
224     DPRINT1("bDescriptorType %x\n", ConfigurationDescriptor->bDescriptorType);
225     DPRINT1("wTotalLength %x\n", ConfigurationDescriptor->wTotalLength);
226     DPRINT1("bNumInterfaces %x\n", ConfigurationDescriptor->bNumInterfaces);
227     DPRINT1("bConfigurationValue %x\n", ConfigurationDescriptor->bConfigurationValue);
228     DPRINT1("iConfiguration %x\n", ConfigurationDescriptor->iConfiguration);
229     DPRINT1("bmAttributes %x\n", ConfigurationDescriptor->bmAttributes);
230     DPRINT1("MaxPower %x\n", ConfigurationDescriptor->MaxPower);
231 }
232 
233 NTSTATUS
234 USBSTOR_SelectConfigurationAndInterface(
235     IN PDEVICE_OBJECT DeviceObject,
236     IN PFDO_DEVICE_EXTENSION DeviceExtension)
237 {
238     PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor;
239     PUSB_ENDPOINT_DESCRIPTOR InEndpointDescriptor, OutEndpointDescriptor;
240     NTSTATUS Status;
241     PURB Urb;
242     PUSBD_INTERFACE_LIST_ENTRY InterfaceList;
243 
244     Status = USBSTOR_ScanConfigurationDescriptor(DeviceExtension->ConfigurationDescriptor, &InterfaceDescriptor, &InEndpointDescriptor, &OutEndpointDescriptor);
245     if (!NT_SUCCESS(Status))
246     {
247         return Status;
248     }
249 
250     // now allocate one interface entry and terminating null entry
251     InterfaceList = (PUSBD_INTERFACE_LIST_ENTRY)AllocateItem(PagedPool, sizeof(USBD_INTERFACE_LIST_ENTRY) * 2);
252     if (!InterfaceList)
253     {
254         return STATUS_INSUFFICIENT_RESOURCES;
255     }
256 
257     // initialize interface list entry
258     InterfaceList[0].InterfaceDescriptor = InterfaceDescriptor;
259 
260     // now allocate the urb
261     Urb = USBD_CreateConfigurationRequestEx(DeviceExtension->ConfigurationDescriptor, InterfaceList);
262     if (!Urb)
263     {
264         FreeItem(InterfaceList);
265         return STATUS_INSUFFICIENT_RESOURCES;
266     }
267 
268 
269     ASSERT(InterfaceList[0].Interface);
270 
271     // submit urb
272     Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb);
273     if (!NT_SUCCESS(Status))
274     {
275         // failed to set configuration
276         DPRINT1("USBSTOR_SelectConfiguration failed to set interface %x\n", Status);
277         FreeItem(InterfaceList);
278         ExFreePoolWithTag(Urb, 0);
279         return Status;
280     }
281 
282     // backup interface information
283     DeviceExtension->InterfaceInformation = (PUSBD_INTERFACE_INFORMATION)AllocateItem(NonPagedPool, Urb->UrbSelectConfiguration.Interface.Length);
284     if (!DeviceExtension->InterfaceInformation)
285     {
286         FreeItem(InterfaceList);
287         ExFreePoolWithTag(Urb, 0);
288         return STATUS_INSUFFICIENT_RESOURCES;
289     }
290 
291     // copy interface information
292     RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectConfiguration.Interface, Urb->UrbSelectConfiguration.Interface.Length);
293 
294     // store pipe handle
295     DeviceExtension->ConfigurationHandle = Urb->UrbSelectConfiguration.ConfigurationHandle;
296 
297     // now prepare interface urb
298     UsbBuildSelectInterfaceRequest(Urb, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor->bNumEndpoints), DeviceExtension->ConfigurationHandle, InterfaceDescriptor->bInterfaceNumber, InterfaceDescriptor->bAlternateSetting);
299 
300     // copy interface information structure back - as offset for SelectConfiguration / SelectInterface request do differ
301     RtlCopyMemory(&Urb->UrbSelectInterface.Interface, DeviceExtension->InterfaceInformation, DeviceExtension->InterfaceInformation->Length);
302 
303     // now select the interface
304     Status = USBSTOR_SyncUrbRequest(DeviceExtension->LowerDeviceObject, Urb);
305     if (NT_SUCCESS(Status))
306     {
307         // update configuration info
308         ASSERT(Urb->UrbSelectInterface.Interface.Length == DeviceExtension->InterfaceInformation->Length);
309         RtlCopyMemory(DeviceExtension->InterfaceInformation, &Urb->UrbSelectInterface.Interface, Urb->UrbSelectInterface.Interface.Length);
310     }
311 
312     FreeItem(InterfaceList);
313     ExFreePoolWithTag(Urb, 0);
314 
315     return Status;
316 }
317 
318 NTSTATUS
319 USBSTOR_GetPipeHandles(
320     IN PFDO_DEVICE_EXTENSION DeviceExtension)
321 {
322     ULONG Index;
323     BOOLEAN BulkInFound = FALSE, BulkOutFound = FALSE;
324 
325     // enumerate all pipes and extract bulk-in / bulk-out pipe handle
326     for (Index = 0; Index < DeviceExtension->InterfaceInformation->NumberOfPipes; Index++)
327     {
328         if (DeviceExtension->InterfaceInformation->Pipes[Index].PipeType == UsbdPipeTypeBulk)
329         {
330             if (USB_ENDPOINT_DIRECTION_IN(DeviceExtension->InterfaceInformation->Pipes[Index].EndpointAddress))
331             {
332                 DeviceExtension->BulkInPipeIndex = Index;
333 
334                 // there should not be another bulk in pipe
335                 ASSERT(BulkInFound == FALSE);
336                 BulkInFound = TRUE;
337             }
338             else
339             {
340                 DeviceExtension->BulkOutPipeIndex = Index;
341 
342                 // there should not be another bulk out pipe
343                 ASSERT(BulkOutFound == FALSE);
344                 BulkOutFound = TRUE;
345             }
346         }
347     }
348 
349     if (!BulkInFound || !BulkOutFound)
350     {
351         // WTF? usb port driver does not give us bulk pipe access
352         DPRINT1("USBSTOR_GetPipeHandles> BulkInFound %c BulkOutFound %c missing!!!\n", BulkInFound, BulkOutFound);
353         return STATUS_DEVICE_CONFIGURATION_ERROR;
354     }
355 
356     return STATUS_SUCCESS;
357 }
358