Adds the SCSI Read Disc Information command, which should be given for multimedia device consumers to retrieve the DVD/BD disk information about: * Total tracks contained at the disc Total and active sessions Border * status(incomplete, damaged, etc.) This information is wanted for supporting the DVD-ROM and BD-ROM devices. End-user-impact: Now, multimedia device consumers have a way to retrieve the multimedia disk information. Signed-off-by: Igor Kononenko <i.kononenko@xxxxxxxxx> --- drivers/usb/gadget/function/f_mass_storage.c | 37 ++++ include/scsi/scsi_proto.h | 1 + include/uapi/linux/cdrom.h | 195 +++++++++++++++++-- 3 files changed, 212 insertions(+), 21 deletions(-) diff --git a/drivers/usb/gadget/function/f_mass_storage.c b/drivers/usb/gadget/function/f_mass_storage.c index 7e736e5594f9..d3d8a806b5e6 100644 --- a/drivers/usb/gadget/function/f_mass_storage.c +++ b/drivers/usb/gadget/function/f_mass_storage.c @@ -1932,6 +1932,40 @@ static void send_status(struct fsg_common *common) return; } +static int do_read_disc_info(struct fsg_common *common, struct fsg_buffhd *bh) +{ + struct fsg_lun *curlun = common->curlun; + struct cdb_disc_info *cdb = (struct cdb_disc_info *)common->cmnd; + disc_information *info = (disc_information *)bh->buf; + + if (cdb->type != DISC_TYPE_STANDARD) { + LERROR(curlun, + "Unsupported disc information type(%02Xh) requested\n", + cdb->type); + return -EINVAL; + } + memset(info, 0, sizeof(disc_information)); + info->disc_information_length = cpu_to_be16( + sizeof(*info) - sizeof(info->disc_information_length)); + + info->border_status = DISC_LAST_SESS_COMPLETE; + info->disc_status = DISC_STATUS_FINALIZED; + + /* We only support one session per disk */ + info->n_first_track = 1; + info->n_sessions_lsb = 1; + info->first_track_lsb = 1; + info->last_track_lsb = 1; + + /* Setting the unrestricted use because we only support (CD/DVD/BD)-ROM */ + info->uru = 1; + + info->disc_type = DISC_FIELD_DA_ROM; + + common->data_size_to_handle = sizeof(*info); + return 0; +} + /** * Attempts to guess medium type by looking at the length of the disc layout. */ @@ -2253,6 +2287,8 @@ static struct cdb_command_check cdb_checker_table[] = { { CDB_REG_CHECKER(TEST_UNIT_READY, 6, CDB_NO_SIZE_FIELD, DATA_DIR_NONE, 0x0000, MEDIUM_REQUIRED) }, + { CDB_REG_NO_CHECKER(READ_DISC_INFORMATION, CDB_SIZE_FIELD_7, + DATA_DIR_TO_HOST, MEDIUM_REQUIRED) }, { CDB_REG_NO_CHECKER(GET_CONFIGURATION, CDB_SIZE_FIELD_7, DATA_DIR_TO_HOST, MEDIUM_REQUIRED) }, @@ -2286,6 +2322,7 @@ static struct cdb_handler cdb_handlers_table[] = { { CDB_REG_HANDLER(SYNCHRONIZE_CACHE, &do_synchronize_cache) }, { CDB_REG_HANDLER(TEST_UNIT_READY, NULL) }, + { CDB_REG_HANDLER_BUFFHD(READ_DISC_INFORMATION, &do_read_disc_info) }, { CDB_REG_HANDLER_BUFFHD(GET_CONFIGURATION, &do_get_configuration) }, /* * Although optional, this command is used by MS-Windows. We diff --git a/include/scsi/scsi_proto.h b/include/scsi/scsi_proto.h index 6b2a8ee1f0a3..6728fcbd73e4 100644 --- a/include/scsi/scsi_proto.h +++ b/include/scsi/scsi_proto.h @@ -77,6 +77,7 @@ #define GET_EVENT_STATUS_NOTIFICATION 0x4a #define LOG_SELECT 0x4c #define LOG_SENSE 0x4d +#define READ_DISC_INFORMATION 0x51 #define XDWRITEREAD_10 0x53 #define MODE_SELECT_10 0x55 #define RESERVE_10 0x56 diff --git a/include/uapi/linux/cdrom.h b/include/uapi/linux/cdrom.h index 442693fdc059..460377e1a532 100644 --- a/include/uapi/linux/cdrom.h +++ b/include/uapi/linux/cdrom.h @@ -816,51 +816,204 @@ struct rwrt_feature_desc { __u8 reserved3; }; +/* Disc Information Data Types */ +#define DISC_TYPE_STANDARD (0x00U) +#define DISC_TYPE_TRACK (0x01U) +#define DISC_TYPE_POW (0x02U) + +/* Disc Status */ +#define DISC_STATUS_EMPTY (0x00U) +#define DISC_STATUS_INCOMPLETE (0x01U) +#define DISC_STATUS_FINALIZED (0x02U) +#define DISC_STATUS_OTHER (0x03U) + +/* State of Last Session */ +#define DISC_LAST_SESS_EMPTY (0x00U) +#define DISC_LAST_SESS_INCOMPLETE (0x01U) +#define DISC_LAST_SESS_DAMAGED (0x02U) +#define DISC_LAST_SESS_COMPLETE (0x03U) + +/* Background Format Status Codes */ +#define DISC_BACK_FMT_NEITHER (0x00U) +#define DISC_BACK_FMT_STARTED (0x01U) +#define DISC_BACK_FMT_PROGRESS (0x02U) +#define DISC_BACK_FMT_COMPLETED (0x03U) + +/* Disc Type Field */ +#define DISC_FIELD_DA_ROM (0x00U) +#define DISC_FIELD_I (0x10U) +#define DISC_FIELD_ROM_XA (0x20U) +#define DISC_FIELD_UNDEF (0xFFU) + +/** + * @brief The READ DISC INFORMATION CDB(0051h) + * The READ DISC INFORMATION command allows the Host to request information about + * the currently mounted MM disc. + */ +struct cdb_disc_info { + __u8 code; + +#if defined(__BIG_ENDIAN_BITFIELD) + __u8 reserved1 : 5; + /** + * When a disc is present, Data Type defines the specific information requested + */ + __u8 type : 3; +#elif defined(__LITTLE_ENDIAN_BITFIELD) + __u8 type : 3; + __u8 reserved1 : 5; +#endif + + __u8 reserved2[5]; + + __be16 length; + + __u8 control; +} __packed; + typedef struct { __be16 disc_information_length; #if defined(__BIG_ENDIAN_BITFIELD) - __u8 reserved1 : 3; - __u8 erasable : 1; - __u8 border_status : 2; - __u8 disc_status : 2; + /** + * The Disc Information Data Type field shall be set to the reported + * Disc Information Type + */ + __u8 info_data_type : 3; + /** + * The Erasable bit, when set to one, indicates that CD-RW, DVD-RAM, DVD-RW, DVD+RW, + * HD DVD-RAM, or BD-RE media is present and the Drive is capable of writing the media. + * If the Erasable bit is set to zero, then either the medium is not erasable or the + * Drive is unable to write the media. + */ + __u8 erasable : 1; + /** + * The State of Last Session field specifies the recorded state of the last + * session, regardless of the number of sessions on the disc. + */ + __u8 border_status : 2; + /* The Disc Status field indicates the recorded status of the disc */ + __u8 disc_status : 2; #elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 disc_status : 2; - __u8 border_status : 2; - __u8 erasable : 1; - __u8 reserved1 : 3; + __u8 disc_status : 2; + __u8 border_status : 2; + __u8 erasable : 1; + __u8 info_data_type : 3; #else #error "Please fix <asm/byteorder.h>" #endif + /** + * The Number of First Track on Disc is the track number of the Logical Track that + * contains LBA 0 + */ __u8 n_first_track; __u8 n_sessions_lsb; + /** + * First Track Number in Last Session (bytes 5 & 10) is the track number of the + * first Logical Track in the last session. + * This includes the incomplete logical track. + */ __u8 first_track_lsb; + /** + * Last Track Number in Last Session (bytes 6 & 11) is the track number of the last + * Logical Track in the last session. + * This includes the incomplete logical track. + */ __u8 last_track_lsb; #if defined(__BIG_ENDIAN_BITFIELD) - __u8 did_v : 1; - __u8 dbc_v : 1; - __u8 uru : 1; - __u8 reserved2 : 2; - __u8 dbit : 1; - __u8 mrw_status : 2; + /** + * The DID_V (Disc ID Valid) bit, when set to one, indicates that the Disc + * Identification field is valid + */ + __u8 did_v : 1; + /** + * The DBC_V (Disc Bar Code Valid bit, when set to one, indicates that the Disc Bar + * Code field (bytes 24 through 31) is valid + */ + __u8 dbc_v : 1; + /** + * The URU (Unrestricted Use Disc) bit may be zero for special use CD-R, CD-RW, + * or DVD-R, medium. + * For all other media types, URU shall be set to one. When URU is zero, the mounted + * disc is defined for restricted use. + */ + __u8 uru : 1; + /** + * DAC_V indicates the validity of the Disc Application Code in byte 32. If DAC_V is + * set to zero, then the Disc Application Code is not valid. If DAC_V is set to one, + * the Disc Application Code is valid. + */ + __u8 dac_v: 1; + __u8 reserved2 : 1; + /** + * If the disc is MRW formatted or MRW formatting (state = 01b, 10b, or 11b), + * then bit 2 of byte 7 (Dbit) is a copy of the “dirty bit” from the defect table. + * If Dbit is set to zero, then the MRW structures are current. + * If Dbit is set to one, then the MRW structures may not be current. + * When BG format status = 00b, Dbit shall be set to zero. + */ + __u8 dbit : 1; + /** + * The BG format status is the background format status of the mounted disc. + * Drives that report the Formattable Feature and either the MRW Feature or the DVD+RW + * Feature, or both are required to implement Background format. + * For all other Drives, this field shall be @param DISC_BACK_FMT_NEITHER. + */ + __u8 mrw_status : 2; #elif defined(__LITTLE_ENDIAN_BITFIELD) - __u8 mrw_status : 2; - __u8 dbit : 1; - __u8 reserved2 : 2; - __u8 uru : 1; - __u8 dbc_v : 1; - __u8 did_v : 1; + __u8 mrw_status : 2; + __u8 dbit : 1; + __u8 reserved2 : 1; + __u8 dac_v: 1; + __u8 uru : 1; + __u8 dbc_v : 1; + __u8 did_v : 1; #endif + /** + * The Disc Type field is associated only with CD media type + */ __u8 disc_type; __u8 n_sessions_msb; __u8 first_track_msb; __u8 last_track_msb; + + /** + * For CD-R/RW, the Disc Identification number recorded in the PMA is returned. + * The Disc Identification Number is recorded in the PMA as a six-digit BCD number. + * It is returned in the Disc Information Block as a 32 bit binary integer. + * This value should be zero filled for all other media types. + */ __u32 disc_id; + /** + * The Last Session Lead-in Start Address field is dependent on medium and + * recorded status. + */ __u32 lead_in; + /** + * The Last Possible Lead-out Start Address field is dependent on medium and + * recorded status. + */ __u32 lead_out; + /** + * For CD, the Disc Bar Code field contains the hexadecimal value of the bar code + * if the Drive has the ability to read Disc Bar Code and a bar code is present. + * For all other media this field should be set to zeros. + */ __u8 disc_bar_code[8]; + /** + * + */ __u8 reserved3; + /** + * The Number of OPC Tables field is the number of OPC tables that follow this field. + * If OPC has not been determined for the currently mounted medium, the Number of + * OPC Tables field is set to zero. + * The Number of OPC Tables represents the number of disc speeds for which the OPC + * values are known. + * Since each OPC Table is 8 bytes in length, then the number of bytes that follow + * the Number of OPC Tables field is 8 x Number of OPC Tables. + */ __u8 n_opc; -} disc_information; +} __packed disc_information; typedef struct { __be16 track_information_length; -- 2.32.0