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