xref: /reactos/drivers/usb/usbstor_new/misc.c (revision 3c774903)
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/misc.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 #define NDEBUG
15 #include <debug.h>
16 
17 //
18 // driver verifier
19 //
20 IO_COMPLETION_ROUTINE SyncForwardIrpCompletionRoutine;
21 
22 NTSTATUS
23 NTAPI
24 USBSTOR_SyncForwardIrpCompletionRoutine(
25     PDEVICE_OBJECT DeviceObject,
26     PIRP Irp,
27     PVOID Context)
28 {
29     if (Irp->PendingReturned)
30     {
31         KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
32     }
33     return STATUS_MORE_PROCESSING_REQUIRED;
34 }
35 
36 NTSTATUS
37 NTAPI
38 USBSTOR_SyncForwardIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
39 {
40     KEVENT Event;
41     NTSTATUS Status;
42 
43     //
44     // initialize event
45     //
46     KeInitializeEvent(&Event, NotificationEvent, FALSE);
47 
48     //
49     // copy irp stack location
50     //
51     IoCopyCurrentIrpStackLocationToNext(Irp);
52 
53     //
54     // set completion routine
55     //
56     IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
57 
58 
59     //
60     // call driver
61     //
62     Status = IoCallDriver(DeviceObject, Irp);
63 
64     //
65     // check if pending
66     //
67     if (Status == STATUS_PENDING)
68     {
69         //
70         // wait for the request to finish
71         //
72         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
73 
74         //
75         // copy status code
76         //
77         Status = Irp->IoStatus.Status;
78     }
79 
80     //
81     // done
82     //
83     return Status;
84 }
85 
86 NTSTATUS
87 NTAPI
88 USBSTOR_GetBusInterface(
89     IN PDEVICE_OBJECT DeviceObject,
90     OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterface)
91 {
92     KEVENT Event;
93     NTSTATUS Status;
94     PIRP Irp;
95     IO_STATUS_BLOCK IoStatus;
96     PIO_STACK_LOCATION Stack;
97 
98     //
99     // sanity checks
100     //
101     ASSERT(DeviceObject);
102     ASSERT(BusInterface);
103 
104 
105     //
106     // initialize event
107     //
108     KeInitializeEvent(&Event, NotificationEvent, FALSE);
109 
110 
111     //
112     // create irp
113     //
114     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
115                                        DeviceObject,
116                                        NULL,
117                                        0,
118                                        NULL,
119                                        &Event,
120                                        &IoStatus);
121 
122     //
123     // was irp built
124     //
125     if (Irp == NULL)
126     {
127         //
128         // no memory
129         //
130         return STATUS_INSUFFICIENT_RESOURCES;
131     }
132 
133     //
134     // initialize request
135     //
136     Stack=IoGetNextIrpStackLocation(Irp);
137     Stack->MajorFunction = IRP_MJ_PNP;
138     Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
139     Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
140     Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&USB_BUS_INTERFACE_USBDI_GUID;
141     Stack->Parameters.QueryInterface.Version = 2;
142     Stack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
143     Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
144     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
145 
146     //
147     // call driver
148     //
149     Status= IoCallDriver(DeviceObject, Irp);
150 
151     //
152     // did operation complete
153     //
154     if (Status == STATUS_PENDING)
155     {
156         //
157         // wait for completion
158         //
159         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
160 
161         //
162         // collect status
163         //
164         Status=IoStatus.Status;
165     }
166 
167     return Status;
168 }
169 
170 NTSTATUS
171 USBSTOR_SyncUrbRequest(
172     IN PDEVICE_OBJECT DeviceObject,
173     OUT PURB UrbRequest)
174 {
175     PIRP Irp;
176     PIO_STACK_LOCATION IoStack;
177     KEVENT Event;
178     NTSTATUS Status;
179 
180     //
181     // allocate irp
182     //
183     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
184     if (!Irp)
185     {
186         //
187         // no memory
188         //
189         return STATUS_INSUFFICIENT_RESOURCES;
190     }
191 
192     //
193     // initialize event
194     //
195     KeInitializeEvent(&Event, NotificationEvent, FALSE);
196 
197 
198     //
199     // get next stack location
200     //
201     IoStack = IoGetNextIrpStackLocation(Irp);
202 
203     //
204     // initialize stack location
205     //
206     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
207     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
208     IoStack->Parameters.Others.Argument1 = (PVOID)UrbRequest;
209     IoStack->Parameters.DeviceIoControl.InputBufferLength = UrbRequest->UrbHeader.Length;
210     Irp->IoStatus.Status = STATUS_SUCCESS;
211 
212     //
213     // setup completion routine
214     //
215     IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
216 
217     //
218     // call driver
219     //
220     Status = IoCallDriver(DeviceObject, Irp);
221 
222     //
223     // check if request is pending
224     //
225     if (Status == STATUS_PENDING)
226     {
227         //
228         // wait for completion
229         //
230         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
231 
232         //
233         // update status
234         //
235         Status = Irp->IoStatus.Status;
236     }
237 
238     //
239     // free irp
240     //
241     IoFreeIrp(Irp);
242 
243     //
244     // done
245     //
246     return Status;
247 }
248 
249 PVOID
250 AllocateItem(
251     IN POOL_TYPE PoolType,
252     IN ULONG ItemSize)
253 {
254     //
255     // allocate item
256     //
257     PVOID Item = ExAllocatePoolWithTag(PoolType, ItemSize, USB_STOR_TAG);
258 
259     if (Item)
260     {
261         //
262         // zero item
263         //
264         RtlZeroMemory(Item, ItemSize);
265     }
266 
267     //
268     // return element
269     //
270     return Item;
271 }
272 
273 VOID
274 FreeItem(
275     IN PVOID Item)
276 {
277     //
278     // free item
279     //
280     ExFreePoolWithTag(Item, USB_STOR_TAG);
281 }
282 
283 NTSTATUS
284 USBSTOR_ClassRequest(
285     IN PDEVICE_OBJECT DeviceObject,
286     IN PFDO_DEVICE_EXTENSION DeviceExtension,
287     IN UCHAR RequestType,
288     IN USHORT Index,
289     IN ULONG TransferFlags,
290     IN ULONG TransferBufferLength,
291     IN PVOID TransferBuffer)
292 
293 {
294     PURB Urb;
295     NTSTATUS Status;
296 
297     //
298     // first allocate urb
299     //
300     Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
301     if (!Urb)
302     {
303         //
304         // no memory
305         //
306         return STATUS_INSUFFICIENT_RESOURCES;
307     }
308 
309     //
310     // initialize vendor request
311     //
312     Urb->UrbControlVendorClassRequest.Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
313     Urb->UrbControlVendorClassRequest.Hdr.Function = URB_FUNCTION_CLASS_INTERFACE;
314     Urb->UrbControlVendorClassRequest.TransferFlags = TransferFlags;
315     Urb->UrbControlVendorClassRequest.TransferBufferLength = TransferBufferLength;
316     Urb->UrbControlVendorClassRequest.TransferBuffer = TransferBuffer;
317     Urb->UrbControlVendorClassRequest.Request = RequestType;
318     Urb->UrbControlVendorClassRequest.Index = Index;
319 
320     //
321     // submit request
322     //
323     Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
324 
325     //
326     // free urb
327     //
328     FreeItem(Urb);
329 
330     //
331     // done
332     //
333     return Status;
334 }
335 
336 
337 NTSTATUS
338 USBSTOR_GetMaxLUN(
339     IN PDEVICE_OBJECT DeviceObject,
340     IN PFDO_DEVICE_EXTENSION DeviceExtension)
341 {
342     PUCHAR Buffer;
343     NTSTATUS Status;
344 
345     //
346     // allocate 1-byte buffer
347     //
348     Buffer = (PUCHAR)AllocateItem(NonPagedPool, sizeof(UCHAR));
349     if (!Buffer)
350     {
351         //
352         // no memory
353         //
354         FreeItem(Buffer);
355         return STATUS_INSUFFICIENT_RESOURCES;
356     }
357 
358     //
359     // execute request
360     //
361     Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_GET_MAX_LUN, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_IN, sizeof(UCHAR), Buffer);
362 
363     DPRINT("MaxLUN: %x\n", *Buffer);
364 
365     if (NT_SUCCESS(Status))
366     {
367         if (*Buffer > 0xF)
368         {
369             //
370             // invalid response documented in usb mass storage specification
371             //
372             Status = STATUS_DEVICE_DATA_ERROR;
373         }
374         else
375         {
376             //
377             // store maxlun
378             //
379             DeviceExtension->MaxLUN = *Buffer;
380         }
381     }
382     else
383     {
384         //
385         // "USB Mass Storage Class. Bulk-Only Transport. Revision 1.0"
386         // 3.2  Get Max LUN (class-specific request) :
387         // Devices that do not support multiple LUNs may STALL this command.
388         //
389         USBSTOR_ResetDevice(DeviceExtension->LowerDeviceObject, DeviceExtension);
390 
391         DeviceExtension->MaxLUN = 0;
392         Status = STATUS_SUCCESS;
393     }
394 
395     //
396     // free buffer
397     //
398     FreeItem(Buffer);
399 
400     //
401     // done
402     //
403     return Status;
404 
405 }
406 
407 NTSTATUS
408 USBSTOR_ResetDevice(
409     IN PDEVICE_OBJECT DeviceObject,
410     IN PFDO_DEVICE_EXTENSION DeviceExtension)
411 {
412     NTSTATUS Status;
413 
414     //
415     // execute request
416     //
417     Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_RESET_DEVICE, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_OUT, 0, NULL);
418 
419     //
420     // done
421     //
422     return Status;
423 
424 }
425 
426 BOOLEAN
427 USBSTOR_IsFloppy(
428     IN PUCHAR Buffer,
429     IN ULONG BufferLength,
430     OUT PUCHAR MediumTypeCode)
431 {
432     PUFI_CAPACITY_FORMAT_HEADER FormatHeader;
433     PUFI_CAPACITY_DESCRIPTOR Descriptor;
434     ULONG Length, Index, BlockCount, BlockLength;
435 
436     //
437     // get format header
438     //
439     FormatHeader = (PUFI_CAPACITY_FORMAT_HEADER)Buffer;
440 
441     //
442     // sanity checks
443     //
444     ASSERT(FormatHeader->Reserved1 == 0x00);
445     ASSERT(FormatHeader->Reserved2 == 0x00);
446     ASSERT(FormatHeader->Reserved3 == 0x00);
447 
448     //
449     // is there capacity data
450     //
451     if (!FormatHeader->CapacityLength)
452     {
453         //
454         // no data provided
455         //
456         DPRINT1("[USBSTOR] No capacity length\n");
457         return FALSE;
458     }
459 
460     //
461     // the format header are always 8 bytes in length
462     //
463     ASSERT((FormatHeader->CapacityLength & 0x7) == 0);
464     DPRINT1("CapacityLength %x\n", FormatHeader->CapacityLength);
465 
466     //
467     // grab length and locate first descriptor
468     //
469     Length = FormatHeader->CapacityLength;
470     Descriptor = (PUFI_CAPACITY_DESCRIPTOR)(FormatHeader + 1);
471     for(Index = 0; Index < Length / sizeof(UFI_CAPACITY_DESCRIPTOR); Index++)
472     {
473         //
474         // blocks are little endian format
475         //
476         BlockCount = NTOHL(Descriptor->BlockCount);
477 
478         //
479         // get block length
480         //
481         BlockLength = NTOHL((Descriptor->BlockLengthByte0 << 24 | Descriptor->BlockLengthByte1 << 16 | Descriptor->BlockLengthByte2 << 8));
482 
483         DPRINT1("BlockCount %x BlockLength %x Code %x\n", BlockCount, BlockLength, Descriptor->Code);
484 
485         if (BlockLength == 512 && BlockCount == 1440)
486         {
487             //
488             // 720 KB DD
489             //
490             *MediumTypeCode = 0x1E;
491             return TRUE;
492         }
493         else if (BlockLength == 1024 && BlockCount == 1232)
494         {
495             //
496             // 1,25 MB
497             //
498             *MediumTypeCode = 0x93;
499             return TRUE;
500         }
501         else if (BlockLength == 512 && BlockCount == 2880)
502         {
503             //
504             // 1,44MB KB DD
505             //
506             *MediumTypeCode = 0x94;
507             return TRUE;
508         }
509 
510         //
511         // move to next descriptor
512         //
513         Descriptor = (Descriptor + 1);
514     }
515 
516     //
517     // no floppy detected
518     //
519     return FALSE;
520 }
521