diff --git a/libburn/drive.c b/libburn/drive.c index e69e17a..f0157b9 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -475,6 +475,7 @@ void burn_disc_erase_sync(struct burn_drive *d, int fast) /* @param flag: bit0 = fill formatted size with zeros + bit1, bit2 are for d->format_unit() */ void burn_disc_format_sync(struct burn_drive *d, off_t size, int flag) { @@ -489,12 +490,12 @@ void burn_disc_format_sync(struct burn_drive *d, off_t size, int flag) #ifdef Libburn_format_ignore_sizE size = 0; #else - stages = 1 + (flag & 1); + stages = 1 + ((flag & 1) && size > 1024 * 1024); #endif d->cancel = 0; d->busy = BURN_DRIVE_FORMATTING; - ret = d->format_unit(d, size, 0); + ret = d->format_unit(d, size, flag & 6); if (ret <= 0) d->cancel = 1; /* reset the progress */ @@ -525,11 +526,11 @@ void burn_disc_format_sync(struct burn_drive *d, off_t size, int flag) burn_drive_inquire_media(d); if (flag & 1) { /* write size in zeros */; - pbase = 0x8000; + pbase = 0x8000 + 0x7fff * (stages == 1); pfill = 0xffff - pbase; buf_secs = 16; /* Must not be more than 16 */ num_bufs = size / buf_secs / 2048; - if (num_bufs <= 0 || num_bufs > 0x7fffffff) { + if (num_bufs > 0x7fffffff) { d->cancel = 1; goto ex; } diff --git a/libburn/libburn.h b/libburn/libburn.h index 2491480..a136dd3 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -853,6 +853,8 @@ void burn_disc_erase(struct burn_drive *drive, int fast); @param flag Bitfield for control purposes: bit0= after formatting, write the given number of zero-bytes to the media and eventually perform preliminary closing. + bit1= insist in size 0 even if there is a better default known + bit2= format to maximum available size */ void burn_disc_format(struct burn_drive *drive, off_t size, int flag); diff --git a/libburn/libdax_msgs.h b/libburn/libdax_msgs.h index a5c0169..c81bd45 100644 --- a/libburn/libdax_msgs.h +++ b/libburn/libdax_msgs.h @@ -347,6 +347,9 @@ Range "scdbackup" : 0x00020000 to 0x0002ffff 0x00020127 (NOTE,HIGH) = Write start address is ... 0x00020128 (FATAL,HIGH) = Unsupported inquiry_type with mmc_get_performance 0x00020129 (SORRY,HIGH) = Will not format media type + 0x00020130 (SORRY,HIGH) = Drive and media state unsuitable for blanking + 0x00020131 (SORRY,HIGH) = No suitable formatting type offered by drive + libdax_audioxtr: 0x00020200 (SORRY,HIGH) = Cannot open audio source file diff --git a/libburn/mmc.c b/libburn/mmc.c index 257e7e2..ffad211 100644 --- a/libburn/mmc.c +++ b/libburn/mmc.c @@ -65,7 +65,6 @@ extern struct libdax_msgs *libdax_messenger; Todo: Determine first free lba for appending data. - Determine start lba of most recent mkisofs session. */ @@ -110,6 +109,11 @@ static unsigned char MMC_SET_STREAMING[] = static unsigned char MMC_GET_PERFORMANCE[] = { 0xAC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; +/* ts A70108 : To obtain info about drive and media formatting opportunities */ +static unsigned char MMC_READ_FORMAT_CAPACITIES[] = + { 0x23, 0, 0, 0, 0, 0, 0, 0, 0, 0}; + + static int mmc_function_spy_do_tell = 0; int mmc_function_spy(char * text) @@ -1104,6 +1108,104 @@ void mmc_get_configuration(struct burn_drive *d) } + +/* ts A70108 */ +/* mmc5r03c.pdf 6.24 */ +int mmc_read_format_capacities(struct burn_drive *d, int top_wanted) +{ + struct buffer buf; + int len, type, score, num_descr, max_score = -1, i; + off_t size; + struct command c; + unsigned char *dpt; + char msg[160]; + + mmc_function_spy("mmc_read_format_capacities"); + + d->format_descr_type = 3; + d->format_curr_max_size = 0; + d->best_format_type = -1; + d->best_format_size = 0; + + memcpy(c.opcode, MMC_READ_FORMAT_CAPACITIES, + sizeof(MMC_GET_CONFIGURATION)); + c.retry = 1; + c.oplen = sizeof(MMC_READ_FORMAT_CAPACITIES); + c.opcode[7]= 0x02; + c.opcode[8]= 0x00; /* accept 512 bytes (not more than 260 possible) */ + c.page = &buf; + c.page->sectors = 0; + c.page->bytes = 0; + c.dir = FROM_DRIVE; + + d->issue_command(d, &c); + if (c.error) + return 0; + + len = c.page->data[3]; + if (len<8) + return 0; + + dpt = c.page->data + 4; + /* decode 6.24.3.2 Current/Maximum Capacity Descriptor */ + d->format_descr_type = dpt[4] & 3; + d->format_curr_max_size = (((off_t) dpt[0]) << 24) + + (dpt[1] << 16) + (dpt[2] << 8) + dpt[3]; + + sprintf(msg, + "Current/Maximum Capacity Descriptor : type = %d : %.f", + d->format_descr_type, (double) d->format_curr_max_size); + libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002, + LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, + msg, 0, 0); + + d->format_curr_max_size *= (off_t) 2048; + + /* 6.24.3.3 Formattable Capacity Descriptors */ + num_descr = (len - 8) / 8; + for (i = 0; i < num_descr; i++) { + dpt = c.page->data + 12 + 8 * i; + size = (((off_t) dpt[0]) << 24) + + (dpt[1] << 16) + (dpt[2] << 8) + dpt[3]; + size *= (off_t) 2048; + type = dpt[4] >> 2; + + sprintf(msg, "Capacity Descriptor %2.2Xh %.fs = %.1f MB",type, + (double) size / 2048 , (double) size / 1024 / 1024); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00000002, + LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, + msg, 0, 0); + + if (type == 0x10) { /* full format */ + score = 1; + } else if(type == 0x13) { + score = 100; + } else if(type == 0x15) { + score = 50; + } else { + continue; + } + if(type == top_wanted) + score+= 1000000000; + if (score > max_score) { + d->best_format_type = type; + d->best_format_size = size; + max_score = score; + } + } + + sprintf(msg, + "best_format_type = %2.2Xh , best_format_size = %.f", + d->best_format_type, (double) d->best_format_size); + libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002, + LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, + msg, 0, 0); + + return 1; +} + + void mmc_sync_cache(struct burn_drive *d) { struct command c; @@ -1168,14 +1270,16 @@ int mmc_read_buffer_capacity(struct burn_drive *d) >>> all-in-one automat. @param size The size (in bytes) to be sent with the FORMAT comand - @param flag unused yet, submit 0 + @param flag bit1= insist in size 0 even if there is a better default known + bit2= format to maximum available size + bit3= expand format up to at least size */ int mmc_format_unit(struct burn_drive *d, off_t size, int flag) { struct buffer buf; struct command c; - int ret, tolerate_failure = 0, return_immediately = 0, i; - off_t num_of_blocks = 0; + int ret, tolerate_failure = 0, return_immediately = 0, i, format_type; + off_t num_of_blocks = 0, diff; char msg[160],descr[80]; mmc_function_spy("mmc_format_unit"); @@ -1198,10 +1302,11 @@ int mmc_format_unit(struct burn_drive *d, off_t size, int flag) /* >>> use case: background formatting during write */ /* mmc5r03c.pdf , 6.5.4.2.14, DVD+RW Basic Format */ - c.page->data[8] = 0x26 << 2; /* Format type */ + format_type = 0x26; - /* Note: parameter "size" is ignored here */ - memset(c.page->data + 4, 0xff, 4); /* maximum blocksize */ + if ((size <= 0 && !(flag & 2)) || (flag & (4 | 8))) + /* maximum capacity */ + memset(c.page->data + 4, 0xff, 4); if (d->bg_format_status == 1) /* is partly formatted */ c.page->data[11] = 1; /* Restart bit */ @@ -1217,22 +1322,67 @@ int mmc_format_unit(struct burn_drive *d, off_t size, int flag) } else if (d->current_profile == 0x13) {/*DVD-RW restricted overwrite*/ /* >>> use case: quick grow formatting during write */ - /* >>> check wether READ FORMAT CAPACITIES does report - 0x13 formatting. If not, skip this. It seems to work - without formatting on e.g. freshly formatted media. */ - tolerate_failure = 1; - + ret = mmc_read_format_capacities(d, 0x13); + if (ret > 0) { + if (d->best_format_type == 0x13) { + if (d->best_format_size <= 0) + return 1; + } else { + /* formatted or intermediate state ? */ + if (d->format_descr_type == 2 || + d->format_descr_type == 3) + return 1; + /* does trying make sense at all ? */ + tolerate_failure = 1; + } + } + if (d->best_format_type == 0x13 && (flag & (4 | 8))) { + num_of_blocks = d->best_format_size / 2048; + if (flag & 8) { + /* num_of_blocks needed to reach size */ + diff = (size - d->format_curr_max_size) /32768; + if ((size - d->format_curr_max_size) % 32768) + diff++; + diff *= 16; + if (diff < num_of_blocks) + num_of_blocks = diff; + } + if (num_of_blocks > 0) + for (i = 0; i < 4; i++) + c.page->data[4 + i] = + (num_of_blocks >> (24 - 8 * i)) & 0xff; + } /* 6.5.4.2.8 , DVD-RW Quick Grow Last Border */ - c.page->data[8] = 0x13 << 2; /* Format type */ + format_type = 0x13; c.page->data[11] = 16; /* block size * 2k */ sprintf(descr, "DVD-RW, quick grow"); } else if (d->current_profile == 0x14) {/*DVD-RW sequential recording*/ /* >>> use case : transition from Sequential to Overwrite */ - /* 6.5.4.2.10 , DVD-RW Quick (-> Restricted Overwrite) */ + /* To Restricted Overwrite */ + /* 6.5.4.2.10 , 15h DVD-RW Quick */ /* c.page->data[4-7]==0 : 0 blocks */ - c.page->data[8] = 0x15 << 2; /* Format type */ + /* or 6.5.4.2.5 Format Type = 10h (Full Format) */ + mmc_read_format_capacities(d, (flag & 4) ? 0x10 : 0x15); + if (d->best_format_type == 0x15 || + d->best_format_type == 0x10) { + if ((flag & 4) || d->best_format_type == 0x10) { + num_of_blocks = d->best_format_size / 2048; + for (i = 0; i < 4; i++) + c.page->data[4 + i] = + (num_of_blocks >> (24 - 8 * i)) & 0xff; + } + + } else { + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020131, + LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, + "No suitable formatting type offered by drive", + 0, 0); + return 0; + } + format_type = d->best_format_type; c.page->data[11] = 16; /* block size * 2k */ sprintf(descr, "DVD-RW, quick"); return_immediately = 1; /* caller must do the waiting */ @@ -1246,9 +1396,16 @@ int mmc_format_unit(struct burn_drive *d, off_t size, int flag) libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002011e, LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); + msg, 0, 0); return 0; } + c.page->data[8] = format_type << 2; + + sprintf(msg, "Format type %2.2Xh , blocks = %d\n", + format_type, (int) num_of_blocks); + libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002, + LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, + msg, 0, 0); d->issue_command(d, &c); if (c.error && !tolerate_failure) { diff --git a/libburn/transport.h b/libburn/transport.h index c058f79..429febf 100644 --- a/libburn/transport.h +++ b/libburn/transport.h @@ -141,6 +141,11 @@ struct burn_drive /* ts A61218 from 46h GET CONFIGURATION */ int bg_format_status; /* 0=needs format start, 1=needs format restart*/ + /* ts A70108 from 23h READ FORMAT CAPACITY mmc5r03c.pdf 6.24 */ + int format_descr_type; /* 1=unformatted, 2=formatted, 3=unclear */ + off_t format_curr_max_size; /* meaning depends on format_descr_type */ + int best_format_type; + off_t best_format_size; volatile int released; diff --git a/libburn/write.c b/libburn/write.c index 747c663..1579274 100644 --- a/libburn/write.c +++ b/libburn/write.c @@ -975,6 +975,19 @@ int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o, char msg[160]; int ret; + d->nwa = 0; + if (o->start_byte >= 0) { + d->nwa = o->start_byte / 32768; /* align to 32 kB */ + + sprintf(msg, "Write start address is %d * 32768", d->nwa); + libdax_msgs_submit(libdax_messenger, d->global_index, + 0x00020127, + LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, + msg, 0,0); + + d->nwa *= 16; /* convert to 2048 block units */ + } + if (d->current_profile == 0x13) { /* DVD-RW restricted overwrite */ /* ??? mmc5r03c.pdf 7.5.2 : @@ -995,7 +1008,9 @@ int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o, d->busy = BURN_DRIVE_FORMATTING; - ret = d->format_unit(d, (off_t) 0, 0); /* "quick grow" */ + /* "quick grow" to at least byte equivalent of d->nwa */ + ret = d->format_unit(d, (off_t) d->nwa * (off_t) 2048, + (d->nwa > 0) << 3); if (ret <= 0) return 0; d->busy = BURN_DRIVE_WRITING; @@ -1010,17 +1025,6 @@ int burn_disc_setup_dvd_minus_rw(struct burn_write_opts *o, return 0; } - d->nwa = 0; - if (o->start_byte >= 0) { - d->nwa = o->start_byte / 32768; - - sprintf(msg, "Write start address is %d * 32768", d->nwa); - libdax_msgs_submit(libdax_messenger, d->global_index, - 0x00020127, - LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, - msg, 0,0); - } - /* >>> perform OPC if needed */; /* >>> */;