Blame lib/driver/mmc/mmc_hl_cmds.c

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
}