[USBSTOR]
[reactos.git] / reactos / drivers / usb / usbstor / misc.c
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
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
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 //
60 // call driver
61 //
62 Status = IoCallDriver(DeviceObject, Irp);
63
64 //
65 // check if pending
66 //
67 if (Status == STATUS_PENDING)
68 {
69 //
70 // wait for the request to finish
71 //
72 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
73
74 //
75 // copy status code
76 //
77 Status = Irp->IoStatus.Status;
78 }
79
80 //
81 // done
82 //
83 return Status;
84 }
85
86 NTSTATUS
87 NTAPI
88 USBSTOR_GetBusInterface(
89 IN PDEVICE_OBJECT DeviceObject,
90 OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterface)
91 {
92 KEVENT Event;
93 NTSTATUS Status;
94 PIRP Irp;
95 IO_STATUS_BLOCK IoStatus;
96 PIO_STACK_LOCATION Stack;
97
98 //
99 // sanity checks
100 //
101 ASSERT(DeviceObject);
102 ASSERT(BusInterface);
103
104
105 //
106 // initialize event
107 //
108 KeInitializeEvent(&Event, NotificationEvent, FALSE);
109
110
111 //
112 // create irp
113 //
114 Irp = IoBuildSynchronousFsdRequest(IRP_MJ_PNP,
115 DeviceObject,
116 NULL,
117 0,
118 NULL,
119 &Event,
120 &IoStatus);
121
122 //
123 // was irp built
124 //
125 if (Irp == NULL)
126 {
127 //
128 // no memory
129 //
130 return STATUS_INSUFFICIENT_RESOURCES;
131 }
132
133 //
134 // initialize request
135 //
136 Stack=IoGetNextIrpStackLocation(Irp);
137 Stack->MajorFunction = IRP_MJ_PNP;
138 Stack->MinorFunction = IRP_MN_QUERY_INTERFACE;
139 Stack->Parameters.QueryInterface.Size = sizeof(BUS_INTERFACE_STANDARD);
140 Stack->Parameters.QueryInterface.InterfaceType = (LPGUID)&USB_BUS_INTERFACE_USBDI_GUID;
141 Stack->Parameters.QueryInterface.Version = 2;
142 Stack->Parameters.QueryInterface.Interface = (PINTERFACE)BusInterface;
143 Stack->Parameters.QueryInterface.InterfaceSpecificData = NULL;
144 Irp->IoStatus.Status = STATUS_NOT_SUPPORTED;
145
146 //
147 // call driver
148 //
149 Status= IoCallDriver(DeviceObject, Irp);
150
151 //
152 // did operation complete
153 //
154 if (Status == STATUS_PENDING)
155 {
156 //
157 // wait for completion
158 //
159 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
160
161 //
162 // collect status
163 //
164 Status=IoStatus.Status;
165 }
166
167 return Status;
168 }
169
170 NTSTATUS
171 USBSTOR_SyncUrbRequest(
172 IN PDEVICE_OBJECT DeviceObject,
173 OUT PURB UrbRequest)
174 {
175 PIRP Irp;
176 PIO_STACK_LOCATION IoStack;
177 KEVENT Event;
178 NTSTATUS Status;
179
180 //
181 // allocate irp
182 //
183 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
184 if (!Irp)
185 {
186 //
187 // no memory
188 //
189 return STATUS_INSUFFICIENT_RESOURCES;
190 }
191
192 //
193 // initialize event
194 //
195 KeInitializeEvent(&Event, NotificationEvent, FALSE);
196
197
198 //
199 // get next stack location
200 //
201 IoStack = IoGetNextIrpStackLocation(Irp);
202
203 //
204 // initialize stack location
205 //
206 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
207 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
208 IoStack->Parameters.Others.Argument1 = (PVOID)UrbRequest;
209 IoStack->Parameters.DeviceIoControl.InputBufferLength = UrbRequest->UrbHeader.Length;
210 Irp->IoStatus.Status = STATUS_SUCCESS;
211
212 //
213 // setup completion routine
214 //
215 IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
216
217 //
218 // call driver
219 //
220 Status = IoCallDriver(DeviceObject, Irp);
221
222 //
223 // check if request is pending
224 //
225 if (Status == STATUS_PENDING)
226 {
227 //
228 // wait for completion
229 //
230 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
231
232 //
233 // update status
234 //
235 Status = Irp->IoStatus.Status;
236 }
237
238 //
239 // free irp
240 //
241 IoFreeIrp(Irp);
242
243 //
244 // done
245 //
246 return Status;
247 }
248
249 PVOID
250 AllocateItem(
251 IN POOL_TYPE PoolType,
252 IN ULONG ItemSize)
253 {
254 //
255 // allocate item
256 //
257 PVOID Item = ExAllocatePoolWithTag(PoolType, ItemSize, USB_STOR_TAG);
258
259 if (Item)
260 {
261 //
262 // zero item
263 //
264 RtlZeroMemory(Item, ItemSize);
265 }
266
267 //
268 // return element
269 //
270 return Item;
271 }
272
273 VOID
274 FreeItem(
275 IN PVOID Item)
276 {
277 //
278 // free item
279 //
280 ExFreePoolWithTag(Item, USB_STOR_TAG);
281 }
282
283 NTSTATUS
284 USBSTOR_ClassRequest(
285 IN PDEVICE_OBJECT DeviceObject,
286 IN PFDO_DEVICE_EXTENSION DeviceExtension,
287 IN UCHAR RequestType,
288 IN USHORT Index,
289 IN ULONG TransferFlags,
290 IN ULONG TransferBufferLength,
291 IN PVOID TransferBuffer)
292
293 {
294 PURB Urb;
295 PUCHAR Buffer;
296 NTSTATUS Status;
297
298 //
299 // first allocate urb
300 //
301 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
302 if (!Urb)
303 {
304 //
305 // no memory
306 //
307 return STATUS_INSUFFICIENT_RESOURCES;
308 }
309
310 //
311 // allocate 1-byte buffer
312 //
313 Buffer = (PUCHAR)AllocateItem(NonPagedPool, sizeof(UCHAR));
314 if (!Buffer)
315 {
316 //
317 // no memory
318 //
319 FreeItem(Buffer);
320 return STATUS_INSUFFICIENT_RESOURCES;
321 }
322
323 //
324 // initialize vendor request
325 //
326 Urb->UrbControlVendorClassRequest.Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
327 Urb->UrbControlVendorClassRequest.Hdr.Function = URB_FUNCTION_CLASS_INTERFACE;
328 Urb->UrbControlVendorClassRequest.TransferFlags = TransferFlags;
329 Urb->UrbControlVendorClassRequest.TransferBufferLength = TransferBufferLength;
330 Urb->UrbControlVendorClassRequest.TransferBuffer = TransferBuffer;
331 Urb->UrbControlVendorClassRequest.Request = RequestType;
332 Urb->UrbControlVendorClassRequest.Index = Index;
333
334 //
335 // submit request
336 //
337 Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
338
339 //
340 // free urb
341 //
342 FreeItem(Urb);
343
344 //
345 // done
346 //
347 return Status;
348 }
349
350
351 NTSTATUS
352 USBSTOR_GetMaxLUN(
353 IN PDEVICE_OBJECT DeviceObject,
354 IN PFDO_DEVICE_EXTENSION DeviceExtension)
355 {
356 PUCHAR Buffer;
357 NTSTATUS Status;
358
359 //
360 // allocate 1-byte buffer
361 //
362 Buffer = (PUCHAR)AllocateItem(NonPagedPool, sizeof(UCHAR));
363 if (!Buffer)
364 {
365 //
366 // no memory
367 //
368 FreeItem(Buffer);
369 return STATUS_INSUFFICIENT_RESOURCES;
370 }
371
372 //
373 // execute request
374 //
375 Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_GET_MAX_LUN, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_IN, sizeof(UCHAR), Buffer);
376
377 DPRINT("MaxLUN: %x\n", *Buffer);
378
379 if (*Buffer > 0xF)
380 {
381 //
382 // invalid response documented in usb mass storage specification
383 //
384 Status = STATUS_DEVICE_DATA_ERROR;
385 }
386 else
387 {
388 //
389 // store maxlun
390 //
391 DeviceExtension->MaxLUN = *Buffer;
392 }
393
394 //
395 // free buffer
396 //
397 FreeItem(Buffer);
398
399 //
400 // done
401 //
402 return Status;
403
404 }
405
406 NTSTATUS
407 USBSTOR_ResetDevice(
408 IN PDEVICE_OBJECT DeviceObject,
409 IN PFDO_DEVICE_EXTENSION DeviceExtension)
410 {
411 NTSTATUS Status;
412
413 //
414 // execute request
415 //
416 Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_RESET_DEVICE, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_OUT, 0, NULL);
417
418 //
419 // done
420 //
421 return Status;
422
423 }
424
425 BOOLEAN
426 USBSTOR_IsFloppy(
427 IN PUCHAR Buffer,
428 IN ULONG BufferLength,
429 OUT PUCHAR MediumTypeCode)
430 {
431 PUFI_CAPACITY_FORMAT_HEADER FormatHeader;
432 PUFI_CAPACITY_DESCRIPTOR Descriptor;
433 ULONG Length, Index, BlockCount, BlockLength;
434
435 //
436 // get format header
437 //
438 FormatHeader = (PUFI_CAPACITY_FORMAT_HEADER)Buffer;
439
440 //
441 // sanity checks
442 //
443 ASSERT(FormatHeader->Reserved1 == 0x00);
444 ASSERT(FormatHeader->Reserved2 == 0x00);
445 ASSERT(FormatHeader->Reserved3 == 0x00);
446
447 //
448 // is there capacity data
449 //
450 if (!FormatHeader->CapacityLength)
451 {
452 //
453 // no data provided
454 //
455 DPRINT1("[USBSTOR] No capacity length\n");
456 return FALSE;
457 }
458
459 //
460 // the format header are always 8 bytes in length
461 //
462 ASSERT((FormatHeader->CapacityLength & 0x7) == 0);
463 DPRINT1("CapacityLength %x\n", FormatHeader->CapacityLength);
464
465 //
466 // grab length and locate first descriptor
467 //
468 Length = FormatHeader->CapacityLength;
469 Descriptor = (PUFI_CAPACITY_DESCRIPTOR)(FormatHeader + 1);
470 for(Index = 0; Index < Length / sizeof(UFI_CAPACITY_DESCRIPTOR); Index++)
471 {
472 //
473 // blocks are little endian format
474 //
475 BlockCount = NTOHL(Descriptor->BlockCount);
476
477 //
478 // get block length
479 //
480 BlockLength = NTOHL((Descriptor->BlockLengthByte0 << 24 | Descriptor->BlockLengthByte1 << 16 | Descriptor->BlockLengthByte2 << 8));
481
482 DPRINT1("BlockCount %x BlockLength %x Code %x\n", BlockCount, BlockLength, Descriptor->Code);
483
484 if (BlockLength == 512 && BlockCount == 1440)
485 {
486 //
487 // 720 KB DD
488 //
489 *MediumTypeCode = 0x1E;
490 return TRUE;
491 }
492 else if (BlockLength == 1024 && BlockCount == 1232)
493 {
494 //
495 // 1,25 MB
496 //
497 *MediumTypeCode = 0x93;
498 return TRUE;
499 }
500 else if (BlockLength == 512 && BlockCount == 2880)
501 {
502 //
503 // 1,44MB KB DD
504 //
505 *MediumTypeCode = 0x94;
506 return TRUE;
507 }
508
509 //
510 // move to next descriptor
511 //
512 Descriptor = (Descriptor + 1);
513 }
514
515 //
516 // no floppy detected
517 //
518 return FALSE;
519 }
520