1*7b34dc5fSav /* $OpenBSD: cdio.c,v 1.63 2008/06/30 23:35:39 av Exp $ */ 2de23af84Sjmc 3de23af84Sjmc /* Copyright (c) 1995 Serge V. Vakulenko 4de23af84Sjmc * All rights reserved. 5de23af84Sjmc * 6de23af84Sjmc * Redistribution and use in source and binary forms, with or without 7de23af84Sjmc * modification, are permitted provided that the following conditions 8de23af84Sjmc * are met: 9de23af84Sjmc * 10de23af84Sjmc * 1. Redistributions of source code must retain the above copyright 11de23af84Sjmc * notice, this list of conditions and the following disclaimer. 12de23af84Sjmc * 2. Redistributions in binary form must reproduce the above copyright 13de23af84Sjmc * notice, this list of conditions and the following disclaimer in the 14de23af84Sjmc * documentation and/or other materials provided with the distribution. 15de23af84Sjmc * 3. All advertising materials mentioning features or use of this software 16de23af84Sjmc * must display the following acknowledgement: 17de23af84Sjmc * This product includes software developed by Serge V. Vakulenko. 18de23af84Sjmc * 4. The name of the author may not be used to endorse or promote products 19de23af84Sjmc * derived from this software without specific prior written permission. 20de23af84Sjmc * 21de23af84Sjmc * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 22de23af84Sjmc * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 23de23af84Sjmc * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 24de23af84Sjmc * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 25de23af84Sjmc * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 26de23af84Sjmc * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 27de23af84Sjmc * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 28de23af84Sjmc * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 29de23af84Sjmc * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 30de23af84Sjmc * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31de23af84Sjmc */ 32de23af84Sjmc 33c92011ceSdownsj /* 34c92011ceSdownsj * Compact Disc Control Utility by Serge V. Vakulenko <vak@cronyx.ru>. 35c92011ceSdownsj * Based on the non-X based CD player by Jean-Marc Zucconi and 36c92011ceSdownsj * Andrey A. Chernov. 37c92011ceSdownsj * 38c92011ceSdownsj * Fixed and further modified on 5-Sep-1995 by Jukka Ukkonen <jau@funet.fi>. 39c92011ceSdownsj * 40c92011ceSdownsj * 11-Sep-1995: Jukka A. Ukkonen <jau@funet.fi> 41c92011ceSdownsj * A couple of further fixes to my own earlier "fixes". 42c92011ceSdownsj * 43c92011ceSdownsj * 18-Sep-1995: Jukka A. Ukkonen <jau@funet.fi> 44c92011ceSdownsj * Added an ability to specify addresses relative to the 45c92011ceSdownsj * beginning of a track. This is in fact a variation of 46c92011ceSdownsj * doing the simple play_msf() call. 47c92011ceSdownsj * 48c92011ceSdownsj * 11-Oct-1995: Serge V.Vakulenko <vak@cronyx.ru> 49c92011ceSdownsj * New eject algorithm. 50c92011ceSdownsj * Some code style reformatting. 51c92011ceSdownsj * 52c92011ceSdownsj * $FreeBSD: cdcontrol.c,v 1.13 1996/06/25 21:01:27 ache Exp $ 53c92011ceSdownsj */ 54c92011ceSdownsj 55ec6762c7Sfgsch #include <sys/param.h> 56ec6762c7Sfgsch #include <sys/file.h> 57ec6762c7Sfgsch #include <sys/cdio.h> 58ec6762c7Sfgsch #include <sys/ioctl.h> 59cf22b6b5Smjc #include <sys/queue.h> 607993cdedSmjc #include <sys/scsiio.h> 61cf22b6b5Smjc #include <sys/stat.h> 62ec6762c7Sfgsch 63c92011ceSdownsj #include <ctype.h> 64dfcdb41bSespie #include <err.h> 65dfcdb41bSespie #include <errno.h> 66c92011ceSdownsj #include <stdio.h> 67c92011ceSdownsj #include <stdlib.h> 68c92011ceSdownsj #include <string.h> 69c92011ceSdownsj #include <unistd.h> 70ec6762c7Sfgsch #include <histedit.h> 71c92011ceSdownsj #include <util.h> 72dfcdb41bSespie #include <vis.h> 73c92011ceSdownsj 74ec6762c7Sfgsch #include "extern.h" 75c92011ceSdownsj 76c92011ceSdownsj #define ASTS_INVALID 0x00 /* Audio status byte not valid */ 77c92011ceSdownsj #define ASTS_PLAYING 0x11 /* Audio play operation in progress */ 78c92011ceSdownsj #define ASTS_PAUSED 0x12 /* Audio play operation paused */ 79c92011ceSdownsj #define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */ 80c92011ceSdownsj #define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */ 81c92011ceSdownsj #define ASTS_VOID 0x15 /* No current audio status to return */ 82c92011ceSdownsj 83c92011ceSdownsj #ifndef DEFAULT_CD_DRIVE 8433d336edSderaadt # define DEFAULT_CD_DRIVE "cd0" 85c92011ceSdownsj #endif 86c92011ceSdownsj 87c92011ceSdownsj #define CMD_DEBUG 1 88f87f2499Smillert #define CMD_DEVICE 2 89f87f2499Smillert #define CMD_EJECT 3 90f87f2499Smillert #define CMD_HELP 4 91f87f2499Smillert #define CMD_INFO 5 92f87f2499Smillert #define CMD_PAUSE 6 93f87f2499Smillert #define CMD_PLAY 7 94f87f2499Smillert #define CMD_QUIT 8 95f87f2499Smillert #define CMD_RESUME 9 96f87f2499Smillert #define CMD_STOP 10 97f87f2499Smillert #define CMD_VOLUME 11 98f87f2499Smillert #define CMD_CLOSE 12 99f87f2499Smillert #define CMD_RESET 13 100f87f2499Smillert #define CMD_SET 14 101f87f2499Smillert #define CMD_STATUS 15 102f87f2499Smillert #define CMD_NEXT 16 103f87f2499Smillert #define CMD_PREV 17 104f87f2499Smillert #define CMD_REPLAY 18 1059ed7639aSespie #define CMD_CDDB 19 106ae359c1cSespie #define CMD_CDID 20 1077993cdedSmjc #define CMD_BLANK 21 108a076f0c4Smjc #define CMD_CDRIP 22 109a076f0c4Smjc #define CMD_CDPLAY 23 110c92011ceSdownsj 111c92011ceSdownsj struct cmdtab { 112c92011ceSdownsj int command; 113c92011ceSdownsj char *name; 1149ed7639aSespie unsigned int min; 115c92011ceSdownsj char *args; 116c92011ceSdownsj } cmdtab[] = { 117c92011ceSdownsj { CMD_CLOSE, "close", 1, "" }, 118c934c333Salek { CMD_DEBUG, "debug", 3, "on | off" }, 119f87f2499Smillert { CMD_DEVICE, "device", 1, "devname" }, 120c92011ceSdownsj { CMD_EJECT, "eject", 1, "" }, 121c92011ceSdownsj { CMD_HELP, "?", 1, 0 }, 122c92011ceSdownsj { CMD_HELP, "help", 1, "" }, 123c92011ceSdownsj { CMD_INFO, "info", 1, "" }, 1243301428eSangelos { CMD_NEXT, "next", 1, "" }, 125c92011ceSdownsj { CMD_PAUSE, "pause", 2, "" }, 126c92011ceSdownsj { CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" }, 1278bdf91ceSkrw { CMD_PLAY, "play", 1, "[tr1] m1:s1[.f1] [tr2] [m2:s2[.f2]]" }, 128c92011ceSdownsj { CMD_PLAY, "play", 1, "[#block [len]]" }, 1293301428eSangelos { CMD_PREV, "previous", 2, "" }, 130c92011ceSdownsj { CMD_QUIT, "quit", 1, "" }, 131c92011ceSdownsj { CMD_RESET, "reset", 4, "" }, 132c92011ceSdownsj { CMD_RESUME, "resume", 1, "" }, 1334efcb1a6Sangelos { CMD_REPLAY, "replay", 3, "" }, 134c92011ceSdownsj { CMD_SET, "set", 2, "msf | lba" }, 135c92011ceSdownsj { CMD_STATUS, "status", 1, "" }, 136c92011ceSdownsj { CMD_STOP, "stop", 3, "" }, 137c92011ceSdownsj { CMD_VOLUME, "volume", 1, "<l> <r> | left | right | mute | mono | stereo" }, 1389ed7639aSespie { CMD_CDDB, "cddbinfo", 2, "[n]" }, 139a681df93Sfgsch { CMD_CDID, "cdid", 3, "" }, 1404464b108Smillert { CMD_QUIT, "exit", 2, "" }, 1417993cdedSmjc { CMD_BLANK, "blank", 1, "" }, 142a076f0c4Smjc { CMD_CDRIP, "cdrip", 1, "[[track1-trackN] ...]" }, 143a076f0c4Smjc { CMD_CDPLAY, "cdplay", 1, "[[track1-trackN] ...]" }, 1449ed7639aSespie { 0, 0, 0, 0} 145c92011ceSdownsj }; 146c92011ceSdownsj 1473a87bfaeScsapuntz struct cd_toc_entry *toc_buffer; 148c92011ceSdownsj 149c92011ceSdownsj char *cdname; 150c92011ceSdownsj int fd = -1; 151c7ed6047Sav int writeperm = 0; 152*7b34dc5fSav int mediacap = 0; 153c92011ceSdownsj int verbose = 1; 154c92011ceSdownsj int msf = 1; 1559ed7639aSespie const char *cddb_host; 1569ed7639aSespie char **track_names; 157c92011ceSdownsj 158ec6762c7Sfgsch EditLine *el = NULL; /* line-editing structure */ 159ec6762c7Sfgsch History *hist = NULL; /* line-editing history */ 160ec6762c7Sfgsch void switch_el(void); 161ec6762c7Sfgsch 162c92011ceSdownsj extern char *__progname; 163c92011ceSdownsj 164c72b5b24Smillert int setvol(int, int); 165c72b5b24Smillert int read_toc_entrys(int); 166c72b5b24Smillert int play_msf(int, int, int, int, int, int); 167c72b5b24Smillert int play_track(int, int, int, int); 168c72b5b24Smillert int get_vol(int *, int *); 169c72b5b24Smillert int status(int *, int *, int *, int *); 170*7b34dc5fSav int is_wave(int); 1719dfd8015Sav __dead void tao(int argc, char **argv); 172c72b5b24Smillert int play(char *arg); 173c72b5b24Smillert int info(char *arg); 1749ed7639aSespie int cddbinfo(char *arg); 175c72b5b24Smillert int pstatus(char *arg); 176c72b5b24Smillert int play_next(char *arg); 177c72b5b24Smillert int play_prev(char *arg); 178c72b5b24Smillert int play_same(char *arg); 179c72b5b24Smillert char *input(int *); 180ec6762c7Sfgsch char *prompt(void); 1819ed7639aSespie void prtrack(struct cd_toc_entry *e, int lastflag, char *name); 182f3c3a9c6Smillert void lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f); 183c72b5b24Smillert unsigned int msf2lba(u_char m, u_char s, u_char f); 184c72b5b24Smillert int play_blocks(int blk, int len); 185c72b5b24Smillert int run(int cmd, char *arg); 186c72b5b24Smillert char *parse(char *buf, int *cmd); 187da50f41aSespie void help(void); 188da50f41aSespie void usage(void); 189da50f41aSespie char *strstatus(int); 190ae359c1cSespie int cdid(void); 1918dcc8943Skrw void addmsf(u_int *, u_int *, u_int *, u_char, u_char, u_char); 192b8a783aeSkrw int cmpmsf(u_char, u_char, u_char, u_char, u_char, u_char); 1933438b82bSkrw void toc2msf(u_int, u_char *, u_char *, u_char *); 194c92011ceSdownsj 195f18d0a50Sderaadt void 1961837a5caSderaadt help(void) 197c92011ceSdownsj { 198c92011ceSdownsj struct cmdtab *c; 199c92011ceSdownsj char *s, n; 2005a6bb450Sderaadt u_int i; 201c92011ceSdownsj 202c92011ceSdownsj for (c = cmdtab; c->name; ++c) { 203c92011ceSdownsj if (!c->args) 204c92011ceSdownsj continue; 205c92011ceSdownsj printf("\t"); 206c92011ceSdownsj for (i = c->min, s = c->name; *s; s++, i--) { 207c92011ceSdownsj if (i > 0) 208c92011ceSdownsj n = toupper(*s); 209c92011ceSdownsj else 210c92011ceSdownsj n = *s; 211c92011ceSdownsj putchar(n); 212c92011ceSdownsj } 213c92011ceSdownsj if (*c->args) 214c92011ceSdownsj printf(" %s", c->args); 215c92011ceSdownsj printf("\n"); 216c92011ceSdownsj } 217c92011ceSdownsj printf("\n\tThe word \"play\" is not required for the play commands.\n"); 218c92011ceSdownsj printf("\tThe plain target address is taken as a synonym for play.\n"); 219c92011ceSdownsj } 220c92011ceSdownsj 221f18d0a50Sderaadt void 2221837a5caSderaadt usage(void) 223c92011ceSdownsj { 2243888ebd6Sjmc fprintf(stderr, "usage: %s [-sv] [-d host:port] [-f device] [command args ...]\n", 225f18d0a50Sderaadt __progname); 226c92011ceSdownsj exit(1); 227c92011ceSdownsj } 228c92011ceSdownsj 229f18d0a50Sderaadt int 2309ed7639aSespie main(int argc, char **argv) 231c92011ceSdownsj { 232c283657cSmiod int ch, cmd; 233c92011ceSdownsj char *arg; 234c92011ceSdownsj 235c92011ceSdownsj cdname = getenv("DISC"); 236c92011ceSdownsj if (!cdname) 237c92011ceSdownsj cdname = getenv("CDROM"); 238c92011ceSdownsj 2399ed7639aSespie cddb_host = getenv("CDDB"); 2409ed7639aSespie if (!cddb_host) 2419ed7639aSespie cddb_host = "freedb.freedb.org"; 2429ed7639aSespie 243c283657cSmiod while ((ch = getopt(argc, argv, "svd:f:")) != -1) 244c283657cSmiod switch (ch) { 245c92011ceSdownsj case 's': 246c92011ceSdownsj verbose = 0; 247c283657cSmiod break; 248c92011ceSdownsj case 'v': 249c92011ceSdownsj verbose = 2; 250c283657cSmiod break; 251c92011ceSdownsj case 'f': 252c92011ceSdownsj cdname = optarg; 253c283657cSmiod break; 2549ed7639aSespie case 'd': 2559ed7639aSespie cddb_host = optarg; 256c283657cSmiod break; 257c92011ceSdownsj default: 258c92011ceSdownsj usage(); 259c92011ceSdownsj } 260c283657cSmiod 261c92011ceSdownsj argc -= optind; 262c92011ceSdownsj argv += optind; 263c92011ceSdownsj 264c92011ceSdownsj if (argc > 0 && ! strcasecmp(*argv, "help")) 265c92011ceSdownsj usage(); 266c92011ceSdownsj 267c92011ceSdownsj if (!cdname) { 268c92011ceSdownsj cdname = DEFAULT_CD_DRIVE; 269c92011ceSdownsj fprintf(stderr, 270c92011ceSdownsj "No CD device name specified. Defaulting to %s.\n", cdname); 271c92011ceSdownsj } 272c92011ceSdownsj 2737993cdedSmjc if (argc > 0 && !strcasecmp(*argv, "tao")) { 2749dfd8015Sav tao(argc, argv); 2759dfd8015Sav /* NOTREACHED */ 2767993cdedSmjc } 277c92011ceSdownsj if (argc > 0) { 278c92011ceSdownsj char buf[80], *p; 279c92011ceSdownsj int len; 280c92011ceSdownsj 281c92011ceSdownsj for (p=buf; argc-->0; ++argv) { 2820144018cSkrw len = snprintf(p, buf + sizeof buf - p, 2830144018cSkrw "%s%s", (p > buf) ? " " : "", *argv); 284c92011ceSdownsj 285a60fa294Smoritz if (len == -1 || len >= buf + sizeof buf - p) 2860144018cSkrw errx(1, "argument list too long."); 287c92011ceSdownsj 288c92011ceSdownsj p += len; 289c92011ceSdownsj } 290c92011ceSdownsj arg = parse(buf, &cmd); 291c92011ceSdownsj return (run(cmd, arg)); 292c92011ceSdownsj } 293c92011ceSdownsj 294c92011ceSdownsj if (verbose == 1) 295c92011ceSdownsj verbose = isatty(0); 296c92011ceSdownsj 297c92011ceSdownsj if (verbose) { 298c92011ceSdownsj printf("Compact Disc Control utility, version %s\n", VERSION); 299c92011ceSdownsj printf("Type `?' for command list\n\n"); 300c92011ceSdownsj } 301c92011ceSdownsj 302ec6762c7Sfgsch switch_el(); 303ec6762c7Sfgsch 304c92011ceSdownsj for (;;) { 305c92011ceSdownsj arg = input(&cmd); 306c92011ceSdownsj if (run(cmd, arg) < 0) { 307c92011ceSdownsj if (verbose) 308f87f2499Smillert warn(NULL); 309c92011ceSdownsj close(fd); 310c92011ceSdownsj fd = -1; 311c92011ceSdownsj } 312c92011ceSdownsj fflush(stdout); 313c92011ceSdownsj } 314c92011ceSdownsj } 315c92011ceSdownsj 316f18d0a50Sderaadt int 3179ed7639aSespie run(int cmd, char *arg) 318c92011ceSdownsj { 319*7b34dc5fSav int l, r, rc; 320f87f2499Smillert static char newcdname[MAXPATHLEN]; 321c92011ceSdownsj 322c92011ceSdownsj switch (cmd) { 323c92011ceSdownsj 324c92011ceSdownsj case CMD_QUIT: 325ec6762c7Sfgsch switch_el(); 326c92011ceSdownsj exit(0); 327c92011ceSdownsj 328c92011ceSdownsj case CMD_INFO: 329c7ed6047Sav if (!open_cd(cdname, 0)) 330c92011ceSdownsj return (0); 331c92011ceSdownsj 332c92011ceSdownsj return info(arg); 333c92011ceSdownsj 3349ed7639aSespie case CMD_CDDB: 335c7ed6047Sav if (!open_cd(cdname, 0)) 3369ed7639aSespie return (0); 3379ed7639aSespie 3389ed7639aSespie return cddbinfo(arg); 3399ed7639aSespie 340ae359c1cSespie case CMD_CDID: 341c7ed6047Sav if (!open_cd(cdname, 0)) 342ae359c1cSespie return (0); 343ae359c1cSespie return cdid(); 344ae359c1cSespie 345c92011ceSdownsj case CMD_STATUS: 346c7ed6047Sav if (!open_cd(cdname, 0)) 347c92011ceSdownsj return (0); 348c92011ceSdownsj 349c92011ceSdownsj return pstatus(arg); 350c92011ceSdownsj 351c92011ceSdownsj case CMD_PAUSE: 352c7ed6047Sav if (!open_cd(cdname, 0)) 353c92011ceSdownsj return (0); 354c92011ceSdownsj 355c92011ceSdownsj return ioctl(fd, CDIOCPAUSE); 356c92011ceSdownsj 357c92011ceSdownsj case CMD_RESUME: 358c7ed6047Sav if (!open_cd(cdname, 0)) 359c92011ceSdownsj return (0); 360c92011ceSdownsj 361c92011ceSdownsj return ioctl(fd, CDIOCRESUME); 362c92011ceSdownsj 363c92011ceSdownsj case CMD_STOP: 364c7ed6047Sav if (!open_cd(cdname, 0)) 365c92011ceSdownsj return (0); 366c92011ceSdownsj 367c92011ceSdownsj rc = ioctl(fd, CDIOCSTOP); 368c92011ceSdownsj 369c92011ceSdownsj (void) ioctl(fd, CDIOCALLOW); 370c92011ceSdownsj 371c92011ceSdownsj return (rc); 372c92011ceSdownsj 373c92011ceSdownsj case CMD_RESET: 374c7ed6047Sav if (!open_cd(cdname, 0)) 375c92011ceSdownsj return (0); 376c92011ceSdownsj 377c92011ceSdownsj rc = ioctl(fd, CDIOCRESET); 378c92011ceSdownsj if (rc < 0) 379c92011ceSdownsj return rc; 380c92011ceSdownsj close(fd); 381c92011ceSdownsj fd = -1; 382c92011ceSdownsj return (0); 383c92011ceSdownsj 384c92011ceSdownsj case CMD_DEBUG: 385c7ed6047Sav if (!open_cd(cdname, 0)) 386c92011ceSdownsj return (0); 387c92011ceSdownsj 388c92011ceSdownsj if (!strcasecmp(arg, "on")) 389c92011ceSdownsj return ioctl(fd, CDIOCSETDEBUG); 390c92011ceSdownsj 391c92011ceSdownsj if (!strcasecmp(arg, "off")) 392c92011ceSdownsj return ioctl(fd, CDIOCCLRDEBUG); 393c92011ceSdownsj 394c92011ceSdownsj printf("%s: Invalid command arguments\n", __progname); 395c92011ceSdownsj 396c92011ceSdownsj return (0); 397c92011ceSdownsj 398f87f2499Smillert case CMD_DEVICE: 399f87f2499Smillert /* close old device */ 400f87f2499Smillert if (fd > -1) { 401f87f2499Smillert (void) ioctl(fd, CDIOCALLOW); 402f87f2499Smillert close(fd); 403f87f2499Smillert fd = -1; 404f87f2499Smillert } 405f87f2499Smillert 406d8a9cdc1Salek if (strlen(arg) == 0) { 407d8a9cdc1Salek printf("%s: Invalid parameter\n", __progname); 408d8a9cdc1Salek return (0); 409d8a9cdc1Salek } 410d8a9cdc1Salek 411f87f2499Smillert /* open new device */ 4127993cdedSmjc if (!open_cd(arg, 0)) 413f87f2499Smillert return (0); 4143cbec610Slebel (void) strlcpy(newcdname, arg, sizeof(newcdname)); 415f87f2499Smillert cdname = newcdname; 416f87f2499Smillert return (1); 417f87f2499Smillert 418c92011ceSdownsj case CMD_EJECT: 419c7ed6047Sav if (!open_cd(cdname, 0)) 420c92011ceSdownsj return (0); 421c92011ceSdownsj 422c92011ceSdownsj (void) ioctl(fd, CDIOCALLOW); 423c92011ceSdownsj rc = ioctl(fd, CDIOCEJECT); 424c92011ceSdownsj if (rc < 0) 425c92011ceSdownsj return (rc); 426c92011ceSdownsj #if defined(__OpenBSD__) 427c92011ceSdownsj close(fd); 428c92011ceSdownsj fd = -1; 429c92011ceSdownsj #endif 4309ed7639aSespie if (track_names) 4319ed7639aSespie free_names(track_names); 4329ed7639aSespie track_names = NULL; 433c92011ceSdownsj return (0); 434c92011ceSdownsj 435c92011ceSdownsj case CMD_CLOSE: 436c92011ceSdownsj #if defined(CDIOCCLOSE) 437c7ed6047Sav if (!open_cd(cdname, 0)) 438c92011ceSdownsj return (0); 439c92011ceSdownsj 440c92011ceSdownsj (void) ioctl(fd, CDIOCALLOW); 441c92011ceSdownsj rc = ioctl(fd, CDIOCCLOSE); 442c92011ceSdownsj if (rc < 0) 443c92011ceSdownsj return (rc); 444c92011ceSdownsj close(fd); 445c92011ceSdownsj fd = -1; 446c92011ceSdownsj return (0); 447c92011ceSdownsj #else 448c92011ceSdownsj printf("%s: Command not yet supported\n", __progname); 449c92011ceSdownsj return (0); 450c92011ceSdownsj #endif 451c92011ceSdownsj 452c92011ceSdownsj case CMD_PLAY: 453c7ed6047Sav if (!open_cd(cdname, 0)) 454c92011ceSdownsj return (0); 455c92011ceSdownsj 456c92011ceSdownsj while (isspace(*arg)) 457c92011ceSdownsj arg++; 458c92011ceSdownsj 459c92011ceSdownsj return play(arg); 460c92011ceSdownsj 461c92011ceSdownsj case CMD_SET: 462c92011ceSdownsj if (!strcasecmp(arg, "msf")) 463c92011ceSdownsj msf = 1; 464c92011ceSdownsj else if (!strcasecmp(arg, "lba")) 465c92011ceSdownsj msf = 0; 466c92011ceSdownsj else 467c92011ceSdownsj printf("%s: Invalid command arguments\n", __progname); 468c92011ceSdownsj return (0); 469c92011ceSdownsj 470c92011ceSdownsj case CMD_VOLUME: 471c7ed6047Sav if (!open_cd(cdname, 0)) 472c92011ceSdownsj return (0); 473c92011ceSdownsj 474c92011ceSdownsj if (!strncasecmp(arg, "left", strlen(arg))) 475c92011ceSdownsj return ioctl(fd, CDIOCSETLEFT); 476c92011ceSdownsj 477c92011ceSdownsj if (!strncasecmp(arg, "right", strlen(arg))) 478c92011ceSdownsj return ioctl(fd, CDIOCSETRIGHT); 479c92011ceSdownsj 480c92011ceSdownsj if (!strncasecmp(arg, "mono", strlen(arg))) 481c92011ceSdownsj return ioctl(fd, CDIOCSETMONO); 482c92011ceSdownsj 483c92011ceSdownsj if (!strncasecmp(arg, "stereo", strlen(arg))) 484ac9e9f6dSdownsj return ioctl(fd, CDIOCSETSTEREO); 485c92011ceSdownsj 486c92011ceSdownsj if (!strncasecmp(arg, "mute", strlen(arg))) 487c92011ceSdownsj return ioctl(fd, CDIOCSETMUTE); 488c92011ceSdownsj 489c92011ceSdownsj if (2 != sscanf(arg, "%d%d", &l, &r)) { 490c92011ceSdownsj printf("%s: Invalid command arguments\n", __progname); 491c92011ceSdownsj return (0); 492c92011ceSdownsj } 493c92011ceSdownsj 494c92011ceSdownsj return setvol(l, r); 495c92011ceSdownsj 4963301428eSangelos case CMD_NEXT: 497c7ed6047Sav if (!open_cd(cdname, 0)) 4983301428eSangelos return (0); 4993301428eSangelos 5003301428eSangelos return play_next(arg); 5013301428eSangelos 5023301428eSangelos case CMD_PREV: 503c7ed6047Sav if (!open_cd(cdname, 0)) 5043301428eSangelos return (0); 5053301428eSangelos 5063301428eSangelos return play_prev(arg); 5073301428eSangelos 5084efcb1a6Sangelos case CMD_REPLAY: 509c7ed6047Sav if (!open_cd(cdname, 0)) 5104efcb1a6Sangelos return 0; 5114efcb1a6Sangelos 5124efcb1a6Sangelos return play_same(arg); 5137993cdedSmjc case CMD_BLANK: 514c7ed6047Sav if (!open_cd(cdname, 1)) 5157993cdedSmjc return 0; 5167993cdedSmjc 517*7b34dc5fSav if (get_media_capabilities(&mediacap) == -1) { 5185c0dfce9Sav warnx("Can't determine media type"); 5195c0dfce9Sav return (0); 5205c0dfce9Sav } 521*7b34dc5fSav if ((mediacap & MEDIACAP_CDRW_WRITE) == 0) { 5225c0dfce9Sav warnx("The media doesn't support blanking"); 5235c0dfce9Sav return (0); 5245c0dfce9Sav } 5255c0dfce9Sav 5267993cdedSmjc return blank(); 527a076f0c4Smjc case CMD_CDRIP: 528c7ed6047Sav if (!open_cd(cdname, 0)) 529a076f0c4Smjc return (0); 530a076f0c4Smjc 531a076f0c4Smjc while (isspace(*arg)) 532a076f0c4Smjc arg++; 533a076f0c4Smjc 534a076f0c4Smjc return cdrip(arg); 535a076f0c4Smjc case CMD_CDPLAY: 536c7ed6047Sav if (!open_cd(cdname, 0)) 537a076f0c4Smjc return (0); 538a076f0c4Smjc 539a076f0c4Smjc while (isspace(*arg)) 540a076f0c4Smjc arg++; 541a076f0c4Smjc 542a076f0c4Smjc return cdplay(arg); 543c92011ceSdownsj default: 544c92011ceSdownsj case CMD_HELP: 545c92011ceSdownsj help(); 546c92011ceSdownsj return (0); 547c92011ceSdownsj 548c92011ceSdownsj } 549c92011ceSdownsj } 550c92011ceSdownsj 551f7dfecd4Sav /* 552f7dfecd4Sav * Check if audio file has RIFF WAVE format. If not, we assume it's just PCM. 553f7dfecd4Sav */ 554f7dfecd4Sav int 555f7dfecd4Sav is_wave(int fd) 556f7dfecd4Sav { 557f7dfecd4Sav char buf[WAVHDRLEN]; 558f7dfecd4Sav int rv; 559f7dfecd4Sav 560f7dfecd4Sav rv = 0; 561f7dfecd4Sav if (read(fd, buf, sizeof(buf)) == sizeof(buf)) { 562f7dfecd4Sav if (memcmp(buf, "RIFF", 4) == 0 && 563f7dfecd4Sav memcmp(buf + 8, "WAVE", 4) == 0) 564f7dfecd4Sav rv = 1; 565f7dfecd4Sav } 566f7dfecd4Sav 567f7dfecd4Sav return (rv); 568f7dfecd4Sav } 569f7dfecd4Sav 5709dfd8015Sav __dead void 5719dfd8015Sav tao(int argc, char **argv) 5729dfd8015Sav { 5739dfd8015Sav struct stat sb; 5749dfd8015Sav struct track_info *cur_track; 5759dfd8015Sav struct track_info *tr; 5769dfd8015Sav off_t availblk, needblk = 0; 5779dfd8015Sav u_int blklen; 5789dfd8015Sav u_int ntracks = 0; 5799dfd8015Sav char type; 580*7b34dc5fSav int ch, speed; 581*7b34dc5fSav const char *errstr; 5829dfd8015Sav 5839dfd8015Sav if (argc == 1) 5849dfd8015Sav usage(); 5859dfd8015Sav 5869dfd8015Sav SLIST_INIT(&tracks); 5879dfd8015Sav type = 'd'; 588*7b34dc5fSav speed = DRIVE_SPEED_OPTIMAL; 5899dfd8015Sav blklen = 2048; 5909dfd8015Sav while (argc > 1) { 5919dfd8015Sav tr = malloc(sizeof(struct track_info)); 5929dfd8015Sav if (tr == NULL) 5939dfd8015Sav err(1, "tao"); 5949dfd8015Sav 5959dfd8015Sav optreset = 1; 5969dfd8015Sav optind = 1; 597*7b34dc5fSav while ((ch = getopt(argc, argv, "ads:")) != -1) { 5989dfd8015Sav switch (ch) { 5999dfd8015Sav case 'a': 6009dfd8015Sav type = 'a'; 6019dfd8015Sav blklen = 2352; 6029dfd8015Sav break; 6039dfd8015Sav case 'd': 6049dfd8015Sav type = 'd'; 6059dfd8015Sav blklen = 2048; 6069dfd8015Sav break; 607*7b34dc5fSav case 's': 608*7b34dc5fSav if (strcmp(optarg, "auto") == 0) { 609*7b34dc5fSav speed = DRIVE_SPEED_OPTIMAL; 610*7b34dc5fSav } else if (strcmp(optarg, "max") == 0) { 611*7b34dc5fSav speed = DRIVE_SPEED_MAX; 612*7b34dc5fSav } else { 613*7b34dc5fSav speed = (int)strtonum(optarg, 1, 614*7b34dc5fSav CD_MAX_SPEED, &errstr); 615*7b34dc5fSav if (errstr != NULL) { 616*7b34dc5fSav errx(1, 617*7b34dc5fSav "incorrect speed value"); 618*7b34dc5fSav } 619*7b34dc5fSav } 620*7b34dc5fSav break; 6219dfd8015Sav default: 6229dfd8015Sav usage(); 6239dfd8015Sav /* NOTREACHED */ 6249dfd8015Sav } 6259dfd8015Sav } 6269dfd8015Sav 627*7b34dc5fSav if (speed != DRIVE_SPEED_OPTIMAL && speed != DRIVE_SPEED_MAX) 628*7b34dc5fSav tr->speed = CD_SPEED_TO_KBPS(speed, blklen); 629*7b34dc5fSav else 630*7b34dc5fSav tr->speed = speed; 631*7b34dc5fSav 6329dfd8015Sav tr->type = type; 6339dfd8015Sav tr->blklen = blklen; 6349dfd8015Sav argc -= optind; 6359dfd8015Sav argv += optind; 6369dfd8015Sav if (argv[0] == NULL) 6379dfd8015Sav usage(); 6389dfd8015Sav tr->file = argv[0]; 6399dfd8015Sav tr->fd = open(tr->file, O_RDONLY, 0640); 6409dfd8015Sav if (tr->fd == -1) 6419dfd8015Sav err(1, "cannot open file %s", tr->file); 6429dfd8015Sav if (fstat(tr->fd, &sb) == -1) 6439dfd8015Sav err(1, "cannot stat file %s", tr->file); 6449dfd8015Sav tr->sz = sb.st_size; 645f7dfecd4Sav tr->off = 0; 646f7dfecd4Sav if (tr->type == 'a') { 647f7dfecd4Sav if (is_wave(tr->fd)) { 6489dfd8015Sav tr->sz -= WAVHDRLEN; 649f7dfecd4Sav tr->off = WAVHDRLEN; 650f7dfecd4Sav } 651f7dfecd4Sav } 6529dfd8015Sav if (SLIST_EMPTY(&tracks)) 6539dfd8015Sav SLIST_INSERT_HEAD(&tracks, tr, track_list); 6549dfd8015Sav else 6559dfd8015Sav SLIST_INSERT_AFTER(cur_track, tr, track_list); 6569dfd8015Sav cur_track = tr; 6579dfd8015Sav } 6589dfd8015Sav 6599dfd8015Sav if (!open_cd(cdname, 1)) 6609dfd8015Sav exit(1); 661*7b34dc5fSav if (get_media_capabilities(&mediacap) == -1) 6629dfd8015Sav errx(1, "Can't determine media type"); 663*7b34dc5fSav if ((mediacap & MEDIACAP_TAO) == 0) 6649dfd8015Sav errx(1, "The media can't be written in TAO mode"); 6659dfd8015Sav 6669dfd8015Sav get_disc_size(&availblk); 6679dfd8015Sav SLIST_FOREACH(tr, &tracks, track_list) { 6689dfd8015Sav needblk += tr->sz/tr->blklen; 6699dfd8015Sav ntracks++; 6709dfd8015Sav } 6719dfd8015Sav needblk += (ntracks - 1) * 150; /* transition area between tracks */ 6729dfd8015Sav if (needblk > availblk) 6739dfd8015Sav errx(1, "Only %llu of the required %llu blocks available", 6749dfd8015Sav availblk, needblk); 6759dfd8015Sav if (writetao(&tracks) != 0) 6769dfd8015Sav exit(1); 6779dfd8015Sav else 6789dfd8015Sav exit(0); 6799dfd8015Sav } 6809dfd8015Sav 681f18d0a50Sderaadt int 6829ed7639aSespie play(char *arg) 683c92011ceSdownsj { 684c92011ceSdownsj struct ioc_toc_header h; 6858bdf91ceSkrw unsigned char tm, ts, tf; 6868bdf91ceSkrw unsigned int tr1, tr2, m1, m2, s1, s2, f1, f2, i1, i2; 6878bdf91ceSkrw unsigned int blk, len, n; 6888bdf91ceSkrw char c; 6898bdf91ceSkrw int rc; 690c92011ceSdownsj 691c92011ceSdownsj rc = ioctl(fd, CDIOREADTOCHEADER, &h); 692c92011ceSdownsj 693c92011ceSdownsj if (rc < 0) 694c92011ceSdownsj return (rc); 695c92011ceSdownsj 6968bdf91ceSkrw if (h.starting_track > h.ending_track) { 6978bdf91ceSkrw printf("TOC starting_track > TOC ending_track\n"); 6988bdf91ceSkrw return (0); 6998bdf91ceSkrw } 7008bdf91ceSkrw 701c92011ceSdownsj n = h.ending_track - h.starting_track + 1; 702c92011ceSdownsj rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry)); 703c92011ceSdownsj 704c92011ceSdownsj if (rc < 0) 705c92011ceSdownsj return (rc); 706c92011ceSdownsj 7078bdf91ceSkrw /* 7088bdf91ceSkrw * Truncate trailing white space. Then by adding %c to the end of the 7098bdf91ceSkrw * sscanf() formats we catch any errant trailing characters. 7108bdf91ceSkrw */ 7118bdf91ceSkrw rc = strlen(arg) - 1; 7128bdf91ceSkrw while (rc >= 0 && isspace(arg[rc])) { 7138bdf91ceSkrw arg[rc] = '\0'; 7148bdf91ceSkrw rc--; 7158bdf91ceSkrw } 7168bdf91ceSkrw 717c92011ceSdownsj if (!arg || ! *arg) { 718c92011ceSdownsj /* Play the whole disc */ 7198bdf91ceSkrw return (play_track(h.starting_track, 1, h.ending_track, 1)); 720c92011ceSdownsj } 721c92011ceSdownsj 722c92011ceSdownsj if (strchr(arg, '#')) { 723c92011ceSdownsj /* Play block #blk [ len ] */ 7248bdf91ceSkrw if (2 != sscanf(arg, "#%u%u%c", &blk, &len, &c) && 7258bdf91ceSkrw 1 != sscanf(arg, "#%u%c", &blk, &c)) { 7268bdf91ceSkrw printf("%s: Invalid command arguments\n", __progname); 7278bdf91ceSkrw return (0); 7288bdf91ceSkrw } 729c92011ceSdownsj 730c92011ceSdownsj if (len == 0) { 731c92011ceSdownsj if (msf) 732c92011ceSdownsj len = msf2lba(toc_buffer[n].addr.msf.minute, 733c92011ceSdownsj toc_buffer[n].addr.msf.second, 734c92011ceSdownsj toc_buffer[n].addr.msf.frame) - blk; 735c92011ceSdownsj else 73643844f6cSkrw len = toc_buffer[n].addr.lba - blk; 737c92011ceSdownsj } 738c92011ceSdownsj return play_blocks(blk, len); 739c92011ceSdownsj } 740c92011ceSdownsj 7418bdf91ceSkrw if (strchr(arg, ':') == NULL) { 742c92011ceSdownsj /* 7438bdf91ceSkrw * Play track tr1[.i1] [tr2[.i2]] 744c92011ceSdownsj */ 7458bdf91ceSkrw if (4 == sscanf(arg, "%u.%u%u.%u%c", &tr1, &i1, &tr2, &i2, &c)) 7468bdf91ceSkrw goto play_track; 747c92011ceSdownsj 7488bdf91ceSkrw i2 = 1; 7498bdf91ceSkrw if (3 == sscanf(arg, "%u.%u%u%c", &tr1, &i1, &tr2, &c)) 7508bdf91ceSkrw goto play_track; 751c92011ceSdownsj 7528bdf91ceSkrw i1 = 1; 7538bdf91ceSkrw if (3 == sscanf(arg, "%u%u.%u%c", &tr1, &tr2, &i2, &c)) 7548bdf91ceSkrw goto play_track; 755c92011ceSdownsj 7568bdf91ceSkrw tr2 = 0; 7578bdf91ceSkrw i2 = 1; 7588bdf91ceSkrw if (2 == sscanf(arg, "%u.%u%c", &tr1, &i1, &c)) 7598bdf91ceSkrw goto play_track; 760c92011ceSdownsj 7618bdf91ceSkrw i1 = i2 = 1; 7628bdf91ceSkrw if (2 == sscanf(arg, "%u%u%c", &tr1, &tr2, &c)) 7638bdf91ceSkrw goto play_track; 764c92011ceSdownsj 7658bdf91ceSkrw i1 = i2 = 1; 7668bdf91ceSkrw tr2 = 0; 7678bdf91ceSkrw if (1 == sscanf(arg, "%u%c", &tr1, &c)) 7688bdf91ceSkrw goto play_track; 769c92011ceSdownsj 7708bdf91ceSkrw printf("%s: Invalid command arguments\n", __progname); 7717a498d98Skrw return (0); 7728bdf91ceSkrw 7738bdf91ceSkrw play_track: 7748bdf91ceSkrw if (tr1 > n || tr2 > n) { 7758bdf91ceSkrw printf("Track number must be between 0 and %u\n", n); 7768bdf91ceSkrw return (0); 7778bdf91ceSkrw } else if (tr2 == 0) 7788bdf91ceSkrw tr2 = h.ending_track; 7798bdf91ceSkrw 7808bdf91ceSkrw if (tr1 > tr2) { 7818bdf91ceSkrw printf("starting_track > ending_track\n"); 7827a498d98Skrw return (0); 7837a498d98Skrw } 784c92011ceSdownsj 7858bdf91ceSkrw return (play_track(tr1, i1, tr2, i2)); 7868bdf91ceSkrw } 7878bdf91ceSkrw 7888bdf91ceSkrw /* 7898bdf91ceSkrw * Play MSF [tr1] m1:s1[.f1] [tr2] [m2:s2[.f2]] 7908bdf91ceSkrw * 7918bdf91ceSkrw * Start Time End Time 7928bdf91ceSkrw * ---------- -------- 7938bdf91ceSkrw * tr1 m1:s1.f1 tr2 m2:s2.f2 7948bdf91ceSkrw * tr1 m1:s1 tr2 m2:s2.f2 7958bdf91ceSkrw * tr1 m1:s1.f1 tr2 m2:s2 7968bdf91ceSkrw * tr1 m1:s1 tr2 m2:s2 7978bdf91ceSkrw * m1:s1.f1 tr2 m2:s2.f2 7988bdf91ceSkrw * m1:s1 tr2 m2:s2.f2 7998bdf91ceSkrw * m1:s1.f1 tr2 m2:s2 8008bdf91ceSkrw * m1:s1 tr2 m2:s2 8018bdf91ceSkrw * tr1 m1:s1.f1 m2:s2.f2 8028bdf91ceSkrw * tr1 m1:s1 m2:s2.f2 8038bdf91ceSkrw * tr1 m1:s1.f1 m2:s2 8048bdf91ceSkrw * tr1 m1:s1 m2:s2 8058bdf91ceSkrw * m1:s1.f1 m2:s2.f2 8068bdf91ceSkrw * m1:s1 m2:s2.f2 8078bdf91ceSkrw * m1:s1.f1 m2:s2 8088bdf91ceSkrw * m1:s1 m2:s2 8098bdf91ceSkrw * tr1 m1:s1.f1 tr2 8108bdf91ceSkrw * tr1 m1:s1 tr2 8118bdf91ceSkrw * m1:s1.f1 tr2 8128bdf91ceSkrw * m1:s1 tr2 8138bdf91ceSkrw * tr1 m1:s1.f1 <end of disc> 8148bdf91ceSkrw * tr1 m1:s1 <end of disc> 8158bdf91ceSkrw * m1:s1.f1 <end of disc> 8168bdf91ceSkrw * m1:s1 <end of disc> 8178bdf91ceSkrw */ 8188bdf91ceSkrw 8198bdf91ceSkrw /* tr1 m1:s1.f1 tr2 m2:s2.f2 */ 8208bdf91ceSkrw if (8 == sscanf(arg, "%u%u:%u.%u%u%u:%u.%u%c", 8218bdf91ceSkrw &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2, &c)) 8228bdf91ceSkrw goto play_msf; 8238bdf91ceSkrw 8248bdf91ceSkrw /* tr1 m1:s1 tr2 m2:s2.f2 */ 8258bdf91ceSkrw f1 = 0; 8268bdf91ceSkrw if (7 == sscanf(arg, "%u%u:%u%u%u:%u.%u%c", 8278bdf91ceSkrw &tr1, &m1, &s1, &tr2, &m2, &s2, &f2, &c)) 8288bdf91ceSkrw goto play_msf; 8298bdf91ceSkrw 8308bdf91ceSkrw /* tr1 m1:s1.f1 tr2 m2:s2 */ 8318bdf91ceSkrw f2 =0; 8328bdf91ceSkrw if (7 == sscanf(arg, "%u%u:%u.%u%u%u:%u%c", 8338bdf91ceSkrw &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &c)) 8348bdf91ceSkrw goto play_msf; 8358bdf91ceSkrw 8368bdf91ceSkrw /* m1:s1.f1 tr2 m2:s2.f2 */ 8378bdf91ceSkrw tr1 = 0; 8388bdf91ceSkrw if (7 == sscanf(arg, "%u:%u.%u%u%u:%u.%u%c", 8398bdf91ceSkrw &m1, &s1, &f1, &tr2, &m2, &s2, &f2, &c)) 8408bdf91ceSkrw goto play_msf; 8418bdf91ceSkrw 8428bdf91ceSkrw /* tr1 m1:s1.f1 m2:s2.f2 */ 8438bdf91ceSkrw tr2 = 0; 8448bdf91ceSkrw if (7 == sscanf(arg, "%u%u:%u.%u%u:%u.%u%c", 8458bdf91ceSkrw &tr1, &m1, &s1, &f1, &m2, &s2, &f2, &c)) 8468bdf91ceSkrw goto play_msf; 8478bdf91ceSkrw 8488bdf91ceSkrw /* m1:s1 tr2 m2:s2.f2 */ 8498bdf91ceSkrw tr1 = f1 = 0; 8508bdf91ceSkrw if (6 == sscanf(arg, "%u:%u%u%u:%u.%u%c", 8518bdf91ceSkrw &m1, &s1, &tr2, &m2, &s2, &f2, &c)) 8528bdf91ceSkrw goto play_msf; 8538bdf91ceSkrw 8548bdf91ceSkrw /* m1:s1.f1 tr2 m2:s2 */ 8558bdf91ceSkrw tr1 = f2 = 0; 8568bdf91ceSkrw if (6 == sscanf(arg, "%u:%u.%u%u%u:%u%c", 8578bdf91ceSkrw &m1, &s1, &f1, &tr2, &m2, &s2, &c)) 8588bdf91ceSkrw goto play_msf; 8598bdf91ceSkrw 8608bdf91ceSkrw /* m1:s1.f1 m2:s2.f2 */ 8618bdf91ceSkrw tr1 = tr2 = 0; 8628bdf91ceSkrw if (6 == sscanf(arg, "%u:%u.%u%u:%u.%u%c", 8638bdf91ceSkrw &m1, &s1, &f1, &m2, &s2, &f2, &c)) 8648bdf91ceSkrw goto play_msf; 8658bdf91ceSkrw 8668bdf91ceSkrw /* tr1 m1:s1.f1 m2:s2 */ 8678bdf91ceSkrw tr2 = f2 = 0; 8688bdf91ceSkrw if (6 == sscanf(arg, "%u%u:%u.%u%u:%u%c", 8698bdf91ceSkrw &tr1, &m1, &s1, &f1, &m2, &s2, &c)) 8708bdf91ceSkrw goto play_msf; 8718bdf91ceSkrw 8728bdf91ceSkrw /* tr1 m1:s1 m2:s2.f2 */ 8738bdf91ceSkrw tr2 = f1 = 0; 8748bdf91ceSkrw if (6 == sscanf(arg, "%u%u:%u%u:%u.%u%c", 8758bdf91ceSkrw &tr1, &m1, &s1, &m2, &s2, &f2, &c)) 8768bdf91ceSkrw goto play_msf; 8778bdf91ceSkrw 8788bdf91ceSkrw /* tr1 m1:s1 tr2 m2:s2 */ 8798bdf91ceSkrw f1 = f2 = 0; 8808bdf91ceSkrw if (6 == sscanf(arg, "%u%u:%u%u%u:%u%c", 8818bdf91ceSkrw &tr1, &m1, &s1, &tr2, &m2, &s2, &c)) 8828bdf91ceSkrw goto play_msf; 8838bdf91ceSkrw 8848bdf91ceSkrw /* m1:s1 tr2 m2:s2 */ 8858bdf91ceSkrw tr1 = f1 = f2 = 0; 8868bdf91ceSkrw if (5 == sscanf(arg, "%u:%u%u%u:%u%c", &m1, &s1, &tr2, &m2, &s2, &c)) 8878bdf91ceSkrw goto play_msf; 8888bdf91ceSkrw 8898bdf91ceSkrw /* tr1 m1:s1 m2:s2 */ 8908bdf91ceSkrw f1 = tr2 = f2 = 0; 8918bdf91ceSkrw if (5 == sscanf(arg, "%u%u:%u%u:%u%c", &tr1, &m1, &s1, &m2, &s2, &c)) 8928bdf91ceSkrw goto play_msf; 8938bdf91ceSkrw 8948bdf91ceSkrw /* m1:s1 m2:s2.f2 */ 8958bdf91ceSkrw tr1 = f1 = tr2 = 0; 8968bdf91ceSkrw if (5 == sscanf(arg, "%u:%u%u:%u.%u%c", &m1, &s1, &m2, &s2, &f2, &c)) 8978bdf91ceSkrw goto play_msf; 8988bdf91ceSkrw 8998bdf91ceSkrw /* m1:s1.f1 m2:s2 */ 9008bdf91ceSkrw tr1 = tr2 = f2 = 0; 9018bdf91ceSkrw if (5 == sscanf(arg, "%u:%u.%u%u:%u%c", &m1, &s1, &f1, &m2, &s2, &c)) 9028bdf91ceSkrw goto play_msf; 9038bdf91ceSkrw 9048bdf91ceSkrw /* tr1 m1:s1.f1 tr2 */ 9058bdf91ceSkrw m2 = s2 = f2 = 0; 9068bdf91ceSkrw if (5 == sscanf(arg, "%u%u:%u.%u%u%c", &tr1, &m1, &s1, &f1, &tr2, &c)) 9078bdf91ceSkrw goto play_msf; 9088bdf91ceSkrw 9098bdf91ceSkrw /* m1:s1 m2:s2 */ 9108bdf91ceSkrw tr1 = f1 = tr2 = f2 = 0; 9118bdf91ceSkrw if (4 == sscanf(arg, "%u:%u%u:%u%c", &m1, &s1, &m2, &s2, &c)) 9128bdf91ceSkrw goto play_msf; 9138bdf91ceSkrw 9148bdf91ceSkrw /* tr1 m1:s1.f1 <end of disc> */ 9158bdf91ceSkrw tr2 = m2 = s2 = f2 = 0; 9168bdf91ceSkrw if (4 == sscanf(arg, "%u%u:%u.%u%c", &tr1, &m1, &s1, &f1, &c)) 9178bdf91ceSkrw goto play_msf; 9188bdf91ceSkrw 9198bdf91ceSkrw /* tr1 m1:s1 tr2 */ 9208bdf91ceSkrw f1 = m2 = s2 = f2 = 0; 9218bdf91ceSkrw if (4 == sscanf(arg, "%u%u:%u%u%c", &tr1, &m1, &s1, &tr2, &c)) 9228bdf91ceSkrw goto play_msf; 9238bdf91ceSkrw 9248bdf91ceSkrw /* m1:s1.f1 tr2 */ 9258bdf91ceSkrw tr1 = m2 = s2 = f2 = 0; 9268bdf91ceSkrw if (4 == sscanf(arg, "%u%u:%u%u%c", &m1, &s1, &f1, &tr2, &c)) 9278bdf91ceSkrw goto play_msf; 9288bdf91ceSkrw 9298bdf91ceSkrw /* m1:s1.f1 <end of disc> */ 9308bdf91ceSkrw tr1 = tr2 = m2 = s2 = f2 = 0; 9318bdf91ceSkrw if (3 == sscanf(arg, "%u:%u.%u%c", &m1, &s1, &f1, &c)) 9328bdf91ceSkrw goto play_msf; 9338bdf91ceSkrw 9348bdf91ceSkrw /* tr1 m1:s1 <end of disc> */ 9358bdf91ceSkrw f1 = tr2 = m2 = s2 = f2 = 0; 9368bdf91ceSkrw if (3 == sscanf(arg, "%u%u:%u%c", &tr1, &m1, &s1, &c)) 9378bdf91ceSkrw goto play_msf; 9388bdf91ceSkrw 9398bdf91ceSkrw /* m1:s1 tr2 */ 9408bdf91ceSkrw tr1 = f1 = m2 = s2 = f2 = 0; 9418bdf91ceSkrw if (3 == sscanf(arg, "%u:%u%u%c", &m1, &s1, &tr2, &c)) 9428bdf91ceSkrw goto play_msf; 9438bdf91ceSkrw 9448bdf91ceSkrw /* m1:s1 <end of disc> */ 9458bdf91ceSkrw tr1 = f1 = tr2 = m2 = s2 = f2 = 0; 9468bdf91ceSkrw if (2 == sscanf(arg, "%u:%u%c", &m1, &s1, &c)) 9478bdf91ceSkrw goto play_msf; 9488bdf91ceSkrw 9498bdf91ceSkrw printf("%s: Invalid command arguments\n", __progname); 9508bdf91ceSkrw return (0); 9518bdf91ceSkrw 9528bdf91ceSkrw play_msf: 9538bdf91ceSkrw if (tr1 > n || tr2 > n) { 9548bdf91ceSkrw printf("Track number must be between 0 and %u\n", n); 9558bdf91ceSkrw return (0); 9568bdf91ceSkrw } else if (m1 > 99 || m2 > 99) { 9578bdf91ceSkrw printf("Minutes must be between 0 and 99\n"); 9588bdf91ceSkrw return (0); 9598bdf91ceSkrw } else if (s1 > 59 || s2 > 59) { 9608bdf91ceSkrw printf("Seconds must be between 0 and 59\n"); 9618bdf91ceSkrw return (0); 9628bdf91ceSkrw } if (f1 > 74 || f2 > 74) { 9638bdf91ceSkrw printf("Frames number must be between 0 and 74\n"); 9648bdf91ceSkrw return (0); 9658bdf91ceSkrw } 9668bdf91ceSkrw 9678bdf91ceSkrw if (tr1 > 0) { 9688bdf91ceSkrw /* 9698bdf91ceSkrw * Start time is relative to tr1, Add start time of tr1 9708bdf91ceSkrw * to (m1,s1,f1) to yield absolute start time. 9718bdf91ceSkrw */ 9727a498d98Skrw toc2msf(tr1, &tm, &ts, &tf); 9737a498d98Skrw addmsf(&m1, &s1, &f1, tm, ts, tf); 9747a498d98Skrw 9757a498d98Skrw /* Compare (m1,s1,f1) to start time of next track. */ 9763438b82bSkrw toc2msf(tr1+1, &tm, &ts, &tf); 977b8a783aeSkrw if (cmpmsf(m1, s1, f1, tm, ts, tf) == 1) { 9788bdf91ceSkrw printf("Track %u is not that long.\n", tr1); 9798bdf91ceSkrw return (0); 9808bdf91ceSkrw } 9818bdf91ceSkrw } 9828bdf91ceSkrw 9838bdf91ceSkrw toc2msf(n+1, &tm, &ts, &tf); 9848bdf91ceSkrw if (cmpmsf(m1, s1, f1, tm, ts, tf) == 1) { 9858bdf91ceSkrw printf("Start time is after end of disc.\n"); 986c92011ceSdownsj return (0); 987c92011ceSdownsj } 988c92011ceSdownsj 9898bdf91ceSkrw if (tr2 > 0) { 9907a498d98Skrw /* 9918bdf91ceSkrw * End time is relative to tr2, Add start time of tr2 9928bdf91ceSkrw * to (m2,s2,f2) to yield absolute end time. 9937a498d98Skrw */ 9947a498d98Skrw toc2msf(tr2, &tm, &ts, &tf); 9958dcc8943Skrw addmsf(&m2, &s2, &f2, tm, ts, tf); 9968bdf91ceSkrw 9977a498d98Skrw /* Compare (m2,s2,f2) to start time of next track. */ 9987a498d98Skrw toc2msf(tr2+1, &tm, &ts, &tf); 9997a498d98Skrw if (cmpmsf(m2, s2, f2, tm, ts, tf) == 1) { 10008bdf91ceSkrw printf("Track %u is not that long.\n", tr2); 10017a498d98Skrw return (0); 10027a498d98Skrw } 10037a498d98Skrw } 10047a498d98Skrw 10053438b82bSkrw toc2msf(n+1, &tm, &ts, &tf); 10068bdf91ceSkrw 10078bdf91ceSkrw if (!(tr2 || m2 || s2 || f2)) { 10088bdf91ceSkrw /* Play to end of disc. */ 1009c92011ceSdownsj m2 = tm; 1010c92011ceSdownsj s2 = ts; 1011c92011ceSdownsj f2 = tf; 10128bdf91ceSkrw } else if (cmpmsf(m2, s2, f2, tm, ts, tf) == 1) { 10138bdf91ceSkrw printf("End time is after end of disc.\n"); 10148bdf91ceSkrw return (0); 10158bdf91ceSkrw } 10168bdf91ceSkrw 10178bdf91ceSkrw if (cmpmsf(m1, s1, f1, m2, s2, f2) == 1) { 10188bdf91ceSkrw printf("Start time is after end time.\n"); 10198bdf91ceSkrw return (0); 1020c92011ceSdownsj } 10213438b82bSkrw 1022c92011ceSdownsj return play_msf(m1, s1, f1, m2, s2, f2); 1023c92011ceSdownsj } 1024c92011ceSdownsj 1025c2a796bdSderaadt /* ARGSUSED */ 1026f18d0a50Sderaadt int 10279ed7639aSespie play_prev(char *arg) 10283301428eSangelos { 10293301428eSangelos int trk, min, sec, frm, rc; 10303301428eSangelos struct ioc_toc_header h; 10313301428eSangelos 1032f18d0a50Sderaadt if (status(&trk, &min, &sec, &frm) >= 0) { 10333301428eSangelos trk--; 10343301428eSangelos 10353301428eSangelos rc = ioctl(fd, CDIOREADTOCHEADER, &h); 1036f18d0a50Sderaadt if (rc < 0) { 1037f87f2499Smillert warn("getting toc header"); 10383301428eSangelos return (rc); 10393301428eSangelos } 10403301428eSangelos 10413301428eSangelos if (trk < h.starting_track) 10423301428eSangelos return play_track(h.starting_track, 1, 1043ada687dbSangelos h.ending_track + 1, 1); 1044ada687dbSangelos return play_track(trk, 1, h.ending_track, 1); 10453301428eSangelos } 10463301428eSangelos 10473301428eSangelos return (0); 10483301428eSangelos } 10493301428eSangelos 1050c2a796bdSderaadt /* ARGSUSED */ 1051f18d0a50Sderaadt int 10529ed7639aSespie play_same(char *arg) 10534efcb1a6Sangelos { 10544efcb1a6Sangelos int trk, min, sec, frm, rc; 10554efcb1a6Sangelos struct ioc_toc_header h; 10564efcb1a6Sangelos 1057f18d0a50Sderaadt if (status (&trk, &min, &sec, &frm) >= 0) { 10584efcb1a6Sangelos rc = ioctl(fd, CDIOREADTOCHEADER, &h); 1059f18d0a50Sderaadt if (rc < 0) { 1060f87f2499Smillert warn("getting toc header"); 10614efcb1a6Sangelos return (rc); 10624efcb1a6Sangelos } 10634efcb1a6Sangelos 1064ada687dbSangelos return play_track(trk, 1, h.ending_track, 1); 10654efcb1a6Sangelos } 10664efcb1a6Sangelos 10674efcb1a6Sangelos return (0); 10684efcb1a6Sangelos } 10694efcb1a6Sangelos 1070c2a796bdSderaadt /* ARGSUSED */ 1071f18d0a50Sderaadt int 10729ed7639aSespie play_next(char *arg) 10733301428eSangelos { 10743301428eSangelos int trk, min, sec, frm, rc; 10753301428eSangelos struct ioc_toc_header h; 10763301428eSangelos 1077f18d0a50Sderaadt if (status(&trk, &min, &sec, &frm) >= 0) { 10783301428eSangelos trk++; 10793301428eSangelos rc = ioctl(fd, CDIOREADTOCHEADER, &h); 1080f18d0a50Sderaadt if (rc < 0) { 1081f87f2499Smillert warn("getting toc header"); 10823301428eSangelos return (rc); 10833301428eSangelos } 10843301428eSangelos 1085f18d0a50Sderaadt if (trk > h.ending_track) { 10863301428eSangelos printf("%s: end of CD\n", __progname); 10873301428eSangelos 10883301428eSangelos rc = ioctl(fd, CDIOCSTOP); 10893301428eSangelos 10903301428eSangelos (void) ioctl(fd, CDIOCALLOW); 10913301428eSangelos 10923301428eSangelos return (rc); 10933301428eSangelos } 10943301428eSangelos 1095ada687dbSangelos return play_track(trk, 1, h.ending_track, 1); 10963301428eSangelos } 10973301428eSangelos 10983301428eSangelos return (0); 10993301428eSangelos } 11003301428eSangelos 1101f18d0a50Sderaadt char * 11029ed7639aSespie strstatus(int sts) 1103c92011ceSdownsj { 1104c92011ceSdownsj switch (sts) { 1105f18d0a50Sderaadt case ASTS_INVALID: 1106f18d0a50Sderaadt return ("invalid"); 1107f18d0a50Sderaadt case ASTS_PLAYING: 1108f18d0a50Sderaadt return ("playing"); 1109f18d0a50Sderaadt case ASTS_PAUSED: 1110f18d0a50Sderaadt return ("paused"); 1111f18d0a50Sderaadt case ASTS_COMPLETED: 1112f18d0a50Sderaadt return ("completed"); 1113f18d0a50Sderaadt case ASTS_ERROR: 1114f18d0a50Sderaadt return ("error"); 1115f18d0a50Sderaadt case ASTS_VOID: 1116f18d0a50Sderaadt return ("void"); 1117f18d0a50Sderaadt default: 1118f18d0a50Sderaadt return ("??"); 1119c92011ceSdownsj } 1120c92011ceSdownsj } 1121c92011ceSdownsj 1122c2a796bdSderaadt /* ARGSUSED */ 1123f18d0a50Sderaadt int 11249ed7639aSespie pstatus(char *arg) 1125c92011ceSdownsj { 1126c92011ceSdownsj struct ioc_vol v; 1127c92011ceSdownsj struct ioc_read_subchannel ss; 1128c92011ceSdownsj struct cd_sub_channel_info data; 1129c92011ceSdownsj int rc, trk, m, s, f; 1130dfcdb41bSespie char vis_catalog[1 + 4 * 15]; 1131c92011ceSdownsj 1132c92011ceSdownsj rc = status(&trk, &m, &s, &f); 1133f87f2499Smillert if (rc >= 0) { 11349ed7639aSespie if (verbose) { 11359ed7639aSespie if (track_names) 11369ed7639aSespie printf("Audio status = %d<%s>, " 11379ed7639aSespie "current track = %d (%s)\n" 11389ed7639aSespie "\tcurrent position = %d:%02d.%02d\n", 11399ed7639aSespie rc, strstatus(rc), trk, 11409ed7639aSespie trk ? track_names[trk-1] : "", m, s, f); 1141c92011ceSdownsj else 11429ed7639aSespie printf("Audio status = %d<%s>, " 11439ed7639aSespie "current track = %d, " 11449ed7639aSespie "current position = %d:%02d.%02d\n", 11459ed7639aSespie rc, strstatus(rc), trk, m, s, f); 11469ed7639aSespie } else 1147c92011ceSdownsj printf("%d %d %d:%02d.%02d\n", rc, trk, m, s, f); 1148f87f2499Smillert } else 1149c92011ceSdownsj printf("No current status info available\n"); 1150c92011ceSdownsj 1151c92011ceSdownsj bzero(&ss, sizeof (ss)); 1152c92011ceSdownsj ss.data = &data; 1153c92011ceSdownsj ss.data_len = sizeof (data); 1154c92011ceSdownsj ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 1155c92011ceSdownsj ss.data_format = CD_MEDIA_CATALOG; 1156c92011ceSdownsj rc = ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &ss); 1157c92011ceSdownsj if (rc >= 0) { 1158c92011ceSdownsj printf("Media catalog is %sactive", 1159c92011ceSdownsj ss.data->what.media_catalog.mc_valid ? "": "in"); 1160c92011ceSdownsj if (ss.data->what.media_catalog.mc_valid && 1161dfcdb41bSespie ss.data->what.media_catalog.mc_number[0]) { 1162dfcdb41bSespie strvisx(vis_catalog, 1163c2a796bdSderaadt (char *)ss.data->what.media_catalog.mc_number, 1164dfcdb41bSespie 15, VIS_SAFE); 1165dfcdb41bSespie printf(", number \"%.15s\"", vis_catalog); 1166dfcdb41bSespie } 1167c92011ceSdownsj putchar('\n'); 1168c92011ceSdownsj } else 1169c92011ceSdownsj printf("No media catalog info available\n"); 1170c92011ceSdownsj 1171c92011ceSdownsj rc = ioctl(fd, CDIOCGETVOL, &v); 1172f87f2499Smillert if (rc >= 0) { 1173c92011ceSdownsj if (verbose) 1174c92011ceSdownsj printf("Left volume = %d, right volume = %d\n", 1175c92011ceSdownsj v.vol[0], v.vol[1]); 1176c92011ceSdownsj else 1177c92011ceSdownsj printf("%d %d\n", v.vol[0], v.vol[1]); 1178f87f2499Smillert } else 1179c92011ceSdownsj printf("No volume level info available\n"); 1180c92011ceSdownsj return(0); 1181c92011ceSdownsj } 1182c92011ceSdownsj 1183f18d0a50Sderaadt int 11841837a5caSderaadt cdid(void) 1185ae359c1cSespie { 1186ae359c1cSespie unsigned long id; 1187ae359c1cSespie struct ioc_toc_header h; 1188ae359c1cSespie int rc, n; 1189ae359c1cSespie 1190ae359c1cSespie rc = ioctl(fd, CDIOREADTOCHEADER, &h); 1191ae359c1cSespie if (rc == -1) { 1192ae359c1cSespie warn("getting toc header"); 1193ae359c1cSespie return (rc); 1194ae359c1cSespie } 1195ae359c1cSespie 1196ae359c1cSespie n = h.ending_track - h.starting_track + 1; 1197ae359c1cSespie rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry)); 1198ae359c1cSespie if (rc < 0) 1199ae359c1cSespie return (rc); 1200ae359c1cSespie 1201ae359c1cSespie id = cddb_discid(n, toc_buffer); 1202ae359c1cSespie if (id) { 1203ae359c1cSespie if (verbose) 1204ae359c1cSespie printf("CDID="); 1205ae359c1cSespie printf("%08lx\n", id); 1206ae359c1cSespie } 1207ae359c1cSespie return id ? 0 : 1; 1208ae359c1cSespie } 1209ae359c1cSespie 1210c2a796bdSderaadt /* ARGSUSED */ 1211ae359c1cSespie int 12129ed7639aSespie info(char *arg) 1213c92011ceSdownsj { 1214c92011ceSdownsj struct ioc_toc_header h; 1215c92011ceSdownsj int rc, i, n; 1216c92011ceSdownsj 1217c92011ceSdownsj rc = ioctl(fd, CDIOREADTOCHEADER, &h); 1218c92011ceSdownsj if (rc >= 0) { 1219c92011ceSdownsj if (verbose) 1220c92011ceSdownsj printf("Starting track = %d, ending track = %d, TOC size = %d bytes\n", 1221c92011ceSdownsj h.starting_track, h.ending_track, h.len); 1222c92011ceSdownsj else 1223c92011ceSdownsj printf("%d %d %d\n", h.starting_track, 1224c92011ceSdownsj h.ending_track, h.len); 1225c92011ceSdownsj } else { 1226f87f2499Smillert warn("getting toc header"); 1227c92011ceSdownsj return (rc); 1228c92011ceSdownsj } 1229c92011ceSdownsj 1230c92011ceSdownsj n = h.ending_track - h.starting_track + 1; 1231c92011ceSdownsj rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry)); 1232c92011ceSdownsj if (rc < 0) 1233c92011ceSdownsj return (rc); 1234c92011ceSdownsj 1235c92011ceSdownsj if (verbose) { 1236c92011ceSdownsj printf("track start duration block length type\n"); 1237c92011ceSdownsj printf("-------------------------------------------------\n"); 1238c92011ceSdownsj } 1239c92011ceSdownsj 1240c92011ceSdownsj for (i = 0; i < n; i++) { 1241c92011ceSdownsj printf("%5d ", toc_buffer[i].track); 12429ed7639aSespie prtrack(toc_buffer + i, 0, NULL); 1243c92011ceSdownsj } 1244c92011ceSdownsj printf("%5d ", toc_buffer[n].track); 12459ed7639aSespie prtrack(toc_buffer + n, 1, NULL); 12469ed7639aSespie return (0); 12479ed7639aSespie } 12489ed7639aSespie 12499ed7639aSespie int 12509ed7639aSespie cddbinfo(char *arg) 12519ed7639aSespie { 12529ed7639aSespie struct ioc_toc_header h; 12539ed7639aSespie int rc, i, n; 12549ed7639aSespie 12559ed7639aSespie rc = ioctl(fd, CDIOREADTOCHEADER, &h); 12569ed7639aSespie if (rc == -1) { 12579ed7639aSespie warn("getting toc header"); 12589ed7639aSespie return (rc); 12599ed7639aSespie } 12609ed7639aSespie 12619ed7639aSespie n = h.ending_track - h.starting_track + 1; 12629ed7639aSespie rc = read_toc_entrys((n + 1) * sizeof (struct cd_toc_entry)); 12639ed7639aSespie if (rc < 0) 12649ed7639aSespie return (rc); 12659ed7639aSespie 12669ed7639aSespie if (track_names) 12679ed7639aSespie free_names(track_names); 12689ed7639aSespie track_names = NULL; 12699ed7639aSespie 12709ed7639aSespie track_names = cddb(cddb_host, n, toc_buffer, arg); 12719ed7639aSespie if (!track_names) 12729ed7639aSespie return(0); 12739ed7639aSespie 12749ed7639aSespie printf("-------------------------------------------------\n"); 12759ed7639aSespie 12769ed7639aSespie for (i = 0; i < n; i++) { 12779ed7639aSespie printf("%5d ", toc_buffer[i].track); 12789ed7639aSespie prtrack(toc_buffer + i, 0, track_names[i]); 12799ed7639aSespie } 12809ed7639aSespie printf("%5d ", toc_buffer[n].track); 12819ed7639aSespie prtrack(toc_buffer + n, 1, ""); 1282c92011ceSdownsj return (0); 1283c92011ceSdownsj } 1284c92011ceSdownsj 1285f18d0a50Sderaadt void 12869ed7639aSespie lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f) 1287c92011ceSdownsj { 1288c92011ceSdownsj lba += 150; /* block start offset */ 1289c92011ceSdownsj lba &= 0xffffff; /* negative lbas use only 24 bits */ 1290c92011ceSdownsj *m = lba / (60 * 75); 1291c92011ceSdownsj lba %= (60 * 75); 1292c92011ceSdownsj *s = lba / 75; 1293c92011ceSdownsj *f = lba % 75; 1294c92011ceSdownsj } 1295c92011ceSdownsj 1296f18d0a50Sderaadt unsigned int 1297da50f41aSespie msf2lba(u_char m, u_char s, u_char f) 1298c92011ceSdownsj { 1299c92011ceSdownsj return (((m * 60) + s) * 75 + f) - 150; 1300c92011ceSdownsj } 1301c92011ceSdownsj 13029ed7639aSespie unsigned long 13039ed7639aSespie entry2time(struct cd_toc_entry *e) 13049ed7639aSespie { 13059ed7639aSespie int block; 13069ed7639aSespie u_char m, s, f; 13079ed7639aSespie 13089ed7639aSespie if (msf) { 13099ed7639aSespie return (e->addr.msf.minute * 60 + e->addr.msf.second); 13109ed7639aSespie } else { 131143844f6cSkrw block = e->addr.lba; 13129ed7639aSespie lba2msf(block, &m, &s, &f); 13139ed7639aSespie return (m*60+s); 13149ed7639aSespie } 13159ed7639aSespie } 13169ed7639aSespie 13179ed7639aSespie unsigned long 13189ed7639aSespie entry2frames(struct cd_toc_entry *e) 13199ed7639aSespie { 13209ed7639aSespie int block; 13219ed7639aSespie unsigned char m, s, f; 13229ed7639aSespie 13239ed7639aSespie if (msf) { 13249ed7639aSespie return e->addr.msf.frame + e->addr.msf.second * 75 + 13259ed7639aSespie e->addr.msf.minute * 60 * 75; 13269ed7639aSespie } else { 132743844f6cSkrw block = e->addr.lba; 13289ed7639aSespie lba2msf(block, &m, &s, &f); 13299ed7639aSespie return f + s * 75 + m * 60 * 75; 13309ed7639aSespie } 13319ed7639aSespie } 13329ed7639aSespie 1333f18d0a50Sderaadt void 13349ed7639aSespie prtrack(struct cd_toc_entry *e, int lastflag, char *name) 1335c92011ceSdownsj { 1336c92011ceSdownsj int block, next, len; 1337c92011ceSdownsj u_char m, s, f; 1338c92011ceSdownsj 1339c92011ceSdownsj if (msf) { 13409ed7639aSespie if (!name || lastflag) 1341c92011ceSdownsj /* Print track start */ 1342c92011ceSdownsj printf("%2d:%02d.%02d ", e->addr.msf.minute, 1343c92011ceSdownsj e->addr.msf.second, e->addr.msf.frame); 1344c92011ceSdownsj 1345c92011ceSdownsj block = msf2lba(e->addr.msf.minute, e->addr.msf.second, 1346c92011ceSdownsj e->addr.msf.frame); 1347c92011ceSdownsj } else { 134843844f6cSkrw block = e->addr.lba; 13499ed7639aSespie if (!name || lastflag) { 1350c92011ceSdownsj lba2msf(block, &m, &s, &f); 1351c92011ceSdownsj /* Print track start */ 1352c92011ceSdownsj printf("%2d:%02d.%02d ", m, s, f); 1353c92011ceSdownsj } 13549ed7639aSespie } 1355c92011ceSdownsj if (lastflag) { 13569ed7639aSespie if (!name) 1357c92011ceSdownsj /* Last track -- print block */ 1358c92011ceSdownsj printf(" - %6d - -\n", block); 13599ed7639aSespie else 13609ed7639aSespie printf("\n"); 1361c92011ceSdownsj return; 1362c92011ceSdownsj } 1363c92011ceSdownsj 1364c92011ceSdownsj if (msf) 1365c92011ceSdownsj next = msf2lba(e[1].addr.msf.minute, e[1].addr.msf.second, 1366c92011ceSdownsj e[1].addr.msf.frame); 1367c92011ceSdownsj else 136843844f6cSkrw next = e[1].addr.lba; 1369c92011ceSdownsj len = next - block; 1370fbd1c299Sfgsch lba2msf(len - 150, &m, &s, &f); 1371c92011ceSdownsj 13729ed7639aSespie if (name) 13739ed7639aSespie printf("%2d:%02d.%02d %s\n", m, s, f, name); 1374c92011ceSdownsj /* Print duration, block, length, type */ 13759ed7639aSespie else 1376c92011ceSdownsj printf("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, 1377c92011ceSdownsj (e->control & 4) ? "data" : "audio"); 1378c92011ceSdownsj } 1379c92011ceSdownsj 1380f18d0a50Sderaadt int 13819ed7639aSespie play_track(int tstart, int istart, int tend, int iend) 1382c92011ceSdownsj { 1383c92011ceSdownsj struct ioc_play_track t; 1384c92011ceSdownsj 1385c92011ceSdownsj t.start_track = tstart; 1386c92011ceSdownsj t.start_index = istart; 1387c92011ceSdownsj t.end_track = tend; 1388c92011ceSdownsj t.end_index = iend; 1389c92011ceSdownsj 1390c92011ceSdownsj return ioctl(fd, CDIOCPLAYTRACKS, &t); 1391c92011ceSdownsj } 1392c92011ceSdownsj 1393f18d0a50Sderaadt int 13949ed7639aSespie play_blocks(int blk, int len) 1395c92011ceSdownsj { 1396c92011ceSdownsj struct ioc_play_blocks t; 1397c92011ceSdownsj 1398c92011ceSdownsj t.blk = blk; 1399c92011ceSdownsj t.len = len; 1400c92011ceSdownsj 1401c92011ceSdownsj return ioctl(fd, CDIOCPLAYBLOCKS, &t); 1402c92011ceSdownsj } 1403c92011ceSdownsj 1404f18d0a50Sderaadt int 14059ed7639aSespie setvol(int left, int right) 1406c92011ceSdownsj { 1407c92011ceSdownsj struct ioc_vol v; 1408c92011ceSdownsj 1409c92011ceSdownsj v.vol[0] = left; 1410c92011ceSdownsj v.vol[1] = right; 1411c92011ceSdownsj v.vol[2] = 0; 1412c92011ceSdownsj v.vol[3] = 0; 1413c92011ceSdownsj 1414c92011ceSdownsj return ioctl(fd, CDIOCSETVOL, &v); 1415c92011ceSdownsj } 1416c92011ceSdownsj 1417f18d0a50Sderaadt int 14189ed7639aSespie read_toc_entrys(int len) 1419c92011ceSdownsj { 1420c92011ceSdownsj struct ioc_read_toc_entry t; 1421c92011ceSdownsj 14223a87bfaeScsapuntz if (toc_buffer) { 14233a87bfaeScsapuntz free(toc_buffer); 14243a87bfaeScsapuntz toc_buffer = 0; 14253a87bfaeScsapuntz } 14263a87bfaeScsapuntz 14273a87bfaeScsapuntz toc_buffer = malloc(len); 14283a87bfaeScsapuntz 14293a87bfaeScsapuntz if (!toc_buffer) { 14303a87bfaeScsapuntz errno = ENOMEM; 14313a87bfaeScsapuntz return (-1); 14323a87bfaeScsapuntz } 14333a87bfaeScsapuntz 1434c92011ceSdownsj t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 1435c92011ceSdownsj t.starting_track = 0; 1436c92011ceSdownsj t.data_len = len; 1437c92011ceSdownsj t.data = toc_buffer; 1438c92011ceSdownsj 1439c92011ceSdownsj return (ioctl(fd, CDIOREADTOCENTRYS, (char *) &t)); 1440c92011ceSdownsj } 1441c92011ceSdownsj 1442f18d0a50Sderaadt int 14439ed7639aSespie play_msf(int start_m, int start_s, int start_f, int end_m, int end_s, int end_f) 1444c92011ceSdownsj { 1445c92011ceSdownsj struct ioc_play_msf a; 1446c92011ceSdownsj 1447c92011ceSdownsj a.start_m = start_m; 1448c92011ceSdownsj a.start_s = start_s; 1449c92011ceSdownsj a.start_f = start_f; 1450c92011ceSdownsj a.end_m = end_m; 1451c92011ceSdownsj a.end_s = end_s; 1452c92011ceSdownsj a.end_f = end_f; 1453c92011ceSdownsj 1454c92011ceSdownsj return ioctl(fd, CDIOCPLAYMSF, (char *) &a); 1455c92011ceSdownsj } 1456c92011ceSdownsj 145767831131Sespie int 14589ed7639aSespie status(int *trk, int *min, int *sec, int *frame) 1459c92011ceSdownsj { 1460c92011ceSdownsj struct ioc_read_subchannel s; 1461c92011ceSdownsj struct cd_sub_channel_info data; 1462c92011ceSdownsj u_char mm, ss, ff; 1463c92011ceSdownsj 1464c92011ceSdownsj bzero(&s, sizeof (s)); 1465c92011ceSdownsj s.data = &data; 1466c92011ceSdownsj s.data_len = sizeof (data); 1467c92011ceSdownsj s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 1468c92011ceSdownsj s.data_format = CD_CURRENT_POSITION; 1469c92011ceSdownsj 1470c92011ceSdownsj if (ioctl(fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) 1471c92011ceSdownsj return -1; 1472c92011ceSdownsj 1473c92011ceSdownsj *trk = s.data->what.position.track_number; 1474c92011ceSdownsj if (msf) { 1475c92011ceSdownsj *min = s.data->what.position.reladdr.msf.minute; 1476c92011ceSdownsj *sec = s.data->what.position.reladdr.msf.second; 1477c92011ceSdownsj *frame = s.data->what.position.reladdr.msf.frame; 1478c92011ceSdownsj } else { 147943844f6cSkrw /* 148043844f6cSkrw * NOTE: CDIOCREADSUBCHANNEL does not put the lba info into 148143844f6cSkrw * host order like CDIOREADTOCENTRYS does. 148243844f6cSkrw */ 148343844f6cSkrw lba2msf(betoh32(s.data->what.position.reladdr.lba), &mm, &ss, 148443844f6cSkrw &ff); 1485c92011ceSdownsj *min = mm; 1486c92011ceSdownsj *sec = ss; 1487c92011ceSdownsj *frame = ff; 1488c92011ceSdownsj } 1489c92011ceSdownsj 1490c92011ceSdownsj return s.data->header.audio_status; 1491c92011ceSdownsj } 1492c92011ceSdownsj 1493f18d0a50Sderaadt char * 14949ed7639aSespie input(int *cmd) 1495c92011ceSdownsj { 1496ec6762c7Sfgsch char *buf; 1497ec6762c7Sfgsch int siz = 0; 1498c92011ceSdownsj char *p; 14998b59c5f0Sotto HistEvent hev; 1500c92011ceSdownsj 1501c92011ceSdownsj do { 1502ec6762c7Sfgsch if ((buf = (char *) el_gets(el, &siz)) == NULL || !siz) { 1503c92011ceSdownsj *cmd = CMD_QUIT; 1504c92011ceSdownsj fprintf(stderr, "\r\n"); 1505c92011ceSdownsj return (0); 1506c92011ceSdownsj } 1507ec6762c7Sfgsch if (strlen(buf) > 1) 15088b59c5f0Sotto history(hist, &hev, H_ENTER, buf); 1509c92011ceSdownsj p = parse(buf, cmd); 1510c92011ceSdownsj } while (!p); 1511c92011ceSdownsj return (p); 1512c92011ceSdownsj } 1513c92011ceSdownsj 1514f18d0a50Sderaadt char * 15159ed7639aSespie parse(char *buf, int *cmd) 1516c92011ceSdownsj { 1517c92011ceSdownsj struct cmdtab *c; 1518c92011ceSdownsj char *p; 1519c92011ceSdownsj int len; 1520c92011ceSdownsj 1521c92011ceSdownsj for (p=buf; isspace(*p); p++) 1522c92011ceSdownsj continue; 1523c92011ceSdownsj 1524c92011ceSdownsj if (isdigit(*p) || (p[0] == '#' && isdigit(p[1]))) { 1525c92011ceSdownsj *cmd = CMD_PLAY; 1526c92011ceSdownsj return (p); 1527c92011ceSdownsj } 1528c92011ceSdownsj 1529c92011ceSdownsj for (buf = p; *p && ! isspace(*p); p++) 1530c92011ceSdownsj continue; 1531c92011ceSdownsj 1532c92011ceSdownsj len = p - buf; 1533c92011ceSdownsj if (!len) 1534c92011ceSdownsj return (0); 1535c92011ceSdownsj 1536c92011ceSdownsj if (*p) { /* It must be a spacing character! */ 1537c92011ceSdownsj char *q; 1538c92011ceSdownsj 1539c92011ceSdownsj *p++ = 0; 1540c92011ceSdownsj for (q=p; *q && *q != '\n' && *q != '\r'; q++) 1541c92011ceSdownsj continue; 1542c92011ceSdownsj *q = 0; 1543c92011ceSdownsj } 1544c92011ceSdownsj 1545c92011ceSdownsj *cmd = -1; 1546c92011ceSdownsj for (c=cmdtab; c->name; ++c) { 1547c92011ceSdownsj /* Is it an exact match? */ 1548c92011ceSdownsj if (!strcasecmp(buf, c->name)) { 1549c92011ceSdownsj *cmd = c->command; 1550c92011ceSdownsj break; 1551c92011ceSdownsj } 1552c92011ceSdownsj 1553c92011ceSdownsj /* Try short hand forms then... */ 1554c92011ceSdownsj if (len >= c->min && ! strncasecmp(buf, c->name, len)) { 1555c92011ceSdownsj if (*cmd != -1 && *cmd != c->command) { 1556c92011ceSdownsj fprintf(stderr, "Ambiguous command\n"); 1557c92011ceSdownsj return (0); 1558c92011ceSdownsj } 1559c92011ceSdownsj *cmd = c->command; 1560c92011ceSdownsj } 1561c92011ceSdownsj } 1562c92011ceSdownsj 1563c92011ceSdownsj if (*cmd == -1) { 1564c92011ceSdownsj fprintf(stderr, "%s: Invalid command, enter ``help'' for commands.\n", 1565c92011ceSdownsj __progname); 1566c92011ceSdownsj return (0); 1567c92011ceSdownsj } 1568c92011ceSdownsj 1569c92011ceSdownsj while (isspace(*p)) 1570c92011ceSdownsj p++; 1571c92011ceSdownsj return p; 1572c92011ceSdownsj } 1573c92011ceSdownsj 1574f18d0a50Sderaadt int 15757993cdedSmjc open_cd(char *dev, int needwrite) 1576f87f2499Smillert { 1577f87f2499Smillert char *realdev; 157895cc45e3Smillert int tries; 1579c92011ceSdownsj 1580c7ed6047Sav if (fd > -1) { 1581c7ed6047Sav if (needwrite && !writeperm) { 1582c7ed6047Sav close(fd); 1583c7ed6047Sav fd = -1; 1584c7ed6047Sav } else 1585c92011ceSdownsj return (1); 1586c7ed6047Sav } 1587c92011ceSdownsj 158895cc45e3Smillert for (tries = 0; fd < 0 && tries < 10; tries++) { 15897993cdedSmjc if (needwrite) 15907993cdedSmjc fd = opendev(dev, O_RDWR, OPENDEV_PART, &realdev); 15917993cdedSmjc else 1592f87f2499Smillert fd = opendev(dev, O_RDONLY, OPENDEV_PART, &realdev); 1593c92011ceSdownsj if (fd < 0) { 159495cc45e3Smillert if (errno == ENXIO) { 1595c92011ceSdownsj /* ENXIO has an overloaded meaning here. 1596c92011ceSdownsj * The original "Device not configured" should 1597c92011ceSdownsj * be interpreted as "No disc in drive %s". */ 1598f87f2499Smillert warnx("No disc in drive %s.", realdev); 1599c92011ceSdownsj return (0); 160095cc45e3Smillert } else if (errno != EIO) { 160195cc45e3Smillert /* EIO may simply mean the device is not ready 160295cc45e3Smillert * yet which is common with CD changers. */ 160395cc45e3Smillert warn("Can't open %s", realdev); 160495cc45e3Smillert return (0); 1605c92011ceSdownsj } 160695cc45e3Smillert } 160795cc45e3Smillert sleep(1); 160895cc45e3Smillert } 160995cc45e3Smillert if (fd < 0) { 1610f87f2499Smillert warn("Can't open %s", realdev); 1611f87f2499Smillert return (0); 1612c92011ceSdownsj } 1613c7ed6047Sav writeperm = needwrite; 1614c92011ceSdownsj return (1); 1615c92011ceSdownsj } 1616ec6762c7Sfgsch 1617ec6762c7Sfgsch char * 1618ec6762c7Sfgsch prompt(void) 1619ec6762c7Sfgsch { 1620ec6762c7Sfgsch return (verbose ? "cdio> " : ""); 1621ec6762c7Sfgsch } 1622ec6762c7Sfgsch 1623ec6762c7Sfgsch void 1624ec6762c7Sfgsch switch_el(void) 1625ec6762c7Sfgsch { 16268b59c5f0Sotto HistEvent hev; 16278b59c5f0Sotto 1628ec6762c7Sfgsch if (el == NULL && hist == NULL) { 16298b59c5f0Sotto el = el_init(__progname, stdin, stdout, stderr); 1630ec6762c7Sfgsch hist = history_init(); 16318b59c5f0Sotto history(hist, &hev, H_SETSIZE, 100); 1632ec6762c7Sfgsch el_set(el, EL_HIST, history, hist); 1633ec6762c7Sfgsch el_set(el, EL_EDITOR, "emacs"); 1634ec6762c7Sfgsch el_set(el, EL_PROMPT, prompt); 1635ec6762c7Sfgsch el_set(el, EL_SIGNAL, 1); 1636ec6762c7Sfgsch el_source(el, NULL); 1637ec6762c7Sfgsch 1638ec6762c7Sfgsch } else { 1639ec6762c7Sfgsch if (hist != NULL) { 1640ec6762c7Sfgsch history_end(hist); 1641ec6762c7Sfgsch hist = NULL; 1642ec6762c7Sfgsch } 1643ec6762c7Sfgsch if (el != NULL) { 1644ec6762c7Sfgsch el_end(el); 1645ec6762c7Sfgsch el = NULL; 1646ec6762c7Sfgsch } 1647ec6762c7Sfgsch } 1648ec6762c7Sfgsch } 16498dcc8943Skrw 16508dcc8943Skrw void 16518dcc8943Skrw addmsf(u_int *m, u_int *s, u_int *f, u_char m_inc, u_char s_inc, u_char f_inc) 16528dcc8943Skrw { 16538dcc8943Skrw *f += f_inc; 16548dcc8943Skrw if (*f > 75) { 16558dcc8943Skrw *s += *f / 75; 16568dcc8943Skrw *f %= 75; 16578dcc8943Skrw } 16588dcc8943Skrw 16598dcc8943Skrw *s += s_inc; 16608dcc8943Skrw if (*s > 60) { 16618dcc8943Skrw *m += *s / 60; 16628dcc8943Skrw *s %= 60; 16638dcc8943Skrw } 16648dcc8943Skrw 16658dcc8943Skrw *m += m_inc; 16668dcc8943Skrw } 16673438b82bSkrw 1668b8a783aeSkrw int 1669b8a783aeSkrw cmpmsf(u_char m1, u_char s1, u_char f1, u_char m2, u_char s2, u_char f2) 1670b8a783aeSkrw { 1671b8a783aeSkrw if (m1 > m2) 1672b8a783aeSkrw return (1); 1673b8a783aeSkrw else if (m1 < m2) 1674b8a783aeSkrw return (-1); 1675b8a783aeSkrw 1676b8a783aeSkrw if (s1 > s2) 1677b8a783aeSkrw return (1); 1678b8a783aeSkrw else if (s1 < s2) 1679b8a783aeSkrw return (-1); 1680b8a783aeSkrw 1681b8a783aeSkrw if (f1 > f2) 1682b8a783aeSkrw return (1); 1683b8a783aeSkrw else if (f1 < f2) 1684b8a783aeSkrw return (-1); 1685b8a783aeSkrw 1686b8a783aeSkrw return (0); 1687b8a783aeSkrw } 1688b8a783aeSkrw 16893438b82bSkrw void 16903438b82bSkrw toc2msf(u_int track, u_char *m, u_char *s, u_char *f) 16913438b82bSkrw { 16923438b82bSkrw struct cd_toc_entry *ctep; 16933438b82bSkrw 16943438b82bSkrw ctep = &toc_buffer[track - 1]; 16953438b82bSkrw 16963438b82bSkrw if (msf) { 16973438b82bSkrw *m = ctep->addr.msf.minute; 16983438b82bSkrw *s = ctep->addr.msf.second; 16993438b82bSkrw *f = ctep->addr.msf.frame; 17003438b82bSkrw } else 17013438b82bSkrw lba2msf(ctep->addr.lba, m, s, f); 17023438b82bSkrw } 1703