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