本文是基于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接口的调用相关推荐

  1. 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 ...

  2. STM32MP157驱动开发——Linux 音频驱动

    STM32MP157驱动开发--Linux 音频驱动 一.简介 1.CS42L51 简介 2.I2S总线 3.STM32MP1 SAI 总线接口 二.驱动开发 1.音频驱动 1)修改设备树 i2c 接 ...

  3. Linux音频驱动之一:音频驱动注册流程

    本文是基于mini2440开发板Linux版本号是linux-2.6.32.2的学习笔记 一.uda134x平台设备的注册 static struct s3c24xx_uda134x_platform ...

  4. Linux设备驱动模型二 kobject

    Linux设备驱动模型二 kobject 1 kobject 1.1 kobject数据结构 kobject是sysfs文件系统的基础数据结构,它定义在include/linux/kobjec.h中 ...

  5. Linux 音频驱动(四) ASoC音频驱动之Machine驱动

    目录 1. 基本介绍 2. 源码分析 2.1. Machine数据结构 struct snd_soc_dai_link 3. 声卡 3.1. 数据结构struct snd_soc_card 3.2. ...

  6. Linux 音频驱动(五) ALSA音频驱动之PCM逻辑设备

    目录 1. 前言 2. PCM逻辑设备 2.1. 创建 PCM逻辑设备: 2.2. PCM逻辑设备文件操作函数集:snd_pcm_f_ops[] 2.3. Open PCM逻辑设备 2.4. Writ ...

  7. linux 音频架构绕过,linux音频驱动架构

    1.linux音频驱动架构分为3部分组成:硬件无关层(核心层ALSA).板级音频数字接口层驱动(McASP.McBSP等).外部codes驱动 sound/soc/davinci/ti81xx-etv ...

  8. 转载:Linux音频驱动-OSS和ALSA声音系统简介及其比较

    Linux音频驱动-OSS和ALSA声音系统简介及其比较 概述 昨天想在Ubuntu上用一下HTK工具包来绘制语音信号的频谱图和提取MFCC的结果,但由于前段时间把Ubuntu升级到13.04,系统的 ...

  9. Linux 音频驱动

    Linux 音频驱动 硬件介绍 WM8960与IMX6ULL之间有两个通信接口:I2C和I2S 其中I2C用于配置WM8960 I2S用于音频数据传输 修改设备树文件 编写I2C子节点设备树 code ...

最新文章

  1. 企业家Scott Gerber:小公司应用开发的十条建议
  2. java servlet文件下载_Java之Servlet文件下载20190228
  3. linux apache mod_jk,Linux上安装Apache,安装mod_jk,相关配置
  4. vscode 调试.net core 2.0 输出乱码解决方法
  5. 未来十年,小程序将消失!
  6. Hadoop生态圈-Flume的组件之sink处理器
  7. VS2010调试技巧
  8. 简单html,用CSS设计一个留言板
  9. 计算机三级网络技术上机,计算机三级网络技术上机部分(南开100题题库)
  10. SecureCRT Win免安装版本,简单好用
  11. 脑机接口技术介绍、应用与挑战
  12. javascript history对象详解
  13. jcp jsr_JCP成为“可怕的单一文化”
  14. Python常用数字处理基本操作汇总
  15. 2021年化工自动化控制仪表考试题及化工自动化控制仪表考试试卷
  16. 微信发布的辟谣小程序
  17. 题解 CF1395A 【Boboniu Likes to Color Balls】
  18. maven 项目 springMVC实现文件图片的上传下载功能详解(源码已提供,小白必看)
  19. 群硕入列FoodTalks优质供应商地图数字化板块
  20. 旋转编码器(STM32)

热门文章

  1. php 车牌号限号,不限行也不限号!还能送车牌?这种车你考虑吗?
  2. 通过Guest账号共享XP上的打印机
  3. 从K个数组中任取一个字符串进行按顺序拼接
  4. E - Obstacle Course的详细解答
  5. Cisco 新兴网络技术考试答案
  6. 互联网究竟是怎么诞生的?
  7. 滥用无限授权--你的地址还安全吗?
  8. 计算机辅助设计绘图员技能鉴定试题(建筑类),计算机辅助设计高级绘图员技能鉴定试题...
  9. 电脑操作系统 GUI 进化史
  10. 新手玩转Linux Kernel漏洞之Null Pointer Dereference