static vsf_err_t vsfusbd_MSCBOT_ErrHandler(struct vsfusbd_device_t *device, struct vsfusbd_MSCBOT_param_t *param, uint8_t error) { param->CSW.dCSWStatus = error; // OUT: NACK(don't enable_OUT, if OUT is enabled, it will be disabled after data is sent) // IN: if (dCBWDataTransferLength > 0) // send_ZLP // send_CSW if (((param->CBW.bmCBWFlags & USBMSC_CBWFLAGS_DIR_MASK) == USBMSC_CBWFLAGS_DIR_IN) && (param->CBW.dCBWDataTransferLength > 0)) { if (param->scsi_transact != NULL) { param->scsi_transact->data_size = 0; } param->transact.ep = param->ep_in; param->transact.data_size = 0; param->transact.stream = NULL; param->transact.cb.on_finish = vsfusbd_MSCBOT_on_data_finish; param->transact.cb.param = param; return vsfusbd_ep_send(param->device, ¶m->transact); } else { vsfusbd_MSCBOT_SendCSW(device, param); } return VSFERR_NONE; }
static vsf_err_t vsfusbd_MSCBOT_IN_hanlder(struct vsfusbd_device_t *device, uint8_t ep) { struct interface_usbd_t *drv = device->drv; struct vsfusbd_config_t *config = &device->config[device->configuration]; int8_t iface = config->ep_OUT_iface_map[ep]; struct vsfusbd_MSCBOT_param_t *param = NULL; uint16_t pkg_size; uint32_t remain_size; uint8_t *pbuffer; if (iface < 0) { return VSFERR_FAIL; } param = (struct vsfusbd_MSCBOT_param_t *)config->iface[iface].protocol_param; if (NULL == param) { return VSFERR_FAIL; } switch (param->bot_status) { case VSFUSBD_MSCBOT_STATUS_ERROR: case VSFUSBD_MSCBOT_STATUS_CSW: param->bot_status = VSFUSBD_MSCBOT_STATUS_IDLE; drv->ep.enable_OUT(param->ep_out); break; case VSFUSBD_MSCBOT_STATUS_IN: remain_size = param->page_size - param->tbuffer.position; pbuffer = ¶m->tbuffer.buffer.buffer[param->tbuffer.position]; if (remain_size) { pkg_size = vsfusbd_MSCBOT_GetInPkgSize(drv, ep, remain_size); drv->ep.write_IN_buffer(param->ep_in, pbuffer, pkg_size); drv->ep.set_IN_count(param->ep_in, pkg_size); param->tbuffer.position += pkg_size; return VSFERR_NONE; } param->tbuffer.position = 0; if (++param->cur_usb_page >= param->page_num) { return vsfusbd_MSCBOT_SendCSW(device, param); } if (param->cur_scsi_page > param->cur_usb_page) { param->idle = false; param->tbuffer.buffer = *vsfusbd_MSCBOT_GetBuffer(param); return vsfusbd_MSCBOT_IN_hanlder(device, ep); } else { param->idle = true; } break; default: return VSFERR_FAIL; } return VSFERR_NONE; }
static vsf_err_t vsfusbd_MSCBOT_class_poll(uint8_t iface, struct vsfusbd_device_t *device) { struct interface_usbd_t *drv = device->drv; struct vsfusbd_config_t *config = &device->config[device->configuration]; struct vsfusbd_MSCBOT_param_t *param = (struct vsfusbd_MSCBOT_param_t *)config->iface[iface].protocol_param; enum vsfusbd_MSCBOT_status_t bot_status = param->bot_status; uint8_t i; if (NULL == param) { return VSFERR_FAIL; } for (i = 0; i <= param->max_lun; i++) { SCSI_Poll(¶m->lun_info[i]); } if (!param->poll) { return VSFERR_NONE; } if (((VSFUSBD_MSCBOT_STATUS_IN == bot_status) && (param->cur_scsi_page < param->page_num) && ((param->cur_scsi_page - param->cur_usb_page) < 2)) || ((VSFUSBD_MSCBOT_STATUS_OUT == bot_status) && (param->cur_scsi_page < param->page_num) && (param->cur_usb_page > param->cur_scsi_page))) { struct SCSI_LUN_info_t *lun_info = ¶m->lun_info[param->CBW.bCBWLUN]; uint8_t index = (param->tick_tock + 1) & 1; struct vsf_buffer_t *buffer = ¶m->page_buffer[index]; vsf_err_t err; if (USBMSC_CSW_OK == param->dCSWStatus) { err = SCSI_IO(param->cur_handlers, lun_info, param->CBW.CBWCB, buffer, param->cur_scsi_page); if (err != VSFERR_NONE) { if (err > 0) { // not failure here return VSFERR_NONE; } return vsfusbd_MSCBOT_ErrHandler(device, param, USBMSC_CSW_FAIL); } } param->cur_scsi_page++; if (VSFUSBD_MSCBOT_STATUS_IN == bot_status) { if (param->idle) { param->idle = false; param->tbuffer.buffer = *vsfusbd_MSCBOT_GetBuffer(param); vsfusbd_MSCBOT_IN_hanlder((void *)device, param->ep_in); } } else if (VSFUSBD_MSCBOT_STATUS_OUT == bot_status) { if (param->cur_scsi_page >= param->page_num) { return vsfusbd_MSCBOT_SendCSW(device, param); } if (param->idle) { param->idle = false; param->tbuffer.buffer = *vsfusbd_MSCBOT_GetBuffer(param); return drv->ep.enable_OUT(param->ep_out); } } } return VSFERR_NONE; }
static vsf_err_t vsfusbd_MSCBOT_OUT_hanlder(struct vsfusbd_device_t *device, uint8_t ep) { struct interface_usbd_t *drv = device->drv; struct vsfusbd_config_t *config = &device->config[device->configuration]; int8_t iface = config->ep_OUT_iface_map[ep]; struct vsfusbd_MSCBOT_param_t *param = NULL; struct SCSI_LUN_info_t *lun_info = NULL; uint16_t pkg_size, ep_size; uint8_t buffer[64], *pbuffer; if (iface < 0) { return VSFERR_FAIL; } param = (struct vsfusbd_MSCBOT_param_t *)config->iface[iface].protocol_param; if (NULL == param) { return VSFERR_FAIL; } ep_size = drv->ep.get_OUT_epsize(ep); pkg_size = drv->ep.get_OUT_count(ep); if (pkg_size > ep_size) { return VSFERR_FAIL; } drv->ep.read_OUT_buffer(ep, buffer, pkg_size); switch (param->bot_status) { case VSFUSBD_MSCBOT_STATUS_IDLE: memcpy(¶m->CBW, buffer, sizeof(param->CBW)); if ((param->CBW.dCBWSignature != USBMSC_CBW_SIGNATURE) || (param->CBW.bCBWLUN > param->max_lun) || (pkg_size != 31)) { // TODO: invalid CBW, how to process this error? return VSFERR_FAIL; } lun_info = ¶m->lun_info[param->CBW.bCBWLUN]; if ((param->CBW.bCBWCBLength < 1) || (param->CBW.bCBWCBLength > 16)) { // TODO: invalid CB length, how to process this error? return VSFERR_FAIL; } param->page_size = param->page_num = 0; param->cur_handlers = NULL; param->tbuffer.buffer = *vsfusbd_MSCBOT_GetBuffer(param); param->dCSWStatus = USBMSC_CSW_OK; if (SCSI_Handle(param->cur_handlers, lun_info, param->CBW.CBWCB, ¶m->tbuffer.buffer, ¶m->page_size, ¶m->page_num)) { enum SCSI_errcode_t errcode = SCSI_GetErrorCode(); if (SCSI_ERRCODE_INVALID_COMMAND == errcode) { param->cur_handlers = param->user_handlers; if (NULL == param->cur_handlers) { vsfusbd_MSCBOT_ErrHandler(device, param, USBMSC_CSW_FAIL); return VSFERR_FAIL; } else if (SCSI_Handle(param->cur_handlers, lun_info, param->CBW.CBWCB, ¶m->tbuffer.buffer, ¶m->page_size, ¶m->page_num)) { errcode = SCSI_GetErrorCode(); if (SCSI_ERRCODE_INVALID_COMMAND == errcode) { vsfusbd_MSCBOT_ErrHandler(device, param, USBMSC_CSW_FAIL); return VSFERR_FAIL; } return vsfusbd_MSCBOT_ErrHandler(device, param, USBMSC_CSW_FAIL); } } return vsfusbd_MSCBOT_ErrHandler(device, param, USBMSC_CSW_FAIL); } param->tbuffer.position = param->cur_usb_page = param->cur_scsi_page = 0; if (param->CBW.dCBWDataTransferLength) { if ((param->CBW.bmCBWFlags & USBMSC_CBWFLAGS_DIR_MASK) == USBMSC_CBWFLAGS_DIR_IN) { param->bot_status = VSFUSBD_MSCBOT_STATUS_IN; if (param->tbuffer.buffer.size) { return vsfusbd_MSCBOT_IN_hanlder(device, param->ep_in); } else { param->poll = true; param->idle = true; } } else { param->bot_status = VSFUSBD_MSCBOT_STATUS_OUT; param->poll = true; param->idle = false; return drv->ep.enable_OUT(param->ep_out); } } else { return vsfusbd_MSCBOT_SendCSW(device, param); } break; case VSFUSBD_MSCBOT_STATUS_OUT: if (param->cur_usb_page >= param->page_num) { vsfusbd_MSCBOT_ErrHandler(device, param, USBMSC_CSW_PHASE_ERROR); lun_info->status.sense_key = SCSI_SENSEKEY_ILLEGAL_REQUEST; lun_info->status.asc = SCSI_ASC_INVALID_FIELED_IN_COMMAND; return VSFERR_FAIL; } lun_info = ¶m->lun_info[param->CBW.bCBWLUN]; pbuffer = ¶m->tbuffer.buffer.buffer[param->tbuffer.position]; if ((pkg_size + param->tbuffer.position) <= param->page_size) { memcpy(pbuffer, buffer, pkg_size); param->tbuffer.position += pkg_size; if (param->tbuffer.position < param->page_size) { drv->ep.enable_OUT(param->ep_out); return VSFERR_NONE; } param->tbuffer.position = 0; param->cur_usb_page++; if ((param->cur_usb_page - param->cur_scsi_page) < 2) { param->idle = false; param->tbuffer.buffer = *vsfusbd_MSCBOT_GetBuffer(param); drv->ep.enable_OUT(param->ep_out); } else { param->idle = true; } } else { vsfusbd_MSCBOT_ErrHandler(device, param, USBMSC_CSW_PHASE_ERROR); lun_info->status.sense_key = SCSI_SENSEKEY_ILLEGAL_REQUEST; lun_info->status.asc = SCSI_ASC_INVALID_FIELED_IN_COMMAND; return VSFERR_FAIL; } break; default: vsfusbd_MSCBOT_ErrHandler(device, param, USBMSC_CSW_PHASE_ERROR); return VSFERR_FAIL; } return VSFERR_NONE; }
static void vsfusbd_MSCBOT_on_cbw(void *p) { struct vsfusbd_MSCBOT_param_t *param = (struct vsfusbd_MSCBOT_param_t *)p; struct vsfusbd_device_t *device = param->device; struct vsfscsi_lun_t *lun; if (param->transact.data_size || (param->CBW.dCBWSignature != USBMSC_CBW_SIGNATURE) || (param->CBW.bCBWCBLength < 1) || (param->CBW.bCBWCBLength > 16)) { vsfusbd_MSCBOT_on_idle(param); return; } if (param->CBW.bCBWLUN > param->scsi_dev.max_lun) { reply_failure: vsfusbd_MSCBOT_ErrHandler(device, param, USBMSC_CSW_FAIL); return; } param->CSW.dCSWStatus = USBMSC_CSW_OK; lun = ¶m->scsi_dev.lun[param->CBW.bCBWLUN]; if (vsfscsi_execute(lun, param->CBW.CBWCB)) { goto reply_failure; } if (param->CBW.dCBWDataTransferLength) { struct vsfusbd_transact_t *transact = ¶m->transact; if (!lun->transact.data_size) { goto reply_failure; } param->scsi_transact = &lun->transact; transact->data_size = param->scsi_transact->data_size; transact->stream = param->scsi_transact->stream; transact->cb.on_finish = vsfusbd_MSCBOT_on_data_finish; transact->cb.param = param; if ((param->CBW.bmCBWFlags & USBMSC_CBWFLAGS_DIR_MASK) == USBMSC_CBWFLAGS_DIR_IN) { transact->ep = param->ep_in; vsfusbd_ep_send(param->device, transact); } else { transact->ep = param->ep_out; vsfusbd_ep_recv(param->device, transact); } } else { if (param->scsi_transact->data_size && param->scsi_transact) { vsfscsi_cancel_transact(param->scsi_transact); param->scsi_transact = NULL; } vsfusbd_MSCBOT_SendCSW(device, param); } }
static void vsfusbd_MSCBOT_on_data_finish(void *p) { struct vsfusbd_MSCBOT_param_t *param = (struct vsfusbd_MSCBOT_param_t *)p; vsfusbd_MSCBOT_SendCSW(param->device, param); }