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