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 *
sioctl_open(const char * str,unsigned int mode,int nbio)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
_sioctl_create(struct sioctl_hdl * hdl,struct sioctl_ops * ops,unsigned int mode,int nbio)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
_sioctl_psleep(struct sioctl_hdl * hdl,int event)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
sioctl_close(struct sioctl_hdl * hdl)96 sioctl_close(struct sioctl_hdl *hdl)
97 {
98 hdl->ops->close(hdl);
99 }
100
101 int
sioctl_nfds(struct sioctl_hdl * hdl)102 sioctl_nfds(struct sioctl_hdl *hdl)
103 {
104 return hdl->ops->nfds(hdl);
105 }
106
107 int
sioctl_pollfd(struct sioctl_hdl * hdl,struct pollfd * pfd,int events)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
sioctl_revents(struct sioctl_hdl * hdl,struct pollfd * pfd)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
sioctl_eof(struct sioctl_hdl * hdl)124 sioctl_eof(struct sioctl_hdl *hdl)
125 {
126 return hdl->eof;
127 }
128
129 int
sioctl_ondesc(struct sioctl_hdl * hdl,void (* cb)(void *,struct sioctl_desc *,int),void * arg)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
sioctl_onval(struct sioctl_hdl * hdl,void (* cb)(void *,unsigned int,unsigned int),void * arg)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
_sioctl_ondesc_cb(struct sioctl_hdl * hdl,struct sioctl_desc * desc,unsigned int val)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
_sioctl_onval_cb(struct sioctl_hdl * hdl,unsigned int addr,unsigned int val)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
sioctl_setval(struct sioctl_hdl * hdl,unsigned int addr,unsigned int val)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