2006-04-04 00:20:48 +00:00
|
|
|
/*
|
2006-04-12 03:23:46 +00:00
|
|
|
$Id: mmc-tool.c,v 1.5 2006/04/12 03:23:46 rocky Exp $
|
2006-04-04 00:20:48 +00:00
|
|
|
|
|
|
|
|
Copyright (C) 2006 Rocky Bernstein <rocky@panix.com>
|
|
|
|
|
|
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
|
the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
|
along with this program; if not, write to the Free Software
|
|
|
|
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
/* A program to using the MMC interface to list CD and drive features
|
|
|
|
|
from the MMC GET_CONFIGURATION command . */
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
|
# include "config.h"
|
|
|
|
|
#endif
|
|
|
|
|
#include <stdio.h>
|
|
|
|
|
#ifdef HAVE_SYS_TYPES_H
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STRING_H
|
|
|
|
|
#include <string.h>
|
|
|
|
|
#endif
|
|
|
|
|
#ifdef HAVE_STDLIB_H
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
|
#endif
|
|
|
|
|
#include <cdio/cdio.h>
|
|
|
|
|
#include <cdio/mmc.h>
|
|
|
|
|
#include "util.h"
|
|
|
|
|
#include "getopt.h"
|
|
|
|
|
|
|
|
|
|
/* Used by `main' to communicate with `parse_opt'. And global options
|
|
|
|
|
*/
|
|
|
|
|
struct arguments
|
|
|
|
|
{
|
|
|
|
|
int i_speed;
|
|
|
|
|
int i_blocksize;
|
|
|
|
|
} opts;
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
init(const char *argv0)
|
|
|
|
|
{
|
|
|
|
|
program_name = strrchr(argv0,'/');
|
|
|
|
|
program_name = program_name ? strdup(program_name+1) : strdup(argv0);
|
|
|
|
|
opts.i_blocksize = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Configuration option codes */
|
|
|
|
|
typedef enum {
|
2006-04-12 03:23:46 +00:00
|
|
|
OPT_HANDLED = 0,
|
|
|
|
|
OPT_USAGE,
|
|
|
|
|
OPT_VERSION,
|
|
|
|
|
} option_t;
|
2006-04-04 00:20:48 +00:00
|
|
|
|
2006-04-12 03:23:46 +00:00
|
|
|
typedef enum {
|
2006-04-04 00:20:48 +00:00
|
|
|
/* These are the remaining configuration options */
|
2006-04-12 03:23:46 +00:00
|
|
|
OP_FINISHED = 0,
|
2006-04-04 00:20:48 +00:00
|
|
|
OP_BLOCKSIZE,
|
2006-04-12 03:23:46 +00:00
|
|
|
OP_CLOSETRAY,
|
2006-04-04 00:20:48 +00:00
|
|
|
OP_EJECT,
|
2006-04-07 02:32:03 +00:00
|
|
|
OP_IDLE,
|
2006-04-04 00:20:48 +00:00
|
|
|
OP_MCN,
|
|
|
|
|
OP_SPEED,
|
2006-04-12 03:23:46 +00:00
|
|
|
} operation_enum_t;
|
|
|
|
|
|
|
|
|
|
typedef struct
|
|
|
|
|
{
|
|
|
|
|
operation_enum_t op;
|
|
|
|
|
union
|
|
|
|
|
{
|
|
|
|
|
long int i_num;
|
|
|
|
|
char * psz;
|
|
|
|
|
} arg;
|
2006-04-04 00:20:48 +00:00
|
|
|
} operation_t;
|
2006-04-12 03:23:46 +00:00
|
|
|
|
2006-04-04 00:20:48 +00:00
|
|
|
|
|
|
|
|
enum { MAX_OPS = 10 };
|
|
|
|
|
|
|
|
|
|
unsigned int last_op = 0;
|
2006-04-12 03:23:46 +00:00
|
|
|
operation_t operation[MAX_OPS] = { {OP_FINISHED, {0}} };
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
push_op(operation_t *p_op)
|
|
|
|
|
{
|
|
|
|
|
if (last_op < MAX_OPS) {
|
|
|
|
|
memcpy(&operation[last_op], p_op, sizeof(operation_t));
|
|
|
|
|
last_op++;
|
|
|
|
|
}
|
|
|
|
|
}
|
2006-04-04 00:20:48 +00:00
|
|
|
|
|
|
|
|
/* Parse a options. */
|
|
|
|
|
static bool
|
|
|
|
|
parse_options (int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
int opt;
|
2006-04-12 03:23:46 +00:00
|
|
|
operation_t op;
|
2006-04-04 00:20:48 +00:00
|
|
|
|
|
|
|
|
const char* helpText =
|
|
|
|
|
"Usage: %s [OPTION...]\n"
|
|
|
|
|
" Issues libcdio Multimedia commands\n"
|
|
|
|
|
"options: \n"
|
|
|
|
|
" -b, --blocksize[=INT] set blocksize. If no block size or a \n"
|
|
|
|
|
" zero blocksize is given we return the\n"
|
|
|
|
|
" current setting.\n"
|
2006-04-12 03:23:46 +00:00
|
|
|
" -e, --eject [drive] eject drive via ALLOW_MEDIUM_REMOVAL\n"
|
2006-04-07 02:32:03 +00:00
|
|
|
" and a MMC START/STOP command\n"
|
|
|
|
|
" -I, --idle set CD-ROM to idle or power down\n"
|
|
|
|
|
" via MMC START/STOP command"
|
2006-04-04 00:20:48 +00:00
|
|
|
" -m, --mcn get media catalog number (AKA UPC)\n"
|
2006-04-07 02:32:03 +00:00
|
|
|
" -s, --speed-KB=INT Set drive speed to SPEED K bytes/sec\n"
|
|
|
|
|
" Note: 1x = 176 KB/s \n"
|
|
|
|
|
" -S, --speed-X=INT Set drive speed to INT X\n"
|
|
|
|
|
" Note: 1x = 176 KB/s \n"
|
2006-04-04 00:20:48 +00:00
|
|
|
" -V, --version display version and copyright information\n"
|
|
|
|
|
" and exit\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"Help options:\n"
|
|
|
|
|
" -?, --help Show this help message\n"
|
|
|
|
|
" --usage Display brief usage message\n";
|
|
|
|
|
|
|
|
|
|
const char* usageText =
|
|
|
|
|
"Usage: %s [-a|--access-mode STRING] [-m|--mode MODE-TYPE]\n"
|
|
|
|
|
" [-s|--speed INT]\n"
|
|
|
|
|
" [-V|--version] [-?|--help] [--usage]\n";
|
|
|
|
|
|
|
|
|
|
/* Command-line options */
|
2006-04-12 03:23:46 +00:00
|
|
|
const char* optionsString = "b::c:e::Is:V?";
|
2006-04-04 00:20:48 +00:00
|
|
|
struct option optionsTable[] = {
|
|
|
|
|
|
|
|
|
|
{"blocksize", optional_argument, &opts.i_blocksize, 'b' },
|
2006-04-12 03:23:46 +00:00
|
|
|
/* {"close", required_argument, NULL, 'c'}, */
|
|
|
|
|
{"eject", optional_argument, NULL, 'e'},
|
2006-04-07 02:32:03 +00:00
|
|
|
{"idle", no_argument, NULL, 'I'},
|
2006-04-04 00:20:48 +00:00
|
|
|
{"mcn", no_argument, NULL, 'm'},
|
2006-04-07 02:32:03 +00:00
|
|
|
{"speed-KB", required_argument, NULL, 's'},
|
|
|
|
|
{"speed-X", required_argument, NULL, 'S'},
|
2006-04-04 00:20:48 +00:00
|
|
|
|
|
|
|
|
{"version", no_argument, NULL, 'V'},
|
|
|
|
|
{"help", no_argument, NULL, '?' },
|
2006-04-12 03:23:46 +00:00
|
|
|
{"usage", no_argument, NULL, OPT_USAGE },
|
2006-04-04 00:20:48 +00:00
|
|
|
{ NULL, 0, NULL, 0 }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
while ((opt = getopt_long(argc, argv, optionsString, optionsTable, NULL)) >= 0)
|
|
|
|
|
switch (opt)
|
|
|
|
|
{
|
|
|
|
|
case 'b':
|
2006-04-12 03:23:46 +00:00
|
|
|
op.op = OP_BLOCKSIZE;
|
|
|
|
|
op.arg.i_num = opts.i_blocksize;
|
|
|
|
|
push_op(&op);
|
|
|
|
|
break;
|
|
|
|
|
case 'c':
|
|
|
|
|
op.op = OP_CLOSETRAY;
|
|
|
|
|
op.arg.psz = strdup(optarg);
|
|
|
|
|
push_op(&op);
|
2006-04-04 00:20:48 +00:00
|
|
|
break;
|
|
|
|
|
case 'e':
|
2006-04-12 03:23:46 +00:00
|
|
|
op.op = OP_EJECT;
|
|
|
|
|
op.arg.psz=NULL;
|
|
|
|
|
if (optarg) op.arg.psz = strdup(optarg);
|
|
|
|
|
push_op(&op);
|
2006-04-04 00:20:48 +00:00
|
|
|
break;
|
2006-04-07 02:32:03 +00:00
|
|
|
case 'I':
|
2006-04-12 03:23:46 +00:00
|
|
|
op.op = OP_IDLE;
|
|
|
|
|
op.arg.psz=NULL;
|
|
|
|
|
push_op(&op);
|
2006-04-07 02:32:03 +00:00
|
|
|
break;
|
2006-04-04 00:20:48 +00:00
|
|
|
case 'm':
|
2006-04-12 03:23:46 +00:00
|
|
|
op.op = OP_MCN;
|
|
|
|
|
op.arg.psz=NULL;
|
|
|
|
|
push_op(&op);
|
2006-04-04 00:20:48 +00:00
|
|
|
break;
|
|
|
|
|
case 's':
|
2006-04-12 03:23:46 +00:00
|
|
|
op.op = OP_SPEED;
|
|
|
|
|
op.arg.i_num=atoi(optarg);
|
|
|
|
|
push_op(&op);
|
2006-04-04 00:20:48 +00:00
|
|
|
break;
|
2006-04-07 02:32:03 +00:00
|
|
|
case 'S':
|
2006-04-12 03:23:46 +00:00
|
|
|
op.op = OP_SPEED;
|
|
|
|
|
op.arg.i_num=176 * atoi(optarg);
|
|
|
|
|
push_op(&op);
|
2006-04-07 02:32:03 +00:00
|
|
|
break;
|
2006-04-04 00:20:48 +00:00
|
|
|
case 'V':
|
|
|
|
|
print_version(program_name, VERSION, 0, true);
|
|
|
|
|
free(program_name);
|
|
|
|
|
exit (EXIT_SUCCESS);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case '?':
|
|
|
|
|
fprintf(stdout, helpText, program_name);
|
|
|
|
|
free(program_name);
|
|
|
|
|
exit(EXIT_INFO);
|
|
|
|
|
break;
|
|
|
|
|
|
2006-04-12 03:23:46 +00:00
|
|
|
case OPT_USAGE:
|
2006-04-04 00:20:48 +00:00
|
|
|
fprintf(stderr, usageText, program_name);
|
|
|
|
|
free(program_name);
|
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
|
break;
|
|
|
|
|
|
2006-04-12 03:23:46 +00:00
|
|
|
case OPT_HANDLED:
|
2006-04-04 00:20:48 +00:00
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (optind < argc) {
|
|
|
|
|
const char *remaining_arg = argv[optind++];
|
|
|
|
|
|
|
|
|
|
if (source_name != NULL) {
|
|
|
|
|
report( stderr, "%s: Source specified in option %s and as %s\n",
|
|
|
|
|
program_name, source_name, remaining_arg );
|
|
|
|
|
free(program_name);
|
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
source_name = strdup(remaining_arg);
|
|
|
|
|
|
|
|
|
|
if (optind < argc) {
|
|
|
|
|
report( stderr, "%s: Source specified in previously %s and %s\n",
|
|
|
|
|
program_name, source_name, remaining_arg );
|
|
|
|
|
free(program_name);
|
|
|
|
|
exit (EXIT_FAILURE);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
|
{
|
|
|
|
|
CdIo_t *p_cdio;
|
|
|
|
|
|
|
|
|
|
driver_return_code_t rc;
|
|
|
|
|
unsigned int i;
|
|
|
|
|
|
|
|
|
|
init(argv[0]);
|
|
|
|
|
|
|
|
|
|
parse_options(argc, argv);
|
|
|
|
|
p_cdio = cdio_open (source_name, DRIVER_DEVICE);
|
|
|
|
|
|
|
|
|
|
if (NULL == p_cdio) {
|
|
|
|
|
printf("Couldn't find CD\n");
|
|
|
|
|
return 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (i=0; i < last_op; i++) {
|
2006-04-12 03:23:46 +00:00
|
|
|
const operation_t *p_op = &operation[i];
|
|
|
|
|
switch (p_op->op) {
|
2006-04-04 00:20:48 +00:00
|
|
|
case OP_SPEED:
|
2006-04-12 03:23:46 +00:00
|
|
|
rc = mmc_set_speed(p_cdio, p_op->arg.i_num);
|
2006-04-04 00:20:48 +00:00
|
|
|
report(stdout, "%s (mmc_set_speed): %s\n", program_name,
|
|
|
|
|
cdio_driver_errmsg(rc));
|
|
|
|
|
break;
|
|
|
|
|
case OP_BLOCKSIZE:
|
2006-04-12 03:23:46 +00:00
|
|
|
if (p_op->arg.i_num) {
|
|
|
|
|
driver_return_code_t rc = mmc_set_blocksize(p_cdio, p_op->arg.i_num);
|
2006-04-04 00:20:48 +00:00
|
|
|
report(stdout, "%s (mmc_set_blocksize): %s\n", program_name,
|
|
|
|
|
cdio_driver_errmsg(rc));
|
|
|
|
|
} else {
|
|
|
|
|
int i_blocksize = mmc_get_blocksize(p_cdio);
|
|
|
|
|
if (i_blocksize > 0) {
|
|
|
|
|
report(stdout, "%s (mmc_get_blocksize): %d\n", program_name,
|
|
|
|
|
i_blocksize);
|
|
|
|
|
} else {
|
|
|
|
|
report(stdout, "%s (mmc_get_blocksize): can't retrieve.\n",
|
|
|
|
|
program_name);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
break;
|
2006-04-12 03:23:46 +00:00
|
|
|
#if 0
|
|
|
|
|
case OP_CLOSETRAY:
|
|
|
|
|
rc = mmc_close_tray(p_cdio, op.arg.psz);
|
|
|
|
|
report(stdout, "%s (mmc_close_tray): %s\n", program_name,
|
|
|
|
|
cdio_driver_errmsg(rc));
|
|
|
|
|
free(p_op->arg.psz);
|
|
|
|
|
break;
|
|
|
|
|
#endif
|
2006-04-04 00:20:48 +00:00
|
|
|
case OP_EJECT:
|
|
|
|
|
rc = mmc_eject_media(p_cdio);
|
|
|
|
|
report(stdout, "%s (mmc_eject_media): %s\n", program_name,
|
|
|
|
|
cdio_driver_errmsg(rc));
|
2006-04-12 03:23:46 +00:00
|
|
|
if (p_op->arg.psz) free(p_op->arg.psz);
|
2006-04-04 00:20:48 +00:00
|
|
|
break;
|
2006-04-07 02:32:03 +00:00
|
|
|
case OP_IDLE:
|
|
|
|
|
rc = mmc_start_stop_media(p_cdio, false, false, true);
|
|
|
|
|
report(stdout, "%s (mmc_start_stop_media - powerdown): %s\n",
|
|
|
|
|
program_name, cdio_driver_errmsg(rc));
|
|
|
|
|
break;
|
2006-04-04 00:20:48 +00:00
|
|
|
case OP_MCN:
|
|
|
|
|
{
|
|
|
|
|
char *psz_mcn = mmc_get_mcn(p_cdio);
|
|
|
|
|
if (psz_mcn) {
|
|
|
|
|
report(stdout, "%s (mmc_get_mcn): %s\n", program_name, psz_mcn);
|
|
|
|
|
free(psz_mcn);
|
|
|
|
|
} else
|
|
|
|
|
report(stdout, "%s (mmc_get_mcn): can't retrieve\n", program_name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
free(source_name);
|
|
|
|
|
cdio_destroy(p_cdio);
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
}
|