Index: cdparanoia-III-10.2-new/interface/cdda_interface.h
===================================================================
--- cdparanoia-III-10.2-new/interface/cdda_interface.h (nonexistent)
+++ cdparanoia-III-10.2-new/interface/cdda_interface.h (revision 5)
@@ -0,0 +1,207 @@
+/******************************************************************
+ * CopyPolicy: GNU Lesser General Public License 2.1 applies
+ * Copyright (C) 2001-2008 Xiph.org
+ * Original version by Heiko Eissfeldt heiko@escape.colossus.de
+ *
+ * Toplevel interface header; applications include this
+ *
+ ******************************************************************/
+
+#ifndef _cdda_interface_h_
+#define _cdda_interface_h_
+
+#ifndef CD_FRAMESIZE
+#define CD_FRAMESIZE 2048
+#endif
+#ifndef CD_FRAMESIZE_RAW
+#define CD_FRAMESIZE_RAW 2352
+#endif
+#define CD_FRAMESAMPLES (CD_FRAMESIZE_RAW / 4)
+
+#include <sys/types.h>
+#include <signal.h>
+
+#define MAXTRK 100
+
+typedef struct TOC { /* structure of table of contents */
+ unsigned char bFlags;
+ unsigned char bTrack;
+ int32_t dwStartSector;
+} TOC;
+
+/* interface types */
+#define GENERIC_SCSI 0
+#define COOKED_IOCTL 1
+#define TEST_INTERFACE 2
+#define SGIO_SCSI 3
+#define SGIO_SCSI_BUGGY1 4
+
+#define CDDA_MESSAGE_FORGETIT 0
+#define CDDA_MESSAGE_PRINTIT 1
+#define CDDA_MESSAGE_LOGIT 2
+
+/* cdrom access function pointer */
+
+typedef struct cdda_private_data cdda_private_data_t;
+
+typedef struct cdrom_drive{
+
+ int opened; /* This struct may just represent a candidate for opening */
+
+ char *cdda_device_name;
+ char *ioctl_device_name;
+
+ int cdda_fd;
+ int ioctl_fd;
+
+ char *drive_model;
+ int drive_type;
+ int interface;
+ int bigendianp;
+ int nsectors;
+
+ int cd_extra;
+ int tracks;
+ TOC disc_toc[MAXTRK];
+ long audio_first_sector;
+ long audio_last_sector;
+
+ int errordest;
+ int messagedest;
+ char *errorbuf;
+ char *messagebuf;
+
+ /* functions specific to particular drives/interfaces */
+
+ int (*enable_cdda) (struct cdrom_drive *d, int onoff);
+ int (*read_toc) (struct cdrom_drive *d);
+ long (*read_audio) (struct cdrom_drive *d, void *p, long begin,
+ long sectors);
+ int (*set_speed) (struct cdrom_drive *d, int speed);
+ int error_retry;
+ int report_all;
+
+ int is_atapi;
+ int is_mmc;
+
+ cdda_private_data_t *private_data;
+ void *reserved;
+ unsigned char inqbytes[4];
+
+ /* Scsi parameters and state */
+ unsigned char density;
+ unsigned char orgdens;
+ unsigned int orgsize;
+ long bigbuff;
+ int adjust_ssize;
+
+ int fua;
+ int lun;
+
+ sigset_t sigset;
+
+} cdrom_drive;
+
+#define IS_AUDIO(d,i) (!(d->disc_toc[i].bFlags & 0x04))
+
+/******** Identification/autosense functions */
+
+extern cdrom_drive *cdda_find_a_cdrom(int messagedest, char **message);
+extern cdrom_drive *cdda_identify(const char *device, int messagedest,
+ char **message);
+extern cdrom_drive *cdda_identify_cooked(const char *device,int messagedest,
+ char **message);
+extern cdrom_drive *cdda_identify_scsi(const char *generic_device,
+ const char *ioctl_device,
+ int messagedest, char **message);
+#ifdef CDDA_TEST
+extern cdrom_drive *cdda_identify_test(const char *filename,
+ int messagedest, char **message);
+#endif
+
+/******** Drive oriented functions */
+
+extern char *cdda_version();
+extern int cdda_speed_set(cdrom_drive *d, int speed);
+extern void cdda_verbose_set(cdrom_drive *d,int err_action, int mes_action);
+extern char *cdda_messages(cdrom_drive *d);
+extern char *cdda_errors(cdrom_drive *d);
+
+extern int cdda_close(cdrom_drive *d);
+extern int cdda_open(cdrom_drive *d);
+extern long cdda_read(cdrom_drive *d, void *buffer,
+ long beginsector, long sectors);
+extern long cdda_read_timed(cdrom_drive *d, void *buffer,
+ long beginsector, long sectors, int *milliseconds);
+
+extern long cdda_track_firstsector(cdrom_drive *d,int track);
+extern long cdda_track_lastsector(cdrom_drive *d,int track);
+extern long cdda_tracks(cdrom_drive *d);
+extern int cdda_sector_gettrack(cdrom_drive *d,long sector);
+extern int cdda_track_channels(cdrom_drive *d,int track);
+extern int cdda_track_audiop(cdrom_drive *d,int track);
+extern int cdda_track_copyp(cdrom_drive *d,int track);
+extern int cdda_track_preemp(cdrom_drive *d,int track);
+extern long cdda_disc_firstsector(cdrom_drive *d);
+extern long cdda_disc_lastsector(cdrom_drive *d);
+
+/* transport errors: */
+
+#define TR_OK 0
+#define TR_EWRITE 1 /* Error writing packet command (transport) */
+#define TR_EREAD 2 /* Error reading packet data (transport) */
+#define TR_UNDERRUN 3 /* Read underrun */
+#define TR_OVERRUN 4 /* Read overrun */
+#define TR_ILLEGAL 5 /* Illegal/rejected request */
+#define TR_MEDIUM 6 /* Medium error */
+#define TR_BUSY 7 /* Device busy */
+#define TR_NOTREADY 8 /* Device not ready */
+#define TR_FAULT 9 /* Devive failure */
+#define TR_UNKNOWN 10 /* Unspecified error */
+#define TR_STREAMING 11 /* loss of streaming */
+
+static char *strerror_tr[]={
+ "Success",
+ "Error writing packet command to device",
+ "Error reading command from device",
+ "SCSI packet data underrun (too little data)",
+ "SCSI packet data overrun (too much data)",
+ "Illegal SCSI request (rejected by target)",
+ "Medium reading data from medium",
+ "Device busy",
+ "Device not ready",
+ "Target hardware fault",
+ "Unspecified error",
+ "Drive lost streaming"
+};
+
+/* Errors returned by lib:
+
+001: Unable to set CDROM to read audio mode
+002: Unable to read table of contents lead-out
+003: CDROM reporting illegal number of tracks
+004: Unable to read table of contents header
+005: Unable to read table of contents entry
+006: Could not read any data from drive
+007: Unknown, unrecoverable error reading data
+008: Unable to identify CDROM model
+009: CDROM reporting illegal table of contents
+010: Unaddressable sector
+
+100: Interface not supported
+101: Drive is neither a CDROM nor a WORM device
+102: Permision denied on cdrom (ioctl) device
+103: Permision denied on cdrom (data) device
+
+300: Kernel memory error
+
+400: Device not open
+401: Invalid track number
+402: Track not audio data
+403: No audio tracks on disc
+404: No medium present
+405: Option not supported by drive
+
+*/
+#endif
+
Index: cdparanoia-III-10.2-new/interface/cooked_interface.c
===================================================================
--- cdparanoia-III-10.2-new/interface/cooked_interface.c (nonexistent)
+++ cdparanoia-III-10.2-new/interface/cooked_interface.c (revision 5)
@@ -0,0 +1,287 @@
+/******************************************************************
+ * CopyPolicy: GNU Lesser General Public License 2.1 applies
+ * Copyright (C) Monty xiphmont@mit.edu
+ *
+ * CDROM code specific to the cooked ioctl interface
+ *
+ ******************************************************************/
+
+#include "low_interface.h"
+#include "common_interface.h"
+#include "utils.h"
+#include <time.h>
+static int timed_ioctl(cdrom_drive *d, int fd, int command, void *arg){
+ struct timespec tv1;
+ struct timespec tv2;
+ int ret1=clock_gettime(d->private_data->clock,&tv1);
+ int ret2=ioctl(fd, command,arg);
+ int ret3=clock_gettime(d->private_data->clock,&tv2);
+ if(ret1<0 || ret3<0){
+ d->private_data->last_milliseconds=-1;
+ }else{
+ d->private_data->last_milliseconds = (tv2.tv_sec-tv1.tv_sec)*1000. + (tv2.tv_nsec-tv1.tv_nsec)/1000000.;
+ }
+ return ret2;
+}
+
+static int cooked_readtoc (cdrom_drive *d){
+ int i;
+ int tracks;
+ struct cdrom_tochdr hdr;
+ struct cdrom_tocentry entry;
+
+ /* get TocHeader to find out how many entries there are */
+ if(ioctl(d->ioctl_fd, CDROMREADTOCHDR, &hdr ))
+ switch(errno){
+ case EPERM:
+ cderror(d,"102: Permision denied on cdrom (ioctl) device\n");
+ return(-102);
+ default:
+ cderror(d,"004: Unable to read table of contents header\n");
+ return(-4);
+ }
+
+ /* get all TocEntries */
+ for(i=0;i<hdr.cdth_trk1;i++){
+ entry.cdte_track= i+1;
+ entry.cdte_format = CDROM_LBA;
+ if(ioctl(d->ioctl_fd,CDROMREADTOCENTRY,&entry)){
+ cderror(d,"005: Unable to read table of contents entry\n");
+ return(-5);
+ }
+
+ d->disc_toc[i].bFlags = (entry.cdte_adr << 4) | (entry.cdte_ctrl & 0x0f);
+ d->disc_toc[i].bTrack = i+1;
+ d->disc_toc[i].dwStartSector = entry.cdte_addr.lba;
+ }
+
+ entry.cdte_track = CDROM_LEADOUT;
+ entry.cdte_format = CDROM_LBA;
+ if(ioctl(d->ioctl_fd, CDROMREADTOCENTRY, &entry)){
+ cderror(d,"005: Unable to read table of contents entry\n");
+ return(-5);
+ }
+ d->disc_toc[i].bFlags = (entry.cdte_adr << 4) | (entry.cdte_ctrl & 0x0f);
+ d->disc_toc[i].bTrack = entry.cdte_track;
+ d->disc_toc[i].dwStartSector = entry.cdte_addr.lba;
+
+ tracks=hdr.cdth_trk1+1;
+ d->cd_extra=FixupTOC(d,tracks);
+ return(--tracks); /* without lead-out */
+}
+
+/* Set operating speed */
+static int cooked_setspeed(cdrom_drive *d, int speed)
+{
+ if(d->ioctl_fd!=-1)
+ return ioctl(d->ioctl_fd, CDROM_SELECT_SPEED, speed);
+ else
+ return 0;
+}
+
+/* read 'SectorBurst' adjacent sectors of audio sectors
+ * to Buffer '*p' beginning at sector 'lSector'
+ */
+
+static long cooked_read (cdrom_drive *d, void *p, long begin, long sectors){
+ int retry_count,err,ret=0;
+ struct cdrom_read_audio arg;
+ char *buffer=(char *)p;
+
+ /* read d->nsectors at a time, max. */
+ sectors=(sectors>d->nsectors?d->nsectors:sectors);
+ if(p==NULL)buffer = malloc(sectors*CD_FRAMESIZE_RAW);
+
+ arg.addr.lba = begin;
+ arg.addr_format = CDROM_LBA;
+ arg.nframes = sectors;
+ arg.buf=buffer;
+ retry_count=0;
+
+ do {
+ if((err=timed_ioctl(d,d->ioctl_fd, CDROMREADAUDIO, &arg))){
+ if(!d->error_retry){
+ ret=-7;
+ goto done;
+ }
+ switch(errno){
+ case ENOMEM:
+ /* D'oh. Possible kernel error. Keep limping */
+ if(sectors==1){
+ /* Nope, can't continue */
+ cderror(d,"300: Kernel memory error\n");
+ ret=-300;
+ goto done;
+ }
+ case ENXIO:
+ case EBADF:
+ case ENOMEDIUM:
+ errno=ENOMEDIUM;
+ ret=0;
+ goto done;
+ default:
+ if(sectors==1){
+
+
+ /* *Could* be I/O or media error. I think. If we're at
+ 30 retries, we better skip this unhappy little
+ sector. */
+ if(retry_count>MAX_RETRIES-1){
+ char b[256];
+ sprintf(b,"010: Unable to access sector %ld: skipping...\n",
+ begin);
+ cderror(d,b);
+ ret=-10;
+ goto done;
+ }
+ break;
+ }
+ }
+ if(retry_count>4)
+ if(sectors>1)
+ sectors=sectors*3/4;
+ retry_count++;
+ if(retry_count>MAX_RETRIES){
+ cderror(d,"007: Unknown, unrecoverable error reading data\n");
+ ret=-7;
+ goto done;
+ }
+ }else
+ break;
+ } while (err);
+
+ ret=sectors;
+
+ done:
+ if(p==NULL && buffer)free(buffer);
+ return ret;
+}
+
+/* hook */
+static int Dummy (cdrom_drive *d,int Switch){
+ return(0);
+}
+
+static int verify_read_command(cdrom_drive *d){
+ int i;
+ int16_t *buff=malloc(CD_FRAMESIZE_RAW);
+ int audioflag=0;
+
+ cdmessage(d,"Verifying drive can read CDDA...\n");
+
+ d->enable_cdda(d,1);
+
+ for(i=1;i<=d->tracks;i++){
+ if(cdda_track_audiop(d,i)==1){
+ long firstsector=cdda_track_firstsector(d,i);
+ long lastsector=cdda_track_lastsector(d,i);
+ long sector=(firstsector+lastsector)>>1;
+ audioflag=1;
+
+ if(d->read_audio(d,buff,sector,1)>0){
+ cdmessage(d,"\tExpected command set reads OK.\n");
+ d->enable_cdda(d,0);
+ free(buff);
+ return(0);
+ }
+ }
+ }
+
+ d->enable_cdda(d,0);
+
+ if(!audioflag){
+ cdmessage(d,"\tCould not find any audio tracks on this disk.\n");
+ return(-403);
+ }
+
+ cdmessage(d,"\n\tUnable to read any data; "
+ "drive probably not CDDA capable.\n");
+
+ cderror(d,"006: Could not read any data from drive\n");
+
+ free(buff);
+ return(-6);
+}
+
+#include "drive_exceptions.h"
+
+static void check_exceptions(cdrom_drive *d,exception *list){
+
+ int i=0;
+ while(list[i].model){
+ if(!strncmp(list[i].model,d->drive_model,strlen(list[i].model))){
+ if(list[i].bigendianp!=-1)d->bigendianp=list[i].bigendianp;
+ return;
+ }
+ i++;
+ }
+}
+
+/* set function pointers to use the ioctl routines */
+int cooked_init_drive (cdrom_drive *d){
+ int ret;
+
+ switch(d->drive_type){
+ case MATSUSHITA_CDROM_MAJOR: /* sbpcd 1 */
+ case MATSUSHITA_CDROM2_MAJOR: /* sbpcd 2 */
+ case MATSUSHITA_CDROM3_MAJOR: /* sbpcd 3 */
+ case MATSUSHITA_CDROM4_MAJOR: /* sbpcd 4 */
+ /* don't make the buffer too big; this sucker don't preempt */
+
+ cdmessage(d,"Attempting to set sbpcd buffer size...\n");
+
+ d->nsectors=8;
+ while(1){
+
+ /* this ioctl returns zero on error; exactly wrong, but that's
+ what it does. */
+
+ if(ioctl(d->ioctl_fd, CDROMAUDIOBUFSIZ, d->nsectors)==0){
+ d->nsectors>>=1;
+ if(d->nsectors==0){
+ char buffer[256];
+ d->nsectors=8;
+ sprintf(buffer,"\tTrouble setting buffer size. Defaulting to %d sectors.\n",
+ d->nsectors);
+ cdmessage(d,buffer);
+ break; /* Oh, well. Try to read anyway.*/
+ }
+ }else{
+ char buffer[256];
+ sprintf(buffer,"\tSetting read block size at %d sectors (%ld bytes).\n",
+ d->nsectors,(long)d->nsectors*CD_FRAMESIZE_RAW);
+ cdmessage(d,buffer);
+ break;
+ }
+ }
+
+ break;
+ case IDE0_MAJOR:
+ case IDE1_MAJOR:
+ case IDE2_MAJOR:
+ case IDE3_MAJOR:
+ d->nsectors=8; /* it's a define in the linux kernel; we have no
+ way of determining other than this guess tho */
+ d->bigendianp=0;
+ d->is_atapi=1;
+
+ check_exceptions(d,atapi_list);
+
+ break;
+ default:
+ d->nsectors=40;
+ }
+ d->enable_cdda = Dummy;
+ d->read_audio = cooked_read;
+ d->read_toc = cooked_readtoc;
+ d->set_speed = cooked_setspeed;
+ ret=d->tracks=d->read_toc(d);
+ if(d->tracks<1)
+ return(ret);
+
+ d->opened=1;
+ if((ret=verify_read_command(d)))return(ret);
+ d->error_retry=1;
+ return(0);
+}
+
Index: cdparanoia-III-10.2-new/interface/interface.c
===================================================================
--- cdparanoia-III-10.2-new/interface/interface.c (nonexistent)
+++ cdparanoia-III-10.2-new/interface/interface.c (revision 5)
@@ -0,0 +1,158 @@
+/******************************************************************
+ * CopyPolicy: GNU Lesser General Public License 2.1 applies
+ * Copyright (C) 1998-2008 Monty xiphmont@mit.edu
+ *
+ * Top-level interface module for cdrom drive access. SCSI, ATAPI, etc
+ * specific stuff are in other modules. Note that SCSI does use
+ * specialized ioctls; these appear in common_interface.c where the
+ * generic_scsi stuff is in scsi_interface.c.
+ *
+ ******************************************************************/
+
+#include "low_interface.h"
+#include "common_interface.h"
+#include "utils.h"
+#include "../version.h"
+
+char *cdda_version(void){
+ return VERSIONNUM;
+}
+
+static void _clean_messages(cdrom_drive *d){
+ if(d){
+ if(d->messagebuf)free(d->messagebuf);
+ if(d->errorbuf)free(d->errorbuf);
+ d->messagebuf=NULL;
+ d->errorbuf=NULL;
+ }
+}
+
+/* doubles as "cdrom_drive_free()" */
+int cdda_close(cdrom_drive *d){
+ if(d){
+ if(d->opened)
+ d->enable_cdda(d,0);
+
+ _clean_messages(d);
+ if(d->cdda_device_name)free(d->cdda_device_name);
+ if(d->ioctl_device_name)free(d->ioctl_device_name);
+ if(d->drive_model)free(d->drive_model);
+ if(d->cdda_fd!=-1)close(d->cdda_fd);
+ if(d->ioctl_fd!=-1 && d->ioctl_fd!=d->cdda_fd)close(d->ioctl_fd);
+ if(d->private_data){
+ if(d->private_data->sg_hd)free(d->private_data->sg_hd);
+ free(d->private_data);
+ }
+
+ free(d);
+ }
+ return(0);
+}
+
+/* finish initializing the drive! */
+int cdda_open(cdrom_drive *d){
+ int ret;
+ if(d->opened)return(0);
+
+ switch(d->interface){
+ case SGIO_SCSI_BUGGY1:
+ case SGIO_SCSI:
+ case GENERIC_SCSI:
+ if((ret=scsi_init_drive(d)))
+ return(ret);
+ break;
+ case COOKED_IOCTL:
+ if((ret=cooked_init_drive(d)))
+ return(ret);
+ break;
+#ifdef CDDA_TEST
+ case TEST_INTERFACE:
+ if((ret=test_init_drive(d)))
+ return(ret);
+ break;
+#endif
+ default:
+ cderror(d,"100: Interface not supported\n");
+ return(-100);
+ }
+
+ /* Check TOC, enable for CDDA */
+
+ /* Some drives happily return a TOC even if there is no disc... */
+ {
+ int i;
+ for(i=0;i<d->tracks;i++)
+ if(d->disc_toc[i].dwStartSector<0 ||
+ d->disc_toc[i+1].dwStartSector==0){
+ d->opened=0;
+ cderror(d,"009: CDROM reporting illegal table of contents\n");
+ return(-9);
+ }
+ }
+
+ if((ret=d->enable_cdda(d,1)))
+ return(ret);
+
+ /* d->select_speed(d,d->maxspeed); most drives are full speed by default */
+ if(d->bigendianp==-1)d->bigendianp=data_bigendianp(d);
+ return(0);
+}
+
+int cdda_speed_set(cdrom_drive *d, int speed)
+{
+ if(d->set_speed)
+ if(!d->set_speed(d,speed))return 0;
+
+ cderror(d,"405: Option not supported by drive\n");
+ return -405;
+}
+
+long cdda_read_timed(cdrom_drive *d, void *buffer, long beginsector, long sectors, int *ms){
+ if(ms)*ms= -1;
+ if(d->opened){
+ if(sectors>0){
+ sectors=d->read_audio(d,buffer,beginsector,sectors);
+
+ if(sectors>0){
+ /* byteswap? */
+ if(d->bigendianp==-1) /* not determined yet */
+ d->bigendianp=data_bigendianp(d);
+
+ if(d->bigendianp!=bigendianp()){
+ int i;
+ u_int16_t *p=(u_int16_t *)buffer;
+ long els=sectors*CD_FRAMESIZE_RAW/2;
+
+ for(i=0;i<els;i++)p[i]=swap16(p[i]);
+ }
+ }
+ }
+ if(ms)*ms=d->private_data->last_milliseconds;
+ return(sectors);
+ }
+
+ cderror(d,"400: Device not open\n");
+ return(-400);
+}
+
+long cdda_read(cdrom_drive *d, void *buffer, long beginsector, long sectors){
+ return cdda_read_timed(d,buffer,beginsector,sectors,NULL);
+}
+
+void cdda_verbose_set(cdrom_drive *d,int err_action, int mes_action){
+ d->messagedest=mes_action;
+ d->errordest=err_action;
+}
+
+extern char *cdda_messages(cdrom_drive *d){
+ char *ret=d->messagebuf;
+ d->messagebuf=NULL;
+ return(ret);
+}
+
+extern char *cdda_errors(cdrom_drive *d){
+ char *ret=d->errorbuf;
+ d->errorbuf=NULL;
+ return(ret);
+}
+
Index: cdparanoia-III-10.2-new/interface/scan_devices.c
===================================================================
--- cdparanoia-III-10.2-new/interface/scan_devices.c (nonexistent)
+++ cdparanoia-III-10.2-new/interface/scan_devices.c (revision 5)
@@ -0,0 +1,831 @@
+/******************************************************************
+ * CopyPolicy: GNU Lesser General Public License 2.1 applies
+ * Copyright (C) 1998-2008 Monty xiphmont@mit.edu
+ *
+ * Autoscan for or verify presence of a cdrom device
+ *
+ ******************************************************************/
+
+#define _GNU_SOURCE /* get cuserid */
+#define _USE_XOPEN /* get cuserid */
+#include <limits.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <pwd.h>
+#include <time.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include "cdda_interface.h"
+#include "low_interface.h"
+#include "common_interface.h"
+#include "utils.h"
+
+#define MAX_DEV_LEN 20 /* Safe because strings only come from below */
+/* must be absolute paths! */
+static char *scsi_cdrom_prefixes[]={
+ "/dev/scd",
+ "/dev/sr",
+ NULL};
+static char *scsi_generic_prefixes[]={
+ "/dev/sg",
+ NULL};
+
+static char *devfs_scsi_test="/dev/scsi/";
+static char *devfs_scsi_cd="cd";
+static char *devfs_scsi_generic="generic";
+
+static char *cdrom_devices[]={
+ "/dev/cdrom",
+ "/dev/cdroms/cdrom?",
+ "/dev/hd?",
+ "/dev/sg?",
+ "/dev/cdu31a",
+ "/dev/cdu535",
+ "/dev/sbpcd",
+ "/dev/sbpcd?",
+ "/dev/sonycd",
+ "/dev/mcd",
+ "/dev/sjcd",
+ /* "/dev/aztcd", timeout is too long */
+ "/dev/cm206cd",
+ "/dev/gscd",
+ "/dev/optcd",NULL};
+
+/* Functions here look for a cdrom drive; full init of a drive type
+ happens in interface.c */
+
+cdrom_drive *cdda_find_a_cdrom(int messagedest,char **messages){
+ /* Brute force... */
+
+ int i=0;
+ cdrom_drive *d;
+
+ while(cdrom_devices[i]!=NULL){
+
+ /* is it a name or a pattern? */
+ char *pos;
+ if((pos=strchr(cdrom_devices[i],'?'))){
+ int j;
+ /* try first eight of each device */
+ for(j=0;j<4;j++){
+ char *buffer=copystring(cdrom_devices[i]);
+
+ /* number, then letter */
+
+ buffer[pos-(cdrom_devices[i])]=j+48;
+ if((d=cdda_identify(buffer,messagedest,messages)))
+ return(d);
+ idmessage(messagedest,messages,"",NULL);
+ buffer[pos-(cdrom_devices[i])]=j+97;
+ if((d=cdda_identify(buffer,messagedest,messages)))
+ return(d);
+ idmessage(messagedest,messages,"",NULL);
+ }
+ }else{
+ /* Name. Go for it. */
+ if((d=cdda_identify(cdrom_devices[i],messagedest,messages)))
+ return(d);
+
+ idmessage(messagedest,messages,"",NULL);
+ }
+ i++;
+ }
+ idmessage(messagedest,messages,
+ "\n\nNo cdrom drives accessible to %s found.\n",
+ cuserid(NULL));
+ return(NULL);
+}
+
+cdrom_drive *cdda_identify(const char *device, int messagedest,char **messages){
+ struct stat st;
+ cdrom_drive *d=NULL;
+
+ idmessage(messagedest,messages,"Checking %s for cdrom...",device);
+
+ if(stat(device,&st)){
+ idperror(messagedest,messages,"\tCould not stat %s",device);
+ return(NULL);
+ }
+
+#ifndef CDDA_TEST
+ if (!S_ISCHR(st.st_mode) &&
+ !S_ISBLK(st.st_mode)){
+ idmessage(messagedest,messages,"\t%s is not a block or character device",device);
+ return(NULL);
+ }
+#endif
+
+ /* an IDE device may have scsi-ide support, SG_IO support and cooked
+ support. Prefer the SCSI variants, they give the most control */
+ d=cdda_identify_scsi(NULL,device,messagedest,messages);
+ if(!d)d=cdda_identify_cooked(device,messagedest,messages);
+
+#ifdef CDDA_TEST
+ if(!d)d=cdda_identify_test(device,messagedest,messages);
+#endif
+
+ return(d);
+}
+
+char *test_resolve_symlink(const char *file,int messagedest,char **messages){
+ char resolved[PATH_MAX];
+ struct stat st;
+ if(lstat(file,&st)){
+ idperror(messagedest,messages,"\t\tCould not stat %s",file);
+ return(NULL);
+ }
+
+ if(realpath(file,resolved))
+ return(strdup(resolved));
+
+ idperror(messagedest,messages,"\t\tCould not resolve symlink %s",file);
+ return(NULL);
+
+}
+
+cdrom_drive *cdda_identify_cooked(const char *dev, int messagedest,
+ char **messages){
+
+ cdrom_drive *d=NULL;
+ struct stat st;
+ int fd=-1, i;
+ int type;
+ char *description=NULL;
+ char *device;
+
+ idmessage(messagedest,messages,"\tTesting %s for cooked ioctl() interface",dev);
+
+ device=test_resolve_symlink(dev,messagedest,messages);
+ if(device==NULL)return(NULL);
+
+ if(stat(device,&st)){
+ idperror(messagedest,messages,"\t\tCould not stat %s",device);
+ free(device);
+ return(NULL);
+ }
+
+ if (!S_ISCHR(st.st_mode) &&
+ !S_ISBLK(st.st_mode)){
+ idmessage(messagedest,messages,"\t\t%s is not a block or character device",device);
+ free(device);
+ return(NULL);
+ }
+
+ type=(int)(st.st_rdev>>8);
+ switch (type) {
+ case IDE0_MAJOR:
+ case IDE1_MAJOR:
+ case IDE2_MAJOR:
+ case IDE3_MAJOR:
+ /* Yay, ATAPI... */
+ /* Ping for CDROM-ness */
+
+ fd=open(device,O_RDONLY|O_NONBLOCK);
+ if(fd==-1){
+ idperror(messagedest,messages,"\t\tUnable to open %s",device);
+ free(device);
+ return(NULL);
+ }
+
+ if(ioctl_ping_cdrom(fd)){
+ idmessage(messagedest,messages,"\t\tDevice %s is not a CDROM",device);
+ close(fd);
+ free(device);
+ return(NULL);
+ }
+ {
+ char *temp=atapi_drive_info(fd);
+ description=catstring(NULL,"ATAPI compatible ");
+ description=catstring(description,temp);
+ free(temp);
+ }
+
+ break;
+ case CDU31A_CDROM_MAJOR:
+ /* major indicates this is a cdrom; no ping necessary. */
+ description=copystring("Sony CDU31A or compatible");
+ break;
+ case CDU535_CDROM_MAJOR:
+ /* major indicates this is a cdrom; no ping necessary. */
+ description=copystring("Sony CDU535 or compatible");
+ break;
+
+ case MATSUSHITA_CDROM_MAJOR:
+ case MATSUSHITA_CDROM2_MAJOR:
+ case MATSUSHITA_CDROM3_MAJOR:
+ case MATSUSHITA_CDROM4_MAJOR:
+ /* major indicates this is a cdrom; no ping necessary. */
+ description=copystring("non-ATAPI IDE-style Matsushita/Panasonic CR-5xx or compatible");
+ break;
+ case SANYO_CDROM_MAJOR:
+ description=copystring("Sanyo proprietary or compatible: NOT CDDA CAPABLE");
+ break;
+ case MITSUMI_CDROM_MAJOR:
+ case MITSUMI_X_CDROM_MAJOR:
+ description=copystring("Mitsumi proprietary or compatible: NOT CDDA CAPABLE");
+ break;
+ case OPTICS_CDROM_MAJOR:
+ description=copystring("Optics Dolphin or compatible: NOT CDDA CAPABLE");
+ break;
+ case AZTECH_CDROM_MAJOR:
+ description=copystring("Aztech proprietary or compatible: NOT CDDA CAPABLE");
+ break;
+ case GOLDSTAR_CDROM_MAJOR:
+ description=copystring("Goldstar proprietary: NOT CDDA CAPABLE");
+ break;
+ case CM206_CDROM_MAJOR:
+ description=copystring("Philips/LMS CM206 proprietary: NOT CDDA CAPABLE");
+ break;
+
+ case SCSI_CDROM_MAJOR:
+ case SCSI_GENERIC_MAJOR:
+ /* Nope nope nope */
+ idmessage(messagedest,messages,"\t\t%s is not a cooked ioctl CDROM.",device);
+ free(device);
+ return(NULL);
+ default:
+ /* What the hell is this? */
+ idmessage(messagedest,messages,"\t\t%s is not a cooked ioctl CDROM.",device);
+ free(device);
+ return(NULL);
+ }
+
+ /* Minimum init */
+
+ d=calloc(1,sizeof(cdrom_drive));
+ d->cdda_device_name=device;
+ d->ioctl_device_name=copystring(device);
+ d->drive_model=description;
+ d->drive_type=type;
+ d->cdda_fd=fd;
+ d->ioctl_fd=fd;
+ d->interface=COOKED_IOCTL;
+ d->bigendianp=-1; /* We don't know yet... */
+ d->nsectors=-1;
+ d->private_data=calloc(1,sizeof(*d->private_data));
+ {
+ /* goddamnit */
+ struct timespec tv;
+ d->private_data->clock=(clock_gettime(CLOCK_MONOTONIC,&tv)<0?CLOCK_REALTIME:CLOCK_MONOTONIC);
+ }
+ idmessage(messagedest,messages,"\t\tCDROM sensed: %s\n",description);
+ return(d);
+}
+
+struct sg_id {
+ long l1; /* target | lun << 8 | channel << 16 | low_ino << 24 */
+ long l2; /* Unique id */
+} sg_id;
+
+typedef struct scsiid{
+ int bus;
+ int id;
+ int lun;
+} scsiid;
+
+/* Even *this* isn't as simple as it bloody well should be :-P */
+/* SG has an easy interface, but SCSI overall does not */
+static int get_scsi_id(int fd, scsiid *id){
+ struct sg_id argid;
+ int busarg;
+
+ /* get the host/id/lun */
+
+ if(fd==-1)return(-1);
+ if(ioctl(fd,SCSI_IOCTL_GET_IDLUN,&argid))return(-1);
+ id->bus=argid.l2; /* for now */
+ id->id=argid.l1&0xff;
+ id->lun=(argid.l1>>8)&0xff;
+
+ if(ioctl(fd,SCSI_IOCTL_GET_BUS_NUMBER,&busarg)==0)
+ id->bus=busarg;
+
+ return(0);
+}
+
+/* slightly wasteful, but a clean abstraction */
+static char *scsi_match(const char *device,char **prefixes,
+ char *devfs_test,
+ char *devfs_other,
+ char *prompt,int messagedest,char **messages){
+ int dev=open(device,O_RDONLY|O_NONBLOCK);
+ scsiid a,b;
+
+ int i,j;
+ char buffer[200];
+
+ /* if we're running under /devfs, build the device name from the
+ device we already have */
+ if(!strncmp(device,devfs_test,strlen(devfs_test))){
+ char *pos;
+ strcpy(buffer,device);
+ pos=strrchr(buffer,'/');
+ if(pos){
+ int matchf;
+ sprintf(pos,"/%s",devfs_other);
+ matchf=open(buffer,O_RDONLY|O_NONBLOCK);
+ for (i = 0; (i<10) && (matchf==-1); i++) {
+ fprintf(stderr, "Error trying to open %s exclusively (%s). retrying in 1 seconds.\n", buffer, strerror(errno));
+ usleep(1000000 + 100000.0 * rand()/(RAND_MAX+1.0));
+ matchf = open(buffer,O_RDONLY|O_NONBLOCK);
+ }
+ if(matchf!=-1){
+ close(matchf);
+ close(dev);
+ return(strdup(buffer));
+ }
+ }
+ }
+
+ /* get the host/id/lun */
+ if(dev==-1){
+ idperror(messagedest,messages,"\t\tCould not access device %s",
+ device);
+
+ goto matchfail;
+ }
+ if(get_scsi_id(dev,&a)){
+ idperror(messagedest,messages,"\t\tDevice %s could not perform ioctl()",
+ device);
+
+ goto matchfail;
+ }
+
+ /* go through most likely /dev nodes for a match */
+ for(i=0;i<25;i++){
+ for(j=0;j<2;j++){
+ int pattern=0;
+ int matchf, k;
+
+ while(prefixes[pattern]!=NULL){
+ switch(j){
+ case 0:
+ /* number */
+ sprintf(buffer,"%s%d",prefixes[pattern],i);
+ break;
+ case 1:
+ /* number */
+ sprintf(buffer,"%s%c",prefixes[pattern],i+'a');
+ break;
+ }
+
+ matchf=open(buffer,O_RDONLY|O_NONBLOCK);
+ for (k = 0; (k<10) && (matchf==-1); k++) {
+ fprintf(stderr, "Error trying to open %s exclusively (%s). retrying in 1 second.\n", buffer, strerror(errno));
+ usleep(1000000 + 100000.0 * rand()/(RAND_MAX+1.0));
+ matchf=open(buffer,O_RDONLY|O_NONBLOCK);
+ }
+
+ if(matchf!=-1){
+ if(get_scsi_id(matchf,&b)==0){
+ if(a.bus==b.bus && a.id==b.id && a.lun==b.lun){
+ close(matchf);
+ close(dev);
+ return(strdup(buffer));
+ }
+ }
+ close(matchf);
+ }
+ pattern++;
+ }
+ }
+ }
+
+ idmessage(messagedest,messages,prompt,device);
+
+matchfail:
+
+ if(dev!=-1)close(dev);
+ return(NULL);
+}
+
+void strscat(char *a,char *b,int n){
+ int i;
+
+ for(i=n;i>0;i--)
+ if(b[i-1]>' ')break;
+
+ strncat(a,b,i);
+ strcat(a," ");
+}
+
+/* At this point, we're going to punt compatability before SG2, and
+ allow only SG2 and SG3 */
+static int verify_SG_version(cdrom_drive *d,int messagedest,
+ char **messages){
+ /* are we using the new SG driver by Doug Gilbert? If not, punt */
+ int version,major,minor;
+ char buffer[256];
+ idmessage(messagedest,messages,
+ "\nFound an accessible SCSI CDROM drive."
+ "\nLooking at revision of the SG interface in use...","");
+
+ if(ioctl(d->cdda_fd,SG_GET_VERSION_NUM,&version)){
+ /* Up, guess not. */
+ idmessage(messagedest,messages,
+ "\tOOPS! Old 2.0/early 2.1/early 2.2.x (non-ac patch) style "
+ "SG.\n\tCdparanoia no longer supports the old interface.\n","");
+ return(0);
+ }
+ major=version/10000;
+ version-=major*10000;
+ minor=version/100;
+ version-=minor*100;
+
+ sprintf(buffer,"\tSG interface version %d.%d.%d; OK.",
+ major,minor,version);
+
+ idmessage(messagedest,messages,buffer,"");
+ return(major);
+}
+
+int check_sgio(const char *device, int messagedest, char **messages){
+ int fd;
+ struct sg_io_hdr hdr;
+
+ if (!device) return 0;
+
+ /* we don't really care what type of device it is -- if it can do
+ * SG_IO, then we'll put it through the normal mmc/atapi/etc tests
+ * later, but it's good enough for now. */
+ fd = open(device, O_RDWR|O_NONBLOCK);
+ if (fd < 0){
+ idperror(messagedest,messages,
+ "\t\tCould not access device %s to test for SG_IO support",device);
+ return 0;
+ }
+
+ memset(&hdr, 0, sizeof (struct sg_io_hdr));
+ /* First try with interface_id = 'A'; for all but the sg case,
+ * that'll get us a -EINVAL if it supports SG_IO, and some other
+ * error for all other cases. */
+ hdr.interface_id = 'A';
+ if (ioctl(fd, SG_IO, &hdr)) {
+ switch (errno) {
+ case EINVAL: /* sr and ata give us EINVAL when SG_IO is
+ * supported but interface_id is bad. */
+
+ case ENOSYS: /* sg gives us ENOSYS when SG_IO is supported but
+ * interface_id is bad. IMHO, this is wrong and
+ * needs fixing in the kernel. */
+
+ close(fd);
+ return 1;
+
+ default: /* everything else gives ENOTTY, I think. I'm just
+ * going to be paranoid and reject everything else. */
+
+ close(fd);
+ return 0;
+
+ }
+ }
+ /* if we get here, something is dreadfuly wrong. ioctl(fd,SG_IO,&hdr)
+ * handled SG_IO, but took hdr.interface_id = 'A' as valid, and an empty
+ * command as good. Don't trust it. */
+ close(fd);
+ return 0;
+}
+
+/* scanning is always done by specifying a device name in
+ specialized_device; generic_device is only filled when the generic device
+ force option is used, and in that case, use of SG (not SGIO) should indeed be
+ forced */
+cdrom_drive *cdda_identify_scsi(const char *generic_device,
+ const char *specialized_device, int messagedest,
+ char **messages){
+
+ cdrom_drive *d=NULL;
+ struct stat i_st;
+ struct stat g_st;
+ int use_sgio=1;
+ int i_fd=-1, i;
+ int g_fd=-1;
+ int version;
+ int type;
+ char *p;
+
+ if(generic_device)
+ idmessage(messagedest,messages,"\tTesting %s for SCSI/MMC interface",
+ generic_device);
+ else
+ if(specialized_device)
+ idmessage(messagedest,messages,"\tTesting %s for SCSI/MMC interface",
+ specialized_device);
+
+
+ if(generic_device){
+ use_sgio = 0;
+ idmessage(messagedest,messages,"\t\tgeneric device forced; not testing for SG_IO interface",
+ generic_device);
+
+ if(stat(generic_device,&g_st)){
+ idperror(messagedest,messages,"\t\tCould not access device %s",
+ generic_device);
+ return(NULL);
+ }
+
+ if((int)(g_st.st_rdev>>8)!=SCSI_GENERIC_MAJOR){
+ idmessage(messagedest,messages,"\t\t%s is not a generic SCSI device",
+ generic_device);
+ return(NULL);
+ }
+ }
+
+ if(specialized_device){
+ if(stat(specialized_device,&i_st)){
+ idperror(messagedest,messages,"\t\tCould not access device %s",
+ specialized_device);
+ return(NULL);
+ }
+ }
+
+ /* we need to resolve any symlinks for the lookup code to work */
+
+ if(generic_device){
+ generic_device=test_resolve_symlink(generic_device,messagedest,messages);
+ if(generic_device==NULL)goto cdda_identify_scsi_fail;
+ }
+ if(specialized_device){
+ specialized_device=test_resolve_symlink(specialized_device,messagedest,messages);
+ if(specialized_device==NULL)goto cdda_identify_scsi_fail;
+ }
+
+ /* sgio is always preferred if it's there, unless user has forced the generic scsi device name */
+ if(use_sgio){
+ if(check_sgio(specialized_device,messagedest,messages)){
+ idmessage(messagedest,messages,"\t\tSG_IO device: %s",specialized_device);
+ }else{
+ idmessage(messagedest,messages,"\t\tno SG_IO support for device: %s",specialized_device);
+ use_sgio=0;
+ }
+ }
+
+ if(!use_sgio){
+
+ /* was a generic device passed in as the specialized device name? */
+ if(specialized_device){
+ if((int)(i_st.st_rdev>>8)==SCSI_GENERIC_MAJOR){
+ char *temp=(char *)generic_device;
+ generic_device=specialized_device;
+ specialized_device=temp;
+ }
+
+ if(!generic_device || !specialized_device){
+ if(generic_device){
+ specialized_device=
+ scsi_match(generic_device,scsi_cdrom_prefixes,
+ devfs_scsi_test,devfs_scsi_cd,
+ "\t\tNo cdrom device found to match generic device %s",
+ messagedest,messages);
+ }else{
+ generic_device=
+ scsi_match(specialized_device,scsi_generic_prefixes,
+ devfs_scsi_test,devfs_scsi_generic,
+ "\t\tNo generic SCSI device found to match CDROM device %s",
+ messagedest,messages);
+ if(!generic_device)
+ goto cdda_identify_scsi_fail;
+ }
+ }
+ }
+
+ idmessage(messagedest,messages,"\t\tgeneric device: %s",generic_device);
+ idmessage(messagedest,messages,"\t\tioctl device: %s",(specialized_device?
+ specialized_device:
+ "not found"));
+ if(specialized_device){
+ if(stat(specialized_device,&i_st)){
+ idperror(messagedest,messages,"\t\tCould not access cdrom device "
+ "%s",specialized_device);
+ goto cdda_identify_scsi_fail;
+ }
+ }
+
+ if(stat(generic_device,&g_st)){
+ idperror(messagedest,messages,"\t\tCould not access generic SCSI device "
+ "%s",generic_device);
+
+ goto cdda_identify_scsi_fail;
+ }
+ }
+
+ if(specialized_device) {
+ if(use_sgio)
+ i_fd=open(specialized_device,O_RDWR|O_NONBLOCK);
+ else
+ i_fd=open(specialized_device,O_RDONLY|O_NONBLOCK);
+ }
+
+ if(generic_device)
+ g_fd=open(generic_device,O_RDWR);
+
+
+ if(specialized_device && i_fd==-1){
+ idperror(messagedest,messages,"\t\tCould not open cdrom device "
+ "%s (continuing)",specialized_device);
+ goto cdda_identify_scsi_fail;
+ }
+
+ if(generic_device && g_fd==-1){
+ idperror(messagedest,messages,"\t\tCould not open generic SCSI device "
+ "%s",generic_device);
+ goto cdda_identify_scsi_fail;
+ }
+
+ if(i_fd!=-1){
+ type=(int)(i_st.st_rdev>>8);
+
+ if(!use_sgio){
+ if(type==SCSI_CDROM_MAJOR){
+ if (!S_ISBLK(i_st.st_mode)) {
+ idmessage(messagedest,messages,"\t\tSCSI CDROM device %s not a "
+ "block device",specialized_device);
+ goto cdda_identify_scsi_fail;
+ }
+ }else{
+ idmessage(messagedest,messages,"\t\tSCSI CDROM device %s has wrong "
+ "major number",specialized_device);
+ goto cdda_identify_scsi_fail;
+ }
+ }
+ }
+
+ if(g_fd != -1){
+ if((int)(g_st.st_rdev>>8)==SCSI_GENERIC_MAJOR){
+ if (!S_ISCHR(g_st.st_mode)) {
+ idmessage(messagedest,messages,"\t\tGeneric SCSI device %s not a "
+ "char device",generic_device);
+ goto cdda_identify_scsi_fail;
+ }
+ }else{
+ idmessage(messagedest,messages,"\t\tGeneric SCSI device %s has wrong "
+ "major number",generic_device);
+ goto cdda_identify_scsi_fail;
+ }
+ }
+
+ d=calloc(1,sizeof(cdrom_drive));
+ d->drive_type=type;
+ d->cdda_fd=g_fd;
+ d->ioctl_fd=i_fd;
+ d->bigendianp=-1; /* We don't know yet... */
+ d->nsectors=-1;
+ d->messagedest = messagedest;
+ d->private_data=calloc(1,sizeof(*d->private_data));
+ {
+ /* goddamnit */
+ struct timespec tv;
+ d->private_data->clock=(clock_gettime(CLOCK_MONOTONIC,&tv)<0?CLOCK_REALTIME:CLOCK_MONOTONIC);
+ }
+ if(use_sgio){
+ d->interface=SGIO_SCSI;
+ d->private_data->sg_buffer=(unsigned char *)(d->private_data->sg_hd=malloc(MAX_BIG_BUFF_SIZE));
+ g_fd=d->cdda_fd=dup(d->ioctl_fd);
+ }else{
+ version=verify_SG_version(d,messagedest,messages);
+ switch(version){
+ case -1:case 0:case 1:
+ d->interface=GENERIC_SCSI;
+ goto cdda_identify_scsi_fail;
+ case 2:case 3:
+ d->interface=GENERIC_SCSI;
+ break;
+ }
+
+ /* malloc our big buffer for scsi commands */
+ d->private_data->sg_hd=malloc(MAX_BIG_BUFF_SIZE);
+ d->private_data->sg_buffer=((unsigned char *)d->private_data->sg_hd)+SG_OFF;
+ }
+
+ {
+ /* get the lun */
+ scsiid lun;
+ if(get_scsi_id(i_fd,&lun))
+ d->lun=0; /* a reasonable guess on a failed ioctl */
+ else
+ d->lun=lun.lun;
+ }
+
+ p = (char *)scsi_inquiry(d);
+
+ if (!p){
+
+ /* 2.6 kernels have a bug where the block layer implements
+ SG_DXFER_TO_FROM_DEVICE as a write operation instead of read.
+ I've submitted a kernel patch, but it will take a while to
+ propogate. Work around it for now. --Monty */
+
+ if(d->interface == SGIO_SCSI){
+ /* test the inquiry with the workaround */
+ d->interface = SGIO_SCSI_BUGGY1;
+ p = (char *)scsi_inquiry(d);
+
+ if(p){
+ idmessage(messagedest,messages,
+ "\t\tThis kernel's block layer has a buggy SG_DXFER_TO_FROM_DEVICE;\n\t\t activating workaround.\n",NULL);
+ }else{
+ /* Failed for some reason other than the buggy ioctl(); set the interface type back */
+ d->interface = SGIO_SCSI;
+ }
+ }
+ }
+
+ if (!p){
+ idmessage(messagedest,messages,
+ "\t\tInquiry command failed; unable to probe drive\n",NULL);
+ goto cdda_identify_scsi_fail;
+ }
+
+ /* It would seem some TOSHIBA CDROMs gets things wrong */
+ if (p &&
+ !strncmp (p + 8, "TOSHIBA", 7) &&
+ !strncmp (p + 16, "CD-ROM", 6) &&
+ p[0] == TYPE_DISK) {
+ p[0] = TYPE_ROM;
+ p[1] |= 0x80; /* removable */
+ }
+
+ if (*p != TYPE_ROM && *p != TYPE_WORM) {
+ idmessage(messagedest,messages,
+ "\t\tDrive is neither a CDROM nor a WORM device\n",NULL);
+ goto cdda_identify_scsi_fail;
+ }
+
+ d->drive_model=calloc(36,1);
+ memcpy(d->inqbytes,p,4);
+ d->cdda_device_name=copystring(generic_device);
+ d->ioctl_device_name=copystring(specialized_device);
+ d->drive_model=calloc(36,1);
+ strscat(d->drive_model,p+8,8);
+ strscat(d->drive_model,p+16,16);
+ strscat(d->drive_model,p+32,4);
+
+ idmessage(messagedest,messages,"\nCDROM model sensed sensed: %s",d->drive_model);
+ return(d);
+
+cdda_identify_scsi_fail:
+ if(generic_device)free((char *)generic_device);
+ if(specialized_device)free((char *)specialized_device);
+ if(i_fd!=-1)close(i_fd);
+ if(g_fd!=-1)close(g_fd);
+ if(d){
+ if(d->private_data){
+ if(d->private_data->sg_hd)free(d->private_data->sg_hd);
+ free(d->private_data);
+ }
+ free(d);
+ }
+ return(NULL);
+}
+
+#ifdef CDDA_TEST
+
+cdrom_drive *cdda_identify_test(const char *filename, int messagedest,
+ char **messages){
+
+ cdrom_drive *d=NULL;
+ struct stat st;
+ int fd=-1,i;
+
+ idmessage(messagedest,messages,"\tTesting %s for file/test interface",
+ filename);
+
+ if(stat(filename,&st)){
+ idperror(messagedest,messages,"\t\tCould not access file %s",
+ filename);
+ return(NULL);
+ }
+
+ if(!S_ISREG(st.st_mode)){
+ idmessage(messagedest,messages,"\t\t%s is not a regular file",
+ filename);
+ return(NULL);
+ }
+
+ fd=open(filename,O_RDONLY);
+ if(fd==-1){
+ idperror(messagedest,messages,"\t\tCould not open file %s",filename);
+ return(NULL);
+ }
+
+ d=calloc(1,sizeof(cdrom_drive));
+
+ d->cdda_device_name=copystring(filename);
+ d->ioctl_device_name=copystring(filename);
+ d->drive_type=-1;
+ d->cdda_fd=fd;
+ d->ioctl_fd=fd;
+ d->interface=TEST_INTERFACE;
+ d->bigendianp=-1; /* We don't know yet... */
+ d->nsectors=-1;
+ d->private_data=calloc(1,sizeof(*d->private_data));
+ d->drive_model=copystring("File based test interface");
+ idmessage(messagedest,messages,"\t\tCDROM sensed: %s\n",d->drive_model);
+
+ return(d);
+}
+
+#endif
Index: cdparanoia-III-10.2-new/interface/scsi_interface.c
===================================================================
--- cdparanoia-III-10.2-new/interface/scsi_interface.c (nonexistent)
+++ cdparanoia-III-10.2-new/interface/scsi_interface.c (revision 5)
@@ -0,0 +1,1750 @@
+/******************************************************************
+ * CopyPolicy: GNU Lesser General Public License 2.1 applies
+ * Original interface.c Copyright (C) 1994-1997
+ * Eissfeldt heiko@colossus.escape.de
+ * Current incarnation Copyright (C) 1998-2008 Monty xiphmont@mit.edu
+ *
+ * Generic SCSI interface specific code.
+ *
+ ******************************************************************/
+
+#include "low_interface.h"
+#include "common_interface.h"
+#include "utils.h"
+#include <time.h>
+static int timed_ioctl(cdrom_drive *d, int fd, int command, void *arg){
+ struct timespec tv1;
+ struct timespec tv2;
+ int ret1=clock_gettime(d->private_data->clock,&tv1);
+ int ret2=ioctl(fd, command,arg);
+ int ret3=clock_gettime(d->private_data->clock,&tv2);
+ if(ret1<0 || ret3<0){
+ d->private_data->last_milliseconds=-1;
+ }else{
+ d->private_data->last_milliseconds = (tv2.tv_sec-tv1.tv_sec)*1000. + (tv2.tv_nsec-tv1.tv_nsec)/1000000.;
+ }
+ return ret2;
+}
+
+/* hook */
+static int Dummy (cdrom_drive *d,int s){
+ return(0);
+}
+
+#include "drive_exceptions.h"
+static void tweak_SG_buffer(cdrom_drive *d) {
+ int table, reserved, cur, err;
+ char buffer[256];
+
+ /* SG_SET_RESERVED_SIZE doesn't actually allocate or reserve anything.
+ * what it _does_ do is give you an error if you ask for a value
+ * larger than q->max_sectors (the length of the device's bio request
+ * queue). So we walk it up from 1 sector until it fails, then get
+ * the value we set it to last.
+ */
+ /* start with 2 frames, round down to our queue's sector size */
+ cur = 1;
+ do {
+ cur <<= 1; reserved = cur * (1<<9);
+ err = ioctl(d->cdda_fd, SG_SET_RESERVED_SIZE, &reserved);
+ } while(err >= 0 && (cur*(1<<9) < 0x40000000));
+ ioctl(d->cdda_fd, SG_GET_RESERVED_SIZE, &reserved);
+
+ /* this doesn't currently ever work, but someday somebody might
+ implement working sg lists with SG_IO devices, so who knows... */
+ if (ioctl(d->cdda_fd, SG_GET_SG_TABLESIZE, &table) < 0)
+ table=1;
+
+ sprintf(buffer,"\tDMA scatter/gather table entries: %d\n\t"
+ "table entry size: %d bytes\n\t"
+ "maximum theoretical transfer: %d sectors\n",
+ table, reserved, table*(reserved/CD_FRAMESIZE_RAW));
+ cdmessage(d,buffer);
+
+ cur=reserved; /* only use one entry for now */
+
+ /* so since we never go above q->max_sectors, we should never get -EIO.
+ * we might still get -ENOMEM, but we back off for that later. Monty
+ * had an old comment: "not too much; new kernels have trouble with DMA
+ * allocation, so be more conservative: 32kB max until I test more
+ * thoroughly". We're not currently honoring that, because we should
+ * always get -ENOMEM.
+ *
+ * Updated: but we don't always get -ENOMEM. Sometimes USB drives
+ * still fail the wrong way. This needs some kernel-land investigation.
+ */
+ /* Bumping to 64kB transfer max --Monty */
+
+ if (!getenv("CDDA_IGNORE_BUFSIZE_LIMIT")) {
+ cur=(cur>1024*64?1024*64:cur);
+ }else{
+ cdmessage(d,"\tEnvironment variable CDDA_IGNORE_BUFSIZE_LIMIT set,\n"
+ "\t\tforcing maximum possible sector size. This can break\n"
+ "\t\tspectacularly; use with caution!\n");
+ }
+ d->nsectors=cur/CD_FRAMESIZE_RAW;
+ d->bigbuff=cur;
+
+ sprintf(buffer,"\tSetting default read size to %d sectors (%d bytes).\n\n",
+ d->nsectors,d->nsectors*CD_FRAMESIZE_RAW);
+
+ if(cur==0) exit(1);
+
+ cdmessage(d,buffer);
+}
+
+static void clear_garbage(cdrom_drive *d){
+ fd_set fdset;
+ struct timeval tv;
+ struct sg_header *sg_hd=d->private_data->sg_hd;
+ int flag=0;
+
+ /* clear out any possibly preexisting garbage */
+ FD_ZERO(&fdset);
+ FD_SET(d->cdda_fd,&fdset);
+ tv.tv_sec=0;
+ tv.tv_usec=0;
+
+ /* I like select */
+ while(select(d->cdda_fd+1,&fdset,NULL,NULL,&tv)==1){
+
+ sg_hd->twelve_byte = 0;
+ sg_hd->result = 0;
+ sg_hd->reply_len = SG_OFF;
+ read(d->cdda_fd, sg_hd, 1);
+
+ /* reset for select */
+ FD_ZERO(&fdset);
+ FD_SET(d->cdda_fd,&fdset);
+ tv.tv_sec=0;
+ tv.tv_usec=0;
+ if(!flag && d->report_all)
+ cdmessage(d,"Clearing previously returned data from SCSI buffer\n");
+ flag=1;
+ }
+}
+
+static int check_sbp_error(const unsigned char status,
+ const unsigned char *sbp) {
+ char key = sbp[2] & 0xf;
+ char ASC = sbp[12];
+ char ASCQ = sbp[13];
+
+ if(status==0)return 0;
+ if(status==8)return TR_BUSY;
+
+ if (sbp[0]) {
+ switch (key){
+ case 0:
+ if (errno==0)
+ errno = EIO;
+ return(TR_UNKNOWN);
+ case 1:
+ break;
+ case 2:
+ errno = ENOMEDIUM;
+ return(TR_NOTREADY);
+ case 3:
+ if ((ASC==0x0C) & (ASCQ==0x09)) {
+ /* loss of streaming */
+ if (errno==0)
+ errno = EIO;
+ return(TR_STREAMING);
+ } else {
+ if (errno==0)
+ errno = EIO;
+ return(TR_MEDIUM);
+ }
+ case 4:
+ if (errno==0)
+ errno = EIO;
+ return(TR_FAULT);
+ case 5:
+ if (errno==0)
+ errno = EINVAL;
+ return(TR_ILLEGAL);
+ default:
+ if (errno==0)
+ errno = EIO;
+ return(TR_UNKNOWN);
+ }
+ }
+ return 0;
+}
+
+/* process a complete scsi command. */
+static int sg2_handle_scsi_cmd(cdrom_drive *d,
+ unsigned char *cmd,
+ unsigned int cmd_len,
+ unsigned int in_size,
+ unsigned int out_size,
+ unsigned char bytefill,
+ int bytecheck,
+ unsigned char *sense_buffer){
+ struct timespec tv1;
+ struct timespec tv2;
+ int tret1,tret2;
+ int status = 0;
+ struct sg_header *sg_hd=d->private_data->sg_hd;
+ long writebytes=SG_OFF+cmd_len+in_size;
+
+ /* generic scsi device services */
+
+ /* clear out any possibly preexisting garbage */
+ clear_garbage(d);
+
+ memset(sg_hd,0,sizeof(sg_hd));
+ memset(sense_buffer,0,SG_MAX_SENSE);
+ memcpy(d->private_data->sg_buffer,cmd,cmd_len+in_size);
+ sg_hd->twelve_byte = cmd_len == 12;
+ sg_hd->result = 0;
+ sg_hd->reply_len = SG_OFF + out_size;
+
+ /* The following is one of the scariest hacks I've ever had to use.
+ The idea is this: We want to know if a command fails. The
+ generic scsi driver (as of now) won't tell us; it hands back the
+ uninitialized contents of the preallocated kernel buffer. We
+ force this buffer to a known value via another bug (nonzero data
+ length for a command that doesn't take data) such that we can
+ tell if the command failed. Scared yet? */
+
+ if(bytecheck && out_size>in_size){
+ memset(d->private_data->sg_buffer+cmd_len+in_size,bytefill,out_size-in_size);
+ /* the size does not remove cmd_len due to the way the kernel
+ driver copies buffers */
+ writebytes+=(out_size-in_size);
+ }
+
+ {
+ /* Select on write with a 5 second timeout. This is a hack until
+ a better error reporting layer is in place; right now, always
+ print a message. */
+
+ fd_set fdset;
+ struct timeval tv;
+
+ FD_ZERO(&fdset);
+ FD_SET(d->cdda_fd,&fdset);
+ tv.tv_sec=60; /* Increased to 1m for plextor, as the drive will
+ try to get through rough spots on its own and
+ this can take time 19991129 */
+ tv.tv_usec=0;
+
+ while(1){
+ int ret=select(d->cdda_fd+1,NULL,&fdset,NULL,&tv);
+ if(ret>0)break;
+ if(ret<0 && errno!=EINTR)break;
+ if(ret==0){
+ fprintf(stderr,"\nSCSI transport error: timeout waiting to write"
+ " packet\n\n");
+ return(TR_EWRITE);
+ }
+ }
+ }
+
+ sigprocmask (SIG_BLOCK, &(d->sigset), NULL );
+ tret1=clock_gettime(d->private_data->clock,&tv1);
+ errno=0;
+ status = write(d->cdda_fd, sg_hd, writebytes );
+
+ if (status<0 || status != writebytes ) {
+ sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL );
+ if(errno==0)errno=EIO;
+ return(TR_EWRITE);
+ }
+
+
+ {
+ /* Select on read (and write; this signals an error) with a 5
+ second timeout. This is a hack until a better error reporting
+ layer is in place; right now, always print a
+ message. */
+
+ fd_set rset;
+ struct timeval tv;
+
+ FD_ZERO(&rset);
+ FD_SET(d->cdda_fd,&rset);
+ tv.tv_sec=60; /* Increased to 1m for plextor, as the drive will
+ try to get through rough spots on its own and
+ this can take time 19991129 */
+ tv.tv_usec=0;
+
+ while(1){
+ int ret=select(d->cdda_fd+1,&rset,NULL,NULL,&tv);
+ if(ret<0 && errno!=EINTR)break;
+ if(ret==0){
+ sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL );
+ fprintf(stderr,"\nSCSI transport error: timeout waiting to read"
+ " packet\n\n");
+ return(TR_EREAD);
+ }
+ if(ret>0){
+ /* is it readable or something else? */
+ if(FD_ISSET(d->cdda_fd,&rset))break;
+ sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL );
+ fprintf(stderr,"\nSCSI transport: error reading packet\n\n");
+ return(TR_EREAD);
+ }
+ }
+ }
+
+ tret2=clock_gettime(d->private_data->clock,&tv2);
+ errno=0;
+ status = read(d->cdda_fd, sg_hd, SG_OFF + out_size);
+ sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL );
+ memcpy(sense_buffer,sg_hd->sense_buffer,SG_MAX_SENSE);
+
+ if (status<0)return status;
+
+ if(status != SG_OFF + out_size || sg_hd->result){
+ if(errno==0)errno=EIO;
+ return(TR_EREAD);
+ }
+
+ status = check_sbp_error(sg_hd->target_status, sense_buffer);
+ if(status)return status;
+
+ /* Failed/Partial DMA transfers occasionally get through. Why? No clue,
+ but it's been demonstrated in practice that we occasionally get
+ fewer bytes than we request with no indication anything went
+ wrong. */
+
+ if(bytecheck && in_size+cmd_len<out_size){
+ long i,flag=0;
+ for(i=in_size;i<out_size;i++)
+ if(d->private_data->sg_buffer[i]!=bytefill){
+ flag=1;
+ break;
+ }
+
+ if(!flag){
+ errno=EINVAL;
+ return(TR_ILLEGAL);
+ }
+ }
+
+ errno=0;
+ if(tret1<0 || tret2<0){
+ d->private_data->last_milliseconds=-1;
+ }else{
+ d->private_data->last_milliseconds = (tv2.tv_sec-tv1.tv_sec)*1000 + (tv2.tv_nsec-tv1.tv_nsec)/1000000;
+ }
+ return(0);
+}
+
+static int sgio_handle_scsi_cmd(cdrom_drive *d,
+ unsigned char *cmd,
+ unsigned int cmd_len,
+ unsigned int in_size,
+ unsigned int out_size,
+ unsigned char bytefill,
+ int bytecheck,
+ unsigned char *sense){
+
+ int status = 0;
+ struct sg_io_hdr hdr;
+
+ memset(&hdr,0,sizeof(hdr));
+ memset(sense,0,sizeof(sense));
+ memcpy(d->private_data->sg_buffer,cmd+cmd_len,in_size);
+
+ hdr.cmdp = cmd;
+ hdr.cmd_len = cmd_len;
+ hdr.sbp = sense;
+ hdr.mx_sb_len = SG_MAX_SENSE;
+ hdr.timeout = 50000;
+ hdr.interface_id = 'S';
+ hdr.dxferp = d->private_data->sg_buffer;
+ hdr.flags = SG_FLAG_DIRECT_IO; /* direct IO if we can get it */
+
+ /* scary buffer fill hack */
+ if(bytecheck && out_size>in_size)
+ memset(hdr.dxferp+in_size,bytefill,out_size-in_size);
+
+ if (in_size) {
+ hdr.dxfer_len = in_size;
+ hdr.dxfer_direction = SG_DXFER_TO_DEV;
+
+ errno = 0;
+ status = ioctl(d->ioctl_fd, SG_IO, &hdr);
+ if (status >= 0 && hdr.status){
+ status = check_sbp_error(hdr.status,hdr.sbp);
+ if(status) return status;
+ }
+ if (status < 0) return TR_EWRITE;
+ }
+
+ if (!in_size | out_size) {
+ hdr.dxfer_len = out_size;
+
+ if(bytecheck && d->interface != SGIO_SCSI_BUGGY1)
+ hdr.dxfer_direction = out_size ? SG_DXFER_TO_FROM_DEV : SG_DXFER_NONE;
+ else
+ hdr.dxfer_direction = out_size ? SG_DXFER_FROM_DEV : SG_DXFER_NONE;
+
+ errno = 0;
+ status = timed_ioctl(d,d->ioctl_fd, SG_IO, &hdr);
+ if (status >= 0 && hdr.status){
+ status = check_sbp_error(hdr.status,hdr.sbp);
+ if(status) return status;
+ }
+ if (status < 0) return status;
+ }
+
+ /* Failed/Partial DMA transfers occasionally get through. Why? No clue,
+ but it's been demonstrated in practice that we occasionally get
+ fewer bytes than we request with no indication anything went
+ wrong. */
+
+ if(bytecheck && in_size<out_size){
+ long i,flag=0;
+ for(i=in_size;i<out_size;i++)
+ if(d->private_data->sg_buffer[i]!=bytefill){
+ flag=1;
+ break;
+ }
+
+ if(!flag){
+ errno=EINVAL;
+ return(TR_ILLEGAL);
+ }
+ }
+
+ /* Can't rely on .duration because we can't be certain kernel has HZ set to something useful */
+ /* d->private_data->last_milliseconds = hdr.duration; */
+
+ errno = 0;
+ return 0;
+}
+
+static int handle_scsi_cmd(cdrom_drive *d,
+ unsigned char *cmd,
+ unsigned int cmd_len,
+ unsigned int in_size,
+ unsigned int out_size,
+ unsigned char bytefill,
+ int bytecheck,
+ unsigned char *sense){
+
+ if(d->interface == SGIO_SCSI || d->interface == SGIO_SCSI_BUGGY1)
+ return sgio_handle_scsi_cmd(d,cmd,cmd_len,in_size,out_size,bytefill,bytecheck,sense);
+ return sg2_handle_scsi_cmd(d,cmd,cmd_len,in_size,out_size,bytefill,bytecheck,sense);
+
+}
+
+static int test_unit_ready(cdrom_drive *d){
+ unsigned char sense[SG_MAX_SENSE];
+ unsigned char key, ASC, ASCQ;
+ unsigned char cmd[6] = { 0x00, /* TEST_UNIT_READY */
+ 0, /* reserved */
+ 0, /* reserved */
+ 0, /* reserved */
+ 0, /* reserved */
+ 0};/* control */
+
+ handle_scsi_cmd(d, cmd, 6, 0, 56, 0,0, sense);
+
+ key = d->private_data->sg_buffer[2] & 0xf;
+ ASC = d->private_data->sg_buffer[12];
+ ASCQ = d->private_data->sg_buffer[13];
+
+ if(key == 2 && ASC == 4 && ASCQ == 1) return 0;
+ return 1;
+}
+
+static void reset_scsi(cdrom_drive *d){
+ int arg,tries=0;
+ d->enable_cdda(d,0);
+
+ cdmessage(d,"sending SG SCSI reset... ");
+ if(ioctl(d->cdda_fd,SG_SCSI_RESET,&arg))
+ cdmessage(d,"FAILED: EBUSY\n");
+ else
+ cdmessage(d,"OK\n");
+
+ while(1) {
+ if(test_unit_ready(d))break;
+ tries++;
+ usleep(10);
+ }
+
+ d->enable_cdda(d,1);
+}
+
+static int mode_sense_atapi(cdrom_drive *d,int size,int page){
+ unsigned char sense[SG_MAX_SENSE];
+ unsigned char cmd[10]= {0x5A, /* MODE_SENSE */
+ 0x00, /* reserved */
+ 0x00, /* page */
+ 0, /* reserved */
+ 0, /* reserved */
+ 0, /* reserved */
+ 0, /* reserved */
+ 0, /* MSB (0) */
+ 0, /* sizeof(modesense - SG_OFF) */
+ 0}; /* reserved */
+
+ cmd[1]=d->lun<<5;
+ cmd[2]=0x3F&page;
+ cmd[8]=size+4;
+
+ if (handle_scsi_cmd (d, cmd, 10, 0, size+4,'\377',1,sense)) return(1);
+
+ {
+ unsigned char *b=d->private_data->sg_buffer;
+ if(b[0])return(1); /* Handles only up to 256 bytes */
+ if(b[6])return(1); /* Handles only up to 256 bytes */
+
+ b[0]=b[1]-3;
+ b[1]=b[2];
+ b[2]=b[3];
+ b[3]=b[7];
+
+ memmove(b+4,b+8,size-4);
+ }
+ return(0);
+}
+
+/* group 0 (6b) command */
+
+static int mode_sense_scsi(cdrom_drive *d,int size,int page){
+ unsigned char sense[SG_MAX_SENSE];
+ unsigned char cmd[6]={0x1A, /* MODE_SENSE */
+ 0x00, /* return block descriptor/lun */
+ 0x00, /* page */
+ 0, /* reserved */
+ 0, /* sizeof(modesense - SG_OFF) */
+ 0}; /* control */
+
+ cmd[1]=d->lun<<5;
+ cmd[2]=(0x3F&page);
+ cmd[4]=size;
+
+ if (handle_scsi_cmd (d, cmd, 6, 0, size, '\377',1, sense)) return(1);
+
+ /* dump it all... */
+
+
+ return(0);
+}
+
+static int mode_sense(cdrom_drive *d,int size,int page){
+ if(d->is_atapi)
+ return(mode_sense_atapi(d,size,page));
+ return(mode_sense_scsi(d,size,page));
+}
+
+/* Current SG/SGIO impleenmtations specifically disallow mode set
+ unless running as root (or setuid). One can see why (could be
+ disastrous on, eg, a SCSI disk), but it curtails what we can do
+ with older SCSI cdroms. */
+static int mode_select(cdrom_drive *d,int density,int secsize){
+ /* short circut the way Heiko does it; less flexible, but shorter */
+ unsigned char sense[SG_MAX_SENSE];
+ if(d->is_atapi){
+ unsigned char cmd[26] = { 0x55, /* MODE_SELECT */
+ 0x10, /* no save page */
+ 0, /* reserved */
+ 0, /* reserved */
+ 0, /* reserved */
+ 0, /* reserved */
+ 0, /* reserved */
+ 0, /* reserved */
+ 16, /* sizeof(mode) */
+ 0, /* reserved */
+
+ /* mode parameter header */
+ 0, 0, 0, 0, 0, 0, 0,
+ 8, /* Block Descriptor Length */
+
+ /* descriptor block */
+ 0, /* Density Code */
+ 0, 0, 0, /* # of Blocks */
+ 0, /* reserved */
+ 0, 0, 0};/* Blocklen */
+ unsigned char *mode = cmd + 18;
+
+ /* prepare to read cds in the previous mode */
+ mode [0] = density;
+ mode [6] = secsize >> 8; /* block length "msb" */
+ mode [7] = secsize & 0xFF; /* block length lsb */
+
+ /* do the scsi cmd */
+ return(handle_scsi_cmd (d,cmd,10, 16, 0,0,0,sense));
+
+ }else{
+ unsigned char cmd[18] = { 0x15, /* MODE_SELECT */
+ 0x10, /* no save page */
+ 0, /* reserved */
+ 0, /* reserved */
+ 12, /* sizeof(mode) */
+ 0, /* reserved */
+ /* mode section */
+ 0,
+ 0, 0,
+ 8, /* Block Descriptor Length */
+ 0, /* Density Code */
+ 0, 0, 0, /* # of Blocks */
+ 0, /* reserved */
+ 0, 0, 0};/* Blocklen */
+ unsigned char *mode = cmd + 10;
+
+ /* prepare to read cds in the previous mode */
+ mode [0] = density;
+ mode [6] = secsize >> 8; /* block length "msb" */
+ mode [7] = secsize & 0xFF; /* block length lsb */
+
+ /* do the scsi cmd */
+ return(handle_scsi_cmd (d,cmd,6, 12, 0,0,0,sense));
+ }
+}
+
+/* get current sector size from SCSI cdrom drive */
+static unsigned int get_orig_sectorsize(cdrom_drive *d){
+ if(mode_sense(d,12,0x01))return(-1);
+
+ d->orgdens = d->private_data->sg_buffer[4];
+ return(d->orgsize = ((int)(d->private_data->sg_buffer[10])<<8)+d->private_data->sg_buffer[11]);
+}
+
+/* switch CDROM scsi drives to given sector size */
+static int set_sectorsize (cdrom_drive *d,unsigned int secsize){
+ return(mode_select(d,d->orgdens,secsize));
+}
+
+/* switch old Toshiba/DEC and HP drives from/to cdda density */
+int scsi_enable_cdda (cdrom_drive *d, int fAudioMode){
+ if (fAudioMode) {
+ if(mode_select(d,d->density,CD_FRAMESIZE_RAW)){
+ if(d->error_retry)
+ cderror(d,"001: Unable to set CDROM to read audio mode\n");
+ return(-1);
+ }
+ } else {
+ if(mode_select(d,d->orgdens,d->orgsize)){
+ if(d->error_retry)
+ cderror(d,"001: Unable to set CDROM to read audio mode\n");
+ return(-1);
+ }
+ }
+ return(0);
+}
+
+typedef struct scsi_TOC { /* structure of scsi table of contents (cdrom) */
+ unsigned char reserved1;
+ unsigned char bFlags;
+ unsigned char bTrack;
+ unsigned char reserved2;
+ signed char start_MSB;
+ unsigned char start_1;
+ unsigned char start_2;
+ unsigned char start_LSB;
+} scsi_TOC;
+
+
+/* read the table of contents from the cd and fill the TOC array */
+/* Do it like the kernel ioctl driver; the 'all at once' approach
+ fails on at least one Kodak drive. */
+
+static int scsi_read_toc (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 header first */
+ unsigned char sense[SG_MAX_SENSE];
+ unsigned char cmd[10] = { 0x43, 0, 0, 0, 0, 0, 1, 0, 12, 0};
+ cmd[1]=d->lun<<5;
+
+ if (handle_scsi_cmd (d,cmd,10, 0, 12,'\377',1,sense)){
+ cderror(d,"004: Unable to read table of contents header\n");
+ return(-4);
+ }
+
+ first=d->private_data->sg_buffer[2];
+ last=d->private_data->sg_buffer[3];
+ 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);
+ }
+
+ for (i = first; i <= last; i++){
+ memcpy(cmd, (char []){ 0x43, 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
+ cmd[1]=d->lun<<5;
+ cmd[6]=i;
+
+ if (handle_scsi_cmd (d,cmd, 10, 0, 12,'\377',1,sense)){
+ cderror(d,"005: Unable to read table of contents entry\n");
+ return(-5);
+ }
+ {
+ scsi_TOC *toc=(scsi_TOC *)(d->private_data->sg_buffer+4);
+
+ d->disc_toc[i-first].bFlags=toc->bFlags;
+ d->disc_toc[i-first].bTrack=i;
+ d->disc_toc[i-first].dwStartSector= d->adjust_ssize *
+ (((int)(toc->start_MSB)<<24) |
+ (toc->start_1<<16)|
+ (toc->start_2<<8)|
+ (toc->start_LSB));
+ }
+ }
+
+ memcpy(cmd, (char []){ 0x43, 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10);
+ cmd[1]=d->lun<<5;
+ cmd[6]=0xAA;
+
+ if (handle_scsi_cmd (d,cmd,10, 0, 12,'\377',1,sense)){
+ cderror(d,"002: Unable to read table of contents lead-out\n");
+ return(-2);
+ }
+ {
+ scsi_TOC *toc=(scsi_TOC *)(d->private_data->sg_buffer+4);
+
+ d->disc_toc[i-first].bFlags=toc->bFlags;
+ d->disc_toc[i-first].bTrack=0xAA;
+ d->disc_toc[i-first].dwStartSector= d->adjust_ssize *
+ (((int)(toc->start_MSB)<<24) |
+ (toc->start_1<<16)|
+ (toc->start_2<<8)|
+ (toc->start_LSB));
+ }
+
+ d->cd_extra = FixupTOC(d,tracks+1); /* include lead-out */
+ return(tracks);
+}
+
+/* a contribution from Boris for IMS cdd 522 */
+/* check this for ACER/Creative/Foo 525,620E,622E, etc? */
+static int scsi_read_toc2 (cdrom_drive *d){
+ u_int32_t foo,bar;
+
+ int i;
+ unsigned tracks;
+
+ unsigned char cmd[10] = { 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ unsigned char sense[SG_MAX_SENSE];
+ cmd[5]=1;
+ cmd[8]=255;
+
+ if (handle_scsi_cmd (d,cmd,10, 0, 256,'\377',1,sense)){
+ cderror(d,"004: Unable to read table of contents header\n");
+ return(-4);
+ }
+
+ /* copy to our structure and convert start sector */
+ tracks = d->private_data->sg_buffer[1];
+ if (tracks > MAXTRK) {
+ cderror(d,"003: CDROM reporting illegal number of tracks\n");
+ return(-3);
+ }
+
+ for (i = 0; i < tracks; i++){
+ memcpy(cmd, (char[]){ 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10);
+ cmd[5]=i+1;
+ cmd[8]=255;
+
+ if (handle_scsi_cmd (d,cmd,10, 0, 256,'\377',1,sense)){
+ cderror(d,"005: Unable to read table of contents entry\n");
+ return(-5);
+ }
+
+ d->disc_toc[i].bFlags = d->private_data->sg_buffer[10];
+ d->disc_toc[i].bTrack = i + 1;
+
+ d->disc_toc[i].dwStartSector= d->adjust_ssize *
+ (((signed char)(d->private_data->sg_buffer[2])<<24) |
+ (d->private_data->sg_buffer[3]<<16)|
+ (d->private_data->sg_buffer[4]<<8)|
+ (d->private_data->sg_buffer[5]));
+ }
+
+ d->disc_toc[i].bFlags = 0;
+ d->disc_toc[i].bTrack = i + 1;
+ memcpy (&foo, d->private_data->sg_buffer+2, 4);
+ memcpy (&bar, d->private_data->sg_buffer+6, 4);
+ d->disc_toc[i].dwStartSector = d->adjust_ssize * (be32_to_cpu(foo) +
+ be32_to_cpu(bar));
+
+ d->disc_toc[i].dwStartSector= d->adjust_ssize *
+ ((((signed char)(d->private_data->sg_buffer[2])<<24) |
+ (d->private_data->sg_buffer[3]<<16)|
+ (d->private_data->sg_buffer[4]<<8)|
+ (d->private_data->sg_buffer[5]))+
+
+ ((((signed char)(d->private_data->sg_buffer[6])<<24) |
+ (d->private_data->sg_buffer[7]<<16)|
+ (d->private_data->sg_buffer[8]<<8)|
+ (d->private_data->sg_buffer[9]))));
+
+
+ d->cd_extra = FixupTOC(d,tracks+1);
+ return(tracks);
+}
+
+static int scsi_set_speed (cdrom_drive *d, int speed){
+ unsigned char cmd[12]={0xBB, 0, 0, 0, 0xff, 0xff, 0, 0, 0, 0, 0, 0};
+ unsigned char sense[SG_MAX_SENSE];
+
+ if(speed>=0)
+ speed=speed*44100*4/1024;
+ else
+ speed=-1;
+ cmd[2] = (speed >> 8) & 0xFF;
+ cmd[3] = (speed) & 0xFF;
+ return handle_scsi_cmd(d,cmd,12,0,0,0,0,sense);
+}
+
+/* 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, unsigned char *sense){
+ int ret;
+ unsigned char cmd[10]={0x28, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if(d->fua)
+ cmd[1]=0x08;
+
+ cmd[1]|=d->lun<<5;
+
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[8] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_A8 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xA8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if(d->fua)
+ cmd[1]=0x08;
+
+ cmd[1]|=d->lun<<5;
+
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[9] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_D4_10 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[10]={0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if(d->fua)
+ cmd[1]=0x08;
+
+ cmd[1]|=d->lun<<5;
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[8] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_D4_12 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if(d->fua)
+ cmd[1]=0x08;
+
+ cmd[1]|=d->lun<<5;
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[9] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_D5 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[10]={0xd5, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if(d->fua)
+ cmd[1]=0x08;
+
+ cmd[1]|=d->lun<<5;
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[8] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,10,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_D8 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xd8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if(d->fua)
+ cmd[1]=0x08;
+
+ cmd[1]|=d->lun<<5;
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[9] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_mmc (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xbe, 0x2, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0};
+
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[8] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_mmcB (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xbe, 0x0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0};
+
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[8] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_mmc2 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xbe, 0x2, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0};
+
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[8] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_mmc2B (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xbe, 0x0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0};
+
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[8] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_mmc3 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xbe, 0x6, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0};
+
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[8] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_mmc3B (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xbe, 0x4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0};
+
+ cmd[3] = (begin >> 16) & 0xFF;
+ cmd[4] = (begin >> 8) & 0xFF;
+ cmd[5] = begin & 0xFF;
+ cmd[8] = sectors;
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+/* straight from the MMC3 spec */
+static inline void LBA_to_MSF(long lba,
+ unsigned char *M,
+ unsigned char *S,
+ unsigned char *F){
+ if(lba>=-150){
+ *M=(lba+150)/(60*75);
+ lba-=(*M)*60*75;
+ *S=(lba+150)/75;
+ lba-=(*S)*75;
+ *F=(lba+150);
+ }else{
+ *M=(lba+450150)/(60*75);
+ lba-=(*M)*60*75;
+ *S=(lba+450150)/75;
+ lba-=(*S)*75;
+ *F=(lba+450150);
+ }
+}
+
+
+static int i_read_msf (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xb9, 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0};
+
+ LBA_to_MSF(begin,cmd+3,cmd+4,cmd+5);
+ LBA_to_MSF(begin+sectors,cmd+6,cmd+7,cmd+8);
+
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_msf2 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xb9, 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0};
+
+ LBA_to_MSF(begin,cmd+3,cmd+4,cmd+5);
+ LBA_to_MSF(begin+sectors,cmd+6,cmd+7,cmd+8);
+
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+static int i_read_msf3 (cdrom_drive *d, void *p, long begin, long sectors, unsigned char *sense){
+ int ret;
+ unsigned char cmd[12]={0xb9, 4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0};
+
+ LBA_to_MSF(begin,cmd+3,cmd+4,cmd+5);
+ LBA_to_MSF(begin+sectors,cmd+6,cmd+7,cmd+8);
+
+ if((ret=handle_scsi_cmd(d,cmd,12,0,sectors * CD_FRAMESIZE_RAW,'\177',1,sense)))
+ return(ret);
+ if(p)memcpy(p,d->private_data->sg_buffer,sectors*CD_FRAMESIZE_RAW);
+ return(0);
+}
+
+
+static long scsi_read_map (cdrom_drive *d, void *p, long begin, long sectors,
+ int (*map)(cdrom_drive *, void *, long, long,
+ unsigned char *)){
+ unsigned char sense[SG_MAX_SENSE];
+ int retry_count,err;
+ char *buffer=(char *)p;
+
+ /* read d->nsectors at a time, max. */
+ sectors=(sectors>d->nsectors?d->nsectors:sectors);
+ sectors=(sectors<1?1:sectors);
+
+ retry_count=0;
+
+ while(1) {
+
+ if((err=map(d,(p?buffer:NULL),begin,sectors,sense))){
+ if(d->report_all){
+ char b[256];
+
+ sprintf(b,"scsi_read error: sector=%ld length=%ld retry=%d\n",
+ begin,sectors,retry_count);
+ cdmessage(d,b);
+ sprintf(b," Sense key: %x ASC: %x ASCQ: %x\n",
+ (int)(sense[2]&0xf),
+ (int)(sense[12]),
+ (int)(sense[13]));
+ cdmessage(d,b);
+ sprintf(b," Transport error: %s\n",strerror_tr[err]);
+ cdmessage(d,b);
+ sprintf(b," System error: %s\n",strerror(errno));
+ cdmessage(d,b);
+
+ fprintf(stderr,"scsi_read error: sector=%ld length=%ld retry=%d\n",
+ begin,sectors,retry_count);
+ fprintf(stderr," Sense key: %x ASC: %x ASCQ: %x\n",
+ (int)(sense[2]&0xf),
+ (int)(sense[12]),
+ (int)(sense[13]));
+ fprintf(stderr," Transport error: %s\n",strerror_tr[err]);
+ fprintf(stderr," System error: %s\n",strerror(errno));
+ }
+
+ switch(errno){
+ case EINTR:
+ usleep(100);
+ continue;
+ case ENOMEM:
+ /* D'oh. Possible kernel error. Keep limping */
+ usleep(100);
+ if(sectors==1){
+ /* Nope, can't continue */
+ cderror(d,"300: Kernel memory error\n");
+ return(-300);
+ }
+ if(d->report_all){
+ char b[256];
+ sprintf(b,"scsi_read: kernel couldn't alloc %ld bytes. "
+ "backing off...\n",sectors*CD_FRAMESIZE_RAW);
+
+ cdmessage(d,b);
+ }
+ sectors--;
+ continue;
+ case ENOMEDIUM:
+ cderror(d,"404: No medium present\n");
+ return(-404);
+
+ default:
+ if(sectors==1){
+ if(errno==EIO)
+ if(d->fua==-1) /* testing for FUA support */
+ return(-7);
+
+ /* *Could* be I/O or media error. I think. If we're at
+ 30 retries, we better skip this unhappy little
+ sector. */
+ if(retry_count>MAX_RETRIES-1){
+ char b[256];
+ sprintf(b,"010: Unable to access sector %ld\n",
+ begin);
+ cderror(d,b);
+ return(-10);
+
+ }
+ break;
+ }
+
+ /* Hmm. OK, this is just a tad silly. just in case this was
+ a timeout and a reset happened, we need to set the drive
+ back to cdda */
+ reset_scsi(d);
+ }
+ if(!d->error_retry)return(-7);
+
+ }else{
+
+ /* Did we get all the bytes we think we did, or did the kernel
+ suck? */
+ if(buffer){
+ long i;
+ for(i=sectors*CD_FRAMESIZE_RAW;i>1;i-=2)
+ if(buffer[i-1]!='\177' || buffer[i-2]!='\177')
+ break;
+
+ i/=CD_FRAMESIZE_RAW;
+ if(i!=sectors){
+ if(d->report_all){
+ char b[256];
+ sprintf(b,"scsi_read underrun: pos=%ld len=%ld read=%ld retry=%d\n",
+ begin,sectors,i,retry_count);
+
+ cdmessage(d,b);
+ }
+ reset_scsi(d);
+ }
+
+ if(i>0)return(i);
+
+ }else
+ break;
+ }
+
+ retry_count++;
+ if(sectors==1 && retry_count>MAX_RETRIES){
+ cderror(d,"007: Unknown, unrecoverable error reading data\n");
+ return(-7);
+ }
+ if(sectors>1)sectors=sectors/2;
+ d->enable_cdda(d,0);
+ d->enable_cdda(d,1);
+
+ }
+ return(sectors);
+}
+
+long scsi_read_28 (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_28));
+}
+
+long scsi_read_A8 (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_A8));
+}
+
+long scsi_read_D4_10 (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_D4_10));
+}
+
+long scsi_read_D4_12 (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_D4_12));
+}
+
+long scsi_read_D5 (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_D5));
+}
+
+long scsi_read_D8 (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_D8));
+}
+
+long scsi_read_mmc (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_mmc));
+}
+
+long scsi_read_mmc2 (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_mmc2));
+}
+
+long scsi_read_mmc3 (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_mmc3));
+}
+
+long scsi_read_mmcB (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_mmcB));
+}
+
+long scsi_read_mmc2B (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_mmc2B));
+}
+
+long scsi_read_mmc3B (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_mmc3B));
+}
+
+long scsi_read_msf (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_msf));
+}
+
+long scsi_read_msf2 (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_msf2));
+}
+
+long scsi_read_msf3 (cdrom_drive *d, void *p, long begin,
+ long sectors){
+ return(scsi_read_map(d,p,begin,sectors,i_read_msf3));
+}
+
+
+/* Some drives, given an audio read command, return only 2048 bytes
+ of data as opposed to 2352 bytes. Look for bytess at the end of the
+ single sector verification read */
+
+static int count_2352_bytes(cdrom_drive *d){
+ long i;
+ for(i=2351;i>=0;i--)
+ if(d->private_data->sg_buffer[i]!=(unsigned char)'\177')
+ return(((i+3)>>2)<<2);
+
+ return(0);
+}
+
+static int verify_nonzero(cdrom_drive *d){
+ long i,flag=0;
+ for(i=0;i<2352;i++)
+ if(d->private_data->sg_buffer[i]!=0){
+ flag=1;
+ break;
+ }
+
+ return(flag);
+}
+
+/* So many different read commands, densities, features...
+ Verify that our selected 'read' command actually reads
+ nonzero data, else search through other possibilities */
+
+static int verify_read_command(cdrom_drive *d){
+ int i,j,k;
+ int audioflag=0;
+
+ int (*enablecommand) (struct cdrom_drive *d, int speed);
+ long (*readcommand) (struct cdrom_drive *d, void *p, long begin,
+ long sectors);
+ unsigned char density;
+
+ int16_t *buff=malloc(CD_FRAMESIZE_RAW);
+
+ cdmessage(d,"Verifying CDDA command set...\n");
+
+ /* try the expected command set; grab the center of each track, look
+ for data */
+
+ if(d->enable_cdda(d,1)==0){
+
+ for(i=1;i<=d->tracks;i++){
+ if(cdda_track_audiop(d,i)==1){
+ long firstsector=cdda_track_firstsector(d,i);
+ long lastsector=cdda_track_lastsector(d,i);
+ long sector=(firstsector+lastsector)>>1;
+ audioflag=1;
+
+ if(d->read_audio(d,buff,sector,1)>0){
+ if(count_2352_bytes(d)==2352){
+ cdmessage(d,"\tExpected command set reads OK.\n");
+ d->enable_cdda(d,0);
+ free(buff);
+ return(0);
+ }
+ }
+ }
+ }
+
+ d->enable_cdda(d,0);
+ }
+ if(!audioflag){
+ cdmessage(d,"\tCould not find any audio tracks on this disk.\n");
+ return(-403);
+ }
+
+ {
+ char *es="",*rs="";
+ d->bigendianp=-1;
+ density=d->density;
+ readcommand=d->read_audio;
+ enablecommand=d->enable_cdda;
+
+
+ /* No nonzeroes? D'oh. Exhaustive search */
+ cdmessage(d,"\tExpected command set FAILED!\n"
+ "\tPerforming full probe for CDDA command set...\n");
+
+ /* loops:
+ density/enable no, 0x0/org, 0x04/org, 0x82/org
+ read command read_10 read_12 read_nec read_sony read_mmc read_mmc2 */
+
+ /* NEC test must come before sony; the nec drive expects d8 to be
+ 10 bytes, and a 12 byte verson (Sony) crashes the drive */
+
+ for(j=0;j<15;j++){
+ int densitypossible=1;
+
+ switch(j){
+ case 0:
+ d->read_audio=scsi_read_28;
+ rs="28 0x,00";
+ break;
+ case 1:
+ d->read_audio=scsi_read_A8;
+ rs="a8 0x,00";
+ break;
+
+ case 2:
+ d->read_audio=scsi_read_mmcB;
+ rs="be 02,10";
+ densitypossible=0;
+ break;
+ case 3:
+ d->read_audio=scsi_read_mmc2B;
+ rs="be 02,f8";
+ densitypossible=0;
+ break;
+ case 4:
+ d->read_audio=scsi_read_mmc3B;
+ rs="be 06,f8";
+ densitypossible=0;
+ break;
+
+ case 5:
+ d->read_audio=scsi_read_mmc;
+ rs="be 00,10";
+ densitypossible=0;
+ break;
+ case 6:
+ d->read_audio=scsi_read_mmc2;
+ rs="be 00,f8";
+ densitypossible=0;
+ break;
+ case 7:
+ d->read_audio=scsi_read_mmc3;
+ rs="be 04,f8";
+ densitypossible=0;
+ break;
+
+ case 8:
+ d->read_audio=scsi_read_msf;
+ rs="b9 00,10";
+ densitypossible=0;
+ break;
+ case 9:
+ d->read_audio=scsi_read_msf2;
+ rs="b9 00,f8";
+ densitypossible=0;
+ break;
+ case 10:
+ d->read_audio=scsi_read_msf3;
+ rs="b9 04,f8";
+ densitypossible=0;
+ break;
+
+ case 11:
+ d->read_audio=scsi_read_D4_10;
+ rs="d4(10)0x";
+ break;
+ case 12:
+ d->read_audio=scsi_read_D4_12;
+ rs="d4(12)0x";
+ break;
+ case 13:
+ d->read_audio=scsi_read_D5;
+ rs="d5 0x,00";
+ break;
+ case 14:
+ d->read_audio=scsi_read_D8;
+ rs="d8 0x,00";
+ break;
+ }
+
+ for(i=0;i<5;i++){
+ switch(i){
+ case 0:
+ d->density=0;
+ d->enable_cdda=Dummy;
+ es="none ";
+ if(!densitypossible)i=5; /* short circuit MMC style commands */
+ break;
+ case 1:
+ d->density=0;
+ d->enable_cdda=scsi_enable_cdda;
+ es="yes/0x00";
+ break;
+ case 2:
+ d->density=0x04;
+ d->enable_cdda=scsi_enable_cdda;
+ es="yes/0x04";
+ break;
+ case 3:
+ d->density=0x82;
+ d->enable_cdda=scsi_enable_cdda;
+ es="yes/0x82";
+ break;
+ case 4:
+ d->density=0x81;
+ d->enable_cdda=scsi_enable_cdda;
+ es="yes/0x81";
+ break;
+ }
+
+ cdmessage(d,"\ttest -> density: [");
+ cdmessage(d,es);
+ cdmessage(d,"] command: [");
+ cdmessage(d,rs);
+ cdmessage(d,"]\n");
+
+ {
+ int densityflag=0;
+ int rejectflag=0;
+ int zeroflag=0;
+ int lengthflag=0;
+
+ if(d->enable_cdda(d,1)==0){
+ for(k=1;k<=d->tracks;k++){
+ if(cdda_track_audiop(d,k)==1){
+ long firstsector=cdda_track_firstsector(d,k);
+ long lastsector=cdda_track_lastsector(d,k);
+ long sector=(firstsector+lastsector)>>1;
+
+ if(d->read_audio(d,buff,sector,1)>0){
+ if((lengthflag=count_2352_bytes(d))==2352){
+ if(verify_nonzero(d)){
+ cdmessage(d,"\t\tCommand set FOUND!\n");
+
+ free(buff);
+ d->enable_cdda(d,0);
+ return(0);
+ }else{
+ zeroflag++;
+ }
+ }
+ }else{
+ rejectflag++;
+ break;
+ }
+ }
+ }
+ d->enable_cdda(d,0);
+ }else{
+ densityflag++;
+ }
+
+ if(densityflag)
+ cdmessage(d,"\t\tDrive rejected density set\n");
+ if(rejectflag){
+ char buffer[256];
+ sprintf(buffer,"\t\tDrive rejected read command packet(s)\n");
+ cdmessage(d,buffer);
+ }
+ if(lengthflag>0 && lengthflag<2352){
+ char buffer[256];
+ sprintf(buffer,"\t\tDrive returned at least one packet, but with\n"
+ "\t\tincorrect size (%d)\n",lengthflag);
+ cdmessage(d,buffer);
+ }
+ if(zeroflag){
+ char buffer[256];
+ sprintf(buffer,"\t\tDrive returned %d packet(s), but contents\n"
+ "\t\twere entirely zero\n",zeroflag);
+ cdmessage(d,buffer);
+ }
+ }
+ }
+ }
+
+ /* D'oh. */
+ d->density=density;
+ d->read_audio=readcommand;
+ d->enable_cdda=enablecommand;
+
+ cdmessage(d,"\tUnable to find any suitable command set from probe;\n"
+ "\tdrive probably not CDDA capable.\n");
+
+ cderror(d,"006: Could not read any data from drive\n");
+
+ }
+ free(buff);
+ return(-6);
+}
+
+static void check_cache(cdrom_drive *d){
+ long i;
+
+ if(!(d->read_audio==scsi_read_mmc ||
+ d->read_audio==scsi_read_mmc2 ||
+ d->read_audio==scsi_read_mmc3 ||
+ d->read_audio==scsi_read_mmcB ||
+ d->read_audio==scsi_read_mmc2B ||
+ d->read_audio==scsi_read_mmc3B)){
+
+ cdmessage(d,"This command set may use a Force Unit Access bit.");
+ cdmessage(d,"\nChecking drive for FUA bit support...\n");
+
+ d->enable_cdda(d,1);
+ d->fua=1;
+
+ for(i=1;i<=d->tracks;i++){
+ if(cdda_track_audiop(d,i)==1){
+ long firstsector=cdda_track_firstsector(d,i);
+ long lastsector=cdda_track_lastsector(d,i);
+ long sector=(firstsector+lastsector)>>1;
+
+ if(d->read_audio(d,NULL,sector,1)>0){
+ cdmessage(d,"\tDrive accepted FUA bit.\n");
+ d->enable_cdda(d,0);
+ return;
+ }
+ }
+ }
+
+ d->fua=0;
+ cdmessage(d,"\tDrive rejected FUA bit.\n");
+
+ /* we only use the FUA bit as a possible extra layer of
+ redundancy; too many drives accept it, but still don't force
+ unit access. Still use the old cachebusting algo. */
+ return;
+ }
+}
+
+static int check_atapi(cdrom_drive *d){
+ int atapiret=-1;
+ int fd = d->cdda_fd; /* check the device we'll actually be using to read */
+
+ cdmessage(d,"\nChecking for SCSI emulation...\n");
+
+ if (ioctl(fd,SG_EMULATED_HOST,&atapiret)){
+ cderror(d,"\tSG_EMULATED_HOST ioctl() failed!\n");
+ return(-1);
+ } else {
+ if(atapiret==1){
+ if(d->interface == SGIO_SCSI){
+ cdmessage(d,"\tDrive is ATAPI (using SG_IO host adaptor emulation)\n");
+ }else if(d->interface == SGIO_SCSI_BUGGY1){
+ cdmessage(d,"\tDrive is ATAPI (using SG_IO host adaptor emulation with workarounds)\n");
+ }else{
+ cdmessage(d,"\tDrive is ATAPI (using SCSI host adaptor emulation)\n");
+ /* Disable kernel SCSI command translation layer for access through sg */
+ if (ioctl(fd,SG_SET_TRANSFORM,0))
+ cderror(d,"\tCouldn't disable kernel command translation layer\n");
+ }
+ d->is_atapi=1;
+ }else{
+ cdmessage(d,"\tDrive is SCSI\n");
+ d->is_atapi=0;
+ }
+
+ return(d->is_atapi);
+ }
+}
+
+static int check_mmc(cdrom_drive *d){
+ unsigned char *b;
+ cdmessage(d,"\nChecking for MMC style command set...\n");
+
+ d->is_mmc=0;
+ if(mode_sense(d,22,0x2A)==0){
+
+ b=d->private_data->sg_buffer;
+ b+=b[3]+4;
+
+ if((b[0]&0x3F)==0x2A){
+ /* MMC style drive! */
+ d->is_mmc=1;
+
+ if(b[1]>=4){
+ if(b[5]&0x1){
+ cdmessage(d,"\tDrive is MMC style\n");
+ return(1);
+ }else{
+ cdmessage(d,"\tDrive is MMC, but reports CDDA incapable.\n");
+ cdmessage(d,"\tIt will likely not be able to read audio data.\n");
+ return(1);
+ }
+ }
+ }
+ }
+
+ cdmessage(d,"\tDrive does not have MMC CDDA support\n");
+ return(0);
+}
+
+static void check_exceptions(cdrom_drive *d,exception *list){
+
+ int i=0;
+ while(list[i].model){
+ if(!strncmp(list[i].model,d->drive_model,strlen(list[i].model))){
+ if(list[i].density)d->density=list[i].density;
+ if(list[i].enable)d->enable_cdda=list[i].enable;
+ if(list[i].read)d->read_audio=list[i].read;
+ if(list[i].bigendianp!=-1)d->bigendianp=list[i].bigendianp;
+ return;
+ }
+ i++;
+ }
+}
+
+/* request vendor brand and model */
+unsigned char *scsi_inquiry(cdrom_drive *d){
+ unsigned char sense[SG_MAX_SENSE];
+ unsigned char cmd[6]={ 0x12,0,0,0,56,0 };
+
+ if(handle_scsi_cmd(d,cmd,6, 0, 56,'\377',1,sense)) {
+ cderror(d,"008: Unable to identify CDROM model\n");
+ return(NULL);
+ }
+ return (d->private_data->sg_buffer);
+}
+
+int scsi_init_drive(cdrom_drive *d){
+ int ret;
+
+ check_atapi(d);
+ check_mmc(d);
+
+ /* generic Sony type defaults; specialize from here */
+ d->density = 0x0;
+ d->enable_cdda = Dummy;
+ d->read_audio = scsi_read_D8;
+ d->fua=0x0;
+ if(d->is_atapi)d->lun=0; /* it should already be; just to make sure */
+
+ if(d->is_mmc){
+
+ d->read_audio = scsi_read_mmc2B;
+ d->bigendianp=0;
+
+ check_exceptions(d,mmc_list);
+
+ }else{
+
+ if(d->is_atapi){
+ /* Not MMC maybe still uses 0xbe */
+
+ d->read_audio = scsi_read_mmc2B;
+ d->bigendianp=0;
+
+ check_exceptions(d,atapi_list);
+
+ }else{
+
+ check_exceptions(d,scsi_list);
+
+ }
+ }
+
+ if(!d->is_atapi)set_sectorsize(d,2048); /* we really do want the
+ 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 :
+ scsi_read_toc;
+ d->set_speed = scsi_set_speed;
+
+ if(!d->is_atapi){
+ unsigned sector_size= get_orig_sectorsize(d);
+
+ if(sector_size<2048 && set_sectorsize(d,2048))
+ d->adjust_ssize = 2048 / sector_size;
+ else
+ d->adjust_ssize = 1;
+ }else
+ d->adjust_ssize = 1;
+
+ d->tracks=d->read_toc(d);
+ if(d->tracks<1)
+ return(d->tracks);
+
+ tweak_SG_buffer(d);
+ d->opened=1;
+
+ if((ret=verify_read_command(d)))return(ret);
+ check_cache(d);
+
+ d->error_retry=1;
+ d->private_data->sg_hd=realloc(d->private_data->sg_hd,d->nsectors*CD_FRAMESIZE_RAW + SG_OFF + 128);
+ d->private_data->sg_buffer=((unsigned char *)d->private_data->sg_hd)+SG_OFF;
+ d->report_all=1;
+ return(0);
+}
+
Index: cdparanoia-III-10.2-new/interface/test_interface.c
===================================================================
--- cdparanoia-III-10.2-new/interface/test_interface.c (nonexistent)
+++ cdparanoia-III-10.2-new/interface/test_interface.c (revision 5)
@@ -0,0 +1,224 @@
+/******************************************************************
+ * CopyPolicy: GNU Lessger General Public License 2.1 applies
+ * Copyright (C) Monty xiphmont@mit.edu
+ *
+ * Fake interface backend for testing paranoia layer
+ *
+ ******************************************************************/
+
+#ifdef CDDA_TEST
+#include "low_interface.h"
+#include "utils.h"
+
+/* Build which test model? */
+#define CDDA_TEST_OK
+#undef CDDA_TEST_JITTER_SMALL
+#undef CDDA_TEST_JITTER_LARGE
+#undef CDDA_TEST_JITTER_MASSIVE
+#undef CDDA_TEST_FRAG_SMALL
+#undef CDDA_TEST_FRAG_LARGE
+#undef CDDA_TEST_FRAG_MASSIVE
+#undef CDDA_TEST_BOGUS_BYTES
+#undef CDDA_TEST_DROPDUPE_BYTES
+#undef CDDA_TEST_SCRATCH
+#undef CDDA_TEST_UNDERRUN
+
+#undef CDDA_TEST_ALLJITTER
+#undef CDDA_TEST_SOMEJITTER
+#undef CDDA_TEST_SEEKJITTER
+
+static int test_readtoc (cdrom_drive *d){
+ int tracks=0;
+ long bytes;
+ long sectors;
+
+ /* only one track, as many sectors as the file */
+
+ bytes=lseek(d->cdda_fd,0,SEEK_END);
+ lseek(d->cdda_fd,0,SEEK_SET);
+ sectors=bytes/CD_FRAMESIZE_RAW;
+
+ d->disc_toc[0].bFlags = 0;
+ d->disc_toc[0].bTrack = 1;
+ d->disc_toc[0].dwStartSector = 37;
+
+ d->disc_toc[1].bFlags = 0x4;
+ d->disc_toc[1].bTrack = CDROM_LEADOUT;
+ d->disc_toc[1].dwStartSector = sectors+37;
+
+ tracks=2;
+ d->cd_extra=0;
+ return(--tracks); /* without lead-out */
+}
+
+/* we emulate jitter, scratches, atomic jitter and bogus bytes on
+ boundaries, etc */
+
+static long test_read(cdrom_drive *d, void *p, long begin, long sectors){
+ int jitter_flag=0;
+ int los_flag=0;
+ static int jitter=0;
+ int bytes_so_far=0;
+ long bytestotal;
+ static FILE *fd=NULL;
+ static long lastread=0;
+
+ if(!fd)fd=fdopen(d->cdda_fd,"r");
+
+ if(begin<lastread)
+ d->private_data->last_milliseconds=20;
+ else
+ d->private_data->last_milliseconds=sectors;
+
+#ifdef CDDA_TEST_UNDERRUN
+ sectors-=1;
+#endif
+
+#ifdef CDDA_TEST_SEEKJITTER
+ if(lastread!=begin)jitter_flag=1;
+#else
+#ifdef CDDA_TEST_ALLJITTER
+ jitter_flag=1;
+#else
+#ifdef CDDA_TEST_SOMEJITTER
+ jitter_flag=(drand48()>.9?1:0);
+ los_flag=(drand48()>.9?1:0);
+#else
+ los_flag=1;
+#endif
+#endif
+#endif
+
+ lastread=begin+sectors;
+ bytestotal=sectors*CD_FRAMESIZE_RAW;
+
+ begin*=CD_FRAMESIZE_RAW;
+
+ while(bytes_so_far<bytestotal){
+ int inner_bytes=bytestotal-bytes_so_far;
+ char *inner_buf=(p ? p+bytes_so_far : NULL);
+ long seeki;
+ long rbytes;
+ long this_bytes=inner_bytes;
+
+#ifdef CDDA_TEST_OK
+
+#else
+#ifdef CDDA_TEST_JITTER_SMALL
+ if(jitter_flag)jitter=4*(int)((drand48()-.5)*CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_JITTER_LARGE
+ if(jitter_flag)jitter=32*(int)((drand48()-.5)*CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_JITTER_MASSIVE
+ if(jitter_flag)jitter=128*(int)((drand48()-.5)*CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_FRAG_SMALL
+ if(los_flag)this_bytes=256*(int)(drand48()*CD_FRAMESIZE_RAW/8);
+ if(jitter_flag)jitter=4*(int)((drand48()-.5)*CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_FRAG_LARGE
+ if(los_flag)this_bytes=16*(int)(drand48()*CD_FRAMESIZE_RAW/8);
+ if(jitter_flag)jitter=4*(int)((drand48()-.5)*CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_FRAG_MASSIVE
+ if(los_flag)this_bytes=8*(int)(drand48()*CD_FRAMESIZE_RAW/8);
+ if(jitter_flag)jitter=32*(int)((drand48()-.5)*CD_FRAMESIZE_RAW/8);
+
+#else
+#ifdef CDDA_TEST_DROPDUPE_BYTES
+ if(los_flag)this_bytes=CD_FRAMESIZE_RAW;
+ if(jitter_flag)
+ if (drand48()>.8)
+ this_jitter=32;
+ else
+ this_jitter=0;
+
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+#endif
+
+
+ if(this_bytes>inner_bytes)this_bytes=inner_bytes;
+ if(begin+jitter+bytes_so_far<0)jitter=0;
+ seeki=begin+bytes_so_far+jitter;
+
+ if(fseek(fd,seeki,SEEK_SET)<0){
+ return(0);
+ }
+ if(!inner_buf){
+ char *temp = malloc(this_bytes);
+ rbytes=fread(temp,1,this_bytes,fd);
+ free(temp);
+ }else
+ rbytes=fread(inner_buf,1,this_bytes,fd);
+
+
+ bytes_so_far+=rbytes;
+ if(rbytes==0)break;
+
+#ifdef CDDA_TEST_SEEKJITTER
+ jitter_flag=0;
+ los_flag=0;
+#else
+#ifdef CDDA_TEST_ALLJITTER
+ jitter_flag=1;
+ los_flag=0;
+#else
+#ifdef CDDA_TEST_SOMEJITTER
+ jitter_flag=(drand48()>.9?1:0);
+ los_flag=(drand48()>.9?1:0);
+#else
+ los_flag=1;
+#endif
+#endif
+#endif
+
+ }
+
+#ifdef CDDA_TEST_SCRATCH
+ {
+ long location=300*CD_FRAMESIZE_RAW+(drand48()*56)+512;
+
+ if(begin<=location && begin+bytestotal>location){
+ if(p)memset(p+location-begin,(int)(drand48()*256),1100);
+ }
+ }
+#endif
+
+ return(sectors);
+}
+
+/* hook */
+static int Dummy (cdrom_drive *d,int Switch){
+ return(0);
+}
+
+/* set function pointers to use the ioctl routines */
+int test_init_drive (cdrom_drive *d){
+
+ d->nsectors=13;
+ d->enable_cdda = Dummy;
+ d->read_audio = test_read;
+ d->read_toc = test_readtoc;
+ d->set_speed = Dummy;
+ d->tracks=d->read_toc(d);
+ if(d->tracks==-1)
+ return(d->tracks);
+ d->opened=1;
+ srand48(0);
+ return(0);
+}
+
+#endif
+
Index: cdparanoia-III-10.2-new/interface
===================================================================
--- cdparanoia-III-10.2-new/interface (nonexistent)
+++ cdparanoia-III-10.2-new/interface (revision 5)
Property changes on: cdparanoia-III-10.2-new/interface
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: cdparanoia-III-10.2-new
===================================================================
--- cdparanoia-III-10.2-new (nonexistent)
+++ cdparanoia-III-10.2-new (revision 5)
Property changes on: cdparanoia-III-10.2-new
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~
Index: create.patch.sh
===================================================================
--- create.patch.sh (nonexistent)
+++ create.patch.sh (revision 5)
@@ -0,0 +1,15 @@
+#!/bin/sh
+
+VERSION=10.2
+
+tar --files-from=file.list -xzvf ../cdparanoia-III-$VERSION.tar.gz
+mv cdparanoia-III-$VERSION cdparanoia-III-$VERSION-orig
+
+cp -rf ./cdparanoia-III-$VERSION-new ./cdparanoia-III-$VERSION
+
+diff --unified -Nr cdparanoia-III-$VERSION-orig cdparanoia-III-$VERSION > cdparanoia-$VERSION-private-data.patch
+
+mv cdparanoia-$VERSION-private-data.patch ../patches
+
+rm -rf ./cdparanoia-III-$VERSION
+rm -rf ./cdparanoia-III-$VERSION-orig
Property changes on: create.patch.sh
___________________________________________________________________
Added: svn:executable
## -0,0 +1 ##
+*
\ No newline at end of property
Index: file.list
===================================================================
--- file.list (nonexistent)
+++ file.list (revision 5)
@@ -0,0 +1,6 @@
+cdparanoia-III-10.2/interface/cdda_interface.h
+cdparanoia-III-10.2/interface/cooked_interface.c
+cdparanoia-III-10.2/interface/interface.c
+cdparanoia-III-10.2/interface/scan_devices.c
+cdparanoia-III-10.2/interface/scsi_interface.c
+cdparanoia-III-10.2/interface/test_interface.c
Index: .
===================================================================
--- . (nonexistent)
+++ . (revision 5)
Property changes on: .
___________________________________________________________________
Added: svn:ignore
## -0,0 +1,73 ##
+
+# install dir
+dist
+
+# Target build dirs
+.a1x-newlib
+.a2x-newlib
+.at91sam7s-newlib
+
+.build-machine
+
+.a1x-glibc
+.a2x-glibc
+.h3-glibc
+.h5-glibc
+.i586-glibc
+.i686-glibc
+.imx6-glibc
+.jz47xx-glibc
+.makefile
+.am335x-glibc
+.omap543x-glibc
+.p5600-glibc
+.power8-glibc
+.power8le-glibc
+.power9-glibc
+.power9le-glibc
+.m1000-glibc
+.riscv64-glibc
+.rk328x-glibc
+.rk33xx-glibc
+.rk339x-glibc
+.s8xx-glibc
+.s9xx-glibc
+.x86_64-glibc
+
+# Hidden files (each file)
+.makefile
+.dist
+.rootfs
+
+# src & hw requires
+.src_requires
+.src_requires_depend
+.requires
+.requires_depend
+
+# Tarballs
+*.gz
+*.bz2
+*.lz
+*.xz
+*.tgz
+*.txz
+
+# Signatures
+*.asc
+*.sig
+*.sign
+*.sha1sum
+
+# Patches
+*.patch
+
+# Descriptions
+*.dsc
+*.txt
+
+# Default linux config files
+*.defconfig
+
+# backup copies
+*~