libcdio-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Libcdio-devel] [PATCH] OS/2 support


From: Rocky Bernstein
Subject: Re: [Libcdio-devel] [PATCH] OS/2 support
Date: Sun, 8 Feb 2009 05:59:10 -0500

Sorry for the delay. The OS2 patches should now be in the libcdio git
repository.

I had some problems applying the patch. (Patch wants the original listed
first, not second and it would have been helpful to attach this as a
separate file).

I have no way to check whether these changes work. So please double check my
work. (I often make mistakes ;-)

Thanks.

On Mon, Jan 12, 2009 at 8:31 AM, KO Myung-Hun <address@hidden> wrote:

> 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.orglib/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);
>
>


reply via email to

[Prev in Thread] Current Thread [Next in Thread]