summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Coulter <mjc@cvs.openbsd.org>2006-05-31 01:14:42 +0000
committerMichael Coulter <mjc@cvs.openbsd.org>2006-05-31 01:14:42 +0000
commitb7e06e0faad4c8501344e9a3df2dc87691753266 (patch)
tree8acae3262f89052187567eff15372b55dbc9c4b0
parent3a7e619f19cf277f8d491b67251257dea1d6f143 (diff)
add rewritable blanking and track-at-once burning support
ok deraadt@
-rw-r--r--usr.bin/cdio/Makefile4
-rw-r--r--usr.bin/cdio/cdio.124
-rw-r--r--usr.bin/cdio/cdio.c79
-rw-r--r--usr.bin/cdio/extern.h9
-rw-r--r--usr.bin/cdio/mmc.c290
5 files changed, 382 insertions, 24 deletions
diff --git a/usr.bin/cdio/Makefile b/usr.bin/cdio/Makefile
index 25f09099828..585ce29f4ca 100644
--- a/usr.bin/cdio/Makefile
+++ b/usr.bin/cdio/Makefile
@@ -1,9 +1,9 @@
-# $OpenBSD: Makefile,v 1.3 2003/02/13 05:48:38 fgsch Exp $
+# $OpenBSD: Makefile,v 1.4 2006/05/31 01:14:41 mjc Exp $
PROG= cdio
DPADD= ${LIBUTIL} ${LIBEDIT} ${LIBTERMCAP}
LDADD= -lutil -ledit -ltermcap
-SRCS= cdio.c cddb.c
+SRCS= cdio.c cddb.c mmc.c
CDIAGFLAGS=-Wall -W -Wmissing-prototypes -pedantic
.include <bsd.prog.mk>
diff --git a/usr.bin/cdio/cdio.1 b/usr.bin/cdio/cdio.1
index 34e24f6bc4c..7f9c73ce447 100644
--- a/usr.bin/cdio/cdio.1
+++ b/usr.bin/cdio/cdio.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: cdio.1,v 1.31 2006/01/23 00:41:10 krw Exp $
+.\" $OpenBSD: cdio.1,v 1.32 2006/05/31 01:14:41 mjc Exp $
.\"
.\" Copyright (c) 1995 Serge V. Vakulenko
.\" All rights reserved.
@@ -97,6 +97,8 @@ The word
.Ic play
may be omitted.
.Bl -tag -width Ds
+.It Ic blank
+Minimally blank the disc.
.It Ic cddb Op Ar n
Print the table of contents after matching the disc with the cddb.
In case of multiple matches, reissue the command with
@@ -198,6 +200,26 @@ the current media catalog status,
and the current values of the volume for left and right channels.
.It Ic stop
Stop the disc.
+.It Xo Ic tao
+.Op Fl t Ar tracktypes
+.Ar trackfile ...
+.Xc
+Write track-at-once cd containing each
+.Ar trackfile
+specified.
+The string
+.Ar tracktypes
+is used to assign types to each corresponding
+.Ar trackfile .
+Valid characters for the
+.Ar tracktypes
+string are 'a' for audio, 'd' for data.
+If there are more tracks specified than corresponding
+types, the last type will be used for the remainder.
+If
+.Ar tracktypes
+is completely unspecified, a track type of data is used.
+This option is only available from the command line.
.It Ic volume Ar left_channel Ar right_channel
Set the volume of the left channel to
.Ar left_channel
diff --git a/usr.bin/cdio/cdio.c b/usr.bin/cdio/cdio.c
index 784d54f0a42..6d1f7b53aaa 100644
--- a/usr.bin/cdio/cdio.c
+++ b/usr.bin/cdio/cdio.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: cdio.c,v 1.47 2006/01/20 00:58:32 krw Exp $ */
+/* $OpenBSD: cdio.c,v 1.48 2006/05/31 01:14:41 mjc Exp $ */
/* Copyright (c) 1995 Serge V. Vakulenko
* All rights reserved.
@@ -56,6 +56,7 @@
#include <sys/file.h>
#include <sys/cdio.h>
#include <sys/ioctl.h>
+#include <sys/scsiio.h>
#include <ctype.h>
#include <err.h>
@@ -101,6 +102,7 @@
#define CMD_REPLAY 18
#define CMD_CDDB 19
#define CMD_CDID 20
+#define CMD_BLANK 21
struct cmdtab {
int command;
@@ -132,6 +134,7 @@ struct cmdtab {
{ CMD_CDDB, "cddbinfo", 2, "[n]" },
{ CMD_CDID, "cdid", 3, "" },
{ CMD_QUIT, "exit", 2, "" },
+{ CMD_BLANK, "blank", 1, "" },
{ 0, 0, 0, 0}
};
@@ -143,6 +146,7 @@ int verbose = 1;
int msf = 1;
const char *cddb_host;
char **track_names;
+char *track_types;
EditLine *el = NULL; /* line-editing structure */
History *hist = NULL; /* line-editing history */
@@ -156,7 +160,7 @@ int play_msf(int, int, int, int, int, int);
int play_track(int, int, int, int);
int get_vol(int *, int *);
int status(int *, int *, int *, int *);
-int open_cd(char *);
+int open_cd(char *, int);
int play(char *arg);
int info(char *arg);
int cddbinfo(char *arg);
@@ -258,6 +262,31 @@ main(int argc, char **argv)
"No CD device name specified. Defaulting to %s.\n", cdname);
}
+ if (argc > 0 && ! strcasecmp(*argv, "tao")) {
+ optreset = 1;
+ optind = 0;
+ while ((ch = getopt(argc, argv, "t:")) != -1) {
+ switch (ch) {
+ case 't':
+ track_types = optarg;
+ break;
+ default:
+ usage();
+ }
+
+ }
+ argc -= optind;
+ argv += optind;
+ if (argc == 0)
+ usage();
+ if (! open_cd(cdname, 1))
+ exit(1);
+ if (writetao(argc,argv) != 0)
+ exit(1);
+ else
+ exit(0);
+ }
+
if (argc > 0) {
char buf[80], *p;
int len;
@@ -310,42 +339,42 @@ run(int cmd, char *arg)
exit(0);
case CMD_INFO:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
return info(arg);
case CMD_CDDB:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
return cddbinfo(arg);
case CMD_CDID:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
return cdid();
case CMD_STATUS:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
return pstatus(arg);
case CMD_PAUSE:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
return ioctl(fd, CDIOCPAUSE);
case CMD_RESUME:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
return ioctl(fd, CDIOCRESUME);
case CMD_STOP:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
rc = ioctl(fd, CDIOCSTOP);
@@ -355,7 +384,7 @@ run(int cmd, char *arg)
return (rc);
case CMD_RESET:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
rc = ioctl(fd, CDIOCRESET);
@@ -366,7 +395,7 @@ run(int cmd, char *arg)
return (0);
case CMD_DEBUG:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
if (! strcasecmp(arg, "on"))
@@ -393,14 +422,14 @@ run(int cmd, char *arg)
}
/* open new device */
- if (!open_cd(arg))
+ if (! open_cd(arg, 0))
return (0);
(void) strlcpy(newcdname, arg, sizeof(newcdname));
cdname = newcdname;
return (1);
case CMD_EJECT:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
(void) ioctl(fd, CDIOCALLOW);
@@ -418,7 +447,7 @@ run(int cmd, char *arg)
case CMD_CLOSE:
#if defined(CDIOCCLOSE)
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
(void) ioctl(fd, CDIOCALLOW);
@@ -434,7 +463,7 @@ run(int cmd, char *arg)
#endif
case CMD_PLAY:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
while (isspace(*arg))
@@ -452,7 +481,7 @@ run(int cmd, char *arg)
return (0);
case CMD_VOLUME:
- if (fd < 0 && !open_cd(cdname))
+ if (fd < 0 && !open_cd(cdname, 0))
return (0);
if (!strncasecmp(arg, "left", strlen(arg)))
@@ -478,22 +507,27 @@ run(int cmd, char *arg)
return setvol(l, r);
case CMD_NEXT:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
return play_next(arg);
case CMD_PREV:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return (0);
return play_prev(arg);
case CMD_REPLAY:
- if (fd < 0 && ! open_cd(cdname))
+ if (fd < 0 && ! open_cd(cdname, 0))
return 0;
return play_same(arg);
+ case CMD_BLANK:
+ if (fd < 0 && ! open_cd(cdname, 1))
+ return 0;
+
+ return blank();
default:
case CMD_HELP:
help();
@@ -1396,7 +1430,7 @@ parse(char *buf, int *cmd)
}
int
-open_cd(char *dev)
+open_cd(char *dev, int needwrite)
{
char *realdev;
int tries;
@@ -1405,7 +1439,10 @@ open_cd(char *dev)
return (1);
for (tries = 0; fd < 0 && tries < 10; tries++) {
- fd = opendev(dev, O_RDONLY, OPENDEV_PART, &realdev);
+ if (needwrite)
+ fd = opendev(dev, O_RDWR, OPENDEV_PART, &realdev);
+ else
+ fd = opendev(dev, O_RDONLY, OPENDEV_PART, &realdev);
if (fd < 0) {
if (errno == ENXIO) {
/* ENXIO has an overloaded meaning here.
diff --git a/usr.bin/cdio/extern.h b/usr.bin/cdio/extern.h
index 9ea3469ef5d..b766ba3cac3 100644
--- a/usr.bin/cdio/extern.h
+++ b/usr.bin/cdio/extern.h
@@ -31,5 +31,14 @@ extern unsigned long entry2frames(struct cd_toc_entry *);
extern char ** cddb(const char *, int, struct cd_toc_entry *, char *);
extern unsigned long cddb_discid(int, struct cd_toc_entry *);
extern void free_names(char **);
+extern int blank(void);
+extern int unit_ready(void);
+extern int synchronize_cache(void);
+extern int close_session(void);
+extern int get_nwa(int *);
+extern int writetao(int, char *[]);
+extern int writetrack(char *, u_int, u_int, char);
+extern int mode_sense_write(unsigned char []);
+extern int mode_select_write(unsigned char []);
#define VERSION "2.1"
diff --git a/usr.bin/cdio/mmc.c b/usr.bin/cdio/mmc.c
new file mode 100644
index 00000000000..a582a2493ac
--- /dev/null
+++ b/usr.bin/cdio/mmc.c
@@ -0,0 +1,290 @@
+#include <sys/limits.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/scsiio.h>
+#include <err.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "extern.h"
+
+#define WAVHDRLEN 44
+extern int fd;
+extern char *track_types;
+
+int
+blank(void)
+{
+ scsireq_t scr;
+ int r;
+
+ bzero(&scr, sizeof(scr));
+ scr.cmd[0] = 0xa1;
+ scr.cmd[1] = 0x01;
+ scr.cmdlen = 12;
+ scr.datalen = 0;
+ scr.timeout = 120000;
+ scr.flags = SCCMD_ESCAPE;
+ scr.senselen = SENSEBUFLEN;
+
+ r = ioctl(fd, SCIOCCOMMAND, &scr);
+ return (r == 0 ? scr.retsts : -1);
+}
+
+int
+unit_ready(void)
+{
+ scsireq_t scr;
+ int r;
+
+ bzero(&scr, sizeof(scr));
+ scr.cmd[0] = 0x00;
+ scr.cmdlen = 6;
+ scr.datalen = 0;
+ scr.timeout = 120000;
+ scr.flags = SCCMD_ESCAPE;
+ scr.senselen = SENSEBUFLEN;
+
+ r = ioctl(fd, SCIOCCOMMAND, &scr);
+ return (r == 0 ? scr.retsts : -1);
+}
+
+int
+synchronize_cache(void)
+{
+ scsireq_t scr;
+ int r;
+
+ bzero(&scr, sizeof(scr));
+ scr.cmd[0] = 0x35;
+ scr.cmdlen = 10;
+ scr.datalen = 0;
+ scr.timeout = 120000;
+ scr.flags = SCCMD_ESCAPE;
+ scr.senselen = SENSEBUFLEN;
+
+ r = ioctl(fd, SCIOCCOMMAND, &scr);
+ return (r == 0 ? scr.retsts : -1);
+}
+
+int
+close_session(void)
+{
+ scsireq_t scr;
+ int r;
+
+ bzero(&scr, sizeof(scr));
+ scr.cmd[0] = 0x5b;
+ scr.cmd[2] = 0x02; /* close session */
+ scr.cmd[5] = 0x00; /* track number */
+ scr.cmdlen = 10;
+ scr.datalen = 0;
+ scr.timeout = 120000;
+ scr.flags = SCCMD_ESCAPE;
+ scr.senselen = SENSEBUFLEN;
+
+ r = ioctl(fd, SCIOCCOMMAND, &scr);
+ return (r == 0 ? scr.retsts : -1);
+
+}
+
+int
+writetao(int ntracks, char *track_files[])
+{
+ u_char modebuf[70];
+ u_int blklen;
+ u_int t;
+ int i,r;
+ u_char bdlen;
+
+ if (track_types == NULL)
+ track_types = strdup("d");
+ if ((r = mode_sense_write(modebuf)) != SCCMD_OK) {
+ warnx("mode sense failed: %d", r);
+ return (r);
+ }
+ bdlen = modebuf[7];
+ modebuf[2+8+bdlen] |= 0x40; /* Buffer Underrun Free Enable */
+ modebuf[2+8+bdlen] |= 0x01; /* change write type to TAO */
+
+ for (i = 0, t = 0; t < ntracks; t++) {
+ if (track_types[i] == 'd') {
+ modebuf[3+8+bdlen] = 0x04; /* track mode = data */
+ modebuf[4+8+bdlen] = 0x08; /* 2048 block track mode */
+ modebuf[8+8+bdlen] = 0x00; /* turn off XA */
+ blklen = 2048;
+ } else if (track_types[i] == 'a') {
+ modebuf[3+8+bdlen] = 0x00; /* track mode = audio */
+ modebuf[4+8+bdlen] = 0x00; /* 2352 block track mode */
+ modebuf[8+8+bdlen] = 0x00; /* turn off XA */
+ blklen = 2352;
+ } else {
+ warnx("invalid track type specified");
+ return (1);
+ }
+ while (unit_ready() != SCCMD_OK)
+ continue;
+ if ((r = mode_select_write(modebuf)) != SCCMD_OK) {
+ warnx("mode select failed: %d",r);
+ return (r);
+ }
+ writetrack(track_files[t], blklen, t, track_types[i]);
+ synchronize_cache();
+ if (track_types[i+1] != '\0')
+ i++;
+ }
+ fprintf(stderr,"\n");
+ synchronize_cache();
+ close_session();
+ return (0);
+}
+
+int
+writetrack(char *file, u_int blklen, u_int trackno, char type)
+{
+ u_char databuf[65536];
+ struct stat sb;
+ scsireq_t scr;
+ u_int end_lba, lba;
+ u_int tmp;
+ int r,rfd;
+ u_char nblk;
+
+ nblk = 65535/blklen;
+ bzero(&scr, sizeof(scr));
+ scr.timeout = 300000;
+ scr.cmd[0] = 0x2a;
+ scr.cmd[1] = 0x00;
+ scr.cmd[8] = nblk; /* Transfer length in blocks (LSB) */
+ scr.cmdlen = 10;
+ scr.databuf = (caddr_t)databuf;
+ scr.datalen = nblk * blklen;
+ scr.senselen = SENSEBUFLEN;
+ scr.flags = SCCMD_ESCAPE|SCCMD_WRITE;
+
+ if (get_nwa(&lba) != SCCMD_OK) {
+ warnx("cannot get next writable address");
+ return (-1);
+ }
+ tmp = htobe32(lba); /* update lba in cdb */
+ memcpy(&scr.cmd[2], &tmp, sizeof(tmp));
+
+ if (stat(file, &sb) != 0) {
+ warn("cannot stat file %s",file);
+ return (-1);
+ }
+ if (sb.st_size / blklen + 1 > UINT_MAX || sb.st_size < blklen) {
+ warnx("file %s has invalid size",file);
+ return (-1);
+ }
+ if (type == 'a')
+ sb.st_size -= WAVHDRLEN;
+ if (sb.st_size % blklen) {
+ warnx("file %s is not multiple of block length %d",file,blklen);
+ end_lba = sb.st_size / blklen + lba + 1;
+ } else {
+ end_lba = sb.st_size / blklen + lba;
+ }
+ rfd = open(file, O_RDONLY, 0640);
+ if (type == 'a') {
+ if (lseek(rfd, WAVHDRLEN, SEEK_SET) == -1)
+ err(1, "seek failed");
+ }
+ while ((lba < end_lba) && (nblk != 0)) {
+ while (lba + nblk <= end_lba) {
+ read(rfd, databuf, nblk * blklen);
+ scr.cmd[8] = nblk;
+ scr.datalen = nblk * blklen;
+ r = ioctl(fd, SCIOCCOMMAND, &scr);
+ if (r != 0) {
+ warn("ioctl failed while attempting to write");
+ return (-1);
+ }
+ if (scr.retsts != SCCMD_OK) {
+ warnx("ioctl returned bad status while attempting to write: %d", scr.retsts);
+ return (r);
+ }
+ lba += nblk;
+ fprintf(stderr,"\rLBA: 0x%06x/0x%06x",lba,end_lba);
+ tmp = htobe32(lba); /* update lba in cdb */
+ memcpy(&scr.cmd[2], &tmp, sizeof(tmp));
+ }
+ nblk--;
+ }
+ close(rfd);
+ return (0);
+}
+
+int
+mode_sense_write(unsigned char buf[])
+{
+ scsireq_t scr;
+ int r;
+
+ bzero(&scr, sizeof(scr));
+ scr.timeout = 4000;
+ scr.senselen = SENSEBUFLEN;
+ scr.cmd[0] = 0x5a;
+ scr.cmd[1] = 0x00;
+ scr.cmd[2] = 0x05; /* Write parameters mode page */
+ scr.cmd[7] = 0x00;
+ scr.cmd[8] = 0x46; /* 16 for the header + size from pg. 89 mmc-r10a.pdf */
+ scr.cmdlen = 10;
+ scr.datalen= 0x46;
+ scr.flags = SCCMD_ESCAPE|SCCMD_READ;
+ scr.databuf = (caddr_t)buf;
+
+ r = ioctl(fd, SCIOCCOMMAND, &scr);
+ return (r == 0 ? scr.retsts : -1);
+}
+
+int
+mode_select_write(unsigned char buf[])
+{
+ scsireq_t scr;
+ int r;
+
+ bzero(&scr, sizeof(scr));
+ scr.timeout = 4000;
+ scr.senselen = SENSEBUFLEN;
+ scr.cmd[0] = 0x55;
+ scr.cmd[1] = 0x10; /* pages aren't vendor specific */
+ scr.cmd[2] = 0x00;
+ scr.cmd[7] = 0x00;
+ scr.cmd[8] = 2 + buf[1] + 256 * buf[0];
+ scr.cmdlen = 10;
+ scr.datalen = 2 + buf[1] + 256 * buf[0];
+ scr.flags = SCCMD_ESCAPE|SCCMD_WRITE;
+ scr.databuf = (caddr_t)buf;
+
+ r = ioctl(fd, SCIOCCOMMAND, &scr);
+ return (r == 0 ? scr.retsts : -1);
+}
+
+int
+get_nwa(int *nwa)
+{
+ u_char databuf[28];
+ scsireq_t scr;
+ int r,tmp;
+
+ bzero(&scr, sizeof(scr));
+ scr.timeout = 4000;
+ scr.senselen = SENSEBUFLEN;
+ scr.cmd[0] = 0x52; /* READ TRACK INFO */
+ scr.cmd[1] = 0x01;
+ scr.cmd[5] = 0xff; /* Invisible Track */
+ scr.cmd[2] = 0x05; /* Write parameters mode page */
+ scr.cmd[7] = 0x00;
+ scr.cmd[8] = 0x1c;
+ scr.cmdlen = 10;
+ scr.datalen= 0x1c;
+ scr.flags = SCCMD_ESCAPE|SCCMD_READ;
+ scr.databuf = (caddr_t)databuf;
+
+ r = ioctl(fd, SCIOCCOMMAND, &scr);
+ memcpy(&tmp, &databuf[12], sizeof(tmp));
+ *nwa = betoh32(tmp);
+ return (r == 0 ? scr.retsts : -1);
+}