Merge my current work done on the kd++ branch:
[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 //
15 // driver verifier
16 //
17 IO_COMPLETION_ROUTINE SyncForwardIrpCompletionRoutine;
18
19 NTSTATUS
20 NTAPI
21 USBSTOR_SyncForwardIrpCompletionRoutine(
22 PDEVICE_OBJECT DeviceObject,
23 PIRP Irp,
24 PVOID Context)
25 {
26 if (Irp->PendingReturned)
27 {
28 KeSetEvent((PKEVENT)Context, IO_NO_INCREMENT, FALSE);
29 }
30 return STATUS_MORE_PROCESSING_REQUIRED;
31 }
32
33 NTSTATUS
34 NTAPI
35 USBSTOR_SyncForwardIrp(PDEVICE_OBJECT DeviceObject, PIRP Irp)
36 {
37 KEVENT Event;
38 NTSTATUS Status;
39
40 //
41 // initialize event
42 //
43 KeInitializeEvent(&Event, NotificationEvent, FALSE);
44
45 //
46 // copy irp stack location
47 //
48 IoCopyCurrentIrpStackLocationToNext(Irp);
49
50 //
51 // set completion routine
52 //
53 IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
54
55
56 //
57 // call driver
58 //
59 Status = IoCallDriver(DeviceObject, Irp);
60
61 //
62 // check if pending
63 //
64 if (Status == STATUS_PENDING)
65 {
66 //
67 // wait for the request to finish
68 //
69 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
70
71 //
72 // copy status code
73 //
74 Status = Irp->IoStatus.Status;
75 }
76
77 //
78 // done
79 //
80 return Status;
81 }
82
83 NTSTATUS
84 NTAPI
85 USBSTOR_GetBusInterface(
86 IN PDEVICE_OBJECT DeviceObject,
87 OUT PUSB_BUS_INTERFACE_USBDI_V2 BusInterface)
88 {
89 KEVENT Event;
90 NTSTATUS Status;
91 PIRP Irp;
92 IO_STATUS_BLOCK IoStatus;
93 PIO_STACK_LOCATION Stack;
94
95 //
96 // sanity checks
97 //
98 ASSERT(DeviceObject);
99 ASSERT(BusInterface);
100
101
102 //
103 // initialize event
104 //
105 KeInitializeEvent(&Event, NotificationEvent, FALSE);
106
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
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 //
196 // get next stack location
197 //
198 IoStack = IoGetNextIrpStackLocation(Irp);
199
200 //
201 // initialize stack location
202 //
203 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
204 IoStack->Parameters.DeviceIoControl.IoControlCode = IOCTL_INTERNAL_USB_SUBMIT_URB;
205 IoStack->Parameters.Others.Argument1 = (PVOID)UrbRequest;
206 IoStack->Parameters.DeviceIoControl.InputBufferLength = UrbRequest->UrbHeader.Length;
207 Irp->IoStatus.Status = STATUS_SUCCESS;
208
209 //
210 // setup completion routine
211 //
212 IoSetCompletionRoutine(Irp, USBSTOR_SyncForwardIrpCompletionRoutine, &Event, TRUE, TRUE, TRUE);
213
214 //
215 // call driver
216 //
217 Status = IoCallDriver(DeviceObject, Irp);
218
219 //
220 // check if request is pending
221 //
222 if (Status == STATUS_PENDING)
223 {
224 //
225 // wait for completion
226 //
227 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
228
229 //
230 // update status
231 //
232 Status = Irp->IoStatus.Status;
233 }
234
235 //
236 // free irp
237 //
238 IoFreeIrp(Irp);
239
240 //
241 // done
242 //
243 return Status;
244 }
245
246 PVOID
247 AllocateItem(
248 IN POOL_TYPE PoolType,
249 IN ULONG ItemSize)
250 {
251 //
252 // allocate item
253 //
254 PVOID Item = ExAllocatePoolWithTag(PoolType, ItemSize, USB_STOR_TAG);
255
256 if (Item)
257 {
258 //
259 // zero item
260 //
261 RtlZeroMemory(Item, ItemSize);
262 }
263
264 //
265 // return element
266 //
267 return Item;
268 }
269
270 VOID
271 FreeItem(
272 IN PVOID Item)
273 {
274 //
275 // free item
276 //
277 ExFreePoolWithTag(Item, USB_STOR_TAG);
278 }
279
280 NTSTATUS
281 USBSTOR_ClassRequest(
282 IN PDEVICE_OBJECT DeviceObject,
283 IN PFDO_DEVICE_EXTENSION DeviceExtension,
284 IN UCHAR RequestType,
285 IN USHORT Index,
286 IN ULONG TransferFlags,
287 IN ULONG TransferBufferLength,
288 IN PVOID TransferBuffer)
289
290 {
291 PURB Urb;
292 PUCHAR Buffer;
293 NTSTATUS Status;
294
295 //
296 // first allocate urb
297 //
298 Urb = (PURB)AllocateItem(NonPagedPool, sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST));
299 if (!Urb)
300 {
301 //
302 // no memory
303 //
304 return STATUS_INSUFFICIENT_RESOURCES;
305 }
306
307 //
308 // allocate 1-byte buffer
309 //
310 Buffer = (PUCHAR)AllocateItem(NonPagedPool, sizeof(UCHAR));
311 if (!Buffer)
312 {
313 //
314 // no memory
315 //
316 FreeItem(Buffer);
317 return STATUS_INSUFFICIENT_RESOURCES;
318 }
319
320 //
321 // initialize vendor request
322 //
323 Urb->UrbControlVendorClassRequest.Hdr.Length = sizeof(struct _URB_CONTROL_VENDOR_OR_CLASS_REQUEST);
324 Urb->UrbControlVendorClassRequest.Hdr.Function = URB_FUNCTION_CLASS_INTERFACE;
325 Urb->UrbControlVendorClassRequest.TransferFlags = TransferFlags;
326 Urb->UrbControlVendorClassRequest.TransferBufferLength = TransferBufferLength;
327 Urb->UrbControlVendorClassRequest.TransferBuffer = TransferBuffer;
328 Urb->UrbControlVendorClassRequest.Request = RequestType;
329 Urb->UrbControlVendorClassRequest.Index = Index;
330
331 //
332 // submit request
333 //
334 Status = USBSTOR_SyncUrbRequest(DeviceObject, Urb);
335
336 //
337 // free urb
338 //
339 FreeItem(Urb);
340
341 //
342 // done
343 //
344 return Status;
345 }
346
347
348 NTSTATUS
349 USBSTOR_GetMaxLUN(
350 IN PDEVICE_OBJECT DeviceObject,
351 IN PFDO_DEVICE_EXTENSION DeviceExtension)
352 {
353 PUCHAR Buffer;
354 NTSTATUS Status;
355
356 //
357 // allocate 1-byte buffer
358 //
359 Buffer = (PUCHAR)AllocateItem(NonPagedPool, sizeof(UCHAR));
360 if (!Buffer)
361 {
362 //
363 // no memory
364 //
365 FreeItem(Buffer);
366 return STATUS_INSUFFICIENT_RESOURCES;
367 }
368
369 //
370 // execute request
371 //
372 Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_GET_MAX_LUN, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_IN, sizeof(UCHAR), Buffer);
373
374 DPRINT("MaxLUN: %x\n", *Buffer);
375
376 if (*Buffer > 0xF)
377 {
378 //
379 // invalid response documented in usb mass storage specification
380 //
381 Status = STATUS_DEVICE_DATA_ERROR;
382 }
383 else
384 {
385 //
386 // store maxlun
387 //
388 DeviceExtension->MaxLUN = *Buffer;
389 }
390
391 //
392 // free buffer
393 //
394 FreeItem(Buffer);
395
396 //
397 // done
398 //
399 return Status;
400
401 }
402
403 NTSTATUS
404 USBSTOR_ResetDevice(
405 IN PDEVICE_OBJECT DeviceObject,
406 IN PFDO_DEVICE_EXTENSION DeviceExtension)
407 {
408 NTSTATUS Status;
409
410 //
411 // execute request
412 //
413 Status = USBSTOR_ClassRequest(DeviceObject, DeviceExtension, USB_BULK_RESET_DEVICE, DeviceExtension->InterfaceInformation->InterfaceNumber, USBD_TRANSFER_DIRECTION_OUT, 0, NULL);
414
415 //
416 // done
417 //
418 return Status;
419
420 }
421
422 BOOLEAN
423 USBSTOR_IsFloppy(
424 IN PUCHAR Buffer,
425 IN ULONG BufferLength,
426 OUT PUCHAR MediumTypeCode)
427 {
428 PUFI_CAPACITY_FORMAT_HEADER FormatHeader;
429 PUFI_CAPACITY_DESCRIPTOR Descriptor;
430 ULONG Length, Index, BlockCount, BlockLength;
431
432 //
433 // get format header
434 //
435 FormatHeader = (PUFI_CAPACITY_FORMAT_HEADER)Buffer;
436
437 //
438 // sanity checks
439 //
440 ASSERT(FormatHeader->Reserved1 == 0x00);
441 ASSERT(FormatHeader->Reserved2 == 0x00);
442 ASSERT(FormatHeader->Reserved3 == 0x00);
443
444 //
445 // is there capacity data
446 //
447 if (!FormatHeader->CapacityLength)
448 {
449 //
450 // no data provided
451 //
452 DPRINT1("[USBSTOR] No capacity length\n");
453 return FALSE;
454 }
455
456 //
457 // the format header are always 8 bytes in length
458 //
459 ASSERT((FormatHeader->CapacityLength & 0x7) == 0);
460 DPRINT1("CapacityLength %x\n", FormatHeader->CapacityLength);
461
462 //
463 // grab length and locate first descriptor
464 //
465 Length = FormatHeader->CapacityLength;
466 Descriptor = (PUFI_CAPACITY_DESCRIPTOR)(FormatHeader + 1);
467 for(Index = 0; Index < Length / sizeof(UFI_CAPACITY_DESCRIPTOR); Index++)
468 {
469 //
470 // blocks are little endian format
471 //
472 BlockCount = NTOHL(Descriptor->BlockCount);
473
474 //
475 // get block length
476 //
477 BlockLength = NTOHL((Descriptor->BlockLengthByte0 << 24 | Descriptor->BlockLengthByte1 << 16 | Descriptor->BlockLengthByte2 << 8));
478
479 DPRINT1("BlockCount %x BlockLength %x Code %x\n", BlockCount, BlockLength, Descriptor->Code);
480
481 if (BlockLength == 512 && BlockCount == 1440)
482 {
483 //
484 // 720 KB DD
485 //
486 *MediumTypeCode = 0x1E;
487 return TRUE;
488 }
489 else if (BlockLength == 1024 && BlockCount == 1232)
490 {
491 //
492 // 1,25 MB
493 //
494 *MediumTypeCode = 0x93;
495 return TRUE;
496 }
497 else if (BlockLength == 512 && BlockCount == 2880)
498 {
499 //
500 // 1,44MB KB DD
501 //
502 *MediumTypeCode = 0x94;
503 return TRUE;
504 }
505
506 //
507 // move to next descriptor
508 //
509 Descriptor = (Descriptor + 1);
510 }
511
512 //
513 // no floppy detected
514 //
515 return FALSE;
516 }
517