1*7b639200Sratchov /* $OpenBSD: siofile.c,v 1.28 2024/12/20 07:35:56 ratchov Exp $ */ 287bc9f6aSratchov /* 387bc9f6aSratchov * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org> 487bc9f6aSratchov * 587bc9f6aSratchov * Permission to use, copy, modify, and distribute this software for any 687bc9f6aSratchov * purpose with or without fee is hereby granted, provided that the above 787bc9f6aSratchov * copyright notice and this permission notice appear in all copies. 887bc9f6aSratchov * 987bc9f6aSratchov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 1087bc9f6aSratchov * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1187bc9f6aSratchov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1287bc9f6aSratchov * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1387bc9f6aSratchov * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1487bc9f6aSratchov * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1587bc9f6aSratchov * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1687bc9f6aSratchov */ 1787bc9f6aSratchov #include <sys/time.h> 1887bc9f6aSratchov #include <sys/types.h> 1987bc9f6aSratchov 2087bc9f6aSratchov #include <poll.h> 2187bc9f6aSratchov #include <sndio.h> 2287bc9f6aSratchov #include <stdio.h> 2387bc9f6aSratchov #include <stdlib.h> 2487bc9f6aSratchov #include <string.h> 2587bc9f6aSratchov 2687bc9f6aSratchov #include "abuf.h" 2787bc9f6aSratchov #include "defs.h" 2887bc9f6aSratchov #include "dev.h" 29d07fece6Sratchov #include "dev_sioctl.h" 3087bc9f6aSratchov #include "dsp.h" 31395f8c55Sratchov #include "fdpass.h" 3287bc9f6aSratchov #include "file.h" 3387bc9f6aSratchov #include "siofile.h" 3487bc9f6aSratchov #include "utils.h" 3587bc9f6aSratchov 36b4234b19Sratchov #define WATCHDOG_USEC 4000000 /* 4 seconds */ 37d135469bSratchov 38fcda7a7eSratchov void dev_sio_onmove(void *, int); 39fcda7a7eSratchov void dev_sio_timeout(void *); 4087bc9f6aSratchov int dev_sio_pollfd(void *, struct pollfd *); 4187bc9f6aSratchov int dev_sio_revents(void *, struct pollfd *); 4287bc9f6aSratchov void dev_sio_run(void *); 4387bc9f6aSratchov void dev_sio_hup(void *); 4487bc9f6aSratchov 45bbbe65dfSratchov extern struct fileops dev_sioctl_ops; 46bbbe65dfSratchov 4787bc9f6aSratchov struct fileops dev_sio_ops = { 4887bc9f6aSratchov "sio", 4987bc9f6aSratchov dev_sio_pollfd, 5087bc9f6aSratchov dev_sio_revents, 5187bc9f6aSratchov dev_sio_run, 5287bc9f6aSratchov dev_sio_run, 5387bc9f6aSratchov dev_sio_hup 5487bc9f6aSratchov }; 5587bc9f6aSratchov 5687bc9f6aSratchov void 5787bc9f6aSratchov dev_sio_onmove(void *arg, int delta) 5887bc9f6aSratchov { 5987bc9f6aSratchov struct dev *d = arg; 6087bc9f6aSratchov 6187bc9f6aSratchov #ifdef DEBUG 62*7b639200Sratchov logx(4, "%s: tick, delta = %d", d->path, delta); 63*7b639200Sratchov 6487bc9f6aSratchov d->sio.sum_utime += file_utime - d->sio.utime; 6587bc9f6aSratchov d->sio.sum_wtime += file_wtime - d->sio.wtime; 6687bc9f6aSratchov d->sio.wtime = file_wtime; 6787bc9f6aSratchov d->sio.utime = file_utime; 6887bc9f6aSratchov if (d->mode & MODE_PLAY) 6987bc9f6aSratchov d->sio.pused -= delta; 7087bc9f6aSratchov if (d->mode & MODE_REC) 7187bc9f6aSratchov d->sio.rused += delta; 7287bc9f6aSratchov #endif 7387bc9f6aSratchov dev_onmove(d, delta); 7487bc9f6aSratchov } 7587bc9f6aSratchov 76d135469bSratchov void 77d135469bSratchov dev_sio_timeout(void *arg) 78d135469bSratchov { 79d135469bSratchov struct dev *d = arg; 80d135469bSratchov 81*7b639200Sratchov logx(1, "%s: watchdog timeout", d->path); 822435013dSratchov dev_migrate(d); 834a2af8d6Sratchov dev_abort(d); 84d135469bSratchov } 85d135469bSratchov 8636355b88Sratchov /* 8736355b88Sratchov * open the device. 8836355b88Sratchov */ 8936355b88Sratchov int 9036355b88Sratchov dev_sio_open(struct dev *d) 91bd94a039Sedd { 9236355b88Sratchov struct sio_par par; 9336355b88Sratchov unsigned int rate, mode = d->reqmode & (SIO_PLAY | SIO_REC); 94bd94a039Sedd 9536355b88Sratchov d->sio.hdl = fdpass_sio_open(d->num, mode); 9636355b88Sratchov if (d->sio.hdl == NULL) { 97bd94a039Sedd if (mode != (SIO_PLAY | SIO_REC)) 98bd94a039Sedd return 0; 9936355b88Sratchov d->sio.hdl = fdpass_sio_open(d->num, SIO_PLAY); 10036355b88Sratchov if (d->sio.hdl != NULL) 101bd94a039Sedd mode = SIO_PLAY; 102bd94a039Sedd else { 10336355b88Sratchov d->sio.hdl = fdpass_sio_open(d->num, SIO_REC); 10436355b88Sratchov if (d->sio.hdl != NULL) 105bd94a039Sedd mode = SIO_REC; 106bd94a039Sedd else 107bd94a039Sedd return 0; 108bd94a039Sedd } 109*7b639200Sratchov logx(1, "%s: warning, device opened in %s mode", 110*7b639200Sratchov d->path, mode == SIO_PLAY ? "play-only" : "rec-only"); 111bd94a039Sedd } 11236355b88Sratchov d->mode = mode; 113bd94a039Sedd 11436355b88Sratchov d->sioctl.hdl = fdpass_sioctl_open(d->num, SIOCTL_READ | SIOCTL_WRITE); 115*7b639200Sratchov if (d->sioctl.hdl == NULL) 116*7b639200Sratchov logx(1, "%s: no control device", d->path); 117bd94a039Sedd 11887bc9f6aSratchov sio_initpar(&par); 11987bc9f6aSratchov par.bits = d->par.bits; 12087bc9f6aSratchov par.bps = d->par.bps; 12187bc9f6aSratchov par.sig = d->par.sig; 12287bc9f6aSratchov par.le = d->par.le; 12387bc9f6aSratchov par.msb = d->par.msb; 124bd94a039Sedd if (d->mode & SIO_PLAY) 12587bc9f6aSratchov par.pchan = d->pchan; 126bd94a039Sedd if (d->mode & SIO_REC) 12787bc9f6aSratchov par.rchan = d->rchan; 12887bc9f6aSratchov par.appbufsz = d->bufsz; 12987bc9f6aSratchov par.round = d->round; 13087bc9f6aSratchov par.rate = d->rate; 13187bc9f6aSratchov if (!sio_setpar(d->sio.hdl, &par)) 13287bc9f6aSratchov goto bad_close; 13387bc9f6aSratchov if (!sio_getpar(d->sio.hdl, &par)) 13487bc9f6aSratchov goto bad_close; 1354285a83aSratchov 13636355b88Sratchov /* 13736355b88Sratchov * If the requested rate is not supported by the device, 13836355b88Sratchov * use the new one, but retry using a block size that would 13936355b88Sratchov * match the requested one 14036355b88Sratchov */ 14136355b88Sratchov rate = par.rate; 14236355b88Sratchov if (rate != d->rate) { 14336355b88Sratchov sio_initpar(&par); 14436355b88Sratchov par.bits = d->par.bits; 14536355b88Sratchov par.bps = d->par.bps; 14636355b88Sratchov par.sig = d->par.sig; 14736355b88Sratchov par.le = d->par.le; 14836355b88Sratchov par.msb = d->par.msb; 14936355b88Sratchov if (mode & SIO_PLAY) 15036355b88Sratchov par.pchan = d->reqpchan; 15136355b88Sratchov if (mode & SIO_REC) 15236355b88Sratchov par.rchan = d->reqrchan; 15336355b88Sratchov par.appbufsz = d->bufsz * rate / d->rate; 15436355b88Sratchov par.round = d->round * rate / d->rate; 15536355b88Sratchov par.rate = rate; 15636355b88Sratchov if (!sio_setpar(d->sio.hdl, &par)) 15736355b88Sratchov goto bad_close; 15836355b88Sratchov if (!sio_getpar(d->sio.hdl, &par)) 15936355b88Sratchov goto bad_close; 16036355b88Sratchov } 16136355b88Sratchov 1624285a83aSratchov #ifdef DEBUG 1634285a83aSratchov /* 1647c71888cSratchov * We support any parameter combination exposed by the kernel, 1654285a83aSratchov * and we have no other choice than trusting the kernel for 1664285a83aSratchov * returning correct parameters. But let's check parameters 1674285a83aSratchov * early and nicely report kernel bugs rather than crashing 1684285a83aSratchov * later in memset(), malloc() or alike. 1694285a83aSratchov */ 1704285a83aSratchov 1714285a83aSratchov if (par.bits > BITS_MAX) { 172*7b639200Sratchov logx(0, "%s: %u: unsupported number of bits", d->path, par.bits); 1734285a83aSratchov goto bad_close; 1744285a83aSratchov } 1754285a83aSratchov if (par.bps > SIO_BPS(BITS_MAX)) { 176*7b639200Sratchov logx(0, "%s: %u: unsupported sample size", d->path, par.bps); 1774285a83aSratchov goto bad_close; 1784285a83aSratchov } 179bd94a039Sedd if ((d->mode & SIO_PLAY) && par.pchan > NCHAN_MAX) { 180*7b639200Sratchov logx(0, "%s: %u: unsupported number of play channels", d->path, par.pchan); 1814285a83aSratchov goto bad_close; 1824285a83aSratchov } 183bd94a039Sedd if ((d->mode & SIO_REC) && par.rchan > NCHAN_MAX) { 184*7b639200Sratchov logx(0, "%s: %u: unsupported number of rec channels", d->path, par.rchan); 1854285a83aSratchov goto bad_close; 1864285a83aSratchov } 1874285a83aSratchov if (par.bufsz == 0 || par.bufsz > RATE_MAX) { 188*7b639200Sratchov logx(0, "%s: %u: unsupported buffer size", d->path, par.bufsz); 1894285a83aSratchov goto bad_close; 1904285a83aSratchov } 1914285a83aSratchov if (par.round == 0 || par.round > par.bufsz || 1924285a83aSratchov par.bufsz % par.round != 0) { 193*7b639200Sratchov logx(0, "%s: %u: unsupported block size", d->path, par.round); 1944285a83aSratchov goto bad_close; 1954285a83aSratchov } 1964285a83aSratchov if (par.rate == 0 || par.rate > RATE_MAX) { 197*7b639200Sratchov logx(0, "%s: %u: unsupported rate", d->path, par.rate); 1984285a83aSratchov goto bad_close; 1994285a83aSratchov } 2004285a83aSratchov #endif 20187bc9f6aSratchov d->par.bits = par.bits; 20287bc9f6aSratchov d->par.bps = par.bps; 20387bc9f6aSratchov d->par.sig = par.sig; 20487bc9f6aSratchov d->par.le = par.le; 20587bc9f6aSratchov d->par.msb = par.msb; 206bd94a039Sedd if (d->mode & SIO_PLAY) 20787bc9f6aSratchov d->pchan = par.pchan; 208bd94a039Sedd if (d->mode & SIO_REC) 20987bc9f6aSratchov d->rchan = par.rchan; 21087bc9f6aSratchov d->bufsz = par.bufsz; 21187bc9f6aSratchov d->round = par.round; 21287bc9f6aSratchov d->rate = par.rate; 213bd94a039Sedd if (d->mode & MODE_PLAY) 214bd94a039Sedd d->mode |= MODE_MON; 21587bc9f6aSratchov sio_onmove(d->sio.hdl, dev_sio_onmove, d); 216731605d7Sratchov d->sio.file = file_new(&dev_sio_ops, d, "dev", sio_nfds(d->sio.hdl)); 217bbbe65dfSratchov if (d->sioctl.hdl) { 218bbbe65dfSratchov d->sioctl.file = file_new(&dev_sioctl_ops, d, "mix", 219bbbe65dfSratchov sioctl_nfds(d->sioctl.hdl)); 220bbbe65dfSratchov } 221d135469bSratchov timo_set(&d->sio.watchdog, dev_sio_timeout, d); 222d07fece6Sratchov dev_sioctl_open(d); 22387bc9f6aSratchov return 1; 22487bc9f6aSratchov bad_close: 22587bc9f6aSratchov sio_close(d->sio.hdl); 226d07fece6Sratchov if (d->sioctl.hdl) { 227d07fece6Sratchov sioctl_close(d->sioctl.hdl); 228d07fece6Sratchov d->sioctl.hdl = NULL; 229d07fece6Sratchov } 23087bc9f6aSratchov return 0; 23187bc9f6aSratchov } 23287bc9f6aSratchov 23387bc9f6aSratchov void 23487bc9f6aSratchov dev_sio_close(struct dev *d) 23587bc9f6aSratchov { 236d07fece6Sratchov dev_sioctl_close(d); 23787bc9f6aSratchov #ifdef DEBUG 238*7b639200Sratchov logx(3, "%s: closed", d->path); 23987bc9f6aSratchov #endif 24059613df7Sratchov timo_del(&d->sio.watchdog); 24187bc9f6aSratchov file_del(d->sio.file); 24287bc9f6aSratchov sio_close(d->sio.hdl); 243d07fece6Sratchov if (d->sioctl.hdl) { 244bbbe65dfSratchov file_del(d->sioctl.file); 245d07fece6Sratchov sioctl_close(d->sioctl.hdl); 246d07fece6Sratchov d->sioctl.hdl = NULL; 247d07fece6Sratchov } 24887bc9f6aSratchov } 24987bc9f6aSratchov 25087bc9f6aSratchov void 25187bc9f6aSratchov dev_sio_start(struct dev *d) 25287bc9f6aSratchov { 25387bc9f6aSratchov if (!sio_start(d->sio.hdl)) { 254*7b639200Sratchov logx(1, "%s: failed to start device", d->path); 25587bc9f6aSratchov return; 25687bc9f6aSratchov } 25787bc9f6aSratchov if (d->mode & MODE_PLAY) { 25887bc9f6aSratchov d->sio.cstate = DEV_SIO_CYCLE; 25987bc9f6aSratchov d->sio.todo = 0; 26087bc9f6aSratchov } else { 26187bc9f6aSratchov d->sio.cstate = DEV_SIO_READ; 26287bc9f6aSratchov d->sio.todo = d->round * d->rchan * d->par.bps; 26387bc9f6aSratchov } 26487bc9f6aSratchov #ifdef DEBUG 26587bc9f6aSratchov d->sio.pused = 0; 26687bc9f6aSratchov d->sio.rused = 0; 26787bc9f6aSratchov d->sio.sum_utime = 0; 26887bc9f6aSratchov d->sio.sum_wtime = 0; 26987bc9f6aSratchov d->sio.wtime = file_wtime; 27087bc9f6aSratchov d->sio.utime = file_utime; 271*7b639200Sratchov logx(3, "%s: started", d->path); 27287bc9f6aSratchov #endif 273d135469bSratchov timo_add(&d->sio.watchdog, WATCHDOG_USEC); 27487bc9f6aSratchov } 27587bc9f6aSratchov 27687bc9f6aSratchov void 27787bc9f6aSratchov dev_sio_stop(struct dev *d) 27887bc9f6aSratchov { 279ec8a3410Sratchov if (!sio_eof(d->sio.hdl) && !sio_flush(d->sio.hdl)) { 280*7b639200Sratchov logx(1, "%s: failed to stop device", d->path); 28187bc9f6aSratchov return; 28287bc9f6aSratchov } 28387bc9f6aSratchov #ifdef DEBUG 284*7b639200Sratchov logx(3, "%s: stopped, load avg = %lld / %lld", 285*7b639200Sratchov d->path, d->sio.sum_utime / 1000, d->sio.sum_wtime / 1000); 28687bc9f6aSratchov #endif 287d135469bSratchov timo_del(&d->sio.watchdog); 28887bc9f6aSratchov } 28987bc9f6aSratchov 29087bc9f6aSratchov int 29187bc9f6aSratchov dev_sio_pollfd(void *arg, struct pollfd *pfd) 29287bc9f6aSratchov { 29387bc9f6aSratchov struct dev *d = arg; 29487bc9f6aSratchov int events; 29587bc9f6aSratchov 29687bc9f6aSratchov events = (d->sio.cstate == DEV_SIO_READ) ? POLLIN : POLLOUT; 29787bc9f6aSratchov return sio_pollfd(d->sio.hdl, pfd, events); 29887bc9f6aSratchov } 29987bc9f6aSratchov 30087bc9f6aSratchov int 30187bc9f6aSratchov dev_sio_revents(void *arg, struct pollfd *pfd) 30287bc9f6aSratchov { 30387bc9f6aSratchov struct dev *d = arg; 30487bc9f6aSratchov int events; 30587bc9f6aSratchov 30687bc9f6aSratchov events = sio_revents(d->sio.hdl, pfd); 30787bc9f6aSratchov #ifdef DEBUG 30887bc9f6aSratchov d->sio.events = events; 30987bc9f6aSratchov #endif 31087bc9f6aSratchov return events; 31187bc9f6aSratchov } 31287bc9f6aSratchov 31387bc9f6aSratchov void 31487bc9f6aSratchov dev_sio_run(void *arg) 31587bc9f6aSratchov { 31687bc9f6aSratchov struct dev *d = arg; 31787bc9f6aSratchov unsigned char *data, *base; 31887bc9f6aSratchov unsigned int n; 31987bc9f6aSratchov 32087bc9f6aSratchov /* 32187bc9f6aSratchov * sio_read() and sio_write() would block at the end of the 32287bc9f6aSratchov * cycle so we *must* return and restart poll()'ing. Otherwise 32387bc9f6aSratchov * we may trigger dev_cycle() which would make all clients 32487bc9f6aSratchov * underrun (ex, on a play-only device) 32587bc9f6aSratchov */ 32687bc9f6aSratchov for (;;) { 32787bc9f6aSratchov if (d->pstate != DEV_RUN) 32887bc9f6aSratchov return; 32987bc9f6aSratchov switch (d->sio.cstate) { 33087bc9f6aSratchov case DEV_SIO_READ: 33187bc9f6aSratchov #ifdef DEBUG 33287bc9f6aSratchov if (!(d->sio.events & POLLIN)) { 333*7b639200Sratchov logx(0, "%s: recording, but POLLIN not set", d->path); 33487bc9f6aSratchov panic(); 33587bc9f6aSratchov } 33687bc9f6aSratchov if (d->sio.todo == 0) { 337*7b639200Sratchov logx(0, "%s: can't read data", d->path); 33887bc9f6aSratchov panic(); 33987bc9f6aSratchov } 34087bc9f6aSratchov if (d->prime > 0) { 341*7b639200Sratchov logx(0, "%s: unexpected data", d->path); 34287bc9f6aSratchov panic(); 34387bc9f6aSratchov } 34487bc9f6aSratchov #endif 34587bc9f6aSratchov base = d->decbuf ? d->decbuf : (unsigned char *)d->rbuf; 34687bc9f6aSratchov data = base + 34787bc9f6aSratchov d->rchan * d->round * d->par.bps - 34887bc9f6aSratchov d->sio.todo; 34987bc9f6aSratchov n = sio_read(d->sio.hdl, data, d->sio.todo); 35087bc9f6aSratchov d->sio.todo -= n; 35187bc9f6aSratchov #ifdef DEBUG 352*7b639200Sratchov logx(4, "%s: read %u bytes, todo %u / %u", d->path, 353*7b639200Sratchov n, d->sio.todo, d->round * d->rchan * d->par.bps); 35487bc9f6aSratchov #endif 35587bc9f6aSratchov if (d->sio.todo > 0) 35687bc9f6aSratchov return; 35787bc9f6aSratchov #ifdef DEBUG 35887bc9f6aSratchov d->sio.rused -= d->round; 35987bc9f6aSratchov if (d->sio.rused >= d->round) { 360*7b639200Sratchov logx(2, "%s: rec hw xrun, rused = %d / %d", 361*7b639200Sratchov d->path, d->sio.rused, d->bufsz); 36287bc9f6aSratchov } 36387bc9f6aSratchov #endif 36487bc9f6aSratchov d->sio.cstate = DEV_SIO_CYCLE; 36587bc9f6aSratchov break; 36687bc9f6aSratchov case DEV_SIO_CYCLE: 367d135469bSratchov timo_del(&d->sio.watchdog); 368d135469bSratchov timo_add(&d->sio.watchdog, WATCHDOG_USEC); 369d135469bSratchov 37087bc9f6aSratchov #ifdef DEBUG 37187bc9f6aSratchov /* 37287bc9f6aSratchov * check that we're called at cycle boundary: 37387bc9f6aSratchov * either after a recorded block, or when POLLOUT is 37487bc9f6aSratchov * raised 37587bc9f6aSratchov */ 37687bc9f6aSratchov if (!((d->mode & MODE_REC) && d->prime == 0) && 37787bc9f6aSratchov !(d->sio.events & POLLOUT)) { 378*7b639200Sratchov logx(0, "%s: cycle not at block boundary", d->path); 37987bc9f6aSratchov panic(); 38087bc9f6aSratchov } 38187bc9f6aSratchov #endif 38287bc9f6aSratchov dev_cycle(d); 38387bc9f6aSratchov if (d->mode & MODE_PLAY) { 38487bc9f6aSratchov d->sio.cstate = DEV_SIO_WRITE; 38587bc9f6aSratchov d->sio.todo = d->round * d->pchan * d->par.bps; 38687bc9f6aSratchov break; 38787bc9f6aSratchov } else { 38887bc9f6aSratchov d->sio.cstate = DEV_SIO_READ; 38987bc9f6aSratchov d->sio.todo = d->round * d->rchan * d->par.bps; 39087bc9f6aSratchov return; 39187bc9f6aSratchov } 39287bc9f6aSratchov case DEV_SIO_WRITE: 39387bc9f6aSratchov #ifdef DEBUG 39487bc9f6aSratchov if (d->sio.todo == 0) { 395*7b639200Sratchov logx(0, "%s: can't write data", d->path); 39687bc9f6aSratchov panic(); 39787bc9f6aSratchov } 39887bc9f6aSratchov #endif 39987bc9f6aSratchov base = d->encbuf ? d->encbuf : (unsigned char *)DEV_PBUF(d); 40087bc9f6aSratchov data = base + 40187bc9f6aSratchov d->pchan * d->round * d->par.bps - 40287bc9f6aSratchov d->sio.todo; 40387bc9f6aSratchov n = sio_write(d->sio.hdl, data, d->sio.todo); 40487bc9f6aSratchov d->sio.todo -= n; 40587bc9f6aSratchov #ifdef DEBUG 406*7b639200Sratchov logx(4, "%s: wrote %u bytes, todo %u / %u", 407*7b639200Sratchov d->path, n, d->sio.todo, d->round * d->pchan * d->par.bps); 40887bc9f6aSratchov #endif 40987bc9f6aSratchov if (d->sio.todo > 0) 41087bc9f6aSratchov return; 41187bc9f6aSratchov #ifdef DEBUG 41287bc9f6aSratchov d->sio.pused += d->round; 41387bc9f6aSratchov if (d->prime == 0 && 41487bc9f6aSratchov d->sio.pused <= d->bufsz - d->round) { 415*7b639200Sratchov logx(2, "%s: play hw xrun, pused = %d / %d", 416*7b639200Sratchov d->path, d->sio.pused, d->bufsz); 41787bc9f6aSratchov } 41887bc9f6aSratchov if (d->sio.pused < 0 || 41987bc9f6aSratchov d->sio.pused > d->bufsz) { 42087bc9f6aSratchov /* device driver or libsndio bug */ 421*7b639200Sratchov logx(2, "%s: out of bounds pused = %d / %d", 422*7b639200Sratchov d->path, d->sio.pused, d->bufsz); 42387bc9f6aSratchov } 42487bc9f6aSratchov #endif 42587bc9f6aSratchov d->poffs += d->round; 4268aadda71Sratchov if (d->poffs == d->psize) 42787bc9f6aSratchov d->poffs = 0; 42887bc9f6aSratchov if ((d->mode & MODE_REC) && d->prime == 0) { 42987bc9f6aSratchov d->sio.cstate = DEV_SIO_READ; 43087bc9f6aSratchov d->sio.todo = d->round * d->rchan * d->par.bps; 43187bc9f6aSratchov } else 43287bc9f6aSratchov d->sio.cstate = DEV_SIO_CYCLE; 43387bc9f6aSratchov return; 43487bc9f6aSratchov } 43587bc9f6aSratchov } 43687bc9f6aSratchov } 43787bc9f6aSratchov 43887bc9f6aSratchov void 43987bc9f6aSratchov dev_sio_hup(void *arg) 44087bc9f6aSratchov { 44187bc9f6aSratchov struct dev *d = arg; 44287bc9f6aSratchov 44346f2f343Sratchov #ifdef DEBUG 444*7b639200Sratchov logx(2, "%s: disconnected", d->path); 44546f2f343Sratchov #endif 44636355b88Sratchov dev_migrate(d); 4474a2af8d6Sratchov dev_abort(d); 44887bc9f6aSratchov } 449