xref: /reactos/drivers/usb/usbstor/fdo.c (revision 37b2c145)
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     ULONG 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 = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0));
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         // add device objects
74         for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
75         {
76             if (DeviceExtension->ChildPDO[Index])
77             {
78                 // store child pdo
79                 DeviceRelations->Objects[DeviceRelations->Count] = DeviceExtension->ChildPDO[Index];
80 
81                 // add reference
82                 ObReferenceObject(DeviceExtension->ChildPDO[Index]);
83 
84                 DeviceRelations->Count++;
85             }
86         }
87 
88         Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
89         Irp->IoStatus.Status = STATUS_SUCCESS;
90     }
91 
92     IoCopyCurrentIrpStackLocationToNext(Irp);
93 
94     return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
95 }
96 
97 NTSTATUS
98 USBSTOR_FdoHandleRemoveDevice(
99     IN PDEVICE_OBJECT DeviceObject,
100     IN PFDO_DEVICE_EXTENSION DeviceExtension,
101     IN OUT PIRP Irp)
102 {
103     NTSTATUS Status;
104     ULONG Index;
105 
106     DPRINT("Handling FDO removal %p\n", DeviceObject);
107 
108     // FIXME: wait for devices finished processing
109     for (Index = 0; Index < 16; Index++)
110     {
111         if (DeviceExtension->ChildPDO[Index] != NULL)
112         {
113             DPRINT("Deleting PDO %p RefCount %x AttachedDevice %p \n", DeviceExtension->ChildPDO[Index], DeviceExtension->ChildPDO[Index]->ReferenceCount, DeviceExtension->ChildPDO[Index]->AttachedDevice);
114             IoDeleteDevice(DeviceExtension->ChildPDO[Index]);
115         }
116     }
117 
118     // Freeing everything in DeviceExtension
119     ASSERT(
120         DeviceExtension->DeviceDescriptor &&
121         DeviceExtension->ConfigurationDescriptor &&
122         DeviceExtension->InterfaceInformation &&
123         DeviceExtension->ResetDeviceWorkItem
124     );
125 
126     ExFreePoolWithTag(DeviceExtension->DeviceDescriptor, USB_STOR_TAG);
127     ExFreePoolWithTag(DeviceExtension->ConfigurationDescriptor, USB_STOR_TAG);
128     ExFreePoolWithTag(DeviceExtension->InterfaceInformation, USB_STOR_TAG);
129     IoFreeWorkItem(DeviceExtension->ResetDeviceWorkItem);
130 
131     if (DeviceExtension->SerialNumber)
132     {
133         ExFreePoolWithTag(DeviceExtension->SerialNumber, USB_STOR_TAG);
134     }
135 
136     // Send the IRP down the stack
137     IoSkipCurrentIrpStackLocation(Irp);
138     Irp->IoStatus.Status = STATUS_SUCCESS;
139     Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
140 
141     // Detach from the device stack
142     IoDetachDevice(DeviceExtension->LowerDeviceObject);
143 
144     IoDeleteDevice(DeviceObject);
145 
146     return Status;
147 }
148 
149 NTSTATUS
150 USBSTOR_FdoHandleStartDevice(
151     IN PDEVICE_OBJECT DeviceObject,
152     IN PFDO_DEVICE_EXTENSION DeviceExtension,
153     IN OUT PIRP Irp)
154 {
155     PUSB_INTERFACE_DESCRIPTOR InterfaceDesc;
156     NTSTATUS Status;
157     UCHAR Index = 0;
158     PIO_WORKITEM WorkItem;
159 
160     // forward irp to lower device
161     Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
162     if (!NT_SUCCESS(Status))
163     {
164         DPRINT1("USBSTOR_FdoHandleStartDevice Lower device failed to start %x\n", Status);
165         return Status;
166     }
167 
168     if (!DeviceExtension->ResetDeviceWorkItem)
169     {
170         WorkItem = IoAllocateWorkItem(DeviceObject);
171         DeviceExtension->ResetDeviceWorkItem = WorkItem;
172 
173         if (!WorkItem)
174         {
175             return STATUS_INSUFFICIENT_RESOURCES;
176         }
177     }
178 
179     // initialize irp queue
180     USBSTOR_QueueInitialize(DeviceExtension);
181 
182     // first get device & configuration & string descriptor
183     Status = USBSTOR_GetDescriptors(DeviceObject);
184     if (!NT_SUCCESS(Status))
185     {
186         DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device descriptor with %x\n", Status);
187         return Status;
188     }
189 
190 #if DBG
191     USBSTOR_DumpDeviceDescriptor(DeviceExtension->DeviceDescriptor);
192 #endif
193 
194     // Check that this device uses bulk transfers and is SCSI
195 
196     InterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)DeviceExtension->ConfigurationDescriptor + sizeof(USB_CONFIGURATION_DESCRIPTOR));
197     ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
198     ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
199 
200     DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass);
201     if (InterfaceDesc->bInterfaceProtocol != 0x50)
202     {
203         DPRINT1("USB Device is not a bulk only device and is not currently supported\n");
204         return STATUS_NOT_SUPPORTED;
205     }
206 
207     if (InterfaceDesc->bInterfaceSubClass == 0x04) // UFI subclass
208     {
209         // FIXME: need to pad CDBs to 12 byte
210         // mode select commands must be translated from 1AH / 15h to 5AH / 55h
211         DPRINT1("[USBSTOR] Error: need to pad CDBs\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