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