ALSA驱动框架


 一.前言

在alsa架构中,当应用程序调用open、read、write时,将调用驱动程序中的相应接口,本篇博客就从驱动程序中的snd_fops结构体开始说起。

二.  入口函数alsa_sound_init

kernel/linux-3.4.2/sound/core/Sound.c

1. snd_fops结构体

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); }

snp_fops结构体最终通过register_chrdev函数注册到系统中。从这个地方可以看出alsa驱动也是字符设备驱动。

在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接口。

 

 

 




免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM