|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \file control/control_ext.c
|
|
Packit Service |
db8eaa |
* \ingroup CtlPlugin_SDK
|
|
Packit Service |
db8eaa |
* \brief External Control Plugin SDK
|
|
Packit Service |
db8eaa |
* \author Takashi Iwai <tiwai@suse.de>
|
|
Packit Service |
db8eaa |
* \date 2005
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
/*
|
|
Packit Service |
db8eaa |
* Control Interface - External Control Plugin SDK
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* Copyright (c) 2005 Takashi Iwai <tiwai@suse.de>
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* This library is free software; you can redistribute it and/or modify
|
|
Packit Service |
db8eaa |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit Service |
db8eaa |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
db8eaa |
* the License, or (at your option) any later version.
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
db8eaa |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
db8eaa |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
db8eaa |
* GNU Lesser General Public License for more details.
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
db8eaa |
* License along with this library; if not, write to the Free Software
|
|
Packit Service |
db8eaa |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#include <stdio.h>
|
|
Packit Service |
db8eaa |
#include <stdlib.h>
|
|
Packit Service |
db8eaa |
#include <unistd.h>
|
|
Packit Service |
db8eaa |
#include <string.h>
|
|
Packit Service |
db8eaa |
#include "control_local.h"
|
|
Packit Service |
db8eaa |
#include "control_external.h"
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
#ifndef PIC
|
|
Packit Service |
db8eaa |
/* entry for static linking */
|
|
Packit Service |
db8eaa |
const char *_snd_module_control_ext = "";
|
|
Packit Service |
db8eaa |
#endif
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_close(snd_ctl_t *handle)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (ext->callback->close)
|
|
Packit Service |
db8eaa |
ext->callback->close(ext);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_nonblock(snd_ctl_t *handle, int nonblock)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
ext->nonblock = nonblock;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_async(snd_ctl_t *ctl ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
int sig ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
pid_t pid ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return -ENOSYS;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_subscribe_events(snd_ctl_t *handle, int subscribe)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (subscribe < 0)
|
|
Packit Service |
db8eaa |
return ext->subscribed;
|
|
Packit Service |
db8eaa |
ext->subscribed = !!subscribe;
|
|
Packit Service |
db8eaa |
if (ext->callback->subscribe_events)
|
|
Packit Service |
db8eaa |
ext->callback->subscribe_events(ext, subscribe);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_card_info(snd_ctl_t *handle, snd_ctl_card_info_t *info)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
memset(info, 0, sizeof(*info));
|
|
Packit Service |
db8eaa |
info->card = ext->card_idx;
|
|
Packit Service |
db8eaa |
memcpy(info->id, ext->id, sizeof(info->id));
|
|
Packit Service |
db8eaa |
memcpy(info->driver, ext->driver, sizeof(info->driver));
|
|
Packit Service |
db8eaa |
memcpy(info->name, ext->name, sizeof(info->name));
|
|
Packit Service |
db8eaa |
memcpy(info->longname, ext->longname, sizeof(info->longname));
|
|
Packit Service |
db8eaa |
memcpy(info->mixername, ext->mixername, sizeof(info->mixername));
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_elem_list(snd_ctl_t *handle, snd_ctl_elem_list_t *list)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
int ret;
|
|
Packit Service |
db8eaa |
unsigned int i, offset;
|
|
Packit Service |
db8eaa |
snd_ctl_elem_id_t *ids;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
list->count = ext->callback->elem_count(ext);
|
|
Packit Service |
db8eaa |
list->used = 0;
|
|
Packit Service |
db8eaa |
ids = list->pids;
|
|
Packit Service |
db8eaa |
offset = list->offset;
|
|
Packit Service |
db8eaa |
for (i = 0; i < list->space; i++) {
|
|
Packit Service |
db8eaa |
if (offset >= list->count)
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
snd_ctl_elem_id_clear(ids);
|
|
Packit Service |
db8eaa |
ret = ext->callback->elem_list(ext, offset, ids);
|
|
Packit Service |
db8eaa |
if (ret < 0)
|
|
Packit Service |
db8eaa |
return ret;
|
|
Packit Service |
db8eaa |
ids->numid = offset + 1; /* fake number */
|
|
Packit Service |
db8eaa |
list->used++;
|
|
Packit Service |
db8eaa |
offset++;
|
|
Packit Service |
db8eaa |
ids++;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static snd_ctl_ext_key_t get_elem(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int numid = id->numid;
|
|
Packit Service |
db8eaa |
if (numid > 0) {
|
|
Packit Service |
db8eaa |
ext->callback->elem_list(ext, numid - 1, id);
|
|
Packit Service |
db8eaa |
id->numid = numid;
|
|
Packit Service |
db8eaa |
} else
|
|
Packit Service |
db8eaa |
id->numid = 0;
|
|
Packit Service |
db8eaa |
return ext->callback->find_elem(ext, id);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_elem_info(snd_ctl_t *handle, snd_ctl_elem_info_t *info)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
snd_ctl_ext_key_t key;
|
|
Packit Service |
db8eaa |
int type, ret;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
key = get_elem(ext, &info->id);
|
|
Packit Service |
db8eaa |
if (key == SND_CTL_EXT_KEY_NOT_FOUND)
|
|
Packit Service |
db8eaa |
return -ENOENT;
|
|
Packit Service |
db8eaa |
ret = ext->callback->get_attribute(ext, key, &type, &info->access, &info->count);
|
|
Packit Service |
db8eaa |
if (ret < 0)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
info->type = type;
|
|
Packit Service |
db8eaa |
ret = -EINVAL;
|
|
Packit Service |
db8eaa |
switch (info->type) {
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_BOOLEAN:
|
|
Packit Service |
db8eaa |
info->value.integer.min = 0;
|
|
Packit Service |
db8eaa |
info->value.integer.max = 1;
|
|
Packit Service |
db8eaa |
ret = 0;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_INTEGER:
|
|
Packit Service |
db8eaa |
if (! ext->callback->get_integer_info)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->get_integer_info(ext, key, &info->value.integer.min,
|
|
Packit Service |
db8eaa |
&info->value.integer.max,
|
|
Packit Service |
db8eaa |
&info->value.integer.step);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_INTEGER64:
|
|
Packit Service |
db8eaa |
if (! ext->callback->get_integer64_info)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
int64_t xmin, xmax, xstep;
|
|
Packit Service |
db8eaa |
ret = ext->callback->get_integer64_info(ext, key,
|
|
Packit Service |
db8eaa |
&xmin,
|
|
Packit Service |
db8eaa |
&xmax,
|
|
Packit Service |
db8eaa |
&xstep);
|
|
Packit Service |
db8eaa |
info->value.integer64.min = xmin;
|
|
Packit Service |
db8eaa |
info->value.integer64.max = xmax;
|
|
Packit Service |
db8eaa |
info->value.integer64.step = xstep;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_ENUMERATED:
|
|
Packit Service |
db8eaa |
if (! ext->callback->get_enumerated_info)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->get_enumerated_info(ext, key, &info->value.enumerated.items);
|
|
Packit Service |
db8eaa |
ext->callback->get_enumerated_name(ext, key, info->value.enumerated.item,
|
|
Packit Service |
db8eaa |
info->value.enumerated.name,
|
|
Packit Service |
db8eaa |
sizeof(info->value.enumerated.name));
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
default:
|
|
Packit Service |
db8eaa |
ret = 0;
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err:
|
|
Packit Service |
db8eaa |
if (ext->callback->free_key)
|
|
Packit Service |
db8eaa |
ext->callback->free_key(ext, key);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return ret;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_elem_add(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_ctl_elem_info_t *info ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_elem_replace(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_ctl_elem_info_t *info ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_elem_remove(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_elem_read(snd_ctl_t *handle, snd_ctl_elem_value_t *control)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
snd_ctl_ext_key_t key;
|
|
Packit Service |
db8eaa |
int type, ret;
|
|
Packit Service |
db8eaa |
unsigned int access, count;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
key = get_elem(ext, &control->id);
|
|
Packit Service |
db8eaa |
if (key == SND_CTL_EXT_KEY_NOT_FOUND)
|
|
Packit Service |
db8eaa |
return -ENOENT;
|
|
Packit Service |
db8eaa |
ret = ext->callback->get_attribute(ext, key, &type, &access, &count);
|
|
Packit Service |
db8eaa |
if (ret < 0)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = -EINVAL;
|
|
Packit Service |
db8eaa |
switch (type) {
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_BOOLEAN:
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_INTEGER:
|
|
Packit Service |
db8eaa |
if (! ext->callback->read_integer)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->read_integer(ext, key, control->value.integer.value);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_INTEGER64:
|
|
Packit Service |
db8eaa |
if (! ext->callback->read_integer64)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->read_integer64(ext, key,
|
|
Packit Service |
db8eaa |
(int64_t*)control->value.integer64.value);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_ENUMERATED:
|
|
Packit Service |
db8eaa |
if (! ext->callback->read_enumerated)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->read_enumerated(ext, key, control->value.enumerated.item);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_BYTES:
|
|
Packit Service |
db8eaa |
if (! ext->callback->read_bytes)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->read_bytes(ext, key, control->value.bytes.data,
|
|
Packit Service |
db8eaa |
sizeof(control->value.bytes.data));
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_IEC958:
|
|
Packit Service |
db8eaa |
if (! ext->callback->read_iec958)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->read_iec958(ext, key, (snd_aes_iec958_t *)&control->value.iec958);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
default:
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err:
|
|
Packit Service |
db8eaa |
if (ext->callback->free_key)
|
|
Packit Service |
db8eaa |
ext->callback->free_key(ext, key);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return ret;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_elem_write(snd_ctl_t *handle, snd_ctl_elem_value_t *control)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
snd_ctl_ext_key_t key;
|
|
Packit Service |
db8eaa |
int type, ret;
|
|
Packit Service |
db8eaa |
unsigned int access, count;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
key = get_elem(ext, &control->id);
|
|
Packit Service |
db8eaa |
if (key == SND_CTL_EXT_KEY_NOT_FOUND)
|
|
Packit Service |
db8eaa |
return -ENOENT;
|
|
Packit Service |
db8eaa |
ret = ext->callback->get_attribute(ext, key, &type, &access, &count);
|
|
Packit Service |
db8eaa |
if (ret < 0)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = -EINVAL;
|
|
Packit Service |
db8eaa |
switch (type) {
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_BOOLEAN:
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_INTEGER:
|
|
Packit Service |
db8eaa |
if (! ext->callback->write_integer)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->write_integer(ext, key, control->value.integer.value);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_INTEGER64:
|
|
Packit Service |
db8eaa |
if (! ext->callback->write_integer64)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->write_integer64(ext, key, (int64_t *)control->value.integer64.value);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_ENUMERATED:
|
|
Packit Service |
db8eaa |
if (! ext->callback->write_enumerated)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->write_enumerated(ext, key, control->value.enumerated.item);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_BYTES:
|
|
Packit Service |
db8eaa |
if (! ext->callback->write_bytes)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->write_bytes(ext, key, control->value.bytes.data,
|
|
Packit Service |
db8eaa |
sizeof(control->value.bytes.data));
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
case SND_CTL_ELEM_TYPE_IEC958:
|
|
Packit Service |
db8eaa |
if (! ext->callback->write_iec958)
|
|
Packit Service |
db8eaa |
goto err;
|
|
Packit Service |
db8eaa |
ret = ext->callback->write_iec958(ext, key, (snd_aes_iec958_t *)&control->value.iec958);
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
default:
|
|
Packit Service |
db8eaa |
break;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err:
|
|
Packit Service |
db8eaa |
if (ext->callback->free_key)
|
|
Packit Service |
db8eaa |
ext->callback->free_key(ext, key);
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return ret;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_elem_lock(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_elem_unlock(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_elem_tlv(snd_ctl_t *handle, int op_flag,
|
|
Packit Service |
db8eaa |
unsigned int numid,
|
|
Packit Service |
db8eaa |
unsigned int *tlv, unsigned int tlv_size)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
snd_ctl_ext_key_t key;
|
|
Packit Service |
db8eaa |
int type, ret;
|
|
Packit Service |
db8eaa |
unsigned int access, count, len;
|
|
Packit Service |
db8eaa |
snd_ctl_elem_id_t id;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/* we don't support TLV on protocol ver 1.0.0 or earlier */
|
|
Packit Service |
db8eaa |
if (ext->version <= SNDRV_PROTOCOL_VERSION(1, 0, 0))
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
snd_ctl_elem_id_clear(&id;;
|
|
Packit Service |
db8eaa |
if (numid > 0) {
|
|
Packit Service |
db8eaa |
ext->callback->elem_list(ext, numid - 1, &id;;
|
|
Packit Service |
db8eaa |
id.numid = numid;
|
|
Packit Service |
db8eaa |
} else
|
|
Packit Service |
db8eaa |
id.numid = 0;
|
|
Packit Service |
db8eaa |
key = ext->callback->find_elem(ext, &id;;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (key == SND_CTL_EXT_KEY_NOT_FOUND)
|
|
Packit Service |
db8eaa |
return -ENOENT;
|
|
Packit Service |
db8eaa |
ret = ext->callback->get_attribute(ext, key, &type, &access, &count);
|
|
Packit Service |
db8eaa |
if (ret < 0)
|
|
Packit Service |
db8eaa |
return ret;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if ((op_flag == 0 && (access & SND_CTL_EXT_ACCESS_TLV_READ) == 0) ||
|
|
Packit Service |
db8eaa |
(op_flag > 0 && (access & SND_CTL_EXT_ACCESS_TLV_WRITE) == 0) ||
|
|
Packit Service |
db8eaa |
(op_flag < 0 && (access & SND_CTL_EXT_ACCESS_TLV_COMMAND) == 0))
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
if (access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
|
|
Packit Service |
db8eaa |
return ext->tlv.c(ext, key, op_flag, numid, tlv, tlv_size);
|
|
Packit Service |
db8eaa |
} else {
|
|
Packit Service |
db8eaa |
if (op_flag)
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
len = ext->tlv.p[1] + 2 * sizeof(unsigned int);
|
|
Packit Service |
db8eaa |
if (tlv_size < len)
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
memcpy(tlv, ext->tlv.p, len);
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_next_device(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
int *device ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_prefer_subdevice(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
int subdev ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_hwdep_info(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_hwdep_info_t *info ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_pcm_info(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_pcm_info_t *info ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_rawmidi_info(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
snd_rawmidi_info_t *info ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_set_power_state(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
unsigned int state ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_get_power_state(snd_ctl_t *handle ATTRIBUTE_UNUSED,
|
|
Packit Service |
db8eaa |
unsigned int *state ATTRIBUTE_UNUSED)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_read(snd_ctl_t *handle, snd_ctl_event_t *event)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (ext->callback->read_event) {
|
|
Packit Service |
db8eaa |
memset(event, 0, sizeof(*event));
|
|
Packit Service |
db8eaa |
return ext->callback->read_event(ext, &event->data.elem.id, &event->data.elem.mask);
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_poll_descriptors_count(snd_ctl_t *handle)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (ext->callback->poll_descriptors_count)
|
|
Packit Service |
db8eaa |
return ext->callback->poll_descriptors_count(ext);
|
|
Packit Service |
db8eaa |
if (ext->poll_fd >= 0)
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_poll_descriptors(snd_ctl_t *handle, struct pollfd *pfds, unsigned int space)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (ext->callback->poll_descriptors)
|
|
Packit Service |
db8eaa |
return ext->callback->poll_descriptors(ext, pfds, space);
|
|
Packit Service |
db8eaa |
if (ext->poll_fd < 0)
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
if (space > 0) {
|
|
Packit Service |
db8eaa |
pfds->fd = ext->poll_fd;
|
|
Packit Service |
db8eaa |
pfds->events = POLLIN|POLLERR|POLLNVAL;
|
|
Packit Service |
db8eaa |
return 1;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static int snd_ctl_ext_poll_revents(snd_ctl_t *handle, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t *ext = handle->private_data;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (ext->callback->poll_revents)
|
|
Packit Service |
db8eaa |
return ext->callback->poll_revents(ext, pfds, nfds, revents);
|
|
Packit Service |
db8eaa |
if (nfds == 1) {
|
|
Packit Service |
db8eaa |
*revents = pfds->revents;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
static const snd_ctl_ops_t snd_ctl_ext_ops = {
|
|
Packit Service |
db8eaa |
.close = snd_ctl_ext_close,
|
|
Packit Service |
db8eaa |
.nonblock = snd_ctl_ext_nonblock,
|
|
Packit Service |
db8eaa |
.async = snd_ctl_ext_async,
|
|
Packit Service |
db8eaa |
.subscribe_events = snd_ctl_ext_subscribe_events,
|
|
Packit Service |
db8eaa |
.card_info = snd_ctl_ext_card_info,
|
|
Packit Service |
db8eaa |
.element_list = snd_ctl_ext_elem_list,
|
|
Packit Service |
db8eaa |
.element_info = snd_ctl_ext_elem_info,
|
|
Packit Service |
db8eaa |
.element_add = snd_ctl_ext_elem_add,
|
|
Packit Service |
db8eaa |
.element_replace = snd_ctl_ext_elem_replace,
|
|
Packit Service |
db8eaa |
.element_remove = snd_ctl_ext_elem_remove,
|
|
Packit Service |
db8eaa |
.element_read = snd_ctl_ext_elem_read,
|
|
Packit Service |
db8eaa |
.element_write = snd_ctl_ext_elem_write,
|
|
Packit Service |
db8eaa |
.element_lock = snd_ctl_ext_elem_lock,
|
|
Packit Service |
db8eaa |
.element_unlock = snd_ctl_ext_elem_unlock,
|
|
Packit Service |
db8eaa |
.element_tlv = snd_ctl_ext_elem_tlv,
|
|
Packit Service |
db8eaa |
.hwdep_next_device = snd_ctl_ext_next_device,
|
|
Packit Service |
db8eaa |
.hwdep_info = snd_ctl_ext_hwdep_info,
|
|
Packit Service |
db8eaa |
.pcm_next_device = snd_ctl_ext_next_device,
|
|
Packit Service |
db8eaa |
.pcm_info = snd_ctl_ext_pcm_info,
|
|
Packit Service |
db8eaa |
.pcm_prefer_subdevice = snd_ctl_ext_prefer_subdevice,
|
|
Packit Service |
db8eaa |
.rawmidi_next_device = snd_ctl_ext_next_device,
|
|
Packit Service |
db8eaa |
.rawmidi_info = snd_ctl_ext_rawmidi_info,
|
|
Packit Service |
db8eaa |
.rawmidi_prefer_subdevice = snd_ctl_ext_prefer_subdevice,
|
|
Packit Service |
db8eaa |
.set_power_state = snd_ctl_ext_set_power_state,
|
|
Packit Service |
db8eaa |
.get_power_state = snd_ctl_ext_get_power_state,
|
|
Packit Service |
db8eaa |
.read = snd_ctl_ext_read,
|
|
Packit Service |
db8eaa |
.poll_descriptors_count = snd_ctl_ext_poll_descriptors_count,
|
|
Packit Service |
db8eaa |
.poll_descriptors = snd_ctl_ext_poll_descriptors,
|
|
Packit Service |
db8eaa |
.poll_revents = snd_ctl_ext_poll_revents,
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/*
|
|
Packit Service |
db8eaa |
* Exported functions
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/*! \page ctl_external_plugins External Control Plugin SDK
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
\section ctl_externals External Control Plugins
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The external plugins are implemented in a shared object file located
|
|
Packit Service |
db8eaa |
at /usr/lib/alsa-lib (the exact location depends on the build option
|
|
Packit Service |
db8eaa |
and asoundrc configuration). It has to be the file like
|
|
Packit Service |
db8eaa |
libasound_module_ctl_MYPLUGIN.so, where MYPLUGIN corresponds to your
|
|
Packit Service |
db8eaa |
own plugin name.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The entry point of the plugin is defined via
|
|
Packit Service |
db8eaa |
#SND_CTL_PLUGIN_DEFINE_FUNC() macro. This macro defines the function
|
|
Packit Service |
db8eaa |
with a proper name to be referred from alsa-lib. The function takes
|
|
Packit Service |
db8eaa |
the following 5 arguments:
|
|
Packit Service |
db8eaa |
\code
|
|
Packit Service |
db8eaa |
int (snd_ctl_t **phandle, const char *name, snd_config_t *root,
|
|
Packit Service |
db8eaa |
snd_config_t *conf, int mode)
|
|
Packit Service |
db8eaa |
\endcode
|
|
Packit Service |
db8eaa |
The first argument, phandle, is the pointer to store the resultant control
|
|
Packit Service |
db8eaa |
handle. The arguments name, root and mode are the parameters
|
|
Packit Service |
db8eaa |
to be passed to the plugin constructor. The conf is the configuration
|
|
Packit Service |
db8eaa |
tree for the plugin. The arguments above are defined in the macro
|
|
Packit Service |
db8eaa |
itself, so don't use variables with the same names to shadow
|
|
Packit Service |
db8eaa |
parameters.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
After parsing the configuration parameters in the given conf tree,
|
|
Packit Service |
db8eaa |
usually you will call the external plugin API function
|
|
Packit Service |
db8eaa |
#snd_ctl_ext_create().
|
|
Packit Service |
db8eaa |
The control handle must be filled *phandle in return.
|
|
Packit Service |
db8eaa |
Then this function must return either a value 0 when succeeded, or a
|
|
Packit Service |
db8eaa |
negative value as the error code.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
Finally, add #SND_CTL_PLUGIN_SYMBOL() with the name of your
|
|
Packit Service |
db8eaa |
plugin as the argument at the end. This defines the proper versioned
|
|
Packit Service |
db8eaa |
symbol as the reference.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The typical code would look like below:
|
|
Packit Service |
db8eaa |
\code
|
|
Packit Service |
db8eaa |
struct myctl_info {
|
|
Packit Service |
db8eaa |
snd_ctl_ext_t ext;
|
|
Packit Service |
db8eaa |
int my_own_data;
|
|
Packit Service |
db8eaa |
...
|
|
Packit Service |
db8eaa |
};
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
SND_CTL_PLUGIN_DEFINE_FUNC(myctl)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_config_iterator_t i, next;
|
|
Packit Service |
db8eaa |
struct myctl_info *myctl;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
snd_config_for_each(i, next, conf) {
|
|
Packit Service |
db8eaa |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit Service |
db8eaa |
const char *id;
|
|
Packit Service |
db8eaa |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
if (strcmp(id, "my_own_parameter") == 0) {
|
|
Packit Service |
db8eaa |
....
|
|
Packit Service |
db8eaa |
continue;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
SNDERR("Unknown field %s", id);
|
|
Packit Service |
db8eaa |
return -EINVAL;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
myctl = calloc(1, sizeof(*myctl));
|
|
Packit Service |
db8eaa |
if (myctl == NULL)
|
|
Packit Service |
db8eaa |
return -ENOMEM;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
myctl->ext.version = SND_CTL_EXT_VERSION;
|
|
Packit Service |
db8eaa |
myctl->ext.card_idx = 0;
|
|
Packit Service |
db8eaa |
strcpy(myctl->ext.id, "Myctl");
|
|
Packit Service |
db8eaa |
strcpy(myctl->ext.name, "My Control");
|
|
Packit Service |
db8eaa |
strcpy(myctl->ext.longname, "My External Control for Foobar");
|
|
Packit Service |
db8eaa |
strcpy(myctl->ext.mixername, "My Control");
|
|
Packit Service |
db8eaa |
myctl->ext.callback = &my_own_callback;
|
|
Packit Service |
db8eaa |
myctl->ext.private_data = myctl;
|
|
Packit Service |
db8eaa |
....
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = snd_pcm_extplug_create(&myctl->ext, name, mode);
|
|
Packit Service |
db8eaa |
if (err < 0) {
|
|
Packit Service |
db8eaa |
myctl_free(myctl);
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
*phandle = myctl->ext.handle;
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
SND_CTL_PLUGIN_SYMBOL(myctl);
|
|
Packit Service |
db8eaa |
\endcode
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
Read the codes in alsa-plugins package for the real examples.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
\section ctl_ext_impl Implementation of External Control Plugins
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The following fields have to be filled in external control record before calling
|
|
Packit Service |
db8eaa |
#snd_ctl_ext_create() : version, card_idx, id, name, longname, mixername, poll_fd and callback.
|
|
Packit Service |
db8eaa |
Otherfields are optional and should be initialized with zero.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The constant #SND_CTL_EXT_VERSION must be passed to the version
|
|
Packit Service |
db8eaa |
field for the version check in alsa-lib. The card_idx field specifies the card
|
|
Packit Service |
db8eaa |
index of this control. [FIXME: solve confliction of card index in alsa-lib?]
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The id, name, longname and mixername fields are the strings shown in the card_info
|
|
Packit Service |
db8eaa |
inqurirys. They are the char arrays, so you have to copy strings to these
|
|
Packit Service |
db8eaa |
fields.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The callback field contains the table of callback functions for this plugin (defined as
|
|
Packit Service |
db8eaa |
#snd_ctl_ext_callback_t).
|
|
Packit Service |
db8eaa |
The poll_fd can be used to specify the poll file descriptor for this control.
|
|
Packit Service |
db8eaa |
Set -1 if not available. Alternatively, you can define poll_descriptors_count and
|
|
Packit Service |
db8eaa |
poll_descriptors callbacks in the callback table for handling the poll descriptor(s)
|
|
Packit Service |
db8eaa |
dynamically after the creation of plugin instance.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The driver can set an arbitrary value (pointer) to private_data
|
|
Packit Service |
db8eaa |
field to refer its own data in the callbacks.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The rest fields are filled by #snd_ctl_ext_create(). The handle field
|
|
Packit Service |
db8eaa |
is the resultant PCM handle. The others are the current status of the
|
|
Packit Service |
db8eaa |
PCM.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
\section ctl_ext_impl Callback Functions of External Control Plugins
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The callback functions in #snd_ctl_ext_callback_t define the real
|
|
Packit Service |
db8eaa |
behavior of the driver. There are many callbacks but many of them are optional.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The close callback is called when the PCM is closed. If the plugin
|
|
Packit Service |
db8eaa |
allocates private resources, this is the place to release them
|
|
Packit Service |
db8eaa |
again. This callback is optional.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The elem_count and elem_list callbacks are mandatory. The elem_count returns the
|
|
Packit Service |
db8eaa |
total number of control elements. The elem_list returns the control element ID
|
|
Packit Service |
db8eaa |
of the corresponding element offset (the offset is from 0 to elem_count - 1).
|
|
Packit Service |
db8eaa |
The id field is initialized to all zero in prior to elem_list callback. The callback
|
|
Packit Service |
db8eaa |
has to fill the necessary field (typically iface, name and index) in return via the
|
|
Packit Service |
db8eaa |
standard control API functions like #snd_ctl_elem_id_set_interface,
|
|
Packit Service |
db8eaa |
#snd_ctl_elem_id_set_name and #snd_ctl_elem_id_set_index, etc. The callbacks should
|
|
Packit Service |
db8eaa |
return 0 if successful, or a negative error code.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The find_elem callback is used to convert the given control element ID to the
|
|
Packit Service |
db8eaa |
certain key value for the faster access to get, read and write callbacks.
|
|
Packit Service |
db8eaa |
The key type is alias of unsigned long, so you can assign some static number
|
|
Packit Service |
db8eaa |
(e.g. index of the array) to this value of the corresponding element, or
|
|
Packit Service |
db8eaa |
assign the pointer (cast to #snd_ctl_ext_key_t). When no key is defined or found,
|
|
Packit Service |
db8eaa |
return #SND_CTL_EXT_KEY_NOT_FOUND. This callback is (very likely) required
|
|
Packit Service |
db8eaa |
if you use get, read and write callbacks as follows.
|
|
Packit Service |
db8eaa |
If you need to create a record dynamically (e.g. via malloc) at each find_elem call,
|
|
Packit Service |
db8eaa |
the allocated record can be released with the optional free_key callback.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The get_attribute is a mandatory callback, which returns the attribute of the
|
|
Packit Service |
db8eaa |
control element given via a key value (converted with find_elem callback).
|
|
Packit Service |
db8eaa |
It must fill the control element type (#snd_ctl_elem_type_t), the access type
|
|
Packit Service |
db8eaa |
(#snd_ctl_ext_access_t), and the count (element array size). The callback returns
|
|
Packit Service |
db8eaa |
0 if successful, or a negative error code, as usual.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The get_integer_info, get_integetr64_info and get_enumerated_info callbacks are called
|
|
Packit Service |
db8eaa |
to return the information of the given control element for each element type.
|
|
Packit Service |
db8eaa |
For integer and integer64 types, the callbacks need to fill the minimal (imin),
|
|
Packit Service |
db8eaa |
maximal (imax) and the step (istep) values of the control. For the enumerated type,
|
|
Packit Service |
db8eaa |
the number of enum items must be filled. Additionally, the enum control has to define
|
|
Packit Service |
db8eaa |
get_enumerated_name callback to store the name of the enumerated item of the given control
|
|
Packit Service |
db8eaa |
element. All functions return 0 if successful, or a negative error code.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
For reading the current values of a control element, read_integer, read_integer64,
|
|
Packit Service |
db8eaa |
read_enumerated, read_bytes and read_iec958 callbacks are called depending on the
|
|
Packit Service |
db8eaa |
element type. These callbacks have to fill the current values of the element in return.
|
|
Packit Service |
db8eaa |
Note that a control element can be an array. If it contains more than one values
|
|
Packit Service |
db8eaa |
(i.e. the count value in get_attribute callback is more than 1), all values
|
|
Packit Service |
db8eaa |
must be filled on the given value pointer as an array. Also, note that the boolean type
|
|
Packit Service |
db8eaa |
is handled as integer here (although boolean type doesn't need to define the corresponding
|
|
Packit Service |
db8eaa |
info callback since it's obvious). These callbacks return 0 if successful, or
|
|
Packit Service |
db8eaa |
a negative error code.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
For writing the current values, write_integer, write_integer64, write_bytes, and
|
|
Packit Service |
db8eaa |
write_iec958 callbacks are called as well as for read. The callbacks should check the
|
|
Packit Service |
db8eaa |
current values and compare with the given values. If they are identical, the callbacks
|
|
Packit Service |
db8eaa |
should do nothing and return 0. If they differ, update the current values and return 1,
|
|
Packit Service |
db8eaa |
instead. For any errors, return a negative error code.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The subscribe_events callback is called when the application subscribes or cancels
|
|
Packit Service |
db8eaa |
the event notifications (e.g. through mixer API). The current value of event
|
|
Packit Service |
db8eaa |
subscription is kept in the subscribed field.
|
|
Packit Service |
db8eaa |
The read_event callback is called for reading a pending notification event.
|
|
Packit Service |
db8eaa |
The callback needs to fill the event_mask value, a bit-field defined as SND_CTL_EVENT_MASK_XXX.
|
|
Packit Service |
db8eaa |
If no event is pending, return -EAGAIN. These two callbacks are optional.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
The poll_descriptors_count and poll_descriptors callbacks are used to return
|
|
Packit Service |
db8eaa |
the poll descriptor(s) via callbacks. As already mentioned, if the callback cannot
|
|
Packit Service |
db8eaa |
set the static poll_fd, you can define these callbacks to return dynamically.
|
|
Packit Service |
db8eaa |
Also, when multiple poll descriptors are required, use these callbacks.
|
|
Packit Service |
db8eaa |
The poll_revents callback is used for handle poll revents.
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Create an external control plugin instance
|
|
Packit Service |
db8eaa |
* \param ext the plugin handle
|
|
Packit Service |
db8eaa |
* \param name name of control
|
|
Packit Service |
db8eaa |
* \param mode control open mode
|
|
Packit Service |
db8eaa |
* \return 0 if successful, or a negative error code
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
* Creates the external control instance.
|
|
Packit Service |
db8eaa |
*
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
int snd_ctl_ext_create(snd_ctl_ext_t *ext, const char *name, int mode)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
snd_ctl_t *ctl;
|
|
Packit Service |
db8eaa |
int err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
if (ext->version < SNDRV_PROTOCOL_VERSION(1, 0, 0) ||
|
|
Packit Service |
db8eaa |
ext->version > SND_CTL_EXT_VERSION) {
|
|
Packit Service |
db8eaa |
SNDERR("ctl_ext: Plugin version mismatch\n");
|
|
Packit Service |
db8eaa |
return -ENXIO;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
err = snd_ctl_new(&ctl, SND_CTL_TYPE_EXT, name);
|
|
Packit Service |
db8eaa |
if (err < 0)
|
|
Packit Service |
db8eaa |
return err;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
ext->handle = ctl;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
ctl->ops = &snd_ctl_ext_ops;
|
|
Packit Service |
db8eaa |
ctl->private_data = ext;
|
|
Packit Service |
db8eaa |
ctl->poll_fd = ext->poll_fd;
|
|
Packit Service |
db8eaa |
if (mode & SND_CTL_NONBLOCK)
|
|
Packit Service |
db8eaa |
ext->nonblock = 1;
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
return 0;
|
|
Packit Service |
db8eaa |
}
|
|
Packit Service |
db8eaa |
|
|
Packit Service |
db8eaa |
/**
|
|
Packit Service |
db8eaa |
* \brief Delete the external control plugin
|
|
Packit Service |
db8eaa |
* \param ext the plugin handle
|
|
Packit Service |
db8eaa |
* \return 0 if successful, or a negative error code
|
|
Packit Service |
db8eaa |
*/
|
|
Packit Service |
db8eaa |
int snd_ctl_ext_delete(snd_ctl_ext_t *ext)
|
|
Packit Service |
db8eaa |
{
|
|
Packit Service |
db8eaa |
return snd_ctl_close(ext->handle);
|
|
Packit Service |
db8eaa |
}
|