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