Blame lib/driver/MSWindows/win32.c

Packit dd8086
/*
Packit dd8086
  Copyright (C) 2003-2006, 2008, 2010-2012, 2014, 2017
Packit dd8086
  Rocky Bernstein <rocky@gnu.org>
Packit dd8086
Packit dd8086
  This program is free software: you can redistribute it and/or modify
Packit dd8086
  it under the terms of the GNU General Public License as published by
Packit dd8086
  the Free Software Foundation, either version 3 of the License, or
Packit dd8086
  (at your option) any later version.
Packit dd8086
Packit dd8086
  This program is distributed in the hope that it will be useful,
Packit dd8086
  but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit dd8086
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit dd8086
  GNU General Public License for more details.
Packit dd8086
Packit dd8086
  You should have received a copy of the GNU General Public License
Packit dd8086
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
Packit dd8086
*/
Packit dd8086
Packit dd8086
/* This file contains Win32-specific code and implements low-level
Packit dd8086
   control of the CD drive. Inspired by vlc's cdrom.h code
Packit dd8086
*/
Packit dd8086

Packit dd8086
#ifdef HAVE_CONFIG_H
Packit dd8086
# include "config.h"
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_STDBOOL_H
Packit dd8086
# include <stdbool.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#include <cdio/cdio.h>
Packit dd8086
#include <cdio/sector.h>
Packit dd8086
#include <cdio/util.h>
Packit dd8086
#include <cdio/mmc.h>
Packit dd8086
#include <cdio/logging.h>
Packit dd8086
#include "cdio_assert.h"
Packit dd8086
#include "cdio_private.h" /* protoype for cdio_is_device_win32 */
Packit dd8086
Packit dd8086
#include <string.h>
Packit dd8086
Packit dd8086
#ifdef HAVE_WIN32_CDROM
Packit dd8086
Packit dd8086
#include <ctype.h>
Packit dd8086
#include <stdio.h>
Packit dd8086
Packit dd8086
#ifdef HAVE_STDLIB_H
Packit dd8086
#include <stdlib.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_ERRNO_H
Packit dd8086
#include <errno.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_UNISTD_H
Packit dd8086
#include <unistd.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_FCNTL_H
Packit dd8086
#include <fcntl.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#include <windows.h>
Packit dd8086
#include <winioctl.h>
Packit dd8086
#include "win32.h"
Packit dd8086
Packit dd8086
#ifdef HAVE_SYS_STAT_H
Packit dd8086
#include <sys/stat.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef HAVE_SYS_TYPES_H
Packit dd8086
#include <sys/types.h>
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#if defined (_MSC_VER) || defined (_XBOX)
Packit dd8086
#undef IN
Packit dd8086
#else
Packit dd8086
#include "aspi32.h"
Packit dd8086
#endif
Packit dd8086
Packit dd8086
#ifdef _XBOX
Packit dd8086
#include "stdint.h"
Packit dd8086
#include <xtl.h>
Packit dd8086
#define WIN_NT 1
Packit dd8086
#else
Packit dd8086
#define WIN_NT               ( GetVersion() < 0x80000000 )
Packit dd8086
#endif
Packit dd8086
Packit dd8086
/* mingw-w64 defines this to lseek64 when LFS is enabled */
Packit dd8086
#ifdef lseek
Packit dd8086
# undef lseek
Packit dd8086
#endif
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Set the volume of an audio CD.
Packit dd8086
Packit dd8086
  @param p_cdio the CD object to be acted upon.
Packit dd8086
Packit dd8086
*/
Packit dd8086
static driver_return_code_t
Packit dd8086
audio_get_volume_win32 ( void *p_user_data,
Packit dd8086
			 /*out*/ cdio_audio_volume_t *p_volume)
Packit dd8086
{
Packit dd8086
  if ( WIN_NT ) {
Packit dd8086
    return audio_get_volume_win32ioctl (p_user_data, p_volume);
Packit dd8086
  } else {
Packit dd8086
    return DRIVER_OP_UNSUPPORTED; /* not yet, but soon I hope */
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Pause playing CD through analog output
Packit dd8086
Packit dd8086
  @param p_cdio the CD object to be acted upon.
Packit dd8086
*/
Packit dd8086
static driver_return_code_t
Packit dd8086
audio_pause_win32 (void *p_user_data)
Packit dd8086
{
Packit dd8086
  if ( WIN_NT ) {
Packit dd8086
    return audio_pause_win32ioctl (p_user_data);
Packit dd8086
  } else {
Packit dd8086
    return DRIVER_OP_UNSUPPORTED; /* not yet, but soon I hope */
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Playing CD through analog output at the given MSF.
Packit dd8086
Packit dd8086
  @param p_cdio the CD object to be acted upon.
Packit dd8086
*/
Packit dd8086
static driver_return_code_t
Packit dd8086
audio_play_msf_win32 (void *p_user_data, msf_t *p_start_msf, msf_t *p_end_msf)
Packit dd8086
{
Packit dd8086
  if ( WIN_NT ) {
Packit dd8086
    return audio_play_msf_win32ioctl (p_user_data, p_start_msf, p_end_msf);
Packit dd8086
  } else {
Packit dd8086
    return DRIVER_OP_UNSUPPORTED; /* not yet, but soon I hope */
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Read Audio Subchannel information
Packit dd8086
Packit dd8086
  @param p_cdio the CD object to be acted upon.
Packit dd8086
Packit dd8086
*/
Packit dd8086
static driver_return_code_t
Packit dd8086
audio_read_subchannel_win32 (void *p_user_data,
Packit dd8086
			     cdio_subchannel_t *p_subchannel)
Packit dd8086
{
Packit dd8086
  if ( WIN_NT ) {
Packit dd8086
    return audio_read_subchannel_win32ioctl (p_user_data, p_subchannel);
Packit dd8086
  } else {
Packit dd8086
    return audio_read_subchannel_mmc(p_user_data, p_subchannel);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
  /*!
Packit dd8086
    Resume playing an audio CD.
Packit dd8086
Packit dd8086
    @param p_cdio the CD object to be acted upon.
Packit dd8086
Packit dd8086
  */
Packit dd8086
static driver_return_code_t
Packit dd8086
audio_resume_win32 (void *p_user_data)
Packit dd8086
{
Packit dd8086
  if ( WIN_NT ) {
Packit dd8086
    return audio_resume_win32ioctl (p_user_data);
Packit dd8086
  } else {
Packit dd8086
    return DRIVER_OP_UNSUPPORTED; /* not yet, but soon I hope */
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Set the volume of an audio CD.
Packit dd8086
Packit dd8086
  @param p_cdio the CD object to be acted upon.
Packit dd8086
Packit dd8086
*/
Packit dd8086
static driver_return_code_t
Packit dd8086
audio_set_volume_win32 ( void *p_user_data, cdio_audio_volume_t *p_volume)
Packit dd8086
{
Packit dd8086
  if ( WIN_NT ) {
Packit dd8086
    return audio_set_volume_win32ioctl (p_user_data, p_volume);
Packit dd8086
  } else {
Packit dd8086
    return DRIVER_OP_UNSUPPORTED; /* not yet, but soon I hope */
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
static driver_return_code_t
Packit dd8086
audio_stop_win32 ( void *p_user_data)
Packit dd8086
{
Packit dd8086
  if ( WIN_NT ) {
Packit dd8086
    return audio_stop_win32ioctl (p_user_data);
Packit dd8086
  } else {
Packit dd8086
    return DRIVER_OP_UNSUPPORTED; /* not yet, but soon I hope */
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/* General ioctl() CD-ROM command function */
Packit dd8086
static bool
Packit dd8086
_cdio_mciSendCommand(int id, UINT msg, DWORD flags, void *arg)
Packit dd8086
{
Packit dd8086
#ifdef _XBOX
Packit dd8086
  return false;
Packit dd8086
#else
Packit dd8086
  MCIERROR mci_error;
Packit dd8086
Packit dd8086
  mci_error = mciSendCommand(id, msg, flags, (DWORD_PTR)arg);
Packit dd8086
  if ( mci_error ) {
Packit dd8086
    char error[256];
Packit dd8086
Packit dd8086
    mciGetErrorString(mci_error, error, 256);
Packit dd8086
    cdio_warn("mciSendCommand() error: %s", error);
Packit dd8086
  }
Packit dd8086
  return(mci_error == 0);
Packit dd8086
#endif
Packit dd8086
}
Packit dd8086
Packit dd8086
static access_mode_t
Packit dd8086
str_to_access_mode_win32(const char *psz_access_mode)
Packit dd8086
{
Packit dd8086
  const access_mode_t default_access_mode =
Packit dd8086
    WIN_NT ? _AM_IOCTL : _AM_ASPI;
Packit dd8086
Packit dd8086
  if (NULL==psz_access_mode) return default_access_mode;
Packit dd8086
Packit dd8086
  if (!strcmp(psz_access_mode, "ioctl"))
Packit dd8086
    return _AM_IOCTL;
Packit dd8086
  else if (!strcmp(psz_access_mode, "ASPI")) {
Packit dd8086
#ifdef _XBOX
Packit dd8086
    cdio_warn ("XBOX doesn't support access type: %s. Default used instead.",
Packit dd8086
	       psz_access_mode);
Packit dd8086
    return default_access_mode;
Packit dd8086
#else
Packit dd8086
    return _AM_ASPI;
Packit dd8086
#endif
Packit dd8086
  } else if (!strcmp(psz_access_mode, "MMC_RDWR")) {
Packit dd8086
    return _AM_MMC_RDWR;
Packit dd8086
  } else if (!strcmp(psz_access_mode, "MMC_RDWR_EXCL")) {
Packit dd8086
    return _AM_MMC_RDWR_EXCL;
Packit dd8086
  } else {
Packit dd8086
    cdio_warn ("unknown access type: %s. Default used instead.",
Packit dd8086
	       psz_access_mode);
Packit dd8086
    return default_access_mode;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
static discmode_t
Packit dd8086
get_discmode_win32(void *p_user_data)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
Packit dd8086
  if (p_env->hASPI) {
Packit dd8086
    return get_discmode_aspi (p_env);
Packit dd8086
  } else {
Packit dd8086
    return get_discmode_win32ioctl (p_env);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
static driver_return_code_t
Packit dd8086
get_last_session_win32(void *p_user_data,
Packit dd8086
                       /*out*/ lsn_t *i_last_session) {
Packit dd8086
  if ( WIN_NT ) {
Packit dd8086
    return get_last_session_win32ioctl(p_user_data, i_last_session);
Packit dd8086
  } else {
Packit dd8086
    return DRIVER_OP_UNSUPPORTED;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
static const char *
Packit dd8086
is_cdrom_win32(const char drive_letter) {
Packit dd8086
  if ( WIN_NT ) {
Packit dd8086
    return is_cdrom_win32ioctl (drive_letter);
Packit dd8086
  } else {
Packit dd8086
    return is_cdrom_aspi(drive_letter);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Run a SCSI MMC command.
Packit dd8086
Packit dd8086
  env	        private CD structure
Packit dd8086
  i_timeout_ms  time in milliseconds we will wait for the command
Packit dd8086
                to complete. If this value is -1, use the default
Packit dd8086
		time-out value.
Packit dd8086
  p_buf	        Buffer for data, both sending and receiving
Packit dd8086
  i_buf	        Size of buffer
Packit dd8086
  e_direction	direction the transfer is to go.
Packit dd8086
  cdb	        CDB bytes. All values that are needed should be set on
Packit dd8086
                input. We'll figure out what the right CDB length should be.
Packit dd8086
Packit dd8086
  Return 0 if command completed successfully.
Packit dd8086
 */
Packit dd8086
static int
Packit dd8086
run_mmc_cmd_win32( void *p_user_data, unsigned int i_timeout_ms,
Packit dd8086
		   unsigned int i_cdb, const mmc_cdb_t *p_cdb,
Packit dd8086
		   cdio_mmc_direction_t e_direction,
Packit dd8086
		   unsigned int i_buf, /*in/out*/ void *p_buf )
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
Packit dd8086
  if (p_env->hASPI) {
Packit dd8086
    return run_mmc_cmd_aspi( p_env, i_timeout_ms, i_cdb, p_cdb,
Packit dd8086
			     e_direction, i_buf, p_buf );
Packit dd8086
  } else {
Packit dd8086
    return run_mmc_cmd_win32ioctl( p_env, i_timeout_ms, i_cdb, p_cdb,
Packit dd8086
				   e_direction, i_buf, p_buf );
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Initialize CD device.
Packit dd8086
 */
Packit dd8086
static bool
Packit dd8086
init_win32 (void *p_user_data)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
  bool b_ret;
Packit dd8086
  if (p_env->gen.init) {
Packit dd8086
    cdio_error ("init called more than once");
Packit dd8086
    return false;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  p_env->gen.init           = true;
Packit dd8086
  p_env->gen.toc_init       = false;
Packit dd8086
  p_env->gen.b_cdtext_error = false;
Packit dd8086
  p_env->gen.fd             = open (p_env->gen.source_name, O_RDONLY|O_BINARY, 0);
Packit dd8086
Packit dd8086
  /* Initializations */
Packit dd8086
  p_env->h_device_handle = NULL;
Packit dd8086
  p_env->i_sid           = 0;
Packit dd8086
  p_env->hASPI           = 0;
Packit dd8086
  p_env->lpSendCommand   = 0;
Packit dd8086
  p_env->b_aspi_init     = false;
Packit dd8086
  p_env->b_ioctl_init    = false;
Packit dd8086
Packit dd8086
Packit dd8086
  switch (p_env->access_mode) {
Packit dd8086
  case _AM_IOCTL:
Packit dd8086
  case _AM_MMC_RDWR:
Packit dd8086
  case _AM_MMC_RDWR_EXCL:
Packit dd8086
    b_ret = init_win32ioctl(p_env);
Packit dd8086
    break;
Packit dd8086
  case _AM_ASPI:
Packit dd8086
    b_ret = init_aspi(p_env);
Packit dd8086
    break;
Packit dd8086
  default:
Packit dd8086
    return 0;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* It looks like get_media_changed_mmc will always
Packit dd8086
     return 1 (media changed) on the first call. So
Packit dd8086
     we call it here to clear that flag. We may have
Packit dd8086
     to rethink this if there's a problem doing this
Packit dd8086
     extra work down the line. */
Packit dd8086
  if (b_ret) get_media_changed_mmc(p_user_data);
Packit dd8086
  return b_ret;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Release and free resources associated with cd.
Packit dd8086
 */
Packit dd8086
static void
Packit dd8086
free_win32 (void *p_user_data)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
Packit dd8086
  if (NULL == p_env) return;
Packit dd8086
  if (p_env->gen.fd >= 0) close(p_env->gen.fd);
Packit dd8086
Packit dd8086
  free (p_env->gen.source_name);
Packit dd8086
Packit dd8086
  if( p_env->h_device_handle )
Packit dd8086
    CloseHandle( p_env->h_device_handle );
Packit dd8086
  if( p_env->hASPI )
Packit dd8086
    FreeLibrary( p_env->hASPI );
Packit dd8086
Packit dd8086
  free (p_env);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Reads an audio device into data starting from lsn.
Packit dd8086
   Returns 0 if no error.
Packit dd8086
 */
Packit dd8086
static int
Packit dd8086
read_audio_sectors (void *p_user_data, void *p_buf, lsn_t i_lsn,
Packit dd8086
		    unsigned int i_blocks)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
  if ( p_env->hASPI ) {
Packit dd8086
    return read_audio_sectors_aspi( p_env, p_buf, i_lsn, i_blocks );
Packit dd8086
  } else {
Packit dd8086
#if 0
Packit dd8086
    return read_audio_sectors_win32ioctl( p_env, p_buf, i_lsn, i_blocks );
Packit dd8086
#else
Packit dd8086
    return mmc_read_sectors( p_env->gen.cdio, p_buf, i_lsn,
Packit dd8086
                                  CDIO_MMC_READ_TYPE_CDDA, i_blocks);
Packit dd8086
#endif
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Reads an audio device into data starting from lsn.
Packit dd8086
   Returns 0 if no error.
Packit dd8086
 */
Packit dd8086
static driver_return_code_t
Packit dd8086
read_data_sectors_win32 (void *p_user_data, void *p_buf, lsn_t i_lsn,
Packit dd8086
			 uint16_t i_blocksize, uint32_t i_blocks)
Packit dd8086
{
Packit dd8086
  driver_return_code_t rc =
Packit dd8086
    read_data_sectors_mmc(p_user_data, p_buf, i_lsn, i_blocksize, i_blocks);
Packit dd8086
  if ( DRIVER_OP_SUCCESS != rc  ) {
Packit dd8086
    /* Try using generic "cooked" mode. */
Packit dd8086
    return read_data_sectors_generic( p_user_data, p_buf, i_lsn,
Packit dd8086
				      i_blocksize, i_blocks );
Packit dd8086
  }
Packit dd8086
  return DRIVER_OP_SUCCESS;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Reads a single mode1 sector from cd device into data starting from
Packit dd8086
   lsn. Returns 0 if no error.
Packit dd8086
 */
Packit dd8086
static int
Packit dd8086
read_mode1_sector_win32 (void *p_user_data, void *p_buf, lsn_t lsn,
Packit dd8086
			 bool b_form2)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
Packit dd8086
  if (p_env->gen.ioctls_debugged == 75)
Packit dd8086
    cdio_debug ("only displaying every 75th ioctl from now on");
Packit dd8086
Packit dd8086
  if (p_env->gen.ioctls_debugged == 30 * 75)
Packit dd8086
    cdio_debug ("only displaying every 30*75th ioctl from now on");
Packit dd8086
Packit dd8086
  if (p_env->gen.ioctls_debugged < 75
Packit dd8086
      || (p_env->gen.ioctls_debugged < (30 * 75)
Packit dd8086
	  && p_env->gen.ioctls_debugged % 75 == 0)
Packit dd8086
      || p_env->gen.ioctls_debugged % (30 * 75) == 0)
Packit dd8086
    cdio_debug ("reading %lu", (unsigned long int) lsn);
Packit dd8086
Packit dd8086
  p_env->gen.ioctls_debugged++;
Packit dd8086
Packit dd8086
  if ( p_env->hASPI ) {
Packit dd8086
    return read_mode1_sector_aspi( p_env, p_buf, lsn, b_form2 );
Packit dd8086
  } else {
Packit dd8086
    return read_mode1_sector_win32ioctl( p_env, p_buf, lsn, b_form2 );
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Reads nblocks of mode1 sectors from cd device into data starting
Packit dd8086
   from lsn.
Packit dd8086
   Returns 0 if no error.
Packit dd8086
 */
Packit dd8086
static int
Packit dd8086
read_mode1_sectors_win32 (void *p_user_data, void *p_buf, lsn_t lsn,
Packit dd8086
			  bool b_form2, unsigned int nblocks)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
  int i;
Packit dd8086
  int retval;
Packit dd8086
Packit dd8086
  for (i = 0; i < nblocks; i++) {
Packit dd8086
    if (b_form2) {
Packit dd8086
      retval = read_mode1_sector_win32 (p_env, ((char *)p_buf) +
Packit dd8086
					(M2RAW_SECTOR_SIZE * i),
Packit dd8086
					lsn + i, true);
Packit dd8086
      if ( retval ) return retval;
Packit dd8086
    } else {
Packit dd8086
      char buf[M2RAW_SECTOR_SIZE] = { 0, };
Packit dd8086
      if ( (retval = read_mode1_sector_win32 (p_env, buf, lsn + i, false)) )
Packit dd8086
	return retval;
Packit dd8086
Packit dd8086
      memcpy (((char *)p_buf) + (CDIO_CD_FRAMESIZE * i),
Packit dd8086
	      buf, CDIO_CD_FRAMESIZE);
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
  return 0;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Reads a single mode2 sector from cd device into data starting
Packit dd8086
   from lsn. Returns 0 if no error.
Packit dd8086
 */
Packit dd8086
static int
Packit dd8086
read_mode2_sector_win32 (void *p_user_data, void *data, lsn_t lsn,
Packit dd8086
			 bool b_form2)
Packit dd8086
{
Packit dd8086
  char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
Packit dd8086
  if (p_env->gen.ioctls_debugged == 75)
Packit dd8086
    cdio_debug ("only displaying every 75th ioctl from now on");
Packit dd8086
Packit dd8086
  if (p_env->gen.ioctls_debugged == 30 * 75)
Packit dd8086
    cdio_debug ("only displaying every 30*75th ioctl from now on");
Packit dd8086
Packit dd8086
  if (p_env->gen.ioctls_debugged < 75
Packit dd8086
      || (p_env->gen.ioctls_debugged < (30 * 75)
Packit dd8086
	  && p_env->gen.ioctls_debugged % 75 == 0)
Packit dd8086
      || p_env->gen.ioctls_debugged % (30 * 75) == 0)
Packit dd8086
    cdio_debug ("reading %lu", (unsigned long int) lsn);
Packit dd8086
Packit dd8086
  p_env->gen.ioctls_debugged++;
Packit dd8086
Packit dd8086
  if ( p_env->hASPI ) {
Packit dd8086
    int ret;
Packit dd8086
    ret = read_mode2_sector_aspi(p_user_data, buf, lsn, 1);
Packit dd8086
    if( ret != 0 ) return ret;
Packit dd8086
    if (b_form2)
Packit dd8086
      memcpy (data, buf, M2RAW_SECTOR_SIZE);
Packit dd8086
    else
Packit dd8086
      memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE);
Packit dd8086
    return 0;
Packit dd8086
  } else {
Packit dd8086
    return read_mode2_sector_win32ioctl( p_env, data, lsn, b_form2 );
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Reads nblocks of mode2 sectors from cd device into data starting
Packit dd8086
   from lsn.
Packit dd8086
   Returns 0 if no error.
Packit dd8086
 */
Packit dd8086
static int
Packit dd8086
read_mode2_sectors_win32 (void *p_user_data, void *data, lsn_t lsn,
Packit dd8086
			  bool b_form2, unsigned int i_blocks)
Packit dd8086
{
Packit dd8086
  int i;
Packit dd8086
  int retval;
Packit dd8086
  unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
Packit dd8086
Packit dd8086
  for (i = 0; i < i_blocks; i++) {
Packit dd8086
    if ( (retval = read_mode2_sector_win32 (p_user_data,
Packit dd8086
					    ((char *)data) + (blocksize * i),
Packit dd8086
					    lsn + i, b_form2)) )
Packit dd8086
      return retval;
Packit dd8086
  }
Packit dd8086
  return 0;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
   Return the size of the CD in logical block address (LBA) units.
Packit dd8086
 */
Packit dd8086
static lsn_t
Packit dd8086
get_disc_last_lsn_win32 (void *p_user_data)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
Packit dd8086
  return p_env->tocent[p_env->gen.i_tracks].start_lsn;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Set the key "arg" to "value" in source device.
Packit dd8086
*/
Packit dd8086
static int
Packit dd8086
set_arg_win32 (void *p_user_data, const char key[], const char value[])
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
Packit dd8086
  if (!strcmp (key, "source"))
Packit dd8086
    {
Packit dd8086
      if (!value)
Packit dd8086
	return -2;
Packit dd8086
Packit dd8086
      free (p_env->gen.source_name);
Packit dd8086
Packit dd8086
      p_env->gen.source_name = strdup (value);
Packit dd8086
    }
Packit dd8086
  else if (!strcmp (key, "access-mode"))
Packit dd8086
    {
Packit dd8086
      p_env->access_mode = str_to_access_mode_win32(value);
Packit dd8086
      if (p_env->access_mode == _AM_ASPI && !p_env->b_aspi_init)
Packit dd8086
	return init_aspi(p_env) ? 1 : -3;
Packit dd8086
      else if (p_env->access_mode == _AM_IOCTL && !p_env->b_ioctl_init)
Packit dd8086
	return init_win32ioctl(p_env) ? 1 : -3;
Packit dd8086
      else
Packit dd8086
	return -4;
Packit dd8086
      return 0;
Packit dd8086
    }
Packit dd8086
  else
Packit dd8086
    return -1;
Packit dd8086
Packit dd8086
  return 0;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Read and cache the CD's Track Table of Contents and track info.
Packit dd8086
  Return true if successful or false if an error.
Packit dd8086
*/
Packit dd8086
static bool
Packit dd8086
read_toc_win32 (void *p_user_data)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
  bool ret;
Packit dd8086
  if( p_env->hASPI ) {
Packit dd8086
    ret = read_toc_aspi( p_env );
Packit dd8086
  } else {
Packit dd8086
    ret = read_toc_win32ioctl( p_env );
Packit dd8086
  }
Packit dd8086
  if (ret) p_env->gen.toc_init = true ;
Packit dd8086
  return ret;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Close media tray.
Packit dd8086
 */
Packit dd8086
static driver_return_code_t
Packit dd8086
open_close_media_win32 (const char *psz_win32_drive, DWORD command_flags)
Packit dd8086
{
Packit dd8086
#ifdef _XBOX
Packit dd8086
  return DRIVER_OP_UNSUPPORTED;
Packit dd8086
#else
Packit dd8086
  MCI_OPEN_PARMS op;
Packit dd8086
  DWORD i_flags;
Packit dd8086
  int ret;
Packit dd8086
Packit dd8086
  memset( &op, 0, sizeof(MCI_OPEN_PARMS) );
Packit dd8086
  op.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO;
Packit dd8086
  op.lpstrElementName = psz_win32_drive;
Packit dd8086
Packit dd8086
  /* Set the flags for the device type */
Packit dd8086
  i_flags = MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID |
Packit dd8086
    MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE;
Packit dd8086
Packit dd8086
  if( _cdio_mciSendCommand( 0, MCI_OPEN, i_flags, &op ) ) {
Packit dd8086
    /* Eject disc */
Packit dd8086
    ret = _cdio_mciSendCommand( op.wDeviceID, MCI_SET, command_flags, 0 ) == 0;
Packit dd8086
    /* Release access to the device */
Packit dd8086
    _cdio_mciSendCommand( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 );
Packit dd8086
  } else
Packit dd8086
    ret = DRIVER_OP_ERROR;
Packit dd8086
Packit dd8086
  return ret;
Packit dd8086
#endif
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Eject media.
Packit dd8086
 */
Packit dd8086
static driver_return_code_t
Packit dd8086
eject_media_win32 (void *p_user_data)
Packit dd8086
{
Packit dd8086
  const _img_private_t *p_env = p_user_data;
Packit dd8086
  char psz_drive[4];
Packit dd8086
  unsigned int i_device = strlen(p_env->gen.source_name);
Packit dd8086
Packit dd8086
  strcpy( psz_drive, "X:" );
Packit dd8086
  if (6 == i_device) {
Packit dd8086
    psz_drive[0] = p_env->gen.source_name[4];
Packit dd8086
  } else if (2 == i_device) {
Packit dd8086
    psz_drive[0] = p_env->gen.source_name[0];
Packit dd8086
  } else {
Packit dd8086
    cdio_info ("Can't pick out drive letter from device %s",
Packit dd8086
	       p_env->gen.source_name);
Packit dd8086
    return DRIVER_OP_ERROR;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  return open_close_media_win32(psz_drive, MCI_SET_DOOR_OPEN);
Packit dd8086
}
Packit dd8086
Packit dd8086
static bool
Packit dd8086
is_mmc_supported(void *user_data)
Packit dd8086
{
Packit dd8086
    _img_private_t *env = user_data;
Packit dd8086
    switch (env->access_mode) {
Packit dd8086
      case _AM_NONE:
Packit dd8086
	return false;
Packit dd8086
      case _AM_IOCTL:
Packit dd8086
      case _AM_ASPI:
Packit dd8086
      case _AM_MMC_RDWR:
Packit dd8086
      case _AM_MMC_RDWR_EXCL:
Packit dd8086
	return true;
Packit dd8086
    }
Packit dd8086
    /* Not reached. */
Packit dd8086
    return false;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the value associated with the key "arg".
Packit dd8086
*/
Packit dd8086
static const char *
Packit dd8086
get_arg_win32 (void *p_user_data, const char key[])
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
Packit dd8086
  if (!strcmp (key, "source")) {
Packit dd8086
    return p_env->gen.source_name;
Packit dd8086
  } else if (!strcmp (key, "access-mode")) {
Packit dd8086
    switch (p_env->access_mode) {
Packit dd8086
    case _AM_IOCTL:
Packit dd8086
      return "ioctl";
Packit dd8086
    case _AM_ASPI:
Packit dd8086
      return "ASPI";
Packit dd8086
    case _AM_MMC_RDWR:
Packit dd8086
      return "MMC_RDWR";
Packit dd8086
    case _AM_MMC_RDWR_EXCL:
Packit dd8086
      return "MMC_RDWR_EXCL";
Packit dd8086
    case _AM_NONE:
Packit dd8086
      return "no access method";
Packit dd8086
    }
Packit dd8086
  } else if (!strcmp (key, "scsi-tuple")) {
Packit dd8086
    return p_env->gen.scsi_tuple;
Packit dd8086
  } else if (!strcmp (key, "mmc-supported?")) {
Packit dd8086
      return is_mmc_supported(p_user_data) ? "true" : "false";
Packit dd8086
  }
Packit dd8086
  return NULL;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the media catalog number MCN.
Packit dd8086
Packit dd8086
  Note: string is malloc'd so caller should free() then returned
Packit dd8086
  string when done with it.
Packit dd8086
Packit dd8086
 */
Packit dd8086
static char *
Packit dd8086
_cdio_get_mcn (const void *p_user_data) {
Packit dd8086
  const _img_private_t *p_env = p_user_data;
Packit dd8086
Packit dd8086
  if( p_env->hASPI ) {
Packit dd8086
    return mmc_get_mcn( p_env->gen.cdio );
Packit dd8086
  } else {
Packit dd8086
    return get_mcn_win32ioctl(p_env);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the international standard recording code ISRC.
Packit dd8086
Packit dd8086
  Note: string is malloc'd so caller should free() then returned
Packit dd8086
  string when done with it.
Packit dd8086
Packit dd8086
 */
Packit dd8086
static char *
Packit dd8086
_cdio_get_track_isrc (const void *p_user_data, track_t i_track) {
Packit dd8086
  const _img_private_t *p_env = p_user_data;
Packit dd8086
Packit dd8086
  if( p_env->hASPI ) {
Packit dd8086
    return mmc_get_track_isrc( p_env->gen.cdio, i_track );
Packit dd8086
  } else {
Packit dd8086
    return get_track_isrc_win32ioctl(p_env, i_track);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Get format of track.
Packit dd8086
*/
Packit dd8086
static track_format_t
Packit dd8086
_cdio_get_track_format(void *p_obj, track_t i_track)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_obj;
Packit dd8086
Packit dd8086
  if ( !p_env ) return TRACK_FORMAT_ERROR;
Packit dd8086
Packit dd8086
  if (!p_env->gen.toc_init)
Packit dd8086
    if (!read_toc_win32 (p_env)) return TRACK_FORMAT_ERROR;
Packit dd8086
Packit dd8086
  if ( i_track < p_env->gen.i_first_track
Packit dd8086
       || i_track >= p_env->gen.i_tracks + p_env->gen.i_first_track )
Packit dd8086
    return TRACK_FORMAT_ERROR;
Packit dd8086
Packit dd8086
  if( p_env->hASPI ) {
Packit dd8086
    return get_track_format_aspi(p_env, i_track);
Packit dd8086
  } else {
Packit dd8086
    return get_track_format_win32ioctl(p_env, i_track);
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return true if we have XA data (green, mode2 form1) or
Packit dd8086
  XA data (green, mode2 form2). That is track begins:
Packit dd8086
  sync - header - subheader
Packit dd8086
  12     4      -  8
Packit dd8086
Packit dd8086
  FIXME: there's gotta be a better design for this and get_track_format?
Packit dd8086
*/
Packit dd8086
static bool
Packit dd8086
_cdio_get_track_green(void *p_obj, track_t i_track)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_obj;
Packit dd8086
Packit dd8086
  switch (_cdio_get_track_format(p_env, i_track)) {
Packit dd8086
  case TRACK_FORMAT_XA:
Packit dd8086
    return true;
Packit dd8086
  case TRACK_FORMAT_ERROR:
Packit dd8086
  case TRACK_FORMAT_CDI:
Packit dd8086
  case TRACK_FORMAT_AUDIO:
Packit dd8086
    return false;
Packit dd8086
  case TRACK_FORMAT_DATA:
Packit dd8086
    if (_AM_ASPI == p_env->access_mode )
Packit dd8086
      return ((p_env->tocent[i_track-p_env->gen.i_first_track].Control & 8) != 0);
Packit dd8086
  default:
Packit dd8086
    break;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* FIXME: Dunno if this is the right way, but it's what
Packit dd8086
     I was using in cd-info for a while.
Packit dd8086
   */
Packit dd8086
  return ((p_env->tocent[i_track-p_env->gen.i_first_track].Control & 2) != 0);
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return the starting MSF (minutes/secs/frames) for track number
Packit dd8086
  i_tracks in obj.  Track numbers start at 1.
Packit dd8086
  The "leadout" track is specified either by
Packit dd8086
  using i_tracks LEADOUT_TRACK or the total tracks+1.
Packit dd8086
  False is returned if there is no track entry.
Packit dd8086
*/
Packit dd8086
static bool
Packit dd8086
_cdio_get_track_msf(void *p_user_data, track_t i_tracks, msf_t *p_msf)
Packit dd8086
{
Packit dd8086
  _img_private_t *p_env = p_user_data;
Packit dd8086
Packit dd8086
  if (!p_msf) return false;
Packit dd8086
Packit dd8086
  if (!p_env->gen.toc_init)
Packit dd8086
    if (!read_toc_win32 (p_env)) return false;
Packit dd8086
Packit dd8086
  if (i_tracks == CDIO_CDROM_LEADOUT_TRACK) i_tracks = p_env->gen.i_tracks+1;
Packit dd8086
Packit dd8086
  if (i_tracks > p_env->gen.i_tracks+1 || i_tracks == 0) {
Packit dd8086
    return false;
Packit dd8086
  } else {
Packit dd8086
    cdio_lsn_to_msf(p_env->tocent[i_tracks-1].start_lsn, p_msf);
Packit dd8086
    return true;
Packit dd8086
  }
Packit dd8086
}
Packit dd8086
Packit dd8086
#endif /* HAVE_WIN32_CDROM */
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return an array of strings giving possible CD devices.
Packit dd8086
 */
Packit dd8086
char **
Packit dd8086
cdio_get_devices_win32 (void)
Packit dd8086
{
Packit dd8086
#ifndef HAVE_WIN32_CDROM
Packit dd8086
  return NULL;
Packit dd8086
#else
Packit dd8086
  char **drives = NULL;
Packit dd8086
  unsigned int num_drives=0;
Packit dd8086
  char drive_letter;
Packit dd8086
Packit dd8086
  /* Scan the system for CD-ROM drives.
Packit dd8086
  */
Packit dd8086
Packit dd8086
#ifdef FINISHED
Packit dd8086
  /* Now check the currently mounted CD drives */
Packit dd8086
  if (NULL != (ret_drive = cdio_check_mounts("/etc/mtab"))) {
Packit dd8086
    cdio_add_device_list(&drives, drive, &num_drives);
Packit dd8086
  }
Packit dd8086
Packit dd8086
  /* Finally check possible mountable drives in /etc/fstab */
Packit dd8086
  if (NULL != (ret_drive = cdio_check_mounts("/etc/fstab"))) {
Packit dd8086
    cdio_add_device_list(&drives, drive, &num_drives);
Packit dd8086
  }
Packit dd8086
#endif
Packit dd8086
Packit dd8086
  /* Scan the system for CD-ROM drives.
Packit dd8086
     Not always 100% reliable, so use the USE_MNTENT code above first.
Packit dd8086
  */
Packit dd8086
  for (drive_letter='A'; drive_letter <= 'Z'; drive_letter++) {
Packit dd8086
    const char *drive_str=is_cdrom_win32(drive_letter);
Packit dd8086
    if (drive_str != NULL) {
Packit dd8086
      cdio_add_device_list(&drives, drive_str, &num_drives);
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
  cdio_add_device_list(&drives, NULL, &num_drives);
Packit dd8086
  return drives;
Packit dd8086
#endif /*HAVE_WIN32_CDROM*/
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return a string containing the default CD device if none is specified.
Packit dd8086
  if CdIo is NULL (we haven't initialized a specific device driver),
Packit dd8086
  then find a suitable one and return the default device for that.
Packit dd8086
Packit dd8086
  NULL is returned if we couldn't get a default device.
Packit dd8086
*/
Packit dd8086
char *
Packit dd8086
cdio_get_default_device_win32(void)
Packit dd8086
{
Packit dd8086
Packit dd8086
#ifdef HAVE_WIN32_CDROM
Packit dd8086
  char drive_letter;
Packit dd8086
Packit dd8086
  for (drive_letter='A'; drive_letter <= 'Z'; drive_letter++) {
Packit dd8086
    const char *drive_str=is_cdrom_win32(drive_letter);
Packit dd8086
    if (drive_str != NULL) {
Packit dd8086
      return strdup(drive_str);
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
#endif
Packit dd8086
  return NULL;
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Return true if source_name could be a device containing a CD-ROM and
Packit dd8086
  we are on a MS Windows platform.
Packit dd8086
*/
Packit dd8086
bool
Packit dd8086
cdio_is_device_win32(const char *source_name)
Packit dd8086
{
Packit dd8086
#ifdef HAVE_WIN32_CDROM
Packit dd8086
  unsigned int len;
Packit dd8086
Packit dd8086
  if (NULL == source_name) return false;
Packit dd8086
  len = strlen(source_name);
Packit dd8086
Packit dd8086
  if ((len == 2) && isalpha((unsigned char) source_name[0])
Packit dd8086
	    && (source_name[len-1] == ':'))
Packit dd8086
    return true;
Packit dd8086
Packit dd8086
  if ( ! WIN_NT ) return false;
Packit dd8086
Packit dd8086
  /* Test to see if of form: \\.\x: */
Packit dd8086
  return ( (len == 6)
Packit dd8086
	   && source_name[0] == '\\' && source_name[1] == '\\'
Packit dd8086
	   && source_name[2] == '.'  && source_name[3] == '\\'
Packit dd8086
	   && isalpha((unsigned char) source_name[len-2])
Packit dd8086
	   && (source_name[len-1] == ':') );
Packit dd8086
#else
Packit dd8086
  return false;
Packit dd8086
#endif
Packit dd8086
}
Packit dd8086
Packit dd8086
driver_return_code_t
Packit dd8086
close_tray_win32 (const char *psz_win32_drive)
Packit dd8086
{
Packit dd8086
#ifdef HAVE_WIN32_CDROM
Packit dd8086
#if 1
Packit dd8086
  return open_close_media_win32(psz_win32_drive, MCI_SET_DOOR_CLOSED|MCI_WAIT);
Packit dd8086
#else
Packit dd8086
  if ( WIN_NT ) {
Packit dd8086
    return close_tray_win32ioctl (psz_win32_drive);
Packit dd8086
  } else {
Packit dd8086
    return DRIVER_OP_UNSUPPORTED; /* not yet, but soon I hope */
Packit dd8086
  }
Packit dd8086
#endif
Packit dd8086
#else
Packit dd8086
  return DRIVER_OP_UNSUPPORTED;
Packit dd8086
#endif /* HAVE_WIN32_CDROM*/
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Initialization routine. This is the only thing that doesn't
Packit dd8086
  get called via a function pointer. In fact *we* are the
Packit dd8086
  ones to set that up.
Packit dd8086
 */
Packit dd8086
CdIo_t *
Packit dd8086
cdio_open_win32 (const char *psz_source_name)
Packit dd8086
{
Packit dd8086
#ifdef HAVE_WIN32_CDROM
Packit dd8086
  if ( WIN_NT ) {
Packit dd8086
    return cdio_open_am_win32(psz_source_name, "ioctl");
Packit dd8086
  } else {
Packit dd8086
    return cdio_open_am_win32(psz_source_name, "ASPI");
Packit dd8086
  }
Packit dd8086
#else
Packit dd8086
  return NULL;
Packit dd8086
#endif /* HAVE_WIN32_CDROM */
Packit dd8086
}
Packit dd8086
Packit dd8086
/*!
Packit dd8086
  Initialization routine. This is the only thing that doesn't
Packit dd8086
  get called via a function pointer. In fact *we* are the
Packit dd8086
  ones to set that up.
Packit dd8086
 */
Packit dd8086
CdIo_t *
Packit dd8086
cdio_open_am_win32 (const char *psz_orig_source, const char *psz_access_mode)
Packit dd8086
{
Packit dd8086
Packit dd8086
#ifdef HAVE_WIN32_CDROM
Packit dd8086
  CdIo_t *ret;
Packit dd8086
  _img_private_t *_data;
Packit dd8086
  char *psz_source;
Packit dd8086
Packit dd8086
  cdio_funcs_t _funcs;
Packit dd8086
Packit dd8086
  memset( &_funcs, 0, sizeof(_funcs) );
Packit dd8086
Packit dd8086
  _funcs.audio_get_volume       = audio_get_volume_win32;
Packit dd8086
  _funcs.audio_pause            = audio_pause_win32;
Packit dd8086
  _funcs.audio_play_msf         = audio_play_msf_win32;
Packit dd8086
#if 0
Packit dd8086
  _funcs.audio_play_track_index = audio_play_track_index_win32;
Packit dd8086
#endif
Packit dd8086
  _funcs.audio_read_subchannel  = audio_read_subchannel_win32;
Packit dd8086
  _funcs.audio_resume           = audio_resume_win32;
Packit dd8086
  _funcs.audio_set_volume       = audio_set_volume_win32;
Packit dd8086
  _funcs.audio_stop             = audio_stop_win32;
Packit dd8086
  _funcs.eject_media            = eject_media_win32;
Packit dd8086
  _funcs.free                   = free_win32;
Packit dd8086
  _funcs.get_arg                = get_arg_win32;
Packit dd8086
  _funcs.get_cdtext             = get_cdtext_generic;
Packit dd8086
  _funcs.get_cdtext_raw         = read_cdtext_generic;
Packit dd8086
  _funcs.get_default_device     = cdio_get_default_device_win32;
Packit dd8086
  _funcs.get_devices            = cdio_get_devices_win32;
Packit dd8086
  _funcs.get_disc_last_lsn      = get_disc_last_lsn_win32;
Packit dd8086
  _funcs.get_discmode           = get_discmode_win32;
Packit dd8086
  _funcs.get_drive_cap          = get_drive_cap_mmc;
Packit dd8086
  _funcs.get_first_track_num    = get_first_track_num_generic;
Packit dd8086
  _funcs.get_hwinfo             = NULL;
Packit dd8086
  _funcs.get_last_session       = get_last_session_win32;
Packit dd8086
  _funcs.get_media_changed      = get_media_changed_mmc;
Packit dd8086
  _funcs.get_mcn                = _cdio_get_mcn;
Packit dd8086
  _funcs.get_num_tracks         = get_num_tracks_generic;
Packit dd8086
  _funcs.get_track_channels     = get_track_channels_generic,
Packit dd8086
  _funcs.get_track_copy_permit  = get_track_copy_permit_generic,
Packit dd8086
  _funcs.get_track_format       = _cdio_get_track_format;
Packit dd8086
  _funcs.get_track_green        = _cdio_get_track_green;
Packit dd8086
  _funcs.get_track_lba          = NULL; /* This could be done if need be. */
Packit dd8086
  _funcs.get_track_msf          = _cdio_get_track_msf;
Packit dd8086
  _funcs.get_track_preemphasis  = get_track_preemphasis_generic,
Packit dd8086
  _funcs.get_track_isrc         = _cdio_get_track_isrc;
Packit dd8086
  _funcs.lseek                  = NULL;
Packit dd8086
  _funcs.read                   = NULL;
Packit dd8086
  _funcs.read_audio_sectors     = read_audio_sectors;
Packit dd8086
  _funcs.read_data_sectors      = read_data_sectors_win32;
Packit dd8086
  _funcs.read_mode1_sector      = read_mode1_sector_win32;
Packit dd8086
  _funcs.read_mode1_sectors     = read_mode1_sectors_win32;
Packit dd8086
  _funcs.read_mode2_sector      = read_mode2_sector_win32;
Packit dd8086
  _funcs.read_mode2_sectors     = read_mode2_sectors_win32;
Packit dd8086
  _funcs.read_toc               = read_toc_win32;
Packit dd8086
  _funcs.run_mmc_cmd            = run_mmc_cmd_win32;
Packit dd8086
  _funcs.set_arg                = set_arg_win32;
Packit dd8086
  _funcs.set_blocksize          = set_blocksize_mmc;
Packit dd8086
  _funcs.set_speed              = set_drive_speed_mmc;
Packit dd8086
Packit dd8086
  _data                 = calloc(1, sizeof (_img_private_t));
Packit dd8086
  _data->access_mode    = str_to_access_mode_win32(psz_access_mode);
Packit dd8086
  _data->gen.init       = false;
Packit dd8086
  _data->gen.fd         = -1;
Packit dd8086
Packit dd8086
  if (NULL == psz_orig_source) {
Packit dd8086
    psz_source=cdio_get_default_device_win32();
Packit dd8086
    if (NULL == psz_source) {
Packit dd8086
      goto error_exit;
Packit dd8086
    }
Packit dd8086
    set_arg_win32(_data, "source", psz_source);
Packit dd8086
    free(psz_source);
Packit dd8086
  } else {
Packit dd8086
    if (cdio_is_device_win32(psz_orig_source))
Packit dd8086
      set_arg_win32(_data, "source", psz_orig_source);
Packit dd8086
    else {
Packit dd8086
      /* The below would be okay as an info message if all device
Packit dd8086
	 drivers worked this way. */
Packit dd8086
      cdio_debug ("source %s is a not a device", psz_orig_source);
Packit dd8086
      goto error_exit;
Packit dd8086
    }
Packit dd8086
  }
Packit dd8086
Packit dd8086
  ret = cdio_new ((void *)_data, &_funcs);
Packit dd8086
  if (ret == NULL) {
Packit dd8086
    goto error_exit;
Packit dd8086
  }
Packit dd8086
Packit dd8086
  if (init_win32(_data)) {
Packit dd8086
    return ret;
Packit dd8086
  }
Packit dd8086
  
Packit dd8086
Packit dd8086
 error_exit:
Packit dd8086
  free_win32(_data);
Packit dd8086
  return(NULL);
Packit dd8086
#else
Packit dd8086
  return NULL;
Packit dd8086
#endif /* HAVE_WIN32_CDROM */
Packit dd8086
Packit dd8086
}
Packit dd8086
Packit dd8086
bool
Packit dd8086
cdio_have_win32 (void)
Packit dd8086
{
Packit dd8086
#ifdef HAVE_WIN32_CDROM
Packit dd8086
  return true;
Packit dd8086
#else
Packit dd8086
  return false;
Packit dd8086
#endif /* HAVE_WIN32_CDROM */
Packit dd8086
}