diff options
author | Jason Downs <downsj@cvs.openbsd.org> | 1996-08-23 23:42:30 +0000 |
---|---|---|
committer | Jason Downs <downsj@cvs.openbsd.org> | 1996-08-23 23:42:30 +0000 |
commit | 769d6e17c184919bb5c31e939c8a0315a9060e02 (patch) | |
tree | b4e5857b5b593f730ab9feb41d5823f2092bd78d | |
parent | 8535feda839f1ae28d672fc7d72ade1f6b8cc06f (diff) |
A renamed and moved cdcontrol from FreeBSD.
-rw-r--r-- | usr.bin/cdio/Makefile | 7 | ||||
-rw-r--r-- | usr.bin/cdio/cdio.1 | 162 | ||||
-rw-r--r-- | usr.bin/cdio/cdio.c | 1055 |
3 files changed, 1224 insertions, 0 deletions
diff --git a/usr.bin/cdio/Makefile b/usr.bin/cdio/Makefile new file mode 100644 index 00000000000..d185d9c4c9c --- /dev/null +++ b/usr.bin/cdio/Makefile @@ -0,0 +1,7 @@ +# $OpenBSD: Makefile,v 1.1 1996/08/23 23:42:28 downsj Exp $ + +PROG= cdio +DPADD= ${LIBUTIL} +LDADD= -lutil + +.include <bsd.prog.mk> diff --git a/usr.bin/cdio/cdio.1 b/usr.bin/cdio/cdio.1 new file mode 100644 index 00000000000..76f79b0c3c1 --- /dev/null +++ b/usr.bin/cdio/cdio.1 @@ -0,0 +1,162 @@ +.\" $OpenBSD: cdio.1,v 1.1 1996/08/23 23:42:28 downsj Exp $ +.Dd July 3, 1995 +.Dt CDIO 1 +.Os OpenBSD +.Sh NAME +.Nm cdio +.Nd compact disc control utility +.Sh SYNOPSIS +.Nm cdio +.Op Fl s +.Op Fl v +.Op Fl f Ar discname +.Op Ar command args... +.Sh DESCRIPTION +.Nm cdio +is a program to control audio features of a CD drive. The device is a name such +as cd0 or mcd0. +.Pp +If the device not specified, the environment variable +.Ev DISC +will be used to find the cd device. +.Pp +If no command is given, then +.Nm cdio +enters an interactive mode, reading commands from the standard input. +.Pp +The following options are available: +.Bl -tag -width flag +.It Fl s +Silent mode - do not print table headers and human readable comments. +.It Fl v +Verbose mode - print as much information as possible. +.It Fl f Ar discname +Specifies a device name, such as /dev/rcd0d or mcd0. +Both absolute path and relative to /dev filename are possible. +The raw parition name is added if needed. +.El +.Pp +The available commands are listed below. Only as many +characters as are required to uniquely identify a command +need be specified. Word +.Nm play +can be ommitted. +.Bl -tag -width Cm + +.It Cm play Ar first_track Op Ar last_track +Play from track +.Nm first_track +to track +.Nm last_track. +The first track has number 1. +can be ommited in all cases. + +.It Cm play Ar start_m:start_s.start_f Op Ar end_m:end_s.end_f +Play from the absolute address +(MSF) defined by +.Nm start_m +in minutes, +.Nm start_s, +in seconds and +.Nm start_f +(frame number) to the absolute address defined by +.Nm end_m +in minutes, +.Nm end_s, +in seconds and +.Nm end_f +(frame number). Minutes are in the range 0-99. Seconds are in the range 0-59. +Frame numbers are in the range 0-74. + +.It Cm play Op Ar #start_block Op length +Play starting from the logical block +.Nm start_block +using +.Nm length +logical blocks. + +.It Cm pause +Stop playing. Do not stop the disc. + +.It Cm resume +Resume playing. Used after the +.Nm pause + command. + +.It Cm stop +Stop the disc. + +.It Cm eject +Eject the disc. + +.It Cm close +Inject the disc. + +.It Cm volume Ar left_channel Ar right_channel +Set the volume of left channel to +.Nm left_channel +and the volume of right channel to +.Nm right_channel. +Allowed values are in the range 0-255. + +.It Cm volume Ar mute +Turn the sound off. + +.It Cm volume Ar mono +Set the mono mode. + +.It Cm volume Ar stereo +Set the stereo mode. + +.It Cm volume Ar left +Play the left subtrack on both left and right channels. + +.It Cm volume Ar right +Play the right subtrack on both left and right channels. + +.It Cm info +Print the the table of contents. + +.It Cm status +Print the information about the disc: +the current playing status and position, +the current media catalog status, +the current values of the volume for left and right channels. + +.It Cm help +Print the list of available commands. + +.It Cm debug Ar on +Enable the debugging mode of the CD device driver. + +.It Cm debug Ar off +Disable the driver debugging mode. + +.It Cm reset +Perform the hardware reset of the device. + +.It Cm set Ar msf +Set minute-second-frame ioctl mode (default). + +.It Cm set Ar lba +Set LBA ioctl mode. + +.It Cm quit +Quit the program. + +.Sh FILES +.Bl -tag -width /dev/rmcd0c -compact +.It Pa /dev/rcd0d +.It Pa /dev/racd0d +.It Pa /dev/rmcd0d +.El +.Sh AUTHORS +Jean-Marc Zucconi, +Andrey A.\ Chernov, +Serge V.\ Vakulenko +.Sh HISTORY +The +.Nm cdio +command is based on +.Nm cdcontrol , +which first appeared in FreeBSD 2.1 diff --git a/usr.bin/cdio/cdio.c b/usr.bin/cdio/cdio.c new file mode 100644 index 00000000000..03ac4b19370 --- /dev/null +++ b/usr.bin/cdio/cdio.c @@ -0,0 +1,1055 @@ +/* $OpenBSD: cdio.c,v 1.1 1996/08/23 23:42:29 downsj Exp $ */ +/* + * Compact Disc Control Utility by Serge V. Vakulenko <vak@cronyx.ru>. + * Based on the non-X based CD player by Jean-Marc Zucconi and + * Andrey A. Chernov. + * + * Fixed and further modified on 5-Sep-1995 by Jukka Ukkonen <jau@funet.fi>. + * + * 11-Sep-1995: Jukka A. Ukkonen <jau@funet.fi> + * A couple of further fixes to my own earlier "fixes". + * + * 18-Sep-1995: Jukka A. Ukkonen <jau@funet.fi> + * Added an ability to specify addresses relative to the + * beginning of a track. This is in fact a variation of + * doing the simple play_msf() call. + * + * 11-Oct-1995: Serge V.Vakulenko <vak@cronyx.ru> + * New eject algorithm. + * Some code style reformatting. + * + * $FreeBSD: cdcontrol.c,v 1.13 1996/06/25 21:01:27 ache Exp $ + */ + +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <util.h> +#include <errno.h> +#include <sys/file.h> +#include <sys/cdio.h> +#include <sys/ioctl.h> + +#define VERSION "2.0" + +#define ASTS_INVALID 0x00 /* Audio status byte not valid */ +#define ASTS_PLAYING 0x11 /* Audio play operation in progress */ +#define ASTS_PAUSED 0x12 /* Audio play operation paused */ +#define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */ +#define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */ +#define ASTS_VOID 0x15 /* No current audio status to return */ + +#ifndef DEFAULT_CD_DRIVE +# define DEFAULT_CD_DRIVE "/dev/cd0c" +#endif + +#ifndef DEFAULT_CD_PARTITION +# define DEFAULT_CD_PARTITION "d" +#endif + +#define CMD_DEBUG 1 +#define CMD_EJECT 2 +#define CMD_HELP 3 +#define CMD_INFO 4 +#define CMD_PAUSE 5 +#define CMD_PLAY 6 +#define CMD_QUIT 7 +#define CMD_RESUME 8 +#define CMD_STOP 9 +#define CMD_VOLUME 10 +#define CMD_CLOSE 11 +#define CMD_RESET 12 +#define CMD_SET 13 +#define CMD_STATUS 14 + +struct cmdtab { + int command; + char *name; + unsigned min; + char *args; +} cmdtab[] = { +{ CMD_CLOSE, "close", 1, "" }, +{ CMD_DEBUG, "debug", 1, "on | off" }, +{ CMD_EJECT, "eject", 1, "" }, +{ CMD_HELP, "?", 1, 0 }, +{ CMD_HELP, "help", 1, "" }, +{ CMD_INFO, "info", 1, "" }, +{ CMD_PAUSE, "pause", 2, "" }, +{ CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" }, +{ CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" }, +{ CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" }, +{ CMD_PLAY, "play", 1, "[#block [len]]" }, +{ CMD_QUIT, "quit", 1, "" }, +{ CMD_RESET, "reset", 4, "" }, +{ CMD_RESUME, "resume", 1, "" }, +{ CMD_SET, "set", 2, "msf | lba" }, +{ CMD_STATUS, "status", 1, "" }, +{ CMD_STOP, "stop", 3, "" }, +{ CMD_VOLUME, "volume", 1, "<l> <r> | left | right | mute | mono | stereo" }, +{ 0, } +}; + +struct cd_toc_entry toc_buffer[100]; + +char *cdname; +int fd = -1; +int verbose = 1; +int msf = 1; + +extern char *__progname; + +int setvol __P((int, int)); +int read_toc_entrys __P((int)); +int play_msf __P((int, int, int, int, int, int)); +int play_track __P((int, int, int, int)); +int get_vol __P((int *, int *)); +int status __P((int *, int *, int *, int *)); +int open_cd __P((void)); +int play __P((char *arg)); +int info __P((char *arg)); +int pstatus __P((char *arg)); +char *input __P((int *)); +void prtrack __P((struct cd_toc_entry *e, int lastflag)); +void lba2msf __P((unsigned long lba, + u_char *m, u_char *s, u_char *f)); +unsigned int msf2lba __P((u_char m, u_char s, u_char f)); +int play_blocks __P((int blk, int len)); +int run __P((int cmd, char *arg)); +char *parse __P((char *buf, int *cmd)); + +void help () +{ + struct cmdtab *c; + char *s, n; + int i; + + for (c=cmdtab; c->name; ++c) { + if (! c->args) + continue; + printf("\t"); + for (i = c->min, s = c->name; *s; s++, i--) { + if (i > 0) + n = toupper(*s); + else + n = *s; + putchar(n); + } + if (*c->args) + printf (" %s", c->args); + printf ("\n"); + } + printf ("\n\tThe word \"play\" is not required for the play commands.\n"); + printf ("\tThe plain target address is taken as a synonym for play.\n"); +} + +void usage () +{ + printf ("Usage:\n\t%s [ -vs ] [ -f disc ] [ command args... ]\n", __progname); + printf ("Options:\n"); + printf ("\t-v - verbose mode\n"); + printf ("\t-s - silent mode\n"); + printf ("\t-f disc - a block device name such as /dev/cd0c\n"); + printf ("\tMUSIC_CD - shell variable with device name\n"); + printf ("Commands:\n"); + help (); + exit (1); +} + +int main (argc, argv) + int argc; + char **argv; +{ + int cmd; + char *arg; + + cdname = getenv ("DISC"); + if (! cdname) + cdname = getenv ("CDROM"); + + for (;;) { + switch (getopt (argc, argv, "svhf:")) { + case EOF: + break; + case 's': + verbose = 0; + continue; + case 'v': + verbose = 2; + continue; + case 'f': + cdname = optarg; + continue; + case 'h': + default: + usage (); + } + break; + } + argc -= optind; + argv += optind; + + if (argc > 0 && ! strcasecmp (*argv, "help")) + usage (); + + if (! cdname) { + cdname = DEFAULT_CD_DRIVE; + fprintf (stderr, + "No CD device name specified. Defaulting to %s.\n", cdname); + } + + if (argc > 0) { + char buf[80], *p; + int len; + + for (p=buf; argc-->0; ++argv) { + len = strlen (*argv); + + if (p + len >= buf + sizeof (buf) - 1) + usage (); + + if (p > buf) + *p++ = ' '; + + strcpy (p, *argv); + p += len; + } + *p = 0; + arg = parse (buf, &cmd); + return (run (cmd, arg)); + } + + if (verbose == 1) + verbose = isatty (0); + + if (verbose) { + printf ("Compact Disc Control utility, version %s\n", VERSION); + printf ("Type `?' for command list\n\n"); + } + + for (;;) { + arg = input (&cmd); + if (run (cmd, arg) < 0) { + if (verbose) + perror (__progname); + close (fd); + fd = -1; + } + fflush (stdout); + } +} + +int run (cmd, arg) + int cmd; + char *arg; +{ + int l, r, rc; + + switch (cmd) { + + case CMD_QUIT: + exit (0); + + case CMD_INFO: + if (fd < 0 && ! open_cd ()) + return (0); + + return info (arg); + + case CMD_STATUS: + if (fd < 0 && ! open_cd ()) + return (0); + + return pstatus (arg); + + case CMD_PAUSE: + if (fd < 0 && ! open_cd ()) + return (0); + + return ioctl (fd, CDIOCPAUSE); + + case CMD_RESUME: + if (fd < 0 && ! open_cd ()) + return (0); + + return ioctl (fd, CDIOCRESUME); + + case CMD_STOP: + if (fd < 0 && ! open_cd ()) + return (0); + + rc = ioctl (fd, CDIOCSTOP); + + (void) ioctl (fd, CDIOCALLOW); + + return (rc); + + case CMD_RESET: + if (fd < 0 && ! open_cd ()) + return (0); + + rc = ioctl (fd, CDIOCRESET); + if (rc < 0) + return rc; + close(fd); + fd = -1; + return (0); + + case CMD_DEBUG: + if (fd < 0 && ! open_cd ()) + return (0); + + if (! strcasecmp (arg, "on")) + return ioctl (fd, CDIOCSETDEBUG); + + if (! strcasecmp (arg, "off")) + return ioctl (fd, CDIOCCLRDEBUG); + + printf ("%s: Invalid command arguments\n", __progname); + + return (0); + + case CMD_EJECT: + if (fd < 0 && ! open_cd ()) + return (0); + + (void) ioctl (fd, CDIOCALLOW); + rc = ioctl (fd, CDIOCEJECT); + if (rc < 0) + return (rc); +#if defined(__OpenBSD__) + close(fd); + fd = -1; +#endif + return (0); + + case CMD_CLOSE: +#if defined(CDIOCCLOSE) + if (fd < 0 && ! open_cd ()) + return (0); + + (void) ioctl (fd, CDIOCALLOW); + rc = ioctl (fd, CDIOCCLOSE); + if (rc < 0) + return (rc); + close(fd); + fd = -1; + return (0); +#else + printf ("%s: Command not yet supported\n", __progname); + return (0); +#endif + + case CMD_PLAY: + if (fd < 0 && ! open_cd ()) + return (0); + + while (isspace (*arg)) + arg++; + + return play (arg); + + case CMD_SET: + if (! strcasecmp (arg, "msf")) + msf = 1; + else if (! strcasecmp (arg, "lba")) + msf = 0; + else + printf ("%s: Invalid command arguments\n", __progname); + return (0); + + case CMD_VOLUME: + if (fd < 0 && !open_cd ()) + return (0); + + if (! strncasecmp (arg, "left", strlen(arg))) + return ioctl (fd, CDIOCSETLEFT); + + if (! strncasecmp (arg, "right", strlen(arg))) + return ioctl (fd, CDIOCSETRIGHT); + + if (! strncasecmp (arg, "mono", strlen(arg))) + return ioctl (fd, CDIOCSETMONO); + +#if defined(CDIOCSETSTERIO) + if (! strncasecmp (arg, "stereo", strlen(arg))) + return ioctl (fd, CDIOCSETSTERIO); +#else + printf ("%s: Command argument not yet supported\n", + __progname); + return (0); +#endif + + if (! strncasecmp (arg, "mute", strlen(arg))) + return ioctl (fd, CDIOCSETMUTE); + + if (2 != sscanf (arg, "%d %d", &l, &r)) { + printf ("%s: Invalid command arguments\n", __progname); + return (0); + } + + return setvol (l, r); + + default: + case CMD_HELP: + help (); + return (0); + + } +} + +int play (arg) + char *arg; +{ + struct ioc_toc_header h; + int rc, n, start, end = 0, istart = 1, iend = 1; + + rc = ioctl (fd, CDIOREADTOCHEADER, &h); + + if (rc < 0) + return (rc); + + n = h.ending_track - h.starting_track + 1; + rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); + + if (rc < 0) + return (rc); + + if (! arg || ! *arg) { + /* Play the whole disc */ + if (msf) + return play_blocks (0, msf2lba (toc_buffer[n].addr.msf.minute, + toc_buffer[n].addr.msf.second, + toc_buffer[n].addr.msf.frame)); + else + return play_blocks (0, ntohl(toc_buffer[n].addr.lba)); + } + + if (strchr (arg, '#')) { + /* Play block #blk [ len ] */ + int blk, len = 0; + + if (2 != sscanf (arg, "#%d%d", &blk, &len) && + 1 != sscanf (arg, "#%d", &blk)) + goto Clean_up; + + if (len == 0) { + if (msf) + len = msf2lba (toc_buffer[n].addr.msf.minute, + toc_buffer[n].addr.msf.second, + toc_buffer[n].addr.msf.frame) - blk; + else + len = ntohl(toc_buffer[n].addr.lba) - blk; + } + return play_blocks (blk, len); + } + + if (strchr (arg, ':')) { + /* + * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ] + * + * Will now also undestand timed addresses relative + * to the beginning of a track in the form... + * + * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]] + */ + unsigned tr1, tr2; + unsigned m1, m2, s1, s2, f1, f2; + unsigned char tm, ts, tf; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (8 == sscanf (arg, "%d %d:%d.%d %d %d:%d.%d", + &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (7 == sscanf (arg, "%d %d:%d %d %d:%d.%d", + &tr1, &m1, &s1, &tr2, &m2, &s2, &f2)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (7 == sscanf (arg, "%d %d:%d.%d %d %d:%d", + &tr1, &m1, &s1, &f1, &tr2, &m2, &s2)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (7 == sscanf (arg, "%d %d:%d.%d %d:%d.%d", + &tr1, &m1, &s1, &f1, &m2, &s2, &f2)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (6 == sscanf (arg, "%d %d:%d.%d %d:%d", + &tr1, &m1, &s1, &f1, &m2, &s2)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (6 == sscanf (arg, "%d %d:%d %d:%d.%d", + &tr1, &m1, &s1, &m2, &s2, &f2)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (6 == sscanf (arg, "%d %d:%d.%d %d %d", + &tr1, &m1, &s1, &f1, &tr2, &m2)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (5 == sscanf (arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (5 == sscanf (arg, "%d %d:%d %d %d", + &tr1, &m1, &s1, &tr2, &m2)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (5 == sscanf (arg, "%d %d:%d.%d %d", + &tr1, &m1, &s1, &f1, &tr2)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (4 == sscanf (arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (4 == sscanf (arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + if (3 == sscanf (arg, "%d %d:%d", &tr1, &m1, &s1)) + goto Play_Relative_Addresses; + + tr2 = m2 = s2 = f2 = f1 = 0; + goto Try_Absolute_Timed_Addresses; + +Play_Relative_Addresses: + if (! tr1) + tr1 = 1; + else if (tr1 > n) + tr1 = n; + + if (msf) { + tm = toc_buffer[tr1].addr.msf.minute; + ts = toc_buffer[tr1].addr.msf.second; + tf = toc_buffer[tr1].addr.msf.frame; + } else + lba2msf(ntohl(toc_buffer[tr1].addr.lba), + &tm, &ts, &tf); + if ((m1 > tm) + || ((m1 == tm) + && ((s1 > ts) + || ((s1 == ts) + && (f1 > tf))))) { + printf ("Track %d is not that long.\n", tr1); + return (0); + } + + tr1--; + + f1 += tf; + if (f1 >= 75) { + s1 += f1 / 75; + f1 %= 75; + } + + s1 += ts; + if (s1 >= 60) { + m1 += s1 / 60; + s1 %= 60; + } + + m1 += tm; + + if (! tr2) { + if (m2 || s2 || f2) { + tr2 = tr1; + f2 += f1; + if (f2 >= 75) { + s2 += f2 / 75; + f2 %= 75; + } + + s2 += s1; + if (s2 > 60) { + m2 += s2 / 60; + s2 %= 60; + } + + m2 += m1; + } else { + tr2 = n; + if (msf) { + m2 = toc_buffer[n].addr.msf.minute; + s2 = toc_buffer[n].addr.msf.second; + f2 = toc_buffer[n].addr.msf.frame; + } else { + lba2msf(ntohl(toc_buffer[n].addr.lba), + &tm, &ts, &tf); + m2 = tm; + s2 = ts; + f2 = tf; + } + } + } else if (tr2 > n) { + tr2 = n; + m2 = s2 = f2 = 0; + } else { + if (m2 || s2 || f2) + tr2--; + if (msf) { + tm = toc_buffer[tr2].addr.msf.minute; + ts = toc_buffer[tr2].addr.msf.second; + tf = toc_buffer[tr2].addr.msf.frame; + } else + lba2msf(ntohl(toc_buffer[tr2].addr.lba), + &tm, &ts, &tf); + f2 += tf; + if (f2 >= 75) { + s2 += f2 / 75; + f2 %= 75; + } + + s2 += ts; + if (s2 > 60) { + m2 += s2 / 60; + s2 %= 60; + } + + m2 += tm; + } + + if (msf) { + tm = toc_buffer[n].addr.msf.minute; + ts = toc_buffer[n].addr.msf.second; + tf = toc_buffer[n].addr.msf.frame; + } else + lba2msf(ntohl(toc_buffer[n].addr.lba), + &tm, &ts, &tf); + if ((tr2 < n) + && ((m2 > tm) + || ((m2 == tm) + && ((s2 > ts) + || ((s2 == ts) + && (f2 > tf)))))) { + printf ("The playing time of the disc is not that long.\n"); + return (0); + } + return (play_msf (m1, s1, f1, m2, s2, f2)); + +Try_Absolute_Timed_Addresses: + if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d", + &m1, &s1, &f1, &m2, &s2, &f2) && + 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) && + 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) && + 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) && + 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) && + 2 != sscanf (arg, "%d:%d", &m1, &s1)) + goto Clean_up; + + if (m2 == 0) { + if (msf) { + m2 = toc_buffer[n].addr.msf.minute; + s2 = toc_buffer[n].addr.msf.second; + f2 = toc_buffer[n].addr.msf.frame; + } else { + lba2msf(ntohl(toc_buffer[n].addr.lba), + &tm, &ts, &tf); + m2 = tm; + s2 = ts; + f2 = tf; + } + } + return play_msf (m1, s1, f1, m2, s2, f2); + } + + /* + * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ] + */ + if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) && + 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) && + 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) && + 2 != sscanf (arg, "%d.%d", &start, &istart) && + 2 != sscanf (arg, "%d%d", &start, &end) && + 1 != sscanf (arg, "%d", &start)) + goto Clean_up; + + if (end == 0) + end = n; + return (play_track (start, istart, end, iend)); + +Clean_up: + printf ("%s: Invalid command arguments\n", __progname); + return (0); +} + +char *strstatus (sts) + int sts; +{ + switch (sts) { + case ASTS_INVALID: return ("invalid"); + case ASTS_PLAYING: return ("playing"); + case ASTS_PAUSED: return ("paused"); + case ASTS_COMPLETED: return ("completed"); + case ASTS_ERROR: return ("error"); + case ASTS_VOID: return ("void"); + default: return ("??"); + } +} + +int pstatus (arg) + char *arg; +{ + struct ioc_vol v; + struct ioc_read_subchannel ss; + struct cd_sub_channel_info data; + int rc, trk, m, s, f; + + rc = status (&trk, &m, &s, &f); + if (rc >= 0) + if (verbose) + printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n", + rc, strstatus (rc), trk, m, s, f); + else + printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f); + else + printf ("No current status info available\n"); + + bzero (&ss, sizeof (ss)); + ss.data = &data; + ss.data_len = sizeof (data); + ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; + ss.data_format = CD_MEDIA_CATALOG; + rc = ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &ss); + if (rc >= 0) { + printf("Media catalog is %sactive", + ss.data->what.media_catalog.mc_valid ? "": "in"); + if (ss.data->what.media_catalog.mc_valid && + ss.data->what.media_catalog.mc_number[0]) + printf(", number \"%.15s\"", + ss.data->what.media_catalog.mc_number); + putchar('\n'); + } else + printf("No media catalog info available\n"); + + rc = ioctl (fd, CDIOCGETVOL, &v); + if (rc >= 0) + if (verbose) + printf ("Left volume = %d, right volume = %d\n", + v.vol[0], v.vol[1]); + else + printf ("%d %d\n", v.vol[0], v.vol[1]); + else + printf ("No volume level info available\n"); + return(0); +} + +int info (arg) + char *arg; +{ + struct ioc_toc_header h; + int rc, i, n; + + rc = ioctl (fd, CDIOREADTOCHEADER, &h); + if (rc >= 0) { + if (verbose) + printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n", + h.starting_track, h.ending_track, h.len); + else + printf ("%d %d %d\n", h.starting_track, + h.ending_track, h.len); + } else { + perror ("getting toc header"); + return (rc); + } + + n = h.ending_track - h.starting_track + 1; + rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry)); + if (rc < 0) + return (rc); + + if (verbose) { + printf ("track start duration block length type\n"); + printf ("-------------------------------------------------\n"); + } + + for (i = 0; i < n; i++) { + printf ("%5d ", toc_buffer[i].track); + prtrack (toc_buffer + i, 0); + } + printf ("%5d ", toc_buffer[n].track); + prtrack (toc_buffer + n, 1); + return (0); +} + +void lba2msf (lba, m, s, f) + unsigned long lba; + u_char *m; + u_char *s; + u_char *f; +{ + lba += 150; /* block start offset */ + lba &= 0xffffff; /* negative lbas use only 24 bits */ + *m = lba / (60 * 75); + lba %= (60 * 75); + *s = lba / 75; + *f = lba % 75; +} + +unsigned int msf2lba (m, s, f) + u_char m; + u_char s; + u_char f; +{ + return (((m * 60) + s) * 75 + f) - 150; +} + +void prtrack (e, lastflag) + struct cd_toc_entry *e; + int lastflag; +{ + int block, next, len; + u_char m, s, f; + + if (msf) { + /* Print track start */ + printf ("%2d:%02d.%02d ", e->addr.msf.minute, + e->addr.msf.second, e->addr.msf.frame); + + block = msf2lba (e->addr.msf.minute, e->addr.msf.second, + e->addr.msf.frame); + } else { + block = ntohl(e->addr.lba); + lba2msf(block, &m, &s, &f); + /* Print track start */ + printf ("%2d:%02d.%02d ", m, s, f); + } + if (lastflag) { + /* Last track -- print block */ + printf (" - %6d - -\n", block); + return; + } + + if (msf) + next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second, + e[1].addr.msf.frame); + else + next = ntohl(e[1].addr.lba); + len = next - block; + lba2msf (len, &m, &s, &f); + + /* Print duration, block, length, type */ + printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len, + (e->control & 4) ? "data" : "audio"); +} + +int play_track (tstart, istart, tend, iend) + int tstart; + int istart; + int tend; + int iend; +{ + struct ioc_play_track t; + + t.start_track = tstart; + t.start_index = istart; + t.end_track = tend; + t.end_index = iend; + + return ioctl (fd, CDIOCPLAYTRACKS, &t); +} + +int play_blocks (blk, len) + int blk; + int len; +{ + struct ioc_play_blocks t; + + t.blk = blk; + t.len = len; + + return ioctl (fd, CDIOCPLAYBLOCKS, &t); +} + +int setvol (left, right) + int left; + int right; +{ + struct ioc_vol v; + + v.vol[0] = left; + v.vol[1] = right; + v.vol[2] = 0; + v.vol[3] = 0; + + return ioctl (fd, CDIOCSETVOL, &v); +} + +int read_toc_entrys (len) + int len; +{ + struct ioc_read_toc_entry t; + + t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; + t.starting_track = 0; + t.data_len = len; + t.data = toc_buffer; + + return (ioctl (fd, CDIOREADTOCENTRYS, (char *) &t)); +} + +int play_msf (start_m, start_s, start_f, end_m, end_s, end_f) + int start_m; + int start_s; + int start_f; + int end_m; + int end_s; + int end_f; +{ + struct ioc_play_msf a; + + a.start_m = start_m; + a.start_s = start_s; + a.start_f = start_f; + a.end_m = end_m; + a.end_s = end_s; + a.end_f = end_f; + + return ioctl (fd, CDIOCPLAYMSF, (char *) &a); +} + +int status (trk, min, sec, frame) + int *trk; + int *min; + int *sec; + int *frame; +{ + struct ioc_read_subchannel s; + struct cd_sub_channel_info data; + u_char mm, ss, ff; + + bzero (&s, sizeof (s)); + s.data = &data; + s.data_len = sizeof (data); + s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT; + s.data_format = CD_CURRENT_POSITION; + + if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0) + return -1; + + *trk = s.data->what.position.track_number; + if (msf) { + *min = s.data->what.position.reladdr.msf.minute; + *sec = s.data->what.position.reladdr.msf.second; + *frame = s.data->what.position.reladdr.msf.frame; + } else { + lba2msf(ntohl(s.data->what.position.reladdr.lba), + &mm, &ss, &ff); + *min = mm; + *sec = ss; + *frame = ff; + } + + return s.data->header.audio_status; +} + +char *input (cmd) + int *cmd; +{ + static char buf[80]; + char *p; + + do { + if (verbose) + fprintf (stderr, "%s> ", __progname); + if (! fgets (buf, sizeof (buf), stdin)) { + *cmd = CMD_QUIT; + fprintf (stderr, "\r\n"); + return (0); + } + p = parse (buf, cmd); + } while (! p); + return (p); +} + +char *parse (buf, cmd) + char *buf; + int *cmd; +{ + struct cmdtab *c; + char *p; + int len; + + for (p=buf; isspace (*p); p++) + continue; + + if (isdigit (*p) || (p[0] == '#' && isdigit (p[1]))) { + *cmd = CMD_PLAY; + return (p); + } + + for (buf = p; *p && ! isspace (*p); p++) + continue; + + len = p - buf; + if (! len) + return (0); + + if (*p) { /* It must be a spacing character! */ + char *q; + + *p++ = 0; + for (q=p; *q && *q != '\n' && *q != '\r'; q++) + continue; + *q = 0; + } + + *cmd = -1; + for (c=cmdtab; c->name; ++c) { + /* Is it an exact match? */ + if (! strcasecmp (buf, c->name)) { + *cmd = c->command; + break; + } + + /* Try short hand forms then... */ + if (len >= c->min && ! strncasecmp (buf, c->name, len)) { + if (*cmd != -1 && *cmd != c->command) { + fprintf (stderr, "Ambiguous command\n"); + return (0); + } + *cmd = c->command; + } + } + + if (*cmd == -1) { + fprintf (stderr, "%s: Invalid command, enter ``help'' for commands.\n", + __progname); + return (0); + } + + while (isspace (*p)) + p++; + return p; +} + +int open_cd () +{ + char *dev; + + if (fd > -1) + return (1); + + fd = opendev(cdname, O_RDONLY, OPENDEV_PART, &dev); + if (fd < 0) { + if ((errno == ENXIO) || (errno == EIO)) { + /* ENXIO has an overloaded meaning here. + * The original "Device not configured" should + * be interpreted as "No disc in drive %s". */ + fprintf (stderr, "%s: No disc in drive %s.\n", __progname, dev); + return (0); + } + perror (dev); + exit (1); + } + return (1); +} |