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