USB Gadget UAC1实现分析
对于USB Gdaget驱动,有两个结构体,分别代表实例usb_function_instance(模板)和实例本身usb_function。
其中包含了usb_function_instance的结构体中包含了通过fsconfig可配置的参数,而包含了usb_function的结构体包含了设备的相关回调函数。
根通UAC1代码的f_audio_bind可知,由于UAC1通过gadget创建一个UAC扬声器,对于收到的PCM数据,其通过ALSA的playback设置即/dev/snd/pcmCoD0p来最终输出
而在f_audio_bind函数中调用gaudio_setup根据/dev/snd/pcmCoD0p设备信息初始化gadget设备信息。
uac playback ——> usb gadget ——->板载/dev/snd/pcmCoD0p
f_uac1_opts
f_uac1_opt由f_audio_alloc_inst函数实现,发生于:
mkdir -p functions/uac1.usb0
在 UAC1驱动中,usb_function_instance对应的结体为f_uac1_opts
struct f_uac1_opts {
struct usb_function_instance func_inst;
int req_buf_size; //48000
int req_count;//256
int audio_buf_size;//200
char *fn_play;// /dev/snd/pcmC0D0p
char *fn_cap;// /dev/snd/pcmC0D0c
char *fn_cntl;// /dev/snd/pcmC0D0p
unsigned bound:1;
unsigned fn_play_alloc:1;
unsigned fn_cap_alloc:1;
unsigned fn_cntl_alloc:1;
struct mutex lock;
int refcnt;
};
其可配置参数为
root@ATK-IMX6U:/sys/kernel/config/usb_gadget/g1/functions/uac1.usb0# ls
audio_buf_size fn_cap fn_cntl fn_play req_buf_size req_count
对应于f_uac1_opts相应的成员。
f_audio
f_audio是实例,其创建发生于
mkdir -p configs/c.1
ln -s functions/uac1.usb0 configs/c.1/
其主要功能是初始化初始化gaudio的usb_function回调函数。
struct gaudio_snd_dev {
struct gaudio *card;
struct file *filp;
struct snd_pcm_substream *substream;
int access;
int format;
int channels;
int rate;
};
struct gaudio {
struct usb_function func;
struct usb_gadget *gadget;
/* ALSA sound device interfaces */
struct gaudio_snd_dev control;
struct gaudio_snd_dev playback;
struct gaudio_snd_dev capture;
};
struct f_audio {
struct gaudio card;
/* endpoints handle full and/or high speeds */
struct usb_ep *out_ep;
spinlock_t lock;
struct f_audio_buf *copy_buf;
struct work_struct playback_work;
struct list_head play_queue;
/* Control Set command */
struct list_head cs;
u8 set_cmd;
struct usb_audio_control *set_con;
};
对usb_function回调的函数初始化还是老三样:
audio->card.func.bind = f_audio_bind; //启用UDC时连接回调
audio->card.func.set_alt = f_audio_set_alt;//选择接口
audio->card.func.setup = f_audio_setup;//控制请求
audio->card.func.disable = f_audio_disable;
audio->card.func.unbind = f_audio_unbind;//禁用UDC
audio->card.func.free_func = f_audio_free;//释内实例
f_audio_bind
启用UDC时,先执行f_audio_bind函数。
f_audio_bind调用gaudio_setup初始化与linux设备端的uac设备信息,并建立文件打开链接。这些设备默认如下:
playback:/dev/snd/pcmC0D0p
capture:/dev/snd/pcmC0D0p
control:/dev/snd/pcmC0D0c
然后根据上面playback打开的设备实际参数信息修改gadget uac设备的相关描述符信息,这些参数包括:通道数、采样率
然后根调用usb_interface_id给uac控制和数据流接口描述符分析接口描述符的id.
//audo control
status = usb_interface_id(c, f);//allocate an unused interface ID
ac_interface_desc.bInterfaceNumber = status;
//audo streaming
status = usb_interface_id(c, f);
as_interface_alt_0_desc.bInterfaceNumber = status;
as_interface_alt_1_desc.bInterfaceNumber = status;
分配端点信息
ep = usb_ep_autoconfig(cdev->gadget, &as_out_ep_desc);
audio->out_ep = ep;
audio->out_ep->desc = &as_out_ep_desc;
ep->driver_data = cdev; /* claim */
最后是调用usb_assign_descriptors构建配置描述符,这里只有全速和高速的,没有超高速的。
status = usb_assign_descriptors(f, f_audio_desc, f_audio_desc, NULL);
描述符数组如下:
static struct usb_descriptor_header *f_audio_desc[] = {
(struct usb_descriptor_header *)&ac_interface_desc,//音频控制接口描述符
(struct usb_descriptor_header *)&ac_header_desc,//Audio Control Interface Header Descriptor
(struct usb_descriptor_header *)&input_terminal_desc,// Audio Control Input Terminal Descriptor
(struct usb_descriptor_header *)&output_terminal_desc,// Audio Control Feature Unit Descriptor
(struct usb_descriptor_header *)&feature_unit_desc,//Audio Control Output Terminal Descriptor
(struct usb_descriptor_header *)&as_interface_alt_0_desc,//音频流接口描述符
(struct usb_descriptor_header *)&as_interface_alt_1_desc,//音频流接口描述符(备用接口描述符)
(struct usb_descriptor_header *)&as_header_desc, // Audio Streaming Interface Descriptor
(struct usb_descriptor_header *)&as_type_i_desc,//Audio Streaming Format Type Descriptor
(struct usb_descriptor_header *)&as_out_ep_desc,//Endpoint Descriptor
(struct usb_descriptor_header *)&as_iso_out_desc,//Audio Data Endpoint Descriptor
NULL,
};
通过分析其配置描述符,确实只有一个UAC扬声器设备,没有麦克风。如果需要,需要自行修改源代码。