xref: /reactos/drivers/usb/usbstor/misc.c (revision 53221834)
1 /*
2  * PROJECT:     ReactOS Universal Serial Bus Bulk Storage Driver
3  * LICENSE:     GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later)
4  * PURPOSE:     USB block storage device driver.
5  * COPYRIGHT:   2005-2006 James Tabor
6  *              2011-2012 Michael Martin (michael.martin@reactos.org)
7  *              2011-2013 Johannes Anderwald (johannes.anderwald@reactos.org)
8  */
9 
10 #include "usbstor.h"
11 
12 #define NDEBUG
13 #include <debug.h>
14 
15 
16 IO_COMPLETION_ROUTINE SyncForwardIrpCompletionRoutine;
17 
18 NTSTATUS
19 NTAPI
20 USBSTOR_SyncForwardIrpCompletionRoutine(
21     PDEVICE_OBJECT DeviceObject,
22     PIRP Irp,
23     PVOID Context)
24 {
25     if (Irp->PendingReturned)
26     {
27         KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
28     }
29     return STATUS_MORE_PROCESSING_REQUIRED;
30 }
31 
32 NTSTATUS
33 NTAPI
34 USBSTOR_SyncForwardIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
35 {
36     KEVENT Event;
37     NTSTATUS Status;
38 
39     KeInitializeEvent(&Event, NotificationEvent, FALSE);
40     IoCopyCurrentIrpStackLocationToNext(Irp);
41     IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
42 
43     Status = IoCallDriver(DeviceObject, Irp);
44 
45     if (Status == STATUS_PENDING)
46     {
47         // wait for the request to finish
48         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
49         Status = Irp->IoStatus.Status;
50     }
51 
52     return Status;
53 }
54 
55 NTSTATUS
56 NTAPI
57 USBSTOR_GetBusInterface(
58     IN PDEVICE_OBJECT DeviceObject,
59     OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterface)
60 {
61     KEVENT Event;
62     NTSTATUS Status;
63     PIRP Irp;
64     IO_STATUS_BLOCK IoStatus;
65     PIO_STACK_LOCATION Stack;
66 
67     ASSERT(DeviceObject);
68     ASSERT(BusInterface);
69 
70     KeInitializeEvent(&Event, NotificationEvent, FALSE);
71 
72     Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
73                                        DeviceObject,
74                                        NULL,
75                                        0,
76                                        NULL,
77                                        &Event,
78                                        &IoStatus);
79     if (Irp == NULL)
80     {
81         return STATUS_INSUFFICIENT_RESOURCES;
82     }
83 
84     // initialize request
85     Stack = IoGetNextIrpStackLocation(Irp);
86     Stack->MajorFunction = IRP_MJ_PNP;
87     Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
88     Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
89     Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&USB_BUS_INTERFACE_USBDI_GUID;
90     Stack->Parameters.QueryInterface.Version = 2;
91     Stack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
92     Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
93     Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
94 
95     Status = IoCallDriver(DeviceObject, Irp);
96 
97     if (Status == STATUS_PENDING)
98     {
99         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
100         Status = IoStatus.Status;
101     }
102 
103     return Status;
104 }
105 
106 NTSTATUS
107 USBSTOR_SyncUrbRequest(
108     IN PDEVICE_OBJECT DeviceObject,
109     OUT PURB UrbRequest)
110 {
111     PIRP Irp;
112     PIO_STACK_LOCATION IoStack;
113     KEVENT Event;
114     NTSTATUS Status;
115 
116     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
117     if (!Irp)
118     {
119         return STATUS_INSUFFICIENT_RESOURCES;
120     }
121 
122     KeInitializeEvent(&Event, NotificationEvent, FALSE);
123 
124     IoStack = IoGetNextIrpStackLocation(Irp);
125 
126     // initialize stack location
127     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
128     IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
129     IoStack->Parameters.Others.Argument1 = (PVOID)UrbRequest;
130     IoStack->Parameters.DeviceIoControl.InputBufferLength = UrbRequest->UrbHeader.Length;
131     Irp->IoStatus.Status = STATUS_SUCCESS;
132 
133     IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
134 
135     Status = IoCallDriver(DeviceObject, Irp);
136 
137     if (Status == STATUS_PENDING)
138     {
139         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
140         Status = Irp->IoStatus.Status;
141     }
142 
143     IoFreeIrp(Irp);
144     return Status;
145 }
146 
147 PVOID
148 AllocateItem(
149     IN POOL_TYPE PoolType,
150     IN ULONG ItemSize)
151 {
152     PVOID Item = ExAllocatePoolWithTag(PoolType, ItemSize, USB_STOR_TAG);
153 
154     if (Item)
155     {
156         RtlZeroMemory(Item, ItemSize);
157     }
158 
159     return Item;
160 }
161 
162 VOID
163 FreeItem(
164     IN PVOID Item)
165 {
166     ExFreePoolWithTag(Item, USB_STOR_TAG);
167 }
168 
169 NTSTATUS
170 USBSTOR_ClassRequest(
171     IN PDEVICE_OBJECT DeviceObject,
172     IN PFDO_DEVICE_EXTENSION DeviceExtension,
173     IN UCHAR RequestType,
174     IN USHORT Index,
175     IN ULONG TransferFlags,
176     IN ULONG TransferBufferLength,
177     IN PVOID TransferBuffer)
178 
179 {
180     PURB Urb;
181     NTSTATUS Status;
182 
183     Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
184     if (!Urb)
185     {
186         return STATUS_INSUFFICIENT_RESOURCES;
187     }
188 
189     Urb->UrbControlVendorClassRequest.Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
190     Urb->UrbControlVendorClassRequest.Hdr.Function = URB_FUNCTION_CLASS_INTERFACE;
191     Urb->UrbControlVendorClassRequest.TransferFlags = TransferFlags;
192     Urb->UrbControlVendorClassRequest.TransferBufferLength = TransferBufferLength;
193     Urb->UrbControlVendorClassRequest.TransferBuffer = TransferBuffer;
194     Urb->UrbControlVendorClassRequest.Request = RequestType;
195     Urb->UrbControlVendorClassRequest.Index = Index;
196 
197     Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
198 
199     FreeItem(Urb);
200     return Status;
201 }
202 
203 NTSTATUS
204 USBSTOR_GetMaxLUN(
205     IN PDEVICE_OBJECT DeviceObject,
206     IN PFDO_DEVICE_EXTENSION DeviceExtension)
207 {
208     PUCHAR Buffer;
209     NTSTATUS Status;
210 
211     Buffer = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool, sizeof(UCHAR), USB_STOR_TAG);
212     if (!Buffer)
213     {
214         return STATUS_INSUFFICIENT_RESOURCES;
215     }
216 
217     Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_GET_MAX_LUN, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_IN, sizeof(UCHAR), Buffer);
218 
219     DPRINT("MaxLUN: %x\n", *Buffer);
220 
221     if (NT_SUCCESS(Status))
222     {
223         if (*Buffer > MAX_LUN)
224         {
225             // invalid response documented in usb mass storage specification
226             Status = STATUS_DEVICE_DATA_ERROR;
227         }
228         else
229         {
230             // store maxlun
231             DeviceExtension->MaxLUN = *Buffer;
232         }
233     }
234     else
235     {
236         // "USB Mass Storage Class. Bulk-Only Transport. Revision 1.0"
237         // 3.2  Get Max LUN (class-specific request) :
238         // Devices that do not support multiple LUNs may STALL this command.
239         USBSTOR_ResetDevice(DeviceExtension->LowerDeviceObject, DeviceExtension);
240 
241         DeviceExtension->MaxLUN = 0;
242         Status = STATUS_SUCCESS;
243     }
244 
245     ExFreePoolWithTag(Buffer, USB_STOR_TAG);
246     return Status;
247 }
248 
249 NTSTATUS
250 USBSTOR_ResetDevice(
251     IN PDEVICE_OBJECT DeviceObject,
252     IN PFDO_DEVICE_EXTENSION DeviceExtension)
253 {
254     NTSTATUS Status;
255 
256     Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_RESET_DEVICE, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_OUT, 0, NULL);
257     return Status;
258 }
259 
260 // if somebody wants to add UFI support, here is a useful function
261 #if 0
262 BOOLEAN
263 USBSTOR_IsFloppy(
264     IN PUCHAR Buffer,
265     IN ULONG BufferLength,
266     OUT PUCHAR MediumTypeCode)
267 {
268     PUFI_CAPACITY_FORMAT_HEADER FormatHeader;
269     PUFI_CAPACITY_DESCRIPTOR Descriptor;
270     ULONG Length, Index, BlockCount, BlockLength;
271 
272     FormatHeader = (PUFI_CAPACITY_FORMAT_HEADER)Buffer;
273     ASSERT(FormatHeader->Reserved1 == 0x00);
274     ASSERT(FormatHeader->Reserved2 == 0x00);
275     ASSERT(FormatHeader->Reserved3 == 0x00);
276 
277     // is there capacity data
278     if (!FormatHeader->CapacityLength)
279     {
280         DPRINT1("[USBSTOR] No capacity length\n");
281         return FALSE;
282     }
283 
284     // the format header are always 8 bytes in length
285     ASSERT((FormatHeader->CapacityLength & 0x7) == 0);
286     DPRINT1("CapacityLength %x\n", FormatHeader->CapacityLength);
287 
288     // grab length and locate first descriptor
289     Length = FormatHeader->CapacityLength;
290     Descriptor = (PUFI_CAPACITY_DESCRIPTOR)(FormatHeader + 1);
291     for (Index = 0; Index < Length / sizeof(UFI_CAPACITY_DESCRIPTOR); Index++)
292     {
293         // blocks are little endian format
294         BlockCount = NTOHL(Descriptor->BlockCount);
295         BlockLength = NTOHL((Descriptor->BlockLengthByte0 << 24 | Descriptor->BlockLengthByte1 << 16 | Descriptor->BlockLengthByte2 << 8));
296 
297         DPRINT1("BlockCount %x BlockLength %x Code %x\n", BlockCount, BlockLength, Descriptor->Code);
298 
299         if (BlockLength == 512 && BlockCount == 1440)
300         {
301             // 720 KB DD
302             *MediumTypeCode = 0x1E;
303             return TRUE;
304         }
305         else if (BlockLength == 1024 && BlockCount == 1232)
306         {
307             // 1,25 MB
308             *MediumTypeCode = 0x93;
309             return TRUE;
310         }
311         else if (BlockLength == 512 && BlockCount == 2880)
312         {
313             // 1,44MB KB DD
314             *MediumTypeCode = 0x94;
315             return TRUE;
316         }
317 
318         Descriptor++;
319     }
320 
321     return FALSE;
322 }
323 #endif
324