[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.24

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