Blame src/control/control_ext.c

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