16#define MSD_REQ_RESET 0xFF
17#define MSD_REQ_GET_MAX_LUN 0xFE
19#define MSD_CBW_SIGNATURE 0x43425355
20#define MSD_CSW_SIGNATURE 0x53425355
22#define CBW_FLAGS_RESERVED_MASK 0b01111111
23#define CBW_LUN_RESERVED_MASK 0b11110000
24#define CBW_CMD_LEN_RESERVED_MASK 0b11000000
26#define CSW_STATUS_PASSED 0x00
27#define CSW_STATUS_FAILED 0x01
28#define CSW_STATUS_PHASE_ERROR 0x02
30#define MSD_SETUP_WORD(setup, index) (uint16_t)(((uint16_t)setup[index+1] << 8)\
31 | (setup[index] & 0x00FF))
33#define MSD_SETUP_VALUE(setup) MSD_SETUP_WORD(setup, 2)
34#define MSD_SETUP_INDEX(setup) MSD_SETUP_WORD(setup, 4)
35#define MSD_SETUP_LENGTH(setup) MSD_SETUP_WORD(setup, 6)
38 const uint8_t *data,
size_t len) {
39 usb_scsi_transport_handler_t *trp =
reinterpret_cast<usb_scsi_transport_handler_t*
>(transport->handler);
40 msg_t status = usbTransmit(trp->usbp, trp->ep, data, len);
48 const uint8_t *data,
size_t len) {
49 usb_scsi_transport_handler_t *trp =
reinterpret_cast<usb_scsi_transport_handler_t*
>(transport->handler);
50 msg_t status = usbTransmitStart(trp->usbp, trp->ep, data, len);
58 usb_scsi_transport_handler_t *trp =
reinterpret_cast<usb_scsi_transport_handler_t*
>(transport->handler);
59 msg_t status = usbTransmitWait(trp->usbp, trp->ep);
67 uint8_t *data,
size_t len) {
68 usb_scsi_transport_handler_t *trp =
reinterpret_cast<usb_scsi_transport_handler_t*
>(transport->handler);
69 msg_t status = usbReceive(trp->usbp, trp->ep, data, len);
70 if (MSG_RESET != status)
79 for (
size_t i = 0; i < USB_MSD_LUN_COUNT; i++) {
80 scsiObjectInit(&
m_luns[i].target);
93 while (!chThdShouldTerminateX()) {
94 const msg_t status = usbReceive(
m_usb, USB_MSD_DATA_EP, (uint8_t*)&
m_cbw,
sizeof(
m_cbw));
96 if (MSG_RESET == status) {
97 chThdSleepMilliseconds(50);
103 if (SCSI_SUCCESS == scsiExecCmd(target,
m_cbw.cmd_data)) {
106 sendCsw(CSW_STATUS_FAILED, scsiResidue(target));
116 if (
sizeof(msd_cbw_t) != recvd) {
121 if (cbw.signature != MSD_CBW_SIGNATURE) {
129 if ((cbw.cmd_len & CBW_CMD_LEN_RESERVED_MASK) != 0) {
133 if ((cbw.flags & CBW_FLAGS_RESERVED_MASK) != 0) {
137 if (cbw.lun >= USB_MSD_LUN_COUNT) {
145 m_csw.signature = MSD_CSW_SIGNATURE;
146 m_csw.data_residue = residue;
148 m_csw.status = status;
167 {
'v',CH_KERNEL_MAJOR+
'0',
'.',CH_KERNEL_MINOR+
'0'}
183 BaseBlockDevice *blkdev, uint8_t *
blkbuf,
size_t blkbufsize,
184 const scsi_inquiry_response_t *inquiry,
185 const scsi_unit_serial_number_inquiry_response_t *serialInquiry) {
188 auto& lun =
m_luns[lunIndex];
191 if (NULL == inquiry) {
195 lun.config.inquiry_response = inquiry;
197 if (NULL == serialInquiry) {
201 lun.config.unit_serial_number_inquiry_response = serialInquiry;
203 lun.config.blkbuf =
blkbuf;
204 lun.config.blkbufsize = blkbufsize;
205 lun.config.blkdev = blkdev;
208 scsiStart(&lun.target, &lun.config);
213 if (MSD_SETUP_INDEX(usbp->setup) != 0) {
217 if (usbp->setup[0] == (USB_RTYPE_TYPE_CLASS | USB_RTYPE_RECIPIENT_INTERFACE | USB_RTYPE_DIR_HOST2DEV)
218 && usbp->setup[1] == MSD_REQ_RESET) {
229 usbSetupTransfer(usbp, 0, 0, NULL);
231 }
else if (usbp->setup[0] == (USB_RTYPE_TYPE_CLASS | USB_RTYPE_RECIPIENT_INTERFACE | USB_RTYPE_DIR_DEV2HOST)
232 && usbp->setup[1] == MSD_REQ_GET_MAX_LUN) {
234 static uint8_t zero = USB_MSD_LUN_COUNT - 1;
235 usbSetupTransfer(usbp, &zero, 1, NULL);
void sendCsw(uint8_t status, uint32_t residue)
void attachLun(uint8_t lunIndex, BaseBlockDevice *blkdev, uint8_t *blkbuf, size_t blkbufsize, const scsi_inquiry_response_t *inquiry, const scsi_unit_serial_number_inquiry_response_t *serialInquiry)
LunEntry m_luns[USB_MSD_LUN_COUNT]
MassStorageController(USBDriver *usb)
static bool cbwValid(const msd_cbw_t &cbw, msg_t status)
chibios_rt::Mutex m_lunMutex
static bool cbwMeaningful(const msd_cbw_t &cbw)
void ThreadTask() override
SCSITransport m_scsiTransport
usb_scsi_transport_handler_t m_scsiTransportHandler
A base class for a controller that requires its own thread.
bool msd_request_hook_new(USBDriver *usbp)
static const scsi_unit_serial_number_inquiry_response_t default_scsi_unit_serial_number_inquiry_response
Hardcoded default SCSI unit serial number inquiry response structure.
static const scsi_inquiry_response_t default_scsi_inquiry_response
Hardcoded default SCSI inquiry response structure.
static uint32_t scsi_transport_transmit_start(const SCSITransport *transport, const uint8_t *data, size_t len)
static uint32_t scsi_transport_transmit_wait(const SCSITransport *transport)
static uint32_t scsi_transport_receive(const SCSITransport *transport, uint8_t *data, size_t len)
static uint32_t scsi_transport_transmit(const SCSITransport *transport, const uint8_t *data, size_t len)
uint8_t blkbuf[4 *MMCSD_BLOCK_SIZE]