b741542d2b7e0065cef0880b3131d430095e293e
[reactos.git] / reactos / 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 - 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
1174 //
1175 // free resources
1176 //
1177 ExFreePoolWithTag(Request->DataBuffer, USB_STOR_TAG);
1178 ExFreePoolWithTag(Request, USB_STOR_TAG);
1179 IoFreeIrp(Irp);
1180 return Status;
1181 }
1182
1183 NTSTATUS
1184 USBSTOR_SendInquiryIrp(
1185 IN PDEVICE_OBJECT PDODeviceObject)
1186 {
1187 NTSTATUS Status;
1188 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1189 PUFI_INQUIRY_RESPONSE Response;
1190
1191 //
1192 // get device extension
1193 //
1194 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
1195
1196 //
1197 // send request
1198 //
1199 Status = USBSTOR_SendIrp(PDODeviceObject, sizeof(UFI_INQUIRY_RESPONSE), SCSIOP_INQUIRY, (PVOID*)&Response);
1200 if (!NT_SUCCESS(Status))
1201 {
1202 //
1203 // command failed
1204 //
1205 DPRINT1("USBSTOR_SendInquiryIrp Failed with %x\n", Status);
1206 return Status;
1207 }
1208
1209 DPRINT1("Response %p\n", Response);
1210 DPRINT1("DeviceType %x\n", Response->DeviceType);
1211 DPRINT1("RMB %x\n", Response->RMB);
1212 DPRINT1("Version %x\n", Response->Version);
1213 DPRINT1("Format %x\n", Response->Format);
1214 DPRINT1("Length %x\n", Response->Length);
1215 DPRINT1("Reserved %p\n", Response->Reserved);
1216 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]);
1217 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],
1218 Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
1219 Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
1220 Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
1221
1222 DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
1223
1224 //
1225 // store result
1226 //
1227 PDODeviceExtension->InquiryData = (PVOID)Response;
1228 return Status;
1229 }
1230
1231 NTSTATUS
1232 USBSTOR_SendFormatCapacityIrp(
1233 IN PDEVICE_OBJECT PDODeviceObject)
1234 {
1235 NTSTATUS Status;
1236 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1237 PUCHAR Response;
1238
1239 //
1240 // get device extension
1241 //
1242 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
1243
1244 //
1245 // send request
1246 //
1247 Status = USBSTOR_SendIrp(PDODeviceObject, 0xFC, SCSIOP_READ_FORMATTED_CAPACITY, (PVOID*)&Response);
1248 if (!NT_SUCCESS(Status))
1249 {
1250 //
1251 // command failed
1252 //
1253 return Status;
1254 }
1255
1256 //
1257 // check if its a floppy
1258 //
1259 PDODeviceExtension->IsFloppy = USBSTOR_IsFloppy(Response, 0xFC /*FIXME*/, &PDODeviceExtension->MediumTypeCode);
1260
1261 //
1262 // free response
1263 //
1264 ExFreePoolWithTag(Response, USB_STOR_TAG);
1265 return Status;
1266 }
1267
1268
1269
1270 NTSTATUS
1271 USBSTOR_CreatePDO(
1272 IN PDEVICE_OBJECT DeviceObject,
1273 IN UCHAR LUN)
1274 {
1275 PDEVICE_OBJECT PDO;
1276 NTSTATUS Status;
1277 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1278 PUFI_INQUIRY_RESPONSE Response;
1279 PFDO_DEVICE_EXTENSION FDODeviceExtension;
1280
1281 //
1282 // get device extension
1283 //
1284 FDODeviceExtension = (PFDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
1285
1286
1287 //
1288 // create child device object
1289 //
1290 Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO);
1291 if (!NT_SUCCESS(Status))
1292 {
1293 //
1294 // failed to create device
1295 //
1296 return Status;
1297 }
1298
1299 //
1300 // patch the stack size
1301 //
1302 PDO->StackSize = DeviceObject->StackSize;
1303
1304 //
1305 // get device extension
1306 //
1307 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension;
1308
1309 //
1310 // initialize device extension
1311 //
1312 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
1313 PDODeviceExtension->Common.IsFDO = FALSE;
1314 PDODeviceExtension->LowerDeviceObject = DeviceObject;
1315 PDODeviceExtension->PDODeviceObject = &FDODeviceExtension->ChildPDO[LUN];
1316 PDODeviceExtension->Self = PDO;
1317 PDODeviceExtension->LUN = LUN;
1318
1319 //
1320 // set device flags
1321 //
1322 PDO->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
1323
1324 //
1325 // device is initialized
1326 //
1327 PDO->Flags &= ~DO_DEVICE_INITIALIZING;
1328
1329 //
1330 // output device object
1331 //
1332 FDODeviceExtension->ChildPDO[LUN] = PDO;
1333
1334 //
1335 // send inquiry command by irp
1336 //
1337 Status = USBSTOR_SendInquiryIrp(PDO);
1338 ASSERT(Status == STATUS_SUCCESS);
1339
1340 //
1341 // check response data
1342 //
1343 Response = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
1344 ASSERT(Response);
1345
1346 if (Response->DeviceType == 0)
1347 {
1348 //
1349 // check if it is a floppy
1350 //
1351 Status = USBSTOR_SendFormatCapacityIrp(PDO);
1352
1353 //
1354 // display result
1355 //
1356 DPRINT1("[USBSTOR] Status %x IsFloppy %x MediumTypeCode %x\n", Status, PDODeviceExtension->IsFloppy, PDODeviceExtension->MediumTypeCode);
1357
1358 //
1359 // failing command is non critical
1360 //
1361 Status = STATUS_SUCCESS;
1362 }
1363
1364 //
1365 // done
1366 //
1367 return Status;
1368 }