* Sync up to trunk head (r60691).
[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 %p\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 ULONG Index;
129
130 DPRINT("Handling FDO removal %p\n", DeviceObject);
131
132 /* FIXME: wait for devices finished processing */
133 for(Index = 0; Index < 16; Index++)
134 {
135 if (DeviceExtension->ChildPDO[Index] != NULL)
136 {
137 DPRINT("Deleting PDO %p RefCount %x AttachedDevice %p \n", DeviceExtension->ChildPDO[Index], DeviceExtension->ChildPDO[Index]->ReferenceCount, DeviceExtension->ChildPDO[Index]->AttachedDevice);
138 IoDeleteDevice(DeviceExtension->ChildPDO[Index]);
139 }
140 }
141
142 /* Send the IRP down the stack */
143 IoSkipCurrentIrpStackLocation(Irp);
144 Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
145
146 /* Detach from the device stack */
147 IoDetachDevice(DeviceExtension->LowerDeviceObject);
148
149 /* Delete the device object */
150 IoDeleteDevice(DeviceObject);
151
152 return Status;
153 }
154
155 NTSTATUS
156 USBSTOR_FdoHandleStartDevice(
157 IN PDEVICE_OBJECT DeviceObject,
158 IN PFDO_DEVICE_EXTENSION DeviceExtension,
159 IN OUT PIRP Irp)
160 {
161 PUSB_INTERFACE_DESCRIPTOR InterfaceDesc;
162 NTSTATUS Status;
163 UCHAR Index = 0;
164
165 //
166 // forward irp to lower device
167 //
168 Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
169 if (!NT_SUCCESS(Status))
170 {
171 //
172 // failed to start
173 //
174 DPRINT1("USBSTOR_FdoHandleStartDevice Lower device failed to start %x\n", Status);
175 return Status;
176 }
177
178 //
179 // intialize irp queue
180 //
181 USBSTOR_QueueInitialize(DeviceExtension);
182
183 //
184 // first get device & configuration & string descriptor
185 //
186 Status = USBSTOR_GetDescriptors(DeviceObject);
187 if (!NT_SUCCESS(Status))
188 {
189 //
190 // failed to get device descriptor
191 //
192 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device descriptor with %x\n", Status);
193 return Status;
194 }
195
196 //
197 // dump device descriptor
198 //
199 USBSTOR_DumpDeviceDescriptor(DeviceExtension->DeviceDescriptor);
200
201 //
202 // Check that this device uses bulk transfers and is SCSI
203 //
204 InterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)DeviceExtension->ConfigurationDescriptor + sizeof(USB_CONFIGURATION_DESCRIPTOR));
205
206 //
207 // sanity check
208 //
209 ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
210 ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
211
212 DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass);
213 if (InterfaceDesc->bInterfaceProtocol != 0x50)
214 {
215 DPRINT1("USB Device is not a bulk only device and is not currently supported\n");
216 return STATUS_NOT_SUPPORTED;
217 }
218
219 if (InterfaceDesc->bInterfaceSubClass != 0x06)
220 {
221 //
222 // FIXME: need to pad CDBs to 12 byte
223 // mode select commands must be translated from 1AH / 15h to 5AH / 55h
224 //
225 DPRINT1("[USBSTOR] Error: need to pad CDBs\n");
226 return STATUS_NOT_IMPLEMENTED;
227 }
228
229 //
230 // now select an interface
231 //
232 Status = USBSTOR_SelectConfigurationAndInterface(DeviceObject, DeviceExtension);
233 if (!NT_SUCCESS(Status))
234 {
235 //
236 // failed to get device descriptor
237 //
238 DPRINT1("USBSTOR_FdoHandleStartDevice failed to select configuration / interface with %x\n", Status);
239 return Status;
240 }
241
242 //
243 // check if we got a bulk in + bulk out endpoint
244 //
245 Status = USBSTOR_GetPipeHandles(DeviceExtension);
246 if (!NT_SUCCESS(Status))
247 {
248 //
249 // failed to get pipe handles descriptor
250 //
251 DPRINT1("USBSTOR_FdoHandleStartDevice no pipe handles %x\n", Status);
252 return Status;
253 }
254
255 //
256 // get num of lun which are supported
257 //
258 Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension);
259 if (!NT_SUCCESS(Status))
260 {
261 //
262 // failed to get max LUN
263 //
264 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get max lun %x\n", Status);
265 return Status;
266 }
267
268 //
269 // now create for each LUN a device object, 1 minimum
270 //
271 do
272 {
273 //
274 // create pdo
275 //
276 Status = USBSTOR_CreatePDO(DeviceObject, Index);
277
278 //
279 // check for failure
280 //
281 if (!NT_SUCCESS(Status))
282 {
283 //
284 // failed to create child pdo
285 //
286 DPRINT1("USBSTOR_FdoHandleStartDevice USBSTOR_CreatePDO failed for Index %lu with Status %x\n", Index, Status);
287 return Status;
288 }
289
290 //
291 // increment pdo index
292 //
293 Index++;
294 DeviceExtension->InstanceCount++;
295
296 }while(Index < DeviceExtension->MaxLUN);
297
298 #if 0
299 //
300 // finally get usb device interface
301 //
302 Status = USBSTOR_GetBusInterface(DeviceExtension->LowerDeviceObject, &DeviceExtension->BusInterface);
303 if (!NT_SUCCESS(Status))
304 {
305 //
306 // failed to device interface
307 //
308 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device interface %x\n", Status);
309 return Status;
310 }
311 #endif
312
313
314 //
315 // start the timer
316 //
317 //IoStartTimer(DeviceObject);
318
319
320 //
321 // fdo is now initialized
322 //
323 DPRINT("USBSTOR_FdoHandleStartDevice FDO is initialized\n");
324 return STATUS_SUCCESS;
325 }
326
327 NTSTATUS
328 USBSTOR_FdoHandlePnp(
329 IN PDEVICE_OBJECT DeviceObject,
330 IN OUT PIRP Irp)
331 {
332 PIO_STACK_LOCATION IoStack;
333 PFDO_DEVICE_EXTENSION DeviceExtension;
334 NTSTATUS Status;
335
336 //
337 // get current stack location
338 //
339 IoStack = IoGetCurrentIrpStackLocation(Irp);
340
341 //
342 // get device extension
343 //
344 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
345
346 //
347 // sanity check
348 //
349 ASSERT(DeviceExtension->Common.IsFDO);
350
351 switch(IoStack->MinorFunction)
352 {
353 case IRP_MN_SURPRISE_REMOVAL:
354 {
355 DPRINT("IRP_MN_SURPRISE_REMOVAL %p\n", DeviceObject);
356 Irp->IoStatus.Status = STATUS_SUCCESS;
357
358 //
359 // forward irp to next device object
360 //
361 IoSkipCurrentIrpStackLocation(Irp);
362 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
363 }
364 case IRP_MN_QUERY_DEVICE_RELATIONS:
365 {
366 DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS %p\n", DeviceObject);
367 Status = USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp);
368 break;
369 }
370 case IRP_MN_STOP_DEVICE:
371 {
372 DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n");
373 IoStopTimer(DeviceObject);
374 Irp->IoStatus.Status = STATUS_SUCCESS;
375
376 //
377 // forward irp to next device object
378 //
379 IoSkipCurrentIrpStackLocation(Irp);
380 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
381 }
382 case IRP_MN_REMOVE_DEVICE:
383 {
384 DPRINT("IRP_MN_REMOVE_DEVICE\n");
385
386 return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp);
387 }
388 case IRP_MN_QUERY_CAPABILITIES:
389 {
390 //
391 // FIXME: set custom capabilities
392 //
393 IoSkipCurrentIrpStackLocation(Irp);
394 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
395 }
396 case IRP_MN_QUERY_STOP_DEVICE:
397 case IRP_MN_QUERY_REMOVE_DEVICE:
398 {
399 #if 0
400 //
401 // we can if nothing is pending
402 //
403 if (DeviceExtension->IrpPendingCount != 0 ||
404 DeviceExtension->ActiveSrb != NULL)
405 #else
406 if (TRUE)
407 #endif
408 {
409 /* We have pending requests */
410 DPRINT1("Failing removal/stop request due to pending requests present\n");
411 Status = STATUS_UNSUCCESSFUL;
412 }
413 else
414 {
415 /* We're all clear */
416 Irp->IoStatus.Status = STATUS_SUCCESS;
417
418 IoSkipCurrentIrpStackLocation(Irp);
419 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
420 }
421 break;
422 }
423 case IRP_MN_START_DEVICE:
424 {
425 Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp);
426 break;
427 }
428 default:
429 {
430 //
431 // forward irp to next device object
432 //
433 IoSkipCurrentIrpStackLocation(Irp);
434 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
435 }
436 }
437
438 //
439 // complete request
440 //
441 if (Status != STATUS_PENDING)
442 {
443 //
444 // store result
445 //
446 Irp->IoStatus.Status = Status;
447
448 //
449 // complete request
450 //
451 IoCompleteRequest(Irp, IO_NO_INCREMENT);
452 }
453
454 //
455 // done processing
456 //
457 return Status;
458 }