1/**
2 * \file timer/timer_query.c
3 * \author Jaroslav Kysela <perex@perex.cz>
4 * \date 2001
5 *
6 * Timer Query Interface is designed to obtain identification of timers.
7 */
8/*
9 *  Timer Query Interface - main file
10 *  Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
11 *
12 *
13 *   This library is free software; you can redistribute it and/or modify
14 *   it under the terms of the GNU Lesser General Public License as
15 *   published by the Free Software Foundation; either version 2.1 of
16 *   the License, or (at your option) any later version.
17 *
18 *   This program is distributed in the hope that it will be useful,
19 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
20 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 *   GNU Lesser General Public License for more details.
22 *
23 *   You should have received a copy of the GNU Lesser General Public
24 *   License along with this library; if not, write to the Free Software
25 *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
26 *
27 */
28
29#include "timer_local.h"
30
31static int snd_timer_query_open_conf(snd_timer_query_t **timer,
32				     const char *name, snd_config_t *timer_root,
33				     snd_config_t *timer_conf, int mode)
34{
35	const char *str;
36	char buf[256], errbuf[256];
37	int err;
38	snd_config_t *conf, *type_conf = NULL;
39	snd_config_iterator_t i, next;
40	const char *id;
41	const char *lib = NULL, *open_name = NULL;
42	int (*open_func)(snd_timer_query_t **, const char *, snd_config_t *, snd_config_t *, int) = NULL;
43#ifndef PIC
44	extern void *snd_timer_query_open_symbols(void);
45#endif
46	void *h = NULL;
47	if (snd_config_get_type(timer_conf) != SND_CONFIG_TYPE_COMPOUND) {
48		if (name)
49			SNDERR("Invalid type for TIMER %s definition", name);
50		else
51			SNDERR("Invalid type for TIMER definition");
52		return -EINVAL;
53	}
54	err = snd_config_search(timer_conf, "type", &conf);
55	if (err < 0) {
56		SNDERR("type is not defined");
57		return err;
58	}
59	err = snd_config_get_id(conf, &id);
60	if (err < 0) {
61		SNDERR("unable to get id");
62		return err;
63	}
64	err = snd_config_get_string(conf, &str);
65	if (err < 0) {
66		SNDERR("Invalid type for %s", id);
67		return err;
68	}
69	err = snd_config_search_definition(timer_root, "timer_query_type", str, &type_conf);
70	if (err >= 0) {
71		if (snd_config_get_type(type_conf) != SND_CONFIG_TYPE_COMPOUND) {
72			SNDERR("Invalid type for TIMER type %s definition", str);
73			err = -EINVAL;
74			goto _err;
75		}
76		snd_config_for_each(i, next, type_conf) {
77			snd_config_t *n = snd_config_iterator_entry(i);
78			const char *id;
79			if (snd_config_get_id(n, &id) < 0)
80				continue;
81			if (strcmp(id, "comment") == 0)
82				continue;
83			if (strcmp(id, "lib") == 0) {
84				err = snd_config_get_string(n, &lib);
85				if (err < 0) {
86					SNDERR("Invalid type for %s", id);
87					goto _err;
88				}
89				continue;
90			}
91			if (strcmp(id, "open") == 0) {
92				err = snd_config_get_string(n, &open_name);
93				if (err < 0) {
94					SNDERR("Invalid type for %s", id);
95					goto _err;
96				}
97				continue;
98			}
99			SNDERR("Unknown field %s", id);
100			err = -EINVAL;
101			goto _err;
102		}
103	}
104	if (!open_name) {
105		open_name = buf;
106		snprintf(buf, sizeof(buf), "_snd_timer_query_%s_open", str);
107	}
108#ifndef PIC
109	snd_timer_query_open_symbols();
110#endif
111	h = INTERNAL(snd_dlopen)(lib, RTLD_NOW, errbuf, sizeof(errbuf));
112	if (h)
113		open_func = snd_dlsym(h, open_name, SND_DLSYM_VERSION(SND_TIMER_QUERY_DLSYM_VERSION));
114	err = 0;
115	if (!h) {
116		SNDERR("Cannot open shared library %s (%s)", lib, errbuf);
117		err = -ENOENT;
118	} else if (!open_func) {
119		SNDERR("symbol %s is not defined inside %s", open_name, lib);
120		snd_dlclose(h);
121		err = -ENXIO;
122	}
123       _err:
124	if (type_conf)
125		snd_config_delete(type_conf);
126	if (! err) {
127		err = open_func(timer, name, timer_root, timer_conf, mode);
128		if (err < 0)
129			snd_dlclose(h);
130		else
131			(*timer)->dl_handle = h;
132	}
133	return err;
134}
135
136static int snd_timer_query_open_noupdate(snd_timer_query_t **timer, snd_config_t *root, const char *name, int mode)
137{
138	int err;
139	snd_config_t *timer_conf;
140	err = snd_config_search_definition(root, "timer_query", name, &timer_conf);
141	if (err < 0) {
142		SNDERR("Unknown timer %s", name);
143		return err;
144	}
145	err = snd_timer_query_open_conf(timer, name, root, timer_conf, mode);
146	snd_config_delete(timer_conf);
147	return err;
148}
149
150/**
151 * \brief Opens a new connection to the timer query interface.
152 * \param timer Returned handle (NULL if not wanted)
153 * \param name ASCII identifier of the RawMidi handle
154 * \param mode Open mode
155 * \return 0 on success otherwise a negative error code
156 *
157 * Opens a new connection to the RawMidi interface specified with
158 * an ASCII identifier and mode.
159 */
160int snd_timer_query_open(snd_timer_query_t **timer, const char *name, int mode)
161{
162	snd_config_t *top;
163	int err;
164
165	assert(timer && name);
166	err = snd_config_update_ref(&top);
167	if (err < 0)
168		return err;
169	err = snd_timer_query_open_noupdate(timer, top, name, mode);
170	snd_config_unref(top);
171	return err;
172}
173
174/**
175 * \brief Opens a new connection to the timer query interface using local configuration
176 * \param timer Returned handle (NULL if not wanted)
177 * \param name ASCII identifier of the RawMidi handle
178 * \param mode Open mode
179 * \param lconf Local configuration
180 * \return 0 on success otherwise a negative error code
181 *
182 * Opens a new connection to the RawMidi interface specified with
183 * an ASCII identifier and mode.
184 */
185int snd_timer_query_open_lconf(snd_timer_query_t **timer, const char *name,
186			       int mode, snd_config_t *lconf)
187{
188	assert(timer && name && lconf);
189	return snd_timer_query_open_noupdate(timer, lconf, name, mode);
190}
191
192/**
193 * \brief close timer query handle
194 * \param timer timer handle
195 * \return 0 on success otherwise a negative error code
196 *
197 * Closes the specified timer handle and frees all associated
198 * resources.
199 */
200int snd_timer_query_close(snd_timer_query_t *timer)
201{
202	int err;
203  	assert(timer);
204	err = timer->ops->close(timer);
205	if (timer->dl_handle)
206		snd_dlclose(timer->dl_handle);
207	free(timer->name);
208	free(timer);
209	return err;
210}
211
212/**
213 * \brief obtain the next timer identification
214 * \param timer timer handle
215 * \param tid timer identification
216 * \return 0 on success otherwise a negative error code
217 *
218 * if tid->dev_class is -1, then the first device is returned
219 * if result tid->dev_class is -1, no more devices are left
220 */
221int snd_timer_query_next_device(snd_timer_query_t *timer, snd_timer_id_t *tid)
222{
223  	assert(timer);
224  	assert(tid);
225	return timer->ops->next_device(timer, tid);
226}
227
228/**
229 * \brief get size of the snd_timer_ginfo_t structure in bytes
230 * \return size of the snd_timer_ginfo_t structure in bytes
231 */
232size_t snd_timer_ginfo_sizeof(void)
233{
234	return sizeof(snd_timer_ginfo_t);
235}
236
237/**
238 * \brief allocate a new snd_timer_ginfo_t structure
239 * \param info returned pointer
240 * \return 0 on success otherwise a negative error code if fails
241 *
242 * Allocates a new snd_timer_info_t structure using the standard
243 * malloc C library function.
244 */
245int snd_timer_ginfo_malloc(snd_timer_ginfo_t **info)
246{
247	assert(info);
248	*info = calloc(1, sizeof(snd_timer_ginfo_t));
249	if (!*info)
250		return -ENOMEM;
251	return 0;
252}
253
254/**
255 * \brief frees the snd_timer_ginfo_t structure
256 * \param info pointer to the snd_timer_ginfo_t structure to free
257 *
258 * Frees the given snd_timer_info_t structure using the standard
259 * free C library function.
260 */
261void snd_timer_ginfo_free(snd_timer_ginfo_t *info)
262{
263	assert(info);
264	free(info);
265}
266
267/**
268 * \brief copy one snd_timer_info_t structure to another
269 * \param dst destination snd_timer_info_t structure
270 * \param src source snd_timer_info_t structure
271 */
272void snd_timer_ginfo_copy(snd_timer_ginfo_t *dst, const snd_timer_ginfo_t *src)
273{
274	assert(dst && src);
275	*dst = *src;
276}
277
278/**
279 * \brief set timer identification
280 * \param obj pointer to #snd_timer_ginfo_t structure
281 * \param tid pointer to #snd_timer_id_t structure
282 * \return zero on success otherwise a negative error number
283 */
284int snd_timer_ginfo_set_tid(snd_timer_ginfo_t *obj, snd_timer_id_t *tid)
285{
286	obj->tid = *((snd_timer_id_t *)tid);
287	return 0;
288}
289
290/**
291 * \brief get timer identification
292 * \param obj pointer to #snd_timer_ginfo_t structure
293 * \return pointer to snd_timer_id_t
294 */
295snd_timer_id_t *snd_timer_ginfo_get_tid(snd_timer_ginfo_t *obj)
296{
297	return (snd_timer_id_t *)&obj->tid;
298}
299
300/**
301 * \brief get timer flags
302 * \param obj pointer to #snd_timer_ginfo_t structure
303 * \return timer flags
304 */
305unsigned int snd_timer_ginfo_get_flags(snd_timer_ginfo_t *obj)
306{
307	return obj->flags;
308}
309
310/**
311 * \brief get associated card with timer
312 * \param obj pointer to #snd_timer_ginfo_t structure
313 * \return associated card
314 */
315int snd_timer_ginfo_get_card(snd_timer_ginfo_t *obj)
316{
317	return obj->card;
318}
319
320/**
321 * \brief get timer identification
322 * \param obj pointer to #snd_timer_ginfo_t structure
323 * \return timer identification
324 */
325char *snd_timer_ginfo_get_id(snd_timer_ginfo_t *obj)
326{
327	return (char *)obj->id;
328}
329
330/**
331 * \brief get timer name
332 * \param obj pointer to #snd_timer_ginfo_t structure
333 * \return timer name
334 */
335char *snd_timer_ginfo_get_name(snd_timer_ginfo_t *obj)
336{
337	return (char *)obj->name;
338}
339
340/**
341 * \brief get timer resolution in ns
342 * \param obj pointer to #snd_timer_ginfo_t structure
343 * \return timer resolution in ns
344 */
345unsigned long snd_timer_ginfo_get_resolution(snd_timer_ginfo_t *obj)
346{
347	return obj->resolution;
348}
349
350/**
351 * \brief get timer minimal resolution in ns
352 * \param obj pointer to #snd_timer_ginfo_t structure
353 * \return timer minimal resolution in ns
354 */
355unsigned long snd_timer_ginfo_get_resolution_min(snd_timer_ginfo_t *obj)
356{
357	return obj->resolution_min;
358}
359
360/**
361 * \brief get timer maximal resolution in ns
362 * \param obj pointer to #snd_timer_ginfo_t structure
363 * \return timer maximal resolution in ns
364 */
365unsigned long snd_timer_ginfo_get_resolution_max(snd_timer_ginfo_t *obj)
366{
367	return obj->resolution_max;
368}
369
370/**
371 * \brief get current timer clients
372 * \param obj pointer to #snd_timer_ginfo_t structure
373 * \return current timer clients
374 */
375unsigned int snd_timer_ginfo_get_clients(snd_timer_ginfo_t *obj)
376{
377	return obj->clients;
378}
379
380/**
381 * \brief obtain the timer global information
382 * \param timer timer handle
383 * \param info timer information
384 * \return 0 on success otherwise a negative error code
385 */
386#ifndef DOXYGEN
387EXPORT_SYMBOL int INTERNAL(snd_timer_query_info)(snd_timer_query_t *timer, snd_timer_ginfo_t *info)
388#else
389int snd_timer_query_info(snd_timer_query_t *timer, snd_timer_ginfo_t *info)
390#endif
391{
392  	assert(timer);
393  	assert(info);
394	return timer->ops->info(timer, info);
395}
396use_default_symbol_version(__snd_timer_query_info, snd_timer_query_info, ALSA_0.9.0);
397
398/**
399 * \brief set the timer global parameters
400 * \param timer timer handle
401 * \param params timer parameters
402 * \return 0 on success otherwise a negative error code
403 */
404#ifndef DOXYGEN
405EXPORT_SYMBOL int INTERNAL(snd_timer_query_params)(snd_timer_query_t *timer, snd_timer_gparams_t *params)
406#else
407int snd_timer_query_params(snd_timer_query_t *timer, snd_timer_gparams_t *params)
408#endif
409{
410  	assert(timer);
411  	assert(params);
412	return timer->ops->params(timer, params);
413}
414use_default_symbol_version(__snd_timer_query_params, snd_timer_query_params, ALSA_0.9.0);
415
416/**
417 * \brief get the timer global status
418 * \param timer timer handle
419 * \param status timer status
420 * \return 0 on success otherwise a negative error code
421 */
422#ifndef DOXYGEN
423EXPORT_SYMBOL int INTERNAL(snd_timer_query_status)(snd_timer_query_t *timer, snd_timer_gstatus_t *status)
424#else
425int snd_timer_query_status(snd_timer_query_t *timer, snd_timer_gstatus_t *status)
426#endif
427{
428  	assert(timer);
429  	assert(status);
430	return timer->ops->status(timer, status);
431}
432use_default_symbol_version(__snd_timer_query_status, snd_timer_query_status, ALSA_0.9.0);
433
434/**
435 * \brief get size of the snd_timer_id_t structure in bytes
436 * \return size of the snd_timer_id_t structure in bytes
437 */
438size_t snd_timer_id_sizeof()
439{
440	return sizeof(snd_timer_id_t);
441}
442
443/**
444 * \brief allocate a new snd_timer_id_t structure
445 * \param info returned pointer
446 * \return 0 on success otherwise a negative error code if fails
447 *
448 * Allocates a new snd_timer_id_t structure using the standard
449 * malloc C library function.
450 */
451int snd_timer_id_malloc(snd_timer_id_t **info)
452{
453	assert(info);
454	*info = calloc(1, sizeof(snd_timer_id_t));
455	if (!*info)
456		return -ENOMEM;
457	return 0;
458}
459
460/**
461 * \brief frees the snd_timer_id_t structure
462 * \param info pointer to the snd_timer_id_t structure to free
463 *
464 * Frees the given snd_timer_id_t structure using the standard
465 * free C library function.
466 */
467void snd_timer_id_free(snd_timer_id_t *info)
468{
469	assert(info);
470	free(info);
471}
472
473/**
474 * \brief copy one snd_timer_id_t structure to another
475 * \param dst destination snd_timer_id_t structure
476 * \param src source snd_timer_id_t structure
477 */
478void snd_timer_id_copy(snd_timer_id_t *dst, const snd_timer_id_t *src)
479{
480	assert(dst && src);
481	*dst = *src;
482}
483
484/**
485 * \brief set timer class
486 * \param tid pointer to #snd_timer_id_t structure
487 * \param dev_class class of timer device
488 */
489void snd_timer_id_set_class(snd_timer_id_t * tid, int dev_class)
490{
491	assert(tid);
492	tid->dev_class = dev_class;
493}
494
495/**
496 * \brief get timer class
497 * \param tid pointer to #snd_timer_id_t structure
498 * \return timer class
499 */
500int snd_timer_id_get_class(snd_timer_id_t * tid)
501{
502	assert(tid);
503	return tid->dev_class;
504}
505
506/**
507 * \brief set timer sub-class
508 * \param tid pointer to #snd_timer_id_t structure
509 * \param dev_sclass sub-class of timer device
510 */
511void snd_timer_id_set_sclass(snd_timer_id_t * tid, int dev_sclass)
512{
513	assert(tid);
514	tid->dev_sclass = dev_sclass;
515}
516
517/**
518 * \brief get timer sub-class
519 * \param tid pointer to #snd_timer_id_t structure
520 * \return timer sub-class
521 */
522int snd_timer_id_get_sclass(snd_timer_id_t * tid)
523{
524	assert(tid);
525	return tid->dev_sclass;
526}
527
528/**
529 * \brief set timer card
530 * \param tid pointer to #snd_timer_id_t structure
531 * \param card card number
532 */
533void snd_timer_id_set_card(snd_timer_id_t * tid, int card)
534{
535	assert(tid);
536	tid->card = card;
537}
538
539/**
540 * \brief get timer card
541 * \param tid pointer to #snd_timer_id_t structure
542 * \return timer card number
543 */
544int snd_timer_id_get_card(snd_timer_id_t * tid)
545{
546	assert(tid);
547	return tid->card;
548}
549
550/**
551 * \brief set timer device
552 * \param tid pointer to #snd_timer_id_t structure
553 * \param device device number
554 */
555void snd_timer_id_set_device(snd_timer_id_t * tid, int device)
556{
557	assert(tid);
558	tid->device = device;
559}
560
561/**
562 * \brief get timer device
563 * \param tid pointer to #snd_timer_id_t structure
564 * \return timer device number
565 */
566int snd_timer_id_get_device(snd_timer_id_t * tid)
567{
568	assert(tid);
569	return tid->device;
570}
571
572/**
573 * \brief set timer subdevice
574 * \param tid pointer to #snd_timer_id_t structure
575 * \param subdevice subdevice number
576 */
577void snd_timer_id_set_subdevice(snd_timer_id_t * tid, int subdevice)
578{
579	assert(tid);
580	tid->subdevice = subdevice;
581}
582
583/**
584 * \brief get timer subdevice
585 * \param tid pointer to #snd_timer_id_t structure
586 * \return timer subdevice number
587 */
588int snd_timer_id_get_subdevice(snd_timer_id_t * tid)
589{
590	assert(tid);
591	return tid->subdevice;
592}
593