[USBSTOR]

- Implement retrieving string device type from SCSI device type
- Handle BusQueryDeviceId
- Implement support routines for sending CBW / CSW / Data
- Implement retrieving device type (SCSI inquiry request)
- WIP

svn path=/branches/usb-bringup/; revision=51567
This commit is contained in:
Johannes Anderwald 2011-05-03 19:40:03 +00:00
parent 991d02daa5
commit 7821a805ef
5 changed files with 714 additions and 5 deletions

View file

@ -3,7 +3,7 @@ add_definitions(-DDEBUG_MODE)
include_directories(${REACTOS_SOURCE_DIR}/ntoskrnl/include)
add_library(usbstor SHARED descriptor.c fdo.c misc.c pdo.c usbstor.c usbstor.rc)
add_library(usbstor SHARED descriptor.c fdo.c misc.c pdo.c scsi.c usbstor.c usbstor.rc)
set_module_type(usbstor kernelmodedriver)
add_importlibs(usbstor ntoskrnl hal usbd)

View file

@ -11,6 +11,221 @@
#include "usbstor.h"
LPCSTR
USBSTOR_GetDeviceType(
IN PUFI_INQUIRY_RESPONSE InquiryData)
{
//
// check if device type is zero
//
if (InquiryData->DeviceType == 0)
{
//
// direct access device
//
//
// FIXME: check if floppy
//
return "Disk";
}
//
// FIXME: use constant - derrived from http://en.wikipedia.org/wiki/SCSI_Peripheral_Device_Type
//
switch (InquiryData->DeviceType)
{
case 1:
{
//
// sequential device, i.e magnetic tape
//
return "Sequential";
}
case 4:
{
//
// write once device
//
return "Worm";
}
case 5:
{
//
// CDROM device
//
return "CdRom";
}
case 7:
{
//
// optical memory device
//
return "Optical";
}
case 8:
{
//
// medium change device
//
return "Changer";
}
default:
{
//
// other device
//
return "CdRom";
}
}
}
ULONG
CopyField(
IN PUCHAR Name,
IN PUCHAR Buffer,
IN ULONG MaxLength)
{
ULONG Index;
for(Index = 0; Index < MaxLength; Index++)
{
if (Name[Index] == '\0')
return Index;
Buffer[Index] = Name[Index];
}
return MaxLength;
}
NTSTATUS
USBSTOR_PdoHandleQueryDeviceId(
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp)
{
PPDO_DEVICE_EXTENSION DeviceExtension;
NTSTATUS Status;
UCHAR Buffer[100];
LPCSTR DeviceType;
ULONG Offset = 0, Index;
PUFI_INQUIRY_RESPONSE InquiryData;
ANSI_STRING AnsiString;
UNICODE_STRING DeviceId;
//
// get device extension
//
DeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// sanity check
//
ASSERT(DeviceExtension->InquiryData);
//
// get inquiry data
//
InquiryData = (PUFI_INQUIRY_RESPONSE)DeviceExtension->InquiryData;
//
// get device type
//
DeviceType = USBSTOR_GetDeviceType(InquiryData);
//
// lets create device string
//
Offset = sprintf(&Buffer[Offset], "USBSTOR\\%s&Ven_", DeviceType);
//
// copy vendor id
//
Offset += CopyField(InquiryData->Vendor, &Buffer[Offset], 8);
//
// copy product string
//
Offset += sprintf(&Buffer[Offset], "&Prod_");
//
// copy product identifier
//
Offset += CopyField(InquiryData->Product, &Buffer[Offset], 16);
//
// copy revision string
//
Offset += sprintf(&Buffer[Offset], "&Rev_");
//
// copy revision identifer
//
Offset += CopyField(InquiryData->Revision, &Buffer[Offset], 4);
//
// FIXME: device serial number
//
Offset +=sprintf(&Buffer[Offset], "\\00000000&%d", DeviceExtension->LUN);
//
// now convert restricted characters to underscores
//
for(Index = 0; Index < Offset; Index++)
{
if (Buffer[Index] <= ' ' || Buffer[Index] >= 0x7F /* last printable ascii character */ || Buffer[Index] == ',')
{
//
// convert to underscore
//
Buffer[Index] = '_';
}
}
//
// now initialize ansi string
//
RtlInitAnsiString(&AnsiString, (PCSZ)Buffer);
//
// allocate DeviceId string
//
DeviceId.Length = 0;
DeviceId.MaximumLength = (Offset + 2) * sizeof(WCHAR);
DeviceId.Buffer = (LPWSTR)AllocateItem(PagedPool, DeviceId.MaximumLength);
if (!DeviceId.Buffer)
{
//
// no memory
//
Irp->IoStatus.Information = 0;
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// convert to unicode
//
Status = RtlAnsiStringToUnicodeString(&DeviceId, &AnsiString, FALSE);
if (NT_SUCCESS(Status))
{
//
// store result
//
Irp->IoStatus.Information = (ULONG_PTR)DeviceId.Buffer;
}
DPRINT1("DeviceId %wZ\n", &DeviceId);
//
// done
//
return Status;
}
NTSTATUS
USBSTOR_PdoHandleDeviceRelations(
IN PDEVICE_OBJECT DeviceObject,
@ -102,9 +317,20 @@ USBSTOR_PdoHandlePnp(
Status = STATUS_NOT_SUPPORTED;
break;
case IRP_MN_QUERY_ID:
DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_QUERY_ID unimplemented\n");
{
if (IoStack->Parameters.QueryId.IdType == BusQueryDeviceID)
{
//
// handle query device id
//
Status = USBSTOR_PdoHandleQueryDeviceId(DeviceObject, Irp);
break;
}
DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_QUERY_ID IdType %x unimplemented\n", IoStack->Parameters.QueryId.IdType);
Status = STATUS_NOT_SUPPORTED;
break;
}
case IRP_MN_REMOVE_DEVICE:
DPRINT1("USBSTOR_PdoHandlePnp: IRP_MN_REMOVE_DEVICE unimplemented\n");
Status = STATUS_SUCCESS;
@ -209,6 +435,8 @@ USBSTOR_CreatePDO(
//
*ChildDeviceObject = PDO;
USBSTOR_SendInquiryCmd(PDO);
//
// done
//

406
drivers/usb/usbstor/scsi.c Normal file
View file

@ -0,0 +1,406 @@
/*
* PROJECT: ReactOS Universal Serial Bus Bulk Storage Driver
* LICENSE: GPL - See COPYING in the top level directory
* FILE: drivers/usb/usbstor/pdo.c
* PURPOSE: USB block storage device driver.
* PROGRAMMERS:
* James Tabor
* Michael Martin (michael.martin@reactos.org)
* Johannes Anderwald (johannes.anderwald@reactos.org)
*/
#include "usbstor.h"
NTSTATUS
USBSTOR_BuildCBW(
IN ULONG Tag,
IN ULONG DataTransferLength,
IN UCHAR LUN,
IN UCHAR CommandBlockLength,
IN PUCHAR CommandBlock,
IN OUT PCBW Control)
{
//
// sanity check
//
ASSERT(CommandBlockLength <= 16);
//
// now initialize CBW
//
Control->Signature = CBW_SIGNATURE;
Control->Tag = Tag;
Control->DataTransferLength = DataTransferLength;
Control->Flags = 0x80;
Control->LUN = (LUN & MAX_LUN);
Control->CommandBlockLength = CommandBlockLength;
//
// copy command block
//
RtlCopyMemory(Control->CommandBlock, CommandBlock, CommandBlockLength);
//
// done
//
return STATUS_SUCCESS;
}
NTSTATUS
USBSTOR_SendCBW(
IN PDEVICE_OBJECT DeviceObject,
IN UCHAR CommandBlockLength,
IN PUCHAR CommandBlock,
IN ULONG DataTransferLength,
OUT PCBW *OutControl)
{
PCBW Control;
NTSTATUS Status;
PURB Urb;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// get FDO device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
//
// first allocate CBW
//
Control = (PCBW)AllocateItem(NonPagedPool, 512);
if (!Control)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// first allocate CBW
//
Status = USBSTOR_BuildCBW(0xDEADDEAD, DataTransferLength, PDODeviceExtension->LUN, CommandBlockLength, CommandBlock, Control);
if (!NT_SUCCESS(Status))
{
//
// failed to build CBW
//
return Status;
}
//
// now build the urb
//
Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
if (!Urb)
{
//
// failed to allocate urb
//
FreeItem(Control);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// now initialize the urb
//
Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkOutPipeIndex].PipeHandle;
Urb->UrbBulkOrInterruptTransfer.TransferBuffer = (PVOID)Control;
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = sizeof(CBW);
Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_OUT | USBD_SHORT_TRANSFER_OK;
//
// now send urb
//
Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
//
// free urb
//
FreeItem(Urb);
//
// store cbw
//
*OutControl = Control;
//
// return operation status
//
return Status;
}
NTSTATUS
USBSTOR_SendData(
IN PDEVICE_OBJECT DeviceObject,
IN ULONG DataTransferLength,
IN PVOID DataTransfer)
{
PMDL TransferBufferMDL;
PURB Urb;
NTSTATUS Status;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// get FDO device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
//
// allocate mdl for buffer, buffer must be allocated from NonPagedPool
//
TransferBufferMDL = IoAllocateMdl(DataTransfer, DataTransferLength, FALSE, FALSE, NULL);
if (!TransferBufferMDL)
{
//
// failed to allocate MDL
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// build mdl for nonpaged pool
//
MmBuildMdlForNonPagedPool(TransferBufferMDL);
//
// now build the urb
//
Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
if (!Urb)
{
//
// failed to allocate urb
//
IoFreeMdl(TransferBufferMDL);
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// now initialize the urb
//
Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle;
Urb->UrbBulkOrInterruptTransfer.TransferBufferMDL = TransferBufferMDL;
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DataTransferLength;
Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
//
// now send urb
//
Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
//
// free urb
//
FreeItem(Urb);
//
// free mdl
//
IoFreeMdl(TransferBufferMDL);
//
// done
//
return Status;
}
NTSTATUS
USBSTOR_SendCSW(
IN PDEVICE_OBJECT DeviceObject,
IN PVOID Data,
IN ULONG DataLength,
OUT PCSW OutCSW)
{
NTSTATUS Status;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PFDO_DEVICE_EXTENSION FDODeviceExtension;
PURB Urb;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// get FDO device extension
//
FDODeviceExtension = (PFDO_DEVICE_EXTENSION)PDODeviceExtension->LowerDeviceObject->DeviceExtension;
//
// now build the urb
//
Urb = (PURB)AllocateItem(NonPagedPool, sizeof(URB));
if (!Urb)
{
//
// failed to allocate urb
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// now initialize the urb
//
Urb->UrbBulkOrInterruptTransfer.Hdr.Length = sizeof(URB);
Urb->UrbBulkOrInterruptTransfer.Hdr.Function = URB_FUNCTION_BULK_OR_INTERRUPT_TRANSFER;
Urb->UrbBulkOrInterruptTransfer.PipeHandle = FDODeviceExtension->InterfaceInformation->Pipes[FDODeviceExtension->BulkInPipeIndex].PipeHandle;
Urb->UrbBulkOrInterruptTransfer.TransferBuffer = Data;
Urb->UrbBulkOrInterruptTransfer.TransferBufferLength = DataLength;
Urb->UrbBulkOrInterruptTransfer.TransferFlags = USBD_TRANSFER_DIRECTION_IN | USBD_SHORT_TRANSFER_OK;
//
// now send urb
//
Status = USBSTOR_SyncUrbRequest(FDODeviceExtension->LowerDeviceObject, Urb);
if (NT_SUCCESS(Status))
{
//
// copy csw status
//
RtlCopyMemory(OutCSW, Data, sizeof(CSW));
}
//
// free urb
//
FreeItem(Urb);
//
// done
//
return Status;
}
NTSTATUS
USBSTOR_SendInquiryCmd(
IN PDEVICE_OBJECT DeviceObject)
{
UFI_INQUIRY_CMD Cmd;
CSW CSW;
NTSTATUS Status;
PUFI_INQUIRY_RESPONSE Response;
PPDO_DEVICE_EXTENSION PDODeviceExtension;
PCBW OutControl;
//
// get PDO device extension
//
PDODeviceExtension = (PPDO_DEVICE_EXTENSION)DeviceObject->DeviceExtension;
//
// allocate inquiry response
//
Response = (PUFI_INQUIRY_RESPONSE)AllocateItem(NonPagedPool, sizeof(UFI_INQUIRY_RESPONSE));
if (!Response)
{
//
// no memory
//
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// initialize inquiry cmd
//
RtlZeroMemory(&Cmd, sizeof(UFI_INQUIRY_CMD));
Cmd.Code = UFI_INQURIY_CODE;
Cmd.LUN = (PDODeviceExtension->LUN & MAX_LUN);
Cmd.AllocationLength = sizeof(UFI_INQUIRY_RESPONSE);
//
// now send inquiry cmd
//
Status = USBSTOR_SendCBW(DeviceObject, UFI_INQUIRY_CMD_LEN, (PUCHAR)&Cmd, sizeof(UFI_INQUIRY_RESPONSE), &OutControl);
if (!NT_SUCCESS(Status))
{
//
// failed to send CBW
//
DPRINT1("USBSTOR_SendInquiryCmd> USBSTOR_SendCBW failed with %x\n", Status);
FreeItem(Response);
ASSERT(FALSE);
return Status;
}
//
// now send inquiry response
//
Status = USBSTOR_SendData(DeviceObject, sizeof(UFI_INQUIRY_RESPONSE), Response);
if (!NT_SUCCESS(Status))
{
//
// failed to send CBW
//
DPRINT1("USBSTOR_SendInquiryCmd> USBSTOR_SendData failed with %x\n", Status);
FreeItem(Response);
ASSERT(FALSE);
return Status;
}
DPRINT1("Response %p\n", Response);
DPRINT1("DeviceType %x\n", Response->DeviceType);
DPRINT1("RMB %x\n", Response->RMB);
DPRINT1("Version %x\n", Response->Version);
DPRINT1("Format %x\n", Response->Format);
DPRINT1("Length %x\n", Response->Length);
DPRINT1("Reserved %x\n", Response->Reserved);
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]);
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],
Response->Product[4], Response->Product[5], Response->Product[6], Response->Product[7],
Response->Product[8], Response->Product[9], Response->Product[10], Response->Product[11],
Response->Product[12], Response->Product[13], Response->Product[14], Response->Product[15]);
DPRINT1("Revision %c%c%c%c\n", Response->Revision[0], Response->Revision[1], Response->Revision[2], Response->Revision[3]);
//
// send csw
//
Status = USBSTOR_SendCSW(DeviceObject, OutControl, 512, &CSW);
DPRINT1("------------------------\n");
DPRINT1("CSW %p\n", &CSW);
DPRINT1("Signature %x\n", CSW.Signature);
DPRINT1("Tag %x\n", CSW.Tag);
DPRINT1("DataResidue %x\n", CSW.DataResidue);
DPRINT1("Status %x\n", CSW.Status);
//
// free item
//
FreeItem(OutControl);
//
// store inquiry data
//
PDODeviceExtension->InquiryData = (PVOID)Response;
//
// FIXME: handle error
//
ASSERT(CSW.Status == 0);
//
// done
//
return Status;
}

View file

@ -239,9 +239,9 @@ DriverEntry(
DriverObject->DriverExtension->AddDevice = USBSTOR_AddDevice;
//
// driver start i/o routine
// FIXME: driver start i/o routine
//
DriverObject->DriverStartIo = USBSTOR_StartIo;
//DriverObject->DriverStartIo = USBSTOR_StartIo;
//

View file

@ -52,7 +52,8 @@ typedef struct
{
COMMON_DEVICE_EXTENSION Common;
PDEVICE_OBJECT LowerDeviceObject; // points to FDO
UCHAR LUN; // lun id
PVOID InquiryData; // USB SCSI inquiry data
}PDO_DEVICE_EXTENSION, *PPDO_DEVICE_EXTENSION;
@ -61,6 +62,66 @@ typedef struct
//
#define USB_BULK_GET_MAX_LUN 0xFE
typedef struct
{
ULONG Signature; // CBW signature
ULONG Tag; // CBW Tag of operation
ULONG DataTransferLength; // data transfer length
UCHAR Flags; // CBW Flags endpoint direction
UCHAR LUN; // lun unit
UCHAR CommandBlockLength; // Command block length
UCHAR CommandBlock[16];
}CBW, *PCBW;
#define CBW_SIGNATURE 0x43425355
#define MAX_LUN 0xF
typedef struct
{
ULONG Signature; // CSW signature
ULONG Tag; // CSW tag
ULONG DataResidue; // CSW data transfer diff
UCHAR Status; // CSW status
}CSW, *PCSW;
//--------------------------------------------------------------------------------------------------------------------------------------------
//
// UFI INQUIRY command
//
typedef struct
{
UCHAR Code; // operation code 0x12
UCHAR LUN; // lun address
UCHAR PageCode; // product data information, always 0x00
UCHAR Reserved; // reserved 0x00
UCHAR AllocationLength; // length of inquiry data to be returned, default 36 bytes
UCHAR Reserved1[7]; //reserved bytes 0x00
}UFI_INQUIRY_CMD, *PUFI_INQUIRY_CMD;
C_ASSERT(sizeof(UFI_INQUIRY_CMD) == 12);
#define UFI_INQURIY_CODE 0x12
#define UFI_INQUIRY_CMD_LEN 0x6
//
// UFI INQUIRY command response
//
typedef struct
{
UCHAR DeviceType; // device type
UCHAR RMB; // removable media bit
UCHAR Version; // contains version 0x00
UCHAR Format; // response format
UCHAR Length; // additional length
USHORT Reserved; // reserved
UCHAR Vendor[8]; // vendor identification string
UCHAR Product[16]; // product identification string
UCHAR Revision[4]; // product revision code
}UFI_INQUIRY_RESPONSE, *PUFI_INQUIRY_RESPONSE;
C_ASSERT(sizeof(UFI_INQUIRY_RESPONSE) == 36);
//---------------------------------------------------------------------
//
// fdo.c routines
@ -119,6 +180,13 @@ USBSTOR_GetMaxLUN(
IN PDEVICE_OBJECT DeviceObject,
IN PFDO_DEVICE_EXTENSION DeviceExtension);
NTSTATUS
NTAPI
USBSTOR_SyncForwardIrpCompletionRoutine(
PDEVICE_OBJECT DeviceObject,
PIRP Irp,
PVOID Context);
//---------------------------------------------------------------------
//
@ -138,3 +206,10 @@ NTSTATUS
USBSTOR_GetPipeHandles(
IN PFDO_DEVICE_EXTENSION DeviceExtension);
//---------------------------------------------------------------------
//
// scsi.c routines
//
NTSTATUS
USBSTOR_SendInquiryCmd(
IN PDEVICE_OBJECT DeviceObject);