write.c 72.2 KB
Newer Older
Mario Danic's avatar
Mario Danic committed
1 2
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */

3
/* Copyright (c) 2004 - 2006 Derek Foreman, Ben Jansens
4
   Copyright (c) 2006 - 2011 Thomas Schmitt <scdbackup@gmx.net>
5 6 7 8
   Provided under GPL version 2 or later.
*/


9 10 11 12
#ifdef HAVE_CONFIG_H
#include "../config.h"
#endif

Mario Danic's avatar
Mario Danic committed
13 14
#include <unistd.h>
#include <signal.h>
15 16 17 18 19

/* ts A61009 */
/* #include <a ssert.h> */


20 21 22 23 24 25
/* ts A61106 : Deliberate defect provocation macros
               DO NOT DEFINE THESE IF YOU WANT SUCCESSFUL TAO !
#define Libburn_experimental_no_close_tracK 1
#define Libburn_experimental_no_close_sessioN 1
*/

26 27 28 29 30
/* ts A61114 : Highly experimental : try to achieve SAO on appendables
               THIS DOES NOT WORK YET !
#define Libburn_sao_can_appenD 1
*/

31
#include <sys/types.h>
Mario Danic's avatar
Mario Danic committed
32 33 34 35
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
36 37 38
#include <fcntl.h>
#include <errno.h>
#include <sys/stat.h>
39
#include <sys/time.h>
40

Mario Danic's avatar
Mario Danic committed
41 42 43 44 45 46 47 48 49 50 51 52
#include "error.h"
#include "sector.h"
#include "libburn.h"
#include "drive.h"
#include "transport.h"
#include "debug.h"
#include "init.h"
#include "toc.h"
#include "util.h"
#include "sg.h"
#include "write.h"
#include "options.h"
53
#include "structure.h"
54
#include "source.h"
55 56
#include "mmc.h"
#include "spc.h"
Mario Danic's avatar
Mario Danic committed
57

58 59 60 61
#include "libdax_msgs.h"
extern struct libdax_msgs *libdax_messenger;


62 63 64 65 66 67
/* ts A91120 : <<< experimental */
#ifdef Libburn_mmap_write_buffeR
#include <sys/mman.h>
#endif


68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
/* The maximum output size to be used with CD media. This is also curbed
   by BURN_OS_TRANSPORT_BUFFER_SIZE. The smaller number gets into effect.
*/ 
#define Libburn_cd_obS (32 * 1024)

/* The size to be used with DVD media.
*/
#define Libburn_dvd_obS (32 * 1024)

/* The size to be used with BD-RE media in normal, not streamed mode.
*/
#define Libburn_bd_re_obS (32 * 1024)

/* The size to be used with BD-RE media in streamed mode.
*/
#define Libburn_bd_re_streamed_obS (64 * 1024)


Mario Danic's avatar
Mario Danic committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99
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
100 101 102
		/* ts A61008 */
		/* a ssert(0); */
		return -1;
Mario Danic's avatar
Mario Danic committed
103 104 105 106 107 108 109 110

	if (mode & BURN_COPY)
		ctrl |= 2;

	return ctrl;
}

/* only the ctrl nibble is set here (not adr) */
111 112 113
/* 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)
Mario Danic's avatar
Mario Danic committed
114
{
115 116 117 118 119 120 121 122 123
	int ret;

	ret = type_to_ctrl(mode) << 4;
	if (ret == -1) {
		*ctladr = 0xff;
		*form = -1;
		return;
	}
	*ctladr = ret;
Mario Danic's avatar
Mario Danic committed
124 125 126

	if (mode & BURN_AUDIO)
		*form = 0;
127 128 129 130 131 132 133 134
	if (mode & BURN_MODE0) {

		/* ts A61009 */
		/* a ssert(0); */
		*form = -1;
		return;
	}

Mario Danic's avatar
Mario Danic committed
135 136
	if (mode & BURN_MODE1)
		*form = 0x10;
137 138 139 140 141 142 143 144
	if (mode & BURN_MODE2) {

		/* ts A61009 */
		/* a ssert(0); */ /* XXX someone's gonna want this sometime */
		*form = -1;
		return;
	}

Mario Danic's avatar
Mario Danic committed
145 146 147 148 149 150 151 152 153 154
	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;
}

155 156 157

/* ts A71002 : outsourced from burn_write_flush() : no sync cache here */
int burn_write_flush_buffer(struct burn_write_opts *o,struct burn_track *track)
Mario Danic's avatar
Mario Danic committed
158 159 160 161 162 163 164 165
{
	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;
166
		/* A61101 */
167
		if(track != NULL) {
168
			track->writecount += d->buffer->bytes;
169 170
			track->written_sectors += d->buffer->sectors;
		}
171 172
		/* ts A61119 */
		d->progress.buffered_bytes += d->buffer->bytes;
173

Mario Danic's avatar
Mario Danic committed
174
		d->nwa += d->buffer->sectors;
175 176
		d->buffer->bytes = 0;
		d->buffer->sectors = 0;
Mario Danic's avatar
Mario Danic committed
177
	}
178 179 180 181 182 183 184 185 186
	return 1;
}


int burn_write_flush(struct burn_write_opts *o, struct burn_track *track)
{
	int ret;
	struct burn_drive *d = o->drive;

187
	ret = burn_write_flush_buffer(o, track);
188 189
	if (ret <= 0)
		return ret;
Mario Danic's avatar
Mario Danic committed
190 191 192 193
	d->sync_cache(d);
	return 1;
}

194

195 196
/* ts A71002 : outsourced from burn_write_close_track() */
int burn_write_track_minsize(struct burn_write_opts *o, struct burn_session *s,
197
				int tnum)
198 199
{
	char msg[81];
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232
	struct burn_drive *d;
	struct burn_track *t;
	int todo, step, cancelled, seclen;

	d = o->drive;
	t = s->track[tnum];

	/* ts A61103 : pad up track to minimum size of 600 sectors */
	if (t->written_sectors < 300) {
		todo = 300 - t->written_sectors;
		sprintf(msg,"Padding up track to minimum size (+ %d sectors)",
			todo);
		libdax_msgs_submit(libdax_messenger, o->drive->global_index,
			0x0002011a,
			LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);
		step = BUFFER_SIZE / 4096; /* shall fit any sector size */
		if (step <= 0)
			step = 1;
		seclen = burn_sector_length(t->mode);
		if (seclen <= 0)
			seclen = 2048;
		memset(d->buffer, 0, sizeof(struct buffer));
		cancelled = d->cancel;
		for (; todo > 0; todo -= step) {
			if (step > todo)
				step = todo;
			d->buffer->bytes = step*seclen;
			d->buffer->sectors = step;
			d->cancel = 0;
			d->write(d, d->nwa, d->buffer);
			d->nwa += d->buffer->sectors;
			t->writecount += d->buffer->bytes;
			t->written_sectors += d->buffer->sectors;
233
			d->progress.buffered_bytes += d->buffer->bytes;
234 235 236
		}
		d->cancel = cancelled;
	}
237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
	return 1;
}


/* ts A61030 */
int burn_write_close_track(struct burn_write_opts *o, struct burn_session *s,
				int tnum)
{
	char msg[81];
	struct burn_drive *d;
	struct burn_track *t;

	/* ts A61106 */
#ifdef Libburn_experimental_no_close_tracK
	return 1;
#endif

	d = o->drive;
	t = s->track[tnum];
256 257

	d->busy = BURN_DRIVE_CLOSING_TRACK;
258

259
	sprintf(msg, "Closing track %2.2d", tnum+1);
260 261 262 263 264 265
	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. */
266
	/* ts A70129 
267
	   Probably the right value for appendables is d->last_track_no
268 269
	*/
	d->close_track_session(o->drive, 0, 0xff);
270

271
	d->busy = BURN_DRIVE_WRITING;
272

273 274 275 276
	return 1;
}


277

278
/* ts A61030 */
279
int burn_write_close_session(struct burn_write_opts *o, struct burn_session *s)
280
{
281 282 283 284 285 286

	/* ts A61106 */
#ifdef Libburn_experimental_no_close_sessioN
	return 1;
#endif

287 288 289 290
	libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
			"Closing session", 0, 0);

291 292 293
	/* ts A61102 */
	o->drive->busy = BURN_DRIVE_CLOSING_SESSION;

294
	o->drive->close_track_session(o->drive, 1, 0);
295 296 297 298

	/* ts A61102 */
	o->drive->busy = BURN_DRIVE_WRITING;

299 300 301 302
	return 1;
}


303 304 305 306 307 308
/* 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

Mario Danic's avatar
Mario Danic committed
309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325
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]);
	}
}

326 327 328
#endif /* Libburn_write_with_print_cuE */


329 330 331
/* ts A61009 : changed type from void to int */
/** @return 1 = success , <=0 failure */
static int add_cue(struct cue_sheet *sheet, unsigned char ctladr,
Mario Danic's avatar
Mario Danic committed
332 333 334 335 336 337 338 339 340 341 342
		    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);
343 344 345 346 347 348 349 350 351 352 353

	/* 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;
	}

Mario Danic's avatar
Mario Danic committed
354 355 356 357 358 359 360 361 362 363
	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;
364
	return 1;
Mario Danic's avatar
Mario Danic committed
365 366
}

367
/* ts A61114: added parameter nwa */
Mario Danic's avatar
Mario Danic committed
368
struct cue_sheet *burn_create_toc_entries(struct burn_write_opts *o,
369 370
					  struct burn_session *session,
					  int nwa)
Mario Danic's avatar
Mario Danic committed
371
{
372
	int i, m, s, f, form, pform, runtime = -150, ret, track_length;
Mario Danic's avatar
Mario Danic committed
373 374 375 376 377 378 379 380 381 382
	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;

383 384 385 386 387
#ifdef Libburn_sao_can_appenD
	if (d->status == BURN_DISC_APPENDABLE)
 		runtime = nwa-150;
#endif

388
	sheet = calloc(1, sizeof(struct cue_sheet));
389

390
	/* ts A61009 : react on failures of calloc(), add_cue_sheet()
391 392 393 394 395 396 397 398 399
	               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;
	}

Mario Danic's avatar
Mario Danic committed
400 401 402
	sheet->data = NULL;
	sheet->count = 0;
	type_to_form(tar[0]->mode, &ctladr, &form);
403 404 405 406 407 408 409 410 411 412 413 414
	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;
Mario Danic's avatar
Mario Danic committed
415 416 417 418
	runtime += 150;

	burn_print(1, "toc for %d tracks:\n", ntr);
	d->toc_entries = ntr + 3;
419 420 421 422

	/* ts A61009 */
	/* a ssert(d->toc_entry == NULL); */
	if (d->toc_entry != NULL) {
423 424 425 426 427 428 429 430

		/* ts A61109 : this happens with appendable CDs 
			>>> Open question: is the existing TOC needed ? */

		/* ts A61109 : for non-SAO, this sheet is thrown away later */
		free((char *) d->toc_entry);

		/*
431 432 433 434 435
		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;
436
		*/
437 438
	}

439
	d->toc_entry = calloc(d->toc_entries, sizeof(struct burn_toc_entry));
Mario Danic's avatar
Mario Danic committed
440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
	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;

460 461 462 463 464
	/* ts A70121 : The pause before the first track is not a Pre-gap.
	   To count it as part 2 of a Pre-gap is a dirty hack. It also seems
	   to have caused confusion in dealing with part 1 of an eventual
	   real Pre-gap. mmc5r03c.pdf 6.33.3.2, 6.33.3.18 .
	*/
Mario Danic's avatar
Mario Danic committed
465
	tar[0]->pregap2 = 1;
466

Mario Danic's avatar
Mario Danic committed
467 468 469
	pform = form;
	for (i = 0; i < ntr; i++) {
		type_to_form(tar[i]->mode, &ctladr, &form);
470 471 472 473 474 475


		/* ts A70121 : This seems to be thw wrong test. Correct would
		   be to compare tar[]->mode or bit2 of ctladr.
		*/ 

Mario Danic's avatar
Mario Danic committed
476
		if (pform != form) {
477 478 479 480 481 482

			ret = add_cue(sheet, ctladr | 1, i + 1, 0, form, 0,
					 runtime);
			if (ret <= 0)
				goto failed;

Mario Danic's avatar
Mario Danic committed
483 484
			runtime += 150;
/* XXX fix pregap interval 1 for data tracks */
485 486 487 488 489 490
/* 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;
*/
491 492 493 494 495 496 497 498 499 500 501
/* ts A70121 : it is unclear why (form & BURN_AUDIO) should prevent pregap1.
   I believe, correct would be:
			runtime += 75;
			tar[i]->pregap1 = 1;

   The test for pform != form is wrong anyway. 

   Next one has to care for Post-gap: table 555 in mmc5r03c.pdf does not
   show any although 6.33.3.19 would prescribe some.

   Nobody seems to have ever tested this situation, up to now.
502 503
   It is banned for now in burn_disc_write().
   Warning have been placed in libburn.h .
504 505
*/

Mario Danic's avatar
Mario Danic committed
506 507 508 509 510 511 512 513 514 515 516 517 518 519
			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);
520 521 522 523 524

		ret = add_cue(sheet, ctladr | 1, i + 1, 1, form, 0, runtime);
		if (ret <= 0)
			goto failed;

525 526 527 528 529 530
		/* ts A70125 : 
		   Still not understanding the sense behind linking tracks,
		   i decided to at least enforce the MMC specs' minimum
		   track length.
		*/ 
		track_length = burn_track_get_sectors(tar[i]);
531
		if (track_length < 300 && !burn_track_is_open_ended(tar[i])) {
532 533 534 535 536 537 538
			track_length = 300;
			if (!tar[i]->pad)
				tar[i]->pad = 1;
			burn_track_set_sectors(tar[i], track_length);
		}
		runtime += track_length;

Mario Danic's avatar
Mario Danic committed
539 540 541 542 543 544 545
/* 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]);
546 547 548 549 550 551 552 553 554 555 556

			/* ts A61101 : I doubt that linking would yield a
					desireable effect. With TAO it is
					counterproductive in any way.
			*/
			if (o->write_type == BURN_WRITE_TAO)
				tar[i]->source->next = NULL;
			else

				if (i +1 != ntr)
					tar[i]->source->next = tar[i+1]->source;
Mario Danic's avatar
Mario Danic committed
557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
		} 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);
576 577 578
	ret = add_cue(sheet, ctladr | 1, 0xAA, 1, 1, 0, runtime);
	if (ret <= 0)
		goto failed;
Mario Danic's avatar
Mario Danic committed
579
	return sheet;
580 581 582 583 584

failed:;
	if (sheet != NULL)
		free((char *) sheet);
	return NULL;
Mario Danic's avatar
Mario Danic committed
585 586 587 588 589 590 591 592 593 594
}

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;
595 596 597
	/* ts A61009 */
	/* a ssert(0); */
	return -1;
Mario Danic's avatar
Mario Danic committed
598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669
}

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;
670
	int i, ret;
Mario Danic's avatar
Mario Danic committed
671 672 673 674 675 676 677 678 679 680 681 682

	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))
683
			{ ret = 0; goto ex; }
Mario Danic's avatar
Mario Danic committed
684
	}
685 686 687 688 689 690 691

	/* ts A61103 */
	ret = 1;
ex:;
	if (o->write_type == BURN_WRITE_TAO)
		burn_write_close_session(o, s);
	return ret;
Mario Danic's avatar
Mario Danic committed
692 693
}

694 695 696

/* ts A61218 : outsourced from burn_write_track() */
int burn_disc_init_track_status(struct burn_write_opts *o,
697
				struct burn_session *s, int tnum, int sectors)
698 699 700 701 702 703 704 705 706 707 708 709
{
	struct burn_drive *d = o->drive;

	/* Update progress */
	d->progress.start_sector = d->nwa;
	d->progress.sectors = sectors;
	d->progress.sector = 0;

	/* 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;

710 711 712
	/* ts A61102 */
	d->busy = BURN_DRIVE_WRITING;

713 714 715 716
	return 1;
}


Mario Danic's avatar
Mario Danic committed
717 718 719 720 721
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;
722
	int i, tmp = 0, open_ended = 0, ret= 0, nwa, lba;
Mario Danic's avatar
Mario Danic committed
723
	int sectors;
724
	char msg[80];
Mario Danic's avatar
Mario Danic committed
725 726 727 728 729

	d->rlba = -150;

/* XXX for tao, we don't want the pregaps  but still want post? */
	if (o->write_type != BURN_WRITE_TAO) {
730 731 732 733

		/* ts A61102 */
		d->busy = BURN_DRIVE_WRITING_PREGAP;

Mario Danic's avatar
Mario Danic committed
734 735 736 737 738 739
		if (t->pregap1)
			d->rlba += 75;
		if (t->pregap2)
			d->rlba += 150;

		if (t->pregap1) {
740 741 742 743 744

			struct burn_track *pt;
			/* ts A70121 : Removed pseudo suicidal initializer 
				 = s->track[tnum - 1];
			*/
Mario Danic's avatar
Mario Danic committed
745 746

			if (tnum == 0) {
747 748 749

				/* ts A70121 : This is not possible because
				   track 1 cannot have a pregap at all.
750
				   MMC-5 6.33.3.2 precribes a mandatory pause
751 752 753 754 755 756
				   prior to any track 1. Pre-gap is prescribed
				   for mode changes like audio-to-data.
				   To set burn_track.pregap1 for track 1 is
				   kindof a dirty hack.
				*/

Mario Danic's avatar
Mario Danic committed
757 758
				printf("first track should not have a pregap1\n");
				pt = t;
759 760
			} else
				pt = s->track[tnum - 1]; /* ts A70121 */
Mario Danic's avatar
Mario Danic committed
761 762 763
			for (i = 0; i < 75; i++)
				if (!sector_pregap(o, t->entry->point,
					           pt->entry->control, pt->mode))
764
					{ ret = 0; goto ex; }
Mario Danic's avatar
Mario Danic committed
765 766 767 768 769
		}
		if (t->pregap2)
			for (i = 0; i < 150; i++)
				if (!sector_pregap(o, t->entry->point,
					           t->entry->control, t->mode))
770
					{ ret = 0; goto ex; }
Mario Danic's avatar
Mario Danic committed
771 772 773
	} else {
		o->control = t->entry->control;
		d->send_write_parameters(d, o);
774

775
		/* ts A61103 */
776
		ret = d->get_nwa(d, -1, &lba, &nwa);
777 778 779 780 781

		/* ts A70213: CD-TAO: eventually expand size of track to max */
		burn_track_apply_fillup(t, d->media_capacity_remaining, 0);

		/* <<< */
782
		sprintf(msg, 
783 784 785
	"TAO pre-track %2.2d : get_nwa(%d)=%d, d=%d , demand=%.f , cap=%.f\n",
	tnum+1, nwa, ret, d->nwa, (double) burn_track_get_sectors(t) * 2048.0,
	(double) d->media_capacity_remaining);
786 787
		libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002,
				LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
788
				msg, 0, 0);
789 790 791 792 793 794 795 796 797 798 799 800

		/* ts A91003 */
		if (nwa < d->nwa) {
			libdax_msgs_submit(libdax_messenger, d->global_index,
				0x00020173,
				LIBDAX_MSGS_SEV_FAILURE, LIBDAX_MSGS_PRIO_HIGH,
			   "Drive tells NWA smaller than last written address",
				0, 0);
			d->sync_cache(d);
			return 0;
		}
		d->nwa = nwa;
801

Mario Danic's avatar
Mario Danic committed
802 803 804
	}

/* user data */
805

Mario Danic's avatar
Mario Danic committed
806
	sectors = burn_track_get_sectors(t);
807 808
	open_ended = burn_track_is_open_ended(t);

809
	burn_disc_init_track_status(o, s, tnum, sectors);
810

811
        burn_print(12, "track %d is %d sectors long\n", tnum, sectors);
Mario Danic's avatar
Mario Danic committed
812

813
	/* ts A61030 : this cannot happen. tnum is always < s->tracks */
Mario Danic's avatar
Mario Danic committed
814 815 816
	if (tnum == s->tracks)
		tmp = sectors > 150 ? 150 : sectors;

817
	for (i = 0; open_ended || i < sectors - tmp; i++) {
818 819 820 821 822 823

		/* ts A61023 : http://libburn.pykix.org/ticket/14
                               From time to time inquire drive buffer */
		if ((i%64)==0)
			d->read_buffer_capacity(d);

Mario Danic's avatar
Mario Danic committed
824
		if (!sector_data(o, t, 0))
825
			{ ret = 0; goto ex; }
Mario Danic's avatar
Mario Danic committed
826

827 828 829 830 831 832 833
		/* ts A61031 */
		if (open_ended) {
			d->progress.sectors = sectors = i;
                        if (burn_track_is_data_done(t)) 
	break;
		}

Mario Danic's avatar
Mario Danic committed
834 835 836 837
		/* update current progress */
		d->progress.sector++;
	}
	for (; i < sectors; i++) {
838 839 840 841 842

		/* ts A61030: program execution never gets to this point */
		fprintf(stderr,"LIBBURN_DEBUG: TNUM=%d  TRACKS=%d  TMP=%d\n",
			tnum, s->tracks, tmp);

Mario Danic's avatar
Mario Danic committed
843
		burn_print(1, "last track, leadout prep\n");
844 845 846 847 848

		/* ts A61023 */
		if ((i%64)==0)
			d->read_buffer_capacity(d);

Mario Danic's avatar
Mario Danic committed
849
		if (!sector_data(o, t, 1))
850
			{ ret = 0; goto ex; }
Mario Danic's avatar
Mario Danic committed
851 852 853 854 855 856 857 858 859

		/* 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))
860
				{ ret = 0; goto ex; }
Mario Danic's avatar
Mario Danic committed
861 862 863 864 865 866
	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)
867
				{ ret = 0; goto ex; }
868

869 870 871
			/* A61101 : probably this is not all payload data */
			/* A61108 : but audio count is short without this */
			t->writecount += d->buffer->bytes;
872 873
			t->written_sectors += d->buffer->sectors;
			d->progress.buffered_bytes += d->buffer->bytes;
874

Mario Danic's avatar
Mario Danic committed
875 876 877 878 879
			d->nwa += d->buffer->sectors;
			d->buffer->bytes = 0;
			d->buffer->sectors = 0;
		}
	}
880 881 882 883

	/* ts A61103 */
	ret = 1;
ex:;
884 885
	if (d->cancel)
		burn_source_cancel(t->source);
886
	if (o->write_type == BURN_WRITE_TAO) {
887

888 889
		/* ts A71002 */
		if (!burn_write_flush_buffer(o, t))
890
			ret = 0;
891

892 893 894 895
		/* Ensure that at least 600 kB get written */
		burn_write_track_minsize(o, s, tnum);
		d->sync_cache(d);

896
		/* ts A61030 */
897 898 899 900 901
		/* ts A91003 :
		   At least in simulation mode this causes NWA=0 for the
		   next track. cdrecord does not use CLOSE TRACK at all but
		   ends the tracks by SYNCHRONIZE CACHE alone.
		*/
902 903 904 905 906 907 908 909
		/* ts A91202 :
		   Peng Shao reports that his LG GH22LS30 issues an SCSI error
		   on CLOSE TRACK even in non-dummy mode. So i better give up
		   this gesture which seems not be needed by any drive.
			if (!o->simulate)
				if (burn_write_close_track(o, s, tnum) <= 0)
					ret = 0;
		*/
910
	}
911
	return ret;
Mario Danic's avatar
Mario Danic committed
912 913
}

914
/* ts A61009 */
915 916 917
/* @param flag bit1 = do not libdax_msgs_submit() */
int burn_disc_write_is_ok(struct burn_write_opts *o, struct burn_disc *disc,
			int flag)
918 919 920 921 922 923
{
	int i, t;
	char msg[80];

	for (i = 0; i < disc->sessions; i++)
		for (t = 0; t < disc->session[i]->tracks; t++)
924 925
			if (sector_headers_is_ok(
				o, disc->session[i]->track[t]->mode) != 1)
926 927 928 929 930
				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);
931 932 933 934
	if (!(flag & 2))
		libdax_msgs_submit(libdax_messenger, -1, 0x0002010a,
				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
				msg, 0, 0);
935 936 937
	return 0;
}

938 939 940 941 942 943

/* ts A61218 : outsourced from burn_disc_write_sync() */
int burn_disc_init_write_status(struct burn_write_opts *o,
				struct burn_disc *disc)
{
	struct burn_drive *d = o->drive;
944 945
	struct burn_track *t = NULL;
	int sx, tx;
946

947 948
	d->cancel = 0;

949 950
#ifdef Libburn_reset_progress_asynC
	/* <<< This is now done in async.c */
951 952 953 954 955 956 957 958 959 960 961 962 963
	/* 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;
964
	d->progress.track = 0;
965
#endif /* Libburn_reset_progress_asynC */
966 967 968 969 970 971 972

	/* ts A61023 */
	d->progress.buffer_capacity = 0;
	d->progress.buffer_available = 0;
	d->progress.buffered_bytes = 0;
	d->progress.buffer_min_fill = 0xffffffff;

973 974 975 976 977 978 979 980
	/* ts A70711 */
	d->pessimistic_buffer_free = 0;
	d->pbf_altered = 0;
	d->pessimistic_writes = 0;
	d->waited_writes = 0;
	d->waited_tries = 0;
	d->waited_usec = 0;

981 982 983 984 985 986 987 988 989
	/* Set eventual media fill up for last track only */
	for (sx = 0; sx < disc->sessions; sx++)
		for (tx = 0 ; tx < disc->session[sx]->tracks; tx++) {
			t = disc->session[sx]->track[tx];
			burn_track_set_fillup(t, 0);
		}
	if (o->fill_up_media && t != NULL)
		burn_track_set_fillup(t, 1);

990 991 992 993 994 995
	d->busy = BURN_DRIVE_WRITING;

	return 1;
}


996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007
/* ts A70219 : API */
int burn_precheck_write(struct burn_write_opts *o, struct burn_disc *disc,
				 char reasons[BURN_REASONS_LEN], int silent)
{
	enum burn_write_types wt;
	struct burn_drive *d = o->drive;
	char msg[160], *reason_pt;
	int no_media = 0;

	reason_pt= reasons;
	reasons[0] = 0;

1008 1009 1010 1011 1012 1013 1014
	if (d->drive_role == 0) {
		sprintf(reasons,
			 "DRIVE: is a virtual placeholder (null-drive)");
		no_media = 1;
		goto ex;
	}

1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026
	/* check write mode against write job */
	wt = burn_write_opts_auto_write_type(o, disc, reasons, 1);
	if (wt == BURN_WRITE_NONE) {
		if (strncmp(reasons, "MEDIA: ", 7)==0)
			no_media = 1;
		goto ex;
	}

	sprintf(reasons, "%s: ", d->current_profile_text);
	reason_pt= reasons + strlen(reasons);
	if (d->status == BURN_DISC_UNSUITABLE)
		goto unsuitable_profile;
1027
	if (d->drive_role == 2 ||
1028 1029 1030
		d->current_profile == 0x1a || d->current_profile == 0x12 ||
		d->current_profile == 0x43) { 
		/* DVD+RW , DVD-RAM , BD-RE, emulated drive on stdio file */
1031 1032 1033 1034 1035
		if (o->start_byte >= 0 && (o->start_byte % 2048))
			strcat(reasons,
			 "write start address not properly aligned to 2048, ");
	} else if (d->current_profile == 0x09 || d->current_profile == 0x0a) {
		/* CD-R , CD-RW */
1036 1037 1038 1039 1040 1041 1042 1043 1044
		if (!burn_disc_write_is_ok(o, disc, (!!silent) << 1))
			strcat(reasons, "unsuitable track mode found, ");
		if (o->start_byte >= 0)
			strcat(reasons, "write start address not supported, ");
	} else if (d->current_profile == 0x13) {
		/* DVD-RW Restricted Overwrite */
		if (o->start_byte >= 0 && (o->start_byte % 32768))
			strcat(reasons,
			  "write start address not properly aligned to 32k, ");
1045 1046
	} else if (d->drive_role == 3 ||
		   d->current_profile == 0x11 || d->current_profile == 0x14 ||
1047
	           d->current_profile == 0x15 ||
1048 1049 1050 1051
	           d->current_profile == 0x1b || d->current_profile == 0x2b ||
		   d->current_profile == 0x41) {
		/* DVD-R* Sequential , DVD+R[/DL] , BD-R,
		   sequential stdio "drive" */
1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086
		if (o->start_byte >= 0)
			strcat(reasons, "write start address not supported, ");
	} else {
unsuitable_profile:;
		sprintf(msg, "Unsuitable media detected. Profile %4.4Xh  %s",
			d->current_profile, d->current_profile_text);
		if (!silent)
			libdax_msgs_submit(libdax_messenger, d->global_index,
				0x0002011e,
				LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
				msg, 0, 0);
		strcat(reasons, "no suitable media profile detected, ");
		return 0;
	}
ex:;
	if (reason_pt[0]) {
		if (no_media) {
			if (!silent)
				libdax_msgs_submit(libdax_messenger,
				  d->global_index, 0x0002013a,
				  LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
				  "No suitable media detected", 0, 0);
			return -1;
		}
		if (!silent)
			libdax_msgs_submit(libdax_messenger,
				  d->global_index, 0x00020139,
				  LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
				  "Write job parameters are unsuitable", 0, 0);
		return 0;
	}
	return 1;
}


1087
/* ts A70129 : learned much from dvd+rw-tools-7.0/growisofs_mmc.cpp */
1088 1089
int burn_disc_open_track_dvd_minus_r(struct burn_write_opts *o,
					struct burn_session *s, int tnum)
1090 1091 1092 1093
{
	struct burn_drive *d = o->drive;
	char msg[160];
	int ret, lba, nwa;
1094
	off_t size;
1095 1096 1097 1098

	d->send_write_parameters(d, o);
	ret = d->get_nwa(d, -1, &lba, &nwa);
	sprintf(msg, 
1099
		"DVD pre-track %2.2d : get_nwa(%d), ret= %d , d->nwa= %d",
1100
		tnum+1, nwa, ret, d->nwa);
1101 1102
	libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002,
			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, msg,0,0);
1103 1104
	if (nwa > d->nwa)
		d->nwa = nwa;
1105 1106
	/* ts A70214 : eventually adjust already expanded size of track */
	burn_track_apply_fillup(s->track[tnum], d->media_capacity_remaining,1);
1107

1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118
#ifdef Libburn_pioneer_dvr_216d_with_opC
	fprintf(stderr, "libburn_DEBUG: Libburn_pioneer_dvr_216d_with_opC : num_opc_tables = %d\n", d->num_opc_tables);
	if (d->num_opc_tables <= 0 && !o->simulate) {
		fprintf(stderr, "libburn_DEBUG: Libburn_pioneer_dvr_216d_with_opC : performing OPC\n");
		d->perform_opc(d);
		fprintf(stderr, "libburn_DEBUG: Libburn_pioneer_dvr_216d_with_opC : done\n");
	}
#endif

#ifdef Libburn_pioneer_dvr_216d_get_evenT
	mmc_get_event(d);
1119 1120
#endif

1121
	if (o->write_type == BURN_WRITE_SAO) { /* DAO */
1122
 		/* Round track size up to write chunk size and reserve track */
1123 1124
		size = ((off_t) burn_track_get_sectors(s->track[tnum]))
			* (off_t) 2048;
1125 1126
		if (size % o->obs)
			size += (off_t) (o->obs - (size % o->obs));
1127 1128 1129 1130 1131 1132 1133
		ret = d->reserve_track(d, size);
		if (ret <= 0) {
			sprintf(msg, "Cannot reserve track of %.f bytes",
				(double) size);
			libdax_msgs_submit(libdax_messenger, d->global_index,
				0x00020138,
				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
1134
				msg, 0, 0);
1135 1136 1137
			return 0;
		}
	}
1138 1139 1140 1141
	return 1;
}


1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161
/* ts A70226 */
int burn_disc_open_track_dvd_plus_r(struct burn_write_opts *o,
					struct burn_session *s, int tnum)
{
	struct burn_drive *d = o->drive;
	char msg[160];
	int ret, lba, nwa;
	off_t size;

	ret = d->get_nwa(d, -1, &lba, &nwa);
	sprintf(msg, 
		"DVD+R pre-track %2.2d : get_nwa(%d), ret= %d , d->nwa= %d",
		tnum+1, nwa, ret, d->nwa);
	libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002,
			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO, msg,0,0);
	if (nwa > d->nwa)
		d->nwa = nwa;
	/* ts A70214 : eventually adjust already expanded size of track */
	burn_track_apply_fillup(s->track[tnum], d->media_capacity_remaining,1);

1162 1163
	if (o->write_type == BURN_WRITE_SAO &&
	    ! burn_track_is_open_ended(s->track[tnum])) {
1164
 		/* Round track size up to write chunk size and reserve track */
1165 1166
		size = ((off_t) burn_track_get_sectors(s->track[tnum]))
			* (off_t) 2048;
1167 1168
		if (size % o->obs)
			size += (off_t) (o->obs - (size % o->obs));
1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183
		ret = d->reserve_track(d, size);
		if (ret <= 0) {
			sprintf(msg, "Cannot reserve track of %.f bytes",
				(double) size);
			libdax_msgs_submit(libdax_messenger, d->global_index,
				0x00020138,
				LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
				msg, 0, 0);
			return 0;
		}
	}
	return 1;
}


1184 1185 1186 1187 1188
/* ts A70129 */
int burn_disc_close_track_dvd_minus_r(struct burn_write_opts *o,
					struct burn_session *s, int tnum)
{
	struct burn_drive *d = o->drive;
1189
	char msg[80];
1190

1191 1192
	/* only with Incremental writing */
	if (o->write_type != BURN_WRITE_TAO)
1193 1194
		return 2;

1195 1196 1197 1198 1199
	sprintf(msg, "Closing track %2.2d  (absolute track number %d)",
		tnum + 1, d->last_track_no);
	libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);

1200
	d->busy = BURN_DRIVE_CLOSING_SESSION;
1201 1202
	/* Ignoring tnum here and hoping that d->last_track_no is correct */
	d->close_track_session(d, 0, d->last_track_no); /* CLOSE TRACK, 001b */
1203
	d->busy = BURN_DRIVE_WRITING;
1204
	d->last_track_no++;
1205 1206 1207 1208
	return 1;
}


1209 1210 1211 1212
/* ts A70229 */
int burn_disc_finalize_dvd_plus_r(struct burn_write_opts *o)
{
	struct burn_drive *d = o->drive;
1213
	char msg[80];
1214

1215 1216
	sprintf(msg, "Finalizing %s ...",
		d->current_profile_text);
1217 1218 1219
	libdax_msgs_submit(libdax_messenger, d->global_index,
			0x00000002,
			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
1220
			msg, 0, 0);
1221

1222 1223 1224 1225 1226 1227 1228
	if(d->current_profile == 0x41) { /* BD-R */
		/* CLOSE SESSION, 110b, Finalize Disc */
		d->close_track_session(d, 3, 0);  /* (3<<1)|0 = 6 */
	} else {
		/* CLOSE SESSION, 101b, Finalize with minimal radius */
		d->close_track_session(d, 2, 1);  /* (2<<1)|1 = 5 */
	}
1229

1230 1231
	sprintf(msg, "... finalizing %s done               ",
		d->current_profile_text);
1232 1233 1234
	libdax_msgs_submit(libdax_messenger, d->global_index,
			0x00000002,
			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
1235
			msg, 0, 0);
1236 1237 1238 1239 1240

	return 1;
}


1241 1242
/* ts A70226 */
int burn_disc_close_track_dvd_plus_r(struct burn_write_opts *o,
1243
			struct burn_session *s, int tnum, int is_last_track)
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
{
	struct burn_drive *d = o->drive;
	char msg[80];

	sprintf(msg,
		"Closing track %2.2d  (absolute track and session number %d)",
		tnum + 1, d->last_track_no);
	libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH, msg,0,0);

	d->busy = BURN_DRIVE_CLOSING_SESSION;
	d->close_track_session(d, 0, d->last_track_no); /* CLOSE TRACK, 001b */
1256 1257 1258 1259

	/* Each session becomes a single logical track. So to distinguish them,
	   it is mandatory to close the session together with each track. */

1260 1261 1262 1263
	if (is_last_track && !o->multi) 
		burn_disc_finalize_dvd_plus_r(o);
	else
 		d->close_track_session(d, 1, 0); /* CLOSE SESSION, 010b */
1264 1265 1266 1267 1268 1269
	d->busy = BURN_DRIVE_WRITING;
	d->last_track_no++;
	return 1;
}


1270 1271 1272 1273 1274 1275 1276 1277
/* <<<
#define Libburn_simplified_dvd_chunk_transactioN 1
*/

#ifdef Libburn_simplified_dvd_chunk_transactioN

/* ts A91114 : EXPERIMENTAL, NOT COMPLETELY IMPLEMENTED

1278 1279
   Simplified data transmission for DVD. libburn via GNU/Linux USB is 30 %
   slower than growisofs or cdrecord when transmitting 32 KB chunks.
1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299
   With 64 KB chunks it is 20% faster than the competitors.
   No heavy CPU load is visible but there might be subtle race conditions in
   the USB driver which work better with shorter time gaps between WRITE
   commands.

   Insight: It is actually about the interference of track source reading
            with SCSI writing via USB. growisofs reads with O_DIRECT into a
            mmap()ed buffer. When doing the same, libburn with 32 KB chunks
            reaches similar write speed.
            On the other hand, 64 KB chunks are 20% faster than that and
            are not improved by reading O_DIRECT.

            O_DIRECT is a property of the input fd of struct burn_source.
            It can only be done with properly aligned memory and with aligned
            read size. Alignment size is file system system specific.
            System call
                mmap(NULL, (size_t) buffer_size, PROT_READ | PROT_WRITE,
                     MAP_SHARED | MAP_ANONYMOUS, -1, (off_t) 0);
            is supposed to allocate a properly aligned buffer.
            64 KB is supposed to be a safe size.
1300 1301 1302 1303 1304 1305
            Actually mmap() seems to be the main cause for a positive effect
            of O_DIRECT.

   This simplified transmission function did not bring visible benefit.
   So for now it is not worth to teach it all applicable details of old
   CD sector oriented transmission.
1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318

   @return 1= ok, go on , 2= no input with track->open_ended = nothing written
           <= 0 = error
*/
static int transact_dvd_chunk(struct burn_write_opts *opts,
				 struct burn_track *track)
{
	int curr = 0, valid, err;
	struct burn_drive *d = opts->drive;
        struct buffer *out = d->buffer;
	unsigned char *data = out->data;

#ifdef Libburn_log_in_and_out_streaM
1319
	/* ts A61031 */
1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395
	static int tee_fd= -1;
	if(tee_fd==-1)
		tee_fd= open("/tmp/libburn_sg_readin",
				O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
#endif /* Libburn_log_in_and_out_streaM */


	/* Read a chunk full of data */

	/* ??? Do we have offset padding ? >>> First produce offset padding */;

	/*  <<<< */
	if (0 && !track->eos) {
		for (curr = 0; curr < opts->obs; curr += 2048) {
			if (track->source->read != NULL)
				valid = track->source->read(track->source,
						data + curr, 2048);
			else
				valid = track->source->read_xt(track->source,
						data + curr, 2048);
			if (valid <= 0) {
				track->eos = 1;
		break;
			}
			track->sourcecount += valid;

#ifdef Libburn_log_in_and_out_streaM
			if(tee_fd!=-1 && valid>0) {
				write(tee_fd, data + curr, valid);
			}
#endif /* Libburn_log_in_and_out_streaM */

		}
	} else if (!track->eos){
		valid = track->source->read(track->source, data, opts->obs);
		if (valid <= 0) {
			track->eos = 1;
		} else {
			track->sourcecount += valid;
			curr = valid;

#ifdef Libburn_log_in_and_out_streaM
			if(tee_fd!=-1 && valid>0) {
				write(tee_fd, data, valid);
			}
#endif /* Libburn_log_in_and_out_streaM */
		}
	}
	if (curr == 0 && track->open_ended) {

		/* >>> allow tail padding */;

		return 2;
	}
	if (curr < opts->obs)
		memset(data + curr , 0, opts->obs - curr);

	/* Write chunk */
	out->bytes = opts->obs;
	out->sectors = out->bytes / 2048;
	err = d->write(d, d->nwa, out);
	if (err == BE_CANCELLED)
		return 0;
	track->writecount += out->bytes;
	track->written_sectors += out->sectors;
	d->progress.buffered_bytes += out->bytes;
	d->nwa += out->sectors;
	out->bytes = 0;
	out->sectors = 0;

	return 1;
}

#endif /* Libburn_simplified_dvd_chunk_transactioN */


1396
/* ts A61218 - A81208 */
1397
int burn_dvd_write_track(struct burn_write_opts *o,
1398
			struct burn_session *s, int tnum, int is_last_track)
1399 1400 1401 1402 1403
{
	struct burn_track *t = s->track[tnum];
	struct burn_drive *d = o->drive;
	struct buffer *out = d->buffer;
	int sectors;
1404
	int i, open_ended = 0, ret= 0, is_flushed = 0;
1405
	int first_buf_cap = 0, further_cap = 0, buf_cap_step = 1024;
1406

1407 1408 1409
	/* ts A70213 : eventually expand size of track to max */
	burn_track_apply_fillup(t, d->media_capacity_remaining, 0);

1410 1411 1412
	if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
	    d->current_profile == 0x15) {
		/* DVD-R, DVD-RW Sequential, DVD-R/DL Sequential */
1413 1414 1415
		ret = burn_disc_open_track_dvd_minus_r(o, s, tnum);
		if (ret <= 0)
			goto ex;
1416 1417 1418 1419 1420
		/* Pioneer DVR-216D rev 1.09 hates multiple buffer inquiries
		   before the drive buffer is full.
		*/
		first_buf_cap = 0;
		further_cap = -1;
1421 1422 1423 1424 1425
	} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
		/* DVD+R , DVD+R/DL */
		ret = burn_disc_open_track_dvd_plus_r(o, s, tnum);
		if (ret <= 0)
			goto ex;
1426 1427 1428 1429 1430
	} else if (d->current_profile == 0x41) {
		/* BD-R SRM */
		ret = burn_disc_open_track_dvd_plus_r(o, s, tnum);
		if (ret <= 0)
			goto ex;
1431 1432 1433 1434
	}

	sectors = burn_track_get_sectors(t);
	open_ended = burn_track_is_open_ended(t);
1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445
	/* <<< */
	{
		char msg[160];

		sprintf(msg,
		 "DVD pre-track %2.2d : demand=%.f%s, cap=%.f\n",
			tnum+1, (double) sectors * 2048.0,
			(open_ended ? " (open ended)" : ""),
			(double) d->media_capacity_remaining);
		libdax_msgs_submit(libdax_messenger, d->global_index, 0x000002,
				LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
1446
				msg, 0, 0);
1447 1448
	}

1449

1450
	/* (offset padding is done within sector_data()) */
1451

1452
	burn_disc_init_track_status(o, s, tnum, sectors);
1453 1454 1455
	for (i = 0; open_ended || i < sectors; i++) {

		/* From time to time inquire drive buffer */
1456 1457 1458 1459
		/* ts A91110: Eventually avoid to do this more than once
		              before the drive buffer is full. See above DVD-
		*/
		if (i == first_buf_cap ||
1460 1461
		   ((i % buf_cap_step) == 0 &&
		    (i >= further_cap || further_cap < 0))) {
1462
			d->read_buffer_capacity(d);
1463 1464 1465 1466
			if (further_cap < 0)
				further_cap =
			 	    d->progress.buffer_capacity / 2048 + 128;
		}
1467

1468 1469 1470 1471 1472 1473 1474 1475
#ifdef Libburn_simplified_dvd_chunk_transactioN

		ret = transact_dvd_chunk(o, t);
		if (ret <= 0)
			{ret = 0; goto ex;}
		i += o->obs / 2048 - 1;
		d->progress.sector += o->obs / 2048 - 1;
#else
1476 1477 1478
		/* transact a (CD sized) sector */
		if (!sector_data(o, t, 0))
			{ ret = 0; goto ex; }
1479
#endif
1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490

		if (open_ended) {
			d->progress.sectors = sectors = i;
                        if (burn_track_is_data_done(t)) 
	break;
		}

		/* update current progress */
		d->progress.sector++;
	}
	
1491
	/* (tail padding is done in sector_data()) */
1492

1493
	/* Pad up buffer to next full o->obs (usually 32 kB) */
1494
	if (o->obs_pad && out->bytes > 0 && out->bytes < o->obs) {
1495 1496 1497 1498 1499 1500 1501
		memset(out->data + out->bytes, 0, o->obs - out->bytes);
		out->sectors += (o->obs - out->bytes) / 2048;
		out->bytes = o->obs;
	}
	ret = burn_write_flush(o, t);
	if (ret <= 0)
		goto ex;
1502 1503 1504
	is_flushed = 1;

	/* Eventually finalize track */
1505 1506 1507
	if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
	    d->current_profile == 0x15) {
		/* DVD-R, DVD-RW Sequential, DVD-R/DL Sequential */
1508
		ret = burn_disc_close_track_dvd_minus_r(o, s, tnum);
1509 1510 1511 1512
		if (ret <= 0)
			goto ex;
	} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
		/* DVD+R , DVD+R/DL */
1513 1514
		ret = burn_disc_close_track_dvd_plus_r(o, s, tnum,
							 is_last_track);
1515
		if (ret <= 0)
1516
			goto ex;
1517 1518 1519 1520 1521 1522
	} else if (d->current_profile == 0x41) {
		/* BD-R SRM */
		ret = burn_disc_close_track_dvd_plus_r(o, s, tnum,
							 is_last_track);
		if (ret <= 0)
			goto ex;
1523
	}
1524 1525
	ret = 1;
ex:;
1526 1527
	if (d->cancel)
		burn_source_cancel(t->source);
1528
	if (!is_flushed)
1529
		d->sync_cache(d); /* burn_write_flush() was not called */
1530 1531 1532 1533 1534 1535 1536 1537 1538 1539
	return ret;
}


/* ts A61219 */
int burn_disc_close_session_dvd_plus_rw(struct burn_write_opts *o,
					struct burn_session *s)
{
	struct burn_drive *d = o->drive;

1540
	d->busy = BURN_DRIVE_CLOSING_SESSION;
1541 1542
	/* This seems to be a quick end : "if (!dvd_compat)" */
	/* >>> Stop de-icing (ongoing background format) quickly
1543
	       by mmc_close() (but with opcode[2]=0).
1544 1545 1546 1547 1548
	       Wait for unit to get ready.
	       return 1;
	*/
	/* Else: end eventual background format in a "DVD-RO" compatible way */
	d->close_track_session(d, 1, 0); /* same as CLOSE SESSION for CD */
1549
	d->busy = BURN_DRIVE_WRITING;
1550 1551 1552 1553
	return 1;
}


1554 1555 1556 1557 1558 1559 1560
/* ts A61228 */
int burn_disc_close_session_dvd_minus_rw(struct burn_write_opts *o,
					struct burn_session *s)
{
	struct burn_drive *d = o->drive;

	d->busy = BURN_DRIVE_CLOSING_SESSION;
1561 1562 1563 1564 1565 1566 1567
	if (d->current_profile == 0x13) {
		d->close_track_session(d, 1, 0); /* CLOSE SESSION, 010b */

		/* ??? under what circumstances to use close functiom 011b 
		       "Finalize disc" ? */

	}
1568 1569 1570 1571 1572
	d->busy = BURN_DRIVE_WRITING;
	return 1;
}


1573
/* ts A70129 : for profile 0x11 DVD-R, 0x14 DVD-RW Seq, 0x15 DVD-R/DL Seq */
1574 1575 1576 1577 1578
int burn_disc_close_session_dvd_minus_r(struct burn_write_opts *o,
					struct burn_session *s)
{
	struct burn_drive *d = o->drive;

1579 1580 1581
	/* only for Incremental writing */
	if (o->write_type != BURN_WRITE_TAO)
		return 2;
1582

1583 1584 1585 1586 1587
#ifdef Libburn_dvd_r_dl_multi_no_close_sessioN
	if (d->current_profile == 0x15 && o->multi)
		return 2;
#endif

1588 1589 1590 1591
	libdax_msgs_submit(libdax_messenger, o->drive->global_index,0x00020119,
			LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
			"Closing session", 0, 0);

1592 1593 1594 1595 1596 1597 1598
	d->busy = BURN_DRIVE_CLOSING_SESSION;
	d->close_track_session(d, 1, 0); /* CLOSE SESSION, 010b */
	d->busy = BURN_DRIVE_WRITING;
	return 1;
}


1599 1600
/* ts A61218 */
int burn_dvd_write_session(struct burn_write_opts *o,
1601
				struct burn_session *s, int is_last_session)
1602
{
1603
	int i, ret, multi_mem;
1604 1605
        struct burn_drive *d = o->drive;

1606 1607 1608 1609
	/* ts A90108 */
	if (d->current_profile == 0x41 && d->status == BURN_DISC_APPENDABLE &&
	    d->state_of_last_session == 1) {
		/* last session on BD-R is still open */;
1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 1652 1653 1654 1655

		/* BR-R were not closed by libburn-0.6.0.pl00 if o->multi==0.
		   This leads to an unreadable, but recoverable) media state.
		   Technically they are appendable although the last session
		   is not readable.

		   By default the open session gets closed here before the new
		   session is written. E.g. after writing a small dummy seesion
		   number 2 one can read session 1 and write session 3 which
		   points to data of session 1.

		   For the case that no media with 3 sessions is desired it is
		   possible to activate the following coarse single-session
		   closing code:
		   No new session will be written but calling programs will
		   report success. Quite misleading.
		   Activate only if really needed by
		   # define Libburn_bug_A90108_close_disC yes
		*/


#ifdef Libburn_bug_A90108_close_disC

		/* Close open session and media. 
		   That was the goal of the failed run which led to the
		   unreadable (but recoverable) media state.

		   It is not easy to implement a general close function for
		   all media types. Therefore this pseudo write code is under
		   control of #ifdef.
		*/
		libdax_msgs_submit(libdax_messenger, d->global_index,
				0x00020171,
				LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
				"Closing BD-R with accidently open session",
				0, 0);
 		d->close_track_session(d, 3, 0); /* CLOSE SESSION, 110b */
		d->state_of_last_session = 3; /* mark as complete session */
		d->status = BURN_DISC_FULL;
		sleep(3); /* The caller might need time to arrange itself */
		return 1;

#else /* Libburn_bug_A90108_close_disC */

		/* This is the default mode.
		*/
1656 1657 1658 1659 1660 1661 1662
		libdax_msgs_submit(libdax_messenger, d->global_index,
				0x00020170,
				LIBDAX_MSGS_SEV_NOTE, LIBDAX_MSGS_PRIO_HIGH,
				"Closing open session before writing new one",
				0, 0);
 		d->close_track_session(d, 1, 0); /* CLOSE SESSION, 010b */
		d->state_of_last_session = 3; /* mark as complete session */
1663 1664 1665

#endif /* ! Libburn_bug_A90108_close_disC */

1666
	}
1667

1668
	for (i = 0; i < s->tracks; i++) {
1669 1670
		ret = burn_dvd_write_track(o, s, i,
			is_last_session && i == (s->tracks - 1));
1671 1672 1673
		if (ret <= 0)
	break;
	}
1674 1675 1676
	if (d->current_profile == 0x11 || d->current_profile == 0x14 ||
	    d->current_profile == 0x15) {
		/* DVD-R , DVD-RW Sequential, DVD-R/DL Sequential */
1677 1678 1679
		multi_mem = o->multi;
		if (!is_last_session)
			o->multi = 1;
1680
		ret = burn_disc_close_session_dvd_minus_r(o, s);
1681
		o->multi = multi_mem;
1682 1683
		if (ret <= 0)
			return 0;
1684 1685
	} else if (d->current_profile == 0x12 || d->current_profile == 0x43) {
		/* DVD-RAM , BD-RE */
1686 1687 1688
		/* ??? any finalization needed ? */;
	} else if (d->current_profile == 0x13) {
		/* DVD-RW restricted overwrite */
1689
		if (d->needs_close_session) {
1690
			ret = burn_disc_close_session_dvd_minus_rw(o, s);
1691 1692 1693
			if (ret <= 0)
				return 0;
		}
1694 1695
	} else if (d->current_profile == 0x1a) {
		/* DVD+RW */
1696
		if (d->needs_close_session) {
1697
			ret = burn_disc_close_session_dvd_plus_rw(o, s);
1698 1699 1700
			if (ret <= 0)
				return 0;
		}
1701 1702
	} else if (d->current_profile == 0x1b || d->current_profile == 0x2b) {
		/* DVD+R , DVD+R/DL do each track as an own session */;
1703 1704
	} else if (d->current_profile == 0x41) {
		/* BD-R SRM do each track as an own session */;
1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717
	}
	return 1;
}