diff options
author | Michael Shalayeff <mickey@cvs.openbsd.org> | 1996-05-16 09:28:57 +0000 |
---|---|---|
committer | Michael Shalayeff <mickey@cvs.openbsd.org> | 1996-05-16 09:28:57 +0000 |
commit | cce64b8c239c48d8a40a028c26cb08ad645d3840 (patch) | |
tree | 17a86a55d7a69b5223b445894ab0899f54cb7ef2 /sys | |
parent | cf3fdeb83b3dc4d2a89ee0ac772ea3eb608e3c33 (diff) |
from NetBSD PR#812:
allow CDDA disks to be read.
not tested, anyone w/ SCSI CD is ought to.
here is the test program (not tested too ;):
#define CDDA
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/scsiio.h>
#include <sys/cdio.h>
#include <scsi/scsi_all.h>
#include <scsi/scsi_cd.h>
#include <scsi/scsi_disk.h>
extern int errno;
void
usage()
{
fprintf(stderr, "usage: cdda -d device -b blkcnt -o offset >output\n");
exit(1);
}
char databuf[CD_DA_BLKSIZ];
main(int argc, char *argv[])
{
int ch;
int fd;
off_t offset = 0;
int cnt = 0;
char *dev = 0;
struct scsi_rw_big read_cmd;
struct scsi_mode_sense sense_cmd;
struct cd_mode_data bdesc;
scsireq_t req;
while ((ch = getopt(argc, argv, "d:b:o:")) != -1) {
switch (ch) {
case 'd':
dev = optarg;
break;
case 'b':
cnt = atoi(optarg);
if (cnt <= 0)
usage();
break;
case 'o':
offset = atoi(optarg);
break;
case '?':
default:
usage();
}
}
if (dev == NULL || cnt == 0)
usage();
fd = open(dev, O_RDONLY);
if (fd == -1)
err(1,"can't open device %s", dev);
#ifdef DEBUG
ch = SC_DB_FLOW;
ioctl(fd, SCIOCDEBUG, &ch);
#endif
ch = 1;
if (ioctl(fd, CDIOCSETCDDA, &ch) == -1)
warn("can't set CDDA mode");
read_cmd.opcode = READ_BIG; /* READ10 */
read_cmd.byte2 = 0; /* no relative */
read_cmd.reserved = 0;
read_cmd.length2 = 0;
read_cmd.length1 = 1; /* read one block at a time.
hope it caches! */
read_cmd.control = 0; /* LBA mode, leave flag & link zero */
for (; cnt > 0; cnt--, offset++) {
read_cmd.addr_3 = (offset >> 24) & 0xff;
read_cmd.addr_2 = (offset >> 16) & 0xff;
read_cmd.addr_1 = (offset >> 8) & 0xff;
read_cmd.addr_0 = offset & 0xff;
memset(&req, 0, sizeof(req));
req.flags = SCCMD_READ;
/* timeout is in milliseconds--not that it's obvious from the
include files! */
req.timeout = 10000; /* 10 sec */
bcopy(&read_cmd, req.cmd, sizeof(read_cmd));
req.cmdlen = sizeof(read_cmd);
req.databuf = databuf;
req.datalen = sizeof(databuf);
req.senselen = sizeof(req.sense); /* XXX */
if (ioctl(fd, SCIOCCOMMAND, &req) == -1) {
fprintf(stderr, "bad ioctl: %d\n", errno);
ch = 0;
ioctl(fd, CDIOCSETCDDA, &ch);
#ifdef DEBUG
ioctl(fd, SCIOCDEBUG, &ch);
#endif
exit(1);
}
if (req.retsts != 0 || req.error != 0) {
ch = 0;
ioctl(fd, CDIOCSETCDDA, &ch);
#ifdef DEBUG
ioctl(fd, SCIOCDEBUG, &ch);
#endif
errx(1,"return status %d, error %d\n", req.retsts, req.error);
}
if (req.datalen_used != sizeof(databuf)) {
ch = 0;
ioctl(fd, CDIOCSETCDDA, &ch);
#ifdef DEBUG
ioctl(fd, SCIOCDEBUG, &ch);
#endif
errx(1,"didn't get full buffer back (%x)", req.datalen_used);
}
write(1, databuf, sizeof(databuf));
}
ch = 0;
if (ioctl(fd, CDIOCSETCDDA, &ch) == -1)
warn("can't reset CDDA mode");
#ifdef DEBUG
ioctl(fd, SCIOCDEBUG, &ch);
#endif
close(fd);
exit(0);
}
Diffstat (limited to 'sys')
-rw-r--r-- | sys/scsi/cd.c | 100 | ||||
-rw-r--r-- | sys/scsi/scsi_cd.h | 17 | ||||
-rw-r--r-- | sys/sys/cdio.h | 3 |
3 files changed, 119 insertions, 1 deletions
diff --git a/sys/scsi/cd.c b/sys/scsi/cd.c index 08ee3872ae7..31105662554 100644 --- a/sys/scsi/cd.c +++ b/sys/scsi/cd.c @@ -86,11 +86,17 @@ struct cd_softc { #define CDF_WLABEL 0x04 /* label is writable */ #define CDF_LABELLING 0x08 /* writing label */ #define CDF_ANCIENT 0x10 /* disk is ancient; for minphys */ +#ifdef CDDA +#define CDF_CDDAMODE 0x08 +#endif struct scsi_link *sc_link; /* contains our targ, lun, etc. */ struct cd_parms { int blksize; u_long disksize; /* total number sectors */ } params; +#ifdef CDDA + struct cd_parms orig_params; /* filled in when CD-DA mode starts */ +#endif struct buf buf_queue; }; @@ -267,6 +273,18 @@ cdopen(dev, flag, fmt, p) if ((error = cdlock(cd)) != 0) return error; +#ifdef CDDA + /* + * We can't open the block device if the drive is in CDDA + * mode. If we allow such opens, either the drive will get + * quite unhappy about undersized I/O or the BSD I/O subsystem + * will start trashing memory with disk transfers overrunning + * the end of their buffers. Either way, it's Bad. + */ + if (cd->flags & CDF_CDDAMODE && fmt == S_IFBLK) + return EBUSY; +#endif + if (cd->sc_dk.dk_openmask != 0) { /* * If any partition is open, but the disk has been invalidated, @@ -276,6 +294,16 @@ cdopen(dev, flag, fmt, p) error = EIO; goto bad3; } +#ifdef CDDA + /* + * If it's in CDDA mode, process may only open the + * raw partition + */ + if (cd->flags & CDF_CDDAMODE && part != RAW_PART) { + error = EBUSY; + goto bad3; + } +#endif } else { /* Check that it is still responding and ok. */ error = scsi_test_unit_ready(sc_link, @@ -432,6 +460,18 @@ cdstrategy(bp) if (bp->b_bcount == 0) goto done; +#ifdef CDDA + /* + * If in CDDA mode, return immediately (the user must issue + * SCSI read commands directly using SCIOCCOMMAND). The BSD + * I/O subsystem just can't deal with bizzare block sizes like + * those used for CD-DA frames. + */ + if (cd->flags & CDF_CDDAMODE) { + bp->b_error = EIO; + goto bad; + } +#endif /* * Do bounds checking, adjust transfer. if error, process. * If end of partition, just return. @@ -909,6 +949,66 @@ cdioctl(dev, cmd, addr, flag, p) return 0; case CDIOCRESET: return cd_reset(cd); +#ifdef CDDA + case CDIOCSETCDDA: { + int onoff = *(int *)addr; + /* select CD-DA mode */ + struct cd_mode_data data; + + if (CDPART(dev) != RAW_PART) + return ENOTTY; + if (error = cd_get_mode(cd, &data, AUDIO_PAGE)) + return error; + if (onoff) { + /* turn it on */ + if (cd->flags & CDF_CDDAMODE) + return EALREADY; + /* + * do not permit changing of block size if the block + * device is open, or if some other partition (not + * a raw partition) is open. + */ + if (cd->sc_dk.dk_bopenmask || + (cd->sc_dk.dk_copenmask & ~(1 << RAW_PART))) + return EBUSY; + + data.blk_desc.density = CD_DA_DENSITY_CODE; + data.blk_desc.blklen[0] = (CD_DA_BLKSIZ >> 16) & 0xff; + data.blk_desc.blklen[1] = (CD_DA_BLKSIZ >> 8) & 0xff; + data.blk_desc.blklen[2] = CD_DA_BLKSIZ & 0xff; + + if (cd_set_mode(cd, &data) != 0) + return EIO; + + cd->orig_params = cd->params; + cd->flags |= CDF_CDDAMODE; + } else { + if (!(cd->flags & CDF_CDDAMODE)) + return EALREADY; + /* turn it off */ + data.blk_desc.density = CD_NORMAL_DENSITY_CODE; + data.blk_desc.blklen[0] = (cd->orig_params.blksize >> 16) & 0xff; + data.blk_desc.blklen[1] = (cd->orig_params.blksize >> 8) & 0xff; + data.blk_desc.blklen[2] = (cd->orig_params.blksize) & 0xff; + + if (cd_set_mode(cd, &data) != 0) + return EIO; + + cd->flags &= ~CDF_CDDAMODE; + cd->params = cd->orig_params; + } + if (cd_get_parms(cd, 0) != 0) { + data.blk_desc.density = CD_NORMAL_DENSITY_CODE; + data.blk_desc.blklen[0] = (cd->orig_params.blksize >> 16) & 0xff; + data.blk_desc.blklen[1] = (cd->orig_params.blksize >> 8) & 0xff; + data.blk_desc.blklen[2] = (cd->orig_params.blksize) & 0xff; + (void) cd_set_mode(cd, &data); /* it better work...! */ + cd->params = cd->orig_params; + return EIO; + } + return 0; + } +#endif default: if (CDPART(dev) != RAW_PART) diff --git a/sys/scsi/scsi_cd.h b/sys/scsi/scsi_cd.h index ddf2431b2da..2135a4a6ce6 100644 --- a/sys/scsi/scsi_cd.h +++ b/sys/scsi/scsi_cd.h @@ -191,6 +191,23 @@ union cd_pages { } audio; }; +#ifdef CDDA +/* + * There are 2352 bytes in a CD digital audio frame. One frame is 1/75 of a + * second, at 44.1kHz sample rate, 16 bits/sample, 2 channels. + * + * The frame data have the two channels interleaved, with the left + * channel first. Samples are little endian 16-bit signed values. + */ +#define CD_DA_BLKSIZ 2352 /* # bytes in CD-DA frame */ +#ifndef CD_NORMAL_DENSITY_CODE +#define CD_NORMAL_DENSITY_CODE 0x00 /* from Toshiba CD-ROM specs */ +#endif +#ifndef CD_DA_DENSITY_CODE +#define CD_DA_DENSITY_CODE 0x82 /* from Toshiba CD-ROM specs */ +#endif +#endif /* CDDA */ + struct cd_mode_data { struct scsi_mode_header header; struct scsi_blk_desc blk_desc; diff --git a/sys/sys/cdio.h b/sys/sys/cdio.h index 0ef183f8ad5..22707e96d74 100644 --- a/sys/sys/cdio.h +++ b/sys/sys/cdio.h @@ -1,4 +1,4 @@ -/* $OpenBSD: cdio.h,v 1.4 1996/03/03 12:11:24 niklas Exp $ */ +/* $OpenBSD: cdio.h,v 1.5 1996/05/16 09:28:54 mickey Exp $ */ /* $NetBSD: cdio.h,v 1.11 1996/02/19 18:29:04 scottr Exp $ */ #ifndef _SYS_CDIO_H_ @@ -174,6 +174,7 @@ struct ioc_vol { #define CDIOCEJECT _IO('c', 24) #define CDIOCALLOW _IO('c', 25) #define CDIOCPREVENT _IO('c', 26) +#define CDIOCSETCDDA _IOW('c', 27, int) /* (re)set CDDA reading mode */ struct ioc_play_msf { u_char start_m; |