Add DVD+RW support to the ATA driver and burncd. This also closes

PR40430 by "Peter Haight <peterh@sapros.com>" that has semilar patches
included and which I merged with my own work.

HW sponsored by: FreeBSD Foundation & FreeBSD Mall Inc

Enjoy!
This commit is contained in:
Søren Schmidt 2002-08-08 07:59:24 +00:00
parent 6933e3c12b
commit b2e73852e5
5 changed files with 225 additions and 33 deletions

View File

@ -102,6 +102,8 @@ static int acd_mode_sense(struct acd_softc *, int, caddr_t, int);
static int acd_mode_select(struct acd_softc *, caddr_t, int);
static int acd_set_speed(struct acd_softc *, int, int);
static void acd_get_cap(struct acd_softc *);
static int acd_read_format_caps(struct acd_softc *, struct cdr_format_capacities *);
static int acd_format(struct acd_softc *, struct cdr_format_params *);
/* internal vars */
static u_int32_t acd_lun_map = 0;
@ -1029,6 +1031,14 @@ acdioctl(dev_t dev, u_long cmd, caddr_t addr, int flags, struct thread *td)
error = acd_send_cue(cdp, (struct cdr_cuesheet *)addr);
break;
case CDRIOCREADFORMATCAPS:
error = acd_read_format_caps(cdp, (struct cdr_format_capacities *)addr);
break;
case CDRIOCFORMAT:
error = acd_format(cdp, (struct cdr_format_params *)addr);
break;
case DVDIOCREPORTKEY:
if (!cdp->cap.read_dvdrom)
error = EINVAL;
@ -1184,7 +1194,7 @@ acd_start(struct ata_device *atadev)
ccb[9] = 0x10;
}
}
else
else
ccb[0] = ATAPI_WRITE_BIG;
ccb[1] = 0;
@ -1563,21 +1573,23 @@ acd_read_track_info(struct acd_softc *cdp,
static int
acd_get_progress(struct acd_softc *cdp, int *finished)
{
int8_t ccb[16] = { ATAPI_READ_CAPACITY, 0, 0, 0, 0, 0, 0, 0,
int8_t ccb[16] = { ATAPI_REQUEST_SENSE, 0, 0, 0,
sizeof(struct atapi_reqsense), 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0 };
struct atapi_reqsense *sense = cdp->device->result;
char tmp[8];
struct atapi_reqsense sense;
int error;
if (atapi_test_ready(cdp->device) != EBUSY) {
if (atapi_queue_cmd(cdp->device, ccb, tmp, sizeof(tmp),
ATPR_F_READ, 30, NULL, NULL) != EBUSY) {
error = atapi_queue_cmd(cdp->device, ccb,
(caddr_t)&sense, sizeof(struct atapi_reqsense),
ATPR_F_READ, 30, NULL, NULL);
if (error) {
if (error != EBUSY)
*finished = 100;
return 0;
}
return error;
}
if (sense->sksv)
*finished =
((sense->sk_specific2 | (sense->sk_specific1 << 8)) * 100) / 65535;
if (sense.sksv)
*finished = ((sense.sk_specific2|(sense.sk_specific1<<8))*100)/65535;
else
*finished = 0;
return 0;
@ -2000,3 +2012,29 @@ acd_get_cap(struct acd_softc *cdp)
cdp->cap.max_vol_levels = ntohs(cdp->cap.max_vol_levels);
cdp->cap.buf_size = ntohs(cdp->cap.buf_size);
}
static int
acd_read_format_caps(struct acd_softc *cdp, struct cdr_format_capacities *caps)
{
int8_t ccb[16] = { ATAPI_READ_FORMAT_CAPACITIES, 0, 0, 0, 0, 0, 0,
(sizeof(struct cdr_format_capacities) >> 8) & 0xff,
sizeof(struct cdr_format_capacities) & 0xff,
0, 0, 0, 0, 0, 0, 0 };
return atapi_queue_cmd(cdp->device, ccb, (caddr_t)caps,
sizeof(struct cdr_format_capacities),
ATPR_F_READ, 30, NULL, NULL);
}
static int
acd_format(struct acd_softc *cdp, struct cdr_format_params* params)
{
int error;
int8_t ccb[16] = { ATAPI_FORMAT, 0x11, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0 };
error = atapi_queue_cmd(cdp->device, ccb, (u_int8_t *)params,
sizeof(struct cdr_format_params), 0, 30, NULL,NULL);
return error;
}

View File

@ -299,7 +299,7 @@ struct write_param {
#define CDR_WTYPE_RAW 0x03
u_int8_t test_write :1; /* test write enable */
u_int8_t reserved2_5 :1;
u_int8_t link_size_valid :1;
u_int8_t burnproof :1; /* BurnProof enable */
u_int8_t reserved2_7 :1;
u_int8_t track_mode :4; /* track mode */
@ -319,7 +319,7 @@ struct write_param {
u_int8_t datablock_type :4; /* data type code (see cdrio.h) */
u_int8_t reserved4_4567 :4;
u_int8_t reserved5;
u_int8_t link_size;
u_int8_t reserved6;
u_int8_t host_app_code :6; /* host application code */
u_int8_t reserved7_67 :2;

View File

@ -85,6 +85,37 @@ struct cdr_cuesheet {
int test_write;
};
struct cdr_format_capacity {
u_int32_t blocks;
u_int32_t reserved:2;
u_int32_t type:6;
u_int32_t param:24;
};
struct cdr_format_capacities {
u_int8_t reserved1[3];
u_int8_t length;
u_int32_t blocks;
u_int32_t type:2;
u_int32_t reserved2:6;
u_int32_t block_size:24;
struct cdr_format_capacity format[32];
};
struct cdr_format_params {
u_int8_t reserved;
u_int8_t vs:1;
u_int8_t immed:1;
u_int8_t try_out:1;
u_int8_t ip:1;
u_int8_t stpf:1;
u_int8_t dcrt:1;
u_int8_t dpry:1;
u_int8_t fov:1;
u_int16_t length;
struct cdr_format_capacity format;
};
#define CDRIOCBLANK _IOW('c', 100, int)
#define CDR_B_ALL 0x0
#define CDR_B_MIN 0x1
@ -101,5 +132,7 @@ struct cdr_cuesheet {
#define CDRIOCGETBLOCKSIZE _IOR('c', 109, int)
#define CDRIOCSETBLOCKSIZE _IOW('c', 110, int)
#define CDRIOCGETPROGRESS _IOR('c', 111, int)
#define CDRIOCREADFORMATCAPS _IOR('c', 112, struct cdr_format_capacities)
#define CDRIOCFORMAT _IOW('c', 113, struct cdr_format_params)
#endif /* !_SYS_CDRIO_H_ */

View File

@ -54,6 +54,8 @@ burn the CD-R/RW in DAO (disk at once) mode.
eject the media when done.
.It Fl f Ar device
set the device to use for the burning process.
.It Fl F
force operation regardless of warnings.
.It Fl l
read a list of image files from filename.
.It Fl m
@ -91,6 +93,10 @@ only those areas that make the media appear blank for further usage are erased.
Erase a CD-RW medium.
This erases the entire media.
Can take up to 1 hour to finish.
.It Cm format dwd+rw
Formats a DVD+RW media to the default max size and 2048byte blocks. This
operation can take a long time to finish. Progress reporting is done
during the process.
.It Cm fixate
Fixate the medium so that the TOC is generated and the media can be used
in an ordinary CD drive.
@ -129,6 +135,9 @@ and
.Dq "no gaps"
.Pq Fl n
modes.
.It Cm dvdrw
Set the write mode to write a DVD+RW from the follwing image. DVD's only
have one track.
.It Ar file
All other arguments are treated as filenames of images to write to the media,
or in case the

View File

@ -40,6 +40,7 @@
#include <sys/stat.h>
#include <sys/cdio.h>
#include <sys/cdrio.h>
#include <sys/dvdio.h>
#include <sys/param.h>
#include <arpa/inet.h>
@ -48,7 +49,7 @@
struct track_info {
int file;
char *file_name;
u_int file_size;
off_t file_size;
int block_size;
int block_type;
int pregap;
@ -59,7 +60,8 @@ static int fd, quiet, verbose, saved_block_size, notracks;
void add_track(char *, int, int, int);
void do_DAO(int, int);
void do_TAO(int, int);
void do_TAO(int, int, int);
void do_format(int, int, char *);
int write_file(struct track_info *);
int roundup_blocks(struct track_info *);
void cue_ent(struct cdr_cue_entry *, int, int, int, int, int, int, int);
@ -71,11 +73,11 @@ main(int argc, char **argv)
{
int ch, arg, addr;
int dao = 0, eject = 0, fixate = 0, list = 0, multi = 0, preemp = 0;
int nogap = 0, speed = 4, test_write = 0;
int block_size = 0, block_type = 0, cdopen = 0;
int nogap = 0, speed = 4, test_write = 0, force = 0;
int block_size = 0, block_type = 0, cdopen = 0, dvdrw = 0;
const char *dev = "/dev/acd0c";
while ((ch = getopt(argc, argv, "def:lmnpqs:tv")) != -1) {
while ((ch = getopt(argc, argv, "def:Flmnpqs:tv")) != -1) {
switch (ch) {
case 'd':
dao = 1;
@ -88,6 +90,10 @@ main(int argc, char **argv)
case 'f':
dev = optarg;
break;
case 'F':
force = 1;
break;
case 'l':
list = 1;
@ -167,8 +173,9 @@ main(int argc, char **argv)
break;
}
if (!strcasecmp(argv[arg], "erase") || !strcasecmp(argv[arg], "blank")){
int error, blank, percent;
if ((!strcasecmp(argv[arg], "erase") ||
!strcasecmp(argv[arg], "blank")) && !test_write) {
int error, blank, percent, last = 0;
if (!strcasecmp(argv[arg], "erase"))
blank = CDR_B_ALL;
@ -188,13 +195,25 @@ main(int argc, char **argv)
"%sing CD - %d %% done \r",
blank == CDR_B_ALL ?
"eras" : "blank", percent);
if (error || percent == 100)
if (error || percent == 100 ||
(percent == 0 && last == 99))
break;
last = percent;
}
if (!quiet)
printf("\n");
continue;
}
if (!strcasecmp(argv[arg], "format") && !test_write) {
if (arg + 1 < argc &&
(!strcasecmp(argv[arg + 1], "dvd+rw") ||
!strcasecmp(argv[arg + 1], "dvd-rw")))
do_format(fd, force, argv[arg + 1]);
else
err(EX_NOINPUT, "format media type invalid");
arg++;
continue;
}
if (!strcasecmp(argv[arg], "audio") || !strcasecmp(argv[arg], "raw")) {
block_type = CDR_DB_RAW;
block_size = 2352;
@ -227,6 +246,13 @@ main(int argc, char **argv)
nogap = 1;
continue;
}
if (!strcasecmp(argv[arg], "dvdrw")) {
block_type = CDR_DB_ROM_MODE1;
block_size = 2048;
dvdrw = 1;
continue;
}
if (!block_size)
err(EX_NOINPUT, "no data format selected");
if (list) {
@ -252,6 +278,8 @@ main(int argc, char **argv)
add_track(argv[arg], block_size, block_type, nogap);
}
if (notracks) {
if (dvdrw && notracks > 1)
err(EX_USAGE, "DVD's only have 1 track");
if (ioctl(fd, CDIOCSTART, 0) < 0)
err(EX_IOERR, "ioctl(CDIOCSTART)");
if (!cdopen) {
@ -262,7 +290,7 @@ main(int argc, char **argv)
if (dao)
do_DAO(test_write, multi);
else
do_TAO(test_write, preemp);
do_TAO(test_write, preemp, dvdrw);
}
if (fixate && !dao) {
if (!quiet)
@ -436,7 +464,7 @@ do_DAO(int test_write, int multi)
}
void
do_TAO(int test_write, int preemp)
do_TAO(int test_write, int preemp, int dvdrw)
{
struct cdr_track track;
int i;
@ -448,8 +476,13 @@ do_TAO(int test_write, int preemp)
if (ioctl(fd, CDRIOCINITTRACK, &track) < 0)
err(EX_IOERR, "ioctl(CDRIOCINITTRACK)");
if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR, &tracks[i].addr) < 0)
err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)");
if (dvdrw)
tracks[i].addr = 0;
else
if (ioctl(fd, CDRIOCNEXTWRITEABLEADDR,
&tracks[i].addr) < 0)
err(EX_IOERR, "ioctl(CDRIOCNEXTWRITEABLEADDR)");
if (!quiet)
fprintf(stderr, "next writeable LBA %d\n",
tracks[i].addr);
@ -460,12 +493,91 @@ do_TAO(int test_write, int preemp)
}
}
#define NTOH3B(x) ((x&0x0000ff)<<16) | (x&0x00ff00) | ((x&0xff0000)>>16)
void
do_format(int fd, int force, char *type)
{
struct cdr_format_capacities capacities;
struct cdr_format_params format_params;
int count, i, percent, last = 0;
if (ioctl(fd, CDRIOCREADFORMATCAPS, &capacities) == -1)
err(EX_IOERR, "ioctl(CDRIOCREADFORMATCAPS)");
if (verbose) {
fprintf(stderr, "format list entries=%d\n",
capacities.length / sizeof(struct cdr_format_capacity));
fprintf(stderr, "current format: blocks=%u type=0x%x block_size=%u\n",
ntohl(capacities.blocks), capacities.type,
NTOH3B(capacities.block_size));
}
count = capacities.length / sizeof(struct cdr_format_capacity);
if (verbose) {
for (i = 0; i < count; ++i)
fprintf(stderr,
"format %d: blocks=%u type=0x%x param=%u\n",
i, ntohl(capacities.format[i].blocks),
capacities.format[i].type,
NTOH3B(capacities.format[i].param));
}
for (i = 0; i < count; ++i) {
if (!strcasecmp(type, "dvd+rw")) {
if (capacities.format[i].type == 0x26) {
break;
}
}
if (!strcasecmp(type, "dvd-rw")) {
if (capacities.format[i].type == 0x0) {
break;
}
}
}
if (i == count)
err(EX_IOERR, "could not find a valid format capacity");
if (!quiet)
fprintf(stderr,"formatting with blocks=%u type=0x%x param=%u\n",
ntohl(capacities.format[i].blocks),
capacities.format[i].type,
NTOH3B(capacities.format[i].param));
if (!force && capacities.type == 2)
err(EX_IOERR, "media already formatted (use -F to override)");
memset(&format_params, 0, sizeof(struct cdr_format_params));
format_params.fov = 1;
format_params.immed = 1;
format_params.length = ntohs(sizeof(struct cdr_format_capacity));
memcpy(&format_params.format, &capacities.format[i],
sizeof(struct cdr_format_capacity));
if(ioctl(fd, CDRIOCFORMAT, &format_params) == -1)
err(EX_IOERR, "ioctl(CDRIOCFORMAT)");
while (1) {
sleep(1);
if (ioctl(fd, CDRIOCGETPROGRESS, &percent) == -1)
err(EX_IOERR, "ioctl(CDRIOGETPROGRESS)");
if (percent > 0 && !quiet)
fprintf(stderr, "formatting DVD - %d %% done \r",
percent);
if (percent == 100 || (percent == 0 && last == 99))
break;
last = percent;
}
if (!quiet)
fprintf(stderr, "\n");
}
int
write_file(struct track_info *track_info)
{
int size, count, filesize;
off_t size, count, filesize;
char buf[2352*BLOCKS];
static int tot_size = 0;
static off_t tot_size = 0;
filesize = track_info->file_size / 1024;
@ -476,7 +588,7 @@ write_file(struct track_info *track_info)
lseek(fd, track_info->addr * track_info->block_size, SEEK_SET);
if (verbose)
fprintf(stderr, "addr = %d size = %d blocks = %d\n",
fprintf(stderr, "addr = %d size = %qd blocks = %d\n",
track_info->addr, track_info->file_size,
roundup_blocks(track_info));
@ -485,7 +597,7 @@ write_file(struct track_info *track_info)
fprintf(stderr, "writing from stdin\n");
else
fprintf(stderr,
"writing from file %s size %d KB\n",
"writing from file %s size %qd KB\n",
track_info->file_name, filesize);
}
size = 0;
@ -503,7 +615,7 @@ write_file(struct track_info *track_info)
track_info->block_size;
}
if ((res = write(fd, buf, count)) != count) {
fprintf(stderr, "\nonly wrote %d of %d bytes err=%d\n",
fprintf(stderr, "\nonly wrote %d of %qd bytes err=%d\n",
res, count, errno);
break;
}
@ -512,12 +624,12 @@ write_file(struct track_info *track_info)
if (!quiet) {
int pct;
fprintf(stderr, "written this track %d KB", size/1024);
fprintf(stderr, "written this track %qd KB", size/1024);
if (track_info->file != STDIN_FILENO && filesize) {
pct = (size / 1024) * 100 / filesize;
fprintf(stderr, " (%d%%)", pct);
}
fprintf(stderr, " total %d KB\r", tot_size/1024);
fprintf(stderr, " total %qd KB\r", tot_size/1024);
}
if (size >= track_info->file_size)
break;