在Linux中,先后出现了音频设备的两种框架OSS和ALSA,本节将在介绍数字音频设备及音频设备硬件接口的基础上,展现OSS和ALSA驱动的结构。
17.1~17.2节讲解了音频设备及PCM、IIS和AC97硬件接口。
17.3节阐述了Linux OSS音频设备驱动的组成、mixer接口、dsp接口及用户空间编程方法。
17.4节阐述了Linux ALSA音频设备驱动的组成、card和组件管理、PCM设备、control接口、AC97 API及用户空间编程方法。
17.5节以S3C2410通过IIS接口外接UDA1341编解码器的实例讲解了OSS驱动。
17.6节以PXA255通过AC97接口外接AC97 编解码器的实例讲解了ALSA驱动。
17.1数字音频设备
目前,手机、PDA、MP3等许多嵌入式设备中包含了数字音频设备,一个典型的数字音频系统的电路组成如图17.1所示。图17.1中的嵌入式微控制器 /DSP中集成了PCM、IIS或AC97音频接口,通过这些接口连接外部的音频编解码器即可实现声音的AD和DA转换,图中的功放完成模拟信号的放大功能。
图17.1 典型的数字音频系统电路
音频编解码器是数字音频系统的核心,衡量它的指标主要有:
? 采样频率
采样的过程就是将通常的模拟音频信号的电信号转换成二进制码0和1的过程,这些0和1便构成了数字音频文件。如图17.2中的正弦曲线代表原始音频曲线,方格代表采样后得到的结果,二者越吻合说明采样结果越好。
采样频率是每秒钟的采样次数,我们常说的 44.1kHz 采样频率就是每秒钟采样44100 次。理论上采样频率越高,转换精度越高,目前主流的采样频率是48kHz。
? 量化精度
量化精度是指对采样数据分析的精度,比如24bit量化精度就是是将标准电平信号按照2的24次方进行分析,也就是说将图17.2中的纵坐标等分为224等分。量化精度越高,声音就越逼真。
图17.2 数字音频采样
17.2音频设备硬件接口
17.2.1 PCM接口
针对不同的数字音频子系统,出现了几种微处理器或DSP与音频器件间用于数字转换的接口。
最简单的音频接口是PCM(脉冲编码调制)接口,该接口由时钟脉冲(BCLK)、帧同步信号(FS)及接收数据(DR)和发送数据(DX)组成。在FS信号的上升沿,数据传输从MSB(Most Significant Bit)字开始,FS频率等于采样率。FS信号之后开始数据字的传输,单个的数据位按顺序进行传输,1个时钟周期传输1个数据字。发送MSB时,信号的等级首先降到最低,以避免在不同终端的接口使用不同的数据方案时造成MSB的丢失。
PCM接口很容易实现,原则上能够支持任何数据方案和任何采样率,但需要每个音频通道获得一个独立的数据队列。
17.2.2 IIS接口
IIS 接口(Inter-IC Sound)在20世纪80年代首先被飞利浦用于消费音频,并在一个称为LRCLK(Left/Right CLOCK)的信号机制中经过多路转换,将两路音频信号变成单一的数据队列。当LRCLK为高时,左声道数据被传输;LRCLK为低时,右声道数据被传输。与PCM相比,IIS更适合于立体声系统。对于多通道系统,在同样的BCLK和LRCLK条件下,并行执行几个数据队列也是可能的。
17.2.3 AC97接口
AC'97(Audio Codec 1997)是以Intel为首的五个PC厂商Intel、Creative Labs、NS、Analog Device与Yamaha共同提出的规格标准。与PCM和IIS不同,AC'97不只是一种数据格式,用于音频编码的内部架构规格,它还具有控制功能。 AC'97采用AC-Link与外部的编解码器相连,AC-Link接口包括位时钟(BITCLK)、同步信号校正(SYNC)和从编码到处理器及从处理器中解码(SDATDIN与SDATAOUT)的数据队列。AC'97数据帧以SYNC脉冲开始,包括12个20位时间段(时间段为标准中定义的不同的目的服务)及16位“tag”段,共计256个数据序列。例如,时间段“1”和“2”用于访问编码的控制寄存器,而时间段“3”和“4”分别负载左、右两个音频通道。“tag”段表示其他段中哪一个包含有效数据。把帧分成时间段使传输控制信号和音频数据仅通过4根线到达9个音频通道或转换成其他数据流成为可能。与具有分离控制接口的IIS方案相比,AC'97明显减少了整体管脚数。一般来说,AC'97 编解码器采用TQFP48封装,如图17.3所示。
图17.3 AC97 Codec芯片
PCM、IIS和AC97各有其优点和应用范围,例如在CD、MD、MP3随身听多采用IIS接口,移动电话会采用PCM接口,具有音频功能的PDA则多使用和PC一样的AC'97编码格式。
17.3 Linux OSS音频设备驱动
17.3.1 OSS驱动的组成
OSS标准中有2个最基本的音频设备:mixer(混音器)和DSP(数字信号处理器)。
在声卡的硬件电路中,mixer是一个很重要的组成部分,它的作用是将多个信号组合或者叠加在一起,对于不同的声卡来说,其混音器的作用可能各不相同。OSS驱动中,/dev/mixer设备文件是应用程序对mixer进行操作的软件接口。
混音器电路通常由两个部分组成:输入混音器(input mixer)和输出混音器(output mixer)。输入混音器负责从多个不同的信号源接收模拟信号,这些信号源有时也被称为混音通道或者混音设备。模拟信号通过增益控制器和由软件控制的音量调节器后,在不同的混音通道中进行级别(level)调制,然后被送到输入混音器中进行声音的合成。混音器上的电子开关可以控制哪些通道中有信号与混音器相连,有些声卡只允许连接一个混音通道作为录音的音源,而有些声卡则允许对混音通道做任意的连接。经过输入混音器处理后的信号仍然为模拟信号,它们将被送到A/D转换器进行数字化处理。
输出混音器的工作原理与输入混音器类似,同样也有多个信号源与混音器相连,并且事先都经过了增益调节。当输出混音器对所有的模拟信号进行了混合之后,通常还会有一个总控增益调节器来控制输出声音的大小,此外还有一些音调控制器来调节输出声音的音调。经过输出混音器处理后的信号也是模拟信号,它们最终会被送给喇叭或者其它的模拟输出设备。对混音器的编程包括如何设置增益控制器的级别,以及怎样在不同的音源间进行切换,这些操作通常来讲是不连续的,而且不会像录音或者放音那样需要占用大量的计算机资源。由于混音器的操作不符合典型的读/写操作模式,因此除了 open()和close()两个系统调用之外,大部分的操作都是通过ioctl()系统调用来完成的。与/dev/dsp不同,/dev/mixer允许多个应用程序同时访问,并且混音器的设置值会一直保持到对应的设备文件被关闭为止。
DSP也称为编解码器,实现录音(录音)和放音(播放),其对应的设备文件是/dev/dsp或/dev/sound/dsp。OSS声卡驱动程序提供的 /dev/dsp是用于数字采样和数字录音的设备文件,向该设备写数据即意味着激活声卡上的D/A转换器进行放音,而向该设备读数据则意味着激活声卡上的 A/D转换器进行录音。
在从DSP设备读取数据时,从声卡输入的模拟信号经过A/D转换器变成数字采样后的样本,保存在声卡驱动程序的内核缓冲区中,当应用程序通过 read()系统调用从声卡读取数据时,保存在内核缓冲区中的数字采样结果将被复制到应用程序所指定的用户缓冲区中。需要指出的是,声卡采样频率是由内核中的驱动程序所决定的,而不取决于应用程序从声卡读取数据的速度。如果应用程序读取数据的速度过慢,以致低于声卡的采样频率,那么多余的数据将会被丢弃(即overflow);如果读取数据的速度过快,以致高于声卡的采样频率,那么声卡驱动程序将会阻塞那些请求数据的应用程序,直到新的数据到来为止。
在向DSP设备写入数据时,数字信号会经过D/A转换器变成模拟信号,然后产生出声音。应用程序写入数据的速度应该至少等于声卡的采样频率,过慢会产生声音暂停或者停顿的现象(即underflow)。如果用户写入过快的话,它会被内核中的声卡驱动程序阻塞,直到硬件有能力处理新的数据为止。
与其它设备有所不同,声卡通常不需要支持非阻塞(non-blocking)的I/O操作。即便内核OSS驱动提供了非阻塞的I/O支持,用户空间也不宜采用。
无论是从声卡读取数据,或是向声卡写入数据,事实上都具有特定的格式(format),如无符号8位、单声道、8KHz采样率,如果默认值无法达到要求,可以通过ioctl()系统调用来改变它们。通常说来,在应用程序中打开设备文件/dev/dsp之后,接下去就应该为其设置恰当的格式,然后才能从声卡读取或者写入数据。
17.3.2 mixer接口
int register_sound_mixer(struct file_operations *fops, int dev);
上述函数用于注册1个混音器,第1个参数fops即是文件操作接口,第2个参数dev是设备编号,如果填入-1,则系统自动分配1个设备编号。mixer 是 1个典型的字符设备,因此编码的主要工作是实现file_operations中的open()、ioctl()等函数。
mixer接口file_operations中的最重要函数是ioctl(),它实现混音器的不同IO控制命令,代码清单17.1给出了1个ioctl()的范例。
代码清单17.1 mixer()接口ioctl()函数范例
1 static int mixdev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
2 {
3 ...
4 switch (cmd)
5 {
6 case SOUND_MIXER_READ_MIC:
7 ...
8 case SOUND_MIXER_WRITE_MIC:
9 ...
10 case SOUND_MIXER_WRITE_RECSRC:
11 ...
12 case SOUND_MIXER_WRITE_MUTE:
13 ...
14 }
15 //其它命令
16 return mixer_ioctl(codec, cmd, arg);
17 }
1 static int xxx_init(void)
2 {
3 struct xxx_state *s = &xxx_state;
4 ...
5 //注册dsp设备
6 if ((audio_dev_dsp = register_sound_dsp(&xxx_audio_fops, - 1)) < 0)
7 goto err_dev1;
8 //设备mixer设备
9 if ((audio_dev_mixer = register_sound_mixer(&xxx_mixer_fops, - 1)) < 0)
10 goto err_dev2;
11 ...
12 }
13
14 void __exit xxx_exit(void)
15 {
16 //注销dsp和mixer设备接口
17 unregister_sound_dsp(audio_dev_dsp);
18 unregister_sound_mixer(audio_dev_mixer);
19 ...
20 }
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 #include
8 #define LENGTH 3 /* 存储秒数 */
9 #define RATE 8000 /* 采样频率 */
10 #define SIZE 8 /* 量化位数 */
11 #define CHANNELS 1 /* 声道数目 */
12 /* 用于保存数字音频数据的内存缓冲区 */
13 unsigned char buf[LENGTH *RATE * SIZE * CHANNELS / 8];
14 int main()
15 {
16 int fd; /* 声音设备的文件描述符 */
17 int arg; /* 用于ioctl调用的参数 */
18 int status; /* 系统调用的返回值 */
19 /* 打开声音设备 */
20 fd = open("/dev/dsp", O_RDWR);
21 if (fd < 0)
22 {
23 perror("open of /dev/dsp failed");
24 exit(1);
25 }
26 /* 设置采样时的量化位数 */
27 arg = SIZE;
28 status = ioctl(fd, SOUND_PCM_WRITE_BITS, &arg);
29 if (status == - 1)
30 perror("SOUND_PCM_WRITE_BITS ioctl failed");
31 if (arg != SIZE)
32 perror("unable to set sample size");
33 /* 设置采样时的通道数目 */
34 arg = CHANNELS;
35 status = ioctl(fd, SOUND_PCM_WRITE_CHANNELS, &arg);
36 if (status == - 1)
37 perror("SOUND_PCM_WRITE_CHANNELS ioctl failed");
38 if (arg != CHANNELS)
39 perror("unable to set number of channels");
40 /* 设置采样率 */
41 arg = RATE;
42 status = ioctl(fd, SOUND_PCM_WRITE_RATE, &arg);
43 if (status == - 1)
44 perror("SOUND_PCM_WRITE_WRITE ioctl failed");
45 /* 循环,直到按下Control-C */
46 while (1)
47 {
48 printf("Say something:/n");
49 status = read(fd, buf, sizeof(buf)); /* 录音 */
50 if (status != sizeof(buf))
51 perror("read wrong number of bytes");
52 printf("You said:/n");
53 status = write(fd, buf, sizeof(buf)); /* 放音 */
54 if (status != sizeof(buf))
55 perror("wrote wrong number of bytes");
56 /* 在继续录音前等待放音结束 */
57 status = ioctl(fd, SOUND_PCM_SYNC, 0);
58 if (status == - 1)
59 perror("SOUND_PCM_SYNC ioctl failed");
60 }
61 }
SOUND_MIXER_VOLUME 主音量调节
SOUND_MIXER_BASS 低音控制
SOUND_MIXER_TREBLE 高音控制
SOUND_MIXER_SYNTH FM合成器
SOUND_MIXER_PCM 主D/A转换器
SOUND_MIXER_SPEAKER PC喇叭
SOUND_MIXER_LINE 音频线输入
SOUND_MIXER_MIC 麦克风输入
SOUND_MIXER_CD CD输入
SOUND_MIXER_IMIX 放音音量
SOUND_MIXER_ALTPCM 从D/A 转换器
SOUND_MIXER_RECLEV 录音音量
SOUND_MIXER_IGAIN 输入增益
SOUND_MIXER_OGAIN 输出增益
SOUND_MIXER_LINE1 声卡的第1输入
SOUND_MIXER_LINE2 声卡的第2输入
SOUND_MIXER_LINE3 声卡的第3输入
1 #include
2 #include
3 #include
4 #include
5 #include
6 #include
7 /* 用来存储所有可用混音设备的名称 */
8 const char *sound_device_names[] = SOUND_DEVICE_NAMES;
9 int fd; /* 混音设备所对应的文件描述符 */
10 int devmask, stereodevs; /* 混音器信息对应的bit掩码 */
11 char *name;
12 /* 显示命令的使用方法及所有可用的混音设备 */
13 void usage()
14 {
15 int i;
16 fprintf(stderr, "usage: %s /n"
17 "%s /n/n""Where is one of:/n", name, name);
18 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
19 if ((1 << i) &devmask)
20 /* 只显示有效的混音设备 */
21 fprintf(stderr, "%s ", sound_device_names[i]);
22 fprintf(stderr, "/n");
23 exit(1);
24 }
25
26 int main(int argc, char *argv[])
27 {
28 int left, right, level; /* 增益设置 */
29 int status; /* 系统调用的返回值 */
30 int device; /* 选用的混音设备 */
31 char *dev; /* 混音设备的名称 */
32 int i;
33 name = argv[0];
34 /* 以只读方式打开混音设备 */
35 fd = open("/dev/mixer", O_RDONLY);
36 if (fd == - 1)
37 {
38 perror("unable to open /dev/mixer");
39 exit(1);
40 }
41
42 /* 获得所需要的信息 */
43 status = ioctl(fd, SOUND_MIXER_READ_DEVMASK, &devmask);
44 if (status == - 1)
45 perror("SOUND_MIXER_READ_DEVMASK ioctl failed");
46 status = ioctl(fd, SOUND_MIXER_READ_STEREODEVS, &stereodevs);
47 if (status == - 1)
48 perror("SOUND_MIXER_READ_STEREODEVS ioctl failed");
49 /* 检查用户输入 */
50 if (argc != 3 && argc != 4)
51 usage();
52 /* 保存用户输入的混音器名称 */
53 dev = argv[1];
54 /* 确定即将用到的混音设备 */
55 for (i = 0; i < SOUND_MIXER_NRDEVICES; i++)
56 if (((1 << i) &devmask) && !strcmp(dev, sound_device_names[i]))
57 break;
58 if (i == SOUND_MIXER_NRDEVICES)
59 {
60 /* 没有找到匹配项 */
61 fprintf(stderr, "%s is not a valid mixer device/n", dev);
62 usage();
63 }
64 /* 查找到有效的混音设备 */
65 device = i;
66 /* 获取增益值 */
67 if (argc == 4)
68 {
69 /* 左、右声道均给定 */
70 left = atoi(argv[2]);
71 right = atoi(argv[3]);
72 }
73 else
74 {
75 /* 左、右声道设为相等 */
76 left = atoi(argv[2]);
77 right = atoi(argv[2]);
78 }
79
80 /* 对非立体声设备给出警告信息 */
81 if ((left != right) && !((1 << i) &stereodevs))
82 {
83 fprintf(stderr, "warning: %s is not a stereo device/n", dev);
84 }
85
86 /* 将两个声道的值合到同一变量中 */
87 level = (right << 8) + left;
88
89 /* 设置增益 */
90 status = ioctl(fd, MIXER_WRITE(device), &level);
91 if (status == - 1)
92 {
93 perror("MIXER_WRITE ioctl failed");
94 exit(1);
95 }
96 /* 获得从驱动返回的左右声道的增益 */
97 left = level &0xff;
98 right = (level &0xff00) >> 8;
99 /* 显示实际设置的增益 */
100 fprintf(stderr, "%s gain set to %d%% / %d%%/n", dev, left, right);
101 /* 关闭混音设备 */
102 close(fd);
103 return 0;
104 }
1 struct xxxchip //芯片特定的数据结构体
2 {
3 ...
4 };
5 card = snd_card_new(index, id, THIS_MODULE, sizeof(struct
6 xxxchip)); //创建声卡并申请xxx_chi内存作为card-> private_data
7 struct xxxchip *chip = card->private_data;
代码清单17.6 创建芯片特定的数据方法2
1 struct snd_card *card;
2 struct xxxchip *chip;
3 //使用0作为第4个参数,并动态分配xxx_chip的内存:
4 card = snd_card_new(index[dev], id[dev], THIS_MODULE, 0);
5 ...
6 chip = kzalloc(sizeof(*chip), GFP_KERNEL);
7 //在xxxchip结构体中,应该包括声卡指针:
8 struct xxxchip
9 {
10 struct snd_card *card;
11 ...
12 };
13 //并将其card成员赋值为snd_card_new()创建的card指针:
14 chip->card = card;
15 static struct snd_device_ops ops =
16 {
17 .dev_free = snd_xxx_chip_dev_free, //组件析构
18 };
19 ...
20 //创建自定义组件
21 snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops);
22 //在析构函数中释放xxxchip内存
23 static int snd_xxx_chip_dev_free(struct snd_device *device)
24 {
25 return snd_xxx_chip_free(device->device_data); //释放
26 }
1 static int snd_xxxctl_put(struct snd_kcontrol *kcontrol, struct
2 snd_ctl_elem_value *ucontrol)
3 {
4 //从snd_kcontrol获得xxxchip指针
5 struct xxxchip *chip = snd_kcontrol_chip(kcontrol);
6 int changed = 0;//缺省返回值为0
7 //值被改变
8 if (chip->current_value != ucontrol->value.integer.value[0])
9 {
10 change_current_value(chip, ucontrol->value.integer.value[0]);
11 changed = 1;//返回值为1
12 }
13 return changed;
14 }
1 struct snd_ac97_bus_ops
2 {
3 void(*reset)(struct snd_ac97 *ac97); //复位函数
4 //写入函数
5 void(*write)(struct snd_ac97 *ac97, unsigned short reg, unsigned short val);
6 //读取函数
7 unsigned short(*read)(struct snd_ac97 *ac97, unsigned short reg);
8 void(*wait)(struct snd_ac97 *ac97);
9 void(*init)(struct snd_ac97 *ac97);
10 };
1 struct snd_ac97_bus *bus;
2 //AC97总线操作
3 static struct snd_ac97_bus_ops ops =
4 {
5 .write = snd_mychip_ac97_write,
6 .read = snd_mychip_ac97_read,
7 };
8 //AC97总线与操作创建
9 snd_ac97_bus(card, 0, &ops, NULL, &bus);
10 //AC97模板
11 struct snd_ac97_template ac97;
12 int err;
13 memset(&ac97, 0, sizeof(ac97));
14 ac97.private_data = chip;//私有数据
15 //注册混音器
16 snd_ac97_mixer(bus, &ac97, &chip->ac97);
上述代码第1行的snd_ac97_bus结构体指针bus的指针被传入第9行的snd_ac97_bus()函数并被赋值,chip->ac97的指针被传入第16行的snd_ac97_mixer()并被赋值,chip->ac97将成员新创建AC97实例的指针。
1 static unsigned short snd_xxxchip_ac97_read(struct snd_ac97 *ac97, unsigned
2 short reg)
3 {
4 struct xxxchip *chip = ac97->private_data;
5 ...
6 return the_register_value; //返回寄存器值
7 }
8
9 static void snd_xxxchip_ac97_write(struct snd_ac97 *ac97, unsigned short reg,
10 unsigned short val)
11 {
12 struct xxxchip *chip = ac97->private_data;
13 ...
14 // 将被给的寄存器值写入codec
15 }
1 #include
2 #include
3 #include
4
5 main(int argc, char *argv[])
6 {
7 int i;
8 int err;
9 short buf[128];
10 snd_pcm_t *playback_handle; //PCM设备句柄
11 snd_pcm_hw_params_t *hw_params; //硬件信息和PCM流配置
12 //打开PCM,最后1个参数为0意味着标准配置
13 if ((err = snd_pcm_open(&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)
14 ) < 0)
15 {
16 fprintf(stderr, "cannot open audio device %s (%s)/n", argv[1], snd_strerror
17 (err));
18 exit(1);
19 }
20 //分配snd_pcm_hw_params_t结构体
21 if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
22 {
23 fprintf(stderr, "cannot allocate hardware parameter structure (%s)/n",
24 snd_strerror(err));
25 exit(1);
26 }
27 //初始化hw_params
28 if ((err = snd_pcm_hw_params_any(playback_handle, hw_params)) < 0)
29 {
30 fprintf(stderr, "cannot initialize hardware parameter structure (%s)/n",
31 snd_strerror(err));
32 exit(1);
33 }
34 //初始化访问权限
35 if ((err = snd_pcm_hw_params_set_access(playback_handle, hw_params,
36 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
37 {
38 fprintf(stderr, "cannot set access type (%s)/n", snd_strerror(err));
39 exit(1);
40 }
41 //初始化采样格式
42 if ((err = snd_pcm_hw_params_set_format(playback_handle, hw_params,
43 SND_PCM_FORMAT_S16_LE)) < 0)
44 {
45 fprintf(stderr, "cannot set sample format (%s)/n", snd_strerror(err));
46 exit(1);
47 }
48 //设置采样率,如果硬件不支持我们设置的采样率,将使用最接近的
49 if ((err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, 44100,
50 0)) < 0)
51 {
52 fprintf(stderr, "cannot set sample rate (%s)/n", snd_strerror(err));
53 exit(1);
54 }
55 //设置通道数量
56 if ((err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, 2)) < 0)
57 {
58 fprintf(stderr, "cannot set channel count (%s)/n", snd_strerror(err));
59 exit(1);
60 }
61 //设置hw_params
62 if ((err = snd_pcm_hw_params(playback_handle, hw_params)) < 0)
63 {
64 fprintf(stderr, "cannot set parameters (%s)/n", snd_strerror(err));
65 exit(1);
66 }
67 //释放分配的snd_pcm_hw_params_t结构体
68 snd_pcm_hw_params_free(hw_params);
69 //完成硬件参数设置,使设备准备好
70 if ((err = snd_pcm_prepare(playback_handle)) < 0)
71 {
72 fprintf(stderr, "cannot prepare audio interface for use (%s)/n",
73 snd_strerror(err));
74 exit(1);
75 }
76
77 for (i = 0; i < 10; ++i)
78 {
79 //写音频数据到PCM设备
80 if ((err = snd_pcm_writei(playback_handle, buf, 128)) != 128)
81 {
82 fprintf(stderr, "write to audio interface failed (%s)/n", snd_strerror
83 (err));
84 exit(1);
85 }
86 }
87 //关闭PCM设备句柄
88 snd_pcm_close(playback_handle);
89 exit(0);
90 }
1 #include
2 #include
3 #include
4 #include
5 #include
6
7 snd_pcm_t *playback_handle;
8 short buf[4096];
9
10 int playback_callback(snd_pcm_sframes_t nframes)
11 {
12 int err;
13 printf("playback callback called with %u frames/n", nframes);
14 /* 填充缓冲区 */
15 if ((err = snd_pcm_writei(playback_handle, buf, nframes)) < 0)
16 {
17 fprintf(stderr, "write failed (%s)/n", snd_strerror(err));
18 }
19
20 return err;
21 }
22
23 main(int argc, char *argv[])
24 {
25
26 snd_pcm_hw_params_t *hw_params;
27 snd_pcm_sw_params_t *sw_params;
28 snd_pcm_sframes_t frames_to_deliver;
29 int nfds;
30 int err;
31 struct pollfd *pfds;
32
33 if ((err = snd_pcm_open(&playback_handle, argv[1], SND_PCM_STREAM_PLAYBACK, 0)
34 ) < 0)
35 {
36 fprintf(stderr, "cannot open audio device %s (%s)/n", argv[1], snd_strerror
37 (err));
38 exit(1);
39 }
40
41 if ((err = snd_pcm_hw_params_malloc(&hw_params)) < 0)
42 {
43 fprintf(stderr, "cannot allocate hardware parameter structure (%s)/n",
44 snd_strerror(err));
45 exit(1);
46 }
47
48 if ((err = snd_pcm_hw_params_any(playback_handle, hw_params)) < 0)
49 {
50 fprintf(stderr, "cannot initialize hardware parameter structure (%s)/n",
51 snd_strerror(err));
52 exit(1);
53 }
54
55 if ((err = snd_pcm_hw_params_set_access(playback_handle, hw_params,
56 SND_PCM_ACCESS_RW_INTERLEAVED)) < 0)
57 {
58 fprintf(stderr, "cannot set access type (%s)/n", snd_strerror(err));
59 exit(1);
60 }
61
62 if ((err = snd_pcm_hw_params_set_format(playback_handle, hw_params,
63 SND_PCM_FORMAT_S16_LE)) < 0)
64 {
65 fprintf(stderr, "cannot set sample format (%s)/n", snd_strerror(err));
66 exit(1);
67 }
68
69 if ((err = snd_pcm_hw_params_set_rate_near(playback_handle, hw_params, 44100,
70 0)) < 0)
71 {
72 fprintf(stderr, "cannot set sample rate (%s)/n", snd_strerror(err));
73 exit(1);
74 }
75
76 if ((err = snd_pcm_hw_params_set_channels(playback_handle, hw_params, 2)) < 0)
77 {
78 fprintf(stderr, "cannot set channel count (%s)/n", snd_strerror(err));
79 exit(1);
80 }
81
82 if ((err = snd_pcm_hw_params(playback_handle, hw_params)) < 0)
83 {
84 fprintf(stderr, "cannot set parameters (%s)/n", snd_strerror(err));
85 exit(1);
86 }
87
88 snd_pcm_hw_params_free(hw_params);
89
90 /* 告诉ALSA当4096个以上帧可以传递时唤醒我们 */
91 if ((err = snd_pcm_sw_params_malloc(&sw_params)) < 0)
92 {
93 fprintf(stderr, "cannot allocate software parameters structure (%s)/n",
94 snd_strerror(err));
95 exit(1);
96 }
97 if ((err = snd_pcm_sw_params_current(playback_handle, sw_params)) < 0)
98 {
99 fprintf(stderr, "cannot initialize software parameters structure (%s)/n",
100 snd_strerror(err));
101 exit(1);
102 }
103 /* 设置4096帧传递一次数据 */
104 if ((err = snd_pcm_sw_params_set_avail_min(playback_handle, sw_params, 4096))
105 < 0)
106 {
107 fprintf(stderr, "cannot set minimum available count (%s)/n", snd_strerror
108 (err));
109 exit(1);
110 }
111 /* 一旦有数据就开始播放 */
112 if ((err = snd_pcm_sw_params_set_start_threshold(playback_handle, sw_params,
113 0U)) < 0)
114 {
115 fprintf(stderr, "cannot set start mode (%s)/n", snd_strerror(err));
116 exit(1);
117 }
118 if ((err = snd_pcm_sw_params(playback_handle, sw_params)) < 0)
119 {
120 fprintf(stderr, "cannot set software parameters (%s)/n", snd_strerror(err));
121 exit(1);
122 }
123
124 /* 每4096帧接口将中断内核,ALSA将很快唤醒本程序 */
125
126 if ((err = snd_pcm_prepare(playback_handle)) < 0)
127 {
128 fprintf(stderr, "cannot prepare audio interface for use (%s)/n",
129 snd_strerror(err));
130 exit(1);
131 }
132
133 while (1)
134 {
135
136 /* 等待,直到接口准备好传递数据,或者1秒超时发生 */
137 if ((err = snd_pcm_wait(playback_handle, 1000)) < 0)
138 {
139 fprintf(stderr, "poll failed (%s)/n", strerror(errno));
140 break;
141 }
142
143 /* 查出有多少空间可放置playback数据 */
144 if ((frames_to_deliver = snd_pcm_avail_update(playback_handle)) < 0)
145 {
146 if (frames_to_deliver == - EPIPE)
147 {
148 fprintf(stderr, "an xrun occured/n");
149 break;
150 }
151 else
152 {
153 fprintf(stderr, "unknown ALSA avail update return value (%d)/n",
154 frames_to_deliver);
155 break;
156 }
157 }
158
159 frames_to_deliver = frames_to_deliver > 4096 ? 4096 : frames_to_deliver;
160
161 /* 传递数据 */
162 if (playback_callback(frames_to_deliver) != frames_to_deliver)
163 {
164 fprintf(stderr, "playback callback failed/n");
165 break;
166 }
167 }
168
169 snd_pcm_close(playback_handle);
170 exit(0);
171 }
1 //音频(dsp)文件操作
2 static struct file_operations smdk2410_audio_fops =
3 {
4 llseek: smdk2410_audio_llseek,
5 write: smdk2410_audio_write,
6 read: smdk2410_audio_read,
7 poll: smdk2410_audio_poll,
8 ioctl: smdk2410_audio_ioctl,
9 open: smdk2410_audio_open,
10 release: smdk2410_audio_release
11 };
12 //混音器文件操作
13 static struct file_operations smdk2410_mixer_fops =
14 {
15 ioctl: smdk2410_mixer_ioctl,
16 open: smdk2410_mixer_open,
17 release: smdk2410_mixer_release
18 };
19
20 int __init s3c2410_uda1341_init(void)
21 {
22 unsigned long flags;
23
24 local_irq_save(flags);
25
26 /* 设置IIS接口引脚GPIO */
27
28 set_gpio_ctrl(GPIO_L3CLOCK); // GPB 4: L3CLOCK, 输出
29 set_gpio_ctrl(GPIO_L3DATA); // GPB 3: L3DATA, 输出
30 set_gpio_ctrl(GPIO_L3MODE); // GPB 2: L3MODE, 输出
31
32
33 set_gpio_ctrl(GPIO_E3 | GPIO_PULLUP_EN | GPIO_MODE_IISSDI); //GPE 3: IISSDI
34 set_gpio_ctrl(GPIO_E0 | GPIO_PULLUP_EN | GPIO_MODE_IISSDI); //GPE 0: IISLRCK
35 set_gpio_ctrl(GPIO_E1 | GPIO_PULLUP_EN | GPIO_MODE_IISSCLK); //GPE 1:IISSCLK
36 set_gpio_ctrl(GPIO_E2 | GPIO_PULLUP_EN | GPIO_MODE_CDCLK); //GPE 2: CDCLK
37 set_gpio_ctrl(GPIO_E4 | GPIO_PULLUP_EN | GPIO_MODE_IISSDO); //GPE 4: IISSDO
38
39 local_irq_restore(flags);
40
41 init_uda1341();
42
43 /* 输出流采样DMA通道2 */
44 output_stream.dma_ch = DMA_CH2;
45
46 if (audio_init_dma(&output_stream, "UDA1341 out"))
47 {
48 audio_clear_dma(&output_stream);
49 printk(KERN_WARNING AUDIO_NAME_VERBOSE ": unable to get DMA channels/n");
50 return - EBUSY;
51 }
52 /* 输入流采样DMA通道1 */
53 input_stream.dma_ch = DMA_CH1;
54
55 if (audio_init_dma(&input_stream, "UDA1341 in"))
56 {
57 audio_clear_dma(&input_stream);
58 printk(KERN_WARNING AUDIO_NAME_VERBOSE ": unable to get DMA channels/n");
59 return - EBUSY;
60 }
61
62 /* 注册dsp和mixer设备接口 */
63 audio_dev_dsp = register_sound_dsp(&smdk2410_audio_fops, - 1);
64 audio_dev_mixer = register_sound_mixer(&smdk2410_mixer_fops, - 1);
65
66 printk(AUDIO_NAME_VERBOSE " initialized/n");
67
68 return 0;
69 }
1 void __exit s3c2410_uda1341_exit(void)
2 {
3 //注销dsp和mixer设备接口
4 unregister_sound_dsp(audio_dev_dsp);
5 unregister_sound_mixer(audio_dev_mixer);
6
7 //注销DMA通道
8 audio_clear_dma(&output_stream);
9 audio_clear_dma(&input_stream); /* input */
10 printk(AUDIO_NAME_VERBOSE " unloaded/n");
11 }
1 static int smdk2410_mixer_ioctl(struct inode *inode, struct file *file,
2 unsigned int cmd, unsigned long arg)
3 {
4 int ret;
5 long val = 0;
6
7 switch (cmd)
8 {
9 case SOUND_MIXER_INFO: //获得mixer信息
10 {
11 mixer_info info;
12 strncpy(info.id, "UDA1341", sizeof(info.id));
13 strncpy(info.name, "Philips UDA1341", sizeof(info.name));
14 info.modify_counter = audio_mix_modcnt;
15 return copy_to_user((void*)arg, &info, sizeof(info));
16 }
17
18 case SOUND_OLD_MIXER_INFO:
19 {
20 _old_mixer_info info;
21 strncpy(info.id, "UDA1341", sizeof(info.id));
22 strncpy(info.name, "Philips UDA1341", sizeof(info.name));
23 return copy_to_user((void*)arg, &info, sizeof(info));
24 }
25
26 case SOUND_MIXER_READ_STEREODEVS://获取设备对立体声的支持
27 return put_user(0, (long*)arg);
28
29 case SOUND_MIXER_READ_CAPS: //获取声卡能力
30 val = SOUND_CAP_EXCL_INPUT;
31 return put_user(val, (long*)arg);
32
33 case SOUND_MIXER_WRITE_VOLUME: //设置音量
34 ret = get_user(val, (long*)arg);
35 if (ret)
36 return ret;
37 uda1341_volume = 63-(((val &0xff) + 1) *63) / 100;
38 uda1341_l3_address(UDA1341_REG_DATA0);
39 uda1341_l3_data(uda1341_volume);
40 break;
41
42 case SOUND_MIXER_READ_VOLUME: //获取音量
43 val = ((63-uda1341_volume) *100) / 63;
44 val |= val << 8;
45 return put_user(val, (long*)arg);
46
47 case SOUND_MIXER_READ_IGAIN: //获得增益
48 val = ((31-mixer_igain) *100) / 31;
49 return put_user(val, (int*)arg);
50
51 case SOUND_MIXER_WRITE_IGAIN: //设置增益
52 ret = get_user(val, (int*)arg);
53 if (ret)
54 return ret;
55 mixer_igain = 31-(val *31 / 100);
56 /* 使用mixer增益通道1 */
57 uda1341_l3_address(UDA1341_REG_DATA0);
58 uda1341_l3_data(EXTADDR(EXT0));
59 uda1341_l3_data(EXTDATA(EXT0_CH1_GAIN(mixer_igain)));
60 break;
61
62 default:
63 DPRINTK("mixer ioctl %u unknown/n", cmd);
64 return - ENOSYS;
65 }
66
67 audio_mix_modcnt++;
68 return 0;
69 }
1 static ssize_t smdk2410_audio_read(struct file *file, char *buffer, size_t
2 count, loff_t *ppos)
3 {
4 const char *buffer0 = buffer;
5 audio_stream_t *s = &input_stream; //得到数据区的指针
6 int chunksize, ret = 0;
7
8 DPRINTK("audio_read: count=%d/n", count);
9
10 if (ppos != &file->f_pos)
11 return - ESPIPE;
12
13 if (!s->buffers)
14 {
15 int i;
16
17 if (audio_setup_buf(s))
18 return - ENOMEM;
19 //依次从缓存区读取数据
20 for (i = 0; i < s->nbfrags; i++)
21 {
22 audio_buf_t *b = s->buf;
23 down(&b->sem);
24 s3c2410_dma_queue_buffer(s->dma_ch, (void*)b, b->dma_addr, s->fragsize,
25 DMA_BUF_RD);
26 NEXT_BUF(s, buf);
27 }
28 }
29
30 //满足用户的所有读需求
31 while (count > 0)
32 {
33 audio_buf_t *b = s->buf;
34
35 if (file->f_flags &O_NONBLOCK) //非阻塞
36 {
37 ret = - EAGAIN;
38 if (down_trylock(&b->sem))
39 break;
40 }
41 else
42 {
43 ret = - ERESTARTSYS;
44 if (down_interruptible(&b->sem))
45 break;
46 }
47
48 chunksize = b->size;
49 //从缓存区读取数据
50 if (chunksize > count)
51 chunksize = count;
52 DPRINTK("read %d from %d/n", chunksize, s->buf_idx);
53 if (copy_to_user(buffer, b->start + s->fragsize - b->size, //调用拷贝函数
54 chunksize))
55 {
56 up(&b->sem);
57 return - EFAULT;
58 }
59 b->size -= chunksize;
60
61 buffer += chunksize;
62 count -= chunksize; //已经给用户拷贝了一部分,count减少
63 if (b->size > 0)
64 {
65 up(&b->sem);
66 break;
67 }
68 //将缓存区释放
69 s3c2410_dma_queue_buffer(s->dma_ch, (void*)b, b->dma_addr, s->fragsize,
70 DMA_BUF_RD);
71
72 NEXT_BUF(s, buf);
73 }
74
75 if ((buffer - buffer0))
76 ret = buffer - buffer0;
77
78 return ret;
79 }
1 static ssize_t smdk2410_audio_write(struct file *file, const char *buffer,
2 size_t count, loff_t *ppos)
3 {
4 const char *buffer0 = buffer;
5 audio_stream_t *s = &output_stream;
6 int chunksize, ret = 0;
7
8 DPRINTK("audio_write : start count=%d/n", count);
9
10 switch (file->f_flags &O_ACCMODE)
11 {
12 case O_WRONLY: //只写
13 case O_RDWR: //读写
14 break;
15 default: //只读不合法
16 return - EPERM;
17 }
18 //设置DMA缓冲区
19 if (!s->buffers && audio_setup_buf(s))
20 return - ENOMEM;
21
22 count &= ~0x03;
23
24 while (count > 0) //直到满足用户的所有写需求
25 {
26 audio_buf_t *b = s->buf;
27 //非阻塞访问
28 if (file->f_flags &O_NONBLOCK)
29 {
30 ret = - EAGAIN;
31 if (down_trylock(&b->sem))
32 break;
33 }
34 else
35 {
36 ret = - ERESTARTSYS;
37 if (down_interruptible(&b->sem))
38 break;
39 }
40 //从用户空间拷贝音频数据
41 if (audio_channels == 2)
42 {
43 chunksize = s->fragsize - b->size;
44 if (chunksize > count)
45 chunksize = count;
46 DPRINTK("write %d to %d/n", chunksize, s->buf_idx);
47 if (copy_from_user(b->start + b->size, buffer, chunksize))
48 {
49 up(&b->sem);
50 return - EFAULT;
51 }
52 b->size += chunksize;
53 }
54 else
55 {
56 chunksize = (s->fragsize - b->size) >> 1;
57
58 if (chunksize > count)
59 chunksize = count;
60 DPRINTK("write %d to %d/n", chunksize *2, s->buf_idx);
61 if (copy_from_user_mono_stereo(b->start + b->size, buffer, chunksize))
62 {
63 up(&b->sem);
64 return - EFAULT;
65 }
66
67 b->size += chunksize * 2;
68 }
69
70 buffer += chunksize;
71 count -= chunksize; //已经从用户拷贝了一部分,count减少
72 if (b->size < s->fragsize)
73 {
74 up(&b->sem);
75 break;
76 }
77 //发起DMA操作
78 s3c2410_dma_queue_buffer(s->dma_ch, (void*)b, b->dma_addr, b->size,
79 DMA_BUF_WR);
80 b->size = 0;
81 NEXT_BUF(s, buf);
82 }
83
84 if ((buffer - buffer0))
85 ret = buffer - buffer0;
86
87 DPRINTK("audio_write : end count=%d/n/n", ret);
88
89 return ret;
90 }
1 static int __init sa11xx_uda1341_probe(struct platform_device *devptr)
2 {
3 int err;
4 struct snd_card *card;
5 struct sa11xx_uda1341 *chip;
6
7 /* 新建card */
8 card = snd_card_new(-1, id, THIS_MODULE, sizeof(struct sa11xx_uda1341));
9 if (card == NULL)
10 return -ENOMEM;
11
12 chip = card->private_data;
13 spin_lock_init(&chip->s[0].dma_lock);
14 spin_lock_init(&chip->s[1].dma_lock);
15
16 card->private_free = snd_sa11xx_uda1341_free;//card私有数据释放
17 chip->card = card;
18 chip->samplerate = AUDIO_RATE_DEFAULT;
19
20 // 注册control(mixer)接口
21 if ((err = snd_chip_uda1341_mixer_new(card, &chip->uda1341)))
22 goto nodev;
23
24 // 注册PCM接口
25 if ((err = snd_card_sa11xx_uda1341_pcm(chip, 0)) < 0)
26 goto nodev;
27
28 strcpy(card->driver, "UDA1341");
29 strcpy(card->shortname, "H3600 UDA1341TS");
30 sprintf(card->longname, "Compaq iPAQ H3600 with Philips UDA1341TS");
31
32 snd_card_set_dev(card, &devptr->dev);
33 //注册card
34 if ((err = snd_card_register(card)) == 0) {
35 printk( KERN_INFO "iPAQ audio support initialized/n" );
36 platform_set_drvdata(devptr, card);
37 return 0;
38 }
39
40 nodev:
41 snd_card_free(card);
42 return err;
43 }
44
45 static int __devexit sa11xx_uda1341_remove(struct platform_device *devptr)
46 {
47 //释放card
48 snd_card_free(platform_get_drvdata(devptr));
49 platform_set_drvdata(devptr, NULL);
50 return 0;
51 }
1 static struct snd_pcm_hardware snd_sa11xx_uda1341_capture =
2 {
3 .info = (SNDRV_PCM_INFO_INTERLEAVED |
4 SNDRV_PCM_INFO_BLOCK_TRANSFER |
5 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
6 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
7 .formats = SNDRV_PCM_FMTBIT_S16_LE,
8 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |/
9 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |/
10 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |/
11 SNDRV_PCM_RATE_KNOT),
12 .rate_min = 8000,
13 .rate_max = 48000,
14 .channels_min = 2,
15 .channels_max = 2,
16 .buffer_bytes_max = 64*1024,
17 .period_bytes_min = 64,
18 .period_bytes_max = DMA_BUF_SIZE,
19 .periods_min = 2,
20 .periods_max = 255,
21 .fifo_size = 0,
22 };
23
24 static struct snd_pcm_hardware snd_sa11xx_uda1341_playback =
25 {
26 .info = (SNDRV_PCM_INFO_INTERLEAVED |
27 SNDRV_PCM_INFO_BLOCK_TRANSFER |
28 SNDRV_PCM_INFO_MMAP | SNDRV_PCM_INFO_MMAP_VALID |
29 SNDRV_PCM_INFO_PAUSE | SNDRV_PCM_INFO_RESUME),
30 .formats = SNDRV_PCM_FMTBIT_S16_LE,
31 .rates = (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_16000 |/
32 SNDRV_PCM_RATE_22050 | SNDRV_PCM_RATE_32000 |/
33 SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 |/
34 SNDRV_PCM_RATE_KNOT),
35 .rate_min = 8000,
36 .rate_max = 48000,
37 .channels_min = 2,
38 .channels_max = 2,
39 .buffer_bytes_max = 64*1024,
40 .period_bytes_min = 64,
41 .period_bytes_max = DMA_BUF_SIZE,
42 .periods_min = 2,
43 .periods_max = 255,
44 .fifo_size = 0,
45 };
1 static struct snd_pcm_ops snd_card_sa11xx_uda1341_playback_ops =
2 {
3 .open = snd_card_sa11xx_uda1341_open,
4 .close = snd_card_sa11xx_uda1341_close,
5 .ioctl = snd_pcm_lib_ioctl,
6 .hw_params = snd_sa11xx_uda1341_hw_params,
7 .hw_free = snd_sa11xx_uda1341_hw_free,
8 .prepare = snd_sa11xx_uda1341_prepare,
9 .trigger = snd_sa11xx_uda1341_trigger,
10 .pointer = snd_sa11xx_uda1341_pointer,
11 };
12
13 static struct snd_pcm_ops snd_card_sa11xx_uda1341_capture_ops =
14 {
15 .open = snd_card_sa11xx_uda1341_open,
16 .close = snd_card_sa11xx_uda1341_close,
17 .ioctl = snd_pcm_lib_ioctl,
18 .hw_params = snd_sa11xx_uda1341_hw_params,
19 .hw_free = snd_sa11xx_uda1341_hw_free,
20 .prepare = snd_sa11xx_uda1341_prepare,
21 .trigger = snd_sa11xx_uda1341_trigger,
22 .pointer = snd_sa11xx_uda1341_pointer,
23 };
1 static int __init snd_card_sa11xx_uda1341_pcm(struct sa11xx_uda1341 *sa11xx_uda1341, int device)
2 {
3 struct snd_pcm *pcm;
4 int err;
5 /* 新建pcm设备,playback和capture都为1个 */
6 if ((err = snd_pcm_new(sa11xx_uda1341->card, "UDA1341 PCM", device, 1, 1, &pcm)) < 0)
7 return err;
8
9 /* 建立初始缓冲区并设置dma_type为isa */
10 snd_pcm_lib_preallocate_pages_for_all(pcm, SNDRV_DMA_TYPE_DEV,
11 snd_dma_isa_data(),
12 64*1024, 64*1024);
13 /* 设置pcm的操作 */
14 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, snd_card_sa11xx_uda1341_playback_ops);
15 snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &snd_card_sa11xx_uda1341_capture_ops);
16 pcm->private_data = sa11xx_uda1341;
17 pcm->info_flags = 0;
18 strcpy(pcm->name, "UDA1341 PCM");
19
20 sa11xx_uda1341_audio_init(sa11xx_uda1341);
21
22 /* 设置DMA控制器 */
23 audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_PLAYBACK], audio_dma_callback);
24 audio_dma_request(&sa11xx_uda1341->s[SNDRV_PCM_STREAM_CAPTURE], audio_dma_callback);
25
26 sa11xx_uda1341->pcm = pcm;
27
28 return 0;
29 }
1 static int snd_card_sa11xx_uda1341_open(struct snd_pcm_substream *substream)
2 {
3 struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
4 struct snd_pcm_runtime *runtime = substream->runtime;
5 int stream_id = substream->pstr->stream;
6 int err;
7
8 chip->s[stream_id].stream = substream;
9
10 if (stream_id == SNDRV_PCM_STREAM_PLAYBACK) //播放子流
11 runtime->hw = snd_sa11xx_uda1341_playback;
12 else //录音子流
13 runtime->hw = snd_sa11xx_uda1341_capture;
14 if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0)
15 return err;
16 if ((err = snd_pcm_hw_constraint_list(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,&hw_constraints_rates)) < 0)
17 return err;
18
19 return 0;
20 }
21
22 static int snd_card_sa11xx_uda1341_close(struct snd_pcm_substream *substream)
23 {
24 struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
25
26 chip->s[substream->pstr->stream].stream = NULL;
27 return 0;
28 }
1 static int snd_sa11xx_uda1341_trigger(struct snd_pcm_substream *substream, int
2 cmd)
3 {
4 struct sa11xx_uda1341 *chip = snd_pcm_substream_chip(substream);
5 int stream_id = substream->pstr->stream;
6 struct audio_stream *s = &chip->s[stream_id];
7 struct audio_stream *s1 = &chip->s[stream_id ^ 1];
8 int err = 0;
9
10 /* 注意本地中断已经被中间层代码禁止 */
11 spin_lock(&s->dma_lock);
12 switch (cmd)
13 {
14 case SNDRV_PCM_TRIGGER_START://开启PCM
15 if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active) //开启录音,不在播放
16 {
17 s1->tx_spin = 1;
18 audio_process_dma(s1);
19 }
20 else
21 {
22 s->tx_spin = 0;
23 }
24
25 /* 被请求的流启动 */
26 s->active = 1;
27 audio_process_dma(s);
28 break;
29 case SNDRV_PCM_TRIGGER_STOP:
30 /* 被请求的流关闭 */
31 audio_stop_dma(s);
32 if (stream_id == SNDRV_PCM_STREAM_PLAYBACK && s1->active) //在录音时开启播放
33 {
34 s->tx_spin = 1;
35 audio_process_dma(s); //启动DMA
36 }
37 else
38 {
39 if (s1->tx_spin)
40 {
41 s1->tx_spin = 0;
42 audio_stop_dma(s1); //停止DMA
43 }
44 }
45
46 break;
47 case SNDRV_PCM_TRIGGER_SUSPEND: //挂起
48 s->active = 0;
49 #ifdef HH_VERSION
50 sa1100_dma_stop(s->dmach); //停止DMA
51 #endif
52 s->old_offset = audio_get_dma_pos(s) + 1;
53 #ifdef HH_VERSION
54 sa1100_dma_flush_all(s->dmach);
55 #endif
56 s->periods = 0;
57 break;
58 case SNDRV_PCM_TRIGGER_RESUME: //恢复
59 s->active = 1;
60 s->tx_spin = 0;
61 audio_process_dma(s); //开启DMA
62 if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active)
63 {
64 s1->tx_spin = 1;
65 audio_process_dma(s1);
66 }
67 break;
68 case SNDRV_PCM_TRIGGER_PAUSE_PUSH: //暂停
69 #ifdef HH_VERSION
70 sa1100_dma_stop(s->dmach); //停止DMA
71 #endif
72 s->active = 0;
73 if (stream_id == SNDRV_PCM_STREAM_PLAYBACK)
74 {
75 if (s1->active)
76 {
77 s->tx_spin = 1;
78 s->old_offset = audio_get_dma_pos(s) + 1;
79 #ifdef HH_VERSION
80 sa1100_dma_flush_all(s->dmach);
81 #endif
82 audio_process_dma(s); //开启DMA
83 }
84 }
85 else
86 {
87 if (s1->tx_spin)
88 {
89 s1->tx_spin = 0;
90 #ifdef HH_VERSION
91 sa1100_dma_flush_all(s1->dmach);
92 #endif
93 }
94 }
95 break;
96 case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: //暂停释放
97 s->active = 1;
98 if (s->old_offset)
99 {
100 s->tx_spin = 0;
101 audio_process_dma(s);
102 break;
103 }
104 if (stream_id == SNDRV_PCM_STREAM_CAPTURE && !s1->active)
105 {
106 s1->tx_spin = 1;
107 audio_process_dma(s1);
108 }
109 #ifdef HH_VERSION
110 sa1100_dma_resume(s->dmach);
111 #endif
112 break;
113 default:
114 err = - EINVAL;
115 break;
116 }
117 spin_unlock(&s->dma_lock);
118 return err;
119 }
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 };
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 }
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 }