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
26struct sioctl_hdl *
27sioctl_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
56void
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
67int
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
95void
96sioctl_close(struct sioctl_hdl *hdl)
97{
98	hdl->ops->close(hdl);
99}
100
101int
102sioctl_nfds(struct sioctl_hdl *hdl)
103{
104	return hdl->ops->nfds(hdl);
105}
106
107int
108sioctl_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
115int
116sioctl_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
123int
124sioctl_eof(struct sioctl_hdl *hdl)
125{
126	return hdl->eof;
127}
128
129int
130sioctl_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
138int
139sioctl_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
147void
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
163void
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
171int
172sioctl_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