2006-08-15 20:37:04 +00:00
|
|
|
/* -*- indent-tabs-mode: t; tab-width: 8; c-basic-offset: 8; -*- */
|
|
|
|
|
2006-10-09 12:49:08 +00:00
|
|
|
/* ts A61009 */
|
|
|
|
/* #include <a ssert.h> */
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include "error.h"
|
|
|
|
#include "sector.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"
|
|
|
|
#include "options.h"
|
|
|
|
|
2006-10-31 11:55:51 +00:00
|
|
|
|
2007-02-23 19:08:58 +00:00
|
|
|
/* ts A70223 : in init.c */
|
|
|
|
extern int burn_support_untested_profiles;
|
|
|
|
|
|
|
|
|
2006-10-31 11:55:51 +00:00
|
|
|
#ifdef Libburn_log_in_and_out_streaM
|
|
|
|
/* <<< ts A61031 */
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#endif /* Libburn_log_in_and_out_streaM */
|
|
|
|
|
|
|
|
|
2006-10-09 12:49:08 +00:00
|
|
|
/* ts A61005 */
|
|
|
|
#include "libdax_msgs.h"
|
|
|
|
extern struct libdax_msgs *libdax_messenger;
|
|
|
|
|
|
|
|
|
2006-12-21 20:06:04 +00:00
|
|
|
/* ts A61219 : Based on knowlege from dvd+rw-tools-7.0 and mmc5r03c.pdf */
|
2006-12-20 11:20:08 +00:00
|
|
|
#define Libburn_support_dvd_plus_rW 1
|
2006-12-21 20:06:04 +00:00
|
|
|
|
2006-12-30 00:15:07 +00:00
|
|
|
/* ts A61229 */
|
|
|
|
#define Libburn_support_dvd_minusrw_overW 1
|
|
|
|
|
2007-01-12 16:26:31 +00:00
|
|
|
/* ts A70112 */
|
|
|
|
#define Libburn_support_dvd_raM 1
|
|
|
|
|
2007-03-06 19:50:32 +00:00
|
|
|
/* ts A70129 */
|
2007-01-30 19:16:35 +00:00
|
|
|
#define Libburn_support_dvd_r_seQ 1
|
2007-01-29 17:57:31 +00:00
|
|
|
|
2007-03-06 19:50:32 +00:00
|
|
|
/* ts A70306 >>> UNTESTED */
|
|
|
|
#define Libburn_support_dvd_plus_R 1
|
2007-01-29 17:57:31 +00:00
|
|
|
|
2007-01-30 19:16:35 +00:00
|
|
|
/* Progress report:
|
2006-12-20 11:20:08 +00:00
|
|
|
ts A61219 : It seems to work with a used (i.e. thoroughly formatted) DVD+RW.
|
|
|
|
Error messages of class DEBUG appear because of inability to
|
|
|
|
read TOC or track info. Nevertheless, the written images verify.
|
|
|
|
ts A61220 : Burned to a virgin DVD+RW by help of new mmc_format_unit()
|
|
|
|
(did not test wether it would work without). Burned to a
|
|
|
|
not completely formatted DVD+RW. (Had worked before without
|
2006-12-21 20:06:04 +00:00
|
|
|
mmc_format_unit() but i did not exceed the formatted range
|
|
|
|
as reported by dvd+rw-mediainfo.)
|
|
|
|
ts A61221 : Speed setting now works for both of my drives. The according
|
|
|
|
functions in dvd+rw-tools are a bit intimidating to the reader.
|
|
|
|
I hope it is possible to leave much of this to the drive.
|
|
|
|
And if it fails ... well, it's only speed setting. :))
|
2007-01-01 17:10:54 +00:00
|
|
|
ts A61229 : Burned to several DVD-RW formatted to mode Restricted Overwrite
|
|
|
|
by dvd+rw-format. Needs Libburn_support_dvd_minusrw_overW.
|
|
|
|
ts A61230 : Other than growisofs, libburn does not send a mode page 5 for
|
|
|
|
such DVD-RW (which the MMC-5 standard does deprecate) and it
|
|
|
|
really seems to work without such a page.
|
|
|
|
ts A70101 : Formatted DVD-RW media. Success is varying with media, but
|
|
|
|
dvd+rw-format does not do better with the same media.
|
2007-01-12 16:26:31 +00:00
|
|
|
ts A70112 : Support for writing to DVD-RAM.
|
2007-01-30 19:16:35 +00:00
|
|
|
ts A70130 : Burned a first non-multi sequential DVD-RW. Feature 0021h
|
|
|
|
Incremental Recording vanishes after that and media thus gets
|
|
|
|
not recognized as suitable any more.
|
|
|
|
After a run with -multi another disc still offers 0021h .
|
|
|
|
dvd+rw-mediainfo shows two tracks. The second, an afio archive
|
|
|
|
is readable by afio. Third and forth veryfy too. Suddenly
|
|
|
|
dvd+rw-mediainfo sees lba 0 with track 2. But #2 still verifies
|
|
|
|
if one knows its address.
|
2007-02-05 13:28:57 +00:00
|
|
|
ts A70203 : DVD-RW need to get blanked fully. Then feature 0021h persists.
|
|
|
|
Meanwhile Incremental streaming is supported like CD TAO:
|
|
|
|
with unpredicted size, multi-track, multi-session.
|
|
|
|
ts A70205 : Beginning to implement DVD-R[W] DAO : single track and session,
|
|
|
|
size prediction mandatory.
|
2007-02-10 17:23:49 +00:00
|
|
|
ts A70208 : Finally made tests with DVD-R. Worked exactly as new DVD-RW.
|
2007-01-01 17:10:54 +00:00
|
|
|
|
2006-12-20 11:20:08 +00:00
|
|
|
*/
|
|
|
|
|
2006-10-09 12:49:08 +00:00
|
|
|
|
2007-01-31 17:34:49 +00:00
|
|
|
static unsigned char MMC_GET_MSINFO[] =
|
|
|
|
{ 0x43, 0, 1, 0, 0, 0, 0, 16, 0, 0 };
|
2006-08-15 20:37:04 +00:00
|
|
|
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 };
|
2007-01-05 12:58:36 +00:00
|
|
|
static unsigned char MMC_BLANK[] = { 0xA1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
2006-08-15 20:37:04 +00:00
|
|
|
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 };
|
2006-12-01 21:38:34 +00:00
|
|
|
|
|
|
|
/* ts A61201 : inserted 0, before 16, */
|
2006-08-15 20:37:04 +00:00
|
|
|
static unsigned char MMC_GET_CONFIGURATION[] =
|
2006-12-01 21:38:34 +00:00
|
|
|
{ 0x46, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
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_CLOSE[] = { 0x5B, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
static unsigned char MMC_TRACK_INFO[] = { 0x52, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
|
|
|
|
static unsigned char MMC_SEND_CUE_SHEET[] =
|
|
|
|
{ 0x5D, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
|
|
|
|
|
2006-10-23 11:31:37 +00:00
|
|
|
/* ts A61023 : get size and free space of drive buffer */
|
2006-12-21 20:06:04 +00:00
|
|
|
static unsigned char MMC_READ_BUFFER_CAPACITY[] =
|
|
|
|
{ 0x5C, 0, 0, 0, 0, 0, 0, 16, 0, 0 };
|
2006-10-23 11:31:37 +00:00
|
|
|
|
2006-12-20 11:20:08 +00:00
|
|
|
/* ts A61219 : format DVD+RW (and various others) */
|
|
|
|
static unsigned char MMC_FORMAT_UNIT[] = { 0x04, 0x11, 0, 0, 0, 0 };
|
|
|
|
|
2006-12-21 20:06:04 +00:00
|
|
|
/* ts A61221 :
|
|
|
|
To set speed for DVD media (0xBB is for CD but works on my LG GSA drive) */
|
|
|
|
static unsigned char MMC_SET_STREAMING[] =
|
|
|
|
{ 0xB6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
|
|
2006-12-25 19:00:26 +00:00
|
|
|
/* ts A61225 :
|
|
|
|
To obtain write speed descriptors (command can do other things too) */
|
|
|
|
static unsigned char MMC_GET_PERFORMANCE[] =
|
|
|
|
{ 0xAC, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
2006-08-27 15:16:33 +00:00
|
|
|
|
2007-01-09 21:06:55 +00:00
|
|
|
/* ts A70108 : To obtain info about drive and media formatting opportunities */
|
|
|
|
static unsigned char MMC_READ_FORMAT_CAPACITIES[] =
|
|
|
|
{ 0x23, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
|
|
2007-02-05 13:28:57 +00:00
|
|
|
/* ts A70205 : To describe the layout of a DVD-R[W] DAO session */
|
|
|
|
static unsigned char MMC_RESERVE_TRACK[] =
|
|
|
|
{ 0x53, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
|
|
|
|
2007-01-09 21:06:55 +00:00
|
|
|
|
2006-08-27 15:16:33 +00:00
|
|
|
static int mmc_function_spy_do_tell = 0;
|
|
|
|
|
|
|
|
int mmc_function_spy(char * text)
|
|
|
|
{
|
|
|
|
|
|
|
|
if (mmc_function_spy_do_tell)
|
|
|
|
fprintf(stderr,"libburn: experimental: mmc_function_spy: %s\n",
|
|
|
|
text);
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
int mmc_function_spy_ctrl(int do_tell)
|
|
|
|
{
|
|
|
|
mmc_function_spy_do_tell= !!do_tell;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-01 16:15:09 +00:00
|
|
|
/* ts A70201 */
|
|
|
|
int mmc_four_char_to_int(unsigned char *data)
|
|
|
|
{
|
2007-02-14 12:20:32 +00:00
|
|
|
return (data[0] << 24) | (data[1] << 16) | (data[2] << 8) | data[3];
|
2007-02-01 16:15:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A70201 */
|
|
|
|
int mmc_int_to_four_char(unsigned char *data, int num)
|
|
|
|
{
|
|
|
|
data[0] = (num >> 24) & 0xff;
|
|
|
|
data[1] = (num >> 16) & 0xff;
|
|
|
|
data[2] = (num >> 8) & 0xff;
|
|
|
|
data[3] = num & 0xff;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
void mmc_send_cue_sheet(struct burn_drive *d, struct cue_sheet *s)
|
|
|
|
{
|
|
|
|
struct buffer buf;
|
|
|
|
struct command c;
|
|
|
|
|
2006-08-27 15:16:33 +00:00
|
|
|
|
|
|
|
mmc_function_spy("mmc_send_cue_sheet");
|
2006-08-15 20:37:04 +00:00
|
|
|
c.retry = 1;
|
|
|
|
c.oplen = sizeof(MMC_SEND_CUE_SHEET);
|
|
|
|
memcpy(c.opcode, MMC_SEND_CUE_SHEET, sizeof(MMC_SEND_CUE_SHEET));
|
|
|
|
c.page = &buf;
|
|
|
|
c.page->bytes = s->count * 8;
|
|
|
|
c.page->sectors = 0;
|
|
|
|
c.opcode[6] = (c.page->bytes >> 16) & 0xFF;
|
|
|
|
c.opcode[7] = (c.page->bytes >> 8) & 0xFF;
|
|
|
|
c.opcode[8] = c.page->bytes & 0xFF;
|
|
|
|
c.dir = TO_DRIVE;
|
|
|
|
memcpy(c.page->data, s->data, c.page->bytes);
|
|
|
|
d->issue_command(d, &c);
|
|
|
|
}
|
|
|
|
|
2007-02-01 16:15:09 +00:00
|
|
|
|
2007-02-05 13:28:57 +00:00
|
|
|
/* ts A70205 : Announce size of a DVD-R[W] DAO session.
|
|
|
|
@param size The size in bytes to be announced to the drive.
|
|
|
|
It will get rounded up to align to 32 KiB.
|
|
|
|
*/
|
|
|
|
int mmc_reserve_track(struct burn_drive *d, off_t size)
|
|
|
|
{
|
|
|
|
struct command c;
|
|
|
|
int lba;
|
2007-02-06 13:06:39 +00:00
|
|
|
char msg[80];
|
2007-02-05 13:28:57 +00:00
|
|
|
|
|
|
|
mmc_function_spy("mmc_reserve_track");
|
|
|
|
c.retry = 1;
|
|
|
|
c.oplen = sizeof(MMC_RESERVE_TRACK);
|
|
|
|
memcpy(c.opcode, MMC_RESERVE_TRACK, sizeof(MMC_RESERVE_TRACK));
|
|
|
|
|
2007-02-06 13:06:39 +00:00
|
|
|
/* Round to 32 KiB and divide by 2048
|
|
|
|
(by nice binary rounding trick learned from dvd+rw-tools) */
|
2007-02-05 13:28:57 +00:00
|
|
|
lba = ((size + (off_t) 0x7fff) >> 11) & ~0xf;
|
|
|
|
mmc_int_to_four_char(c.opcode+5, lba);
|
|
|
|
|
2007-02-06 13:06:39 +00:00
|
|
|
sprintf(msg, "reserving track of %d blocks", lba);
|
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
|
|
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
|
|
|
msg, 0, 0);
|
|
|
|
|
2007-02-05 13:28:57 +00:00
|
|
|
c.page = NULL;
|
|
|
|
c.dir = NO_TRANSFER;
|
|
|
|
d->issue_command(d, &c);
|
2007-02-06 13:06:39 +00:00
|
|
|
return !c.error;
|
2007-02-05 13:28:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2007-02-01 16:15:09 +00:00
|
|
|
/* ts A70201 :
|
|
|
|
Common track info fetcher for mmc_get_nwa() and mmc_fake_toc()
|
|
|
|
*/
|
|
|
|
int mmc_read_track_info(struct burn_drive *d, int trackno, struct buffer *buf)
|
|
|
|
{
|
|
|
|
struct command c;
|
|
|
|
|
|
|
|
mmc_function_spy("mmc_read_track_info");
|
|
|
|
c.retry = 1;
|
|
|
|
c.oplen = sizeof(MMC_TRACK_INFO);
|
|
|
|
memcpy(c.opcode, MMC_TRACK_INFO, sizeof(MMC_TRACK_INFO));
|
|
|
|
c.opcode[1] = 1;
|
|
|
|
if(trackno<=0) {
|
|
|
|
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
|
|
|
|
d->current_profile == 0x12 )
|
|
|
|
/* DVD+RW , DVD-RW restricted overwrite , DVD-RAM */
|
|
|
|
trackno = 1;
|
2007-02-13 14:37:25 +00:00
|
|
|
else if (d->current_profile == 0x10 ||
|
|
|
|
d->current_profile == 0x11 ||
|
2007-02-23 19:08:58 +00:00
|
|
|
d->current_profile == 0x14 ||
|
|
|
|
d->current_profile == 0x15)
|
2007-02-13 14:37:25 +00:00
|
|
|
/* DVD-ROM , DVD-R[W] Sequential */
|
2007-02-01 16:15:09 +00:00
|
|
|
trackno = d->last_track_no;
|
|
|
|
else /* mmc5r03c.pdf: valid only for CD, DVD+R, DVD+R DL */
|
|
|
|
trackno = 0xFF;
|
|
|
|
}
|
2007-03-01 12:07:29 +00:00
|
|
|
mmc_int_to_four_char(c.opcode + 2, trackno);
|
2007-02-01 16:15:09 +00:00
|
|
|
c.page = buf;
|
|
|
|
memset(buf->data, 0, BUFFER_SIZE);
|
|
|
|
c.dir = FROM_DRIVE;
|
|
|
|
d->issue_command(d, &c);
|
|
|
|
if (c.error)
|
|
|
|
return 0;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-11-11 12:22:53 +00:00
|
|
|
/* ts A61110 : added parameters trackno, lba, nwa. Redefined return value.
|
|
|
|
@return 1=nwa is valid , 0=nwa is not valid , -1=error */
|
2007-02-01 16:15:09 +00:00
|
|
|
/* ts A70201 : outsourced 52h READ TRACK INFO command */
|
2006-11-11 12:22:53 +00:00
|
|
|
int mmc_get_nwa(struct burn_drive *d, int trackno, int *lba, int *nwa)
|
2006-08-15 20:37:04 +00:00
|
|
|
{
|
|
|
|
struct buffer buf;
|
2007-02-13 14:37:25 +00:00
|
|
|
int ret, num;
|
2007-02-01 16:15:09 +00:00
|
|
|
unsigned char *data;
|
2006-08-15 20:37:04 +00:00
|
|
|
|
2006-08-27 15:16:33 +00:00
|
|
|
mmc_function_spy("mmc_get_nwa");
|
2007-02-01 16:15:09 +00:00
|
|
|
|
|
|
|
ret = mmc_read_track_info(d, trackno, &buf);
|
|
|
|
if (ret <= 0)
|
|
|
|
return ret;
|
|
|
|
data = buf.data;
|
2007-02-13 14:37:25 +00:00
|
|
|
*lba = mmc_four_char_to_int(data + 8);
|
|
|
|
*nwa = mmc_four_char_to_int(data + 12);
|
|
|
|
num = mmc_four_char_to_int(data + 16);
|
|
|
|
if (d->current_profile == 0x1a || d->current_profile == 0x13 ||
|
|
|
|
d->current_profile == 0x12) {
|
|
|
|
/* overwriteable */
|
|
|
|
*lba = *nwa = num = 0;
|
2006-12-20 17:05:33 +00:00
|
|
|
} else if (!(data[7]&1)) {
|
|
|
|
/* ts A61106 : MMC-1 Table 142 : NWA_V = NWA Valid Flag */
|
2006-11-06 19:58:24 +00:00
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
|
|
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
|
|
|
"mmc_get_nwa: Track Info Block: NWA_V == 0", 0, 0);
|
2006-11-11 12:22:53 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2007-02-15 20:18:07 +00:00
|
|
|
if (num > 0) {
|
2007-02-13 14:37:25 +00:00
|
|
|
d->media_capacity_remaining = ((off_t) num) * ((off_t) 2048);
|
2007-02-15 20:18:07 +00:00
|
|
|
d->media_lba_limit = *nwa + num;
|
|
|
|
} else
|
|
|
|
d->media_lba_limit = 0;
|
2007-02-14 12:20:32 +00:00
|
|
|
|
|
|
|
/*
|
2007-02-15 20:18:07 +00:00
|
|
|
fprintf(stderr, "LIBBURN_DEBUG: media_lba_limit= %d\n",
|
|
|
|
d->media_lba_limit);
|
2007-02-14 12:20:32 +00:00
|
|
|
*/
|
|
|
|
|
2006-11-11 12:22:53 +00:00
|
|
|
return 1;
|
2006-08-15 20:37:04 +00:00
|
|
|
}
|
|
|
|
|
2006-10-09 12:49:08 +00:00
|
|
|
/* ts A61009 : function is obviously unused. */
|
|
|
|
/* void mmc_close_disc(struct burn_drive *d, struct burn_write_opts *o) */
|
|
|
|
void mmc_close_disc(struct burn_write_opts *o)
|
2006-08-15 20:37:04 +00:00
|
|
|
{
|
2006-10-09 12:49:08 +00:00
|
|
|
struct burn_drive *d;
|
|
|
|
|
2006-08-27 15:16:33 +00:00
|
|
|
mmc_function_spy("mmc_close_disc");
|
2006-10-09 12:49:08 +00:00
|
|
|
|
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
|
|
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
|
|
|
"HOW THAT ? mmc_close_disc() was called", 0, 0);
|
|
|
|
|
|
|
|
/* ts A61009 : made impossible by removing redundant parameter d */
|
|
|
|
/* a ssert(o->drive == d); */
|
|
|
|
d = o->drive;
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
o->multi = 0;
|
|
|
|
spc_select_write_params(d, o);
|
|
|
|
mmc_close(d, 1, 0);
|
|
|
|
}
|
|
|
|
|
2006-10-09 12:49:08 +00:00
|
|
|
/* ts A61009 : function is obviously unused. */
|
|
|
|
/* void mmc_close_session(struct burn_drive *d, struct burn_write_opts *o) */
|
|
|
|
void mmc_close_session(struct burn_write_opts *o)
|
2006-08-15 20:37:04 +00:00
|
|
|
{
|
2006-10-09 12:49:08 +00:00
|
|
|
struct burn_drive *d;
|
|
|
|
|
2006-08-27 15:16:33 +00:00
|
|
|
mmc_function_spy("mmc_close_session");
|
2006-10-09 12:49:08 +00:00
|
|
|
|
|
|
|
libdax_msgs_submit(libdax_messenger, -1, 0x00000002,
|
|
|
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_ZERO,
|
|
|
|
"HOW THAT ? mmc_close_session() was called", 0, 0);
|
|
|
|
|
|
|
|
/* ts A61009 : made impossible by removing redundant parameter d */
|
|
|
|
/* a ssert(o->drive == d); */
|
|
|
|
d = o->drive;
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
o->multi = 3;
|
|
|
|
spc_select_write_params(d, o);
|
|
|
|
mmc_close(d, 1, 0);
|
|
|
|
}
|
|
|
|
|
2007-03-01 12:07:29 +00:00
|
|
|
/* ts A70227 : extended meaning of session to address all possible values
|
|
|
|
of 5Bh CLOSE TRACK SESSION to address any Close Function.
|
|
|
|
@param session contains the two high bits of Close Function
|
|
|
|
@param track if not 0: sets the lowest bit of Close Function
|
|
|
|
*/
|
2006-08-15 20:37:04 +00:00
|
|
|
void mmc_close(struct burn_drive *d, int session, int track)
|
|
|
|
{
|
|
|
|
struct command c;
|
|
|
|
|
2006-10-09 12:49:08 +00:00
|
|
|
mmc_function_spy("mmc_close");
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
c.retry = 1;
|
|
|
|
c.oplen = sizeof(MMC_CLOSE);
|
|
|
|
memcpy(c.opcode, MMC_CLOSE, sizeof(MMC_CLOSE));
|
2006-10-31 11:55:51 +00:00
|
|
|
|
2007-03-01 12:07:29 +00:00
|
|
|
/* (ts A61030 : shifted !!session rather than or-ing plain session ) */
|
|
|
|
c.opcode[2] = ((session & 3) << 1) | !!track;
|
2006-08-15 20:37:04 +00:00
|
|
|
c.opcode[4] = track >> 8;
|
|
|
|
c.opcode[5] = track & 0xFF;
|
|
|
|
c.page = NULL;
|
|
|
|
c.dir = NO_TRANSFER;
|
|
|
|
d->issue_command(d, &c);
|
|
|
|
}
|
|
|
|
|
|
|
|
void mmc_get_event(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
struct buffer buf;
|
|
|
|
struct command c;
|
|
|
|
|
2006-08-27 15:16:33 +00:00
|
|
|
mmc_function_spy("mmc_get_event");
|
2006-08-15 20:37:04 +00:00
|
|
|
c.retry = 1;
|
|
|
|
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);
|
|
|
|
burn_print(12, "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]);
|
|
|
|
burn_print(12, "event: %d:%d:%d:%d\n", c.page->data[4],
|
|
|
|
c.page->data[5], c.page->data[6], c.page->data[7]);
|
|
|
|
}
|
|
|
|
|
2006-10-09 12:49:08 +00:00
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
void mmc_write_12(struct burn_drive *d, int start, struct buffer *buf)
|
|
|
|
{
|
|
|
|
struct command c;
|
|
|
|
int len;
|
|
|
|
|
2006-08-27 15:16:33 +00:00
|
|
|
mmc_function_spy("mmc_write_12");
|
2006-08-15 20:37:04 +00:00
|
|
|
len = buf->sectors;
|
2006-10-09 12:49:08 +00:00
|
|
|
|
|
|
|
/* ts A61009 */
|
|
|
|
/* a ssert(buf->bytes >= buf->sectors);*/ /* can be == at 0... */
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
burn_print(100, "trying to write %d at %d\n", len, start);
|
|
|
|
memcpy(c.opcode, MMC_WRITE_12, sizeof(MMC_WRITE_12));
|
|
|
|
c.retry = 1;
|
|
|
|
c.oplen = sizeof(MMC_WRITE_12);
|
2007-03-01 12:07:29 +00:00
|
|
|
mmc_int_to_four_char(c.opcode + 2, start);
|
|
|
|
mmc_int_to_four_char(c.opcode + 6, len);
|
2006-08-15 20:37:04 +00:00
|
|
|
c.page = buf;
|
|
|
|
c.dir = TO_DRIVE;
|
|
|
|
|
|
|
|
d->issue_command(d, &c);
|
|
|
|
}
|
|
|
|
|
|
|
|
int mmc_write(struct burn_drive *d, int start, struct buffer *buf)
|
|
|
|
{
|
|
|
|
int cancelled;
|
|
|
|
struct command c;
|
|
|
|
int len;
|
|
|
|
|
2006-10-31 11:55:51 +00:00
|
|
|
#ifdef Libburn_log_in_and_out_streaM
|
|
|
|
/* <<< ts A61031 */
|
|
|
|
static int tee_fd= -1;
|
|
|
|
if(tee_fd==-1)
|
|
|
|
tee_fd= open("/tmp/libburn_sg_written",
|
|
|
|
O_WRONLY|O_CREAT|O_TRUNC,S_IRUSR|S_IWUSR);
|
|
|
|
#endif /* Libburn_log_in_and_out_streaM */
|
|
|
|
|
2006-08-27 15:16:33 +00:00
|
|
|
mmc_function_spy("mmc_write");
|
2006-08-15 20:37:04 +00:00
|
|
|
pthread_mutex_lock(&d->access_lock);
|
|
|
|
cancelled = d->cancel;
|
|
|
|
pthread_mutex_unlock(&d->access_lock);
|
|
|
|
|
|
|
|
if (cancelled)
|
|
|
|
return BE_CANCELLED;
|
|
|
|
|
2007-02-15 20:18:07 +00:00
|
|
|
/* ts A70215 */
|
|
|
|
if (d->media_lba_limit > 0 && start >= d->media_lba_limit) {
|
|
|
|
char msg[160];
|
|
|
|
|
|
|
|
sprintf(msg,
|
|
|
|
"Exceeding range of permissible write addresses (%d >= %d)",
|
|
|
|
start, d->media_lba_limit);
|
|
|
|
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
|
|
0x0002012d,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
msg, 0, 0);
|
|
|
|
d->cancel = 1; /* No need for mutexing because atomic */
|
|
|
|
return BE_CANCELLED;
|
|
|
|
}
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
len = buf->sectors;
|
2006-10-09 12:49:08 +00:00
|
|
|
|
|
|
|
/* ts A61009 : buffer fill problems are to be handled by caller */
|
|
|
|
/* a ssert(buf->bytes >= buf->sectors);*/ /* can be == at 0... */
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
burn_print(100, "trying to write %d at %d\n", len, start);
|
|
|
|
memcpy(c.opcode, MMC_WRITE_10, sizeof(MMC_WRITE_10));
|
|
|
|
c.retry = 1;
|
|
|
|
c.oplen = sizeof(MMC_WRITE_10);
|
2007-03-01 12:07:29 +00:00
|
|
|
mmc_int_to_four_char(c.opcode + 2, start);
|
2006-08-15 20:37:04 +00:00
|
|
|
c.opcode[6] = 0;
|
|
|
|
c.opcode[7] = (len >> 8) & 0xFF;
|
|
|
|
c.opcode[8] = len & 0xFF;
|
|
|
|
c.page = buf;
|
|
|
|
c.dir = TO_DRIVE;
|
|
|
|
/*
|
|
|
|
burn_print(12, "%d, %d, %d, %d - ", c->opcode[2], c->opcode[3], c->opcode[4], c->opcode[5]);
|
|
|
|
burn_print(12, "%d, %d, %d, %d\n", c->opcode[6], c->opcode[7], c->opcode[8], c->opcode[9]);
|
|
|
|
*/
|
|
|
|
|
2006-10-31 11:55:51 +00:00
|
|
|
#ifdef Libburn_log_in_and_out_streaM
|
|
|
|
/* <<< ts A61031 */
|
|
|
|
if(tee_fd!=-1) {
|
|
|
|
write(tee_fd,c.page->data,len*2048);
|
|
|
|
}
|
|
|
|
#endif /* Libburn_log_in_and_out_streaM */
|
2006-08-15 20:37:04 +00:00
|
|
|
|
|
|
|
d->issue_command(d, &c);
|
2006-11-12 15:28:09 +00:00
|
|
|
|
|
|
|
/* ts A61112 : react on eventual error condition */
|
|
|
|
if (c.error && c.sense[2]!=0) {
|
|
|
|
|
|
|
|
/* >>> make this scsi_notify_error() when liberated */
|
|
|
|
if (c.sense[2]!=0) {
|
2006-12-20 11:20:08 +00:00
|
|
|
char msg[160];
|
2006-11-12 15:28:09 +00:00
|
|
|
sprintf(msg,
|
2006-12-20 11:20:08 +00:00
|
|
|
"SCSI error on write(%d,%d): key=%X asc=%2.2Xh ascq=%2.2Xh",
|
|
|
|
start, len,
|
2006-11-12 15:28:09 +00:00
|
|
|
c.sense[2],c.sense[12],c.sense[13]);
|
|
|
|
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
|
|
0x0002011d,
|
|
|
|
LIBDAX_MSGS_SEV_FATAL, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
msg, 0, 0);
|
|
|
|
}
|
|
|
|
pthread_mutex_lock(&d->access_lock);
|
|
|
|
d->cancel = 1;
|
|
|
|
pthread_mutex_unlock(&d->access_lock);
|
|
|
|
return BE_CANCELLED;
|
|
|
|
}
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2007-02-01 16:15:09 +00:00
|
|
|
|
|
|
|
/* ts A70201 : Set up an entry for mmc_fake_toc() */
|
|
|
|
int mmc_fake_toc_entry(struct burn_toc_entry *entry, int session_number,
|
|
|
|
int track_number,
|
|
|
|
unsigned char *size_data, unsigned char *start_data)
|
|
|
|
{
|
|
|
|
int min, sec, frames, num;
|
|
|
|
|
|
|
|
/* mark DVD extensions as valid */
|
|
|
|
entry->extensions_valid |= 1;
|
|
|
|
|
|
|
|
/* defaults are as of mmc5r03.pdf 6.26.3.2.4 Fabricated TOC */
|
|
|
|
entry->session = session_number & 0xff;
|
|
|
|
entry->session_msb = (session_number >> 8) & 0xff;
|
|
|
|
entry->adr = 1;
|
|
|
|
entry->control = 4;
|
|
|
|
entry->tno = 0;
|
|
|
|
entry->point = track_number & 0xff;
|
|
|
|
entry->point_msb = (track_number >> 8) & 0xff;
|
2007-02-13 14:37:25 +00:00
|
|
|
num = mmc_four_char_to_int(size_data);
|
2007-02-01 16:15:09 +00:00
|
|
|
entry->track_blocks = num;
|
|
|
|
burn_lba_to_msf(num, &min, &sec, &frames);
|
|
|
|
if (min > 255) {
|
|
|
|
min = 255;
|
|
|
|
sec = 255;
|
|
|
|
frames = 255;
|
|
|
|
}
|
|
|
|
entry->min = min;
|
|
|
|
entry->sec = sec;
|
|
|
|
entry->frame = frames;
|
|
|
|
entry->zero = 0;
|
2007-02-13 14:37:25 +00:00
|
|
|
num = mmc_four_char_to_int(start_data);
|
2007-02-01 16:15:09 +00:00
|
|
|
entry->start_lba = num;
|
|
|
|
burn_lba_to_msf(num, &min, &sec, &frames);
|
|
|
|
if (min > 255) {
|
|
|
|
min = 255;
|
|
|
|
sec = 255;
|
|
|
|
frames = 255;
|
|
|
|
}
|
|
|
|
entry->pmin = min;
|
|
|
|
entry->psec = sec;
|
|
|
|
entry->pframe = frames;
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* ts A70131 : compose a disc TOC structure from d->complete_sessions
|
|
|
|
and 52h READ TRACK INFORMATION */
|
|
|
|
int mmc_fake_toc(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
struct burn_track *track;
|
|
|
|
struct burn_session *session;
|
|
|
|
struct burn_toc_entry *entry;
|
|
|
|
struct buffer buf;
|
|
|
|
int i, session_number, prev_session = -1, ret, lba;
|
|
|
|
unsigned char *tdata, size_data[4], start_data[4];
|
2007-02-14 12:20:32 +00:00
|
|
|
char msg[160];
|
2007-02-01 16:15:09 +00:00
|
|
|
|
|
|
|
if (d->last_track_no <= 0 || d->complete_sessions <= 0 ||
|
|
|
|
d->status == BURN_DISC_BLANK)
|
|
|
|
return 2;
|
2007-02-14 12:20:32 +00:00
|
|
|
if (d->last_track_no > BURN_MMC_FAKE_TOC_MAX_SIZE) {
|
|
|
|
sprintf(msg,
|
|
|
|
"Too many logical tracks recorded (%d , max. %d)\n",
|
|
|
|
d->last_track_no, BURN_MMC_FAKE_TOC_MAX_SIZE);
|
|
|
|
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
|
|
0x0002012c,
|
|
|
|
LIBDAX_MSGS_SEV_SORRY, LIBDAX_MSGS_PRIO_HIGH,
|
|
|
|
msg, 0,0);
|
|
|
|
return 0;
|
|
|
|
}
|
2007-02-01 16:15:09 +00:00
|
|
|
d->disc = burn_disc_create();
|
|
|
|
if (d->disc == NULL)
|
|
|
|
return -1;
|
|
|
|
d->toc_entries = d->last_track_no + d->complete_sessions;
|
|
|
|
d->toc_entry = malloc(d->toc_entries * sizeof(struct burn_toc_entry));
|
|
|
|
if (d->toc_entry == NULL)
|
|
|
|
return -1;
|
|
|
|
memset(d->toc_entry, 0,d->toc_entries * sizeof(struct burn_toc_entry));
|
|
|
|
for (i = 0; i < d->complete_sessions; i++) {
|
|
|
|
session = burn_session_create();
|
|
|
|
burn_disc_add_session(d->disc, session, BURN_POS_END);
|
|
|
|
burn_session_free(session);
|
|
|
|
}
|
|
|
|
memset(size_data, 0, 4);
|
|
|
|
memset(start_data, 0, 4);
|
|
|
|
|
|
|
|
/* Entry Layout :
|
|
|
|
session 1 track 1 entry 0
|
|
|
|
...
|
|
|
|
session 1 track N entry N-1
|
|
|
|
leadout 1 entry N
|
|
|
|
session 2 track N+1 entry N+1
|
|
|
|
...
|
|
|
|
session 2 track M+1 entry M+1
|
|
|
|
leadout 2 entry M+2
|
|
|
|
session X track K entry (K-1)+(X-1)
|
|
|
|
...
|
|
|
|
session X track i+1 entry i+(X-1)
|
|
|
|
leadout X entry i+X
|
|
|
|
*/
|
|
|
|
for (i = 0; i < d->last_track_no; i++) {
|
|
|
|
ret = mmc_read_track_info(d, i+1, &buf);
|
2007-02-14 12:20:32 +00:00
|
|
|
if (ret <= 0)
|
2007-02-01 16:15:09 +00:00
|
|
|
return ret;
|
|
|
|
tdata = buf.data;
|
|
|
|
session_number = (tdata[33] << 8) | tdata[3];
|
|
|
|
if (session_number <= 0)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (session_number != prev_session && prev_session > 0) {
|
2007-02-02 17:32:09 +00:00
|
|
|
/* leadout entry previous session */
|
2007-02-01 16:15:09 +00:00
|
|
|
entry = &(d->toc_entry[(i - 1) + prev_session]);
|
|
|
|
lba = mmc_four_char_to_int(start_data) +
|
|
|
|
mmc_four_char_to_int(size_data);
|
|
|
|
mmc_int_to_four_char(start_data, lba);
|
|
|
|
mmc_int_to_four_char(size_data, 0);
|
2007-02-02 17:32:09 +00:00
|
|
|
mmc_fake_toc_entry(entry, prev_session, 0xA2,
|
2007-02-01 16:15:09 +00:00
|
|
|
size_data, start_data);
|
|
|
|
entry->min= entry->sec= entry->frame= 0;
|
|
|
|
d->disc->session[prev_session - 1]->leadout_entry =
|
|
|
|
entry;
|
|
|
|
}
|
|
|
|
|
2007-02-13 14:37:25 +00:00
|
|
|
if (session_number > d->disc->sessions) {
|
|
|
|
if (i == d->last_track_no - 1) {
|
|
|
|
/* ts A70212 : Last track field Free Blocks */
|
|
|
|
d->media_capacity_remaining =
|
|
|
|
((off_t) mmc_four_char_to_int(tdata + 16)) *
|
|
|
|
((off_t) 2048);
|
2007-02-15 20:18:07 +00:00
|
|
|
d->media_lba_limit = 0;
|
2007-02-13 14:37:25 +00:00
|
|
|
}
|
2007-02-01 16:15:09 +00:00
|
|
|
continue;
|
2007-02-13 14:37:25 +00:00
|
|
|
}
|
2007-02-01 16:15:09 +00:00
|
|
|
|
|
|
|
entry = &(d->toc_entry[i + session_number - 1]);
|
|
|
|
track = burn_track_create();
|
|
|
|
if (track == NULL)
|
|
|
|
return -1;
|
|
|
|
burn_session_add_track(
|
|
|
|
d->disc->session[session_number - 1],
|
|
|
|
track, BURN_POS_END);
|
|
|
|
track->entry = entry;
|
|
|
|
burn_track_free(track);
|
|
|
|
|
|
|
|
memcpy(size_data, tdata + 24, 4);
|
|
|
|
memcpy(start_data, tdata + 8, 4);
|
|
|
|
mmc_fake_toc_entry(entry, session_number, i + 1,
|
|
|
|
size_data, start_data);
|
|
|
|
|
2007-02-02 17:32:09 +00:00
|
|
|
if (prev_session != session_number)
|
|
|
|
d->disc->session[session_number - 1]->firsttrack = i+1;
|
|
|
|
d->disc->session[session_number - 1]->lasttrack = i+1;
|
2007-02-01 16:15:09 +00:00
|
|
|
prev_session = session_number;
|
|
|
|
}
|
2007-02-02 17:32:09 +00:00
|
|
|
if (prev_session > 0 && prev_session <= d->disc->sessions) {
|
|
|
|
/* leadout entry of last session of closed disc */
|
|
|
|
entry = &(d->toc_entry[(d->last_track_no - 1) + prev_session]);
|
|
|
|
lba = mmc_four_char_to_int(start_data) +
|
|
|
|
mmc_four_char_to_int(size_data);
|
|
|
|
mmc_int_to_four_char(start_data, lba);
|
|
|
|
mmc_int_to_four_char(size_data, 0);
|
|
|
|
mmc_fake_toc_entry(entry, prev_session, 0xA2,
|
|
|
|
size_data, start_data);
|
|
|
|
entry->min= entry->sec= entry->frame= 0;
|
|
|
|
d->disc->session[prev_session - 1]->leadout_entry = entry;
|
|
|
|
}
|
2007-02-01 16:15:09 +00:00
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
void mmc_read_toc(struct burn_drive *d)
|
|
|
|
{
|
|
|
|
/* read full toc, all sessions, in m/s/f form, 4k buffer */
|
2007-02-01 16:15:09 +00:00
|
|
|
/* ts A70201 : or fake a toc from track information */
|
2006-08-15 20:37:04 +00:00
|
|
|
struct burn_track *track;
|
|
|
|
struct burn_session *session;
|
|
|
|
struct buffer buf;
|
|
|
|
struct command c;
|
|
|
|
int dlen;
|
2006-10-22 13:03:28 +00:00
|
|
|
int i, bpl= 12;
|
2006-08-15 20:37:04 +00:00
|
|
|
unsigned char *tdata;
|
|
|
|
|
2006-08-27 15:16:33 +00:00
|
|
|
mmc_function_spy("mmc_read_toc");
|
2007-02-01 16:15:09 +00:00
|
|
|
if (!(d->current_profile == -1 || d->current_is_cd_profile)) {
|
2007-01-31 17:34:49 +00:00
|
|
|
/* ts A70131 : MMC_GET_TOC uses Response Format 2
|
|
|
|
For DVD this fails with 5,24,00 */
|
2007-02-01 16:15:09 +00:00
|
|
|
/* One could try Response Format 0: mmc5r03.pdf 6.26.3.2
|
|
|
|
which does not yield the same result wit the same disc
|
|
|
|
on different drives.
|
|
|
|
*/
|
|
|
|
/* ts A70201 :
|
|
|
|
This uses the session count from 51h READ DISC INFORMATION
|
|
|
|
and the track records from 52h READ TRACK INFORMATION
|
|
|
|
*/
|
|
|
|
mmc_fake_toc(d);
|
2007-01-31 17:34:49 +00:00
|
|
|
|
2007-02-01 16:15:09 +00:00
|
|
|
if (d->status == BURN_DISC_UNREADY)
|
|
|
|
d->status = BURN_DISC_FULL;
|
|
|
|
return;
|
2007-01-31 17:34:49 +00:00
|
|
|
}
|
2007-02-01 16:15:09 +00:00
|
|
|
memcpy(c.opcode, MMC_GET_TOC, sizeof(MMC_GET_TOC));
|
2006-08-15 20:37:04 +00:00
|
|
|
c.retry = 1;
|
|
|
|
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) {
|
2006-10-20 15:16:29 +00:00
|
|
|
|
|
|
|
/* ts A61020 : this snaps on non-blank DVD media */
|
2006-11-06 15:52:45 +00:00
|
|
|
/* ts A61106 : also snaps on CD with unclosed track/session */
|
2006-10-20 15:16:29 +00:00
|
|
|
/* Very unsure wether this old measure is ok.
|
|
|
|
Obviously higher levels do not care about this.
|
2006-12-20 11:20:08 +00:00
|
|
|
outdated info: DVD+RW burns go on after passing through here.
|
2006-10-20 15:16:29 +00:00
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
d->busy = BURN_DRIVE_IDLE;
|
2006-10-20 15:16:29 +00:00
|
|
|
*/
|
|
|
|
libdax_msgs_submit(libdax_messenger, d->global_index,
|
|
|
|
0x0002010d,
|
|
|
|
LIBDAX_MSGS_SEV_DEBUG, LIBDAX_MSGS_PRIO_HIGH,
|
2007-01-31 17:34:49 +00:00
|
|
|
"Could not inquire TOC", 0,0);
|
2006-10-20 15:16:29 +00:00
|
|
|
d->status = BURN_DISC_UNSUITABLE;
|
|
|
|
d->toc_entries = 0;
|
|
|
|
/* Prefering memory leaks over fandangos */
|
|
|
|
d->toc_entry = malloc(sizeof(struct burn_toc_entry));
|
2007-02-01 16:15:09 +00:00
|
|
|
memset(&(d->toc_entry[0]), 0, sizeof(struct burn_toc_entry));
|
2006-10-20 15:16:29 +00:00
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
dlen = c.page->data[0] * 256 + c.page->data[1];
|
|
|
|
d->toc_entries = (dlen - 2) / 11;
|
|
|
|
/*
|
|
|
|
some drives fail this check.
|
|
|
|
|
2006-10-09 12:49:08 +00:00
|
|
|
ts A61007 : if re-enabled then not via Assert.
|
|
|
|
a ssert(((dlen - 2) % 11) == 0);
|
2006-08-15 20:37:04 +00:00
|
|
|
*/
|
|
|
|
d->toc_entry = malloc(d->toc_entries * sizeof(struct burn_toc_entry));
|
2007-02-01 16:15:09 +00:00
|
|
|
for (i = 0; i < d->toc_entries; i++)
|
|
|
|
memset(&(d->toc_entry[i]), 0, sizeof(struct burn_toc_entry));
|
2006-08-15 20:37:04 +00:00
|
|
|
tdata = c.page->data + 4;
|
|
|
|
|
|
|
|
burn_print(12, "TOC:\n");
|
|
|
|
|
|
|
|
d->disc = burn_disc_create();
|
|
|
|
|
|
|
|
for (i = 0; i < c.page->data[3]; i++) {
|
|
|
|
session = burn_session_create();
|
|
|
|
burn_disc_add_session(d->disc, session, BURN_POS_END);
|
|
|
|
burn_session_free(session);
|
|
|
|
}
|
2006-10-22 13:03:28 +00:00
|
|
|
|
|
|
|
/* ts A61022 */
|
|
|
|
burn_print(bpl, "-----------------------------------\n");
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
for (i = 0; i < d->toc_entries; i++, tdata += 11) {
|
2006-10-22 13:03:28 +00:00
|
|
|
|
|
|
|
/* ts A61022: was burn_print level 12 */
|
|
|
|
burn_print(bpl, "S %d, PT %2.2Xh, TNO %d :", tdata[0],tdata[3],
|
2006-08-15 20:37:04 +00:00
|
|
|
tdata[2]);
|
2006-10-22 13:03:28 +00:00
|
|
|
burn_print(bpl, " MSF(%d:%d:%d)", tdata[4],tdata[5],tdata[6]);
|
|
|
|
burn_print(bpl, " PMSF(%d:%d:%d %d)",
|
|
|
|
tdata[8], tdata[9], tdata[10],
|
2007-02-01 16:15:09 +00:00
|
|
|
burn_msf_to_lba(tdata[8], tdata[9], tdata[10]));
|
2006-10-22 13:03:28 +00:00
|
|
|
burn_print(bpl, " - control %d, adr %d\n", tdata[1] & 0xF,
|
2006-08-15 20:37:04 +00:00
|
|
|
tdata[1] >> 4);
|
|
|
|
|
2006-10-20 11:34:52 +00:00
|
|
|
/*
|
|
|
|
fprintf(stderr, "libburn_experimental: toc entry #%d : %d %d %d\n",i,tdata[8], tdata[9], tdata[10]);
|
|
|
|
*/
|
|
|
|
|
2006-08-15 20:37:04 +00:00
|
|
|
if (tdata[3] == 1) {
|
|
|
|
if (burn_msf_to_lba(tdata[8], tdata[9], tdata[10])) {
|
|
|
|
d->disc->session[0]->hidefirst = 1;
|
|
|
|
track = burn_track_create();
|
|
|
|
burn_session_add_track(d->disc->
|
|
|
|
session[tdata[0] - 1],
|
|
|
|
track, BURN_POS_END);
|
|
|
|
burn_track_free(track);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
2006-12-11 12:53:12 +00:00
|
|
|
if (tdata[0] <= 0 || tdata[0] > d->disc->sessions)
|
|
|
|
tdata[0] = d->disc->sessions;
|
|
|
|
if (tdata[3] < 100 && tdata[0] > 0) {
|
2006-08-15 20:37:04 +00:00
|
|
|
track = burn_track_create();
|
|
|
|
burn_session_add_track(d->disc->session[tdata[0] - 1],
|
|
|
|
track, BURN_POS_END);
|
|
|
|
track->entry = &d->toc_entry[i];
|
|
|
|
burn_track_free(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 |