linux音訊子系統 - control裝置
阿新 • • 發佈:2018-11-03
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 |