From 2799fe1b44a97301b3fc87a29323cc731db1964f Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Tue, 6 Feb 2007 13:06:39 +0000 Subject: [PATCH] Implemented DVD-R[W] DAO as BURN_WRITE_SAO --- cdrskin/cdrskin_timestamp.h | 2 +- libburn/drive.c | 10 ++++ libburn/libburn.h | 31 +++++++++---- libburn/libdax_msgs.h | 6 +++ libburn/mmc.c | 53 ++++++++++++++++----- libburn/write.c | 91 +++++++++++++++++++++++++++++-------- 6 files changed, 151 insertions(+), 42 deletions(-) diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index 60a004a..41b7fdc 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2007.02.05.132335" +#define Cdrskin_timestamP "2007.02.06.130410" diff --git a/libburn/drive.c b/libburn/drive.c index 1b39e2a..e776886 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -1590,6 +1590,8 @@ int burn_disc_get_multi_caps(struct burn_drive *d, enum burn_write_types wt, } else if (s == BURN_DISC_APPENDABLE && (wt == BURN_WRITE_SAO || wt == BURN_WRITE_RAW)) { return 0; + } else if (wt == BURN_WRITE_RAW && !d->current_is_cd_profile) { + return 0; } else if (d->current_profile == 0x09 || d->current_profile == 0x0a) { /* CD-R , CD-RW */ if (d->block_types[BURN_WRITE_TAO]) { @@ -1609,13 +1611,21 @@ int burn_disc_get_multi_caps(struct burn_drive *d, enum burn_write_types wt, if (o->advised_write_mode == BURN_WRITE_NONE) o->advised_write_mode = BURN_WRITE_RAW; } + if (wt == BURN_WRITE_RAW) + o->multi_session = o->multi_track = 0; } else if (d->current_profile == 0x11 || d->current_profile == 0x14) { /* DVD-R , sequential DVD-RW */ + if (s == BURN_DISC_BLANK) { + o->might_do_sao = 1; + o->advised_write_mode = BURN_WRITE_SAO; + } if (d->current_has_feat21h) { o->multi_session = o->multi_track = 1; o->might_do_tao = 2; o->advised_write_mode = BURN_WRITE_TAO; } + if (wt == BURN_WRITE_SAO) + o->multi_session = o->multi_track = 0; } else if (d->current_profile == 0x12 || d->current_profile == 0x13 || d->current_profile == 0x1a) { /* DVD-RAM, overwriteable DVD-RW, DVD+RW */ diff --git a/libburn/libburn.h b/libburn/libburn.h index 2517f5a..fdeef0e 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -107,24 +107,31 @@ struct burn_write_opts; enum burn_write_types { /** Packet writing. - currently unsupported + currently unsupported, (for DVD Incremental Streaming use TAO) */ BURN_WRITE_PACKET, - /** Track At Once recording. - 2s gaps between tracks, no fonky lead-ins + /** With CD: Track At Once recording + 2s gaps between tracks, no fonky lead-ins + + With sequential DVD-R[W]: Incremental Streaming + With DVD-RAM/+RW: Random Writeable (used sequentially) + With overwriteable DVD-RW: Rigid Restricted Overwrite */ BURN_WRITE_TAO, - /** Session At Once. - Block type MUST be BURN_BLOCK_SAO - ts A70122 : Currently not capable of mixing data and audio tracks. + /** With CD: Session At Once + Block type MUST be BURN_BLOCK_SAO + ts A70122: Currently not capable of mixing data and audio tracks. + + With sequential DVD-R[W]: Disc-at-once, DAO + Single session, single track, fixed size mandatory, (-dvd-compat) */ BURN_WRITE_SAO, - /** Raw disc at once recording. - all subcodes must be provided by lib or user - only raw block types are supported + /** With CD: Raw disc at once recording. + all subcodes must be provided by lib or user + only raw block types are supported */ BURN_WRITE_RAW, @@ -1385,6 +1392,10 @@ struct burn_multi_caps { writing a session. It also guarantees that the drive will be able to predict and use the appropriate Next Writeable Address to place the next session on the media without overwriting the existing ones. + It does not guarantee that the selected write type is able to do + an appending session after the next session. (E.g. CD SAO is capable + of multi-session by keeping a disc appendable. But .might_do_sao + will be 0 afterwards, when checking the appendable media.) 1= media may be kept appendable by burn_write_opts_set_multi(o,1) 0= media will not be apendable appendable */ @@ -1447,7 +1458,7 @@ struct burn_multi_caps { via burn_disc_free_multi_caps() when no longer needed. @param d The drive to inquire @param wt With BURN_WRITE_NONE the best capabilities of all write modes - get returned. If set to a write mode like BURN_WRITE_TAO the + get returned. If set to a write mode like BURN_WRITE_SAO the capabilities with that particular mode are returned. @param caps returns the info structure @param flag Bitfield for control purposes (unused yet, submit 0) diff --git a/libburn/libdax_msgs.h b/libburn/libdax_msgs.h index 382be62..72d3a3f 100644 --- a/libburn/libdax_msgs.h +++ b/libburn/libdax_msgs.h @@ -352,6 +352,12 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff 0x00020131 (SORRY,HIGH) = No suitable formatting type offered by drive 0x00020132 (SORRY,HIGH) = Selected format is not suitable for libburn 0x00020133 (SORRY,HIGH) = Cannot mix data and audio in SAO mode + 0x00020134 (NOTE,HIGH) = Defaulted TAO to DAO + 0x00020135 (SORRY,HIGH) = Cannot perform TAO, job unsuitable for DAO + 0x00020136 (SORRY,HIGH) = DAO Burning restricted to single fixed size track + 0x00020137 (HINT,HIGH) = TAO would be possible + 0x00020138 (FATAL,HIGH) = Cannot reserve track + libdax_audioxtr: 0x00020200 (SORRY,HIGH) = Cannot open audio source file diff --git a/libburn/mmc.c b/libburn/mmc.c index ab2ff4b..2a40eb8 100644 --- a/libburn/mmc.c +++ b/libburn/mmc.c @@ -208,20 +208,27 @@ int mmc_reserve_track(struct burn_drive *d, off_t size) { struct command c; int lba; + char msg[80]; mmc_function_spy("mmc_reserve_track"); c.retry = 1; c.oplen = sizeof(MMC_RESERVE_TRACK); memcpy(c.opcode, MMC_RESERVE_TRACK, sizeof(MMC_RESERVE_TRACK)); - /* Nice rounding trick learned from dvd+rw-tools */ + /* Round to 32 KiB and divide by 2048 + (by nice binary rounding trick learned from dvd+rw-tools) */ lba = ((size + (off_t) 0x7fff) >> 11) & ~0xf; mmc_int_to_four_char(c.opcode+5, lba); + sprintf(msg, "reserving track of %d blocks", lba); + libdax_msgs_submit(libdax_messenger, -1, 0x00000002, + LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, + msg, 0, 0); + c.page = NULL; c.dir = NO_TRANSFER; d->issue_command(d, &c); - return !!c.error; + return !c.error; } @@ -1521,6 +1528,10 @@ void mmc_get_configuration(struct burn_drive *d) if (cp == 0x12) d->current_is_supported_profile = 1; #endif +#ifdef Libburn_support_dvd_r_seQ + if (cp == 0x11 || cp == 0x14) + d->current_is_supported_profile = 1; +#endif /* Enable this to get loud and repeated reports about the feature set : #define Libburn_print_feature_descriptorS 1 @@ -1645,11 +1656,6 @@ void mmc_get_configuration(struct burn_drive *d) } } -#ifdef Libburn_support_dvd_r_seQ - /* might get adjusted later by mmc_read_disc_info() */ - if ((cp == 0x11 || cp == 0x14) && d->current_has_feat21h) - d->current_is_supported_profile = 1; -#endif } @@ -1778,6 +1784,11 @@ void mmc_sync_cache(struct burn_drive *d) c.oplen = sizeof(MMC_SYNC_CACHE); c.page = NULL; c.dir = NO_TRANSFER; + + libdax_msgs_submit(libdax_messenger, -1, 0x00000002, + LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, + "\nsyncing cache", 0, 0); + d->issue_command(d, &c); } @@ -2232,8 +2243,8 @@ int mmc_compose_mode_page_5(struct burn_drive *d, pd[0] = 5; pd[1] = d->mdata->write_page_length; - /* ts A61229 */ - if (d->current_profile == 0x13) { /* DVD-RW restricted overwrite */ + if (d->current_profile == 0x13) { + /* A61229 : DVD-RW restricted overwrite */ /* learned from transport.hxx : page05_setup() and mmc3r10g.pdf table 347 */ /* BUFE (burnproof), no LS_V (i.e. default Link Size, i hope), @@ -2247,11 +2258,28 @@ int mmc_compose_mode_page_5(struct burn_drive *d, pd[5] = 0; } else if ((d->current_profile == 0x14 || d->current_profile == 0x11) - && d->current_has_feat21h == 1) { /* ts A70128 */ - /* learned from transport.hxx : page05_setup() + && o->write_type == BURN_WRITE_SAO) { + /* ts A70205 : DVD-R[W} : Disc-at-once, DAO */ + /* Learned from dvd+rw-tools and mmc5r03c.pdf . + See doc/cookbook.txt for more detailed references. */ + + /* BUFE , LS_V = 0, Test Write, Write Type = 2 SAO (DAO) */ + pd[2] = ((!!o->underrun_proof) << 6) + | ((!!o->simulate) << 4) + | 2; + /* No multi-session , FP = 0 , Track Mode = 5 */ + pd[3] = 5; + /* Data Block Type = 8 */ + pd[4] = 8; + + } else if (d->current_profile == 0x14 || d->current_profile == 0x11) { + /* ts A70128 : DVD-R[W] Incremental Streaming */ + /* Learned from transport.hxx : page05_setup() and mmc5r03c.pdf 7.5, 4.2.3.4 Table 17 and spc3r23.pdf 6.8, 7.4.3 */ - /* BUFE , LS_V = 1, Test Write, Write Type = 00h Incremental */ + + /* BUFE , LS_V = 1, Test Write, + Write Type = 0 Packet/Incremental */ pd[2] = ((!!o->underrun_proof) << 6) | (1 << 5) | ((!!o->simulate) << 4); @@ -2279,6 +2307,7 @@ int mmc_compose_mode_page_5(struct burn_drive *d, } else { /* Traditional setup for CD */ + pd[2] = ((!!o->underrun_proof) << 6) | ((!!o->simulate) << 4) | (o->write_type & 0x0f); diff --git a/libburn/write.c b/libburn/write.c index f792da5..160a563 100644 --- a/libburn/write.c +++ b/libburn/write.c @@ -869,22 +869,40 @@ int burn_disc_init_write_status(struct burn_write_opts *o, /* ts A70129 : learned much from dvd+rw-tools-7.0/growisofs_mmc.cpp */ -int burn_disc_open_track_dvd_minus_r(struct burn_write_opts *o, int tnum) +int burn_disc_open_track_dvd_minus_r(struct burn_write_opts *o, + struct burn_session *s, int tnum) { struct burn_drive *d = o->drive; char msg[160]; int ret, lba, nwa; + off_t size; d->send_write_parameters(d, o); ret = d->get_nwa(d, -1, &lba, &nwa); sprintf(msg, "DVD pre-track %2.2d : get_nwa(%d), ret= %d , d->nwa= %d\n", tnum+1, nwa, ret, d->nwa); - libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002, - LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, - msg,0,0); + libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002, + LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, msg,0,0); if (nwa > d->nwa) d->nwa = nwa; + + if (o->write_type == BURN_WRITE_SAO) { /* DAO */ + /* Round track size up to 32 KiB and reserve track */ + size = ((off_t) burn_track_get_sectors(s->track[tnum])) + * (off_t) 2048; + size = (size + (off_t) 0x7fff) & ~((off_t) 0x7fff); + ret = d->reserve_track(d, size); + if (ret <= 0) { + sprintf(msg, "Cannot reserve track of %.f bytes", + (double) size); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020138, + LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, + msg, 0,0); + return 0; + } + } return 1; } @@ -896,8 +914,8 @@ int burn_disc_close_track_dvd_minus_r(struct burn_write_opts *o, struct burn_drive *d = o->drive; char msg[80]; - /* only DVD-R or sequential DVD-RW */ - if (d->current_has_feat21h != 1) /* only with Incremental writing */ + /* only with Incremental writing */ + if (o->write_type != BURN_WRITE_TAO) return 2; sprintf(msg, "Closing track %2.2d (absolute track number %d)", @@ -929,7 +947,7 @@ int burn_dvd_write_track(struct burn_write_opts *o, if (d->current_profile == 0x11 || d->current_profile == 0x14) { /* DVD-R, DVD-RW Sequential */ - ret = burn_disc_open_track_dvd_minus_r(o, tnum); + ret = burn_disc_open_track_dvd_minus_r(o, s, tnum); if (ret <= 0) goto ex; } @@ -1026,8 +1044,9 @@ int burn_disc_close_session_dvd_minus_r(struct burn_write_opts *o, { struct burn_drive *d = o->drive; - if (d->current_has_feat21h != 1) - return 2; /* only for Incremental writing */ + /* only for Incremental writing */ + if (o->write_type != BURN_WRITE_TAO) + return 2; libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119, LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, @@ -1047,7 +1066,7 @@ int burn_dvd_write_session(struct burn_write_opts *o, int i,ret; struct burn_drive *d = o->drive; - /* >>> open_session ? (maybe with DAO) */ + /* >>> open_session ? */ for (i = 0; i < s->tracks; i++) { ret = burn_dvd_write_track(o, s, i); @@ -1189,11 +1208,7 @@ int burn_disc_setup_dvd_minus_r(struct burn_write_opts *o, { struct burn_drive *d = o->drive; - if (d->current_has_feat21h) { - /* most setup is in burn_disc_setup_track_dvd_minus_r() */; - } else { - return 0; /* >>> no DAO for now */ - } + /* most setup is in burn_disc_setup_track_dvd_minus_r() */; d->nwa = 0; return 1; @@ -1204,7 +1219,7 @@ int burn_disc_setup_dvd_minus_r(struct burn_write_opts *o, int burn_dvd_write_sync(struct burn_write_opts *o, struct burn_disc *disc) { - int i, ret, sx, tx, mode, exotic_track = 0; + int i, ret, sx, tx, mode, exotic_track = 0, dao_is_ok; struct burn_drive *d = o->drive; char msg[160]; @@ -1289,9 +1304,47 @@ int burn_dvd_write_sync(struct burn_write_opts *o, /* _Rigid_ Restricted Overwrite demands this */ o->obs_pad = 1; /* fill-up track's last 32k buffer */ - } else if ((d->current_profile == 0x11 || d->current_profile == 0x14) - && d->current_has_feat21h == 1) { - /* DVD-R , DVD-RW Sequential (for now only Incremental) */ + } else if (d->current_profile == 0x11 || d->current_profile == 0x14) { + /* DVD-R , DVD-RW Sequential */ + dao_is_ok = + (disc->sessions == 1 && + disc->session[0]->tracks == 1 && + (! burn_track_is_open_ended( + disc->session[0]->track[0])) && + (!o->multi) && d->status == BURN_DISC_BLANK + ); + if (o->write_type == BURN_WRITE_TAO && + !d->current_has_feat21h) { + if (dao_is_ok) { + o->write_type = BURN_WRITE_SAO; + libdax_msgs_submit(libdax_messenger, + d->global_index, 0x00020134, + LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, + "Defaulted TAO to DAO (lack of feature 21h)", + 0, 0); + } else { + libdax_msgs_submit(libdax_messenger, + d->global_index, 0x00020135, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "Cannot perform TAO (lack of feature 21h), job unsuitable for DAO", + 0, 0); + goto early_failure; + } + } else if (o->write_type == BURN_WRITE_SAO && !dao_is_ok) { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020136, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "DAO burning is restricted to a single fixed size track and no multi-session", + 0,0); + if (d->current_has_feat21h) + libdax_msgs_submit(libdax_messenger, + d->global_index, 0x00020137, + LIBDAX_MSGS_SEV_HINT, + LIBDAX_MSGS_PRIO_HIGH, + "TAO would be possible and could do the job", + 0,0); + goto early_failure; + } if (o->start_byte >= 0) { sprintf(msg, "Write start address not supported"); libdax_msgs_submit(libdax_messenger, d->global_index,