diff --git a/THANKS b/THANKS index 3d96c569..92f8e497 100644 --- a/THANKS +++ b/THANKS @@ -22,6 +22,9 @@ Justin B. Ruggles Justin F. Hallett Fink packaging and matters OSX +KO Myung-Hun + OS2 Driver + Kris Verbeeck : CDDB library support from libcddb http://libcddb.sourceforge.net Gentoo ebuild-file diff --git a/configure.ac b/configure.ac index a64e0e30..54be5bdc 100644 --- a/configure.ac +++ b/configure.ac @@ -440,6 +440,13 @@ int has_timeout=sizeof(test.timeout);], # LIBS="$LIBS -lcam" cd_drivers="${cd_drivers}, NetBSD " ;; + os2*) + AC_DEFINE([HAVE_OS2_CDROM], [1], + [Define 1 if you have OS/2 CD-ROM support]) + LT_NO_UNDEFINED="-no-undefined" + LDFLAGS="$LDFLAGS -Zbin-files" + cd_drivers="${cd_drivers}, OS2 " + ;; *) AC_MSG_WARN([Don't have OS CD-reading support for ${host_os}...]) AC_MSG_WARN([Will use generic support.]) @@ -474,6 +481,7 @@ AC_SUBST(HAVE_FREEBSD_CDROM) AC_SUBST(HAVE_LINUX_CDROM) AC_SUBST(HAVE_SOLARIS_CDROM) AC_SUBST(HAVE_WIN32_CDROM) +AC_SUBST(HAVE_OS2_CDROM) LIBCDIO_SOURCE_PATH="`pwd`" AC_DEFINE_UNQUOTED(LIBCDIO_SOURCE_PATH, "$LIBCDIO_SOURCE_PATH", diff --git a/include/cdio/device.h b/include/cdio/device.h index f8b6051a..e3a705e2 100644 --- a/include/cdio/device.h +++ b/include/cdio/device.h @@ -1,7 +1,7 @@ /* -*- c -*- $Id: device.h,v 1.39 2008/03/28 01:28:50 rocky Exp $ - Copyright (C) 2005, 2006, 2008 Rocky Bernstein + Copyright (C) 2005, 2006, 2008, 2009 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 @@ -157,6 +157,7 @@ extern "C" { DRIVER_NETBSD, /**< NetBSD Driver. */ DRIVER_LINUX, /**< GNU/Linux Driver */ DRIVER_SOLARIS, /**< Sun Solaris Driver */ + DRIVER_OS2, /**< IBM OS/2 Driver */ DRIVER_OSX, /**< Apple OSX Driver */ DRIVER_WIN32, /**< Microsoft Windows Driver. Includes ASPI and ioctl access. */ @@ -575,7 +576,7 @@ extern "C" { CdIo_t * cdio_open_aix (const char *psz_source); /*! Return a string containing the default device name that the - BSDI driver would use when none is specified. + AIX driver would use when none is specified. @return the cdio object for subsequent operations. NULL on error or there is no AIX driver. @@ -810,6 +811,44 @@ extern "C" { char **cdio_get_devices_win32(void); + /*! Set up CD-ROM for reading using the IBM OS/2 driver. The + device_name is the some sort of device name. + + NULL is returned on error or there is no OS/2 driver. + + 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. + + @see cdio_open_cd, cdio_open + */ + CdIo_t * cdio_open_os2 (const char *psz_source); + + /*! Set up CD-ROM for reading using the IBM OS/2 driver. The + device_name is the some sort of device name. + + NULL is returned on error or there is no OS/2 driver. + + @see cdio_open_cd, cdio_open + */ + CdIo_t * cdio_open_am_os2 (const char *psz_source, + const char *psz_access_mode); + + /*! Return a string containing the default device name that the + OS/2 driver would use when none is specified. A scan is made + for CD-ROM drives with CDs in them. + + 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_default_device_os2(void); + + /*! Return a list of all of the CD-ROM devices that the OS/2 driver + can find. + */ + char **cdio_get_devices_os2(void); + /*! Set up CD-ROM for reading using the Nero driver. The device_name is the some sort of device name. diff --git a/lib/cdda_interface/common_interface.h b/lib/cdda_interface/common_interface.h index f7dad0a4..aa1b30f3 100644 --- a/lib/cdda_interface/common_interface.h +++ b/lib/cdda_interface/common_interface.h @@ -1,7 +1,7 @@ /* $Id: common_interface.h,v 1.7 2008/04/16 17:00:40 karl Exp $ - Copyright (C) 2004, 2005, 2008 Rocky Bernstein + Copyright (C) 2004, 2005, 2008, 2009 Rocky Bernstein Copyright (C) 1998 Monty xiphmont@mit.edu This program is free software: you can redistribute it and/or modify @@ -28,7 +28,7 @@ #include #include "low_interface.h" -#if defined(HAVE_LSTAT) && !defined(HAVE_WIN32_CDROM) +#if defined(HAVE_LSTAT) && !defined(HAVE_WIN32_CDROM) && !defined(HAVE_OS2_CDROM) /* Define this if the CD-ROM device is a file in the filesystem that can be lstat'd */ diff --git a/lib/driver/Makefile.am b/lib/driver/Makefile.am index 5f07c3a9..4eb777a3 100644 --- a/lib/driver/Makefile.am +++ b/lib/driver/Makefile.am @@ -1,6 +1,6 @@ # $Id: Makefile.am,v 1.28 2008/10/20 01:25:15 rocky Exp $ # -# Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 +# Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 # Rocky Bernstein # # This program is free software: you can redistribute it and/or modify @@ -42,7 +42,7 @@ # public release, then set AGE to 0. A changed interface means an # incompatibility with previous versions. -libcdio_la_CURRENT = 10 +libcdio_la_CURRENT = 11 libcdio_la_REVISION = 0 libcdio_la_AGE = 0 @@ -89,6 +89,7 @@ libcdio_sources = \ MSWindows/win32.c \ MSWindows/win32.h \ netbsd.c \ + os2.c \ osx.c \ read.c \ sector.c \ diff --git a/lib/driver/cdio_private.h b/lib/driver/cdio_private.h index 0bad5a0e..6c463301 100644 --- a/lib/driver/cdio_private.h +++ b/lib/driver/cdio_private.h @@ -1,7 +1,7 @@ /* $Id: cdio_private.h,v 1.37 2008/04/22 15:29:11 karl Exp $ - Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein + Copyright (C) 2003, 2004, 2005, 2008, 2009 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 @@ -485,6 +485,7 @@ extern "C" { driver_return_code_t close_tray_freebsd (const char *psz_drive); driver_return_code_t close_tray_linux (const char *psz_drive); driver_return_code_t close_tray_netbsd (const char *psz_drive); + driver_return_code_t close_tray_os2 (const char *psz_drive); driver_return_code_t close_tray_osx (const char *psz_drive); driver_return_code_t close_tray_solaris (const char *psz_drive); driver_return_code_t close_tray_win32 (const char *psz_drive); @@ -523,6 +524,10 @@ extern "C" { True if Sun Solaris driver is available. */ bool cdio_have_solaris (void); + /*! DEPRICATED: use cdio_have_driver(). + True if IBM OS2 driver is available. */ + bool cdio_have_os2 (void); + /*! DEPRICATED: use cdio_have_driver(). True if Apple OSX driver is available. */ bool cdio_have_osx (void); diff --git a/lib/driver/device.c b/lib/driver/device.c index fc7bd22d..6e108f26 100644 --- a/lib/driver/device.c +++ b/lib/driver/device.c @@ -47,7 +47,8 @@ /* The below array gives of the drivers that are currently available for on a particular host. */ -CdIo_driver_t CdIo_driver[CDIO_MAX_DRIVER] = { {0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} }; +CdIo_driver_t CdIo_driver[CDIO_MAX_DRIVER] = { + {0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL} }; /* The last valid entry of Cdio_driver. -1 or (CDIO_DRIVER_UNINIT) means uninitialzed. @@ -67,6 +68,8 @@ const driver_id_t cdio_os_driver = DRIVER_FREEBSD; const driver_id_t cdio_os_driver = DRIVER_LINUX; #elif HAVE_DARWIN_CDROM const driver_id_t cdio_os_driver = DRIVER_OSX; +#elif HAVE_OS2_CDROM +const driver_id_t cdio_os_driver = DRIVER_OS2; #elif HAVE_SOLARIS_CDROM const driver_id_t cdio_os_driver = DRIVER_SOLARIS; #elif HAVE_WIN32_CDROM @@ -187,6 +190,19 @@ CdIo_driver_t CdIo_all_drivers[CDIO_MAX_DRIVER+1] = { &close_tray_solaris }, + {DRIVER_OS2, + CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK|CDIO_SRC_IS_SCSI_MASK, + "OS2", + "IBM OS/2 driver", + &cdio_have_os2, + &cdio_open_os2, + &cdio_open_am_os2, + &cdio_get_default_device_os2, + &cdio_is_device_os2, + &cdio_get_devices_os2, + &close_tray_os2 + }, + {DRIVER_OSX, CDIO_SRC_IS_DEVICE_MASK|CDIO_SRC_IS_NATIVE_MASK|CDIO_SRC_IS_SCSI_MASK, "OS X", @@ -942,6 +958,7 @@ cdio_open_am (const char *psz_orig_source, driver_id_t driver_id, case DRIVER_SOLARIS: case DRIVER_WIN32: case DRIVER_OSX: + case DRIVER_OS2: case DRIVER_NRG: case DRIVER_BINCUE: case DRIVER_CDRDAO: diff --git a/lib/driver/generic.h b/lib/driver/generic.h index 595d3c1b..cfc339b5 100644 --- a/lib/driver/generic.h +++ b/lib/driver/generic.h @@ -134,6 +134,12 @@ extern "C" { */ bool cdio_is_device_win32(const char *source_name); + /*! + Return true if source_name could be a device containing a CD-ROM on + OS/2 + */ + bool cdio_is_device_os2(const char *source_name); + /*! Return true if source_name could be a device containing a CD-ROM on diff --git a/lib/driver/os2.c b/lib/driver/os2.c new file mode 100644 index 00000000..6e6d29f5 --- /dev/null +++ b/lib/driver/os2.c @@ -0,0 +1,1552 @@ +/* + $Id: os2.c,v 1.30 2008/04/21 18:30:21 karl Exp $ + + Copyright (C) 2009 KO Myung-Hun + + 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 3 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, see . +*/ + +/* This file contains OS/2-specific code using the DosDevIOCtl + access method. +*/ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +static const char _rcsid[] = "$Id: os2.c,v 1.30 2008/04/21 18:30:21 karl Exp $"; + +#include +#include +#include +#include +#include "cdio_assert.h" +#include "cdio_private.h" + +#include + +#ifdef HAVE_OS2_CDROM + +#define INCL_DOS +#define INCL_DOSDEVIOCTL +#include + +#include + + +typedef struct { + lsn_t lsn_start; + UCHAR uc_adr; + UCHAR uc_control; +} toc_t; + +typedef enum { + _AM_NONE, + _AM_OS2, +} access_mode_t; + +typedef struct { + /* Things common to all drivers like this. + This must be first. */ + generic_img_private_t gen; + + access_mode_t access_mode; + + /* Track information */ + toc_t toc[CDIO_CD_MAX_TRACKS + 1]; /* 1 more for leadout */ + int i_first_track; + int i_last_track; + + /* Some of the more OS specific things. */ + HFILE h_cd; + BYTE uc_drive; +} _img_private_t; + +#pragma pack(1) + +static track_format_t +get_track_format_os2(const _img_private_t *p_env, track_t i_track); + +static bool read_toc_os2 (void *p_user_data); + +static int +run_mmc_cmd_os2( void *p_user_data, unsigned int i_timeout_ms, + unsigned int i_cdb, const mmc_cdb_t *p_cdb, + cdio_mmc_direction_t e_direction, + unsigned int i_buf, /*in/out*/ void *p_buf ); + +/*! + Set the volume of an audio CD. + + @param p_cdio the CD object to be acted upon. + +*/ +static driver_return_code_t +audio_get_volume_os2 (void *p_user_data, + /*out*/ cdio_audio_volume_t *p_volume) +{ + _img_private_t *p_env = p_user_data; + + struct { + UCHAR auch_sign[4]; + } s_param = {{'C', 'D', '0', '1'}}; + + struct { + struct { + BYTE uc_in_ch; + BYTE uc_vol; + } as_out_ch[4]; + } s_data; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + int i; + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMAUDIO, CDROMAUDIO_GETCHANNEL, + &s_param, sizeof( s_param ), &ul_param_len, + &s_data, sizeof( s_data ), &ul_data_len ); + + if( rc ) + { + cdio_warn("audio_get_volume_os2 : DosDevIOCtl(GETCHANNEL) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + for( i = 0; i < 4; i++ ) + p_volume->level[ i ] = s_data.as_out_ch[ i ].uc_vol; + + return DRIVER_OP_SUCCESS; +} + +/*! + Pause playing CD through analog output + + @param p_cdio the CD object to be acted upon. +*/ +static driver_return_code_t +audio_pause_os2 (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + + struct { + UCHAR auch_sign[4]; + } s_param = {{'C', 'D', '0', '1'}}; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMAUDIO, CDROMAUDIO_STOPAUDIO, + &s_param, sizeof( s_param ), &ul_param_len, + NULL, 0, &ul_data_len ); + + if( rc ) + { + cdio_warn("audio_pause_os2 : DosDevIOCtl(STOPAUDIO) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + return DRIVER_OP_SUCCESS; +} + +/*! + Playing CD through analog output at the given MSF. + + @param p_cdio the CD object to be acted upon. +*/ +static driver_return_code_t +audio_play_msf_os2 (void *p_user_data, msf_t *p_start_msf, msf_t *p_end_msf) +{ + _img_private_t *p_env = p_user_data; + + struct { + UCHAR auch_sign[4]; + BYTE uc_access_mode; + BYTE uc_start_msf_f; + BYTE uc_start_msf_s; + BYTE uc_start_msf_m; + BYTE uc_start_msf_reserved; + BYTE uc_end_msf_f; + BYTE uc_end_msf_s; + BYTE uc_end_msf_m; + BYTE uc_end_msf_reserved; + } s_param = { + .auch_sign = {'C', 'D', '0', '1'}, + .uc_access_mode = 01, /* use MSF format */ + }; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + + s_param.uc_start_msf_m = cdio_from_bcd8(p_start_msf->m); + s_param.uc_start_msf_s = cdio_from_bcd8(p_start_msf->s); + s_param.uc_start_msf_f = cdio_from_bcd8(p_start_msf->f); + + s_param.uc_end_msf_m = cdio_from_bcd8(p_end_msf->m); + s_param.uc_end_msf_s = cdio_from_bcd8(p_end_msf->s); + s_param.uc_end_msf_f = cdio_from_bcd8(p_end_msf->f); + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMAUDIO, CDROMAUDIO_PLAYAUDIO, + &s_param, sizeof( s_param ), &ul_param_len, + NULL, 0, &ul_data_len ); + + if( rc ) + { + cdio_warn("audio_play_msf_os2 : DosDevIOCtl(PLAYAUDIO) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + return DRIVER_OP_SUCCESS; +} + +/*! + Read Audio Subchannel information + + @param p_cdio the CD object to be acted upon. + +*/ +static driver_return_code_t +audio_read_subchannel_os2 (void *p_user_data, + cdio_subchannel_t *p_subchannel) +{ + _img_private_t *p_env = p_user_data; + + struct { + UCHAR auch_sign[4]; + } s_param = {{'C', 'D', '0', '1'}}; + + struct { + BYTE uc_control_and_adr; + BYTE uc_track_number; /* in BCD */ + BYTE uc_index; /* in BCD */ + BYTE uc_running_time_in_track_m; + BYTE uc_running_time_in_track_s; + BYTE uc_running_time_in_track_f; + BYTE uc_reserved; + BYTE uc_running_time_on_disk_m; + BYTE uc_running_time_on_disk_s; + BYTE uc_running_time_on_disk_f; + } s_data_subchannel_q; + + struct { + USHORT us_audio_status_bits; + ULONG ul_start_msf; + ULONG ul_end_msf; + } s_data_audio_status; + + ULONG ul_data_device_status; + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMAUDIO, CDROMAUDIO_GETSUBCHANNELQ, + &s_param, sizeof( s_param ), &ul_param_len, + &s_data_subchannel_q, sizeof( s_data_subchannel_q ), &ul_data_len ); + + if( rc ) + { + cdio_warn("audio_read_subchannel_os2 : DosDevIOCtl(GETSUBCHANNELQ) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIOSTATUS, + &s_param, sizeof( s_param ), &ul_param_len, + &s_data_audio_status, sizeof( s_data_audio_status ), &ul_data_len ); + + if( rc ) + { + cdio_warn("audio_read_subchannel_os2 : DosDevIOCtl(GETAUDIOSTATUS) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMDISK, CDROMDISK_DEVICESTATUS, + &s_param, sizeof( s_param ), &ul_param_len, + &ul_data_device_status, sizeof( ul_data_device_status ), &ul_data_len ); + + if( rc ) + { + cdio_warn("audio_read_subchannel_os2 : DosDevIOCtl(DEVICESTATUS) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + p_subchannel->track = cdio_from_bcd8(s_data_subchannel_q.uc_track_number); + p_subchannel->index = cdio_from_bcd8(s_data_subchannel_q.uc_index); + + p_subchannel->abs_addr.m = cdio_to_bcd8(s_data_subchannel_q.uc_running_time_on_disk_m); + p_subchannel->abs_addr.s = cdio_to_bcd8(s_data_subchannel_q.uc_running_time_on_disk_s); + p_subchannel->abs_addr.f = cdio_to_bcd8(s_data_subchannel_q.uc_running_time_on_disk_f); + p_subchannel->rel_addr.m = cdio_to_bcd8(s_data_subchannel_q.uc_running_time_in_track_m); + p_subchannel->rel_addr.s = cdio_to_bcd8(s_data_subchannel_q.uc_running_time_in_track_s); + p_subchannel->rel_addr.f = cdio_to_bcd8(s_data_subchannel_q.uc_running_time_in_track_f); + + p_subchannel->address = s_data_subchannel_q.uc_control_and_adr & 0x0F; + p_subchannel->control = ( s_data_subchannel_q.uc_control_and_adr >> 4 ) & 0x0F; + + if( ul_data_device_status & 0x1000 ) + p_subchannel->audio_status = CDIO_MMC_READ_SUB_ST_PLAY; + else if( s_data_audio_status.us_audio_status_bits & 1 ) + p_subchannel->audio_status = CDIO_MMC_READ_SUB_ST_PAUSED; + else if( s_data_audio_status.ul_start_msf == 0 && + s_data_audio_status.ul_end_msf == 0 ) + p_subchannel->audio_status = CDIO_MMC_READ_SUB_ST_NO_STATUS; + else + p_subchannel->audio_status = CDIO_MMC_READ_SUB_ST_COMPLETED; + + return DRIVER_OP_SUCCESS; +} + + /*! + Resume playing an audio CD. + + @param p_cdio the CD object to be acted upon. + + */ +static driver_return_code_t +audio_resume_os2 (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + + struct { + UCHAR auch_sign[4]; + } s_param = {{'C', 'D', '0', '1'}}; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMAUDIO, CDROMAUDIO_RESUMEAUDIO, + &s_param, sizeof( s_param ), &ul_param_len, + NULL, 0, &ul_data_len ); + + if( rc ) + { + cdio_warn("audio_resume_os2 : DosDevIOCtl(RESUMEAUDIO) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + return DRIVER_OP_SUCCESS; +} + +/*! + Set the volume of an audio CD. + + @param p_cdio the CD object to be acted upon. + +*/ +static driver_return_code_t +audio_set_volume_os2 ( void *p_user_data, cdio_audio_volume_t *p_volume) +{ + _img_private_t *p_env = p_user_data; + + struct { + UCHAR auch_sign[4]; + } s_param = {{'C', 'D', '0', '1'}}; + + struct { + struct { + BYTE uc_in_ch; + BYTE uc_vol; + } as_out_ch[4]; + } s_data; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + int i; + + /* first retrive current input ch. */ + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMAUDIO, CDROMAUDIO_GETCHANNEL, + &s_param, sizeof( s_param ), &ul_param_len, + &s_data, sizeof( s_data ), &ul_data_len ); + + if( rc ) + { + cdio_warn("audio_set_volume_os2 : DosDevIOCtl(GETCHANNEL) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + for( i = 0; i < 4; i++ ) + s_data.as_out_ch[ i ].uc_vol = p_volume->level[ i ]; + + /* now set volumes */ + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMAUDIO, CDROMAUDIO_SETCHANNELCTRL, + &s_param, sizeof( s_param ), &ul_param_len, + &s_data, sizeof( s_data ), &ul_data_len ); + + if( rc ) + { + cdio_warn("audio_set_volume_os2 : DosDevIOCtl(SETCHANNELCTRL) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + return DRIVER_OP_SUCCESS; +} + +static driver_return_code_t +audio_stop_os2 (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + + struct { + UCHAR auch_sign[4]; + } s_param = {{'C', 'D', '0', '1'}}; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMAUDIO, CDROMAUDIO_STOPAUDIO, + &s_param, sizeof( s_param ), &ul_param_len, + NULL, 0, &ul_data_len ); + + if( rc ) + { + cdio_warn("audio_stop_os2 : DosDevIOCtl(STOPAUDIO) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + return DRIVER_OP_SUCCESS; +} + +/*! + Get disc type associated with cd object. +*/ +static discmode_t +dvd_discmode_os2 (_img_private_t *p_env) +{ + discmode_t discmode=CDIO_DISC_MODE_NO_INFO; + driver_return_code_t rc; + + /* See if this is a DVD. */ + cdio_dvd_struct_t dvd; /* DVD READ STRUCT for layer 0. */ + + dvd.physical.type = CDIO_DVD_STRUCT_PHYSICAL; + dvd.physical.layer_num = 0; + + rc = mmc_get_dvd_struct_physical_private (p_env, &run_mmc_cmd_os2, + &dvd); + + if (DRIVER_OP_SUCCESS == rc) { + switch(dvd.physical.layer[0].book_type) { + case CDIO_DVD_BOOK_DVD_ROM: return CDIO_DISC_MODE_DVD_ROM; + case CDIO_DVD_BOOK_DVD_RAM: return CDIO_DISC_MODE_DVD_RAM; + case CDIO_DVD_BOOK_DVD_R: return CDIO_DISC_MODE_DVD_R; + case CDIO_DVD_BOOK_DVD_RW: return CDIO_DISC_MODE_DVD_RW; + case CDIO_DVD_BOOK_DVD_PR: return CDIO_DISC_MODE_DVD_PR; + case CDIO_DVD_BOOK_DVD_PRW: return CDIO_DISC_MODE_DVD_PRW; + default: return CDIO_DISC_MODE_DVD_OTHER; + } + } + return discmode; +} + +/*! + Get disc type associated with the cd object. +*/ +static discmode_t +get_discmode_os2(void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + + track_t i_track; + discmode_t discmode; + + if (!p_env) return CDIO_DISC_MODE_ERROR; + + discmode = dvd_discmode_os2(p_env); + + if (CDIO_DISC_MODE_NO_INFO != discmode) return discmode; + + if (!p_env->gen.toc_init) read_toc_os2 (p_env); + + if (!p_env->gen.toc_init) return CDIO_DISC_MODE_ERROR; + + for (i_track = p_env->gen.i_first_track; + i_track < p_env->gen.i_first_track + p_env->gen.i_tracks ; + i_track ++) { + track_format_t track_fmt=get_track_format_os2(p_env, i_track); + + switch(track_fmt) { + case TRACK_FORMAT_AUDIO: + switch(discmode) { + case CDIO_DISC_MODE_NO_INFO: + discmode = CDIO_DISC_MODE_CD_DA; + break; + case CDIO_DISC_MODE_CD_DA: + case CDIO_DISC_MODE_CD_MIXED: + case CDIO_DISC_MODE_ERROR: + /* No change*/ + break; + default: + discmode = CDIO_DISC_MODE_CD_MIXED; + } + break; + case TRACK_FORMAT_XA: + switch(discmode) { + case CDIO_DISC_MODE_NO_INFO: + discmode = CDIO_DISC_MODE_CD_XA; + break; + case CDIO_DISC_MODE_CD_XA: + case CDIO_DISC_MODE_CD_MIXED: + case CDIO_DISC_MODE_ERROR: + /* No change*/ + break; + default: + discmode = CDIO_DISC_MODE_CD_MIXED; + } + break; + case TRACK_FORMAT_DATA: + switch(discmode) { + case CDIO_DISC_MODE_NO_INFO: + discmode = CDIO_DISC_MODE_CD_DATA; + break; + case CDIO_DISC_MODE_CD_DATA: + case CDIO_DISC_MODE_CD_MIXED: + case CDIO_DISC_MODE_ERROR: + /* No change*/ + break; + default: + discmode = CDIO_DISC_MODE_CD_MIXED; + } + break; + case TRACK_FORMAT_ERROR: + default: + discmode = CDIO_DISC_MODE_ERROR; + } + } + return discmode; +} + +#define CDROMDISK_EXECMD 0x7A + +/* 0, if transfer data to device, 1, if transfer data from device */ +#define EX_DIRECTION_IN 0x0001 +/* 0, if don't check playing audio, 1, if device plays audio return error */ +#define EX_PLAYING_CHK 0x0002 + +/*! + Run a SCSI MMC command. + + env private CD structure + i_timeout_ms time in milliseconds we will wait for the command + to complete. If this value is -1, use the default + time-out value. + p_buf Buffer for data, both sending and receiving + i_buf Size of buffer + e_direction direction the transfer is to go. + cdb CDB bytes. All values that are needed should be set on + input. We'll figure out what the right CDB length should be. + + Return 0 if command completed successfully. + */ +static int +run_mmc_cmd_os2( void *p_user_data, unsigned int i_timeout_ms, + unsigned int i_cdb, const mmc_cdb_t *p_cdb, + cdio_mmc_direction_t e_direction, + unsigned int i_buf, /*in/out*/ void *p_buf ) +{ + _img_private_t *p_env = p_user_data; + + struct { + UCHAR auch_sign[4]; // 'CD01' + USHORT us_data_length; // length of the Data Packet + USHORT us_cmd_length; // length of the Command Buffer + USHORT us_flags; // flags + BYTE auc_cmd_buffer[16]; // Command Buffer for SCSI command + } s_param = { + .auch_sign = {'C', 'D', '0', '1'}, + }; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + + s_param.us_data_length = i_buf; + s_param.us_cmd_length = i_cdb; + s_param.us_flags = + ( e_direction == SCSI_MMC_DATA_READ ) ? EX_DIRECTION_IN : 0; + + memcpy( s_param.auc_cmd_buffer, p_cdb, i_cdb ); + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMDISK, CDROMDISK_EXECMD, + &s_param, sizeof( s_param ), &ul_param_len, + p_buf, i_buf, &ul_data_len ); + + if( rc ) + { + cdio_warn("run_mmc_cmd_os2 : DosDevIOCtl(EXECMD) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + return DRIVER_OP_SUCCESS; +} + +/*! + Initialize CD device. + */ +static bool +init_os2 (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + + ULONG ul_action; + ULONG rc; + + if (p_env->gen.init) { + cdio_warn ("init called more than once"); + return false; + } + + /* Initializations */ + p_env->h_cd = 0; + + rc = DosOpen((PSZ)p_env->gen.source_name, &p_env->h_cd, + &ul_action, 0, FILE_NORMAL, + OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, + OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE | OPEN_FLAGS_DASD, + NULL ); + if( rc ) + { + cdio_warn("init_os2 : DosOpen(%s) = %ld\n", p_env->gen.source_name, rc ); + + return false; + } + + p_env->uc_drive = toupper( p_env->gen.source_name[ 0 ]) - 'A'; + + 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.fd = p_env->h_cd; + + return true; +} + +/*! + Release and free resources associated with cd. + */ +static void +free_os2 (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + + if( !p_env ) + return; + + free (p_env->gen.source_name); + + if( p_env->h_cd ) + DosClose( p_env->h_cd ); + + free (p_env); + +} + +/*! + Reads i_blocks of audio sectors from cd device into p_data starting + from i_lsn. + Returns DRIVER_OP_SUCCESS if no error. + */ +static int +read_audio_sectors_os2 (void *p_user_data, void *p_buf, lsn_t i_lsn, + unsigned int i_blocks) +{ + _img_private_t *p_env = p_user_data; + + struct + { + UCHAR auch_sign[ 4 ]; + BYTE uc_addr_mode; + USHORT us_sectors; + ULONG ul_start_sector; + BYTE uc_reserved; + BYTE uc_interleaved_size; + } s_param = { + .auch_sign = {'C', 'D', '0', '1'}, + .uc_addr_mode = 0, /* use LBA format */ + }; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + + s_param.us_sectors = i_blocks; + s_param.ul_start_sector = i_lsn; + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMDISK, CDROMDISK_READLONG, + &s_param, sizeof( s_param ), &ul_param_len, + p_buf, CDIO_CD_FRAMESIZE_RAW * i_blocks, &ul_data_len ); + + if( rc ) + { + cdio_warn("read_audio_sectors_os2 : DosDevIOCtl(READLONG) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + return DRIVER_OP_SUCCESS; +} + +/*! + Reads a single raw sector using the DosDevIOCtl method into + data starting from lsn. Returns 0 if no error. + */ +static int +read_raw_sector (_img_private_t *p_env, void *p_buf, lsn_t lsn) +{ + struct + { + UCHAR auch_sign[ 4 ]; + BYTE uc_addr_mode; + USHORT us_sectors; + ULONG ul_start_sector; + BYTE uc_reserved; + BYTE uc_interleaved_size; + } s_param = { + .auch_sign = {'C', 'D', '0', '1'}, + .uc_addr_mode = 0, /* use LBA format */ + .us_sectors = 1, + }; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + + s_param.ul_start_sector = lsn; + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMDISK, CDROMDISK_READLONG, + &s_param, sizeof( s_param ), &ul_param_len, + p_buf, CDIO_CD_FRAMESIZE_RAW, &ul_data_len ); + + if( rc ) + { + cdio_warn("read_raw_sector : DosDevIOCtl(READLONG) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + return DRIVER_OP_SUCCESS; +} + +/*! + Reads a single mode1 sector from cd device into data starting from + lsn. Returns 0 if no error. + */ +static int +read_mode1_sector_os2 (void *p_user_data, void *p_buf, lsn_t lsn, + bool b_form2) +{ + _img_private_t *p_env = p_user_data; + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + int ret = read_raw_sector (p_env, buf, lsn); + + if ( 0 != ret) return ret; + + memcpy (p_buf, + buf + CDIO_CD_SYNC_SIZE+CDIO_CD_HEADER_SIZE, + b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE); + + return 0; +} + +/*! + Reads nblocks of mode1 sectors from cd device into data starting + from lsn. + Returns 0 if no error. + */ +static int +read_mode1_sectors_os2 (void *p_user_data, void *p_buf, lsn_t lsn, + bool b_form2, unsigned int nblocks) +{ + _img_private_t *p_env = p_user_data; + int i; + int retval; + + for (i = 0; i < nblocks; i++) { + if (b_form2) { + retval = read_mode1_sector_os2 ( + p_env, ((char *)p_buf) + + (M2RAW_SECTOR_SIZE * i), + lsn + i, true); + if ( retval ) return retval; + } else { + char buf[M2RAW_SECTOR_SIZE] = { 0, }; + if ( (retval = read_mode1_sector_os2 (p_env, buf, lsn + i, false)) ) + return retval; + + memcpy (((char *)p_buf) + (CDIO_CD_FRAMESIZE * i), + buf, CDIO_CD_FRAMESIZE); + } + } + 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_os2 (void *p_user_data, void *data, lsn_t lsn, + bool b_form2) +{ + _img_private_t *p_env = p_user_data; + char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; + int ret = read_raw_sector (p_env, buf, lsn); + + if ( 0 != ret) return ret; + + memcpy (data, + buf + CDIO_CD_SYNC_SIZE + CDIO_CD_XA_HEADER, + b_form2 ? M2RAW_SECTOR_SIZE: 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_os2 (void *p_user_data, void *data, lsn_t lsn, + bool b_form2, unsigned int i_blocks) +{ + int i; + int retval; + unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE; + + for (i = 0; i < i_blocks; i++) { + if ( (retval = read_mode2_sector_os2 (p_user_data, + ((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 lsn_t +get_disc_last_lsn_os2 (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + + struct { + UCHAR auch_sign[4]; + } s_param = {{'C', 'D', '0', '1'}}; + + ULONG ul_data_volume_size; + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMDISK, CDROMDISK_GETVOLUMESIZE, + &s_param, sizeof( s_param ), &ul_param_len, + &ul_data_volume_size, sizeof( ul_data_volume_size ), &ul_data_len ); + + if( rc ) + { + cdio_warn("get_disc_last_lsn_os2 : DosDevIOCtl(GETVOLUMESIZE) = 0x%lx\n", rc ); + + return CDIO_INVALID_LSN; + } + + return ul_data_volume_size; +} + +/*! + Set the key "arg" to "value" in source device. +*/ +static int +set_arg_os2 (void *p_user_data, const char key[], const char value[]) +{ + _img_private_t *p_env = p_user_data; + + if (!strcmp (key, "source")) + { + if (!value) + return DRIVER_OP_ERROR; + + free (p_env->gen.source_name); + p_env->gen.source_name = strdup (value); + } + else if (!strcmp (key, "access-mode")) + { + if (!strcmp(value, "OS2")) + p_env->access_mode = _AM_OS2; + else + cdio_warn ("unknown access type: %s. ignored.", value); + } + else + return DRIVER_OP_ERROR; + + return DRIVER_OP_SUCCESS; +} + +/*! + Read and cache the CD's Track Table of Contents and track info. + Return true if successful or false if an error. +*/ +static bool +read_toc_os2 (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + + struct { + UCHAR auch_sign[4]; + } s_param_disk = {{'C', 'D', '0', '1'}}; + + struct { + BYTE uc_first_track; + BYTE uc_last_track; + ULONG ul_lead_out_addr; /* in MSF */ + } s_data_disk; + + struct { + UCHAR auch_sign[4]; + BYTE uc_track; + } s_param_track = { + .auch_sign = {'C', 'D', '0', '1'}, + }; + + struct { + ULONG ul_track_addr; /* in MSF */ + BYTE uc_control_and_adr; + } s_data_track; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + int i_track; + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIODISK, + &s_param_disk, sizeof( s_param_disk ), &ul_param_len, + &s_data_disk, sizeof( s_data_disk ), &ul_data_len ); + + if( rc ) + { + cdio_warn("read_toc_os2 : DosDevIOCtl(GETAUDIODISK) = 0x%lx\n", rc ); + + return false; + } + + p_env->gen.i_first_track = s_data_disk.uc_first_track; + p_env->gen.i_tracks = s_data_disk.uc_last_track - s_data_disk.uc_first_track + 1; + + p_env->i_first_track = s_data_disk.uc_first_track; + p_env->i_last_track = s_data_disk.uc_last_track; + + for( i_track = p_env->i_first_track; i_track <= p_env->i_last_track; i_track++ ) + { + s_param_track.uc_track = i_track; + + rc = DosDevIOCtl( + p_env->h_cd, IOCTL_CDROMAUDIO, CDROMAUDIO_GETAUDIOTRACK, + &s_param_track, sizeof( s_param_track ), &ul_param_len, + &s_data_track, sizeof( s_data_track ), &ul_data_len ); + + if( rc ) + { + cdio_warn("read_toc_os2 : DosDevIOCtl(GETAUDIOTRACK) = 0x%lx\n", rc ); + + return false; + } + + p_env->toc[i_track].lsn_start = + cdio_lba_to_lsn( cdio_msf3_to_lba( + ( s_data_track.ul_track_addr >> 16 ) & 0xFF, + ( s_data_track.ul_track_addr >> 8 ) & 0xFF, + s_data_track.ul_track_addr & 0xFF )); + + p_env->toc[i_track].uc_adr = s_data_track.uc_control_and_adr & 0x0F; + p_env->toc[i_track].uc_control = ( s_data_track.uc_control_and_adr >> 4 ) & 0x0F; + + p_env->gen.track_flags[i_track].preemphasis = + p_env->toc[i_track].uc_control & 0x01 + ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE; + + p_env->gen.track_flags[i_track].copy_permit = + p_env->toc[i_track].uc_control & 0x02 + ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE; + + p_env->gen.track_flags[i_track].channels = + p_env->toc[i_track].uc_control & 0x08 ? 4 : 2; + } + + /* store lead out info */ + p_env->toc[p_env->i_last_track + 1].lsn_start = + cdio_lba_to_lsn( cdio_msf3_to_lba( + ( s_data_disk.ul_lead_out_addr >> 16 ) & 0xFF, + ( s_data_disk.ul_lead_out_addr >> 8 ) & 0xFF, + s_data_disk.ul_lead_out_addr & 0xFF )); + + p_env->gen.toc_init = true; + + return true; +} + +/*! + Eject media. + */ +static driver_return_code_t +eject_media_os2 (void *p_user_data) +{ + _img_private_t *p_env = p_user_data; + + struct { + BYTE uc_cmd_info; + BYTE uc_drive; + } s_param; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + + s_param.uc_cmd_info = 2; + s_param.uc_drive = p_env->uc_drive; + + rc = DosDevIOCtl( + ( HFILE )-1, IOCTL_DISK, DSK_UNLOCKEJECTMEDIA, + &s_param, sizeof( s_param ), &ul_param_len, + NULL, 0, &ul_data_len ); + + if( rc ) + { + cdio_warn("eject_media_os2 : DosDevIOCtl(UNLOCKEJECTMEDIA) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + return DRIVER_OP_SUCCESS; +} + +/*! + Return the value associated with the key "arg". +*/ +static const char * +get_arg_os2 (void *p_user_data, const char key[]) +{ + _img_private_t *p_env = p_user_data; + + if (!strcmp (key, "source")) { + return p_env->gen.source_name; + } else if (!strcmp (key, "access-mode")) { + switch (p_env->access_mode) { + case _AM_OS2: + return "OS2"; + case _AM_NONE: + return "no access method"; + } + } + return NULL; +} + +/*! + Return the media catalog number MCN. + + Note: string is malloc'd so caller should free() then returned + string when done with it. + + */ +static char * +_cdio_get_mcn (const void *p_user_data) { + const _img_private_t *p_env = p_user_data; + return mmc_get_mcn( p_env->gen.cdio ); +} + +/*! + Get the format (XA, DATA, AUDIO) of a track. +*/ +static track_format_t +get_track_format_os2(const _img_private_t *p_env, track_t i_track) +{ + /* This is pretty much copied from the "badly broken" cdrom_count_tracks + in linux/cdrom.c. + */ + + if (p_env->toc[i_track].uc_control & 0x04) { + if (p_env->toc[i_track].uc_adr == 0x10) + return TRACK_FORMAT_CDI; + else if (p_env->toc[i_track].uc_adr == 0x20) + return TRACK_FORMAT_XA; + else + return TRACK_FORMAT_DATA; + } else + return TRACK_FORMAT_AUDIO; +} + +/*! + Get format of track. +*/ +static track_format_t +_cdio_get_track_format(void *p_obj, track_t i_track) +{ + _img_private_t *p_env = p_obj; + + if ( !p_env ) + return TRACK_FORMAT_ERROR; + + if (!p_env->gen.toc_init) + if (!read_toc_os2 (p_env)) + return TRACK_FORMAT_ERROR; + + if ( i_track < p_env->gen.i_first_track + || i_track >= p_env->gen.i_tracks + p_env->gen.i_first_track ) + return TRACK_FORMAT_ERROR; + + return get_track_format_os2(p_env, i_track); +} + +/*! + 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_obj, track_t i_track) +{ + _img_private_t *p_env = p_obj; + + switch (_cdio_get_track_format(p_env, i_track)) { + case TRACK_FORMAT_XA: + return true; + case TRACK_FORMAT_ERROR: + case TRACK_FORMAT_CDI: + case TRACK_FORMAT_AUDIO: + return false; + case TRACK_FORMAT_DATA: + default: + break; + } + + /* FIXME: Dunno if this is the right way, but it's what + I was using in cd-info for a while. + */ + return ((p_env->toc[i_track].uc_control & 2) != 0); +} + +/*! + Return the starting MSF (minutes/secs/frames) for track number + i_tracks in obj. Track numbers start at 1. + The "leadout" track is specified either by + using i_tracks LEADOUT_TRACK or the total tracks+1. + False is returned if there is no track entry. +*/ +static bool +_cdio_get_track_msf(void *p_user_data, track_t i_tracks, msf_t *p_msf) +{ + _img_private_t *p_env = p_user_data; + + if (!p_msf) + return false; + + if (!p_env->gen.toc_init) + if (!read_toc_os2 (p_env)) + return false; + + if (i_tracks == CDIO_CDROM_LEADOUT_TRACK) + i_tracks = p_env->gen.i_tracks+1; + + if (i_tracks > p_env->gen.i_tracks+1 || i_tracks == 0) { + return false; + } else { + cdio_lsn_to_msf(p_env->toc[i_tracks].lsn_start, p_msf); + return true; + } +} + +#endif /* HAVE_OS2_CDROM */ + +/*! + Return an array of strings giving possible CD devices. + */ +char ** +cdio_get_devices_os2 (void) +{ +#ifndef HAVE_OS2_CDROM + return NULL; +#else + char **drives = NULL; + unsigned int num_drives=0; + + struct { + BYTE uc_cmd_info; + BYTE uc_drive; + } s_param; + + struct { + struct { + USHORT us_bytes_per_sector; + BYTE uc_sectors_per_cluster; + USHORT us_reserved_sectors; + BYTE uc_number_of_fats; + USHORT us_root_dir_entries; + USHORT us_total_sectors; + BYTE uc_media_descriptor; + USHORT us_sectors_per_fat; + USHORT us_sectors_per_track; + USHORT us_number_of_heads; + ULONG ul_hidden_sectors; + ULONG ul_large_total_sectors; + BYTE auc_reserved[6]; + } s_ebpb; + + USHORT us_cylinders; + BYTE uc_dev_type; + USHORT us_dev_attr; + } s_data; + + ULONG ul_param_len; + ULONG ul_data_len; + UCHAR uc_drive; + char sz_drive_str[ 3 ] = "X:"; + ULONG rc; + + /* Scan the system for CD-ROM drives. + */ + + for( uc_drive = 0; uc_drive < 26; uc_drive++ ) + { + s_param.uc_cmd_info = 0; + s_param.uc_drive = uc_drive; + + rc = DosDevIOCtl( + ( HFILE )-1, IOCTL_DISK, DSK_GETDEVICEPARAMS, + &s_param, sizeof( s_param ), &ul_param_len, + &s_data, sizeof( s_data ), &ul_data_len ); + + if( rc ) + continue; + + switch( s_data.s_ebpb.uc_media_descriptor ) + { + case 4 : /* CD-R */ + case 128 + 4 : /* CD-R but cannot be written */ + case 5 : /* CD-ROM */ + case 128 + 5 : /* CD-ROM but cannot be written */ + case 6 : /* DVD-ROM */ + case 128 + 6 : /* DVD-ROM but cannot be written */ + case 7 : /* DVD-RAM */ + case 128 + 7 : /* DVD-RAM but cannot be written */ + case 8 : /* CD-RW */ + case 128 + 8 : /* CD-RW but cannot be written */ + case 9 : /* DVD-R */ + case 128 + 9 : /* DVD-R but cannot be written */ + case 10 : /* DVD-RW */ + case 128 + 10 : /* DVD-RW but cannot be written */ + case 11 : /* DVD+RW */ + case 128 + 11 : /* DVD+RW but cannot be written */ + sz_drive_str[0] = 'A' + uc_drive; + cdio_add_device_list(&drives, strdup(sz_drive_str), &num_drives); + break; + } + } + + cdio_add_device_list(&drives, NULL, &num_drives); + return drives; +#endif /*HAVE_OS2_CDROM*/ +} + +#define IOCTL_CDROMDISK2 0x82 + +#define CDROMDISK2_DRIVELETTERS 0x60 + +/*! + Return a string containing the default CD device if none is specified. + if CdIo is NULL (we haven't initialized a specific device driver), + then find a suitable one and return the default device for that. + + NULL is returned if we couldn't get a default device. +*/ +char * +cdio_get_default_device_os2(void) +{ +#ifdef HAVE_OS2_CDROM + struct { + USHORT us_drive_count; + USHORT us_drive_first; + } s_drive_letters; + + HFILE h_cd2; + ULONG ul_action; + ULONG ul_param_len; + ULONG ul_data_len; + char sz_drive_str[ 3 ] = "X:"; + ULONG rc; + + rc = DosOpen((PSZ)"CD-ROM2$", &h_cd2, &ul_action, 0, FILE_NORMAL, + OPEN_ACTION_OPEN_IF_EXISTS | OPEN_ACTION_FAIL_IF_NEW, + OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, + NULL ); + + if( rc ) + { + cdio_warn("cdio_get_default_device_os2 : DosOpen(CD-ROM2$) = %ld\n", rc ); + + return NULL; + } + + rc = DosDevIOCtl( + h_cd2, IOCTL_CDROMDISK2, CDROMDISK2_DRIVELETTERS, + NULL, 0, &ul_param_len, + &s_drive_letters, sizeof( s_drive_letters ), &ul_data_len ); + + DosClose( h_cd2 ); + + if( rc ) + { + cdio_warn("cdio_get_default_device_os2 : DosDevIOCtl(DRIVELETTERS) = 0x%lx\n", rc ); + + return NULL; + } + + if( s_drive_letters.us_drive_count == 0 ) + return NULL; + + sz_drive_str[0] = 'A' + s_drive_letters.us_drive_first; + + return strdup( sz_drive_str ); +#else + return NULL; +#endif +} + +/*! + Return true if source_name could be a device containing a CD-ROM. +*/ +bool +cdio_is_device_os2(const char *source_name) +{ + if (!source_name) + return false; + +#ifdef HAVE_OS2_CDROM + return (isalpha(source_name[0]) && + source_name[1] == ':' && + source_name[2] == '\0'); +#else + return false; +#endif +} + +/*! + Close tray on CD-ROM. + + @param p_user_data the CD object to be acted upon. + +*/ +driver_return_code_t +close_tray_os2 (const char *psz_os2_drive) +{ +#ifdef HAVE_OS2_CDROM + struct { + BYTE uc_cmd_info; + BYTE uc_drive; + } s_param; + + ULONG ul_param_len; + ULONG ul_data_len; + ULONG rc; + + s_param.uc_cmd_info = 3; + s_param.uc_drive = toupper(psz_os2_drive[0]) - 'A'; + + rc = DosDevIOCtl( + ( HFILE )-1, IOCTL_DISK, DSK_UNLOCKEJECTMEDIA, + &s_param, sizeof( s_param ), &ul_param_len, + NULL, 0, &ul_data_len ); + + if( rc && rc != 99 /* device in use */ ) + { + cdio_warn("close_tray_os2 : DosDevIOCtl(UNLOCKEJECTMEDIA) = 0x%lx\n", rc ); + + return DRIVER_OP_ERROR; + } + + return DRIVER_OP_SUCCESS; +#else + return DRIVER_OP_UNSUPPORTED; +#endif /* HAVE_OS2_CDROM */ +} + +/*! + Initialization routine. This is the only thing that doesn't + get called via a function pointer. In fact *we* are the + ones to set that up. + */ +CdIo_t * +cdio_open_os2 (const char *psz_orig_source) +{ + +#ifdef HAVE_OS2_CDROM + CdIo_t *ret; + _img_private_t *_data; + char *psz_source; + + cdio_funcs_t _funcs; + + memset( &_funcs, 0, sizeof(_funcs) ); + + _funcs.audio_get_volume = audio_get_volume_os2; + _funcs.audio_pause = audio_pause_os2; + _funcs.audio_play_msf = audio_play_msf_os2; +#if 0 + _funcs.audio_play_track_index = audio_play_track_index_os2; +#endif + _funcs.audio_read_subchannel = audio_read_subchannel_os2; + _funcs.audio_resume = audio_resume_os2; + _funcs.audio_set_volume = audio_set_volume_os2; + _funcs.audio_stop = audio_stop_os2; + _funcs.eject_media = eject_media_os2; + _funcs.free = free_os2; + _funcs.get_arg = get_arg_os2; +#if 0 + _funcs.get_blocksize = get_blocksize_os2; +#endif + _funcs.get_cdtext = get_cdtext_generic; + _funcs.get_default_device = cdio_get_default_device_os2; + _funcs.get_devices = cdio_get_devices_os2; + _funcs.get_disc_last_lsn = get_disc_last_lsn_os2; + _funcs.get_discmode = get_discmode_os2; + _funcs.get_drive_cap = get_drive_cap_mmc; + _funcs.get_first_track_num = get_first_track_num_generic; + _funcs.get_hwinfo = NULL; +#if 0 + _funcs.get_last_session = get_last_session_os2; +#endif + _funcs.get_media_changed = get_media_changed_mmc; + _funcs.get_mcn = _cdio_get_mcn; + _funcs.get_num_tracks = get_num_tracks_generic; + _funcs.get_track_channels = get_track_channels_generic; + _funcs.get_track_copy_permit = get_track_copy_permit_generic; + _funcs.get_track_format = _cdio_get_track_format; + _funcs.get_track_green = _cdio_get_track_green; + _funcs.get_track_lba = NULL; /* This could be done if need be. */ +#if 0 + _funcs.get_track_pregap_lba = get_track_pregap_lba_os2; + _funcs.get_track_isrc = get_track_isrc_os2; +#endif + _funcs.get_track_msf = _cdio_get_track_msf; + _funcs.get_track_preemphasis = get_track_preemphasis_generic; + _funcs.lseek = cdio_generic_lseek; + _funcs.read = cdio_generic_read; + _funcs.read_audio_sectors = read_audio_sectors_os2; + _funcs.read_data_sectors = read_data_sectors_mmc; + _funcs.read_mode1_sector = read_mode1_sector_os2; + _funcs.read_mode1_sectors = read_mode1_sectors_os2; + _funcs.read_mode2_sector = read_mode2_sector_os2; + _funcs.read_mode2_sectors = read_mode2_sectors_os2; + _funcs.read_toc = read_toc_os2; + _funcs.run_mmc_cmd = run_mmc_cmd_os2; + _funcs.set_arg = set_arg_os2; + _funcs.set_blocksize = set_blocksize_mmc; + _funcs.set_speed = set_drive_speed_mmc; + + _data = calloc(1, sizeof (_img_private_t)); + _data->access_mode = _AM_OS2; + _data->gen.init = false; + _data->gen.fd = -1; + + if (NULL == psz_orig_source) { + psz_source=cdio_get_default_device_os2(); + if (NULL == psz_source) return NULL; + set_arg_os2(_data, "source", psz_source); + free(psz_source); + } else { + if (cdio_is_device_os2(psz_orig_source)) + set_arg_os2(_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 a not a device", psz_orig_source); +#endif + free(_data); + return NULL; + } + } + + ret = cdio_new ((void *)_data, &_funcs); + if (ret == NULL) return NULL; + + ret->driver_id = DRIVER_OS2; + + if (init_os2(_data)) + return ret; + else { + free_os2 (_data); + return NULL; + } +#else + return NULL; +#endif /* HAVE_OS2_CDROM */ + +} + +/*! + Initialization routine. This is the only thing that doesn't + get called via a function pointer. In fact *we* are the + ones to set that up. + */ +CdIo_t * +cdio_open_am_os2 (const char *psz_source_name, const char *psz_access_mode) +{ + + if (psz_access_mode != NULL) + cdio_warn ("there is only one access mode for OS/2. Arg %s ignored", + psz_access_mode); + return cdio_open_os2(psz_source_name); +} + +bool +cdio_have_os2 (void) +{ +#ifdef HAVE_OS2_CDROM + return true; +#else + return false; +#endif /* HAVE_OS2_CDROM */ +} diff --git a/src/cd-paranoia/cd-paranoia.c b/src/cd-paranoia/cd-paranoia.c index 5c78a98d..ddb7f7ef 100644 --- a/src/cd-paranoia/cd-paranoia.c +++ b/src/cd-paranoia/cd-paranoia.c @@ -1,7 +1,7 @@ /* $Id: cd-paranoia.c,v 1.37 2008/06/19 15:44:30 flameeyes Exp $ - Copyright (C) 2004, 2005, 2006, 2007, 2008 Rocky Bernstein + Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Rocky Bernstein (C) 1998 Monty This program is free software: you can redistribute it and/or modify @@ -528,10 +528,10 @@ callback(long int inpos, paranoia_cb_mode_t function) buffer[aheadposition+19]='>'; } - fprintf(stderr,buffer); + fprintf(stderr, "%s", buffer); if (logfile != NULL && function==-1) { - fprintf(logfile,buffer+1); + fprintf(logfile, "%s", buffer+1); fprintf(logfile,"\n\n"); fflush(logfile); } diff --git a/src/cd-paranoia/report.c b/src/cd-paranoia/report.c index c1be3508..9c8ce678 100644 --- a/src/cd-paranoia/report.c +++ b/src/cd-paranoia/report.c @@ -36,7 +36,7 @@ void report(const char *s) { if (!quiet) { - fprintf(stderr,s); + fprintf(stderr, "%s", s); fputc('\n',stderr); } } diff --git a/src/cdda-player.c b/src/cdda-player.c index 6f3c7b42..82edaa4a 100644 --- a/src/cdda-player.c +++ b/src/cdda-player.c @@ -1,7 +1,7 @@ /* $Id: cdda-player.c,v 1.50 2008/06/19 15:44:14 flameeyes Exp $ - Copyright (C) 2005, 2006, 2008 Rocky Bernstein + Copyright (C) 2005, 2006, 2008, 2009 Rocky Bernstein Adapted from Gerd Knorr's player.c program Copyright (C) 1997, 1998 @@ -110,7 +110,9 @@ static bool b_verbose = false; static bool debug = false; static bool b_interactive = true; static bool b_prefer_cdtext = true; +#ifdef CDDB_ADDED static bool b_cddb = false; /* CDDB database present */ +#endif static bool b_db = false; /* we have a database at all */ static bool b_record = false; /* we have a record for static the inserted CD */ @@ -143,7 +145,9 @@ static char year[5]; static bool b_cdtext_title; /* true if from CD-Text, false if from CDDB */ static bool b_cdtext_artist; /* true if from CD-Text, false if from CDDB */ static bool b_cdtext_genre; /* true if from CD-Text, false if from CDDB */ +#ifdef CDTEXT_CATEGORY_ADDED static bool b_cdtext_category; /* true if from CD-Text, false if from CDDB */ +#endif static bool b_cdtext_year; /* true if from CD-Text, false if from CDDB */ static cdio_audio_volume_t audio_volume; diff --git a/src/util.c b/src/util.c index 4667d0b3..09264e2c 100644 --- a/src/util.c +++ b/src/util.c @@ -1,7 +1,7 @@ /* $Id: util.c,v 1.54 2008/04/14 17:30:27 karl Exp $ - Copyright (C) 2003, 2004, 2005, 2007, 2008 Rocky Bernstein + Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 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 @@ -160,7 +160,7 @@ open_input(const char *psz_source, source_image_t source_image, char * fillout_device_name(const char *device_name) { -#if defined(HAVE_WIN32_CDROM) +#if defined(HAVE_WIN32_CDROM) || defined(HAVE_OS2_CDROM) return strdup(device_name); #else unsigned int prefix_len = strlen(DEV_PREFIX);