Files
TAIXIN/sdk/lib/bus/rttusb/usbhost/class/usbh_audio.c

1361 lines
46 KiB
C

/*
* Copyright (c) 2022, sakumisu
*
* SPDX-License-Identifier: Apache-2.0
*/
#include "rtthread.h"
#ifdef RT_USBH_UAC
#include "basic_include.h"
#include "rttusb_host.h"
#include "usbh_audio.h"
#define DEV_FORMAT "/dev/audio%d"
/* general descriptor field offsets */
#define DESC_bLength 0 /** Length offset */
#define DESC_bDescriptorType 1 /** Descriptor type offset */
#define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */
/* interface descriptor field offsets */
#define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */
#define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */
#define AUDIO_FREE_PIPE 0
#define AUDIO_ALLOC_PIPE 1
#define AUDIO_MIC_EN 1 //应用层MIC使能
#define AUDIO_SPK_EN 1 //应用层SPK使能
#define AUDIO_VOLUME_CONTROL_EN 0 //UAC音量控制使能 (根据设备是否支持该功能,自行选择打开)
#define AUDIO_SET_INTF_ALTSETTING 1
/* ---------------------------- MIC ---------------------------- */
#define AUDIO_MIC_SAMPLING_FREQ 8000 //设置MIC接收的采样率
#define AUDIO_MIC_RESOLUTION_BITS 16 //设置MIC接收的采样精度
#define AUDIO_MIC_MODULE_CHANNEL 1 //设置MIC接收的通道数
#define AUDIO_MIC_RESOLUTION_BYTES (AUDIO_MIC_RESOLUTION_BITS / 8)
#define AUDIO_RX_PACKET_SIZE ((AUDIO_MIC_SAMPLING_FREQ * AUDIO_MIC_MODULE_CHANNEL * AUDIO_MIC_RESOLUTION_BYTES) / 1000) //计算MIC每毫秒接收的数据包大小
/* ---------------------------- SPK ---------------------------- */
#define AUDIO_SPK_SAMPLING_FREQ 8000 //设置SPK发送的采样率
#define AUDIO_SPK_RESOLUTION_BITS 16 //设置SPK发送的采样精度
#define AUDIO_SPK_MODULE_CHANNEL 1 //设置SPK发送的通道数
#define AUDIO_SPK_RESOLUTION_BYTES (AUDIO_SPK_RESOLUTION_BITS / 8)
#define AUDIO_TX_PACKET_SIZE ((AUDIO_SPK_SAMPLING_FREQ * AUDIO_SPK_MODULE_CHANNEL * AUDIO_SPK_RESOLUTION_BYTES) / 1000) //计算SPK每毫秒发送的数据包大小
extern uint32 usbmic_packet_len;
extern uint8_t uac_run;
extern uint8_t uac_open;
static int usb_dma_uac_irq_times = 0;
static struct uclass_driver usbh_audio_class;
rt_uint8_t g_audio_buf[128];
struct usbh_audio g_audio_class[CONFIG_USBHOST_MAX_AUDIO_CLASS];
static rt_uint32_t g_devinuse = 0;
static struct usbh_audio *usbh_audio_class_alloc(void)
{
int devno;
for (devno = 0; devno < CONFIG_USBHOST_MAX_AUDIO_CLASS; devno++) {
if ((g_devinuse & (1 << devno)) == 0) {
g_devinuse |= (1 << devno);
memset(&g_audio_class[devno], 0, sizeof(struct usbh_audio));
g_audio_class[devno].minor = devno;
return &g_audio_class[devno];
}
}
return RT_NULL;
}
static void usbh_audio_class_free(struct usbh_audio *audio_class)
{
int devno = audio_class->minor;
if (devno >= 0 && devno < 32) {
g_devinuse &= ~(1 << devno);
}
memset(audio_class, 0, sizeof(struct usbh_audio));
}
int usbh_audio_open(struct usbh_audio *audio_class, const char *name, rt_uint32_t samp_freq)
{
struct urequest setup;
struct uendpoint_descriptor *ep_desc = RT_NULL;
rt_uint8_t intf = 0xff;
rt_uint8_t altsetting = 1;
int timeout = USB_TIMEOUT_BASIC;
// if (audio_class->is_opened) {
// return 0;
// }
for (rt_uint8_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
printf("audio_class->module[%d]\n",i);
for (rt_uint8_t j = 0; j < audio_class->num_of_intf_altsettings; j++) {
for (rt_uint8_t k = 0; k < audio_class->module[i].altsetting[j].sampfreq_num; k++) {
if (audio_class->module[i].altsetting[j].sampfreq[k] == samp_freq) {
intf = audio_class->module[i].data_intf;
altsetting = j;
printf("usb host audio open:%d %d\n",intf,altsetting);
goto freq_found;
}
}
}
}
}
return -EIO;
freq_found:
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_SET_INTERFACE;
setup.wValue = altsetting;
setup.wIndex = intf;
setup.wLength = 0;
if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8)
{
return RET_ERR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return RET_ERR;
}
if (strcmp(name, "mic") == 0)
{
ep_desc = &audio_class->isoin;
}
else if (strcmp(name, "speaker") == 0)
{
ep_desc = &audio_class->isoout;
}
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_ENDPOINT;
setup.bRequest = SET_CUR;
setup.wValue = (SAMPLING_FREQ_CONTROL << 8) | 0x00;
setup.wIndex = ep_desc->bEndpointAddress;
setup.wLength = 3;
memcpy(g_audio_buf, &samp_freq, 3);
if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8)
{
return RET_ERR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, g_audio_buf, 3, timeout) != 3)
{
return RET_ERR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return RET_ERR;
}
os_printf("Open audio module :%s, altsetting: %u\r\n", name, altsetting);
audio_class->is_opened = TRUE;
uac_open = 1;
uac_run = 1;
return RT_EOK;
}
int usbh_audio_close(struct usbh_audio *audio_class, const char *name)
{
struct urequest setup;
rt_uint8_t intf = 0xff;
int timeout = USB_TIMEOUT_BASIC;
for (size_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
intf = audio_class->module[i].data_intf;
}
}
if (intf == 0xff) {
return -EIO;
}
LOG_D("Close audio module :%s\r\n", name);
audio_class->is_opened = FALSE;
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE;
setup.bRequest = USB_REQ_SET_INTERFACE;
setup.wValue = 0;
setup.wIndex = intf;
setup.wLength = 0;
if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return RT_ERROR;
}
uac_open = 0;
uac_run = 0;
return RT_EOK;
}
int usbh_audio_get_min_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *min_volume)
{
struct urequest setup;
rt_uint8_t intf = 0xff;
rt_uint8_t feature_id = 0xff;
rt_uint8_t ch;
int timeout = USB_TIMEOUT_BASIC;
for (size_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
intf = audio_class->ctrl_intf;
feature_id = audio_class->module[i].feature_unit_id;
ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels;
}
}
if (intf == 0xff) {
return -EIO;
}
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE;
setup.bRequest = GET_MIN;
setup.wValue = (VOLUME_CONTROL << 8) | ch;
setup.wIndex = (feature_id << 8) | intf;
setup.wLength = 2;
if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, g_audio_buf, 2, timeout) != 2)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, RT_NULL, 0, timeout) != 0)
{
return RT_ERROR;
}
memcpy(min_volume, g_audio_buf, 2);
return RT_EOK;
}
int usbh_audio_get_max_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *max_volume)
{
struct urequest setup;
rt_uint8_t intf = 0xff;
rt_uint8_t feature_id = 0xff;
rt_uint8_t ch;
int timeout = USB_TIMEOUT_BASIC;
for (size_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
intf = audio_class->ctrl_intf;
feature_id = audio_class->module[i].feature_unit_id;
ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels;
}
}
if (intf == 0xff) {
return -EIO;
}
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE;
setup.bRequest = GET_MAX;
setup.wValue = (VOLUME_CONTROL << 8) | ch;
setup.wIndex = (feature_id << 8) | intf;
setup.wLength = 2;
if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, g_audio_buf, 2, timeout) != 2)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, RT_NULL, 0, timeout) != 0)
{
return RT_ERROR;
}
memcpy(max_volume, g_audio_buf, 2);
return RT_EOK;
}
int usbh_audio_get_cur_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *cur_volume)
{
struct urequest setup;
rt_uint8_t intf = 0xff;
rt_uint8_t feature_id = 0xff;
rt_uint8_t ch;
int timeout = USB_TIMEOUT_BASIC;
for (size_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
intf = audio_class->ctrl_intf;
feature_id = audio_class->module[i].feature_unit_id;
ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels;
}
}
if (intf == 0xff) {
return -EIO;
}
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE;
setup.bRequest = GET_CUR;
setup.wValue = (VOLUME_CONTROL << 8) | ch;
setup.wIndex = (feature_id << 8) | intf;
setup.wLength = 2;
if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, g_audio_buf, 2, timeout) != 2)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, RT_NULL, 0, timeout) != 0)
{
return RT_ERROR;
}
memcpy(cur_volume, g_audio_buf, 2);
return RT_EOK;
}
int usbh_audio_get_res_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *res_volume)
{
struct urequest setup;
rt_uint8_t intf = 0xff;
rt_uint8_t feature_id = 0xff;
rt_uint8_t ch;
int timeout = USB_TIMEOUT_BASIC;
for (size_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
intf = audio_class->ctrl_intf;
feature_id = audio_class->module[i].feature_unit_id;
ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels;
}
}
if (intf == 0xff) {
return -EIO;
}
setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE;
setup.bRequest = GET_RES;
setup.wValue = (VOLUME_CONTROL << 8) | ch;
setup.wIndex = (feature_id << 8) | intf;
setup.wLength = 2;
if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, g_audio_buf, 2, timeout) != 2)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, RT_NULL, 0, timeout) != 0)
{
return RT_ERROR;
}
memcpy(res_volume, g_audio_buf, 2);
return RT_EOK;
}
int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t volume_hex)
{
struct urequest setup;
rt_uint8_t intf = 0xff;
rt_uint8_t feature_id = 0xff;
rt_uint8_t ch;
int timeout = USB_TIMEOUT_BASIC;
if(audio_class == RT_NULL)
{
return -EIO;
}
for (size_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
intf = audio_class->ctrl_intf;
feature_id = audio_class->module[i].feature_unit_id;
ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels;
}
}
if (intf == 0xff || feature_id == 0xff) {
return -EIO;
}
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE;
setup.bRequest = SET_CUR;
setup.wValue = (VOLUME_CONTROL << 8) | ch;
setup.wIndex = (feature_id << 8) | intf;
setup.wLength = 2;
memcpy(g_audio_buf, &volume_hex, 2);
if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, g_audio_buf, 2, timeout) != 2)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return RT_ERROR;
}
return RT_EOK;
}
int usbh_audio_set_volume_db(struct usbh_audio *audio_class, const char *name, int volume_db, int min_volume_db, int max_volume_db)
{
struct urequest setup;
rt_uint8_t intf = 0xff;
rt_uint8_t feature_id = 0xff;
rt_uint16_t volume_hex;
float volume_min_db,volume_max_db;
rt_uint8_t ch;
int timeout = USB_TIMEOUT_BASIC;
if(audio_class == RT_NULL)
{
return -EIO;
}
if ((volume_db > 127) || (volume_db < -127)) {
return -EIO;
}
for (size_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
intf = audio_class->ctrl_intf;
feature_id = audio_class->module[i].feature_unit_id;
ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels;
}
}
if (intf == 0xff || feature_id == 0xff) {
return -EIO;
}
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE;
setup.bRequest = SET_CUR;
setup.wValue = (VOLUME_CONTROL << 8) | ch;
setup.wIndex = (feature_id << 8) | intf;
setup.wLength = 2;
if (min_volume_db < 0x8000) {
volume_min_db = (float)min_volume_db / 256;
} else {
volume_min_db = (float)(min_volume_db - 0x10000) / 256;
}
if (max_volume_db < 0x8000) {
volume_max_db = (float)max_volume_db / 256;
} else {
volume_max_db = (float)(max_volume_db - 0x10000) / 256;
}
os_printf("Get ch: [%s] , dB range: %f dB ~ %f dB , set %d dB\r\n", name, volume_min_db, volume_max_db, volume_db);
if (volume_db > volume_max_db || volume_db < volume_min_db)
{
os_printf("set (%d dB) not in range!!!\n",volume_db);
return RT_ERROR;
}
if (volume_db >= 0) {
volume_hex = volume_db * 256;
if (volume_hex > max_volume_db) {
os_printf("%s [ERR]volume_hex(%x) not in range\n",__FUNCTION__,volume_hex);
return RT_ERROR;
}
} else {
volume_hex = volume_db * 256 + 0x10000;
if (volume_hex < min_volume_db) {
os_printf("%s [ERR]volume_hex(%x) not in range\n",__FUNCTION__,volume_hex);
return RT_ERROR;
}
}
memcpy(g_audio_buf, &volume_hex, 2);
if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, g_audio_buf, 2, timeout) != 2)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return RT_ERROR;
}
os_printf("%s success, volume_hex:%x\n",__FUNCTION__,volume_hex);
return RT_EOK;
}
int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, bool mute)
{
struct urequest setup;
rt_uint8_t intf = 0xff;
rt_uint8_t feature_id = 0xff;
int timeout = USB_TIMEOUT_BASIC;
rt_uint8_t ch;
for (size_t i = 0; i < audio_class->module_num; i++) {
if (strcmp(name, audio_class->module[i].name) == 0) {
intf = audio_class->ctrl_intf;
feature_id = audio_class->module[i].feature_unit_id;
ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels;
}
}
if (intf == 0xff) {
return -EIO;
}
setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE;
setup.bRequest = SET_CUR;
setup.wValue = (MUTE_CONTROL << 8) | ch;
setup.wIndex = (feature_id << 8) | intf;
setup.wLength = 1;
memcpy(g_audio_buf, &mute, 1);
if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, g_audio_buf, 1, timeout) != 1)
{
return RT_ERROR;
}
if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0)
{
return RT_ERROR;
}
return RT_EOK;
}
void usbh_audio_list_module(struct usbh_audio *audio_class)
{
uep_desc_t ep_desc = RT_NULL;
rt_uint8_t mult;
rt_uint16_t mps;
os_printf("============= Audio module information ===================\r\n");
os_printf("bcdADC :%04x\r\n", audio_class->bcdADC);
os_printf("Num of modules :%u\r\n", audio_class->module_num);
os_printf("Num of altsettings:%u\r\n", audio_class->num_of_intf_altsettings);
for (rt_uint8_t i = 0; i < audio_class->module_num; i++) {
os_printf(" module name :%s\r\n", audio_class->module[i].name);
os_printf(" module feature unit id :%d\r\n", audio_class->module[i].feature_unit_id);
if(strcmp("mic", audio_class->module[i].name) == 0) {
ep_desc = &audio_class->isoin;
}else if (strcmp("speaker", audio_class->module[i].name) == 0) {
ep_desc = &audio_class->isoout;
}
mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT;
mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK;
if (ep_desc->bEndpointAddress & 0x80) {
audio_class->isoin_mps = mps * (mult + 1);
} else {
audio_class->isoout_mps = mps * (mult + 1);
}
os_printf(" Ep=%02X Attr=%02x Mps=%d Interval=%02u Mult=%02u\r\n",
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
mps,
ep_desc->bInterval,
mult);
for (rt_uint8_t j = 0; j < audio_class->num_of_intf_altsettings; j++) {
if (j == 0) {
os_printf(" Ingore altsetting 0\r\n");
continue;
}
os_printf(" Altsetting %u\r\n", j);
os_printf(" module channels :%u\r\n", audio_class->module[i].altsetting[j].channels);
//LOG_D(" module format_type :%u\r\n",audio_class->module[i].altsetting[j].format_type);
os_printf(" module bitresolution :%u\r\n", audio_class->module[i].altsetting[j].bitresolution);
os_printf(" module sampfreq num :%u\r\n", audio_class->module[i].altsetting[j].sampfreq_num);
for (rt_uint8_t k = 0; k < audio_class->module[i].altsetting[j].sampfreq_num; k++) {
os_printf(" module sampfreq :%d hz\r\n", audio_class->module[i].altsetting[j].sampfreq[k]);
}
}
}
os_printf("============= Audio module information ===================\r\n");
}
static rt_err_t rt_usbh_class_driver_audio_enable(void *arg)
{
int ret;
struct uhintf **p_intf = arg;
rt_uint8_t intf;
rt_uint8_t cur_iface = 0xff;
rt_uint8_t cur_iface_count = 0xff;
rt_uint8_t cur_alt_setting = 0xff;
rt_uint8_t input_offset = 0;
rt_uint8_t output_offset = 0;
rt_uint8_t feature_unit_offset = 0;
rt_uint8_t format_offset = 0;
rt_uint8_t *p = RT_NULL;
uhcd_t hcd = NULL;
uep_desc_t ep_desc;
if (p_intf[0] == NULL) {
return -EIO;
}
hcd = p_intf[0]->device->hcd;
intf = p_intf[0]->intf_desc->bInterfaceNumber;
struct usbh_audio *audio_class = usbh_audio_class_alloc();
if (audio_class == RT_NULL) {
LOG_D("Fail to alloc audio_class\r\n");
return RET_ERR;
}
audio_class->device = p_intf[0]->device;
audio_class->ctrl_intf = intf;
audio_class->num_of_intf_altsettings = 2;
p_intf[0]->user_data = audio_class;
p = (rt_uint8_t *)(p_intf[0]->device->cfg_desc);
while (p[DESC_bLength]) {
switch (p[DESC_bDescriptorType]) {
case USB_DESC_TYPE_IAD:
cur_iface_count = p[3];
break;
case USB_DESC_TYPE_INTERFACE:
cur_iface = p[INTF_DESC_bInterfaceNumber];
cur_alt_setting = p[INTF_DESC_bAlternateSetting];
break;
case USB_DESC_TYPE_ENDPOINT:
//os_printf("USB_DESC_TYPE_ENDPOINT\n");
if(((cur_iface == audio_class->module[0].data_intf) && (audio_class->module[0].data_intf != 0)) ||
((cur_iface == audio_class->module[1].data_intf) && (audio_class->module[1].data_intf != 0)))
{
ep_desc = (struct uendpoint_descriptor *)p;
os_printf("Altsetting:%u, Ep=%02x Attr=%02u Mps=%d Interval=%02u Cur_iface:%d\r\n",
cur_alt_setting,
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
ep_desc->wMaxPacketSize,
ep_desc->bInterval,
cur_iface);
if (cur_alt_setting == AUDIO_SET_INTF_ALTSETTING) {
if(((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN ) &&
((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_ISOC))
{
audio_class->isoin = *ep_desc;
}
if(((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_OUT ) &&
((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_ISOC))
{
audio_class->isoout = *ep_desc;
}
}
}
break;
case UDESC_CS_INTERFACE:
if (cur_iface == audio_class->ctrl_intf) {
switch (p[DESC_bDescriptorSubType]) {
case UDESCSUB_AC_HEADER: {
struct usb_audio_control_descriptor *desc = (struct usb_audio_control_descriptor *)p;
audio_class->bcdADC = desc->bcdADC;
audio_class->bInCollection = desc->bInCollection;
} break;
case UDESCSUB_AC_INPUT: {
struct usb_audio_input_terminal *desc = (struct usb_audio_input_terminal *)p;
audio_class->module[input_offset].input_terminal_id = desc->bTerminalId;
audio_class->module[input_offset].input_terminal_type = desc->wTerminalType;
audio_class->module[input_offset].input_channel_config = desc->wChannelConfig;
if (desc->wTerminalType == UAT_STREAM) {
audio_class->module[input_offset].terminal_link_id = desc->bTerminalId;
}
if (desc->wTerminalType == UATI_MICROPHONE) {
audio_class->module[input_offset].name = "mic";
}
input_offset++;
} break;
break;
case UDESCSUB_AC_OUTPUT: {
struct usb_audio_output_terminal *desc = (struct usb_audio_output_terminal *)p;
audio_class->module[output_offset].output_terminal_id = desc->bTerminalId;
audio_class->module[output_offset].output_terminal_type = desc->wTerminalType;
if (desc->wTerminalType == UAT_STREAM) {
audio_class->module[output_offset].terminal_link_id = desc->bTerminalId;
}
if (desc->wTerminalType == UATO_SPEAKER) {
audio_class->module[output_offset].name = "speaker";
}
output_offset++;
} break;
case UDESCSUB_AC_FEATURE: {
struct usb_audio_feature_unit *desc = (struct usb_audio_feature_unit *)p;
audio_class->module[feature_unit_offset].feature_unit_id = desc->bUnitId;
audio_class->module[feature_unit_offset].feature_unit_controlsize = desc->bControlSize;
for (rt_uint8_t j = 0; j < desc->bControlSize; j++) {
audio_class->module[feature_unit_offset].feature_unit_controls[j] = p[6 + j];
}
feature_unit_offset++;
} break;
case UDESCSUB_AC_PROCESSING:
break;
default:
break;
}
} else if ((cur_iface < (audio_class->ctrl_intf + cur_iface_count)) && (cur_iface > audio_class->ctrl_intf)) {
switch (p[DESC_bDescriptorSubType]) {
case AS_GENERAL:
break;
case FORMAT_TYPE: {
struct usb_audio_streaming_type1_descriptor *desc = (struct usb_audio_streaming_type1_descriptor *)p;
audio_class->module[format_offset].data_intf = cur_iface;
audio_class->module[format_offset].altsetting[cur_alt_setting].channels = desc->bNrChannels;
audio_class->module[format_offset].altsetting[cur_alt_setting].format_type = desc->bFormatType;
audio_class->module[format_offset].altsetting[cur_alt_setting].bitresolution = desc->bBitResolution;
audio_class->module[format_offset].altsetting[cur_alt_setting].sampfreq_num = desc->bSamFreqType;
for (rt_uint8_t j = 0; j < desc->bSamFreqType; j++) {
audio_class->module[format_offset].altsetting[cur_alt_setting].sampfreq[j] = (rt_uint32_t)(p[10 + j * 3] << 16) |
(rt_uint32_t)(p[9 + j * 3] << 8) |
(rt_uint32_t)(p[8 + j * 3] << 0);
}
if (cur_alt_setting == (audio_class->num_of_intf_altsettings - 1)) {
format_offset++;
}
} break;
default:
break;
}
}
break;
default:
break;
}
/* skip to next descriptor */
p += p[DESC_bLength];
}
if ((input_offset != output_offset) && (input_offset != feature_unit_offset) && (input_offset != format_offset)) {
return -EIO;
}
audio_class->module_num = input_offset;
usbh_audio_list_module(audio_class);
audio_class->rx_buff = (rt_uint8_t *)rt_malloc(AUDIO_RX_PACKET_SIZE + USB_RX_BUFF_RESERVE_SIZE);
if(audio_class->rx_buff == RT_NULL) {
os_printf("malloc rx_buff fail\n");
return RT_ENOMEM;
}
for (size_t i = 0; i < audio_class->module_num; i++) {
ret = usbh_audio_close(audio_class, audio_class->module[i].name);
if (ret < 0) {
os_printf("Fail to close audio module :%s\r\n", audio_class->module[i].name);
return ret;
}
}
snprintf(audio_class->devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, audio_class->minor);
os_printf("Register Audio Class:%s\r\n", audio_class->devname);
usbh_audio_run(audio_class);
return 0;
}
static rt_err_t rt_usbh_class_driver_audio_disable(void *arg)
{
int ret = RT_EOK;
struct uhintf *p_intf = arg;
if (p_intf == NULL) {
return -EIO;
}
struct usbh_audio *audio_class = (struct usbh_audio *)p_intf->user_data;
if (audio_class) {
if (audio_class->devname[0] != '\0') {
os_printf("Unregister Audio Class:%s\r\n", audio_class->devname);
usbh_audio_stop(audio_class);
}
if(audio_class->rx_buff) {
rt_free(audio_class->rx_buff);
}
usbh_audio_class_free(audio_class);
}
return ret;
}
/* ----------------------------- USB 2.0 / USB 1.1 UAC IRQ ----------------------------- */
static void _usbh_audio_spk_tx(void * p_dev, uint8_t ep, uint8_t *data, uint32_t len)
{
struct usb_device_dma_cfg dma_cfg;
if (p_dev == RT_NULL || data == RT_NULL || len == 0) {
return;
}
dma_cfg.ep_index = ep;
dma_cfg.ep_dir = USB_CORE_HOST_EP_TX;
dma_cfg.dma_addr = (rt_uint32_t *)data;
dma_cfg.dma_len = len;
usb_device_ioctl((struct usb_device *)p_dev, USB_HOST_KICK_EP_DMA, (rt_uint32_t)&dma_cfg, (rt_uint32_t)RT_NULL);
}
bool rtt_uac_data_deal(void *p_dev, rt_uint8_t ep)
{
rt_int32_t rx_len = 0;
usb_device_ioctl((struct usb_device *)p_dev, USB_HOST_GET_RX_DMA_LEN, ep, (rt_uint32_t)&rx_len);
if((rx_len == 0) || (rx_len != AUDIO_RX_PACKET_SIZE)){
return 1;
}
if(rx_len < 0){
os_printf("The length of the configured dma needs to be increased\n");
return 1;
}
usbmic_packet_len = rx_len;
// os_printf("rx_len:%d\n", rx_len);
return 0;
}
void rtt_usbh_audio_irq(void * dev, rt_uint32_t irq, rt_uint8_t ep)
{
rt_uint32_t ret;
struct usb_device *p_dev = (struct usb_device *)dev;
struct usb_device_dma_cfg dma_cfg;
if (!p_dev)
return;
switch (irq)
{
case USB_EP_RX_IRQ:
if ((ep == (&g_audio_class[0])->pipe_in->pipe_index) && ((&g_audio_class[0])->pipe_in != RT_NULL)) {
#if AUDIO_MIC_EN
usb_dma_uac_irq_times++;
if(uac_open && uac_run) {
ret = rtt_uac_data_deal(p_dev, ep);
if(ret == 0){
ret = usbmic_deal((struct usb_device *)p_dev, (uint8_t *)(&g_audio_class[0])->rx_buff);
}
dma_cfg.ep_index = ep;
dma_cfg.ep_dir = USB_CORE_HOST_EP_RX;
dma_cfg.dma_addr = (rt_uint32_t *)g_audio_class[0].rx_buff;
dma_cfg.dma_len = AUDIO_RX_PACKET_SIZE;
usb_device_ioctl((struct usb_device *)p_dev, USB_HOST_KICK_EP_DMA, (rt_uint32_t)&dma_cfg, (rt_uint32_t)RT_NULL);
}
#endif
}
break;
case USB_EP_TX_IRQ:
if ((ep == (&g_audio_class[0])->pipe_out->pipe_index) && ((&g_audio_class[0])->pipe_out != RT_NULL)) {
#if AUDIO_SPK_EN
usb_dma_uac_irq_times++;
if(uac_open && uac_run)
{
usbspk_tx((struct usb_device *)p_dev, ep, AUDIO_TX_PACKET_SIZE, _usbh_audio_spk_tx);
}
#endif
}
break;
default:
break;
}
}
rt_uint32_t rtt_usbh_audio_dev_pipe_mange(rt_uint8_t dev_num, const char *name, rt_uint8_t alloc_or_free)
{
uep_desc_t ep_desc = RT_NULL;
upipe_t pipe;
struct usbh_audio *audio_class = RT_NULL;
if(dev_num >= CONFIG_USBHOST_MAX_AUDIO_CLASS)
{
os_printf("Invalid dev_num %d!!!!!!!!\n",dev_num);
return -RT_ERROR;
}
audio_class = &g_audio_class[dev_num];
if (strcmp(name, "mic") == 0) {
ep_desc = &audio_class->isoin;
} else if (strcmp(name, "speaker") == 0) {
ep_desc = &audio_class->isoout;
}
os_printf("Audio Class dev%d: Altsetting:%u, Ep=%02x Attr=%02u Mps=%d Interval=%02u\r\n",
dev_num,
AUDIO_SET_INTF_ALTSETTING,
ep_desc->bEndpointAddress,
ep_desc->bmAttributes,
ep_desc->wMaxPacketSize,
ep_desc->bInterval);
if(ep_desc->bEndpointAddress == 0 || ep_desc->bmAttributes == 0 || ep_desc->wMaxPacketSize == 0)
{
return -RT_ERROR;
}
if(alloc_or_free)
{
pipe = rt_usb_instance_find_pipe(audio_class->device, ep_desc->bEndpointAddress);
if(pipe != RT_NULL) {
os_printf("g_video_class[%d] pipe has been alloced!!!\n",dev_num);
return -RT_ERROR;
}
if (rt_usb_hcd_alloc_pipe(audio_class->device->hcd, &pipe, audio_class->device, ep_desc) != RT_EOK) {
rt_kprintf("alloc iso pipe failed\n");
return -RT_ERROR;
}
os_printf("alloc iso pipe ok %x\n",pipe);
rt_usb_instance_add_pipe(audio_class->device, pipe);
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN)
{
audio_class->pipe_in = pipe;
}
else
{
audio_class->pipe_out = pipe;
}
struct usb_device *p_dev = NULL;
switch(g_audio_class[0].device->hcd->devid)
{
case HG_USB11_HOST_CONTROLLER_DEVID:
{
os_printf("HG_USB11_HOST_CONTROLLER_DEVID\n");
p_dev = (struct usb_device *)dev_get(HG_USB11HOST_DEVID);
if (p_dev) {
os_printf("kick usb11\n");
};
/* USB Full Speed : 1 frame = 1 ms */
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN)
{
usb_device_ioctl(p_dev, USB_HOST_SET_RX_INTERVAL, pipe->pipe_index, 1);
}
else
{
usb_device_ioctl(p_dev, USB_HOST_SET_TX_INTERVAL, pipe->pipe_index, 1);
}
}
break;
case HG_USB_HOST_CONTROLLER_DEVID:
{
os_printf("HG_USB_HOST_CONTROLLER_DEVID\n");
p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
if (p_dev) {
os_printf("kick usb20\n");
};
if (usb_device_ioctl(p_dev, USB_HOST_GET_BUS_SPEED, 0, 0)) {
/* USB High Speed : 8 microframe = 1 ms */
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN)
{
usb_device_ioctl(p_dev, USB_HOST_SET_RX_INTERVAL, pipe->pipe_index, 4);
}
else
{
usb_device_ioctl(p_dev, USB_HOST_SET_TX_INTERVAL, pipe->pipe_index, 4);
}
} else {
/* USB Full Speed : 1 frame = 1 ms */
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN)
{
usb_device_ioctl(p_dev, USB_HOST_SET_RX_INTERVAL, pipe->pipe_index, 1);
}
else
{
usb_device_ioctl(p_dev, USB_HOST_SET_TX_INTERVAL, pipe->pipe_index, 1);
}
}
}
break;
default:
break;
}
}
else
{
if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN)
{
if(audio_class->pipe_in != RT_NULL) {
rt_list_remove(&audio_class->pipe_in->list);
rt_usb_hcd_free_pipe(audio_class->device->hcd, audio_class->pipe_in);
audio_class->pipe_in = RT_NULL;
} else {
os_printf("g_audio_class[%d] pipe_in is NULL, not free\n",dev_num);
return -RT_ERROR;
}
}
else
{
if(audio_class->pipe_out != RT_NULL) {
rt_list_remove(&audio_class->pipe_out->list);
rt_usb_hcd_free_pipe(audio_class->device->hcd, audio_class->pipe_out);
audio_class->pipe_out = RT_NULL;
} else {
os_printf("g_audio_class[%d] pipe_out is NULL, not free\n",dev_num);
return -RT_ERROR;
}
}
}
return RT_EOK;
}
/* 用户调用接口 */
rt_uint32_t rtt_usbh_audio_user_open()
{
rt_uint32_t ret;
struct usbh_audio *audio_class = &g_audio_class[0];
struct usb_device *p_dev = NULL;
switch(g_audio_class[0].device->hcd->devid)
{
case HG_USB11_HOST_CONTROLLER_DEVID:
{
os_printf("HG_USB11_HOST_CONTROLLER_DEVID\n");
p_dev = (struct usb_device *)dev_get(HG_USB11HOST_DEVID);
if (p_dev) {
os_printf("kick usb11\n");
};
}
break;
case HG_USB_HOST_CONTROLLER_DEVID:
{
os_printf("HG_USB_HOST_CONTROLLER_DEVID\n");
p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
if (p_dev) {
os_printf("kick usb20\n");
};
}
break;
default:
break;
}
#if AUDIO_VOLUME_CONTROL_EN
rt_uint16_t min_volume,max_volume,res_volume,cur_volume;
#if AUDIO_MIC_EN
//设置设备非静音状态和音量大小
usbh_audio_set_mute(audio_class, "mic", 0);
//获取设备最大最小音量,设置音量大小
usbh_audio_get_cur_volume(audio_class, "mic", &cur_volume);
usbh_audio_get_min_volume(audio_class, "mic", &min_volume);
usbh_audio_get_max_volume(audio_class, "mic", &max_volume);
usbh_audio_get_res_volume(audio_class, "mic", &res_volume);
os_printf("[mic] min volume:%x,max volume:%x cur_volume:%x res_volume:%x\n",min_volume,max_volume,cur_volume,res_volume);
usbh_audio_set_volume(audio_class, "mic", max_volume); //默认设置最大音量
//usbh_audio_set_volume_db(audio_class, "mic", -127, min_volume, max_volume); //根据打印的可调dB范围设置
#endif
#if AUDIO_SPK_EN
//设置设备非静音状态
usbh_audio_set_mute(audio_class, "speaker", 0);
//获取设备最大最小音量,设置音量大小
usbh_audio_get_cur_volume(audio_class, "speaker", &cur_volume);
usbh_audio_get_min_volume(audio_class, "speaker", &min_volume);
usbh_audio_get_max_volume(audio_class, "speaker", &max_volume);
usbh_audio_get_res_volume(audio_class, "spekaer", &res_volume);
os_printf("[speaker] min volume:%x,max volume:%x cur_volume:%x res_volume:%x\n",min_volume,max_volume,cur_volume,res_volume);
usbh_audio_set_volume(audio_class, "speaker", max_volume); //默认设置最大音量
//usbh_audio_set_volume_db(audio_class, "speaker", -37, min_volume, max_volume); //根据打印的可调dB范围设置
#endif
#endif
//给设备分配pipe
#if AUDIO_MIC_EN
rtt_usbh_audio_dev_pipe_mange(0, "mic", AUDIO_ALLOC_PIPE);
#endif
#if AUDIO_SPK_EN
rtt_usbh_audio_dev_pipe_mange(0, "speaker", AUDIO_ALLOC_PIPE);
#endif
//USB发送打开UAC数据流命令
#if AUDIO_MIC_EN
ret = usbh_audio_open(audio_class, "mic", AUDIO_MIC_SAMPLING_FREQ);
if(ret != 0){
printf("mic open fail\n");
return -RT_ERROR;
}
#endif
#if AUDIO_SPK_EN
ret = usbh_audio_open(audio_class, "speaker", AUDIO_SPK_SAMPLING_FREQ);
if(ret != 0){
printf("speaker open fail\n");
return -RT_ERROR;
}
#endif
//应用层数据流初始化
#if AUDIO_MIC_EN
usbmic_room_init();
usbmic_enum_finish(&usb_dma_uac_irq_times);
#endif
#if AUDIO_SPK_EN
usbspk_room_init(AUDIO_TX_PACKET_SIZE);
usbspk_enum_finish(&usb_dma_uac_irq_times);
#endif
//使能端点收发,触发中断循环
#if AUDIO_MIC_EN
struct usb_device_dma_cfg dma_cfg;
dma_cfg.ep_index = (&g_audio_class[0])->pipe_in->pipe_index;
dma_cfg.ep_dir = USB_CORE_HOST_EP_RX;
dma_cfg.dma_addr = (rt_uint32_t *)g_audio_class[0].rx_buff;
dma_cfg.dma_len = AUDIO_RX_PACKET_SIZE;
usb_device_ioctl((struct usb_device *)p_dev, USB_HOST_KICK_EP_DMA, (rt_uint32_t)&dma_cfg, (rt_uint32_t)RT_NULL);
#endif
#if AUDIO_SPK_EN
usbspk_tx(p_dev, (&g_audio_class[0])->pipe_out->pipe_index, AUDIO_TX_PACKET_SIZE, _usbh_audio_spk_tx);
#endif
return RET_OK;
}
rt_uint32_t rtt_usbh_audio_user_close()
{
struct usbh_audio *audio_class = &g_audio_class[0];
rtt_usbh_audio_user_stop();
#if AUDIO_MIC_EN
rtt_usbh_audio_dev_pipe_mange(0, "mic", AUDIO_FREE_PIPE);
#endif
#if AUDIO_SPK_EN
rtt_usbh_audio_dev_pipe_mange(0, "speaker", AUDIO_FREE_PIPE);
#endif
#if AUDIO_MIC_EN
usbh_audio_close(audio_class, "mic");
#endif
#if AUDIO_SPK_EN
usbh_audio_close(audio_class, "speaker");
#endif
return RT_EOK;
}
rt_uint32_t rtt_usbh_audio_user_stop()
{
struct usb_device *p_dev = NULL;
uac_stop();
switch(g_audio_class[0].device->hcd->devid)
{
case HG_USB11_HOST_CONTROLLER_DEVID:
{
os_printf("HG_USB11_HOST_CONTROLLER_DEVID\n");
p_dev = (struct usb_device *)dev_get(HG_USB11HOST_DEVID);
if (p_dev) {
#if AUDIO_MIC_EN
hgusb11_v0_host_ep_abort(p_dev, USB_CORE_HOST_EP_RX, (&g_audio_class[0])->pipe_in->pipe_index);
#endif
#if AUDIO_SPK_EN
hgusb11_v0_host_ep_abort(p_dev, USB_CORE_HOST_EP_TX, (&g_audio_class[0])->pipe_out->pipe_index);
#endif
};
}
break;
case HG_USB_HOST_CONTROLLER_DEVID:
{
os_printf("HG_USB_HOST_CONTROLLER_DEVID\n");
p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
if (p_dev) {
#if AUDIO_MIC_EN
hgusb20_ep_rx_abort((struct hgusb20_dev *)p_dev, (&g_audio_class[0])->pipe_in->pipe_index);
#endif
#if AUDIO_SPK_EN
hgusb20_ep_tx_abort((struct hgusb20_dev *)p_dev, (&g_audio_class[0])->pipe_out->pipe_index);
#endif
};
}
break;
default:
break;
}
return RT_EOK;
}
rt_uint32_t rtt_usbh_audio_user_start()
{
struct usb_device *p_dev = NULL;
switch(g_audio_class[0].device->hcd->devid)
{
case HG_USB11_HOST_CONTROLLER_DEVID:
{
os_printf("HG_USB11_HOST_CONTROLLER_DEVID\n");
p_dev = (struct usb_device *)dev_get(HG_USB11HOST_DEVID);
if (p_dev) {
os_printf("kick usb11\n");
};
}
break;
case HG_USB_HOST_CONTROLLER_DEVID:
{
os_printf("HG_USB_HOST_CONTROLLER_DEVID\n");
p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID);
if (p_dev) {
os_printf("kick usb20\n");
};
}
break;
default:
break;
}
if(uac_open) {
uac_run = 1;
#if AUDIO_MIC_EN
struct usb_device_dma_cfg dma_cfg;
dma_cfg.ep_index = (&g_audio_class[0])->pipe_in->pipe_index;
dma_cfg.ep_dir = USB_CORE_HOST_EP_RX;
dma_cfg.dma_addr = (rt_uint32_t *)g_audio_class[0].rx_buff;
dma_cfg.dma_len = AUDIO_RX_PACKET_SIZE;
usb_device_ioctl((struct usb_device *)p_dev, USB_HOST_KICK_EP_DMA, (rt_uint32_t)&dma_cfg, (rt_uint32_t)RT_NULL);
#endif
#if AUDIO_SPK_EN
usbspk_tx((struct usb_device *)p_dev, (&g_audio_class[0])->pipe_out->pipe_index, AUDIO_TX_PACKET_SIZE, _usbh_audio_spk_tx);
#endif
}
return RT_EOK;
}
int32 demo_atcmd_usbh_audio(const char *cmd, char *argv[], uint32 argc)
{
if (*argv[0] == '1') {
if (*argv[1] == '1') {
rtt_usbh_audio_user_open();
}
if (*argv[1] == '0') {
rtt_usbh_audio_user_close();
}
} else if (*argv[0] == '2') {
if (*argv[1] == '1') {
}
if (*argv[1] == '0') {
}
}
printf("OK/n");
return 0;
}
void usbh_audio_thread_entry(void *arg)
{
//struct usbh_audio *audio_class = arg;
}
__attribute__((weak)) void usbh_audio_run(struct usbh_audio *audio_class)
{
rtt_usbh_audio_user_open();
#if 0
rt_thread_t usbh_audio_thread;
usbh_audio_thread = rt_thread_create("usbh_video_thread",
usbh_audio_thread_entry,
audio_class,
1024,
OS_TASK_PRIORITY_NORMAL,
20);
if(usbh_audio_thread != RT_NULL)
rt_thread_startup(usbh_audio_thread);
#endif
}
__attribute__((weak)) void usbh_audio_stop(struct usbh_audio *audio_class)
{
}
ucd_t rt_usbh_class_driver_audio(void)
{
usbh_audio_class.class_code = USB_CLASS_AUDIO;
usbh_audio_class.enable = rt_usbh_class_driver_audio_enable;
usbh_audio_class.disable = rt_usbh_class_driver_audio_disable;
return &usbh_audio_class;
}
#endif