Annotation of src/usr.bin/cdio/cdio.c, Revision 1.5
1.5 ! angelos 1: /* $OpenBSD: cdio.c,v 1.4 1997/02/23 02:29:02 niklas Exp $ */
1.1 downsj 2: /*
3: * Compact Disc Control Utility by Serge V. Vakulenko <vak@cronyx.ru>.
4: * Based on the non-X based CD player by Jean-Marc Zucconi and
5: * Andrey A. Chernov.
6: *
7: * Fixed and further modified on 5-Sep-1995 by Jukka Ukkonen <jau@funet.fi>.
8: *
9: * 11-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
10: * A couple of further fixes to my own earlier "fixes".
11: *
12: * 18-Sep-1995: Jukka A. Ukkonen <jau@funet.fi>
13: * Added an ability to specify addresses relative to the
14: * beginning of a track. This is in fact a variation of
15: * doing the simple play_msf() call.
16: *
17: * 11-Oct-1995: Serge V.Vakulenko <vak@cronyx.ru>
18: * New eject algorithm.
19: * Some code style reformatting.
20: *
21: * $FreeBSD: cdcontrol.c,v 1.13 1996/06/25 21:01:27 ache Exp $
22: */
23:
24: #include <ctype.h>
25: #include <stdio.h>
26: #include <stdlib.h>
27: #include <string.h>
28: #include <unistd.h>
29: #include <util.h>
30: #include <errno.h>
31: #include <sys/file.h>
32: #include <sys/cdio.h>
33: #include <sys/ioctl.h>
34:
35: #define VERSION "2.0"
36:
37: #define ASTS_INVALID 0x00 /* Audio status byte not valid */
38: #define ASTS_PLAYING 0x11 /* Audio play operation in progress */
39: #define ASTS_PAUSED 0x12 /* Audio play operation paused */
40: #define ASTS_COMPLETED 0x13 /* Audio play operation successfully completed */
41: #define ASTS_ERROR 0x14 /* Audio play operation stopped due to error */
42: #define ASTS_VOID 0x15 /* No current audio status to return */
43:
44: #ifndef DEFAULT_CD_DRIVE
1.3 deraadt 45: # define DEFAULT_CD_DRIVE "cd0"
1.1 downsj 46: #endif
47:
48: #define CMD_DEBUG 1
49: #define CMD_EJECT 2
50: #define CMD_HELP 3
51: #define CMD_INFO 4
52: #define CMD_PAUSE 5
53: #define CMD_PLAY 6
54: #define CMD_QUIT 7
55: #define CMD_RESUME 8
56: #define CMD_STOP 9
57: #define CMD_VOLUME 10
58: #define CMD_CLOSE 11
59: #define CMD_RESET 12
60: #define CMD_SET 13
61: #define CMD_STATUS 14
1.5 ! angelos 62: #define CMD_NEXT 15
! 63: #define CMD_PREV 16
1.1 downsj 64:
65: struct cmdtab {
66: int command;
67: char *name;
68: unsigned min;
69: char *args;
70: } cmdtab[] = {
71: { CMD_CLOSE, "close", 1, "" },
72: { CMD_DEBUG, "debug", 1, "on | off" },
73: { CMD_EJECT, "eject", 1, "" },
74: { CMD_HELP, "?", 1, 0 },
75: { CMD_HELP, "help", 1, "" },
76: { CMD_INFO, "info", 1, "" },
1.5 ! angelos 77: { CMD_NEXT, "next", 1, "" },
1.1 downsj 78: { CMD_PAUSE, "pause", 2, "" },
79: { CMD_PLAY, "play", 1, "min1:sec1[.fram1] [min2:sec2[.fram2]]" },
80: { CMD_PLAY, "play", 1, "track1[.index1] [track2[.index2]]" },
81: { CMD_PLAY, "play", 1, "tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]" },
82: { CMD_PLAY, "play", 1, "[#block [len]]" },
1.5 ! angelos 83: { CMD_PREV, "previous", 2, "" },
1.1 downsj 84: { CMD_QUIT, "quit", 1, "" },
85: { CMD_RESET, "reset", 4, "" },
86: { CMD_RESUME, "resume", 1, "" },
87: { CMD_SET, "set", 2, "msf | lba" },
88: { CMD_STATUS, "status", 1, "" },
89: { CMD_STOP, "stop", 3, "" },
90: { CMD_VOLUME, "volume", 1, "<l> <r> | left | right | mute | mono | stereo" },
91: { 0, }
92: };
93:
94: struct cd_toc_entry toc_buffer[100];
95:
96: char *cdname;
97: int fd = -1;
98: int verbose = 1;
99: int msf = 1;
100:
101: extern char *__progname;
102:
103: int setvol __P((int, int));
104: int read_toc_entrys __P((int));
105: int play_msf __P((int, int, int, int, int, int));
106: int play_track __P((int, int, int, int));
107: int get_vol __P((int *, int *));
108: int status __P((int *, int *, int *, int *));
109: int open_cd __P((void));
110: int play __P((char *arg));
111: int info __P((char *arg));
112: int pstatus __P((char *arg));
1.5 ! angelos 113: int play_next __P((char *arg));
! 114: int play_prev __P((char *arg));
1.1 downsj 115: char *input __P((int *));
116: void prtrack __P((struct cd_toc_entry *e, int lastflag));
117: void lba2msf __P((unsigned long lba,
118: u_char *m, u_char *s, u_char *f));
119: unsigned int msf2lba __P((u_char m, u_char s, u_char f));
120: int play_blocks __P((int blk, int len));
121: int run __P((int cmd, char *arg));
122: char *parse __P((char *buf, int *cmd));
123:
124: void help ()
125: {
126: struct cmdtab *c;
127: char *s, n;
128: int i;
129:
130: for (c=cmdtab; c->name; ++c) {
131: if (! c->args)
132: continue;
133: printf("\t");
134: for (i = c->min, s = c->name; *s; s++, i--) {
135: if (i > 0)
136: n = toupper(*s);
137: else
138: n = *s;
139: putchar(n);
140: }
141: if (*c->args)
142: printf (" %s", c->args);
143: printf ("\n");
144: }
145: printf ("\n\tThe word \"play\" is not required for the play commands.\n");
146: printf ("\tThe plain target address is taken as a synonym for play.\n");
147: }
148:
149: void usage ()
150: {
151: printf ("Usage:\n\t%s [ -vs ] [ -f disc ] [ command args... ]\n", __progname);
152: printf ("Options:\n");
153: printf ("\t-v - verbose mode\n");
154: printf ("\t-s - silent mode\n");
155: printf ("\t-f disc - a block device name such as /dev/cd0c\n");
156: printf ("\tMUSIC_CD - shell variable with device name\n");
157: printf ("Commands:\n");
158: help ();
159: exit (1);
160: }
161:
162: int main (argc, argv)
163: int argc;
164: char **argv;
165: {
166: int cmd;
167: char *arg;
168:
169: cdname = getenv ("DISC");
170: if (! cdname)
171: cdname = getenv ("CDROM");
172:
173: for (;;) {
174: switch (getopt (argc, argv, "svhf:")) {
175: case EOF:
176: break;
177: case 's':
178: verbose = 0;
179: continue;
180: case 'v':
181: verbose = 2;
182: continue;
183: case 'f':
184: cdname = optarg;
185: continue;
186: case 'h':
187: default:
188: usage ();
189: }
190: break;
191: }
192: argc -= optind;
193: argv += optind;
194:
195: if (argc > 0 && ! strcasecmp (*argv, "help"))
196: usage ();
197:
198: if (! cdname) {
199: cdname = DEFAULT_CD_DRIVE;
200: fprintf (stderr,
201: "No CD device name specified. Defaulting to %s.\n", cdname);
202: }
203:
204: if (argc > 0) {
205: char buf[80], *p;
206: int len;
207:
208: for (p=buf; argc-->0; ++argv) {
209: len = strlen (*argv);
210:
211: if (p + len >= buf + sizeof (buf) - 1)
212: usage ();
213:
214: if (p > buf)
215: *p++ = ' ';
216:
217: strcpy (p, *argv);
218: p += len;
219: }
220: *p = 0;
221: arg = parse (buf, &cmd);
222: return (run (cmd, arg));
223: }
224:
225: if (verbose == 1)
226: verbose = isatty (0);
227:
228: if (verbose) {
229: printf ("Compact Disc Control utility, version %s\n", VERSION);
230: printf ("Type `?' for command list\n\n");
231: }
232:
233: for (;;) {
234: arg = input (&cmd);
235: if (run (cmd, arg) < 0) {
236: if (verbose)
237: perror (__progname);
238: close (fd);
239: fd = -1;
240: }
241: fflush (stdout);
242: }
243: }
244:
245: int run (cmd, arg)
246: int cmd;
247: char *arg;
248: {
249: int l, r, rc;
250:
251: switch (cmd) {
252:
253: case CMD_QUIT:
254: exit (0);
255:
256: case CMD_INFO:
257: if (fd < 0 && ! open_cd ())
258: return (0);
259:
260: return info (arg);
261:
262: case CMD_STATUS:
263: if (fd < 0 && ! open_cd ())
264: return (0);
265:
266: return pstatus (arg);
267:
268: case CMD_PAUSE:
269: if (fd < 0 && ! open_cd ())
270: return (0);
271:
272: return ioctl (fd, CDIOCPAUSE);
273:
274: case CMD_RESUME:
275: if (fd < 0 && ! open_cd ())
276: return (0);
277:
278: return ioctl (fd, CDIOCRESUME);
279:
280: case CMD_STOP:
281: if (fd < 0 && ! open_cd ())
282: return (0);
283:
284: rc = ioctl (fd, CDIOCSTOP);
285:
286: (void) ioctl (fd, CDIOCALLOW);
287:
288: return (rc);
289:
290: case CMD_RESET:
291: if (fd < 0 && ! open_cd ())
292: return (0);
293:
294: rc = ioctl (fd, CDIOCRESET);
295: if (rc < 0)
296: return rc;
297: close(fd);
298: fd = -1;
299: return (0);
300:
301: case CMD_DEBUG:
302: if (fd < 0 && ! open_cd ())
303: return (0);
304:
305: if (! strcasecmp (arg, "on"))
306: return ioctl (fd, CDIOCSETDEBUG);
307:
308: if (! strcasecmp (arg, "off"))
309: return ioctl (fd, CDIOCCLRDEBUG);
310:
311: printf ("%s: Invalid command arguments\n", __progname);
312:
313: return (0);
314:
315: case CMD_EJECT:
316: if (fd < 0 && ! open_cd ())
317: return (0);
318:
319: (void) ioctl (fd, CDIOCALLOW);
320: rc = ioctl (fd, CDIOCEJECT);
321: if (rc < 0)
322: return (rc);
323: #if defined(__OpenBSD__)
324: close(fd);
325: fd = -1;
326: #endif
327: return (0);
328:
329: case CMD_CLOSE:
330: #if defined(CDIOCCLOSE)
331: if (fd < 0 && ! open_cd ())
332: return (0);
333:
334: (void) ioctl (fd, CDIOCALLOW);
335: rc = ioctl (fd, CDIOCCLOSE);
336: if (rc < 0)
337: return (rc);
338: close(fd);
339: fd = -1;
340: return (0);
341: #else
342: printf ("%s: Command not yet supported\n", __progname);
343: return (0);
344: #endif
345:
346: case CMD_PLAY:
347: if (fd < 0 && ! open_cd ())
348: return (0);
349:
350: while (isspace (*arg))
351: arg++;
352:
353: return play (arg);
354:
355: case CMD_SET:
356: if (! strcasecmp (arg, "msf"))
357: msf = 1;
358: else if (! strcasecmp (arg, "lba"))
359: msf = 0;
360: else
361: printf ("%s: Invalid command arguments\n", __progname);
362: return (0);
363:
364: case CMD_VOLUME:
365: if (fd < 0 && !open_cd ())
366: return (0);
367:
368: if (! strncasecmp (arg, "left", strlen(arg)))
369: return ioctl (fd, CDIOCSETLEFT);
370:
371: if (! strncasecmp (arg, "right", strlen(arg)))
372: return ioctl (fd, CDIOCSETRIGHT);
373:
374: if (! strncasecmp (arg, "mono", strlen(arg)))
375: return ioctl (fd, CDIOCSETMONO);
376:
377: #if defined(CDIOCSETSTERIO)
378: if (! strncasecmp (arg, "stereo", strlen(arg)))
379: return ioctl (fd, CDIOCSETSTERIO);
380: #else
381: printf ("%s: Command argument not yet supported\n",
382: __progname);
383: return (0);
384: #endif
385:
386: if (! strncasecmp (arg, "mute", strlen(arg)))
387: return ioctl (fd, CDIOCSETMUTE);
388:
389: if (2 != sscanf (arg, "%d %d", &l, &r)) {
390: printf ("%s: Invalid command arguments\n", __progname);
391: return (0);
392: }
393:
394: return setvol (l, r);
395:
1.5 ! angelos 396: case CMD_NEXT:
! 397: if (fd < 0 && ! open_cd ())
! 398: return (0);
! 399:
! 400: return play_next (arg);
! 401:
! 402: case CMD_PREV:
! 403: if (fd < 0 && ! open_cd ())
! 404: return (0);
! 405:
! 406: return play_prev (arg);
! 407:
1.1 downsj 408: default:
409: case CMD_HELP:
410: help ();
411: return (0);
412:
413: }
414: }
415:
416: int play (arg)
417: char *arg;
418: {
419: struct ioc_toc_header h;
420: int rc, n, start, end = 0, istart = 1, iend = 1;
421:
422: rc = ioctl (fd, CDIOREADTOCHEADER, &h);
423:
424: if (rc < 0)
425: return (rc);
426:
427: n = h.ending_track - h.starting_track + 1;
428: rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry));
429:
430: if (rc < 0)
431: return (rc);
432:
433: if (! arg || ! *arg) {
434: /* Play the whole disc */
435: if (msf)
1.4 niklas 436: return
437: play_blocks (msf2lba (toc_buffer[0].addr.msf.minute,
438: toc_buffer[0].addr.msf.second,
439: toc_buffer[0].addr.msf.frame),
440: msf2lba (toc_buffer[n].addr.msf.minute,
441: toc_buffer[n].addr.msf.second,
442: toc_buffer[n].addr.msf.frame));
1.1 downsj 443: else
1.4 niklas 444: return play_blocks (ntohl (toc_buffer[0].addr.lba),
445: ntohl (toc_buffer[n].addr.lba));
1.1 downsj 446: }
447:
448: if (strchr (arg, '#')) {
449: /* Play block #blk [ len ] */
450: int blk, len = 0;
451:
452: if (2 != sscanf (arg, "#%d%d", &blk, &len) &&
453: 1 != sscanf (arg, "#%d", &blk))
454: goto Clean_up;
455:
456: if (len == 0) {
457: if (msf)
458: len = msf2lba (toc_buffer[n].addr.msf.minute,
459: toc_buffer[n].addr.msf.second,
460: toc_buffer[n].addr.msf.frame) - blk;
461: else
462: len = ntohl(toc_buffer[n].addr.lba) - blk;
463: }
464: return play_blocks (blk, len);
465: }
466:
467: if (strchr (arg, ':')) {
468: /*
469: * Play MSF m1:s1 [ .f1 ] [ m2:s2 [ .f2 ] ]
470: *
471: * Will now also undestand timed addresses relative
472: * to the beginning of a track in the form...
473: *
474: * tr1 m1:s1[.f1] [[tr2] [m2:s2[.f2]]]
475: */
476: unsigned tr1, tr2;
477: unsigned m1, m2, s1, s2, f1, f2;
478: unsigned char tm, ts, tf;
479:
480: tr2 = m2 = s2 = f2 = f1 = 0;
481: if (8 == sscanf (arg, "%d %d:%d.%d %d %d:%d.%d",
482: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2, &f2))
483: goto Play_Relative_Addresses;
484:
485: tr2 = m2 = s2 = f2 = f1 = 0;
486: if (7 == sscanf (arg, "%d %d:%d %d %d:%d.%d",
487: &tr1, &m1, &s1, &tr2, &m2, &s2, &f2))
488: goto Play_Relative_Addresses;
489:
490: tr2 = m2 = s2 = f2 = f1 = 0;
491: if (7 == sscanf (arg, "%d %d:%d.%d %d %d:%d",
492: &tr1, &m1, &s1, &f1, &tr2, &m2, &s2))
493: goto Play_Relative_Addresses;
494:
495: tr2 = m2 = s2 = f2 = f1 = 0;
496: if (7 == sscanf (arg, "%d %d:%d.%d %d:%d.%d",
497: &tr1, &m1, &s1, &f1, &m2, &s2, &f2))
498: goto Play_Relative_Addresses;
499:
500: tr2 = m2 = s2 = f2 = f1 = 0;
501: if (6 == sscanf (arg, "%d %d:%d.%d %d:%d",
502: &tr1, &m1, &s1, &f1, &m2, &s2))
503: goto Play_Relative_Addresses;
504:
505: tr2 = m2 = s2 = f2 = f1 = 0;
506: if (6 == sscanf (arg, "%d %d:%d %d:%d.%d",
507: &tr1, &m1, &s1, &m2, &s2, &f2))
508: goto Play_Relative_Addresses;
509:
510: tr2 = m2 = s2 = f2 = f1 = 0;
511: if (6 == sscanf (arg, "%d %d:%d.%d %d %d",
512: &tr1, &m1, &s1, &f1, &tr2, &m2))
513: goto Play_Relative_Addresses;
514:
515: tr2 = m2 = s2 = f2 = f1 = 0;
516: if (5 == sscanf (arg, "%d %d:%d %d:%d", &tr1, &m1, &s1, &m2, &s2))
517: goto Play_Relative_Addresses;
518:
519: tr2 = m2 = s2 = f2 = f1 = 0;
520: if (5 == sscanf (arg, "%d %d:%d %d %d",
521: &tr1, &m1, &s1, &tr2, &m2))
522: goto Play_Relative_Addresses;
523:
524: tr2 = m2 = s2 = f2 = f1 = 0;
525: if (5 == sscanf (arg, "%d %d:%d.%d %d",
526: &tr1, &m1, &s1, &f1, &tr2))
527: goto Play_Relative_Addresses;
528:
529: tr2 = m2 = s2 = f2 = f1 = 0;
530: if (4 == sscanf (arg, "%d %d:%d %d", &tr1, &m1, &s1, &tr2))
531: goto Play_Relative_Addresses;
532:
533: tr2 = m2 = s2 = f2 = f1 = 0;
534: if (4 == sscanf (arg, "%d %d:%d.%d", &tr1, &m1, &s1, &f1))
535: goto Play_Relative_Addresses;
536:
537: tr2 = m2 = s2 = f2 = f1 = 0;
538: if (3 == sscanf (arg, "%d %d:%d", &tr1, &m1, &s1))
539: goto Play_Relative_Addresses;
540:
541: tr2 = m2 = s2 = f2 = f1 = 0;
542: goto Try_Absolute_Timed_Addresses;
543:
544: Play_Relative_Addresses:
545: if (! tr1)
546: tr1 = 1;
547: else if (tr1 > n)
548: tr1 = n;
549:
550: if (msf) {
551: tm = toc_buffer[tr1].addr.msf.minute;
552: ts = toc_buffer[tr1].addr.msf.second;
553: tf = toc_buffer[tr1].addr.msf.frame;
554: } else
555: lba2msf(ntohl(toc_buffer[tr1].addr.lba),
556: &tm, &ts, &tf);
557: if ((m1 > tm)
558: || ((m1 == tm)
559: && ((s1 > ts)
560: || ((s1 == ts)
561: && (f1 > tf))))) {
562: printf ("Track %d is not that long.\n", tr1);
563: return (0);
564: }
565:
566: tr1--;
567:
568: f1 += tf;
569: if (f1 >= 75) {
570: s1 += f1 / 75;
571: f1 %= 75;
572: }
573:
574: s1 += ts;
575: if (s1 >= 60) {
576: m1 += s1 / 60;
577: s1 %= 60;
578: }
579:
580: m1 += tm;
581:
582: if (! tr2) {
583: if (m2 || s2 || f2) {
584: tr2 = tr1;
585: f2 += f1;
586: if (f2 >= 75) {
587: s2 += f2 / 75;
588: f2 %= 75;
589: }
590:
591: s2 += s1;
592: if (s2 > 60) {
593: m2 += s2 / 60;
594: s2 %= 60;
595: }
596:
597: m2 += m1;
598: } else {
599: tr2 = n;
600: if (msf) {
601: m2 = toc_buffer[n].addr.msf.minute;
602: s2 = toc_buffer[n].addr.msf.second;
603: f2 = toc_buffer[n].addr.msf.frame;
604: } else {
605: lba2msf(ntohl(toc_buffer[n].addr.lba),
606: &tm, &ts, &tf);
607: m2 = tm;
608: s2 = ts;
609: f2 = tf;
610: }
611: }
612: } else if (tr2 > n) {
613: tr2 = n;
614: m2 = s2 = f2 = 0;
615: } else {
616: if (m2 || s2 || f2)
617: tr2--;
618: if (msf) {
619: tm = toc_buffer[tr2].addr.msf.minute;
620: ts = toc_buffer[tr2].addr.msf.second;
621: tf = toc_buffer[tr2].addr.msf.frame;
622: } else
623: lba2msf(ntohl(toc_buffer[tr2].addr.lba),
624: &tm, &ts, &tf);
625: f2 += tf;
626: if (f2 >= 75) {
627: s2 += f2 / 75;
628: f2 %= 75;
629: }
630:
631: s2 += ts;
632: if (s2 > 60) {
633: m2 += s2 / 60;
634: s2 %= 60;
635: }
636:
637: m2 += tm;
638: }
639:
640: if (msf) {
641: tm = toc_buffer[n].addr.msf.minute;
642: ts = toc_buffer[n].addr.msf.second;
643: tf = toc_buffer[n].addr.msf.frame;
644: } else
645: lba2msf(ntohl(toc_buffer[n].addr.lba),
646: &tm, &ts, &tf);
647: if ((tr2 < n)
648: && ((m2 > tm)
649: || ((m2 == tm)
650: && ((s2 > ts)
651: || ((s2 == ts)
652: && (f2 > tf)))))) {
653: printf ("The playing time of the disc is not that long.\n");
654: return (0);
655: }
656: return (play_msf (m1, s1, f1, m2, s2, f2));
657:
658: Try_Absolute_Timed_Addresses:
659: if (6 != sscanf (arg, "%d:%d.%d%d:%d.%d",
660: &m1, &s1, &f1, &m2, &s2, &f2) &&
661: 5 != sscanf (arg, "%d:%d.%d%d:%d", &m1, &s1, &f1, &m2, &s2) &&
662: 5 != sscanf (arg, "%d:%d%d:%d.%d", &m1, &s1, &m2, &s2, &f2) &&
663: 3 != sscanf (arg, "%d:%d.%d", &m1, &s1, &f1) &&
664: 4 != sscanf (arg, "%d:%d%d:%d", &m1, &s1, &m2, &s2) &&
665: 2 != sscanf (arg, "%d:%d", &m1, &s1))
666: goto Clean_up;
667:
668: if (m2 == 0) {
669: if (msf) {
670: m2 = toc_buffer[n].addr.msf.minute;
671: s2 = toc_buffer[n].addr.msf.second;
672: f2 = toc_buffer[n].addr.msf.frame;
673: } else {
674: lba2msf(ntohl(toc_buffer[n].addr.lba),
675: &tm, &ts, &tf);
676: m2 = tm;
677: s2 = ts;
678: f2 = tf;
679: }
680: }
681: return play_msf (m1, s1, f1, m2, s2, f2);
682: }
683:
684: /*
685: * Play track trk1 [ .idx1 ] [ trk2 [ .idx2 ] ]
686: */
687: if (4 != sscanf (arg, "%d.%d%d.%d", &start, &istart, &end, &iend) &&
688: 3 != sscanf (arg, "%d.%d%d", &start, &istart, &end) &&
689: 3 != sscanf (arg, "%d%d.%d", &start, &end, &iend) &&
690: 2 != sscanf (arg, "%d.%d", &start, &istart) &&
691: 2 != sscanf (arg, "%d%d", &start, &end) &&
692: 1 != sscanf (arg, "%d", &start))
693: goto Clean_up;
694:
695: if (end == 0)
696: end = n;
697: return (play_track (start, istart, end, iend));
698:
699: Clean_up:
700: printf ("%s: Invalid command arguments\n", __progname);
1.5 ! angelos 701: return (0);
! 702: }
! 703:
! 704: int play_prev (arg)
! 705: char *arg;
! 706: {
! 707: int trk, min, sec, frm, rc;
! 708: struct ioc_toc_header h;
! 709:
! 710: if (status (&trk, &min, &sec, &frm) >= 0)
! 711: {
! 712: trk--;
! 713:
! 714: rc = ioctl (fd, CDIOREADTOCHEADER, &h);
! 715: if (rc < 0)
! 716: {
! 717: perror ("getting toc header");
! 718: return (rc);
! 719: }
! 720:
! 721: if (trk < h.starting_track)
! 722: return play_track (h.starting_track, 1,
! 723: h.starting_track + 1, 1);
! 724:
! 725: return play_track (trk, 1, trk + 1, 1);
! 726: }
! 727:
! 728: return (0);
! 729: }
! 730:
! 731: int play_next (arg)
! 732: char *arg;
! 733: {
! 734: int trk, min, sec, frm, rc;
! 735: struct ioc_toc_header h;
! 736:
! 737: if (status (&trk, &min, &sec, &frm) >= 0)
! 738: {
! 739: trk++;
! 740: rc = ioctl (fd, CDIOREADTOCHEADER, &h);
! 741: if (rc < 0)
! 742: {
! 743: perror ("getting toc header");
! 744: return (rc);
! 745: }
! 746:
! 747: if (trk > h.ending_track)
! 748: {
! 749: printf("%s: end of CD\n", __progname);
! 750:
! 751: rc = ioctl (fd, CDIOCSTOP);
! 752:
! 753: (void) ioctl (fd, CDIOCALLOW);
! 754:
! 755: return (rc);
! 756: }
! 757:
! 758: return play_track (trk, 1, trk + 1, 1);
! 759: }
! 760:
1.1 downsj 761: return (0);
762: }
763:
764: char *strstatus (sts)
765: int sts;
766: {
767: switch (sts) {
768: case ASTS_INVALID: return ("invalid");
769: case ASTS_PLAYING: return ("playing");
770: case ASTS_PAUSED: return ("paused");
771: case ASTS_COMPLETED: return ("completed");
772: case ASTS_ERROR: return ("error");
773: case ASTS_VOID: return ("void");
774: default: return ("??");
775: }
776: }
777:
778: int pstatus (arg)
779: char *arg;
780: {
781: struct ioc_vol v;
782: struct ioc_read_subchannel ss;
783: struct cd_sub_channel_info data;
784: int rc, trk, m, s, f;
785:
786: rc = status (&trk, &m, &s, &f);
787: if (rc >= 0)
788: if (verbose)
789: printf ("Audio status = %d<%s>, current track = %d, current position = %d:%02d.%02d\n",
790: rc, strstatus (rc), trk, m, s, f);
791: else
792: printf ("%d %d %d:%02d.%02d\n", rc, trk, m, s, f);
793: else
794: printf ("No current status info available\n");
795:
796: bzero (&ss, sizeof (ss));
797: ss.data = &data;
798: ss.data_len = sizeof (data);
799: ss.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
800: ss.data_format = CD_MEDIA_CATALOG;
801: rc = ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &ss);
802: if (rc >= 0) {
803: printf("Media catalog is %sactive",
804: ss.data->what.media_catalog.mc_valid ? "": "in");
805: if (ss.data->what.media_catalog.mc_valid &&
806: ss.data->what.media_catalog.mc_number[0])
807: printf(", number \"%.15s\"",
808: ss.data->what.media_catalog.mc_number);
809: putchar('\n');
810: } else
811: printf("No media catalog info available\n");
812:
813: rc = ioctl (fd, CDIOCGETVOL, &v);
814: if (rc >= 0)
815: if (verbose)
816: printf ("Left volume = %d, right volume = %d\n",
817: v.vol[0], v.vol[1]);
818: else
819: printf ("%d %d\n", v.vol[0], v.vol[1]);
820: else
821: printf ("No volume level info available\n");
822: return(0);
823: }
824:
825: int info (arg)
826: char *arg;
827: {
828: struct ioc_toc_header h;
829: int rc, i, n;
830:
831: rc = ioctl (fd, CDIOREADTOCHEADER, &h);
832: if (rc >= 0) {
833: if (verbose)
834: printf ("Starting track = %d, ending track = %d, TOC size = %d bytes\n",
835: h.starting_track, h.ending_track, h.len);
836: else
837: printf ("%d %d %d\n", h.starting_track,
838: h.ending_track, h.len);
839: } else {
840: perror ("getting toc header");
841: return (rc);
842: }
843:
844: n = h.ending_track - h.starting_track + 1;
845: rc = read_toc_entrys ((n + 1) * sizeof (struct cd_toc_entry));
846: if (rc < 0)
847: return (rc);
848:
849: if (verbose) {
850: printf ("track start duration block length type\n");
851: printf ("-------------------------------------------------\n");
852: }
853:
854: for (i = 0; i < n; i++) {
855: printf ("%5d ", toc_buffer[i].track);
856: prtrack (toc_buffer + i, 0);
857: }
858: printf ("%5d ", toc_buffer[n].track);
859: prtrack (toc_buffer + n, 1);
860: return (0);
861: }
862:
863: void lba2msf (lba, m, s, f)
864: unsigned long lba;
865: u_char *m;
866: u_char *s;
867: u_char *f;
868: {
869: lba += 150; /* block start offset */
870: lba &= 0xffffff; /* negative lbas use only 24 bits */
871: *m = lba / (60 * 75);
872: lba %= (60 * 75);
873: *s = lba / 75;
874: *f = lba % 75;
875: }
876:
877: unsigned int msf2lba (m, s, f)
878: u_char m;
879: u_char s;
880: u_char f;
881: {
882: return (((m * 60) + s) * 75 + f) - 150;
883: }
884:
885: void prtrack (e, lastflag)
886: struct cd_toc_entry *e;
887: int lastflag;
888: {
889: int block, next, len;
890: u_char m, s, f;
891:
892: if (msf) {
893: /* Print track start */
894: printf ("%2d:%02d.%02d ", e->addr.msf.minute,
895: e->addr.msf.second, e->addr.msf.frame);
896:
897: block = msf2lba (e->addr.msf.minute, e->addr.msf.second,
898: e->addr.msf.frame);
899: } else {
900: block = ntohl(e->addr.lba);
901: lba2msf(block, &m, &s, &f);
902: /* Print track start */
903: printf ("%2d:%02d.%02d ", m, s, f);
904: }
905: if (lastflag) {
906: /* Last track -- print block */
907: printf (" - %6d - -\n", block);
908: return;
909: }
910:
911: if (msf)
912: next = msf2lba (e[1].addr.msf.minute, e[1].addr.msf.second,
913: e[1].addr.msf.frame);
914: else
915: next = ntohl(e[1].addr.lba);
916: len = next - block;
917: lba2msf (len, &m, &s, &f);
918:
919: /* Print duration, block, length, type */
920: printf ("%2d:%02d.%02d %6d %6d %5s\n", m, s, f, block, len,
921: (e->control & 4) ? "data" : "audio");
922: }
923:
924: int play_track (tstart, istart, tend, iend)
925: int tstart;
926: int istart;
927: int tend;
928: int iend;
929: {
930: struct ioc_play_track t;
931:
932: t.start_track = tstart;
933: t.start_index = istart;
934: t.end_track = tend;
935: t.end_index = iend;
936:
937: return ioctl (fd, CDIOCPLAYTRACKS, &t);
938: }
939:
940: int play_blocks (blk, len)
941: int blk;
942: int len;
943: {
944: struct ioc_play_blocks t;
945:
946: t.blk = blk;
947: t.len = len;
948:
949: return ioctl (fd, CDIOCPLAYBLOCKS, &t);
950: }
951:
952: int setvol (left, right)
953: int left;
954: int right;
955: {
956: struct ioc_vol v;
957:
958: v.vol[0] = left;
959: v.vol[1] = right;
960: v.vol[2] = 0;
961: v.vol[3] = 0;
962:
963: return ioctl (fd, CDIOCSETVOL, &v);
964: }
965:
966: int read_toc_entrys (len)
967: int len;
968: {
969: struct ioc_read_toc_entry t;
970:
971: t.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
972: t.starting_track = 0;
973: t.data_len = len;
974: t.data = toc_buffer;
975:
976: return (ioctl (fd, CDIOREADTOCENTRYS, (char *) &t));
977: }
978:
979: int play_msf (start_m, start_s, start_f, end_m, end_s, end_f)
980: int start_m;
981: int start_s;
982: int start_f;
983: int end_m;
984: int end_s;
985: int end_f;
986: {
987: struct ioc_play_msf a;
988:
989: a.start_m = start_m;
990: a.start_s = start_s;
991: a.start_f = start_f;
992: a.end_m = end_m;
993: a.end_s = end_s;
994: a.end_f = end_f;
995:
996: return ioctl (fd, CDIOCPLAYMSF, (char *) &a);
997: }
998:
999: int status (trk, min, sec, frame)
1000: int *trk;
1001: int *min;
1002: int *sec;
1003: int *frame;
1004: {
1005: struct ioc_read_subchannel s;
1006: struct cd_sub_channel_info data;
1007: u_char mm, ss, ff;
1008:
1009: bzero (&s, sizeof (s));
1010: s.data = &data;
1011: s.data_len = sizeof (data);
1012: s.address_format = msf ? CD_MSF_FORMAT : CD_LBA_FORMAT;
1013: s.data_format = CD_CURRENT_POSITION;
1014:
1015: if (ioctl (fd, CDIOCREADSUBCHANNEL, (char *) &s) < 0)
1016: return -1;
1017:
1018: *trk = s.data->what.position.track_number;
1019: if (msf) {
1020: *min = s.data->what.position.reladdr.msf.minute;
1021: *sec = s.data->what.position.reladdr.msf.second;
1022: *frame = s.data->what.position.reladdr.msf.frame;
1023: } else {
1024: lba2msf(ntohl(s.data->what.position.reladdr.lba),
1025: &mm, &ss, &ff);
1026: *min = mm;
1027: *sec = ss;
1028: *frame = ff;
1029: }
1030:
1031: return s.data->header.audio_status;
1032: }
1033:
1034: char *input (cmd)
1035: int *cmd;
1036: {
1037: static char buf[80];
1038: char *p;
1039:
1040: do {
1041: if (verbose)
1042: fprintf (stderr, "%s> ", __progname);
1043: if (! fgets (buf, sizeof (buf), stdin)) {
1044: *cmd = CMD_QUIT;
1045: fprintf (stderr, "\r\n");
1046: return (0);
1047: }
1048: p = parse (buf, cmd);
1049: } while (! p);
1050: return (p);
1051: }
1052:
1053: char *parse (buf, cmd)
1054: char *buf;
1055: int *cmd;
1056: {
1057: struct cmdtab *c;
1058: char *p;
1059: int len;
1060:
1061: for (p=buf; isspace (*p); p++)
1062: continue;
1063:
1064: if (isdigit (*p) || (p[0] == '#' && isdigit (p[1]))) {
1065: *cmd = CMD_PLAY;
1066: return (p);
1067: }
1068:
1069: for (buf = p; *p && ! isspace (*p); p++)
1070: continue;
1071:
1072: len = p - buf;
1073: if (! len)
1074: return (0);
1075:
1076: if (*p) { /* It must be a spacing character! */
1077: char *q;
1078:
1079: *p++ = 0;
1080: for (q=p; *q && *q != '\n' && *q != '\r'; q++)
1081: continue;
1082: *q = 0;
1083: }
1084:
1085: *cmd = -1;
1086: for (c=cmdtab; c->name; ++c) {
1087: /* Is it an exact match? */
1088: if (! strcasecmp (buf, c->name)) {
1089: *cmd = c->command;
1090: break;
1091: }
1092:
1093: /* Try short hand forms then... */
1094: if (len >= c->min && ! strncasecmp (buf, c->name, len)) {
1095: if (*cmd != -1 && *cmd != c->command) {
1096: fprintf (stderr, "Ambiguous command\n");
1097: return (0);
1098: }
1099: *cmd = c->command;
1100: }
1101: }
1102:
1103: if (*cmd == -1) {
1104: fprintf (stderr, "%s: Invalid command, enter ``help'' for commands.\n",
1105: __progname);
1106: return (0);
1107: }
1108:
1109: while (isspace (*p))
1110: p++;
1111: return p;
1112: }
1113:
1114: int open_cd ()
1115: {
1116: char *dev;
1117:
1118: if (fd > -1)
1119: return (1);
1120:
1121: fd = opendev(cdname, O_RDONLY, OPENDEV_PART, &dev);
1122: if (fd < 0) {
1123: if ((errno == ENXIO) || (errno == EIO)) {
1124: /* ENXIO has an overloaded meaning here.
1125: * The original "Device not configured" should
1126: * be interpreted as "No disc in drive %s". */
1127: fprintf (stderr, "%s: No disc in drive %s.\n", __progname, dev);
1128: return (0);
1129: }
1130: perror (dev);
1131: exit (1);
1132: }
1133: return (1);
1134: }