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