Differences between version 6 and previous revision of cdmrw.c.

Other diffs: Previous Major Revision, Previous Author

Newer page: version 6 Last edited on Monday, 20 April 2009 2:46:52 by CyberLeo Revert
Older page: version 5 Last edited on Sunday, 19 April 2009 13:40:30 by CyberLeo Revert
@@ -1,4 +1,585 @@
+<code c>  
+/*  
+ * Copyright (c) 2002 Jens Axboe <axboe@suse.de>  
+ *  
+ * cdmrw -- utility to manage mt rainier cd drives + media  
+ *  
+ * This program is free software; you can redistribute it and/or modify  
+ * it under the terms of the GNU General Public License version 2 as  
+ * published by the Free Software Foundation.  
+ *  
+ * 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., 675 Mass Ave, Cambridge, MA 02139, USA.  
+ */  
+#include <stdio.h>  
+#include <unistd.h>  
+#include <stdlib.h>  
+#include <fcntl.h>  
+#include <byteswap.h>  
+#include <sys/ioctl.h>  
+  
+#include <linux/cdrom.h>  
+  
+#define INIT_CGC(cgc) memset((cgc), 0, sizeof(struct cdrom_generic_command))  
+  
+#define FORMAT_TYPE_RESTART 1  
+#define FORMAT_TYPE_FULL 2  
+  
+#define LBA_DMA 0  
+#define LBA_GAA 1  
+  
+/*  
+ * early mrw drives may use mode page 0x2c still, 0x03 is the official one  
+ */  
+#define MRW_MODE_PC_PRE1 0x2c  
+#define MRW_MODE_PC 0x03  
+  
+#define UHZ 100  
+  
+static int format_type, format_force, poll_wait, poll_err, suspend_format;  
+static int lba_space = -1, mrw_mode_page;  
+  
+static char mrw_device[256];  
+  
+static char *lba_spaces[] = { "DMA", "GAA" };  
+  
+void dump_cgc(struct cdrom_generic_command *cgc)  
+{  
+ struct request_sense *sense = cgc->sense;  
+ int i;  
+  
+ printf("cdb: ");  
+ for (i = 0; i < 12; i++)  
+ printf("%02x ", cgc->cmd[i]);  
+ printf("\n");  
+  
+ printf("buffer (%d): ", cgc->buflen);  
+ for (i = 0; i < cgc->buflen; i++)  
+ printf("%02x ", cgc->buffer[i]);  
+ printf("\n");  
+  
+ if (!sense)  
+ return;  
+  
+ printf("sense: %02x.%02x.%02x\n", sense->sense_key, sense->asc, sense->ascq);  
+}  
+  
+/*  
+ * issue packet command (blocks until it has completed)  
+ */  
+int wait_cmd(int fd, struct cdrom_generic_command *cgc, void *buffer,  
+ int len, int ddir, int timeout, int quiet)  
+{  
+ struct request_sense sense;  
+ int ret;  
+  
+ memset(&sense, 0, sizeof(sense));  
+  
+ cgc->timeout = timeout;  
+ cgc->buffer = buffer;  
+ cgc->buflen = len;  
+ cgc->data_direction = ddir;  
+ cgc->sense = &sense;  
+ cgc->quiet = 0;  
+  
+ ret = ioctl(fd, CDROM_SEND_PACKET, cgc);  
+ if (ret == -1 && !quiet) {  
+ perror("ioctl");  
+ dump_cgc(cgc);  
+ }  
+  
+ return ret;  
+}  
+  
+int start_bg_format(int fd, int new)  
+{  
+ struct cdrom_generic_command cgc;  
+ unsigned char buffer[12];  
+  
+ INIT_CGC(&cgc);  
+ memset(buffer, 0, sizeof(buffer));  
+  
+ cgc.cmd[0] = GPCMD_FORMAT_UNIT;  
+ cgc.cmd[1] = (1 << 4) | 1;  
+  
+ buffer[1] = 1 << 1;  
+ buffer[3] = 8;  
+  
+ buffer[4] = 0xff;  
+ buffer[5] = 0xff;  
+ buffer[6] = 0xff;  
+ buffer[7] = 0xff;  
+ buffer[8] = 0x24 << 2;  
+ buffer[11] = !new;  
+  
+ return wait_cmd(fd, &cgc, buffer, sizeof(buffer), CGC_DATA_WRITE, 120 * UHZ, 0);  
+}  
+  
+/*  
+ * instantiate a format, if appropriate  
+ */  
+int mrw_format(int fd, int media_status)  
+{  
+ if (media_status == CDM_MRW_BGFORMAT_ACTIVE) {  
+ printf("%s: back ground format already active\n", mrw_device);  
+ return 1;  
+ } else if (media_status == CDM_MRW_BGFORMAT_COMPLETE && !format_force) {  
+ printf("%s: disc is already mrw formatted\n", mrw_device);  
+ return 1;  
+ }  
+  
+ if (format_type == FORMAT_TYPE_RESTART && media_status != CDM_MRW_BGFORMAT_INACTIVE) {  
+ printf("%s: can't restart format, need full\n", mrw_device);  
+ return 1;  
+ }  
+  
+ return start_bg_format(fd, format_type == FORMAT_TYPE_FULL);  
+}  
+  
+int mrw_format_suspend(int fd, int media_status)  
+{  
+ struct cdrom_generic_command cgc;  
+  
+ if (media_status != CDM_MRW_BGFORMAT_ACTIVE) {  
+ printf("%s: can't suspend, format not running\n", mrw_device);  
+ return 1;  
+ }  
+  
+ printf("%s: suspending back ground format: ", mrw_device);  
+  
+ INIT_CGC(&cgc);  
+  
+ cgc.cmd[0] = GPCMD_CLOSE_TRACK;  
+ cgc.cmd[1] = 0; /* IMMED */  
+ cgc.cmd[2] = 1 << 1;  
+  
+ if (wait_cmd(fd, &cgc, NULL, 0, CGC_DATA_NONE, 300 * UHZ, 0)) {  
+ printf("failed\n");  
+ return 1;  
+ }  
+  
+ printf("done\n");  
+ return 0;  
+}  
+  
+int get_media_event(int fd)  
+{  
+ struct cdrom_generic_command cgc;  
+ unsigned char buffer[8];  
+ int ret;  
+  
+ INIT_CGC(&cgc);  
+ memset(buffer, 0, sizeof(buffer));  
+  
+ cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;  
+ cgc.cmd[1] = 1;  
+ cgc.cmd[4] = 16;  
+ cgc.cmd[8] = sizeof(buffer);  
+  
+ ret = wait_cmd(fd, &cgc, buffer, sizeof(buffer), CGC_DATA_READ, 10*UHZ, 0);  
+ if (ret < 0) {  
+ perror("GET_EVENT");  
+ return ret;  
+ }  
+  
+ return buffer[4] & 0xf;  
+}  
+  
+int get_progress(int fd)  
+{  
+ struct cdrom_generic_command cgc;  
+ struct request_sense sense;  
+ int progress;  
+  
+ INIT_CGC(&cgc);  
+ memset(&sense, 0, sizeof(sense));  
+  
+ cgc.cmd[0] = GPCMD_TEST_UNIT_READY;  
+ cgc.sense = &sense;  
+  
+ (void) wait_cmd(fd, &cgc, NULL, 0, CGC_DATA_NONE, 10 * UHZ, 0);  
+  
+ printf("progress: ");  
+ if (sense.sks[0] & 0x80) {  
+ progress = (sense.sks[1] << 8) + sense.sks[2];  
+ fprintf(stderr, "%d%%\r", progress);  
+ } else  
+ printf("no progress indicator\n");  
+  
+ return 0;  
+}  
+  
+int get_format_progress(int fd)  
+{  
+ struct cdrom_generic_command cgc;  
+ struct request_sense sense;  
+  
+#if 0  
+ if (poll_err)  
+ return 0;  
+#endif  
+  
+ INIT_CGC(&cgc);  
+ memset(&sense, 0, sizeof(sense));  
+  
+ cgc.cmd[0] = GPCMD_TEST_UNIT_READY;  
+ cgc.sense = &sense;  
+  
+ if (wait_cmd(fd, &cgc, NULL, 0, CGC_DATA_NONE, 10 * UHZ, 0)) {  
+ printf("%s: TUR failed\n", mrw_device);  
+ return 0;  
+ }  
+  
+ /*  
+ * all mrw drives should support progress indicator, but you never  
+ * know...  
+ */  
+ if (!(sense.sks[0] & 0x80)) {  
+ printf("drive fails to support progress indicator\n");  
+ poll_err = 1;  
+ //return 0;  
+ }  
+  
+ return (sense.sks[1] << 8) + sense.sks[2];  
+}  
+  
+/*  
+ * return mrw media status bits from disc info or -1 on failure  
+ */  
+int get_mrw_media_status(int fd)  
+{  
+ struct cdrom_generic_command cgc;  
+ disc_information di;  
+  
+ INIT_CGC(&cgc);  
+  
+ cgc.cmd[0] = GPCMD_READ_DISC_INFO;  
+ cgc.cmd[8] = sizeof(di);  
+  
+ if (wait_cmd(fd, &cgc, &di, sizeof(di), CGC_DATA_READ, UHZ, 0)) {  
+ printf("read disc info failed\n");  
+ return -1;  
+ }  
+  
+ return di.mrw_status;  
+}  
+  
+int poll_events(int fd)  
+{  
+ int event, quit, first, progress, media_status;  
+  
+ quit = 0;  
+ first = 1;  
+ do {  
+ event = get_media_event(fd);  
+ if (event < 0)  
+ break;  
+  
+ switch (event) {  
+ case 0:  
+ if (first)  
+ printf("no media change\n");  
+ break;  
+ case 1:  
+ printf("eject request\n");  
+ if ((media_status = get_mrw_media_status(fd)) == -1)  
+ break;  
+ if (media_status == CDM_MRW_BGFORMAT_ACTIVE)  
+ mrw_format_suspend(fd, media_status);  
+ quit = 1;  
+ break;  
+ case 2:  
+ printf("new media\n");  
+ break;  
+ case 3:  
+ printf("media removal\n");  
+ quit = 1;  
+ break;  
+ case 4:  
+ printf("media change\n");  
+ break;  
+ case 5:  
+ printf("bgformat complete!\n");  
+ quit = 1;  
+ break;  
+ case 6:  
+ printf("bgformat automatically restarted\n");  
+ break;  
+ default:  
+ printf("unknown media event (%d)\n", event);  
+ break;  
+ }  
+  
+ if (!quit) {  
+ first = 0;  
+ progress = get_progress(fd);  
+ if (event)  
+ continue;  
+  
+ sleep(2);  
+ }  
+  
+ } while (!quit);  
+  
+ return event;  
+}  
+  
+/*  
+ * issue GET_CONFIGURATION and check for the mt rainier profile  
+ */  
+int check_for_mrw(int fd)  
+{  
+ struct mrw_feature_desc *mfd;  
+ struct cdrom_generic_command cgc;  
+ char buffer[16];  
+  
+ INIT_CGC(&cgc);  
+  
+ cgc.cmd[0] = GPCMD_GET_CONFIGURATION;  
+ cgc.cmd[3] = CDF_MRW;  
+ cgc.cmd[8] = sizeof(buffer);  
+  
+ if (wait_cmd(fd, &cgc, buffer, sizeof(buffer), CGC_DATA_READ, UHZ, 1))  
+ return 1;  
+  
+ mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)];  
+  
+ return !mfd->write;  
+}  
+  
+int __get_lba_space(int fd, int pc, char *buffer, int size)  
+{  
+ struct cdrom_generic_command cgc;  
+  
+ INIT_CGC(&cgc);  
+  
+ cgc.cmd[0] = GPCMD_MODE_SENSE_10;  
+ cgc.cmd[2] = pc | (0 << 6);  
+ cgc.cmd[8] = size;  
+  
+ if (wait_cmd(fd, &cgc, buffer, size, CGC_DATA_READ, UHZ, 1))  
+ return 1;  
+  
+ return 0;  
+}  
+  
+/*  
+ * return LBA_DMA or LBA_GAA, -1 on failure  
+ */  
+int get_lba_space(int fd)  
+{  
+ struct mode_page_header *mph;  
+ char buffer[32];  
+ int offset;  
+  
+ if (__get_lba_space(fd, mrw_mode_page, buffer, sizeof(buffer)))  
+ return -1;  
+  
+ mph = (struct mode_page_header *) buffer;  
+ offset = sizeof(*mph) + bswap_16(mph->desc_length);  
+  
+ /*  
+ * LBA space bit is bit 0 in byte 3 of the mrw mode page  
+ */  
+ return buffer[offset + 3] & 1;  
+}  
+  
+int probe_mrw_mode_page(int fd)  
+{  
+ char buffer[32];  
+  
+ mrw_mode_page = -1;  
+  
+ if (!__get_lba_space(fd, MRW_MODE_PC, buffer, sizeof(buffer)))  
+ mrw_mode_page = MRW_MODE_PC;  
+ else if (!__get_lba_space(fd, MRW_MODE_PC_PRE1, buffer, sizeof(buffer)))  
+ mrw_mode_page = MRW_MODE_PC_PRE1;  
+  
+ if (mrw_mode_page == MRW_MODE_PC_PRE1)  
+ printf("%s: still using deprecated mrw mode page\n",mrw_device);  
+  
+ return mrw_mode_page;  
+}  
+  
+int switch_lba_space(int fd, int lba_space)  
+{  
+ struct cdrom_generic_command cgc;  
+ struct mode_page_header *mph;  
+ int cur_space, offset, size;  
+ char buffer[32];  
+  
+ if (__get_lba_space(fd, mrw_mode_page, buffer, sizeof(buffer)))  
+ return 1;  
+  
+ mph = (struct mode_page_header *) buffer;  
+ offset = sizeof(*mph) + bswap_16(mph->desc_length);  
+ cur_space = buffer[offset + 3] & 1;  
+  
+ if (cur_space == lba_space)  
+ return 0;  
+  
+ /*  
+ * mode data length doesn't include its own space  
+ */  
+ size = bswap_16(mph->mode_data_length) + 2;  
+  
+ /*  
+ * init command and set the required lba space  
+ */  
+ INIT_CGC(&cgc);  
+  
+ cgc.cmd[0] = GPCMD_MODE_SELECT_10;  
+ cgc.cmd[8] = size;  
+  
+ buffer[offset + 3] = lba_space;  
+  
+ if (wait_cmd(fd, &cgc, buffer, size, CGC_DATA_WRITE, UHZ, 0))  
+ return 1;  
+  
+ return 0;  
+}  
+  
+void print_mrw_status(int media_status)  
+{  
+ switch (media_status) {  
+ case CDM_MRW_NOTMRW:  
+ printf("not a mrw formatted disc\n");  
+ break;  
+ case CDM_MRW_BGFORMAT_INACTIVE:  
+ printf("mrw format inactive and not complete\n");  
+ break;  
+ case CDM_MRW_BGFORMAT_ACTIVE:  
+ printf("mrw format running\n");  
+ break;  
+ case CDM_MRW_BGFORMAT_COMPLETE:  
+ printf("disc is mrw formatted\n");  
+ break;  
+ }  
+}  
+  
+void print_options(const char *prg)  
+{  
+ printf("%s: options:\n", prg);  
+ printf("\t-d:\t<device>\n");  
+ printf("\t-f:\t<{restart, full} format type\n");  
+ printf("\t-F:\tforce format\n");  
+ printf("\t-s:\tsuspend format\n");  
+ printf("\t-p:\tpoll for format completion\n");  
+}  
+  
+void get_options(int argc, char *argv[])  
+{  
+ char c;  
+  
+ strcpy(mrw_device, "/dev/cdrom");  
+  
+ while ((c = getopt(argc, argv, "d:f:Fpsl:")) != EOF) {  
+ switch (c) {  
+ case 'd':  
+ strcpy(mrw_device, optarg);  
+ break;  
+ case 'f':  
+ if (!strcmp(optarg, "full"))  
+ format_type = FORMAT_TYPE_FULL;  
+ else if (!strcmp(optarg, "restart"))  
+ format_type = FORMAT_TYPE_RESTART;  
+ else  
+ printf("%s: invalid format type %s\n", argv[0], optarg);  
+ break;  
+ case 'F':  
+ format_force = 1;  
+ break;  
+ case 'p':  
+ poll_wait = 1;  
+ break;  
+ case 's':  
+ suspend_format = 1;  
+ break;  
+ case 'l':  
+ if (!strcmp(optarg, "gaa"))  
+ lba_space = LBA_GAA;  
+ else if (!strcmp(optarg, "dma"))  
+ lba_space = LBA_DMA;  
+ else  
+ printf("%s: invalid address space %s\n", argv[0], optarg);  
+ break;  
+ default:  
+ if (optarg)  
+ printf("%s: unknown option '%s'\n", argv[0], optarg);  
+ print_options(argv[0]);  
+ exit(1);  
+ }  
+ }  
+}  
+  
+int main(int argc, char *argv[])  
+{  
+ int fd, media_status, progress;  
+  
+ if (argc == 1) {  
+ print_options(argv[0]);  
+ return 1;  
+ }  
+  
+ get_options(argc, argv);  
+  
+ fd = open(mrw_device, O_RDONLY | O_NONBLOCK);  
+ if (fd == -1) {  
+ perror("open");  
+ return 1;  
+ }  
+  
+ if (check_for_mrw(fd)) {  
+ printf("%s: %s is not a mrw drive or mrw reader\n", argv[0], mrw_device);  
+ return 1;  
+ }  
+  
+ if ((media_status = get_mrw_media_status(fd)) == -1) {  
+ printf("%s: failed to retrieve media status\n", argv[0]);  
+ return 1;  
+ }  
+  
+ print_mrw_status(media_status);  
+  
+ if (probe_mrw_mode_page(fd) == -1) {  
+ printf("%s: failed to probe mrw mode page\n", mrw_device);  
+ return 1;  
+ }  
+  
+ if (lba_space != -1) {  
+ if (switch_lba_space(fd, lba_space)) {  
+ printf("%s: failed switching lba space\n", mrw_device);  
+ return 1;  
+ }  
+ }  
+  
+ printf("LBA space: %s\n", lba_spaces[get_lba_space(fd)]);  
+  
+ if (media_status == CDM_MRW_BGFORMAT_ACTIVE) {  
+ progress = get_format_progress(fd);  
+ printf("%s: back ground format %d%% complete\n", mrw_device, progress);  
+ }  
+  
+ if (format_type) {  
+ if (mrw_format(fd, media_status))  
+ return 1;  
+ } else if (suspend_format)  
+ mrw_format_suspend(fd, media_status);  
+  
+ if (poll_wait)  
+ poll_events(fd);  
+  
+ return 0;  
+}  
+</code>  
+  
 <?plugin RawHtml 
 <pre class="brush: c;"> 
 /* 
  * Copyright (c) 2002 Jens Axboe <axboe@suse.de> 

version 6

/*
 * Copyright (c) 2002 Jens Axboe <axboe@suse.de>
 *
 * cdmrw -- utility to manage mt rainier cd drives + media
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License version 2 as
 *   published by the Free Software Foundation.
 *
 *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <byteswap.h>
#include <sys/ioctl.h>

#include <linux/cdrom.h>

#define INIT_CGC(cgc)   memset((cgc), 0, sizeof(struct cdrom_generic_command))

#define FORMAT_TYPE_RESTART     1
#define FORMAT_TYPE_FULL        2

#define LBA_DMA                 0
#define LBA_GAA                 1

/*
 * early mrw drives may use mode page 0x2c still, 0x03 is the official one
 */
#define MRW_MODE_PC_PRE1        0x2c
#define MRW_MODE_PC             0x03

#define UHZ                     100

static int format_type, format_force, poll_wait, poll_err, suspend_format;
static int lba_space = -1, mrw_mode_page;

static char mrw_device[256];

static char *lba_spaces[] = { "DMA", "GAA" };

void dump_cgc(struct cdrom_generic_command *cgc)
{
        struct request_sense *sense = cgc->sense;
        int i;

        printf("cdb: ");
        for (i = 0; i < 12; i++)
                printf("%02x ", cgc->cmd[i]);
        printf("\n");

        printf("buffer (%d): ", cgc->buflen);
        for (i = 0; i < cgc->buflen; i++)
                printf("%02x ", cgc->buffer[i]);
        printf("\n");

        if (!sense)
                return;

        printf("sense: %02x.%02x.%02x\n", sense->sense_key, sense->asc, sense->ascq);
}

/*
 * issue packet command (blocks until it has completed)
 */
int wait_cmd(int fd, struct cdrom_generic_command *cgc, void *buffer,
             int len, int ddir, int timeout, int quiet)
{
        struct request_sense sense;
        int ret;

        memset(&sense, 0, sizeof(sense));

        cgc->timeout = timeout;
        cgc->buffer = buffer;
        cgc->buflen = len;
        cgc->data_direction = ddir;
        cgc->sense = &sense;
        cgc->quiet = 0;

        ret = ioctl(fd, CDROM_SEND_PACKET, cgc);
        if (ret == -1 && !quiet) {
                perror("ioctl");
                dump_cgc(cgc);
        }

        return ret;
}

int start_bg_format(int fd, int new)
{
        struct cdrom_generic_command cgc;
        unsigned char buffer[12];

        INIT_CGC(&cgc);
        memset(buffer, 0, sizeof(buffer));

        cgc.cmd[0] = GPCMD_FORMAT_UNIT;
        cgc.cmd[1] = (1 << 4) | 1;

        buffer[1] = 1 << 1;
        buffer[3] = 8;

        buffer[4] = 0xff;
        buffer[5] = 0xff;
        buffer[6] = 0xff;
        buffer[7] = 0xff;
        buffer[8] = 0x24 << 2;
        buffer[11] = !new;

        return wait_cmd(fd, &cgc, buffer, sizeof(buffer), CGC_DATA_WRITE, 120 * UHZ, 0);
}

/*
 * instantiate a format, if appropriate
 */
int mrw_format(int fd, int media_status)
{
        if (media_status == CDM_MRW_BGFORMAT_ACTIVE) {
                printf("%s: back ground format already active\n", mrw_device);
                return 1;
        } else if (media_status == CDM_MRW_BGFORMAT_COMPLETE && !format_force) {
                printf("%s: disc is already mrw formatted\n", mrw_device);
                return 1;
        }

        if (format_type == FORMAT_TYPE_RESTART && media_status != CDM_MRW_BGFORMAT_INACTIVE) {
                printf("%s: can't restart format, need full\n", mrw_device);
                return 1;
        }

        return start_bg_format(fd, format_type == FORMAT_TYPE_FULL);
}

int mrw_format_suspend(int fd, int media_status)
{
        struct cdrom_generic_command cgc;

        if (media_status != CDM_MRW_BGFORMAT_ACTIVE) {
                printf("%s: can't suspend, format not running\n", mrw_device);
                return 1;
        }

        printf("%s: suspending back ground format: ", mrw_device);

        INIT_CGC(&cgc);

        cgc.cmd[0] = GPCMD_CLOSE_TRACK;
        cgc.cmd[1] = 0; /* IMMED */
        cgc.cmd[2] = 1 << 1;

        if (wait_cmd(fd, &cgc, NULL, 0, CGC_DATA_NONE, 300 * UHZ, 0)) {
                printf("failed\n");
                return 1;
        }

        printf("done\n");
        return 0;
}

int get_media_event(int fd)
{
        struct cdrom_generic_command cgc;
        unsigned char buffer[8];
        int ret;

        INIT_CGC(&cgc);
        memset(buffer, 0, sizeof(buffer));

        cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
        cgc.cmd[1] = 1;
        cgc.cmd[4] = 16;
        cgc.cmd[8] = sizeof(buffer);

        ret = wait_cmd(fd, &cgc, buffer, sizeof(buffer), CGC_DATA_READ, 10*UHZ, 0);
        if (ret < 0) {
                perror("GET_EVENT");
                return ret;
        }

        return buffer[4] & 0xf;
}

int get_progress(int fd)
{
        struct cdrom_generic_command cgc;
        struct request_sense sense;
        int progress;

        INIT_CGC(&cgc);
        memset(&sense, 0, sizeof(sense));

        cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
        cgc.sense = &sense;

        (void) wait_cmd(fd, &cgc, NULL, 0, CGC_DATA_NONE, 10 * UHZ, 0);

        printf("progress: ");
        if (sense.sks[0] & 0x80) {
                progress = (sense.sks[1] << 8) + sense.sks[2];
                fprintf(stderr, "%d%%\r", progress);
        } else
                printf("no progress indicator\n");

        return 0;
}

int get_format_progress(int fd)
{
        struct cdrom_generic_command cgc;
        struct request_sense sense;

#if 0
        if (poll_err)
                return 0;
#endif

        INIT_CGC(&cgc);
        memset(&sense, 0, sizeof(sense));

        cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
        cgc.sense = &sense;

        if (wait_cmd(fd, &cgc, NULL, 0, CGC_DATA_NONE, 10 * UHZ, 0)) {
                printf("%s: TUR failed\n", mrw_device);
                return 0;
        }

        /*
         * all mrw drives should support progress indicator, but you never
         * know...
         */
        if (!(sense.sks[0] & 0x80)) {
                printf("drive fails to support progress indicator\n");
                poll_err = 1;
                //return 0;
        }

        return (sense.sks[1] << 8) + sense.sks[2];
}

/*
 * return mrw media status bits from disc info or -1 on failure
 */
int get_mrw_media_status(int fd)
{
        struct cdrom_generic_command cgc;
        disc_information di;

        INIT_CGC(&cgc);

        cgc.cmd[0] = GPCMD_READ_DISC_INFO;
        cgc.cmd[8] = sizeof(di);

        if (wait_cmd(fd, &cgc, &di, sizeof(di), CGC_DATA_READ, UHZ, 0)) {
                printf("read disc info failed\n");
                return -1;
        }

        return di.mrw_status;
}

int poll_events(int fd)
{
        int event, quit, first, progress, media_status;

        quit = 0;
        first = 1;
        do {
                event = get_media_event(fd);
                if (event < 0)
                        break;

                switch (event) {
                        case 0:
                                if (first)
                                        printf("no media change\n");
                                break;
                        case 1:
                                printf("eject request\n");
                                if ((media_status = get_mrw_media_status(fd)) == -1)
                                        break;
                                if (media_status == CDM_MRW_BGFORMAT_ACTIVE)
                                        mrw_format_suspend(fd, media_status);
                                quit = 1;
                                break;
                        case 2:
                                printf("new media\n");
                                break;
                        case 3:
                                printf("media removal\n");
                                quit = 1;
                                break;
                        case 4:
                                printf("media change\n");
                                break;
                        case 5:
                                printf("bgformat complete!\n");
                                quit = 1;
                                break;
                        case 6:
                                printf("bgformat automatically restarted\n");
                                break;
                        default:
                                printf("unknown media event (%d)\n", event);
                                break;
                }

                if (!quit) {
                        first = 0;
                        progress = get_progress(fd);
                        if (event)
                                continue;

                        sleep(2);
                }

        } while (!quit);

        return event;
}

/*
 * issue GET_CONFIGURATION and check for the mt rainier profile
 */
int check_for_mrw(int fd)
{
        struct mrw_feature_desc *mfd;
        struct cdrom_generic_command cgc;
        char buffer[16];

        INIT_CGC(&cgc);

        cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
        cgc.cmd[3] = CDF_MRW;
        cgc.cmd[8] = sizeof(buffer);

        if (wait_cmd(fd, &cgc, buffer, sizeof(buffer), CGC_DATA_READ, UHZ, 1))
                return 1;

        mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)];

        return !mfd->write;
}

int __get_lba_space(int fd, int pc, char *buffer, int size)
{
        struct cdrom_generic_command cgc;

        INIT_CGC(&cgc);

        cgc.cmd[0] = GPCMD_MODE_SENSE_10;
        cgc.cmd[2] = pc | (0 << 6);
        cgc.cmd[8] = size;

        if (wait_cmd(fd, &cgc, buffer, size, CGC_DATA_READ, UHZ, 1))
                return 1;

        return 0;
}

/*
 * return LBA_DMA or LBA_GAA, -1 on failure
 */
int get_lba_space(int fd)
{
        struct mode_page_header *mph;
        char buffer[32];
        int offset;

        if (__get_lba_space(fd, mrw_mode_page, buffer, sizeof(buffer)))
                return -1;

        mph = (struct mode_page_header *) buffer;
        offset = sizeof(*mph) + bswap_16(mph->desc_length);

        /*
         * LBA space bit is bit 0 in byte 3 of the mrw mode page
         */
        return buffer[offset + 3] & 1;
}

int probe_mrw_mode_page(int fd)
{
        char buffer[32];

        mrw_mode_page = -1;

        if (!__get_lba_space(fd, MRW_MODE_PC, buffer, sizeof(buffer)))
                mrw_mode_page = MRW_MODE_PC;
        else if (!__get_lba_space(fd, MRW_MODE_PC_PRE1, buffer, sizeof(buffer)))
                mrw_mode_page = MRW_MODE_PC_PRE1;

        if (mrw_mode_page == MRW_MODE_PC_PRE1)
                printf("%s: still using deprecated mrw mode page\n",mrw_device);

        return mrw_mode_page;
}

int switch_lba_space(int fd, int lba_space)
{
        struct cdrom_generic_command cgc;
        struct mode_page_header *mph;
        int cur_space, offset, size;
        char buffer[32];

        if (__get_lba_space(fd, mrw_mode_page, buffer, sizeof(buffer)))
                return 1;

        mph = (struct mode_page_header *) buffer;
        offset = sizeof(*mph) + bswap_16(mph->desc_length);
        cur_space = buffer[offset + 3] & 1;

        if (cur_space == lba_space)
                return 0;

        /*
         * mode data length doesn't include its own space
         */
        size = bswap_16(mph->mode_data_length) + 2;

        /*
         * init command and set the required lba space
         */
        INIT_CGC(&cgc);

        cgc.cmd[0] = GPCMD_MODE_SELECT_10;
        cgc.cmd[8] = size;

        buffer[offset + 3] = lba_space;

        if (wait_cmd(fd, &cgc, buffer, size, CGC_DATA_WRITE, UHZ, 0))
                return 1;

        return 0;
}

void print_mrw_status(int media_status)
{
        switch (media_status) {
                case CDM_MRW_NOTMRW:
                        printf("not a mrw formatted disc\n");
                        break;
                case CDM_MRW_BGFORMAT_INACTIVE:
                        printf("mrw format inactive and not complete\n");
                        break;
                case CDM_MRW_BGFORMAT_ACTIVE:
                        printf("mrw format running\n");
                        break;
                case CDM_MRW_BGFORMAT_COMPLETE:
                        printf("disc is mrw formatted\n");
                        break;
        }
}

void print_options(const char *prg)
{
        printf("%s: options:\n", prg);
        printf("\t-d:\t<device>\n");
        printf("\t-f:\t<{restart, full} format type\n");
        printf("\t-F:\tforce format\n");
        printf("\t-s:\tsuspend format\n");
        printf("\t-p:\tpoll for format completion\n");
}

void get_options(int argc, char *argv[])
{
        char c;

        strcpy(mrw_device, "/dev/cdrom");

        while ((c = getopt(argc, argv, "d:f:Fpsl:")) != EOF) {
                switch (c) {
                        case 'd':
                                strcpy(mrw_device, optarg);
                                break;
                        case 'f':
                                if (!strcmp(optarg, "full"))
                                        format_type = FORMAT_TYPE_FULL;
                                else if (!strcmp(optarg, "restart"))
                                        format_type = FORMAT_TYPE_RESTART;
                                else
                                        printf("%s: invalid format type %s\n", argv[0], optarg);
                                break;
                        case 'F':
                                format_force = 1;
                                break;
                        case 'p':
                                poll_wait = 1;
                                break;
                        case 's':
                                suspend_format = 1;
                                break;
                        case 'l':
                                if (!strcmp(optarg, "gaa"))
                                        lba_space = LBA_GAA;
                                else if (!strcmp(optarg, "dma"))
                                        lba_space = LBA_DMA;
                                else
                                        printf("%s: invalid address space %s\n", argv[0], optarg);
                                break;
                        default:
                                if (optarg)
                                        printf("%s: unknown option '%s'\n", argv[0], optarg);
                                print_options(argv[0]);
                                exit(1);
                }
        }
}

int main(int argc, char *argv[])
{
        int fd, media_status, progress;

        if (argc == 1) {
                print_options(argv[0]);
                return 1;
        }

        get_options(argc, argv);

        fd = open(mrw_device, O_RDONLY | O_NONBLOCK);
        if (fd == -1) {
                perror("open");
                return 1;
        }

        if (check_for_mrw(fd)) {
                printf("%s: %s is not a mrw drive or mrw reader\n", argv[0], mrw_device);
                return 1;
        }

        if ((media_status = get_mrw_media_status(fd)) == -1) {
                printf("%s: failed to retrieve media status\n", argv[0]);
                return 1;
        }

        print_mrw_status(media_status);

        if (probe_mrw_mode_page(fd) == -1) {
                printf("%s: failed to probe mrw mode page\n", mrw_device);
                return 1;
        }

        if (lba_space != -1) {
                if (switch_lba_space(fd, lba_space)) {
                        printf("%s: failed switching lba space\n", mrw_device);
                        return 1;
                }
        }

        printf("LBA space: %s\n", lba_spaces[get_lba_space(fd)]);

        if (media_status == CDM_MRW_BGFORMAT_ACTIVE) {
                progress = get_format_progress(fd);
                printf("%s: back ground format %d%% complete\n", mrw_device, progress);
        }

        if (format_type) {
                if (mrw_format(fd, media_status))
                        return 1;
        } else if (suspend_format)
                mrw_format_suspend(fd, media_status);

        if (poll_wait)
                poll_events(fd);

        return 0;
}
Plugin RawHtml disabled. Raw HTML is only allowed in locked pages.
<?plugin RawHtml
<pre class="brush: c;">
/*
 * Copyright (c) 2002 Jens Axboe <axboe@suse.de>
 *
 * cdmrw -- utility to manage mt rainier cd drives + media
 *
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License version 2 as
 *   published by the Free Software Foundation.
 *
 *   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., 675 Mass Ave, Cambridge, MA 02139, USA.
 */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <byteswap.h>
#include <sys/ioctl.h>

#include <linux/cdrom.h>

#define INIT_CGC(cgc)   memset((cgc), 0, sizeof(struct cdrom_generic_command))

#define FORMAT_TYPE_RESTART     1
#define FORMAT_TYPE_FULL        2

#define LBA_DMA                 0
#define LBA_GAA                 1

/*
 * early mrw drives may use mode page 0x2c still, 0x03 is the official one
 */
#define MRW_MODE_PC_PRE1        0x2c
#define MRW_MODE_PC             0x03

#define UHZ                     100

static int format_type, format_force, poll_wait, poll_err, suspend_format;
static int lba_space = -1, mrw_mode_page;

static char mrw_device[256];

static char *lba_spaces[] = { "DMA", "GAA" };

void dump_cgc(struct cdrom_generic_command *cgc)
{
        struct request_sense *sense = cgc->sense;
        int i;

        printf("cdb: ");
        for (i = 0; i < 12; i++)
                printf("%02x ", cgc->cmd[i]);
        printf("\n");

        printf("buffer (%d): ", cgc->buflen);
        for (i = 0; i < cgc->buflen; i++)
                printf("%02x ", cgc->buffer[i]);
        printf("\n");

        if (!sense)
                return;

        printf("sense: %02x.%02x.%02x\n", sense->sense_key, sense->asc, sense->ascq);
}

/*
 * issue packet command (blocks until it has completed)
 */
int wait_cmd(int fd, struct cdrom_generic_command *cgc, void *buffer,
             int len, int ddir, int timeout, int quiet)
{
        struct request_sense sense;
        int ret;

        memset(&sense, 0, sizeof(sense));

        cgc->timeout = timeout;
        cgc->buffer = buffer;
        cgc->buflen = len;
        cgc->data_direction = ddir;
        cgc->sense = &sense;
        cgc->quiet = 0;

        ret = ioctl(fd, CDROM_SEND_PACKET, cgc);
        if (ret == -1 && !quiet) {
                perror("ioctl");
                dump_cgc(cgc);
        }

        return ret;
}

int start_bg_format(int fd, int new)
{
        struct cdrom_generic_command cgc;
        unsigned char buffer[12];

        INIT_CGC(&cgc);
        memset(buffer, 0, sizeof(buffer));

        cgc.cmd[0] = GPCMD_FORMAT_UNIT;
        cgc.cmd[1] = (1 << 4) | 1;

        buffer[1] = 1 << 1;
        buffer[3] = 8;

        buffer[4] = 0xff;
        buffer[5] = 0xff;
        buffer[6] = 0xff;
        buffer[7] = 0xff;
        buffer[8] = 0x24 << 2;
        buffer[11] = !new;

        return wait_cmd(fd, &cgc, buffer, sizeof(buffer), CGC_DATA_WRITE, 120 * UHZ, 0);
}

/*
 * instantiate a format, if appropriate
 */
int mrw_format(int fd, int media_status)
{
        if (media_status == CDM_MRW_BGFORMAT_ACTIVE) {
                printf("%s: back ground format already active\n", mrw_device);
                return 1;
        } else if (media_status == CDM_MRW_BGFORMAT_COMPLETE && !format_force) {
                printf("%s: disc is already mrw formatted\n", mrw_device);
                return 1;
        }

        if (format_type == FORMAT_TYPE_RESTART && media_status != CDM_MRW_BGFORMAT_INACTIVE) {
                printf("%s: can't restart format, need full\n", mrw_device);
                return 1;
        }

        return start_bg_format(fd, format_type == FORMAT_TYPE_FULL);
}

int mrw_format_suspend(int fd, int media_status)
{
        struct cdrom_generic_command cgc;

        if (media_status != CDM_MRW_BGFORMAT_ACTIVE) {
                printf("%s: can't suspend, format not running\n", mrw_device);
                return 1;
        }

        printf("%s: suspending back ground format: ", mrw_device);

        INIT_CGC(&cgc);

        cgc.cmd[0] = GPCMD_CLOSE_TRACK;
        cgc.cmd[1] = 0; /* IMMED */
        cgc.cmd[2] = 1 << 1;

        if (wait_cmd(fd, &cgc, NULL, 0, CGC_DATA_NONE, 300 * UHZ, 0)) {
                printf("failed\n");
                return 1;
        }

        printf("done\n");
        return 0;
}

int get_media_event(int fd)
{
        struct cdrom_generic_command cgc;
        unsigned char buffer[8];
        int ret;

        INIT_CGC(&cgc);
        memset(buffer, 0, sizeof(buffer));

        cgc.cmd[0] = GPCMD_GET_EVENT_STATUS_NOTIFICATION;
        cgc.cmd[1] = 1;
        cgc.cmd[4] = 16;
        cgc.cmd[8] = sizeof(buffer);

        ret = wait_cmd(fd, &cgc, buffer, sizeof(buffer), CGC_DATA_READ, 10*UHZ, 0);
        if (ret < 0) {
                perror("GET_EVENT");
                return ret;
        }

        return buffer[4] & 0xf;
}

int get_progress(int fd)
{
        struct cdrom_generic_command cgc;
        struct request_sense sense;
        int progress;

        INIT_CGC(&cgc);
        memset(&sense, 0, sizeof(sense));

        cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
        cgc.sense = &sense;

        (void) wait_cmd(fd, &cgc, NULL, 0, CGC_DATA_NONE, 10 * UHZ, 0);

        printf("progress: ");
        if (sense.sks[0] & 0x80) {
                progress = (sense.sks[1] << 8) + sense.sks[2];
                fprintf(stderr, "%d%%\r", progress);
        } else
                printf("no progress indicator\n");

        return 0;
}

int get_format_progress(int fd)
{
        struct cdrom_generic_command cgc;
        struct request_sense sense;

#if 0
        if (poll_err)
                return 0;
#endif

        INIT_CGC(&cgc);
        memset(&sense, 0, sizeof(sense));

        cgc.cmd[0] = GPCMD_TEST_UNIT_READY;
        cgc.sense = &sense;

        if (wait_cmd(fd, &cgc, NULL, 0, CGC_DATA_NONE, 10 * UHZ, 0)) {
                printf("%s: TUR failed\n", mrw_device);
                return 0;
        }

        /*
         * all mrw drives should support progress indicator, but you never
         * know...
         */
        if (!(sense.sks[0] & 0x80)) {
                printf("drive fails to support progress indicator\n");
                poll_err = 1;
                //return 0;
        }

        return (sense.sks[1] << 8) + sense.sks[2];
}

/*
 * return mrw media status bits from disc info or -1 on failure
 */
int get_mrw_media_status(int fd)
{
        struct cdrom_generic_command cgc;
        disc_information di;

        INIT_CGC(&cgc);

        cgc.cmd[0] = GPCMD_READ_DISC_INFO;
        cgc.cmd[8] = sizeof(di);

        if (wait_cmd(fd, &cgc, &di, sizeof(di), CGC_DATA_READ, UHZ, 0)) {
                printf("read disc info failed\n");
                return -1;
        }

        return di.mrw_status;
}

int poll_events(int fd)
{
        int event, quit, first, progress, media_status;

        quit = 0;
        first = 1;
        do {
                event = get_media_event(fd);
                if (event < 0)
                        break;

                switch (event) {
                        case 0:
                                if (first)
                                        printf("no media change\n");
                                break;
                        case 1:
                                printf("eject request\n");
                                if ((media_status = get_mrw_media_status(fd)) == -1)
                                        break;
                                if (media_status == CDM_MRW_BGFORMAT_ACTIVE)
                                        mrw_format_suspend(fd, media_status);
                                quit = 1;
                                break;
                        case 2:
                                printf("new media\n");
                                break;
                        case 3:
                                printf("media removal\n");
                                quit = 1;
                                break;
                        case 4:
                                printf("media change\n");
                                break;
                        case 5:
                                printf("bgformat complete!\n");
                                quit = 1;
                                break;
                        case 6:
                                printf("bgformat automatically restarted\n");
                                break;
                        default:
                                printf("unknown media event (%d)\n", event);
                                break;
                }

                if (!quit) {
                        first = 0;
                        progress = get_progress(fd);
                        if (event)
                                continue;

                        sleep(2);
                }

        } while (!quit);

        return event;
}

/*
 * issue GET_CONFIGURATION and check for the mt rainier profile
 */
int check_for_mrw(int fd)
{
        struct mrw_feature_desc *mfd;
        struct cdrom_generic_command cgc;
        char buffer[16];

        INIT_CGC(&cgc);

        cgc.cmd[0] = GPCMD_GET_CONFIGURATION;
        cgc.cmd[3] = CDF_MRW;
        cgc.cmd[8] = sizeof(buffer);

        if (wait_cmd(fd, &cgc, buffer, sizeof(buffer), CGC_DATA_READ, UHZ, 1))
                return 1;

        mfd = (struct mrw_feature_desc *)&buffer[sizeof(struct feature_header)];

        return !mfd->write;
}

int __get_lba_space(int fd, int pc, char *buffer, int size)
{
        struct cdrom_generic_command cgc;

        INIT_CGC(&cgc);

        cgc.cmd[0] = GPCMD_MODE_SENSE_10;
        cgc.cmd[2] = pc | (0 << 6);
        cgc.cmd[8] = size;

        if (wait_cmd(fd, &cgc, buffer, size, CGC_DATA_READ, UHZ, 1))
                return 1;

        return 0;
}

/*
 * return LBA_DMA or LBA_GAA, -1 on failure
 */
int get_lba_space(int fd)
{
        struct mode_page_header *mph;
        char buffer[32];
        int offset;

        if (__get_lba_space(fd, mrw_mode_page, buffer, sizeof(buffer)))
                return -1;

        mph = (struct mode_page_header *) buffer;
        offset = sizeof(*mph) + bswap_16(mph->desc_length);

        /*
         * LBA space bit is bit 0 in byte 3 of the mrw mode page
         */
        return buffer[offset + 3] & 1;
}

int probe_mrw_mode_page(int fd)
{
        char buffer[32];

        mrw_mode_page = -1;

        if (!__get_lba_space(fd, MRW_MODE_PC, buffer, sizeof(buffer)))
                mrw_mode_page = MRW_MODE_PC;
        else if (!__get_lba_space(fd, MRW_MODE_PC_PRE1, buffer, sizeof(buffer)))
                mrw_mode_page = MRW_MODE_PC_PRE1;

        if (mrw_mode_page == MRW_MODE_PC_PRE1)
                printf("%s: still using deprecated mrw mode page\n",mrw_device);

        return mrw_mode_page;
}

int switch_lba_space(int fd, int lba_space)
{
        struct cdrom_generic_command cgc;
        struct mode_page_header *mph;
        int cur_space, offset, size;
        char buffer[32];

        if (__get_lba_space(fd, mrw_mode_page, buffer, sizeof(buffer)))
                return 1;

        mph = (struct mode_page_header *) buffer;
        offset = sizeof(*mph) + bswap_16(mph->desc_length);
        cur_space = buffer[offset + 3] & 1;

        if (cur_space == lba_space)
                return 0;

        /*
         * mode data length doesn't include its own space
         */
        size = bswap_16(mph->mode_data_length) + 2;

        /*
         * init command and set the required lba space
         */
        INIT_CGC(&cgc);

        cgc.cmd[0] = GPCMD_MODE_SELECT_10;
        cgc.cmd[8] = size;

        buffer[offset + 3] = lba_space;

        if (wait_cmd(fd, &cgc, buffer, size, CGC_DATA_WRITE, UHZ, 0))
                return 1;

        return 0;
}

void print_mrw_status(int media_status)
{
        switch (media_status) {
                case CDM_MRW_NOTMRW:
                        printf("not a mrw formatted disc\n");
                        break;
                case CDM_MRW_BGFORMAT_INACTIVE:
                        printf("mrw format inactive and not complete\n");
                        break;
                case CDM_MRW_BGFORMAT_ACTIVE:
                        printf("mrw format running\n");
                        break;
                case CDM_MRW_BGFORMAT_COMPLETE:
                        printf("disc is mrw formatted\n");
                        break;
        }
}

void print_options(const char *prg)
{
        printf("%s: options:\n", prg);
        printf("\t-d:\t<device>\n");
        printf("\t-f:\t<{restart, full} format type\n");
        printf("\t-F:\tforce format\n");
        printf("\t-s:\tsuspend format\n");
        printf("\t-p:\tpoll for format completion\n");
}

void get_options(int argc, char *argv[])
{
        char c;

        strcpy(mrw_device, "/dev/cdrom");

        while ((c = getopt(argc, argv, "d:f:Fpsl:")) != EOF) {
                switch (c) {
                        case 'd':
                                strcpy(mrw_device, optarg);
                                break;
                        case 'f':
                                if (!strcmp(optarg, "full"))
                                        format_type = FORMAT_TYPE_FULL;
                                else if (!strcmp(optarg, "restart"))
                                        format_type = FORMAT_TYPE_RESTART;
                                else
                                        printf("%s: invalid format type %s\n", argv[0], optarg);
                                break;
                        case 'F':
                                format_force = 1;
                                break;
                        case 'p':
                                poll_wait = 1;
                                break;
                        case 's':
                                suspend_format = 1;
                                break;
                        case 'l':
                                if (!strcmp(optarg, "gaa"))
                                        lba_space = LBA_GAA;
                                else if (!strcmp(optarg, "dma"))
                                        lba_space = LBA_DMA;
                                else
                                        printf("%s: invalid address space %s\n", argv[0], optarg);
                                break;
                        default:
                                if (optarg)
                                        printf("%s: unknown option '%s'\n", argv[0], optarg);
                                print_options(argv[0]);
                                exit(1);
                }
        }
}

int main(int argc, char *argv[])
{
        int fd, media_status, progress;

        if (argc == 1) {
                print_options(argv[0]);
                return 1;
        }

        get_options(argc, argv);

        fd = open(mrw_device, O_RDONLY | O_NONBLOCK);
        if (fd == -1) {
                perror("open");
                return 1;
        }

        if (check_for_mrw(fd)) {
                printf("%s: %s is not a mrw drive or mrw reader\n", argv[0], mrw_device);
                return 1;
        }

        if ((media_status = get_mrw_media_status(fd)) == -1) {
                printf("%s: failed to retrieve media status\n", argv[0]);
                return 1;
        }

        print_mrw_status(media_status);

        if (probe_mrw_mode_page(fd) == -1) {
                printf("%s: failed to probe mrw mode page\n", mrw_device);
                return 1;
        }

        if (lba_space != -1) {
                if (switch_lba_space(fd, lba_space)) {
                        printf("%s: failed switching lba space\n", mrw_device);
                        return 1;
                }
        }

        printf("LBA space: %s\n", lba_spaces[get_lba_space(fd)]);

        if (media_status == CDM_MRW_BGFORMAT_ACTIVE) {
                progress = get_format_progress(fd);
                printf("%s: back ground format %d%% complete\n", mrw_device, progress);
        }

        if (format_type) {
                if (mrw_format(fd, media_status))
                        return 1;
        } else if (suspend_format)
                mrw_format_suspend(fd, media_status);

        if (poll_wait)
                poll_events(fd);

        return 0;
}
</pre>
?>