Browse Source

For Linux 2.4, USB : Carefully avoided to inquire more data than available

ZeroThreeEight
Thomas Schmitt 14 years ago
parent
commit
79adcb520b
  1. 2
      cdrskin/cdrskin_timestamp.h
  2. 381
      libburn/mmc.c
  3. 26
      libburn/sbc.c
  4. 148
      libburn/spc.c
  5. 3
      libburn/spc.h
  6. 5
      libburn/toc.c
  7. 1
      libburn/transport.h

2
cdrskin/cdrskin_timestamp.h

@ -1 +1 @@
#define Cdrskin_timestamP "2007.05.21.184334"
#define Cdrskin_timestamP "2007.05.21.185450"

381
libburn/mmc.c

@ -92,6 +92,11 @@ extern struct libdax_msgs *libdax_messenger;
ts A70330 : Allowed finalizing of DVD+R.
*/
/* ts A70519 : With MMC commands of data direction FROM_DRIVE:
Made struct command.dxfer_len equal to Allocation Length
of MMC commands. Made sure that not more bytes are allowed
for transfer than there are available.
*/
static unsigned char MMC_GET_MSINFO[] =
{ 0x43, 0, 1, 0, 0, 0, 0, 16, 0, 0 };
@ -116,6 +121,7 @@ static unsigned char MMC_SYNC_CACHE[] = { 0x35, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_GET_EVENT[] = { 0x4A, 1, 0, 0, 16, 0, 0, 0, 8, 0 };
static unsigned char MMC_CLOSE[] = { 0x5B, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_TRACK_INFO[] = { 0x52, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_SEND_CUE_SHEET[] =
{ 0x5D, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
@ -188,9 +194,13 @@ void mmc_send_cue_sheet(struct burn_drive *d, struct cue_sheet *s)
mmc_function_spy("mmc_send_cue_sheet");
c.retry = 1;
scsi_init_command(&c, MMC_SEND_CUE_SHEET, sizeof(MMC_SEND_CUE_SHEET));
/*
c.oplen = sizeof(MMC_SEND_CUE_SHEET);
memcpy(c.opcode, MMC_SEND_CUE_SHEET, sizeof(MMC_SEND_CUE_SHEET));
*/
c.retry = 1;
c.page = &buf;
c.page->bytes = s->count * 8;
c.page->sectors = 0;
@ -214,10 +224,12 @@ int mmc_reserve_track(struct burn_drive *d, off_t size)
char msg[80];
mmc_function_spy("mmc_reserve_track");
c.retry = 1;
scsi_init_command(&c, MMC_RESERVE_TRACK, sizeof(MMC_RESERVE_TRACK));
/*
c.oplen = sizeof(MMC_RESERVE_TRACK);
memcpy(c.opcode, MMC_RESERVE_TRACK, sizeof(MMC_RESERVE_TRACK));
*/
c.retry = 1;
/* 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;
@ -238,14 +250,22 @@ int mmc_reserve_track(struct burn_drive *d, off_t size)
/* ts A70201 :
Common track info fetcher for mmc_get_nwa() and mmc_fake_toc()
*/
int mmc_read_track_info(struct burn_drive *d, int trackno, struct buffer *buf)
int mmc_read_track_info(struct burn_drive *d, int trackno, struct buffer *buf,
int alloc_len)
{
struct command c;
mmc_function_spy("mmc_read_track_info");
c.retry = 1;
scsi_init_command(&c, MMC_TRACK_INFO, sizeof(MMC_TRACK_INFO));
/*
c.oplen = sizeof(MMC_TRACK_INFO);
memcpy(c.opcode, MMC_TRACK_INFO, sizeof(MMC_TRACK_INFO));
*/
c.dxfer_len = alloc_len;
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
c.opcode[8] = c.dxfer_len & 0xff;
c.retry = 1;
c.opcode[1] = 1;
if(trackno<=0) {
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
@ -278,12 +298,12 @@ int mmc_read_track_info(struct burn_drive *d, int trackno, struct buffer *buf)
int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa)
{
struct buffer buf;
int ret, num;
int ret, num, alloc_len = 20;
unsigned char *data;
mmc_function_spy("mmc_get_nwa");
ret = mmc_read_track_info(d, trackno, &buf);
ret = mmc_read_track_info(d, trackno, &buf, alloc_len);
if (ret <= 0)
return ret;
data = buf.data;
@ -368,9 +388,12 @@ void mmc_close(struct burn_drive *d, int session, int track)
mmc_function_spy("mmc_close");
c.retry = 1;
scsi_init_command(&c, MMC_CLOSE, sizeof(MMC_CLOSE));
/*
c.oplen = sizeof(MMC_CLOSE);
memcpy(c.opcode, MMC_CLOSE, sizeof(MMC_CLOSE));
*/
c.retry = 1;
/* (ts A61030 : shifted !!session rather than or-ing plain session ) */
c.opcode[2] = ((session & 3) << 1) | !!track;
@ -385,11 +408,19 @@ void mmc_get_event(struct burn_drive *d)
{
struct buffer buf;
struct command c;
int alloc_len= 8;
mmc_function_spy("mmc_get_event");
c.retry = 1;
scsi_init_command(&c, MMC_GET_EVENT, sizeof(MMC_GET_EVENT));
/*
c.oplen = sizeof(MMC_GET_EVENT);
memcpy(c.opcode, MMC_GET_EVENT, sizeof(MMC_GET_EVENT));
*/
c.dxfer_len = alloc_len;
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
c.opcode[8] = c.dxfer_len & 0xff;
c.retry = 1;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
@ -415,9 +446,13 @@ void mmc_write_12(struct burn_drive *d, int start, struct buffer *buf)
/* a ssert(buf->bytes >= buf->sectors);*/ /* can be == at 0... */
burn_print(100, "trying to write %d at %d\n", len, start);
scsi_init_command(&c, MMC_WRITE_12, sizeof(MMC_WRITE_12));
/*
memcpy(c.opcode, MMC_WRITE_12, sizeof(MMC_WRITE_12));
c.retry = 1;
c.oplen = sizeof(MMC_WRITE_12);
*/
c.retry = 1;
mmc_int_to_four_char(c.opcode + 2, start);
mmc_int_to_four_char(c.opcode + 6, len);
c.page = buf;
@ -469,9 +504,13 @@ int mmc_write(struct burn_drive *d, int start, struct buffer *buf)
/* a ssert(buf->bytes >= buf->sectors);*/ /* can be == at 0... */
burn_print(100, "trying to write %d at %d\n", len, start);
scsi_init_command(&c, MMC_WRITE_10, sizeof(MMC_WRITE_10));
/*
memcpy(c.opcode, MMC_WRITE_10, sizeof(MMC_WRITE_10));
c.retry = 1;
c.oplen = sizeof(MMC_WRITE_10);
*/
c.retry = 1;
mmc_int_to_four_char(c.opcode + 2, start);
c.opcode[6] = 0;
c.opcode[7] = (len >> 8) & 0xFF;
@ -570,7 +609,7 @@ int mmc_fake_toc(struct burn_drive *d)
struct burn_session *session;
struct burn_toc_entry *entry;
struct buffer buf;
int i, session_number, prev_session = -1, ret, lba;
int i, session_number, prev_session = -1, ret, lba, alloc_len = 34;
unsigned char *tdata, size_data[4], start_data[4];
char msg[160];
@ -618,7 +657,7 @@ int mmc_fake_toc(struct burn_drive *d)
leadout X entry i+X
*/
for (i = 0; i < d->last_track_no; i++) {
ret = mmc_read_track_info(d, i+1, &buf);
ret = mmc_read_track_info(d, i+1, &buf, alloc_len);
if (ret <= 0)
return ret;
tdata = buf.data;
@ -687,7 +726,7 @@ int mmc_fake_toc(struct burn_drive *d)
}
void mmc_read_toc(struct burn_drive *d)
static int mmc_read_toc_al(struct burn_drive *d, int *alloc_len)
{
/* read full toc, all sessions, in m/s/f form, 4k buffer */
/* ts A70201 : or fake a toc from track information */
@ -696,10 +735,14 @@ void mmc_read_toc(struct burn_drive *d)
struct buffer buf;
struct command c;
int dlen;
int i, bpl= 12;
int i, bpl= 12, old_alloc_len;
unsigned char *tdata;
mmc_function_spy("mmc_read_toc");
if (*alloc_len < 4)
return 0;
if (!(d->current_profile == -1 || d->current_is_cd_profile)) {
/* ts A70131 : MMC_GET_TOC uses Response Format 2
For DVD this fails with 5,24,00 */
@ -715,11 +758,17 @@ void mmc_read_toc(struct burn_drive *d)
if (d->status == BURN_DISC_UNREADY)
d->status = BURN_DISC_FULL;
return;
return 1;
}
scsi_init_command(&c, MMC_GET_TOC, sizeof(MMC_GET_TOC));
/*
memcpy(c.opcode, MMC_GET_TOC, sizeof(MMC_GET_TOC));
c.retry = 1;
c.oplen = sizeof(MMC_GET_TOC);
*/
c.dxfer_len = *alloc_len;
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
c.opcode[8] = c.dxfer_len & 0xff;
c.retry = 1;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
@ -746,11 +795,19 @@ void mmc_read_toc(struct burn_drive *d)
d->toc_entry = malloc(sizeof(struct burn_toc_entry));
memset(&(d->toc_entry[0]), 0, sizeof(struct burn_toc_entry));
return;
return 0;
}
dlen = c.page->data[0] * 256 + c.page->data[1];
old_alloc_len = *alloc_len;
*alloc_len = dlen + 2;
if (old_alloc_len < 15)
return 1;
if (dlen + 2 > old_alloc_len)
dlen = old_alloc_len - 2;
d->toc_entries = (dlen - 2) / 11;
if (d->toc_entries < 1)
return 0;
/*
some drives fail this check.
@ -839,6 +896,22 @@ void mmc_read_toc(struct burn_drive *d)
if (d->status == BURN_DISC_UNREADY)
d->status = BURN_DISC_FULL;
toc_find_modes(d);
return 1;
}
void mmc_read_toc(struct burn_drive *d)
{
int alloc_len = 4, ret;
ret = mmc_read_toc_al(d, &alloc_len);
/*
fprintf(stderr,
"LIBBURN_DEBUG: 43h READ TOC alloc_len = %d , ret = %d\n",
alloc_len, ret);
*/
if (alloc_len >= 15)
ret = mmc_read_toc_al(d, &alloc_len);
}
@ -852,7 +925,7 @@ int mmc_read_multi_session_c1(struct burn_drive *d, int *trackno, int *start)
struct buffer buf;
struct command c;
unsigned char *tdata;
int num_sessions, session_no, num_tracks;
int num_sessions, session_no, num_tracks, alloc_len = 12;
struct burn_disc *disc;
struct burn_session **sessions;
struct burn_track **tracks;
@ -895,9 +968,15 @@ inquire_drive:;
MMC-3 states that DVD had no tracks. So maybe this mandatory fake
is a forgotten legacy ?
*/
scsi_init_command(&c, MMC_GET_MSINFO, sizeof(MMC_GET_MSINFO));
/*
memcpy(c.opcode, MMC_GET_MSINFO, sizeof(MMC_GET_MSINFO));
c.retry = 1;
c.oplen = sizeof(MMC_GET_MSINFO);
*/
c.dxfer_len = alloc_len;
c.opcode[7]= (c.dxfer_len >> 8) & 0xff;
c.opcode[8]= c.dxfer_len & 0xff;
c.retry = 1;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
@ -914,14 +993,14 @@ inquire_drive:;
}
void mmc_read_disc_info(struct burn_drive *d)
static int mmc_read_disc_info_al(struct burn_drive *d, int *alloc_len)
{
struct buffer buf;
unsigned char *data;
struct command c;
char msg[160];
/* ts A70131 : had to move mmc_read_toc() to end of function */
int do_read_toc = 0, session_state, disc_status;
int do_read_toc = 0, session_state, disc_status, len, old_alloc_len;
/* ts A61020 */
d->start_lba = d->end_lba = -2000000000;
@ -935,14 +1014,23 @@ void mmc_read_disc_info(struct burn_drive *d)
/* ts A61202 */
d->toc_entries = 0;
if (d->status == BURN_DISC_EMPTY)
return;
return 1;
mmc_get_configuration(d);
if (*alloc_len < 2)
mmc_function_spy("mmc_read_disc_info");
scsi_init_command(&c, MMC_GET_DISC_INFO, sizeof(MMC_GET_DISC_INFO));
/*
memcpy(c.opcode, MMC_GET_DISC_INFO, sizeof(MMC_GET_DISC_INFO));
c.retry = 1;
c.oplen = sizeof(MMC_GET_DISC_INFO);
*/
c.dxfer_len = *alloc_len;
c.opcode[7]= (c.dxfer_len >> 8) & 0xff;
c.opcode[8]= c.dxfer_len & 0xff;
c.retry = 1;
c.page = &buf;
c.page->sectors = 0;
c.page->bytes = 0;
@ -951,10 +1039,20 @@ void mmc_read_disc_info(struct burn_drive *d)
if (c.error) {
d->busy = BURN_DRIVE_IDLE;
return;
return 0;
}
data = c.page->data;
len = (data[0] << 8) | data[1];
old_alloc_len = *alloc_len;
*alloc_len = len + 2;
if (old_alloc_len < 34)
return 1;
if (*alloc_len < 24) /* data[23] is the last byte used her */
return 0;
if (len + 2 > old_alloc_len)
len = old_alloc_len - 2;
d->erasable = !!(data[2] & 16);
disc_status = data[2] & 3;
@ -997,7 +1095,7 @@ void mmc_read_disc_info(struct burn_drive *d)
msg, 0,0);
}
d->status = BURN_DISC_UNSUITABLE;
return;
return 0;
}
/* >>> ts A61217 : Note for future
@ -1042,12 +1140,28 @@ void mmc_read_disc_info(struct burn_drive *d)
if (do_read_toc)
mmc_read_toc(d);
return 1;
}
void mmc_read_disc_info(struct burn_drive *d)
{
int alloc_len = 34, ret;
ret = mmc_read_disc_info_al(d, &alloc_len);
/*
fprintf(stderr,"LIBBURN_DEBUG: 51h alloc_len = %d , ret = %d\n",
alloc_len, ret);
*/
/* for now there is no need to inquire the variable lenght part */
}
void mmc_read_atip(struct burn_drive *d)
{
struct buffer buf;
struct command c;
int alloc_len = 28;
/* ts A61021 */
unsigned char *data;
@ -1063,9 +1177,16 @@ void mmc_read_atip(struct burn_drive *d)
/* 24, 32, 40, 48, -, -, -, - */
mmc_function_spy("mmc_read_atip");
scsi_init_command(&c, MMC_GET_ATIP, sizeof(MMC_GET_ATIP));
/*
memcpy(c.opcode, MMC_GET_ATIP, sizeof(MMC_GET_ATIP));
c.retry = 1;
c.oplen = sizeof(MMC_GET_ATIP);
*/
c.dxfer_len = alloc_len;
c.opcode[7]= (c.dxfer_len >> 8) & 0xff;
c.opcode[8]= c.dxfer_len & 0xff;
c.retry = 1;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
@ -1221,9 +1342,13 @@ void mmc_read_sectors(struct burn_drive *d,
/* a ssert(d->busy); */
burn_print(12, "reading %d from %d\n", len, start);
scsi_init_command(&c, MMC_READ_CD, sizeof(MMC_READ_CD));
/*
memcpy(c.opcode, MMC_READ_CD, sizeof(MMC_READ_CD));
c.retry = 1;
c.oplen = sizeof(MMC_READ_CD);
*/
c.retry = 1;
temp = start;
c.opcode[5] = temp & 0xFF;
temp >>= 8;
@ -1277,11 +1402,15 @@ void mmc_erase(struct burn_drive *d, int fast)
struct command c;
mmc_function_spy("mmc_erase");
scsi_init_command(&c, MMC_BLANK, sizeof(MMC_BLANK));
/*
memcpy(c.opcode, MMC_BLANK, sizeof(MMC_BLANK));
c.oplen = sizeof(MMC_BLANK);
*/
c.opcode[1] = 16; /* IMMED set to 1 */
c.opcode[1] |= !!fast;
c.retry = 1;
c.oplen = sizeof(MMC_BLANK);
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
@ -1294,9 +1423,12 @@ void mmc_read_lead_in(struct burn_drive *d, struct buffer *buf)
mmc_function_spy("mmc_read_lead_in");
len = buf->sectors;
scsi_init_command(&c, MMC_READ_CD, sizeof(MMC_READ_CD));
/*
memcpy(c.opcode, MMC_READ_CD, sizeof(MMC_READ_CD));
c.retry = 1;
c.oplen = sizeof(MMC_READ_CD);
*/
c.retry = 1;
c.opcode[5] = 0;
c.opcode[4] = 0;
c.opcode[3] = 0;
@ -1316,9 +1448,13 @@ void mmc_perform_opc(struct burn_drive *d)
struct command c;
mmc_function_spy("mmc_perform_opc");
scsi_init_command(&c, MMC_SEND_OPC, sizeof(MMC_SEND_OPC));
/*
memcpy(c.opcode, MMC_SEND_OPC, sizeof(MMC_SEND_OPC));
c.retry = 1;
c.oplen = sizeof(MMC_SEND_OPC);
*/
c.retry = 1;
c.opcode[1] = 1;
c.page = NULL;
c.dir = NO_TRANSFER;
@ -1343,9 +1479,12 @@ int mmc_set_streaming(struct burn_drive *d, int r_speed, int w_speed)
r_speed = 0x10000000; /* ~ 2 TB/s */
if (w_speed <= 0)
w_speed = 0x10000000; /* ~ 2 TB/s */
c.retry = 1;
scsi_init_command(&c, MMC_SET_STREAMING, sizeof(MMC_SET_STREAMING));
/*
c.oplen = sizeof(MMC_SET_STREAMING);
memcpy(c.opcode, MMC_SET_STREAMING, sizeof(MMC_SET_STREAMING));
*/
c.retry = 1;
c.page = &buf;
c.page->bytes = 28;
c.opcode[9] = (c.page->bytes >> 8) & 0xff;
@ -1427,9 +1566,12 @@ void mmc_set_speed(struct burn_drive *d, int r, int w)
if (w<=0 || w>0xffff)
w = 0xffff;
scsi_init_command(&c, MMC_SET_SPEED, sizeof(MMC_SET_SPEED));
/*
memcpy(c.opcode, MMC_SET_SPEED, sizeof(MMC_SET_SPEED));
c.retry = 1;
c.oplen = sizeof(MMC_SET_SPEED);
*/
c.retry = 1;
c.opcode[2] = r >> 8;
c.opcode[3] = r & 0xFF;
c.opcode[4] = w >> 8;
@ -1483,16 +1625,21 @@ static char *mmc_obtain_profile_name(int profile_number)
}
/* ts A61201 : found in unfunctional state */
void mmc_get_configuration(struct burn_drive *d)
/* ts A61201 : found in unfunctional state
*/
static int mmc_get_configuration_al(struct burn_drive *d, int *alloc_len)
{
struct buffer buf;
int len, cp, descr_len = 0, feature_code, prf_number, only_current = 1;
int old_alloc_len;
unsigned char *descr, *prf, *up_to, *prf_end;
struct command c;
int phys_if_std = 0;
char *phys_name = "";
if (*alloc_len < 8)
return 0;
d->current_profile = 0;
d->current_profile_text[0] = 0;
d->current_is_cd_profile = 0;
@ -1502,9 +1649,17 @@ void mmc_get_configuration(struct burn_drive *d)
d->current_feat2fh_byte4 = -1;
mmc_function_spy("mmc_get_configuration");
scsi_init_command(&c, MMC_GET_CONFIGURATION,
sizeof(MMC_GET_CONFIGURATION));
/*
memcpy(c.opcode, MMC_GET_CONFIGURATION, sizeof(MMC_GET_CONFIGURATION));
c.retry = 1;
c.oplen = sizeof(MMC_GET_CONFIGURATION);
*/
c.dxfer_len= *alloc_len;
c.retry = 1;
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
c.opcode[8] = c.dxfer_len & 0xff;
c.page = &buf;
c.page->sectors = 0;
c.page->bytes = 0;
@ -1512,11 +1667,13 @@ void mmc_get_configuration(struct burn_drive *d)
d->issue_command(d, &c);
if (c.error)
return;
len = mmc_four_char_to_int(c.page->data);
return 0;
old_alloc_len = *alloc_len;
*alloc_len = len = mmc_four_char_to_int(c.page->data);
if (len > old_alloc_len)
len = old_alloc_len;
if (len < 8 || len > 4096)
return;
return 0;
cp = (c.page->data[6]<<8) | c.page->data[7];
d->current_profile = cp;
strcpy(d->current_profile_text, mmc_obtain_profile_name(cp));
@ -1671,15 +1828,34 @@ void mmc_get_configuration(struct burn_drive *d)
}
}
return 1;
}
void mmc_get_configuration(struct burn_drive *d)
{
int alloc_len = 8, ret;
/* first command execution to learn Allocation Length */
ret = mmc_get_configuration_al(d, &alloc_len);
/*
fprintf(stderr,"LIBBURN_DEBUG: 46h alloc_len = %d , ret = %d\n",
alloc_len, ret);
*/
if (alloc_len > 8 && ret > 0)
/* second execution with announced length */
mmc_get_configuration_al(d, &alloc_len);
}
/* ts A70108 */
/* mmc5r03c.pdf 6.24 */
int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
static int mmc_read_format_capacities_al(struct burn_drive *d,
int *alloc_len, int top_wanted)
{
struct buffer buf;
int len, type, score, num_descr, max_score = -2000000000, i, sign = 1;
int old_alloc_len;
off_t size, num_blocks;
struct command c;
unsigned char *dpt;
@ -1689,18 +1865,26 @@ int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
mmc_function_spy("mmc_read_format_capacities");
if (*alloc_len < 4)
return 0;
d->format_descr_type = 3;
d->format_curr_max_size = 0;
d->format_curr_blsas = 0;
d->best_format_type = -1;
d->best_format_size = 0;
scsi_init_command(&c, MMC_READ_FORMAT_CAPACITIES,
sizeof(MMC_READ_FORMAT_CAPACITIES));
/*
memcpy(c.opcode, MMC_READ_FORMAT_CAPACITIES,
sizeof(MMC_READ_FORMAT_CAPACITIES));
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.dxfer_len = *alloc_len;
c.retry = 1;
c.opcode[7]= (c.dxfer_len >> 8) & 0xff;
c.opcode[8]= c.dxfer_len & 0xff;
c.page = &buf;
c.page->sectors = 0;
c.page->bytes = 0;
@ -1711,7 +1895,13 @@ int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
return 0;
len = c.page->data[3];
if (len<8)
old_alloc_len = *alloc_len;
*alloc_len = len + 4;
if (old_alloc_len < 12)
return 1;
if (len + 4 > old_alloc_len)
len = old_alloc_len - 4;
if (len < 8)
return 0;
dpt = c.page->data + 4;
@ -1807,14 +1997,34 @@ int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
}
int mmc_read_format_capacities(struct burn_drive *d, int top_wanted)
{
int alloc_len = 4, ret;
ret = mmc_read_format_capacities_al(d, &alloc_len, top_wanted);
/*
fprintf(stderr,"LIBBURN_DEBUG: 23h alloc_len = %d , ret = %d\n",
alloc_len, ret);
*/
if (alloc_len >= 12 && ret > 0)
ret = mmc_read_format_capacities_al(d, &alloc_len, top_wanted);
return ret;
}
void mmc_sync_cache(struct burn_drive *d)
{
struct command c;
mmc_function_spy("mmc_sync_cache");
scsi_init_command(&c, MMC_SYNC_CACHE, sizeof(MMC_SYNC_CACHE));
/*
memcpy(c.opcode, MMC_SYNC_CACHE, sizeof(MMC_SYNC_CACHE));
c.retry = 1;
c.oplen = sizeof(MMC_SYNC_CACHE);
*/
c.retry = 1;
c.page = NULL;
c.dir = NO_TRANSFER;
@ -1834,12 +2044,21 @@ int mmc_read_buffer_capacity(struct burn_drive *d)
struct buffer buf;
struct command c;
unsigned char *data;
int alloc_len = 12;
mmc_function_spy("mmc_read_buffer_capacity");
scsi_init_command(&c, MMC_READ_BUFFER_CAPACITY,
sizeof(MMC_READ_BUFFER_CAPACITY));
/*
memcpy(c.opcode, MMC_READ_BUFFER_CAPACITY,
sizeof(MMC_READ_BUFFER_CAPACITY));
c.retry = 1;
c.oplen = sizeof(MMC_READ_BUFFER_CAPACITY);
*/
c.dxfer_len = alloc_len;
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
c.opcode[8] = c.dxfer_len & 0xff;
c.retry = 1;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
@ -1889,9 +2108,13 @@ int mmc_format_unit(struct burn_drive *d, off_t size, int flag)
int full_format_type = 0x00; /* Full Format (or 0x10 for DVD-RW ?) */
mmc_function_spy("mmc_format_unit");
c.retry = 1;
scsi_init_command(&c, MMC_FORMAT_UNIT, sizeof(MMC_FORMAT_UNIT));
/*
c.oplen = sizeof(MMC_FORMAT_UNIT);
memcpy(c.opcode, MMC_FORMAT_UNIT, sizeof(MMC_FORMAT_UNIT));
*/
c.retry = 1;
c.page = &buf;
c.page->bytes = 12;
c.page->sectors = 0;
@ -2099,10 +2322,11 @@ unsuitable_media:;
/* ts A61225 */
int mmc_get_write_performance(struct burn_drive *d)
static int mmc_get_write_performance_al(struct burn_drive *d,
int *alloc_len, int *max_descr)
{
struct buffer buf;
int len, i, b, max_descr, num_descr, ret;
int len, i, b, num_descr, ret, old_alloc_len;
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 */
@ -2121,19 +2345,29 @@ int mmc_get_write_performance(struct burn_drive *d)
if (d->current_profile <= 0)
mmc_get_configuration(d);
if (*alloc_len < 8)
return 0;
scsi_init_command(&c, MMC_GET_PERFORMANCE,
sizeof(MMC_GET_PERFORMANCE));
/*
memcpy(c.opcode, MMC_GET_PERFORMANCE, sizeof(MMC_GET_PERFORMANCE));
c.oplen = sizeof(MMC_GET_PERFORMANCE);
*/
/* ts A70519 : now controlled externally
max_descr = ( BUFFER_SIZE - 8 ) / 16 - 1;
*/
/* >>> future: maintain a list of write descriptors
if (max_descr > d->max_write_descr - d->num_write_descr)
max_descr = d->max_write_descr;
*/
c.dxfer_len = *alloc_len;
c.opcode[8] = ( max_descr >> 8 ) & 0xff;
c.opcode[9] = ( max_descr >> 0 ) & 0xff;
c.opcode[8] = ( *max_descr >> 8 ) & 0xff;
c.opcode[9] = ( *max_descr >> 0 ) & 0xff;
c.opcode[10] = 3;
c.retry = 1;
c.oplen = sizeof(MMC_GET_PERFORMANCE);
c.page = &buf;
c.page->sectors = 0;
c.page->bytes = 0;
@ -2141,17 +2375,24 @@ int mmc_get_write_performance(struct burn_drive *d)
d->issue_command(d, &c);
if (c.error)
return 0;
len = (c.page->data[0] << 24)
+ (c.page->data[1] << 16)
+ (c.page->data[2] << 8)
+ c.page->data[3];
if (len<12)
len = mmc_four_char_to_int(c.page->data);
old_alloc_len = *alloc_len;
*alloc_len = len + 4;
if (len + 4 > old_alloc_len)
len = old_alloc_len - 4;
num_descr = ( *alloc_len - 8 ) / 16;
if (*max_descr == 0) {
*max_descr = num_descr;
return 1;
}
if (old_alloc_len < 16)
return 1;
if (len < 12)
return 0;
pd = c.page->data;
num_descr = ( len - 4 ) / 16;
if (num_descr > max_descr)
num_descr = max_descr;
if (num_descr > *max_descr)
num_descr = *max_descr;
for (i = 0; i < num_descr; i++) {
exact_bit = !!(pd[8 + i*16] & 2);
end_lba = read_speed = write_speed = 0;
@ -2214,6 +2455,24 @@ int mmc_get_write_performance(struct burn_drive *d)
}
int mmc_get_write_performance(struct burn_drive *d)
{
int alloc_len = 8, max_descr = 0, ret;
/* first command execution to learn number of descriptors and
dxfer_len */
ret = mmc_get_write_performance_al(d, &alloc_len, &max_descr);
/*
fprintf(stderr,"LIBBURN_DEBUG: ACh alloc_len = %d , ret = %d\n",
alloc_len, ret);
*/
if (max_descr > 0 && ret > 0)
/* second execution with announced length */
ret = mmc_get_write_performance_al(d, &alloc_len, &max_descr);
return ret;
}
/* ts A61021 : the mmc specific part of sg.c:enumerate_common()
*/
int mmc_setup_drive(struct burn_drive *d)

26
libburn/sbc.c

@ -11,19 +11,22 @@
#include "options.h"
/* spc command set */
static char SBC_LOAD[] = { 0x1b, 0, 0, 0, 3, 0 };
static char SBC_UNLOAD[] = { 0x1b, 0, 0, 0, 2, 0 };
static char SBC_START_UNIT[] = { 0x1b, 0, 0, 0, 1, 0 };
static unsigned char SBC_LOAD[] = { 0x1b, 0, 0, 0, 3, 0 };
static unsigned char SBC_UNLOAD[] = { 0x1b, 0, 0, 0, 2, 0 };
static unsigned char SBC_START_UNIT[] = { 0x1b, 0, 0, 0, 1, 0 };
void sbc_load(struct burn_drive *d)
{
struct command c;
scsi_init_command(&c, SBC_LOAD, sizeof(SBC_LOAD));
/*
memcpy(c.opcode, SBC_LOAD, sizeof(SBC_LOAD));
c.retry = 1;
c.oplen = sizeof(SBC_LOAD);
c.dir = NO_TRANSFER;
c.page = NULL;
*/
c.retry = 1;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
spc_wait_unit_attention(d, 60);
}
@ -32,11 +35,13 @@ void sbc_eject(struct burn_drive *d)
{
struct command c;
c.page = NULL;
scsi_init_command(&c, SBC_UNLOAD, sizeof(SBC_UNLOAD));
/*
memcpy(c.opcode, SBC_UNLOAD, sizeof(SBC_UNLOAD));
c.oplen = 1;
c.oplen = sizeof(SBC_UNLOAD);
c.page = NULL;
*/
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
@ -46,11 +51,14 @@ int sbc_start_unit(struct burn_drive *d)
{
struct command c;
scsi_init_command(&c, SBC_START_UNIT, sizeof(SBC_START_UNIT));
/*
memcpy(c.opcode, SBC_START_UNIT, sizeof(SBC_START_UNIT));
c.retry = 1;
c.oplen = sizeof(SBC_START_UNIT);
c.dir = NO_TRANSFER;
c.page = NULL;
*/
c.retry = 1;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
return (c.error==0);
}

148
libburn/spc.c

@ -29,7 +29,8 @@ extern struct libdax_msgs *libdax_messenger;
/* spc command set */
static unsigned char SPC_INQUIRY[] = { 0x12, 0, 0, 0, 255, 0 };
/* ts A70519 : allocation length byte 3+4 was 0,255 */
static unsigned char SPC_INQUIRY[] = { 0x12, 0, 0, 0, 36, 0 };
/*static char SPC_TEST[]={0,0,0,0,0,0};*/
static unsigned char SPC_PREVENT[] = { 0x1e, 0, 0, 0, 1, 0 };
@ -40,14 +41,35 @@ static unsigned char SPC_MODE_SELECT[] =
static unsigned char SPC_REQUEST_SENSE[] = { 0x03, 0, 0, 0, 18, 0 };
static unsigned char SPC_TEST_UNIT_READY[] = { 0x00, 0, 0, 0, 0, 0 };
/* ts A70519 : An initializer for the abstract SCSI command structure */
int scsi_init_command(struct command *c, unsigned char *opcode, int oplen)
{
if (oplen > 16)
return 0;
memcpy(c->opcode, opcode, oplen);
c->oplen = oplen;
c->dir = NO_TRANSFER;
c->dxfer_len = -1;
memset(c->sense, 0, sizeof(c->sense));
c->error = 0;
c->retry = 0;
c->page = NULL;
return 1;
}
int spc_test_unit_ready_r(struct burn_drive *d, int *key, int *asc, int *ascq)
{
struct command c;
c.retry = 0;
scsi_init_command(&c, SPC_TEST_UNIT_READY,sizeof(SPC_TEST_UNIT_READY));
/*
c.oplen = sizeof(SPC_TEST_UNIT_READY);
memcpy(c.opcode, SPC_TEST_UNIT_READY, sizeof(SPC_TEST_UNIT_READY));
c.page = NULL;
*/
c.retry = 0;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
if (c.error) {
@ -68,7 +90,7 @@ int spc_test_unit_ready(struct burn_drive *d)
/* ts A70315 */
/** Wait until the drive state becomes clear in or until max_usec elapsed */
/** Wait until the drive state becomes clear or until max_usec elapsed */
int spc_wait_unit_attention(struct burn_drive *d, int max_sec)
{
int i, ret, key, asc, ascq;
@ -89,9 +111,14 @@ void spc_request_sense(struct burn_drive *d, struct buffer *buf)
{
struct command c;
scsi_init_command(&c, SPC_REQUEST_SENSE, sizeof(SPC_REQUEST_SENSE));
c.retry = 0;
/*
c.oplen = sizeof(SPC_REQUEST_SENSE);
memcpy(c.opcode, SPC_REQUEST_SENSE, sizeof(SPC_REQUEST_SENSE));
*/
c.dxfer_len= c.opcode[4];
c.retry = 0;
c.page = buf;
c.page->sectors = 0;
c.page->bytes = 0;
@ -113,24 +140,29 @@ void spc_inquiry(struct burn_drive *d)
struct burn_scsi_inquiry_data *id;
struct command c;
scsi_init_command(&c, SPC_INQUIRY, sizeof(SPC_INQUIRY));
/*
memcpy(c.opcode, SPC_INQUIRY, sizeof(SPC_INQUIRY));
c.retry = 1;
c.oplen = sizeof(SPC_INQUIRY);
*/
c.dxfer_len= (c.opcode[3] << 8) | c.opcode[4];
c.retry = 1;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
id = (struct burn_scsi_inquiry_data *)d->idata;
id->vendor[8] = 0;
id->product[16] = 0;
id->revision[4] = 0;
memset(id->vendor, 0, 9);
memset(id->product, 0, 17);
memset(id->revision, 0, 5);
if (c.error) {
id->valid = -1;
return;
}
memcpy(id->vendor, c.page->data + 8, 8);
memcpy(id->product, c.page->data + 16, 16);
memcpy(id->revision, c.page->data + 32, 4);
id->valid = 1;
return;
}
@ -139,10 +171,13 @@ void spc_prevent(struct burn_drive *d)
{
struct command c;
scsi_init_command(&c, SPC_PREVENT, sizeof(SPC_PREVENT));
/*
memcpy(c.opcode, SPC_PREVENT, sizeof(SPC_PREVENT));
c.retry = 1;
c.oplen = sizeof(SPC_PREVENT);
c.page = NULL;
*/
c.retry = 1;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
@ -151,19 +186,27 @@ void spc_allow(struct burn_drive *d)
{
struct command c;
scsi_init_command(&c, SPC_ALLOW, sizeof(SPC_ALLOW));
/*
memcpy(c.opcode, SPC_ALLOW, sizeof(SPC_ALLOW));
c.retry = 1;
c.oplen = sizeof(SPC_ALLOW);
c.page = NULL;
*/
c.retry = 1;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
void spc_sense_caps(struct burn_drive *d)
/*
ts A70518 : Do not call with *alloc_len < 8
*/
/** flag&1= do only inquire alloc_len */
static int spc_sense_caps_al(struct burn_drive *d, int *alloc_len, int flag)
{
struct buffer buf;
struct scsi_mode_data *m;
int size, page_length, num_write_speeds = 0, i, speed, ret;
int old_alloc_len, was_error = 0;
unsigned char *page;
struct command c;
struct burn_speed_descriptor *sd;
@ -171,18 +214,30 @@ void spc_sense_caps(struct burn_drive *d)
/* ts A61225 : 1 = report about post-MMC-1 speed descriptors */
static int speed_debug = 0;
if (*alloc_len < 8)
return 0;
memset(&buf, 0, sizeof(buf));
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
/*
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SENSE);
*/
c.dxfer_len = *alloc_len;
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
c.opcode[8] = c.dxfer_len & 0xff;
c.retry = 1;
c.opcode[2] = 0x2A;
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
if (c.error)
if (c.error) {
memset(&buf, 0, sizeof(buf));
d->mdata->valid = -1;
was_error = 1;
}
size = c.page->data[0] * 256 + c.page->data[1];
m = d->mdata;
@ -195,6 +250,14 @@ void spc_sense_caps(struct burn_drive *d)
set of speed descriptors. In MMC-5 E.11 it is declared "legacy".
*/
page_length = page[1];
old_alloc_len = *alloc_len;
*alloc_len = page_length + 8;
if (flag & 1)
return !was_error;
if (page_length + 8 > old_alloc_len)
page_length = old_alloc_len - 8;
if (page_length < 22)
return 0;
m->valid = 0;
burn_mdata_free_subs(m);
@ -253,7 +316,7 @@ void spc_sense_caps(struct burn_drive *d)
0x0002013c,
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
msg, 0, 0);
return;
return 0;
}
for (i = 0; i < num_write_speeds; i++) {
@ -297,6 +360,24 @@ try_mmc_get_performance:;
fprintf(stderr,
"LIBBURN_DEBUG: ACh min_write_speed = %d , max_write_speed = %d\n",
m->min_write_speed, m->max_write_speed);
return !was_error;
}
void spc_sense_caps(struct burn_drive *d)
{
int alloc_len, start_len = 22, ret;
/* first command execution to learn Allocation Length */
alloc_len = start_len;
ret = spc_sense_caps_al(d, &alloc_len, 1);
/*
fprintf(stderr,"LIBBURN_DEBUG: 5Ah alloc_len = %d , ret = %d\n",
alloc_len, ret);
*/
if (alloc_len >= start_len && ret > 0)
/* second execution with announced length */
spc_sense_caps_al(d, &alloc_len, 0);
}
@ -304,13 +385,19 @@ void spc_sense_error_params(struct burn_drive *d)
{
struct buffer buf;
struct scsi_mode_data *m;
int size;
int size, alloc_len = 12 ;
unsigned char *page;
struct command c;
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
/*
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SENSE);
*/
c.dxfer_len = alloc_len;
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
c.opcode[8] = c.dxfer_len & 0xff;
c.retry = 1;
c.opcode[2] = 0x01;
c.page = &buf;
c.page->bytes = 0;
@ -332,9 +419,12 @@ void spc_select_error_params(struct burn_drive *d,
struct buffer buf;
struct command c;
scsi_init_command(&c, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
/*
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SELECT);
*/
c.retry = 1;
c.opcode[8] = 8 + 2 + d->mdata->retry_page_length;
c.page = &buf;
c.page->bytes = 0;
@ -363,7 +453,7 @@ void spc_sense_write_params(struct burn_drive *d)
{
struct buffer buf;
struct scsi_mode_data *m;
int size, dummy;
int size, dummy, alloc_len = 10;
unsigned char *page;
struct command c;
@ -371,9 +461,15 @@ void spc_sense_write_params(struct burn_drive *d)
/* a ssert(d->mdata->cdr_write || d->mdata->cdrw_write ||
d->mdata->dvdr_write || d->mdata->dvdram_write); */
scsi_init_command(&c, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
/*
memcpy(c.opcode, SPC_MODE_SENSE, sizeof(SPC_MODE_SENSE));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SENSE);
*/
c.dxfer_len = alloc_len;
c.opcode[7] = (c.dxfer_len >> 8) & 0xff;
c.opcode[8] = c.dxfer_len & 0xff;
c.retry = 1;
c.opcode[2] = 0x05;
c.page = &buf;
c.page->bytes = 0;
@ -428,9 +524,12 @@ void spc_select_write_params(struct burn_drive *d,
o->block_type,spc_block_type(o->block_type));
*/
scsi_init_command(&c, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
/*
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SELECT);
*/
c.retry = 1;
c.opcode[8] = 8 + 2 + d->mdata->write_page_length;
c.page = &buf;
c.page->bytes = 0;
@ -488,9 +587,12 @@ void spc_probe_write_modes(struct burn_drive *d)
try_block_type = useable_block_type;
last_try= 1;
}
scsi_init_command(&c, SPC_MODE_SELECT,sizeof(SPC_MODE_SELECT));
/*
memcpy(c.opcode, SPC_MODE_SELECT, sizeof(SPC_MODE_SELECT));
c.retry = 1;
c.oplen = sizeof(SPC_MODE_SELECT);
*/
c.retry = 1;
c.opcode[8] = 8 + 2 + 0x32;
c.page = &buf;

3
libburn/spc.h

@ -55,4 +55,7 @@ enum response scsi_error_msg(struct burn_drive *d, unsigned char *sense,
int scsi_notify_error(struct burn_drive *, struct command *c,
unsigned char *sense, int senselen, int flag);
/* ts A70519 */
int scsi_init_command(struct command *c, unsigned char *opcode, int oplen);
#endif /*__SPC*/

5
libburn/toc.c

@ -128,9 +128,14 @@ void toc_find_modes(struct burn_drive *d)
if (e && !(e->control & 4)) {
t->mode = BURN_AUDIO;
} else {
t->mode = BURN_MODE1;
/* ts A70519 : this does not work with Linux 2.4 USB because one cannot
predict the exact dxfer_size without knowing the sector type.
mem.sectors = 1;
d->read_sectors(d, lba, mem.sectors, &o, &mem);
t->mode = sector_identify(mem.data);
*/
}
}
}

1
libburn/transport.h

@ -51,6 +51,7 @@ struct command
unsigned char opcode[16];
int oplen;
int dir;
int dxfer_len;
unsigned char sense[128];
int error;
int retry;

Loading…
Cancel
Save