1
0
mirror of https://github.com/mist-devel/mist-firmware.git synced 2026-04-29 05:26:02 +00:00

Add USB storage device support

Activate with the mist.ini setting: usb_storage=1
This commit is contained in:
Gyorgy Szombathelyi
2021-11-07 18:43:17 +01:00
parent 5d67bc61e6
commit b7d755f00b
15 changed files with 1149 additions and 633 deletions

View File

@@ -10,13 +10,13 @@ DUMP = $(BASE)-objdump
TODAY = `date +"%m/%d/%y"`
PRJ = firmware
SRC = hw/AT91SAM/Cstartup_SAM7.c hw/AT91SAM/hardware.c hw/AT91SAM/spi.c hw/AT91SAM/mmc.c hw/AT91SAM/cdc_enumerate.c
SRC = hw/AT91SAM/Cstartup_SAM7.c hw/AT91SAM/hardware.c hw/AT91SAM/spi.c hw/AT91SAM/mmc.c hw/AT91SAM/at91sam_usb.c hw/AT91SAM/usbdev.c
SRC += fdd.c firmware.c fpga.c hdd.c main.c menu.c osd.c state.c syscalls.c user_io.c data_io.c boot.c idxfile.c config.c tos.c ikbd.c xmodem.c ini_parser.c cue_parser.c mist_cfg.c archie.c pcecd.c arc_file.c font.c utils.c
SRC += usb/max3421e.c usb/usb.c usb/usbdebug.c usb/hub.c usb/hid.c usb/hidparser.c usb/timer.c usb/asix.c usb/pl2303.c usb/usbrtc.c usb/joymapping.c
SRC += fat_compat.c
SRC += FatFs/diskio.c FatFs/ff.c FatFs/ffunicode.c
# SRC += usb/storage.c
SRC += cdc_control.c
SRC += cdc_control.c storage_control.c
OBJ = $(SRC:.c=.o)
DEP = $(SRC:.c=.d)

View File

@@ -5,8 +5,8 @@
#include <stdio.h>
#include "cdc_enumerate.h"
#include "cdc_control.h"
#include "usbdev.h"
#include "utils.h"
#include "user_io.h"
#include "tos.h"
@@ -18,12 +18,6 @@ static unsigned long flush_timer = 0;
extern const char version[];
void cdc_control_open(void) {
iprintf("CDC control open\n");
usb_cdc_open();
}
// send everything in buffer
void cdc_control_flush(void) {
if(fill) usb_cdc_write(buffer, fill);
@@ -62,13 +56,12 @@ void cdc_control_poll(void) {
flush_timer = 0;
}
// low level usb handling happens inside usb_cdc_poll
if(usb_cdc_poll()) {
if(usb_cdc_is_configured()) {
uint16_t read, i;
char data[AT91C_EP_OUT_SIZE];
char data[BULK_OUT_SIZE];
// check for user input
if((read = usb_cdc_read(data, AT91C_EP_OUT_SIZE)) != 0) {
if((read = usb_cdc_read(data, BULK_OUT_SIZE)) != 0) {
switch(tos_get_cdc_control_redirect()) {
case CDC_REDIRECT_RS232:

View File

@@ -8,7 +8,6 @@
#define CDC_REDIRECT_PARALLEL 0x04
#define CDC_REDIRECT_MIDI 0x05
void cdc_control_open(void);
void cdc_control_poll(void);
void cdc_control_tx(char c);
void cdc_control_flush(void);

260
hw/AT91SAM/at91sam_usb.c Normal file
View File

@@ -0,0 +1,260 @@
//*----------------------------------------------------------------------------
//* ATMEL Microcontroller Software Support - ROUSSET -
//*----------------------------------------------------------------------------
//* The software is delivered "AS IS" without warranty or condition of any
//* kind, either express, implied or statutory. This includes without
//* limitation any warranty or condition with respect to merchantability or
//* fitness for any particular purpose, or against the infringements of
//* intellectual property rights of others.
//*----------------------------------------------------------------------------
//* File Name : cdc_enumerate.c
//* Object : Handle CDC enumeration
//*
//* 1.0 Apr 20 200 : ODi Creation
//* 1.1 14/Sep/2004 JPP : Minor change
//* 1.1 15/12/2004 JPP : suppress warning
//*----------------------------------------------------------------------------
// 12. Apr. 2006: added modification found in the mikrocontroller.net gcc-Forum
// additional line marked with /* +++ */
// 1. Sept. 2006: fixed case: board.h -> Board.h
#include "AT91SAM7S256.h"
#include <string.h>
#include "at91sam_usb.h"
#include "hardware.h"
#include "debug.h"
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define WORD(a) (a)&0xff, ((a)>>8)&0xff
// Private members
static unsigned int currentRcvBank;
static AT91F_USB_Enumerate stp_callback;
static void usb_irq_handler(void) {
AT91_REG isr = AT91C_BASE_UDP->UDP_ISR & AT91C_BASE_UDP->UDP_IMR;
// tx_hex("i: ", isr);
// handle all known interrupt sources
if(isr & AT91C_UDP_ENDBUSRES) {
AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_ENDBUSRES;
// tx_str("USB bus reset\r\n");
// reset all endpoints
AT91C_BASE_UDP->UDP_RSTEP = (unsigned int)-1;
AT91C_BASE_UDP->UDP_RSTEP = 0;
// Enable the function
AT91C_BASE_UDP->UDP_FADDR = AT91C_UDP_FEN;
// Configure endpoint 0
AT91C_BASE_UDP->UDP_CSR[0] = (AT91C_UDP_EPEDS | AT91C_UDP_EPTYPE_CTRL);
// enable ep0 interrupt
AT91C_BASE_UDP->UDP_IER = AT91C_UDP_EPINT0;
}
// data received for endpoint 0
if(isr & AT91C_UDP_EPINT0) {
AT91C_BASE_UDP->UDP_ICR = AT91C_UDP_EPINT0;
(*stp_callback)();
}
// clear all remaining irqs
AT91C_BASE_UDP->UDP_ICR = AT91C_BASE_UDP->UDP_ISR;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_USB_Open
//* \brief
//*----------------------------------------------------------------------------
void AT91F_USB_Open(AT91F_USB_Enumerate setup_callback) {
// Set the PLL USB Divider
AT91C_BASE_CKGR->CKGR_PLLR |= AT91C_CKGR_USBDIV_1 ;
// Specific Chip USB Initialisation
// Enables the 48MHz USB clock UDPCK and System Peripheral USB Clock
AT91C_BASE_PMC->PMC_SCER = AT91C_PMC_UDP;
AT91C_BASE_PMC->PMC_PCER = (1 << AT91C_ID_UDP);
// Enable UDP PullUp (USB_DP_PUP) : enable & Clear of the corresponding PIO
// Set in PIO mode and Configure in Output with pullup
AT91C_BASE_PIOA->PIO_PER = USB_PUP;
AT91C_BASE_PIOA->PIO_OER = USB_PUP;
AT91C_BASE_PIOA->PIO_CODR = USB_PUP;
currentRcvBank = AT91C_UDP_RX_DATA_BK0;
/* Enable usb_interrupt */
AT91C_AIC_SMR[AT91C_ID_UDP] = AT91C_AIC_SRCTYPE_INT_HIGH_LEVEL | 4;
AT91C_AIC_SVR[AT91C_ID_UDP] = (unsigned int)usb_irq_handler;
*AT91C_AIC_IECR = (1 << AT91C_ID_UDP);
stp_callback = setup_callback;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_USB_Is_Configured
//* \brief Test if the device is configured
//*----------------------------------------------------------------------------
uint8_t AT91F_USB_Is_Configured(void) {
return AT91C_BASE_UDP->UDP_GLBSTATE & AT91C_UDP_CONFG;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_USB_Read
//* \brief Read available data from Endpoint OUT
//*----------------------------------------------------------------------------
uint16_t AT91F_USB_Read(char *pData, uint16_t length) {
uint16_t packetSize, nbBytesRcv = 0;
if ( !AT91F_USB_Is_Configured() )
return 0;
if ( AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] & currentRcvBank ) {
packetSize = MIN(AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] >> 16, length);
while(packetSize--)
pData[nbBytesRcv++] = AT91C_BASE_UDP->UDP_FDR[AT91C_EP_OUT];
AT91C_BASE_UDP->UDP_CSR[AT91C_EP_OUT] &= ~(currentRcvBank);
// toggle banks
if(currentRcvBank == AT91C_UDP_RX_DATA_BK0)
currentRcvBank = AT91C_UDP_RX_DATA_BK1;
else
currentRcvBank = AT91C_UDP_RX_DATA_BK0;
}
return nbBytesRcv;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_USB_Write
//* \brief Send through endpoint 2
//*----------------------------------------------------------------------------
static void wait4tx(char ep) {
long to = GetTimer(2); // wait max 2ms for tx to succeed
// wait for host to acknowledge data reception
while ( !(AT91C_BASE_UDP->UDP_CSR[ep] & AT91C_UDP_TXCOMP) )
if(CheckTimer(to)) return;
// clear flag (clear irq)
AT91C_BASE_UDP->UDP_CSR[ep] &= ~AT91C_UDP_TXCOMP;
// wait for register clear to succeed
while (AT91C_BASE_UDP->UDP_CSR[ep] & AT91C_UDP_TXCOMP);
}
// copy bytes to the endpoint fifo and start transmission
static uint16_t ep_tx(char ep, const char *pData, uint16_t length) {
uint16_t b2c = MIN(length, ep?AT91C_EP_IN_SIZE:8);
uint16_t retval = b2c;
// copy all bytes into send buffer
while (b2c--) AT91C_BASE_UDP->UDP_FDR[ep] = *pData++;
AT91C_BASE_UDP->UDP_CSR[ep] |= AT91C_UDP_TXPKTRDY;
return retval;
}
uint16_t AT91F_USB_Write(const char *pData, uint16_t length) {
if ( !AT91F_USB_Is_Configured() )
return length;
while(length) {
uint16_t sent = ep_tx(AT91C_EP_IN, pData, length);
length -= sent;
pData += sent;
wait4tx(AT91C_EP_IN);
}
return length;
}
//*----------------------------------------------------------------------------
//* \fn AT91F_USB_SendData
//* \brief Send Data through the control endpoint
//*----------------------------------------------------------------------------
void AT91F_USB_SendData(const char *pData, uint16_t length) {
AT91_REG csr;
do {
long to = GetTimer(2); // wait max 2ms for tx to succeed
uint32_t sent = ep_tx(0, pData, length);
length -= sent;
pData += sent;
// wait for transmission with timeout
do {
csr = AT91C_BASE_UDP->UDP_CSR[0];
// Data IN stage has been stopped by a status OUT
if (csr & AT91C_UDP_RX_DATA_BK0) {
AT91C_BASE_UDP->UDP_CSR[0] &= ~(AT91C_UDP_RX_DATA_BK0);
return;
}
} while (( !(csr & AT91C_UDP_TXCOMP) ) && !CheckTimer(to));
// clear flag (clear irq)
AT91C_BASE_UDP->UDP_CSR[0] &= ~AT91C_UDP_TXCOMP;
// wait for register clear to succeed
while (AT91C_BASE_UDP->UDP_CSR[0] & AT91C_UDP_TXCOMP);
} while (length);
}
//*----------------------------------------------------------------------------
//* \fn AT91F_USB_SendStr
//* \brief Send a string through the control endpoint
//*----------------------------------------------------------------------------
void AT91F_USB_SendStr(const char *str, uint32_t max) {
uint8_t len = 2*strlen(str)+2;
char cmd[len], *p;
cmd[0] = len;
cmd[1] = 0x03;
p = cmd+2;
while(*str) {
*p++ = *str++;
*p++ = 0;
}
AT91F_USB_SendData(cmd, MIN(len, max));
}
//*----------------------------------------------------------------------------
//* \fn AT91F_USB_SendWord
//* \brief Send a 16 bit word through the control endpoint
//*----------------------------------------------------------------------------
void AT91F_USB_SendWord(uint16_t data) {
AT91F_USB_SendData((char *) &data, sizeof(data));
}
//*----------------------------------------------------------------------------
//* \fn AT91F_USB_SendZlp
//* \brief Send zero length packet through the control endpoint
//*----------------------------------------------------------------------------
void AT91F_USB_SendZlp() {
AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_TXPKTRDY;
wait4tx(0);
}
//*----------------------------------------------------------------------------
//* \fn AT91F_USB_SendStall
//* \brief Stall the control endpoint
//*----------------------------------------------------------------------------
void AT91F_USB_SendStall() {
AT91C_BASE_UDP->UDP_CSR[0] |= AT91C_UDP_FORCESTALL;
while ( !(AT91C_BASE_UDP->UDP_CSR[0] & AT91C_UDP_ISOERROR) );
AT91C_BASE_UDP->UDP_CSR[0] &= ~(AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR);
while (AT91C_BASE_UDP->UDP_CSR[0] & (AT91C_UDP_FORCESTALL | AT91C_UDP_ISOERROR));
}

View File

@@ -1,34 +1,38 @@
//*----------------------------------------------------------------------------
//* ATMEL Microcontroller Software Support - ROUSSET -
//*----------------------------------------------------------------------------
//* The software is delivered "AS IS" without warranty or condition of any
//* kind, either express, implied or statutory. This includes without
//* limitation any warranty or condition with respect to merchantability or
//* fitness for any particular purpose, or against the infringements of
//* intellectual property rights of others.
//*----------------------------------------------------------------------------
//* File Name : cdc_enumerate.h
//* Object : Handle CDC enumeration
//*
//* 1.0 Apr 20 200 : ODi Creation
//*----------------------------------------------------------------------------
#ifndef CDC_ENUMERATE_H
#define CDC_ENUMERATE_H
#include <inttypes.h>
#define AT91C_EP_OUT_SIZE 0x40
#define AT91C_EP_OUT 1
#define AT91C_EP_IN_SIZE 0x40
#define AT91C_EP_IN 2
void usb_cdc_open(void);
unsigned char usb_cdc_is_configured(void);
unsigned int usb_cdc_write(const char *pData, unsigned int length);
uint16_t usb_cdc_read(char *pData, uint16_t length);
#define usb_cdc_poll() usb_cdc_is_configured()
#endif // CDC_ENUMERATE_H
//*----------------------------------------------------------------------------
//* ATMEL Microcontroller Software Support - ROUSSET -
//*----------------------------------------------------------------------------
//* The software is delivered "AS IS" without warranty or condition of any
//* kind, either express, implied or statutory. This includes without
//* limitation any warranty or condition with respect to merchantability or
//* fitness for any particular purpose, or against the infringements of
//* intellectual property rights of others.
//*----------------------------------------------------------------------------
//* File Name : cdc_enumerate.h
//* Object : Handle CDC enumeration
//*
//* 1.0 Apr 20 200 : ODi Creation
//*----------------------------------------------------------------------------
#ifndef AT91SAM_USB_H
#define AT91SAM_USB_H
#include <inttypes.h>
#define AT91C_EP_OUT_SIZE 0x40
#define AT91C_EP_OUT 1
#define AT91C_EP_IN_SIZE 0x40
#define AT91C_EP_IN 2
typedef void (*AT91F_USB_Enumerate)(void);
void AT91F_USB_Open(AT91F_USB_Enumerate setup_callback);
uint8_t AT91F_USB_Is_Configured(void);
uint16_t AT91F_USB_Read(char *pData, uint16_t length);
uint16_t AT91F_USB_Write(const char *pData, uint16_t length);
void AT91F_USB_SendData(const char *pData, uint16_t length);
void AT91F_USB_SendStr(const char *str, uint32_t max);
void AT91F_USB_SendWord(uint16_t data);
void AT91F_USB_SendZlp();
void AT91F_USB_SendStall();
#endif // AT91SAM_USB_H

View File

@@ -299,7 +299,7 @@ RAMFUNC static unsigned char MMC_ReceiveDataBlock(unsigned char *pReadBuffer)
{
if (timeout++ >= 1000000) // we can't wait forever
{
// iprintf("CMD17 (READ_BLOCK): no data token! (lba=%lu)\r", lba);
iprintf("CMD17/18 (READ_BLOCK): no data token!\r");
return(0);
}
}
@@ -339,7 +339,7 @@ RAMFUNC unsigned char MMC_Read(unsigned long lba, unsigned char *pReadBuffer)
if (MMC_Command(CMD17, lba))
{
// iprintf("CMD17 (READ_BLOCK): invalid response 0x%02X (lba=%lu)\r", response, lba);
iprintf("CMD17 (READ_BLOCK): invalid response 0x%02X (lba=%lu)\r", response, lba);
DisableCard();
return(0);
}

File diff suppressed because it is too large Load Diff

37
hw/AT91SAM/usbdev.h Normal file
View File

@@ -0,0 +1,37 @@
/*
This file is part of MiST-firmware
MiST-firmware is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
MiST-firmware is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef USBDEV_H
#define USBDEV_H
#include <inttypes.h>
#include "at91sam_usb.h"
#define BULK_IN_SIZE AT91C_EP_IN_SIZE
#define BULK_OUT_SIZE AT91C_EP_OUT_SIZE
void usb_dev_open(void);
uint8_t usb_cdc_is_configured(void);
uint16_t usb_cdc_write(const char *pData, uint16_t length);
uint16_t usb_cdc_read(char *pData, uint16_t length);
uint8_t usb_storage_is_configured(void);
uint16_t usb_storage_write(const char *pData, uint16_t length);
uint16_t usb_storage_read(char *pData, uint16_t length);
#endif // USBDEV_H

8
main.c
View File

@@ -53,11 +53,12 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include "arc_file.h"
#include "font.h"
#include "tos.h"
#include "cdc_control.h"
#include "usb.h"
#include "debug.h"
#include "mist_cfg.h"
#include "cdc_enumerate.h"
#include "usbdev.h"
#include "cdc_control.h"
#include "storage_control.h"
#ifndef _WANT_IO_LONG_LONG
#error "newlib lacks support of long long type in IO functions. Please use a toolchain that was compiled with option --enable-newlib-io-long-long."
@@ -185,10 +186,11 @@ int main(void)
fpga_init(s);
}
cdc_control_open();
usb_dev_open();
while (1) {
cdc_control_poll();
storage_control_poll();
user_io_poll();

View File

@@ -8,6 +8,7 @@ mouse_speed=100 ; set to scale mouse speed (in percentage, defaul
joystick_emu_fixed_index=0 ; set to 1 for always emulating the first two joystick via keyboard
joystick_remap=0583,2060,1,2,4,8,10,20,20,8,400,800,40,80
key_menu_as_rgui=0 ; set to 1 to make the MENU key map to RGUI in Minimig (e.g. for Right Amiga)
usb_storage=0 ; set to 1 to allow accessing the SD Card via the USB port
[minimig_config]
;conf_default="68020 AGA"

View File

@@ -109,6 +109,7 @@ const ini_var_t mist_ini_vars[] = {
#endif
{"ROM", (void*)ini_rom_upload, CUSTOM_HANDLER, 0, 0, 1},
{"AMIGA_MOD_KEYS", (void*)(&(mist_cfg.amiga_mod_keys)), UINT8, 0, 1, 1},
{"USB_STORAGE", (void*)(&(mist_cfg.usb_storage)), UINT8, 0, 1, 1},
// [MINIMIG_CONFIG]
{"KICK1X_MEMORY_DETECTION_PATCH", (void*)(&(minimig_cfg.kick1x_memory_detection_patch)), UINT8, 0, 1, 2},
{"CLOCK_FREQ", (void*)(&(minimig_cfg.clock_freq)), UINT8, 0, 2, 2},

View File

@@ -32,6 +32,7 @@ typedef struct {
uint8_t led_animation;
uint8_t sdram64;
uint8_t amiga_mod_keys;
uint8_t usb_storage;
} mist_cfg_t;

296
storage_control.c Normal file
View File

@@ -0,0 +1,296 @@
/*
storage_control.c
*/
#include <inttypes.h>
#include <string.h>
#include <stdio.h>
#include "swab.h"
#include "utils.h"
#include "storage_control.h"
#include "fat_compat.h"
#include "usbdev.h"
#include "mmc.h"
#include "debug.h"
#define SENSEKEY_NO_SENSE 0x0
#define SENSEKEY_NOT_READY 0x2
#define SENSEKEY_MEDIUM_ERROR 0x3
#define SENSEKEY_HARDWARE_ERROR 0x4
#define SENSEKEY_ILLEGAL_REQUEST 0x5
#define SENSEKEY_UNIT_ATTENTION 0x6
#define SENSEKEY_ABORTED_COMMAND 0xB
typedef struct
{
uint8_t key;
uint8_t asc;
uint8_t ascq;
} sense_t;
static sense_t sense;
typedef struct {
uint32_t dCBWSignature;
uint32_t dCBWTag;
uint32_t dCBWDataTransferLength;
uint8_t bmCBWFlags;
uint8_t bCBWLUN;
uint8_t bCBWCLength;
uint8_t CBWCB[16];
} __attribute__ ((packed)) CBW_t;
typedef struct {
uint32_t dCSWSignature;
uint32_t dCSWTag;
uint32_t dCSWDataResidue;
uint8_t bCSWStatus;
} __attribute__ ((packed)) CSW_t;
typedef struct {
uint8_t DeviceType : 5;
uint8_t DeviceTypeQualifier : 3;
uint8_t DeviceTypeModifier : 7;
uint8_t RemovableMedia : 1;
uint8_t Versions;
uint8_t ResponseDataFormat : 4;
uint8_t HiSupport : 1;
uint8_t NormACA : 1;
uint8_t ReservedBit : 1;
uint8_t AERC : 1;
uint8_t AdditionalLength;
uint8_t Reserved[2];
uint8_t SoftReset : 1;
uint8_t CommandQueue : 1;
uint8_t Reserved2 : 1;
uint8_t LinkedCommands : 1;
uint8_t Synchronous : 1;
uint8_t Wide16Bit : 1;
uint8_t Wide32Bit : 1;
uint8_t RelativeAddressing : 1;
uint8_t VendorId[8];
uint8_t ProductId[16];
uint8_t ProductRevisionLevel[4];
uint8_t VendorSpecific[20];
uint8_t Reserved3[2];
uint8_t VersionDescriptors[8];
uint8_t Reserved4[30];
} __attribute__ ((packed)) INQUIRYDATA_t;
typedef struct {
uint8_t ErrorCode :7;
uint8_t Valid :1;
uint8_t SegmentNumber;
uint8_t SenseKey :4;
uint8_t Reserved :1;
uint8_t IncorrectLength :1;
uint8_t EndOfMedia :1;
uint8_t FileMark :1;
uint8_t Information[4];
uint8_t AdditionalSenseLength;
uint8_t CommandSpecificInformation[4];
uint8_t AdditionalSenseCode;
uint8_t AdditionalSenseCodeQualifier;
uint8_t FieldReplaceableUnitCode;
uint8_t SenseKeySpecific[3];
} __attribute__ ((packed)) SENSEDATA_t;
typedef struct {
uint32_t LBA;
uint32_t blocklen;
} __attribute__ ((packed)) CAPACITYDATA_t;
static void clear_sense() {
sense.key = sense.asc = sense.ascq = 0;
}
static void make_sense(uint8_t key, uint8_t asc, uint8_t ascq) {
sense.key = key;
sense.asc = asc;
sense.ascq = ascq;
}
static void scsi_inquiry(uint8_t *cmd) {
uint16_t len = cmd[3]<<8 | cmd[4];
INQUIRYDATA_t *data = (INQUIRYDATA_t*)sector_buffer;
memset(data, 0, sizeof(INQUIRYDATA_t));
data->RemovableMedia = 1;
data->ResponseDataFormat = 2;
data->AdditionalLength = 0x1f;
memcpy(data->VendorId, "Lotharek", 8);
memcpy(data->ProductId, "MiST Board ", 16);
memcpy(data->ProductRevisionLevel, "1.3 ", 4);
usb_storage_write(sector_buffer, MIN(len, sizeof(INQUIRYDATA_t)));
}
static void scsi_readcapacity(uint8_t *cmd) {
CAPACITYDATA_t cap;
cap.LBA = swab32(MMC_GetCapacity()-1);
cap.blocklen = swab32(512);
usb_storage_write((const char*) &cap, sizeof(CAPACITYDATA_t));
}
static void scsi_request_sense(uint8_t *cmd) {
uint8_t len = cmd[4];
SENSEDATA_t dat;
memset(&dat, 0, sizeof(SENSEDATA_t));
dat.ErrorCode = 0x70;
dat.Valid = 1;
dat.SenseKey = sense.key;
dat.AdditionalSenseLength = sizeof(SENSEDATA_t)-7;
dat.AdditionalSenseCode = sense.asc;
dat.AdditionalSenseCodeQualifier = sense.ascq;
usb_storage_write((const char*) &dat, MIN(len, sizeof(SENSEDATA_t)));
}
static void scsi_mode_sense(uint8_t *cmd) {
hexdump(cmd, 6, 0);
// TODO: more complete implementation
uint8_t len = cmd[4];
memset(sector_buffer, 0, len);
usb_storage_write(sector_buffer, len);
}
static uint8_t scsi_read(uint8_t *cmd) {
uint32_t lba = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
uint16_t len = cmd[7]<<8 | cmd[8];
storage_debugf("Read lba=%d len=%d", lba, len);
while (len) {
uint8_t ret;
uint16_t read = len>(SECTOR_BUFFER_SIZE/512) ? (SECTOR_BUFFER_SIZE/512) : len;
DISKLED_ON
if (len == 1) ret=MMC_Read(lba, sector_buffer);
else ret=MMC_ReadMultiple(lba, sector_buffer, read);
DISKLED_OFF
if (!ret) {
iprintf("STORAGE: Error reading from MMC (lba=%d, len=%d)\n", lba, len);
return 0;
}
lba+=read;
len-=read;
usb_storage_write(sector_buffer, read*512);
}
return 1;
}
static uint8_t scsi_write(uint8_t *cmd) {
uint32_t lba = cmd[2]<<24 | cmd[3]<<16 | cmd[4]<<8 | cmd[5];
uint16_t len = cmd[7]<<8 | cmd[8];
storage_debugf("Write lba=%d len=%d", lba, len);
while (len) {
uint16_t write = len>(SECTOR_BUFFER_SIZE/512) ? (SECTOR_BUFFER_SIZE/512) : len;
uint16_t read, total_read = write*512;
uint8_t *buf = sector_buffer;
long to = GetTimer(100); // wait max 100ms for host
while (total_read) {
if (CheckTimer(to)) {
iprintf("STORAGE: Timeout while waiting for USB host during write (lba=%d, len=%d)\n", lba, len);
return 0;
}
read = usb_storage_read(buf, total_read);
total_read -= read;
buf += read;
}
//hexdump(sector_buffer, write*512, 0);
DISKLED_ON
if (write == 1) MMC_Write(lba, sector_buffer);
else MMC_WriteMultiple(lba, sector_buffer, write);
DISKLED_OFF
lba+=write;
len-=write;
}
return 1;
}
static void storage_control_send_csw(uint32_t tag, uint8_t status) {
CSW_t* csw = (CSW_t*)sector_buffer;
csw->dCSWSignature = 0x53425355;
csw->dCSWTag = tag;
csw->dCSWDataResidue = 0;
csw->bCSWStatus = status;
usb_storage_write(sector_buffer, sizeof(CSW_t));
}
void storage_control_poll(void) {
uint16_t read;
uint32_t tag;
uint8_t ret;
if (!usb_storage_is_configured()) return;
// read CSW
if((read = usb_storage_read(sector_buffer, BULK_OUT_SIZE)) != 0) {
CBW_t *cbw = (CBW_t*)sector_buffer;
if (read != 31 || cbw->dCBWSignature != 0x43425355) {
return;
}
tag = cbw->dCBWTag;
//hexdump(sector_buffer, read, 0);
//iprintf("\n");
switch (cbw->CBWCB[0]) {
case 0x00:
storage_debugf("Test Unit Ready");
clear_sense();
storage_control_send_csw(tag, 0);
break;
case 0x03:
storage_debugf("Request sense");
scsi_request_sense(cbw->CBWCB);
storage_control_send_csw(tag, 0);
break;
case 0x12:
storage_debugf("Inquiry");
clear_sense();
scsi_inquiry(cbw->CBWCB);
storage_control_send_csw(tag, 0);
break;
case 0x1A:
storage_debugf("Mode Sense");
clear_sense();
scsi_mode_sense(cbw->CBWCB);
storage_control_send_csw(tag, 0);
break;
case 0x1E:
storage_debugf("Prevent Removal");
clear_sense();
storage_control_send_csw(tag, 0);
break;
case 0x25:
storage_debugf("Read Capacity");
clear_sense();
scsi_readcapacity(cbw->CBWCB);
storage_control_send_csw(tag, 0);
break;
case 0x28:
ret = scsi_read(cbw->CBWCB);
if (ret)
clear_sense();
else
make_sense(SENSEKEY_MEDIUM_ERROR, 0x11, 0x00);
storage_control_send_csw(tag, !ret);
break;
case 0x2A:
ret = scsi_write(cbw->CBWCB);
if (ret)
clear_sense();
else
make_sense(SENSEKEY_MEDIUM_ERROR, 0x03, 0x00);
storage_control_send_csw(tag, !ret);
break;
case 0x1B:
storage_debugf("Start stop unit");
clear_sense();
storage_control_send_csw(tag, 0);
break;
default:
iprintf("STORAGE: Unhandled cmd: %02x", cbw->CBWCB[0]);
make_sense(SENSEKEY_ILLEGAL_REQUEST, 0x20, 0x00);
storage_control_send_csw(tag, 1);
break;
}
}
}

6
storage_control.h Normal file
View File

@@ -0,0 +1,6 @@
#ifndef STORAGE_CONTROL_H
#define STORAGE_CONTROL_H
void storage_control_poll(void);
#endif

View File

@@ -1,6 +1,10 @@
#ifndef _UTILS_H_
#define _UTILS_H_
#include <stddef.h>
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
unsigned char decval(unsigned char in, unsigned char min, unsigned char max);
unsigned char incval(unsigned char in, unsigned char min, unsigned char max);
unsigned char bin2bcd(unsigned char in);