KT24-1110_65E-HA-651B/apps/common/usb/host/usb_ctrl_transfer.c
2024-11-10 18:44:17 +08:00

623 lines
19 KiB
C

/**
* @file usb_ctrl_transfer.c
* @brief usb 控制传输接口
* @author chenrixin@zh-jieli.com
* @version 1.00
* @date 2017-02-09
*/
#include "usb/host/usb_host.h"
#include "usb_ctrl_transfer.h"
#include "app_config.h"
#include "device_drive.h"
#include "gpio.h"
#include "usb/scsi.h"
#define LOG_TAG_CONST USB
#define LOG_TAG "[USB]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
#if USB_HOST_ENABLE
_WEAK_
void usb_dis_ep0_txdly(const usb_dev id)
{
}
static void ep0_h_isr(struct usb_host_device *host_dev, u32 ep)
{
usb_dev usb_id = host_device2id(host_dev);
usb_sem_post(host_dev);
}
/**
* @brief usb_ctlXfer
*
* @param host_dev
* @param urb
*
* @return
*/
static int usb_ctlXfer(struct usb_host_device *host_dev, struct ctlXfer *urb)
{
u32 ret = DEV_ERR_NONE;
u8 reg = 0;
u32 data_len;
usb_dev usb_id = host_device2id(host_dev);
u8 devnum = host_dev->private_data.devnum;
u32 max_packet_size = host_dev->private_data.ep0_max_packet_size;
usb_write_faddr(usb_id, devnum);
switch (urb->stage) {
case USB_PID_SETUP :
usb_write_ep0(usb_id, (u8 *)&urb->setup, 8);
reg = CSR0H_SetupPkt | CSR0H_TxPktRdy;
break;
case USB_PID_IN :
if (urb->setup.wLength) {
reg = CSR0H_ReqPkt;
} else {
reg = CSR0H_StatusPkt | CSR0H_ReqPkt;
}
break;
case USB_PID_OUT:
if (urb->setup.wLength) {
data_len = min(urb->setup.wLength, max_packet_size);
reg = CSR0H_TxPktRdy;
usb_write_ep0(usb_id, urb->buffer, data_len);
urb->setup.wLength -= data_len;
urb->buffer += data_len;
} else {
reg = CSR0H_StatusPkt | CSR0H_TxPktRdy;
}
break;
default :
break;
}
#if USB_HOST_ASYNC
//config ep0 callback fun
usb_h_set_ep_isr(host_dev, 0, ep0_h_isr, host_dev);
usb_set_intr_txe(usb_id, 0);
#endif
usb_write_csr0(usb_id, reg);
u32 st = 0;
u32 ot = get_jiffies() + 500;
while (1) {
if (usb_host_timeout(ot)) {
log_error("time out %x\n", reg);
ret = -DEV_ERR_TIMEOUT;
goto __exit;
}
if (usb_h_dev_status(usb_id)) {
st ++;
} else {
st = 0;
}
if (((usb_read_devctl(usb_id) & BIT(2)) == 0) || (st > 1000)) {
log_error("usb%d_offline\n", usb_id);
ret = -DEV_ERR_OFFLINE;
goto __exit;
}
#if USB_HOST_ASYNC
ret = usb_sem_pend(host_dev, 250); //wait isr
if (ret) {
log_error("usb%d_offline\n", usb_id);
ret = -DEV_ERR_OFFLINE;
goto __exit;
}
#endif
reg = usb_read_csr0(usb_id);
if (reg & CSR0H_RxStall) {
log_error(" rxStall CSR0:0x%x", reg);
ret = -DEV_ERR_CONTROL_STALL;
goto __exit;
}
if (reg & CSR0H_Error) {
log_error(" Error CSR0:0x%x", reg);
usb_write_csr0(usb_id, 0);
ret = -DEV_ERR_CONTROL;
goto __exit;
}
if (USB_PID_IN == urb->stage) {
if (reg & CSR0H_RxPktRdy) {
data_len = usb_read_count0(usb_id);
data_len = min(data_len, urb->setup.wLength);
usb_read_ep0(usb_id, urb->buffer, data_len);;
urb->buffer += data_len;
urb->setup.wLength -= data_len;
if (data_len < max_packet_size) {
urb->setup.wLength = 0;
}
if (urb->setup.wLength) {
usb_write_csr0(usb_id, CSR0H_ReqPkt);
} else {
usb_write_csr0(usb_id, 0);
break;
}
}
} else {
if (!(reg & CSR0H_TxPktRdy)) {
break;
}
}
}
__exit:
usb_clr_intr_txe(usb_id, 0);
usb_dis_ep0_txdly(usb_id);
return ret;
}
/**
* @brief usb_control_transfers
*
* @param struct host_dev
* @param urb
*
* @return
*/
static int usb_control_transfers(struct usb_host_device *host_dev, struct ctlXfer *urb)
{
usb_dev usb_id = host_device2id(host_dev);
int res;
/*SETUP*/
urb->stage = USB_PID_SETUP; //SETUP transaction
res = usb_ctlXfer(host_dev, urb);
if (res) {
return res;
}
/*IN or OUT*/
urb->stage = USB_PID_IN;
while (urb->setup.wLength) {
if (urb->setup.bRequestType & USB_DIR_IN) { //Request Direction
urb->stage = USB_PID_IN; //IN transaction
res = usb_ctlXfer(host_dev, urb);
if (res) {
return res;
}
urb->stage = USB_PID_OUT;
} else {
urb->stage = USB_PID_OUT; //OUT transaction
res = usb_ctlXfer(host_dev, urb);
if (res) {
return res;
}
urb->stage = USB_PID_IN;
}
}
res = usb_ctlXfer(host_dev, urb);
if (res) {
return res;
}
return DEV_ERR_NONE;
}
/**
* @brief usb_control_msg
*
* @param host_dev
* @param request
* @param requesttype
* @param value
* @param index
* @param data
* @param size
*
* @return
*/
static int usb_control_msg(struct usb_host_device *host_dev,
u8 request, u8 requesttype,
u16 value, u16 index,
void *data, u16 size)
{
struct ctlXfer urb;
urb.setup.bRequestType = requesttype;
urb.setup.bRequest = request;
urb.setup.wValue = cpu_to_le16(value);
urb.setup.wIndex = cpu_to_le16(index);
urb.setup.wLength = cpu_to_le16(size);
urb.buffer = data;
return usb_control_transfers(host_dev, &urb);
}
/**
* @brief usb_clear_feature
*
* @param host_dev
* @param ep
*
* @return
*/
int usb_clear_feature(struct usb_host_device *host_dev, u32 ep)
{
return usb_control_msg(host_dev, USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, ep, NULL, 0);
}
int set_address(struct usb_host_device *host_dev, u8 devnum)
{
return usb_control_msg(host_dev, USB_REQ_SET_ADDRESS, 0, devnum, 0, NULL, 0);
}
int usb_get_device_descriptor(struct usb_host_device *host_dev, struct usb_device_descriptor *desc)
{
return usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_DEVICE << 8),
0,
desc,
USB_DT_DEVICE_SIZE
);
}
int usb_get_string_descriptor(struct usb_host_device *host_dev, struct usb_device_descriptor *desc)
{
int ret = DEV_ERR_NONE;
#if 0
struct usb_private_data *private_data = host_dev->private_data ;
/**********get string language*********/
u8 buf[16];
memset(buf, 0x0, sizeof(buf));
ret = usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_STRING << 8),
0,
desc,
sizeof(buf)
);
if (ret) {
return ret;
}
memcpy(&private_data->language, buf + 2, sizeof(private_data->language));
/**********get manufacturer string**********/
memset(private_data->manufacturer, 0x0, sizeof(private_data->manufacturer));
if (desc->iManufacturer) {
ret = usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_STRING << 8) | desc->iManufacturer,
0,
private_data->manufacturer,
sizeof(private_data->manufacturer)
);
if (ret) {
return ret;
}
}
/**********get product string**********/
memset(private_data->product, 0x0, sizeof(private_data->product));
if (desc->iProduct) {
ret = usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_STRING << 8) | desc->iProduct,
0,
private_data->product,
sizeof(private_data->product)
);
if (ret) {
return ret;
}
}
#endif
return ret;
}
int set_configuration(struct usb_host_device *host_dev)
{
return usb_control_msg(host_dev, USB_REQ_SET_CONFIGURATION, 0, 1, 0, NULL, 0);
}
int set_configuration_add_value(struct usb_host_device *host_dev, u16 value)
{
return usb_control_msg(host_dev, USB_REQ_SET_CONFIGURATION, 0, value, 0, NULL, 0);
}
int get_config_descriptor(struct usb_host_device *host_dev, void *cfg_desc, u32 len)
{
return usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_CONFIG << 8),
0,
cfg_desc,
len);
}
int get_config_descriptor_add_value_l(struct usb_host_device *host_dev, void *cfg_desc, u32 len, u8 value_l)
{
return usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_CONFIG << 8) | value_l,
0,
cfg_desc,
len);
}
int get_msd_max_lun(struct usb_host_device *host_dev, void *lun)
{
return usb_control_msg(host_dev,
USB_MSD_MAX_LUN,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0,
0,
lun,
1);
}
int set_msd_reset(struct usb_host_device *host_dev)
{
return usb_control_msg(host_dev,
0xff,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0,
0,
NULL,
0);
}
int hid_set_idle(struct usb_host_device *host_dev, u32 id)
{
return usb_control_msg(host_dev, 0x0a, 0x21, 0, id << 8, NULL, 0);
}
int hid_get_report(struct usb_host_device *host_dev, u8 *report, u8 report_id, u16 report_len)
{
return usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN | USB_RECIP_INTERFACE,
0x2200,
report_id,
report,
report_len);
}
int hid_set_output_report(struct usb_host_device *host_dev, u8 *report, u8 report_id, u8 report_len)
{
return usb_control_msg(host_dev,
0x09,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0x0201,
report_id,
report,
report_len);
}
int usb_set_remote_wakeup(struct usb_host_device *host_dev)
{
return usb_control_msg(host_dev, USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0);
}
int get_device_status(struct usb_host_device *host_dev)
{
u16 status;
return usb_control_msg(host_dev, USB_REQ_GET_STATUS, USB_DIR_IN, 0, 0, (u8 *)&status, 2);
}
int usb_get_device_qualifier(struct usb_host_device *host_dev, u8 *buffer)
{
return usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_DEVICE_QUALIFIER << 8),
0,
buffer,
0x0a);
}
#define AOA_CMD51 0x33
#define AOA_CMD52 0x34
#define AOA_CMD53 0x35
int usb_get_aoa_version(struct usb_host_device *host_dev, u16 *version)
{
return usb_control_msg(host_dev,
AOA_CMD51,
USB_DIR_IN | USB_TYPE_VENDOR,
0,
0,
version,
2);
}
int usb_set_credentials(struct usb_host_device *host_dev, const char *string, int index)
{
return usb_control_msg(host_dev,
AOA_CMD52,
USB_DIR_OUT | USB_TYPE_VENDOR,
0,
index,
(u8 *)string,
strlen(string));
}
int usb_switch2aoa(struct usb_host_device *host_dev)
{
return usb_control_msg(host_dev,
AOA_CMD53,
USB_DIR_OUT | USB_TYPE_VENDOR,
0,
0,
NULL,
0);
}
int usb_switch2slave(struct usb_host_device *host_dev)
{
return usb_control_msg(host_dev,
0x51,
USB_DIR_OUT | USB_TYPE_VENDOR,
0,
0,
NULL,
0);
}
/* Control request for registering a HID device.
* Upon registering, a unique ID is sent by the accessory in the
* value parameter. This ID will be used for future commands for
* the device
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_REGISTER_HID_DEVICE
* value: Accessory assigned ID for the HID device
* index: total length of the HID report descriptor
* data none
*/
#define ACCESSORY_REGISTER_HID 54
int usb_aoa_register_hid(struct usb_host_device *host_dev, u16 value, u16 index)
{
return usb_control_msg(host_dev,
ACCESSORY_REGISTER_HID,
USB_DIR_OUT | USB_TYPE_VENDOR,
value,
index,
NULL,
0);
}
/* Control request for unregistering a HID device.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_REGISTER_HID
* value: Accessory assigned ID for the HID device
* index: 0
* data none
*/
#define ACCESSORY_UNREGISTER_HID 55
int usb_aoa_unregister_hid(struct usb_host_device *host_dev, u16 value)
{
return usb_control_msg(host_dev,
ACCESSORY_UNREGISTER_HID,
USB_DIR_OUT | USB_TYPE_VENDOR,
value,
0,
NULL,
0);
}
/* Control request for sending the HID report descriptor.
* If the HID descriptor is longer than the endpoint zero max packet size,
* the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
* commands. The data for the descriptor must be sent sequentially
* if multiple packets are needed.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SET_HID_REPORT_DESC
* value: Accessory assigned ID for the HID device
* index: offset of data in descriptor
* (needed when HID descriptor is too big for one packet)
* data the HID report descriptor
*/
#define ACCESSORY_SET_HID_REPORT_DESC 56
int usb_aoa_set_hid_report_desc(struct usb_host_device *host_dev, u16 value, u16 offset, const char *pbuf, u32 len)
{
return usb_control_msg(host_dev,
ACCESSORY_SET_HID_REPORT_DESC,
USB_DIR_OUT | USB_TYPE_VENDOR,
value,
offset,
(u8 *)pbuf,
len);
}
/* Control request for sending HID events.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SEND_HID_EVENT
* value: Accessory assigned ID for the HID device
* index: 0
* data the HID report for the event
*/
#define ACCESSORY_SEND_HID_EVENT 57
int usb_aoa_send_hid_event(struct usb_host_device *host_dev, u16 value, const u8 *pbuf, u32 len)
{
return usb_control_msg(host_dev,
ACCESSORY_SEND_HID_EVENT,
USB_DIR_OUT | USB_TYPE_VENDOR,
value,
0,
(u8 *)pbuf,
len);
}
int get_ms_extended_compat_id(struct usb_host_device *host_dev, u8 *buffer)
{
return usb_control_msg(host_dev,
0x01,
USB_DIR_IN | USB_RECIP_DEVICE | USB_TYPE_VENDOR,
0x0000,
4,
buffer,
0x28);
}
int usb_set_interface(struct usb_host_device *host_dev, u8 interface, u8 alternateSetting)
{
log_info("%s Set Interface:%d AlternateSetting:%d", __func__, interface, alternateSetting);
return usb_control_msg(host_dev,
USB_REQ_SET_INTERFACE,
USB_RECIP_INTERFACE,
alternateSetting,
interface,
NULL,
0);
}
int usb_audio_sampling_frequency_control(struct usb_host_device *host_dev, u32 ep, u32 sampe_rate)
{
log_info("%s ep:%d sampe_rate:%d", __func__, ep, sampe_rate);
return usb_control_msg(host_dev,
1,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
0x0100,
ep,
&sampe_rate,
3);
}
int usb_audio_volume_control(struct usb_host_device *host_dev, u8 feature_id, u8 channel_num, u16 volume)
{
log_info("%s featureID:%d vol:%x", __func__, feature_id, volume);
return usb_control_msg(host_dev,
1,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(0x02 << 8) | channel_num,
feature_id << 8,
&volume,
2);
}
int usb_audio_mute_control(struct usb_host_device *host_dev, u8 feature_id, u8 mute)
{
log_info("%s featureID:%d mute:%d", __func__, feature_id, mute);
return usb_control_msg(host_dev,
1,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0x0100,
feature_id << 8,
&mute,
1);
}
#endif