xref: /reactos/drivers/usb/usbstor_new/pdo.c (revision 1734f297)
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/pdo.c
5  * PURPOSE:     USB block storage device driver.
6  * PROGRAMMERS:
7  *              James Tabor
8  *              Michael Martin (michael.martin@reactos.org)
9  *              Johannes Anderwald (johannes.anderwald@reactos.org)
10  */
11 
12 #include "usbstor.h"
13 
14 #define NDEBUG
15 #include <debug.h>
16 
17 LPCSTR
18 USBSTOR_GetDeviceType(
19     IN PUFI_INQUIRY_RESPONSE InquiryData,
20     IN UCHAR IsFloppy)
21 {
22     //
23     // check if device type is zero
24     //
25     if (InquiryData->DeviceType == 0)
26     {
27         if (IsFloppy)
28         {
29             //
30             // floppy device
31             //
32             return "SFloppy";
33         }
34 
35         //
36         // direct access device
37         //
38         return "Disk";
39     }
40 
41     //
42     // FIXME: use constant - derived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
43     //
44     switch (InquiryData->DeviceType)
45     {
46         case 1:
47         {
48             //
49             // sequential device, i.e magnetic tape
50             //
51             return "Sequential";
52         }
53         case 4:
54         {
55             //
56             // write once device
57             //
58             return "Worm";
59         }
60         case 5:
61         {
62             //
63             // CDROM device
64             //
65             return "CdRom";
66         }
67         case 7:
68         {
69             //
70             // optical memory device
71             //
72             return "Optical";
73         }
74         case 8:
75         {
76             //
77             // medium change device
78             //
79             return "Changer";
80         }
81         default:
82         {
83             //
84             // other device
85             //
86             return "Other";
87         }
88     }
89 }
90 
91 LPCSTR
92 USBSTOR_GetGenericType(
93     IN PUFI_INQUIRY_RESPONSE InquiryData,
94     IN UCHAR IsFloppy)
95 {
96     //
97     // check if device type is zero
98     //
99     if (InquiryData->DeviceType == 0)
100     {
101         if (IsFloppy)
102         {
103             //
104             // floppy device
105             //
106             return "GenSFloppy";
107         }
108 
109         //
110         // direct access device
111         //
112         return "GenDisk";
113     }
114 
115     //
116     // FIXME: use constant - derived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
117     //
118     switch (InquiryData->DeviceType)
119     {
120         case 1:
121         {
122             //
123             // sequential device, i.e magnetic tape
124             //
125             return "GenSequential";
126         }
127         case 4:
128         {
129             //
130             // write once device
131             //
132             return "GenWorm";
133         }
134         case 5:
135         {
136             //
137             // CDROM device
138             //
139             return "GenCdRom";
140         }
141         case 7:
142         {
143             //
144             // optical memory device
145             //
146             return "GenOptical";
147         }
148         case 8:
149         {
150             //
151             // medium change device
152             //
153             return "GenChanger";
154         }
155         default:
156         {
157             //
158             // other device
159             //
160             return "UsbstorOther";
161         }
162     }
163 }
164 
165 
166 ULONG
167 CopyField(
168     IN PUCHAR Name,
169     IN PCHAR Buffer,
170     IN ULONG MaxLength)
171 {
172     ULONG Index;
173 
174     for(Index = 0; Index < MaxLength; Index++)
175     {
176         if (Name[Index] <= ' ' || Name[Index] >= 0x7F /* last printable ascii character */ ||  Name[Index] == ',')
177         {
178             //
179             // convert to underscore
180             //
181             Buffer[Index] = '_';
182         }
183         else
184         {
185             //
186             // just copy character
187             //
188             Buffer[Index] = Name[Index];
189         }
190     }
191 
192     return MaxLength;
193 }
194 
195 NTSTATUS
196 USBSTOR_PdoHandleQueryDeviceText(
197     IN PDEVICE_OBJECT DeviceObject,
198     IN PIRP Irp)
199 {
200     //PPDO_DEVICE_EXTENSION DeviceExtension;
201     PIO_STACK_LOCATION IoStack;
202     LPWSTR Buffer;
203     static WCHAR DeviceText[] = L"USB Mass Storage Device";
204 
205     //
206     // get current stack location
207     //
208     IoStack = IoGetCurrentIrpStackLocation(Irp);
209 
210     if (IoStack->Parameters.QueryDeviceText.DeviceTextType == DeviceTextDescription)
211     {
212         DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextDescription\n");
213 
214         //
215         // allocate item
216         //
217         Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
218         if (!Buffer)
219         {
220             //
221             // no memory
222             //
223             Irp->IoStatus.Information = 0;
224             return STATUS_INSUFFICIENT_RESOURCES;
225         }
226 
227         //
228         // copy buffer
229         //
230         wcscpy(Buffer, DeviceText);
231 
232         //
233         // save result
234         //
235         Irp->IoStatus.Information = (ULONG_PTR)Buffer;
236         return STATUS_SUCCESS;
237     }
238     else
239     {
240         DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextLocationInformation\n");
241 
242         //
243         // allocate item
244         //
245         Buffer = (LPWSTR)AllocateItem(PagedPool, sizeof(DeviceText));
246         if (!Buffer)
247         {
248             //
249             // no memory
250             //
251             Irp->IoStatus.Information = 0;
252             return STATUS_INSUFFICIENT_RESOURCES;
253         }
254 
255         //
256         // copy buffer
257         //
258         wcscpy(Buffer, DeviceText);
259 
260         //
261         // save result
262         //
263         Irp->IoStatus.Information = (ULONG_PTR)Buffer;
264         return STATUS_SUCCESS;
265     }
266 
267 }
268 
269 
270 NTSTATUS
271 USBSTOR_PdoHandleQueryDeviceId(
272     IN PDEVICE_OBJECT DeviceObject,
273     IN PIRP Irp)
274 {
275     PPDO_DEVICE_EXTENSION DeviceExtension;
276     NTSTATUS Status;
277     CHAR Buffer[100];
278     LPCSTR DeviceType;
279     ULONG Offset = 0;
280     PUFI_INQUIRY_RESPONSE InquiryData;
281     ANSI_STRING AnsiString;
282     UNICODE_STRING DeviceId;
283 
284     //
285     // get device extension
286     //
287     DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
288 
289     //
290     // sanity check
291     //
292     ASSERT(DeviceExtension->InquiryData);
293 
294     //
295     // get inquiry data
296     //
297     InquiryData = (PUFI_INQUIRY_RESPONSE)DeviceExtension->InquiryData;
298 
299     //
300     // get device type
301     //
302     DeviceType = USBSTOR_GetDeviceType(InquiryData, DeviceExtension->IsFloppy);
303 
304     //
305     // zero buffer
306     //
307     RtlZeroMemory(Buffer, sizeof(Buffer));
308 
309     //
310     // lets create device string
311     //
312     Offset = sprintf(&Buffer[Offset], "USBSTOR\\");
313     Offset += sprintf(&Buffer[Offset], DeviceType);
314     Offset += sprintf(&Buffer[Offset], "&Ven_");
315     Offset += CopyField(InquiryData->Vendor, &Buffer[Offset], 8);
316     Offset += sprintf(&Buffer[Offset], "&Prod_");
317     Offset += CopyField(InquiryData->Product, &Buffer[Offset], 16);
318     Offset += sprintf(&Buffer[Offset], "&Rev_");
319     Offset += CopyField(InquiryData->Revision, &Buffer[Offset], 4);
320 
321     //
322     // now initialize ansi string
323     //
324     RtlInitAnsiString(&AnsiString, (PCSZ)Buffer);
325 
326     //
327     // allocate DeviceId string
328     //
329     DeviceId.Length = 0;
330     DeviceId.MaximumLength = (strlen((PCHAR)Buffer) + 1) * sizeof(WCHAR);
331     DeviceId.Buffer = (LPWSTR)AllocateItem(PagedPool, DeviceId.MaximumLength);
332     if (!DeviceId.Buffer)
333     {
334         //
335         // no memory
336         //
337         Irp->IoStatus.Information = 0;
338         return STATUS_INSUFFICIENT_RESOURCES;
339     }
340 
341 
342     //
343     // convert to unicode
344     //
345     Status = RtlAnsiStringToUnicodeString(&DeviceId, &AnsiString, FALSE);
346 
347     if (NT_SUCCESS(Status))
348     {
349         //
350         // store result
351         //
352         Irp->IoStatus.Information = (ULONG_PTR)DeviceId.Buffer;
353     }
354 
355     DPRINT("DeviceId %wZ Status %x\n", &DeviceId, Status);
356 
357     //
358     // done
359     //
360     return Status;
361 }
362 
363 VOID
364 USBSTOR_ConvertToUnicodeString(
365     IN CHAR * Buffer,
366     IN ULONG ResultBufferLength,
367     IN ULONG ResultBufferOffset,
368     OUT LPWSTR ResultBuffer,
369     OUT PULONG NewResultBufferOffset)
370 {
371     UNICODE_STRING DeviceString;
372     ANSI_STRING AnsiString;
373     NTSTATUS Status;
374 
375     ASSERT(ResultBufferLength);
376     ASSERT(ResultBufferLength > ResultBufferOffset);
377 
378     DPRINT("ResultBufferOffset %lu ResultBufferLength %lu Buffer %s Length %lu\n", ResultBufferOffset, ResultBufferLength, Buffer, strlen(Buffer));
379 
380     //
381     // construct destination string
382     //
383     DeviceString.Buffer = &ResultBuffer[ResultBufferOffset];
384     DeviceString.Length = 0;
385     DeviceString.MaximumLength = (ResultBufferLength - ResultBufferOffset) * sizeof(WCHAR);
386 
387     //
388     // initialize source string
389     //
390     RtlInitAnsiString(&AnsiString, Buffer);
391 
392     //
393     // convert to unicode
394     //
395     Status = RtlAnsiStringToUnicodeString(&DeviceString, &AnsiString, FALSE);
396     ASSERT(Status == STATUS_SUCCESS);
397 
398     //
399     // subtract consumed bytes
400     //
401     ResultBufferLength -= (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
402     ResultBufferOffset += (DeviceString.Length + sizeof(WCHAR)) / sizeof(WCHAR);
403 
404     //
405     // store new offset
406     //
407     *NewResultBufferOffset = ResultBufferOffset;
408 }
409 
410 
411 
412 NTSTATUS
413 USBSTOR_PdoHandleQueryHardwareId(
414     IN PDEVICE_OBJECT DeviceObject,
415     IN OUT PIRP Irp)
416 {
417     PPDO_DEVICE_EXTENSION PDODeviceExtension;
418     PFDO_DEVICE_EXTENSION FDODeviceExtension;
419     LPCSTR GenericType, DeviceType;
420     LPWSTR Buffer;
421     CHAR Id1[50], Id2[50], Id3[50], Id4[50], Id5[50], Id6[50];
422     ULONG Id1Length, Id2Length, Id3Length, Id4Length, Id5Length,Id6Length;
423     ULONG Offset, TotalLength, Length;
424     PUFI_INQUIRY_RESPONSE InquiryData;
425 
426     //
427     // get PDO device extension
428     //
429     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
430 
431     //
432     // get FDO device extension
433     //
434     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
435 
436     //
437     // sanity check
438     //
439     ASSERT(FDODeviceExtension->DeviceDescriptor);
440 
441     //
442     // get inquiry data
443     //
444     InquiryData = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
445 
446 
447     //
448     // get device type and generic type
449     //
450     DeviceType = USBSTOR_GetDeviceType(InquiryData, PDODeviceExtension->IsFloppy);
451     GenericType = USBSTOR_GetGenericType(InquiryData, PDODeviceExtension->IsFloppy);
452 
453     ASSERT(GenericType);
454 
455     //
456     // generate id 1
457     // USBSTOR\SCSIType_Vendor(8)_Product(16)_Revision(4)
458     //
459     RtlZeroMemory(Id1, sizeof(Id1));
460     Offset = 0;
461     Offset = sprintf(&Id1[Offset], "USBSTOR\\");
462     Offset += sprintf(&Id1[Offset], DeviceType);
463     Offset += CopyField(InquiryData->Vendor, &Id1[Offset], 8);
464     Offset += CopyField(InquiryData->Product, &Id1[Offset], 16);
465     Offset += CopyField(InquiryData->Revision, &Id1[Offset], 4);
466     Id1Length = strlen(Id1) + 1;
467     DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId1 %s\n", Id1);
468 
469     //
470     // generate id 2
471     // USBSTOR\SCSIType_VENDOR(8)_Product(16)
472     //
473     RtlZeroMemory(Id2, sizeof(Id2));
474     Offset = 0;
475     Offset = sprintf(&Id2[Offset], "USBSTOR\\");
476     Offset += sprintf(&Id2[Offset], DeviceType);
477     Offset += CopyField(InquiryData->Vendor, &Id2[Offset], 8);
478     Offset += CopyField(InquiryData->Product, &Id2[Offset], 16);
479     Id2Length = strlen(Id2) + 1;
480     DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId2 %s\n", Id2);
481 
482     //
483     // generate id 3
484     // USBSTOR\SCSIType_VENDOR(8)
485     //
486     RtlZeroMemory(Id3, sizeof(Id3));
487     Offset = 0;
488     Offset = sprintf(&Id3[Offset], "USBSTOR\\");
489     Offset += sprintf(&Id3[Offset], DeviceType);
490     Offset += CopyField(InquiryData->Vendor, &Id3[Offset], 8);
491     Id3Length = strlen(Id3) + 1;
492     DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId3 %s\n", Id3);
493 
494     //
495     // generate id 4
496     // USBSTOR\SCSIType_VENDOR(8)_Product(16)_Revision(1)
497     //
498     RtlZeroMemory(Id4, sizeof(Id4));
499     Offset = 0;
500     Offset = sprintf(&Id4[Offset], "USBSTOR\\");
501     Offset += sprintf(&Id4[Offset], DeviceType);
502     Offset += CopyField(InquiryData->Vendor, &Id4[Offset], 8);
503     Offset += CopyField(InquiryData->Product, &Id4[Offset], 16);
504     Offset += CopyField(InquiryData->Revision, &Id4[Offset], 1);
505     Id4Length = strlen(Id4) + 1;
506     DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId4 %s\n", Id4);
507 
508     //
509     // generate id 5
510     // USBSTOR\SCSIType
511     //
512     RtlZeroMemory(Id5, sizeof(Id5));
513     Offset = 0;
514     Offset = sprintf(&Id5[Offset], "USBSTOR\\");
515     Offset += sprintf(&Id5[Offset], GenericType);
516     Id5Length = strlen(Id5) + 1;
517     DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId5 %s\n", Id5);
518 
519     //
520     // generate id 6
521     // SCSIType
522     //
523     RtlZeroMemory(Id6, sizeof(Id6));
524     Offset = 0;
525     Offset = sprintf(&Id6[Offset], GenericType);
526     Id6Length = strlen(Id6) + 1;
527     DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId6 %s\n", Id6);
528 
529     //
530     // compute total length
531     //
532     TotalLength = Id1Length + Id2Length + Id3Length + Id4Length + Id5Length + Id6Length + 1;
533 
534     //
535     // allocate buffer
536     //
537     Buffer = (LPWSTR)AllocateItem(PagedPool, TotalLength * sizeof(WCHAR));
538     if (!Buffer)
539     {
540         //
541         // no memory
542         //
543         Irp->IoStatus.Information = 0;
544         return STATUS_INSUFFICIENT_RESOURCES;
545     }
546 
547     //
548     // reset offset
549     //
550     Offset = 0;
551     Length = TotalLength;
552 
553     USBSTOR_ConvertToUnicodeString(Id1, Length, Offset, Buffer, &Offset);
554     USBSTOR_ConvertToUnicodeString(Id2, Length, Offset, Buffer, &Offset);
555     USBSTOR_ConvertToUnicodeString(Id3, Length, Offset, Buffer, &Offset);
556     USBSTOR_ConvertToUnicodeString(Id4, Length, Offset, Buffer, &Offset);
557     USBSTOR_ConvertToUnicodeString(Id5, Length, Offset, Buffer, &Offset);
558     USBSTOR_ConvertToUnicodeString(Id6, Length, Offset, Buffer, &Offset);
559 
560     //
561     // sanity check
562     //
563     ASSERT(Offset + 1 == Length);
564 
565     //
566     // store result
567     //
568     Irp->IoStatus.Information = (ULONG_PTR)Buffer;
569 
570     //
571     // done
572     //
573     return STATUS_SUCCESS;
574 }
575 
576 NTSTATUS
577 USBSTOR_PdoHandleQueryCompatibleId(
578     IN PDEVICE_OBJECT DeviceObject,
579     IN OUT PIRP Irp)
580 {
581     PPDO_DEVICE_EXTENSION PDODeviceExtension;
582     PFDO_DEVICE_EXTENSION FDODeviceExtension;
583     CHAR Buffer[100];
584     ULONG Length, Offset;
585     LPWSTR InstanceId;
586     LPCSTR DeviceType;
587 
588     //
589     // get PDO device extension
590     //
591     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
592 
593     //
594     // get FDO device extension
595     //
596     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
597 
598     //
599     // sanity check
600     //
601     ASSERT(FDODeviceExtension->DeviceDescriptor);
602 
603     //
604     // get target device type
605     //
606     DeviceType = USBSTOR_GetDeviceType((PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData, PDODeviceExtension->IsFloppy);
607 
608     //
609     // zero memory
610     //
611     RtlZeroMemory(Buffer, sizeof(Buffer));
612 
613     //
614     // format instance id
615     //
616     Length = sprintf(Buffer, "USBSTOR\\%s", DeviceType) + 1;
617     Length += sprintf(&Buffer[Length], "USBSTOR\\%s", "RAW") + 2;
618 
619     //
620     // allocate instance id
621     //
622     InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
623     if (!InstanceId)
624     {
625         //
626         // no memory
627         //
628         Irp->IoStatus.Information = 0;
629         return STATUS_INSUFFICIENT_RESOURCES;
630     }
631 
632     USBSTOR_ConvertToUnicodeString(Buffer, Length, 0, InstanceId, &Offset);
633     USBSTOR_ConvertToUnicodeString(&Buffer[Offset], Length, Offset, InstanceId, &Offset);
634 
635     DPRINT("USBSTOR_PdoHandleQueryCompatibleId %S\n", InstanceId);
636 
637     //
638     // store result
639     //
640     Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
641 
642     //
643     // completed successfully
644     //
645     return STATUS_SUCCESS;
646 }
647 
648 NTSTATUS
649 USBSTOR_PdoHandleQueryInstanceId(
650     IN PDEVICE_OBJECT DeviceObject,
651     IN OUT PIRP Irp)
652 {
653     PPDO_DEVICE_EXTENSION PDODeviceExtension;
654     PFDO_DEVICE_EXTENSION FDODeviceExtension;
655     WCHAR Buffer[100];
656     ULONG Length;
657     LPWSTR InstanceId;
658 
659     //
660     // get PDO device extension
661     //
662     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
663 
664     //
665     // get FDO device extension
666     //
667     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
668 
669     //
670     // format instance id
671     //
672     if (FDODeviceExtension->SerialNumber)
673     {
674         //
675         // using serial number from device
676         //
677         swprintf(Buffer, L"%s&%c", FDODeviceExtension->SerialNumber->bString, PDODeviceExtension->LUN);
678     }
679     else
680     {
681         //
682         // use instance count and LUN
683         //
684         swprintf(Buffer, L"%04lu&%c", FDODeviceExtension->InstanceCount, PDODeviceExtension->LUN);
685     }
686 
687     //
688     // calculate length
689     //
690     Length = wcslen(Buffer) + 1;
691 
692     //
693     // allocate instance id
694     //
695     InstanceId = (LPWSTR)AllocateItem(PagedPool, Length * sizeof(WCHAR));
696     if (!InstanceId)
697     {
698         //
699         // no memory
700         //
701         Irp->IoStatus.Information = 0;
702         return STATUS_INSUFFICIENT_RESOURCES;
703     }
704 
705     //
706     // copy instance id
707     //
708     wcscpy(InstanceId, Buffer);
709 
710     DPRINT("USBSTOR_PdoHandleQueryInstanceId %S\n", InstanceId);
711 
712     //
713     // store result
714     //
715     Irp->IoStatus.Information = (ULONG_PTR)InstanceId;
716 
717     //
718     // completed successfully
719     //
720     return STATUS_SUCCESS;
721 }
722 
723 NTSTATUS
724 USBSTOR_PdoHandleDeviceRelations(
725     IN PDEVICE_OBJECT DeviceObject,
726     IN OUT PIRP Irp)
727 {
728     PDEVICE_RELATIONS DeviceRelations;
729     PIO_STACK_LOCATION IoStack;
730 
731     DPRINT("USBSTOR_PdoHandleDeviceRelations\n");
732 
733     //
734     // get current irp stack location
735     //
736     IoStack = IoGetCurrentIrpStackLocation(Irp);
737 
738     //
739     // check if relation type is BusRelations
740     //
741     if (IoStack->Parameters.QueryDeviceRelations.Type != TargetDeviceRelation)
742     {
743         //
744         // PDO handles only target device relation
745         //
746         return Irp->IoStatus.Status;
747     }
748 
749     //
750     // allocate device relations
751     //
752     DeviceRelations = (PDEVICE_RELATIONS)AllocateItem(PagedPool, sizeof(DEVICE_RELATIONS));
753     if (!DeviceRelations)
754     {
755         //
756         // no memory
757         //
758         return STATUS_INSUFFICIENT_RESOURCES;
759     }
760 
761     //
762     // initialize device relations
763     //
764     DeviceRelations->Count = 1;
765     DeviceRelations->Objects[0] = DeviceObject;
766     ObReferenceObject(DeviceObject);
767 
768     //
769     // store result
770     //
771     Irp->IoStatus.Information = (ULONG_PTR)DeviceRelations;
772 
773     //
774     // completed successfully
775     //
776     return STATUS_SUCCESS;
777 }
778 
779 
780 NTSTATUS
781 USBSTOR_PdoHandlePnp(
782     IN PDEVICE_OBJECT DeviceObject,
783     IN OUT PIRP Irp)
784 {
785     PIO_STACK_LOCATION IoStack;
786     PPDO_DEVICE_EXTENSION DeviceExtension;
787     NTSTATUS Status;
788     PDEVICE_CAPABILITIES Caps;
789     ULONG bDelete;
790 
791     //
792     // get current stack location
793     //
794     IoStack = IoGetCurrentIrpStackLocation(Irp);
795 
796     //
797     // get device extension
798     //
799     DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
800 
801     //
802     // sanity check
803     //
804     ASSERT(DeviceExtension->Common.IsFDO == FALSE);
805 
806     switch(IoStack->MinorFunction)
807     {
808        case IRP_MN_QUERY_DEVICE_RELATIONS:
809        {
810            Status = USBSTOR_PdoHandleDeviceRelations(DeviceObject, Irp);
811            break;
812        }
813        case IRP_MN_QUERY_DEVICE_TEXT:
814        {
815            Status = USBSTOR_PdoHandleQueryDeviceText(DeviceObject, Irp);
816            break;
817        }
818        case IRP_MN_QUERY_ID:
819        {
820            if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
821            {
822                //
823                // handle query device id
824                //
825                Status = USBSTOR_PdoHandleQueryDeviceId(DeviceObject, Irp);
826                break;
827            }
828            else if (IoStack->Parameters.QueryId.IdType == BusQueryHardwareIDs)
829            {
830                //
831                // handle instance id
832                //
833                Status = USBSTOR_PdoHandleQueryHardwareId(DeviceObject, Irp);
834                break;
835            }
836            else if (IoStack->Parameters.QueryId.IdType == BusQueryInstanceID)
837            {
838                //
839                // handle instance id
840                //
841                Status = USBSTOR_PdoHandleQueryInstanceId(DeviceObject, Irp);
842                break;
843            }
844            else if (IoStack->Parameters.QueryId.IdType == BusQueryCompatibleIDs)
845            {
846                //
847                // handle instance id
848                //
849                Status = USBSTOR_PdoHandleQueryCompatibleId(DeviceObject, Irp);
850                break;
851            }
852 
853            DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType);
854            Status = STATUS_NOT_SUPPORTED;
855            Irp->IoStatus.Information = 0;
856            break;
857        }
858        case IRP_MN_REMOVE_DEVICE:
859        {
860            DPRINT("IRP_MN_REMOVE_DEVICE\n");
861 
862            if(*DeviceExtension->PDODeviceObject != NULL)
863            {
864                //
865                // clear entry in FDO pdo list
866                //
867                *DeviceExtension->PDODeviceObject = NULL;
868                bDelete = TRUE;
869            }
870            else
871            {
872                //
873                // device object already marked for deletion
874                //
875                bDelete = FALSE;
876            }
877 
878            /* Complete the IRP */
879            Irp->IoStatus.Status = STATUS_SUCCESS;
880            IoCompleteRequest(Irp, IO_NO_INCREMENT);
881 
882            if (bDelete)
883            {
884                /* Delete the device object */
885                IoDeleteDevice(DeviceObject);
886            }
887            return STATUS_SUCCESS;
888        }
889        case IRP_MN_QUERY_CAPABILITIES:
890        {
891            //
892            // just forward irp to lower device
893            //
894            Status = USBSTOR_SyncForwardIrp(DeviceExtension->LowerDeviceObject, Irp);
895            ASSERT(Status == STATUS_SUCCESS);
896 
897            if (NT_SUCCESS(Status))
898            {
899                //
900                // check if no unique id
901                //
902                Caps = (PDEVICE_CAPABILITIES)IoStack->Parameters.DeviceCapabilities.Capabilities;
903                Caps->UniqueID = FALSE; // no unique id is supported
904                Caps->Removable = TRUE; //FIXME
905            }
906            break;
907        }
908        case IRP_MN_QUERY_REMOVE_DEVICE:
909        case IRP_MN_QUERY_STOP_DEVICE:
910        {
911 #if 0
912            //
913            // if we're not claimed it's ok
914            //
915            if (DeviceExtension->Claimed)
916 #else
917            if (TRUE)
918 #endif
919            {
920                Status = STATUS_UNSUCCESSFUL;
921                DPRINT1("[USBSTOR] Request %x fails because device is still claimed\n", IoStack->MinorFunction);
922            }
923            else
924                Status = STATUS_SUCCESS;
925            break;
926        }
927        case IRP_MN_START_DEVICE:
928        {
929            //
930            // no-op for PDO
931            //
932            Status = STATUS_SUCCESS;
933            break;
934        }
935        case IRP_MN_SURPRISE_REMOVAL:
936        {
937            Status = STATUS_SUCCESS;
938            break;
939        }
940        default:
941         {
942             //
943             // do nothing
944             //
945             Status = Irp->IoStatus.Status;
946         }
947     }
948 
949     //
950     // complete request
951     //
952     if (Status != STATUS_PENDING)
953     {
954         //
955         // store result
956         //
957         Irp->IoStatus.Status = Status;
958 
959         //
960         // complete request
961         //
962         IoCompleteRequest(Irp, IO_NO_INCREMENT);
963     }
964 
965     //
966     // done processing
967     //
968     return Status;
969 }
970 
971 NTSTATUS
972 NTAPI
973 USBSTOR_CompletionRoutine(
974     IN PDEVICE_OBJECT DeviceObject,
975     IN PIRP Irp,
976     IN PVOID Ctx)
977 {
978     PKEVENT Event = (PKEVENT)Ctx;
979 
980     //
981     // signal event
982     //
983     KeSetEvent(Event, 0, FALSE);
984     return STATUS_MORE_PROCESSING_REQUIRED;
985 }
986 
987 NTSTATUS
988 USBSTOR_AllocateIrp(
989     IN PDEVICE_OBJECT DeviceObject,
990     IN ULONG DataTransferLength,
991     IN UCHAR OpCode,
992     IN PKEVENT Event,
993     OUT PSCSI_REQUEST_BLOCK *OutRequest,
994     OUT PIRP *OutIrp)
995 {
996     PIRP Irp;
997     PIO_STACK_LOCATION IoStack;
998     PSCSI_REQUEST_BLOCK Request;
999     PCDB pCDB;
1000 
1001     //
1002     // allocate irp
1003     //
1004     Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
1005     if (!Irp)
1006     {
1007         //
1008         // no memory
1009         //
1010         return STATUS_INSUFFICIENT_RESOURCES;
1011     }
1012 
1013     //
1014     // get next stack location
1015     //
1016     IoStack = IoGetNextIrpStackLocation(Irp);
1017 
1018     //
1019     // create scsi block
1020     //
1021     Request = ExAllocatePoolWithTag(NonPagedPool,
1022                                     sizeof(SCSI_REQUEST_BLOCK),
1023                                     USB_STOR_TAG);
1024     if (!Request)
1025     {
1026         //
1027         // no memory
1028         //
1029         IoFreeIrp(Irp);
1030         return STATUS_INSUFFICIENT_RESOURCES;
1031     }
1032 
1033     //
1034     // init request
1035     //
1036     RtlZeroMemory(Request, sizeof(SCSI_REQUEST_BLOCK));
1037 
1038     //
1039     // allocate data transfer block
1040     //
1041     Request->DataBuffer = ExAllocatePoolWithTag(NonPagedPool,
1042                                                 DataTransferLength,
1043                                                 USB_STOR_TAG);
1044     if (!Request->DataBuffer)
1045     {
1046         //
1047         // no memory
1048         //
1049         IoFreeIrp(Irp);
1050         ExFreePoolWithTag(Request, USB_STOR_TAG);
1051         return STATUS_INSUFFICIENT_RESOURCES;
1052     }
1053 
1054     //
1055     // allocate MDL
1056     //
1057     Irp->MdlAddress = IoAllocateMdl(Request->DataBuffer, DataTransferLength, FALSE, FALSE, NULL);
1058     if (!Irp->MdlAddress)
1059     {
1060         //
1061         // no memory
1062         //
1063         IoFreeIrp(Irp);
1064         ExFreePoolWithTag(Request->DataBuffer, USB_STOR_TAG);
1065         ExFreePoolWithTag(Request, USB_STOR_TAG);
1066         return STATUS_INSUFFICIENT_RESOURCES;
1067     }
1068 
1069     //
1070     // non paged pool
1071     //
1072     MmBuildMdlForNonPagedPool(Irp->MdlAddress);
1073 
1074     //
1075     // init scsi block
1076     //
1077     Request->DataTransferLength = DataTransferLength;
1078     Request->Function = SRB_FUNCTION_EXECUTE_SCSI;
1079     Request->SrbFlags = SRB_FLAGS_DATA_IN;
1080 
1081     RtlZeroMemory(Request->DataBuffer, DataTransferLength);
1082 
1083 
1084     //
1085     // get SCSI command data block
1086     //
1087     pCDB = (PCDB)Request->Cdb;
1088 
1089     //
1090     // set op code
1091     //
1092     pCDB->AsByte[0] = OpCode;
1093 
1094     //
1095     // store result
1096     //
1097     IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1098     IoStack->Parameters.Others.Argument1 = Request;
1099     IoStack->DeviceObject = DeviceObject;
1100 
1101     //
1102     // init event
1103     //
1104     KeInitializeEvent(Event, NotificationEvent, FALSE);
1105 
1106     //
1107     // lets setup a completion routine
1108     //
1109     IoSetCompletionRoutine(Irp, USBSTOR_CompletionRoutine, (PVOID)Event, TRUE, TRUE, TRUE);
1110 
1111     //
1112     // output result
1113     //
1114     *OutIrp = Irp;
1115     *OutRequest = Request;
1116     return STATUS_SUCCESS;
1117 }
1118 
1119 NTSTATUS
1120 USBSTOR_SendIrp(
1121     IN PDEVICE_OBJECT PDODeviceObject,
1122     IN ULONG DataTransferLength,
1123     IN UCHAR OpCode,
1124     OUT PVOID *OutData)
1125 {
1126     NTSTATUS Status;
1127     PIRP Irp;
1128     KEVENT Event;
1129     PPDO_DEVICE_EXTENSION PDODeviceExtension;
1130     PSCSI_REQUEST_BLOCK Request;
1131 
1132     //
1133     // let's allocate an irp
1134     //
1135     Status = USBSTOR_AllocateIrp(PDODeviceObject, DataTransferLength, OpCode, &Event, &Request, &Irp);
1136     if (!NT_SUCCESS(Status))
1137     {
1138         //
1139         // failed
1140         //
1141         DPRINT1("[USBSTOR] Failed to build irp\n");
1142         return Status;
1143     }
1144 
1145     //
1146     // get device extension
1147     //
1148     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
1149 
1150     //
1151     // send irp
1152     //
1153     ASSERT(Irp);
1154     ASSERT(PDODeviceExtension->LowerDeviceObject);
1155     Status = IoCallDriver(PDODeviceExtension->Self, Irp);
1156 
1157     if (Status == STATUS_PENDING)
1158     {
1159         //
1160         // wait for completion
1161         //
1162         KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1163         Status = Irp->IoStatus.Status;
1164     }
1165 
1166     if (NT_SUCCESS(Status))
1167     {
1168         //
1169         // store result
1170         //
1171         *OutData = Request->DataBuffer;
1172     }
1173     else
1174     {
1175         //
1176         // free the data
1177         //
1178         ExFreePoolWithTag(Request->DataBuffer, USB_STOR_TAG);
1179         *OutData = NULL;
1180     }
1181 
1182     //
1183     // free resources
1184     //
1185     ExFreePoolWithTag(Request, USB_STOR_TAG);
1186     IoFreeMdl(Irp->MdlAddress);
1187     IoFreeIrp(Irp);
1188     return Status;
1189 }
1190 
1191 NTSTATUS
1192 USBSTOR_SendInquiryIrp(
1193     IN PDEVICE_OBJECT PDODeviceObject)
1194 {
1195     NTSTATUS Status;
1196     PPDO_DEVICE_EXTENSION PDODeviceExtension;
1197     PUFI_INQUIRY_RESPONSE Response;
1198 
1199     //
1200     // get device extension
1201     //
1202     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
1203 
1204     //
1205     // send request
1206     //
1207     Status = USBSTOR_SendIrp(PDODeviceObject, sizeof(UFI_INQUIRY_RESPONSE), SCSIOP_INQUIRY, (PVOID*)&Response);
1208     if (!NT_SUCCESS(Status))
1209     {
1210         //
1211         // command failed
1212         //
1213         DPRINT1("USBSTOR_SendInquiryIrp Failed with %x\n", Status);
1214         return Status;
1215     }
1216 
1217     DPRINT1("Response %p\n", Response);
1218     DPRINT1("DeviceType %x\n", Response->DeviceType);
1219     DPRINT1("RMB %x\n", Response->RMB);
1220     DPRINT1("Version %x\n", Response->Version);
1221     DPRINT1("Format %x\n", Response->Format);
1222     DPRINT1("Length %x\n", Response->Length);
1223     DPRINT1("Reserved %p\n", Response->Reserved);
1224     DPRINT1("Vendor %c%c%c%c%c%c%c%c\n", Response->Vendor[0], Response->Vendor[1], Response->Vendor[2], Response->Vendor[3], Response->Vendor[4], Response->Vendor[5], Response->Vendor[6], Response->Vendor[7]);
1225     DPRINT1("Product %c%c%c%c%c%c%c%c%c%c%c%c%c%c%c%c\n", Response->Product[0], Response->Product[1], Response->Product[2], Response->Product[3],
1226                                                           Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
1227                                                           Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
1228                                                           Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
1229 
1230     DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
1231 
1232     //
1233     // store result
1234     //
1235     PDODeviceExtension->InquiryData = (PVOID)Response;
1236     return Status;
1237 }
1238 
1239 NTSTATUS
1240 USBSTOR_SendFormatCapacityIrp(
1241     IN PDEVICE_OBJECT PDODeviceObject)
1242 {
1243     NTSTATUS Status;
1244     PPDO_DEVICE_EXTENSION PDODeviceExtension;
1245     PUCHAR Response;
1246 
1247     //
1248     // get device extension
1249     //
1250     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
1251 
1252     //
1253     // send request
1254     //
1255     Status = USBSTOR_SendIrp(PDODeviceObject, 0xFC, SCSIOP_READ_FORMATTED_CAPACITY, (PVOID*)&Response);
1256     if (!NT_SUCCESS(Status))
1257     {
1258         //
1259         // command failed
1260         //
1261         return Status;
1262     }
1263 
1264     //
1265     // check if its a floppy
1266     //
1267     PDODeviceExtension->IsFloppy = USBSTOR_IsFloppy(Response, 0xFC /*FIXME*/, &PDODeviceExtension->MediumTypeCode);
1268 
1269     //
1270     // free response
1271     //
1272     ExFreePoolWithTag(Response, USB_STOR_TAG);
1273     return Status;
1274 }
1275 
1276 
1277 
1278 NTSTATUS
1279 USBSTOR_CreatePDO(
1280     IN PDEVICE_OBJECT DeviceObject,
1281     IN UCHAR LUN)
1282 {
1283     PDEVICE_OBJECT PDO;
1284     NTSTATUS Status;
1285     PPDO_DEVICE_EXTENSION PDODeviceExtension;
1286     PUFI_INQUIRY_RESPONSE Response;
1287     PFDO_DEVICE_EXTENSION FDODeviceExtension;
1288 
1289     //
1290     // get device extension
1291     //
1292     FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1293 
1294 
1295     //
1296     // create child device object
1297     //
1298     Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO);
1299     if (!NT_SUCCESS(Status))
1300     {
1301         //
1302         // failed to create device
1303         //
1304         return Status;
1305     }
1306 
1307     //
1308     // patch the stack size
1309     //
1310     PDO->StackSize = DeviceObject->StackSize;
1311 
1312     //
1313     // get device extension
1314     //
1315     PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension;
1316 
1317     //
1318     // initialize device extension
1319     //
1320     RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
1321     PDODeviceExtension->Common.IsFDO = FALSE;
1322     PDODeviceExtension->LowerDeviceObject = DeviceObject;
1323     PDODeviceExtension->PDODeviceObject = &FDODeviceExtension->ChildPDO[LUN];
1324     PDODeviceExtension->Self = PDO;
1325     PDODeviceExtension->LUN = LUN;
1326 
1327     //
1328     // set device flags
1329     //
1330     PDO->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
1331 
1332     //
1333     // device is initialized
1334     //
1335     PDO->Flags &= ~DO_DEVICE_INITIALIZING;
1336 
1337     //
1338     // output device object
1339     //
1340     FDODeviceExtension->ChildPDO[LUN] = PDO;
1341 
1342     //
1343     // send inquiry command by irp
1344     //
1345     Status = USBSTOR_SendInquiryIrp(PDO);
1346     ASSERT(Status == STATUS_SUCCESS);
1347 
1348     //
1349     // check response data
1350     //
1351     Response = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
1352     ASSERT(Response);
1353 
1354     if (Response->DeviceType == 0)
1355     {
1356         //
1357         // check if it is a floppy
1358         //
1359         Status = USBSTOR_SendFormatCapacityIrp(PDO);
1360 
1361         //
1362         // display result
1363         //
1364         DPRINT1("[USBSTOR] Status %x IsFloppy %x MediumTypeCode %x\n", Status, PDODeviceExtension->IsFloppy, PDODeviceExtension->MediumTypeCode);
1365 
1366         //
1367         // failing command is non critical
1368         //
1369         Status = STATUS_SUCCESS;
1370     }
1371 
1372     //
1373     // done
1374     //
1375     return Status;
1376 }
1377