[USBSTOR] Refactor device reset and pipe reset code.
[reactos.git] / drivers / usb / usbstor / fdo.c
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 VOID
17 USBSTOR_DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
18 {
19 DPRINT1("Dumping Device Descriptor %p\n", DeviceDescriptor);
20 DPRINT1("bLength %x\n", DeviceDescriptor->bLength);
21 DPRINT1("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType);
22 DPRINT1("bcdUSB %x\n", DeviceDescriptor->bcdUSB);
23 DPRINT1("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass);
24 DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass);
25 DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol);
26 DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0);
27 DPRINT1("idVendor %x\n", DeviceDescriptor->idVendor);
28 DPRINT1("idProduct %x\n", DeviceDescriptor->idProduct);
29 DPRINT1("bcdDevice %x\n", DeviceDescriptor->bcdDevice);
30 DPRINT1("iManufacturer %x\n", DeviceDescriptor->iManufacturer);
31 DPRINT1("iProduct %x\n", DeviceDescriptor->iProduct);
32 DPRINT1("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber);
33 DPRINT1("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
34 }
35
36 NTSTATUS
37 USBSTOR_FdoHandleDeviceRelations(
38 IN PFDO_DEVICE_EXTENSION DeviceExtension,
39 IN OUT PIRP Irp)
40 {
41 ULONG DeviceCount = 0;
42 LONG Index;
43 PDEVICE_RELATIONS DeviceRelations;
44 PIO_STACK_LOCATION IoStack;
45
46 IoStack = IoGetCurrentIrpStackLocation(Irp);
47
48 // check if relation type is BusRelations
49 if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
50 {
51 // FDO always only handles bus relations
52 return USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
53 }
54
55 // go through array and count device objects
56 for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
57 {
58 if (DeviceExtension->ChildPDO[Index])
59 {
60 DeviceCount++;
61 }
62 }
63
64 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0));
65 if (!DeviceRelations)
66 {
67 return STATUS_INSUFFICIENT_RESOURCES;
68 }
69
70 // add device objects
71 for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
72 {
73 if (DeviceExtension->ChildPDO[Index])
74 {
75 // store child pdo
76 DeviceRelations->Objects[DeviceRelations->Count] = DeviceExtension->ChildPDO[Index];
77
78 // add reference
79 ObReferenceObject(DeviceExtension->ChildPDO[Index]);
80
81 DeviceRelations->Count++;
82 }
83 }
84
85 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
86
87 return STATUS_SUCCESS;
88 }
89
90 NTSTATUS
91 USBSTOR_FdoHandleRemoveDevice(
92 IN PDEVICE_OBJECT DeviceObject,
93 IN PFDO_DEVICE_EXTENSION DeviceExtension,
94 IN OUT PIRP Irp)
95 {
96 NTSTATUS Status;
97 ULONG Index;
98
99 DPRINT("Handling FDO removal %p\n", DeviceObject);
100
101 // FIXME: wait for devices finished processing
102 for (Index = 0; Index < 16; Index++)
103 {
104 if (DeviceExtension->ChildPDO[Index] != NULL)
105 {
106 DPRINT("Deleting PDO %p RefCount %x AttachedDevice %p \n", DeviceExtension->ChildPDO[Index], DeviceExtension->ChildPDO[Index]->ReferenceCount, DeviceExtension->ChildPDO[Index]->AttachedDevice);
107 IoDeleteDevice(DeviceExtension->ChildPDO[Index]);
108 }
109 }
110
111 // Send the IRP down the stack
112 IoSkipCurrentIrpStackLocation(Irp);
113 Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
114
115 // Detach from the device stack
116 IoDetachDevice(DeviceExtension->LowerDeviceObject);
117
118 IoDeleteDevice(DeviceObject);
119
120 return Status;
121 }
122
123 NTSTATUS
124 USBSTOR_FdoHandleStartDevice(
125 IN PDEVICE_OBJECT DeviceObject,
126 IN PFDO_DEVICE_EXTENSION DeviceExtension,
127 IN OUT PIRP Irp)
128 {
129 PUSB_INTERFACE_DESCRIPTOR InterfaceDesc;
130 NTSTATUS Status;
131 UCHAR Index = 0;
132 PIO_WORKITEM WorkItem;
133
134 // forward irp to lower device
135 Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
136 if (!NT_SUCCESS(Status))
137 {
138 DPRINT1("USBSTOR_FdoHandleStartDevice Lower device failed to start %x\n", Status);
139 return Status;
140 }
141
142 if (!DeviceExtension->ResetDeviceWorkItem)
143 {
144 WorkItem = IoAllocateWorkItem(DeviceObject);
145 DeviceExtension->ResetDeviceWorkItem = WorkItem;
146
147 if (!WorkItem)
148 {
149 return STATUS_INSUFFICIENT_RESOURCES;
150 }
151 }
152
153 // initialize irp queue
154 USBSTOR_QueueInitialize(DeviceExtension);
155
156 // first get device & configuration & string descriptor
157 Status = USBSTOR_GetDescriptors(DeviceObject);
158 if (!NT_SUCCESS(Status))
159 {
160 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device descriptor with %x\n", Status);
161 return Status;
162 }
163
164 USBSTOR_DumpDeviceDescriptor(DeviceExtension->DeviceDescriptor);
165
166
167 // Check that this device uses bulk transfers and is SCSI
168
169 InterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)DeviceExtension->ConfigurationDescriptor + sizeof(USB_CONFIGURATION_DESCRIPTOR));
170 ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
171 ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
172
173 DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass);
174 if (InterfaceDesc->bInterfaceProtocol != 0x50)
175 {
176 DPRINT1("USB Device is not a bulk only device and is not currently supported\n");
177 return STATUS_NOT_SUPPORTED;
178 }
179
180 if (InterfaceDesc->bInterfaceSubClass != 0x06)
181 {
182 // FIXME: need to pad CDBs to 12 byte
183 // mode select commands must be translated from 1AH / 15h to 5AH / 55h
184 DPRINT1("[USBSTOR] Error: need to pad CDBs\n");
185 return STATUS_NOT_IMPLEMENTED;
186 }
187
188 // now select an interface
189 Status = USBSTOR_SelectConfigurationAndInterface(DeviceObject, DeviceExtension);
190 if (!NT_SUCCESS(Status))
191 {
192 // failed to get device descriptor
193 DPRINT1("USBSTOR_FdoHandleStartDevice failed to select configuration / interface with %x\n", Status);
194 return Status;
195 }
196
197 // check if we got a bulk in + bulk out endpoint
198 Status = USBSTOR_GetPipeHandles(DeviceExtension);
199 if (!NT_SUCCESS(Status))
200 {
201 DPRINT1("USBSTOR_FdoHandleStartDevice no pipe handles %x\n", Status);
202 return Status;
203 }
204
205 Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension);
206 if (!NT_SUCCESS(Status))
207 {
208 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get max lun %x\n", Status);
209 return Status;
210 }
211
212 // now create for each LUN a device object, 1 minimum
213 do
214 {
215 Status = USBSTOR_CreatePDO(DeviceObject, Index);
216
217 if (!NT_SUCCESS(Status))
218 {
219 DPRINT1("USBSTOR_FdoHandleStartDevice USBSTOR_CreatePDO failed for Index %lu with Status %x\n", Index, Status);
220 return Status;
221 }
222
223 Index++;
224 DeviceExtension->InstanceCount++;
225
226 } while(Index < DeviceExtension->MaxLUN);
227
228 #if 0
229 //
230 // finally get usb device interface
231 //
232 Status = USBSTOR_GetBusInterface(DeviceExtension->LowerDeviceObject, &DeviceExtension->BusInterface);
233 if (!NT_SUCCESS(Status))
234 {
235 //
236 // failed to device interface
237 //
238 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device interface %x\n", Status);
239 return Status;
240 }
241 #endif
242
243 //IoStartTimer(DeviceObject);
244
245 DPRINT("USBSTOR_FdoHandleStartDevice FDO is initialized\n");
246 return STATUS_SUCCESS;
247 }
248
249 NTSTATUS
250 USBSTOR_FdoHandlePnp(
251 IN PDEVICE_OBJECT DeviceObject,
252 IN OUT PIRP Irp)
253 {
254 PIO_STACK_LOCATION IoStack;
255 PFDO_DEVICE_EXTENSION DeviceExtension;
256 NTSTATUS Status;
257
258 IoStack = IoGetCurrentIrpStackLocation(Irp);
259 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
260 ASSERT(DeviceExtension->Common.IsFDO);
261
262 switch(IoStack->MinorFunction)
263 {
264 case IRP_MN_SURPRISE_REMOVAL:
265 {
266 DPRINT("IRP_MN_SURPRISE_REMOVAL %p\n", DeviceObject);
267 Irp->IoStatus.Status = STATUS_SUCCESS;
268
269 // forward irp to next device object
270 IoSkipCurrentIrpStackLocation(Irp);
271 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
272 }
273 case IRP_MN_QUERY_DEVICE_RELATIONS:
274 {
275 DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS %p\n", DeviceObject);
276 Status = USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp);
277 break;
278 }
279 case IRP_MN_STOP_DEVICE:
280 {
281 DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n");
282 IoStopTimer(DeviceObject);
283 Irp->IoStatus.Status = STATUS_SUCCESS;
284
285 // forward irp to next device object
286 IoSkipCurrentIrpStackLocation(Irp);
287 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
288 }
289 case IRP_MN_REMOVE_DEVICE:
290 {
291 DPRINT("IRP_MN_REMOVE_DEVICE\n");
292
293 return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp);
294 }
295 case IRP_MN_QUERY_CAPABILITIES:
296 {
297 // FIXME: set custom capabilities
298 IoSkipCurrentIrpStackLocation(Irp);
299 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
300 }
301 case IRP_MN_QUERY_STOP_DEVICE:
302 case IRP_MN_QUERY_REMOVE_DEVICE:
303 {
304 #if 0
305 //
306 // we can if nothing is pending
307 //
308 if (DeviceExtension->IrpPendingCount != 0 ||
309 DeviceExtension->ActiveSrb != NULL)
310 #else
311 if (TRUE)
312 #endif
313 {
314 /* We have pending requests */
315 DPRINT1("Failing removal/stop request due to pending requests present\n");
316 Status = STATUS_UNSUCCESSFUL;
317 }
318 else
319 {
320 /* We're all clear */
321 Irp->IoStatus.Status = STATUS_SUCCESS;
322
323 IoSkipCurrentIrpStackLocation(Irp);
324 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
325 }
326 break;
327 }
328 case IRP_MN_START_DEVICE:
329 {
330 Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp);
331 break;
332 }
333 default:
334 {
335 // forward irp to next device object
336 IoSkipCurrentIrpStackLocation(Irp);
337 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
338 }
339 }
340
341 if (Status != STATUS_PENDING)
342 {
343 Irp->IoStatus.Status = Status;
344 IoCompleteRequest(Irp, IO_NO_INCREMENT);
345 }
346
347 return Status;
348 }