From 60e2e7df283a72f120a8a6d4e4d3ed60def39d9c Mon Sep 17 00:00:00 2001 From: Thomas Schmitt Date: Sun, 18 Oct 2015 12:52:08 +0000 Subject: [PATCH] New API calls burn_drive_get_serial_no() and burn_drive_get_media_sno() --- cdrskin/cdrskin_timestamp.h | 2 +- libburn/drive.c | 78 ++++++++++++++++++++++++++ libburn/libburn.h | 52 +++++++++++++++++ libburn/mmc.c | 27 +++++++-- libburn/spc.c | 109 ++++++++++++++++++++++++++++++++++++ libburn/spc.h | 5 ++ libburn/transport.h | 12 +++- 7 files changed, 278 insertions(+), 7 deletions(-) diff --git a/cdrskin/cdrskin_timestamp.h b/cdrskin/cdrskin_timestamp.h index 07816d0..03ba242 100644 --- a/cdrskin/cdrskin_timestamp.h +++ b/cdrskin/cdrskin_timestamp.h @@ -1 +1 @@ -#define Cdrskin_timestamP "2015.09.23.110012" +#define Cdrskin_timestamP "2015.10.18.125353" diff --git a/libburn/drive.c b/libburn/drive.c index d5f1277..1cb7530 100644 --- a/libburn/drive.c +++ b/libburn/drive.c @@ -89,6 +89,10 @@ int burn_setup_drive(struct burn_drive *d, char *fname) d->stream_recording_start= 0; d->role_5_nwa = 0; 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; } @@ -704,6 +708,14 @@ int burn_drive_release_fl(struct burn_drive *d, int flag) } 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; /* 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; +} + diff --git a/libburn/libburn.h b/libburn/libburn.h index 45b5deb..7709c5e 100644 --- a/libburn/libburn.h +++ b/libburn/libburn.h @@ -1257,6 +1257,51 @@ int burn_disc_pretend_full(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 */ /** Reads ATIP information from inserted media. To be obtained via 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 */ +/* 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*/ diff --git a/libburn/mmc.c b/libburn/mmc.c index 8f743c1..e4ce941 100644 --- a/libburn/mmc.c +++ b/libburn/mmc.c @@ -1,7 +1,7 @@ /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens - Copyright (c) 2006 - 2014 Thomas Schmitt + Copyright (c) 2006 - 2015 Thomas Schmitt Provided under GPL version 2 or later. */ @@ -257,7 +257,7 @@ static unsigned char MMC_READ_CAPACITY[] = static unsigned char MMC_READ_DISC_STRUCTURE[] = { 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[] = { 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] & 2)); - } else if (feature_code == 0x108 || feature_code == 0x10c) { - int i, c_limit; +#endif /* Libburn_print_feature_descriptorS */ + } else if (feature_code == 0x108 || feature_code == 0x10c) { + int c_limit; + +#ifdef Libburn_print_feature_descriptorS + int i; fprintf(stderr, "LIBBURN_EXPERIMENTAL : %s = ", feature_code == 0x108 ? "Drive Serial Number" : "Drive Firmware Date"); +#endif /* Libburn_print_feature_descriptorS */ + 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++) if (descr[4 + i] < 0x20 || descr[4 + i] > 0x7e || descr[4 + i] == '\\') @@ -5281,7 +5299,6 @@ ex:; } - /* ts A61021 : the mmc specific part of sg.c:enumerate_common() */ int mmc_setup_drive(struct burn_drive *d) diff --git a/libburn/spc.c b/libburn/spc.c index fcbbb7d..8be6fa2 100644 --- a/libburn/spc.c +++ b/libburn/spc.c @@ -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_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 */ int scsi_init_command(struct command *c, unsigned char *opcode, int oplen) @@ -891,6 +895,109 @@ ex:; 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) { if (mmc_function_spy(d, "getcaps") <= 0) @@ -1554,6 +1661,8 @@ static char *scsi_command_name(unsigned int c, int flag) return "BLANK"; case 0xaa: return "WRITE(12)"; + case 0xab: + return "READ MEDIA SERIAL NUMBER"; case 0xac: return "GET PERFORMANCE"; case 0xad: diff --git a/libburn/spc.h b/libburn/spc.h index 81f635a..7b7512e 100644 --- a/libburn/spc.h +++ b/libburn/spc.h @@ -23,6 +23,11 @@ void spc_sense_write_params(struct burn_drive *); void spc_select_write_params(struct burn_drive *, struct burn_session *, int, 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_request_sense(struct burn_drive *d, struct buffer *buf); int spc_block_type(enum burn_block_types b); diff --git a/libburn/transport.h b/libburn/transport.h index ec4579f..9ccbc42 100644 --- a/libburn/transport.h +++ b/libburn/transport.h @@ -1,7 +1,7 @@ /* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */ /* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens - Copyright (c) 2006 - 2014 Thomas Schmitt + Copyright (c) 2006 - 2015 Thomas Schmitt Provided under GPL version 2 or later. */ @@ -253,6 +253,16 @@ struct burn_drive */ 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. bit0= damage bit , bit1= nwa valid bit */