mmc: add mmc_close_tray().

mmc-tool: add option for close tray and to get mode-sense 2A data.
This commit is contained in:
rocky
2006-04-12 09:30:14 +00:00
parent a87210b686
commit 0c2b1bfa9e
8 changed files with 276 additions and 88 deletions

View File

@@ -1,7 +1,7 @@
/*
$Id: mmc-tool.c,v 1.5 2006/04/12 03:23:46 rocky Exp $
$Id: mmc-tool.c,v 1.6 2006/04/12 09:30:14 rocky Exp $
Copyright (C) 2006 Rocky Bernstein <rocky@panix.com>
Copyright (C) 2006 Rocky Bernstein <rocky@cpan.org>
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
@@ -38,26 +38,18 @@
#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 {
OPT_HANDLED = 0,
OPT_USAGE,
OPT_DRIVE_CAP,
OPT_VERSION,
} option_t;
@@ -68,6 +60,7 @@ typedef enum {
OP_CLOSETRAY,
OP_EJECT,
OP_IDLE,
OP_MODE_SENSE_2A,
OP_MCN,
OP_SPEED,
} operation_enum_t;
@@ -103,6 +96,7 @@ parse_options (int argc, char *argv[])
{
int opt;
operation_t op;
int i_blocksize = 0;
const char* helpText =
"Usage: %s [OPTION...]\n"
@@ -111,6 +105,9 @@ parse_options (int argc, char *argv[])
" -b, --blocksize[=INT] set blocksize. If no block size or a \n"
" zero blocksize is given we return the\n"
" current setting.\n"
" -C, --drive-cap [6|10] print mode sense 2a data\n"
" using 6-byte or 10-byte form\n"
" -c, --close drive close drive via ALLOW_MEDIUM_REMOVAL\n"
" -e, --eject [drive] eject drive via ALLOW_MEDIUM_REMOVAL\n"
" and a MMC START/STOP command\n"
" -I, --idle set CD-ROM to idle or power down\n"
@@ -133,11 +130,12 @@ parse_options (int argc, char *argv[])
" [-V|--version] [-?|--help] [--usage]\n";
/* Command-line options */
const char* optionsString = "b::c:e::Is:V?";
const char* optionsString = "b::c:C::e::Is:V?";
struct option optionsTable[] = {
{"blocksize", optional_argument, &opts.i_blocksize, 'b' },
/* {"close", required_argument, NULL, 'c'}, */
{"blocksize", optional_argument, &i_blocksize, 'b' },
{"close", required_argument, NULL, 'c'},
{"drive-cap", optional_argument, NULL, 'C'},
{"eject", optional_argument, NULL, 'e'},
{"idle", no_argument, NULL, 'I'},
{"mcn", no_argument, NULL, 'm'},
@@ -155,9 +153,26 @@ parse_options (int argc, char *argv[])
{
case 'b':
op.op = OP_BLOCKSIZE;
op.arg.i_num = opts.i_blocksize;
op.arg.i_num = i_blocksize;
push_op(&op);
break;
case 'C':
op.arg.i_num = optarg ? atoi(optarg) : 10;
switch (op.arg.i_num) {
case 10:
op.op = OP_MODE_SENSE_2A;
op.arg.i_num = 10;
push_op(&op);
break;
case 6:
op.op = OP_MODE_SENSE_2A;
op.arg.i_num = 6;
push_op(&op);
break;
default:
report( stderr, "%s: Expecting 6 or 10 or nothing\n", program_name );
}
break;
case 'c':
op.op = OP_CLOSETRAY;
op.arg.psz = strdup(optarg);
@@ -209,6 +224,7 @@ parse_options (int argc, char *argv[])
case OPT_HANDLED:
break;
i_blocksize = 0;
}
if (optind < argc) {
@@ -234,6 +250,163 @@ parse_options (int argc, char *argv[])
return true;
}
static void
print_mode_sense (unsigned int i_mmc_size, const uint8_t buf[22])
{
printf("Mode sense %d information\n", i_mmc_size);
if (buf[2] & 0x01) {
printf("\tReads CD-R media.\n");
}
if (buf[2] & 0x02) {
printf("\tReads CD-RW media.\n");
}
if (buf[2] & 0x04) {
printf("\tReads fixed-packet tracks when Addressing type is method 2.\n");
}
if (buf[2] & 0x08) {
printf("\tReads DVD ROM media.\n");
}
if (buf[2] & 0x10) {
printf("\tReads DVD-R media.\n");
}
if (buf[2] & 0x20) {
printf("\tReads DVD-RAM media.\n");
}
if (buf[2] & 0x40) {
printf("\tReads DVD-RAM media.\n");
}
if (buf[3] & 0x01) {
printf("\tWrites CD-R media.\n");
}
if (buf[3] & 0x02) {
printf("\tWrites CD-RW media.\n");
}
if (buf[3] & 0x04) {
printf("\tSupports emulation write.\n");
}
if (buf[3] & 0x10) {
printf("\tWrites DVD-R media.\n");
}
if (buf[3] & 0x20) {
printf("\tWrites DVD-RAM media.\n");
}
if (buf[4] & 0x01) {
printf("\tCan play audio.\n");
}
if (buf[4] & 0x02) {
printf("\tDelivers composition A/V stream.\n");
}
if (buf[4] & 0x04) {
printf("\tSupports digital output on port 2.\n");
}
if (buf[4] & 0x08) {
printf("\tSupports digital output on port 1.\n");
}
if (buf[4] & 0x10) {
printf("\tReads Mode-2 form 1 (e.g. XA) media.\n");
}
if (buf[4] & 0x20) {
printf("\tReads Mode-2 form 2 media.\n");
}
if (buf[4] & 0x40) {
printf("\tReads multi-session CD media.\n");
}
if (buf[4] & 0x80) {
printf("\tSupports Buffer under-run free recording on CD-R/RW media.\n");
}
if (buf[4] & 0x01) {
printf("\tCan read audio data with READ CD.\n");
}
if (buf[4] & 0x02) {
printf("\tREAD CD data stream is accurate.\n");
}
if (buf[5] & 0x04) {
printf("\tReads R-W subchannel information.\n");
}
if (buf[5] & 0x08) {
printf("\tReads de-interleaved R-W subchannel.\n");
}
if (buf[5] & 0x10) {
printf("\tSupports C2 error pointers.\n");
}
if (buf[5] & 0x20) {
printf("\tReads ISRC information.\n");
}
if (buf[5] & 0x40) {
printf("\tReads ISRC informaton.\n");
}
if (buf[5] & 0x40) {
printf("\tReads media catalog number (MCN also known as UPC).\n");
}
if (buf[5] & 0x80) {
printf("\tReads bar codes.\n");
}
if (buf[6] & 0x01) {
printf("\tPREVENT/ALLOW may lock media.\n");
}
printf("\tLock state is %slocked.\n", (buf[6] & 0x02) ? "" : "un");
printf("\tPREVENT/ALLOW jumper is %spresent.\n", (buf[6] & 0x04) ? "": "not ");
if (buf[6] & 0x08) {
printf("\tEjects media with START STOP UNIT.\n");
}
{
const unsigned int i_load_type = (buf[6]>>5 & 0x07);
printf("\tLoading mechanism type is %d: ", i_load_type);
switch (buf[6]>>5 & 0x07) {
case 0:
printf("caddy type loading mechanism.\n");
break;
case 1:
printf("tray type loading mechanism.\n");
break;
case 2:
printf("popup type loading mechanism.\n");
break;
case 3:
printf("reserved\n");
break;
case 4:
printf("changer with individually changeable discs.\n");
break;
case 5:
printf("changer using Magazine mechanism.\n");
break;
case 6:
printf("changer using Magazine mechanism.\n");
break;
default:
printf("Invalid.\n");
break;
}
}
if (buf[7] & 0x01) {
printf("\tVolume controls each channel separately.\n");
}
if (buf[7] & 0x02) {
printf("\tHas a changer that supports disc present reporting.\n");
}
if (buf[7] & 0x04) {
printf("\tCan load empty slot in changer.\n");
}
if (buf[7] & 0x08) {
printf("\tSide change capable.\n");
}
if (buf[7] & 0x10) {
printf("\tReads raw R-W subchannel information from lead in.\n");
}
{
const unsigned int i_speed_Kbs = CDIO_MMC_GETPOS_LEN16(buf, 8);
printf("\tMaximum read speed is %d K bytes/sec (about %dX)\n",
i_speed_Kbs, i_speed_Kbs / 176) ;
}
printf("\tNumber of Volume levels is %d\n", CDIO_MMC_GETPOS_LEN16(buf, 10));
printf("\tBuffers size for data is %d KB\n", CDIO_MMC_GETPOS_LEN16(buf, 12));
printf("\tCurrent read speed is %d KB\n", CDIO_MMC_GETPOS_LEN16(buf, 14));
printf("\tMaximum write speed is %d KB\n", CDIO_MMC_GETPOS_LEN16(buf, 18));
printf("\tCurrent write speed is %d KB\n", CDIO_MMC_GETPOS_LEN16(buf, 28));
}
int
main(int argc, char *argv[])
{
@@ -276,14 +449,30 @@ main(int argc, char *argv[])
}
}
break;
#if 0
case OP_MODE_SENSE_2A:
{
uint8_t buf[22] = { 0, }; /* Place to hold returned data */
if (p_op->arg.i_num == 10) {
rc = mmc_mode_sense_10(p_cdio, buf, sizeof(buf),
CDIO_MMC_CAPABILITIES_PAGE);
} else {
rc = mmc_mode_sense_6(p_cdio, buf, sizeof(buf),
CDIO_MMC_CAPABILITIES_PAGE);
}
if (DRIVER_OP_SUCCESS == rc) {
print_mode_sense(p_op->arg.i_num, buf);
} else {
report(stdout, "%s (mmc_mode_sense 2a - drive_cap %d): %s\n",
program_name, p_op->arg.i_num, cdio_driver_errmsg(rc));
}
}
break;
case OP_CLOSETRAY:
rc = mmc_close_tray(p_cdio, op.arg.psz);
rc = mmc_close_tray(p_cdio);
report(stdout, "%s (mmc_close_tray): %s\n", program_name,
cdio_driver_errmsg(rc));
free(p_op->arg.psz);
break;
#endif
case OP_EJECT:
rc = mmc_eject_media(p_cdio);
report(stdout, "%s (mmc_eject_media): %s\n", program_name,