b41cb9345d123f2d036ebba4feb5795808731313
[reactos.git] / drivers / usb / usbstor / pdo.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 * 2017 Vadim Galyant
9 * 2019 Victor Perevertkin (victor.perevertkin@reactos.org)
10 */
11
12 #include "usbstor.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17
18 LPCSTR
19 USBSTOR_GetDeviceType(
20 IN PINQUIRYDATA InquiryData,
21 IN UCHAR IsFloppy)
22 {
23 if (InquiryData->DeviceType == 0)
24 {
25 if (IsFloppy)
26 {
27 // floppy device
28 return "SFloppy";
29 }
30
31 // direct access device
32 return "Disk";
33 }
34
35 switch (InquiryData->DeviceType)
36 {
37 case 1:
38 {
39 // sequential device, i.e magnetic tape
40 return "Sequential";
41 }
42 case 4:
43 {
44 // write once device
45 return "Worm";
46 }
47 case 5:
48 {
49 // CDROM device
50 return "CdRom";
51 }
52 case 7:
53 {
54 // optical memory device
55 return "Optical";
56 }
57 case 8:
58 {
59 // medium change device
60 return "Changer";
61 }
62 default:
63 {
64 // other device
65 return "Other";
66 }
67 }
68 }
69
70 LPCSTR
71 USBSTOR_GetGenericType(
72 IN PINQUIRYDATA InquiryData,
73 IN UCHAR IsFloppy)
74 {
75 if (InquiryData->DeviceType == 0)
76 {
77 if (IsFloppy)
78 {
79 // floppy device
80 return "GenSFloppy";
81 }
82
83 // direct access device
84 return "GenDisk";
85 }
86
87 switch (InquiryData->DeviceType)
88 {
89 case 1:
90 {
91 // sequential device, i.e magnetic tape
92 return "GenSequential";
93 }
94 case 4:
95 {
96 // write once device
97 return "GenWorm";
98 }
99 case 5:
100 {
101 // CDROM device
102 return "GenCdRom";
103 }
104 case 7:
105 {
106 // optical memory device
107 return "GenOptical";
108 }
109 case 8:
110 {
111 // medium change device
112 return "GenChanger";
113 }
114 default:
115 {
116 // other device
117 return "UsbstorOther";
118 }
119 }
120 }
121
122 ULONG
123 CopyField(
124 IN PUCHAR Name,
125 IN PCHAR Buffer,
126 IN ULONG MaxLength)
127 {
128 ULONG Index;
129
130 for (Index = 0; Index < MaxLength; Index++)
131 {
132 if (Name[Index] <= ' ' || Name[Index] >= 0x7F /* last printable ascii character */ || Name[Index] == ',')
133 {
134 // convert to underscore
135 Buffer[Index] = '_';
136 }
137 else
138 {
139 // just copy character
140 Buffer[Index] = Name[Index];
141 }
142 }
143
144 return MaxLength;
145 }
146
147 NTSTATUS
148 USBSTOR_PdoHandleQueryDeviceText(
149 IN PDEVICE_OBJECT DeviceObject,
150 IN PIRP Irp)
151 {
152 PIO_STACK_LOCATION IoStack;
153 LPWSTR Buffer;
154 static WCHAR DeviceText[] = L"USB Mass Storage Device";
155
156 IoStack = IoGetCurrentIrpStackLocation(Irp);
157
158 if (IoStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription)
159 {
160 DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextDescription\n");
161
162 Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
163 if (!Buffer)
164 {
165 Irp->IoStatus.Information = 0;
166 return STATUS_INSUFFICIENT_RESOURCES;
167 }
168
169 wcscpy(Buffer, DeviceText);
170
171 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
172 return STATUS_SUCCESS;
173 }
174 else
175 {
176 DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextLocationInformation\n");
177
178 Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
179 if (!Buffer)
180 {
181 Irp->IoStatus.Information = 0;
182 return STATUS_INSUFFICIENT_RESOURCES;
183 }
184
185 wcscpy(Buffer, DeviceText);
186
187 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
188 return STATUS_SUCCESS;
189 }
190
191 }
192
193 NTSTATUS
194 USBSTOR_PdoHandleQueryDeviceId(
195 IN PDEVICE_OBJECT DeviceObject,
196 IN PIRP Irp)
197 {
198 PPDO_DEVICE_EXTENSION DeviceExtension;
199 NTSTATUS Status;
200 CHAR Buffer[100] = {0};
201 LPCSTR DeviceType;
202 ULONG Offset = 0;
203 PINQUIRYDATA InquiryData;
204 ANSI_STRING AnsiString;
205 UNICODE_STRING DeviceId;
206
207 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
208 ASSERT(DeviceExtension->InquiryData);
209 InquiryData = DeviceExtension->InquiryData;
210
211 DeviceType = USBSTOR_GetDeviceType(InquiryData, DeviceExtension->IsFloppy);
212
213 // lets create device string
214 Offset = sprintf(&Buffer[Offset], "USBSTOR\\");
215 Offset += sprintf(&Buffer[Offset], DeviceType);
216 Offset += sprintf(&Buffer[Offset], "&Ven_");
217 Offset += CopyField(InquiryData->VendorId, &Buffer[Offset], 8);
218 Offset += sprintf(&Buffer[Offset], "&Prod_");
219 Offset += CopyField(InquiryData->ProductId, &Buffer[Offset], 16);
220 Offset += sprintf(&Buffer[Offset], "&Rev_");
221 Offset += CopyField(InquiryData->ProductRevisionLevel, &Buffer[Offset], 4);
222
223 RtlInitAnsiString(&AnsiString, (PCSZ)Buffer);
224
225 // allocate DeviceId string
226 DeviceId.Length = 0;
227 DeviceId.MaximumLength = (USHORT)((strlen((PCHAR)Buffer) + 1) * sizeof(WCHAR));
228 DeviceId.Buffer = (LPWSTR)AllocateItem(PagedPool, DeviceId.MaximumLength);
229 if (!DeviceId.Buffer)
230 {
231 Irp->IoStatus.Information = 0;
232 return STATUS_INSUFFICIENT_RESOURCES;
233 }
234
235 Status = RtlAnsiStringToUnicodeString(&DeviceId, &AnsiString, FALSE);
236
237 if (NT_SUCCESS(Status))
238 {
239 Irp->IoStatus.Information = (ULONG_PTR)DeviceId.Buffer;
240 }
241
242 DPRINT("DeviceId %wZ Status %x\n", &DeviceId, Status);
243
244 return Status;
245 }
246
247 VOID
248 USBSTOR_ConvertToUnicodeString(
249 IN CHAR * Buffer,
250 IN ULONG ResultBufferLength,
251 IN ULONG ResultBufferOffset,
252 OUT LPWSTR ResultBuffer,
253 OUT PULONG NewResultBufferOffset)
254 {
255 UNICODE_STRING DeviceString;
256 ANSI_STRING AnsiString;
257 NTSTATUS Status;
258
259 ASSERT(ResultBufferLength);
260 ASSERT(ResultBufferLength > ResultBufferOffset);
261
262 DPRINT("ResultBufferOffset %lu ResultBufferLength %lu Buffer %s Length %lu\n", ResultBufferOffset, ResultBufferLength, Buffer, strlen(Buffer));
263
264 // construct destination string
265 DeviceString.Buffer = &ResultBuffer[ResultBufferOffset];
266 DeviceString.Length = 0;
267 DeviceString.MaximumLength = (ResultBufferLength - ResultBufferOffset) * sizeof(WCHAR);
268
269 // initialize source string
270 RtlInitAnsiString(&AnsiString, Buffer);
271
272 Status = RtlAnsiStringToUnicodeString(&DeviceString, &AnsiString, FALSE);
273 ASSERT(Status == STATUS_SUCCESS);
274
275 // subtract consumed bytes
276 ResultBufferLength -= (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
277 ResultBufferOffset += (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
278
279 *NewResultBufferOffset = ResultBufferOffset;
280 }
281
282 NTSTATUS
283 USBSTOR_PdoHandleQueryHardwareId(
284 IN PDEVICE_OBJECT DeviceObject,
285 IN OUT PIRP Irp)
286 {
287 PPDO_DEVICE_EXTENSION PDODeviceExtension;
288 PFDO_DEVICE_EXTENSION FDODeviceExtension;
289 LPCSTR GenericType, DeviceType;
290 LPWSTR Buffer;
291 CHAR Id1[50], Id2[50], Id3[50], Id4[50], Id5[50], Id6[50];
292 ULONG Id1Length, Id2Length, Id3Length, Id4Length, Id5Length,Id6Length;
293 ULONG Offset, TotalLength, Length;
294 PINQUIRYDATA InquiryData;
295
296 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
297 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
298 ASSERT(FDODeviceExtension->DeviceDescriptor);
299 InquiryData = PDODeviceExtension->InquiryData;
300
301 DeviceType = USBSTOR_GetDeviceType(InquiryData, PDODeviceExtension->IsFloppy);
302 GenericType = USBSTOR_GetGenericType(InquiryData, PDODeviceExtension->IsFloppy);
303
304 ASSERT(GenericType);
305
306 // generate id 1
307 // USBSTOR\SCSIType_VendorId(8)_ProductId(16)_Revision(4)
308 RtlZeroMemory(Id1, sizeof(Id1));
309 Offset = 0;
310 Offset = sprintf(&Id1[Offset], "USBSTOR\\");
311 Offset += sprintf(&Id1[Offset], DeviceType);
312 Offset += CopyField(InquiryData->VendorId, &Id1[Offset], 8);
313 Offset += CopyField(InquiryData->ProductId, &Id1[Offset], 16);
314 Offset += CopyField(InquiryData->ProductRevisionLevel, &Id1[Offset], 4);
315 Id1Length = strlen(Id1) + 1;
316 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId1 %s\n", Id1);
317
318 // generate id 2
319 // USBSTOR\SCSIType_VendorId(8)_ProductId(16)
320 RtlZeroMemory(Id2, sizeof(Id2));
321 Offset = 0;
322 Offset = sprintf(&Id2[Offset], "USBSTOR\\");
323 Offset += sprintf(&Id2[Offset], DeviceType);
324 Offset += CopyField(InquiryData->VendorId, &Id2[Offset], 8);
325 Offset += CopyField(InquiryData->ProductId, &Id2[Offset], 16);
326 Id2Length = strlen(Id2) + 1;
327 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId2 %s\n", Id2);
328
329 // generate id 3
330 // USBSTOR\SCSIType_VendorId(8)
331 RtlZeroMemory(Id3, sizeof(Id3));
332 Offset = 0;
333 Offset = sprintf(&Id3[Offset], "USBSTOR\\");
334 Offset += sprintf(&Id3[Offset], DeviceType);
335 Offset += CopyField(InquiryData->VendorId, &Id3[Offset], 8);
336 Id3Length = strlen(Id3) + 1;
337 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId3 %s\n", Id3);
338
339 // generate id 4
340 // USBSTOR\SCSIType_VendorId(8)_ProductId(16)_Revision(1)
341 RtlZeroMemory(Id4, sizeof(Id4));
342 Offset = 0;
343 Offset = sprintf(&Id4[Offset], "USBSTOR\\");
344 Offset += sprintf(&Id4[Offset], DeviceType);
345 Offset += CopyField(InquiryData->VendorId, &Id4[Offset], 8);
346 Offset += CopyField(InquiryData->ProductId, &Id4[Offset], 16);
347 Offset += CopyField(InquiryData->ProductRevisionLevel, &Id4[Offset], 1);
348 Id4Length = strlen(Id4) + 1;
349 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId4 %s\n", Id4);
350
351 // generate id 5
352 // USBSTOR\SCSIType
353 RtlZeroMemory(Id5, sizeof(Id5));
354 Offset = 0;
355 Offset = sprintf(&Id5[Offset], "USBSTOR\\");
356 Offset += sprintf(&Id5[Offset], GenericType);
357 Id5Length = strlen(Id5) + 1;
358 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId5 %s\n", Id5);
359
360 // generate id 6
361 // SCSIType
362 RtlZeroMemory(Id6, sizeof(Id6));
363 Offset = 0;
364 Offset = sprintf(&Id6[Offset], GenericType);
365 Id6Length = strlen(Id6) + 1;
366 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId6 %s\n", Id6);
367
368 TotalLength = Id1Length + Id2Length + Id3Length + Id4Length + Id5Length + Id6Length + 1;
369
370 Buffer = (LPWSTR)AllocateItem(PagedPool, TotalLength * sizeof(WCHAR));
371 if (!Buffer)
372 {
373 Irp->IoStatus.Information = 0;
374 return STATUS_INSUFFICIENT_RESOURCES;
375 }
376
377 // reset offset
378 Offset = 0;
379 Length = TotalLength;
380
381 USBSTOR_ConvertToUnicodeString(Id1, Length, Offset, Buffer, &Offset);
382 USBSTOR_ConvertToUnicodeString(Id2, Length, Offset, Buffer, &Offset);
383 USBSTOR_ConvertToUnicodeString(Id3, Length, Offset, Buffer, &Offset);
384 USBSTOR_ConvertToUnicodeString(Id4, Length, Offset, Buffer, &Offset);
385 USBSTOR_ConvertToUnicodeString(Id5, Length, Offset, Buffer, &Offset);
386 USBSTOR_ConvertToUnicodeString(Id6, Length, Offset, Buffer, &Offset);
387
388 ASSERT(Offset + 1 == Length);
389
390 Irp->IoStatus.Information = (ULONG_PTR)Buffer;
391 return STATUS_SUCCESS;
392 }
393
394 NTSTATUS
395 USBSTOR_PdoHandleQueryCompatibleId(
396 IN PDEVICE_OBJECT DeviceObject,
397 IN OUT PIRP Irp)
398 {
399 PPDO_DEVICE_EXTENSION PDODeviceExtension;
400 PFDO_DEVICE_EXTENSION FDODeviceExtension;
401 CHAR Buffer[100] = {0};
402 ULONG Length, Offset;
403 LPWSTR InstanceId;
404 LPCSTR DeviceType;
405
406 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
407 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
408 ASSERT(FDODeviceExtension->DeviceDescriptor);
409 DeviceType = USBSTOR_GetDeviceType(PDODeviceExtension->InquiryData, PDODeviceExtension->IsFloppy);
410
411 // format instance id
412 Length = sprintf(Buffer, "USBSTOR\\%s", DeviceType) + 1;
413 Length += sprintf(&Buffer[Length], "USBSTOR\\%s", "RAW") + 2;
414
415 InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
416 if (!InstanceId)
417 {
418 Irp->IoStatus.Information = 0;
419 return STATUS_INSUFFICIENT_RESOURCES;
420 }
421
422 USBSTOR_ConvertToUnicodeString(Buffer, Length, 0, InstanceId, &Offset);
423 USBSTOR_ConvertToUnicodeString(&Buffer[Offset], Length, Offset, InstanceId, &Offset);
424
425 DPRINT("USBSTOR_PdoHandleQueryCompatibleId %S\n", InstanceId);
426
427 Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
428 return STATUS_SUCCESS;
429 }
430
431 NTSTATUS
432 USBSTOR_PdoHandleQueryInstanceId(
433 IN PDEVICE_OBJECT DeviceObject,
434 IN OUT PIRP Irp)
435 {
436 PPDO_DEVICE_EXTENSION PDODeviceExtension;
437 PFDO_DEVICE_EXTENSION FDODeviceExtension;
438 WCHAR Buffer[100];
439 ULONG Length;
440 LPWSTR InstanceId;
441
442 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
443 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
444
445 // format instance id
446 if (FDODeviceExtension->SerialNumber)
447 {
448 // using serial number from device
449 swprintf(Buffer, L"%s&%c", FDODeviceExtension->SerialNumber->bString, PDODeviceExtension->LUN);
450 }
451 else
452 {
453 // use instance count and LUN
454 swprintf(Buffer, L"%04lu&%c", FDODeviceExtension->InstanceCount, PDODeviceExtension->LUN);
455 }
456
457 Length = wcslen(Buffer) + 1;
458
459 InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
460 if (!InstanceId)
461 {
462 Irp->IoStatus.Information = 0;
463 return STATUS_INSUFFICIENT_RESOURCES;
464 }
465
466 wcscpy(InstanceId, Buffer);
467
468 DPRINT("USBSTOR_PdoHandleQueryInstanceId %S\n", InstanceId);
469
470 Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
471 return STATUS_SUCCESS;
472 }
473
474 NTSTATUS
475 USBSTOR_PdoHandleDeviceRelations(
476 IN PDEVICE_OBJECT DeviceObject,
477 IN OUT PIRP Irp)
478 {
479 PDEVICE_RELATIONS DeviceRelations;
480 PIO_STACK_LOCATION IoStack;
481
482 DPRINT("USBSTOR_PdoHandleDeviceRelations\n");
483
484 IoStack = IoGetCurrentIrpStackLocation(Irp);
485
486 // check if relation type is BusRelations
487 if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
488 {
489 // PDO handles only target device relation
490 return Irp->IoStatus.Status;
491 }
492
493 DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
494 if (!DeviceRelations)
495 {
496 return STATUS_INSUFFICIENT_RESOURCES;
497 }
498
499 // initialize device relations
500 DeviceRelations->Count = 1;
501 DeviceRelations->Objects[0] = DeviceObject;
502 ObReferenceObject(DeviceObject);
503
504 Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
505 return STATUS_SUCCESS;
506 }
507
508 NTSTATUS
509 USBSTOR_PdoHandlePnp(
510 IN PDEVICE_OBJECT DeviceObject,
511 IN OUT PIRP Irp)
512 {
513 PIO_STACK_LOCATION IoStack;
514 PPDO_DEVICE_EXTENSION DeviceExtension;
515 NTSTATUS Status;
516 PDEVICE_CAPABILITIES Caps;
517 ULONG bDelete;
518
519 IoStack = IoGetCurrentIrpStackLocation(Irp);
520 DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
521 ASSERT(DeviceExtension->Common.IsFDO == FALSE);
522
523 switch(IoStack->MinorFunction)
524 {
525 case IRP_MN_QUERY_DEVICE_RELATIONS:
526 {
527 Status = USBSTOR_PdoHandleDeviceRelations(DeviceObject, Irp);
528 break;
529 }
530 case IRP_MN_QUERY_DEVICE_TEXT:
531 {
532 Status = USBSTOR_PdoHandleQueryDeviceText(DeviceObject, Irp);
533 break;
534 }
535 case IRP_MN_QUERY_ID:
536 {
537 if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
538 {
539 Status = USBSTOR_PdoHandleQueryDeviceId(DeviceObject, Irp);
540 break;
541 }
542 else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
543 {
544 Status = USBSTOR_PdoHandleQueryHardwareId(DeviceObject, Irp);
545 break;
546 }
547 else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
548 {
549 Status = USBSTOR_PdoHandleQueryInstanceId(DeviceObject, Irp);
550 break;
551 }
552 else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
553 {
554 Status = USBSTOR_PdoHandleQueryCompatibleId(DeviceObject, Irp);
555 break;
556 }
557
558 DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType);
559 Status = STATUS_NOT_SUPPORTED;
560 Irp->IoStatus.Information = 0;
561 break;
562 }
563 case IRP_MN_REMOVE_DEVICE:
564 {
565 DPRINT("IRP_MN_REMOVE_DEVICE\n");
566
567 if(*DeviceExtension->PDODeviceObject != NULL)
568 {
569 *DeviceExtension->PDODeviceObject = NULL;
570 bDelete = TRUE;
571 }
572 else
573 {
574 // device object already marked for deletion
575 bDelete = FALSE;
576 }
577
578 Irp->IoStatus.Status = STATUS_SUCCESS;
579 IoCompleteRequest(Irp, IO_NO_INCREMENT);
580
581 if (bDelete)
582 {
583 IoDeleteDevice(DeviceObject);
584 }
585 return STATUS_SUCCESS;
586 }
587 case IRP_MN_QUERY_CAPABILITIES:
588 {
589 // just forward irp to lower device
590 Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
591 ASSERT(Status == STATUS_SUCCESS);
592
593 if (NT_SUCCESS(Status))
594 {
595 // check if no unique id
596 Caps = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities;
597 Caps->UniqueID = FALSE; // no unique id is supported
598 Caps->Removable = TRUE; //FIXME
599 }
600 break;
601 }
602 case IRP_MN_QUERY_REMOVE_DEVICE:
603 case IRP_MN_QUERY_STOP_DEVICE:
604 {
605 #if 0
606 //
607 // if we're not claimed it's ok
608 //
609 if (DeviceExtension->Claimed)
610 #else
611 if (TRUE)
612 #endif
613 {
614 Status = STATUS_UNSUCCESSFUL;
615 DPRINT1("[USBSTOR] Request %x fails because device is still claimed\n", IoStack->MinorFunction);
616 }
617 else
618 Status = STATUS_SUCCESS;
619 break;
620 }
621 case IRP_MN_START_DEVICE:
622 {
623 // no-op for PDO
624 Status = STATUS_SUCCESS;
625 break;
626 }
627 case IRP_MN_SURPRISE_REMOVAL:
628 {
629 Status = STATUS_SUCCESS;
630 break;
631 }
632 default:
633 {
634 // do nothing
635 Status = Irp->IoStatus.Status;
636 }
637 }
638
639 if (Status != STATUS_PENDING)
640 {
641 Irp->IoStatus.Status = Status;
642 IoCompleteRequest(Irp, IO_NO_INCREMENT);
643 }
644
645 return Status;
646 }
647
648 NTSTATUS
649 NTAPI
650 USBSTOR_SyncCompletionRoutine(
651 IN PDEVICE_OBJECT DeviceObject,
652 IN PIRP Irp,
653 IN PVOID Ctx)
654 {
655 KeSetEvent((PKEVENT)Ctx, IO_NO_INCREMENT, FALSE);
656 return STATUS_MORE_PROCESSING_REQUIRED;
657 }
658
659 /*
660 * @name USBSTOR_SendInternalCdb
661 *
662 * Issues an internal SCSI request to device.
663 * The request is sent in a synchronous way.
664 */
665 static
666 NTSTATUS
667 USBSTOR_SendInternalCdb(
668 IN PDEVICE_OBJECT PdoDevice,
669 IN PCDB Cdb,
670 IN UCHAR CdbLength,
671 IN ULONG TimeOutValue,
672 OUT PVOID OutDataBuffer,
673 OUT PULONG OutDataTransferLength)
674 {
675 PSCSI_REQUEST_BLOCK Srb;
676 PSENSE_DATA SenseBuffer;
677 PIO_STACK_LOCATION IoStack;
678 KEVENT Event;
679 PIRP Irp = NULL;
680 PMDL Mdl = NULL;
681 ULONG ix = 0;
682 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
683 UCHAR SrbStatus;
684
685 DPRINT("USBSTOR_SendInternalCdb SCSIOP %x\n", Cdb->CDB6GENERIC.OperationCode);
686
687 Srb = ExAllocatePoolWithTag(NonPagedPool,
688 sizeof(SCSI_REQUEST_BLOCK),
689 USB_STOR_TAG);
690
691 if (Srb)
692 {
693 SenseBuffer = ExAllocatePoolWithTag(NonPagedPool,
694 SENSE_BUFFER_SIZE,
695 USB_STOR_TAG);
696
697 if (SenseBuffer)
698 {
699 Mdl = IoAllocateMdl(OutDataBuffer,
700 *OutDataTransferLength,
701 FALSE,
702 FALSE,
703 NULL);
704
705 if (!Mdl)
706 {
707 ExFreePoolWithTag(SenseBuffer, USB_STOR_TAG);
708 ExFreePoolWithTag(Srb, USB_STOR_TAG);
709 return Status;
710 }
711
712 MmBuildMdlForNonPagedPool(Mdl);
713
714 // make 3 attempts - the device may be in STALL state after the first one
715 do
716 {
717 Irp = IoAllocateIrp(PdoDevice->StackSize, FALSE);
718
719 if (!Irp)
720 {
721 break;
722 }
723
724 IoStack = IoGetNextIrpStackLocation(Irp);
725 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
726 IoStack->Parameters.Scsi.Srb = Srb;
727
728 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
729
730 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
731 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
732 Srb->CdbLength = CdbLength;
733 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
734 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_NO_QUEUE_FREEZE;
735 Srb->DataTransferLength = *OutDataTransferLength;
736 Srb->TimeOutValue = TimeOutValue;
737 Srb->DataBuffer = OutDataBuffer;
738 Srb->SenseInfoBuffer = SenseBuffer;
739
740 RtlCopyMemory(Srb->Cdb, Cdb, CdbLength);
741
742 Irp->MdlAddress = Mdl;
743
744 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
745
746 IoSetCompletionRoutine(Irp,
747 USBSTOR_SyncCompletionRoutine,
748 &Event,
749 TRUE,
750 TRUE,
751 TRUE);
752
753 if (IoCallDriver(PdoDevice, Irp) == STATUS_PENDING)
754 {
755 KeWaitForSingleObject(&Event,
756 Executive,
757 KernelMode,
758 FALSE,
759 NULL);
760 }
761
762 SrbStatus = SRB_STATUS(Srb->SrbStatus);
763
764 IoFreeIrp(Irp);
765 Irp = NULL;
766
767 if (SrbStatus == SRB_STATUS_SUCCESS ||
768 SrbStatus == SRB_STATUS_DATA_OVERRUN)
769 {
770 Status = STATUS_SUCCESS;
771 *OutDataTransferLength = Srb->DataTransferLength;
772 break;
773 }
774
775 Status = STATUS_UNSUCCESSFUL;
776
777 ++ix;
778 } while (ix < 3);
779
780 if (Mdl)
781 {
782 IoFreeMdl(Mdl);
783 }
784
785 ExFreePoolWithTag(SenseBuffer, USB_STOR_TAG);
786 }
787
788 ExFreePoolWithTag(Srb, USB_STOR_TAG);
789 }
790
791 return Status;
792 }
793
794 /*
795 * @name USBSTOR_FillInquiryData
796 *
797 * Sends a SCSI Inquiry request and fills in the PDODeviceExtension->InquiryData field with a result.
798 */
799 static
800 NTSTATUS
801 USBSTOR_FillInquiryData(
802 IN PDEVICE_OBJECT PDODeviceObject)
803 {
804 NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
805 PPDO_DEVICE_EXTENSION PDODeviceExtension;
806 CDB Cdb;
807 ULONG DataTransferLength = INQUIRYDATABUFFERSIZE;
808 PINQUIRYDATA InquiryData;
809
810 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
811 InquiryData = ExAllocatePoolWithTag(NonPagedPool, INQUIRYDATABUFFERSIZE, USB_STOR_TAG);
812
813 if (!InquiryData)
814 {
815 DPRINT1("USBSTOR_FillInquiryData failed with %x\n", Status);
816 return Status;
817 }
818
819 RtlZeroMemory(&Cdb, sizeof(Cdb));
820 Cdb.CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
821 Cdb.CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
822
823 Status = USBSTOR_SendInternalCdb(PDODeviceObject, &Cdb, CDB6GENERIC_LENGTH, 20, InquiryData, &DataTransferLength);
824
825 if (!NT_SUCCESS(Status))
826 {
827 DPRINT1("USBSTOR_FillInquiryData failed with %x\n", Status);
828 ExFreePoolWithTag(InquiryData, USB_STOR_TAG);
829 return Status;
830 }
831
832 DPRINT("DeviceType %x\n", InquiryData->DeviceType);
833 DPRINT("DeviceTypeModifier %x\n", InquiryData->DeviceTypeModifier);
834 DPRINT("RemovableMedia %x\n", InquiryData->RemovableMedia);
835 DPRINT("Version %x\n", InquiryData->Versions);
836 DPRINT("Format %x\n", InquiryData->ResponseDataFormat);
837 DPRINT("Length %x\n", InquiryData->AdditionalLength);
838 DPRINT("Reserved %p\n", InquiryData->Reserved);
839 DPRINT("VendorId %c%c%c%c%c%c%c%c\n", InquiryData->VendorId[0], InquiryData->VendorId[1], InquiryData->VendorId[2], InquiryData->VendorId[3], InquiryData->VendorId[4], InquiryData->VendorId[5], InquiryData->VendorId[6], InquiryData->VendorId[7]);
840 DPRINT("ProductId %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", InquiryData->ProductId[0], InquiryData->ProductId[1], InquiryData->ProductId[2], InquiryData->ProductId[3],
841 InquiryData->ProductId[4], InquiryData->ProductId[5], InquiryData->ProductId[6], InquiryData->ProductId[7],
842 InquiryData->ProductId[8], InquiryData->ProductId[9], InquiryData->ProductId[10], InquiryData->ProductId[11],
843 InquiryData->ProductId[12], InquiryData->ProductId[13], InquiryData->ProductId[14], InquiryData->ProductId[15]);
844
845 DPRINT("Revision %c%c%c%c\n", InquiryData->ProductRevisionLevel[0], InquiryData->ProductRevisionLevel[1], InquiryData->ProductRevisionLevel[2], InquiryData->ProductRevisionLevel[3]);
846
847 PDODeviceExtension->InquiryData = InquiryData;
848 return Status;
849 }
850
851 NTSTATUS
852 USBSTOR_CreatePDO(
853 IN PDEVICE_OBJECT DeviceObject,
854 IN UCHAR LUN)
855 {
856 PDEVICE_OBJECT PDO;
857 NTSTATUS Status;
858 PPDO_DEVICE_EXTENSION PDODeviceExtension;
859 PFDO_DEVICE_EXTENSION FDODeviceExtension;
860
861 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
862
863 // create child device object
864 Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO);
865 if (!NT_SUCCESS(Status))
866 {
867 DPRINT1("Failed to create PDO, status %x\n", Status);
868 return Status;
869 }
870
871 // patch the stack size
872 PDO->StackSize = DeviceObject->StackSize;
873
874 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension;
875
876 // initialize device extension
877 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
878 PDODeviceExtension->Common.IsFDO = FALSE;
879 PDODeviceExtension->LowerDeviceObject = DeviceObject;
880 PDODeviceExtension->PDODeviceObject = &FDODeviceExtension->ChildPDO[LUN];
881 PDODeviceExtension->Self = PDO;
882 PDODeviceExtension->LUN = LUN;
883
884 PDO->Flags |= DO_DIRECT_IO;
885
886 // device is initialized
887 PDO->Flags &= ~DO_DEVICE_INITIALIZING;
888
889 // output device object
890 FDODeviceExtension->ChildPDO[LUN] = PDO;
891
892 // send inquiry command by irp
893 Status = USBSTOR_FillInquiryData(PDO);
894
895 if (!NT_SUCCESS(Status))
896 {
897 return Status;
898 }
899
900 if (PDODeviceExtension->InquiryData->DeviceType == DIRECT_ACCESS_DEVICE || PDODeviceExtension->InquiryData->DeviceType == READ_ONLY_DIRECT_ACCESS_DEVICE)
901 {
902 PDODeviceExtension->IsFloppy = FALSE; // TODO: implement the actual check
903 }
904 else
905 {
906 // we work only with DIRECT_ACCESS_DEVICE for now
907 return STATUS_NOT_SUPPORTED;
908 }
909
910 return Status;
911 }