Blame src/mmc-tool.c

Packit dd8086
/*
Packit dd8086
  Copyright (C) 2006, 2008, 2010-2011, 2014, 2017
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
/* A program to using the MMC interface to list CD and drive features
Packit dd8086
   from the MMC GET_CONFIGURATION command . */
Packit dd8086
Packit dd8086
#include "util.h"
Packit dd8086
Packit dd8086
#ifdef HAVE_STDIO_H
Packit dd8086
#include <stdio.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_SYS_TYPES_H
Packit dd8086
#include <sys/types.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_STRING_H
Packit dd8086
#include <string.h>
Packit dd8086
#endif
Packit dd8086
#ifdef HAVE_STDLIB_H
Packit dd8086
#include <stdlib.h>
Packit dd8086
#endif
Packit dd8086
#include <cdio/cdio.h>
Packit dd8086
#include <cdio/mmc.h>
Packit dd8086
#include <cdio/mmc_cmds.h>
Packit dd8086
#include "getopt.h"
Packit dd8086
Packit dd8086
Packit dd8086
/* Configuration option codes */
Packit dd8086
typedef enum {
Packit dd8086
  OPT_HANDLED = 0,
Packit dd8086
  OPT_USAGE,
Packit dd8086
  OPT_DRIVE_CAP,
Packit dd8086
  OPT_VERSION,
Packit dd8086
} option_t;
Packit dd8086
Packit dd8086
typedef enum {
Packit dd8086
  /* These are the remaining configuration options */
Packit dd8086
  OP_FINISHED = 0,
Packit dd8086
  OP_BLOCKSIZE,
Packit dd8086
  OP_CLOSETRAY,
Packit dd8086
  OP_EJECT,
Packit dd8086
  OP_IDLE,
Packit dd8086
  OP_INQUIRY,
Packit dd8086
  OP_MODE_SENSE_2A,
Packit dd8086
  OP_MCN,
Packit dd8086
  OP_SPEED,
Packit dd8086
} operation_enum_t;
Packit dd8086
Packit dd8086
typedef struct
Packit dd8086
{
Packit dd8086
  operation_enum_t op;
Packit dd8086
  union
Packit dd8086
  {
Packit dd8086
    long int i_num;
Packit dd8086
    char * psz;
Packit dd8086
  } arg;
Packit dd8086
} operation_t;
Packit dd8086
Packit dd8086
Packit dd8086
enum { MAX_OPS = 10 };
Packit dd8086
Packit dd8086
static unsigned int last_op = 0;
Packit dd8086
static operation_t operation[MAX_OPS] = { {OP_FINISHED, {0}} };
Packit dd8086
Packit dd8086
static void
Packit dd8086
push_op(operation_t *p_op)
Packit dd8086
{
Packit dd8086
  if (last_op < MAX_OPS) {
Packit dd8086
    memcpy(&operation[last_op], p_op, sizeof(operation_t));
Packit dd8086
    last_op++;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/* Parse command-line options. */
Packit dd8086
static bool
Packit dd8086
parse_options (int argc, char *argv[])
Packit dd8086
{
Packit dd8086
  int opt;
Packit dd8086
  int rc = EXIT_FAILURE;
Packit dd8086
  operation_t op;
Packit dd8086
  int i_blocksize = 0;
Packit dd8086
Packit dd8086
  static const char helpText[] =
Packit dd8086
    "Usage: %s [OPTION...]\n"
Packit dd8086
    " Issues libcdio Multimedia commands. Operations occur in the order\n"
Packit dd8086
    " in which the options are given and a given operation may appear\n"
Packit dd8086
    " more than once to have it run more than once.\n"
Packit dd8086
    "options: \n"
Packit dd8086
    "  -b, --blocksize[=INT]           set blocksize. If no block size or a \n"
Packit dd8086
    "                                  zero blocksize is given we return the\n"
Packit dd8086
    "                                  current setting.\n"
Packit dd8086
    "  -C, --drive-cap [6|10]          print mode sense 2a data\n"
Packit dd8086
    "                                  using 6-byte or 10-byte form\n"
Packit dd8086
    "  -c, --close drive               close drive via ALLOW_MEDIUM_REMOVAL\n"
Packit dd8086
    "  -e, --eject [drive]             eject drive via ALLOW_MEDIUM_REMOVAL\n"
Packit dd8086
    "                                  and a MMC START/STOP command\n"
Packit dd8086
    "  -I, --idle                      set CD-ROM to idle or power down\n"
Packit dd8086
    "                                  via MMC START/STOP command\n"
Packit dd8086
    "  -i, --inquiry                   print HW info via INQUIRY\n"
Packit dd8086
    "  -m, --mcn                       get media catalog number (AKA UPC)\n"
Packit dd8086
    "  -s, --speed-KB=INT              Set drive speed to SPEED K bytes/sec\n"
Packit dd8086
    "                                  Note: 1x = 176 KB/s          \n"
Packit dd8086
    "  -S, --speed-X=INT               Set drive speed to INT X\n"
Packit dd8086
    "                                  Note: 1x = 176 KB/s          \n"
Packit dd8086
    "  -V, --version                   display version and copyright information\n"
Packit dd8086
    "                                  and exit\n"
Packit dd8086
    "\n"
Packit dd8086
    "Help options:\n"
Packit dd8086
    "  -?, --help                      Show this help message\n"
Packit dd8086
    "  --usage                         Display brief usage message\n";
Packit dd8086
Packit dd8086
  static const char usageText[] =
Packit dd8086
    "Usage: %s [-b|--blocksize[=INT]] [-m|--mcn]\n"
Packit dd8086
    "        [-I|--idle] [-I|inquiry] [-m[-s|--speed-KB INT]\n"
Packit dd8086
    "        [-V|--version] [-?|--help] [--usage]\n";
Packit dd8086
Packit dd8086
  /* Command-line options */
Packit dd8086
  static const char optionsString[] = "b::c:C::e::Iis:V?";
Packit dd8086
  const struct option optionsTable[] = {
Packit dd8086
Packit dd8086
    {"blocksize", optional_argument, &i_blocksize, 'b' },
Packit dd8086
    {"close", required_argument, NULL, 'c'},
Packit dd8086
    {"drive-cap", optional_argument, NULL, 'C'},
Packit dd8086
    {"eject", optional_argument, NULL, 'e'},
Packit dd8086
    {"idle", no_argument, NULL, 'I'},
Packit dd8086
    {"inquiry", no_argument, NULL, 'i'},
Packit dd8086
    {"mcn",   no_argument, NULL, 'm'},
Packit dd8086
    {"speed-KB", required_argument, NULL, 's'},
Packit dd8086
    {"speed-X",  required_argument, NULL, 'S'},
Packit dd8086
Packit dd8086
    {"version", no_argument, NULL, 'V'},
Packit dd8086
    {"help", no_argument, NULL, '?' },
Packit dd8086
    {"usage", no_argument, NULL, OPT_USAGE },
Packit dd8086
    { NULL, 0, NULL, 0 }
Packit dd8086
  };
Packit dd8086
Packit dd8086
  while ((opt = getopt_long(argc, argv, optionsString, optionsTable, NULL)) >= 0)
Packit dd8086
    switch (opt)
Packit dd8086
      {
Packit dd8086
      case 'b':
Packit dd8086
	op.op = OP_BLOCKSIZE;
Packit dd8086
	op.arg.i_num = i_blocksize;
Packit dd8086
	push_op(&op);
Packit dd8086
	break;
Packit dd8086
      case 'C':
Packit dd8086
	op.arg.i_num = optarg ? atoi(optarg) : 10;
Packit dd8086
	switch (op.arg.i_num) {
Packit dd8086
	case 10:
Packit dd8086
	    op.op = OP_MODE_SENSE_2A;
Packit dd8086
	  op.arg.i_num = 10;
Packit dd8086
	  push_op(&op);
Packit dd8086
	  break;
Packit dd8086
	case 6:
Packit dd8086
	  op.op = OP_MODE_SENSE_2A;
Packit dd8086
	  op.arg.i_num = 6;
Packit dd8086
	  push_op(&op);
Packit dd8086
	  break;
Packit dd8086
	default:
Packit dd8086
	  report( stderr, "%s: Expecting 6 or 10 or nothing\n", program_name );
Packit dd8086
	}
Packit dd8086
	break;
Packit dd8086
      case 'c':
Packit dd8086
	op.op = OP_CLOSETRAY;
Packit dd8086
	op.arg.psz = strdup(optarg);
Packit dd8086
	push_op(&op);
Packit dd8086
	break;
Packit dd8086
      case 'e':
Packit dd8086
	op.op = OP_EJECT;
Packit dd8086
	op.arg.psz=NULL;
Packit dd8086
	if (optarg) op.arg.psz = strdup(optarg);
Packit dd8086
	push_op(&op);
Packit dd8086
	break;
Packit dd8086
      case 'i':
Packit dd8086
	op.op = OP_INQUIRY;
Packit dd8086
	op.arg.psz=NULL;
Packit dd8086
	push_op(&op);
Packit dd8086
	break;
Packit dd8086
      case 'I':
Packit dd8086
	op.op = OP_IDLE;
Packit dd8086
	op.arg.psz=NULL;
Packit dd8086
	push_op(&op);
Packit dd8086
	break;
Packit dd8086
      case 'm':
Packit dd8086
	op.op = OP_MCN;
Packit dd8086
	op.arg.psz=NULL;
Packit dd8086
	push_op(&op);
Packit dd8086
	break;
Packit dd8086
      case 's':
Packit dd8086
	op.op = OP_SPEED;
Packit dd8086
	op.arg.i_num=atoi(optarg);
Packit dd8086
	push_op(&op);
Packit dd8086
	break;
Packit dd8086
      case 'S':
Packit dd8086
	op.op = OP_SPEED;
Packit dd8086
	op.arg.i_num=176 * atoi(optarg);
Packit dd8086
	push_op(&op);
Packit dd8086
	break;
Packit dd8086
      case 'V':
Packit dd8086
        print_version(program_name, VERSION, 0, true);
Packit dd8086
	rc = EXIT_SUCCESS;
Packit dd8086
	goto error_exit;
Packit dd8086
      case '?':
Packit dd8086
	fprintf(stdout, helpText, program_name);
Packit dd8086
	goto error_exit;
Packit dd8086
      case OPT_USAGE:
Packit dd8086
	fprintf(stderr, usageText, program_name);
Packit dd8086
	goto error_exit;
Packit dd8086
Packit dd8086
      case OPT_HANDLED:
Packit dd8086
	break;
Packit dd8086
      }
Packit dd8086
Packit dd8086
  if (optind < argc) {
Packit dd8086
    const char *remaining_arg = argv[optind++];
Packit dd8086
Packit dd8086
    if (source_name != NULL) {
Packit dd8086
      report( stderr, "%s: Source specified in option %s and as %s\n",
Packit dd8086
	      program_name, source_name, remaining_arg );
Packit dd8086
      goto error_exit;
Packit dd8086
    }
Packit dd8086
Packit dd8086
    source_name = strdup(remaining_arg);
Packit dd8086
Packit dd8086
    if (optind < argc) {
Packit dd8086
      report( stderr, "%s: Source specified in previously %s and %s\n",
Packit dd8086
	      program_name, source_name, remaining_arg );
Packit dd8086
      free(source_name);
Packit dd8086
      goto error_exit;
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
  return true;
Packit dd8086
 error_exit:
Packit dd8086
  free(program_name);
Packit dd8086
  exit(rc);
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
_log_handler (cdio_log_level_t level, const char message[])
Packit dd8086
{
Packit dd8086
  if (level == CDIO_LOG_ERROR) {
Packit dd8086
    // print an error like default, but *don't* exit.
Packit dd8086
    fprintf (stderr, "**ERROR: %s\n", message);
Packit dd8086
    fflush (stderr);
Packit dd8086
    return;
Packit dd8086
  }
Packit dd8086
  gl_default_cdio_log_handler (level, message);
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
init(const char *argv0)
Packit dd8086
{
Packit dd8086
  gl_default_cdio_log_handler = cdio_log_set_handler (_log_handler);
Packit dd8086
  program_name = strrchr(argv0,'/');
Packit dd8086
  program_name = program_name ? strdup(program_name+1) : strdup(argv0);
Packit dd8086
}
Packit dd8086
Packit dd8086
static void
Packit dd8086
print_mode_sense (unsigned int i_mmc_size, const uint8_t buf[30])
Packit dd8086
{
Packit dd8086
  printf("Mode sense %d information\n", i_mmc_size);
Packit dd8086
  if (buf[2] & 0x01) {
Packit dd8086
    printf("\tReads CD-R media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[2] & 0x02) {
Packit dd8086
    printf("\tReads CD-RW media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[2] & 0x04) {
Packit dd8086
    printf("\tReads fixed-packet tracks when Addressing type is method 2.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[2] & 0x08) {
Packit dd8086
    printf("\tReads DVD ROM media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[2] & 0x10) {
Packit dd8086
    printf("\tReads DVD-R media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[2] & 0x20) {
Packit dd8086
    printf("\tReads DVD-RAM media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[2] & 0x40) {
Packit dd8086
    printf("\tReads DVD-RAM media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[3] & 0x01) {
Packit dd8086
    printf("\tWrites CD-R media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[3] & 0x02) {
Packit dd8086
    printf("\tWrites CD-RW media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[3] & 0x04) {
Packit dd8086
    printf("\tSupports emulation write.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[3] & 0x10) {
Packit dd8086
    printf("\tWrites DVD-R media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[3] & 0x20) {
Packit dd8086
    printf("\tWrites DVD-RAM media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[4] & 0x01) {
Packit dd8086
    printf("\tCan play audio.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[4] & 0x02) {
Packit dd8086
    printf("\tDelivers composition A/V stream.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[4] & 0x04) {
Packit dd8086
    printf("\tSupports digital output on port 2.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[4] & 0x08) {
Packit dd8086
    printf("\tSupports digital output on port 1.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[4] & 0x10) {
Packit dd8086
    printf("\tReads Mode-2 form 1 (e.g. XA) media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[4] & 0x20) {
Packit dd8086
    printf("\tReads Mode-2 form 2 media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[4] & 0x40) {
Packit dd8086
    printf("\tReads multi-session CD media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[4] & 0x80) {
Packit dd8086
    printf("\tSupports Buffer under-run free recording on CD-R/RW media.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[4] & 0x01) {
Packit dd8086
    printf("\tCan read audio data with READ CD.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[4] & 0x02) {
Packit dd8086
    printf("\tREAD CD data stream is accurate.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[5] & 0x04) {
Packit dd8086
    printf("\tReads R-W subchannel information.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[5] & 0x08) {
Packit dd8086
    printf("\tReads de-interleaved R-W subchannel.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[5] & 0x10) {
Packit dd8086
    printf("\tSupports C2 error pointers.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[5] & 0x20) {
Packit dd8086
    printf("\tReads ISRC information.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[5] & 0x40) {
Packit dd8086
    printf("\tReads ISRC informaton.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[5] & 0x40) {
Packit dd8086
    printf("\tReads media catalog number (MCN also known as UPC).\n");
Packit dd8086
  }
Packit dd8086
  if (buf[5] & 0x80) {
Packit dd8086
    printf("\tReads bar codes.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[6] & 0x01) {
Packit dd8086
    printf("\tPREVENT/ALLOW may lock media.\n");
Packit dd8086
  }
Packit dd8086
  printf("\tLock state is %slocked.\n", (buf[6] & 0x02) ? "" : "un");
Packit dd8086
  printf("\tPREVENT/ALLOW jumper is %spresent.\n", (buf[6] & 0x04) ? "": "not ");
Packit dd8086
  if (buf[6] & 0x08) {
Packit dd8086
    printf("\tEjects media with START STOP UNIT.\n");
Packit dd8086
  }
Packit dd8086
  {
Packit dd8086
    const unsigned int i_load_type = (buf[6]>>5 & 0x07);
Packit dd8086
    printf("\tLoading mechanism type  is %d: ", i_load_type);
Packit dd8086
    switch (buf[6]>>5 & 0x07) {
Packit dd8086
    case 0:
Packit dd8086
      printf("caddy type loading mechanism.\n");
Packit dd8086
      break;
Packit dd8086
    case 1:
Packit dd8086
      printf("tray type loading mechanism.\n");
Packit dd8086
      break;
Packit dd8086
    case 2:
Packit dd8086
      printf("popup type loading mechanism.\n");
Packit dd8086
      break;
Packit dd8086
    case 3:
Packit dd8086
      printf("reserved\n");
Packit dd8086
      break;
Packit dd8086
    case 4:
Packit dd8086
      printf("changer with individually changeable discs.\n");
Packit dd8086
      break;
Packit dd8086
    case 5:
Packit dd8086
      printf("changer using Magazine mechanism.\n");
Packit dd8086
      break;
Packit dd8086
    case 6:
Packit dd8086
      printf("changer using Magazine mechanism.\n");
Packit dd8086
      break;
Packit dd8086
    default:
Packit dd8086
      printf("Invalid.\n");
Packit dd8086
      break;
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (buf[7] & 0x01) {
Packit dd8086
    printf("\tVolume controls each channel separately.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[7] & 0x02) {
Packit dd8086
    printf("\tHas a changer that supports disc present reporting.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[7] & 0x04) {
Packit dd8086
    printf("\tCan load empty slot in changer.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[7] & 0x08) {
Packit dd8086
    printf("\tSide change capable.\n");
Packit dd8086
  }
Packit dd8086
  if (buf[7] & 0x10) {
Packit dd8086
    printf("\tReads raw R-W subchannel information from lead in.\n");
Packit dd8086
  }
Packit dd8086
  {
Packit dd8086
    const unsigned int i_speed_Kbs = CDIO_MMC_GETPOS_LEN16(buf,  8);
Packit dd8086
    printf("\tMaximum read speed is %d K bytes/sec (about %dX)\n",
Packit dd8086
	   i_speed_Kbs, i_speed_Kbs / 176) ;
Packit dd8086
  }
Packit dd8086
  printf("\tNumber of Volume levels is %d\n",  CDIO_MMC_GETPOS_LEN16(buf, 10));
Packit dd8086
  printf("\tBuffers size for data is %d KB\n", CDIO_MMC_GETPOS_LEN16(buf, 12));
Packit dd8086
  printf("\tCurrent read speed is %d KB\n",    CDIO_MMC_GETPOS_LEN16(buf, 14));
Packit dd8086
  printf("\tMaximum write speed is %d KB\n",   CDIO_MMC_GETPOS_LEN16(buf, 18));
Packit dd8086
  printf("\tCurrent write speed is %d KB\n",   CDIO_MMC_GETPOS_LEN16(buf, 28));
Packit dd8086
}
Packit dd8086
Packit dd8086
int
Packit dd8086
main(int argc, char *argv[])
Packit dd8086
{
Packit dd8086
  CdIo_t *p_cdio;
Packit dd8086
Packit dd8086
  driver_return_code_t rc = DRIVER_OP_SUCCESS;
Packit dd8086
  unsigned int i;
Packit dd8086
Packit dd8086
  init(argv[0]);
Packit dd8086
Packit dd8086
  parse_options(argc, argv);
Packit dd8086
  p_cdio = cdio_open (source_name, DRIVER_DEVICE);
Packit dd8086
Packit dd8086
  if (NULL == p_cdio) {
Packit dd8086
    printf("Couldn't find CD\n");
Packit dd8086
    rc = 1;
Packit dd8086
    goto exit;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  for (i=0; i < last_op; i++) {
Packit dd8086
    const operation_t *p_op = &operation[i];
Packit dd8086
    switch (p_op->op) {
Packit dd8086
    case OP_SPEED:
Packit dd8086
      rc = mmc_set_speed(p_cdio, p_op->arg.i_num, 0);
Packit dd8086
      report(stdout, "%s (mmc_set_speed): %s\n", program_name,
Packit dd8086
	     cdio_driver_errmsg(rc));
Packit dd8086
      break;
Packit dd8086
    case OP_BLOCKSIZE:
Packit dd8086
      if (p_op->arg.i_num) {
Packit dd8086
	driver_return_code_t blocksize_rc = mmc_set_blocksize(p_cdio, p_op->arg.i_num);
Packit dd8086
	report(stdout, "%s (mmc_set_blocksize): %s\n", program_name,
Packit dd8086
	       cdio_driver_errmsg(blocksize_rc));
Packit dd8086
      } else {
Packit dd8086
	int i_blocksize = mmc_get_blocksize(p_cdio);
Packit dd8086
	if (i_blocksize > 0) {
Packit dd8086
	  report(stdout, "%s (mmc_get_blocksize): %d\n", program_name,
Packit dd8086
		 i_blocksize);
Packit dd8086
	} else {
Packit dd8086
	  report(stdout, "%s (mmc_get_blocksize): can't retrieve.\n",
Packit dd8086
		 program_name);
Packit dd8086
	}
Packit dd8086
      }
Packit dd8086
      break;
Packit dd8086
    case OP_MODE_SENSE_2A:
Packit dd8086
      {
Packit dd8086
	uint8_t buf[30] = { 0, };    /* Place to hold returned data */
Packit dd8086
	if (p_op->arg.i_num == 10) {
Packit dd8086
	  rc = mmc_mode_sense_10(p_cdio, buf, sizeof(buf),
Packit dd8086
				 CDIO_MMC_CAPABILITIES_PAGE);
Packit dd8086
	} else {
Packit dd8086
	  rc = mmc_mode_sense_6(p_cdio, buf, sizeof(buf),
Packit dd8086
				 CDIO_MMC_CAPABILITIES_PAGE);
Packit dd8086
	}
Packit dd8086
	if (DRIVER_OP_SUCCESS == rc) {
Packit dd8086
	  print_mode_sense(p_op->arg.i_num, buf);
Packit dd8086
	} else {
Packit dd8086
	  report(stdout, "%s (mmc_mode_sense 2a - drive_cap %d): %s\n",
Packit dd8086
		 program_name, p_op->arg.i_num, cdio_driver_errmsg(rc));
Packit dd8086
	}
Packit dd8086
      }
Packit dd8086
      break;
Packit dd8086
    case OP_CLOSETRAY:
Packit dd8086
      rc = mmc_close_tray(p_cdio);
Packit dd8086
      report(stdout, "%s (mmc_close_tray): %s\n", program_name,
Packit dd8086
	     cdio_driver_errmsg(rc));
Packit dd8086
      free(p_op->arg.psz);
Packit dd8086
      break;
Packit dd8086
    case OP_EJECT:
Packit dd8086
      rc = mmc_eject_media(p_cdio);
Packit dd8086
      report(stdout, "%s (mmc_eject_media): %s\n", program_name,
Packit dd8086
	     cdio_driver_errmsg(rc));
Packit dd8086
      if (p_op->arg.psz) free(p_op->arg.psz);
Packit dd8086
      break;
Packit dd8086
    case OP_IDLE:
Packit dd8086
      rc = mmc_start_stop_unit(p_cdio, false, false, true, 0);
Packit dd8086
      report(stdout, "%s (mmc_start_stop_media - powerdown): %s\n",
Packit dd8086
	     program_name, cdio_driver_errmsg(rc));
Packit dd8086
      break;
Packit dd8086
    case OP_INQUIRY:
Packit dd8086
      {
Packit dd8086
	cdio_hwinfo_t hw_info = { "", "", ""};
Packit dd8086
	if (mmc_get_hwinfo(p_cdio, &hw_info)) {
Packit dd8086
	  printf("%-8s: %s\n%-8s: %s\n%-8s: %s\n",
Packit dd8086
		 "Vendor"  , hw_info.psz_vendor,
Packit dd8086
		 "Model"   , hw_info.psz_model,
Packit dd8086
		 "Revision", hw_info.psz_revision);
Packit dd8086
	} else {
Packit dd8086
	  report(stdout, "%s (mmc_gpcmd_inquiry error)\n", program_name);
Packit dd8086
	}
Packit dd8086
      }
Packit dd8086
      break;
Packit dd8086
    case OP_MCN:
Packit dd8086
      {
Packit dd8086
	char *psz_mcn = mmc_get_mcn(p_cdio);
Packit dd8086
	if (psz_mcn) {
Packit dd8086
	  report(stdout, "%s (mmc_get_mcn): %s\n", program_name, psz_mcn);
Packit dd8086
	  cdio_free(psz_mcn);
Packit dd8086
	} else
Packit dd8086
	  report(stdout, "%s (mmc_get_mcn): can't retrieve\n", program_name);
Packit dd8086
      }
Packit dd8086
      break;
Packit dd8086
    default:
Packit dd8086
      ;
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
 exit:
Packit dd8086
  free(source_name);
Packit dd8086
  free(program_name);
Packit dd8086
  cdio_destroy(p_cdio);
Packit dd8086
Packit dd8086
  return rc;
Packit dd8086
}