struct mixer *mixer_open(unsigned int card)
{
struct snd_ctl_elem_list elist;
struct snd_ctl_elem_info tmp;
struct snd_ctl_elem_id *eid = NULL;
struct mixer *mixer = NULL;
unsigned int n, m;
int fd;
char fn[256];
/* 获取对应操作的文件句柄名称 */
snprintf(fn, sizeof(fn), "/dev/snd/controlC%u", card);
fd = open(fn, O_RDWR);//打开control设备
memset(&elist, 0, sizeof(elist));
/* 第一遍调用SNDRV_CTL_IOCTL_ELEM_LIST,获取snd_kcontrol的个数 */
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
goto fail;
mixer = calloc(1, sizeof(*mixer));/* 获取个数后,对应分配空间 */
mixer->ctl = calloc(elist.count, sizeof(struct mixer_ctl));
mixer->elem_info = calloc(elist.count, sizeof(struct snd_ctl_elem_info));
if (ioctl(fd, SNDRV_CTL_IOCTL_CARD_INFO, &mixer->card_info) < 0)//获取card信息
goto fail;
eid = calloc(elist.count, sizeof(struct snd_ctl_elem_id));
mixer->count = elist.count;
mixer->fd = fd;
elist.space = mixer->count;//space大于0,第二次调用SNDRV_CTL_IOCTL_ELEM_LIST获取更多信息
elist.pids = eid;//传入kernel获得实际值,包含了所有kctl的id对象
/* 第二遍调用,获取对应的snd_ctl_elem_id数组,且numid从1开始,0表示无效 */
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_LIST, &elist) < 0)
goto fail;
for (n = 0; n < mixer->count; n++) {
struct snd_ctl_elem_info *ei = mixer->elem_info + n;
ei->id.numid = eid[n].numid;//从kernel获得了实际的numid值
/*根据获取的snd_kcontrol对应的numid,调用获取对应的snd_ctl_elem_info,
内核的具体步骤是,根据numid,获取对应的snd_kcontrol,之后调用其info操
作接口,填充用户传入snd_ctl_elem_info缓冲。*/
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, ei) < 0)//第一次获取指定控件信息,例如enumerated.items
goto fail;
mixer->ctl[n].info = ei;
mixer->ctl[n].mixer = mixer;
/* 如果为枚举量,还需要进一步获取每个枚举量对应的字符串描述 */
if (ei->type == SNDRV_CTL_ELEM_TYPE_ENUMERATED) {
char **enames = calloc(ei->value.enumerated.items, sizeof(char*));//根据字符串的个数来申请,如on、off
mixer->ctl[n].ename = enames;
for (m = 0; m < ei->value.enumerated.items; m++) {
memset(&tmp, 0, sizeof(tmp));
tmp.id.numid = ei->id.numid;
tmp.value.enumerated.item = m;//字符串下标
if (ioctl(fd, SNDRV_CTL_IOCTL_ELEM_INFO, &tmp) < 0)//第二次
goto fail;
enames[m] = strdup(tmp.value.enumerated.name);//将字符串On、Off保存在mixer->ctl[n].ename中
}
}
}
return mixer;
}
static int snd_open(struct inode *inode, struct file *file)
{
unsigned int minor = iminor(inode);
struct snd_minor *mptr = NULL;
const struct file_operations *new_fops;
int err = 0;
if (minor >= ARRAY_SIZE(snd_minors))
return -ENODEV;
mptr = snd_minors[minor];
new_fops = fops_get(mptr->f_ops);
replace_fops(file, new_fops);
if (file->f_op->open)
err = file->f_op->open(inode, file);
return err;
}
/*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_open(struct inode *inode, struct file *file)
{
unsigned long flags;
struct snd_card *card;
struct snd_ctl_file *ctl;
int err;
err = nonseekable_open(inode, file);
card = snd_lookup_minor_data(iminor(inode), SNDRV_DEVICE_TYPE_CONTROL);
err = snd_card_file_add(card, file);
ctl = kzalloc(sizeof(*ctl), GFP_KERNEL);
ctl->card = card;
ctl->prefer_pcm_subdevice = -1;
ctl->prefer_rawmidi_subdevice = -1;
ctl->pid = get_pid(task_pid(current));
file->private_data = ctl;//保存snd_ctl_file对象
list_add_tail(&ctl->list, &card->ctl_files);
return 0;
}
获取所有kcontrol的列表,包含了所有kcontrol对应的物理控件
static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
case SNDRV_CTL_IOCTL_ELEM_LIST:
return snd_ctl_elem_list(card, argp);
}
static int snd_ctl_elem_list(struct snd_card *card,
struct snd_ctl_elem_list __user *_list)
{
struct list_head *plist;
struct snd_ctl_elem_list list;
struct snd_kcontrol *kctl;
struct snd_ctl_elem_id *dst, *id;
unsigned int offset, space, jidx;