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