本帖最后由 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协议的传输部分。
|