0751842803744dfa0f4f5a0627ee1de961fee331
[reactos.git] / reactos / 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 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 }