2006-08-15 20:37:04 +00:00
|
|
|
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
2006-10-09 08:43:15 +00:00
|
|
|
|
|
|
|
/* ts A61009 */
|
|
|
|
/* #include <a ssert.h> */
|
|
|
|
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <ctype.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include "error.h"
|
|
|
|
#include "sector.h"
|
|
|
|
#include "libburn.h"
|
|
|
|
#include "drive.h"
|
|
|
|
#include "transport.h"
|
|
|
|
#include "crc.h"
|
|
|
|
#include "debug.h"
|
|
|
|
#include "init.h"
|
|
|
|
#include "lec.h"
|
|
|
|
#include "toc.h"
|
|
|
|
#include "util.h"
|
|
|
|
#include "sg.h"
|
|
|
|
#include "write.h"
|
|
|
|
#include "options.h"
|
|
|
|
|
2006-10-09 08:43:15 +00:00
|
|
|
#include "libdax_msgs.h"
|
|
|
|
extern struct libdax_msgs *libdax_messenger;
|
|
|
|
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
static int type_to_ctrl(int mode)
|
|
|
|
{
|
|
|
|
int ctrl = 0;
|
|
|
|
|
|
|
|
int data = BURN_MODE2 | BURN_MODE1 | BURN_MODE0;
|
|
|
|
|
|
|
|
if (mode & data) {
|
|
|
|
ctrl |= 4;
|
|
|
|
} else if (mode & BURN_AUDIO) {
|
|
|
|
if (mode & BURN_4CH)
|
|
|
|
ctrl |= 8;
|
|
|
|
if (mode & BURN_PREEMPHASIS)
|
|
|
|
ctrl |= 1;
|
|
|
|
} else
|
2006-10-09 08:43:15 +00:00
|
|
|
/* ts A61008 */
|
|
|
|
/* a ssert(0); */
|
|
|
|
return -1;
|
2006-08-15 20:37:04 +00:00
|
|
|
|
|
|
|
if (mode & BURN_COPY)
|
|
|
|
ctrl |= 2;
|
|
|
|
|
|
|
|
return ctrl;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* only the ctrl nibble is set here (not adr) */
|
2006-10-09 08:43:15 +00:00
|
|
|
/* ts A61009 : removed "static" , reacted on type_to_ctrl() == -1
|
|
|
|
preserved ignorance towards unknown modes (for now) */
|
|
|
|
void type_to_form(int mode, unsigned char *ctladr, int *form)
|
2006-08-15 20:37:04 +00:00
|
|
|
{
|
2006-10-09 08:43:15 +00:00
|
|
|
int ret;
|
|
|
|
|
|
|
|
ret = type_to_ctrl(mode) << 4;
|
|
|
|
if (ret == -1) {
|
|
|
|
*ctladr = 0xff;
|
|
|
|
*form = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
*ctladr = ret;
|
2006-08-15 20:37:04 +00:00
|
|
|
|
|
|
|
if (mode & BURN_AUDIO)
|
|
|
|
*form = 0;
|
2006-10-09 08:43:15 +00:00
|
|
|
if (mode & BURN_MODE0) {
|
|
|
|
|
|
|
|
/* ts A61009 */
|
|
|
|
/* a ssert(0); */
|
|
|
|
*form = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
if (mode & BURN_MODE1)
|
|
|
|
*form = 0x10;
|
2006-10-09 08:43:15 +00:00
|
|
|
if (mode & BURN_MODE2) {
|
|
|
|
|
|
|
|
/* ts A61009 */
|
|
|
|
/* a ssert(0); */ /* XXX someone's gonna want this sometime */
|
|
|
|
*form = -1;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
if (mode & BURN_MODE_RAW)
|
|
|
|
*form = 0;
|
|
|
|
if (mode & BURN_SUBCODE_P16) /* must be expanded to R96 */
|
|
|
|
*form |= 0x40;
|
|
|
|
if (mode & BURN_SUBCODE_P96)
|
|
|
|
*form |= 0xC0;
|
|
|
|
if (mode & BURN_SUBCODE_R96)
|
|
|
|
*form |= 0x40;
|
|
|
|
}
|
|
|
|
|
|
|
|
int burn_write_flush(struct burn_write_opts *o)
|
|
|
|
{
|
|
|
|
struct burn_drive *d = o->drive;
|
|
|
|
|
|
|
|
if (d->buffer->bytes && !d->cancel) {
|
|
|
|
int err;
|
|
|
|
err = d->write(d, d->nwa, d->buffer);
|
|
|
|
if (err == BE_CANCELLED)
|
|
|
|
return 0;
|
|
|
|
d->nwa += d->buffer->sectors;
|
|
|
|
}
|
|
|
|
d->sync_cache(d);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-08-20 18:21:29 +00:00
|
|
|
|
2006-10-31 11:55:51 +00:00
|
|
|
/* ts A61030 */
|
|
|
|
int burn_write_close_track(struct burn_write_opts *o, int tnum)
|
|
|
|
{
|
|
|
|
char msg[81];
|
|
|
|
|
|
|
|
sprintf(msg, "Closing track %2.2d\n", tnum+1);
|
|
|
|
libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
|
|
|
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
|
|
|
|
|
|
|
|
/* MMC-1 mentions track number 0xFF for "the incomplete track",
|
|
|
|
MMC-3 does not. I tried both. 0xFF was in effect when other
|
|
|
|
bugs finally gave up and made way for readable tracks. */
|
|
|
|
o->drive->close_track_session(o->drive, 0, 0xff); /* tnum+1); */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A61030 */
|
|
|
|
int burn_write_close_session(struct burn_write_opts *o)
|
|
|
|
{
|
|
|
|
libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
|
|
|
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Closing session", 0, 0);
|
|
|
|
|
|
|
|
o->drive->close_track_session(o->drive, 1, 0);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-20 18:21:29 +00:00
|
|
|
/* ts A60819:
|
|
|
|
This is unused since about Feb 2006, icculus.org/burn CVS.
|
|
|
|
The compiler complains. We shall please our compiler.
|
|
|
|
*/
|
|
|
|
#ifdef Libburn_write_with_function_print_cuE
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
static void print_cue(struct cue_sheet *sheet)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
unsigned char *unit;
|
|
|
|
|
|
|
|
printf("\n");
|
|
|
|
printf("ctladr|trno|indx|form|scms| msf\n");
|
|
|
|
printf("------+----+----+----+----+--------\n");
|
|
|
|
for (i = 0; i < sheet->count; i++) {
|
|
|
|
unit = sheet->data + 8 * i;
|
|
|
|
printf(" %1X %1X | %02X | %02X | %02X | %02X |",
|
|
|
|
(unit[0] & 0xf0) >> 4, unit[0] & 0xf, unit[1], unit[2],
|
|
|
|
unit[3], unit[4]);
|
|
|
|
printf("%02X:%02X:%02X\n", unit[5], unit[6], unit[7]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2006-08-20 18:21:29 +00:00
|
|
|
#endif /* Libburn_write_with_print_cuE */
|
|
|
|
|
|
|
|
|
2006-10-09 08:43:15 +00:00
|
|
|
/* ts A61009 : changed type from void to int */
|
|
|
|
/** @return 1 = success , <=0 failure */
|
|
|
|
static int add_cue(struct cue_sheet *sheet, unsigned char ctladr,
|
2006-08-15 20:37:04 +00:00
|
|
|
unsigned char tno, unsigned char indx,
|
|
|
|
unsigned char form, unsigned char scms, int lba)
|
|
|
|
{
|
|
|
|
unsigned char *unit;
|
|
|
|
unsigned char *ptr;
|
|
|
|
int m, s, f;
|
|
|
|
|
|
|
|
burn_lba_to_msf(lba, &m, &s, &f);
|
|
|
|
|
|
|
|
sheet->count++;
|
|
|
|
ptr = realloc(sheet->data, sheet->count * 8);
|
2006-10-09 08:43:15 +00:00
|
|
|
|
|
|
|
/* ts A61009 */
|
|
|
|
/* a ssert(ptr); */
|
|
|
|
if (ptr == NULL) {
|
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Could not allocate new auxiliary object (cue_sheet->data)",
|
|
|
|
0, 0);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
sheet->data = ptr;
|
|
|
|
unit = sheet->data + (sheet->count - 1) * 8;
|
|
|
|
unit[0] = ctladr;
|
|
|
|
unit[1] = tno;
|
|
|
|
unit[2] = indx;
|
|
|
|
unit[3] = form;
|
|
|
|
unit[4] = scms;
|
|
|
|
unit[5] = m;
|
|
|
|
unit[6] = s;
|
|
|
|
unit[7] = f;
|
2006-10-09 08:43:15 +00:00
|
|
|
return 1;
|
2006-08-15 20:37:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
|
|
|
|
struct burn_session *session)
|
|
|
|
{
|
2006-10-09 08:43:15 +00:00
|
|
|
int i, m, s, f, form, pform, runtime = -150, ret;
|
2006-08-15 20:37:04 +00:00
|
|
|
unsigned char ctladr;
|
|
|
|
struct burn_drive *d;
|
|
|
|
struct burn_toc_entry *e;
|
|
|
|
struct cue_sheet *sheet;
|
|
|
|
struct burn_track **tar = session->track;
|
|
|
|
int ntr = session->tracks;
|
|
|
|
int rem = 0;
|
|
|
|
|
|
|
|
d = o->drive;
|
|
|
|
|
|
|
|
sheet = malloc(sizeof(struct cue_sheet));
|
2006-10-09 08:43:15 +00:00
|
|
|
|
|
|
|
/* ts A61009 : react on failures of malloc(), add_cue_sheet()
|
|
|
|
type_to_form() */
|
|
|
|
if (sheet == NULL) {
|
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x00020111,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Could not allocate new auxiliary object (cue_sheet)",
|
|
|
|
0, 0);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
sheet->data = NULL;
|
|
|
|
sheet->count = 0;
|
|
|
|
type_to_form(tar[0]->mode, &ctladr, &form);
|
2006-10-09 08:43:15 +00:00
|
|
|
if (form == -1) {
|
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x00020116,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Track mode has unusable value", 0, 0);
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
ret = add_cue(sheet, ctladr | 1, 0, 0, 1, 0, runtime);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
|
|
|
ret = add_cue(sheet, ctladr | 1, 1, 0, form, 0, runtime);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
2006-08-15 20:37:04 +00:00
|
|
|
runtime += 150;
|
|
|
|
|
|
|
|
burn_print(1, "toc for %d tracks:\n", ntr);
|
|
|
|
d->toc_entries = ntr + 3;
|
2006-10-09 08:43:15 +00:00
|
|
|
|
|
|
|
/* ts A61009 */
|
|
|
|
/* a ssert(d->toc_entry == NULL); */
|
|
|
|
if (d->toc_entry != NULL) {
|
|
|
|
libdax_msgs_submit(libdax_messenger,
|
|
|
|
d->global_index, 0x00020117,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"toc_entry of drive is already in use", 0, 0);
|
|
|
|
goto failed;
|
|
|
|
}
|
|
|
|
|
2006-10-19 08:31:33 +00:00
|
|
|
d->toc_entry = calloc(d->toc_entries, sizeof(struct burn_toc_entry));
|
2006-08-15 20:37:04 +00:00
|
|
|
e = d->toc_entry;
|
|
|
|
e[0].point = 0xA0;
|
|
|
|
if (tar[0]->mode & BURN_AUDIO)
|
|
|
|
e[0].control = TOC_CONTROL_AUDIO;
|
|
|
|
else
|
|
|
|
e[0].control = TOC_CONTROL_DATA;
|
|
|
|
e[0].pmin = 1;
|
|
|
|
e[0].psec = o->format;
|
|
|
|
e[0].adr = 1;
|
|
|
|
e[1].point = 0xA1;
|
|
|
|
e[1].pmin = ntr;
|
|
|
|
e[1].adr = 1;
|
|
|
|
if (tar[ntr - 1]->mode & BURN_AUDIO)
|
|
|
|
e[1].control = TOC_CONTROL_AUDIO;
|
|
|
|
else
|
|
|
|
e[1].control = TOC_CONTROL_DATA;
|
|
|
|
e[2].point = 0xA2;
|
|
|
|
e[2].control = e[1].control;
|
|
|
|
e[2].adr = 1;
|
|
|
|
|
|
|
|
tar[0]->pregap2 = 1;
|
|
|
|
pform = form;
|
|
|
|
for (i = 0; i < ntr; i++) {
|
|
|
|
type_to_form(tar[i]->mode, &ctladr, &form);
|
|
|
|
if (pform != form) {
|
2006-10-09 08:43:15 +00:00
|
|
|
|
|
|
|
ret = add_cue(sheet, ctladr | 1, i + 1, 0, form, 0,
|
|
|
|
runtime);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
runtime += 150;
|
|
|
|
/* XXX fix pregap interval 1 for data tracks */
|
2006-08-20 18:21:29 +00:00
|
|
|
/* ts A60813 silence righteous compiler warning about C++ style comments
|
|
|
|
This is possibly not a comment but rather a trace of Derek Foreman
|
|
|
|
experiments. Thus not to be beautified - but to be preserved rectified.
|
|
|
|
/ / if (!(form & BURN_AUDIO))
|
|
|
|
/ / tar[i]->pregap1 = 1;
|
|
|
|
*/
|
2006-08-15 20:37:04 +00:00
|
|
|
tar[i]->pregap2 = 1;
|
|
|
|
}
|
|
|
|
/* XXX HERE IS WHERE WE DO INDICES IN THE CUE SHEET */
|
|
|
|
/* XXX and we should make sure the gaps conform to ecma-130... */
|
|
|
|
tar[i]->entry = &e[3 + i];
|
|
|
|
e[3 + i].point = i + 1;
|
|
|
|
burn_lba_to_msf(runtime, &m, &s, &f);
|
|
|
|
e[3 + i].pmin = m;
|
|
|
|
e[3 + i].psec = s;
|
|
|
|
e[3 + i].pframe = f;
|
|
|
|
e[3 + i].adr = 1;
|
|
|
|
e[3 + i].control = type_to_ctrl(tar[i]->mode);
|
|
|
|
burn_print(1, "track %d control %d\n", tar[i]->mode,
|
|
|
|
e[3 + i].control);
|
2006-10-09 08:43:15 +00:00
|
|
|
|
|
|
|
ret = add_cue(sheet, ctladr | 1, i + 1, 1, form, 0, runtime);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
runtime += burn_track_get_sectors(tar[i]);
|
|
|
|
/* if we're padding, we'll clear any current shortage.
|
|
|
|
if we're not, we'll slip toc entries by a sector every time our
|
|
|
|
shortage is more than a sector
|
|
|
|
XXX this is untested :)
|
|
|
|
*/
|
|
|
|
if (!tar[i]->pad) {
|
|
|
|
rem += burn_track_get_shortage(tar[i]);
|
|
|
|
if (i +1 != ntr)
|
|
|
|
tar[i]->source->next = tar[i+1]->source;
|
|
|
|
} else if (rem) {
|
|
|
|
rem = 0;
|
|
|
|
runtime++;
|
|
|
|
}
|
|
|
|
if (rem > burn_sector_length(tar[i]->mode)) {
|
|
|
|
rem -= burn_sector_length(tar[i]->mode);
|
|
|
|
runtime--;
|
|
|
|
}
|
|
|
|
pform = form;
|
|
|
|
}
|
|
|
|
burn_lba_to_msf(runtime, &m, &s, &f);
|
|
|
|
e[2].pmin = m;
|
|
|
|
e[2].psec = s;
|
|
|
|
e[2].pframe = f;
|
|
|
|
burn_print(1, "run time is %d (%d:%d:%d)\n", runtime, m, s, f);
|
|
|
|
for (i = 0; i < d->toc_entries; i++)
|
|
|
|
burn_print(1, "point %d (%02d:%02d:%02d)\n",
|
|
|
|
d->toc_entry[i].point, d->toc_entry[i].pmin,
|
|
|
|
d->toc_entry[i].psec, d->toc_entry[i].pframe);
|
2006-10-09 08:43:15 +00:00
|
|
|
ret = add_cue(sheet, ctladr | 1, 0xAA, 1, 1, 0, runtime);
|
|
|
|
if (ret <= 0)
|
|
|
|
goto failed;
|
2006-08-15 20:37:04 +00:00
|
|
|
return sheet;
|
2006-10-09 08:43:15 +00:00
|
|
|
|
|
|
|
failed:;
|
|
|
|
if (sheet != NULL)
|
|
|
|
free((char *) sheet);
|
|
|
|
return NULL;
|
2006-08-15 20:37:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int burn_sector_length(int tracktype)
|
|
|
|
{
|
|
|
|
if (tracktype & BURN_AUDIO)
|
|
|
|
return 2352;
|
|
|
|
if (tracktype & BURN_MODE_RAW)
|
|
|
|
return 2352;
|
|
|
|
if (tracktype & BURN_MODE1)
|
|
|
|
return 2048;
|
2006-10-09 08:43:15 +00:00
|
|
|
/* ts A61009 */
|
|
|
|
/* a ssert(0); */
|
|
|
|
return -1;
|
2006-08-15 20:37:04 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
int burn_subcode_length(int tracktype)
|
|
|
|
{
|
|
|
|
if (tracktype & BURN_SUBCODE_P16)
|
|
|
|
return 16;
|
|
|
|
if ((tracktype & BURN_SUBCODE_P96) || (tracktype & BURN_SUBCODE_R96))
|
|
|
|
return 96;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int burn_write_leadin(struct burn_write_opts *o,
|
|
|
|
struct burn_session *s, int first)
|
|
|
|
{
|
|
|
|
struct burn_drive *d = o->drive;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
d->busy = BURN_DRIVE_WRITING_LEADIN;
|
|
|
|
|
|
|
|
burn_print(5, first ? " first leadin\n" : " leadin\n");
|
|
|
|
|
|
|
|
if (first)
|
|
|
|
count = 0 - d->alba - 150;
|
|
|
|
else
|
|
|
|
count = 4500;
|
|
|
|
|
|
|
|
d->progress.start_sector = d->alba;
|
|
|
|
d->progress.sectors = count;
|
|
|
|
d->progress.sector = 0;
|
|
|
|
|
|
|
|
while (count != 0) {
|
|
|
|
if (!sector_toc(o, s->track[0]->mode))
|
|
|
|
return 0;
|
|
|
|
count--;
|
|
|
|
d->progress.sector++;
|
|
|
|
}
|
|
|
|
d->busy = BURN_DRIVE_WRITING;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int burn_write_leadout(struct burn_write_opts *o,
|
|
|
|
int first, unsigned char control, int mode)
|
|
|
|
{
|
|
|
|
struct burn_drive *d = o->drive;
|
|
|
|
int count;
|
|
|
|
|
|
|
|
d->busy = BURN_DRIVE_WRITING_LEADOUT;
|
|
|
|
|
|
|
|
d->rlba = -150;
|
|
|
|
burn_print(5, first ? " first leadout\n" : " leadout\n");
|
|
|
|
if (first)
|
|
|
|
count = 6750;
|
|
|
|
else
|
|
|
|
count = 2250;
|
|
|
|
d->progress.start_sector = d->alba;
|
|
|
|
d->progress.sectors = count;
|
|
|
|
d->progress.sector = 0;
|
|
|
|
|
|
|
|
while (count != 0) {
|
|
|
|
if (!sector_lout(o, control, mode))
|
|
|
|
return 0;
|
|
|
|
count--;
|
|
|
|
d->progress.sector++;
|
|
|
|
}
|
|
|
|
d->busy = BURN_DRIVE_WRITING;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int burn_write_session(struct burn_write_opts *o, struct burn_session *s)
|
|
|
|
{
|
|
|
|
struct burn_drive *d = o->drive;
|
|
|
|
struct burn_track *prev = NULL, *next = NULL;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
d->rlba = 0;
|
|
|
|
burn_print(1, " writing a session\n");
|
|
|
|
for (i = 0; i < s->tracks; i++) {
|
|
|
|
if (i > 0)
|
|
|
|
prev = s->track[i - 1];
|
|
|
|
if (i + 1 < s->tracks)
|
|
|
|
next = s->track[i + 1];
|
|
|
|
else
|
|
|
|
next = NULL;
|
|
|
|
|
|
|
|
if (!burn_write_track(o, s, i))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int burn_write_track(struct burn_write_opts *o, struct burn_session *s,
|
|
|
|
int tnum)
|
|
|
|
{
|
|
|
|
struct burn_track *t = s->track[tnum];
|
|
|
|
struct burn_drive *d = o->drive;
|
2006-10-31 18:48:18 +00:00
|
|
|
int i, tmp = 0, open_ended = 0;
|
2006-08-15 20:37:04 +00:00
|
|
|
int sectors;
|
|
|
|
|
|
|
|
d->rlba = -150;
|
|
|
|
|
|
|
|
/* XXX for tao, we don't want the pregaps but still want post? */
|
|
|
|
if (o->write_type != BURN_WRITE_TAO) {
|
|
|
|
if (t->pregap1)
|
|
|
|
d->rlba += 75;
|
|
|
|
if (t->pregap2)
|
|
|
|
d->rlba += 150;
|
|
|
|
|
|
|
|
if (t->pregap1) {
|
|
|
|
struct burn_track *pt = s->track[tnum - 1];
|
|
|
|
|
|
|
|
if (tnum == 0) {
|
|
|
|
printf("first track should not have a pregap1\n");
|
|
|
|
pt = t;
|
|
|
|
}
|
|
|
|
for (i = 0; i < 75; i++)
|
|
|
|
if (!sector_pregap(o, t->entry->point,
|
|
|
|
pt->entry->control, pt->mode))
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (t->pregap2)
|
|
|
|
for (i = 0; i < 150; i++)
|
|
|
|
if (!sector_pregap(o, t->entry->point,
|
|
|
|
t->entry->control, t->mode))
|
|
|
|
return 0;
|
|
|
|
} else {
|
|
|
|
o->control = t->entry->control;
|
|
|
|
d->send_write_parameters(d, o);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* user data */
|
|
|
|
sectors = burn_track_get_sectors(t);
|
2006-10-31 18:48:18 +00:00
|
|
|
open_ended = burn_track_is_open_ended(t);
|
|
|
|
|
|
|
|
/* <<< ts A61031 */
|
|
|
|
fprintf(stderr, "libburn_experimental: sectors= %d , open_ended= %d\n",
|
|
|
|
sectors,open_ended);
|
2006-08-15 20:37:04 +00:00
|
|
|
|
|
|
|
/* Update progress */
|
|
|
|
d->progress.start_sector = d->nwa;
|
|
|
|
d->progress.sectors = sectors;
|
|
|
|
d->progress.sector = 0;
|
|
|
|
|
2006-09-01 10:52:01 +00:00
|
|
|
/* ts A60831: added tnum-line, extended print message on proposal
|
|
|
|
by bonfire-app@wanadoo.fr in http://libburn.pykix.org/ticket/58 */
|
|
|
|
d->progress.track = tnum;
|
2006-10-23 11:31:37 +00:00
|
|
|
|
2006-09-01 10:52:01 +00:00
|
|
|
burn_print(12, "track %d is %d sectors long\n", tnum, sectors);
|
2006-08-15 20:37:04 +00:00
|
|
|
|
2006-10-31 11:55:51 +00:00
|
|
|
/* ts A61030 : this cannot happen. tnum is alsways < s-tracks */
|
2006-08-15 20:37:04 +00:00
|
|
|
if (tnum == s->tracks)
|
|
|
|
tmp = sectors > 150 ? 150 : sectors;
|
|
|
|
|
2006-10-31 18:48:18 +00:00
|
|
|
for (i = 0; open_ended || i < sectors - tmp; i++) {
|
2006-10-23 11:31:37 +00:00
|
|
|
|
|
|
|
/* ts A61023 : http://libburn.pykix.org/ticket/14
|
|
|
|
From time to time inquire drive buffer */
|
|
|
|
if ((i%64)==0)
|
|
|
|
d->read_buffer_capacity(d);
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
if (!sector_data(o, t, 0))
|
|
|
|
return 0;
|
|
|
|
|
2006-10-31 18:48:18 +00:00
|
|
|
/* ts A61031 */
|
|
|
|
if (open_ended) {
|
|
|
|
d->progress.sectors = sectors = i;
|
|
|
|
if (burn_track_is_data_done(t))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
/* update current progress */
|
|
|
|
d->progress.sector++;
|
|
|
|
}
|
|
|
|
for (; i < sectors; i++) {
|
2006-10-31 11:55:51 +00:00
|
|
|
|
|
|
|
/* ts A61030: program execution never gets to this point */
|
|
|
|
fprintf(stderr,"LIBBURN_DEBUG: TNUM=%d TRACKS=%d TMP=%d\n",
|
|
|
|
tnum, s->tracks, tmp);
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
burn_print(1, "last track, leadout prep\n");
|
2006-10-23 11:31:37 +00:00
|
|
|
|
|
|
|
/* ts A61023 */
|
|
|
|
if ((i%64)==0)
|
|
|
|
d->read_buffer_capacity(d);
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
if (!sector_data(o, t, 1))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
/* update progress */
|
|
|
|
d->progress.sector++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t->postgap)
|
|
|
|
for (i = 0; i < 150; i++)
|
|
|
|
if (!sector_postgap(o, t->entry->point, t->entry->control,
|
|
|
|
t->mode))
|
|
|
|
return 0;
|
|
|
|
i = t->offset;
|
|
|
|
if (o->write_type == BURN_WRITE_SAO) {
|
|
|
|
if (d->buffer->bytes) {
|
|
|
|
int err;
|
|
|
|
err = d->write(d, d->nwa, d->buffer);
|
|
|
|
if (err == BE_CANCELLED)
|
|
|
|
return 0;
|
|
|
|
d->nwa += d->buffer->sectors;
|
|
|
|
d->buffer->bytes = 0;
|
|
|
|
d->buffer->sectors = 0;
|
|
|
|
}
|
|
|
|
}
|
2006-10-31 11:55:51 +00:00
|
|
|
if (o->write_type == BURN_WRITE_TAO) {
|
2006-08-15 20:37:04 +00:00
|
|
|
if (!burn_write_flush(o))
|
|
|
|
return 0;
|
2006-10-31 11:55:51 +00:00
|
|
|
|
|
|
|
/* ts A61030 */
|
|
|
|
if (burn_write_close_track(o, tnum) <= 0)
|
|
|
|
return 0;
|
|
|
|
}
|
2006-08-15 20:37:04 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
2006-10-10 11:26:46 +00:00
|
|
|
/* ts A61009 */
|
|
|
|
int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc)
|
|
|
|
{
|
|
|
|
int i, t;
|
|
|
|
char msg[80];
|
|
|
|
|
|
|
|
for (i = 0; i < disc->sessions; i++)
|
|
|
|
for (t = 0; t < disc->session[i]->tracks; t++)
|
|
|
|
if (!sector_headers_is_ok(
|
|
|
|
o, disc->session[i]->track[t]->mode))
|
|
|
|
goto bad_track_mode_found;
|
|
|
|
return 1;
|
|
|
|
bad_track_mode_found:;
|
|
|
|
sprintf(msg, "Unsuitable track mode 0x%x in track %d of session %d",
|
|
|
|
disc->session[i]->track[t]->mode, i+1, t+1);
|
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x0002010a,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
msg, 0, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
void burn_disc_write_sync(struct burn_write_opts *o, struct burn_disc *disc)
|
|
|
|
{
|
|
|
|
struct cue_sheet *sheet;
|
|
|
|
struct burn_drive *d = o->drive;
|
|
|
|
struct buffer buf;
|
|
|
|
struct burn_track *lt;
|
|
|
|
int first = 1, i;
|
|
|
|
int res;
|
2006-10-31 11:55:51 +00:00
|
|
|
char msg[80];
|
2006-08-15 20:37:04 +00:00
|
|
|
|
2006-09-24 20:25:54 +00:00
|
|
|
/* ts A60924 : libburn/message.c gets obsoleted
|
2006-08-15 20:37:04 +00:00
|
|
|
burn_message_clear_queue();
|
2006-09-24 20:25:54 +00:00
|
|
|
*/
|
2006-08-15 20:37:04 +00:00
|
|
|
|
|
|
|
burn_print(1, "sync write of %d sessions\n", disc->sessions);
|
|
|
|
d->buffer = &buf;
|
|
|
|
memset(d->buffer, 0, sizeof(struct buffer));
|
|
|
|
|
|
|
|
d->rlba = -150;
|
|
|
|
|
|
|
|
d->toc_temp = 9;
|
|
|
|
|
|
|
|
/* Apparently some drives require this command to be sent, and a few drives
|
|
|
|
return crap. so we send the command, then ignore the result.
|
|
|
|
*/
|
|
|
|
res = d->get_nwa(d);
|
2006-10-31 11:55:51 +00:00
|
|
|
|
|
|
|
/* >>> ts A61031 : one should not ignore the "crap" but find out
|
|
|
|
when and why it occurs. Multi-session will hardly
|
|
|
|
work on base of flat guessing.
|
|
|
|
*/
|
|
|
|
sprintf(msg, "Ignored nwa: %d\n", res);
|
|
|
|
libdax_msgs_submit(libdax_messenger, d->global_index, 0x00000002,
|
|
|
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
|
|
|
msg, 0, 0);
|
2006-08-15 20:37:04 +00:00
|
|
|
|
|
|
|
d->alba = d->start_lba;
|
|
|
|
d->nwa = d->alba;
|
|
|
|
|
|
|
|
if (o->write_type != BURN_WRITE_TAO)
|
|
|
|
d->send_write_parameters(d, o);
|
|
|
|
|
|
|
|
/* init progress before showing the state */
|
|
|
|
d->progress.session = 0;
|
|
|
|
d->progress.sessions = disc->sessions;
|
|
|
|
d->progress.track = 0;
|
|
|
|
d->progress.tracks = disc->session[0]->tracks;
|
|
|
|
/* TODO: handle indices */
|
|
|
|
d->progress.index = 0;
|
|
|
|
d->progress.indices = disc->session[0]->track[0]->indices;
|
|
|
|
/* TODO: handle multissession discs */
|
|
|
|
/* XXX: sectors are only set during write track */
|
|
|
|
d->progress.start_sector = 0;
|
|
|
|
d->progress.sectors = 0;
|
|
|
|
d->progress.sector = 0;
|
|
|
|
|
2006-10-23 11:31:37 +00:00
|
|
|
/* ts A61023 */
|
|
|
|
d->progress.buffer_capacity = 0;
|
|
|
|
d->progress.buffer_available = 0;
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
d->busy = BURN_DRIVE_WRITING;
|
|
|
|
|
|
|
|
for (i = 0; i < disc->sessions; i++) {
|
|
|
|
/* update progress */
|
|
|
|
d->progress.session = i;
|
|
|
|
d->progress.tracks = disc->session[i]->tracks;
|
|
|
|
|
|
|
|
sheet = burn_create_toc_entries(o, disc->session[i]);
|
2006-10-09 08:43:15 +00:00
|
|
|
|
|
|
|
/* ts A61009 */
|
|
|
|
if (sheet == NULL)
|
|
|
|
goto fail;
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
/* print_cue(sheet);*/
|
|
|
|
if (o->write_type == BURN_WRITE_SAO)
|
|
|
|
d->send_cue_sheet(d, sheet);
|
|
|
|
free(sheet);
|
|
|
|
|
|
|
|
if (o->write_type == BURN_WRITE_RAW) {
|
|
|
|
if (!burn_write_leadin(o, disc->session[i], first))
|
|
|
|
goto fail;
|
|
|
|
} else {
|
|
|
|
if (first) {
|
2006-10-31 11:55:51 +00:00
|
|
|
|
|
|
|
/* ts A61030 : this made the burner take data */
|
|
|
|
if(o->write_type == BURN_WRITE_TAO)
|
|
|
|
d->nwa= d->alba= 0;
|
|
|
|
else {
|
|
|
|
|
|
|
|
d->nwa = -150;
|
|
|
|
d->alba = -150;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
} else {
|
|
|
|
d->nwa += 4500;
|
|
|
|
d->alba += 4500;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!burn_write_session(o, disc->session[i]))
|
|
|
|
goto fail;
|
|
|
|
|
|
|
|
lt = disc->session[i]->track[disc->session[i]->tracks - 1];
|
|
|
|
if (o->write_type == BURN_WRITE_RAW) {
|
|
|
|
if (!burn_write_leadout(o, first, lt->entry->control,
|
|
|
|
lt->mode))
|
|
|
|
goto fail;
|
|
|
|
} else {
|
2006-10-31 11:55:51 +00:00
|
|
|
|
|
|
|
/* ts A61030 */
|
|
|
|
if (o->write_type == BURN_WRITE_TAO) {
|
|
|
|
if (burn_write_close_session(o) <= 0)
|
|
|
|
goto fail;
|
|
|
|
} else
|
|
|
|
|
|
|
|
if (!burn_write_flush(o))
|
|
|
|
goto fail;
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
d->nwa += first ? 6750 : 2250;
|
|
|
|
d->alba += first ? 6750 : 2250;
|
|
|
|
}
|
|
|
|
if (first)
|
|
|
|
first = 0;
|
|
|
|
|
|
|
|
/* XXX: currently signs an end of session */
|
|
|
|
d->progress.sector = 0;
|
|
|
|
d->progress.start_sector = 0;
|
|
|
|
d->progress.sectors = 0;
|
|
|
|
}
|
2006-10-31 11:55:51 +00:00
|
|
|
|
|
|
|
/* ts A61030: extended skipping of flush to TAO: session is closed */
|
|
|
|
if (o->write_type != BURN_WRITE_SAO && o->write_type != BURN_WRITE_TAO)
|
2006-08-15 20:37:04 +00:00
|
|
|
if (!burn_write_flush(o))
|
|
|
|
goto fail;
|
2006-10-31 11:55:51 +00:00
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
sleep(1);
|
|
|
|
|
|
|
|
burn_print(1, "done\n");
|
|
|
|
d->busy = BURN_DRIVE_IDLE;
|
|
|
|
|
2006-10-31 11:55:51 +00:00
|
|
|
/* ts A61012 : This return was traditionally missing. I suspect this
|
2006-10-13 11:46:07 +00:00
|
|
|
to have caused Cdrskin_eject() failures */
|
|
|
|
return;
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
fail:
|
|
|
|
d->sync_cache(d);
|
|
|
|
burn_print(1, "done - failed\n");
|
2006-10-10 11:26:46 +00:00
|
|
|
libdax_msgs_submit(libdax_messenger, d->global_index, 0x0002010b,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
"Burn run failed", 0, 0);
|
2006-08-15 20:37:04 +00:00
|
|
|
d->busy = BURN_DRIVE_IDLE;
|
|
|
|
}
|