08efa25ce5fb398f5f02568f1e1468020472dd69
[reactos.git] / drivers / usb / usbstor / fdo.c
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); */ //This crashes for some reason during unload
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 DPRINT1("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass);
197 if (InterfaceDesc->bInterfaceProtocol != 0x50)
198 {
199 DPRINT1("USB Device is not a bulk only device and is not currently supported\n");
200 return STATUS_NOT_SUPPORTED;
201 }
202
203
204 //
205 // now select an interface
206 //
207 Status = USBSTOR_SelectConfigurationAndInterface(DeviceObject, DeviceExtension);
208 if (!NT_SUCCESS(Status))
209 {
210 //
211 // failed to get device descriptor
212 //
213 DPRINT1("USBSTOR_FdoHandleStartDevice failed to select configuration / interface with %x\n", Status);
214 return Status;
215 }
216
217 //
218 // check if we got a bulk in + bulk out endpoint
219 //
220 Status = USBSTOR_GetPipeHandles(DeviceExtension);
221 if (!NT_SUCCESS(Status))
222 {
223 //
224 // failed to get pipe handles descriptor
225 //
226 DPRINT1("USBSTOR_FdoHandleStartDevice no pipe handles %x\n", Status);
227 return Status;
228 }
229
230 //
231 // get num of lun which are supported
232 //
233 Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension);
234 if (!NT_SUCCESS(Status))
235 {
236 //
237 // failed to get max LUN
238 //
239 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get max lun %x\n", Status);
240 return Status;
241 }
242
243 //
244 // now create for each LUN a device object, 1 minimum
245 //
246 do
247 {
248 //
249 // create pdo
250 //
251 Status = USBSTOR_CreatePDO(DeviceObject, &DeviceExtension->ChildPDO[Index]);
252
253 //
254 // check for failure
255 //
256 if (!NT_SUCCESS(Status))
257 {
258 //
259 // failed to create child pdo
260 //
261 DPRINT1("USBSTOR_FdoHandleStartDevice USBSTOR_CreatePDO failed for Index %lu with Status %x\n", Index, Status);
262 return Status;
263 }
264
265 //
266 // increment pdo index
267 //
268 Index++;
269
270 }while(Index < DeviceExtension->MaxLUN);
271
272 #if 0
273 //
274 // finally get usb device interface
275 //
276 Status = USBSTOR_GetBusInterface(DeviceExtension->LowerDeviceObject, &DeviceExtension->BusInterface);
277 if (!NT_SUCCESS(Status))
278 {
279 //
280 // failed to device interface
281 //
282 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device interface %x\n", Status);
283 return Status;
284 }
285 #endif
286
287 //
288 // fdo is now initialized
289 //
290 DPRINT1("USBSTOR_FdoHandleStartDevice FDO is initialized\n");
291 return STATUS_SUCCESS;
292 }
293
294 NTSTATUS
295 USBSTOR_FdoHandlePnp(
296 IN PDEVICE_OBJECT DeviceObject,
297 IN OUT PIRP Irp)
298 {
299 PIO_STACK_LOCATION IoStack;
300 PFDO_DEVICE_EXTENSION DeviceExtension;
301 NTSTATUS Status;
302
303 //
304 // get current stack location
305 //
306 IoStack = IoGetCurrentIrpStackLocation(Irp);
307
308 //
309 // get device extension
310 //
311 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
312
313 //
314 // sanity check
315 //
316 ASSERT(DeviceExtension->Common.IsFDO);
317
318 switch(IoStack->MinorFunction)
319 {
320 case IRP_MN_QUERY_DEVICE_RELATIONS:
321 {
322 Status = USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp);
323 break;
324 }
325 case IRP_MN_STOP_DEVICE:
326 DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n");
327 Status = STATUS_NOT_SUPPORTED;
328 break;
329 case IRP_MN_REMOVE_DEVICE:
330 {
331 DPRINT1("IRP_MN_REMOVE_DEVICE\n");
332
333 return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp);
334 }
335 case IRP_MN_QUERY_CAPABILITIES:
336 {
337 //
338 // FIXME: set custom capabilities
339 //
340 IoSkipCurrentIrpStackLocation(Irp);
341 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
342 }
343 case IRP_MN_START_DEVICE:
344 {
345 Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp);
346 break;
347 }
348 default:
349 {
350 //
351 // forward irp to next device object
352 //
353 IoSkipCurrentIrpStackLocation(Irp);
354 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
355 }
356 }
357
358 //
359 // complete request
360 //
361 if (Status != STATUS_PENDING)
362 {
363 //
364 // store result
365 //
366 Irp->IoStatus.Status = Status;
367
368 //
369 // complete request
370 //
371 IoCompleteRequest(Irp, IO_NO_INCREMENT);
372 }
373
374 //
375 // done processing
376 //
377 return Status;
378 }