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