From 587ebbbb92ed0610562ca059121c263e1faa19dd Mon Sep 17 00:00:00 2001 From: John Hodge Date: Sat, 19 May 2012 21:52:03 +0800 Subject: [PATCH] Modules/USB - Added prototype mass storage driver --- BuildConf/x86/default.mk | 2 +- KernelLand/Modules/USB/MSC/Makefile | 10 ++ KernelLand/Modules/USB/MSC/common.h | 28 +++++ KernelLand/Modules/USB/MSC/main.c | 142 +++++++++++++++++++++++++ KernelLand/Modules/USB/MSC/msc_proto.h | 33 ++++++ KernelLand/Modules/USB/MSC/scsi.c | 71 +++++++++++++ KernelLand/Modules/USB/MSC/scsi.h | 42 ++++++++ 7 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 KernelLand/Modules/USB/MSC/Makefile create mode 100644 KernelLand/Modules/USB/MSC/common.h create mode 100644 KernelLand/Modules/USB/MSC/main.c create mode 100644 KernelLand/Modules/USB/MSC/msc_proto.h create mode 100644 KernelLand/Modules/USB/MSC/scsi.c create mode 100644 KernelLand/Modules/USB/MSC/scsi.h diff --git a/BuildConf/x86/default.mk b/BuildConf/x86/default.mk index 51bb9fcd..274e559f 100644 --- a/BuildConf/x86/default.mk +++ b/BuildConf/x86/default.mk @@ -11,5 +11,5 @@ MODULES += x86/ISADMA x86/VGAText MODULES += USB/Core USB/UHCI #USB/OHCI -MODULES += USB/HID +MODULES += USB/HID USB/MSC #MODULES += Interfaces/UDI diff --git a/KernelLand/Modules/USB/MSC/Makefile b/KernelLand/Modules/USB/MSC/Makefile new file mode 100644 index 00000000..bb53fc9c --- /dev/null +++ b/KernelLand/Modules/USB/MSC/Makefile @@ -0,0 +1,10 @@ +# +# Acess2 USB MSC Driver +# + +OBJ = main.o scsi.o +CPPFLAGS = -I../Core/include +NAME = MSC + +-include ../Makefile.tpl + diff --git a/KernelLand/Modules/USB/MSC/common.h b/KernelLand/Modules/USB/MSC/common.h new file mode 100644 index 00000000..f459080c --- /dev/null +++ b/KernelLand/Modules/USB/MSC/common.h @@ -0,0 +1,28 @@ +/* + * Acess2 USB Stack Mass Storage Driver + * - By John Hodge (thePowersGang) + * + * common.h + * - Common header + */ +#ifndef _MSC__COMMON_H_ +#define _MSC__COMMON_H_ + +#include +#include + +typedef struct sMSCInfo tMSCInfo; + +struct sMSCInfo +{ + Uint64 BlockCount; + size_t BlockSize; +}; + +extern void MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data); +extern void MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data); + +extern tLVM_VolType gMSC_SCSI_VolType; +extern Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize); +#endif + diff --git a/KernelLand/Modules/USB/MSC/main.c b/KernelLand/Modules/USB/MSC/main.c new file mode 100644 index 00000000..6d64b7bb --- /dev/null +++ b/KernelLand/Modules/USB/MSC/main.c @@ -0,0 +1,142 @@ +/* + * Acess2 USB Stack Mass Storage Driver + * - By John Hodge (thePowersGang) + * + * main.c + * - Driver Core + */ +#define DEBUG 1 +#define VERSION VER2(0,1) +#include +#include +#include "common.h" +#include "msc_proto.h" + +// === PROTOTYPES === + int MSC_Initialise(char **Arguments); +void MSC_Cleanup(void); +void MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen); +void MSC_DataIn(tUSBInterface *Dev, int EndPt, int Length, void *Data); +// --- Internal Helpers + int MSC_int_CreateCBW(tMSC_CBW *Cbw, int bInput, size_t CmdLen, const void *CmdData, size_t DataLen); +void MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data); +void MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data); + +// === GLOBALS === +MODULE_DEFINE(0, VERSION, USB_MSC, MSC_Initialise, MSC_Cleanup, "USB_Core", NULL); +tUSBDriver gMSC_Driver_BulkOnly = { + .Name = "MSC_BulkOnly", + .Match = {.Class = {0x080050, 0xFF00FF}}, + .Connected = MSC_DeviceConnected, + .MaxEndpoints = 2, + .Endpoints = { + {0x82, MSC_DataIn}, + {0x02, NULL}, + } + }; +int giMSC_NextTag; + +// === CODE === +int MSC_Initialise(char **Arguments) +{ + USB_RegisterDriver( &gMSC_Driver_BulkOnly ); + return 0; +} + +void MSC_Cleanup(void) +{ +} + +void MSC_DeviceConnected(tUSBInterface *Dev, void *Descriptors, size_t DescriptorsLen) +{ + tMSCInfo *info; + // TODO: Get the class code (and hence what command set is in use) + // TODO: Get the maximum packet size too + + info = malloc( sizeof(*info) ); + USB_SetDeviceDataPtr(Dev, info); + + info->BlockCount = MSC_SCSI_GetSize(Dev, &info->BlockSize); + + LVM_AddVolume(&gMSC_SCSI_VolType, "0", Dev, info->BlockSize, info->BlockCount); +} + +void MSC_DataIn(tUSBInterface *Dev, int EndPt, int Length, void *Data) +{ + // Will this ever be needed? +} + +int MSC_int_CreateCBW(tMSC_CBW *Cbw, int bInput, size_t CmdLen, const void *CmdData, size_t DataLen) +{ + if( CmdLen == 0 ) { + Log_Error("MSC", "Zero length commands are invalid"); + return -1; + } + + if( CmdLen > 16 ) { + Log_Error("MSC", "Command data >16 bytes (%i)", CmdLen); + return -1; + } + + Cbw->dCBWSignature = LittleEndian32(0x43425355); + Cbw->dCBWTag = giMSC_NextTag ++; + Cbw->dCBWDataTransferLength = LittleEndian32(DataLen); + Cbw->bmCBWFlags = (bInput ? 0x80 : 0x00); + Cbw->bCBWLUN = 0; // TODO: Logical Unit Number (param from proto) + Cbw->bCBWLength = CmdLen; + memcpy(Cbw->CBWCB, CmdData, CmdLen); + + return 0; +} + +void MSC_SendData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, const void *Data) +{ + tMSC_CBW cbw; + tMSC_CSW csw; + const int endpoint_out = 2; + const int endpoint_in = 1; + const int max_packet_size = 64; + + if( MSC_int_CreateCBW(&cbw, 0, CmdLen, CmdData, DataLen) ) + return ; + + // Send CBW + USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw); + + // Send Data + for( size_t ofs = 0; ofs < DataLen; ofs += max_packet_size ) + { + USB_SendData(Dev, endpoint_out, MIN(max_packet_size, DataLen - ofs), Data + ofs); + } + + // Read CSW + USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw); + // TODO: Validate CSW +} + +void MSC_RecvData(tUSBInterface *Dev, size_t CmdLen, const void *CmdData, size_t DataLen, void *Data) +{ + tMSC_CBW cbw; + tMSC_CSW csw; + const int endpoint_out = 2; + const int endpoint_in = 1; + const int max_packet_size = 64; + + if( MSC_int_CreateCBW(&cbw, 1, CmdLen, CmdData, DataLen) ) + return ; + + // Send CBW + USB_SendData(Dev, endpoint_out, sizeof(cbw), &cbw); + + // Read Data + for( size_t ofs = 0; ofs < DataLen; ofs += max_packet_size ) + { + // TODO: use async version and wait for the transaction to complete + USB_RecvData(Dev, endpoint_in, MIN(max_packet_size, DataLen - ofs), Data + ofs); + } + + // Read CSW + USB_RecvData(Dev, endpoint_in, sizeof(csw), &csw); + // TODO: Validate CSW +} + diff --git a/KernelLand/Modules/USB/MSC/msc_proto.h b/KernelLand/Modules/USB/MSC/msc_proto.h new file mode 100644 index 00000000..913822fd --- /dev/null +++ b/KernelLand/Modules/USB/MSC/msc_proto.h @@ -0,0 +1,33 @@ +/* + * Acess2 USB Stack Mass Storage Driver + * - By John Hodge (thePowersGang) + * + * main.c + * - Driver Core + */ +#ifndef _MSC__MSC_PROTO_H_ +#define _MSC__MSC_PROTO_H_ + +typedef struct sMSC_CBW tMSC_CBW; +typedef struct sMSC_CSW tMSC_CSW; + +struct sMSC_CBW +{ + Uint32 dCBWSignature; // = 0x43425355 + Uint32 dCBWTag; + Uint32 dCBWDataTransferLength; + Uint8 bmCBWFlags; + Uint8 bCBWLUN; + Uint8 bCBWLength; + Uint8 CBWCB[16]; +}; + +struct sMSC_CSW +{ + Uint32 dCSWSignature; // = 0x53425355 + Uint32 dCSWTag; + Uint32 dCSWDataResidue; + Uint8 dCSWStatus; +}; + +#endif diff --git a/KernelLand/Modules/USB/MSC/scsi.c b/KernelLand/Modules/USB/MSC/scsi.c new file mode 100644 index 00000000..c4220d80 --- /dev/null +++ b/KernelLand/Modules/USB/MSC/scsi.c @@ -0,0 +1,71 @@ +/* + * Acess2 USB Stack Mass Storage Driver + * - By John Hodge (thePowersGang) + * + * scsi.c + * - "SCSI Transparent Command Set" handling code + */ +#define DEBUG 0 +#include "common.h" +#include "scsi.h" + +// === PROTOTYPES === +Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize); +int MSC_SCSI_ReadData(void *Ptr, Uint64 Block, size_t Count, void *Dest); +int MSC_SCSI_WriteData(void *Ptr, Uint64 Block, size_t Count, const void *Dest); + +// === GLOBALS === +tLVM_VolType gMSC_SCSI_VolType = { + .Name = "USB-MSC-SCSI", + .Read = MSC_SCSI_ReadData, + .Write = MSC_SCSI_WriteData + }; + +// === CODE === +Uint64 MSC_SCSI_GetSize(tUSBInterface *Dev, size_t *BlockSize) +{ + struct sSCSI_Cmd_ReadCapacity16 cmd; + struct sSCSI_Ret_ReadCapacity16 ret; + + cmd.Op = 0x9E; + cmd.Svc = 0x10; + cmd.LBA = BigEndian64( 0 ); + cmd.AllocationLength = BigEndian32(sizeof(ret)); + cmd.Flags = 0; + cmd.Control = 0; + + ret.BlockSize = 0; + ret.BlockCount = 0; + MSC_RecvData(Dev, sizeof(cmd), &cmd, sizeof(ret), &ret); + + *BlockSize = BigEndian32(ret.BlockSize); + return BigEndian64(ret.BlockCount); +} + +int MSC_SCSI_ReadData(void *Ptr, Uint64 Block, size_t Count, void *Dest) +{ + tUSBInterface *Dev = Ptr; + tMSCInfo *info = USB_GetDeviceDataPtr(Dev); + struct sSCSI_Cmd_Read16 cmd; + + // TODO: Bounds checking? + + cmd.Op = 0x88; + cmd.Flags = 0; + cmd.LBA = BigEndian64(Block); + cmd.Length = BigEndian32(Count); + cmd.GroupNumber = 0; + cmd.Control = 0; + + MSC_RecvData(Dev, sizeof(cmd), &cmd, Count*info->BlockSize, Dest); + // TODO: Error check + + return Count; +} + +int MSC_SCSI_WriteData(void *Ptr, Uint64 Block, size_t Count, const void *Data) +{ + Log_Warning("MSC_SCSI", "TODO: Impliment MSC_SCSI_WriteData"); + return 0; +} + diff --git a/KernelLand/Modules/USB/MSC/scsi.h b/KernelLand/Modules/USB/MSC/scsi.h new file mode 100644 index 00000000..47959890 --- /dev/null +++ b/KernelLand/Modules/USB/MSC/scsi.h @@ -0,0 +1,42 @@ +/* + * Acess2 USB Stack Mass Storage Driver + * - By John Hodge (thePowersGang) + * + * scsi.h + * - "SCSI Transparent Command Set" handling code + */ +#ifndef _MSC__SCSI_H_ +#define _MSC__SCSI_H_ + +// NOTE: All commands are big-endian + +struct sSCSI_Cmd_ReadCapacity16 +{ + Uint8 Op; // 0x9E + Uint8 Svc; // 0x10 + Uint64 LBA; // + Uint32 AllocationLength; + Uint8 Flags; + Uint8 Control; +} PACKED; + +struct sSCSI_Ret_ReadCapacity16 +{ + Uint64 BlockCount; + Uint32 BlockSize; + Uint8 Flags; + Uint8 _resvd[32-13]; +} PACKED; + +struct sSCSI_Cmd_Read16 +{ + Uint8 Op; // 0x88 + Uint8 Flags; + Uint64 LBA; + Uint32 Length; + Uint8 GroupNumber; + Uint8 Control; +} PACKED; + +#endif + -- 2.20.1