From 8a3d07022cae65efe26a59452db88d9033d45bb0 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Thu, 9 Jun 2005 17:12:08 +0000 Subject: [PATCH] Add external control plugin SDK Added external control plugin SDK. --- include/Makefile.am | 3 +- include/control.h | 4 +- include/control_external.h | 184 +++++++++++++++ src/Versions | 3 + src/control/Makefile.am | 2 +- src/control/control_ext.c | 459 +++++++++++++++++++++++++++++++++++++ 6 files changed, 652 insertions(+), 3 deletions(-) create mode 100644 include/control_external.h create mode 100644 src/control/control_ext.c diff --git a/include/Makefile.am b/include/Makefile.am index 29b041c8..50634557 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -9,7 +9,8 @@ alsainclude_HEADERS = asoundlib.h asoundef.h \ hwdep.h control.h mixer.h mixer_abst.h \ seq_event.h seq.h seqmid.h seq_midi_event.h \ conv.h instr.h iatomic.h \ - alisp.h pcm_external.h pcm_ioplug.h pcm_extplug.h + alisp.h pcm_external.h pcm_ioplug.h pcm_extplug.h \ + control_external.h noinst_HEADERS = sys.h search.h list.h aserver.h local.h alsa-symbols.h diff --git a/include/control.h b/include/control.h index 3cd1a295..28c1fc8f 100644 --- a/include/control.h +++ b/include/control.h @@ -171,7 +171,9 @@ typedef enum _snd_ctl_type { /** Shared memory client CTL */ SND_CTL_TYPE_SHM, /** INET client CTL (not yet implemented) */ - SND_CTL_TYPE_INET + SND_CTL_TYPE_INET, + /** External control plugin */ + SND_CTL_TYPE_EXT } snd_ctl_type_t; /** Non blocking mode (flag for open mode) \hideinitializer */ diff --git a/include/control_external.h b/include/control_external.h new file mode 100644 index 00000000..c3638059 --- /dev/null +++ b/include/control_external.h @@ -0,0 +1,184 @@ +/** + * \file include/control_external.h + * \brief External control plugin SDK + * \author Takashi Iwai + * \date 2005 + * + * External control plugin SDK. + */ + +/* + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ +#ifndef __ALSA_CONTROL_EXTERNAL_H +#define __ALSA_CONTROL_EXTERNAL_H + +#include "control.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * \defgroup CtlPlugin_SDK External control plugin SDK + * \{ + */ + +/** + * Define the object entry for external control plugins + */ +#define SND_CTL_PLUGIN_ENTRY(name) _snd_ctl_##name##_open + +/** + * Define the symbols of the given control plugin with versions + */ +#define SND_CTL_PLUGIN_SYMBOL(name) SND_DLSYM_BUILD_VERSION(SND_CTL_PLUGIN_ENTRY(name), SND_CONTROL_DLSYM_VERSION); + +/** + * Define the control plugin + */ +#define SND_CTL_PLUGIN_DEFINE_FUNC(plugin) \ +int SND_CTL_PLUGIN_ENTRY(plugin) (snd_ctl_t **handlep, const char *name,\ + snd_config_t *root, snd_config_t *conf, int mode) + +/** External control plugin handle */ +typedef struct snd_ctl_ext snd_ctl_ext_t; +/** Callback table of control ext */ +typedef struct snd_ctl_ext_callback snd_ctl_ext_callback_t; +/** Key to access a control pointer */ +typedef unsigned long snd_ctl_ext_key_t; + +/* + * Protocol version + */ +#define SND_CTL_EXT_VERSION_MAJOR 1 /**< Protocol major version */ +#define SND_CTL_EXT_VERSION_MINOR 0 /**< Protocol minor version */ +#define SND_CTL_EXT_VERSION_TINY 0 /**< Protocol tiny version */ +/** + * external plugin protocol version + */ +#define SND_CTL_EXT_VERSION ((SND_CTL_EXT_VERSION_MAJOR<<16) |\ + (SND_CTL_EXT_VERSION_MINOR<<8) |\ + (SND_CTL_EXT_VERSION_TINY)) + +/** Handle of control ext */ +struct snd_ctl_ext { + /** + * protocol version; #SND_CTL_EXT_VERSION must be filled here + * before calling #snd_ctl_ext_create() + */ + unsigned int version; + /** + * Index of this card; must be filled before calling #snd_ctl_ext_create() + */ + int card_idx; + /** + * ID string of this card; must be filled before calling #snd_ctl_ext_create() + */ + char id[16]; + /** + * Driver name of this card; must be filled before calling #snd_ctl_ext_create() + */ + char driver[16]; + /** + * short name of this card; must be filled before calling #snd_ctl_ext_create() + */ + char name[32]; + /** + * Long name of this card; must be filled before calling #snd_ctl_ext_create() + */ + char longname[80]; + /** + * Mixer name of this card; must be filled before calling #snd_ctl_ext_create() + */ + char mixername[80]; + /** + * poll descriptor + */ + int poll_fd; + + /** + * callbacks of this plugin; must be filled before calling #snd_pcm_ioplug_create() + */ + const snd_ctl_ext_callback_t *callback; + /** + * private data, which can be used freely in the driver callbacks + */ + void *private_data; + /** + * control handle filled by #snd_ctl_ext_create() + */ + snd_ctl_t *handle; + + int nonblock; /**< non-block mode; read-only */ + int subscribed; /**< events subscribed; read-only */ +}; + +/** Callback table of ext */ +struct snd_ctl_ext_callback { + void (*close)(snd_ctl_ext_t *ext); /* opt */ + void (*subscribe_events)(snd_ctl_ext_t *ext, int subscribe); /* opt */ + int (*elem_count)(snd_ctl_ext_t *ext); /* req */ + int (*elem_list)(snd_ctl_ext_t *ext, unsigned int offset, snd_ctl_elem_id_t *id); /* req */ + snd_ctl_ext_key_t (*find_elem)(snd_ctl_ext_t *ext, const snd_ctl_elem_id_t *id); /* req */ + void (*free_key)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key); /* opt */ + int (*get_attribute)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + int *type, unsigned int *acc, unsigned int *count); /* req */ + int (*get_integer_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + long *imin, long *imax, long *istep); + int (*get_integer64_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, + int64_t *imin, int64_t *imax, int64_t *istep); + int (*get_enumerated_info)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items); + int (*get_enumerated_name)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int item, + char *name, size_t name_max_len); + int (*read_integer)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value); + int (*read_integer64)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int64_t *value); + int (*read_enumerated)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items); + int (*read_bytes)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned char *data, + size_t max_bytes); + int (*read_iec958)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, snd_aes_iec958_t *iec958); + int (*write_integer)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, long *value); + int (*write_integer64)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, int64_t *value); + int (*write_enumerated)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned int *items); + int (*write_bytes)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, unsigned char *data, + size_t max_bytes); + int (*write_iec958)(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key, snd_aes_iec958_t *iec958); + int (*read_event)(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id, unsigned int *event_mask); + int (*poll_descriptors_count)(snd_ctl_ext_t *ext); + int (*poll_descriptors)(snd_ctl_ext_t *ext, struct pollfd *pfds, unsigned int space); + int (*poll_revents)(snd_ctl_ext_t *ext, struct pollfd *pfds, unsigned int nfds, unsigned short *revents); +}; + +enum snd_ctl_ext_access_t { + SND_CTL_EXT_ACCESS_READ = (1<<0), + SND_CTL_EXT_ACCESS_WRITE = (1<<1), + SND_CTL_EXT_ACCESS_READWRITE = (3<<0), + SND_CTL_EXT_ACCESS_VOLATILE = (1<<2), + SND_CTL_EXT_ACCESS_INACTIVE = (1<<8), +}; + +#define SND_CTL_EXT_KEY_NOT_FOUND (snd_ctl_ext_key_t)(-1) + +int snd_ctl_ext_create(snd_ctl_ext_t *ext, const char *name, int mode); +int snd_ctl_ext_delete(snd_ctl_ext_t *ext); + +/** \} */ + +#ifdef __cplusplus +} +#endif + +#endif /* __ALSA_CONTROL_EXTERNAL_H */ diff --git a/src/Versions b/src/Versions index 2d14d8d5..f9d5f81a 100644 --- a/src/Versions +++ b/src/Versions @@ -254,4 +254,7 @@ ALSA_1.0.10 { snd_mixer_selem_set_capture_dB_all; snd_mixer_selem_compare; + snd_ctl_ext_create; + snd_ctl_ext_delete; + } ALSA_1.0.9; diff --git a/src/control/Makefile.am b/src/control/Makefile.am index 072bdf2b..8e4b5fd4 100644 --- a/src/control/Makefile.am +++ b/src/control/Makefile.am @@ -2,7 +2,7 @@ EXTRA_LTLIBRARIES = libcontrol.la libcontrol_la_SOURCES = cards.c hcontrol.c \ control.c control_hw.c control_shm.c \ - setup.c control_symbols.c + control_ext.c setup.c control_symbols.c noinst_HEADERS = control_local.h diff --git a/src/control/control_ext.c b/src/control/control_ext.c new file mode 100644 index 00000000..69d85672 --- /dev/null +++ b/src/control/control_ext.c @@ -0,0 +1,459 @@ +/* + * Control Interface - External Control Plugin SDK + * + * Copyright (c) 2005 Takashi Iwai + * + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as + * published by the Free Software Foundation; either version 2.1 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include +#include +#include +#include +#include "control_local.h" +#include "control_external.h" + +static int snd_ctl_ext_close(snd_ctl_t *handle) +{ + snd_ctl_ext_t *ext = handle->private_data; + + if (ext->callback->close) + ext->callback->close(ext); + return 0; +} + +static int snd_ctl_ext_nonblock(snd_ctl_t *handle, int nonblock) +{ + snd_ctl_ext_t *ext = handle->private_data; + + ext->nonblock = nonblock; + return 0; +} + +static int snd_ctl_ext_async(snd_ctl_t *ctl ATTRIBUTE_UNUSED, + int sig ATTRIBUTE_UNUSED, + pid_t pid ATTRIBUTE_UNUSED) +{ + return -ENOSYS; +} + +static int snd_ctl_ext_subscribe_events(snd_ctl_t *handle, int subscribe) +{ + snd_ctl_ext_t *ext = handle->private_data; + + if (subscribe < 0) + return ext->subscribed; + ext->subscribed = !!subscribe; + if (ext->callback->subscribe_events) + ext->callback->subscribe_events(ext, subscribe); + return 0; +} + +static int snd_ctl_ext_card_info(snd_ctl_t *handle, snd_ctl_card_info_t *info) +{ + snd_ctl_ext_t *ext = handle->private_data; + + memset(info, 0, sizeof(*info)); + info->card = ext->card_idx; + memcpy(info->id, ext->id, sizeof(info->id)); + memcpy(info->driver, ext->driver, sizeof(info->driver)); + memcpy(info->name, ext->name, sizeof(info->name)); + memcpy(info->longname, ext->longname, sizeof(info->longname)); + memcpy(info->mixername, ext->mixername, sizeof(info->mixername)); + return 0; +} + +static int snd_ctl_ext_elem_list(snd_ctl_t *handle, snd_ctl_elem_list_t *list) +{ + snd_ctl_ext_t *ext = handle->private_data; + int ret; + unsigned int i, offset; + snd_ctl_elem_id_t *ids; + + list->count = ext->callback->elem_count(ext); + list->used = 0; + ids = list->pids; + offset = list->offset; + for (i = 0; i < list->space; i++) { + if (offset >= list->count) + break; + snd_ctl_elem_id_clear(ids); + ret = ext->callback->elem_list(ext, offset, ids); + if (ret < 0) + return ret; + list->used++; + offset++; + ids++; + } + return 0; +} + +static int snd_ctl_ext_elem_info(snd_ctl_t *handle, snd_ctl_elem_info_t *info) +{ + snd_ctl_ext_t *ext = handle->private_data; + snd_ctl_ext_key_t key; + int type, ret; + + key = ext->callback->find_elem(ext, &info->id); + if (key == SND_CTL_EXT_KEY_NOT_FOUND) + return -ENOENT; + ret = ext->callback->get_attribute(ext, key, &type, &info->access, &info->count); + if (ret < 0) + goto err; + info->type = type; + ret = -EINVAL; + switch (info->type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + info->value.integer.min = 0; + info->value.integer.max = 1; + ret = 0; + break; + case SND_CTL_ELEM_TYPE_INTEGER: + if (! ext->callback->get_integer_info) + goto err; + ret = ext->callback->get_integer_info(ext, key, &info->value.integer.min, + &info->value.integer.max, + &info->value.integer.step); + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + if (! ext->callback->get_integer64_info) + goto err; + ret = ext->callback->get_integer64_info(ext, key, &info->value.integer64.min, + &info->value.integer64.max, + &info->value.integer64.step); + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + if (! ext->callback->get_enumerated_info) + goto err; + ret = ext->callback->get_enumerated_info(ext, key, &info->value.enumerated.items); + ext->callback->get_enumerated_name(ext, key, info->value.enumerated.item, + info->value.enumerated.name, + sizeof(info->value.enumerated.name)); + break; + default: + ret = 0; + break; + } + + err: + if (ext->callback->free_key) + ext->callback->free_key(ext, key); + + return ret; +} + +static int snd_ctl_ext_elem_add(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_ctl_elem_info_t *info ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_elem_replace(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_ctl_elem_info_t *info ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_elem_remove(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_elem_read(snd_ctl_t *handle, snd_ctl_elem_value_t *control) +{ + snd_ctl_ext_t *ext = handle->private_data; + snd_ctl_ext_key_t key; + int type, ret; + unsigned int access, count; + + key = ext->callback->find_elem(ext, &control->id); + if (key == SND_CTL_EXT_KEY_NOT_FOUND) + return -ENOENT; + ret = ext->callback->get_attribute(ext, key, &type, &access, &count); + if (ret < 0) + goto err; + ret = -EINVAL; + switch (type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + case SND_CTL_ELEM_TYPE_INTEGER: + if (! ext->callback->read_integer) + goto err; + ret = ext->callback->read_integer(ext, key, control->value.integer.value); + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + if (! ext->callback->read_integer64) + goto err; + ret = ext->callback->read_integer64(ext, key, control->value.integer64.value); + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + if (! ext->callback->read_enumerated) + goto err; + ret = ext->callback->read_enumerated(ext, key, control->value.enumerated.item); + break; + case SND_CTL_ELEM_TYPE_BYTES: + if (! ext->callback->read_bytes) + goto err; + ret = ext->callback->read_bytes(ext, key, control->value.bytes.data, + sizeof(control->value.bytes.data)); + break; + case SND_CTL_ELEM_TYPE_IEC958: + if (! ext->callback->read_iec958) + goto err; + ret = ext->callback->read_iec958(ext, key, (snd_aes_iec958_t *)&control->value.iec958); + break; + default: + break; + } + + err: + if (ext->callback->free_key) + ext->callback->free_key(ext, key); + + return ret; +} + +static int snd_ctl_ext_elem_write(snd_ctl_t *handle, snd_ctl_elem_value_t *control) +{ + snd_ctl_ext_t *ext = handle->private_data; + snd_ctl_ext_key_t key; + int type, ret; + unsigned int access, count; + + key = ext->callback->find_elem(ext, &control->id); + if (key == SND_CTL_EXT_KEY_NOT_FOUND) + return -ENOENT; + ret = ext->callback->get_attribute(ext, key, &type, &access, &count); + if (ret < 0) + goto err; + ret = -EINVAL; + switch (type) { + case SND_CTL_ELEM_TYPE_BOOLEAN: + case SND_CTL_ELEM_TYPE_INTEGER: + if (! ext->callback->write_integer) + goto err; + ret = ext->callback->write_integer(ext, key, control->value.integer.value); + break; + case SND_CTL_ELEM_TYPE_INTEGER64: + if (! ext->callback->write_integer64) + goto err; + ret = ext->callback->write_integer64(ext, key, control->value.integer64.value); + break; + case SND_CTL_ELEM_TYPE_ENUMERATED: + if (! ext->callback->write_enumerated) + goto err; + ret = ext->callback->write_enumerated(ext, key, control->value.enumerated.item); + break; + case SND_CTL_ELEM_TYPE_BYTES: + if (! ext->callback->write_bytes) + goto err; + ret = ext->callback->write_bytes(ext, key, control->value.bytes.data, + sizeof(control->value.bytes.data)); + break; + case SND_CTL_ELEM_TYPE_IEC958: + if (! ext->callback->write_iec958) + goto err; + ret = ext->callback->write_iec958(ext, key, (snd_aes_iec958_t *)&control->value.iec958); + break; + default: + break; + } + + err: + if (ext->callback->free_key) + ext->callback->free_key(ext, key); + + return ret; +} + +static int snd_ctl_ext_elem_lock(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_elem_unlock(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_next_device(snd_ctl_t *handle ATTRIBUTE_UNUSED, + int *device ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_prefer_subdevice(snd_ctl_t *handle ATTRIBUTE_UNUSED, + int subdev ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_hwdep_info(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_hwdep_info_t *info ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_pcm_info(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_pcm_info_t *info ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_rawmidi_info(snd_ctl_t *handle ATTRIBUTE_UNUSED, + snd_rawmidi_info_t *info ATTRIBUTE_UNUSED) +{ + return -ENXIO; +} + +static int snd_ctl_ext_set_power_state(snd_ctl_t *handle ATTRIBUTE_UNUSED, + unsigned int state ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_ctl_ext_get_power_state(snd_ctl_t *handle ATTRIBUTE_UNUSED, + unsigned int *state ATTRIBUTE_UNUSED) +{ + return 0; +} + +static int snd_ctl_ext_read(snd_ctl_t *handle, snd_ctl_event_t *event) +{ + snd_ctl_ext_t *ext = handle->private_data; + + memset(event, 0, sizeof(*event)); + return ext->callback->read_event(ext, &event->data.elem.id, &event->data.elem.mask); +} + +static int snd_ctl_ext_poll_descriptors_count(snd_ctl_t *handle) +{ + snd_ctl_ext_t *ext = handle->private_data; + + if (ext->callback->poll_descriptors_count) + return ext->callback->poll_descriptors_count(ext); + if (ext->poll_fd >= 0) + return 1; + return 0; +} + +static int snd_ctl_ext_poll_descriptors(snd_ctl_t *handle, struct pollfd *pfds, unsigned int space) +{ + snd_ctl_ext_t *ext = handle->private_data; + + if (ext->callback->poll_descriptors) + return ext->callback->poll_descriptors(ext, pfds, space); + if (ext->poll_fd < 0) + return 0; + if (space > 0) { + pfds->fd = ext->poll_fd; + pfds->events = POLLIN|POLLERR|POLLNVAL; + return 1; + } + return 0; +} + +static int snd_ctl_ext_poll_revents(snd_ctl_t *handle, struct pollfd *pfds, unsigned int nfds, unsigned short *revents) +{ + snd_ctl_ext_t *ext = handle->private_data; + + if (ext->callback->poll_revents) + return ext->callback->poll_revents(ext, pfds, nfds, revents); + if (nfds == 1) { + *revents = pfds->revents; + return 0; + } + return -EINVAL; +} + +static snd_ctl_ops_t snd_ctl_ext_ops = { + .close = snd_ctl_ext_close, + .nonblock = snd_ctl_ext_nonblock, + .async = snd_ctl_ext_async, + .subscribe_events = snd_ctl_ext_subscribe_events, + .card_info = snd_ctl_ext_card_info, + .element_list = snd_ctl_ext_elem_list, + .element_info = snd_ctl_ext_elem_info, + .element_add = snd_ctl_ext_elem_add, + .element_replace = snd_ctl_ext_elem_replace, + .element_remove = snd_ctl_ext_elem_remove, + .element_read = snd_ctl_ext_elem_read, + .element_write = snd_ctl_ext_elem_write, + .element_lock = snd_ctl_ext_elem_lock, + .element_unlock = snd_ctl_ext_elem_unlock, + .hwdep_next_device = snd_ctl_ext_next_device, + .hwdep_info = snd_ctl_ext_hwdep_info, + .pcm_next_device = snd_ctl_ext_next_device, + .pcm_info = snd_ctl_ext_pcm_info, + .pcm_prefer_subdevice = snd_ctl_ext_prefer_subdevice, + .rawmidi_next_device = snd_ctl_rawmidi_next_device, + .rawmidi_info = snd_ctl_ext_rawmidi_info, + .rawmidi_prefer_subdevice = snd_ctl_ext_prefer_subdevice, + .set_power_state = snd_ctl_ext_set_power_state, + .get_power_state = snd_ctl_ext_get_power_state, + .read = snd_ctl_ext_read, + .poll_descriptors_count = snd_ctl_ext_poll_descriptors_count, + .poll_descriptors = snd_ctl_ext_poll_descriptors, + .poll_revents = snd_ctl_ext_poll_revents, +}; + +/** + * \brief Create an external control plugin instance + * \param ext the plugin handle + * \param name name of control + * \param mode control open mode + * \return 0 if successful, or a negative error code + * + * Creates the external control instance. + * + */ +int snd_ctl_ext_create(snd_ctl_ext_t *ext, const char *name, int mode) +{ + snd_ctl_t *ctl; + int err; + + if (ext->version != SND_CTL_EXT_VERSION) { + SNDERR("ctl_ext: Plugin version mismatch\n"); + return -ENXIO; + } + + err = snd_ctl_new(&ctl, SND_CTL_TYPE_EXT, name); + if (err < 0) + return err; + + ext->handle = ctl; + + ctl->ops = &snd_ctl_ext_ops; + ctl->private_data = ext; + ctl->poll_fd = ext->poll_fd; + if (mode & SND_CTL_NONBLOCK) + ext->nonblock = 1; + + return 0; +} + +/** + * \brief Delete the external control plugin + * \param ext the plugin handle + * \return 0 if successful, or a negative error code + */ +int snd_ctl_ext_delete(snd_ctl_ext_t *ext) +{ + return snd_ctl_close(ext->handle); +} -- 2.47.1