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