[paranoia-dev] Paranoia IV
Mikko Nummelin
mnummeli at cc.hut.fi
Sat Apr 12 15:33:33 PDT 2003
On Sat, 12 Apr 2003, Laurent Pinchart wrote:
> Hi everybody,
>
> I'm currently trying to extract audio tracks from a protected audio disc.
>
> The disc contains a corrupted TOC, and some sectors contain errors.
>
> The TOC can be read properly by my Hitachi DVD drive, but not by my Plextor
> CD-RW driver. I modified CD Paranoia III 9.8 to get the TOC correctly on the
> CD-RW drive (using the READ TOC command, format Full TOC), and this works
> fine.
>
> I'm now trying to fix the erroneous sectors problem. The CD can be played on
> an audio CD player, so the data are not corrupted. I suspect the CIRC and/or
> Q sub-channel data to be corrupted, so that a 'smart' CD drive will fail to
> read the data.
>
> I'm thinking about setting the TB (Transfer Block) byte in the Error Recovery
> Parameters page to 1, so that the data will be transfered to the host even
> when an unrecoverable read error occured.
>
> I have several questions:
>
> 1) Is CD Paranoia still maintained ? If so, has anyone worked on the problems
> I described ? I don't want to fix things that are already fixed in CD
> Paranoia IV.
>
> 2) Does anyone know why some drives are able to read the TOC properly while
> other are not ? I suppose that's because the drives use different methods to
> read the TOC, but I'd appreciate a more detailed explaination.
>
> 3) Is there a way lower-level read command than READ CD ? Is there a way to
> read the 588 bits of the CD small frames ? Or a way to read the CIRC codes ?
>
> 4) A friend of mine has been able to read the audio tracks using Clone CD on a
> TEAC DW-224E drive, running Windows XP. Why are some drives able to read the
> sectors, while others are not ? Is there a difference in the CIRC
> implementation, with some drives being better at correcting errors than
> others ? Or does it mean that only the sub-channels information are corrupted
> and the CIRC is correct ? I'm really puzzled by that.
>
> Thanks for any information you can provide.
A Finnish hacker (whose name I don't provide without permission) sent a
patch to me solving this problem. It adds a new '-P' switch to
cdparanoia command, which allows ripping Cactus-protected CD's with
Plextor. It (a) changes the way TOC is read, (b) alters the reading command.
The patch is as follows:
----- 8< -----
diff -Nru cdparanoia-III-alpha9.8/interface/cdda_interface.h cdparanoia-III-alpha9.8P/interface/cdda_interface.h
--- cdparanoia-III-alpha9.8/interface/cdda_interface.h 2001-03-24 03:15:46.000000000 +0200
+++ cdparanoia-III-alpha9.8P/interface/cdda_interface.h 2003-03-15 18:07:43.000000000 +0200
@@ -126,7 +126,7 @@
extern char *cdda_errors(cdrom_drive *d);
extern int cdda_close(cdrom_drive *d);
-extern int cdda_open(cdrom_drive *d);
+extern int cdda_open(cdrom_drive *d, int protected);
extern long cdda_read(cdrom_drive *d, void *buffer,
long beginsector, long sectors);
diff -Nru cdparanoia-III-alpha9.8/interface/interface.c cdparanoia-III-alpha9.8P/interface/interface.c
--- cdparanoia-III-alpha9.8/interface/interface.c 2000-04-20 01:41:04.000000000 +0300
+++ cdparanoia-III-alpha9.8P/interface/interface.c 2003-03-15 18:07:43.000000000 +0200
@@ -42,13 +42,13 @@
}
/* finish initializing the drive! */
-int cdda_open(cdrom_drive *d){
+int cdda_open(cdrom_drive *d, int protected){
int ret;
if(d->opened)return(0);
switch(d->interface){
case GENERIC_SCSI:
- if((ret=scsi_init_drive(d)))
+ if((ret=scsi_init_drive(d, protected)))
return(ret);
break;
case COOKED_IOCTL:
diff -Nru cdparanoia-III-alpha9.8/interface/low_interface.h cdparanoia-III-alpha9.8P/interface/low_interface.h
--- cdparanoia-III-alpha9.8/interface/low_interface.h 2001-03-26 09:12:11.000000000 +0300
+++ cdparanoia-III-alpha9.8P/interface/low_interface.h 2003-03-15 18:07:43.000000000 +0200
@@ -65,7 +65,7 @@
extern int cooked_init_drive (cdrom_drive *d);
extern unsigned char *scsi_inquiry (cdrom_drive *d);
-extern int scsi_init_drive (cdrom_drive *d);
+extern int scsi_init_drive (cdrom_drive *d, int protected);
#ifdef CDDA_TEST
extern int test_init_drive (cdrom_drive *d);
#endif
diff -Nru cdparanoia-III-alpha9.8/interface/scsi_interface.c cdparanoia-III-alpha9.8P/interface/scsi_interface.c
--- cdparanoia-III-alpha9.8/interface/scsi_interface.c 2001-03-24 03:15:46.000000000 +0200
+++ cdparanoia-III-alpha9.8P/interface/scsi_interface.c 2003-03-15 18:07:43.000000000 +0200
@@ -600,6 +600,84 @@
return(tracks);
}
+/* Yeah, it may be a crude hack. All at once is really the only way to go,
+ kernel ioctl way can be fooled by copy protections, i.e. corrupted TOCs.
+ So, we'll read the whole thing and scan for audio tracks. */
+
+static int scsi_read_toc_hack (cdrom_drive *d){
+ int i,first,last;
+ unsigned tracks;
+
+ /* READTOC, MSF format flag, res, res, res, res, Start track, len msb,
+ len lsb, flags */
+
+ /* read the whole freakin' TOC */
+ memcpy(d->sg_buffer, (char []){ 0x43, 0, 2, 0, 0, 0, 0, 8, 0, 0}, 10);
+ d->sg_buffer[1]=d->lun<<5;
+
+ if (handle_scsi_cmd (d,10, 0, 2048,'\377',1)){
+ cderror(d,"004: Unable to read table of contents header\n");
+ return(-4);
+ }
+
+ {
+ unsigned short len = *(d->sg_buffer)*256 + *(d->sg_buffer+1);
+ unsigned char *ptr = d->sg_buffer+4;
+ unsigned char flag, track;
+ unsigned int msf;
+ unsigned int leadout = 0;
+ unsigned char leadout_flag = 0;
+ first = 100;
+ last = 0;
+ while (ptr < d->sg_buffer+2+len)
+ {
+ flag = *(ptr+1);
+ track = *(ptr+3);
+ if (track < 100)
+ {
+ if (track < first)
+ first = track;
+ else if (track > last)
+ last = track;
+ }
+ ptr += 11;
+ }
+
+ tracks=last-first+1;
+
+ if (last > MAXTRK || first > MAXTRK || last<0 || first<0) {
+ cderror(d,"003: CDROM reporting illegal number of tracks\n");
+ return(-3);
+ }
+
+ ptr = d->sg_buffer+4;
+ while (ptr < d->sg_buffer+2+len)
+ {
+ flag = *(ptr+1);
+ track = *(ptr+3);
+ msf = (*(ptr+8)*60 + *(ptr+9))*75 + *(ptr+10) - 150;
+ if (track < 100)
+ {
+ d->disc_toc[track-first].bFlags = flag;
+ d->disc_toc[track-first].bTrack = track;
+ d->disc_toc[track-first].dwStartSector = d->adjust_ssize * msf;
+ }
+ else if (track == 0xa2 && msf > leadout)
+ {
+ leadout = msf;
+ leadout_flag = flag;
+ }
+ ptr += 11;
+ }
+ d->disc_toc[last-first+1].bFlags = leadout_flag;
+ d->disc_toc[last-first+1].bTrack = 0xAA;
+ d->disc_toc[last-first+1].dwStartSector = d->adjust_ssize * leadout;
+ }
+
+ d->cd_extra = FixupTOC(d,tracks+1); /* include lead-out */
+ return(tracks);
+}
+
/* These do one 'extra' copy in the name of clean code */
static int i_read_28 (cdrom_drive *d, void *p, long begin, long sectors){
@@ -1391,7 +1469,7 @@
}
<p>-int scsi_init_drive(cdrom_drive *d){
+int scsi_init_drive(cdrom_drive *d, int protected){
int ret;
check_atapi(d);
@@ -1432,7 +1510,10 @@
sector size at 2048 to begin.*/
d->enable_cdda(d,0);
- d->read_toc = (!memcmp(d->drive_model, "IMS", 3) && !d->is_atapi) ? scsi_read_toc2 :
+ if (protected)
+ d->read_toc = scsi_read_toc_hack;
+ else
+ d->read_toc = (!memcmp(d->drive_model, "IMS", 3) && !d->is_atapi) ? scsi_read_toc2 :
scsi_read_toc;
d->set_speed = NULL;
@@ -1446,6 +1527,9 @@
d->adjust_ssize = 1;
}else
d->adjust_ssize = 1;
+
+ if (protected)
+ d->read_audio = scsi_read_D8;
d->tracks=d->read_toc(d);
if(d->tracks<1)
diff -Nru cdparanoia-III-alpha9.8/main.c cdparanoia-III-alpha9.8P/main.c
--- cdparanoia-III-alpha9.8/main.c 2001-03-26 06:44:50.000000000 +0300
+++ cdparanoia-III-alpha9.8P/main.c 2003-03-15 18:07:43.000000000 +0200
@@ -275,7 +275,9 @@
" retries without progress.\n"
" -Z --disable-paranoia : disable all paranoia checking\n"
" -Y --disable-extra-paranoia : only do cdda2wav-style overlap checking\n"
-" -X --abort-on-skip : abort on imperfect reads/skips\n\n"
+" -X --abort-on-skip : abort on imperfect reads/skips\n"
+" -P --protected : some workaround stuff for protected\n"
+" discs (SCSI only)\n\n"
"OUTPUT SMILIES:\n"
" :-) Normal operation, low/no jitter\n"
@@ -585,7 +587,7 @@
memset(dispcache,' ',graph);
}
-const char *optstring = "escCn:o:O:d:g:S:prRwafvqVQhZz::YXWBi:Tt:";
+const char *optstring = "escCn:o:O:d:g:S:prRwafvqVQhZz::YXWBi:Tt:P";
struct option options [] = {
{"stderr-progress",no_argument,NULL,'e'},
@@ -618,6 +620,7 @@
{"disable-fragmentation",no_argument,NULL,'F'},
{"output-info",required_argument,NULL,'i'},
{"never-skip",optional_argument,NULL,'z'},
+ {"protected",optional_argument,NULL,'P'},
{NULL,0,NULL,0}
};
@@ -661,6 +664,7 @@
int output_endian=0; /* -1=host, 0=little, 1=big */
int query_only=0;
int batch=0,i;
+ int protected=0;
/* full paranoia, but allow skipping */
int paranoia_mode=PARANOIA_MODE_FULL^PARANOIA_MODE_NEVERSKIP;
@@ -790,6 +794,9 @@
case 'O':
sample_offset=atoi(optarg);
break;
+ case 'P':
+ protected = 1;
+ break;
default:
usage(stderr);
exit(1);
@@ -896,7 +903,7 @@
}
}
- switch(cdda_open(d)){
+ switch(cdda_open(d, protected)){
case -2:case -3:case -4:case -5:
report("\nUnable to open disc. Is there an audio CD in the drive?");
exit(1);
----- 8< -----
<p>Mikko Nummelin
--- >8 ----
List archives: http://www.xiph.org/archives/
Paranoia homepage: http://www.xiph.org/paranoia/
To unsubscribe from this list, send mail to 'paranoia-dev-request at xiph.org'
containing only the word 'unsubscribe' in the body. No subject is needed.
Unsubscribe messages sent to the list will be ignored/filtered.
More information about the Paranoia-dev
mailing list