本节博客开始介绍,alsa声卡的软件框架。
1.入口函数alsa_sound_init
kernel/linux-3.4.2/sound/core/Sound.c
static const struct file_operations snd_fops = { .owner = THIS_MODULE, .open = snd_open, .llseek = noop_llseek, };
static int __init alsa_sound_init(void) { snd_major = major; snd_ecards_limit = cards_limit; if (register_chrdev(major, "alsa", &snd_fops)) { snd_printk(KERN_ERR "unable to register native major device number %d\n", major); }
在snd_fops中只有open函数,并没有读写函数。可以猜测的出来,这个snd_fops中的open函数只是起到一个中转的作用,它肯定会找到一个新的file_operation结构体。
static int snd_open(struct inode *inode, struct file *file) { unsigned int minor = iminor(inode); struct snd_minor *mptr = NULL; const struct file_operations *old_fops; //以次设备号minor在数组snd_minors中找到一项。 mptr = snd_minors[minor]; old_fops = file->f_op; //取出file_operation结构体 file->f_op = fops_get(mptr->f_ops); if (file->f_op->open) { err = file->f_op->open(inode, file); }
2.数组snd_minors是由谁进行设置的呢?
/** * snd_register_device_for_dev - Register the ALSA device file for the card * @type: the device type, SNDRV_DEVICE_TYPE_XXX * @card: the card instance * @dev: the device index * @f_ops: the file operations * @private_data: user pointer for f_ops->open() * @name: the device file name * @device: the &struct device to link this new device to * * Registers an ALSA device file for the given card. * The operators have to be set in reg parameter. * * Returns zero if successful, or a negative error code on failure. */ int snd_register_device_for_dev(int type, struct snd_card *card, int dev, const struct file_operations *f_ops, void *private_data, const char *name, struct device *device) { int minor; struct snd_minor *preg; preg = kmalloc(sizeof *preg, GFP_KERNEL); preg->type = type; preg->card = card ? card->number : -1; preg->device = dev; preg->f_ops = f_ops; preg->private_data = private_data; #ifdef CONFIG_SND_DYNAMIC_MINORS minor = snd_find_free_minor(type); #else minor = snd_kernel_minor(type, card, dev); #endif snd_minors[minor] = preg; preg->dev = device_create(sound_class, device, MKDEV(major, minor), private_data, "%s", name); return 0; }
3.函数snd_register_device_for_dev是在哪被调用的呢?
函数snd_register_device_for_dev在两个地方被调用:1)snd_register_device 2)snd_pcm_dev_register
3.1 snd_register_device
kernel/linux-3.4.2/include/sound/Core.h
static inline int snd_register_device(int type, struct snd_card *card, int dev, const struct file_operations *f_ops, void *private_data, const char *name) { return snd_register_device_for_dev(type, card, dev, f_ops, private_data, name, snd_card_get_device_link(card)); }
3.1.1函数snd_register_device又是在哪被调用的呢?
kernel/linux-3.4.2/sound/core/Control.c
/* * registration of the control device */ static int snd_ctl_dev_register(struct snd_device *device) { struct snd_card *card = device->device_data; int err, cardnum; char name[16]; cardnum = card->number; sprintf(name, "controlC%i", cardnum); if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1, &snd_ctl_f_ops, card, name)) < 0) return err; return 0; }
3.1.2函数snd_ctl_dev_register又是在哪被调用的呢?
/* * create control core: * called from init.c */ int snd_ctl_create(struct snd_card *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 snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops); }
3.1.3 snd_ctl_create又是在哪被调用的呢?
/** * snd_card_create - create and initialize a soundcard structure * @idx: card index (address) [0 ... (SNDRV_CARDS-1)] * @xid: card identification (ASCII string) * @module: top level module for locking * @extra_size: allocate this extra size after the main soundcard structure * @card_ret: the pointer to store the created card instance * * Creates and initializes a soundcard structure. * * The function allocates snd_card instance via kzalloc with the given * space for the driver to use freely. The allocated struct is stored * in the given card_ret pointer. * * Returns zero if successful or a negative error code. */ int snd_card_create(int idx, const char *xid, struct module *module, int extra_size, struct snd_card **card_ret) { struct snd_card *card; card->number = idx; card->module = module; /* the control interface cannot be accessed from the user space until */ /* snd_cards_bitmask and snd_cards are set with snd_card_register */ err = snd_ctl_create(card); }
3.1.4 函数snd_card_create又是在哪被调用的呢?
3.2 snd_pcm_dev_register在哪被调用的呢?
kernel/linux-3.4.2/sound/core/Pcm.c
static int _snd_pcm_new(struct snd_card *card, const char *id, int device, int playback_count, int capture_count, bool internal, 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, }; }
3.2.1 函数_snd_pcm_new又是在哪被调用的呢?
/** * snd_pcm_new - create a new PCM instance * @card: the card instance * @id: the id string * @device: the device index (zero based) * @playback_count: the number of substreams for playback * @capture_count: the number of substreams for capture * @rpcm: the pointer to store the new pcm instance * * Creates a new PCM instance. * * The pcm operators have to be set afterwards to the new instance * via snd_pcm_set_ops(). * * Returns zero if successful, or a negative error code on failure. */ int snd_pcm_new(struct snd_card *card, const char *id, int device, int playback_count, int capture_count, struct snd_pcm **rpcm) { return _snd_pcm_new(card, id, device, playback_count, capture_count, false, rpcm); }
3.2.2函数snd_pcm_new调用的呢?
有很多文件调用了snd_pcm_new接口,对应不同的声卡。某个声卡驱动程序中调用了snd_pcm_new接口。