From 6c14d289181f9268fb0a5e489687da75581a791c Mon Sep 17 00:00:00 2001 From: rocky Date: Sat, 18 Dec 2004 17:29:32 +0000 Subject: [PATCH] BIG REORGANIZATION. Reorganize directory structure for inclusion of cd-paranoia. Works for GNU/Linux. Other OS's may be broken. Regression test output needs to be adjusted too. Move: lib/driver (split off of lib) lib/iso9660 (split off of lib) Add from paranoia: lib/cdda_interface lib/paranoia src/paranoia Also made some small changes to capability indentification to show more reading capabilties and show that. cd-info now shows the total disc size. --- .cvsignore | 2 + Makefile.am | 5 +- configure.ac | 29 +- include/cdio/Makefile.am | 4 +- include/cdio/cdda_interface.h | 217 +++ include/cdio/cdio.h | 36 +- include/cdio/paranoia.h | 123 ++ include/cdio/scsi_mmc.h | 12 +- include/cdio/types.h | 8 +- lib/.cvsignore | 6 - lib/Makefile.am | 186 +-- lib/cdda_interface/.cvsignore | 8 + lib/cdda_interface/Makefile.am | 76 ++ lib/cdda_interface/common_interface.c | 262 ++++ lib/cdda_interface/common_interface.h | 34 + lib/cdda_interface/cooked_interface.c | 291 ++++ lib/cdda_interface/drive_exceptions.h | 95 ++ lib/cdda_interface/interface.c | 149 ++ lib/cdda_interface/low_interface.h | 86 ++ lib/cdda_interface/scan_devices.c | 733 ++++++++++ lib/cdda_interface/scsi_interface.c | 1580 ++++++++++++++++++++++ lib/cdda_interface/smallft.c | 547 ++++++++ lib/cdda_interface/smallft.h | 12 + lib/cdda_interface/test_interface.c | 238 ++++ lib/cdda_interface/toc.c | 199 +++ lib/cdda_interface/utils.c | 138 ++ lib/cdda_interface/utils.h | 133 ++ lib/driver/.cvsignore | 9 + lib/{ => driver}/FreeBSD/Makefile | 2 +- lib/{ => driver}/FreeBSD/freebsd.c | 4 +- lib/{ => driver}/FreeBSD/freebsd.h | 2 +- lib/{ => driver}/FreeBSD/freebsd_cam.c | 4 +- lib/{ => driver}/FreeBSD/freebsd_ioctl.c | 4 +- lib/{ => driver}/MSWindows/Makefile | 2 +- lib/{ => driver}/MSWindows/aspi32.c | 4 +- lib/{ => driver}/MSWindows/aspi32.h | 2 +- lib/{ => driver}/MSWindows/win32.c | 4 +- lib/{ => driver}/MSWindows/win32.h | 2 +- lib/{ => driver}/MSWindows/win32_ioctl.c | 4 +- lib/driver/Makefile.am | 173 +++ lib/{ => driver}/_cdio_aix.c | 4 +- lib/{ => driver}/_cdio_bsdi.c | 4 +- lib/{ => driver}/_cdio_generic.c | 4 +- lib/{ => driver}/_cdio_linux.c | 4 +- lib/{ => driver}/_cdio_osx.c | 4 +- lib/{ => driver}/_cdio_stdio.c | 4 +- lib/{ => driver}/_cdio_stdio.h | 2 +- lib/{ => driver}/_cdio_stream.c | 4 +- lib/{ => driver}/_cdio_stream.h | 2 +- lib/{ => driver}/_cdio_sunos.c | 4 +- lib/{ => driver}/cd_types.c | 2 +- lib/{ => driver}/cdio.c | 4 +- lib/{ => driver}/cdio_assert.h | 2 +- lib/{ => driver}/cdio_private.h | 2 +- lib/{ => driver}/cdtext.c | 2 +- lib/{ => driver}/cdtext_private.h | 2 +- lib/{ => driver}/ds.c | 4 +- lib/{ => driver}/generic.h | 2 +- lib/{ => driver}/image.h | 2 +- lib/{ => driver}/image/Makefile | 2 +- lib/{ => driver}/image/bincue.c | 4 +- lib/{ => driver}/image/cdrdao.c | 4 +- lib/{ => driver}/image/nrg.c | 4 +- lib/{ => driver}/image/nrg.h | 2 +- lib/{ => driver}/image_common.h | 2 +- lib/{ => driver}/libcdio.sym | 0 lib/{ => driver}/logging.c | 4 +- lib/{ => driver}/portable.h | 2 +- lib/{ => driver}/scsi_mmc.c | 79 +- lib/{ => driver}/scsi_mmc_private.h | 14 +- lib/{ => driver}/sector.c | 4 +- lib/{ => driver}/util.c | 4 +- lib/iso9660/.cvsignore | 9 + lib/iso9660/Makefile.am | 141 ++ lib/{ => iso9660}/iso9660.c | 4 +- lib/{ => iso9660}/iso9660_fs.c | 4 +- lib/{ => iso9660}/iso9660_private.h | 2 +- lib/{ => iso9660}/libiso9660.sym | 0 lib/{ => iso9660}/xa.c | 2 +- lib/paranoia/.cvsignore | 8 + lib/paranoia/Makefile.am | 77 ++ lib/paranoia/gap.c | 222 +++ lib/paranoia/gap.h | 44 + lib/paranoia/isort.c | 132 ++ lib/paranoia/isort.h | 65 + lib/paranoia/overlap.c | 210 +++ lib/paranoia/overlap.h | 34 + lib/paranoia/p_block.c | 402 ++++++ lib/paranoia/p_block.h | 208 +++ lib/paranoia/paranoia.c | 1399 +++++++++++++++++++ libcdio_cdda.pc.in | 11 + libcdio_paranoia.pc.in | 11 + src/Makefile.am | 4 +- src/cd-info.c | 13 +- src/cd-paranoia/.cvsignore | 6 + src/cd-paranoia/Makefile.am | 34 + src/cd-paranoia/buffering_write.c | 73 + src/cd-paranoia/buffering_write.h | 23 + src/cd-paranoia/cd-paranoia.1 | 352 +++++ src/cd-paranoia/cd-paranoia.1.jp | 354 +++++ src/cd-paranoia/cd-paranoia.c | 1324 ++++++++++++++++++ src/cd-paranoia/header.c | 135 ++ src/cd-paranoia/header.h | 17 + src/cd-paranoia/report.c | 60 + src/cd-paranoia/report.h | 3 + src/cd-paranoia/utils.h | 128 ++ src/cd-paranoia/version.h | 29 + src/util.c | 40 +- test/Makefile.am | 4 +- 109 files changed, 10863 insertions(+), 329 deletions(-) create mode 100644 include/cdio/cdda_interface.h create mode 100644 include/cdio/paranoia.h create mode 100644 lib/cdda_interface/.cvsignore create mode 100644 lib/cdda_interface/Makefile.am create mode 100644 lib/cdda_interface/common_interface.c create mode 100644 lib/cdda_interface/common_interface.h create mode 100644 lib/cdda_interface/cooked_interface.c create mode 100644 lib/cdda_interface/drive_exceptions.h create mode 100644 lib/cdda_interface/interface.c create mode 100644 lib/cdda_interface/low_interface.h create mode 100644 lib/cdda_interface/scan_devices.c create mode 100644 lib/cdda_interface/scsi_interface.c create mode 100644 lib/cdda_interface/smallft.c create mode 100644 lib/cdda_interface/smallft.h create mode 100644 lib/cdda_interface/test_interface.c create mode 100644 lib/cdda_interface/toc.c create mode 100644 lib/cdda_interface/utils.c create mode 100644 lib/cdda_interface/utils.h create mode 100644 lib/driver/.cvsignore rename lib/{ => driver}/FreeBSD/Makefile (94%) rename lib/{ => driver}/FreeBSD/freebsd.c (99%) rename lib/{ => driver}/FreeBSD/freebsd.h (99%) rename lib/{ => driver}/FreeBSD/freebsd_cam.c (98%) rename lib/{ => driver}/FreeBSD/freebsd_ioctl.c (97%) rename lib/{ => driver}/MSWindows/Makefile (94%) rename lib/{ => driver}/MSWindows/aspi32.c (99%) rename lib/{ => driver}/MSWindows/aspi32.h (99%) rename lib/{ => driver}/MSWindows/win32.c (99%) rename lib/{ => driver}/MSWindows/win32.h (98%) rename lib/{ => driver}/MSWindows/win32_ioctl.c (99%) create mode 100644 lib/driver/Makefile.am rename lib/{ => driver}/_cdio_aix.c (99%) rename lib/{ => driver}/_cdio_bsdi.c (99%) rename lib/{ => driver}/_cdio_generic.c (98%) rename lib/{ => driver}/_cdio_linux.c (99%) rename lib/{ => driver}/_cdio_osx.c (99%) rename lib/{ => driver}/_cdio_stdio.c (97%) rename lib/{ => driver}/_cdio_stdio.h (96%) rename lib/{ => driver}/_cdio_stream.c (96%) rename lib/{ => driver}/_cdio_stream.h (98%) rename lib/{ => driver}/_cdio_sunos.c (99%) rename lib/{ => driver}/cd_types.c (99%) rename lib/{ => driver}/cdio.c (99%) rename lib/{ => driver}/cdio_assert.h (96%) rename lib/{ => driver}/cdio_private.h (99%) rename lib/{ => driver}/cdtext.c (98%) rename lib/{ => driver}/cdtext_private.h (98%) rename lib/{ => driver}/ds.c (97%) rename lib/{ => driver}/generic.h (98%) rename lib/{ => driver}/image.h (97%) rename lib/{ => driver}/image/Makefile (94%) rename lib/{ => driver}/image/bincue.c (99%) rename lib/{ => driver}/image/cdrdao.c (99%) rename lib/{ => driver}/image/nrg.c (99%) rename lib/{ => driver}/image/nrg.h (98%) rename lib/{ => driver}/image_common.h (98%) rename lib/{ => driver}/libcdio.sym (100%) rename lib/{ => driver}/logging.c (95%) rename lib/{ => driver}/portable.h (97%) rename lib/{ => driver}/scsi_mmc.c (90%) rename lib/{ => driver}/scsi_mmc_private.h (94%) rename lib/{ => driver}/sector.c (97%) rename lib/{ => driver}/util.c (96%) create mode 100644 lib/iso9660/.cvsignore create mode 100644 lib/iso9660/Makefile.am rename lib/{ => iso9660}/iso9660.c (99%) rename lib/{ => iso9660}/iso9660_fs.c (99%) rename lib/{ => iso9660}/iso9660_private.h (97%) rename lib/{ => iso9660}/libiso9660.sym (100%) rename lib/{ => iso9660}/xa.c (98%) create mode 100644 lib/paranoia/.cvsignore create mode 100644 lib/paranoia/Makefile.am create mode 100644 lib/paranoia/gap.c create mode 100644 lib/paranoia/gap.h create mode 100644 lib/paranoia/isort.c create mode 100644 lib/paranoia/isort.h create mode 100644 lib/paranoia/overlap.c create mode 100644 lib/paranoia/overlap.h create mode 100644 lib/paranoia/p_block.c create mode 100644 lib/paranoia/p_block.h create mode 100644 lib/paranoia/paranoia.c create mode 100644 libcdio_cdda.pc.in create mode 100644 libcdio_paranoia.pc.in create mode 100644 src/cd-paranoia/.cvsignore create mode 100644 src/cd-paranoia/Makefile.am create mode 100644 src/cd-paranoia/buffering_write.c create mode 100644 src/cd-paranoia/buffering_write.h create mode 100644 src/cd-paranoia/cd-paranoia.1 create mode 100644 src/cd-paranoia/cd-paranoia.1.jp create mode 100644 src/cd-paranoia/cd-paranoia.c create mode 100644 src/cd-paranoia/header.c create mode 100644 src/cd-paranoia/header.h create mode 100644 src/cd-paranoia/report.c create mode 100644 src/cd-paranoia/report.h create mode 100644 src/cd-paranoia/utils.h create mode 100644 src/cd-paranoia/version.h diff --git a/.cvsignore b/.cvsignore index 13cb78c2..0e46e20b 100644 --- a/.cvsignore +++ b/.cvsignore @@ -48,6 +48,8 @@ libtool libcdio.pc libcdio.spec libiso9660.pc +libcdio_cdda.pc +libcdio_paranoia.pc ltmain.sh mkinstalldirs stamp-h1 diff --git a/Makefile.am b/Makefile.am index 0418be2d..f532f87c 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.29 2004/11/16 00:10:55 nboullis Exp $ +# $Id: Makefile.am,v 1.30 2004/12/18 17:29:32 rocky Exp $ # # Copyright (C) 2003, 2004 Rocky Bernstein # @@ -29,7 +29,8 @@ SUBDIRS = doc include lib src test example # pkg-config(1) related rules pkgconfigdir = $(libdir)/pkgconfig -pkgconfig_DATA = libiso9660.pc libcdio.pc +pkgconfig_DATA = libcdio.pc libcdio_paranoia.pc \ + libcdda_interface.pc libiso9660.pc $(pkgconfig_DATA): config.status diff --git a/configure.ac b/configure.ac index 092e5c43..78f7423e 100644 --- a/configure.ac +++ b/configure.ac @@ -19,7 +19,7 @@ define(RELEASE_NUM, 72) define(CDIO_VERSION_STR, 0.$1cvs) AC_PREREQ(2.52) -AC_REVISION([$Id: configure.ac,v 1.118 2004/12/15 01:45:15 rocky Exp $])dnl +AC_REVISION([$Id: configure.ac,v 1.119 2004/12/18 17:29:32 rocky Exp $])dnl AC_INIT(libcdio, CDIO_VERSION_STR(RELEASE_NUM)) AC_CONFIG_SRCDIR(src/cd-info.c) AM_INIT_AUTOMAKE @@ -123,6 +123,12 @@ dnl headers AC_HEADER_STDC AC_CHECK_HEADERS(errno.h fcntl.h stdio.h sys/cdio.h glob.h stdbool.h stdarg.h) +AC_CHECK_HEADERS(linux/sbpcd.h, SBPCD_H="-DSBPCD_H='1' ") +AC_CHECK_HEADERS(linux/ucdrom.h, UCDROM_H="-DUCDROM_H='1' ") + +AC_SUBST(SBPCD_H) +AC_SUBST(UCDROM_H) +AC_SUBST(TYPESIZES) dnl compiler AC_C_BIGENDIAN @@ -235,11 +241,17 @@ AM_CONDITIONAL(DISABLE_CPP, test "x$disable_cpp" = "xyes") dnl Checks for header files. -LIBCDIO_CFLAGS='-I$(top_srcdir)/lib/ -I$(top_srcdir)/include/' -LIBCDIO_LIBS='$(top_builddir)/lib/libcdio.la' -LIBISO9660_LIBS='$(top_builddir)/lib/libiso9660.la' +LIBCDIO_CDDA_LIBS='$(top_builddir)/lib/cdda_interface/libcdio_cdda.la' +LIBCDIO_CFLAGS='-I$(top_srcdir)/lib/driver -I$(top_srcdir)/include/' +LIBCDIO_LIBS='$(top_builddir)/lib/driver/libcdio.la' +LIBCDIO_PARANOIA_LIBS='$(top_builddir)/lib/paranoia/libcdio_paranoia.la' +LIBISO9660_CFLAGS='-I$(top_builddir)/lib/iso9660/' +LIBISO9660_LIBS='$(top_builddir)/lib/iso9660/libiso9660.la' +AC_SUBST(LIBCDIO_CDDA_LIBS) AC_SUBST(LIBCDIO_CFLAGS) +AC_SUBST(LIBISO9660_CFLAGS) AC_SUBST(LIBCDIO_LIBS) +AC_SUBST(LIBCDIO_PARANOIA_LIBS) AC_SUBST(LIBISO9660_LIBS) case $host_os in @@ -421,7 +433,7 @@ AC_ARG_ENABLE(vcd_info, enable_vcd_info=yes) fi if test x$enable_vcd_info = xyes; then - PKG_CHECK_MODULES(VCDINFO, libvcdinfo >= 0.7.20, + PKG_CHECK_MODULES(VCDINFO, libvcdinfo >= 0.7.21, [AC_DEFINE([HAVE_VCDINFO],1, [Define this if you have libvcdinfo installed])], [AC_MSG_WARN(a new enough libvcdinfo not found. @@ -439,7 +451,9 @@ AC_CONFIG_COMMANDS([checks], AC_CONFIG_FILES([ \ Makefile \ + libcdio_cdda.pc \ libcdio.pc \ + libcdio_paranoia.pc \ libcdio.spec \ libiso9660.pc \ example/Makefile \ @@ -449,6 +463,11 @@ AC_CONFIG_FILES([ \ doc/doxygen/Doxyfile \ doc/Makefile \ lib/Makefile \ + lib/cdda_interface/Makefile \ + lib/driver/Makefile \ + lib/iso9660/Makefile \ + lib/paranoia/Makefile \ + src/cd-paranoia/Makefile \ src/Makefile \ test/check_nrg.sh \ test/check_cue.sh \ diff --git a/include/cdio/Makefile.am b/include/cdio/Makefile.am index 4ffe4a0a..cfb18dd8 100644 --- a/include/cdio/Makefile.am +++ b/include/cdio/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.14 2004/10/28 10:08:56 rocky Exp $ +# $Id: Makefile.am,v 1.15 2004/12/18 17:29:32 rocky Exp $ # # Copyright (C) 2003, 2004 Rocky Bernstein # @@ -25,6 +25,8 @@ libcdioincludedir=$(includedir)/cdio libcdioinclude_HEADERS = \ bytesex.h \ bytesex_asm.h \ + paranoia.h \ + cdda_interface.h \ cdio.h \ cdtext.h \ cdtext.h \ diff --git a/include/cdio/cdda_interface.h b/include/cdio/cdda_interface.h new file mode 100644 index 00000000..662d1ad4 --- /dev/null +++ b/include/cdio/cdda_interface.h @@ -0,0 +1,217 @@ +/* + $Id: cdda_interface.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 2001 Xiph.org + and Heiko Eissfeldt heiko@escape.colossus.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/** \file cdda_paranoia.h + * \brief The top-level interface header; applications include this. + * + ******************************************************************/ + +#ifndef _CDDA_INTERFACE_H_ +#define _CDDA_INTERFACE_H_ + +#include + +#define CD_FRAMESAMPLES (CDIO_CD_FRAMESIZE_RAW / 4) + +#include +#include + +/** We keep MAXTRK since this header is exposed publicly and other + programs may have used this. +*/ +#define MAXTRK (CDIO_CD_MAX_TRACKS+1) + +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 CDDA_MESSAGE_FORGETIT 0 +#define CDDA_MESSAGE_PRINTIT 1 +#define CDDA_MESSAGE_LOGIT 2 + +/** cdrom access function pointer */ + +struct cdrom_drive_s { + + 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/interrfaces */ + + int (*enable_cdda) (cdrom_drive_t *d, int onoff); + int (*read_toc) (cdrom_drive_t *d); + long (*read_audio) (cdrom_drive_t *d, void *p, long begin, + long sectors); + int (*set_speed) (cdrom_drive_t *d, int speed); + int error_retry; + int report_all; + + int is_atapi; + int is_mmc; + + /* SCSI command buffer and offset pointers */ + unsigned char *sg; + unsigned char *sg_buffer; + 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; + +}; + +#define IS_AUDIO(d,i) (!(d->disc_toc[i].bFlags & 0x04)) + +/** autosense functions */ + +extern cdrom_drive_t *cdda_find_a_cdrom(int messagedest, char **message); +extern cdrom_drive_t *cdda_identify(const char *device, int messagedest, + char **message); +extern cdrom_drive_t *cdda_identify_cooked(const char *device,int messagedest, + char **message); +extern cdrom_drive_t *cdda_identify_scsi(const char *generic_device, + const char *ioctl_device, + int messagedest, char **message); +#ifdef CDDA_TEST +extern cdrom_drive_t *cdda_identify_test(const char *filename, + int messagedest, char **message); +#endif + +/** oriented functions */ + +extern int cdda_speed_set(cdrom_drive_t *d, int speed); +extern void cdda_verbose_set(cdrom_drive_t *d,int err_action, int mes_action); +extern char *cdda_messages(cdrom_drive_t *d); +extern char *cdda_errors(cdrom_drive_t *d); + +extern int cdda_close(cdrom_drive_t *d); +extern int cdda_open(cdrom_drive_t *d); +extern long cdda_read(cdrom_drive_t *d, void *buffer, + long int beginsector, long int sectors); + +extern long cdda_track_firstsector(cdrom_drive_t *d,int track); +extern long cdda_track_lastsector(cdrom_drive_t *d,int track); +extern long cdda_tracks(cdrom_drive_t *d); +extern int cdda_sector_gettrack(cdrom_drive_t *d,long sector); +extern int cdda_track_channels(cdrom_drive_t *d,int track); +extern int cdda_track_audiop(cdrom_drive_t *d,int track); +extern int cdda_track_copyp(cdrom_drive_t *d,int track); +extern int cdda_track_preemp(cdrom_drive_t *d,int track); +extern long cdda_disc_firstsector(cdrom_drive_t *d); +extern long cdda_disc_lastsector(cdrom_drive_t *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 */ + +#ifdef NEED_STRERROR_TR +const 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" +}; +#endif /*NEED_STERROR_TR*/ + +/** 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 + +*/ +#endif /*_CDDA_INTERFACE_H_*/ + diff --git a/include/cdio/cdio.h b/include/cdio/cdio.h index 4ed8d7cf..7e18b271 100644 --- a/include/cdio/cdio.h +++ b/include/cdio/cdio.h @@ -1,5 +1,5 @@ /* -*- c -*- - $Id: cdio.h,v 1.67 2004/12/15 01:45:15 rocky Exp $ + $Id: cdio.h,v 1.68 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2001 Herbert Valerio Riedel Copyright (C) 2003, 2004 Rocky Bernstein @@ -469,65 +469,65 @@ extern "C" { unsigned int i_sectors); /*! - Reads a mode1 sector + Reads a mode 1 sector @param p_cdio object to read from @param buf place to read data into @param lsn sector to read - @param b_form2 true for reading mode1 form2 sectors or false for - mode1 form1 sectors. + @param b_form2 true for reading mode1 form 2 sectors or false for + mode 1 form 1 sectors. @return 0 if no error, nonzero otherwise. */ - int cdio_read_mode1_sector (const CdIo *p_cdio, void *buf, lsn_t lsn, + int cdio_read_mode1_sector (const CdIo *p_cdio, void *p_buf, lsn_t i_lsn, bool b_form2); /*! - Reads mode1 sectors + Reads mode 1 sectors @param p_cdio object to read from @param buf place to read data into @param lsn sector to read - @param b_form2 true for reading mode1 form2 sectors or false for - mode1 form1 sectors. + @param b_form2 true for reading mode 1 form 2 sectors or false for + mode 1 form 1 sectors. @param i_sectors number of sectors to read @return 0 if no error, nonzero otherwise. */ - int cdio_read_mode1_sectors (const CdIo *p_cdio, void *buf, lsn_t lsn, + int cdio_read_mode1_sectors (const CdIo *p_cdio, void *p_buf, lsn_t i_lsn, bool b_form2, unsigned int i_sectors); /*! - Reads a mode1 sector + Reads a mode 2 sector @param p_cdio object to read from @param buf place to read data into @param lsn sector to read - @param b_form2 true for reading mode1 form2 sectors or false for - mode1 form1 sectors. + @param b_form2 true for reading mode 2 form 2 sectors or false for + mode 2 form 1 sectors. @return 0 if no error, nonzero otherwise. */ - int cdio_read_mode2_sector (const CdIo *p_cdio, void *buf, lsn_t lsn, + int cdio_read_mode2_sector (const CdIo *p_cdio, void *p_buf, lsn_t i_lsn, bool b_form2); /*! - Reads mode2 sectors + Reads mode 2 sectors @param p_cdio object to read from @param buf place to read data into @param lsn sector to read - @param b_form2 true for reading mode1 form2 sectors or false for - mode1 form1 sectors. + @param b_form2 true for reading mode2 form 2 sectors or false for + mode 2 form 1 sectors. @param i_sectors number of sectors to read @return 0 if no error, nonzero otherwise. */ - int cdio_read_mode2_sectors (const CdIo *p_cdio, void *buf, lsn_t lsn, + int cdio_read_mode2_sectors (const CdIo *p_cdio, void *p_buf, lsn_t i_lsn, bool b_form2, unsigned int i_sectors); /*! - Set the arg "key" with "value" in "obj". + Set the arg "key" with "value" in "p_cdio". @param p_cdio the CD object to set @param key the key to set diff --git a/include/cdio/paranoia.h b/include/cdio/paranoia.h new file mode 100644 index 00000000..274bb8a0 --- /dev/null +++ b/include/cdio/paranoia.h @@ -0,0 +1,123 @@ +/* + $Id: paranoia.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** \file cdda_paranoia.h + * \brief The top-level header for libcdda_paranoia: + a library for reading CD-DA with error tolerance and repair. + */ + +#ifndef _CDIO_PARANOIA_H_ +#define _CDIO_PARANOIA_H_ + +#include + +#define CD_FRAMEWORDS (CDIO_CD_FRAMESIZE_RAW/2) + +/**! Flags used in paranoia_modeset. */ + +#define PARANOIA_MODE_FULL 0xff +#define PARANOIA_MODE_DISABLE 0 + +#define PARANOIA_MODE_VERIFY 1 +#define PARANOIA_MODE_FRAGMENT 2 +#define PARANOIA_MODE_OVERLAP 4 +#define PARANOIA_MODE_SCRATCH 8 +#define PARANOIA_MODE_REPAIR 16 +#define PARANOIA_MODE_NEVERSKIP 32 + +/** cdrom_paranoia is an opaque structure which is used in all of the + library operations. + */ +typedef struct cdrom_paranoia_s cdrom_paranoia_t; +typedef struct cdrom_drive_s cdrom_drive_t; + +typedef enum { + PARANOIA_CB_READ, + PARANOIA_CB_VERIFY, + PARANOIA_CB_FIXUP_EDGE, + PARANOIA_CB_FIXUP_ATOM, + PARANOIA_CB_SCRATCH, + PARANOIA_CB_REPAIR, + PARANOIA_CB_SKIP, + PARANOIA_CB_DRIFT, + PARANOIA_CB_BACKOFF, + PARANOIA_CB_OVERLAP, + PARANOIA_CB_FIXUP_DROPPED, + PARANOIA_CB_FIXUP_DUPED, + PARANOIA_CB_READERR +} paranoia_cb_mode_t; + +#ifdef __cplusplus +extern "C" { +#endif + + /*! + Get and initialize a new cdrom_paranoia object from cdrom_drive. + Run this before calling any of the other paranoia routines below. + + @return new cdrom_paranoia object Call paranoia_free() when you are + done with it + */ +extern cdrom_paranoia_t *paranoia_init(cdrom_drive_t *d); + + /*! + Free any resources associated with obj. + + @see paranoia_init. + */ +extern void paranoia_free(cdrom_paranoia_t *p); + + /*! + Set the kind of repair you want to on for reading. + The modes are listed above + */ +extern void paranoia_modeset(cdrom_paranoia_t *p, int mode); + + /*! + reposition reading offset. + + @param whence like corresponding parameter in libc's lseek, e.g. + SEEK_SET or SEEK_END. + */ +extern lsn_t paranoia_seek(cdrom_paranoia_t *p, off_t seek, int whence); + + /*! The returned buffer is *not* to be freed by the caller. It will + persist only until the next call to paranoia_read() for this p + */ +extern int16_t *paranoia_read(cdrom_paranoia_t *p, + void(*callback)(long int, paranoia_cb_mode_t)); + +extern int16_t *paranoia_read_limited(cdrom_paranoia_t *p, + void(*callback)(long int, + paranoia_cb_mode_t), + int maxretries); + + +extern void paranoia_overlapset(cdrom_paranoia_t *p,long overlap); + +extern void paranoia_set_range(cdrom_paranoia_t *p, long int start, + long int end); + +#ifdef __cplusplus +} +#endif + +#endif /*_CDIO_PARANOIA_H_*/ diff --git a/include/cdio/scsi_mmc.h b/include/cdio/scsi_mmc.h index 632b85fa..d32b752c 100644 --- a/include/cdio/scsi_mmc.h +++ b/include/cdio/scsi_mmc.h @@ -1,5 +1,5 @@ /* - $Id: scsi_mmc.h,v 1.35 2004/12/04 12:01:48 rocky Exp $ + $Id: scsi_mmc.h,v 1.36 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein @@ -415,12 +415,18 @@ char *scsi_mmc_get_mcn ( const CdIo *p_cdio ); Can read only up to 25 blocks. */ int scsi_mmc_read_sectors ( const CdIo *p_cdio, void *p_buf, lba_t lba, - int sector_type, unsigned int nblocks); + int sector_type, unsigned int i_blocks); /*! Set the block size for subsequest read requests, via a SCSI MMC MODE_SELECT 6 command. */ -int scsi_mmc_set_blocksize ( const CdIo *p_cdio, unsigned int bsize); +int scsi_mmc_set_blocksize ( const CdIo *p_cdio, unsigned int i_bsize); + +/*! + Set the block size for subsequest read requests, via a SCSI MMC + MODE_SENSE 6 command. + */ +int scsi_mmc_get_blocksize ( const CdIo *p_cdio ); #endif /* __SCSI_MMC_H__ */ diff --git a/include/cdio/types.h b/include/cdio/types.h index 6609be61..dbe0214d 100644 --- a/include/cdio/types.h +++ b/include/cdio/types.h @@ -1,5 +1,5 @@ /* - $Id: types.h,v 1.23 2004/09/03 23:20:11 rocky Exp $ + $Id: types.h,v 1.24 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2002, 2003, 2004 Rocky Bernstein @@ -298,8 +298,6 @@ extern "C" { #define CDIO_DRIVE_CAP_MISC_MULTI_SESSION 0x00020 /**< read sessions>1 */ #define CDIO_DRIVE_CAP_MISC_MEDIA_CHANGED 0x00080 /**< media changed */ #define CDIO_DRIVE_CAP_MISC_RESET 0x00100 /**< hard reset device */ -#define CDIO_DRIVE_CAP_MCN 0x00200 /**< can read MCN */ -#define CDIO_DRIVE_CAP_ISRC 0x00200 /**< can read ISRC */ #define CDIO_DRIVE_CAP_MISC_FILE 0x20000 /**< drive is really a file, i.e a CD file image */ @@ -316,6 +314,10 @@ extern "C" { #define CDIO_DRIVE_CAP_READ_DVD_RW 0x00200 /**< drive can read DVD-RW */ #define CDIO_DRIVE_CAP_READ_DVD_RPW 0x00400 /**< drive can read DVD+RW */ #define CDIO_DRIVE_CAP_READ_C2_ERRS 0x00800 /**< has C2 error correction */ +#define CDIO_DRIVE_CAP_READ_MODE2_FORM1 0x01000 /**< can read mode 2 form 1 */ +#define CDIO_DRIVE_CAP_READ_MODE2_FORM2 0x02000 /**< can read mode 2 form 2 */ +#define CDIO_DRIVE_CAP_READ_MCN 0x04000 /**< can read MCN */ +#define CDIO_DRIVE_CAP_READ_ISRC 0x08000 /**< can read ISRC */ /*! Writing masks.. */ #define CDIO_DRIVE_CAP_WRITE_CD_R 0x00001 /**< drive can write CD-R */ diff --git a/lib/.cvsignore b/lib/.cvsignore index ed5ff996..22a4e729 100644 --- a/lib/.cvsignore +++ b/lib/.cvsignore @@ -1,9 +1,3 @@ -.deps -.libs Makefile Makefile.in -*.o -*.lo -*.la -*.la.ver diff --git a/lib/Makefile.am b/lib/Makefile.am index 4ec9e94b..f4c3726f 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.64 2004/12/15 01:45:15 rocky Exp $ +# $Id: Makefile.am,v 1.65 2004/12/18 17:29:32 rocky Exp $ # # Copyright (C) 2003, 2004 Rocky Bernstein # @@ -17,187 +17,7 @@ # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # ######################################################## -# Things to make the libcdio and libiso9660 libraries -######################################################## -# -# From libtool documentation amended with guidance from N. Boullis: -# -# 1. Start with version information of `0:0:0' for each libtool library. -# -# 2. It is probably not a good idea to update the version information -# several times between public releases, but rather once per public -# release. (This seems to be more an aesthetic consideration than -# a hard technical one.) -# -# 3. If the library source code has changed at all since the last -# update, then increment REVISION (`C:R:A' becomes `C:R+1:A'). -# -# 4. If any interfaces have been added, removed, or changed since the -# last update, increment CURRENT, and set REVISION to 0. -# -# 5. If any interfaces have been added since the last public release, -# then increment AGE. -# -# 6. If any interfaces have been removed or changed since the last -# public release, then set AGE to 0. A changed interface means an -# incompatibility with previous versions. - -libcdio_la_CURRENT := 3 -libcdio_la_REVISION := 0 -libcdio_la_AGE := 0 - -libiso9660_la_CURRENT := 3 -libiso9660_la_REVISION := 0 -libiso9660_la_AGE := 0 - -EXTRA_DIST = image/Makefile FreeBSD/Makefile MSWindows/Makefile \ - libcdio.sym libiso9660.sym - -noinst_HEADERS = cdio_assert.h cdio_private.h portable.h - -libcdio_sources = \ - _cdio_aix.c \ - _cdio_bsdi.c \ - _cdio_generic.c \ - _cdio_linux.c \ - _cdio_osx.c \ - _cdio_stdio.c \ - _cdio_stdio.h \ - _cdio_stream.c \ - _cdio_stream.h \ - _cdio_sunos.c \ - cd_types.c \ - cdio.c \ - cdtext.c \ - cdtext_private.h \ - ds.c \ - FreeBSD/freebsd.c \ - FreeBSD/freebsd.h \ - FreeBSD/freebsd_cam.c \ - FreeBSD/freebsd_ioctl.c \ - generic.h \ - image.h \ - image/bincue.c \ - image/cdrdao.c \ - image_common.h \ - image/nrg.c \ - image/nrg.h \ - MSWindows/aspi32.c \ - MSWindows/aspi32.h \ - MSWindows/win32_ioctl.c \ - MSWindows/win32.c \ - MSWindows/win32.h \ - logging.c \ - scsi_mmc.c \ - scsi_mmc_private.h \ - sector.c \ - util.c - -lib_LTLIBRARIES = libcdio.la libiso9660.la - -libcdio_la_SOURCES = $(libcdio_sources) -libcdio_la_ldflags = -version-info $(libcdio_la_CURRENT):$(libcdio_la_REVISION):$(libcdio_la_AGE) - -libiso9660_la_SOURCES = \ - iso9660.c \ - iso9660_private.h \ - iso9660_fs.c \ - xa.c - -libiso9660_la_LIBADD = libcdio.la -libiso9660_la_ldflags = -version-info $(libiso9660_la_CURRENT):$(libiso9660_la_REVISION):$(libiso9660_la_AGE) - -INCLUDES = $(LIBCDIO_CFLAGS) - -######################################################## -# Things to version the symbols in the libraries +# make all libraries ######################################################## -# An explanation of the versioning problem from Nicolas Boullis and -# the versioned symbol solution he uses below... -# -# Currently, libvcdinfo uses the cdio_open function from libcdio. -# Let's imagine a program foobar that uses both the vcdinfo_open -# function from libvcdinfo and the cdio_open function from libcdio. - -# Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME -# libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both -# libvcdinfo.so.0 and libcdio.so.0. Everything looks fine. -# -# Now, for some reason, you decide to change the cdio_open function. -# That's your right, but you have to bump the CURRENT version and (if I -# understand it correctly, athough this is not that clear in libtool's -# documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is -# sane since the interface changes incompatibly. - -# Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and -# foobar still require libcdio.so.0. Everything is still fine. - -# Now, after some minor changes, the author of foobar recompiles foobar. -# Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar -# now segfaults... - -# What is happening? When you run foobar, if brings both libvcdinfo.so.0 -# and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you -# have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the -# global namespace. Hence, you have to incompatible versions of the -# cdio_open function in the name space. When foobar calls cdio_open, it -# may choose the wrong function, and segfaults... - -# With versioned symbols, the cdio_open function from libcdio.so.0 may be -# known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open -# function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of -# libcdio would still be brought in by the most recent foobar, but foobar -# (and libvcdinfo) know which versioned function to use and then use the -# good one. - - -# This is some simple versioning where every symbol is versioned with -# something that looks like the SONAME of the library. More complex (and -# better) versioning is possible; it is for example what is used by glibc. -# But good complex versioning is something that requires much more -# work... - - -# The below is a impliments symbol versioning. First of all, I -# compute MAJOR as CURENT - AGE; that is what is used within libtool -# (at least on GNU/Linux systems) for the number in the SONAME. The -# nm command gives the list of symbols known in each of the object -# files that will be part of the shared library. And the sed command -# extracts from this list those symbols that will be shared. (This sed -# command comes from libtool.) - -libcdio_la_MAJOR := $(shell expr $(libcdio_la_CURRENT) - $(libcdio_la_AGE)) -if BUILD_VERSIONED_LIBS -libcdio_la_LDFLAGS = $(libcdio_la_ldflags) -Wl,--version-script=libcdio.la.ver -libcdio_la_DEPENDENCIES = libcdio.la.ver - -libcdio.la.ver: $(libcdio_la_OBJECTS) $(srcdir)/libcdio.sym - echo 'CDIO_$(libcdio_la_MAJOR) { ' > $@ - echo " global:" >> $@ - nm $(patsubst %.lo,%.o,$(libcdio_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio.sym; then echo " $${symbol};"; fi; done >> $@ - echo " local:" >> $@ - nm $(patsubst %.lo,%.o,$(libcdio_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio.sym; then :; else echo " $${symbol};"; fi; done >> $@ - echo '};' >> $@ -else -libcdio_la_LDFLAGS = $(libcdio_la_ldflags) -endif - -libiso9660_la_MAJOR := $(shell expr $(libiso9660_la_CURRENT) - $(libiso9660_la_AGE)) -if BUILD_VERSIONED_LIBS -libiso9660_la_LDFLAGS = $(libiso9660_la_ldflags) -Wl,--version-script=libiso9660.la.ver -libiso9660_la_DEPENDENCIES = libcdio.la libiso9660.la.ver - -libiso9660.la.ver: $(libiso9660_la_OBJECTS) $(srcdir)/libiso9660.sym - echo 'ISO9660_$(libiso9660_la_MAJOR) {' > $@ - echo " global:" >> $@ - nm $(patsubst %.lo,%.o,$(libiso9660_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libiso9660.sym; then echo " $${symbol};"; fi; done >> $@ - echo " local:" >> $@ - nm $(patsubst %.lo,%.o,$(libiso9660_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libiso9660.sym; then :; else echo " $${symbol};"; fi; done >> $@ - echo '};' >> $@ - -MOSTLYCLEANFILES = libcdio.la.ver libiso9660.la.ver -else -libiso9660_la_LDFLAGS = $(libiso9660_la_ldflags) -libiso9660_la_DEPENDENCIES = libcdio.la -endif +SUBDIRS = driver iso9660 cdda_interface paranoia diff --git a/lib/cdda_interface/.cvsignore b/lib/cdda_interface/.cvsignore new file mode 100644 index 00000000..c17b1b9e --- /dev/null +++ b/lib/cdda_interface/.cvsignore @@ -0,0 +1,8 @@ +.deps +.libs +Makefile +Makefile.in +*.o +*.lo +*.la +*.la.ver diff --git a/lib/cdda_interface/Makefile.am b/lib/cdda_interface/Makefile.am new file mode 100644 index 00000000..f4f37fd8 --- /dev/null +++ b/lib/cdda_interface/Makefile.am @@ -0,0 +1,76 @@ +# $Id: Makefile.am,v 1.1 2004/12/18 17:29:32 rocky Exp $ +# +# Copyright (C) 2004 Rocky Bernstein +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +######################################################## +# Things to make the cdda_interface library +######################################################## + +# +# From libtool documentation amended with guidance from N. Boullis: +# +# 1. Start with version information of `0:0:0' for each libtool library. +# +# 2. It is probably not a good idea to update the version information +# several times between public releases, but rather once per public +# release. (This seems to be more an aesthetic consideration than +# a hard technical one.) +# +# 3. If the library source code has changed at all since the last +# update, then increment REVISION (`C:R:A' becomes `C:R+1:A'). +# +# 4. If any interfaces have been added, removed, or changed since the +# last update, increment CURRENT, and set REVISION to 0. +# +# 5. If any interfaces have been added since the last public release, +# then increment AGE. +# +# 6. If any interfaces have been removed or changed since the last +# public release, then set AGE to 0. A changed interface means an +# incompatibility with previous versions. + +libcdio_cdda_la_CURRENT := 0 +libcdio_cdda_la_REVISION := 0 +libcdio_cdda_la_AGE := 0 + +noinst_HEADERS = common_interface.h drive_exceptions.h low_interface.h \ + smallft.h utils.h + +libcdio_cdda_sources = common_interface.c cooked_interface.c interface.c \ + scan_devices.c scsi_interface.c smallft.c test_interface.c \ + toc.c utils.c + +lib_LTLIBRARIES = libcdio_cdda.la + +libcdio_cdda_la_SOURCES = $(libcdio_cdda_sources) +libcdio_cdda_la_ldflags = -version-info $(libcdio_cdda_la_CURRENT):$(libcdio_cdda_la_REVISION):$(libcdio_cdda_la_AGE) + +libcdio_cdda_la_LDFLAGS = $(libcdio_cdda_la_ldflags) + +INCLUDES = $(LIBCDIO_CFLAGS) + +FLAGS=@LIBCDIO_CFLAGS@ @UCDROM_H@ @TYPESIZES@ @CFLAGS@ + +OPT=$(FLAGS) +DEBUG=$(FLAGS) -DCDDA_TEST + +## test: +## $(MAKE) libcdio_cdda.a CFLAGS="$(DEBUG)" +## $(CC) $(DEBUG) -c test_interface.c +## $(LD) $(DEBUG) test_interface.o $(LDFLAGS) -o cdda_test $(LIBS) libcdio_cdda.a + +LIBS = $(LIBCDIO_LIBS) diff --git a/lib/cdda_interface/common_interface.c b/lib/cdda_interface/common_interface.c new file mode 100644 index 00000000..f42daa22 --- /dev/null +++ b/lib/cdda_interface/common_interface.c @@ -0,0 +1,262 @@ +/* + $Id: common_interface.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998, 2002 Monty monty@xiph.org + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/****************************************************************** + * + * CDROM communication common to all interface methods is done here + * (mostly ioctl stuff, but not ioctls specific to the 'cooked' + * interface) + * + ******************************************************************/ + +#include +#include "common_interface.h" +#include "utils.h" +#include "smallft.h" + +#include + +/* Test for presence of a cdrom by pinging with the 'CDROMVOLREAD' ioctl() */ +int +ioctl_ping_cdrom(int fd) +{ + struct cdrom_volctrl volctl; + if (ioctl(fd, CDROMVOLREAD, &volctl)) + return(1); /* failure */ + + return(0); + /* success! */ +} + + +/* Use the ioctl thingy above ping the cdrom; this will get model info */ +char *atapi_drive_info(int fd){ + /* Work around the fact that the struct grew without warning in + 2.1/2.0.34 */ + + struct hd_driveid *id=malloc(512); /* the size in 2.0.34 */ + char *ret; + + if (!(ioctl(fd, HDIO_GET_IDENTITY, id))) { + + if(id->model==0 || id->model[0]==0) + ret=copystring("Generic Unidentifiable ATAPI CDROM"); + else + ret=copystring(id->model); + }else + ret=copystring("Generic Unidentifiable CDROM"); + + free(id); + return(ret); +} + +int +data_bigendianp(cdrom_drive_t *d) +{ + float lsb_votes=0; + float msb_votes=0; + int i,checked; + int endiancache=d->bigendianp; + float *a=calloc(1024,sizeof(float)); + float *b=calloc(1024,sizeof(float)); + long readsectors=5; + int16_t *buff=malloc(readsectors*CDIO_CD_FRAMESIZE_RAW); + + /* look at the starts of the audio tracks */ + /* if real silence, tool in until some static is found */ + + /* Force no swap for now */ + d->bigendianp=-1; + + cdmessage(d,"\nAttempting to determine drive endianness from data..."); + d->enable_cdda(d,1); + for(i=0,checked=0;itracks;i++){ + float lsb_energy=0; + float msb_energy=0; + if(cdda_track_audiop(d,i+1)==1){ + long firstsector=cdda_track_firstsector(d,i+1); + long lastsector=cdda_track_lastsector(d,i+1); + int zeroflag=-1; + long beginsec=0; + + /* find a block with nonzero data */ + + while(firstsector+readsectors<=lastsector){ + int j; + + if(d->read_audio(d,buff,firstsector,readsectors)>0){ + + /* Avoid scanning through jitter at the edges */ + for(beginsec=0;beginsecenable_cdda(d,0); + free(a); + free(b); + free(buff); + return(-1); + } + } + + beginsec*=CDIO_CD_FRAMESIZE_RAW/2; + + /* un-interleave for an fft */ + if(!zeroflag){ + int j; + + for(j=0;j<128;j++)a[j]=le16_to_cpu(buff[j*2+beginsec+460]); + for(j=0;j<128;j++)b[j]=le16_to_cpu(buff[j*2+beginsec+461]); + fft_forward(128,a,NULL,NULL); + fft_forward(128,b,NULL,NULL); + for(j=0;j<128;j++)lsb_energy+=fabs(a[j])+fabs(b[j]); + + for(j=0;j<128;j++)a[j]=be16_to_cpu(buff[j*2+beginsec+460]); + for(j=0;j<128;j++)b[j]=be16_to_cpu(buff[j*2+beginsec+461]); + fft_forward(128,a,NULL,NULL); + fft_forward(128,b,NULL,NULL); + for(j=0;j<128;j++)msb_energy+=fabs(a[j])+fabs(b[j]); + } + } + if(lsb_energymsb_energy){ + msb_votes+=lsb_energy/msb_energy; + checked++; + } + + if(checked==5 && (lsb_votes==0 || msb_votes==0))break; + cdmessage(d,"."); + } + + free(buff); + free(a); + free(b); + d->bigendianp=endiancache; + d->enable_cdda(d,0); + + /* How did we vote? Be potentially noisy */ + if(lsb_votes>msb_votes){ + char buffer[256]; + cdmessage(d,"\n\tData appears to be coming back little endian.\n"); + sprintf(buffer,"\tcertainty: %d%%\n",(int) + (100.*lsb_votes/(lsb_votes+msb_votes)+.5)); + cdmessage(d,buffer); + return(0); + }else{ + if(msb_votes>lsb_votes){ + char buffer[256]; + cdmessage(d,"\n\tData appears to be coming back big endian.\n"); + sprintf(buffer,"\tcertainty: %d%%\n",(int) + (100.*msb_votes/(lsb_votes+msb_votes)+.5)); + cdmessage(d,buffer); + return(1); + } + + cdmessage(d,"\n\tCannot determine CDROM drive endianness.\n"); + return(bigendianp()); + return(-1); + } +} + +/************************************************************************/ +/* Here we fix up a couple of things that will never happen. yeah, + right. The multisession stuff is from Hannu's code; it assumes it + knows the leadoud/leadin size. */ + +int +FixupTOC(cdrom_drive_t *d,int tracks) +{ + struct cdrom_multisession ms_str; + int j; + + /* First off, make sure the 'starting sector' is >=0 */ + + for(j=0;jdisc_toc[j].dwStartSector<0){ + cdmessage(d,"\n\tTOC entry claims a negative start offset: massaging" + ".\n"); + d->disc_toc[j].dwStartSector=0; + } + if(jdisc_toc[j].dwStartSector> + d->disc_toc[j+1].dwStartSector){ + cdmessage(d,"\n\tTOC entry claims an overly large start offset: massaging" + ".\n"); + d->disc_toc[j].dwStartSector=0; + } + + } + /* Make sure the listed 'starting sectors' are actually increasing. + Flag things that are blatant/stupid/wrong */ + { + long last=d->disc_toc[0].dwStartSector; + for(j=1;jdisc_toc[j].dwStartSectordisc_toc[j].dwStartSector=last; + + } + last=d->disc_toc[j].dwStartSector; + } + } + + /* For a scsi device, the ioctl must go to the specialized SCSI + CDROM device, not the generic device. */ + + if (d->ioctl_fd != -1) { + int result; + + ms_str.addr_format = CDROM_LBA; + result = ioctl(d->ioctl_fd, CDROMMULTISESSION, &ms_str); + if (result == -1) return -1; + + if (ms_str.addr.lba > 100) { + + /* This is an odd little piece of code --Monty */ + + /* believe the multisession offset :-) */ + /* adjust end of last audio track to be in the first session */ + for (j = tracks-1; j >= 0; j--) { + if (j > 0 && !IS_AUDIO(d,j) && IS_AUDIO(d,j-1)) { + if ((d->disc_toc[j].dwStartSector > ms_str.addr.lba - 11400) && + (ms_str.addr.lba - 11400 > d->disc_toc[j-1].dwStartSector)) + d->disc_toc[j].dwStartSector = ms_str.addr.lba - 11400; + break; + } + } + return 1; + } + } + return 0; +} + + diff --git a/lib/cdda_interface/common_interface.h b/lib/cdda_interface/common_interface.h new file mode 100644 index 00000000..50fc5e4d --- /dev/null +++ b/lib/cdda_interface/common_interface.h @@ -0,0 +1,34 @@ +/* + $Id: common_interface.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _CDDA_COMMON_INTERFACE_H_ +#define _CDDA_COMMON_INTERFACE_H_ + +#include "low_interface.h" + +/* Test for presence of a cdrom by pinging with the 'CDROMVOLREAD' ioctl() */ +extern int ioctl_ping_cdrom(int fd); + +extern char *atapi_drive_info(int fd); +extern int data_bigendianp(cdrom_drive_t *d); +extern int FixupTOC(cdrom_drive_t *d,int tracks); + +#endif /*_CDDA_COMMON_INTERFACE_H_*/ diff --git a/lib/cdda_interface/cooked_interface.c b/lib/cdda_interface/cooked_interface.c new file mode 100644 index 00000000..2eb73353 --- /dev/null +++ b/lib/cdda_interface/cooked_interface.c @@ -0,0 +1,291 @@ +/* + $Id: cooked_interface.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Original interface.c Copyright (C) 1994-1997 + Eissfeldt heiko@colossus.escape.de + Current blenderization Copyright (C) 1998-1999 Monty xiphmont@mit.edu + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/****************************************************************** + * + * CDROM code specific to the cooked ioctl interface + * + ******************************************************************/ + +#include "low_interface.h" +#include "common_interface.h" +#include "utils.h" + +static int +cooked_readtoc (cdrom_drive_t *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;iioctl_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 = CDIO_CDROM_LEADOUT_TRACK; + 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_t *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 int +cooked_read (cdrom_drive_t *d, void *p, long begin, long sectors) +{ + int retry_count,err; + struct cdrom_read_audio arg; + char *buffer=(char *)p; + + /* read d->nsectors at a time, max. */ + sectors=(sectors>d->nsectors?d->nsectors:sectors); + + arg.addr.lba = begin; + arg.addr_format = CDROM_LBA; + arg.nframes = sectors; + arg.buf=buffer; + retry_count=0; + + do { + if((err=ioctl(d->ioctl_fd, CDROMREADAUDIO, &arg))){ + if(!d->error_retry)return(-7); + 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"); + return(-300); + } + 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); + return(-10); + + } + 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"); + return(-7); + } + }else + break; + } while (err); + + return(sectors); +} + +/* hook */ +static int Dummy (cdrom_drive_t *d,int Switch) +{ + return(0); +} + +static int +verify_read_command(cdrom_drive_t *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_t *d, const exception_t *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_t *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->set_speed = cooked_setspeed; + d->read_toc = cooked_readtoc; + 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); +} + diff --git a/lib/cdda_interface/drive_exceptions.h b/lib/cdda_interface/drive_exceptions.h new file mode 100644 index 00000000..cf55ce1a --- /dev/null +++ b/lib/cdda_interface/drive_exceptions.h @@ -0,0 +1,95 @@ +/* + $Id: drive_exceptions.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +extern int scsi_enable_cdda(cdrom_drive_t *d, int); +extern long scsi_read_mmc(cdrom_drive_t *d, void *,long,long); +extern long scsi_read_mmc2(cdrom_drive_t *d, void *,long,long); +extern long scsi_read_D4_10(cdrom_drive_t *, void *,long,long); +extern long scsi_read_D4_12(cdrom_drive_t *, void *,long,long); +extern long scsi_read_D8(cdrom_drive_t *, void *,long,long); +extern long scsi_read_28(cdrom_drive_t *, void *,long,long); +extern long scsi_read_A8(cdrom_drive_t *, void *,long,long); + +typedef struct exception { + const char *model; + int atapi; /* If the ioctl doesn't work */ + unsigned char density; + int (*enable)(cdrom_drive_t *,int); + long (*read)(cdrom_drive_t *,void *, long, long); + int bigendianp; +} exception_t; + +/* specific to general */ + +/* list of drives that affect autosensing in ATAPI specific portions of code + (force drives to detect as ATAPI or SCSI, force ATAPI read command */ + +static exception_t atapi_list[]={ + {"SAMSUNG SCR-830 REV 2.09 2.09 ", 1, 0, Dummy,scsi_read_mmc2,0}, + {"Memorex CR-622", 1, 0, Dummy, NULL,0}, + {"SONY CD-ROM CDU-561", 0, 0, Dummy, NULL,0}, + {"Chinon CD-ROM CDS-525", 0, 0, Dummy, NULL,0}, + {NULL,0,0,NULL,NULL,0}}; + +/* list of drives that affect MMC default settings */ + +#ifdef NEED_MMC_LIST +static exception_t mmc_list[]={ + {"SAMSUNG SCR-830 REV 2.09 2.09 ", 1, 0, Dummy,scsi_read_mmc2,0}, + {"Memorex CR-622", 1, 0, Dummy, NULL,0}, + {"SONY CD-ROM CDU-561", 0, 0, Dummy, NULL,0}, + {"Chinon CD-ROM CDS-525", 0, 0, Dummy, NULL,0}, + {"KENWOOD CD-ROM UCR", -1, 0, NULL,scsi_read_D8, 0}, + {NULL,0,0,NULL,NULL,0}}; +#endif /*NEED_MMC_LIST*/ + +/* list of drives that affect SCSI default settings */ + +#ifdef NEED_SCSI_LIST +static exception_t scsi_list[]={ + {"TOSHIBA", -1,0x82,scsi_enable_cdda,scsi_read_28, 0}, + {"IBM", -1,0x82,scsi_enable_cdda,scsi_read_28, 0}, + {"DEC", -1,0x82,scsi_enable_cdda,scsi_read_28, 0}, + + {"IMS", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, + {"KODAK", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, + {"RICOH", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, + {"HP", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, + {"PHILIPS", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, + {"PLASMON", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, + {"GRUNDIG CDR100IPW", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, + {"MITSUMI CD-R ", -1, 0,scsi_enable_cdda,scsi_read_28, 1}, + {"KENWOOD CD-ROM UCR", -1, 0, NULL,scsi_read_D8, 0}, + + {"YAMAHA", -1, 0,scsi_enable_cdda, NULL, 0}, + + {"PLEXTOR", -1, 0, NULL, NULL, 0}, + {"SONY", -1, 0, NULL, NULL, 0}, + + {"NEC", -1, 0, NULL,scsi_read_D4_10,0}, + + /* the 7501 locks up if hit with the 10 byte version from the + autoprobe first */ + {"MATSHITA CD-R CW-7501", -1, 0, NULL,scsi_read_D4_12,-1}, + + {NULL,0,0,NULL,NULL,0}}; + +#endif /* NEED_SCSI_LIST*/ diff --git a/lib/cdda_interface/interface.c b/lib/cdda_interface/interface.c new file mode 100644 index 00000000..3f63b30a --- /dev/null +++ b/lib/cdda_interface/interface.c @@ -0,0 +1,149 @@ +/****************************************************************** + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) 1998 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" + +static void _clean_messages(cdrom_drive_t *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_t *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->sg)free(d->sg); + + free(d); + } + return(0); +} + +/* finish initializing the drive! */ +int +cdda_open(cdrom_drive_t *d) +{ + int ret; + if(d->opened)return(0); + + switch(d->interface){ + 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;itracks;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_t *d, int speed) +{ + return d->set_speed ? d->set_speed(d, speed) : 0; +} + +long cdda_read(cdrom_drive_t *d, void *buffer, long beginsector, long sectors) +{ + if(d->opened){ + if(sectors>0){ + sectors=d->read_audio(d,buffer,beginsector,sectors); + + if(sectors!=-1){ + /* 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;imessagedest=mes_action; + d->errordest=err_action; +} + +extern char *cdda_messages(cdrom_drive_t *d) +{ + char *ret=d->messagebuf; + d->messagebuf=NULL; + return(ret); +} + +extern char *cdda_errors(cdrom_drive_t *d) +{ + char *ret=d->errorbuf; + d->errorbuf=NULL; + return(ret); +} + diff --git a/lib/cdda_interface/low_interface.h b/lib/cdda_interface/low_interface.h new file mode 100644 index 00000000..8dd57ce7 --- /dev/null +++ b/lib/cdda_interface/low_interface.h @@ -0,0 +1,86 @@ +/* + $Id: low_interface.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/** internal include file for cdda interface kit for Linux */ + +#ifndef _CDDA_LOW_INTERFACE_ +#define _CDDA_LOW_INTERFACE_ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* some include file locations have changed with newer kernels */ + +#ifdef SBPCD_H +#include +#endif + +#ifdef UCDROM_H +#include +#endif + +#ifndef CDROMAUDIOBUFSIZ +#define CDROMAUDIOBUFSIZ 0x5382 /* set the audio buffer size */ +#endif + +#include +#include + +#include +#include + +#define MAX_RETRIES 8 +#define MAX_BIG_BUFF_SIZE 65536 +#define MIN_BIG_BUFF_SIZE 4096 +#define SG_OFF sizeof(struct sg_header) + +#ifndef SG_EMULATED_HOST +/* old kernel version; the check for the ioctl is still runtime, this + is just to build */ +#define SG_EMULATED_HOST 0x2203 +#define SG_SET_TRANSFORM 0x2204 +#define SG_GET_TRANSFORM 0x2205 +#endif + +extern int cooked_init_drive (cdrom_drive_t *d); +extern unsigned char *scsi_inquiry (cdrom_drive_t *d); +extern int scsi_init_drive (cdrom_drive_t *d); +#ifdef CDDA_TEST +extern int test_init_drive (cdrom_drive_t *d); +#endif +#endif /*_CDDA_LOW_INTERFACE_*/ + diff --git a/lib/cdda_interface/scan_devices.c b/lib/cdda_interface/scan_devices.c new file mode 100644 index 00000000..0e3a209e --- /dev/null +++ b/lib/cdda_interface/scan_devices.c @@ -0,0 +1,733 @@ +/* + $Id: scan_devices.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/****************************************************************** + * + * Autoscan for or verify presence of a cdrom device + * + ******************************************************************/ + +#include +#include +#include +#include +#include +#include +#include +#include +#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! */ +const char *scsi_cdrom_prefixes[]={ + "/dev/scd", + "/dev/sr", + NULL}; +const char *scsi_generic_prefixes[]={ + "/dev/sg", + NULL}; + +const char *devfs_scsi_test="/dev/scsi/"; +const char *devfs_scsi_cd="cd"; +const char *devfs_scsi_generic="generic"; + +const 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_t * +cdda_find_a_cdrom(int messagedest, char **messages){ + /* Brute force... */ + + int i=0; + cdrom_drive_t *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++; + } + { + struct passwd *temp; + temp=getpwuid(geteuid()); + idmessage(messagedest,messages, + "\n\nNo cdrom drives accessible to %s found.\n", + temp->pw_name); + } + return(NULL); +} + +cdrom_drive_t * +cdda_identify(const char *device, int messagedest,char **messages) +{ + struct stat st; + cdrom_drive_t *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 + + d=cdda_identify_cooked(device,messagedest,messages); + if(!d)d=cdda_identify_scsi(device,NULL,messagedest,messages); + +#ifdef CDDA_TEST + if(!d)d=cdda_identify_test(device,messagedest,messages); +#endif + + return(d); +} + +static 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_t * +cdda_identify_cooked(const char *dev, int messagedest, + char **messages) +{ + + cdrom_drive_t *d=NULL; + struct stat st; + int fd=-1; + 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); + } + + if(fd==-1)fd=open(device,O_RDONLY|O_NONBLOCK); + if(fd==-1){ + idperror(messagedest,messages,"\t\tUnable to open %s",device); + free(device); + if(description)free(description); + return(NULL); + } + + /* Minimum init */ + + d=calloc(1,sizeof(cdrom_drive_t)); + 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; + 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, const char **prefixes, + const char *devfs_test, + const char *devfs_other, + const 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); + 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; + + 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); + 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); +} + +static 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_t *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); +} + +cdrom_drive_t * +cdda_identify_scsi(const char *generic_device, + const char *ioctl_device, int messagedest, + char **messages) +{ + cdrom_drive_t *d=NULL; + struct stat i_st; + struct stat g_st; + int i_fd=-1; + int g_fd=-1; + int version; + int type=-1; + char *p; + + if(generic_device) + idmessage(messagedest,messages,"\tTesting %s for SCSI interface", + generic_device); + else + if(ioctl_device) + idmessage(messagedest,messages,"\tTesting %s for SCSI interface", + ioctl_device); + + + /* Do this first; it's wasteful, but the messages make more sense */ + if(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){ + if((int)(g_st.st_rdev>>8)!=SCSI_CDROM_MAJOR){ + idmessage(messagedest,messages,"\t\t%s is not a SCSI device", + generic_device); + return(NULL); + }else{ + char *temp=(char *)generic_device; + generic_device=ioctl_device; + ioctl_device=temp; + } + } + } + if(ioctl_device){ + if(stat(ioctl_device,&i_st)){ + idperror(messagedest,messages,"\t\tCould not access device %s", + ioctl_device); + return(NULL); + } + if((int)(i_st.st_rdev>>8)!=SCSI_CDROM_MAJOR){ + if((int)(i_st.st_rdev>>8)!=SCSI_GENERIC_MAJOR){ + idmessage(messagedest,messages,"\t\t%s is not a SCSI device", + ioctl_device); + return(NULL); + }else{ + char *temp=(char *)generic_device; + generic_device=ioctl_device; + ioctl_device=temp; + } + } + } + + /* 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(ioctl_device){ + ioctl_device=test_resolve_symlink(ioctl_device,messagedest,messages); + if(ioctl_device==NULL)goto cdda_identify_scsi_fail; + + } + + if(!generic_device || !ioctl_device){ + if(generic_device){ + ioctl_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(ioctl_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",(ioctl_device? + ioctl_device: + "not found")); + + 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(ioctl_device)i_fd=open(ioctl_device,O_RDONLY|O_NONBLOCK); + g_fd=open(generic_device,O_RDWR); + + if(ioctl_device && i_fd==-1) + idperror(messagedest,messages,"\t\tCould not open SCSI cdrom device " + "%s (continuing)",ioctl_device); + + if(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){ + if(stat(ioctl_device,&i_st)){ + idperror(messagedest,messages,"\t\tCould not access SCSI cdrom device " + "%s",ioctl_device); + goto cdda_identify_scsi_fail; + } + + type=(int)(i_st.st_rdev>>8); + + if(type==SCSI_CDROM_MAJOR){ + if (!S_ISBLK(i_st.st_mode)) { + idmessage(messagedest,messages,"\t\tSCSI CDROM device %s not a " + "block device",ioctl_device); + goto cdda_identify_scsi_fail; + } + }else{ + idmessage(messagedest,messages,"\t\tSCSI CDROM device %s has wrong " + "major number",ioctl_device); + goto cdda_identify_scsi_fail; + } + } + + 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_t)); + + 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; + + 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->sg=malloc(MAX_BIG_BUFF_SIZE); + d->sg_buffer=d->sg+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 = scsi_inquiry(d); + + /* It would seem some TOSHIBA CDROMs gets things wrong */ + + if (!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 || (*p != TYPE_ROM && *p != TYPE_WORM)) { + idmessage(messagedest,messages, + "\t\tDrive is neither a CDROM nor a WORM device\n",NULL); + free(d->sg); + free(d); + 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(ioctl_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(ioctl_device)free((char *)ioctl_device); + if(i_fd!=-1)close(i_fd); + if(g_fd!=-1)close(g_fd); + return(NULL); +} + +#ifdef CDDA_TEST + +cdrom_drive_t *cdda_identify_test(const char *filename, int messagedest, + char **messages){ + + cdrom_drive_t *d=NULL; + struct stat st; + int fd=-1; + + 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_t)); + + 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->drive_model=copystring("File based test interface"); + idmessage(messagedest,messages,"\t\tCDROM sensed: %s\n",d->drive_model); + + return(d); +} + +#endif diff --git a/lib/cdda_interface/scsi_interface.c b/lib/cdda_interface/scsi_interface.c new file mode 100644 index 00000000..0fb28ee4 --- /dev/null +++ b/lib/cdda_interface/scsi_interface.c @@ -0,0 +1,1580 @@ +/* + $Id: scsi_interface.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Original interface.c Copyright (C) 1994-1997 + Eissfeldt heiko@colossus.escape.de + Current blenderization Copyright (C) 1998-1999 Monty xiphmont@mit.edu + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/****************************************************************** + * + * Generic SCSI interface specific code. + * + ******************************************************************/ + +#define NEED_STRERROR_TR +#define NEED_MMC_LIST +#define NEED_SCSI_LIST + +#include "low_interface.h" +#include "common_interface.h" +#include "utils.h" +#include + +/* hook */ +static int +Dummy (cdrom_drive_t *d,int s){ + return(0); +} + +#include "drive_exceptions.h" + +static void +tweak_SG_buffer(cdrom_drive_t *d){ + int table,reserved; + char buffer[256]; + + /* maximum transfer size? */ + if(ioctl(d->cdda_fd,SG_GET_RESERVED_SIZE,&reserved)){ + /* Up, guess not. */ + cdmessage(d,"\tCould not get scatter/gather buffer size.\n"); + return; + } + + if(ioctl(d->cdda_fd,SG_GET_SG_TABLESIZE,&table))table=1; + { + int cur; + + 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/CDIO_CD_FRAMESIZE_RAW); + cdmessage(d,buffer); + + cur=table*reserved; + + /* not too much; new kernels have trouble with DMA allocation, so + be more conservative: 32kB max until I test more thoroughly */ + cur=(cur>1024*32?1024*32:cur); + d->nsectors=cur/CDIO_CD_FRAMESIZE_RAW; + d->bigbuff=cur; + + sprintf(buffer,"\tSetting default read size to %d sectors (%d bytes).\n\n", + d->nsectors,d->nsectors*CDIO_CD_FRAMESIZE_RAW); + cdmessage(d,buffer); + } + + /* Disable command queue; we don't need it, no reason to have it on */ + reserved=0; + if(ioctl(d->cdda_fd,SG_SET_COMMAND_Q,&reserved)){ + cdmessage(d,"\tCouldn't disable command queue! Continuing anyway...\n"); + } + +} + +static void +reset_scsi(cdrom_drive_t *d) +{ + int arg; + 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"); + + d->enable_cdda(d,1); +} + +static void +clear_garbage(cdrom_drive_t *d) +{ + fd_set fdset; + struct timeval tv; + struct sg_header *sg_hd=(struct sg_header *)d->sg; + 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; + } +} + +/* process a complete scsi command. */ +static int +handle_scsi_cmd(cdrom_drive_t *d, + unsigned int cmd_len, unsigned int in_size, + unsigned int out_size, unsigned char bytefill, + int bytecheck) +{ + int status = 0; + struct sg_header *sg_hd=(struct sg_header *)d->sg; + 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)); + 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->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 in alpha 10; 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 ); + 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 in alpha 10; 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); + } + } + } + + errno=0; + status = read(d->cdda_fd, sg_hd, SG_OFF + out_size); + sigprocmask ( SIG_UNBLOCK, &(d->sigset), NULL ); + + if (status<0)return(TR_EREAD); + + if(status != SG_OFF + out_size || sg_hd->result){ + if(errno==0)errno=EIO; + return(TR_EREAD); + } + + if(sg_hd->sense_buffer[0]){ + char key=sg_hd->sense_buffer[2]&0xf; + char ASC=sg_hd->sense_buffer[12]; + char ASCQ=sg_hd->sense_buffer[13]; + switch(key){ + case 0: + if(errno==0)errno=EIO; + return(TR_UNKNOWN); + case 1: + break; + case 2: + if(errno==0)errno=EBUSY; + return(TR_BUSY); + 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); + } + } + + /* still not foolproof; the following doesn't guarantee that we got + all the data, just that the command was not rejected. */ + + /* Why do this with the above sense stuff? For some reason, + commands still get through. Perhaps no data comes back even + though the target reports success? */ + + if(bytecheck && in_size+cmd_lensg_buffer[i]!=bytefill){ + flag=1; + break; + } + + if(!flag){ + errno=EINVAL; + return(TR_ILLEGAL); + } + } + + errno=0; + return(0); +} + +/* Group 1 (10b) command */ + +static int +mode_sense_atapi(cdrom_drive_t *d, int size, int page) +{ + memcpy(d->sg_buffer, + (char []) {CDIO_MMC_GPCMD_MODE_SENSE_10, + 0x00, /* reserved */ + 0x00, /* page */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* MSB (0) */ + 0, /* sizeof(modesense - SG_OFF) */ + 0}, /* reserved */ + 10); + + d->sg_buffer[1]=d->lun<<5; + d->sg_buffer[2]=0x3F&page; + d->sg_buffer[8]=size+4; + + if (handle_scsi_cmd (d, 10, 0, size+4,'\377',1)) return(1); + + { + char *b=d->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); + } + return(0); +} + +/* group 0 (6b) command */ + +static int +mode_sense_scsi(cdrom_drive_t *d, int size, int page) +{ + memcpy(d->sg_buffer, + (char []) {CDIO_MMC_GPCMD_MODE_SENSE, + 0x00, /* return block descriptor/lun */ + 0x00, /* page */ + 0, /* reserved */ + 0, /* sizeof(modesense - SG_OFF) */ + 0}, /* control */ + 6); + + d->sg_buffer[1]=d->lun<<5; + d->sg_buffer[2]=(0x3F&page); + d->sg_buffer[4]=size; + + if (handle_scsi_cmd (d, 6, 0, size, '\377',1)) return(1); + return(0); +} + +static int mode_sense(cdrom_drive_t *d,int size,int page){ + if(d->is_atapi) + return(mode_sense_atapi(d,size,page)); + return(mode_sense_scsi(d,size,page)); +} + +static int mode_select(cdrom_drive_t *d,int density,int secsize){ + /* short circut the way Heiko does it; less flexible, but shorter */ + if(d->is_atapi){ + unsigned char *mode = d->sg_buffer + 18; + + memcpy(d->sg_buffer, + (char []) { CDIO_MMC_GPCMD_MODE_SELECT, + 0x10, /* no save page */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 0, /* reserved */ + 12, /* 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 */ + 26); + + d->sg_buffer[1]|=d->lun<<5; + + /* 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,10, 16, 0,0,0)); + + }else{ + unsigned char *mode = d->sg_buffer + 10; + + memcpy(d->sg_buffer, + (char []) { CDIO_MMC_GPCMD_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 */ + 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,6, 12, 0,0,0)); + } +} + +/* get current sector size from SCSI cdrom drive */ +static unsigned int +get_orig_sectorsize(cdrom_drive_t *d) +{ + if(mode_sense(d,12,0x01))return(-1); + + d->orgdens = d->sg_buffer[4]; + return(d->orgsize = ((int)(d->sg_buffer[10])<<8)+d->sg_buffer[11]); +} + +/* switch CDROM scsi drives to given sector size */ +static int set_sectorsize (cdrom_drive_t *d,unsigned int secsize) +{ + return(mode_select(d,d->orgdens,secsize)); +} + +/* switch Toshiba/DEC and HP drives from/to cdda density */ +int +scsi_enable_cdda (cdrom_drive_t *d, int fAudioMode) +{ + if (fAudioMode) { + if(mode_select(d,d->density,CDIO_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_t *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 */ + memcpy(d->sg_buffer, (char []){ CDIO_MMC_GPCMD_READ_TOC, + 0, 0, 0, 0, 0, 1, 0, 12, 0}, 10); + d->sg_buffer[1]=d->lun<<5; + + if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){ + cderror(d,"004: Unable to read table of contents header\n"); + return(-4); + } + + first=d->sg_buffer[2]; + last=d->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(d->sg_buffer, (char []){ CDIO_MMC_GPCMD_READ_TOC, + 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10); + d->sg_buffer[1]=d->lun<<5; + d->sg_buffer[6]=i; + + if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){ + cderror(d,"005: Unable to read table of contents entry\n"); + return(-5); + } + { + scsi_TOC *toc=(scsi_TOC *)(d->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(d->sg_buffer, (char []){ CDIO_MMC_GPCMD_READ_TOC, + 0, 0, 0, 0, 0, 0, 0, 12, 0}, 10); + d->sg_buffer[1]=d->lun<<5; + d->sg_buffer[6]=0xAA; + + if (handle_scsi_cmd (d,10, 0, 12,'\377',1)){ + cderror(d,"002: Unable to read table of contents lead-out\n"); + return(-2); + } + { + scsi_TOC *toc=(scsi_TOC *)(d->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_t *d) +{ + u_int32_t foo,bar; + + int i; + unsigned tracks; + + memcpy(d->sg_buffer, (char[]){ 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10); + d->sg_buffer[5]=1; + d->sg_buffer[8]=255; + + if (handle_scsi_cmd (d,10, 0, 256,'\377',1)){ + cderror(d,"004: Unable to read table of contents header\n"); + return(-4); + } + + /* copy to our structure and convert start sector */ + tracks = d->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(d->sg_buffer, (char[]){ 0xe5, 0, 0, 0, 0, 0, 0, 0, 0, 0}, 10); + d->sg_buffer[5]=i+1; + d->sg_buffer[8]=255; + + if (handle_scsi_cmd (d,10, 0, 256,'\377',1)){ + cderror(d,"005: Unable to read table of contents entry\n"); + return(-5); + } + + d->disc_toc[i].bFlags = d->sg_buffer[10]; + d->disc_toc[i].bTrack = i + 1; + + d->disc_toc[i].dwStartSector= d->adjust_ssize * + (((signed char)(d->sg_buffer[2])<<24) | + (d->sg_buffer[3]<<16)| + (d->sg_buffer[4]<<8)| + (d->sg_buffer[5])); + } + + d->disc_toc[i].bFlags = 0; + d->disc_toc[i].bTrack = i + 1; + memcpy (&foo, d->sg_buffer+2, 4); + memcpy (&bar, d->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->sg_buffer[2])<<24) | + (d->sg_buffer[3]<<16)| + (d->sg_buffer[4]<<8)| + (d->sg_buffer[5]))+ + + ((((signed char)(d->sg_buffer[6])<<24) | + (d->sg_buffer[7]<<16)| + (d->sg_buffer[8]<<8)| + (d->sg_buffer[9])))); + + + d->cd_extra = FixupTOC(d,tracks+1); + return(tracks); +} + +/* These do one 'extra' copy in the name of clean code */ + +static int +i_read_28 (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + int ret; + memcpy(d->sg_buffer,(char []){ + CDIO_MMC_GPCMD_READ_10, + 0, 0, 0, 0, 0, 0, 0, 0, 0}, + 10); + + if(d->fua) + d->sg_buffer[1]=0x08; + + d->sg_buffer[1]|=d->lun<<5; + + d->sg_buffer[3] = (begin >> 16) & 0xFF; + d->sg_buffer[4] = (begin >> 8) & 0xFF; + d->sg_buffer[5] = begin & 0xFF; + d->sg_buffer[8] = sectors; + if((ret=handle_scsi_cmd(d,10,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +static int +i_read_A8 (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + int ret; + memcpy(d->sg_buffer,(char []){ + CDIO_MMC_GPCMD_READ_12, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + 12); + + if(d->fua) + d->sg_buffer[1]=0x08; + + d->sg_buffer[1]|=d->lun<<5; + + d->sg_buffer[3] = (begin >> 16) & 0xFF; + d->sg_buffer[4] = (begin >> 8) & 0xFF; + d->sg_buffer[5] = begin & 0xFF; + d->sg_buffer[9] = sectors; + if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +static int +i_read_D4_10 (cdrom_drive_t *d, void *p, long begin, long sectors) +{ + int ret; + memcpy(d->sg_buffer,(char []){0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0},10); + + if(d->fua) + d->sg_buffer[1]=0x08; + + d->sg_buffer[1]|=d->lun<<5; + d->sg_buffer[3] = (begin >> 16) & 0xFF; + d->sg_buffer[4] = (begin >> 8) & 0xFF; + d->sg_buffer[5] = begin & 0xFF; + d->sg_buffer[8] = sectors; + if((ret=handle_scsi_cmd(d,10,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +static int i_read_D4_12 (cdrom_drive_t *d, void *p, long begin, long sectors) +{ + int ret; + memcpy(d->sg_buffer,(char []){0xd4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12); + + if(d->fua) + d->sg_buffer[1]=0x08; + + d->sg_buffer[1]|=d->lun<<5; + d->sg_buffer[3] = (begin >> 16) & 0xFF; + d->sg_buffer[4] = (begin >> 8) & 0xFF; + d->sg_buffer[5] = begin & 0xFF; + d->sg_buffer[9] = sectors; + if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +static int +i_read_D5 (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + int ret; + memcpy(d->sg_buffer,(char []){0xd5, 0, 0, 0, 0, 0, 0, 0, 0, 0},10); + + if(d->fua) + d->sg_buffer[1]=0x08; + + d->sg_buffer[1]|=d->lun<<5; + d->sg_buffer[3] = (begin >> 16) & 0xFF; + d->sg_buffer[4] = (begin >> 8) & 0xFF; + d->sg_buffer[5] = begin & 0xFF; + d->sg_buffer[8] = sectors; + if((ret=handle_scsi_cmd(d,10,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +static int +i_read_D8 (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + int ret; + memcpy(d->sg_buffer,(char []){0xd8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},12); + + if(d->fua) + d->sg_buffer[1]=0x08; + + d->sg_buffer[1]|=d->lun<<5; + d->sg_buffer[3] = (begin >> 16) & 0xFF; + d->sg_buffer[4] = (begin >> 8) & 0xFF; + d->sg_buffer[5] = begin & 0xFF; + d->sg_buffer[9] = sectors; + if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +static int +i_read_mmc (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + int ret; + /* if(begin<=12007 && begin+sectors>12000){ + errno=EIO; + return(TR_ILLEGAL); + }*/ + + memcpy(d->sg_buffer,(char []){ + CDIO_MMC_GPCMD_READ_CD, + 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0},12); + + d->sg_buffer[3] = (begin >> 16) & 0xFF; + d->sg_buffer[4] = (begin >> 8) & 0xFF; + d->sg_buffer[5] = begin & 0xFF; + d->sg_buffer[8] = sectors; + if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +static int +i_read_mmc2 (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + int ret; + memcpy(d->sg_buffer,(char []){ + CDIO_MMC_GPCMD_READ_CD, + 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12); + + d->sg_buffer[3] = (begin >> 16) & 0xFF; + d->sg_buffer[4] = (begin >> 8) & 0xFF; + d->sg_buffer[5] = begin & 0xFF; + d->sg_buffer[8] = sectors; + if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +static int +i_read_mmc3 (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + int ret; + memcpy(d->sg_buffer,(char []){ + CDIO_MMC_GPCMD_READ_CD, + 4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12); + + d->sg_buffer[3] = (begin >> 16) & 0xFF; + d->sg_buffer[4] = (begin >> 8) & 0xFF; + d->sg_buffer[5] = begin & 0xFF; + d->sg_buffer[8] = sectors; + if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +/* straight from the MMC3 spec */ +static inline void +LBA_to_MSF(long int lba, unsigned char *M, unsigned char *S, unsigned char *F) +{ + if (lba>=-CDIO_PREGAP_SECTORS){ + *M = ( lba+CDIO_PREGAP_SECTORS)/(CDIO_CD_FRAMES_PER_MIN); + lba -= (*M)*(CDIO_CD_FRAMES_PER_MIN); + *S = (lba+CDIO_PREGAP_SECTORS)/CDIO_CD_FRAMES_PER_SEC; + lba -= (*S)*CDIO_CD_FRAMES_PER_SEC; + *F = (lba+CDIO_PREGAP_SECTORS); + } else { + *M = (lba+450150)/(CDIO_CD_FRAMES_PER_MIN); + lba -= (*M)*(CDIO_CD_FRAMES_PER_MIN); + *S = (lba+450150)/CDIO_CD_FRAMES_PER_SEC; + lba -= (*S)*CDIO_CD_FRAMES_PER_SEC; + *F = (lba+450150); + } +} + + +static int +i_read_msf (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + int ret; + memcpy(d->sg_buffer,(char []){ + CDIO_MMC_GPCMD_READ_MSF, + 0, 0, 0, 0, 0, 0, 0, 0, 0x10, 0, 0},12); + + LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5); + LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8); + + if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +static int +i_read_msf2 (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + int ret; + memcpy(d->sg_buffer,(char []){ + CDIO_MMC_GPCMD_READ_MSF, + 0, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12); + + LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5); + LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8); + + if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +static int +i_read_msf3 (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + int ret; + memcpy(d->sg_buffer,(char []){ + CDIO_MMC_GPCMD_READ_MSF, + 4, 0, 0, 0, 0, 0, 0, 0, 0xf8, 0, 0},12); + + LBA_to_MSF(begin,d->sg_buffer+3,d->sg_buffer+4,d->sg_buffer+5); + LBA_to_MSF(begin+sectors,d->sg_buffer+6,d->sg_buffer+7,d->sg_buffer+8); + + if((ret=handle_scsi_cmd(d,12,0,sectors * CDIO_CD_FRAMESIZE_RAW,'\177',1))) + return(ret); + if(p)memcpy(p,d->sg_buffer,sectors*CDIO_CD_FRAMESIZE_RAW); + return(0); +} + +static long +scsi_read_map (cdrom_drive_t *d, void *p, long int begin, long int sectors, + int (*map)(cdrom_drive_t *, void *, long, long)) +{ + 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))){ + if(d->report_all){ + struct sg_header *sg_hd=(struct sg_header *)d->sg; + 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)(sg_hd->sense_buffer[2]&0xf), + (int)(sg_hd->sense_buffer[12]), + (int)(sg_hd->sense_buffer[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)(sg_hd->sense_buffer[2]&0xf), + (int)(sg_hd->sense_buffer[12]), + (int)(sg_hd->sense_buffer[13])); + fprintf(stderr," Transport error: %s\n",strerror_tr[err]); + fprintf(stderr," System error: %s\n",strerror(errno)); + } + + if(!d->error_retry)return(-7); + 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*CDIO_CD_FRAMESIZE_RAW); + + cdmessage(d,b); + } + sectors--; + continue; + 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); + } + }else{ + + /* Did we get all the bytes we think we did, or did the kernel + suck? */ + if(buffer){ + long i; + for(i=sectors*CDIO_CD_FRAMESIZE_RAW;i>1;i-=2) + if(buffer[i-1]!='\177' || buffer[i-2]!='\177') + break; + + i/=CDIO_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 int +scsi_read_28 (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + return(scsi_read_map(d,p,begin,sectors,i_read_28)); +} + +long int +scsi_read_A8 (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + return(scsi_read_map(d,p,begin,sectors,i_read_A8)); +} + +long int +scsi_read_D4_10 (cdrom_drive_t *d, void *p, long int begin, long int sectors) +{ + return(scsi_read_map(d,p,begin,sectors,i_read_D4_10)); +} + +long int +scsi_read_D4_12 (cdrom_drive_t *d, void *p, long int begin, + long int sectors) +{ + return(scsi_read_map(d,p,begin,sectors,i_read_D4_12)); +} + +static long int +scsi_read_D5 (cdrom_drive_t *d, void *p, long begin, long sectors) +{ + return(scsi_read_map(d,p,begin,sectors,i_read_D5)); +} + +long scsi_read_D8 (cdrom_drive_t *d, void *p, long begin, + long sectors) +{ + return(scsi_read_map(d,p,begin,sectors,i_read_D8)); +} + +long scsi_read_mmc (cdrom_drive_t *d, void *p, long begin, + long sectors) +{ + return(scsi_read_map(d,p,begin,sectors,i_read_mmc)); +} + +long scsi_read_mmc2 (cdrom_drive_t *d, void *p, long begin, + long sectors) +{ + return(scsi_read_map(d,p,begin,sectors,i_read_mmc2)); +} + +static long +scsi_read_mmc3 (cdrom_drive_t *d, void *p, long begin, long sectors) +{ + return(scsi_read_map(d,p,begin,sectors,i_read_mmc3)); +} + +static long +scsi_read_msf (cdrom_drive_t *d, void *p, long begin, long sectors) +{ + return(scsi_read_map(d,p,begin,sectors,i_read_msf)); +} + +static long +scsi_read_msf2 (cdrom_drive_t *d, void *p, long begin, long sectors) +{ + return(scsi_read_map(d,p,begin,sectors,i_read_msf2)); +} + +static long +scsi_read_msf3 (cdrom_drive_t *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_t *d) +{ + long int i; + for (i=CDIO_CD_FRAMESIZE_RAW-1; i>=0; i--) + if(d->sg_buffer[i]!=(unsigned char)'\177') + return(((i+3)>>2)<<2); + + return(0); +} + +static int +verify_nonzero(cdrom_drive_t *d) +{ + long i,flag=0; + for (i=0; isg_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_t *d) +{ + int i,j,k; + int audioflag=0; + + int (*enablecommand) (cdrom_drive_t *d, int speed); + long (*readcommand) (cdrom_drive_t *d, void *p, long begin, + long int sectors); + unsigned char density; + + int16_t *buff=malloc(CDIO_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)==CDIO_CD_FRAMESIZE_RAW){ + 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); + } + + + { + const 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>=0;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_mmc; + rs="be 00,10"; + densitypossible=0; + break; + case 3: + d->read_audio=scsi_read_mmc2; + rs="be 00,f8"; + densitypossible=0; + break; + case 4: + d->read_audio=scsi_read_mmc3; + rs="be 04,f8"; + densitypossible=0; + break; + + case 5: + d->read_audio=scsi_read_msf; + rs="b9 00,10"; + densitypossible=0; + break; + case 6: + d->read_audio=scsi_read_msf2; + rs="b9 00,f8"; + densitypossible=0; + break; + case 7: + d->read_audio=scsi_read_msf3; + rs="b9 04,f8"; + densitypossible=0; + break; + + case 8: + d->read_audio=scsi_read_D4_10; + rs="d4(10)0x"; + break; + case 9: + d->read_audio=scsi_read_D4_12; + rs="d4(12)0x"; + break; + case 10: + d->read_audio=scsi_read_D5; + rs="d5 0x,00"; + break; + case 11: + d->read_audio=scsi_read_D8; + rs="d8 0x,00"; + j=-2; + break; + } + + for(i=0;i>=0;i++){ + switch(i){ + case 0: + d->density=0; + d->enable_cdda=Dummy; + es="none "; + if(!densitypossible)i=-2; /* 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"; + case 4: + d->density=0x81; + d->enable_cdda=scsi_enable_cdda; + es="yes/0x81"; + i=-2; + 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))==CDIO_CD_FRAMESIZE_RAW){ + 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 && lengthflagdensity=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_fua_bit(cdrom_drive_t *d){ + int16_t *buff=malloc(CDIO_CD_FRAMESIZE_RAW); + long i; + + if(d->read_audio==scsi_read_mmc)return; + if(d->read_audio==scsi_read_mmc2)return; + if(d->read_audio==scsi_read_mmc3)return; + + 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,buff,sector,1)>0){ + cdmessage(d,"\tDrive accepted FUA bit.\n"); + d->enable_cdda(d,0); + free(buff); + return; + } + } + } + + d->fua=0; + cdmessage(d,"\tDrive rejected FUA bit.\n"); + free(buff); + return; +} + +static int +check_atapi(cdrom_drive_t *d){ + int atapiret=-1; + int fd = d->cdda_fd; /* this is the correct fd (not ioctl_fd), as the + generic device is the device we need to check */ + + 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){ + 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_t *d){ + char *b; + cdmessage(d,"\nChecking for MMC style command set...\n"); + + d->is_mmc=0; + if(mode_sense(d,22,0x2A)==0){ + + b=d->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_t *d, exception_t *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_t *d){ + memcpy(d->sg_buffer,(char[]){ 0x12,0,0,0,56,0},6); + + if(handle_scsi_cmd(d,6, 0, 56,'\377',1)) { + cderror(d,"008: Unable to identify CDROM model\n"); + return(NULL); + } + return (d->sg_buffer); +} + + +int +scsi_init_drive(cdrom_drive_t *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_mmc2; + d->bigendianp=0; + + check_exceptions(d,mmc_list); + + }else{ + + if(d->is_atapi){ + /* Not MMC maybe still uses CDIO_MMC_GPCMD_READ_CD */ + + d->read_audio = scsi_read_mmc2; + d->bigendianp=0; + + check_exceptions(d,atapi_list); + + }else{ + + check_exceptions(d,scsi_list); + + } + } + + /* we really do want the sector size at 2048 to begin.*/ + if (!d->is_atapi) + set_sectorsize(d, CDIO_CD_FRAMESIZE); + + 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 = NULL; + + + if (!d->is_atapi) { + unsigned int sector_size= get_orig_sectorsize(d); + + if ( (sector_size < CDIO_CD_FRAMESIZE) + && set_sectorsize(d, CDIO_CD_FRAMESIZE) ) + d->adjust_ssize = CDIO_CD_FRAMESIZE / 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_fua_bit(d); + + d->error_retry=1; + d->sg=realloc(d->sg,d->nsectors*CDIO_CD_FRAMESIZE_RAW + SG_OFF + 128); + d->sg_buffer=d->sg+SG_OFF; + d->report_all=1; + return(0); +} + diff --git a/lib/cdda_interface/smallft.c b/lib/cdda_interface/smallft.c new file mode 100644 index 00000000..e3b92fa7 --- /dev/null +++ b/lib/cdda_interface/smallft.c @@ -0,0 +1,547 @@ +/****************************************************************** + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) 1998 Monty xiphmont@mit.edu + * + * FFT implementation from OggSquish, minus cosine transforms, + * minus all but radix 2/4 case + * + * See OggSquish or NetLib for the version that can do other than just + * power-of-two sized vectors. + * + ******************************************************************/ + +#include +#include +#include "smallft.h" + +static void drfti1(int n, float *wa, int *ifac){ + static int ntryh[4] = { 4,2,3,5 }; + static float tpi = 6.28318530717958647692528676655900577; + float arg,argh,argld,fi; + int ntry=0,i,j=-1; + int k1, l1, l2, ib; + int ld, ii, ip, is, nq, nr; + int ido, ipm, nfm1; + int nl=n; + int nf=0; + + L101: + j++; + if (j < 4) + ntry=ntryh[j]; + else + ntry+=2; + + L104: + nq=nl/ntry; + nr=nl-ntry*nq; + if (nr!=0) goto L101; + + nf++; + ifac[nf+1]=ntry; + nl=nq; + if(ntry!=2)goto L107; + if(nf==1)goto L107; + + for (i=1;i + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/****************************************************************** + * + * 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/CDIO_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) +{ + +#if defined(CDDA_TEST_SEEKJITTER) \ + || defined(CDDA_TEST_ALLJITTER) \ + || defined(CDDA_TEST_SOMEJITTER) + int jitter_flag=0; +#endif + + 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"); + +#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*CDIO_CD_FRAMESIZE_RAW; + + begin*=CDIO_CD_FRAMESIZE_RAW; + + while(bytes_so_far.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); + } + 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*CDIO_CD_FRAMESIZE_RAW+(drand48()*56)+512; + + if(begin<=location && begin+bytestotal>location){ + 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 + diff --git a/lib/cdda_interface/toc.c b/lib/cdda_interface/toc.c new file mode 100644 index 00000000..27d17008 --- /dev/null +++ b/lib/cdda_interface/toc.c @@ -0,0 +1,199 @@ +/* + $Id: toc.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 1998 Monty xiphmont@mit.edu + derived from code (C) 1994-1996 Heiko Eissfeldt + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/****************************************************************** + * Table of contents convenience functions + ******************************************************************/ + +#include "low_interface.h" +#include "utils.h" + +long +cdda_track_firstsector(cdrom_drive_t *d,int track) +{ + if(!d->opened){ + cderror(d,"400: Device not open\n"); + return(-1); + } + + if (track == 0) { + if (d->disc_toc[0].dwStartSector == 0) { + /* first track starts at lba 0 -> no pre-gap */ + cderror(d,"401: Invalid track number\n"); + return(-1); + } + else { + return 0; /* pre-gap of first track always starts at lba 0 */ + } + } + + if(track<0 || track>d->tracks){ + cderror(d,"401: Invalid track number\n"); + return(-1); + } + return(d->disc_toc[track-1].dwStartSector); +} + +long +cdda_disc_firstsector(cdrom_drive_t *d) +{ + int i; + if(!d->opened){ + cderror(d,"400: Device not open\n"); + return(-1); + } + + /* look for an audio track */ + for(i=0;itracks;i++) + if(cdda_track_audiop(d,i+1)==1) { + if (i == 0) /* disc starts at lba 0 if first track is an audio track */ + return 0; + else + return(cdda_track_firstsector(d,i+1)); + } + + cderror(d,"403: No audio tracks on disc\n"); + return(-1); +} + +long +cdda_track_lastsector(cdrom_drive_t *d,int track) +{ + if(!d->opened){ + cderror(d,"400: Device not open\n"); + return(-1); + } + + if (track == 0) { + if (d->disc_toc[0].dwStartSector == 0) { + /* first track starts at lba 0 -> no pre-gap */ + cderror(d,"401: Invalid track number\n"); + return(-1); + } + else { + return d->disc_toc[0].dwStartSector-1; + } + } + + if(track<1 || track>d->tracks){ + cderror(d,"401: Invalid track number\n"); + return(-1); + } + /* Safe, we've always the leadout at disc_toc[tracks] */ + return(d->disc_toc[track].dwStartSector-1); +} + +long +cdda_disc_lastsector(cdrom_drive_t *d) +{ + int i; + if(!d->opened){ + cderror(d,"400: Device not open\n"); + return(-1); + } + + /* look for an audio track */ + for(i=d->tracks-1;i>=0;i--) + if(cdda_track_audiop(d,i+1)==1) + return(cdda_track_lastsector(d,i+1)); + + cderror(d,"403: No audio tracks on disc\n"); + return(-1); +} + +long +cdda_tracks(cdrom_drive_t *d) +{ + if(!d->opened){ + cderror(d,"400: Device not open\n"); + return(-1); + } + return(d->tracks); +} + +int +cdda_sector_gettrack(cdrom_drive_t *d,long sector) +{ + if(!d->opened){ + cderror(d,"400: Device not open\n"); + return(-1); + }else{ + int i; + + if (sector < d->disc_toc[0].dwStartSector) + return 0; /* We're in the pre-gap of first track */ + + for(i=0;itracks;i++){ + if(d->disc_toc[i].dwStartSector<=sector && + d->disc_toc[i+1].dwStartSector>sector) + return (i+1); + } + + cderror(d,"401: Invalid track number\n"); + return -1; + } +} + +static int +cdda_track_bitmap(cdrom_drive_t *d,int track,int bit,int set,int clear) +{ + if(!d->opened){ + cderror(d,"400: Device not open\n"); + return(-1); + } + + if (track == 0) + track = 1; /* map to first track number */ + + if(track<1 || track>d->tracks){ + cderror(d,"401: Invalid track number\n"); + return(-1); + } + if ((d->disc_toc[track-1].bFlags & bit)) + return(set); + else + return(clear); +} + + +int +cdda_track_channels(cdrom_drive_t *d,int track) +{ + return(cdda_track_bitmap(d,track,8,4,2)); +} + +int +cdda_track_audiop(cdrom_drive_t *d,int track) +{ + return(cdda_track_bitmap(d,track,4,0,1)); +} + +int +cdda_track_copyp(cdrom_drive_t *d,int track) +{ + return(cdda_track_bitmap(d,track,2,1,0)); +} + +int +cdda_track_preemp(cdrom_drive_t *d, int track) +{ + return(cdda_track_bitmap(d,track,1,1,0)); +} + diff --git a/lib/cdda_interface/utils.c b/lib/cdda_interface/utils.c new file mode 100644 index 00000000..30f28ade --- /dev/null +++ b/lib/cdda_interface/utils.c @@ -0,0 +1,138 @@ +/* + $Id: utils.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "common_interface.h" +#include "utils.h" +void +cderror(cdrom_drive_t *d,const char *s) +{ + if(s && d){ + switch(d->errordest){ + case CDDA_MESSAGE_PRINTIT: + write(STDERR_FILENO,s,strlen(s)); + break; + case CDDA_MESSAGE_LOGIT: + d->errorbuf=catstring(d->errorbuf,s); + break; + case CDDA_MESSAGE_FORGETIT: + default: ; + } + } +} + +void +cdmessage(cdrom_drive_t *d, const char *s) +{ + if(s && d){ + switch(d->messagedest){ + case CDDA_MESSAGE_PRINTIT: + write(STDERR_FILENO,s,strlen(s)); + break; + case CDDA_MESSAGE_LOGIT: + d->messagebuf=catstring(d->messagebuf,s); + break; + case CDDA_MESSAGE_FORGETIT: + default: ; + } + } +} + +void +idperror(int messagedest,char **messages,const char *f, + const char *s) +{ + + char *buffer; + int malloced=0; + if(!f) + buffer=(char *)s; + else + if(!s) + buffer=(char *)f; + else{ + buffer=malloc(strlen(f)+strlen(s)+9); + sprintf(buffer,f,s); + malloced=1; + } + + if(buffer){ + switch(messagedest){ + case CDDA_MESSAGE_PRINTIT: + write(STDERR_FILENO,buffer,strlen(buffer)); + if(errno){ + write(STDERR_FILENO,": ",2); + write(STDERR_FILENO,strerror(errno),strlen(strerror(errno))); + write(STDERR_FILENO,"\n",1); + } + break; + case CDDA_MESSAGE_LOGIT: + if(messages){ + *messages=catstring(*messages,buffer); + if(errno){ + *messages=catstring(*messages,": "); + *messages=catstring(*messages,strerror(errno)); + *messages=catstring(*messages,"\n"); + } + } + break; + case CDDA_MESSAGE_FORGETIT: + default: ; + } + } + if(malloced)free(buffer); +} + +void +idmessage(int messagedest,char **messages,const char *f, + const char *s) +{ + char *buffer; + int malloced=0; + if(!f) + buffer=(char *)s; + else + if(!s) + buffer=(char *)f; + else{ + buffer=malloc(strlen(f)+strlen(s)+10); + sprintf(buffer,f,s); + strcat(buffer,"\n"); + malloced=1; + } + + if(buffer){ + switch(messagedest){ + case CDDA_MESSAGE_PRINTIT: + write(STDERR_FILENO,buffer,strlen(buffer)); + if(!malloced)write(STDERR_FILENO,"\n",1); + break; + case CDDA_MESSAGE_LOGIT: + if(messages){ + *messages=catstring(*messages,buffer); + if(!malloced)*messages=catstring(*messages,"\n"); + } + break; + case CDDA_MESSAGE_FORGETIT: + default: ; + } + } + if(malloced)free(buffer); +} diff --git a/lib/cdda_interface/utils.h b/lib/cdda_interface/utils.h new file mode 100644 index 00000000..87bfa250 --- /dev/null +++ b/lib/cdda_interface/utils.h @@ -0,0 +1,133 @@ +/* + $Id: utils.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include + +/* I wonder how many alignment issues this is gonna trip in the + future... it shouldn't trip any... I guess we'll find out :) */ + +static inline int bigendianp(void){ + int test=1; + char *hack=(char *)(&test); + if(hack[0])return(0); + return(1); +} + +static inline int32_t swap32(int32_t x){ + return((((u_int32_t)x & 0x000000ffU) << 24) | + (((u_int32_t)x & 0x0000ff00U) << 8) | + (((u_int32_t)x & 0x00ff0000U) >> 8) | + (((u_int32_t)x & 0xff000000U) >> 24)); +} + +static inline int16_t swap16(int16_t x){ + return((((u_int16_t)x & 0x00ffU) << 8) | + (((u_int16_t)x & 0xff00U) >> 8)); +} + +#if BYTE_ORDER == LITTLE_ENDIAN + +static inline int32_t be32_to_cpu(int32_t x){ + return(swap32(x)); +} + +static inline int16_t be16_to_cpu(int16_t x){ + return(swap16(x)); +} + +static inline int32_t le32_to_cpu(int32_t x){ + return(x); +} + +static inline int16_t le16_to_cpu(int16_t x){ + return(x); +} + +#else + +static inline int32_t be32_to_cpu(int32_t x){ + return(x); +} + +static inline int16_t be16_to_cpu(int16_t x){ + return(x); +} + +static inline int32_t le32_to_cpu(int32_t x){ + return(swap32(x)); +} + +static inline int16_t le16_to_cpu(int16_t x){ + return(swap16(x)); +} + + +#endif + +static inline int32_t cpu_to_be32(int32_t x){ + return(be32_to_cpu(x)); +} + +static inline int32_t cpu_to_le32(int32_t x){ + return(le32_to_cpu(x)); +} + +static inline int16_t cpu_to_be16(int16_t x){ + return(be16_to_cpu(x)); +} + +static inline int16_t cpu_to_le16(int16_t x){ + return(le16_to_cpu(x)); +} + +static inline char *copystring(const char *s){ + if(s){ + char *ret=malloc((strlen(s)+9)*sizeof(char)); /* +9 to get around a linux + libc 5 bug. below too */ + strcpy(ret,s); + return(ret); + } + return(NULL); +} + +static inline char *catstring(char *buff,const char *s){ + if(s){ + if(buff) + buff=realloc(buff,strlen(buff)+strlen(s)+9); + else + buff=calloc(strlen(s)+9,1); + strcat(buff,s); + } + return(buff); +} + +void cderror(cdrom_drive_t *d, const char *s); + +void cdmessage(cdrom_drive_t *d,const char *s); + +void idperror(int messagedest,char **messages,const char *f, const char *s); + +void idmessage(int messagedest,char **messages,const char *f, const char *s); + diff --git a/lib/driver/.cvsignore b/lib/driver/.cvsignore new file mode 100644 index 00000000..ed5ff996 --- /dev/null +++ b/lib/driver/.cvsignore @@ -0,0 +1,9 @@ +.deps +.libs +Makefile +Makefile.in +*.o +*.lo +*.la +*.la.ver + diff --git a/lib/FreeBSD/Makefile b/lib/driver/FreeBSD/Makefile similarity index 94% rename from lib/FreeBSD/Makefile rename to lib/driver/FreeBSD/Makefile index a375cd15..d369e415 100644 --- a/lib/FreeBSD/Makefile +++ b/lib/driver/FreeBSD/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1 2004/06/20 15:35:31 rocky Exp $ +# $Id: Makefile,v 1.1 2004/12/18 17:29:32 rocky Exp $ # # Copyright (C) 2004 Rocky Bernstein # This program is free software; you can redistribute it and/or modify diff --git a/lib/FreeBSD/freebsd.c b/lib/driver/FreeBSD/freebsd.c similarity index 99% rename from lib/FreeBSD/freebsd.c rename to lib/driver/FreeBSD/freebsd.c index 3fa2ae9e..a1614bf9 100644 --- a/lib/FreeBSD/freebsd.c +++ b/lib/driver/FreeBSD/freebsd.c @@ -1,5 +1,5 @@ /* - $Id: freebsd.c,v 1.42 2004/10/26 07:34:41 rocky Exp $ + $Id: freebsd.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein @@ -27,7 +27,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: freebsd.c,v 1.42 2004/10/26 07:34:41 rocky Exp $"; +static const char _rcsid[] = "$Id: freebsd.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #include "freebsd.h" diff --git a/lib/FreeBSD/freebsd.h b/lib/driver/FreeBSD/freebsd.h similarity index 99% rename from lib/FreeBSD/freebsd.h rename to lib/driver/FreeBSD/freebsd.h index cb82e2a7..5498dc5e 100644 --- a/lib/FreeBSD/freebsd.h +++ b/lib/driver/FreeBSD/freebsd.h @@ -1,5 +1,5 @@ /* - $Id: freebsd.h,v 1.21 2004/07/31 09:26:31 rocky Exp $ + $Id: freebsd.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein diff --git a/lib/FreeBSD/freebsd_cam.c b/lib/driver/FreeBSD/freebsd_cam.c similarity index 98% rename from lib/FreeBSD/freebsd_cam.c rename to lib/driver/FreeBSD/freebsd_cam.c index a54cbbdb..c6a5fbc8 100644 --- a/lib/FreeBSD/freebsd_cam.c +++ b/lib/driver/FreeBSD/freebsd_cam.c @@ -1,5 +1,5 @@ /* - $Id: freebsd_cam.c,v 1.31 2004/08/07 09:42:34 rocky Exp $ + $Id: freebsd_cam.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein @@ -26,7 +26,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: freebsd_cam.c,v 1.31 2004/08/07 09:42:34 rocky Exp $"; +static const char _rcsid[] = "$Id: freebsd_cam.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #ifdef HAVE_FREEBSD_CDROM diff --git a/lib/FreeBSD/freebsd_ioctl.c b/lib/driver/FreeBSD/freebsd_ioctl.c similarity index 97% rename from lib/FreeBSD/freebsd_ioctl.c rename to lib/driver/FreeBSD/freebsd_ioctl.c index 5538c96d..eb0673cd 100644 --- a/lib/FreeBSD/freebsd_ioctl.c +++ b/lib/driver/FreeBSD/freebsd_ioctl.c @@ -1,5 +1,5 @@ /* - $Id: freebsd_ioctl.c,v 1.12 2004/08/10 02:29:46 rocky Exp $ + $Id: freebsd_ioctl.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein @@ -27,7 +27,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: freebsd_ioctl.c,v 1.12 2004/08/10 02:29:46 rocky Exp $"; +static const char _rcsid[] = "$Id: freebsd_ioctl.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #ifdef HAVE_FREEBSD_CDROM diff --git a/lib/MSWindows/Makefile b/lib/driver/MSWindows/Makefile similarity index 94% rename from lib/MSWindows/Makefile rename to lib/driver/MSWindows/Makefile index a375cd15..d369e415 100644 --- a/lib/MSWindows/Makefile +++ b/lib/driver/MSWindows/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1 2004/06/20 15:35:31 rocky Exp $ +# $Id: Makefile,v 1.1 2004/12/18 17:29:32 rocky Exp $ # # Copyright (C) 2004 Rocky Bernstein # This program is free software; you can redistribute it and/or modify diff --git a/lib/MSWindows/aspi32.c b/lib/driver/MSWindows/aspi32.c similarity index 99% rename from lib/MSWindows/aspi32.c rename to lib/driver/MSWindows/aspi32.c index 087769a0..ddb73174 100644 --- a/lib/MSWindows/aspi32.c +++ b/lib/driver/MSWindows/aspi32.c @@ -1,5 +1,5 @@ /* - $Id: aspi32.c,v 1.53 2004/11/07 16:29:05 rocky Exp $ + $Id: aspi32.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein @@ -27,7 +27,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: aspi32.c,v 1.53 2004/11/07 16:29:05 rocky Exp $"; +static const char _rcsid[] = "$Id: aspi32.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #include #include diff --git a/lib/MSWindows/aspi32.h b/lib/driver/MSWindows/aspi32.h similarity index 99% rename from lib/MSWindows/aspi32.h rename to lib/driver/MSWindows/aspi32.h index d2467847..1f607592 100644 --- a/lib/MSWindows/aspi32.h +++ b/lib/driver/MSWindows/aspi32.h @@ -1,6 +1,6 @@ /* Win32 aspi specific */ /* - $Id: aspi32.h,v 1.13 2004/08/27 04:12:29 rocky Exp $ + $Id: aspi32.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein diff --git a/lib/MSWindows/win32.c b/lib/driver/MSWindows/win32.c similarity index 99% rename from lib/MSWindows/win32.c rename to lib/driver/MSWindows/win32.c index 1788bf7a..e77dc121 100644 --- a/lib/MSWindows/win32.c +++ b/lib/driver/MSWindows/win32.c @@ -1,5 +1,5 @@ /* - $Id: win32.c,v 1.50 2004/10/31 17:43:30 rocky Exp $ + $Id: win32.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein @@ -26,7 +26,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: win32.c,v 1.50 2004/10/31 17:43:30 rocky Exp $"; +static const char _rcsid[] = "$Id: win32.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #include #include diff --git a/lib/MSWindows/win32.h b/lib/driver/MSWindows/win32.h similarity index 98% rename from lib/MSWindows/win32.h rename to lib/driver/MSWindows/win32.h index b2aac876..98b33b30 100644 --- a/lib/MSWindows/win32.h +++ b/lib/driver/MSWindows/win32.h @@ -1,5 +1,5 @@ /* - $Id: win32.h,v 1.21 2004/08/10 03:44:56 rocky Exp $ + $Id: win32.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein diff --git a/lib/MSWindows/win32_ioctl.c b/lib/driver/MSWindows/win32_ioctl.c similarity index 99% rename from lib/MSWindows/win32_ioctl.c rename to lib/driver/MSWindows/win32_ioctl.c index 305a0b0c..798102e2 100644 --- a/lib/MSWindows/win32_ioctl.c +++ b/lib/driver/MSWindows/win32_ioctl.c @@ -1,5 +1,5 @@ /* - $Id: win32_ioctl.c,v 1.43 2004/11/07 06:36:53 rocky Exp $ + $Id: win32_ioctl.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein @@ -26,7 +26,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: win32_ioctl.c,v 1.43 2004/11/07 06:36:53 rocky Exp $"; +static const char _rcsid[] = "$Id: win32_ioctl.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #ifdef HAVE_WIN32_CDROM diff --git a/lib/driver/Makefile.am b/lib/driver/Makefile.am new file mode 100644 index 00000000..29545ef1 --- /dev/null +++ b/lib/driver/Makefile.am @@ -0,0 +1,173 @@ +# $Id: Makefile.am,v 1.1 2004/12/18 17:29:32 rocky Exp $ +# +# Copyright (C) 2003, 2004 Rocky Bernstein +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +######################################################## +# Things to make the libcdio library +######################################################## +# +# From libtool documentation amended with guidance from N. Boullis: +# +# 1. Start with version information of `0:0:0' for each libtool library. +# +# 2. It is probably not a good idea to update the version information +# several times between public releases, but rather once per public +# release. (This seems to be more an aesthetic consideration than +# a hard technical one.) +# +# 3. If the library source code has changed at all since the last +# update, then increment REVISION (`C:R:A' becomes `C:R+1:A'). +# +# 4. If any interfaces have been added, removed, or changed since the +# last update, increment CURRENT, and set REVISION to 0. +# +# 5. If any interfaces have been added since the last public release, +# then increment AGE. +# +# 6. If any interfaces have been removed or changed since the last +# public release, then set AGE to 0. A changed interface means an +# incompatibility with previous versions. + +libcdio_la_CURRENT := 3 +libcdio_la_REVISION := 0 +libcdio_la_AGE := 0 + +EXTRA_DIST = image/Makefile FreeBSD/Makefile MSWindows/Makefile \ + libcdio.sym + +noinst_HEADERS = cdio_assert.h cdio_private.h portable.h + +libcdio_sources = \ + _cdio_aix.c \ + _cdio_bsdi.c \ + _cdio_generic.c \ + _cdio_linux.c \ + _cdio_osx.c \ + _cdio_stdio.c \ + _cdio_stdio.h \ + _cdio_stream.c \ + _cdio_stream.h \ + _cdio_sunos.c \ + cd_types.c \ + cdio.c \ + cdtext.c \ + cdtext_private.h \ + ds.c \ + FreeBSD/freebsd.c \ + FreeBSD/freebsd.h \ + FreeBSD/freebsd_cam.c \ + FreeBSD/freebsd_ioctl.c \ + generic.h \ + image.h \ + image/bincue.c \ + image/cdrdao.c \ + image_common.h \ + image/nrg.c \ + image/nrg.h \ + MSWindows/aspi32.c \ + MSWindows/aspi32.h \ + MSWindows/win32_ioctl.c \ + MSWindows/win32.c \ + MSWindows/win32.h \ + logging.c \ + scsi_mmc.c \ + scsi_mmc_private.h \ + sector.c \ + util.c + +lib_LTLIBRARIES = libcdio.la + +libcdio_la_SOURCES = $(libcdio_sources) +libcdio_la_ldflags = -version-info $(libcdio_la_CURRENT):$(libcdio_la_REVISION):$(libcdio_la_AGE) + +INCLUDES = $(LIBCDIO_CFLAGS) + +######################################################## +# Things to version the symbols in the libraries +######################################################## + +# An explanation of the versioning problem from Nicolas Boullis and +# the versioned symbol solution he uses below... +# +# Currently, libvcdinfo uses the cdio_open function from libcdio. +# Let's imagine a program foobar that uses both the vcdinfo_open +# function from libvcdinfo and the cdio_open function from libcdio. + +# Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME +# libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both +# libvcdinfo.so.0 and libcdio.so.0. Everything looks fine. +# +# Now, for some reason, you decide to change the cdio_open function. +# That's your right, but you have to bump the CURRENT version and (if I +# understand it correctly, athough this is not that clear in libtool's +# documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is +# sane since the interface changes incompatibly. + +# Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and +# foobar still require libcdio.so.0. Everything is still fine. + +# Now, after some minor changes, the author of foobar recompiles foobar. +# Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar +# now segfaults... + +# What is happening? When you run foobar, if brings both libvcdinfo.so.0 +# and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you +# have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the +# global namespace. Hence, you have to incompatible versions of the +# cdio_open function in the name space. When foobar calls cdio_open, it +# may choose the wrong function, and segfaults... + +# With versioned symbols, the cdio_open function from libcdio.so.0 may be +# known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open +# function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of +# libcdio would still be brought in by the most recent foobar, but foobar +# (and libvcdinfo) know which versioned function to use and then use the +# good one. + + +# This is some simple versioning where every symbol is versioned with +# something that looks like the SONAME of the library. More complex (and +# better) versioning is possible; it is for example what is used by glibc. +# But good complex versioning is something that requires much more +# work... + + +# The below is a impliments symbol versioning. First of all, I +# compute MAJOR as CURENT - AGE; that is what is used within libtool +# (at least on GNU/Linux systems) for the number in the SONAME. The +# nm command gives the list of symbols known in each of the object +# files that will be part of the shared library. And the sed command +# extracts from this list those symbols that will be shared. (This sed +# command comes from libtool.) + +libcdio_la_MAJOR := $(shell expr $(libcdio_la_CURRENT) - $(libcdio_la_AGE)) +if BUILD_VERSIONED_LIBS +libcdio_la_LDFLAGS = $(libcdio_la_ldflags) -Wl,--version-script=libcdio.la.ver +libcdio_la_DEPENDENCIES = libcdio.la.ver + +libcdio.la.ver: $(libcdio_la_OBJECTS) $(srcdir)/libcdio.sym + echo 'CDIO_$(libcdio_la_MAJOR) { ' > $@ + echo " global:" >> $@ + nm $(patsubst %.lo,%.o,$(libcdio_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio.sym; then echo " $${symbol};"; fi; done >> $@ + echo " local:" >> $@ + nm $(patsubst %.lo,%.o,$(libcdio_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio.sym; then :; else echo " $${symbol};"; fi; done >> $@ + echo '};' >> $@ +else +libcdio_la_LDFLAGS = $(libcdio_la_ldflags) +endif + +MOSTLYCLEANFILES = libcdio.la.ver diff --git a/lib/_cdio_aix.c b/lib/driver/_cdio_aix.c similarity index 99% rename from lib/_cdio_aix.c rename to lib/driver/_cdio_aix.c index 4c5961c4..a59e0e5a 100644 --- a/lib/_cdio_aix.c +++ b/lib/driver/_cdio_aix.c @@ -1,5 +1,5 @@ /* - $Id: _cdio_aix.c,v 1.1 2004/12/15 01:45:15 rocky Exp $ + $Id: _cdio_aix.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein @@ -37,7 +37,7 @@ #ifdef HAVE_AIX_CDROM -static const char _rcsid[] = "$Id: _cdio_aix.c,v 1.1 2004/12/15 01:45:15 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_aix.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #ifdef HAVE_GLOB_H #include diff --git a/lib/_cdio_bsdi.c b/lib/driver/_cdio_bsdi.c similarity index 99% rename from lib/_cdio_bsdi.c rename to lib/driver/_cdio_bsdi.c index 0ad92596..7c9b675d 100644 --- a/lib/_cdio_bsdi.c +++ b/lib/driver/_cdio_bsdi.c @@ -1,5 +1,5 @@ /* - $Id: _cdio_bsdi.c,v 1.44 2004/11/20 12:50:26 rocky Exp $ + $Id: _cdio_bsdi.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2001 Herbert Valerio Riedel Copyright (C) 2002, 2003, 2004 Rocky Bernstein @@ -27,7 +27,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: _cdio_bsdi.c,v 1.44 2004/11/20 12:50:26 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_bsdi.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #include #include diff --git a/lib/_cdio_generic.c b/lib/driver/_cdio_generic.c similarity index 98% rename from lib/_cdio_generic.c rename to lib/driver/_cdio_generic.c index 317f943b..401e6886 100644 --- a/lib/_cdio_generic.c +++ b/lib/driver/_cdio_generic.c @@ -1,5 +1,5 @@ /* - $Id: _cdio_generic.c,v 1.29 2004/11/01 09:14:21 rocky Exp $ + $Id: _cdio_generic.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein @@ -25,7 +25,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: _cdio_generic.c,v 1.29 2004/11/01 09:14:21 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_generic.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #include #include diff --git a/lib/_cdio_linux.c b/lib/driver/_cdio_linux.c similarity index 99% rename from lib/_cdio_linux.c rename to lib/driver/_cdio_linux.c index 1cd8bf1f..0bf5ae82 100644 --- a/lib/_cdio_linux.c +++ b/lib/driver/_cdio_linux.c @@ -1,5 +1,5 @@ /* - $Id: _cdio_linux.c,v 1.101 2004/12/04 11:50:40 rocky Exp $ + $Id: _cdio_linux.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2001 Herbert Valerio Riedel Copyright (C) 2002, 2003, 2004 Rocky Bernstein @@ -27,7 +27,7 @@ # include "config.h" #endif -static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.101 2004/12/04 11:50:40 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_linux.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #include diff --git a/lib/_cdio_osx.c b/lib/driver/_cdio_osx.c similarity index 99% rename from lib/_cdio_osx.c rename to lib/driver/_cdio_osx.c index 6fc73d04..0f1564ba 100644 --- a/lib/_cdio_osx.c +++ b/lib/driver/_cdio_osx.c @@ -1,5 +1,5 @@ /* - $Id: _cdio_osx.c,v 1.70 2004/10/26 07:34:41 rocky Exp $ + $Id: _cdio_osx.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein from vcdimager code: @@ -34,7 +34,7 @@ #include "config.h" #endif -static const char _rcsid[] = "$Id: _cdio_osx.c,v 1.70 2004/10/26 07:34:41 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_osx.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #include #include diff --git a/lib/_cdio_stdio.c b/lib/driver/_cdio_stdio.c similarity index 97% rename from lib/_cdio_stdio.c rename to lib/driver/_cdio_stdio.c index 4b22acee..8a8b3fcc 100644 --- a/lib/_cdio_stdio.c +++ b/lib/driver/_cdio_stdio.c @@ -1,5 +1,5 @@ /* - $Id: _cdio_stdio.c,v 1.8 2004/06/19 19:15:15 rocky Exp $ + $Id: _cdio_stdio.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2003, 2004 Rocky Bernstein @@ -39,7 +39,7 @@ #include "_cdio_stream.h" #include "_cdio_stdio.h" -static const char _rcsid[] = "$Id: _cdio_stdio.c,v 1.8 2004/06/19 19:15:15 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_stdio.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #define CDIO_STDIO_BUFSIZE (128*1024) diff --git a/lib/_cdio_stdio.h b/lib/driver/_cdio_stdio.h similarity index 96% rename from lib/_cdio_stdio.h rename to lib/driver/_cdio_stdio.h index 3bad81c5..c8043b04 100644 --- a/lib/_cdio_stdio.h +++ b/lib/driver/_cdio_stdio.h @@ -1,5 +1,5 @@ /* - $Id: _cdio_stdio.h,v 1.3 2004/02/07 18:53:02 rocky Exp $ + $Id: _cdio_stdio.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2003 Rocky Bernstein diff --git a/lib/_cdio_stream.c b/lib/driver/_cdio_stream.c similarity index 96% rename from lib/_cdio_stream.c rename to lib/driver/_cdio_stream.c index 34553de2..34b8eea7 100644 --- a/lib/_cdio_stream.c +++ b/lib/driver/_cdio_stream.c @@ -1,5 +1,5 @@ /* - $Id: _cdio_stream.c,v 1.10 2004/10/24 23:42:39 rocky Exp $ + $Id: _cdio_stream.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000, 2004 Herbert Valerio Riedel @@ -34,7 +34,7 @@ #include #include "_cdio_stream.h" -static const char _rcsid[] = "$Id: _cdio_stream.c,v 1.10 2004/10/24 23:42:39 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_stream.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; /* * DataSource implementations diff --git a/lib/_cdio_stream.h b/lib/driver/_cdio_stream.h similarity index 98% rename from lib/_cdio_stream.h rename to lib/driver/_cdio_stream.h index 126f0d23..33815160 100644 --- a/lib/_cdio_stream.h +++ b/lib/driver/_cdio_stream.h @@ -1,5 +1,5 @@ /* - $Id: _cdio_stream.h,v 1.8 2004/02/07 18:53:02 rocky Exp $ + $Id: _cdio_stream.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2003, 2004 Rocky Bernstein diff --git a/lib/_cdio_sunos.c b/lib/driver/_cdio_sunos.c similarity index 99% rename from lib/_cdio_sunos.c rename to lib/driver/_cdio_sunos.c index baa6c4c6..9bbb61b7 100644 --- a/lib/_cdio_sunos.c +++ b/lib/driver/_cdio_sunos.c @@ -1,5 +1,5 @@ /* - $Id: _cdio_sunos.c,v 1.80 2004/12/06 05:30:43 rocky Exp $ + $Id: _cdio_sunos.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2001 Herbert Valerio Riedel Copyright (C) 2002, 2003, 2004 Rocky Bernstein @@ -38,7 +38,7 @@ #ifdef HAVE_SOLARIS_CDROM -static const char _rcsid[] = "$Id: _cdio_sunos.c,v 1.80 2004/12/06 05:30:43 rocky Exp $"; +static const char _rcsid[] = "$Id: _cdio_sunos.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #ifdef HAVE_GLOB_H #include diff --git a/lib/cd_types.c b/lib/driver/cd_types.c similarity index 99% rename from lib/cd_types.c rename to lib/driver/cd_types.c index d3fc6dd2..db32cb55 100644 --- a/lib/cd_types.c +++ b/lib/driver/cd_types.c @@ -1,5 +1,5 @@ /* - $Id: cd_types.c,v 1.10 2004/06/23 09:28:02 rocky Exp $ + $Id: cd_types.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein diff --git a/lib/cdio.c b/lib/driver/cdio.c similarity index 99% rename from lib/cdio.c rename to lib/driver/cdio.c index 831a78e7..0b59f4fb 100644 --- a/lib/cdio.c +++ b/lib/driver/cdio.c @@ -1,5 +1,5 @@ /* - $Id: cdio.c,v 1.78 2004/12/17 04:50:46 rocky Exp $ + $Id: cdio.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein Copyright (C) 2001 Herbert Valerio Riedel @@ -39,7 +39,7 @@ #include #include "cdio_private.h" -static const char _rcsid[] = "$Id: cdio.c,v 1.78 2004/12/17 04:50:46 rocky Exp $"; +static const char _rcsid[] = "$Id: cdio.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; const char *track_format2str[6] = diff --git a/lib/cdio_assert.h b/lib/driver/cdio_assert.h similarity index 96% rename from lib/cdio_assert.h rename to lib/driver/cdio_assert.h index a885da41..8c770176 100644 --- a/lib/cdio_assert.h +++ b/lib/driver/cdio_assert.h @@ -1,5 +1,5 @@ /* - $Id: cdio_assert.h,v 1.4 2003/09/18 13:40:54 rocky Exp $ + $Id: cdio_assert.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel diff --git a/lib/cdio_private.h b/lib/driver/cdio_private.h similarity index 99% rename from lib/cdio_private.h rename to lib/driver/cdio_private.h index 8136a623..01054d51 100644 --- a/lib/cdio_private.h +++ b/lib/driver/cdio_private.h @@ -1,5 +1,5 @@ /* - $Id: cdio_private.h,v 1.42 2004/09/03 23:20:11 rocky Exp $ + $Id: cdio_private.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein diff --git a/lib/cdtext.c b/lib/driver/cdtext.c similarity index 98% rename from lib/cdtext.c rename to lib/driver/cdtext.c index 553e2402..3a162528 100644 --- a/lib/cdtext.c +++ b/lib/driver/cdtext.c @@ -1,5 +1,5 @@ /* - $Id: cdtext.c,v 1.10 2004/11/08 04:13:27 rocky Exp $ + $Id: cdtext.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein toc reading routine adapted from cuetools diff --git a/lib/cdtext_private.h b/lib/driver/cdtext_private.h similarity index 98% rename from lib/cdtext_private.h rename to lib/driver/cdtext_private.h index 5bacd8d6..a258e222 100644 --- a/lib/cdtext_private.h +++ b/lib/driver/cdtext_private.h @@ -1,5 +1,5 @@ /* - $Id: cdtext_private.h,v 1.6 2004/10/28 03:50:32 rocky Exp $ + $Id: cdtext_private.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein diff --git a/lib/ds.c b/lib/driver/ds.c similarity index 97% rename from lib/ds.c rename to lib/driver/ds.c index 9c234d7d..9a82e447 100644 --- a/lib/ds.c +++ b/lib/driver/ds.c @@ -1,5 +1,5 @@ /* - $Id: ds.c,v 1.4 2004/10/09 03:20:28 rocky Exp $ + $Id: ds.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel @@ -30,7 +30,7 @@ #include #include "cdio_assert.h" -static const char _rcsid[] = "$Id: ds.c,v 1.4 2004/10/09 03:20:28 rocky Exp $"; +static const char _rcsid[] = "$Id: ds.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; struct _CdioList { diff --git a/lib/generic.h b/lib/driver/generic.h similarity index 98% rename from lib/generic.h rename to lib/driver/generic.h index c48b721f..5d721e98 100644 --- a/lib/generic.h +++ b/lib/driver/generic.h @@ -1,5 +1,5 @@ /* - $Id: generic.h,v 1.3 2004/10/24 23:42:39 rocky Exp $ + $Id: generic.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein diff --git a/lib/image.h b/lib/driver/image.h similarity index 97% rename from lib/image.h rename to lib/driver/image.h index 4d11567d..25b632e6 100644 --- a/lib/image.h +++ b/lib/driver/image.h @@ -1,5 +1,5 @@ /* - $Id: image.h,v 1.3 2004/07/11 14:25:07 rocky Exp $ + $Id: image.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein diff --git a/lib/image/Makefile b/lib/driver/image/Makefile similarity index 94% rename from lib/image/Makefile rename to lib/driver/image/Makefile index a375cd15..d369e415 100644 --- a/lib/image/Makefile +++ b/lib/driver/image/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.1 2004/06/20 15:35:31 rocky Exp $ +# $Id: Makefile,v 1.1 2004/12/18 17:29:32 rocky Exp $ # # Copyright (C) 2004 Rocky Bernstein # This program is free software; you can redistribute it and/or modify diff --git a/lib/image/bincue.c b/lib/driver/image/bincue.c similarity index 99% rename from lib/image/bincue.c rename to lib/driver/image/bincue.c index bcb4d641..dfb158a3 100644 --- a/lib/image/bincue.c +++ b/lib/driver/image/bincue.c @@ -1,5 +1,5 @@ /* - $Id: bincue.c,v 1.47 2004/11/07 21:13:10 rocky Exp $ + $Id: bincue.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2002, 2003, 2004 Rocky Bernstein Copyright (C) 2001 Herbert Valerio Riedel @@ -26,7 +26,7 @@ (*.cue). */ -static const char _rcsid[] = "$Id: bincue.c,v 1.47 2004/11/07 21:13:10 rocky Exp $"; +static const char _rcsid[] = "$Id: bincue.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #include "image.h" #include "cdio_assert.h" diff --git a/lib/image/cdrdao.c b/lib/driver/image/cdrdao.c similarity index 99% rename from lib/image/cdrdao.c rename to lib/driver/image/cdrdao.c index a464a667..8711989b 100644 --- a/lib/image/cdrdao.c +++ b/lib/driver/image/cdrdao.c @@ -1,5 +1,5 @@ /* - $Id: cdrdao.c,v 1.30 2004/11/07 21:13:10 rocky Exp $ + $Id: cdrdao.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein toc reading routine adapted from cuetools @@ -25,7 +25,7 @@ (*.cue). */ -static const char _rcsid[] = "$Id: cdrdao.c,v 1.30 2004/11/07 21:13:10 rocky Exp $"; +static const char _rcsid[] = "$Id: cdrdao.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; #include "image.h" #include "cdio_assert.h" diff --git a/lib/image/nrg.c b/lib/driver/image/nrg.c similarity index 99% rename from lib/image/nrg.c rename to lib/driver/image/nrg.c index 5a87c3ce..bf35fbac 100644 --- a/lib/image/nrg.c +++ b/lib/driver/image/nrg.c @@ -1,5 +1,5 @@ /* - $Id: nrg.c,v 1.44 2004/12/17 04:57:14 rocky Exp $ + $Id: nrg.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein Copyright (C) 2001, 2003 Herbert Valerio Riedel @@ -46,7 +46,7 @@ #include "_cdio_stdio.h" #include "nrg.h" -static const char _rcsid[] = "$Id: nrg.c,v 1.44 2004/12/17 04:57:14 rocky Exp $"; +static const char _rcsid[] = "$Id: nrg.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; /* reader */ diff --git a/lib/image/nrg.h b/lib/driver/image/nrg.h similarity index 98% rename from lib/image/nrg.h rename to lib/driver/image/nrg.h index a1c6c18b..44ad0215 100644 --- a/lib/image/nrg.h +++ b/lib/driver/image/nrg.h @@ -1,5 +1,5 @@ /* - $Id: nrg.h,v 1.3 2004/07/09 02:46:42 rocky Exp $ + $Id: nrg.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein Copyright (C) 2001, 2003 Herbert Valerio Riedel diff --git a/lib/image_common.h b/lib/driver/image_common.h similarity index 98% rename from lib/image_common.h rename to lib/driver/image_common.h index 5785774a..575bdfef 100644 --- a/lib/image_common.h +++ b/lib/driver/image_common.h @@ -1,5 +1,5 @@ /* - $Id: image_common.h,v 1.17 2004/10/09 03:20:28 rocky Exp $ + $Id: image_common.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein diff --git a/lib/libcdio.sym b/lib/driver/libcdio.sym similarity index 100% rename from lib/libcdio.sym rename to lib/driver/libcdio.sym diff --git a/lib/logging.c b/lib/driver/logging.c similarity index 95% rename from lib/logging.c rename to lib/driver/logging.c index 0af3f0c6..d40894f3 100644 --- a/lib/logging.c +++ b/lib/driver/logging.c @@ -1,5 +1,5 @@ /* - $Id: logging.c,v 1.7 2004/10/31 14:55:35 rocky Exp $ + $Id: logging.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2003, 2004 Rocky Bernstein @@ -31,7 +31,7 @@ #include "cdio_assert.h" #include "portable.h" -static const char _rcsid[] = "$Id: logging.c,v 1.7 2004/10/31 14:55:35 rocky Exp $"; +static const char _rcsid[] = "$Id: logging.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; cdio_log_level_t cdio_loglevel_default = CDIO_LOG_WARN; diff --git a/lib/portable.h b/lib/driver/portable.h similarity index 97% rename from lib/portable.h rename to lib/driver/portable.h index 701776af..9e1dd069 100644 --- a/lib/portable.h +++ b/lib/driver/portable.h @@ -1,5 +1,5 @@ /* - $Id: portable.h,v 1.4 2004/11/07 21:13:10 rocky Exp $ + $Id: portable.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) Rocky Bernstein diff --git a/lib/scsi_mmc.c b/lib/driver/scsi_mmc.c similarity index 90% rename from lib/scsi_mmc.c rename to lib/driver/scsi_mmc.c index 44f092af..04cf38f6 100644 --- a/lib/scsi_mmc.c +++ b/lib/driver/scsi_mmc.c @@ -1,6 +1,6 @@ /* Common SCSI Multimedia Command (MMC) routines. - $Id: scsi_mmc.c,v 1.32 2004/12/06 04:47:57 rocky Exp $ + $Id: scsi_mmc.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein @@ -93,8 +93,11 @@ scsi_mmc_get_drive_cap_buf(const uint8_t *p, if (p[2] & 0x02) *p_read_cap |= CDIO_DRIVE_CAP_READ_CD_RW; if (p[2] & 0x08) *p_read_cap |= CDIO_DRIVE_CAP_READ_DVD_ROM; if (p[4] & 0x01) *p_read_cap |= CDIO_DRIVE_CAP_READ_AUDIO; + if (p[4] & 0x10) *p_read_cap |= CDIO_DRIVE_CAP_READ_MODE2_FORM1; + if (p[4] & 0x20) *p_read_cap |= CDIO_DRIVE_CAP_READ_MODE2_FORM2; if (p[5] & 0x01) *p_read_cap |= CDIO_DRIVE_CAP_READ_CD_DA; if (p[5] & 0x10) *p_read_cap |= CDIO_DRIVE_CAP_READ_C2_ERRS; + if (p[5] & 0x20) *p_read_cap |= CDIO_DRIVE_CAP_READ_ISRC; /* Writer */ if (p[3] & 0x01) *p_write_cap |= CDIO_DRIVE_CAP_WRITE_CD_R; @@ -154,13 +157,66 @@ scsi_mmc_run_cmd( const CdIo *p_cdio, unsigned int i_timeout_ms, #define DEFAULT_TIMEOUT_MS 6000 +int +scsi_mmc_get_blocksize_private ( const void *p_env, + const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd) +{ + int i_status = 0; + scsi_mmc_cdb_t cdb = {{0, }}; + + struct + { + uint8_t reserved1; + uint8_t medium; + uint8_t reserved2; + uint8_t block_desc_length; + uint8_t density; + uint8_t number_of_blocks_hi; + uint8_t number_of_blocks_med; + uint8_t number_of_blocks_lo; + uint8_t reserved3; + uint8_t block_length_hi; + uint8_t block_length_med; + uint8_t block_length_lo; + } mh; + + uint8_t *p = &mh.block_length_med; + + if ( ! p_env || ! run_scsi_mmc_cmd ) + return -2; + + memset (&mh, 0, sizeof (mh)); + + CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SENSE); + + cdb.field[1] = 0x3F&1; + cdb.field[4] = 12; + + i_status = run_scsi_mmc_cmd (p_env, DEFAULT_TIMEOUT_MS, + scsi_mmc_get_cmd_len(cdb.field[0]), &cdb, + SCSI_MMC_DATA_WRITE, sizeof(mh), &mh); + if (0 != i_status) return -2; + + return CDIO_MMC_GET_LEN16(p); +} + +int +scsi_mmc_get_blocksize ( const CdIo *p_cdio) +{ + if ( ! p_cdio ) return -2; + return + scsi_mmc_get_blocksize_private (p_cdio->env, p_cdio->op.run_scsi_mmc_cmd); + +} + + /*! * Eject using SCSI MMC commands. Return 0 if successful. */ int scsi_mmc_eject_media( const CdIo *p_cdio ) { - int i_status; + int i_status = 0; scsi_mmc_cdb_t cdb = {{0, }}; uint8_t buf[1]; scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd; @@ -175,8 +231,7 @@ scsi_mmc_eject_media( const CdIo *p_cdio ) i_status = run_scsi_mmc_cmd (p_cdio->env, DEFAULT_TIMEOUT_MS, scsi_mmc_get_cmd_len(cdb.field[0]), &cdb, SCSI_MMC_DATA_WRITE, 0, &buf); - if (0 != i_status) - return i_status; + if (0 != i_status) return i_status; CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_START_STOP); cdb.field[4] = 1; @@ -228,7 +283,7 @@ scsi_mmc_read_sectors ( const CdIo *p_cdio, void *p_buf, lba_t lba, int scsi_mmc_set_blocksize_private ( const void *p_env, const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd, - unsigned int bsize) + unsigned int i_bsize) { scsi_mmc_cdb_t cdb = {{0, }}; @@ -253,9 +308,9 @@ scsi_mmc_set_blocksize_private ( const void *p_env, memset (&mh, 0, sizeof (mh)); mh.block_desc_length = 0x08; - mh.block_length_hi = (bsize >> 16) & 0xff; - mh.block_length_med = (bsize >> 8) & 0xff; - mh.block_length_lo = (bsize >> 0) & 0xff; + mh.block_length_hi = (i_bsize >> 16) & 0xff; + mh.block_length_med = (i_bsize >> 8) & 0xff; + mh.block_length_lo = (i_bsize >> 0) & 0xff; CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SELECT_6); @@ -268,12 +323,12 @@ scsi_mmc_set_blocksize_private ( const void *p_env, } int -scsi_mmc_set_blocksize ( const CdIo *cdio, unsigned int bsize) +scsi_mmc_set_blocksize ( const CdIo *p_cdio, unsigned int i_bsize) { - if ( ! cdio ) return -2; + if ( ! p_cdio ) return -2; return - scsi_mmc_set_blocksize_private (cdio->env, cdio->op.run_scsi_mmc_cmd, - bsize); + scsi_mmc_set_blocksize_private (p_cdio->env, p_cdio->op.run_scsi_mmc_cmd, + i_bsize); } diff --git a/lib/scsi_mmc_private.h b/lib/driver/scsi_mmc_private.h similarity index 94% rename from lib/scsi_mmc_private.h rename to lib/driver/scsi_mmc_private.h index b71d6d99..f53a0220 100644 --- a/lib/scsi_mmc_private.h +++ b/lib/driver/scsi_mmc_private.h @@ -1,6 +1,6 @@ /* private MMC helper routines. - $Id: scsi_mmc_private.h,v 1.9 2004/07/31 07:43:26 rocky Exp $ + $Id: scsi_mmc_private.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein @@ -55,9 +55,8 @@ scsi_mmc_get_dvd_struct_physical_private ( void *p_env, const int -scsi_mmc_set_blocksize_private ( const void *p_env, - const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd, - unsigned int bsize); +scsi_mmc_get_blocksize_private ( const void *p_env, + const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd); char *scsi_mmc_get_mcn_private ( void *p_env, const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd @@ -99,7 +98,8 @@ scsi_mmc_get_drive_cap_generic (const void *p_user_data, /*out*/ cdio_drive_write_cap_t *p_write_cap, /*out*/ cdio_drive_misc_cap_t *p_misc_cap); - - - +int +scsi_mmc_set_blocksize_private ( const void *p_env, + const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd, + unsigned int i_bsize); diff --git a/lib/sector.c b/lib/driver/sector.c similarity index 97% rename from lib/sector.c rename to lib/driver/sector.c index 3562dcce..a284f07c 100644 --- a/lib/sector.c +++ b/lib/driver/sector.c @@ -1,5 +1,5 @@ /* - $Id: sector.c,v 1.15 2004/11/18 01:56:09 rocky Exp $ + $Id: sector.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2004 Rocky Bernstein Copyright (C) 2000 Herbert Valerio Riedel @@ -35,7 +35,7 @@ #include -static const char _rcsid[] = "$Id: sector.c,v 1.15 2004/11/18 01:56:09 rocky Exp $"; +static const char _rcsid[] = "$Id: sector.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; lba_t cdio_lba_to_lsn (lba_t lba) diff --git a/lib/util.c b/lib/driver/util.c similarity index 96% rename from lib/util.c rename to lib/driver/util.c index edf0f0bd..06d2178b 100644 --- a/lib/util.c +++ b/lib/driver/util.c @@ -1,5 +1,5 @@ /* - $Id: util.c,v 1.6 2004/11/15 01:34:09 rocky Exp $ + $Id: util.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2003, 2004 Rocky Bernstein @@ -36,7 +36,7 @@ #include #include -static const char _rcsid[] = "$Id: util.c,v 1.6 2004/11/15 01:34:09 rocky Exp $"; +static const char _rcsid[] = "$Id: util.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; size_t _cdio_strlenv(char **str_array) diff --git a/lib/iso9660/.cvsignore b/lib/iso9660/.cvsignore new file mode 100644 index 00000000..ed5ff996 --- /dev/null +++ b/lib/iso9660/.cvsignore @@ -0,0 +1,9 @@ +.deps +.libs +Makefile +Makefile.in +*.o +*.lo +*.la +*.la.ver + diff --git a/lib/iso9660/Makefile.am b/lib/iso9660/Makefile.am new file mode 100644 index 00000000..28ff3c13 --- /dev/null +++ b/lib/iso9660/Makefile.am @@ -0,0 +1,141 @@ +# $Id: Makefile.am,v 1.1 2004/12/18 17:29:32 rocky Exp $ +# +# Copyright (C) 2003, 2004 Rocky Bernstein +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +######################################################## +# Things to make the libiso9660 library +######################################################## +# +# From libtool documentation amended with guidance from N. Boullis: +# +# 1. Start with version information of `0:0:0' for each libtool library. +# +# 2. It is probably not a good idea to update the version information +# several times between public releases, but rather once per public +# release. (This seems to be more an aesthetic consideration than +# a hard technical one.) +# +# 3. If the library source code has changed at all since the last +# update, then increment REVISION (`C:R:A' becomes `C:R+1:A'). +# +# 4. If any interfaces have been added, removed, or changed since the +# last update, increment CURRENT, and set REVISION to 0. +# +# 5. If any interfaces have been added since the last public release, +# then increment AGE. +# +# 6. If any interfaces have been removed or changed since the last +# public release, then set AGE to 0. A changed interface means an +# incompatibility with previous versions. + +libiso9660_la_CURRENT := 3 +libiso9660_la_REVISION := 0 +libiso9660_la_AGE := 0 + +EXTRA_DIST = libiso9660.sym + +noinst_HEADERS = iso9660_private.h + +lib_LTLIBRARIES = libiso9660.la + +libiso9660_la_SOURCES = \ + iso9660.c \ + iso9660_private.h \ + iso9660_fs.c \ + xa.c + +libiso9660_la_LIBADD = @LIBCDIO_LIBS@ +libiso9660_la_ldflags = -version-info $(libiso9660_la_CURRENT):$(libiso9660_la_REVISION):$(libiso9660_la_AGE) + +INCLUDES = $(LIBCDIO_CFLAGS) + +######################################################## +# Things to version the symbols in the libraries +######################################################## + +# An explanation of the versioning problem from Nicolas Boullis and +# the versioned symbol solution he uses below... +# +# Currently, libvcdinfo uses the cdio_open function from libcdio. +# Let's imagine a program foobar that uses both the vcdinfo_open +# function from libvcdinfo and the cdio_open function from libcdio. + +# Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME +# libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both +# libvcdinfo.so.0 and libcdio.so.0. Everything looks fine. +# +# Now, for some reason, you decide to change the cdio_open function. +# That's your right, but you have to bump the CURRENT version and (if I +# understand it correctly, athough this is not that clear in libtool's +# documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is +# sane since the interface changes incompatibly. + +# Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and +# foobar still require libcdio.so.0. Everything is still fine. + +# Now, after some minor changes, the author of foobar recompiles foobar. +# Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar +# now segfaults... + +# What is happening? When you run foobar, if brings both libvcdinfo.so.0 +# and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you +# have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the +# global namespace. Hence, you have to incompatible versions of the +# cdio_open function in the name space. When foobar calls cdio_open, it +# may choose the wrong function, and segfaults... + +# With versioned symbols, the cdio_open function from libcdio.so.0 may be +# known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open +# function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of +# libcdio would still be brought in by the most recent foobar, but foobar +# (and libvcdinfo) know which versioned function to use and then use the +# good one. + + +# This is some simple versioning where every symbol is versioned with +# something that looks like the SONAME of the library. More complex (and +# better) versioning is possible; it is for example what is used by glibc. +# But good complex versioning is something that requires much more +# work... + + +# The below is a impliments symbol versioning. First of all, I +# compute MAJOR as CURENT - AGE; that is what is used within libtool +# (at least on GNU/Linux systems) for the number in the SONAME. The +# nm command gives the list of symbols known in each of the object +# files that will be part of the shared library. And the sed command +# extracts from this list those symbols that will be shared. (This sed +# command comes from libtool.) + +libiso9660_la_MAJOR := $(shell expr $(libiso9660_la_CURRENT) - $(libiso9660_la_AGE)) +if BUILD_VERSIONED_LIBS +libiso9660_la_LDFLAGS = $(libiso9660_la_ldflags) -Wl,--version-script=libiso9660.la.ver +libiso9660_la_DEPENDENCIES = @LIBCDIO_LIBS@ libiso9660.la.ver + +libiso9660.la.ver: $(libiso9660_la_OBJECTS) $(srcdir)/libiso9660.sym + echo 'ISO9660_$(libiso9660_la_MAJOR) {' > $@ + echo " global:" >> $@ + nm $(patsubst %.lo,%.o,$(libiso9660_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libiso9660.sym; then echo " $${symbol};"; fi; done >> $@ + echo " local:" >> $@ + nm $(patsubst %.lo,%.o,$(libiso9660_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libiso9660.sym; then :; else echo " $${symbol};"; fi; done >> $@ + echo '};' >> $@ + +MOSTLYCLEANFILES = libiso9660.la.ver +else +libiso9660_la_LDFLAGS = $(libiso9660_la_ldflags) +libiso9660_la_DEPENDENCIES = @LIBCDIO_LIBS@ +endif diff --git a/lib/iso9660.c b/lib/iso9660/iso9660.c similarity index 99% rename from lib/iso9660.c rename to lib/iso9660/iso9660.c index 5d7abeb0..6ce940ef 100644 --- a/lib/iso9660.c +++ b/lib/iso9660/iso9660.c @@ -1,5 +1,5 @@ /* - $Id: iso9660.c,v 1.25 2004/11/21 22:32:03 rocky Exp $ + $Id: iso9660.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2003, 2004 Rocky Bernstein @@ -37,7 +37,7 @@ #include #endif -static const char _rcsid[] = "$Id: iso9660.c,v 1.25 2004/11/21 22:32:03 rocky Exp $"; +static const char _rcsid[] = "$Id: iso9660.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; /* some parameters... */ #define SYSTEM_ID "CD-RTOS CD-BRIDGE" diff --git a/lib/iso9660_fs.c b/lib/iso9660/iso9660_fs.c similarity index 99% rename from lib/iso9660_fs.c rename to lib/iso9660/iso9660_fs.c index 029ccdb6..22a2ff34 100644 --- a/lib/iso9660_fs.c +++ b/lib/iso9660/iso9660_fs.c @@ -1,5 +1,5 @@ /* - $Id: iso9660_fs.c,v 1.42 2004/11/06 17:50:05 rocky Exp $ + $Id: iso9660_fs.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2001 Herbert Valerio Riedel Copyright (C) 2003, 2004 Rocky Bernstein @@ -51,7 +51,7 @@ #include -static const char _rcsid[] = "$Id: iso9660_fs.c,v 1.42 2004/11/06 17:50:05 rocky Exp $"; +static const char _rcsid[] = "$Id: iso9660_fs.c,v 1.1 2004/12/18 17:29:32 rocky Exp $"; /* Implementation of iso9660_t type */ struct _iso9660 { diff --git a/lib/iso9660_private.h b/lib/iso9660/iso9660_private.h similarity index 97% rename from lib/iso9660_private.h rename to lib/iso9660/iso9660_private.h index 4d7358ae..2f36f8a1 100644 --- a/lib/iso9660_private.h +++ b/lib/iso9660/iso9660_private.h @@ -1,5 +1,5 @@ /* - $Id: iso9660_private.h,v 1.8 2004/06/02 07:44:02 rocky Exp $ + $Id: iso9660_private.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2003, 2004 Rocky Bernstein diff --git a/lib/libiso9660.sym b/lib/iso9660/libiso9660.sym similarity index 100% rename from lib/libiso9660.sym rename to lib/iso9660/libiso9660.sym diff --git a/lib/xa.c b/lib/iso9660/xa.c similarity index 98% rename from lib/xa.c rename to lib/iso9660/xa.c index 3d19b628..9325bdf4 100644 --- a/lib/xa.c +++ b/lib/iso9660/xa.c @@ -1,5 +1,5 @@ /* - $Id: xa.c,v 1.5 2004/10/22 01:13:38 rocky Exp $ + $Id: xa.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2000 Herbert Valerio Riedel Copyright (C) 2003 Rocky Bernstein diff --git a/lib/paranoia/.cvsignore b/lib/paranoia/.cvsignore new file mode 100644 index 00000000..c17b1b9e --- /dev/null +++ b/lib/paranoia/.cvsignore @@ -0,0 +1,8 @@ +.deps +.libs +Makefile +Makefile.in +*.o +*.lo +*.la +*.la.ver diff --git a/lib/paranoia/Makefile.am b/lib/paranoia/Makefile.am new file mode 100644 index 00000000..e0b1f200 --- /dev/null +++ b/lib/paranoia/Makefile.am @@ -0,0 +1,77 @@ +# $Id: Makefile.am,v 1.1 2004/12/18 17:29:32 rocky Exp $ +# +# Copyright (C) 2004 Rocky Bernstein +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +######################################################## +# Things to make the libcdio_paranoia library +######################################################## + +# +# From libtool documentation amended with guidance from N. Boullis: +# +# 1. Start with version information of `0:0:0' for each libtool library. +# +# 2. It is probably not a good idea to update the version information +# several times between public releases, but rather once per public +# release. (This seems to be more an aesthetic consideration than +# a hard technical one.) +# +# 3. If the library source code has changed at all since the last +# update, then increment REVISION (`C:R:A' becomes `C:R+1:A'). +# +# 4. If any interfaces have been added, removed, or changed since the +# last update, increment CURRENT, and set REVISION to 0. +# +# 5. If any interfaces have been added since the last public release, +# then increment AGE. +# +# 6. If any interfaces have been removed or changed since the last +# public release, then set AGE to 0. A changed interface means an +# incompatibility with previous versions. + +libcdio_paranoia_la_CURRENT := 0 +libcdio_paranoia_la_REVISION := 0 +libcdio_paranoia_la_AGE := 0 + +noinst_HEADERS = gap.h isort.h overlap.h p_block.h + +libcdio_paranoia_sources = gap.c isort.c overlap.c overlap.h \ + p_block.c paranoia.c + +lib_LTLIBRARIES = libcdio_paranoia.la + +libcdio_paranoia_la_SOURCES = $(libcdio_paranoia_sources) +libcdio_paranoia_la_ldflags = -version-info $(libcdio_paranoia_la_CURRENT):$(libcdio_paranoia_la_REVISION):$(libcdio_paranoia_la_AGE) + +libcdio_paranoia_la_LDFLAGS = $(libcdio_paranoia_la_ldflags) + +INCLUDES = $(LIBCDIO_CFLAGS) + +FLAGS=@LIBCDIO_CFLAGS@ @TYPESIZES@ @CFLAGS@ -I.. -I../.. +OPT=$(FLAGS) +DEBUG=$(FLAGS) + +## SUFFIXES = .t +## TFILES = isort.t gap.t p_block.t paranoia.t +##test: $(TFILES) +##.c.t: +## $(CC) -g -DTEST $(DEBUG) -o $@ $< $(LIBS) +## $@ +##debug: +## $(MAKE) libcdio_paranoia.a CFLAGS="$(DEBUG)" + +LIBS = $(LIBCDIO_LIBS) $(LIBCDIO_CDDA_LIBS) diff --git a/lib/paranoia/gap.c b/lib/paranoia/gap.c new file mode 100644 index 00000000..366f5b5e --- /dev/null +++ b/lib/paranoia/gap.c @@ -0,0 +1,222 @@ +/* + $Id: gap.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*** + * Gap analysis support code for paranoia + * + ***/ + +#include "config.h" +#include "p_block.h" +#include +#include "gap.h" +#include + +/**** Gap analysis code ***************************************************/ + +long int +i_paranoia_overlap_r(int16_t *buffA,int16_t *buffB, + long offsetA, long offsetB) +{ + long beginA=offsetA; + long beginB=offsetB; + + for( ; beginA>=0 && beginB>=0; beginA--,beginB-- ) + if (buffA[beginA] != buffB[beginB]) break; + beginA++; + beginB++; + + return(offsetA-beginA); +} + +long int +i_paranoia_overlap_f(int16_t *buffA,int16_t *buffB, + long offsetA, long offsetB, + long sizeA,long sizeB) +{ + long endA=offsetA; + long endB=offsetB; + + for(;endA or <- */ +void +i_analyze_rift_f(int16_t *A,int16_t *B, + long sizeA, long sizeB, + long aoffset, long boffset, + long *matchA,long *matchB,long *matchC) +{ + + long apast=sizeA-aoffset; + long bpast=sizeB-boffset; + long i; + + *matchA=0, *matchB=0, *matchC=0; + + /* Look for three possible matches... (A) Ariftv->B, (B) Briftv->A and + (c) AB->AB. */ + + for(i=0;;i++){ + if(i=MIN_WORDS_RIFT){ + *matchA=i; + break; + } + + if(i=MIN_WORDS_RIFT){ + *matchB=i; + break; + } + if(i=MIN_WORDS_RIFT){ + *matchC=i; + break; + } + }else + if(i>=bpast)break; + + } + + if(*matchA==0 && *matchB==0 && *matchC==0)return; + + if(*matchC)return; + if(*matchA){ + if(i_stutter_or_gap(A,B,aoffset-*matchA,boffset,*matchA)) + return; + *matchB=-*matchA; /* signify we need to remove n bytes from B */ + *matchA=0; + return; + }else{ + if(i_stutter_or_gap(B,A,boffset-*matchB,aoffset,*matchB)) + return; + *matchA=-*matchB; + *matchB=0; + return; + } +} + +/* riftv must be first even val of rift moving back */ + +void +i_analyze_rift_r(int16_t *A,int16_t *B, + long sizeA, long sizeB, + long aoffset, long boffset, + long *matchA,long *matchB,long *matchC) +{ + + long apast=aoffset+1; + long bpast=boffset+1; + long i; + + *matchA=0, *matchB=0, *matchC=0; + + /* Look for three possible matches... (A) Ariftv->B, (B) Briftv->A and + (c) AB->AB. */ + + for(i=0;;i++){ + if(i=MIN_WORDS_RIFT){ + *matchA=i; + break; + } + if(i=MIN_WORDS_RIFT){ + *matchB=i; + break; + } + if(i=MIN_WORDS_RIFT){ + *matchC=i; + break; + } + }else + if(i>=bpast)break; + + } + + if(*matchA==0 && *matchB==0 && *matchC==0)return; + + if(*matchC)return; + + if(*matchA){ + if(i_stutter_or_gap(A,B,aoffset+1,boffset-*matchA+1,*matchA)) + return; + *matchB=-*matchA; /* signify we need to remove n bytes from B */ + *matchA=0; + return; + }else{ + if(i_stutter_or_gap(B,A,boffset+1,aoffset-*matchB+1,*matchB)) + return; + *matchA=-*matchB; + *matchB=0; + return; + } +} + +void +analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB, + long aoffset, long boffset, + long *matchA, long *matchB) +{ + *matchA=-1; + *matchB=-1; + + sizeA=min(sizeA,aoffset+MIN_WORDS_RIFT); + sizeB=min(sizeB,boffset+MIN_WORDS_RIFT); + + aoffset++; + boffset++; + + while(aoffset + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _GAP_H_ +#define _GAP_H_ + +extern long i_paranoia_overlap_r(int16_t *buffA,int16_t *buffB, + long offsetA, long offsetB); +extern long i_paranoia_overlap_f(int16_t *buffA,int16_t *buffB, + long offsetA, long offsetB, + long sizeA,long sizeB); +extern int i_stutter_or_gap(int16_t *A, int16_t *B,long offA, long offB, + long gap); +extern void i_analyze_rift_f(int16_t *A,int16_t *B, + long sizeA, long sizeB, + long aoffset, long boffset, + long *matchA,long *matchB,long *matchC); +extern void i_analyze_rift_r(int16_t *A,int16_t *B, + long sizeA, long sizeB, + long aoffset, long boffset, + long *matchA,long *matchB,long *matchC); + +extern void analyze_rift_silence_f(int16_t *A,int16_t *B,long sizeA,long sizeB, + long aoffset, long boffset, + long *matchA, long *matchB); +#endif /*_GAP_H*/ diff --git a/lib/paranoia/isort.c b/lib/paranoia/isort.c new file mode 100644 index 00000000..2ed823a5 --- /dev/null +++ b/lib/paranoia/isort.c @@ -0,0 +1,132 @@ +/* + $Id: isort.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/* sorted vector abstraction for paranoia */ + +/* Old isort got a bit complex. This re-constrains complexity to + give a go at speed through a more alpha-6-like mechanism. */ + +#include +#include +#include "p_block.h" +#include "isort.h" + +sort_info *sort_alloc(long size){ + sort_info *ret=calloc(1,sizeof(sort_info)); + + ret->vector=NULL; + ret->sortbegin=-1; + ret->size=-1; + ret->maxsize=size; + + ret->head=calloc(65536,sizeof(sort_link *)); + ret->bucketusage=malloc(65536*sizeof(long)); + ret->revindex=calloc(size,sizeof(sort_link)); + ret->lastbucket=0; + + return(ret); +} + +void sort_unsortall(sort_info *i){ + if(i->lastbucket>2000){ /* a guess */ + memset(i->head,0,65536*sizeof(sort_link *)); + }else{ + long b; + for(b=0;blastbucket;b++) + i->head[i->bucketusage[b]]=NULL; + } + + i->lastbucket=0; + i->sortbegin=-1; +} + +void sort_free(sort_info *i){ + free(i->revindex); + free(i->head); + free(i->bucketusage); + free(i); +} + +static void sort_sort(sort_info *i,long sortlo,long sorthi){ + long j; + + for(j=sorthi-1;j>=sortlo;j--){ + sort_link **hv=i->head+i->vector[j]+32768; + sort_link *l=i->revindex+j; + + if(*hv==NULL){ + i->bucketusage[i->lastbucket]=i->vector[j]+32768; + i->lastbucket++; + } + l->next=*hv; + *hv=l; + } + i->sortbegin=0; +} + +/* size *must* be less than i->maxsize */ +void sort_setup(sort_info *i,int16_t *vector,long *abspos, + long size,long sortlo,long sorthi){ + if(i->sortbegin!=-1)sort_unsortall(i); + + i->vector=vector; + i->size=size; + i->abspos=abspos; + + i->lo=min(size,max(sortlo-*abspos,0)); + i->hi=max(0,min(sorthi-*abspos,size)); +} + +sort_link * +sort_getmatch(sort_info *i,long post,long overlap,int value) +{ + sort_link *ret; + + if(i->sortbegin==-1)sort_sort(i,i->lo,i->hi); + /* Now we reuse lo and hi */ + + post=max(0,min(i->size,post)); + i->val=value+32768; + i->lo=max(0,post-overlap); /* absolute position */ + i->hi=min(i->size,post+overlap); /* absolute position */ + + ret=i->head[i->val]; + while(ret){ + if(ipos(i,ret)lo){ + ret=ret->next; + }else{ + if(ipos(i,ret)>=i->hi) + ret=NULL; + break; + } + } + /*i->head[i->val]=ret;*/ + return(ret); +} + +sort_link * +sort_nextmatch(sort_info *i,sort_link *prev) +{ + sort_link *ret=prev->next; + + if(!ret || ipos(i,ret)>=i->hi)return(NULL); + return(ret); +} + diff --git a/lib/paranoia/isort.h b/lib/paranoia/isort.h new file mode 100644 index 00000000..6ac98122 --- /dev/null +++ b/lib/paranoia/isort.h @@ -0,0 +1,65 @@ +/* + $Id: isort.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _ISORT_H_ +#define _ISORT_H_ + +typedef struct sort_link{ + struct sort_link *next; +} sort_link; + +typedef struct sort_info{ + int16_t *vector; /* vector (storage doesn't belong to us) */ + + long *abspos; /* pointer for side effects */ + long size; /* vector size */ + + long maxsize; /* maximum vector size */ + + long sortbegin; /* range of contiguous sorted area */ + long lo,hi; /* current post, overlap range */ + int val; /* ...and val */ + + /* sort structs */ + sort_link **head; /* sort buckets (65536) */ + + long *bucketusage; /* of used buckets (65536) */ + long lastbucket; + sort_link *revindex; + +} sort_info; + +extern sort_info *sort_alloc(long size); +extern void sort_unsortall(sort_info *i); +extern void sort_setup(sort_info *i,int16_t *vector,long *abspos,long size, + long sortlo, long sorthi); +extern void sort_free(sort_info *i); +extern sort_link *sort_getmatch(sort_info *i,long post,long overlap,int value); +extern sort_link *sort_nextmatch(sort_info *i,sort_link *prev); + +#define is(i) (i->size) +#define ib(i) (*i->abspos) +#define ie(i) (i->size+*i->abspos) +#define iv(i) (i->vector) +#define ipos(i,l) (l-i->revindex) + +#endif + diff --git a/lib/paranoia/overlap.c b/lib/paranoia/overlap.c new file mode 100644 index 00000000..e0cf6c6d --- /dev/null +++ b/lib/paranoia/overlap.c @@ -0,0 +1,210 @@ +/* + $Id: overlap.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*** + * + * Statistic code and cache management for overlap settings + * + ***/ + +#include +#include +#include +#include +#include "p_block.h" +#include "overlap.h" +#include "isort.h" + +/**** Internal cache management *****************************************/ + +void +paranoia_resetcache(cdrom_paranoia_t *p) +{ + c_block *c=c_first(p); + v_fragment *v; + + while(c){ + free_c_block(c); + c=c_first(p); + } + + v=v_first(p); + while(v){ + free_v_fragment(v); + v=v_first(p); + } +} + +void +paranoia_resetall(cdrom_paranoia_t *p) +{ + p->root.returnedlimit=0; + p->dyndrift=0; + p->root.lastsector=0; + + if(p->root.vector){ + i_cblock_destructor(p->root.vector); + p->root.vector=NULL; + } + + paranoia_resetcache(p); +} + +void +i_paranoia_trim(cdrom_paranoia_t *p, long int beginword, long int endword) +{ + root_block *root=&(p->root); + if(root->vector!=NULL){ + long target=beginword-MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; + long rbegin=cb(root->vector); + long rend=ce(root->vector); + + if(rbegin>beginword) + goto rootfree; + + if(rbegin+MAX_SECTOR_OVERLAP*CD_FRAMEWORDSrend) + goto rootfree; + + { + long int offset=target-rbegin; + c_removef(root->vector,offset); + } + } + + { + c_block *c=c_first(p); + while(c){ + c_block *next=c_next(c); + if(ce(c)vector); + root->vector=NULL; + root->returnedlimit=-1; + root->lastsector=0; + +} + +/**** Statistical and heuristic[al? :-] management ************************/ + +void +offset_adjust_settings(cdrom_paranoia_t *p, + void(*callback)(long int, paranoia_cb_mode_t)) +{ + if(p->stage2.offpoints>=10){ + /* drift: look at the average offset value. If it's over one + sector, frob it. We just want a little hysteresis [sp?]*/ + long av=(p->stage2.offpoints?p->stage2.offaccum/p->stage2.offpoints:0); + + if(abs(av)>p->dynoverlap/4){ + av=(av/MIN_SECTOR_EPSILON)*MIN_SECTOR_EPSILON; + + if(callback)(*callback)(ce(p->root.vector),PARANOIA_CB_DRIFT); + p->dyndrift+=av; + + /* Adjust all the values in the cache otherwise we get a + (potentially unstable) feedback loop */ + { + c_block *c=c_first(p); + v_fragment *v=v_first(p); + + while(v && v->one){ + /* safeguard beginning bounds case with a hammer */ + if(fb(v)one)one=NULL; + }else{ + fb(v)-=av; + } + v=v_next(v); + } + while(c){ + long adj=min(av,cb(c)); + c_set(c,cb(c)-adj); + c=c_next(c); + } + } + + p->stage2.offaccum=0; + p->stage2.offmin=0; + p->stage2.offmax=0; + p->stage2.offpoints=0; + p->stage2.newpoints=0; + p->stage2.offdiff=0; + } + } + + if(p->stage1.offpoints>=10){ + /* dynoverlap: we arbitrarily set it to 4x the running difference + value, unless min/max are more */ + + p->dynoverlap=(p->stage1.offpoints?p->stage1.offdiff/ + p->stage1.offpoints*3:CD_FRAMEWORDS); + + if(p->dynoverlap<-p->stage1.offmin*1.5) + p->dynoverlap=-p->stage1.offmin*1.5; + + if(p->dynoverlapstage1.offmax*1.5) + p->dynoverlap=p->stage1.offmax*1.5; + + if(p->dynoverlapdynoverlap=MIN_SECTOR_EPSILON; + if(p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS) + p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; + + if(callback)(*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP); + + if(p->stage1.offpoints>600){ /* bit of a bug; this routine is + called too often due to the overlap + mesh alg we use in stage 1 */ + p->stage1.offpoints/=1.2; + p->stage1.offaccum/=1.2; + p->stage1.offdiff/=1.2; + } + p->stage1.offmin=0; + p->stage1.offmax=0; + p->stage1.newpoints=0; + } +} + +void +offset_add_value(cdrom_paranoia_t *p,offsets *o,long value, + void(*callback)(long int, paranoia_cb_mode_t)) +{ + if(o->offpoints!=-1){ + + o->offdiff+=abs(value); + o->offpoints++; + o->newpoints++; + o->offaccum+=value; + if(valueoffmin)o->offmin=value; + if(value>o->offmax)o->offmax=value; + + if(o->newpoints>=10)offset_adjust_settings(p,callback); + } +} + diff --git a/lib/paranoia/overlap.h b/lib/paranoia/overlap.h new file mode 100644 index 00000000..d772da9c --- /dev/null +++ b/lib/paranoia/overlap.h @@ -0,0 +1,34 @@ +/* + $Id: overlap.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _OVERLAP_H_ +#define _OVERLAP_H_ + +extern void offset_add_value(cdrom_paranoia_t *p,offsets *o,long value, + void(*callback)(long int, paranoia_cb_mode_t)); +extern void offset_clear_settings(offsets *o); +extern void offset_adjust_settings(cdrom_paranoia_t *p, + void(*callback)(long, paranoia_cb_mode_t)); +extern void i_paranoia_trim(cdrom_paranoia_t *p,long beginword,long endword); +extern void paranoia_resetall(cdrom_paranoia_t *p); +extern void paranoia_resetcache(cdrom_paranoia_t *p); + +#endif /*_OVERLAP_H_*/ diff --git a/lib/paranoia/p_block.c b/lib/paranoia/p_block.c new file mode 100644 index 00000000..5546e826 --- /dev/null +++ b/lib/paranoia/p_block.c @@ -0,0 +1,402 @@ +/* + $Id: p_block.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include "p_block.h" +#include +#include + +linked_list *new_list(void *(*newp)(void),void (*freep)(void *)) +{ + linked_list *ret=calloc(1,sizeof(linked_list)); + ret->new_poly=newp; + ret->free_poly=freep; + return(ret); +} + +linked_element *add_elem(linked_list *l,void *elem) +{ + + linked_element *ret=calloc(1,sizeof(linked_element)); + ret->stamp=l->current++; + ret->ptr=elem; + ret->list=l; + + if(l->head) + l->head->prev=ret; + else + l->tail=ret; + ret->next=l->head; + ret->prev=NULL; + l->head=ret; + l->active++; + + return(ret); +} + +linked_element * +new_elem(linked_list *list) +{ + void *new=list->new_poly(); + return(add_elem(list,new)); +} + +void +free_elem(linked_element *e,int free_ptr) +{ + linked_list *l=e->list; + if(free_ptr)l->free_poly(e->ptr); + + if(e==l->head) + l->head=e->next; + if(e==l->tail) + l->tail=e->prev; + + if(e->prev) + e->prev->next=e->next; + if(e->next) + e->next->prev=e->prev; + + l->active--; + free(e); +} + +void +free_list(linked_list *list,int free_ptr) +{ + while(list->head) + free_elem(list->head,free_ptr); + free(list); +} + +void *get_elem(linked_element *e) +{ + return(e->ptr); +} + +linked_list *copy_list(linked_list *list) +{ + linked_list *new=new_list(list->new_poly,list->free_poly); + linked_element *i=list->tail; + + while(i){ + add_elem(new,i->ptr); + i=i->prev; + } + return(new); +} + +/**** C_block stuff ******************************************************/ + +static c_block * +i_cblock_constructor(cdrom_paranoia_t *p) +{ + c_block *ret=calloc(1,sizeof(c_block)); + return(ret); +} + +void +i_cblock_destructor(c_block *c) +{ + if(c){ + if(c->vector)free(c->vector); + if(c->flags)free(c->flags); + c->e=NULL; + free(c); + } +} + +c_block * +new_c_block(cdrom_paranoia_t *p) +{ + linked_element *e=new_elem(p->cache); + c_block *c=e->ptr; + c->e=e; + c->p=p; + return(c); +} + +void free_c_block(c_block *c) +{ + /* also rid ourselves of v_fragments that reference this block */ + v_fragment *v=v_first(c->p); + + while(v){ + v_fragment *next=v_next(v); + if(v->one==c)free_v_fragment(v); + v=next; + } + + free_elem(c->e,1); +} + +static v_fragment * +i_vfragment_constructor(void) +{ + v_fragment *ret=calloc(1,sizeof(v_fragment)); + return(ret); +} + +static inline void +i_v_fragment_destructor(v_fragment *v) +{ + free(v); +} + +v_fragment * +new_v_fragment(cdrom_paranoia_t *p, c_block *one, + long int begin, long int end, int last) +{ + linked_element *e=new_elem(p->fragments); + v_fragment *b=e->ptr; + + b->e=e; + b->p=p; + + b->one=one; + b->begin=begin; + b->vector=one->vector+begin-one->begin; + b->size=end-begin; + b->lastsector=last; + + return(b); +} + +void free_v_fragment(v_fragment *v) +{ + free_elem(v->e,1); +} + +c_block * +c_first(cdrom_paranoia_t *p) +{ + if(p->cache->head) + return(p->cache->head->ptr); + return(NULL); +} + +c_block * +c_last(cdrom_paranoia_t *p) +{ + if(p->cache->tail) + return(p->cache->tail->ptr); + return(NULL); +} + +c_block * +c_next(c_block *c) +{ + if(c->e->next) + return(c->e->next->ptr); + return(NULL); +} + +c_block * +c_prev(c_block *c) +{ + if(c->e->prev) + return(c->e->prev->ptr); + return(NULL); +} + +v_fragment * +v_first(cdrom_paranoia_t *p) +{ + if(p->fragments->head){ + return(p->fragments->head->ptr); + } + return(NULL); +} + +v_fragment * +v_last(cdrom_paranoia_t *p) +{ + if(p->fragments->tail) + return(p->fragments->tail->ptr); + return(NULL); +} + +v_fragment * +v_next(v_fragment *v) +{ + if(v->e->next) + return(v->e->next->ptr); + return(NULL); +} + +v_fragment * +v_prev(v_fragment *v) +{ + if(v->e->prev) + return(v->e->prev->ptr); + return(NULL); +} + +void +recover_cache(cdrom_paranoia_t *p) +{ + linked_list *l=p->cache; + + /* Are we at/over our allowed cache size? */ + while(l->active>p->cache_limit) + /* cull from the tail of the list */ + free_c_block(c_last(p)); + +} + +int16_t * +v_buffer(v_fragment *v) +{ + if(!v->one)return(NULL); + if(!cv(v->one))return(NULL); + return(v->vector); +} + +/* alloc a c_block not on a cache list */ +c_block * +c_alloc(int16_t *vector,long begin,long size) +{ + c_block *c=calloc(1,sizeof(c_block)); + c->vector=vector; + c->begin=begin; + c->size=size; + return(c); +} + +void c_set(c_block *v,long begin){ + v->begin=begin; +} + +/* pos here is vector position from zero */ +void c_insert(c_block *v,long pos,int16_t *b,long size) +{ + int vs=cs(v); + if(pos<0 || pos>vs)return; + + if(v->vector) + v->vector=realloc(v->vector,sizeof(int16_t)*(size+vs)); + else + v->vector=malloc(sizeof(int16_t)*size); + + if(posvector+pos+size,v->vector+pos, + (vs-pos)*sizeof(int16_t)); + memcpy(v->vector+pos,b,size*sizeof(int16_t)); + + v->size+=size; +} + +void c_remove(c_block *v,long cutpos,long cutsize) +{ + int vs=cs(v); + if(cutpos<0 || cutpos>vs)return; + if(cutpos+cutsize>vs)cutsize=vs-cutpos; + if(cutsize<0)cutsize=vs-cutpos; + if(cutsize<1)return; + + memmove(v->vector+cutpos,v->vector+cutpos+cutsize, + (vs-cutpos-cutsize)*sizeof(int16_t)); + + v->size-=cutsize; +} + +void c_overwrite(c_block *v,long pos,int16_t *b,long size){ + int vs=cs(v); + + if(pos<0)return; + if(pos+size>vs)size=vs-pos; + + memcpy(v->vector+pos,b,size*sizeof(int16_t)); +} + +void +c_append(c_block *v, int16_t *vector, long size) +{ + int vs=cs(v); + + /* update the vector */ + if(v->vector) + v->vector=realloc(v->vector,sizeof(int16_t)*(size+vs)); + else + v->vector=malloc(sizeof(int16_t)*size); + memcpy(v->vector+vs,vector,sizeof(int16_t)*size); + + v->size+=size; +} + +void c_removef(c_block *v, long cut){ + c_remove(v,0,cut); + v->begin+=cut; +} + + + +/**** Initialization *************************************************/ + +void +i_paranoia_firstlast(cdrom_paranoia_t *p) +{ + int i; + cdrom_drive_t *d=p->d; + p->current_lastsector=-1; + for(i=cdda_sector_gettrack(d,p->cursor);icurrent_lastsector=cdda_track_lastsector(d,i-1); + if(p->current_lastsector==-1) + p->current_lastsector=cdda_disc_lastsector(d); + + p->current_firstsector=-1; + for(i=cdda_sector_gettrack(d,p->cursor);i>0;i--) + if(!cdda_track_audiop(d,i)) + p->current_firstsector=cdda_track_firstsector(d,i+1); + if(p->current_firstsector==-1) + p->current_firstsector=cdda_disc_firstsector(d); + +} + +cdrom_paranoia_t * +paranoia_init(cdrom_drive_t *d) +{ + cdrom_paranoia_t *p=calloc(1,sizeof(cdrom_paranoia_t)); + + p->cache=new_list((void *)&i_cblock_constructor, + (void *)&i_cblock_destructor); + + p->fragments=new_list((void *)&i_vfragment_constructor, + (void *)&i_v_fragment_destructor); + + p->readahead=150; + p->sortcache=sort_alloc(p->readahead*CD_FRAMEWORDS); + p->d=d; + p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; + p->cache_limit=JIGGLE_MODULO; + p->enable=PARANOIA_MODE_FULL; + p->cursor=cdda_disc_firstsector(d); + p->lastread=LONG_MAX; + + /* One last one... in case data and audio tracks are mixed... */ + i_paranoia_firstlast(p); + + return(p); +} + diff --git a/lib/paranoia/p_block.h b/lib/paranoia/p_block.h new file mode 100644 index 00000000..f62e0c65 --- /dev/null +++ b/lib/paranoia/p_block.h @@ -0,0 +1,208 @@ +/* + $Id: p_block.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) by Monty (xiphmont@mit.edu) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _P_BLOCK_H_ +#define _P_BLOCK_H_ + +#include +#include + +#define MIN_WORDS_OVERLAP 64 /* 16 bit words */ +#define MIN_WORDS_SEARCH 64 /* 16 bit words */ +#define MIN_WORDS_RIFT 16 /* 16 bit words */ +#define MAX_SECTOR_OVERLAP 32 /* sectors */ +#define MIN_SECTOR_EPSILON 128 /* words */ +#define MIN_SECTOR_BACKUP 16 /* sectors */ +#define JIGGLE_MODULO 15 /* sectors */ +#define MIN_SILENCE_BOUNDARY 1024 /* 16 bit words */ + +#define min(x,y) ((x)>(y)?(y):(x)) +#define max(x,y) ((x)<(y)?(y):(x)) + +#include "isort.h" + +typedef struct linked_list{ + /* linked list */ + struct linked_element *head; + struct linked_element *tail; + + void *(*new_poly)(); + void (*free_poly)(void *poly); + long current; + long active; + +} linked_list; + +typedef struct linked_element{ + void *ptr; + struct linked_element *prev; + struct linked_element *next; + + struct linked_list *list; + int stamp; +} linked_element; + +extern linked_list *new_list(void *(*new)(void),void (*free)(void *)); +extern linked_element *new_elem(linked_list *list); +extern linked_element *add_elem(linked_list *list,void *elem); +extern void free_list(linked_list *list,int free_ptr); /* unlink or free */ +extern void free_elem(linked_element *e,int free_ptr); /* unlink or free */ +extern void *get_elem(linked_element *e); +extern linked_list *copy_list(linked_list *list); /* shallow; doesn't copy + contained structures */ + +typedef struct c_block{ + /* The buffer */ + int16_t *vector; + long begin; + long size; + + /* auxiliary support structures */ + unsigned char *flags; /* 1 known boundaries in read data + 2 known blanked data + 4 matched sample + 8 reserved + 16 reserved + 32 reserved + 64 reserved + 128 reserved + */ + + /* end of session cases */ + long lastsector; + cdrom_paranoia_t *p; + struct linked_element *e; + +} c_block; + +extern void free_c_block(c_block *c); +extern void i_cblock_destructor(c_block *c); +extern c_block *new_c_block(cdrom_paranoia_t *p); + +typedef struct v_fragment{ + c_block *one; + + long begin; + long size; + int16_t *vector; + + /* end of session cases */ + long lastsector; + + /* linked list */ + cdrom_paranoia_t *p; + struct linked_element *e; + +} v_fragment; + +extern void free_v_fragment(v_fragment *c); +extern v_fragment *new_v_fragment(cdrom_paranoia_t *p, c_block *one, + long int begin, long int end, + int lastsector); +extern int16_t *v_buffer(v_fragment *v); + +extern c_block *c_first(cdrom_paranoia_t *p); +extern c_block *c_last(cdrom_paranoia_t *p); +extern c_block *c_next(c_block *c); +extern c_block *c_prev(c_block *c); + +extern v_fragment *v_first(cdrom_paranoia_t *p); +extern v_fragment *v_last(cdrom_paranoia_t *p); +extern v_fragment *v_next(v_fragment *v); +extern v_fragment *v_prev(v_fragment *v); + +typedef struct root_block{ + long returnedlimit; + long lastsector; + cdrom_paranoia_t *p; + + c_block *vector; /* doesn't use any sorting */ + int silenceflag; + long silencebegin; +} root_block; + +typedef struct offsets{ + + long offpoints; + long newpoints; + long offaccum; + long offdiff; + long offmin; + long offmax; + +} offsets; + +struct cdrom_paranoia_s { + cdrom_drive_t *d; + + root_block root; /* verified/reconstructed cached data */ + linked_list *cache; /* our data as read from the cdrom */ + long int cache_limit; + linked_list *fragments; /* fragments of blocks that have been 'verified' */ + sort_info *sortcache; + + int readahead; /* sectors of readahead in each readop */ + int jitter; + long lastread; + + paranoia_cb_mode_t enable; + long int cursor; + long int current_lastsector; + long int current_firstsector; + + /* statistics for drift/overlap */ + struct offsets stage1; + struct offsets stage2; + + long dynoverlap; + long dyndrift; + + /* statistics for verification */ + +}; + +extern c_block *c_alloc(int16_t *vector,long begin,long size); +extern void c_set(c_block *v,long begin); +extern void c_insert(c_block *v,long pos,int16_t *b,long size); +extern void c_remove(c_block *v,long cutpos,long cutsize); +extern void c_overwrite(c_block *v,long pos,int16_t *b,long size); +extern void c_append(c_block *v, int16_t *vector, long size); +extern void c_removef(c_block *v, long cut); + +#define ce(v) (v->begin+v->size) +#define cb(v) (v->begin) +#define cs(v) (v->size) + +/* pos here is vector position from zero */ + +extern void recover_cache(cdrom_paranoia_t *p); +extern void i_paranoia_firstlast(cdrom_paranoia_t *p); + +#define cv(c) (c->vector) + +#define fe(f) (f->begin+f->size) +#define fb(f) (f->begin) +#define fs(f) (f->size) +#define fv(f) (v_buffer(f)) + +#define CDP_COMPILE +#endif /*_P_BLOCK_H_*/ + diff --git a/lib/paranoia/paranoia.c b/lib/paranoia/paranoia.c new file mode 100644 index 00000000..a88b9e19 --- /dev/null +++ b/lib/paranoia/paranoia.c @@ -0,0 +1,1399 @@ +/* + $Id: paranoia.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/*** + * Toplevel file for the paranoia abstraction over the cdda lib + * + ***/ + +/* immediate todo:: */ +/* Allow disabling of root fixups? */ +/* Dupe bytes are creeping into cases that require greater overlap + than a single fragment can provide. We need to check against a + larger area* (+/-32 sectors of root?) to better eliminate + dupes. Of course this leads to other problems... Is it actually a + practically solvable problem? */ +/* Bimodal overlap distributions break us. */ +/* scratch detection/tolerance not implemented yet */ + +/*************************************************************** + + Da new shtick: verification now a two-step assymetric process. + + A single 'verified/reconstructed' data segment cache, and then the + multiple fragment cache + + verify a newly read block against previous blocks; do it only this + once. We maintain a list of 'verified sections' from these matches. + + We then glom these verified areas into a new data buffer. + Defragmentation fixups are allowed here alone. + + We also now track where read boundaries actually happened; do not + verify across matching boundaries. + + **************************************************************/ + +/*************************************************************** + + Silence. "It's BAAAAAAaaack." + + audio is now treated as great continents of values floating on a + mantle of molten silence. Silence is not handled by basic + verification at all; we simply anchor sections of nonzero audio to a + position and fill in everything else as silence. We also note the + audio that interfaces with silence; an edge must be 'wet'. + + **************************************************************/ + +#include +#include +#include +#include +#include +#include +#include "../cdda_interface/smallft.h" +#include "p_block.h" +#include +#include "overlap.h" +#include "gap.h" +#include "isort.h" + +static inline long +re(root_block *root) +{ + if(!root)return(-1); + if(!root->vector)return(-1); + return(ce(root->vector)); +} + +static inline long +rb(root_block *root) +{ + if(!root)return(-1); + if(!root->vector)return(-1); + return(cb(root->vector)); +} + +static inline +long rs(root_block *root) +{ + if(!root)return(-1); + if(!root->vector)return(-1); + return(cs(root->vector)); +} + +static inline int16_t * +rv(root_block *root){ + if(!root)return(NULL); + if(!root->vector)return(NULL); + return(cv(root->vector)); +} + +#define rc(r) (r->vector) + +/**** matching and analysis code *****************************************/ + +static inline long +i_paranoia_overlap(int16_t *buffA,int16_t *buffB, + long offsetA, long offsetB, + long sizeA,long sizeB, + long *ret_begin, long *ret_end) +{ + long beginA=offsetA,endA=offsetA; + long beginB=offsetB,endB=offsetB; + + for(;beginA>=0 && beginB>=0;beginA--,beginB--) + if(buffA[beginA]!=buffB[beginB])break; + beginA++; + beginB++; + + for(;endA=0 && beginB>=0;beginA--,beginB--){ + if(buffA[beginA]!=buffB[beginB])break; + /* don't allow matching across matching sector boundaries */ + /* don't allow matching through known missing data */ + if((flagsA[beginA]&flagsB[beginB]&1)){ + beginA--; + beginB--; + break; + } + if((flagsA[beginA]&2)|| (flagsB[beginB]&2))break; + } + beginA++; + beginB++; + + for(;endAflags; + long ret=0; + + if(flagB==NULL) + ret=i_paranoia_overlap(cv(A),iv(B),posA,posB, + cs(A),is(B),begin,end); + else + if((flagB[posB]&2)==0) + ret=i_paranoia_overlap2(cv(A),iv(B),flagA,flagB,posA,posB,cs(A), + is(B),begin,end); + + if(ret>MIN_WORDS_SEARCH){ + *offset=+(posA+cb(A))-(posB+ib(B)); + *begin+=cb(A); + *end+=cb(A); + return(ret); + } + + return(0); +} + +/* post is w.r.t. B. in stage one, we post from old. In stage 2 we + post from root. Begin, end, offset count from B's frame of + reference */ + +static inline long int +try_sort_sync(cdrom_paranoia_t *p, + sort_info *A,char *Aflags, + c_block *B, + long int post, + long int *begin, + long int *end, + long *offset, + void (*callback)(long int, paranoia_cb_mode_t)) +{ + + long dynoverlap=p->dynoverlap; + sort_link *ptr=NULL; + char *Bflags=B->flags; + + /* block flag matches 0x02 (unmatchable) */ + if(Bflags==NULL || (Bflags[post-cb(B)]&2)==0){ + /* always try absolute offset zero first! */ + { + long zeropos=post-ib(A); + if(zeropos>=0 && zeroposstage1),*offset,callback); + + return(1); + } + } + } + } + } else + return(0); + + ptr=sort_getmatch(A,post-ib(A),dynoverlap,cv(B)[post-cb(B)]); + + while(ptr){ + + if(do_const_sync(B,A,Aflags, + post-cb(B),ipos(A,ptr), + begin,end,offset)){ + offset_add_value(p,&(p->stage1),*offset,callback); + return(1); + } + ptr=sort_nextmatch(A,ptr); + } + + *begin=-1; + *end=-1; + *offset=-1; + return(0); +} + +static inline void +stage1_matched(c_block *old,c_block *new, + long matchbegin,long matchend, + long matchoffset, + void (*callback)(long int, paranoia_cb_mode_t)) +{ + long i; + long oldadjbegin=matchbegin-cb(old); + long oldadjend=matchend-cb(old); + long newadjbegin=matchbegin-matchoffset-cb(new); + long newadjend=matchend-matchoffset-cb(new); + + if (matchbegin-matchoffset<=cb(new) || + matchbegin<=cb(old) || + (new->flags[newadjbegin]&1) || + (old->flags[oldadjbegin]&1)) { + if(matchoffset) + if(callback)(*callback)(matchbegin,PARANOIA_CB_FIXUP_EDGE); + } else + if(callback)(*callback)(matchbegin,PARANOIA_CB_FIXUP_ATOM); + + if(matchend-matchoffset>=ce(new) || + (new->flags[newadjend]&1) || + matchend>=ce(old) || + (old->flags[oldadjend]&1)){ + if(matchoffset) + if(callback)(*callback)(matchend,PARANOIA_CB_FIXUP_EDGE); + }else + if (callback) + (*callback)(matchend, PARANOIA_CB_FIXUP_ATOM); + + /* Mark the verification flags. Don't mark the first or + last OVERLAP/2 elements so that overlapping fragments + have to overlap by OVERLAP to actually merge. We also + remove elements from the sort such that later sorts do + not have to sift through already matched data */ + + newadjbegin+=OVERLAP_ADJ; + newadjend-=OVERLAP_ADJ; + for(i=newadjbegin;iflags[i]|=4; /* mark verified */ + + oldadjbegin+=OVERLAP_ADJ; + oldadjend-=OVERLAP_ADJ; + for(i=oldadjbegin;iflags[i]|=4; /* mark verified */ + +} + +static long int +i_iterate_stage1(cdrom_paranoia_t *p, c_block *old, c_block *new, + void(*callback)(long int, paranoia_cb_mode_t)) +{ + + long matchbegin=-1,matchend=-1,matchoffset; + + /* we no longer try to spread the stage one search area by dynoverlap */ + long searchend=min(ce(old),ce(new)); + long searchbegin=max(cb(old),cb(new)); + long searchsize=searchend-searchbegin; + sort_info *i=p->sortcache; + long ret=0; + long j; + + long tried=0,matched=0; + + if(searchsize<=0)return(0); + + /* match return values are in terms of the new vector, not old */ + + for(j=searchbegin;jflags[j-cb(new)]&6)==0){ + tried++; + if(try_sort_sync(p,i,new->flags,old,j,&matchbegin,&matchend,&matchoffset, + callback)==1){ + + matched+=matchend-matchbegin; + + /* purely cosmetic: if we're matching zeros, don't use the + callback because they will appear to be all skewed */ + { + long j=matchbegin-cb(old); + long end=matchend-cb(old); + for(;jj)j=matchend-1; + } + } + } +#ifdef NOISY + fprintf(stderr,"iterate_stage1: search area=%ld[%ld-%ld] tried=%ld matched=%ld spans=%ld\n", + searchsize,searchbegin,searchend,tried,matched,ret); +#endif + + return(ret); +} + +static long int +i_stage1(cdrom_paranoia_t *p, c_block *new, + void (*callback)(long int, paranoia_cb_mode_t)) +{ + long size=cs(new); + c_block *ptr=c_last(p); + int ret=0; + long begin=0,end; + + if(ptr)sort_setup(p->sortcache,cv(new),&cb(new),cs(new), + cb(new),ce(new)); + + while(ptr && ptr!=new){ + + if(callback)(*callback)(cb(new),PARANOIA_CB_VERIFY); + i_iterate_stage1(p,ptr,new,callback); + + ptr=c_prev(ptr); + } + + /* parse the verified areas of new into v_fragments */ + + begin=0; + while(beginflags[begin]&4)break; + for(end=begin;endflags[end]&4)==0)break; + if(begin>=size)break; + + ret++; + + new_v_fragment(p,new,cb(new)+max(0,begin-OVERLAP_ADJ), + cb(new)+min(size,end+OVERLAP_ADJ), + (end+OVERLAP_ADJ>=size && new->lastsector)); + + begin=end; + } + + return(ret); +} + +/* reconcile v_fragments to root buffer. Free if matched, fragment/fixup root + if necessary */ + +typedef struct sync_result { + long offset; + long begin; + long end; +} sync_result; + +/* do *not* match using zero posts */ +static long int +i_iterate_stage2(cdrom_paranoia_t *p, + v_fragment *v, + sync_result *r, + void(*callback)(long int, paranoia_cb_mode_t)) +{ + root_block *root=&(p->root); + long matchbegin=-1,matchend=-1,offset; + long fbv,fev; + +#ifdef NOISY + fprintf(stderr,"Stage 2 search: fbv=%ld fev=%ld\n",fb(v),fe(v)); +#endif + + if(min(fe(v)+p->dynoverlap,re(root))- + max(fb(v)-p->dynoverlap,rb(root))<=0)return(0); + + if(callback)(*callback)(fb(v),PARANOIA_CB_VERIFY); + + /* just a bit of v; determine the correct area */ + fbv=max(fb(v),rb(root)-p->dynoverlap); + + /* we want to avoid zeroes */ + while(fbvdynoverlap),fe(v)); + + { + /* spread the search area a bit. We post from root, so containment + must strictly adhere to root */ + long searchend=min(fev+p->dynoverlap,re(root)); + long searchbegin=max(fbv-p->dynoverlap,rb(root)); + sort_info *i=p->sortcache; + long j; + + sort_setup(i,fv(v),&fb(v),fs(v),fbv,fev); + for(j=searchbegin;jbegin=matchbegin; + r->end=matchend; + r->offset=-offset; + if(offset)if(callback)(*callback)(r->begin,PARANOIA_CB_FIXUP_EDGE); + return(1); + } + } + } + + return(0); +} + +/* simple test for a root vector that ends in silence*/ +static void +i_silence_test(root_block *root) +{ + int16_t *vec=rv(root); + long end=re(root)-rb(root)-1; + long j; + + for(j=end-1;j>=0;j--)if(vec[j]!=0)break; + if(j<0 || end-j>MIN_SILENCE_BOUNDARY){ + if(j<0)j=0; + root->silenceflag=1; + root->silencebegin=rb(root)+j; + if(root->silencebeginreturnedlimit) + root->silencebegin=root->returnedlimit; + } +} + +/* match into silence vectors at offset zero if at all possible. This + also must be called with vectors in ascending begin order in case + there are nonzero islands */ +static long int +i_silence_match(root_block *root, v_fragment *v, + void(*callback)(long int, paranoia_cb_mode_t)) +{ + + cdrom_paranoia_t *p=v->p; + int16_t *vec=fv(v); + long end=fs(v),begin; + long j; + + /* does this vector begin wet? */ + if(enddynoverlap? */ + if(fb(v)>=re(root) && fb(v)-p->dynoverlapsilencebegin); + end=min(j,re(root)); + + if(beginre(root)){ + long voff=begin-fb(v); + + c_remove(rc(root),begin-rb(root),-1); + c_append(rc(root),vec+voff,fs(v)-voff); + } + offset_add_value(p,&p->stage2,0,callback); + + }else{ + if(jre(root)){ + c_remove(rc(root),root->silencebegin-rb(root),-1); + c_append(rc(root),vec+voff,fs(v)-voff); + } + offset_add_value(p,&p->stage2,end-begin,callback); + }else + return(0); + } + + /* test the new root vector for ending in silence */ + root->silenceflag=0; + i_silence_test(root); + + if(v->lastsector)root->lastsector=1; + free_v_fragment(v); + return(1); +} + +static long int +i_stage2_each(root_block *root, v_fragment *v, + void(*callback)(long int, paranoia_cb_mode_t)) +{ + + cdrom_paranoia_t *p=v->p; + long dynoverlap=p->dynoverlap/2*2; + + if(!v || !v->one)return(0); + + if(!rv(root)){ + return(0); + }else{ + sync_result r; + + if(i_iterate_stage2(p,v,&r,callback)){ + + long begin=r.begin-rb(root); + long end=r.end-rb(root); + long offset=r.begin+r.offset-fb(v)-begin; + long temp; + c_block *l=NULL; + + /* we have a match! We don't rematch off rift, we chase the + match all the way to both extremes doing rift analysis. */ + +#ifdef NOISY + fprintf(stderr,"Stage 2 match\n"); +#endif + + /* chase backward */ + /* note that we don't extend back right now, only forward. */ + while((begin+offset>0 && begin>0)){ + long matchA=0,matchB=0,matchC=0; + long beginL=begin+offset; + + if(l==NULL){ + int16_t *buff=malloc(fs(v)*sizeof(int16_t)); + l=c_alloc(buff,fb(v),fs(v)); + memcpy(buff,fv(v),fs(v)*sizeof(int16_t)); + } + + i_analyze_rift_r(rv(root),cv(l), + rs(root),cs(l), + begin-1,beginL-1, + &matchA,&matchB,&matchC); + +#ifdef NOISY + fprintf(stderr,"matching rootR: matchA:%ld matchB:%ld matchC:%ld\n", + matchA,matchB,matchC); +#endif + + if(matchA){ + /* a problem with root */ + if(matchA>0){ + /* dropped bytes; add back from v */ + if(callback)(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED); + if(rb(root)+beginroot.returnedlimit) + break; + else{ + c_insert(rc(root),begin,cv(l)+beginL-matchA, + matchA); + offset-=matchA; + begin+=matchA; + end+=matchA; + } + }else{ + /* duplicate bytes; drop from root */ + if(callback)(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED); + if(rb(root)+begin+matchAroot.returnedlimit) + break; + else{ + c_remove(rc(root),begin+matchA,-matchA); + offset-=matchA; + begin+=matchA; + end+=matchA; + } + } + }else if(matchB){ + /* a problem with the fragment */ + if(matchB>0){ + /* dropped bytes */ + if(callback)(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED); + c_insert(l,beginL,rv(root)+begin-matchB, + matchB); + offset+=matchB; + }else{ + /* duplicate bytes */ + if(callback)(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED); + c_remove(l,beginL+matchB,-matchB); + offset+=matchB; + } + }else if(matchC){ + /* Uhh... problem with both */ + + /* Set 'disagree' flags in root */ + if(rb(root)+begin-matchCroot.returnedlimit) + break; + c_overwrite(rc(root),begin-matchC, + cv(l)+beginL-matchC,matchC); + + }else{ + /* do we have a mismatch due to silence beginning/end case? */ + /* in the 'chase back' case, we don't do anything. */ + + /* Did not determine nature of difficulty... + report and bail */ + + /*RRR(*callback)(post,PARANOIA_CB_XXX);*/ + break; + } + /* not the most efficient way, but it will do for now */ + beginL=begin+offset; + i_paranoia_overlap(rv(root),cv(l), + begin,beginL, + rs(root),cs(l), + &begin,&end); + } + + /* chase forward */ + temp=l?cs(l):fs(v); + while(end+offset0){ + /* dropped bytes; add back from v */ + if(callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED); + if(end+rb(root)root.returnedlimit) + break; + c_insert(rc(root),end,cv(l)+endL,matchA); + }else{ + /* duplicate bytes; drop from root */ + if(callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED); + if(end+rb(root)root.returnedlimit) + break; + c_remove(rc(root),end,-matchA); + } + }else if(matchB){ + /* a problem with the fragment */ + if(matchB>0){ + /* dropped bytes */ + if(callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED); + c_insert(l,endL,rv(root)+end,matchB); + }else{ + /* duplicate bytes */ + if(callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED); + c_remove(l,endL,-matchB); + } + }else if(matchC){ + /* Uhh... problem with both */ + + /* Set 'disagree' flags in root */ + if(end+rb(root)root.returnedlimit) + break; + c_overwrite(rc(root),end,cv(l)+endL,matchC); + }else{ + analyze_rift_silence_f(rv(root),cv(l), + rs(root),cs(l), + end,endL, + &matchA,&matchB); + if(matchA){ + /* silence in root */ + /* Can only do this if we haven't already returned data */ + if(end+rb(root)>=p->root.returnedlimit){ + c_remove(rc(root),end,-1); + } + + }else if(matchB){ + /* silence in fragment; lose it */ + + if(l)i_cblock_destructor(l); + free_v_fragment(v); + return(1); + + }else{ + /* Could not determine nature of difficulty... + report and bail */ + + /*RRR(*callback)(post,PARANOIA_CB_XXX);*/ + } + break; + } + /* not the most efficient way, but it will do for now */ + i_paranoia_overlap(rv(root),cv(l), + begin,beginL, + rs(root),cs(l), + NULL,&end); + } + + /* if this extends our range, let's glom */ + { + long sizeA=rs(root); + long sizeB; + long vecbegin; + int16_t *vector; + + if(l){ + sizeB=cs(l); + vector=cv(l); + vecbegin=cb(l); + }else{ + sizeB=fs(v); + vector=fv(v); + vecbegin=fb(v); + } + + if(sizeB-offset>sizeA || v->lastsector){ + if(v->lastsector){ + root->lastsector=1; + } + + if(endstage2,offset+vecbegin-rb(root),callback); + } + } + if(l)i_cblock_destructor(l); + free_v_fragment(v); + return(1); + + }else{ + /* D'oh. No match. What to do with the fragment? */ + if(fe(v)+dynoverlapsilenceflag){ + /* It *should* have matched. No good; free it. */ + free_v_fragment(v); + } + /* otherwise, we likely want this for an upcoming match */ + /* we don't free the sort info (if it was collected) */ + return(0); + + } + } +} + +static int +i_init_root(root_block *root, v_fragment *v,long int begin, + void(*callback)(long int, paranoia_cb_mode_t)) +{ + if(fb(v)<=begin && fe(v)>begin){ + + root->lastsector=v->lastsector; + root->returnedlimit=begin; + + if(rv(root)){ + i_cblock_destructor(rc(root)); + rc(root)=NULL; + } + + { + int16_t *buff=malloc(fs(v)*sizeof(int16_t)); + memcpy(buff,fv(v),fs(v)*sizeof(int16_t)); + root->vector=c_alloc(buff,fb(v),fs(v)); + } + + i_silence_test(root); + + return(1); + }else + return(0); +} + +static int +vsort(const void *a,const void *b) +{ + return((*(v_fragment **)a)->begin-(*(v_fragment **)b)->begin); +} + +static int +i_stage2(cdrom_paranoia_t *p, long int beginword, long int endword, + void (*callback)(long int, paranoia_cb_mode_t)) +{ + + int flag=1,ret=0; + root_block *root=&(p->root); + +#ifdef NOISY + fprintf(stderr,"Fragments:%ld\n",p->fragments->active); + fflush(stderr); +#endif + + /* even when the 'silence flag' is lit, we try to do non-silence + matching in the event that there are still audio vectors with + content to be sunk before the silence */ + + while(flag){ + /* loop through all the current fragments */ + v_fragment *first=v_first(p); + long active=p->fragments->active,count=0; + v_fragment *list[active]; + + while(first){ + v_fragment *next=v_next(first); + list[count++]=first; + first=next; + } + + flag=0; + if(count){ + /* sorted in ascending order of beginning */ + qsort(list,active,sizeof(v_fragment *),&vsort); + + /* we try a nonzero based match even if in silent mode in + the case that there are still cached vectors to sink + behind continent->ocean boundary */ + + for(count=0;countone){ + if(rv(root)==NULL){ + if(i_init_root(&(p->root),first,beginword,callback)){ + free_v_fragment(first); + flag=1; + ret++; + } + }else{ + if(i_stage2_each(root,first,callback)){ + ret++; + flag=1; + } + } + } + } + + /* silence handling */ + if(!flag && p->root.silenceflag){ + for(count=0;countone){ + if(rv(root)!=NULL){ + if(i_silence_match(root,first,callback)){ + ret++; + flag=1; + } + } + } + } + } + } + } + return(ret); +} + +static void +i_end_case(cdrom_paranoia_t *p,long endword, + void(*callback)(long int, paranoia_cb_mode_t)) +{ + + root_block *root=&p->root; + + /* have an 'end' flag; if we've just read in the last sector in a + session, set the flag. If we verify to the end of a fragment + which has the end flag set, we're done (set a done flag). Pad + zeroes to the end of the read */ + + if(root->lastsector==0)return; + if(endwordroot); + c_block *graft=NULL; + int vflag=0; + int gend=0; + long post; + +#ifdef NOISY + fprintf(stderr,"\nskipping\n"); +#endif + + if(rv(root)==NULL){ + post=0; + } else { + post=re(root); + } + if(post==-1)post=0; + + if(callback)(*callback)(post,PARANOIA_CB_SKIP); + + /* We want to add a sector. Look for a c_block that spans, + preferrably a verified area */ + + { + c_block *c=c_first(p); + while(c){ + long cbegin=cb(c); + long cend=ce(c); + if(cbegin<=post && cend>post){ + long vend=post; + + if(c->flags[post-cbegin]&4){ + /* verified area! */ + while(vendflags[vend-cbegin]&4))vend++; + if(!vflag || vend>vflag){ + graft=c; + gend=vend; + } + vflag=1; + } else { + /* not a verified area */ + if(!vflag){ + while(vendflags[vend-cbegin]&4)==0)vend++; + if(graft==NULL || gend>vend){ + /* smallest unverified area */ + graft=c; + gend=vend; + } + } + } + } + c=c_next(c); + } + + if(graft){ + long cbegin=cb(graft); + long cend=ce(graft); + + while(gendflags[gend-cbegin]&4))gend++; + gend=min(gend+OVERLAP_ADJ,cend); + + if(rv(root)==NULL){ + int16_t *buff=malloc(cs(graft)); + memcpy(buff,cv(graft),cs(graft)); + rc(root)=c_alloc(buff,cb(graft),cs(graft)); + }else{ + c_append(rc(root),cv(graft)+post-cbegin, + gend-post); + } + + root->returnedlimit=re(root); + return; + } + } + + /* No? Fine. Great. Write in some zeroes :-P */ + { + void *temp=calloc(CDIO_CD_FRAMESIZE_RAW,sizeof(int16_t)); + + if(rv(root)==NULL){ + rc(root)=c_alloc(temp,post,CDIO_CD_FRAMESIZE_RAW); + }else{ + c_append(rc(root),temp,CDIO_CD_FRAMESIZE_RAW); + free(temp); + } + root->returnedlimit=re(root); + } +} + +/**** toplevel ****************************************/ + +void +paranoia_free(cdrom_paranoia_t *p) +{ + paranoia_resetall(p); + sort_free(p->sortcache); + free(p); +} + +void +paranoia_modeset(cdrom_paranoia_t *p, int enable) +{ + p->enable=enable; +} + +lsn_t +paranoia_seek(cdrom_paranoia_t *p, off_t seek, int mode) +{ + long sector; + long ret; + switch(mode){ + case SEEK_SET: + sector=seek; + break; + case SEEK_END: + sector=cdda_disc_lastsector(p->d)+seek; + break; + default: + sector=p->cursor+seek; + break; + } + + if(cdda_sector_gettrack(p->d,sector)==-1)return(-1); + + i_cblock_destructor(p->root.vector); + p->root.vector=NULL; + p->root.lastsector=0; + p->root.returnedlimit=0; + + ret=p->cursor; + p->cursor=sector; + + i_paranoia_firstlast(p); + + /* Evil hack to fix pregap patch for NEC drives! To be rooted out in a10 */ + p->current_firstsector=sector; + + return(ret); +} + +/* returns last block read, -1 on error */ +static c_block * +i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword, + void(*callback)(long, paranoia_cb_mode_t)) +{ + +/* why do it this way? We need to read lots of sectors to kludge + around stupid read ahead buffers on cheap drives, as well as avoid + expensive back-seeking. We also want to 'jiggle' the start address + to try to break borderline drives more noticeably (and make broken + drives with unaddressable sectors behave more often). */ + + long readat,firstread; + long totaltoread=p->readahead; + long sectatonce=p->d->nsectors; + long driftcomp=(float)p->dyndrift/CD_FRAMEWORDS+.5; + c_block *new=NULL; + root_block *root=&p->root; + int16_t *buffer=NULL; + char *flags=NULL; + long sofar; + long dynoverlap=(p->dynoverlap+CD_FRAMEWORDS-1)/CD_FRAMEWORDS; + long anyflag=0; + + /* What is the first sector to read? want some pre-buffer if + we're not at the extreme beginning of the disc */ + + if(p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){ + + /* we want to jitter the read alignment boundary */ + long target; + if(rv(root)==NULL || rb(root)>beginword) + target=p->cursor-dynoverlap; + else + target=re(root)/(CD_FRAMEWORDS)-dynoverlap; + + if(target+MIN_SECTOR_BACKUP>p->lastread && target<=p->lastread) + target=p->lastread-MIN_SECTOR_BACKUP; + + /* we want to jitter the read alignment boundary, as some + drives, beginning from a specific point, will tend to + lose bytes between sectors in the same place. Also, as + our vectors are being made up of multiple reads, we want + the overlap boundaries to move.... */ + + readat=(target&(~((long)JIGGLE_MODULO-1)))+p->jitter; + if(readat>target)readat-=JIGGLE_MODULO; + p->jitter++; + if (p->jitter>=JIGGLE_MODULO) + p->jitter=0; + + } else { + readat=p->cursor; + } + + readat+=driftcomp; + + if (p->enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)) { + flags=calloc(totaltoread*CD_FRAMEWORDS,1); + new=new_c_block(p); + recover_cache(p); + } else { + /* in the case of root it's just the buffer */ + paranoia_resetall(p); + new=new_c_block(p); + } + + buffer=malloc(totaltoread*CDIO_CD_FRAMESIZE_RAW); + sofar=0; + firstread=-1; + + /* actual read loop */ + + while(sofarcurrent_firstsector){ + secread-=p->current_firstsector-adjread; + adjread=p->current_firstsector; + } + if(adjread+secread-1>p->current_lastsector) + secread=p->current_lastsector-adjread+1; + + if(sofar+secread>totaltoread)secread=totaltoread-sofar; + + if (secread>0){ + + if (firstread<0) firstread=adjread; + if ((thisread=cdda_read(p->d,buffer+sofar*CD_FRAMEWORDS,adjread, + secread))lastread=adjread+secread; + + if(adjread+secread-1==p->current_lastsector) + new->lastsector=-1; + + if(callback)(*callback)((adjread+secread-1)*CD_FRAMEWORDS,PARANOIA_CB_READ); + + sofar+=secread; + readat=adjread+secread; + } else + if(readatcurrent_firstsector) + readat+=sectatonce; /* due to being before the readable area */ + else + break; /* due to being past the readable area */ + } + + if (anyflag) { + new->vector=buffer; + new->begin=firstread*CD_FRAMEWORDS-p->dyndrift; + new->size=sofar*CD_FRAMEWORDS; + new->flags=flags; + } else { + if(new)free_c_block(new); + free(buffer); + free(flags); + new=NULL; + } + return(new); +} + +/* The returned buffer is *not* to be freed by the caller. It will + persist only until the next call to paranoia_read() for this p */ + +int16_t * +paranoia_read(cdrom_paranoia_t *p, void(*callback)(long, paranoia_cb_mode_t)) +{ + return paranoia_read_limited(p, callback, 20); +} + +/* I added max_retry functionality this way in order to avoid + breaking any old apps using the nerw libs. cdparanoia 9.8 will + need the updated libs, but nothing else will require it. */ +int16_t * +paranoia_read_limited(cdrom_paranoia_t *p, + void(*callback)(long int, paranoia_cb_mode_t), + int max_retries) +{ + long int beginword = p->cursor*(CD_FRAMEWORDS); + long int endword = beginword+CD_FRAMEWORDS; + long int retry_count= 0; + long int lastend = -2; + root_block *root = &p->root; + + if (beginword > p->root.returnedlimit) + p->root.returnedlimit=beginword; + lastend=re(root); + + /* First, is the sector we want already in the root? */ + while(rv(root)==NULL || + rb(root)>beginword || + (re(root)enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)) || + re(root)enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){ + i_paranoia_trim(p,beginword,endword); + recover_cache(p); + if(rb(root)!=-1 && p->root.lastsector) + i_end_case(p, endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), + callback); + else + i_stage2(p, beginword, + endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), + callback); + }else + i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), + callback); /* only trips if we're already done */ + + if(!(rb(root)==-1 || rb(root)>beginword || + re(root)enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)){ + + if(p->enable&PARANOIA_MODE_VERIFY) + i_stage1(p,new,callback); + else{ + /* just make v_fragments from the boundary information. */ + long begin=0,end=0; + + while(beginflags[begin]&1))begin++; + end=begin+1; + while(endflags[end]&1)==0)end++; + { + new_v_fragment(p,new,begin+cb(new), + end+cb(new), + (new->lastsector && cb(new)+end==ce(new))); + } + begin=end; + } + } + + }else{ + + if(p->root.vector)i_cblock_destructor(p->root.vector); + free_elem(new->e,0); + p->root.vector=new; + + i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS), + callback); + + } + } + } + + /* Are we doing lots of retries? **************************************/ + + /* Check unaddressable sectors first. There's no backoff here; + jiggle and minimum backseek handle that for us */ + + if(rb(root)!=-1 && lastend+588dynoverlap==MAX_SECTOR_OVERLAP*CD_FRAMEWORDS || + retry_count==max_retries){ + if (!(p->enable&PARANOIA_MODE_NEVERSKIP)) + verify_skip_case(p,callback); + retry_count=0; + } else { + if (p->stage1.offpoints!=-1){ /* hack */ + p->dynoverlap*=1.5; + if (p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS) + p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS; + if (callback) + (*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP); + } + } + } + } + } + p->cursor++; + + return(rv(root)+(beginword-rb(root))); +} + +/* a temporary hack */ +void +paranoia_overlapset(cdrom_paranoia_t *p, long int overlap) +{ + p->dynoverlap=overlap*CD_FRAMEWORDS; + p->stage1.offpoints=-1; +} diff --git a/libcdio_cdda.pc.in b/libcdio_cdda.pc.in new file mode 100644 index 00000000..88155e86 --- /dev/null +++ b/libcdio_cdda.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: @PACKAGE_NAME@ +Description: Portable CD-ROM I/O library +Version: @PACKAGE_VERSION@ +#Requires: glib-2.0 +Libs: -L${libdir} -lcdda_interface +Cflags: -I${includedir} diff --git a/libcdio_paranoia.pc.in b/libcdio_paranoia.pc.in new file mode 100644 index 00000000..eff5591a --- /dev/null +++ b/libcdio_paranoia.pc.in @@ -0,0 +1,11 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: @PACKAGE_NAME@ +Description: Portable CD-ROM I/O library +Version: @PACKAGE_VERSION@ +#Requires: glib-2.0 +Libs: -L${libdir} -lcdio_paranoia -lcdda_interface +Cflags: -I${includedir} diff --git a/src/Makefile.am b/src/Makefile.am index 6c0d771e..c0ad8f6a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.26 2004/10/26 08:32:29 rocky Exp $ +# $Id: Makefile.am,v 1.27 2004/12/18 17:29:32 rocky Exp $ # # Copyright (C) 2003, 2004 Rocky Bernstein # @@ -19,6 +19,8 @@ #################################################### # Things to make the sample/test programs #################################################### +SUBDIRS = cd-paranoia + CDDB_LIBS=@CDDB_LIBS@ if MAINTAINER_MODE diff --git a/src/cd-info.c b/src/cd-info.c index 0dab1f1f..ba3ff09b 100644 --- a/src/cd-info.c +++ b/src/cd-info.c @@ -1,5 +1,5 @@ /* - $Id: cd-info.c,v 1.101 2004/12/04 11:44:16 rocky Exp $ + $Id: cd-info.c,v 1.102 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein Copyright (C) 1996, 1997, 1998 Gerd Knorr @@ -47,7 +47,6 @@ #include #include "cdio_assert.h" -#include "iso9660_private.h" #include #ifdef __linux__ @@ -1060,9 +1059,13 @@ main(int argc, const char *argv[]) psz_msf = cdio_msf_to_str(&msf); if (i == CDIO_CDROM_LEADOUT_TRACK) { - if (!opts.no_tracks) - printf("%3d: %8s %06lu leadout\n", (int) i, psz_msf, - (long unsigned int) cdio_msf_to_lsn(&msf)); + if (!opts.no_tracks) { + lsn_t lsn= cdio_msf_to_lsn(&msf); + long unsigned int i_mb = ( lsn * CDIO_CD_FRAMESIZE_RAW ) / + (1024 * 1024); + printf( "%3d: %8s %06lu leadout (%lu MB)\n", (int) i, psz_msf, + (long unsigned int) lsn, i_mb ); + } free(psz_msf); break; } else if (!opts.no_tracks) { diff --git a/src/cd-paranoia/.cvsignore b/src/cd-paranoia/.cvsignore new file mode 100644 index 00000000..0a0bb169 --- /dev/null +++ b/src/cd-paranoia/.cvsignore @@ -0,0 +1,6 @@ +.deps +.libs +Makefile +Makefile.in +*.o +cd-paranoia diff --git a/src/cd-paranoia/Makefile.am b/src/cd-paranoia/Makefile.am new file mode 100644 index 00000000..6fb5455c --- /dev/null +++ b/src/cd-paranoia/Makefile.am @@ -0,0 +1,34 @@ +# $Id: Makefile.am,v 1.1 2004/12/18 17:29:32 rocky Exp $ +# +# Copyright (C) 2004 Rocky Bernstein +# Copyright (C) 1998 Monty xiphmont@mit.edu +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 2 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +# +############################################################################### + +cd_paranoia_SOURCES = cd-paranoia.c \ + buffering_write.c buffering_write.h \ + header.c header.h \ + report.c report.h + +cd_paranoia_LDADD = $(LIBCDIO_LIBS) $(LIBCDIO_CDDA_LIBS) $(LIBCDIO_PARANOIA_LIBS) + +bin_PROGRAMS = cd-paranoia$(EXEEXT) + +man_MANS = cd-paranoia.1 cd-paranoia.1.jp +EXTRA_DIST = $(man_MANS) + +INCLUDES = -I$(top_srcdir) $(LIBCDIO_CFLAGS) diff --git a/src/cd-paranoia/buffering_write.c b/src/cd-paranoia/buffering_write.c new file mode 100644 index 00000000..63c01164 --- /dev/null +++ b/src/cd-paranoia/buffering_write.c @@ -0,0 +1,73 @@ +/* Eliminate teeny little writes. patch submitted by + Rob Ross --Monty 19991008 */ + +#include +#include +#include +#include + +#define OUTBUFSZ 32*1024 + +#include "utils.h" +#include "buffering_write.h" + + +/* GLOBALS FOR BUFFERING CALLS */ +static int bw_fd = -1; +static long bw_pos = 0; +static char bw_outbuf[OUTBUFSZ]; + + +/* buffering_write() - buffers data to a specified size before writing. + * + * Restrictions: + * - MUST CALL BUFFERING_CLOSE() WHEN FINISHED!!! + * + */ +long buffering_write(int fd, char *buffer, long num) +{ + if (fd != bw_fd) { + /* clean up after buffering for some other file */ + if (bw_fd >= 0 && bw_pos > 0) { + if (blocking_write(bw_fd, bw_outbuf, bw_pos)) { + perror("write (in buffering_write, flushing)"); + } + } + bw_fd = fd; + bw_pos = 0; + } + + if (bw_pos + num > OUTBUFSZ) { + /* fill our buffer first, then write, then modify buffer and num */ + memcpy(&bw_outbuf[bw_pos], buffer, OUTBUFSZ - bw_pos); + if (blocking_write(fd, bw_outbuf, OUTBUFSZ)) { + perror("write (in buffering_write, full buffer)"); + return(-1); + } + num -= (OUTBUFSZ - bw_pos); + buffer += (OUTBUFSZ - bw_pos); + bw_pos = 0; + } + /* save data */ + memcpy(&bw_outbuf[bw_pos], buffer, num); + bw_pos += num; + + return(0); +} + +/* buffering_close() - writes out remaining buffered data before closing + * file. + * + */ +int buffering_close(int fd) +{ + if (fd == bw_fd && bw_pos > 0) { + /* write out remaining data and clean up */ + if (blocking_write(fd, bw_outbuf, bw_pos)) { + perror("write (in buffering_close)"); + } + bw_fd = -1; + bw_pos = 0; + } + return(close(fd)); +} diff --git a/src/cd-paranoia/buffering_write.h b/src/cd-paranoia/buffering_write.h new file mode 100644 index 00000000..55c9d8a9 --- /dev/null +++ b/src/cd-paranoia/buffering_write.h @@ -0,0 +1,23 @@ +/* + * Copyright: GNU Public License 2 applies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Copyright (C) 2004 Rocky Bernstein + * (C) 1998 Monty + * + */ + +extern long blocking_write(int outf, char *buffer, long i_num); diff --git a/src/cd-paranoia/cd-paranoia.1 b/src/cd-paranoia/cd-paranoia.1 new file mode 100644 index 00000000..47d4309f --- /dev/null +++ b/src/cd-paranoia/cd-paranoia.1 @@ -0,0 +1,352 @@ +.TH CDPARANOIA 1 "02 Mar 2001" +.SH NAME +cdparanoia 9.8 (Paranoia release III) \- an audio CD reading utility which includes extra data verification features +.SH SYNOPSIS +.B cdparanoia +.RB [ options ] +.B span +.RB [ outfile ] +.SH DESCRIPTION +.B cdparanoia +retrieves audio tracks from CDDA capable CDROM drives. The data can +be saved to a file or directed to standard output in WAV, AIFF, AIFF-C +or raw format. Most ATAPI, SCSI and several proprietary CDROM drive +makes are supported; +.B cdparanoia +can determine if the target drive is CDDA capable. +.P +In addition to simple reading, +.B cdparanoia +adds extra-robust data verification, synchronization, error handling +and scratch reconstruction capability. +.SH OPTIONS + +.TP +.B \-v --verbose +Be absurdly verbose about the autosensing and reading process. Good +for setup and debugging. + +.TP +.B \-q --quiet +Do not print any progress or error information during the reading process. + +.TP +.B \-e --stderr-progress +Force output of progress information to stderr (for wrapper scripts). + +.TP +.B \-V --version +Print the program version and quit. + +.TP +.B \-Q --query +Perform CDROM drive autosense, query and print the CDROM table of +contents, then quit. + +.TP +.B \-s --search-for-drive +Forces a complete search for a cdrom drive, even if the /dev/cdrom link exists. + +.TP +.B \-h --help +Print a brief synopsis of +.B cdparanoia +usage and options. + +.TP +.B \-p --output-raw +Output headerless data as raw 16 bit PCM data with interleaved samples in host byte order. To force little or big endian byte order, use +.B \-r +or +.B \-R +as described below. + +.TP +.B \-r --output-raw-little-endian +Output headerless data as raw 16 bit PCM data with interleaved samples in LSB first byte order. + +.TP +.B \-R --output-raw-big-endian +Output headerless data as raw 16 bit PCM data with interleaved samples in MSB first byte order. + +.TP +.B \-w --output-wav +Output data in Micro$oft RIFF WAV format (note that WAV data is always +LSB first byte order). + +.TP +.B \-f --output-aiff +Output data in Apple AIFF format (note that AIFC data is +always in MSB first byte order). + +.TP +.B \-a --output-aifc +Output data in uncompressed Apple AIFF-C format (note that AIFF-C data is +always in MSB first byte order). + +.TP +.BI "\-B --batch " + +Cdda2wav-style batch output flag; cdparanoia will split the output +into multiple files at track boundaries. Output file names are +prepended with 'track#.' + +.TP +.B \-c --force-cdrom-little-endian +Some CDROM drives misreport their endianness (or do not report it at +all); it's possible that cdparanoia will guess wrong. Use +.B \-c +to force cdparanoia to treat the drive as a little endian device. + +.TP +.B \-C --force-cdrom-big-endian +As above but force cdparanoia to treat the drive as a big endian device. + +.TP +.BI "\-n --force-default-sectors " n +Force the interface backend to do atomic reads of +.B n +sectors per read. This number can be misleading; the kernel will often +split read requests into multiple atomic reads (the automated Paranoia +code is aware of this) or allow reads only wihin a restricted size +range. +.B This option should generally not be used. + +.TP +.BI "\-d --force-cdrom-device " device +Force the interface backend to read from +.B device +rather than the first readable CDROM drive it finds. This can be used +to specify devices of any valid interface type (ATAPI, SCSI or +proprietary). + +.TP +.BI "\-g --force-generic-device " device +This option is used along with +.B \-d +when one wants explicit control in setting both the SCSI cdrom and +generic devices seperately. This option is only useful on +non-standard SCSI setups. + +.TP +.BI "\-S --force-read-speed " number +Use this option explicitly to set the read rate of the CD drive (where +supported). This can reduce underruns on machines with slow disks, or +which are low on memory. + +.TP +.BI "\-t --toc-offset " number +Use this option to force the entire disc LBA addressing to shift by +the given amount; the value is added to the beginning offsets in the +TOC. This can be used to shift track boundaries for the whole disc +manually on sector granularity. The next option does something +similar... + +.TP +.BI "\-T --toc-bias " +Some drives (usually random Toshibas) report the actual track +beginning offset values in the TOC, but then treat the beginning of +track 1 index 1 as sector 0 for all read operations. This results in +every track seeming to start too late (losing a bit of the beginning +and catching a bit of the next track). +.B \-T +accounts for this behavior. Note that this option will cause +cdparanoia to attempt to read sectors before or past the known user +data area of the disc, resulting in read errors at disc edges on most +drives and possibly even hard lockups on some buggy hardware. + +.TP +.BI "\-O --sample-offset " number +Use this option to force the entire disc to shift sample position +output by the given amount; This can be used to shift track boundaries +for the whole disc manually on sample granularity. Note that this will +cause cdparanoia to attempt to read partial sectors before or past the +known user data area of the disc, probably causing read errors on most +drives and possibly even hard lockups on some buggy hardware. + + +.TP +.B \-Z --disable-paranoia +Disable +.B all +data verification and correction features. When using -Z, cdparanoia +reads data exactly as would cdda2wav with an overlap setting of zero. +This option implies that +.B \-Y +is active. + +.TP +.B \-z --never-skip[=max_retries] +Do not accept any skips; retry forever if needed. An optional maximum +number of retries can be specified; for comparison, default without -z is +currently 20. + +.TP +.B \-Y --disable-extra-paranoia +Disables intra-read data verification; only overlap checking at read +boundaries is performed. It can wedge if errors occur in the attempted overlap area. Not recommended. + +.TP +.B \-X --abort-on-skip +If the read skips due to imperfect data, a scratch, whatever, abort reading this track. If output is to a file, delete the partially completed file. + +.SH OUTPUT SMILIES +.TP +.B + :-) +Normal operation, low/no jitter +.TP +.B + :-| +Normal operation, considerable jitter +.TP +.B + :-/ +Read drift +.TP +.B + :-P +Unreported loss of streaming in atomic read operation +.TP +.B + 8-| +Finding read problems at same point during reread; hard to correct +.TP +.B + :-0 +SCSI/ATAPI transport error +.TP +.B + :-( +Scratch detected +.TP +.B + ;-( +Gave up trying to perform a correction +.TP +.B + 8-X +Aborted read due to known, uncorrectable error +.TP +.B + :^D +Finished extracting + +.SH PROGRESS BAR SYMBOLS +.TP +.B + +No corrections needed +.TP +.B + - +Jitter correction required +.TP +.B + + +Unreported loss of streaming/other error in read +.TP +.B + ! +Errors found after stage 1 correction; the drive is making the +same error through multiple re-reads, and cdparanoia is having trouble +detecting them. +.TP +.B + e +SCSI/ATAPI transport error (corrected) +.TP +.B + V +Uncorrected error/skip + +.SH SPAN ARGUMENT + +The span argument specifies which track, tracks or subsections of +tracks to read. This argument is required. +.B NOTE: +Unless the span is a simple number, it's generally a good idea to +quote the span argument to protect it from the shell. +.P +The span argument may be a simple track number or an offset/span +specification. The syntax of an offset/span takes the rough form: +.P +1[ww:xx:yy.zz]-2[aa:bb:cc.dd] +.P +Here, 1 and 2 are track numbers; the numbers in brackets provide a +finer grained offset within a particular track. [aa:bb:cc.dd] is in +hours/minutes/seconds/sectors format. Zero fields need not be +specified: [::20], [:20], [20], [20.], etc, would be interpreted as +twenty seconds, [10:] would be ten minutes, [.30] would be thirty +sectors (75 sectors per second). +.P +When only a single offset is supplied, it is interpreted as a starting +offset and ripping will continue to the end of the track. If a single +offset is preceeded or followed by a hyphen, the implicit missing +offset is taken to be the start or end of the disc, respectively. Thus: + +.TP +.B 1:[20.35] +Specifies ripping from track 1, second 20, sector 35 to the end of +track 1. +.TP +.B 1:[20.35]- +Specifies ripping from 1[20.35] to the end of the disc +.TP +.B \-2 +Specifies ripping from the beginning of the disc up to (and including) track 2 +.TP +.B \-2:[30.35] +Specifies ripping from the beginning of the disc up to 2:[30.35] +.TP +.B 2-4 +Specifies ripping from the beginning of track 2 to the end of track 4. +.P +Again, don't forget to protect square brackets and preceeding hyphens from +the shell. + +.SH EXAMPLES + +A few examples, protected from the shell: +.TP +Query only with exhaustive search for a drive and full reporting of autosense: +.P + cdparanoia -vsQ +.TP +Extract an entire disc, putting each track in a seperate file: +.P + cdparanoia -B +.TP +Extract from track 1, time 0:30.12 to 1:10.00: +.P + cdparanoia "1[:30.12]-1[1:10]" +.TP +Extract from the beginning of the disc up to track 3: +.P + cdparanoia -- "-3" +.TP +The "--" above is to distinguish "-3" from an option flag. +.SH OUTPUT + +The output file argument is optional; if it is not specified, +cdparanoia will output samples to one of +.BR cdda.wav ", " cdda.aifc ", or " cdda.raw +depending on whether +.BR \-w ", " \-a ", " \-r " or " \-R " is used (" \-w +is the implicit default). The output file argument of +.B \- +specifies standard output; all data formats may be piped. + +.SH ACKNOWLEDGEMENTS +Cdparanoia sprang from and once drew heavily from the interface of +Heiko Eissfeldt's (heiko@colossus.escape.de) 'cdda2wav' +package. Cdparanoia would not have happened without it. +.P +Joerg Schilling has also contributed SCSI expertise through his +generic SCSI transport library. +.P +.SH AUTHOR +Monty +.P +Cdparanoia's homepage may be found at: +http://www.xiph.org/paranoia/ diff --git a/src/cd-paranoia/cd-paranoia.1.jp b/src/cd-paranoia/cd-paranoia.1.jp new file mode 100644 index 00000000..97d205f4 --- /dev/null +++ b/src/cd-paranoia/cd-paranoia.1.jp @@ -0,0 +1,354 @@ +.TH CDPARANOIA 1 +.\" Translated Sun Aug 22 18:02:41 JST 1999 +.\" by FUJIWARA Teruyoshi +.SH 名前 +cdparanoia (Paranoia release III) \- オーディオ CD 読み取りユーティリティ。特別なデータ照合機能を持つ。 +.SH 日付 +バージョンIII リリースα9.6 (17 Aug 1999) +.SH 書式 +.B cdparanoia +.RB [ options ] +.B span +.RB [ outfile ] +.SH 説明 +.B cdparanoia +は CD-DA 機能を持つ CD-ROM ドライブからオーディオトラックを取り出しま +す。このデータは WAV, AIFF, AIFF-C, raw 形式でファイルにセーブすること +や、標準出力に送ることができます。ほとんどの ATAPI, SCSI, メーカー独自 +の CD-ROM ドライブがサポートされています。 +.B cdparanoia +は対象のドライブが CD-DA 機能を持っているかどうかを判別できます。 +.P +単純な読み取りだけでなく、 +.B cdparanoia +は特別に頑健なデータ照合機能、同期機能、エラー処理機能、破損データの再 +構成機能を持っています。 +.SH オプション + +.TP +.B \-v --verbose +自動検出と読み取りの処理について、ばかばかしいほど冗長な表示を行います。 +設定やデバッグの際に便利です。 + +.TP +.B \-q --quiet +読み取り処理の途中に、進行状況やエラー情報を全く表示しません。 + +.TP +.B \-e --stderr-progress +進行状況を(ラッパスクリプトのために)標準エラー出力に出力します。 + +.TP +.B \-V --version +プログラムのバージョンを表示して終了します。 + +.TP +.B \-Q --query +CD-ROM ドライブの自動検出を行い、CD-ROM の TOC の問い合わせと表示を行 +い、終了します。 + +.TP +.B \-s --search-for-drive +たとえ /dev/cdrom のリンクが存在していても、CD-ROM ドライブの完全な +検索を行います。 + +.TP +.B \-h --help +.B cdparanoia +の使い方とオプションを簡単な説明を出力します。 + +.TP +.B \-p --output-raw +ヘッダ無しのデータをホストのバイト順で、インタリーブ処理を施した +サンプル音声を含む raw 形式の 16 ビット PCM データとして出力します。 +バイト順としてリトルエンディアンあるいはビッグエンディアンを指定するに +は、後述の +.B \-r +または +.B \-R +オプションを使ってください。 + +.TP +.B \-r --output-raw-little-endian +ヘッダ無しのデータを LSB first のバイト順で、インタリーブ処理を施した +サンプル音声を含む raw 形式の 16 ビット PCM データとして出力します。 + +.TP +.B \-R --output-raw-big-endian +ヘッダ無しのデータを MSB first のバイト順で、インタリーブ処理を施した +サンプル音声を含む raw 形式の 16 ビット PCM データとして出力します。 + +.TP +.B \-w --output-wav +データを Micro$oft の RIFF WAV 形式で出力します(WAV データのバイト順は +必ず LSB first である点に注意)。 + +.TP +.B \-f --output-aiff +データを Apple の AIFF 形式で出力します(AIFC データのバイト順は必ず +MSB first である点に注意)。 + +.TP +.B \-a --output-aifc +データを無圧縮 の Apple AIFF-C 形式で出力します(AIFF-C データのバイト +順は必ず MSB first である点に注意)。 + +.TP +.BI "\-B --batch " +cdda2wav 形式のバッチ出力を行います。cdparanoia は出力をトラック境界で +複数ファイルに分割します。出力ファイルのファイル名の先頭部分は、'track(番号)' +となります。 + +.TP +.B \-c --force-cdrom-little-endian +一部の CD-ROM は間違ったエンディアンを報告します(あるいはエンディアン +に関する情報を全く報告しません)。そのため、cdparanoia がエンディアンを +間違えることがあります。ドライブをリトルエンディアンのデバイスとして +cdparanoia に扱わせるには、 +.B \-c +オプションを使います。 + +.TP +.B \-C --force-cdrom-big-endian +前のオプションの逆で、デバイスをビッグエンディアンのデバイスとして +cdparanoia に扱わせます。 + +.TP +.BI "\-n --force-default-sectors " n +インタフェースのバックエンドが行う最小単位の読み取りを、 +1 回の読み取りごとに +.B n +セクタとします。この数は問題を起こすおそれがあります。カーネルは多くの +場合、読み取り要求を最小単位の読み取り(cdparanoia による自動処理はこれ +に対応しています)複数個に分割するか、制限された大きさの範囲でしか +読み取りを許可しません。 +.B 普通はこのオプションを使うべきではありません。 + +.TP +.BI "\-d --force-cdrom-device " device +インタフェースのバックエンドによる読み取りを、最初に見つけた読み取り可 +能な CD-ROM ドライブではなく、指定した +.B device +から行うようにします。このオプションでは、利用可能である任意の +インタフェース(ATAPI, SCSI, メーカー独自)を持つデバイスを指定すること +ができます。 + +.TP +.BI "\-g --force-generic-device " device +このオプションは、SCSI CD-ROM と汎用デバイスの設定を明示的に別々に制御 +したい時に +.B \-d +オプションと組み合わせて使います。このオプションが役立つのは、SCSI の +設定が標準と異なる場合だけです。 + +.TP +.BI "\-S --force-read-speed " number +CD ドライブからの読み込み速度を設定するには、このオプションを明示的に +使ってください(ドライブが対応している場合)。このオプションを用いると、 +ディスクが遅い場合やメモリが少ない場合に起こるアンダーランを減らすこと +ができます。 + +.TP +.B \-Z --disable-paranoia +データ照合と訂正機能を +.b 全て +無効にします。-Z オプションを用いると、cdparanoia は +オーバーラップの設定が 0 である cdda2wav と全く同じようにデータの +読み取りを行います。 +このオプションを指定すると +.B \-W , +.B \-X , +.B \-Y +オプションも有効になりますが、 +.B \-Z \-W \-X \-Y +と全く同じでは +.B ありません。 +なぜなら、 +.B \-W +から +.B \-Z +までのオプションにより照合のレベルが階層的に変わるからです。実際に有効 +になるのは最後に指定したオプションだけです。 + +.TP +.B \-Y --disable-extra-paranoia +読み取ったデータの中間におけるデータ照合を行いません。つまり、 +データの読み取り境界におけるオーバーラップ部分のチェックしか行いません。 + +.TP +.B \-X --disable-scratch-detection +照合の途中では傷の探査も行わず、傷に対して頑健な同期処理も行いません。 +.B \-X +オプションを指定した場合、傷ついた CD を与えると cdparanoia は読み取り +の失敗を起こします。 + +.TP +.B \-W --disable-scratch-repair +傷を検出し、同期を保つ処理を行います。ただし壊れたデータの修復は行いま +せん。ログファイルの出力を行うと( +.RB \-i +オプション)、全ての傷のフレーム位置がログファイルに出力されます。 + +.SH 出力される顔文字 +.TP +.B + :-) +正常動作。ジッタは少ないか、全くない +.TP +.B + :-| +正常動作。ジッタは許容範囲 +.TP +.B + :-/ +読み取りでドリフトが発生 +.TP +.B + :-P +最小単位の読み取り操作において、報告されていない損失がストリーミングにある +.TP +.B + 8-| +繰り返して読み取りを行ったが、同じ位置で問題が起きた。修正は困難である +.TP +.B + :-0 +SCSI/ATAPI のデータ転送エラー +.TP +.B + :-( +傷が検出された +.TP +.B + ;-( +データの訂正をあきらめた +.TP +.B + :^D +読み取り終了 + +.SH 進行表示の意味 +.TP +.B +<スペース> +訂正は不要 +.TP +.B + - +ジッタの訂正が必要 +.TP +.B + + +報告されていない損失がストリーミングにある。あるいは別のエラーが読み取り +時に発生した +.TP +.B + ! +ステージ 1 訂正の後にエラーが見つかった。読み取りを複数回繰り返しても +同じエラーが発生し、cdparanoia はそのエラーをうまく検出できない。 +.TP +.B + e +SCSI/ATAPI のデータ転送エラー(訂正済み) +.TP +.B + V +訂正できないエラー/データのスキップ + +.SH 引き数 'span' + +引き数 span は、読み取りを行うトラックまたはトラックの一部を指定します。 +この引き数は必ず必要です。 +.B 注意: +span が単なる数字でなければ、シェルが引き数 span を展開してしまわない +ようにクォートするのが普通でしょう。 +.P +引き数 span は、単なるトラック番号か、オフセットとスパンの組合せの指定 +となります。オフセットとスパンの組合せを指定する方法は、だいたい以下の +ようになります: +.P +1[ww:xx:yy.zz]-2[aa:bb:cc.dd] +.P +ここで 1 と 2 はトラック番号です。角括弧の中の数値は、指定されたトラック +における、より細かいオフセット指定です。[aa:bb:cc.dd] は +「時間/分/秒/セクタ」の形式です。値が 0 であるフィールドは指定しなくて +も構いません。つまり [::20], [:20], [20], [20.] 等は 20 秒と解釈され、 +[10:] は 10 秒と解釈され、[.30] は 30 セクタと解釈されます(75 セクタで +1 秒です)。 +.P +オフセットを 1 つしか指定しなければ、これは開始位置のオフセットを表し、 +吸い出しはそのトラックの終わりまで行われます。オフセットが 1 つだけあ +り、その前後にハイフン(-)がある場合には、省略されているオフセットは +ディスクの先頭あるいは末尾として解釈されます。例を以下に示します: + +.TP +.B 1:[20.35] +トラック 1 の 20 秒、35 セクタの位置から、トラック 1 の末尾までを吸い +出します。 +.TP +.B 1:[20.35]- +1[20.35] の位置からディスクの末尾までを吸い出します。 +.TP +.B \-2 +ディスクの先頭からトラック 2 まで(トラック 2 も含みます)を吸い出します。 +.TP +.B \-2:[30.35] +ディスクの先頭から 2:[30.35] の位置まで吸い出します。 +.TP +.B 2-4 +トラック 2 の先頭からトラック 4 の末尾までを吸い出します。 +.P +繰り返しになりますが、角括弧および単語の先頭にあるハイフンは必ずクォート +して、シェルに展開されないようにしてください。 + +.SH 指定例 + +クォートも含めた指定例をいくつか示します: +.TP +ドライブの調査だけを徹底的に行い、自動検出の結果を全て報告します: +.P + cdparanoia -vsQ +.TP +ディスク全体を吸い出します。それぞれのトラックは別々のファイルにします: +.P + cdparanoia -B "1-" +.TP +トラック 1 の時刻 0:30.12 から時刻 1:10.00 までを吸い出します: +.P + cdparanoia "1[:30.12]-1[1:10]" +.TP +トラック 1 の時刻 0:30.12 から 1 分間のデータを吸い出します: +.P + cdparanoia "1[:30.12]-[1:00]" + +.SH 出力 + +出力ファイルを指定する引き数は省略可能です。指定されていなければ、 +cdparanoia はサンプル音声を +.BR cdda.wav ", " cdda.aifc ", " cdda.raw +のいずれかに出力します。どのファイルに出力されるのかは、オプション +.BR \-w ", " \-a ", " \-r "," \-R +のうちいずれを使うかによって決まります(何も指定しなければ +.BR \-w +がデフォルト値です)。出力ファイルを指定する引き数が +.B \- +ならば、出力は標準出力に対して行われます。どのデータ形式でもパイプに送 +ることができます。 + +.SH 謝辞 +cdparanoia の基となったのは Heiko Eissfeldt さん +(heiko@colossus.escape.de)が作成した 'cdda2wav' パッケージであり、 +以前は cdparanoia のインタフェースの大部分は cdda2wav からもらってきた +ものでした。cdda2wav がなければ、cdparanoia が作られることはなかったで +しょう。 +.P +Joerg Schilling さんが作成した汎用 SCSI データ転送ライブラリから、SCSI +の専門知識を多く学ばせていただきました。 +.P +.SH 作者 +Monty +.P +cdparanoia のホームページは以下の場所にあります: +.P +.ce +http://www.xiph.org/paranoia/ diff --git a/src/cd-paranoia/cd-paranoia.c b/src/cd-paranoia/cd-paranoia.c new file mode 100644 index 00000000..3145c2af --- /dev/null +++ b/src/cd-paranoia/cd-paranoia.c @@ -0,0 +1,1324 @@ +/* + * Copyright: GNU Public License 2 applies + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Copyright (C) 2004 Rocky Bernstein + * (C) 1998 Monty + * + * See ChangeLog for recent changes. + * + * last changes: + * 09.04.04 - conversion to use libcdio. + * 22.01.98 - first version + * 15.02.98 - alpha 2: juggled two includes from interface/low_interface.h + * that move contents in Linux 2.1 + * Linked status bar to isatty to avoid it appearing + * in a redirected file. + * Played with making TOC less verbose. + * 04.04.98 - alpha 3: zillions of bugfixes, also added MMC and IDE_SCSI + * emulation support + * 05.04.98 - alpha 4: Segfault fix, cosmetic repairs + * 05.04.98 - alpha 5: another segfault fix, cosmetic repairs, + * Gadi Oxman provided code to identify/fix nonstandard + * ATAPI CDROMs + * 07.04.98 - alpha 6: Bugfixes to autodetection + * 18.06.98 - alpha 7: Additional SCSI error handling code + * cosmetic fixes + * segfault fixes + * new sync/silence code, smaller fft + * 15.07.98 - alpha 8: More new SCSI code, better error recovery + * more segfault fixes (two linux bugs, one my fault) + * Fixup reporting fixes, smilie fixes. + * AIFF support (in addition to AIFC) + * Path parsing fixes + * Changes are becoming TNTC. Will resume the log at beta. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include "utils.h" +#include "report.h" +#include "version.h" +#include "header.h" +#include "buffering_write.h" + +extern int verbose; +extern int quiet; + +static long parse_offset(cdrom_drive_t *d, char *offset, int begin){ + long track=-1; + long hours=-1; + long minutes=-1; + long seconds=-1; + long sectors=-1; + char *time=NULL,*temp=NULL; + long ret; + + if(offset==NULL)return(-1); + + /* seperate track from time offset */ + temp=strchr(offset,']'); + if(temp){ + *temp='\0'; + temp=strchr(offset,'['); + if(temp==NULL){ + report("Error parsing span argument"); + exit(1); + } + *temp='\0'; + time=temp+1; + } + + /* parse track */ + { + int chars=strspn(offset,"0123456789"); + if(chars>0){ + offset[chars]='\0'; + track=atoi(offset); + if(track<0 || track>d->tracks){ /*take track 0 as pre-gap of 1st track*/ + char buffer[256]; + sprintf(buffer,"Track #%ld does not exist.",track); + report(buffer); + exit(1); + } + } + } + + while(time){ + long val,chars; + char *sec=strrchr(time,'.'); + if(!sec)sec=strrchr(time,':'); + if(!sec)sec=time-1; + + chars=strspn(sec+1,"0123456789"); + if(chars) + val=atoi(sec+1); + else + val=0; + + switch(*sec){ + case '.': + if(sectors!=-1){ + report("Error parsing span argument"); + exit(1); + } + sectors=val; + break; + default: + if(seconds==-1) + seconds=val; + else + if(minutes==-1) + minutes=val; + else + if(hours==-1) + hours=val; + else{ + report("Error parsing span argument"); + exit(1); + } + break; + } + + if(sec<=time)break; + *sec='\0'; + } + + if(track==-1){ + if(seconds==-1 && sectors==-1)return(-1); + if(begin==-1) + ret=cdda_disc_firstsector(d); + else + ret=begin; + }else{ + if(seconds==-1 && sectors==-1){ + if(begin==-1){ /* first half of a span */ + return(cdda_track_firstsector(d,track)); + }else{ + return(cdda_track_lastsector(d,track)); + } + }else{ + /* relative offset into a track */ + ret=cdda_track_firstsector(d,track); + } + } + + /* OK, we had some sort of offset into a track */ + + if(sectors!=-1) ret +=sectors; + if(seconds!=-1) ret += seconds*CDIO_CD_FRAMES_PER_SEC; + if(minutes!=-1) ret += minutes*CDIO_CD_FRAMES_PER_MIN; + if(hours!=-1) ret += hours *60*CDIO_CD_FRAMES_PER_MIN; + + /* We don't want to outside of the track; if it's relative, that's OK... */ + if(track!=-1){ + if(cdda_sector_gettrack(d,ret)!=track){ + report("Time/sector offset goes beyond end of specified track."); + exit(1); + } + } + + /* Don't pass up end of session */ + + if(ret>cdda_disc_lastsector(d)){ + report("Time/sector offset goes beyond end of disc."); + exit(1); + } + + return(ret); +} + +static void display_toc(cdrom_drive_t *d){ + long audiolen=0; + int i; + report("\nTable of contents (audio tracks only):\n" + "track length begin copy pre ch\n" + "==========================================================="); + + for(i=1;i<=d->tracks;i++) + if(cdda_track_audiop(d,i)){ + char buffer[256]; + + long sec=cdda_track_firstsector(d,i); + long off=cdda_track_lastsector(d,i)-sec+1; + + sprintf(buffer, + "%3d. %7ld [%02d:%02d.%02d] %7ld [%02d:%02d.%02d] %s %s %s", + i, + off, + (int) (off/(CDIO_CD_FRAMES_PER_MIN)), + (int) ((off/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN), + (int) (off % CDIO_CD_FRAMES_PER_SEC), + sec, + (int) (sec/(CDIO_CD_FRAMES_PER_MIN)), + (int) ((sec/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN), + (int) (sec % CDIO_CD_FRAMES_PER_SEC), + cdda_track_copyp(d,i)?" OK":" no", + cdda_track_preemp(d,i)?" yes":" no", + cdda_track_channels(d,i)==2?" 2":" 4"); + report(buffer); + audiolen+=off; + } + { + char buffer[256]; + sprintf(buffer, "TOTAL %7ld [%02d:%02d.%02d] (audio only)", + audiolen, + (int) (audiolen/(CDIO_CD_FRAMES_PER_MIN)), + (int) ((audiolen/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN), + (int) (audiolen % CDIO_CD_FRAMES_PER_SEC)); + report(buffer); + } + report(""); +} + +static void usage(FILE *f){ + fprintf( f, +VERSION"\n" + +"USAGE:\n" +" cdparanoia [options] [outfile]\n\n" + +"OPTIONS:\n" +" -v --verbose : extra verbose operation\n" +" -q --quiet : quiet operation\n" +" -e --stderr-progress : force output of progress information to\n" +" stderr (for wrapper scripts)\n" +" -V --version : print version info and quit\n" +" -Q --query : autosense drive, query disc and quit\n" +" -B --batch : 'batch' mode (saves each track to a\n" +" seperate file.\n" +" -s --search-for-drive : do an exhaustive search for drive\n" +" -h --help : print help\n\n" + +" -p --output-raw : output raw 16 bit PCM in host byte \n" +" order\n" +" -r --output-raw-little-endian : output raw 16 bit little-endian PCM\n" +" -R --output-raw-big-endian : output raw 16 bit big-endian PCM\n" +" -w --output-wav : output as WAV file (default)\n" +" -f --output-aiff : output as AIFF file\n" +" -a --output-aifc : output as AIFF-C file\n\n" + +" -c --force-cdrom-little-endian : force treating drive as little endian\n" +" -C --force-cdrom-big-endian : force treating drive as big endian\n" +" -n --force-default-sectors : force default number of sectors in read\n" +" to n sectors\n" +" -o --force-search-overlap : force minimum overlap search during\n" +" verification to n sectors\n" +" -d --force-cdrom-device : use specified device; disallow \n" +" autosense\n" +" -g --force-generic-device : use specified generic scsi device\n" +" -S --force-read-speed : read from device at specified speed\n" +" -t --toc-offset : Add sectors to the values reported\n" +" when addressing tracks. May be negative\n" +" -T --toc-bias : Assume that the beginning offset of \n" +" track 1 as reported in the TOC will be\n" +" addressed as LBA 0. Necessary for some\n" +" Toshiba drives to get track boundaries\n" +" correct\n" +" -O --sample-offset : Add samples to the offset when\n" +" reading data. May be negative.\n" +" -z --never-skip[=n] : never accept any less than perfect\n" +" data reconstruction (don't allow 'V's)\n" +" but if [n] is given, skip after [n]\n" +" retries without progress.\n" +" -Z --disable-paranoia : disable all paranoia checking\n" +" -Y --disable-extra-paranoia : only do cdda2wav-style overlap checking\n" +" -X --abort-on-skip : abort on imperfect reads/skips\n\n" + +"OUTPUT SMILIES:\n" +" :-) Normal operation, low/no jitter\n" +" :-| Normal operation, considerable jitter\n" +" :-/ Read drift\n" +" :-P Unreported loss of streaming in atomic read operation\n" +" 8-| Finding read problems at same point during reread; hard to correct\n" +" :-0 SCSI/ATAPI transport error\n" +" :-( Scratch detected\n" +" ;-( Gave up trying to perform a correction\n" +" 8-X Aborted (as per -X) due to a scratch/skip\n" +" :^D Finished extracting\n\n" + +"PROGRESS BAR SYMBOLS:\n" +" No corrections needed\n" +" - Jitter correction required\n" +" + Unreported loss of streaming/other error in read\n" +" ! Errors are getting through stage 1 but corrected in stage2\n" +" e SCSI/ATAPI transport error (corrected)\n" +" V Uncorrected error/skip\n\n" + +"SPAN ARGUMENT:\n" +"The span argument may be a simple track number or a offset/span\n" +"specification. The syntax of an offset/span takes the rough form:\n\n" + +" 1[ww:xx:yy.zz]-2[aa:bb:cc.dd] \n\n" + +"Here, 1 and 2 are track numbers; the numbers in brackets provide a\n" +"finer grained offset within a particular track. [aa:bb:cc.dd] is in\n" +"hours/minutes/seconds/sectors format. Zero fields need not be\n" +"specified: [::20], [:20], [20], [20.], etc, would be interpreted as\n" +"twenty seconds, [10:] would be ten minutes, [.30] would be thirty\n" +"sectors (75 sectors per second).\n\n" + +"When only a single offset is supplied, it is interpreted as a starting\n" +"offset and ripping will continue to the end of he track. If a single\n" +"offset is preceeded or followed by a hyphen, the implicit missing\n" +"offset is taken to be the start or end of the disc, respectively. Thus:\n\n" + +" 1:[20.35] Specifies ripping from track 1, second 20, sector 35 to \n" +" the end of track 1.\n\n" + +" 1:[20.35]- Specifies ripping from 1[20.35] to the end of the disc\n\n" + +" -2 Specifies ripping from the beginning of the disc up to\n" +" (and including) track 2\n\n" + +" -2:[30.35] Specifies ripping from the beginning of the disc up to\n" +" 2:[30.35]\n\n" + +" 2-4 Specifies ripping from the beginning of track two to the\n" +" end of track 4.\n\n" + +"Don't forget to protect square brackets and preceeding hyphens from\n" +"the shell...\n\n" +"A few examples, protected from the shell:\n" +" A) query only with exhaustive search for a drive and full reporting\n" +" of autosense:\n" +" cdparanoia -vsQ\n\n" +" B) extract up to and including track 3, putting each track in a seperate\n" +" file:\n" +" cdparanoia -B -- \"-3\"\n\n" +" C) extract from track 1, time 0:30.12 to 1:10.00:\n" +" cdparanoia \"1[:30.12]-1[1:10]\"\n\n" + +"Submit bug reports to bug-libcdio@gnu.org\n\n"); +} + +long callbegin; +long callend; +long callscript=0; + +static const char *callback_strings[15]={ + "wrote", + "finished", + "read", + "verify", + "jitter", + "correction", + "scratch", + "scratch repair", + "skip", + "drift", + "backoff", + "overlap", + "dropped", + "duped", + "transport error"}; + +static int skipped_flag=0; +static int abort_on_skip=0; +static void +callback(long int inpos, paranoia_cb_mode_t function) +{ + /* + + (== PROGRESS == [--+!---x--------------> | 007218 01 ] == :-) . ==) + + */ + + int graph=30; + char buffer[256]; + static long c_sector=0,v_sector=0; + static char dispcache[30]=" "; + static int last=0; + static long lasttime=0; + long sector,osector=0; + struct timeval thistime; + static char heartbeat=' '; + int position=0,aheadposition=0; + static int overlap=0; + static int printit=-1; + + static int slevel=0; + static int slast=0; + static int stimeout=0; + const char *smilie="= :-)"; + + if(callscript) + fprintf(stderr,"##: %d [%s] @ %ld\n", + function,(function>=-2&&function<=13?callback_strings[function+2]: + ""),inpos); + + if(!quiet){ + long test; + osector=inpos; + sector=inpos/CD_FRAMEWORDS; + + if(printit==-1){ + if(isatty(STDERR_FILENO)){ + printit=1; + }else{ + printit=0; + } + } + + if(printit==1){ /* else don't bother; it's probably being + redirected */ + position=((float)(sector-callbegin)/ + (callend-callbegin))*graph; + + aheadposition=((float)(c_sector-callbegin)/ + (callend-callbegin))*graph; + + if(function==-2){ + v_sector=sector; + return; + } + if(function==-1){ + last=8; + heartbeat='*'; + slevel=0; + v_sector=sector; + }else + if(position=0) + switch(function){ + case PARANOIA_CB_VERIFY: + if(stimeout>=30){ + if(overlap>CD_FRAMEWORDS) + slevel=2; + else + slevel=1; + } + break; + case PARANOIA_CB_READ: + if(sector>c_sector)c_sector=sector; + break; + + case PARANOIA_CB_FIXUP_EDGE: + if(stimeout>=5){ + if(overlap>CD_FRAMEWORDS) + slevel=2; + else + slevel=1; + } + if(dispcache[position]==' ') + dispcache[position]='-'; + break; + case PARANOIA_CB_FIXUP_ATOM: + if(slevel<3 || stimeout>5)slevel=3; + if(dispcache[position]==' ' || + dispcache[position]=='-') + dispcache[position]='+'; + break; + case PARANOIA_CB_READERR: + slevel=6; + if(dispcache[position]!='V') + dispcache[position]='e'; + break; + case PARANOIA_CB_SKIP: + slevel=8; + dispcache[position]='V'; + break; + case PARANOIA_CB_OVERLAP: + overlap=osector; + break; + case PARANOIA_CB_SCRATCH: + slevel=7; + break; + case PARANOIA_CB_DRIFT: + if(slevel<4 || stimeout>5)slevel=4; + break; + case PARANOIA_CB_FIXUP_DROPPED: + case PARANOIA_CB_FIXUP_DUPED: + slevel=5; + if(dispcache[position]==' ' || + dispcache[position]=='-' || + dispcache[position]=='+') + dispcache[position]='!'; + break; + case PARANOIA_CB_REPAIR: + case PARANOIA_CB_BACKOFF: + break; + } + + switch(slevel){ + case 0: /* finished, or no jitter */ + if(skipped_flag) + smilie=" 8-X"; + else + smilie=" :^D"; + break; + case 1: /* normal. no atom, low jitter */ + smilie=" :-)"; + break; + case 2: /* normal, overlap > 1 */ + smilie=" :-|"; + break; + case 4: /* drift */ + smilie=" :-/"; + break; + case 3: /* unreported loss of streaming */ + smilie=" :-P"; + break; + case 5: /* dropped/duped bytes */ + smilie=" 8-|"; + break; + case 6: /* scsi error */ + smilie=" :-0"; + break; + case 7: /* scratch */ + smilie=" :-("; + break; + case 8: /* skip */ + smilie=" ;-("; + skipped_flag=1; + break; + + } + + gettimeofday(&thistime,NULL); + test=thistime.tv_sec*10+thistime.tv_usec/100000; + + if(lasttime!=test || function==-1 || slast!=slevel){ + if(lasttime!=test || function==-1){ + last++; + lasttime=test; + if(last>7)last=0; + stimeout++; + switch(last){ + case 0: + heartbeat=' '; + break; + case 1:case 7: + heartbeat='.'; + break; + case 2:case 6: + heartbeat='o'; + break; + case 3:case 5: + heartbeat='0'; + break; + case 4: + heartbeat='O'; + break; + } + if(function==-1) + heartbeat='*'; + + } + if(slast!=slevel){ + stimeout=0; + } + slast=slevel; + + if(abort_on_skip && skipped_flag && function !=-1){ + sprintf(buffer, + "\r (== PROGRESS == [%s| %06ld %02d ] ==%s %c ==) ", + " ...aborting; please wait... ", + v_sector,overlap/CD_FRAMEWORDS,smilie,heartbeat); + }else{ + if(v_sector==0) + sprintf(buffer, + "\r (== PROGRESS == [%s| ...... %02d ] ==%s %c ==) ", + dispcache,overlap/CD_FRAMEWORDS,smilie,heartbeat); + + else + sprintf(buffer, + "\r (== PROGRESS == [%s| %06ld %02d ] ==%s %c ==) ", + dispcache,v_sector,overlap/CD_FRAMEWORDS,smilie,heartbeat); + + if(aheadposition>=0 && aheadposition=argc && !query_only){ + if(batch) + span=NULL; + else{ + /* D'oh. No span. Fetch me a brain, Igor. */ + usage(stderr); + exit(1); + } + }else + span=copystring(argv[optind]); + + report(VERSION); + + /* Query the cdrom/disc; we may need to override some settings */ + + if(force_generic_device) + d=cdda_identify_scsi(force_generic_device,force_cdrom_device,verbose,NULL); + else + if(force_cdrom_device) + d=cdda_identify(force_cdrom_device,verbose,NULL); + else + if(search) + d=cdda_find_a_cdrom(verbose,NULL); + else{ + /* does the /dev/cdrom link exist? */ + struct stat s; + if(lstat("/dev/cdrom",&s)){ + /* no link. Search anyway */ + d=cdda_find_a_cdrom(verbose,NULL); + }else{ + d=cdda_identify("/dev/cdrom",verbose,NULL); + if(d==NULL && !verbose){ + verbose=1; + report("\n/dev/cdrom exists but isn't accessible. By default,\n" + "cdparanoia stops searching for an accessible drive here.\n" + "Consider using -sv to force a more complete autosense\n" + "of the machine.\n\nMore information about /dev/cdrom:"); + + d=cdda_identify("/dev/cdrom",CDDA_MESSAGE_PRINTIT,NULL); + report("\n"); + exit(1); + }else + report(""); + } + } + + if(!d){ + if(!verbose) + report("\nUnable to open cdrom drive; -v will give more information."); + exit(1); + } + + if(verbose) + cdda_verbose_set(d,CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_PRINTIT); + else + cdda_verbose_set(d,CDDA_MESSAGE_PRINTIT,CDDA_MESSAGE_FORGETIT); + + /* possibly force hand on endianness of drive, sector request size */ + if(force_cdrom_endian!=-1){ + d->bigendianp=force_cdrom_endian; + switch(force_cdrom_endian){ + case 0: + report("Forcing CDROM sense to little-endian; ignoring preset and autosense"); + break; + case 1: + report("Forcing CDROM sense to big-endian; ignoring preset and autosense"); + break; + } + } + if(force_cdrom_sectors!=-1){ + if(force_cdrom_sectors<0 || force_cdrom_sectors>100){ + report("Default sector read size must be 1<= n <= 100\n"); + cdda_close(d); + d=NULL; + exit(1); + } + { + char buffer[256]; + sprintf(buffer,"Forcing default to read %d sectors; " + "ignoring preset and autosense",force_cdrom_sectors); + report(buffer); + d->nsectors=force_cdrom_sectors; + d->bigbuff=force_cdrom_sectors*CDIO_CD_FRAMESIZE_RAW; + } + } + if (force_cdrom_overlap!=-1) { + if (force_cdrom_overlap<0 || force_cdrom_overlap>CDIO_CD_FRAMES_PER_SEC) { + report("Search overlap sectors must be 0<= n <=75\n"); + cdda_close(d); + d=NULL; + exit(1); + } + { + char buffer[256]; + sprintf(buffer,"Forcing search overlap to %d sectors; " + "ignoring autosense",force_cdrom_overlap); + report(buffer); + } + } + + switch(cdda_open(d)){ + case -2:case -3:case -4:case -5: + report("\nUnable to open disc. Is there an audio CD in the drive?"); + exit(1); + case -6: + report("\nCdparanoia could not find a way to read audio from this drive."); + exit(1); + case 0: + break; + default: + report("\nUnable to open disc."); + exit(1); + } + + /* Dump the TOC */ + if(query_only || verbose)display_toc(d); + if(query_only)exit(0); + + /* bias the disc. A hack. Of course. */ + /* we may need to read before or past user area; this is never + default, and we do it because the [allegedly informed] user told + us to */ + if(sample_offset){ + toc_offset+=sample_offset/588; + sample_offset%=588; + if(sample_offset<0){ + sample_offset+=588; + toc_offset--; + } + } + + if(toc_bias){ + toc_offset=-cdda_track_firstsector(d,1); + } + for(i=0;itracks+1;i++) + d->disc_toc[i].dwStartSector+=toc_offset; + + + if(force_cdrom_speed!=-1){ + cdda_speed_set(d,force_cdrom_speed); + } + + if(d->nsectors==1){ + report("WARNING: The autosensed/selected sectors per read value is\n" + " one sector, making it very unlikely Paranoia can \n" + " work.\n\n" + " Attempting to continue...\n\n"); + } + + /* parse the span, set up begin and end sectors */ + + { + long first_sector; + long last_sector; + long batch_first; + long batch_last; + int batch_track; + + if(span){ + /* look for the hyphen */ + char *span2=strchr(span,'-'); + if(strrchr(span,'-')!=span2){ + report("Error parsing span argument"); + cdda_close(d); + d=NULL; + exit(1); + } + + if(span2!=NULL){ + *span2='\0'; + span2++; + } + + first_sector=parse_offset(d,span,-1); + if(first_sector==-1) + last_sector=parse_offset(d,span2,cdda_disc_firstsector(d)); + else + last_sector=parse_offset(d,span2,first_sector); + + if(first_sector==-1){ + if(last_sector==-1){ + report("Error parsing span argument"); + cdda_close(d); + d=NULL; + exit(1); + }else{ + first_sector=cdda_disc_firstsector(d); + } + }else{ + if(last_sector==-1){ + if(span2){ /* There was a hyphen */ + last_sector=cdda_disc_lastsector(d); + }else{ + last_sector= + cdda_track_lastsector(d,cdda_sector_gettrack(d,first_sector)); + } + } + } + }else{ + first_sector=cdda_disc_firstsector(d); + last_sector=cdda_disc_lastsector(d); + } + + { + char buffer[250]; + int track1=cdda_sector_gettrack(d,first_sector); + int track2=cdda_sector_gettrack(d,last_sector); + long off1=first_sector-cdda_track_firstsector(d,track1); + long off2=last_sector-cdda_track_firstsector(d,track2); + int i; + + for(i=track1;i<=track2;i++) + if(!cdda_track_audiop(d,i)){ + report("Selected span contains non audio tracks. Aborting.\n\n"); + exit(1); + } + + sprintf(buffer,"Ripping from sector %7ld (track %2d [%d:%02d.%02d])\n" + "\t to sector %7ld (track %2d [%d:%02d.%02d])\n", + first_sector, + track1, + (int) (off1/(CDIO_CD_FRAMES_PER_MIN)), + (int) ((off1/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN), + (int) (off1 % CDIO_CD_FRAMES_PER_SEC), + last_sector, + track2, + (int) (off2/(CDIO_CD_FRAMES_PER_MIN)), + (int) ((off2/CDIO_CD_FRAMES_PER_SEC) % CDIO_CD_SECS_PER_MIN), + (int) (off2 % CDIO_CD_FRAMES_PER_SEC)); + report(buffer); + + } + + { + long cursor; + int16_t offset_buffer[1176]; + int offset_buffer_used=0; + int offset_skip=sample_offset*4; + + p=paranoia_init(d); + paranoia_modeset(p,paranoia_mode); + if(force_cdrom_overlap!=-1)paranoia_overlapset(p,force_cdrom_overlap); + + if(verbose) + cdda_verbose_set(d,CDDA_MESSAGE_LOGIT,CDDA_MESSAGE_LOGIT); + else + cdda_verbose_set(d,CDDA_MESSAGE_FORGETIT,CDDA_MESSAGE_FORGETIT); + + paranoia_seek(p,cursor=first_sector,SEEK_SET); + + /* this is probably a good idea in general */ + seteuid(getuid()); + setegid(getgid()); + + /* we'll need to be able to read one sector past user data if we + have a sample offset in order to pick up the last bytes. We + need to set the disc length forward here so that the libs are + willing to read past, assuming that works on the hardware, of + course */ + if(sample_offset) + d->disc_toc[d->tracks].dwStartSector++; + + while(cursor<=last_sector){ + char outfile_name[256]; + if(batch){ + batch_first=cursor; + batch_last= + cdda_track_lastsector(d,batch_track= + cdda_sector_gettrack(d,cursor)); + if(batch_last>last_sector)batch_last=last_sector; + }else{ + batch_first=first_sector; + batch_last=last_sector; + batch_track=-1; + } + + callbegin=batch_first; + callend=batch_last; + + /* argv[optind] is the span, argv[optind+1] (if exists) is outfile */ + + if(optind+1256?256:pos); + + if(batch) + snprintf(outfile_name,246,"%strack%02d.%s",path,batch_track,file); + else + snprintf(outfile_name,246,"%s%s",path,file); + + if(file[0]=='\0'){ + switch(output_type){ + case 0: /* raw */ + strcat(outfile_name,"cdda.raw"); + break; + case 1: + strcat(outfile_name,"cdda.wav"); + break; + case 2: + strcat(outfile_name,"cdda.aifc"); + break; + case 3: + strcat(outfile_name,"cdda.aiff"); + break; + } + } + + out=open(outfile_name,O_RDWR|O_CREAT|O_TRUNC,0666); + if(out==-1){ + report3("Cannot open specified output file %s: %s",outfile_name, + strerror(errno)); + cdda_close(d); + d=NULL; + exit(1); + } + report2("outputting to %s\n",outfile_name); + } + }else{ + /* default */ + if(batch) + sprintf(outfile_name,"track%02d.",batch_track); + else + outfile_name[0]='\0'; + + switch(output_type){ + case 0: /* raw */ + strcat(outfile_name,"cdda.raw"); + break; + case 1: + strcat(outfile_name,"cdda.wav"); + break; + case 2: + strcat(outfile_name,"cdda.aifc"); + break; + case 3: + strcat(outfile_name,"cdda.aiff"); + break; + } + + out=open(outfile_name,O_RDWR|O_CREAT|O_TRUNC,0666); + if(out==-1){ + report3("Cannot open default output file %s: %s",outfile_name, + strerror(errno)); + cdda_close(d); + d=NULL; + exit(1); + } + report2("outputting to %s\n",outfile_name); + } + + switch(output_type){ + case 0: /* raw */ + break; + case 1: /* wav */ + WriteWav(out,(batch_last-batch_first+1)*CDIO_CD_FRAMESIZE_RAW); + break; + case 2: /* aifc */ + WriteAifc(out,(batch_last-batch_first+1)*CDIO_CD_FRAMESIZE_RAW); + break; + case 3: /* aiff */ + WriteAiff(out,(batch_last-batch_first+1)*CDIO_CD_FRAMESIZE_RAW); + break; + } + + /* Off we go! */ + + if(offset_buffer_used){ + /* partial sector from previous batch read */ + cursor++; + if(buffering_write(out, + ((char *)offset_buffer)+offset_buffer_used, + CDIO_CD_FRAMESIZE_RAW-offset_buffer_used)){ + report2("Error writing output: %s",strerror(errno)); + exit(1); + } + } + + skipped_flag=0; + while(cursor<=batch_last){ + /* read a sector */ + int16_t *readbuf=paranoia_read_limited(p, callback, max_retries); + char *err=cdda_errors(d); + char *mes=cdda_messages(d); + + if(mes || err) + fprintf(stderr,"\r " + " \r%s%s\n", + mes?mes:"",err?err:""); + + if(err)free(err); + if(mes)free(mes); + if(readbuf==NULL){ + skipped_flag=1; + report("\nparanoia_read: Unrecoverable error, bailing.\n"); + break; + } + if(skipped_flag && abort_on_skip){ + cursor=batch_last+1; + break; + } + + skipped_flag=0; + cursor++; + + if(output_endian!=bigendianp()){ + int i; + for(i=0;ibatch_last){ + int i; + /* read a sector and output the partial offset. Save the + rest for the next batch iteration */ + readbuf=paranoia_read_limited(p,callback,max_retries); + err=cdda_errors(d);mes=cdda_messages(d); + + if(mes || err) + fprintf(stderr,"\r " + " \r%s%s\n", + mes?mes:"",err?err:""); + + if(err)free(err);if(mes)free(mes); + if(readbuf==NULL){ + skipped_flag=1; + report("\nparanoia_read: Unrecoverable error reading through " + "sample_offset shift\n\tat end of track, bailing.\n"); + break; + } + if(skipped_flag && abort_on_skip)break; + skipped_flag=0; + /* do not move the cursor */ + + if(output_endian!=bigendianp()) + for(i=0;i + Copyright (C) 1998 Monty xiphmont@mit.edu + and Heiko Eissfeldt heiko@escape.colossus.de + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +/** \file header.h + * \brief WAV, AIFF and AIFC header-writing routines. + */ + +#include "header.h" +#include +#include +#include +#include + +static void PutNum(long num,int f,int endianness,int bytes){ + int i; + unsigned char c; + + if(!endianness) + i=0; + else + i=bytes-1; + while(bytes--){ + c=(num>>(i<<3))&0xff; + if(write(f,&c,1)==-1){ + perror("Could not write to output."); + exit(1); + } + if(endianness) + i--; + else + i++; + } +} + +/** Writes WAV headers */ +void +WriteWav(int f, long int bytes) +{ + /* quick and dirty */ + + write(f,"RIFF",4); /* 0-3 */ + PutNum(bytes+44-8,f,0,4); /* 4-7 */ + write(f,"WAVEfmt ",8); /* 8-15 */ + PutNum(16,f,0,4); /* 16-19 */ + PutNum(1,f,0,2); /* 20-21 */ + PutNum(2,f,0,2); /* 22-23 */ + PutNum(44100,f,0,4); /* 24-27 */ + PutNum(44100*2*2,f,0,4); /* 28-31 */ + PutNum(4,f,0,2); /* 32-33 */ + PutNum(16,f,0,2); /* 34-35 */ + write(f,"data",4); /* 36-39 */ + PutNum(bytes,f,0,4); /* 40-43 */ +} + +/** Writes AIFF headers */ +void +WriteAiff(int f, long int bytes) +{ + long size=bytes+54; + long frames=bytes/4; + + /* Again, quick and dirty */ + + write(f,"FORM",4); /* 4 */ + PutNum(size-8,f,1,4); /* 8 */ + write(f,"AIFF",4); /* 12 */ + + write(f,"COMM",4); /* 16 */ + PutNum(18,f,1,4); /* 20 */ + PutNum(2,f,1,2); /* 22 */ + PutNum(frames,f,1,4); /* 26 */ + PutNum(16,f,1,2); /* 28 */ + write(f,"@\016\254D\0\0\0\0\0\0",10); /* 38 (44.100 as a float) */ + + write(f,"SSND",4); /* 42 */ + PutNum(bytes+8,f,1,4); /* 46 */ + PutNum(0,f,1,4); /* 50 */ + PutNum(0,f,1,4); /* 54 */ + +} + +/** Writes AIFC headers */ +void +WriteAifc(int f, long bytes) +{ + long size=bytes+86; + long frames=bytes/4; + + /* Again, quick and dirty */ + + write(f,"FORM",4); /* 4 */ + PutNum(size-8,f,1,4); /* 8 */ + write(f,"AIFC",4); /* 12 */ + write(f,"FVER",4); /* 16 */ + PutNum(4,f,1,4); /* 20 */ + PutNum(2726318400UL,f,1,4); /* 24 */ + + write(f,"COMM",4); /* 28 */ + PutNum(38,f,1,4); /* 32 */ + PutNum(2,f,1,2); /* 34 */ + PutNum(frames,f,1,4); /* 38 */ + PutNum(16,f,1,2); /* 40 */ + write(f,"@\016\254D\0\0\0\0\0\0",10); /* 50 (44.100 as a float) */ + + write(f,"NONE",4); /* 54 */ + PutNum(14,f,1,1); /* 55 */ + write(f,"not compressed",14); /* 69 */ + PutNum(0,f,1,1); /* 70 */ + + write(f,"SSND",4); /* 74 */ + PutNum(bytes+8,f,1,4); /* 78 */ + PutNum(0,f,1,4); /* 82 */ + PutNum(0,f,1,4); /* 86 */ + +} + diff --git a/src/cd-paranoia/header.h b/src/cd-paranoia/header.h new file mode 100644 index 00000000..de899af1 --- /dev/null +++ b/src/cd-paranoia/header.h @@ -0,0 +1,17 @@ +/****************************************************************** + * CopyPolicy: GNU Public License 2 applies + * Copyright (C) 1998 Monty xiphmont@mit.edu + ******************************************************************/ + +/** \file header.h + * \brief header for WAV, AIFF and AIFC header-writing routines. + */ + +/** Writes WAV headers */ +extern void WriteWav(int f,long int i_bytes); + +/** Writes AIFC headers */ +extern void WriteAifc(int f,long int i_bytes); + +/** Writes AIFF headers */ +extern void WriteAiff(int f,long int_bytes); diff --git a/src/cd-paranoia/report.c b/src/cd-paranoia/report.c new file mode 100644 index 00000000..e894c917 --- /dev/null +++ b/src/cd-paranoia/report.c @@ -0,0 +1,60 @@ +/* + $Id: report.c,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/****************************************************************** + * + * reporting/logging routines + * + ******************************************************************/ + +#include +#include "config.h" +#include +#include "report.h" + +int quiet=0; +int verbose=CDDA_MESSAGE_FORGETIT; + +void +report(const char *s) +{ + if (!quiet) { + fprintf(stderr,s); + fputc('\n',stderr); + } +} + +void +report2(const char *s, char *s2) +{ + if (!quiet) { + fprintf(stderr,s,s2); + fputc('\n',stderr); + } +} + +void +report3(const char *s, char *s2, char *s3) +{ + if (!quiet) { + fprintf(stderr,s,s2,s3); + fputc('\n',stderr); + } +} diff --git a/src/cd-paranoia/report.h b/src/cd-paranoia/report.h new file mode 100644 index 00000000..70573398 --- /dev/null +++ b/src/cd-paranoia/report.h @@ -0,0 +1,3 @@ +extern void report(const char *s); +extern void report2(const char *s, char *s2); +extern void report3(const char *s, char *s2, char *s3); diff --git a/src/cd-paranoia/utils.h b/src/cd-paranoia/utils.h new file mode 100644 index 00000000..e6ea845c --- /dev/null +++ b/src/cd-paranoia/utils.h @@ -0,0 +1,128 @@ +/* + $Id: utils.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 1998 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include + +extern long buffering_write(int outf, char *buffer, long num); +extern int buffering_close(int fd); + + +/* I wonder how many alignment issues this is gonna trip in the + future... it shouldn't trip any... I guess we'll find out :) */ + +static inline int bigendianp(void){ + int test=1; + char *hack=(char *)(&test); + if(hack[0])return(0); + return(1); +} + +static inline int32_t swap32(int32_t x){ + return((((u_int32_t)x & 0x000000ffU) << 24) | + (((u_int32_t)x & 0x0000ff00U) << 8) | + (((u_int32_t)x & 0x00ff0000U) >> 8) | + (((u_int32_t)x & 0xff000000U) >> 24)); +} + +static inline int16_t swap16(int16_t x){ + return((((u_int16_t)x & 0x00ffU) << 8) | + (((u_int16_t)x & 0xff00U) >> 8)); +} + +#if BYTE_ORDER == LITTLE_ENDIAN + +static inline int32_t be32_to_cpu(int32_t x){ + return(swap32(x)); +} + +static inline int16_t be16_to_cpu(int16_t x){ + return(swap16(x)); +} + +static inline int32_t le32_to_cpu(int32_t x){ + return(x); +} + +static inline int16_t le16_to_cpu(int16_t x){ + return(x); +} + +#else + +static inline int32_t be32_to_cpu(int32_t x){ + return(x); +} + +static inline int16_t be16_to_cpu(int16_t x){ + return(x); +} + +static inline int32_t le32_to_cpu(int32_t x){ + return(swap32(x)); +} + +static inline int16_t le16_to_cpu(int16_t x){ + return(swap16(x)); +} + + +#endif + +static inline int32_t cpu_to_be32(int32_t x){ + return(be32_to_cpu(x)); +} + +static inline int32_t cpu_to_le32(int32_t x){ + return(le32_to_cpu(x)); +} + +static inline int16_t cpu_to_be16(int16_t x){ + return(be16_to_cpu(x)); +} + +static inline int16_t cpu_to_le16(int16_t x){ + return(le16_to_cpu(x)); +} + +static inline char *copystring(const char *s){ + if(s){ + char *ret=malloc((strlen(s)+1)*sizeof(char)); + strcpy(ret,s); + return(ret); + } + return(NULL); +} + +static inline char *catstring(char *buff,const char *s){ + if(s){ + if(buff) + buff=realloc(buff,strlen(buff)+strlen(s)+1); + else + buff=calloc(strlen(s)+1,1); + strcat(buff,s); + } + return(buff); +} + diff --git a/src/cd-paranoia/version.h b/src/cd-paranoia/version.h new file mode 100644 index 00000000..0dffa83f --- /dev/null +++ b/src/cd-paranoia/version.h @@ -0,0 +1,29 @@ +/* + $Id: version.h,v 1.1 2004/12/18 17:29:32 rocky Exp $ + + Copyright (C) 2004 Rocky Bernstein + Copyright (C) 2001 Monty xiphmont@mit.edu + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ +/****************************************************************** + * cdda_paranoia generation III release 9.8 libcdio + ******************************************************************/ + + +#define VERSION "cdparanoia III release 9.8 libcdio\n"\ + "(C) 2001 Monty and Xiphophorus\n"\ + "(C) 2004 Rocky Bernstein \n\n"\ + "Report bugs to bug-libcdio@gnu.org\n" diff --git a/src/util.c b/src/util.c index 474734d5..5d0e8185 100644 --- a/src/util.c +++ b/src/util.c @@ -1,5 +1,5 @@ /* - $Id: util.c,v 1.27 2004/11/06 09:16:04 rocky Exp $ + $Id: util.c,v 1.28 2004/12/18 17:29:32 rocky Exp $ Copyright (C) 2003, 2004 Rocky Bernstein @@ -433,8 +433,10 @@ print_drive_capabilities(cdio_drive_read_cap_t i_read_cap, report( stdout, _("Can set drive speed : %s\n"), i_misc_cap & CDIO_DRIVE_CAP_MISC_SELECT_SPEED ? "Yes" : "No" ); +#if FIXED report( stdout, _("Can detect if CD changed : %s\n"), i_misc_cap & CDIO_DRIVE_CAP_MISC_MEDIA_CHANGED ? "Yes" : "No" ); +#endif report( stdout, _("Can read multiple sessions : %s\n"), i_misc_cap & CDIO_DRIVE_CAP_MISC_MULTI_SESSION ? "Yes" : "No" ); report( stdout, _("Can hard reset device : %s\n\n"), @@ -448,14 +450,24 @@ print_drive_capabilities(cdio_drive_read_cap_t i_read_cap, report( stdout, "Uknown drive reading properties\n" ); } else { report( stdout, "Reading....\n"); + report( stdout, _(" Can read Mode 2 Form 1 : %s\n"), + i_read_cap & CDIO_DRIVE_CAP_READ_MODE2_FORM1 ? "Yes" : "No" ); + report( stdout, _(" Can read Mode 2 Form 2 : %s\n"), + i_read_cap & CDIO_DRIVE_CAP_READ_MODE2_FORM2 ? "Yes" : "No" ); + report( stdout, _(" Can read C2 Errors : %s\n"), + i_read_cap & CDIO_DRIVE_CAP_READ_C2_ERRS ? "Yes" : "No" ); + report( stdout, _(" Can read IRSC : %s\n"), + i_read_cap & CDIO_DRIVE_CAP_READ_ISRC ? "Yes" : "No" ); report( stdout, _(" Can play audio : %s\n"), - i_read_cap & CDIO_DRIVE_CAP_READ_AUDIO ? "Yes" : "No" ); - report( stdout, _(" Can read CD-R : %s\n"), - i_read_cap & CDIO_DRIVE_CAP_READ_CD_R ? "Yes" : "No" ); - report( stdout, _(" Can read CD-RW : %s\n"), - i_read_cap & CDIO_DRIVE_CAP_READ_CD_RW ? "Yes" : "No" ); - report( stdout, _(" Can read DVD-ROM : %s\n"), - i_read_cap & CDIO_DRIVE_CAP_READ_DVD_ROM ? "Yes" : "No" ); + i_read_cap & CDIO_DRIVE_CAP_READ_AUDIO ? "Yes" : "No" ); + report( stdout, _(" Can read CD-DA : %s\n"), + i_read_cap & CDIO_DRIVE_CAP_READ_CD_DA ? "Yes" : "No" ); + report( stdout, _(" Can read CD-R : %s\n"), + i_read_cap & CDIO_DRIVE_CAP_READ_CD_R ? "Yes" : "No" ); + report( stdout, _(" Can read CD-RW : %s\n"), + i_read_cap & CDIO_DRIVE_CAP_READ_CD_RW ? "Yes" : "No" ); + report( stdout, _(" Can read DVD-ROM : %s\n"), + i_read_cap & CDIO_DRIVE_CAP_READ_DVD_ROM ? "Yes" : "No" ); } @@ -465,16 +477,18 @@ print_drive_capabilities(cdio_drive_read_cap_t i_read_cap, report( stdout, "Uknown drive writing properties\n" ); } else { report( stdout, "\nWriting....\n"); + report( stdout, _(" Can write using Burn Proof: %s\n"), + i_write_cap & CDIO_DRIVE_CAP_WRITE_BURN_PROOF ? "Yes" : "No" ); report( stdout, _(" Can write CD-RW : %s\n"), - i_write_cap & CDIO_DRIVE_CAP_WRITE_CD_RW ? "Yes" : "No" ); + i_write_cap & CDIO_DRIVE_CAP_WRITE_CD_RW ? "Yes" : "No" ); report( stdout, _(" Can write DVD-R : %s\n"), - i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_R ? "Yes" : "No" ); + i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_R ? "Yes" : "No" ); report( stdout, _(" Can write DVD-RAM : %s\n"), - i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_RAM ? "Yes" : "No" ); + i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_RAM ? "Yes" : "No" ); report( stdout, _(" Can write DVD-RW : %s\n"), - i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_RW ? "Yes" : "No" ); + i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_RW ? "Yes" : "No" ); report( stdout, _(" Can write DVD+RW : %s\n"), - i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_RPW ? "Yes" : "No" ); + i_write_cap & CDIO_DRIVE_CAP_WRITE_DVD_RPW ? "Yes" : "No" ); } } diff --git a/test/Makefile.am b/test/Makefile.am index 1c091791..7b4a809e 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.34 2004/11/21 04:02:09 rocky Exp $ +# $Id: Makefile.am,v 1.35 2004/12/18 17:29:32 rocky Exp $ # # Copyright (C) 2003, 2004 Rocky Bernstein # @@ -26,7 +26,7 @@ hack = check_sizeof testassert testischar testiso9660 testtoc testbincue noinst_PROGRAMS = $(hack) testdefault -INCLUDES = -I$(top_srcdir) $(LIBCDIO_CFLAGS) +INCLUDES = -I$(top_srcdir) $(LIBCDIO_CFLAGS) $(LIBISO9660_CFLAGS) check_sizeof_LDADD = $(LIBISO9660_LIBS) $(LIBCDIO_LIBS) $(LIBICONV) testassert_LDADD = $(LIBCDIO_LIBS)