diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index f280373..6a40854 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2007.01.26.173236" +#define Cdrskin_timestamP "2007.01.29.175822" diff --git a/libburn/drive.c b/libburn/drive.c index 68e81c4..531d983 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -347,6 +347,9 @@ int burn_drive_mark_unready(struct burn_drive *d) /* ts A61202 */ d->current_profile = -1; + d->current_has_feat21h = 0; + d->current_feat2fh_byte4 = -1; + d->status = BURN_DISC_UNREADY; if (d->toc_entry != NULL) free(d->toc_entry); diff --git a/libburn/mmc.c b/libburn/mmc.c index dc88108..d21e659 100644 --- a/libburn/mmc.c +++ b/libburn/mmc.c @@ -44,6 +44,11 @@ extern struct libdax_msgs *libdax_messenger; #define Libburn_support_dvd_raM 1 +/* ts A70129 >>> EXPERIMENTAL +#define Libburn_support_dvd_r_seQ 1 +*/ + + /* Progress report (with Libburn_support_dvd_plus_rW defined): ts A61219 : It seems to work with a used (i.e. thoroughly formatted) DVD+RW. Error messages of class DEBUG appear because of inability to @@ -590,6 +595,7 @@ void mmc_read_disc_info(struct burn_drive *d) */ d->status = BURN_DISC_BLANK; + d->last_track_no = 0; break; case 1: d->status = BURN_DISC_APPENDABLE; @@ -613,6 +619,14 @@ void mmc_read_disc_info(struct burn_drive *d) */ d->bg_format_status = data[7] & 3; + if (d->status == BURN_DISC_BLANK) + d->last_track_no = 1; /* The "incomplete track" */ + else + /* ts A70129 : mmc5r03c.pdf 6.22.3.1.7 + This includes the "incomplete track" if the disk is + appendable. I.e number of complete tracks + 1. */ + d->last_track_no = (data[11] << 8) | data[6]; + /* Preliminarily declare blank: ts A61219 : DVD+RW (is not bg_format_status==0 "blank") ts A61229 : same for DVD-RW Restricted overwrite @@ -1066,13 +1080,17 @@ static char *mmc_obtain_profile_name(int profile_number) void mmc_get_configuration(struct burn_drive *d) { struct buffer buf; - int len, cp; + int len, cp, descr_len = 0, feature_code, prf_number, only_current = 1; + unsigned char *descr, *prf, *up_to, *prf_end; struct command c; d->current_profile = 0; d->current_profile_text[0] = 0; d->current_is_cd_profile = 0; d->current_is_supported_profile = 0; + d->current_has_feat21h = 0; + d->current_feat21h_link_size = -1; + d->current_feat2fh_byte4 = -1; mmc_function_spy("mmc_get_configuration"); memcpy(c.opcode, MMC_GET_CONFIGURATION, sizeof(MMC_GET_CONFIGURATION)); @@ -1087,9 +1105,9 @@ void mmc_get_configuration(struct burn_drive *d) if (c.error) return; len = (c.page->data[0] << 24) - + (c.page->data[1] << 16) - + (c.page->data[2] << 8) - + c.page->data[3]; + | (c.page->data[1] << 16) + | (c.page->data[2] << 8) + | c.page->data[3]; if (len<8) return; @@ -1112,10 +1130,133 @@ void mmc_get_configuration(struct burn_drive *d) d->current_is_supported_profile = 1; #endif - /* >>> see mmc5r03c.pdf 5.2 - Interpret list of profile and feature descriptors. +/* Enable this to get loud and repeated reports about the feature set : +#define Libburn_print_feature_descriptorS 1 +*/ + /* ts A70127 : Interpret list of profile and feature descriptors. + see mmc5r03c.pdf 5.2 + >>> Ouch: What to do if list is larger than buffer size. + Specs state that the call has to be repeated. */ + up_to = c.page->data + (len < BUFFER_SIZE ? len : BUFFER_SIZE); +#ifdef Libburn_print_feature_descriptorS + fprintf(stderr, + "-----------------------------------------------------------------\n"); + fprintf(stderr, + "LIBBURN_EXPERIMENTAL : feature list length = %d , shown = %d\n", + len, up_to - c.page->data); +#endif /* Libburn_print_feature_descriptorS */ + + for (descr = c.page->data + 8; descr + 3 < up_to; descr += descr_len) { + descr_len = 4 + descr[3]; + feature_code = (descr[0] << 8) | descr[1]; + if (only_current && !(descr[2] & 1)) + continue; + +#ifdef Libburn_print_feature_descriptorS + fprintf(stderr, + "LIBBURN_EXPERIMENTAL : %s feature %4.4Xh\n", + descr[2] & 1 ? "+" : "-", + feature_code); +#endif /* Libburn_print_feature_descriptorS */ + + if (feature_code == 0x0) { + prf_end = descr + 4 + descr[3]; + for (prf = descr + 4; prf + 2 < prf_end; prf += 4) { + if (only_current && !(prf[2] & 1)) + continue; + prf_number = (prf[0] << 8) | prf[1]; + +#ifdef Libburn_print_feature_descriptorS + fprintf(stderr, + "LIBBURN_EXPERIMENTAL : %s profile %4.4Xh \"%s\"\n", + prf[2] & 1 ? "+" : "-", + prf_number, + mmc_obtain_profile_name(prf_number)); +#endif /* Libburn_print_feature_descriptorS */ + + } + + } else if (feature_code == 0x21) { + int i; + + d->current_has_feat21h = (descr[2] & 1); + for (i = 0; i < descr[7]; i++) { + if (i == 0 || descr[8 + i] == 16) + d->current_feat21h_link_size = + descr[8 + i]; + +#ifdef Libburn_print_feature_descriptorS + fprintf(stderr, + "LIBBURN_EXPERIMENTAL : + Link Size = %d\n", + descr[8 + i]); +#endif /* Libburn_print_feature_descriptorS */ + + } + + } else if (feature_code == 0x2F) { + if (descr[2] & 1) + d->current_feat2fh_byte4 = descr[4]; + +#ifdef Libburn_print_feature_descriptorS + fprintf(stderr, "LIBBURN_EXPERIMENTAL : BUF = %d , Test Write = %d , DVD-RW = %d\n", + !!(descr[4] & 64), !!(descr[4] & 4), + !!(descr[4] & 2)); +#endif /* Libburn_print_feature_descriptorS */ + +#ifdef Libburn_print_feature_descriptorS + } else if (feature_code == 0x01) { + int pys_if_std = 0; + char *phys_name = ""; + + pys_if_std = (descr[4] << 24) | (descr[5] << 16) | + (descr[6] << 8) | descr[9]; + if (pys_if_std == 1) + phys_name = "SCSI Family"; + else if(pys_if_std == 2) + phys_name = "ATAPI"; + else if(pys_if_std == 3 || pys_if_std == 4 || + pys_if_std == 6) + phys_name = "IEEE 1394 FireWire"; + else if(pys_if_std == 7) + phys_name = "Serial ATAPI"; + else if(pys_if_std == 7) + phys_name = "USB"; + + fprintf(stderr, + "LIBBURN_EXPERIMENTAL : Phys. Interface Standard %Xh \"%s\"\n", + pys_if_std, phys_name); + + } else if (feature_code == 0x107) { + + fprintf(stderr, "LIBBURN_EXPERIMENTAL : CD SPEED = %d , page 2Ah = %d , SET STREAMING = %d\n", + !!(descr[4] & 8), !!(descr[4] & 4), + !!(descr[4] & 2)); + + } else if (feature_code == 0x108 || feature_code == 0x10c) { + int i, c_limit; + + fprintf(stderr, "LIBBURN_EXPERIMENTAL : %s = ", + feature_code == 0x108 ? + "Drive Serial Number" : "Drive Firmware Date"); + c_limit = descr[3] - 2 * (feature_code == 0x10c); + for (i = 0; i < c_limit; i++) + if (descr[4 + i] < 0x20 || descr[4 + i] > 0x7e + || descr[4 + i] == '\\') + fprintf(stderr,"\\%2.2X",descr[4 + i]); + else + fprintf(stderr, "%c", descr[4 + i]); + fprintf(stderr, "\n"); + +#endif /* Libburn_print_feature_descriptorS */ + + } + } +#ifdef Libburn_support_dvd_r_seQ + if ((cp == 0x11 || cp == 0x14) && d->current_has_feat21h) + d->current_is_supported_profile = 1; +#endif } @@ -1663,15 +1804,19 @@ int mmc_setup_drive(struct burn_drive *d) d->start_lba = -2000000000; d->end_lba = -2000000000; - /* ts A61201 */ + /* ts A61201 - A70128 */ d->erasable = 0; d->current_profile = -1; d->current_profile_text[0] = 0; d->current_is_cd_profile = 0; d->current_is_supported_profile = 0; + d->current_has_feat21h = 0; + d->current_feat21h_link_size = -1; + d->current_feat2fh_byte4 = -1; d->needs_close_session = 0; d->bg_format_status = -1; d->num_format_descr = 0; + d->last_track_no = 0; return 1; } @@ -1702,6 +1847,38 @@ int mmc_compose_mode_page_5(struct burn_drive *d, pd[4] = 8; /* Link size dummy */ 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() + 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 */ + pd[2] = ((!!o->underrun_proof) << 6) + | (1 << 5) + | ((!!o->simulate) << 4); + /* Multi-session , FP = 1 , Track Mode = 5 */ + pd[3] = ((3 * !!o->multi) << 6) | (1 << 5) | 5; + /* Data Block Type = 8 */ + pd[4] = 8; + /* Link Size */ + if (d->current_feat21h_link_size >= 0) + pd[5] = d->current_feat21h_link_size; + else + pd[5] = 16; + if (d->current_feat21h_link_size != 16) { + char msg[80]; + + sprintf(msg, + "Feature 21h Link Size = %d (expected 16)\n", + d->current_feat21h_link_size); + libdax_msgs_submit(libdax_messenger, -1, 0x00000002, + LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, + msg, 0, 0); + } + /* Packet Size */ + pd[13] = 16; + } else { /* Traditional setup for CD */ pd[2] = ((!!o->underrun_proof) << 6) diff --git a/libburn/transport.h b/libburn/transport.h index ec46d9b..31cf3cf 100644 --- a/libburn/transport.h +++ b/libburn/transport.h @@ -152,11 +152,28 @@ struct burn_drive int current_is_cd_profile; int current_is_supported_profile; + /* ts A70128 : MMC-to-MMC feature info from 46h for DVD-RW. + Quite internal. Regard as opaque :) + */ + /* 1 = incremental recording available, 0 = not available */ + int current_has_feat21h; + + /* Link Size item number 0 from feature 0021h descriptor */ + int current_feat21h_link_size; + + /* Flags from feature 002Fh feature descriptor mmc5r03c.pdf 5.3.25 : + bit1= DVD-RW supported + bit2= Test Write available + bit3= DVD-R DL supported + bit6= Buffer Under-run Free recording available (page 05h BUFE) + */ + int current_feat2fh_byte4; + /* ts A70114 : wether a DVD-RW media holds an incomplete session (which could need closing after write) */ int needs_close_session; - /* ts A61218 from 46h GET CONFIGURATION */ + /* ts A61218 from 51h READ DISC INFORMATION */ int bg_format_status; /* 0=needs format start, 1=needs format restart*/ /* ts A70108 from 23h READ FORMAT CAPACITY mmc5r03c.pdf 6.24 */ @@ -181,6 +198,11 @@ struct burn_drive int rlba; /* relative lba in section */ int start_lba; int end_lba; + + /* ts A70129 : + from 51h READ DISC INFORMATION Last Track Number in Last Session */ + int last_track_no; + int toc_temp; struct burn_disc *disc; /* disc structure */ int block_types[4]; diff --git a/libburn/write.c b/libburn/write.c index 6f20ff8..542b624 100644 --- a/libburn/write.c +++ b/libburn/write.c @@ -195,7 +195,11 @@ int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s, /* MMC-1 mentions track number 0xFF for "the incomplete track", MMC-3 does not. I tried both. 0xFF was in effect when other bugs finally gave up and made way for readable tracks. */ - d->close_track_session(o->drive, 0, 0xff); /* tnum+1); */ + /* ts A70129 + Probably the right value would be d->last_track_no+tnum for + appendables + */ + d->close_track_session(o->drive, 0, 0xff); /* ts A61102 */ d->busy = BURN_DRIVE_WRITING; @@ -676,7 +680,7 @@ int burn_write_track(struct burn_write_opts *o, struct burn_session *s, /* ts A70121 : This is not possible because track 1 cannot have a pregap at all. - MMC-5 6.33.3.2 precribes a mandatoy pause + MMC-5 6.33.3.2 precribes a mandatory pause prior to any track 1. Pre-gap is prescribed for mode changes like audio-to-data. To set burn_track.pregap1 for track 1 is @@ -865,7 +869,50 @@ int burn_disc_init_write_status(struct burn_write_opts *o, } -/* ts A61218 */ +/* 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) +{ + struct burn_drive *d = o->drive; + char msg[160]; + int ret, lba, nwa; + + 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); + if (nwa > d->nwa) + d->nwa = nwa; + return 1; +} + + +/* ts A70129 */ +int burn_disc_close_track_dvd_minus_r(struct burn_write_opts *o, + struct burn_session *s, int tnum) +{ + struct burn_drive *d = o->drive; + + /* only DVD-R or sequential DVD-RW */ + if (d->current_has_feat21h != 1) /* only with Incremental writing */ + return 2; + + d->busy = BURN_DRIVE_CLOSING_SESSION; + /* 0xff was a name for the last track in MMC-1 but later + it vanished. One would need to determine the absolute + logical track number in multi-session situations. + Probably: d->last_track_no+tnum + */ + d->close_track_session(d, 0, 0xff); /* CLOSE TRACK, 001b */ + d->busy = BURN_DRIVE_WRITING; + return 1; +} + + +/* ts A61218 - A70129 */ int burn_dvd_write_track(struct burn_write_opts *o, struct burn_session *s, int tnum) { @@ -873,12 +920,17 @@ int burn_dvd_write_track(struct burn_write_opts *o, struct burn_drive *d = o->drive; struct buffer *out = d->buffer; int sectors; - int i, open_ended = 0, ret= 0; + int i, open_ended = 0, ret= 0, is_flushed = 0; sectors = burn_track_get_sectors(t); open_ended = burn_track_is_open_ended(t); - /* >>> any type specific track preparations */; + if (d->current_profile == 0x11 || d->current_profile == 0x14) { + /* DVD-R, DVD-RW Sequential */ + ret = burn_disc_open_track_dvd_minus_r(o, tnum); + if (ret <= 0) + goto ex; + } burn_disc_init_track_status(o, s, tnum, sectors); for (i = 0; open_ended || i < sectors; i++) { @@ -910,14 +962,19 @@ int burn_dvd_write_track(struct burn_write_opts *o, ret = burn_write_flush(o, t); if (ret <= 0) goto ex; + is_flushed = 1; - /* >>> any other normal track finalizing */; - + /* Eventually finalize track */ + if (d->current_profile == 0x11 || d->current_profile == 0x14) { + /* DVD-R, DVD-RW Sequential */ + ret = burn_disc_close_track_dvd_minus_r(o, s, tnum); + if (ret != 2) + goto ex; + } ret = 1; ex:; - if (ret<=0) { + if (!is_flushed) d->sync_cache(d); /* burn_write_flush() was not called */ - } return ret; } @@ -961,6 +1018,22 @@ int burn_disc_close_session_dvd_minus_rw(struct burn_write_opts *o, } +/* ts A70129 : for profile 0x11 DVD-R and 0x14 DVD-RW Sequential */ +int burn_disc_close_session_dvd_minus_r(struct burn_write_opts *o, + struct burn_session *s) +{ + struct burn_drive *d = o->drive; + + if (d->current_has_feat21h != 1) /* only for Incremental writing */ + return 2; + + d->busy = BURN_DRIVE_CLOSING_SESSION; + d->close_track_session(d, 1, 0); /* CLOSE SESSION, 010b */ + d->busy = BURN_DRIVE_WRITING; + return 1; +} + + /* ts A61218 */ int burn_dvd_write_session(struct burn_write_opts *o, struct burn_session *s) @@ -968,18 +1041,21 @@ int burn_dvd_write_session(struct burn_write_opts *o, int i,ret; struct burn_drive *d = o->drive; + /* >>> open_session ? (maybe with DAO) */ + for (i = 0; i < s->tracks; i++) { ret = burn_dvd_write_track(o, s, i); if (ret <= 0) break; } - if (d->current_profile == 0x1a) { - /* DVD+RW */ - if (d->needs_close_session) { - ret = burn_disc_close_session_dvd_plus_rw(o, s); - if (ret <= 0) - return 0; - } + if ((d->current_profile == 0x11 || d->current_profile == 0x14)) { + /* DVD-R , DVD-RW Sequential */ + ret = burn_disc_close_session_dvd_minus_r(o, s); + if (ret <= 0) + return 0; + } else if (d->current_profile == 0x12) { + /* DVD-RAM */ + /* ??? any finalization needed ? */; } else if (d->current_profile == 0x13) { /* DVD-RW restricted overwrite */ if (d->needs_close_session) { @@ -987,9 +1063,13 @@ int burn_dvd_write_session(struct burn_write_opts *o, if (ret <= 0) return 0; } - } else if (d->current_profile == 0x12) { - /* DVD-RAM */ - /* ??? any finalization needed ? */; + } else if (d->current_profile == 0x1a) { + /* DVD+RW */ + if (d->needs_close_session) { + ret = burn_disc_close_session_dvd_plus_rw(o, s); + if (ret <= 0) + return 0; + } } return 1; } @@ -1067,7 +1147,7 @@ int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o, 5.4.14 finally states that profile 0013h includes feature 002Ch rather than 0026h. - d->send_write_parameters(d, o); + d->send_write_parameters(d, o); */ d->busy = BURN_DRIVE_FORMATTING; @@ -1097,7 +1177,24 @@ int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o, } -/* ts A61218 */ +/* ts A70129 */ +int burn_disc_setup_dvd_minus_r(struct burn_write_opts *o, + struct burn_disc *disc) +{ + 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 */ + } + + d->nwa = 0; + return 1; +} + + +/* ts A61218 - A70129 */ int burn_dvd_write_sync(struct burn_write_opts *o, struct burn_disc *disc) { @@ -1161,7 +1258,8 @@ int burn_dvd_write_sync(struct burn_write_opts *o, } o->obs_pad = 0; /* no filling-up of track's last 32k buffer */ - } else if (d->current_profile == 0x13) { /* DVD-RW Rest. Overwrite */ + } else if (d->current_profile == 0x13) { + /* DVD-RW Restricted Overwrite */ if (o->start_byte >= 0 && (o->start_byte % 32768)) { sprintf(msg, "Write start address not properly aligned to 32K"); @@ -1182,9 +1280,31 @@ int burn_dvd_write_sync(struct burn_write_opts *o, goto early_failure; } - /* ??? is this necessary ? */ + /* _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) */ + if (o->start_byte >= 0) { + sprintf(msg, "Write start address not supported"); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020124, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + msg, 0,0); + goto early_failure; + } + ret = burn_disc_setup_dvd_minus_r(o, disc); + if (ret <= 0) { + sprintf(msg, + "Write preparation setup failed for DVD-R[W]"); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020121, + LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH, + msg, 0,0); + goto early_failure; + } + } else { sprintf(msg, "Unsuitable media detected. Profile %4.4Xh %s", d->current_profile, d->current_profile_text);