xref: /reactos/drivers/usb/usbstor/fdo.c (revision 59de5081)
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     DPRINT1("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     DPRINT1("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, &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     // fdo is now initialized
305     //
306     DPRINT1("USBSTOR_FdoHandleStartDevice FDO is initialized\n");
307     return STATUS_SUCCESS;
308 }
309 
310 NTSTATUS
311 USBSTOR_FdoHandlePnp(
312     IN PDEVICE_OBJECT DeviceObject,
313     IN OUT PIRP Irp)
314 {
315     PIO_STACK_LOCATION IoStack;
316     PFDO_DEVICE_EXTENSION DeviceExtension;
317     NTSTATUS Status;
318 
319     //
320     // get current stack location
321     //
322     IoStack = IoGetCurrentIrpStackLocation(Irp);
323 
324     //
325     // get device extension
326     //
327     DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
328 
329     //
330     // sanity check
331     //
332     ASSERT(DeviceExtension->Common.IsFDO);
333 
334     switch(IoStack->MinorFunction)
335     {
336        case IRP_MN_QUERY_DEVICE_RELATIONS:
337        {
338            Status = USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp);
339            break;
340        }
341        case IRP_MN_STOP_DEVICE:
342            DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n");
343            Status = STATUS_NOT_SUPPORTED;
344            break;
345        case IRP_MN_REMOVE_DEVICE:
346        {
347            DPRINT1("IRP_MN_REMOVE_DEVICE\n");
348 
349            return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp);
350        }
351        case IRP_MN_QUERY_CAPABILITIES:
352        {
353            //
354            // FIXME: set custom capabilities
355            //
356            IoSkipCurrentIrpStackLocation(Irp);
357            return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
358        }
359        case IRP_MN_START_DEVICE:
360        {
361            Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp);
362            break;
363        }
364        default:
365         {
366             //
367             // forward irp to next device object
368             //
369             IoSkipCurrentIrpStackLocation(Irp);
370             return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
371         }
372     }
373 
374     //
375     // complete request
376     //
377     if (Status != STATUS_PENDING)
378     {
379         //
380         // store result
381         //
382         Irp->IoStatus.Status = Status;
383 
384         //
385         // complete request
386         //
387         IoCompleteRequest(Irp, IO_NO_INCREMENT);
388     }
389 
390     //
391     // done processing
392     //
393     return Status;
394 }
395