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