New API calls burn_drive_get_speedlist() , burn_drive_free_speedlist()

This commit is contained in:
Thomas Schmitt 2006-12-26 17:07:53 +00:00
parent ae1b8ce61c
commit 1bd1985aeb
7 changed files with 261 additions and 16 deletions

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2006.12.25.190811"
#define Cdrskin_timestamP "2006.12.26.170459"

View File

@ -54,6 +54,7 @@ void burn_drive_free(struct burn_drive *d)
if (burn_drive_is_open(d))
d->release(d);
free((void *) d->idata);
burn_mdata_free_subs(d->mdata);
free((void *) d->mdata);
if(d->toc_entry != NULL)
free((void *) d->toc_entry);
@ -144,6 +145,9 @@ int burn_drive_inquire_media(struct burn_drive *d)
int loop_count, old_speed = -1234567890, new_speed = -987654321;
int old_erasable = -1234567890, new_erasable = -987654321;
/* ts A61225 : after loading the tray, mode page 2Ah can change */
d->getcaps(d);
/* ts A61020 : d->status was set to BURN_DISC_BLANK as pure guess */
if (d->mdata->cdr_write || d->mdata->cdrw_write ||
@ -152,6 +156,8 @@ int burn_drive_inquire_media(struct burn_drive *d)
#ifdef Libburn_grab_release_and_grab_agaiN
/* This code demanded the app to release and re-grab. */
/* ??? ts A61225 : is this safe now (after d->getcaps()) ? */
d->read_disc_info(d);
#else
@ -226,9 +232,6 @@ int burn_drive_grab(struct burn_drive *d, int le)
/* ts A61118 */
d->start_unit(d);
/* ts A61225 : after loading the tray, mode page 2Ah can change */
d->getcaps(d);
/* ts A61202 : gave bit1 of le a meaning */
sose = d->silent_on_scsi_error;
if (!le)
@ -1290,3 +1293,111 @@ int burn_drive_wrote_well(struct burn_drive *d)
return !d->cancel;
}
/* ts A61226 */
int burn_speed_descriptor_new(struct burn_speed_descriptor **s,
struct burn_speed_descriptor *prev,
struct burn_speed_descriptor *next, int flag)
{
struct burn_speed_descriptor *o;
(*s) = o = malloc(sizeof(struct burn_speed_descriptor));
if (o == NULL)
return -1;
o->source = 0;
o->profile_loaded = -2;
o->profile_name[0] = 0;
o->wrc = 0;
o->exact = 0;
o->mrw = 0;
o->end_lba = -1;
o->write_speed = 0;
o->read_speed = 0;
o->prev = prev;
if (prev != NULL) {
next = prev->next;
prev->next = o;
}
o->next = next;
if (next != NULL)
next->prev = o;
return 1;
}
/* ts A61226 */
/* @param flag bit0= destroy whole next-chain of descriptors */
int burn_speed_descriptor_destroy(struct burn_speed_descriptor **s, int flag)
{
struct burn_speed_descriptor *next, *o;
if ((*s) == NULL)
return 0;
if (flag&1)
for (o = (*s); o->prev != NULL; o = o->prev);
else
o = (*s);
next = o->next;
if (next != NULL)
next->prev = o->prev;
if (o->prev != NULL)
o->prev->next = next;
free((char *) (*s));
(*s) = NULL;
if (flag&1)
return burn_speed_descriptor_destroy(&next, flag&1);
return 1;
}
/* ts A61226 */
int burn_speed_descriptor_copy(struct burn_speed_descriptor *from,
struct burn_speed_descriptor *to, int flag)
{
to->source = from->source;
to->profile_loaded = from->profile_loaded;
strcpy(to->profile_name, from->profile_name);
to->wrc = from->wrc;
to->exact = from->exact;
to->mrw = from->mrw;
to->end_lba = from->end_lba;
to->write_speed = from->write_speed;
to->read_speed = from->read_speed;
return 1;
}
/* ts A61226 : free dynamically allocated sub data of struct scsi_mode_data */
int burn_mdata_free_subs(struct scsi_mode_data *m)
{
burn_speed_descriptor_destroy(&(m->speed_descriptors), 1);
return 1;
}
/* ts A61226 : API function */
int burn_drive_get_speedlist(struct burn_drive *d,
struct burn_speed_descriptor **speed_list)
{
int ret;
struct burn_speed_descriptor *sd, *csd = NULL;
(*speed_list) = NULL;
for (sd = d->mdata->speed_descriptors; sd != NULL; sd = sd->next) {
ret = burn_speed_descriptor_new(&csd, NULL, csd, 0);
if (ret <= 0)
return -1;
burn_speed_descriptor_copy(sd, csd, 0);
}
(*speed_list) = csd;
return (csd != NULL);
}
/* ts A61226 : API function */
int burn_drive_free_speedlist(struct burn_speed_descriptor **speed_list)
{
return burn_speed_descriptor_destroy(speed_list, 1);
}

View File

@ -10,6 +10,8 @@
struct burn_drive;
struct command;
struct mempage;
struct scsi_mode_data;
struct burn_speed_descriptor;
#define LEAD_IN 1
#define GAP 2
@ -75,4 +77,18 @@ int burn_drive_inquire_media(struct burn_drive *d);
/* ts A61125 : model aspects of burn_drive_release */
int burn_drive_mark_unready(struct burn_drive *d);
/* ts A61226 */
int burn_speed_descriptor_new(struct burn_speed_descriptor **s,
struct burn_speed_descriptor *prev,
struct burn_speed_descriptor *next, int flag);
/* ts A61226 */
/* @param flag bit0= destroy whole next-chain of descriptors */
int burn_speed_descriptor_destroy(struct burn_speed_descriptor **s, int flag);
/* ts A61226 : free dynamically allocated sub data of struct scsi_mode_data */
int burn_mdata_free_subs(struct scsi_mode_data *m);
#endif /* __DRIVE */

View File

@ -414,6 +414,55 @@ struct burn_progress {
unsigned buffer_min_fill;
};
/* ts A61226 */
/** Description of a speed capability as reported by the drive in conjunction
with eventually loaded media. There can be more than one such object per
drive. So they are chained via .next and .prev , where NULL marks the end
of the chain. This list is set up by burn_drive_scan() and gets updated
by burn_drive_grab().
A copy may be obtained by burn_drive_get_speedlist() and disposed by
burn_drive_free_speedlist().
For technical background info see SCSI specs MMC and SPC:
mode page 2Ah (from SPC 5Ah MODE SENSE) , mmc3r10g.pdf , 6.3.11 Table 364
ACh GET PERFORMANCE, Type 03h , mmc5r03c.pdf , 6.8.5.3 Table 312
*/
struct burn_speed_descriptor {
/** Where this info comes from :
0 = misc , 1 = mode page 2Ah , 2 = ACh GET PERFORMANCE */
int source;
/** The media type that was reported as current at the time of report
-2 = state unknown, -1 = no media was loaded , else see
burn_disc_get_profile() */
int profile_loaded;
char profile_name[80];
/** The attributed capacity of appropriate media in logical block units
i.e. 2352 raw bytes or 2048 data bytes. -1 = capacity unknown. */
int end_lba;
/** Write speed is given in 1000 bytes/s , 0 = invalid. The numbers
are supposed to be usable with burn_drive_set_speed() */
int write_speed;
int read_speed;
/** Expert info from ACh GET PERFORMANCE and/or mode page 2Ah.
Expect values other than 0 or 1 to get a meaning in future.*/
/* Rotational control: 0 = CLV/default , 1 = CAV */
int wrc;
/* 1 = drive promises reported performance over full media */
int exact;
/* 1 = suitable for mixture of read and write */
int mrw;
/** List chaining. Use .next until NULL to iterate over the list */
struct burn_speed_descriptor *prev;
struct burn_speed_descriptor *next;
};
/** Initialize the library.
This must be called before using any other functions in the library. It
may be called more than once with no effect.
@ -735,11 +784,12 @@ int burn_disc_track_lba_nwa(struct burn_drive *d, struct burn_write_opts *o,
/* ts A61202 */
/** Tells the MMC Profile identifier of the loaded media. The drive must be
grabbed in order to get a non-zero result.
libburn currently writes only to profiles 0x09 "CD-R", 0x0a "CD-RW" or
0x1a "DVD+RW".
@param d The drive where the media is inserted.
@param pno Profile Number as of mmc5r03c.pdf, table 89
@param name Profile Name (e.g "CD-RW", unknown profiles have empty name)
@return 1 profile is valid, 0 no profile info available
Note: libburn currently writes only to profiles 0x09 "CD-R", 0x0a "CD-RW".
*/
int burn_disc_get_profile(struct burn_drive *d, int *pno, char name[80]);
@ -1177,6 +1227,31 @@ int burn_drive_get_min_write_speed(struct burn_drive *d);
*/
int burn_drive_get_read_speed(struct burn_drive *d);
/* ts A61226 */
/** Obtain a copy of the current speed descriptor list. The drive's list gets
updated on various occasions such as burn_drive_grab() but the copy
obtained here stays untouched. It has to be disposed via
burn_drive_free_speedlist() when it is not longer needed. Speeds
may appear several times in the list. The list content depends much on
drive and media type. It seems that .source == 1 applies mostly to CD media
whereas .source == 2 applies to any media.
@param d Drive to query
@param speed_list The copy. If empty, *speed_list gets returned as NULL.
@return 1=success , 0=list empty , <0 severe error
*/
int burn_drive_get_speedlist(struct burn_drive *d,
struct burn_speed_descriptor **speed_list);
/* ts A61226 */
/** Dispose a speed descriptor list copy which was obtained by
burn_drive_get_speedlist().
@param speed_list The list copy. *speed_list gets set to NULL.
@return 1=list disposed , 0= *speedlist was already NULL
*/
int burn_drive_free_speedlist(struct burn_speed_descriptor **speed_list);
/** Gets a copy of the toc_entry structure associated with a track
@param t Track to get the entry from
@param entry Struct for the library to fill out

View File

@ -910,7 +910,7 @@ int mmc_set_streaming(struct burn_drive *d, int r_speed, int w_speed)
if (d->mdata->max_end_lba > 0)
end_lba = d->mdata->max_end_lba - 1;
sprintf(msg, "mmc_set_streaming: end_lba=%lu , r=%d , w=%d",
sprintf(msg, "mmc_set_streaming: end_lba=%d , r=%d , w=%d",
end_lba, r_speed, w_speed);
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002,
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
@ -1202,7 +1202,7 @@ int mmc_format_unit(struct burn_drive *d)
int mmc_get_write_performance(struct burn_drive *d)
{
struct buffer buf;
int len, i, b, pass, was_exact_bit = 0, max_descr, num_descr;
int len, i, b, max_descr, num_descr, ret;
int exact_bit, read_speed, write_speed;
/* if this call delivers usable data then they should override
previously recorded min/max speed and not compete with them */
@ -1211,12 +1211,16 @@ int mmc_get_write_performance(struct burn_drive *d)
struct command c;
unsigned long end_lba;
unsigned char *pd;
struct burn_speed_descriptor *sd;
/* A61225 : 1 = report about speed descriptors */
static int speed_debug = 0;
mmc_function_spy("mmc_get_write_performance");
if (d->current_profile <= 0)
mmc_get_configuration(d);
memcpy(c.opcode, MMC_GET_PERFORMANCE, sizeof(MMC_GET_PERFORMANCE));
max_descr = ( BUFFER_SIZE - 8 ) / 16 - 1;
@ -1248,7 +1252,7 @@ int mmc_get_write_performance(struct burn_drive *d)
num_descr = ( len - 4 ) / 16;
if (num_descr > max_descr)
num_descr = max_descr;
for (pass = 0; pass < 2; pass++) for (i = 0; i < num_descr; i++) {
for (i = 0; i < num_descr; i++) {
exact_bit = !!(pd[8 + i*16] & 2);
end_lba = read_speed = write_speed = 0;
for (b = 0; b < 4 ; b++) {
@ -1259,16 +1263,30 @@ int mmc_get_write_performance(struct burn_drive *d)
if (end_lba > 0x7ffffffe)
end_lba = 0x7ffffffe;
if (pass == 0 && speed_debug)
if (speed_debug)
fprintf(stderr,
"LIBBURN_DEBUG: kB/s: write=%d read=%d end=%lu exact=%d\n",
write_speed, read_speed, end_lba, exact_bit);
if (pass == 0 && !exact_bit)
continue;
if (pass == 1 && was_exact_bit)
continue;
was_exact_bit |= exact_bit;
/* ts A61226 */
ret = burn_speed_descriptor_new(&(d->mdata->speed_descriptors),
NULL, d->mdata->speed_descriptors, 0);
if (ret > 0) {
sd = d->mdata->speed_descriptors;
sd->source = 2;
if (d->current_profile > 0) {
sd->profile_loaded = d->current_profile;
strcpy(sd->profile_name,
d->current_profile_text);
}
sd->wrc = (pd[8 + i*16] >> 3 ) & 3;
sd->exact = exact_bit;
sd->mrw = pd[8 + i*16] & 1;
sd->end_lba = end_lba;
sd->write_speed = write_speed;
sd->read_speed = read_speed;
}
if (end_lba > d->mdata->max_end_lba)
d->mdata->max_end_lba = end_lba;
if (end_lba < d->mdata->min_end_lba)

View File

@ -15,6 +15,7 @@
#include <stdlib.h>
#include "libburn.h"
#include "transport.h"
#include "spc.h"
#include "mmc.h"
@ -135,6 +136,7 @@ void spc_sense_caps(struct burn_drive *d)
int size, page_length, num_write_speeds = 0, i, speed, ret;
unsigned char *page;
struct command c;
struct burn_speed_descriptor *sd;
/* ts A61225 : 1 = report about post-MMC-1 speed descriptors */
static int speed_debug = 0;
@ -161,6 +163,9 @@ void spc_sense_caps(struct burn_drive *d)
*/
page_length = page[1];
m->valid = 0;
burn_mdata_free_subs(m);
m->buffer_size = page[12] * 256 + page[13];
m->dvdram_read = page[2] & 32;
m->dvdram_write = page[3] & 32;
@ -192,9 +197,11 @@ void spc_sense_caps(struct burn_drive *d)
m->valid = 1;
mmc_get_configuration(d);
/* ts A61225 : end of MMC-1 , begin of MMC-3 */
if (page_length < 32) /* no write speed descriptors ? */
return;
goto try_mmc_get_performance;
m->cur_write_speed = page[28] * 256 + page[29];
@ -212,6 +219,21 @@ void spc_sense_caps(struct burn_drive *d)
"LIBBURN_DEBUG: write speed #%d = %d kB/s (rc %d)\n",
i, speed, page[32 + 4*i +1] & 7);
/* ts A61226 */
ret = burn_speed_descriptor_new(&(d->mdata->speed_descriptors),
NULL, d->mdata->speed_descriptors, 0);
if (ret > 0) {
sd = d->mdata->speed_descriptors;
sd->source = 1;
if (d->current_profile > 0) {
sd->profile_loaded = d->current_profile;
strcpy(sd->profile_name,
d->current_profile_text);
}
sd->wrc = (( page[32 + 4*i +1] & 7 ) == 1 );
sd->write_speed = speed;
}
if (speed > m->max_write_speed)
m->max_write_speed = speed;
if (speed < m->min_write_speed)
@ -223,13 +245,13 @@ void spc_sense_caps(struct burn_drive *d)
"LIBBURN_DEBUG: 5Ah,2Ah min_write_speed = %d , max_write_speed = %d\n",
m->min_write_speed, m->max_write_speed);
try_mmc_get_performance:;
ret = mmc_get_write_performance(d);
if (ret > 0 && speed_debug)
fprintf(stderr,
"LIBBURN_DEBUG: ACh min_write_speed = %d , max_write_speed = %d\n",
m->min_write_speed, m->max_write_speed);
}
@ -551,6 +573,7 @@ int burn_scsi_setup_drive(struct burn_drive *d, int bus_no, int host_no,
d->idata->valid = 0;
d->mdata = malloc(sizeof(struct scsi_mode_data));
d->mdata->valid = 0;
d->mdata->speed_descriptors = NULL;
/* ts A61007 : obsolete Assert in drive_getcaps() */
if(d->idata == NULL || d->mdata == NULL) {

View File

@ -65,6 +65,7 @@ struct burn_scsi_inquiry_data
int valid;
};
struct scsi_mode_data
{
int buffer_size;
@ -88,6 +89,7 @@ struct scsi_mode_data
Speed values go into *_*_speed */
int min_end_lba;
int max_end_lba;
struct burn_speed_descriptor *speed_descriptors;
int cur_read_speed;
int cur_write_speed;