alsa声卡dev - snd - pcmC0D0p的open打开流程 下载本文

内容发布更新时间 : 2024/5/27 16:49:23星期一 下面是文章的全部内容请认真阅读。

(unsigned char *)src_areas[0].addr + sample_size * src_ofs * channels,

dmix->u.dmix.sum_buffer + dst_ofs * channels, sample_size, sample_size,

sizeof(signed int));

这里的do_mix_areas在i386中,使用下面完全用汇编实现的拷贝函数MIX_AREAS_32完成数据从src到dst的快速拷贝,

每拷贝一次,声卡就会发出一点声音[luther.gliethttp] /*

* for plain i386, 32-bit version (24-bit resolution) */

static void MIX_AREAS_32(unsigned int size, volatile signed int *dst, signed int *src,

volatile signed int *sum, size_t dst_step, size_t src_step, size_t sum_step)

_snd_pcm_asym_open _snd_pcm_dmix_open

snd_pcm_plugin_avail_update

==> snd_pcm_avail_update(slave);

==> pcm->fast_ops->avail_update(pcm->fast_op_arg); ==> snd_pcm_dmix_avail_update

==> snd_pcm_mmap_playback_avail(pcm);

alsa_sound_init

#define CONFIG_SND_MAJOR 116 /* standard configuration */ static int major = CONFIG_SND_MAJOR; module_init(alsa_sound_init) alsa_sound_init

==> register_chrdev(major, \// 主设备号为116的所有设备都为alsa设备,节点方法集为snd_fops

static const struct file_operations snd_fops = // alsa的设备名为pcmC0D1c或pcmC0D1p等[luther.gliethttp]. {

.owner = THIS_MODULE, .open = snd_open };

snd_open

==> __snd_open(inode, file); ==> __snd_open

unsigned int minor = iminor(inode);

mptr = snd_minors[minor];

file->f_op = fops_get(mptr->f_ops); file->f_op->open(inode, file);

const struct file_operations snd_pcm_f_ops[2] = {

{ // alsa使用到的SNDRV_PCM_STREAM_PLAYBACK放音方法集[luther.gliethttp]

.owner = THIS_MODULE, .write = snd_pcm_write,

.aio_write = snd_pcm_aio_write,

.open = snd_pcm_playback_open, .release = snd_pcm_release,

.poll = snd_pcm_playback_poll,

.unlocked_ioctl = snd_pcm_playback_ioctl, .compat_ioctl = snd_pcm_ioctl_compat, .mmap = snd_pcm_mmap, .fasync = snd_pcm_fasync,

.get_unmapped_area = dummy_get_unmapped_area, },

{ // alsa使用到的SNDRV_PCM_STREAM_CAPTURE录音方法集[luther.gliethttp]

.owner = THIS_MODULE, .read = snd_pcm_read,

.aio_read = snd_pcm_aio_read, .open = snd_pcm_capture_open, .release = snd_pcm_release, .poll = snd_pcm_capture_poll,

.unlocked_ioctl = snd_pcm_capture_ioctl, .compat_ioctl = snd_pcm_ioctl_compat, .mmap = snd_pcm_mmap, .fasync = snd_pcm_fasync,

.get_unmapped_area = dummy_get_unmapped_area, }

};

========================================================================= snd_intel8x0_probe

==> snd_intel8x0_create

==> request_irq(pci->irq, snd_intel8x0_interrupt, IRQF_SHARED, card->shortname, chip) snd_intel8x0_interrupt snd_intel8x0_update

snd_open

==> snd_pcm_playback_open ==> snd_pcm_open ==> snd_pcm_open_file

==> snd_pcm_open_substream

==> substream->ops->open(substream)即snd_intel8x0_playback_ops.open

==> snd_intel8x0_playback_open ==> snd_intel8x0_pcm_open

static int snd_intel8x0_pcm_open(struct snd_pcm_substream *substream, struct ichdev *ichdev) {

struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; int err;

ichdev->substream = substream;

runtime->hw = snd_intel8x0_stream; // 声卡配置硬件信息[luther.gliethttp]

runtime->hw.rates = ichdev->pcm->rates; snd_pcm_limit_hw_rates(runtime);

if (chip->device_type == DEVICE_SIS) {

runtime->hw.buffer_bytes_max = 64*1024; runtime->hw.period_bytes_max = 64*1024; }

if ((err = snd_pcm_hw_constraint_integer(runtime, SNDRV_PCM_HW_PARAM_PERIODS)) < 0) return err;

runtime->private_data = ichdev; return 0; }

ioctl(SNDRV_PCM_IOCTL_HW_PARAMS)

==> snd_pcm_f_ops.unlocked_ioctl即:snd_pcm_playback_ioctl ==> snd_pcm_playback_ioctl ==> snd_pcm_playback_ioctl1 ==> snd_pcm_common_ioctl1

case SNDRV_PCM_IOCTL_HW_PARAMS:

return snd_pcm_hw_params_user(substream, arg); ==> snd_pcm_hw_params_user ==> snd_pcm_hw_params

==> substream->ops->hw_params即snd_intel8x0_playback_ops.hw_params ==> snd_intel8x0_hw_params

==> snd_ac97_pcm_open(ichdev->pcm, params_rate(hw_params), params_channels(hw_params), ichdev->pcm->r[dbl].slots);

ioctl(SNDRV_PCM_IOCTL_PREPARE) ==> snd_pcm_playback_ioctl ==> snd_pcm_playback_ioctl1 ==> snd_pcm_common_ioctl1

==> snd_pcm_prepare // prepare the PCM substream to be triggerable ==> snd_pcm_action_nonatomic(&snd_pcm_action_prepare, substream, f_flags);

==> snd_pcm_action_single(ops, substream, state); ops->pre_action(substream, state); ops->do_action(substream, state); ops->post_action(substream, state);

上面ops就是之前提到的snd_pcm_action_prepare

==> snd_pcm_do_prepare调用snd_pcm_do_reset(substream, 0);复位

substream->ops->prepare(substream);即snd_intel8x0_playback_ops.prepare

==> snd_intel8x0_pcm_prepare

static int snd_intel8x0_pcm_prepare(struct snd_pcm_substream *substream) {

struct intel8x0 *chip = snd_pcm_substream_chip(substream); struct snd_pcm_runtime *runtime = substream->runtime; struct ichdev *ichdev = get_ichdev(substream);

ichdev->physbuf = runtime->dma_addr; // dma缓冲区地址

ichdev->size = snd_pcm_lib_buffer_bytes(substream); // 将帧缓冲大小转为字节空间大小[luther.gliethttp] ichdev->fragsize = snd_pcm_lib_period_bytes(substream); if (ichdev->ichd == ICHD_PCMOUT) {

snd_intel8x0_setup_pcm_out(chip, runtime); // 为play模式设置ac97寄存器[luther.gliethttp] if (chip->device_type == DEVICE_INTEL_ICH4)

ichdev->pos_shift = (runtime->sample_bits > 16) ? 2 : 1; }

snd_intel8x0_setup_periods(chip, ichdev); // 设置PCI总线ac97的bank地址空间[luther.gliethttp] return 0; }

==> snd_intel8x0_setup_pcm_out

static void snd_intel8x0_setup_pcm_out(struct intel8x0 *chip, struct snd_pcm_runtime *runtime) {

unsigned int cnt;

int dbl = runtime->rate > 48000;

// 一共有如下几种设备:enum { DEVICE_INTEL, DEVICE_INTEL_ICH4, DEVICE_SIS, DEVICE_ALI, DEVICE_NFORCE };

spin_lock_irq(&chip->reg_lock); switch (chip->device_type) { case DEVICE_ALI: