[BACK]Return to siofile.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

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: }