Beispiel #1
0
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, &param->transact);
	}
	else
	{
		vsfusbd_MSCBOT_SendCSW(device, param);
	}

	return VSFERR_NONE;
}
Beispiel #2
0
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 = &param->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;
}
Beispiel #3
0
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(&param->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 = &param->lun_info[param->CBW.bCBWLUN];
		uint8_t index = (param->tick_tock + 1) & 1;
		struct vsf_buffer_t *buffer = &param->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;
}
Beispiel #4
0
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(&param->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 = &param->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, &param->tbuffer.buffer, &param->page_size, 
					&param->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, &param->tbuffer.buffer, 
						&param->page_size, &param->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 = &param->lun_info[param->CBW.bCBWLUN];
		pbuffer = &param->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;
}
Beispiel #5
0
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 = &param->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 = &param->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);
	}
}
Beispiel #6
0
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);
}