1. 程式人生 > >linux音訊子系統 - control裝置

linux音訊子系統 - control裝置

control裝置主要是能控制音訊裝置的音量、開關等,在驅動中有兩個主要的結構體:snd_kcontrol_new和snd_kcontrol,驅動開發者主要是定義這兩個結構體,來進行control裝置的開發

結構體

struct snd_kcontrol_new

此結構體類似模板,最終還是要構成一個snd_kcontrol結構體來進行註冊

(include/sound/control.h)

struct snd_kcontrol_new {
    snd_ctl_elem_iface_t iface; /* interface identifier */
unsigned int device; /* device/client number */ unsigned int subdevice; /* subdevice (substream) number */ const unsigned char *name; /* ASCII name of item */ unsigned int index; /* index of item */ unsigned int access; /* access rights */ unsigned int count; /* count of same elements */
snd_kcontrol_info_t *info; snd_kcontrol_get_t *get;--------相當於read snd_kcontrol_put_t *put;--------相當於write union { snd_kcontrol_tlv_rw_t *c; const unsigned int *p; } tlv; unsigned long private_value; };

struct snd_kcontrol

(include/sound/control.h)

struct
snd_kcontrol { struct list_head list; /* list of controls */ struct snd_ctl_elem_id id; unsigned int count; /* count of same elements */ snd_kcontrol_info_t *info; snd_kcontrol_get_t *get; snd_kcontrol_put_t *put; union { snd_kcontrol_tlv_rw_t *c; const unsigned int *p; } tlv; unsigned long private_value; void *private_data; void (*private_free)(struct snd_kcontrol *kcontrol); struct snd_kcontrol_volatile vd[0]; /* volatile data */ };

control設備註冊

驅動架構文章中,我們知道音效卡註冊最終會呼叫到每個子裝置的註冊函式,control裝置屬於音效卡的子裝置,所以control裝置得先註冊到音效卡中

control註冊進音效卡

snd_ctl_create會把control註冊到音效卡中

(sound/core/control.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,------------control註冊函式
        .dev_disconnect = snd_ctl_dev_disconnect,
    };

    if (snd_BUG_ON(!card))
        return -ENXIO;
    return snd_device_new(card, SNDRV_DEV_CONTROL, card, &ops);---把control加入到音效卡的devices連結串列中
}

card註冊時,最終呼叫此函式來進行control註冊:

static int snd_ctl_dev_register(struct snd_device *device)
{
    struct snd_card *card = device->device_data;
    int err, cardnum;
    char name[16];

    if (snd_BUG_ON(!card))
        return -ENXIO;
    cardnum = card->number;
    if (snd_BUG_ON(cardnum < 0 || cardnum >= SNDRV_CARDS))
        return -ENXIO;
    sprintf(name, "controlC%i", cardnum);
    if ((err = snd_register_device(SNDRV_DEVICE_TYPE_CONTROL, card, -1,
                       &snd_ctl_f_ops, card, name)) < 0)------最終呼叫device_create進行設備註冊
        return err;
    return 0;
}

control單元加入到control裝置

control這個裝置是有好幾種單元來組成的,每個單元相對應一個snd_kcontrol,所以上層要操作的control都是要先找到對應的control單元,再來進行操作,所以在註冊的時候,要把control單元都加入到音效卡中

int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
{
    struct snd_ctl_elem_id id;
    unsigned int idx;
    unsigned int count;
    int err = -EINVAL;

    if (! kcontrol)
        return err;
    if (snd_BUG_ON(!card || !kcontrol->info))
        goto error;
    id = kcontrol->id;
    if (id.index > UINT_MAX - kcontrol->count)
        goto error;

    down_write(&card->controls_rwsem);
    if (snd_ctl_find_id(card, &id)) {
        up_write(&card->controls_rwsem);
        snd_printd(KERN_ERR "control %i:%i:%i:%s:%i is already present\n",
                    id.iface,
                    id.device,
                    id.subdevice,
                    id.name,
                    id.index);
        err = -EBUSY;
        goto error;
    }
    if (snd_ctl_find_hole(card, kcontrol->count) < 0) {
        up_write(&card->controls_rwsem);
        err = -ENOMEM;
        goto error;
    }
    list_add_tail(&kcontrol->list, &card->controls);---------加入音效卡的controls連結串列中
    card->controls_count += kcontrol->count;
    kcontrol->id.numid = card->last_numid + 1;
    card->last_numid += kcontrol->count;
    count = kcontrol->count;
    up_write(&card->controls_rwsem);
    for (idx = 0; idx < count; idx++, id.index++, id.numid++)
        snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_ADD, &id);
    return 0;

 error:
    snd_ctl_free_one(kcontrol);
    return err;
}

而對於snd_kcontrol_new結構體可以用下面的函式重定義成結構體snd_kcontrol

struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new * kcontrolnew, void * private_data);

control檔案操作

(sound/core/control.c)

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

這些ops操作函式最終要呼叫kcontrol的info/get/put函式,這些函式原型為:

typedef int (snd_kcontrol_info_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_info * uinfo);
typedef int (snd_kcontrol_get_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
typedef int (snd_kcontrol_put_t) (struct snd_kcontrol * kcontrol, struct snd_ctl_elem_value * ucontrol);
typedef int (snd_kcontrol_tlv_rw_t)(struct snd_kcontrol *kcontrol,
                    int op_flag, /* 0=read,1=write,-1=command */
                    unsigned int size,
                    unsigned int __user *tlv);

change log

date content linux
2017/11/24 origin 3.10