从下面可以知道,此CODE有一个输入,8个输出,如果按照双通道的立体声来计算的话,有2个立体声输入,4个立体声输出。
寄存器的定义如下,在应用层的角度主要用来控制音量,MUTE。也可以设置采用频率(输入和输出,即对于播放和录音)。
AD1936 Sound CODEC Linux Driver [Analog Devices Wiki]https://wiki.analog.com/resources/tools-software/linux-drivers/sound/ad1936ad193x.c « codecs « soc « sound - kernel/git/torvalds/linux.git - Linux kernel source tree
在开始学习代码之前,需要搞清楚一些大的概念
1:声卡在Linux中的定义
2:音频设备的驱动定义是什么?
Linux音频驱动-PCM设备_半月旋空-CSDN博客_linux pcm
Linux LASA声卡驱动之三:PCM设备的创建_u012830148的博客-CSDN博客
Advanced Linux Sound Architecture (简体中文) - ArchWiki
通过int snd_device_new(struct snd_card *card, enum snd_device_type type,void *device_data, struct snd_device_ops *ops)
的实例化来创建不同的音频设备,其中我们常见的是PCM设备
如创建的如下设备节点
/dev/snd # ls -al
total 0
drwxr-xr-x 2 root root 120 1970-01-01 00:00 .
drwxr-xr-x 18 root root 3040 1970-01-01 00:00 ..
crw-rw---- 1 system audio 116, 0 1970-01-01 00:00 controlC0
crw-rw---- 1 system audio 116, 24 1970-01-01 00:00 pcmC0D0c
crw-rw---- 1 system audio 116, 16 1970-01-01 00:00 pcmC0D0p
crw-rw---- 1 system audio 116, 33 1970-01-01 00:00 timer
硬件名字使用hw:i,j这样的格式。其中i是卡号,j是这块声卡上的设备号。
每个声卡最多可以包含4个pcm的实例,每个pcm实例对应一个pcm设备文件,pcm实例数量的这种限制源于linux设备号所占用的大小,如果以后使用64位的设备号, 我们就可以创建更多的pcm实例,不过大多数情况下,在嵌入式设备中,一个pcm实例已经足够了。
/**
* snd_device_new - create an ALSA device component
* @card: the card instance
* @type: the device type, SNDRV_DEV_XXX
* @device_data: the data pointer of this device
* @ops: the operator table
*
* Creates a new device component for the given data pointer.
* The device will be assigned to the card and managed together
* by the card.
*
* The data pointer plays a role as the identifier, too, so the
* pointer address must be unique and unchanged.
*
* Return: Zero if successful, or a negative error code on failure.
*/
int snd_device_new(struct snd_card *card, enum snd_device_type type,
void *device_data, struct snd_device_ops *ops)
{
struct snd_device *dev;
struct list_head *p;
if (snd_BUG_ON(!card || !device_data || !ops))
return -ENXIO;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
dev_err(card->dev, "Cannot allocate device, type=%d\n", type);
return -ENOMEM;
}
INIT_LIST_HEAD(&dev->list);
dev->card = card;
dev->type = type;
dev->state = SNDRV_DEV_BUILD;
dev->device_data = device_data;
dev->ops = ops;
/* insert the entry in an incrementally sorted list */
list_for_each_prev(p, &card->devices) {
struct snd_device *pdev = list_entry(p, struct snd_device, list);
if ((unsigned int)pdev->type <= (unsigned int)type)
break;
}
list_add(&dev->list, p);
return 0;
}