|
Packit |
dd8086 |
/*
|
|
Packit |
dd8086 |
"Higher-level" Multimedia Command (MMC) commands which build on
|
|
Packit |
dd8086 |
the "lower-level" commands.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
Copyright (C) 2010-2011, 2014 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 |
#ifdef HAVE_CONFIG_H
|
|
Packit |
dd8086 |
# include "config.h"
|
|
Packit |
dd8086 |
# define __CDIO_CONFIG_H__ 1
|
|
Packit |
dd8086 |
#endif
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
#include <cdio/cdio.h>
|
|
Packit |
dd8086 |
#include <cdio/mmc_cmds.h>
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Close tray using a MMC START STOP UNIT command.
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@return DRIVER_OP_SUCCESS (0) if we got the status.
|
|
Packit |
dd8086 |
return codes are the same as driver_return_code_t
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_close_tray(CdIo_t *p_cdio)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
return mmc_start_stop_unit(p_cdio, false, false, 0, 0);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Eject using MMC commands. If CD-ROM is "locked" we'll unlock it.
|
|
Packit |
dd8086 |
Command is not "immediate" -- we'll wait for the command to complete.
|
|
Packit |
dd8086 |
For a more general (and lower-level) routine, @see mmc_start_stop_media.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@return DRIVER_OP_SUCCESS (0) if we got the status.
|
|
Packit |
dd8086 |
return codes are the same as driver_return_code_t
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_eject_media( const CdIo_t *p_cdio )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
int i_status = 0;
|
|
Packit |
dd8086 |
i_status = mmc_prevent_allow_medium_removal(p_cdio, false, false, 0);
|
|
Packit |
dd8086 |
if (0 != i_status) return i_status;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return mmc_start_stop_unit(p_cdio, true, false, 0, 0);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Detects if a disc (CD or DVD) is erasable or not.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_user_data the CD object to be acted upon.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param b_erasable, if not NULL, on return will be set indicate whether
|
|
Packit |
dd8086 |
the operation was a success (DRIVER_OP_SUCCESS) or if not to some
|
|
Packit |
dd8086 |
other value.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@return true if the disc is detected as erasable (rewritable), false
|
|
Packit |
dd8086 |
otherwise.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
/* From Frank Endres: */
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_get_disc_erasable(const CdIo_t *p_cdio, bool *b_erasable) {
|
|
Packit |
dd8086 |
uint8_t buf[42] = { 0, };
|
|
Packit |
dd8086 |
driver_return_code_t i_status;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
i_status = mmc_read_disc_information(p_cdio, buf, sizeof(buf),
|
|
Packit |
dd8086 |
CDIO_MMC_READ_DISC_INFO_STANDARD, 0);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (DRIVER_OP_SUCCESS == i_status)
|
|
Packit |
dd8086 |
*b_erasable = ((buf[2] & 0x10) ? true : false);
|
|
Packit |
dd8086 |
else
|
|
Packit |
dd8086 |
*b_erasable = false;
|
|
Packit |
dd8086 |
return i_status;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* From Frank Endres: */
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Detects the disc type using the SCSI-MMC GET CONFIGURATION command.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param i_status, if not NULL, on return will be set indicate whether
|
|
Packit |
dd8086 |
the operation was a success (DRIVER_OP_SUCCESS) or if not to some
|
|
Packit |
dd8086 |
other value.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_disctype the disc type set on success.
|
|
Packit |
dd8086 |
@return DRIVER_OP_SUCCESS (0) if we got the status.
|
|
Packit |
dd8086 |
return codes are the same as driver_return_code_t
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_get_disctype( const CdIo_t *p_cdio, unsigned int i_timeout_ms,
|
|
Packit |
dd8086 |
cdio_mmc_feature_profile_t *p_disctype)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
uint8_t buf[500] = { 0, };
|
|
Packit |
dd8086 |
driver_return_code_t i_status;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (0 == i_timeout_ms) i_timeout_ms = mmc_timeout_ms;
|
|
Packit |
dd8086 |
i_status = mmc_get_configuration(p_cdio, &buf, sizeof(buf),
|
|
Packit |
dd8086 |
CDIO_MMC_GET_CONF_ALL_FEATURES,
|
|
Packit |
dd8086 |
0, i_timeout_ms);
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (DRIVER_OP_SUCCESS == i_status) {
|
|
Packit |
dd8086 |
uint8_t *p, *q;
|
|
Packit |
dd8086 |
uint8_t profiles_list_length;
|
|
Packit |
dd8086 |
uint16_t profile_number;
|
|
Packit |
dd8086 |
bool profile_active;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/* there is always a profile list feature listed at the
|
|
Packit |
dd8086 |
first place of the features list */
|
|
Packit |
dd8086 |
p = buf + 8;
|
|
Packit |
dd8086 |
profiles_list_length = p[3];
|
|
Packit |
dd8086 |
q = p+4;
|
|
Packit |
dd8086 |
*p_disctype = CDIO_MMC_FEATURE_PROF_NON_CONFORM;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
while ((CDIO_MMC_FEATURE_PROF_NON_CONFORM == *p_disctype) &&
|
|
Packit |
dd8086 |
(q < p + profiles_list_length)) {
|
|
Packit |
dd8086 |
profile_number = CDIO_MMC_GET_LEN16(q);
|
|
Packit |
dd8086 |
profile_active = q[2] & 0x01;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
if (profile_active)
|
|
Packit |
dd8086 |
switch (profile_number) {
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_CD_ROM:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_CD_R:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_CD_RW:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_DVD_ROM:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_DVD_R_SEQ:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_DVD_RAM:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_DVD_RW_RO:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_DVD_RW_SEQ:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_DVD_R_DL_SEQ:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_DVD_R_DL_JR:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_DVD_PRW:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_DVD_PR:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_DVD_PRW_DL:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_DVD_PR_DL:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_BD_ROM:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_BD_SEQ:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_BD_R_RANDOM:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_BD_RE:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_HD_DVD_ROM:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_HD_DVD_R:
|
|
Packit |
dd8086 |
case CDIO_MMC_FEATURE_PROF_HD_DVD_RAM:
|
|
Packit |
dd8086 |
*p_disctype = (cdio_mmc_feature_profile_t) profile_number;
|
|
Packit |
dd8086 |
break;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
q += 4;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
return i_status;
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Run a SCSI-MMC MMC MODE SENSE command (6- or 10-byte version)
|
|
Packit |
dd8086 |
and put the results in p_buf
|
|
Packit |
dd8086 |
@param p_cdio the CD object to be acted upon.
|
|
Packit |
dd8086 |
@param p_buf pointer to location to store mode sense information
|
|
Packit |
dd8086 |
@param i_size number of bytes allocated to p_buf
|
|
Packit |
dd8086 |
@param page which "page" of the mode sense command we are interested in
|
|
Packit |
dd8086 |
@return DRIVER_OP_SUCCESS if we ran the command ok.
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_mode_sense(CdIo_t *p_cdio, /*out*/ void *p_buf, unsigned int i_size,
|
|
Packit |
dd8086 |
int page)
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
/* We used to make a choice as to which routine we'd use based
|
|
Packit |
dd8086 |
cdio_have_atapi(). But since that calls this in its determination,
|
|
Packit |
dd8086 |
we had an infinite recursion. So we can't use cdio_have_atapi()
|
|
Packit |
dd8086 |
(until we put in better capability checks.)
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
if ( DRIVER_OP_SUCCESS == mmc_mode_sense_6(p_cdio, p_buf, i_size, page) )
|
|
Packit |
dd8086 |
return DRIVER_OP_SUCCESS;
|
|
Packit |
dd8086 |
return mmc_mode_sense_10(p_cdio, p_buf, i_size, page);
|
|
Packit |
dd8086 |
}
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
/**
|
|
Packit |
dd8086 |
Set the drive speed in CD-ROM speed units.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@param p_cdio CD structure set by cdio_open().
|
|
Packit |
dd8086 |
@param i_drive_speed speed in CD-ROM speed units. Note this
|
|
Packit |
dd8086 |
not Kbytes/sec as would be used in the MMC spec or
|
|
Packit |
dd8086 |
in mmc_set_speed(). To convert CD-ROM speed units
|
|
Packit |
dd8086 |
to Kbs, multiply the number by 176 (for raw data)
|
|
Packit |
dd8086 |
and by 150 (for filesystem data). On many CD-ROM
|
|
Packit |
dd8086 |
drives, specifying a value too large will result
|
|
Packit |
dd8086 |
in using the fastest speed. GNU/Linux ioctl
|
|
Packit |
dd8086 |
treats <= 0 as max speed, so we'll do that here
|
|
Packit |
dd8086 |
as well.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@return the drive speed if greater than 0. -1 if we had an error. is -2
|
|
Packit |
dd8086 |
returned if this is not implemented for the current driver.
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
@see cdio_set_speed and mmc_set_speed
|
|
Packit |
dd8086 |
*/
|
|
Packit |
dd8086 |
driver_return_code_t
|
|
Packit |
dd8086 |
mmc_set_drive_speed( const CdIo_t *p_cdio, int i_drive_speed )
|
|
Packit |
dd8086 |
{
|
|
Packit |
dd8086 |
if (i_drive_speed <= 0)
|
|
Packit |
dd8086 |
i_drive_speed = 0xffff;
|
|
Packit |
dd8086 |
else
|
|
Packit |
dd8086 |
i_drive_speed *= 176;
|
|
Packit |
dd8086 |
|
|
Packit |
dd8086 |
return mmc_set_speed(p_cdio, i_drive_speed, 0);
|
|
Packit |
dd8086 |
}
|