本帖最后由 Simon21ic 于 2016-1-26 16:39 编辑
U盘设备端使用的是MassStorageClass协议,简单的说一下通信方式:
主机发送31字节的CBW命令,然后根据数据方向,主机发送或者接受N多个块的数据,最后设备发送17字节的CSW应答。
启动后:
- vsf_err_t vsfusbd_MSCBOT_class_init(uint8_t iface,
- struct vsfusbd_device_t *device)
- {
- 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;
- param->scsi_transact = NULL;
- param->device = device;
- vsfscsi_init(¶m->scsi_dev);
- vsfusbd_MSCBOT_on_idle(param);
- return VSFERR_NONE;
- }
- static void vsfusbd_MSCBOT_on_idle(void *p)
- {
- struct vsfusbd_MSCBOT_param_t *param = (struct vsfusbd_MSCBOT_param_t *)p;
- param->bufstream.buffer.buffer = (uint8_t *)¶m->CBW;
- param->bufstream.buffer.size = sizeof(param->CBW);
- param->bufstream.read = false;
- param->stream.user_mem = ¶m->bufstream;
- param->stream.op = &buffer_stream_op;
- stream_init(¶m->stream);
- param->transact.ep = param->ep_out;
- param->transact.data_size = sizeof(param->CBW);
- param->transact.stream = ¶m->stream;
- param->transact.cb.on_finish = vsfusbd_MSCBOT_on_cbw;
- param->transact.cb.param = param;
- vsfusbd_ep_recv(param->device, ¶m->transact);
- }
这里初始化了CBW的流,并调用USB接口,接收EP数据,接收完成后,回调vsfusbd_MSCBOT_on_cbw。
- 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->CBW.dCBWSignature != USBMSC_CBW_SIGNATURE) ||
- (param->CBW.bCBWCBLength < 1) || (param->CBW.bCBWCBLength > 16))
- {
- // TODO: invalid CBW, how to process this error?
- 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);
- }
- }
on_cbw里,会判断命令是否合法,然后调用vsfscsi_execute执行到SCSI层,会返回一个流(根据方向,可以输入也可以输出),然后根据方向,调用ep_send或者ep_recv,直接传入SCSI流。并且,完成后,回调vsfusbd_MSCBOT_on_data_finish。
- 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);
- }
on_finish就只需要简单的调用发送CSW命令即可,当然,发送CSW命令也只是设置流,调用ep_send,并且设置回调为vsfusbd_MSCBOT_on_idle,继续下一个循环。
这样,虽然代码没显式的使用状态机,但是通过这些callback,也是实现了一个状态机,200行不到的代码,就能够实现MSC协议的传输部分。
|