static void msc_data_rx_cb(usbd_device *usbd_dev, uint8_t ep) { usbd_mass_storage *ms; struct usb_msc_trans *trans; int len, max_len, left; void *p; ms = &_mass_storage; trans = &ms->trans; /* RX only */ left = sizeof(struct usb_msc_cbw) - trans->cbw_cnt; if (0 < left) { max_len = MIN(ms->ep_out_size, left); p = &trans->cbw.buf[0x1ff & trans->cbw_cnt]; len = usbd_ep_read_packet(usbd_dev, ep, p, max_len); trans->cbw_cnt += len; if (sizeof(struct usb_msc_cbw) == trans->cbw_cnt) { scsi_command(ms, trans, EVENT_CBW_VALID); if (trans->byte_count < trans->bytes_to_read) { /* We must wait until there is something to * read again. */ return; } } } if (trans->byte_count < trans->bytes_to_read) { if (0 < trans->block_count) { if ((0 == trans->byte_count) && (NULL != ms->lock)) { (*ms->lock)(); } } left = trans->bytes_to_read - trans->byte_count; max_len = MIN(ms->ep_out_size, left); p = &trans->msd_buf[0x1ff & trans->byte_count]; len = usbd_ep_read_packet(usbd_dev, ep, p, max_len); trans->byte_count += len; if (0 < trans->block_count) { if (0 == (0x1ff & trans->byte_count)) { uint32_t lba; lba = trans->lba_start + trans->current_block; if (0 != (*ms->write_block)(lba, trans->msd_buf)) { /* Error */ } trans->current_block++; } } /////////////////////ADD THIS////////////////////////////////////////////////////////////////////////////////// if (false == trans->csw_valid) { scsi_command(ms, trans, EVENT_NEED_STATUS); trans->csw_valid = true; } left = sizeof(struct usb_msc_csw) - trans->csw_sent; if (0 < left) { max_len = MIN(ms->ep_out_size, left); p = &trans->csw.buf[trans->csw_sent]; len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p, max_len); trans->csw_sent += len; } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////// } else if (trans->byte_count < trans->bytes_to_write) { if (0 < trans->block_count) { if ((0 == trans->byte_count) && (NULL != ms->lock)) { (*ms->lock)(); } if (0 == (0x1ff & trans->byte_count)) { uint32_t lba; lba = trans->lba_start + trans->current_block; if (0 != (*ms->read_block)(lba, trans->msd_buf)) { /* Error */ } trans->current_block++; } } left = trans->bytes_to_write - trans->byte_count; max_len = MIN(ms->ep_out_size, left); p = &trans->msd_buf[0x1ff & trans->byte_count]; len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p, max_len); trans->byte_count += len; } else { if (0 < trans->block_count) { if (trans->current_block == trans->block_count) { uint32_t lba; lba = trans->lba_start + trans->current_block; if (0 != (*ms->write_block)(lba, trans->msd_buf)) { /* Error */ } trans->current_block = 0; if (NULL != ms->unlock) { (*ms->unlock)(); } } } if (false == trans->csw_valid) { scsi_command(ms, trans, EVENT_NEED_STATUS); trans->csw_valid = true; } left = sizeof(struct usb_msc_csw) - trans->csw_sent; if (0 < left) { max_len = MIN(ms->ep_out_size, left); p = &trans->csw.buf[trans->csw_sent]; len = usbd_ep_write_packet(usbd_dev, ms->ep_in, p, max_len); trans->csw_sent += len; } } }
static void scsi_read_format_capacities(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event) { if (EVENT_CBW_VALID == event) { trans->msd_buf[3] = 0x08; trans->msd_buf[4] = ms->block_count >> 24; trans->msd_buf[5] = 0xff & (ms->block_count >> 16); trans->msd_buf[6] = 0xff & (ms->block_count >> 8); trans->msd_buf[7] = 0xff & ms->block_count; trans->msd_buf[8] = 0x02; trans->msd_buf[9] = 0; trans->msd_buf[10] = 0x02; trans->msd_buf[11] = 0; trans->bytes_to_write = 9; set_sbc_status_good(ms); } } static void scsi_command(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event) { if (EVENT_CBW_VALID == event) { /* Setup the default success */ trans->csw_sent = 0; trans->csw.csw.dCSWSignature = CSW_SIGNATURE; trans->csw.csw.dCSWTag = trans->cbw.cbw.dCBWTag; trans->csw.csw.dCSWDataResidue = 0; trans->csw.csw.bCSWStatus = CSW_STATUS_SUCCESS; trans->bytes_to_write = 0; trans->bytes_to_read = 0; trans->byte_count = 0; } switch (trans->cbw.cbw.CBWCB[0]) { case SCSI_TEST_UNIT_READY: case SCSI_SEND_DIAGNOSTIC: /* Do nothing, just send the success. */ set_sbc_status_good(ms); break; case SCSI_FORMAT_UNIT: scsi_format_unit(ms, trans, event); break; case SCSI_REQUEST_SENSE: scsi_request_sense(ms, trans, event); break; case SCSI_MODE_SENSE_6: scsi_mode_sense_6(ms, trans, event); break; case SCSI_READ_6: scsi_read_6(ms, trans, event); break; case SCSI_INQUIRY: scsi_inquiry(ms, trans, event); break; case SCSI_READ_CAPACITY: scsi_read_capacity(ms, trans, event); break; case SCSI_READ_10: scsi_read_10(ms, trans, event); break; case SCSI_WRITE_6: scsi_write_6(ms, trans, event); break; case SCSI_WRITE_10: scsi_write_10(ms, trans, event); break; //////////////////ADD THIS/////////////////////////////////////////////////////////////////////////////////////////////////// case SCSI_READ_FORMAT_CAPACITIES: scsi_read_format_capacities(ms, trans, event); break; //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// default: set_sbc_status(ms, SBC_SENSE_KEY_ILLEGAL_REQUEST, SBC_ASC_INVALID_COMMAND_OPERATION_CODE, SBC_ASCQ_NA); trans->bytes_to_write = 0; trans->bytes_to_read = 0; trans->csw.csw.bCSWStatus = CSW_STATUS_FAILED; break; } }
static const uint8_t _spc3_inquiry_sn_response[20] = { 0x00, 0x80, 0x00, 0x10, // . 16 (third pin 123456) 't','h','i','r','d',' ','p','i','n',' ','1','2','3','4','5','6' }; static void scsi_inquiry(usbd_mass_storage *ms, struct usb_msc_trans *trans, enum trans_event event) { if (EVENT_CBW_VALID == event) { uint8_t evpd; uint8_t *buf; buf = get_cbw_buf(trans); evpd = 1 & buf[1]; if (evpd == 0) { size_t len; trans->bytes_to_write = sizeof(_spc3_inquiry_response); memcpy(trans->msd_buf, _spc3_inquiry_response, sizeof(_spc3_inquiry_response)); len = strlen(ms->vendor_id); len = MIN(len, 8); memcpy(&trans->msd_buf[8], ms->vendor_id, len); len = strlen(ms->product_id); len = MIN(len, 16); memcpy(&trans->msd_buf[16], ms->product_id, len); len = strlen(ms->product_revision_level); len = MIN(len, 4); memcpy(&trans->msd_buf[32], ms->product_revision_level, len); trans->csw.csw.dCSWDataResidue = sizeof(_spc3_inquiry_response); set_sbc_status_good(ms); } /////////////////////////////////ADD THIS///////////////////////////////////////////////////////////////////////////// else if (evpd == 1) { trans->bytes_to_write = sizeof(_spc3_inquiry_sn_response); memcpy(trans->msd_buf, _spc3_inquiry_sn_response, sizeof(_spc3_inquiry_sn_response)); trans->csw.csw.dCSWDataResidue = sizeof(_spc3_inquiry_sn_response); set_sbc_status_good(ms); } /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// else { /* TODO: Add VPD 0x83 support */ /* TODO: Add VPD 0x00 support */ } } }
Source: https://habr.com/ru/post/304924/
All Articles