|
Packit |
dd8086 |
/* Common Multimedia Command (MMC) routines.
|
|
Packit |
dd8086 |
Copyright (C) 2004-2008, 2010-2012, 2014
|
|
Packit |
dd8086 |
Rocky Bernstein <rocky@gnu.org>
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
This program is free software: you can redistribute it and/or modify
|
|
Packit |
dd8086 |
it under the terms of the GNU General Public License as published by
|
|
Packit |
dd8086 |
the Free Software Foundation, either version 3 of the License, or
|
|
Packit |
dd8086 |
(at your option) any later version.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
This program is distributed in the hope that it will be useful,
|
|
Packit |
dd8086 |
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
dd8086 |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
dd8086 |
GNU General Public License for more details.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
You should have received a copy of the GNU General Public License
|
|
Packit |
dd8086 |
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
dd8086 |
# include "config.h"
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef HAVE_STDBOOL_H
|
|
Packit |
dd8086 |
# include <stdbool.h>
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#include <cdio/cdio.h>
|
|
Packit |
dd8086 |
#include <cdio/logging.h>
|
|
Packit |
dd8086 |
#include <cdio/mmc.h>
|
|
Packit |
dd8086 |
#include <cdio/mmc_cmds.h>
|
|
Packit |
dd8086 |
#include <cdio/util.h>
|
|
Packit |
dd8086 |
#include "cdio_private.h"
|
|
Packit |
dd8086 |
#include "cdtext_private.h"
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef HAVE_STRING_H
|
|
Packit |
dd8086 |
#include <string.h>
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef HAVE_STDLIB_H
|
|
Packit |
dd8086 |
#include <stdlib.h>
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef HAVE_STDIO_H
|
|
Packit |
dd8086 |
# include <stdio.h>
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef HAVE_ERRNO_H
|
|
Packit |
dd8086 |
# include <errno.h>
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
const char
|
|
Packit |
dd8086 |
*mmc_cmd2str(uint8_t command)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
switch( command ) {
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_TEST_UNIT_READY:
|
|
Packit |
dd8086 |
return "TEST UNIT READY";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_REQUEST_SENSE:
|
|
Packit |
dd8086 |
return "REQUEST SENSE";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_FORMAT_UNIT:
|
|
Packit |
dd8086 |
return "FORMAT UNIT";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_INQUIRY:
|
|
Packit |
dd8086 |
return "INQUIRY";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_MODE_SELECT_6:
|
|
Packit |
dd8086 |
return "MODE SELECT (6)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_MODE_SENSE_6:
|
|
Packit |
dd8086 |
return "MODE SENSE (6)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_START_STOP_UNIT:
|
|
Packit |
dd8086 |
return "START STOP UNIT";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
|
|
Packit |
dd8086 |
return "PREVENT ALLOW MEDIUM REMOVAL";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_FORMAT_CAPACITIES:
|
|
Packit |
dd8086 |
return "READ FORMAT CAPACITIES";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_CAPACITIY:
|
|
Packit |
dd8086 |
return "READ_CAPACITIY";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_10:
|
|
Packit |
dd8086 |
return "READ (10)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_WRITE_10:
|
|
Packit |
dd8086 |
return "WRITE (10)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_SEEK_10:
|
|
Packit |
dd8086 |
return "SEEK (10)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_ERASE_10:
|
|
Packit |
dd8086 |
return "ERASE (10)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_WRITE_AND_VERIFY_10:
|
|
Packit |
dd8086 |
return "WRITE AND VERIFY (10)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_VERIFY_10:
|
|
Packit |
dd8086 |
return "VERIFY (10)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_SYNCHRONIZE_CACHE:
|
|
Packit |
dd8086 |
return "SYNCHRONIZE CACHE";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_WRITE_BUFFER:
|
|
Packit |
dd8086 |
return "WRITE BUFFER";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_BUFFER:
|
|
Packit |
dd8086 |
return "READ_BUFFER";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_SUBCHANNEL:
|
|
Packit |
dd8086 |
return "READ_SUBCHANNEL";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_TOC:
|
|
Packit |
dd8086 |
return "READ TOC";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_HEADER:
|
|
Packit |
dd8086 |
return "READ_HEADER";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_PLAY_AUDIO_10:
|
|
Packit |
dd8086 |
return "PLAY AUDIO (10)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_GET_CONFIGURATION:
|
|
Packit |
dd8086 |
return "GET_CONFIGURATION";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_PLAY_AUDIO_MSF:
|
|
Packit |
dd8086 |
return "PLAY AUDIO MSF";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_PLAY_AUDIO_TI:
|
|
Packit |
dd8086 |
return "PLAY_AUDIO TI";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_PLAY_TRACK_REL_10:
|
|
Packit |
dd8086 |
return "PLAY TRACK REL (10)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_GET_EVENT_STATUS:
|
|
Packit |
dd8086 |
return "GET EVENT STATUS";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_PAUSE_RESUME:
|
|
Packit |
dd8086 |
return "PAUSE RESUME";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_DISC_INFORMATION:
|
|
Packit |
dd8086 |
return "READ DISC INFORMATION";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_TRACK_INFORMATION:
|
|
Packit |
dd8086 |
return "READ TRACK INFORMATION";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_RESERVE_TRACK:
|
|
Packit |
dd8086 |
return "RESERVE TRACK";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_SEND_OPC_INFORMATION:
|
|
Packit |
dd8086 |
return "SEND OPC INFORMATION";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_MODE_SELECT_10:
|
|
Packit |
dd8086 |
return "MODE SELECT (10)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_REPAIR_TRACK:
|
|
Packit |
dd8086 |
return "REPAIR_TRACK";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_MODE_SENSE_10:
|
|
Packit |
dd8086 |
return "MODE SENSE (10)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_CLOSE_TRACK_SESSION:
|
|
Packit |
dd8086 |
return "CLOSE TRACK SESSION";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_BUFFER_CAPACITY:
|
|
Packit |
dd8086 |
return "READ_BUFFER CAPACITY";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_SEND_CUE_SHEET:
|
|
Packit |
dd8086 |
return "SEND_CUE SHEET";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_REPORT_LUNS:
|
|
Packit |
dd8086 |
return "REPORT LUNS";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_BLANK:
|
|
Packit |
dd8086 |
return "BLANK";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_SECURITY_PROTOCOL_IN:
|
|
Packit |
dd8086 |
return "SECURITY PROTOCOL IN";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_SEND_KEY:
|
|
Packit |
dd8086 |
return "SEND KEY";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_REPORT_KEY:
|
|
Packit |
dd8086 |
return "REPORT KEY";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_PLAY_AUDIO_12:
|
|
Packit |
dd8086 |
return "PLAY_AUDIO (12)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_LOAD_UNLOAD:
|
|
Packit |
dd8086 |
return "LOAD UNLOAD";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_SET_READ_AHEAD:
|
|
Packit |
dd8086 |
return "SET READ AHEAD";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_12:
|
|
Packit |
dd8086 |
return "READ (12)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_PLAY_TRACK_REL_12:
|
|
Packit |
dd8086 |
return "PLAY_TRACK REL (12)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_WRITE_12:
|
|
Packit |
dd8086 |
return "WRITE (12)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_MEDIA_SERIAL_12:
|
|
Packit |
dd8086 |
return "READ MEDIA SERIAL (12)";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_GET_PERFORMANCE:
|
|
Packit |
dd8086 |
return "GET PERFORMANCE";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_DVD_STRUCTURE:
|
|
Packit |
dd8086 |
return "READ DVD STRUCTURE";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_SECURITY_PROTOCOL_OUT:
|
|
Packit |
dd8086 |
return "SECURITY PROTOCOL_OUT";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_SET_STREAMING:
|
|
Packit |
dd8086 |
return "SET STREAMING";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_MSF:
|
|
Packit |
dd8086 |
return "READ MSF";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_SET_SPEED:
|
|
Packit |
dd8086 |
return "SET SPEED";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_MECHANISM_STATUS:
|
|
Packit |
dd8086 |
return "MECHANISM STATUS";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_CD:
|
|
Packit |
dd8086 |
return "READ CD";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_SEND_DISC_STRUCTURE:
|
|
Packit |
dd8086 |
return "SEND DISC STRUCTURE";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_CD_PLAYBACK_STATUS:
|
|
Packit |
dd8086 |
return "CD PLAYBACK STATUS";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_PLAYBACK_CONTROL:
|
|
Packit |
dd8086 |
return "PLAYBACK CONTROL";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_CDDA:
|
|
Packit |
dd8086 |
return "READ CDDA";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_CDXA:
|
|
Packit |
dd8086 |
return "READ CDXA";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
case CDIO_MMC_GPCMD_READ_ALL_SUBCODES:
|
|
Packit |
dd8086 |
return "READ ALL SUBCODES";
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
default:
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
char buf[30];
|
|
Packit |
dd8086 |
snprintf(buf, sizeof(buf), "Unknown 0x%x", command);
|
|
Packit |
dd8086 |
return strdup(buf);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/*************************************************************************
|
|
Packit |
dd8086 |
MMC CdIo Operations which a driver may use.
|
|
Packit |
dd8086 |
These are not accessible directly.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
Most of these routines just pick out the cdio pointer and call the
|
|
Packit |
dd8086 |
corresponding publically-accessible routine.
|
|
Packit |
dd8086 |
*************************************************************************/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Read Audio Subchannel information
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_user_data the CD object to be acted upon.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
audio_read_subchannel_mmc ( void *p_user_data, cdio_subchannel_t *p_subchannel)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
generic_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
if (!p_env) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
return mmc_audio_read_subchannel(p_env->cdio, p_subchannel);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get the block size for subsequest read requests, via MMC.
|
|
Packit |
dd8086 |
@return the blocksize if > 0; error if <= 0
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
int
|
|
Packit |
dd8086 |
get_blocksize_mmc (void *p_user_data)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
generic_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
if (!p_env) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
return mmc_get_blocksize(p_env->cdio);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get the lsn of the end of the CD (via MMC).
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
lsn_t
|
|
Packit |
dd8086 |
get_disc_last_lsn_mmc (void *p_user_data)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
generic_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
if (!p_env) return CDIO_INVALID_LSN;
|
|
Packit |
dd8086 |
return mmc_get_disc_last_lsn(p_env->cdio);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
void
|
|
Packit |
dd8086 |
get_drive_cap_mmc (const void *p_user_data,
|
|
Packit |
dd8086 |
/*out*/ cdio_drive_read_cap_t *p_read_cap,
|
|
Packit |
dd8086 |
/*out*/ cdio_drive_write_cap_t *p_write_cap,
|
|
Packit |
dd8086 |
/*out*/ cdio_drive_misc_cap_t *p_misc_cap)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
const generic_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
mmc_get_drive_cap( p_env->cdio,
|
|
Packit |
dd8086 |
p_read_cap, p_write_cap, p_misc_cap );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Find out if media has changed since the last call. @param
|
|
Packit |
dd8086 |
p_user_data the environment of the CD object to be acted upon.
|
|
Packit |
dd8086 |
@return 1 if media has changed since last call, 0 if not. Error
|
|
Packit |
dd8086 |
return codes are the same as driver_return_code_t
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
int
|
|
Packit |
dd8086 |
get_media_changed_mmc (const void *p_user_data)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
const generic_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
return mmc_get_media_changed( p_env->cdio );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
char *
|
|
Packit |
dd8086 |
get_mcn_mmc (const void *p_user_data)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
const generic_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
return mmc_get_mcn( p_env->cdio );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
get_tray_status (const void *p_user_data)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
const generic_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
return mmc_get_tray_status( p_env->cdio );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Read sectors using SCSI-MMC GPCMD_READ_CD.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_read_data_sectors ( CdIo_t *p_cdio, void *p_buf,
|
|
Packit |
dd8086 |
lsn_t i_lsn, uint16_t i_blocksize,
|
|
Packit |
dd8086 |
uint32_t i_blocks )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return mmc_read_cd(p_cdio,
|
|
Packit |
dd8086 |
p_buf, /* place to store data */
|
|
Packit |
dd8086 |
i_lsn, /* lsn */
|
|
Packit |
dd8086 |
0, /* read_sector_type */
|
|
Packit |
dd8086 |
false, /* digital audio play */
|
|
Packit |
dd8086 |
false, /* return sync header */
|
|
Packit |
dd8086 |
0, /* header codes */
|
|
Packit |
dd8086 |
true, /* return user data */
|
|
Packit |
dd8086 |
false, /* return EDC ECC */
|
|
Packit |
dd8086 |
false, /* return C2 Error information */
|
|
Packit |
dd8086 |
0, /* subchannel selection bits */
|
|
Packit |
dd8086 |
ISO_BLOCKSIZE, /* blocksize*/
|
|
Packit |
dd8086 |
i_blocks /* Number of blocks. */);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Read sectors using SCSI-MMC GPCMD_READ_CD.
|
|
Packit |
dd8086 |
Can read only up to 25 blocks.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
read_data_sectors_mmc ( void *p_user_data, void *p_buf,
|
|
Packit |
dd8086 |
lsn_t i_lsn, uint16_t i_blocksize,
|
|
Packit |
dd8086 |
uint32_t i_blocks )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
const generic_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
return mmc_read_data_sectors( p_env->cdio, p_buf, i_lsn, i_blocksize,
|
|
Packit |
dd8086 |
i_blocks );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Set read blocksize (via MMC)
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
set_blocksize_mmc (void *p_user_data, uint16_t i_blocksize)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
generic_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
if (!p_env) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
return mmc_set_blocksize(p_env->cdio, i_blocksize);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/** Set the drive speed Set the drive speed in K bytes per second. (via
|
|
Packit |
dd8086 |
MMC).
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
set_speed_mmc (void *p_user_data, int i_speed)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
generic_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
if (!p_env) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
return mmc_set_speed( p_env->cdio, i_speed, 0);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Set the drive speed in CD-ROM speed units (via MMC).
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
set_drive_speed_mmc (void *p_user_data, int i_Kbs_speed)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
generic_img_private_t *p_env = p_user_data;
|
|
Packit |
dd8086 |
if (!p_env) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
return mmc_set_drive_speed( p_env->cdio, i_Kbs_speed );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get the output port volumes and port selections used on AUDIO PLAY
|
|
Packit |
dd8086 |
commands via a MMC MODE SENSE command using the CD Audio Control
|
|
Packit |
dd8086 |
Page.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_audio_get_volume( CdIo_t *p_cdio, /*out*/ mmc_audio_volume_t *p_volume )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
uint8_t buf[16];
|
|
Packit |
dd8086 |
int i_rc = mmc_mode_sense(p_cdio, buf, sizeof(buf), CDIO_MMC_AUDIO_CTL_PAGE);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( DRIVER_OP_SUCCESS == i_rc ) {
|
|
Packit |
dd8086 |
p_volume->port[0].selection = 0xF & buf[8];
|
|
Packit |
dd8086 |
p_volume->port[0].volume = buf[9];
|
|
Packit |
dd8086 |
p_volume->port[1].selection = 0xF & buf[10];
|
|
Packit |
dd8086 |
p_volume->port[1].volume = buf[11];
|
|
Packit |
dd8086 |
p_volume->port[2].selection = 0xF & buf[12];
|
|
Packit |
dd8086 |
p_volume->port[2].volume = buf[13];
|
|
Packit |
dd8086 |
p_volume->port[3].selection = 0xF & buf[14];
|
|
Packit |
dd8086 |
p_volume->port[3].volume = buf[15];
|
|
Packit |
dd8086 |
return DRIVER_OP_SUCCESS;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return i_rc;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get the DVD type associated with cd object.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
discmode_t
|
|
Packit |
dd8086 |
mmc_get_dvd_struct_physical_private ( void *p_env,
|
|
Packit |
dd8086 |
mmc_run_cmd_fn_t run_mmc_cmd,
|
|
Packit |
dd8086 |
cdio_dvd_struct_t *s)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
mmc_cdb_t cdb = {{0, }};
|
|
Packit |
dd8086 |
unsigned char buf[4 + 4 * 20], *base;
|
|
Packit |
dd8086 |
int i_status;
|
|
Packit |
dd8086 |
uint8_t layer_num = s->physical.layer_num;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdio_dvd_layer_t *layer;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_env) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
if (!run_mmc_cmd) return DRIVER_OP_UNSUPPORTED;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (layer_num >= CDIO_DVD_MAX_LAYERS)
|
|
Packit |
dd8086 |
return -EINVAL;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_DVD_STRUCTURE);
|
|
Packit |
dd8086 |
cdb.field[6] = layer_num;
|
|
Packit |
dd8086 |
cdb.field[7] = CDIO_DVD_STRUCT_PHYSICAL;
|
|
Packit |
dd8086 |
cdb.field[9] = sizeof(buf) & 0xff;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_status = run_mmc_cmd(p_env, mmc_timeout_ms,
|
|
Packit |
dd8086 |
mmc_get_cmd_len(cdb.field[0]),
|
|
Packit |
dd8086 |
&cdb, SCSI_MMC_DATA_READ,
|
|
Packit |
dd8086 |
sizeof(buf), &buf;;
|
|
Packit |
dd8086 |
if (0 != i_status)
|
|
Packit |
dd8086 |
return CDIO_DISC_MODE_ERROR;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
base = &buf[4];
|
|
Packit |
dd8086 |
layer = &s->physical.layer[layer_num];
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/*
|
|
Packit |
dd8086 |
* place the data... really ugly, but at least we won't have to
|
|
Packit |
dd8086 |
* worry about endianess in userspace.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
memset(layer, 0, sizeof(*layer));
|
|
Packit |
dd8086 |
layer->book_version = base[0] & 0xf;
|
|
Packit |
dd8086 |
layer->book_type = base[0] >> 4;
|
|
Packit |
dd8086 |
layer->min_rate = base[1] & 0xf;
|
|
Packit |
dd8086 |
layer->disc_size = base[1] >> 4;
|
|
Packit |
dd8086 |
layer->layer_type = base[2] & 0xf;
|
|
Packit |
dd8086 |
layer->track_path = (base[2] >> 4) & 1;
|
|
Packit |
dd8086 |
layer->nlayers = (base[2] >> 5) & 3;
|
|
Packit |
dd8086 |
layer->track_density = base[3] & 0xf;
|
|
Packit |
dd8086 |
layer->linear_density = base[3] >> 4;
|
|
Packit |
dd8086 |
layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
|
|
Packit |
dd8086 |
layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
|
|
Packit |
dd8086 |
layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
|
|
Packit |
dd8086 |
layer->bca = base[16] >> 7;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return (discmode_t) DRIVER_OP_SUCCESS;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get the media catalog number (MCN) or the ISRC
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
Note: string is malloc'd so caller should free() then returned
|
|
Packit |
dd8086 |
string when done with it.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_cdio
|
|
Packit |
dd8086 |
@param i_track track number
|
|
Packit |
dd8086 |
@param sub_chan_param 2 for MCN, 3 for ISRC
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@return malloc'd string holding the MCN or ISRC on success
|
|
Packit |
dd8086 |
or NULL on failure
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
char *
|
|
Packit |
dd8086 |
mmc_get_mcn_isrc_private ( const CdIo_t *p_cdio,
|
|
Packit |
dd8086 |
track_t i_track,
|
|
Packit |
dd8086 |
unsigned char sub_chan_param
|
|
Packit |
dd8086 |
)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
char buf[24]; /* 4 header + 20 data (MMC-4 tables 424, 431, 432) */
|
|
Packit |
dd8086 |
unsigned int num_data;
|
|
Packit |
dd8086 |
size_t length;
|
|
Packit |
dd8086 |
driver_return_code_t i_rc;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
switch(sub_chan_param) {
|
|
Packit |
dd8086 |
case CDIO_SUBCHANNEL_MEDIA_CATALOG: /* MCN */
|
|
Packit |
dd8086 |
length = CDIO_MCN_SIZE;
|
|
Packit |
dd8086 |
break;
|
|
Packit |
dd8086 |
case CDIO_SUBCHANNEL_TRACK_ISRC: /* ISRC */
|
|
Packit |
dd8086 |
length = CDIO_ISRC_SIZE;
|
|
Packit |
dd8086 |
break;
|
|
Packit |
dd8086 |
default:
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* inquire number of available reply bytes
|
|
Packit |
dd8086 |
workaround for bad device drivers
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
num_data = 4; /* header only */
|
|
Packit |
dd8086 |
i_rc = mmc_read_subchannel (p_cdio, i_track,
|
|
Packit |
dd8086 |
sub_chan_param, &num_data, buf, 0);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (i_rc != DRIVER_OP_SUCCESS)
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (num_data > sizeof(buf))
|
|
Packit |
dd8086 |
num_data = sizeof(buf);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (num_data < 9 + length)
|
|
Packit |
dd8086 |
return NULL; /* Not enough data available */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_rc = mmc_read_subchannel (p_cdio, i_track,
|
|
Packit |
dd8086 |
sub_chan_param, &num_data, buf, 0);
|
|
Packit |
dd8086 |
if (i_rc != DRIVER_OP_SUCCESS)
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (num_data < 9 + length)
|
|
Packit |
dd8086 |
return NULL; /* Not enough data returned */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( ! (buf[8] & 0x80) ) /* MCVAL / TCVAL bit indicates a valid response */
|
|
Packit |
dd8086 |
return NULL; /* MCN/ISRC not valid */
|
|
Packit |
dd8086 |
return strndup(&buf[9], length);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_set_blocksize_private ( void *p_env,
|
|
Packit |
dd8086 |
const mmc_run_cmd_fn_t run_mmc_cmd,
|
|
Packit |
dd8086 |
uint16_t i_blocksize)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
mmc_cdb_t cdb = {{0, }};
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
struct
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
uint8_t reserved1;
|
|
Packit |
dd8086 |
uint8_t medium;
|
|
Packit |
dd8086 |
uint8_t reserved2;
|
|
Packit |
dd8086 |
uint8_t block_desc_length;
|
|
Packit |
dd8086 |
uint8_t density;
|
|
Packit |
dd8086 |
uint8_t number_of_blocks_hi;
|
|
Packit |
dd8086 |
uint8_t number_of_blocks_med;
|
|
Packit |
dd8086 |
uint8_t number_of_blocks_lo;
|
|
Packit |
dd8086 |
uint8_t reserved3;
|
|
Packit |
dd8086 |
uint8_t block_length_hi;
|
|
Packit |
dd8086 |
uint8_t block_length_med;
|
|
Packit |
dd8086 |
uint8_t block_length_lo;
|
|
Packit |
dd8086 |
} mh;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( ! p_env ) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
if ( ! run_mmc_cmd ) return DRIVER_OP_UNSUPPORTED;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset (&mh, 0, sizeof (mh));
|
|
Packit |
dd8086 |
mh.block_desc_length = 0x08;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* while i_blocksize is uint16_t, this expression is always 0 */
|
|
Packit |
dd8086 |
mh.block_length_hi = (i_blocksize >> 16) & 0xff;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
mh.block_length_med = (i_blocksize >> 8) & 0xff;
|
|
Packit |
dd8086 |
mh.block_length_lo = (i_blocksize >> 0) & 0xff;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SELECT_6);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdb.field[1] = 1 << 4;
|
|
Packit |
dd8086 |
cdb.field[4] = 12;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return run_mmc_cmd (p_env, mmc_timeout_ms,
|
|
Packit |
dd8086 |
mmc_get_cmd_len(cdb.field[0]), &cdb,
|
|
Packit |
dd8086 |
SCSI_MMC_DATA_WRITE, sizeof(mh), &mh);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/***********************************************************
|
|
Packit |
dd8086 |
User-accessible Operations.
|
|
Packit |
dd8086 |
************************************************************/
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Read Audio Subchannel information
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_audio_read_subchannel (CdIo_t *p_cdio, cdio_subchannel_t *p_subchannel)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
mmc_cdb_t cdb;
|
|
Packit |
dd8086 |
driver_return_code_t i_rc;
|
|
Packit |
dd8086 |
cdio_mmc_subchannel_t mmc_subchannel;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_cdio) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset(&mmc_subchannel, 0, sizeof(mmc_subchannel));
|
|
Packit |
dd8086 |
mmc_subchannel.format = CDIO_CDROM_MSF;
|
|
Packit |
dd8086 |
memset(&cdb, 0, sizeof(mmc_cdb_t));
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_SUBCHANNEL);
|
|
Packit |
dd8086 |
CDIO_MMC_SET_READ_LENGTH8(cdb.field, sizeof(cdio_mmc_subchannel_t));
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdb.field[1] = CDIO_CDROM_MSF;
|
|
Packit |
dd8086 |
cdb.field[2] = 0x40; /* subq */
|
|
Packit |
dd8086 |
cdb.field[3] = CDIO_SUBCHANNEL_CURRENT_POSITION;
|
|
Packit |
dd8086 |
cdb.field[6] = 0; /* track number (only in isrc mode, ignored) */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_rc = mmc_run_cmd(p_cdio, mmc_timeout_ms, &cdb, SCSI_MMC_DATA_READ,
|
|
Packit |
dd8086 |
sizeof(cdio_mmc_subchannel_t), &mmc_subchannel);
|
|
Packit |
dd8086 |
if (DRIVER_OP_SUCCESS == i_rc) {
|
|
Packit |
dd8086 |
p_subchannel->format = mmc_subchannel.format;
|
|
Packit |
dd8086 |
p_subchannel->audio_status = mmc_subchannel.audio_status;
|
|
Packit |
dd8086 |
p_subchannel->address = mmc_subchannel.address;
|
|
Packit |
dd8086 |
p_subchannel->control = mmc_subchannel.control;
|
|
Packit |
dd8086 |
p_subchannel->track = mmc_subchannel.track;
|
|
Packit |
dd8086 |
p_subchannel->index = mmc_subchannel.index;
|
|
Packit |
dd8086 |
p_subchannel->abs_addr.m = cdio_to_bcd8(mmc_subchannel.abs_addr[1]);
|
|
Packit |
dd8086 |
p_subchannel->abs_addr.s = cdio_to_bcd8(mmc_subchannel.abs_addr[2]);
|
|
Packit |
dd8086 |
p_subchannel->abs_addr.f = cdio_to_bcd8(mmc_subchannel.abs_addr[3]);
|
|
Packit |
dd8086 |
p_subchannel->rel_addr.m = cdio_to_bcd8(mmc_subchannel.rel_addr[1]);
|
|
Packit |
dd8086 |
p_subchannel->rel_addr.s = cdio_to_bcd8(mmc_subchannel.rel_addr[2]);
|
|
Packit |
dd8086 |
p_subchannel->rel_addr.f = cdio_to_bcd8(mmc_subchannel.rel_addr[3]);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return i_rc;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get the block size used in read requests, via MMC (e.g. READ_10,
|
|
Packit |
dd8086 |
READ_MSF, ...)
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@return the blocksize if > 0; error if <= 0
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
int
|
|
Packit |
dd8086 |
mmc_get_blocksize ( CdIo_t *p_cdio)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
int i_status;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
uint8_t buf[255] = { 0, };
|
|
Packit |
dd8086 |
uint8_t *p;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* First try using the 6-byte MODE SENSE command. */
|
|
Packit |
dd8086 |
i_status = mmc_mode_sense_6(p_cdio, buf, sizeof(buf),
|
|
Packit |
dd8086 |
CDIO_MMC_R_W_ERROR_PAGE);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (DRIVER_OP_SUCCESS == i_status && buf[3]>=8) {
|
|
Packit |
dd8086 |
p = &buf[4+5];
|
|
Packit |
dd8086 |
return CDIO_MMC_GET_LEN16(p);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Next try using the 10-byte MODE SENSE command. */
|
|
Packit |
dd8086 |
i_status = mmc_mode_sense_10(p_cdio, buf, sizeof(buf),
|
|
Packit |
dd8086 |
CDIO_MMC_R_W_ERROR_PAGE);
|
|
Packit |
dd8086 |
p = &buf[6];
|
|
Packit |
dd8086 |
if (DRIVER_OP_SUCCESS == i_status && CDIO_MMC_GET_LEN16(p)>=8) {
|
|
Packit |
dd8086 |
return CDIO_MMC_GET_LEN16(p);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#ifdef IS_THIS_CORRECT
|
|
Packit |
dd8086 |
/* Lastly try using the READ CAPACITY command. */
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
lba_t lba = 0;
|
|
Packit |
dd8086 |
uint16_t i_blocksize;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_status = mmc_read_capacity(p_cdio, &lba, &i_blocksize);
|
|
Packit |
dd8086 |
if ( DRIVER_OP_SUCCESS == i_status )
|
|
Packit |
dd8086 |
return i_blocksize;
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return DRIVER_OP_UNSUPPORTED;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Return the number of length in bytes of the Command Descriptor
|
|
Packit |
dd8086 |
buffer (CDB) for a given MMC command. The length will be
|
|
Packit |
dd8086 |
either 6, 10, or 12.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
uint8_t
|
|
Packit |
dd8086 |
mmc_get_cmd_len(uint8_t scsi_cmd)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
static const uint8_t scsi_cdblen[8] = {6, 10, 10, 12, 12, 12, 10, 10};
|
|
Packit |
dd8086 |
return scsi_cdblen[((scsi_cmd >> 5) & 7)];
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Return the size of the CD in logical block address (LBA) units.
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@return the lsn. On error 0 or CDIO_INVALD_LSN.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
lsn_t
|
|
Packit |
dd8086 |
mmc_get_disc_last_lsn ( const CdIo_t *p_cdio )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
mmc_cdb_t cdb = {{0, }};
|
|
Packit |
dd8086 |
uint8_t buf[12] = { 0, };
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
lsn_t retval = 0;
|
|
Packit |
dd8086 |
int i_status;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Operation code */
|
|
Packit |
dd8086 |
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdb.field[1] = 0; /* lba; msf: 0x2 */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Format */
|
|
Packit |
dd8086 |
cdb.field[2] = CDIO_MMC_READTOC_FMT_TOC;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CDIO_MMC_SET_START_TRACK(cdb.field, CDIO_CDROM_LEADOUT_TRACK);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CDIO_MMC_SET_READ_LENGTH16(cdb.field, sizeof(buf));
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_status = mmc_run_cmd(p_cdio, mmc_timeout_ms, &cdb, SCSI_MMC_DATA_READ,
|
|
Packit |
dd8086 |
sizeof(buf), buf);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (i_status) return CDIO_INVALID_LSN;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
int i;
|
|
Packit |
dd8086 |
for (i = 8; i < 12; i++) {
|
|
Packit |
dd8086 |
retval <<= 8;
|
|
Packit |
dd8086 |
retval += buf[i];
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return retval;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Return the discmode as reported by the SCSI-MMC Read (FULL) TOC
|
|
Packit |
dd8086 |
command.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
Information was obtained from Section 5.1.13 (Read TOC/PMA/ATIP)
|
|
Packit |
dd8086 |
pages 56-62 from the MMC draft specification, revision 10a
|
|
Packit |
dd8086 |
at http://www.t10.org/ftp/t10/drafts/mmc/mmc-r10a.pdf See
|
|
Packit |
dd8086 |
especially tables 72, 73 and 75.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
discmode_t
|
|
Packit |
dd8086 |
mmc_get_discmode( const CdIo_t *p_cdio )
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
uint8_t buf[14] = { 0, };
|
|
Packit |
dd8086 |
mmc_cdb_t cdb;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memset(&cdb, 0, sizeof(mmc_cdb_t));
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC);
|
|
Packit |
dd8086 |
CDIO_MMC_SET_READ_LENGTH8(cdb.field, sizeof(buf));
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdb.field[1] = CDIO_CDROM_MSF; /* The MMC-5 spec may require this. */
|
|
Packit |
dd8086 |
cdb.field[2] = CDIO_MMC_READTOC_FMT_FULTOC;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
mmc_run_cmd(p_cdio, 2000, &cdb, SCSI_MMC_DATA_READ, sizeof(buf), buf);
|
|
Packit |
dd8086 |
if (buf[7] == 0xA0) {
|
|
Packit |
dd8086 |
if (buf[13] == 0x00) {
|
|
Packit |
dd8086 |
if (buf[5] & 0x04)
|
|
Packit |
dd8086 |
return CDIO_DISC_MODE_CD_DATA;
|
|
Packit |
dd8086 |
else
|
|
Packit |
dd8086 |
return CDIO_DISC_MODE_CD_DA;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
else if (buf[13] == 0x10)
|
|
Packit |
dd8086 |
return CDIO_DISC_MODE_CD_I;
|
|
Packit |
dd8086 |
else if (buf[13] == 0x20)
|
|
Packit |
dd8086 |
return CDIO_DISC_MODE_CD_XA;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return CDIO_DISC_MODE_NO_INFO;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get drive capabilities for a device.
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@return the drive capabilities.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
void
|
|
Packit |
dd8086 |
mmc_get_drive_cap (CdIo_t *p_cdio,
|
|
Packit |
dd8086 |
/*out*/ cdio_drive_read_cap_t *p_read_cap,
|
|
Packit |
dd8086 |
/*out*/ cdio_drive_write_cap_t *p_write_cap,
|
|
Packit |
dd8086 |
/*out*/ cdio_drive_misc_cap_t *p_misc_cap)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
/* Largest buffer size we use. */
|
|
Packit |
dd8086 |
#define BUF_MAX 2048
|
|
Packit |
dd8086 |
uint8_t buf[BUF_MAX+2] = { 0, };
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
int i_status;
|
|
Packit |
dd8086 |
uint16_t i_data = BUF_MAX;
|
|
Packit |
dd8086 |
int page = CDIO_MMC_ALL_PAGES;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( ! p_cdio ) return;
|
|
Packit |
dd8086 |
retry:
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* In the first run we run MODE SENSE 10 we are trying to get the
|
|
Packit |
dd8086 |
length of the data features. */
|
|
Packit |
dd8086 |
i_status = mmc_mode_sense_10(p_cdio, buf, 8, CDIO_MMC_ALL_PAGES);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (DRIVER_OP_SUCCESS == i_status) {
|
|
Packit |
dd8086 |
uint16_t i_data_try = (uint16_t) CDIO_MMC_GET_LEN16(buf);
|
|
Packit |
dd8086 |
if (i_data_try < BUF_MAX) i_data = i_data_try;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Now try getting all features with length set above, possibly
|
|
Packit |
dd8086 |
truncated or the default length if we couldn't get the proper
|
|
Packit |
dd8086 |
length. */
|
|
Packit |
dd8086 |
i_status = mmc_mode_sense_10(p_cdio, buf, i_data, CDIO_MMC_ALL_PAGES);
|
|
Packit |
dd8086 |
if (0 != i_status && CDIO_MMC_CAPABILITIES_PAGE != page) {
|
|
Packit |
dd8086 |
page = CDIO_MMC_CAPABILITIES_PAGE;
|
|
Packit |
dd8086 |
goto retry;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (DRIVER_OP_SUCCESS == i_status) {
|
|
Packit |
dd8086 |
uint8_t *p;
|
|
Packit |
dd8086 |
uint8_t *p_max = buf + 256;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
*p_read_cap = 0;
|
|
Packit |
dd8086 |
*p_write_cap = 0;
|
|
Packit |
dd8086 |
*p_misc_cap = 0;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* set to first sense mask, and then walk through the masks */
|
|
Packit |
dd8086 |
p = buf + 8;
|
|
Packit |
dd8086 |
while( (p < &(buf[2+i_data])) && (p < p_max) ) {
|
|
Packit |
dd8086 |
uint8_t which_page;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
which_page = p[0] & 0x3F;
|
|
Packit |
dd8086 |
switch( which_page )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
case CDIO_MMC_AUDIO_CTL_PAGE:
|
|
Packit |
dd8086 |
case CDIO_MMC_R_W_ERROR_PAGE:
|
|
Packit |
dd8086 |
case CDIO_MMC_CDR_PARMS_PAGE:
|
|
Packit |
dd8086 |
/* Don't handle these yet. */
|
|
Packit |
dd8086 |
break;
|
|
Packit |
dd8086 |
case CDIO_MMC_CAPABILITIES_PAGE:
|
|
Packit |
dd8086 |
mmc_get_drive_cap_buf(p, p_read_cap, p_write_cap, p_misc_cap);
|
|
Packit |
dd8086 |
break;
|
|
Packit |
dd8086 |
default: ;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
p += (p[1] + 2);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
} else {
|
|
Packit |
dd8086 |
cdio_info("%s: %s\n", "error in MODE_SELECT", strerror(errno));
|
|
Packit |
dd8086 |
*p_read_cap = CDIO_DRIVE_CAP_ERROR;
|
|
Packit |
dd8086 |
*p_write_cap = CDIO_DRIVE_CAP_ERROR;
|
|
Packit |
dd8086 |
*p_misc_cap = CDIO_DRIVE_CAP_ERROR;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get the MMC level supported by the device.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
cdio_mmc_level_t
|
|
Packit |
dd8086 |
mmc_get_drive_mmc_cap(CdIo_t *p_cdio)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
uint8_t buf[256] = { 0, };
|
|
Packit |
dd8086 |
uint8_t len;
|
|
Packit |
dd8086 |
int rc = mmc_mode_sense(p_cdio, buf, sizeof(buf),
|
|
Packit |
dd8086 |
CDIO_MMC_CAPABILITIES_PAGE);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (DRIVER_OP_SUCCESS != rc) {
|
|
Packit |
dd8086 |
return CDIO_MMC_LEVEL_NONE;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
len = buf[1];
|
|
Packit |
dd8086 |
if (16 > len) {
|
|
Packit |
dd8086 |
return CDIO_MMC_LEVEL_WEIRD;
|
|
Packit |
dd8086 |
} else if (28 <= len) {
|
|
Packit |
dd8086 |
return CDIO_MMC_LEVEL_3;
|
|
Packit |
dd8086 |
} else if (24 <= len) {
|
|
Packit |
dd8086 |
return CDIO_MMC_LEVEL_2;
|
|
Packit |
dd8086 |
} else if (20 <= len) {
|
|
Packit |
dd8086 |
return CDIO_MMC_LEVEL_1;
|
|
Packit |
dd8086 |
} else {
|
|
Packit |
dd8086 |
return CDIO_MMC_LEVEL_WEIRD;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get the DVD type associated with cd object.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@return the DVD discmode.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
discmode_t
|
|
Packit |
dd8086 |
mmc_get_dvd_struct_physical ( const CdIo_t *p_cdio, cdio_dvd_struct_t *s)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
if ( ! p_cdio ) return -2;
|
|
Packit |
dd8086 |
return
|
|
Packit |
dd8086 |
mmc_get_dvd_struct_physical_private (p_cdio->env,
|
|
Packit |
dd8086 |
p_cdio->op.run_mmc_cmd,
|
|
Packit |
dd8086 |
s);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get the CD-ROM hardware info via a MMC INQUIRY command.
|
|
Packit |
dd8086 |
False is returned if we had an error getting the information.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@return true if we were able to get hardware info, false if we had
|
|
Packit |
dd8086 |
an error.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
bool
|
|
Packit |
dd8086 |
mmc_get_hwinfo ( const CdIo_t *p_cdio,
|
|
Packit |
dd8086 |
/*out*/ cdio_hwinfo_t *hw_info )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
int i_status; /* Result of MMC command */
|
|
Packit |
dd8086 |
char buf[36] = { 0, }; /* Place to hold returned data */
|
|
Packit |
dd8086 |
mmc_cdb_t cdb = {{0, }}; /* Command Descriptor Block */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_INQUIRY);
|
|
Packit |
dd8086 |
cdb.field[4] = sizeof(buf);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (! p_cdio || ! hw_info ) return false;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_status = mmc_run_cmd(p_cdio, mmc_timeout_ms,
|
|
Packit |
dd8086 |
&cdb, SCSI_MMC_DATA_READ,
|
|
Packit |
dd8086 |
sizeof(buf), &buf;;
|
|
Packit |
dd8086 |
if (i_status == 0) {
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
memcpy(hw_info->psz_vendor,
|
|
Packit |
dd8086 |
buf + 8,
|
|
Packit |
dd8086 |
sizeof(hw_info->psz_vendor)-1);
|
|
Packit |
dd8086 |
hw_info->psz_vendor[sizeof(hw_info->psz_vendor)-1] = '\0';
|
|
Packit |
dd8086 |
memcpy(hw_info->psz_model,
|
|
Packit |
dd8086 |
buf + 8 + CDIO_MMC_HW_VENDOR_LEN,
|
|
Packit |
dd8086 |
sizeof(hw_info->psz_model)-1);
|
|
Packit |
dd8086 |
hw_info->psz_model[sizeof(hw_info->psz_model)-1] = '\0';
|
|
Packit |
dd8086 |
memcpy(hw_info->psz_revision,
|
|
Packit |
dd8086 |
buf + 8 + CDIO_MMC_HW_VENDOR_LEN + CDIO_MMC_HW_MODEL_LEN,
|
|
Packit |
dd8086 |
sizeof(hw_info->psz_revision)-1);
|
|
Packit |
dd8086 |
hw_info->psz_revision[sizeof(hw_info->psz_revision)-1] = '\0';
|
|
Packit |
dd8086 |
return true;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return false;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Find out if media has changed since the last call.
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@return 1 if media has changed since last call, 0 if not. Error
|
|
Packit |
dd8086 |
return codes are the same as driver_return_code_t
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
int mmc_get_media_changed(const CdIo_t *p_cdio)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
uint8_t status_buf[2];
|
|
Packit |
dd8086 |
int i_status;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_status = mmc_get_event_status(p_cdio, status_buf);
|
|
Packit |
dd8086 |
if (i_status != DRIVER_OP_SUCCESS)
|
|
Packit |
dd8086 |
return i_status;
|
|
Packit |
dd8086 |
return (status_buf[0] & 0x02) ? 1 : 0;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get the media catalog number (MCN) from the CD via MMC.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@return the media catalog number r NULL if there is none or we
|
|
Packit |
dd8086 |
don't have the ability to get it.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
Note: The caller must free the returned string with cdio_free()
|
|
Packit |
dd8086 |
when done with it.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
char *
|
|
Packit |
dd8086 |
mmc_get_mcn ( const CdIo_t *p_cdio )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
if ( ! p_cdio ) return NULL;
|
|
Packit |
dd8086 |
return mmc_get_mcn_isrc_private (p_cdio, 0, CDIO_SUBCHANNEL_MEDIA_CATALOG );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Get the international standard recording code (ISRC) of the track via MMC.
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@param i_track the track to get the ISRC info for.
|
|
Packit |
dd8086 |
@return the international standard recording code or NULL if there is
|
|
Packit |
dd8086 |
none or we don't have the ability to get it.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
Note: The caller must free the returned string with cdio_free()
|
|
Packit |
dd8086 |
when done with it.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
char *
|
|
Packit |
dd8086 |
mmc_get_track_isrc ( const CdIo_t *p_cdio, track_t i_track )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
if ( ! p_cdio ) return NULL;
|
|
Packit |
dd8086 |
return mmc_get_mcn_isrc_private (p_cdio, i_track, CDIO_SUBCHANNEL_TRACK_ISRC );
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Read cdtext information for a CdIo_t object .
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@return pointer to data on success, NULL on error or CD-Text information does
|
|
Packit |
dd8086 |
not exist.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
Note: the caller must free the returned memory
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
uint8_t *
|
|
Packit |
dd8086 |
mmc_read_cdtext (const CdIo_t *p_cdio)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
unsigned char buf[4];
|
|
Packit |
dd8086 |
unsigned char * wdata;
|
|
Packit |
dd8086 |
int i_status;
|
|
Packit |
dd8086 |
unsigned int i_cdtext;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if ( ! p_cdio )
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* We may need to give CD-Text a little more time to complete. */
|
|
Packit |
dd8086 |
/* First off, just try and read the size */
|
|
Packit |
dd8086 |
i_cdtext = 4;
|
|
Packit |
dd8086 |
i_status = mmc_read_toc_cdtext(p_cdio, &i_cdtext, buf, 0);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (i_status != DRIVER_OP_SUCCESS) {
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (i_cdtext > CDTEXT_LEN_BINARY_MAX + 2)
|
|
Packit |
dd8086 |
i_cdtext = CDTEXT_LEN_BINARY_MAX + 4;
|
|
Packit |
dd8086 |
else
|
|
Packit |
dd8086 |
i_cdtext += 2; /* data length does not include the data length field */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
wdata = malloc(i_cdtext); /* is zeroed in mmc_toc_read_cdtext */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Read all of it */
|
|
Packit |
dd8086 |
i_status = mmc_read_toc_cdtext(p_cdio, &i_cdtext, wdata, 0);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (i_status != DRIVER_OP_SUCCESS) {
|
|
Packit |
dd8086 |
free(wdata);
|
|
Packit |
dd8086 |
return NULL;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return wdata;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Find out if media tray is open or closed.
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@return 1 if media is open, 0 if closed. Error
|
|
Packit |
dd8086 |
return codes are the same as driver_return_code_t
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
int mmc_get_tray_status(const CdIo_t *p_cdio)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
uint8_t status_buf[2];
|
|
Packit |
dd8086 |
int i_status;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_status = mmc_get_event_status(p_cdio, status_buf);
|
|
Packit |
dd8086 |
if (i_status != DRIVER_OP_SUCCESS)
|
|
Packit |
dd8086 |
return i_status;
|
|
Packit |
dd8086 |
return (status_buf[1] & 0x01) ? 1 : 0;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Added in version 0.83 by scdbackup */
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Obtain the SCSI sense reply of the most-recently-performed MMC command.
|
|
Packit |
dd8086 |
These bytes give an indication of possible problems which occured in
|
|
Packit |
dd8086 |
the drive while the command was performed. With some commands they tell
|
|
Packit |
dd8086 |
about the current state of the drive (e.g. 00h TEST UNIT READY).
|
|
Packit |
dd8086 |
@param p_cdio CD structure set by cdio_open().
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param sense returns the sense bytes received from the drive.
|
|
Packit |
dd8086 |
This is allocated memory or NULL if no sense bytes are
|
|
Packit |
dd8086 |
available. Dispose non-NULL pointers by cdio_free() when no longer
|
|
Packit |
dd8086 |
needed. See SPC-3 4.5.3 Fixed format sense data. SCSI error
|
|
Packit |
dd8086 |
codes as of SPC-3 Annex D, MMC-5 Annex F: sense[2]&15 = Key ,
|
|
Packit |
dd8086 |
sense[12] = ASC , sense[13] = ASCQ
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@return number of valid bytes in sense, 0 in case of no sense
|
|
Packit |
dd8086 |
bytes available, <0 in case of internal error.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
int
|
|
Packit |
dd8086 |
mmc_last_cmd_sense(const CdIo_t *p_cdio, cdio_mmc_request_sense_t **pp_sense)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
generic_img_private_t *gen;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_cdio) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
gen = p_cdio->env;
|
|
Packit |
dd8086 |
*pp_sense = NULL;
|
|
Packit |
dd8086 |
if (gen->scsi_mmc_sense_valid <= 0)
|
|
Packit |
dd8086 |
return 0;
|
|
Packit |
dd8086 |
*pp_sense = calloc(1, gen->scsi_mmc_sense_valid);
|
|
Packit |
dd8086 |
if (*pp_sense == NULL)
|
|
Packit |
dd8086 |
return DRIVER_OP_ERROR;
|
|
Packit |
dd8086 |
memcpy(*pp_sense, gen->scsi_mmc_sense, gen->scsi_mmc_sense_valid);
|
|
Packit |
dd8086 |
return gen->scsi_mmc_sense_valid;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Run a MMC command.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param cdio CD structure set by cdio_open().
|
|
Packit |
dd8086 |
@param i_timeout time in milliseconds we will wait for the command
|
|
Packit |
dd8086 |
to complete. If this value is -1, use the default
|
|
Packit |
dd8086 |
time-out value.
|
|
Packit |
dd8086 |
@param buf Buffer for data, both sending and receiving
|
|
Packit |
dd8086 |
@param len Size of buffer
|
|
Packit |
dd8086 |
@param e_direction direction the transfer is to go
|
|
Packit |
dd8086 |
@param cdb CDB bytes. All values that are needed should be set on
|
|
Packit |
dd8086 |
input. We'll figure out what the right CDB length
|
|
Packit |
dd8086 |
should be.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_run_cmd( const CdIo_t *p_cdio, unsigned int i_timeout_ms,
|
|
Packit |
dd8086 |
const mmc_cdb_t *p_cdb,
|
|
Packit |
dd8086 |
cdio_mmc_direction_t e_direction, unsigned int i_buf,
|
|
Packit |
dd8086 |
/*in/out*/ void *p_buf )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
if (!p_cdio) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
if (!p_cdio->op.run_mmc_cmd) return DRIVER_OP_UNSUPPORTED;
|
|
Packit |
dd8086 |
return p_cdio->op.run_mmc_cmd(p_cdio->env, i_timeout_ms,
|
|
Packit |
dd8086 |
mmc_get_cmd_len(p_cdb->field[0]),
|
|
Packit |
dd8086 |
p_cdb, e_direction, i_buf, p_buf);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* Added by SukkoPera to allow CDB length to be specified manually */
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Run a Multimedia command (MMC) specifying the CDB length.
|
|
Packit |
dd8086 |
The motivation here is for example ot use in is an undocumented
|
|
Packit |
dd8086 |
debug command for LG drives (namely E7), whose length is being
|
|
Packit |
dd8086 |
miscalculated by mmc_get_cmd_len(); it doesn't follow the usual
|
|
Packit |
dd8086 |
code number to length conventions. Patch supplied by SukkoPera.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_cdio CD structure set by cdio_open().
|
|
Packit |
dd8086 |
@param i_timeout_ms time in milliseconds we will wait for the command
|
|
Packit |
dd8086 |
to complete.
|
|
Packit |
dd8086 |
@param p_cdb CDB bytes. All values that are needed should be set
|
|
Packit |
dd8086 |
on input.
|
|
Packit |
dd8086 |
@param i_cdb number of CDB bytes.
|
|
Packit |
dd8086 |
@param e_direction direction the transfer is to go.
|
|
Packit |
dd8086 |
@param i_buf Size of buffer
|
|
Packit |
dd8086 |
@param p_buf Buffer for data, both sending and receiving.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@return 0 if command completed successfully.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_run_cmd_len( const CdIo_t *p_cdio, unsigned int i_timeout_ms,
|
|
Packit |
dd8086 |
const mmc_cdb_t *p_cdb, unsigned int i_cdb,
|
|
Packit |
dd8086 |
cdio_mmc_direction_t e_direction, unsigned int i_buf,
|
|
Packit |
dd8086 |
/*in/out*/ void *p_buf )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
if (!p_cdio) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
if (!p_cdio->op.run_mmc_cmd) return DRIVER_OP_UNSUPPORTED;
|
|
Packit |
dd8086 |
return p_cdio->op.run_mmc_cmd(p_cdio->env, i_timeout_ms,
|
|
Packit |
dd8086 |
i_cdb,
|
|
Packit |
dd8086 |
p_cdb, e_direction, i_buf, p_buf);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
See if CD-ROM has feature with value value
|
|
Packit |
dd8086 |
@return true if we have the feature and false if not.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
bool_3way_t
|
|
Packit |
dd8086 |
mmc_have_interface( CdIo_t *p_cdio, cdio_mmc_feature_interface_t e_interface )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
int i_status; /* Result of MMC command */
|
|
Packit |
dd8086 |
uint8_t buf[65530] = { 0, }; /* Place to hold returned data */
|
|
Packit |
dd8086 |
mmc_cdb_t cdb = {{0, }}; /* Command Descriptor Buffer */
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_cdio || !p_cdio->op.run_mmc_cmd) return nope;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_GET_CONFIGURATION);
|
|
Packit |
dd8086 |
CDIO_MMC_SET_READ_LENGTH8(cdb.field, sizeof(buf));
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
cdb.field[1] = CDIO_MMC_GET_CONF_NAMED_FEATURE;
|
|
Packit |
dd8086 |
cdb.field[3] = CDIO_MMC_FEATURE_CORE;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_status = mmc_run_cmd(p_cdio, 0, &cdb, SCSI_MMC_DATA_READ, sizeof(buf),
|
|
Packit |
dd8086 |
&buf;;
|
|
Packit |
dd8086 |
if (DRIVER_OP_SUCCESS == i_status) {
|
|
Packit |
dd8086 |
uint8_t *p;
|
|
Packit |
dd8086 |
uint32_t i_data;
|
|
Packit |
dd8086 |
uint8_t *p_max = buf + 65530;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_data = (unsigned int) CDIO_MMC_GET_LEN32(buf);
|
|
Packit |
dd8086 |
/* set to first sense feature code, and then walk through the masks */
|
|
Packit |
dd8086 |
p = buf + 8;
|
|
Packit |
dd8086 |
while( (p < &(buf[i_data])) && (p < p_max) ) {
|
|
Packit |
dd8086 |
uint16_t i_feature;
|
|
Packit |
dd8086 |
uint8_t i_feature_additional = p[3];
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_feature = CDIO_MMC_GET_LEN16(p);
|
|
Packit |
dd8086 |
if (CDIO_MMC_FEATURE_CORE == i_feature) {
|
|
Packit |
dd8086 |
uint8_t *q = p+4;
|
|
Packit |
dd8086 |
uint32_t i_interface_standard = CDIO_MMC_GET_LEN32(q);
|
|
Packit |
dd8086 |
if (e_interface == i_interface_standard) return yep;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
p += i_feature_additional + 4;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return nope;
|
|
Packit |
dd8086 |
} else
|
|
Packit |
dd8086 |
return dunno;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Read sectors using SCSI-MMC GPCMD_READ_CD.
|
|
Packit |
dd8086 |
Can read only up to 25 blocks.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_read_sectors ( const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
|
|
Packit |
dd8086 |
int sector_type, uint32_t i_blocks )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
mmc_cdb_t cdb = {{0, }};
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
mmc_run_cmd_fn_t run_mmc_cmd;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (!p_cdio) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
if (!p_cdio->op.run_mmc_cmd ) return DRIVER_OP_UNSUPPORTED;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
run_mmc_cmd = p_cdio->op.run_mmc_cmd;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_CD);
|
|
Packit |
dd8086 |
CDIO_MMC_SET_READ_TYPE (cdb.field, sector_type);
|
|
Packit |
dd8086 |
CDIO_MMC_SET_READ_LBA (cdb.field, i_lsn);
|
|
Packit |
dd8086 |
CDIO_MMC_SET_READ_LENGTH24(cdb.field, i_blocks);
|
|
Packit |
dd8086 |
CDIO_MMC_SET_MAIN_CHANNEL_SELECTION_BITS(cdb.field,
|
|
Packit |
dd8086 |
CDIO_MMC_MCSB_ALL_HEADERS);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return run_mmc_cmd (p_cdio->env, mmc_timeout_ms,
|
|
Packit |
dd8086 |
mmc_get_cmd_len(cdb.field[0]), &cdb,
|
|
Packit |
dd8086 |
SCSI_MMC_DATA_READ,
|
|
Packit |
dd8086 |
CDIO_CD_FRAMESIZE_RAW * i_blocks,
|
|
Packit |
dd8086 |
p_buf);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_set_blocksize ( const CdIo_t *p_cdio, uint16_t i_blocksize)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
if ( ! p_cdio ) return DRIVER_OP_UNINIT;
|
|
Packit |
dd8086 |
return
|
|
Packit |
dd8086 |
mmc_set_blocksize_private (p_cdio->env, p_cdio->op.run_mmc_cmd,
|
|
Packit |
dd8086 |
i_blocksize);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/*
|
|
Packit |
dd8086 |
* Local variables:
|
|
Packit |
dd8086 |
* c-file-style: "gnu"
|
|
Packit |
dd8086 |
* tab-width: 8
|
|
Packit |
dd8086 |
* indent-tabs-mode: nil
|
|
Packit |
dd8086 |
* End:
|
|
Packit |
dd8086 |
*/
|