1d5ac70f0Sopenharmony_ci/**
2d5ac70f0Sopenharmony_ci * \file control/control_ext.c
3d5ac70f0Sopenharmony_ci * \ingroup CtlPlugin_SDK
4d5ac70f0Sopenharmony_ci * \brief External Control Plugin SDK
5d5ac70f0Sopenharmony_ci * \author Takashi Iwai <tiwai@suse.de>
6d5ac70f0Sopenharmony_ci * \date 2005
7d5ac70f0Sopenharmony_ci */
8d5ac70f0Sopenharmony_ci/*
9d5ac70f0Sopenharmony_ci *  Control Interface - External Control Plugin SDK
10d5ac70f0Sopenharmony_ci *
11d5ac70f0Sopenharmony_ci *  Copyright (c) 2005 Takashi Iwai <tiwai@suse.de>
12d5ac70f0Sopenharmony_ci *
13d5ac70f0Sopenharmony_ci *
14d5ac70f0Sopenharmony_ci *   This library is free software; you can redistribute it and/or modify
15d5ac70f0Sopenharmony_ci *   it under the terms of the GNU Lesser General Public License as
16d5ac70f0Sopenharmony_ci *   published by the Free Software Foundation; either version 2.1 of
17d5ac70f0Sopenharmony_ci *   the License, or (at your option) any later version.
18d5ac70f0Sopenharmony_ci *
19d5ac70f0Sopenharmony_ci *   This program is distributed in the hope that it will be useful,
20d5ac70f0Sopenharmony_ci *   but WITHOUT ANY WARRANTY; without even the implied warranty of
21d5ac70f0Sopenharmony_ci *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22d5ac70f0Sopenharmony_ci *   GNU Lesser General Public License for more details.
23d5ac70f0Sopenharmony_ci *
24d5ac70f0Sopenharmony_ci *   You should have received a copy of the GNU Lesser General Public
25d5ac70f0Sopenharmony_ci *   License along with this library; if not, write to the Free Software
26d5ac70f0Sopenharmony_ci *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
27d5ac70f0Sopenharmony_ci *
28d5ac70f0Sopenharmony_ci */
29d5ac70f0Sopenharmony_ci
30d5ac70f0Sopenharmony_ci#include "control_local.h"
31d5ac70f0Sopenharmony_ci#include "control_external.h"
32d5ac70f0Sopenharmony_ci#include <stdio.h>
33d5ac70f0Sopenharmony_ci#include <stdlib.h>
34d5ac70f0Sopenharmony_ci#include <unistd.h>
35d5ac70f0Sopenharmony_ci#include <string.h>
36d5ac70f0Sopenharmony_ci
37d5ac70f0Sopenharmony_ci#ifndef PIC
38d5ac70f0Sopenharmony_ci/* entry for static linking */
39d5ac70f0Sopenharmony_ciconst char *_snd_module_control_ext = "";
40d5ac70f0Sopenharmony_ci#endif
41d5ac70f0Sopenharmony_ci
42d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_close(snd_ctl_t *handle)
43d5ac70f0Sopenharmony_ci{
44d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
45d5ac70f0Sopenharmony_ci
46d5ac70f0Sopenharmony_ci	if (ext->callback->close)
47d5ac70f0Sopenharmony_ci		ext->callback->close(ext);
48d5ac70f0Sopenharmony_ci	return 0;
49d5ac70f0Sopenharmony_ci}
50d5ac70f0Sopenharmony_ci
51d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_nonblock(snd_ctl_t *handle, int nonblock)
52d5ac70f0Sopenharmony_ci{
53d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
54d5ac70f0Sopenharmony_ci
55d5ac70f0Sopenharmony_ci	ext->nonblock = nonblock;
56d5ac70f0Sopenharmony_ci	return 0;
57d5ac70f0Sopenharmony_ci}
58d5ac70f0Sopenharmony_ci
59d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_async(snd_ctl_t *ctl ATTRIBUTE_UNUSED,
60d5ac70f0Sopenharmony_ci			     int sig ATTRIBUTE_UNUSED,
61d5ac70f0Sopenharmony_ci			     pid_t pid ATTRIBUTE_UNUSED)
62d5ac70f0Sopenharmony_ci{
63d5ac70f0Sopenharmony_ci	return -ENOSYS;
64d5ac70f0Sopenharmony_ci}
65d5ac70f0Sopenharmony_ci
66d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_subscribe_events(snd_ctl_t *handle, int subscribe)
67d5ac70f0Sopenharmony_ci{
68d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
69d5ac70f0Sopenharmony_ci
70d5ac70f0Sopenharmony_ci	if (subscribe < 0)
71d5ac70f0Sopenharmony_ci		return ext->subscribed;
72d5ac70f0Sopenharmony_ci	ext->subscribed = !!subscribe;
73d5ac70f0Sopenharmony_ci	if (ext->callback->subscribe_events)
74d5ac70f0Sopenharmony_ci		ext->callback->subscribe_events(ext, subscribe);
75d5ac70f0Sopenharmony_ci	return 0;
76d5ac70f0Sopenharmony_ci}
77d5ac70f0Sopenharmony_ci
78d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_card_info(snd_ctl_t *handle, snd_ctl_card_info_t *info)
79d5ac70f0Sopenharmony_ci{
80d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
81d5ac70f0Sopenharmony_ci
82d5ac70f0Sopenharmony_ci	memset(info, 0, sizeof(*info));
83d5ac70f0Sopenharmony_ci	info->card = ext->card_idx;
84d5ac70f0Sopenharmony_ci	memcpy(info->id, ext->id, sizeof(info->id));
85d5ac70f0Sopenharmony_ci	memcpy(info->driver, ext->driver, sizeof(info->driver));
86d5ac70f0Sopenharmony_ci	memcpy(info->name, ext->name, sizeof(info->name));
87d5ac70f0Sopenharmony_ci	memcpy(info->longname, ext->longname, sizeof(info->longname));
88d5ac70f0Sopenharmony_ci	memcpy(info->mixername, ext->mixername, sizeof(info->mixername));
89d5ac70f0Sopenharmony_ci	return 0;
90d5ac70f0Sopenharmony_ci}
91d5ac70f0Sopenharmony_ci
92d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_list(snd_ctl_t *handle, snd_ctl_elem_list_t *list)
93d5ac70f0Sopenharmony_ci{
94d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
95d5ac70f0Sopenharmony_ci	int ret;
96d5ac70f0Sopenharmony_ci	unsigned int i, offset;
97d5ac70f0Sopenharmony_ci	snd_ctl_elem_id_t *ids;
98d5ac70f0Sopenharmony_ci
99d5ac70f0Sopenharmony_ci	list->count = ext->callback->elem_count(ext);
100d5ac70f0Sopenharmony_ci	list->used = 0;
101d5ac70f0Sopenharmony_ci	ids = list->pids;
102d5ac70f0Sopenharmony_ci	offset = list->offset;
103d5ac70f0Sopenharmony_ci	for (i = 0; i < list->space; i++) {
104d5ac70f0Sopenharmony_ci		if (offset >= list->count)
105d5ac70f0Sopenharmony_ci			break;
106d5ac70f0Sopenharmony_ci		snd_ctl_elem_id_clear(ids);
107d5ac70f0Sopenharmony_ci		ret = ext->callback->elem_list(ext, offset, ids);
108d5ac70f0Sopenharmony_ci		if (ret < 0)
109d5ac70f0Sopenharmony_ci			return ret;
110d5ac70f0Sopenharmony_ci		ids->numid = offset + 1; /* fake number */
111d5ac70f0Sopenharmony_ci		list->used++;
112d5ac70f0Sopenharmony_ci		offset++;
113d5ac70f0Sopenharmony_ci		ids++;
114d5ac70f0Sopenharmony_ci	}
115d5ac70f0Sopenharmony_ci	return 0;
116d5ac70f0Sopenharmony_ci}
117d5ac70f0Sopenharmony_ci
118d5ac70f0Sopenharmony_cistatic snd_ctl_ext_key_t get_elem(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id)
119d5ac70f0Sopenharmony_ci{
120d5ac70f0Sopenharmony_ci	int numid = id->numid;
121d5ac70f0Sopenharmony_ci	if (numid > 0) {
122d5ac70f0Sopenharmony_ci		ext->callback->elem_list(ext, numid - 1, id);
123d5ac70f0Sopenharmony_ci		id->numid = numid;
124d5ac70f0Sopenharmony_ci	} else
125d5ac70f0Sopenharmony_ci		id->numid = 0;
126d5ac70f0Sopenharmony_ci	return ext->callback->find_elem(ext, id);
127d5ac70f0Sopenharmony_ci}
128d5ac70f0Sopenharmony_ci
129d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_info(snd_ctl_t *handle, snd_ctl_elem_info_t *info)
130d5ac70f0Sopenharmony_ci{
131d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
132d5ac70f0Sopenharmony_ci	snd_ctl_ext_key_t key;
133d5ac70f0Sopenharmony_ci	int type, ret;
134d5ac70f0Sopenharmony_ci
135d5ac70f0Sopenharmony_ci	key = get_elem(ext, &info->id);
136d5ac70f0Sopenharmony_ci	if (key == SND_CTL_EXT_KEY_NOT_FOUND)
137d5ac70f0Sopenharmony_ci		return -ENOENT;
138d5ac70f0Sopenharmony_ci	ret = ext->callback->get_attribute(ext, key, &type, &info->access, &info->count);
139d5ac70f0Sopenharmony_ci	if (ret < 0)
140d5ac70f0Sopenharmony_ci		goto err;
141d5ac70f0Sopenharmony_ci	info->type = type;
142d5ac70f0Sopenharmony_ci	ret = -EINVAL;
143d5ac70f0Sopenharmony_ci	switch (info->type) {
144d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_BOOLEAN:
145d5ac70f0Sopenharmony_ci		info->value.integer.min = 0;
146d5ac70f0Sopenharmony_ci		info->value.integer.max = 1;
147d5ac70f0Sopenharmony_ci		ret = 0;
148d5ac70f0Sopenharmony_ci		break;
149d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_INTEGER:
150d5ac70f0Sopenharmony_ci		if (! ext->callback->get_integer_info)
151d5ac70f0Sopenharmony_ci			goto err;
152d5ac70f0Sopenharmony_ci		ret = ext->callback->get_integer_info(ext, key, &info->value.integer.min,
153d5ac70f0Sopenharmony_ci						      &info->value.integer.max,
154d5ac70f0Sopenharmony_ci						      &info->value.integer.step);
155d5ac70f0Sopenharmony_ci		break;
156d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_INTEGER64:
157d5ac70f0Sopenharmony_ci		if (! ext->callback->get_integer64_info)
158d5ac70f0Sopenharmony_ci			goto err;
159d5ac70f0Sopenharmony_ci		{
160d5ac70f0Sopenharmony_ci			int64_t xmin, xmax, xstep;
161d5ac70f0Sopenharmony_ci			ret = ext->callback->get_integer64_info(ext, key,
162d5ac70f0Sopenharmony_ci								&xmin,
163d5ac70f0Sopenharmony_ci								&xmax,
164d5ac70f0Sopenharmony_ci								&xstep);
165d5ac70f0Sopenharmony_ci			info->value.integer64.min = xmin;
166d5ac70f0Sopenharmony_ci			info->value.integer64.max = xmax;
167d5ac70f0Sopenharmony_ci			info->value.integer64.step = xstep;
168d5ac70f0Sopenharmony_ci		}
169d5ac70f0Sopenharmony_ci		break;
170d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_ENUMERATED:
171d5ac70f0Sopenharmony_ci		if (! ext->callback->get_enumerated_info)
172d5ac70f0Sopenharmony_ci			goto err;
173d5ac70f0Sopenharmony_ci		ret = ext->callback->get_enumerated_info(ext, key, &info->value.enumerated.items);
174d5ac70f0Sopenharmony_ci		ext->callback->get_enumerated_name(ext, key, info->value.enumerated.item,
175d5ac70f0Sopenharmony_ci						   info->value.enumerated.name,
176d5ac70f0Sopenharmony_ci						   sizeof(info->value.enumerated.name));
177d5ac70f0Sopenharmony_ci		break;
178d5ac70f0Sopenharmony_ci	default:
179d5ac70f0Sopenharmony_ci		ret = 0;
180d5ac70f0Sopenharmony_ci		break;
181d5ac70f0Sopenharmony_ci	}
182d5ac70f0Sopenharmony_ci
183d5ac70f0Sopenharmony_ci err:
184d5ac70f0Sopenharmony_ci	if (ext->callback->free_key)
185d5ac70f0Sopenharmony_ci		ext->callback->free_key(ext, key);
186d5ac70f0Sopenharmony_ci
187d5ac70f0Sopenharmony_ci	return ret;
188d5ac70f0Sopenharmony_ci}
189d5ac70f0Sopenharmony_ci
190d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_add(snd_ctl_t *handle ATTRIBUTE_UNUSED,
191d5ac70f0Sopenharmony_ci				snd_ctl_elem_info_t *info ATTRIBUTE_UNUSED)
192d5ac70f0Sopenharmony_ci{
193d5ac70f0Sopenharmony_ci	return -ENXIO;
194d5ac70f0Sopenharmony_ci}
195d5ac70f0Sopenharmony_ci
196d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_replace(snd_ctl_t *handle ATTRIBUTE_UNUSED,
197d5ac70f0Sopenharmony_ci				    snd_ctl_elem_info_t *info ATTRIBUTE_UNUSED)
198d5ac70f0Sopenharmony_ci{
199d5ac70f0Sopenharmony_ci	return -ENXIO;
200d5ac70f0Sopenharmony_ci}
201d5ac70f0Sopenharmony_ci
202d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_remove(snd_ctl_t *handle ATTRIBUTE_UNUSED,
203d5ac70f0Sopenharmony_ci				   snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED)
204d5ac70f0Sopenharmony_ci{
205d5ac70f0Sopenharmony_ci	return -ENXIO;
206d5ac70f0Sopenharmony_ci}
207d5ac70f0Sopenharmony_ci
208d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_read(snd_ctl_t *handle, snd_ctl_elem_value_t *control)
209d5ac70f0Sopenharmony_ci{
210d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
211d5ac70f0Sopenharmony_ci	snd_ctl_ext_key_t key;
212d5ac70f0Sopenharmony_ci	int type, ret;
213d5ac70f0Sopenharmony_ci	unsigned int access, count;
214d5ac70f0Sopenharmony_ci
215d5ac70f0Sopenharmony_ci	key = get_elem(ext, &control->id);
216d5ac70f0Sopenharmony_ci	if (key == SND_CTL_EXT_KEY_NOT_FOUND)
217d5ac70f0Sopenharmony_ci		return -ENOENT;
218d5ac70f0Sopenharmony_ci	ret = ext->callback->get_attribute(ext, key, &type, &access, &count);
219d5ac70f0Sopenharmony_ci	if (ret < 0)
220d5ac70f0Sopenharmony_ci		goto err;
221d5ac70f0Sopenharmony_ci	ret = -EINVAL;
222d5ac70f0Sopenharmony_ci	switch (type) {
223d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_BOOLEAN:
224d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_INTEGER:
225d5ac70f0Sopenharmony_ci		if (! ext->callback->read_integer)
226d5ac70f0Sopenharmony_ci			goto err;
227d5ac70f0Sopenharmony_ci		ret = ext->callback->read_integer(ext, key, control->value.integer.value);
228d5ac70f0Sopenharmony_ci		break;
229d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_INTEGER64:
230d5ac70f0Sopenharmony_ci		if (! ext->callback->read_integer64)
231d5ac70f0Sopenharmony_ci			goto err;
232d5ac70f0Sopenharmony_ci		ret = ext->callback->read_integer64(ext, key,
233d5ac70f0Sopenharmony_ci						    (int64_t*)control->value.integer64.value);
234d5ac70f0Sopenharmony_ci		break;
235d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_ENUMERATED:
236d5ac70f0Sopenharmony_ci		if (! ext->callback->read_enumerated)
237d5ac70f0Sopenharmony_ci			goto err;
238d5ac70f0Sopenharmony_ci		ret = ext->callback->read_enumerated(ext, key, control->value.enumerated.item);
239d5ac70f0Sopenharmony_ci		break;
240d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_BYTES:
241d5ac70f0Sopenharmony_ci		if (! ext->callback->read_bytes)
242d5ac70f0Sopenharmony_ci			goto err;
243d5ac70f0Sopenharmony_ci		ret = ext->callback->read_bytes(ext, key, control->value.bytes.data,
244d5ac70f0Sopenharmony_ci						sizeof(control->value.bytes.data));
245d5ac70f0Sopenharmony_ci		break;
246d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_IEC958:
247d5ac70f0Sopenharmony_ci		if (! ext->callback->read_iec958)
248d5ac70f0Sopenharmony_ci			goto err;
249d5ac70f0Sopenharmony_ci		ret = ext->callback->read_iec958(ext, key, (snd_aes_iec958_t *)&control->value.iec958);
250d5ac70f0Sopenharmony_ci		break;
251d5ac70f0Sopenharmony_ci	default:
252d5ac70f0Sopenharmony_ci		break;
253d5ac70f0Sopenharmony_ci	}
254d5ac70f0Sopenharmony_ci
255d5ac70f0Sopenharmony_ci err:
256d5ac70f0Sopenharmony_ci	if (ext->callback->free_key)
257d5ac70f0Sopenharmony_ci		ext->callback->free_key(ext, key);
258d5ac70f0Sopenharmony_ci
259d5ac70f0Sopenharmony_ci	return ret;
260d5ac70f0Sopenharmony_ci}
261d5ac70f0Sopenharmony_ci
262d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_write(snd_ctl_t *handle, snd_ctl_elem_value_t *control)
263d5ac70f0Sopenharmony_ci{
264d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
265d5ac70f0Sopenharmony_ci	snd_ctl_ext_key_t key;
266d5ac70f0Sopenharmony_ci	int type, ret;
267d5ac70f0Sopenharmony_ci	unsigned int access, count;
268d5ac70f0Sopenharmony_ci
269d5ac70f0Sopenharmony_ci	key = get_elem(ext, &control->id);
270d5ac70f0Sopenharmony_ci	if (key == SND_CTL_EXT_KEY_NOT_FOUND)
271d5ac70f0Sopenharmony_ci		return -ENOENT;
272d5ac70f0Sopenharmony_ci	ret = ext->callback->get_attribute(ext, key, &type, &access, &count);
273d5ac70f0Sopenharmony_ci	if (ret < 0)
274d5ac70f0Sopenharmony_ci		goto err;
275d5ac70f0Sopenharmony_ci	ret = -EINVAL;
276d5ac70f0Sopenharmony_ci	switch (type) {
277d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_BOOLEAN:
278d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_INTEGER:
279d5ac70f0Sopenharmony_ci		if (! ext->callback->write_integer)
280d5ac70f0Sopenharmony_ci			goto err;
281d5ac70f0Sopenharmony_ci		ret = ext->callback->write_integer(ext, key, control->value.integer.value);
282d5ac70f0Sopenharmony_ci		break;
283d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_INTEGER64:
284d5ac70f0Sopenharmony_ci		if (! ext->callback->write_integer64)
285d5ac70f0Sopenharmony_ci			goto err;
286d5ac70f0Sopenharmony_ci		ret = ext->callback->write_integer64(ext, key, (int64_t *)control->value.integer64.value);
287d5ac70f0Sopenharmony_ci		break;
288d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_ENUMERATED:
289d5ac70f0Sopenharmony_ci		if (! ext->callback->write_enumerated)
290d5ac70f0Sopenharmony_ci			goto err;
291d5ac70f0Sopenharmony_ci		ret = ext->callback->write_enumerated(ext, key, control->value.enumerated.item);
292d5ac70f0Sopenharmony_ci		break;
293d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_BYTES:
294d5ac70f0Sopenharmony_ci		if (! ext->callback->write_bytes)
295d5ac70f0Sopenharmony_ci			goto err;
296d5ac70f0Sopenharmony_ci		ret = ext->callback->write_bytes(ext, key, control->value.bytes.data,
297d5ac70f0Sopenharmony_ci						sizeof(control->value.bytes.data));
298d5ac70f0Sopenharmony_ci		break;
299d5ac70f0Sopenharmony_ci	case SND_CTL_ELEM_TYPE_IEC958:
300d5ac70f0Sopenharmony_ci		if (! ext->callback->write_iec958)
301d5ac70f0Sopenharmony_ci			goto err;
302d5ac70f0Sopenharmony_ci		ret = ext->callback->write_iec958(ext, key, (snd_aes_iec958_t *)&control->value.iec958);
303d5ac70f0Sopenharmony_ci		break;
304d5ac70f0Sopenharmony_ci	default:
305d5ac70f0Sopenharmony_ci		break;
306d5ac70f0Sopenharmony_ci	}
307d5ac70f0Sopenharmony_ci
308d5ac70f0Sopenharmony_ci err:
309d5ac70f0Sopenharmony_ci	if (ext->callback->free_key)
310d5ac70f0Sopenharmony_ci		ext->callback->free_key(ext, key);
311d5ac70f0Sopenharmony_ci
312d5ac70f0Sopenharmony_ci	return ret;
313d5ac70f0Sopenharmony_ci}
314d5ac70f0Sopenharmony_ci
315d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_lock(snd_ctl_t *handle ATTRIBUTE_UNUSED,
316d5ac70f0Sopenharmony_ci				 snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED)
317d5ac70f0Sopenharmony_ci{
318d5ac70f0Sopenharmony_ci	return -ENXIO;
319d5ac70f0Sopenharmony_ci}
320d5ac70f0Sopenharmony_ci
321d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_unlock(snd_ctl_t *handle ATTRIBUTE_UNUSED,
322d5ac70f0Sopenharmony_ci				   snd_ctl_elem_id_t *id ATTRIBUTE_UNUSED)
323d5ac70f0Sopenharmony_ci{
324d5ac70f0Sopenharmony_ci	return -ENXIO;
325d5ac70f0Sopenharmony_ci}
326d5ac70f0Sopenharmony_ci
327d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_elem_tlv(snd_ctl_t *handle, int op_flag,
328d5ac70f0Sopenharmony_ci				unsigned int numid,
329d5ac70f0Sopenharmony_ci				unsigned int *tlv, unsigned int tlv_size)
330d5ac70f0Sopenharmony_ci{
331d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
332d5ac70f0Sopenharmony_ci	snd_ctl_ext_key_t key;
333d5ac70f0Sopenharmony_ci	int type, ret;
334d5ac70f0Sopenharmony_ci	unsigned int access, count, len;
335d5ac70f0Sopenharmony_ci	snd_ctl_elem_id_t id;
336d5ac70f0Sopenharmony_ci
337d5ac70f0Sopenharmony_ci	/* we don't support TLV on protocol ver 1.0.0 or earlier */
338d5ac70f0Sopenharmony_ci	if (ext->version <= SNDRV_PROTOCOL_VERSION(1, 0, 0))
339d5ac70f0Sopenharmony_ci		return -ENXIO;
340d5ac70f0Sopenharmony_ci
341d5ac70f0Sopenharmony_ci	snd_ctl_elem_id_clear(&id);
342d5ac70f0Sopenharmony_ci	if (numid > 0) {
343d5ac70f0Sopenharmony_ci		ext->callback->elem_list(ext, numid - 1, &id);
344d5ac70f0Sopenharmony_ci		id.numid = numid;
345d5ac70f0Sopenharmony_ci	} else
346d5ac70f0Sopenharmony_ci		id.numid = 0;
347d5ac70f0Sopenharmony_ci	key = ext->callback->find_elem(ext, &id);
348d5ac70f0Sopenharmony_ci
349d5ac70f0Sopenharmony_ci	if (key == SND_CTL_EXT_KEY_NOT_FOUND)
350d5ac70f0Sopenharmony_ci		return -ENOENT;
351d5ac70f0Sopenharmony_ci	ret = ext->callback->get_attribute(ext, key, &type, &access, &count);
352d5ac70f0Sopenharmony_ci	if (ret < 0)
353d5ac70f0Sopenharmony_ci		return ret;
354d5ac70f0Sopenharmony_ci
355d5ac70f0Sopenharmony_ci	if ((op_flag == 0 && (access & SND_CTL_EXT_ACCESS_TLV_READ) == 0) ||
356d5ac70f0Sopenharmony_ci	    (op_flag > 0 && (access & SND_CTL_EXT_ACCESS_TLV_WRITE) == 0) ||
357d5ac70f0Sopenharmony_ci	    (op_flag < 0 && (access & SND_CTL_EXT_ACCESS_TLV_COMMAND) == 0))
358d5ac70f0Sopenharmony_ci		return -ENXIO;
359d5ac70f0Sopenharmony_ci	if (access & SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK) {
360d5ac70f0Sopenharmony_ci		return ext->tlv.c(ext, key, op_flag, numid, tlv, tlv_size);
361d5ac70f0Sopenharmony_ci	} else {
362d5ac70f0Sopenharmony_ci		if (op_flag)
363d5ac70f0Sopenharmony_ci			return -ENXIO;
364d5ac70f0Sopenharmony_ci		len = ext->tlv.p[1] + 2 * sizeof(unsigned int);
365d5ac70f0Sopenharmony_ci		if (tlv_size < len)
366d5ac70f0Sopenharmony_ci			return -ENOMEM;
367d5ac70f0Sopenharmony_ci		memcpy(tlv, ext->tlv.p, len);
368d5ac70f0Sopenharmony_ci		return 0;
369d5ac70f0Sopenharmony_ci	}
370d5ac70f0Sopenharmony_ci}
371d5ac70f0Sopenharmony_ci
372d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_next_device(snd_ctl_t *handle ATTRIBUTE_UNUSED,
373d5ac70f0Sopenharmony_ci				   int *device ATTRIBUTE_UNUSED)
374d5ac70f0Sopenharmony_ci{
375d5ac70f0Sopenharmony_ci	return -ENXIO;
376d5ac70f0Sopenharmony_ci}
377d5ac70f0Sopenharmony_ci
378d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_prefer_subdevice(snd_ctl_t *handle ATTRIBUTE_UNUSED,
379d5ac70f0Sopenharmony_ci					int subdev ATTRIBUTE_UNUSED)
380d5ac70f0Sopenharmony_ci{
381d5ac70f0Sopenharmony_ci	return -ENXIO;
382d5ac70f0Sopenharmony_ci}
383d5ac70f0Sopenharmony_ci
384d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_hwdep_info(snd_ctl_t *handle ATTRIBUTE_UNUSED,
385d5ac70f0Sopenharmony_ci				  snd_hwdep_info_t *info ATTRIBUTE_UNUSED)
386d5ac70f0Sopenharmony_ci{
387d5ac70f0Sopenharmony_ci	return -ENXIO;
388d5ac70f0Sopenharmony_ci}
389d5ac70f0Sopenharmony_ci
390d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_pcm_info(snd_ctl_t *handle ATTRIBUTE_UNUSED,
391d5ac70f0Sopenharmony_ci				snd_pcm_info_t *info ATTRIBUTE_UNUSED)
392d5ac70f0Sopenharmony_ci{
393d5ac70f0Sopenharmony_ci	return -ENXIO;
394d5ac70f0Sopenharmony_ci}
395d5ac70f0Sopenharmony_ci
396d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_rawmidi_info(snd_ctl_t *handle ATTRIBUTE_UNUSED,
397d5ac70f0Sopenharmony_ci				    snd_rawmidi_info_t *info ATTRIBUTE_UNUSED)
398d5ac70f0Sopenharmony_ci{
399d5ac70f0Sopenharmony_ci	return -ENXIO;
400d5ac70f0Sopenharmony_ci}
401d5ac70f0Sopenharmony_ci
402d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_set_power_state(snd_ctl_t *handle ATTRIBUTE_UNUSED,
403d5ac70f0Sopenharmony_ci				       unsigned int state ATTRIBUTE_UNUSED)
404d5ac70f0Sopenharmony_ci{
405d5ac70f0Sopenharmony_ci	return 0;
406d5ac70f0Sopenharmony_ci}
407d5ac70f0Sopenharmony_ci
408d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_get_power_state(snd_ctl_t *handle ATTRIBUTE_UNUSED,
409d5ac70f0Sopenharmony_ci				       unsigned int *state ATTRIBUTE_UNUSED)
410d5ac70f0Sopenharmony_ci{
411d5ac70f0Sopenharmony_ci	return 0;
412d5ac70f0Sopenharmony_ci}
413d5ac70f0Sopenharmony_ci
414d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_read(snd_ctl_t *handle, snd_ctl_event_t *event)
415d5ac70f0Sopenharmony_ci{
416d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
417d5ac70f0Sopenharmony_ci
418d5ac70f0Sopenharmony_ci	if (ext->callback->read_event) {
419d5ac70f0Sopenharmony_ci		memset(event, 0, sizeof(*event));
420d5ac70f0Sopenharmony_ci		return ext->callback->read_event(ext, &event->data.elem.id, &event->data.elem.mask);
421d5ac70f0Sopenharmony_ci	}
422d5ac70f0Sopenharmony_ci
423d5ac70f0Sopenharmony_ci	return -EINVAL;
424d5ac70f0Sopenharmony_ci}
425d5ac70f0Sopenharmony_ci
426d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_poll_descriptors_count(snd_ctl_t *handle)
427d5ac70f0Sopenharmony_ci{
428d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
429d5ac70f0Sopenharmony_ci
430d5ac70f0Sopenharmony_ci	if (ext->callback->poll_descriptors_count)
431d5ac70f0Sopenharmony_ci		return ext->callback->poll_descriptors_count(ext);
432d5ac70f0Sopenharmony_ci	if (ext->poll_fd >= 0)
433d5ac70f0Sopenharmony_ci		return 1;
434d5ac70f0Sopenharmony_ci	return 0;
435d5ac70f0Sopenharmony_ci}
436d5ac70f0Sopenharmony_ci
437d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_poll_descriptors(snd_ctl_t *handle, struct pollfd *pfds, unsigned int space)
438d5ac70f0Sopenharmony_ci{
439d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
440d5ac70f0Sopenharmony_ci
441d5ac70f0Sopenharmony_ci	if (ext->callback->poll_descriptors)
442d5ac70f0Sopenharmony_ci		return ext->callback->poll_descriptors(ext, pfds, space);
443d5ac70f0Sopenharmony_ci	if (ext->poll_fd < 0)
444d5ac70f0Sopenharmony_ci		return 0;
445d5ac70f0Sopenharmony_ci	if (space > 0) {
446d5ac70f0Sopenharmony_ci		pfds->fd = ext->poll_fd;
447d5ac70f0Sopenharmony_ci		pfds->events = POLLIN|POLLERR|POLLNVAL;
448d5ac70f0Sopenharmony_ci		return 1;
449d5ac70f0Sopenharmony_ci	}
450d5ac70f0Sopenharmony_ci	return 0;
451d5ac70f0Sopenharmony_ci}
452d5ac70f0Sopenharmony_ci
453d5ac70f0Sopenharmony_cistatic int snd_ctl_ext_poll_revents(snd_ctl_t *handle, struct pollfd *pfds, unsigned int nfds, unsigned short *revents)
454d5ac70f0Sopenharmony_ci{
455d5ac70f0Sopenharmony_ci	snd_ctl_ext_t *ext = handle->private_data;
456d5ac70f0Sopenharmony_ci
457d5ac70f0Sopenharmony_ci	if (ext->callback->poll_revents)
458d5ac70f0Sopenharmony_ci		return ext->callback->poll_revents(ext, pfds, nfds, revents);
459d5ac70f0Sopenharmony_ci	if (nfds == 1) {
460d5ac70f0Sopenharmony_ci		*revents = pfds->revents;
461d5ac70f0Sopenharmony_ci                return 0;
462d5ac70f0Sopenharmony_ci	}
463d5ac70f0Sopenharmony_ci	return -EINVAL;
464d5ac70f0Sopenharmony_ci}
465d5ac70f0Sopenharmony_ci
466d5ac70f0Sopenharmony_cistatic const snd_ctl_ops_t snd_ctl_ext_ops = {
467d5ac70f0Sopenharmony_ci	.close = snd_ctl_ext_close,
468d5ac70f0Sopenharmony_ci	.nonblock = snd_ctl_ext_nonblock,
469d5ac70f0Sopenharmony_ci	.async = snd_ctl_ext_async,
470d5ac70f0Sopenharmony_ci	.subscribe_events = snd_ctl_ext_subscribe_events,
471d5ac70f0Sopenharmony_ci	.card_info = snd_ctl_ext_card_info,
472d5ac70f0Sopenharmony_ci	.element_list = snd_ctl_ext_elem_list,
473d5ac70f0Sopenharmony_ci	.element_info = snd_ctl_ext_elem_info,
474d5ac70f0Sopenharmony_ci	.element_add = snd_ctl_ext_elem_add,
475d5ac70f0Sopenharmony_ci	.element_replace = snd_ctl_ext_elem_replace,
476d5ac70f0Sopenharmony_ci	.element_remove = snd_ctl_ext_elem_remove,
477d5ac70f0Sopenharmony_ci	.element_read = snd_ctl_ext_elem_read,
478d5ac70f0Sopenharmony_ci	.element_write = snd_ctl_ext_elem_write,
479d5ac70f0Sopenharmony_ci	.element_lock = snd_ctl_ext_elem_lock,
480d5ac70f0Sopenharmony_ci	.element_unlock = snd_ctl_ext_elem_unlock,
481d5ac70f0Sopenharmony_ci	.element_tlv = snd_ctl_ext_elem_tlv,
482d5ac70f0Sopenharmony_ci	.hwdep_next_device = snd_ctl_ext_next_device,
483d5ac70f0Sopenharmony_ci	.hwdep_info = snd_ctl_ext_hwdep_info,
484d5ac70f0Sopenharmony_ci	.pcm_next_device = snd_ctl_ext_next_device,
485d5ac70f0Sopenharmony_ci	.pcm_info = snd_ctl_ext_pcm_info,
486d5ac70f0Sopenharmony_ci	.pcm_prefer_subdevice = snd_ctl_ext_prefer_subdevice,
487d5ac70f0Sopenharmony_ci	.rawmidi_next_device = snd_ctl_ext_next_device,
488d5ac70f0Sopenharmony_ci	.rawmidi_info = snd_ctl_ext_rawmidi_info,
489d5ac70f0Sopenharmony_ci	.rawmidi_prefer_subdevice = snd_ctl_ext_prefer_subdevice,
490d5ac70f0Sopenharmony_ci	.set_power_state = snd_ctl_ext_set_power_state,
491d5ac70f0Sopenharmony_ci	.get_power_state = snd_ctl_ext_get_power_state,
492d5ac70f0Sopenharmony_ci	.read = snd_ctl_ext_read,
493d5ac70f0Sopenharmony_ci	.poll_descriptors_count = snd_ctl_ext_poll_descriptors_count,
494d5ac70f0Sopenharmony_ci	.poll_descriptors = snd_ctl_ext_poll_descriptors,
495d5ac70f0Sopenharmony_ci	.poll_revents = snd_ctl_ext_poll_revents,
496d5ac70f0Sopenharmony_ci};
497d5ac70f0Sopenharmony_ci
498d5ac70f0Sopenharmony_ci/*
499d5ac70f0Sopenharmony_ci * Exported functions
500d5ac70f0Sopenharmony_ci */
501d5ac70f0Sopenharmony_ci
502d5ac70f0Sopenharmony_ci/*! \page ctl_external_plugins External Control Plugin SDK
503d5ac70f0Sopenharmony_ci
504d5ac70f0Sopenharmony_ci\section ctl_externals External Control Plugins
505d5ac70f0Sopenharmony_ci
506d5ac70f0Sopenharmony_ciThe external plugins are implemented in a shared object file located
507d5ac70f0Sopenharmony_ciat /usr/lib/alsa-lib (the exact location depends on the build option
508d5ac70f0Sopenharmony_ciand asoundrc configuration).  It has to be the file like
509d5ac70f0Sopenharmony_cilibasound_module_ctl_MYPLUGIN.so, where MYPLUGIN corresponds to your
510d5ac70f0Sopenharmony_ciown plugin name.
511d5ac70f0Sopenharmony_ci
512d5ac70f0Sopenharmony_ciThe entry point of the plugin is defined via
513d5ac70f0Sopenharmony_ci#SND_CTL_PLUGIN_DEFINE_FUNC() macro.  This macro defines the function
514d5ac70f0Sopenharmony_ciwith a proper name to be referred from alsa-lib.  The function takes
515d5ac70f0Sopenharmony_cithe following 5 arguments:
516d5ac70f0Sopenharmony_ci\code
517d5ac70f0Sopenharmony_ciint (snd_ctl_t **phandle, const char *name, snd_config_t *root,
518d5ac70f0Sopenharmony_ci	snd_config_t *conf, int mode)
519d5ac70f0Sopenharmony_ci\endcode
520d5ac70f0Sopenharmony_ciThe first argument, phandle, is the pointer to store the resultant control
521d5ac70f0Sopenharmony_cihandle.  The arguments name, root and mode are the parameters
522d5ac70f0Sopenharmony_cito be passed to the plugin constructor.  The conf is the configuration
523d5ac70f0Sopenharmony_citree for the plugin.  The arguments above are defined in the macro
524d5ac70f0Sopenharmony_ciitself, so don't use variables with the same names to shadow
525d5ac70f0Sopenharmony_ciparameters.
526d5ac70f0Sopenharmony_ci
527d5ac70f0Sopenharmony_ciAfter parsing the configuration parameters in the given conf tree,
528d5ac70f0Sopenharmony_ciusually you will call the external plugin API function
529d5ac70f0Sopenharmony_ci#snd_ctl_ext_create().
530d5ac70f0Sopenharmony_ciThe control handle must be filled *phandle in return.
531d5ac70f0Sopenharmony_ciThen this function must return either a value 0 when succeeded, or a
532d5ac70f0Sopenharmony_cinegative value as the error code.
533d5ac70f0Sopenharmony_ci
534d5ac70f0Sopenharmony_ciFinally, add #SND_CTL_PLUGIN_SYMBOL() with the name of your
535d5ac70f0Sopenharmony_ciplugin as the argument at the end.  This defines the proper versioned
536d5ac70f0Sopenharmony_cisymbol as the reference.
537d5ac70f0Sopenharmony_ci
538d5ac70f0Sopenharmony_ciThe typical code would look like below:
539d5ac70f0Sopenharmony_ci\code
540d5ac70f0Sopenharmony_cistruct myctl_info {
541d5ac70f0Sopenharmony_ci	snd_ctl_ext_t ext;
542d5ac70f0Sopenharmony_ci	int my_own_data;
543d5ac70f0Sopenharmony_ci	...
544d5ac70f0Sopenharmony_ci};
545d5ac70f0Sopenharmony_ci
546d5ac70f0Sopenharmony_ciSND_CTL_PLUGIN_DEFINE_FUNC(myctl)
547d5ac70f0Sopenharmony_ci{
548d5ac70f0Sopenharmony_ci	snd_config_iterator_t i, next;
549d5ac70f0Sopenharmony_ci	struct myctl_info *myctl;
550d5ac70f0Sopenharmony_ci	int err;
551d5ac70f0Sopenharmony_ci
552d5ac70f0Sopenharmony_ci	snd_config_for_each(i, next, conf) {
553d5ac70f0Sopenharmony_ci		snd_config_t *n = snd_config_iterator_entry(i);
554d5ac70f0Sopenharmony_ci		const char *id;
555d5ac70f0Sopenharmony_ci		if (snd_config_get_id(n, &id) < 0)
556d5ac70f0Sopenharmony_ci			continue;
557d5ac70f0Sopenharmony_ci		if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
558d5ac70f0Sopenharmony_ci			continue;
559d5ac70f0Sopenharmony_ci		if (strcmp(id, "my_own_parameter") == 0) {
560d5ac70f0Sopenharmony_ci			....
561d5ac70f0Sopenharmony_ci			continue;
562d5ac70f0Sopenharmony_ci		}
563d5ac70f0Sopenharmony_ci		SNDERR("Unknown field %s", id);
564d5ac70f0Sopenharmony_ci		return -EINVAL;
565d5ac70f0Sopenharmony_ci	}
566d5ac70f0Sopenharmony_ci
567d5ac70f0Sopenharmony_ci	myctl = calloc(1, sizeof(*myctl));
568d5ac70f0Sopenharmony_ci	if (myctl == NULL)
569d5ac70f0Sopenharmony_ci		return -ENOMEM;
570d5ac70f0Sopenharmony_ci
571d5ac70f0Sopenharmony_ci	myctl->ext.version = SND_CTL_EXT_VERSION;
572d5ac70f0Sopenharmony_ci	myctl->ext.card_idx = 0;
573d5ac70f0Sopenharmony_ci	strcpy(myctl->ext.id, "Myctl");
574d5ac70f0Sopenharmony_ci	strcpy(myctl->ext.name, "My Control");
575d5ac70f0Sopenharmony_ci	strcpy(myctl->ext.longname, "My External Control for Foobar");
576d5ac70f0Sopenharmony_ci	strcpy(myctl->ext.mixername, "My Control");
577d5ac70f0Sopenharmony_ci	myctl->ext.callback = &my_own_callback;
578d5ac70f0Sopenharmony_ci	myctl->ext.private_data = myctl;
579d5ac70f0Sopenharmony_ci	....
580d5ac70f0Sopenharmony_ci
581d5ac70f0Sopenharmony_ci	err = snd_pcm_extplug_create(&myctl->ext, name, mode);
582d5ac70f0Sopenharmony_ci	if (err < 0) {
583d5ac70f0Sopenharmony_ci		myctl_free(myctl);
584d5ac70f0Sopenharmony_ci		return err;
585d5ac70f0Sopenharmony_ci	}
586d5ac70f0Sopenharmony_ci
587d5ac70f0Sopenharmony_ci	*phandle = myctl->ext.handle;
588d5ac70f0Sopenharmony_ci	return 0;
589d5ac70f0Sopenharmony_ci}
590d5ac70f0Sopenharmony_ci
591d5ac70f0Sopenharmony_ciSND_CTL_PLUGIN_SYMBOL(myctl);
592d5ac70f0Sopenharmony_ci\endcode
593d5ac70f0Sopenharmony_ci
594d5ac70f0Sopenharmony_ciRead the codes in alsa-plugins package for the real examples.
595d5ac70f0Sopenharmony_ci
596d5ac70f0Sopenharmony_ci
597d5ac70f0Sopenharmony_ci\section ctl_ext_impl Implementation of External Control Plugins
598d5ac70f0Sopenharmony_ci
599d5ac70f0Sopenharmony_ciThe following fields have to be filled in external control record before calling
600d5ac70f0Sopenharmony_ci#snd_ctl_ext_create() : version, card_idx, id, name, longname, mixername, poll_fd and callback.
601d5ac70f0Sopenharmony_ciOtherfields are optional and should be initialized with zero.
602d5ac70f0Sopenharmony_ci
603d5ac70f0Sopenharmony_ciThe constant #SND_CTL_EXT_VERSION must be passed to the version
604d5ac70f0Sopenharmony_cifield for the version check in alsa-lib.  The card_idx field specifies the card
605d5ac70f0Sopenharmony_ciindex of this control.  [FIXME: solve confliction of card index in alsa-lib?]
606d5ac70f0Sopenharmony_ci
607d5ac70f0Sopenharmony_ciThe id, name, longname and mixername fields are the strings shown in the card_info
608d5ac70f0Sopenharmony_ciinqurirys.  They are the char arrays, so you have to <i>copy</i> strings to these
609d5ac70f0Sopenharmony_cifields.
610d5ac70f0Sopenharmony_ci
611d5ac70f0Sopenharmony_ciThe callback field contains the  table of callback functions for this plugin (defined as
612d5ac70f0Sopenharmony_ci#snd_ctl_ext_callback_t).
613d5ac70f0Sopenharmony_ciThe poll_fd can be used to specify the poll file descriptor for this control.
614d5ac70f0Sopenharmony_ciSet -1 if not available.  Alternatively, you can define poll_descriptors_count and
615d5ac70f0Sopenharmony_cipoll_descriptors callbacks in the callback table for handling the poll descriptor(s)
616d5ac70f0Sopenharmony_cidynamically after the creation of plugin instance.
617d5ac70f0Sopenharmony_ci
618d5ac70f0Sopenharmony_ciThe driver can set an arbitrary value (pointer) to private_data
619d5ac70f0Sopenharmony_cifield to refer its own data in the callbacks.
620d5ac70f0Sopenharmony_ci
621d5ac70f0Sopenharmony_ciThe rest fields are filled by #snd_ctl_ext_create().  The handle field
622d5ac70f0Sopenharmony_ciis the resultant PCM handle.  The others are the current status of the
623d5ac70f0Sopenharmony_ciPCM.
624d5ac70f0Sopenharmony_ci
625d5ac70f0Sopenharmony_ci\section ctl_ext_impl_cb Callback Functions of External Control Plugins
626d5ac70f0Sopenharmony_ci
627d5ac70f0Sopenharmony_ciThe callback functions in #snd_ctl_ext_callback_t define the real
628d5ac70f0Sopenharmony_cibehavior of the driver.  There are many callbacks but many of them are optional.
629d5ac70f0Sopenharmony_ci
630d5ac70f0Sopenharmony_ciThe close callback is called when the PCM is closed.  If the plugin
631d5ac70f0Sopenharmony_ciallocates private resources, this is the place to release them
632d5ac70f0Sopenharmony_ciagain.  This callback is optional.
633d5ac70f0Sopenharmony_ci
634d5ac70f0Sopenharmony_ciThe elem_count and elem_list callbacks are mandatory.  The elem_count returns the
635d5ac70f0Sopenharmony_citotal number of control elements.  The elem_list returns the control element ID
636d5ac70f0Sopenharmony_ciof the corresponding element offset (the offset is from 0 to elem_count - 1).
637d5ac70f0Sopenharmony_ciThe id field is initialized to all zero in prior to elem_list callback.  The callback
638d5ac70f0Sopenharmony_cihas to fill the necessary field (typically iface, name and index) in return via the
639d5ac70f0Sopenharmony_cistandard control API functions like #snd_ctl_elem_id_set_interface,
640d5ac70f0Sopenharmony_ci#snd_ctl_elem_id_set_name and #snd_ctl_elem_id_set_index, etc.  The callbacks should
641d5ac70f0Sopenharmony_cireturn 0 if successful, or a negative error code.
642d5ac70f0Sopenharmony_ci
643d5ac70f0Sopenharmony_ciThe find_elem callback is used to convert the given control element ID to the
644d5ac70f0Sopenharmony_cicertain key value for the faster access to get, read and write callbacks.
645d5ac70f0Sopenharmony_ciThe key type is alias of unsigned long, so you can assign some static number
646d5ac70f0Sopenharmony_ci(e.g. index of the array) to this value of the corresponding element, or
647d5ac70f0Sopenharmony_ciassign the pointer (cast to #snd_ctl_ext_key_t).  When no key is defined or found,
648d5ac70f0Sopenharmony_cireturn #SND_CTL_EXT_KEY_NOT_FOUND.  This callback is (very likely) required
649d5ac70f0Sopenharmony_ciif you use get, read and write callbacks as follows.
650d5ac70f0Sopenharmony_ciIf you need to create a record dynamically (e.g. via malloc) at each find_elem call,
651d5ac70f0Sopenharmony_cithe allocated record can be released with the optional free_key callback.
652d5ac70f0Sopenharmony_ci
653d5ac70f0Sopenharmony_ciThe get_attribute is a mandatory callback, which returns the attribute of the
654d5ac70f0Sopenharmony_cicontrol element given via a key value (converted with find_elem callback).
655d5ac70f0Sopenharmony_ciIt must fill the control element type (#snd_ctl_elem_type_t), the access type
656d5ac70f0Sopenharmony_ci(#snd_ctl_ext_access_t), and the count (element array size).  The callback returns
657d5ac70f0Sopenharmony_ci0 if successful, or a negative error code, as usual.
658d5ac70f0Sopenharmony_ci
659d5ac70f0Sopenharmony_ciThe get_integer_info, get_integetr64_info and get_enumerated_info callbacks are called
660d5ac70f0Sopenharmony_cito return the information of the given control element for each element type.
661d5ac70f0Sopenharmony_ciFor integer and integer64 types, the callbacks need to fill the minimal (imin),
662d5ac70f0Sopenharmony_cimaximal (imax) and the step (istep) values of the control.  For the enumerated type,
663d5ac70f0Sopenharmony_cithe number of enum items must be filled.  Additionally, the enum control has to define
664d5ac70f0Sopenharmony_ciget_enumerated_name callback to store the name of the enumerated item of the given control
665d5ac70f0Sopenharmony_cielement.  All functions return 0 if successful, or a negative error code.
666d5ac70f0Sopenharmony_ci
667d5ac70f0Sopenharmony_ciFor reading the current values of a control element, read_integer, read_integer64,
668d5ac70f0Sopenharmony_ciread_enumerated, read_bytes and read_iec958 callbacks are called depending on the
669d5ac70f0Sopenharmony_cielement type.  These callbacks have to fill the current values of the element in return.
670d5ac70f0Sopenharmony_ciNote that a control element can be an array.  If it contains more than one values
671d5ac70f0Sopenharmony_ci(i.e. the count value in get_attribute callback is more than 1), <i>all</i> values
672d5ac70f0Sopenharmony_cimust be filled on the given value pointer as an array.  Also, note that the boolean type
673d5ac70f0Sopenharmony_ciis handled as integer here (although boolean type doesn't need to define the corresponding
674d5ac70f0Sopenharmony_ciinfo callback since it's obvious).  These callbacks return 0 if successful, or
675d5ac70f0Sopenharmony_cia negative error code.
676d5ac70f0Sopenharmony_ci
677d5ac70f0Sopenharmony_ciFor writing the current values, write_integer, write_integer64, write_bytes, and
678d5ac70f0Sopenharmony_ciwrite_iec958 callbacks are called as well as for read.  The callbacks should check the
679d5ac70f0Sopenharmony_cicurrent values and compare with the given values.  If they are identical, the callbacks
680d5ac70f0Sopenharmony_cishould do nothing and return 0.  If they differ, update the current values and return 1,
681d5ac70f0Sopenharmony_ciinstead.  For any errors, return a negative error code.
682d5ac70f0Sopenharmony_ci
683d5ac70f0Sopenharmony_ciThe subscribe_events callback is called when the application subscribes or cancels
684d5ac70f0Sopenharmony_cithe event notifications (e.g. through mixer API).  The current value of event
685d5ac70f0Sopenharmony_cisubscription is kept in the subscribed field.
686d5ac70f0Sopenharmony_ciThe read_event callback is called for reading a pending notification event.
687d5ac70f0Sopenharmony_ciThe callback needs to fill the event_mask value, a bit-field defined as SND_CTL_EVENT_MASK_XXX.
688d5ac70f0Sopenharmony_ciIf no event is pending, return -EAGAIN.  These two callbacks are optional.
689d5ac70f0Sopenharmony_ci
690d5ac70f0Sopenharmony_ciThe poll_descriptors_count and poll_descriptors callbacks are used to return
691d5ac70f0Sopenharmony_cithe poll descriptor(s) via callbacks.  As already mentioned, if the callback cannot
692d5ac70f0Sopenharmony_ciset the static poll_fd, you can define these callbacks to return dynamically.
693d5ac70f0Sopenharmony_ciAlso, when multiple poll descriptors are required, use these callbacks.
694d5ac70f0Sopenharmony_ciThe poll_revents callback is used for handle poll revents.
695d5ac70f0Sopenharmony_ci
696d5ac70f0Sopenharmony_ci*/
697d5ac70f0Sopenharmony_ci
698d5ac70f0Sopenharmony_ci/**
699d5ac70f0Sopenharmony_ci * \brief Create an external control plugin instance
700d5ac70f0Sopenharmony_ci * \param ext the plugin handle
701d5ac70f0Sopenharmony_ci * \param name name of control
702d5ac70f0Sopenharmony_ci * \param mode control open mode
703d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code
704d5ac70f0Sopenharmony_ci *
705d5ac70f0Sopenharmony_ci * Creates the external control instance.
706d5ac70f0Sopenharmony_ci *
707d5ac70f0Sopenharmony_ci */
708d5ac70f0Sopenharmony_ciint snd_ctl_ext_create(snd_ctl_ext_t *ext, const char *name, int mode)
709d5ac70f0Sopenharmony_ci{
710d5ac70f0Sopenharmony_ci	snd_ctl_t *ctl;
711d5ac70f0Sopenharmony_ci	int err;
712d5ac70f0Sopenharmony_ci
713d5ac70f0Sopenharmony_ci	if (ext->version < SNDRV_PROTOCOL_VERSION(1, 0, 0) ||
714d5ac70f0Sopenharmony_ci	    ext->version > SND_CTL_EXT_VERSION) {
715d5ac70f0Sopenharmony_ci		SNDERR("ctl_ext: Plugin version mismatch");
716d5ac70f0Sopenharmony_ci		return -ENXIO;
717d5ac70f0Sopenharmony_ci	}
718d5ac70f0Sopenharmony_ci
719d5ac70f0Sopenharmony_ci	err = snd_ctl_new(&ctl, SND_CTL_TYPE_EXT, name, mode);
720d5ac70f0Sopenharmony_ci	if (err < 0)
721d5ac70f0Sopenharmony_ci		return err;
722d5ac70f0Sopenharmony_ci
723d5ac70f0Sopenharmony_ci	ext->handle = ctl;
724d5ac70f0Sopenharmony_ci
725d5ac70f0Sopenharmony_ci	ctl->ops = &snd_ctl_ext_ops;
726d5ac70f0Sopenharmony_ci	ctl->private_data = ext;
727d5ac70f0Sopenharmony_ci	ctl->poll_fd = ext->poll_fd;
728d5ac70f0Sopenharmony_ci	if (mode & SND_CTL_NONBLOCK)
729d5ac70f0Sopenharmony_ci		ext->nonblock = 1;
730d5ac70f0Sopenharmony_ci
731d5ac70f0Sopenharmony_ci	return 0;
732d5ac70f0Sopenharmony_ci}
733d5ac70f0Sopenharmony_ci
734d5ac70f0Sopenharmony_ci/**
735d5ac70f0Sopenharmony_ci * \brief Delete the external control plugin
736d5ac70f0Sopenharmony_ci * \param ext the plugin handle
737d5ac70f0Sopenharmony_ci * \return 0 if successful, or a negative error code
738d5ac70f0Sopenharmony_ci */
739d5ac70f0Sopenharmony_ciint snd_ctl_ext_delete(snd_ctl_ext_t *ext)
740d5ac70f0Sopenharmony_ci{
741d5ac70f0Sopenharmony_ci	return snd_ctl_close(ext->handle);
742d5ac70f0Sopenharmony_ci}
743