xref: /reactos/drivers/usb/usbstor/pdo.c (revision 40462c92)
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     WCHAR Buffer[100];
441     ULONG Length;
442     LPWSTR InstanceId;
443 
444     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
445     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
446 
447     // format instance id
448     if (FDODeviceExtension->SerialNumber)
449     {
450         // using serial number from device
451         swprintf(Buffer, L"%s&%c", FDODeviceExtension->SerialNumber->bString, PDODeviceExtension->LUN);
452     }
453     else
454     {
455         // use instance count and LUN
456         swprintf(Buffer, L"%04lu&%c", FDODeviceExtension->InstanceCount, PDODeviceExtension->LUN);
457     }
458 
459     Length = wcslen(Buffer) + 1;
460 
461     InstanceId = ExAllocatePoolWithTag(PagedPool, Length * sizeof(WCHAR), USB_STOR_TAG);
462     if (!InstanceId)
463     {
464         Irp->IoStatus.Information = 0;
465         return STATUS_INSUFFICIENT_RESOURCES;
466     }
467 
468     wcscpy(InstanceId, Buffer);
469 
470     DPRINT("USBSTOR_PdoHandleQueryInstanceId %S\n", InstanceId);
471 
472     Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
473     return STATUS_SUCCESS;
474 }
475 
476 NTSTATUS
477 USBSTOR_PdoHandleDeviceRelations(
478     IN PDEVICE_OBJECT DeviceObject,
479     IN OUT PIRP Irp)
480 {
481     PDEVICE_RELATIONS DeviceRelations;
482     PIO_STACK_LOCATION IoStack;
483 
484     DPRINT("USBSTOR_PdoHandleDeviceRelations\n");
485 
486     IoStack = IoGetCurrentIrpStackLocation(Irp);
487 
488     // check if relation type is BusRelations
489     if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
490     {
491         // PDO handles only target device relation
492         return Irp->IoStatus.Status;
493     }
494 
495     DeviceRelations = ExAllocatePoolWithTag(PagedPool, sizeof(DEVICE_RELATIONS), USB_STOR_TAG);
496     if (!DeviceRelations)
497     {
498         return STATUS_INSUFFICIENT_RESOURCES;
499     }
500 
501     // initialize device relations
502     DeviceRelations->Count = 1;
503     DeviceRelations->Objects[0] = DeviceObject;
504     ObReferenceObject(DeviceObject);
505 
506     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
507     return STATUS_SUCCESS;
508 }
509 
510 NTSTATUS
511 USBSTOR_PdoHandlePnp(
512     IN PDEVICE_OBJECT DeviceObject,
513     IN OUT PIRP Irp)
514 {
515     PIO_STACK_LOCATION IoStack;
516     PPDO_DEVICE_EXTENSION DeviceExtension;
517     NTSTATUS Status;
518     PDEVICE_CAPABILITIES Caps;
519     ULONG bDelete;
520 
521     IoStack = IoGetCurrentIrpStackLocation(Irp);
522     DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
523     ASSERT(DeviceExtension->Common.IsFDO == FALSE);
524 
525     switch(IoStack->MinorFunction)
526     {
527        case IRP_MN_QUERY_DEVICE_RELATIONS:
528        {
529            Status = USBSTOR_PdoHandleDeviceRelations(DeviceObject, Irp);
530            break;
531        }
532        case IRP_MN_QUERY_DEVICE_TEXT:
533        {
534            Status = USBSTOR_PdoHandleQueryDeviceText(DeviceObject, Irp);
535            break;
536        }
537        case IRP_MN_QUERY_ID:
538        {
539            if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
540            {
541                Status = USBSTOR_PdoHandleQueryDeviceId(DeviceObject, Irp);
542                break;
543            }
544            else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
545            {
546                Status = USBSTOR_PdoHandleQueryHardwareId(DeviceObject, Irp);
547                break;
548            }
549            else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
550            {
551                Status = USBSTOR_PdoHandleQueryInstanceId(DeviceObject, Irp);
552                break;
553            }
554            else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
555            {
556                Status = USBSTOR_PdoHandleQueryCompatibleId(DeviceObject, Irp);
557                break;
558            }
559 
560            DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType);
561            Status = STATUS_NOT_SUPPORTED;
562            Irp->IoStatus.Information = 0;
563            break;
564        }
565        case IRP_MN_REMOVE_DEVICE:
566        {
567            DPRINT("IRP_MN_REMOVE_DEVICE\n");
568 
569            if(*DeviceExtension->PDODeviceObject != NULL)
570            {
571                *DeviceExtension->PDODeviceObject = NULL;
572                bDelete = TRUE;
573            }
574            else
575            {
576                // device object already marked for deletion
577                bDelete = FALSE;
578            }
579 
580            Irp->IoStatus.Status = STATUS_SUCCESS;
581            IoCompleteRequest(Irp, IO_NO_INCREMENT);
582 
583            if (bDelete)
584            {
585                IoDeleteDevice(DeviceObject);
586            }
587            return STATUS_SUCCESS;
588        }
589        case IRP_MN_QUERY_CAPABILITIES:
590        {
591            // just forward irp to lower device
592            Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
593            ASSERT(Status == STATUS_SUCCESS);
594 
595            if (NT_SUCCESS(Status))
596            {
597                // check if no unique id
598                Caps = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities;
599                Caps->UniqueID = FALSE; // no unique id is supported
600                Caps->Removable = TRUE; //FIXME
601            }
602            break;
603        }
604        case IRP_MN_QUERY_REMOVE_DEVICE:
605        case IRP_MN_QUERY_STOP_DEVICE:
606        {
607 #if 0
608            //
609            // if we're not claimed it's ok
610            //
611            if (DeviceExtension->Claimed)
612 #else
613            if (TRUE)
614 #endif
615            {
616                Status = STATUS_UNSUCCESSFUL;
617                DPRINT1("[USBSTOR] Request %x fails because device is still claimed\n", IoStack->MinorFunction);
618            }
619            else
620                Status = STATUS_SUCCESS;
621            break;
622        }
623        case IRP_MN_START_DEVICE:
624        {
625            // no-op for PDO
626            Status = STATUS_SUCCESS;
627            break;
628        }
629        case IRP_MN_SURPRISE_REMOVAL:
630        {
631            Status = STATUS_SUCCESS;
632            break;
633        }
634        default:
635         {
636             // do nothing
637             Status = Irp->IoStatus.Status;
638         }
639     }
640 
641     if (Status != STATUS_PENDING)
642     {
643         Irp->IoStatus.Status = Status;
644         IoCompleteRequest(Irp, IO_NO_INCREMENT);
645     }
646 
647     return Status;
648 }
649 
650 NTSTATUS
651 NTAPI
652 USBSTOR_SyncCompletionRoutine(
653     IN PDEVICE_OBJECT DeviceObject,
654     IN PIRP Irp,
655     IN PVOID Ctx)
656 {
657     KeSetEvent((PKEVENT)Ctx, IO_NO_INCREMENT, FALSE);
658     return STATUS_MORE_PROCESSING_REQUIRED;
659 }
660 
661 /*
662 * @name USBSTOR_SendInternalCdb
663 *
664 * Issues an internal SCSI request to device.
665 * The request is sent in a synchronous way.
666 */
667 static
668 NTSTATUS
669 USBSTOR_SendInternalCdb(
670     IN PDEVICE_OBJECT PdoDevice,
671     IN PCDB Cdb,
672     IN UCHAR CdbLength,
673     IN ULONG TimeOutValue,
674     OUT PVOID OutDataBuffer,
675     OUT PULONG OutDataTransferLength)
676 {
677     PSCSI_REQUEST_BLOCK Srb;
678     PSENSE_DATA SenseBuffer;
679     PIO_STACK_LOCATION IoStack;
680     KEVENT Event;
681     PIRP Irp = NULL;
682     PMDL Mdl = NULL;
683     ULONG ix = 0;
684     NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
685     UCHAR SrbStatus;
686 
687     DPRINT("USBSTOR_SendInternalCdb SCSIOP %x\n", Cdb->CDB6GENERIC.OperationCode);
688 
689     Srb = ExAllocatePoolWithTag(NonPagedPool,
690                                 sizeof(SCSI_REQUEST_BLOCK),
691                                 USB_STOR_TAG);
692 
693     if (Srb)
694     {
695         SenseBuffer = ExAllocatePoolWithTag(NonPagedPool,
696                                             SENSE_BUFFER_SIZE,
697                                             USB_STOR_TAG);
698 
699         if (SenseBuffer)
700         {
701             Mdl = IoAllocateMdl(OutDataBuffer,
702                     *OutDataTransferLength,
703                     FALSE,
704                     FALSE,
705                     NULL);
706 
707             if (!Mdl)
708             {
709                 ExFreePoolWithTag(SenseBuffer, USB_STOR_TAG);
710                 ExFreePoolWithTag(Srb, USB_STOR_TAG);
711                 return Status;
712             }
713 
714             MmBuildMdlForNonPagedPool(Mdl);
715 
716             // make 3 attempts - the device may be in STALL state after the first one
717             do
718             {
719                 Irp = IoAllocateIrp(PdoDevice->StackSize, FALSE);
720 
721                 if (!Irp)
722                 {
723                     break;
724                 }
725 
726                 IoStack = IoGetNextIrpStackLocation(Irp);
727                 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
728                 IoStack->Parameters.Scsi.Srb = Srb;
729 
730                 RtlZeroMemory(Srb, sizeof(SCSI_REQUEST_BLOCK));
731 
732                 Srb->Length = sizeof(SCSI_REQUEST_BLOCK);
733                 Srb->Function = SRB_FUNCTION_EXECUTE_SCSI;
734                 Srb->CdbLength = CdbLength;
735                 Srb->SenseInfoBufferLength = SENSE_BUFFER_SIZE;
736                 Srb->SrbFlags = SRB_FLAGS_DATA_IN | SRB_FLAGS_NO_QUEUE_FREEZE;
737                 Srb->DataTransferLength = *OutDataTransferLength;
738                 Srb->TimeOutValue = TimeOutValue;
739                 Srb->DataBuffer = OutDataBuffer;
740                 Srb->SenseInfoBuffer = SenseBuffer;
741 
742                 RtlCopyMemory(Srb->Cdb, Cdb, CdbLength);
743 
744                 Irp->MdlAddress = Mdl;
745 
746                 KeInitializeEvent(&Event, SynchronizationEvent, FALSE);
747 
748                 IoSetCompletionRoutine(Irp,
749                                        USBSTOR_SyncCompletionRoutine,
750                                        &Event,
751                                        TRUE,
752                                        TRUE,
753                                        TRUE);
754 
755                 if (IoCallDriver(PdoDevice, Irp) == STATUS_PENDING)
756                 {
757                     KeWaitForSingleObject(&Event,
758                                           Executive,
759                                           KernelMode,
760                                           FALSE,
761                                           NULL);
762                 }
763 
764                 SrbStatus = SRB_STATUS(Srb->SrbStatus);
765 
766                 IoFreeIrp(Irp);
767                 Irp = NULL;
768 
769                 if (SrbStatus == SRB_STATUS_SUCCESS ||
770                      SrbStatus == SRB_STATUS_DATA_OVERRUN)
771                 {
772                     Status = STATUS_SUCCESS;
773                     *OutDataTransferLength = Srb->DataTransferLength;
774                     break;
775                 }
776 
777                 Status = STATUS_UNSUCCESSFUL;
778 
779                 ++ix;
780             } while (ix < 3);
781 
782             if (Mdl)
783             {
784                 IoFreeMdl(Mdl);
785             }
786 
787             ExFreePoolWithTag(SenseBuffer, USB_STOR_TAG);
788         }
789 
790         ExFreePoolWithTag(Srb, USB_STOR_TAG);
791     }
792 
793     return Status;
794 }
795 
796 /*
797 * @name USBSTOR_FillInquiryData
798 *
799 * Sends a SCSI Inquiry request and fills in the PDODeviceExtension->InquiryData field with a result.
800 */
801 static
802 NTSTATUS
803 USBSTOR_FillInquiryData(
804     IN PDEVICE_OBJECT PDODeviceObject)
805 {
806     NTSTATUS Status = STATUS_INSUFFICIENT_RESOURCES;
807     PPDO_DEVICE_EXTENSION PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
808     CDB Cdb;
809     ULONG DataTransferLength = INQUIRYDATABUFFERSIZE;
810     PINQUIRYDATA InquiryData = (PINQUIRYDATA)&PDODeviceExtension->InquiryData;
811 
812     RtlZeroMemory(&Cdb, sizeof(Cdb));
813     Cdb.CDB6INQUIRY.OperationCode = SCSIOP_INQUIRY;
814     Cdb.CDB6INQUIRY.AllocationLength = INQUIRYDATABUFFERSIZE;
815 
816     Status = USBSTOR_SendInternalCdb(PDODeviceObject, &Cdb, CDB6GENERIC_LENGTH, 20, InquiryData, &DataTransferLength);
817 
818     if (!NT_SUCCESS(Status))
819     {
820         DPRINT1("USBSTOR_FillInquiryData failed with %x\n", Status);
821         return Status;
822     }
823 
824     DPRINT("DeviceType %x\n", InquiryData->DeviceType);
825     DPRINT("DeviceTypeModifier %x\n", InquiryData->DeviceTypeModifier);
826     DPRINT("RemovableMedia %x\n", InquiryData->RemovableMedia);
827     DPRINT("Version %x\n", InquiryData->Versions);
828     DPRINT("Format %x\n", InquiryData->ResponseDataFormat);
829     DPRINT("Length %x\n", InquiryData->AdditionalLength);
830     DPRINT("Reserved %p\n", InquiryData->Reserved);
831     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]);
832     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],
833                                                            InquiryData->ProductId[4], InquiryData->ProductId[5], InquiryData->ProductId[6], InquiryData->ProductId[7],
834                                                            InquiryData->ProductId[8], InquiryData->ProductId[9], InquiryData->ProductId[10], InquiryData->ProductId[11],
835                                                            InquiryData->ProductId[12], InquiryData->ProductId[13], InquiryData->ProductId[14], InquiryData->ProductId[15]);
836 
837     DPRINT("Revision %c%c%c%c\n", InquiryData->ProductRevisionLevel[0], InquiryData->ProductRevisionLevel[1], InquiryData->ProductRevisionLevel[2], InquiryData->ProductRevisionLevel[3]);
838 
839     return Status;
840 }
841 
842 NTSTATUS
843 USBSTOR_CreatePDO(
844     IN PDEVICE_OBJECT DeviceObject,
845     IN UCHAR LUN)
846 {
847     PDEVICE_OBJECT PDO;
848     NTSTATUS Status;
849     PPDO_DEVICE_EXTENSION PDODeviceExtension;
850     PFDO_DEVICE_EXTENSION FDODeviceExtension;
851     PINQUIRYDATA InquiryData;
852 
853     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
854 
855     // create child device object
856     Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO);
857     if (!NT_SUCCESS(Status))
858     {
859         DPRINT1("Failed to create PDO, status %x\n", Status);
860         return Status;
861     }
862 
863     // patch the stack size
864     PDO->StackSize = DeviceObject->StackSize;
865 
866     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension;
867     InquiryData = (PINQUIRYDATA)&PDODeviceExtension->InquiryData;
868 
869     // initialize device extension
870     RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
871     PDODeviceExtension->Common.IsFDO = FALSE;
872     PDODeviceExtension->LowerDeviceObject = DeviceObject;
873     PDODeviceExtension->PDODeviceObject = &FDODeviceExtension->ChildPDO[LUN];
874     PDODeviceExtension->Self = PDO;
875     PDODeviceExtension->LUN = LUN;
876 
877     PDO->Flags |= DO_DIRECT_IO;
878 
879     // device is initialized
880     PDO->Flags &= ~DO_DEVICE_INITIALIZING;
881 
882     // output device object
883     FDODeviceExtension->ChildPDO[LUN] = PDO;
884 
885     // send inquiry command by irp
886     Status = USBSTOR_FillInquiryData(PDO);
887 
888     if (!NT_SUCCESS(Status))
889     {
890         return Status;
891     }
892 
893     if (InquiryData->DeviceType != DIRECT_ACCESS_DEVICE &&
894         InquiryData->DeviceType != READ_ONLY_DIRECT_ACCESS_DEVICE)
895     {
896         return STATUS_NOT_SUPPORTED;
897     }
898 
899     return Status;
900 }
901