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