1 /*	$OpenBSD$	*/
2 /*
3  * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4  * Copyright (c) 2016 Tobias Kortkamp <t@tobik.me>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #ifdef USE_OSS
20 #include <sys/ioctl.h>
21 #include <sys/soundcard.h>
22 
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <poll.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 
31 #include "debug.h"
32 #include "sio_priv.h"
33 #include "bsd-compat.h"
34 
35 #define DEVPATH_PREFIX	"/dev/dsp"
36 #define DEVPATH_MAX 	(1 +		\
37 	sizeof(DEVPATH_PREFIX) - 1 +	\
38 	sizeof(int) * 3)
39 
40 struct sio_oss_fmt {
41 	int fmt;
42 	unsigned int bits;
43 	unsigned int bps;
44 	unsigned int sig;
45 	unsigned int le;
46 	unsigned int msb;
47 };
48 
49 static struct sio_oss_fmt formats[] = {
50 	/* See http://manuals.opensound.com/developer/formats.html.
51 	 * AFMT_{S8,U16}_* are marked as obsolete so are missing here.
52 	 */
53 
54 	/* le+msb not important */
55 	{ AFMT_U8,	8, 1, 0, 0, 0 },
56 	{ AFMT_U8,	8, 1, 0, 1, 0 },
57 	{ AFMT_U8,	8, 1, 0, 0, 1 },
58 	{ AFMT_U8,	8, 1, 0, 1, 1 },
59 
60 	/* msb not important */
61 	{ AFMT_S16_BE, 16, 2, 1, 0, 0 },
62 	{ AFMT_S16_BE, 16, 2, 1, 0, 1 },
63 	{ AFMT_S16_LE, 16, 2, 1, 1, 0 },
64 	{ AFMT_S16_LE, 16, 2, 1, 1, 1 },
65 	{ AFMT_S24_BE, 24, 3, 1, 0, 0 },
66 	{ AFMT_S24_BE, 24, 3, 1, 0, 1 },
67 	{ AFMT_S24_LE, 24, 3, 1, 1, 0 },
68 	{ AFMT_S24_LE, 24, 3, 1, 1, 1 },
69 	{ AFMT_U24_BE, 24, 3, 0, 0, 0 },
70 	{ AFMT_U24_BE, 24, 3, 0, 0, 1 },
71 	{ AFMT_U24_LE, 24, 3, 0, 1, 0 },
72 	{ AFMT_U24_LE, 24, 3, 0, 1, 1 },
73 
74 	{ AFMT_S32_BE, 32, 4, 1, 0, 1 },
75 	{ AFMT_S32_LE, 32, 4, 1, 1, 1 },
76 	{ AFMT_U32_BE, 32, 4, 0, 0, 1 },
77 	{ AFMT_U32_LE, 32, 4, 0, 1, 1 },
78 };
79 
80 struct sio_oss_hdl {
81 	struct sio_hdl sio;
82 	int fd;
83 	int idelta, odelta;
84 	int iused;
85 	int oused;
86 	int bpf;
87 
88 	int fmt;
89 	unsigned int rate;
90 	unsigned int chan;
91 	unsigned int appbufsz;
92 	unsigned int round;
93 
94 	int filling;
95 };
96 
97 static struct sio_hdl *sio_oss_fdopen(const char *, int, unsigned int, int);
98 static int sio_oss_getcap(struct sio_hdl *, struct sio_cap *);
99 static int sio_oss_getfd(const char *, unsigned int, int);
100 static int sio_oss_getpar(struct sio_hdl *, struct sio_par *);
101 static int sio_oss_nfds(struct sio_hdl *);
102 static int sio_oss_pollfd(struct sio_hdl *, struct pollfd *, int);
103 static int sio_oss_revents(struct sio_hdl *, struct pollfd *);
104 static int sio_oss_setpar(struct sio_hdl *, struct sio_par *);
105 static int sio_oss_start(struct sio_hdl *);
106 static int sio_oss_stop(struct sio_hdl *);
107 static int sio_oss_xrun(struct sio_oss_hdl *);
108 static size_t sio_oss_read(struct sio_hdl *, void *, size_t);
109 static size_t sio_oss_write(struct sio_hdl *, const void *, size_t);
110 static void sio_oss_close(struct sio_hdl *);
111 static int sio_oss_setvol(struct sio_hdl *, unsigned int);
112 static void sio_oss_getvol(struct sio_hdl *);
113 
114 static struct sio_ops sio_oss_ops = {
115 	sio_oss_close,
116 	sio_oss_setpar,
117 	sio_oss_getpar,
118 	sio_oss_getcap,
119 	sio_oss_write,
120 	sio_oss_read,
121 	sio_oss_start,
122 	sio_oss_stop,
123 	sio_oss_nfds,
124 	sio_oss_pollfd,
125 	sio_oss_revents,
126 	sio_oss_setvol,
127 	sio_oss_getvol,
128 };
129 
130 /*
131  * guess device capabilities
132  */
133 static int
sio_oss_getcap(struct sio_hdl * sh,struct sio_cap * cap)134 sio_oss_getcap(struct sio_hdl *sh, struct sio_cap *cap)
135 {
136 	/* From sound(4):
137 	 * The FreeBSD multichannel matrix processor supports up to 18
138 	 * interleaved channels, but the limit is currently set to 8
139 	 * channels (as commonly used for 7.1 surround sound).
140 	 */
141 	static unsigned int chans[] = {
142 		1, 2, 4, 6, 8
143 	};
144 	static unsigned int rates[] = {
145 		8000, 11025, 12000, 16000, 22050, 24000, 32000, 44100,
146 		48000, 64000, 88200, 96000, 192000
147 	};
148 	static int afmts[] = {
149 		AFMT_U8, AFMT_S16_LE, AFMT_S16_BE, AFMT_S24_LE, AFMT_U24_LE,
150 		AFMT_S32_LE, AFMT_U32_LE
151 	};
152 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
153 	unsigned int nconf = 0;
154 	unsigned int enc_map = 0, rchan_map = 0, pchan_map = 0, rate_map;
155 	unsigned int i, j, k, conf;
156 	int fmts;
157 
158 	if (ioctl(hdl->fd, SNDCTL_DSP_GETFMTS, &fmts) == -1) {
159 		DPERROR("sio_oss_getcap: GETFMTS");
160 		hdl->sio.eof = 1;
161 		return 0;
162 	}
163 
164 	/*
165 	 * get a subset of supported encodings
166 	 */
167 	for (j = 0, i = 0; i < sizeof(afmts) / sizeof(afmts[0]); i++) {
168 		if (fmts & afmts[i]) {
169 			for (k = 0; k < sizeof(formats) / sizeof(formats[0]); k++) {
170 				if (formats[k].fmt == afmts[i]) {
171 					cap->enc[j].sig = formats[k].sig;
172 					cap->enc[j].bits = formats[k].bits;
173 					cap->enc[j].bps = formats[k].bps;
174 					cap->enc[j].le = formats[k].le;
175 					cap->enc[j].msb = formats[k].msb;
176 					enc_map |= 1 << j;
177 					j++;
178 					break;
179 				}
180 			}
181 		}
182 	}
183 
184 	/*
185 	 * fill channels
186 	 */
187 	if (hdl->sio.mode & SIO_PLAY) {
188 		for (i = 0; i < sizeof(chans) / sizeof(chans[0]); i++) {
189 			cap->pchan[i] = chans[i];
190 			pchan_map |= (1 << i);
191 		}
192 	}
193 	if (hdl->sio.mode & SIO_REC) {
194 		for (i = 0; i < sizeof(chans) / sizeof(chans[0]); i++) {
195 			cap->rchan[i] = chans[i];
196 			rchan_map |= (1 << i);
197 		}
198 	}
199 
200 	/*
201 	 * fill rates
202 	 */
203 	for (j = 0; j < sizeof(formats) / sizeof(formats[0]); j++) {
204 		rate_map = 0;
205 		if ((enc_map & (1 << j)) == 0)
206 			continue;
207 		for (i = 0; i < sizeof(rates) / sizeof(rates[0]); i++) {
208 			cap->rate[i] = rates[i];
209 			rate_map |= (1 << i);
210 		}
211 		for (conf = 0; conf < nconf; conf++) {
212 			if (cap->confs[conf].rate == rate_map) {
213 				cap->confs[conf].enc |= (1 << j);
214 				break;
215 			}
216 		}
217 		if (conf == nconf) {
218 			if (nconf == SIO_NCONF)
219 				break;
220 			cap->confs[nconf].enc = (1 << j);
221 			cap->confs[nconf].pchan = pchan_map;
222 			cap->confs[nconf].rchan = rchan_map;
223 			cap->confs[nconf].rate = rate_map;
224 			nconf++;
225 		}
226 	}
227 	cap->nconf = nconf;
228 
229 	return 1;
230 }
231 
232 static int
sio_oss_getfd(const char * str,unsigned int mode,int nbio)233 sio_oss_getfd(const char *str, unsigned int mode, int nbio)
234 {
235 	const char *p;
236 	char path[DEVPATH_MAX];
237 	unsigned int devnum;
238 	int fd, flags, val;
239 	audio_buf_info bi;
240 
241 	p = _sndio_parsetype(str, "rsnd");
242 	if (p == NULL) {
243 		DPRINTF("sio_oss_getfd: %s: \"rsnd\" expected\n", str);
244 		return -1;
245 	}
246 	switch (*p) {
247 	case '/':
248 		p++;
249 		break;
250 	default:
251 		DPRINTF("sio_oss_getfd: %s: '/' expected\n", str);
252 		return -1;
253 	}
254 	if (strcmp(p, "default") == 0) {
255 		strlcpy(path, DEVPATH_PREFIX, sizeof(path));
256 	} else {
257 		p = _sndio_parsenum(p, &devnum, 255);
258 		if (p == NULL || *p != '\0') {
259 			DPRINTF("sio_sun_getfd: %s: number expected after '/'\n", str);
260 			return -1;
261 		}
262 		snprintf(path, sizeof(path), DEVPATH_PREFIX "%u", devnum);
263 	}
264 	if (mode == (SIO_PLAY | SIO_REC))
265 		flags = O_RDWR;
266 	else
267 		flags = (mode & SIO_PLAY) ? O_WRONLY : O_RDONLY;
268 	while ((fd = open(path, flags | O_NONBLOCK | O_CLOEXEC)) == -1) {
269 		if (errno == EINTR)
270 			continue;
271 		DPERROR(path);
272 		return -1;
273 	}
274 
275 	/*
276 	 * Check if the device supports playing/recording.
277 	 * Unfortunately, it's possible for devices to be opened RDWR
278 	 * even when they don't support playing/recording.
279 	 */
280 	if (mode & SIO_PLAY && ioctl(fd, SNDCTL_DSP_GETOSPACE, &bi) == -1) {
281 		close(fd);
282 		return -1;
283 	}
284 	if (mode & SIO_REC && ioctl(fd, SNDCTL_DSP_GETISPACE, &bi) == -1) {
285 		close(fd);
286 		return -1;
287 	}
288 
289 	val = 1;
290 	if (ioctl(fd, SNDCTL_DSP_LOW_WATER, &val) == -1) {
291 		DPERROR("sio_oss_start: LOW_WATER");
292 		close(fd);
293 		return -1;
294 	}
295 	return fd;
296 }
297 
298 static struct sio_hdl *
sio_oss_fdopen(const char * str,int fd,unsigned int mode,int nbio)299 sio_oss_fdopen(const char *str, int fd, unsigned int mode, int nbio)
300 {
301 	struct sio_oss_hdl *hdl;
302 
303 	hdl = malloc(sizeof(struct sio_oss_hdl));
304 	if (hdl == NULL)
305 		return NULL;
306 	_sio_create(&hdl->sio, &sio_oss_ops, mode, nbio);
307 
308 	/* Set default device parameters */
309 	hdl->fmt = AFMT_S16_LE;
310 	hdl->rate = 48000;
311 	hdl->chan = 2;
312 	hdl->round = 960;
313 	hdl->appbufsz = 8 * 960;
314 	hdl->filling = 0;
315 	hdl->fd = fd;
316 
317 	return (struct sio_hdl *)hdl;
318 }
319 
320 struct sio_hdl *
_sio_oss_open(const char * str,unsigned int mode,int nbio)321 _sio_oss_open(const char *str, unsigned int mode, int nbio)
322 {
323 	struct sio_oss_hdl *hdl;
324 	int fd;
325 
326 	fd = sio_oss_getfd(str, mode, nbio);
327 	if (fd == -1)
328 		return NULL;
329 
330 	hdl = (struct sio_oss_hdl *)sio_oss_fdopen(str, fd, mode, nbio);
331 	if (hdl != NULL)
332 		return (struct sio_hdl*)hdl;
333 
334 	while (close(fd) == -1 && errno == EINTR)
335 		; /* retry */
336 
337 	return NULL;
338 }
339 
340 static void
sio_oss_close(struct sio_hdl * sh)341 sio_oss_close(struct sio_hdl *sh)
342 {
343 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
344 
345 	while (close(hdl->fd) == -1 && errno == EINTR)
346 		; /* retry */
347 	free(hdl);
348 }
349 
350 static int
sio_oss_start(struct sio_hdl * sh)351 sio_oss_start(struct sio_hdl *sh)
352 {
353 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
354 	int trig;
355 
356 	hdl->iused = 0;
357 	hdl->oused = 0;
358 	hdl->idelta = 0;
359 	hdl->odelta = 0;
360 
361 	if (hdl->sio.mode & SIO_PLAY) {
362 		/*
363 		 * keep the device paused and let sio_oss_pollfd() trigger the
364 		 * start later, to avoid buffer underruns
365 		 */
366 		hdl->filling = 1;
367 		trig = 0;
368 	} else {
369 		/*
370 		 * no play buffers to fill, start now!
371 		 */
372 		trig = PCM_ENABLE_INPUT;
373 		_sio_onmove_cb(&hdl->sio, 0);
374 	}
375 	if (ioctl(hdl->fd, SNDCTL_DSP_SETTRIGGER, &trig) == -1) {
376 		DPERROR("sio_oss_start: SETTRIGGER");
377 		hdl->sio.eof = 1;
378 		return 0;
379 	}
380 	return 1;
381 }
382 
383 static int
sio_oss_stop(struct sio_hdl * sh)384 sio_oss_stop(struct sio_hdl *sh)
385 {
386 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl*)sh;
387 	int trig;
388 
389 	if (hdl->filling) {
390 		hdl->filling = 0;
391 		return 1;
392 	}
393 	trig = 0;
394 	if (ioctl(hdl->fd, SNDCTL_DSP_SETTRIGGER, &trig) == -1) {
395 		DPERROR("sio_oss_stop: SETTRIGGER");
396 		hdl->sio.eof = 1;
397 		return 0;
398 	}
399 	return 1;
400 }
401 
402 static int
sio_oss_setpar(struct sio_hdl * sh,struct sio_par * par)403 sio_oss_setpar(struct sio_hdl *sh, struct sio_par *par)
404 {
405 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
406 	unsigned int i, round, bufsz;
407 	int frag_max, frag_shift, frag_count, frag;
408 	unsigned int le, sig, msb;
409 
410 	le = par->le;
411 	sig = par->sig;
412 	msb = par->msb;
413 
414 	if (le == ~0U)
415 		le = 0;
416 	if (sig == ~0U)
417 		sig = 0;
418 	if (msb == ~0U)
419 		msb = 0;
420 
421 	hdl->fmt = AFMT_S16_LE;
422 	for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
423 		if (formats[i].bits == par->bits &&
424 		    formats[i].le == le &&
425 		    formats[i].sig == sig &&
426 		    formats[i].msb == msb) {
427 			hdl->fmt = formats[i].fmt;
428 			break;
429 		}
430 	}
431 
432 	if (par->rate != ~0U)
433 		hdl->rate = par->rate;
434 	if (hdl->rate < 8000)
435 		hdl->rate = 8000;
436 	if (hdl->rate > 192000)
437 		hdl->rate = 192000;
438 
439 	if ((hdl->sio.mode & SIO_PLAY) && par->pchan != ~0U)
440 		hdl->chan = par->pchan;
441 	else if ((hdl->sio.mode & SIO_REC) && par->rchan != ~0U)
442 		hdl->chan = par->rchan;
443 
444 	if (ioctl(hdl->fd, SNDCTL_DSP_SETFMT, &hdl->fmt) == -1) {
445 		DPERROR("sio_oss_setpar: SETFMT");
446 		hdl->sio.eof = 1;
447 		return 0;
448 	}
449 
450 	for (i = 0; ; i++) {
451 		if (i == sizeof(formats) / sizeof(formats[0])) {
452 			DPRINTF("sio_oss_setpar: unknown fmt %d\n", hdl->fmt);
453 			hdl->sio.eof = 1;
454 			return 0;
455 		}
456 		if (formats[i].fmt == hdl->fmt)
457 			break;
458 	}
459 
460 	if (ioctl(hdl->fd, SNDCTL_DSP_SPEED, &hdl->rate) == -1) {
461 		DPERROR("sio_oss_setpar: SPEED");
462 		hdl->sio.eof = 1;
463 		return 0;
464 	}
465 
466 	if (ioctl(hdl->fd, SNDCTL_DSP_CHANNELS, &hdl->chan) == -1) {
467 		DPERROR("sio_oss_setpar: CHANNELS");
468 		hdl->sio.eof = 1;
469 		return 0;
470 	}
471 
472 	hdl->bpf = formats[i].bps * hdl->chan;
473 
474 	if (par->round != ~0U && par->appbufsz != ~0U) {
475 		round = par->round;
476 		bufsz = par->appbufsz;
477 	} else if (par->round != ~0U) {
478 		round = par->round;
479 		bufsz = 2 * par->round;
480 	} else if (par->appbufsz != ~0U) {
481 		round = par->appbufsz / 2;
482 		bufsz = par->appbufsz;
483 	} else {
484 		/*
485 		 * even if it's not specified, we have to set the
486 		 * block size to ensure that both play and record
487 		 * direction get the same block size. Pick an
488 		 * arbitrary value that would work for most players at
489 		 * 48kHz, stereo, 16-bit.
490 		 */
491 		round = 512;
492 		bufsz = 1024;
493 	}
494 
495 	frag_max = round * hdl->chan * formats[i].bps;
496 	frag_shift = 8;
497 	while (1 << (frag_shift + 1) <= frag_max)
498 		frag_shift++;
499 
500 	frag_count = bufsz / round;
501 	if (frag_count < 2)
502 		frag_count = 2;
503 
504 	frag = frag_count << 16 | frag_shift;
505 	if (ioctl(hdl->fd, SNDCTL_DSP_SETFRAGMENT, &frag) == -1) {
506 		DPERROR("sio_oss_setpar: SETFRAGMENT");
507 		hdl->sio.eof = 1;
508 		return 0;
509 	}
510 
511 	return 1;
512 }
513 
514 static int
sio_oss_getpar(struct sio_hdl * sh,struct sio_par * par)515 sio_oss_getpar(struct sio_hdl *sh, struct sio_par *par)
516 {
517 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
518 	unsigned int i, found = 0;
519 	audio_buf_info pbi, rbi;
520 
521 	for (i = 0; i < sizeof(formats)/sizeof(formats[0]); i++) {
522 		if (formats[i].fmt == hdl->fmt) {
523 			par->sig = formats[i].sig;
524 			par->le = formats[i].le;
525 			par->bits = formats[i].bits;
526 			par->bps = formats[i].bps;
527 			par->msb = formats[i].msb;
528 			found = 1;
529 			break;
530 		}
531 	}
532 	if (!found) {
533 		DPRINTF("sio_oss_getpar: unknown format %d\n", hdl->fmt);
534 		hdl->sio.eof = 1;
535 		return 0;
536 	}
537 
538 	par->rate = hdl->rate;
539 	par->pchan = hdl->chan;
540 	par->rchan = hdl->chan;
541 	par->xrun = SIO_IGNORE;
542 
543 	if (hdl->sio.mode & SIO_PLAY) {
544 		if (ioctl(hdl->fd, SNDCTL_DSP_GETOSPACE, &pbi) == -1) {
545 			DPERROR("sio_oss_getpar: SNDCTL_DSP_GETOSPACE");
546 			hdl->sio.eof = 1;
547 			return 0;
548 		}
549 		par->round = pbi.fragsize / (par->pchan * par->bps);
550 		par->bufsz = pbi.fragstotal * par->round;
551 	}
552 	if (hdl->sio.mode & SIO_REC) {
553 		if (ioctl(hdl->fd, SNDCTL_DSP_GETISPACE, &rbi) == -1) {
554 			DPERROR("sio_oss_getpar: SNDCTL_DSP_GETISPACE");
555 			hdl->sio.eof = 1;
556 			return 0;
557 		}
558 		if (!(hdl->sio.mode & SIO_PLAY)) {
559 			par->round = rbi.fragsize / (par->rchan * par->bps);
560 			par->bufsz = rbi.fragstotal * par->round;
561 		}
562 	}
563 	par->appbufsz = par->bufsz;
564 #ifdef DEBUG
565 	if ((hdl->sio.mode & (SIO_REC | SIO_PLAY)) == (SIO_REC | SIO_PLAY)) {
566 		if (pbi.fragsize != rbi.fragsize) {
567 			DPRINTF("sio_oss_getpar: frag size/count mismatch\n"
568 			    "play: count = %d, size = %d\n"
569 			    "rec:  count = %d, size = %d\n",
570 			    pbi.fragstotal, pbi.fragsize,
571 			    rbi.fragstotal, rbi.fragsize);
572 			hdl->sio.eof = 1;
573 			return 0;
574 		}
575 	}
576 #endif
577 	return 1;
578 }
579 
580 static size_t
sio_oss_read(struct sio_hdl * sh,void * buf,size_t len)581 sio_oss_read(struct sio_hdl *sh, void *buf, size_t len)
582 {
583 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
584 	ssize_t n;
585 
586 	while ((n = read(hdl->fd, buf, len)) == -1) {
587 		if (errno == EINTR)
588 			continue;
589 		if (errno != EAGAIN) {
590 			DPERROR("sio_oss_read: read");
591 			hdl->sio.eof = 1;
592 		}
593 		return 0;
594 	}
595 	if (n == 0) {
596 		DPRINTF("sio_oss_read: eof\n");
597 		hdl->sio.eof = 1;
598 		return 0;
599 	}
600 
601 	hdl->idelta += n;
602 	return n;
603 }
604 
605 static size_t
sio_oss_write(struct sio_hdl * sh,const void * buf,size_t len)606 sio_oss_write(struct sio_hdl *sh, const void *buf, size_t len)
607 {
608 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
609 	const unsigned char *data = buf;
610 	ssize_t n, todo;
611 
612 	todo = len;
613 	while ((n = write(hdl->fd, data, todo)) == -1) {
614 		if (errno == EINTR)
615 			continue;
616 		if (errno != EAGAIN) {
617 			DPERROR("sio_oss_write: write");
618 			hdl->sio.eof = 1;
619 		}
620 		return 0;
621 	}
622 
623 	hdl->odelta += n;
624 	return n;
625 }
626 
627 static int
sio_oss_nfds(struct sio_hdl * hdl)628 sio_oss_nfds(struct sio_hdl *hdl)
629 {
630 	return 1;
631 }
632 
633 static int
sio_oss_pollfd(struct sio_hdl * sh,struct pollfd * pfd,int events)634 sio_oss_pollfd(struct sio_hdl *sh, struct pollfd *pfd, int events)
635 {
636 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
637 	int trig;
638 
639 	pfd->fd = hdl->fd;
640 	pfd->events = events;
641 	if (hdl->filling && hdl->sio.wused == hdl->sio.par.bufsz *
642 		hdl->sio.par.pchan * hdl->sio.par.bps) {
643 		hdl->filling = 0;
644 		trig = 0;
645 		if (hdl->sio.mode & SIO_PLAY)
646 			trig |= PCM_ENABLE_OUTPUT;
647 		if (hdl->sio.mode & SIO_REC)
648 			trig |= PCM_ENABLE_INPUT;
649 		if (ioctl(hdl->fd, SNDCTL_DSP_SETTRIGGER, &trig) == -1) {
650 			DPERROR("sio_oss_pollfd: SETTRIGGER");
651 			hdl->sio.eof = 1;
652 			return 0;
653 		}
654 		_sio_onmove_cb(&hdl->sio, 0);
655 	}
656 	return 1;
657 }
658 
659 static int
sio_oss_xrun(struct sio_oss_hdl * hdl)660 sio_oss_xrun(struct sio_oss_hdl *hdl)
661 {
662 	int clk;
663 	int wsil, rdrop, cmove;
664 	int rbpf, rround;
665 	int wbpf;
666 
667 	DPRINTFN(2, "sio_oss_xrun:\n");
668 #ifdef DEBUG
669 	if (_sndio_debug >= 2)
670 		_sio_printpos(&hdl->sio);
671 #endif
672 
673 	/*
674 	 * we assume rused/wused are zero if rec/play modes are not
675 	 * selected. This allows us to keep the same formula for all
676 	 * modes, provided we set rbpf/wbpf to 1 to avoid division by
677 	 * zero.
678 	 *
679 	 * to understand the formula, draw a picture :)
680 	 */
681 	rbpf = (hdl->sio.mode & SIO_REC) ?
682 	    hdl->sio.par.bps * hdl->sio.par.rchan : 1;
683 	wbpf = (hdl->sio.mode & SIO_PLAY) ?
684 	    hdl->sio.par.bps * hdl->sio.par.pchan : 1;
685 	rround = hdl->sio.par.round * rbpf;
686 
687 	clk = hdl->sio.cpos % hdl->sio.par.round;
688 	rdrop = (clk * rbpf - hdl->sio.rused) % rround;
689 	if (rdrop < 0)
690 		rdrop += rround;
691 	cmove = (rdrop + hdl->sio.rused) / rbpf;
692 	wsil = cmove * wbpf + hdl->sio.wused;
693 
694 	DPRINTFN(2, "wsil = %d, cmove = %d, rdrop = %d\n", wsil, cmove, rdrop);
695 
696 	if (!sio_oss_stop(&hdl->sio))
697 		return 0;
698 	if (!sio_oss_start(&hdl->sio))
699 		return 0;
700 	if (hdl->sio.mode & SIO_PLAY) {
701 		hdl->odelta -= cmove * hdl->bpf;
702 		hdl->sio.wsil = wsil;
703 	}
704 	if (hdl->sio.mode & SIO_REC) {
705 		hdl->idelta -= cmove * hdl->bpf;
706 		hdl->sio.rdrop = rdrop;
707 	}
708 	DPRINTFN(2, "xrun: corrected\n");
709 	DPRINTFN(2, "wsil = %d, rdrop = %d, odelta = %d, idelta = %d\n",
710 	    wsil, rdrop, hdl->odelta, hdl->idelta);
711 	return 1;
712 }
713 
714 static int
sio_oss_revents(struct sio_hdl * sh,struct pollfd * pfd)715 sio_oss_revents(struct sio_hdl *sh, struct pollfd *pfd)
716 {
717 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
718 	audio_errinfo ei;
719 	int delta, iused, oused;
720 	int revents = pfd->revents;
721 	oss_count_t optr, iptr;
722 
723 	if ((pfd->revents & POLLHUP) ||
724 	    (pfd->revents & (POLLIN | POLLOUT)) == 0)
725 		return pfd->revents;
726 
727 	/* Hide xruns from clients */
728 	if (ioctl(hdl->fd, SNDCTL_DSP_GETERROR, &ei) == -1) {
729 		DPERROR("sio_oss_revents: GETERROR");
730 		hdl->sio.eof = 1;
731 		return POLLHUP;
732 	}
733 	if (ei.play_underruns > 0 || ei.rec_overruns > 0) {
734 		if (!sio_oss_xrun(hdl))
735 			return POLLHUP;
736 		return 0;
737 	}
738 
739 	if (hdl->sio.mode & SIO_PLAY) {
740 		if (ioctl(hdl->fd, SNDCTL_DSP_CURRENT_OPTR, &optr) == -1) {
741 			DPERROR("sio_oss_revents: CURRENT_OPTR");
742 			hdl->sio.eof = 1;
743 			return POLLHUP;
744 		}
745 		oused = optr.fifo_samples * hdl->bpf;
746 		hdl->odelta -= oused - hdl->oused;
747 		hdl->oused = oused;
748 		if (!(hdl->sio.mode & SIO_REC)) {
749 			hdl->idelta = hdl->odelta;
750 		}
751 	}
752 	if (hdl->sio.mode & SIO_REC) {
753 		if (ioctl(hdl->fd, SNDCTL_DSP_CURRENT_IPTR, &iptr) == -1) {
754 			DPERROR("sio_oss_revents: CURRENT_IPTR");
755 			hdl->sio.eof = 1;
756 			return POLLHUP;
757 		}
758 		iused = iptr.fifo_samples * hdl->bpf;
759 		hdl->idelta += iused - hdl->iused;
760 		hdl->iused = iused;
761 		if (!(hdl->sio.mode & SIO_PLAY)) {
762 			hdl->odelta = hdl->idelta;
763 		}
764 	}
765 
766 	delta = (hdl->idelta > hdl->odelta) ? hdl->idelta : hdl->odelta;
767 	if (delta > 0) {
768 		_sio_onmove_cb(&hdl->sio, delta / hdl->bpf);
769 		hdl->idelta -= delta;
770 		hdl->odelta -= delta;
771 	}
772 	return revents;
773 }
774 
775 static int
sio_oss_setvol(struct sio_hdl * sh,unsigned int vol)776 sio_oss_setvol(struct sio_hdl *sh, unsigned int vol)
777 {
778 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
779 	int newvol;
780 
781 	/* Scale to 0..100 */
782 	newvol = (100 * vol + SIO_MAXVOL / 2) / SIO_MAXVOL;
783 	newvol = newvol | (newvol << 8);
784 
785 	if (ioctl(hdl->fd, SNDCTL_DSP_SETPLAYVOL, &newvol) == -1) {
786 		DPERROR("sio_oss_setvol");
787 		hdl->sio.eof = 1;
788 		return 0;
789 	}
790 
791 	return 1;
792 }
793 
794 static void
sio_oss_getvol(struct sio_hdl * sh)795 sio_oss_getvol(struct sio_hdl *sh)
796 {
797 	struct sio_oss_hdl *hdl = (struct sio_oss_hdl *)sh;
798 	int vol;
799 
800 	if (ioctl(hdl->fd, SNDCTL_DSP_GETPLAYVOL, &vol) == -1) {
801 		DPERROR("sio_oss_getvol");
802 		hdl->sio.eof = 1;
803 		return;
804 	}
805 
806 	/* Use left channel volume and scale to SIO_MAXVOL */
807 	vol = (SIO_MAXVOL * (vol & 0x7f) + 50) / 100;
808 	_sio_onvol_cb(&hdl->sio, vol);
809 }
810 
811 #endif /* defined USE_OSS */
812