New API calls burn_drive_get_serial_no() and burn_drive_get_media_sno()

This commit is contained in:
Thomas Schmitt 2015-10-18 12:52:08 +00:00
parent 948e2035fc
commit ef6c211e4c
7 changed files with 278 additions and 7 deletions

View File

@ -1 +1 @@
#define Cdrskin_timestamP "2015.09.23.110012" #define Cdrskin_timestamP "2015.10.18.125353"

View File

@ -89,6 +89,10 @@ int burn_setup_drive(struct burn_drive *d, char *fname)
d->stream_recording_start= 0; d->stream_recording_start= 0;
d->role_5_nwa = 0; d->role_5_nwa = 0;
d->features = NULL; d->features = NULL;
d->drive_serial_number = NULL;
d->drive_serial_number_len = -1;
d->media_serial_number = NULL;
d->media_serial_number_len = -1;
return 1; return 1;
} }
@ -704,6 +708,14 @@ int burn_drive_release_fl(struct burn_drive *d, int flag)
} }
d->needs_sync_cache = 0; /* just to be sure */ d->needs_sync_cache = 0; /* just to be sure */
if (d->drive_serial_number != NULL)
BURN_FREE_MEM(d->drive_serial_number);
if (d->media_serial_number != NULL)
BURN_FREE_MEM(d->media_serial_number);
d->drive_serial_number = d->media_serial_number = NULL;
d->drive_serial_number_len = d->media_serial_number_len = 0;
d->released = 1; d->released = 1;
/* ts A61125 : outsourced model aspects */ /* ts A61125 : outsourced model aspects */
@ -3490,3 +3502,69 @@ int burn_drive_has_feature(struct burn_drive *d, int feature_code,
} }
/* ts B51016 API */
int burn_drive_get_serial_no(struct burn_drive *d, char **sno, int *sno_len)
{
int ret;
if (*sno != NULL)
BURN_FREE_MEM(*sno);
if (d->drive_serial_number_len > 0)
*sno_len = d->drive_serial_number_len;
else
*sno_len = 0;
BURN_ALLOC_MEM(*sno, char, *sno_len + 1);
if (d->drive_serial_number_len > 0)
memcpy(*sno, d->drive_serial_number, *sno_len);
(*sno)[*sno_len] = 0;
ret = 1;
ex:
return ret;
}
/* ts B51016 API */
int burn_drive_get_media_sno(struct burn_drive *d, char **sno, int *sno_len)
{
int ret;
#ifdef Libburn_enable_scsi_cmd_ABh
struct burn_feature_descr *feat;
#endif
if (*sno != NULL)
BURN_FREE_MEM(*sno);
*sno = NULL;
if (d->media_serial_number_len == -1) {
#ifdef Libburn_enable_scsi_cmd_ABh
if (burn_drive_has_feature(d, 0x109, &feat, 0))
#ifndef Libburn_enable_scsi_cmd_ABh_pretend_currenT
if (feat->flags & 1) /* current */
#endif
spc_read_media_serial_number(d);
#else
;
#endif /* ! Libburn_enable_scsi_cmd_ABh */
}
if (d->media_serial_number_len > 0)
*sno_len = d->media_serial_number_len;
else
*sno_len = 0;
BURN_ALLOC_MEM(*sno, char, *sno_len + 1);
if (*sno_len > 0)
memcpy(*sno, d->media_serial_number, *sno_len);
(*sno)[*sno_len] = 0;
ret = 1;
ex:
return ret;
}

View File

@ -1257,6 +1257,51 @@ int burn_disc_pretend_full(struct burn_drive *drive);
int burn_disc_pretend_full_uncond(struct burn_drive *drive); int burn_disc_pretend_full_uncond(struct burn_drive *drive);
/* ts B51016 */
/** Returns the Drive Serial Number as of MMC feature 108h.
@param d The drive to inquire.
@param sno Returns the bytes of the serial number. A trailing 0-byte
is appended for convenience. MMC specifies ASCII 0x20 to
0x7h as possible byte values. But given drive firmware
habits there is no warranty that *sno contains no other
byte values.
Submit *sno as NULL or pointing to free()-able memory.
Apply free() to *sno when no longer needed.
@param sno_len Returns the number of valid bytes in returned *sno,
not counting the appended trailing 0.
@return 1= success (but maybe *sno_len is 0), <= 0 severe failure
@since 1.4.2
*/
int burn_drive_get_serial_no(struct burn_drive *d, char **sno, int *sno_len);
/* ts B51016 */
/** Returns the Media Serial Number as of MMC feature 109h and command ABh
READ MEDIA SERIAL NUMBER.
Note: This call will return an empty result unless the macro
Libburn_enable_scsi_cmd_ABh
is defined at compile time.
This is because the command READ MEDIA SERIAL NUMBER demands
superuser authority on Linux, because no medium with serial number
could be tested yet, and because this command made one of the test
drives unusable until power cycle when it was executed despite
feature 109h was not announced as "current".
@param d The drive to inquire.
@param sno Returns the bytes of the serial number. A trailing 0-byte
is appended for convenience. There is no warranty that
*sno contains no other byte values.
Submit *sno as NULL or pointing to free()-able memory.
Apply free() to *sno when no longer needed.
@param sno_len Returns the number of valid bytes in returned *sno,
not counting the appended trailing 0.
@return 1= success (but maybe *sno_len is 0), <= 0 severe failure
@since 1.4.2
*/
int burn_drive_get_media_sno(struct burn_drive *d, char **sno, int *sno_len);
/* ts A61021 */ /* ts A61021 */
/** Reads ATIP information from inserted media. To be obtained via /** Reads ATIP information from inserted media. To be obtained via
burn_drive_get_write_speed(), burn_drive_get_min_write_speed(), burn_drive_get_write_speed(), burn_drive_get_min_write_speed(),
@ -4274,5 +4319,12 @@ int burn_nec_optiarc_rep_err_rate(struct burn_drive *d,
#endif /* Libburn_develop_quality_scaN */ #endif /* Libburn_develop_quality_scaN */
/* Linux 3.16 problems with ABh Read Media Serial Number:
- as normal user lets ioctl(SG_IO) return -1 and errno = EFAULT
- as superuser renders LG BH16NS40 unusable until power cycle
#de fine Libburn_enable_scsi_cmd_ABh yes
#de fine Libburn_enable_scsi_cmd_ABh_pretend_currenT yes
*/
#endif /*LIBBURN_H*/ #endif /*LIBBURN_H*/

View File

@ -1,7 +1,7 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens /* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
Copyright (c) 2006 - 2014 Thomas Schmitt <scdbackup@gmx.net> Copyright (c) 2006 - 2015 Thomas Schmitt <scdbackup@gmx.net>
Provided under GPL version 2 or later. Provided under GPL version 2 or later.
*/ */
@ -257,7 +257,7 @@ static unsigned char MMC_READ_CAPACITY[] =
static unsigned char MMC_READ_DISC_STRUCTURE[] = static unsigned char MMC_READ_DISC_STRUCTURE[] =
{ 0xAD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; { 0xAD, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
/* ts B21125 : An alternatvie to BEh READ CD /* ts B21125 : An alternative to BEh READ CD
*/ */
static unsigned char MMC_READ_CD_MSF[] = static unsigned char MMC_READ_CD_MSF[] =
{ 0xB9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; { 0xB9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
@ -3225,13 +3225,31 @@ static int mmc_get_configuration_al(struct burn_drive *d, int *alloc_len)
!!(descr[4] & 8), !!(descr[4] & 4), !!(descr[4] & 8), !!(descr[4] & 4),
!!(descr[4] & 2)); !!(descr[4] & 2));
} else if (feature_code == 0x108 || feature_code == 0x10c) { #endif /* Libburn_print_feature_descriptorS */
int i, c_limit;
} else if (feature_code == 0x108 || feature_code == 0x10c) {
int c_limit;
#ifdef Libburn_print_feature_descriptorS
int i;
fprintf(stderr, "LIBBURN_EXPERIMENTAL : %s = ", fprintf(stderr, "LIBBURN_EXPERIMENTAL : %s = ",
feature_code == 0x108 ? feature_code == 0x108 ?
"Drive Serial Number" : "Drive Firmware Date"); "Drive Serial Number" : "Drive Firmware Date");
#endif /* Libburn_print_feature_descriptorS */
c_limit = descr[3] - 2 * (feature_code == 0x10c); c_limit = descr[3] - 2 * (feature_code == 0x10c);
if (feature_code == 0x108) {
if (d->drive_serial_number != NULL)
BURN_FREE_MEM(d->drive_serial_number);
BURN_ALLOC_MEM(d->drive_serial_number,
char, c_limit + 1);
memcpy(d->drive_serial_number, descr + 4,
c_limit);
d->drive_serial_number[c_limit] = 0;
d->drive_serial_number_len = c_limit;
}
#ifdef Libburn_print_feature_descriptorS
for (i = 0; i < c_limit; i++) for (i = 0; i < c_limit; i++)
if (descr[4 + i] < 0x20 || descr[4 + i] > 0x7e if (descr[4 + i] < 0x20 || descr[4 + i] > 0x7e
|| descr[4 + i] == '\\') || descr[4 + i] == '\\')
@ -5281,7 +5299,6 @@ ex:;
} }
/* ts A61021 : the mmc specific part of sg.c:enumerate_common() /* ts A61021 : the mmc specific part of sg.c:enumerate_common()
*/ */
int mmc_setup_drive(struct burn_drive *d) int mmc_setup_drive(struct burn_drive *d)

View File

@ -59,6 +59,10 @@ static unsigned char SPC_MODE_SELECT[] = { 0x55, 16, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char SPC_REQUEST_SENSE[] = { 0x03, 0, 0, 0, 18, 0 }; 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 }; static unsigned char SPC_TEST_UNIT_READY[] = { 0x00, 0, 0, 0, 0, 0 };
#ifdef Libburn_enable_scsi_cmd_ABh
static unsigned char SPC_READ_MEDIA_SERIAL_NUMBER[] =
{ 0xAB, 0x01, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
#endif
/* ts A70519 : An initializer for the abstract SCSI command structure */ /* ts A70519 : An initializer for the abstract SCSI command structure */
int scsi_init_command(struct command *c, unsigned char *opcode, int oplen) int scsi_init_command(struct command *c, unsigned char *opcode, int oplen)
@ -891,6 +895,109 @@ ex:;
BURN_FREE_MEM(c); BURN_FREE_MEM(c);
} }
#ifdef Libburn_enable_scsi_cmd_ABh
/* At least on Linux kernel 3.16 the command ABh causes EFAULT if not sent
from the superuser.
For a test it may be replaced by a dummy 28h READ12 on block 0.
This causes no EFAULT although it sets the wrong dxfer_len 4 rather
than 2048. So it is indeed a permission problem and not bad alignment.
*/
/* ts B51016 */
int spc_read_media_serial_number_al(struct burn_drive *d, int *alloc_len)
{
struct buffer *buf = NULL;
struct command *c = NULL;
unsigned char *data;
int ret;
if (*alloc_len < 4)
{ret = 0; goto ex;}
BURN_ALLOC_MEM(buf, struct buffer, 1);
BURN_ALLOC_MEM(c, struct command, 1);
if (mmc_function_spy(d, "spc_read_media_serial_number") <= 0)
{ret = 0; goto ex;}
/*
#de fine Spc_read_media_serial_number_dummY yes
*/
#ifdef Spc_read_media_serial_number_dummY
{
static unsigned char MMC_READ_12[] =
{ 0x28, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0 };
scsi_init_command(c, MMC_READ_12, sizeof(MMC_READ_12));
c->dxfer_len = *alloc_len;
}
#else
scsi_init_command(c, SPC_READ_MEDIA_SERIAL_NUMBER,
sizeof(SPC_READ_MEDIA_SERIAL_NUMBER));
c->dxfer_len = *alloc_len;
/* (Will not accept more than 32 KB anyway) */
c->opcode[8] = (c->dxfer_len >> 8) & 0xff;
c->opcode[9] = c->dxfer_len & 0xff;
#endif /* ! Spc_read_media_serial_number_dummY */
c->retry = 1;
c->page = buf;
memset(c->page->data, 0, *alloc_len);
c->page->bytes = 0;
c->page->sectors = 0;
c->dir = FROM_DRIVE;
d->issue_command(d, c);
if (c->error)
{ret = 0; goto ex;}
data = c->page->data;
#ifdef Spc_read_media_serial_number_dummY
d->media_serial_number_len = 0;
#else
d->media_serial_number_len =
(data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[7];
#endif
if (*alloc_len >= d->media_serial_number_len + 4) {
if (d->media_serial_number != NULL)
BURN_FREE_MEM(d->media_serial_number);
BURN_ALLOC_MEM(d->media_serial_number, char,
d->media_serial_number_len + 1);
if (d->media_serial_number_len > 0)
memcpy(d->media_serial_number, data + 4,
d->media_serial_number_len);
d->media_serial_number[d->media_serial_number_len] = 0;
}
*alloc_len = d->media_serial_number_len + 4;
ret = 1;
ex:;
BURN_FREE_MEM(c);
BURN_FREE_MEM(buf);
return ret;
}
int spc_read_media_serial_number(struct burn_drive *d)
{
int alloc_len = 4, ret;
ret = spc_read_media_serial_number_al(d, &alloc_len);
if (alloc_len > 4 && alloc_len <= 0x8000 && ret > 0)
ret = spc_read_media_serial_number_al(d, &alloc_len);
return ret;
}
#endif /* Libburn_enable_scsi_cmd_ABh */
void spc_getcaps(struct burn_drive *d) void spc_getcaps(struct burn_drive *d)
{ {
if (mmc_function_spy(d, "getcaps") <= 0) if (mmc_function_spy(d, "getcaps") <= 0)
@ -1554,6 +1661,8 @@ static char *scsi_command_name(unsigned int c, int flag)
return "BLANK"; return "BLANK";
case 0xaa: case 0xaa:
return "WRITE(12)"; return "WRITE(12)";
case 0xab:
return "READ MEDIA SERIAL NUMBER";
case 0xac: case 0xac:
return "GET PERFORMANCE"; return "GET PERFORMANCE";
case 0xad: case 0xad:

View File

@ -23,6 +23,11 @@ void spc_sense_write_params(struct burn_drive *);
void spc_select_write_params(struct burn_drive *, void spc_select_write_params(struct burn_drive *,
struct burn_session *, int, struct burn_session *, int,
const struct burn_write_opts *); const struct burn_write_opts *);
#ifdef Libburn_enable_scsi_cmd_ABh
int spc_read_media_serial_number(struct burn_drive *d);
#endif
void spc_probe_write_modes(struct burn_drive *); void spc_probe_write_modes(struct burn_drive *);
void spc_request_sense(struct burn_drive *d, struct buffer *buf); void spc_request_sense(struct burn_drive *d, struct buffer *buf);
int spc_block_type(enum burn_block_types b); int spc_block_type(enum burn_block_types b);

View File

@ -1,7 +1,7 @@
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
/* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens /* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
Copyright (c) 2006 - 2014 Thomas Schmitt <scdbackup@gmx.net> Copyright (c) 2006 - 2015 Thomas Schmitt <scdbackup@gmx.net>
Provided under GPL version 2 or later. Provided under GPL version 2 or later.
*/ */
@ -253,6 +253,16 @@ struct burn_drive
*/ */
int current_feat2fh_byte4; int current_feat2fh_byte4;
/* ts B51016 : Result from feature 108h : Drive Serial Number
*/
char *drive_serial_number;
char drive_serial_number_len;
/* ts B51016 : Result from command AB READ MEDIA SERIAL NUMBER
*/
char *media_serial_number;
char media_serial_number_len;
/* ts B10524 : whether the damage bit was set for the future track. /* ts B10524 : whether the damage bit was set for the future track.
bit0= damage bit , bit1= nwa valid bit bit0= damage bit , bit1= nwa valid bit
*/ */