1*ec8a3410Sratchov /* $OpenBSD: sio_aucat.c,v 1.21 2022/04/29 08:30:48 ratchov Exp $ */
2b041ccb2Sratchov /*
3b041ccb2Sratchov * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4b041ccb2Sratchov *
5b041ccb2Sratchov * Permission to use, copy, modify, and distribute this software for any
6b041ccb2Sratchov * purpose with or without fee is hereby granted, provided that the above
7b041ccb2Sratchov * copyright notice and this permission notice appear in all copies.
8b041ccb2Sratchov *
9b041ccb2Sratchov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10b041ccb2Sratchov * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11b041ccb2Sratchov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12b041ccb2Sratchov * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13b041ccb2Sratchov * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14b041ccb2Sratchov * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15b041ccb2Sratchov * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16b041ccb2Sratchov */
17b041ccb2Sratchov
18b041ccb2Sratchov #include <sys/types.h>
19b041ccb2Sratchov #include <sys/socket.h>
20b041ccb2Sratchov #include <sys/un.h>
217ceac65eSratchov #include <netinet/in.h>
22b041ccb2Sratchov
23b041ccb2Sratchov #include <errno.h>
24b041ccb2Sratchov #include <fcntl.h>
25b041ccb2Sratchov #include <poll.h>
26b041ccb2Sratchov #include <stdio.h>
27b041ccb2Sratchov #include <stdlib.h>
28b041ccb2Sratchov #include <string.h>
29b041ccb2Sratchov #include <unistd.h>
30b041ccb2Sratchov
3182bfc72bSratchov #include "aucat.h"
3282bfc72bSratchov #include "debug.h"
33b041ccb2Sratchov #include "sio_priv.h"
34b041ccb2Sratchov
35b041ccb2Sratchov struct sio_aucat_hdl {
36b041ccb2Sratchov struct sio_hdl sio;
3782bfc72bSratchov struct aucat aucat;
387207b069Sratchov unsigned int rbpf, wbpf; /* read and write bytes-per-frame */
39b041ccb2Sratchov int events; /* events the user requested */
407207b069Sratchov unsigned int curvol, reqvol; /* current and requested volume */
41b041ccb2Sratchov int delta; /* some of received deltas */
4282bfc72bSratchov #define PSTATE_INIT 0
4382bfc72bSratchov #define PSTATE_RUN 1
4482bfc72bSratchov int pstate;
45443bd1b2Sratchov size_t round; /* write block size */
46443bd1b2Sratchov size_t walign; /* align write packets size to this */
47b041ccb2Sratchov };
48b041ccb2Sratchov
49b041ccb2Sratchov static void sio_aucat_close(struct sio_hdl *);
50b041ccb2Sratchov static int sio_aucat_start(struct sio_hdl *);
51b041ccb2Sratchov static int sio_aucat_stop(struct sio_hdl *);
52*ec8a3410Sratchov static int sio_aucat_flush(struct sio_hdl *);
53b041ccb2Sratchov static int sio_aucat_setpar(struct sio_hdl *, struct sio_par *);
54b041ccb2Sratchov static int sio_aucat_getpar(struct sio_hdl *, struct sio_par *);
55b041ccb2Sratchov static int sio_aucat_getcap(struct sio_hdl *, struct sio_cap *);
56b041ccb2Sratchov static size_t sio_aucat_read(struct sio_hdl *, void *, size_t);
57b041ccb2Sratchov static size_t sio_aucat_write(struct sio_hdl *, const void *, size_t);
58b041ccb2Sratchov static int sio_aucat_nfds(struct sio_hdl *);
59b041ccb2Sratchov static int sio_aucat_pollfd(struct sio_hdl *, struct pollfd *, int);
60b041ccb2Sratchov static int sio_aucat_revents(struct sio_hdl *, struct pollfd *);
617207b069Sratchov static int sio_aucat_setvol(struct sio_hdl *, unsigned int);
62b041ccb2Sratchov static void sio_aucat_getvol(struct sio_hdl *);
63b041ccb2Sratchov
64b041ccb2Sratchov static struct sio_ops sio_aucat_ops = {
65b041ccb2Sratchov sio_aucat_close,
66b041ccb2Sratchov sio_aucat_setpar,
67b041ccb2Sratchov sio_aucat_getpar,
68b041ccb2Sratchov sio_aucat_getcap,
69b041ccb2Sratchov sio_aucat_write,
70b041ccb2Sratchov sio_aucat_read,
71b041ccb2Sratchov sio_aucat_start,
72b041ccb2Sratchov sio_aucat_stop,
73*ec8a3410Sratchov sio_aucat_flush,
74b041ccb2Sratchov sio_aucat_nfds,
75b041ccb2Sratchov sio_aucat_pollfd,
76b041ccb2Sratchov sio_aucat_revents,
77b041ccb2Sratchov sio_aucat_setvol,
78b041ccb2Sratchov sio_aucat_getvol
79b041ccb2Sratchov };
80b041ccb2Sratchov
81b041ccb2Sratchov /*
82b041ccb2Sratchov * execute the next message, return 0 if blocked
83b041ccb2Sratchov */
84b041ccb2Sratchov static int
sio_aucat_runmsg(struct sio_aucat_hdl * hdl)85b041ccb2Sratchov sio_aucat_runmsg(struct sio_aucat_hdl *hdl)
86b041ccb2Sratchov {
87b5fec221Sratchov int delta;
887207b069Sratchov unsigned int size, ctl;
89b5fec221Sratchov
90d418f94bSratchov if (!_aucat_rmsg(&hdl->aucat, &hdl->sio.eof))
91b041ccb2Sratchov return 0;
92b5fec221Sratchov switch (ntohl(hdl->aucat.rmsg.cmd)) {
93b041ccb2Sratchov case AMSG_DATA:
94b5fec221Sratchov size = ntohl(hdl->aucat.rmsg.u.data.size);
95b5fec221Sratchov if (size == 0 || size % hdl->rbpf) {
96b041ccb2Sratchov DPRINTF("sio_aucat_runmsg: bad data message\n");
97b041ccb2Sratchov hdl->sio.eof = 1;
98b041ccb2Sratchov return 0;
99b041ccb2Sratchov }
10000b79159Sratchov DPRINTFN(3, "aucat: data(%d)\n", size);
10182bfc72bSratchov return 1;
1025ffd5747Sratchov case AMSG_FLOWCTL:
103b5fec221Sratchov delta = ntohl(hdl->aucat.rmsg.u.ts.delta);
1045ffd5747Sratchov hdl->aucat.maxwrite += delta * (int)hdl->wbpf;
10500b79159Sratchov DPRINTFN(3, "aucat: flowctl(%d), maxwrite = %d\n",
1065ffd5747Sratchov delta, hdl->aucat.maxwrite);
107b041ccb2Sratchov break;
108b041ccb2Sratchov case AMSG_MOVE:
109b5fec221Sratchov delta = ntohl(hdl->aucat.rmsg.u.ts.delta);
110b5fec221Sratchov hdl->delta += delta;
11100b79159Sratchov DPRINTFN(3, "aucat: move(%d), delta = %d, maxwrite = %d\n",
1125ffd5747Sratchov delta, hdl->delta, hdl->aucat.maxwrite);
113b041ccb2Sratchov if (hdl->delta >= 0) {
114d418f94bSratchov _sio_onmove_cb(&hdl->sio, hdl->delta);
115b041ccb2Sratchov hdl->delta = 0;
116b041ccb2Sratchov }
117b041ccb2Sratchov break;
118b041ccb2Sratchov case AMSG_SETVOL:
119b5fec221Sratchov ctl = ntohl(hdl->aucat.rmsg.u.vol.ctl);
120b5fec221Sratchov hdl->curvol = hdl->reqvol = ctl;
12100b79159Sratchov DPRINTFN(3, "aucat: setvol(%d)\n", ctl);
122d418f94bSratchov _sio_onvol_cb(&hdl->sio, ctl);
123b041ccb2Sratchov break;
12482bfc72bSratchov case AMSG_STOP:
12500b79159Sratchov DPRINTFN(3, "aucat: stop()\n");
12682bfc72bSratchov hdl->pstate = PSTATE_INIT;
127b041ccb2Sratchov break;
128b041ccb2Sratchov default:
129e8cc0bfdSratchov DPRINTF("sio_aucat_runmsg: unhandled message %u\n",
130e8cc0bfdSratchov hdl->aucat.rmsg.cmd);
131b041ccb2Sratchov hdl->sio.eof = 1;
132b041ccb2Sratchov return 0;
133b041ccb2Sratchov }
13482bfc72bSratchov hdl->aucat.rstate = RSTATE_MSG;
13582bfc72bSratchov hdl->aucat.rtodo = sizeof(struct amsg);
136b041ccb2Sratchov return 1;
137b041ccb2Sratchov }
138b041ccb2Sratchov
13982bfc72bSratchov static int
sio_aucat_buildmsg(struct sio_aucat_hdl * hdl)14082bfc72bSratchov sio_aucat_buildmsg(struct sio_aucat_hdl *hdl)
14182bfc72bSratchov {
14282bfc72bSratchov if (hdl->curvol != hdl->reqvol) {
14382bfc72bSratchov hdl->aucat.wstate = WSTATE_MSG;
14482bfc72bSratchov hdl->aucat.wtodo = sizeof(struct amsg);
145b5fec221Sratchov hdl->aucat.wmsg.cmd = htonl(AMSG_SETVOL);
146b5fec221Sratchov hdl->aucat.wmsg.u.vol.ctl = htonl(hdl->reqvol);
14782bfc72bSratchov hdl->curvol = hdl->reqvol;
148d418f94bSratchov return _aucat_wmsg(&hdl->aucat, &hdl->sio.eof);
14982bfc72bSratchov }
15082bfc72bSratchov return 0;
15182bfc72bSratchov }
15282bfc72bSratchov
153b041ccb2Sratchov struct sio_hdl *
_sio_aucat_open(const char * str,unsigned int mode,int nbio)154d418f94bSratchov _sio_aucat_open(const char *str, unsigned int mode, int nbio)
155b041ccb2Sratchov {
156b041ccb2Sratchov struct sio_aucat_hdl *hdl;
157b041ccb2Sratchov
158b041ccb2Sratchov hdl = malloc(sizeof(struct sio_aucat_hdl));
159b041ccb2Sratchov if (hdl == NULL)
160b041ccb2Sratchov return NULL;
161163486f8Sratchov if (!_aucat_open(&hdl->aucat, str, mode)) {
162b041ccb2Sratchov free(hdl);
163b041ccb2Sratchov return NULL;
164b041ccb2Sratchov }
165d418f94bSratchov _sio_create(&hdl->sio, &sio_aucat_ops, mode, nbio);
16682bfc72bSratchov hdl->curvol = SIO_MAXVOL;
16782bfc72bSratchov hdl->reqvol = SIO_MAXVOL;
16882bfc72bSratchov hdl->pstate = PSTATE_INIT;
169443bd1b2Sratchov hdl->round = 0xdeadbeef;
170443bd1b2Sratchov hdl->walign = 0xdeadbeef;
17182bfc72bSratchov return (struct sio_hdl *)hdl;
17282bfc72bSratchov }
173b041ccb2Sratchov
174b041ccb2Sratchov static void
sio_aucat_close(struct sio_hdl * sh)175b041ccb2Sratchov sio_aucat_close(struct sio_hdl *sh)
176b041ccb2Sratchov {
177b041ccb2Sratchov struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
178b041ccb2Sratchov
179b041ccb2Sratchov if (!hdl->sio.eof && hdl->sio.started)
180b041ccb2Sratchov (void)sio_aucat_stop(&hdl->sio);
181d418f94bSratchov _aucat_close(&hdl->aucat, hdl->sio.eof);
182b041ccb2Sratchov free(hdl);
183b041ccb2Sratchov }
184b041ccb2Sratchov
185b041ccb2Sratchov static int
sio_aucat_start(struct sio_hdl * sh)186b041ccb2Sratchov sio_aucat_start(struct sio_hdl *sh)
187b041ccb2Sratchov {
188b041ccb2Sratchov struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
189b041ccb2Sratchov
190e6877796Sratchov hdl->wbpf = hdl->sio.par.bps * hdl->sio.par.pchan;
191e6877796Sratchov hdl->rbpf = hdl->sio.par.bps * hdl->sio.par.rchan;
19207e4e28eSratchov hdl->aucat.maxwrite = 0;
193e6877796Sratchov hdl->round = hdl->sio.par.round;
194b041ccb2Sratchov hdl->delta = 0;
195e791f9efSratchov DPRINTFN(2, "aucat: start, maxwrite = %d\n", hdl->aucat.maxwrite);
196b041ccb2Sratchov
19782bfc72bSratchov AMSG_INIT(&hdl->aucat.wmsg);
198b5fec221Sratchov hdl->aucat.wmsg.cmd = htonl(AMSG_START);
19982bfc72bSratchov hdl->aucat.wtodo = sizeof(struct amsg);
200d418f94bSratchov if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
201b041ccb2Sratchov return 0;
20282bfc72bSratchov hdl->aucat.rstate = RSTATE_MSG;
20382bfc72bSratchov hdl->aucat.rtodo = sizeof(struct amsg);
204d418f94bSratchov if (!_aucat_setfl(&hdl->aucat, 1, &hdl->sio.eof))
205b041ccb2Sratchov return 0;
206443bd1b2Sratchov hdl->walign = hdl->round * hdl->wbpf;
20782bfc72bSratchov hdl->pstate = PSTATE_RUN;
208b041ccb2Sratchov return 1;
209b041ccb2Sratchov }
210b041ccb2Sratchov
211b041ccb2Sratchov static int
sio_aucat_drain(struct sio_hdl * sh,int drain)212*ec8a3410Sratchov sio_aucat_drain(struct sio_hdl *sh, int drain)
213b041ccb2Sratchov {
214b041ccb2Sratchov #define ZERO_MAX 0x400
215b041ccb2Sratchov static unsigned char zero[ZERO_MAX];
216b041ccb2Sratchov struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
2177207b069Sratchov unsigned int n, count;
218b041ccb2Sratchov
219d418f94bSratchov if (!_aucat_setfl(&hdl->aucat, 0, &hdl->sio.eof))
220b041ccb2Sratchov return 0;
221b041ccb2Sratchov /*
222b041ccb2Sratchov * complete message or data block in progress
223b041ccb2Sratchov */
22482bfc72bSratchov if (hdl->aucat.wstate == WSTATE_MSG) {
225d418f94bSratchov if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
226b041ccb2Sratchov return 0;
227b041ccb2Sratchov }
22882bfc72bSratchov if (hdl->aucat.wstate == WSTATE_DATA) {
2295ffd5747Sratchov hdl->aucat.maxwrite = hdl->aucat.wtodo;
23082bfc72bSratchov while (hdl->aucat.wstate != WSTATE_IDLE) {
23182bfc72bSratchov count = hdl->aucat.wtodo;
232b041ccb2Sratchov if (count > ZERO_MAX)
233b041ccb2Sratchov count = ZERO_MAX;
234b041ccb2Sratchov n = sio_aucat_write(&hdl->sio, zero, count);
235b041ccb2Sratchov if (n == 0)
236b041ccb2Sratchov return 0;
237b041ccb2Sratchov }
238b041ccb2Sratchov }
239b041ccb2Sratchov
240b041ccb2Sratchov /*
241b041ccb2Sratchov * send stop message
242b041ccb2Sratchov */
24382bfc72bSratchov AMSG_INIT(&hdl->aucat.wmsg);
244b5fec221Sratchov hdl->aucat.wmsg.cmd = htonl(AMSG_STOP);
245*ec8a3410Sratchov hdl->aucat.wmsg.u.stop.drain = drain;
24682bfc72bSratchov hdl->aucat.wtodo = sizeof(struct amsg);
247d418f94bSratchov if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
248b041ccb2Sratchov return 0;
249b041ccb2Sratchov
250b041ccb2Sratchov /*
251b041ccb2Sratchov * wait for the STOP ACK
252b041ccb2Sratchov */
25382bfc72bSratchov while (hdl->pstate != PSTATE_INIT) {
25482bfc72bSratchov switch (hdl->aucat.rstate) {
25582bfc72bSratchov case RSTATE_MSG:
256b041ccb2Sratchov if (!sio_aucat_runmsg(hdl))
257b041ccb2Sratchov return 0;
258b041ccb2Sratchov break;
25982bfc72bSratchov case RSTATE_DATA:
260b041ccb2Sratchov if (!sio_aucat_read(&hdl->sio, zero, ZERO_MAX))
261b041ccb2Sratchov return 0;
262b041ccb2Sratchov break;
263b041ccb2Sratchov }
264b041ccb2Sratchov }
265b041ccb2Sratchov return 1;
266b041ccb2Sratchov }
267b041ccb2Sratchov
268b041ccb2Sratchov static int
sio_aucat_stop(struct sio_hdl * sh)269*ec8a3410Sratchov sio_aucat_stop(struct sio_hdl *sh)
270*ec8a3410Sratchov {
271*ec8a3410Sratchov return sio_aucat_drain(sh, 1);
272*ec8a3410Sratchov }
273*ec8a3410Sratchov
274*ec8a3410Sratchov static int
sio_aucat_flush(struct sio_hdl * sh)275*ec8a3410Sratchov sio_aucat_flush(struct sio_hdl *sh)
276*ec8a3410Sratchov {
277*ec8a3410Sratchov return sio_aucat_drain(sh, 0);
278*ec8a3410Sratchov }
279*ec8a3410Sratchov
280*ec8a3410Sratchov static int
sio_aucat_setpar(struct sio_hdl * sh,struct sio_par * par)281b041ccb2Sratchov sio_aucat_setpar(struct sio_hdl *sh, struct sio_par *par)
282b041ccb2Sratchov {
283b041ccb2Sratchov struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
284b041ccb2Sratchov
28582bfc72bSratchov AMSG_INIT(&hdl->aucat.wmsg);
286b5fec221Sratchov hdl->aucat.wmsg.cmd = htonl(AMSG_SETPAR);
28782bfc72bSratchov hdl->aucat.wmsg.u.par.bits = par->bits;
28882bfc72bSratchov hdl->aucat.wmsg.u.par.bps = par->bps;
28982bfc72bSratchov hdl->aucat.wmsg.u.par.sig = par->sig;
29082bfc72bSratchov hdl->aucat.wmsg.u.par.le = par->le;
29182bfc72bSratchov hdl->aucat.wmsg.u.par.msb = par->msb;
292b5fec221Sratchov hdl->aucat.wmsg.u.par.rate = htonl(par->rate);
293b5fec221Sratchov hdl->aucat.wmsg.u.par.appbufsz = htonl(par->appbufsz);
29482bfc72bSratchov hdl->aucat.wmsg.u.par.xrun = par->xrun;
295b041ccb2Sratchov if (hdl->sio.mode & SIO_REC)
296b5fec221Sratchov hdl->aucat.wmsg.u.par.rchan = htons(par->rchan);
297b041ccb2Sratchov if (hdl->sio.mode & SIO_PLAY)
298b5fec221Sratchov hdl->aucat.wmsg.u.par.pchan = htons(par->pchan);
29982bfc72bSratchov hdl->aucat.wtodo = sizeof(struct amsg);
300d418f94bSratchov if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
301b041ccb2Sratchov return 0;
302b041ccb2Sratchov return 1;
303b041ccb2Sratchov }
304b041ccb2Sratchov
305b041ccb2Sratchov static int
sio_aucat_getpar(struct sio_hdl * sh,struct sio_par * par)306b041ccb2Sratchov sio_aucat_getpar(struct sio_hdl *sh, struct sio_par *par)
307b041ccb2Sratchov {
308b041ccb2Sratchov struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
309b041ccb2Sratchov
31082bfc72bSratchov AMSG_INIT(&hdl->aucat.wmsg);
311b5fec221Sratchov hdl->aucat.wmsg.cmd = htonl(AMSG_GETPAR);
31282bfc72bSratchov hdl->aucat.wtodo = sizeof(struct amsg);
313d418f94bSratchov if (!_aucat_wmsg(&hdl->aucat, &hdl->sio.eof))
314b041ccb2Sratchov return 0;
31582bfc72bSratchov hdl->aucat.rtodo = sizeof(struct amsg);
316d418f94bSratchov if (!_aucat_rmsg(&hdl->aucat, &hdl->sio.eof))
317b041ccb2Sratchov return 0;
318b5fec221Sratchov if (ntohl(hdl->aucat.rmsg.cmd) != AMSG_GETPAR) {
319b041ccb2Sratchov DPRINTF("sio_aucat_getpar: protocol err\n");
320b041ccb2Sratchov hdl->sio.eof = 1;
321b041ccb2Sratchov return 0;
322b041ccb2Sratchov }
32382bfc72bSratchov par->bits = hdl->aucat.rmsg.u.par.bits;
32482bfc72bSratchov par->bps = hdl->aucat.rmsg.u.par.bps;
32582bfc72bSratchov par->sig = hdl->aucat.rmsg.u.par.sig;
32682bfc72bSratchov par->le = hdl->aucat.rmsg.u.par.le;
32782bfc72bSratchov par->msb = hdl->aucat.rmsg.u.par.msb;
328b5fec221Sratchov par->rate = ntohl(hdl->aucat.rmsg.u.par.rate);
329b5fec221Sratchov par->bufsz = ntohl(hdl->aucat.rmsg.u.par.bufsz);
330b5fec221Sratchov par->appbufsz = ntohl(hdl->aucat.rmsg.u.par.appbufsz);
33182bfc72bSratchov par->xrun = hdl->aucat.rmsg.u.par.xrun;
332b5fec221Sratchov par->round = ntohl(hdl->aucat.rmsg.u.par.round);
333b041ccb2Sratchov if (hdl->sio.mode & SIO_PLAY)
334b5fec221Sratchov par->pchan = ntohs(hdl->aucat.rmsg.u.par.pchan);
335b041ccb2Sratchov if (hdl->sio.mode & SIO_REC)
336b5fec221Sratchov par->rchan = ntohs(hdl->aucat.rmsg.u.par.rchan);
337b041ccb2Sratchov return 1;
338b041ccb2Sratchov }
339b041ccb2Sratchov
340b041ccb2Sratchov static int
sio_aucat_getcap(struct sio_hdl * sh,struct sio_cap * cap)341b041ccb2Sratchov sio_aucat_getcap(struct sio_hdl *sh, struct sio_cap *cap)
342b041ccb2Sratchov {
3437207b069Sratchov unsigned int i, bps, le, sig, chan, rindex, rmult;
3447207b069Sratchov static unsigned int rates[] = { 8000, 11025, 12000 };
345b041ccb2Sratchov
346b041ccb2Sratchov bps = 1;
347b041ccb2Sratchov sig = le = 0;
348b041ccb2Sratchov cap->confs[0].enc = 0;
349b041ccb2Sratchov for (i = 0; i < SIO_NENC; i++) {
350b041ccb2Sratchov if (bps > 4)
351b041ccb2Sratchov break;
352b041ccb2Sratchov cap->confs[0].enc |= 1 << i;
353b041ccb2Sratchov cap->enc[i].bits = bps == 4 ? 24 : bps * 8;
354b041ccb2Sratchov cap->enc[i].bps = bps;
355b041ccb2Sratchov cap->enc[i].sig = sig ^ 1;
356b041ccb2Sratchov cap->enc[i].le = bps > 1 ? le : SIO_LE_NATIVE;
357b041ccb2Sratchov cap->enc[i].msb = 1;
358b041ccb2Sratchov le++;
359b041ccb2Sratchov if (le > 1 || bps == 1) {
360b041ccb2Sratchov le = 0;
361b041ccb2Sratchov sig++;
362b041ccb2Sratchov }
363b041ccb2Sratchov if (sig > 1 || (le == 0 && bps > 1)) {
364b041ccb2Sratchov sig = 0;
365b041ccb2Sratchov bps++;
366b041ccb2Sratchov }
367b041ccb2Sratchov }
368b041ccb2Sratchov chan = 1;
369b041ccb2Sratchov cap->confs[0].rchan = 0;
370b041ccb2Sratchov for (i = 0; i < SIO_NCHAN; i++) {
371b041ccb2Sratchov if (chan > 16)
372b041ccb2Sratchov break;
373b041ccb2Sratchov cap->confs[0].rchan |= 1 << i;
374b041ccb2Sratchov cap->rchan[i] = chan;
375b041ccb2Sratchov if (chan >= 12) {
376b041ccb2Sratchov chan += 4;
377b041ccb2Sratchov } else if (chan >= 2) {
378b041ccb2Sratchov chan += 2;
379b041ccb2Sratchov } else
380b041ccb2Sratchov chan++;
381b041ccb2Sratchov }
382b041ccb2Sratchov chan = 1;
383b041ccb2Sratchov cap->confs[0].pchan = 0;
384b041ccb2Sratchov for (i = 0; i < SIO_NCHAN; i++) {
385b041ccb2Sratchov if (chan > 16)
386b041ccb2Sratchov break;
387b041ccb2Sratchov cap->confs[0].pchan |= 1 << i;
388b041ccb2Sratchov cap->pchan[i] = chan;
389b041ccb2Sratchov if (chan >= 12) {
390b041ccb2Sratchov chan += 4;
391b041ccb2Sratchov } else if (chan >= 2) {
392b041ccb2Sratchov chan += 2;
393b041ccb2Sratchov } else
394b041ccb2Sratchov chan++;
395b041ccb2Sratchov }
396b041ccb2Sratchov rindex = 0;
397b041ccb2Sratchov rmult = 1;
398b041ccb2Sratchov cap->confs[0].rate = 0;
399b041ccb2Sratchov for (i = 0; i < SIO_NRATE; i++) {
400b041ccb2Sratchov if (rmult >= 32)
401b041ccb2Sratchov break;
402b041ccb2Sratchov cap->rate[i] = rates[rindex] * rmult;
403b041ccb2Sratchov cap->confs[0].rate |= 1 << i;
404b041ccb2Sratchov rindex++;
4057207b069Sratchov if (rindex == sizeof(rates) / sizeof(unsigned int)) {
406b041ccb2Sratchov rindex = 0;
407b041ccb2Sratchov rmult *= 2;
408b041ccb2Sratchov }
409b041ccb2Sratchov }
410b041ccb2Sratchov cap->nconf = 1;
411b041ccb2Sratchov return 1;
412b041ccb2Sratchov }
413b041ccb2Sratchov
414b041ccb2Sratchov static size_t
sio_aucat_read(struct sio_hdl * sh,void * buf,size_t len)415b041ccb2Sratchov sio_aucat_read(struct sio_hdl *sh, void *buf, size_t len)
416b041ccb2Sratchov {
417b041ccb2Sratchov struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
418b041ccb2Sratchov
41982bfc72bSratchov while (hdl->aucat.rstate == RSTATE_MSG) {
420b041ccb2Sratchov if (!sio_aucat_runmsg(hdl))
421b041ccb2Sratchov return 0;
422b041ccb2Sratchov }
423d418f94bSratchov return _aucat_rdata(&hdl->aucat, buf, len, &hdl->sio.eof);
424b041ccb2Sratchov }
425b041ccb2Sratchov
426b041ccb2Sratchov static size_t
sio_aucat_write(struct sio_hdl * sh,const void * buf,size_t len)427b041ccb2Sratchov sio_aucat_write(struct sio_hdl *sh, const void *buf, size_t len)
428b041ccb2Sratchov {
429b041ccb2Sratchov struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
43082bfc72bSratchov size_t n;
431b041ccb2Sratchov
43282bfc72bSratchov while (hdl->aucat.wstate == WSTATE_IDLE) {
43382bfc72bSratchov if (!sio_aucat_buildmsg(hdl))
434b041ccb2Sratchov break;
435b041ccb2Sratchov }
4365ffd5747Sratchov if (len <= 0 || hdl->aucat.maxwrite <= 0)
437b041ccb2Sratchov return 0;
4385ffd5747Sratchov if (len > hdl->aucat.maxwrite)
4395ffd5747Sratchov len = hdl->aucat.maxwrite;
440443bd1b2Sratchov if (len > hdl->walign)
441443bd1b2Sratchov len = hdl->walign;
442d418f94bSratchov n = _aucat_wdata(&hdl->aucat, buf, len, hdl->wbpf, &hdl->sio.eof);
4435ffd5747Sratchov hdl->aucat.maxwrite -= n;
444443bd1b2Sratchov hdl->walign -= n;
445443bd1b2Sratchov if (hdl->walign == 0)
446443bd1b2Sratchov hdl->walign = hdl->round * hdl->wbpf;
447b041ccb2Sratchov return n;
448b041ccb2Sratchov }
449b041ccb2Sratchov
450b041ccb2Sratchov static int
sio_aucat_nfds(struct sio_hdl * hdl)451b041ccb2Sratchov sio_aucat_nfds(struct sio_hdl *hdl)
452b041ccb2Sratchov {
453b041ccb2Sratchov return 1;
454b041ccb2Sratchov }
455b041ccb2Sratchov
456b041ccb2Sratchov static int
sio_aucat_pollfd(struct sio_hdl * sh,struct pollfd * pfd,int events)457b041ccb2Sratchov sio_aucat_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events)
458b041ccb2Sratchov {
459b041ccb2Sratchov struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
460b041ccb2Sratchov
461b041ccb2Sratchov hdl->events = events;
4625ffd5747Sratchov if (hdl->aucat.maxwrite <= 0)
463b041ccb2Sratchov events &= ~POLLOUT;
464d418f94bSratchov return _aucat_pollfd(&hdl->aucat, pfd, events);
465b041ccb2Sratchov }
466b041ccb2Sratchov
467b041ccb2Sratchov static int
sio_aucat_revents(struct sio_hdl * sh,struct pollfd * pfd)468b041ccb2Sratchov sio_aucat_revents(struct sio_hdl *sh, struct pollfd *pfd)
469b041ccb2Sratchov {
470b041ccb2Sratchov struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
471b041ccb2Sratchov int revents = pfd->revents;
472b041ccb2Sratchov
473b041ccb2Sratchov if (revents & POLLIN) {
47482bfc72bSratchov while (hdl->aucat.rstate == RSTATE_MSG) {
47582bfc72bSratchov if (!sio_aucat_runmsg(hdl))
476b041ccb2Sratchov break;
477b041ccb2Sratchov }
47882bfc72bSratchov if (hdl->aucat.rstate != RSTATE_DATA)
47982bfc72bSratchov revents &= ~POLLIN;
480b041ccb2Sratchov }
481b041ccb2Sratchov if (revents & POLLOUT) {
4825ffd5747Sratchov if (hdl->aucat.maxwrite <= 0)
483b041ccb2Sratchov revents &= ~POLLOUT;
484b041ccb2Sratchov }
485b041ccb2Sratchov if (hdl->sio.eof)
486b041ccb2Sratchov return POLLHUP;
487e791f9efSratchov DPRINTFN(3, "sio_aucat_revents: %x\n", revents & hdl->events);
488b041ccb2Sratchov return revents & (hdl->events | POLLHUP);
489b041ccb2Sratchov }
490b041ccb2Sratchov
491b041ccb2Sratchov static int
sio_aucat_setvol(struct sio_hdl * sh,unsigned int vol)4927207b069Sratchov sio_aucat_setvol(struct sio_hdl *sh, unsigned int vol)
493b041ccb2Sratchov {
494b041ccb2Sratchov struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
495b041ccb2Sratchov
496b041ccb2Sratchov hdl->reqvol = vol;
497b041ccb2Sratchov return 1;
498b041ccb2Sratchov }
499b041ccb2Sratchov
500b041ccb2Sratchov static void
sio_aucat_getvol(struct sio_hdl * sh)501b041ccb2Sratchov sio_aucat_getvol(struct sio_hdl *sh)
502b041ccb2Sratchov {
503b041ccb2Sratchov struct sio_aucat_hdl *hdl = (struct sio_aucat_hdl *)sh;
504b041ccb2Sratchov
505d418f94bSratchov _sio_onvol_cb(&hdl->sio, hdl->reqvol);
506b041ccb2Sratchov return;
507b041ccb2Sratchov }
508