`

Linux音频设备驱动-6

 
阅读更多

4/27/2010 11:46:27 PM

17.6.3 控制接口的实现
代码清单17.33第21行调用的snd_chip_uda1341_mixer_new()可以认为是UDA1341 ALSA驱动mixer控制组件的“构造函数”,其中会创建的控制元素的定义如代码清单17.39,包括一些枚举和单值元素。
代码清单17.39 UDA1341 ALSA驱动控制接口snd_kcontrol_new结构体
1 #define UDA1341_SINGLE(xname, where, reg, shift, mask, invert) /
2 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_uda1341_info_single, /
3 .get = snd_uda1341_get_single, .put = snd_uda1341_put_single, /
4 .private_value = where | (reg << 5) | (shift << 9) | (mask << 12) | (invert << 18) /
5 }
6
7 #define UDA1341_ENUM(xname, where, reg, shift, mask, invert) /
8 { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .info = snd_uda1341_info_enum, /
9 .get = snd_uda1341_get_enum, .put = snd_uda1341_put_enum, /
10 .private_value = where | (reg << 5) | (shift << 9) | (mask << 12) | (invert << 18) /
11 }
12
13 static struct snd_kcontrol_new snd_uda1341_controls[] =
14 {
15 UDA1341_SINGLE("Master Playback Switch", CMD_MUTE, data0_2, 2, 1, 1),
16 UDA1341_SINGLE("Master Playback Volume", CMD_VOLUME, data0_0, 0, 63, 1),
17
18 UDA1341_SINGLE("Bass Playback Volume", CMD_BASS, data0_1, 2, 15, 0),
19 UDA1341_SINGLE("Treble Playback Volume", CMD_TREBBLE, data0_1, 0, 3, 0),
20
21 UDA1341_SINGLE("Input Gain Switch", CMD_IGAIN, stat1, 5, 1, 0),
22 UDA1341_SINGLE("Output Gain Switch", CMD_OGAIN, stat1, 6, 1, 0),
23
24 UDA1341_SINGLE("Mixer Gain Channel 1 Volume", CMD_CH1, ext0, 0, 31, 1),
25 UDA1341_SINGLE("Mixer Gain Channel 2 Volume", CMD_CH2, ext1, 0, 31, 1),
26
27 UDA1341_SINGLE("Mic Sensitivity Volume", CMD_MIC, ext2, 2, 7, 0),
28
29 UDA1341_SINGLE("AGC Output Level", CMD_AGC_LEVEL, ext6, 0, 3, 0),
30 UDA1341_SINGLE("AGC Time Constant", CMD_AGC_TIME, ext6, 2, 7, 0),
31 UDA1341_SINGLE("AGC Time Constant Switch", CMD_AGC, ext4, 4, 1, 0),
32
33 UDA1341_SINGLE("DAC Power", CMD_DAC, stat1, 0, 1, 0),
34 UDA1341_SINGLE("ADC Power", CMD_ADC, stat1, 1, 1, 0),
35
36 UDA1341_ENUM("Peak detection", CMD_PEAK, data0_2, 5, 1, 0),
37 UDA1341_ENUM("De-emphasis", CMD_DEEMP, data0_2, 3, 3, 0),
38 UDA1341_ENUM("Mixer mode", CMD_MIXER, ext2, 0, 3, 0),
39 UDA1341_ENUM("Filter mode", CMD_FILTER, data0_2, 0, 3, 0),
40
41 UDA1341_2REGS("Gain Input Amplifier Gain (channel 2)", CMD_IG, ext4, ext5, 0, 0, 3, 31, 0),
42 };
从上述代码中宏UDA1341_SINGLE和UDA1341_ENUM的定义可知,单值元素的info()、get()、put()成员函数分别为 snd_uda1341_info_single()、snd_uda1341_get_single()和 snd_uda1341_put_single();枚举元素的info()、get()、put()成员函数分别为 snd_uda1341_info_enum()、snd_uda1341_get_enum()、和snd_uda1341_put_enum()。作为例子,代码清单17.40给出了单值元素相关函数的实现。
代码清单17.40 UDA1341 ALSA驱动控制接口单值元素info/get/put函数
1 static int snd_uda1341_info_single(struct snd_kcontrol *kcontrol, struct
2 snd_ctl_elem_info *uinfo)
3 {
4 int mask = (kcontrol->private_value >> 12) &63;
5
6 uinfo->type = mask == 1 ? SNDRV_CTL_ELEM_TYPE_BOOLEAN :
7 SNDRV_CTL_ELEM_TYPE_INTEGER;
8 uinfo->count = 1; //数量为1
9 uinfo->value.integer.min = 0; //最小值
10 uinfo->value.integer.max = mask; //最大值
11 return 0;
12 }
13
14 static int snd_uda1341_get_single(struct snd_kcontrol *kcontrol, struct
15 snd_ctl_elem_value *ucontrol)
16 {
17 struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
18 struct uda1341 *uda = clnt->driver_data;
19 int where = kcontrol->private_value &31;
20 int mask = (kcontrol->private_value >> 12) &63;
21 int invert = (kcontrol->private_value >> 18) &1;
22
23 ucontrol->value.integer.value[0] = uda->cfg[where]; //返回给ucontrol
24 if (invert) //如果反转
25 ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
26
27 return 0;
28 }
29
30 static int snd_uda1341_put_single(struct snd_kcontrol *kcontrol, struct
31 snd_ctl_elem_value *ucontrol)
32 {
33 struct l3_client *clnt = snd_kcontrol_chip(kcontrol);
34 struct uda1341 *uda = clnt->driver_data;
35 int where = kcontrol->private_value &31;
36 int reg = (kcontrol->private_value >> 5) &15;
37 int shift = (kcontrol->private_value >> 9) &7;
38 int mask = (kcontrol->private_value >> 12) &63;
39 int invert = (kcontrol->private_value >> 18) &1;
40 unsigned short val;
41
42 val = (ucontrol->value.integer.value[0] &mask);//从ucontrol获得值
43 if (invert) //如果反转
44 val = mask - val;
45
46 uda->cfg[where] = val;
47 return snd_uda1341_update_bits(clnt, reg, mask, shift, val, FLUSH);//更新位
48 }
17.7实例3:PXA255+AC97 ALSA驱动
Intel 公司的XScale PXA255是一款基于ARM5TE内核技术的嵌入式处理器。它提供了符合AC97 rev2.0标准的AC97控制单元(ACUNIT)和音频控制连接(AC-Link)。ACUNIT就是CODEC控制器,它通过AC-Link连接和控制AC97 CODEC芯片,例如Philips公司出品的一款符合AC97标准的多功能CODEC芯片UCB1400。它不仅是一枚CODEC芯片,还集成了触摸和能量管理两个功能模块,在嵌入式系统中应用广泛。
AC-Link 连接了ACUNIT 和UCB1400Codec,只要对ACUNIT寄存器操作就可以实现同UCBI400之间的数据传输。通过ACUNIT还可读写CODEC内部寄存器,实现对音频采样和混音处理的控制。当然这些读写操作也是经由AC-Link传输的。
Intel Xscale PXA255提供了16个DMA通道,可以很方便的为外围设备提供数据传送。ACUNIT也为CODEC的立体声输入输出和话筒输入提供了独立的16 bit数据通道。每个通道都有一个专门的FIFO。
由于它是一个标准的AC97设备,因此,其驱动的控制部分实现可以说是非常的简单,按照17.4.4节的要求,需要实现AC97 codec寄存器读写的硬件级函数pxa2xx_ac97_read()和pxa2xx_ac97_write(),并在模块初始化时注册相关的AC97 组件,如代码清单17.41。
代码清单17.41 PXA255连接AC97 codec ALSA驱动控制组件
1 static unsigned short pxa2xx_ac97_read(struct snd_ac97 *ac97, unsigned short
2 reg)
3 {
4 unsigned short val = - 1;
5 volatile u32 *reg_addr;
6
7 down(&car_mutex);
8
9 /* 设置首/次codec空间 */
10 reg_addr = (ac97->num &1) ? &SAC_REG_BASE: &PAC_REG_BASE;
11 reg_addr += (reg >> 1);
12
13 /* 通过ac97 link读 */
14 GSR = GSR_CDONE | GSR_SDONE;
15 gsr_bits = 0;
16 val = *reg_addr;
17 if (reg == AC97_GPIO_STATUS)
18 goto out;
19 if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) &GSR_SDONE, 1) <= 0
20 && !((GSR | gsr_bits) &GSR_SDONE))
21 //等待
22 {
23 printk(KERN_ERR "%s: read error (ac97_reg=%d GSR=%#lx)/n",
24 __FUNCTION__,reg, GSR | gsr_bits);
25 val = - 1;
26 goto out;
27 }
28
29 /* 置数据有效 */
30 GSR = GSR_CDONE | GSR_SDONE;
31 gsr_bits = 0;
32 val = *reg_addr;
33 /* 但是我们已经开启另一个周期... */
34 wait_event_timeout(gsr_wq, (GSR | gsr_bits) &GSR_SDONE, 1);
35
36 out: up(&car_mutex);
37 return val;
38 }
39
40 static void pxa2xx_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
41 unsigned short val)
42 {
43 volatile u32 *reg_addr;
44
45 down(&car_mutex);
46
47 /*设置首/次codec空间*/
48 reg_addr = (ac97->num &1) ? &SAC_REG_BASE: &PAC_REG_BASE;
49 reg_addr += (reg >> 1);
50
51 GSR = GSR_CDONE | GSR_SDONE;
52 gsr_bits = 0;
53 *reg_addr = val; //通过ac97 link写
54 if (wait_event_timeout(gsr_wq, (GSR | gsr_bits) &GSR_CDONE, 1) <= 0
55 && !((GSR | gsr_bits) &GSR_CDONE))
56 printk(KERN_ERR "%s: write error (ac97_reg=%d GSR=%#lx)/n",
57 __FUNCTION__,reg, GSR | gsr_bits);
58
59 up(&car_mutex);
60 }
61
62 static int pxa2xx_ac97_probe(struct platform_device *dev)
63 {
64 struct snd_card *card;
65 struct snd_ac97_bus *ac97_bus;
66 struct snd_ac97_template ac97_template;
67 int ret;
68
69 ret = - ENOMEM;
70 /* 新建card */
71 card = snd_card_new(SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1, THIS_MODULE, 0);
72 if (!card)
73 goto err;
74 card->dev = &dev->dev;
75 strncpy(card->driver, dev->dev.driver->name, sizeof(card->driver));
76
77 /* 构造pcm组件 */
78 ret = pxa2xx_pcm_new(card, &pxa2xx_ac97_pcm_client, &pxa2xx_ac97_pcm);
79 if (ret)
80 goto err;
81
82 /* 申请中断 */
83 ret = request_irq(IRQ_AC97, pxa2xx_ac97_irq, 0, "AC97", NULL);
84 if (ret < 0)
85 goto err;
86
87 ...
88
89 /* 初始化ac97 bus */
90 ret = snd_ac97_bus(card, 0, &pxa2xx_ac97_ops, NULL, &ac97_bus);
91 if (ret)
92 goto err;
93 memset(&ac97_template, 0, sizeof(ac97_template));
94 ret = snd_ac97_mixer(ac97_bus, &ac97_template, &pxa2xx_ac97_ac97);
95 if (ret)
96 goto err;
97 ...
98
99 /* 注册card */
100 ret = snd_card_register(card);
101 if (ret == 0)
102 {
103 platform_set_drvdata(dev, card);
104 return 0;
105 }
106
107 err: if (card)
108 snd_card_free(card);
109 ...
110
111 returns ret;
112 }
17.8总结
音频设备接口包括PCM、IIS和AC97几种,分别适用于不同的应用场合。针对音频设备,Linux内核中包含了2类音频设备驱动框架,OSS和 ALSA,前者包含dsp和mixer字符设备接口,在用户空间的编程中,完全使用文件操作;后者以card和组件(pcm、mixer等)为主线,在用户空间的编程中不使用文件接口而使用alsalib。
在音频设备驱动中,几乎必须使用DMA,而DMA的缓冲区会被分割成一个一个的段,每次 DMA操作进行其中的一段。OSS驱动的阻塞读写具有流控能力,在用户空间不需要进行流量方面的定时工作,但是它需要及时的写(播放)和读(录音),以免出现缓冲区的underflow或overflow。
分享到:
评论

相关推荐

    华清远见驱动教程

    -第1章、设备驱动概述 ...-第17章、Linux音频设备驱动 -第18章、LCD设备驱动 -第19章、Flash设备驱动 -第20章、USB主机与设备驱动 -第21章、PCI设备驱动 -第22章、Linux设备驱动的调试 -第23章、Linux设备驱动的移植

    Linux音频设备驱动

    对linux的音频驱动讲解的非常到为,写的非常到好,这是大神级别到

    8810音频驱动linux-android。完整资料.zip

    在音频设备驱动中ASoC被分为Machine、Platform和Codec三大部分。 Codec部分:负责音频解码,这部分代码全然无平台无关(设备原厂提供) Platform部分:包括了平台的音频DMA和音频接口的配置和控制(I2S,PCM。AC97...

    Linux设备驱动详解第二版

    第17章 Linux音频设备驱动 388 第18章 LCD设备驱动 440 第19章 Flash设备驱动 479 第20章 USB主机与设备驱动 507 第21章 PCI设备驱动 547 第4篇 Linux设备驱动调试、移植 第22章 Linux设备驱动的...

    arm linux利用alsa驱动并使用usb音频设备

    主要介绍了arm linux利用alsa驱动并使用usb音频设备的相关资料,需要的朋友可以参考下

    Linux设备驱动程序开发详解

    字符设备、块设备、TTY设备、I2C设备、LCD设备、音频设备、USB设备、网络设备、PCI设备等Linux设备驱动的架构和框架中各个复杂数据架构和函数的关系,并讲解了Linux驱动开发的大量实例,使读者能够独立开发各类Linux...

    嵌入式Linux设备驱动开发详解

    本书特色:本书系统地介绍了嵌入式Linux设备驱动开发的相关知识和实例,主要包括: 数码管驱动程序;键盘驱动程序;A/D、D/A驱动程序;LCD驱动程序;触摸屏驱动程序;CAN总线驱动程序;I2C总线驱动程序;音频总线...

    linux设备驱动详解(宋宝华 高清 非影印版)

    字符设备、块设备、TTY设备、IC设备、LCD设备、音频设备、USB设备、网络设备、PCI设备等Linux设备驱动的架构和框架中各个复杂数据架构和函数的关系,并讲解了Linux驱动开发的大量实例,使读者能够独立开发各类Linux...

    精通LINUX设备驱动程序开发

     第6章 串行设备驱动程序   第7章 输入设备驱动程序   第8章 I2C协议  第9章 PCMCIA和CF   第10章 PCI   第11章 USB  第12章 视频驱动程序   第13章 音频驱动程序   第14章 块设备驱动程序...

    精通Linux设备驱动程序开发

    第6章 串行设备驱动程序 第7章 输入设备驱动程序 第8章 I2C协议 第9章 PCMCIA和CF 第10章 PCI 第11章 USB 第12章 视频驱动程序 第13章 音频驱动程序 第14章 块设备驱动程序 第15章 网络接口卡 第16章 ...

    Linux 蓝牙协议栈的USB+设备驱动

    给出实现蓝牙设备驱动的重要数据结构和流程,并总结Linux 下开发蓝牙USB 设备驱动的一般方法和关键技术。 关键词:Linux 系统;蓝牙协议栈;设备驱动 USB Device Driver for Linux Bluetooth Stack LIANG Jun-xue...

    《Linux 设备驱动开发详解》第一版第一次印刷勘误

    字符设备、块设备、TTY设备、IC设备、LCD设备、音频设备、USB设备、网络设备、PCI设备等Linux设备驱动的架构和框架中各个复杂数据架构和函数的关系,并讲解了Linux驱动开发的大量实例,使读者能够独立开发各类Linux...

    精通linux设备驱动程序开发

    《精通Linux设备驱动程序开发》是Linux设备驱动程序开发领域的权威著作。全书基于2.6内核,不仅透彻讲解了基本概念和技术,更深人探讨了其他书没有涵盖或浅尝辄止的许多重要主题和关键难点,如PCMCIA、I2C和USB等...

    Linux设备驱动开发

    字符设备、块设备、TTY设备、I2C设备、LCD设备、音频设备、USB设备、网络设备、PCI设备等Linux设备驱动的架构和框架中各个复杂数据架构和函数的关系,并讲解了Linux驱动开发的大量实例,使读者能够独立开发各类Linux...

    Linux_alsa.zip_alsa_linux 音频驱动

    Linux alsa 音频设备驱动文件

    \精通Linux设备驱动程序开发

    《精通Linux设备驱动程序开发》是Linux设备驱动程序开发领域的权威著作。全书基于2.6内核,不仅透彻讲解了基本概念和技术,更深人探讨了其他书没有涵盖或浅尝辄止的许多重要主题和关键难点,如PCMCIA、I2C和USB等...

    嵌入式Linux设备驱动开发

    字符设备、块设备、TTY设备、I2C设备、LCD设备、音频设备、USB设备、网络设备、PCI设备等Linux设备驱动的架构和框架中各个复杂数据架构和函数的关系,并讲解了大量Linux驱动开发的大量实例,使读者能够独立开发各类...

    嵌入式Linux设备驱动开发视频教程

    linux嵌入式开发 教程描述:介绍Linux设备驱动...字符设备、块设备、TTY设备、I2C设备、LCD设备、音频设备、USB设备、网络设备、PCI设备等Linux设备驱动的架构和框架中各个复杂数据架构和函数的关系,并讲解了Linux

Global site tag (gtag.js) - Google Analytics