first
This commit is contained in:
490
apps/common/device/usb/device/cdc.c
Normal file
490
apps/common/device/usb/device/cdc.c
Normal file
@ -0,0 +1,490 @@
|
||||
#include "usb/device/usb_stack.h"
|
||||
#include "usb/usb_config.h"
|
||||
#include "usb/device/cdc.h"
|
||||
#include "app_config.h"
|
||||
#include "os/os_api.h"
|
||||
#include "cdc_defs.h" //need redefine __u8, __u16, __u32
|
||||
|
||||
#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 TCFG_USB_SLAVE_CDC_ENABLE
|
||||
|
||||
|
||||
struct usb_cdc_gadget {
|
||||
u8 *cdc_buffer;
|
||||
u8 *bulk_ep_out_buffer;
|
||||
u8 *bulk_ep_in_buffer;
|
||||
void *priv;
|
||||
int (*output)(void *priv, u8 *obuf, u32 olen);
|
||||
void (*wakeup_handler)(struct usb_device_t *usb_device);
|
||||
OS_MUTEX mutex_data;
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
OS_MUTEX mutex_intr;
|
||||
u8 *intr_ep_in_buffer;
|
||||
#endif
|
||||
u8 bmTransceiver;
|
||||
u8 subtype_data[8];
|
||||
};
|
||||
|
||||
static struct usb_cdc_gadget *cdc_hdl;
|
||||
|
||||
#if USB_MALLOC_ENABLE
|
||||
|
||||
#else
|
||||
static u8 _cdc_buffer[MAXP_SIZE_CDC_BULKOUT] SEC(.cdc_var) __attribute__((aligned(4)));
|
||||
static struct usb_cdc_gadget _cdc_hdl SEC(.cdc_var);
|
||||
#endif
|
||||
|
||||
static const u8 cdc_virtual_comport_desc[] = {
|
||||
//IAD Descriptor
|
||||
0x08, //bLength
|
||||
0x0b, //bDescriptorType
|
||||
0x00, //bFirstInterface
|
||||
0x02, //bInterfaceCount
|
||||
0x02, //bFunctionClass, Comunication and CDC control
|
||||
0x02, //bFunctionSubClass
|
||||
0x01, //bFunctionProtocol
|
||||
0x00, //iFunction
|
||||
//Interface 0, Alt 0
|
||||
0x09, //Length
|
||||
0x04, //DescriptorType:Interface
|
||||
0x00, //InterfaceNum
|
||||
0x00, //AlternateSetting
|
||||
0x01, //NumEndpoint
|
||||
0x02, //InterfaceClass, Communation and CDC control
|
||||
0x02, //InterfaceSubClass, Abstract Control Model
|
||||
0x01, //InterfaceProtocol, AT commands defined by ITU-T V.250 etc
|
||||
0x00, //Interface String
|
||||
//CDC Interface Descriptor
|
||||
0x05, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x00, //bDescriptorSubType, Header Functional Desc
|
||||
0x10, 0x01, //bcdCDC, version 1.10
|
||||
//CDC Interface Descriptor
|
||||
0x05, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x01, //bDescriptorSubType, Call Management Functional Descriptor
|
||||
0x03, //bmCapabilities, D7..D2 reversed
|
||||
// D7..D2 reversed
|
||||
// D1 sends/receives call management information only over a Data Class interface
|
||||
// D0 handle call management itself
|
||||
0x01, //bDataInterface
|
||||
//CDC Interface Descriptor
|
||||
0x04, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x02, //bDescriptorSubType, Abstract Control Management Functional Descriptor
|
||||
0x02, //bmCapabilities, D7..D2 reversed
|
||||
// D7..D4 reversed
|
||||
// D3 supports the notification Network_Connection
|
||||
// D2 not supports the request Send_Break
|
||||
// D1 supports the request combination of Set_Line_Coding, Set_Control_Line_State, Get_Line_Coding, and the notification Serial_State
|
||||
// D0 supports the request combination of Set_Comm_Feature, Clear_Comm_Feature, and Get_Comm_Feature
|
||||
//CDC Interface Descriptor
|
||||
0x05, //bLength
|
||||
0x24, //bDescriptorType
|
||||
0x06, //bDescriptorSubType, Union Functional Descriptor
|
||||
0x00, //bControlInterface
|
||||
0x01, //bSubordinateInterface[0]
|
||||
//Endpoint In
|
||||
0x07, //bLength
|
||||
0x05, //bDescritorType
|
||||
0x82, //bEndpointAddr
|
||||
0x03, //bmAttributes, interrupt
|
||||
0x08, 0x00, //wMaxPacketSize
|
||||
0x01, //bInterval, 1ms
|
||||
//Interface 1, Alt 0
|
||||
0x09, //Length
|
||||
0x04, //DescriptorType:Interface
|
||||
0x01, //InterfaceNum
|
||||
0x00, //AlternateSetting
|
||||
0x02, //NumEndpoint
|
||||
0x0a, //InterfaceClass, CDC Data
|
||||
0x00, //InterfaceSubClass
|
||||
0x00, //InterfaceProtocol
|
||||
0x00, //Interface String
|
||||
//Endpoint Out
|
||||
0x07, //bLength
|
||||
0x05, //bDescriptor
|
||||
0x02, //bEndpointAddr
|
||||
0x02, //bmAttributes, bulk
|
||||
0x40, 0x00, //wMaxPacketSize
|
||||
0x00, //bInterval
|
||||
//Endpoint In
|
||||
0x07, //bLength
|
||||
0x05, //bDescritorType
|
||||
0x83, //bEndpointAddr
|
||||
0x02, //bmAttributes, bulk
|
||||
0x40, 0x00, //wMaxPacketSize
|
||||
0x00, //bInterval
|
||||
};
|
||||
|
||||
static void cdc_endpoint_init(struct usb_device_t *usb_device, u32 itf);
|
||||
static u32 cdc_setup_rx(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req);
|
||||
|
||||
static void usb_cdc_line_coding_init(struct usb_cdc_line_coding *lc)
|
||||
{
|
||||
lc->dwDTERate = 460800;
|
||||
lc->bCharFormat = USB_CDC_1_STOP_BITS;
|
||||
lc->bParityType = USB_CDC_NO_PARITY;
|
||||
lc->bDataBits = 8;
|
||||
}
|
||||
|
||||
static void dump_line_coding(struct usb_cdc_line_coding *lc)
|
||||
{
|
||||
log_debug("dtw rate : %d", lc->dwDTERate);
|
||||
log_debug("stop bits : %d", lc->bCharFormat);
|
||||
log_debug("verify bits : %d", lc->bParityType);
|
||||
log_debug("data bits : %d", lc->bDataBits);
|
||||
}
|
||||
|
||||
static u32 cdc_setup(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
int recip_type;
|
||||
u32 len;
|
||||
|
||||
recip_type = ctrl_req->bRequestType & USB_TYPE_MASK;
|
||||
|
||||
switch (recip_type) {
|
||||
case USB_TYPE_CLASS:
|
||||
switch (ctrl_req->bRequest) {
|
||||
case USB_CDC_REQ_SET_LINE_CODING:
|
||||
log_debug("set line coding");
|
||||
usb_set_setup_recv(usb_device, cdc_setup_rx);
|
||||
break;
|
||||
case USB_CDC_REQ_GET_LINE_CODING:
|
||||
log_debug("get line codling");
|
||||
len = ctrl_req->wLength < sizeof(struct usb_cdc_line_coding) ?
|
||||
ctrl_req->wLength : sizeof(struct usb_cdc_line_coding);
|
||||
if (cdc_hdl == NULL) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
break;
|
||||
}
|
||||
usb_set_data_payload(usb_device, ctrl_req, cdc_hdl->subtype_data, len);
|
||||
dump_line_coding((struct usb_cdc_line_coding *)cdc_hdl->subtype_data);
|
||||
break;
|
||||
case USB_CDC_REQ_SET_CONTROL_LINE_STATE:
|
||||
log_debug("set control line state - %d", ctrl_req->wValue);
|
||||
if (cdc_hdl) {
|
||||
/* if (ctrl_req->wValue & BIT(0)) { //DTR */
|
||||
cdc_hdl->bmTransceiver |= BIT(0);
|
||||
/* } else { */
|
||||
/* usb_slave->cdc->bmTransceiver &= ~BIT(0); */
|
||||
/* } */
|
||||
/* if (ctrl_req->wValue & BIT(1)) { //RTS */
|
||||
cdc_hdl->bmTransceiver |= BIT(1);
|
||||
/* } else { */
|
||||
/* usb_slave->cdc->bmTransceiver &= ~BIT(1); */
|
||||
/* } */
|
||||
cdc_hdl->bmTransceiver |= BIT(4); //cfg done
|
||||
}
|
||||
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
|
||||
//cdc_endpoint_init(usb_device, (ctrl_req->wIndex & USB_RECIP_MASK));
|
||||
break;
|
||||
default:
|
||||
log_error("unsupported class req");
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
log_error("unsupported req type");
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static u32 cdc_setup_rx(struct usb_device_t *usb_device, struct usb_ctrlrequest *ctrl_req)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
int recip_type;
|
||||
struct usb_cdc_line_coding *lc = 0;
|
||||
u32 len;
|
||||
u8 read_ep[8];
|
||||
|
||||
len = ctrl_req->wLength;
|
||||
usb_read_ep0(usb_id, read_ep, len);
|
||||
recip_type = ctrl_req->bRequestType & USB_TYPE_MASK;
|
||||
switch (recip_type) {
|
||||
case USB_TYPE_CLASS:
|
||||
switch (ctrl_req->bRequest) {
|
||||
case USB_CDC_REQ_SET_LINE_CODING:
|
||||
log_debug("USB_CDC_REQ_SET_LINE_CODING");
|
||||
if (cdc_hdl == NULL) {
|
||||
break;
|
||||
}
|
||||
if (len > sizeof(struct usb_cdc_line_coding)) {
|
||||
len = sizeof(struct usb_cdc_line_coding);
|
||||
}
|
||||
memcpy(cdc_hdl->subtype_data, read_ep, len);
|
||||
lc = (struct usb_cdc_line_coding *)cdc_hdl->subtype_data;
|
||||
dump_line_coding(lc);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
return USB_EP0_STAGE_SETUP;
|
||||
}
|
||||
|
||||
static void cdc_reset(struct usb_device_t *usb_device, u32 itf)
|
||||
{
|
||||
log_error("%s()", __func__);
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
#if USB_ROOT2
|
||||
usb_disable_ep(usb_id, CDC_DATA_EP_IN);
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
usb_disable_ep(usb_id, CDC_INTR_EP_IN);
|
||||
#endif
|
||||
#else
|
||||
cdc_endpoint_init(usb_device, itf);
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 cdc_desc_config(const usb_dev usb_id, u8 *ptr, u32 *itf)
|
||||
{
|
||||
u8 *tptr;
|
||||
|
||||
tptr = ptr;
|
||||
memcpy(tptr, cdc_virtual_comport_desc, sizeof(cdc_virtual_comport_desc));
|
||||
//iad interface number
|
||||
tptr[2] = *itf;
|
||||
//control interface number
|
||||
tptr[8 + 2] = *itf;
|
||||
tptr[8 + 9 + 5 + 4] = *itf + 1;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 3] = *itf;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 4] = *itf + 1;
|
||||
//interrupt in ep
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 2] = USB_DIR_IN | CDC_INTR_EP_IN;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 4] = MAXP_SIZE_CDC_INTRIN & 0xff;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 5] = (MAXP_SIZE_CDC_INTRIN >> 8) & 0xff;
|
||||
#if defined(FUSB_MODE) && FUSB_MODE == 0
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 6] = 4; //high-speed mode, 125x2^(4-1)=1ms
|
||||
#endif
|
||||
//data interface number
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 2] = *itf + 1;
|
||||
//bulk out ep
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 2] = CDC_DATA_EP_OUT;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 4] = MAXP_SIZE_CDC_BULKOUT & 0xff;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 5] = (MAXP_SIZE_CDC_BULKOUT >> 8) & 0xff;
|
||||
//bulk in ep
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 2] = USB_DIR_IN | CDC_DATA_EP_IN;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 4] = MAXP_SIZE_CDC_BULKIN & 0xff;
|
||||
tptr[8 + 9 + 5 + 5 + 4 + 5 + 7 + 9 + 7 + 5] = (MAXP_SIZE_CDC_BULKIN >> 8) & 0xff;
|
||||
tptr += sizeof(cdc_virtual_comport_desc);
|
||||
|
||||
if (usb_set_interface_hander(usb_id, *itf, cdc_setup) != *itf) {
|
||||
ASSERT(0, "cdc set interface_hander fail");
|
||||
}
|
||||
if (usb_set_reset_hander(usb_id, *itf, cdc_reset) != *itf) {
|
||||
|
||||
}
|
||||
*itf += 2;
|
||||
return (u32)(tptr - ptr);
|
||||
}
|
||||
|
||||
void cdc_set_wakeup_handler(void (*handle)(struct usb_device_t *usb_device))
|
||||
{
|
||||
if (cdc_hdl) {
|
||||
cdc_hdl->wakeup_handler = handle;
|
||||
}
|
||||
}
|
||||
|
||||
static void cdc_wakeup_handler(struct usb_device_t *usb_device, u32 ep)
|
||||
{
|
||||
if (cdc_hdl && cdc_hdl->wakeup_handler) {
|
||||
cdc_hdl->wakeup_handler(usb_device);
|
||||
}
|
||||
}
|
||||
|
||||
void cdc_set_output_handle(void *priv, int (*output_handler)(void *priv, u8 *buf, u32 len))
|
||||
{
|
||||
if (cdc_hdl) {
|
||||
cdc_hdl->output = output_handler;
|
||||
cdc_hdl->priv = priv;
|
||||
}
|
||||
}
|
||||
|
||||
static void cdc_intrrx(struct usb_device_t *usb_device, u32 ep)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
if (cdc_hdl == NULL) {
|
||||
return;
|
||||
}
|
||||
u8 *cdc_rx_buf = cdc_hdl->cdc_buffer;
|
||||
//由于bulk传输使用双缓冲,无法用usb_get_ep_buffer()知道是哪一个buffer,需要外部buffer接收数据
|
||||
u32 len = usb_g_bulk_read(usb_id, CDC_DATA_EP_OUT, cdc_rx_buf, MAXP_SIZE_CDC_BULKOUT, 0);
|
||||
if (cdc_hdl->output) {
|
||||
cdc_hdl->output(cdc_hdl->priv, cdc_rx_buf, len);
|
||||
}
|
||||
}
|
||||
|
||||
static void cdc_endpoint_init(struct usb_device_t *usb_device, u32 itf)
|
||||
{
|
||||
ASSERT(cdc_hdl, "cdc not register");
|
||||
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
|
||||
usb_g_ep_config(usb_id, CDC_DATA_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_BULK,
|
||||
0, cdc_hdl->bulk_ep_in_buffer, MAXP_SIZE_CDC_BULKIN);
|
||||
|
||||
usb_g_ep_config(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK,
|
||||
1, cdc_hdl->bulk_ep_out_buffer, MAXP_SIZE_CDC_BULKOUT);
|
||||
/* usb_g_set_intr_hander(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, cdc_intrrx); */
|
||||
usb_g_set_intr_hander(usb_id, CDC_DATA_EP_OUT | USB_DIR_OUT, cdc_wakeup_handler);
|
||||
usb_enable_ep(usb_id, CDC_DATA_EP_IN);
|
||||
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
usb_g_ep_config(usb_id, CDC_INTR_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_INT,
|
||||
0, cdc_hdl->intr_ep_in_buffer, MAXP_SIZE_CDC_INTRIN);
|
||||
usb_enable_ep(usb_id, CDC_INTR_EP_IN);
|
||||
#endif
|
||||
}
|
||||
|
||||
u32 cdc_read_data(const usb_dev usb_id, u8 *buf, u32 len)
|
||||
{
|
||||
u32 rxlen;
|
||||
if (cdc_hdl == NULL) {
|
||||
return 0;
|
||||
}
|
||||
u8 *cdc_rx_buf = cdc_hdl->cdc_buffer;
|
||||
os_mutex_pend(&cdc_hdl->mutex_data, 0);
|
||||
//由于bulk传输使用双缓冲,无法用usb_get_ep_buffer()知道是哪一个buffer,需要外部buffer接收数据
|
||||
rxlen = usb_g_bulk_read(usb_id, CDC_DATA_EP_OUT, cdc_rx_buf, MAXP_SIZE_CDC_BULKOUT, 0);
|
||||
rxlen = rxlen > len ? len : rxlen;
|
||||
if (rxlen > 0) {
|
||||
memcpy(buf, cdc_rx_buf, rxlen);
|
||||
}
|
||||
os_mutex_post(&cdc_hdl->mutex_data);
|
||||
return rxlen;
|
||||
}
|
||||
|
||||
u32 cdc_write_data(const usb_dev usb_id, u8 *buf, u32 len)
|
||||
{
|
||||
u32 txlen, offset;
|
||||
if (cdc_hdl == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if ((cdc_hdl->bmTransceiver & (BIT(1) | BIT(4))) != (BIT(1) | BIT(4))) {
|
||||
return 0;
|
||||
}
|
||||
offset = 0;
|
||||
os_mutex_pend(&cdc_hdl->mutex_data, 0);
|
||||
while (offset < len) {
|
||||
txlen = len - offset > MAXP_SIZE_CDC_BULKIN ?
|
||||
MAXP_SIZE_CDC_BULKIN : len - offset;
|
||||
txlen = usb_g_bulk_write(usb_id, CDC_DATA_EP_IN, buf + offset, txlen);
|
||||
if (txlen == 0) {
|
||||
break;
|
||||
}
|
||||
if ((cdc_hdl->bmTransceiver & (BIT(1) | BIT(4))) != (BIT(1) | BIT(4))) {
|
||||
break;
|
||||
}
|
||||
offset += txlen;
|
||||
}
|
||||
//当最后一包的包长等于maxpktsize,需要发一个0长包表示结束
|
||||
if ((offset % MAXP_SIZE_CDC_BULKIN) == 0) {
|
||||
usb_g_bulk_write(usb_id, CDC_DATA_EP_IN, NULL, 0);
|
||||
}
|
||||
os_mutex_post(&cdc_hdl->mutex_data);
|
||||
return offset;
|
||||
}
|
||||
|
||||
u32 cdc_write_inir(const usb_dev usb_id, u8 *buf, u32 len)
|
||||
{
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
u32 txlen, offset;
|
||||
if (cdc_hdl == NULL) {
|
||||
return 0;
|
||||
}
|
||||
if ((cdc_hdl->bmTransceiver & BIT(4)) == 0) {
|
||||
return 0;
|
||||
}
|
||||
offset = 0;
|
||||
os_mutex_pend(&cdc_hdl->mutex_intr, 0);
|
||||
while (offset < len) {
|
||||
txlen = len - offset > MAXP_SIZE_CDC_INTRIN ?
|
||||
MAXP_SIZE_CDC_INTRIN : len - offset;
|
||||
txlen = usb_g_intr_write(usb_id, CDC_INTR_EP_IN, buf + offset, txlen);
|
||||
if (txlen == 0) {
|
||||
break;
|
||||
}
|
||||
if ((cdc_hdl->bmTransceiver & BIT(4)) == 0) {
|
||||
break;
|
||||
}
|
||||
offset += txlen;
|
||||
}
|
||||
os_mutex_post(&cdc_hdl->mutex_intr);
|
||||
return offset;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
void cdc_register(const usb_dev usb_id)
|
||||
{
|
||||
struct usb_cdc_line_coding *lc;
|
||||
/* log_info("%s() %d", __func__, __LINE__); */
|
||||
if (!cdc_hdl) {
|
||||
#if USB_MALLOC_ENABLE
|
||||
cdc_hdl = zalloc(sizeof(struct usb_cdc_gadget));
|
||||
if (!cdc_hdl) {
|
||||
log_error("cdc_register err 1");
|
||||
return;
|
||||
}
|
||||
cdc_hdl->cdc_buffer = malloc(MAXP_SIZE_CDC_BULKOUT);
|
||||
if (!cdc_hdl->cdc_buffer) {
|
||||
log_error("cdc_register err 2");
|
||||
goto __exit_err;
|
||||
}
|
||||
#else
|
||||
memset(&_cdc_hdl, 0, sizeof(struct usb_cdc_gadget));
|
||||
cdc_hdl = &_cdc_hdl;
|
||||
cdc_hdl->cdc_buffer = _cdc_buffer;
|
||||
#endif
|
||||
lc = (struct usb_cdc_line_coding *)cdc_hdl->subtype_data;
|
||||
usb_cdc_line_coding_init(lc);
|
||||
os_mutex_create(&cdc_hdl->mutex_data);
|
||||
|
||||
cdc_hdl->bulk_ep_in_buffer = usb_alloc_ep_dmabuffer(usb_id, CDC_DATA_EP_IN | USB_DIR_IN, MAXP_SIZE_CDC_BULKIN + MAXP_SIZE_CDC_BULKOUT);
|
||||
cdc_hdl->bulk_ep_out_buffer = cdc_hdl->bulk_ep_in_buffer + MAXP_SIZE_CDC_BULKIN;
|
||||
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
os_mutex_create(&cdc_hdl->mutex_intr);
|
||||
cdc_hdl->intr_ep_in_buffer = usb_alloc_ep_dmabuffer(usb_id, CDC_INTR_EP_IN | USB_DIR_IN, MAXP_SIZE_CDC_INTRIN);
|
||||
#endif
|
||||
|
||||
}
|
||||
return;
|
||||
__exit_err:
|
||||
#if USB_MALLOC_ENABLE
|
||||
if (cdc_hdl->cdc_buffer) {
|
||||
free(cdc_hdl->cdc_buffer);
|
||||
}
|
||||
if (cdc_hdl) {
|
||||
free(cdc_hdl);
|
||||
}
|
||||
#endif
|
||||
cdc_hdl = NULL;
|
||||
}
|
||||
|
||||
void cdc_release(const usb_dev usb_id)
|
||||
{
|
||||
/* log_info("%s() %d", __func__, __LINE__); */
|
||||
if (cdc_hdl) {
|
||||
#if USB_MALLOC_ENABLE
|
||||
free(cdc_hdl->cdc_buffer);
|
||||
free(cdc_hdl);
|
||||
#endif
|
||||
cdc_hdl = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
23
apps/common/device/usb/device/cdc.h
Normal file
23
apps/common/device/usb/device/cdc.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef __CDC_H__
|
||||
#define __CDC_H__
|
||||
|
||||
#include "usb/device/usb_stack.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
u32 cdc_desc_config(const usb_dev usb_id, u8 *ptr, u32 *itf);
|
||||
void cdc_set_wakeup_handler(void (*handle)(struct usb_device_t *usb_device));
|
||||
void cdc_set_output_handle(void *priv, int (*output_handler)(void *priv, u8 *buf, u32 len));
|
||||
u32 cdc_read_data(const usb_dev usb_id, u8 *buf, u32 len);
|
||||
u32 cdc_write_data(const usb_dev usb_id, u8 *buf, u32 len);
|
||||
u32 cdc_write_inir(const usb_dev usb_id, u8 *buf, u32 len);
|
||||
void cdc_register(const usb_dev usb_id);
|
||||
void cdc_release(const usb_dev usb_id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
457
apps/common/device/usb/device/cdc_defs.h
Normal file
457
apps/common/device/usb/device/cdc_defs.h
Normal file
@ -0,0 +1,457 @@
|
||||
|
||||
/*
|
||||
* USB Communications Device Class (CDC) definitions
|
||||
*
|
||||
* CDC says how to talk to lots of different types of network adapters,
|
||||
* notably ethernet adapters and various modems. It's used mostly with
|
||||
* firmware based USB peripherals.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_USB_CDC_H
|
||||
#define __LINUX_USB_CDC_H
|
||||
|
||||
#include "typedef.h" /* __u8 etc */
|
||||
|
||||
#ifdef __le16
|
||||
#undef __le16
|
||||
#endif
|
||||
typedef unsigned short __le16;
|
||||
#ifdef __le32
|
||||
#undef __le32
|
||||
#endif
|
||||
typedef unsigned int __le32;
|
||||
#ifdef __u8
|
||||
#undef __u8
|
||||
#endif
|
||||
typedef unsigned char __u8;
|
||||
#ifdef __u16
|
||||
#undef __u16
|
||||
#endif
|
||||
typedef unsigned short __u16;
|
||||
#ifdef __u32
|
||||
#undef __u32
|
||||
#endif
|
||||
typedef unsigned int __u32;
|
||||
|
||||
#define USB_CDC_SUBCLASS_ACM 0x02
|
||||
#define USB_CDC_SUBCLASS_ETHERNET 0x06
|
||||
#define USB_CDC_SUBCLASS_WHCM 0x08
|
||||
#define USB_CDC_SUBCLASS_DMM 0x09
|
||||
#define USB_CDC_SUBCLASS_MDLM 0x0a
|
||||
#define USB_CDC_SUBCLASS_OBEX 0x0b
|
||||
#define USB_CDC_SUBCLASS_EEM 0x0c
|
||||
#define USB_CDC_SUBCLASS_NCM 0x0d
|
||||
#define USB_CDC_SUBCLASS_MBIM 0x0e
|
||||
|
||||
#define USB_CDC_PROTO_NONE 0
|
||||
|
||||
#define USB_CDC_ACM_PROTO_AT_V25TER 1
|
||||
#define USB_CDC_ACM_PROTO_AT_PCCA101 2
|
||||
#define USB_CDC_ACM_PROTO_AT_PCCA101_WAKE 3
|
||||
#define USB_CDC_ACM_PROTO_AT_GSM 4
|
||||
#define USB_CDC_ACM_PROTO_AT_3G 5
|
||||
#define USB_CDC_ACM_PROTO_AT_CDMA 6
|
||||
#define USB_CDC_ACM_PROTO_VENDOR 0xff
|
||||
|
||||
#define USB_CDC_PROTO_EEM 7
|
||||
|
||||
#define USB_CDC_NCM_PROTO_NTB 1
|
||||
#define USB_CDC_MBIM_PROTO_NTB 2
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Class-Specific descriptors ... there are a couple dozen of them
|
||||
*/
|
||||
|
||||
#define USB_CDC_HEADER_TYPE 0x00 /* header_desc */
|
||||
#define USB_CDC_CALL_MANAGEMENT_TYPE 0x01 /* call_mgmt_descriptor */
|
||||
#define USB_CDC_ACM_TYPE 0x02 /* acm_descriptor */
|
||||
#define USB_CDC_UNION_TYPE 0x06 /* union_desc */
|
||||
#define USB_CDC_COUNTRY_TYPE 0x07
|
||||
#define USB_CDC_NETWORK_TERMINAL_TYPE 0x0a /* network_terminal_desc */
|
||||
#define USB_CDC_ETHERNET_TYPE 0x0f /* ether_desc */
|
||||
#define USB_CDC_WHCM_TYPE 0x11
|
||||
#define USB_CDC_MDLM_TYPE 0x12 /* mdlm_desc */
|
||||
#define USB_CDC_MDLM_DETAIL_TYPE 0x13 /* mdlm_detail_desc */
|
||||
#define USB_CDC_DMM_TYPE 0x14
|
||||
#define USB_CDC_OBEX_TYPE 0x15
|
||||
#define USB_CDC_NCM_TYPE 0x1a
|
||||
#define USB_CDC_MBIM_TYPE 0x1b
|
||||
|
||||
/* "Header Functional Descriptor" from CDC spec 5.2.3.1 */
|
||||
struct usb_cdc_header_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__le16 bcdCDC;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Call Management Descriptor" from CDC spec 5.2.3.2 */
|
||||
struct usb_cdc_call_mgmt_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 bmCapabilities;
|
||||
#define USB_CDC_CALL_MGMT_CAP_CALL_MGMT 0x01
|
||||
#define USB_CDC_CALL_MGMT_CAP_DATA_INTF 0x02
|
||||
|
||||
__u8 bDataInterface;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Abstract Control Management Descriptor" from CDC spec 5.2.3.3 */
|
||||
struct usb_cdc_acm_descriptor {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 bmCapabilities;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* capabilities from 5.2.3.3 */
|
||||
|
||||
#define USB_CDC_COMM_FEATURE 0x01
|
||||
#define USB_CDC_CAP_LINE 0x02
|
||||
#define USB_CDC_CAP_BRK 0x04
|
||||
#define USB_CDC_CAP_NOTIFY 0x08
|
||||
|
||||
/* "Union Functional Descriptor" from CDC spec 5.2.3.8 */
|
||||
struct usb_cdc_union_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 bMasterInterface0;
|
||||
__u8 bSlaveInterface0;
|
||||
/* ... and there could be other slave interfaces */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Country Selection Functional Descriptor" from CDC spec 5.2.3.9 */
|
||||
struct usb_cdc_country_functional_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 iCountryCodeRelDate;
|
||||
__le16 wCountyCode0;
|
||||
/* ... and there can be a lot of country codes */
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Network Channel Terminal Functional Descriptor" from CDC spec 5.2.3.11 */
|
||||
struct usb_cdc_network_terminal_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 bEntityId;
|
||||
__u8 iName;
|
||||
__u8 bChannelIndex;
|
||||
__u8 bPhysicalInterface;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Ethernet Networking Functional Descriptor" from CDC spec 5.2.3.16 */
|
||||
struct usb_cdc_ether_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__u8 iMACAddress;
|
||||
__le32 bmEthernetStatistics;
|
||||
__le16 wMaxSegmentSize;
|
||||
__le16 wNumberMCFilters;
|
||||
__u8 bNumberPowerFilters;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "Telephone Control Model Functional Descriptor" from CDC WMC spec 6.3..3 */
|
||||
struct usb_cdc_dmm_desc {
|
||||
__u8 bFunctionLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubtype;
|
||||
__u16 bcdVersion;
|
||||
__le16 wMaxCommand;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "MDLM Functional Descriptor" from CDC WMC spec 6.7.2.3 */
|
||||
struct usb_cdc_mdlm_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__le16 bcdVersion;
|
||||
__u8 bGUID[16];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "MDLM Detail Functional Descriptor" from CDC WMC spec 6.7.2.4 */
|
||||
struct usb_cdc_mdlm_detail_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
/* type is associated with mdlm_desc.bGUID */
|
||||
__u8 bGuidDescriptorType;
|
||||
__u8 bDetailData[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "OBEX Control Model Functional Descriptor" */
|
||||
struct usb_cdc_obex_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__le16 bcdVersion;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "NCM Control Model Functional Descriptor" */
|
||||
struct usb_cdc_ncm_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__le16 bcdNcmVersion;
|
||||
__u8 bmNetworkCapabilities;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* "MBIM Control Model Functional Descriptor" */
|
||||
struct usb_cdc_mbim_desc {
|
||||
__u8 bLength;
|
||||
__u8 bDescriptorType;
|
||||
__u8 bDescriptorSubType;
|
||||
|
||||
__le16 bcdMBIMVersion;
|
||||
__le16 wMaxControlMessage;
|
||||
__u8 bNumberFilters;
|
||||
__u8 bMaxFilterSize;
|
||||
__le16 wMaxSegmentSize;
|
||||
__u8 bmNetworkCapabilities;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Class-Specific Control Requests (6.2)
|
||||
*
|
||||
* section 3.6.2.1 table 4 has the ACM profile, for modems.
|
||||
* section 3.8.2 table 10 has the ethernet profile.
|
||||
*
|
||||
* Microsoft's RNDIS stack for Ethernet is a vendor-specific CDC ACM variant,
|
||||
* heavily dependent on the encapsulated (proprietary) command mechanism.
|
||||
*/
|
||||
|
||||
#define USB_CDC_SEND_ENCAPSULATED_COMMAND 0x00
|
||||
#define USB_CDC_GET_ENCAPSULATED_RESPONSE 0x01
|
||||
#define USB_CDC_REQ_SET_LINE_CODING 0x20
|
||||
#define USB_CDC_REQ_GET_LINE_CODING 0x21
|
||||
#define USB_CDC_REQ_SET_CONTROL_LINE_STATE 0x22
|
||||
#define USB_CDC_REQ_SEND_BREAK 0x23
|
||||
#define USB_CDC_SET_ETHERNET_MULTICAST_FILTERS 0x40
|
||||
#define USB_CDC_SET_ETHERNET_PM_PATTERN_FILTER 0x41
|
||||
#define USB_CDC_GET_ETHERNET_PM_PATTERN_FILTER 0x42
|
||||
#define USB_CDC_SET_ETHERNET_PACKET_FILTER 0x43
|
||||
#define USB_CDC_GET_ETHERNET_STATISTIC 0x44
|
||||
#define USB_CDC_GET_NTB_PARAMETERS 0x80
|
||||
#define USB_CDC_GET_NET_ADDRESS 0x81
|
||||
#define USB_CDC_SET_NET_ADDRESS 0x82
|
||||
#define USB_CDC_GET_NTB_FORMAT 0x83
|
||||
#define USB_CDC_SET_NTB_FORMAT 0x84
|
||||
#define USB_CDC_GET_NTB_INPUT_SIZE 0x85
|
||||
#define USB_CDC_SET_NTB_INPUT_SIZE 0x86
|
||||
#define USB_CDC_GET_MAX_DATAGRAM_SIZE 0x87
|
||||
#define USB_CDC_SET_MAX_DATAGRAM_SIZE 0x88
|
||||
#define USB_CDC_GET_CRC_MODE 0x89
|
||||
#define USB_CDC_SET_CRC_MODE 0x8a
|
||||
|
||||
/* Line Coding Structure from CDC spec 6.2.13 */
|
||||
struct usb_cdc_line_coding {
|
||||
__le32 dwDTERate;
|
||||
__u8 bCharFormat;
|
||||
#define USB_CDC_1_STOP_BITS 0
|
||||
#define USB_CDC_1_5_STOP_BITS 1
|
||||
#define USB_CDC_2_STOP_BITS 2
|
||||
|
||||
__u8 bParityType;
|
||||
#define USB_CDC_NO_PARITY 0
|
||||
#define USB_CDC_ODD_PARITY 1
|
||||
#define USB_CDC_EVEN_PARITY 2
|
||||
#define USB_CDC_MARK_PARITY 3
|
||||
#define USB_CDC_SPACE_PARITY 4
|
||||
|
||||
__u8 bDataBits;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* table 62; bits in multicast filter */
|
||||
#define USB_CDC_PACKET_TYPE_PROMISCUOUS (1 << 0)
|
||||
#define USB_CDC_PACKET_TYPE_ALL_MULTICAST (1 << 1) /* no filter */
|
||||
#define USB_CDC_PACKET_TYPE_DIRECTED (1 << 2)
|
||||
#define USB_CDC_PACKET_TYPE_BROADCAST (1 << 3)
|
||||
#define USB_CDC_PACKET_TYPE_MULTICAST (1 << 4) /* filtered */
|
||||
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Class-Specific Notifications (6.3) sent by interrupt transfers
|
||||
*
|
||||
* section 3.8.2 table 11 of the CDC spec lists Ethernet notifications
|
||||
* section 3.6.2.1 table 5 specifies ACM notifications, accepted by RNDIS
|
||||
* RNDIS also defines its own bit-incompatible notifications
|
||||
*/
|
||||
|
||||
#define USB_CDC_NOTIFY_NETWORK_CONNECTION 0x00
|
||||
#define USB_CDC_NOTIFY_RESPONSE_AVAILABLE 0x01
|
||||
#define USB_CDC_NOTIFY_SERIAL_STATE 0x20
|
||||
#define USB_CDC_NOTIFY_SPEED_CHANGE 0x2a
|
||||
|
||||
struct usb_cdc_notification {
|
||||
__u8 bmRequestType;
|
||||
__u8 bNotificationType;
|
||||
__le16 wValue;
|
||||
__le16 wIndex;
|
||||
__le16 wLength;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_cdc_speed_change {
|
||||
__le32 DLBitRRate; /* contains the downlink bit rate (IN pipe) */
|
||||
__le32 ULBitRate; /* contains the uplink bit rate (OUT pipe) */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*-------------------------------------------------------------------------*/
|
||||
|
||||
/*
|
||||
* Class Specific structures and constants
|
||||
*
|
||||
* CDC NCM NTB parameters structure, CDC NCM subclass 6.2.1
|
||||
*
|
||||
*/
|
||||
|
||||
struct usb_cdc_ncm_ntb_parameters {
|
||||
__le16 wLength;
|
||||
__le16 bmNtbFormatsSupported;
|
||||
__le32 dwNtbInMaxSize;
|
||||
__le16 wNdpInDivisor;
|
||||
__le16 wNdpInPayloadRemainder;
|
||||
__le16 wNdpInAlignment;
|
||||
__le16 wPadding1;
|
||||
__le32 dwNtbOutMaxSize;
|
||||
__le16 wNdpOutDivisor;
|
||||
__le16 wNdpOutPayloadRemainder;
|
||||
__le16 wNdpOutAlignment;
|
||||
__le16 wNtbOutMaxDatagrams;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* CDC NCM transfer headers, CDC NCM subclass 3.2
|
||||
*/
|
||||
|
||||
#define USB_CDC_NCM_NTH16_SIGN 0x484D434E /* NCMH */
|
||||
#define USB_CDC_NCM_NTH32_SIGN 0x686D636E /* ncmh */
|
||||
|
||||
struct usb_cdc_ncm_nth16 {
|
||||
__le32 dwSignature;
|
||||
__le16 wHeaderLength;
|
||||
__le16 wSequence;
|
||||
__le16 wBlockLength;
|
||||
__le16 wNdpIndex;
|
||||
} __attribute__((packed));
|
||||
|
||||
struct usb_cdc_ncm_nth32 {
|
||||
__le32 dwSignature;
|
||||
__le16 wHeaderLength;
|
||||
__le16 wSequence;
|
||||
__le32 dwBlockLength;
|
||||
__le32 dwNdpIndex;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* CDC NCM datagram pointers, CDC NCM subclass 3.3
|
||||
*/
|
||||
|
||||
#define USB_CDC_NCM_NDP16_CRC_SIGN 0x314D434E /* NCM1 */
|
||||
#define USB_CDC_NCM_NDP16_NOCRC_SIGN 0x304D434E /* NCM0 */
|
||||
#define USB_CDC_NCM_NDP32_CRC_SIGN 0x316D636E /* ncm1 */
|
||||
#define USB_CDC_NCM_NDP32_NOCRC_SIGN 0x306D636E /* ncm0 */
|
||||
|
||||
#define USB_CDC_MBIM_NDP16_IPS_SIGN 0x00535049 /* IPS<sessionID> : IPS0 for now */
|
||||
#define USB_CDC_MBIM_NDP32_IPS_SIGN 0x00737069 /* ips<sessionID> : ips0 for now */
|
||||
#define USB_CDC_MBIM_NDP16_DSS_SIGN 0x00535344 /* DSS<sessionID> */
|
||||
#define USB_CDC_MBIM_NDP32_DSS_SIGN 0x00737364 /* dss<sessionID> */
|
||||
|
||||
/* 16-bit NCM Datagram Pointer Entry */
|
||||
struct usb_cdc_ncm_dpe16 {
|
||||
__le16 wDatagramIndex;
|
||||
__le16 wDatagramLength;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* 16-bit NCM Datagram Pointer Table */
|
||||
struct usb_cdc_ncm_ndp16 {
|
||||
__le32 dwSignature;
|
||||
__le16 wLength;
|
||||
__le16 wNextNdpIndex;
|
||||
struct usb_cdc_ncm_dpe16 dpe16[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* 32-bit NCM Datagram Pointer Entry */
|
||||
struct usb_cdc_ncm_dpe32 {
|
||||
__le32 dwDatagramIndex;
|
||||
__le32 dwDatagramLength;
|
||||
} __attribute__((__packed__));
|
||||
|
||||
/* 32-bit NCM Datagram Pointer Table */
|
||||
struct usb_cdc_ncm_ndp32 {
|
||||
__le32 dwSignature;
|
||||
__le16 wLength;
|
||||
__le16 wReserved6;
|
||||
__le32 dwNextNdpIndex;
|
||||
__le32 dwReserved12;
|
||||
struct usb_cdc_ncm_dpe32 dpe32[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/* CDC NCM subclass 3.2.1 and 3.2.2 */
|
||||
#define USB_CDC_NCM_NDP16_INDEX_MIN 0x000C
|
||||
#define USB_CDC_NCM_NDP32_INDEX_MIN 0x0010
|
||||
|
||||
/* CDC NCM subclass 3.3.3 Datagram Formatting */
|
||||
#define USB_CDC_NCM_DATAGRAM_FORMAT_CRC 0x30
|
||||
#define USB_CDC_NCM_DATAGRAM_FORMAT_NOCRC 0X31
|
||||
|
||||
/* CDC NCM subclass 4.2 NCM Communications Interface Protocol Code */
|
||||
#define USB_CDC_NCM_PROTO_CODE_NO_ENCAP_COMMANDS 0x00
|
||||
#define USB_CDC_NCM_PROTO_CODE_EXTERN_PROTO 0xFE
|
||||
|
||||
/* CDC NCM subclass 5.2.1 NCM Functional Descriptor, bmNetworkCapabilities */
|
||||
#define USB_CDC_NCM_NCAP_ETH_FILTER (1 << 0)
|
||||
#define USB_CDC_NCM_NCAP_NET_ADDRESS (1 << 1)
|
||||
#define USB_CDC_NCM_NCAP_ENCAP_COMMAND (1 << 2)
|
||||
#define USB_CDC_NCM_NCAP_MAX_DATAGRAM_SIZE (1 << 3)
|
||||
#define USB_CDC_NCM_NCAP_CRC_MODE (1 << 4)
|
||||
#define USB_CDC_NCM_NCAP_NTB_INPUT_SIZE (1 << 5)
|
||||
|
||||
/* CDC NCM subclass Table 6-3: NTB Parameter Structure */
|
||||
#define USB_CDC_NCM_NTB16_SUPPORTED (1 << 0)
|
||||
#define USB_CDC_NCM_NTB32_SUPPORTED (1 << 1)
|
||||
|
||||
/* CDC NCM subclass Table 6-3: NTB Parameter Structure */
|
||||
#define USB_CDC_NCM_NDP_ALIGN_MIN_SIZE 0x04
|
||||
#define USB_CDC_NCM_NTB_MAX_LENGTH 0x1C
|
||||
|
||||
/* CDC NCM subclass 6.2.5 SetNtbFormat */
|
||||
#define USB_CDC_NCM_NTB16_FORMAT 0x00
|
||||
#define USB_CDC_NCM_NTB32_FORMAT 0x01
|
||||
|
||||
/* CDC NCM subclass 6.2.7 SetNtbInputSize */
|
||||
#define USB_CDC_NCM_NTB_MIN_IN_SIZE 2048
|
||||
#define USB_CDC_NCM_NTB_MIN_OUT_SIZE 2048
|
||||
|
||||
/* NTB Input Size Structure */
|
||||
struct usb_cdc_ncm_ndp_input_size {
|
||||
__le32 dwNtbInMaxSize;
|
||||
__le16 wNtbInMaxDatagrams;
|
||||
__le16 wReserved;
|
||||
} __attribute__((packed));
|
||||
|
||||
/* CDC NCM subclass 6.2.11 SetCrcMode */
|
||||
#define USB_CDC_NCM_CRC_NOT_APPENDED 0x00
|
||||
#define USB_CDC_NCM_CRC_APPENDED 0x01
|
||||
|
||||
#endif /* __LINUX_USB_CDC_H */
|
||||
202
apps/common/device/usb/device/descriptor.c
Normal file
202
apps/common/device/usb/device/descriptor.c
Normal file
@ -0,0 +1,202 @@
|
||||
/**
|
||||
* @file descriptor.c
|
||||
* @brief overwrite usb device descriptor
|
||||
* @version 1.00
|
||||
* @date 2019-05-06
|
||||
*/
|
||||
|
||||
#include "usb/device/usb_stack.h"
|
||||
#include "usb/device/descriptor.h"
|
||||
#include "usb/device/uac_audio.h"
|
||||
|
||||
#include "app_config.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 TCFG_USB_SLAVE_ENABLE
|
||||
|
||||
static const u8 sDeviceDescriptor[] = { //<Device Descriptor
|
||||
USB_DT_DEVICE_SIZE, // bLength: Size of descriptor
|
||||
USB_DT_DEVICE, // bDescriptorType: Device
|
||||
#if defined(FUSB_MODE) && FUSB_MODE
|
||||
0x10, 0x01, // bcdUSB: USB 1.1
|
||||
#elif defined(FUSB_MODE) && (FUSB_MODE ==0 )
|
||||
0x00, 0x02, // bcdUSB: USB 2.0
|
||||
#else
|
||||
#error "USB_SPEED_MODE not defined"
|
||||
#endif
|
||||
0x00, // bDeviceClass: none
|
||||
0x00, // bDeviceSubClass: none
|
||||
0x00, // bDeviceProtocol: none
|
||||
EP0_SETUP_LEN,//EP0_LEN, // bMaxPacketSize0: 8/64 bytes
|
||||
'J', 'L', // idVendor: 0x4a4c - JL
|
||||
'U', 'A', // idProduct: chip id
|
||||
0x00, 0x01, // bcdDevice: version 1.0
|
||||
0x01, // iManufacturer: Index to string descriptor that contains the string <Your Name> in Unicode
|
||||
0x02, // iProduct: Index to string descriptor that contains the string <Your Product Name> in Unicode
|
||||
0x03, // iSerialNumber: none
|
||||
0x01 // bNumConfigurations: 1
|
||||
};
|
||||
|
||||
static const u8 LANGUAGE_STR[] = {
|
||||
0x04, 0x03, 0x09, 0x04
|
||||
};
|
||||
|
||||
|
||||
static const u8 product_string[] = {
|
||||
42,
|
||||
0x03,
|
||||
'U', 0x00,
|
||||
'S', 0x00,
|
||||
'B', 0x00,
|
||||
' ', 0x00,
|
||||
'C', 0x00,
|
||||
'o', 0x00,
|
||||
'm', 0x00,
|
||||
'p', 0x00,
|
||||
'o', 0x00,
|
||||
's', 0x00,
|
||||
'i', 0x00,
|
||||
't', 0x00,
|
||||
'e', 0x00,
|
||||
' ', 0x00,
|
||||
'D', 0x00,
|
||||
'e', 0x00,
|
||||
'v', 0x00,
|
||||
'i', 0x00,
|
||||
'c', 0x00,
|
||||
'e', 0x00,
|
||||
};
|
||||
|
||||
static const u8 MANUFACTURE_STR[] = {
|
||||
34, //该描述符的长度为34字节
|
||||
0x03, //字符串描述符的类型编码为0x03
|
||||
0x4a, 0x00, //J
|
||||
0x69, 0x00, //i
|
||||
0x65, 0x00, //e
|
||||
0x6c, 0x00, //l
|
||||
0x69, 0x00, //i
|
||||
0x20, 0x00, //
|
||||
0x54, 0x00, //T
|
||||
0x65, 0x00, //e
|
||||
0x63, 0x00, //c
|
||||
0x68, 0x00, //h
|
||||
0x6e, 0x00, //n
|
||||
0x6f, 0x00, //o
|
||||
0x6c, 0x00, //l
|
||||
0x6f, 0x00, //o
|
||||
0x67, 0x00, //g
|
||||
0x79, 0x00, //y
|
||||
};
|
||||
|
||||
static const u8 sConfigDescriptor[] = { //<Config Descriptor
|
||||
//ConfiguraTIon
|
||||
USB_DT_CONFIG_SIZE, //bLength
|
||||
USB_DT_CONFIG, //DescriptorType : ConfigDescriptor
|
||||
0, 0, //TotalLength
|
||||
0,//bNumInterfaces: 在set_descriptor函数里面计算
|
||||
0x01, //bConfigurationValue - ID of this configuration
|
||||
0x00, //Unused
|
||||
#if USB_ROOT2 || USB_SUSPEND_RESUME || USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP
|
||||
0xA0, //Attributes:Bus Power remotewakeup
|
||||
#else
|
||||
0x80, //Attributes:Bus Power
|
||||
#endif
|
||||
50, //MaxPower * 2ma
|
||||
};
|
||||
|
||||
static const u8 serial_string[] = {
|
||||
0x22, 0x03, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x30, 0x00, 0x36, 0x00, 0x46, 0x00, 0x36, 0x00,
|
||||
0x34, 0x00, 0x30, 0x00, 0x39, 0x00, 0x36, 0x00, 0x42, 0x00, 0x32, 0x00, 0x32, 0x00, 0x45, 0x00,
|
||||
0x37, 0x00
|
||||
};
|
||||
|
||||
void get_device_descriptor(u8 *ptr)
|
||||
{
|
||||
memcpy(ptr, sDeviceDescriptor, USB_DT_DEVICE_SIZE);
|
||||
}
|
||||
|
||||
void get_language_str(u8 *ptr)
|
||||
{
|
||||
memcpy(ptr, LANGUAGE_STR, LANGUAGE_STR[0]);
|
||||
}
|
||||
|
||||
void get_manufacture_str(u8 *ptr)
|
||||
{
|
||||
memcpy(ptr, MANUFACTURE_STR, MANUFACTURE_STR[0]);
|
||||
}
|
||||
|
||||
void get_iserialnumber_str(u8 *ptr)
|
||||
{
|
||||
#if USB_ROOT2
|
||||
memcpy(ptr, serial_string, serial_string[0]);
|
||||
#else
|
||||
extern __attribute__((weak)) u8 *get_norflash_uuid(void);
|
||||
u8 flash_id[16] = {0};
|
||||
int i;
|
||||
u8 bcd;
|
||||
if (get_norflash_uuid && get_norflash_uuid()) {
|
||||
ptr[0] = 0x22;
|
||||
ptr[1] = 0x03;
|
||||
memset(&ptr[2], 0, 0x20);
|
||||
memcpy(flash_id, get_norflash_uuid(), 16);
|
||||
//take 8 bytes from flash uuid
|
||||
for (i = 0; i < 8; i++) {
|
||||
bcd = flash_id[i] >> 4;
|
||||
if (bcd > 9) {
|
||||
bcd = bcd - 0xa + 'A';
|
||||
} else {
|
||||
bcd = bcd + '0';
|
||||
}
|
||||
ptr[2 + i * 4] = bcd;
|
||||
bcd = flash_id[i] & 0xf;
|
||||
if (bcd > 9) {
|
||||
bcd = bcd - 0xa + 'A';
|
||||
} else {
|
||||
bcd = bcd + '0';
|
||||
}
|
||||
ptr[2 + i * 4 + 2] = bcd;
|
||||
}
|
||||
} else {
|
||||
memcpy(ptr, serial_string, serial_string[0]);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#if USB_ROOT2
|
||||
static const u8 ee_string[] = {0x12, 0x03, 0x4D, 0x00, 0x53, 0x00, 0x46, 0x00, 0x54,
|
||||
0x00, 0x31, 0x00, 0x30, 0x00, 0x30, 0x00, 0x90, 0x00
|
||||
};
|
||||
void get_string_ee(u8 *ptr)
|
||||
{
|
||||
memcpy(ptr, ee_string, ee_string[0]);
|
||||
}
|
||||
#endif
|
||||
|
||||
void get_product_str(u8 *ptr)
|
||||
{
|
||||
memcpy(ptr, product_string, product_string[0]);
|
||||
}
|
||||
|
||||
const u8 *usb_get_config_desc()
|
||||
{
|
||||
return sConfigDescriptor;
|
||||
}
|
||||
|
||||
const u8 *usb_get_string_desc(u32 id)
|
||||
{
|
||||
const u8 *pstr = uac_get_string(id);
|
||||
if (pstr != NULL) {
|
||||
return pstr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
332
apps/common/device/usb/device/hid.c
Normal file
332
apps/common/device/usb/device/hid.c
Normal file
@ -0,0 +1,332 @@
|
||||
#include "os/os_api.h"
|
||||
#include "usb/device/usb_stack.h"
|
||||
#include "usb/device/hid.h"
|
||||
#include "usb_config.h"
|
||||
|
||||
#include "app_config.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_USER_HID
|
||||
#undef TCFG_USB_SLAVE_HID_ENABLE
|
||||
#define TCFG_USB_SLAVE_HID_ENABLE 0
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
|
||||
#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"
|
||||
static const u8 sHIDDescriptor[] = {
|
||||
//HID
|
||||
//InterfaceDeszcriptor:
|
||||
USB_DT_INTERFACE_SIZE, // Length
|
||||
USB_DT_INTERFACE, // DescriptorType
|
||||
/* 0x04, // bInterface number */
|
||||
0x00, // bInterface number
|
||||
0x00, // AlternateSetting
|
||||
0x01, // NumEndpoint
|
||||
/* 0x02, // NumEndpoint */
|
||||
USB_CLASS_HID, // Class = Human Interface Device
|
||||
0x00, // Subclass, 0 No subclass, 1 Boot Interface subclass
|
||||
0x00, // Procotol, 0 None, 1 Keyboard, 2 Mouse
|
||||
0x00, // Interface Name
|
||||
|
||||
//HIDDescriptor:
|
||||
0x09, // bLength
|
||||
USB_HID_DT_HID, // bDescriptorType, HID Descriptor
|
||||
0x00, 0x01, // bcdHID, HID Class Specification release NO.
|
||||
0x00, // bCuntryCode, Country localization (=none)
|
||||
0x01, // bNumDescriptors, Number of descriptors to follow
|
||||
0x22, // bDescriptorType, Report Desc. 0x22, Physical Desc. 0x23
|
||||
0,//LOW(ReportLength)
|
||||
0, //HIGH(ReportLength)
|
||||
|
||||
//EndpointDescriptor:
|
||||
USB_DT_ENDPOINT_SIZE, // bLength
|
||||
USB_DT_ENDPOINT, // bDescriptorType, Type
|
||||
USB_DIR_IN | HID_EP_IN, // bEndpointAddress
|
||||
USB_ENDPOINT_XFER_INT, // Interrupt
|
||||
LOBYTE(MAXP_SIZE_HIDIN), HIBYTE(MAXP_SIZE_HIDIN),// Maximum packet size
|
||||
HID_INTR_INTERVAL, // Poll every 10msec seconds
|
||||
|
||||
//@Endpoint Descriptor:
|
||||
/* USB_DT_ENDPOINT_SIZE, // bLength
|
||||
USB_DT_ENDPOINT, // bDescriptorType, Type
|
||||
USB_DIR_OUT | HID_EP_OUT, // bEndpointAddress
|
||||
USB_ENDPOINT_XFER_INT, // Interrupt
|
||||
LOBYTE(MAXP_SIZE_HIDOUT), HIBYTE(MAXP_SIZE_HIDOUT),// Maximum packet size
|
||||
HID_INTR_INTERVAL, // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms */
|
||||
};
|
||||
|
||||
static const u8 sHIDReportDesc[] = {
|
||||
USAGE_PAGE(1, CONSUMER_PAGE),
|
||||
USAGE(1, CONSUMER_CONTROL),
|
||||
COLLECTION(1, APPLICATION),
|
||||
|
||||
LOGICAL_MIN(1, 0x00),
|
||||
LOGICAL_MAX(1, 0x01),
|
||||
|
||||
USAGE(1, VOLUME_INC),
|
||||
USAGE(1, VOLUME_DEC),
|
||||
USAGE(1, MUTE),
|
||||
USAGE(1, PLAY_PAUSE),
|
||||
USAGE(1, SCAN_NEXT_TRACK),
|
||||
USAGE(1, SCAN_PREV_TRACK),
|
||||
USAGE(1, FAST_FORWARD),
|
||||
USAGE(1, STOP),
|
||||
|
||||
USAGE(1, TRACKING_INC),
|
||||
USAGE(1, TRACKING_DEC),
|
||||
USAGE(1, STOP_EJECT),
|
||||
USAGE(1, VOLUME),
|
||||
USAGE(2, BALANCE_LEFT),
|
||||
USAGE(2, BALANCE_RIGHT),
|
||||
USAGE(1, PLAY),
|
||||
USAGE(1, PAUSE),
|
||||
|
||||
REPORT_SIZE(1, 0x01),
|
||||
REPORT_COUNT(1, 0x10),
|
||||
INPUT(1, 0x42),
|
||||
END_COLLECTION,
|
||||
|
||||
};
|
||||
|
||||
static u32 get_hid_report_desc_len(u32 index)
|
||||
{
|
||||
u32 len = 0;
|
||||
len = sizeof(sHIDReportDesc);
|
||||
return len;
|
||||
}
|
||||
static void *get_hid_report_desc(u32 index)
|
||||
{
|
||||
u8 *ptr = NULL;
|
||||
ptr = (u8 *)sHIDReportDesc;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
static u8 *hid_ep_in_dma;
|
||||
/* static u8 *hid_ep_out_dma; */
|
||||
|
||||
static u32 hid_tx_data(struct usb_device_t *usb_device, const u8 *buffer, u32 len)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
return usb_g_intr_write(usb_id, HID_EP_IN, buffer, len);
|
||||
}
|
||||
static void hid_rx_data(struct usb_device_t *usb_device, u32 ep)
|
||||
{
|
||||
/* const usb_dev usb_id = usb_device2id(usb_device); */
|
||||
/* u32 rx_len = usb_g_intr_read(usb_id, ep, NULL, 64, 0); */
|
||||
/* hid_tx_data(usb_device, hid_ep_out_dma, rx_len); */
|
||||
}
|
||||
|
||||
static void hid_endpoint_init(struct usb_device_t *usb_device, u32 itf)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
usb_g_ep_config(usb_id, HID_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_INT, 0, hid_ep_in_dma, MAXP_SIZE_HIDIN);
|
||||
usb_enable_ep(usb_id, HID_EP_IN);
|
||||
|
||||
/* usb_g_set_intr_hander(usb_id, HID_EP_OUT, hid_rx_data); */
|
||||
/* usb_g_ep_config(usb_id, HID_EP_OUT, USB_ENDPOINT_XFER_INT, 1, ep_buffer, MAXP_SIZE_HIDOUT); */
|
||||
}
|
||||
u32 hid_register(const usb_dev usb_id)
|
||||
{
|
||||
hid_ep_in_dma = usb_alloc_ep_dmabuffer(usb_id, HID_EP_IN | USB_DIR_IN, MAXP_SIZE_HIDIN);
|
||||
|
||||
/* hid_ep_out_dma = hid_ep_in_dma + MAXP_SIZE_HIDIN; */
|
||||
return 0;
|
||||
}
|
||||
|
||||
void hid_release(const usb_dev usb_id)
|
||||
{
|
||||
return ;
|
||||
}
|
||||
|
||||
static void hid_reset(struct usb_device_t *usb_device, u32 itf)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
log_debug("%s", __func__);
|
||||
#if USB_ROOT2
|
||||
usb_disable_ep(usb_id, HID_EP_IN);
|
||||
#else
|
||||
hid_endpoint_init(usb_device, itf);
|
||||
#endif
|
||||
}
|
||||
static u32 hid_recv_output_report(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u32 ret = 0;
|
||||
u8 read_ep[8];
|
||||
u8 mute;
|
||||
u16 volume = 0;
|
||||
usb_read_ep0(usb_id, read_ep, MIN(sizeof(read_ep), setup->wLength));
|
||||
ret = USB_EP0_STAGE_SETUP;
|
||||
put_buf(read_ep, 8);
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 hid_itf_hander(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u32 tx_len;
|
||||
u8 *tx_payload = usb_get_setup_buffer(usb_device);
|
||||
u32 bRequestType = req->bRequestType & USB_TYPE_MASK;
|
||||
switch (bRequestType) {
|
||||
case USB_TYPE_STANDARD:
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_GET_DESCRIPTOR:
|
||||
switch (HIBYTE(req->wValue)) {
|
||||
case USB_HID_DT_HID:
|
||||
tx_payload = (u8 *)sHIDDescriptor + USB_DT_INTERFACE_SIZE;
|
||||
tx_len = 9;
|
||||
tx_payload = usb_set_data_payload(usb_device, req, tx_payload, tx_len);
|
||||
tx_payload[7] = LOBYTE(get_hid_report_desc_len(req->wIndex));
|
||||
tx_payload[8] = HIBYTE(get_hid_report_desc_len(req->wIndex));
|
||||
break;
|
||||
case USB_HID_DT_REPORT:
|
||||
hid_endpoint_init(usb_device, req->wIndex);
|
||||
tx_len = get_hid_report_desc_len(req->wIndex);
|
||||
tx_payload = get_hid_report_desc(req->wIndex);
|
||||
usb_set_data_payload(usb_device, req, tx_payload, tx_len);
|
||||
break;
|
||||
}// USB_REQ_GET_DESCRIPTOR
|
||||
break;
|
||||
case USB_REQ_SET_DESCRIPTOR:
|
||||
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
|
||||
break;
|
||||
case USB_REQ_SET_INTERFACE:
|
||||
if (usb_device->bDeviceStates == USB_DEFAULT) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_ADDRESS) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_CONFIGURED) {
|
||||
//只有一个interface 没有Alternate
|
||||
if (req->wValue == 0) { //alt 0
|
||||
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
|
||||
} else {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case USB_REQ_GET_INTERFACE:
|
||||
if (req->wValue || (req->wLength != 1)) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_DEFAULT) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_ADDRESS) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_CONFIGURED) {
|
||||
tx_len = 1;
|
||||
tx_payload[0] = 0x00;
|
||||
usb_set_data_payload(usb_device, req, tx_payload, tx_len);
|
||||
}
|
||||
break;
|
||||
case USB_REQ_GET_STATUS:
|
||||
if (usb_device->bDeviceStates == USB_DEFAULT) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else if (usb_device->bDeviceStates == USB_ADDRESS) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
} else {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
}
|
||||
break;
|
||||
}//bRequest @ USB_TYPE_STANDARD
|
||||
break;
|
||||
|
||||
case USB_TYPE_CLASS: {
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_SET_IDLE:
|
||||
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
|
||||
break;
|
||||
case USB_REQ_GET_IDLE:
|
||||
tx_len = 1;
|
||||
tx_payload[0] = 0;
|
||||
usb_set_data_payload(usb_device, req, tx_payload, tx_len);
|
||||
break;
|
||||
case USB_REQ_SET_REPORT:
|
||||
usb_set_setup_recv(usb_device, hid_recv_output_report);
|
||||
break;
|
||||
}//bRequest @ USB_TYPE_CLASS
|
||||
}
|
||||
break;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 hid_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
|
||||
{
|
||||
log_debug("hid interface num:%d\n", *cur_itf_num);
|
||||
u8 *_ptr = ptr;
|
||||
memcpy(ptr, sHIDDescriptor, sizeof(sHIDDescriptor));
|
||||
ptr[2] = *cur_itf_num;
|
||||
if (usb_set_interface_hander(usb_id, *cur_itf_num, hid_itf_hander) != *cur_itf_num) {
|
||||
ASSERT(0, "hid set interface_hander fail");
|
||||
}
|
||||
if (usb_set_reset_hander(usb_id, *cur_itf_num, hid_reset) != *cur_itf_num) {
|
||||
ASSERT(0, "hid set interface_reset_hander fail");
|
||||
}
|
||||
|
||||
ptr[USB_DT_INTERFACE_SIZE + 7] = LOBYTE(get_hid_report_desc_len(0));
|
||||
ptr[USB_DT_INTERFACE_SIZE + 8] = HIBYTE(get_hid_report_desc_len(0));
|
||||
*cur_itf_num = *cur_itf_num + 1;
|
||||
return sizeof(sHIDDescriptor) ;
|
||||
}
|
||||
|
||||
void hid_key_handler(struct usb_device_t *usb_device, u32 hid_key)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
if (usb_get_ep_status(usb_id, HID_EP_IN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
u16 key_buf = hid_key;
|
||||
hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
|
||||
os_time_dly(2);
|
||||
key_buf = 0;
|
||||
hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
|
||||
}
|
||||
|
||||
void hid_key_handler_send_one_packet(struct usb_device_t *usb_device, u32 hid_key)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u16 key_buf = hid_key;
|
||||
hid_tx_data(usb_device, (const u8 *)&key_buf, 2);
|
||||
}
|
||||
|
||||
struct hid_button {
|
||||
u8 report_id;
|
||||
u8 button1: 1;
|
||||
u8 button2: 1;
|
||||
u8 button3: 1;
|
||||
u8 no_button: 5;
|
||||
u8 X_axis;
|
||||
u8 Y_axis;
|
||||
};
|
||||
struct hid_button hid_key;
|
||||
void hid_test(struct usb_device_t *usb_device)
|
||||
{
|
||||
static u32 tx_count = 0;
|
||||
|
||||
hid_key_handler(usb_device, BIT(tx_count));
|
||||
tx_count ++;
|
||||
if (BIT(tx_count) > USB_AUDIO_PAUSE) {
|
||||
tx_count = 0;
|
||||
}
|
||||
}
|
||||
#else
|
||||
void hid_key_handler(struct usb_device_t *usb_device, u32 hid_key)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
void hid_key_handler_for_one_packet(struct usb_device_t *usb_device, u32 hid_key)
|
||||
{
|
||||
|
||||
}
|
||||
#endif
|
||||
1126
apps/common/device/usb/device/msd.c
Normal file
1126
apps/common/device/usb/device/msd.c
Normal file
File diff suppressed because it is too large
Load Diff
76
apps/common/device/usb/device/msd_upgrade.c
Normal file
76
apps/common/device/usb/device/msd_upgrade.c
Normal file
@ -0,0 +1,76 @@
|
||||
#include "system/includes.h"
|
||||
#include "usb/device/msd.h"
|
||||
#include "usb/scsi.h"
|
||||
#include "usb_config.h"
|
||||
#include "app_config.h"
|
||||
#include "cpu.h"
|
||||
#include "asm/debug.h"
|
||||
|
||||
#define WRITE_FLASH 0xFB
|
||||
#define READ_FLASH 0xFD
|
||||
#define OTHER_CMD 0xFC
|
||||
typedef enum {
|
||||
UPGRADE_NULL = 0,
|
||||
UPGRADE_USB_HARD_KEY,
|
||||
UPGRADE_USB_SOFT_KEY,
|
||||
UPGRADE_UART_KEY,
|
||||
} UPGRADE_STATE;
|
||||
|
||||
extern void nvram_set_boot_state(u32 state);
|
||||
extern void hw_mmu_disable(void);
|
||||
extern void ram_protect_close(void);
|
||||
|
||||
AT(.volatile_ram_code)
|
||||
void go_mask_usb_updata()
|
||||
{
|
||||
#ifdef CONFIG_CPU_BR18
|
||||
gpio_set_die(IO_PORTD_02, 0);
|
||||
gpio_set_die(IO_PORTB_04, 0);
|
||||
cpu_reset();
|
||||
|
||||
#else
|
||||
local_irq_disable();
|
||||
ram_protect_close();
|
||||
//FIXME
|
||||
/* hw_mmu_disable(); */
|
||||
nvram_set_boot_state(UPGRADE_USB_SOFT_KEY);
|
||||
JL_CLOCK->PWR_CON |= (1 << 4);
|
||||
#endif
|
||||
|
||||
/* chip_reset(); */
|
||||
/* cpu_reset(); */
|
||||
while (1);
|
||||
}
|
||||
#if TCFG_PC_UPDATE
|
||||
|
||||
u32 _usb_bulk_rw_test(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw);
|
||||
|
||||
u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw)
|
||||
{
|
||||
/* if (_usb_bulk_rw_test(usb_device, cbw)) { */
|
||||
/* return TRUE; */
|
||||
/* } */
|
||||
|
||||
switch (cbw->operationCode) {
|
||||
//////////////////////Boot Loader Custom CMD
|
||||
case WRITE_FLASH:
|
||||
case READ_FLASH:
|
||||
case OTHER_CMD:
|
||||
log_d("goto mask pc mode\n");
|
||||
go_mask_usb_updata();
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#else
|
||||
u32 private_scsi_cmd(const struct usb_device_t *usb_device, struct usb_scsi_cbw *cbw)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
#endif
|
||||
|
||||
463
apps/common/device/usb/device/task_pc.c
Normal file
463
apps/common/device/usb/device/task_pc.c
Normal file
@ -0,0 +1,463 @@
|
||||
/**
|
||||
* @file task_pc.c
|
||||
* @brief 从机模式
|
||||
* @author chenrixin@zh-jieli.com
|
||||
* @version 1.0.0
|
||||
* @date 2020-02-29
|
||||
*/
|
||||
|
||||
#include "system/app_core.h"
|
||||
#include "system/includes.h"
|
||||
#include "server/server_core.h"
|
||||
#include "app_config.h"
|
||||
#include "app_action.h"
|
||||
#include "os/os_api.h"
|
||||
#include "device/sdmmc.h"
|
||||
|
||||
#include "app_charge.h"
|
||||
#include "asm/charge.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_ENABLE
|
||||
#if USB_PC_NO_APP_MODE == 0
|
||||
#include "app_task.h"
|
||||
#endif
|
||||
#include "usb/usb_config.h"
|
||||
#include "usb/device/usb_stack.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
#include "usb/device/hid.h"
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
#include "usb/device/msd.h"
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
#include "usb/device/cdc.h"
|
||||
#endif
|
||||
|
||||
#if (TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0)
|
||||
#include "dev_multiplex_api.h"
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_APPLE_DOCK_EN
|
||||
#include "apple_dock/iAP.h"
|
||||
#endif
|
||||
|
||||
#if (TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE)
|
||||
#include "cfg_tool.h"
|
||||
#endif
|
||||
|
||||
#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
|
||||
&& TCFG_CHARGESTORE_PORT == IO_PORT_DP)
|
||||
#include "asm/chargestore.h"
|
||||
#endif
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[USB_TASK]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
#define USB_TASK_NAME "usb_msd"
|
||||
|
||||
#define USBSTACK_EVENT 0x80
|
||||
#define USBSTACK_MSD_RUN 0x81
|
||||
#define USBSTACK_MSD_RELASE 0x82
|
||||
#define USBSTACK_HID 0x83
|
||||
#define USBSTACK_MSD_RESET 0x84
|
||||
|
||||
extern int usb_audio_demo_init(void);
|
||||
extern void usb_audio_demo_exit(void);
|
||||
|
||||
static usb_dev usbfd = 0;//SEC(.usb_g_bss);
|
||||
static OS_MUTEX msd_mutex ;//SEC(.usb_g_bss);
|
||||
static u8 msd_in_task;
|
||||
static u8 msd_run_reset;
|
||||
|
||||
|
||||
static void usb_task(void *p)
|
||||
{
|
||||
int ret = 0;
|
||||
int msg[16];
|
||||
while (1) {
|
||||
ret = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
|
||||
if (ret != OS_TASKQ) {
|
||||
continue;
|
||||
}
|
||||
if (msg[0] != Q_MSG) {
|
||||
continue;
|
||||
}
|
||||
switch (msg[1]) {
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
case USBSTACK_MSD_RUN:
|
||||
os_mutex_pend(&msd_mutex, 0);
|
||||
msd_in_task = 1;
|
||||
#if TCFG_USB_APPLE_DOCK_EN
|
||||
apple_mfi_link((void *)msg[2]);
|
||||
#else
|
||||
USB_MassStorage((void *)msg[2]);
|
||||
#endif
|
||||
if (msd_run_reset) {
|
||||
msd_reset((struct usb_device_t *)msg[2], 0);
|
||||
msd_run_reset = 0;
|
||||
}
|
||||
msd_in_task = 0;
|
||||
os_mutex_post(&msd_mutex);
|
||||
break;
|
||||
case USBSTACK_MSD_RELASE:
|
||||
os_sem_post((OS_SEM *)msg[2]);
|
||||
while (1) {
|
||||
os_time_dly(10000);
|
||||
}
|
||||
break;
|
||||
// case USBSTACK_MSD_RESET:
|
||||
// os_mutex_pend(&msd_mutex, 0);
|
||||
// msd_reset((struct usb_device_t *)msg[2], (u32)msg[3]);
|
||||
// os_mutex_post(&msd_mutex);
|
||||
// break;
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void usb_msd_wakeup(struct usb_device_t *usb_device)
|
||||
{
|
||||
os_taskq_post_msg(USB_TASK_NAME, 2, USBSTACK_MSD_RUN, usb_device);
|
||||
}
|
||||
static void usb_msd_reset_wakeup(struct usb_device_t *usb_device, u32 itf_num)
|
||||
{
|
||||
/* os_taskq_post_msg(USB_TASK_NAME, 3, USBSTACK_MSD_RESET, usb_device, itf_num); */
|
||||
if (msd_in_task) {
|
||||
msd_run_reset = 1;
|
||||
} else {
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
msd_reset(usb_device, 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
static void usb_msd_init()
|
||||
{
|
||||
r_printf("%s()", __func__);
|
||||
int err;
|
||||
os_mutex_create(&msd_mutex);
|
||||
err = task_create(usb_task, NULL, USB_TASK_NAME);
|
||||
if (err != OS_NO_ERR) {
|
||||
r_printf("usb_msd task creat fail %x\n", err);
|
||||
}
|
||||
}
|
||||
static void usb_msd_free()
|
||||
{
|
||||
r_printf("%s()", __func__);
|
||||
|
||||
os_mutex_del(&msd_mutex, 0);
|
||||
|
||||
int err;
|
||||
OS_SEM sem;
|
||||
os_sem_create(&sem, 0);
|
||||
os_taskq_post_msg(USB_TASK_NAME, 2, USBSTACK_MSD_RELASE, (int)&sem);
|
||||
os_sem_pend(&sem, 0);
|
||||
|
||||
|
||||
err = task_kill(USB_TASK_NAME);
|
||||
if (!err) {
|
||||
r_printf("usb_msd_uninit succ!!\n");
|
||||
} else {
|
||||
r_printf("usb_msd_uninit fail!!\n");
|
||||
}
|
||||
}
|
||||
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
static void usb_cdc_wakeup(struct usb_device_t *usb_device)
|
||||
{
|
||||
//回调函数在中断里,正式使用不要在这里加太多东西阻塞中断,
|
||||
//或者先post到任务,由任务调用cdc_read_data()读取再执行后续工作
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u8 buf[64] = {0};
|
||||
static u8 buf_rx[256] = {0};
|
||||
static u8 rx_len_total = 0;
|
||||
u32 rlen;
|
||||
|
||||
log_debug("cdc rx hook");
|
||||
rlen = cdc_read_data(usb_id, buf, 64);
|
||||
|
||||
/* put_buf(buf, rlen);//固件三部测试使用 */
|
||||
/* cdc_write_data(usb_id, buf, rlen);//固件三部测试使用 */
|
||||
|
||||
if ((buf[0] == 0x5A) && (buf[1] == 0xAA) && (buf[2] == 0xA5)) {
|
||||
memset(buf_rx, 0, 256);
|
||||
memcpy(buf_rx, buf, rlen);
|
||||
/* log_info("need len = %d\n", buf_rx[5] + 6); */
|
||||
/* log_info("rx len = %d\n", rlen); */
|
||||
if ((buf_rx[5] + 6) == rlen) {
|
||||
rx_len_total = 0;
|
||||
#if TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE
|
||||
#if (TCFG_COMM_TYPE == TCFG_USB_COMM)
|
||||
/* put_buf(buf_rx, rlen); */
|
||||
online_cfg_tool_data_deal(buf_rx, rlen);
|
||||
#else
|
||||
put_buf(buf, rlen);
|
||||
cdc_write_data(usb_id, buf, rlen);
|
||||
#endif
|
||||
#endif
|
||||
} else {
|
||||
rx_len_total += rlen;
|
||||
}
|
||||
} else {
|
||||
if ((rx_len_total + rlen) > 256) {
|
||||
memset(buf_rx, 0, 256);
|
||||
rx_len_total = 0;
|
||||
return;
|
||||
}
|
||||
memcpy(buf_rx + rx_len_total, buf, rlen);
|
||||
/* log_info("need len = %d\n", buf_rx[5] + 6); */
|
||||
/* log_info("rx len = %d\n", rx_len_total + rlen); */
|
||||
if ((buf_rx[5] + 6) == (rx_len_total + rlen)) {
|
||||
#if TCFG_CFG_TOOL_ENABLE || TCFG_EFFECT_TOOL_ENABLE
|
||||
#if (TCFG_COMM_TYPE == TCFG_USB_COMM)
|
||||
/* put_buf(buf_rx, rx_len_total + rlen); */
|
||||
online_cfg_tool_data_deal(buf_rx, rx_len_total + rlen);
|
||||
#else
|
||||
put_buf(buf, rlen);
|
||||
cdc_write_data(usb_id, buf, rlen);
|
||||
#endif
|
||||
#endif
|
||||
rx_len_total = 0;
|
||||
} else {
|
||||
rx_len_total += rlen;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void usb_start()
|
||||
{
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
usb_audio_demo_init();
|
||||
#endif
|
||||
|
||||
#ifdef USB_DEVICE_CLASS_CONFIG
|
||||
g_printf("USB_DEVICE_CLASS_CONFIG:%x", USB_DEVICE_CLASS_CONFIG);
|
||||
#if TCFG_USB_CDC_BACKGROUND_RUN
|
||||
usb_device_mode(usbfd, USB_DEVICE_CLASS_CONFIG | CDC_CLASS);
|
||||
#else
|
||||
usb_device_mode(usbfd, USB_DEVICE_CLASS_CONFIG);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
//没有复用时候判断 sd开关
|
||||
//复用时候判断是否参与复用
|
||||
#if (!TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_SD0_ENABLE)\
|
||||
||(TCFG_SD0_ENABLE && TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_DM_MULTIPLEX_WITH_SD_PORT != 0)
|
||||
msd_register_disk("sd0", NULL);
|
||||
#endif
|
||||
|
||||
#if (!TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_SD1_ENABLE)\
|
||||
||(TCFG_SD1_ENABLE && TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 && TCFG_DM_MULTIPLEX_WITH_SD_PORT != 1)
|
||||
msd_register_disk("sd1", NULL);
|
||||
#endif
|
||||
|
||||
#if TCFG_NOR_FAT
|
||||
msd_register_disk("fat_nor", NULL);
|
||||
#endif
|
||||
|
||||
#if TCFG_VIR_UDISK_ENABLE
|
||||
msd_register_disk("vir_udisk0", NULL);
|
||||
#endif
|
||||
|
||||
msd_set_wakeup_handle(usb_msd_wakeup);
|
||||
msd_set_reset_wakeup_handle(usb_msd_reset_wakeup);
|
||||
usb_msd_init();
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
cdc_set_wakeup_handler(usb_cdc_wakeup);
|
||||
#endif
|
||||
}
|
||||
static void usb_remove_disk()
|
||||
{
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
os_mutex_pend(&msd_mutex, 0);
|
||||
msd_unregister_all();
|
||||
os_mutex_post(&msd_mutex);
|
||||
#endif
|
||||
}
|
||||
void usb_pause()
|
||||
{
|
||||
log_info("usb pause");
|
||||
|
||||
usb_sie_disable(usbfd);
|
||||
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
if (msd_set_wakeup_handle(NULL)) {
|
||||
usb_remove_disk();
|
||||
usb_msd_free();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
usb_audio_demo_exit();
|
||||
#endif
|
||||
|
||||
usb_device_mode(usbfd, 0);
|
||||
}
|
||||
|
||||
void usb_stop()
|
||||
{
|
||||
log_info("App Stop - usb");
|
||||
|
||||
usb_pause();
|
||||
|
||||
usb_sie_close(usbfd);
|
||||
}
|
||||
|
||||
#if TCFG_USB_CDC_BACKGROUND_RUN
|
||||
void usb_cdc_background_run()
|
||||
{
|
||||
g_printf("CDC is running in the background");
|
||||
usb_device_mode(0, CDC_CLASS);
|
||||
cdc_set_wakeup_handler(usb_cdc_wakeup);
|
||||
}
|
||||
#endif
|
||||
|
||||
int pc_device_event_handler(struct sys_event *event)
|
||||
{
|
||||
if ((int)event->arg != DEVICE_EVENT_FROM_OTG) {
|
||||
return false;
|
||||
}
|
||||
|
||||
int switch_app_case = false;
|
||||
const char *usb_msg = (const char *)event->u.dev.value;
|
||||
log_debug("usb event : %d DEVICE_EVENT_FROM_OTG %s", event->u.dev.event, usb_msg);
|
||||
|
||||
if (usb_msg[0] == 's') {
|
||||
if (event->u.dev.event == DEVICE_EVENT_IN) {
|
||||
log_info("usb %c online", usb_msg[2]);
|
||||
usbfd = usb_msg[2] - '0';
|
||||
#if USB_PC_NO_APP_MODE
|
||||
usb_start();
|
||||
#elif TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
|
||||
|
||||
#if TCFG_USB_CDC_BACKGROUND_RUN
|
||||
mult_sdio_suspend();
|
||||
usb_cdc_background_run();
|
||||
switch_app_case = 0;
|
||||
#else
|
||||
usb_otg_suspend(0, OTG_KEEP_STATE);
|
||||
mult_sdio_suspend();
|
||||
usb_pause();
|
||||
mult_sdio_resume();
|
||||
switch_app_case = 0;
|
||||
#endif//TCFG_USB_CDC_BACKGROUND_RUN
|
||||
|
||||
#else
|
||||
|
||||
|
||||
#if (TWFG_APP_POWERON_IGNORE_DEV && TCFG_USB_CDC_BACKGROUND_RUN && TCFG_PC_ENABLE)
|
||||
if (jiffies_to_msecs(jiffies) < TWFG_APP_POWERON_IGNORE_DEV) {
|
||||
usb_cdc_background_run();
|
||||
switch_app_case = 0;
|
||||
} else {
|
||||
usb_pause();
|
||||
switch_app_case = 1;
|
||||
}
|
||||
#elif (TCFG_USB_CDC_BACKGROUND_RUN)
|
||||
usb_cdc_background_run();
|
||||
switch_app_case = 0;
|
||||
|
||||
#elif (TWFG_APP_POWERON_IGNORE_DEV == 0)
|
||||
usb_pause();
|
||||
switch_app_case = 1;
|
||||
|
||||
#else
|
||||
usb_pause();
|
||||
switch_app_case = 1;
|
||||
#endif
|
||||
|
||||
#endif
|
||||
} else if (event->u.dev.event == DEVICE_EVENT_OUT) {
|
||||
log_info("usb %c offline", usb_msg[2]);
|
||||
#if USB_PC_NO_APP_MODE
|
||||
usb_stop();
|
||||
#else
|
||||
|
||||
#ifdef CONFIG_SOUNDBOX
|
||||
if (true == app_check_curr_task(APP_PC_TASK)) {
|
||||
#else
|
||||
if (app_get_curr_task() == APP_PC_TASK) {
|
||||
#endif
|
||||
switch_app_case = 2;
|
||||
} else {
|
||||
/* 此处的模式限制会在USB已连接,蓝牙播歌切换到蓝牙模式后再拔出USB的情况下,
|
||||
无法检测到再次插入USB */
|
||||
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
|
||||
mult_sdio_suspend();
|
||||
#endif
|
||||
usb_stop();
|
||||
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
|
||||
mult_sdio_resume();
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
return switch_app_case;
|
||||
}
|
||||
|
||||
#if USB_PC_NO_APP_MODE
|
||||
void usbstack_init()
|
||||
{
|
||||
register_sys_event_handler(SYS_DEVICE_EVENT, DEVICE_EVENT_FROM_OTG, 2,
|
||||
(void (*)(struct sys_event *))pc_device_event_handler);
|
||||
}
|
||||
|
||||
void usbstack_exit()
|
||||
{
|
||||
unregister_sys_event_handler((void (*)(struct sys_event *))pc_device_event_handler);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (TCFG_OTG_MODE & OTG_DET_DM_ONLY)
|
||||
static void otg_sof_check_before_hook()
|
||||
{
|
||||
log_debug("sof_check_before");
|
||||
#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
|
||||
&& TCFG_CHARGESTORE_PORT == IO_PORT_DP)
|
||||
power_wakeup_index_enable(2, 0);
|
||||
chargestore_api_stop();
|
||||
#endif
|
||||
}
|
||||
|
||||
static void otg_sof_check_after_hook()
|
||||
{
|
||||
log_debug("sof_check_after");
|
||||
#if ((TCFG_CHARGESTORE_ENABLE || TCFG_TEST_BOX_ENABLE || TCFG_ANC_BOX_ENABLE) \
|
||||
&& TCFG_CHARGESTORE_PORT == IO_PORT_DP)
|
||||
chargestore_api_restart();
|
||||
power_wakeup_index_enable(2, 1);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int otg_sof_check_hook_register()
|
||||
{
|
||||
//需要在otg定时器启动之前(即devices_init()之前)注册钩子函数
|
||||
usb_otg_sof_check_register_hooks(otg_sof_check_before_hook,
|
||||
otg_sof_check_after_hook);
|
||||
return 0;
|
||||
}
|
||||
early_initcall(otg_sof_check_hook_register);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
1401
apps/common/device/usb/device/uac1.c
Normal file
1401
apps/common/device/usb/device/uac1.c
Normal file
File diff suppressed because it is too large
Load Diff
514
apps/common/device/usb/device/uac_stream.c
Normal file
514
apps/common/device/usb/device/uac_stream.c
Normal file
@ -0,0 +1,514 @@
|
||||
#include "app_config.h"
|
||||
#include "system/includes.h"
|
||||
#include "printf.h"
|
||||
#include "usb/usb_config.h"
|
||||
#include "usb/device/usb_stack.h"
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
#include "usb/device/uac_audio.h"
|
||||
#include "uac_stream.h"
|
||||
#include "audio_config.h"
|
||||
|
||||
/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
|
||||
#include "audio_track.h"
|
||||
/* #endif */
|
||||
|
||||
|
||||
#define LOG_TAG_CONST USB
|
||||
#define LOG_TAG "[UAC]"
|
||||
#define LOG_ERROR_ENABLE
|
||||
#define LOG_DEBUG_ENABLE
|
||||
#define LOG_INFO_ENABLE
|
||||
/* #define LOG_DUMP_ENABLE */
|
||||
#define LOG_CLI_ENABLE
|
||||
#include "debug.h"
|
||||
|
||||
#define UAC_DEBUG_ECHO_MODE 0
|
||||
|
||||
static volatile u8 speaker_stream_is_open = 0;
|
||||
struct uac_speaker_handle {
|
||||
cbuffer_t cbuf;
|
||||
volatile u8 need_resume;
|
||||
u8 channel;
|
||||
u8 alive;
|
||||
void *buffer;
|
||||
void *audio_track;
|
||||
//void (*rx_handler)(int, void *, int);
|
||||
};
|
||||
|
||||
static void (*uac_rx_handler)(int, void *, int) = NULL;
|
||||
|
||||
#if (SOUNDCARD_ENABLE)
|
||||
#define UAC_BUFFER_SIZE (4 * 1024)
|
||||
#else
|
||||
#define UAC_BUFFER_SIZE (1 * 1024)
|
||||
#endif
|
||||
|
||||
#define UAC_BUFFER_MAX (UAC_BUFFER_SIZE * 50 / 100)
|
||||
|
||||
static struct uac_speaker_handle *uac_speaker = NULL;
|
||||
|
||||
#if USB_MALLOC_ENABLE
|
||||
#else
|
||||
static struct uac_speaker_handle uac_speaker_handle SEC(.uac_var);
|
||||
static u8 uac_rx_buffer[UAC_BUFFER_SIZE] ALIGNED(4) SEC(.uac_rx);
|
||||
#endif
|
||||
u32 uac_speaker_stream_length()
|
||||
{
|
||||
return UAC_BUFFER_SIZE;
|
||||
}
|
||||
u32 uac_speaker_stream_size()
|
||||
{
|
||||
if (!speaker_stream_is_open) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (uac_speaker) {
|
||||
return cbuf_get_data_size(&uac_speaker->cbuf);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 uac_speaker_get_alive()
|
||||
{
|
||||
if (uac_speaker) {
|
||||
return uac_speaker->alive;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void uac_speaker_set_alive(u8 alive)
|
||||
{
|
||||
local_irq_disable();
|
||||
if (uac_speaker) {
|
||||
uac_speaker->alive = alive;
|
||||
}
|
||||
local_irq_enable();
|
||||
}
|
||||
|
||||
void uac_speaker_stream_buf_clear(void)
|
||||
{
|
||||
if (speaker_stream_is_open) {
|
||||
cbuf_clear(&uac_speaker->cbuf);
|
||||
}
|
||||
}
|
||||
|
||||
void set_uac_speaker_rx_handler(void *priv, void (*rx_handler)(int, void *, int))
|
||||
{
|
||||
uac_rx_handler = rx_handler;
|
||||
/* if (uac_speaker) { */
|
||||
/* uac_speaker->rx_handler = rx_handler; */
|
||||
/* } */
|
||||
}
|
||||
|
||||
int uac_speaker_stream_sample_rate(void)
|
||||
{
|
||||
/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
|
||||
if (uac_speaker && uac_speaker->audio_track) {
|
||||
int sr = audio_local_sample_track_rate(uac_speaker->audio_track);
|
||||
if ((sr < (SPK_AUDIO_RATE + 100)) && (sr > (SPK_AUDIO_RATE - 100))) {
|
||||
return sr;
|
||||
}
|
||||
/* printf("uac audio_track reset \n"); */
|
||||
/* local_irq_disable(); */
|
||||
/* audio_local_sample_track_close(uac_speaker->audio_track); */
|
||||
/* uac_speaker->audio_track = audio_local_sample_track_open(SPK_CHANNEL, SPK_AUDIO_RATE, 1000); */
|
||||
/* local_irq_enable(); */
|
||||
}
|
||||
/* #endif */
|
||||
return SPK_AUDIO_RATE;
|
||||
}
|
||||
|
||||
void uac_speaker_stream_write(const u8 *obuf, u32 len)
|
||||
{
|
||||
if (speaker_stream_is_open) {
|
||||
//write dac
|
||||
/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
|
||||
if (uac_speaker->audio_track) {
|
||||
audio_local_sample_track_in_period(uac_speaker->audio_track, (len >> 1) / uac_speaker->channel);
|
||||
}
|
||||
/* #endif */
|
||||
int wlen = cbuf_write(&uac_speaker->cbuf, (void *)obuf, len);
|
||||
if (wlen != len) {
|
||||
//putchar('W');
|
||||
}
|
||||
//if (uac_speaker->rx_handler) {
|
||||
if (uac_rx_handler) {
|
||||
/* if (uac_speaker->cbuf.data_len >= UAC_BUFFER_MAX) { */
|
||||
// 马上就要满了,赶紧取走
|
||||
uac_speaker->need_resume = 1; //2020-12-22注:无需唤醒
|
||||
/* } */
|
||||
if (uac_speaker->need_resume) {
|
||||
uac_speaker->need_resume = 0;
|
||||
uac_rx_handler(0, (void *)obuf, len);
|
||||
//uac_speaker->rx_handler(0, (void *)obuf, len);
|
||||
}
|
||||
}
|
||||
uac_speaker->alive = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int uac_speaker_read(void *priv, void *data, u32 len)
|
||||
{
|
||||
int r_len;
|
||||
int err = 0;
|
||||
|
||||
local_irq_disable();
|
||||
if (!speaker_stream_is_open) {
|
||||
local_irq_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
r_len = cbuf_get_data_size(&uac_speaker->cbuf);
|
||||
if (r_len) {
|
||||
r_len = r_len > len ? len : r_len;
|
||||
r_len = cbuf_read(&uac_speaker->cbuf, data, r_len);
|
||||
if (!r_len) {
|
||||
putchar('U');
|
||||
}
|
||||
}
|
||||
|
||||
if (r_len == 0) {
|
||||
uac_speaker->need_resume = 1;
|
||||
}
|
||||
local_irq_enable();
|
||||
return r_len;
|
||||
}
|
||||
|
||||
void uac_speaker_stream_open(u32 samplerate, u32 ch)
|
||||
{
|
||||
if (speaker_stream_is_open) {
|
||||
return;
|
||||
}
|
||||
log_info("%s", __func__);
|
||||
|
||||
if (!uac_speaker) {
|
||||
#if USB_MALLOC_ENABLE
|
||||
|
||||
uac_speaker = zalloc(sizeof(struct uac_speaker_handle));
|
||||
if (!uac_speaker) {
|
||||
return;
|
||||
}
|
||||
|
||||
uac_speaker->buffer = malloc(UAC_BUFFER_SIZE);
|
||||
if (!uac_speaker->buffer) {
|
||||
free(uac_speaker);
|
||||
uac_speaker = NULL;
|
||||
goto __err;
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
uac_speaker = &uac_speaker_handle;
|
||||
|
||||
memset(uac_speaker, 0, sizeof(struct uac_speaker_handle));
|
||||
|
||||
uac_speaker->buffer = uac_rx_buffer;
|
||||
#endif
|
||||
uac_speaker->channel = ch;
|
||||
/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
|
||||
uac_speaker->audio_track = audio_local_sample_track_open(ch, samplerate, 1000);
|
||||
/* #endif */
|
||||
}
|
||||
|
||||
|
||||
//uac_speaker->rx_handler = NULL;
|
||||
|
||||
cbuf_init(&uac_speaker->cbuf, uac_speaker->buffer, UAC_BUFFER_SIZE);
|
||||
speaker_stream_is_open = 1;
|
||||
struct sys_event event;
|
||||
event.type = SYS_DEVICE_EVENT;
|
||||
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||||
event.u.dev.event = USB_AUDIO_PLAY_OPEN;
|
||||
event.u.dev.value = (int)((ch << 24) | samplerate);
|
||||
|
||||
#if !UAC_DEBUG_ECHO_MODE
|
||||
sys_event_notify(&event);
|
||||
#endif
|
||||
|
||||
return;
|
||||
|
||||
__err:
|
||||
return;
|
||||
}
|
||||
|
||||
void uac_speaker_stream_close()
|
||||
{
|
||||
if (speaker_stream_is_open == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
log_info("%s", __func__);
|
||||
speaker_stream_is_open = 0;
|
||||
|
||||
if (uac_speaker) {
|
||||
/* #ifdef CONFIG_MEDIA_DEVELOP_ENABLE */
|
||||
audio_local_sample_track_close(uac_speaker->audio_track);
|
||||
/* #endif */
|
||||
uac_speaker->audio_track = NULL;
|
||||
#if USB_MALLOC_ENABLE
|
||||
if (uac_speaker->buffer) {
|
||||
free(uac_speaker->buffer);
|
||||
}
|
||||
free(uac_speaker);
|
||||
#endif
|
||||
uac_speaker = NULL;
|
||||
}
|
||||
struct sys_event event;
|
||||
event.type = SYS_DEVICE_EVENT;
|
||||
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||||
event.u.dev.event = USB_AUDIO_PLAY_CLOSE;
|
||||
event.u.dev.value = (int)0;
|
||||
|
||||
#if !UAC_DEBUG_ECHO_MODE
|
||||
sys_event_notify(&event);
|
||||
#endif
|
||||
}
|
||||
|
||||
int uac_get_spk_vol()
|
||||
{
|
||||
int max_vol = get_max_sys_vol();
|
||||
int vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
|
||||
if (vol * 100 / max_vol < 100) {
|
||||
return vol * 100 / max_vol;
|
||||
} else {
|
||||
return 99;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static u8 flag_uac_event_enable = 1;
|
||||
void set_uac_event_flag(u8 en)
|
||||
{
|
||||
flag_uac_event_enable = en;
|
||||
}
|
||||
u8 get_uac_event_flag(void)
|
||||
{
|
||||
return flag_uac_event_enable;
|
||||
}
|
||||
static volatile u32 mic_stream_is_open;
|
||||
|
||||
u8 uac_get_mic_stream_status(void)
|
||||
{
|
||||
return mic_stream_is_open;
|
||||
}
|
||||
|
||||
void uac_mute_volume(u32 type, u32 l_vol, u32 r_vol)
|
||||
{
|
||||
struct sys_event event;
|
||||
event.type = SYS_DEVICE_EVENT;
|
||||
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||||
|
||||
static u32 last_spk_l_vol = (u32) - 1, last_spk_r_vol = (u32) - 1;
|
||||
static u32 last_mic_vol = (u32) - 1;
|
||||
|
||||
if (!get_uac_event_flag()) {
|
||||
return;
|
||||
}
|
||||
switch (type) {
|
||||
case MIC_FEATURE_UNIT_ID: //MIC
|
||||
if (mic_stream_is_open == 0) {
|
||||
return ;
|
||||
}
|
||||
if (l_vol == last_mic_vol) {
|
||||
return;
|
||||
}
|
||||
last_mic_vol = l_vol;
|
||||
event.u.dev.event = USB_AUDIO_SET_MIC_VOL;
|
||||
break;
|
||||
case SPK_FEATURE_UNIT_ID: //SPK
|
||||
if (speaker_stream_is_open == 0) {
|
||||
return;
|
||||
}
|
||||
if (l_vol == last_spk_l_vol && r_vol == last_spk_r_vol) {
|
||||
return;
|
||||
}
|
||||
last_spk_l_vol = l_vol;
|
||||
last_spk_r_vol = r_vol;
|
||||
event.u.dev.event = USB_AUDIO_SET_PLAY_VOL;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
event.u.dev.value = (int)(r_vol << 16 | l_vol);
|
||||
#if !UAC_DEBUG_ECHO_MODE
|
||||
sys_event_notify(&event);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
static int (*mic_tx_handler)(int, void *, int) = NULL;
|
||||
int uac_mic_stream_read(u8 *buf, u32 len)
|
||||
{
|
||||
if (mic_stream_is_open == 0) {
|
||||
return 0;
|
||||
}
|
||||
#if 0//48K 1ksin
|
||||
const s16 sin_48k[] = {
|
||||
0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
|
||||
14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
|
||||
14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
|
||||
0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
|
||||
-14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
|
||||
-14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
|
||||
};
|
||||
u16 *l_ch = (u16 *)buf;
|
||||
u16 *r_ch = (u16 *)buf;
|
||||
r_ch++;
|
||||
for (int i = 0; i < len / 2; i++) {
|
||||
*l_ch = sin_48k[i];
|
||||
*r_ch = sin_48k[i];
|
||||
l_ch += 1;
|
||||
r_ch += 1;
|
||||
}
|
||||
return len;
|
||||
#elif UAC_DEBUG_ECHO_MODE
|
||||
#if MIC_CHANNEL == 2
|
||||
uac_speaker_read(NULL, buf, len);
|
||||
const s16 sin_48k[] = {
|
||||
0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
|
||||
14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
|
||||
14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
|
||||
0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
|
||||
-14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
|
||||
-14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
|
||||
};
|
||||
u16 *r_ch = (u16 *)buf;
|
||||
r_ch++;
|
||||
for (int i = 0; i < len / 4; i++) {
|
||||
*r_ch = sin_48k[i];
|
||||
r_ch += 2;
|
||||
}
|
||||
#else
|
||||
uac_speaker_read(NULL, buf, len * 2);
|
||||
u16 *r_ch = (u16 *)buf;
|
||||
for (int i = 0; i < len / 2; i++) {
|
||||
r_ch[i] = r_ch[i * 2];
|
||||
}
|
||||
|
||||
#endif
|
||||
return len;
|
||||
#else
|
||||
if (mic_tx_handler) {
|
||||
#if 1
|
||||
return mic_tx_handler(0, buf, len);
|
||||
#else
|
||||
//16bit ---> 24bit
|
||||
int rlen = mic_tx_handler(0, tmp_buf, len / 3 * 2);
|
||||
rlen /= 2; //sampe point
|
||||
for (int i = 0 ; i < rlen ; i++) {
|
||||
buf[i * 3] = 0;
|
||||
buf[i * 3 + 1] = tmp_buf[i * 2];
|
||||
buf[i * 3 + 2] = tmp_buf[i * 2 + 1];
|
||||
}
|
||||
#endif
|
||||
} else {
|
||||
//putchar('N');
|
||||
}
|
||||
return 0;
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
void set_uac_mic_tx_handler(void *priv, int (*tx_handler)(int, void *, int))
|
||||
{
|
||||
mic_tx_handler = tx_handler;
|
||||
}
|
||||
static u32 mic_close_tid = 0;
|
||||
static u8 mic_sw;
|
||||
u32 uac_mic_stream_open(u32 samplerate, u32 frame_len, u32 ch)
|
||||
{
|
||||
mic_sw = 1;
|
||||
if (mic_stream_is_open) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* mic_tx_handler = NULL; */
|
||||
log_info("%s", __func__);
|
||||
|
||||
struct sys_event event;
|
||||
event.type = SYS_DEVICE_EVENT;
|
||||
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||||
event.u.dev.event = USB_AUDIO_MIC_OPEN;
|
||||
event.u.dev.value = (int)((ch << 24) | samplerate);
|
||||
mic_stream_is_open = 1;
|
||||
|
||||
#if !UAC_DEBUG_ECHO_MODE
|
||||
sys_event_notify(&event);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void uac_mic_stream_close_delay()
|
||||
{
|
||||
mic_close_tid = 0;
|
||||
if (!mic_sw) {
|
||||
|
||||
} else {
|
||||
return ;
|
||||
}
|
||||
log_info("%s", __func__);
|
||||
struct sys_event event;
|
||||
event.type = SYS_DEVICE_EVENT;
|
||||
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||||
event.u.dev.event = USB_AUDIO_MIC_CLOSE;
|
||||
event.u.dev.value = (int)0;
|
||||
mic_stream_is_open = 0;
|
||||
|
||||
#if !UAC_DEBUG_ECHO_MODE
|
||||
sys_event_notify(&event);
|
||||
#endif
|
||||
}
|
||||
void uac_mic_stream_close()
|
||||
{
|
||||
mic_sw = 0;
|
||||
if (mic_stream_is_open == 0) {
|
||||
return ;
|
||||
}
|
||||
//FIXME:
|
||||
//未知原因出现频繁开关mic,导致出现audio或者蓝牙工作异常,
|
||||
//收到mic关闭命令后延时1s再发消息通知audio模块执行关闭动作
|
||||
//如果在1s之内继续收到usb下发的关闭命令,则继续推迟1s。
|
||||
if (mic_close_tid == 0) {
|
||||
mic_close_tid = sys_hi_timeout_add(NULL, uac_mic_stream_close_delay, 1000);
|
||||
} else {
|
||||
sys_hi_timeout_modify(mic_close_tid, 1000);
|
||||
}
|
||||
}
|
||||
|
||||
_WEAK_
|
||||
s8 app_audio_get_volume(u8 state)
|
||||
{
|
||||
return 88;
|
||||
}
|
||||
_WEAK_
|
||||
void usb_audio_demo_exit(void)
|
||||
{
|
||||
|
||||
}
|
||||
_WEAK_
|
||||
int usb_audio_demo_init(void)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
_WEAK_
|
||||
u8 get_max_sys_vol(void)
|
||||
{
|
||||
return 100;
|
||||
}
|
||||
_WEAK_
|
||||
void *audio_local_sample_track_open(u8 channel, int sample_rate, int period)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
_WEAK_
|
||||
int audio_local_sample_track_in_period(void *c, int samples)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
_WEAK_
|
||||
void audio_local_sample_track_close(void *c)
|
||||
{
|
||||
}
|
||||
#endif
|
||||
31
apps/common/device/usb/device/uac_stream.h
Normal file
31
apps/common/device/usb/device/uac_stream.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*****************************************************************
|
||||
>file name : usb_audio.h
|
||||
>author : lichao
|
||||
>create time : Wed 22 May 2019 10:39:35 AM CST
|
||||
*****************************************************************/
|
||||
#ifndef _UAC_STREAM_H_
|
||||
#define _UAC_STREAM_H_
|
||||
#include "typedef.h"
|
||||
|
||||
enum uac_event {
|
||||
USB_AUDIO_PLAY_OPEN = 0x0,
|
||||
USB_AUDIO_PLAY_CLOSE,
|
||||
USB_AUDIO_MIC_OPEN,
|
||||
USB_AUDIO_MIC_CLOSE,
|
||||
// USB_AUDIO_MUTE,
|
||||
USB_AUDIO_SET_PLAY_VOL,
|
||||
USB_AUDIO_SET_MIC_VOL,
|
||||
};
|
||||
|
||||
|
||||
void uac_speaker_stream_buf_clear(void);
|
||||
u32 uac_speaker_stream_length();
|
||||
u32 uac_speaker_stream_size();
|
||||
void set_uac_speaker_rx_handler(void *priv, void (*rx_handler)(int, void *, int));
|
||||
void set_uac_mic_tx_handler(void *priv, int (*tx_handler)(int, void *, int));
|
||||
int uac_speaker_stream_sample_rate(void);
|
||||
|
||||
int uac_speaker_read(void *priv, void *data, u32 len);
|
||||
u32 uac_speaker_get_alive();
|
||||
void uac_speaker_set_alive(u8 alive);
|
||||
#endif
|
||||
258
apps/common/device/usb/device/usb_device.c
Normal file
258
apps/common/device/usb/device/usb_device.c
Normal file
@ -0,0 +1,258 @@
|
||||
#include "usb/device/usb_stack.h"
|
||||
#include "usb_config.h"
|
||||
#include "usb/device/msd.h"
|
||||
#include "usb/scsi.h"
|
||||
#include "usb/device/hid.h"
|
||||
#include "usb/device/uac_audio.h"
|
||||
#include "usb/device/cdc.h"
|
||||
#include "irq.h"
|
||||
#include "init.h"
|
||||
#include "gpio.h"
|
||||
#include "app_config.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 TCFG_USB_SLAVE_ENABLE
|
||||
|
||||
static void usb_device_init(const usb_dev usb_id)
|
||||
{
|
||||
|
||||
usb_config(usb_id);
|
||||
usb_g_sie_init(usb_id);
|
||||
#if defined(FUSB_MODE) && FUSB_MODE
|
||||
usb_write_power(usb_id, 0x40);
|
||||
#elif defined(FUSB_MODE) && (FUSB_MODE == 0)
|
||||
usb_write_power(usb_id, 0x60);
|
||||
#endif
|
||||
usb_slave_init(usb_id);
|
||||
u8 *ep0_dma_buffer = usb_alloc_ep_dmabuffer(usb_id, 0, 64);
|
||||
|
||||
usb_set_dma_raddr(usb_id, 0, ep0_dma_buffer);
|
||||
usb_set_dma_raddr(usb_id, 1, ep0_dma_buffer);
|
||||
usb_set_dma_raddr(usb_id, 2, ep0_dma_buffer);
|
||||
usb_set_dma_raddr(usb_id, 3, ep0_dma_buffer);
|
||||
usb_set_dma_raddr(usb_id, 4, ep0_dma_buffer);
|
||||
|
||||
usb_write_intr_usbe(usb_id, INTRUSB_RESET_BABBLE | INTRUSB_SUSPEND);
|
||||
usb_clr_intr_txe(usb_id, -1);
|
||||
usb_clr_intr_rxe(usb_id, -1);
|
||||
usb_set_intr_txe(usb_id, 0);
|
||||
usb_set_intr_rxe(usb_id, 0);
|
||||
usb_g_isr_reg(usb_id, 3, 0);
|
||||
/* usb_sof_isr_reg(usb_id,3,0); */
|
||||
/* usb_sofie_enable(usb_id); */
|
||||
/* USB_DEBUG_PRINTF("ep0 addr %x %x\n", usb_get_dma_taddr(0), ep0_dma_buffer); */
|
||||
}
|
||||
static void usb_device_hold(const usb_dev usb_id)
|
||||
{
|
||||
|
||||
usb_g_hold(usb_id);
|
||||
usb_release(usb_id);
|
||||
}
|
||||
|
||||
|
||||
static int usb_ep_conflict_check(const usb_dev usb_id);
|
||||
int usb_device_mode(const usb_dev usb_id, const u32 class)
|
||||
{
|
||||
|
||||
/* usb_device_set_class(CLASS_CONFIG); */
|
||||
u8 class_index = 0;
|
||||
if (class == 0) {
|
||||
gpio_direction_input(IO_PORT_DM + 2 * usb_id);
|
||||
gpio_set_pull_up(IO_PORT_DM + 2 * usb_id, 0);
|
||||
gpio_set_pull_down(IO_PORT_DM + 2 * usb_id, 0);
|
||||
gpio_set_die(IO_PORT_DM + 2 * usb_id, 0);
|
||||
|
||||
gpio_direction_input(IO_PORT_DP + 2 * usb_id);
|
||||
gpio_set_pull_up(IO_PORT_DP + 2 * usb_id, 0);
|
||||
gpio_set_pull_down(IO_PORT_DP + 2 * usb_id, 0);
|
||||
gpio_set_die(IO_PORT_DP + 2 * usb_id, 0);
|
||||
|
||||
os_time_dly(15);
|
||||
|
||||
gpio_set_die(IO_PORT_DM + 2 * usb_id, 1);
|
||||
gpio_set_die(IO_PORT_DP + 2 * usb_id, 1);
|
||||
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
msd_release(usb_id);
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
uac_release(usb_id);
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
cdc_release(usb_id);
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
hid_release(usb_id);
|
||||
#endif
|
||||
usb_device_hold(usb_id);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* int ret = usb_ep_conflict_check(usb_id); */
|
||||
/* if (ret) { */
|
||||
/* return ret; */
|
||||
/* } */
|
||||
|
||||
usb_memory_init();
|
||||
|
||||
usb_add_desc_config(usb_id, MAX_INTERFACE_NUM, NULL);
|
||||
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
if ((class & MASSSTORAGE_CLASS) == MASSSTORAGE_CLASS) {
|
||||
log_info("add desc msd");
|
||||
usb_add_desc_config(usb_id, class_index++, msd_desc_config);
|
||||
msd_register(usb_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
if ((class & AUDIO_CLASS) == AUDIO_CLASS) {
|
||||
log_info("add audio desc");
|
||||
usb_add_desc_config(usb_id, class_index++, uac_audio_desc_config);
|
||||
uac_register(usb_id, AUDIO_CLASS);
|
||||
} else if ((class & SPEAKER_CLASS) == SPEAKER_CLASS) {
|
||||
log_info("add desc speaker");
|
||||
usb_add_desc_config(usb_id, class_index++, uac_spk_desc_config);
|
||||
uac_register(usb_id, SPEAKER_CLASS);
|
||||
} else if ((class & MIC_CLASS) == MIC_CLASS) {
|
||||
log_info("add desc mic");
|
||||
usb_add_desc_config(usb_id, class_index++, uac_mic_desc_config);
|
||||
uac_register(usb_id, MIC_CLASS);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
if ((class & HID_CLASS) == HID_CLASS) {
|
||||
log_info("add desc std hid");
|
||||
usb_add_desc_config(usb_id, class_index++, hid_desc_config);
|
||||
hid_register(usb_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
if ((class & CDC_CLASS) == CDC_CLASS) {
|
||||
log_info("add desc cdc");
|
||||
usb_add_desc_config(usb_id, class_index++, cdc_desc_config);
|
||||
cdc_register(usb_id);
|
||||
}
|
||||
#endif
|
||||
|
||||
usb_device_init(usb_id);
|
||||
user_setup_filter_install(usb_id2device(usb_id));
|
||||
return 0;
|
||||
}
|
||||
/* module_initcall(usb_device_mode); */
|
||||
|
||||
static int usb_ep_conflict_check(const usb_dev usb_id)
|
||||
{
|
||||
u8 usb_ep_tx_list[] = {
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
MSD_BULK_EP_IN,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
HID_EP_IN,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
MIC_ISO_EP_IN,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
CDC_DATA_EP_IN,
|
||||
#if CDC_INTR_EP_ENABLE
|
||||
CDC_INTR_EP_IN,
|
||||
#endif
|
||||
#endif
|
||||
};
|
||||
u8 usb_ep_rx_list[] = {
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
MSD_BULK_EP_OUT,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
HID_EP_OUT,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
SPK_ISO_EP_OUT,
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_CDC_ENABLE
|
||||
CDC_DATA_EP_OUT,
|
||||
#endif
|
||||
};
|
||||
int ret = 0;
|
||||
int i, j;
|
||||
|
||||
for (i = 0; i < sizeof(usb_ep_tx_list) - 1; i++) {
|
||||
for (j = i + 1; j < sizeof(usb_ep_tx_list); j++) {
|
||||
if (usb_ep_tx_list[i] == usb_ep_tx_list[j]) {
|
||||
ret = -1;
|
||||
ASSERT(0, "ep%d conflict, dir in\n", usb_ep_tx_list[i]);
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (i = 0; i < sizeof(usb_ep_rx_list) - 1; i++) {
|
||||
for (j = i + 1; j < sizeof(usb_ep_rx_list); j++) {
|
||||
if (usb_ep_rx_list[i] == usb_ep_rx_list[j]) {
|
||||
ret = -1;
|
||||
ASSERT(0, "ep%d conflict, dir out\n", usb_ep_rx_list[i]);
|
||||
goto __exit;
|
||||
}
|
||||
}
|
||||
}
|
||||
__exit:
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* @brief otg检测中sof初始化,不要放在TCFG_USB_SLAVE_ENABLE里
|
||||
* @parm id usb设备号
|
||||
* @return 0 ,忽略sof检查,1 等待sof信号
|
||||
*/
|
||||
u32 usb_otg_sof_check_init(const usb_dev id)
|
||||
{
|
||||
/* return 0;// */
|
||||
u8 *ep0_dma_buffer = usb_alloc_ep_dmabuffer(id, 0, 64);
|
||||
|
||||
usb_g_sie_init(id);
|
||||
|
||||
#ifdef USB_HW_20
|
||||
//husb调用完usb_g_sie_init(),或者收到usb reset中断,intrusbe,intrtxe,
|
||||
//intrrxe会复位成默认值,不手动清零以及关中断,会收到usb reset中断,由于
|
||||
//空指针问题导致异常
|
||||
usb_write_intr_usbe(id, 0);
|
||||
usb_clr_intr_txe(id, -1);
|
||||
usb_clr_intr_rxe(id, -1);
|
||||
if (id == 0) {
|
||||
unrequest_irq(IRQ_USB_CTRL_IDX);
|
||||
#if USB_MAX_HW_NUM > 1
|
||||
} else {
|
||||
unrequest_irq(IRQ_USB1_CTRL_IDX);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(FUSB_MODE) && FUSB_MODE
|
||||
usb_write_power(id, 0x40);
|
||||
#elif defined(FUSB_MODE) && (FUSB_MODE == 0)
|
||||
usb_write_power(id, 0x60);
|
||||
#endif
|
||||
|
||||
usb_set_dma_raddr(id, 0, ep0_dma_buffer);
|
||||
|
||||
for (int ep = 1; ep < USB_MAX_HW_EPNUM; ep++) {
|
||||
usb_disable_ep(id, ep);
|
||||
}
|
||||
usb_sof_clr_pnd(id);
|
||||
return 1;
|
||||
}
|
||||
223
apps/common/device/usb/device/user_setup.c
Normal file
223
apps/common/device/usb/device/user_setup.c
Normal file
@ -0,0 +1,223 @@
|
||||
#include "usb/device/usb_stack.h"
|
||||
#include "usb_config.h"
|
||||
#include "usb/device/msd.h"
|
||||
#include "usb/scsi.h"
|
||||
#include "usb/device/hid.h"
|
||||
#include "usb/device/uac_audio.h"
|
||||
#include "irq.h"
|
||||
#include "init.h"
|
||||
#include "gpio.h"
|
||||
#include "app_config.h"
|
||||
|
||||
#if TCFG_USB_APPLE_DOCK_EN
|
||||
#include "apple_dock/iAP.h"
|
||||
#endif
|
||||
|
||||
#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 TCFG_USB_SLAVE_ENABLE
|
||||
|
||||
static const u8 user_stirng[] = {
|
||||
24,
|
||||
0x03,
|
||||
'U', 0x00,
|
||||
'S', 0x00,
|
||||
'B', 0x00,
|
||||
'A', 0x00,
|
||||
'u', 0x00,
|
||||
'd', 0x00,
|
||||
'i', 0x00,
|
||||
'o', 0x00,
|
||||
'1', 0x00,
|
||||
'.', 0x00,
|
||||
'0', 0x00,
|
||||
};
|
||||
|
||||
#if TCFG_USB_APPLE_DOCK_EN
|
||||
static const u8 IAP_interface_string[] = {
|
||||
0x1c, 0x03,
|
||||
//iAP Interface
|
||||
0x69, 0x00, 0x41, 0x00, 0x50, 0x00, 0x20, 0x00, 0x49, 0x00, 0x6e, 0x00, 0x74, 0x00,
|
||||
0x65, 0x00, 0x72, 0x00, 0x66, 0x00, 0x61, 0x00, 0x63, 0x00, 0x65, 0x00
|
||||
};
|
||||
#endif
|
||||
|
||||
static u8 root2_testing;
|
||||
u32 usb_root2_testing()
|
||||
{
|
||||
#if USB_ROOT2
|
||||
return root2_testing;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
u32 check_ep_vaild(u32 ep)
|
||||
{
|
||||
u32 en = 0;
|
||||
switch (ep) {
|
||||
case 0:
|
||||
en = 1;
|
||||
break;
|
||||
#if TCFG_USB_SLAVE_MSD_ENABLE
|
||||
case 1:
|
||||
en = 1;
|
||||
break;
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_HID_ENABLE
|
||||
case 2:
|
||||
en = 1;
|
||||
break;
|
||||
#endif
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
case 3:
|
||||
en = 1;
|
||||
break;
|
||||
#endif
|
||||
case 4:
|
||||
break;
|
||||
}
|
||||
return en;
|
||||
}
|
||||
static u32 setup_endpoint(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u32 tx_len = 0;
|
||||
u8 *tx_payload = usb_get_setup_buffer(usb_device);
|
||||
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
if (uac_setup_endpoint(usb_device, req)) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
u32 ep = LOBYTE(req->wIndex) & 0x0f;
|
||||
if (check_ep_vaild(ep) == 0) {
|
||||
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
|
||||
return 1;// not zero user handle this request
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
static u32 setup_device(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
|
||||
{
|
||||
const usb_dev usb_id = usb_device2id(usb_device);
|
||||
u32 ret = 0;
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_GET_DESCRIPTOR:
|
||||
switch (HIBYTE(req->wValue)) {
|
||||
case USB_DT_STRING:
|
||||
switch (LOBYTE(req->wValue)) {
|
||||
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||||
case SPEAKER_STR_INDEX:
|
||||
case MIC_STR_INDEX:
|
||||
if (usb_device->bDeviceStates == USB_DEFAULT) {
|
||||
ret = 0;
|
||||
} else {
|
||||
usb_set_data_payload(usb_device, req, user_stirng, sizeof(user_stirng));
|
||||
ret = 1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
#if TCFG_USB_APPLE_DOCK_EN
|
||||
case MSD_STR_INDEX:
|
||||
if (apple_mfi_chip_online_lib()) {
|
||||
y_printf("MSD_STR_INDEX \n");
|
||||
usb_set_data_payload(usb_device, req, IAP_interface_string, sizeof(IAP_interface_string));
|
||||
apple_mfi_pass_ready_set_api();
|
||||
extern void apple_usb_msd_wakeup(struct usb_device_t *usb_device);
|
||||
apple_usb_msd_wakeup(usb_device);
|
||||
ret = 1;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case USB_DT_DEVICE:
|
||||
#if USB_ROOT2
|
||||
if (req->wLength == 0xffff) {
|
||||
root2_testing = 1;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case USB_REQ_SET_CONFIGURATION:
|
||||
break;
|
||||
case USB_REQ_SET_ADDRESS:
|
||||
/* if(req->wLength || req->wIndex){ */
|
||||
/* ret = 1; */
|
||||
/* usb_set_setup_phase(usb_device, USB_EP0_SET_STALL); */
|
||||
/* dump_setup_request(req); */
|
||||
/* log_debug_hexdump((u8 *)req, 8); */
|
||||
/* } */
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static u32 setup_other(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
|
||||
{
|
||||
u32 ret = 0;
|
||||
u32 tx_len;
|
||||
u8 *tx_payload = usb_get_setup_buffer(usb_device);
|
||||
switch (req->bRequest) {
|
||||
case USB_REQ_GET_STATUS:
|
||||
#if TCFG_TYPEC_EARPHONE_TEST_FILTER
|
||||
tx_len = 1;
|
||||
tx_payload[0] = 0xfe;
|
||||
usb_set_data_payload(usb_device, req, tx_payload, tx_len);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
ret = 1 ;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
static u32 user_setup_filter(struct usb_device_t *usb_device, struct usb_ctrlrequest *request)
|
||||
{
|
||||
// dump_setup_request(request);
|
||||
// log_debug_hexdump((u8 *)request, 8);
|
||||
u32 ret = 0;
|
||||
u32 recip = request->bRequestType & USB_RECIP_MASK;
|
||||
switch (recip) {
|
||||
case USB_RECIP_DEVICE:
|
||||
ret = setup_device(usb_device, request);
|
||||
break;
|
||||
case USB_RECIP_INTERFACE:
|
||||
break;
|
||||
case USB_RECIP_ENDPOINT:
|
||||
ret = setup_endpoint(usb_device, request);
|
||||
break;
|
||||
case USB_RECIP_OTHER:
|
||||
ret = setup_other(usb_device, request);
|
||||
break;
|
||||
}
|
||||
#if 0
|
||||
const char *statas[] = {"USB_ATTACHED", "USB_POWERED", "USB_DEFAULT",
|
||||
"USB_ADDRESS", "USB_CONFIGURED", "USB_SUSPENDED"
|
||||
};
|
||||
|
||||
const char *phases[] = {"SETUP", "IN", "OUT",
|
||||
"STALL",
|
||||
};
|
||||
|
||||
printf("state:%s phase: %s", statas[usb_device->bDeviceStates],
|
||||
phases[usb_device->bsetup_phase]);
|
||||
#endif
|
||||
return ret;// not zero user handle this request
|
||||
}
|
||||
void user_setup_filter_install(struct usb_device_t *usb_device)
|
||||
{
|
||||
usb_set_setup_hook(usb_device, user_setup_filter);
|
||||
}
|
||||
#endif
|
||||
Reference in New Issue
Block a user