Linux音频驱动之二:Control接口的调用
本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记
一. control接口说明
Control接口主要让用户空间的应用程序(alsa-lib)可以访问和控制音频codec芯片中的多路开关,滑动控件等。
二.control接口的open
由“Linux音频驱动之一:音频驱动注册流程”这篇文章可知,control device调用的是snd_ctl_dev_register函数注册的。
static int snd_ctl_dev_register(struct snd_device *device)
{struct snd_card *card = device->device_data;int err, cardnum;char name[16];if (snd_BUG_ON(!card))return -ENXIO;cardnum = card->number;if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))return -ENXIO;sprintf(name, "controlC%i", cardnum);if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,&snd_ctl_f_ops, card, name)) < 0)return err;return 0;
}
传入的f_ops是snd_ctl_f_ops,如下面所示。
static const struct file_operations snd_ctl_f_ops =
{.owner = THIS_MODULE,.read = snd_ctl_read,.open = snd_ctl_open,.release = snd_ctl_release,.poll = snd_ctl_poll,.unlocked_ioctl = snd_ctl_ioctl,.compat_ioctl = snd_ctl_ioctl_compat,.fasync = snd_ctl_fasync,
};
当打开control device设备时,就会调用上面的snd_ctl_open函数。
进入snd_ctl_open函数分析。
- 获取snd_card数据。
card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);mreg = snd_minors[minor];private_data = mreg->private_data;
iminor(inode) = MINOR(inode->i_rdev)
inode->i_rdev是文件对应设备的设备号,MINOR(inode->i_rdev)是次设备号。
我们在control device这个设备注册的时候,在snd_minors数组里面寻找一个没有使用的元素,把fops,snd_card,type等信息保存。把该元素的下标minor作为次设备号。
主设备号是116
#define CONFIG_SND_MAJOR 116
dev_t = 116 << 20 | minor
最后把dev_t注册进了内核。
现在open时根据次设备号找到snd_minors[minor],得到snd_card数据。
- 调用snd_card_file_add函数
这个函数将打开的文件保存,放入了snd_card的files_list链表。作用是用于跟踪连接状态,避免热插拔释放繁忙资源。
int snd_card_file_add(struct snd_card *card, struct file *file)
{struct snd_monitor_file *mfile;mfile = kmalloc(sizeof(*mfile), GFP_KERNEL);if (mfile == NULL)return -ENOMEM;mfile->file = file;mfile->disconnected_f_op = NULL;spin_lock(&card->files_lock);if (card->shutdown) {spin_unlock(&card->files_lock);kfree(mfile);return -ENODEV;}list_add(&mfile->list, &card->files_list);spin_unlock(&card->files_lock);return 0;
}
- 申请一个snd_ctl_file结构体,保存snd_card等信息,并把它赋值给了file->private_data,后面通过file->private_data可以访问到snd_card等信息。
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
ctl->card = card;
ctl->prefer_pcm_subdevice = -1;
ctl->prefer_rawmidi_subdevice = -1;
ctl->pid = current->pid;
file->private_data = ctl;
- 把snd_ctl_file添加到snd_card的ctl_files链表。
list_add_tail(&ctl->list, &card->ctl_files);
三. control接口的write操作
control接口的write操作通过要snd_ctl_ioctl。进入snd_ctl_ioctl函数。
通过file->private_data得到snd_ctl_file,通过snd_ctl_file得到snd_card。
ctl = file->private_data;
card = ctl->card;
write操作调用的接口是snd_ctl_elem_write_user。
进入snd_ctl_elem_write_user函数看一下。
- 从用户空间拷贝数据到内核。数据类型是snd_ctl_elem_value
control = memdup_user(_control, sizeof(*control));
- 写snd_ctl_elem_value数据。
result = snd_ctl_elem_write(card, file, control);
进入snd_ctl_elem_write函数。
- 根据用户传进来的snd_ctl_elem_value的ID找到对应的snd_kcontrol。
在声卡初始化的时候底层有注册20个snd_kcontrol到snd_card的controls链表。
kctl = snd_ctl_find_id(card, &control->id);
- 调用kctl->put函数。
result = kctl->put(kctl, control);
kctl->put函数在snd_kcontrol注册前赋值,函数是snd_soc_put_volsw
四. snd_soc_put_volsw函数
以音量设置的control为例。
uda1341_snd_controls[0] =
{.iface = SNDRV_CTL_ELEM_IFACE_MIXER,.name = "Master Playback Volume",.info = snd_soc_info_volsw,.get = snd_soc_get_volsw,.put = snd_soc_put_volsw,.private_value ={soc_mixer_control.reg = UDA134X_DATA000,soc_mixer_control.shift = 0,soc_mixer_control.rshift = 0,soc_mixer_control.max = 0x3F,soc_mixer_control.invert = 1,},
}
- 根据snd_kcontrol得到soc_mixer_control和snd_soc_codec
struct soc_mixer_control *mc = (struct soc_mixer_control *)kcontrol->private_value;
struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
- 计算部分
unsigned int reg = mc->reg;unsigned int shift = mc->shift;unsigned int rshift = mc->rshift;int max = mc->max;unsigned int mask = (1 << fls(max)) - 1;unsigned int invert = mc->invert;unsigned int val, val2, val_mask;val = (ucontrol->value.integer.value[0] & mask);if (invert)val = max - val;val_mask = mask << shift;val = val << shift;if (shift != rshift) {val2 = (ucontrol->value.integer.value[1] & mask);if (invert)val2 = max - val2;val_mask |= mask << rshift;val |= val2 << rshift;}
reg = UDA134X_DATA000;
shift = 0;
rshift = 0;
max = 0x3f;
fls(max),max最高位的位置,fls(max) = 6, mask = 0x3f;
invert是否反转,invert = 1,需要反转;
val,用户空间给的值,反转的话,需要用最大值减,值越大,音量越大,需要设置到寄存器的值越小;
val_mask = 0x3f << 0;
val = val << 0;
shift != rshift的情况,猜测是左右声道需要分别设置,我们这里不需要设置。
- 调用snd_soc_update_bits函数
snd_soc_update_bits(codec, reg, val_mask, val);snd_soc_write(codec, reg, new);codec->write(codec, reg, val);
codec->write = uda134x_write
uda134x_write函数在“Linux音频驱动之五:UDA1341芯片操作接口”中分析了,这里不在分析,就是写寄存器的值。
参考博客:
https://blog.csdn.net/sunweizhong1024/article/details/7697363
https://blog.csdn.net/droidphone/article/details/6409983
Linux音频驱动之二:Control接口的调用相关推荐
- Linux 音频驱动(二) ASoC音频驱动之Platform驱动
目录 1. 简介 2. 源码分析 2.1. CPU DAI 2.1.1. 数据结构struct snd_soc_dai_driver 2.1.2. 注册CPU DAI:snd_soc_register ...
- STM32MP157驱动开发——Linux 音频驱动
STM32MP157驱动开发--Linux 音频驱动 一.简介 1.CS42L51 简介 2.I2S总线 3.STM32MP1 SAI 总线接口 二.驱动开发 1.音频驱动 1)修改设备树 i2c 接 ...
- Linux音频驱动之一:音频驱动注册流程
本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记 一.uda134x平台设备的注册 static struct s3c24xx_uda134x_platform ...
- Linux设备驱动模型二 kobject
Linux设备驱动模型二 kobject 1 kobject 1.1 kobject数据结构 kobject是sysfs文件系统的基础数据结构,它定义在include/linux/kobjec.h中 ...
- Linux 音频驱动(四) ASoC音频驱动之Machine驱动
目录 1. 基本介绍 2. 源码分析 2.1. Machine数据结构 struct snd_soc_dai_link 3. 声卡 3.1. 数据结构struct snd_soc_card 3.2. ...
- Linux 音频驱动(五) ALSA音频驱动之PCM逻辑设备
目录 1. 前言 2. PCM逻辑设备 2.1. 创建 PCM逻辑设备: 2.2. PCM逻辑设备文件操作函数集:snd_pcm_f_ops[] 2.3. Open PCM逻辑设备 2.4. Writ ...
- linux 音频架构绕过,linux音频驱动架构
1.linux音频驱动架构分为3部分组成:硬件无关层(核心层ALSA).板级音频数字接口层驱动(McASP.McBSP等).外部codes驱动 sound/soc/davinci/ti81xx-etv ...
- 转载:Linux音频驱动-OSS和ALSA声音系统简介及其比较
Linux音频驱动-OSS和ALSA声音系统简介及其比较 概述 昨天想在Ubuntu上用一下HTK工具包来绘制语音信号的频谱图和提取MFCC的结果,但由于前段时间把Ubuntu升级到13.04,系统的 ...
- Linux 音频驱动
Linux 音频驱动 硬件介绍 WM8960与IMX6ULL之间有两个通信接口:I2C和I2S 其中I2C用于配置WM8960 I2S用于音频数据传输 修改设备树文件 编写I2C子节点设备树 code ...
最新文章
- 企业家Scott Gerber:小公司应用开发的十条建议
- java servlet文件下载_Java之Servlet文件下载20190228
- linux apache mod_jk,Linux上安装Apache,安装mod_jk,相关配置
- vscode 调试.net core 2.0 输出乱码解决方法
- 未来十年,小程序将消失!
- Hadoop生态圈-Flume的组件之sink处理器
- VS2010调试技巧
- 简单html,用CSS设计一个留言板
- 计算机三级网络技术上机,计算机三级网络技术上机部分(南开100题题库)
- SecureCRT Win免安装版本,简单好用
- 脑机接口技术介绍、应用与挑战
- javascript history对象详解
- jcp jsr_JCP成为“可怕的单一文化”
- Python常用数字处理基本操作汇总
- 2021年化工自动化控制仪表考试题及化工自动化控制仪表考试试卷
- 微信发布的辟谣小程序
- 题解 CF1395A 【Boboniu Likes to Color Balls】
- maven 项目 springMVC实现文件图片的上传下载功能详解(源码已提供,小白必看)
- 群硕入列FoodTalks优质供应商地图数字化板块
- 旋转编码器(STM32)