110099Sjkh/* 213884Sache * Compact Disc Control Utility by Serge V. Vakulenko <vak@cronyx.ru>. 310099Sjkh * Based on the non-X based CD player by Jean-Marc Zucconi and 413832Sache * Andrey A. Chernov. 513884Sache * 613985Sache * Fixed and further modified on 5-Sep-1995 by Jukka Ukkonen <jau@funet.fi>. 713985Sache * 813985Sache * 11-Sep-1995: Jukka A. Ukkonen <jau@funet.fi> 913985Sache * A couple of further fixes to my own earlier "fixes". 1013985Sache * 1113985Sache * 18-Sep-1995: Jukka A. Ukkonen <jau@funet.fi> 1213985Sache * Added an ability to specify addresses relative to the 1313985Sache * beginning of a track. This is in fact a variation of 1413985Sache * doing the simple play_msf() call. 1513985Sache * 1613985Sache * 11-Oct-1995: Serge V.Vakulenko <vak@cronyx.ru> 1713985Sache * New eject algorithm. 1813985Sache * Some code style reformatting. 19180507Sgahr * 20180507Sgahr * 13-Dec-1999: Knut A. Syed <kas@kas.no> 21180507Sgahr * Volume-command modified. If used with only one 22180507Sgahr * parameter it now sets both channels. If used without 23180507Sgahr * parameters it will print volume-info. 24180507Sgahr * Version 2.0.1 25180507Sgahr * 26180507Sgahr * 27-Jun-2008 Pietro Cerutti <gahr@FreeBSD.org> 27180507Sgahr * Further enhancement to volume. Values not in range 0-255 28180507Sgahr * are now reduced to be in range. This prevents overflow in 29180507Sgahr * the uchar storing the volume (256 -> 0, -20 -> 236, ...). 30180507Sgahr * Version 2.0.2 31180507Sgahr * 3210099Sjkh */ 3313985Sache 34114601Sobrien#include <sys/cdefs.h> 35114601Sobrien__FBSDID("$FreeBSD: releng/11.0/usr.sbin/cdcontrol/cdcontrol.c 227225 2011-11-06 16:52:26Z ed $"); 3629103Scharnier 3777168Skris#include <sys/cdio.h> 3896213Smaxim#include <sys/cdrio.h> 3977168Skris#include <sys/file.h> 4077168Skris#include <sys/ioctl.h> 4177168Skris#include <sys/param.h> 4290868Smike#include <arpa/inet.h> 4313985Sache#include <ctype.h> 4429103Scharnier#include <err.h> 4529103Scharnier#include <errno.h> 4677168Skris#include <histedit.h> 4796213Smaxim#include <limits.h> 4869793Sobrien#include <paths.h> 4910099Sjkh#include <stdio.h> 5010099Sjkh#include <stdlib.h> 5110099Sjkh#include <string.h> 5210099Sjkh#include <unistd.h> 5377168Skris#include <vis.h> 5410099Sjkh 55180507Sgahr#define VERSION "2.0.2" 5610099Sjkh 5787573Smikeh#define ASTS_INVALID 0x00 /* Audio status byte not valid */ 5887573Smikeh#define ASTS_PLAYING 0x11 /* Audio play operation in progress */ 5987573Smikeh#define ASTS_PAUSED 0x12 /* Audio play operation paused */ 6087573Smikeh#define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */ 6187573Smikeh#define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */ 6287573Smikeh#define ASTS_VOID 0x15 /* No current audio status to return */ 6310099Sjkh 64122855Seivind#ifdef DEFAULT_CD_DRIVE 65122855Seivind# error "Setting DEFAULT_CD_DRIVE is no longer supported" 6613985Sache#endif 6713985Sache 6887573Smikeh#define CMD_DEBUG 1 6987573Smikeh#define CMD_EJECT 2 7087573Smikeh#define CMD_HELP 3 7187573Smikeh#define CMD_INFO 4 7287573Smikeh#define CMD_PAUSE 5 7387573Smikeh#define CMD_PLAY 6 7487573Smikeh#define CMD_QUIT 7 7587573Smikeh#define CMD_RESUME 8 7687573Smikeh#define CMD_STOP 9 7787573Smikeh#define CMD_VOLUME 10 7887573Smikeh#define CMD_CLOSE 11 7987573Smikeh#define CMD_RESET 12 8087573Smikeh#define CMD_SET 13 8187573Smikeh#define CMD_STATUS 14 8287573Smikeh#define CMD_CDID 15 8387573Smikeh#define CMD_NEXT 16 8487573Smikeh#define CMD_PREVIOUS 17 8596213Smaxim#define CMD_SPEED 18 8687573Smikeh#define STATUS_AUDIO 0x1 8787573Smikeh#define STATUS_MEDIA 0x2 8887573Smikeh#define STATUS_VOLUME 0x4 8913985Sache 90227225Sedstatic struct cmdtab { 9110099Sjkh int command; 9287568Smikeh const char *name; 9387568Smikeh unsigned min; 9487568Smikeh const char *args; 9510099Sjkh} cmdtab[] = { 9687573Smikeh{ CMD_CLOSE, "close", 1, "" }, 9787573Smikeh{ CMD_DEBUG, "debug", 1, "on | off" }, 9887573Smikeh{ CMD_EJECT, "eject", 1, "" }, 9987573Smikeh{ CMD_HELP, "?", 1, 0 }, 10087573Smikeh{ CMD_HELP, "help", 1, "" }, 10187573Smikeh{ CMD_INFO, "info", 1, "" }, 10287573Smikeh{ CMD_NEXT, "next", 1, "" }, 10387573Smikeh{ CMD_PAUSE, "pause", 2, "" }, 10487573Smikeh{ CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" }, 10587573Smikeh{ CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" }, 10687573Smikeh{ CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" }, 10787573Smikeh{ CMD_PLAY, "play", 1, "[#block [len]]" }, 10887573Smikeh{ CMD_PREVIOUS, "previous", 2, "" }, 10987573Smikeh{ CMD_QUIT, "quit", 1, "" }, 11087573Smikeh{ CMD_RESET, "reset", 4, "" }, 11187573Smikeh{ CMD_RESUME, "resume", 1, "" }, 11287573Smikeh{ CMD_SET, "set", 2, "msf | lba" }, 11387573Smikeh{ CMD_STATUS, "status", 1, "[audio | media | volume]" }, 11487573Smikeh{ CMD_STOP, "stop", 3, "" }, 11587573Smikeh{ CMD_VOLUME, "volume", 1, 116180507Sgahr "<l&r> <l> <r> | left | right | mute | mono | stereo" }, 11787573Smikeh{ CMD_CDID, "cdid", 2, "" }, 11896213Smaxim{ CMD_SPEED, "speed", 2, "speed" }, 11987573Smikeh{ 0, NULL, 0, NULL } 12010099Sjkh}; 12110099Sjkh 122227225Sedstatic struct cd_toc_entry toc_buffer[100]; 12310099Sjkh 124227225Sedstatic const char *cdname; 125227225Sedstatic int fd = -1; 126227225Sedstatic int verbose = 1; 127227225Sedstatic int msf = 1; 12810099Sjkh 129227225Sedstatic int setvol(int, int); 130227225Sedstatic int read_toc_entrys(int); 131227225Sedstatic int play_msf(int, int, int, int, int, int); 132227225Sedstatic int play_track(int, int, int, int); 133227225Sedstatic int status(int *, int *, int *, int *); 134227225Sedstatic int open_cd(void); 135227225Sedstatic int next_prev(char *arg, int); 136227225Sedstatic int play(char *arg); 137227225Sedstatic int info(char *arg); 138227225Sedstatic int cdid(void); 139227225Sedstatic int pstatus(char *arg); 140227225Sedstatic char *input(int *); 141227225Sedstatic void prtrack(struct cd_toc_entry *e, int lastflag); 142227225Sedstatic void lba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f); 143227225Sedstatic unsigned int msf2lba(u_char m, u_char s, u_char f); 144227225Sedstatic int play_blocks(int blk, int len); 145227225Sedstatic int run(int cmd, char *arg); 146227225Sedstatic char *parse(char *buf, int *cmd); 147227225Sedstatic void help(void); 148227225Sedstatic void usage(void); 149227225Sedstatic char *use_cdrom_instead(const char *); 150227225Sedstatic const char *strstatus(int); 15199800Salfredstatic u_int dbprog_discid(void); 152227225Sedstatic const char *cdcontrol_prompt(void); 15310099Sjkh 154227225Sedstatic void 155227225Sedhelp(void) 15610099Sjkh{ 15710099Sjkh struct cmdtab *c; 15887568Smikeh const char *s; 15987568Smikeh char n; 16013985Sache int i; 16110099Sjkh 16210099Sjkh for (c=cmdtab; c->name; ++c) { 16310099Sjkh if (! c->args) 16410099Sjkh continue; 16513985Sache printf("\t"); 16613985Sache for (i = c->min, s = c->name; *s; s++, i--) { 16713985Sache if (i > 0) 16813985Sache n = toupper(*s); 16913985Sache else 17013985Sache n = *s; 17113985Sache putchar(n); 17213985Sache } 17310099Sjkh if (*c->args) 17410099Sjkh printf (" %s", c->args); 17510099Sjkh printf ("\n"); 17610099Sjkh } 17713985Sache printf ("\n\tThe word \"play\" is not required for the play commands.\n"); 17813985Sache printf ("\tThe plain target address is taken as a synonym for play.\n"); 17910099Sjkh} 18010099Sjkh 181227225Sedstatic void 182227225Sedusage(void) 18310099Sjkh{ 18443479Sbillf fprintf (stderr, "usage: cdcontrol [-sv] [-f device] [command ...]\n"); 18510099Sjkh exit (1); 18610099Sjkh} 18710099Sjkh 188227225Sedstatic char * 189227225Seduse_cdrom_instead(const char *old_envvar) 19071122Sjoe{ 19171122Sjoe char *device; 19271122Sjoe 19371122Sjoe device = getenv(old_envvar); 19471122Sjoe if (device) 19571122Sjoe warnx("%s environment variable deprecated, " 19671122Sjoe "please use CDROM in the future.", old_envvar); 19771122Sjoe return device; 19871122Sjoe} 19971122Sjoe 20071122Sjoe 201227225Sedint 202227225Sedmain(int argc, char **argv) 20310099Sjkh{ 20410099Sjkh int cmd; 20510099Sjkh char *arg; 20610099Sjkh 20710099Sjkh for (;;) { 20810099Sjkh switch (getopt (argc, argv, "svhf:")) { 209176407Sru case -1: 21010099Sjkh break; 21110099Sjkh case 's': 21210099Sjkh verbose = 0; 21310099Sjkh continue; 21410099Sjkh case 'v': 21510099Sjkh verbose = 2; 21610099Sjkh continue; 21710099Sjkh case 'f': 21810099Sjkh cdname = optarg; 21910099Sjkh continue; 22010099Sjkh case 'h': 22110099Sjkh default: 22210099Sjkh usage (); 22310099Sjkh } 22410099Sjkh break; 22510099Sjkh } 22610099Sjkh argc -= optind; 22710099Sjkh argv += optind; 22810099Sjkh 22913985Sache if (argc > 0 && ! strcasecmp (*argv, "help")) 23010099Sjkh usage (); 23110099Sjkh 23210099Sjkh if (! cdname) { 23370149Sdes cdname = getenv("CDROM"); 23470149Sdes } 23570149Sdes 23675324Sjoe if (! cdname) 23775324Sjoe cdname = use_cdrom_instead("MUSIC_CD"); 23875324Sjoe if (! cdname) 23975324Sjoe cdname = use_cdrom_instead("CD_DRIVE"); 24075324Sjoe if (! cdname) 24175324Sjoe cdname = use_cdrom_instead("DISC"); 24275324Sjoe if (! cdname) 24375324Sjoe cdname = use_cdrom_instead("CDPLAY"); 24475324Sjoe 24510099Sjkh if (argc > 0) { 24610099Sjkh char buf[80], *p; 247197833Sjh int len, rc; 24810099Sjkh 24913985Sache for (p=buf; argc-->0; ++argv) { 25010099Sjkh len = strlen (*argv); 25113985Sache 25210099Sjkh if (p + len >= buf + sizeof (buf) - 1) 25310099Sjkh usage (); 25413985Sache 25510099Sjkh if (p > buf) 25610099Sjkh *p++ = ' '; 25713985Sache 25810099Sjkh strcpy (p, *argv); 25910099Sjkh p += len; 26010099Sjkh } 26110099Sjkh *p = 0; 26210099Sjkh arg = parse (buf, &cmd); 263197833Sjh rc = run (cmd, arg); 264197833Sjh if (rc < 0 && verbose) 265197833Sjh warn(NULL); 266197833Sjh 267197833Sjh return (rc); 26810099Sjkh } 26910099Sjkh 27010099Sjkh if (verbose == 1) 27110099Sjkh verbose = isatty (0); 27213985Sache 27310099Sjkh if (verbose) { 27413985Sache printf ("Compact Disc Control utility, version %s\n", VERSION); 27510099Sjkh printf ("Type `?' for command list\n\n"); 27610099Sjkh } 27710099Sjkh 27810099Sjkh for (;;) { 27910099Sjkh arg = input (&cmd); 28010099Sjkh if (run (cmd, arg) < 0) { 28110099Sjkh if (verbose) 28229103Scharnier warn(NULL); 28310099Sjkh close (fd); 28410099Sjkh fd = -1; 28510099Sjkh } 28610099Sjkh fflush (stdout); 28710099Sjkh } 28810099Sjkh} 28910099Sjkh 290227225Sedstatic int 291227225Sedrun(int cmd, char *arg) 29210099Sjkh{ 29396213Smaxim long speed; 294180507Sgahr int l, r, rc, count; 29510099Sjkh 29610099Sjkh switch (cmd) { 29713985Sache 29810099Sjkh case CMD_QUIT: 29910099Sjkh exit (0); 30010099Sjkh 30113985Sache case CMD_INFO: 30213985Sache if (fd < 0 && ! open_cd ()) 30313985Sache return (0); 30410099Sjkh 30510099Sjkh return info (arg); 30610099Sjkh 30763091Sjoe case CMD_CDID: 30863091Sjoe if (fd < 0 && ! open_cd ()) 30963091Sjoe return (0); 31063091Sjoe 31163091Sjoe return cdid (); 31263091Sjoe 31313884Sache case CMD_STATUS: 31413985Sache if (fd < 0 && ! open_cd ()) 31513985Sache return (0); 31613985Sache 31713884Sache return pstatus (arg); 31813884Sache 31977168Skris case CMD_NEXT: 32077168Skris case CMD_PREVIOUS: 32177168Skris if (fd < 0 && ! open_cd ()) 32277168Skris return (0); 32377168Skris 32477168Skris while (isspace (*arg)) 32577168Skris arg++; 32677168Skris 32777168Skris return next_prev (arg, cmd); 32877168Skris 32910099Sjkh case CMD_PAUSE: 33013985Sache if (fd < 0 && ! open_cd ()) 33113985Sache return (0); 33213985Sache 33310099Sjkh return ioctl (fd, CDIOCPAUSE); 33410099Sjkh 33510099Sjkh case CMD_RESUME: 33613985Sache if (fd < 0 && ! open_cd ()) 33713985Sache return (0); 33813985Sache 33910099Sjkh return ioctl (fd, CDIOCRESUME); 34010099Sjkh 34110099Sjkh case CMD_STOP: 34213985Sache if (fd < 0 && ! open_cd ()) 34313985Sache return (0); 34410099Sjkh 34513985Sache rc = ioctl (fd, CDIOCSTOP); 34613985Sache 34713985Sache (void) ioctl (fd, CDIOCALLOW); 34813985Sache 34913985Sache return (rc); 35013985Sache 35113884Sache case CMD_RESET: 35213985Sache if (fd < 0 && ! open_cd ()) 35313985Sache return (0); 35413985Sache 35513884Sache rc = ioctl (fd, CDIOCRESET); 35613884Sache if (rc < 0) 35713884Sache return rc; 35813884Sache close(fd); 35913884Sache fd = -1; 36013884Sache return (0); 36113884Sache 36210099Sjkh case CMD_DEBUG: 36313985Sache if (fd < 0 && ! open_cd ()) 36413985Sache return (0); 36513985Sache 36613985Sache if (! strcasecmp (arg, "on")) 36710099Sjkh return ioctl (fd, CDIOCSETDEBUG); 36813985Sache 36913985Sache if (! strcasecmp (arg, "off")) 37010099Sjkh return ioctl (fd, CDIOCCLRDEBUG); 37113985Sache 37229103Scharnier warnx("invalid command arguments"); 37313985Sache 37410099Sjkh return (0); 37510099Sjkh 37610099Sjkh case CMD_EJECT: 37713985Sache if (fd < 0 && ! open_cd ()) 37813985Sache return (0); 37913985Sache 38010099Sjkh (void) ioctl (fd, CDIOCALLOW); 38110099Sjkh rc = ioctl (fd, CDIOCEJECT); 38210099Sjkh if (rc < 0) 38310099Sjkh return (rc); 38413865Sache return (0); 38513865Sache 38613985Sache case CMD_CLOSE: 38713985Sache if (fd < 0 && ! open_cd ()) 38813985Sache return (0); 38913985Sache 39013985Sache (void) ioctl (fd, CDIOCALLOW); 39113865Sache rc = ioctl (fd, CDIOCCLOSE); 39213865Sache if (rc < 0) 39313865Sache return (rc); 39413865Sache close(fd); 39510099Sjkh fd = -1; 39610099Sjkh return (0); 39710099Sjkh 39810099Sjkh case CMD_PLAY: 39913985Sache if (fd < 0 && ! open_cd ()) 40013985Sache return (0); 40113985Sache 40213985Sache while (isspace (*arg)) 40313985Sache arg++; 40413985Sache 40510099Sjkh return play (arg); 40610099Sjkh 40713884Sache case CMD_SET: 40813985Sache if (! strcasecmp (arg, "msf")) 40913884Sache msf = 1; 41013985Sache else if (! strcasecmp (arg, "lba")) 41113884Sache msf = 0; 41213884Sache else 41329103Scharnier warnx("invalid command arguments"); 41413884Sache return (0); 41513884Sache 41610099Sjkh case CMD_VOLUME: 41713985Sache if (fd < 0 && !open_cd ()) 41813985Sache return (0); 41910099Sjkh 420201608Sdwmalone if (! strlen (arg)) { 421201608Sdwmalone char volume[] = "volume"; 422180507Sgahr 423201608Sdwmalone return pstatus (volume); 424201608Sdwmalone } 425201608Sdwmalone 42613985Sache if (! strncasecmp (arg, "left", strlen(arg))) 42710099Sjkh return ioctl (fd, CDIOCSETLEFT); 42813985Sache 42913985Sache if (! strncasecmp (arg, "right", strlen(arg))) 43010099Sjkh return ioctl (fd, CDIOCSETRIGHT); 43113985Sache 43213985Sache if (! strncasecmp (arg, "mono", strlen(arg))) 43310099Sjkh return ioctl (fd, CDIOCSETMONO); 43413985Sache 43513985Sache if (! strncasecmp (arg, "stereo", strlen(arg))) 43610099Sjkh return ioctl (fd, CDIOCSETSTERIO); 43710099Sjkh 43813985Sache if (! strncasecmp (arg, "mute", strlen(arg))) 43913985Sache return ioctl (fd, CDIOCSETMUTE); 44013985Sache 441180507Sgahr count = sscanf (arg, "%d %d", &l, &r); 442180507Sgahr if (count == 1) 443180507Sgahr return setvol (l, l); 444180507Sgahr if (count == 2) 445180507Sgahr return setvol (l, r); 446180507Sgahr warnx("invalid command arguments"); 447180507Sgahr return (0); 44813985Sache 44996213Smaxim case CMD_SPEED: 45096213Smaxim if (fd < 0 && ! open_cd ()) 45196213Smaxim return (0); 45296213Smaxim 45396213Smaxim errno = 0; 454105421Snjl if (strcasecmp("max", arg) == 0) 455105421Snjl speed = CDR_MAX_SPEED; 456105421Snjl else 457105421Snjl speed = strtol(arg, NULL, 10) * 177; 458105421Snjl if (speed <= 0 || speed > INT_MAX) { 45996213Smaxim warnx("invalid command arguments %s", arg); 46096213Smaxim return (0); 46196213Smaxim } 46296213Smaxim return ioctl(fd, CDRIOCREADSPEED, &speed); 46396213Smaxim 46413985Sache default: 46513985Sache case CMD_HELP: 46613985Sache help (); 46713985Sache return (0); 46813985Sache 46910099Sjkh } 47010099Sjkh} 47110099Sjkh 472227225Sedstatic int 473227225Sedplay(char *arg) 47410099Sjkh{ 47510099Sjkh struct ioc_toc_header h; 47687568Smikeh unsigned int n; 47787568Smikeh int rc, start, end = 0, istart = 1, iend = 1; 47810099Sjkh 47910099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 48013985Sache 48110099Sjkh if (rc < 0) 48210099Sjkh return (rc); 48310099Sjkh 48410099Sjkh n = h.ending_track - h.starting_track + 1; 48510099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 48613985Sache 48710099Sjkh if (rc < 0) 48810099Sjkh return (rc); 48910099Sjkh 49013989Sache if (! arg || ! *arg) { 49113985Sache /* Play the whole disc */ 49213989Sache if (msf) 49313989Sache return play_blocks (0, msf2lba (toc_buffer[n].addr.msf.minute, 49413989Sache toc_buffer[n].addr.msf.second, 49513989Sache toc_buffer[n].addr.msf.frame)); 49613989Sache else 49713989Sache return play_blocks (0, ntohl(toc_buffer[n].addr.lba)); 49813989Sache } 49910099Sjkh 50010099Sjkh if (strchr (arg, '#')) { 50113985Sache /* Play block #blk [ len ] */ 50210099Sjkh int blk, len = 0; 50310099Sjkh 50410099Sjkh if (2 != sscanf (arg, "#%d%d", &blk, &len) && 50513985Sache 1 != sscanf (arg, "#%d", &blk)) 50613985Sache goto Clean_up; 50713985Sache 50813989Sache if (len == 0) { 50913989Sache if (msf) 51013989Sache len = msf2lba (toc_buffer[n].addr.msf.minute, 51113989Sache toc_buffer[n].addr.msf.second, 51213989Sache toc_buffer[n].addr.msf.frame) - blk; 51313989Sache else 51413989Sache len = ntohl(toc_buffer[n].addr.lba) - blk; 51513989Sache } 51610099Sjkh return play_blocks (blk, len); 51710099Sjkh } 51810099Sjkh 51910099Sjkh if (strchr (arg, ':')) { 52010099Sjkh /* 52110099Sjkh * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] 52213985Sache * 52313985Sache * Will now also undestand timed addresses relative 52413985Sache * to the beginning of a track in the form... 52513985Sache * 52613985Sache * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]] 52710099Sjkh */ 52813985Sache unsigned tr1, tr2; 52913985Sache unsigned m1, m2, s1, s2, f1, f2; 53013989Sache unsigned char tm, ts, tf; 53110099Sjkh 53213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 53313985Sache if (8 == sscanf (arg, "%d %d:%d.%d %d %d:%d.%d", 53413985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2)) 53513985Sache goto Play_Relative_Addresses; 53613985Sache 53713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 53813985Sache if (7 == sscanf (arg, "%d %d:%d %d %d:%d.%d", 53913985Sache &tr1, &m1, &s1, &tr2, &m2, &s2, &f2)) 54013985Sache goto Play_Relative_Addresses; 54113985Sache 54213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 54313985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d %d:%d", 54413985Sache &tr1, &m1, &s1, &f1, &tr2, &m2, &s2)) 54513985Sache goto Play_Relative_Addresses; 54613985Sache 54713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 54813985Sache if (7 == sscanf (arg, "%d %d:%d.%d %d:%d.%d", 54913985Sache &tr1, &m1, &s1, &f1, &m2, &s2, &f2)) 55013985Sache goto Play_Relative_Addresses; 55113985Sache 55213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 55313985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d:%d", 55413985Sache &tr1, &m1, &s1, &f1, &m2, &s2)) 55513985Sache goto Play_Relative_Addresses; 55613985Sache 55713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 55813985Sache if (6 == sscanf (arg, "%d %d:%d %d:%d.%d", 55913985Sache &tr1, &m1, &s1, &m2, &s2, &f2)) 56013985Sache goto Play_Relative_Addresses; 56113985Sache 56213985Sache tr2 = m2 = s2 = f2 = f1 = 0; 56313985Sache if (6 == sscanf (arg, "%d %d:%d.%d %d %d", 56413985Sache &tr1, &m1, &s1, &f1, &tr2, &m2)) 56513985Sache goto Play_Relative_Addresses; 56613985Sache 56713985Sache tr2 = m2 = s2 = f2 = f1 = 0; 56813985Sache if (5 == sscanf (arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2)) 56913985Sache goto Play_Relative_Addresses; 57013985Sache 57113985Sache tr2 = m2 = s2 = f2 = f1 = 0; 57213985Sache if (5 == sscanf (arg, "%d %d:%d %d %d", 57313985Sache &tr1, &m1, &s1, &tr2, &m2)) 57413985Sache goto Play_Relative_Addresses; 57513985Sache 57613985Sache tr2 = m2 = s2 = f2 = f1 = 0; 57713985Sache if (5 == sscanf (arg, "%d %d:%d.%d %d", 57813985Sache &tr1, &m1, &s1, &f1, &tr2)) 57913985Sache goto Play_Relative_Addresses; 58013985Sache 58113985Sache tr2 = m2 = s2 = f2 = f1 = 0; 58213985Sache if (4 == sscanf (arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2)) 58313985Sache goto Play_Relative_Addresses; 58413985Sache 58513985Sache tr2 = m2 = s2 = f2 = f1 = 0; 58613985Sache if (4 == sscanf (arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1)) 58713985Sache goto Play_Relative_Addresses; 58813985Sache 58913985Sache tr2 = m2 = s2 = f2 = f1 = 0; 59013985Sache if (3 == sscanf (arg, "%d %d:%d", &tr1, &m1, &s1)) 59113985Sache goto Play_Relative_Addresses; 59213985Sache 59313985Sache tr2 = m2 = s2 = f2 = f1 = 0; 59413985Sache goto Try_Absolute_Timed_Addresses; 59513985Sache 59613985SachePlay_Relative_Addresses: 59713985Sache if (! tr1) 59813985Sache tr1 = 1; 59913985Sache else if (tr1 > n) 60013985Sache tr1 = n; 60113985Sache 602112559Seivind tr1--; 603112559Seivind 60413989Sache if (msf) { 60513989Sache tm = toc_buffer[tr1].addr.msf.minute; 60613989Sache ts = toc_buffer[tr1].addr.msf.second; 60713989Sache tf = toc_buffer[tr1].addr.msf.frame; 60813989Sache } else 60913989Sache lba2msf(ntohl(toc_buffer[tr1].addr.lba), 61013989Sache &tm, &ts, &tf); 61113989Sache if ((m1 > tm) 61213989Sache || ((m1 == tm) 61313989Sache && ((s1 > ts) 61413989Sache || ((s1 == ts) 61513989Sache && (f1 > tf))))) { 61613985Sache printf ("Track %d is not that long.\n", tr1); 61713985Sache return (0); 61813985Sache } 61913985Sache 62013989Sache f1 += tf; 62113985Sache if (f1 >= 75) { 62213985Sache s1 += f1 / 75; 62313985Sache f1 %= 75; 62413985Sache } 62513985Sache 62613989Sache s1 += ts; 62713985Sache if (s1 >= 60) { 62813985Sache m1 += s1 / 60; 62913985Sache s1 %= 60; 63013985Sache } 63113985Sache 63213989Sache m1 += tm; 63313985Sache 63413985Sache if (! tr2) { 63513985Sache if (m2 || s2 || f2) { 63613985Sache tr2 = tr1; 63713985Sache f2 += f1; 63813985Sache if (f2 >= 75) { 63913985Sache s2 += f2 / 75; 64013985Sache f2 %= 75; 64113985Sache } 64213985Sache 64313985Sache s2 += s1; 64413985Sache if (s2 > 60) { 64513985Sache m2 += s2 / 60; 64613985Sache s2 %= 60; 64713985Sache } 64813985Sache 64913985Sache m2 += m1; 65013985Sache } else { 65113985Sache tr2 = n; 65213989Sache if (msf) { 65313989Sache m2 = toc_buffer[n].addr.msf.minute; 65413989Sache s2 = toc_buffer[n].addr.msf.second; 65513989Sache f2 = toc_buffer[n].addr.msf.frame; 65613989Sache } else { 65713989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 65813989Sache &tm, &ts, &tf); 65913989Sache m2 = tm; 66013989Sache s2 = ts; 66113989Sache f2 = tf; 66213989Sache } 66313985Sache } 66413985Sache } else if (tr2 > n) { 66513985Sache tr2 = n; 66613985Sache m2 = s2 = f2 = 0; 66713985Sache } else { 66813985Sache if (m2 || s2 || f2) 66913985Sache tr2--; 67013989Sache if (msf) { 67113989Sache tm = toc_buffer[tr2].addr.msf.minute; 67213989Sache ts = toc_buffer[tr2].addr.msf.second; 67313989Sache tf = toc_buffer[tr2].addr.msf.frame; 67413989Sache } else 67513989Sache lba2msf(ntohl(toc_buffer[tr2].addr.lba), 67613989Sache &tm, &ts, &tf); 67713989Sache f2 += tf; 67813985Sache if (f2 >= 75) { 67913985Sache s2 += f2 / 75; 68013985Sache f2 %= 75; 68113985Sache } 68213985Sache 68313989Sache s2 += ts; 68413985Sache if (s2 > 60) { 68513985Sache m2 += s2 / 60; 68613985Sache s2 %= 60; 68713985Sache } 68813985Sache 68913989Sache m2 += tm; 69013985Sache } 69113985Sache 69213989Sache if (msf) { 69313989Sache tm = toc_buffer[n].addr.msf.minute; 69413989Sache ts = toc_buffer[n].addr.msf.second; 69513989Sache tf = toc_buffer[n].addr.msf.frame; 69613989Sache } else 69713989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 69813989Sache &tm, &ts, &tf); 69913985Sache if ((tr2 < n) 70013989Sache && ((m2 > tm) 70113989Sache || ((m2 == tm) 70213989Sache && ((s2 > ts) 70313989Sache || ((s2 == ts) 70413989Sache && (f2 > tf)))))) { 70513985Sache printf ("The playing time of the disc is not that long.\n"); 70613985Sache return (0); 70713985Sache } 70813985Sache return (play_msf (m1, s1, f1, m2, s2, f2)); 70913985Sache 71013985SacheTry_Absolute_Timed_Addresses: 71113985Sache if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d", 71213985Sache &m1, &s1, &f1, &m2, &s2, &f2) && 71310099Sjkh 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && 71410099Sjkh 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && 71510099Sjkh 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) && 71610099Sjkh 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && 71710099Sjkh 2 != sscanf (arg, "%d:%d", &m1, &s1)) 71813985Sache goto Clean_up; 71913985Sache 72010099Sjkh if (m2 == 0) { 72113989Sache if (msf) { 72213989Sache m2 = toc_buffer[n].addr.msf.minute; 72313989Sache s2 = toc_buffer[n].addr.msf.second; 72413989Sache f2 = toc_buffer[n].addr.msf.frame; 72513989Sache } else { 72613989Sache lba2msf(ntohl(toc_buffer[n].addr.lba), 72713989Sache &tm, &ts, &tf); 72813989Sache m2 = tm; 72913989Sache s2 = ts; 73013989Sache f2 = tf; 73113989Sache } 73210099Sjkh } 73310099Sjkh return play_msf (m1, s1, f1, m2, s2, f2); 73410099Sjkh } 73510099Sjkh 73610099Sjkh /* 73710099Sjkh * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] 73810099Sjkh */ 73910099Sjkh if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && 74010099Sjkh 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) && 74110099Sjkh 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) && 74210099Sjkh 2 != sscanf (arg, "%d.%d", &start, &istart) && 74310099Sjkh 2 != sscanf (arg, "%d%d", &start, &end) && 74410099Sjkh 1 != sscanf (arg, "%d", &start)) 74513985Sache goto Clean_up; 74613985Sache 74710099Sjkh if (end == 0) 74810099Sjkh end = n; 74913985Sache return (play_track (start, istart, end, iend)); 75013985Sache 75113985SacheClean_up: 75229103Scharnier warnx("invalid command arguments"); 75313985Sache return (0); 75410099Sjkh} 75510099Sjkh 756227225Sedstatic int 757227225Sednext_prev(char *arg, int cmd) 75877168Skris{ 75977168Skris struct ioc_toc_header h; 76077168Skris int dir, junk, n, off, rc, trk; 76177168Skris 76277168Skris dir = (cmd == CMD_NEXT) ? 1 : -1; 76377168Skris rc = ioctl (fd, CDIOREADTOCHEADER, &h); 76477168Skris if (rc < 0) 76577168Skris return (rc); 76677168Skris 76777168Skris n = h.ending_track - h.starting_track + 1; 76877168Skris rc = status (&trk, &junk, &junk, &junk); 76977168Skris if (rc < 0) 77077168Skris return (-1); 77177168Skris 77277168Skris if (arg && *arg) { 77377168Skris if (sscanf (arg, "%u", &off) != 1) { 77477168Skris warnx("invalid command argument"); 77577168Skris return (0); 77677168Skris } else 77777168Skris trk += off * dir; 77877168Skris } else 77977168Skris trk += dir; 78077168Skris 78177168Skris if (trk > h.ending_track) 78277168Skris trk = 1; 78377168Skris 78477168Skris return (play_track (trk, 1, n, 1)); 78577168Skris} 78677168Skris 787227225Sedstatic const char * 788227225Sedstrstatus(int sts) 78910099Sjkh{ 79010099Sjkh switch (sts) { 79187573Smikeh case ASTS_INVALID: return ("invalid"); 79287573Smikeh case ASTS_PLAYING: return ("playing"); 79387573Smikeh case ASTS_PAUSED: return ("paused"); 79487573Smikeh case ASTS_COMPLETED: return ("completed"); 79587573Smikeh case ASTS_ERROR: return ("error"); 79687573Smikeh case ASTS_VOID: return ("void"); 79787573Smikeh default: return ("??"); 79810099Sjkh } 79910099Sjkh} 80010099Sjkh 801227225Sedstatic int 802227225Sedpstatus(char *arg) 80310099Sjkh{ 80410099Sjkh struct ioc_vol v; 80513888Sache struct ioc_read_subchannel ss; 80613888Sache struct cd_sub_channel_info data; 80713884Sache int rc, trk, m, s, f; 80832782Sjmz int what = 0; 80977168Skris char *p, vmcn[(4 * 15) + 1]; 81010099Sjkh 81132782Sjmz while ((p = strtok(arg, " \t"))) { 81232782Sjmz arg = 0; 81332782Sjmz if (!strncasecmp(p, "audio", strlen(p))) 81432782Sjmz what |= STATUS_AUDIO; 81532782Sjmz else if (!strncasecmp(p, "media", strlen(p))) 81632782Sjmz what |= STATUS_MEDIA; 81732782Sjmz else if (!strncasecmp(p, "volume", strlen(p))) 81832782Sjmz what |= STATUS_VOLUME; 81932782Sjmz else { 82032782Sjmz warnx("invalid command arguments"); 82132782Sjmz return 0; 82232782Sjmz } 82332782Sjmz } 82432782Sjmz if (!what) 82532782Sjmz what = STATUS_AUDIO|STATUS_MEDIA|STATUS_VOLUME; 82632782Sjmz if (what & STATUS_AUDIO) { 82732782Sjmz rc = status (&trk, &m, &s, &f); 82832782Sjmz if (rc >= 0) 82910099Sjkh if (verbose) 83032782Sjmz printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n", 83132782Sjmz rc, strstatus (rc), trk, m, s, f); 83210099Sjkh else 83332782Sjmz printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f); 83432782Sjmz else 83513888Sache printf ("No current status info available\n"); 83632782Sjmz } 83732782Sjmz if (what & STATUS_MEDIA) { 83832782Sjmz bzero (&ss, sizeof (ss)); 83932782Sjmz ss.data = &data; 84032782Sjmz ss.data_len = sizeof (data); 84132782Sjmz ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 84232782Sjmz ss.data_format = CD_MEDIA_CATALOG; 84332782Sjmz rc = ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &ss); 84432782Sjmz if (rc >= 0) { 84513889Sache printf("Media catalog is %sactive", 84687573Smikeh ss.data->what.media_catalog.mc_valid ? "": "in"); 84716736Sache if (ss.data->what.media_catalog.mc_valid && 84816736Sache ss.data->what.media_catalog.mc_number[0]) 84977168Skris { 85077168Skris strvisx (vmcn, ss.data->what.media_catalog.mc_number, 85177168Skris (sizeof (vmcn) - 1) / 4, VIS_OCTAL | VIS_NL); 85277168Skris printf(", number \"%.*s\"", (int)sizeof (vmcn), vmcn); 85377168Skris } 85413889Sache putchar('\n'); 85532782Sjmz } else 85613888Sache printf("No media catalog info available\n"); 85732782Sjmz } 85832782Sjmz if (what & STATUS_VOLUME) { 85932782Sjmz rc = ioctl (fd, CDIOCGETVOL, &v); 86032782Sjmz if (rc >= 0) 86110099Sjkh if (verbose) 86232782Sjmz printf ("Left volume = %d, right volume = %d\n", 86332782Sjmz v.vol[0], v.vol[1]); 86410099Sjkh else 86532782Sjmz printf ("%d %d\n", v.vol[0], v.vol[1]); 86632782Sjmz else 86713888Sache printf ("No volume level info available\n"); 86832782Sjmz } 86913884Sache return(0); 87013884Sache} 87110099Sjkh 87263091Sjoe/* 87363091Sjoe * dbprog_sum 87463091Sjoe * Convert an integer to its text string representation, and 87563091Sjoe * compute its checksum. Used by dbprog_discid to derive the 87663091Sjoe * disc ID. 87763091Sjoe * 87863091Sjoe * Args: 87963091Sjoe * n - The integer value. 88063091Sjoe * 88163091Sjoe * Return: 88263091Sjoe * The integer checksum. 88363091Sjoe */ 88463091Sjoestatic int 88563091Sjoedbprog_sum(int n) 88663091Sjoe{ 88763091Sjoe char buf[12], 88863091Sjoe *p; 88963091Sjoe int ret = 0; 89063091Sjoe 89163091Sjoe /* For backward compatibility this algorithm must not change */ 89263091Sjoe sprintf(buf, "%u", n); 89363091Sjoe for (p = buf; *p != '\0'; p++) 89463091Sjoe ret += (*p - '0'); 89563091Sjoe 89663091Sjoe return(ret); 89763091Sjoe} 89863091Sjoe 89963091Sjoe 90063091Sjoe/* 90163091Sjoe * dbprog_discid 90263091Sjoe * Compute a magic disc ID based on the number of tracks, 90363091Sjoe * the length of each track, and a checksum of the string 90463091Sjoe * that represents the offset of each track. 90563091Sjoe * 90663091Sjoe * Args: 90763091Sjoe * s - Pointer to the curstat_t structure. 90863091Sjoe * 90963091Sjoe * Return: 91063091Sjoe * The integer disc ID. 91163091Sjoe */ 91263091Sjoestatic u_int 913201608Sdwmalonedbprog_discid(void) 91463091Sjoe{ 91563091Sjoe struct ioc_toc_header h; 91663091Sjoe int rc; 91763091Sjoe int i, ntr, 91863091Sjoe t = 0, 91963091Sjoe n = 0; 92063091Sjoe 92163091Sjoe rc = ioctl (fd, CDIOREADTOCHEADER, &h); 92263091Sjoe if (rc < 0) 92363091Sjoe return 0; 92463091Sjoe ntr = h.ending_track - h.starting_track + 1; 92563091Sjoe i = msf; 92663091Sjoe msf = 1; 92763091Sjoe rc = read_toc_entrys ((ntr + 1) * sizeof (struct cd_toc_entry)); 92863091Sjoe msf = i; 92963091Sjoe if (rc < 0) 93063091Sjoe return 0; 93163091Sjoe /* For backward compatibility this algorithm must not change */ 93263091Sjoe for (i = 0; i < ntr; i++) { 93363091Sjoe#define TC_MM(a) toc_buffer[a].addr.msf.minute 93463091Sjoe#define TC_SS(a) toc_buffer[a].addr.msf.second 93563091Sjoe n += dbprog_sum((TC_MM(i) * 60) + TC_SS(i)); 93663091Sjoe 93763091Sjoe t += ((TC_MM(i+1) * 60) + TC_SS(i+1)) - 93887573Smikeh ((TC_MM(i) * 60) + TC_SS(i)); 93963091Sjoe } 94063091Sjoe 94163091Sjoe return((n % 0xff) << 24 | t << 8 | ntr); 94263091Sjoe} 94363091Sjoe 944227225Sedstatic int 945227225Sedcdid(void) 94663091Sjoe{ 94763091Sjoe u_int id; 94863091Sjoe 94963091Sjoe id = dbprog_discid(); 95063091Sjoe if (id) 95163091Sjoe { 95263091Sjoe if (verbose) 95363091Sjoe printf ("CDID="); 95463091Sjoe printf ("%08x\n",id); 95563091Sjoe } 95663091Sjoe return id ? 0 : 1; 95763091Sjoe} 95863091Sjoe 959227225Sedstatic int 960227225Sedinfo(char *arg __unused) 96113884Sache{ 96213884Sache struct ioc_toc_header h; 96313884Sache int rc, i, n; 96413884Sache 96510099Sjkh rc = ioctl (fd, CDIOREADTOCHEADER, &h); 96613888Sache if (rc >= 0) { 96710099Sjkh if (verbose) 96810099Sjkh printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n", 96910099Sjkh h.starting_track, h.ending_track, h.len); 97010099Sjkh else 97110099Sjkh printf ("%d %d %d\n", h.starting_track, 97210099Sjkh h.ending_track, h.len); 97313888Sache } else { 97429103Scharnier warn("getting toc header"); 97510099Sjkh return (rc); 97610099Sjkh } 97710099Sjkh 97810099Sjkh n = h.ending_track - h.starting_track + 1; 97910099Sjkh rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); 98010099Sjkh if (rc < 0) 98110099Sjkh return (rc); 98213985Sache 98310099Sjkh if (verbose) { 98410099Sjkh printf ("track start duration block length type\n"); 98510099Sjkh printf ("-------------------------------------------------\n"); 98610099Sjkh } 98713985Sache 98810099Sjkh for (i = 0; i < n; i++) { 98910099Sjkh printf ("%5d ", toc_buffer[i].track); 99010099Sjkh prtrack (toc_buffer + i, 0); 99110099Sjkh } 99213867Sache printf ("%5d ", toc_buffer[n].track); 99310099Sjkh prtrack (toc_buffer + n, 1); 99410099Sjkh return (0); 99510099Sjkh} 99610099Sjkh 997227225Sedstatic void 998227225Sedlba2msf(unsigned long lba, u_char *m, u_char *s, u_char *f) 99910099Sjkh{ 100087573Smikeh lba += 150; /* block start offset */ 100187573Smikeh lba &= 0xffffff; /* negative lbas use only 24 bits */ 100210099Sjkh *m = lba / (60 * 75); 100310099Sjkh lba %= (60 * 75); 100410099Sjkh *s = lba / 75; 100510099Sjkh *f = lba % 75; 100610099Sjkh} 100710099Sjkh 1008227225Sedstatic unsigned int 1009227225Sedmsf2lba(u_char m, u_char s, u_char f) 101010099Sjkh{ 101110099Sjkh return (((m * 60) + s) * 75 + f) - 150; 101210099Sjkh} 101310099Sjkh 1014227225Sedstatic void 1015227225Sedprtrack(struct cd_toc_entry *e, int lastflag) 101610099Sjkh{ 101710099Sjkh int block, next, len; 101810099Sjkh u_char m, s, f; 101910099Sjkh 102013884Sache if (msf) { 102113884Sache /* Print track start */ 102213884Sache printf ("%2d:%02d.%02d ", e->addr.msf.minute, 102313884Sache e->addr.msf.second, e->addr.msf.frame); 102410099Sjkh 102513884Sache block = msf2lba (e->addr.msf.minute, e->addr.msf.second, 102613884Sache e->addr.msf.frame); 102713884Sache } else { 102813884Sache block = ntohl(e->addr.lba); 102913884Sache lba2msf(block, &m, &s, &f); 103013884Sache /* Print track start */ 103113884Sache printf ("%2d:%02d.%02d ", m, s, f); 103213884Sache } 103310099Sjkh if (lastflag) { 103410099Sjkh /* Last track -- print block */ 103510099Sjkh printf (" - %6d - -\n", block); 103610099Sjkh return; 103710099Sjkh } 103810099Sjkh 103913884Sache if (msf) 104013884Sache next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second, 104113884Sache e[1].addr.msf.frame); 104213884Sache else 104313884Sache next = ntohl(e[1].addr.lba); 104410099Sjkh len = next - block; 1045103861Smaxim /* Take into account a start offset time. */ 1046103861Smaxim lba2msf (len - 150, &m, &s, &f); 104710099Sjkh 104810099Sjkh /* Print duration, block, length, type */ 104910099Sjkh printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, 105013985Sache (e->control & 4) ? "data" : "audio"); 105110099Sjkh} 105210099Sjkh 1053227225Sedstatic int 1054227225Sedplay_track(int tstart, int istart, int tend, int iend) 105510099Sjkh{ 105610099Sjkh struct ioc_play_track t; 105710099Sjkh 105810099Sjkh t.start_track = tstart; 105910099Sjkh t.start_index = istart; 106010099Sjkh t.end_track = tend; 106110099Sjkh t.end_index = iend; 106213985Sache 106310099Sjkh return ioctl (fd, CDIOCPLAYTRACKS, &t); 106410099Sjkh} 106510099Sjkh 1066227225Sedstatic int 1067227225Sedplay_blocks(int blk, int len) 106810099Sjkh{ 106913985Sache struct ioc_play_blocks t; 107010099Sjkh 107110099Sjkh t.blk = blk; 107210099Sjkh t.len = len; 107313985Sache 107410099Sjkh return ioctl (fd, CDIOCPLAYBLOCKS, &t); 107510099Sjkh} 107610099Sjkh 1077227225Sedstatic int 1078227225Sedsetvol(int left, int right) 107910099Sjkh{ 108013985Sache struct ioc_vol v; 108110099Sjkh 1082180507Sgahr left = left < 0 ? 0 : left > 255 ? 255 : left; 1083180507Sgahr right = right < 0 ? 0 : right > 255 ? 255 : right; 1084180507Sgahr 108513985Sache v.vol[0] = left; 108613985Sache v.vol[1] = right; 108710099Sjkh v.vol[2] = 0; 108810099Sjkh v.vol[3] = 0; 108913985Sache 109010099Sjkh return ioctl (fd, CDIOCSETVOL, &v); 109110099Sjkh} 109210099Sjkh 1093227225Sedstatic int 1094227225Sedread_toc_entrys(int len) 109510099Sjkh{ 109610099Sjkh struct ioc_read_toc_entry t; 109710099Sjkh 109813884Sache t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 109913737Sache t.starting_track = 0; 110010099Sjkh t.data_len = len; 110110099Sjkh t.data = toc_buffer; 110213985Sache 110313985Sache return (ioctl (fd, CDIOREADTOCENTRYS, (char *) &t)); 110410099Sjkh} 110510099Sjkh 1106227225Sedstatic int 1107227225Sedplay_msf(int start_m, int start_s, int start_f, 110813985Sache int end_m, int end_s, int end_f) 110910099Sjkh{ 111087573Smikeh struct ioc_play_msf a; 111110099Sjkh 111210099Sjkh a.start_m = start_m; 111310099Sjkh a.start_s = start_s; 111410099Sjkh a.start_f = start_f; 111510099Sjkh a.end_m = end_m; 111610099Sjkh a.end_s = end_s; 111710099Sjkh a.end_f = end_f; 111813985Sache 111910099Sjkh return ioctl (fd, CDIOCPLAYMSF, (char *) &a); 112010099Sjkh} 112110099Sjkh 1122227225Sedstatic int 1123227225Sedstatus(int *trk, int *min, int *sec, int *frame) 112410099Sjkh{ 112510099Sjkh struct ioc_read_subchannel s; 112610099Sjkh struct cd_sub_channel_info data; 112713884Sache u_char mm, ss, ff; 112810099Sjkh 112910099Sjkh bzero (&s, sizeof (s)); 113010099Sjkh s.data = &data; 113110099Sjkh s.data_len = sizeof (data); 113213884Sache s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; 113310099Sjkh s.data_format = CD_CURRENT_POSITION; 113413985Sache 113510099Sjkh if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) 113610099Sjkh return -1; 113713985Sache 113810099Sjkh *trk = s.data->what.position.track_number; 113913884Sache if (msf) { 114013884Sache *min = s.data->what.position.reladdr.msf.minute; 114113884Sache *sec = s.data->what.position.reladdr.msf.second; 114213884Sache *frame = s.data->what.position.reladdr.msf.frame; 114313884Sache } else { 114413884Sache lba2msf(ntohl(s.data->what.position.reladdr.lba), 114513884Sache &mm, &ss, &ff); 114613884Sache *min = mm; 114713884Sache *sec = ss; 114813884Sache *frame = ff; 114913884Sache } 115013985Sache 115110099Sjkh return s.data->header.audio_status; 115210099Sjkh} 115310099Sjkh 1154227225Sedstatic const char * 1155201608Sdwmalonecdcontrol_prompt(void) 115610099Sjkh{ 115750039Smdodd return ("cdcontrol> "); 115850039Smdodd} 115950039Smdodd 1160227225Sedstatic char * 1161227225Sedinput(int *cmd) 116250039Smdodd{ 116350039Smdodd#define MAXLINE 80 116450039Smdodd static EditLine *el = NULL; 116550039Smdodd static History *hist = NULL; 116684261Sobrien HistEvent he; 116750039Smdodd static char buf[MAXLINE]; 116850039Smdodd int num = 0; 116950071Smdodd int len; 117050039Smdodd const char *bp = NULL; 117110099Sjkh char *p; 117210099Sjkh 117310099Sjkh do { 117450039Smdodd if (verbose) { 117550039Smdodd if (!el) { 117684261Sobrien el = el_init("cdcontrol", stdin, stdout, 117784261Sobrien stderr); 117850039Smdodd hist = history_init(); 1179151471Sstefanf history(hist, &he, H_SETSIZE, 100); 118050039Smdodd el_set(el, EL_HIST, history, hist); 118150039Smdodd el_set(el, EL_EDITOR, "emacs"); 118250039Smdodd el_set(el, EL_PROMPT, cdcontrol_prompt); 118350039Smdodd el_set(el, EL_SIGNAL, 1); 118450042Smdodd el_source(el, NULL); 118550039Smdodd } 118663070Smckay if ((bp = el_gets(el, &num)) == NULL || num == 0) { 118763070Smckay *cmd = CMD_QUIT; 118863070Smckay fprintf (stderr, "\r\n"); 118950039Smdodd return (0); 119063070Smckay } 119150039Smdodd 119250071Smdodd len = (num > MAXLINE) ? MAXLINE : num; 119350071Smdodd memcpy(buf, bp, len); 119450071Smdodd buf[len] = 0; 119584261Sobrien history(hist, &he, H_ENTER, bp); 119650039Smdodd#undef MAXLINE 119750039Smdodd 119850039Smdodd } else { 119950039Smdodd if (! fgets (buf, sizeof (buf), stdin)) { 120050039Smdodd *cmd = CMD_QUIT; 120150039Smdodd fprintf (stderr, "\r\n"); 120250039Smdodd return (0); 120350039Smdodd } 120410099Sjkh } 120510099Sjkh p = parse (buf, cmd); 120610099Sjkh } while (! p); 120710099Sjkh return (p); 120810099Sjkh} 120910099Sjkh 1210227225Sedstatic char * 1211227225Sedparse(char *buf, int *cmd) 121210099Sjkh{ 121310099Sjkh struct cmdtab *c; 121410099Sjkh char *p; 121587568Smikeh unsigned int len; 121610099Sjkh 121713985Sache for (p=buf; isspace (*p); p++) 121813985Sache continue; 121910099Sjkh 122013985Sache if (isdigit (*p) || (p[0] == '#' && isdigit (p[1]))) { 122113985Sache *cmd = CMD_PLAY; 122213985Sache return (p); 122377168Skris } else if (*p == '+') { 122477168Skris *cmd = CMD_NEXT; 122577168Skris return (p + 1); 122677168Skris } else if (*p == '-') { 122777168Skris *cmd = CMD_PREVIOUS; 122877168Skris return (p + 1); 122913985Sache } 123010099Sjkh 123113985Sache for (buf = p; *p && ! isspace (*p); p++) 123213985Sache continue; 123396214Smaxim 123413985Sache len = p - buf; 123510099Sjkh if (! len) 123610099Sjkh return (0); 123713985Sache 123887573Smikeh if (*p) { /* It must be a spacing character! */ 123913985Sache char *q; 124013985Sache 124113985Sache *p++ = 0; 124213985Sache for (q=p; *q && *q != '\n' && *q != '\r'; q++) 124313985Sache continue; 124413985Sache *q = 0; 124513985Sache } 124613985Sache 124710099Sjkh *cmd = -1; 124810099Sjkh for (c=cmdtab; c->name; ++c) { 124913985Sache /* Is it an exact match? */ 125013985Sache if (! strcasecmp (buf, c->name)) { 125113985Sache *cmd = c->command; 125213985Sache break; 125313985Sache } 125413985Sache 125513985Sache /* Try short hand forms then... */ 125613985Sache if (len >= c->min && ! strncasecmp (buf, c->name, len)) { 125713985Sache if (*cmd != -1 && *cmd != c->command) { 125829103Scharnier warnx("ambiguous command"); 125913985Sache return (0); 126013985Sache } 126110099Sjkh *cmd = c->command; 126213985Sache } 126313985Sache } 126410099Sjkh 126510099Sjkh if (*cmd == -1) { 126629103Scharnier warnx("invalid command, enter ``help'' for commands"); 126710099Sjkh return (0); 126810099Sjkh } 126913985Sache 127013985Sache while (isspace (*p)) 127113985Sache p++; 127210099Sjkh return p; 127310099Sjkh} 127410099Sjkh 1275227225Sedstatic int 1276227225Sedopen_cd(void) 127710099Sjkh{ 127854164Sjoe char devbuf[MAXPATHLEN]; 1279127714Sdwmalone const char *dev; 128010099Sjkh 128110099Sjkh if (fd > -1) 128210099Sjkh return (1); 128313985Sache 1284122855Seivind if (cdname) { 1285122855Seivind if (*cdname == '/') { 1286122855Seivind snprintf (devbuf, MAXPATHLEN, "%s", cdname); 1287122855Seivind } else { 1288122855Seivind snprintf (devbuf, MAXPATHLEN, "%s%s", _PATH_DEV, cdname); 1289122855Seivind } 1290127714Sdwmalone fd = open (dev = devbuf, O_RDONLY); 129161105Smsmith } else { 1292127714Sdwmalone fd = open(dev = "/dev/cdrom", O_RDONLY); 1293122855Seivind if (fd < 0 && errno == ENOENT) 1294127714Sdwmalone fd = open(dev = "/dev/cd0", O_RDONLY); 1295122855Seivind if (fd < 0 && errno == ENOENT) 1296127714Sdwmalone fd = open(dev = "/dev/acd0", O_RDONLY); 129754164Sjoe } 129813985Sache 129910099Sjkh if (fd < 0) { 130013985Sache if (errno == ENXIO) { 130113985Sache /* ENXIO has an overloaded meaning here. 130213985Sache * The original "Device not configured" should 130313985Sache * be interpreted as "No disc in drive %s". */ 1304127714Sdwmalone warnx("no disc in drive %s", dev); 130513985Sache return (0); 130610099Sjkh } 1307127714Sdwmalone err(1, "%s", dev); 130810099Sjkh } 130910099Sjkh return (1); 131010099Sjkh} 1311