1. 程式人生 > >Android音訊驅動-ASOC之Control Device建立

Android音訊驅動-ASOC之Control Device建立

soc-core.c
    snd_soc_instantiate_card
init.c
    snd_card_new
control.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_card
init.c
    snd_card_register
device.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;
}