diff --git a/configure.ac b/configure.ac index f1da75fc..092e5c43 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.117 2004/12/09 01:03:29 rocky Exp $])dnl +AC_REVISION([$Id: configure.ac,v 1.118 2004/12/15 01:45:15 rocky Exp $])dnl AC_INIT(libcdio, CDIO_VERSION_STR(RELEASE_NUM)) AC_CONFIG_SRCDIR(src/cd-info.c) AM_INIT_AUTOMAKE @@ -243,6 +243,11 @@ AC_SUBST(LIBCDIO_LIBS) AC_SUBST(LIBISO9660_LIBS) case $host_os in + aix*) + AC_DEFINE([HAVE_AIX_CDROM], [1], + [Define 1 if you have AIX CD-ROM support]) + cd_drivers="${cd_drivers}, AIX" + ;; darwin6*|darwin7*) AC_CHECK_HEADERS(IOKit/IOKitLib.h CoreFoundation/CFBase.h, [have_iokit_h="yes"]) diff --git a/include/cdio/cdio.h b/include/cdio/cdio.h index d2979811..4ed8d7cf 100644 --- a/include/cdio/cdio.h +++ b/include/cdio/cdio.h @@ -1,5 +1,5 @@ /* -*- c -*- - $Id: cdio.h,v 1.66 2004/10/24 23:42:39 rocky Exp $ + $Id: cdio.h,v 1.67 2004/12/15 01:45:15 rocky Exp $ Copyright (C) 2001 Herbert Valerio Riedel Copyright (C) 2003, 2004 Rocky Bernstein @@ -30,7 +30,7 @@ /** Application Interface or Protocol version number. If the public * interface changes, we increase this number. */ -#define CDIO_API_VERSION 2 +#define CDIO_API_VERSION 3 #include @@ -91,6 +91,7 @@ extern "C" { typedef enum { DRIVER_UNKNOWN, /**< Used as input when we don't care what kind of driver to use. */ + DRIVER_AIX, /**< AIX driver */ DRIVER_BSDI, /**< BSDI driver */ DRIVER_FREEBSD, /**< FreeBSD driver - includes CAM and ioctl access */ DRIVER_LINUX, /**< GNU/Linux Driver */ @@ -120,7 +121,7 @@ extern "C" { enumeration in driver_id_t. Since we have a bogus (but useful) 0th entry above we don't have to add one. */ -#define CDIO_MIN_DRIVER DRIVER_BSDI +#define CDIO_MIN_DRIVER DRIVER_AIX #define CDIO_MIN_DEVICE_DRIVER CDIO_MIN_DRIVER #define CDIO_MAX_DRIVER DRIVER_NRG #define CDIO_MAX_DEVICE_DRIVER DRIVER_WIN32 @@ -551,6 +552,9 @@ extern "C" { /* True if xxx driver is available. where xxx=linux, solaris, nrg, ... */ + /*! True if AIX driver is available. */ + bool cdio_have_aix (void); + /*! True if BSDI driver is available. */ bool cdio_have_bsdi (void); @@ -680,6 +684,57 @@ extern "C" { */ CdIo * cdio_open_cue (const char *cue_name); + /*! Set up CD-ROM for reading using the AIX driver. The device_name is + the some sort of device name. + + @return the cdio object for subsequent operations. + NULL on error or there is no BSDI driver. + + @see cdio_open + */ + CdIo * cdio_open_am_aix (const char *psz_source_name, + const char *psz_access_mode); + + /*! Set up CD-ROM for reading using the AIX driver. The device_name is + the some sort of device name. + + @return the cdio object for subsequent operations. + NULL on error or there is no BSDI driver. + + @see cdio_open + */ + CdIo * cdio_open_aix (const char *psz_source_name); + + /*! Return a string containing the default device name that the + BSDI driver would use when none is specified. + + @return the cdio object for subsequent operations. + NULL on error or there is no AIX driver. + + @see cdio_open_cd, cdio_open + */ + char * cdio_get_default_device_aix(void); + + /*! Return a list of all of the CD-ROM devices that the AIX driver + can find. + + In some situations of drivers or OS's we can't find a CD device if + there is no media in it and it is possible for this routine to return + NULL even though there may be a hardware CD-ROM. + */ + char **cdio_get_devices_aix(void); + + /*! Set up CD-ROM for reading using the BSDI driver. The device_name is + the some sort of device name. + + @return the cdio object for subsequent operations. + NULL on error or there is no BSDI driver. + + @see cdio_open + */ + CdIo * cdio_open_am_bsdi (const char *psz_source_name, + const char *psz_access_mode); + /*! Set up CD-ROM for reading using the BSDI driver. The device_name is the some sort of device name. diff --git a/lib/Makefile.am b/lib/Makefile.am index d3812784..4ec9e94b 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -1,4 +1,4 @@ -# $Id: Makefile.am,v 1.63 2004/12/04 05:20:35 rocky Exp $ +# $Id: Makefile.am,v 1.64 2004/12/15 01:45:15 rocky Exp $ # # Copyright (C) 2003, 2004 Rocky Bernstein # @@ -56,6 +56,7 @@ EXTRA_DIST = image/Makefile FreeBSD/Makefile MSWindows/Makefile \ noinst_HEADERS = cdio_assert.h cdio_private.h portable.h libcdio_sources = \ + _cdio_aix.c \ _cdio_bsdi.c \ _cdio_generic.c \ _cdio_linux.c \ diff --git a/lib/_cdio_aix.c b/lib/_cdio_aix.c new file mode 100644 index 00000000..4c5961c4 --- /dev/null +++ b/lib/_cdio_aix.c @@ -0,0 +1,1023 @@ +/* + $Id: _cdio_aix.c,v 1.1 2004/12/15 01:45:15 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 +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#ifdef HAVE_STRING_H +#include +#endif + +#include +#include +#include +#include +#include "cdio_assert.h" +#include "cdio_private.h" + +#define DEFAULT_CDIO_DEVICE "/dev/rcd0" + +#ifdef HAVE_AIX_CDROM + +static const char _rcsid[] = "$Id: _cdio_aix.c,v 1.1 2004/12/15 01:45:15 rocky Exp $"; + +#ifdef HAVE_GLOB_H +#include +#endif + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include "cdtext_private.h" + +typedef struct _TRACK_DATA { + uchar Format; + uchar Control : 4; + uchar Adr : 4; + uchar TrackNumber; + uchar Reserved1; + uchar Address[4]; +} TRACK_DATA, *PTRACK_DATA; + +typedef struct _CDROM_TOC { + uchar Length[2]; + uchar FirstTrack; + uchar LastTrack; + TRACK_DATA TrackData[CDIO_CD_MAX_TRACKS+1]; +} CDROM_TOC, *PCDROM_TOC; + + +typedef struct _TRACK_DATA_FULL { + uchar SessionNumber; + uchar Control : 4; + uchar Adr : 4; + uchar TNO; + uchar POINT; /* Tracknumber (of session?) or lead-out/in (0xA0, 0xA1, 0xA2) */ + uchar Min; /* Only valid if disctype is CDDA ? */ + uchar Sec; /* Only valid if disctype is CDDA ? */ + uchar Frame; /* Only valid if disctype is CDDA ? */ + uchar Zero; /* Always zero */ + uchar PMIN; /* start min, if POINT is a track; if lead-out/in 0xA0: First Track */ + uchar PSEC; + uchar PFRAME; +} TRACK_DATA_FULL, *PTRACK_DATA_FULL; + +typedef struct _CDROM_TOC_FULL { + uchar Length[2]; + uchar FirstSession; + uchar LastSession; + TRACK_DATA_FULL TrackData[CDIO_CD_MAX_TRACKS+3]; +} CDROM_TOC_FULL, *PCDROM_TOC_FULL; + + +/* reader */ + +typedef enum { + _AM_NONE, + _AM_CTRL_SCSI +} access_mode_t; + + +typedef struct { + lsn_t start_lsn; + uchar Control : 4; + uchar Format; + cdtext_t cdtext; /* CD-TEXT */ +} track_info_t; + +typedef struct { + /* Things common to all drivers like this. + This must be first. */ + generic_img_private_t gen; + + access_mode_t access_mode; + + /* Some of the more OS specific things. */ + /* Entry info for each track, add 1 for leadout. */ + track_info_t tocent[CDIO_CD_MAX_TRACKS+1]; + +} _img_private_t; + +static track_format_t get_track_format_aix(void *p_user_data, + track_t i_track); + +static access_mode_t +str_to_access_mode_aix(const char *psz_access_mode) +{ + const access_mode_t default_access_mode = _AM_CTRL_SCSI; + + if (NULL==psz_access_mode) return default_access_mode; + + if (!strcmp(psz_access_mode, "SCSI")) + return _AM_CTRL_SCSI; + else { + cdio_warn ("unknown access type: %s. Default SCSI used.", + psz_access_mode); + return default_access_mode; + } +} + + +/*! + Initialize CD device. + */ +static bool +init_aix (_img_private_t *p_env) +{ + + if (p_env->gen.init) { + cdio_warn ("init called more than once"); + return false; + } + + p_env->gen.fd = openx (p_env->gen.source_name, O_RDONLY, NULL, + SC_DIAGNOSTIC); + + /*p_env->gen.fd = openx (p_env->gen.source_name, O_RDONLY, NULL, + IDE_SINGLE);*/ + + if (p_env->gen.fd < 0) + { + cdio_warn ("open (%s): %s", p_env->gen.source_name, strerror (errno)); + return false; + } + + p_env->gen.init = true; + p_env->gen.toc_init = false; + p_env->gen.b_cdtext_init = false; + p_env->gen.b_cdtext_error = false; + p_env->gen.i_joliet_level = 0; /* Assume no Joliet extensions initally */ + p_env->access_mode = _AM_CTRL_SCSI; + + return true; +} + +/*! + Run a SCSI MMC command. + + p_user_data internal CD structure. + i_timeout_ms time in milliseconds we will wait for the command + to complete. + i_cdb Size of p_cdb + p_cdb CDB bytes. + e_direction direction the transfer is to go. + i_buf Size of buffer + p_buf Buffer for data, both sending and receiving + + Return 0 if no error. + */ +static int +run_scsi_cmd_aix( const void *p_user_data, unsigned int i_timeout_ms, + unsigned int i_cdb, const scsi_mmc_cdb_t *p_cdb, + scsi_mmc_direction_t e_direction, + unsigned int i_buf, /*in/out*/ void *p_buf ) +{ + const _img_private_t *p_env = p_user_data; + struct sc_passthru cgc; + int i_rc; + + memset (&cgc, 0, sizeof (cgc)); + memcpy(cgc.scsi_cdb, p_cdb, sizeof(scsi_mmc_cdb_t)); + +#ifdef AIX_DISABLE_ASYNC + /* This enables synchronous negotiation mode. Some CD-ROM drives + * don't handle this well. + */ + cgc.flags = 0; +#else + cgc.flags = SC_ASYNC; +#endif + + if (0 != i_buf) + cgc.flags |= SCSI_MMC_DATA_READ == e_direction ? B_READ : B_WRITE; + + cgc.timeout_value = msecs2secs(i_timeout_ms); + cgc.buffer = p_buf; + cgc.data_length = i_buf; + cgc.command_length= i_cdb; + + i_rc = ioctl(p_env->gen.fd, DK_PASSTHRU, &cgc); + if (-1 == i_rc) { + cdio_warn("DKIOCMD error: %s", strerror(errno)); + } + return i_rc; +} + +/*! + Reads audio sectors from CD device into data starting from lsn. + Returns 0 if no error. + + May have to check size of nblocks. There may be a limit that + can be read in one go, e.g. 25 blocks. +*/ + +static int +_read_audio_sectors_aix (void *p_user_data, void *data, lsn_t lsn, + unsigned int nblocks) +{ + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + +#ifdef FINISHED + struct cdrom_msf *msf = (struct cdrom_msf *) &buf; + msf_t _msf; + struct cdrom_cdda cdda; + + _img_private_t *env = p_user_data; + + cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf); + msf->cdmsf_min0 = from_bcd8(_msf.m); + msf->cdmsf_sec0 = from_bcd8(_msf.s); + msf->cdmsf_frame0 = from_bcd8(_msf.f); + + if (env->gen.ioctls_debugged == 75) + cdio_debug ("only displaying every 75th ioctl from now on"); + + if (env->gen.ioctls_debugged == 30 * 75) + cdio_debug ("only displaying every 30*75th ioctl from now on"); + + if (env->gen.ioctls_debugged < 75 + || (env->gen.ioctls_debugged < (30 * 75) + && env->gen.ioctls_debugged % 75 == 0) + || env->gen.ioctls_debugged % (30 * 75) == 0) + cdio_debug ("reading %d", lsn); + + env->gen.ioctls_debugged++; + + cdda.cdda_addr = lsn; + cdda.cdda_length = nblocks; + cdda.cdda_data = (caddr_t) data; + if (ioctl (env->gen.fd, CDROMCDDA, &cdda) == -1) { + perror ("ioctl(..,CDROMCDDA,..)"); + return 1; + /* exit (EXIT_FAILURE); */ + } +#endif + memcpy (data, buf, CDIO_CD_FRAMESIZE_RAW); + + return 0; +} + +/*! + Reads a single mode1 sector from cd device into data starting + from lsn. Returns 0 if no error. + */ +static int +_read_mode1_sector_aix (void *env, void *data, lsn_t lsn, + bool b_form2) +{ + +#if FIXED + do something here. +#else + return cdio_generic_read_form1_sector(env, data, lsn); +#endif +} + +/*! + Reads nblocks of mode2 sectors from cd device into data starting + from lsn. + Returns 0 if no error. + */ +static int +_read_mode1_sectors_aix (void *p_user_data, void *p_data, lsn_t lsn, + bool b_form2, unsigned int nblocks) +{ + _img_private_t *p_env = p_user_data; + unsigned int i; + int retval; + unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE; + + for (i = 0; i < nblocks; i++) { + if ( (retval = _read_mode1_sector_aix (p_env, + ((char *)p_data) + (blocksize * i), + lsn + i, b_form2)) ) + return retval; + } + return 0; +} + +/*! + Reads a single mode2 sector from cd device into data starting from lsn. + Returns 0 if no error. + */ +static int +_read_mode2_sector_aix (void *p_user_data, void *p_data, lsn_t lsn, + bool b_form2) +{ + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + int offset = 0; +#ifdef FINISHED + struct cdrom_msf *msf = (struct cdrom_msf *) &buf; + msf_t _msf; + struct cdrom_cdxa cd_read; + + _img_private_t *p_env = p_user_data; + + cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf); + msf->cdmsf_min0 = from_bcd8(_msf.m); + msf->cdmsf_sec0 = from_bcd8(_msf.s); + msf->cdmsf_frame0 = from_bcd8(_msf.f); + + if (p_env->gen.ioctls_debugged == 75) + cdio_debug ("only displaying every 75th ioctl from now on"); + + if (p_env->gen.ioctls_debugged == 30 * 75) + cdio_debug ("only displaying every 30*75th ioctl from now on"); + + if (p_env->gen.ioctls_debugged < 75 + || (p_env->gen.ioctls_debugged < (30 * 75) + && p_env->gen.ioctls_debugged % 75 == 0) + || p_env->gen.ioctls_debugged % (30 * 75) == 0) + cdio_debug ("reading %2.2d:%2.2d:%2.2d", + msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0); + + p_env->gen.ioctls_debugged++; + + /* Using CDROMXA ioctl will actually use the same uscsi command + * as ATAPI, except we don't need to be root + */ + offset = CDIO_CD_XA_SYNC_HEADER; + cd_read.cdxa_addr = lsn; + cd_read.cdxa_data = buf; + cd_read.cdxa_length = 1; + cd_read.cdxa_format = CDROM_XA_SECTOR_DATA; + + if (ioctl (p_env->gen.fd, CDROMCDXA, &cd_read) == -1) { + perror ("ioctl(..,CDROMCDXA,..)"); + return 1; + /* exit (EXIT_FAILURE); */ + } +#endif + + if (b_form2) + memcpy (p_data, buf + (offset-CDIO_CD_SUBHEADER_SIZE), M2RAW_SECTOR_SIZE); + else + memcpy (((char *)p_data), buf + offset, CDIO_CD_FRAMESIZE); + + return 0; +} + +/*! + Reads nblocks of mode2 sectors from cd device into data starting + from lsn. + Returns 0 if no error. + */ +static int +_read_mode2_sectors_aix (void *p_user_data, void *data, lsn_t lsn, + bool b_form2, unsigned int nblocks) +{ + _img_private_t *env = p_user_data; + unsigned int i; + int retval; + unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE; + + for (i = 0; i < nblocks; i++) { + if ( (retval = _read_mode2_sector_aix (env, + ((char *)data) + (blocksize * i), + lsn + i, b_form2)) ) + return retval; + } + return 0; +} + + +/*! + Return the size of the CD in logical block address (LBA) units. + */ +static uint32_t +_cdio_stat_size (void *p_user_data) +{ + uint32_t i_size=0; +#ifdef FINISHED + _img_private_t *env = p_user_data; + + struct cdrom_tocentry tocent; + + tocent.cdte_track = CDIO_CDROM_LEADOUT_TRACK; + tocent.cdte_format = CDIO_CDROM_LBA; + if (ioctl (env->gen.fd, CDROMREADTOCENTRY, &tocent) == -1) + { + perror ("ioctl(CDROMREADTOCENTRY)"); + exit (EXIT_FAILURE); + } + + i_size = tocent.cdte_addr.lba; +#endif + + return i_size; +} + +/*! + Set the arg "key" with "value" in the source device. + Currently "source" and "access-mode" are valid keys. + "source" sets the source device in I/O operations + "access-mode" sets the the method of CD access + + 0 is returned if no error was found, and nonzero if there as an error. +*/ +static int +_set_arg_aix (void *p_user_data, const char key[], const char value[]) +{ + _img_private_t *env = p_user_data; + + if (!strcmp (key, "source")) + { + if (!value) + return -2; + + free (env->gen.source_name); + + env->gen.source_name = strdup (value); + } + else if (!strcmp (key, "access-mode")) + { + env->access_mode = str_to_access_mode_aix(key); + } + else + return -1; + + return 0; +} + +/* + * aixioc_send + Issue ioctl command. + + Args: + p_env - environment + cmd - ioctl command + arg - ioctl argument + b_print_err - whether an error message is to be displayed if the + ioctl fails + + Return: + true/false - ioctl successful +*/ +static bool +aixioc_send(_img_private_t *p_env, int cmd, void *arg, bool b_print_err) +{ + struct cd_audio_cmd *ac; + + if (p_env->gen.fd < 0) + return false; + + if (cmd == DKAUDIO) { + ac = (struct cd_audio_cmd *) arg; + ac->status = 0; /* Nuke status for audio cmds */ + } + + if (ioctl(p_env->gen.fd, cmd, arg) < 0) { + if (b_print_err) { + cdio_warn("errno=%d (%s)", errno, strerror(errno)); + } + return false; + } + return true; +} + +/*! + Read and cache the CD's Track Table of Contents and track info. + via a SCSI MMC READ_TOC (FULTOC). Return true if successful or + false if an error. +*/ +static bool +read_toc_ioctl_aix (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + struct cd_audio_cmd cmdbuf; + int i; + + cmdbuf.msf_flag = false; + cmdbuf.audio_cmds = CD_TRK_INFO_AUDIO; + if (!aixioc_send(p_env, IDE_CDAUDIO, (void *) &cmdbuf, true)) + return false; + + p_env->gen.i_first_track = cmdbuf.indexing.track_index.first_track; + p_env->gen.i_tracks = ( cmdbuf.indexing.track_index.last_track + - p_env->gen.i_first_track ) + 1; + + /* Do it again to get the last MSF data */ + cmdbuf.msf_flag = true; + if (!aixioc_send(p_env, IDE_CDAUDIO, (void *) &cmdbuf, true)) + return false; + + cmdbuf.audio_cmds = CD_GET_TRK_MSF; + + for (i = 0; i <= p_env->gen.i_tracks; i++) { + int i_track = i + p_env->gen.i_first_track; + + /* Get the track info */ + cmdbuf.indexing.track_msf.track = i_track; + if (!aixioc_send(p_env, IDE_CDAUDIO, (void *) &cmdbuf, TRUE)) + return false; + + p_env->tocent[ i_track ].start_lsn = + cdio_msf3_to_lba( + cmdbuf.indexing.track_msf.mins, + cmdbuf.indexing.track_msf.secs, + cmdbuf.indexing.track_msf.frames ); + } + + return true; +} + +/*! + Read and cache the CD's Track Table of Contents and track info. + via a SCSI MMC READ_TOC (FULTOC). Return true if successful or + false if an error. +*/ +static bool +read_toc_aix (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + scsi_mmc_cdb_t cdb = {{0, }}; + CDROM_TOC_FULL cdrom_toc_full; + int i_status, i, i_seen_flag; + int i_track_format = 0; + + /* Operation code */ + CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC); + + cdb.field[1] = 0x00; + + /* Format */ + cdb.field[2] = CDIO_MMC_READTOC_FMT_FULTOC; + + memset(&cdrom_toc_full, 0, sizeof(cdrom_toc_full)); + + /* Setup to read header, to get length of data */ + CDIO_MMC_SET_READ_LENGTH16(cdb.field, sizeof(cdrom_toc_full)); + + i_status = run_scsi_cmd_aix (p_env, 1000*60*3, + scsi_mmc_get_cmd_len(cdb.field[0]), + &cdb, SCSI_MMC_DATA_READ, + sizeof(cdrom_toc_full), &cdrom_toc_full); + + if ( 0 != i_status ) { + cdio_debug ("SCSI MMC READ_TOC failed\n"); + return read_toc_ioctl_aix(p_user_data); + } + + i_seen_flag=0; + for( i = 0 ; i <= CDIO_CD_MAX_TRACKS+3; i++ ) { + + if ( 0xA0 == cdrom_toc_full.TrackData[i].POINT ) { + /* First track number */ + p_env->gen.i_first_track = cdrom_toc_full.TrackData[i].PMIN; + i_track_format = cdrom_toc_full.TrackData[i].PSEC; + i_seen_flag|=0x01; + } + + if ( 0xA1 == cdrom_toc_full.TrackData[i].POINT ) { + /* Last track number */ + p_env->gen.i_tracks = + cdrom_toc_full.TrackData[i].PMIN - p_env->gen.i_first_track + 1; + i_seen_flag|=0x02; + } + + if ( 0xA2 == cdrom_toc_full.TrackData[i].POINT ) { + /* Start position of the lead out */ + p_env->tocent[ p_env->gen.i_tracks ].start_lsn = + cdio_msf3_to_lba( + cdrom_toc_full.TrackData[i].PMIN, + cdrom_toc_full.TrackData[i].PSEC, + cdrom_toc_full.TrackData[i].PFRAME ); + p_env->tocent[ p_env->gen.i_tracks ].Control + = cdrom_toc_full.TrackData[i].Control; + p_env->tocent[ p_env->gen.i_tracks ].Format = i_track_format; + i_seen_flag|=0x04; + } + + if (cdrom_toc_full.TrackData[i].POINT > 0 + && cdrom_toc_full.TrackData[i].POINT <= p_env->gen.i_tracks) { + p_env->tocent[ cdrom_toc_full.TrackData[i].POINT - 1 ].start_lsn = + cdio_msf3_to_lba( + cdrom_toc_full.TrackData[i].PMIN, + cdrom_toc_full.TrackData[i].PSEC, + cdrom_toc_full.TrackData[i].PFRAME ); + p_env->tocent[ cdrom_toc_full.TrackData[i].POINT - 1 ].Control = + cdrom_toc_full.TrackData[i].Control; + p_env->tocent[ cdrom_toc_full.TrackData[i].POINT - 1 ].Format = + i_track_format; + + cdio_debug("p_sectors: %i, %lu", i, + (unsigned long int) (p_env->tocent[i].start_lsn)); + + if (cdrom_toc_full.TrackData[i].POINT == p_env->gen.i_tracks) + i_seen_flag|=0x08; + } + + if ( 0x0F == i_seen_flag ) break; + } + if ( 0x0F == i_seen_flag ) { + p_env->gen.toc_init = true; + return true; + } + return false; +} + +/*! + Eject media in CD drive. If successful, as a side effect we + also free obj. + */ +static int +eject_media_aix (void *p_user_data) { + + _img_private_t *env = p_user_data; + int ret; + + close(env->gen.fd); + env->gen.fd = -1; + if (env->gen.fd > -1) { + if ((ret = ioctl(env->gen.fd, DKEJECT)) != 0) { + cdio_generic_free((void *) env); + cdio_warn ("DKEJECT failed: %s", strerror(errno)); + return 1; + } else { + return 0; + } + } + return 2; +} + +#if 0 +static void * +_cdio_malloc_and_zero(size_t size) { + void *ptr; + + if( !size ) size++; + + if((ptr = malloc(size)) == NULL) { + cdio_warn("malloc() failed: %s", strerror(errno)); + return NULL; + } + + memset(ptr, 0, size); + return ptr; +} +#endif + +/*! + Return the value associated with the key "arg". +*/ +static const char * +get_arg_aix (void *p_user_data, const char key[]) +{ + _img_private_t *env = p_user_data; + + if (!strcmp (key, "source")) { + return env->gen.source_name; + } else if (!strcmp (key, "access-mode")) { + switch (env->access_mode) { + case _AM_CTRL_SCSI: + return "SCSI"; + case _AM_NONE: + return "no access method"; + } + } + return NULL; +} + +/*! + Return a string containing the default CD device if none is specified. + */ +char * +cdio_get_default_device_aix(void) +{ + return strdup(DEFAULT_CDIO_DEVICE); +} + +/*! + Get disc type associated with cd object. +*/ + +static discmode_t +get_discmode_aix (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + struct mode_form_op media; + int ret; + + /* Get the media info */ + media.action= CD_GET_MODE; + + if((ret = ioctl(p_env->gen.fd, DK_CD_MODE, &media)) != 0) { + cdio_warn ("DK_CD_MODE failed: %s", strerror(errno)); + return CDIO_DISC_MODE_NO_INFO; + } + switch(media.cd_mode_form) { + case CD_DA: + return CDIO_DISC_MODE_CD_DA; + case DVD_ROM: + return CDIO_DISC_MODE_DVD_ROM; + case DVD_RAM: + return CDIO_DISC_MODE_DVD_RAM; + case DVD_RW: + return CDIO_DISC_MODE_DVD_RW; + default: /* no valid match */ + return CDIO_DISC_MODE_NO_INFO; + } +} + +/*! + Get format of track. +*/ +static track_format_t +get_track_format_aix(void *p_user_data, track_t i_track) +{ + _img_private_t *p_env = p_user_data; + + if ( !p_env ) return TRACK_FORMAT_ERROR; + if (!p_env->gen.init) init_aix(p_env); + if (!p_env->gen.toc_init) read_toc_aix (p_user_data) ; + + if ( (i_track > p_env->gen.i_tracks+p_env->gen.i_first_track) + || i_track < p_env->gen.i_first_track) + return TRACK_FORMAT_ERROR; + + i_track -= p_env->gen.i_first_track; + +#ifdef FINISHED + /* This is pretty much copied from the "badly broken" cdrom_count_tracks + in linux/cdrom.c. + */ + if (p_env->tocent[i_track].cdte_ctrl & CDROM_DATA_TRACK) { + if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_CDI_TRACK) + return TRACK_FORMAT_CDI; + else if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_XA_TRACK) + return TRACK_FORMAT_XA; + else + return TRACK_FORMAT_DATA; + } else + return TRACK_FORMAT_AUDIO; +#else + return TRACK_FORMAT_ERROR; +#endif + +} + +/*! + Return true if we have XA data (green, mode2 form1) or + XA data (green, mode2 form2). That is track begins: + sync - header - subheader + 12 4 - 8 + + FIXME: there's gotta be a better design for this and get_track_format? +*/ +static bool +_cdio_get_track_green(void *p_user_data, track_t i_track) +{ + _img_private_t *p_env = p_user_data; + + if ( !p_env ) return false; + if (!p_env->gen.init) init_aix(p_env); + if (!p_env->gen.toc_init) read_toc_aix (p_env) ; + + if (i_track >= p_env->gen.i_tracks+p_env->gen.i_first_track + || i_track < p_env->gen.i_first_track) + return false; + + i_track -= p_env->gen.i_first_track; + + /* FIXME: Dunno if this is the right way, but it's what + I was using in cd-info for a while. + */ + +#ifdef FINISHED + return ((p_env->tocent[i_track].cdte_ctrl & 2) != 0); +#else + return false; +#endif +} + +/*! + Return the starting MSF (minutes/secs/frames) for track number + track_num in obj. Track numbers usually start at something + greater than 0, usually 1. + + The "leadout" track is specified either by + using track_num LEADOUT_TRACK or the total tracks+1. + False is returned if there is no entry. +*/ +static bool +_cdio_get_track_msf(void *p_user_data, track_t i_track, msf_t *msf) +{ + _img_private_t *p_env = p_user_data; + + if (NULL == msf) return false; + + if (!p_env->gen.init) init_aix(p_env); + if (!p_env->gen.toc_init) read_toc_aix (p_env) ; + + if (i_track == CDIO_CDROM_LEADOUT_TRACK) + i_track = p_env->gen.i_tracks + p_env->gen.i_first_track; + +#ifdef FINISHED + if (i_track > (p_env->gen.i_tracks+p_env->gen.i_first_track) + || i_track < p_env->gen.i_first_track) { + return false; + } else { + struct cdrom_tocentry *msf0 = &p_env->tocent[i_track-1]; + msf->m = to_bcd8(msf0->cdte_addr.msf.minute); + msf->s = to_bcd8(msf0->cdte_addr.msf.second); + msf->f = to_bcd8(msf0->cdte_addr.msf.frame); + return true; + } +#else + return FALSE; +#endif +} + +#else +/*! + Return a string containing the default VCD device if none is specified. + */ +char * +cdio_get_default_device_aix(void) +{ + return strdup(DEFAULT_CDIO_DEVICE); +} + +#endif /* HAVE_AIX_CDROM */ + +/*! + Return an array of strings giving possible CD devices. + */ +char ** +cdio_get_devices_aix (void) +{ +#ifndef HAVE_AIX_CDROM + return NULL; +#else + struct stat st; + char **drives = NULL; + unsigned int i_files=0; +#ifdef HAVE_GLOB_H + unsigned int i; + glob_t globbuf; + + globbuf.gl_offs = 0; + glob("/dev/rcd?", 0, NULL, &globbuf); + for (i=0; iaccess_mode = _AM_CTRL_SCSI; + _data->gen.init = false; + _data->gen.fd = -1; + _data->gen.toc_init = false; + _data->gen.b_cdtext_init = false; + _data->gen.b_cdtext_error = false; + + if (NULL == psz_orig_source) { + psz_source = cdio_get_default_device_aix(); + if (NULL == psz_source) return NULL; + _set_arg_aix(_data, "source", psz_source); + free(psz_source); + } else { + if (cdio_is_device_generic(psz_orig_source)) + _set_arg_aix(_data, "source", psz_orig_source); + else { + /* The below would be okay if all device drivers worked this way. */ +#if 0 + cdio_info ("source %s is not a device", psz_orig_source); +#endif + return NULL; + } + } + + ret = cdio_new ( (void *) _data, &_funcs ); + if (ret == NULL) return NULL; + + if (init_aix(_data)) + return ret; + else { + cdio_generic_free (_data); + return NULL; + } + +#else + return NULL; +#endif /* HAVE_AIX_CDROM */ + +} + +bool +cdio_have_aix (void) +{ +#ifdef HAVE_AIX_CDROM + return true; +#else + return false; +#endif /* HAVE_AIX_CDROM */ +} diff --git a/lib/cdio.c b/lib/cdio.c index 9ff656b0..ee70b9ae 100644 --- a/lib/cdio.c +++ b/lib/cdio.c @@ -1,5 +1,5 @@ /* - $Id: cdio.c,v 1.76 2004/12/04 11:50:40 rocky Exp $ + $Id: cdio.c,v 1.77 2004/12/15 01:45:15 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.76 2004/12/04 11:50:40 rocky Exp $"; +static const char _rcsid[] = "$Id: cdio.c,v 1.77 2004/12/15 01:45:15 rocky Exp $"; const char *track_format2str[6] = @@ -79,7 +79,9 @@ CdIo_driver_t CdIo_driver[CDIO_MAX_DRIVER] = { {0} }; #define CDIO_DRIVER_UNINIT -1 int CdIo_last_driver = CDIO_DRIVER_UNINIT; -#ifdef HAVE_BSDI_CDROM +#ifdef HAVE_AIX_CDROM +const driver_id_t cdio_os_driver = DRIVER_AIX; +#elif HAVE_BSDI_CDROM const driver_id_t cdio_os_driver = DRIVER_BSDI; #elif HAVE_FREEBSD_CDROM const driver_id_t cdio_os_driver = DRIVER_FREEBSD; @@ -117,6 +119,18 @@ CdIo_driver_t CdIo_all_drivers[CDIO_MAX_DRIVER+1] = { NULL }, + {DRIVER_BSDI, + CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK|CDIO_SRC_IS_SCSI_MASK, + "AIX", + "AIX SCSI driver", + &cdio_have_aix, + &cdio_open_aix, + &cdio_open_am_aix, + &cdio_get_default_device_aix, + &cdio_is_device_generic, + &cdio_get_devices_aix + }, + {DRIVER_BSDI, CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK|CDIO_SRC_IS_SCSI_MASK, "BSDI", @@ -1053,6 +1067,7 @@ cdio_open_am (const char *psz_orig_source, driver_id_t driver_id, return ret; } break; + case DRIVER_AIX: case DRIVER_BSDI: case DRIVER_FREEBSD: case DRIVER_LINUX: