Annotation of src/usr.bin/aucat/siofile.c, Revision 1.12
1.12 ! ratchov 1: /* $OpenBSD: siofile.c,v 1.11 2012/05/23 19:25:11 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 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:
18: #include <sys/time.h>
19: #include <sys/types.h>
20:
21: #include <poll.h>
22: #include <sndio.h>
23: #include <stdio.h>
24: #include <stdlib.h>
25: #include <string.h>
26:
27: #include "aparams.h"
28: #include "aproc.h"
1.4 ratchov 29: #include "abuf.h"
1.1 ratchov 30: #include "conf.h"
31: #include "dev.h"
32: #include "file.h"
33: #include "siofile.h"
34: #ifdef DEBUG
35: #include "dbg.h"
36: #endif
37:
38: struct siofile {
39: struct file file;
40: struct sio_hdl *hdl;
1.10 ratchov 41: unsigned int wtickets, wbpf;
42: unsigned int rtickets, rbpf;
43: unsigned int bufsz;
1.1 ratchov 44: int started;
1.9 ratchov 45: void (*onmove)(void *, int);
46: void *arg;
1.7 ratchov 47: #ifdef DEBUG
48: long long wtime, utime;
49: #endif
1.1 ratchov 50: };
51:
52: void siofile_close(struct file *);
1.10 ratchov 53: unsigned int siofile_read(struct file *, unsigned char *, unsigned int);
54: unsigned int siofile_write(struct file *, unsigned char *, unsigned int);
1.9 ratchov 55: void siofile_start(struct file *, void (*)(void *, int), void *);
1.1 ratchov 56: void siofile_stop(struct file *);
57: int siofile_nfds(struct file *);
58: int siofile_pollfd(struct file *, struct pollfd *, int);
59: int siofile_revents(struct file *, struct pollfd *);
60:
61: struct fileops siofile_ops = {
62: "sio",
63: sizeof(struct siofile),
64: siofile_close,
65: siofile_read,
66: siofile_write,
67: siofile_start,
68: siofile_stop,
69: siofile_nfds,
70: siofile_pollfd,
71: siofile_revents
72: };
73:
1.4 ratchov 74: int wsio_out(struct aproc *, struct abuf *);
75: int rsio_in(struct aproc *, struct abuf *);
76:
77: struct aproc_ops rsio_ops = {
78: "rsio",
79: rsio_in,
80: rfile_out,
81: rfile_eof,
82: rfile_hup,
83: NULL, /* newin */
84: NULL, /* newout */
85: aproc_ipos,
86: aproc_opos,
87: rfile_done
88: };
89:
90: struct aproc_ops wsio_ops = {
91: "wsio",
92: wfile_in,
93: wsio_out,
94: wfile_eof,
95: wfile_hup,
96: NULL, /* newin */
97: NULL, /* newout */
98: aproc_ipos,
99: aproc_opos,
100: wfile_done
101: };
102:
103: struct aproc *
104: rsio_new(struct file *f)
105: {
106: struct aproc *p;
107:
108: p = aproc_new(&rsio_ops, f->name);
109: p->u.io.file = f;
110: p->u.io.partial = 0;
111: f->rproc = p;
112: return p;
113: }
114:
115: struct aproc *
116: wsio_new(struct file *f)
117: {
118: struct aproc *p;
119:
120: p = aproc_new(&wsio_ops, f->name);
121: p->u.io.file = f;
122: p->u.io.partial = 0;
123: f->wproc = p;
124: return p;
125: }
126:
127: int
128: wsio_out(struct aproc *p, struct abuf *obuf)
129: {
130: struct siofile *f = (struct siofile *)p->u.io.file;
131:
132: if (f->wtickets == 0) {
133: #ifdef DEBUG
134: if (debug_level >= 4) {
135: file_dbg(&f->file);
136: dbg_puts(": no more write tickets\n");
137: }
138: #endif
139: f->file.state &= ~FILE_WOK;
140: return 0;
141: }
142: return wfile_out(p, obuf);
143: }
144:
145: int
146: rsio_in(struct aproc *p, struct abuf *ibuf)
147: {
148: struct siofile *f = (struct siofile *)p->u.io.file;
149:
150: if (f->rtickets == 0) {
151: #ifdef DEBUG
152: if (debug_level >= 4) {
153: file_dbg(&f->file);
154: dbg_puts(": no more read tickets\n");
155: }
156: #endif
157: f->file.state &= ~FILE_ROK;
158: return 0;
159: }
160: return rfile_in(p, ibuf);
161: }
162:
1.1 ratchov 163: void
164: siofile_cb(void *addr, int delta)
165: {
166: struct siofile *f = (struct siofile *)addr;
167: struct aproc *p;
168:
169: #ifdef DEBUG
170: if (delta < 0 || delta > (60 * RATE_MAX)) {
1.4 ratchov 171: file_dbg(&f->file);
1.1 ratchov 172: dbg_puts(": ");
173: dbg_puti(delta);
174: dbg_puts(": bogus sndio delta");
175: dbg_panic();
176: }
1.4 ratchov 177: if (debug_level >= 4) {
178: file_dbg(&f->file);
179: dbg_puts(": tick, delta = ");
180: dbg_puti(delta);
1.7 ratchov 181: dbg_puts(", load = ");
182: dbg_puti((file_utime - f->utime) / 1000);
183: dbg_puts(" + ");
184: dbg_puti((file_wtime - f->wtime) / 1000);
1.4 ratchov 185: dbg_puts("\n");
186: }
1.7 ratchov 187: f->wtime = file_wtime;
188: f->utime = file_utime;
1.1 ratchov 189: #endif
190: if (delta != 0) {
191: p = f->file.wproc;
192: if (p && p->ops->opos)
193: p->ops->opos(p, NULL, delta);
194: p = f->file.rproc;
195: if (p && p->ops->ipos)
196: p->ops->ipos(p, NULL, delta);
197: }
1.9 ratchov 198: if (f->onmove)
199: f->onmove(f->arg, delta);
1.4 ratchov 200: f->wtickets += delta * f->wbpf;
201: f->rtickets += delta * f->rbpf;
1.1 ratchov 202: }
203:
204: /*
205: * Open the device.
206: */
207: struct siofile *
1.10 ratchov 208: siofile_new(struct fileops *ops, char *path, unsigned int *rmode,
1.1 ratchov 209: struct aparams *ipar, struct aparams *opar,
1.10 ratchov 210: unsigned int *bufsz, unsigned int *round)
1.1 ratchov 211: {
212: struct sio_par par;
213: struct sio_hdl *hdl;
214: struct siofile *f;
1.10 ratchov 215: unsigned int mode = *rmode;
1.1 ratchov 216:
1.11 ratchov 217: hdl = sio_open(path, mode, 1);
1.5 ratchov 218: if (hdl == NULL) {
219: if (mode != (SIO_PLAY | SIO_REC))
220: return NULL;
1.11 ratchov 221: hdl = sio_open(path, SIO_PLAY, 1);
1.5 ratchov 222: if (hdl != NULL)
223: mode = SIO_PLAY;
224: else {
1.11 ratchov 225: hdl = sio_open(path, SIO_REC, 1);
1.5 ratchov 226: if (hdl != NULL)
227: mode = SIO_REC;
228: else
229: return NULL;
230: }
231: #ifdef DEBUG
232: if (debug_level >= 1) {
233: dbg_puts("warning, device opened in ");
234: dbg_puts(mode == SIO_PLAY ? "play-only" : "rec-only");
235: dbg_puts(" mode\n");
236: }
237: #endif
238: }
239:
1.1 ratchov 240: sio_initpar(&par);
1.4 ratchov 241: if (mode & SIO_REC) {
1.1 ratchov 242: par.bits = ipar->bits;
243: par.bps = ipar->bps;
244: par.sig = ipar->sig;
245: par.le = ipar->le;
246: par.msb = ipar->msb;
247: par.rate = ipar->rate;
1.8 ratchov 248: par.rchan = ipar->cmax + 1;
1.1 ratchov 249: } else {
250: par.bits = opar->bits;
251: par.bps = opar->bps;
252: par.sig = opar->sig;
253: par.le = opar->le;
254: par.msb = opar->msb;
255: par.rate = opar->rate;
256: }
1.4 ratchov 257: if (mode & SIO_PLAY)
1.8 ratchov 258: par.pchan = opar->cmax + 1;
259: if (*bufsz)
260: par.appbufsz = *bufsz;
261: if (*round)
262: par.round = *round;
1.1 ratchov 263: if (!sio_setpar(hdl, &par))
264: goto bad_close;
265: if (!sio_getpar(hdl, &par))
266: goto bad_close;
1.4 ratchov 267: if (mode & SIO_REC) {
1.1 ratchov 268: ipar->bits = par.bits;
269: ipar->bps = par.bps;
270: ipar->sig = par.sig;
271: ipar->le = par.le;
272: ipar->msb = par.msb;
273: ipar->rate = par.rate;
1.8 ratchov 274: ipar->cmin = 0;
275: ipar->cmax = par.rchan - 1;
1.1 ratchov 276: }
1.4 ratchov 277: if (mode & SIO_PLAY) {
1.1 ratchov 278: opar->bits = par.bits;
279: opar->bps = par.bps;
280: opar->sig = par.sig;
281: opar->le = par.le;
282: opar->msb = par.msb;
283: opar->rate = par.rate;
1.8 ratchov 284: opar->cmin = 0;
285: opar->cmax = par.pchan - 1;
1.1 ratchov 286: }
1.5 ratchov 287: *rmode = mode;
1.1 ratchov 288: *bufsz = par.bufsz;
289: *round = par.round;
290: f = (struct siofile *)file_new(ops, path, sio_nfds(hdl));
291: if (f == NULL)
292: goto bad_close;
293: f->hdl = hdl;
294: f->started = 0;
1.4 ratchov 295: f->wtickets = 0;
296: f->rtickets = 0;
297: f->wbpf = par.pchan * par.bps;
298: f->rbpf = par.rchan * par.bps;
299: f->bufsz = par.bufsz;
1.1 ratchov 300: sio_onmove(f->hdl, siofile_cb, f);
301: return f;
302: bad_close:
303: sio_close(hdl);
304: return NULL;
305: }
306:
307: void
1.9 ratchov 308: siofile_start(struct file *file, void (*cb)(void *, int), void *arg)
1.1 ratchov 309: {
310: struct siofile *f = (struct siofile *)file;
311:
312: if (!sio_start(f->hdl)) {
313: #ifdef DEBUG
314: dbg_puts(f->file.name);
315: dbg_puts(": failed to start device\n");
316: #endif
317: file_close(file);
318: return;
319: }
320: f->started = 1;
1.4 ratchov 321: f->wtickets = f->bufsz * f->wbpf;
322: f->rtickets = 0;
1.1 ratchov 323: #ifdef DEBUG
1.7 ratchov 324: f->wtime = file_wtime;
325: f->utime = file_utime;
1.1 ratchov 326: if (debug_level >= 3) {
327: file_dbg(&f->file);
328: dbg_puts(": started\n");
329: }
330: #endif
1.9 ratchov 331: f->onmove = cb;
332: f->arg = arg;
1.1 ratchov 333: }
334:
335: void
336: siofile_stop(struct file *file)
337: {
338: struct siofile *f = (struct siofile *)file;
339:
340: f->started = 0;
1.9 ratchov 341: f->onmove = NULL;
1.1 ratchov 342: if (!sio_eof(f->hdl) && !sio_stop(f->hdl)) {
343: #ifdef DEBUG
344: dbg_puts(f->file.name);
345: dbg_puts(": failed to stop device\n");
346: #endif
347: file_close(file);
348: return;
349: }
350: #ifdef DEBUG
351: if (debug_level >= 3) {
352: file_dbg(&f->file);
353: dbg_puts(": stopped\n");
354: }
355: #endif
356: }
357:
1.10 ratchov 358: unsigned int
359: siofile_read(struct file *file, unsigned char *data, unsigned int count)
1.1 ratchov 360: {
361: struct siofile *f = (struct siofile *)file;
1.10 ratchov 362: unsigned int n;
1.1 ratchov 363:
1.4 ratchov 364: #ifdef DEBUG
365: if (f->rtickets == 0) {
366: file_dbg(&f->file);
367: dbg_puts(": called with no read tickets\n");
368: }
369: #endif
370: if (count > f->rtickets)
371: count = f->rtickets;
1.1 ratchov 372: n = f->started ? sio_read(f->hdl, data, count) : 0;
373: if (n == 0) {
374: f->file.state &= ~FILE_ROK;
375: if (sio_eof(f->hdl)) {
376: #ifdef DEBUG
377: dbg_puts(f->file.name);
378: dbg_puts(": failed to read from device\n");
379: #endif
380: file_eof(&f->file);
381: } else {
382: #ifdef DEBUG
383: if (debug_level >= 4) {
384: file_dbg(&f->file);
385: dbg_puts(": reading blocked\n");
386: }
387: #endif
388: }
389: return 0;
1.4 ratchov 390: } else {
391: f->rtickets -= n;
392: if (f->rtickets == 0) {
393: f->file.state &= ~FILE_ROK;
394: #ifdef DEBUG
395: if (debug_level >= 4) {
396: file_dbg(&f->file);
397: dbg_puts(": read tickets exhausted\n");
398: }
399: #endif
400: }
1.1 ratchov 401: }
402: return n;
403:
404: }
405:
1.10 ratchov 406: unsigned int
407: siofile_write(struct file *file, unsigned char *data, unsigned int count)
1.1 ratchov 408: {
409: struct siofile *f = (struct siofile *)file;
1.10 ratchov 410: unsigned int n;
1.1 ratchov 411:
1.4 ratchov 412: #ifdef DEBUG
413: if (f->wtickets == 0) {
414: file_dbg(&f->file);
415: dbg_puts(": called with no write tickets\n");
416: }
417: #endif
418: if (count > f->wtickets)
419: count = f->wtickets;
1.1 ratchov 420: n = f->started ? sio_write(f->hdl, data, count) : 0;
421: if (n == 0) {
422: f->file.state &= ~FILE_WOK;
423: if (sio_eof(f->hdl)) {
424: #ifdef DEBUG
425: dbg_puts(f->file.name);
426: dbg_puts(": failed to write on device\n");
427: #endif
428: file_hup(&f->file);
429: } else {
430: #ifdef DEBUG
431: if (debug_level >= 4) {
432: file_dbg(&f->file);
433: dbg_puts(": writing blocked\n");
434: }
435: #endif
436: }
437: return 0;
1.4 ratchov 438: } else {
439: f->wtickets -= n;
440: if (f->wtickets == 0) {
441: f->file.state &= ~FILE_WOK;
442: #ifdef DEBUG
443: if (debug_level >= 4) {
444: file_dbg(&f->file);
445: dbg_puts(": write tickets exhausted\n");
446: }
447: #endif
448: }
1.1 ratchov 449: }
450: return n;
451: }
452:
453: int
454: siofile_nfds(struct file *file)
455: {
456: return sio_nfds(((struct siofile *)file)->hdl);
457: }
458:
459: int
460: siofile_pollfd(struct file *file, struct pollfd *pfd, int events)
461: {
462: struct siofile *f = (struct siofile *)file;
463:
464: if (!f->started)
465: events &= ~(POLLIN | POLLOUT);
466: return sio_pollfd(((struct siofile *)file)->hdl, pfd, events);
467: }
468:
469: int
470: siofile_revents(struct file *file, struct pollfd *pfd)
471: {
472: return sio_revents(((struct siofile *)file)->hdl, pfd);
473: }
474:
475: void
476: siofile_close(struct file *file)
477: {
478: struct siofile *f = (struct siofile *)file;
479:
480: if (f->started)
481: siofile_stop(&f->file);
1.12 ! ratchov 482: sio_close(((struct siofile *)file)->hdl);
1.1 ratchov 483: }