1 /* $NetBSD: cdplay.c,v 1.42 2009/04/11 11:52:35 lukem Exp $ */ 2 3 /* 4 * Copyright (c) 1999, 2000, 2001 Andrew Doran. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 */ 29 30 /* 31 * Compact Disc Control Utility, originally by Serge V. Vakulenko 32 * <vak@cronyx.ru>. First appeared in FreeBSD under the guise of 33 * cdcontrol(1). Based on the non-X based CD player by Jean-Marc 34 * Zucconi and Andrey A. Chernov. Fixed and further modified on 35 * by Jukka Ukkonen <jau@funet.fi>. Lots of fixes and improvements 36 * made subsequently by The NetBSD Project. 37 * 38 * from FreeBSD: cdcontrol.c,v 1.17.2.1 1999/01/31 15:36:01 billf Exp 39 */ 40 41 #include <sys/cdefs.h> 42 #ifndef lint 43 __RCSID("$NetBSD: cdplay.c,v 1.42 2009/04/11 11:52:35 lukem Exp $"); 44 #endif /* not lint */ 45 46 #include <sys/types.h> 47 48 #include <sys/endian.h> 49 #include <sys/ioctl.h> 50 #include <sys/file.h> 51 #include <sys/cdio.h> 52 #include <sys/time.h> 53 #include <sys/audioio.h> 54 #include <sys/scsiio.h> 55 56 #include <assert.h> 57 58 #include <ctype.h> 59 #include <err.h> 60 #include <errno.h> 61 #include <histedit.h> 62 #include <limits.h> 63 #include <sched.h> 64 #include <signal.h> 65 #include <stdio.h> 66 #include <stdlib.h> 67 #include <string.h> 68 #include <unistd.h> 69 #include <util.h> 70 71 enum cmd { 72 CMD_CLOSE, 73 CMD_DIGITAL, 74 CMD_EJECT, 75 CMD_HELP, 76 CMD_INFO, 77 CMD_NEXT, 78 CMD_PAUSE, 79 CMD_PLAY, 80 CMD_PREV, 81 CMD_QUIT, 82 CMD_RESET, 83 CMD_RESUME, 84 CMD_SET, 85 CMD_SHUFFLE, 86 CMD_SINGLE, 87 CMD_SKIP, 88 CMD_STATUS, 89 CMD_STOP, 90 CMD_VOLUME, 91 }; 92 93 struct cmdtab { 94 enum cmd command; 95 const char *name; 96 unsigned int min; 97 const char *args; 98 } const cmdtab[] = { 99 { CMD_HELP, "?", 1, 0 }, 100 { CMD_CLOSE, "close", 1, NULL }, 101 { CMD_DIGITAL, "digital", 1, "fpw" }, 102 { CMD_EJECT, "eject", 1, NULL }, 103 { CMD_HELP, "help", 1, NULL }, 104 { CMD_INFO, "info", 1, NULL }, 105 { CMD_NEXT, "next", 1, NULL }, 106 { CMD_PAUSE, "pause", 2, NULL }, 107 { CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" }, 108 { CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" }, 109 { CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" }, 110 { CMD_PLAY, "play", 1, "[#block [len]]" }, 111 { CMD_PREV, "prev", 2, NULL }, 112 { CMD_QUIT, "quit", 1, NULL }, 113 { CMD_RESET, "reset", 4, NULL }, 114 { CMD_RESUME, "resume", 4, NULL }, 115 { CMD_SET, "set", 2, "msf | lba" }, 116 { CMD_SHUFFLE, "shuffle", 2, NULL }, 117 { CMD_SINGLE, "single", 2, "[<track>]" }, 118 { CMD_SKIP, "skip", 2, NULL }, 119 { CMD_STATUS, "status", 3, NULL }, 120 { CMD_STOP, "stop", 3, NULL }, 121 { CMD_VOLUME, "volume", 1, "<l> <r>|left|right|mute|mono|stereo" }, 122 }; 123 124 #define IOCTL_SIMPLE(fd, ctl) \ 125 do { \ 126 if (ioctl((fd), (ctl)) >= 0) { \ 127 close(fd); \ 128 fd = -1; \ 129 } else \ 130 warn("ioctl(" #ctl ")");\ 131 } while (/* CONSTCOND */ 0) 132 133 #define CDDA_SIZE 2352 134 135 #define CD_MAX_TRACK 99 /* largest 2 digit BCD number */ 136 137 struct cd_toc_entry toc_buffer[CD_MAX_TRACK + 1]; 138 139 const char *cdname; 140 int fd = -1; 141 int msf = 1; 142 int shuffle; 143 int interactive = 1; 144 int digital = 0; 145 int tbvalid = 0; 146 struct itimerval itv_timer; 147 struct { 148 const char *auname; 149 u_char *audata, *aubuf; 150 int afd; 151 int fpw; 152 int lba_start, lba_end, lba_current; 153 int lowat, hiwat, readseek, playseek; 154 int playing, changed; 155 int read_errors; 156 } da; 157 158 History *hist; 159 HistEvent he; 160 EditLine *elptr; 161 162 int get_vol(int *, int *); 163 int get_status(int *, int *, int *, int *, int *); 164 void help(void); 165 int info(const char *); 166 void lba2msf(u_long, u_int *, u_int *, u_int *); 167 int main(int, char **); 168 u_int msf2lba(u_int, u_int, u_int); 169 int opencd(void); 170 int openaudio(void); 171 const char *parse(char *, int *); 172 int play(const char *, int); 173 int play_blocks(int, int); 174 int play_digital(int, int); 175 int play_msf(int, int, int, int, int, int); 176 int play_track(int, int, int, int); 177 int print_status(const char *); 178 void print_track(struct cd_toc_entry *); 179 const char *prompt(void); 180 int readaudio(int, int, int, u_char *); 181 int read_toc_entrys(int); 182 int run(int, const char *); 183 int setvol(int, int); 184 void sig_timer(int); 185 int skip(int, int); 186 const char *strstatus(int); 187 void usage(void); 188 189 void toc2msf(u_int, u_int *, u_int *, u_int *); 190 int toc2lba(u_int); 191 void addmsf(u_int *, u_int *, u_int *, u_int, u_int, u_int); 192 193 int 194 main(int argc, char **argv) 195 { 196 const char *arg; 197 char buf[80], *p; 198 static char defdev[16]; 199 int cmd, len, c; 200 char *line; 201 const char *elline; 202 int scratch, rv; 203 struct sigaction sa_timer; 204 205 cdname = getenv("MUSIC_CD"); 206 if (cdname == NULL) 207 cdname = getenv("CD_DRIVE"); 208 if (cdname == NULL) 209 cdname = getenv("DISC"); 210 if (cdname == NULL) 211 cdname = getenv("CDPLAY"); 212 213 da.auname = getenv("AUDIODEV"); 214 if (!da.auname) 215 da.auname = getenv("SPEAKER"); 216 if (!da.auname) 217 da.auname = "/dev/sound"; 218 219 while ((c = getopt(argc, argv, "a:f:h")) != -1) 220 switch (c) { 221 case 'a': 222 da.auname = optarg; 223 continue; 224 case 'f': 225 cdname = optarg; 226 continue; 227 case 'h': 228 default: 229 usage(); 230 /* NOTREACHED */ 231 } 232 argc -= optind; 233 argv += optind; 234 235 if (argc > 0 && strcasecmp(*argv, "help") == 0) 236 usage(); 237 238 if (cdname == NULL) { 239 snprintf(defdev, sizeof(defdev), "cd0%c", 240 'a' + getrawpartition()); 241 cdname = defdev; 242 } 243 244 opencd(); 245 srandom((u_long)time(NULL)); 246 da.afd = -1; 247 248 if (argc > 0) { 249 interactive = 0; 250 for (p = buf; argc-- > 0; argv++) { 251 len = strlen(*argv); 252 253 if (p + len >= buf + sizeof(buf) - 1) 254 usage(); 255 if (p > buf) 256 *p++ = ' '; 257 258 strlcpy(p, *argv, sizeof(buf) - (p - buf)); 259 p += len; 260 } 261 *p = '\0'; 262 arg = parse(buf, &cmd); 263 return (run(cmd, arg)); 264 } 265 266 setbuf(stdout, NULL); 267 printf("Type `?' for command list\n\n"); 268 269 hist = history_init(); 270 history(hist, &he, H_SETSIZE, 100); /* 100 elt history buffer */ 271 elptr = el_init(getprogname(), stdin, stdout, stderr); 272 el_set(elptr, EL_EDITOR, "emacs"); 273 el_set(elptr, EL_PROMPT, prompt); 274 el_set(elptr, EL_HIST, history, hist); 275 el_set(elptr, EL_SIGNAL, 1); 276 el_source(elptr, NULL); 277 278 sigemptyset(&sa_timer.sa_mask); 279 sa_timer.sa_handler = sig_timer; 280 sa_timer.sa_flags = SA_RESTART; 281 if ((rv = sigaction(SIGALRM, &sa_timer, NULL)) < 0) 282 err(EXIT_FAILURE, "sigaction()"); 283 284 for (;;) { 285 line = NULL; 286 arg = NULL; 287 do { 288 if (((elline = el_gets(elptr, &scratch)) != NULL) 289 && (scratch != 0)){ 290 history(hist, &he, H_ENTER, elline); 291 line = strdup(elline); 292 if (line != NULL) { 293 arg = parse(line, &cmd); 294 free(line); 295 } 296 } else { 297 cmd = CMD_QUIT; 298 warnx("\r\n"); 299 arg = NULL; 300 break; 301 } 302 } while (arg == NULL); 303 304 if (run(cmd, arg) < 0) { 305 if (fd != -1) 306 close(fd); 307 fd = -1; 308 } 309 } 310 311 el_end(elptr); 312 history_end(hist); 313 exit(EXIT_SUCCESS); 314 /* NOTREACHED */ 315 } 316 317 void 318 usage(void) 319 { 320 321 fprintf(stderr, "usage: cdplay [-a audio_device] [-f cd_device] [command ...]\n"); 322 exit(EXIT_FAILURE); 323 /* NOTREACHED */ 324 } 325 326 void 327 help(void) 328 { 329 const struct cmdtab *c, *mc; 330 const char *s; 331 int i, n; 332 333 mc = cmdtab + sizeof(cmdtab) / sizeof(cmdtab[0]); 334 for (c = cmdtab; c < mc; c++) { 335 for (i = c->min, s = c->name; *s != '\0'; s++, i--) { 336 n = (i > 0 ? toupper((unsigned char)*s) : *s); 337 putchar(n); 338 } 339 if (c->args != NULL) 340 printf(" %s", c->args); 341 putchar('\n'); 342 } 343 printf( 344 "\nThe word \"play\" is not required for the play commands.\n" 345 "The plain target address is taken as a synonym for play.\n"); 346 } 347 348 int 349 run(int cmd, const char *arg) 350 { 351 int l, r, rv; 352 353 rv = 0; 354 if (cmd == CMD_QUIT) { 355 close(fd); 356 exit(EXIT_SUCCESS); 357 /* NOTREACHED */ 358 } 359 360 if (fd < 0 && !opencd()) 361 return (0); 362 363 switch (cmd) { 364 case CMD_INFO: 365 rv = info(arg); 366 break; 367 368 case CMD_STATUS: 369 rv = print_status(arg); 370 break; 371 372 case CMD_PAUSE: 373 if (digital) { 374 da.playing = 0; 375 return (0); 376 } else if ((rv = ioctl(fd, CDIOCPAUSE)) < 0) 377 warn("ioctl(CDIOCPAUSE)"); 378 break; 379 380 case CMD_RESUME: 381 if (digital) { 382 da.playing = 1; 383 return (0); 384 } else if ((rv = ioctl(fd, CDIOCRESUME)) < 0) 385 warn("ioctl(CDIOCRESUME)"); 386 break; 387 388 case CMD_STOP: 389 if (digital) { 390 da.playing = 0; 391 return (0); 392 } else { 393 if ((rv = ioctl(fd, CDIOCSTOP)) < 0) 394 warn("ioctl(CDIOCSTOP)"); 395 if (ioctl(fd, CDIOCALLOW) < 0) 396 warn("ioctl(CDIOCALLOW)"); 397 } 398 break; 399 400 case CMD_RESET: 401 tbvalid = 0; 402 IOCTL_SIMPLE(fd, CDIOCRESET); 403 return (0); 404 405 case CMD_EJECT: 406 tbvalid = 0; 407 if (digital) 408 da.playing = 0; 409 if (shuffle) 410 run(CMD_SHUFFLE, NULL); 411 if (ioctl(fd, CDIOCALLOW) < 0) 412 warn("ioctl(CDIOCALLOW)"); 413 IOCTL_SIMPLE(fd, CDIOCEJECT); 414 break; 415 416 case CMD_CLOSE: 417 ioctl(fd, CDIOCALLOW); 418 IOCTL_SIMPLE(fd, CDIOCCLOSE); 419 if (interactive && fd == -1) 420 opencd(); 421 break; 422 423 case CMD_PLAY: 424 while (isspace((unsigned char)*arg)) 425 arg++; 426 rv = play(arg, 1); 427 break; 428 429 case CMD_PREV: 430 rv = skip(-1, 1); 431 break; 432 433 case CMD_NEXT: 434 rv = skip(1, 1); 435 break; 436 437 case CMD_SINGLE: 438 if (interactive == 0) 439 errx(EXIT_FAILURE, 440 "'single' valid only in interactive mode"); 441 /*FALLTHROUGH*/ 442 case CMD_SHUFFLE: 443 if (interactive == 0) 444 errx(EXIT_FAILURE, 445 "`shuffle' valid only in interactive mode"); 446 if (shuffle == 0) { 447 if (digital == 0) { 448 itv_timer.it_interval.tv_sec = 1; 449 itv_timer.it_interval.tv_usec = 0; 450 itv_timer.it_value.tv_sec = 1; 451 itv_timer.it_value.tv_usec = 0; 452 if (setitimer(ITIMER_REAL, &itv_timer, NULL) == 0) { 453 if (cmd == CMD_SHUFFLE) { 454 shuffle = 1; 455 } else { 456 while (isspace((unsigned char)*arg)) 457 arg++; 458 shuffle = -atoi(arg); 459 } 460 } 461 } else 462 shuffle = cmd == CMD_SINGLE ? -atoi(arg) : 1; 463 /* 464 if (shuffle) 465 rv = skip(0, 1); 466 */ 467 } else { 468 if (digital == 0) { 469 itv_timer.it_interval.tv_sec = 0; 470 itv_timer.it_interval.tv_usec = 0; 471 itv_timer.it_value.tv_sec = 0; 472 itv_timer.it_value.tv_usec = 0; 473 setitimer(ITIMER_REAL, &itv_timer, NULL); 474 } 475 shuffle = 0; 476 } 477 if (shuffle < 0) 478 printf("single track:\t%d\n", -shuffle); 479 else 480 printf("shuffle play:\t%s\n", (shuffle != 0) ? "on" : "off"); 481 rv = 0; 482 break; 483 484 case CMD_DIGITAL: 485 if (digital == 0) { 486 int fpw, intv_usecs, hz_usecs; 487 488 fpw = atoi(arg); 489 if (fpw > 0) 490 da.fpw = fpw; 491 else 492 da.fpw = 5; 493 da.read_errors = 0; 494 495 /* real rate: 75 frames per second */ 496 intv_usecs = 13333 * da.fpw; 497 /* 498 * interrupt earlier for safety, by a value which 499 * doesn't hurt interactice response if we block 500 * in the signal handler 501 */ 502 intv_usecs -= 50000; 503 hz_usecs = 1000000 / sysconf(_SC_CLK_TCK); 504 if (intv_usecs < hz_usecs) { 505 /* can't have a shorter interval, increase 506 buffer size to compensate */ 507 da.fpw += (hz_usecs - intv_usecs) / 13333; 508 intv_usecs = hz_usecs; 509 } 510 511 da.aubuf = malloc(da.fpw * CDDA_SIZE); 512 if (da.aubuf == NULL) { 513 warn("Not enough memory for audio buffers"); 514 return (1); 515 } 516 if (da.afd == -1 && !openaudio()) { 517 warn("Cannot open audio device"); 518 return (1); 519 } 520 itv_timer.it_interval.tv_sec = itv_timer.it_value.tv_sec = 521 intv_usecs / 1000000; 522 itv_timer.it_interval.tv_usec = itv_timer.it_value.tv_usec = 523 intv_usecs % 1000000; 524 rv = setitimer(ITIMER_REAL, &itv_timer, NULL); 525 if (rv == 0) { 526 digital = 1; 527 } else 528 warnx("setitimer in CMD_DIGITAL"); 529 msf = 0; 530 tbvalid = 0; 531 } else { 532 if (shuffle == 1) 533 itv_timer.it_interval.tv_sec = itv_timer.it_value.tv_sec = 1; 534 else 535 itv_timer.it_interval.tv_sec = itv_timer.it_value.tv_sec = 0; 536 itv_timer.it_interval.tv_usec = itv_timer.it_value.tv_usec = 0; 537 digital = 0; 538 rv = setitimer(ITIMER_REAL, &itv_timer, NULL); 539 free(da.audata); 540 close(da.afd); 541 da.afd = -1; 542 } 543 return (0); 544 545 case CMD_SKIP: 546 if (!interactive) 547 errx(EXIT_FAILURE, 548 "`skip' valid only in interactive mode"); 549 if (!shuffle) 550 warnx("`skip' valid only in shuffle mode"); 551 else 552 skip(0, 1); 553 break; 554 555 case CMD_SET: 556 tbvalid = 0; 557 if (strcasecmp(arg, "msf") == 0) 558 msf = 1; 559 else if (strcasecmp(arg, "lba") == 0) 560 msf = 0; 561 else 562 warnx("invalid command arguments"); 563 break; 564 565 case CMD_VOLUME: 566 if (digital) { 567 rv = 0; 568 warnx("`volume' is ignored while in digital xfer mode"); 569 } else if (strncasecmp(arg, "left", strlen(arg)) == 0) 570 rv = ioctl(fd, CDIOCSETLEFT); 571 else if (strncasecmp(arg, "right", strlen(arg)) == 0) 572 rv = ioctl(fd, CDIOCSETRIGHT); 573 else if (strncasecmp(arg, "mono", strlen(arg)) == 0) 574 rv = ioctl(fd, CDIOCSETMONO); 575 else if (strncasecmp(arg, "stereo", strlen(arg)) == 0) 576 rv = ioctl(fd, CDIOCSETSTEREO); 577 else if (strncasecmp(arg, "mute", strlen(arg)) == 0) 578 rv = ioctl(fd, CDIOCSETMUTE); 579 else { 580 rv = 0; 581 if (sscanf(arg, "%d %d", &l, &r) != 2) { 582 if (sscanf(arg, "%d", &l) == 1) 583 r = l; 584 else { 585 warnx("invalid command arguments"); 586 break; 587 } 588 } 589 rv = setvol(l, r); 590 } 591 break; 592 593 case CMD_HELP: 594 default: 595 help(); 596 rv = 0; 597 break; 598 } 599 600 return (rv); 601 } 602 603 int 604 play(const char *arg, int fromuser) 605 { 606 int rv, start, end, istart, iend, blk, len, relend; 607 u_int n, tr1, tr2, m1, m2, s1, s2, f1, f2, tm, ts, tf; 608 struct ioc_toc_header h; 609 610 if (shuffle && fromuser) { 611 warnx("`play' not valid in shuffle mode"); 612 return (0); 613 } 614 615 if ((rv = ioctl(fd, CDIOREADTOCHEADER, &h)) < 0) { 616 warn("ioctl(CDIOREADTOCHEADER)"); 617 return (rv); 618 } 619 620 end = 0; 621 istart = iend = 1; 622 n = h.ending_track - h.starting_track + 1; 623 rv = read_toc_entrys((n + 1) * sizeof(struct cd_toc_entry)); 624 if (rv < 0) 625 return (rv); 626 627 if (arg == NULL || *arg == '\0') { 628 /* Play the whole disc */ 629 return (play_track(h.starting_track, 1, h.ending_track, 99)); 630 } 631 632 if (strchr(arg, '#') != NULL) { 633 /* Play block #blk [ len ] */ 634 len = 0; 635 636 if (2 != sscanf(arg, "#%d%d", &blk, &len) && 637 1 != sscanf(arg, "#%d", &blk)) 638 goto Clean_up; 639 640 if (len == 0) { 641 len = toc2lba(n); 642 } 643 return (play_blocks(blk, len)); 644 } 645 646 if (strchr(arg, ':') != NULL) { 647 /* 648 * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] 649 * 650 * Will now also undestand timed addresses relative 651 * to the beginning of a track in the form... 652 * 653 * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]] 654 */ 655 relend = 1; 656 tr2 = m2 = s2 = f2 = f1 = 0; 657 if (8 == sscanf(arg, "%d %d:%d.%d %d %d:%d.%d", &tr1, &m1, 658 &s1, &f1, &tr2, &m2, &s2, &f2)) 659 goto Play_Relative_Addresses; 660 661 tr2 = m2 = s2 = f2 = f1 = 0; 662 if (7 == sscanf(arg, "%d %d:%d %d %d:%d.%d", &tr1, &m1, &s1, 663 &tr2, &m2, &s2, &f2)) 664 goto Play_Relative_Addresses; 665 666 tr2 = m2 = s2 = f2 = f1 = 0; 667 if (7 == sscanf(arg, "%d %d:%d.%d %d %d:%d", &tr1, &m1, &s1, 668 &f1, &tr2, &m2, &s2)) 669 goto Play_Relative_Addresses; 670 671 tr2 = m2 = s2 = f2 = f1 = 0; 672 if (7 == sscanf(arg, "%d %d:%d.%d %d:%d.%d", &tr1, &m1, &s1, 673 &f1, &m2, &s2, &f2)) 674 goto Play_Relative_Addresses; 675 676 tr2 = m2 = s2 = f2 = f1 = 0; 677 if (6 == sscanf(arg, "%d %d:%d.%d %d:%d", &tr1, &m1, &s1, &f1, 678 &m2, &s2)) 679 goto Play_Relative_Addresses; 680 681 tr2 = m2 = s2 = f2 = f1 = 0; 682 if (6 == sscanf(arg, "%d %d:%d %d:%d.%d", &tr1, &m1, &s1, &m2, 683 &s2, &f2)) 684 goto Play_Relative_Addresses; 685 686 tr2 = m2 = s2 = f2 = f1 = 0; 687 if (6 == sscanf(arg, "%d %d:%d.%d %d %d", &tr1, &m1, &s1, &f1, 688 &tr2, &m2)) 689 goto Play_Relative_Addresses; 690 691 tr2 = m2 = s2 = f2 = f1 = 0; 692 if (6 == sscanf(arg, "%d %d:%d %d %d:%d", &tr1, &m1, &s1, &tr2, 693 &m2, &s2)) 694 goto Play_Relative_Addresses; 695 696 tr2 = m2 = s2 = f2 = f1 = 0; 697 if (5 == sscanf(arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, 698 &s2)) 699 goto Play_Relative_Addresses; 700 701 tr2 = m2 = s2 = f2 = f1 = 0; 702 if (5 == sscanf(arg, "%d %d:%d %d %d", &tr1, &m1, &s1, &tr2, 703 &m2)) 704 goto Play_Relative_Addresses; 705 706 relend=0; 707 tr2 = m2 = s2 = f2 = f1 = 0; 708 if (5 == sscanf(arg, "%d %d:%d.%d %d", &tr1, &m1, &s1, &f1, 709 &tr2)) 710 goto Play_Relative_Addresses; 711 712 tr2 = m2 = s2 = f2 = f1 = 0; 713 if (4 == sscanf(arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2)) 714 goto Play_Relative_Addresses; 715 716 tr2 = m2 = s2 = f2 = f1 = 0; 717 if (4 == sscanf(arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1)) 718 goto Play_Relative_Addresses; 719 720 tr2 = m2 = s2 = f2 = f1 = 0; 721 if (3 == sscanf(arg, "%d %d:%d", &tr1, &m1, &s1)) 722 goto Play_Relative_Addresses; 723 724 tr2 = m2 = s2 = f2 = f1 = 0; 725 goto Try_Absolute_Timed_Addresses; 726 727 Play_Relative_Addresses: 728 if (!tr1) 729 tr1 = 1; 730 else if (tr1 > n) 731 tr1 = n; 732 733 toc2msf(tr1-1, &tm, &ts, &tf); 734 addmsf(&m1, &s1, &f1, tm, ts, tf); 735 736 toc2msf(tr1, &tm, &ts, &tf); 737 738 if ((m1 > tm) || ((m1 == tm) && ((s1 > ts) || ((s1 == ts) && 739 (f1 > tf))))) { 740 warnx("Track %d is not that long.", tr1); 741 return (0); 742 } 743 tr1--; /* XXXXX ???? */ 744 745 746 if (!tr2) { 747 if (relend) { 748 tr2 = tr1; 749 750 addmsf(&m2, &s2, &f2, m1, s1, f1); 751 } else { 752 tr2 = n; 753 754 toc2msf(n, &m2, &s2, &f2); 755 } 756 } else { 757 if (tr2 > n) { 758 tr2 = n; 759 m2 = s2 = f2 = 0; 760 } else { 761 if (relend) 762 tr2--; 763 764 toc2msf(tr2, &tm, &ts, &tf); 765 addmsf(&m2, &s2, &f2, tm, ts, tf); 766 } 767 } 768 769 toc2msf(n, &tm, &ts, &tf); 770 771 if ((tr2 < n) && ((m2 > tm) || ((m2 == tm) && ((s2 > ts) || 772 ((s2 == ts) && (f2 > tf)))))) { 773 warnx("The playing time of the disc is not that long."); 774 return (0); 775 } 776 777 return (play_msf(m1, s1, f1, m2, s2, f2)); 778 779 Try_Absolute_Timed_Addresses: 780 m2 = UINT_MAX; 781 782 if (6 != sscanf(arg, "%d:%d.%d%d:%d.%d", 783 &m1, &s1, &f1, &m2, &s2, &f2) && 784 5 != sscanf(arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && 785 5 != sscanf(arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && 786 3 != sscanf(arg, "%d:%d.%d", &m1, &s1, &f1) && 787 4 != sscanf(arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && 788 2 != sscanf(arg, "%d:%d", &m1, &s1)) 789 goto Clean_up; 790 791 if (m2 == UINT_MAX) { 792 if (msf) { 793 m2 = toc_buffer[n].addr.msf.minute; 794 s2 = toc_buffer[n].addr.msf.second; 795 f2 = toc_buffer[n].addr.msf.frame; 796 } else { 797 lba2msf(toc_buffer[n].addr.lba, &tm, &ts, &tf); 798 m2 = tm; 799 s2 = ts; 800 f2 = tf; 801 } 802 } 803 return (play_msf(m1, s1, f1, m2, s2, f2)); 804 } 805 806 /* 807 * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] 808 */ 809 if (4 != sscanf(arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && 810 3 != sscanf(arg, "%d.%d%d", &start, &istart, &end) && 811 3 != sscanf(arg, "%d%d.%d", &start, &end, &iend) && 812 2 != sscanf(arg, "%d.%d", &start, &istart) && 813 2 != sscanf(arg, "%d%d", &start, &end) && 814 1 != sscanf(arg, "%d", &start)) 815 goto Clean_up; 816 817 if (end == 0) 818 end = n; 819 return (play_track(start, istart, end, iend)); 820 821 Clean_up: 822 warnx("invalid command arguments"); 823 return (0); 824 } 825 826 void 827 sig_timer(int sig) 828 { 829 int aulen, auwr, fpw; 830 sigset_t anymore; 831 832 sigpending(&anymore); 833 if (sigismember(&anymore, SIGALRM)) 834 return; 835 if (digital) { 836 if (!da.playing) 837 return; 838 if (da.changed) { 839 da.lba_current = da.lba_start; 840 da.changed = 0; 841 } 842 /* read frames into circular buffer */ 843 fpw = da.lba_end - da.lba_current + 1; 844 if (fpw > da.fpw) 845 fpw = da.fpw; 846 if (fpw > 0) { 847 aulen = readaudio(fd, da.lba_current, fpw, da.aubuf); 848 if (aulen > 0) { 849 auwr = write(da.afd, da.aubuf, aulen); 850 da.lba_current += fpw; 851 } 852 } 853 if (da.lba_current > da.lba_end) 854 da.playing = 0; 855 } 856 if (shuffle) 857 skip(0, 0); 858 #if 0 859 sched_yield(); 860 #endif 861 setitimer(ITIMER_REAL, &itv_timer, NULL); 862 } 863 864 int 865 skip(int dir, int fromuser) 866 { 867 char str[16]; 868 int rv, trk, idx, m, s, f; 869 struct ioc_toc_header h; 870 871 if ((rv = ioctl(fd, CDIOREADTOCHEADER, &h)) < 0) { 872 warn("ioctl(CDIOREADTOCHEADER)"); 873 return (rv); 874 } 875 if ((rv = get_status(&trk, &idx, &m, &s, &f)) < 0) 876 return (rv); 877 878 if (dir == 0 || shuffle != 0) { 879 if (fromuser || (rv != CD_AS_PLAY_IN_PROGRESS && 880 rv != CD_AS_PLAY_PAUSED)) 881 trk = shuffle < 0 ? (-shuffle) : 882 (int)((h.starting_track + 883 arc4random() % (h.ending_track - h.starting_track + 1))); 884 else 885 return (0); 886 } else { 887 trk += dir; 888 if (trk > h.ending_track) 889 trk = h.starting_track; 890 else if(trk < h.starting_track) 891 trk = h.ending_track; 892 } 893 894 if (shuffle) 895 snprintf(str, sizeof(str), "%d %d", trk, trk); 896 else 897 snprintf(str, sizeof(str), "%d", trk); 898 899 return (play(str, 0)); 900 } 901 902 const char * 903 strstatus(int sts) 904 { 905 const char *str; 906 907 switch (sts) { 908 case CD_AS_AUDIO_INVALID: 909 str = "invalid"; 910 break; 911 case CD_AS_PLAY_IN_PROGRESS: 912 str = "playing"; 913 break; 914 case CD_AS_PLAY_PAUSED: 915 str = "paused"; 916 break; 917 case CD_AS_PLAY_COMPLETED: 918 str = "completed"; 919 break; 920 case CD_AS_PLAY_ERROR: 921 str = "error"; 922 break; 923 case CD_AS_NO_STATUS: 924 str = "not playing"; 925 break; 926 default: 927 str = "<unknown>"; 928 break; 929 } 930 931 return (str); 932 } 933 934 int 935 print_status(const char *arg) 936 { 937 struct cd_sub_channel_info data; 938 struct ioc_read_subchannel ss; 939 int rv, trk, idx, m, s, f; 940 struct ioc_vol v; 941 942 if ((rv = get_status(&trk, &idx, &m, &s, &f)) >= 0) { 943 printf("audio status:\t%s\n", strstatus(rv)); 944 printf("current track:\t%d\n", trk); 945 if (!digital) 946 printf("current index:\t%d\n", idx); 947 printf("position:\t%d:%02d.%02d\n", m, s, f); 948 } else 949 printf("audio status:\tno info available\n"); 950 951 if (shuffle < 0) 952 printf("single track:\t%d\n", -shuffle); 953 else 954 printf("shuffle play:\t%s\n", (shuffle != 0) ? "on" : "off"); 955 if (digital) 956 printf("digital xfer:\tto %s " 957 "(%d frames per wakeup, %lld.%06lds period)\n", 958 da.auname, da.fpw, 959 (long long)itv_timer.it_interval.tv_sec, 960 961 (long)itv_timer.it_interval.tv_usec); 962 else 963 printf("digital xfer:\toff\n"); 964 965 bzero(&ss, sizeof(ss)); 966 ss.data = &data; 967 ss.data_len = sizeof(data); 968 ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 969 ss.data_format = CD_MEDIA_CATALOG; 970 971 if (!digital && ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &ss) >= 0) { 972 printf("media catalog:\t%sactive", 973 ss.data->what.media_catalog.mc_valid ? "" : "in"); 974 if (ss.data->what.media_catalog.mc_valid && 975 ss.data->what.media_catalog.mc_number[0]) 976 printf(" (%.15s)", 977 ss.data->what.media_catalog.mc_number); 978 putchar('\n'); 979 } else 980 printf("media catalog:\tnone\n"); 981 982 if (digital) 983 return (0); 984 if (ioctl(fd, CDIOCGETVOL, &v) >= 0) { 985 printf("left volume:\t%d\n", v.vol[0]); 986 printf("right volume:\t%d\n", v.vol[1]); 987 } else { 988 printf("left volume:\tnot available\n"); 989 printf("right volume:\tnot available\n"); 990 } 991 992 ; return (0); 993 } 994 995 int 996 info(const char *arg) 997 { 998 struct ioc_toc_header h; 999 int rc, i, n; 1000 1001 if ((rc = ioctl(fd, CDIOREADTOCHEADER, &h)) < 0) { 1002 warn("ioctl(CDIOREADTOCHEADER)"); 1003 return (rc); 1004 } 1005 1006 n = h.ending_track - h.starting_track + 1; 1007 rc = read_toc_entrys((n + 1) * sizeof(struct cd_toc_entry)); 1008 if (rc < 0) 1009 return (rc); 1010 1011 printf("track start duration block length type\n"); 1012 printf("--------------------------------------------------\n"); 1013 1014 for (i = 0; i < n; i++) { 1015 printf("%5d ", toc_buffer[i].track); 1016 print_track(toc_buffer + i); 1017 } 1018 printf(" - "); /* Lead-out area */ 1019 print_track(toc_buffer + n); 1020 return (0); 1021 } 1022 1023 void 1024 lba2msf(u_long lba, u_int *m, u_int *s, u_int *f) 1025 { 1026 1027 lba += 150; /* block start offset */ 1028 lba &= 0xffffff; /* negative lbas use only 24 bits */ 1029 *m = lba / (60 * 75); 1030 lba %= (60 * 75); 1031 *s = lba / 75; 1032 *f = lba % 75; 1033 } 1034 1035 u_int 1036 msf2lba(u_int m, u_int s, u_int f) 1037 { 1038 1039 return (((m * 60) + s) * 75 + f) - 150; 1040 } 1041 1042 void 1043 print_track(struct cd_toc_entry *e) 1044 { 1045 int block, next, len; 1046 u_int m, s, f; 1047 1048 if (msf) { 1049 /* Print track start */ 1050 printf("%2d:%02d.%02d ", e->addr.msf.minute, 1051 e->addr.msf.second, e->addr.msf.frame); 1052 1053 block = msf2lba(e->addr.msf.minute, e->addr.msf.second, 1054 e->addr.msf.frame); 1055 } else { 1056 block = e->addr.lba; 1057 lba2msf(block, &m, &s, &f); 1058 /* Print track start */ 1059 printf("%2d:%02d.%02d ", m, s, f); 1060 } 1061 if (e->track > CD_MAX_TRACK) { 1062 /* lead-out area -- print block */ 1063 printf(" - %6d - lead-out\n", block); 1064 return; 1065 } 1066 if (msf) 1067 next = msf2lba(e[1].addr.msf.minute, e[1].addr.msf.second, 1068 e[1].addr.msf.frame); 1069 else 1070 next = e[1].addr.lba; 1071 len = next - block; 1072 /* XXX: take into account the 150 frame start offset time */ 1073 /* XXX: this is a mis-use of lba2msf() because 'len' is a */ 1074 /* XXX: length in frames and not a LBA! */ 1075 lba2msf(len - 150, &m, &s, &f); 1076 1077 /* Print duration, block, length, type */ 1078 printf("%2d:%02d.%02d %6d %6d %8s\n", m, s, f, block, len, 1079 (e->control & 4) ? "data" : "audio"); 1080 } 1081 1082 int 1083 play_track(int tstart, int istart, int tend, int iend) 1084 { 1085 struct ioc_play_track t; 1086 int rv; 1087 1088 if (digital) { 1089 tstart--; 1090 if (msf) { 1091 return (play_msf(toc_buffer[tstart].addr.msf.minute, 1092 toc_buffer[tstart].addr.msf.second, toc_buffer[tstart].addr.msf.frame, 1093 toc_buffer[tend].addr.msf.minute, toc_buffer[tend].addr.msf.second, 1094 toc_buffer[tend].addr.msf.frame)); 1095 } else 1096 return (play_digital(toc_buffer[tstart].addr.lba, 1097 toc_buffer[tend].addr.lba)); 1098 } 1099 t.start_track = tstart; 1100 t.start_index = istart; 1101 t.end_track = tend; 1102 t.end_index = iend; 1103 1104 if ((rv = ioctl(fd, CDIOCPLAYTRACKS, &t)) < 0) 1105 warn("ioctl(CDIOCPLAYTRACKS)"); 1106 return (rv); 1107 } 1108 1109 int 1110 play_blocks(int blk, int len) 1111 { 1112 struct ioc_play_blocks t; 1113 int rv; 1114 1115 t.blk = blk; 1116 t.len = len; 1117 1118 if ((rv = ioctl(fd, CDIOCPLAYBLOCKS, &t)) < 0) 1119 warn("ioctl(CDIOCPLAYBLOCKS"); 1120 return (rv); 1121 } 1122 1123 int 1124 play_digital(start, end) 1125 int start, end; 1126 { 1127 da.lba_start = start; 1128 da.lba_end = --end; 1129 da.changed = da.playing = 1; 1130 return (0); 1131 } 1132 1133 int 1134 setvol(int left, int right) 1135 { 1136 struct ioc_vol v; 1137 int rv; 1138 1139 v.vol[0] = left; 1140 v.vol[1] = right; 1141 v.vol[2] = 0; 1142 v.vol[3] = 0; 1143 1144 if ((rv = ioctl(fd, CDIOCSETVOL, &v)) < 0) 1145 warn("ioctl(CDIOCSETVOL)"); 1146 return (rv); 1147 } 1148 1149 int 1150 read_toc_entrys(int len) 1151 { 1152 struct ioc_read_toc_entry t; 1153 int rv; 1154 1155 t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 1156 t.starting_track = 0; 1157 t.data_len = len; 1158 t.data = toc_buffer; 1159 1160 if ((rv = ioctl(fd, CDIOREADTOCENTRYS, &t)) < 0) 1161 warn("ioctl(CDIOREADTOCENTRYS)"); 1162 tbvalid = 1; 1163 return (rv); 1164 } 1165 1166 int 1167 play_msf(int start_m, int start_s, int start_f, int end_m, int end_s, 1168 int end_f) 1169 { 1170 struct ioc_play_msf a; 1171 int rv; 1172 1173 if (digital) 1174 return (play_digital(msf2lba(start_m, start_s, start_f), 1175 msf2lba(end_m, end_s, end_f))); 1176 a.start_m = start_m; 1177 a.start_s = start_s; 1178 a.start_f = start_f; 1179 a.end_m = end_m; 1180 a.end_s = end_s; 1181 a.end_f = end_f; 1182 1183 if ((rv = ioctl(fd, CDIOCPLAYMSF, &a)) < 0) 1184 warn("ioctl(CDIOCPLAYMSF)"); 1185 return (rv); 1186 } 1187 1188 int 1189 get_status(int *trk, int *idx, int *min, int *sec, int *frame) 1190 { 1191 struct ioc_read_subchannel s; 1192 struct cd_sub_channel_info data; 1193 struct ioc_toc_header h; 1194 u_int mm, ss, ff; 1195 int rv; 1196 int i, n, rc; 1197 uint32_t lba; 1198 1199 if (!tbvalid) { 1200 if ((rc = ioctl(fd, CDIOREADTOCHEADER, &h)) < 0) { 1201 warn("ioctl(CDIOREADTOCHEADER)"); 1202 return (rc); 1203 } 1204 1205 n = h.ending_track - h.starting_track + 1; 1206 rc = read_toc_entrys((n + 1) * sizeof(struct cd_toc_entry)); 1207 if (rc < 0) 1208 return (rc); 1209 } 1210 1211 #define SWAPLBA(x) (msf?be32toh(x):(x)) 1212 if (digital && da.playing) { 1213 lba = da.lba_current + 150; 1214 for (i = 1; i < 99; i++) { 1215 if (lba < SWAPLBA(toc_buffer[i].addr.lba)) { 1216 lba -= SWAPLBA(toc_buffer[i - 1].addr.lba); 1217 *trk = i; 1218 break; 1219 } 1220 } 1221 lba2msf(lba - 150, &mm, &ss, &ff); 1222 *min = mm; 1223 *sec = ss; 1224 *frame = ff; 1225 *idx = 0; 1226 return CD_AS_PLAY_IN_PROGRESS; 1227 } 1228 bzero(&s, sizeof(s)); 1229 s.data = &data; 1230 s.data_len = sizeof(data); 1231 s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 1232 s.data_format = CD_CURRENT_POSITION; 1233 1234 if ((rv = ioctl(fd, CDIOCREADSUBCHANNEL, &s)) < 0) { 1235 warn("ioctl(CDIOCREADSUBCHANNEL)"); 1236 return (rv); 1237 } 1238 1239 *trk = s.data->what.position.track_number; 1240 *idx = s.data->what.position.index_number; 1241 if (msf) { 1242 *min = s.data->what.position.reladdr.msf.minute; 1243 *sec = s.data->what.position.reladdr.msf.second; 1244 *frame = s.data->what.position.reladdr.msf.frame; 1245 } else { 1246 lba2msf(s.data->what.position.reladdr.lba, &mm, 1247 &ss, &ff); 1248 *min = mm; 1249 *sec = ss; 1250 *frame = ff; 1251 } 1252 1253 return (s.data->header.audio_status); 1254 } 1255 1256 const char * 1257 prompt(void) 1258 { 1259 1260 return ("cdplay> "); 1261 } 1262 1263 const char * 1264 parse(char *buf, int *cmd) 1265 { 1266 const struct cmdtab *c, *mc; 1267 char *p, *q; 1268 unsigned int len; 1269 1270 for (p = buf; isspace((unsigned char)*p); p++) 1271 continue; 1272 1273 if (isdigit((unsigned char)*p) || (p[0] == '#' && isdigit((unsigned char)p[1]))) { 1274 *cmd = CMD_PLAY; 1275 return (p); 1276 } 1277 1278 for (buf = p; *p != '\0' && !isspace((unsigned char)*p); p++) 1279 continue; 1280 1281 if ((len = p - buf) == 0) 1282 return (0); 1283 1284 if (*p != '\0') { /* It must be a spacing character! */ 1285 *p++ = 0; 1286 for (q = p; *q != '\0' && *q != '\n' && *q != '\r'; q++) 1287 continue; 1288 *q = 0; 1289 } 1290 1291 *cmd = -1; 1292 1293 mc = cmdtab + sizeof(cmdtab) / sizeof(cmdtab[0]); 1294 for (c = cmdtab; c < mc; c++) { 1295 /* Is it an exact match? */ 1296 if (strcasecmp(buf, c->name) == 0) { 1297 *cmd = c->command; 1298 break; 1299 } 1300 /* Try short hand forms then... */ 1301 if (len >= c->min && strncasecmp(buf, c->name, len) == 0) { 1302 if (*cmd != -1 && *cmd != (int)c->command) { 1303 warnx("ambiguous command"); 1304 return (0); 1305 } 1306 *cmd = c->command; 1307 } 1308 } 1309 1310 if (*cmd == -1) { 1311 warnx("invalid command, enter ``help'' for commands"); 1312 return (0); 1313 } 1314 1315 while (isspace((unsigned char)*p)) 1316 p++; 1317 return (p); 1318 } 1319 1320 int 1321 opencd(void) 1322 { 1323 char devbuf[80]; 1324 1325 if (fd > -1) 1326 return (1); 1327 1328 fd = opendisk(cdname, O_RDONLY, devbuf, sizeof(devbuf), 0); 1329 if (fd < 0) { 1330 if (errno == ENXIO) { 1331 /* 1332 * ENXIO has an overloaded meaning here. The 1333 * original "Device not configured" should be 1334 * interpreted as "No disc in drive %s". 1335 */ 1336 warnx("no disc in drive %s", devbuf); 1337 return (0); 1338 } 1339 err(EXIT_FAILURE, "%s", devbuf); 1340 } 1341 return (1); 1342 } 1343 1344 int 1345 openaudio() 1346 { 1347 audio_info_t ai; 1348 audio_encoding_t ae; 1349 int rc, aei; 1350 1351 if (da.afd > -1) 1352 return (1); 1353 da.afd = open(da.auname, O_WRONLY); 1354 if (da.afd < 0) { 1355 warn("openaudio"); 1356 return (0); 1357 } 1358 AUDIO_INITINFO(&ai); 1359 ae.index = 0; 1360 aei = -1; 1361 rc = ioctl(da.afd, AUDIO_GETENC, &ae); 1362 do { 1363 if (ae.encoding == AUDIO_ENCODING_SLINEAR_LE && ae.precision == 16) 1364 aei = ae.index; 1365 ae.index++; 1366 rc = ioctl(da.afd, AUDIO_GETENC, &ae); 1367 } while (rc == 0); 1368 if (aei == -1) { 1369 warn("No suitable audio encoding found!"); 1370 close(da.afd); 1371 da.afd = -1; 1372 return (0); 1373 } 1374 ai.mode = AUMODE_PLAY_ALL; 1375 ai.play.sample_rate = 44100; 1376 ai.play.channels = 2; 1377 ai.play.precision = 16; 1378 ai.play.encoding = AUDIO_ENCODING_SLINEAR_LE; 1379 ai.blocksize = 0; 1380 rc = ioctl(da.afd, AUDIO_SETINFO, &ai); 1381 if (rc < 0) { 1382 warn("AUDIO_SETINFO"); 1383 close(da.afd); 1384 da.afd = -1; 1385 return (0); 1386 } 1387 return (1); 1388 } 1389 1390 int 1391 readaudio(afd, lba, blocks, data) 1392 int afd, lba, blocks; 1393 u_char *data; 1394 { 1395 struct scsireq sc; 1396 int rc; 1397 1398 memset(&sc, 0, sizeof(sc)); 1399 sc.cmd[0] = 0xBE; 1400 sc.cmd[1] = 1 << 2; 1401 sc.cmd[2] = (lba >> 24) & 0xff; 1402 sc.cmd[3] = (lba >> 16) & 0xff; 1403 sc.cmd[4] = (lba >> 8) & 0xff; 1404 sc.cmd[5] = lba & 0xff; 1405 sc.cmd[6] = (blocks >> 16) & 0xff; 1406 sc.cmd[7] = (blocks >> 8) & 0xff; 1407 sc.cmd[8] = blocks & 0xff; 1408 sc.cmd[9] = 1 << 4; 1409 sc.cmd[10] = 0; 1410 sc.cmdlen = 12; 1411 sc.databuf = (caddr_t) data; 1412 sc.datalen = CDDA_SIZE * blocks; 1413 sc.senselen = sizeof(sc.sense); 1414 sc.flags = SCCMD_READ; 1415 sc.timeout = 10000; /* 10s */ 1416 rc = ioctl(afd, SCIOCCOMMAND, &sc); 1417 if (rc < 0 || sc.retsts != SCCMD_OK) { 1418 if (da.read_errors < 10) { 1419 warnx("scsi cmd failed: retsts %d status %d\n", 1420 sc.retsts, sc.status); 1421 } 1422 da.read_errors++; 1423 return -1; 1424 } 1425 return CDDA_SIZE * blocks; 1426 } 1427 1428 void 1429 toc2msf(u_int i, u_int *m, u_int *s, u_int *f) 1430 { 1431 struct cd_toc_entry *ctep; 1432 1433 assert(i <= CD_MAX_TRACK); 1434 1435 ctep = &toc_buffer[i]; 1436 1437 if (msf) { 1438 *m = ctep->addr.msf.minute; 1439 *s = ctep->addr.msf.second; 1440 *f = ctep->addr.msf.frame; 1441 } else { 1442 lba2msf(ctep->addr.lba, m, s, f); 1443 } 1444 } 1445 1446 int 1447 toc2lba(u_int i) 1448 { 1449 struct cd_toc_entry *ctep; 1450 1451 assert(i > 0); 1452 assert(i <= CD_MAX_TRACK); 1453 1454 ctep = &toc_buffer[i-1]; 1455 1456 if (msf) { 1457 return msf2lba( 1458 ctep->addr.msf.minute, 1459 ctep->addr.msf.second, 1460 ctep->addr.msf.frame); 1461 } else { 1462 return (ctep->addr.lba); 1463 } 1464 } 1465 1466 void 1467 addmsf(u_int *m, u_int *s, u_int *f, u_int m2, u_int s2, u_int f2) 1468 { 1469 *f += f2; 1470 if (*f > 75) { 1471 *s += *f / 75; 1472 *f %= 75; 1473 } 1474 1475 *s += s2; 1476 if (*s > 60) { 1477 *m += *s / 60; 1478 *s %= 60; 1479 } 1480 1481 *m += m2; 1482 } 1483