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

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