* Sync up to trunk head (r65120).
[reactos.git] / drivers / usb / usbstor / pdo.c
1 /*
2 * PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: drivers/usb/usbstor/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 - derrived 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 - derrived 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 = (PSCSI_REQUEST_BLOCK)ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
1022 if (!Request)
1023 {
1024 //
1025 // no memory
1026 //
1027 IoFreeIrp(Irp);
1028 return STATUS_INSUFFICIENT_RESOURCES;
1029 }
1030
1031 //
1032 // init request
1033 //
1034 RtlZeroMemory(Request, sizeof(SCSI_REQUEST_BLOCK));
1035
1036 //
1037 // allocate data transfer block
1038 //
1039 Request->DataBuffer = ExAllocatePool(NonPagedPool, DataTransferLength);
1040 if (!Request)
1041 {
1042 //
1043 // no memory
1044 //
1045 IoFreeIrp(Irp);
1046 ExFreePool(Request);
1047 return STATUS_INSUFFICIENT_RESOURCES;
1048 }
1049
1050 //
1051 // allocate MDL
1052 //
1053 Irp->MdlAddress = IoAllocateMdl(Request->DataBuffer, DataTransferLength, FALSE, FALSE, NULL);
1054 if (!Irp->MdlAddress)
1055 {
1056 //
1057 // no memory
1058 //
1059 IoFreeIrp(Irp);
1060 ExFreePool(Request);
1061 return STATUS_INSUFFICIENT_RESOURCES;
1062 }
1063
1064 //
1065 // non paged pool
1066 //
1067 MmBuildMdlForNonPagedPool(Irp->MdlAddress);
1068
1069 //
1070 // init scsi block
1071 //
1072 Request->DataTransferLength = DataTransferLength;
1073 Request->Function = SRB_FUNCTION_EXECUTE_SCSI;
1074 Request->SrbFlags = SRB_FLAGS_DATA_IN;
1075
1076 RtlZeroMemory(Request->DataBuffer, DataTransferLength);
1077
1078
1079 //
1080 // get SCSI command data block
1081 //
1082 pCDB = (PCDB)Request->Cdb;
1083
1084 //
1085 // set op code
1086 //
1087 pCDB->AsByte[0] = OpCode;
1088
1089 //
1090 // store result
1091 //
1092 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1093 IoStack->Parameters.Others.Argument1 = Request;
1094 IoStack->DeviceObject = DeviceObject;
1095
1096 //
1097 // init event
1098 //
1099 KeInitializeEvent(Event, NotificationEvent, FALSE);
1100
1101 //
1102 // lets setup a completion routine
1103 //
1104 IoSetCompletionRoutine(Irp, USBSTOR_CompletionRoutine, (PVOID)Event, TRUE, TRUE, TRUE);
1105
1106 //
1107 // output result
1108 //
1109 *OutIrp = Irp;
1110 *OutRequest = Request;
1111 return STATUS_SUCCESS;
1112 }
1113
1114 NTSTATUS
1115 USBSTOR_SendIrp(
1116 IN PDEVICE_OBJECT PDODeviceObject,
1117 IN ULONG DataTransferLength,
1118 IN UCHAR OpCode,
1119 OUT PVOID *OutData)
1120 {
1121 NTSTATUS Status;
1122 PIRP Irp;
1123 KEVENT Event;
1124 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1125 PSCSI_REQUEST_BLOCK Request;
1126
1127 //
1128 // let's allocate an irp
1129 //
1130 Status = USBSTOR_AllocateIrp(PDODeviceObject, DataTransferLength, OpCode, &Event, &Request, &Irp);
1131 if (!NT_SUCCESS(Status))
1132 {
1133 //
1134 // failed
1135 //
1136 DPRINT1("[USBSTOR] Failed to build irp\n");
1137 return Status;
1138 }
1139
1140 //
1141 // get device extension
1142 //
1143 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
1144
1145 //
1146 // send irp
1147 //
1148 ASSERT(Irp);
1149 ASSERT(PDODeviceExtension->LowerDeviceObject);
1150 Status = IoCallDriver(PDODeviceExtension->Self, Irp);
1151
1152 if (Status == STATUS_PENDING)
1153 {
1154 //
1155 // wait for completion
1156 //
1157 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1158 Status = Irp->IoStatus.Status;
1159 }
1160
1161 if (NT_SUCCESS(Status))
1162 {
1163 //
1164 // store result
1165 //
1166 *OutData = Request->DataBuffer;
1167 }
1168
1169 //
1170 // free resources
1171 //
1172 ExFreePool(Request);
1173 IoFreeIrp(Irp);
1174 return Status;
1175 }
1176
1177 NTSTATUS
1178 USBSTOR_SendInquiryIrp(
1179 IN PDEVICE_OBJECT PDODeviceObject)
1180 {
1181 NTSTATUS Status;
1182 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1183 PUFI_INQUIRY_RESPONSE Response;
1184
1185 //
1186 // get device extension
1187 //
1188 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
1189
1190 //
1191 // send request
1192 //
1193 Status = USBSTOR_SendIrp(PDODeviceObject, sizeof(UFI_INQUIRY_RESPONSE), SCSIOP_INQUIRY, (PVOID*)&Response);
1194 if (!NT_SUCCESS(Status))
1195 {
1196 //
1197 // command failed
1198 //
1199 DPRINT1("USBSTOR_SendInquiryIrp Failed with %x\n", Status);
1200 return Status;
1201 }
1202
1203 DPRINT1("Response %p\n", Response);
1204 DPRINT1("DeviceType %x\n", Response->DeviceType);
1205 DPRINT1("RMB %x\n", Response->RMB);
1206 DPRINT1("Version %x\n", Response->Version);
1207 DPRINT1("Format %x\n", Response->Format);
1208 DPRINT1("Length %x\n", Response->Length);
1209 DPRINT1("Reserved %p\n", Response->Reserved);
1210 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]);
1211 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],
1212 Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
1213 Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
1214 Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
1215
1216 DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
1217
1218 //
1219 // store result
1220 //
1221 PDODeviceExtension->InquiryData = (PVOID)Response;
1222 return Status;
1223 }
1224
1225 NTSTATUS
1226 USBSTOR_SendFormatCapacityIrp(
1227 IN PDEVICE_OBJECT PDODeviceObject)
1228 {
1229 NTSTATUS Status;
1230 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1231 PUCHAR Response;
1232
1233 //
1234 // get device extension
1235 //
1236 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
1237
1238 //
1239 // send request
1240 //
1241 Status = USBSTOR_SendIrp(PDODeviceObject, 0xFC, SCSIOP_READ_FORMATTED_CAPACITY, (PVOID*)&Response);
1242 if (!NT_SUCCESS(Status))
1243 {
1244 //
1245 // command failed
1246 //
1247 return Status;
1248 }
1249
1250 //
1251 // check if its a floppy
1252 //
1253 PDODeviceExtension->IsFloppy = USBSTOR_IsFloppy(Response, 0xFC /*FIXME*/, &PDODeviceExtension->MediumTypeCode);
1254
1255 //
1256 // free response
1257 //
1258 ExFreePool(Response);
1259 return Status;
1260 }
1261
1262
1263
1264 NTSTATUS
1265 USBSTOR_CreatePDO(
1266 IN PDEVICE_OBJECT DeviceObject,
1267 IN UCHAR LUN)
1268 {
1269 PDEVICE_OBJECT PDO;
1270 NTSTATUS Status;
1271 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1272 PUFI_INQUIRY_RESPONSE Response;
1273 PFDO_DEVICE_EXTENSION FDODeviceExtension;
1274
1275 //
1276 // get device extension
1277 //
1278 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1279
1280
1281 //
1282 // create child device object
1283 //
1284 Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO);
1285 if (!NT_SUCCESS(Status))
1286 {
1287 //
1288 // failed to create device
1289 //
1290 return Status;
1291 }
1292
1293 //
1294 // patch the stack size
1295 //
1296 PDO->StackSize = DeviceObject->StackSize;
1297
1298 //
1299 // get device extension
1300 //
1301 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension;
1302
1303 //
1304 // initialize device extension
1305 //
1306 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
1307 PDODeviceExtension->Common.IsFDO = FALSE;
1308 PDODeviceExtension->LowerDeviceObject = DeviceObject;
1309 PDODeviceExtension->PDODeviceObject = &FDODeviceExtension->ChildPDO[LUN];
1310 PDODeviceExtension->Self = PDO;
1311 PDODeviceExtension->LUN = LUN;
1312
1313 //
1314 // set device flags
1315 //
1316 PDO->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
1317
1318 //
1319 // device is initialized
1320 //
1321 PDO->Flags &= ~DO_DEVICE_INITIALIZING;
1322
1323 //
1324 // output device object
1325 //
1326 FDODeviceExtension->ChildPDO[LUN] = PDO;
1327
1328 //
1329 // send inquiry command by irp
1330 //
1331 Status = USBSTOR_SendInquiryIrp(PDO);
1332 ASSERT(Status == STATUS_SUCCESS);
1333
1334 //
1335 // check response data
1336 //
1337 Response = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
1338 ASSERT(Response);
1339
1340 if (Response->DeviceType == 0)
1341 {
1342 //
1343 // check if it is a floppy
1344 //
1345 Status = USBSTOR_SendFormatCapacityIrp(PDO);
1346
1347 //
1348 // display result
1349 //
1350 DPRINT1("[USBSTOR] Status %x IsFloppy %x MediumTypeCode %x\n", Status, PDODeviceExtension->IsFloppy, PDODeviceExtension->MediumTypeCode);
1351
1352 //
1353 // failing command is non critical
1354 //
1355 Status = STATUS_SUCCESS;
1356 }
1357
1358 //
1359 // done
1360 //
1361 return Status;
1362 }