Android音频驱动-ASOC之Control Device创建

来源:互联网 发布:夏易网络王宇阳视频 编辑:程序博客网 时间:2024/05/21 23:43
soc-core.c    snd_soc_instantiate_cardinit.c    snd_card_newcontrol.c    snd_ctl_create

Control设备和PCM设备一样,都属于声卡下的逻辑设备。用户空间的应用程序通过alsa-lib访问该Control设备,
读取或控制control的控制状态,从而达到控制音频Codec进行各种Mixer等控制操作。
Control设备的创建过程大体上和PCM设备的创建过程相同。

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,    };    if (snd_BUG_ON(!card))        return -ENXIO;    return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);}int snd_device_new(struct snd_card *card, enum snd_device_type type,           void *device_data, struct snd_device_ops *ops){    struct snd_device *dev;    struct list_head *p;    if (snd_BUG_ON(!card || !device_data || !ops))        return -ENXIO;    dev = kzalloc(sizeof(*dev), GFP_KERNEL);    if (dev == NULL) {        dev_err(card->dev, "Cannot allocate device, type=%d\n", type);        return -ENOMEM;    }    INIT_LIST_HEAD(&dev->list);    dev->card = card;    dev->type = type;    dev->state = SNDRV_DEV_BUILD;    dev->device_data = device_data;    dev->ops = ops;    /* insert the entry in an incrementally sorted list */    list_for_each_prev(p, &card->devices) {        struct snd_device *pdev = list_entry(p, struct snd_device, list);        if ((unsigned int)pdev->type <= (unsigned int)type)            break;    }    list_add(&dev->list, p);    return 0;}
soc-core.c    snd_soc_instantiate_cardinit.c    snd_card_registerdevice.c    snd_device_register_all    __snd_device_register    dev->ops->dev_register(dev);control.c    snd_ctl_dev_register

和pcm设备一样,control设备的名字遵循一定的规则:controlCxx,这里的xx代表声卡的编号。
我们也可以通过代码正是这一点,下面的是snd_ctl_dev_register()函数的代码:

/*static const struct file_operations snd_ctl_f_ops ={    .owner =    THIS_MODULE,    .read =     snd_ctl_read,    .open =     snd_ctl_open,    .release =  snd_ctl_release,    .llseek =   no_llseek,    .poll =     snd_ctl_poll,    .unlocked_ioctl =   snd_ctl_ioctl,    .compat_ioctl = snd_ctl_ioctl_compat,    .fasync =   snd_ctl_fasync,};*/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;}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));}

control设备的相关信息被保存在snd_minors[]数组中,用control设备的此设备号作索引,
即可在snd_minors[]数组中找出相关的信息。用户程序需要打开control设备时,
驱动程序通过snd_minors[]全局数组和此设备号,可以获得snd_ctl_f_ops结构中的各个回调函数,
然后通过这些回调函数访问control中的信息和数据

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;    preg->card_ptr = card;    mutex_lock(&sound_mutex);    minor = snd_kernel_minor(type, card, dev);    if (minor >= 0 && snd_minors[minor])        minor = -EBUSY;    if (minor < 0) {        mutex_unlock(&sound_mutex);        kfree(preg);        return minor;    }    snd_minors[minor] = preg;    preg->dev = device_create(sound_class, device, MKDEV(major, minor),                  private_data, "%s", name);    if (IS_ERR(preg->dev)) {        snd_minors[minor] = NULL;        mutex_unlock(&sound_mutex);        minor = PTR_ERR(preg->dev);        kfree(preg);        return minor;    }    mutex_unlock(&sound_mutex);    return 0;}