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