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