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)
18 USBSTOR_GetDescriptor(
19 IN PDEVICE_OBJECT DeviceObject
,
20 IN UCHAR DescriptorType
,
21 IN ULONG DescriptorLength
,
22 IN UCHAR DescriptorIndex
,
24 OUT PVOID
*OutDescriptor
)
31 ASSERT(OutDescriptor
);
32 ASSERT(DescriptorLength
);
34 // first allocate descriptor buffer
35 Descriptor
= AllocateItem(NonPagedPool
, DescriptorLength
);
39 return STATUS_INSUFFICIENT_RESOURCES
;
42 Urb
= (PURB
) AllocateItem(NonPagedPool
, sizeof(URB
));
47 return STATUS_INSUFFICIENT_RESOURCES
;
51 UsbBuildGetDescriptorRequest(Urb
,
52 sizeof(Urb
->UrbControlDescriptorRequest
),
62 Status
= USBSTOR_SyncUrbRequest(DeviceObject
, Urb
);
66 if (NT_SUCCESS(Status
))
68 *OutDescriptor
= Descriptor
;
75 USBSTOR_GetDescriptors(
76 IN PDEVICE_OBJECT DeviceObject
)
79 PFDO_DEVICE_EXTENSION DeviceExtension
;
80 USHORT DescriptorLength
;
82 DeviceExtension
= (PFDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
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
))
88 DeviceExtension
->DeviceDescriptor
= NULL
;
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
))
96 FreeItem(DeviceExtension
->DeviceDescriptor
);
97 DeviceExtension
->DeviceDescriptor
= NULL
;
102 DescriptorLength
= DeviceExtension
->ConfigurationDescriptor
->wTotalLength
;
104 // release basic descriptor
105 FreeItem(DeviceExtension
->ConfigurationDescriptor
);
106 DeviceExtension
->ConfigurationDescriptor
= NULL
;
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
))
112 FreeItem(DeviceExtension
->DeviceDescriptor
);
113 DeviceExtension
->DeviceDescriptor
= NULL
;
117 // check if there is a serial number provided
118 if (DeviceExtension
->DeviceDescriptor
->iSerialNumber
)
121 Status
= USBSTOR_GetDescriptor(DeviceExtension
->LowerDeviceObject
, USB_STRING_DESCRIPTOR_TYPE
, 100 * sizeof(WCHAR
), DeviceExtension
->DeviceDescriptor
->iSerialNumber
, 0x0409, (PVOID
*)&DeviceExtension
->SerialNumber
);
122 if (!NT_SUCCESS(Status
))
124 FreeItem(DeviceExtension
->DeviceDescriptor
);
125 DeviceExtension
->DeviceDescriptor
= NULL
;
127 FreeItem(DeviceExtension
->ConfigurationDescriptor
);
128 DeviceExtension
->ConfigurationDescriptor
= NULL
;
130 DeviceExtension
->SerialNumber
= NULL
;
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
)
146 PUSB_CONFIGURATION_DESCRIPTOR CurrentDescriptor
;
147 PUSB_ENDPOINT_DESCRIPTOR EndpointDescriptor
;
149 ASSERT(ConfigurationDescriptor
);
150 ASSERT(OutInterfaceDescriptor
);
151 ASSERT(InEndpointDescriptor
);
152 ASSERT(OutEndpointDescriptor
);
154 *OutInterfaceDescriptor
= NULL
;
155 *InEndpointDescriptor
= NULL
;
156 *OutEndpointDescriptor
= NULL
;
159 CurrentDescriptor
= ConfigurationDescriptor
;
163 if (CurrentDescriptor
->bDescriptorType
== USB_INTERFACE_DESCRIPTOR_TYPE
)
165 if (*OutInterfaceDescriptor
)
167 // we only process the first interface descriptor as ms does -> see documentation
171 // store interface descriptor
172 *OutInterfaceDescriptor
= (PUSB_INTERFACE_DESCRIPTOR
)CurrentDescriptor
;
174 else if (CurrentDescriptor
->bDescriptorType
== USB_ENDPOINT_DESCRIPTOR_TYPE
)
176 EndpointDescriptor
= (PUSB_ENDPOINT_DESCRIPTOR
)CurrentDescriptor
;
178 ASSERT(*OutInterfaceDescriptor
);
181 if ((EndpointDescriptor
->bmAttributes
& USB_ENDPOINT_TYPE_MASK
) == USB_ENDPOINT_TYPE_BULK
)
183 if (USB_ENDPOINT_DIRECTION_IN(EndpointDescriptor
->bEndpointAddress
))
185 *InEndpointDescriptor
= EndpointDescriptor
;
189 *OutEndpointDescriptor
= EndpointDescriptor
;
192 else if ((EndpointDescriptor
->bmAttributes
& USB_ENDPOINT_TYPE_MASK
) == USB_ENDPOINT_TYPE_INTERRUPT
)
198 // move to next descriptor
199 CurrentDescriptor
= (PUSB_CONFIGURATION_DESCRIPTOR
)((ULONG_PTR
)CurrentDescriptor
+ CurrentDescriptor
->bLength
);
201 // was it the last descriptor
202 if ((ULONG_PTR
)CurrentDescriptor
>= ((ULONG_PTR
)ConfigurationDescriptor
+ ConfigurationDescriptor
->wTotalLength
))
209 // check if everything has been found
210 if (*OutInterfaceDescriptor
== NULL
|| *InEndpointDescriptor
== NULL
|| *OutEndpointDescriptor
== NULL
)
212 DPRINT1("USBSTOR_ScanConfigurationDescriptor: Failed to find InterfaceDescriptor %p InEndpointDescriptor %p OutEndpointDescriptor %p\n", *OutInterfaceDescriptor
, *InEndpointDescriptor
, *OutEndpointDescriptor
);
213 return STATUS_UNSUCCESSFUL
;
216 return STATUS_SUCCESS
;
220 DumpConfigurationDescriptor(PUSB_CONFIGURATION_DESCRIPTOR ConfigurationDescriptor
)
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
);
234 USBSTOR_SelectConfigurationAndInterface(
235 IN PDEVICE_OBJECT DeviceObject
,
236 IN PFDO_DEVICE_EXTENSION DeviceExtension
)
238 PUSB_INTERFACE_DESCRIPTOR InterfaceDescriptor
;
239 PUSB_ENDPOINT_DESCRIPTOR InEndpointDescriptor
, OutEndpointDescriptor
;
242 PUSBD_INTERFACE_LIST_ENTRY InterfaceList
;
244 Status
= USBSTOR_ScanConfigurationDescriptor(DeviceExtension
->ConfigurationDescriptor
, &InterfaceDescriptor
, &InEndpointDescriptor
, &OutEndpointDescriptor
);
245 if (!NT_SUCCESS(Status
))
250 // now allocate one interface entry and terminating null entry
251 InterfaceList
= (PUSBD_INTERFACE_LIST_ENTRY
)AllocateItem(PagedPool
, sizeof(USBD_INTERFACE_LIST_ENTRY
) * 2);
254 return STATUS_INSUFFICIENT_RESOURCES
;
257 // initialize interface list entry
258 InterfaceList
[0].InterfaceDescriptor
= InterfaceDescriptor
;
260 // now allocate the urb
261 Urb
= USBD_CreateConfigurationRequestEx(DeviceExtension
->ConfigurationDescriptor
, InterfaceList
);
264 FreeItem(InterfaceList
);
265 return STATUS_INSUFFICIENT_RESOURCES
;
269 ASSERT(InterfaceList
[0].Interface
);
272 Status
= USBSTOR_SyncUrbRequest(DeviceExtension
->LowerDeviceObject
, Urb
);
273 if (!NT_SUCCESS(Status
))
275 // failed to set configuration
276 DPRINT1("USBSTOR_SelectConfiguration failed to set interface %x\n", Status
);
277 FreeItem(InterfaceList
);
278 ExFreePoolWithTag(Urb
, 0);
282 // backup interface information
283 DeviceExtension
->InterfaceInformation
= (PUSBD_INTERFACE_INFORMATION
)AllocateItem(NonPagedPool
, Urb
->UrbSelectConfiguration
.Interface
.Length
);
284 if (!DeviceExtension
->InterfaceInformation
)
286 FreeItem(InterfaceList
);
287 ExFreePoolWithTag(Urb
, 0);
288 return STATUS_INSUFFICIENT_RESOURCES
;
291 // copy interface information
292 RtlCopyMemory(DeviceExtension
->InterfaceInformation
, &Urb
->UrbSelectConfiguration
.Interface
, Urb
->UrbSelectConfiguration
.Interface
.Length
);
295 DeviceExtension
->ConfigurationHandle
= Urb
->UrbSelectConfiguration
.ConfigurationHandle
;
297 // now prepare interface urb
298 UsbBuildSelectInterfaceRequest(Urb
, GET_SELECT_INTERFACE_REQUEST_SIZE(InterfaceDescriptor
->bNumEndpoints
), DeviceExtension
->ConfigurationHandle
, InterfaceDescriptor
->bInterfaceNumber
, InterfaceDescriptor
->bAlternateSetting
);
300 // copy interface information structure back - as offset for SelectConfiguration / SelectInterface request do differ
301 RtlCopyMemory(&Urb
->UrbSelectInterface
.Interface
, DeviceExtension
->InterfaceInformation
, DeviceExtension
->InterfaceInformation
->Length
);
303 // now select the interface
304 Status
= USBSTOR_SyncUrbRequest(DeviceExtension
->LowerDeviceObject
, Urb
);
305 if (NT_SUCCESS(Status
))
307 // update configuration info
308 ASSERT(Urb
->UrbSelectInterface
.Interface
.Length
== DeviceExtension
->InterfaceInformation
->Length
);
309 RtlCopyMemory(DeviceExtension
->InterfaceInformation
, &Urb
->UrbSelectInterface
.Interface
, Urb
->UrbSelectInterface
.Interface
.Length
);
312 FreeItem(InterfaceList
);
313 ExFreePoolWithTag(Urb
, 0);
319 USBSTOR_GetPipeHandles(
320 IN PFDO_DEVICE_EXTENSION DeviceExtension
)
323 BOOLEAN BulkInFound
= FALSE
, BulkOutFound
= FALSE
;
325 // enumerate all pipes and extract bulk-in / bulk-out pipe handle
326 for (Index
= 0; Index
< DeviceExtension
->InterfaceInformation
->NumberOfPipes
; Index
++)
328 if (DeviceExtension
->InterfaceInformation
->Pipes
[Index
].PipeType
== UsbdPipeTypeBulk
)
330 if (USB_ENDPOINT_DIRECTION_IN(DeviceExtension
->InterfaceInformation
->Pipes
[Index
].EndpointAddress
))
332 DeviceExtension
->BulkInPipeIndex
= Index
;
334 // there should not be another bulk in pipe
335 ASSERT(BulkInFound
== FALSE
);
340 DeviceExtension
->BulkOutPipeIndex
= Index
;
342 // there should not be another bulk out pipe
343 ASSERT(BulkOutFound
== FALSE
);
349 if (!BulkInFound
|| !BulkOutFound
)
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
;
356 return STATUS_SUCCESS
;