vsf_err_t vsf_malstream_read(struct vsf_malstream_t *malstream, uint64_t addr, uint32_t size) { struct vsf_stream_t *stream = (struct vsf_stream_t *)malstream->mbufstream; malstream->addr = addr; malstream->size = size; stream->callback_tx.param = malstream; stream->callback_tx.on_inout = vsf_malstream_on_inout; stream->callback_tx.on_connect = NULL; stream->callback_tx.on_disconnect = NULL; stream_connect_tx(stream); malstream->pt.thread = vsf_malstream_read_thread; malstream->pt.user_data = malstream; return vsfsm_pt_init(&malstream->sm, &malstream->pt); }
void vsfusbd_CDCData_connect(struct vsfusbd_CDC_param_t *param) { stream_connect_tx(param->stream_rx); stream_connect_rx(param->stream_tx); }
static vsf_err_t vsfip_telnetd_thread(struct vsfsm_pt_t *pt, vsfsm_evt_t evt) { struct vsfip_telnetd_t *telnetd = (struct vsfip_telnetd_t *)pt->user_data; vsf_err_t err = VSFERR_NONE; int i; vsfsm_pt_begin(pt); telnetd->caller_pt.sm = pt->sm; telnetd->so = vsfip_socket(AF_INET, IPPROTO_TCP); if (NULL == telnetd->so) { return VSFERR_FAIL; } if ((vsfip_bind(telnetd->so, telnetd->port) != 0) || (vsfip_listen(telnetd->so, telnetd->session_num) != 0)) { err = VSFERR_FAIL; goto fail_socket_connect; } while (1) { telnetd->caller_pt.state = 0; vsfsm_pt_entry(pt); err = vsfip_tcp_accept(&telnetd->caller_pt, evt, telnetd->so, &telnetd->cur_session); if (err > 0) return err; else if (err < 0) { continue; } // get session for (i = 0; i < telnetd->session_num; i++) { if (!telnetd->sessions[i].connected) { struct vsfip_telnetd_session_t *session = &telnetd->sessions[i]; session->connected = true; session->disconnect = false; session->so = telnetd->cur_session; session->stream_rx->callback_tx.param = session; session->stream_rx->callback_tx.on_inout = vsfip_telnetd_session_stream_on_out; session->stream_tx->callback_rx.param = session; session->stream_tx->callback_rx.on_inout = vsfip_telnetd_session_stream_on_in; stream_connect_tx(session->stream_rx); stream_connect_rx(session->stream_tx); vsfsm_sem_init(&session->stream_tx_sem, 0, VSFIP_TELNETD_EVT_STREAM_IN); vsfsm_sem_init(&session->stream_rx_sem, 0, VSFIP_TELNETD_EVT_STREAM_OUT); session->txpt.thread = vsfip_telnetd_session_tx_thread; session->txpt.user_data = session; session->rxpt.thread = vsfip_telnetd_session_rx_thread; session->rxpt.user_data = session; vsfsm_pt_init(&session->txsm, &session->txpt); vsfsm_pt_init(&session->rxsm, &session->rxpt); break; } } if (i == telnetd->session_num) { telnetd->caller_pt.state = 0; vsfsm_pt_entry(pt); err = vsfip_tcp_close(&telnetd->caller_pt, evt, telnetd->cur_session); if (err > 0) return err; vsfip_close(telnetd->cur_session); } } fail_socket_connect: vsfip_close(telnetd->so); telnetd->so = NULL; vsfsm_pt_end(pt); return VSFERR_NONE; }
static struct vsfsm_state_t * vsfusbd_HID_evt_handler(struct vsfsm_t *sm, vsfsm_evt_t evt) { struct vsfusbd_HID_param_t *param = (struct vsfusbd_HID_param_t *)sm->user_data; struct vsfusbd_device_t *device = param->device; uint8_t i; switch (evt) { case VSFSM_EVT_INIT: if (param->ep_out != 0) { vsfusbd_set_OUT_handler(device, param->ep_out, vsfusbd_HID_OUT_hanlder); device->drv->ep.enable_OUT(param->ep_out); } param->bufstream.mem.read = true; param->bufstream.stream.op = &bufstream_op; param->bufstream.stream.callback_tx.on_connect = NULL; param->bufstream.stream.callback_tx.on_disconnect = NULL; param->bufstream.stream.callback_tx.on_inout = NULL; param->output_state = HID_OUTPUT_STATE_WAIT; param->busy = false; for(i = 0; i < param->num_of_report; i++) { struct vsfusbd_HID_report_t *report = ¶m->reports[i]; report->pos = 0; report->idle_cnt = 0; report->changed = true; } // enable timer param->timer4ms.sm = sm; param->timer4ms.evt = VSFUSBD_HID_EVT_TIMER4MS; param->timer4ms.interval = 4; param->timer4ms.trigger_cnt = -1; vsftimer_enqueue(¶m->timer4ms); break; case VSFUSBD_HID_EVT_TIMER4MS: { struct vsfusbd_HID_report_t *report; uint8_t i; for (i = 0; i < param->num_of_report; i++) { report = ¶m->reports[i]; if ((report->type == USB_HID_REPORT_INPUT) && (report->idle != 0)) { report->idle_cnt++; } } if (param->busy) { break; } } // fall through case VSFUSBD_HID_EVT_INREPORT: { struct vsfusbd_transact_t *transact = ¶m->IN_transact; struct vsfusbd_HID_report_t *report; uint8_t i; for (i = 0; i < param->num_of_report; i++) { report = ¶m->reports[i]; if ((report->type == USB_HID_REPORT_INPUT) && (report->changed || ((report->idle != 0) && (report->idle_cnt >= report->idle)))) { param->bufstream.mem.buffer = report->buffer; stream_init(¶m->stream); stream_connect_tx(¶m->stream); transact->ep = param->ep_in; transact->data_size = report->buffer.size; transact->stream = ¶m->stream; transact->zlp = false; transact->cb.on_finish = vsfusbd_HID_INREPORT_callback; transact->cb.param = param; vsfusbd_ep_send(device, transact); report->changed = false; report->idle_cnt = 0; param->busy = true; break; } } } break; } return NULL; }
static struct vsfsm_state_t * vsfshell_evt_handler(struct vsfsm_t *sm, vsfsm_evt_t evt) { struct vsfshell_t *shell = (struct vsfshell_t *)sm->user_data; switch (evt) { case VSFSM_EVT_INIT: shell->prompted = false; shell->output_interrupted = false; shell->tbuffer.buffer.buffer = (uint8_t *)shell->cmd_buff; shell->tbuffer.buffer.size = sizeof(shell->cmd_buff); shell->tbuffer.position = 0; vsfsm_crit_init(&shell->output_crit, VSFSHELL_EVT_OUTPUT_CRIT_AVAIL); shell->stream_rx->callback_rx.param = shell; shell->stream_rx->callback_rx.on_inout = vsfshell_streamrx_on_in; shell->stream_rx->callback_rx.on_connect = vsfshell_streamrx_on_txconn; shell->stream_tx->callback_tx.param = shell; shell->stream_tx->callback_tx.on_inout = vsfshell_streamtx_on_out; shell->stream_tx->callback_tx.on_connect = vsfshell_streamtx_on_rxconn; // shell->output_pt is only called by shell->input_pt shell->output_pt.thread = (vsfsm_pt_thread_t)vsfshell_output_thread; shell->output_pt.sm = sm; shell->output_pt.user_data = shell; // shell->input_pt is used to hanlde the events from stream_rx shell->input_pt.thread = vsfshell_input_thread; shell->input_pt.sm = sm; shell->input_pt.user_data = shell; shell->input_pt.state = 0; shell->input_pt.thread(&shell->input_pt, VSFSM_EVT_INIT); // default input sm is shell itself shell->input_sm = &shell->sm; stream_connect_rx(shell->stream_rx); stream_connect_tx(shell->stream_tx); break; case VSFSHELL_EVT_STREAMRX_ONCONN: break; case VSFSHELL_EVT_STREAMTX_ONCONN: // pass to shell->input_pt shell->input_pt.thread(&shell->input_pt, evt); break; case VSFSHELL_EVT_STREAMRX_ONIN: if (shell->input_sm == &shell->sm) { // pass to shell->input_pt shell->input_pt.thread(&shell->input_pt, evt); } else if (shell->input_sm != NULL) { vsfsm_post_evt(shell->input_sm, evt); } break; case VSFSHELL_EVT_STREAMTX_ONOUT: if (shell->output_sm == &shell->sm) { // pass to shell->input_pt shell->input_pt.thread(&shell->input_pt, evt); } else if (shell->output_sm != NULL) { vsfsm_post_evt(shell->output_sm, evt); } break; } return NULL; }
static vsf_err_t vsf_mal2scsi_execute(struct vsfscsi_lun_t *lun, uint8_t *CDB, uint8_t CDB_size, uint32_t size) { struct vsf_mal2scsi_t *mal2scsi = (struct vsf_mal2scsi_t *)lun->param; struct vsfscsi_transact_t *transact = &lun->dev->transact; struct vsfmal_t *mal = mal2scsi->malstream.mal; uint8_t group_code = CDB[0] & 0xE0, cmd_code = CDB[0] & 0x1F; uint8_t *pbuf; if (transact->lun != NULL) { return VSFERR_FAIL; } // check user_handler first if (mal2scsi->vendor_handlers != NULL) { struct vsfscsi_handler_t *handler = vsfscsi_get_handler(mal2scsi->vendor_handlers, CDB[0]); if (handler != NULL) { return handler->handler(lun, CDB); } } if (!mal2scsi->malstream.mal_ready || (transact->lun != NULL)) { goto exit_not_ready; } switch (group_code) { case SCSI_GROUPCODE6: switch (cmd_code) { case SCSI_CMDCODE_MODE_SELECT: case SCSI_CMDCODE_TEST_UNIT_READY: case SCSI_CMDCODE_VERIFY: case SCSI_CMDCODE_FORMAT_UNIT: case SCSI_CMDCODE_START_STOP_UNIT: case SCSI_CMDCODE_ALLOW_MEDIUM_REMOVAL: break; case SCSI_CMDCODE_REQUEST_SENSE: pbuf = vsf_mal2scsi_prepare_transact(lun, 18, false, true); if (NULL == pbuf) { goto exit_not_ready; } pbuf[0] = 0x70; pbuf[2] = lun->sensekey; pbuf[7] = 0x0A; pbuf[12] = lun->asc; transact->data_size = min(CDB[4], 18); break; case SCSI_CMDCODE_READ: transact->LBA = GET_BE_U16(&CDB[2]); transact->data_size = CDB[4]; goto do_mal_read; break; case SCSI_CMDCODE_WRITE: transact->LBA = GET_BE_U16(&CDB[2]); transact->data_size = CDB[4]; goto do_mal_write; break; case SCSI_CMDCODE_INQUIRY: if (CDB[1] & 1) { // When the EVPD bit is set to one, // the PAGE CODE field specifies which page of // vital product data information the device server shall return if (CDB[2] != 0) { goto exit_invalid_field_in_command; } // 0x00: Supported VPD Pages pbuf = vsf_mal2scsi_prepare_transact(lun, 5, false, true); if (NULL == pbuf) { goto exit_not_ready; } } else { struct vsf_mal2scsi_cparam_t *cparam = (struct vsf_mal2scsi_cparam_t *)&mal2scsi->cparam; if (CDB[2] != 0) { // If the PAGE CODE field is not set to zero // when the EVPD bit is set to zero, // the command shall be terminated with CHECK CONDITION status, // with the sense key set to ILLEGAL REQUEST, // and the additional sense code set to INVALID FIELD IN CDB. goto exit_invalid_field_in_command; } // If the EVPD bit is set to zero, // the device server shall return the standard INQUIRY data. pbuf = vsf_mal2scsi_prepare_transact(lun, 36, false, true); if (NULL == pbuf) { goto exit_not_ready; } pbuf[0] = cparam->type; if (cparam->removable) { pbuf[1] = 0x80; } pbuf[3] = 2; pbuf[4] = 31; pbuf += 8; memcpy(pbuf, cparam->vendor, sizeof(cparam->vendor)); pbuf += sizeof(cparam->vendor); memcpy(pbuf, cparam->product, sizeof(cparam->product)); pbuf += sizeof(cparam->product); memcpy(pbuf, cparam->revision, sizeof(cparam->revision)); } break; case SCSI_CMDCODE_MODE_SENSE: pbuf = vsf_mal2scsi_prepare_transact(lun, 4, false, true); if (NULL == pbuf) { goto exit_not_ready; } pbuf[0] = 3; break; default: goto exit_invalid_command; } break; case SCSI_GROUPCODE10_1: switch (cmd_code) { case SCSI_CMDCODE_READ_FORMAT_CAPACITIES: pbuf = vsf_mal2scsi_prepare_transact(lun, 12, false, true); if (NULL == pbuf) { goto exit_not_ready; } pbuf[3] = 8; SET_BE_U32(&pbuf[4], mal->cap.block_num); SET_BE_U32(&pbuf[8], mal->cap.block_size); pbuf[8] = 2; break; case SCSI_CMDCODE_READ_CAPACITY: pbuf = vsf_mal2scsi_prepare_transact(lun, 8, false, true); if (NULL == pbuf) { goto exit_not_ready; } SET_BE_U32(&pbuf[0], mal->cap.block_num - 1); SET_BE_U32(&pbuf[4], mal->cap.block_size); break; case SCSI_CMDCODE_READ: transact->LBA = GET_BE_U32(&CDB[2]); transact->data_size = GET_BE_U16(&CDB[7]); goto do_mal_read; break; case SCSI_CMDCODE_WRITE: transact->LBA = GET_BE_U32(&CDB[2]); transact->data_size = GET_BE_U16(&CDB[7]); goto do_mal_write; break; default: goto exit_invalid_command; } break; case SCSI_GROUPCODE10_2: switch (cmd_code) { case SCSI_CMDCODE_MODE_SELECT: break; case SCSI_CMDCODE_MODE_SENSE: break; default: goto exit_invalid_command; } break; case SCSI_GROUPCODE16: switch (cmd_code) { case SCSI_CMDCODE_READ: transact->LBA = GET_BE_U64(&CDB[2]); transact->data_size = GET_BE_U32(&CDB[10]); do_mal_read: transact->LBA *= mal->cap.block_size; transact->data_size *= mal->cap.block_size; pbuf = vsf_mal2scsi_prepare_transact(lun, transact->data_size, false, false); if (NULL == pbuf) { goto exit_not_ready; } vsf_malstream_read(&mal2scsi->malstream, transact->LBA, transact->data_size); break; case SCSI_CMDCODE_WRITE: transact->LBA = GET_BE_U64(&CDB[2]); transact->data_size = GET_BE_U32(&CDB[10]); do_mal_write: transact->LBA *= mal->cap.block_size; transact->data_size *= mal->cap.block_size; pbuf = vsf_mal2scsi_prepare_transact(lun, transact->data_size, true, false); if (NULL == pbuf) { goto exit_not_ready; } vsf_malstream_write(&mal2scsi->malstream, transact->LBA, transact->data_size); break; default: goto exit_invalid_command; } break; case SCSI_GROUPCODE12: switch (cmd_code) { case SCSI_CMDCODE_READ: transact->LBA = GET_BE_U32(&CDB[2]); transact->data_size = GET_BE_U32(&CDB[6]); goto do_mal_read; break; case SCSI_CMDCODE_WRITE: transact->LBA = GET_BE_U32(&CDB[2]); transact->data_size = GET_BE_U32(&CDB[6]); goto do_mal_write; break; default: goto exit_invalid_command; } break; default: goto exit_invalid_command; } lun->sensekey = SCSI_SENSEKEY_NO_SENSE; lun->asc = SCSI_ASC_NONE; if (transact->lun->stream != NULL) { if (transact->lun->stream->op == &bufstream_op) { stream_connect_tx(transact->lun->stream); } } return VSFERR_NONE; exit_invalid_command: lun->sensekey = SCSI_SENSEKEY_ILLEGAL_REQUEST; lun->asc = SCSI_ASC_INVALID_COMMAND; return VSFERR_FAIL; exit_invalid_field_in_command: lun->sensekey = SCSI_SENSEKEY_ILLEGAL_REQUEST; lun->asc = SCSI_ASC_INVALID_FIELD_IN_COMMAND; return VSFERR_FAIL; exit_not_ready: lun->sensekey = SCSI_SENSEKEY_NOT_READY; lun->asc = SCSI_ASC_NONE; return VSFERR_FAIL; }