mirror of
https://github.com/reactos/reactos.git
synced 2024-10-15 13:45:58 +00:00
7821a805ef
- 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
407 lines
10 KiB
C
407 lines
10 KiB
C
/*
|
|
* 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;
|
|
}
|