(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: