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

Annotation of src/usr.bin/sndiod/siofile.c, Revision 1.23

1.23    ! edd         1: /*     $OpenBSD: siofile.c,v 1.22 2020/06/28 05:21:39 ratchov Exp $    */
1.1       ratchov     2: /*
                      3:  * Copyright (c) 2008-2012 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: #include <sys/time.h>
                     18: #include <sys/types.h>
                     19:
                     20: #include <poll.h>
                     21: #include <sndio.h>
                     22: #include <stdio.h>
                     23: #include <stdlib.h>
                     24: #include <string.h>
                     25:
                     26: #include "abuf.h"
                     27: #include "defs.h"
                     28: #include "dev.h"
1.18      ratchov    29: #include "dev_sioctl.h"
1.1       ratchov    30: #include "dsp.h"
1.10      ratchov    31: #include "fdpass.h"
1.1       ratchov    32: #include "file.h"
                     33: #include "siofile.h"
                     34: #include "utils.h"
                     35:
1.9       ratchov    36: #define WATCHDOG_USEC  4000000         /* 4 seconds */
1.2       ratchov    37:
1.3       ratchov    38: void dev_sio_onmove(void *, int);
                     39: void dev_sio_timeout(void *);
1.1       ratchov    40: int dev_sio_pollfd(void *, struct pollfd *);
                     41: int dev_sio_revents(void *, struct pollfd *);
                     42: void dev_sio_run(void *);
                     43: void dev_sio_hup(void *);
                     44:
1.19      ratchov    45: extern struct fileops dev_sioctl_ops;
                     46:
1.1       ratchov    47: struct fileops dev_sio_ops = {
                     48:        "sio",
                     49:        dev_sio_pollfd,
                     50:        dev_sio_revents,
                     51:        dev_sio_run,
                     52:        dev_sio_run,
                     53:        dev_sio_hup
                     54: };
                     55:
                     56: void
                     57: dev_sio_onmove(void *arg, int delta)
                     58: {
                     59:        struct dev *d = arg;
                     60:
                     61: #ifdef DEBUG
                     62:        if (log_level >= 4) {
                     63:                dev_log(d);
                     64:                log_puts(": tick, delta = ");
                     65:                log_puti(delta);
                     66:                log_puts("\n");
                     67:        }
                     68:        d->sio.sum_utime += file_utime - d->sio.utime;
                     69:        d->sio.sum_wtime += file_wtime - d->sio.wtime;
                     70:        d->sio.wtime = file_wtime;
                     71:        d->sio.utime = file_utime;
                     72:        if (d->mode & MODE_PLAY)
                     73:                d->sio.pused -= delta;
                     74:        if (d->mode & MODE_REC)
                     75:                d->sio.rused += delta;
                     76: #endif
                     77:        dev_onmove(d, delta);
                     78: }
                     79:
1.2       ratchov    80: void
                     81: dev_sio_timeout(void *arg)
                     82: {
                     83:        struct dev *d = arg;
                     84:
                     85:        dev_log(d);
                     86:        log_puts(": watchdog timeout\n");
1.20      ratchov    87:        dev_abort(d);
1.2       ratchov    88: }
                     89:
1.23    ! edd        90: static int
        !            91: dev_sio_openalt(struct dev *d, struct dev_alt *n,
        !            92:     struct sio_hdl **rhdl, struct sioctl_hdl **rctlhdl, unsigned int *rmode)
        !            93: {
        !            94:        struct sio_hdl *hdl;
        !            95:        struct sioctl_hdl *ctlhdl;
        !            96:        unsigned int mode = d->reqmode & (MODE_PLAY | MODE_REC);
        !            97:
        !            98:        hdl = fdpass_sio_open(d->num, n->idx, mode);
        !            99:        if (hdl == NULL) {
        !           100:                if (mode != (SIO_PLAY | SIO_REC))
        !           101:                        return 0;
        !           102:                hdl = fdpass_sio_open(d->num, n->idx, SIO_PLAY);
        !           103:                if (hdl != NULL)
        !           104:                        mode = SIO_PLAY;
        !           105:                else {
        !           106:                        hdl = fdpass_sio_open(d->num, n->idx, SIO_REC);
        !           107:                        if (hdl != NULL)
        !           108:                                mode = SIO_REC;
        !           109:                        else
        !           110:                                return 0;
        !           111:                }
        !           112:                if (log_level >= 1) {
        !           113:                        log_puts("warning, device opened in ");
        !           114:                        log_puts(mode == SIO_PLAY ? "play-only" : "rec-only");
        !           115:                        log_puts(" mode\n");
        !           116:                }
        !           117:        }
        !           118:
        !           119:        ctlhdl = fdpass_sioctl_open(d->num, n->idx, SIOCTL_READ | SIOCTL_WRITE);
        !           120:        if (ctlhdl == NULL) {
        !           121:                if (log_level >= 1) {
        !           122:                        dev_log(d);
        !           123:                        log_puts(": no control device\n");
        !           124:                }
        !           125:        }
        !           126:
        !           127:        *rhdl = hdl;
        !           128:        *rctlhdl = ctlhdl;
        !           129:        *rmode = mode;
        !           130:        return 1;
        !           131: }
        !           132:
1.1       ratchov   133: /*
1.17      ratchov   134:  * open the device using one of the provided paths
                    135:  */
1.23    ! edd       136: static int
        !           137: dev_sio_openlist(struct dev *d,
        !           138:     struct sio_hdl **rhdl, struct sioctl_hdl **rctlhdl, unsigned int *rmode)
1.17      ratchov   139: {
1.21      ratchov   140:        struct dev_alt *n;
1.22      ratchov   141:        struct ctl *c;
                    142:        int val;
1.17      ratchov   143:
1.21      ratchov   144:        for (n = d->alt_list; n != NULL; n = n->next) {
                    145:                if (d->alt_num == n->idx)
                    146:                        continue;
1.23    ! edd       147:                if (log_level >= 2) {
        !           148:                        dev_log(d);
        !           149:                        log_puts(": trying ");
        !           150:                        log_puts(n->name);
        !           151:                        log_puts("\n");
        !           152:                }
        !           153:                if (dev_sio_openalt(d, n, rhdl, rctlhdl, rmode)) {
1.17      ratchov   154:                        if (log_level >= 2) {
                    155:                                dev_log(d);
                    156:                                log_puts(": using ");
1.21      ratchov   157:                                log_puts(n->name);
1.17      ratchov   158:                                log_puts("\n");
                    159:                        }
1.21      ratchov   160:                        d->alt_num = n->idx;
1.22      ratchov   161:                        for (c = d->ctl_list; c != NULL; c = c->next) {
                    162:                                if (c->addr < CTLADDR_ALT_SEL ||
                    163:                                    c->addr >= CTLADDR_ALT_SEL + DEV_NMAX)
                    164:                                        continue;
                    165:                                val = (c->addr - CTLADDR_ALT_SEL) == n->idx;
                    166:                                if (c->curval == val)
                    167:                                        continue;
                    168:                                c->curval = val;
                    169:                                if (val)
                    170:                                        c->val_mask = ~0U;
                    171:                        }
1.23    ! edd       172:                        return 1;
1.17      ratchov   173:                }
                    174:        }
1.23    ! edd       175:        return 0;
1.17      ratchov   176: }
                    177:
                    178: /*
1.1       ratchov   179:  * open the device.
                    180:  */
                    181: int
                    182: dev_sio_open(struct dev *d)
                    183: {
                    184:        struct sio_par par;
                    185:
1.23    ! edd       186:        if (!dev_sio_openlist(d, &d->sio.hdl, &d->sioctl.hdl, &d->mode))
        !           187:                return 0;
        !           188:
1.1       ratchov   189:        sio_initpar(&par);
                    190:        par.bits = d->par.bits;
                    191:        par.bps = d->par.bps;
                    192:        par.sig = d->par.sig;
                    193:        par.le = d->par.le;
                    194:        par.msb = d->par.msb;
1.23    ! edd       195:        if (d->mode & SIO_PLAY)
1.1       ratchov   196:                par.pchan = d->pchan;
1.23    ! edd       197:        if (d->mode & SIO_REC)
1.1       ratchov   198:                par.rchan = d->rchan;
                    199:        if (d->bufsz)
                    200:                par.appbufsz = d->bufsz;
                    201:        if (d->round)
                    202:                par.round = d->round;
                    203:        if (d->rate)
                    204:                par.rate = d->rate;
                    205:        if (!sio_setpar(d->sio.hdl, &par))
                    206:                goto bad_close;
                    207:        if (!sio_getpar(d->sio.hdl, &par))
                    208:                goto bad_close;
1.5       ratchov   209:
                    210: #ifdef DEBUG
                    211:        /*
1.13      ratchov   212:         * We support any parameter combination exposed by the kernel,
1.5       ratchov   213:         * and we have no other choice than trusting the kernel for
                    214:         * returning correct parameters. But let's check parameters
                    215:         * early and nicely report kernel bugs rather than crashing
                    216:         * later in memset(), malloc() or alike.
                    217:         */
                    218:
                    219:        if (par.bits > BITS_MAX) {
1.15      ratchov   220:                dev_log(d);
1.5       ratchov   221:                log_puts(": ");
                    222:                log_putu(par.bits);
                    223:                log_puts(": unsupported number of bits\n");
                    224:                goto bad_close;
                    225:        }
                    226:        if (par.bps > SIO_BPS(BITS_MAX)) {
1.15      ratchov   227:                dev_log(d);
1.5       ratchov   228:                log_puts(": ");
1.14      ratchov   229:                log_putu(par.bps);
1.5       ratchov   230:                log_puts(": unsupported sample size\n");
                    231:                goto bad_close;
                    232:        }
1.23    ! edd       233:        if ((d->mode & SIO_PLAY) && par.pchan > NCHAN_MAX) {
1.15      ratchov   234:                dev_log(d);
1.5       ratchov   235:                log_puts(": ");
                    236:                log_putu(par.pchan);
                    237:                log_puts(": unsupported number of play channels\n");
                    238:                goto bad_close;
1.11      ratchov   239:        }
1.23    ! edd       240:        if ((d->mode & SIO_REC) && par.rchan > NCHAN_MAX) {
1.15      ratchov   241:                dev_log(d);
1.5       ratchov   242:                log_puts(": ");
                    243:                log_putu(par.rchan);
                    244:                log_puts(": unsupported number of rec channels\n");
                    245:                goto bad_close;
                    246:        }
                    247:        if (par.bufsz == 0 || par.bufsz > RATE_MAX) {
1.15      ratchov   248:                dev_log(d);
1.5       ratchov   249:                log_puts(": ");
                    250:                log_putu(par.bufsz);
                    251:                log_puts(": unsupported buffer size\n");
                    252:                goto bad_close;
                    253:        }
                    254:        if (par.round == 0 || par.round > par.bufsz ||
                    255:            par.bufsz % par.round != 0) {
1.15      ratchov   256:                dev_log(d);
1.5       ratchov   257:                log_puts(": ");
                    258:                log_putu(par.round);
                    259:                log_puts(": unsupported block size\n");
                    260:                goto bad_close;
                    261:        }
                    262:        if (par.rate == 0 || par.rate > RATE_MAX) {
1.15      ratchov   263:                dev_log(d);
1.5       ratchov   264:                log_puts(": ");
                    265:                log_putu(par.rate);
                    266:                log_puts(": unsupported rate\n");
                    267:                goto bad_close;
                    268:        }
                    269: #endif
                    270:
1.1       ratchov   271:        d->par.bits = par.bits;
                    272:        d->par.bps = par.bps;
                    273:        d->par.sig = par.sig;
                    274:        d->par.le = par.le;
                    275:        d->par.msb = par.msb;
1.23    ! edd       276:        if (d->mode & SIO_PLAY)
1.1       ratchov   277:                d->pchan = par.pchan;
1.23    ! edd       278:        if (d->mode & SIO_REC)
1.1       ratchov   279:                d->rchan = par.rchan;
                    280:        d->bufsz = par.bufsz;
                    281:        d->round = par.round;
                    282:        d->rate = par.rate;
1.23    ! edd       283:        if (d->mode & MODE_PLAY)
        !           284:                d->mode |= MODE_MON;
1.1       ratchov   285:        sio_onmove(d->sio.hdl, dev_sio_onmove, d);
1.16      ratchov   286:        d->sio.file = file_new(&dev_sio_ops, d, "dev", sio_nfds(d->sio.hdl));
1.19      ratchov   287:        if (d->sioctl.hdl) {
                    288:                d->sioctl.file = file_new(&dev_sioctl_ops, d, "mix",
                    289:                    sioctl_nfds(d->sioctl.hdl));
                    290:        }
1.2       ratchov   291:        timo_set(&d->sio.watchdog, dev_sio_timeout, d);
1.18      ratchov   292:        dev_sioctl_open(d);
1.1       ratchov   293:        return 1;
                    294:  bad_close:
                    295:        sio_close(d->sio.hdl);
1.18      ratchov   296:        if (d->sioctl.hdl) {
                    297:                sioctl_close(d->sioctl.hdl);
                    298:                d->sioctl.hdl = NULL;
                    299:        }
1.1       ratchov   300:        return 0;
                    301: }
                    302:
1.16      ratchov   303: /*
                    304:  * Open an alternate device. Upon success and if the new device is
                    305:  * compatible with the old one, close the old device and continue
                    306:  * using the new one. The new device is not started.
                    307:  */
                    308: int
                    309: dev_sio_reopen(struct dev *d)
                    310: {
                    311:        struct sio_par par;
                    312:        struct sio_hdl *hdl;
1.23    ! edd       313:        struct sioctl_hdl *ctlhdl;
        !           314:        unsigned int mode;
1.16      ratchov   315:
1.23    ! edd       316:        if (!dev_sio_openlist(d, &hdl, &ctlhdl, &mode))
1.16      ratchov   317:                return 0;
                    318:
                    319:        sio_initpar(&par);
                    320:        par.bits = d->par.bits;
                    321:        par.bps = d->par.bps;
                    322:        par.sig = d->par.sig;
                    323:        par.le = d->par.le;
                    324:        par.msb = d->par.msb;
1.23    ! edd       325:        if (mode & SIO_PLAY)
        !           326:                par.pchan = d->reqpchan;
        !           327:        if (mode & SIO_REC)
        !           328:                par.rchan = d->reqrchan;
1.16      ratchov   329:        par.appbufsz = d->bufsz;
                    330:        par.round = d->round;
                    331:        par.rate = d->rate;
                    332:        if (!sio_setpar(hdl, &par))
                    333:                goto bad_close;
                    334:        if (!sio_getpar(hdl, &par))
                    335:                goto bad_close;
                    336:
                    337:        /* check if new parameters are compatible with old ones */
                    338:        if (par.round != d->round || par.bufsz != d->bufsz ||
                    339:            par.rate != d->rate) {
                    340:                if (log_level >= 1) {
                    341:                        dev_log(d);
                    342:                        log_puts(": alternate device not compatible\n");
                    343:                }
                    344:                goto bad_close;
                    345:        }
                    346:
                    347:        /* close unused device */
                    348:        timo_del(&d->sio.watchdog);
                    349:        file_del(d->sio.file);
                    350:        sio_close(d->sio.hdl);
1.18      ratchov   351:        if (d->sioctl.hdl) {
1.19      ratchov   352:                file_del(d->sioctl.file);
1.18      ratchov   353:                sioctl_close(d->sioctl.hdl);
                    354:                d->sioctl.hdl = NULL;
                    355:        }
1.16      ratchov   356:
                    357:        /* update parameters */
1.23    ! edd       358:        d->mode = mode;
1.16      ratchov   359:        d->par.bits = par.bits;
                    360:        d->par.bps = par.bps;
                    361:        d->par.sig = par.sig;
                    362:        d->par.le = par.le;
                    363:        d->par.msb = par.msb;
                    364:        if (d->mode & SIO_PLAY)
                    365:                d->pchan = par.pchan;
                    366:        if (d->mode & SIO_REC)
                    367:                d->rchan = par.rchan;
                    368:
                    369:        d->sio.hdl = hdl;
1.18      ratchov   370:        d->sioctl.hdl = ctlhdl;
1.16      ratchov   371:        d->sio.file = file_new(&dev_sio_ops, d, "dev", sio_nfds(hdl));
1.19      ratchov   372:        if (d->sioctl.hdl) {
                    373:                d->sioctl.file = file_new(&dev_sioctl_ops, d, "mix",
                    374:                    sioctl_nfds(ctlhdl));
                    375:        }
1.16      ratchov   376:        sio_onmove(hdl, dev_sio_onmove, d);
                    377:        return 1;
                    378: bad_close:
                    379:        sio_close(hdl);
1.18      ratchov   380:        if (ctlhdl)
                    381:                sioctl_close(ctlhdl);
1.16      ratchov   382:        return 0;
                    383: }
                    384:
1.1       ratchov   385: void
                    386: dev_sio_close(struct dev *d)
                    387: {
1.18      ratchov   388:        dev_sioctl_close(d);
1.1       ratchov   389: #ifdef DEBUG
                    390:        if (log_level >= 3) {
                    391:                dev_log(d);
                    392:                log_puts(": closed\n");
                    393:        }
                    394: #endif
1.7       ratchov   395:        timo_del(&d->sio.watchdog);
1.1       ratchov   396:        file_del(d->sio.file);
1.11      ratchov   397:        sio_close(d->sio.hdl);
1.18      ratchov   398:        if (d->sioctl.hdl) {
1.19      ratchov   399:                file_del(d->sioctl.file);
1.18      ratchov   400:                sioctl_close(d->sioctl.hdl);
                    401:                d->sioctl.hdl = NULL;
                    402:        }
1.21      ratchov   403:        d->alt_num = -1;
1.1       ratchov   404: }
                    405:
                    406: void
                    407: dev_sio_start(struct dev *d)
                    408: {
                    409:        if (!sio_start(d->sio.hdl)) {
                    410:                if (log_level >= 1) {
                    411:                        dev_log(d);
                    412:                        log_puts(": failed to start device\n");
                    413:                }
                    414:                return;
                    415:        }
                    416:        if (d->mode & MODE_PLAY) {
                    417:                d->sio.cstate = DEV_SIO_CYCLE;
                    418:                d->sio.todo = 0;
                    419:        } else {
                    420:                d->sio.cstate = DEV_SIO_READ;
                    421:                d->sio.todo = d->round * d->rchan * d->par.bps;
                    422:        }
                    423: #ifdef DEBUG
                    424:        d->sio.pused = 0;
                    425:        d->sio.rused = 0;
                    426:        d->sio.sum_utime = 0;
                    427:        d->sio.sum_wtime = 0;
                    428:        d->sio.wtime = file_wtime;
                    429:        d->sio.utime = file_utime;
                    430:        if (log_level >= 3) {
                    431:                dev_log(d);
                    432:                log_puts(": started\n");
                    433:        }
                    434: #endif
1.2       ratchov   435:        timo_add(&d->sio.watchdog, WATCHDOG_USEC);
1.1       ratchov   436: }
                    437:
                    438: void
                    439: dev_sio_stop(struct dev *d)
                    440: {
                    441:        if (!sio_eof(d->sio.hdl) && !sio_stop(d->sio.hdl)) {
                    442:                if (log_level >= 1) {
                    443:                        dev_log(d);
                    444:                        log_puts(": failed to stop device\n");
                    445:                }
                    446:                return;
                    447:        }
                    448: #ifdef DEBUG
                    449:        if (log_level >= 3) {
                    450:                dev_log(d);
                    451:                log_puts(": stopped, load avg = ");
                    452:                log_puti(d->sio.sum_utime / 1000);
                    453:                log_puts(" / ");
                    454:                log_puti(d->sio.sum_wtime / 1000);
                    455:                log_puts("\n");
                    456:        }
                    457: #endif
1.2       ratchov   458:        timo_del(&d->sio.watchdog);
1.1       ratchov   459: }
                    460:
                    461: int
                    462: dev_sio_pollfd(void *arg, struct pollfd *pfd)
                    463: {
                    464:        struct dev *d = arg;
                    465:        int events;
1.11      ratchov   466:
1.1       ratchov   467:        events = (d->sio.cstate == DEV_SIO_READ) ? POLLIN : POLLOUT;
                    468:        return sio_pollfd(d->sio.hdl, pfd, events);
                    469: }
                    470:
                    471: int
                    472: dev_sio_revents(void *arg, struct pollfd *pfd)
                    473: {
                    474:        struct dev *d = arg;
                    475:        int events;
                    476:
                    477:        events = sio_revents(d->sio.hdl, pfd);
                    478: #ifdef DEBUG
                    479:        d->sio.events = events;
                    480: #endif
                    481:        return events;
                    482: }
                    483:
                    484: void
                    485: dev_sio_run(void *arg)
                    486: {
                    487:        struct dev *d = arg;
                    488:        unsigned char *data, *base;
                    489:        unsigned int n;
                    490:
                    491:        /*
                    492:         * sio_read() and sio_write() would block at the end of the
                    493:         * cycle so we *must* return and restart poll()'ing. Otherwise
                    494:         * we may trigger dev_cycle() which would make all clients
                    495:         * underrun (ex, on a play-only device)
                    496:         */
                    497:        for (;;) {
                    498:                if (d->pstate != DEV_RUN)
                    499:                        return;
                    500:                switch (d->sio.cstate) {
                    501:                case DEV_SIO_READ:
                    502: #ifdef DEBUG
                    503:                        if (!(d->sio.events & POLLIN)) {
                    504:                                dev_log(d);
                    505:                                log_puts(": recording, but POLLIN not set\n");
                    506:                                panic();
                    507:                        }
                    508:                        if (d->sio.todo == 0) {
                    509:                                dev_log(d);
                    510:                                log_puts(": can't read data\n");
                    511:                                panic();
                    512:                        }
                    513:                        if (d->prime > 0) {
                    514:                                dev_log(d);
                    515:                                log_puts(": unexpected data\n");
                    516:                                panic();
                    517:                        }
                    518: #endif
                    519:                        base = d->decbuf ? d->decbuf : (unsigned char *)d->rbuf;
                    520:                        data = base +
                    521:                            d->rchan * d->round * d->par.bps -
                    522:                            d->sio.todo;
                    523:                        n = sio_read(d->sio.hdl, data, d->sio.todo);
                    524:                        d->sio.todo -= n;
                    525: #ifdef DEBUG
                    526:                        if (log_level >= 4) {
                    527:                                dev_log(d);
                    528:                                log_puts(": read ");
                    529:                                log_putu(n);
                    530:                                log_puts(": bytes, todo ");
                    531:                                log_putu(d->sio.todo);
                    532:                                log_puts("/");
                    533:                                log_putu(d->round * d->rchan * d->par.bps);
                    534:                                log_puts("\n");
                    535:                        }
                    536: #endif
                    537:                        if (d->sio.todo > 0)
                    538:                                return;
                    539: #ifdef DEBUG
                    540:                        d->sio.rused -= d->round;
                    541:                        if (log_level >= 2) {
                    542:                                if (d->sio.rused >= d->round) {
                    543:                                        dev_log(d);
                    544:                                        log_puts(": rec hw xrun, rused = ");
                    545:                                        log_puti(d->sio.rused);
                    546:                                        log_puts("/");
                    547:                                        log_puti(d->bufsz);
                    548:                                        log_puts("\n");
                    549:                                }
                    550:                                if (d->sio.rused < 0 ||
                    551:                                    d->sio.rused >= d->bufsz) {
                    552:                                        dev_log(d);
                    553:                                        log_puts(": out of bounds rused = ");
                    554:                                        log_puti(d->sio.rused);
                    555:                                        log_puts("/");
                    556:                                        log_puti(d->bufsz);
                    557:                                        log_puts("\n");
                    558:                                }
                    559:                        }
                    560: #endif
                    561:                        d->sio.cstate = DEV_SIO_CYCLE;
                    562:                        break;
                    563:                case DEV_SIO_CYCLE:
1.2       ratchov   564:                        timo_del(&d->sio.watchdog);
                    565:                        timo_add(&d->sio.watchdog, WATCHDOG_USEC);
                    566:
1.1       ratchov   567: #ifdef DEBUG
                    568:                        /*
                    569:                         * check that we're called at cycle boundary:
                    570:                         * either after a recorded block, or when POLLOUT is
                    571:                         * raised
                    572:                         */
                    573:                        if (!((d->mode & MODE_REC) && d->prime == 0) &&
                    574:                            !(d->sio.events & POLLOUT)) {
                    575:                                dev_log(d);
                    576:                                log_puts(": cycle not at block boundary\n");
                    577:                                panic();
                    578:                        }
                    579: #endif
                    580:                        dev_cycle(d);
                    581:                        if (d->mode & MODE_PLAY) {
                    582:                                d->sio.cstate = DEV_SIO_WRITE;
                    583:                                d->sio.todo = d->round * d->pchan * d->par.bps;
                    584:                                break;
                    585:                        } else {
                    586:                                d->sio.cstate = DEV_SIO_READ;
                    587:                                d->sio.todo = d->round * d->rchan * d->par.bps;
                    588:                                return;
                    589:                        }
                    590:                case DEV_SIO_WRITE:
                    591: #ifdef DEBUG
                    592:                        if (d->sio.todo == 0) {
                    593:                                dev_log(d);
                    594:                                log_puts(": can't write data\n");
                    595:                                panic();
                    596:                        }
                    597: #endif
                    598:                        base = d->encbuf ? d->encbuf : (unsigned char *)DEV_PBUF(d);
                    599:                        data = base +
                    600:                            d->pchan * d->round * d->par.bps -
                    601:                            d->sio.todo;
                    602:                        n = sio_write(d->sio.hdl, data, d->sio.todo);
                    603:                        d->sio.todo -= n;
                    604: #ifdef DEBUG
                    605:                        if (log_level >= 4) {
                    606:                                dev_log(d);
                    607:                                log_puts(": wrote ");
                    608:                                log_putu(n);
                    609:                                log_puts(" bytes, todo ");
                    610:                                log_putu(d->sio.todo);
                    611:                                log_puts("/");
                    612:                                log_putu(d->round * d->pchan * d->par.bps);
                    613:                                log_puts("\n");
                    614:                        }
                    615: #endif
                    616:                        if (d->sio.todo > 0)
                    617:                                return;
                    618: #ifdef DEBUG
                    619:                        d->sio.pused += d->round;
                    620:                        if (log_level >= 2) {
                    621:                                if (d->prime == 0 &&
                    622:                                    d->sio.pused <= d->bufsz - d->round) {
                    623:                                        dev_log(d);
                    624:                                        log_puts(": play hw xrun, pused = ");
                    625:                                        log_puti(d->sio.pused);
                    626:                                        log_puts("/");
                    627:                                        log_puti(d->bufsz);
                    628:                                        log_puts("\n");
                    629:                                }
                    630:                                if (d->sio.pused < 0 ||
                    631:                                    d->sio.pused > d->bufsz) {
                    632:                                        /* device driver or libsndio bug */
                    633:                                        dev_log(d);
                    634:                                        log_puts(": out of bounds pused = ");
                    635:                                        log_puti(d->sio.pused);
                    636:                                        log_puts("/");
                    637:                                        log_puti(d->bufsz);
                    638:                                        log_puts("\n");
                    639:                                }
                    640:                        }
                    641: #endif
                    642:                        d->poffs += d->round;
1.4       ratchov   643:                        if (d->poffs == d->psize)
1.1       ratchov   644:                                d->poffs = 0;
                    645:                        if ((d->mode & MODE_REC) && d->prime == 0) {
                    646:                                d->sio.cstate = DEV_SIO_READ;
                    647:                                d->sio.todo = d->round * d->rchan * d->par.bps;
                    648:                        } else
                    649:                                d->sio.cstate = DEV_SIO_CYCLE;
                    650:                        return;
                    651:                }
                    652:        }
                    653: }
                    654:
                    655: void
                    656: dev_sio_hup(void *arg)
                    657: {
                    658:        struct dev *d = arg;
                    659:
1.8       ratchov   660: #ifdef DEBUG
                    661:        if (log_level >= 2) {
                    662:                dev_log(d);
                    663:                log_puts(": disconnected\n");
                    664:        }
                    665: #endif
1.16      ratchov   666:        if (!dev_reopen(d))
1.20      ratchov   667:                dev_abort(d);
1.1       ratchov   668: }