9e293df80a6a87432c69fe457fcf312886d5a656
[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 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&%d", FDODeviceExtension->SerialNumber->bString, PDODeviceExtension->LUN);
675 }
676 else
677 {
678 //
679 // FIXME: should use some random value
680 //
681 swprintf(Buffer, L"%s&%d", L"00000000", 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 = TRUE; //FIXME
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 default:
933 {
934 //
935 // do nothing
936 //
937 Status = Irp->IoStatus.Status;
938 }
939 }
940
941 //
942 // complete request
943 //
944 if (Status != STATUS_PENDING)
945 {
946 //
947 // store result
948 //
949 Irp->IoStatus.Status = Status;
950
951 //
952 // complete request
953 //
954 IoCompleteRequest(Irp, IO_NO_INCREMENT);
955 }
956
957 //
958 // done processing
959 //
960 return Status;
961 }
962
963 NTSTATUS
964 NTAPI
965 USBSTOR_CompletionRoutine(
966 IN PDEVICE_OBJECT DeviceObject,
967 IN PIRP Irp,
968 IN PVOID Ctx)
969 {
970 PKEVENT Event = (PKEVENT)Ctx;
971
972 //
973 // signal event
974 //
975 KeSetEvent(Event, 0, FALSE);
976 return STATUS_MORE_PROCESSING_REQUIRED;
977 }
978
979 NTSTATUS
980 USBSTOR_AllocateIrp(
981 IN PDEVICE_OBJECT DeviceObject,
982 IN ULONG DataTransferLength,
983 IN UCHAR OpCode,
984 IN PKEVENT Event,
985 OUT PSCSI_REQUEST_BLOCK *OutRequest,
986 OUT PIRP *OutIrp)
987 {
988 PIRP Irp;
989 PIO_STACK_LOCATION IoStack;
990 PSCSI_REQUEST_BLOCK Request;
991 PCDB pCDB;
992
993 //
994 // allocate irp
995 //
996 Irp = IoAllocateIrp(DeviceObject->StackSize, FALSE);
997 if (!Irp)
998 {
999 //
1000 // no memory
1001 //
1002 return STATUS_INSUFFICIENT_RESOURCES;
1003 }
1004
1005 //
1006 // get next stack location
1007 //
1008 IoStack = IoGetNextIrpStackLocation(Irp);
1009
1010 //
1011 // create scsi block
1012 //
1013 Request = (PSCSI_REQUEST_BLOCK)ExAllocatePool(NonPagedPool, sizeof(SCSI_REQUEST_BLOCK));
1014 if (!Request)
1015 {
1016 //
1017 // no memory
1018 //
1019 IoFreeIrp(Irp);
1020 return STATUS_INSUFFICIENT_RESOURCES;
1021 }
1022
1023 //
1024 // init request
1025 //
1026 RtlZeroMemory(Request, sizeof(SCSI_REQUEST_BLOCK));
1027
1028 //
1029 // allocate data transfer block
1030 //
1031 Request->DataBuffer = ExAllocatePool(NonPagedPool, DataTransferLength);
1032 if (!Request)
1033 {
1034 //
1035 // no memory
1036 //
1037 IoFreeIrp(Irp);
1038 ExFreePool(Request);
1039 return STATUS_INSUFFICIENT_RESOURCES;
1040 }
1041
1042 //
1043 // allocate MDL
1044 //
1045 Irp->MdlAddress = IoAllocateMdl(Request->DataBuffer, DataTransferLength, FALSE, FALSE, NULL);
1046 if (!Irp->MdlAddress)
1047 {
1048 //
1049 // no memory
1050 //
1051 IoFreeIrp(Irp);
1052 ExFreePool(Request);
1053 return STATUS_INSUFFICIENT_RESOURCES;
1054 }
1055
1056 //
1057 // non paged pool
1058 //
1059 MmBuildMdlForNonPagedPool(Irp->MdlAddress);
1060
1061 //
1062 // init scsi block
1063 //
1064 Request->DataTransferLength = DataTransferLength;
1065 Request->Function = SRB_FUNCTION_EXECUTE_SCSI;
1066 Request->SrbFlags = SRB_FLAGS_DATA_IN;
1067
1068 RtlZeroMemory(Request->DataBuffer, DataTransferLength);
1069
1070
1071 //
1072 // get SCSI command data block
1073 //
1074 pCDB = (PCDB)Request->Cdb;
1075
1076 //
1077 // set op code
1078 //
1079 pCDB->AsByte[0] = OpCode;
1080
1081 //
1082 // store result
1083 //
1084 IoStack->MajorFunction = IRP_MJ_INTERNAL_DEVICE_CONTROL;
1085 IoStack->Parameters.Others.Argument1 = Request;
1086 IoStack->DeviceObject = DeviceObject;
1087
1088 //
1089 // init event
1090 //
1091 KeInitializeEvent(Event, NotificationEvent, FALSE);
1092
1093 //
1094 // lets setup a completion routine
1095 //
1096 IoSetCompletionRoutine(Irp, USBSTOR_CompletionRoutine, (PVOID)Event, TRUE, TRUE, TRUE);
1097
1098 //
1099 // output result
1100 //
1101 *OutIrp = Irp;
1102 *OutRequest = Request;
1103 return STATUS_SUCCESS;
1104 }
1105
1106 NTSTATUS
1107 USBSTOR_SendIrp(
1108 IN PDEVICE_OBJECT PDODeviceObject,
1109 IN ULONG DataTransferLength,
1110 IN UCHAR OpCode,
1111 OUT PVOID *OutData)
1112 {
1113 NTSTATUS Status;
1114 PIRP Irp;
1115 KEVENT Event;
1116 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1117 PSCSI_REQUEST_BLOCK Request;
1118
1119 //
1120 // let's allocate an irp
1121 //
1122 Status = USBSTOR_AllocateIrp(PDODeviceObject, DataTransferLength, OpCode, &Event, &Request, &Irp);
1123 if (!NT_SUCCESS(Status))
1124 {
1125 //
1126 // failed
1127 //
1128 DPRINT1("[USBSTOR] Failed to build irp\n");
1129 return Status;
1130 }
1131
1132 //
1133 // get device extension
1134 //
1135 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
1136
1137 //
1138 // send irp
1139 //
1140 ASSERT(Irp);
1141 ASSERT(PDODeviceExtension->LowerDeviceObject);
1142 Status = IoCallDriver(PDODeviceExtension->Self, Irp);
1143
1144 if (Status == STATUS_PENDING)
1145 {
1146 //
1147 // wait for completion
1148 //
1149 KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE, NULL);
1150 Status = Irp->IoStatus.Status;
1151 }
1152
1153 if (NT_SUCCESS(Status))
1154 {
1155 //
1156 // store result
1157 //
1158 *OutData = Request->DataBuffer;
1159 }
1160
1161 //
1162 // free resources
1163 //
1164 ExFreePool(Request);
1165 IoFreeIrp(Irp);
1166 return Status;
1167 }
1168
1169 NTSTATUS
1170 USBSTOR_SendInquiryIrp(
1171 IN PDEVICE_OBJECT PDODeviceObject)
1172 {
1173 NTSTATUS Status;
1174 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1175 PUFI_INQUIRY_RESPONSE Response;
1176
1177 //
1178 // get device extension
1179 //
1180 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
1181
1182 //
1183 // send request
1184 //
1185 Status = USBSTOR_SendIrp(PDODeviceObject, sizeof(UFI_INQUIRY_RESPONSE), SCSIOP_INQUIRY, (PVOID*)&Response);
1186 if (!NT_SUCCESS(Status))
1187 {
1188 //
1189 // command failed
1190 //
1191 DPRINT1("USBSTOR_SendInquiryIrp Failed with %x\n", Status);
1192 return Status;
1193 }
1194
1195 DPRINT1("Response %p\n", Response);
1196 DPRINT1("DeviceType %x\n", Response->DeviceType);
1197 DPRINT1("RMB %x\n", Response->RMB);
1198 DPRINT1("Version %x\n", Response->Version);
1199 DPRINT1("Format %x\n", Response->Format);
1200 DPRINT1("Length %x\n", Response->Length);
1201 DPRINT1("Reserved %x\n", Response->Reserved);
1202 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]);
1203 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],
1204 Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
1205 Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
1206 Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
1207
1208 DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
1209
1210 //
1211 // store result
1212 //
1213 PDODeviceExtension->InquiryData = (PVOID)Response;
1214 return Status;
1215 }
1216
1217 NTSTATUS
1218 USBSTOR_SendFormatCapacityIrp(
1219 IN PDEVICE_OBJECT PDODeviceObject)
1220 {
1221 NTSTATUS Status;
1222 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1223 PUCHAR Response;
1224
1225 //
1226 // get device extension
1227 //
1228 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDODeviceObject->DeviceExtension;
1229
1230 //
1231 // send request
1232 //
1233 Status = USBSTOR_SendIrp(PDODeviceObject, 0xFC, SCSIOP_READ_FORMATTED_CAPACITY, (PVOID*)&Response);
1234 if (!NT_SUCCESS(Status))
1235 {
1236 //
1237 // command failed
1238 //
1239 return Status;
1240 }
1241
1242 //
1243 // check if its a floppy
1244 //
1245 PDODeviceExtension->IsFloppy = USBSTOR_IsFloppy(Response, 0xFC /*FIXME*/, &PDODeviceExtension->MediumTypeCode);
1246
1247 //
1248 // free response
1249 //
1250 ExFreePool(Response);
1251 return Status;
1252 }
1253
1254
1255
1256 NTSTATUS
1257 USBSTOR_CreatePDO(
1258 IN PDEVICE_OBJECT DeviceObject,
1259 IN UCHAR LUN,
1260 OUT PDEVICE_OBJECT *ChildDeviceObject)
1261 {
1262 PDEVICE_OBJECT PDO;
1263 NTSTATUS Status;
1264 PPDO_DEVICE_EXTENSION PDODeviceExtension;
1265 PUFI_INQUIRY_RESPONSE Response;
1266
1267 //
1268 // create child device object
1269 //
1270 Status = IoCreateDevice(DeviceObject->DriverObject, sizeof(PDO_DEVICE_EXTENSION), NULL, FILE_DEVICE_MASS_STORAGE, FILE_AUTOGENERATED_DEVICE_NAME | FILE_DEVICE_SECURE_OPEN, FALSE, &PDO);
1271 if (!NT_SUCCESS(Status))
1272 {
1273 //
1274 // failed to create device
1275 //
1276 return Status;
1277 }
1278
1279 //
1280 // patch the stack size
1281 //
1282 PDO->StackSize = DeviceObject->StackSize;
1283
1284 //
1285 // get device extension
1286 //
1287 PDODeviceExtension = (PPDO_DEVICE_EXTENSION)PDO->DeviceExtension;
1288
1289 //
1290 // initialize device extension
1291 //
1292 RtlZeroMemory(PDODeviceExtension, sizeof(PDO_DEVICE_EXTENSION));
1293 PDODeviceExtension->Common.IsFDO = FALSE;
1294 PDODeviceExtension->LowerDeviceObject = DeviceObject;
1295 PDODeviceExtension->PDODeviceObject = ChildDeviceObject;
1296 PDODeviceExtension->Self = PDO;
1297 PDODeviceExtension->LUN = LUN;
1298
1299 //
1300 // set device flags
1301 //
1302 PDO->Flags |= DO_DIRECT_IO | DO_MAP_IO_BUFFER;
1303
1304 //
1305 // device is initialized
1306 //
1307 PDO->Flags &= ~DO_DEVICE_INITIALIZING;
1308
1309 //
1310 // output device object
1311 //
1312 *ChildDeviceObject = PDO;
1313
1314 //
1315 // send inquiry command by irp
1316 //
1317 Status = USBSTOR_SendInquiryIrp(PDO);
1318 ASSERT(Status == STATUS_SUCCESS);
1319
1320 //
1321 // check response data
1322 //
1323 Response = (PUFI_INQUIRY_RESPONSE)PDODeviceExtension->InquiryData;
1324 ASSERT(Response);
1325
1326 if (Response->DeviceType == 0)
1327 {
1328 //
1329 // check if it is a floppy
1330 //
1331 Status = USBSTOR_SendFormatCapacityIrp(PDO);
1332
1333 //
1334 // display result
1335 //
1336 DPRINT1("[USBSTOR] Status %x IsFloppy %x MediumTypeCode %x\n", Status, PDODeviceExtension->IsFloppy, PDODeviceExtension->MediumTypeCode);
1337
1338 //
1339 // failing command is non critical
1340 //
1341 Status = STATUS_SUCCESS;
1342 }
1343
1344 //
1345 // done
1346 //
1347 return Status;
1348 }