diff options
author | sos <sos@FreeBSD.org> | 2002-08-08 07:59:24 +0000 |
---|---|---|
committer | sos <sos@FreeBSD.org> | 2002-08-08 07:59:24 +0000 |
commit | 12355fce849b88ec85106092c90e813493705508 (patch) | |
tree | 020fde6a5b99212c341268e55e3b6576b1a95553 | |
parent | 77f180ef672e189c01b122b1bea1a933f7f8002b (diff) | |
download | FreeBSD-src-12355fce849b88ec85106092c90e813493705508.zip FreeBSD-src-12355fce849b88ec85106092c90e813493705508.tar.gz |
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!
-rw-r--r-- | sys/dev/ata/atapi-cd.c | 62 | ||||
-rw-r--r-- | sys/dev/ata/atapi-cd.h | 4 | ||||
-rw-r--r-- | sys/sys/cdrio.h | 33 | ||||
-rw-r--r-- | usr.sbin/burncd/burncd.8 | 9 | ||||
-rw-r--r-- | usr.sbin/burncd/burncd.c | 150 |
5 files changed, 225 insertions, 33 deletions
diff --git a/sys/dev/ata/atapi-cd.c b/sys/dev/ata/atapi-cd.c index 333305d..c209065 100644 --- a/sys/dev/ata/atapi-cd.c +++ b/sys/dev/ata/atapi-cd.c @@ -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; + + error = atapi_queue_cmd(cdp->device, ccb, + (caddr_t)&sense, sizeof(struct atapi_reqsense), + ATPR_F_READ, 30, NULL, NULL); - if (atapi_test_ready(cdp->device) != EBUSY) { - if (atapi_queue_cmd(cdp->device, ccb, tmp, sizeof(tmp), - ATPR_F_READ, 30, NULL, NULL) != EBUSY) { + 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; +} diff --git a/sys/dev/ata/atapi-cd.h b/sys/dev/ata/atapi-cd.h index 038c4f0..cdd5dc8 100644 --- a/sys/dev/ata/atapi-cd.h +++ b/sys/dev/ata/atapi-cd.h @@ -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; diff --git a/sys/sys/cdrio.h b/sys/sys/cdrio.h index da01d7e..77cb1be 100644 --- a/sys/sys/cdrio.h +++ b/sys/sys/cdrio.h @@ -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_ */ diff --git a/usr.sbin/burncd/burncd.8 b/usr.sbin/burncd/burncd.8 index c1c0bef..47dc84f 100644 --- a/usr.sbin/burncd/burncd.8 +++ b/usr.sbin/burncd/burncd.8 @@ -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 diff --git a/usr.sbin/burncd/burncd.c b/usr.sbin/burncd/burncd.c index 31e7d51..1d3d2fd 100644 --- a/usr.sbin/burncd/burncd.c +++ b/usr.sbin/burncd/burncd.c @@ -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; |