diff options
Diffstat (limited to 'src/input/vcd/libcdio/scsi_mmc.c')
-rw-r--r-- | src/input/vcd/libcdio/scsi_mmc.c | 589 |
1 files changed, 0 insertions, 589 deletions
diff --git a/src/input/vcd/libcdio/scsi_mmc.c b/src/input/vcd/libcdio/scsi_mmc.c deleted file mode 100644 index 9b4a456a5..000000000 --- a/src/input/vcd/libcdio/scsi_mmc.c +++ /dev/null @@ -1,589 +0,0 @@ -/* Common SCSI Multimedia Command (MMC) routines. - - $Id: scsi_mmc.c,v 1.1 2005/01/01 02:43:57 rockyb Exp $ - - Copyright (C) 2004 Rocky Bernstein <rocky@panix.com> - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -*/ - -#ifdef HAVE_CONFIG_H -# include "config.h" -#endif - -#include <cdio/cdio.h> -#include <cdio/logging.h> -#include <cdio/scsi_mmc.h> -#include "cdio_private.h" - -#ifdef HAVE_STRING_H -#include <string.h> -#endif - -#ifdef HAVE_STDLIB_H -#include <stdlib.h> -#endif - -#ifdef HAVE_ERRNO_H -#include <errno.h> -#endif - -/*! - On input a MODE_SENSE command was issued and we have the results - in p. We interpret this and return a bit mask set according to the - capabilities. - */ -void -scsi_mmc_get_drive_cap_buf(const uint8_t *p, - /*out*/ cdio_drive_read_cap_t *p_read_cap, - /*out*/ cdio_drive_write_cap_t *p_write_cap, - /*out*/ cdio_drive_misc_cap_t *p_misc_cap) -{ - /* Reader */ - if (p[2] & 0x01) *p_read_cap |= CDIO_DRIVE_CAP_READ_CD_R; - if (p[2] & 0x02) *p_read_cap |= CDIO_DRIVE_CAP_READ_CD_RW; - if (p[2] & 0x08) *p_read_cap |= CDIO_DRIVE_CAP_READ_DVD_ROM; - if (p[4] & 0x01) *p_read_cap |= CDIO_DRIVE_CAP_READ_AUDIO; - if (p[5] & 0x01) *p_read_cap |= CDIO_DRIVE_CAP_READ_CD_DA; - if (p[5] & 0x10) *p_read_cap |= CDIO_DRIVE_CAP_READ_C2_ERRS; - - /* Writer */ - if (p[3] & 0x01) *p_write_cap |= CDIO_DRIVE_CAP_WRITE_CD_R; - if (p[3] & 0x02) *p_write_cap |= CDIO_DRIVE_CAP_WRITE_CD_RW; - if (p[3] & 0x10) *p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_R; - if (p[3] & 0x20) *p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_RAM; - if (p[4] & 0x80) *p_misc_cap |= CDIO_DRIVE_CAP_WRITE_BURN_PROOF; - - /* Misc */ - if (p[4] & 0x40) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_MULTI_SESSION; - if (p[6] & 0x01) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_LOCK; - if (p[6] & 0x08) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_EJECT; - if (p[6] >> 5 != 0) - *p_misc_cap |= CDIO_DRIVE_CAP_MISC_CLOSE_TRAY; -} - -/*! - Return the number of length in bytes of the Command Descriptor - buffer (CDB) for a given SCSI MMC command. The length will be - either 6, 10, or 12. -*/ -uint8_t -scsi_mmc_get_cmd_len(uint8_t scsi_cmd) -{ - static const uint8_t scsi_cdblen[8] = {6, 10, 10, 12, 12, 12, 10, 10}; - return scsi_cdblen[((scsi_cmd >> 5) & 7)]; -} - -/*! - Run a SCSI MMC command. - - cdio CD structure set by cdio_open(). - i_timeout time in milliseconds we will wait for the command - to complete. If this value is -1, use the default - time-out value. - buf Buffer for data, both sending and receiving - len Size of buffer - e_direction direction the transfer is to go - cdb CDB bytes. All values that are needed should be set on - input. We'll figure out what the right CDB length should be. - - We return 0 if command completed successfully and 1 if not. - */ -int -scsi_mmc_run_cmd( const CdIo *p_cdio, unsigned int i_timeout_ms, - const scsi_mmc_cdb_t *p_cdb, - scsi_mmc_direction_t e_direction, unsigned int i_buf, - /*in/out*/ void *p_buf ) -{ - if (p_cdio && p_cdio->op.run_scsi_mmc_cmd) { - return p_cdio->op.run_scsi_mmc_cmd(p_cdio->env, i_timeout_ms, - scsi_mmc_get_cmd_len(p_cdb->field[0]), - p_cdb, e_direction, i_buf, p_buf); - } else - return 1; -} - -#define DEFAULT_TIMEOUT_MS 6000 - -/*! - * Eject using SCSI MMC commands. Return 0 if successful. - */ -int -scsi_mmc_eject_media( const CdIo *cdio ) -{ - int i_status; - scsi_mmc_cdb_t cdb = {{0, }}; - uint8_t buf[1]; - scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd; - - if ( ! cdio || ! cdio->op.run_scsi_mmc_cmd ) - return -2; - - run_scsi_mmc_cmd = cdio->op.run_scsi_mmc_cmd; - - CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_ALLOW_MEDIUM_REMOVAL); - - i_status = run_scsi_mmc_cmd (cdio->env, DEFAULT_TIMEOUT_MS, - scsi_mmc_get_cmd_len(cdb.field[0]), &cdb, - SCSI_MMC_DATA_WRITE, 0, &buf); - if (0 != i_status) - return i_status; - - CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_START_STOP); - cdb.field[4] = 1; - i_status = run_scsi_mmc_cmd (cdio->env, DEFAULT_TIMEOUT_MS, - scsi_mmc_get_cmd_len(cdb.field[0]), &cdb, - SCSI_MMC_DATA_WRITE, 0, &buf); - if (0 != i_status) - return i_status; - - CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_START_STOP); - cdb.field[4] = 2; /* eject */ - - return run_scsi_mmc_cmd (cdio->env, DEFAULT_TIMEOUT_MS, - scsi_mmc_get_cmd_len(cdb.field[0]), &cdb, - SCSI_MMC_DATA_WRITE, 0, &buf); - -} - -/*! Packet driver to read mode2 sectors. - Can read only up to 25 blocks. -*/ -int -scsi_mmc_read_sectors ( const CdIo *cdio, void *p_buf, lba_t lba, - int sector_type, unsigned int nblocks ) -{ - scsi_mmc_cdb_t cdb = {{0, }}; - - scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd; - - if ( ! cdio || ! cdio->op.run_scsi_mmc_cmd ) - return -2; - - run_scsi_mmc_cmd = cdio->op.run_scsi_mmc_cmd; - - CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_CD); - CDIO_MMC_SET_READ_TYPE (cdb.field, sector_type); - CDIO_MMC_SET_READ_LBA (cdb.field, lba); - CDIO_MMC_SET_READ_LENGTH24(cdb.field, nblocks); - CDIO_MMC_SET_MAIN_CHANNEL_SELECTION_BITS(cdb.field, - CDIO_MMC_MCSB_ALL_HEADERS); - - return run_scsi_mmc_cmd (cdio->env, DEFAULT_TIMEOUT_MS, - scsi_mmc_get_cmd_len(cdb.field[0]), &cdb, - SCSI_MMC_DATA_READ, - CDIO_CD_FRAMESIZE_RAW * nblocks, - p_buf); -} - -int -scsi_mmc_set_blocksize_private ( const void *p_env, - const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd, - unsigned int bsize) -{ - scsi_mmc_cdb_t cdb = {{0, }}; - - struct - { - uint8_t reserved1; - uint8_t medium; - uint8_t reserved2; - uint8_t block_desc_length; - uint8_t density; - uint8_t number_of_blocks_hi; - uint8_t number_of_blocks_med; - uint8_t number_of_blocks_lo; - uint8_t reserved3; - uint8_t block_length_hi; - uint8_t block_length_med; - uint8_t block_length_lo; - } mh; - - if ( ! p_env || ! run_scsi_mmc_cmd ) - return -2; - - memset (&mh, 0, sizeof (mh)); - mh.block_desc_length = 0x08; - mh.block_length_hi = (bsize >> 16) & 0xff; - mh.block_length_med = (bsize >> 8) & 0xff; - mh.block_length_lo = (bsize >> 0) & 0xff; - - CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SELECT_6); - - cdb.field[1] = 1 << 4; - cdb.field[4] = 12; - - return run_scsi_mmc_cmd (p_env, DEFAULT_TIMEOUT_MS, - scsi_mmc_get_cmd_len(cdb.field[0]), &cdb, - SCSI_MMC_DATA_WRITE, sizeof(mh), &mh); -} - -int -scsi_mmc_set_blocksize ( const CdIo *cdio, unsigned int bsize) -{ - if ( ! cdio ) return -2; - return - scsi_mmc_set_blocksize_private (cdio->env, cdio->op.run_scsi_mmc_cmd, - bsize); -} - - -/*! - Return the the kind of drive capabilities of device. - */ -void -scsi_mmc_get_drive_cap_private (const void *p_env, - const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd, - /*out*/ cdio_drive_read_cap_t *p_read_cap, - /*out*/ cdio_drive_write_cap_t *p_write_cap, - /*out*/ cdio_drive_misc_cap_t *p_misc_cap) -{ - /* Largest buffer size we use. */ -#define BUF_MAX 2048 - uint8_t buf[BUF_MAX] = { 0, }; - - scsi_mmc_cdb_t cdb = {{0, }}; - int i_status; - uint16_t i_data = BUF_MAX; - - if ( ! p_env || ! run_scsi_mmc_cmd ) - return; - - CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SENSE_10); - cdb.field[1] = 0x0; - cdb.field[2] = CDIO_MMC_ALL_PAGES; - - retry: - CDIO_MMC_SET_READ_LENGTH16(cdb.field, 8); - - /* In the first run we run MODE SENSE 10 we are trying to get the - length of the data features. */ - i_status = run_scsi_mmc_cmd (p_env, DEFAULT_TIMEOUT_MS, - scsi_mmc_get_cmd_len(cdb.field[0]), - &cdb, SCSI_MMC_DATA_READ, - sizeof(buf), &buf); - if (0 == i_status) { - uint16_t i_data_try = (uint16_t) CDIO_MMC_GET_LEN16(buf); - if (i_data_try < BUF_MAX) i_data = i_data_try; - } - - /* Now try getting all features with length set above, possibly - truncated or the default length if we couldn't get the proper - length. */ - CDIO_MMC_SET_READ_LENGTH16(cdb.field, i_data); - - i_status = run_scsi_mmc_cmd (p_env, DEFAULT_TIMEOUT_MS, - scsi_mmc_get_cmd_len(cdb.field[0]), - &cdb, SCSI_MMC_DATA_READ, - sizeof(buf), &buf); - - if (0 != i_status && CDIO_MMC_CAPABILITIES_PAGE != cdb.field[2]) { - cdb.field[2] = CDIO_MMC_CAPABILITIES_PAGE; - goto retry; - } - - if (0 == i_status) { - uint8_t *p; - uint8_t *p_max = buf + 256; - - *p_read_cap = 0; - *p_write_cap = 0; - *p_misc_cap = 0; - - /* set to first sense mask, and then walk through the masks */ - p = buf + 8; - while( (p < &(buf[2+i_data])) && (p < p_max) ) { - uint8_t which_page; - - which_page = p[0] & 0x3F; - switch( which_page ) - { - case CDIO_MMC_AUDIO_CTL_PAGE: - case CDIO_MMC_R_W_ERROR_PAGE: - case CDIO_MMC_CDR_PARMS_PAGE: - /* Don't handle these yet. */ - break; - case CDIO_MMC_CAPABILITIES_PAGE: - scsi_mmc_get_drive_cap_buf(p, p_read_cap, p_write_cap, p_misc_cap); - break; - default: ; - } - p += (p[1] + 2); - } - } else { - cdio_info("%s: %s\n", "error in MODE_SELECT", strerror(errno)); - *p_read_cap = CDIO_DRIVE_CAP_ERROR; - *p_write_cap = CDIO_DRIVE_CAP_ERROR; - *p_misc_cap = CDIO_DRIVE_CAP_ERROR; - } - return; -} - -void -scsi_mmc_get_drive_cap (const CdIo *p_cdio, - /*out*/ cdio_drive_read_cap_t *p_read_cap, - /*out*/ cdio_drive_write_cap_t *p_write_cap, - /*out*/ cdio_drive_misc_cap_t *p_misc_cap) -{ - if ( ! p_cdio ) return; - scsi_mmc_get_drive_cap_private (p_cdio->env, - p_cdio->op.run_scsi_mmc_cmd, - p_read_cap, p_write_cap, p_misc_cap); -} - -void -scsi_mmc_get_drive_cap_generic (const void *p_user_data, - /*out*/ cdio_drive_read_cap_t *p_read_cap, - /*out*/ cdio_drive_write_cap_t *p_write_cap, - /*out*/ cdio_drive_misc_cap_t *p_misc_cap) -{ - const generic_img_private_t *p_env = p_user_data; - scsi_mmc_get_drive_cap( p_env->cdio, - p_read_cap, p_write_cap, p_misc_cap ); -} - - -/*! - Get the DVD type associated with cd object. -*/ -discmode_t -scsi_mmc_get_dvd_struct_physical_private ( void *p_env, const - scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd, - cdio_dvd_struct_t *s) -{ - scsi_mmc_cdb_t cdb = {{0, }}; - unsigned char buf[4 + 4 * 20], *base; - int i_status; - uint8_t layer_num = s->physical.layer_num; - - cdio_dvd_layer_t *layer; - - if ( ! p_env || ! run_scsi_mmc_cmd ) - return -2; - - if (layer_num >= CDIO_DVD_MAX_LAYERS) - return -EINVAL; - - CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_DVD_STRUCTURE); - cdb.field[6] = layer_num; - cdb.field[7] = CDIO_DVD_STRUCT_PHYSICAL; - cdb.field[9] = sizeof(buf) & 0xff; - - i_status = run_scsi_mmc_cmd(p_env, DEFAULT_TIMEOUT_MS, - scsi_mmc_get_cmd_len(cdb.field[0]), - &cdb, SCSI_MMC_DATA_READ, - sizeof(buf), &buf); - if (0 != i_status) - return CDIO_DISC_MODE_ERROR; - - base = &buf[4]; - layer = &s->physical.layer[layer_num]; - - /* - * place the data... really ugly, but at least we won't have to - * worry about endianess in userspace. - */ - memset(layer, 0, sizeof(*layer)); - layer->book_version = base[0] & 0xf; - layer->book_type = base[0] >> 4; - layer->min_rate = base[1] & 0xf; - layer->disc_size = base[1] >> 4; - layer->layer_type = base[2] & 0xf; - layer->track_path = (base[2] >> 4) & 1; - layer->nlayers = (base[2] >> 5) & 3; - layer->track_density = base[3] & 0xf; - layer->linear_density = base[3] >> 4; - layer->start_sector = base[5] << 16 | base[6] << 8 | base[7]; - layer->end_sector = base[9] << 16 | base[10] << 8 | base[11]; - layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15]; - layer->bca = base[16] >> 7; - - return 0; -} - - -/*! - Get the DVD type associated with cd object. -*/ -discmode_t -scsi_mmc_get_dvd_struct_physical ( const CdIo *p_cdio, cdio_dvd_struct_t *s) -{ - if ( ! p_cdio ) return -2; - return - scsi_mmc_get_dvd_struct_physical_private (p_cdio->env, - p_cdio->op.run_scsi_mmc_cmd, - s); -} - -/*! - Get the CD-ROM hardware info via a SCSI MMC INQUIRY command. - False is returned if we had an error getting the information. -*/ -bool -scsi_mmc_get_hwinfo ( const CdIo *p_cdio, - /*out*/ cdio_hwinfo_t *hw_info ) -{ - int i_status; /* Result of SCSI MMC command */ - char buf[36] = { 0, }; /* Place to hold returned data */ - scsi_mmc_cdb_t cdb = {{0, }}; /* Command Descriptor Block */ - - CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_INQUIRY); - cdb.field[4] = sizeof(buf); - - if (! p_cdio || ! hw_info ) return false; - - i_status = scsi_mmc_run_cmd(p_cdio, DEFAULT_TIMEOUT_MS, - &cdb, SCSI_MMC_DATA_READ, - sizeof(buf), &buf); - if (i_status == 0) { - - memcpy(hw_info->psz_vendor, - buf + 8, - sizeof(hw_info->psz_vendor)-1); - hw_info->psz_vendor[sizeof(hw_info->psz_vendor)-1] = '\0'; - memcpy(hw_info->psz_model, - buf + 8 + CDIO_MMC_HW_VENDOR_LEN, - sizeof(hw_info->psz_model)-1); - hw_info->psz_model[sizeof(hw_info->psz_model)-1] = '\0'; - memcpy(hw_info->psz_revision, - buf + 8 + CDIO_MMC_HW_VENDOR_LEN + CDIO_MMC_HW_MODEL_LEN, - sizeof(hw_info->psz_revision)-1); - hw_info->psz_revision[sizeof(hw_info->psz_revision)-1] = '\0'; - return true; - } - return false; -} - -/*! - Return the media catalog number MCN. - - Note: string is malloc'd so caller should free() then returned - string when done with it. - - */ -char * -scsi_mmc_get_mcn_private ( void *p_env, - const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd - ) -{ - scsi_mmc_cdb_t cdb = {{0, }}; - char buf[28] = { 0, }; - int i_status; - - if ( ! p_env || ! run_scsi_mmc_cmd ) - return NULL; - - CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_SUBCHANNEL); - cdb.field[1] = 0x0; - cdb.field[2] = 0x40; - cdb.field[3] = CDIO_SUBCHANNEL_MEDIA_CATALOG; - CDIO_MMC_SET_READ_LENGTH16(cdb.field, sizeof(buf)); - - i_status = run_scsi_mmc_cmd(p_env, DEFAULT_TIMEOUT_MS, - scsi_mmc_get_cmd_len(cdb.field[0]), - &cdb, SCSI_MMC_DATA_READ, - sizeof(buf), buf); - if(i_status == 0) { - return strdup(&buf[9]); - } - return NULL; -} - -char * -scsi_mmc_get_mcn ( const CdIo *p_cdio ) -{ - if ( ! p_cdio ) return NULL; - return scsi_mmc_get_mcn_private (p_cdio->env, - p_cdio->op.run_scsi_mmc_cmd ); -} - -char * -scsi_mmc_get_mcn_generic (const void *p_user_data) -{ - const generic_img_private_t *p_env = p_user_data; - return scsi_mmc_get_mcn( p_env->cdio ); -} - -/* - Read cdtext information for a CdIo object . - - return true on success, false on error or CD-Text information does - not exist. -*/ -bool -scsi_mmc_init_cdtext_private ( void *p_user_data, - const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd, - set_cdtext_field_fn_t set_cdtext_field_fn - ) -{ - - generic_img_private_t *p_env = p_user_data; - scsi_mmc_cdb_t cdb = {{0, }}; - unsigned char wdata[5000] = { 0, }; - int i_status, i_errno; - - if ( ! p_env || ! run_scsi_mmc_cmd || p_env->b_cdtext_error ) - return false; - - /* Operation code */ - CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC); - - cdb.field[1] = CDIO_CDROM_MSF; - /* Format */ - cdb.field[2] = CDIO_MMC_READTOC_FMT_CDTEXT; - - /* Setup to read header, to get length of data */ - CDIO_MMC_SET_READ_LENGTH16(cdb.field, 4); - - errno = 0; - -/* Set read timeout 3 minues. */ -#define READ_TIMEOUT 3*60*1000 - - /* We may need to give CD-Text a little more time to complete. */ - /* First off, just try and read the size */ - i_status = run_scsi_mmc_cmd (p_env, READ_TIMEOUT, - scsi_mmc_get_cmd_len(cdb.field[0]), - &cdb, SCSI_MMC_DATA_READ, - 4, &wdata); - - if (i_status != 0) { - cdio_info ("CD-Text read failed for header: %s\n", strerror(errno)); - i_errno = errno; - p_env->b_cdtext_error = true; - return false; - } else { - /* Now read the CD-Text data */ - int i_cdtext = CDIO_MMC_GET_LEN16(wdata); - - if (i_cdtext > sizeof(wdata)) i_cdtext = sizeof(wdata); - - CDIO_MMC_SET_READ_LENGTH16(cdb.field, i_cdtext); - i_status = run_scsi_mmc_cmd (p_env, READ_TIMEOUT, - scsi_mmc_get_cmd_len(cdb.field[0]), - &cdb, SCSI_MMC_DATA_READ, - i_cdtext, &wdata); - if (i_status != 0) { - cdio_info ("CD-Text read for text failed: %s\n", strerror(errno)); - i_errno = errno; - p_env->b_cdtext_error = true; - return false; - } - p_env->b_cdtext_init = true; - return cdtext_data_init(p_env, p_env->i_first_track, wdata, - set_cdtext_field_fn); - } -} - |