Sync betaflight to Gitea

This commit is contained in:
2026-08-03 16:37:10 +08:00
commit ad3163cf91
4712 changed files with 3301380 additions and 0 deletions
@@ -0,0 +1,669 @@
/**
**************************************************************************
* @file usbh_msc_bot_scsi.c
* @brief usb host msc bulk-only transfer and scsi type
**************************************************************************
* Copyright notice & Disclaimer
*
* The software Board Support Package (BSP) that is made available to
* download from Artery official website is the copyrighted work of Artery.
* Artery authorizes customers to use, copy, and distribute the BSP
* software and its related documentation for the purpose of design and
* development in conjunction with Artery microcontrollers. Use of the
* software is governed by this copyright notice and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
* GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
* TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
* STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
* INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
*
**************************************************************************
*/
#include "usbh_msc_bot_scsi.h"
#include "usbh_msc_class.h"
#include "usb_conf.h"
#include "usbh_core.h"
#include "usbh_ctrl.h"
/** @addtogroup AT32F435_437_middlewares_usbh_class
* @{
*/
/** @defgroup USBH_msc_bot_scsi_class
* @brief usb host class msc bot scsi
* @{
*/
/** @defgroup USBH_msc_bot_scsi_class_private_functions
* @{
*/
static usb_sts_type usbh_bot_cbw(msc_bot_cbw_type *cbw, uint32_t data_length, uint8_t cmd_len, uint8_t flag);
static usb_sts_type usbh_cmd_inquiry(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun);
static usb_sts_type usbh_cmd_capacity10(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun);
static usb_sts_type usbh_cmd_test_unit_ready(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun);
static usb_sts_type usbh_cmd_requset_sense(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun);
static usb_sts_type usbh_cmd_write(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun,
uint32_t data_len, uint32_t address, uint8_t *buffer);
static usb_sts_type usbh_cmd_read(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun,
uint32_t data_len, uint32_t address, uint8_t *buffer);
/**
* @brief usb host bulk-only cbw
* @param cbw: to the structure of msc_bot_cbw_type
* @param data_length: data length
* @param cmd_len: command len
* @param flag: cbw flag
* @retval status: usb_sts_type status
*/
static usb_sts_type usbh_bot_cbw(msc_bot_cbw_type *cbw, uint32_t data_length, uint8_t cmd_len, uint8_t flag)
{
uint8_t i_index;
cbw->dCBWSignature = MSC_CBW_SIGNATURE;
cbw->dCBWTag = MSC_CBW_TAG;
cbw->dCBWDataTransferLength = data_length;
cbw->bmCBWFlags = flag;
cbw->bCBWCBLength = cmd_len;
for(i_index = 0; i_index < MSC_CBW_CB_LEN; i_index ++)
{
cbw->CBWCB[i_index] = 0x00;
}
return USB_OK;
}
/**
* @brief usb host msc command inquiry
* @param bot_trans: to the structure of msc_bot_trans_type
* @param cmd: command buffer
* @param lun: logical unit number
* @retval status: usb_sts_type status
*/
static usb_sts_type usbh_cmd_inquiry(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun)
{
usbh_msc_type *msc_struct = (usbh_msc_type *)bot_trans->msc_struct;
cmd[0] = MSC_OPCODE_INQUIRY;
cmd[1] = lun << 5;
cmd[4] = MSC_INQUIRY_DATA_LEN;
bot_trans->data = (uint8_t *)&msc_struct->l_unit_n[lun].inquiry;
return USB_OK;
}
/**
* @brief usb host msc command capacity10
* @param bot_trans: to the structure of msc_bot_trans_type
* @param cmd: command buffer
* @param lun: logical unit number
* @retval status: usb_sts_type status
*/
static usb_sts_type usbh_cmd_capacity10(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun)
{
usbh_msc_type *msc_struct = (usbh_msc_type *)bot_trans->msc_struct;
cmd[0] = MSC_OPCODE_CAPACITY;
cmd[1] = lun << 5;
msc_struct->bot_trans.data = (uint8_t *)bot_trans->buffer;
return USB_OK;
}
/**
* @brief usb host msc command test unit ready
* @param bot_trans: to the structure of msc_bot_trans_type
* @param cmd: command buffer
* @param lun: logical unit number
* @retval status: usb_sts_type status
*/
static usb_sts_type usbh_cmd_test_unit_ready(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun)
{
cmd[0] = MSC_OPCODE_TEST_UNIT_READY;
cmd[1] = lun << 5;
return USB_OK;
}
/**
* @brief usb host msc command request sense
* @param bot_trans: to the structure of msc_bot_trans_type
* @param cmd: command buffer
* @param lun: logical unit number
* @retval status: usb_sts_type status
*/
static usb_sts_type usbh_cmd_requset_sense(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun)
{
cmd[0] = MSC_OPCODE_REQUEST_SENSE;
cmd[1] = lun << 5;
cmd[4] = MSC_REQUEST_SENSE_DATA_LEN;
bot_trans->data = bot_trans->buffer;
return USB_OK;
}
/**
* @brief usb host msc command write
* @param bot_trans: to the structure of msc_bot_trans_type
* @param cmd: command buffer
* @param lun: logical unit number
* @param data_len: transfer data length
* @param address: logical block address
* @param buffer: transfer data buffer
* @retval status: usb_sts_type status
*/
static usb_sts_type usbh_cmd_write(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun,
uint32_t data_len, uint32_t address, uint8_t *buffer)
{
cmd[0] = MSC_OPCODE_WRITE10;
cmd[1] = lun << 5;
cmd[2] = (uint8_t)(address >> 24);
cmd[3] = (uint8_t)(address >> 16);
cmd[4] = (uint8_t)(address >> 8);
cmd[5] = (uint8_t)(address & 0xFF);
cmd[7] = data_len >> 8;
cmd[8] = data_len;
bot_trans->data = buffer;
return USB_OK;
}
/**
* @brief usb host msc command read
* @param bot_trans: to the structure of msc_bot_trans_type
* @param cmd: command buffer
* @param lun: logical unit number
* @param data_len: transfer data length
* @param address: logical block address
* @param buffer: transfer data buffer
* @retval status: usb_sts_type status
*/
static usb_sts_type usbh_cmd_read(msc_bot_trans_type *bot_trans, uint8_t *cmd, uint8_t lun,
uint32_t data_len, uint32_t address, uint8_t *buffer)
{
cmd[0] = MSC_OPCODE_READ10;
cmd[1] = lun << 5;
cmd[2] = (uint8_t)(address >> 24);
cmd[3] = (uint8_t)(address >> 16);
cmd[4] = (uint8_t)(address >> 8);
cmd[5] = (uint8_t)(address & 0xFF);
cmd[7] = data_len >> 8;
cmd[8] = data_len;
bot_trans->data = buffer;
return USB_OK;
}
/**
* @brief usb host csw check
* @param cbw: to the structure of msc_bot_cbw_type
* @param csw: to the structure of msc_bot_csw_type
* @retval status: usb_sts_type status
*/
usb_sts_type usbh_check_csw(void *uhost, msc_bot_cbw_type *cbw, msc_bot_csw_type *csw)
{
usb_sts_type status = USB_FAIL;
if(csw->dCBWSignature == MSC_CSW_SIGNATURE)
{
if(csw->dCBWTag == cbw->dCBWTag)
{
if(csw->bCSWStatus == 0)
{
status = USB_OK;
}
}
}
return status;
}
/**
* @brief usb host msc bulk-only request
* @param uhost: to the structure of usbh_core_type
* @param bot_trans: to the structure of msc_bot_trans_type
* @retval status: usb_sts_type status
*/
usb_sts_type usb_bot_request(void *uhost, msc_bot_trans_type *bot_trans)
{
usb_sts_type status = USB_WAIT;
urb_sts_type urb_status;
usb_sts_type clr_status;
usbh_core_type *puhost = (usbh_core_type *)uhost;
usbh_msc_type *msc_struct = (usbh_msc_type *)bot_trans->msc_struct;
switch(bot_trans->bot_state)
{
case BOT_STATE_SEND_CBW:
usbh_bulk_send(puhost, msc_struct->chout, (uint8_t *)(&bot_trans->cbw), MSC_CBW_LEN);
bot_trans->bot_state = BOT_STATE_SEND_CBW_WAIT;
break;
case BOT_STATE_SEND_CBW_WAIT:
urb_status = usbh_get_urb_status(puhost, msc_struct->chout);
if(urb_status == URB_DONE)
{
if(bot_trans->cbw.dCBWDataTransferLength != 0)
{
if(bot_trans->cbw.bmCBWFlags == MSC_CBW_FLAG_IN)
{
bot_trans->bot_state = BOT_STATE_DATA_IN;
}
else
{
bot_trans->bot_state = BOT_STATE_DATA_OUT;
}
}
else
{
bot_trans->bot_state = BOT_STATE_RECV_CSW;
}
}
else if(urb_status == URB_NOTREADY)
{
bot_trans->bot_state = BOT_STATE_SEND_CBW;
}
else if(urb_status == URB_STALL)
{
bot_trans->bot_state = BOT_STATE_ERROR_OUT;
}
break;
case BOT_STATE_DATA_IN:
usbh_bulk_recv(puhost, msc_struct->chin, bot_trans->data,
msc_struct->in_maxpacket);
bot_trans->bot_state = BOT_STATE_DATA_IN_WAIT;
break;
case BOT_STATE_DATA_IN_WAIT:
urb_status = usbh_get_urb_status(puhost, msc_struct->chin);
if(urb_status == URB_DONE)
{
if(bot_trans->cbw.dCBWDataTransferLength > msc_struct->in_maxpacket)
{
bot_trans->data += msc_struct->in_maxpacket;
bot_trans->cbw.dCBWDataTransferLength -= msc_struct->in_maxpacket;
}
else
{
bot_trans->cbw.dCBWDataTransferLength = 0;
}
if(bot_trans->cbw.dCBWDataTransferLength > 0)
{
usbh_bulk_recv(puhost, msc_struct->chin, bot_trans->data,
msc_struct->in_maxpacket);
}
else
{
bot_trans->bot_state = BOT_STATE_RECV_CSW;
}
}
else if(urb_status == URB_STALL)
{
bot_trans->bot_state = BOT_STATE_ERROR_IN;
}
break;
case BOT_STATE_DATA_OUT:
usbh_bulk_send(puhost, msc_struct->chout, bot_trans->data, msc_struct->out_maxpacket);
bot_trans->bot_state = BOT_STATE_DATA_OUT_WAIT;
break;
case BOT_STATE_DATA_OUT_WAIT:
urb_status = usbh_get_urb_status(puhost, msc_struct->chout);
if(urb_status == URB_DONE)
{
if(bot_trans->cbw.dCBWDataTransferLength > msc_struct->out_maxpacket)
{
bot_trans->data += msc_struct->out_maxpacket;
bot_trans->cbw.dCBWDataTransferLength -= msc_struct->out_maxpacket;
}
else
{
bot_trans->cbw.dCBWDataTransferLength = 0;
}
if(bot_trans->cbw.dCBWDataTransferLength > 0)
{
usbh_bulk_send(puhost, msc_struct->chout, bot_trans->data, msc_struct->out_maxpacket);
}
else
{
bot_trans->bot_state = BOT_STATE_RECV_CSW;
}
}
else if(urb_status == URB_NOTREADY)
{
bot_trans->bot_state = BOT_STATE_DATA_OUT;
}
else if(urb_status == URB_STALL)
{
bot_trans->bot_state = BOT_STATE_ERROR_OUT;
}
break;
case BOT_STATE_RECV_CSW:
usbh_bulk_recv(puhost, msc_struct->chin, (uint8_t *)&bot_trans->csw,
MSC_CSW_LEN);
bot_trans->bot_state = BOT_STATE_RECV_CSW_WAIT;
break;
case BOT_STATE_RECV_CSW_WAIT:
urb_status = usbh_get_urb_status(puhost, msc_struct->chin);
if(urb_status == URB_DONE)
{
bot_trans->bot_state = BOT_STATE_SEND_CBW;
bot_trans->cmd_state = CMD_STATE_SEND;
status = usbh_check_csw(uhost, &bot_trans->cbw, &bot_trans->csw);
}
else if(urb_status == URB_STALL)
{
bot_trans->bot_state = BOT_STATE_ERROR_IN;
}
break;
case BOT_STATE_ERROR_IN:
clr_status = usbh_clear_ept_feature(puhost, msc_struct->eptin, msc_struct->chin);
if(clr_status == USB_OK)
{
bot_trans->bot_state = BOT_STATE_RECV_CSW;
usbh_set_toggle(puhost, msc_struct->chin, 0);
}
break;
case BOT_STATE_ERROR_OUT:
clr_status = usbh_clear_ept_feature(puhost, msc_struct->eptout, msc_struct->chout);
if(clr_status == USB_OK)
{
usbh_set_toggle(puhost, msc_struct->chout, 1 - puhost->hch[msc_struct->chout].toggle_out);
usbh_set_toggle(puhost, msc_struct->chin, 0);
bot_trans->bot_state = BOT_STATE_ERROR_IN;
}
break;
case BOT_STATE_COMPLETE:
break;
default:
break;
}
return status;
}
/**
* @brief usb host msc bulk-only get inquiry request
* @param uhost: to the structure of usbh_core_type
* @param bot_trans: to the structure of msc_bot_trans_type
* @param lun: logical unit number
* @param inquiry: to the structure of msc_scsi_data_inquiry
* @retval status: usb_sts_type status
*/
usb_sts_type usbh_msc_bot_scsi_get_inquiry(void *uhost, msc_bot_trans_type *bot_trans,
uint8_t lun, msc_scsi_data_inquiry *inquiry)
{
usb_sts_type status = USB_WAIT;
switch(bot_trans->cmd_state)
{
case CMD_STATE_SEND:
usbh_bot_cbw(&bot_trans->cbw, MSC_INQUIRY_DATA_LEN, MSC_INQUIRY_CMD_LEN, MSC_CBW_FLAG_IN);
bot_trans->cbw.bCBWLUN = lun;
usbh_cmd_inquiry(bot_trans, bot_trans->cbw.CBWCB, lun);
bot_trans->cmd_state = CMD_STATE_WAIT;
bot_trans->bot_state = BOT_STATE_SEND_CBW;
break;
case CMD_STATE_WAIT:
status = usb_bot_request(uhost, bot_trans);
if(status == USB_OK)
{
bot_trans->cmd_state = CMD_STATE_SEND;
}
if(status == USB_FAIL)
{
bot_trans->cmd_state = CMD_STATE_SEND;
}
break;
default:
break;
}
return status;
}
/**
* @brief usb host msc bulk-only capacity request
* @param uhost: to the structure of usbh_core_type
* @param bot_trans: to the structure of msc_bot_trans_type
* @param lun: logical unit number
* @param capacity: to the structure of msc_scsi_data_capacity
* @retval status: usb_sts_type status
*/
usb_sts_type usbh_msc_bot_scsi_capacity(void *uhost, msc_bot_trans_type *bot_trans,
uint8_t lun, msc_scsi_data_capacity *capacity)
{
usb_sts_type status = USB_WAIT;
switch(bot_trans->cmd_state)
{
case CMD_STATE_SEND:
usbh_bot_cbw(&bot_trans->cbw, MSC_CAPACITY10_DATA_LEN, MSC_CAPACITY10_CMD_LEN, MSC_CBW_FLAG_IN);
bot_trans->cbw.bCBWLUN = lun;
usbh_cmd_capacity10(bot_trans, bot_trans->cbw.CBWCB, lun);
bot_trans->cmd_state = CMD_STATE_WAIT;
bot_trans->bot_state = BOT_STATE_SEND_CBW;
break;
case CMD_STATE_WAIT:
status = usb_bot_request(uhost, bot_trans);
if(status == USB_OK)
{
capacity->blk_nbr = bot_trans->buffer[3] | bot_trans->buffer[2] << 8 |
bot_trans->buffer[1] << 16 | bot_trans->buffer[0] << 24;
capacity->blk_size = bot_trans->buffer[7] | bot_trans->buffer[6] << 8 ;
bot_trans->cmd_state = CMD_STATE_SEND;
}
if(status == USB_FAIL)
{
bot_trans->cmd_state = CMD_STATE_SEND;
}
break;
default:
break;
}
return status;
}
/**
* @brief usb host msc bulk-only tet unit ready request
* @param uhost: to the structure of usbh_core_type
* @param bot_trans: to the structure of msc_bot_trans_type
* @param lun: logical unit number
* @retval status: usb_sts_type status
*/
usb_sts_type usbh_msc_bot_scsi_test_unit_ready(void *uhost, msc_bot_trans_type *bot_trans,
uint8_t lun)
{
usb_sts_type status = USB_WAIT;
switch(bot_trans->cmd_state)
{
case CMD_STATE_SEND:
usbh_bot_cbw(&bot_trans->cbw, MSC_TEST_UNIT_READY_DATA_LEN,
MSC_TEST_UNIT_READY_CMD_LEN, MSC_CBW_FLAG_OUT);
bot_trans->cbw.bCBWLUN = lun;
usbh_cmd_test_unit_ready(bot_trans, bot_trans->cbw.CBWCB, lun);
bot_trans->cmd_state = CMD_STATE_WAIT;
bot_trans->bot_state = BOT_STATE_SEND_CBW;
break;
case CMD_STATE_WAIT:
status = usb_bot_request(uhost, bot_trans);
if(status == USB_OK)
{
bot_trans->cmd_state = CMD_STATE_SEND;
}
if(status == USB_FAIL)
{
bot_trans->cmd_state = CMD_STATE_SEND;
}
break;
default:
break;
}
return status;
}
/**
* @brief usb host msc bulk-only request sense request
* @param uhost: to the structure of usbh_core_type
* @param bot_trans: to the structure of msc_bot_trans_type
* @param lun: logical unit number
* @retval status: usb_sts_type status
*/
usb_sts_type usbh_msc_bot_scsi_request_sense(void *uhost, msc_bot_trans_type *bot_trans,
uint8_t lun)
{
usb_sts_type status = USB_WAIT;
switch(bot_trans->cmd_state)
{
case CMD_STATE_SEND:
usbh_bot_cbw(&bot_trans->cbw, MSC_REQUEST_SENSE_DATA_LEN,
MSC_REQUEST_SENSE_CMD_LEN, MSC_CBW_FLAG_IN);
bot_trans->cbw.bCBWLUN = lun;
usbh_cmd_requset_sense(bot_trans, bot_trans->cbw.CBWCB, lun);
bot_trans->cmd_state = CMD_STATE_WAIT;
bot_trans->bot_state = BOT_STATE_SEND_CBW;
break;
case CMD_STATE_WAIT:
status = usb_bot_request(uhost, bot_trans);
if(status == USB_OK)
{
bot_trans->cmd_state = CMD_STATE_SEND;
}
if(status == USB_FAIL)
{
bot_trans->cmd_state = CMD_STATE_SEND;
}
break;
default:
break;
}
return status;
}
/**
* @brief usb host msc bulk-only write request
* @param uhost: to the structure of usbh_core_type
* @param bot_trans: to the structure of msc_bot_trans_type
* @param address: logical block address
* @param write_data: write data buffer
* @param write_len: write data length
* @param lun: logical unit number
* @retval status: usb_sts_type status
*/
usb_sts_type usbh_msc_bot_scsi_write(void *uhost, msc_bot_trans_type *bot_trans,
uint32_t address, uint8_t *write_data,
uint32_t write_len, uint8_t lun)
{
usb_sts_type status = USB_WAIT;
switch(bot_trans->cmd_state)
{
case CMD_STATE_SEND:
usbh_bot_cbw(&bot_trans->cbw, write_len * 512,
MSC_WRITE_CMD_LEN, MSC_CBW_FLAG_OUT);
bot_trans->cbw.bCBWLUN = lun;
usbh_cmd_write(bot_trans, bot_trans->cbw.CBWCB, lun, write_len, address, write_data);
bot_trans->cmd_state = CMD_STATE_WAIT;
bot_trans->bot_state = BOT_STATE_SEND_CBW;
break;
case CMD_STATE_WAIT:
status = usb_bot_request(uhost, bot_trans);
if(status == USB_OK)
{
bot_trans->cmd_state = CMD_STATE_SEND;
}
if(status == USB_FAIL)
{
bot_trans->cmd_state = CMD_STATE_SEND;
}
break;
default:
break;
}
return status;
}
/**
* @brief usb host msc bulk-only read request
* @param uhost: to the structure of usbh_core_type
* @param bot_trans: to the structure of msc_bot_trans_type
* @param address: logical block address
* @param read_data: read data buffer
* @param read_len: read data length
* @param lun: logical unit number
* @retval status: usb_sts_type status
*/
usb_sts_type usbh_msc_bot_scsi_read(void *uhost, msc_bot_trans_type *bot_trans,
uint32_t address, uint8_t *read_data,
uint32_t read_len, uint8_t lun)
{
usb_sts_type status = USB_WAIT;
switch(bot_trans->cmd_state)
{
case CMD_STATE_SEND:
usbh_bot_cbw(&bot_trans->cbw, read_len * 512,
MSC_READ_CMD_LEN, MSC_CBW_FLAG_IN);
bot_trans->cbw.bCBWLUN = lun;
usbh_cmd_read(bot_trans, bot_trans->cbw.CBWCB, lun, read_len, address, read_data);
bot_trans->cmd_state = CMD_STATE_WAIT;
bot_trans->bot_state = BOT_STATE_SEND_CBW;
break;
case CMD_STATE_WAIT:
status = usb_bot_request(uhost, bot_trans);
if(status == USB_OK)
{
bot_trans->cmd_state = CMD_STATE_SEND;
}
if(status == USB_FAIL)
{
bot_trans->cmd_state = CMD_STATE_SEND;
}
break;
default:
break;
}
return status;
}
/**
* @brief usb host msc init
* @param msc_struct: to the structure of usbh_msc_type
* @retval status: usb_sts_type status
*/
usb_sts_type msc_bot_scsi_init(usbh_msc_type *msc_struct)
{
msc_struct->state = USBH_MSC_INIT;
msc_struct->ctrl_state = USBH_MSC_STATE_IDLE;
msc_struct->error = MSC_OK;
msc_struct->cur_lun = 0;
msc_struct->max_lun = 0;
msc_struct->use_lun = 0;
msc_struct->bot_trans.msc_struct = &usbh_msc;
msc_struct->bot_trans.cmd_state = CMD_STATE_SEND;
msc_struct->bot_trans.bot_state = BOT_STATE_SEND_CBW;
return USB_OK;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
@@ -0,0 +1,237 @@
/**
**************************************************************************
* @file usbh_msc_bot_scsi.h
* @brief usb host msc bulk-only transfer and scsi header file
**************************************************************************
* Copyright notice & Disclaimer
*
* The software Board Support Package (BSP) that is made available to
* download from Artery official website is the copyrighted work of Artery.
* Artery authorizes customers to use, copy, and distribute the BSP
* software and its related documentation for the purpose of design and
* development in conjunction with Artery microcontrollers. Use of the
* software is governed by this copyright notice and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
* GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
* TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
* STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
* INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
*
**************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBH_MSC_BOT_SCSI_H
#define __USBH_MSC_BOT_SCSI_H
#ifdef __cplusplus
extern "C" {
#endif
#include "usbh_core.h"
#include "usb_conf.h"
/** @addtogroup AT32F435_437_middlewares_usbh_class
* @{
*/
/** @addtogroup USBH_msc_bot_scsi_class
* @{
*/
/** @defgroup USBH_msc_bot_scsi_class_definition
* @{
*/
#define MSC_CBW_SIGNATURE 0x43425355
#define MSC_CSW_SIGNATURE 0x53425355
#define MSC_CBW_TAG 0x50607080
#define MSC_CBW_FLAG_IN 0x80
#define MSC_CBW_FLAG_OUT 0x00
#define MSC_CBW_LEN 31
#define MSC_CSW_LEN 13
#define MSC_CBW_CB_LEN 16
#define MSC_TEST_UNIT_READY_CMD_LEN 12
#define MSC_TEST_UNIT_READY_DATA_LEN 0
#define MSC_INQUIRY_CMD_LEN 12
#define MSC_INQUIRY_DATA_LEN 36
#define MSC_CAPACITY10_CMD_LEN 12
#define MSC_CAPACITY10_DATA_LEN 8
#define MSC_REQUEST_SENSE_CMD_LEN 12
#define MSC_REQUEST_SENSE_DATA_LEN 18
#define MSC_WRITE_CMD_LEN 12
#define MSC_READ_CMD_LEN 10
#define MSC_OPCODE_INQUIRY 0x12
#define MSC_OPCODE_CAPACITY 0x25
#define MSC_OPCODE_TEST_UNIT_READY 0x00
#define MSC_OPCODE_REQUEST_SENSE 0x03
#define MSC_OPCODE_WRITE10 0x2A
#define MSC_OPCODE_READ10 0x28
typedef enum
{
BOT_STATE_IDLE,
BOT_STATE_SEND_CBW,
BOT_STATE_SEND_CBW_WAIT,
BOT_STATE_DATA_IN,
BOT_STATE_DATA_IN_WAIT,
BOT_STATE_DATA_OUT,
BOT_STATE_DATA_OUT_WAIT,
BOT_STATE_RECV_CSW,
BOT_STATE_RECV_CSW_WAIT,
BOT_STATE_ERROR_IN,
BOT_STATE_ERROR_OUT,
BOT_STATE_COMPLETE
}msc_bot_state_type;
typedef enum
{
CMD_STATE_SEND,
CMD_STATE_WAIT,
}msc_cmd_state_type;
/**
* @brief usb msc process state
*/
typedef enum
{
USBH_MSC_INIT,
USBH_MSC_INQUIRY,
USBH_MSC_TEST_UNIT_READY,
USBH_MSC_READ_CAPACITY10,
USBH_MSC_REQUEST_SENSE,
USBH_MSC_READ10,
USBH_MSC_WRITE,
USBH_MSC_BUSY,
USBH_MSC_ERROR,
USBH_MSC_IDLE
}msc_state_type;
typedef enum
{
MSC_OK,
MSC_NOT_READY,
MSC_ERROR
}msc_error_type;
/**
* @brief usb msc inquiry data type
*/
typedef struct
{
uint8_t pdev_type;
uint8_t rmb;
uint8_t version;
uint8_t data_format;
uint8_t length;
uint8_t reserved[3];
uint8_t vendor[8];
uint8_t product[16];
uint8_t revision[4];
}msc_scsi_data_inquiry;
/**
* @brief usb msc capacity data type
*/
typedef struct
{
uint32_t blk_nbr;
uint32_t blk_size;
}msc_scsi_data_capacity;
/**
* @brief usb msc bulk-only command block wrapper type
*/
typedef struct
{
uint32_t dCBWSignature;
uint32_t dCBWTag;
uint32_t dCBWDataTransferLength;
uint8_t bmCBWFlags;
uint8_t bCBWLUN;
uint8_t bCBWCBLength;
uint8_t CBWCB[MSC_CBW_CB_LEN];
}msc_bot_cbw_type;
/**
* @brief usb msc bulk-only command status wrapper type
*/
typedef struct
{
uint32_t dCBWSignature;
uint32_t dCBWTag;
uint32_t dCSWDataResidue;
uint8_t bCSWStatus;
}msc_bot_csw_type;
/**
* @brief usb msc bulk-only transfer control type
*/
typedef struct
{
uint8_t buffer[32];
msc_bot_cbw_type cbw;
msc_bot_csw_type csw;
msc_cmd_state_type cmd_state;
msc_bot_state_type bot_state;
uint8_t *data;
void *msc_struct;
}msc_bot_trans_type;
/**
* @brief usb msc bank type
*/
typedef struct
{
msc_scsi_data_inquiry inquiry;
msc_scsi_data_capacity capacity;
msc_state_type state;
msc_error_type ready;
usb_sts_type pre_state;
uint8_t change;
}usbh_msc_unit_type;
usb_sts_type usb_bot_request(void *uhost, msc_bot_trans_type *bot_trans);
usb_sts_type usbh_msc_bot_scsi_get_inquiry(void *uhost, msc_bot_trans_type *bot_trans,
uint8_t lun, msc_scsi_data_inquiry *inquiry);
usb_sts_type usbh_msc_bot_scsi_capacity(void *uhost, msc_bot_trans_type *bot_trans,
uint8_t lun, msc_scsi_data_capacity *capacity);
usb_sts_type usbh_msc_bot_scsi_test_unit_ready(void *uhost, msc_bot_trans_type *bot_trans,
uint8_t lun);
usb_sts_type usbh_msc_bot_scsi_request_sense(void *uhost, msc_bot_trans_type *bot_trans,
uint8_t lun);
usb_sts_type usbh_msc_bot_scsi_write(void *uhost, msc_bot_trans_type *bot_trans,
uint32_t address, uint8_t *write_data,
uint32_t write_len, uint8_t lun);
usb_sts_type usbh_msc_bot_scsi_read(void *uhost, msc_bot_trans_type *bot_trans,
uint32_t address, uint8_t *read_data,
uint32_t read_len, uint8_t lun);
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif
@@ -0,0 +1,521 @@
/**
**************************************************************************
* @file usbh_msc_class.c
* @brief usb host msc class type
**************************************************************************
* Copyright notice & Disclaimer
*
* The software Board Support Package (BSP) that is made available to
* download from Artery official website is the copyrighted work of Artery.
* Artery authorizes customers to use, copy, and distribute the BSP
* software and its related documentation for the purpose of design and
* development in conjunction with Artery microcontrollers. Use of the
* software is governed by this copyright notice and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
* GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
* TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
* STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
* INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
*
**************************************************************************
*/
#include "usbh_msc_class.h"
#include "usb_conf.h"
#include "usbh_core.h"
#include "usbh_ctrl.h"
/** @addtogroup AT32F435_437_middlewares_usbh_class
* @{
*/
/** @defgroup USBH_msc_class
* @brief usb host class msc demo
* @{
*/
/** @defgroup USBH_msc_class_private_functions
* @{
*/
static usb_sts_type uhost_init_handler(void *uhost);
static usb_sts_type uhost_reset_handler(void *uhost);
static usb_sts_type uhost_request_handler(void *uhost);
static usb_sts_type uhost_process_handler(void *uhost);
static usb_sts_type usbh_msc_get_max_lun(void *uhost, uint8_t *lun);
static usb_sts_type usbh_msc_clear_feature(void *uhost, uint8_t ept_num);
usbh_msc_type usbh_msc;
usbh_class_handler_type uhost_msc_class_handler =
{
uhost_init_handler,
uhost_reset_handler,
uhost_request_handler,
uhost_process_handler,
&usbh_msc
};
/**
* @brief usb host class init handler
* @param uhost: to the structure of usbh_core_type
* @retval status: usb_sts_type status
*/
static usb_sts_type uhost_init_handler(void *uhost)
{
usbh_core_type *puhost = (usbh_core_type *)uhost;
usb_sts_type status = USB_OK;
uint8_t if_x, eptidx = 0;
usbh_msc_type *pmsc = &usbh_msc;
puhost->class_handler->pdata = &usbh_msc;
if_x = usbh_find_interface(puhost, USB_CLASS_CODE_MSC, MSC_SUBCLASS_SCSI_TRANS, MSC_PROTOCOL_BBB);
if(if_x == 0xFF)
{
USBH_DEBUG("Unsupport Device!");
return USB_NOT_SUPPORT;
}
pmsc->protocol = puhost->dev.cfg_desc.interface[if_x].interface.bInterfaceProtocol;
for(eptidx = 0; eptidx < puhost->dev.cfg_desc.interface[if_x].interface.bNumEndpoints; eptidx ++)
{
if(puhost->dev.cfg_desc.interface[if_x].endpoint[eptidx].bEndpointAddress & 0x80)
{
pmsc->eptin = puhost->dev.cfg_desc.interface[if_x].endpoint[eptidx].bEndpointAddress;
pmsc->in_maxpacket = puhost->dev.cfg_desc.interface[if_x].endpoint[eptidx].wMaxPacketSize;
pmsc->in_poll = puhost->dev.cfg_desc.interface[if_x].endpoint[eptidx].bInterval;
pmsc->chin = usbh_alloc_channel(puhost, pmsc->eptin);
/* enable channel */
usbh_hc_open(puhost, pmsc->chin, pmsc->eptin,
puhost->dev.address, EPT_BULK_TYPE,
pmsc->in_maxpacket,
puhost->dev.speed);
}
else
{
pmsc->eptout = puhost->dev.cfg_desc.interface[if_x].endpoint[eptidx].bEndpointAddress;
pmsc->out_maxpacket = puhost->dev.cfg_desc.interface[if_x].endpoint[eptidx].wMaxPacketSize;
pmsc->out_poll = puhost->dev.cfg_desc.interface[if_x].endpoint[eptidx].bInterval;
pmsc->chout = usbh_alloc_channel(puhost, pmsc->eptout);
/* enable channel */
usbh_hc_open(puhost, pmsc->chout,pmsc->eptout,
puhost->dev.address, EPT_BULK_TYPE,
pmsc->out_maxpacket,
puhost->dev.speed);
}
}
msc_bot_scsi_init(pmsc);
usbh_set_toggle(puhost, pmsc->chout, 0);
usbh_set_toggle(puhost, pmsc->chin, 0);
return status;
}
/**
* @brief usb host class reset handler
* @param uhost: to the structure of usbh_core_type
* @retval status: usb_sts_type status
*/
static usb_sts_type uhost_reset_handler(void *uhost)
{
usbh_core_type *puhost = (usbh_core_type *)uhost;
usbh_msc_type *pmsc = (usbh_msc_type *)puhost->class_handler->pdata;
usb_sts_type status = USB_OK;
uint8_t i_index = 0;
if(puhost->class_handler->pdata == NULL)
{
return status;
}
for(i_index = 0; i_index < pmsc->max_lun ; i_index ++)
{
pmsc->l_unit_n[i_index].pre_state = USB_FAIL;
pmsc->l_unit_n[i_index].change = 0;
pmsc->l_unit_n[i_index].state = USBH_MSC_INIT;
pmsc->l_unit_n[i_index].ready = MSC_NOT_READY;
}
if(pmsc->chin != 0 )
{
usbh_free_channel(puhost, pmsc->chin);
usbh_ch_disable(puhost, pmsc->chin);
pmsc->chin = 0;
}
if(pmsc->chout != 0 )
{
usbh_free_channel(puhost, pmsc->chout);
usbh_ch_disable(puhost, pmsc->chout);
pmsc->chout = 0;
}
return status;
}
/**
* @brief usb host hid class request handler
* @param uhost: to the structure of usbh_core_type
* @retval status: usb_sts_type status
*/
static usb_sts_type uhost_request_handler(void *uhost)
{
usbh_core_type *puhost = (usbh_core_type *)uhost;
usbh_msc_type *pmsc = (usbh_msc_type *)puhost->class_handler->pdata;
usb_sts_type status = USB_WAIT;
uint8_t i_index = 0;
switch(pmsc->ctrl_state)
{
case USBH_MSC_STATE_IDLE:
pmsc->ctrl_state = USBH_MSC_STATE_GET_LUN;
break;
case USBH_MSC_STATE_GET_LUN:
if((status = usbh_msc_get_max_lun(uhost, (uint8_t *)&pmsc->max_lun)) == USB_OK)
{
pmsc->max_lun = (pmsc->max_lun & 0xFF) > USBH_SUPPORT_MAX_LUN ? USBH_SUPPORT_MAX_LUN:((pmsc->max_lun & 0xFF) + 1);
USBH_DEBUG("Support max lun %d", pmsc->max_lun);
for(i_index = 0; i_index < pmsc->max_lun ; i_index ++)
{
pmsc->l_unit_n[i_index].pre_state = USB_FAIL;
pmsc->l_unit_n[i_index].change = 0;
pmsc->l_unit_n[i_index].state = USBH_MSC_INIT;
}
}
break;
case USBH_MSC_STATE_ERROR:
if((usbh_msc_clear_feature(uhost, 0)) == USB_OK)
{
pmsc->ctrl_state = USBH_MSC_STATE_GET_LUN;
}
break;
default:
break;
}
return status;
}
/**
* @brief usb host class process handler
* @param uhost: to the structure of usbh_core_type
* @retval status: usb_sts_type status
*/
static usb_sts_type uhost_process_handler(void *uhost)
{
usbh_core_type *puhost = (usbh_core_type *)uhost;
usbh_msc_type *pmsc = (usbh_msc_type *)puhost->class_handler->pdata;
uint64_t msize = 0;
usb_sts_type status;
switch(pmsc->state)
{
case USBH_MSC_INIT:
if(pmsc->cur_lun < pmsc->max_lun)
{
switch(pmsc->l_unit_n[pmsc->cur_lun].state)
{
case USBH_MSC_INIT:
pmsc->l_unit_n[pmsc->cur_lun].ready = MSC_NOT_READY;
pmsc->l_unit_n[pmsc->cur_lun].state = USBH_MSC_INQUIRY;
break;
case USBH_MSC_INQUIRY:
status = usbh_msc_bot_scsi_get_inquiry(uhost, &pmsc->bot_trans, pmsc->cur_lun, &pmsc->l_unit_n[pmsc->cur_lun].inquiry);
if(status == USB_OK)
{
pmsc->l_unit_n[pmsc->cur_lun].state = USBH_MSC_TEST_UNIT_READY;
}
else if(status == USB_FAIL)
{
pmsc->l_unit_n[pmsc->cur_lun].state = USBH_MSC_REQUEST_SENSE;
}
break;
case USBH_MSC_TEST_UNIT_READY:
status = usbh_msc_bot_scsi_test_unit_ready(uhost, &pmsc->bot_trans, pmsc->cur_lun);
if(status == USB_OK)
{
pmsc->l_unit_n[pmsc->cur_lun].state = USBH_MSC_READ_CAPACITY10;
pmsc->l_unit_n[pmsc->cur_lun].ready = MSC_OK;
}
else if(status == USB_FAIL)
{
pmsc->l_unit_n[pmsc->cur_lun].state = USBH_MSC_REQUEST_SENSE;
pmsc->l_unit_n[pmsc->cur_lun].ready = MSC_NOT_READY;
}
break;
case USBH_MSC_READ_CAPACITY10:
status = usbh_msc_bot_scsi_capacity(uhost, &pmsc->bot_trans, pmsc->cur_lun, &pmsc->l_unit_n[pmsc->cur_lun].capacity);
if(status == USB_OK)
{
msize = (uint64_t)pmsc->l_unit_n[pmsc->cur_lun].capacity.blk_nbr * (uint64_t)pmsc->l_unit_n[pmsc->cur_lun].capacity.blk_size;
USBH_DEBUG("Device capacity: %llu Byte", msize);
USBH_DEBUG("Block num: %d ", pmsc->l_unit_n[pmsc->cur_lun].capacity.blk_nbr);
USBH_DEBUG("Block size: %d Byte", pmsc->l_unit_n[pmsc->cur_lun].capacity.blk_size);
pmsc->l_unit_n[pmsc->cur_lun].state = USBH_MSC_IDLE;
pmsc->cur_lun ++;
}
else if(status == USB_FAIL)
{
pmsc->l_unit_n[pmsc->cur_lun].state = USBH_MSC_REQUEST_SENSE;
}
break;
case USBH_MSC_REQUEST_SENSE:
status = usbh_msc_bot_scsi_request_sense(uhost, &pmsc->bot_trans, pmsc->cur_lun);
if(status == USB_OK)
{
pmsc->l_unit_n[pmsc->cur_lun].state = USBH_MSC_TEST_UNIT_READY;
}
else if(status == USB_FAIL)
{
pmsc->l_unit_n[pmsc->cur_lun].ready = MSC_NOT_READY;
pmsc->l_unit_n[pmsc->cur_lun].state = USBH_MSC_ERROR;
}
break;
case USBH_MSC_BUSY:
break;
case USBH_MSC_ERROR:
break;
default:
break;
}
}
else
{
pmsc->state = USBH_MSC_IDLE;
}
break;
case USBH_MSC_IDLE:
if(puhost->user_handler->user_application != NULL)
{
puhost->user_handler->user_application();
}
default:
break;
}
return USB_OK;
}
/**
* @brief usb host msc get max lun
* @param uhost: to the structure of usbh_core_type
* @param lun: max lun buffer
* @retval status: usb_sts_type status
*/
static usb_sts_type usbh_msc_get_max_lun(void *uhost, uint8_t *lun)
{
usbh_core_type *puhost = (usbh_core_type *)uhost;
usb_sts_type status = USB_WAIT;
if(puhost->ctrl.state == CONTROL_IDLE )
{
puhost->ctrl.setup.bmRequestType = USB_DIR_D2H | USB_REQ_RECIPIENT_INTERFACE | USB_REQ_TYPE_CLASS;
puhost->ctrl.setup.bRequest = MSC_REQ_GET_MAX_LUN;
puhost->ctrl.setup.wValue = 0;
puhost->ctrl.setup.wIndex = 0;
puhost->ctrl.setup.wLength = 1;
usbh_ctrl_request(puhost, lun, 1);
}
else
{
status = usbh_ctrl_result_check(puhost, CONTROL_IDLE, ENUM_IDLE);
if(status == USB_OK || status == USB_NOT_SUPPORT)
{
status = USB_OK;
}
}
return status;
}
/**
* @brief usb host msc clear feature
* @param uhost: to the structure of usbh_core_type
* @param ept_num: endpoint number
* @retval status: usb_sts_type status
*/
static usb_sts_type usbh_msc_clear_feature(void *uhost, uint8_t ept_num)
{
usbh_core_type *puhost = (usbh_core_type *)uhost;
usb_sts_type status = USB_WAIT;
if(puhost->ctrl.state == CONTROL_IDLE )
{
puhost->ctrl.setup.bmRequestType = USB_DIR_H2D | USB_REQ_RECIPIENT_ENDPOINT | USB_REQ_TYPE_STANDARD;
puhost->ctrl.setup.bRequest = USB_STD_REQ_CLEAR_FEATURE;
puhost->ctrl.setup.wValue = 0;
puhost->ctrl.setup.wIndex = ept_num;
puhost->ctrl.setup.wLength = 0;
usbh_ctrl_request(puhost, 0, 0);
}
else
{
status = usbh_ctrl_result_check(puhost, CONTROL_IDLE, ENUM_IDLE);
if(status == USB_OK || status == USB_NOT_SUPPORT)
{
status = USB_OK;
}
}
return status;
}
/**
* @brief usb host msc clear feature
* @param lun: logical unit number
* @retval msc_error_type status
*/
msc_error_type usbh_msc_is_ready(void *uhost, uint8_t lun)
{
usbh_core_type *puhost = (usbh_core_type *)uhost;
usbh_msc_type *pmsc = (usbh_msc_type *)puhost->class_handler->pdata;
return pmsc->l_unit_n[lun].ready;
}
/**
* @brief usb host msc read and write handle
* @param uhost: to the structure of usbh_core_type
* @param address: logical block address
* @param data_len: transfer data length
* @param buffer: transfer data buffer
* @param lun: logical unit number
* @retval status: usb_sts_type status
*/
usb_sts_type usbh_msc_rw_handle(void *uhost, uint32_t address, uint32_t len, uint8_t *buffer, uint8_t lun)
{
usbh_core_type *puhost = (usbh_core_type *)uhost;
usbh_msc_type *pmsc = (usbh_msc_type *)puhost->class_handler->pdata;
usb_sts_type status = USB_WAIT;
switch(pmsc->l_unit_n[lun].state)
{
case USBH_MSC_READ10:
status = usbh_msc_bot_scsi_read(uhost, &pmsc->bot_trans, address, buffer, len, lun);
if(status == USB_OK)
{
pmsc->l_unit_n[lun].state = USBH_MSC_IDLE;
}
else if(status == USB_FAIL)
{
pmsc->l_unit_n[lun].state = USBH_MSC_REQUEST_SENSE;
status = USB_WAIT;
}
break;
case USBH_MSC_WRITE:
status = usbh_msc_bot_scsi_write(uhost, &pmsc->bot_trans, address, buffer, len, lun);
if(status == USB_OK)
{
pmsc->l_unit_n[lun].state = USBH_MSC_IDLE;
}
else if(status == USB_FAIL)
{
pmsc->l_unit_n[lun].state = USBH_MSC_REQUEST_SENSE;
status = USB_WAIT;
}
break;
case USBH_MSC_REQUEST_SENSE:
status = usbh_msc_bot_scsi_request_sense(uhost, &pmsc->bot_trans, lun);
if(status == USB_OK)
{
pmsc->l_unit_n[lun].state = USBH_MSC_IDLE;
status = USB_FAIL;
}
else if(status == USB_FAIL)
{
USBH_DEBUG("device not support");
}
break;
default:
break;
}
return status;
}
/**
* @brief usb host msc read
* @param uhost: to the structure of usbh_core_type
* @param address: logical block address
* @param data_len: transfer data length
* @param buffer: transfer data buffer
* @param lun: logical unit number
* @retval status: usb_sts_type status
*/
usb_sts_type usbh_msc_read(void *uhost, uint32_t address, uint32_t len, uint8_t *buffer, uint8_t lun)
{
usbh_core_type *puhost = (usbh_core_type *)uhost;
usbh_msc_type *pmsc = (usbh_msc_type *)puhost->class_handler->pdata;
uint32_t timeout = 0;
if(puhost->conn_sts == 0 || puhost->global_state != USBH_CLASS
|| pmsc->l_unit_n[lun].state != USBH_MSC_IDLE)
{
return USB_FAIL;
}
pmsc->bot_trans.msc_struct = &usbh_msc;
pmsc->l_unit_n[lun].state = USBH_MSC_READ10;
pmsc->use_lun = lun;
timeout = puhost->timer;
while(usbh_msc_rw_handle(uhost, address, len, buffer, lun) == USB_WAIT)
{
if(puhost->conn_sts == 0 || (puhost->timer - timeout) > (len * 10000))
{
pmsc->l_unit_n[lun].state = USBH_MSC_IDLE;
return USB_FAIL;
}
}
return USB_OK;
}
/**
* @brief usb host msc write
* @param uhost: to the structure of usbh_core_type
* @param address: logical block address
* @param data_len: transfer data length
* @param buffer: transfer data buffer
* @param lun: logical unit number
* @retval status: usb_sts_type status
*/
usb_sts_type usbh_msc_write(void *uhost, uint32_t address, uint32_t len, uint8_t *buffer, uint8_t lun)
{
usbh_core_type *puhost = (usbh_core_type *)uhost;
usbh_msc_type *pmsc = (usbh_msc_type *)puhost->class_handler->pdata;
uint32_t timeout = 0;
if(puhost->conn_sts == 0 || puhost->global_state != USBH_CLASS
|| pmsc->l_unit_n[lun].state != USBH_MSC_IDLE)
{
return USB_FAIL;
}
pmsc->bot_trans.msc_struct = &usbh_msc;
pmsc->l_unit_n[lun].state = USBH_MSC_WRITE;
pmsc->use_lun = lun;
timeout = puhost->timer;
while(usbh_msc_rw_handle(uhost, address, len, buffer, lun) == USB_WAIT)
{
if(puhost->conn_sts == 0 || (puhost->timer - timeout) > (len * 10000))
{
pmsc->l_unit_n[lun].state = USBH_MSC_IDLE;
return USB_FAIL;
}
}
return USB_OK;
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
@@ -0,0 +1,141 @@
/**
**************************************************************************
* @file usbh_msc_class.h
* @brief usb host msc class header file
**************************************************************************
* Copyright notice & Disclaimer
*
* The software Board Support Package (BSP) that is made available to
* download from Artery official website is the copyrighted work of Artery.
* Artery authorizes customers to use, copy, and distribute the BSP
* software and its related documentation for the purpose of design and
* development in conjunction with Artery microcontrollers. Use of the
* software is governed by this copyright notice and the following disclaimer.
*
* THIS SOFTWARE IS PROVIDED ON "AS IS" BASIS WITHOUT WARRANTIES,
* GUARANTEES OR REPRESENTATIONS OF ANY KIND. ARTERY EXPRESSLY DISCLAIMS,
* TO THE FULLEST EXTENT PERMITTED BY LAW, ALL EXPRESS, IMPLIED OR
* STATUTORY OR OTHER WARRANTIES, GUARANTEES OR REPRESENTATIONS,
* INCLUDING BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
*
**************************************************************************
*/
/* Define to prevent recursive inclusion -------------------------------------*/
#ifndef __USBH_MSC_CLASS_H
#define __USBH_MSC_CLASS_H
#ifdef __cplusplus
extern "C" {
#endif
#include "usbh_core.h"
#include "usb_conf.h"
#include "usbh_msc_bot_scsi.h"
/** @addtogroup AT32F435_437_middlewares_usbh_class
* @{
*/
/** @addtogroup USBH_msc_class
* @{
*/
/** @defgroup USBH_msc_class_definition
* @{
*/
/**
* @brief usb msc subclass code
*/
#define MSC_SUBCLASS_SCSI_TRANS 0x06
/**
* @brief usb msc protocol code
*/
#define MSC_PROTOCOL_BBB 0x50
/**
* @brief usb msc request code
*/
#define MSC_REQ_GET_MAX_LUN 0xFE
#define MSC_REQ_BOMSR 0xFF
/**
* @brief usb hid request code
*/
#define USB_HID_GET_REPORT 0x01
#define USB_HID_GET_IDLE 0x02
#define USB_HID_GET_PROTOCOL 0x03
#define USB_HID_SET_REPORT 0x09
#define USB_HID_SET_IDLE 0x0A
#define USB_HID_SET_PROTOCOL 0x0B
#define USBH_SUPPORT_MAX_LUN 0x2
/**
* @brief usb msc request state
*/
typedef enum
{
USBH_MSC_STATE_IDLE,
USBH_MSC_STATE_GET_LUN,
USBH_MSC_STATE_ERROR,
USBH_MSC_STATE_COMPLETE,
}usbh_msc_ctrl_state_type;
/**
* @brief usb msc struct
*/
typedef struct
{
uint8_t chin;
uint8_t eptin;
uint16_t in_maxpacket;
uint8_t in_poll;
uint8_t chout;
uint8_t eptout;
uint16_t out_maxpacket;
uint8_t out_poll;
uint8_t protocol;
uint32_t max_lun;
uint32_t cur_lun;
uint32_t use_lun;
usbh_msc_ctrl_state_type ctrl_state;
msc_state_type state;
uint8_t error;
msc_bot_trans_type bot_trans;
usbh_msc_unit_type l_unit_n[USBH_SUPPORT_MAX_LUN];
uint16_t poll_timer;
uint8_t buffer[64];
}usbh_msc_type;
extern usbh_class_handler_type uhost_msc_class_handler;
extern usbh_msc_type usbh_msc;
msc_error_type usbh_msc_is_ready(void *uhost, uint8_t lun);
usb_sts_type usbh_msc_write(void *uhost, uint32_t address, uint32_t len, uint8_t *buffer, uint8_t lun);
usb_sts_type usbh_msc_read(void *uhost, uint32_t address, uint32_t len, uint8_t *buffer, uint8_t lun);
usb_sts_type usbh_msc_rw_handle(void *uhost, uint32_t address, uint32_t len, uint8_t *buffer, uint8_t lun);
usb_sts_type msc_bot_scsi_init(usbh_msc_type *msc_struct);
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
#ifdef __cplusplus
}
#endif
#endif