xref: /reactos/drivers/usb/usbstor/fdo.c (revision 40462c92)
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     Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
164     if (!NT_SUCCESS(Status))
165     {
166         DPRINT1("USBSTOR_FdoHandleStartDevice Lower device failed to start %x\n", Status);
167         return Status;
168     }
169 
170     if (!DeviceExtension->ResetDeviceWorkItem)
171     {
172         WorkItem = IoAllocateWorkItem(DeviceObject);
173         DeviceExtension->ResetDeviceWorkItem = WorkItem;
174 
175         if (!WorkItem)
176         {
177             return STATUS_INSUFFICIENT_RESOURCES;
178         }
179     }
180 
181     // initialize irp queue
182     USBSTOR_QueueInitialize(DeviceExtension);
183 
184     // first get device & configuration & string descriptor
185     Status = USBSTOR_GetDescriptors(DeviceObject);
186     if (!NT_SUCCESS(Status))
187     {
188         DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device descriptor with %x\n", Status);
189         return Status;
190     }
191 
192 #if DBG
193     USBSTOR_DumpDeviceDescriptor(DeviceExtension->DeviceDescriptor);
194 #endif
195 
196     // Check that this device uses bulk transfers and is SCSI
197 
198     InterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)DeviceExtension->ConfigurationDescriptor + sizeof(USB_CONFIGURATION_DESCRIPTOR));
199     ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
200     ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
201 
202     DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass);
203     if (InterfaceDesc->bInterfaceProtocol != USB_PROTOCOL_BULK)
204     {
205         DPRINT1("USB Device is not a bulk only device and is not currently supported\n");
206         return STATUS_NOT_SUPPORTED;
207     }
208 
209     if (InterfaceDesc->bInterfaceSubClass == USB_SUBCLASS_UFI)
210     {
211         DPRINT1("USB Floppy devices are not supported\n");
212         return STATUS_NOT_SUPPORTED;
213     }
214 
215     // now select an interface
216     Status = USBSTOR_SelectConfigurationAndInterface(DeviceObject, DeviceExtension);
217     if (!NT_SUCCESS(Status))
218     {
219         // failed to get device descriptor
220         DPRINT1("USBSTOR_FdoHandleStartDevice failed to select configuration / interface with %x\n", Status);
221         return Status;
222     }
223 
224     // check if we got a bulk in + bulk out endpoint
225     Status = USBSTOR_GetPipeHandles(DeviceExtension);
226     if (!NT_SUCCESS(Status))
227     {
228         DPRINT1("USBSTOR_FdoHandleStartDevice no pipe handles %x\n", Status);
229         return Status;
230     }
231 
232     Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension);
233     if (!NT_SUCCESS(Status))
234     {
235         DPRINT1("USBSTOR_FdoHandleStartDevice failed to get max lun %x\n", Status);
236         return Status;
237     }
238 
239     // now create for each LUN a device object, 1 minimum
240     do
241     {
242         Status = USBSTOR_CreatePDO(DeviceObject, Index);
243 
244         if (!NT_SUCCESS(Status))
245         {
246             DPRINT1("USBSTOR_FdoHandleStartDevice USBSTOR_CreatePDO failed for Index %lu with Status %x\n", Index, Status);
247             return Status;
248         }
249 
250         Index++;
251         DeviceExtension->InstanceCount++;
252 
253     } while(Index < DeviceExtension->MaxLUN);
254 
255 #if 0
256     //
257     // finally get usb device interface
258     //
259     Status = USBSTOR_GetBusInterface(DeviceExtension->LowerDeviceObject, &DeviceExtension->BusInterface);
260     if (!NT_SUCCESS(Status))
261     {
262         //
263         // failed to device interface
264         //
265         DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device interface %x\n", Status);
266         return Status;
267     }
268 #endif
269 
270     //IoStartTimer(DeviceObject);
271 
272     DPRINT("USBSTOR_FdoHandleStartDevice FDO is initialized\n");
273     return STATUS_SUCCESS;
274 }
275 
276 NTSTATUS
277 USBSTOR_FdoHandlePnp(
278     IN PDEVICE_OBJECT DeviceObject,
279     IN OUT PIRP Irp)
280 {
281     PIO_STACK_LOCATION IoStack;
282     PFDO_DEVICE_EXTENSION DeviceExtension;
283     NTSTATUS Status;
284 
285     IoStack = IoGetCurrentIrpStackLocation(Irp);
286     DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
287     ASSERT(DeviceExtension->Common.IsFDO);
288 
289     switch(IoStack->MinorFunction)
290     {
291         case IRP_MN_SURPRISE_REMOVAL:
292         {
293             DPRINT("IRP_MN_SURPRISE_REMOVAL %p\n", DeviceObject);
294             Irp->IoStatus.Status = STATUS_SUCCESS;
295 
296             // forward irp to next device object
297             IoSkipCurrentIrpStackLocation(Irp);
298             return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
299         }
300         case IRP_MN_QUERY_DEVICE_RELATIONS:
301         {
302             DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS %p Type: %u\n", DeviceObject, IoStack->Parameters.QueryDeviceRelations.Type);
303             return USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp);
304         }
305         case IRP_MN_STOP_DEVICE:
306         {
307             DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n");
308             IoStopTimer(DeviceObject);
309             Irp->IoStatus.Status = STATUS_SUCCESS;
310 
311             // forward irp to next device object
312             IoSkipCurrentIrpStackLocation(Irp);
313             return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
314         }
315         case IRP_MN_REMOVE_DEVICE:
316         {
317             DPRINT("IRP_MN_REMOVE_DEVICE\n");
318 
319             return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp);
320         }
321         case IRP_MN_QUERY_CAPABILITIES:
322         {
323             // FIXME: set custom capabilities
324             IoSkipCurrentIrpStackLocation(Irp);
325             return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
326         }
327         case IRP_MN_QUERY_STOP_DEVICE:
328         case IRP_MN_QUERY_REMOVE_DEVICE:
329         {
330 #if 0
331             //
332             // we can if nothing is pending
333             //
334             if (DeviceExtension->IrpPendingCount != 0 ||
335                 DeviceExtension->ActiveSrb != NULL)
336 #else
337             if (TRUE)
338 #endif
339             {
340                 /* We have pending requests */
341                 DPRINT1("Failing removal/stop request due to pending requests present\n");
342                 Status = STATUS_UNSUCCESSFUL;
343             }
344             else
345             {
346                 /* We're all clear */
347                 Irp->IoStatus.Status = STATUS_SUCCESS;
348 
349                 IoSkipCurrentIrpStackLocation(Irp);
350                 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
351             }
352             break;
353         }
354         case IRP_MN_START_DEVICE:
355         {
356             Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp);
357             break;
358         }
359         default:
360         {
361             // forward irp to next device object
362             IoSkipCurrentIrpStackLocation(Irp);
363             return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
364         }
365     }
366 
367     if (Status != STATUS_PENDING)
368     {
369         Irp->IoStatus.Status = Status;
370         IoCompleteRequest(Irp, IO_NO_INCREMENT);
371     }
372 
373     return Status;
374 }
375