浅析uda134x声卡驱动probe的精简步骤
《浅析打开/dev/dsp设备节点代码流程》《浅析放音模式--向/dev/dsp设备write写入音频数据的代码流》《浅析alsa声卡放音模式时s3c24xx处理器DMA中断如何建立和处理》<基于linux-2.6.31.5内核[luther.gliethttp]>
s3c24xx_uda134x_probe
==> platform_device_alloc("soc-audio", -1);
==> platform_set_drvdata(s3c24xx_uda134x_snd_device, &s3c24xx_uda134x_snd_devdata);
==> soc_driver中的soc_probe
==> 调用codec_dev->probe也就是下面的uda134x_soc_probe
static struct snd_soc_device s3c24xx_uda134x_snd_devdata = {
.card = &snd_soc_s3c24xx_uda134x,
.codec_dev = &soc_codec_dev_uda134x, // 核心在于执行它的uda134x_soc_probe
.codec_data = &s3c24xx_uda134x,
};
// 下面是生成的唯一一个PCM实例对应的DAI接口
static struct snd_soc_dai_link s3c24xx_uda134x_dai_link = {
.name = "UDA134X",
.stream_name = "UDA134X",
.codec_dai = &uda134x_dai,
.cpu_dai = &s3c24xx_i2s_dai,
.ops = &s3c24xx_uda134x_ops,
};
struct snd_soc_codec_device soc_codec_dev_uda134x = {
.probe = uda134x_soc_probe,
.remove = uda134x_soc_remove,
.suspend = uda134x_soc_suspend,
.resume = uda134x_soc_resume,
};
uda134x_soc_probe
==> snd_soc_new_pcms为每个card->dai_link[i]组合创建一个pcm实例也就是为s3c24xx_uda134x_dai_link
唯一对应的一个DAI生成唯一的一个PCM实例[luther.gliethttp]
==> snd_soc_init_card
==> snd_card_register注册声卡[card和pcm]
==> snd_device_register_all调用dev->ops->dev_register(dev)注册card->devices
链表上的所有设备,当然包括snd_soc_new_pcms中创建的pcm实例[luther.gliethttp]
==> snd_pcm_dev_register
==> 调用snd_pcm_notify_list链表上的snd_pcm_oss_register_minor
==> snd_pcm_oss_register_minor
==> register_oss_dsp(pcm, 0);创建/dev/dsp设备节点[luther.gliethttp]
同时设置/dev/dsp设备节点的操作方法集为snd_pcm_oss_f_reg
==> snd_pcm_oss_f_reg为/dev/dsp设备节点soundcore_open后的替代fops
这样当应用程序打开/dev/dsp之后,snd_pcm_oss_f_reg将作为该应用程序的默认方法集
==> file->f_op = fops_get(snd_pcm_oss_f_reg);
static const struct file_operations snd_pcm_oss_f_reg =
{
.owner = THIS_MODULE,
.read = snd_pcm_oss_read,
.write = snd_pcm_oss_write,
.open = snd_pcm_oss_open,
.release = snd_pcm_oss_release,
.poll = snd_pcm_oss_poll,
.unlocked_ioctl = snd_pcm_oss_ioctl,
.compat_ioctl = snd_pcm_oss_ioctl_compat,
.mmap = snd_pcm_oss_mmap,
};
// 在snd_pcm_oss_open
// ==> snd_pcm_oss_open_file
// ==> snd_pcm_oss_init_substream
// ==> runtime->oss.rate = 8000;
s3c24xx_pcm_open
==> snd_soc_set_runtime_hwparams(substream, &s3c24xx_pcm_hardware);
static const struct snd_pcm_hardware s3c24xx_pcm_hardware = {
.info = SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
SNDRV_PCM_INFO_PAUSE |
SNDRV_PCM_INFO_RESUME,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_U16_LE |
SNDRV_PCM_FMTBIT_U8 |
SNDRV_PCM_FMTBIT_S8,
.channels_min = 2,
.channels_max = 2,
.buffer_bytes_max = 128*1024,
.period_bytes_min = PAGE_SIZE,
.period_bytes_max = PAGE_SIZE*2,
.periods_min = 2,
.periods_max = 128,
.fifo_size = 32,
};
int snd_soc_set_runtime_hwparams(struct snd_pcm_substream *substream,
const struct snd_pcm_hardware *hw)
{
struct snd_pcm_runtime *runtime = substream->runtime;
runtime->hw.info = hw->info;
runtime->hw.formats = hw->formats;
runtime->hw.period_bytes_min = hw->period_bytes_min;
runtime->hw.period_bytes_max = hw->period_bytes_max;
runtime->hw.periods_min = hw->periods_min;
runtime->hw.periods_max = hw->periods_max;
runtime->hw.buffer_bytes_max = hw->buffer_bytes_max;
runtime->hw.fifo_size = hw->fifo_size;
return 0;
}