xref: /openbsd/lib/libsndio/sioctl.c (revision 36355b88)
1*36355b88Sratchov /*	$OpenBSD: sioctl.c,v 1.2 2021/11/01 14:43:24 ratchov Exp $	*/
2d07fece6Sratchov /*
3d07fece6Sratchov  * Copyright (c) 2014-2020 Alexandre Ratchov <alex@caoua.org>
4d07fece6Sratchov  *
5d07fece6Sratchov  * Permission to use, copy, modify, and distribute this software for any
6d07fece6Sratchov  * purpose with or without fee is hereby granted, provided that the above
7d07fece6Sratchov  * copyright notice and this permission notice appear in all copies.
8d07fece6Sratchov  *
9d07fece6Sratchov  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10d07fece6Sratchov  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11d07fece6Sratchov  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12d07fece6Sratchov  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13d07fece6Sratchov  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14d07fece6Sratchov  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15d07fece6Sratchov  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16d07fece6Sratchov  */
17d07fece6Sratchov #include <errno.h>
18d07fece6Sratchov #include <poll.h>
19d07fece6Sratchov #include <stdlib.h>
20d07fece6Sratchov #include <string.h>
21d07fece6Sratchov #include <unistd.h>
22d07fece6Sratchov 
23d07fece6Sratchov #include "debug.h"
24d07fece6Sratchov #include "sioctl_priv.h"
25d07fece6Sratchov 
26d07fece6Sratchov struct sioctl_hdl *
sioctl_open(const char * str,unsigned int mode,int nbio)27d07fece6Sratchov sioctl_open(const char *str, unsigned int mode, int nbio)
28d07fece6Sratchov {
29d07fece6Sratchov 	static char devany[] = SIO_DEVANY;
30d07fece6Sratchov 	struct sioctl_hdl *hdl;
31d07fece6Sratchov 
32d07fece6Sratchov #ifdef DEBUG
33d07fece6Sratchov 	_sndio_debug_init();
34d07fece6Sratchov #endif
35d07fece6Sratchov 	if (str == NULL) /* backward compat */
36d07fece6Sratchov 		str = devany;
37d07fece6Sratchov 	if (strcmp(str, devany) == 0 && !issetugid()) {
38d07fece6Sratchov 		str = getenv("AUDIODEVICE");
39d07fece6Sratchov 		if (str == NULL)
40d07fece6Sratchov 			str = devany;
41d07fece6Sratchov 	}
42d07fece6Sratchov 	if (strcmp(str, devany) == 0) {
43*36355b88Sratchov 		hdl = _sioctl_aucat_open("snd/default", mode, nbio);
44d07fece6Sratchov 		if (hdl != NULL)
45d07fece6Sratchov 			return hdl;
46d07fece6Sratchov 		return _sioctl_sun_open("rsnd/0", mode, nbio);
47d07fece6Sratchov 	}
48d07fece6Sratchov 	if (_sndio_parsetype(str, "snd"))
49d07fece6Sratchov 		return _sioctl_aucat_open(str, mode, nbio);
50d07fece6Sratchov 	if (_sndio_parsetype(str, "rsnd"))
51d07fece6Sratchov 		return _sioctl_sun_open(str, mode, nbio);
52d07fece6Sratchov 	DPRINTF("sioctl_open: %s: unknown device type\n", str);
53d07fece6Sratchov 	return NULL;
54d07fece6Sratchov }
55d07fece6Sratchov 
56d07fece6Sratchov void
_sioctl_create(struct sioctl_hdl * hdl,struct sioctl_ops * ops,unsigned int mode,int nbio)57d07fece6Sratchov _sioctl_create(struct sioctl_hdl *hdl, struct sioctl_ops *ops,
58d07fece6Sratchov     unsigned int mode, int nbio)
59d07fece6Sratchov {
60d07fece6Sratchov 	hdl->ops = ops;
61d07fece6Sratchov 	hdl->mode = mode;
62d07fece6Sratchov 	hdl->nbio = nbio;
63d07fece6Sratchov 	hdl->eof = 0;
64d07fece6Sratchov 	hdl->ctl_cb = NULL;
65d07fece6Sratchov }
66d07fece6Sratchov 
67d07fece6Sratchov int
_sioctl_psleep(struct sioctl_hdl * hdl,int event)68d07fece6Sratchov _sioctl_psleep(struct sioctl_hdl *hdl, int event)
69d07fece6Sratchov {
70d07fece6Sratchov 	struct pollfd pfds[SIOCTL_MAXNFDS];
71d07fece6Sratchov 	int revents, nfds;
72d07fece6Sratchov 
73d07fece6Sratchov 	for (;;) {
74d07fece6Sratchov 		nfds = sioctl_pollfd(hdl, pfds, event);
75d07fece6Sratchov 		if (nfds == 0)
76d07fece6Sratchov 			return 0;
77d07fece6Sratchov 		while (poll(pfds, nfds, -1) < 0) {
78d07fece6Sratchov 			if (errno == EINTR)
79d07fece6Sratchov 				continue;
80d07fece6Sratchov 			DPERROR("sioctl_psleep: poll");
81d07fece6Sratchov 			hdl->eof = 1;
82d07fece6Sratchov 			return 0;
83d07fece6Sratchov 		}
84d07fece6Sratchov 		revents = sioctl_revents(hdl, pfds);
85d07fece6Sratchov 		if (revents & POLLHUP) {
86d07fece6Sratchov 			DPRINTF("sioctl_psleep: hang-up\n");
87d07fece6Sratchov 			return 0;
88d07fece6Sratchov 		}
89d07fece6Sratchov 		if (event == 0 || (revents & event))
90d07fece6Sratchov 			break;
91d07fece6Sratchov 	}
92d07fece6Sratchov 	return 1;
93d07fece6Sratchov }
94d07fece6Sratchov 
95d07fece6Sratchov void
sioctl_close(struct sioctl_hdl * hdl)96d07fece6Sratchov sioctl_close(struct sioctl_hdl *hdl)
97d07fece6Sratchov {
98d07fece6Sratchov 	hdl->ops->close(hdl);
99d07fece6Sratchov }
100d07fece6Sratchov 
101d07fece6Sratchov int
sioctl_nfds(struct sioctl_hdl * hdl)102d07fece6Sratchov sioctl_nfds(struct sioctl_hdl *hdl)
103d07fece6Sratchov {
104d07fece6Sratchov 	return hdl->ops->nfds(hdl);
105d07fece6Sratchov }
106d07fece6Sratchov 
107d07fece6Sratchov int
sioctl_pollfd(struct sioctl_hdl * hdl,struct pollfd * pfd,int events)108d07fece6Sratchov sioctl_pollfd(struct sioctl_hdl *hdl, struct pollfd *pfd, int events)
109d07fece6Sratchov {
110d07fece6Sratchov 	if (hdl->eof)
111d07fece6Sratchov 		return 0;
112d07fece6Sratchov 	return hdl->ops->pollfd(hdl, pfd, events);
113d07fece6Sratchov }
114d07fece6Sratchov 
115d07fece6Sratchov int
sioctl_revents(struct sioctl_hdl * hdl,struct pollfd * pfd)116d07fece6Sratchov sioctl_revents(struct sioctl_hdl *hdl, struct pollfd *pfd)
117d07fece6Sratchov {
118d07fece6Sratchov 	if (hdl->eof)
119d07fece6Sratchov 		return POLLHUP;
120d07fece6Sratchov 	return hdl->ops->revents(hdl, pfd);
121d07fece6Sratchov }
122d07fece6Sratchov 
123d07fece6Sratchov int
sioctl_eof(struct sioctl_hdl * hdl)124d07fece6Sratchov sioctl_eof(struct sioctl_hdl *hdl)
125d07fece6Sratchov {
126d07fece6Sratchov 	return hdl->eof;
127d07fece6Sratchov }
128d07fece6Sratchov 
129d07fece6Sratchov int
sioctl_ondesc(struct sioctl_hdl * hdl,void (* cb)(void *,struct sioctl_desc *,int),void * arg)130d07fece6Sratchov sioctl_ondesc(struct sioctl_hdl *hdl,
131d07fece6Sratchov     void (*cb)(void *, struct sioctl_desc *, int), void *arg)
132d07fece6Sratchov {
133d07fece6Sratchov 	hdl->desc_cb = cb;
134d07fece6Sratchov 	hdl->desc_arg = arg;
135d07fece6Sratchov 	return hdl->ops->ondesc(hdl);
136d07fece6Sratchov }
137d07fece6Sratchov 
138d07fece6Sratchov int
sioctl_onval(struct sioctl_hdl * hdl,void (* cb)(void *,unsigned int,unsigned int),void * arg)139d07fece6Sratchov sioctl_onval(struct sioctl_hdl *hdl,
140d07fece6Sratchov     void (*cb)(void *, unsigned int, unsigned int), void *arg)
141d07fece6Sratchov {
142d07fece6Sratchov 	hdl->ctl_cb = cb;
143d07fece6Sratchov 	hdl->ctl_arg = arg;
144d07fece6Sratchov 	return hdl->ops->onctl(hdl);
145d07fece6Sratchov }
146d07fece6Sratchov 
147d07fece6Sratchov void
_sioctl_ondesc_cb(struct sioctl_hdl * hdl,struct sioctl_desc * desc,unsigned int val)148d07fece6Sratchov _sioctl_ondesc_cb(struct sioctl_hdl *hdl,
149d07fece6Sratchov     struct sioctl_desc *desc, unsigned int val)
150d07fece6Sratchov {
151d07fece6Sratchov 	if (desc) {
152d07fece6Sratchov 		DPRINTF("_sioctl_ondesc_cb: %u -> %s[%d].%s=%s[%d]:%d\n",
153d07fece6Sratchov 		    desc->addr,
154d07fece6Sratchov 		    desc->node0.name, desc->node0.unit,
155d07fece6Sratchov 		    desc->func,
156d07fece6Sratchov 		    desc->node1.name, desc->node1.unit,
157d07fece6Sratchov 		    val);
158d07fece6Sratchov 	}
159d07fece6Sratchov 	if (hdl->desc_cb)
160d07fece6Sratchov 		hdl->desc_cb(hdl->desc_arg, desc, val);
161d07fece6Sratchov }
162d07fece6Sratchov 
163d07fece6Sratchov void
_sioctl_onval_cb(struct sioctl_hdl * hdl,unsigned int addr,unsigned int val)164d07fece6Sratchov _sioctl_onval_cb(struct sioctl_hdl *hdl, unsigned int addr, unsigned int val)
165d07fece6Sratchov {
166d07fece6Sratchov 	DPRINTF("_sioctl_onval_cb: %u -> %u\n", addr, val);
167d07fece6Sratchov 	if (hdl->ctl_cb)
168d07fece6Sratchov 		hdl->ctl_cb(hdl->ctl_arg, addr, val);
169d07fece6Sratchov }
170d07fece6Sratchov 
171d07fece6Sratchov int
sioctl_setval(struct sioctl_hdl * hdl,unsigned int addr,unsigned int val)172d07fece6Sratchov sioctl_setval(struct sioctl_hdl *hdl, unsigned int addr, unsigned int val)
173d07fece6Sratchov {
174d07fece6Sratchov 	if (!(hdl->mode & SIOCTL_WRITE))
175d07fece6Sratchov 		return 0;
176d07fece6Sratchov 	return hdl->ops->setctl(hdl, addr, val);
177d07fece6Sratchov }
178