[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Libcdio-devel] [PATCH] OS/2 support
From: |
KO Myung-Hun |
Subject: |
[Libcdio-devel] [PATCH] OS/2 support |
Date: |
Mon, 12 Jan 2009 22:31:19 +0900 |
User-agent: |
Mozilla/5.0 (OS/2; U; Warp 4.5; en-US; rv:1.8.1.19) Gecko/20081217 SeaMonkey/1.1.14 Mnenhy/0.7.6.0 |
Hi/2.
These patches add a OS/2 driver for libcdio-0.81.
Review, please.
--
KO Myung-Hun
Using Mozilla SeaMonkey 1.1.14
Under OS/2 Warp 4 for Korean with FixPak #15
On AMD ThunderBird 1 GHz with 512 MB RAM
Korean OS/2 User Community : http://www.ecomstation.co.kr
diff -buNr configure.ac.org configure.ac
--- configure.ac.org 2008-10-26 23:48:24.000000000 +0900
+++ configure.ac 2009-01-09 02:09:10.000000000 +0900
@@ -529,6 +529,13 @@
# 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.])
@@ -563,6 +570,7 @@
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 -buNr include/cdio/device.h.org include/cdio/device.h
--- include/cdio/device.h.org 2008-03-27 18:28:36.000000000 +0900
+++ include/cdio/device.h 2009-01-12 22:05:00.000000000 +0900
@@ -159,6 +159,7 @@
DRIVER_OSX, /**< Apple OSX Driver */
DRIVER_WIN32, /**< Microsoft Windows Driver. Includes ASPI and
ioctl access. */
+ DRIVER_OS2, /**< OS/2 Driver */
DRIVER_NETBSD, /**< NetBSD Driver. */
DRIVER_CDRDAO, /**< cdrdao format CD image. This is listed
before BIN/CUE, to make the code prefer cdrdao
@@ -810,6 +811,44 @@
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 -buNr lib/cdda_interface/common_interface.h.org
lib/cdda_interface/common_interface.h
--- lib/cdda_interface/common_interface.h.org 2008-04-23 23:59:52.000000000
+0900
+++ lib/cdda_interface/common_interface.h 2009-01-09 01:59:08.000000000
+0900
@@ -28,7 +28,7 @@
#include <cdio/types.h>
#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 -buNr lib/driver/cdio_private.h.org lib/driver/cdio_private.h
--- lib/driver/cdio_private.h.org 2008-04-23 23:59:52.000000000 +0900
+++ lib/driver/cdio_private.h 2009-01-12 22:05:42.000000000 +0900
@@ -488,6 +488,7 @@
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);
+ driver_return_code_t close_tray_os2 (const char *psz_drive);
bool cdio_have_netbsd(void);
CdIo_t * cdio_open_netbsd (const char *psz_source);
@@ -531,6 +532,10 @@
True if Microsoft Windows driver is available. */
bool cdio_have_win32 (void);
+ /*! DEPRICATED: use cdio_have_driver().
+ True if IBM OS/2 driver is available. */
+ bool cdio_have_os2 (void);
+
/*! True if Nero driver is available. */
bool cdio_have_nrg (void);
diff -buNr lib/driver/device.c.org lib/driver/device.c
--- lib/driver/device.c.org 2008-04-23 23:59:52.000000000 +0900
+++ lib/driver/device.c 2009-01-09 01:59:08.000000000 +0900
@@ -71,6 +71,8 @@
const driver_id_t cdio_os_driver = DRIVER_SOLARIS;
#elif HAVE_DARWIN_WIN32
const driver_id_t cdio_os_driver = DRIVER_WIN32;
+#elif HAVE_OS2_CDROM
+const driver_id_t cdio_os_driver = DRIVER_OS2;
#else
const driver_id_t cdio_os_driver = DRIVER_UNKNOWN;
#endif
@@ -213,6 +215,19 @@
&close_tray_win32
},
+ {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_CDRDAO,
CDIO_SRC_IS_DISK_IMAGE_MASK,
"CDRDAO",
@@ -939,6 +954,7 @@
case DRIVER_SOLARIS:
case DRIVER_WIN32:
case DRIVER_OSX:
+ case DRIVER_OS2:
case DRIVER_NRG:
case DRIVER_BINCUE:
case DRIVER_CDRDAO:
diff -buNr lib/driver/generic.h.org lib/driver/generic.h
--- lib/driver/generic.h.org 2008-04-23 23:59:52.000000000 +0900
+++ lib/driver/generic.h 2009-01-09 02:26:50.000000000 +0900
@@ -134,6 +134,12 @@
*/
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 -buNr lib/driver/Makefile.am.org lib/driver/Makefile.am
--- lib/driver/Makefile.am.org 2008-10-19 18:25:30.000000000 +0900
+++ lib/driver/Makefile.am 2009-01-06 12:42:40.000000000 +0900
@@ -90,6 +90,7 @@
MSWindows/win32.h \
netbsd.c \
osx.c \
+ os2.c \
read.c \
sector.c \
solaris.c \
diff -buNr lib/driver/os2.c.org lib/driver/os2.c
--- lib/driver/os2.c.org 2009-01-09 23:57:26.000000000 +0900
+++ lib/driver/os2.c 2009-01-11 17:49:36.000000000 +0900
@@ -0,0 +1,1554 @@
+/*
+ $Id: os2.c,v 1.30 2008/04/21 18:30:21 karl Exp $
+
+ Copyright (C) 2009 KO Myung-Hun <address@hidden>
+
+ 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 <http://www.gnu.org/licenses/>.
+*/
+
+/* 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 <cdio/cdio.h>
+#include <cdio/sector.h>
+#include <cdio/util.h>
+#include <cdio/mmc.h>
+#include "cdio_assert.h"
+#include "cdio_private.h"
+
+#include <string.h>
+
+#ifdef HAVE_OS2_CDROM
+
+#define INCL_DOS
+#define INCL_DOSDEVIOCTL
+#include <os2.h>
+
+#include <ctype.h>
+
+
+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 -buNr src/util.c.org src/util.c
--- src/util.c.org 2008-04-15 10:22:12.000000000 +0900
+++ src/util.c 2009-01-09 01:59:12.000000000 +0900
@@ -160,7 +160,7 @@
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);
- [Libcdio-devel] [PATCH] OS/2 support,
KO Myung-Hun <=