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.
8 * Michael Martin (michael.martin@reactos.org)
9 * Johannes Anderwald (johannes.anderwald@reactos.org)
15 USBSTOR_GetDeviceType(
16 IN PUFI_INQUIRY_RESPONSE InquiryData
)
19 // check if device type is zero
21 if (InquiryData
->DeviceType
== 0)
24 // direct access device
28 // FIXME: check if floppy
34 // FIXME: use constant - derrived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
36 switch (InquiryData
->DeviceType
)
41 // sequential device, i.e magnetic tape
62 // optical memory device
69 // medium change device
84 USBSTOR_GetGenericType(
85 IN PUFI_INQUIRY_RESPONSE InquiryData
)
88 // check if device type is zero
90 if (InquiryData
->DeviceType
== 0)
93 // direct access device
97 // FIXME: check if floppy
103 // FIXME: use constant - derrived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
105 switch (InquiryData
->DeviceType
)
110 // sequential device, i.e magnetic tape
112 return "GenSequential";
131 // optical memory device
138 // medium change device
147 return "UsbstorOther";
161 for(Index
= 0; Index
< MaxLength
; Index
++)
163 if (Name
[Index
] <= ' ' || Name
[Index
] >= 0x7F /* last printable ascii character */ || Name
[Index
] == ',')
166 // convert to underscore
173 // just copy character
175 Buffer
[Index
] = Name
[Index
];
183 USBSTOR_PdoHandleQueryDeviceText(
184 IN PDEVICE_OBJECT DeviceObject
,
187 //PPDO_DEVICE_EXTENSION DeviceExtension;
188 PIO_STACK_LOCATION IoStack
;
190 static WCHAR DeviceText
[] = L
"USB Mass Storage Device";
193 // get current stack location
195 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
197 if (IoStack
->Parameters
.QueryDeviceText
.DeviceTextType
== DeviceTextDescription
)
199 DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextDescription\n");
204 Buffer
= (LPWSTR
)AllocateItem(PagedPool
, sizeof(DeviceText
));
210 Irp
->IoStatus
.Information
= 0;
211 return STATUS_INSUFFICIENT_RESOURCES
;
217 wcscpy(Buffer
, DeviceText
);
222 Irp
->IoStatus
.Information
= (ULONG_PTR
)Buffer
;
223 return STATUS_SUCCESS
;
227 DPRINT("USBSTOR_PdoHandleQueryDeviceText DeviceTextLocationInformation\n");
232 Buffer
= (LPWSTR
)AllocateItem(PagedPool
, sizeof(DeviceText
));
238 Irp
->IoStatus
.Information
= 0;
239 return STATUS_INSUFFICIENT_RESOURCES
;
245 wcscpy(Buffer
, DeviceText
);
250 Irp
->IoStatus
.Information
= (ULONG_PTR
)Buffer
;
251 return STATUS_SUCCESS
;
258 USBSTOR_PdoHandleQueryDeviceId(
259 IN PDEVICE_OBJECT DeviceObject
,
262 PPDO_DEVICE_EXTENSION DeviceExtension
;
267 PUFI_INQUIRY_RESPONSE InquiryData
;
268 ANSI_STRING AnsiString
;
269 UNICODE_STRING DeviceId
;
272 // get device extension
274 DeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
279 ASSERT(DeviceExtension
->InquiryData
);
284 InquiryData
= (PUFI_INQUIRY_RESPONSE
)DeviceExtension
->InquiryData
;
289 DeviceType
= USBSTOR_GetDeviceType(InquiryData
);
294 RtlZeroMemory(Buffer
, sizeof(Buffer
));
297 // lets create device string
299 Offset
= sprintf(&Buffer
[Offset
], "USBSTOR\\");
300 Offset
+= sprintf(&Buffer
[Offset
], DeviceType
);
301 Offset
+= sprintf(&Buffer
[Offset
], "&Ven_");
302 Offset
+= CopyField(InquiryData
->Vendor
, &Buffer
[Offset
], 8);
303 Offset
+= sprintf(&Buffer
[Offset
], "&Prod_");
304 Offset
+= CopyField(InquiryData
->Product
, &Buffer
[Offset
], 16);
305 Offset
+= sprintf(&Buffer
[Offset
], "&Rev_");
306 Offset
+= CopyField(InquiryData
->Revision
, &Buffer
[Offset
], 4);
309 // now initialize ansi string
311 RtlInitAnsiString(&AnsiString
, (PCSZ
)Buffer
);
314 // allocate DeviceId string
317 DeviceId
.MaximumLength
= (strlen((PCHAR
)Buffer
) + 1) * sizeof(WCHAR
);
318 DeviceId
.Buffer
= (LPWSTR
)AllocateItem(PagedPool
, DeviceId
.MaximumLength
);
319 if (!DeviceId
.Buffer
)
324 Irp
->IoStatus
.Information
= 0;
325 return STATUS_INSUFFICIENT_RESOURCES
;
330 // convert to unicode
332 Status
= RtlAnsiStringToUnicodeString(&DeviceId
, &AnsiString
, FALSE
);
334 if (NT_SUCCESS(Status
))
339 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceId
.Buffer
;
342 DPRINT("DeviceId %wZ Status %x\n", &DeviceId
, Status
);
351 USBSTOR_ConvertToUnicodeString(
353 IN ULONG ResultBufferLength
,
354 IN ULONG ResultBufferOffset
,
355 OUT LPWSTR ResultBuffer
,
356 OUT PULONG NewResultBufferOffset
)
358 UNICODE_STRING DeviceString
;
359 ANSI_STRING AnsiString
;
362 ASSERT(ResultBufferLength
);
363 ASSERT(ResultBufferLength
> ResultBufferOffset
);
365 DPRINT("ResultBufferOffset %lu ResultBufferLength %lu Buffer %s Length %lu\n", ResultBufferOffset
, ResultBufferLength
, Buffer
, strlen(Buffer
));
368 // construct destination string
370 DeviceString
.Buffer
= &ResultBuffer
[ResultBufferOffset
];
371 DeviceString
.Length
= 0;
372 DeviceString
.MaximumLength
= (ResultBufferLength
- ResultBufferOffset
) * sizeof(WCHAR
);
375 // initialize source string
377 RtlInitAnsiString(&AnsiString
, Buffer
);
380 // convert to unicode
382 Status
= RtlAnsiStringToUnicodeString(&DeviceString
, &AnsiString
, FALSE
);
383 ASSERT(Status
== STATUS_SUCCESS
);
386 // subtract consumed bytes
388 ResultBufferLength
-= (DeviceString
.Length
+ sizeof(WCHAR
)) / sizeof(WCHAR
);
389 ResultBufferOffset
+= (DeviceString
.Length
+ sizeof(WCHAR
)) / sizeof(WCHAR
);
394 *NewResultBufferOffset
= ResultBufferOffset
;
400 USBSTOR_PdoHandleQueryHardwareId(
401 IN PDEVICE_OBJECT DeviceObject
,
404 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
405 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
406 LPCSTR GenericType
, DeviceType
;
408 CHAR Id1
[50], Id2
[50], Id3
[50], Id4
[50], Id5
[50], Id6
[50];
409 ULONG Id1Length
, Id2Length
, Id3Length
, Id4Length
, Id5Length
,Id6Length
;
410 ULONG Offset
, TotalLength
, Length
;
411 PUFI_INQUIRY_RESPONSE InquiryData
;
414 // get PDO device extension
416 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
419 // get FDO device extension
421 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)PDODeviceExtension
->LowerDeviceObject
->DeviceExtension
;
426 ASSERT(FDODeviceExtension
->DeviceDescriptor
);
431 InquiryData
= (PUFI_INQUIRY_RESPONSE
)PDODeviceExtension
->InquiryData
;
435 // get device type and generic type
437 DeviceType
= USBSTOR_GetDeviceType(InquiryData
);
438 GenericType
= USBSTOR_GetGenericType(InquiryData
);
444 // USBSTOR\SCSIType_Vendor(8)_Product(16)_Revision(4)
446 RtlZeroMemory(Id1
, sizeof(Id1
));
448 Offset
= sprintf(&Id1
[Offset
], "USBSTOR\\");
449 Offset
+= sprintf(&Id1
[Offset
], DeviceType
);
450 Offset
+= CopyField(InquiryData
->Vendor
, &Id1
[Offset
], 8);
451 Offset
+= CopyField(InquiryData
->Product
, &Id1
[Offset
], 16);
452 Offset
+= CopyField(InquiryData
->Revision
, &Id1
[Offset
], 4);
453 Id1Length
= strlen(Id1
) + 1;
454 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId1 %s\n", Id1
);
458 // USBSTOR\SCSIType_VENDOR(8)_Product(16)
460 RtlZeroMemory(Id2
, sizeof(Id2
));
462 Offset
= sprintf(&Id2
[Offset
], "USBSTOR\\");
463 Offset
+= sprintf(&Id2
[Offset
], DeviceType
);
464 Offset
+= CopyField(InquiryData
->Vendor
, &Id2
[Offset
], 8);
465 Offset
+= CopyField(InquiryData
->Product
, &Id2
[Offset
], 16);
466 Id2Length
= strlen(Id2
) + 1;
467 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId2 %s\n", Id2
);
471 // USBSTOR\SCSIType_VENDOR(8)
473 RtlZeroMemory(Id3
, sizeof(Id3
));
475 Offset
= sprintf(&Id3
[Offset
], "USBSTOR\\");
476 Offset
+= sprintf(&Id3
[Offset
], DeviceType
);
477 Offset
+= CopyField(InquiryData
->Vendor
, &Id3
[Offset
], 8);
478 Id3Length
= strlen(Id3
) + 1;
479 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId3 %s\n", Id3
);
483 // USBSTOR\SCSIType_VENDOR(8)_Product(16)_Revision(1)
485 RtlZeroMemory(Id4
, sizeof(Id4
));
487 Offset
= sprintf(&Id4
[Offset
], "USBSTOR\\");
488 Offset
+= sprintf(&Id4
[Offset
], DeviceType
);
489 Offset
+= CopyField(InquiryData
->Vendor
, &Id4
[Offset
], 8);
490 Offset
+= CopyField(InquiryData
->Product
, &Id4
[Offset
], 16);
491 Offset
+= CopyField(InquiryData
->Revision
, &Id4
[Offset
], 1);
492 Id4Length
= strlen(Id4
) + 1;
493 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId4 %s\n", Id4
);
499 RtlZeroMemory(Id5
, sizeof(Id5
));
501 Offset
= sprintf(&Id5
[Offset
], "USBSTOR\\");
502 Offset
+= sprintf(&Id5
[Offset
], GenericType
);
503 Id5Length
= strlen(Id5
) + 1;
504 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId5 %s\n", Id5
);
510 RtlZeroMemory(Id6
, sizeof(Id6
));
512 Offset
= sprintf(&Id6
[Offset
], GenericType
);
513 Id6Length
= strlen(Id6
) + 1;
514 DPRINT("USBSTOR_PdoHandleQueryHardwareId HardwareId6 %s\n", Id6
);
517 // compute total length
519 TotalLength
= Id1Length
+ Id2Length
+ Id3Length
+ Id4Length
+ Id5Length
+ Id6Length
+ 1;
524 Buffer
= (LPWSTR
)AllocateItem(PagedPool
, TotalLength
* sizeof(WCHAR
));
530 Irp
->IoStatus
.Information
= 0;
531 return STATUS_INSUFFICIENT_RESOURCES
;
538 Length
= TotalLength
;
540 USBSTOR_ConvertToUnicodeString(Id1
, Length
, Offset
, Buffer
, &Offset
);
541 USBSTOR_ConvertToUnicodeString(Id2
, Length
, Offset
, Buffer
, &Offset
);
542 USBSTOR_ConvertToUnicodeString(Id3
, Length
, Offset
, Buffer
, &Offset
);
543 USBSTOR_ConvertToUnicodeString(Id4
, Length
, Offset
, Buffer
, &Offset
);
544 USBSTOR_ConvertToUnicodeString(Id5
, Length
, Offset
, Buffer
, &Offset
);
545 USBSTOR_ConvertToUnicodeString(Id6
, Length
, Offset
, Buffer
, &Offset
);
550 ASSERT(Offset
+ 1 == Length
);
555 Irp
->IoStatus
.Information
= (ULONG_PTR
)Buffer
;
560 return STATUS_SUCCESS
;
564 USBSTOR_PdoHandleQueryCompatibleId(
565 IN PDEVICE_OBJECT DeviceObject
,
568 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
569 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
571 ULONG Length
, Offset
;
576 // get PDO device extension
578 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
581 // get FDO device extension
583 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)PDODeviceExtension
->LowerDeviceObject
->DeviceExtension
;
588 ASSERT(FDODeviceExtension
->DeviceDescriptor
);
591 // get target device type
593 DeviceType
= USBSTOR_GetDeviceType((PUFI_INQUIRY_RESPONSE
)PDODeviceExtension
->InquiryData
);
598 RtlZeroMemory(Buffer
, sizeof(Buffer
));
601 // format instance id
603 Length
= sprintf(Buffer
, "USBSTOR\\%s", DeviceType
) + 1;
604 Length
+= sprintf(&Buffer
[Length
], "USBSTOR\\%s", "RAW") + 2;
607 // allocate instance id
609 InstanceId
= (LPWSTR
)AllocateItem(PagedPool
, Length
* sizeof(WCHAR
));
615 Irp
->IoStatus
.Information
= 0;
616 return STATUS_INSUFFICIENT_RESOURCES
;
619 USBSTOR_ConvertToUnicodeString(Buffer
, Length
, 0, InstanceId
, &Offset
);
620 USBSTOR_ConvertToUnicodeString(&Buffer
[Offset
], Length
, Offset
, InstanceId
, &Offset
);
622 DPRINT("USBSTOR_PdoHandleQueryCompatibleId %S\n", InstanceId
);
627 Irp
->IoStatus
.Information
= (ULONG_PTR
)InstanceId
;
630 // completed successfully
632 return STATUS_SUCCESS
;
636 USBSTOR_PdoHandleQueryInstanceId(
637 IN PDEVICE_OBJECT DeviceObject
,
640 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
641 PFDO_DEVICE_EXTENSION FDODeviceExtension
;
647 // get PDO device extension
649 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
652 // get FDO device extension
654 FDODeviceExtension
= (PFDO_DEVICE_EXTENSION
)PDODeviceExtension
->LowerDeviceObject
->DeviceExtension
;
657 // format instance id
659 if (FDODeviceExtension
->SerialNumber
)
662 // using serial number from device
664 swprintf(Buffer
, L
"%s&%d", FDODeviceExtension
->SerialNumber
->bString
, PDODeviceExtension
->LUN
);
669 // FIXME: should use some random value
671 swprintf(Buffer
, L
"%s&%d", L
"00000000", PDODeviceExtension
->LUN
);
677 Length
= wcslen(Buffer
) + 1;
680 // allocate instance id
682 InstanceId
= (LPWSTR
)AllocateItem(PagedPool
, Length
* sizeof(WCHAR
));
688 Irp
->IoStatus
.Information
= 0;
689 return STATUS_INSUFFICIENT_RESOURCES
;
695 wcscpy(InstanceId
, Buffer
);
697 DPRINT("USBSTOR_PdoHandleQueryInstanceId %S\n", InstanceId
);
702 Irp
->IoStatus
.Information
= (ULONG_PTR
)InstanceId
;
705 // completed successfully
707 return STATUS_SUCCESS
;
711 USBSTOR_PdoHandleDeviceRelations(
712 IN PDEVICE_OBJECT DeviceObject
,
715 PDEVICE_RELATIONS DeviceRelations
;
716 PIO_STACK_LOCATION IoStack
;
718 DPRINT("USBSTOR_PdoHandleDeviceRelations\n");
721 // get current irp stack location
723 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
726 // check if relation type is BusRelations
728 if (IoStack
->Parameters
.QueryDeviceRelations
.Type
!= TargetDeviceRelation
)
731 // PDO handles only target device relation
733 return Irp
->IoStatus
.Status
;
737 // allocate device relations
739 DeviceRelations
= (PDEVICE_RELATIONS
)AllocateItem(PagedPool
, sizeof(DEVICE_RELATIONS
));
740 if (!DeviceRelations
)
745 return STATUS_INSUFFICIENT_RESOURCES
;
749 // initialize device relations
751 DeviceRelations
->Count
= 1;
752 DeviceRelations
->Objects
[0] = DeviceObject
;
753 ObReferenceObject(DeviceObject
);
758 Irp
->IoStatus
.Information
= (ULONG_PTR
)DeviceRelations
;
761 // completed successfully
763 return STATUS_SUCCESS
;
768 USBSTOR_PdoHandlePnp(
769 IN PDEVICE_OBJECT DeviceObject
,
772 PIO_STACK_LOCATION IoStack
;
773 PPDO_DEVICE_EXTENSION DeviceExtension
;
775 PDEVICE_CAPABILITIES Caps
;
779 // get current stack location
781 IoStack
= IoGetCurrentIrpStackLocation(Irp
);
784 // get device extension
786 DeviceExtension
= (PPDO_DEVICE_EXTENSION
)DeviceObject
->DeviceExtension
;
791 ASSERT(DeviceExtension
->Common
.IsFDO
== FALSE
);
793 switch(IoStack
->MinorFunction
)
795 case IRP_MN_QUERY_DEVICE_RELATIONS
:
797 Status
= USBSTOR_PdoHandleDeviceRelations(DeviceObject
, Irp
);
800 case IRP_MN_QUERY_DEVICE_TEXT
:
802 Status
= USBSTOR_PdoHandleQueryDeviceText(DeviceObject
, Irp
);
805 case IRP_MN_QUERY_ID
:
807 if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryDeviceID
)
810 // handle query device id
812 Status
= USBSTOR_PdoHandleQueryDeviceId(DeviceObject
, Irp
);
815 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryHardwareIDs
)
818 // handle instance id
820 Status
= USBSTOR_PdoHandleQueryHardwareId(DeviceObject
, Irp
);
823 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryInstanceID
)
826 // handle instance id
828 Status
= USBSTOR_PdoHandleQueryInstanceId(DeviceObject
, Irp
);
831 else if (IoStack
->Parameters
.QueryId
.IdType
== BusQueryCompatibleIDs
)
834 // handle instance id
836 Status
= USBSTOR_PdoHandleQueryCompatibleId(DeviceObject
, Irp
);
840 DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack
->Parameters
.QueryId
.IdType
);
841 Status
= STATUS_NOT_SUPPORTED
;
842 Irp
->IoStatus
.Information
= 0;
845 case IRP_MN_REMOVE_DEVICE
:
847 DPRINT("IRP_MN_REMOVE_DEVICE\n");
849 if(*DeviceExtension
->PDODeviceObject
!= NULL
)
852 // clear entry in FDO pdo list
854 *DeviceExtension
->PDODeviceObject
= NULL
;
860 // device object already marked for deletion
865 /* Complete the IRP */
866 Irp
->IoStatus
.Status
= STATUS_SUCCESS
;
867 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
871 /* Delete the device object */
872 IoDeleteDevice(DeviceObject
);
874 return STATUS_SUCCESS
;
876 case IRP_MN_QUERY_CAPABILITIES
:
879 // just forward irp to lower device
881 Status
= USBSTOR_SyncForwardIrp(DeviceExtension
->LowerDeviceObject
, Irp
);
882 ASSERT(Status
== STATUS_SUCCESS
);
884 if (NT_SUCCESS(Status
))
887 // check if no unique id
889 Caps
= (PDEVICE_CAPABILITIES
)IoStack
->Parameters
.DeviceCapabilities
.Capabilities
;
890 Caps
->UniqueID
= TRUE
; //FIXME
891 Caps
->Removable
= TRUE
; //FIXME
895 case IRP_MN_QUERY_REMOVE_DEVICE
:
896 case IRP_MN_QUERY_STOP_DEVICE
:
899 // if we're not claimed it's ok
901 if (DeviceExtension
->Claimed
)
903 Status
= STATUS_UNSUCCESSFUL
;
904 DPRINT1("[USBSTOR] Request %x fails because device is still claimed\n", IoStack
->MinorFunction
);
907 Status
= STATUS_SUCCESS
;
910 case IRP_MN_START_DEVICE
:
915 Status
= STATUS_SUCCESS
;
923 Status
= Irp
->IoStatus
.Status
;
930 if (Status
!= STATUS_PENDING
)
935 Irp
->IoStatus
.Status
= Status
;
940 IoCompleteRequest(Irp
, IO_NO_INCREMENT
);
951 IN PDEVICE_OBJECT DeviceObject
,
952 OUT PDEVICE_OBJECT
*ChildDeviceObject
)
956 PPDO_DEVICE_EXTENSION PDODeviceExtension
;
959 // create child device object
961 Status
= IoCreateDevice(DeviceObject
->DriverObject
, sizeof(PDO_DEVICE_EXTENSION
), NULL
, FILE_DEVICE_MASS_STORAGE
, FILE_AUTOGENERATED_DEVICE_NAME
| FILE_DEVICE_SECURE_OPEN
, FALSE
, &PDO
);
962 if (!NT_SUCCESS(Status
))
965 // failed to create device
971 // patch the stack size
973 PDO
->StackSize
= DeviceObject
->StackSize
;
976 // get device extension
978 PDODeviceExtension
= (PPDO_DEVICE_EXTENSION
)PDO
->DeviceExtension
;
981 // initialize device extension
983 RtlZeroMemory(PDODeviceExtension
, sizeof(PDO_DEVICE_EXTENSION
));
984 PDODeviceExtension
->Common
.IsFDO
= FALSE
;
985 PDODeviceExtension
->LowerDeviceObject
= DeviceObject
;
986 PDODeviceExtension
->PDODeviceObject
= ChildDeviceObject
;
991 PDO
->Flags
|= DO_DIRECT_IO
| DO_MAP_IO_BUFFER
;
994 // device is initialized
996 PDO
->Flags
&= ~DO_DEVICE_INITIALIZING
;
999 // output device object
1001 *ChildDeviceObject
= PDO
;
1003 USBSTOR_SendInquiryCmd(PDO
);