[CRT] Massively improve performance of rand_s
[reactos.git] / drivers / usb / usbstor / fdo.c
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 * 2019 Victor Perevertkin (victor.perevertkin@reactos.org)
9 */
10
11 #include "usbstor.h"
12
13 #define NDEBUG
14 #include <debug.h>
15
16
17 #if DBG
18 static
19 VOID
20 USBSTOR_DumpDeviceDescriptor(PUSB_DEVICE_DESCRIPTOR DeviceDescriptor)
21 {
22 DPRINT("Dumping Device Descriptor %p\n", DeviceDescriptor);
23 DPRINT("bLength %x\n", DeviceDescriptor->bLength);
24 DPRINT("bDescriptorType %x\n", DeviceDescriptor->bDescriptorType);
25 DPRINT("bcdUSB %x\n", DeviceDescriptor->bcdUSB);
26 DPRINT("bDeviceClass %x\n", DeviceDescriptor->bDeviceClass);
27 DPRINT("bDeviceSubClass %x\n", DeviceDescriptor->bDeviceSubClass);
28 DPRINT("bDeviceProtocol %x\n", DeviceDescriptor->bDeviceProtocol);
29 DPRINT("bMaxPacketSize0 %x\n", DeviceDescriptor->bMaxPacketSize0);
30 DPRINT("idVendor %x\n", DeviceDescriptor->idVendor);
31 DPRINT("idProduct %x\n", DeviceDescriptor->idProduct);
32 DPRINT("bcdDevice %x\n", DeviceDescriptor->bcdDevice);
33 DPRINT("iManufacturer %x\n", DeviceDescriptor->iManufacturer);
34 DPRINT("iProduct %x\n", DeviceDescriptor->iProduct);
35 DPRINT("iSerialNumber %x\n", DeviceDescriptor->iSerialNumber);
36 DPRINT("bNumConfigurations %x\n", DeviceDescriptor->bNumConfigurations);
37 }
38 #endif
39
40 NTSTATUS
41 USBSTOR_FdoHandleDeviceRelations(
42 IN PFDO_DEVICE_EXTENSION DeviceExtension,
43 IN OUT PIRP Irp)
44 {
45 INT32 DeviceCount = 0;
46 LONG Index;
47 PDEVICE_RELATIONS DeviceRelations;
48 PIO_STACK_LOCATION IoStack;
49
50 IoStack = IoGetCurrentIrpStackLocation(Irp);
51
52 // FDO always only handles bus relations
53 if (IoStack->Parameters.QueryDeviceRelations.Type == BusRelations)
54 {
55 // go through array and count device objects
56 for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
57 {
58 if (DeviceExtension->ChildPDO[Index])
59 {
60 DeviceCount++;
61 }
62 }
63
64 DeviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS) + (DeviceCount - 1) * sizeof(PDEVICE_OBJECT), USB_STOR_TAG);
65 if (!DeviceRelations)
66 {
67 Irp->IoStatus.Information = 0;
68 Irp->IoStatus.Status = STATUS_INSUFFICIENT_RESOURCES;
69 IoCompleteRequest(Irp, IO_NO_INCREMENT);
70 return STATUS_INSUFFICIENT_RESOURCES;
71 }
72
73 DeviceRelations->Count = 0;
74
75 // add device objects
76 for (Index = 0; Index < max(DeviceExtension->MaxLUN, 1); Index++)
77 {
78 if (DeviceExtension->ChildPDO[Index])
79 {
80 // store child pdo
81 DeviceRelations->Objects[DeviceRelations->Count] = DeviceExtension->ChildPDO[Index];
82
83 // add reference
84 ObReferenceObject(DeviceExtension->ChildPDO[Index]);
85
86 DeviceRelations->Count++;
87 }
88 }
89
90 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
91 Irp->IoStatus.Status = STATUS_SUCCESS;
92 }
93
94 IoCopyCurrentIrpStackLocationToNext(Irp);
95
96 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
97 }
98
99 NTSTATUS
100 USBSTOR_FdoHandleRemoveDevice(
101 IN PDEVICE_OBJECT DeviceObject,
102 IN PFDO_DEVICE_EXTENSION DeviceExtension,
103 IN OUT PIRP Irp)
104 {
105 NTSTATUS Status;
106 ULONG Index;
107
108 DPRINT("Handling FDO removal %p\n", DeviceObject);
109
110 // FIXME: wait for devices finished processing
111 for (Index = 0; Index < USB_MAXCHILDREN; Index++)
112 {
113 if (DeviceExtension->ChildPDO[Index] != NULL)
114 {
115 DPRINT("Deleting PDO %p RefCount %x AttachedDevice %p \n", DeviceExtension->ChildPDO[Index], DeviceExtension->ChildPDO[Index]->ReferenceCount, DeviceExtension->ChildPDO[Index]->AttachedDevice);
116 IoDeleteDevice(DeviceExtension->ChildPDO[Index]);
117 }
118 }
119
120 // Freeing everything in DeviceExtension
121 ASSERT(
122 DeviceExtension->DeviceDescriptor &&
123 DeviceExtension->ConfigurationDescriptor &&
124 DeviceExtension->InterfaceInformation &&
125 DeviceExtension->ResetDeviceWorkItem
126 );
127
128 ExFreePoolWithTag(DeviceExtension->DeviceDescriptor, USB_STOR_TAG);
129 ExFreePoolWithTag(DeviceExtension->ConfigurationDescriptor, USB_STOR_TAG);
130 ExFreePoolWithTag(DeviceExtension->InterfaceInformation, USB_STOR_TAG);
131 IoFreeWorkItem(DeviceExtension->ResetDeviceWorkItem);
132
133 if (DeviceExtension->SerialNumber)
134 {
135 ExFreePoolWithTag(DeviceExtension->SerialNumber, USB_STOR_TAG);
136 }
137
138 // Send the IRP down the stack
139 IoSkipCurrentIrpStackLocation(Irp);
140 Irp->IoStatus.Status = STATUS_SUCCESS;
141 Status = IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
142
143 // Detach from the device stack
144 IoDetachDevice(DeviceExtension->LowerDeviceObject);
145
146 IoDeleteDevice(DeviceObject);
147
148 return Status;
149 }
150
151 NTSTATUS
152 USBSTOR_FdoHandleStartDevice(
153 IN PDEVICE_OBJECT DeviceObject,
154 IN PFDO_DEVICE_EXTENSION DeviceExtension,
155 IN OUT PIRP Irp)
156 {
157 PUSB_INTERFACE_DESCRIPTOR InterfaceDesc;
158 NTSTATUS Status;
159 UCHAR Index = 0;
160 PIO_WORKITEM WorkItem;
161
162 // forward irp to lower device
163 if (!IoForwardIrpSynchronously(DeviceExtension->LowerDeviceObject, Irp))
164 {
165 return STATUS_UNSUCCESSFUL;
166 }
167
168 Status = Irp->IoStatus.Status;
169 if (!NT_SUCCESS(Status))
170 {
171 DPRINT1("USBSTOR_FdoHandleStartDevice Lower device failed to start %x\n", Status);
172 return Status;
173 }
174
175 if (!DeviceExtension->ResetDeviceWorkItem)
176 {
177 WorkItem = IoAllocateWorkItem(DeviceObject);
178 DeviceExtension->ResetDeviceWorkItem = WorkItem;
179
180 if (!WorkItem)
181 {
182 return STATUS_INSUFFICIENT_RESOURCES;
183 }
184 }
185
186 // initialize irp queue
187 USBSTOR_QueueInitialize(DeviceExtension);
188
189 // first get device & configuration & string descriptor
190 Status = USBSTOR_GetDescriptors(DeviceObject);
191 if (!NT_SUCCESS(Status))
192 {
193 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device descriptor with %x\n", Status);
194 return Status;
195 }
196
197 #if DBG
198 USBSTOR_DumpDeviceDescriptor(DeviceExtension->DeviceDescriptor);
199 #endif
200
201 // Check that this device uses bulk transfers and is SCSI
202
203 InterfaceDesc = (PUSB_INTERFACE_DESCRIPTOR)((ULONG_PTR)DeviceExtension->ConfigurationDescriptor + sizeof(USB_CONFIGURATION_DESCRIPTOR));
204 ASSERT(InterfaceDesc->bDescriptorType == USB_INTERFACE_DESCRIPTOR_TYPE);
205 ASSERT(InterfaceDesc->bLength == sizeof(USB_INTERFACE_DESCRIPTOR));
206
207 DPRINT("bInterfaceSubClass %x\n", InterfaceDesc->bInterfaceSubClass);
208 if (InterfaceDesc->bInterfaceProtocol != USB_PROTOCOL_BULK)
209 {
210 DPRINT1("USB Device is not a bulk only device and is not currently supported\n");
211 return STATUS_NOT_SUPPORTED;
212 }
213
214 if (InterfaceDesc->bInterfaceSubClass == USB_SUBCLASS_UFI)
215 {
216 DPRINT1("USB Floppy devices are not supported\n");
217 return STATUS_NOT_SUPPORTED;
218 }
219
220 // now select an interface
221 Status = USBSTOR_SelectConfigurationAndInterface(DeviceObject, DeviceExtension);
222 if (!NT_SUCCESS(Status))
223 {
224 // failed to get device descriptor
225 DPRINT1("USBSTOR_FdoHandleStartDevice failed to select configuration / interface with %x\n", Status);
226 return Status;
227 }
228
229 // check if we got a bulk in + bulk out endpoint
230 Status = USBSTOR_GetPipeHandles(DeviceExtension);
231 if (!NT_SUCCESS(Status))
232 {
233 DPRINT1("USBSTOR_FdoHandleStartDevice no pipe handles %x\n", Status);
234 return Status;
235 }
236
237 Status = USBSTOR_GetMaxLUN(DeviceExtension->LowerDeviceObject, DeviceExtension);
238 if (!NT_SUCCESS(Status))
239 {
240 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get max lun %x\n", Status);
241 return Status;
242 }
243
244 // now create for each LUN a device object, 1 minimum
245 do
246 {
247 Status = USBSTOR_CreatePDO(DeviceObject, Index);
248
249 if (!NT_SUCCESS(Status))
250 {
251 DPRINT1("USBSTOR_FdoHandleStartDevice USBSTOR_CreatePDO failed for Index %lu with Status %x\n", Index, Status);
252 return Status;
253 }
254
255 Index++;
256 DeviceExtension->InstanceCount++;
257
258 } while(Index < DeviceExtension->MaxLUN);
259
260 #if 0
261 //
262 // finally get usb device interface
263 //
264 Status = USBSTOR_GetBusInterface(DeviceExtension->LowerDeviceObject, &DeviceExtension->BusInterface);
265 if (!NT_SUCCESS(Status))
266 {
267 //
268 // failed to device interface
269 //
270 DPRINT1("USBSTOR_FdoHandleStartDevice failed to get device interface %x\n", Status);
271 return Status;
272 }
273 #endif
274
275 //IoStartTimer(DeviceObject);
276
277 DPRINT("USBSTOR_FdoHandleStartDevice FDO is initialized\n");
278 return STATUS_SUCCESS;
279 }
280
281 NTSTATUS
282 USBSTOR_FdoHandlePnp(
283 IN PDEVICE_OBJECT DeviceObject,
284 IN OUT PIRP Irp)
285 {
286 PIO_STACK_LOCATION IoStack;
287 PFDO_DEVICE_EXTENSION DeviceExtension;
288 NTSTATUS Status;
289
290 IoStack = IoGetCurrentIrpStackLocation(Irp);
291 DeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
292 ASSERT(DeviceExtension->Common.IsFDO);
293
294 switch(IoStack->MinorFunction)
295 {
296 case IRP_MN_SURPRISE_REMOVAL:
297 {
298 DPRINT("IRP_MN_SURPRISE_REMOVAL %p\n", DeviceObject);
299 Irp->IoStatus.Status = STATUS_SUCCESS;
300
301 // forward irp to next device object
302 IoSkipCurrentIrpStackLocation(Irp);
303 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
304 }
305 case IRP_MN_QUERY_DEVICE_RELATIONS:
306 {
307 DPRINT("IRP_MN_QUERY_DEVICE_RELATIONS %p Type: %u\n", DeviceObject, IoStack->Parameters.QueryDeviceRelations.Type);
308 return USBSTOR_FdoHandleDeviceRelations(DeviceExtension, Irp);
309 }
310 case IRP_MN_STOP_DEVICE:
311 {
312 DPRINT1("USBSTOR_FdoHandlePnp: IRP_MN_STOP_DEVICE unimplemented\n");
313 IoStopTimer(DeviceObject);
314 Irp->IoStatus.Status = STATUS_SUCCESS;
315
316 // forward irp to next device object
317 IoSkipCurrentIrpStackLocation(Irp);
318 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
319 }
320 case IRP_MN_REMOVE_DEVICE:
321 {
322 DPRINT("IRP_MN_REMOVE_DEVICE\n");
323
324 return USBSTOR_FdoHandleRemoveDevice(DeviceObject, DeviceExtension, Irp);
325 }
326 case IRP_MN_QUERY_CAPABILITIES:
327 {
328 // FIXME: set custom capabilities
329 IoSkipCurrentIrpStackLocation(Irp);
330 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
331 }
332 case IRP_MN_QUERY_STOP_DEVICE:
333 case IRP_MN_QUERY_REMOVE_DEVICE:
334 {
335 if (DeviceExtension->IrpPendingCount != 0 || DeviceExtension->ActiveSrb != NULL)
336 {
337 /* We have pending requests */
338 DPRINT1("Failing removal/stop request due to pending requests present\n");
339 Status = STATUS_UNSUCCESSFUL;
340 }
341 else
342 {
343 /* We're all clear */
344 Irp->IoStatus.Status = STATUS_SUCCESS;
345
346 IoSkipCurrentIrpStackLocation(Irp);
347 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
348 }
349 break;
350 }
351 case IRP_MN_START_DEVICE:
352 {
353 Status = USBSTOR_FdoHandleStartDevice(DeviceObject, DeviceExtension, Irp);
354 break;
355 }
356 default:
357 {
358 // forward irp to next device object
359 IoSkipCurrentIrpStackLocation(Irp);
360 return IoCallDriver(DeviceExtension->LowerDeviceObject, Irp);
361 }
362 }
363
364 if (Status != STATUS_PENDING)
365 {
366 Irp->IoStatus.Status = Status;
367 IoCompleteRequest(Irp, IO_NO_INCREMENT);
368 }
369
370 return Status;
371 }