USB_MSD. Added READ_FORMAT_CAPACITIES handler
This commit is contained in:
parent
b7cefd6fac
commit
92c3714706
|
@ -262,22 +262,47 @@ bool msd_request_hook(USBDriver *usbp) {
|
|||
/* check that it is a HOST2DEV request */
|
||||
if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_HOST2DEV) ||
|
||||
(MSD_SETUP_LENGTH(usbp->setup) != 0) ||
|
||||
(MSD_SETUP_VALUE(usbp->setup) != 0))
|
||||
(MSD_SETUP_VALUE(usbp->setup) != 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* reset all endpoints */
|
||||
/* TODO!*/
|
||||
/*
|
||||
As required by the BOT specification, the Bulk-only mass storage reset request (classspecific
|
||||
request) is implemented. This request is used to reset the mass storage device and
|
||||
its associated interface. This class-specific request should prepare the device for the next
|
||||
CBW from the host.
|
||||
To generate the BOT Mass Storage Reset, the host must send a device request on the
|
||||
default pipe of:
|
||||
• bmRequestType: Class, interface, host to device
|
||||
• bRequest field set to 255 (FFh)
|
||||
• wValue field set to ‘0’
|
||||
• wIndex field set to the interface number
|
||||
• wLength field set to ‘0’
|
||||
*/
|
||||
chSysLockFromISR();
|
||||
|
||||
/* release and abandon current transmission */
|
||||
usbStallReceiveI(usbp, 1);
|
||||
usbStallTransmitI(usbp, 1);
|
||||
/* The device shall NAK the status stage of the device request until
|
||||
* the Bulk-Only Mass Storage Reset is complete.
|
||||
*/
|
||||
* NAK EP1 in and out */
|
||||
usbp->otg->ie[1].DIEPCTL = DIEPCTL_SNAK;
|
||||
usbp->otg->oe[1].DOEPCTL = DOEPCTL_SNAK;
|
||||
|
||||
chSysUnlockFromISR();
|
||||
|
||||
/* response to this request using EP0 */
|
||||
usbSetupTransfer(usbp, 0, 0, NULL);
|
||||
return true;
|
||||
|
||||
case MSD_GET_MAX_LUN:
|
||||
/* check that it is a DEV2HOST request */
|
||||
if (((usbp->setup[0] & USB_RTYPE_DIR_MASK) != USB_RTYPE_DIR_DEV2HOST) ||
|
||||
(MSD_SETUP_LENGTH(usbp->setup) != 1) ||
|
||||
(MSD_SETUP_VALUE(usbp->setup) != 0))
|
||||
(MSD_SETUP_VALUE(usbp->setup) != 0)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* stall to indicate that we don't support LUN */
|
||||
osalSysLockFromISR();
|
||||
|
|
|
@ -25,10 +25,17 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "hal.h"
|
||||
//#include "chprintf.h"
|
||||
|
||||
#include "lib_scsi.h"
|
||||
|
||||
#define DEBUG_TRACE_PRINT FALSE
|
||||
#define DEBUG_TRACE_WARNING FALSE
|
||||
#define DEBUG_TRACE_ERROR FALSE
|
||||
#include "dbgtrace.h"
|
||||
|
||||
#define ARCH_LITTLE_ENDIAN
|
||||
#include "bswap.h"
|
||||
|
||||
/*===========================================================================*/
|
||||
/* Driver local definitions. */
|
||||
/*===========================================================================*/
|
||||
|
@ -50,25 +57,6 @@ typedef struct {
|
|||
/* Driver local functions. */
|
||||
/*===========================================================================*/
|
||||
|
||||
/**
|
||||
* @brief Byte swapping function.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static uint32_t swap_uint32(uint32_t val) {
|
||||
val = ((val << 8) & 0xFF00FF00 ) | ((val >> 8) & 0x00FF00FF);
|
||||
return ((val << 16) & 0xFFFF0000) | ((val >> 16) & 0x0000FFFF);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Byte swapping function.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static uint16_t swap_uint16(uint16_t val) {
|
||||
return ((val >> 8) & 0xff) | ((val & 0xff) << 8);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Combines data request from byte array.
|
||||
*
|
||||
|
@ -83,8 +71,8 @@ static data_request_t decode_data_request(const uint8_t *cmd) {
|
|||
memcpy(&lba, &cmd[2], sizeof(lba));
|
||||
memcpy(&blk, &cmd[7], sizeof(blk));
|
||||
|
||||
req.first_lba = swap_uint32(lba);
|
||||
req.blk_cnt = swap_uint16(blk);
|
||||
req.first_lba = be32_to_cpu(lba);
|
||||
req.blk_cnt = be16_to_cpu(blk);
|
||||
|
||||
return req;
|
||||
}
|
||||
|
@ -253,6 +241,51 @@ static bool mode_sense6(SCSITarget *scsip, const uint8_t *cmd) {
|
|||
sizeof(scsi_mode_sense6_response_t));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SCSI read format capacities command handler.
|
||||
*
|
||||
* @param[in] scsip pointer to @p SCSITarget structure
|
||||
* @param[in] cmd pointer to SCSI command data
|
||||
*
|
||||
* @return The operation status.
|
||||
*
|
||||
* @notapi
|
||||
*/
|
||||
static bool read_format_capacities(SCSITarget *scsip, const uint8_t *cmd) {
|
||||
|
||||
/* An Allocation Length of zero indicates that no data shall be transferred.
|
||||
This condition shall not be considered as an error. The Logical Unit
|
||||
shall terminate the data transfer when Allocation Length bytes have
|
||||
been transferred or when all available data have been transferred to
|
||||
the Initiator, whatever is less. */
|
||||
|
||||
uint16_t len = cmd[7] << 8 | cmd[8];
|
||||
|
||||
if (0 == len) {
|
||||
return SCSI_SUCCESS;
|
||||
}
|
||||
else {
|
||||
scsi_read_format_capacities_response_t ret;
|
||||
BlockDeviceInfo bdi;
|
||||
blkGetInfo(scsip->config->blkdev, &bdi);
|
||||
|
||||
uint32_t tmp = cpu_to_be32(bdi.blk_num);
|
||||
memcpy(ret.blocknum, &tmp, 4);
|
||||
|
||||
uint8_t formatted_media = 0b10;
|
||||
uint16_t blocklen = bdi.blk_size;
|
||||
ret.blocklen[0] = formatted_media;
|
||||
ret.blocklen[1] = 0;
|
||||
ret.blocklen[2] = blocklen >> 8;
|
||||
ret.blocklen[3] = blocklen & 0xFF;
|
||||
|
||||
ret.header[3] = 1 * 8;
|
||||
|
||||
return transmit_data(scsip, (uint8_t *)&ret,
|
||||
sizeof(scsi_read_format_capacities_response_t));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief SCSI read capacity (10) command handler.
|
||||
*
|
||||
|
@ -270,8 +303,8 @@ static bool read_capacity10(SCSITarget *scsip, const uint8_t *cmd) {
|
|||
BlockDeviceInfo bdi;
|
||||
blkGetInfo(scsip->config->blkdev, &bdi);
|
||||
scsi_read_capacity10_response_t ret;
|
||||
ret.block_size = swap_uint32(bdi.blk_size);
|
||||
ret.last_block_addr = swap_uint32(bdi.blk_num - 1);
|
||||
ret.block_size = cpu_to_be32(bdi.blk_size);
|
||||
ret.last_block_addr = cpu_to_be32(bdi.blk_num - 1);
|
||||
|
||||
return transmit_data(scsip, (uint8_t *)&ret,
|
||||
sizeof(scsi_read_capacity10_response_t));
|
||||
|
@ -370,39 +403,47 @@ bool scsiExecCmd(SCSITarget *scsip, const uint8_t *cmd) {
|
|||
|
||||
switch (cmd[0]) {
|
||||
case SCSI_CMD_INQUIRY:
|
||||
//chprintf(SDDBG, "SCSI_CMD_INQUIRY\r\n");
|
||||
dbgprintf("SCSI_CMD_INQUIRY\r\n");
|
||||
return inquiry(scsip, cmd);
|
||||
|
||||
case SCSI_CMD_REQUEST_SENSE:
|
||||
//chprintf(SDDBG, "SCSI_CMD_REQUEST_SENSE\r\n");
|
||||
dbgprintf("SCSI_CMD_REQUEST_SENSE\r\n");
|
||||
return request_sense(scsip, cmd);
|
||||
|
||||
case SCSI_CMD_READ_CAPACITY_10:
|
||||
//chprintf(SDDBG, "SCSI_CMD_READ_CAPACITY_10\r\n");
|
||||
dbgprintf("SCSI_CMD_READ_CAPACITY_10\r\n");
|
||||
return read_capacity10(scsip, cmd);
|
||||
|
||||
case SCSI_CMD_READ_10:
|
||||
//chprintf(SDDBG, "SCSI_CMD_READ_10\r\n");
|
||||
dbgprintf("SCSI_CMD_READ_10\r\n");
|
||||
return data_read_write10(scsip, cmd);
|
||||
|
||||
case SCSI_CMD_WRITE_10:
|
||||
//chprintf(SDDBG, "SCSI_CMD_WRITE_10\r\n");
|
||||
dbgprintf("SCSI_CMD_WRITE_10\r\n");
|
||||
return data_read_write10(scsip, cmd);
|
||||
|
||||
case SCSI_CMD_TEST_UNIT_READY:
|
||||
//chprintf(SDDBG, "SCSI_CMD_TEST_UNIT_READY\r\n");
|
||||
dbgprintf("SCSI_CMD_TEST_UNIT_READY\r\n");
|
||||
return cmd_ignored(scsip, cmd);
|
||||
|
||||
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
|
||||
//chprintf(SDDBG, "SCSI_CMD_ALLOW_MEDIUM_REMOVAL\r\n");
|
||||
dbgprintf("SCSI_CMD_ALLOW_MEDIUM_REMOVAL\r\n");
|
||||
return cmd_ignored(scsip, cmd);
|
||||
|
||||
case SCSI_CMD_MODE_SENSE_6:
|
||||
//chprintf(SDDBG, "SCSI_CMD_MODE_SENSE_6\r\n");
|
||||
dbgprintf("SCSI_CMD_MODE_SENSE_6\r\n");
|
||||
return mode_sense6(scsip, cmd);
|
||||
|
||||
case SCSI_CMD_READ_FORMAT_CAPACITIES:
|
||||
dbgprintf("SCSI_CMD_READ_FORMAT_CAPACITIES\r\n");
|
||||
return read_format_capacities(scsip, cmd);
|
||||
|
||||
case SCSI_CMD_VERIFY_10:
|
||||
dbgprintf("SCSI_CMD_VERIFY_10\r\n");
|
||||
return cmd_ignored(scsip, cmd);
|
||||
|
||||
default:
|
||||
//(SDDBG, "SCSI unhandled command: %d\r\n", cmd[0]);
|
||||
warnprintf("SCSI unhandled command: %X\r\n", cmd[0]);
|
||||
return cmd_unhandled(scsip, cmd);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -37,6 +37,7 @@
|
|||
#define SCSI_CMD_SEND_DIAGNOSTIC 0x1D
|
||||
#define SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL 0x1E
|
||||
#define SCSI_CMD_READ_CAPACITY_10 0x25
|
||||
#define SCSI_CMD_READ_FORMAT_CAPACITIES 0x23
|
||||
#define SCSI_CMD_READ_10 0x28
|
||||
#define SCSI_CMD_WRITE_10 0x2A
|
||||
#define SCSI_CMD_VERIFY_10 0x2F
|
||||
|
@ -156,6 +157,16 @@ typedef struct PACKED_VAR {
|
|||
uint32_t block_size;
|
||||
} scsi_read_capacity10_response_t;
|
||||
|
||||
/**
|
||||
* @brief Represents SCSI read format capacity response structure.
|
||||
* @details See SCSI specification.
|
||||
*/
|
||||
typedef struct PACKED_VAR {
|
||||
uint8_t header[4];
|
||||
uint8_t blocknum[4];
|
||||
uint8_t blocklen[4];
|
||||
} scsi_read_format_capacities_response_t;
|
||||
|
||||
/**
|
||||
* @brief Type of a SCSI transport transmit call.
|
||||
*
|
||||
|
|
|
@ -58,7 +58,7 @@ static bool is_inserted(void *instance) {
|
|||
|
||||
static bool is_protected(void *instance) {
|
||||
RamDisk *rd = instance;
|
||||
if (rd->state != BLK_READY) {
|
||||
if (BLK_READY == rd->state) {
|
||||
return rd->readonly;
|
||||
}
|
||||
else {
|
||||
|
@ -68,7 +68,7 @@ static bool is_protected(void *instance) {
|
|||
|
||||
static bool connect(void *instance) {
|
||||
RamDisk *rd = instance;
|
||||
if (rd->state == BLK_STOP) {
|
||||
if (BLK_STOP == rd->state) {
|
||||
rd->state = BLK_READY;
|
||||
}
|
||||
return HAL_SUCCESS;
|
||||
|
@ -76,7 +76,7 @@ static bool connect(void *instance) {
|
|||
|
||||
static bool disconnect(void *instance) {
|
||||
RamDisk *rd = instance;
|
||||
if (rd->state != BLK_STOP) {
|
||||
if (BLK_STOP != rd->state) {
|
||||
rd->state = BLK_STOP;
|
||||
}
|
||||
return HAL_SUCCESS;
|
||||
|
@ -114,7 +114,7 @@ static bool write(void *instance, uint32_t startblk,
|
|||
static bool sync(void *instance) {
|
||||
|
||||
RamDisk *rd = instance;
|
||||
if (rd->state != BLK_READY) {
|
||||
if (BLK_READY != rd->state) {
|
||||
return HAL_FAILED;
|
||||
}
|
||||
else {
|
||||
|
@ -125,7 +125,7 @@ static bool sync(void *instance) {
|
|||
static bool get_info(void *instance, BlockDeviceInfo *bdip) {
|
||||
|
||||
RamDisk *rd = instance;
|
||||
if (rd->state != BLK_READY) {
|
||||
if (BLK_READY != rd->state) {
|
||||
return HAL_FAILED;
|
||||
}
|
||||
else {
|
||||
|
|
|
@ -52,6 +52,15 @@ RamDisk ramdisk;
|
|||
__attribute__((section("DATA_RAM"))) static uint8_t ramdisk_storage[RAMDISK_BLOCK_SIZE * RAMDISK_BLOCK_CNT];
|
||||
static uint8_t blkbuf[RAMDISK_BLOCK_SIZE];
|
||||
|
||||
BaseSequentialStream *GlobalDebugChannel;
|
||||
|
||||
static const SerialConfig sercfg = {
|
||||
115200,
|
||||
0,
|
||||
0,
|
||||
0
|
||||
};
|
||||
|
||||
/*
|
||||
* Application entry point.
|
||||
*/
|
||||
|
@ -67,6 +76,9 @@ int main(void) {
|
|||
halInit();
|
||||
chSysInit();
|
||||
|
||||
sdStart(&SD3, &sercfg);
|
||||
GlobalDebugChannel = (BaseSequentialStream *)&SD3;
|
||||
|
||||
/*
|
||||
* Activates the USB driver and then the USB bus pull-up on D+.
|
||||
* Note, a delay is inserted in order to not have to disconnect the cable
|
||||
|
@ -75,7 +87,6 @@ int main(void) {
|
|||
usbDisconnectBus(&USBD1);
|
||||
chThdSleepMilliseconds(1500);
|
||||
usbStart(&USBD1, &usbcfg);
|
||||
usbConnectBus(&USBD1);
|
||||
|
||||
/*
|
||||
* start RAM disk
|
||||
|
@ -93,6 +104,11 @@ int main(void) {
|
|||
msdObjectInit(&USBMSD1);
|
||||
msdStart(&USBMSD1, &USBD1, (BaseBlockDevice *)&ramdisk, blkbuf, NULL);
|
||||
|
||||
/*
|
||||
*
|
||||
*/
|
||||
usbConnectBus(&USBD1);
|
||||
|
||||
/*
|
||||
* Starting threads.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue