[Libburn] libburn_drive_get_busy get's locked
Tiago Cogumbreiro
cogumbreiro@linus.uac.pt
Thu, 04 Dec 2003 01:26:14 -0100
--=-gF5Ce/NaMz0iG8kaNFps
Content-Type: text/plain
Content-Transfer-Encoding: 7bit
I am testing the changes to making possible to get the progress while
blanking the media, unfornatly after i call libburn_drive_get_busy it
locks until i the cd is fully blanked thus making impossible to test the
progress, did i do anything wrong?
I am sending as attachments the changed source files.
--=-gF5Ce/NaMz0iG8kaNFps
Content-Disposition: attachment; filename=blank.c
Content-Type: text/x-c; name=blank.c; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include "libburn.h"
#include "toc.h"
#include <unistd.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
static struct libburn_drive_info *drives;
static unsigned int n_drives;
static void blank_disc(struct drive *drive)
{
enum libburn_drive_status s;
struct libburn_progress progress;
if (libburn_drive_grab(drive, 1) != LIBBURN_GRAB_OK) {
fprintf(stderr, "Unable to open the drive!\n");
return;
}
while (libburn_drive_get_busy(drive, NULL))
usleep(1000);
while ((s = libburn_drive_get_status(drive)) == LIBBURN_STATUS_UNREADY)
usleep(1000);
printf("%d\n", s);
if (s != LIBBURN_STATUS_FULL) {
libburn_drive_release(drive, 0);
fprintf(stderr, "No disc found!\n");
return;
}
fprintf(stderr, "Blanking disc...\n");
libburn_erase_disc(drive, 1);
fprintf(stderr, "please wait...\n");
while (libburn_drive_get_busy(drive, &progress)) {
fprintf(stderr, "%d\n", progress.abs_sector);
usleep(200);
}
fprintf(stderr, "Done\n");
libburn_drive_release(drive, 0);
}
void parse_args(int argc, char **argv, int *drive)
{
int i;
int help = 0;
for (i = 1; i < argc; ++i) {
if (!strcmp(argv[i], "--drive")) {
++i;
if (i >= argc)
printf("--drive requires an argument\n");
else
*drive = atoi(argv[i]);
} else if (!strcmp(argv[i], "--verbose")) {
++i;
if (i >= argc)
printf("--verbose requires an argument\n");
else
libburn_set_verbosity(atoi(argv[i]));
} else if (!strcmp(argv[i], "--help")) {
help = 1;
}
}
if (help) {
printf("Usage: %s [--drive <num>] [--verbose <level>]\n", argv[0]);
exit(EXIT_FAILURE);
}
}
int main(int argc, char **argv)
{
int drive = 0;
parse_args(argc, argv, &drive);
fprintf(stderr, "Initializing library...");
if (libburn_initialize())
fprintf(stderr, "Success\n");
else {
printf("Failed\n");
return 1;
}
fprintf(stderr, "Scanning for devices...");
while (!libburn_drive_scan(&drives, &n_drives)) ;
fprintf(stderr, "Done\n");
blank_disc(drives[drive].drive);
libburn_finish();
return 0;
}
--=-gF5Ce/NaMz0iG8kaNFps
Content-Disposition: attachment; filename=sg.c
Content-Type: text/x-c; name=sg.c; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <assert.h>
#include <errno.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <malloc.h>
#include <string.h>
#include <sys/poll.h>
#include <linux/hdreg.h>
#include "transport.h"
#include "drive.h"
#include "sg.h"
#include "spc.h"
#include "mmc.h"
#include "sbc.h"
#include "debug.h"
#include "toc.h"
#include "util.h"
static void enumerate_common(char *fname);
static int sgio_test(int fd)
{
unsigned char test_ops[] = {0,0,0,0,0,0};
sg_io_hdr_t s;
memset(&s, 0, sizeof(sg_io_hdr_t));
s.interface_id = 'S';
s.dxfer_direction = SG_DXFER_NONE;
s.cmd_len = 6;
s.cmdp = test_ops;
s.timeout = 12345;
return ioctl(fd, SG_IO, &s);
}
void ata_enumerate(void)
{
struct hd_driveid tm;
int i, fd;
char fname[10];
for (i = 0; i < 26; i++) {
sprintf(fname, "/dev/hd%c", 'a' + i);
fd = open(fname, O_RDONLY | O_NONBLOCK);
if (fd == -1)
continue;
/* found a drive */
ioctl(fd, HDIO_GET_IDENTITY, &tm);
/* not atapi */
if (!(tm.config & 0x8000) || (tm.config & 0x4000)) {
close(fd);
continue;
}
/* if SG_IO fails on an atapi device, we should stop
trying to use hd* devices */
if (sgio_test(fd) == -1) {
close(fd);
return;
}
close(fd);
enumerate_common(fname);
}
}
void sg_enumerate(void)
{
struct sg_scsi_id sid;
int i, fd;
char fname[10];
for (i = 0; i < 32; i++) {
sprintf(fname, "/dev/sg%d", i);
fd = open(fname, O_RDONLY);
if (fd == -1)
continue;
/* found a drive */
ioctl(fd, SG_GET_SCSI_ID, &sid);
close(fd);
if (sid.scsi_type != TYPE_ROM)
continue;
enumerate_common(fname);
}
}
static void enumerate_common(char *fname)
{
struct drive *t;
struct drive out;
out.devname = libburn_strdup(fname);
out.fd = -1337;
out.atomic_grab = sg_atomic_grab;
out.release = sg_release;
out.issue_command = sg_issue_command;
out.getcaps = spc_getcaps;
out.released = 1;
out.status = LIBBURN_STATUS_UNREADY;
out.eject = sbc_eject;
out.load = sbc_load;
out.lock = spc_prevent;
out.unlock = spc_allow;
out.read_disc_info = spc_sense_write_params;
out.read_toc = mmc_read_toc;
out.write = mmc_write;
out.erase = mmc_erase;
out.read_sectors = mmc_read_sectors;
out.perform_opc = mmc_perform_opc;
out.set_speed = mmc_set_speed;
out.send_parameters = spc_select_error_params;
out.send_write_parameters = spc_select_write_params;
out.sync_cache = mmc_sync_cache;
out.request_sense = mmc_request_sense;
out.idata = malloc(sizeof(struct scsi_inquiry_data));
out.idata->valid = 0;
out.mdata = malloc(sizeof(struct scsi_mode_data));
out.mdata->valid = 0;
memset(&out.params, 0, sizeof(struct params));
t = libburn_drive_register(&out);
/* try to get the drive info */
if (sg_atomic_grab(t)) {
libburn_print(2, "getting drive info\n");
t->getcaps(t);
t->unlock(t);
t->released = 1;
} else {
libburn_print(2, "unable to grab new located drive\n");
}
}
/*
we use the sg reference count to decide whether we can use the
drive or not.
if refcount is not one, drive is open somewhere else.
*/
int sg_atomic_grab(struct drive *d)
{
int fd, count;
fd = open(d->devname, O_RDWR | O_NONBLOCK);
assert(fd != -1337);
if (-1 != fd) {
/* er = ioctl(fd, SG_GET_ACCESS_COUNT, &count);*/
count = 1;
if (1 == count) {
d->fd = fd;
fcntl(fd, F_SETOWN, getpid());
d->released = 0;
return 1;
}
libburn_print(1, "could not acquire drive - already open\n");
close(fd);
return 0;
}
libburn_print(1, "could not acquire drive\n");
return 0;
}
/*
non zero return means you still have the drive and it's not
in a state to be released? (is that even possible?)
*/
int sg_release(struct drive *d)
{
if (d->fd < 1) {
libburn_print(1, "release an ungrabbed drive. die\n");
return 0;
}
close(d->fd);
d->fd = -1337;
return 0;
}
int sg_issue_command(struct drive *d, struct command *c)
{
int done = 0;
int err;
sg_io_hdr_t s;
c->error = 0;
if (d->fd < 1 || d->released) {
libburn_print(1,
"command issued on ungrabbed drive, chaos.\n");
libburn_print(1, "fd = %d, released = %d\n", d->fd,
d->released);
}
memset(&s, 0, sizeof(sg_io_hdr_t));
s.interface_id = 'S';
if (c->dir == TO_DRIVE)
s.dxfer_direction = SG_DXFER_TO_DEV;
else if (c->dir == FROM_DRIVE)
s.dxfer_direction = SG_DXFER_FROM_DEV;
else if (c->dir == NO_TRANSFER) {
s.dxfer_direction = SG_DXFER_NONE;
assert(!c->page);
}
s.cmd_len = c->oplen;
s.cmdp = c->opcode;
s.mx_sb_len = 32;
s.sbp = c->sense;
memset(c->sense, 0, sizeof(c->sense));
s.timeout = 20000000;
if (c->page) {
s.dxferp = c->page->data;
if (c->dir == FROM_DRIVE) {
s.dxfer_len = BUFFER_SIZE;
/* touch page so we can use valgrind */
memset(c->page->data, 0, BUFFER_SIZE);
} else {
assert(c->page->bytes > 0);
s.dxfer_len = c->page->bytes;
}
} else {
s.dxferp = NULL;
s.dxfer_len = 0;
}
s.usr_ptr = c;
do {
err = ioctl(d->fd, SG_IO, &s);
assert(err != -1);
if (s.sb_len_wr) {
switch(scsi_error(d, s.sbp, s.sb_len_wr)) {
case RETRY:
done = 0;
break;
case FAIL:
done = 1;
c->error = 1;
break;
}
} else {
done = 1;
}
} while (!done);
return 1;
}
enum response scsi_error(struct drive *d, unsigned char *sense, int senselen)
{
int key, asc, ascq;
senselen = senselen;
key = sense[2];
asc = sense[12];
ascq = sense[13];
libburn_print(12, "CONDITION: 0x%x 0x%x 0x%x on %s %s\n",
key, asc, ascq, d->idata->vendor, d->idata->product);
switch (asc) {
case 0:
libburn_print(12, "NO ERROR!\n");
return RETRY;
case 2:
libburn_print(1, "not ready\n");
return RETRY;
case 4:
libburn_print(1,
"logical unit is in the process of becoming ready\n");
return RETRY;
case 0x24:
if (key == 5)
libburn_print(1, "invalid field in cdb\n");
else
break;
return FAIL;
case 0x21:
libburn_print(1, "invalid address or something\n");
return FAIL;
case 0x28:
if (key == 6)
libburn_print(1,
"Not ready to ready change, medium may have changed\n");
else
break;
return RETRY;
case 0x20:
if (key == 5)
libburn_print(1, "bad opcode\n");
return FAIL;
case 0x3A:
libburn_print(12, "Medium not present in %s %s\n",
d->idata->vendor, d->idata->product);
d->status = LIBBURN_STATUS_NO_DISC;
return FAIL;
}
libburn_print(1, "unknown failure\n");
libburn_print(1, "key:0x%x, asc:0x%x, ascq:0x%x\n", key, asc, ascq);
return FAIL;
}
--=-gF5Ce/NaMz0iG8kaNFps
Content-Disposition: attachment; filename=mmc.c
Content-Type: text/x-c; name=mmc.c; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include "libburn.h"
#include "transport.h"
#include "mmc.h"
#include "spc.h"
#include "drive.h"
#include "debug.h"
#include "toc.h"
#include "structure.h"
static unsigned char MMC_GET_TOC[] = { 0x43, 2, 2, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_GET_ATIP[] = { 0x43, 2, 4, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_GET_DISC_INFO[] = { 0x51, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_READ_CD[] = { 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_ERASE[] = { 0xA1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_SEND_OPC[] = { 0x54, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_SET_SPEED[] ={ 0xBB, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_WRITE_12[] = { 0xAA, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_WRITE_10[] = { 0x2A, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_GET_CONFIGURATION[] ={ 0x46, 0, 0, 0, 0, 0, 16, 0, 0 };
static unsigned char MMC_SYNC_CACHE[] = { 0x35, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
static unsigned char MMC_GET_EVENT[] = { 0x4A, 1, 0, 0, 16, 0, 0, 0, 8, 0 };
static unsigned char MMC_REQUEST_SENSE[] = { 0x03, 0, 0, 0, 18, 0};
void mmc_request_sense(struct drive *d, struct buffer *buf)
{
struct command c;
c.oplen = sizeof(MMC_REQUEST_SENSE);
memcpy(c.opcode, MMC_REQUEST_SENSE, sizeof(MMC_REQUEST_SENSE));
c.page = buf;
c.page->sectors = 0;
c.page->bytes = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
}
void mmc_get_event(struct drive *d)
{
struct buffer buf;
struct command c;
c.oplen = sizeof(MMC_GET_EVENT);
memcpy(c.opcode, MMC_GET_EVENT, sizeof(MMC_GET_EVENT));
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
printf("0x%x:0x%x:0x%x:0x%x\n",
c.page->data[0], c.page->data[1], c.page->data[2], c.page->data[3]);
printf("event: %d:%d:%d:%d\n",
c.page->data[4], c.page->data[5], c.page->data[6], c.page->data[7]);
}
void mmc_write_12(struct drive *d, int start, struct buffer *buf)
{
struct command c;
int len;
len = buf->sectors;
assert(buf->bytes >= buf->sectors); /* can be == at 0... */
libburn_print(100, "trying to write %d at %d\n", len, start);
memcpy(c.opcode, MMC_WRITE_12, sizeof(MMC_WRITE_12));
c.oplen = sizeof(MMC_WRITE_12);
c.opcode[2] = start >> 24;
c.opcode[3] = (start >> 16) & 0xFF;
c.opcode[4] = (start >> 8) & 0xFF;
c.opcode[5] = start & 0xFF;
c.opcode[6] = len >> 24;
c.opcode[7] = (len >> 16) & 0xFF;
c.opcode[8] = (len >> 8) & 0xFF;
c.opcode[9] = len & 0xFF;
c.page = buf;
c.dir = TO_DRIVE;
d->issue_command(d, &c);
}
void mmc_write(struct drive *d, int start, struct buffer *buf)
{
struct command c;
int len;
len = buf->sectors;
assert(buf->bytes >= buf->sectors); /* can be == at 0... */
libburn_print(100, "trying to write %d at %d\n", len, start);
memcpy(c.opcode, MMC_WRITE_10, sizeof(MMC_WRITE_10));
c.oplen = sizeof(MMC_WRITE_10);
c.opcode[2] = start >> 24;
c.opcode[3] = (start >> 16) & 0xFF;
c.opcode[4] = (start >> 8) & 0xFF;
c.opcode[5] = start & 0xFF;
c.opcode[6] = 0;
c.opcode[7] = (len >> 8) & 0xFF;
c.opcode[8] = len & 0xFF;
c.page = buf;
c.dir = TO_DRIVE;
/*
printf("%d, %d, %d, %d - ", c->opcode[2], c->opcode[3], c->opcode[4], c->opcode[5]);
printf("%d, %d, %d, %d\n", c->opcode[6], c->opcode[7], c->opcode[8], c->opcode[9]);
*/
/* write(fileno(stderr), c.page->data, c.page->bytes);*/
d->issue_command(d, &c);
}
void mmc_read_toc(struct drive *d)
{
/* read full toc, all sessions, in m/s/f form, 4k buffer */
struct track *track;
struct session *session;
struct buffer buf;
struct command c;
int dlen;
int i;
unsigned char *tdata;
memcpy(c.opcode, MMC_GET_TOC, sizeof(MMC_GET_TOC));
c.oplen = sizeof(MMC_GET_TOC);
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
if (c.error) {
d->busy = LIBBURN_BUSY_NO;
return;
}
dlen = c.page->data[0] * 256 + c.page->data[1];
d->toc_entries = (dlen - 2) / 11;
/*
some drives fail this check.
assert(((dlen - 2) % 11) == 0);
*/
d->toc_entry = malloc(d->toc_entries * sizeof(struct toc_entry));
tdata = c.page->data + 4;
libburn_print(12, "TOC:\n");
d->disc = libburn_disc_create();
for (i = 0; i < c.page->data[3]; i++) {
session = libburn_session_create();
libburn_session_add(d->disc, session, LIBBURN_POS_END);
libburn_session_destroy(session);
}
for (i = 0; i < d->toc_entries; i++, tdata += 11) {
libburn_print(12, "S %d, PT %d, TNO %d : ", tdata[0], tdata[3],
tdata[2]);
libburn_print(12, "(%d:%d:%d)", tdata[8], tdata[9], tdata[10]);
libburn_print(12, "A(%d:%d:%d)", tdata[4], tdata[5], tdata[6]);
libburn_print(12, " - control %d, adr %d\n", tdata[1] & 0xF,
tdata[1] >> 4);
if (tdata[3] == 1) {
if (libburn_msf_to_lba(tdata[8], tdata[9], tdata[10])) {
d->disc->session[0]->hidefirst = 1;
track = libburn_track_create();
libburn_track_add(
d->disc->session[tdata[0] - 1],
track, LIBBURN_POS_END);
libburn_track_destroy(track);
}
}
if (tdata[3] < 100) {
track = libburn_track_create();
libburn_track_add(d->disc->session[tdata[0] - 1],
track, LIBBURN_POS_END);
track->entry = &d->toc_entry[i];
libburn_track_destroy(track);
}
d->toc_entry[i].session = tdata[0];
d->toc_entry[i].adr = tdata[1] >> 4;
d->toc_entry[i].control = tdata[1] & 0xF;
d->toc_entry[i].tno = tdata[2];
d->toc_entry[i].point = tdata[3];
d->toc_entry[i].min = tdata[4];
d->toc_entry[i].sec = tdata[5];
d->toc_entry[i].frame = tdata[6];
d->toc_entry[i].zero = tdata[7];
d->toc_entry[i].pmin = tdata[8];
d->toc_entry[i].psec = tdata[9];
d->toc_entry[i].pframe = tdata[10];
if (tdata[3] == 0xA0)
d->disc->session[tdata[0] - 1]->firsttrack = tdata[8];
if (tdata[3] == 0xA1)
d->disc->session[tdata[0] - 1]->lasttrack = tdata[8];
if (tdata[3] == 0xA2)
d->disc->session[tdata[0] - 1]->leadout_entry =
&d->toc_entry[i];
}
d->status = LIBBURN_STATUS_FULL;
toc_find_modes(d);
}
void mmc_read_disc_info(struct drive *d)
{
struct buffer buf;
unsigned char *data;
struct command c;
memcpy(c.opcode, MMC_GET_DISC_INFO, sizeof(MMC_GET_DISC_INFO));
c.oplen = sizeof(MMC_GET_DISC_INFO);
c.page = &buf;
c.page->sectors = 0;
c.page->bytes = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
if (c.error) {
d->busy = LIBBURN_BUSY_NO;
return;
}
data = c.page->data;
switch (data[2] & 3) {
case 0:
d->toc_entries = 0;
d->start_lba = libburn_msf_to_lba(data[17], data[18], data[19]);
d->end_lba = libburn_msf_to_lba(data[21], data[22], data[23]);
d->status = LIBBURN_STATUS_BLANK;
spc_try_write_modes(d);
break;
case 1:
case 2:
mmc_read_toc(d);
break;
}
}
void mmc_read_atip(struct drive *d)
{
struct buffer buf;
struct command c;
memcpy(c.opcode, MMC_GET_ATIP, sizeof(MMC_GET_ATIP));
c.oplen = sizeof(MMC_GET_ATIP);
c.page = &buf;
c.page->bytes = 0;
c.page->sectors = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
libburn_print(1, "atip shit for you\n");
}
void mmc_read_sectors(struct drive *d,
int start,
int len,
const struct libburn_read_opts *o,
struct buffer *buf)
{
int temp;
int errorblock, req;
struct command c;
assert(len >= 0);
/* if the drive isn't busy, why the hell are we here? */
assert(d->busy);
printf("reading %d from %d\n", len, start);
memcpy(c.opcode, MMC_READ_CD, sizeof(MMC_READ_CD));
c.oplen = sizeof(MMC_READ_CD);
temp = start;
c.opcode[5] = temp & 0xFF;
temp >>= 8;
c.opcode[4] = temp & 0xFF;
temp >>= 8;
c.opcode[3] = temp & 0xFF;
temp >>= 8;
c.opcode[2] = temp & 0xFF;
c.opcode[8] = len & 0xFF;
len >>= 8;
c.opcode[7] = len & 0xFF;
len >>= 8;
c.opcode[6] = len & 0xFF;
req = 0xF8;
if (d->busy == LIBBURN_BUSY_GRABBING ||
o->protected_audio ||
o->report_recovered_errors)
req |= 2;
c.opcode[10] = 0;
/* always read the subcode, throw it away later, since we don't know
what we're really reading
*/
if (d->busy == LIBBURN_BUSY_GRABBING || (o->subcodes_audio)
|| (o->subcodes_data))
c.opcode[10] = 1;
c.opcode[9] = req;
c.page = buf;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
if (c.error) {
printf("got an error over here\n");
printf("%d, %d, %d, %d\n", c.sense[3], c.sense[4], c.sense[5], c.sense[6]);
errorblock = (c.sense[3] << 24) +
(c.sense[4] << 16) + (c.sense[5] << 8) + c.sense[6];
c.page->sectors = errorblock - start + 1;
libburn_print(1, "error on block %d\n", errorblock);
printf("error on block %d\n", errorblock);
printf("returning %d sectors\n", c.page->sectors);
}
}
void mmc_erase(struct drive *d, int fast)
{
struct command c;
memcpy(c.opcode, MMC_ERASE, sizeof(MMC_ERASE));
c.opcode[1] = !!fast;
c.oplen = sizeof(MMC_ERASE);
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
void mmc_read_lead_in(struct drive *d, struct buffer *buf)
{
int len;
struct command c;
len = buf->sectors;
memcpy(c.opcode, MMC_READ_CD, sizeof(MMC_READ_CD));
c.oplen = sizeof(MMC_READ_CD);
c.opcode[5] = 0;
c.opcode[4] = 0;
c.opcode[3] = 0;
c.opcode[2] = 0xF0;
c.opcode[8] = 1;
c.opcode[7] = 0;
c.opcode[6] = 0;
c.opcode[9] = 0;
c.opcode[10] = 2;
c.page = buf;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
}
void mmc_perform_opc(struct drive *d)
{
struct command c;
memcpy(c.opcode, MMC_SEND_OPC, sizeof(MMC_SEND_OPC));
c.oplen = sizeof(MMC_SEND_OPC);
c.opcode[1] = 1;
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
void mmc_set_speed(struct drive *d, int read, int write)
{
struct command c;
memcpy(c.opcode, MMC_SET_SPEED, sizeof(MMC_SET_SPEED));
c.oplen = sizeof(MMC_SET_SPEED);
c.opcode[2] = read >> 8;
c.opcode[3] = read & 0xFF;
c.opcode[4] = write >> 8;
c.opcode[5] = write & 0xFF;
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
void mmc_get_configuration(struct drive *d)
{
struct buffer buf;
int len;
struct command c;
memcpy(c.opcode, MMC_GET_CONFIGURATION,
sizeof(MMC_GET_CONFIGURATION));
c.oplen = sizeof(MMC_GET_CONFIGURATION);
c.page = &buf;
c.page->sectors = 0;
c.page->bytes = 0;
c.dir = FROM_DRIVE;
d->issue_command(d, &c);
libburn_print(1, "got it back\n");
len = (c.page->data[0] << 24)
+ (c.page->data[1] << 16)
+ (c.page->data[2] << 8)
+ c.page->data[3];
libburn_print(1, "all %d bytes of it\n", len);
libburn_print(1, "%d, %d, %d, %d\n",
c.page->data[0],
c.page->data[1], c.page->data[2], c.page->data[3]);
}
void mmc_sync_cache(struct drive *d)
{
struct command c;
memcpy(c.opcode, MMC_SYNC_CACHE, sizeof(MMC_SYNC_CACHE));
c.oplen = sizeof(MMC_SYNC_CACHE);
c.page = NULL;
c.dir = NO_TRANSFER;
d->issue_command(d, &c);
}
--=-gF5Ce/NaMz0iG8kaNFps
Content-Disposition: attachment; filename=mmc.h
Content-Type: text/x-c-header; name=mmc.h; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __MMC
#define __MMC
struct drive;
struct command;
struct buffer;
/* MMC commands */
void mmc_read(struct drive *);
void mmc_get_event(struct drive *);
void mmc_write(struct drive *, int start, struct buffer *buf);
void mmc_sync_cache(struct drive *);
void mmc_load(struct drive *);
void mmc_eject(struct drive *);
void mmc_erase(struct drive *, int);
void mmc_read_toc(struct drive *);
void mmc_read_disc_info(struct drive *);
void mmc_read_atip(struct drive *);
void mmc_read_sectors(struct drive *,
int,
int,
const struct libburn_read_opts *,
struct buffer *);
void mmc_set_speed(struct drive *, int, int);
void mmc_read_lead_in(struct drive *, struct buffer *);
void mmc_perform_opc(struct drive *);
void mmc_get_configuration(struct drive *);
void mmc_request_sense(struct drive *d, struct buffer *buf);
#endif /*__MMC*/
--=-gF5Ce/NaMz0iG8kaNFps
Content-Disposition: attachment; filename=drive.c
Content-Type: text/x-c; name=drive.c; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#include <malloc.h>
#include <unistd.h>
#include <signal.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include "libburn.h"
#include "drive.h"
#include "transport.h"
#include "message.h"
#include "debug.h"
#include "init.h"
#include "toc.h"
#include "util.h"
#include "sg.h"
#include "structure.h"
static struct drive drive_array[255];
static int drivetop = -1;
void libburn_drive_destroy(void)
{
int i;
struct drive *d;
for (i = 0; i < drivetop + 1; i++) {
d = &drive_array[i];
free((void *)d->idata);
free((void *)d->mdata);
free((void *)d->toc_entry);
free(d->devname);
}
drivetop = -1;
memset(drive_array, 0, sizeof(drive_array));
}
/*
void drive_read_lead_in(int dnum)
{
mmc_read_lead_in(&drive_array[dnum], get_4k());
}
*/
unsigned int libburn_drive_count(void)
{
return drivetop + 1;
}
enum libburn_grab libburn_drive_grab(struct drive *d, int le)
{
int errcode;
if (!d->released) {
libburn_print(1, "can't grab - already grabbed\n");
return LIBBURN_GRAB_FAIL;
}
errcode = d->atomic_grab(d);
if (errcode == 0) {
libburn_print(1, "low level drive grab failed\n");
return LIBBURN_GRAB_FAIL;
}
d->busy = LIBBURN_BUSY_GRABBING;
if (le)
d->load(d);
d->lock(d);
if (d->mdata->cdr_write || d->mdata->cdrw_write ||
d->mdata->dvdr_write || d->mdata->dvdram_write) {
d->read_disc_info(d);
} else
d->read_toc(d);
d->busy = LIBBURN_BUSY_NO;
return LIBBURN_GRAB_OK;
}
struct drive *libburn_drive_register(struct drive *d)
{
d->write_type = -1;
d->block_type = -1;
d->block_types[0] = 0;
d->block_types[1] = 0;
d->block_types[2] = 0;
d->block_types[3] = 0;
d->toc_temp = 0;
d->nwa = 0;
d->alba = 0;
d->rlba = 0;
d->cancel = 0;
d->busy = LIBBURN_BUSY_NO;
d->params.flags = 0;
d->toc_entries = 0;
d->toc_entry = NULL;
/* remove mediacatalog from drive plz */
d->has_mediacatalog = 0;
d->disc = NULL;
memcpy(&drive_array[drivetop + 1], d, sizeof(struct drive));
return &drive_array[++drivetop];
}
void libburn_drive_release(struct drive *d, int le)
{
if (d->released)
libburn_print(1, "second release on drive!\n");
assert(!d->busy);
if (le)
d->eject(d);
d->unlock(d);
d->release(d);
d->status = LIBBURN_STATUS_UNREADY;
d->released = 1;
if (d->toc_entry)
free(d->toc_entry);
d->toc_entry = NULL;
d->toc_entries = 0;
if (d->disc != NULL) {
libburn_disc_destroy(d->disc);
d->disc = NULL;
}
/* XXX remove mediacatalog from drive*/
d->has_mediacatalog = 0;
}
void libburn_wait_all()
{
unsigned int i;
int finished = 0;
struct drive *d;
while (!finished) {
finished = 1;
d = drive_array;
for (i = libburn_drive_count(); i > 0; --i, ++d) {
assert(d->released);
}
if (!finished)
sleep(1);
}
}
void libburn_erase_disc_sync(struct drive *d, int fast)
{
libburn_message_clear_queue();
libburn_print(1, "erasing drive %s %s\n", d->idata->vendor,
d->idata->product);
if (d->status != LIBBURN_STATUS_FULL)
return;
d->cancel = 0;
d->busy = LIBBURN_BUSY_ERASING;
d->erase(d, fast);
d->busy = LIBBURN_BUSY_NO;
}
enum libburn_drive_status libburn_drive_get_status(struct drive *d)
{
assert(!d->released);
return d->status;
}
int libburn_drive_get_busy(struct drive *d, struct libburn_progress *p)
{
if (p) {
if(d->busy == LIBBURN_BUSY_ERASING) {
struct buffer *buf = malloc(sizeof(struct buffer));
p->session = 1;
p->sessions = 1;
p->track = 1;
p->tracks = 1;
p->index = 1;
p->indices = 1;
p->abs_sectors = 0x10000;
p->rel_sectors = 0x10000;
d->request_sense(d, buf);
p->abs_sector = (buf->data[17] << 8) | buf->data[18];
p->rel_sector = p->abs_sector;
free(buf);
}
/* this is where we do stuff! */
}
return d->busy != LIBBURN_BUSY_NO;
}
void libburn_drive_cancel(struct drive *d)
{
d->cancel = 1;
}
int libburn_drive_get_block_types(struct drive *d,
enum libburn_write_types write_type)
{
libburn_print(12, "write type: %d\n", write_type);
assert( /* (write_type >= LIBBURN_WRITE_PACKET) && */
(write_type <= LIBBURN_WRITE_RAW));
return d->block_types[write_type];
}
static void strip_spaces(char *str)
{
char *tmp;
tmp = str + strlen(str) - 1;
while (isspace(*tmp))
*(tmp--) = '\0';
tmp = str;
while (*tmp) {
if (isspace(*tmp) && isspace(*(tmp + 1))) {
char *tmp2;
for (tmp2 = tmp + 1; *tmp2; ++tmp2)
*(tmp2 - 1) = *tmp2;
*(tmp2 - 1) = '\0';
} else
++tmp;
}
}
static int drive_getcaps(struct drive *d, struct libburn_drive_info *out)
{
struct scsi_inquiry_data *id;
assert(d->idata);
assert(d->mdata);
if (!d->idata->valid || !d->mdata->valid)
return 0;
id = (struct scsi_inquiry_data *)d->idata;
memcpy(out->vendor, id->vendor, sizeof(id->vendor));
strip_spaces(out->vendor);
memcpy(out->product, id->product, sizeof(id->product));
strip_spaces(out->product);
strncpy(out->location, d->devname, 16);
out->location[16] = '\0';
out->buffer_size = d->mdata->buffer_size;
out->read_dvdram = !!d->mdata->dvdram_read;
out->read_dvdr = !!d->mdata->dvdr_read;
out->read_dvdrom = !!d->mdata->dvdrom_read;
out->read_cdr = !!d->mdata->cdr_read;
out->read_cdrw = !!d->mdata->cdrw_read;
out->write_dvdram = !!d->mdata->dvdram_write;
out->write_dvdr = !!d->mdata->dvdr_write;
out->write_cdr = !!d->mdata->cdr_write;
out->write_cdrw = !!d->mdata->cdrw_write;
out->write_simulate = !!d->mdata->simulate;
out->read_max_speed = d->mdata->max_read_speed;
out->write_max_speed = d->mdata->max_write_speed;
out->c2_errors = !!d->mdata->c2_pointers;
out->drive = d;
return 1;
}
int libburn_drive_scan_sync(struct libburn_drive_info *drives[],
unsigned int *n_drives)
{
/* state vars for the scan process */
static int scanning = 0, scanned, found;
static unsigned num_scanned, count;
unsigned int i;
struct drive *d;
assert(libburn_running);
if (!scanning) {
scanning = 1;
/* make sure the drives aren't in use */
libburn_wait_all(); /* make sure the queue cleans up
before checking for the released
state */
d = drive_array;
count = libburn_drive_count();
for (i = 0; i < count; ++i, ++d)
assert(d->released == 1);
/* refresh the lib's drives */
sg_enumerate();
ata_enumerate();
count = libburn_drive_count();
if (count)
*drives =
malloc(sizeof(struct libburn_drive_info) *
count);
else
*drives = NULL;
*n_drives = scanned = found = num_scanned = 0;
}
for (i = 0; i < count; ++i) {
if (scanned & (1 << i))
continue; /* already scanned the device */
while (!drive_getcaps(&drive_array[i],
&(*drives)[num_scanned])) {
sleep(1);
}
scanned |= 1 << i;
found |= 1 << i;
num_scanned++;
(*n_drives)++;
}
if (num_scanned == count) {
/* done scanning */
scanning = 0;
return 1;
}
return 0;
}
struct disc *libburn_drive_get_disc(struct drive *d)
{
d->disc->refcnt++;
return d->disc;
}
--=-gF5Ce/NaMz0iG8kaNFps
Content-Disposition: attachment; filename=drive.h
Content-Type: text/x-c-header; name=drive.h; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
#ifndef __DRIVE
#define __DRIVE
#include "libburn.h"
#include "toc.h"
#include "structure.h"
struct drive;
struct command;
struct mempage;
#define LEAD_IN 1
#define GAP 2
#define USER_DATA 3
#define LEAD_OUT 4
#define SYNC 5
/** Possible busy states for a drive */
enum libburn_drive_busy
{
/** The drive is not in an operation */
LIBBURN_BUSY_NO,
/** The library is spawning the processes to handle a pending
operation (A read/write/etc is about to start but hasn't quite
yet) */
LIBBURN_BUSY_SPAWNING,
/** The drive is reading data from a disc */
LIBBURN_BUSY_READING,
/** The drive is writing data to a disc */
LIBBURN_BUSY_WRITING,
/** The drive is erasing a disc */
LIBBURN_BUSY_ERASING,
/** The drive is being grabbed */
LIBBURN_BUSY_GRABBING
};
#define SESSION_LEADOUT_ENTRY(d,s) (d)->toc->session[(s)].leadout_entry
#define CURRENT_SESSION_START(d) \
libburn_msf_to_lba(d->toc->session[d->currsession].start_m, \
d->toc->session[d->currsession].start_s, \
d->toc->session[d->currsession].start_f)
#define SESSION_END(d,s) \
TOC_ENTRY_PLBA((d)->toc, SESSION_LEADOUT_ENTRY((d), (s)))
#define PREVIOUS_SESSION_END(d) \
TOC_ENTRY_PLBA((d)->toc, SESSION_LEADOUT_ENTRY((d), (d)->currsession-1))
#define LAST_SESSION_END(d) \
TOC_ENTRY_PLBA((d)->toc, \
SESSION_LEADOUT_ENTRY((d), (d)->toc->sessions-1))
struct drive *libburn_drive_register(struct drive *);
unsigned int libburn_drive_count(void);
void libburn_wait_all();
void libburn_drive_release_finish(struct drive *d);
int libburn_sector_length_write(struct drive *d);
int libburn_track_control(struct drive *d, int);
void libburn_write_empty_sector(int fd);
void libburn_write_empty_subcode(int fd);
void libburn_drive_destroy(void);
void libburn_send_toc(struct drive *d, struct toc *t);
int libburn_drive_scan_sync(struct libburn_drive_info *drives[],
unsigned int *n_drives);
void libburn_erase_disc_sync(struct drive *d, int fast);
#endif /* __DRIVE */
--=-gF5Ce/NaMz0iG8kaNFps--