File syn_usb_msc.c¶
File List > drivers > syn_usb_msc.c
Go to the documentation of this file
#include "syn_usb_msc.h"
#include <string.h>
#define SYN_USB_MSC_CBW_SIGNATURE 0x43425355U
#define SYN_USB_MSC_CSW_SIGNATURE 0x53425355U
static SYN_Status usb_msc_setup_handler(void *ctx, const SYN_USB_SetupPacket *pkt, uint8_t *resp,
uint16_t *rlen)
{
if ((ctx == NULL) || (pkt == NULL) || (resp == NULL) || (rlen == NULL)) {
return SYN_INVALID_PARAM;
}
/* GET_MAX_LUN request (0xFE) */
if (pkt->bRequest == 0xFEU) {
resp[0] = 0; /* 0 LUNs (single drive) */
*rlen = 1;
return SYN_OK;
}
return SYN_OK;
}
static void usb_msc_data_out_handler(void *ctx, uint8_t ep, const uint8_t *data, uint16_t len)
{
SYN_USB_MSC *msc = (SYN_USB_MSC *)ctx;
if ((msc == NULL) || (data == NULL)) {
return;
}
if (ep == msc->ep_out && len >= 31U) {
syn_usb_msc_process_cbw(msc, data);
}
}
static void usb_msc_data_in_handler(void *ctx, uint8_t ep)
{
SYN_USB_MSC *msc = (SYN_USB_MSC *)ctx;
if (msc == NULL) {
return;
}
if (ep == msc->ep_in) {
msc->tx_len = 0U;
}
}
static SYN_Status usb_msc_configured_handler(void *ctx, uint8_t config)
{
(void)ctx;
(void)config;
return SYN_OK;
}
SYN_Status syn_usb_msc_init(SYN_USB_MSC *msc)
{
if (msc == NULL) {
return SYN_INVALID_PARAM;
}
memset(msc, 0, sizeof(*msc));
msc->ep_in = 0x82U; /* Bulk IN Endpoint 2 */
msc->ep_out = 0x02U; /* Bulk OUT Endpoint 2 */
msc->iface_num = 0U;
msc->media.block_size = SYN_USB_MSC_BLOCK_SIZE;
return SYN_OK;
}
SYN_Status syn_usb_msc_register(SYN_USB_Device *dev, SYN_USB_MSC *msc)
{
if ((dev == NULL) || (msc == NULL)) {
return SYN_INVALID_PARAM;
}
SYN_USB_ClassDriver driver;
memset(&driver, 0, sizeof(driver));
driver.iface_start = msc->iface_num;
driver.iface_count = 1U;
driver.ctx = msc;
driver.setup = usb_msc_setup_handler;
driver.data_out = usb_msc_data_out_handler;
driver.data_in = usb_msc_data_in_handler;
driver.configured = usb_msc_configured_handler;
static const uint8_t msc_desc[9] = {0x09, 0x04, 0x00, 0x00, 0x02, 0x08, 0x06, 0x50, 0x00};
return syn_usb_register_class(dev, &driver, msc_desc, (uint16_t)sizeof(msc_desc));
}
SYN_Status syn_usb_msc_set_media(SYN_USB_MSC *msc, const SYN_USB_MSC_Media *media)
{
if ((msc == NULL) || (media == NULL)) {
return SYN_INVALID_PARAM;
}
msc->media = *media;
return SYN_OK;
}
SYN_Status syn_usb_msc_process_cbw(SYN_USB_MSC *msc, const uint8_t cbw_raw[31])
{
if ((msc == NULL) || (cbw_raw == NULL)) {
return SYN_INVALID_PARAM;
}
uint32_t sig = ((uint32_t)cbw_raw[0]) | (((uint32_t)cbw_raw[1]) << 8) |
(((uint32_t)cbw_raw[2]) << 16) | (((uint32_t)cbw_raw[3]) << 24);
if (sig != SYN_USB_MSC_CBW_SIGNATURE) {
return SYN_ERROR; /* Invalid CBW signature */
}
msc->cbw.dCBWSignature = sig;
msc->cbw.dCBWTag = ((uint32_t)cbw_raw[4]) | (((uint32_t)cbw_raw[5]) << 8) |
(((uint32_t)cbw_raw[6]) << 16) | (((uint32_t)cbw_raw[7]) << 24);
msc->cbw.dCBWDataTransferLength = ((uint32_t)cbw_raw[8]) | (((uint32_t)cbw_raw[9]) << 8) |
(((uint32_t)cbw_raw[10]) << 16) |
(((uint32_t)cbw_raw[11]) << 24);
msc->cbw.bmCBWFlags = cbw_raw[12];
msc->cbw.bCBWLUN = cbw_raw[13];
msc->cbw.bCBWCBLength = cbw_raw[14];
memcpy(msc->cbw.CBWCB, &cbw_raw[15], 16);
/* Construct matching CSW response */
msc->csw.dCSWSignature = SYN_USB_MSC_CSW_SIGNATURE;
msc->csw.dCSWTag = msc->cbw.dCBWTag;
msc->csw.dCSWDataResidue = 0U;
msc->csw.bCSWStatus = 0U; /* Success */
uint8_t opcode = msc->cbw.CBWCB[0];
switch (opcode) {
case SYN_SCSI_TEST_UNIT_READY:
case SYN_SCSI_REQUEST_SENSE:
case SYN_SCSI_INQUIRY:
case SYN_SCSI_READ_CAPACITY_10:
case SYN_SCSI_READ_10:
case SYN_SCSI_WRITE_10:
msc->csw.bCSWStatus = 0U;
break;
default:
msc->csw.bCSWStatus = 1U; /* Unsupported opcode -> Command Failed */
break;
}
return SYN_OK;
}