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