This commit is contained in:
huxi
2025-12-03 11:12:34 +08:00
parent c23ae4f24c
commit bc195654bf
8163 changed files with 3799544 additions and 92 deletions
+557
View File
@@ -0,0 +1,557 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#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];
u8 comm_feature[2];
};
static struct usb_cdc_gadget *cdc_hdl;
#if USB_MALLOC_ENABLE
#else
static u8 _cdc_buffer[MAXP_SIZE_CDC_BULKOUT] SEC(.usb.data.bss.exchange) __attribute__((aligned(4)));
static struct usb_cdc_gadget _cdc_hdl SEC(.usb.data.bss.exchange);
#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
0x03, //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_info("dtw rate : %d", lc->dwDTERate);
log_info("stop bits : %d", lc->bCharFormat);
log_info("verify bits : %d", lc->bParityType);
log_info("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_SEND_ENCAPSULATED_COMMAND:
usb_set_setup_recv(usb_device, cdc_setup_rx);
break;
case USB_CDC_GET_ENCAPSULATED_RESPONSE:
//Not need to transfer ITU-T V250 AT command,
//just sample for this command
memset(usb_get_setup_buffer(usb_device), 0, ctrl_req->wLength);
usb_set_data_payload(usb_device, ctrl_req, usb_get_setup_buffer(usb_device), ctrl_req->wLength);
break;
case 0x02: //Set_Comm_Feature
usb_set_setup_recv(usb_device, cdc_setup_rx);
break;
case 0x03: //Clear_Comm_Feature
if (ctrl_req->wValue == 0x01) { //ABSTRACT_STATE
cdc_hdl->comm_feature[0] = 0;
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
}
break;
case 0x04: //Get_Comm_Feature
if (ctrl_req->wValue == 0x01) { //ABSTRACT_STATE
usb_set_data_payload(usb_device, ctrl_req, cdc_hdl->comm_feature, ctrl_req->wLength);
}
break;
case USB_CDC_REQ_SET_LINE_CODING:
log_info("set line coding");
usb_set_setup_recv(usb_device, cdc_setup_rx);
break;
case USB_CDC_REQ_GET_LINE_CODING:
log_info("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_info("set control line state - %d", ctrl_req->wValue);
if (cdc_hdl) {
/* if (ctrl_req->wValue & BIT(0)) { //DTR */
cdc_hdl->bmTransceiver |= BIT(0);
/* } else { */
/* cdc_hdl->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 = usb_get_setup_buffer(usb_device);
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_SEND_ENCAPSULATED_COMMAND:
log_info("USB_CDC_SEND_ENCAPSULATED_COMMAND");
log_debug_hexdump(read_ep, len);
break;
case 0x02: //Set_Comm_Feature
log_info("USB_CDC_REQ_SET_COMM_FEATURE");
if (cdc_hdl == NULL) {
break;
}
memcpy(cdc_hdl->comm_feature, read_ep, len);
log_debug_hexdump(read_ep, len);
break;
case USB_CDC_REQ_SET_LINE_CODING:
log_info("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_debug("%s", __func__);
//cppcheck-suppress unreadVariable
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)
{
//cppcheck-suppress unreadVariable
struct usb_device_t *usb_device = usb_id2device(usb_id);
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;
tptr[8 + 9 + 5 + 5 + 4 + 5 + 6] = CDC_INTR_INTERVAL;
#if defined(FUSB_MODE) && FUSB_MODE == 0
if (usb_device->bSpeed == USB_SPEED_FULL) {
tptr[8 + 9 + 5 + 5 + 4 + 5 + 6] = CDC_INTR_INTERVAL_FS; //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;
}
if (!(cdc_hdl->bmTransceiver & BIT(0))) {
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);
cdc_hdl->bulk_ep_out_buffer = usb_alloc_ep_dmabuffer(usb_id, CDC_DATA_EP_OUT, MAXP_SIZE_CDC_BULKOUT * 2);
#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 (cdc_hdl->bulk_ep_in_buffer) {
usb_free_ep_dmabuffer(usb_id, cdc_hdl->bulk_ep_in_buffer);
cdc_hdl->bulk_ep_in_buffer = NULL;
}
if (cdc_hdl->bulk_ep_out_buffer) {
usb_free_ep_dmabuffer(usb_id, cdc_hdl->bulk_ep_out_buffer);
cdc_hdl->bulk_ep_out_buffer = NULL;
}
#if CDC_INTR_EP_ENABLE
if (cdc_hdl->intr_ep_in_buffer) {
usb_free_ep_dmabuffer(usb_id, cdc_hdl->intr_ep_in_buffer);
cdc_hdl->intr_ep_in_buffer = NULL;
}
#endif
#if USB_MALLOC_ENABLE
free(cdc_hdl->cdc_buffer);
free(cdc_hdl);
#endif
cdc_hdl = NULL;
}
}
#endif
+23
View 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
@@ -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 */
@@ -0,0 +1,337 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "os/os_api.h"
#include "usb/device/usb_stack.h"
#include "usb/device/hid.h"
#include "usb_config.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_CUSTOM_HID_ENABLE
typedef void (*hid_rx_handle_t)(void *hdl, u8 *buffer, u32 len);
struct custom_hid_hdl {
u8 cfg_done;
void *priv_hdl;
hid_rx_handle_t hid_rx_hook;
};
static struct custom_hid_hdl *custom_hid_info;
#if USB_MALLOC_ENABLE
#else
static struct custom_hid_hdl _custom_hid_info;
#endif
static const u8 sHIDDescriptor[] = {
//HID
//InterfaceDeszcriptor:
USB_DT_INTERFACE_SIZE, // Length
USB_DT_INTERFACE, // DescriptorType
0x00, // bInterface number
0x00, // AlternateSetting
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
0x01, 0x02, // 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, 0, // wDescriptorLength
//EndpointDescriptor:
USB_DT_ENDPOINT_SIZE, // bLength
USB_DT_ENDPOINT, // bDescriptorType, Type
USB_DIR_IN | CUSTOM_HID_EP_IN, // bEndpointAddress
USB_ENDPOINT_XFER_INT, // Interrupt
LOBYTE(MAXP_SIZE_CUSTOM_HIDIN), HIBYTE(MAXP_SIZE_CUSTOM_HIDIN),// Maximum packet size
CUSTOM_HID_INTERVAL, // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms
//Endpoint Descriptor:
USB_DT_ENDPOINT_SIZE, // bLength
USB_DT_ENDPOINT, // bDescriptorType, Type
CUSTOM_HID_EP_OUT, // bEndpointAddress
USB_ENDPOINT_XFER_INT, // Interrupt
LOBYTE(MAXP_SIZE_CUSTOM_HIDOUT), HIBYTE(MAXP_SIZE_CUSTOM_HIDOUT),// Maximum packet size
CUSTOM_HID_INTERVAL, // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms
};
static const u8 sHIDReportDesc[] = {
USAGE_PAGE(2, 0x02, 0xff),
USAGE(1, 0x02),
COLLECTION(1, APPLICATION),
USAGE(1, 0x03),
LOGICAL_MIN(1, 0x00),
LOGICAL_MAX(2, 0xff, 0x00),
REPORT_SIZE(1, 8),
REPORT_COUNT(1, 0x40),
INPUT(1, 0x00),
USAGE(1, 0x04),
LOGICAL_MIN(1, 0x00),
LOGICAL_MAX(2, 0xff, 0x00),
REPORT_SIZE(1, 0x08),
REPORT_COUNT(1, 0X40),
OUTPUT(1, 0x00),
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;
}
u32 custom_hid_tx_data(const usb_dev usb_id, const u8 *buffer, u32 len)
{
if (len > MAXP_SIZE_CUSTOM_HIDIN) {
len = MAXP_SIZE_CUSTOM_HIDIN;
}
if (custom_hid_info == NULL || custom_hid_info->cfg_done == 0) {
return 0;
}
return usb_g_intr_write(usb_id, CUSTOM_HID_EP_IN, buffer, len);
}
static void custom_hid_rx_data(struct usb_device_t *usb_device, u32 ep)
{
const usb_dev usb_id = usb_device2id(usb_device);
u8 rx_buffer[64] = {0};
u32 rx_len = usb_g_intr_read(usb_id, CUSTOM_HID_EP_OUT, rx_buffer, 64, 0);
if (custom_hid_info && custom_hid_info->hid_rx_hook) {
custom_hid_info->hid_rx_hook(custom_hid_info->priv_hdl, rx_buffer, rx_len);
}
}
int custom_hid_get_ready(const usb_dev usb_id)
{
if (custom_hid_info && custom_hid_info->cfg_done) {
return 1;
}
return 0;
}
void custom_hid_set_rx_hook(void *priv, void (*rx_hook)(void *priv, u8 *buf, u32 len))
{
if (custom_hid_info) {
custom_hid_info->priv_hdl = priv;
custom_hid_info->hid_rx_hook = rx_hook;
}
}
static u8 *custom_hid_ep_in_dma;
static u8 *custom_hid_ep_out_dma;
static void custom_hid_endpoint_init(struct usb_device_t *usb_device, u32 itf)
{
const usb_dev usb_id = usb_device2id(usb_device);
//u8 *ep_buffer = usb_alloc_ep_dmabuffer(usb_id, CUSTOM_HID_EP_IN | USB_DIR_IN, MAXP_SIZE_CUSTOM_HIDIN);
usb_g_ep_config(usb_id, CUSTOM_HID_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_INT, 0, custom_hid_ep_in_dma, MAXP_SIZE_CUSTOM_HIDIN);
//ep_buffer = usb_alloc_ep_dmabuffer(usb_id, CUSTOM_HID_EP_OUT, MAXP_SIZE_CUSTOM_HIDOUT);
usb_g_set_intr_hander(usb_id, CUSTOM_HID_EP_OUT, custom_hid_rx_data);
usb_g_ep_config(usb_id, CUSTOM_HID_EP_OUT, USB_ENDPOINT_XFER_INT, 1, custom_hid_ep_out_dma, MAXP_SIZE_CUSTOM_HIDOUT);
usb_enable_ep(usb_id, CUSTOM_HID_EP_OUT);
}
static void custom_hid_reset(struct usb_device_t *usb_device, u32 itf)
{
//cppcheck-suppress unreadVariable
const usb_dev usb_id = usb_device2id(usb_device);
log_debug("%s", __func__);
#if USB_ROOT2
usb_disable_ep(usb_id, HID_EP_OUT);
#else
custom_hid_endpoint_init(usb_device, itf);
#endif
}
static u32 custom_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:
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;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}// USB_REQ_GET_DESCRIPTOR
break;
case USB_REQ_SET_DESCRIPTOR:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
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
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
break;
case USB_REQ_GET_INTERFACE:
if (req->wLength) {
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;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}//bRequest @ USB_TYPE_STANDARD
break;
case USB_TYPE_CLASS:
switch (req->bRequest) {
case USB_REQ_SET_IDLE:
/* custom_hid_endpoint_init(usb_device, LOBYTE(req->wIndex)); */
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
custom_hid_info->cfg_done = 1;
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_GET_REPORT:
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;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}//bRequest @ USB_TYPE_CLASS
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
return 0;
}
u32 custom_hid_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
{
//cppcheck-suppress unreadVariable
struct usb_device_t *usb_device = usb_id2device(usb_id);
log_debug("custom hid interface num:%d\n", *cur_itf_num);
memcpy(ptr, sHIDDescriptor, sizeof(sHIDDescriptor));
ptr[2] = *cur_itf_num;
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));
#if defined(FUSB_MODE) && FUSB_MODE == 0
if (usb_device->bSpeed == USB_SPEED_FULL) {
ptr[9 + 9 + 6] = CUSTOM_HID_INTERVAL_FS;
ptr[9 + 9 + 7 + 6] = CUSTOM_HID_INTERVAL_FS;
}
#endif
if (usb_set_interface_hander(usb_id, *cur_itf_num, custom_hid_itf_hander) != *cur_itf_num) {
ASSERT(0, "custom hid set interface_hander fail");
}
if (usb_set_reset_hander(usb_id, *cur_itf_num, custom_hid_reset) != *cur_itf_num) {
ASSERT(0, "custom hid set interface_reset_hander fail");
}
*cur_itf_num = *cur_itf_num + 1;
return sizeof(sHIDDescriptor);
}
u32 custom_hid_register(usb_dev usb_id)
{
if (custom_hid_info) {
return 0;
}
#if USB_MALLOC_ENABLE
custom_hid_info = malloc(sizeof(struct custom_hid_hdl));
if (!custom_hid_info) {
log_error("custom hid allocates memory fail 1\n");
return -1;
}
#else
custom_hid_info = &_custom_hid_info;
#endif
memset(custom_hid_info, 0, sizeof(struct custom_hid_hdl));
custom_hid_ep_in_dma = usb_alloc_ep_dmabuffer(usb_id, CUSTOM_HID_EP_IN | USB_DIR_IN, MAXP_SIZE_CUSTOM_HIDIN);
custom_hid_ep_out_dma = usb_alloc_ep_dmabuffer(usb_id, CUSTOM_HID_EP_OUT, MAXP_SIZE_CUSTOM_HIDOUT);
return 0;
}
void custom_hid_release()
{
if (custom_hid_info == NULL) {
return;
}
if (custom_hid_ep_in_dma) {
usb_free_ep_dmabuffer(0, custom_hid_ep_in_dma);
custom_hid_ep_in_dma = NULL;
}
if (custom_hid_ep_out_dma) {
usb_free_ep_dmabuffer(0, custom_hid_ep_out_dma);
custom_hid_ep_out_dma = NULL;
}
#if USB_MALLOC_ENABLE
free(custom_hid_info);
#else
memset(custom_hid_info, 0, sizeof(struct custom_hid_hdl));
#endif
custom_hid_info = NULL;
}
#endif
@@ -0,0 +1,237 @@
/**
* @file descriptor.c
* @brief overwrite usb device descriptor
* @version 1.00
* @date 2019-05-06
*/
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#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
0x54, 0x36, // idVendor: 0x3654 - Zhuhai Jieli Technology
'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
};
u8 __attribute__((weak))is_webusb_register()
{
return 0;
}
void get_device_descriptor(u8 *ptr)
{
memcpy(ptr, sDeviceDescriptor, USB_DT_DEVICE_SIZE);
#if TCFG_USB_WEBUSB_ENABLE
/* 0x10, 0x02, // bcdUSB: USB 2.1 */
if (is_webusb_register()) {
ptr[2] = 0x10;
ptr[3] = 0x02;
}
#endif
}
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 *tzflash_get_uuid(void);
u8 flash_id[16] = {0};
int i;
u8 bcd;
if (tzflash_get_uuid && tzflash_get_uuid()) {
ptr[0] = 0x22;
ptr[1] = 0x03;
memset(&ptr[2], 0, 0x20);
memcpy(flash_id, tzflash_get_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;
}
void get_device_info_to_ota(void *parm_priv)
{
u8 *tmp = parm_priv;
memcpy(tmp, &(sDeviceDescriptor[8]), 4);
tmp[8]++;
//cppcheck-suppress knownConditionTrueFalse
if (product_string[0] > 28) {
log_error("The product_string length is more than 28 Byte");
memcpy(&(parm_priv[4]), product_string, 28);
} else {
memcpy(&(parm_priv[4]), product_string, product_string[0]);
}
}
#endif
+355
View File
@@ -0,0 +1,355 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#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, // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms */
//@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, hid_ep_out_dma, 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 = usb_alloc_ep_dmabuffer(usb_id, HID_EP_OUT, MAXP_SIZE_HIDOUT); */
return 0;
}
void hid_release(const usb_dev usb_id)
{
if (hid_ep_in_dma) {
usb_free_ep_dmabuffer(usb_id, hid_ep_in_dma);
hid_ep_in_dma = NULL;
}
//if (hid_ep_out_dma) {
// usb_free_ep_dmabuffer(usb_id, hid_ep_out_dma);
// hid_ep_out_dma = NULL;
//}
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);
struct usb_device_t *usb_device = usb_id2device(usb_id);
u8 *_ptr = ptr;
memcpy(ptr, sHIDDescriptor, sizeof(sHIDDescriptor));
ptr[2] = *cur_itf_num;
#if defined(FUSB_MODE) && FUSB_MODE == 0
if (usb_device->bSpeed == USB_SPEED_FULL) {
ptr[9 + 9 + 6] = HID_INTR_INTERVAL_FS;
ptr[9 + 9 + 7 + 6] = HID_INTR_INTERVAL_FS;
}
#endif
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
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,93 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#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
usb_g_hold(0);
#if USB_MAX_HW_NUM > 1
usb_g_hold(1);
#endif
local_irq_disable();
ram_protect_close();
//TODO
//hw_mmu_disable();
nvram_set_boot_state(UPGRADE_USB_SOFT_KEY);
#if (defined CONFIG_CPU_BR52)
//JL_CLOCK->PWR_CON |= (1 << 4);
#else
/* JL_CLOCK->PWR_CON |= (1 << 4); */
#endif // end with #ifdef CONFIG_CPU_BR52
#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
@@ -0,0 +1,57 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "app_config.h"
#include "rcsp_hid_inter.h"
#include "usb/device/custom_hid.h"
static void (*rcsp_hid_recieve_callback)(void *priv, void *buf, u16 len) = NULL;
void rcsp_hid_recieve(void *priv, void *buf, u16 len)
{
if (rcsp_hid_recieve_callback) {
rcsp_hid_recieve_callback(priv, buf, len);
}
}
bool JL_rcsp_hid_fw_ready(void *priv)
{
return custom_hid_get_ready(0) ? true : false;
}
static int update_send_user_data_do(void *priv, void *data, u16 len)
{
//-------------------!!!!!!!!!!考虑关闭RCSP_BTMATE_EN使能编译报错
extern void dongle_send_data_to_pc_3(u8 * data, u16 len);
dongle_send_data_to_pc_3(data, len);
return 0;
}
static int update_regiest_recieve_cbk(void *priv, void *cbk)
{
printf("%s, %x\n", __func__, (u32)cbk);
rcsp_hid_recieve_callback = cbk;
return 0;
}
static int update_regiest_state_cbk(void *priv, void *cbk)
{
return 0;
}
static const struct rcsp_hid_operation_t rcsp_hid_update_operation = {
.send_data = update_send_user_data_do,
.regist_recieve_cbk = update_regiest_recieve_cbk,
.regist_state_cbk = update_regiest_state_cbk,
};
void rcsp_hid_get_operation_table(struct rcsp_hid_operation_t **interface_pt)
{
*interface_pt = (void *)&rcsp_hid_update_operation;
}
@@ -0,0 +1,17 @@
#ifndef _RCSP_HID_INTER_H_
#define _RCSP_HID_INTER_H_
#include "typedef.h"
struct rcsp_hid_operation_t {
int (*send_data)(void *priv, void *buf, u16 len);
int(*regist_recieve_cbk)(void *priv, void *cbk);
int(*regist_state_cbk)(void *priv, void *cbk);
};
bool JL_rcsp_hid_fw_ready(void *priv);
void rcsp_hid_get_operation_table(struct rcsp_hid_operation_t **interface_pt);
void rcsp_hid_recieve(void *priv, void *buf, u16 len);
#endif
+338
View File
@@ -0,0 +1,338 @@
/**
* @file task_pc.c
* @brief 从机模式
* @author chenrixin@zh-jieli.com
* @version 1.0.0
* @date 2020-02-29
*/
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "system/includes.h"
#include "app_config.h"
#include "app_action.h"
#include "os/os_api.h"
#include "device/sdmmc/sdmmc.h"
#include "app_charge.h"
#include "asm/charge.h"
#include "app_main.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"
#include "usb/usb_task.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
#include "cfg_tool_cdc.h"
#endif
#if TCFG_USB_CUSTOM_HID_ENABLE
#include "usb/device/custom_hid.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"
extern u8 msd_in_task;
extern u8 msd_run_reset;
#if TCFG_USB_SLAVE_MSD_ENABLE
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)
{
if (msd_in_task) {
msd_run_reset = 1;
} else {
msd_reset(usb_device, 0);
}
}
#endif
#if TCFG_USB_SLAVE_CDC_ENABLE
static void usb_cdc_wakeup(struct usb_device_t *usb_device)
{
//回调函数在中断里,正式使用不要在这里加太多东西阻塞中断,
//或者先post到任务,由任务调用cdc_read_data()读取再执行后续工作
#if TCFG_CFG_TOOL_ENABLE && (TCFG_COMM_TYPE == TCFG_USB_COMM)
int msg[1] = {0};
msg[0] = (u32)usb_device;
if (OS_NO_ERR != os_taskq_post_type("app_core", MSG_FROM_CDC_DATA, 1, msg)) {
log_error("cdc_rx post error\n");
}
#endif
}
static int cdc_rx_data(int *msg)
{
/* log_debug("msg[0]:0x%x\n", (u32)msg[0]); */
const struct usb_device_t *usb_device = (struct usb_device_t *)msg[0];
const usb_dev usb_id = usb_device2id(usb_device);
u8 buf[64] = {0};
u32 rlen;
rlen = cdc_read_data(usb_id, buf, 64);
/* log_debug("cdc rx data"); */
/* put_buf(buf, rlen);//固件三部测试使用 */
/* cdc_write_data(usb_id, buf, rlen);//固件三部测试使用 */
cfg_tool_data_from_cdc(buf, rlen);
return rlen;
}
APP_MSG_HANDLER(cdc_data_msg_entry) = {
.owner = 0xff,
.from = MSG_FROM_CDC_DATA,
.handler = cdc_rx_data,
};
#endif
#if TCFG_USB_CUSTOM_HID_ENABLE
static void custom_hid_rx_handler(void *priv, u8 *buf, u32 len)
{
printf("%s,%d,\n", __func__, __LINE__);
put_buf(buf, len);
//custom_hid_tx_data(0, buf, len);
}
#endif /* #if TCFG_USB_CUSTOM_HID_ENABLE */
//webusb和msd设备互斥,用户设置webusb模式还是msd模式,这里返回用户想要的模式,可以动态修改返回值
u8 __attribute__((weak))is_webusb_mode()
{
#if TCFG_USB_WEBUSB_ENABLE
return 1;
#else
return 0;
#endif
}
void usb_start(const usb_dev usbfd)
{
u32 class = 0;
#if TCFG_USB_SLAVE_MSD_ENABLE
class |= MASSSTORAGE_CLASS;
#endif
#if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE
class |= SPEAKER_CLASS;
#endif
#if TCFG_USB_SLAVE_AUDIO_MIC_ENABLE
class |= MIC_CLASS;
#endif
#if TCFG_USB_SLAVE_HID_ENABLE
class |= HID_CLASS;
#endif
#if TCFG_USB_SLAVE_CDC_ENABLE
class |= CDC_CLASS;
#endif
#if TCFG_USB_CUSTOM_HID_ENABLE
class |= CUSTOM_HID_CLASS;
#endif
g_printf("USB_DEVICE_CLASS_CONFIG:%x", class);
if (is_webusb_mode()) {
class = WEBUSB_CLASS;//web模式和其它互斥
}
usb_device_mode(usbfd, class);
if (!is_webusb_mode()) {
#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_NANDFLASH_DEV_ENABLE
msd_register_disk(TCFG_NANDFLASH_FAT_ROOT, 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);
#endif
}
#if TCFG_USB_SLAVE_CDC_ENABLE
cdc_set_wakeup_handler(usb_cdc_wakeup);
#endif
#if TCFG_USB_CUSTOM_HID_ENABLE
custom_hid_set_rx_hook(NULL, custom_hid_rx_handler);
printf("custom_hid rx_hook\n");
#endif
}
void usb_pause(const usb_dev usbfd)
{
log_info("usb pause");
usb_sie_disable(usbfd);
#if TCFG_USB_SLAVE_MSD_ENABLE
if (msd_set_wakeup_handle(NULL)) {
msd_unregister_all();
}
#endif
usb_device_mode(usbfd, 0);
}
void usb_stop(const usb_dev usbfd)
{
log_info("usb stop");
usb_pause(usbfd);
usb_sie_close(usbfd);
}
int usb_standby(const usb_dev usbfd)
{
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
usb_otg_suspend(usbfd, OTG_KEEP_STATE);
mult_sdio_suspend();
usb_pause(usbfd);
mult_sdio_resume();
#else
usb_pause(usbfd);
#endif
return 1;
}
#if TCFG_USB_CDC_BACKGROUND_RUN
void usb_cdc_background_run(const usb_dev usbfd)
{
g_printf("CDC is running in the background");
usb_device_mode(usbfd, CDC_CLASS);
cdc_set_wakeup_handler(usb_cdc_wakeup);
}
int usb_cdc_background_standby(const usb_dev usbfd)
{
int ret = 0;
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
mult_sdio_suspend();
usb_cdc_background_run(usbfd);
#else
#if TCFG_PC_ENABLE
#if TWFG_APP_POWERON_IGNORE_DEV
if (jiffies_to_msecs(jiffies) < TWFG_APP_POWERON_IGNORE_DEV) {
usb_cdc_background_run(usbfd);
} else
#endif
{
usb_pause(usbfd);
ret = 1;
}
#else
usb_cdc_background_run(usbfd);
#endif
#endif
return ret;
}
#endif
int pc_device_event_handler(int *msg)
{
if (msg[0] != DEVICE_EVENT_FROM_OTG) {
return false;
}
int switch_app_case = false;
const char *usb_msg = (const char *)msg[2];
if (usb_msg[0] == 's') {
log_debug("usb event : %d DEVICE_EVENT_FROM_OTG %s", msg[1], usb_msg);
if (msg[1] == DEVICE_EVENT_IN) {
log_info("usb %c online", usb_msg[2]);
switch_app_case = 1;
} else if (msg[1] == DEVICE_EVENT_OUT) {
log_info("usb %c offline", usb_msg[2]);
if (true == app_in_mode(APP_MODE_PC)) {
switch_app_case = 2;
} else {
usb_message_to_stack(USBSTACK_STOP, 0, 1);
}
}
}
return switch_app_case;
}
#endif
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,493 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "app_config.h"
#include "system/includes.h"
#include "printf.h"
#include "usb/usb_config.h"
#include "usb/device/usb_stack.h"
#include "generic/circular_buf.h"
#include "system/event.h"
#include "usb/device/uac_audio.h"
#include "uac_stream.h"
#include "audio_config.h"
#include "pc_spk_player.h"
#include "pc_spk_file.h"
#include "pc_mic_recoder.h"
#include "app_msg.h"
#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"
static volatile u8 speaker_stream_is_open = 0;
static volatile u8 mic_stream_is_open = 0;
struct uac_speaker_handle {
cbuffer_t cbuf;
volatile u8 need_resume;
u8 channel;
u32 samplerate;
u32 bitwidth;
u32 timestamp;
//void (*rx_handler)(int, void *, int);
};
static void (*uac_rx_handler)(int, void *, int) = NULL;
static u16 speaker_close_tid = 0;
static struct uac_speaker_handle *uac_speaker = NULL;
#if USB_MALLOC_ENABLE
#else
static struct uac_speaker_handle uac_speaker_handle SEC(.usb.data.bss.exchange);
#endif
u8 uac_audio_is_24bit_in_4byte()
{
return UAC_24BIT_IN_4BYTE;
}
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; */
/* } */
}
//这里起中断往后面推数
void uac_speaker_stream_write(const u8 *obuf, u32 len)
{
#if 0 //multiple channel test
if (uac_speaker) {
if (uac_speaker->channel == 4) {
s16 *ch0 = (s16 *)obuf;
s16 *ch1 = (s16 *)obuf;
ch1++;
for (int i = 0; i < len / 8; i++) {
ch0[i * 2] = ch0[i * 4];
ch1[i * 2] = ch0[i * 4 + 1];
}
len /= 2;
} else if (uac_speaker->channel == 6) {
s16 *ch0 = (s16 *)obuf;
s16 *ch1 = (s16 *)obuf;
ch1++;
for (int i = 0; i < len / 12; i++) {
ch0[i * 2] = ch0[i * 6];
ch1[i * 2] = ch0[i * 6 + 1];
}
len /= 3;
} else if (uac_speaker->channel == 8) {
s16 *ch0 = (s16 *)obuf;
s16 *ch1 = (s16 *)obuf;
ch1++;
for (int i = 0; i < len / 16; i++) {
ch0[i * 2] = ch0[i * 8];
ch1[i * 2] = ch0[i * 8 + 1];
}
len /= 4;
}
}
#endif
#if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE
pc_spk_data_isr_cb((void *)obuf, len);
#endif
}
void uac_speaker_stream_get_volume(u16 *l_vol, u16 *r_vol)
{
uac_get_cur_vol(0, l_vol, r_vol);
}
u8 uac_speaker_stream_status(void)
{
return speaker_stream_is_open;
}
void uac_speaker_stream_open(u32 samplerate, u32 ch, u32 bitwidth)
{
u32 last_sr = 0;
#if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE
last_sr = pc_spk_get_fmt_sample_rate();
#endif
if (speaker_stream_is_open) {
if (speaker_close_tid) {
sys_hi_timeout_del(speaker_close_tid);
speaker_close_tid = 0;
}
if (uac_speaker->samplerate != samplerate ||
uac_speaker->channel != ch ||
uac_speaker->bitwidth != bitwidth) {
uac_speaker->samplerate = samplerate;
uac_speaker->channel = ch;
uac_speaker->bitwidth = bitwidth;
#if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE
pc_spk_set_fmt(ch, bitwidth, samplerate);
pcspk_restart_player_by_taskq();
#endif
}
uac_speaker->timestamp = jiffies;
return;
}
log_info("%s", __func__);
if (!uac_speaker) {
#if USB_MALLOC_ENABLE
uac_speaker = zalloc(sizeof(struct uac_speaker_handle));
if (!uac_speaker) {
return;
}
#else
uac_speaker = &uac_speaker_handle;
memset(uac_speaker, 0, sizeof(struct uac_speaker_handle));
#endif
}
//uac_speaker->rx_handler = NULL;
uac_speaker->channel = ch;
uac_speaker->samplerate = samplerate;
uac_speaker->bitwidth = bitwidth;
speaker_stream_is_open = 1;
#if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE
log_info(">> Case : USB_AUDIO_PLAY_OPEN\n");
#if TCFG_USER_EMITTER_ENABLE
app_send_message(APP_MSG_PC_AUDIO_PLAY_OPEN, (int)((ch << 24) | samplerate));
#endif
pc_spk_set_fmt(ch, bitwidth, samplerate);
pcspk_open_player_by_taskq();
#endif
uac_speaker->timestamp = jiffies;
}
void uac_speaker_stream_close_delay(void *priv)
{
int release = (int)priv;
speaker_close_tid = 0;
if (speaker_stream_is_open == 0) {
return;
}
log_info("%s", __func__);
speaker_stream_is_open = 0;
if (uac_speaker) {
#if USB_MALLOC_ENABLE
free(uac_speaker);
#endif
uac_speaker = NULL;
}
#if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE
log_info(">> Case : USB_AUDIO_PLAY_CLOSE\n");
if (release) {
pc_spk_player_close();
} else {
pcspk_close_player_by_taskq();
}
#if TCFG_USER_EMITTER_ENABLE
app_send_message(APP_MSG_PC_AUDIO_PLAY_CLOSE, 0);
#endif
#endif
}
void uac_speaker_stream_close(int release)
{
if (speaker_stream_is_open == 0) {
return;
}
if (uac_speaker) {
if (jiffies_to_msecs(jiffies - uac_speaker->timestamp) > 150 || release) {
if (speaker_close_tid) {
sys_hi_timeout_del(speaker_close_tid);
speaker_close_tid = 0;
}
uac_speaker_stream_close_delay((void *)release);
} else {
if (speaker_close_tid == 0) {
speaker_close_tid = sys_hi_timeout_add(NULL, uac_speaker_stream_close_delay, 150);
} else {
sys_hi_timeout_modify(speaker_close_tid, 150);
}
}
}
}
int uac_get_spk_vol()
{
int max_vol = app_audio_volume_max_query(AppVol_USB);
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;
}
void uac_mute_volume(u32 type, u32 l_vol, u32 r_vol)
{
static u32 last_spk_l_vol = (u32) - 1, last_spk_r_vol = (u32) - 1;
static u32 last_mic_vol = (u32) - 1;
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;
pc_mic_set_volume_by_taskq(l_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;
//TODO
#if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE
printf(">> PC, r_vol:%d, l_vol:%d\n", r_vol, l_vol);
/* app_audio_set_volume(APP_AUDIO_STATE_MUSIC, (r_vol + l_vol) / 2, 1); */
pcspk_set_volume_by_taskq();
#endif
break;
default:
break;
}
}
static int (*mic_tx_handler)(void *, void *, int) = NULL;
static void *mic_tx_handler_priv = NULL;
static u32 mic_close_tid = 0;
static u32 mic_samplerate;
static u32 mic_bitwidth;
static u8 mic_channel;
static u32 mic_timestamp;
int uac_mic_stream_read(u8 *buf, u32 len)
{
if (mic_stream_is_open == 0) {
memset(buf, 0, len);
return len;
}
#if 0//48K 1ksin
const s16 sin_48k[] ALIGNED(4) = {
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
};
const u8 sin_16k[] ALIGNED(4) = {
0x00, 0x00, 0xFB, 0x30, 0x81, 0x5A, 0x41, 0x76,
0xFE, 0x7F, 0x41, 0x76, 0x82, 0x5A, 0xFC, 0x30,
0x00, 0x00, 0x04, 0xCF, 0x7E, 0xA5, 0xC0, 0x89,
0x01, 0x80, 0xBF, 0x89, 0x7E, 0xA5, 0x04, 0xCF,
};
s16 *sin_wav = NULL;
if (mic_samplerate == 48000) {
sin_wav = (s16 *)sin_48k;
} else if (mic_samplerate == 16000) {
sin_wav = (s16 *)sin_16k;
} else {
sin_wav = (s16 *)sin_48k;
/* ASSERT(0, "unsupport samplerate: %d", mic_samplerate); */
}
if (mic_channel == 1) {
memcpy(buf, sin_wav, len);
} else if (mic_channel == 2) {
u16 *l_ch = (u16 *)buf;
u16 *r_ch = (u16 *)buf;
r_ch++;
for (int i = 0; i < len / 4; i++) {
*l_ch = sin_wav[i];
*r_ch = sin_wav[i];
l_ch += 2;
r_ch += 2;
}
} else if (mic_channel == 4) {
u16 *ch0 = (u16 *)buf;
u16 *ch1 = (u16 *)buf;
u16 *ch2 = (u16 *)buf;
u16 *ch3 = (u16 *)buf;
ch1 += 1, ch2 += 2, ch3 += 3;
for (int i = 0; i < len / 8; i++) {
ch0[i * 4] = sin_wav[i];
ch1[i * 4] = sin_wav[i];
ch2[i * 4] = sin_wav[i];
ch3[i * 4] = sin_wav[i];
}
} else if (mic_channel == 8) {
u16 *ch0 = (u16 *)buf;
u16 *ch1 = (u16 *)buf;
u16 *ch2 = (u16 *)buf;
u16 *ch3 = (u16 *)buf;
u16 *ch4 = (u16 *)buf;
u16 *ch5 = (u16 *)buf;
u16 *ch6 = (u16 *)buf;
u16 *ch7 = (u16 *)buf;
ch1 += 1, ch2 += 2, ch3 += 3, ch4 += 4, ch5 += 5, ch6 += 6, ch7 += 7;
for (int i = 0; i < len / 16; i++) {
ch0[i * 8] = sin_wav[i];
ch1[i * 8] = sin_wav[i];
ch2[i * 8] = sin_wav[i];
ch3[i * 8] = sin_wav[i];
ch4[i * 8] = sin_wav[i];
ch5[i * 8] = sin_wav[i];
ch6[i * 8] = sin_wav[i];
ch7[i * 8] = sin_wav[i];
}
}
return len;
#else
if (mic_tx_handler) {
return mic_tx_handler(mic_tx_handler_priv, buf, len);
} else {
//putchar('N');
memset(buf, 0, len);
}
return len;
#endif
}
void set_uac_mic_tx_handler(void *priv, int (*tx_handler)(void *, void *, int))
{
mic_tx_handler = tx_handler;
mic_tx_handler_priv = priv;
}
void uac_mic_stream_get_volume(u16 *vol)
{
*vol = uac_get_mic_vol(0);
}
u8 uac_get_mic_stream_status(void)
{
return mic_stream_is_open;
}
u32 uac_mic_stream_open(u32 samplerate, u32 ch, u32 bitwidth)
{
u32 last_sr = 0;
#if TCFG_USB_SLAVE_AUDIO_MIC_ENABLE
last_sr = pc_mic_get_fmt_sample_rate();
pc_mic_set_fmt(ch, bitwidth, samplerate);
#endif
if (mic_stream_is_open) {
if (mic_close_tid) {
sys_hi_timeout_del(mic_close_tid);
mic_close_tid = 0;
}
if (mic_samplerate != samplerate ||
mic_channel != ch ||
mic_bitwidth != bitwidth) {
mic_tx_handler = NULL; //添加测试
mic_samplerate = samplerate;
mic_bitwidth = bitwidth;
mic_channel = ch;
#if TCFG_USB_SLAVE_AUDIO_MIC_ENABLE
//重启mic recorder
pc_mic_recoder_restart_by_taskq();
#endif
}
mic_timestamp = jiffies;
return 0;
}
mic_tx_handler = NULL; //这里需要赋值为NULL
mic_samplerate = samplerate;
mic_bitwidth = bitwidth;
mic_channel = ch;
log_info("%s", __func__);
mic_stream_is_open = 1;
#if TCFG_USB_SLAVE_AUDIO_MIC_ENABLE
log_info("## Func:%s, Line:%d, Open Mic!!\n", __func__, __LINE__);
#if TCFG_USER_EMITTER_ENABLE
app_send_message(APP_MSG_PC_AUDIO_MIC_OPEN, (int)((ch << 24) | samplerate));
#endif
pc_mic_recoder_open_by_taskq();
#endif
mic_timestamp = jiffies;
return 0;
}
static void uac_mic_stream_close_delay(void *priv)
{
int release = (u8)priv;
mic_close_tid = 0;
log_info("%s", __func__);
mic_stream_is_open = 0;
#if TCFG_USB_SLAVE_AUDIO_MIC_ENABLE
log_info("## Func:%s, Line:%d, Close Mic!!\n", __func__, __LINE__);
if (release) {
pc_mic_recoder_close();
} else {
pc_mic_recoder_close_by_taskq();
}
#if TCFG_USER_EMITTER_ENABLE
app_send_message(APP_MSG_PC_AUDIO_MIC_CLOSE, 0);
#endif
#endif
}
void uac_mic_stream_close(int release)
{
if (mic_stream_is_open == 0) {
return ;
}
//FIXME:
//未知原因出现频繁开关mic,导致出现audio或者蓝牙工作异常,
//收到mic关闭命令后延时150ms再发消息通知audio模块执行关闭动作
//如果在150ms之内继续收到usb下发的关闭命令,则继续推迟150ms。
if (jiffies_to_msecs(jiffies - mic_timestamp) >= 150 || release) {
if (mic_close_tid) {
sys_hi_timeout_del(mic_close_tid);
mic_close_tid = 0;
}
uac_mic_stream_close_delay((void *)release);
} else {
if (mic_close_tid == 0) {
mic_close_tid = sys_hi_timeout_add(NULL, uac_mic_stream_close_delay, 150);
} else {
sys_hi_timeout_modify(mic_close_tid, 150);
}
}
}
@@ -0,0 +1,36 @@
/*****************************************************************
>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,
};
int uac_get_spk_vol();
u8 uac_audio_is_24bit_in_4byte();
void uac_speaker_stream_open(u32 samplerate, u32 ch, u32 bitwidth);
void uac_speaker_stream_close();
void uac_speaker_stream_write(const u8 *obuf, u32 len);
void uac_speaker_stream_get_volume(u16 *l_vol, u16 *r_vol);
void set_uac_speaker_rx_handler(void *priv, void (*rx_handler)(int, void *, int));
u32 uac_mic_stream_open(u32 samplerate, u32 ch, u32 bitwidth);
void uac_mic_stream_close();
int uac_mic_stream_read(u8 *buf, u32 len);
void uac_mic_stream_get_volume(u16 *vol);
void set_uac_mic_tx_handler(void *priv, int (*tx_handler)(void *, void *, int));
void uac_mute_volume(u32 type, u32 l_vol, u32 r_vol);
#endif
@@ -0,0 +1,297 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#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/custom_hid.h"
#include "usb/device/uac_audio.h"
#include "usb/device/cdc.h"
#include "usb/device/webusb.h"
#include "irq.h"
#include "init.h"
#include "gpio.h"
#include "app_config.h"
#include "clock_manager/clock_manager.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)
{
u32 speed = USB_SPEED_FULL;
#if defined(FUSB_MODE) && FUSB_MODE
speed = USB_SPEED_FULL;
#elif defined(FUSB_MODE) && (FUSB_MODE == 0)
speed = USB_SPEED_HIGH;
#endif
usb_config(usb_id);
usb_g_sie_init(usb_id);
usb_slave_init(usb_id, speed);
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)
{
//cppcheck-suppress unreadVariable
u8 class_index = 0;
if (class == 0) {
usb_device_hold(usb_id);
#if TCFG_USB_SLAVE_MSD_ENABLE
msd_release(usb_id);
#endif
#if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE
uac_spk_release(usb_id);
#endif
#if TCFG_USB_SLAVE_AUDIO_MIC_ENABLE
uac_mic_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
#if TCFG_USB_CUSTOM_HID_ENABLE
custom_hid_release();
#endif
#if TCFG_USB_WEBUSB_ENABLE
webusb_release(usb_id);
#endif
#ifdef CONFIG_CPU_BR27
clock_unlock("usb_device");
#endif
return 0;
}
/* int ret = usb_ep_conflict_check(usb_id); */
/* if (ret) { */
/* return ret; */
/* } */
#ifdef CONFIG_CPU_BR27
clock_lock("usb_device", 320000000);
#endif
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_SPK_ENABLE || TCFG_USB_SLAVE_AUDIO_MIC_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_spk_register(usb_id);
uac_mic_register(usb_id);
} 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_spk_register(usb_id);
} 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_mic_register(usb_id);
}
#endif
#if TCFG_USB_CUSTOM_HID_ENABLE
if ((class & CUSTOM_HID_CLASS) == CUSTOM_HID_CLASS) {
log_info("add desc std custom_hid");
custom_hid_register(usb_id);
usb_add_desc_config(usb_id, class_index++, custom_hid_desc_config);
}
#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);
//dongle 1t2设置两条usb通路
#if 0//CONFIG_APP_DONGLE && (CONFIG_BT_GATT_CLIENT_NUM == 2)
hid_register_second(usb_id);
usb_add_desc_config(usb_id, class_index++, hid_second_desc_config);
#endif
}
#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
#if TCFG_USB_WEBUSB_ENABLE
if ((class & WEBUSB_CLASS) == WEBUSB_CLASS) {
usb_add_desc_config(usb_id, class_index++, webusb_desc_config);
webusb_register(usb_id);
}
#endif
usb_device_init(usb_id);
usb_device_set_class(usb_id2device(usb_id), class);
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_MIC_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_SPK_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中断,intrusbeintrtxe
//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;
}
@@ -0,0 +1,262 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#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/descriptor.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
extern void go_mask_usb_updata();
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_SPK_ENABLE || TCFG_USB_SLAVE_AUDIO_MIC_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)
{
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;
}
_WEAK_
u32 webusb_setup_device_hook(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
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;
u8 *tx_payload = usb_get_setup_buffer(usb_device);
#if TCFG_USB_WEBUSB_ENABLE
ret = webusb_setup_device_hook(usb_device, req);
if (ret) {
return ret;
}
#endif
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_SPK_ENABLE || TCFG_USB_SLAVE_AUDIO_MIC_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
get_device_descriptor(tx_payload);
for (int i = 0; i < 8; i++) {
//为了兼容windows7等老电脑,配置成不同类时应该使用不同pid
if (usb_device->wDeviceClass & BIT(i)) {
tx_payload[11] += i + 1;
}
}
//为了兼容macOS,必须设成复合设备,否则macbook会不认设备
tx_payload[0x4] = 0xef; //device class should be Multi-interface Function 0xEF
tx_payload[0x5] = 0x2; //device subclass should be Multi-interface Function 2
tx_payload[0x6] = 0x1; //device protocol should be Multi-interface Function 1
usb_set_data_payload(usb_device, req, tx_payload, tx_payload[0]);
ret = 1;
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)
{
u8 ack_data[8] = {0};
u32 ret = 0;
u8 *tx_payload = usb_get_setup_buffer(usb_device);
switch (req->bRequest) {
case USB_REQ_GET_STATUS:
#if 0//TCFG_TYPEC_EARPHONE_TEST_FILTER
tx_payload[0] = 0xfe;
usb_set_data_payload(usb_device, req, tx_payload, 1);
#endif
if ((req->wValue == 0xfc) && (req->wIndex == 0xfe)) {
if (req->wLength == sizeof(ack_data)) { //支持该私有命令响应
log_info("support private update command\n");
memset(ack_data, 0xff, sizeof(ack_data));
usb_set_data_payload(usb_device, req, ack_data, sizeof(ack_data));
} else if (req->wLength == 0x00) { //准备跳转升级模式
log_info("run func go_mask_usb_updata()\n");
usb_set_setup_phase(usb_device, USB_EP0_STAGE_SETUP);
go_mask_usb_updata();
}
ret = 1;
}
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
+454
View File
@@ -0,0 +1,454 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "os/os_api.h"
#include "usb/device/webusb.h"
#include "usb_config.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 && TCFG_USB_WEBUSB_ENABLE
#define MS_OS_20_SET_HEADER_DESCRIPTOR 0x00
#define MS_OS_20_SUBSET_HEADER_CONFIGURATION 0x01
#define MS_OS_20_SUBSET_HEADER_FUNCTION 0x02
#define MS_OS_20_FEATURE_COMPATIBLE_ID 0x03
#define MS_OS_20_FEATURE_REG_PROPERTY 0x04
#define MS_OS_20_DESCRIPTOR_LENGTH 0x1e
#define MS_OS20_OFFSET_BFIRSTINTERFACE (0x0A + 0x08 + 0x04)
#define WEBUSB_REQ_URL (1)
#define WEBUSB_REQ_MS_DESC (2)
#define WEBUSB_iInterface 0x11
static u8 webusb_interface_num;
typedef void (*webusb_rx_handle_t)(void *hdl, u8 *buffer, u32 len);
struct webusb_handle_t {
u8 *ep_out_dmabuffer;
u8 *ep_in_dmabuffer;
void (*wakeup_handle)(struct usb_device_t *usb_device);
void *priv_hdl;
webusb_rx_handle_t rx_hook;
};
static struct webusb_handle_t *webusb_handle = NULL;
static void webusb_epout_isr(struct usb_device_t *usb_device, u32 ep);
static void webusb_epin_isr(struct usb_device_t *usb_device, u32 ep);
static const u8 sWebUSBDescriptor[] = {
0x09, // bLength
0x04, // bDescriptorType = Interface
0x00, // bInterfaceNumber = 0
0x00, // bAlternateSetting
0x02, // bNumEndpoints = 2
0xFF, // bInterfaceClass = Vendor Specific (0xFF)
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
WEBUSB_iInterface, // iInterface
//EndpointDescriptor:
USB_DT_ENDPOINT_SIZE, // bLength
USB_DT_ENDPOINT, // bDescriptorType, Type
USB_DIR_IN | WEBUSB_EP_IN, // bEndpointAddress
USB_ENDPOINT_XFER_BULK, // Interrupt
LOBYTE(MAXP_SIZE_WEBUSBIN), HIBYTE(MAXP_SIZE_WEBUSBIN),// Maximum packet size
0, // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms
//Endpoint Descriptor:
USB_DT_ENDPOINT_SIZE, // bLength
USB_DT_ENDPOINT, // bDescriptorType, Type
WEBUSB_EP_OUT, // bEndpointAddress
USB_ENDPOINT_XFER_BULK, // Interrupt
LOBYTE(MAXP_SIZE_WEBUSBOUT), HIBYTE(MAXP_SIZE_WEBUSBOUT),// Maximum packet size
0, // bInterval, for high speed 2^(n-1) * 125us, for full/low speed n * 1ms
};
/* --------------------------------------------------------------------
* BOS Descriptor with WebUSB + Microsoft OS 2.0
* ------------------------------------------------------------------ */
static const uint8_t bos_descriptor[] = {
// BOS Descriptor
0x05, // bLength
0x0F, // bDescriptorType = BOS
0x39, 0x00, // wTotalLength (57 bytes = 5 + 24 + 28)
0x02, // bNumDeviceCaps = 2
// ---- WebUSB Platform Capability Descriptor ----
0x18, // bLength = 24
0x10, // bDescriptorType = Device Capability
0x05, // bDevCapabilityType = PLATFORM
0x00, // bReserved
// PlatformCapabilityUUID (WebUSB UUID = 3408B638-09A9-47A0-8BFD-A0768815B665)
0x38, 0xB6, 0x08, 0x34,
0xA9, 0x09,
0xA0, 0x47,
0x8B, 0xFD,
0xA0, 0x76, 0x88, 0x15, 0xB6, 0x65,
0x00, 0x01, // bcdVersion 1.0
WEBUSB_REQ_URL, // bVendorCode (for WebUSB requests)
0x01, // iLandingPage (string index for default URL)
// ---- Microsoft OS 2.0 Platform Capability Descriptor ----
0x1C, // bLength = 28
0x10, // bDescriptorType = Device Capability
0x05, // bDevCapabilityType = PLATFORM
0x00, // bReserved
// MS OS 2.0 Platform Capability UUID = D8DD60DF-4589-4C7C-9CD2-659D9E648A9F
0xDF, 0x60, 0xDD, 0xD8,
0x89, 0x45,
0xC7, 0x4C,
0x9C, 0xD2,
0x65, 0x9D, 0x9E, 0x64, 0x8A, 0x9F,
0x00, 0x00, 0x03, 0x06, // dwWindowsVersion = 0x06030000 (Win 8.1+)
MS_OS_20_DESCRIPTOR_LENGTH, 0x00, //Descriptor set length
WEBUSB_REQ_MS_DESC, // bMS_VendorCode (for MS OS requests)
0x00, // bAltEnumCode
};
/* --------------------------------------------------------------------
* Microsoft OS 2.0 Descriptor Set
* ------------------------------------------------------------------ */
static const uint8_t ms_os_20_descriptor[] = {
// ---- Microsoft OS 2.0 Descriptor Set Header ----
0x0A, 0x00, // wLength = 10
MS_OS_20_SET_HEADER_DESCRIPTOR, 0x00, // wDescriptorType = SET_HEADER
0x00, 0x00, 0x03, 0x06, // dwWindowsVersion = 0x06030000
MS_OS_20_DESCRIPTOR_LENGTH, 0x00, // Size, MS OS 2.0 descriptor set
// ---- Compatible ID Feature Descriptor ----
0x14, 0x00, // wLength = 20
MS_OS_20_FEATURE_COMPATIBLE_ID, 0x00, // wDescriptorType = FEATURE_COMPATIBLE_ID
'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, // Compatible ID = "WINUSB\0\0"
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // Sub-Compatible ID (unused)
};
/* --------------------------------------------------------------------
* WebUSB URL Descriptor (GET_URL response)
* URL = https://doc.zh-jieli.com
* ------------------------------------------------------------------ */
static const uint8_t webusb_url_descriptor[] = {
3 + 16, // bLength = (3 + 16 chars)
0x03, // bDescriptorType = URL
0x01, // bScheme = 1 (https://)
'd', 'o', 'c', '.', 'z', 'h', '-', 'j', 'i', 'e', 'l', 'i', '.', 'c', 'o', 'm'
};
#define WEBUSB_REQUEST_GET_URL 0x02
#define MS_OS_20_REQUEST_DESCRIPTOR 0x07
static const uint8_t device_qualifier_descriptor[] = {
0x0A, // bLength
0x06, // bDescriptorType = DEVICE_QUALIFIER
0x10, 0x02, // bcdUSB = 2.00
0x00, // bDeviceClass
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 = 64
0x01, // bNumConfigurations
0x00 // bReserved
};
static const u8 iweb_usb_string[] = {
44, //该描述符的长度为44字节
0x03, //字符串描述符的类型编码为0x03
0x77, 0x00, //w
0x65, 0x00, //e
0x62, 0x00, //b
0x75, 0x00, //u
0x73, 0x00, //s
0x62, 0x00, //b
0x5f, 0x00, //_
0x69, 0x00, //i
0x6e, 0x00, //n
0x74, 0x00, //t
0x65, 0x00, //e
0x72, 0x00, //r
0x66, 0x00, //f
0x61, 0x00, //a
0x63, 0x00, //c
0x65, 0x00, //e
0x5f, 0x00, //_
0x6e, 0x00, //n
0x61, 0x00, //a
0x6d, 0x00, //m
0x65, 0x00, //e
};
u32 webusb_setup_device_hook(struct usb_device_t *usb_device, struct usb_ctrlrequest *req)
{
if (webusb_handle == NULL) {
return 0;
}
u32 ret = 1;
u32 h_wValue = HIBYTE(req->wValue);
u32 l_wValue = LOBYTE(req->wValue);
if (req->bRequest == USB_REQ_GET_DESCRIPTOR) {
/* BOS Descriptor */
if (h_wValue == USB_DT_BOS) {
usb_set_data_payload(usb_device, req, bos_descriptor, sizeof(bos_descriptor));
}
/* Device Qualifier Descriptor */
else if (h_wValue == USB_DT_DEVICE_QUALIFIER) {
usb_set_data_payload(usb_device, req, device_qualifier_descriptor, sizeof(device_qualifier_descriptor));
}
/* WebUSB string descriptor */
else if (h_wValue == USB_DT_STRING && l_wValue == WEBUSB_iInterface) {
usb_set_data_payload(usb_device, req, iweb_usb_string, sizeof(iweb_usb_string));
} else {
ret = 0;
}
}
/* Microsoft OS 2.0 Descriptor request */
else if (req->bRequest == WEBUSB_REQ_MS_DESC && req->wIndex == MS_OS_20_REQUEST_DESCRIPTOR) {
usb_set_data_payload(usb_device, req, ms_os_20_descriptor, sizeof(ms_os_20_descriptor));
}
/* WebUSB GET_URL request */
else if (req->bRequest == WEBUSB_REQ_URL && req->wIndex == WEBUSB_REQUEST_GET_URL) {
usb_set_data_payload(usb_device, req, webusb_url_descriptor, sizeof(webusb_url_descriptor));
} else {
ret = 0;
}
return ret;
}
static void webusb_endpoint_init(struct usb_device_t *usb_device, u32 itf)
{
const usb_dev usb_id = usb_device2id(usb_device);
/* usb_g_set_intr_hander(usb_id, WEBUSB_EP_OUT, webusb_epout_isr); */
usb_g_ep_config(usb_id, WEBUSB_EP_OUT, USB_ENDPOINT_XFER_BULK, 0, webusb_handle->ep_out_dmabuffer, 64);
usb_g_set_intr_hander(usb_id, WEBUSB_EP_IN | USB_DIR_IN, webusb_epin_isr);
usb_g_ep_config(usb_id, WEBUSB_EP_IN | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 1, webusb_handle->ep_in_dmabuffer, 64);
usb_enable_ep(usb_id, WEBUSB_EP_IN);
}
u32 webusb_tx_data(const usb_dev usb_id, const u8 *buffer, u32 len)
{
if (webusb_handle == NULL) {
return -1;
}
if (len > MAXP_SIZE_WEBUSBIN) {
len = MAXP_SIZE_WEBUSBIN;
}
return usb_g_intr_write(usb_id, WEBUSB_EP_IN, buffer, len);
}
void webusb_set_rx_hook(void *priv, void (*rx_hook)(void *priv, u8 *buf, u32 len))
{
webusb_handle->priv_hdl = priv;
webusb_handle->rx_hook = rx_hook;
}
static void webusb_reset(struct usb_device_t *usb_device, u32 itf)
{
//cppcheck-suppress unreadVariable
webusb_endpoint_init(usb_device, itf);
}
static void webusb_epout_isr(struct usb_device_t *usb_device, u32 ep)
{
const usb_dev usb_id = usb_device2id(usb_device);
u8 buf[64];
int len = usb_g_bulk_read(usb_id, ep, buf, sizeof(buf), 0);
if (webusb_handle->rx_hook) {
webusb_handle->rx_hook(webusb_handle->priv_hdl, buf, len);
} else {
log_info("webusb_recv:len = %d\n", len);
}
}
//发送完成的中断,需要打开ep_config里面的ie,并且注册中断回调函数
static void webusb_epin_isr(struct usb_device_t *usb_device, u32 ep)
{
const usb_dev usb_id = usb_device2id(usb_device);
u8 buf[64];
int len = usb_g_bulk_write(usb_id, ep, buf, sizeof(buf));
log_info("send:len = %d\n", len);
}
//ep0 recv demo
static u8 passwd_verify_ok;
static u32 webusb_passwd_verify(struct usb_device_t *usb_device, struct usb_ctrlrequest *setup)
{
const usb_dev usb_id = usb_device2id(usb_device);
u32 ret = USB_EP0_STAGE_SETUP;
u8 read_ep[64];
u32 len = MIN(setup->wLength, sizeof(read_ep));
usb_read_ep0(usb_id, read_ep, len);
ret = USB_EP0_STAGE_SETUP;
passwd_verify_ok = 0;
if (memcmp(read_ep, "123", 3) == 0) {
passwd_verify_ok = 1;
usb_g_bulk_write(usb_id, WEBUSB_EP_IN, read_ep, sizeof(read_ep));
printf("passwd verify ok\n");
}
setup->wLength -= len;
if (setup->wLength) {
return USB_EP0_STAGE_OUT;
}
return ret;
}
static u32 webusb_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_SET_SECURITY_DATA:
usb_set_setup_recv(usb_device, webusb_passwd_verify);
break;
case USB_REQ_GET_SECURITY_DATA:
tx_len = req->wLength;
tx_payload[0] = passwd_verify_ok;
usb_set_data_payload(usb_device, req, tx_payload, tx_len);
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
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
break;
case USB_REQ_GET_INTERFACE:
if (req->wLength) {
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;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}//bRequest @ USB_TYPE_STANDARD
break;
case USB_TYPE_CLASS:
switch (req->bRequest) {
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}//bRequest @ USB_TYPE_CLASS
break;
default:
usb_set_setup_phase(usb_device, USB_EP0_SET_STALL);
}
return 0;
}
u32 webusb_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num)
{
//cppcheck-suppress unreadVariable
struct usb_device_t *usb_device = usb_id2device(usb_id);
log_debug("webusb interface num:%d\n", *cur_itf_num);
memcpy(ptr, sWebUSBDescriptor, sizeof(sWebUSBDescriptor));
ptr[2] = *cur_itf_num;
if (usb_set_interface_hander(usb_id, *cur_itf_num, webusb_itf_hander) != *cur_itf_num) {
ASSERT(0, "webusb set interface_hander fail");
}
if (usb_set_reset_hander(usb_id, *cur_itf_num, webusb_reset) != *cur_itf_num) {
ASSERT(0, "webusb set interface_reset_hander fail");
}
webusb_interface_num = *cur_itf_num;
*cur_itf_num = *cur_itf_num + 1;
return sizeof(sWebUSBDescriptor);
}
u8 is_webusb_register()
{
if (webusb_handle) {
return 1;
}
return 0;
}
u32 webusb_register(usb_dev usb_id)
{
if (webusb_handle) {
return 0;
}
webusb_handle = (struct webusb_handle_t *)zalloc(sizeof(struct webusb_handle_t));
webusb_handle->ep_in_dmabuffer = usb_alloc_ep_dmabuffer(usb_id, WEBUSB_EP_IN | USB_DIR_IN, 64);
webusb_handle->ep_out_dmabuffer = usb_alloc_ep_dmabuffer(usb_id, WEBUSB_EP_OUT, 64);
return 0;
}
void webusb_release(usb_dev usb_id)
{
if (webusb_handle == NULL) {
return ;
}
usb_free_ep_dmabuffer(usb_id, webusb_handle->ep_in_dmabuffer);
usb_free_ep_dmabuffer(usb_id, webusb_handle->ep_out_dmabuffer);
free(webusb_handle);
webusb_handle = NULL;
}
#endif
@@ -0,0 +1,15 @@
#ifndef __WEBUSB_H__
#define __WEBUSB_H__
#include "usb/usb_config.h"
#include "usb/device/usb_stack.h"
u32 webusb_desc_config(const usb_dev usb_id, u8 *ptr, u32 *cur_itf_num);
u32 webusb_register(usb_dev usb_id);
void webusb_release(usb_dev usb_id);
void webusb_set_rx_hook(void *priv, void (*rx_hook)(void *priv, u8 *buf, u32 len));
u32 webusb_tx_data(const usb_dev usb_id, const u8 *buffer, u32 len);
#endif /*WEBUSB_H*/
+476
View File
@@ -0,0 +1,476 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "system/includes.h"
#include "cpu/includes.h"
#include "system/timer.h"
#include "device/ioctl_cmds.h"
#include "usb/host/usb_host.h"
#include "usb_ctrl_transfer.h"
#include "usb_bulk_transfer.h"
#include "device_drive.h"
#include "adb.h"
#include "usb_config.h"
#include "app_config.h"
#if TCFG_ADB_ENABLE
#define LOG_TAG_CONST USB
#define LOG_TAG "[adb]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
#include "adb_rsa_key.c"
struct adb_device_t adb;
struct device adb_device;
void aoa_switch(struct usb_host_device *host_dev);
static u8 *adb_bulk_ep_in_buf;
static u8 *adb_bulk_ep_out_buf;
static int set_adb_power(struct usb_host_device *host_dev, u32 value)
{
return DEV_ERR_NONE;
}
static int get_adb_power(struct usb_host_device *host_dev, u32 value)
{
return DEV_ERR_NONE;
}
static const struct interface_ctrl adb_ops = {
.interface_class = USB_CLASS_ADB,
.set_power = set_adb_power,
.get_power = get_adb_power,
.ioctl = NULL,
};
static const struct usb_interface_info adb_inf = {
.ctrl = (struct interface_ctrl *) &adb_ops,
.dev.adb = &adb,
};
u32 usb_adb_interface_ptp_mtp_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
pBuf += sizeof(struct usb_interface_descriptor);
for (int i = 0; i < interface->bNumEndpoints; i++) {
struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)pBuf;
if (endpoint->bDescriptorType == USB_DT_ENDPOINT) {
if (endpoint->bmAttributes == USB_ENDPOINT_XFER_BULK) {
if (endpoint->bEndpointAddress & USB_DIR_IN) {
adb.extr_in = endpoint->bEndpointAddress & 0xf;
} else {
adb.extr_out = endpoint->bEndpointAddress;
}
}
pBuf += USB_DT_ENDPOINT_SIZE;
} else {
return 0;
}
}
printf("%s() %x %x\n", __func__, adb.extr_in, adb.extr_out);
return pBuf - (u8 *)interface ;
}
int usb_adb_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
pBuf += sizeof(struct usb_interface_descriptor);
int len = 0;
const usb_dev usb_id = host_device2id(host_dev);
adb_device.private_data = host_dev;
host_dev->interface_info[interface_num] = &adb_inf;
for (int endnum = 0; endnum < interface->bNumEndpoints; endnum++) {
struct usb_endpoint_descriptor *end_desc = (struct usb_endpoint_descriptor *)pBuf;
if (end_desc->bDescriptorType != USB_DT_ENDPOINT ||
end_desc->bLength != USB_DT_ENDPOINT_SIZE) {
log_error("ep bDescriptorType = %d bLength = %d", end_desc->bDescriptorType, end_desc->bLength);
return -USB_DT_ENDPOINT;
}
len += USB_DT_ENDPOINT_SIZE;
pBuf += USB_DT_ENDPOINT_SIZE;
if ((end_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
if (end_desc->bEndpointAddress & USB_DIR_IN) {
adb.host_epin = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
adb.target_epin = end_desc->bEndpointAddress & 0x0f;
#if defined(FUSB_MODE) && FUSB_MODE == 0
adb.rxmaxp = end_desc->wMaxPacketSize;
#endif
log_debug("D(%d)->H(%d)", adb.target_epin, adb.host_epin);
} else {
adb.host_epout = usb_get_ep_num(usb_id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
adb.target_epout = end_desc->bEndpointAddress & 0x0f;
#if defined(FUSB_MODE) && FUSB_MODE == 0
adb.txmaxp = end_desc->wMaxPacketSize;
#endif
log_debug("H(%d)->D(%d)", adb.host_epout, adb.target_epout);
}
}
}
if (!adb_bulk_ep_in_buf) {
adb_bulk_ep_in_buf = usb_h_alloc_ep_buffer(usb_id, adb.host_epin | USB_DIR_IN, 64 * 2);
}
#ifdef USB_HW_20
usb_write_rxfuncaddr(usb_id, adb.host_epin, host_dev->private_data.devnum);
#endif
usb_h_ep_config(usb_id, adb.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 0, 0, adb_bulk_ep_in_buf, 64);
if (!adb_bulk_ep_out_buf) {
adb_bulk_ep_out_buf = usb_h_alloc_ep_buffer(usb_id, adb.host_epout | USB_DIR_OUT, 64);
}
#ifdef USB_HW_20
usb_write_txfuncaddr(usb_id, adb.host_epout, host_dev->private_data.devnum);
#endif
usb_h_ep_config(usb_id, adb.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, adb_bulk_ep_out_buf, 64);
return len;
}
static int adb_send_packet(struct amessage *msg, const u8 *data_ptr)
{
if (msg == NULL) {
return usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, NULL, 0);
}
u32 count = msg->data_length;
msg->magic = msg->command ^ 0xffffffff;
const u8 *_data_ptr = data_ptr;
msg->data_check = 0;
while (count--) {
msg->data_check += *_data_ptr++;
}
int ret = usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, (u8 *)msg, sizeof(*msg));
if (ret < 0) {
return ret;
}
if (data_ptr != NULL) {
return usb_bulk_only_send(&adb_device, adb.host_epout, 64, adb.target_epout, data_ptr, msg->data_length);
} else {
return 0;
}
}
static int adb_recv(u8 *buffer, u32 len, u32 timeout)
{
return usb_bulk_only_receive(&adb_device, adb.host_epin, 64, adb.target_epin, buffer, len);
}
#define check_usb_status(ret) do{\
if(ret < 0){\
log_info("%s() @ %d %d\n", __func__, __LINE__, ret);\
return ret;\
}\
}while(0);
static u8 adb_signatrue_data_index ;
u32 adb_auth()
{
log_info("%s() %d\n", __func__, __LINE__);
struct amessage msg;
int ret = 0;
u8 *cmd_string;
adb.local_id = 0x58525047;
adb.remote_id = 0;
msg.command = A_CNXN;
msg.arg0 = A_VERSION;
msg.arg1 = 0x00001000;
cmd_string = (u8 *)"host::";
msg.data_length = strlen((const char *)cmd_string) + 1;
ret = adb_send_packet(&msg, cmd_string);
check_usb_status(ret);
memset(&msg, 0, 24);
ret = adb_recv((u8 *)&msg, 24, 5);
check_usb_status(ret);
if (msg.command == A_CNXN) {
if (adb_recv(adb.buffer, msg.data_length, 1 * 100)) {
log_error("auth error 0\n");
return 0;
}
log_info("auth not send rsa pub key\n");
return 0;
} else if (msg.command == A_AUTH) {
} else {
log_error("auth error 1\n");
return 1;
}
ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
check_usb_status(ret);
msg.command = A_AUTH;
msg.arg0 = ADB_AUTH_SIGNATURE;
msg.data_length = sizeof(adb_signatrue_data[0]);
if (adb_signatrue_data_index > 2) {
adb_signatrue_data_index = 0;
}
adb_signatrue_data_index ++;
cmd_string = (u8 *)&adb_signatrue_data[adb_signatrue_data_index][0];
ret = adb_send_packet(&msg, cmd_string);
check_usb_status(ret);
ret = adb_send_packet(NULL, NULL);//zero packet
check_usb_status(ret);
memset(&msg, 0, 24);
ret = adb_recv((u8 *)&msg, 24, 1 * 100);
check_usb_status(ret);
if (msg.command != A_AUTH) {
log_error("auth error 2\n");
return 1;
}
ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
check_usb_status(ret);
__RETRY:
msg.command = A_AUTH;
msg.arg0 = ADB_AUTH_RSAPUBLICKEY;
msg.arg1 = 0;
msg.data_length = sizeof(adb_rsa_pub_key);
ret = adb_send_packet(&msg, (u8 *)adb_rsa_pub_key);
check_usb_status(ret);
ret = adb_recv((u8 *)&msg, 24, 30 * 100);
if (ret < 0) {
if (ret == -DEV_ERR_TIMEOUT) {
goto __RETRY;
}
check_usb_status(ret);
}
ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);//最长等待30s,等手机点击确认授权adb
if (ret < 0) {
if (ret == -DEV_ERR_TIMEOUT) {
goto __RETRY;
}
check_usb_status(ret);
}
if (msg.command == A_AUTH) {
goto __RETRY;
}
return 0;
}
u32 adb_shell_login()
{
log_info("%s() %d\n", __func__, __LINE__);
struct amessage msg;
u8 *cmd_string;
/* __AUTH_SUCCESS: */
cmd_string = (u8 *)"shell:";
msg.command = A_OPEN;
msg.arg0 = adb.local_id;
msg.arg1 = 0;
msg.data_length = strlen((char const *)cmd_string) + 1;
int ret = adb_send_packet(&msg, cmd_string);
check_usb_status(ret);
memset(&msg, 0, 24);
ret = adb_recv((u8 *)&msg, 24, 1 * 100);
check_usb_status(ret);
if (msg.command != A_OKAY) {
log_error("A_OKAY error\n");
return 4;
}
ret = adb_recv((u8 *)&msg, 24, 1 * 100);
check_usb_status(ret);
if (msg.command != A_WRTE) {
log_error("A_WRTE error\n");
return 5;
}
adb.remote_id = msg.arg0;
ret = adb_recv(adb.buffer, msg.data_length, 1 * 100);
check_usb_status(ret);
msg.command = A_OKAY;
msg.arg0 = adb.local_id;
msg.arg1 = adb.remote_id;
msg.data_length = 0;
ret = adb_send_packet(&msg, NULL);
check_usb_status(ret);
return 0;
}
static u32 adb_ex_cmd(const char *cmd_string, u8 *echo_buffer, u32 max_len)
{
log_info("%s\n", cmd_string);
int ret;
struct amessage msg;
msg.command = A_WRTE;
msg.arg0 = adb.local_id;
msg.arg1 = adb.remote_id;
msg.data_length = strlen(cmd_string);
ret = adb_send_packet(&msg, (u8 *)cmd_string);
check_usb_status(ret);
memset(&msg, 0, 24);
memset(echo_buffer, 0, max_len);
ret = adb_recv((u8 *)&msg, sizeof(msg), 3 * 100);
check_usb_status(ret);
if (msg.command != A_OKAY) {
return true;
}
u32 offset = 0;
do {
ret = adb_recv((u8 *)&msg, sizeof(msg), 3 * 100);
check_usb_status(ret);
if (msg.command != A_WRTE) {
log_info("command %x\n", msg.command);
return true;
}
if ((offset + msg.data_length) > max_len) {
log_info("%s", echo_buffer);
echo_buffer[offset] = 0;
offset = 0;
}
ret = adb_recv(&echo_buffer[offset], msg.data_length, 3 * 100);
check_usb_status(ret);
offset += msg.data_length;
if (msg.data_length == 0) {
log_info("no data_length\n");
break;
}
if (offset >= max_len) {
}
/* echo_buffer[offset] = '\n'; */
echo_buffer[offset] = 0;
if (echo_buffer[offset - 2] == 0x24 && echo_buffer[offset - 1] == 0x20) {
/* puts("end\n"); */
break;
} else if (echo_buffer[offset - 2] == 0x23 && echo_buffer[offset - 1] == 0x20) {
/* puts("end 1\n"); */
break;
}
msg.command = A_OKAY;
msg.arg0 = adb.local_id;
msg.arg1 = adb.remote_id;
msg.data_length = 0;
ret = adb_send_packet(&msg, NULL);
check_usb_status(ret);
} while (1);
msg.command = A_OKAY;
msg.arg0 = adb.local_id;
msg.arg1 = adb.remote_id;
msg.data_length = 0;
/* puts("exit\n"); */
return adb_send_packet(&msg, NULL);
}
#define APP_ACTIVITY_PATH "com.zh-jieli.gmaeCenter/com.zh-jieli.gameCenter.activity.guide.SplashActivity\n"
#define APP_WEBSITE "http://www.zh-jieli.com\n"
#define APP_BASH_IN_PATH "/sdcard/jilei/active.bash"
#define APP_BASH_OUT_PATH "/data/local/tmp/active.bash"
u32 adb_game_active()
{
log_info("%s() %d\n", __func__, __LINE__);
u32 max_len = adb.max_len;;
u8 *adb_buffer = adb.buffer;
//1,启动app
adb_ex_cmd("am start -n " APP_ACTIVITY_PATH, adb_buffer, max_len);
puts((char *)adb_buffer);
//查找Error字符串,如果找到跳转网页下载app,否则执行adb指令
if (strstr((const char *)adb_buffer, "Error") != NULL) {
adb_ex_cmd("am start -a android.intent.action.VIEW -d " APP_WEBSITE, adb_buffer, max_len);
puts((char *)adb_buffer);
} else {
adb_ex_cmd("dd if=" APP_BASH_IN_PATH " of=" APP_BASH_OUT_PATH "\n", adb_buffer, max_len);
puts((char *)adb_buffer);
adb_ex_cmd("chown shell " APP_BASH_OUT_PATH";chmod 777 "APP_BASH_OUT_PATH "\n", adb_buffer, max_len);
puts((char *)adb_buffer);
adb_ex_cmd("trap \"\" HUP;sh "APP_BASH_OUT_PATH "&\n", adb_buffer, max_len);
puts((char *)adb_buffer);
}
return 0;
}
static void mtp_ptp_open_session(u32 is_mtp)
{
/* usbh_bulk_send_blocking(ADB_HOST_EP, adb_device.extr_out, (u8 *)_open_session, 16); */
/* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 12, 3); */
/* usbh_bulk_send_blocking(ADB_HOST_EP, adb_device.extr_out, (u8 *)get_device_info, sizeof(get_device_info)); */
/* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 512, 3); */
/* usbh_request_bulk_blocking(ADB_HOST_EP, adb_device.extr_in, get_data_buffer(), 12, 3); */
}
static void adb_open_session()
{
struct usb_host_device *host_dev = adb_device.private_data;
if (adb.extr_in && adb.extr_out) {
get_ms_extended_compat_id(host_dev, adb.buffer);
get_device_status(host_dev, NULL);
get_config_descriptor(host_dev, adb.buffer, 0xff);
/* mtp_ptp_open_session(ac6921_data_buffer[0x12] == 0x4d); */
}
}
u32 adb_process()
{
adb.max_len = 1024;
adb.buffer = malloc(adb.max_len);
os_time_dly(20);
do {
adb_open_session();
if (adb_auth()) {
break;
}
if (adb_shell_login()) {
break;
}
adb_game_active();
log_info("adb active succ");
return 0;
} while (0);
free(adb.buffer);
log_info("adb active error");
return 1;
}
void adb_switch_aoa(u32 id)
{
struct usb_host_device *host_dev = adb_device.private_data;
aoa_switch(host_dev);
/* usb_host_remount(id, 3, 30, 50, 1); */
}
#endif //TCFG_ADB_ENABLE
+73
View File
@@ -0,0 +1,73 @@
#ifndef __ADB_H__
#define __ADB_H__
#include "system/task.h"
#include "device/device.h"
#include "usb/scsi.h"
#include "usb_bulk_transfer.h"
#include "usb/host/usb_host.h"
struct adb_device_t {
u32 local_id;
u32 remote_id;
void *buffer;
u32 max_len;
u8 target_epin;
u8 target_epout;
u8 host_epin;
u8 host_epout;
u8 extr_in;
u8 extr_out;
};
u32 usb_adb_interface_ptp_mtp_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
int usb_adb_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
u32 adb_process();
void adb_switch_aoa(u32 id);
#if 1
#define A_SYNC 0x434e5953
#define A_CNXN 0x4e584e43
#define A_OPEN 0x4e45504f
#define A_OKAY 0x59414b4f
#define A_CLSE 0x45534c43
#define A_WRTE 0x45545257
#define A_AUTH 0x48545541
//#define S_ID_LOCAL 0x00003456
/* AUTH packets first argument */
/* Request */
#define ADB_AUTH_TOKEN 1
/* Response */
#define ADB_AUTH_SIGNATURE 2
#define ADB_AUTH_RSAPUBLICKEY 3
#define A_VERSION 0x01000000 // ADB protocol version
#define ADB_VERSION_MAJOR 1 // Used for help/version information
#define ADB_VERSION_MINOR 0 // Used for help/version information
#else
#define A_SYNC 0x53594e43
#define A_CNXN 0x434e584e
#define A_OPEN 0x4f50454e
#define A_OKAY 0x4f4b4159
#define A_CLSE 0x434c5345
#define A_WRTE 0x57525445
#define A_VERSION 0x00000001 // ADB protocol version
#define ADB_VERSION_MAJOR 1 // Used for help/version information
#define ADB_VERSION_MINOR 0 // Used for help/version information
#endif
struct amessage {
unsigned long int command; /* command identifier constant */
unsigned long int arg0; /* first argument */
unsigned long int arg1; /* second argument */
unsigned long int data_length; /* length of payload (0 is allowed) */
unsigned long int data_check; /* checksum of data payload */
unsigned long int magic; /* command ^ 0xffffffff */
};
#endif /*ADB_H*/
@@ -0,0 +1,123 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "typedef.h"
#include "app_config.h"
#if TCFG_ADB_ENABLE
static const u8 _open_session[] = {
0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x02, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00
};
static const u8 get_device_info[] = {
0x0C, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x10, 0x01, 0x00, 0x00, 0x00,
};
static const u8 adb_signatrue_data[][256] = {
{
0xFA, 0xA6, 0xE3, 0x50, 0x3C, 0xC4, 0x95, 0xFE, 0xBB, 0x46, 0xE0, 0x9F, 0xD9, 0x9A, 0x18, 0xC1,
0x28, 0x67, 0xA9, 0x46, 0xF8, 0x20, 0xBF, 0xDB, 0xFE, 0x6B, 0xC8, 0xC4, 0x0A, 0x09, 0xFA, 0x9A,
0xCD, 0x51, 0xE3, 0x67, 0xD1, 0xDF, 0xD2, 0x92, 0xD3, 0x9E, 0xFA, 0x17, 0x76, 0x01, 0xF5, 0xE2,
0xBD, 0x64, 0x9C, 0x92, 0x82, 0x4B, 0xE4, 0x27, 0x21, 0x22, 0x1A, 0x70, 0x99, 0x8F, 0xC5, 0xD5,
0xE2, 0x02, 0x2C, 0xA4, 0x13, 0x08, 0x1E, 0x42, 0x83, 0x5C, 0x7E, 0x3C, 0x1F, 0x97, 0x1B, 0xAF,
0x6F, 0x7E, 0x4F, 0xAB, 0xDA, 0x6A, 0x61, 0x56, 0x03, 0x79, 0xB5, 0xF0, 0x97, 0xEE, 0xEC, 0x88,
0x6F, 0x9E, 0x8D, 0x41, 0xE2, 0x13, 0x9B, 0x21, 0xEE, 0x6F, 0x09, 0x81, 0x62, 0xC1, 0xB5, 0xE7,
0xC2, 0x5C, 0x4A, 0x8C, 0x39, 0xAA, 0x50, 0x08, 0x48, 0xB5, 0x1D, 0xF6, 0x7C, 0x67, 0xD6, 0x39,
0x63, 0x7E, 0x5E, 0x49, 0x3D, 0x9B, 0x49, 0x4B, 0x67, 0x8E, 0x06, 0x31, 0x07, 0x4E, 0x56, 0x8A,
0xC4, 0x9D, 0x84, 0xA9, 0xF4, 0xFC, 0xE3, 0x2D, 0x1D, 0x2A, 0x98, 0x52, 0x40, 0x49, 0x93, 0x71,
0xA7, 0x43, 0x0D, 0x78, 0xEB, 0xFA, 0x49, 0x7A, 0x39, 0xBF, 0xE4, 0x06, 0x08, 0x1B, 0x20, 0x84,
0xDC, 0x64, 0xBB, 0xDE, 0x1A, 0x5E, 0x4B, 0xF8, 0x57, 0xBF, 0x9C, 0x8C, 0xB9, 0x1D, 0xEE, 0xB3,
0x90, 0x17, 0x03, 0x8B, 0x3E, 0x9F, 0x8A, 0x23, 0xEC, 0x30, 0xA7, 0x24, 0x5E, 0x5B, 0x58, 0xAA,
0x5A, 0xAE, 0xE2, 0x14, 0xC1, 0xAE, 0xA3, 0xF9, 0xAF, 0x70, 0xE0, 0x14, 0x7D, 0x73, 0x3B, 0x6D,
0x9B, 0x06, 0x2F, 0xAA, 0xFF, 0x7A, 0x2A, 0x56, 0x6F, 0x91, 0x70, 0x6D, 0x4A, 0x18, 0x35, 0x51,
0xD5, 0x5D, 0xFB, 0xA1, 0x8B, 0x03, 0xF2, 0x0C, 0x56, 0xF0, 0x5A, 0x4A, 0x08, 0x89, 0xFE, 0x86
},
{
0x60, 0xE6, 0x4A, 0x3D, 0x12, 0xD1, 0x48, 0x25, 0x7D, 0x6E, 0x8E, 0x03, 0xE2, 0xC8, 0xE7, 0x66,
0x96, 0xD7, 0xD3, 0xBF, 0xE6, 0x97, 0x13, 0x3A, 0x2D, 0x2B, 0x85, 0xE7, 0xDA, 0x5C, 0x87, 0xD8,
0xDC, 0x88, 0xAC, 0xF7, 0xC3, 0xF0, 0x5A, 0xE8, 0x95, 0x66, 0x19, 0xA1, 0xA8, 0x2A, 0xE1, 0x70,
0x13, 0xF0, 0x05, 0x59, 0x3D, 0x89, 0x04, 0x65, 0x08, 0x03, 0x9C, 0xDC, 0x71, 0x24, 0xC5, 0x9E,
0x4D, 0x82, 0xD8, 0x72, 0x07, 0xFD, 0x8F, 0xD3, 0x37, 0x56, 0x8C, 0xB6, 0x01, 0xDB, 0x08, 0x5B,
0xA3, 0x42, 0x8F, 0xF0, 0xCA, 0xDC, 0x80, 0xEB, 0x32, 0xC4, 0x67, 0x1F, 0x73, 0xAF, 0xF0, 0x56,
0xBC, 0x89, 0x72, 0xB1, 0x7D, 0xDA, 0xA4, 0x79, 0x7D, 0x02, 0x35, 0x38, 0xBA, 0xA0, 0x36, 0xFE,
0x5A, 0x70, 0x93, 0xF5, 0x10, 0x7A, 0x92, 0xE9, 0xD4, 0xB0, 0xED, 0xF3, 0x00, 0xD0, 0x27, 0x79,
0x51, 0x54, 0x38, 0x2D, 0x4C, 0xAA, 0x27, 0xEF, 0xA7, 0x8A, 0x34, 0x4E, 0x4B, 0x29, 0x90, 0xC4,
0x3E, 0xA8, 0x8D, 0x3D, 0x00, 0xD6, 0x84, 0x11, 0x17, 0x32, 0xD6, 0xE9, 0x33, 0x02, 0xCD, 0x04,
0x35, 0x3F, 0x1A, 0xC3, 0x05, 0xCF, 0x6F, 0xF4, 0x39, 0x65, 0xE5, 0x6B, 0x88, 0x1E, 0x25, 0xA1,
0xD7, 0xC0, 0x30, 0xE4, 0x0B, 0x2A, 0x61, 0x6D, 0x61, 0xF1, 0x93, 0xAE, 0xC3, 0x42, 0xDC, 0x15,
0x1D, 0x87, 0x60, 0x09, 0x92, 0x64, 0xC1, 0x63, 0xAD, 0xCA, 0x36, 0x63, 0x0E, 0x69, 0x51, 0x45,
0xD0, 0x18, 0x5E, 0x10, 0x88, 0x7B, 0xD9, 0xDE, 0xA3, 0x12, 0x85, 0xF9, 0x30, 0x01, 0x0A, 0xE1,
0x82, 0xD1, 0x49, 0x44, 0xD9, 0x97, 0xE4, 0xF1, 0x55, 0x2D, 0xE2, 0xF3, 0x32, 0xC8, 0xA0, 0xC8,
0x81, 0xB9, 0x02, 0x87, 0x5C, 0x19, 0xB7, 0x21, 0x6A, 0xB9, 0xB0, 0x81, 0x61, 0x8C, 0x35, 0x78
},
{
0x0C, 0x7E, 0xDC, 0x78, 0x60, 0x1A, 0xC8, 0x9B, 0x3A, 0x23, 0x0B, 0x1D, 0x6F, 0xAE, 0x71, 0x6D,
0xD8, 0x3C, 0xE9, 0xA3, 0x51, 0x90, 0xAA, 0x7B, 0x7E, 0x2F, 0x2B, 0xBD, 0x34, 0xF4, 0x43, 0x3F,
0x77, 0xC4, 0x0E, 0x41, 0x04, 0xD9, 0xD4, 0x9C, 0xB3, 0xD2, 0x6B, 0xE1, 0xC6, 0xA8, 0xEF, 0x50,
0x00, 0x11, 0xE1, 0x08, 0x8B, 0xB4, 0xF1, 0xE3, 0x3D, 0x56, 0x83, 0x07, 0x7F, 0xB8, 0x47, 0xF2,
0x84, 0xD2, 0xA1, 0x50, 0x64, 0x5A, 0x08, 0x42, 0x36, 0x23, 0x09, 0x31, 0x9A, 0x6B, 0x61, 0x6F,
0x60, 0x2C, 0xF2, 0x75, 0x4E, 0x6B, 0xB9, 0x15, 0xEE, 0x3C, 0x5E, 0xA2, 0x7F, 0xA0, 0x41, 0xFE,
0x00, 0x6A, 0x30, 0x49, 0x2C, 0xEC, 0x17, 0x8B, 0x04, 0x32, 0xE9, 0x7A, 0x68, 0xA0, 0xF4, 0xDF,
0x34, 0xF7, 0x1E, 0x6F, 0x19, 0x09, 0x37, 0x87, 0x99, 0xAA, 0x81, 0x1A, 0xCD, 0xF3, 0x1F, 0x89,
0x50, 0xB2, 0x17, 0x52, 0x6D, 0x8E, 0xA6, 0x02, 0xC4, 0x2A, 0xAB, 0x3E, 0x5B, 0x38, 0x0C, 0x3F,
0x50, 0xAA, 0x5F, 0xFE, 0x47, 0x04, 0xED, 0xCD, 0xEE, 0x7C, 0xD5, 0xED, 0x5F, 0x0E, 0xC6, 0x9C,
0x79, 0x10, 0x11, 0x6F, 0x65, 0x58, 0x37, 0x95, 0x54, 0x50, 0x59, 0x68, 0x4C, 0x8E, 0xE7, 0x35,
0xF0, 0x96, 0x5A, 0x21, 0x48, 0xB4, 0x53, 0x52, 0xFC, 0xA4, 0x7C, 0x2B, 0xB1, 0xE1, 0x54, 0x2C,
0x42, 0x3B, 0x68, 0xBF, 0xBB, 0x68, 0x0D, 0x62, 0x16, 0x2F, 0xF5, 0xC8, 0x5F, 0x95, 0x11, 0xF2,
0xDF, 0x03, 0x1E, 0xCB, 0x7C, 0xD0, 0x9C, 0xE9, 0x89, 0x62, 0xEA, 0xC5, 0x4B, 0xA9, 0xD5, 0xCC,
0xD2, 0x42, 0x33, 0xA8, 0x7B, 0x2C, 0x56, 0xCF, 0xCE, 0x0D, 0x09, 0x64, 0x62, 0x3F, 0x58, 0x41,
0x71, 0x79, 0x5D, 0x1D, 0xDF, 0x08, 0x0B, 0x36, 0x97, 0x16, 0x24, 0x20, 0x76, 0x9C, 0x9E, 0xEA
}
};
static const u8 adb_rsa_pub_key[] = {
0x51, 0x41, 0x41, 0x41, 0x41, 0x46, 0x4F, 0x56, 0x4F, 0x6E, 0x49, 0x6C, 0x69, 0x51, 0x58, 0x44,
0x73, 0x42, 0x43, 0x42, 0x31, 0x75, 0x6F, 0x68, 0x70, 0x2B, 0x52, 0x71, 0x6E, 0x6E, 0x59, 0x48,
0x2F, 0x75, 0x45, 0x58, 0x34, 0x59, 0x6A, 0x50, 0x71, 0x52, 0x4D, 0x35, 0x4B, 0x75, 0x62, 0x56,
0x50, 0x71, 0x66, 0x57, 0x35, 0x64, 0x56, 0x46, 0x33, 0x2B, 0x76, 0x57, 0x6B, 0x53, 0x4B, 0x71,
0x35, 0x4C, 0x31, 0x42, 0x4F, 0x4E, 0x4D, 0x36, 0x4B, 0x4F, 0x31, 0x69, 0x31, 0x73, 0x69, 0x4F,
0x54, 0x69, 0x34, 0x6C, 0x45, 0x30, 0x6F, 0x54, 0x6F, 0x74, 0x30, 0x41, 0x4B, 0x6E, 0x4D, 0x67,
0x4E, 0x6A, 0x6F, 0x33, 0x45, 0x4D, 0x65, 0x72, 0x30, 0x6C, 0x57, 0x56, 0x54, 0x54, 0x43, 0x39,
0x68, 0x52, 0x66, 0x67, 0x46, 0x65, 0x56, 0x73, 0x43, 0x32, 0x44, 0x74, 0x71, 0x62, 0x61, 0x6D,
0x4A, 0x48, 0x63, 0x41, 0x66, 0x59, 0x77, 0x36, 0x54, 0x62, 0x4C, 0x44, 0x6C, 0x4B, 0x70, 0x6A,
0x38, 0x34, 0x33, 0x63, 0x31, 0x59, 0x5A, 0x65, 0x59, 0x6D, 0x52, 0x56, 0x4D, 0x7A, 0x4D, 0x34,
0x6E, 0x74, 0x49, 0x78, 0x64, 0x56, 0x33, 0x33, 0x76, 0x4B, 0x75, 0x39, 0x38, 0x34, 0x6A, 0x72,
0x43, 0x41, 0x47, 0x68, 0x77, 0x4A, 0x41, 0x67, 0x4A, 0x46, 0x53, 0x41, 0x4B, 0x56, 0x59, 0x51,
0x55, 0x33, 0x6A, 0x4C, 0x76, 0x41, 0x76, 0x57, 0x45, 0x6C, 0x59, 0x47, 0x37, 0x2F, 0x4B, 0x59,
0x6D, 0x55, 0x34, 0x54, 0x71, 0x73, 0x70, 0x64, 0x76, 0x4C, 0x42, 0x6F, 0x65, 0x36, 0x68, 0x64,
0x46, 0x44, 0x65, 0x76, 0x4D, 0x4D, 0x43, 0x63, 0x72, 0x6C, 0x44, 0x49, 0x66, 0x65, 0x45, 0x53,
0x57, 0x68, 0x42, 0x56, 0x35, 0x67, 0x78, 0x6A, 0x57, 0x41, 0x70, 0x4D, 0x47, 0x67, 0x53, 0x71,
0x53, 0x45, 0x6A, 0x70, 0x36, 0x79, 0x62, 0x6A, 0x33, 0x38, 0x50, 0x4C, 0x72, 0x76, 0x49, 0x51,
0x48, 0x77, 0x2B, 0x66, 0x70, 0x6F, 0x51, 0x74, 0x6F, 0x4F, 0x4E, 0x65, 0x37, 0x6F, 0x68, 0x66,
0x42, 0x77, 0x45, 0x66, 0x47, 0x46, 0x4E, 0x63, 0x33, 0x61, 0x70, 0x48, 0x50, 0x6E, 0x59, 0x53,
0x47, 0x4F, 0x67, 0x70, 0x54, 0x78, 0x70, 0x57, 0x57, 0x75, 0x49, 0x42, 0x79, 0x2F, 0x67, 0x38,
0x35, 0x2B, 0x65, 0x54, 0x30, 0x44, 0x61, 0x36, 0x53, 0x65, 0x71, 0x33, 0x67, 0x62, 0x4A, 0x59,
0x64, 0x75, 0x52, 0x44, 0x65, 0x36, 0x5A, 0x39, 0x63, 0x4A, 0x77, 0x48, 0x79, 0x38, 0x43, 0x34,
0x59, 0x79, 0x6B, 0x44, 0x56, 0x45, 0x4B, 0x6A, 0x39, 0x75, 0x52, 0x41, 0x41, 0x45, 0x59, 0x70,
0x52, 0x6B, 0x74, 0x39, 0x66, 0x34, 0x79, 0x51, 0x4A, 0x31, 0x73, 0x4D, 0x48, 0x31, 0x5A, 0x75,
0x4F, 0x55, 0x46, 0x4A, 0x46, 0x65, 0x74, 0x6B, 0x72, 0x67, 0x32, 0x44, 0x46, 0x61, 0x35, 0x30,
0x50, 0x39, 0x48, 0x61, 0x78, 0x6F, 0x4D, 0x59, 0x30, 0x41, 0x79, 0x78, 0x7A, 0x51, 0x72, 0x53,
0x77, 0x4D, 0x44, 0x79, 0x6E, 0x36, 0x64, 0x49, 0x65, 0x38, 0x65, 0x58, 0x46, 0x78, 0x51, 0x62,
0x56, 0x4D, 0x4F, 0x6C, 0x4B, 0x36, 0x79, 0x33, 0x70, 0x6F, 0x2B, 0x4A, 0x4D, 0x42, 0x34, 0x79,
0x4D, 0x42, 0x36, 0x51, 0x77, 0x30, 0x7A, 0x31, 0x35, 0x62, 0x6F, 0x58, 0x4C, 0x78, 0x4D, 0x4B,
0x76, 0x4E, 0x59, 0x6E, 0x4B, 0x4E, 0x70, 0x69, 0x6F, 0x33, 0x67, 0x45, 0x78, 0x5A, 0x2B, 0x48,
0x68, 0x57, 0x62, 0x43, 0x47, 0x69, 0x37, 0x64, 0x4A, 0x6C, 0x56, 0x47, 0x50, 0x6F, 0x74, 0x34,
0x4D, 0x42, 0x45, 0x4C, 0x7A, 0x43, 0x38, 0x66, 0x4C, 0x55, 0x44, 0x69, 0x41, 0x43, 0x49, 0x54,
0x37, 0x75, 0x31, 0x58, 0x31, 0x62, 0x68, 0x65, 0x71, 0x6C, 0x35, 0x59, 0x7A, 0x43, 0x30, 0x6C,
0x67, 0x2F, 0x4B, 0x48, 0x5A, 0x7A, 0x62, 0x36, 0x6D, 0x63, 0x74, 0x4E, 0x2B, 0x34, 0x62, 0x52,
0x74, 0x79, 0x4B, 0x35, 0x75, 0x52, 0x52, 0x4A, 0x70, 0x48, 0x45, 0x56, 0x63, 0x4B, 0x58, 0x57,
0x50, 0x34, 0x30, 0x73, 0x31, 0x79, 0x38, 0x37, 0x75, 0x30, 0x6D, 0x49, 0x50, 0x4A, 0x6E, 0x73,
0x39, 0x6D, 0x4F, 0x2F, 0x2F, 0x44, 0x41, 0x35, 0x4C, 0x32, 0x6D, 0x64, 0x77, 0x56, 0x79, 0x73,
0x72, 0x74, 0x4B, 0x51, 0x69, 0x51, 0x37, 0x36, 0x57, 0x6A, 0x74, 0x59, 0x51, 0x63, 0x41, 0x73,
0x46, 0x2B, 0x42, 0x54, 0x4E, 0x56, 0x48, 0x62, 0x41, 0x6E, 0x7A, 0x7A, 0x52, 0x75, 0x6C, 0x52,
0x61, 0x43, 0x45, 0x78, 0x2B, 0x6E, 0x30, 0x49, 0x6A, 0x35, 0x34, 0x49, 0x45, 0x41, 0x4F, 0x75,
0x55, 0x4B, 0x70, 0x6F, 0x61, 0x48, 0x71, 0x6F, 0x56, 0x4F, 0x33, 0x51, 0x42, 0x36, 0x52, 0x41,
0x51, 0x7A, 0x4D, 0x67, 0x70, 0x44, 0x73, 0x41, 0x30, 0x58, 0x34, 0x4C, 0x6A, 0x4F, 0x32, 0x52,
0x2B, 0x4D, 0x4B, 0x6F, 0x6D, 0x6F, 0x6C, 0x52, 0x5A, 0x6F, 0x32, 0x34, 0x57, 0x32, 0x41, 0x35,
0x57, 0x2B, 0x30, 0x56, 0x4A, 0x77, 0x45, 0x41, 0x41, 0x51, 0x41, 0x3D, 0x20, 0x75, 0x6E, 0x6B,
0x6E, 0x6F, 0x77, 0x6E, 0x40, 0x75, 0x6E, 0x6B, 0x6E, 0x6F, 0x77, 0x6E, 0x00
};
#endif
+255
View File
@@ -0,0 +1,255 @@
/**
* @file aoa.c
* @brief https://source.android.com/devices/accessories/aoa
* http://www.hackermi.com/2015-04/aoa-analyse/
* Android 开放配件协议 1.0
* @author chenrixin@zh-jieli.com
* @version 1
* @date 2020-03-25
*/
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "system/includes.h"
#include "app_config.h"
#include "usb_config.h"
#include "usb/host/usb_host.h"
#include "usb/usb_phy.h"
#include "device_drive.h"
#include "usb_ctrl_transfer.h"
#include "usb_bulk_transfer.h"
#include "usb_storage.h"
#include "adb.h"
#include "aoa.h"
#include "usb_hid_keys.h"
#include "usb/usb_task.h"
#if TCFG_AOA_ENABLE
#include "gamebox.h"
#define LOG_TAG_CONST USB
#define LOG_TAG "[AOA]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
//0x2D00 有一个接口,该接口有两个批量端点,用于输入和输出通信。
//0x2D01 有两个接口,每个接口有两个批量端点,用于输入和输出通信。
//第一个接口处理标准通信,
//第二个接口则处理 ADB 通信。
//要使用接口,请找到第一个批量输入和输出端点,
//使用 SET_CONFIGURATION (0x09) 设备请求将设备配置的值设为 1,然后使用端点进行通信
//
static void aoa_timer_handler(void *priv);
static u32 aoa_timer_id;
static struct aoa_device_t aoa;
static struct device aoa_device;
static u8 *aoa_bulk_ep_in_buf;
static u8 *aoa_bulk_ep_out_buf;
static int set_power(struct usb_host_device *host_dev, u32 value)
{
if (aoa_timer_id) {
usr_timer_del(aoa_timer_id);
aoa_timer_id = 0;
}
return DEV_ERR_NONE;
}
static int get_power(struct usb_host_device *host_dev, u32 value)
{
return DEV_ERR_NONE;
}
static const struct interface_ctrl aoa_ctrl = {
.interface_class = USB_CLASS_AOA,
.set_power = set_power,
.get_power = get_power,
.ioctl = NULL,
};
static const struct usb_interface_info aoa_inf = {
.ctrl = (struct interface_ctrl *) &aoa_ctrl,
.dev.aoa = &aoa,
};
static const char *credetials[] = {"JieLiTec",
"GameBox",
"Android accessories devcie !",
"1.0.0",
"http://www.zh-jieli.com",
"1234567890ABCDEF",
};
void aoa_switch(struct usb_host_device *host_dev)
{
u16 version;
log_info("aoa_switch");
usb_get_aoa_version(host_dev, &version);
log_info("AOA version: %x", version);
for (int i = 0; i < 5; i++) {
log_info("send string [%d] %s", i, credetials[i]);
int r = usb_set_credentials(host_dev, credetials[i], i);
if (r < 0) {
break;
}
}
usb_switch2aoa(host_dev);
}
int usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
pBuf += sizeof(struct usb_interface_descriptor);
int len = 0;
aoa_device.private_data = host_dev;
host_dev->interface_info[interface_num] = &aoa_inf;
for (int endnum = 0; endnum < interface->bNumEndpoints; endnum++) {
struct usb_endpoint_descriptor *end_desc = (struct usb_endpoint_descriptor *)pBuf;
if (end_desc->bDescriptorType != USB_DT_ENDPOINT ||
end_desc->bLength != USB_DT_ENDPOINT_SIZE) {
log_error("ep bDescriptorType = %d bLength = %d", end_desc->bDescriptorType, end_desc->bLength);
return -USB_DT_ENDPOINT;
}
len += USB_DT_ENDPOINT_SIZE;
pBuf += USB_DT_ENDPOINT_SIZE;
if ((end_desc->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) == USB_ENDPOINT_XFER_BULK) {
if (end_desc->bEndpointAddress & USB_DIR_IN) {
aoa.target_epin = end_desc->bEndpointAddress & 0x0f;
#if defined(FUSB_MODE) && FUSB_MODE == 0
aoa.rxmaxp = end_desc->wMaxPacketSize;
#endif
} else {
aoa.target_epout = end_desc->bEndpointAddress & 0x0f;
#if defined(FUSB_MODE) && FUSB_MODE == 0
aoa.txmaxp = end_desc->wMaxPacketSize;
#endif
}
}
}
return len;
}
static int aoa_tx_data(const u8 *pbuf, u32 len)
{
struct usb_host_device *host_dev = aoa_device.private_data;
usb_dev usb_id = host_device2id(host_dev);
g_printf("TX:");
printf_buf(pbuf, len);
return usb_h_ep_write_async(usb_id, aoa.host_epout, 64, aoa.target_epout, pbuf, len, USB_ENDPOINT_XFER_BULK, 1);
}
static void aoa_epin_isr(struct usb_host_device *host_dev, u32 ep)
{
u8 buffer[64] = {0};
usb_dev usb_id = host_device2id(host_dev);
u32 rx_len = usb_h_ep_read_async(usb_id, ep, aoa.target_epin, buffer, sizeof(buffer), USB_ENDPOINT_XFER_BULK, 0);
g_printf("RX:");
printf_buf(buffer, rx_len);
usb_h_ep_read_async(usb_id, ep, aoa.target_epin, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);
}
#define Accessory_assigned_ID 0x0001
u32 aoa_process(u32 mode, u32 id)
{
struct usb_host_device *host_dev = aoa_device.private_data;
struct usb_device_descriptor device_desc;
usb_get_device_descriptor(host_dev, &device_desc);
if ((device_desc.idVendor == 0x18d1) &&
((device_desc.idProduct & 0x2d00) == 0x2d00)) {
log_info("aoa mode ready idVendor:%x idProduct: %x",
device_desc.idVendor, device_desc.idProduct);
} else {
log_info("aoa switch idVendor:%x idProduct: %x",
device_desc.idVendor, device_desc.idProduct);
aoa_switch(host_dev);
//usb_host_remount(id, 3, 30, 50, 1);
int msg[2];
msg[0] = id;
msg[1] = 0;
usb_message_to_stack(USBSTACK_HOST_REMOUNT, msg, 0);
return 0;
}
usb_aoa_register_hid(host_dev, Accessory_assigned_ID, sizeof(hid_report_desc));
u32 offset = 0;
while (offset < sizeof(hid_report_desc)) {
u32 cnt = min(sizeof(hid_report_desc) - offset, 63);
usb_aoa_set_hid_report_desc(host_dev, Accessory_assigned_ID, offset, &hid_report_desc[offset], cnt);
offset += cnt;
}
aoa.host_epout = usb_get_ep_num(id, USB_DIR_OUT, USB_ENDPOINT_XFER_BULK);
aoa.host_epin = usb_get_ep_num(id, USB_DIR_IN, USB_ENDPOINT_XFER_BULK);
log_debug("D(%d)->H(%d)", aoa.target_epin, aoa.host_epin);
log_debug("H(%d)->D(%d)", aoa.host_epout, aoa.target_epout);
usb_h_set_ep_isr(host_dev, aoa.host_epin | USB_DIR_IN, aoa_epin_isr, host_dev);
if (!aoa_bulk_ep_in_buf) {
aoa_bulk_ep_in_buf = usb_h_alloc_ep_buffer(id, aoa.host_epin | USB_DIR_IN, 64 * 2);
}
#ifdef USB_HW_20
usb_write_rxfuncaddr(id, aoa.host_epin, host_dev->private_data.devnum);
#endif
usb_h_ep_config(id, aoa.host_epin | USB_DIR_IN, USB_ENDPOINT_XFER_BULK, 1, 0, aoa_bulk_ep_in_buf, 64);
usb_h_ep_read_async(id, aoa.host_epin, aoa.target_epin, NULL, 0, USB_ENDPOINT_XFER_BULK, 1);
if (!aoa_bulk_ep_out_buf) {
aoa_bulk_ep_out_buf = usb_h_alloc_ep_buffer(id, aoa.host_epout | USB_DIR_OUT, 64);
}
#ifdef USB_HW_20
usb_write_txfuncaddr(id, aoa.host_epout, host_dev->private_data.devnum);
#endif
usb_h_ep_config(id, aoa.host_epout | USB_DIR_OUT, USB_ENDPOINT_XFER_BULK, 0, 0, aoa_bulk_ep_out_buf, 64);
aoa_timer_id = usr_timer_add((void *)0, aoa_timer_handler, 4, 0);
g_printf("aoa succ");
return 1;
}
static void aoa_timer_handler(void *priv)
{
struct usb_host_device *host_dev = aoa_device.private_data;
u8 tx_buffer[32];
if (mouse_data_send == 1) {
tx_buffer[0] = MOUSE_POINT_ID;
memcpy(&tx_buffer[1], &mouse_data, sizeof(mouse_data));
usb_aoa_send_hid_event(host_dev, Accessory_assigned_ID, tx_buffer, sizeof(mouse_data) + 1);
memset(&mouse_data, 0, sizeof(mouse_data)) ;
mouse_data_send = 0;
}
tx_buffer[0] = TOUCH_SCREEN_ID;
struct touch_screen_t t;
memset(&t, 0, sizeof(t));
if (point_list_pop(&t)) {
memcpy(&tx_buffer[1], &t, sizeof(t));
usb_aoa_send_hid_event(host_dev, Accessory_assigned_ID, tx_buffer, sizeof(t) + 1);
}
}
#endif
+20
View File
@@ -0,0 +1,20 @@
#ifndef __AOA_H__
#define __AOA_H__
struct aoa_device_t {
u16 version;
u8 target_epin;
u8 target_epout;
u8 host_epin;
u8 host_epout;
struct adb_device_t *adb;
};
u32 aoa_process(u32 mode, u32 id);
int usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
#endif /*AOA_H*/
@@ -0,0 +1,8 @@
#ifndef _APPLE_MFI_H_
#define _APPLE_MFI_H_
int usb_apple_mfi_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
#endif
+56
View File
@@ -0,0 +1,56 @@
#ifndef __AUDIO_H__
#define __AUDIO_H__
#include "system/task.h"
#include "device/device.h"
#include "usb_bulk_transfer.h"
#include "usb/host/usb_host.h"
#include "usb/device/uac_audio.h"
#define HEADPHONE_SUPPORTED 0x01
#define MICROPHONE_SUPPORTED 0x02
#define HEADSET_SUPPORTED 0x03
struct audio_streaming_t {
u8 bNumEndpoints;
u8 bFormatType; /** FORMAT_TYPE_1 */
u8 bNrChannels; /** physical channels in the stream */
u8 bSubframeSize;
u8 bBitResolution;
u8 bSamFreqType;
u32 tSamFreq[8];
u8 host_ep; //主机传输端点
u8 ep; //从机端点(由描述符中指定)
u8 ep_Interval;
u16 ep_max_packet_size;
};
struct audio_device_t {
u8 interface_num; //接口号
u8 subclass;
u8 support;
void *parent;
struct audio_streaming_t as[8];
};
int usb_audio_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
// API
int usb_audio_play_put_buf(void *ptr, u32 len);
int usb_audio_record_get_buf(void *ptr, u32 len);
//headphone api
void set_usb_audio_play_volume(u16 vol);
void usb_audio_start_play(const usb_dev usb_id, u8 channel, u8 bit_reso, u32 sample_rate); //指定播放数据的声道数,位数,采样率
void usb_audio_stop_play(const usb_dev usb_id);
void usb_audio_pause_play(void);
void usb_audio_resume_play(void);
//microphone api
void set_usb_audio_record_volume(u16 vol);
void usb_audio_start_record(const usb_dev usb_id, u8 bit_reso, u32 sample_rate); //指定录制数据的位数,采样率
void usb_audio_stop_record(const usb_dev usb_id);
void usb_audio_pause_record(void);
void usb_audio_resume_record(void);
#endif
+672
View File
@@ -0,0 +1,672 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "system/includes.h"
#include "cpu/includes.h"
#include "app_config.h"
#include "system/timer.h"
#include "device/ioctl_cmds.h"
#include "device_drive.h"
#if TCFG_HID_HOST_ENABLE
#include "usb/host/usb_host.h"
#include "usb_ctrl_transfer.h"
#include "usb_bulk_transfer.h"
#include "hid.h"
#include "usb_config.h"
#include "usb_hid_keys.h"
#define MAIN_ITEM 0
#define GLOBAL_ITEM 1
#define LOCAL_ITEM 2
#define LOG_TAG_CONST USB
#define LOG_TAG "[HID]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
struct hid_device_t hid_device[USB_MAX_HW_NUM][MAX_HOST_INTERFACE];
static u8 *hid_intr_ep_in_buf[USB_MAX_HW_NUM];
static int set_power(struct usb_host_device *host_dev, u32 value)
{
const usb_dev usb_id = host_device2id(host_dev);
memset(hid_device[usb_id], 0, sizeof(hid_device[usb_id]));
return DEV_ERR_NONE;
}
static int get_power(struct usb_host_device *host_dev, u32 value)
{
return DEV_ERR_NONE;
}
static const struct interface_ctrl hid_ctrl = {
.interface_class = USB_CLASS_HID,
.set_power = set_power,
.get_power = get_power,
.ioctl = NULL,
};
static const struct usb_interface_info _usb_if[USB_MAX_HW_NUM][MAX_HOST_INTERFACE] = {
{
{
.ctrl = (struct interface_ctrl *) &hid_ctrl,
.dev.hid = &hid_device[0][0],
},
{
.ctrl = (struct interface_ctrl *) &hid_ctrl,
.dev.hid = &hid_device[0][1],
},
{
.ctrl = (struct interface_ctrl *) &hid_ctrl,
.dev.hid = &hid_device[0][2],
},
{
.ctrl = (struct interface_ctrl *) &hid_ctrl,
.dev.hid = &hid_device[0][3],
},
},
#if USB_MAX_HW_NUM > 1
{
{
.ctrl = (struct interface_ctrl *) &hid_ctrl,
.dev.hid = &hid_device[1][0],
},
{
.ctrl = (struct interface_ctrl *) &hid_ctrl,
.dev.hid = &hid_device[1][1],
},
{
.ctrl = (struct interface_ctrl *) &hid_ctrl,
.dev.hid = &hid_device[1][2],
},
{
.ctrl = (struct interface_ctrl *) &hid_ctrl,
.dev.hid = &hid_device[1][3],
},
},
#endif
};
static u8 interval[USB_MAX_HW_NUM][16];
int usb_hid_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
pBuf += sizeof(struct usb_interface_descriptor);
const usb_dev usb_id = host_device2id(host_dev);
struct usb_endpoint_descriptor *endpoint;
pBuf += 9;//hid desc;
const struct usb_interface_info *usb_if = &_usb_if[usb_id][interface_num];
memset(usb_if->dev.p, 0, sizeof(struct hid_device_t));
host_dev->interface_info[interface_num] = usb_if;
usb_if->dev.hid->parent = host_dev;
log_info("hid eps %d %d %x %x", interface->bNumEndpoints, interface_num, usb_if, usb_if->dev.p);
log_info("parent %x hid @ interface %d usb_if %x hid %x",
host_dev, interface_num, usb_if, usb_if->dev.hid);
if ((interface->bInterfaceProtocol == 0x02) ||
(interface->bInterfaceProtocol == 0x01)) { //mouse & keyboard
usb_if->dev.hid->bNumEndpoints = interface->bNumEndpoints;
usb_if->dev.hid->report_list[0].usage = interface->bInterfaceProtocol;
for (int i = 0 ; i < interface->bNumEndpoints; i++) {
endpoint = (struct usb_endpoint_descriptor *)pBuf;
if (USB_DIR_IN & endpoint->bEndpointAddress) {
const u8 ep = endpoint->bEndpointAddress & 0x0f;
usb_if->dev.hid->ep_pair[i] = ep;
interval[usb_id][ep] = endpoint->bInterval;
log_info("interfacenum = %d,endpoint = %x interval = %x",
interface->bInterfaceNumber, endpoint->bEndpointAddress, endpoint->bInterval);
}
pBuf += endpoint->bLength;
}
} else {
log_info("vendor");
host_dev->interface_info[interface_num] = NULL; //???
for (int i = 0 ; i < interface->bNumEndpoints; i++) {
endpoint = (struct usb_endpoint_descriptor *)pBuf;
if (USB_DIR_IN & endpoint->bEndpointAddress) {
/* interface_endpoint[interface->bInterfaceNumber] = endpoint->bEndpointAddress & 0x0f; */
log_info("interfacenum = %d,endpoint = %x interval = %x",
interface->bInterfaceNumber, endpoint->bEndpointAddress, endpoint->bInterval);
}
pBuf += endpoint->bLength;
}
return sizeof(struct usb_interface_descriptor);
}
return pBuf - (u8 *)interface;
}
static u32 _hid_report_parse(struct hid_device_t *hid, const u8 *report, u32 len)
{
hid->report_count = 0;
struct report_info_t null_rpt;
struct report_info_t *const rpt = &null_rpt;
memset(rpt, 0, sizeof(*rpt));
unsigned char ops;
int index = 0;
u8 report_size = 0;
u8 report_count = 0;
u8 cur_ops_is_report_size_count;
u8 old_ops_is_report_size_count = 0;
s8 cur_section_bit = 0;
u8 input_bit_index = 0;
u8 total_bits = 0;
u8 output_bit_index = 0;
u8 cur_usage = 0;
u32 undef_type = 0;
u8 undef_usage = 0;
u8 collection_deep = 0;
while (index < len) {
ops = (char)report[index++];
char bSize = ops & 0x03;
bSize = bSize == 3 ? 4 : bSize; // size is 4 when bSize is 3
char bType = (ops >> 2) & 0x03;
char bTag = (ops >> 4) & 0x0F;
cur_ops_is_report_size_count = 0;
char bSizeActual = 0;
int itemVal = 0;
for (int j = 0; j < bSize; j++) {
if (index + j < len) {
itemVal += report[index + j] << (8 * j);
bSizeActual++;
}
}
if (undef_type) {
undef_type ++;
if (bTag == 0x0A) {
undef_usage ++;
} else if (bTag == 0x0C) {
undef_usage --;
}
if (undef_usage == 0 && undef_type > 2) {
undef_type = 0;
}
index += bSize;
continue;
}
if (undef_type) {
index += bSize;
continue;
}
if (itemVal == 0xffb5) {
undef_type = 1;
index += bSize;
continue;
} else {
undef_type = 0;
}
if (bType == MAIN_ITEM) {
if (old_ops_is_report_size_count) {
cur_section_bit += report_size * report_count;
}
if (bTag == 0x08) {
/* log_info("input %X", itemVal); */
/* log_info("\tusage %x", cur_usage); */
/* log_info("\t\tcur_section_bit %d", cur_section_bit); */
if (rpt->usage == 0x02) { //mouse
if (cur_usage == 1) {
if (rpt->btn_start_bit == 0) {
rpt->btn_start_bit = total_bits ;
}
rpt->btn_width += cur_section_bit ;
/* log_info("btn_width %d-%d", rpt->btn_start_bit, rpt->btn_width); */
} else if ((cur_usage == 0x30) || (cur_usage == 0x31)) {
if (rpt->xy_start_bit == 0) {
rpt->xy_start_bit = total_bits;
}
rpt->xy_width = cur_section_bit;
/* log_info("xy_width %d-%d", rpt->xy_start_bit, rpt->xy_width); */
} else if (cur_usage == 0x38) {
if (rpt->wheel_start_bit == 0) {
rpt->wheel_start_bit = total_bits;
}
if (rpt->xy_width || cur_section_bit < 24) {
rpt->wheel_width = cur_section_bit;
/* log_info("wheel_width %d-%d", rpt->wheel_start_bit, rpt->wheel_width); */
} else {
rpt->wheel_width = rpt->xy_width = cur_section_bit / 3;
rpt->xy_start_bit = total_bits;
rpt->wheel_start_bit = rpt->xy_start_bit + rpt->xy_width * 2;
/* log_info("wheel_width %d-%d", rpt->wheel_start_bit, rpt->wheel_width); */
/* log_info("xy_width %d-%d", rpt->xy_start_bit, rpt->xy_width); */
}
} else if (cur_usage == 0xb8) {
rpt->wheel_width = rpt->xy_width = cur_section_bit / 4;
rpt->xy_start_bit = total_bits;
rpt->wheel_start_bit = rpt->xy_start_bit + rpt->xy_width * 2;
}
}
total_bits += cur_section_bit;
/* input_bit[input_bit_index++] = cur_section_bit; */
cur_section_bit = -1;
} else if (bTag == 0x09) {
/* log_info("OUTPUT %X", itemVal); */
/* log_info("\tusage %x", cur_usage); */
/* log_info("\t\tcur_section_bit %d", cur_section_bit); */
/* output_bit[output_bit_index++] = cur_section_bit; */
cur_section_bit = -1;
} else if (bTag == 0x0B) {
/* log_info("Feature %X", itemVal); */
/* log_info("\tusage %x", cur_usage); */
/* log_info("\t\tcur_section_bit %d", cur_section_bit); */
/* output_bit[output_bit_index++] = cur_section_bit; */
cur_section_bit = -1;
} else if (bTag == 0x0A) {
collection_deep ++ ;
log_info("Collection %d %x", collection_deep, rpt->usage);
} else if (bTag == 0x0C) {
collection_deep --;
log_info("End Collection %d %x", collection_deep, rpt->usage);
if (collection_deep == 0) {
if (rpt->usage == 0x02 ||
rpt->usage == 0x06 ||
rpt->usage == 0x07) {
memcpy(&hid->report_list[hid->report_count], rpt, sizeof(*rpt));
memset(rpt, 0, sizeof(*rpt));
hid->report_count ++;
}
}
if (index < len) {
continue;
}
} else {
log_info("MAIN_ITEM Unknown btag :%x", bTag);
return 1;
}
} else if (bType == GLOBAL_ITEM) {
/* log_info("GLOBAL_ITEM"); */
if (bTag == 0x00) {
/* log_info("Usage Page %x", itemVal); */
if (rpt->usage == 0x06) {
if (itemVal == 0x07) {
rpt->usage = 0x07;
log_info("re set type %x", 0x07);
}
}
if (itemVal == 0x02) {
rpt->usage = 0x02;
log_info("re set type %x", 0x02);
}
} else if (bTag == 0x01) {
//log_info("Logical Minimum %x", itemVal);
} else if (bTag == 0x02) {
//log_info("Logical Maximum %x", itemVal);
} else if (bTag == 0x03) {
/* log_info("Physical Minimum %x", itemVal); */
} else if (bTag == 0x04) {
/* log_info("Physical Maximum %x", itemVal); */
} else if (bTag == 0x05) {
/* log_info("Unit Exponent %x", itemVal); */
} else if (bTag == 0x06) {
/* log_info("Unit %x", itemVal); */
} else if (bTag == 0x07) {
/* log_info("Report Size %x", itemVal); */
report_size = itemVal;
cur_ops_is_report_size_count = 1;
} else if (bTag == 0x08) {
log_info("Report ID %x", itemVal, rpt->usage);
rpt->report_id = itemVal;
} else if (bTag == 0x09) {
/* log_info("Report Count %x", itemVal); */
report_count = itemVal;
cur_ops_is_report_size_count = 1;
} else if (bTag == 0x0A) {
/* log_info("Push %x", bSizeActual); */
} else if (bTag == 0x0B) {
/* log_info("Pop %x", bSizeActual); */
} else {
log_info("GLOBAL_ITEM Unknown btag :%x", bTag);
return 2;
}
} else if (bType == LOCAL_ITEM) {
/* log_info("LOCAL_ITEM"); */
if (bTag == 0x00) {
if (rpt->usage == 0) {
rpt->usage = itemVal;
log_info("set type %x", rpt->usage);
}
if (itemVal == 0x30) { //X
} else if (itemVal == 0x31) { //y
} else if (itemVal == 0x38) { //wheel
} else {
}
/* log_info("\t change usage %x -> %x", cur_usage, itemVal); */
cur_usage = itemVal;
if (!collection_deep) {
if (itemVal == 0x06 || itemVal == 0x07 || itemVal == 0x02) {
//仅限键盘和鼠标
rpt->usage = itemVal;
log_info("set typee %x", rpt->usage);
}
}
/* type = itemVal; */
} else if (bTag == 0x01) {
// log_info("Usage Minimum %x", itemVal);
} else if (bTag == 0x02) {
// log_info("Usage Maximum %x", itemVal);
} else if (bTag == 0x03) {
/* log_info("Designator Index %x", itemVal); */
} else if (bTag == 0x04) {
/* log_info("Designator Minimum %x", itemVal); */
} else if (bTag == 0x05) {
/* log_info("Designator Maximum %x", itemVal); */
} else if (bTag == 0x07) {
/* log_info("String Index %x", itemVal); */
} else if (bTag == 0x08) {
/* log_info("String Minimum %x", itemVal); */
} else if (bTag == 0x09) {
/* log_info("String Maximum %x", itemVal); */
} else if (bTag == 0x0A) {
/* log_info("Delimiter %x", itemVal); */
} else {
log_info("LOCAL_ITEM Unknown btag :%x", bTag);
return 3;
}
} else {
log_info("OTHER Unknown btag :%x", bTag);
return 4;
}
if (!cur_ops_is_report_size_count && old_ops_is_report_size_count) {
if (cur_section_bit != -1) {
cur_section_bit += report_size * report_count;
} else {
cur_section_bit = 0;
}
}
if (cur_section_bit == -1) {
cur_section_bit = 0;
}
old_ops_is_report_size_count = cur_ops_is_report_size_count;
index += bSize;
}
return 0;
}
static u32 hid_report_parse(struct hid_device_t *hid, const u8 *report, u32 len)
{
/* u8 type = */_hid_report_parse(hid, report, len);
for (int i = 0; i < hid->report_count; i++) {
struct report_info_t *rpt = &hid->report_list[i];
if (rpt->usage == 0x02) {
if (rpt->report_id == 0) {
rpt->report_id = 0xff;
}
rpt->btn_start_bit /= 8;
rpt->btn_width /= 8;
rpt->xy_start_bit /= 8;
rpt->xy_width /= 8;
rpt->wheel_start_bit /= 8;
rpt->wheel_width /= 8;
log_info("mouse report_id %d",
rpt->report_id);
log_info("btn_width %d-%d",
rpt->btn_start_bit, rpt->btn_width);
log_info("xy_width %d-%d",
rpt->xy_start_bit, rpt->xy_width);
log_info("wheel_width %d-%d",
rpt->wheel_start_bit, rpt->wheel_width);
if (rpt->btn_width != 2) {
rpt->btn_width = 1;
}
log_info("btn_width %d-%d",
rpt->btn_start_bit, rpt->btn_width);
} else if (rpt->usage == 6 || rpt->usage == 7) {
if (rpt->report_id == 0) {
rpt->report_id = 0xff;
}
log_info("keyboard report_id %d", rpt->report_id);
} else {
log_info("unknown usage %d", rpt->usage);
}
}
return 0;
}
void mouse_route(const struct mouse_data_t *p);
/* __attribute__((weak)) void mouse_route(const struct mouse_data_t *p) */
/* { */
/* log_info("btn: %x x-y %d %d wheel %d ac_pan %d", */
/* p->btn, p->x, p->y, p->wheel, p->ac_pan); */
/* } */
static void hid_convert_mouse(const struct report_info_t *mouse, const u8 *buffer)
{
struct mouse_data_t mouse_data;
memset(&mouse_data, 0, sizeof(mouse_data));
if (mouse->report_id != 0xff) {
if (mouse->report_id != buffer[0]) {
log_error("report_id = %x buffer[0] = %x", mouse->report_id, buffer[0]);
return;
}
buffer++;
}
const u8 *ptr;
ptr = &buffer[mouse->btn_start_bit];
if (mouse->btn_width == 2) {
mouse_data.btn = ptr[0] | (ptr[1] << 8);
} else {
mouse_data.btn = ptr[0] ;
}
s16 tmp;
ptr = &buffer[mouse->xy_start_bit];
if (mouse->xy_width == 1 || mouse->xy_width == 2) {
mouse_data.x = (char)ptr[0];
mouse_data.y = (char)ptr[1];
} else if (mouse->xy_width == 4) {
mouse_data.x = ptr[0] | (ptr[1] << 8);
ptr += 2;
mouse_data.y = ptr[0] | (ptr[1] << 8);
} else if (mouse->xy_width == 3) {
tmp = (ptr[1] & 0xf) << 12 | ptr[0] << 4;
tmp = tmp >> 4;
mouse_data.x = tmp;
tmp = (ptr[2] << 8) | ((ptr[1] >> 4) << 4);
tmp = tmp >> 4;
mouse_data.y = tmp;
} else {
log_error("error mouse xy_width %d", mouse->xy_width);
}
ptr = &buffer[mouse->wheel_start_bit];
if (mouse->wheel_width == 1) {
mouse_data.wheel = (char)ptr[0];
} else {
mouse_data.wheel = ptr[0] | (ptr[1] << 8);
}
mouse_route(&mouse_data);
}
__attribute__((weak)) void keyboard_route(const u8 *p)
{
log_info("keyboard_buffer:");
printf_buf(p, 12);
}
void hid_convert_krbd(const struct report_info_t *kbd, u8 *buffer)
{
#if 0
u8 keyboard_buffer[12];
memset(keyboard_buffer, 0, sizeof(keyboard_buffer));
if (kbd->report_id != 0xff) {
if (kbd->report_id != buffer[0]) {
log_error("report_id = %x buffer[0] = %x", kbd->report_id, buffer[0]);
return;
}
buffer++;
}
u8 idx = 0;
u8 index = 0;
int i = 0;
for (i = 0; i < 8; i++) {
if (buffer[0] & BIT(i)) {
keyboard_buffer[idx++] = 0xe0 + i;
}
}
if (buffer[1] == 0) {
buffer += 2;
}
index = idx;
for (; idx < 12; idx++) {
if (*buffer) {
keyboard_buffer[index] = *buffer;
index++;
}
buffer ++;
}
keyboard_route(keyboard_buffer);
#else
if (kbd->report_id != 0xff) {
if (kbd->report_id != buffer[0]) {
log_error("report_id = %x buffer[0] = %x", kbd->report_id, buffer[0]);
return;
}
buffer++;
}
u8 keyboard_buffer[8];
memset(keyboard_buffer, 0, sizeof(keyboard_buffer));
keyboard_buffer[0] = *buffer;
buffer ++;
if (*buffer == 0) {
buffer ++;
}
keyboard_buffer[1] = 0;
/* memcpy(&keyboard_buffer[2], buffer, 6); */
u8 pos = 2;
for (int i = pos; i < 8; i++) {
if (*buffer) {
keyboard_buffer[pos] = *buffer;
pos++;
}
buffer++;
}
keyboard_route(keyboard_buffer);
#endif
}
static void hid_route(const struct hid_device_t *hid, const u8 *buffer)
{
for (int i = 0; i < hid->report_count; i++) {
if (hid->report_list[i].usage == 0x02) {
hid_convert_mouse(&hid->report_list[i], buffer);
} else if ((hid->report_list[i].usage == 0x06) ||
(hid->report_list[i].usage == 0x07)) {
hid_convert_krbd(&hid->report_list[i], buffer);
} else {
r_printf("usage %x", hid->report_list[i].usage);
}
}
}
static void hid_isr(struct usb_interface_info *usb_if, u32 ep)
{
u8 buffer[64] = {0};
struct usb_host_device *host_dev = usb_if->dev.hid->parent;
usb_dev usb_id = host_device2id(host_dev);
u32 target_ep = usb_if->dev.hid->ep_pair[ep];
u32 rx_len = usb_h_ep_read_async(usb_id, ep, target_ep, buffer, 64, USB_ENDPOINT_XFER_INT, 0);
if (rx_len) {
hid_route(usb_if->dev.hid, buffer);
}
/* printf_buf(buffer, rx_len); */
usb_h_ep_read_async(usb_id, ep, target_ep, buffer, 8, USB_ENDPOINT_XFER_INT, 1);
}
void hid_process(u32 id)
{
struct usb_host_device *host_dev = host_id2device(id);
u8 report[256 + 2];
u8 ep_pair[5];
for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
struct usb_interface_info *usb_if = host_dev->interface_info[i];
log_info("parent %x hid @ interface %d usb_if %x hid %x",
host_dev, i, usb_if, usb_if ? usb_if->dev.hid : 0);
if (usb_if &&
(usb_if->ctrl->interface_class == USB_CLASS_HID)) {
hid_set_idle(host_dev, i);
memset(report, 0, sizeof(report));
hid_get_report(host_dev, report, i, 0xff);
printf_buf(report, 256);
hid_report_parse(usb_if->dev.hid, report, 256);
memcpy(ep_pair, usb_if->dev.hid->ep_pair, 4);
if (usb_if->dev.hid->report_count == 0) {
continue;
}
for (int j = 0; j < usb_if->dev.hid->bNumEndpoints; j++) {
u32 host_ep = usb_get_ep_num(id, USB_DIR_IN, USB_ENDPOINT_XFER_INT);
if (host_ep == -1) {
continue;
}
u32 target_ep = ep_pair[j];
usb_if->dev.hid->ep_pair[host_ep] = target_ep;
log_info("D2H ep: %x --> %x interval %d",
target_ep, host_ep, interval[id][target_ep]);
usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, hid_isr, usb_if);
if (!hid_intr_ep_in_buf[id]) {
hid_intr_ep_in_buf[id] = usb_h_alloc_ep_buffer(id, host_ep | USB_DIR_IN, 64);
}
#ifdef USB_HW_20
usb_write_rxfuncaddr(id, host_ep, host_dev->private_data.devnum);
#endif
usb_h_ep_config(id, host_ep | USB_DIR_IN, USB_ENDPOINT_XFER_INT, 1,
interval[id][target_ep], hid_intr_ep_in_buf[id], 64);
int r = usb_h_ep_read_async(id, host_ep, target_ep, NULL, 0, USB_ENDPOINT_XFER_INT, 1);
}
} else {
if (usb_if) {
log_error("error hid class %x", usb_if->ctrl->interface_class);
}
}
}
}
#endif
+83
View File
@@ -0,0 +1,83 @@
/**@file hid.h
* @brief hid驱动头文件(做主机)
* @details 结构体声明,功能函数声明
* @author jieli
* @date 2021-9-1
* @version V1.0
* @copyright Copyright(c)2010-2021 珠海市杰理科技股份有限公司
*********************************************************
* @attention
* 硬件平台:AC632N
* SDK版本:AC632N_V1.0.0_SDK
* @修改日志:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-9-1 <td>1.0 <td>jieli <td>创建初始版本
* </table>
*
*********************************************************
*/
#ifndef __HID_H__
#define __HID_H__
#include "system/task.h"
#include "device/device.h"
#include "usb/scsi.h"
#include "usb_bulk_transfer.h"
#include "usb/host/usb_host.h"
/**@struct report_info_t
* @brief 报告描述符包含的信息结构体\n
* 自定义一些私有数据信息存储在该结构体中
*/
struct report_info_t {
u8 report_id; ///<id号,不同hid设备对应不同id
u8 usage; ///<描述该数据信息的用途
u8 btn_start_bit; ///<鼠标按键数据起始位
u8 btn_width; ///<鼠标按键数据宽度
u8 xy_start_bit; ///<鼠标平移数据起始位
u8 xy_width; ///<鼠标平移数据宽度
u8 wheel_start_bit; ///<鼠标滚轮数据起始位
u8 wheel_width; ///<鼠标滚轮数据宽度
};
#define MAX_REPORT_COUNT 4
/**@struct hid_device_t
* @brief 报告描述符包含的信息结构体\n
* 自定义一些私有数据信息存储在该结构体中
*/
struct hid_device_t {
void *parent; ///<定义的parent指针,指向该hid的所属设备
u8 ep_pair[4]; ///<端点对数组,数组下标存放主机端点,对应的元素存放目标端点
u8 report_count; ///<报告描述符中item计数器
u8 bNumEndpoints; ///<端点数量
struct report_info_t report_list[MAX_REPORT_COUNT]; ///<报告描述符结构体
};
/**@brief USB hid设备解析
* @param[in] host_dev usb_host_device定义的结构体指针
* @param[in] interface_num 接口号
* @param[in] *pBuf 数据指针,指向数据存放的地址
* @return 接口描述符长度
* @par 示例:
* @code
* usb_hid_parser(host_dev,interface_num,pBuf);
* @encode
*/
int usb_hid_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
/**@brief USB hid设备信息处理
* @param[in] id usb设备id号
* @return 无
* @par 示例:
* @code
* hid_process(id);
* @encode
*/
void hid_process(u32 id);
#endif /*HID_H*/
+226
View File
@@ -0,0 +1,226 @@
#ifndef __HOST_UVC_H__
#define __HOST_UVC_H__
#include "usb.h"
#include "uvc.h"
#include "uvc_device.h"
#ifdef __cplusplus
extern "C" {
#endif
/* ------------------------------------------------------------------------
* GUIDs
*/
#define UVC_GUID_UVC_CAMERA {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}
#define UVC_GUID_UVC_OUTPUT {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02}
#define UVC_GUID_UVC_PROCESSING {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01}
#define UVC_GUID_UVC_SELECTOR {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02}
#define UVC_GUID_UNIT_EXTENSION 0x92, 0x42, 0x39, 0x46, 0xD1, 0x0C, 0xE3, 0x4A, 0x87, 0x83, 0x31, 0x33, 0xF9, 0xEA, 0xAA, 0x3B
#if 0
#define UVC_GUID_UNIT_EXTENSION 0xAD, 0xCC, 0xB1, 0xC2,\
0xF6, 0xAB, 0xB8, 0x48,\
0x8E, 0x37, 0x32, 0xD4,\
0xF3, 0xA3, 0xFE, 0xEC
#endif
#define UVC_GUID_FORMAT_MJPEG 'M', 'J', 'P', 'G', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa,0x00, 0x38, 0x9b, 0x71
#define UVC_GUID_FORMAT_YUY2 'Y', 'U', 'Y', '2', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa,0x00, 0x38, 0x9b, 0x71
#define UVC_GUID_FORMAT_NV12 'N', 'V', '1', '2', 0x00, 0x00, 0x10, 0x00, \
0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71
#define CAMERA_CLOSE_BY_IRQ 1
struct uvc_event_listener {
void *priv;
int (*handler)(void *priv, int event);
};
struct uvc_int_endponit {
u8 enable;
int host_ep;
int epin;
u32 interval;
u32 wMaxPacketSize;
u8 *buffer;
};
struct usb_uvc {
u8 host_ep;
u8 ep;
u16 if_alt_num;
u32 wMaxPacketSize;
u32 interval;
u8 *ep_buffer;
u32 fps;
u32 bfh: 1;
u32 error_frame: 1;
u32 cur_frame: 8;
u32 mjpeg_format_index: 8;
u32 yuyv_format_index: 8;
u32 h264_format_index: 8;
u32 reso_num: 8;
u32 camera_open: 1;
u32 xfer_type: 2;
u32 ep_buf_ch: 1;
u32 unused: 2;
u32 format: 8;
void *priv;
struct uvc_int_endponit int_ep;
UVC_STREAM_OUT stream_out;
#if !CAMERA_CLOSE_BY_IRQ
UVC_STREAM_OUT bak_stream_out;
#endif
int (*offline)(void *priv);
void *event_priv;
int (*event_handler)(void *priv, int event);
struct uvc_frame_info pframe[0];
};
#define UVC_FORMAT_YUY2 0
#define UVC_FORMAT_NV12 0
#define UVC_FORMAT_MJPG 1
#if 0
#define FREAME_MAX_WIDTH 1280
#define FREAME_MAX_HEIGHT 720
#else
#define FREAME_MAX_WIDTH 640
#define FREAME_MAX_HEIGHT 480
#endif
#define UVC_FRAME_SZIE (FREAME_MAX_WIDTH * FREAME_MAX_HEIGHT * 2)
#define MJPG_WWIDTH_0 (0x500)
#define MJPG_WHEIGHT_0 (0x2D0)
#define MJPG_WWIDTH_1 (0x0320)
#define MJPG_WHEIGHT_1 (0x0258)
#define MJPG_WWIDTH_2 (0x0280)
#define MJPG_WHEIGHT_2 (0x01E0)
#define MJPG_WWIDTH_3 (0x0160)
#define MJPG_WHEIGHT_3 (0x0120)
#define MJPG_WWIDTH_4 (0x0140)
#define MJPG_WHEIGHT_4 (0x00F0)
#define YUV_WWIDTH_0 (0x500)
#define YUV_WHEIGHT_0 (0x2D0)
#define YUV_WWIDTH_1 (0x0280)
#define YUV_WHEIGHT_1 (0x01E0)
#define YUV_WWIDTH_2 (0x0320)
#define YUV_WHEIGHT_2 (0x0258)
#define YUV_WWIDTH_3 (0x0160)
#define YUV_WHEIGHT_3 (0x0120)
#define YUV_WWIDTH_4 (0x0140)
#define YUV_WHEIGHT_4 (0x00F0)
#define FRAME_FPS_0 (10000000/30)
#define FRAME_FPS_1 (10000000/30)
#define FRAME_FPS_2 (10000000/30)
#define FRAME_FPS_3 (10000000/30)
#define FRAME_FPS_4 (10000000/30)
#if UVC_FORMAT_YUY2||UVC_FORMAT_NV12
#define ISO_EP_INTERVAL 1
#else
#define ISO_EP_INTERVAL 1
#endif
#define UVC_DWCLOCKFREQUENCY 0x01c9c380
#define UVC_IT_TERMINALID 1
#define UVC_OT_TERMINALID 2
#define UVC_PU_TERMINALID 3
#define UVC_EXT_TERMINALID 4
///////////Video Class
/* USB VIDEO INTERFACE TYPE */
#define VIDEO_CTL_INTFACE_TYPE 1
#define VIDEO_STEAM_INTFACE_TYPE 2
/* Video BFH */
#define UVC_FID 0x01
#define UVC_EOF 0x02
#define UVC_PTS 0x04
#define UVC_SCR 0x08
#define UVC_RES 0x10
#define UVC_STI 0x20
#define UVC_ERR 0x40
#define UVC_EOH 0x80
enum stream_state {
STREAM_NO_ERR = 0x0,
STREAM_ERR = 0x1,
STREAM_EOF = 0x2,
STREAM_SOF = 0x3,
};
#define VIDEO_INF_NUM 2
#define SINGLE_UVC 1
/* ISO_INTR_MODE = 2 开启uvc iso 8包合1接收功能
* usb2.0 iso包125us起一次中断, 开启8包合1后,每8个iso包产生一次中断,即 1ms产生一次中断
* 注意:如果iso包长度为0,计数器不会累计,因此可能不会1ms产生一次中断,而是多于1ms才产生一次中断
* */
#define ISO_INTR_MODE 0 //1 iso_intr_cnt
// #define ISO_INTR_MODE 1 //1 iso_intr_cnt
// #define ISO_INTR_MODE 2 //2 iso_intr_cnt
#if (ISO_INTR_MODE == 2)
#if (SINGLE_UVC== 1)
#define ISO_INTR_CNT 8
#else
#define ISO_INTR_CNT 4
#endif
#else
#define ISO_INTR_CNT 1
#endif
extern int usb_uvc_parser(struct usb_host_device *host_dev, u8 interface_num, u8 *pBuf);
extern void *uvc_host_open(void *arg);
extern int uvc_force_reset(void *fd);
extern int uvc_host_close(void *fd);
extern int uvc_host_open_camera(void *fd);
extern int uvc_host_close_camera(void *fd);
extern int uvc_host_online(void);
extern int uvc_host_get_backlight_compensation(void *fd, u32 *iostatus);
extern int uvc_host_req_processing_unit(void *fd, struct uvc_processing_unit *pu);
extern int uvc_host_get_pix_table(void *fd, struct uvc_frame_info **pix_table);
extern int uvc_host_set_pix(void *fd, int index);
extern int uvc_host_set_fps(void *fd, int fps);
extern int uvc_host_camera_out(const usb_dev usb_id);
extern int uvc2usb_ioctl(void *fd, u32 cmd, void *arg);
extern int uvc_host_get_fps(void *fd);
//extern int uvc_get_device_id(void *fd, struct usb_device_id *id);
int usb_host_video_init(const usb_dev usb_id, const u8 sub_id);
extern u32 uvc_host_get_fmt(void);
extern u8 uvc_host_is_support_h264_fmt(void);
#ifdef __cplusplus
}
#endif
#endif /*HOST_UVC_H*/
@@ -0,0 +1,317 @@
/**
* @file usb_bulk_transfer.c
* @brief bulk transfer driver
* @author chenrixin@zh-jieli.com
* @version 1.00
* @date 2017-02-09
*/
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include <string.h>
#include "jiffies.h"
#include "usb_config.h"
#include "usb_bulk_transfer.h"
#include "usb_ctrl_transfer.h"
#include "usb_storage.h"
#include "usb/host/usb_host.h"
#include "usb/usb_phy.h"
#include "app_config.h"
#include "device_drive.h"
#if TCFG_USB_HOST_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"
struct usb_request_block {
void *ptr;
u32 len;
u32 target_ep;
u16 rxmap;
u16 txmap;
u32 msg;
u32 async_mode;
};
static struct usb_request_block urb;
u8 get_async_mode(void)
{
u8 mode = BULK_ASYNC_MODE_EXIT ;
#if UDISK_READ_512_ASYNC_ENABLE
local_irq_disable();
mode = urb.async_mode;
local_irq_enable();
#endif
return mode;
}
void set_async_mode(u8 mode)
{
#if UDISK_READ_512_ASYNC_ENABLE
local_irq_disable();
urb.async_mode = mode;
local_irq_enable();
#endif
}
static void usb_bulk_rx_isr(struct usb_host_device *host_dev, u32 ep)
{
usb_dev usb_id = host_device2id(host_dev);
int l = min(urb.len, urb.rxmap);
l = usb_h_ep_read_async(usb_id, ep, urb.target_ep, urb.ptr, l, USB_ENDPOINT_XFER_BULK, 0);
/* g_printf("%s() %d %d", __func__, l, urb.len); */
if (l > 0) {
urb.len -= l;
if (urb.ptr) {
urb.ptr = (u8 *)urb.ptr + l;
}
urb.msg = 0;
} else {
urb.msg = l;
urb.len = 0;
}
if (urb.len == 0) {
u32 async_mode = get_async_mode();
if (async_mode == BULK_ASYNC_MODE_EXIT) {
usb_sem_post(host_dev);
} else if (async_mode == BULK_ASYNC_MODE_SEM_PEND) {
if (urb.msg == 0) {
usb_sem_post(host_dev);
} else {
r_printf("usb async error");
}
}
} else {
usb_h_ep_read_async(usb_id, ep, urb.target_ep, urb.ptr, urb.len, USB_ENDPOINT_XFER_BULK, 1);
}
}
s32 usb_bulk_only_receive_async(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
const usb_dev usb_id = host_device2id(host_dev);
//cppcheck-suppress unreadVariable
u8 devnum = host_dev->private_data.devnum;
urb.ptr = pBuf;
urb.len = len;
urb.target_ep = target_ep;
#ifdef CONFIG_USB_SUPPORT_MRX_TX
urb.rxmap = 1 * 1024;
#else
urb.rxmap = rxmaxp;
#endif
urb.msg = -DEV_ERR_OFFLINE;
usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, usb_bulk_rx_isr, host_dev);
usb_set_intr_rxe(usb_id, host_ep);
#ifdef USB_HW_20
usb_write_rxfuncaddr(usb_id, host_ep, devnum);
#endif
int ret = usb_h_ep_read_async(usb_id, host_ep, target_ep, urb.ptr, len, USB_ENDPOINT_XFER_BULK, 1);
if (ret < 0) {
return ret;
}
ret = usb_sem_pend(host_dev, 300);
usb_clr_intr_rxe(usb_id, host_ep);
usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, NULL, host_dev);
if (ret) {
return -DEV_ERR_TIMEOUT;
}
return urb.msg ? urb.msg : len;
}
/**
* @brief usb_bulk_receive_async_no_wait 启动USB Bulk 异步预读
* 不用等信号量,启动传输后返回
* @param device 设备句柄
* @param pBuf 读buffer缓冲区,芯片所有memory都可以
* @param len 需要预读的长度
*
* @return 负数表示失败
*/
s32 usb_bulk_receive_async_no_wait(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
const usb_dev usb_id = host_device2id(host_dev);
//cppcheck-suppress unreadVariable
u8 devnum = host_dev->private_data.devnum;
set_async_mode(BULK_ASYNC_MODE_SEM_PEND);
urb.ptr = pBuf;
urb.len = len;
urb.target_ep = target_ep;
#ifdef CONFIG_USB_SUPPORT_MRX_TX
urb.rxmap = 1 * 1024;
#else
urb.rxmap = rxmaxp;
#endif
urb.msg = -DEV_ERR_OFFLINE;
usb_h_set_ep_isr(host_dev, host_ep | USB_DIR_IN, usb_bulk_rx_isr, host_dev);
usb_set_intr_rxe(usb_id, host_ep);
#ifdef USB_HW_20
usb_write_rxfuncaddr(usb_id, host_ep, devnum);
#endif
int ret = usb_h_ep_read_async(usb_id, host_ep, target_ep, urb.ptr, len, USB_ENDPOINT_XFER_BULK, 1);
if (ret < 0) {
if (ret == -DEV_ERR_RXSTALL) {
ret = usb_clear_feature(host_dev, target_ep | USB_DIR_IN);
if (ret == 0) {
return -DEV_ERR_RXSTALL;
}
}
return ret;
}
return len;
}
static s32 _usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
{
#if 0
struct usb_host_device *host_dev = device_to_usbdev(device);
const usb_dev usb_id = host_device2id(host_dev);
return usb_h_bulk_read(usb_id, host_ep, rxmaxp, target_ep, pBuf, len);
#else
return usb_bulk_only_receive_async(device, host_ep, rxmaxp, target_ep, pBuf, len);
#endif
}
s32 usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
int ret = _usb_bulk_only_receive(device, host_ep, rxmaxp, target_ep, pBuf, len);
if (ret == -DEV_ERR_RXSTALL) {
ret = usb_clear_feature(host_dev, target_ep | USB_DIR_IN);
if (ret == 0) {
return -DEV_ERR_RXSTALL;
}
}
return ret;
}
static void usb_bulk_tx_isr(struct usb_host_device *host_dev, u32 ep)
{
usb_dev usb_id = host_device2id(host_dev);
int l = min(urb.len, urb.txmap);
l = usb_h_ep_write_async(usb_id, ep, urb.txmap, urb.target_ep, urb.ptr, l, USB_ENDPOINT_XFER_BULK, 0);
if (l > 0) {
urb.len -= l;
urb.ptr = (u8 *)urb.ptr + l;
urb.msg = 0;
} else {
urb.msg = l;
urb.len = 0;
}
if (urb.len == 0) {
if (urb.msg || l == 0) {
usb_sem_post(host_dev);
}
}
}
s32 usb_bulk_only_send_async(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
const usb_dev usb_id = host_device2id(host_dev);
//cppcheck-suppress unreadVariable
u8 devnum = host_dev->private_data.devnum;
urb.target_ep = target_ep;
#ifdef CONFIG_USB_SUPPORT_MRX_TX
urb.txmap = 8 * 1024;
#else
urb.txmap = txmaxp;
#endif
urb.msg = -DEV_ERR_OFFLINE;
urb.len = len - min(len, urb.txmap);
urb.ptr = (u8 *)pBuf + min(len, urb.txmap);
usb_h_set_ep_isr(host_dev, host_ep, usb_bulk_tx_isr, host_dev);
usb_set_intr_txe(usb_id, host_ep);
#ifdef USB_HW_20
usb_write_txfuncaddr(usb_id, host_ep, devnum);
#endif
int ret = usb_h_ep_write_async(usb_id, host_ep, txmaxp, target_ep, pBuf, min(len, urb.txmap), USB_ENDPOINT_XFER_BULK, 1);
if (ret < 0) {
return ret;
}
ret = usb_sem_pend(host_dev, 250);
usb_clr_intr_txe(usb_id, host_ep);
usb_h_set_ep_isr(host_dev, host_ep, NULL, host_dev);
if (ret) {
r_printf("ret %d", ret);
return -DEV_ERR_TIMEOUT;
}
/* g_printf("%s() %d %d", __func__, urb.len, urb.msg); */
return urb.msg ? urb.msg : len;
}
/**
* @brief usb_bulk_only_send
*
* @param device
* @param host_ep 主机的端点号
* @param target_ep 目标设备的端点号
* @param pBuf
* @param len
*
* @return 负数失败
* 正数发送的字节数
*/
static s32 _usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
{
#if 0
struct usb_host_device *host_dev = device_to_usbdev(device);
const usb_dev usb_id = host_device2id(host_dev);
return usb_h_bulk_write(usb_id, host_ep, txmaxp, target_ep, pBuf, len);
#elif 0
if (len < 512) {
struct usb_host_device *host_dev = device_to_usbdev(device);
const usb_dev usb_id = host_device2id(host_dev);
return usb_h_bulk_write(usb_id, host_ep, txmaxp, target_ep, pBuf, len);
} else {
return usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
}
#else
return usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
#endif
}
s32 usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len)
{
struct usb_host_device *host_dev = device_to_usbdev(device);
int ret = _usb_bulk_only_send(device, host_ep, txmaxp, target_ep, pBuf, len);
if (ret == -DEV_ERR_TXSTALL) {
ret = usb_clear_feature(host_dev, target_ep);
if (ret == 0) {
return -DEV_ERR_TXSTALL;
}
}
return ret;
}
#endif
@@ -0,0 +1,120 @@
/**@file usb_bulk_transfer.h
* @brief usb_bulk_transfer批量传输头文件
* @details 功能函数声明
* @author jieli
* @date 2021-8-1
* @version V1.0
* @copyright Copyright(c)2010-2021 珠海市杰理科技股份有限公司
*********************************************************
* @attention
* 硬件平台:AC695N
* SDK版本:AC695N_V1.0.0_SDK
* @修改日志:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-8-1 <td>1.0 <td>jieli <td>创建初始版本
* </table>
*
*********************************************************
*/
#ifndef __USB_BULK_TRANSFER_H__
#define __USB_BULK_TRANSFER_H__
#include "typedef.h"
#include "device/device.h"
/**@brief 批量传输只读取(异步模式)
* @param[in] device定义的结构体指针
* @param[in] host_ep 主机端点号
* @param[in] rxmaxp 接收端点最大包长
* @param[in] target_ep 目标端点号
* @param[in] *pBuf BUFFER指针
* @param[in] len 数据长度
* @return
* @par 示例:
* @code
* usb_bulk_only_receive_async(device, host_ep, rxmaxp, target_ep, pBuf, len);
* @encode
*/
s32 usb_bulk_only_receive_async(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len);
/**@brief 批量传输只读取(普通模式)
* @param[in] device定义的结构体指针
* @param[in] host_ep 主机端点号
* @param[in] rxmaxp 接收端点最大包长
* @param[in] ep 目标端点号
* @param[in] *pBuf BUFFER指针
* @param[in] len 数据长度
* @return
* @par 示例:
* @code
* usb_bulk_only_receive(device, host_ep, rxmaxp, ep, pBuf, len);
* @encode
*/
s32 usb_bulk_only_receive(struct device *device, u8 host_ep, u16 rxmaxp, u8 ep, u8 *pBuf, u32 len);
/**@brief 批量传输只发送(异步模式)
* @param[in] device定义的结构体指针
* @param[in] host_ep 主机端点号
* @param[in] txmaxp 发送端点最大包长
* @param[in] target_ep 目标端点号
* @param[in] *pBuf BUFFER指针
* @param[in] len 数据长度
* @return
* @par 示例:
* @code
* usb_bulk_only_send_async(device, host_ep, txmaxp, target_ep, pBuf, len);
* @encode
*/
s32 usb_bulk_only_send_async(struct device *device, u8 host_ep, u16 txmaxp, u8 target_ep, const u8 *pBuf, u32 len);
/**@brief 批量传输只发送(普通模式)
* @param[in] device定义的结构体指针
* @param[in] ep 主机端点号
* @param[in] txmaxp 发送端点最大包长
* @param[in] ep 目标端点号
* @param[in] *pBuf BUFFER指针
* @param[in] len 数据长度
* @return
* @par 示例:
* @code
* usb_bulk_only_send(device, host_ep, txmaxp, ep, pBuf, len);
* @encode
*/
s32 usb_bulk_only_send(struct device *device, u8 host_ep, u16 txmaxp, u8 ep, const u8 *pBuf, u32 len);
/**@brief 获取异步模式当前状态
* @param[in] 空
* @return 当前状态
* @par 示例:
* @code
* get_async_mode();
* @encode
*/
u8 get_async_mode(void);
/**@brief 设置异步模式
* @param[in] mode 需要设置的模式
* @return 空
* @par 示例:
* @code
* set_async_mode(BULK_ASYNC_MODE_EXIT);退出异步模式
* @encode
*/
void set_async_mode(u8 mode);
/**@brief 批量传输异步模式读取并且不等待
* @param[in] device定义的结构体指针
* @param[in] ep 主机端点号
* @param[in] rxmaxp 发送端点最大包长
* @param[in] target_ep 目标端点号
* @param[in] *pBuf BUFFER指针
* @param[in] len 数据长度
* @return
* @par 示例:
* @code
* usb_bulk_only_send(device, host_ep, rxmaxp, ep, pBuf, len);
* @encode
*/
s32 usb_bulk_receive_async_no_wait(struct device *device, u8 host_ep, u16 rxmaxp, u8 target_ep, u8 *pBuf, u32 len);
#endif
@@ -0,0 +1,637 @@
/**
* @file usb_ctrl_transfer.c
* @brief usb 控制传输接口
* @author chenrixin@zh-jieli.com
* @version 1.00
* @date 2017-02-09
*/
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "usb/host/usb_host.h"
#include "usb_ctrl_transfer.h"
#include "app_config.h"
#include "device_drive.h"
#include "gpio.h"
#include "usb/scsi.h"
#define LOG_TAG_CONST USB
#define LOG_TAG "[USB]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
#if TCFG_USB_HOST_ENABLE
_WEAK_
void usb_dis_ep0_txdly(const usb_dev id)
{
}
static void ep0_h_isr(struct usb_host_device *host_dev, u32 ep)
{
usb_sem_post(host_dev);
}
/**
* @brief usb_ctlXfer
*
* @param host_dev
* @param urb
*
* @return
*/
static int usb_ctlXfer(struct usb_host_device *host_dev, struct ctlXfer *urb)
{
u32 ret = DEV_ERR_NONE;
u8 reg = 0;
u32 data_len;
usb_dev usb_id = host_device2id(host_dev);
u8 devnum = host_dev->private_data.devnum;
u32 max_packet_size = host_dev->private_data.ep0_max_packet_size;
usb_write_faddr(usb_id, devnum);
#ifdef USB_HW_20
usb_write_txfuncaddr(usb_id, 0, devnum);
#endif
switch (urb->stage) {
case USB_PID_SETUP :
usb_write_ep0(usb_id, (u8 *)&urb->setup, 8);
reg = CSR0H_SetupPkt | CSR0H_TxPktRdy;
break;
case USB_PID_IN :
if (urb->setup.wLength) {
reg = CSR0H_ReqPkt;
} else {
reg = CSR0H_StatusPkt | CSR0H_ReqPkt;
}
break;
case USB_PID_OUT:
if (urb->setup.wLength) {
data_len = min(urb->setup.wLength, max_packet_size);
reg = CSR0H_TxPktRdy;
usb_write_ep0(usb_id, urb->buffer, data_len);
urb->setup.wLength -= data_len;
urb->buffer = (u8 *)urb->buffer + data_len;
} else {
reg = CSR0H_StatusPkt | CSR0H_TxPktRdy;
}
break;
default :
break;
}
#if USB_HOST_ASYNC
//config ep0 callback fun
usb_h_set_ep_isr(host_dev, 0, ep0_h_isr, host_dev);
usb_set_intr_txe(usb_id, 0);
#endif
usb_write_csr0(usb_id, reg | CSR0H_DISPING);
u32 st = 0;
u32 ot = usb_get_jiffies() + 500;
while (1) {
if (usb_host_timeout(ot)) {
log_error("time out %x\n", reg);
ret = -DEV_ERR_TIMEOUT;
goto __exit;
}
if (usb_h_dev_status(usb_id)) {
st ++;
} else {
st = 0;
}
if (((usb_read_devctl(usb_id) & BIT(2)) == 0) || (st > 1000)) {
log_error("usb%d_offline\n", usb_id);
ret = -DEV_ERR_OFFLINE;
goto __exit;
}
#if USB_HOST_ASYNC
ret = usb_sem_pend(host_dev, 250); //wait isr
if (ret) {
log_error("usb%d_offline\n", usb_id);
ret = -DEV_ERR_OFFLINE;
goto __exit;
}
#endif
reg = usb_read_csr0(usb_id);
if (reg & CSR0H_RxStall) {
log_error(" rxStall CSR0:0x%x", reg);
ret = -DEV_ERR_CONTROL_STALL;
goto __exit;
}
if (reg & CSR0H_Error) {
log_error(" Error CSR0:0x%x", reg);
usb_write_csr0(usb_id, 0);
ret = -DEV_ERR_CONTROL;
goto __exit;
}
if (USB_PID_IN == urb->stage) {
if (reg & CSR0H_RxPktRdy) {
data_len = usb_read_count0(usb_id);
data_len = min(data_len, urb->setup.wLength);
usb_read_ep0(usb_id, urb->buffer, data_len);;
urb->buffer = (u8 *)urb->buffer + data_len;
urb->setup.wLength -= data_len;
if (data_len < max_packet_size) {
urb->setup.wLength = 0;
}
if (urb->setup.wLength) {
usb_write_csr0(usb_id, CSR0H_ReqPkt | CSR0H_DISPING);
} else {
usb_write_csr0(usb_id, CSR0H_DISPING);
break;
}
}
} else {
if (!(reg & CSR0H_TxPktRdy)) {
break;
}
}
}
__exit:
usb_clr_intr_txe(usb_id, 0);
usb_dis_ep0_txdly(usb_id);
return ret;
}
/**
* @brief usb_control_transfers
*
* @param struct host_dev
* @param urb
*
* @return
*/
static int usb_control_transfers(struct usb_host_device *host_dev, struct ctlXfer *urb)
{
int res;
/*SETUP*/
urb->stage = USB_PID_SETUP; //SETUP transaction
res = usb_ctlXfer(host_dev, urb);
if (res) {
return res;
}
/*IN or OUT*/
urb->stage = USB_PID_IN;
while (urb->setup.wLength) {
if (urb->setup.bRequestType & USB_DIR_IN) { //Request Direction
urb->stage = USB_PID_IN; //IN transaction
res = usb_ctlXfer(host_dev, urb);
if (res) {
return res;
}
urb->stage = USB_PID_OUT;
} else {
urb->stage = USB_PID_OUT; //OUT transaction
res = usb_ctlXfer(host_dev, urb);
if (res) {
return res;
}
urb->stage = USB_PID_IN;
}
}
res = usb_ctlXfer(host_dev, urb);
if (res) {
return res;
}
return DEV_ERR_NONE;
}
/**
* @brief usb_control_msg
*
* @param host_dev
* @param request
* @param requesttype
* @param value
* @param index
* @param data
* @param size
*
* @return
*/
int usb_control_msg(struct usb_host_device *host_dev,
u8 request, u8 requesttype,
u16 value, u16 index,
void *data, u16 size)
{
struct ctlXfer urb;
urb.setup.bRequestType = requesttype;
urb.setup.bRequest = request;
urb.setup.wValue = cpu_to_le16(value);
urb.setup.wIndex = cpu_to_le16(index);
urb.setup.wLength = cpu_to_le16(size);
urb.buffer = data;
return usb_control_transfers(host_dev, &urb);
}
/**
* @brief usb_clear_feature
*
* @param host_dev
* @param ep
*
* @return
*/
int usb_clear_feature(struct usb_host_device *host_dev, u32 ep)
{
return usb_control_msg(host_dev, USB_REQ_CLEAR_FEATURE, USB_RECIP_ENDPOINT, 0, ep, NULL, 0);
}
int set_address(struct usb_host_device *host_dev, u8 devnum)
{
return usb_control_msg(host_dev, USB_REQ_SET_ADDRESS, 0, devnum, 0, NULL, 0);
}
int usb_get_device_descriptor(struct usb_host_device *host_dev, struct usb_device_descriptor *desc)
{
return usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_DEVICE << 8),
0,
desc,
USB_DT_DEVICE_SIZE
);
}
int usb_get_string_descriptor(struct usb_host_device *host_dev, struct usb_device_descriptor *desc)
{
int ret = DEV_ERR_NONE;
#if 0
struct usb_private_data *private_data = host_dev->private_data ;
/**********get string language*********/
u8 buf[16];
memset(buf, 0x0, sizeof(buf));
ret = usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_STRING << 8),
0,
desc,
sizeof(buf)
);
if (ret) {
return ret;
}
memcpy(&private_data->language, buf + 2, sizeof(private_data->language));
/**********get manufacturer string**********/
memset(private_data->manufacturer, 0x0, sizeof(private_data->manufacturer));
if (desc->iManufacturer) {
ret = usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_STRING << 8) | desc->iManufacturer,
0,
private_data->manufacturer,
sizeof(private_data->manufacturer)
);
if (ret) {
return ret;
}
}
/**********get product string**********/
memset(private_data->product, 0x0, sizeof(private_data->product));
if (desc->iProduct) {
ret = usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_STRING << 8) | desc->iProduct,
0,
private_data->product,
sizeof(private_data->product)
);
if (ret) {
return ret;
}
}
#endif
return ret;
}
int set_configuration(struct usb_host_device *host_dev)
{
return usb_control_msg(host_dev, USB_REQ_SET_CONFIGURATION, 0, 1, 0, NULL, 0);
}
int set_configuration_add_value(struct usb_host_device *host_dev, u16 value)
{
return usb_control_msg(host_dev, USB_REQ_SET_CONFIGURATION, 0, value, 0, NULL, 0);
}
int get_config_descriptor(struct usb_host_device *host_dev, void *cfg_desc, u32 len)
{
return usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_CONFIG << 8),
0,
cfg_desc,
len);
}
int get_config_descriptor_add_value_l(struct usb_host_device *host_dev, void *cfg_desc, u32 len, u8 value_l)
{
return usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_CONFIG << 8) | value_l,
0,
cfg_desc,
len);
}
int get_msd_max_lun(struct usb_host_device *host_dev, void *lun)
{
return usb_control_msg(host_dev,
USB_MSD_MAX_LUN,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0,
0,
lun,
1);
}
int set_msd_reset(struct usb_host_device *host_dev)
{
return usb_control_msg(host_dev,
0xff,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0,
0,
NULL,
0);
}
int hid_set_idle(struct usb_host_device *host_dev, u32 id)
{
return usb_control_msg(host_dev, 0x0a, 0x21, 0, id << 8, NULL, 0);
}
int hid_get_report(struct usb_host_device *host_dev, u8 *report, u8 report_id, u16 report_len)
{
return usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN | USB_RECIP_INTERFACE,
0x2200,
report_id,
report,
report_len);
}
int hid_set_output_report(struct usb_host_device *host_dev, u8 *report, u8 report_id, u8 report_len)
{
return usb_control_msg(host_dev,
0x09,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0x0201,
report_id,
report,
report_len);
}
int usb_set_remote_wakeup(struct usb_host_device *host_dev)
{
return usb_control_msg(host_dev, USB_REQ_SET_FEATURE, USB_RECIP_DEVICE,
USB_DEVICE_REMOTE_WAKEUP, 0, NULL, 0);
}
int get_device_status(struct usb_host_device *host_dev, u8 *status)
{
return usb_control_msg(host_dev, USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_DEVICE, 0, 0, status, 2);
}
int get_interface_status(struct usb_host_device *host_dev, u8 intr, u8 *status)
{
return usb_control_msg(host_dev, USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_INTERFACE, 0, intr, status, 2);
}
int get_endpoint_status(struct usb_host_device *host_dev, u8 ep, u8 *status)
{
return usb_control_msg(host_dev, USB_REQ_GET_STATUS, USB_DIR_IN | USB_RECIP_ENDPOINT, 0, ep, status, 2);
}
int usb_get_device_qualifier(struct usb_host_device *host_dev, u8 *buffer)
{
return usb_control_msg(host_dev,
USB_REQ_GET_DESCRIPTOR,
USB_DIR_IN,
(USB_DT_DEVICE_QUALIFIER << 8),
0,
buffer,
0x0a);
}
#define AOA_CMD51 0x33
#define AOA_CMD52 0x34
#define AOA_CMD53 0x35
int usb_get_aoa_version(struct usb_host_device *host_dev, u16 *version)
{
return usb_control_msg(host_dev,
AOA_CMD51,
USB_DIR_IN | USB_TYPE_VENDOR,
0,
0,
version,
2);
}
int usb_set_credentials(struct usb_host_device *host_dev, const char *string, int index)
{
return usb_control_msg(host_dev,
AOA_CMD52,
USB_DIR_OUT | USB_TYPE_VENDOR,
0,
index,
(u8 *)string,
strlen(string));
}
int usb_switch2aoa(struct usb_host_device *host_dev)
{
return usb_control_msg(host_dev,
AOA_CMD53,
USB_DIR_OUT | USB_TYPE_VENDOR,
0,
0,
NULL,
0);
}
int usb_switch2slave(struct usb_host_device *host_dev)
{
return usb_control_msg(host_dev,
0x51,
USB_DIR_OUT | USB_TYPE_VENDOR,
0,
0,
NULL,
0);
}
/* Control request for registering a HID device.
* Upon registering, a unique ID is sent by the accessory in the
* value parameter. This ID will be used for future commands for
* the device
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_REGISTER_HID_DEVICE
* value: Accessory assigned ID for the HID device
* index: total length of the HID report descriptor
* data none
*/
#define ACCESSORY_REGISTER_HID 54
int usb_aoa_register_hid(struct usb_host_device *host_dev, u16 value, u16 index)
{
return usb_control_msg(host_dev,
ACCESSORY_REGISTER_HID,
USB_DIR_OUT | USB_TYPE_VENDOR,
value,
index,
NULL,
0);
}
/* Control request for unregistering a HID device.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_REGISTER_HID
* value: Accessory assigned ID for the HID device
* index: 0
* data none
*/
#define ACCESSORY_UNREGISTER_HID 55
int usb_aoa_unregister_hid(struct usb_host_device *host_dev, u16 value)
{
return usb_control_msg(host_dev,
ACCESSORY_UNREGISTER_HID,
USB_DIR_OUT | USB_TYPE_VENDOR,
value,
0,
NULL,
0);
}
/* Control request for sending the HID report descriptor.
* If the HID descriptor is longer than the endpoint zero max packet size,
* the descriptor will be sent in multiple ACCESSORY_SET_HID_REPORT_DESC
* commands. The data for the descriptor must be sent sequentially
* if multiple packets are needed.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SET_HID_REPORT_DESC
* value: Accessory assigned ID for the HID device
* index: offset of data in descriptor
* (needed when HID descriptor is too big for one packet)
* data the HID report descriptor
*/
#define ACCESSORY_SET_HID_REPORT_DESC 56
int usb_aoa_set_hid_report_desc(struct usb_host_device *host_dev, u16 value, u16 offset, const char *pbuf, u32 len)
{
return usb_control_msg(host_dev,
ACCESSORY_SET_HID_REPORT_DESC,
USB_DIR_OUT | USB_TYPE_VENDOR,
value,
offset,
(u8 *)pbuf,
len);
}
/* Control request for sending HID events.
*
* requestType: USB_DIR_OUT | USB_TYPE_VENDOR
* request: ACCESSORY_SEND_HID_EVENT
* value: Accessory assigned ID for the HID device
* index: 0
* data the HID report for the event
*/
#define ACCESSORY_SEND_HID_EVENT 57
int usb_aoa_send_hid_event(struct usb_host_device *host_dev, u16 value, const u8 *pbuf, u32 len)
{
return usb_control_msg(host_dev,
ACCESSORY_SEND_HID_EVENT,
USB_DIR_OUT | USB_TYPE_VENDOR,
value,
0,
(u8 *)pbuf,
len);
}
int get_ms_extended_compat_id(struct usb_host_device *host_dev, u8 *buffer)
{
return usb_control_msg(host_dev,
0x01,
USB_DIR_IN | USB_RECIP_DEVICE | USB_TYPE_VENDOR,
0x0000,
4,
buffer,
0x28);
}
int usb_set_interface(struct usb_host_device *host_dev, u8 interface, u8 alternateSetting)
{
log_info("%s Set Interface:%d AlternateSetting:%d", __func__, interface, alternateSetting);
return usb_control_msg(host_dev,
USB_REQ_SET_INTERFACE,
USB_RECIP_INTERFACE,
alternateSetting,
interface,
NULL,
0);
}
int usb_audio_sampling_frequency_control(struct usb_host_device *host_dev, u32 ep, u32 sampe_rate)
{
log_info("%s ep:%d sampe_rate:%d", __func__, ep, sampe_rate);
return usb_control_msg(host_dev,
1,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT,
0x0100,
ep,
&sampe_rate,
3);
}
int usb_audio_volume_control(struct usb_host_device *host_dev, u8 feature_id, u8 channel_num, u16 volume)
{
log_info("%s featureID:%d vol:%x", __func__, feature_id, volume);
return usb_control_msg(host_dev,
1,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
(0x02 << 8) | channel_num,
feature_id << 8,
&volume,
2);
}
int usb_audio_mute_control(struct usb_host_device *host_dev, u8 feature_id, u8 mute)
{
log_info("%s featureID:%d mute:%d", __func__, feature_id, mute);
return usb_control_msg(host_dev,
1,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0x0100,
feature_id << 8,
&mute,
1);
}
#endif
@@ -0,0 +1,404 @@
/**@file usb_ctrl_transfer.h
* @brief usb_ctrl_transfer控制传输头文件
* @details 功能函数声明
* @author jieli
* @date 2021-8-1
* @version V1.0
* @copyright Copyright(c)2010-2021 珠海市杰理科技股份有限公司
*********************************************************
* @attention
* 硬件平台:AC695N
* SDK版本:AC695N_V1.0.0_SDK
* @修改日志:
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-8-1 <td>1.0 <td>jieli <td>创建初始版本
* </table>
*
*********************************************************
*/
#ifndef __USB_CTRL_TRANSFER_H__
#define __USB_CTRL_TRANSFER_H__
#include "usb/ch9.h"
#include "usb/usb_phy.h"
#include "device/device.h"
#include "usb_config.h"
/*
* USB Packet IDs (PIDs)
*/
#define USB_PID_EXT 0xf0 /* USB 2.0 LPM ECN */
#define USB_PID_OUT 0xe1
#define USB_PID_ACK 0xd2
#define USB_PID_DATA0 0xc3
#define USB_PID_PING 0xb4 /* USB 2.0 */
#define USB_PID_SOF 0xa5
#define USB_PID_NYET 0x96 /* USB 2.0 */
#define USB_PID_DATA2 0x87 /* USB 2.0 */
#define USB_PID_SPLIT 0x78 /* USB 2.0 */
#define USB_PID_IN 0x69
#define USB_PID_NAK 0x5a
#define USB_PID_DATA1 0x4b
#define USB_PID_PREAMBLE 0x3c /* Token mode */
#define USB_PID_ERR 0x3c /* USB 2.0: handshake mode */
#define USB_PID_SETUP 0x2d
#define USB_PID_STALL 0x1e
#define USB_PID_MDATA 0x0f /* USB 2.0 */
struct ctlXfer {
struct usb_ctrlrequest setup; ///<控制请求
void *buffer; ///<控制请求的data
u8 stage; ///<当前状态
};
int usb_control_msg(struct usb_host_device *host_dev,
u8 request, u8 requesttype,
u16 value, u16 index,
void *data, u16 size);
/**@brief USB清除或禁用特定的特性
* @param[in] usb_host_device定义的结构体指针
* @param[in] ep 端点号
* @return 0:成功
* @par 示例:
* @code
* usb_clear_feature(host_dev , ep);
* @encode
*/
int usb_clear_feature(struct usb_host_device *usb_dev, u32 ep);
/**@brief USB设置地址
* @param[in] usb_host_device定义的结构体指针
* @param[in] devnum 设备编号
* @return 0:成功
* @par 示例:
* @code
* set_address(host_dev , ep);
* @encode
*/
int set_address(struct usb_host_device *usb_dev, u8 devnum);
/**@brief USB获取设备描述符
* @param[in] usb_host_device定义的结构体指针
* @param[in] usb_device_descriptor定义的结构体指针
* @return 0:成功
* @par 示例:
* @code
* usb_get_device_descriptor(host_dev , device_desc);
* @encode
*/
int usb_get_device_descriptor(struct usb_host_device *usb_dev, struct usb_device_descriptor *desc);
/**@brief USB获取字符串描述符
* @param[in] usb_host_device定义的结构体指针
* @param[in] usb_device_descriptor定义的结构体指针
* @return 0:成功
* @par 示例:
* @code
* usb_get_string_descriptor(host_dev , device_desc);
* @encode
*/
int usb_get_string_descriptor(struct usb_host_device *usb_dev, struct usb_device_descriptor *desc);
/**@brief USB设置相关配置
* @param[in] usb_host_device定义的结构体指针
* @return 0:成功
* @par 示例:
* @code
* set_configuration(host_dev);
* @encode
*/
int set_configuration(struct usb_host_device *usb_dev);
/**@brief USB设置相关配置,添加相关参数
* @param[in] usb_host_device定义的结构体指针
* @param[in] value 当前请求的参数
* @return 0:成功
* @par 示例:
* @code
* set_configuration_add_value(host_dev , value);
* @encode
*/
int set_configuration_add_value(struct usb_host_device *host_dev, u16 value);
/**@brief USB获取配置描述符
* @param[in] usb_host_device定义的结构体指针
* @param[in] cfg_desc 自定义的配置描述符指针
* @param[in] len 长度
* @return 0:成功
* @par 示例:
* @code
* get_config_descriptor(host_dev , cfg_desc , len);
* @encode
*/
int get_config_descriptor(struct usb_host_device *usb_dev, void *cfg_desc, u32 len);
/**@brief USB获取配置描述符,添加相关参数
* @param[in] usb_host_device定义的结构体指针
* @param[in] cfg_desc 自定义的配置描述符指针
* @param[in] len 长度
* @param[in] value_l 请求的参数
* @return 0:成功
* @par 示例:
* @code
* get_config_descriptor_add_value_l(host_dev , cfg_desc , len , value_l);
* @encode
*/
int get_config_descriptor_add_value_l(struct usb_host_device *host_dev, void *cfg_desc, u32 len, u8 value_l);
/**@brief USB获取大容量存储设备的最大逻辑单元号
* @param[in] usb_host_device定义的结构体指针
* @param[in] lun 逻辑单元号
* @return 0:成功
* @par 示例:
* @code
* get_msd_max_lun(host_dev , lun);
* @encode
*/
int get_msd_max_lun(struct usb_host_device *usb_dev, void *lun);
/**@brief USB设置大容量存储设备复位
* @param[in] usb_host_device定义的结构体指针
* @return 0:成功
* @par 示例:
* @code
* set_msd_reset(host_dev);
* @encode
*/
int set_msd_reset(struct usb_host_device *usb_dev);
/**@brief hid设置为空闲模式
* @param[in] usb_host_device定义的结构体指针
* @param[in] id 指定接口或端点号
* @return 0:成功
* @par 示例:
* @code
* hid_set_idle(host_dev , id);
* @encode
*/
int hid_set_idle(struct usb_host_device *usb_dev, u32 id);
/**@brief hid获取报告描述符
* @param[in] usb_host_device定义的结构体指针
* @param[in] report 自定义报告指针,指向报告内容
* @param[in] report_id 报告描述符id号
* @param[in] report_len 报告描述符长度
* @return 0:成功
* @par 示例:
* @code
* hid_get_report(host_dev , report , report_id , report_len);
* @encode
*/
int hid_get_report(struct usb_host_device *usb_dev, u8 *report, u8 report_id, u16 report_len);
/**@brief hid设置输出报告描述符
* @param[in] usb_host_device定义的结构体指针
* @param[in] report 自定义报告指针,指向报告内容
* @param[in] report_id
* @param[in] report_len
* @return 0:成功
* @par 示例:
* @code
* hid_set_output_report(host_dev , report , report_id , report_len);
* @encode
*/
int hid_set_output_report(struct usb_host_device *usb_dev, u8 *report, u8 report_id, u8 report_len);
/**@brief USB设置远程唤醒
* @param[in] usb_host_device定义的结构体指针
* @return 0:成功
* @par 示例:
* @code
* usb_set_remote_wakeup(host_dev);
* @encode
*/
int usb_set_remote_wakeup(struct usb_host_device *usb_dev);
/**@brief USB获取设备状态
* @param[in] usb_host_device定义的结构体指针
* @return 0:成功
* @par 示例:
* @code
* get_device_status(host_dev);
* @encode
*/
int get_device_status(struct usb_host_device *usb_dev, u8 *status);
/**@brief USB获取interface状态
* @param[in] usb_host_device定义的结构体指针
* @return 0:成功
* @par 示例:
* @code
* get_interface_status(host_dev, inter, status);
* @encode
*/
int get_interface_status(struct usb_host_device *usb_dev, u8 intr, u8 *status);
/**@brief USB获取endpoint状态
* @param[in] usb_host_device定义的结构体指针
* @return 0:成功
* @par 示例:
* @code
* get_interface_status(host_dev, ep, status);
* @encode
*/
int get_endpoint_status(struct usb_host_device *usb_dev, u8 ep, u8 *status);
/**@brief USB获取设备限定描述符
* @param[in] usb_host_device定义的结构体指针
* @param[in] BUFFER 自定义的指针,指向限定描述符内容
* @return 0:成功
* @par 示例:
* @code
* usb_get_device_qualifier(host_dev , buffer);
* @encode
*/
int usb_get_device_qualifier(struct usb_host_device *usb_dev, u8 *buffer);
/**@brief USB获取安卓aoa协议版本
* @param[in] usb_host_device定义的结构体指针
* @param[in] version 自定义的指针,指向版本内容
* @return 0:成功
* @par 示例:
* @code
* usb_get_aoa_version(host_dev , version);
* @encode
*/
int usb_get_aoa_version(struct usb_host_device *host_dev, u16 *version);
/**@brief USB设置证书信息
* @param[in] usb_host_device定义的结构体指针
* @param[in] string 字符串指针,指向证书内容
* @param[in] index 传递的参数
* @return 0:成功
* @par 示例:
* @code
* usb_set_credentials(host_dev , string , index);
* @encode
*/
int usb_set_credentials(struct usb_host_device *host_dev, const char *string, int index);
/**@brief USB设置aoa开关
* @param[in] usb_host_device定义的结构体指针
* @return 0:成功
* @par 示例:
* @code
* usb_switch2aoa(host_dev);
* @encode
*/
int usb_switch2aoa(struct usb_host_device *host_dev);
/**@brief USB设置从机模式开关
* @param[in] usb_host_device定义的结构体指针
* @return 0:成功
* @par 示例:
* @code
* usb_switch2slave(host_dev);
* @encode
*/
int usb_switch2slave(struct usb_host_device *host_dev);
/**@brief USB hid设备注册
* @param[in] usb_host_device定义的结构体指针
* @param[in] value 请求的参数
* @param[in] index 传递的参数
* @return 0:成功
* @par 示例:
* @code
* usb_aoa_register_hid(host_dev , value , index);
* @encode
*/
int usb_aoa_register_hid(struct usb_host_device *host_dev, u16 value, u16 index);
/**@brief USB设置hid报告描述符
* @param[in] usb_host_device定义的结构体指针
* @param[in] value 请求的参数
* @param[in] offset 偏移量参数
* @param[in] pbuf 存放数据的BUFFER指针
* @param[in] len 长度
* @return 0:成功
* @par 示例:
* @code
* usb_aoa_set_hid_report_desc(host_dev , value , offset , *pbuf , len);
* @encode
*/
int usb_aoa_set_hid_report_desc(struct usb_host_device *host_dev, u16 value, u16 offset, const char *pbuf, u32 len);
/**@brief USB发送hid事件
* @param[in] usb_host_device定义的结构体指针
* @param[in] value 请求的参数
* @param[in] pbuf 存放数据的BUFFER指针
* @param[in] len 长度
* @return 0:成功
* @par 示例:
* @code
* usb_aoa_send_hid_event(host_dev , value , *pbuf , len);
* @encode
*/
int usb_aoa_send_hid_event(struct usb_host_device *host_dev, u16 value, const u8 *pbuf, u32 len);
/**@brief 获取扩展的大容量存储设备(可兼容)id 号
* @param[in] usb_host_device定义的结构体指针
* @param[in] BUFFER 存放数据的BUFFER
* @return 0:成功
* @par 示例:
* @code
* get_ms_extended_compat_id(host_dev , value , *pbuf , len);
* @encode
*/
int get_ms_extended_compat_id(struct usb_host_device *host_dev, u8 *buffer);
/**@brief USB设置接口
* @param[in] usb_host_device定义的结构体指针
* @param[in] interface 接口参数(请求的参数)
* @param[in] alternateSetting 交替设置(传递的参数)
* @return 0:成功
* @par 示例:
* @code
* usb_set_interface(host_dev , interface , alternateSetting);
* @encode
*/
int usb_set_interface(struct usb_host_device *host_dev, u8 interface, u8 alternateSetting);
/**@brief USB音频采样频率控制
* @param[in] usb_host_device定义的结构体指针
* @param[in] ep 端点号
* @param[in] samp_rate 采样率
* @return 0:成功
* @par 示例:
* @code
* usb_audio_sampling_frequency_control(host_dev , ep , sampe_rate);
* @encode
*/
int usb_audio_sampling_frequency_control(struct usb_host_device *host_dev, u32 ep, u32 sampe_rate);
/**@brief USB音频音量控制
* @param[in] usb_host_device定义的结构体指针
* @param[in] feature_id 特征值id号(端点或接口的id)(传递的参数)
* @param[in] channel_num 通道编号(请求的参数)
* @paeam[in] volume 音量
* @return 0:成功
* @par 示例:
* @code
* usb_audio_volume_control(host_dev , feature_id , channel_num , volume);
* @encode
*/
int usb_audio_volume_control(struct usb_host_device *host_dev, u8 feature_id, u8 channel_num, u16 volume);
/**@brief USB音频静音控制
* @param[in] usb_host_device定义的结构体指针
* @param[in] feature_id 特征值id号(端点或接口的id)(传递的参数)
* @param[in] mute 静音信号(静音标志)
* @return 0:成功
* @par 示例:
* @code
* usb_audio_mute_control(host_dev , feature_id , channel_num , volume);
* @encode
*/
int usb_audio_mute_control(struct usb_host_device *host_dev, u8 feature_id, u8 mute);
#endif
@@ -0,0 +1,353 @@
/**
* USB HID Keyboard scan codes as per USB spec 1.11
* plus some additional codes
*
* Created by MightyPork, 2016
* Public domain
*
* Adapted from:
* https://source.android.com/devices/input/keyboard-devices.html
*/
#ifndef USB_HID_KEYS
#define USB_HID_KEYS
struct keyboard_data_t {
u8 fun_key;
u8 res;
u8 Keypad[6];
} _GNU_PACKED_ ;
struct mouse_data_t {
u8 btn;
s16 x;
s16 y;
s8 wheel;
s8 ac_pan;
} _GNU_PACKED_ ;
struct point_t {
u8 tip_switch: 2;
/* u8 in_range: 1; */
u8 res: 2;
u8 cid: 4;
s16 x;
s16 y;
} _GNU_PACKED_ ;
struct touch_screen_t {
struct point_t p[3];
} _GNU_PACKED_;
struct mouse_point_t {
u8 btn;
s8 x;
s8 y;
s8 wheel;
} _GNU_PACKED_;
/**
* Modifier masks - used for the first byte in the HID report.
* NOTE: The second byte in the report is reserved, 0x00
*/
#define _KEY_MOD_LCTRL 0x01
#define _KEY_MOD_LSHIFT 0x02
#define _KEY_MOD_LALT 0x04
#define _KEY_MOD_LMETA 0x08
#define _KEY_MOD_RCTRL 0x10
#define _KEY_MOD_RSHIFT 0x20
#define _KEY_MOD_RALT 0x40
#define _KEY_MOD_RMETA 0x80
/**
* Scan codes - last N slots in the HID report (usually 6).
* 0x00 if no key pressed.
*
* If more than N keys are pressed, the HID reports
* KEY_ERR_OVF in all slots to indicate this condition.
*/
#define _KEY_NONE 0x00 // No key pressed
#define _KEY_ERR_OVF 0x01 // Keyboard Error Roll Over - used for all slots if too many keys are pressed ("Phantom key")
// 0x02 // Keyboard POST Fail
// 0x03 // Keyboard Error Undefined
#define _KEY_A 0x04 // Keyboard a and A
#define _KEY_B 0x05 // Keyboard b and B
#define _KEY_C 0x06 // Keyboard c and C
#define _KEY_D 0x07 // Keyboard d and D
#define _KEY_E 0x08 // Keyboard e and E
#define _KEY_F 0x09 // Keyboard f and F
#define _KEY_G 0x0a // Keyboard g and G
#define _KEY_H 0x0b // Keyboard h and H
#define _KEY_I 0x0c // Keyboard i and I
#define _KEY_J 0x0d // Keyboard j and J
#define _KEY_K 0x0e // Keyboard k and K
#define _KEY_L 0x0f // Keyboard l and L
#define _KEY_M 0x10 // Keyboard m and M
#define _KEY_N 0x11 // Keyboard n and N
#define _KEY_O 0x12 // Keyboard o and O
#define _KEY_P 0x13 // Keyboard p and P
#define _KEY_Q 0x14 // Keyboard q and Q
#define _KEY_R 0x15 // Keyboard r and R
#define _KEY_S 0x16 // Keyboard s and S
#define _KEY_T 0x17 // Keyboard t and T
#define _KEY_U 0x18 // Keyboard u and U
#define _KEY_V 0x19 // Keyboard v and V
#define _KEY_W 0x1a // Keyboard w and W
#define _KEY_X 0x1b // Keyboard x and X
#define _KEY_Y 0x1c // Keyboard y and Y
#define _KEY_Z 0x1d // Keyboard z and Z
#define _KEY_1 0x1e // Keyboard 1 and !
#define _KEY_2 0x1f // Keyboard 2 and @
#define _KEY_3 0x20 // Keyboard 3 and #
#define _KEY_4 0x21 // Keyboard 4 and $
#define _KEY_5 0x22 // Keyboard 5 and %
#define _KEY_6 0x23 // Keyboard 6 and ^
#define _KEY_7 0x24 // Keyboard 7 and &
#define _KEY_8 0x25 // Keyboard 8 and *
#define _KEY_9 0x26 // Keyboard 9 and (
#define _KEY_0 0x27 // Keyboard 0 and )
#define _KEY_ENTER 0x28 // Keyboard Return (ENTER)
#define _KEY_ESC 0x29 // Keyboard ESCAPE
#define _KEY_BACKSPACE 0x2a // Keyboard DELETE (Backspace)
#define _KEY_TAB 0x2b // Keyboard Tab
#define _KEY_SPACE 0x2c // Keyboard Spacebar
#define _KEY_MINUS 0x2d // Keyboard - and _
#define _KEY_EQUAL 0x2e // Keyboard = and +
#define _KEY_LEFTBRACE 0x2f // Keyboard [ and {
#define _KEY_RIGHTBRACE 0x30 // Keyboard ] and }
#define _KEY_BACKSLASH 0x31 // Keyboard \ and |
#define _KEY_HASHTILDE 0x32 // Keyboard Non-US # and ~
#define _KEY_SEMICOLON 0x33 // Keyboard ; and :
#define _KEY_APOSTROPHE 0x34 // Keyboard ' and "
#define _KEY_GRAVE 0x35 // Keyboard ` and ~
#define _KEY_COMMA 0x36 // Keyboard , and <
#define _KEY_DOT 0x37 // Keyboard . and >
#define _KEY_SLASH 0x38 // Keyboard / and ?
#define _KEY_CAPSLOCK 0x39 // Keyboard Caps Lock
#define _KEY_F1 0x3a // Keyboard F1
#define _KEY_F2 0x3b // Keyboard F2
#define _KEY_F3 0x3c // Keyboard F3
#define _KEY_F4 0x3d // Keyboard F4
#define _KEY_F5 0x3e // Keyboard F5
#define _KEY_F6 0x3f // Keyboard F6
#define _KEY_F7 0x40 // Keyboard F7
#define _KEY_F8 0x41 // Keyboard F8
#define _KEY_F9 0x42 // Keyboard F9
#define _KEY_F10 0x43 // Keyboard F10
#define _KEY_F11 0x44 // Keyboard F11
#define _KEY_F12 0x45 // Keyboard F12
#define _KEY_SYSRQ 0x46 // Keyboard Print Screen
#define _KEY_SCROLLLOCK 0x47 // Keyboard Scroll Lock
#define _KEY_PAUSE 0x48 // Keyboard Pause
#define _KEY_INSERT 0x49 // Keyboard Insert
#define _KEY_HOME 0x4a // Keyboard Home
#define _KEY_PAGEUP 0x4b // Keyboard Page Up
#define _KEY_DELETE 0x4c // Keyboard Delete Forward
#define _KEY_END 0x4d // Keyboard End
#define _KEY_PAGEDOWN 0x4e // Keyboard Page Down
#define _KEY_RIGHT 0x4f // Keyboard Right Arrow
#define _KEY_LEFT 0x50 // Keyboard Left Arrow
#define _KEY_DOWN 0x51 // Keyboard Down Arrow
#define _KEY_UP 0x52 // Keyboard Up Arrow
#define _KEY_NUMLOCK 0x53 // Keyboard Num Lock and Clear
#define _KEY_KPSLASH 0x54 // Keypad /
#define _KEY_KPASTERISK 0x55 // Keypad *
#define _KEY_KPMINUS 0x56 // Keypad -
#define _KEY_KPPLUS 0x57 // Keypad +
#define _KEY_KPENTER 0x58 // Keypad ENTER
#define _KEY_KP1 0x59 // Keypad 1 and End
#define _KEY_KP2 0x5a // Keypad 2 and Down Arrow
#define _KEY_KP3 0x5b // Keypad 3 and PageDn
#define _KEY_KP4 0x5c // Keypad 4 and Left Arrow
#define _KEY_KP5 0x5d // Keypad 5
#define _KEY_KP6 0x5e // Keypad 6 and Right Arrow
#define _KEY_KP7 0x5f // Keypad 7 and Home
#define _KEY_KP8 0x60 // Keypad 8 and Up Arrow
#define _KEY_KP9 0x61 // Keypad 9 and Page Up
#define _KEY_KP0 0x62 // Keypad 0 and Insert
#define _KEY_KPDOT 0x63 // Keypad . and Delete
#define _KEY_102ND 0x64 // Keyboard Non-US \ and |
#define _KEY_COMPOSE 0x65 // Keyboard Application
#define _KEY_POWER 0x66 // Keyboard Power
#define _KEY_KPEQUAL 0x67 // Keypad =
#define _KEY_F13 0x68 // Keyboard F13
#define _KEY_F14 0x69 // Keyboard F14
#define _KEY_F15 0x6a // Keyboard F15
#define _KEY_F16 0x6b // Keyboard F16
#define _KEY_F17 0x6c // Keyboard F17
#define _KEY_F18 0x6d // Keyboard F18
#define _KEY_F19 0x6e // Keyboard F19
#define _KEY_F20 0x6f // Keyboard F20
#define _KEY_F21 0x70 // Keyboard F21
#define _KEY_F22 0x71 // Keyboard F22
#define _KEY_F23 0x72 // Keyboard F23
#define _KEY_F24 0x73 // Keyboard F24
#define _KEY_OPEN 0x74 // Keyboard Execute
#define _KEY_HELP 0x75 // Keyboard Help
#define _KEY_PROPS 0x76 // Keyboard Menu
#define _KEY_FRONT 0x77 // Keyboard Select
#define _KEY_STOP 0x78 // Keyboard Stop
#define _KEY_AGAIN 0x79 // Keyboard Again
#define _KEY_UNDO 0x7a // Keyboard Undo
#define _KEY_CUT 0x7b // Keyboard Cut
#define _KEY_COPY 0x7c // Keyboard Copy
#define _KEY_PASTE 0x7d // Keyboard Paste
#define _KEY_FIND 0x7e // Keyboard Find
#define _KEY_MUTE 0x7f // Keyboard Mute
#define _KEY_VOLUMEUP 0x80 // Keyboard Volume Up
#define _KEY_VOLUMEDOWN 0x81 // Keyboard Volume Down
// 0x82 Keyboard Locking Caps Lock
// 0x83 Keyboard Locking Num Lock
// 0x84 Keyboard Locking Scroll Lock
#define _KEY_KPCOMMA 0x85 // Keypad Comma
// 0x86 Keypad Equal Sign
#define _KEY_RO 0x87 // Keyboard International1
#define _KEY_KATAKANAHIRAGANA 0x88 // Keyboard International2
#define _KEY_YEN 0x89 // Keyboard International3
#define _KEY_HENKAN 0x8a // Keyboard International4
#define _KEY_MUHENKAN 0x8b // Keyboard International5
#define _KEY_KPJPCOMMA 0x8c // Keyboard International6
// 0x8d Keyboard International7
// 0x8e Keyboard International8
// 0x8f Keyboard International9
#define _KEY_HANGEUL 0x90 // Keyboard LANG1
#define _KEY_HANJA 0x91 // Keyboard LANG2
#define _KEY_KATAKANA 0x92 // Keyboard LANG3
#define _KEY_HIRAGANA 0x93 // Keyboard LANG4
#define _KEY_ZENKAKUHANKAKU 0x94 // Keyboard LANG5
// 0x95 Keyboard LANG6
// 0x96 Keyboard LANG7
// 0x97 Keyboard LANG8
// 0x98 Keyboard LANG9
// 0x99 Keyboard Alternate Erase
// 0x9a Keyboard SysReq/Attention
// 0x9b Keyboard Cancel
// 0x9c Keyboard Clear
// 0x9d Keyboard Prior
// 0x9e Keyboard Return
// 0x9f Keyboard Separator
// 0xa0 Keyboard Out
// 0xa1 Keyboard Oper
// 0xa2 Keyboard Clear/Again
// 0xa3 Keyboard CrSel/Props
// 0xa4 Keyboard ExSel
// 0xb0 Keypad 00
// 0xb1 Keypad 000
// 0xb2 Thousands Separator
// 0xb3 Decimal Separator
// 0xb4 Currency Unit
// 0xb5 Currency Sub-unit
#define _KEY_KPLEFTPAREN 0xb6 // Keypad (
#define _KEY_KPRIGHTPAREN 0xb7 // Keypad )
// 0xb8 Keypad {
// 0xb9 Keypad }
// 0xba Keypad Tab
// 0xbb Keypad Backspace
// 0xbc Keypad A
// 0xbd Keypad B
// 0xbe Keypad C
// 0xbf Keypad D
// 0xc0 Keypad E
// 0xc1 Keypad F
// 0xc2 Keypad XOR
// 0xc3 Keypad ^
// 0xc4 Keypad %
// 0xc5 Keypad <
// 0xc6 Keypad >
// 0xc7 Keypad &
// 0xc8 Keypad &&
// 0xc9 Keypad |
// 0xca Keypad ||
// 0xcb Keypad :
// 0xcc Keypad #
// 0xcd Keypad Space
// 0xce Keypad @
// 0xcf Keypad !
// 0xd0 Keypad Memory Store
// 0xd1 Keypad Memory Recall
// 0xd2 Keypad Memory Clear
// 0xd3 Keypad Memory Add
// 0xd4 Keypad Memory Subtract
// 0xd5 Keypad Memory Multiply
// 0xd6 Keypad Memory Divide
// 0xd7 Keypad +/-
// 0xd8 Keypad Clear
// 0xd9 Keypad Clear Entry
// 0xda Keypad Binary
// 0xdb Keypad Octal
// 0xdc Keypad Decimal
// 0xdd Keypad Hexadecimal
#define _KEY_LEFTCTRL 0xe0 // Keyboard Left Control
#define _KEY_LEFTSHIFT 0xe1 // Keyboard Left Shift
#define _KEY_LEFTALT 0xe2 // Keyboard Left Alt
#define _KEY_LEFTMETA 0xe3 // Keyboard Left GUI
#define _KEY_RIGHTCTRL 0xe4 // Keyboard Right Control
#define _KEY_RIGHTSHIFT 0xe5 // Keyboard Right Shift
#define _KEY_RIGHTALT 0xe6 // Keyboard Right Alt
#define _KEY_RIGHTMETA 0xe7 // Keyboard Right GUI
#define _KEY_MEDIA_PLAYPAUSE 0xe8
#define _KEY_MEDIA_STOPCD 0xe9
#define _KEY_MEDIA_PREVIOUSSONG 0xea
#define _KEY_MEDIA_NEXTSONG 0xeb
#define _KEY_MEDIA_EJECTCD 0xec
#define _KEY_MEDIA_VOLUMEUP 0xed
#define _KEY_MEDIA_VOLUMEDOWN 0xee
#define _KEY_MEDIA_MUTE 0xef
#define _KEY_MEDIA_WWW 0xf0
#define _KEY_MEDIA_BACK 0xf1
#define _KEY_MEDIA_FORWARD 0xf2
#define _KEY_MEDIA_STOP 0xf3
#define _KEY_MEDIA_FIND 0xf4
#define _KEY_MEDIA_SCROLLUP 0xf5
#define _KEY_MEDIA_SCROLLDOWN 0xf6
#define _KEY_MEDIA_EDIT 0xf7
#define _KEY_MEDIA_SLEEP 0xf8
#define _KEY_MEDIA_COFFEE 0xf9
#define _KEY_MEDIA_REFRESH 0xfa
#define _KEY_MEDIA_CALC 0xfb
#define _KEY_CUSTOM_CTRL_VOL_UP 0x00e9
#define _KEY_CUSTOM_CTRL_VOL_DOWN 0x00ea
#define _KEY_CUSTOM_CTRL_MUTE 0x00e2
#define _KEY_CUSTOM_CTRL_FORWARD 0x00b5
#define _KEY_CUSTOM_CTRL_STOP 0x00cd
#define _KEY_CUSTOM_CTRL_BACK 0x00b6
#define _KEY_CUSTOM_CTRL_MUSIC 0x0183
#define _KEY_CUSTOM_CTRL_CALCULATOR 0x0192
#define _KEY_CUSTOM_CTRL_SEARCH 0x0221
#define _KEY_CUSTOM_CTRL_EMAIL 0x018A
#define _KEY_CUSTOM_CTRL_HOME 0x0223
#define _KEY_BRIGHTNESS_INCREASE 0x006F
#define _KEY_BRIGHTNESS_REDUCTION 0x0070
#define _KEY_ZOOM_IN 0x022D
#define _KEY_ZOOM_OUT 0x022E
#define _KEY_CUSTOM_COPY 0x021B
#define _KEY_CUSTOM_CUT 0x021C
#define _KEY_CUSTOM_PASTE 0x021D
#define _KEY_CUSTOM_SELECT_ALL 0x021E
#define _KEY_CUSTOM_SPLIT_SCREEN 0x0196
#define _KEY_CUSTOM_LOCK 0x0030
#define _KEY_CUSTOM_ESC 0x0223
#define _KEY_CUSTOM_CALENDAR 0x018e
#define _KEY_CUSTOM_MESSAGE 0X018d
#define _KEY_CUSTOM_BROWER 0x0231
#define _KEY_CUSTOM_PROCESS 0x023a
#define _KEY_CUSTOM_SET 0x029b
#define LED_NUM_LOCK 0x01
#define LED_CAPS_LOCK 0x02
#define LED_SCROLL_CLOCK 0x04
#endif
+793
View File
@@ -0,0 +1,793 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "system/includes.h"
#include "app_config.h"
#include "device_drive.h"
/* #include "os/os_compat.h" */
#include "system/event.h"
#include "clock_manager/clock_manager.h"
#if TCFG_USB_HOST_ENABLE
#include "usb_config.h"
#include "usb/host/usb_host.h"
#include "usb/usb_phy.h"
#include "usb_ctrl_transfer.h"
#include "usb_storage.h"
#include "adb.h"
#include "aoa.h"
#include "hid.h"
#include "audio.h"
#include "host_uvc.h"
#include "usb/usb_task.h"
#if TCFG_USB_APPLE_DOCK_EN
#include "apple_dock/iAP.h"
#include "apple_mfi.h"
#endif
#define LOG_TAG_CONST USB
#define LOG_TAG "[mount]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
static struct usb_host_device host_devices[USB_MAX_HW_NUM];// SEC(.usb_h_bss);
#define device_to_usbdev(device) ((struct usb_host_device *)((device)->private_data))
int host_dev_status(const struct usb_host_device *host_dev)
{
return ((host_dev)->private_data.status);
}
u32 host_device2id(const struct usb_host_device *host_dev)
{
#if USB_MAX_HW_NUM > 1
return ((host_dev)->private_data.usb_id);
#else
return 0;
#endif
}
const struct usb_host_device *host_id2device(const usb_dev id)
{
#if USB_MAX_HW_NUM > 1
return &host_devices[id];
#else
return &host_devices[0];
#endif
}
int usb_sem_init(struct usb_host_device *host_dev)
{
usb_dev usb_id = host_device2id(host_dev);
usb_host_config(usb_id);
OS_SEM *sem = zalloc(sizeof(OS_SEM));
ASSERT(sem, "usb alloc sem error");
host_dev->sem = sem;
log_debug("%s %x %x ", __func__, host_dev, sem);
os_sem_create(host_dev->sem, 0);
return 0;
}
int usb_sem_pend(struct usb_host_device *host_dev, u32 timeout)
{
if (host_dev->sem == NULL) {
return 1;
}
int ret = os_sem_pend(host_dev->sem, timeout);
if (ret) {
log_debug("%s %d ", __func__, ret);
}
return ret;
}
int usb_sem_post(struct usb_host_device *host_dev)
{
if (host_dev->sem == NULL) {
return 1;
}
int ret = os_sem_post(host_dev->sem);
if (ret) {
log_debug("%s %d ", __func__, ret);
}
return 0;
}
int usb_sem_del(struct usb_host_device *host_dev)
{
usb_dev usb_id = host_device2id(host_dev);
if (host_dev == NULL || host_dev->sem == NULL) {
return 0;
}
#if USB_HUB
if (host_dev->father == NULL) {
os_sem_del(host_dev->sem, 0);
}
#else
os_sem_del(host_dev->sem, 0);
#endif
log_debug("%s %x %x ", __func__, host_dev, host_dev->sem);
free(host_dev->sem);
host_dev->sem = NULL;
usb_host_free(usb_id);
return 0;
}
static int _usb_msd_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
log_info("find udisk @ interface %d", interface_num);
#if TCFG_UDISK_ENABLE
return usb_msd_parser(host_dev, interface_num, pBuf);
#else
return USB_DT_INTERFACE_SIZE;
#endif
}
static int _usb_apple_mfi_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
log_info("find udisk @ interface %d", interface_num);
#if TCFG_USB_APPLE_DOCK_EN
return usb_apple_mfi_parser(host_dev, interface_num, pBuf);
#else
return USB_DT_INTERFACE_SIZE;
#endif
}
static int _usb_adb_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
log_info("find adb @ interface %d", interface_num);
#if TCFG_ADB_ENABLE
return usb_adb_parser(host_dev, interface_num, pBuf);
#else
return USB_DT_INTERFACE_SIZE;
#endif
}
static int _usb_aoa_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
log_info("find aoa @ interface %d", interface_num);
#if TCFG_AOA_ENABLE
return usb_aoa_parser(host_dev, interface_num, pBuf);
#else
return USB_DT_INTERFACE_SIZE;
#endif
}
static int _usb_hid_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
log_info("find hid @ interface %d", interface_num);
#if TCFG_HID_HOST_ENABLE
return usb_hid_parser(host_dev, interface_num, pBuf);
#else
return USB_DT_INTERFACE_SIZE;
#endif
}
static int _usb_audio_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
log_info("find audio @ interface %d", interface_num);
#if TCFG_HOST_AUDIO_ENABLE
return usb_audio_parser(host_dev, interface_num, pBuf);
#else
return USB_DT_INTERFACE_SIZE;
#endif
}
static int _usb_adb_interface_ptp_mtp_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
log_info("find adbmtp @ interface %d", interface_num);
#if TCFG_ADB_ENABLE
return usb_adb_interface_ptp_mtp_parse(host_dev, interface_num, pBuf);
#else
return USB_DT_INTERFACE_SIZE;
#endif
}
static int _usb_uvc_parse(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
{
log_info("find uvc @ interface %d", interface_num);
#if TCFG_HOST_UVC_ENABLE
return usb_uvc_parser(host_dev, interface_num, (u8 *)pBuf);
#else
return USB_DT_INTERFACE_SIZE;
#endif
}
/**
* @brief usb_descriptor_parser
*
* @param device
* @param pBuf
* @param total_len
*
* @return
*/
static int usb_descriptor_parser(struct usb_host_device *host_dev, const u8 *pBuf, u32 total_len, struct usb_device_descriptor *device_desc)
{
int len = 0;
u8 interface_num = 0;
//struct usb_private_data *private_data = &host_dev->private_data;
struct usb_config_descriptor *cfg_desc = (struct usb_config_descriptor *)pBuf;
if (cfg_desc->bDescriptorType != USB_DT_CONFIG ||
cfg_desc->bLength < USB_DT_CONFIG_SIZE) {
log_error("invalid descriptor for config bDescriptorType = %d bLength= %d",
cfg_desc->bDescriptorType, cfg_desc->bLength);
return -USB_DT_CONFIG;
}
log_info("idVendor %x idProduct %x", device_desc->idVendor, device_desc->idProduct);
len += USB_DT_CONFIG_SIZE;
pBuf += USB_DT_CONFIG_SIZE;
int i;
u32 have_find_valid_class = 0;
while (len < total_len) {
if (interface_num > MAX_HOST_INTERFACE) {
log_error("interface_num too much");
break;
}
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
if (interface->bDescriptorType == USB_DT_INTERFACE) {
log_debug("inf class %x subclass %x ep %d",
interface->bInterfaceClass, interface->bInterfaceSubClass, interface->bNumEndpoints);
if (interface->bInterfaceClass == USB_CLASS_MASS_STORAGE) {
i = _usb_msd_parser(host_dev, interface_num, pBuf);
if (i < 0) {
log_error("---%s %d---", __func__, __LINE__);
len = total_len;
} else {
interface_num++;
len += i;
pBuf += i;
have_find_valid_class = true;
}
} else if ((device_desc->idVendor == 0x05AC) &&
((device_desc->idProduct & 0xff00) == 0x1200)) {
i = _usb_apple_mfi_parser(host_dev, interface_num, pBuf);
if (i < 0) {
log_error("---%s %d---", __func__, __LINE__);
len = total_len;
} else {
interface_num++;
len += i;
pBuf += i;
have_find_valid_class = true;
}
} else if (interface->bInterfaceClass == USB_CLASS_AUDIO) {
i = _usb_audio_parser(host_dev, interface_num, pBuf);
if (i < 0) {
log_error("---%s %d---", __func__, __LINE__);
len = total_len;
} else {
interface_num++;
len += i;
pBuf += i;
have_find_valid_class = true;
}
} else if ((interface->bInterfaceClass == 0xff) &&
(interface->bInterfaceSubClass == USB_CLASS_ADB)) {
i = _usb_adb_parser(host_dev, interface_num, pBuf);
if (i < 0) {
log_error("---%s %d---", __func__, __LINE__);
len = total_len;
} else {
interface_num++;
len += i;
pBuf += i;
have_find_valid_class = true;
}
} else if ((device_desc->idVendor == 0x18d1) &&
((device_desc->idProduct & 0x2d00) == 0x2d00)) {
i = _usb_aoa_parser(host_dev, interface_num, pBuf);
if (i < 0) {
log_error("---%s %d---", __func__, __LINE__);
len = total_len;
} else {
interface_num++;
len += i;
pBuf += i;
have_find_valid_class = true;
}
} else if (interface->bInterfaceClass == USB_CLASS_HID) {
i = _usb_hid_parser(host_dev, interface_num, pBuf);
if (i < 0) {
log_error("---%s %d---", __func__, __LINE__);
len = total_len;
} else {
interface_num++;
len += i;
pBuf += i;
have_find_valid_class = true;
}
} else if ((interface->bNumEndpoints == 3) &&
(interface->bInterfaceClass == 0xff || interface->bInterfaceClass == 0x06)) {
i = _usb_adb_interface_ptp_mtp_parse(host_dev, interface_num, pBuf);
if (i < 0) {
log_error("---%s %d---", __func__, __LINE__);
len = total_len;
} else {
interface_num++;
len += i;
pBuf += i;
}
have_find_valid_class = true;
} else if ((interface->bInterfaceClass == 0xff) &&
(interface->bInterfaceSubClass == 0xff)) {
i = _usb_aoa_parser(host_dev, interface_num, pBuf);
if (i < 0) {
log_error("---%s %d---", __func__, __LINE__);
len = total_len;
} else {
interface_num++;
len += i;
pBuf += i;
}
have_find_valid_class = true;
} else if (interface->bInterfaceClass == USB_CLASS_VIDEO) {
i = _usb_uvc_parse(host_dev, interface_num, pBuf);
if (i < 0) {
log_error("---%s %d---", __func__, __LINE__);
len = total_len;
} else {
interface_num += 2;
len += i;
pBuf += i;
}
have_find_valid_class = true;
} else {
log_info("find unsupport [class %x subClass %x] @ interface %d",
interface->bInterfaceClass,
interface->bInterfaceSubClass,
interface_num);
len += USB_DT_INTERFACE_SIZE;
pBuf += USB_DT_INTERFACE_SIZE;
}
} else {
/* log_error("unknown section %d %d", len, pBuf[0]); */
if (pBuf[0]) {
len += pBuf[0];
pBuf += pBuf[0];
} else {
len = total_len;
}
}
}
log_debug("len %d total_len %d", len, total_len);
return !have_find_valid_class;
}
/* --------------------------------------------------------------------------*/
/**
* @brief usb_host_suspend
*
* @param usb
*
* @return
*/
/* --------------------------------------------------------------------------*/
void usb_host_suspend(const usb_dev usb_id)
{
usb_h_entry_suspend(usb_id);
}
void usb_host_resume(const usb_dev usb_id)
{
usb_h_resume(usb_id);
}
static int usb_event_notify(const struct usb_host_device *host_dev, u32 ev)
{
const usb_dev id = host_device2id(host_dev);
u32 event;
typedef struct {
char subdev[MAX_HOST_INTERFACE][8];
} subdev_t;
static subdev_t itf_set[USB_MAX_HW_NUM];
static u32 bmUsbEvent[USB_MAX_HW_NUM];
u8 have_post_event = 0;
u8 no_send_event = 0;
if (ev == 0) {
event = DEVICE_EVENT_IN;
} else if (ev == 1) {
event = DEVICE_EVENT_CHANGE;
} else {
event = DEVICE_EVENT_OUT;
goto __usb_event_out;
}
for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
memset(itf_set[id].subdev[i], 0, sizeof(itf_set[id].subdev[i]));
}
for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
no_send_event = 0;
/* memset(itf_set[id].subdev[i], 0, sizeof(itf_set[id].subdev[i])); */
if (host_dev->interface_info[i]) {
switch (host_dev->interface_info[i]->ctrl->interface_class) {
#if TCFG_UDISK_ENABLE
case USB_CLASS_MASS_STORAGE:
if (have_post_event & BIT(0)) {
no_send_event = 1;
} else {
have_post_event |= BIT(0);
}
sprintf(itf_set[id].subdev[i], "udisk%d", id);
bmUsbEvent[id] |= BIT(0);
break;
#endif
#if TCFG_ADB_ENABLE
case USB_CLASS_ADB:
if (have_post_event & BIT(1)) {
no_send_event = 1;
} else {
have_post_event |= BIT(1);
}
sprintf(itf_set[id].subdev[i], "adb%d", id);
bmUsbEvent[id] |= BIT(1);
break;
#endif
#if TCFG_AOA_ENABLE
case USB_CLASS_AOA:
if (have_post_event & BIT(2)) {
no_send_event = 1;
} else {
have_post_event |= BIT(2);
}
sprintf(itf_set[id].subdev[i], "aoa%d", id);
bmUsbEvent[id] |= BIT(2);
break;
#endif
#if TCFG_HID_HOST_ENABLE
case USB_CLASS_HID:
if (have_post_event & BIT(3)) {
no_send_event = 1;
} else {
have_post_event |= BIT(3);
}
sprintf(itf_set[id].subdev[i], "hid%d", id);
bmUsbEvent[id] |= BIT(3);
break;
#endif
#if TCFG_HOST_AUDIO_ENABLE
case USB_CLASS_AUDIO:
if (have_post_event & BIT(4)) {
no_send_event = 1;
} else {
have_post_event |= BIT(4);
}
sprintf(itf_set[id].subdev[i], "audio%d", id);
bmUsbEvent[id] |= BIT(4);
break;
#endif
#if TCFG_HOST_UVC_ENABLE
case USB_CLASS_VIDEO:
if (have_post_event & BIT(5)) {
no_send_event = 1;
} else {
have_post_event |= BIT(5);
}
sprintf(itf_set[id].subdev[5], "uvc%d", id);
bmUsbEvent[id] |= BIT(5);
break;
#endif
}
//cppcheck-suppress knownConditionTrueFalse
/* if (!no_send_event && itf_set[id].subdev[i][0]) { */
if (!no_send_event) {
for (u8 k = 0; k < MAX_HOST_INTERFACE; k++) {
if (itf_set[id].subdev[k][0]) {
log_info("event %x interface %x class %x %s",
event,
i,
host_dev->interface_info[i]->ctrl->interface_class,
itf_set[id].subdev[k]);
/* printf("usb_host_mount notify >>>>>>>>>>>\n"); */
/* usb_driver_event_to_user(DEVICE_EVENT_FROM_USB_HOST, event, itf_set[id].subdev[i]); */
os_taskq_post_msg(USB_TASK_NAME, 3, USBSTACK_HOST_MSG, event, itf_set[id].subdev[k]);
}
}
}
}
}
__usb_event_out:
if (event == DEVICE_EVENT_OUT) {
for (int i = 0; i < 32; i++) {
if (bmUsbEvent[id] & BIT(i)) {
bmUsbEvent[id] &= ~BIT(i);
if (itf_set[id].subdev[i][0]) {
have_post_event = 1;
/* usb_driver_event_to_user(DEVICE_EVENT_FROM_USB_HOST, event, itf_set[id].subdev[i]); */
os_taskq_post_msg(USB_TASK_NAME, 3, USBSTACK_HOST_MSG, event, itf_set[id].subdev[i]);
}
}
}
}
if (have_post_event) {
return DEV_ERR_NONE;
} else {
return DEV_ERR_UNKNOW_CLASS;
}
}
static u32 _usb_host_mount(const usb_dev usb_id, u32 retry, u32 reset_delay, u32 mount_timeout)
{
u32 ret = DEV_ERR_NONE;
struct usb_host_device *host_dev = &host_devices[usb_id];
struct usb_private_data *private_data = &host_dev->private_data;
u32 speed = USB_SPEED_FULL;
#if defined(FUSB_MODE) && FUSB_MODE
speed = USB_SPEED_FULL;
#elif defined(FUSB_MODE) && (FUSB_MODE == 0)
speed = USB_SPEED_HIGH;
#endif
usb_host_clock_lock();
for (int i = 0; i < retry; i++) {
usb_h_sie_init(usb_id);
ret = usb_host_init(usb_id, reset_delay, mount_timeout, speed);
if (ret) {
reset_delay += 10;
continue;
}
void *const ep0_dma = usb_h_alloc_ep_buffer(usb_id, 0, 64);
usb_set_dma_taddr(usb_id, 0, ep0_dma);
usb_sie_enable(usb_id);//enable sie intr
usb_mdelay(reset_delay);
/**********get device descriptor*********/
struct usb_device_descriptor device_desc;
private_data->usb_id = usb_id;
private_data->status = 0;
private_data->devnum = 0;
private_data->ep0_max_packet_size = 8;
usb_get_device_descriptor(host_dev, &device_desc);
/**********set address*********/
usb_mdelay(20);
u8 devnum = rand32() % 16 + 1;
ret = set_address(host_dev, devnum);
check_usb_mount(ret);
private_data->devnum = devnum ;
/**********get device descriptor*********/
usb_mdelay(20);
ret = usb_get_device_descriptor(host_dev, &device_desc);
check_usb_mount(ret);
private_data->ep0_max_packet_size = device_desc.bMaxPacketSize0;
/**********get config descriptor*********/
struct usb_config_descriptor cfg_desc;
ret = get_config_descriptor(host_dev, &cfg_desc, USB_DT_CONFIG_SIZE);
check_usb_mount(ret);
#if USB_H_MALLOC_ENABLE
u8 *desc_buf = zalloc(cfg_desc.wTotalLength + 16);
ASSERT(desc_buf, "desc_buf");
#else
u8 desc_buf[128] = {0};
cfg_desc.wTotalLength = min(sizeof(desc_buf), cfg_desc.wTotalLength);
#endif
ret = get_config_descriptor(host_dev, desc_buf, cfg_desc.wTotalLength);
check_usb_mount(ret);
/**********set configuration*********/
ret = set_configuration(host_dev);
/* printf_buf(desc_buf, cfg_desc.wTotalLength); */
ret |= usb_descriptor_parser(host_dev, desc_buf, cfg_desc.wTotalLength, &device_desc);
#if USB_H_MALLOC_ENABLE
log_info("free:desc_buf= %x\n", desc_buf);
free(desc_buf);
#endif
check_usb_mount(ret);
for (int itf = 0; itf < MAX_HOST_INTERFACE; itf++) {
if (host_dev->interface_info[itf]) {
if (host_dev->interface_info[itf]->ctrl->set_power) {
host_dev->interface_info[itf]->ctrl->set_power(host_dev, 1);
}
}
}
break;//succ
}
if (ret) {
goto __exit_fail;
}
private_data->status = 1;
return DEV_ERR_NONE;
__exit_fail:
log_error("usb_probe fail");
private_data->status = 0;
usb_sie_close(usb_id);
usb_host_clock_unlock(NULL);
return ret;
}
/* --------------------------------------------------------------------------*/
/**
* @brief usb_host_mount
*
* @param usb
*
* @return
*/
/* --------------------------------------------------------------------------*/
u32 usb_host_mount(const usb_dev id, u32 retry, u32 reset_delay, u32 mount_timeout)
{
#if USB_MAX_HW_NUM > 1
const usb_dev usb_id = id;
#else
const usb_dev usb_id = 0;
#endif
u32 ret;
struct usb_host_device *host_dev = &host_devices[usb_id];
memset(host_dev, 0, sizeof(*host_dev));
host_dev->private_data.usb_id = id;
usb_sem_init(host_dev);
usb_h_isr_reg(usb_id, 1, 0);
ret = _usb_host_mount(usb_id, retry, reset_delay, mount_timeout);
usb_otg_resume(usb_id); //打开usb host之后恢复otg检测
if (ret) {
goto __exit_fail;
}
return usb_event_notify(host_dev, 0);
__exit_fail:
usb_sie_disable(usb_id);
usb_sem_del(host_dev);
return ret;
}
static u32 _usb_host_unmount(const usb_dev usb_id)
{
struct usb_host_device *host_dev = &host_devices[usb_id];
struct usb_private_data *private_data = &host_dev->private_data;
private_data->status = 0;
usb_sem_post(host_dev);//拔掉设备时,让读写线程快速释放
for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
if (host_dev->interface_info[i]) {
if (host_dev->interface_info[i]->ctrl->set_power) {
host_dev->interface_info[i]->ctrl->set_power(host_dev, 0);
}
if (host_dev->interface_info[i]->ctrl->release) {
host_dev->interface_info[i]->ctrl->release(host_dev);
}
host_dev->interface_info[i] = NULL;
}
}
usb_sie_close(usb_id);
return DEV_ERR_NONE;
}
/* --------------------------------------------------------------------------*/
/**
* @brief usb_host_unmount
*
* @param usb
*
* @return
*/
/* --------------------------------------------------------------------------*/
/* u32 usb_host_unmount(const usb_dev usb_id, char *device_name) */
u32 usb_host_unmount(const usb_dev id)
{
#if USB_MAX_HW_NUM > 1
const usb_dev usb_id = id;
#else
const usb_dev usb_id = 0;
#endif
u32 ret;
struct usb_host_device *host_dev = &host_devices[usb_id];
#if (TCFG_UDISK_ENABLE && UDISK_READ_512_ASYNC_ENABLE)
_usb_stor_async_wait_sem(host_dev);
#endif
ret = _usb_host_unmount(usb_id);
if (ret) {
goto __exit_fail;
}
usb_sem_del(host_dev);
/* printf("usb_host_unmount notify >>>>>>>>>>>\n"); */
usb_event_notify(host_dev, 2);
return DEV_ERR_NONE;
__exit_fail:
return ret;
}
u32 usb_host_remount(const usb_dev id, u32 retry, u32 delay, u32 ot, u8 notify)
{
#if USB_MAX_HW_NUM > 1
const usb_dev usb_id = id;
#else
const usb_dev usb_id = 0;
#endif
u32 ret;
ret = _usb_host_unmount(usb_id);
if (ret) {
goto __exit_fail;
}
struct usb_host_device *host_dev = &host_devices[usb_id];
os_sem_set(host_dev->sem, 0);
ret = _usb_host_mount(usb_id, retry, delay, ot);
if (ret) {
goto __exit_fail;
}
if (notify) {
usb_event_notify(host_dev, 1);
}
return DEV_ERR_NONE;
__exit_fail:
return ret;
}
int usb_host_force_reset(const usb_dev usb_id)
{
//预留以后加上hub的处理
usb_h_force_reset(usb_id);
return 0;
}
static u16 clock_lock_timer;
void usb_host_clock_unlock(void *priv)
{
#ifdef CONFIG_CPU_BR27
if (clock_lock_timer) {
clock_unlock("usb_host");
sys_timeout_del(clock_lock_timer);
clock_lock_timer = 0;
}
#endif
}
void usb_host_clock_lock(void)
{
#ifdef CONFIG_CPU_BR27
if (clock_lock_timer) {
sys_timer_re_run(clock_lock_timer);
return;
}
clock_lock("usb_host", 320000000);
clock_lock_timer = sys_timeout_add(NULL, usb_host_clock_unlock, 3000);
#endif
}
#endif
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,150 @@
/**@file usb_storage.h
* @brief usb_storage驱动头文件
* @details
* @author jieli
* @date 2021-8-1
* @version V1.0
* @copyright Copyright(c)2010-2021
*********************************************************
* @attention
* AC695N
* SDK版本AC695N_V1.0.0_SDK
* @
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-8-1 <td>1.0 <td>jieli <td>
* </table>
*
*********************************************************
*/
#ifndef __USB_STORAGE_H__
#define __USB_STORAGE_H__
#include "system/task.h"
#include "device/device.h"
#include "usb/scsi.h"
#include "usb_bulk_transfer.h"
#include "usb/host/usb_host.h"
/* u盘预读功能配置, 二选一
* 使 */
#define UDISK_READ_BIGBLOCK_ASYNC_ENABLE 0 //使能大扇区预读方式(不需要额外buf,速度比512预读慢10%)
#define UDISK_READ_512_ASYNC_ENABLE 0 //使能512Byte预读方式(需要额外的512byte buffer,速度比大扇区预读快10%)
/****************************/
#define UDISK_READ_ASYNC_BLOCK_NUM (16) //预读扇区数
//****************************youning***********************************----->
#define UDISK_READ_AHEAD_ENABLE 0 //使能U盘预读功能
#define UDISK_READ_AHEAD_BLOCK_NUM 16 //U盘预读扇区数量
#define check_usb_read_ahead(ret) \
if(ret < 0) {\
log_error("func:%s,line:%d,lba:%d,ret:%d\n", __func__, __LINE__, lba, ret);\
goto __exit;\
} //检查函数返回值,0:正确 非0:错误
//****************************youning***********************************<-----
/**@enum usb_sta
* @brief USB设备当前状态
*/
typedef enum usb_sta {
DEV_IDLE = 0, ///<空闲状态
DEV_INIT, ///<初始化
DEV_OPEN, ///<开启
DEV_READ, ///<读操作
DEV_WRITE, ///<写操作
DEV_CLOSE, ///<关闭
DEV_SUSPEND, ///<挂起
} USB_STA ;
/**@struct udisk_end_desc
* @brief U盘端点描述结构体
*
*/
struct udisk_end_desc {
u8 host_epout; ///<主机端点输出
u8 target_epout; ///<目标端点输出
u8 host_epin; ///<主机端点输入
u8 target_epin; ///<目标端点输入
u16 rxmaxp; ///<接收最大端点号
u16 txmaxp; ///<发送最大端点号
u8 *epin_buf;
u8 *epout_buf;
};
#define ENABLE_DISK_HOTPLUG 0
/**@struct mass_storage
* @brief mass_storage协议所使用的相关变量
*/
struct mass_storage {
OS_MUTEX mutex; ///<互斥量
struct usb_scsi_cbw cbw; ///<CBW指令结构体
struct usb_scsi_csw csw; ///<CSW状态结构体
struct request_sense_data sense; ///<请求数据检查结构体
char *name; ///<设备名字
struct read_capacity_data capacity[2]; ///<读取数据的能力,包含数据块的编号、大小
u8 lun: 4; ///<最大逻辑单元地址
u8 curlun: 4; ///<当前逻辑单元地址
u8 dev_status: 4; ///<设备状态
u8 read_only: 1; ///<只读标志位
u8 init_done: 1; ///<初始化完成标志位
u8 : 2;
u8 suspend_cnt; ///<挂起状态计数器
u32 remain_len; ///<剩余的包长度
u32 prev_lba; ///<上一次扇区
#if (UDISK_READ_BIGBLOCK_ASYNC_ENABLE || UDISK_READ_512_ASYNC_ENABLE)
u8 async_en; ///<异步模式使能
u8 need_send_csw; ///<需要发送csw标志位
u8 *udisk_512_buf; ///<U盘512K大小BUFFER指针
u32 async_prev_lba; ///<异步模式上一次地址
#endif
#if UDISK_READ_AHEAD_ENABLE
u8 udisk_read_ahead_en;
u8 *udisk_read_ahead_buf; ///<U盘512byte大小BUFFER指针
u32 udisk_read_ahead_lba_last; ///<异步模式上一次地址
#endif
#if ENABLE_DISK_HOTPLUG
u8 media_sta_cur; ///<当前媒介状态 //for card reader, card removable
u8 media_sta_prev; ///<上次媒介状态
int test_unit_ready_tick; ///<测试准备标记
#endif
};
enum usb_async_mode {
BULK_ASYNC_MODE_EXIT = 0, ///<退出异步模式
BULK_ASYNC_MODE_SEM_PEND, ///<异步预读等待信号量
};
#define MASS_LBA_INIT (-2)
extern const struct device_operations mass_storage_ops;
/**@brief 使用mass_storage协议,对大容量存储设备进行解析,端点配置
* @param[in] usb_host_device定义的结构体指针
* @param[in] interface_num
* @param[in] *pBuf BUFFER的指针
* @return len BUFFER的长度
* @par
* @code
* usb_msd_parser(host_dev,interface_num,pBuf);
* @encode
*/
int usb_msd_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf);
/**@brief 异步模式等待信号量
* @param[in] usb_host_device定义的结构体指针
* @return 0:
* @par
* @code
* _usb_stor_async_wait_sem(host_dev);
* @encode
*/
int _usb_stor_async_wait_sem(struct usb_host_device *host_dev);
#endif
File diff suppressed because it is too large Load Diff
+580
View File
@@ -0,0 +1,580 @@
/*
* USB Video Class definitions.
*
* Copyright (C) 2009 Laurent Pinchart <laurent.pinchart@skynet.be>
*
* This file holds USB constants and structures defined by the USB Device
* Class Definition for Video Devices. Unless otherwise stated, comments
* below reference relevant sections of the USB Video Class 1.1 specification
* available at
*
* http://www.usb.org/developers/devclass_docs/USB_Video_Class_1_1.zip
*/
#ifndef __LINUX_USB_VIDEO_H
#define __LINUX_USB_VIDEO_H
#include "typedef.h"
#include "usb.h"
#ifndef __u8
#define __u8 unsigned char
#endif
#ifndef __u16
#define __u16 unsigned short
#endif
#ifndef __u32
#define __u32 unsigned int
#endif
/* --------------------------------------------------------------------------
* UVC constants
*/
/* A.2. Video Interface Subclass Codes */
#define UVC_SC_UNDEFINED 0x00
#define UVC_SC_VIDEOCONTROL 0x01
#define UVC_SC_VIDEOSTREAMING 0x02
#define UVC_SC_VIDEO_INTERFACE_COLLECTION 0x03
/* A.3. Video Interface Protocol Codes */
#define UVC_PC_PROTOCOL_UNDEFINED 0x00
/* A.5. Video Class-Specific VC Interface Descriptor Subtypes */
#define UVC_VC_DESCRIPTOR_UNDEFINED 0x00
#define UVC_VC_HEADER 0x01
#define UVC_VC_INPUT_TERMINAL 0x02
#define UVC_VC_OUTPUT_TERMINAL 0x03
#define UVC_VC_SELECTOR_UNIT 0x04
#define UVC_VC_PROCESSING_UNIT 0x05
#define UVC_VC_EXTENSION_UNIT 0x06
/* A.6. Video Class-Specific VS Interface Descriptor Subtypes */
#define UVC_VS_UNDEFINED 0x00
#define UVC_VS_INPUT_HEADER 0x01
#define UVC_VS_OUTPUT_HEADER 0x02
#define UVC_VS_STILL_IMAGE_FRAME 0x03
#define UVC_VS_FORMAT_UNCOMPRESSED 0x04
#define UVC_VS_FRAME_UNCOMPRESSED 0x05
#define UVC_VS_FORMAT_MJPEG 0x06
#define UVC_VS_FRAME_MJPEG 0x07
#define UVC_VS_FORMAT_MPEG2TS 0x0a
#define UVC_VS_FORMAT_DV 0x0c
#define UVC_VS_COLORFORMAT 0x0d
#define UVC_VS_FORMAT_FRAME_BASED 0x10
#define UVC_VS_FRAME_FRAME_BASED 0x11
#define UVC_VS_FORMAT_STREAM_BASED 0x12
/* A.7. Video Class-Specific Endpoint Descriptor Subtypes */
#define UVC_EP_UNDEFINED 0x00
#define UVC_EP_GENERAL 0x01
#define UVC_EP_ENDPOINT 0x02
#define UVC_EP_INTERRUPT 0x03
/* A.8. Video Class-Specific Request Codes */
#define UVC_RC_UNDEFINED 0x00
#define UVC_SET_CUR 0x01
#define UVC_GET_CUR 0x81
#define UVC_GET_MIN 0x82
#define UVC_GET_MAX 0x83
#define UVC_GET_RES 0x84
#define UVC_GET_LEN 0x85
#define UVC_GET_INFO 0x86
#define UVC_GET_DEF 0x87
/* A.9.1. VideoControl Interface Control Selectors */
#define UVC_VC_CONTROL_UNDEFINED 0x00
#define UVC_VC_VIDEO_POWER_MODE_CONTROL 0x01
#define UVC_VC_REQUEST_ERROR_CODE_CONTROL 0x02
/* A.9.2. Terminal Control Selectors */
#define UVC_TE_CONTROL_UNDEFINED 0x00
/* A.9.3. Selector Unit Control Selectors */
#define UVC_SU_CONTROL_UNDEFINED 0x00
#define UVC_SU_INPUT_SELECT_CONTROL 0x01
/* A.9.4. Camera Terminal Control Selectors */
#define UVC_CT_CONTROL_UNDEFINED 0x00
#define UVC_CT_SCANNING_MODE_CONTROL 0x01
#define UVC_CT_AE_MODE_CONTROL 0x02
#define UVC_CT_AE_PRIORITY_CONTROL 0x03
#define UVC_CT_EXPOSURE_TIME_ABSOLUTE_CONTROL 0x04
#define UVC_CT_EXPOSURE_TIME_RELATIVE_CONTROL 0x05
#define UVC_CT_FOCUS_ABSOLUTE_CONTROL 0x06
#define UVC_CT_FOCUS_RELATIVE_CONTROL 0x07
#define UVC_CT_FOCUS_AUTO_CONTROL 0x08
#define UVC_CT_IRIS_ABSOLUTE_CONTROL 0x09
#define UVC_CT_IRIS_RELATIVE_CONTROL 0x0a
#define UVC_CT_ZOOM_ABSOLUTE_CONTROL 0x0b
#define UVC_CT_ZOOM_RELATIVE_CONTROL 0x0c
#define UVC_CT_PANTILT_ABSOLUTE_CONTROL 0x0d
#define UVC_CT_PANTILT_RELATIVE_CONTROL 0x0e
#define UVC_CT_ROLL_ABSOLUTE_CONTROL 0x0f
#define UVC_CT_ROLL_RELATIVE_CONTROL 0x10
#define UVC_CT_PRIVACY_CONTROL 0x11
/* A.9.5. Processing Unit Control Selectors */
#define UVC_PU_CONTROL_UNDEFINED 0x00
#define UVC_PU_BACKLIGHT_COMPENSATION_CONTROL 0x01
#define UVC_PU_BRIGHTNESS_CONTROL 0x02
#define UVC_PU_CONTRAST_CONTROL 0x03
#define UVC_PU_GAIN_CONTROL 0x04
#define UVC_PU_POWER_LINE_FREQUENCY_CONTROL 0x05
#define UVC_PU_HUE_CONTROL 0x06
#define UVC_PU_SATURATION_CONTROL 0x07
#define UVC_PU_SHARPNESS_CONTROL 0x08
#define UVC_PU_GAMMA_CONTROL 0x09
#define UVC_PU_WHITE_BALANCE_TEMPERATURE_CONTROL 0x0a
#define UVC_PU_WHITE_BALANCE_TEMPERATURE_AUTO_CONTROL 0x0b
#define UVC_PU_WHITE_BALANCE_COMPONENT_CONTROL 0x0c
#define UVC_PU_WHITE_BALANCE_COMPONENT_AUTO_CONTROL 0x0d
#define UVC_PU_DIGITAL_MULTIPLIER_CONTROL 0x0e
#define UVC_PU_DIGITAL_MULTIPLIER_LIMIT_CONTROL 0x0f
#define UVC_PU_HUE_AUTO_CONTROL 0x10
#define UVC_PU_ANALOG_VIDEO_STANDARD_CONTROL 0x11
#define UVC_PU_ANALOG_LOCK_STATUS_CONTROL 0x12
/* A.9.7. VideoStreaming Interface Control Selectors */
#define UVC_VS_CONTROL_UNDEFINED 0x00
#define UVC_VS_PROBE_CONTROL 0x01
#define UVC_VS_COMMIT_CONTROL 0x02
#define UVC_VS_STILL_PROBE_CONTROL 0x03
#define UVC_VS_STILL_COMMIT_CONTROL 0x04
#define UVC_VS_STILL_IMAGE_TRIGGER_CONTROL 0x05
#define UVC_VS_STREAM_ERROR_CODE_CONTROL 0x06
#define UVC_VS_GENERATE_KEY_FRAME_CONTROL 0x07
#define UVC_VS_UPDATE_FRAME_SEGMENT_CONTROL 0x08
#define UVC_VS_SYNC_DELAY_CONTROL 0x09
/* B.1. USB Terminal Types */
#define UVC_TT_VENDOR_SPECIFIC 0x0100
#define UVC_TT_STREAMING 0x0101
/* B.2. Input Terminal Types */
#define UVC_ITT_VENDOR_SPECIFIC 0x0200
#define UVC_ITT_CAMERA 0x0201
#define UVC_ITT_MEDIA_TRANSPORT_INPUT 0x0202
/* B.3. Output Terminal Types */
#define UVC_OTT_VENDOR_SPECIFIC 0x0300
#define UVC_OTT_DISPLAY 0x0301
#define UVC_OTT_MEDIA_TRANSPORT_OUTPUT 0x0302
/* B.4. External Terminal Types */
#define UVC_EXTERNAL_VENDOR_SPECIFIC 0x0400
#define UVC_COMPOSITE_CONNECTOR 0x0401
#define UVC_SVIDEO_CONNECTOR 0x0402
#define UVC_COMPONENT_CONNECTOR 0x0403
/* 2.4.2.2. Status Packet Type */
#define UVC_STATUS_TYPE_CONTROL 1
#define UVC_STATUS_TYPE_STREAMING 2
/* 2.4.3.3. Payload Header Information */
#define UVC_STREAM_EOH (1 << 7)
#define UVC_STREAM_ERR (1 << 6)
#define UVC_STREAM_STI (1 << 5)
#define UVC_STREAM_RES (1 << 4)
#define UVC_STREAM_SCR (1 << 3)
#define UVC_STREAM_PTS (1 << 2)
#define UVC_STREAM_EOF (1 << 1)
#define UVC_STREAM_FID (1 << 0)
/* 4.1.2. Control Capabilities */
#define UVC_CONTROL_CAP_GET (1 << 0)
#define UVC_CONTROL_CAP_SET (1 << 1)
#define UVC_CONTROL_CAP_DISABLED (1 << 2)
#define UVC_CONTROL_CAP_AUTOUPDATE (1 << 3)
#define UVC_CONTROL_CAP_ASYNCHRONOUS (1 << 4)
/* ------------------------------------------------------------------------
* UVC structures
*/
/* All UVC descriptors have these 3 fields at the beginning */
struct uvc_descriptor_header {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
} __attribute__((packed));
/* 3.7.2. Video Control Interface Header Descriptor */
struct uvc_header_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u16 bcdUVC;
__u16 wTotalLength;
__u32 dwClockFrequency;
__u8 bInCollection;
__u8 baInterfaceNr[];
} __attribute__((__packed__));
#define UVC_DT_HEADER_SIZE(n) (12+(n))
#define UVC_HEADER_DESCRIPTOR(n) \
uvc_header_descriptor_##n
#define DECLARE_UVC_HEADER_DESCRIPTOR(n) \
struct UVC_HEADER_DESCRIPTOR(n) { \
__u8 bLength; \
__u8 bDescriptorType; \
__u8 bDescriptorSubType; \
__u16 bcdUVC; \
__u16 wTotalLength; \
__u32 dwClockFrequency; \
__u8 bInCollection; \
__u8 baInterfaceNr[n]; \
} __attribute__ ((packed))
/* 3.7.2.1. Input Terminal Descriptor */
struct uvc_input_terminal_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bTerminalID;
__u16 wTerminalType;
__u8 bAssocTerminal;
__u8 iTerminal;
} __attribute__((__packed__));
#define UVC_DT_INPUT_TERMINAL_SIZE 8
/* 3.7.2.2. Output Terminal Descriptor */
struct uvc_output_terminal_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bTerminalID;
__u16 wTerminalType;
__u8 bAssocTerminal;
__u8 bSourceID;
__u8 iTerminal;
} __attribute__((__packed__));
#define UVC_DT_OUTPUT_TERMINAL_SIZE 9
/* 3.7.2.3. Camera Terminal Descriptor */
struct uvc_camera_terminal_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bTerminalID;
__u16 wTerminalType;
__u8 bAssocTerminal;
__u8 iTerminal;
__u16 wObjectiveFocalLengthMin;
__u16 wObjectiveFocalLengthMax;
__u16 wOcularFocalLength;
__u8 bControlSize;
__u8 bmControls[3];
} __attribute__((__packed__));
#define UVC_DT_CAMERA_TERMINAL_SIZE(n) (15+(n))
/* 3.7.2.4. Selector Unit Descriptor */
struct uvc_selector_unit_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bUnitID;
__u8 bNrInPins;
__u8 baSourceID[0];
__u8 iSelector;
} __attribute__((__packed__));
#define UVC_DT_SELECTOR_UNIT_SIZE(n) (6+(n))
#define UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
uvc_selector_unit_descriptor_##n
#define DECLARE_UVC_SELECTOR_UNIT_DESCRIPTOR(n) \
struct UVC_SELECTOR_UNIT_DESCRIPTOR(n) { \
__u8 bLength; \
__u8 bDescriptorType; \
__u8 bDescriptorSubType; \
__u8 bUnitID; \
__u8 bNrInPins; \
__u8 baSourceID[n]; \
__u8 iSelector; \
} __attribute__ ((packed))
/* 3.7.2.5. Processing Unit Descriptor */
struct uvc_processing_unit_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bUnitID;
__u8 bSourceID;
__u16 wMaxMultiplier;
__u8 bControlSize;
__u8 bmControls[2];
__u8 iProcessing;
} __attribute__((__packed__));
#define UVC_DT_PROCESSING_UNIT_SIZE(n) (9+(n))
/* 3.7.2.6. Extension Unit Descriptor */
struct uvc_extension_unit_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bUnitID;
__u8 guidExtensionCode[16];
__u8 bNumControls;
__u8 bNrInPins;
__u8 baSourceID[0];
__u8 bControlSize;
__u8 bmControls[0];
__u8 iExtension;
} __attribute__((__packed__));
#define UVC_DT_EXTENSION_UNIT_SIZE(p, n) (24+(p)+(n))
#define UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
uvc_extension_unit_descriptor_##p_##n
#define DECLARE_UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) \
struct UVC_EXTENSION_UNIT_DESCRIPTOR(p, n) { \
__u8 bLength; \
__u8 bDescriptorType; \
__u8 bDescriptorSubType; \
__u8 bUnitID; \
__u8 guidExtensionCode[16]; \
__u8 bNumControls; \
__u8 bNrInPins; \
__u8 baSourceID[p]; \
__u8 bControlSize; \
__u8 bmControls[n]; \
__u8 iExtension; \
} __attribute__ ((packed))
/* 3.8.2.2. Video Control Interrupt Endpoint Descriptor */
struct uvc_control_endpoint_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u16 wMaxTransferSize;
} __attribute__((__packed__));
#define UVC_DT_CONTROL_ENDPOINT_SIZE 5
/* 3.9.2.1. Input Header Descriptor */
struct uvc_input_header_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bNumFormats;
__u16 wTotalLength;
__u8 bEndpointAddress;
__u8 bmInfo;
__u8 bTerminalLink;
__u8 bStillCaptureMethod;
__u8 bTriggerSupport;
__u8 bTriggerUsage;
__u8 bControlSize;
__u8 bmaControls[];
} __attribute__((__packed__));
#define UVC_DT_INPUT_HEADER_SIZE(n, p) (13+(n*p))
#define UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
uvc_input_header_descriptor_##n_##p
#define DECLARE_UVC_INPUT_HEADER_DESCRIPTOR(n, p) \
struct UVC_INPUT_HEADER_DESCRIPTOR(n, p) { \
__u8 bLength; \
__u8 bDescriptorType; \
__u8 bDescriptorSubType; \
__u8 bNumFormats; \
__u16 wTotalLength; \
__u8 bEndpointAddress; \
__u8 bmInfo; \
__u8 bTerminalLink; \
__u8 bStillCaptureMethod; \
__u8 bTriggerSupport; \
__u8 bTriggerUsage; \
__u8 bControlSize; \
__u8 bmaControls[p][n]; \
} __attribute__ ((packed))
/* 3.9.2.2. Output Header Descriptor */
struct uvc_output_header_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bNumFormats;
__u16 wTotalLength;
__u8 bEndpointAddress;
__u8 bTerminalLink;
__u8 bControlSize;
__u8 bmaControls[];
} __attribute__((__packed__));
#define UVC_DT_OUTPUT_HEADER_SIZE(n, p) (9+(n*p))
#define UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
uvc_output_header_descriptor_##n_##p
#define DECLARE_UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) \
struct UVC_OUTPUT_HEADER_DESCRIPTOR(n, p) { \
__u8 bLength; \
__u8 bDescriptorType; \
__u8 bDescriptorSubType; \
__u8 bNumFormats; \
__u16 wTotalLength; \
__u8 bEndpointAddress; \
__u8 bTerminalLink; \
__u8 bControlSize; \
__u8 bmaControls[p][n]; \
} __attribute__ ((packed))
/* 3.9.2.6. Color matching descriptor */
struct uvc_color_matching_descriptor {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bColorPrimaries;
__u8 bTransferCharacteristics;
__u8 bMatrixCoefficients;
} __attribute__((__packed__));
#define UVC_DT_COLOR_MATCHING_SIZE 6
/* 4.3.1.1. Video Probe and Commit Controls */
struct uvc_streaming_control {
__u16 bmHint;
__u8 bFormatIndex;
__u8 bFrameIndex;
__u32 dwFrameInterval;
__u16 wKeyFrameRate;
__u16 wPFrameRate;
__u16 wCompQuality;
__u16 wCompWindowSize;
__u16 wDelay;
__u32 dwMaxVideoFrameSize;
__u32 dwMaxPayloadTransferSize;
__u32 dwClockFrequency;
__u8 bmFramingInfo;
__u8 bPreferedVersion;
__u8 bMinVersion;
__u8 bMaxVersion;
} __attribute__((__packed__));
/* Uncompressed Payload - 3.1.1. Uncompressed Video Format Descriptor */
struct uvc_format_uncompressed {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bFormatIndex;
__u8 bNumFrameDescriptors;
__u8 guidFormat[16];
__u8 bBitsPerPixel;
__u8 bDefaultFrameIndex;
__u8 bAspectRatioX;
__u8 bAspectRatioY;
__u8 bmInterfaceFlags;
__u8 bCopyProtect;
} __attribute__((__packed__));
#define UVC_DT_FORMAT_UNCOMPRESSED_SIZE 27
/* Uncompressed Payload - 3.1.2. Uncompressed Video Frame Descriptor */
struct uvc_frame_uncompressed {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bFrameIndex;
__u8 bmCapabilities;
__u16 wWidth;
__u16 wHeight;
__u32 dwMinBitRate;
__u32 dwMaxBitRate;
__u32 dwMaxVideoFrameBufferSize;
__u32 dwDefaultFrameInterval;
__u8 bFrameIntervalType;
__u32 dwFrameInterval[];
} __attribute__((__packed__));
#define UVC_DT_FRAME_UNCOMPRESSED_SIZE(n) (26+4*(n))
#define UVC_FRAME_UNCOMPRESSED(n) \
uvc_frame_uncompressed_##n
#define DECLARE_UVC_FRAME_UNCOMPRESSED(n) \
struct UVC_FRAME_UNCOMPRESSED(n) { \
__u8 bLength; \
__u8 bDescriptorType; \
__u8 bDescriptorSubType; \
__u8 bFrameIndex; \
__u8 bmCapabilities; \
__u16 wWidth; \
__u16 wHeight; \
__u32 dwMinBitRate; \
__u32 dwMaxBitRate; \
__u32 dwMaxVideoFrameBufferSize; \
__u32 dwDefaultFrameInterval; \
__u8 bFrameIntervalType; \
__u32 dwFrameInterval[n]; \
} __attribute__ ((packed))
/* MJPEG Payload - 3.1.1. MJPEG Video Format Descriptor */
struct uvc_format_mjpeg {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bFormatIndex;
__u8 bNumFrameDescriptors;
__u8 bmFlags;
__u8 bDefaultFrameIndex;
__u8 bAspectRatioX;
__u8 bAspectRatioY;
__u8 bmInterfaceFlags;
__u8 bCopyProtect;
} __attribute__((__packed__));
#define UVC_DT_FORMAT_MJPEG_SIZE 11
/* MJPEG Payload - 3.1.2. MJPEG Video Frame Descriptor */
struct uvc_frame_mjpeg {
__u8 bLength;
__u8 bDescriptorType;
__u8 bDescriptorSubType;
__u8 bFrameIndex;
__u8 bmCapabilities;
__u16 wWidth;
__u16 wHeight;
__u32 dwMinBitRate;
__u32 dwMaxBitRate;
__u32 dwMaxVideoFrameBufferSize;
__u32 dwDefaultFrameInterval;
__u8 bFrameIntervalType;
__u32 dwFrameInterval[];
} __attribute__((__packed__));
#define UVC_DT_FRAME_MJPEG_SIZE(n) (26+4*(n))
#define UVC_FRAME_MJPEG(n) \
uvc_frame_mjpeg_##n
#define DECLARE_UVC_FRAME_MJPEG(n) \
struct UVC_FRAME_MJPEG(n) { \
__u8 bLength; \
__u8 bDescriptorType; \
__u8 bDescriptorSubType; \
__u8 bFrameIndex; \
__u8 bmCapabilities; \
__u16 wWidth; \
__u16 wHeight; \
__u32 dwMinBitRate; \
__u32 dwMaxBitRate; \
__u32 dwMaxVideoFrameBufferSize; \
__u32 dwDefaultFrameInterval; \
__u8 bFrameIntervalType; \
__u32 dwFrameInterval[n]; \
} __attribute__ ((packed))
#endif /* __LINUX_USB_VIDEO_H */
+903
View File
@@ -0,0 +1,903 @@
/*****************************************************************
>file name : uvc_dev.c
>author : lichao
>create time : Tue 13 Jun 2017 04:20:02 PM HKT
*****************************************************************/
#include "device/usb_stack.h"
/* #include "asm/dma.h" */
#include "uvc_device.h"
#include "usb_config.h"
#include "host_uvc.h"
#include "video_ioctl.h"
/* #include "video/video.h" */
#include "videobuf.h"
#include "generic/list.h"
#include "os/os_api.h"
#include "os/os_type.h"
#include "app_config.h"
#if TCFG_HOST_UVC_ENABLE
#define LOG_TAG_CONST USB
#define LOG_TAG "[UVC_HOST]"
#define LOG_ERROR_ENABLE
#define LOG_DEBUG_ENABLE
#define LOG_INFO_ENABLE
/* #define LOG_DUMP_ENABLE */
#define LOG_CLI_ENABLE
#include "debug.h"
#define UVC_CHANNEL_MAX 2
#define UVC_REC_JPG_HEAD_SIZE 8
#define UVC_REC_JPG_ALIGN 512
#define UVC_JPEG_HEAD 0xE0FFD8FF
#define UVC_JPEG_HEAD1 0xC0FFD8FF
#define USB_DMA_CP_ENABLE (0)//注意:使用硬件dma copy需要异步接收推送数据,否则出现速度快数据错乱的问题
#ifdef CONFIG_UI_ENABLE
#define UVC_RECV_BUFF_SHARE 0 //1:UVC接收数据不受应用层缓存影响,使用共享帧单独给UVC一直接收数据,使用uvc_host_jpg_callback_register注册进行数据获取,应用在屏显等
#else
#define UVC_RECV_BUFF_SHARE 0
#endif
#define UVC_RECV_BUFF_SHARE_SIZE (100*1024) //UVC一帧JPEG大小,建议100K
#define ADDR_ALIGNE(addr,align) ((addr + (align - 1)) / align * align)
static void (*uvc_host_jpg_cb)(char *jpg_buf, u32 jpg_len);
void uvc_host_jpg_callback_register(void (*cb)(char *jpg_buf, u32 jpg_len))
{
uvc_host_jpg_cb = cb;
}
static int uvc_jpeg_head_check(u32 head)
{
if (uvc_host_get_fmt()) {
return true;
}
if (head == UVC_JPEG_HEAD) {
return true;
} else if (head == UVC_JPEG_HEAD1) {
return true;
}
return 0;
}
struct uvc_dev_control {
OS_SEM sem;
struct list_head dev_list;
};
struct mjpg_uvc_image {
u8 *buf;
u32 size;
};
struct uvc_fh {
u8 id;
u8 eof;
u8 fps;
u8 real_fps;
u8 drop_frame;
u8 streamon;
volatile u8 streamoff;
u8 uvc_out;
u8 channel;
u8 alloc_channel;
u8 open[UVC_CHANNEL_MAX];
u8 streamon_ch[UVC_CHANNEL_MAX];
u32 frame_cnt;
u32 drop_frame_cnt;
struct list_head entry;
int free_size;
u8 *buf;
u8 *share_buf;
int b_offset;
/* dma_user_task_t dma_list[16]; */
u8 bfmode;
u8 uvc_video_q;
void *ppbuf;
struct videobuf_queue video_q;
struct video_device *video_dev[UVC_CHANNEL_MAX];
struct device device[UVC_CHANNEL_MAX];
void *private_data;
OS_SEM sem;
OS_SEM img_sem;
struct mjpg_uvc_image img;
volatile u8 image_req;
};
static struct uvc_dev_control uvc_dev;
#define __this (&uvc_dev)
#define list_for_each_uvc(fh) \
list_for_each_entry(fh, &__this->dev_list, entry)
#define list_add_uvc(fh) \
list_add(&fh->entry, &__this->dev_list)
#define list_del_uvc(fh) \
list_del(&fh->entry);
static int uvc_img_cap(void *_fh, u32 arg)
{
struct uvc_fh *fh = (struct uvc_fh *)_fh;
struct video_image_capture *icap = (struct video_image_capture *)arg;
u32 *head;
int err = 0;
if (!icap) {
return -EINVAL;
}
if (fh) {
fh->img.buf = icap->baddr;
fh->img.size = icap->size;
os_sem_create(&fh->img_sem, 0);
err = os_sem_pend(&fh->img_sem, 500);
if (err) {
log_error("image err");
}
fh->image_req = false;
head = (u32 *)(fh->img.buf + 8);
if (uvc_jpeg_head_check(*head)) {
fh->img.size -= 8;
memcpy(icap->baddr, icap->baddr + 8, fh->img.size);
}
os_sem_del(&fh->img_sem, OS_DEL_ALWAYS);
if (icap->size < fh->img.size) {
log_error("image capture size is too small !!!");
} else if (!err) {
log_info("image capture : %d.%dKB", fh->img.size / 1024, (fh->img.size % 1024) * 10 / 1024);
}
icap->size = fh->img.size;
return err;
} else {
log_error("image err in on open uvc");
}
return err;
}
void *uvc_buf_malloc(struct uvc_fh *fh, u32 size, u8 channel)//uvc视频流内存申请
{
void *b;
if (fh->uvc_video_q) {
struct videobuf_buffer *vb;
vb = videobuf_stream_alloc(&fh->video_q, size);
if (!vb) {
return NULL;
}
vb->len = size;
// printf("video_buf: %x\n", vb, vb->data);
return vb->data;
}
if (!channel) {
for (int i = 0; i < UVC_CHANNEL_MAX; i++) {
if (fh->open[i] && fh->streamon_ch[i]) {
channel = i + 1;
break;
}
}
if (!channel) {
return NULL;
}
}
fh->alloc_channel = channel;
if (!fh->open[channel - 1] || !fh->streamon_ch[channel - 1]) {
return NULL;
}
struct video_device *video_dev = (struct video_device *)fh->video_dev[fh->alloc_channel - 1];
if (!video_dev) {
return NULL;
}
b = video_buf_malloc(video_dev, size);
return b;
}
void *uvc_buf_realloc(struct uvc_fh *fh, void *buf, int size, u8 channel)//uvc视频流内存重新申请
{
if (fh->uvc_video_q) {
struct videobuf_buffer *b = container_of(buf, struct videobuf_buffer, data);
b->len = size;
videobuf_stream_realloc(&fh->video_q, b, size);
return b->data;
}
if (!channel || !fh->open[channel - 1] || !fh->streamon_ch[channel - 1]) {
return NULL;
}
struct video_device *video_dev = (struct video_device *)fh->video_dev[channel - 1];
return video_buf_realloc(video_dev, buf, size);
}
void uvc_buf_free(struct uvc_fh *fh, void *buf, u8 channel)//uvc视频流内存释放
{
if (fh->uvc_video_q) {
struct videobuf_buffer *b = container_of(buf, struct videobuf_buffer, data);
ASSERT(buf != NULL, "uvc_buf_free\n");
videobuf_stream_free(&fh->video_q, b);
return;
}
if (!channel || !fh->open[channel - 1] || !fh->streamon_ch[channel - 1]) {
return;
}
struct video_device *video_dev = (struct video_device *)fh->video_dev[channel - 1];
if (!video_dev) {
return ;
}
return video_buf_free(video_dev, buf);
}
u32 uvc_buf_free_space(struct uvc_fh *fh, u8 channel)//uvc视频流内存剩余空间
{
if (fh->uvc_video_q) {
return videobuf_stream_free_space(&fh->video_q);
}
if (!channel) {
find_open:
for (int i = 0; i < UVC_CHANNEL_MAX; i++) {
if (fh->open[i] && fh->streamon_ch[i]) {
channel = i + 1;
break;
}
}
if (!channel) {
return 0;
}
fh->alloc_channel = channel;
}
if (!fh->open[channel - 1] || !fh->streamon_ch[channel - 1]) {
return 0;
}
struct video_device *video_dev = (struct video_device *)fh->video_dev[channel - 1];
if (!video_dev) {
channel = 0;
goto find_open;
}
return video_buf_free_space(video_dev);
}
void uvc_buf_stream_finish(struct uvc_fh *fh, void *buf, u8 channel)//uvc视频流推流
{
if (fh->uvc_video_q) {
struct videobuf_buffer *b = container_of(buf, struct videobuf_buffer, data);
videobuf_stream_finish(&fh->video_q, b);
return;
}
if (!channel || !buf || !fh->open[channel - 1] || !fh->streamon_ch[channel - 1]) {
return;
}
struct video_device *video_dev = (struct video_device *)fh->video_dev[channel - 1];
if (!video_dev) {
return;
}
u32 size;
if (os_sem_valid(&fh->img_sem) && fh->image_req) {//有拍照申请则复制数据到拍照缓存
size = video_buf_size(buf);
size = MIN(size, fh->img.size);
memcpy(fh->img.buf, buf, size);
fh->img.size = size;
os_sem_post(&fh->img_sem);
fh->image_req = false;
}
video_buf_stream_finish(video_dev, buf);//lbuf推流
}
static int uvc_dev_reqbufs(void *_fh, struct uvc_reqbufs *b)
{
struct uvc_fh *fh = (struct uvc_fh *)_fh;
struct video_reqbufs vb_req = {0};
vb_req.buf = b->buf;
vb_req.size = b->size;
videobuf_queue_init(&fh->video_q, 32, "uvc_dev");
fh->uvc_video_q = 1;
return videobuf_reqbufs(&fh->video_q, (struct video_reqbufs *)&vb_req);
/* return 0; */
}
static int uvc_dev_qbuf(void *_fh, struct video_buffer *b)
{
struct uvc_fh *fh = (struct uvc_fh *)_fh;
return videobuf_qbuf(&fh->video_q, b);
/* return 0; */
}
static int uvc_dev_dqbuf(void *_fh, struct video_buffer *b)
{
struct uvc_fh *fh = (struct uvc_fh *)_fh;
if (fh->uvc_out) {
return -ENODEV;
}
if (!fh->streamon) {
return -ENODEV;
}
return videobuf_dqbuf(&fh->video_q, b);
/* return 0; */
}
int uvc_mjpg_stream_out(void *fd, int cnt, void *stream_list, int state)
{
struct uvc_fh *fh = (struct uvc_fh *)fd;
struct uvc_stream_list *list = (struct uvc_stream_list *)stream_list;
int i;
int err = 0;
u32 tmp_jiffies = 0, req_size;
if ((cnt < 0) || !list) {
/*putchar('E');*/
if (fh->buf) {
if (fh->buf != fh->share_buf) {//没有多通道共享内存才释放
uvc_buf_free(fh, fh->buf, fh->alloc_channel);
}
fh->buf = NULL;
if (state != STREAM_SOF) { // eof == 2 next frame start
fh->drop_frame = 1;
}
err = -EINVAL;
} else if (state == STREAM_SOF) {
fh->drop_frame = 0;
}
goto _exit;
}
if (fh->drop_frame) {
if (state == STREAM_EOF) {
fh->drop_frame = 0;
}
goto _exit;
}
if (!fh->buf) {
if (fh->share_buf) {//有共享内存则使用共享内存大小(一般打开两个通道或者开启UI)
fh->buf = fh->share_buf;
fh->free_size = uvc_host_get_fmt() ? UVC_RECV_BUFF_SHARE_SIZE : UVC_RECV_BUFF_SHARE_SIZE - UVC_REC_JPG_ALIGN;
fh->alloc_channel = 0;
} else {//没有使用共享内存,则请求剩余空间足够再申请内存
fh->free_size = uvc_buf_free_space(fh, fh->alloc_channel);
if (fh->free_size > 1024) {
fh->buf = uvc_buf_malloc(fh, fh->free_size, fh->alloc_channel);
if (!uvc_host_get_fmt()) {
fh->free_size -= UVC_REC_JPG_ALIGN;//减512防止realloc时512对齐断言
}
}
}
if (!fh->buf) {
err = -ENOMEM;
goto _exit;
}
fh->b_offset = 0;
}
for (i = 0; i < cnt; i++) {
if ((fh->b_offset + list[i].length + UVC_REC_JPG_HEAD_SIZE) > fh->free_size) {//数据超过当前可用的内存空间则释放当前帧
if (fh->buf != fh->share_buf) {
uvc_buf_free(fh, fh->buf, fh->alloc_channel);
}
fh->buf = NULL;
fh->drop_frame = 1;
putchar('d');
err = -EFAULT;
goto _exit;
}
//复制数据到buf缓存
#if USB_DMA_CP_ENABLE
fh->dma_list[i].src_addr = list[i].addr;
fh->dma_list[i].dst_addr = fh->buf + UVC_REC_JPG_HEAD_SIZE + fh->b_offset;
fh->dma_list[i].len = list[i].length;
#else
memcpy(fh->buf + UVC_REC_JPG_HEAD_SIZE + fh->b_offset, list[i].addr, list[i].length);
#endif
fh->b_offset += list[i].length;
}
#if USB_DMA_CP_ENABLE
dma_task_list_copy(fh->dma_list, cnt);//注意:使用硬件dma copy需要异步接收推送数据,否则出现速度快数据错乱的问题
#endif
if (state == STREAM_EOF) {//USB结束帧则表明一帧图像数据接收完成
fh->frame_cnt++;
#ifdef CONFIG_UVC_DROP_FRAME_ENABLE
if (fh->real_fps && fh->fps && fh->real_fps < fh->fps) {//检测USB的帧率和当前应用层请求的帧率是否一直是否需要丢帧处理
u32 drop = fh->frame_cnt * (fh->fps - fh->real_fps) / fh->fps;
if (fh->drop_frame_cnt != drop) {//不一致需要丢帧处理
fh->drop_frame_cnt = drop;
if (fh->buf != fh->share_buf) {//丢帧
uvc_buf_free(fh, fh->buf, fh->alloc_channel);
}
fh->buf = NULL;
goto _exit;
}
}
#endif
if (uvc_host_get_fmt()) {
req_size = fh->b_offset + UVC_REC_JPG_HEAD_SIZE;
} else {
req_size = ADDR_ALIGNE(fh->b_offset + UVC_REC_JPG_HEAD_SIZE, UVC_REC_JPG_ALIGN);//JPEG图像数据需要512对齐
}
if (uvc_host_jpg_cb) {//有注册回调则先进入回调函数
uvc_host_jpg_cb((char *)fh->buf + UVC_REC_JPG_HEAD_SIZE, fh->b_offset);
}
if (fh->buf == fh->share_buf && fh->share_buf) {//共享数据,则为多通道
for (int ch = 1; ch <= UVC_CHANNEL_MAX; ch++) {//多个通道检测
if (uvc_buf_free_space(fh, ch) > 1024) {//检测剩余空间足够用再申请复制数据
u8 *pbuf = uvc_buf_malloc(fh, req_size, ch);
if (pbuf) {
memcpy(pbuf + UVC_REC_JPG_HEAD_SIZE, fh->buf + UVC_REC_JPG_HEAD_SIZE, fh->b_offset);
fh->buf = pbuf;
if (fh->buf) {
uvc_buf_stream_finish(fh, fh->buf, ch);//推流往应用层
}
}
}
}
} else {//单通道
fh->buf = uvc_buf_realloc(fh, fh->buf, req_size, fh->alloc_channel);//重新申请内存,会释放多余的空间
if (fh->buf) {
uvc_buf_stream_finish(fh, fh->buf, fh->alloc_channel);//推流往应用层
}
}
fh->buf = NULL;
}
_exit:
fh->streamoff = 0;
return err;
}
int uvc_h264_stream_out(void *fd, int cnt, void *stream_list, int state)
{
struct uvc_fh *fh = (struct uvc_fh *)fd;
struct uvc_stream_list *list = (struct uvc_stream_list *)stream_list;
int i;
int err = 0;
u32 tmp_jiffies = 0;
if ((cnt < 0) || !list) {
/* putchar('E'); */
if (fh->buf) {
if (fh->buf != fh->share_buf) {//没有多通道共享内存才释放
uvc_buf_free(fh, fh->buf, 0);
}
fh->buf = NULL;
if (state != STREAM_SOF) { // eof == 2 next frame start
fh->drop_frame = 1;
}
err = -EINVAL;
} else if (state == STREAM_SOF) {
fh->drop_frame = 0;
}
goto _exit;
}
if (fh->drop_frame) {
/* puts("drop\n"); */
if (state == STREAM_EOF) {
fh->drop_frame = 0;
}
goto _exit;
}
if (!fh->buf) {
fh->free_size = uvc_buf_free_space(fh, 0);
if (fh->free_size > 1024) {
fh->buf = uvc_buf_malloc(fh, fh->free_size, 0);
}
if (!fh->buf) {
/* puts("no mem\n"); */
err = -ENOMEM;
goto _exit;
}
fh->b_offset = 0;
}
for (i = 0; i < cnt; i++) {
if ((fh->b_offset + list[i].length) > fh->free_size) {
uvc_buf_free(fh, fh->buf, 0);
fh->buf = NULL;
fh->drop_frame = 1;
putchar('d');
/* printf("%d", fh->id); */
err = -EFAULT;
goto _exit;
}
#if USB_DMA_CP_ENABLE
fh->dma_list[i].src_addr = list[i].addr;
fh->dma_list[i].dst_addr = fh->buf + fh->b_offset;
fh->dma_list[i].len = list[i].length;
#else
memcpy(fh->buf + fh->b_offset, list[i].addr, list[i].length);
#endif
fh->b_offset += list[i].length;
}
#if USB_DMA_CP_ENABLE
dma_task_list_copy(fh->dma_list, cnt);
#endif
if (state == STREAM_EOF) {
/* puts("h264\n"); */
fh->buf = uvc_buf_realloc(fh, fh->buf, fh->b_offset, 0);
uvc_buf_stream_finish(fh, fh->buf, 0);
fh->buf = NULL;
}
_exit:
fh->streamoff = 0;
return err;
}
static int uvc_stream_on(void *device, void *_fh, int index)
{
int err = 0;
u8 channel = 0;
struct uvc_fh *fh = (struct uvc_fh *)_fh;
os_sem_pend(&fh->sem, 0);
for (int i = 0; i < UVC_CHANNEL_MAX; i++) {
if ((u32)(&fh->device[i]) == (u32)device) {
channel = i + 1;
break;
}
}
ASSERT(channel, "err int uvc_stream_on\n");
if (fh->uvc_out) {
os_sem_post(&fh->sem);
return -EINVAL;
}
fh->eof = 1;
fh->drop_frame = 0;
if (fh->streamon) {
fh->streamon++;
fh->streamon_ch[channel - 1]++;
os_sem_post(&fh->sem);
return 0;
}
err = uvc_host_open_camera(fh->private_data);//打开USB,并配置UVC的视频流
if (err) {
log_error("uvc_stream_on err");
os_sem_post(&fh->sem);
return err;
}
fh->streamon++;
fh->streamon_ch[channel - 1]++;
if (fh->uvc_video_q) {
videobuf_streamon(&fh->video_q, (u8 *)&channel);
}
os_sem_post(&fh->sem);
return err;
}
static int uvc_set_real_fps(void *_fh, u8 fp)
{
struct uvc_fh *fh = (struct uvc_fh *)_fh;
fh->real_fps = fp;
return 0;
}
static int uvc_stream_off(void *device, void *_fh, int index)
{
int err = 0;
struct uvc_fh *fh = (struct uvc_fh *)_fh;
u32 time = jiffies + msecs_to_jiffies(10);
u8 channel = 0;
os_sem_pend(&fh->sem, 0);
for (int i = 0; i < UVC_CHANNEL_MAX; i++) {
if ((u32)(&fh->device[i]) == (u32)device) {
channel = i + 1;
break;
}
}
ASSERT(channel, "err int uvc_stream_off\n");
fh->streamon_ch[channel - 1]--;
if (fh->streamon && --fh->streamon) {
os_sem_post(&fh->sem);
return 0;
}
if (!fh->uvc_out) {
uvc_host_close_camera(fh->private_data);//关闭UVC视频流
}
fh->streamoff = 1;
//cppcheck-suppress knownConditionTrueFalse
while (fh->streamoff) {
if (time_after(jiffies, time)) {
break;
}
}
if (fh->buf) {
if (fh->buf != fh->share_buf) {
uvc_buf_free(fh, fh->buf, fh->alloc_channel);
}
fh->buf = NULL;
fh->b_offset = 0;
}
if (fh->uvc_video_q) {
err = videobuf_streamoff(&fh->video_q, 0);
}
os_sem_post(&fh->sem);
return err;
}
static int uvc_dev_init(const struct dev_node *node, void *_data)
{
//struct uvc_platform_data *data = (struct uvc_platform_data *)_data;
os_sem_create(&__this->sem, 1);
INIT_LIST_HEAD(&__this->dev_list);
return 0;
}
static bool uvc_dev_online(const struct dev_node *node)
{
int id;
id = uvc_host_online();
log_debug("[msg]>>>>>>>>>>>id=%d", id);
if (id < 0) {
return false;
}
return true;
}
static int uvc_dev_out(void *fd)
{
struct uvc_fh *fh = (struct uvc_fh *)fd;
os_sem_pend(&fh->sem, 0);
fh->uvc_out = 1;
os_sem_post(&fh->sem);
return 0;
}
static int uvc_dev_open(const char *_name, struct device **device, void *arg)
{
struct uvc_fh *fh = NULL;
struct uvc_host_param param = {0};
char name[8];
int id, i;
u8 channel = 0;
struct video_var_param_info *info = (struct video_var_param_info *)arg;
id = info->f->uvc_id;
list_for_each_uvc(fh) {
if (fh->id == id) {//已经被打开过则使用另外通道
for (i = 0; i < UVC_CHANNEL_MAX; i++) {
if (!fh->open[i]) {
channel = i;
break;
}
}
if (i >= UVC_CHANNEL_MAX) {
log_error("uvc no channel");
os_sem_post(&__this->sem);
return -EINVAL;
}
*device = &fh->device[channel];
(*device)->private_data = fh;
fh->video_dev[channel] = (struct video_device *)info->priv;
fh->open[channel] = 1;
fh->channel++;
os_sem_post(&__this->sem);
return 0;
}
}
fh = (struct uvc_fh *)zalloc(sizeof(*fh));
if (!fh) {
os_sem_post(&__this->sem);
return -ENOMEM;
}
sprintf(name, "uvc%d", id);
param.name = name;//node->name;
if (info->f->pixelformat & VIDEO_PIX_FMT_H264) {
param.uvc_stream_out = uvc_h264_stream_out;
} else {
param.uvc_stream_out = uvc_mjpg_stream_out;
}
param.uvc_out = uvc_dev_out;
param.priv = fh;
log_info("open uvc name = %s", name);
fh->private_data = uvc_host_open(&param);//初始化UVC主机
if (!fh->private_data) {
free(fh);
os_sem_post(&__this->sem);
return -EINVAL;
}
if (info->priv) {
fh->video_dev[channel] = (struct video_device *)info->priv;
}
#if UVC_RECV_BUFF_SHARE
if (!fh->share_buf) {
fh->share_buf = malloc(UVC_RECV_BUFF_SHARE_SIZE);
if (!fh->share_buf) {
log_error("uvc share_buf no men");
free(fh);
os_sem_post(&__this->sem);
return -ENOMEM;
}
}
#endif
os_sem_create(&fh->sem, 0);
list_add_uvc(fh);//打开后添加到链表,在多通道打开则需要查找链表
os_sem_post(&fh->sem);
*device = &fh->device[channel];
(*device)->private_data = fh;
fh->id = id;
fh->open[channel] = 1;
fh->channel++;
os_sem_post(&__this->sem);
return 0;
}
static int uvc_querycap(struct uvc_fh *fh, struct uvc_capability *cap)//获取分辨率
{
int num;
struct uvc_frame_info *reso_table;
os_sem_pend(&fh->sem, 0);
num = uvc_host_get_pix_table(fh->private_data, &reso_table);
if (num > (sizeof(cap->reso) / sizeof(cap->reso[0]))) {
num = sizeof(cap->reso) / sizeof(cap->reso[0]);
}
memcpy(cap->reso, reso_table, sizeof(cap->reso[0]) * num);
cap->fmt = UVC_CAMERA_FMT_MJPG;
cap->reso_num = num;
cap->fps = uvc_host_get_fps(fh->private_data);
fh->fps = cap->fps;
//printf("defualt : uvc_querycap fps = %d, %d*%d\n", cap->fps, cap->reso[cap->reso_num - 1].width, cap->reso[cap->reso_num - 1].height);
os_sem_post(&fh->sem);
return 0;
}
static int uvc_req_processing_unit(struct uvc_fh *fh, struct uvc_processing_unit *pu)
{
int err = 0;
os_sem_pend(&fh->sem, 0);
if (!fh->uvc_out) {
err = uvc_host_req_processing_unit(fh->private_data, pu);
}
os_sem_post(&fh->sem);
return err;
}
static int uvc_dev_reset(struct uvc_fh *fh)
{
int err = 0;
os_sem_pend(&fh->sem, 0);
if (!fh->uvc_out) {
err = uvc_force_reset(fh->private_data);
}
os_sem_post(&fh->sem);
return err;
}
static int usb_ioctl(struct uvc_fh *fh, u32 cmd, void *arg)
{
int err = 0;
if (!fh) {
return -EINVAL;
}
os_sem_pend(&fh->sem, 0);
if (!fh->uvc_out) {
err = uvc2usb_ioctl(fh->private_data, cmd, arg);
}
os_sem_post(&fh->sem);
return err;
}
static int uvc_dev_ioctl(struct device *device, u32 cmd, u32 arg)
{
int ret = 0;
struct uvc_fh *fh = (struct uvc_fh *)device->private_data;
switch (cmd) {
case UVCIOC_QUERYCAP:
ret = uvc_querycap(fh, (struct uvc_capability *)arg);
break;
case UVCIOC_SET_CAP_SIZE:
ret = uvc_host_set_pix(fh->private_data, (int)arg);
break;
case UVCIOC_REQBUFS:
ret = uvc_dev_reqbufs(fh, (struct uvc_reqbufs *)arg);
break;
case UVCIOC_DQBUF:
ret = uvc_dev_dqbuf(fh, (struct video_buffer *)arg);
break;
case UVCIOC_QBUF:
ret = uvc_dev_qbuf(fh, (struct video_buffer *)arg);
break;
case UVCIOC_STREAM_ON:
ret = uvc_stream_on(device, fh, arg);
break;
case UVCIOC_STREAM_OFF:
ret = uvc_stream_off(device, fh, arg);
break;
case UVCIOC_GET_IMAMGE:
ret = uvc_img_cap(fh, arg);
break;
case UVCIOC_RESET:
ret = uvc_dev_reset(fh);
break;
case UVCIOC_REQ_PROCESSING_UNIT:
ret = uvc_req_processing_unit(fh, (struct uvc_processing_unit *)arg);
break;
case UVCIOC_SET_CUR_GRAY:
/*set_uvc_gray(arg);*/
break;
case UVCIOC_SET_CUR_FPS:
uvc_set_real_fps(fh, (u8)arg);
break;
default:
ret = usb_ioctl(fh, cmd, (void *)arg);
break;
}
return ret;
}
static int uvc_dev_close(struct device *device)
{
struct uvc_fh *fh = (struct uvc_fh *)device->private_data;
if (fh) {
if (fh->channel) {
fh->channel--;
}
}
if (fh && fh->channel == 0) {//通道都关闭了
os_sem_pend(&fh->sem, 0);
uvc_host_close(fh->private_data);
for (int i = 0; i < UVC_CHANNEL_MAX; i++) {//多通道关闭
if (&fh->device[i] == device) {//关闭是当前通道
fh->open[i] = 0;
fh->video_dev[i] = NULL;
memset(&fh->device[i], 0, sizeof(struct device));
}
}
if (fh->uvc_video_q) {
videobuf_queue_release(&fh->video_q);
}
list_del_uvc(fh);
if (fh->share_buf) {
free(fh->share_buf);
fh->share_buf = NULL;
}
os_sem_post(&fh->sem);
free(fh);
}
return 0;
}
const struct device_operations uvc_dev_ops = {
.init = uvc_dev_init,
.open = uvc_dev_open,
.ioctl = uvc_dev_ioctl,
.close = uvc_dev_close,
.online = uvc_dev_online,
};
#endif
@@ -0,0 +1,459 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "system/includes.h"
/* #include "server/usb_server.h" */
#include "app_config.h"
/* #include "action.h" */
/* #include "storage_device.h" */
/* #include "user_isp_cfg.h" */
/* #include "server/video_server.h" */
#include "uvc_device.h"
#include "usb_config.h"
#include "host_uvc.h"
#include "video_ioctl.h"
#include "video.h"
#include "videobuf.h"
#include "sdk_config.h"
#include "debug.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
#define TIME_UVC_DEBUG 1//uvc时间debug
#define USER_UVC_DEBUG 0//用于debug uvc一帧数据是否有问题的debug。主要是加上crc和写SD卡做校验
#define LOG_SEM_ENABLE 0// 信号量debug
#if LOG_SEM_ENABLE
#define sem_putchar(x) putchar(x)
#define sem_printf printf
#define sem_put_buf(x,len) put_buf(x,len)
#else
#define sem_putchar(...)
#define sem_printf(...)
#define sem_put_buf(...)
#endif // LOG_SEM_ENABLE
#define JLUVC_JPEG_SIZE_SET_ENABLE 0 //是否限制jpeg大小
#define UVC_JPEG_BUF_SIZE (30 * 1024) //限制jpeg 大小为30KB,(need enable)
extern void jpeg_dec_flush(void);
u8 *jluvc_jpeg_buf = NULL;
int jluvc_jpeg_buf_len = 0;
static u8 jluvc_start = 0;
static OS_SEM jluvc_sem;
struct uvc_cam_jpeg_t {
volatile u8 streamon;
u16 cur_width;
u16 cur_height;
void (*ui_refresh_cb)(void);
};
struct uvc_cam_jpeg_t _uvc_cam_jpeg = {0};
#define __this (&_uvc_cam_jpeg)
static int find_reso(u16 ref_width, u16 ref_height, struct uvc_capability *uvc_cap)
{
u8 find_width = 0;
u8 find_height = 0;
int w_index = 0;
int h_index = 0;
int i;
while (h_index < uvc_cap->reso_num) {
for (i = w_index; i < uvc_cap->reso_num; i++) {
if (ref_width == uvc_cap->reso[i].width) {
find_width = 1;
w_index = i;
}
}
for (i = h_index; i < uvc_cap->reso_num; i++) {
if (ref_height == uvc_cap->reso[i].height) {
find_height = 1;
h_index = i;
break;
}
}
if (find_width && find_height) {
if (uvc_cap->reso[h_index].width == ref_width) {
return h_index;
} else if (uvc_cap->reso[w_index].height == ref_height) {
return w_index;
} else {
w_index++;
h_index++;
continue;
}
} else if (find_height) {
return h_index;
} else if (find_width) {
return w_index;
} else {
return 0;
}
}
return 0;
}
/**
* @brief JLUVC运行状态
*
* JLUVC的运行状态01
*
* @param status
*/
void jlset_uvc_status(u8 status)
{
log_debug("set_uvc_status: %d\n", status);
jluvc_start = status;
}
/**
* @brief JLUVC运行状态
*
* JLUVC当前的运行状态01
*
* @return u8 JLUVC当前的运行状态
*/
u8 jlget_uvc_status(void)
{
return jluvc_start;
}
/**
* @brief JLUVC信号量
*
* JLUVC使用的信号量资源
*/
void jluvc_sem_create(void)
{
sem_printf("-----%s>>\n", __func__);
os_sem_create(&jluvc_sem, 0);
}
/**
* @brief JLUVC信号量
*
* 线JLUVC信号量的计数大于0
* 0线
*/
void jluvc_sem_pend(void)
{
sem_printf("-----%s>\n", __func__);
os_sem_pend(&jluvc_sem, 0);
}
/**
* @brief JLUVC信号量
*
* 线
*/
void jluvc_sem_post(void)
{
sem_printf("-----%s>>\n", __func__);
os_sem_post(&jluvc_sem);
}
/**
* @brief JLUVC信号量
*
* JLUVC使用的信号量资源
*/
void jluvc_sem_del(void)
{
sem_printf("-----%s>>\n", __func__);
os_sem_del(&jluvc_sem, 0);
}
/**
* @brief JLUVC缓冲区
*
* JLUVC操作
*
* @param size ()
* @return NULL
*/
void *jluvc_buf_init(u16 size)
{
log_debug("-----%s>>\n", __func__);
void *ptr = NULL;
if (ptr == NULL) {
ptr = malloc(size);
}
return ptr;
}
/**
* @brief JLUVC缓冲区
*
* JPEG缓冲区内存NULL
*/
void jluvc_buf_deinit(void)
{
log_debug("-----%s>>\n", __func__);
if (jluvc_jpeg_buf) {
free(jluvc_jpeg_buf);
jluvc_jpeg_buf = NULL;
}
}
/**
* @brief JLUVC界面显示
*
* UI任务发送刷新消息UVC JPEG测试界面的刷新操作
* "ui"Q_CALLBACK类型消息来实现界面更新
*
* @note UI组件
*/
static void jluvc_ui_reflush(void)
{
if (__this && __this->ui_refresh_cb) {
__this->ui_refresh_cb();
}
}
int jluvc_set_refresh_cb(void (*cb)(void))
{
if (!__this) {
log_error("%s not find\n", __func__);
return -1;
}
__this->ui_refresh_cb = cb;
return 0;
}
/**
* @brief UVC JPEG接收任务处理函数
* UVC设备JPEG格式的视频流数据
* JPEG数据接收和处理等
* @param arg 使
* @return
* @note 退
*/
static void uvc_jpeg_recv_task(void *arg)
{
void *fd = NULL;
struct uvc_reqbufs breq = {0};
struct video_buffer b = {0};
b.timeout = 50;
b.noblock = 0;
struct uvc_capability uvc_cap;
int err = -1;
int msg[32];
u32 i = 0;
if (dev_online("uvc")) {
const struct video_platform_data *video_data = NULL;
struct uvc_platform_data *uvc_info = NULL;
struct video_var_param_info info;
struct video_format video_f;
char video_name[6] = {0};
sprintf(video_name, "video%d", 0);
extern void *device_platform_data_get(const char *name);
video_data = device_platform_data_get(video_name);
if (video_data && video_data->data) {
for (int i = 0; i < video_data->num; i++) {
if (video_data->data[i].tag == VIDEO_TAG_UVC) {
uvc_info = video_data->data[i].data;
break;
}
}
}
video_f.uvc_id = 0;
info.f = &video_f;
fd = dev_open("uvc", (void *)&info); //指定uvc设备0
if (fd) {
dev_ioctl(fd, UVCIOC_QUERYCAP, (unsigned int)&uvc_cap);
for (int i = 0; i < uvc_cap.reso_num; i++) {
log_debug("uvc support [%d] %d x %d", i, uvc_cap.reso[i].width, uvc_cap.reso[i].height);
}
u8 fmt = uvc_cap.fmt;
int reso_index = find_reso(uvc_info->width, uvc_info->height, &uvc_cap);
u16 width = uvc_cap.reso[reso_index].width;
u16 height = uvc_cap.reso[reso_index].height;
log_debug("fmt :%d reso : %d, ref size : %d x %d, size : %d x %d.\n", fmt, reso_index, uvc_info->width, uvc_info->height, width, height);
dev_ioctl(fd, UVCIOC_SET_CAP_SIZE, (unsigned int)(reso_index + 1));
breq.buf = NULL;
/* breq.size = UVC_JPEG_BUF_SIZE; */
breq.size = uvc_info->mem_size;;
/* breq.size = 300*1024;; */
err = dev_ioctl(fd, UVCIOC_REQBUFS, (unsigned int)&breq);
if (!err) {
dev_ioctl(fd, UVCIOC_STREAM_ON, 0);
} else {
err = -1;
puts("uvc0 video open err1--------------------\n");
}
}
}
jluvc_sem_create();//create sem
u8 usr_wdt_cnt = 0;//定时喂狗
while (1) {
os_taskq_accept(ARRAY_SIZE(msg), msg);
/* os_taskq_pend(NULL, msg, ARRAY_SIZE(msg)); */
if (msg[0] == Q_MSG) {
if (msg[1] == 0xaa) {
if (os_task_del_req(OS_TASK_SELF) == OS_TASK_DEL_REQ) {
//准备退出线程
if (fd) {
dev_ioctl(fd, UVCIOC_STREAM_OFF, 0);
dev_close(fd);
}
os_task_del_res(OS_TASK_SELF);
}
}
}
if (usr_wdt_cnt++ >= 20) {
usr_wdt_cnt = 0;
wdt_clear();
}
//从uvc 缓存中请求一帧图像
if (fd) {
err = dev_ioctl(fd, UVCIOC_DQBUF, (unsigned int)&b);
}
if (err || b.len <= 0) { //请求失败
os_time_dly(1);
continue;
}
//请求成功
//TODO
putchar('R');
log_debug("[msg]>>>>>>>>>>>b.len=%d", b.len);
#if TIME_UVC_DEBUG
static u32 last_time = 0;
static u32 curr_time = 0;
curr_time = jiffies_msec();
printf("[UVC]T = %d ms\n", curr_time - last_time);
#endif
//copy current stream to ui
#if JLUVC_JPEG_SIZE_SET_ENABLE
if (b.len > UVC_JPEG_BUF_SIZE) {
continue;
}
/* if (!jluvc_jpeg_buf && (b.len <= UVC_JPEG_BUF_SIZE)) { //具体要不要限制jpeg的buff大小在这里限制 */
/* jluvc_jpeg_buf = jluvc_buf_init(b.len); */
/* } */
#else
/* if (!jluvc_jpeg_buf) { */
/* jluvc_jpeg_buf = jluvc_buf_init(b.len); */
/* } */
#endif //endif JLUVC_JPEG_SIZE_SET_ENABLE
/* if (jluvc_jpeg_buf [> && (b.len < UVC_JPEG_BUF_SIZE)<]) { //UI刷新数据 */
if (1 /* && (b.len < UVC_JPEG_BUF_SIZE)*/) { //UI刷新数据
jlset_uvc_status(1);
#if USER_UVC_DEBUG
extern u16 CRC16(const void *ptr, u32 len);
void *pp = (void *)b.baddr;
int len = b.len;
FILE *fp;
s8 path[64] = {0};
u16 wr_crc = CRC16((u8 *)pp, len);
u16 rd_crc = 0;
sprintf(path, "storage/sd0/C/a%d.jpg", i);
fp = fopen(path, "wb+");
if (fp) {
printf("@@@path=%s\n", path);
fwrite(pp, len, 1, fp);
i++;
fclose(fp);
}
/* free(pp); */
void *rp = fopen(path, "rb");
if (rp) {
printf("@@@path=%s\n", path);
void *rd_buf = malloc(len);
fread(rd_buf, len, 1, rp);
rd_crc = CRC16((u8 *)rd_buf, len);
fclose(rp);
free(rd_buf);
rd_buf = NULL;
}
printf("wr_crc=%d, rd_crc=%d\n", wr_crc, rd_crc);
#endif//endif
/* memset(jluvc_jpeg_buf, 0, b.len); */
/* memcpy(jluvc_jpeg_buf, (u8 *)b.baddr, b.len); */
/* jluvc_jpeg_buf_len = b.len; */
#if TCFG_UI_ENABLE
int jljpeg_stream_src_data_copy(u8 * buf, int size);
if (!jljpeg_stream_src_data_copy((u8 *)b.baddr, b.len)) {
jluvc_ui_reflush();
}
#endif
/* jluvc_sem_post(); */
}
#if TIME_UVC_DEBUG
last_time = curr_time;
#endif
// put_buf((u8 *)b.baddr+ b.len -512 ,512);
/* if (f) { */
/* fwrite(f, b.baddr, b.len); */
/* } */
#if UVC_JPG_DATA_WRITE2SD
/// fwrite 一帧数据到SD卡中。
void *pp = b.baddr;
int len = b.len;
FILE *fp;
u8 path[64] = {0};
sprintf(path, "storage/sd0/C/avid_%d.jpg", i);
fp = fopen(path, "wb+");
if (fp) {
printf("@@@path=%s\n", path);
fwrite(pp, len, 1, fp);
i++;
fclose(fp);
}
free(pp);
#endif //endif UVC_JPG_DATA_WRITE2SD
dev_ioctl(fd, UVCIOC_QBUF, (unsigned int)&b);
}
}
int video_uvc_jpeg_stream_open(u16 width, u16 height)
{
log_debug("video_uvc_jpeg_stream_open\n");
if (__this->streamon) {
return -1;
}
memset(__this, 0x00, sizeof(struct uvc_cam_jpeg_t));
__this->cur_width = width;
__this->cur_height = height;
__this->streamon = 1;
return os_task_create(uvc_jpeg_recv_task, NULL, 20, 1024, 32, "uvc_jpeg_recv");
}
int video_uvc_jpeg_stream_close()
{
while (OS_TASK_NOT_EXIST != os_task_del_req((const char *)"uvc_jpeg_recv")) {
os_taskq_post_msg((const char *)"uvc_jpeg_recv", 1, 0xaa);
os_time_dly(1);
}
jluvc_sem_del();
jluvc_buf_deinit();
__this->streamon = 0;
return 0;
}
+648
View File
@@ -0,0 +1,648 @@
#ifndef DEVICE_VIDEO_H
#define DEVICE_VIDEO_H
#include "video_ioctl.h"
#include "device/device.h"
#define VIDEO_DEFAULT_BUF_MODE 0x0
#define VIDEO_PPBUF_MODE 0x1
#define VIDEO_TAG_UVC VIDEO_TAG('u', 'v', 'c', ' ')
#define VIDEO_TAG(a,b,c,d) (((a) << 24) | ((b) << 16) | ((c) << 8) | (d))
struct videobuf_queue {
u8 ref;
u8 streaming;
u16 align;
const char *name;
OS_SEM sem;
void *buf;
struct lbuff_head *lbuf;
void *private_data;
};
enum {
VIDREQ_GET_OVERLAY_BUFFER,
VIDREQ_PUT_OVERLAY_BUFFER,
VIDREQ_FREE_OVERLAY_BUFFER,
VIDREQ_GET_CAPTURE_BUFFER,
VIDREQ_SET_CAPTURE_BUFFER,
VIDREQ_PUT_CAPTURE_BUFFER,
VIDREQ_FREE_CAPTURE_BUFFER,
VIDREQ_GET_IMAGE_CAPTURE_BUFFER,
VIDREQ_PUT_IMAGE_CAPTURE_BUFFER,
VIDREQ_IMAGE_CAPTURE_COMPLETED,
VIDREQ_IMAGE_ZOOM, // 10
/*VIDREQ_IMAGE_DISP_ZOOM,*/
VIDREQ_IMAGE_ENC_START,
/*VIDREQ_GET_DISP_CAPABILITY,*/
VIDREQ_GET_ENCODER_CHANNEL,
/*VIDREQ_PUT_IMAGE_TO_BUFFER, // 15*/
/*VIDREQ_RESET_DISP_IMAGE,*/
VIDREQ_RESET_CBUFFER,
/*VIDREQ_PUT_DEC_DATA,*/
VIDREQ_GET_DEC_DATA,
VIDREQ_RESET_DOWN_CBUFFER, //20
VIDREQ_RESET_UP_CBUFFER,
VIDREQ_RESET_ENCODER,
VIDREQ_REKSTART_ENCODER,
VIDREQ_WAIT_ENC_END_STOP_IMC,
VIDREQ_GET_FNUM,
VIDREQ_PAUSE_ENC,
VIDREQ_CONTINUE_ENC,
VIDREQ_PAUSE_ENC_CHANNEL,
VIDREQ_CONTINUE_ENC_CHANNEL,
VIDREQ_GET_TIME_LABEL,
VIDREQ_SET_SOFT_IMAGE_LABEL,
VIDREQ_CAMERA_OUT,
VIDREQ_RESET_UVC_ENC,
VIDREQ_ENCODE_ONE_IMAGE,
VIDREQ_SET_JPG_THUMBNAILS,
VIDREQ_ASYNC_PUT_DEC_DATA,
VIDREQ_BUFF_MOVE,
VIDREQ_GET_MANUAL_ENC_YUV,
VIDREQ_MANUAL_ENC_STREAM,
VIDREQ_GET_SRC_FMT,
VIDREQ_FLUSHINV_DEC_DATA,
VIDREQ_INSERT_WATERMARKIGN,
VIDREQ_MANUAL_DISP_PUTMAP,
VIDREQ_KICK_UP_ONE_FRMAE,
VIDREQ_GET_CORRECT_SIZE,
};
enum video_rec_quality {
VIDEO_LOW_Q,
VIDEO_MID_Q,
VIDEO_HIG_Q,
};
enum video_camera_type {
VIDEO_CAMERA_NORMAL = 0,
VIDEO_CAMERA_UVC,
VIDEO_CAMERA_VIRTUAL,
VIDEO_CAMERA_JLC,
VIDEO_CAMERA_MUX,
};
#define VIDEO_DIR_NONE 0
#define VIDEO_HOR_MIRROR BIT(0)
#define VIDEO_VER_MIRROR BIT(1)
struct YUV_frame_data {
u16 width;
u16 height;
u16 line_num;
u16 data_height;
int pixformat;
u8 *y;
u8 *u;
u8 *v;
};
struct video_frame_yuv {
u16 width;
u16 height;
u8 *y;
u8 *u;
u8 *v;
};
struct video_yuv_buffer {
u8 *y;
u8 *u;
u8 *v;
};
struct image_scale_data {
u8 zstate;
u32 src_reg_data;
u16 out_width;
u16 out_height;
u8 *output_buf;
struct YUV_frame_data input_frame;
};
struct video_image_enc {
u8 mkstart;
u16 img_width;
u16 img_height;
u16 blk_width;
u16 blk_height;
struct video_yuv_buffer *blk_buf;
};
struct video_image_dec {
u8 fkstart;
u16 width;
u16 height;
u8 *buf;
u32 size;
struct video_yuv_buffer *blk_buf;
};
struct video_decode_frame {
u8 type;
unsigned int reset : 1;
unsigned int mode : 7; //0 -- display, 1 -- encode
u16 width;
int line;
u8 *buf;
u8 *circle_y;
u8 *circle_u;
u8 *circle_v;
int cnt;
};
struct video_encode_frame {
u8 type;
u8 reset;
u8 *buf;
int cnt;
int lines;
};
struct video_cap_buffer {
u8 num;
u32 size;
u8 *buf;
u8 *buf2;
u8 ch_num;
u8 ch_busy;
u8 ch_lock;
};
struct video_subdevice;
struct video_var_param_info;
struct video_subdevice_data {
int tag;
void *data;
};
struct video_platform_data {
int num;
const struct video_subdevice_data *data;
};
struct roi_cfg {
u32 roio_xy;
u32 roi1_xy;
u32 roi2_xy;
u32 roi3_xy;
u32 roio_ratio;
u32 roio_ratio1;
u32 roio_ratio2;
u32 roio_ratio3;
u32 roio_config;
};
struct jpg_q_table {
u16 YQT_DCT[0x40] ;
u16 UVQT_DCT[0x40];
u8 DQT[138]; //file header
};
enum video_pix_format {
VID_PIX_FMT_H264,
VID_PIX_FMT_MJPG,
VID_PIX_FMT_IMG,
VID_PIX_FMT_YUV,
};
enum image_pix_format {
IMG_PIX_FMT_JPG,
IMG_PIX_FMT_YUV,
};
struct h264_user_data {
u8 *data;
u32 len;
};
struct h264_s_attr {
u8 quality;
u8 IP_interval;
u8 std_head;
u16 width;
u16 height;
/*u32 i_bitrate;*/
u32 gap_fps;
};
struct h264_qp {
u8 static_min;
u8 static_max;
u8 dynamic_min;
u8 dynamic_max;
u8 enable_change_qp;
};
struct h264_d_attr {
u32 abr_kbps;
struct roi_cfg roi;
struct h264_qp qp;
};
struct mjpg_s_attr {
u8 enc_mode;//0 -- 整帧, 1 -- 帧分段
u8 quality;
u8 samp_fmt;
u8 source;
int head_len;
u16 width;
u16 height;
u32 abr_kbps;
u32 div_size;
u8 *exif;
int exif_size;
u8 dri_en; //jpeg位流分段使能
u32 jpeg_dri_mcu_cnt; //jpeg分段位流 mcu配置
};
struct mjpg_d_attr {
struct jpg_q_table *qt;
u8 *thumbnails;
int thumb_len;
};
struct icap_auxiliary_mem {
u8 *addr;
u32 size;
};
struct image_s_attr {
u8 quality;
u16 width;
u16 height;
enum image_pix_format format;
int aligned_width;
struct jpg_q_table *jpg_qt;
struct icap_auxiliary_mem *aux_mem;
struct jpg_thumbnail *thumb;
u8 *exif;
int exif_size;
};
struct jpg_dec_mem {
u8 *addr;
u32 size;
};
struct jpg_dec_s_attr {
u16 max_o_width;
u16 max_o_height;
u16 src_width;
u16 src_height;
u16 dec_width;
u16 dec_height;
struct jpg_dec_mem dec_mem;
};
struct video_enc_attr {
enum video_pix_format format;
void *attr;
};
struct video_dec_attr {
enum video_pix_format format;
void *attr;
};
struct yuv_image {
u8 format;
u16 width;
u16 height;
u8 *addr;
u32 size;
};
struct video_dev_fps {
u8 camera_fps;
u8 real_fps; //imc real fps !!!
u8 target_fps;
int tlp_time;
};
struct video_osd {
u16 x ;//起始地址
u16 y ;//结束地址
// u32 osd_yuv;//osd颜色
u32 color[3]; //2bit图像yuv颜色配置
//注意:下面的字符串地址必须是全局的,然后年是yyyy,月是nn,日是dd,时是hh,分是mm,秒是ss,其他字符是英文字母&&符号&&汉字
char *osd_str; //用户自定义格式,例如 "yyyy-nn-dd\hh:mm:ss" 或者 "hh:mm:ss"
char *osd_matrix_str; //用户自定义字模字符串,例如“abcd....0123..”
u8 *osd_matrix_base; //用户自定义字模的起始地址
u32 osd_matrix_len;//用户自定义字模数组的长度,no str len!!!
u8 osd_w;//用户自定义字体大小,8的倍数
u8 osd_h;//8的倍数
};
struct image_capture_info {
u8 multi_scale;
struct video_image_capture *icap;
};
#if 1
enum video_osd_mode {
VID_OSD_TEXT = 0,
VID_OSD_GRAPH,
};
enum video_osd_type {
VIDEO_STREAM_OSD,
VIDEO_IMAGE_OSD,
};
struct video_text_osd {
u16 x;//起始地址
u16 y;//结束地址
// u32 osd_yuv;//osd颜色
u32 color[3]; //2bit图像yuv颜色配置
//注意:下面的字符串地址必须是全局的,然后年是yyyy,月是nn,日是dd,时是hh,分是mm,秒是ss,其他字符是英文字母&&符号&&汉字
char *text_format; //用户自定义格式,例如 "yyyy-nn-dd\hh:mm:ss" 或者 "hh:mm:ss"
char *font_matrix_table; //用户自定义字模字符串,例如“abcd....0123..”
u8 *font_matrix_base; //用户自定义字模的起始地址
u32 font_matrix_len;//用户自定义字模数组的长度,no str len!!!
u8 font_w;//用户自定义字体大小,8的倍数
u8 font_h;//8的倍数
u8 direction; //0 -- 顺向, 1 -- 逆向
u8 bit_mode; //2 - 2bit 1 - 1bit
};
struct video_graph_osd {
u8 bit_mode; //2 - 2bit, 16 - 16bit
u16 x;
u16 y;
u32 color[3]; //2bit图像yuv颜色配置
u16 width;
u16 height;
u8 *icon; //图形内容buffer
int icon_size;
};
struct video_osd_config {
struct video_text_osd text_osd;
struct video_graph_osd icon_osd;
};
struct video_osd_attr {
u32 enable;
u32 ability;
enum video_osd_type type;
struct video_text_osd *text_osd;
struct video_graph_osd *graph_osd;
};
struct app_enc_info {
u8 user_cfg_enable;
int qp_offset_low;
int qp_offset_high;
float f_aq_strength;
u8 dsw_size;
int fs_x_points;
int fs_y_points;
int nr_reduction;
int pre_pskip_limit_flag;
int common_pskip_limit_flag;
int pre_pskip_th;
int common_pskip_th;
};
#endif
#define VIDEO_REC_NUM 2 //double rec or single rec
#define VIDEO_PLATFORM_DATA_BEGIN(vdata) \
static const struct video_platform_data vdata = { \
#define VIDEO_PLATFORM_DATA_END() \
};
struct image_capability {
u8 zoom;
u16 width;
u16 height;
struct video_image_capture *icap;
};
struct video_subdevice_ops {
int (*init)(const char *name, struct video_platform_data *);
bool (*online)(const char *name);
int (*get_fmt)(struct video_format *f);
int (*set_fmt)(struct video_format *f);
struct video_endpoint *(*open)(struct video_var_param_info *);
int (*overlay)(struct video_endpoint *, int i);
int (*streamon)(struct video_endpoint *);
int (*streamoff)(struct video_endpoint *);
int (*get_image_capability)(struct video_endpoint *, struct image_capability *);
int (*image_capture)(struct video_endpoint *, struct image_capability *);
int (*response)(struct video_endpoint *, int cmd, void *);
int (*write)(struct video_endpoint *, void *buf, u32 len);
int (*close)(struct video_endpoint *);
int (*querycap)(struct video_endpoint *, struct video_capability *cap);
int (*ioctrl)(struct video_endpoint *, u32 cmd, void *arg);
};
#define MANUAL_CHANNEL 3
struct video_var_param_info {
u32 fps;
u16 width;
u16 height;
u8 ch;
u8 channel;
int source;
struct video_format *f;
void *priv;
};
struct video_subdevice {
u8 subid;
const char *name;
// u32 input_pixelformat;
u32 output_pixelformat;
const struct video_subdevice_ops *ops;
int (*request)(struct video_endpoint *, int cmd, void *);
};
struct video_endpoint {
struct list_head entry;
struct video_subdevice *dev;
int inused;
void *parent;
void *private_data;
void *imc_data;
};
struct video_crop_ctrl {
u16 crop_sx;
u16 crop_ex;
u16 crop_sy;
u16 crop_ey;
};
struct video_crop_sca {
u16 src_w;
u16 src_h;
u16 crop_w;
u16 crop_h;
};
struct video_crop_tri {
int (*do_crop)(void *priv, void *parm);
void *priv;
void *parm;
};
extern struct video_subdevice video_subdev_begin[];
extern struct video_subdevice video_subdev_end[];
extern const struct device_operations video_dev_ops;
extern const struct device_operations usb_cam_dev_ops;
#define REGISTER_VIDEO_SUBDEVICE(dev, id) \
struct video_subdevice dev SEC_USED(.video_subdev.##id) = { \
.subid = id, \
.name = #dev, \
struct video_device;
struct video_device_ops {
const char *name;
bool (*online)(void *p);
int (*init)(const char *name, const struct video_platform_data *data);
int (*open)(struct video_device *);
int (*set_fmt)(struct video_device *, struct video_format *);
int (*overlay)(struct video_device *, int on);
int (*streamon)(struct video_device *);
int (*streamoff)(struct video_device *);
int (*image_capture)(struct video_device *, struct video_image_capture *icap);
int (*start_I_frame)(struct video_device *);
int (*adjust_fps)(struct video_device *, void *);
int (*ioctl)(struct video_device *, int cmd, u32 arg);
int (*write)(struct video_device *, void *data, u32 len);
int (*close)(struct video_device *);
};
extern struct video_device_ops video_dev_begin[];
extern struct video_device_ops video_dev_end[];
#define REGISTER_VIDEO_DEVICE(dev, _name) \
struct video_device_ops dev SEC_USED(.video_device) = { \
.name = _name, \
struct video_fill_frames {
u8 reset_timer;
u32 time_cnt;
u32 o_frame_cnt;
short interval;
short fill_dly;
char fps_remain;
int lost_frames;
int timer;
int timer_one_frame;
spinlock_t lock;
int msg_post;
};
struct video_device {
struct device device;
struct list_head endpoint;
struct list_head entry;
struct videobuf_queue video_q;
struct video_var_param_info info;
struct video_subdevice *subdev[4];
struct video_image_capture *icap;
struct video_device_ops *dev_ops;
struct video_dev_fps fps;
struct video_fill_frames ff;
void *private_data;
OS_SEM sem;
u8 ref;
u8 time_base;
u8 streamon;
u8 subdev_num;
u8 major, mijor;
u8 mal_dbuf;
u8 stop_now;
u32 frame_cnt;
u32 stop_frame_cnt;
u32 stop_frame_interval;
u32 pixelformat;
u32 stop_time;
u32 stop_skip_frame;
u32 start_time;
u32 insert_frame_cnt;
u32 last_insert_time;
};
int video_subdevice_register(struct video_subdevice *dev);
u32 video_buf_free_space(struct video_device *);
void *video_buf_malloc(struct video_device *, u32 size);
void *video_buf_realloc(struct video_device *, void *buf, int size);
void video_buf_free(struct video_device *, void *buf);
void *video_buf_ptr(void *buf);
u32 video_buf_size(void *buf);
void video_buf_stream_finish(struct video_device *, void *buf);
void video_check_stream_finish(struct video_device *video);
int video_buf_query(struct video_device *ep, struct videobuf_state *sta);
int video_subdev_request(struct video_endpoint *ep, int req, void *arg);
int video_dev_is_need_fill_frame(struct video_device *video);
int video_dev_need_fill_frame(struct video_device *);
void video_dev_fill_frames_reset(struct video_device *video);
void video_dev_real_frame_dec(struct video_device *);
void video_dev_reset_frame_interval_timer(struct video_device *);
int video_force_skip_frame(struct video_device *device);
#endif
@@ -0,0 +1,952 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
/* #include "video/fb.h" */
#include "video.h"
#include "videobuf.h"
#include "device/device.h"
#include "system/init.h"
#include "system/task.h"
#include "system/malloc.h"
#include "event.h"
#include "ascii.h"
/* #include "asm/imc_driver.h" */
/* #include "asm/isp_dev.h" */
#include "debug.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
#define list_for_each_video_device(dev) \
for (dev = video_dev_begin; dev < video_dev_end; dev++)
u32 video_buf_free_space(struct video_device *video)
{
return videobuf_stream_free_space(&video->video_q);
}
void *video_buf_malloc(struct video_device *video, u32 size)
{
struct videobuf_buffer *b;
b = videobuf_stream_alloc(&video->video_q, size);
if (!b) {
return NULL;
}
b->len = size;
// printf("video_buf: %x\n", b, b->data);
return b->data;
}
void *video_buf_realloc(struct video_device *video, void *buf, int size)
{
ASSERT(buf);
struct videobuf_buffer *b = container_of(buf, struct videobuf_buffer, data);
void *lbuf;
ASSERT(b);
b->len = size;
lbuf = videobuf_stream_realloc(&video->video_q, b, size);
if (lbuf == NULL) {
return NULL;
}
return b->data;
}
void video_buf_free(struct video_device *video, void *buf)
{
struct videobuf_buffer *b = container_of(buf, struct videobuf_buffer, data);
if (buf == NULL) {
return;
}
/* ASSERT(buf != NULL, "video_buf_free\n"); */
videobuf_stream_free(&video->video_q, b);
}
int video_buf_query(struct video_device *video, struct videobuf_state *sta)
{
return videobuf_query(&video->video_q, sta);
}
void *video_buf_ptr(void *buf)
{
return buf;
}
u32 video_buf_size(void *buf)
{
struct videobuf_buffer *b = container_of(buf, struct videobuf_buffer, data);
return b->len;
}
int video_frame_cnt(struct video_device *video)
{
return video->frame_cnt;
}
static void video_insert_end_frame(struct video_device *video)
{
struct device_event e = {0};
struct videobuf_buffer *b ;//= container_of(buf, struct videobuf_buffer, data);
printf("=========finish: f=%d/%d t=%lu/%d i=%d\n", video->frame_cnt, video->stop_frame_cnt,
jiffies, video->stop_time, video->insert_frame_cnt);
b = videobuf_stream_alloc(&video->video_q, 8);
if (b) {
if (video->pixelformat & VIDEO_PIX_FMT_H264) {
u32 flag = 0x18;
b->len = 8;
memcpy(b->data + 4, &flag, 4);
} else if (video->pixelformat & VIDEO_PIX_FMT_JPEG) {
u8 *buf = (u8 *)b->data;
buf[0] = 0x56;
buf[1] = 0x18;
buf[2] = 0x57;
buf[3] = 0x19;
b->len = 8;
}
videobuf_stream_finish(&video->video_q, b);
#if 0
if (video->time_base) {
e.arg = "video_rec_time";
e.value = 0;
e.event = DEVICE_EVENT_CHANGE;
device_event_notify(DEVICE_EVENT_FROM_VIDEO, &e);
}
#endif
video->frame_cnt = 0;
video->insert_frame_cnt = 0;
video->stop_frame_cnt = video->stop_frame_interval * video->fps.target_fps;
/* video->stop_time = jiffies + msecs_to_jiffies(video->stop_frame_interval * 1000); */
video->start_time = video->stop_time;
video->stop_time = video->stop_time + msecs_to_jiffies(video->stop_frame_interval * 1000);
if (video->dev_ops->start_I_frame) {
video->dev_ops->start_I_frame(video);
}
}
/* spin_lock(&video->ff.lock); */
/* video->ff.o_frame_cnt++; */
/* spin_unlock(&video->ff.lock); */
}
void video_buf_stream_finish(struct video_device *video, void *buf)
{
struct videobuf_buffer *b = container_of(buf, struct videobuf_buffer, data);
if (video->pixelformat & VIDEO_PIX_FMT_JPEG) {
if (!video->frame_cnt) {
video_buf_free(video, buf);
} else {
videobuf_stream_finish(&video->video_q, b);
}
} else {
videobuf_stream_finish(&video->video_q, b);
}
video->frame_cnt++;
/* if (video->time_base && (video->frame_cnt % video->fps.target_fps) == 0) { */
/* e.arg = "video_rec_time"; */
/* e.type = SYS_DEVICE_EVENT; */
/* e.u.dev.value = video->frame_cnt / video->fps.target_fps; */
/* e.u.dev.event = DEVICE_EVENT_CHANGE; */
/* sys_event_notify(&e); */
/* } */
if (video->stop_skip_frame != 2) {
spin_lock(&video->ff.lock);
video->ff.o_frame_cnt++;
spin_unlock(&video->ff.lock);
}
}
void video_check_stream_finish(struct video_device *video)
{
if (video->stop_time == 0) {
return;
}
if (video->stop_skip_frame == 0) {
if (video->pixelformat & VIDEO_PIX_FMT_H264) {
if (time_after(jiffies, video->stop_time - 200)) {
spin_lock(&video->ff.lock);
video->stop_skip_frame = 1;
spin_unlock(&video->ff.lock);
/* if (video->frame_cnt < video->stop_frame_cnt && video->stop_frame_cnt - video->frame_cnt == 20) { */
log_debug("force insert I frame %d/%d\n", video->frame_cnt, video->stop_frame_cnt);
if (video->dev_ops->start_I_frame) {
video->dev_ops->start_I_frame(video);
}
}
} else {
if (time_after(jiffies, video->stop_time - 200)) {
spin_lock(&video->ff.lock);
video->stop_skip_frame = 1;
spin_unlock(&video->ff.lock);
}
}
}
#if 0
//计算当前时间点应有的帧数
int jiffies_interval = jiffies - video->start_time;
int correct_frame_cnt = (jiffies_interval * 10) / (1000 / video->fps.target_fps);
//当前时间的应当有的帧数与实际帧数相差太大,补帧
if (correct_frame_cnt - (int)video->frame_cnt > 3) {
int insert_frame_interval = jiffies_to_msecs(jiffies - video->last_insert_time);
int frame_interval = 1000 / video->fps.target_fps;
#if 0 //todo,打开这个会导致第三路录像慢放(多插帧)
//如果帧差别过大,不考虑卡顿问题,一直补帧
if (correct_frame_cnt - (int)video->frame_cnt >= 10) {
video->insert_frame_cnt++;
video->last_insert_time = jiffies;
video_force_skip_frame(video);
}
//控制补帧间隔,避免连续补帧造成画面卡顿
else
#endif
if (insert_frame_interval > frame_interval * 3) {
video->insert_frame_cnt++;
video->last_insert_time = jiffies;
video_force_skip_frame(video);
}
}
#endif
if (video->time_base && (video->frame_cnt % (video->fps.target_fps * 10)) == 0) {
//每10秒同步下UI计时
#if 0
struct device_event e = {0};
e.arg = "video_rec_time";
e.value = video->frame_cnt / video->fps.target_fps;
e.event = DEVICE_EVENT_CHANGE;
device_event_notify(DEVICE_EVENT_FROM_VIDEO, &e);
#endif
}
if (time_after(jiffies, video->stop_time) || video->frame_cnt >= video->stop_frame_cnt) {
if (video->stop_skip_frame == 1) {
if (video->frame_cnt <= video->stop_frame_cnt) {
spin_lock(&video->ff.lock);
video->stop_skip_frame = 2;
spin_unlock(&video->ff.lock);
u32 need_skip_frame = video->stop_frame_cnt - video->frame_cnt + 1;
while (need_skip_frame--) {
log_debug("force skip frame %d/%d\n", video->frame_cnt, video->stop_frame_cnt);
video_force_skip_frame(video);
/* spin_lock(&video->ff.lock); */
/* video->ff.o_frame_cnt++; */
/* spin_unlock(&video->ff.lock); */
/* need_skip_frame = video->stop_frame_cnt - video->frame_cnt; */
}
video_insert_end_frame(video);
spin_lock(&video->ff.lock);
video->stop_skip_frame = 0;
spin_unlock(&video->ff.lock);
} else {
video_insert_end_frame(video);
spin_lock(&video->ff.lock);
video->stop_skip_frame = 0;
spin_unlock(&video->ff.lock);
}
video_dev_fill_frames_reset(video);
}
}
}
int video_check_h264_manu_finish(struct video_device *video)
{
if (video->stop_time == 0) {
return 0;
}
/* log_d("frame %d/%d %d %d\n", jiffies, video->stop_time,video->frame_cnt,video->stop_frame_cnt); */
if (time_after(jiffies, video->stop_time - 200)) {
if (video->pixelformat & VIDEO_PIX_FMT_H264) {
if (video->frame_cnt <= video->stop_frame_cnt && video->stop_frame_cnt - video->frame_cnt < 1) {
video_insert_end_frame(video);
return 1;
}
}
}
return 0;
}
static void __calculate_fill_interval(struct video_fill_frames *ff)
{
int interval;
if (ff->lost_frames == 0 || ff->fps_remain <= 1) {
ff->fill_dly = 0;
ff->interval = 0;
} else {
interval = (ff->fps_remain - 1) / ff->lost_frames;
if (interval == 0) {
ff->fill_dly = 0;
} else if (ff->fill_dly > 0) {
ff->fill_dly -= ff->interval - interval;
} else {
ff->fill_dly = interval;
}
ff->interval = interval;
}
}
static void video_rec_check_fps(void *_video)
{
struct video_device *video = (struct video_device *)_video;
struct video_fill_frames *ff = &video->ff;
struct video_dev_fps *fps = &video->fps;
spin_lock(&ff->lock);
if (video->dev_ops->adjust_fps) {
video->dev_ops->adjust_fps(video, (void *)&fps->real_fps);
if (fps->real_fps == 0) {
fps->real_fps = fps->camera_fps;
}
}
ff->reset_timer = 1;
ff->fps_remain = video->fps.real_fps;
/* printf("time cnt : %d, target fps : %d, o frame count : %d, real fps : %d\n", ff->time_cnt, fps->target_fps, ff->o_frame_cnt, fps->real_fps); */
if (fps->tlp_time) {
ff->lost_frames = ++ff->time_cnt * 1000 / fps->tlp_time - ff->o_frame_cnt - 1000 / fps->tlp_time;
} else {
ff->lost_frames = ++ff->time_cnt * fps->target_fps - ff->o_frame_cnt - fps->real_fps;
}
/* if (ff->time_cnt >= 60) { */
/* ff->time_cnt = 1; */
/* ff->o_frame_cnt = 0; */
/* } */
__calculate_fill_interval(ff);
spin_unlock(&ff->lock);
/*printf("%ds: %d, %d\n", ff->time_cnt, ff->lost_frames, ff->interval);*/
}
static void video_rec_one_frame_timer(void *_video)
{
struct video_device *video = (struct video_device *)_video;
struct video_fill_frames *ff = &video->ff;
spin_lock(&ff->lock);
ff->lost_frames++;
if (ff->fps_remain > 0) {
ff->fps_remain--;
}
__calculate_fill_interval(ff);
spin_unlock(&ff->lock);
printf("lost: %d, %d\n", ff->lost_frames, ff->fill_dly);
}
/*
static void video_sec_timer(struct video_device *video)
{
struct video_fill_frames *ff = &video->ff;
if (ff->reset_timer) {
sys_hi_timer_modify(ff->timer, 1000);
ff->reset_timer = 0;
}
}
*/
int video_dev_is_need_fill_frame(struct video_device *video)
{
struct video_fill_frames *ff = &video->ff;
int tmp;
spin_lock(&ff->lock);
tmp = ff->fill_dly - 1;
if ((ff->lost_frames > 0) && (tmp <= 0)) {
tmp = ff->lost_frames - 1;
spin_unlock(&ff->lock);
return tmp + 1;
}
spin_unlock(&ff->lock);
return 0;
}
int video_dev_need_fill_frame(struct video_device *video)
{
#if 0
struct video_fill_frames *ff = &video->ff;
#if 0
if (ff->reset_timer) {
ff->reset_timer = 0;
sys_hi_timer_modify(ff->timer, 1000 - 16);
}
#else
if (ff->reset_timer && !ff->timer) {
ff->timer = sys_hi_timer_add(video, video_rec_check_fps, 1000);
ff->reset_timer = 0;
}
#endif
if (ff->o_frame_cnt <= 5) {
return 0;
}
spin_lock(&ff->lock);
if (ff->lost_frames > 0 && --ff->fill_dly <= 0) {
ff->lost_frames--;
__calculate_fill_interval(ff);
if (ff->lost_frames > 100 * (ff->msg_post + 1)) {
ff->msg_post ++;
printf("ff->lost_frames:%d", ff->lost_frames);
/* extern void video_write_err(u8 id, int drop_fcnt); */
/* video_write_err(video->major, ff->lost_frames + 1); */
}
spin_unlock(&ff->lock);
/* printf("\ndrop %d:%d %d\n", video->major, ff->lost_frames, ff->msg_post); */
/* printf("fill: %d, %d, %d\n", ff->fps_remain, ff->lost_frames, ff->interval); */
return ff->lost_frames + 1;
} else {
ff->msg_post = 0;
}
spin_unlock(&ff->lock);
#endif
return 0;
}
void video_dev_reset_frame_interval_timer(struct video_device *video)
{
#if 0
struct video_fill_frames *ff = &video->ff;
u32 fps;
spin_lock(&ff->lock);
fps = video->fps.real_fps;
spin_unlock(&ff->lock);
if (ff->timer_one_frame) {
/* sys_hi_timer_modify(ff->timer_one_frame, (1000 / video->fps.real_fps) * 3 / 2); */
sys_hi_timer_modify(ff->timer_one_frame, (1000 / fps) * 3 / 2);
}
#endif
}
void video_dev_real_frame_dec(struct video_device *video)
{
struct video_fill_frames *ff = &video->ff;
spin_lock(&ff->lock);
if (ff->fps_remain > 0) {
ff->fps_remain--;
}
spin_unlock(&ff->lock);
}
static void video_dev_fill_frames_init(struct video_device *video)
{
struct video_fill_frames *ff = &video->ff;
spin_lock_init(&ff->lock);
video_rec_check_fps(video);
/*ff->timer = sys_hi_timer_add(video, video_rec_check_fps, 2000);*/
/*if (video->fps.real_fps == video->fps.camera_fps) {
ff->timer_one_frame = sys_hi_timer_add(video, video_rec_one_frame_timer, 1000);
}*/
}
void video_dev_fill_frames_reset(struct video_device *video)
{
struct video_fill_frames *ff = &video->ff;
spin_lock(&ff->lock);
ff->time_cnt = 0;
ff->o_frame_cnt = 0;
ff->lost_frames = 0;
spin_unlock(&ff->lock);
}
static void video_dev_fill_frames_uninit(struct video_device *video)
{
#if 0
struct video_fill_frames *ff = &video->ff;
if (ff->timer) {
sys_hi_timer_del(ff->timer);
ff->timer = 0;
}
if (ff->timer_one_frame) {
sys_hi_timer_del(ff->timer_one_frame);
}
#endif
}
static int video_dev_reqbufs(void *_video, struct video_reqbufs *b)
{
struct video_device *video = (struct video_device *)_video;
return videobuf_reqbufs(&video->video_q, b);
}
static int video_dev_qbuf(void *_video, struct video_buffer *b)
{
struct video_device *video = (struct video_device *)_video;
return videobuf_qbuf(&video->video_q, b);
}
static int video_dev_dqbuf(void *_video, struct video_buffer *b)
{
struct video_device *video = (struct video_device *)_video;
return videobuf_dqbuf(&video->video_q, b);
}
static void video_dev_dbuf_release(void *_video)
{
struct video_device *video = (struct video_device *)_video;
videobuf_streamoff(&video->video_q, 0);
videobuf_queue_release(&video->video_q);
video->mal_dbuf = 0;
}
static int video_dev_reqdbuf(void *_video, struct video_reqbufs *b)
{
struct video_device *video = (struct video_device *)_video;
int err = 0;
u8 channel = 0;
err = videobuf_reqbufs(&video->video_q, b);
if (!err) {
err = videobuf_streamon(&video->video_q, (u8 *)&channel);
video->mal_dbuf = 1;
}
return err;
}
static int video_dev_idbuf(void *_video, struct video_buffer *b)
{
struct video_device *video = (struct video_device *)_video;
return videobuf_qbuf(&video->video_q, b);
}
static int video_dev_rdbuf(void *_video, struct video_buffer *b)
{
struct video_device *video = (struct video_device *)_video;
videobuf_dqbuf(&video->video_q, b);
return 0;
}
static int video_ioctrl(void *_video, u32 cmd, void *arg)
{
struct video_device *video = (struct video_device *)_video;
if (video->dev_ops && video->dev_ops->ioctl) {
return video->dev_ops->ioctl(video, cmd, (u32)arg);
}
return 0;
}
/*int video_subdev_request(struct video_endpoint *ep, int req, void *arg)
{
// int err;
struct video_endpoint *p;
struct video_device *video = (struct video_device *)ep->parent;
list_for_each_endpoint(p, video) {
if (p == ep) {
continue;
}
if (p->dev->ops->response) {
p->dev->ops->response(p, req, arg);
}
}
if (req == VIDREQ_IMAGE_CAPTURE_COMPLETED) {
//video->icap->baddr = (u8 *)video_buf_ptr(arg);
video->icap->size = (u32)arg;//video_buf_size(arg);
[>puts("buf & size : \n");
put_u32hex((u32)video->icap->baddr);
put_u32hex(video->icap->size);<]
os_sem_post(&video->sem);
}
return 0;
}*/
static int video_overlay(struct video_device *_video, unsigned int on)
{
int err = -EINVAL;
struct video_device *video = (struct video_device *)_video;
if (video->dev_ops && video->dev_ops->overlay) {
err = video->dev_ops->overlay(video, on);
}
return err;
}
static int video_streamon(struct video_device *_video, int channel)
{
int err;
struct video_device *video = (struct video_device *)_video;
videobuf_streamon(&video->video_q, (u8 *)channel);
if (video->streamon++) {
return 0;
}
if (video->dev_ops && video->dev_ops->streamon) {
err = video->dev_ops->streamon(video);
if (err) {
videobuf_streamoff(&video->video_q, channel);
return err;
}
}
if ((video->major == 0 && video->mijor == 0) || (video->major == 4 && video->mijor == 0)) {
video->time_base = 1;
}
video->start_time = jiffies;
video->stop_time = jiffies + msecs_to_jiffies(video->stop_frame_interval * 1000);
printf("video:%x video->stop_time:%d", (u32)_video, video->stop_time);
video_dev_fill_frames_init(video);
return 0;
}
static int video_streamoff(void *_video, int index)
{
int err;
struct video_device *video = (struct video_device *)_video;
if (--video->streamon == 0) {
if (video->dev_ops && video->dev_ops->streamoff) {
video->dev_ops->streamoff(video);
}
video_dev_fill_frames_uninit(video);
}
err = videobuf_streamoff(&video->video_q, index);
if (err) {
return err;
}
return 0;
}
static int video_remove_image_buf(struct video_device *video, void *arg)
{
struct video_image_capture *icap = (struct video_image_capture *)arg;
struct videobuf_buffer *b = NULL;
b = container_of(video->icap->baddr, struct videobuf_buffer, data);
ASSERT(video->icap->baddr != NULL, "video_remove_image_buf\n");
videobuf_stream_free(&video->video_q, b);
return 0;
}
static int video_image_capture(void *_video, struct video_image_capture *icap)
{
int err = 0;
struct video_device *video = (struct video_device *)_video;
if (video->dev_ops && video->dev_ops->image_capture) {
err = video->dev_ops->image_capture(video, icap);
}
return err;
}
static int video_init(const struct dev_node *node, void *_data)
{
struct video_device_ops *ops;
const struct video_platform_data *data = (const struct video_platform_data *)_data;
list_for_each_video_device(ops) {
if (!ASCII_StrCmp(ops->name, node->name, -1)) {
if (ops->init) {
ops->init(node->name, data);
}
}
}
return 0;
}
static bool video_online(const struct dev_node *node)
{
struct video_device_ops *ops;
list_for_each_video_device(ops) {
if (!ASCII_StrCmp(ops->name, node->name, -1)) {
if (ops->online) {
return ops->online((void *)node->name);
}
}
}
return false;
}
static int video_open(const char *name, struct device **device, void *arg)
{
int major = 0;
int mijor = 0;
struct video_device *video, *n;
struct video_device_ops *ops;
log_debug("video_device_open: %s\n", name);
sscanf(name, "video%d.%d", &major, &mijor);
video = (struct video_device *)zalloc(sizeof(*video));
if (!video) {
log_error("no mem\n");
return -ENOMEM;
}
video->major = major;
video->mijor = mijor;
list_for_each_video_device(ops) {
printf("ops->name:%s name:%s\n", ops->name, name);
if (!ASCII_StrCmp(ops->name, name, -1)) {
int err = ops->open(video);
if (err) {
free(video);
return err;
}
video->dev_ops = ops;
break;
}
}
*device = &video->device;
(*device)->private_data = video;
os_sem_create(&video->sem, 0);
videobuf_queue_init(&video->video_q, 32, name);
return 0;
}
static int video_set_fmt(struct video_device *video, struct video_format *f)
{
if (video->dev_ops && video->dev_ops->set_fmt) {
if (f->type == VIDEO_BUF_TYPE_VIDEO_CAPTURE) {
video->pixelformat = f->pixelformat;
}
return video->dev_ops->set_fmt(video, f);
}
return -EINVAL;
}
static int video_write(struct device *device, void *data, u32 len, u32 addr)
{
struct video_device *video = (struct video_device *)device->private_data;
if (video->dev_ops && video->dev_ops->write) {
if (len == video->dev_ops->write(video, data, len)) {
return len;
}
}
return 0;
}
static int video_close(struct device *device)
{
struct video_device *video = (struct video_device *)device->private_data;
log_debug("video dev close: video%d.%d\n", video->major, video->mijor);
if (video->dev_ops && video->dev_ops->close) {
video->dev_ops->close(video);
}
if (video->mal_dbuf) {
video_dev_dbuf_release(video);
} else {
videobuf_queue_release(&video->video_q);
}
free(video);
return 0;
}
static int video_ioctl(struct device *device, u32 cmd, u32 arg)
{
int ret = 0;
struct video_device *video = (struct video_device *)device->private_data;
switch (cmd) {
case VIDIOC_SET_FMT:
ret = video_set_fmt(video, (struct video_format *)arg);
log_debug("video_dev_set_fmt: %s\n", !ret ? "suss" : "err");
break;
case VIDIOC_OVERLAY:
ret = video_overlay(video, arg);
break;
case VIDIOC_PLAY:
ret = video_overlay(video, arg);
break;
case VIDIOC_STREAM_ON:
ret = video_streamon(video, arg);
log_debug("video_dev_streamon: %s\n", !ret ? "suss" : "err");
break;
case VIDIOC_STREAM_OFF:
ret = video_streamoff(video, arg);
break;
case VIDIOC_IMAGE_CAPTURE:
ret = video_image_capture(video, (struct video_image_capture *)arg);
break;
case VIDIOC_DEL_IMAGE:
ret = video_remove_image_buf(video, (void *)arg);
break;
case VIDIOC_REQBUFS:
ret = video_dev_reqbufs(video, (struct video_reqbufs *)arg);
break;
case VIDIOC_DQBUF:
return video_dev_dqbuf(video, (struct video_buffer *)arg);
break;
case VIDIOC_QBUF:
return video_dev_qbuf(video, (struct video_buffer *)arg);
break;
case VIDIOC_REQDBUF:
ret = video_dev_reqdbuf(video, (struct video_reqbufs *)arg);
break;
case VIDIOC_QUERYBUF:
video_buf_query(video, (struct videobuf_state *)arg);
break;
case VIDIOC_GET_FPS:
ret = video_ioctrl(video, cmd, (void *)arg);
if (ret == 0) {
struct video_dev_fps *fps = (struct video_dev_fps *)arg;
}
break;
case VIDIOC_SET_FPS:
ret = video_ioctrl(video, cmd, (void *)arg);
if (ret == 0) {
struct video_dev_fps *fps = (struct video_dev_fps *)arg;
if (video->streamon == 0) {
memcpy(&video->fps, fps, sizeof(struct video_dev_fps));
} else {
struct video_fill_frames *ff = &video->ff;
spin_lock(&ff->lock);
video->fps.real_fps = fps->real_fps;
spin_unlock(&ff->lock);
}
}
log_debug("video_dev_set_fps: %s\n", !ret ? "suss" : "err");
break;
case VIDIOC_GET_FRAME_CNT:
*(u32 *)arg = video->frame_cnt;
break;
case VIDIOC_SET_STOP_FRAME_INTERVAL:
video->stop_frame_interval = arg;
video->stop_frame_cnt = arg * video->fps.target_fps;
printf("-------stop_frame_interval: %d %d %d\n", arg, video->stop_frame_interval, video->stop_frame_cnt);
break;
case VIDIOC_TRY_STOP_FRAME_INTERVAL:
video->stop_frame_cnt = arg;
break;
case VIDIOC_START_IFREME:
if (video->dev_ops->start_I_frame) {
video->dev_ops->start_I_frame(video);
}
break;
default:
ret = video_ioctrl(video, cmd, (void *)arg);
break;
}
if (ret) {
printf("video_ioct: err = %d\n", ret);
}
return ret;
}
const struct device_operations video_dev_ops = {
.init = video_init,
.open = video_open,
.write = video_write,
.close = video_close,
.ioctl = video_ioctl,
.online = video_online,
};
@@ -0,0 +1,428 @@
#ifndef VIDEO_IOCTL_H
#define VIDEO_IOCTL_H
#include "typedef.h"
#include "generic/list.h"
#include "generic/ioctl.h"
#include "generic/lbuf.h"
#include "system/task.h"
// #include "video/camera.h"
// #include "video/usb_cam_dev.h"
struct video_capability {
char name[16];
u32 capabilities;
};
/* Values for 'capabilities' field */
#define VIDEO_CAP_VIDEO_CAPTURE 0x00000001 /* Is a video capture device */
#define VIDEO_CAP_VIDEO_OUTPUT 0x00000002 /* Is a video output device */
#define VIDEO_CAP_VIDEO_OVERLAY 0x00000004 /* Can do video overlay */
#define VIDEO_CAP_CAMERA_FPS "camera_fps"
#define VIDEO_CAP_TUNER 0x00010000 /* has a tuner */
#define VIDEO_CAP_AUDIO 0x00020000 /* has audio support */
#define VIDEO_CAP_RADIO 0x00040000 /* is a radio device */
#define VIDEO_CAP_MODULATOR 0x00080000 /* has a modulator */
#define VIDEO_CAP_READWRITE 0x01000000 /* read/write systemcalls */
#define VIDEO_CAP_ASYNCIO 0x02000000 /* async I/O */
#define VIDEO_CAP_STREAMING 0x04000000 /* streaming I/O ioctls */
/*#define VIDEO_FPS(a) ((a)*100)*/
#define VIDEO_REC_SET_FPS 4
#define VIDEO_REC_SET_FILL_FRAME 5
#define VIDEO_REC_SET_CAMERA_FPS 6
#define VIDEO_REC_SET_CYC_TIME 8
#define VIDEO_REC_SET_DELAY_LIMIT 9
#define VIDEO_REC_RESET_BITS_RATE 10
#define VIDEO_REC_SET_TIME_STAMP 11
#define VIDEO_PIX_FMT_RAW 0x00000001
#define VIDEO_PIX_FMT_JPEG 0x00000002
#define VIDEO_PIX_FMT_H264 0x00000004
#define VIDEO_PIX_FMT_YUV420 0x00000100
#define VIDEO_PIX_FMT_YUYV 0x00000200
#define VIDEO_PIX_FMT_YV12 0x00000400
#define VIDEO_PIX_FMT_NV12 0x00000800
#define VIDEO_PIX_FMT_YUV422 0x00001000
#define VIDEO_PIX_FMT_YUV444 0x00001100
#define VIDEO_PIX_FMT_YUV 0x0000ff00
#define VIDIOC_QUERYCAP _IOR('V', 0, sizeof(struct video_capability))
#define VIDIOC_GET_FMT _IOR('V', 1, sizeof(struct video_format))
#define VIDIOC_SET_FMT _IOW('V', 1, sizeof(struct video_format))
#define VIDIOC_OVERLAY _IOW('V', 2, sizeof(int))
#define VIDIOC_STREAM_ON _IOW('V', 3, sizeof(enum video_buf_type))
#define VIDIOC_STREAM_OFF _IOW('V', 4, sizeof(enum video_buf_type))
#define VIDIOC_REQBUFS _IOW('V', 5, sizeof(struct video_reqbufs))
#define VIDIOC_QUERYBUF _IOR('V', 6, sizeof(struct videobuf_buffer))
#define VIDIOC_QBUF _IOR('V', 7, sizeof(struct videobuf_buffer))
#define VIDIOC_DQBUF _IOW('V', 8, sizeof(struct videobuf_buffer))
/*#define VIDIOC_GET_AUDIO _IOR('V', 9, sizeof(struct video_audio))
#define VIDIOC_SET_AUDIO _IOW('V', 9, sizeof(struct video_audio))*/
#define VIDIOC_IMAGE_CAPTURE _IOR('V', 10, sizeof(struct video_image_capture))
#define VIDIOC_DEL_IMAGE _IOW('V', 11, sizeof(struct video_image_capture))
#define VIDIOC_PLAY _IOW('V', 12, sizeof(int))
#define VIDIOC_GET_S_ATTR _IOR('V', 13, sizeof(struct video_enc_attr))
#define VIDIOC_SET_S_ATTR _IOW('V', 13, sizeof(struct video_enc_attr))
#define VIDIOC_GET_D_ATTR _IOR('V', 14, sizeof(struct video_enc_attr))
#define VIDIOC_SET_D_ATTR _IOW('V', 14, sizeof(struct video_enc_attr))
#define VIDIOC_GET_FPS _IOR('V', 15, sizeof(struct video_dev_fps))
#define VIDIOC_SET_FPS _IOW('V', 15, sizeof(struct video_dev_fps))
#define VIDIOC_GET_OSD _IOR('V', 16, sizeof(struct video_osd))
#define VIDIOC_SET_OSD _IOW('V', 16, sizeof(struct video_osd))
#define VIDIOC_OSD_ENABLE _IOW('V', 17, sizeof(bool))
#define VIDIOC_OSD_DISABLE _IOW('V', 18, sizeof(bool))
#define VIDIOC_GET_FRAME_CNT _IOW('V', 19, sizeof(int))
#define VIDIOC_TRY_STOP_FRAME_INTERVAL _IOW('V', 20, sizeof(int))
#define VIDIOC_SET_STOP_FRAME_INTERVAL _IOW('V', 21, sizeof(int))
#define VIDIOC_GET_OSD_ATTR _IOR('V', 22, sizeof(struct video_osd_attr))
#define VIDIOC_SET_OSD_ATTR _IOW('V', 23, sizeof(struct video_osd_attr))
#define VIDIOC_START_IFREME _IOW('V', 24, sizeof(int))
#define VIDIOC_APPEND_USER_DATA _IOW('V', 25, sizeof(struct h264_user_data))
#define VIDIOC_V4_PAUSE_RUN _IOW('V', 26, sizeof(int))
#define VIDIOC_SET_AVC _IOW('V', 27, sizeof(struct app_enc_info))
#define VIDIOC_SET_OVERLAY _IOW('V', 26, sizeof(int))
#define VIDIOC_GET_OVERLAY _IOR('V', 26, sizeof(int))
#define VIDIOC_CLEAR_OVERLAY _IOW('V', 27, sizeof(int))
#define VIDIOC_BUF_MOVE _IOW('V', 28, sizeof(int))
#define VIDIOC_SET_ENC_CROP _IOW('V', 29, sizeof(struct video_source_crop))
#define VIDIOC_SET_DIS_CROP _IOW('V', 30, sizeof(struct video_source_crop))
#define VIDIOC_GET_MIRROR _IOR('V', 31, sizeof(struct video_mirror))
#define VIDIOC_SET_MIRROR _IOW('V', 31, sizeof(struct video_mirror))
#define VIDIOC_GET_JAGGY _IOR('V', 32, sizeof(struct video_jaggy))
#define VIDIOC_SET_JAGGY _IOW('V', 32, sizeof(struct video_jaggy))
#define VIDIOC_REQDBUF _IOW('V', 33, sizeof(struct video_reqbufs))
#define VIDIOC_RDBUF _IOR('V', 34, sizeof(struct videobuf_buffer))
#define VIDIOC_IDBUF _IOW('V', 35, sizeof(struct videobuf_buffer))
#define VIDIOC_YUV_CAPTURE _IOR('V', 36, sizeof(struct video_image_capture))
#define VIDIOC_CLOSE_CAMERA _IOW('V', 37, sizeof(int))
#define VIDIOC_SET_CAMERA_INFO _IOW('V', 38, sizeof(struct camera_device_info))
#define VIDIOC_PAUSE _IOW('V', 39, sizeof(int))
#define VIDIOC_RESUME _IOW('V', 40, sizeof(int))
#define VIDIOC_GET_SOURCE_CH _IOW('V', 41, sizeof(int))
#define VIDIOC_SAVE_FILE _IOW('V', 42, sizeof(int))
#define VIDIOC_SET_CYC_TIME _IOW('V', 43, sizeof(int))
enum video_buf_type {
VIDEO_BUF_TYPE_VIDEO_CAPTURE,
VIDEO_BUF_TYPE_IMAGE_CAPTURE,
VIDEO_BUF_TYPE_VIDEO_OVERLAY,
VIDEO_BUF_TYPE_VIDEO_PLAY,
VIDEO_BUF_TYPE_YUV_CAPTURE,
VIDEO_BUF_TYPE_UVC_CAPTURE,
VIDEO_BUF_TYPE_ISP_TRAIN,
VIDEO_BUF_TYPE_QUICK_IMAGE,
VIDEO_BUF_TYPE_STICKER_IMAGE,
VIDEO_PIPE_PRE_CREATE,
};
enum video_three_way_type {
VIDEO_THREE_WAY_NONE,
VIDEO_THREE_WAY_JPEG,
VIDEO_THREE_WAY_H264,
VIDEO_THREE_WAY_DOU_RAW,
};
struct video_mirror {
u32 enc_dis;
u32 mirror;
};
struct video_jaggy {
u32 enc_dis;
u32 jaggy;
};
struct video_window {
u16 left;
u16 top;
u16 width;
u16 height;
u16 border_left;
u16 border_top;
u16 border_right;
u16 border_bottom;
u16 mirror;
u8 win_type;
u8 combine;
};
struct video_format {
enum video_buf_type type;
u8 camera_type;
u8 online;//0:是手动编码,1是联动
u8 enable_dri;
u8 three_way_type;
u8 disp_id;
u8 disp_yuv_type;
u8 disp_fb_buf_num;
u8 uvc_id;
u8 fps;
u8 osd_en;
u16 enc_rotate;
u16 dis_rotate;
u8 stop_wait;
u8 three_in_one_open;
u16 src_width;
u16 src_height;
int blk_width;
int blk_height;
u32 pixelformat;
u32 gap_fps;
struct video_window win;
void *private_data;
u8 double_raw;
void *sticker;
};
struct jpg_thumbnail {
u8 enable;
u8 quality;
u16 width;
u16 height;
u8 *buf;
int len;
};
struct image_sticker {
u8 enable;
u8 format;//YUV420/YUV422
u16 x;
u16 y;
u16 width;
u16 height;
u8 *addr;
u32 size;
};
struct video_image_capture {
u16 width;
u16 height;
u8 *baddr;
u32 size;
int format;
u32 mirror;
struct jpg_thumbnail *thumbnail;
struct image_sticker *sticker;
u8 linear_scale; // 使用软件线性插值标志
};
struct video_reqbufs {
void *buf;
int size;
struct buffer_dev {
void *fd;
u32 head_size;
u32 align_size;
u32 addr;
u32 size;
int (*read)(void *fd, void *buf, u32 addr, int len);
int (*write)(void *fd, void *buf, u32 addr, int len);
} dev;
};
struct videobuf_buffer {
u32 len;
u32 magic;
u32 msec;
u8 data[0];
};
struct videobuf_state {
u32 available_len;
u32 max_continue_len;
};
// struct videobuf_queue {
// u8 ref;
// u8 streaming;
// u16 align;
// const char *name;
// OS_SEM sem;
// void *buf;
// struct lbuff_head *lbuf;
// void *private_data;
// };
struct video_buffer {
u8 index;
u8 noblock;
u16 timeout;
u32 time_msec;
u32 len;
u32 baddr;
void *priv;
u32 test_num;
};
//enum videobuf_state {
//VIDEOBUF_NEEDS_INIT = 0,
//VIDEOBUF_PREPARED = 1,
//VIDEOBUF_QUEUED = 2,
//VIDEOBUF_ACTIVE = 3,
//VIDEOBUF_DONE = 4,
//VIDEOBUF_ERROR = 5,
//VIDEOBUF_IDLE = 6,
//};
//struct videobuf_queue;
//#define VIDEO_MAX_FRAME 16
//struct videobuf_buffer {
//struct list_head stream;
//OS_SEM done;
//u32 baddr;
//u8 state;
//u8 index;
//void *priv_data;
//};
//struct videobuf_queue {
//struct list_head stream;
//struct videobuf_buffer *bufs[VIDEO_MAX_FRAME];
//struct videobuf_buffer *curr;
//struct videobuf_queue_ops *ops;
//OS_SEM sem;
//int msize;
//void *pirv_data;
//u8 streaming;
//};
/*struct video_audio {
u32 capabilities;
};*/
//struct videobuf_queue_ops {
//int (*buf_setup)(struct videobuf_queue *q, int *count);
//int (*buf_prepare)(struct videobuf_queue *q, struct videobuf_buffer *);
//};
/*struct video_ioctl_ops {
int (*vidioc_querycap)(void *fh, struct video_capability *cap);
int (*vidioc_get_fmt_vid_cap)(void *fh, struct video_format *f);
int (*vidioc_get_fmt_vid_out)(void *fh, struct video_format *f);
int (*vidioc_get_fmt_vid_overlay)(void *fh, struct video_format *f);
int (*vidioc_set_fmt_vid_cap)(void *fh, struct video_format *f);
int (*vidioc_set_fmt_vid_out)(void *fh, struct video_format *f);
int (*vidioc_set_fmt_vid_overlay)(void *fh, struct video_format *f);
int (*vidioc_try_fmt_vid_cap)(void *fh, struct video_format *f);
int (*vidioc_try_fmt_vid_out)(void *fh, struct video_format *f);
int (*vidioc_try_fmt_vid_overlay)(void *fh, struct video_format *f);
int (*vidioc_reqbufs)(void *fh, struct video_reqbufs *b);
int (*vidioc_querybuf)(void *fh, struct video_buffer *b);
int (*vidioc_qbuf)(void *fh, struct video_buffer *b);
int (*vidioc_dqbuf)(void *fh, struct video_buffer *b);
int (*vidioc_overlay)(void *fh, unsigned int i);
int (*vidioc_streamon)(void *fh, int i);
int (*vidioc_streamoff)(void *fh, int i);
int (*vidioc_get_audio)(void *fh, struct video_audio *a);
int (*vidioc_set_audio)(void *fh, struct video_audio *a);
};*/
/*struct video_device {
const char *name;
const struct video_ioctl_ops *ioctl;
const struct video_file_operations *fops;
void *priv;
};*/
/*struct video_file_operations {
int (*open)(struct video_device *device);
int (*write)(struct video_device *device, void *buf, u32 len);
int (*close)(struct video_device *device);
};*/
/*struct video_dec_format {
int pixelformat;
};*/
#endif
+295
View File
@@ -0,0 +1,295 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "videobuf.h"
/* #include "video/video_ioctl.h" */
/* #include "system/malloc.h" */
#include "irq.h"
#include "asm/debug.h"
#include "debug.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
void videobuf_queue_init(struct videobuf_queue *q, int align, const char *name)
{
q->ref = 0;
q->buf = NULL;
q->lbuf = NULL;
q->align = align;
q->streaming = 0;
q->name = name;
os_sem_create(&q->sem, 0);
}
void videobuf_queue_release(struct videobuf_queue *q)
{
if (q->buf) {
/* free(q->buf); */
free_psram(q->buf);
q->buf = NULL;
}
}
int videobuf_reqbufs(struct videobuf_queue *q, struct video_reqbufs *req)
{
if (q->lbuf) {
return 0;
}
if (!req->buf) {
/* q->buf = (void *)malloc(req->size); */
q->buf = (void *)malloc_psram(req->size);
if (!q->buf) {
printf("-----------no-mem: size=%x\n", req->size);
return -ENOMEM;
}
req->buf = q->buf;
}
q->lbuf = lbuf_init(req->buf, req->size, q->align, sizeof(struct videobuf_buffer));
return 0;
}
int videobuf_snoop_buf(struct videobuf_queue *q, struct video_buffer *b)
{
printf("\n [ERROR] %s -[no defined] %d\n ", __FUNCTION__, __LINE__);
return 0;
#if 0
int err = 0;
struct videobuf_buffer *buf;
while (1) {
buf = lbuf_snoop(q->lbuf, BIT(b->index));
if (buf) {
if ((q->streaming & BIT(b->index))) {
break;
}
log_info("\n\n\n\n\n\nmmmmmm %x, %x\n\n\n\n\n\n\n\n\n", q->streaming, b->index);
ASSERT(buf && buf->magic == 0x56784321, ", %s, %x, %x, %s, \n", q->name,
(u32)buf, (u32)buf->magic, __func__);
} else {
if (b->noblock) {
b->len = 0;
return 0;
}
if (!(q->streaming & BIT(b->index))) {
b->len = 0;
return -EINVAL;
}
err = os_sem_pend(&q->sem, b->timeout / 10);
if (err != OS_ERR_NONE) {
return err;
}
}
}
ASSERT(buf && buf->magic == 0x56784321, ", %s, %x, %x, %s, \n", q->name,
(u32)buf, (u32)buf->magic, __func__);
b->baddr = (u32)buf->data;
b->len = buf->len;
b->priv = buf;
b->time_msec = buf->msec;
return 0;
#endif
}
int videobuf_dqbuf(struct videobuf_queue *q, struct video_buffer *b)
{
int err = 0;
struct videobuf_buffer *buf;
while (1) {
buf = lbuf_pop(q->lbuf, BIT(b->index));
if (buf) {
if ((q->streaming & BIT(b->index))) {
break;
}
log_info("\n\n\n\n\n\nmmmmmm %x, %x\n\n\n\n\n\n\n\n\n", q->streaming, b->index);
ASSERT(buf && buf->magic == 0x56784321, ", %s, %x, %x, %s, \n", q->name,
(u32)buf, (u32)buf->magic, __func__);
lbuf_free(buf);
} else {
if (b->noblock) {
b->len = 0;
return 0;
}
if (!(q->streaming & BIT(b->index))) {
b->len = 0;
return -EINVAL;
}
err = os_sem_pend(&q->sem, b->timeout / 10);
if (err != OS_ERR_NONE) {
return err;
}
}
}
ASSERT(buf && buf->magic == 0x56784321, ", %s, %x, %x, %s, \n", q->name,
(u32)buf, (u32)buf->magic, __func__);
b->baddr = (u32)buf->data;
b->len = buf->len;
b->priv = buf;
b->time_msec = buf->msec;
return 0;
}
int videobuf_qbuf(struct videobuf_queue *q, struct video_buffer *b)
{
struct videobuf_buffer *buf = (struct videobuf_buffer *)b->priv;
ASSERT(buf && buf->magic == 0x56784321, ", %s, %x, %x, %s, \n", q->name,
(u32)buf, (u32)buf->magic, __func__);
lbuf_free(b->priv);
return 0;
}
int videobuf_streamon(struct videobuf_queue *q, u8 *channel)
{
int i;
struct lbuff_state s;
if (q->streaming == 0) {
//判断之前是否有未释放的buf
ASSERT(lbuf_empty(q->lbuf) == 1, "videobuf not free completed, %s\n", q->name);
lbuf_state(q->lbuf, &s);
if (s.fragment != 1) {
lbuf_dump(q->lbuf);
ASSERT(s.fragment == 1, "videobuf not free completed, %s\n", q->name);
}
} else {
//ASSERT(lbuf_pop(q->lbuf, BIT(channel)) == NULL);
}
for (i = 0; i < 8; i++) {
if (!(q->streaming & BIT(i))) {
*channel = i;
q->streaming |= BIT(i);
return 0;
}
}
return -EFAULT;
}
int videobuf_clear_stream(struct videobuf_queue *q, u8 channel)
{
struct videobuf_buffer *b;
do {
b = lbuf_pop(q->lbuf, BIT(channel));
if (b) {
lbuf_free(b);
}
} while (b);
return 0;
}
int videobuf_streamoff(struct videobuf_queue *q, u8 channel)
{
struct videobuf_buffer *b;
q->streaming &= ~BIT(channel);
videobuf_clear_stream(q, channel);
os_sem_post(&q->sem);
return 0;
}
struct videobuf_buffer *videobuf_stream_alloc(struct videobuf_queue *q, u32 size)
{
struct videobuf_buffer *b;
ASSERT(q->lbuf, "%s\n", q->name);
b = lbuf_alloc(q->lbuf, size);
if (b) {
b->magic = 0x56784321;
}
return b;
}
u32 videobuf_stream_free_space(struct videobuf_queue *q)
{
ASSERT(q->lbuf, "%s\n", q->name);
return lbuf_free_space(q->lbuf);
}
struct videobuf_buffer *videobuf_stream_realloc(struct videobuf_queue *q,
struct videobuf_buffer *b, int size)
{
ASSERT(b && b->magic == 0x56784321, "%s, %x, %x, %s\n", q->name, (u32)b,
(u32)b->magic, __func__);
return lbuf_realloc(b, size);
}
void videobuf_stream_free(struct videobuf_queue *q, struct videobuf_buffer *b)
{
ASSERT(b && b->magic == 0x56784321, "%s, %x, %x, %s\n", q->name, (u32)b,
(u32)b->magic, __func__);
lbuf_free(b);
}
int videobuf_stream_finish(struct videobuf_queue *q, struct videobuf_buffer *b)
{
ASSERT(b && b->magic == 0x56784321, "%s, %x, %x, %s\n", q->name, (u32)b,
(u32)b->magic, __func__);
if (q->streaming == 0) {
/* log_i("\n\n\n\n\n\ntttt %x, %s\n\n\n\n\n\n\n\n\n", q->streaming, q->name); */
lbuf_free(b);
return -EINVAL;
}
lbuf_push(b, q->streaming);
os_sem_set(&q->sem, 0);
os_sem_post(&q->sem);
return 0;
}
int videobuf_query(struct videobuf_queue *q, struct videobuf_state *sta)
{
struct lbuff_state lbuf_sta;
if (sta) {
lbuf_state(q->lbuf, &lbuf_sta);
sta->available_len = lbuf_sta.avaliable;
sta->max_continue_len = lbuf_sta.max_continue_len;
}
return lbuf_traversal(q->lbuf);
}
@@ -0,0 +1,59 @@
#ifndef VIDEOBUF_H
#define VIDEOBUF_H
#include "typedef.h"
#include "generic/list.h"
#include "generic/ioctl.h"
#include "generic/lbuf.h"
#include "video_ioctl.h"
#include "video.h"
void videobuf_queue_init(struct videobuf_queue *q, int align, const char *name);
int videobuf_reqbufs(struct videobuf_queue *q, struct video_reqbufs *req);
int videobuf_snoop_buf(struct videobuf_queue *q, struct video_buffer *b);
int videobuf_dqbuf(struct videobuf_queue *q, struct video_buffer *b);
int videobuf_qbuf(struct videobuf_queue *q, struct video_buffer *b);
int videobuf_streamon(struct videobuf_queue *q, u8 *channel);
int videobuf_streamoff(struct videobuf_queue *q, u8 channel);
int videobuf_clear_stream(struct videobuf_queue *q, u8 channel);
struct videobuf_buffer *videobuf_stream_alloc(struct videobuf_queue *q, u32 size);
struct videobuf_buffer *videobuf_stream_realloc(struct videobuf_queue *q,
struct videobuf_buffer *b, int size);
u32 videobuf_stream_free_space(struct videobuf_queue *q);
void videobuf_stream_free(struct videobuf_queue *q, struct videobuf_buffer *b);
int videobuf_stream_finish(struct videobuf_queue *q, struct videobuf_buffer *b);
int videobuf_query(struct videobuf_queue *q, struct videobuf_state *sta);
void videobuf_queue_release(struct videobuf_queue *q);
#endif
+204
View File
@@ -0,0 +1,204 @@
#ifndef __USB_COMMON_DEFINE_H__
#define __USB_COMMON_DEFINE_H__
///<<<注意此文件不要放函数声明, 只允许宏定义, 并且差异化定义可以根据需求在对应板卡中重新定义, 除非新增,否则不要直接修改这里
///<<<注意此文件不要放函数声明, 只允许宏定义, 并且差异化定义可以根据需求在对应板卡中重新定义, 除非新增,否则不要直接修改这里
///<<<注意此文件不要放函数声明, 只允许宏定义, 并且差异化定义可以根据需求在对应板卡中重新定义, 除非新增,否则不要直接修改这里
//
/// board文件没有定义的宏,在这里定义,防止编译报warning
#ifndef TCFG_PC_ENABLE
#define TCFG_PC_ENABLE 0
#endif
#ifndef TCFG_USB_HOST_ENABLE
#define TCFG_USB_HOST_ENABLE 0
#endif
#ifndef TCFG_OTG_USB_DEV_EN
#define TCFG_OTG_USB_DEV_EN 0b01//USB0 = BIT(0) USB1 = BIT(1)
#endif
#ifndef TCFG_USB_APPLE_DOCK_EN
#define TCFG_USB_APPLE_DOCK_EN 0
#endif
#ifndef TCFG_CHARGE_ENABLE
#define TCFG_CHARGE_ENABLE 0
#endif
#ifndef TCFG_USB_PORT_CHARGE
#define TCFG_USB_PORT_CHARGE 0
#endif
#ifndef TCFG_USB_MIC_ECHO_ENABLE
#define TCFG_USB_MIC_ECHO_ENABLE 0
#endif
#ifndef TCFG_USB_MIC_DATA_FROM_MICEFFECT
#define TCFG_USB_MIC_DATA_FROM_MICEFFECT 0
#endif
#ifndef TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
#define TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0 0
#endif
#ifndef TCFG_ONLY_PC_ENABLE //只有pc模式
#define TCFG_ONLY_PC_ENABLE 0
#endif
#ifndef TCFG_TYPE_C_ENABLE //应用于type-c场景
#define TCFG_TYPE_C_ENABLE 0
#endif
#ifndef TCFG_USB_CDC_BACKGROUND_RUN
#define TCFG_USB_CDC_BACKGROUND_RUN 0
#endif
#ifndef TCFG_FUSB_PLL_TRIM
#define TCFG_FUSB_PLL_TRIM 0
#endif
#ifndef USB_MEM_USE_OVERLAY
#define USB_MEM_USE_OVERLAY 0
#endif
#ifndef USB_EPBUF_ALLOC_USE_LBUF
#define USB_EPBUF_ALLOC_USE_LBUF 0
#endif
#ifndef USB_ROOT2
#define USB_ROOT2 0
#endif
#ifndef USB_MALLOC_ENABLE
#define USB_MALLOC_ENABLE 0
#endif
#ifndef USB_HOST_ASYNC
#define USB_HOST_ASYNC 1
#endif
#ifndef USB_H_MALLOC_ENABLE
#define USB_H_MALLOC_ENABLE 1
#endif
#define OTG_HOST_MODE 0x0001
#define OTG_SLAVE_MODE 0x0002
#define OTG_CHARGE_MODE 0x0004
#define OTG_DET_DP_ONLY 0x0008
#define OTG_DM_MULTI_EN 0x0010
/********************************/
#if TCFG_CHARGE_ENABLE && TCFG_USB_PORT_CHARGE
#define TCFG_OTG_MODE_CHARGE (OTG_CHARGE_MODE)
#else
#define TCFG_OTG_MODE_CHARGE 0
#endif
#if (TCFG_PC_ENABLE)
#define TCFG_PC_UPDATE 1
#define TCFG_OTG_MODE_SLAVE (OTG_SLAVE_MODE)
#else
#define TCFG_PC_UPDATE 0
#define TCFG_OTG_MODE_SLAVE 0
#endif
#if (TCFG_USB_HOST_ENABLE)
#define TCFG_OTG_MODE_HOST (OTG_HOST_MODE)
#else
#define TCFG_OTG_MODE_HOST 0
#endif
#if TCFG_USB_HOST_ENABLE
#ifndef TCFG_USB_HOST_MOUNT_RETRY
#define TCFG_USB_HOST_MOUNT_RETRY 3
#endif
#ifndef TCFG_USB_HOST_MOUNT_RESET
#define TCFG_USB_HOST_MOUNT_RESET 40
#endif
#ifndef TCFG_USB_HOST_MOUNT_TIMEOUT
#define TCFG_USB_HOST_MOUNT_TIMEOUT 50
#endif
#ifndef TCFG_UDISK_ENABLE
#define TCFG_UDISK_ENABLE 1
#endif
#ifndef TCFG_HOST_AUDIO_ENABLE
#define TCFG_HOST_AUDIO_ENABLE 0
#endif
#ifndef TCFG_HID_HOST_ENABLE
#define TCFG_HID_HOST_ENABLE 0
#endif
#ifndef TCFG_AOA_ENABLE
#define TCFG_AOA_ENABLE 0
#endif
#ifndef TCFG_ADB_ENABLE
#define TCFG_ADB_ENABLE 0
#endif
#else
#undef TCFG_UDISK_ENABLE
#define TCFG_UDISK_ENABLE 0
#undef TCFG_HOST_AUDIO_ENABLE
#define TCFG_HOST_AUDIO_ENABLE 0
#undef TCFG_HID_HOST_ENABLE
#define TCFG_HID_HOST_ENABLE 0
#undef TCFG_AOA_ENABLE
#define TCFG_AOA_ENABLE 0
#undef TCFG_ADB_ENABLE
#define TCFG_ADB_ENABLE 0
#endif
#if TCFG_PC_ENABLE
#define TCFG_USB_SLAVE_ENABLE 1
#ifndef TCFG_USB_SLAVE_MSD_ENABLE
#define TCFG_USB_SLAVE_MSD_ENABLE 1
#endif
#ifndef TCFG_USB_SLAVE_AUDIO_SPK_ENABLE
#define TCFG_USB_SLAVE_AUDIO_SPK_ENABLE 0
#endif
#ifndef TCFG_USB_SLAVE_AUDIO_MIC_ENABLE
#define TCFG_USB_SLAVE_AUDIO_MIC_ENABLE 0
#endif
#ifndef TCFG_USB_SLAVE_HID_ENABLE
#define TCFG_USB_SLAVE_HID_ENABLE 0
#endif
#ifndef TCFG_USB_SLAVE_CDC_ENABLE
#define TCFG_USB_SLAVE_CDC_ENABLE 0
#endif
#ifndef TCFG_USB_CUSTOM_HID_ENABLE
#define TCFG_USB_CUSTOM_HID_ENABLE 0
#endif
#else /* TCFG_PC_ENABLE == 0*/
#define TCFG_USB_SLAVE_ENABLE 0
#undef TCFG_USB_SLAVE_MSD_ENABLE
#define TCFG_USB_SLAVE_MSD_ENABLE 0
#undef TCFG_USB_SLAVE_AUDIO_SPK_ENABLE
#define TCFG_USB_SLAVE_AUDIO_SPK_ENABLE 0
#undef TCFG_USB_SLAVE_AUDIO_MIC_ENABLE
#define TCFG_USB_SLAVE_AUDIO_MIC_ENABLE 0
#undef TCFG_USB_SLAVE_HID_ENABLE
#define TCFG_USB_SLAVE_HID_ENABLE 0
#undef TCFG_USB_SLAVE_CDC_ENABLE
#define TCFG_USB_SLAVE_CDC_ENABLE 0
#undef TCFG_USB_CUSTOM_HID_ENABLE
#define TCFG_USB_CUSTOM_HID_ENABLE 0
#endif
#define TCFG_OTG_SLAVE_ONLINE_CNT 3
#define TCFG_OTG_SLAVE_OFFLINE_CNT 2
#define TCFG_OTG_HOST_ONLINE_CNT 2
#define TCFG_OTG_HOST_OFFLINE_CNT 3
#ifndef TCFG_OTG_MODE
#define TCFG_OTG_MODE (TCFG_OTG_MODE_HOST|TCFG_OTG_MODE_SLAVE|TCFG_OTG_MODE_CHARGE)
#endif
#define TCFG_OTG_DET_INTERVAL 250
#if (TCFG_USB_CDC_BACKGROUND_RUN)
#undef TCFG_USB_SLAVE_CDC_ENABLE
#define TCFG_USB_SLAVE_CDC_ENABLE 1
#undef TCFG_USB_SLAVE_ENABLE
#define TCFG_USB_SLAVE_ENABLE 1
#if ((TCFG_OTG_MODE & OTG_SLAVE_MODE) == 0)
#undef TCFG_OTG_MODE
#define TCFG_OTG_MODE (TCFG_OTG_MODE_HOST|OTG_SLAVE_MODE|TCFG_OTG_MODE_CHARGE)
#endif
#endif
#endif
+369
View File
@@ -0,0 +1,369 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "usb_config.h"
#include "usb/scsi.h"
#include "irq.h"
#include "init.h"
#include "gpio.h"
#include "timer.h"
#include "app_config.h"
#include "lbuf.h"
#ifdef CONFIG_ADAPTER_ENABLE
#include "adapter_usb_hid.h"
#endif//CONFIG_ADAPTER_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"
#define SET_INTERRUPT ___interrupt
#define MAX_EP_TX 5
#define MAX_EP_RX 5
static usb_interrupt usb_interrupt_tx[USB_MAX_HW_NUM][MAX_EP_TX];
static usb_interrupt usb_interrupt_rx[USB_MAX_HW_NUM][MAX_EP_RX];
struct usb_config_var_t {
u8 usb_setup_buffer[USB_SETUP_SIZE];
struct usb_ep_addr_t usb_ep_addr;
struct usb_setup_t usb_setup;
};
static struct usb_config_var_t *usb_config_var = {NULL};
#if USB_MALLOC_ENABLE
#else
static struct usb_config_var_t _usb_config_var SEC(.usb.data.bss.exchange);
#endif
extern void *usb_epbuf_alloc(const usb_dev usb_id, u32 ep, u32 size);
extern void usb_epbuf_free(const usb_dev usb_id, void *buf);
__attribute__((always_inline_when_const_args))
void *usb_alloc_ep_dmabuffer(const usb_dev usb_id, u32 ep, u32 dma_size)
{
u8 *ep_buffer = NULL;
//传进去的ep统一映射成bit7为1是rx,方便主从机共用函数
ep_buffer = usb_epbuf_alloc(usb_id, ep ^ USB_DIR_IN, dma_size);
ASSERT(ep_buffer, "%s() ep_buffer = NULL!!!, usb_id = %d, ep = %x, dma_size = %d\n", __func__, usb_id, ep, dma_size);
log_info("usb%d slave, ep = %x, dma_size = %d, ep_buffer = %x\n", usb_id, ep, dma_size, (u32)ep_buffer);
return ep_buffer;
}
void usb_free_ep_dmabuffer(const usb_dev usb_id, void *buf)
{
usb_epbuf_free(usb_id, buf);
log_info("usb%d slave free ep buffer %x\n", usb_id, (u32)buf);
}
static u8 sleep_flag = 0;
u8 get_sleep_flag()
{
return sleep_flag ;
}
void set_sleep_flag(u8 sl_flag)
{
sleep_flag = sl_flag ;
}
static void usb_resume_sign(void *priv)
{
usb_dev usb_id = usb_device2id(priv);
u32 reg = usb_read_power(usb_id);
usb_write_power(usb_id, reg | BIT(2));//send resume
os_time_dly(2);//10ms~20ms
usb_write_power(usb_id, reg);//clean resume
}
static u8 usb_remote_wakeup_flag = USB_READY;//0:初始状态或suspend 1:从机已发送wakeup 2:主机已被唤醒
static u32 usb_remote_wakeup_cnt = 0;
void usb_remote_wakeup_detect(void *priv)
{
if (usb_remote_wakeup_cnt == 0) {
usb_remote_wakeup_flag = USB_SUSPEND;
log_info("Wakeup fail!!! no SOF packet receive!\n");
}
if (usb_remote_wakeup_cnt > USB_REMOTE_WAKEUP_TIMEOUT_DETECT_TIMES - 200) {
usb_remote_wakeup_flag = USB_READY;
log_info("Receive %d SOF packet, USB ready!\n", usb_remote_wakeup_cnt);
} else {
usb_remote_wakeup_flag = USB_RESUME_WAIT;
log_info("Receive %d SOF packet, please increase USB_REMOTE_WAKEUP_TIMEOUT_DETECT_TIMES\n", usb_remote_wakeup_cnt);
}
}
void usb_remote_wakeup(const usb_dev usb_id)
{
struct usb_device_t *usb_device = usb_id2device(usb_id);
if (usb_device->bRemoteWakup) {
sys_timeout_add(usb_device, usb_resume_sign, 1);
}
usb_remote_wakeup_flag = USB_RESUME_WAIT;
usb_remote_wakeup_cnt = 0;
log_info("slave remote_wakeup host signal has been sent");
usb_sof_isr_reg(usb_id, 3, 0);
sys_timeout_add(usb_device, usb_remote_wakeup_detect, USB_REMOTE_WAKEUP_TIMEOUT_DETECT_TIMES);
}
void usb_phy_resume(const usb_dev usb_id)
{
usb_iomode(0);
struct usb_device_t *usb_device = usb_id2device(usb_id);
usb_write_faddr(usb_id, usb_device->baddr);
if (usb_device->baddr == 0) {
usb_device->bDeviceStates = USB_DEFAULT;
} else {
usb_device->bDeviceStates = USB_CONFIGURED;
}
usb_otg_resume(usb_id);
}
void usb_phy_suspend(const usb_dev usb_id)
{
gpio_set_mode(PORTUSB, PORT_PIN_0, PORT_INPUT_PULLUP_10K); //dp
/* musb_read_usb(0, MUSB_INTRUSB); */
usb_otg_suspend(usb_id, OTG_KEEP_STATE);
}
u32 usb_get_suspend_resume_status(const usb_dev usb_id)
{
switch (usb_remote_wakeup_flag) {
case USB_READY:
//log_info("USB READY\n");
putchar('R');
break;
case USB_SUSPEND:
log_info("USB SUSPEND\n");
break;
case USB_RESUME_WAIT:
log_info("USB remote_wakeup send, RESUME WAIT\n");
break;
case USB_RESUME_OK://保留状态,未使用
log_info("USB RESUME OK\n");
break;
default:
break;
}
return usb_remote_wakeup_flag;
}
void usb_isr(const usb_dev usb_id)
{
u32 intr_usb, intr_usbe;
u32 intr_tx, intr_txe;
u32 intr_rx, intr_rxe;
/* __asm__ volatile("ssync"); */
usb_read_intr(usb_id, &intr_usb, &intr_tx, &intr_rx);
usb_read_intre(usb_id, &intr_usbe, &intr_txe, &intr_rxe);
struct usb_device_t *usb_device = usb_id2device(usb_id);
intr_usb &= intr_usbe;
intr_tx &= intr_txe;
intr_rx &= intr_rxe;
if (intr_usb & INTRUSB_SUSPEND) {
log_error("usb suspend");
usb_remote_wakeup_flag = USB_SUSPEND;
set_sleep_flag(1);
#if USB_SUSPEND_RESUME
usb_phy_suspend(usb_id);
#endif
#if USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP
printf("\n NULL \n");
#endif
}
if (intr_usb & INTRUSB_RESET_BABBLE) {
log_error("usb reset");
usb_reset_interface(usb_device);
#if TCFG_FUSB_PLL_TRIM
log_info("FUSB_PLL_AUTO_TRIM RUN\n");
/* fusb_pll_trim(USB_TRIM_HAND, 10); */
fusb_pll_trim(USB_TRIM_AUTO, 10);
#endif
#if USB_SUSPEND_RESUME || USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP
u32 reg = usb_read_power(usb_id);
usb_write_power(usb_id, (reg | INTRUSB_SUSPEND | INTRUSB_RESUME));//enable suspend resume
#endif
}
if (intr_usb & INTRUSB_RESUME) {
log_error("usb resume");
#if USB_SUSPEND_RESUME
usb_phy_resume(usb_id);
#endif
}
if (intr_tx & BIT(0)) {
if (usb_interrupt_rx[usb_id][0]) {
usb_interrupt_rx[usb_id][0](usb_device, 0);
} else {
#if USB_SUSPEND_RESUME || USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP
if (usb_remote_wakeup_flag == USB_RESUME_WAIT) {
if (usb_device->bsetup_phase == USB_EP0_STAGE_SETUP) {
usb_remote_wakeup_flag = USB_READY;
log_info("receive setup packet");
}
}
#endif
usb_control_transfer(usb_device);
}
}
for (int i = 1; i < MAX_EP_TX; i++) {
if (intr_tx & BIT(i)) {
if (usb_interrupt_tx[usb_id][i]) {
usb_interrupt_tx[usb_id][i](usb_device, i);
}
}
}
for (int i = 1; i < MAX_EP_RX; i++) {
if (intr_rx & BIT(i)) {
if (usb_interrupt_rx[usb_id][i]) {
usb_interrupt_rx[usb_id][i](usb_device, i);
}
}
}
__asm__ volatile("csync");
}
void usb_sof_isr(const usb_dev usb_id)
{
usb_sof_clr_pnd(usb_id);
static u32 sof_count = 0;
#if USB_SUSPEND_RESUME || USB_SUSPEND_RESUME_SYSTEM_NO_SLEEP
usb_remote_wakeup_cnt++;
#else
if ((sof_count++ % 1000) == 0) {
log_d("sof 1s isr frame:%d", usb_read_sofframe(usb_id));
}
#endif
}
void usb_suspend_check(void *p)
{
usb_dev usb_id = (usb_dev)p;
static u16 sof_frame = 0;
u16 frame = usb_read_sofframe(usb_id);// sof frame 不更新,则usb进入断开或者suspend状态
if (frame == sof_frame) {
usb_phy_suspend(usb_id);
}
sof_frame = frame;
}
SET_INTERRUPT
void usb0_g_isr()
{
usb_isr(0);
}
SET_INTERRUPT
void usb0_sof_isr()
{
usb_sof_isr(0);
}
#if USB_MAX_HW_NUM == 2
SET_INTERRUPT
void usb1_g_isr()
{
usb_isr(1);
}
SET_INTERRUPT
void usb1_sof_isr()
{
usb_sof_isr(1);
}
#endif
__attribute__((always_inline_when_const_args))
u32 usb_g_set_intr_hander(const usb_dev usb_id, u32 ep, usb_interrupt hander)
{
if (ep & USB_DIR_IN) {
usb_interrupt_tx[usb_id][ep & 0xf] = hander;
} else {
usb_interrupt_rx[usb_id][ep] = hander;
}
return 0;
}
void usb_g_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id)
{
if (usb_id == 0) {
request_irq(IRQ_USB_CTRL_IDX, priority, usb0_g_isr, cpu_id);
} else {
#if USB_MAX_HW_NUM == 2
request_irq(IRQ_USB1_CTRL_IDX, priority, usb1_g_isr, cpu_id);
#endif
}
}
void usb_sof_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id)
{
if (usb_id == 0) {
request_irq(IRQ_USB_SOF_IDX, priority, usb0_sof_isr, cpu_id);
} else {
#if USB_MAX_HW_NUM == 2
request_irq(IRQ_USB1_SOF_IDX, priority, usb1_sof_isr, cpu_id);
#endif
}
usb_sofie_enable(usb_id);
}
u32 usb_config(const usb_dev usb_id)
{
memset(usb_interrupt_rx[usb_id], 0, sizeof(usb_interrupt_rx[usb_id]));
memset(usb_interrupt_tx[usb_id], 0, sizeof(usb_interrupt_tx[usb_id]));
if (!usb_config_var) {
#if USB_MALLOC_ENABLE
usb_config_var = (struct usb_config_var_t *)zalloc(sizeof(struct usb_config_var_t));
if (!usb_config_var) {
return -1;
}
#else
memset(&_usb_config_var, 0, sizeof(_usb_config_var));
usb_config_var = &_usb_config_var;
#endif
}
log_debug("zalloc: usb_config_var = %x\n", usb_config_var);
usb_var_init(usb_id, &(usb_config_var->usb_ep_addr));
usb_setup_init(usb_id, &(usb_config_var->usb_setup), usb_config_var->usb_setup_buffer);
return 0;
}
u32 usb_release(const usb_dev usb_id)
{
log_debug("free zalloc: usb_config_var = %x\n", usb_id, usb_config_var);
usb_var_init(usb_id, NULL);
usb_setup_init(usb_id, NULL, NULL);
#if USB_MALLOC_ENABLE
if (usb_config_var) {
log_debug("free: usb_config_var = %x\n", usb_config_var);
free(usb_config_var);
}
#endif
usb_config_var = NULL;
return 0;
}
+158
View File
@@ -0,0 +1,158 @@
/**@file usb_config.h
* @brief usb_config配置头文件
* @details
* @author jieli
* @date 2021-8-1
* @version V1.0
* @copyright Copyright(c)2010-2021
*********************************************************
* @attention
* AC695N
* SDK版本AC695N_V1.0.0_SDK
* @
* <table>
* <tr><th>Date <th>Version <th>Author <th>Description
* <tr><td>2021-8-1 <td>1.0 <td>jieli <td>
* </table>
*
*********************************************************
*/
#ifndef __USB_CONFIG_H__
#define __USB_CONFIG_H__
#include "typedef.h"
#include "usb/usb.h"
#include "usb/device/usb_stack.h"
#include "usb/host/usb_host.h"
/**@brief USB主机模式配置
* @param[in] usb_id USB的id号
* @return
* @par
* @code
* usb_host_config(usb_id);
* @encode
*/
void usb_host_config(usb_dev usb_id);
/**@brief USB主机模式释放
* @param[in] usb_id USB的id号
* @return
* @par
* @code
* usb_host_free(usb_id);
* @encode
*/
void usb_host_free(usb_dev usb_id);
/**@brief USB主机模式分配端点DMA BUFFER
* @param[in] usb_id USB的id号
* @param[in] ep
* @param[in] dma_size
* @return dma buffer
* @par
* @code
* usb_h_alloc_ep_buffer(usb_id , ep, 16);
* @encode
*/
void *usb_h_alloc_ep_buffer(const usb_dev usb_id, u32 ep, u32 dma_size);
/**@brief USB主机模式释放端点的DMA BUFFER
* @param[in] usb_id USB的id号
* @param[in] buf buffer
* @return
* @par
* @code
* usb_h_free_ep_buffer(usb_id , buf);
* @encode
*/
void usb_h_free_ep_buffer(const usb_dev usb_id, void *buf);
/**@brief USB主机模式中断注册
* @param[in] usb_id USB的id号
* @param[in] priority
* @param[in] cpu_id cpu的id号
* @return
* @par
* @code
* usb_h_isr_reg(usb_id , ep);
* @encode
*/
void usb_h_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id);
/**@brief USB从机模式中断注册
* @param[in] usb_id USB的id号
* @param[in] priority
* @param[in] cpu_id cpu的id号
* @return
* @par
* @code
* usb_g_isr_reg(usb_id , ep);
* @encode
*/
void usb_g_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id);
/**@brief USB SOF中断注册
* @param[in] usb_id USB的id号
* @param[in] priority
* @param[in] cpu_id cpu的id号
* @return
* @par
* @code
* usb_sof_isr_reg(usb_id , ep);
* @encode
*/
void usb_sof_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id);
/**@brief 分配端点的DMA BUFFER
* @param[in] usb_id USB的id号
* @param[in] ep
* @param[in] dma_size
* @return dma buffer
* @par
* @code
* usb_alloc_ep_dmabuffer(usb_id , ep , size);
* @encode
*/
void *usb_alloc_ep_dmabuffer(const usb_dev usb_id, u32 ep, u32 dma_size);
/**@brief 释放端点的DMA BUFFER
* @param[in] usb_id USB的id号
* @param[in] buf buffer
* @return
* @par
* @code
* usb_free_ep_dmabuffer(usb_id, buf);
* @encode
*/
void usb_free_ep_dmabuffer(const usb_dev usb_id, void *buf);
/**@brief USB从机初始化配置
* @param[in] usb_id USB的id号
* @return 0:
* @par
* @code
* usb_config(usb_id);
* @encode
*/
u32 usb_config(const usb_dev usb_id);
/**@brief USB从机释放
* @param[in] usb_id USB的id号
* @return 0:
* @par
* @code
* usb_release(usb_id);
* @encode
*/
u32 usb_release(const usb_dev usb_id);
void usb_phy_resume(const usb_dev usb_id);
void usb_phy_suspend(const usb_dev usb_id);
u32 usb_get_suspend_resume_status(const usb_dev usb_id);//返回0:失败 返回1:成功
#endif /*USB_CONFIG_H*/
@@ -0,0 +1,194 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "usb_config.h"
#include "init.h"
#include "app_config.h"
#include "lbuf.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_HOST_ENABLE || TCFG_USB_SLAVE_ENABLE
#ifndef USB_HW_20
#if (FUSB_MODE == 0)
#error "USB1.1 IP is not support high-speed mode"
#endif
#endif
#define USB_DMA_BUF_ALIGN (8)
//附加的字节数用于ep rx接收crc(占用4字节,dual buf则8字节)以及分配lbuf头信息
//占用。lbuf头结构体20字节,假设需要8对齐,需要占用24字节,另外分配出来的头+buf
//总长度也需要8对齐,in/out ep各调用1次所以要留2份。
#define TO_ALIGN(size, align) (((size) & ((align) - 1)) ? ((align) - ((size) & ((align) - 1))) : 0)
#define _APPEND(size, align, eps) ((size) + TO_ALIGN(size, align) + 24 * (eps) + 8)
#define APPEND(size, eps) _APPEND(size, USB_DMA_BUF_ALIGN, eps)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~ usb slave begin ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#if TCFG_USB_SLAVE_MSD_ENABLE
#define MSD_DMA_SIZE APPEND(MAXP_SIZE_BULKOUT * 2, 1)
#else
#define MSD_DMA_SIZE 0
#endif
#if TCFG_USB_SLAVE_HID_ENABLE
#define HID_DMA_SIZE APPEND(64, 2)
#else
#define HID_DMA_SIZE 0
#endif
#if TCFG_USB_CUSTOM_HID_ENABLE
#define CUSTOM_HID_DMA_SIZE APPEND(64 * 2, 2)
#else
#define CUSTOM_HID_DMA_SIZE 0
#endif
#if TCFG_USB_SLAVE_AUDIO_SPK_ENABLE
#if USB_EP_PROTECT
#define AUDIO_SPK_DMA_SIZE APPEND(1024, 1)
#else
#define AUDIO_SPK_DMA_SIZE APPEND(192, 1)
#endif
#else
#define AUDIO_SPK_DMA_SIZE 0
#endif
#if TCFG_USB_SLAVE_AUDIO_MIC_ENABLE
#define AUDIO_MIC_DMA_SIZE APPEND(192, 1)
#else
#define AUDIO_MIC_DMA_SIZE 0
#endif
#if TCFG_USB_SLAVE_CDC_ENABLE
#if CDC_INTR_EP_ENABLE
#define CDC_DMA_SIZE APPEND(64 * 4, 3) //bulk: 64x2+64 + intr: 64
#else
#define CDC_DMA_SIZE APPEND(64 * 3, 2) //bulk: 64x2+64
#endif
#else
#define CDC_DMA_SIZE 0
#endif
#define USB_DEVICE_DMA_BUF_MAX_SIZE (HID_DMA_SIZE + AUDIO_SPK_DMA_SIZE + AUDIO_MIC_DMA_SIZE + MSD_DMA_SIZE + CDC_DMA_SIZE + CUSTOM_HID_DMA_SIZE)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~ usb slave end ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~ usb host begin ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#if TCFG_UDISK_ENABLE
#define H_MSD_DMA_SIZE APPEND(MAXP_SIZE_BULKOUT * 2 + MAXP_SIZE_BULKIN, 2)
#else
#define H_MSD_DMA_SIZE 0
#endif
#if TCFG_HID_HOST_ENABLE
#define H_HID_DMA_SIZE APPEND(64, 1)
#else
#define H_HID_DMA_SIZE 0
#endif
#if TCFG_AOA_ENABLE
#define H_AOA_DMA_SIZE APPEND(64 + 64, 2)
#else
#define H_AOA_DMA_SIZE 0
#endif
#if TCFG_ADB_ENABLE
#define H_ADB_DMA_SIZE APPEND(64 + 64, 2)
#else
#define H_ADB_DMA_SIZE 0
#endif
#if TCFG_HOST_AUDIO_ENABLE
#define H_AUDIO_DMA_SIZE APPEND(192 + 192, 2)
#else
#define H_AUDIO_DMA_SIZE 0
#endif
#define USB_HOST_DMA_BUF_MAX_SIZE (H_MSD_DMA_SIZE + H_HID_DMA_SIZE + H_AOA_DMA_SIZE + H_ADB_DMA_SIZE + H_AUDIO_DMA_SIZE)
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~ usb host end ~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
#ifndef USB_DMA_BUF_MAX_SIZE
#if (USB_DEVICE_DMA_BUF_MAX_SIZE >= USB_HOST_DMA_BUF_MAX_SIZE)
#define USB_DMA_BUF_MAX_SIZE USB_DEVICE_DMA_BUF_MAX_SIZE
#else
#define USB_DMA_BUF_MAX_SIZE USB_HOST_DMA_BUF_MAX_SIZE
#endif
#endif//USB_DMA_BUF_MAX_SIZE
static u8 ep0_dma_buffer[USB_MAX_HW_NUM][64 + 4] __attribute__((aligned(4)));
#if USB_EPBUF_ALLOC_USE_LBUF
//除了lbuf分配的每份buf之和,还有留一些给lbuf自身
static u8 usb_dma_buf[USB_DMA_BUF_MAX_SIZE + 48] SEC(.usb.data.bss.exchange) __attribute__((aligned(USB_DMA_BUF_ALIGN)));
struct lbuff_head *usb_dma_lbuf = NULL;
int usb_memory_init(void)
{
usb_dma_lbuf = lbuf_init(usb_dma_buf, sizeof(usb_dma_buf), USB_DMA_BUF_ALIGN, 0);
log_info("%s() total dma size %d @%x", __func__, sizeof(usb_dma_buf), usb_dma_buf);
return 0;
}
//early_initcall(usb_memory_init);
void *usb_epbuf_alloc(const usb_dev usb_id, u32 ep, u32 size)
{
if ((ep & 0xf) == 0) {
return ep0_dma_buffer[usb_id];
}
if (ep & USB_DIR_IN) {
size += 8; //fusb的rx,需要额外4字节存放接收的crc,使用ping-pong buffer就需要两份,即4 x 2
}
return lbuf_alloc(usb_dma_lbuf, size);
}
void usb_epbuf_free(const usb_dev usb_id, void *buf)
{
if (buf == ep0_dma_buffer[usb_id]) {
return;
}
lbuf_free(buf);
}
#else /* USB_EPBUF_ALLOC_USE_LBUF */
void *usb_epbuf_alloc(const usb_dev usb_id, u32 ep, u32 size)
{
if ((ep & 0xf) == 0) {
return ep0_dma_buffer[usb_id];
}
if (ep & USB_DIR_IN) {
size += 8; //fusb的rx,需要额外4字节存放接收的crc,使用ping-pong buffer就需要两份,即4 x 2
}
return dma_malloc(size);
}
void usb_epbuf_free(const usb_dev usb_id, void *buf)
{
if (buf == ep0_dma_buffer[usb_id]) {
return;
}
dma_free(buf);
}
#endif
#endif
@@ -0,0 +1,225 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "usb_config.h"
#include "usb/scsi.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"
#define SET_INTERRUPT ___interrupt
#if TCFG_USB_HOST_ENABLE
#if TCFG_HID_HOST_ENABLE
#define MAX_HOST_EP_RX 5
#define MAX_HOST_EP_TX 5
#else
#define MAX_HOST_EP_RX 2
#define MAX_HOST_EP_TX 2 //ep0 & ep1(msd)
#endif
struct host_var_t {
struct usb_ep_addr_t host_ep_addr ;
usb_h_interrupt usb_h_interrupt_rx[MAX_HOST_EP_RX] ;
usb_h_interrupt usb_h_interrupt_tx[MAX_HOST_EP_TX] ;
struct usb_host_device *dev_at_ep[MAX_HOST_EP_RX];
};
static struct host_var_t *host_var[USB_MAX_HW_NUM];// SEC(.usb_h_bss);
static struct host_var_t __host_var[USB_MAX_HW_NUM];
void usb_h_isr(const usb_dev usb_id)
{
u32 intr_usb, intr_usbe;
u32 intr_tx, intr_txe;
u32 intr_rx, intr_rxe;
/* __asm__ volatile("ssync"); */
usb_read_intr(usb_id, &intr_usb, &intr_tx, &intr_rx);
usb_read_intre(usb_id, &intr_usbe, &intr_txe, &intr_rxe);
struct usb_host_device *host_dev = NULL;
/* r_printf("usb_h_isr %x %x %x %x",host_dev,intr_usb,intr_tx,intr_rx); */
intr_usb &= intr_usbe;
intr_tx &= intr_txe;
intr_rx &= intr_rxe;
if (intr_usb & INTRUSB_SUSPEND) {
log_error("usb suspend");
}
if (intr_usb & INTRUSB_RESET_BABBLE) {
log_error("usb reset");
}
if (intr_usb & INTRUSB_RESUME) {
log_error("usb resume");
}
if (intr_tx & BIT(0)) {
if (host_var[usb_id]->usb_h_interrupt_tx[0]) {
host_dev = host_var[usb_id]->dev_at_ep[0];
host_var[usb_id]->usb_h_interrupt_tx[0](host_dev, 0);
}
}
for (int i = 1; i < MAX_HOST_EP_TX; i++) {
if (intr_tx & BIT(i)) {
if (host_var[usb_id]->usb_h_interrupt_tx[i]) {
host_dev = host_var[usb_id]->dev_at_ep[i];
host_var[usb_id]->usb_h_interrupt_tx[i](host_dev, i);
}
}
}
for (int i = 1; i < MAX_HOST_EP_RX; i++) {
if (intr_rx & BIT(i)) {
if (host_var[usb_id]->usb_h_interrupt_rx[i]) {
host_dev = host_var[usb_id]->dev_at_ep[i];
host_var[usb_id]->usb_h_interrupt_rx[i](host_dev, i);
}
}
}
__asm__ volatile("csync");
}
SET_INTERRUPT
void usb0_h_isr()
{
usb_h_isr(0);
}
SET_INTERRUPT
void usb1_h_isr()
{
usb_h_isr(1);
}
__attribute__((always_inline_when_const_args))
u32 usb_h_set_intr_hander(const usb_dev usb_id, u32 ep, usb_h_interrupt hander)
{
if (ep & USB_DIR_IN) {
host_var[usb_id]->usb_h_interrupt_rx[ep & 0xf] = hander;
} else {
host_var[usb_id]->usb_h_interrupt_tx[ep] = hander;
}
return 0;
}
void usb_h_isr_reg(const usb_dev usb_id, u8 priority, u8 cpu_id)
{
if (usb_id == 0) {
request_irq(IRQ_USB_CTRL_IDX, priority, usb0_h_isr, cpu_id);
#if USB_MAX_HW_NUM > 1
} else if (usb_id == 1) {
request_irq(IRQ_USB1_CTRL_IDX, priority, usb1_h_isr, cpu_id);
#endif
}
}
#if ((USB_H_MALLOC_ENABLE == 0) || (USB_MEM_USE_OVERLAY != 0))
#if TCFG_ADB_ENABLE && TCFG_AOA_ENABLE && TCFG_HID_HOST_ENABLE
static u8 ep0_dma[USB_MAX_HW_NUM][64 + 4] __attribute__((aligned(4)));
static u8 ep1_dma[USB_MAX_HW_NUM][64 * 2 + 4] __attribute__((aligned(4)));
static u8 ep2_dma[USB_MAX_HW_NUM][64 * 2 + 4] __attribute__((aligned(4)));
static u8 ep3_dma[USB_MAX_HW_NUM][64 * 2 + 4] __attribute__((aligned(4)));
static u8 ep4_dma[USB_MAX_HW_NUM][64 * 2 + 4] __attribute__((aligned(4)));
#else
static u8 msd_h_dma_buffer[2][MAXP_SIZE_BULKIN + 4] __attribute__((aligned(4)));
#endif
__attribute__((always_inline_when_const_args))
static void *usb_h_get_ep_buffer(const usb_dev usb_id, u32 ep)
{
#if TCFG_ADB_ENABLE && TCFG_AOA_ENABLE && TCFG_HID_HOST_ENABLE
u8 dir = !!(ep & USB_DIR_IN);
u8 *p = NULL;
switch (ep & 0xf) {
case 0:
p = &ep0_dma[usb_id][0];
break;
case 1:
p = &ep1_dma[usb_id][dir * 64];
break;
case 2:
p = &ep2_dma[usb_id][dir * 64];
break;
case 3:
p = &ep3_dma[usb_id][dir * 64];
break;
case 4:
p = &ep4_dma[usb_id][dir * 64];
break;
}
return p;
#else
return msd_h_dma_buffer;
#endif
}
#endif
extern void *usb_epbuf_alloc(const usb_dev usb_id, u32 ep, u32 size);
extern void usb_epbuf_free(const usb_dev usb_id, void *buf);
void *usb_h_alloc_ep_buffer(const usb_dev usb_id, u32 ep, u32 dma_size)
{
u8 *ep_buffer = NULL;
#if ((USB_H_MALLOC_ENABLE == 0) || (USB_MEM_USE_OVERLAY != 0))
ep_buffer = usb_h_get_ep_buffer(usb_id, ep);
#else
ep_buffer = usb_epbuf_alloc(usb_id, ep, dma_size);
#endif
ASSERT(ep_buffer, "%s() ep_buffer = NULL!!!, usb_id = %d, ep = %x, dma_size = %d\n", __func__, usb_id, ep, dma_size);
log_info("usb%d host, ep = %x, dma_size = %d, ep_buffer = %x\n", usb_id, ep, dma_size, (u32)ep_buffer);
return ep_buffer;
}
void usb_h_free_ep_buffer(const usb_dev usb_id, void *buf)
{
#if ((USB_H_MALLOC_ENABLE == 0) || (USB_MEM_USE_OVERLAY != 0))
#else
usb_epbuf_free(usb_id, buf);
#endif
log_info("usb%d host free ep buffer %x\n", usb_id, (u32)buf);
}
void usb_h_set_ep_isr(struct usb_host_device *host_dev, u32 ep, usb_h_interrupt hander, void *p)
{
if (host_dev) {
usb_dev usb_id = host_device2id(host_dev);
host_var[usb_id]->dev_at_ep[ep & 0xf] = p;
usb_h_set_intr_hander(usb_id, ep, hander);
}
}
void usb_host_config(usb_dev usb_id)
{
/* host_var[usb_id] = zalloc(sizeof(struct host_var_t)); */
host_var[usb_id] = &__host_var[usb_id];
ASSERT(host_var[usb_id], "host_var_t");
g_printf("%s() %x %x", __func__, host_var[usb_id], &(host_var[usb_id]->host_ep_addr));
usb_var_init(usb_id, &(host_var[usb_id]->host_ep_addr));
}
void usb_host_free(usb_dev usb_id)
{
g_printf("%s() %x", __func__, host_var[usb_id]);
OS_ENTER_CRITICAL();
/* free(host_var[usb_id]); */
/* host_var[usb_id] = NULL; */
if (host_var[usb_id]) {
memset(host_var[usb_id]->usb_h_interrupt_rx, 0, sizeof(usb_h_interrupt) * MAX_HOST_EP_RX);
memset(host_var[usb_id]->usb_h_interrupt_tx, 0, sizeof(usb_h_interrupt) * MAX_HOST_EP_TX);
}
OS_EXIT_CRITICAL();
}
#endif
@@ -0,0 +1,297 @@
#ifndef __USB_STD_CLASS_DEF_H__
#define __USB_STD_CLASS_DEF_H__
/**************************************************************************/
/*
CLASS BITMAP
7 | 6 | 5 | 4 | 3 | 2 | 1 | 0
HID AUDIO SPEAKER Mass Storage
*/
/**************************************************************************/
#define MASSSTORAGE_CLASS 0x00000001
#define SPEAKER_CLASS 0x00000002
#define MIC_CLASS 0x00000004
#define AUDIO_CLASS (SPEAKER_CLASS|MIC_CLASS)
#define HID_CLASS 0x00000008
#define CDC_CLASS 0x00000010
#define CUSTOM_HID_CLASS 0x00000020
#define WEBUSB_CLASS 0x00000040
#ifndef FUSB_MODE
#define FUSB_MODE 1
#endif
///////////MassStorage Class
#ifndef MSD_BULK_EP_OUT
#define MSD_BULK_EP_OUT 1
#endif
#ifndef MSD_BULK_EP_IN
#define MSD_BULK_EP_IN 1
#endif
#ifndef MAXP_SIZE_BULKOUT_FS
#define MAXP_SIZE_BULKOUT_FS 64
#endif
#ifndef MAXP_SIZE_BULKOUT_HS
#define MAXP_SIZE_BULKOUT_HS 512
#endif
#ifndef MAXP_SIZE_BULKOUT
#if defined(FUSB_MODE) && FUSB_MODE
#define MAXP_SIZE_BULKOUT MAXP_SIZE_BULKOUT_FS
#elif defined(FUSB_MODE) && FUSB_MODE == 0
#define MAXP_SIZE_BULKOUT MAXP_SIZE_BULKOUT_HS
#endif
#endif
#ifndef MAXP_SIZE_BULKIN_FS
#define MAXP_SIZE_BULKIN_FS 64
#endif
#ifndef MAXP_SIZE_BULKIN_HS
#define MAXP_SIZE_BULKIN_HS 512
#endif
#ifndef MAXP_SIZE_BULKIN
#if defined(FUSB_MODE) && FUSB_MODE
#define MAXP_SIZE_BULKIN MAXP_SIZE_BULKIN_FS
#elif defined(FUSB_MODE) && FUSB_MODE == 0
#define MAXP_SIZE_BULKIN MAXP_SIZE_BULKIN_HS
#endif
#endif
#ifndef MSD_STR_INDEX
#define MSD_STR_INDEX 7
#endif
///////////HID class
#ifndef HID_EP_IN
#define HID_EP_IN 2
#endif
#ifndef HID_EP_OUT
#define HID_EP_OUT 2
#endif
#ifndef HID_EP_IN_2
#define HID_EP_IN_2 3
#endif
#ifndef HID_EP_OUT_2
#define HID_EP_OUT_2 3
#endif
#ifndef MAXP_SIZE_HIDOUT
#define MAXP_SIZE_HIDOUT 16
#endif
#ifndef MAXP_SIZE_HIDIN
#define MAXP_SIZE_HIDIN 16
#endif
#ifndef HID_INTR_INTERVAL_FS
#define HID_INTR_INTERVAL_FS 1
#endif
#ifndef HID_INTR_INTERVAL_HS
#define HID_INTR_INTERVAL_HS 4
#endif
#ifndef HID_INTR_INTERVAL
#if defined(FUSB_MODE) && FUSB_MODE
#define HID_INTR_INTERVAL HID_INTR_INTERVAL_FS
#elif defined(FUSB_MODE) && FUSB_MODE == 0
#define HID_INTR_INTERVAL HID_INTR_INTERVAL_HS
#endif
#endif
/////////////Audio Class
/**
*
* 1. uac 2.0使spk的多采样率以及mic的多采样率才能被正确枚举
* 2. Microsoft从Windodws 10 1703uac 2.0Linux则较早就支持
*
* 3. Windows上uac 2.0
* 4.
*/
#define USB_AUDIO_VERSION_1_0 0x10
#define USB_AUDIO_VERSION_2_0 0x20
#ifndef USB_AUDIO_VERSION
#define USB_AUDIO_VERSION USB_AUDIO_VERSION_1_0
#endif
#ifndef UAC_ISO_INTERVAL_FS
#define UAC_ISO_INTERVAL_FS 1
#endif
#ifndef UAC_ISO_INTERVAL_HS
#define UAC_ISO_INTERVAL_HS 4
#endif
#ifndef UAC_ISO_INTERVAL
#if defined(FUSB_MODE) && FUSB_MODE
#define UAC_ISO_INTERVAL UAC_ISO_INTERVAL_FS
#elif defined(FUSB_MODE) && FUSB_MODE == 0
#define UAC_ISO_INTERVAL UAC_ISO_INTERVAL_HS
#endif
#endif
#ifndef UAC_24BIT_IN_4BYTE
//0: 24bit in 3byte, 1: 24 bit in 4byte
//Windows不支持这种数据格式,安卓支持这种数据格式
#define UAC_24BIT_IN_4BYTE 0
#endif
//speaker class
#ifndef SPK_AUDIO_RATE_NUM
#define SPK_AUDIO_RATE_NUM 1
#endif
#if SPK_AUDIO_RATE_NUM == 1
#define SPK_AUDIO_RATE 48000
#else
#define SPK_AUDIO_RATE 96000
#define SPK_AUDIO_RATE_1 44100
#define SPK_AUDIO_RATE_2 48000
#endif
#ifndef SPK_AUDIO_RES
#define SPK_AUDIO_RES 16
#endif
#ifndef SPK_AUDIO_RES_2
#define SPK_AUDIO_RES_2 0//24
#endif
#ifndef SPK_CHANNEL
#define SPK_CHANNEL 2
#endif
#ifndef SPK_FRAME_LEN
#define SPK_FRAME_LEN (((SPK_AUDIO_RATE) * SPK_AUDIO_RES / 8 * SPK_CHANNEL)/1000+4)
#endif
#ifndef SPK_PCM_Type
#define SPK_PCM_Type (SPK_AUDIO_RES >> 4) // 0=8 ,1=16
#endif
#ifndef SPK_AUDIO_TYPE
#define SPK_AUDIO_TYPE (0x02 - SPK_PCM_Type) // TYPE1_PCM16
#endif
#ifndef SPK_ISO_EP_OUT
#ifdef CONFIG_CPU_BR18
#define SPK_ISO_EP_OUT 2
#else
#define SPK_ISO_EP_OUT 3
#endif
#endif
#ifndef SPEAKER_STR_INDEX
#define SPEAKER_STR_INDEX 5
#endif
#ifndef SPK_INPUT_TERMINAL_ID
#define SPK_INPUT_TERMINAL_ID 1
#endif
#ifndef SPK_FEATURE_UNIT_ID
#define SPK_FEATURE_UNIT_ID 2
#endif
#ifndef SPK_OUTPUT_TERMINAL_ID
#define SPK_OUTPUT_TERMINAL_ID 3
#endif
#ifndef SPK_SELECTOR_UNIT_ID
#define SPK_SELECTOR_UNIT_ID 8
#endif
/////////////Microphone Class
#ifndef MIC_AUDIO_RATE_NUM
#define MIC_AUDIO_RATE_NUM 1
#endif
#if MIC_AUDIO_RATE_NUM == 1
#define MIC_AUDIO_RATE 48000
#else
#define MIC_AUDIO_RATE 48000
#define MIC_AUDIO_RATE_1 16000
#define MIC_AUDIO_RATE_2 44100
#endif
#ifndef MIC_AUDIO_RES
#define MIC_AUDIO_RES 16
#endif
#ifndef MIC_AUDIO_RES_2
#define MIC_AUDIO_RES_2 0//24
#endif
#ifndef MIC_CHANNEL
#define MIC_CHANNEL 1
#endif
#ifndef MIC_FRAME_LEN
#define MIC_FRAME_LEN ((MIC_AUDIO_RATE * MIC_AUDIO_RES / 8 * MIC_CHANNEL)/1000)
#endif
#ifndef MIC_PCM_TYPE
#define MIC_PCM_TYPE (MIC_AUDIO_RES >> 4) // 0=8 ,1=16
#endif
#ifndef MIC_AUDIO_TYPE
#define MIC_AUDIO_TYPE (0x02 - MIC_PCM_TYPE)
#endif
#ifndef MIC_ISO_EP_IN
#define MIC_ISO_EP_IN 3
#endif
#ifndef MIC_STR_INDEX
#define MIC_STR_INDEX 6
#endif
#ifndef MIC_INPUT_TERMINAL_ID
#define MIC_INPUT_TERMINAL_ID 4
#endif
#ifndef MIC_FEATURE_UNIT_ID
#define MIC_FEATURE_UNIT_ID 5
#endif
#ifndef MIC_OUTPUT_TERMINAL_ID
#define MIC_OUTPUT_TERMINAL_ID 6
#endif
#ifndef MIC_SELECTOR_UNIT_ID
#define MIC_SELECTOR_UNIT_ID 7
#endif
////////////CDC Class
#ifndef CDC_DATA_EP_IN
#define CDC_DATA_EP_IN 4
#endif
#ifndef CDC_DATA_EP_OUT
#define CDC_DATA_EP_OUT 4
#endif
#ifndef CDC_INTR_EP_IN
#define CDC_INTR_EP_IN 5
#endif
#ifndef MAXP_SIZE_CDC_BULKIN
#define MAXP_SIZE_CDC_BULKIN 64
#endif
#ifndef MAXP_SIZE_CDC_BULKOUT
#define MAXP_SIZE_CDC_BULKOUT 64
#endif
#ifndef MAXP_SIZE_CDC_INTRIN
#define MAXP_SIZE_CDC_INTRIN 8
#endif
#ifndef CDC_INTR_INTERVAL_FS
#define CDC_INTR_INTERVAL_FS 1
#endif
#ifndef CDC_INTR_INTERVAL_HS
#define CDC_INTR_INTERVAL_HS 4
#endif
#ifndef CDC_INTR_INTERVAL
#if defined(FUSB_MODE) && FUSB_MODE
#define CDC_INTR_INTERVAL CDC_INTR_INTERVAL_FS
#elif defined(FUSB_MODE) && FUSB_MODE == 0
#define CDC_INTR_INTERVAL CDC_INTR_INTERVAL_HS
#endif
#endif
#ifndef CDC_INTR_EP_ENABLE
#define CDC_INTR_EP_ENABLE 0
#endif
///////////CUSTOM_HID class
#ifndef CUSTOM_HID_EP_IN
#define CUSTOM_HID_EP_IN 4
#endif
#ifndef CUSTOM_HID_EP_OUT
#define CUSTOM_HID_EP_OUT 4
#endif
#ifndef MAXP_SIZE_CUSTOM_HIDIN
#define MAXP_SIZE_CUSTOM_HIDIN 64
#endif
#ifndef MAXP_SIZE_CUSTOM_HIDOUT
#define MAXP_SIZE_CUSTOM_HIDOUT 64
#endif
#ifndef CUSTOM_HID_INTERVAL_FS
#define CUSTOM_HID_INTERVAL_FS 1
#endif
#ifndef CUSTOM_HID_INTERVAL_HS
#define CUSTOM_HID_INTERVAL_HS 4
#endif
#ifndef CUSTOM_HID_INTERVAL
#if defined(FUSB_MODE) && FUSB_MODE
#define CUSTOM_HID_INTERVAL CUSTOM_HID_INTERVAL_FS
#elif defined(FUSB_MODE) && FUSB_MODE == 0
#define CUSTOM_HID_INTERVAL CUSTOM_HID_INTERVAL_HS
#endif
#endif
#define WEBUSB_EP_IN 2
#define WEBUSB_EP_OUT 2
#define MAXP_SIZE_WEBUSBIN 64
#define MAXP_SIZE_WEBUSBOUT 64
#endif
+310
View File
@@ -0,0 +1,310 @@
#ifdef SUPPORT_MS_EXTENSIONS
#pragma bss_seg(".usb.data.bss")
#pragma data_seg(".usb.data")
#pragma code_seg(".usb.text")
#pragma const_seg(".usb.text.const")
#pragma str_literal_override(".usb.text.const")
#endif
#include "system/includes.h"
#include "system/event.h"
#include "os/os_api.h"
#include "app_main.h"
#if USB_PC_NO_APP_MODE == 0
#include "app_task.h"
#endif
#include "usb/usb_config.h"
#include "usb/usb_task.h"
#include "usb/device/usb_stack.h"
#include "usb/host/usb_host.h"
#include "usb/otg.h"
#if TCFG_USB_SLAVE_MSD_ENABLE
#include "usb/device/msd.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_HOST_UVC_ENABLE
#include "uvc_device.h"
/* #include "usb/host/host_uvc.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"
#if TCFG_USB_SLAVE_ENABLE || TCFG_USB_HOST_ENABLE
/************************** otg data****************************/
#if TCFG_OTG_MODE
struct otg_dev_data otg_data = {
.usb_dev_en = TCFG_OTG_USB_DEV_EN,
.slave_online_cnt = TCFG_OTG_SLAVE_ONLINE_CNT,
.slave_offline_cnt = TCFG_OTG_SLAVE_OFFLINE_CNT,
.host_online_cnt = TCFG_OTG_HOST_ONLINE_CNT,
.host_offline_cnt = TCFG_OTG_HOST_OFFLINE_CNT,
.detect_mode = TCFG_OTG_MODE,
.detect_time_interval = TCFG_OTG_DET_INTERVAL,
};
#endif
extern void usb_cdc_background_run(const usb_dev usbfd);
extern int usb_cdc_background_standby(const usb_dev usbfd);
#include "jlui_app/ui_style.h"
#include "ui/ui_api.h"
u8 msd_in_task;
u8 msd_run_reset;
static OS_SEM msg_sem;
static void usb_task(void *p)
{
int ret;
int msg[16];
int from, event;
char *usb_msg;
usb_dev usb_id;
//cppcheck-suppress unusedVariable
struct device *dev;
u8 disk_msg = 0;
#if USB_EPBUF_ALLOC_USE_LBUF
extern int usb_memory_init(void);
usb_memory_init();
#endif
#if TCFG_OTG_MODE
extern int usb_otg_init(const struct dev_node * node, void *arg);
usb_otg_init(NULL, &otg_data);
#endif
r_printf("usb_task enter\n");
/* ASSERT(TCFG_PSRAM_DEV_ENABLE);//need to enable psram */
while (1) {
ret = os_taskq_pend("taskq", msg, ARRAY_SIZE(msg));
if (ret != OS_TASKQ) {
continue;
}
if (msg[0] != Q_MSG) {
continue;
}
g_printf("msg1 = %d\n", msg[1]);
switch (msg[1]) {
case USBSTACK_OTG_MSG:
from = msg[2];
event = msg[3];
usb_msg = (char *)msg[4];
if (from == DEVICE_EVENT_FROM_OTG) {
usb_id = usb_msg[2] - '0';
if (usb_msg[0] == 's') {
#if TCFG_USB_SLAVE_ENABLE
if (event == DEVICE_EVENT_IN) {
#if USB_PC_NO_APP_MODE
usb_start(usb_id);
#else
#if TCFG_USB_CDC_BACKGROUND_RUN
ret = usb_cdc_background_standby(usb_id);
#else
ret = usb_standby(usb_id);
#endif
//如果需要切入pc模式,将otg事件分发给app mode
if (ret) {
usb_driver_event_to_user(from, event, usb_msg);
}
#endif
} else if (event == DEVICE_EVENT_OUT) {
#if USB_PC_NO_APP_MODE
usb_stop(usb_id);
#else
usb_driver_event_to_user(from, event, usb_msg);
#endif
}
#endif
} else if (usb_msg[0] == 'h') {
#if TCFG_USB_HOST_ENABLE
if (event == DEVICE_EVENT_IN) {
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
mult_usb_mount_before(usb_id);
#endif
//cppcheck-suppress unreadVariable
ret = usb_host_mount(usb_id,
TCFG_USB_HOST_MOUNT_RETRY,
TCFG_USB_HOST_MOUNT_RESET,
TCFG_USB_HOST_MOUNT_TIMEOUT);
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
mult_usb_online_mount_after(usb_id, ret);
#endif
} else if (event == DEVICE_EVENT_OUT) {
usb_host_unmount(usb_id);
}
#endif
}
}
break;
#if TCFG_USB_SLAVE_ENABLE
case USBSTACK_START:
usb_id = msg[2];
#if TCFG_USB_CDC_BACKGROUND_RUN
usb_stop(usb_id);
#endif
usb_start(usb_id);
os_sem_post(&msg_sem);
break;
case USBSTACK_PAUSE:
usb_id = msg[2];
usb_pause(usb_id);
#if TCFG_USB_CDC_BACKGROUND_RUN
usb_cdc_background_run(usb_id);
#endif
os_sem_post(&msg_sem);
break;
case USBSTACK_STOP:
usb_id = msg[2];
usb_stop(usb_id);
os_sem_post(&msg_sem);
break;
#if TCFG_USB_SLAVE_MSD_ENABLE
case USBSTACK_MSD_RUN:
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;
break;
#endif
#if TCFG_USB_CDC_BACKGROUND_RUN
case USBSTACK_CDC_BACKGROUND:
usb_id = msg[2];
usb_cdc_background_run(usb_id);
os_sem_post(&msg_sem);
break;
#endif
#endif
#if TCFG_USB_HOST_ENABLE
case USBSTACK_HOST_MSG:
from = DEVICE_EVENT_FROM_USB_HOST;
event = msg[2];
usb_msg = (char *)msg[3];
if (!strncmp(usb_msg, "udisk", 5)) {
if (event == DEVICE_EVENT_IN) {
dev = dev_open(usb_msg, NULL);
if (dev) {
dev_close(dev);
disk_msg = 1;
} else {
disk_msg = 0;
}
} else if (event == DEVICE_EVENT_OUT) {
} else if (event == DEVICE_EVENT_CHANGE) {
}
//只有U盘尝试open成功才将usb host事件分发给app mode
//offline事件同理,尝试打开不成功则不分发事件
if (disk_msg) {
usb_driver_event_to_user(from, event, usb_msg);
}
}
#if TCFG_HOST_UVC_ENABLE
r_printf("USBSTACK_HOST_MSG: %s, event: %d\n", usb_msg, event);
if (!strncmp((const char *)usb_msg, "uvc", 3)) {
if (event == DEVICE_EVENT_IN) {
/* int sub_id = ((const char *)event->value)[3] - '0'; */
extern int usb_host_video_init(const usb_dev usb_id, const u8 sub_id);
usb_host_video_init(usb_id, usb_id);
extern int video_uvc_jpeg_stream_open(u16 width, u16 height);
video_uvc_jpeg_stream_open(640, 480);
UI_HIDE_CURR_WINDOW();
UI_SHOW_WINDOW(ID_WINDOW_UVC);
} else if (event == DEVICE_EVENT_OUT) {
extern int uvc_host_camera_out(const usb_dev usb_id);
extern int video_uvc_jpeg_stream_close();
video_uvc_jpeg_stream_close();
uvc_host_camera_out(usb_id);
usb_driver_event_to_user(from, event, usb_msg);
extern void jlset_uvc_status(u8 status);
jlset_uvc_status(0);//退出后清除状态
UI_HIDE_CURR_WINDOW();
UI_SHOW_WINDOW(ID_WINDOW_DIAL);
}
}
#endif
break;
case USBSTACK_HOST_REMOUNT:
usb_id = ((int *)msg[2])[0];
ret = usb_host_remount(usb_id, TCFG_USB_HOST_MOUNT_RETRY, TCFG_USB_HOST_MOUNT_RESET, TCFG_USB_HOST_MOUNT_TIMEOUT, 0);
((int *)msg[2])[1] = ret;
os_sem_post(&msg_sem);
break;
#if TCFG_USB_DM_MULTIPLEX_WITH_SD_DAT0
case USBSTACK_HOST_MOUNT_AFTER:
usb_id = ((int *)msg[2])[0];
ret = ((int *)msg[2])[1];
mult_usb_online_mount_after(usb_id, ret);
os_sem_post(&msg_sem);
break;
case USBSTACK_HOST_UNMOUNT_AFTER:
usb_id = ((int *)msg[2])[0];
ret = ((int *)msg[2])[1];
mult_usb_mount_offline(usb_id);
os_sem_post(&msg_sem);
break;
#endif
#endif
default:
break;
}
}
}
static int usb_stack_init(void)
{
r_printf("%s()", __func__);
int err;
os_sem_create(&msg_sem, 0);
err = task_create(usb_task, NULL, USB_TASK_NAME);
if (err != OS_NO_ERR) {
r_printf("usb_msd task creat fail %x\n", err);
}
return 0;
}
late_initcall(usb_stack_init);
void usb_message_to_stack(int msg, void *arg, u8 sync)
{
//先将sem清零0,否则当sync为0时不会pend,另一边post会使counter累加
os_sem_set(&msg_sem, 0);
os_taskq_post_msg(USB_TASK_NAME, 2, msg, arg);
if (sync) {
os_sem_pend(&msg_sem, 200);
}
}
#endif
+28
View File
@@ -0,0 +1,28 @@
#ifndef __USB_TASK_H__
#define __USB_TASK_H__
#include "usb/usb.h"
#include "usb/ch9.h"
#include "usb/usb_phy.h"
#define USB_TASK_NAME "usb_stack"
enum {
USBSTACK_OTG_MSG = 0x80,
USBSTACK_START,
USBSTACK_PAUSE,
USBSTACK_STOP,
USBSTACK_MSD_RUN,
USBSTACK_CDC_BACKGROUND,
USBSTACK_HOST_MSG,
USBSTACK_HOST_MOUNT,
USBSTACK_HOST_UNMOUNT,
USBSTACK_HOST_REMOUNT,
USBSTACK_HOST_MOUNT_AFTER,
USBSTACK_HOST_UNMOUNT_AFTER,
};
void usb_message_to_stack(int msg, void *arg, u8 sync);
#endif