xref: /reactos/drivers/usb/usbstor/fdo.c (revision 50cf16b3)
1 /*
2  * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * FILE:        drivers/usb/usbstor/fdo.c
5  * PURPOSE:     USB block storage device driver.
6  * PROGRAMMERS:
7  *              James Tabor
8  *              Michael Martin (michael.martin@reactos.org)
9  *              Johannes Anderwald (johannes.anderwald@reactos.org)
10  */
11 
12 #include "usbstor.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 VOID
18 USBSTOR_DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
19 {
20     DPRINT1("Dumping Device Descriptor %p\n", DeviceDescriptor);
21     DPRINT1("bLength %x\n", DeviceDescriptor->bLength);
22     DPRINT1("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType);
23     DPRINT1("bcdUSB %x\n", DeviceDescriptor->bcdUSB);
24     DPRINT1("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass);
25     DPRINT1("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass);
26     DPRINT1("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol);
27     DPRINT1("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0);
28     DPRINT1("idVendor %x\n", DeviceDescriptor->idVendor);
29     DPRINT1("idProduct %x\n", DeviceDescriptor->idProduct);
30     DPRINT1("bcdDevice %x\n", DeviceDescriptor->bcdDevice);
31     DPRINT1("iManufacturer %x\n", DeviceDescriptor->iManufacturer);
32     DPRINT1("iProduct %x\n", DeviceDescriptor->iProduct);
33     DPRINT1("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber);
34     DPRINT1("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
35 }
36 
37 NTSTATUS
38 USBSTOR_FdoHandleDeviceRelations(
39     IN PFDO_DEVICE_EXTENSION DeviceExtension,
40     IN OUT PIRP Irp)
41 {
42     ULONG DeviceCount = 0;
43     LONG Index;
44     PDEVICE_RELATIONS DeviceRelations;
45     PIO_STACK_LOCATION IoStack;
46 
47     //
48     // get current irp stack location
49     //
50     IoStack = IoGetCurrentIrpStackLocation(Irp);
51 
52     //
53     // check if relation type is BusRelations
54     //
55     if (IoStack->Parameters.QueryDeviceRelations.Type != BusRelations)
56     {
57         //
58         // FDO always only handles bus relations
59         //
60         return USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
61     }
62 
63     //
64     // go through array and count device objects
65     //
66     for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
67     {
68         if (DeviceExtension->ChildPDO[Index])
69         {
70             //
71             // child pdo
72             //
73             DeviceCount++;
74         }
75     }
76 
77     //
78     // allocate device relations
79     //
80     DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount > 1 ? (DeviceCount-1) * sizeof(PDEVICE_OBJECT) : 0));
81     if (!DeviceRelations)
82     {
83         //
84         // no memory
85         //
86         return STATUS_INSUFFICIENT_RESOURCES;
87     }
88 
89     //
90     // add device objects
91     //
92     for(Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
93     {
94         if (DeviceExtension->ChildPDO[Index])
95         {
96             //
97             // store child pdo
98             //
99             DeviceRelations->Objects[DeviceRelations->Count] = DeviceExtension->ChildPDO[Index];
100 
101             //
102             // add reference
103             //
104             ObReferenceObject(DeviceExtension->ChildPDO[Index]);
105 
106             //
107             // increment count
108             //
109             DeviceRelations->Count++;
110         }
111     }
112 
113     //
114     // store result
115     //
116     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
117 
118     //
119     // request completed successfully
120     //
121     return STATUS_SUCCESS;
122 }
123 
124 NTSTATUS
125 USBSTOR_FdoHandleRemoveDevice(
126     IN PDEVICE_OBJECT DeviceObject,
127     IN PFDO_DEVICE_EXTENSION DeviceExtension,
128     IN OUT PIRP Irp)
129 {
130     NTSTATUS Status;
131     ULONG Index;
132 
133     DPRINT("Handling FDO removal %p\n", DeviceObject);
134 
135     /* FIXME: wait for devices finished processing */
136     for(Index = 0; Index < 16; Index++)
137     {
138         if (DeviceExtension->ChildPDO[Index] != NULL)
139         {
140             DPRINT("Deleting PDO %p RefCount %x AttachedDevice %p \n", DeviceExtension->ChildPDO[Index], DeviceExtension->ChildPDO[Index]->ReferenceCount, DeviceExtension->ChildPDO[Index]->AttachedDevice);
141             IoDeleteDevice(DeviceExtension->ChildPDO[Index]);
142         }
143     }
144 
145     /* Send the IRP down the stack */
146     IoSkipCurrentIrpStackLocation(Irp);
147     Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
148 
149     /* Detach from the device stack */
150     IoDetachDevice(DeviceExtension->LowerDeviceObject);
151 
152     /* Delete the device object */
153     IoDeleteDevice(DeviceObject);
154 
155     return Status;
156 }
157 
158 NTSTATUS
159 USBSTOR_FdoHandleStartDevice(
160     IN PDEVICE_OBJECT DeviceObject,
161     IN PFDO_DEVICE_EXTENSION DeviceExtension,
162     IN OUT PIRP Irp)
163 {
164     PUSB_INTERFACE_DESCRIPTOR InterfaceDesc;
165     NTSTATUS Status;
166     UCHAR Index = 0;
167 
168     //
169     // forward irp to lower device
170     //
171     Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
172     if (!NT_SUCCESS(Status))
173     {
174         //
175         // failed to start
176         //
177         DPRINT1("USBSTOR_FdoHandleStartDevice Lower device failed to start %x\n", Status);
178         return Status;
179     }
180 
181     //
182     // initialize irp queue
183     //
184     USBSTOR_QueueInitialize(DeviceExtension);
185 
186     //
187     // first get device & configuration & string descriptor
188     //
189     Status = USBSTOR_GetDescriptors(DeviceObject);
190     if (!NT_SUCCESS(Status))
191     {
192         //
193         // failed to get device descriptor
194         //
195         DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device descriptor with %x\n", Status);
196         return Status;
197     }
198 
199     //
200     // dump device descriptor
201     //
202     USBSTOR_DumpDeviceDescriptor(DeviceExtension->DeviceDescriptor);
203 
204     //
205     // Check that this device uses bulk transfers and is SCSI
206     //
207     InterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)DeviceExtension->ConfigurationDescriptor + sizeof(USB_CONFIGURATION_DESCRIPTOR));
208 
209     //
210     // sanity check
211     //
212     ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
213     ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
214 
215     DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass);
216     if (InterfaceDesc->bInterfaceProtocol != 0x50)
217     {
218         DPRINT1("USB Device is not a bulk only device and is not currently supported\n");
219         return STATUS_NOT_SUPPORTED;
220     }
221 
222     if (InterfaceDesc->bInterfaceSubClass != 0x06)
223     {
224         //
225         // FIXME: need to pad CDBs to 12 byte
226         // mode select commands must be translated from 1AH / 15h to 5AH / 55h
227         //
228         DPRINT1("[USBSTOR] Error: need to pad CDBs\n");
229         return STATUS_NOT_IMPLEMENTED;
230     }
231 
232     //
233     // now select an interface
234     //
235     Status = USBSTOR_SelectConfigurationAndInterface(DeviceObject, DeviceExtension);
236     if (!NT_SUCCESS(Status))
237     {
238         //
239         // failed to get device descriptor
240         //
241         DPRINT1("USBSTOR_FdoHandleStartDevice failed to select configuration / interface with %x\n", Status);
242         return Status;
243     }
244 
245     //
246     // check if we got a bulk in + bulk out endpoint
247     //
248     Status = USBSTOR_GetPipeHandles(DeviceExtension);
249     if (!NT_SUCCESS(Status))
250     {
251         //
252         // failed to get pipe handles descriptor
253         //
254         DPRINT1("USBSTOR_FdoHandleStartDevice no pipe handles %x\n", Status);
255         return Status;
256     }
257 
258     //
259     // get num of lun which are supported
260     //
261     Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension);
262     if (!NT_SUCCESS(Status))
263     {
264         //
265         // failed to get max LUN
266         //
267         DPRINT1("USBSTOR_FdoHandleStartDevice failed to get max lun %x\n", Status);
268         return Status;
269     }
270 
271     //
272     // now create for each LUN a device object, 1 minimum
273     //
274     do
275     {
276         //
277         // create pdo
278         //
279         Status = USBSTOR_CreatePDO(DeviceObject, Index);
280 
281         //
282         // check for failure
283         //
284         if (!NT_SUCCESS(Status))
285         {
286             //
287             // failed to create child pdo
288             //
289             DPRINT1("USBSTOR_FdoHandleStartDevice USBSTOR_CreatePDO failed for Index %lu with Status %x\n", Index, Status);
290             return Status;
291         }
292 
293         //
294         // increment pdo index
295         //
296         Index++;
297         DeviceExtension->InstanceCount++;
298 
299     }while(Index < DeviceExtension->MaxLUN);
300 
301 #if 0
302     //
303     // finally get usb device interface
304     //
305     Status = USBSTOR_GetBusInterface(DeviceExtension->LowerDeviceObject, &DeviceExtension->BusInterface);
306     if (!NT_SUCCESS(Status))
307     {
308         //
309         // failed to device interface
310         //
311         DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device interface %x\n", Status);
312         return Status;
313     }
314 #endif
315 
316 
317     //
318     // start the timer
319     //
320     //IoStartTimer(DeviceObject);
321 
322 
323     //
324     // fdo is now initialized
325     //
326     DPRINT("USBSTOR_FdoHandleStartDevice FDO is initialized\n");
327     return STATUS_SUCCESS;
328 }
329 
330 NTSTATUS
331 USBSTOR_FdoHandlePnp(
332     IN PDEVICE_OBJECT DeviceObject,
333     IN OUT PIRP Irp)
334 {
335     PIO_STACK_LOCATION IoStack;
336     PFDO_DEVICE_EXTENSION DeviceExtension;
337     NTSTATUS Status;
338 
339     //
340     // get current stack location
341     //
342     IoStack = IoGetCurrentIrpStackLocation(Irp);
343 
344     //
345     // get device extension
346     //
347     DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
348 
349     //
350     // sanity check
351     //
352     ASSERT(DeviceExtension->Common.IsFDO);
353 
354     switch(IoStack->MinorFunction)
355     {
356        case IRP_MN_SURPRISE_REMOVAL:
357        {
358            DPRINT("IRP_MN_SURPRISE_REMOVAL %p\n", DeviceObject);
359            Irp->IoStatus.Status = STATUS_SUCCESS;
360 
361             //
362             // forward irp to next device object
363             //
364             IoSkipCurrentIrpStackLocation(Irp);
365             return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
366        }
367        case IRP_MN_QUERY_DEVICE_RELATIONS:
368        {
369            DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS %p\n", DeviceObject);
370            Status = USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp);
371            break;
372        }
373        case IRP_MN_STOP_DEVICE:
374        {
375            DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n");
376            IoStopTimer(DeviceObject);
377            Irp->IoStatus.Status = STATUS_SUCCESS;
378 
379             //
380             // forward irp to next device object
381             //
382             IoSkipCurrentIrpStackLocation(Irp);
383             return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
384        }
385        case IRP_MN_REMOVE_DEVICE:
386        {
387            DPRINT("IRP_MN_REMOVE_DEVICE\n");
388 
389            return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp);
390        }
391        case IRP_MN_QUERY_CAPABILITIES:
392        {
393            //
394            // FIXME: set custom capabilities
395            //
396            IoSkipCurrentIrpStackLocation(Irp);
397            return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
398        }
399        case IRP_MN_QUERY_STOP_DEVICE:
400        case IRP_MN_QUERY_REMOVE_DEVICE:
401        {
402 #if 0
403            //
404            // we can if nothing is pending
405            //
406            if (DeviceExtension->IrpPendingCount != 0 ||
407                DeviceExtension->ActiveSrb != NULL)
408 #else
409            if (TRUE)
410 #endif
411            {
412                /* We have pending requests */
413                DPRINT1("Failing removal/stop request due to pending requests present\n");
414                Status = STATUS_UNSUCCESSFUL;
415            }
416            else
417            {
418                /* We're all clear */
419                Irp->IoStatus.Status = STATUS_SUCCESS;
420 
421                IoSkipCurrentIrpStackLocation(Irp);
422                return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
423            }
424            break;
425        }
426        case IRP_MN_START_DEVICE:
427        {
428            Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp);
429            break;
430        }
431        default:
432         {
433             //
434             // forward irp to next device object
435             //
436             IoSkipCurrentIrpStackLocation(Irp);
437             return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
438         }
439     }
440 
441     //
442     // complete request
443     //
444     if (Status != STATUS_PENDING)
445     {
446         //
447         // store result
448         //
449         Irp->IoStatus.Status = Status;
450 
451         //
452         // complete request
453         //
454         IoCompleteRequest(Irp, IO_NO_INCREMENT);
455     }
456 
457     //
458     // done processing
459     //
460     return Status;
461 }
462