.name = "UDA134X",
.stream_name = "UDA134X",
.codec_dai = &uda134x_dai,
.cpu_dai = &s3c24xx_i2s_dai,
.ops = &s3c24xx_uda134x_ops,
};
{
。。。。。。
list_add(&dai->list, &dai_list); //将结构体uda134x_dai添加到链表dai_list上。
。。。。。。
}
包含了一个IIS接口寄存器参数设置函数集和几个初始化函数。在文件s3c24xx-i2s.c中
{
。。。。。。
list_add(&dai->list, &dai_list); //将结构体s3c24xx_i2s_dai添加到链表dai_list上。
。。。。。。
}
.startup = s3c24xx_uda134x_startup, //获取时钟计算波特率
.shutdown = s3c24xx_uda134x_shutdown,
.hw_params = s3c24xx_uda134x_hw_params,
};
.name = "S3C24XX_UDA134X",
.platform = &s3c24xx_soc_platform,
.dai_link = &s3c24xx_uda134x_dai_link,
.num_links = 1,
};
配置。另一个由于录音和播放的数据流传输。将这些音频数据从内存中搬运到IIS接口的fifo中是通过
.name = "s3c24xx-audio",
.pcm_ops = &s3c24xx_pcm_ops,
.pcm_free = s3c24xx_pcm_free_dma_buffers,
};
.card = &snd_soc_s3c24xx_uda134x,
.codec_dev = &soc_codec_dev_uda134x,
.codec_data = &s3c24xx_uda134x,
};
static struct platform_driver s3c24xx_uda134x_driver = {
.probe = s3c24xx_uda134x_probe,
.remove = s3c24xx_uda134x_remove,
.driver = {
.name = "s3c24xx_uda134x",
.owner = THIS_MODULE,
},
};
该驱动与名为"s3c24xx_uda134x",的平台设备匹配后调用硬件探测函数s3c24xx_uda134x_probe()
{
//该结构体中包含了与声卡L3DATA,L3MODE,L3CLOCK连接的处理器的三个引脚。
s3c24xx_uda134x.power = s3c24xx_uda134x_l3_pins->power;
s3c24xx_uda134x.model = s3c24xx_uda134x_l3_pins->model;
return -EBUSY;
if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_clk,"clk") < 0) {
return -EBUSY;
}
if (s3c24xx_uda134x_setup_pin(s3c24xx_uda134x_l3_pins->l3_mode, "mode") < 0) {
return -EBUSY;
}
s3c24xx_uda134x_snd_devdata.dev = &s3c24xx_uda134x_snd_device->dev;
ret = platform_device_add(s3c24xx_uda134x_snd_device);
}
.driver = {
.name = "soc-audio",
.owner = THIS_MODULE,
},
.probe = soc_probe,
.remove = soc_remove,
.suspend = soc_suspend,
.resume = soc_resume,
};
{
int ret = 0;
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_card *card = socdev->card;
card->dev = &pdev->dev;
ret = snd_soc_register_card(card); //讲解如下
。。。。。。
}
{
。。。。。。
list_add(&card->list, &card_list);
snd_soc_instantiate_cards(); //
。。。。。。
}
{
struct snd_soc_card *card;
list_for_each_entry(card, &card_list, list) //在链表card_list上找出所有的card并调用初始化函数。
snd_soc_instantiate_card(card);
}
{
struct platform_device *pdev = container_of(card->dev, struct platform_device, dev);
struct snd_soc_codec_device *codec_dev = card->socdev->codec_dev;
。。。。。。
if (card->probe) { //这个初始化函数并没有被实现,为空。
ret = card->probe(pdev);
if (ret < 0)
return;
}
struct snd_soc_dai *cpu_dai = card->dai_link[i].cpu_dai;
if (cpu_dai->probe) {
ret = cpu_dai->probe(pdev, cpu_dai);
if (ret < 0)
goto cpu_dai_err;
}
}
ret = codec_dev->probe(pdev);
if (ret < 0)
goto cpu_dai_err;
}
if (ret < 0)
goto platform_err;
}
}
{
struct snd_soc_device *socdev = platform_get_drvdata(pdev);
struct snd_soc_codec *codec;
struct uda134x_priv *uda134x;
void *codec_setup_data = socdev->codec_data;
int ret = -ENOMEM;
struct uda134x_platform_data *pd;
。。。。。。
codec->private_data = uda134x;
codec->reg_cache_step = 1;
codec->owner = THIS_MODULE;
codec->dai = &uda134x_dai;
codec->num_dai = 1;
codec->read = uda134x_read_reg_cache;
codec->write = uda134x_write; //上层函数对声卡的控制最终都是通过调用该函数来完成的
#ifdef POWER_OFF_ON_STANDBY
codec->set_bias_level = uda134x_set_bias_level;
#endif
INIT_LIST_HEAD(&codec->dapm_widgets);
INIT_LIST_HEAD(&codec->dapm_paths);
ret = snd_soc_new_pcms(socdev, SNDRV_DEFAULT_IDX1, SNDRV_DEFAULT_STR1); 【1】
case UDA134X_UDA1340:
case UDA134X_UDA1344:
ret = snd_soc_add_controls(codec, uda1340_snd_controls,
ARRAY_SIZE(uda1340_snd_controls));
break;
case UDA134X_UDA1341:
ret = snd_soc_add_controls(codec, uda1341_snd_controls, ARRAY_SIZE(uda1341_snd_controls)); 【2】
break;
default:
return -EINVAL;
}
return ret;
}
【1】
{
struct snd_soc_card *card = socdev->card;
struct snd_soc_codec *codec = card->codec;
int ret, i;
ret = snd_card_create(idx, xid, codec->owner, 0, &codec->card); (1)
。。。。。。
codec->card->private_data = codec;
strncpy(codec->card->driver, codec->name, sizeof(codec->card->driver));
for (i = 0; i < card->num_links; i++) { //构造card->num_links个pcm实例
ret = soc_new_pcm(socdev, &card->dai_link[i], i); (2)
。。。。。。
}
return ret;
}
{
struct snd_card *card;
int err, idx2;
card = kzalloc(sizeof(*card) + extra_size, GFP_KERNEL);
。。。。。。
//对结构体 snd_card 初始化。
mutex_unlock(&snd_card_mutex);
card->number = idx;
card->module = module;
INIT_LIST_HEAD(&card->devices);
init_rwsem(&card->controls_rwsem);
rwlock_init(&card->ctl_files_rwlock);
INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files);
spin_lock_init(&card->files_lock);
INIT_LIST_HEAD(&card->files_list);
init_waitqueue_head(&card->shutdown_sleep);
#ifdef CONFIG_PM
mutex_init(&card->power_lock);
init_waitqueue_head(&card->power_sleep);
#endif
err = snd_ctl_create(card); //该函数的讨论如下。
。。。。。。
}
{
static struct snd_device_ops ops = {
.dev_free = snd_ctl_dev_free,
.dev_register = snd_ctl_dev_register, //该函数的调用将创建一个设备节点。
.dev_disconnect = snd_ctl_dev_disconnect,
};
return -ENXIO;
return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops); //讨论如下
}
void *device_data, struct snd_device_ops *ops)
{
struct snd_device *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
dev->card = card;
dev->type = type;
dev->state = SNDRV_DEV_BUILD;
dev->device_data = device_data; //device_data上面传入的参数是 card
dev->ops = ops;
list_add(&dev->list, &card->devices); //将struct snd_device *dev;挂到声卡结构体card->devices上。
return 0;
}
struct snd_soc_dai_link *dai_link, int num)
{
struct snd_soc_card *card = socdev->card;
struct snd_soc_codec *codec = card->codec;
struct snd_soc_platform *platform = card->platform;
struct snd_soc_dai *codec_dai = dai_link->codec_dai;
struct snd_soc_dai *cpu_dai = dai_link->cpu_dai;
struct snd_soc_pcm_runtime *rtd;
struct snd_pcm *pcm;
char new_name[64];
int ret = 0, playback = 0, capture = 0;
if (rtd == NULL)
return -ENOMEM;
rtd->socdev = socdev;
playback = 1;
if (codec_dai->capture.channels_min)
capture = 1;
函数snd_pcm_new构造pcm实例,第一个参数是card指针,第二个是标识字符串,第三个是
PCM设备索引(从0开始),第四和第五个参数分别为播放和录音设备的子流数。
*/
pcm->private_data = rtd;
soc_pcm_ops.mmap = platform->pcm_ops->mmap;
soc_pcm_ops.pointer = platform->pcm_ops->pointer;
soc_pcm_ops.ioctl = platform->pcm_ops->ioctl;
soc_pcm_ops.copy = platform->pcm_ops->copy;
soc_pcm_ops.silence = platform->pcm_ops->silence;
soc_pcm_ops.ack = platform->pcm_ops->ack;
soc_pcm_ops.page = platform->pcm_ops->page;
{
struct snd_pcm_str *stream = &pcm->streams[direction];
struct snd_pcm_substream *substream;
for (substream = stream->substream; substream != NULL; substream = substream->next)
substream->ops = ops;
}
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &soc_pcm_ops);
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &soc_pcm_ops);
。。。。。。
}
int playback_count, int capture_count,
struct snd_pcm ** rpcm)
{
struct snd_pcm *pcm;
int err;
static struct snd_device_ops ops = {
.dev_free = snd_pcm_dev_free,
.dev_register = snd_pcm_dev_register, //该函数的调用会导致 两 个设备节点的创建。后面会讲解。
.dev_disconnect = snd_pcm_dev_disconnect,
};
pcm = kzalloc(sizeof(*pcm), GFP_KERNEL); //创建结构体snd_pcm。
。。。。。。
pcm->card = card;
pcm->device = device;
。。。。。。
if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_PLAYBACK, playback_count)) < 0) {
snd_pcm_free(pcm);
return err;
}
if ((err = snd_pcm_new_stream(pcm, SNDRV_PCM_STREAM_CAPTURE, capture_count)) < 0) {
snd_pcm_free(pcm);
return err;
}
。。。。。。
if ((err = snd_device_new(card, SNDRV_DEV_PCM, pcm, &ops)) < 0) { //如下
snd_pcm_free(pcm);
return err;
}
if (rpcm)
*rpcm = pcm;
return 0;
}
{
struct snd_device *dev;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
dev->card = card;
dev->type = type;
dev->state = SNDRV_DEV_BUILD;
dev->device_data = device_data; //device_data上面传入的参数是 pcm
dev->ops = ops;
list_add(&dev->list, &card->devices); //将struct snd_device *dev;挂到声卡结构体card->devices上。
return 0;
}
snd_ctl_elem_iface_t iface; /* interface identifier */
unsigned int device; /* device/client number */
unsigned int subdevice; /* subdevice (substream) number */
unsigned char *name; /* ASCII name of item */
unsigned int index; /* index of item */
unsigned int access; /* access rights */
unsigned int count; /* count of same elements */
snd_kcontrol_info_t *info;
snd_kcontrol_get_t *get;
snd_kcontrol_put_t *put;
union {
snd_kcontrol_tlv_rw_t *c;
const unsigned int *p;
} tlv;
unsigned long private_value;
};
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
.info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
.put = snd_soc_put_volsw, \
.private_value = SOC_SINGLE_VALUE(reg, shift, max, invert) }
((unsigned long)&(struct soc_mixer_control) \
{.reg = xreg, .shift = xshift, .rshift = xshift, .max = xmax, \
.invert = xinvert})
int snd_soc_init_card(struct snd_soc_device *socdev)
{
struct snd_soc_card *card = socdev->card;
struct snd_soc_codec *codec = card->codec;
int ret = 0, i, ac97 = 0, err = 0;
。。。。。。
ret = snd_card_register(codec->card);
。。。。。。
}
int snd_card_register(struct snd_card *card)
{
。。。。。。
if ((err = snd_device_register_all(card)) < 0)
return err;
。。。。。。
snd_cards[card->number] = card;
。。。。。。
}
int snd_device_register_all(struct snd_card *card)
{
struct snd_device *dev;
int err;
if (snd_BUG_ON(!card))
return -ENXIO;
//对挂在card->devices上的所有snd_device都调用dev->ops->dev_register(dev)来
//创建设备节点。
list_for_each_entry(dev, &card->devices, list) {
if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
if ((err = dev->ops->dev_register(dev)) < 0)
return err;
dev->state = SNDRV_DEV_REGISTERED;
}
}
return 0;
}