BIG REORGANIZATION.

Reorganize directory structure for inclusion of cd-paranoia. Works for
GNU/Linux. Other OS's may be broken. Regression test output needs to
be adjusted too.

Move:
lib/driver (split off of lib)
lib/iso9660 (split off of lib)

Add from paranoia:
lib/cdda_interface
lib/paranoia
src/paranoia

Also made some small changes to capability indentification to show
more reading capabilties and show that.

cd-info now shows the total disc size.
This commit is contained in:
rocky
2004-12-18 17:29:32 +00:00
parent a8f67b6163
commit 6c14d28918
109 changed files with 10863 additions and 329 deletions

9
lib/driver/.cvsignore Normal file
View File

@@ -0,0 +1,9 @@
.deps
.libs
Makefile
Makefile.in
*.o
*.lo
*.la
*.la.ver

View File

@@ -0,0 +1,23 @@
# $Id: Makefile,v 1.1 2004/12/18 17:29:32 rocky Exp $
#
# Copyright (C) 2004 Rocky Bernstein
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#######################################
# The make is done above. This boilerplate Makefile just transfers the call
all install check clean:
cd .. && $(MAKE) $@

View File

@@ -0,0 +1,638 @@
/*
$Id: freebsd.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This file contains FreeBSD-specific code and implements low-level
control of the CD drive. Culled initially I think from xine's or
mplayer's FreeBSD code with lots of modifications.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: freebsd.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
#include "freebsd.h"
#ifdef HAVE_FREEBSD_CDROM
#include <cdio/sector.h>
static access_mode_t
str_to_access_mode_freebsd(const char *psz_access_mode)
{
const access_mode_t default_access_mode = DEFAULT_FREEBSD_AM;
if (NULL==psz_access_mode) return default_access_mode;
if (!strcmp(psz_access_mode, "ioctl"))
return _AM_IOCTL;
else if (!strcmp(psz_access_mode, "CAM"))
return _AM_CAM;
else {
cdio_warn ("unknown access type: %s. Default ioctl used.",
psz_access_mode);
return default_access_mode;
}
}
static void
_free_freebsd (void *obj)
{
_img_private_t *env = obj;
if (NULL == env) return;
if (NULL != env->device) free(env->device);
if (_AM_CAM == env->access_mode)
return free_freebsd_cam(env);
else
return cdio_generic_free(obj);
}
/* Check a drive to see if it is a CD-ROM
Return 1 if a CD-ROM. 0 if it exists but isn't a CD-ROM drive
and -1 if no device exists .
*/
static bool
cdio_is_cdrom(char *drive, char *mnttype)
{
return cdio_is_cdrom_freebsd_ioctl(drive, mnttype);
}
/*!
Reads nblocks of audio sectors from cd device into data starting from lsn.
Returns 0 if no error.
*/
static int
_read_audio_sectors_freebsd (void *user_data, void *data, lsn_t lsn,
unsigned int nblocks)
{
return read_audio_sectors_freebsd_ioctl(user_data, data, lsn, nblocks);
}
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
static int
_read_mode2_sector_freebsd (void *user_data, void *data, lsn_t lsn,
bool b_form2)
{
_img_private_t *env = user_data;
if ( env->access_mode == _AM_CAM )
return read_mode2_sector_freebsd_cam(env, data, lsn, b_form2);
else
return read_mode2_sector_freebsd_ioctl(env, data, lsn, b_form2);
}
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
static int
_read_mode2_sectors_freebsd (void *user_data, void *data, lsn_t lsn,
bool b_form2, unsigned int nblocks)
{
_img_private_t *env = user_data;
if ( env->access_mode == _AM_CAM && b_form2) {
/* We have a routine that covers this case without looping. */
return read_mode2_sectors_freebsd_cam(env, data, lsn, nblocks);
} else {
unsigned int i;
unsigned int i_blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
/* For each frame, pick out the data part we need */
for (i = 0; i < nblocks; i++) {
int retval = _read_mode2_sector_freebsd (env,
((char *)data) +
(i_blocksize * i),
lsn + i, b_form2);
if (retval) return retval;
}
}
return 0;
}
/*!
Return the size of the CD in logical block address (LBA) units.
*/
static uint32_t
_stat_size_freebsd (void *obj)
{
_img_private_t *env = obj;
if (NULL == env) return CDIO_INVALID_LBA;
if (_AM_CAM == env->access_mode)
return stat_size_freebsd_cam(env);
else
return stat_size_freebsd_ioctl(env);
}
/*!
Set the key "arg" to "value" in source device.
*/
static int
_set_arg_freebsd (void *user_data, const char key[], const char value[])
{
_img_private_t *env = user_data;
if (!strcmp (key, "source"))
{
if (!value)
return -2;
free (env->gen.source_name);
env->gen.source_name = strdup (value);
}
else if (!strcmp (key, "access-mode"))
{
env->access_mode = str_to_access_mode_freebsd(value);
if (env->access_mode == _AM_CAM && !env->b_cam_init)
return init_freebsd_cam(env) ? 1 : -3;
return 0;
}
else
return -1;
return 0;
}
/*!
Read and cache the CD's Track Table of Contents and track info.
Return false if unsuccessful;
*/
static bool
read_toc_freebsd (void *p_user_data)
{
_img_private_t *p_env = p_user_data;
track_t i, j;
/* read TOC header */
if ( ioctl(p_env->gen.fd, CDIOREADTOCHEADER, &p_env->tochdr) == -1 ) {
cdio_warn("error in ioctl(CDIOREADTOCHEADER): %s\n", strerror(errno));
return false;
}
p_env->gen.i_first_track = p_env->tochdr.starting_track;
p_env->gen.i_tracks = p_env->tochdr.ending_track -
p_env->gen.i_first_track + 1;
j=0;
for (i=p_env->gen.i_first_track; i<=p_env->gen.i_tracks; i++, j++) {
p_env->tocent[j].track = i;
p_env->tocent[j].address_format = CD_LBA_FORMAT;
if ( ioctl(p_env->gen.fd, CDIOREADTOCENTRY, &(p_env->tocent[j]) ) ) {
cdio_warn("%s %d: %s\n",
"error in ioctl CDROMREADTOCENTRY for track",
i, strerror(errno));
return false;
}
}
p_env->tocent[j].track = CDIO_CDROM_LEADOUT_TRACK;
p_env->tocent[j].address_format = CD_LBA_FORMAT;
if ( ioctl(p_env->gen.fd, CDIOREADTOCENTRY, &(p_env->tocent[j]) ) ){
cdio_warn("%s: %s\n",
"error in ioctl CDROMREADTOCENTRY for leadout track",
strerror(errno));
return false;
}
p_env->gen.toc_init = true;
return true;
}
/*!
Eject media. Return 1 if successful, 0 otherwise.
*/
static int
_eject_media_freebsd (void *user_data)
{
_img_private_t *p_env = user_data;
return (p_env->access_mode == _AM_IOCTL)
? eject_media_freebsd_ioctl(p_env)
: eject_media_freebsd_cam(p_env);
}
/*!
Return the value associated with the key "arg".
*/
static const char *
_get_arg_freebsd (void *user_data, const char key[])
{
_img_private_t *env = user_data;
if (!strcmp (key, "source")) {
return env->gen.source_name;
} else if (!strcmp (key, "access-mode")) {
switch (env->access_mode) {
case _AM_IOCTL:
return "ioctl";
case _AM_CAM:
return "CAM";
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.
FIXME: This is just a guess.
*/
static char *
_get_mcn_freebsd (const void *p_user_data) {
const _img_private_t *p_env = p_user_data;
return (p_env->access_mode == _AM_IOCTL)
? get_mcn_freebsd_ioctl(p_env)
: scsi_mmc_get_mcn(p_env->gen.cdio);
}
static void
get_drive_cap_freebsd (const void *p_user_data,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap)
{
const _img_private_t *p_env = p_user_data;
if (p_env->access_mode == _AM_CAM)
scsi_mmc_get_drive_cap_generic (p_user_data, p_read_cap, p_write_cap,
p_misc_cap);
}
/*!
Run a SCSI MMC command.
p_user_data internal CD structure.
i_timeout_ms time in milliseconds we will wait for the command
to complete. If this value is -1, use the default
time-out value.
i_cdb Size of p_cdb
p_cdb CDB bytes.
e_direction direction the transfer is to go.
i_buf Size of buffer
p_buf Buffer for data, both sending and receiving
Return 0 if no error.
*/
static int
run_scsi_cmd_freebsd( const void *p_user_data, unsigned int i_timeout_ms,
unsigned int i_cdb, const scsi_mmc_cdb_t *p_cdb,
scsi_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf )
{
const _img_private_t *p_env = p_user_data;
if (p_env->access_mode == _AM_CAM)
return run_scsi_cmd_freebsd_cam( p_user_data, i_timeout_ms, i_cdb, p_cdb,
e_direction, i_buf, p_buf );
else
return 2;
}
/*!
Get format of track.
FIXME: We're just guessing this from the GNU/Linux code.
*/
static track_format_t
_get_track_format_freebsd(void *p_user_data, track_t i_track)
{
_img_private_t *p_env = p_user_data;
if (!p_env->gen.toc_init) read_toc_freebsd (p_user_data) ;
if (i_track > TOTAL_TRACKS || i_track == 0)
return TRACK_FORMAT_ERROR;
i_track -= FIRST_TRACK_NUM;
/* This is pretty much copied from the "badly broken" cdrom_count_tracks
in linux/cdrom.c.
*/
if (p_env->tocent[i_track].entry.control & CDIO_CDROM_DATA_TRACK) {
if (p_env->tocent[i_track].address_format == CDIO_CDROM_CDI_TRACK)
return TRACK_FORMAT_CDI;
else if (p_env->tocent[i_track].address_format == CDIO_CDROM_XA_TRACK)
return TRACK_FORMAT_XA;
else
return TRACK_FORMAT_DATA;
} else
return TRACK_FORMAT_AUDIO;
}
/*!
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
_get_track_green_freebsd(void *user_data, track_t i_track)
{
_img_private_t *p_env = user_data;
if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = TOTAL_TRACKS+1;
if (i_track > TOTAL_TRACKS+1 || i_track == 0)
return false;
/* FIXME: Dunno if this is the right way, but it's what
I was using in cdinfo for a while.
*/
return ((p_env->tocent[i_track-FIRST_TRACK_NUM].entry.control & 2) != 0);
}
/*!
Return the starting LSN track number
i_track in obj. Track numbers start at 1.
The "leadout" track is specified either by
using i_track LEADOUT_TRACK or the total tracks+1.
CDIO_INVALID_LBA is returned if there is no track entry.
*/
static lba_t
_get_track_lba_freebsd(void *user_data, track_t i_track)
{
_img_private_t *p_env = user_data;
if (!p_env->gen.toc_init) read_toc_freebsd (p_env) ;
if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = TOTAL_TRACKS+1;
if (i_track > TOTAL_TRACKS+1 || i_track == 0 || !p_env->gen.toc_init) {
return CDIO_INVALID_LBA;
} else {
return cdio_lsn_to_lba(ntohl(p_env->tocent[i_track-FIRST_TRACK_NUM].entry.addr.lba));
}
}
#endif /* HAVE_FREEBSD_CDROM */
/*!
Return an array of strings giving possible CD devices.
*/
char **
cdio_get_devices_freebsd (void)
{
#ifndef HAVE_FREEBSD_CDROM
return NULL;
#else
char drive[40];
char **drives = NULL;
unsigned int num_drives=0;
bool exists=true;
char c;
/* Scan the system for CD-ROM drives.
*/
#ifdef USE_ETC_FSTAB
struct fstab *fs;
setfsent();
/* Check what's in /etc/fstab... */
while ( (fs = getfsent()) )
{
if (strncmp(fs->fs_spec, "/dev/sr", 7))
cdio_add_device_list(&drives, fs->fs_spec, &num_drives);
}
#endif
/* Scan the system for CD-ROM drives.
Not always 100% reliable, so use the USE_MNTENT code above first.
*/
/* Scan SCSI and CAM devices */
for ( c='0'; exists && c <='9'; c++ ) {
sprintf(drive, "/dev/cd%c%s", c, DEVICE_POSTFIX);
exists = cdio_is_cdrom(drive, NULL);
if ( exists ) {
cdio_add_device_list(&drives, drive, &num_drives);
}
}
/* Scan are ATAPI devices */
for ( c='0'; exists && c <='9'; c++ ) {
sprintf(drive, "/dev/acd%c%s", c, DEVICE_POSTFIX);
exists = cdio_is_cdrom(drive, NULL);
if ( exists ) {
cdio_add_device_list(&drives, drive, &num_drives);
}
}
cdio_add_device_list(&drives, NULL, &num_drives);
return drives;
#endif /*HAVE_FREEBSD_CDROM*/
}
/*!
Return a string containing the default CD device if none is specified.
*/
char *
cdio_get_default_device_freebsd()
{
#ifndef HAVE_FREEBSD_CDROM
return NULL;
#else
char drive[40];
bool exists=true;
char c;
/* Scan the system for CD-ROM drives.
*/
#ifdef USE_ETC_FSTAB
struct fstab *fs;
setfsent();
/* Check what's in /etc/fstab... */
while ( (fs = getfsent()) )
{
if (strncmp(fs->fs_spec, "/dev/sr", 7))
return strdup(fs->fs_spec);
}
#endif
/* Scan the system for CD-ROM drives.
Not always 100% reliable, so use the USE_MNTENT code above first.
*/
/* Scan SCSI and CAM devices */
for ( c='0'; exists && c <='9'; c++ ) {
sprintf(drive, "/dev/cd%c%s", c, DEVICE_POSTFIX);
exists = cdio_is_cdrom(drive, NULL);
if ( exists ) {
return strdup(drive);
}
}
/* Scan are ATAPI devices */
for ( c='0'; exists && c <='9'; c++ ) {
sprintf(drive, "/dev/acd%c%s", c, DEVICE_POSTFIX);
exists = cdio_is_cdrom(drive, NULL);
if ( exists ) {
return strdup(drive);
}
}
return NULL;
#endif /*HAVE_FREEBSD_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 *
cdio_open_freebsd (const char *psz_source_name)
{
return cdio_open_am_freebsd(psz_source_name, NULL);
}
/*!
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 *
cdio_open_am_freebsd (const char *psz_orig_source_name,
const char *psz_access_mode)
{
#ifdef HAVE_FREEBSD_CDROM
CdIo *ret;
_img_private_t *_data;
char *psz_source_name;
cdio_funcs _funcs = {
.eject_media = _eject_media_freebsd,
.free = _free_freebsd,
.get_arg = _get_arg_freebsd,
.get_cdtext = get_cdtext_generic,
.get_default_device = cdio_get_default_device_freebsd,
.get_devices = cdio_get_devices_freebsd,
.get_discmode = get_discmode_generic,
.get_drive_cap = get_drive_cap_freebsd,
.get_first_track_num= get_first_track_num_generic,
.get_mcn = _get_mcn_freebsd,
.get_num_tracks = get_num_tracks_generic,
.get_track_format = _get_track_format_freebsd,
.get_track_green = _get_track_green_freebsd,
.get_track_lba = _get_track_lba_freebsd,
.get_track_msf = NULL,
.lseek = cdio_generic_lseek,
.read = cdio_generic_read,
.read_audio_sectors = _read_audio_sectors_freebsd,
.read_mode2_sector = _read_mode2_sector_freebsd,
.read_mode2_sectors = _read_mode2_sectors_freebsd,
.read_toc = read_toc_freebsd,
.run_scsi_mmc_cmd = run_scsi_cmd_freebsd,
.set_arg = _set_arg_freebsd,
.stat_size = _stat_size_freebsd
};
_data = _cdio_malloc (sizeof (_img_private_t));
_data->access_mode = str_to_access_mode_freebsd(psz_access_mode);
_data->gen.init = false;
_data->gen.fd = -1;
_data->gen.toc_init = false;
_data->gen.b_cdtext_init = false;
_data->gen.b_cdtext_error = false;
if (NULL == psz_orig_source_name) {
psz_source_name=cdio_get_default_device_freebsd();
if (NULL == psz_source_name) return NULL;
_data->device = psz_source_name;
_set_arg_freebsd(_data, "source", psz_source_name);
} else {
if (cdio_is_device_generic(psz_orig_source_name)) {
_set_arg_freebsd(_data, "source", psz_orig_source_name);
_data->device = strdup(psz_orig_source_name);
} 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_name);
#endif
return NULL;
}
}
ret = cdio_new ((void *)_data, &_funcs);
if (ret == NULL) return NULL;
if (cdio_generic_init(_data))
if ( _data->access_mode == _AM_IOCTL ) {
return ret;
} else {
if (init_freebsd_cam(_data))
return ret;
else {
cdio_generic_free (_data);
return NULL;
}
}
else {
cdio_generic_free (_data);
return NULL;
}
#else
return NULL;
#endif /* HAVE_FREEBSD_CDROM */
}
bool
cdio_have_freebsd (void)
{
#ifdef HAVE_FREEBSD_CDROM
return true;
#else
return false;
#endif /* HAVE_FREEBSD_CDROM */
}

View File

@@ -0,0 +1,232 @@
/*
$Id: freebsd.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This file contains FreeBSD-specific code and implements low-level
control of the CD drive. Culled initially I think from xine's or
mplayer's FreeBSD code with lots of modifications.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/sector.h>
#include "cdio_assert.h"
#include "cdio_private.h"
/*!
For ioctl access /dev/acd0c is preferred over /dev/cd0c.
For cam access /dev/cd0c is preferred. DEFAULT_CDIO_DEVICE and
DEFAULT_FREEBSD_AM should be consistent.
*/
#ifndef DEFAULT_CDIO_DEVICE
#define DEFAULT_CDIO_DEVICE "/dev/cd0c"
#endif
#ifndef DEFUALT_FREEBSD_AM
#define DEFAULT_FREEBSD_AM _AM_CAM
#endif
#include <string.h>
#ifdef HAVE_FREEBSD_CDROM
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef HAVE_SYS_CDIO_H
# include <sys/cdio.h>
#endif
#ifndef CDIOCREADAUDIO
struct ioc_read_audio
{
u_char address_format;
union msf_lba address;
int nframes;
u_char* buffer;
};
#define CDIOCREADAUDIO _IOWR('c',31,struct ioc_read_audio)
#endif
#include <sys/cdrio.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/param.h> /* for __FreeBSD_version */
#if __FreeBSD_version < 500000
#define DEVICE_POSTFIX "c"
#else
#define DEVICE_POSTFIX ""
#endif
#define HAVE_FREEBSD_CAM
#ifdef HAVE_FREEBSD_CAM
#include <camlib.h>
#include <cam/scsi/scsi_message.h>
#include <cam/scsi/scsi_pass.h>
#include <errno.h>
#define ERRCODE(s) ((((s)[2]&0x0F)<<16)|((s)[12]<<8)|((s)[13]))
#define EMEDIUMTYPE EINVAL
#define ENOMEDIUM ENODEV
#define CREAM_ON_ERRNO(s) do { \
switch ((s)[12]) \
{ case 0x04: errno=EAGAIN; break; \
case 0x20: errno=ENODEV; break; \
case 0x21: if ((s)[13]==0) errno=ENOSPC; \
else errno=EINVAL; \
break; \
case 0x30: errno=EMEDIUMTYPE; break; \
case 0x3A: errno=ENOMEDIUM; break; \
} \
} while(0)
#endif /*HAVE_FREEBSD_CAM*/
#include <cdio/util.h>
#define TOTAL_TRACKS ( p_env->tochdr.ending_track \
- p_env->tochdr.starting_track + 1)
#define FIRST_TRACK_NUM (p_env->tochdr.starting_track)
typedef enum {
_AM_NONE,
_AM_IOCTL,
_AM_CAM
} access_mode_t;
typedef struct {
/* Things common to all drivers like this.
This must be first. */
generic_img_private_t gen;
#ifdef HAVE_FREEBSD_CAM
char *device;
struct cam_device *cam;
union ccb ccb;
#endif
access_mode_t access_mode;
bool b_ioctl_init;
bool b_cam_init;
/* Track information */
struct ioc_toc_header tochdr;
/* Entry info for each track. Add 1 for leadout. */
struct ioc_read_toc_single_entry tocent[CDIO_CD_MAX_TRACKS+1];
} _img_private_t;
bool cdio_is_cdrom_freebsd_ioctl(char *drive, char *mnttype);
track_format_t get_track_format_freebsd_ioctl(const _img_private_t *env,
track_t i_track);
bool get_track_green_freebsd_ioctl(const _img_private_t *env,
track_t i_track);
int eject_media_freebsd_ioctl (_img_private_t *env);
int eject_media_freebsd_cam (_img_private_t *env);
void get_drive_cap_freebsd_cam (const _img_private_t *p_env,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap);
char *get_mcn_freebsd_ioctl (const _img_private_t *p_env);
void free_freebsd_cam (void *obj);
/*!
Using the ioctl method, r nblocks of audio sectors from cd device
into data starting from lsn. Returns 0 if no error.
*/
int read_audio_sectors_freebsd_ioctl (_img_private_t *env, void *data,
lsn_t lsn, unsigned int nblocks);
/*!
Using the CAM method, reads nblocks of mode2 sectors from
cd device using into data starting from lsn. Returns 0 if no
error.
*/
int read_mode2_sector_freebsd_cam (_img_private_t *env, void *data,
lsn_t lsn, bool b_form2);
/*!
Using the ioctl method, reads nblocks of mode2 sectors from
cd device using into data starting from lsn. Returns 0 if no
error.
*/
int read_mode2_sector_freebsd_ioctl (_img_private_t *env, void *data,
lsn_t lsn, bool b_form2);
/*!
Using the CAM method, reads nblocks of mode2 form2 sectors from
cd device using into data starting from lsn. Returns 0 if no
error.
Note: if you want form1 sectors, the caller has to pick out the
appropriate piece.
*/
int read_mode2_sectors_freebsd_cam (_img_private_t *env, void *buf,
lsn_t lsn, unsigned int nblocks);
bool read_toc_freebsd_ioctl (_img_private_t *env);
/*!
Run a SCSI MMC command.
p_user_data internal CD structure.
i_timeout time in milliseconds we will wait for the command
to complete. If this value is -1, use the default
time-out value.
i_cdb Size of p_cdb
p_cdb CDB bytes.
e_direction direction the transfer is to go.
i_buf Size of buffer
p_buf Buffer for data, both sending and receiving
Return 0 if no error.
*/
int run_scsi_cmd_freebsd_cam( const void *p_user_data,
unsigned int i_timeout_ms,
unsigned int i_cdb,
const scsi_mmc_cdb_t *p_cdb,
scsi_mmc_direction_t e_direction,
unsigned int i_buf,
/*in/out*/ void *p_buf );
/*!
Return the size of the CD in logical block address (LBA) units.
*/
uint32_t stat_size_freebsd_cam (_img_private_t *env);
uint32_t stat_size_freebsd_ioctl (_img_private_t *env);
bool init_freebsd_cam (_img_private_t *env);
void free_freebsd_cam (void *user_data);
#endif /*HAVE_FREEBSD_CDROM*/

View File

@@ -0,0 +1,346 @@
/*
$Id: freebsd_cam.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This file contains FreeBSD-specific code and implements low-level
control of the CD drive via SCSI emulation.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: freebsd_cam.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
#ifdef HAVE_FREEBSD_CDROM
#include "freebsd.h"
#include <cdio/scsi_mmc.h>
/* Default value in seconds we will wait for a command to
complete. */
#define DEFAULT_TIMEOUT_MSECS 10000
/*!
Run a SCSI MMC command.
p_user_data internal CD structure.
i_timeout_ms time in milliseconds we will wait for the command
to complete. If this value is -1, use the default
time-out value.
i_cdb Size of p_cdb
p_cdb CDB bytes.
e_direction direction the transfer is to go.
i_buf Size of buffer
p_buf Buffer for data, both sending and receiving
Return 0 if no error.
*/
int
run_scsi_cmd_freebsd_cam( const void *p_user_data, unsigned int i_timeout_ms,
unsigned int i_cdb, const scsi_mmc_cdb_t *p_cdb,
scsi_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf )
{
const _img_private_t *p_env = p_user_data;
int i_status;
int direction = CAM_DEV_QFRZDIS;
union ccb ccb;
if (!p_env || !p_env->cam) return -2;
memset(&ccb, 0, sizeof(ccb));
ccb.ccb_h.path_id = p_env->cam->path_id;
ccb.ccb_h.target_id = p_env->cam->target_id;
ccb.ccb_h.target_lun = p_env->cam->target_lun;
ccb.ccb_h.timeout = i_timeout_ms;
if (!i_cdb)
direction |= CAM_DIR_NONE;
else
direction |= (e_direction == SCSI_MMC_DATA_READ)?CAM_DIR_IN : CAM_DIR_OUT;
cam_fill_csio (&(ccb.csio), 1, NULL,
direction | CAM_DEV_QFRZDIS, MSG_SIMPLE_Q_TAG, p_buf, i_buf,
sizeof(ccb.csio.sense_data), 0, 30*1000);
memcpy(ccb.csio.cdb_io.cdb_bytes, p_cdb, i_cdb);
ccb.csio.cdb_len =
scsi_mmc_get_cmd_len(ccb.csio.cdb_io.cdb_bytes[0]);
if ((i_status = cam_send_ccb(p_env->cam, &ccb)) < 0)
{
cdio_warn ("transport failed: %d", i_status);
return -1;
}
if ((ccb.ccb_h.status & CAM_STATUS_MASK) == CAM_REQ_CMP)
{
return 0;
}
errno = EIO;
i_status = ERRCODE(((unsigned char *)&ccb.csio.sense_data));
if (i_status == 0)
i_status = -1;
else
CREAM_ON_ERRNO(((unsigned char *)&ccb.csio.sense_data));
cdio_warn ("transport failed: %d", i_status);
return i_status;
}
bool
init_freebsd_cam (_img_private_t *p_env)
{
char pass[100];
p_env->cam=NULL;
memset (&p_env->ccb, 0, sizeof(p_env->ccb));
p_env->ccb.ccb_h.func_code = XPT_GDEVLIST;
if (-1 == p_env->gen.fd)
p_env->gen.fd = open (p_env->device, O_RDONLY, 0);
if (p_env->gen.fd < 0)
{
cdio_warn ("open (%s): %s", p_env->device, strerror (errno));
return false;
}
if (ioctl (p_env->gen.fd, CAMGETPASSTHRU, &p_env->ccb) < 0)
{
cdio_warn ("open: %s", strerror (errno));
return false;
}
sprintf (pass,"/dev/%.15s%u",
p_env->ccb.cgdl.periph_name,
p_env->ccb.cgdl.unit_number);
p_env->cam = cam_open_pass (pass,O_RDWR,NULL);
if (!p_env->cam) return false;
p_env->gen.init = true;
p_env->b_cam_init = true;
return true;
}
void
free_freebsd_cam (void *user_data)
{
_img_private_t *p_env = user_data;
if (NULL == p_env) return;
if (p_env->gen.fd > 0)
close (p_env->gen.fd);
p_env->gen.fd = -1;
if(p_env->cam)
cam_close_device(p_env->cam);
free (p_env);
}
static int
_set_bsize (_img_private_t *p_env, unsigned int bsize)
{
scsi_mmc_cdb_t cdb = {{0, }};
struct
{
uint8_t reserved1;
uint8_t medium;
uint8_t reserved2;
uint8_t block_desc_length;
uint8_t density;
uint8_t number_of_blocks_hi;
uint8_t number_of_blocks_med;
uint8_t number_of_blocks_lo;
uint8_t reserved3;
uint8_t block_length_hi;
uint8_t block_length_med;
uint8_t block_length_lo;
} mh;
memset (&mh, 0, sizeof (mh));
mh.block_desc_length = 0x08;
mh.block_length_hi = (bsize >> 16) & 0xff;
mh.block_length_med = (bsize >> 8) & 0xff;
mh.block_length_lo = (bsize >> 0) & 0xff;
memset (&cdb, 0, sizeof (cdb));
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SELECT_6);
cdb.field[1] = 1 << 4;
cdb.field[4] = 12;
return run_scsi_cmd_freebsd_cam (p_env, DEFAULT_TIMEOUT_MSECS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_WRITE,
sizeof(mh), &mh);
}
int
read_mode2_sector_freebsd_cam (_img_private_t *p_env, void *data, lsn_t lsn,
bool b_form2)
{
if ( b_form2 )
return read_mode2_sectors_freebsd_cam(p_env, data, lsn, 1);
else {
/* Need to pick out the data portion from a mode2 form2 frame */
char buf[M2RAW_SECTOR_SIZE] = { 0, };
int retval = read_mode2_sectors_freebsd_cam(p_env, buf, lsn, 1);
if ( retval ) return retval;
memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE);
return 0;
}
}
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
int
read_mode2_sectors_freebsd_cam (_img_private_t *p_env, void *p_buf,
lsn_t lsn, unsigned int nblocks)
{
scsi_mmc_cdb_t cdb = {{0, }};
bool b_read_10 = false;
CDIO_MMC_SET_READ_LBA(cdb.field, lsn);
if (b_read_10) {
int retval;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_10);
CDIO_MMC_SET_READ_LENGTH16(cdb.field, nblocks);
if ((retval = _set_bsize (p_env, M2RAW_SECTOR_SIZE)))
return retval;
if ((retval = run_scsi_cmd_freebsd_cam (p_env, 0,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb,
SCSI_MMC_DATA_READ,
M2RAW_SECTOR_SIZE * nblocks,
p_buf)))
{
_set_bsize (p_env, CDIO_CD_FRAMESIZE);
return retval;
}
if ((retval = _set_bsize (p_env, CDIO_CD_FRAMESIZE)))
return retval;
} else
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_CD);
CDIO_MMC_SET_READ_LENGTH24(cdb.field, nblocks);
cdb.field[1] = 0; /* sector size mode2 */
cdb.field[9] = 0x58; /* 2336 mode2 */
return run_scsi_cmd_freebsd_cam (p_env, 0,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb,
SCSI_MMC_DATA_READ,
M2RAW_SECTOR_SIZE * nblocks, p_buf);
return 0;
}
/*!
Return the size of the CD in logical block address (LBA) units.
*/
uint32_t
stat_size_freebsd_cam (_img_private_t *p_env)
{
scsi_mmc_cdb_t cdb = {{0, }};
uint8_t buf[12] = { 0, };
uint32_t retval;
int i_status;
/* Operation code */
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC);
cdb.field[1] = 0; /* lba; msf: 0x2 */
/* Format */
cdb.field[2] = CDIO_MMC_READTOC_FMT_TOC;
CDIO_MMC_SET_START_TRACK(cdb.field, CDIO_CDROM_LEADOUT_TRACK);
CDIO_MMC_SET_READ_LENGTH16(cdb.field, sizeof(buf));
p_env->ccb.csio.data_ptr = buf;
p_env->ccb.csio.dxfer_len = sizeof (buf);
i_status = run_scsi_cmd_freebsd_cam(p_env, DEFAULT_TIMEOUT_MSECS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
sizeof(buf), buf);
if (0 != i_status)
return 0;
{
int i;
retval = 0;
for (i = 8; i < 12; i++)
{
retval <<= 8;
retval += buf[i];
}
}
return retval;
}
/*!
* Eject using SCSI MMC commands. Return 0 if successful.
*/
int
eject_media_freebsd_cam (_img_private_t *p_env)
{
int i_status;
scsi_mmc_cdb_t cdb = {{0, }};
uint8_t buf[1];
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_ALLOW_MEDIUM_REMOVAL);
i_status = run_scsi_cmd_freebsd_cam (p_env, DEFAULT_TIMEOUT_MSECS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_WRITE, 0, &buf);
if (0 != i_status)
return i_status;
cdb.field[4] = 1;
i_status = run_scsi_cmd_freebsd_cam (p_env, DEFAULT_TIMEOUT_MSECS,
scsi_mmc_get_cmd_len(cdb.field[0]), &cdb,
SCSI_MMC_DATA_WRITE, 0, &buf);
if (0 != i_status)
return i_status;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_START_STOP);
cdb.field[4] = 2; /* eject */
return run_scsi_cmd_freebsd_cam (p_env, DEFAULT_TIMEOUT_MSECS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb,
SCSI_MMC_DATA_WRITE, 0, &buf);
}
#endif /* HAVE_FREEBSD_CDROM */

View File

@@ -0,0 +1,267 @@
/*
$Id: freebsd_ioctl.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This file contains FreeBSD-specific code and implements low-level
control of the CD drive. Culled initially I think from xine's or
mplayer's FreeBSD code with lots of modifications.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: freebsd_ioctl.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
#ifdef HAVE_FREEBSD_CDROM
#include "freebsd.h"
/* Check a drive to see if it is a CD-ROM
Return 1 if a CD-ROM. 0 if it exists but isn't a CD-ROM drive
and -1 if no device exists .
*/
bool
cdio_is_cdrom_freebsd_ioctl(char *drive, char *mnttype)
{
bool is_cd=false;
int cdfd;
struct ioc_toc_header tochdr;
/* If it doesn't exist, return -1 */
if ( !cdio_is_device_quiet_generic(drive) ) {
return(false);
}
/* If it does exist, verify that it's an available CD-ROM */
cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
/* Should we want to test the condition in more detail:
ENOENT is the error for /dev/xxxxx does not exist;
ENODEV means there's no drive present. */
if ( cdfd >= 0 ) {
if ( ioctl(cdfd, CDIOREADTOCHEADER, &tochdr) != -1 ) {
is_cd = true;
}
close(cdfd);
}
/* Even if we can't read it, it might be mounted */
else if ( mnttype && (strcmp(mnttype, "iso9660") == 0) ) {
is_cd = true;
}
return(is_cd);
}
/*!
Reads a single mode2 sector from cd device into data starting from lsn.
Returns 0 if no error.
*/
int
read_audio_sectors_freebsd_ioctl (_img_private_t *_obj, void *data, lsn_t lsn,
unsigned int nblocks)
{
unsigned char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
struct ioc_read_audio cdda;
cdda.address.lba = lsn;
cdda.buffer = buf;
cdda.nframes = nblocks;
cdda.address_format = CDIO_CDROM_LBA;
/* read a frame */
if(ioctl(_obj->gen.fd, CDIOCREADAUDIO, &cdda) < 0) {
perror("CDIOCREADAUDIO");
return 1;
}
memcpy (data, buf, CDIO_CD_FRAMESIZE_RAW);
return 0;
}
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int
read_mode2_sector_freebsd_ioctl (_img_private_t *env, void *data, lsn_t lsn,
bool b_form2)
{
char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
int retval;
if ( !b_form2 )
return cdio_generic_read_form1_sector (env, buf, lsn);
if ( (retval = read_audio_sectors_freebsd_ioctl (env, buf, lsn, 1)) )
return retval;
memcpy (data, buf + CDIO_CD_XA_SYNC_HEADER, M2RAW_SECTOR_SIZE);
return 0;
}
/*!
Return the size of the CD in logical block address (LBA) units.
*/
uint32_t
stat_size_freebsd_ioctl (_img_private_t *_obj)
{
struct ioc_read_toc_single_entry tocent;
uint32_t size;
tocent.track = CDIO_CDROM_LEADOUT_TRACK;
tocent.address_format = CDIO_CDROM_LBA;
if (ioctl (_obj->gen.fd, CDIOREADTOCENTRY, &tocent) == -1)
{
perror ("ioctl(CDROMREADTOCENTRY)");
exit (EXIT_FAILURE);
}
size = tocent.entry.addr.lba;
return size;
}
/*!
Eject media. Return 1 if successful, 0 otherwise.
*/
int
eject_media_freebsd_ioctl (_img_private_t *env)
{
_img_private_t *_obj = env;
int ret=2;
int fd;
if ((fd = open(_obj->gen.source_name, O_RDONLY|O_NONBLOCK)) > -1) {
ret = 1;
if (ioctl(fd, CDIOCALLOW) == -1) {
cdio_warn("ioctl(fd, CDIOCALLOW) failed: %s\n", strerror(errno));
} else if (ioctl(fd, CDIOCEJECT) == -1) {
cdio_warn("ioctl(CDIOCEJECT) failed: %s\n", strerror(errno));
} else {
ret = 0;
}
close(fd);
}
return ret;
}
/*!
Return the media catalog number MCN.
Note: string is malloc'd so caller should free() then returned
string when done with it.
FIXME: This is just a guess.
*/
char *
get_mcn_freebsd_ioctl (const _img_private_t *env) {
struct ioc_read_subchannel subchannel;
struct cd_sub_channel_info subchannel_info;
subchannel.address_format = CDIO_CDROM_MSF;
subchannel.data_format = CDIO_SUBCHANNEL_MEDIA_CATALOG;
subchannel.track = 0;
subchannel.data_len = sizeof(subchannel_info);
subchannel.data = &subchannel_info;
if(ioctl(env->gen.fd, CDIOCREADSUBCHANNEL, &subchannel) < 0) {
perror("CDIOCREADSUBCHANNEL");
return NULL;
}
/* Probably need a loop over tracks rather than give up if we
can't find in track 0.
*/
if (subchannel_info.what.media_catalog.mc_valid)
return strdup(subchannel_info.what.media_catalog.mc_number);
else
return NULL;
}
/*!
Get format of track.
FIXME: We're just guessing this from the GNU/Linux code.
*/
track_format_t
get_track_format_freebsd_ioctl(const _img_private_t *env, track_t i_track)
{
struct ioc_read_subchannel subchannel;
struct cd_sub_channel_info subchannel_info;
subchannel.address_format = CDIO_CDROM_LBA;
subchannel.data_format = CDIO_SUBCHANNEL_CURRENT_POSITION;
subchannel.track = i_track;
subchannel.data_len = 1;
subchannel.data = &subchannel_info;
if(ioctl(env->gen.fd, CDIOCREADSUBCHANNEL, &subchannel) < 0) {
perror("CDIOCREADSUBCHANNEL");
return 1;
}
if (subchannel_info.what.position.control == 0x04) {
if (subchannel_info.what.position.data_format == 0x10)
return TRACK_FORMAT_CDI;
else if (subchannel_info.what.position.data_format == 0x20)
return TRACK_FORMAT_XA;
else
return TRACK_FORMAT_DATA;
} else
return TRACK_FORMAT_AUDIO;
}
/*!
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?
*/
bool
get_track_green_freebsd_ioctl(const _img_private_t *env, track_t i_track)
{
struct ioc_read_subchannel subchannel;
struct cd_sub_channel_info subchannel_info;
subchannel.address_format = CDIO_CDROM_LBA;
subchannel.data_format = CDIO_SUBCHANNEL_CURRENT_POSITION;
subchannel.track = i_track;
subchannel.data_len = 1;
subchannel.data = &subchannel_info;
if(ioctl(env->gen.fd, CDIOCREADSUBCHANNEL, &subchannel) < 0) {
perror("CDIOCREADSUBCHANNEL");
return 1;
}
/* FIXME: Dunno if this is the right way, but it's what
I was using in cdinfo for a while.
*/
return (subchannel_info.what.position.control & 2) != 0;
}
#endif /* HAVE_FREEBSD_CDROM */

View File

@@ -0,0 +1,23 @@
# $Id: Makefile,v 1.1 2004/12/18 17:29:32 rocky Exp $
#
# Copyright (C) 2004 Rocky Bernstein
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#######################################
# The make is done above. This boilerplate Makefile just transfers the call
all install check clean:
cd .. && $(MAKE) $@

View File

@@ -0,0 +1,805 @@
/*
$Id: aspi32.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This file contains Win32-specific code and implements low-level
control of the CD drive via the ASPI API.
Inspired by vlc's cdrom.h code
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: aspi32.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
#include <cdio/cdio.h>
#include <cdio/sector.h>
#include <cdio/util.h>
#include <cdio/scsi_mmc.h>
#include "cdio_assert.h"
#include <string.h>
#ifdef HAVE_WIN32_CDROM
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <windows.h>
#include "win32.h"
#include <sys/stat.h>
#include <sys/types.h>
#include "aspi32.h"
#include "cdtext_private.h"
/* Amount of time we are willing to wait for an operation to complete.
10 seconds?
*/
#define OP_TIMEOUT_MS 10000
static const
char *aspierror(int nErrorCode)
{
switch (nErrorCode)
{
case SS_PENDING:
return "SRB being processed";
break;
case SS_COMP:
return "SRB completed without error";
break;
case SS_ABORTED:
return "SRB aborted";
break;
case SS_ABORT_FAIL:
return "Unable to abort SRB";
break;
case SS_ERR:
return "SRB completed with error";
break;
case SS_INVALID_CMD:
return "Invalid ASPI command";
break;
case SS_INVALID_HA:
return "Invalid host adapter number";
break;
case SS_NO_DEVICE:
return "SCSI device not installed";
break;
case SS_INVALID_SRB:
return "Invalid parameter set in SRB";
break;
case SS_OLD_MANAGER:
return "ASPI manager doesn't support";
break;
case SS_ILLEGAL_MODE:
return "Unsupported MS Windows mode";
break;
case SS_NO_ASPI:
return "No ASPI managers";
break;
case SS_FAILED_INIT:
return "ASPI for windows failed init";
break;
case SS_ASPI_IS_BUSY:
return "No resources available to execute command.";
break;
case SS_BUFFER_TOO_BIG:
return "Buffer size is too big to handle.";
break;
case SS_MISMATCHED_COMPONENTS:
return "The DLLs/EXEs of ASPI don't version check";
break;
case SS_NO_ADAPTERS:
return "No host adapters found";
break;
case SS_INSUFFICIENT_RESOURCES:
return "Couldn't allocate resources needed to init";
break;
case SS_ASPI_IS_SHUTDOWN:
return "Call came to ASPI after PROCESS_DETACH";
break;
case SS_BAD_INSTALL:
return "The DLL or other components are installed wrong.";
break;
default:
return "Unknown ASPI error.";
}
}
/* General ioctl() CD-ROM command function */
static bool
mciSendCommand_aspi(int id, UINT msg, DWORD flags, void *arg)
{
MCIERROR mci_error;
mci_error = mciSendCommand(id, msg, flags, (DWORD)arg);
if ( mci_error ) {
char error[256];
mciGetErrorString(mci_error, error, 256);
cdio_warn("mciSendCommand() error: %s", error);
}
return(mci_error == 0);
}
/*
See if the ASPI DLL is loadable. If so pointers are returned
and we return true. Return false if there was a problem.
*/
static bool
have_aspi( HMODULE *hASPI,
long (**lpGetSupport)( void ),
long (**lpSendCommand)( void* ) )
{
/* check if aspi is available */
*hASPI = LoadLibrary( "wnaspi32.dll" );
if( *hASPI == NULL ) {
cdio_debug("Unable to load ASPI DLL");
return false;
}
(FARPROC) *lpGetSupport = GetProcAddress( *hASPI,
"GetASPI32SupportInfo" );
(FARPROC) *lpSendCommand = GetProcAddress( *hASPI,
"SendASPI32Command" );
/* make sure that we've got both function addresses */
if( *lpGetSupport == NULL || *lpSendCommand == NULL ) {
cdio_debug("Unable to get ASPI function pointers");
FreeLibrary( *hASPI );
return false;
}
return true;
}
/*!
Get disc type associated with cd object.
*/
discmode_t
get_discmode_aspi (_img_private_t *p_env)
{
track_t i_track;
discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
/* 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;
if (0 == scsi_mmc_get_dvd_struct_physical_private (p_env,
&run_scsi_cmd_aspi,
&dvd)) {
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;
}
}
if (!p_env->gen.toc_init)
read_toc_aspi (p_env);
if (!p_env->gen.toc_init)
return CDIO_DISC_MODE_NO_INFO;
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_aspi(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;
}
const char *
is_cdrom_aspi(const char drive_letter)
{
static char psz_win32_drive[7];
HMODULE hASPI = NULL;
long (*lpGetSupport)( void ) = NULL;
long (*lpSendCommand)( void* ) = NULL;
DWORD dwSupportInfo;
int i_adapter, i_hostadapters;
char c_drive;
int i_rc;
if ( !have_aspi(&hASPI, &lpGetSupport, &lpSendCommand) )
return NULL;
/* ASPI support seems to be there. */
dwSupportInfo = lpGetSupport();
i_rc = HIBYTE( LOWORD ( dwSupportInfo ) );
if( SS_COMP != i_rc ) {
cdio_debug("ASPI: %s", aspierror(i_rc));
FreeLibrary( hASPI );
return NULL;
}
i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
if( i_hostadapters == 0 ) {
FreeLibrary( hASPI );
return NULL;
}
c_drive = toupper(drive_letter) - 'A';
for( i_adapter = 0; i_adapter < i_hostadapters; i_adapter++ ) {
struct SRB_GetDiskInfo srbDiskInfo;
int i_target;
SRB_HAInquiry srbInquiry;
srbInquiry.SRB_Cmd = SC_HA_INQUIRY;
srbInquiry.SRB_HaId = i_adapter;
lpSendCommand( (void*) &srbInquiry );
if( srbInquiry.SRB_Status != SS_COMP ) continue;
if( !srbInquiry.HA_Unique[3]) srbInquiry.HA_Unique[3]=8;
for(i_target=0; i_target < srbInquiry.HA_Unique[3]; i_target++)
{
int i_lun;
for( i_lun=0; i_lun<8; i_lun++)
{
srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO;
srbDiskInfo.SRB_Flags = 0;
srbDiskInfo.SRB_Hdr_Rsvd = 0;
srbDiskInfo.SRB_HaId = i_adapter;
srbDiskInfo.SRB_Target = i_target;
srbDiskInfo.SRB_Lun = i_lun;
lpSendCommand( (void*) &srbDiskInfo );
if( (srbDiskInfo.SRB_Status == SS_COMP) &&
(srbDiskInfo.SRB_Int13HDriveInfo == c_drive) ) {
/* Make sure this is a CD-ROM device. */
struct SRB_GDEVBlock srbGDEVBlock;
memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) );
srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE;
srbDiskInfo.SRB_HaId = i_adapter;
srbGDEVBlock.SRB_Target = i_target;
srbGDEVBlock.SRB_Lun = i_lun;
lpSendCommand( (void*) &srbGDEVBlock );
if( ( srbGDEVBlock.SRB_Status == SS_COMP ) &&
( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) ) {
sprintf( psz_win32_drive, "%c:", drive_letter );
FreeLibrary( hASPI );
return(psz_win32_drive);
}
}
}
}
}
FreeLibrary( hASPI );
return NULL;
}
/*!
Initialize CD device.
*/
bool
init_aspi (_img_private_t *env)
{
HMODULE hASPI = NULL;
long (*lpGetSupport)( void ) = NULL;
long (*lpSendCommand)( void* ) = NULL;
DWORD dwSupportInfo;
int i_adapter, i_hostadapters;
char c_drive;
int i_rc;
if (2 == strlen(env->gen.source_name) && isalpha(env->gen.source_name[0]) )
{
c_drive = env->gen.source_name[0];
} else if ( 6 == strlen(env->gen.source_name)
&& isalpha(env->gen.source_name[4] )) {
c_drive = env->gen.source_name[4];
} else {
c_drive = 'C';
}
if ( !have_aspi(&hASPI, &lpGetSupport, &lpSendCommand) )
return false;
/* ASPI support seems to be there. */
dwSupportInfo = lpGetSupport();
i_rc = HIBYTE( LOWORD ( dwSupportInfo ) );
if( SS_COMP != i_rc ) {
cdio_info("ASPI: %s", aspierror(i_rc));
FreeLibrary( hASPI );
return false;
}
i_hostadapters = LOBYTE( LOWORD( dwSupportInfo ) );
if( i_hostadapters == 0 ) {
FreeLibrary( hASPI );
return false;
}
c_drive = toupper(c_drive) - 'A';
for( i_adapter = 0; i_adapter < i_hostadapters; i_adapter++ ) {
struct SRB_GetDiskInfo srbDiskInfo;
int i_target;
SRB_HAInquiry srbInquiry;
srbInquiry.SRB_Cmd = SC_HA_INQUIRY;
srbInquiry.SRB_HaId = i_adapter;
lpSendCommand( (void*) &srbInquiry );
if( srbInquiry.SRB_Status != SS_COMP ) continue;
if( !srbInquiry.HA_Unique[3]) srbInquiry.HA_Unique[3]=8;
for(i_target=0; i_target < srbInquiry.HA_Unique[3]; i_target++)
{
int i_lun;
for (i_lun = 0; i_lun < 8; i_lun++ ) {
srbDiskInfo.SRB_Cmd = SC_GET_DISK_INFO;
srbDiskInfo.SRB_Flags = 0;
srbDiskInfo.SRB_Hdr_Rsvd = 0;
srbDiskInfo.SRB_HaId = i_adapter;
srbDiskInfo.SRB_Target = i_target;
srbDiskInfo.SRB_Lun = i_lun;
lpSendCommand( (void*) &srbDiskInfo );
if( (srbDiskInfo.SRB_Status == SS_COMP) ) {
if (srbDiskInfo.SRB_Int13HDriveInfo != c_drive)
{
continue;
} else {
/* Make sure this is a CD-ROM device. */
struct SRB_GDEVBlock srbGDEVBlock;
memset( &srbGDEVBlock, 0, sizeof(struct SRB_GDEVBlock) );
srbGDEVBlock.SRB_Cmd = SC_GET_DEV_TYPE;
srbGDEVBlock.SRB_HaId = i_adapter;
srbGDEVBlock.SRB_Target = i_target;
lpSendCommand( (void*) &srbGDEVBlock );
if( ( srbGDEVBlock.SRB_Status == SS_COMP ) &&
( srbGDEVBlock.SRB_DeviceType == DTYPE_CDROM ) ) {
env->i_sid = MAKEWORD( i_adapter, i_target );
env->hASPI = (long)hASPI;
env->lpSendCommand = lpSendCommand;
env->b_aspi_init = true;
env->i_lun = i_lun;
cdio_debug("Using ASPI layer");
return true;
} else {
FreeLibrary( hASPI );
cdio_debug( "%c: is not a CD-ROM drive",
env->gen.source_name[0] );
return false;
}
}
}
}
}
}
FreeLibrary( hASPI );
cdio_debug( "Unable to get HaId and target (ASPI)" );
return false;
}
/*!
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.
We return 0 if command completed successfully.
*/
int
run_scsi_cmd_aspi( const void *p_user_data, unsigned int i_timeout_ms,
unsigned int i_cdb, const scsi_mmc_cdb_t * p_cdb,
scsi_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf )
{
const _img_private_t *p_env = p_user_data;
HANDLE hEvent;
struct SRB_ExecSCSICmd ssc;
/* Create the transfer completion event */
hEvent = CreateEvent( NULL, TRUE, FALSE, NULL );
if( hEvent == NULL ) {
cdio_info("CreateEvent failed");
return 1;
}
memset( &ssc, 0, sizeof( ssc ) );
ssc.SRB_Cmd = SC_EXEC_SCSI_CMD;
ssc.SRB_Flags = SCSI_MMC_DATA_READ == e_direction ?
SRB_DIR_IN | SRB_EVENT_NOTIFY : SRB_DIR_OUT | SRB_EVENT_NOTIFY;
ssc.SRB_HaId = LOBYTE( p_env->i_sid );
ssc.SRB_Target = HIBYTE( p_env->i_sid );
ssc.SRB_Lun = p_env->i_lun;
ssc.SRB_SenseLen = SENSE_LEN;
ssc.SRB_PostProc = (LPVOID) hEvent;
ssc.SRB_CDBLen = i_cdb;
/* Result buffer */
ssc.SRB_BufPointer = p_buf;
ssc.SRB_BufLen = i_buf;
memcpy( ssc.CDBByte, p_cdb, i_cdb );
ResetEvent( hEvent );
p_env->lpSendCommand( (void*) &ssc );
/* If the command has still not been processed, wait until it's
* finished */
if( ssc.SRB_Status == SS_PENDING ) {
WaitForSingleObject( hEvent, msecs2secs(i_timeout_ms) );
}
CloseHandle( hEvent );
/* check that the transfer went as planned */
if( ssc.SRB_Status != SS_COMP ) {
cdio_info("ASPI: %s", aspierror(ssc.SRB_Status));
return 2;
}
return 0;
}
/*!
Reads nblocks sectors from cd device into data starting from lsn.
Returns 0 if no error.
*/
static int
read_sectors_aspi (const _img_private_t *env, void *data, lsn_t lsn,
int sector_type, unsigned int nblocks)
{
scsi_mmc_cdb_t cdb = {{0, }};
unsigned int i_buf;
int sync = 0;
int header_code = 2;
int i_user_data = 1;
int edc_ecc = 0;
int error_field = 0;
#if 0
sector_type = 0; /*all types */
#endif
/* Set up passthrough command */
CDIO_MMC_SET_COMMAND (cdb.field, CDIO_MMC_GPCMD_READ_CD);
CDIO_MMC_SET_READ_TYPE (cdb.field, sector_type);
CDIO_MMC_SET_READ_LBA (cdb.field, lsn);
CDIO_MMC_SET_READ_LENGTH24(cdb.field, nblocks);
#if 1
cdb.field[ 9 ] = (sync << 7) |
(header_code << 5) |
(i_user_data << 4) |
(edc_ecc << 3) |
(error_field << 1);
/* ssc.CDBByte[ 9 ] = READ_CD_USERDATA_MODE2; */
#else
CDIO_MMC_SET_MAIN_CHANNEL_SELECTION_BITS(cmd,
CDIO_MMC_MCSB_ALL_HEADERS);
#endif
switch (sector_type) {
case CDIO_MMC_READ_TYPE_ANY:
case CDIO_MMC_READ_TYPE_CDDA:
i_buf = CDIO_CD_FRAMESIZE_RAW;
break;
case CDIO_MMC_READ_TYPE_M2F1:
i_buf = CDIO_CD_FRAMESIZE;
break;
case CDIO_MMC_READ_TYPE_M2F2:
i_buf = 2324;
break;
case CDIO_MMC_READ_TYPE_MODE1:
i_buf = CDIO_CD_FRAMESIZE;
break;
default:
i_buf = CDIO_CD_FRAMESIZE_RAW;
}
return run_scsi_cmd_aspi(env, OP_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ, i_buf*nblocks, data);
}
/*!
Reads an audio device into data starting from lsn.
Returns 0 if no error.
*/
int
read_audio_sectors_aspi (_img_private_t *env, void *data, lsn_t lsn,
unsigned int nblocks)
{
if (read_sectors_aspi(env, data, lsn, CDIO_MMC_READ_TYPE_CDDA, 1)) {
return read_sectors_aspi(env, data, lsn, CDIO_MMC_READ_TYPE_ANY, 1);
}
return 0;
}
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int
read_mode2_sector_aspi (const _img_private_t *env, void *data, lsn_t lsn,
bool b_form2)
{
return read_sectors_aspi(env, data, lsn, b_form2
? CDIO_MMC_READ_TYPE_M2F2
: CDIO_MMC_READ_TYPE_M2F1,
1);
}
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int
read_mode1_sector_aspi (const _img_private_t *env, void *data, lsn_t lsn,
bool b_form2)
{
return read_sectors_aspi(env, data, lsn, CDIO_MMC_READ_TYPE_MODE1, 1);
}
/*!
Read and cache the CD's Track Table of Contents and track info.
Return true if successful or false if an error.
*/
bool
read_toc_aspi (_img_private_t *p_env)
{
scsi_mmc_cdb_t cdb = {{0, }};
unsigned char tocheader[ 4 ];
int i_status;
/* Operation code */
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC);
/* Format */
cdb.field[ 2 ] = CDIO_MMC_READTOC_FMT_TOC;
/* Starting track */
CDIO_MMC_SET_START_TRACK(cdb.field, 0);
CDIO_MMC_SET_READ_LENGTH16(cdb.field, sizeof(tocheader));
i_status = run_scsi_cmd_aspi (p_env, OP_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
sizeof(tocheader), &tocheader);
if (0 != i_status) return false;
p_env->gen.i_first_track = tocheader[2];
p_env->gen.i_tracks = tocheader[3] - tocheader[2] + 1;
{
int i, i_toclength;
unsigned char *p_fulltoc;
i_toclength = 4 /* header */ + tocheader[0] +
((unsigned int) tocheader[1] << 8);
p_fulltoc = malloc( i_toclength );
if( p_fulltoc == NULL ) {
cdio_error( "out of memory" );
return false;
}
CDIO_MMC_SET_READ_LENGTH16(cdb.field, i_toclength);
i_status = run_scsi_cmd_aspi (p_env, OP_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
i_toclength, p_fulltoc);
if( 0 != i_status ) {
p_env->gen.i_tracks = 0;
}
for( i = 0 ; i <= p_env->gen.i_tracks ; i++ ) {
int i_index = 8 + 8 * i;
p_env->tocent[ i ].start_lsn = ((int)p_fulltoc[ i_index ] << 24) +
((int)p_fulltoc[ i_index+1 ] << 16) +
((int)p_fulltoc[ i_index+2 ] << 8) +
(int)p_fulltoc[ i_index+3 ];
p_env->tocent[ i ].Control = (UCHAR)p_fulltoc[ 1 + 8 * i ];
cdio_debug( "p_sectors: %i %lu",
i, (unsigned long int) p_env->tocent[i].start_lsn );
}
free( p_fulltoc );
}
p_env->gen.toc_init = true;
return true;
}
/* Eject media will eventually get removed from _cdio_win32.c */
#if 0
/*!
Eject media. Return 1 if successful, 0 otherwise.
*/
int
wnaspi32_eject_media (void *user_data) {
_img_private_t *env = user_data;
MCI_OPEN_PARMS op;
MCI_STATUS_PARMS st;
DWORD i_flags;
char psz_drive[4];
int ret;
memset( &op, 0, sizeof(MCI_OPEN_PARMS) );
op.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO;
strcpy( psz_drive, "X:" );
psz_drive[0] = env->gen.source_name[0];
op.lpstrElementName = psz_drive;
/* Set the flags for the device type */
i_flags = MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID |
MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE;
if( mciSendCommand_aspi( 0, MCI_OPEN, i_flags, &op ) ) {
st.dwItem = MCI_STATUS_READY;
/* Eject disc */
ret = mciSendCommand_aspi( op.wDeviceID, MCI_SET,
MCI_SET_DOOR_OPEN, 0 ) != 0;
/* Release access to the device */
mciSendCommand_aspi( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 );
} else
ret = 0;
return ret;
}
#endif
/*!
Get format of track.
*/
track_format_t
get_track_format_aspi(const _img_private_t *p_env, track_t track_num)
{
MCI_OPEN_PARMS op;
MCI_STATUS_PARMS st;
DWORD i_flags;
int ret;
memset( &op, 0, sizeof(MCI_OPEN_PARMS) );
op.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO;
op.lpstrElementName = p_env->gen.source_name;
/* Set the flags for the device type */
i_flags = MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID |
MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE;
if( mciSendCommand_aspi( 0, MCI_OPEN, i_flags, &op ) ) {
st.dwItem = MCI_CDA_STATUS_TYPE_TRACK;
st.dwTrack = track_num;
i_flags = MCI_TRACK | MCI_STATUS_ITEM ;
ret = mciSendCommand_aspi( op.wDeviceID, MCI_STATUS, i_flags, &st );
/* Release access to the device */
mciSendCommand_aspi( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 );
switch(st.dwReturn) {
case MCI_CDA_TRACK_AUDIO:
return TRACK_FORMAT_AUDIO;
case MCI_CDA_TRACK_OTHER:
return TRACK_FORMAT_DATA;
default:
return TRACK_FORMAT_XA;
}
}
return TRACK_FORMAT_ERROR;
}
#endif /* HAVE_WIN32_CDROM */

View File

@@ -0,0 +1,249 @@
/* Win32 aspi specific */
/*
$Id: aspi32.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#define ASPI_HAID 0
#define ASPI_TARGET 0
#define DTYPE_CDROM 0x05
#define SENSE_LEN 0x0E
#define SC_HA_INQUIRY 0x00
#define SC_GET_DEV_TYPE 0x01
#define SC_EXEC_SCSI_CMD 0x02
#define SC_GET_DISK_INFO 0x06
//*****************************************************************************
// %%% SRB Status %%%
//*****************************************************************************
#define SS_PENDING 0x00 // SRB being processed
#define SS_COMP 0x01 // SRB completed without error
#define SS_ABORTED 0x02 // SRB aborted
#define SS_ABORT_FAIL 0x03 // Unable to abort SRB
#define SS_ERR 0x04 // SRB completed with error
#define SS_INVALID_CMD 0x80 // Invalid ASPI command
#define SS_INVALID_HA 0x81 // Invalid host adapter number
#define SS_NO_DEVICE 0x82 // SCSI device not installed
#define SS_INVALID_SRB 0xE0 // Invalid parameter set in SRB
#define SS_OLD_MANAGER 0xE1 // ASPI manager doesn't support Windows
#define SS_BUFFER_ALIGN 0xE1 // Buffer not aligned (replaces
// OLD_MANAGER in Win32)
#define SS_ILLEGAL_MODE 0xE2 // Unsupported Windows mode
#define SS_NO_ASPI 0xE3 // No ASPI managers resident
#define SS_FAILED_INIT 0xE4 // ASPI for windows failed init
#define SS_ASPI_IS_BUSY 0xE5 // No resources available to execute
// cmd
#define SS_BUFFER_TOO_BIG 0xE6 // Buffer size to big to handle!
#define SS_MISMATCHED_COMPONENTS 0xE7 // The DLLs/EXEs of ASPI don't version
// check
#define SS_NO_ADAPTERS 0xE8 // No host adapters to manage
#define SS_INSUFFICIENT_RESOURCES 0xE9 // Couldn't allocate resources needed
// to init
#define SS_ASPI_IS_SHUTDOWN 0xEA // Call came to ASPI after
// PROCESS_DETACH
#define SS_BAD_INSTALL 0xEB // The DLL or other components are installed wrong
//*****************************************************************************
// %%% Host Adapter Status %%%
//*****************************************************************************
#define HASTAT_OK 0x00 // Host adapter did not detect an
// error
#define HASTAT_SEL_TO 0x11 // Selection Timeout
#define HASTAT_DO_DU 0x12 // Data overrun data underrun
#define HASTAT_BUS_FREE 0x13 // Unexpected bus free
#define HASTAT_PHASE_ERR 0x14 // Target bus phase sequence
// failure
#define HASTAT_TIMEOUT 0x09 // Timed out while SRB was
// waiting to beprocessed.
#define HASTAT_COMMAND_TIMEOUT 0x0B // Adapter timed out processing SRB.
#define HASTAT_MESSAGE_REJECT 0x0D // While processing SRB, the
// adapter received a MESSAGE
#define HASTAT_BUS_RESET 0x0E // A bus reset was detected.
#define HASTAT_PARITY_ERROR 0x0F // A parity error was detected.
#define HASTAT_REQUEST_SENSE_FAILED 0x10 // The adapter failed in issuing
#define SS_NO_ADAPTERS 0xE8
#define SRB_DIR_IN 0x08
#define SRB_DIR_OUT 0x10
#define SRB_EVENT_NOTIFY 0x40
#define SECTOR_TYPE_MODE2 0x14
#define READ_CD_USERDATA_MODE2 0x10
#define READ_TOC 0x43
#define READ_TOC_FORMAT_TOC 0x0
#pragma pack(1)
struct SRB_GetDiskInfo
{
unsigned char SRB_Cmd;
unsigned char SRB_Status;
unsigned char SRB_HaId;
unsigned char SRB_Flags;
unsigned long SRB_Hdr_Rsvd;
unsigned char SRB_Target;
unsigned char SRB_Lun;
unsigned char SRB_DriveFlags;
unsigned char SRB_Int13HDriveInfo;
unsigned char SRB_Heads;
unsigned char SRB_Sectors;
unsigned char SRB_Rsvd1[22];
};
struct SRB_GDEVBlock
{
unsigned char SRB_Cmd;
unsigned char SRB_Status;
unsigned char SRB_HaId;
unsigned char SRB_Flags;
unsigned long SRB_Hdr_Rsvd;
unsigned char SRB_Target;
unsigned char SRB_Lun;
unsigned char SRB_DeviceType;
unsigned char SRB_Rsvd1;
};
struct SRB_ExecSCSICmd
{
unsigned char SRB_Cmd;
unsigned char SRB_Status;
unsigned char SRB_HaId;
unsigned char SRB_Flags;
unsigned long SRB_Hdr_Rsvd;
unsigned char SRB_Target;
unsigned char SRB_Lun;
unsigned short SRB_Rsvd1;
unsigned long SRB_BufLen;
unsigned char *SRB_BufPointer;
unsigned char SRB_SenseLen;
unsigned char SRB_CDBLen;
unsigned char SRB_HaStat;
unsigned char SRB_TargStat;
unsigned long *SRB_PostProc;
unsigned char SRB_Rsvd2[20];
unsigned char CDBByte[16];
unsigned char SenseArea[SENSE_LEN+2];
};
/*****************************************************************************
%%% SRB - HOST ADAPTER INQUIRY - SC_HA_INQUIRY (0) %%%
*****************************************************************************/
typedef struct // Offset
{ // HX/DEC
BYTE SRB_Cmd; // 00/000 ASPI command code = SC_HA_INQUIRY
BYTE SRB_Status; // 01/001 ASPI command status byte
BYTE SRB_HaId; // 02/002 ASPI host adapter number
BYTE SRB_Flags; // 03/003 ASPI request flags
DWORD SRB_Hdr_Rsvd; // 04/004 Reserved, MUST = 0
BYTE HA_Count; // 08/008 Number of host adapters present
BYTE HA_SCSI_ID; // 09/009 SCSI ID of host adapter
BYTE HA_ManagerId[16]; // 0A/010 String describing the manager
BYTE HA_Identifier[16]; // 1A/026 String describing the host adapter
BYTE HA_Unique[16]; // 2A/042 Host Adapter Unique parameters
WORD HA_Rsvd1; // 3A/058 Reserved, MUST = 0
}
SRB_HAInquiry;
/*!
Get disc type associated with cd object.
*/
discmode_t get_discmode_aspi (_img_private_t *p_env);
/*!
Return the the kind of drive capabilities of device.
Note: string is malloc'd so caller should free() then returned
string when done with it.
*/
char * get_mcn_aspi (const _img_private_t *env);
/*!
Get the format (XA, DATA, AUDIO) of a track.
*/
track_format_t get_track_format_aspi(const _img_private_t *env,
track_t i_track);
/*!
Initialize internal structures for CD device.
*/
bool init_aspi (_img_private_t *env);
/*
Read cdtext information for a CdIo object .
return true on success, false on error or CD-TEXT information does
not exist.
*/
bool init_cdtext_aspi (_img_private_t *env);
const char *is_cdrom_aspi(const char drive_letter);
/*!
Reads an audio device using the DeviceIoControl method into data
starting from lsn. Returns 0 if no error.
*/
int read_audio_sectors_aspi (_img_private_t *obj, void *data, lsn_t lsn,
unsigned int nblocks);
/*!
Reads a single mode1 sector using the DeviceIoControl method into
data starting from lsn. Returns 0 if no error.
*/
int read_mode1_sector_aspi (const _img_private_t *env, void *data,
lsn_t lsn, bool b_form2);
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int read_mode2_sector_aspi (const _img_private_t *env, void *data, lsn_t lsn,
bool b_form2);
/*!
Read and cache the CD's Track Table of Contents and track info.
Return true if successful or false if an error.
*/
bool read_toc_aspi (_img_private_t *env);
/*!
Run a SCSI MMC command.
env private CD structure
i_timeout 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.
*/
int run_scsi_cmd_aspi( const void *p_user_data,
unsigned int i_timeout,
unsigned int i_cdb,
const scsi_mmc_cdb_t * p_cdb,
scsi_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf );

View File

@@ -0,0 +1,805 @@
/*
$Id: win32.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This file contains Win32-specific code and implements low-level
control of the CD drive. Inspired by vlc's cdrom.h code
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: win32.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
#include <cdio/cdio.h>
#include <cdio/sector.h>
#include <cdio/util.h>
#include <cdio/scsi_mmc.h>
#include "cdio_assert.h"
#include "cdio_private.h" /* protoype for cdio_is_device_win32 */
#include <string.h>
#ifdef HAVE_WIN32_CDROM
#include <ctype.h>
#include <stdio.h>
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_FCNTL_H
#include <fcntl.h>
#endif
#include <windows.h>
#include <winioctl.h>
#include "win32.h"
#ifdef HAVE_SYS_STAT_H
#include <sys/stat.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#if defined (MSVC) || defined (_XBOX)
#undef IN
#else
#include "aspi32.h"
#endif
#ifdef _XBOX
#include "stdint.h"
#include <xtl.h>
#define WIN_NT 1
#else
#define WIN_NT ( GetVersion() < 0x80000000 )
#endif
/* General ioctl() CD-ROM command function */
static bool
_cdio_mciSendCommand(int id, UINT msg, DWORD flags, void *arg)
{
#ifdef _XBOX
return false;
#else
MCIERROR mci_error;
mci_error = mciSendCommand(id, msg, flags, (DWORD)arg);
if ( mci_error ) {
char error[256];
mciGetErrorString(mci_error, error, 256);
cdio_warn("mciSendCommand() error: %s", error);
}
return(mci_error == 0);
#endif
}
static access_mode_t
str_to_access_mode_win32(const char *psz_access_mode)
{
const access_mode_t default_access_mode =
WIN_NT ? _AM_IOCTL : _AM_ASPI;
if (NULL==psz_access_mode) return default_access_mode;
if (!strcmp(psz_access_mode, "ioctl"))
return _AM_IOCTL;
else if (!strcmp(psz_access_mode, "ASPI")) {
#ifdef _XBOX
return _AM_ASPI;
#else
cdio_warn ("XBOX doesn't support access type: %s. Default used instead.",
psz_access_mode);
return default_access_mode;
#endif
} else {
cdio_warn ("unknown access type: %s. Default used instead.",
psz_access_mode);
return default_access_mode;
}
}
static discmode_t
get_discmode_win32(void *p_user_data)
{
_img_private_t *p_env = p_user_data;
if (p_env->hASPI) {
return get_discmode_aspi (p_env);
} else {
return get_discmode_win32ioctl (p_env);
}
}
static const char *
is_cdrom_win32(const char drive_letter) {
if ( WIN_NT ) {
return is_cdrom_win32ioctl (drive_letter);
} else {
return is_cdrom_aspi(drive_letter);
}
}
/*!
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_scsi_cmd_win32( const void *p_user_data, unsigned int i_timeout_ms,
unsigned int i_cdb, const scsi_mmc_cdb_t *p_cdb,
scsi_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf )
{
const _img_private_t *p_env = p_user_data;
if (p_env->hASPI) {
return run_scsi_cmd_aspi( p_env, i_timeout_ms, i_cdb, p_cdb,
e_direction, i_buf, p_buf );
} else {
return run_scsi_cmd_win32ioctl( p_env, i_timeout_ms, i_cdb, p_cdb,
e_direction, i_buf, p_buf );
}
}
/*!
Initialize CD device.
*/
static bool
_cdio_init_win32 (void *user_data)
{
_img_private_t *p_env = user_data;
if (p_env->gen.init) {
cdio_error ("init called more than once");
return false;
}
p_env->gen.init = true;
p_env->gen.toc_init = false;
p_env->gen.b_cdtext_init = false;
p_env->gen.b_cdtext_error = false;
/* Initializations */
p_env->h_device_handle = NULL;
p_env->i_sid = 0;
p_env->hASPI = 0;
p_env->lpSendCommand = 0;
p_env->b_aspi_init = false;
p_env->b_ioctl_init = false;
if ( _AM_IOCTL == p_env->access_mode ) {
return init_win32ioctl(p_env);
} else {
return init_aspi(p_env);
}
}
/*!
Release and free resources associated with cd.
*/
static void
_free_win32 (void *user_data)
{
_img_private_t *p_env = user_data;
if (NULL == p_env) return;
free (p_env->gen.source_name);
if( p_env->h_device_handle )
CloseHandle( p_env->h_device_handle );
if( p_env->hASPI )
FreeLibrary( (HMODULE)p_env->hASPI );
free (p_env);
}
/*!
Reads an audio device into data starting from lsn.
Returns 0 if no error.
*/
static int
_cdio_read_audio_sectors (void *user_data, void *data, lsn_t lsn,
unsigned int nblocks)
{
_img_private_t *p_env = user_data;
if ( p_env->hASPI ) {
return read_audio_sectors_aspi( p_env, data, lsn, nblocks );
} else {
return read_audio_sectors_win32ioctl( p_env, data, lsn, nblocks );
}
}
/*!
Reads a single mode1 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
static int
_cdio_read_mode1_sector (void *user_data, void *data, lsn_t lsn,
bool b_form2)
{
_img_private_t *p_env = user_data;
if (p_env->gen.ioctls_debugged == 75)
cdio_debug ("only displaying every 75th ioctl from now on");
if (p_env->gen.ioctls_debugged == 30 * 75)
cdio_debug ("only displaying every 30*75th ioctl from now on");
if (p_env->gen.ioctls_debugged < 75
|| (p_env->gen.ioctls_debugged < (30 * 75)
&& p_env->gen.ioctls_debugged % 75 == 0)
|| p_env->gen.ioctls_debugged % (30 * 75) == 0)
cdio_debug ("reading %lu", (unsigned long int) lsn);
p_env->gen.ioctls_debugged++;
if ( p_env->hASPI ) {
return read_mode1_sector_aspi( p_env, data, lsn, b_form2 );
} else {
return read_mode1_sector_win32ioctl( p_env, data, lsn, b_form2 );
}
}
/*!
Reads nblocks of mode1 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
static int
_cdio_read_mode1_sectors (void *user_data, void *data, lsn_t lsn,
bool b_form2, unsigned int nblocks)
{
_img_private_t *p_env = user_data;
int i;
int retval;
for (i = 0; i < nblocks; i++) {
if (b_form2) {
if ( (retval = _cdio_read_mode1_sector (p_env,
((char *)data) + (M2RAW_SECTOR_SIZE * i),
lsn + i, true)) )
return retval;
} else {
char buf[M2RAW_SECTOR_SIZE] = { 0, };
if ( (retval = _cdio_read_mode1_sector (p_env, buf, lsn + i, false)) )
return retval;
memcpy (((char *)data) + (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
_cdio_read_mode2_sector (void *user_data, void *data, lsn_t lsn,
bool b_form2)
{
char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
_img_private_t *p_env = user_data;
if (p_env->gen.ioctls_debugged == 75)
cdio_debug ("only displaying every 75th ioctl from now on");
if (p_env->gen.ioctls_debugged == 30 * 75)
cdio_debug ("only displaying every 30*75th ioctl from now on");
if (p_env->gen.ioctls_debugged < 75
|| (p_env->gen.ioctls_debugged < (30 * 75)
&& p_env->gen.ioctls_debugged % 75 == 0)
|| p_env->gen.ioctls_debugged % (30 * 75) == 0)
cdio_debug ("reading %lu", (unsigned long int) lsn);
p_env->gen.ioctls_debugged++;
if ( p_env->hASPI ) {
int ret;
ret = read_mode2_sector_aspi(user_data, buf, lsn, 1);
if( ret != 0 ) return ret;
if (b_form2)
memcpy (data, buf, M2RAW_SECTOR_SIZE);
else
memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE);
return 0;
} else {
return read_mode2_sector_win32ioctl( p_env, data, lsn, b_form2 );
}
}
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
static int
_cdio_read_mode2_sectors (void *user_data, void *data, lsn_t lsn,
bool b_form2, unsigned int nblocks)
{
int i;
int retval;
unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
for (i = 0; i < nblocks; i++) {
if ( (retval = _cdio_read_mode2_sector (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 uint32_t
stat_size_win32 (void *user_data)
{
_img_private_t *p_env = user_data;
return p_env->tocent[p_env->gen.i_tracks].start_lsn;
}
/*!
Set the key "arg" to "value" in source device.
*/
static int
set_arg_win32 (void *user_data, const char key[], const char value[])
{
_img_private_t *p_env = user_data;
if (!strcmp (key, "source"))
{
if (!value)
return -2;
free (p_env->gen.source_name);
p_env->gen.source_name = strdup (value);
}
else if (!strcmp (key, "access-mode"))
{
p_env->access_mode = str_to_access_mode_win32(value);
if (p_env->access_mode == _AM_ASPI && !p_env->b_aspi_init)
return init_aspi(p_env) ? 1 : -3;
else if (p_env->access_mode == _AM_IOCTL && !p_env->b_ioctl_init)
return init_win32ioctl(p_env) ? 1 : -3;
else
return -4;
return 0;
}
else
return -1;
return 0;
}
/*!
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_win32 (void *p_user_data)
{
_img_private_t *p_env = p_user_data;
bool ret;
if( p_env->hASPI ) {
ret = read_toc_aspi( p_env );
} else {
ret = read_toc_win32ioctl( p_env );
}
if (ret) p_env->gen.toc_init = true ;
return true;
}
/*!
Eject media. Return 1 if successful, 0 otherwise.
*/
static int
_cdio_eject_media (void *user_data) {
#ifdef _XBOX
return -1;
#else
_img_private_t *env = user_data;
MCI_OPEN_PARMS op;
MCI_STATUS_PARMS st;
DWORD i_flags;
char psz_drive[4];
int ret;
memset( &op, 0, sizeof(MCI_OPEN_PARMS) );
op.lpstrDeviceType = (LPCSTR)MCI_DEVTYPE_CD_AUDIO;
strcpy( psz_drive, "X:" );
psz_drive[0] = env->gen.source_name[0];
op.lpstrElementName = psz_drive;
/* Set the flags for the device type */
i_flags = MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID |
MCI_OPEN_ELEMENT | MCI_OPEN_SHAREABLE;
if( _cdio_mciSendCommand( 0, MCI_OPEN, i_flags, &op ) ) {
st.dwItem = MCI_STATUS_READY;
/* Eject disc */
ret = _cdio_mciSendCommand( op.wDeviceID, MCI_SET, MCI_SET_DOOR_OPEN, 0 ) != 0;
/* Release access to the device */
_cdio_mciSendCommand( op.wDeviceID, MCI_CLOSE, MCI_WAIT, 0 );
} else
ret = 0;
return ret;
#endif
}
/*!
Return the value associated with the key "arg".
*/
static const char *
_get_arg_win32 (void *user_data, const char key[])
{
_img_private_t *env = user_data;
if (!strcmp (key, "source")) {
return env->gen.source_name;
} else if (!strcmp (key, "access-mode")) {
if (env->hASPI)
return "ASPI";
else
return "ioctl";
}
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;
if( p_env->hASPI ) {
return scsi_mmc_get_mcn( p_env->gen.cdio );
} else {
return get_mcn_win32ioctl(p_env);
}
}
/*!
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) read_toc_win32 (p_env) ;
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;
if( p_env->hASPI ) {
return get_track_format_aspi(p_env, i_track);
} else {
return get_track_format_win32ioctl(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 *obj, track_t i_track)
{
_img_private_t *p_env = 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:
if (_AM_ASPI == p_env->access_mode )
return ((p_env->tocent[i_track-p_env->gen.i_first_track].Control & 8) != 0);
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->tocent[i_track-p_env->gen.i_first_track].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 *msf)
{
_img_private_t *p_env = p_user_data;
if (NULL == msf) return false;
if (!p_env->gen.toc_init) read_toc_win32 (p_env) ;
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->tocent[i_tracks-1].start_lsn, msf);
return true;
}
}
#endif /* HAVE_WIN32_CDROM */
/*!
Return an array of strings giving possible CD devices.
*/
char **
cdio_get_devices_win32 (void)
{
#ifndef HAVE_WIN32_CDROM
return NULL;
#else
char **drives = NULL;
unsigned int num_drives=0;
char drive_letter;
/* Scan the system for CD-ROM drives.
*/
#if FINISHED
/* Now check the currently mounted CD drives */
if (NULL != (ret_drive = cdio_check_mounts("/etc/mtab"))) {
cdio_add_device_list(&drives, drive, &num_drives);
}
/* Finally check possible mountable drives in /etc/fstab */
if (NULL != (ret_drive = cdio_check_mounts("/etc/fstab"))) {
cdio_add_device_list(&drives, drive, &num_drives);
}
#endif
/* Scan the system for CD-ROM drives.
Not always 100% reliable, so use the USE_MNTENT code above first.
*/
for (drive_letter='A'; drive_letter <= 'Z'; drive_letter++) {
const char *drive_str=is_cdrom_win32(drive_letter);
if (drive_str != NULL) {
cdio_add_device_list(&drives, drive_str, &num_drives);
}
}
cdio_add_device_list(&drives, NULL, &num_drives);
return drives;
#endif /*HAVE_WIN32_CDROM*/
}
/*!
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_win32(void)
{
#ifdef HAVE_WIN32_CDROM
char drive_letter;
for (drive_letter='A'; drive_letter <= 'Z'; drive_letter++) {
const char *drive_str=is_cdrom_win32(drive_letter);
if (drive_str != NULL) {
return strdup(drive_str);
}
}
#endif
return NULL;
}
/*!
Return true if source_name could be a device containing a CD-ROM.
*/
bool
cdio_is_device_win32(const char *source_name)
{
unsigned int len;
len = strlen(source_name);
if (NULL == source_name) return false;
#ifdef HAVE_WIN32_CDROM
if ((len == 2) && isalpha(source_name[0])
&& (source_name[len-1] == ':'))
return true;
if ( ! WIN_NT ) return false;
/* Test to see if of form: \\.\x: */
return ( (len == 6)
&& source_name[0] == '\\' && source_name[1] == '\\'
&& source_name[2] == '.' && source_name[3] == '\\'
&& isalpha(source_name[len-2])
&& (source_name[len-1] == ':') );
#else
return false;
#endif
}
/*!
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 *
cdio_open_win32 (const char *psz_source_name)
{
#ifdef HAVE_WIN32_CDROM
if ( WIN_NT ) {
return cdio_open_am_win32(psz_source_name, "ioctl");
} else {
return cdio_open_am_win32(psz_source_name, "ASPI");
}
#else
return NULL;
#endif /* HAVE_WIN32_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 *
cdio_open_am_win32 (const char *psz_orig_source, const char *psz_access_mode)
{
#ifdef HAVE_WIN32_CDROM
CdIo *ret;
_img_private_t *_data;
char *psz_source;
cdio_funcs _funcs;
memset( &_funcs, 0, sizeof(_funcs) );
_funcs.eject_media = _cdio_eject_media;
_funcs.free = _free_win32;
_funcs.get_arg = _get_arg_win32;
_funcs.get_cdtext = get_cdtext_generic;
_funcs.get_default_device = cdio_get_default_device_win32;
_funcs.get_devices = cdio_get_devices_win32;
_funcs.get_discmode = get_discmode_win32;
_funcs.get_drive_cap = scsi_mmc_get_drive_cap_generic;
_funcs.get_first_track_num= get_first_track_num_generic;
_funcs.get_hwinfo = NULL;
_funcs.get_mcn = _cdio_get_mcn;
_funcs.get_num_tracks = get_num_tracks_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 implemented if need be. */
_funcs.get_track_msf = _cdio_get_track_msf;
_funcs.lseek = NULL;
_funcs.read = NULL;
_funcs.read_audio_sectors = _cdio_read_audio_sectors;
_funcs.read_mode1_sector = _cdio_read_mode1_sector;
_funcs.read_mode1_sectors = _cdio_read_mode1_sectors;
_funcs.read_mode2_sector = _cdio_read_mode2_sector;
_funcs.read_mode2_sectors = _cdio_read_mode2_sectors;
_funcs.read_toc = &read_toc_win32;
_funcs.run_scsi_mmc_cmd = &run_scsi_cmd_win32;
_funcs.set_arg = set_arg_win32;
_funcs.stat_size = stat_size_win32;
_data = _cdio_malloc (sizeof (_img_private_t));
_data->access_mode = str_to_access_mode_win32(psz_access_mode);
_data->gen.init = false;
_data->gen.fd = -1;
if (NULL == psz_orig_source) {
psz_source=cdio_get_default_device_win32();
if (NULL == psz_source) return NULL;
set_arg_win32(_data, "source", psz_source);
free(psz_source);
} else {
if (cdio_is_device_win32(psz_orig_source))
set_arg_win32(_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
return NULL;
}
}
ret = cdio_new ((void *)_data, &_funcs);
if (ret == NULL) return NULL;
if (_cdio_init_win32(_data))
return ret;
else {
_free_win32 (_data);
return NULL;
}
#else
return NULL;
#endif /* HAVE_WIN32_CDROM */
}
bool
cdio_have_win32 (void)
{
#ifdef HAVE_WIN32_CDROM
return true;
#else
return false;
#endif /* HAVE_WIN32_CDROM */
}

View File

@@ -0,0 +1,170 @@
/*
$Id: win32.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "cdio_private.h"
#pragma pack()
typedef struct {
lsn_t start_lsn;
UCHAR Control : 4;
UCHAR Format;
cdtext_t cdtext; /* CD-TEXT */
} track_info_t;
typedef enum {
_AM_NONE,
_AM_IOCTL,
_AM_ASPI,
} 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;
/* Some of the more OS specific things. */
/* Entry info for each track, add 1 for leadout. */
track_info_t tocent[CDIO_CD_MAX_TRACKS+1];
HANDLE h_device_handle; /* device descriptor */
long hASPI;
short i_sid;
short i_lun;
long (*lpSendCommand)( void* );
bool b_ioctl_init;
bool b_aspi_init;
} _img_private_t;
/*!
Get disc type associated with cd object.
*/
discmode_t get_discmode_win32ioctl (_img_private_t *p_env);
/*!
Reads an audio device using the DeviceIoControl method into data
starting from lsn. Returns 0 if no error.
*/
int read_audio_sectors_win32ioctl (_img_private_t *obj, void *data, lsn_t lsn,
unsigned int nblocks);
/*!
Reads a single mode2 sector using the DeviceIoControl method into
data starting from lsn. Returns 0 if no error.
*/
int read_mode2_sector_win32ioctl (const _img_private_t *env, void *data,
lsn_t lsn, bool b_form2);
/*!
Reads a single mode1 sector using the DeviceIoControl method into
data starting from lsn. Returns 0 if no error.
*/
int read_mode1_sector_win32ioctl (const _img_private_t *env, void *data,
lsn_t lsn, bool b_form2);
const char *is_cdrom_win32ioctl (const char drive_letter);
/*!
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.
*/
int run_scsi_cmd_win32ioctl( const void *p_user_data,
unsigned int i_timeout,
unsigned int i_cdb,
const scsi_mmc_cdb_t * p_cdb,
scsi_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf );
/*!
Initialize internal structures for CD device.
*/
bool init_win32ioctl (_img_private_t *env);
/*!
Read and cache the CD's Track Table of Contents and track info.
Return true if successful or false if an error.
*/
bool read_toc_win32ioctl (_img_private_t *env);
/*!
Return the media catalog number MCN.
Note: string is malloc'd so caller should free() then returned
string when done with it.
*/
char *get_mcn_win32ioctl (const _img_private_t *env);
/*
Read cdtext information for a CdIo object .
return true on success, false on error or CD-TEXT information does
not exist.
*/
bool init_cdtext_win32ioctl (_img_private_t *env);
/*!
Return the the kind of drive capabilities of device.
Note: string is malloc'd so caller should free() then returned
string when done with it.
*/
void get_drive_cap_aspi (const _img_private_t *env,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap);
/*!
Return the the kind of drive capabilities of device.
Note: string is malloc'd so caller should free() then returned
string when done with it.
*/
void get_drive_cap_win32ioctl (const _img_private_t *env,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap);
/*!
Get the format (XA, DATA, AUDIO) of a track.
*/
track_format_t get_track_format_win32ioctl(const _img_private_t *env,
track_t i_track);
void set_cdtext_field_win32(void *user_data, track_t i_track,
track_t i_first_track,
cdtext_field_t e_field, const char *psz_value);

View File

@@ -0,0 +1,739 @@
/*
$Id: win32_ioctl.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This file contains Win32-specific code using the DeviceIoControl
access method.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: win32_ioctl.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
#ifdef HAVE_WIN32_CDROM
#if defined (_XBOX)
#include "inttypes.h"
#include "NtScsi.h"
#include "undocumented.h"
#define FORMAT_ERROR(i_err, psz_msg) \
psz_msg=(char *)LocalAlloc(LMEM_ZEROINIT, 255); \
sprintf(psz_msg, "error file %s: line %d (%s) %d\n",
_FILE__, __LINE__, __PRETTY_FUNCTION__, i_err)
#else
#include <ddk/ntddstor.h>
#include <ddk/ntddscsi.h>
#include <ddk/scsi.h>
#define FORMAT_ERROR(i_err, psz_msg) \
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, \
NULL, i_err, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), \
(LPSTR) psz_msg, 0, NULL)
#endif
#ifdef WIN32
#include <windows.h>
#endif
#include <stdio.h>
#include <stddef.h> /* offsetof() macro */
#include <sys/stat.h>
#include <errno.h>
#include <sys/types.h>
#include <cdio/cdio.h>
#include <cdio/sector.h>
#include "cdio_assert.h"
#include <cdio/scsi_mmc.h>
#include "cdtext_private.h"
#include "cdio/logging.h"
/* Win32 DeviceIoControl specifics */
/***** FIXME: #include ntddcdrm.h from Wine, but probably need to
modify it a little.
*/
#ifndef IOCTL_CDROM_BASE
# define IOCTL_CDROM_BASE FILE_DEVICE_CD_ROM
#endif
#ifndef IOCTL_CDROM_READ_TOC
#define IOCTL_CDROM_READ_TOC \
CTL_CODE(IOCTL_CDROM_BASE, 0x0000, METHOD_BUFFERED, FILE_READ_ACCESS)
#endif
#ifndef IOCTL_CDROM_RAW_READ
#define IOCTL_CDROM_RAW_READ CTL_CODE(IOCTL_CDROM_BASE, 0x000F, \
METHOD_OUT_DIRECT, FILE_READ_ACCESS)
#endif
#ifndef IOCTL_CDROM_READ_Q_CHANNEL
#define IOCTL_CDROM_READ_Q_CHANNEL \
CTL_CODE(IOCTL_CDROM_BASE, 0x000B, METHOD_BUFFERED, FILE_READ_ACCESS)
#endif
typedef struct {
SCSI_PASS_THROUGH Spt;
ULONG Filler;
UCHAR SenseBuf[32];
UCHAR DataBuf[512];
} SCSI_PASS_THROUGH_WITH_BUFFERS;
typedef struct _TRACK_DATA {
UCHAR Format;
UCHAR Control : 4;
UCHAR Adr : 4;
UCHAR TrackNumber;
UCHAR Reserved1;
UCHAR Address[4];
} TRACK_DATA, *PTRACK_DATA;
typedef struct _CDROM_TOC {
UCHAR Length[2];
UCHAR FirstTrack;
UCHAR LastTrack;
TRACK_DATA TrackData[CDIO_CD_MAX_TRACKS+1];
} CDROM_TOC, *PCDROM_TOC;
typedef struct _TRACK_DATA_FULL {
UCHAR SessionNumber;
UCHAR Control : 4;
UCHAR Adr : 4;
UCHAR TNO;
UCHAR POINT; /* Tracknumber (of session?) or lead-out/in (0xA0, 0xA1, 0xA2) */
UCHAR Min; /* Only valid if disctype is CDDA ? */
UCHAR Sec; /* Only valid if disctype is CDDA ? */
UCHAR Frame; /* Only valid if disctype is CDDA ? */
UCHAR Zero; /* Always zero */
UCHAR PMIN; /* start min, if POINT is a track; if lead-out/in 0xA0: First Track */
UCHAR PSEC;
UCHAR PFRAME;
} TRACK_DATA_FULL, *PTRACK_DATA_FULL;
typedef struct _CDROM_TOC_FULL {
UCHAR Length[2];
UCHAR FirstSession;
UCHAR LastSession;
TRACK_DATA_FULL TrackData[CDIO_CD_MAX_TRACKS+3];
} CDROM_TOC_FULL, *PCDROM_TOC_FULL;
typedef enum _TRACK_MODE_TYPE {
YellowMode2,
XAForm2,
CDDA
} TRACK_MODE_TYPE, *PTRACK_MODE_TYPE;
typedef struct __RAW_READ_INFO {
LARGE_INTEGER DiskOffset;
ULONG SectorCount;
TRACK_MODE_TYPE TrackMode;
} RAW_READ_INFO, *PRAW_READ_INFO;
typedef struct _CDROM_SUB_Q_DATA_FORMAT {
UCHAR Format;
UCHAR Track;
} CDROM_SUB_Q_DATA_FORMAT, *PCDROM_SUB_Q_DATA_FORMAT;
typedef struct _SUB_Q_HEADER {
UCHAR Reserved;
UCHAR AudioStatus;
UCHAR DataLength[2];
} SUB_Q_HEADER, *PSUB_Q_HEADER;
typedef struct _SUB_Q_MEDIA_CATALOG_NUMBER {
SUB_Q_HEADER Header;
UCHAR FormatCode;
UCHAR Reserved[3];
UCHAR Reserved1 : 7;
UCHAR Mcval :1;
UCHAR MediaCatalog[15];
} SUB_Q_MEDIA_CATALOG_NUMBER, *PSUB_Q_MEDIA_CATALOG_NUMBER;
#include "win32.h"
#define OP_TIMEOUT_MS 60
/*!
Run a SCSI MMC command.
env private CD structure
i_timeout 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.
*/
int
run_scsi_cmd_win32ioctl( const void *p_user_data,
unsigned int i_timeout_ms,
unsigned int i_cdb, const scsi_mmc_cdb_t * p_cdb,
scsi_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf )
{
const _img_private_t *p_env = p_user_data;
SCSI_PASS_THROUGH_DIRECT sptd;
bool success;
DWORD dwBytesReturned;
sptd.Length = sizeof(sptd);
sptd.PathId = 0; /* SCSI card ID will be filled in automatically */
sptd.TargetId= 0; /* SCSI target ID will also be filled in */
sptd.Lun=0; /* SCSI lun ID will also be filled in */
sptd.CdbLength = i_cdb;
sptd.SenseInfoLength = 0; /* Don't return any sense data */
sptd.DataIn = SCSI_MMC_DATA_READ == e_direction ?
SCSI_IOCTL_DATA_IN : SCSI_IOCTL_DATA_OUT;
sptd.DataTransferLength= i_buf;
sptd.TimeOutValue = msecs2secs(i_timeout_ms);
sptd.DataBuffer = (void *) p_buf;
sptd.SenseInfoOffset = 0;
memcpy(sptd.Cdb, p_cdb, i_cdb);
/* Send the command to drive */
success=DeviceIoControl(p_env->h_device_handle,
IOCTL_SCSI_PASS_THROUGH_DIRECT,
(void *)&sptd,
(DWORD)sizeof(SCSI_PASS_THROUGH_DIRECT),
NULL, 0,
&dwBytesReturned,
NULL);
if(! success) {
char *psz_msg = NULL;
long int i_err = GetLastError();
FORMAT_ERROR(i_err, psz_msg);
cdio_info("Error: %s", psz_msg);
LocalFree(psz_msg);
return 1;
}
return 0;
}
/*!
Get disc type associated with cd object.
*/
discmode_t
get_discmode_win32ioctl (_img_private_t *p_env)
{
track_t i_track;
discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
/* 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;
if (0 == scsi_mmc_get_dvd_struct_physical_private (p_env,
&run_scsi_cmd_win32ioctl,
&dvd)) {
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;
}
}
if (!p_env->gen.toc_init)
read_toc_win32ioctl (p_env);
if (!p_env->gen.toc_init)
return CDIO_DISC_MODE_NO_INFO;
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_win32ioctl(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;
}
/*
Returns a string that can be used in a CreateFile call if
c_drive letter is a character. If not NULL is returned.
*/
const char *
is_cdrom_win32ioctl(const char c_drive_letter)
{
#ifdef _XBOX
char sz_win32_drive_full[] = "\\\\.\\X:";
sz_win32_drive_full[4] = c_drive_letter;
return strdup(sz_win32_drive_full);
#else
UINT uDriveType;
char sz_win32_drive[4];
sz_win32_drive[0]= c_drive_letter;
sz_win32_drive[1]=':';
sz_win32_drive[2]='\\';
sz_win32_drive[3]='\0';
uDriveType = GetDriveType(sz_win32_drive);
switch(uDriveType) {
case DRIVE_CDROM: {
char sz_win32_drive_full[] = "\\\\.\\X:";
sz_win32_drive_full[4] = c_drive_letter;
return strdup(sz_win32_drive_full);
}
default:
cdio_debug("Drive %c is not a CD-ROM", c_drive_letter);
return NULL;
}
#endif
}
/*!
Reads an audio device using the DeviceIoControl method into data
starting from lsn. Returns 0 if no error.
*/
int
read_audio_sectors_win32ioctl (_img_private_t *env, void *data, lsn_t lsn,
unsigned int nblocks)
{
DWORD dwBytesReturned;
RAW_READ_INFO cdrom_raw;
/* Initialize CDROM_RAW_READ structure */
cdrom_raw.DiskOffset.QuadPart = CDIO_CD_FRAMESIZE_RAW * lsn;
cdrom_raw.SectorCount = nblocks;
cdrom_raw.TrackMode = CDDA;
if( DeviceIoControl( env->h_device_handle,
IOCTL_CDROM_RAW_READ, &cdrom_raw,
sizeof(RAW_READ_INFO), data,
CDIO_CD_FRAMESIZE_RAW * nblocks,
&dwBytesReturned, NULL ) == 0 ) {
char *psz_msg = NULL;
long int i_err = GetLastError();
FORMAT_ERROR(i_err, psz_msg);
cdio_info("Error reading audio-mode %lu\n%s)",
(long unsigned int) lsn, psz_msg);
LocalFree(psz_msg);
return 1;
}
return 0;
}
/*!
Reads a single raw sector using the DeviceIoControl method into
data starting from lsn. Returns 0 if no error.
*/
static int
read_raw_sector (const _img_private_t *p_env, void *p_buf, lsn_t lsn)
{
scsi_mmc_cdb_t cdb = {{0, }};
/* ReadCD CDB12 command. The values were taken from MMC1 draft paper. */
CDIO_MMC_SET_COMMAND (cdb.field, CDIO_MMC_GPCMD_READ_CD);
CDIO_MMC_SET_READ_LBA (cdb.field, lsn);
CDIO_MMC_SET_READ_LENGTH24(cdb.field, 1);
cdb.field[9]=0xF8; /* Raw read, 2352 bytes per sector */
return run_scsi_cmd_win32ioctl(p_env, OP_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
CDIO_CD_FRAMESIZE_RAW, p_buf);
}
/*!
Reads a single mode2 sector using the DeviceIoControl method into
data starting from lsn. Returns 0 if no error.
*/
int
read_mode2_sector_win32ioctl (const _img_private_t *p_env, void *p_data,
lsn_t lsn, bool b_form2)
{
char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
int ret = read_raw_sector (p_env, buf, lsn);
if ( 0 != ret) return ret;
memcpy (p_data,
buf + CDIO_CD_SYNC_SIZE + CDIO_CD_XA_HEADER,
b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE);
return 0;
}
/*!
Reads a single mode2 sector using the DeviceIoControl method into
data starting from lsn. Returns 0 if no error.
*/
int
read_mode1_sector_win32ioctl (const _img_private_t *env, void *data,
lsn_t lsn, bool b_form2)
{
char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
int ret = read_raw_sector (env, buf, lsn);
if ( 0 != ret) return ret;
memcpy (data,
buf + CDIO_CD_SYNC_SIZE+CDIO_CD_HEADER_SIZE,
b_form2 ? M2RAW_SECTOR_SIZE: CDIO_CD_FRAMESIZE);
return 0;
}
/*!
Initialize internal structures for CD device.
*/
bool
init_win32ioctl (_img_private_t *env)
{
#ifdef WIN32
OSVERSIONINFO ov;
#endif
#ifdef _XBOX
ANSI_STRING filename;
OBJECT_ATTRIBUTES attributes;
IO_STATUS_BLOCK status;
HANDLE hDevice;
NTSTATUS error;
#else
unsigned int len=strlen(env->gen.source_name);
char psz_win32_drive[7];
DWORD dw_access_flags;
#endif
cdio_debug("using winNT/2K/XP ioctl layer");
#ifdef WIN32
memset(&ov,0,sizeof(OSVERSIONINFO));
ov.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
GetVersionEx(&ov);
if((ov.dwPlatformId==VER_PLATFORM_WIN32_NT) &&
(ov.dwMajorVersion>4))
dw_access_flags = GENERIC_READ|GENERIC_WRITE; /* add gen write on W2k/XP */
else dw_access_flags = GENERIC_READ;
#endif
if (cdio_is_device_win32(env->gen.source_name))
{
#ifdef _XBOX
// Use XBOX cdrom, no matter what drive letter is given.
RtlInitAnsiString(&filename,"\\Device\\Cdrom0");
InitializeObjectAttributes(&attributes, &filename, OBJ_CASE_INSENSITIVE,
NULL);
error = NtCreateFile( &hDevice,
GENERIC_READ |SYNCHRONIZE | FILE_READ_ATTRIBUTES,
&attributes,
&status,
NULL,
0,
FILE_SHARE_READ,
FILE_OPEN,
FILE_NON_DIRECTORY_FILE
| FILE_SYNCHRONOUS_IO_NONALERT );
if (!NT_SUCCESS(error))
{
return false;
}
env->h_device_handle = hDevice;
#else
sprintf( psz_win32_drive, "\\\\.\\%c:", env->gen.source_name[len-2] );
env->h_device_handle = CreateFile( psz_win32_drive,
dw_access_flags,
FILE_SHARE_READ | FILE_SHARE_WRITE,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
if( env->h_device_handle == INVALID_HANDLE_VALUE )
{
/* No good. try toggle write. */
dw_access_flags ^= GENERIC_WRITE;
env->h_device_handle = CreateFile( psz_win32_drive,
dw_access_flags,
FILE_SHARE_READ,
NULL,
OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL,
NULL );
if (env->h_device_handle == NULL)
return false;
}
#endif
env->b_ioctl_init = true;
return true;
}
return false;
}
/*!
Read and cache the CD's Track Table of Contents and track info.
via a SCSI MMC READ_TOC (FULTOC). Return true if successful or
false if an error.
*/
static bool
read_fulltoc_win32mmc (_img_private_t *p_env)
{
scsi_mmc_cdb_t cdb = {{0, }};
CDROM_TOC_FULL cdrom_toc_full;
int i_status, i, i_track_format, i_seen_flag;
/* Operation code */
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC);
cdb.field[1] = 0x00;
/* Format */
cdb.field[2] = CDIO_MMC_READTOC_FMT_FULTOC;
memset(&cdrom_toc_full, 0, sizeof(cdrom_toc_full));
/* Setup to read header, to get length of data */
CDIO_MMC_SET_READ_LENGTH16(cdb.field, sizeof(cdrom_toc_full));
i_status = run_scsi_cmd_win32ioctl (p_env, 1000*60*3,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
sizeof(cdrom_toc_full), &cdrom_toc_full);
if ( 0 != i_status ) {
cdio_debug ("SCSI MMC READ_TOC failed\n");
return false;
}
i_seen_flag=0;
for( i = 0 ; i <= CDIO_CD_MAX_TRACKS+3; i++ ) {
if ( 0xA0 == cdrom_toc_full.TrackData[i].POINT ) {
/* First track number */
p_env->gen.i_first_track = cdrom_toc_full.TrackData[i].PMIN;
i_track_format = cdrom_toc_full.TrackData[i].PSEC;
i_seen_flag|=0x01;
}
if ( 0xA1 == cdrom_toc_full.TrackData[i].POINT ) {
/* Last track number */
p_env->gen.i_tracks =
cdrom_toc_full.TrackData[i].PMIN - p_env->gen.i_first_track + 1;
i_seen_flag|=0x02;
}
if ( 0xA2 == cdrom_toc_full.TrackData[i].POINT ) {
/* Start position of the lead out */
p_env->tocent[ p_env->gen.i_tracks ].start_lsn =
cdio_msf3_to_lba(
cdrom_toc_full.TrackData[i].PMIN,
cdrom_toc_full.TrackData[i].PSEC,
cdrom_toc_full.TrackData[i].PFRAME );
p_env->tocent[ p_env->gen.i_tracks ].Control
= cdrom_toc_full.TrackData[i].Control;
p_env->tocent[ p_env->gen.i_tracks ].Format = i_track_format;
i_seen_flag|=0x04;
}
if (cdrom_toc_full.TrackData[i].POINT > 0
&& cdrom_toc_full.TrackData[i].POINT <= p_env->gen.i_tracks) {
p_env->tocent[ cdrom_toc_full.TrackData[i].POINT - 1 ].start_lsn =
cdio_msf3_to_lba(
cdrom_toc_full.TrackData[i].PMIN,
cdrom_toc_full.TrackData[i].PSEC,
cdrom_toc_full.TrackData[i].PFRAME );
p_env->tocent[ cdrom_toc_full.TrackData[i].POINT - 1 ].Control =
cdrom_toc_full.TrackData[i].Control;
p_env->tocent[ cdrom_toc_full.TrackData[i].POINT - 1 ].Format =
i_track_format;
cdio_debug("p_sectors: %i, %lu", i,
(unsigned long int) (p_env->tocent[i].start_lsn));
if (cdrom_toc_full.TrackData[i].POINT == p_env->gen.i_tracks)
i_seen_flag|=0x08;
}
if ( 0x0F == i_seen_flag ) break;
}
if ( 0x0F == i_seen_flag ) {
p_env->gen.toc_init = true;
return true;
}
return false;
}
/*!
Read and cache the CD's Track Table of Contents and track info.
Return true if successful or false if an error.
*/
bool
read_toc_win32ioctl (_img_private_t *p_env)
{
CDROM_TOC cdrom_toc;
DWORD dwBytesReturned;
unsigned int i;
if ( ! p_env ) return false;
if ( read_fulltoc_win32mmc(p_env) ) return true;
/* SCSI-MMC READ_TOC (FULTOC) read failed. Try reading TOC via
DeviceIoControl instead */
if( DeviceIoControl( p_env->h_device_handle,
IOCTL_CDROM_READ_TOC,
NULL, 0, &cdrom_toc, sizeof(CDROM_TOC),
&dwBytesReturned, NULL ) == 0 ) {
char *psz_msg = NULL;
long int i_err = GetLastError();
FORMAT_ERROR(i_err, psz_msg);
if (psz_msg) {
cdio_warn("could not read TOC (%ld): %s", i_err, psz_msg);
LocalFree(psz_msg);
} else
cdio_warn("could not read TOC (%ld)", i_err);
return false;
}
p_env->gen.i_first_track = cdrom_toc.FirstTrack;
p_env->gen.i_tracks = cdrom_toc.LastTrack - cdrom_toc.FirstTrack + 1;
for( i = 0 ; i <= p_env->gen.i_tracks ; i++ ) {
p_env->tocent[ i ].start_lsn =
cdio_msf3_to_lba( cdrom_toc.TrackData[i].Address[1],
cdrom_toc.TrackData[i].Address[2],
cdrom_toc.TrackData[i].Address[3] );
p_env->tocent[ i ].Control = cdrom_toc.TrackData[i].Control;
p_env->tocent[ i ].Format = cdrom_toc.TrackData[i].Format;
cdio_debug("p_sectors: %i, %lu", i,
(unsigned long int) (p_env->tocent[i].start_lsn));
}
p_env->gen.toc_init = true;
return true;
}
/*!
Return the media catalog number MCN.
Note: string is malloc'd so caller should free() then returned
string when done with it.
*/
char *
get_mcn_win32ioctl (const _img_private_t *env) {
DWORD dwBytesReturned;
SUB_Q_MEDIA_CATALOG_NUMBER mcn;
CDROM_SUB_Q_DATA_FORMAT q_data_format;
memset( &mcn, 0, sizeof(mcn) );
q_data_format.Format = CDIO_SUBCHANNEL_MEDIA_CATALOG;
q_data_format.Track=1;
if( DeviceIoControl( env->h_device_handle,
IOCTL_CDROM_READ_Q_CHANNEL,
&q_data_format, sizeof(q_data_format),
&mcn, sizeof(mcn),
&dwBytesReturned, NULL ) == 0 ) {
cdio_warn( "could not read Q Channel at track %d", 1);
} else if (mcn.Mcval)
return strdup(mcn.MediaCatalog);
return NULL;
}
/*!
Get the format (XA, DATA, AUDIO) of a track.
*/
track_format_t
get_track_format_win32ioctl(const _img_private_t *env, track_t i_track)
{
/* This is pretty much copied from the "badly broken" cdrom_count_tracks
in linux/cdrom.c.
*/
if (env->tocent[i_track - env->gen.i_first_track].Control & 0x04) {
if (env->tocent[i_track - env->gen.i_first_track].Format == 0x10)
return TRACK_FORMAT_CDI;
else if (env->tocent[i_track - env->gen.i_first_track].Format == 0x20)
return TRACK_FORMAT_XA;
else
return TRACK_FORMAT_DATA;
} else
return TRACK_FORMAT_AUDIO;
}
#endif /*HAVE_WIN32_CDROM*/

173
lib/driver/Makefile.am Normal file
View File

@@ -0,0 +1,173 @@
# $Id: Makefile.am,v 1.1 2004/12/18 17:29:32 rocky Exp $
#
# Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
########################################################
# Things to make the libcdio library
########################################################
#
# From libtool documentation amended with guidance from N. Boullis:
#
# 1. Start with version information of `0:0:0' for each libtool library.
#
# 2. It is probably not a good idea to update the version information
# several times between public releases, but rather once per public
# release. (This seems to be more an aesthetic consideration than
# a hard technical one.)
#
# 3. If the library source code has changed at all since the last
# update, then increment REVISION (`C:R:A' becomes `C:R+1:A').
#
# 4. If any interfaces have been added, removed, or changed since the
# last update, increment CURRENT, and set REVISION to 0.
#
# 5. If any interfaces have been added since the last public release,
# then increment AGE.
#
# 6. If any interfaces have been removed or changed since the last
# public release, then set AGE to 0. A changed interface means an
# incompatibility with previous versions.
libcdio_la_CURRENT := 3
libcdio_la_REVISION := 0
libcdio_la_AGE := 0
EXTRA_DIST = image/Makefile FreeBSD/Makefile MSWindows/Makefile \
libcdio.sym
noinst_HEADERS = cdio_assert.h cdio_private.h portable.h
libcdio_sources = \
_cdio_aix.c \
_cdio_bsdi.c \
_cdio_generic.c \
_cdio_linux.c \
_cdio_osx.c \
_cdio_stdio.c \
_cdio_stdio.h \
_cdio_stream.c \
_cdio_stream.h \
_cdio_sunos.c \
cd_types.c \
cdio.c \
cdtext.c \
cdtext_private.h \
ds.c \
FreeBSD/freebsd.c \
FreeBSD/freebsd.h \
FreeBSD/freebsd_cam.c \
FreeBSD/freebsd_ioctl.c \
generic.h \
image.h \
image/bincue.c \
image/cdrdao.c \
image_common.h \
image/nrg.c \
image/nrg.h \
MSWindows/aspi32.c \
MSWindows/aspi32.h \
MSWindows/win32_ioctl.c \
MSWindows/win32.c \
MSWindows/win32.h \
logging.c \
scsi_mmc.c \
scsi_mmc_private.h \
sector.c \
util.c
lib_LTLIBRARIES = libcdio.la
libcdio_la_SOURCES = $(libcdio_sources)
libcdio_la_ldflags = -version-info $(libcdio_la_CURRENT):$(libcdio_la_REVISION):$(libcdio_la_AGE)
INCLUDES = $(LIBCDIO_CFLAGS)
########################################################
# Things to version the symbols in the libraries
########################################################
# An explanation of the versioning problem from Nicolas Boullis and
# the versioned symbol solution he uses below...
#
# Currently, libvcdinfo uses the cdio_open function from libcdio.
# Let's imagine a program foobar that uses both the vcdinfo_open
# function from libvcdinfo and the cdio_open function from libcdio.
# Currently, libcdio has SONAME libcdio.so.0, libvcdinfo has SONAME
# libvcdinfo.so.0 and requires libcdio.so.0, and foobar requires both
# libvcdinfo.so.0 and libcdio.so.0. Everything looks fine.
#
# Now, for some reason, you decide to change the cdio_open function.
# That's your right, but you have to bump the CURRENT version and (if I
# understand it correctly, athough this is not that clear in libtool's
# documentation) set the AGE to 0. Anyway, this bumps the SONAME, which is
# sane since the interface changes incompatibly.
# Now, you have a new libcdio with SONAME libcdio.so.1. But libvcdinfo and
# foobar still require libcdio.so.0. Everything is still fine.
# Now, after some minor changes, the author of foobar recompiles foobar.
# Then, foobar now requires libvcdinfo.so.0 and libcdio.so.1. And foobar
# now segfaults...
# What is happening? When you run foobar, if brings both libvcdinfo.so.0
# and libcdio.so.1, but libvcdinfo.so.0 also brings libcdio.so.0. So you
# have both libcdio.so.0 and libcdio.so.1 that bring their symbols to the
# global namespace. Hence, you have to incompatible versions of the
# cdio_open function in the name space. When foobar calls cdio_open, it
# may choose the wrong function, and segfaults...
# With versioned symbols, the cdio_open function from libcdio.so.0 may be
# known as (something that looks like) cdio_open@@CDIO_0. An the cdio_open
# function from libcdio.so.1 as cdio_open@@CDIO_1. Both versions of
# libcdio would still be brought in by the most recent foobar, but foobar
# (and libvcdinfo) know which versioned function to use and then use the
# good one.
# This is some simple versioning where every symbol is versioned with
# something that looks like the SONAME of the library. More complex (and
# better) versioning is possible; it is for example what is used by glibc.
# But good complex versioning is something that requires much more
# work...
# The below is a impliments symbol versioning. First of all, I
# compute MAJOR as CURENT - AGE; that is what is used within libtool
# (at least on GNU/Linux systems) for the number in the SONAME. The
# nm command gives the list of symbols known in each of the object
# files that will be part of the shared library. And the sed command
# extracts from this list those symbols that will be shared. (This sed
# command comes from libtool.)
libcdio_la_MAJOR := $(shell expr $(libcdio_la_CURRENT) - $(libcdio_la_AGE))
if BUILD_VERSIONED_LIBS
libcdio_la_LDFLAGS = $(libcdio_la_ldflags) -Wl,--version-script=libcdio.la.ver
libcdio_la_DEPENDENCIES = libcdio.la.ver
libcdio.la.ver: $(libcdio_la_OBJECTS) $(srcdir)/libcdio.sym
echo 'CDIO_$(libcdio_la_MAJOR) { ' > $@
echo " global:" >> $@
nm $(patsubst %.lo,%.o,$(libcdio_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio.sym; then echo " $${symbol};"; fi; done >> $@
echo " local:" >> $@
nm $(patsubst %.lo,%.o,$(libcdio_la_OBJECTS)) | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio.sym; then :; else echo " $${symbol};"; fi; done >> $@
echo '};' >> $@
else
libcdio_la_LDFLAGS = $(libcdio_la_ldflags)
endif
MOSTLYCLEANFILES = libcdio.la.ver

1023
lib/driver/_cdio_aix.c Normal file

File diff suppressed because it is too large Load Diff

846
lib/driver/_cdio_bsdi.c Normal file
View File

@@ -0,0 +1,846 @@
/*
$Id: _cdio_bsdi.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2002, 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This file contains BSDI-specific code and implements low-level
control of the CD drive.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: _cdio_bsdi.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
#include <cdio/logging.h>
#include <cdio/sector.h>
#include <cdio/util.h>
#include "cdio_assert.h"
#include "cdio_private.h"
#define DEFAULT_CDIO_DEVICE "/dev/rsr0c"
#include <string.h>
#ifdef HAVE_BSDI_CDROM
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
/*#define USE_ETC_FSTAB*/
#ifdef USE_ETC_FSTAB
#include <fstab.h>
#endif
#include <dvd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include </sys/dev/scsi/scsi.h>
#include </sys/dev/scsi/scsi_ioctl.h>
#include "cdtext_private.h"
typedef enum {
_AM_NONE,
_AM_IOCTL,
} 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;
/* Some of the more OS specific things. */
/* Track information */
struct cdrom_tochdr tochdr;
struct cdrom_tocentry tocent[CDIO_CD_MAX_TRACKS+1];
} _img_private_t;
/* Define the Cdrom Generic Command structure */
typedef struct cgc
{
scsi_mmc_cdb_t cdb;
u_char *buf;
int buflen;
int rw;
unsigned int timeout;
scsi_user_sense_t *sus;
} cgc_t;
/*
This code adapted from Steven M. Schultz's libdvd
*/
static int
run_scsi_cmd_bsdi(const void *p_user_data, unsigned int i_timeout_ms,
unsigned int i_cdb, const scsi_mmc_cdb_t *p_cdb,
scsi_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf )
{
const _img_private_t *p_env = p_user_data;
int i_status, i_asc;
struct scsi_user_cdb suc;
struct scsi_sense *sp;
again:
suc.suc_flags = SCSI_MMC_DATA_READ == e_direction ?
SUC_READ : SUC_WRITE;
suc.suc_cdblen = i_cdb;
memcpy(suc.suc_cdb, p_cdb, i_cdb);
suc.suc_data = p_buf;
suc.suc_datalen = i_buf;
suc.suc_timeout = msecs2secs(i_timeout_ms);
if (ioctl(p_env->gen.fd, SCSIRAWCDB, &suc) == -1)
return(errno);
i_status = suc.suc_sus.sus_status;
#if 0
/*
* If the device returns a scsi sense error and debugging is enabled print
* some hopefully useful information on stderr.
*/
if (i_status && debug)
{
unsigned char *cp;
int i;
cp = suc.suc_sus.sus_sense;
fprintf(stderr,"i_status = %x cdb =",
i_status);
for (i = 0; i < cdblen; i++)
fprintf(stderr, " %x", cgc->cdb[i]);
fprintf(stderr, "\nsense =");
for (i = 0; i < 16; i++)
fprintf(stderr, " %x", cp[i]);
fprintf(stderr, "\n");
}
#endif
/*
* HACK! Some drives return a silly "medium changed" on the first
* command AND a non-zero i_status which gets turned into a fatal
* (EIO) error even though the operation was a success. Retrying
* the operation clears the media changed status and gets the
* answer. */
sp = (struct scsi_sense *)&suc.suc_sus.sus_sense;
i_asc = XSENSE_ASC(sp);
if (i_status == STS_CHECKCOND && i_asc == 0x28)
goto again;
#if 0
if (cgc->sus)
memcpy(cgc->sus, &suc.suc_sus, sizeof (struct scsi_user_sense));
#endif
return(i_status);
}
/* Check a drive to see if it is a CD-ROM
Return 1 if a CD-ROM. 0 if it exists but isn't a CD-ROM drive
and -1 if no device exists .
*/
static bool
cdio_is_cdrom(char *drive, char *mnttype)
{
bool is_cd=false;
int cdfd;
struct cdrom_tochdr tochdr;
/* If it doesn't exist, return -1 */
if ( !cdio_is_device_quiet_generic(drive) ) {
return(false);
}
/* If it does exist, verify that it's an available CD-ROM */
cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0);
/* Should we want to test the condition in more detail:
ENOENT is the error for /dev/xxxxx does not exist;
ENODEV means there's no drive present. */
if ( cdfd >= 0 ) {
if ( ioctl(cdfd, CDROMREADTOCHDR, &tochdr) != -1 ) {
is_cd = true;
}
close(cdfd);
}
/* Even if we can't read it, it might be mounted */
else if ( mnttype && (strcmp(mnttype, "cd9660") == 0) ) {
is_cd = true;
}
return(is_cd);
}
/*!
Initialize CD device.
*/
static bool
_cdio_init (_img_private_t *p_env)
{
if (p_env->gen.init) {
cdio_warn ("init called more than once");
return false;
}
p_env->gen.fd = open (p_env->gen.source_name, O_RDONLY, 0);
if (p_env->gen.fd < 0)
{
cdio_warn ("open (%s): %s", p_env->gen.source_name, strerror (errno));
return false;
}
p_env->gen.init = true;
p_env->gen.toc_init = false;
return true;
}
/* Read audio sectors
*/
static int
_read_audio_sectors_bsdi (void *user_data, void *data, lsn_t lsn,
unsigned int nblocks)
{
char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
struct cdrom_msf *msf = (struct cdrom_msf *) &buf;
msf_t _msf;
_img_private_t *p_env = user_data;
cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf);
msf->cdmsf_min0 = cdio_from_bcd8(_msf.m);
msf->cdmsf_sec0 = cdio_from_bcd8(_msf.s);
msf->cdmsf_frame0 = cdio_from_bcd8(_msf.f);
if (p_env->gen.ioctls_debugged == 75)
cdio_debug ("only displaying every 75th ioctl from now on");
if (p_env->gen.ioctls_debugged == 30 * 75)
cdio_debug ("only displaying every 30*75th ioctl from now on");
if (p_env->gen.ioctls_debugged < 75
|| (p_env->gen.ioctls_debugged < (30 * 75)
&& p_env->gen.ioctls_debugged % 75 == 0)
|| p_env->gen.ioctls_debugged % (30 * 75) == 0)
cdio_debug ("reading %2.2d:%2.2d:%2.2d",
msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0);
p_env->gen.ioctls_debugged++;
switch (p_env->access_mode) {
case _AM_NONE:
cdio_warn ("no way to read audio");
return 1;
break;
case _AM_IOCTL: {
unsigned int i;
for (i=0; i < nblocks; i++) {
if (ioctl (p_env->gen.fd, CDROMREADRAW, &buf) == -1) {
perror ("ioctl()");
return 1;
/* exit (EXIT_FAILURE); */
}
memcpy (((char *)data) + (CDIO_CD_FRAMESIZE_RAW * i), buf,
CDIO_CD_FRAMESIZE_RAW);
}
break;
}
}
return 0;
}
/*!
Reads a single mode1 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
static int
_read_mode1_sector_bsdi (void *user_data, void *data, lsn_t lsn,
bool b_form2)
{
#if FIXED
char buf[M2RAW_SECTOR_SIZE] = { 0, };
do something here.
#else
return cdio_generic_read_form1_sector(user_data, data, lsn);
#endif
return 0;
}
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
static int
_read_mode1_sectors_bsdi (void *user_data, void *data, lsn_t lsn,
bool b_form2, unsigned int nblocks)
{
_img_private_t *p_env = user_data;
unsigned int i;
int retval;
unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
for (i = 0; i < nblocks; i++) {
if ( (retval = _read_mode1_sector_bsdi (p_env,
((char *)data) + (blocksize * i),
lsn + i, b_form2)) )
return retval;
}
return 0;
}
/*!
Reads a single mode2 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
static int
_read_mode2_sector_bsdi (void *user_data, void *data, lsn_t lsn,
bool b_form2)
{
char buf[M2RAW_SECTOR_SIZE] = { 0, };
struct cdrom_msf *msf = (struct cdrom_msf *) &buf;
msf_t _msf;
_img_private_t *p_env = user_data;
cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf);
msf->cdmsf_min0 = cdio_from_bcd8(_msf.m);
msf->cdmsf_sec0 = cdio_from_bcd8(_msf.s);
msf->cdmsf_frame0 = cdio_from_bcd8(_msf.f);
if (p_env->gen.ioctls_debugged == 75)
cdio_debug ("only displaying every 75th ioctl from now on");
if (p_env->gen.ioctls_debugged == 30 * 75)
cdio_debug ("only displaying every 30*75th ioctl from now on");
if (p_env->gen.ioctls_debugged < 75
|| (p_env->gen.ioctls_debugged < (30 * 75)
&& p_env->gen.ioctls_debugged % 75 == 0)
|| p_env->gen.ioctls_debugged % (30 * 75) == 0)
cdio_debug ("reading %2.2d:%2.2d:%2.2d",
msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0);
p_env->gen.ioctls_debugged++;
switch (p_env->access_mode)
{
case _AM_NONE:
cdio_warn ("no way to read mode2");
return 1;
break;
case _AM_IOCTL:
if (ioctl (p_env->gen.fd, CDROMREADMODE2, &buf) == -1)
{
perror ("ioctl()");
return 1;
/* exit (EXIT_FAILURE); */
}
break;
}
if (b_form2)
memcpy (data, buf, M2RAW_SECTOR_SIZE);
else
memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_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_bsdi (void *user_data, void *data, lsn_t lsn,
bool b_form2, unsigned int nblocks)
{
_img_private_t *p_env = user_data;
unsigned int i;
unsigned int i_blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
/* For each frame, pick out the data part we need */
for (i = 0; i < nblocks; i++) {
int retval = _read_mode2_sector_bsdi(p_env,
((char *)data) +
(i_blocksize * i),
lsn + i, b_form2);
if (retval) return retval;
}
return 0;
}
/*!
Return the size of the CD in logical block address (LBA) units.
*/
static uint32_t
_stat_size_bsdi (void *user_data)
{
_img_private_t *p_env = user_data;
struct cdrom_tocentry tocent;
uint32_t size;
tocent.cdte_track = CDIO_CDROM_LEADOUT_TRACK;
tocent.cdte_format = CDROM_LBA;
if (ioctl (p_env->gen.fd, CDROMREADTOCENTRY, &tocent) == -1)
{
perror ("ioctl(CDROMREADTOCENTRY)");
exit (EXIT_FAILURE);
}
size = tocent.cdte_addr.lba;
return size;
}
/*!
Set the key "arg" to "value" in source device.
*/
static int
_set_arg_bsdi (void *user_data, const char key[], const char value[])
{
_img_private_t *p_env = user_data;
if (!strcmp (key, "source"))
{
if (!value)
return -2;
free (p_env->gen.source_name);
p_env->gen.source_name = strdup (value);
}
else if (!strcmp (key, "access-mode"))
{
if (!strcmp(value, "IOCTL"))
p_env->access_mode = _AM_IOCTL;
else
cdio_warn ("unknown access type: %s. ignored.", value);
}
else
return -1;
return 0;
}
/*!
Read and cache the CD's Track Table of Contents and track info.
Return false if successful or true if an error.
*/
static bool
read_toc_bsdi (void *p_user_data)
{
_img_private_t *p_env = p_user_data;
int i;
/* read TOC header */
if ( ioctl(p_env->gen.fd, CDROMREADTOCHDR, &p_env->tochdr) == -1 ) {
cdio_warn("%s: %s\n",
"error in ioctl CDROMREADTOCHDR", strerror(errno));
return false;
}
p_env->gen.i_first_track = p_env->tochdr.cdth_trk0;
p_env->gen.i_tracks = p_env->tochdr.cdth_trk1;
/* read individual tracks */
for (i= p_env->gen.i_first_track; i<=p_env->gen.i_tracks; i++) {
p_env->tocent[i-1].cdte_track = i;
p_env->tocent[i-1].cdte_format = CDROM_MSF;
if (ioctl(p_env->gen.fd, CDROMREADTOCENTRY, &p_env->tocent[i-1]) == -1) {
cdio_warn("%s %d: %s\n",
"error in ioctl CDROMREADTOCENTRY for track",
i, strerror(errno));
return false;
}
/****
struct cdrom_msf0 *msf= &p_env->tocent[i-1].cdte_addr.msf;
fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n",
i, msf->minute, msf->second, msf->frame);
****/
}
/* read the lead-out track */
p_env->tocent[p_env->gen.i_tracks].cdte_track = CDIO_CDROM_LEADOUT_TRACK;
p_env->tocent[p_env->gen.i_tracks].cdte_format = CDROM_MSF;
if (ioctl(p_env->gen.fd, CDROMREADTOCENTRY,
&p_env->tocent[p_env->gen.i_tracks]) == -1 ) {
cdio_warn("%s: %s\n",
"error in ioctl CDROMREADTOCENTRY for lead-out",
strerror(errno));
return false;
}
/*
struct cdrom_msf0 *msf= &p_env->tocent[p_env->gen.i_tracks].cdte_addr.msf;
fprintf (stdout, "--- track# %d (msf %2.2x:%2.2x:%2.2x)\n",
i, msf->minute, msf->second, msf->frame);
*/
p_env->gen.toc_init = true;
return true;
}
/*!
Eject media in CD drive. If successful, as a side effect we
also free obj.
*/
static int
_eject_media_bsdi (void *user_data) {
_img_private_t *p_env = user_data;
int ret=2;
int status;
int fd;
close(p_env->gen.fd);
p_env->gen.fd = -1;
if ((fd = open (p_env->gen.source_name, O_RDONLY|O_NONBLOCK)) > -1) {
if((status = ioctl(fd, CDROM_DRIVE_STATUS, (void *) CDSL_CURRENT)) > 0) {
switch(status) {
case CDS_TRAY_OPEN:
if((ret = ioctl(fd, CDROMCLOSETRAY, 0)) != 0) {
cdio_warn ("ioctl CDROMCLOSETRAY failed: %s\n", strerror(errno));
}
break;
case CDS_DISC_OK:
if((ret = ioctl(fd, CDROMEJECT, 0)) != 0) {
cdio_warn("ioctl CDROMEJECT failed: %s\n", strerror(errno));
}
break;
}
ret=0;
} else {
cdio_warn ("CDROM_DRIVE_STATUS failed: %s\n", strerror(errno));
ret=1;
}
close(fd);
}
return 2;
}
/*!
Return the value associated with the key "arg".
*/
static const char *
_get_arg_bsdi (void *user_data, const char key[])
{
_img_private_t *p_env = 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_IOCTL:
return "ioctl";
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 *
_get_mcn_bsdi (const void *user_data) {
struct cdrom_mcn mcn;
const _img_private_t *p_env = user_data;
if (ioctl(p_env->gen.fd, CDROM_GET_MCN, &mcn) != 0)
return NULL;
return strdup(mcn.medium_catalog_number);
}
/*!
Get format of track.
*/
static track_format_t
get_track_format_bsdi(void *user_data, track_t i_track)
{
_img_private_t *p_env = user_data;
if (!p_env->gen.toc_init) read_toc_bsdi (p_env) ;
if (i_track > p_env->gen.i_tracks || i_track == 0)
return TRACK_FORMAT_ERROR;
i_track -= p_env->gen.i_first_track;
/* This is pretty much copied from the "badly broken" cdrom_count_tracks
in linux/cdrom.c.
*/
if (p_env->tocent[i_track].cdte_ctrl & CDROM_DATA_TRACK) {
if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_CDI_TRACK)
return TRACK_FORMAT_CDI;
else if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_XA_TRACK)
return TRACK_FORMAT_XA;
else
return TRACK_FORMAT_DATA;
} else
return TRACK_FORMAT_AUDIO;
}
/*!
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
_get_track_green_bsdi(void *user_data, track_t i_track)
{
_img_private_t *p_env = user_data;
if (!p_env->gen.toc_init) read_toc_bsdi (p_env) ;
if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = p_env->gen.i_tracks+1;
if (i_track > p_env->gen.i_tracks+1 || i_track == 0)
return false;
/* FIXME: Dunno if this is the right way, but it's what
I was using in cdinfo for a while.
*/
return ((p_env->tocent[i_track-1].cdte_ctrl & 2) != 0);
}
/*!
Return the starting MSF (minutes/secs/frames) for track number
i_track in obj. Track numbers start at 1.
The "leadout" track is specified either by
using i_track LEADOUT_TRACK or the total tracks+1.
False is returned if there is no track entry.
*/
static bool
_get_track_msf_bsdi(void *user_data, track_t i_track, msf_t *msf)
{
_img_private_t *p_env = user_data;
if (NULL == msf) return false;
if (!p_env->gen.toc_init) read_toc_bsdi (p_env) ;
if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = p_env->gen.i_tracks+1;
if (i_track > p_env->gen.i_tracks+1 || i_track == 0) {
return false;
}
i_track -= p_env->gen.i_first_track;
{
struct cdrom_msf0 *msf0= &p_env->tocent[i_track].cdte_addr.msf;
msf->m = cdio_to_bcd8(msf0->minute);
msf->s = cdio_to_bcd8(msf0->second);
msf->f = cdio_to_bcd8(msf0->frame);
return true;
}
}
#endif /* HAVE_BSDI_CDROM */
/*!
Return an array of strings giving possible CD devices.
*/
char **
cdio_get_devices_bsdi (void)
{
#ifndef HAVE_BSDI_CDROM
return NULL;
#else
char drive[40];
char **drives = NULL;
unsigned int num_drives=0;
bool exists=true;
char c;
/* Scan the system for CD-ROM drives.
*/
#ifdef USE_ETC_FSTAB
struct fstab *fs;
setfsent();
/* Check what's in /etc/fstab... */
while ( (fs = getfsent()) )
{
if (strncmp(fs->fs_spec, "/dev/sr", 7))
cdio_add_device_list(&drives, fs->fs_spec, &num_drives);
}
#endif
/* Scan the system for CD-ROM drives.
Not always 100% reliable, so use the USE_MNTENT code above first.
*/
for ( c='0'; exists && c <='9'; c++ ) {
sprintf(drive, "/dev/rsr%cc", c);
exists = cdio_is_cdrom(drive, NULL);
if ( exists ) {
cdio_add_device_list(&drives, drive, &num_drives);
}
}
cdio_add_device_list(&drives, NULL, &num_drives);
return drives;
#endif /*HAVE_BSDI_CDROM*/
}
/*!
Return a string containing the default CD device if none is specified.
*/
char *
cdio_get_default_device_bsdi(void)
{
return strdup(DEFAULT_CDIO_DEVICE);
}
/*!
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 *
cdio_open_am_bsdi (const char *psz_source_name, const char *psz_access_mode)
{
if (psz_access_mode != NULL)
cdio_warn ("there is only one access mode for bsdi. Arg %s ignored",
psz_access_mode);
return cdio_open_bsdi(psz_source_name);
}
/*!
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 *
cdio_open_bsdi (const char *psz_orig_source)
{
#ifdef HAVE_BSDI_CDROM
CdIo *ret;
_img_private_t *_data;
char *psz_source;
cdio_funcs _funcs = {
.eject_media = _eject_media_bsdi,
.free = cdio_generic_free,
.get_arg = _get_arg_bsdi,
.get_cdtext = get_cdtext_generic,
.get_default_device = cdio_get_default_device_bsdi,
.get_devices = cdio_get_devices_bsdi,
.get_drive_cap = scsi_mmc_get_drive_cap_generic,
.get_discmode = get_discmode_generic,
.get_first_track_num= get_first_track_num_generic,
.get_hwinfo = NULL,
.get_mcn = _get_mcn_bsdi,
.get_num_tracks = get_num_tracks_generic,
.get_track_format = get_track_format_bsdi,
.get_track_green = _get_track_green_bsdi,
.get_track_lba = NULL, /* This could be implemented if need be. */
.get_track_msf = _get_track_msf_bsdi,
.lseek = cdio_generic_lseek,
.read = cdio_generic_read,
.read_audio_sectors = _read_audio_sectors_bsdi,
.read_mode1_sector = _read_mode1_sector_bsdi,
.read_mode1_sectors = _read_mode1_sectors_bsdi,
.read_mode2_sector = _read_mode2_sector_bsdi,
.read_mode2_sectors = _read_mode2_sectors_bsdi,
.read_toc = &read_toc_bsdi,
.run_scsi_mmc_cmd = &run_scsi_cmd_bsdi,
.set_arg = _set_arg_bsdi,
.stat_size = _stat_size_bsdi
};
_data = _cdio_malloc (sizeof (_img_private_t));
_data->access_mode = _AM_IOCTL;
_data->gen.init = false;
_data->gen.fd = -1;
_data->gen.toc_init = false;
_data->gen.b_cdtext_init = false;
_data->gen.b_cdtext_error = false;
if (NULL == psz_orig_source) {
psz_source=cdio_get_default_device_linux();
if (NULL == psz_source) return NULL;
_set_arg_bsdi(_data, "source", psz_source);
free(psz_source);
} else {
if (cdio_is_device_generic(psz_orig_source))
_set_arg_bsdi(_data, "source", psz_orig_source);
else {
/* The below would be okay if all device drivers worked this way. */
#if 0
cdio_info ("source %s is not a device", psz_orig_source);
#endif
return NULL;
}
}
ret = cdio_new ( (void *) _data, &_funcs);
if (ret == NULL) return NULL;
if (_cdio_init(_data))
return ret;
else {
cdio_generic_free (_data);
return NULL;
}
#else
return NULL;
#endif /* HAVE_BSDI_CDROM */
}
bool
cdio_have_bsdi (void)
{
#ifdef HAVE_BSDI_CDROM
return true;
#else
return false;
#endif /* HAVE_BSDI_CDROM */
}

426
lib/driver/_cdio_generic.c Normal file
View File

@@ -0,0 +1,426 @@
/*
$Id: _cdio_generic.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* This file contains generic implementations of device-dirver routines.
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static const char _rcsid[] = "$Id: _cdio_generic.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#include <fcntl.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <cdio/sector.h>
#include <cdio/util.h>
#include <cdio/logging.h>
#include "cdio_assert.h"
#include "cdio_private.h"
#include "_cdio_stdio.h"
#include "portable.h"
/*!
Eject media -- there's nothing to do here. We always return 2.
Should we also free resources?
*/
int
cdio_generic_bogus_eject_media (void *user_data) {
/* Sort of a stub here. Perhaps log a message? */
return 2;
}
/*!
Release and free resources associated with cd.
*/
void
cdio_generic_free (void *p_user_data)
{
generic_img_private_t *p_env = p_user_data;
track_t i_track;
if (NULL == p_env) return;
free (p_env->source_name);
for (i_track=0; i_track < p_env->i_tracks; i_track++) {
cdtext_destroy(&(p_env->cdtext_track[i_track]));
}
if (p_env->fd >= 0)
close (p_env->fd);
free (p_env);
}
/*!
Initialize CD device.
*/
bool
cdio_generic_init (void *user_data)
{
generic_img_private_t *p_env = user_data;
if (p_env->init) {
cdio_warn ("init called more than once");
return false;
}
p_env->fd = open (p_env->source_name, O_RDONLY, 0);
if (p_env->fd < 0)
{
cdio_warn ("open (%s): %s", p_env->source_name, strerror (errno));
return false;
}
p_env->init = true;
p_env->toc_init = false;
p_env->b_cdtext_init = false;
p_env->b_cdtext_error = false;
p_env->i_joliet_level = 0; /* Assume no Joliet extensions initally */
return true;
}
/*!
Reads a single form1 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int
cdio_generic_read_form1_sector (void * user_data, void *data, lsn_t lsn)
{
if (0 > cdio_generic_lseek(user_data, CDIO_CD_FRAMESIZE*lsn, SEEK_SET))
return -1;
if (0 > cdio_generic_read(user_data, data, CDIO_CD_FRAMESIZE))
return -1;
return 0;
}
/*!
Reads into buf the next size bytes.
Returns -1 on error.
Is in fact libc's lseek().
*/
off_t
cdio_generic_lseek (void *user_data, off_t offset, int whence)
{
generic_img_private_t *p_env = user_data;
return lseek(p_env->fd, offset, whence);
}
/*!
Reads into buf the next size bytes.
Returns -1 on error.
Is in fact libc's read().
*/
ssize_t
cdio_generic_read (void *user_data, void *buf, size_t size)
{
generic_img_private_t *p_env = user_data;
return read(p_env->fd, buf, size);
}
/*!
Release and free resources associated with stream or disk image.
*/
void
cdio_generic_stdio_free (void *user_data)
{
generic_img_private_t *p_env = user_data;
if (NULL == p_env) return;
if (NULL != p_env->source_name)
free (p_env->source_name);
if (p_env->data_source)
cdio_stdio_destroy (p_env->data_source);
}
/*!
Return true if source_name could be a device containing a CD-ROM.
*/
bool
cdio_is_device_generic(const char *source_name)
{
struct stat buf;
if (0 != stat(source_name, &buf)) {
cdio_warn ("Can't get file status for %s:\n%s", source_name,
strerror(errno));
return false;
}
return (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode));
}
/*!
Like above, but don't give a warning device doesn't exist.
*/
bool
cdio_is_device_quiet_generic(const char *source_name)
{
struct stat buf;
if (0 != stat(source_name, &buf)) {
return false;
}
return (S_ISBLK(buf.st_mode) || S_ISCHR(buf.st_mode));
}
/*!
Add/allocate a drive to the end of drives.
Use cdio_free_device_list() to free this device_list.
*/
void
cdio_add_device_list(char **device_list[], const char *drive,
unsigned int *num_drives)
{
if (NULL != drive) {
unsigned int j;
/* Check if drive is already in list. */
for (j=0; j<*num_drives; j++) {
if (strcmp((*device_list)[j], drive) == 0) break;
}
if (j==*num_drives) {
/* Drive not in list. Add it. */
(*num_drives)++;
if (*device_list) {
*device_list = realloc(*device_list, (*num_drives) * sizeof(char *));
} else {
/* num_drives should be 0. Add assert? */
*device_list = malloc((*num_drives) * sizeof(char *));
}
(*device_list)[*num_drives-1] = strdup(drive);
}
} else {
(*num_drives)++;
if (*device_list) {
*device_list = realloc(*device_list, (*num_drives) * sizeof(char *));
} else {
*device_list = malloc((*num_drives) * sizeof(char *));
}
(*device_list)[*num_drives-1] = NULL;
}
}
/*!
Get cdtext information for a CdIo object .
@param obj the CD object that may contain CD-TEXT information.
@return the CD-TEXT object or NULL if obj is NULL
or CD-TEXT information does not exist.
*/
const cdtext_t *
get_cdtext_generic (void *p_user_data, track_t i_track)
{
generic_img_private_t *p_env = p_user_data;
if ( NULL == p_env ||
(0 != i_track
&& i_track >= p_env->i_tracks+p_env->i_first_track ) )
return NULL;
if (!p_env->b_cdtext_init)
init_cdtext_generic(p_env);
if (!p_env->b_cdtext_init) return NULL;
if (0 == i_track)
return &(p_env->cdtext);
else
return &(p_env->cdtext_track[i_track-p_env->i_first_track]);
}
/*!
Get disc type associated with cd object.
*/
discmode_t
get_discmode_generic (void *p_user_data )
{
generic_img_private_t *p_env = p_user_data;
/* 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;
if (0 == scsi_mmc_get_dvd_struct_physical (p_env->cdio, &dvd)) {
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 get_discmode_cd_generic(p_user_data);
}
/*!
Get disc type associated with cd object.
*/
discmode_t
get_discmode_cd_generic (void *p_user_data )
{
generic_img_private_t *p_env = p_user_data;
track_t i_track;
discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
if (!p_env->toc_init)
p_env->cdio->op.read_toc (p_user_data);
if (!p_env->toc_init)
return CDIO_DISC_MODE_NO_INFO;
for (i_track = p_env->i_first_track;
i_track < p_env->i_first_track + p_env->i_tracks ;
i_track ++) {
track_format_t track_fmt =
p_env->cdio->op.get_track_format(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;
}
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t
get_first_track_num_generic(void *p_user_data)
{
generic_img_private_t *p_env = p_user_data;
if (!p_env->toc_init)
p_env->cdio->op.read_toc (p_user_data);
return p_env->toc_init ? p_env->i_first_track : CDIO_INVALID_TRACK;
}
/*!
Return the number of tracks in the current medium.
*/
track_t
get_num_tracks_generic(void *p_user_data)
{
generic_img_private_t *p_env = p_user_data;
if (!p_env->toc_init)
p_env->cdio->op.read_toc (p_user_data);
return p_env->toc_init ? p_env->i_tracks : CDIO_INVALID_TRACK;
}
void
set_cdtext_field_generic(void *user_data, track_t i_track,
track_t i_first_track,
cdtext_field_t e_field, const char *psz_value)
{
char **pp_field;
generic_img_private_t *env = user_data;
if( i_track == 0 )
pp_field = &(env->cdtext.field[e_field]);
else
pp_field = &(env->cdtext_track[i_track-i_first_track].field[e_field]);
*pp_field = strdup(psz_value);
}
/*!
Read CD-Text information for a CdIo object .
return true on success, false on error or CD-TEXT information does
not exist.
*/
bool
init_cdtext_generic (generic_img_private_t *p_env)
{
return scsi_mmc_init_cdtext_private( p_env,
p_env->cdio->op.run_scsi_mmc_cmd,
set_cdtext_field_generic
);
}

1206
lib/driver/_cdio_linux.c Normal file

File diff suppressed because it is too large Load Diff

1470
lib/driver/_cdio_osx.c Normal file

File diff suppressed because it is too large Load Diff

226
lib/driver/_cdio_stdio.c Normal file
View File

@@ -0,0 +1,226 @@
/*
$Id: _cdio_stdio.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif /*HAVE_UNISTD_H*/
#include <sys/stat.h>
#include <errno.h>
#include <cdio/logging.h>
#include <cdio/util.h>
#include "_cdio_stream.h"
#include "_cdio_stdio.h"
static const char _rcsid[] = "$Id: _cdio_stdio.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
#define CDIO_STDIO_BUFSIZE (128*1024)
typedef struct {
char *pathname;
FILE *fd;
char *fd_buf;
off_t st_size; /* used only for source */
} _UserData;
static int
_stdio_open (void *user_data)
{
_UserData *const ud = user_data;
if ((ud->fd = fopen (ud->pathname, "rb")))
{
ud->fd_buf = _cdio_malloc (CDIO_STDIO_BUFSIZE);
setvbuf (ud->fd, ud->fd_buf, _IOFBF, CDIO_STDIO_BUFSIZE);
}
return (ud->fd == NULL);
}
static int
_stdio_close(void *user_data)
{
_UserData *const ud = user_data;
if (fclose (ud->fd))
cdio_error ("fclose (): %s", strerror (errno));
ud->fd = NULL;
free (ud->fd_buf);
ud->fd_buf = NULL;
return 0;
}
static void
_stdio_free(void *user_data)
{
_UserData *const ud = user_data;
if (ud->pathname)
free(ud->pathname);
if (ud->fd) /* should be NULL anyway... */
_stdio_close(user_data);
free(ud);
}
/*!
Like fseek(3) and in fact may be the same.
This function sets the file position indicator for the stream
pointed to by stream. The new position, measured in bytes, is obtained
by adding offset bytes to the position specified by whence. If whence
is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to
the start of the file, the current position indicator, or end-of-file,
respectively. A successful call to the fseek function clears the end-
of-file indicator for the stream and undoes any effects of the
ungetc(3) function on the same stream.
RETURN VALUE
Upon successful completion, return 0,
Otherwise, -1 is returned and the global variable errno is set to indi-
cate the error.
*/
static long
_stdio_seek(void *user_data, long offset, int whence)
{
_UserData *const ud = user_data;
if ( (offset=fseek (ud->fd, offset, whence)) ) {
cdio_error ("fseek (): %s", strerror (errno));
}
return offset;
}
static long int
_stdio_stat(void *user_data)
{
const _UserData *const ud = user_data;
return ud->st_size;
}
/*!
Like fread(3) and in fact is about the same.
DESCRIPTION:
The function fread reads nmemb elements of data, each size bytes long,
from the stream pointed to by stream, storing them at the location
given by ptr.
RETURN VALUE:
return the number of items successfully read or written (i.e.,
not the number of characters). If an error occurs, or the
end-of-file is reached, the return value is a short item count
(or zero).
We do not distinguish between end-of-file and error, and callers
must use feof(3) and ferror(3) to determine which occurred.
*/
static long
_stdio_read(void *user_data, void *buf, long int count)
{
_UserData *const ud = user_data;
long read;
read = fread(buf, 1, count, ud->fd);
if (read != count)
{ /* fixme -- ferror/feof */
if (feof (ud->fd))
{
cdio_debug ("fread (): EOF encountered");
clearerr (ud->fd);
}
else if (ferror (ud->fd))
{
cdio_error ("fread (): %s", strerror (errno));
clearerr (ud->fd);
}
else
cdio_debug ("fread (): short read and no EOF?!?");
}
return read;
}
/*!
Deallocate resources assocaited with obj. After this obj is unusable.
*/
void
cdio_stdio_destroy(CdioDataSource *obj)
{
cdio_stream_destroy(obj);
}
CdioDataSource*
cdio_stdio_new(const char pathname[])
{
CdioDataSource *new_obj = NULL;
cdio_stream_io_functions funcs = { 0, };
_UserData *ud = NULL;
struct stat statbuf;
if (stat (pathname, &statbuf) == -1)
{
cdio_warn ("could not retrieve file info for `%s': %s",
pathname, strerror (errno));
return NULL;
}
ud = _cdio_malloc (sizeof (_UserData));
ud->pathname = strdup(pathname);
ud->st_size = statbuf.st_size; /* let's hope it doesn't change... */
funcs.open = _stdio_open;
funcs.seek = _stdio_seek;
funcs.stat = _stdio_stat;
funcs.read = _stdio_read;
funcs.close = _stdio_close;
funcs.free = _stdio_free;
new_obj = cdio_stream_new(ud, &funcs);
return new_obj;
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

52
lib/driver/_cdio_stdio.h Normal file
View File

@@ -0,0 +1,52 @@
/*
$Id: _cdio_stdio.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_STDIO_H__
#define __CDIO_STDIO_H__
#include "_cdio_stream.h"
/*!
Initialize a new stdio stream reading from pathname.
A pointer to the stream is returned or NULL if there was an error.
cdio_stream_free should be called on the returned value when you
don't need the stream any more. No other finalization is needed.
*/
CdioDataSource* cdio_stdio_new(const char pathname[]);
/*!
Deallocate resources assocaited with obj. After this obj is unusable.
*/
void cdio_stdio_destroy(CdioDataSource *obj);
#endif /* __CDIO_STREAM_STDIO_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

200
lib/driver/_cdio_stream.c Normal file
View File

@@ -0,0 +1,200 @@
/*
$Id: _cdio_stream.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2000, 2004 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "cdio_assert.h"
/* #define STREAM_DEBUG */
#include <cdio/logging.h>
#include <cdio/util.h>
#include "_cdio_stream.h"
static const char _rcsid[] = "$Id: _cdio_stream.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
/*
* DataSource implementations
*/
struct _CdioDataSource {
void* user_data;
cdio_stream_io_functions op;
int is_open;
long position;
};
/*
Open if not already open.
Return false if we hit an error. Errno should be set for that error.
*/
static bool
_cdio_stream_open_if_necessary(CdioDataSource *p_obj)
{
cdio_assert (p_obj != NULL);
if (!p_obj->is_open) {
if (p_obj->op.open(p_obj->user_data)) {
cdio_warn ("could not open input stream...");
return false;
} else {
cdio_debug ("opened source...");
p_obj->is_open = 1;
p_obj->position = 0;
}
}
return true;
}
/*!
Like 3 fseek and in fact may be the same.
This function sets the file position indicator for the stream
pointed to by stream. The new position, measured in bytes, is obtained
by adding offset bytes to the position specified by whence. If whence
is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to
the start of the file, the current position indicator, or end-of-file,
respectively. A successful call to the fseek function clears the end-
of-file indicator for the stream and undoes any effects of the
ungetc(3) function on the same stream.
RETURN VALUE
Upon successful completion, return 0,
Otherwise, -1 is returned and the global variable errno is set to indi-
cate the error.
*/
long
cdio_stream_seek(CdioDataSource* p_obj, long int offset, int whence)
{
cdio_assert (p_obj != NULL);
if (!_cdio_stream_open_if_necessary(p_obj))
/* errno is set by _cdio_stream_open_if necessary. */
return -1;
if (p_obj->position != offset) {
#ifdef STREAM_DEBUG
cdio_warn("had to reposition DataSource from %ld to %ld!", obj->position, offset);
#endif
p_obj->position = offset;
return p_obj->op.seek(p_obj->user_data, offset, whence);
}
return 0;
}
CdioDataSource*
cdio_stream_new(void *user_data, const cdio_stream_io_functions *funcs)
{
CdioDataSource *new_obj;
new_obj = _cdio_malloc (sizeof (CdioDataSource));
new_obj->user_data = user_data;
memcpy(&(new_obj->op), funcs, sizeof(cdio_stream_io_functions));
return new_obj;
}
/*!
Like fread(3) and in fact may be the same.
DESCRIPTION:
The function fread reads nmemb elements of data, each size bytes long,
from the stream pointed to by stream, storing them at the location
given by ptr.
RETURN VALUE:
return the number of items successfully read or written (i.e.,
not the number of characters). If an error occurs, or the
end-of-file is reached, the return value is a short item count
(or zero).
We do not distinguish between end-of-file and error, and callers
must use feof(3) and ferror(3) to determine which occurred.
*/
long
cdio_stream_read(CdioDataSource* obj, void *ptr, long size, long nmemb)
{
long read_bytes;
cdio_assert (obj != NULL);
if (!_cdio_stream_open_if_necessary(obj)) return 0;
read_bytes = obj->op.read(obj->user_data, ptr, size*nmemb);
obj->position += read_bytes;
return read_bytes;
}
/*!
Return whatever size of stream reports, I guess unit size is bytes.
On error return -1;
*/
long int
cdio_stream_stat(CdioDataSource* obj)
{
cdio_assert (obj != NULL);
if (!_cdio_stream_open_if_necessary(obj)) return -1;
return obj->op.stat(obj->user_data);
}
void
cdio_stream_close(CdioDataSource* obj)
{
cdio_assert (obj != NULL);
if (obj->is_open) {
cdio_debug ("closed source...");
obj->op.close(obj->user_data);
obj->is_open = 0;
obj->position = 0;
}
}
void
cdio_stream_destroy(CdioDataSource* obj)
{
cdio_assert (obj != NULL);
cdio_stream_close(obj);
obj->op.free(obj->user_data);
free(obj);
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

127
lib/driver/_cdio_stream.h Normal file
View File

@@ -0,0 +1,127 @@
/*
$Id: _cdio_stream.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_STREAM_H__
#define __CDIO_STREAM_H__
#include <cdio/types.h>
#include "cdio_private.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* typedef'ed IO functions prototypes */
typedef int(*cdio_data_open_t)(void *user_data);
typedef long(*cdio_data_read_t)(void *user_data, void *buf, long count);
typedef long(*cdio_data_seek_t)(void *user_data, long offset, int whence);
typedef long(*cdio_data_stat_t)(void *user_data);
typedef int(*cdio_data_close_t)(void *user_data);
typedef void(*cdio_data_free_t)(void *user_data);
/* abstract data source */
typedef struct {
cdio_data_open_t open;
cdio_data_seek_t seek;
cdio_data_stat_t stat;
cdio_data_read_t read;
cdio_data_close_t close;
cdio_data_free_t free;
} cdio_stream_io_functions;
CdioDataSource*
cdio_stream_new(void *user_data, const cdio_stream_io_functions *funcs);
/*!
Like fread(3) and in fact may be the same.
DESCRIPTION:
The function fread reads nmemb elements of data, each size bytes long,
from the stream pointed to by stream, storing them at the location
given by ptr.
RETURN VALUE:
return the number of items successfully read or written (i.e.,
not the number of characters). If an error occurs, or the
end-of-file is reached, the return value is a short item count
(or zero).
We do not distinguish between end-of-file and error, and callers
must use feof(3) and ferror(3) to determine which occurred.
*/
long
cdio_stream_read(CdioDataSource* obj, void *ptr, long size, long nmemb);
/*!
Like fseek(3) and in fact may be the same.
This function sets the file position indicator for the stream
pointed to by stream. The new position, measured in bytes, is obtained
by adding offset bytes to the position specified by whence. If whence
is set to SEEK_SET, SEEK_CUR, or SEEK_END, the offset is relative to
the start of the file, the current position indicator, or end-of-file,
respectively. A successful call to the fseek function clears the end-
of-file indicator for the stream and undoes any effects of the
ungetc(3) function on the same stream.
RETURN VALUE
Upon successful completion, return 0,
Otherwise, -1 is returned and the global variable errno is set to indi-
cate the error.
*/
long int cdio_stream_seek(CdioDataSource* obj, long offset, int whence);
/*!
Return whatever size of stream reports, I guess unit size is bytes.
On error return -1;
*/
long int cdio_stream_stat(CdioDataSource* obj);
/*!
Deallocate resources assocaited with obj. After this obj is unusable.
*/
void cdio_stream_destroy(CdioDataSource* obj);
void cdio_stream_close(CdioDataSource* obj);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __CDIO_STREAM_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

927
lib/driver/_cdio_sunos.c Normal file
View File

@@ -0,0 +1,927 @@
/*
$Id: _cdio_sunos.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2002, 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <cdio/logging.h>
#include <cdio/sector.h>
#include <cdio/util.h>
#include <cdio/scsi_mmc.h>
#include "cdio_assert.h"
#include "cdio_private.h"
#define DEFAULT_CDIO_DEVICE "/vol/dev/aliases/cdrom0"
#ifdef HAVE_SOLARIS_CDROM
static const char _rcsid[] = "$Id: _cdio_sunos.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
#ifdef HAVE_GLOB_H
#include <glob.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef HAVE_SYS_CDIO_H
# include <sys/cdio.h> /* CDIOCALLOW etc... */
#else
#error "You need <sys/cdio.h> to have CDROM support"
#endif
#include <sys/dkio.h>
#include <sys/scsi/generic/commands.h>
#include <sys/scsi/impl/uscsi.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include "cdtext_private.h"
/* not defined in dkio.h yet */
#define DK_DVDRW 0x13
/* reader */
typedef enum {
_AM_NONE,
_AM_SUN_CTRL_ATAPI,
_AM_SUN_CTRL_SCSI
#if FINISHED
_AM_READ_CD,
_AM_READ_10
#endif
} 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;
/* Some of the more OS specific things. */
/* Entry info for each track, add 1 for leadout. */
struct cdrom_tocentry tocent[CDIO_CD_MAX_TRACKS+1];
/* Track information */
struct cdrom_tochdr tochdr;
} _img_private_t;
static track_format_t get_track_format_solaris(void *p_user_data,
track_t i_track);
static access_mode_t
str_to_access_mode_sunos(const char *psz_access_mode)
{
const access_mode_t default_access_mode = _AM_SUN_CTRL_SCSI;
if (NULL==psz_access_mode) return default_access_mode;
if (!strcmp(psz_access_mode, "ATAPI"))
return _AM_SUN_CTRL_SCSI; /* force ATAPI to be SCSI */
else if (!strcmp(psz_access_mode, "SCSI"))
return _AM_SUN_CTRL_SCSI;
else {
cdio_warn ("unknown access type: %s. Default SCSI used.",
psz_access_mode);
return default_access_mode;
}
}
/*!
Initialize CD device.
*/
static bool
init_solaris (_img_private_t *p_env)
{
if (!cdio_generic_init(p_env)) return false;
p_env->access_mode = _AM_SUN_CTRL_SCSI;
return true;
}
/*!
Run a SCSI MMC command.
p_user_data internal CD structure.
i_timeout_ms time in milliseconds we will wait for the command
to complete.
i_cdb Size of p_cdb
p_cdb CDB bytes.
e_direction direction the transfer is to go.
i_buf Size of buffer
p_buf Buffer for data, both sending and receiving
Return 0 if no error.
*/
static int
run_scsi_cmd_solaris( const void *p_user_data, unsigned int i_timeout_ms,
unsigned int i_cdb, const scsi_mmc_cdb_t *p_cdb,
scsi_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf )
{
const _img_private_t *p_env = p_user_data;
struct uscsi_cmd cgc;
memset (&cgc, 0, sizeof (struct uscsi_cmd));
cgc.uscsi_cdb = (caddr_t) p_cdb;
cgc.uscsi_flags = SCSI_MMC_DATA_READ == e_direction ?
USCSI_READ : USCSI_WRITE;
cgc.uscsi_timeout = msecs2secs(i_timeout_ms);
cgc.uscsi_bufaddr = p_buf;
cgc.uscsi_buflen = i_buf;
cgc.uscsi_cdblen = i_cdb;
return ioctl(p_env->gen.fd, USCSICMD, &cgc);
}
/*!
Reads audio sectors from CD device into data starting from lsn.
Returns 0 if no error.
May have to check size of nblocks. There may be a limit that
can be read in one go, e.g. 25 blocks.
*/
static int
_read_audio_sectors_solaris (void *p_user_data, void *data, lsn_t lsn,
unsigned int nblocks)
{
struct cdrom_msf solaris_msf;
msf_t _msf;
struct cdrom_cdda cdda;
_img_private_t *p_env = p_user_data;
cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf);
solaris_msf.cdmsf_min0 = cdio_from_bcd8(_msf.m);
solaris_msf.cdmsf_sec0 = cdio_from_bcd8(_msf.s);
solaris_msf.cdmsf_frame0 = cdio_from_bcd8(_msf.f);
if (p_env->gen.ioctls_debugged == 75)
cdio_debug ("only displaying every 75th ioctl from now on");
if (p_env->gen.ioctls_debugged == 30 * 75)
cdio_debug ("only displaying every 30*75th ioctl from now on");
if (p_env->gen.ioctls_debugged < 75
|| (p_env->gen.ioctls_debugged < (30 * 75)
&& p_env->gen.ioctls_debugged % 75 == 0)
|| p_env->gen.ioctls_debugged % (30 * 75) == 0)
cdio_debug ("reading %d", lsn);
p_env->gen.ioctls_debugged++;
cdda.cdda_addr = lsn;
cdda.cdda_length = nblocks;
cdda.cdda_data = (caddr_t) data;
cdda.cdda_subcode = CDROM_DA_NO_SUBCODE;
if (ioctl (p_env->gen.fd, CDROMCDDA, &cdda) == -1) {
perror ("ioctl(..,CDROMCDDA,..)");
return 1;
/* exit (EXIT_FAILURE); */
}
return 0;
}
/*!
Reads a single mode1 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
static int
_read_mode1_sector_solaris (void *env, void *data, lsn_t lsn,
bool b_form2)
{
#if FIXED
do something here.
#else
return cdio_generic_read_form1_sector(env, data, lsn);
#endif
}
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
static int
_read_mode1_sectors_solaris (void *p_user_data, void *p_data, lsn_t lsn,
bool b_form2, unsigned int nblocks)
{
_img_private_t *p_env = p_user_data;
unsigned int i;
int retval;
unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
for (i = 0; i < nblocks; i++) {
if ( (retval = _read_mode1_sector_solaris (p_env,
((char *)p_data) + (blocksize * i),
lsn + i, b_form2)) )
return retval;
}
return 0;
}
/*!
Reads a single mode2 sector from cd device into data starting from lsn.
Returns 0 if no error.
*/
static int
_read_mode2_sector_solaris (void *p_user_data, void *p_data, lsn_t lsn,
bool b_form2)
{
char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, };
struct cdrom_msf solaris_msf;
msf_t _msf;
int offset = 0;
struct cdrom_cdxa cd_read;
_img_private_t *p_env = p_user_data;
cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf);
solaris_msf.cdmsf_min0 = cdio_from_bcd8(_msf.m);
solaris_msf.cdmsf_sec0 = cdio_from_bcd8(_msf.s);
solaris_msf.cdmsf_frame0 = cdio_from_bcd8(_msf.f);
if (p_env->gen.ioctls_debugged == 75)
cdio_debug ("only displaying every 75th ioctl from now on");
if (p_env->gen.ioctls_debugged == 30 * 75)
cdio_debug ("only displaying every 30*75th ioctl from now on");
if (p_env->gen.ioctls_debugged < 75
|| (p_env->gen.ioctls_debugged < (30 * 75)
&& p_env->gen.ioctls_debugged % 75 == 0)
|| p_env->gen.ioctls_debugged % (30 * 75) == 0)
cdio_debug ("reading %2.2d:%2.2d:%2.2d",
solaris_msf.cdmsf_min0, solaris_msf.cdmsf_sec0,
solaris_msf.cdmsf_frame0);
p_env->gen.ioctls_debugged++;
/* Using CDROMXA ioctl will actually use the same uscsi command
* as ATAPI, except we don't need to be root
*/
offset = CDIO_CD_XA_SYNC_HEADER;
cd_read.cdxa_addr = lsn;
cd_read.cdxa_data = buf;
cd_read.cdxa_length = 1;
cd_read.cdxa_format = CDROM_XA_SECTOR_DATA;
if (ioctl (p_env->gen.fd, CDROMCDXA, &cd_read) == -1) {
perror ("ioctl(..,CDROMCDXA,..)");
return 1;
/* exit (EXIT_FAILURE); */
}
if (b_form2)
memcpy (p_data, buf + (offset-CDIO_CD_SUBHEADER_SIZE), M2RAW_SECTOR_SIZE);
else
memcpy (((char *)p_data), buf + offset, CDIO_CD_FRAMESIZE);
return 0;
}
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
static int
_read_mode2_sectors_solaris (void *p_user_data, void *data, lsn_t lsn,
bool b_form2, unsigned int nblocks)
{
_img_private_t *env = p_user_data;
unsigned int i;
int retval;
unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
for (i = 0; i < nblocks; i++) {
if ( (retval = _read_mode2_sector_solaris (env,
((char *)data) + (blocksize * i),
lsn + i, b_form2)) )
return retval;
}
return 0;
}
/*!
Return the size of the CD in logical block address (LBA) units.
*/
static uint32_t
_cdio_stat_size (void *p_user_data)
{
_img_private_t *env = p_user_data;
struct cdrom_tocentry tocent;
uint32_t size;
tocent.cdte_track = CDIO_CDROM_LEADOUT_TRACK;
tocent.cdte_format = CDIO_CDROM_LBA;
if (ioctl (env->gen.fd, CDROMREADTOCENTRY, &tocent) == -1)
{
perror ("ioctl(CDROMREADTOCENTRY)");
exit (EXIT_FAILURE);
}
size = tocent.cdte_addr.lba;
return size;
}
/*!
Set the arg "key" with "value" in the source device.
Currently "source" and "access-mode" are valid keys.
"source" sets the source device in I/O operations
"access-mode" sets the the method of CD access
0 is returned if no error was found, and nonzero if there as an error.
*/
static int
_set_arg_solaris (void *p_user_data, const char key[], const char value[])
{
_img_private_t *env = p_user_data;
if (!strcmp (key, "source"))
{
if (!value)
return -2;
free (env->gen.source_name);
env->gen.source_name = strdup (value);
}
else if (!strcmp (key, "access-mode"))
{
env->access_mode = str_to_access_mode_sunos(key);
}
else
return -1;
return 0;
}
/*!
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_solaris (void *p_user_data)
{
_img_private_t *p_env = p_user_data;
int i;
/* read TOC header */
if ( ioctl(p_env->gen.fd, CDROMREADTOCHDR, &p_env->tochdr) == -1 ) {
cdio_warn("%s: %s\n",
"error in ioctl CDROMREADTOCHDR", strerror(errno));
return false;
}
p_env->gen.i_first_track = p_env->tochdr.cdth_trk0;
p_env->gen.i_tracks = p_env->tochdr.cdth_trk1;
/* read individual tracks */
for (i=p_env->gen.i_first_track; i<=p_env->gen.i_tracks; i++) {
p_env->tocent[i-1].cdte_track = i;
p_env->tocent[i-1].cdte_format = CDIO_CDROM_MSF;
if ( ioctl(p_env->gen.fd, CDROMREADTOCENTRY, &p_env->tocent[i-1]) == -1 ) {
cdio_warn("%s %d: %s\n",
"error in ioctl CDROMREADTOCENTRY for track",
i, strerror(errno));
return false;
}
}
/* read the lead-out track */
p_env->tocent[p_env->tochdr.cdth_trk1].cdte_track = CDIO_CDROM_LEADOUT_TRACK;
p_env->tocent[p_env->tochdr.cdth_trk1].cdte_format = CDIO_CDROM_MSF;
if (ioctl(p_env->gen.fd, CDROMREADTOCENTRY,
&p_env->tocent[p_env->tochdr.cdth_trk1]) == -1 ) {
cdio_warn("%s: %s\n",
"error in ioctl CDROMREADTOCENTRY for lead-out",
strerror(errno));
return false;
}
p_env->gen.toc_init = true;
return true;
}
/*!
Eject media in CD drive. If successful, as a side effect we
also free obj.
*/
static int
eject_media_solaris (void *p_user_data) {
_img_private_t *env = p_user_data;
int ret;
close(env->gen.fd);
env->gen.fd = -1;
if (env->gen.fd > -1) {
if ((ret = ioctl(env->gen.fd, CDROMEJECT)) != 0) {
cdio_generic_free((void *) env);
cdio_warn ("CDROMEJECT failed: %s\n", strerror(errno));
return 1;
} else {
return 0;
}
}
return 2;
}
static void *
_cdio_malloc_and_zero(size_t size) {
void *ptr;
if( !size ) size++;
if((ptr = malloc(size)) == NULL) {
cdio_warn("malloc() failed: %s", strerror(errno));
return NULL;
}
memset(ptr, 0, size);
return ptr;
}
/*!
Return the value associated with the key "arg".
*/
static const char *
get_arg_solaris (void *p_user_data, const char key[])
{
_img_private_t *env = p_user_data;
if (!strcmp (key, "source")) {
return env->gen.source_name;
} else if (!strcmp (key, "access-mode")) {
switch (env->access_mode) {
case _AM_SUN_CTRL_ATAPI:
return "ATAPI";
case _AM_SUN_CTRL_SCSI:
return "SCSI";
case _AM_NONE:
return "no access method";
}
}
return NULL;
}
/*!
Return a string containing the default CD device if none is specified.
*/
char *
cdio_get_default_device_solaris(void)
{
char *volume_device;
char *volume_name;
char *volume_action;
char *device;
struct stat stb;
if ((volume_device = getenv("VOLUME_DEVICE")) != NULL &&
(volume_name = getenv("VOLUME_NAME")) != NULL &&
(volume_action = getenv("VOLUME_ACTION")) != NULL &&
strcmp(volume_action, "insert") == 0) {
device = _cdio_malloc_and_zero(strlen(volume_device)
+ strlen(volume_name) + 2);
if (device == NULL)
return strdup(DEFAULT_CDIO_DEVICE);
sprintf(device, "%s/%s", volume_device, volume_name);
if (stat(device, &stb) != 0 || !S_ISCHR(stb.st_mode)) {
free(device);
return strdup(DEFAULT_CDIO_DEVICE);
}
return device;
}
/* Check if it could be a Solaris media*/
if((stat(DEFAULT_CDIO_DEVICE, &stb) == 0) && S_ISDIR(stb.st_mode)) {
device = _cdio_malloc_and_zero(strlen(DEFAULT_CDIO_DEVICE) + 4);
sprintf(device, "%s/s0", DEFAULT_CDIO_DEVICE);
return device;
}
return strdup(DEFAULT_CDIO_DEVICE);
}
/*!
Get disc type associated with cd object.
*/
static discmode_t
get_discmode_solaris (void *p_user_data)
{
_img_private_t *p_env = p_user_data;
track_t i_track;
discmode_t discmode=CDIO_DISC_MODE_NO_INFO;
struct dk_minfo media;
int ret;
/* Get the media info */
if((ret = ioctl(p_env->gen.fd, DKIOCGMEDIAINFO, &media)) != 0) {
cdio_warn ("DKIOCGMEDIAINFO failed: %s\n", strerror(errno));
return CDIO_DISC_MODE_NO_INFO;
}
switch(media.dki_media_type) {
case DK_CDROM:
case DK_CDR:
case DK_CDRW:
/* Do cdrom detection */
break;
case DK_DVDROM: return CDIO_DISC_MODE_DVD_ROM;
case DK_DVDR: discmode = CDIO_DISC_MODE_DVD_R;
break;
case DK_DVDRAM: discmode = CDIO_DISC_MODE_DVD_RAM;
break;
case DK_DVDRW:
case DK_DVDRW+1: discmode = CDIO_DISC_MODE_DVD_RW;
break;
default: /* no valid match */
return CDIO_DISC_MODE_NO_INFO;
}
/*
GNU/Linux ioctl(.., CDROM_DISC_STATUS) does not return "CD DATA
Form 2" for SVCD's even though they are are form 2.
Issue a SCSI MMC-2 FULL TOC command first to try get more
accurate information.
*/
discmode = scsi_mmc_get_discmode(p_env->gen.cdio);
if (CDIO_DISC_MODE_NO_INFO != discmode)
return discmode;
if((discmode == CDIO_DISC_MODE_DVD_RAM ||
discmode == CDIO_DISC_MODE_DVD_RW ||
discmode == CDIO_DISC_MODE_DVD_R)) {
/* Fallback to uscsi if we can */
if(geteuid() == 0)
return get_discmode_solaris(p_user_data);
return discmode;
}
if (!p_env->gen.toc_init)
read_toc_solaris (p_env);
if (!p_env->gen.toc_init)
return CDIO_DISC_MODE_NO_INFO;
for (i_track = p_env->gen.i_first_track;
i_track < p_env->gen.i_first_track + p_env->tochdr.cdth_trk1 ;
i_track ++) {
track_format_t track_fmt=get_track_format_solaris(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;
}
/*!
Get format of track.
*/
static track_format_t
get_track_format_solaris(void *p_user_data, track_t i_track)
{
_img_private_t *p_env = p_user_data;
if ( !p_env ) return TRACK_FORMAT_ERROR;
if (!p_env->gen.init) init_solaris(p_env);
if (!p_env->gen.toc_init) read_toc_solaris (p_user_data) ;
if ( (i_track > p_env->gen.i_tracks+p_env->gen.i_first_track)
|| i_track < p_env->gen.i_first_track)
return TRACK_FORMAT_ERROR;
i_track -= p_env->gen.i_first_track;
/* This is pretty much copied from the "badly broken" cdrom_count_tracks
in linux/cdrom.c.
*/
if (p_env->tocent[i_track].cdte_ctrl & CDROM_DATA_TRACK) {
if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_CDI_TRACK)
return TRACK_FORMAT_CDI;
else if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_XA_TRACK)
return TRACK_FORMAT_XA;
else
return TRACK_FORMAT_DATA;
} else
return TRACK_FORMAT_AUDIO;
}
/*!
Return true if we have XA data (green, mode2 form1) or
XA data (green, mode2 form2). That is track begins:
sync - header - subheader
12 4 - 8
FIXME: there's gotta be a better design for this and get_track_format?
*/
static bool
_cdio_get_track_green(void *p_user_data, track_t i_track)
{
_img_private_t *p_env = p_user_data;
if ( !p_env ) return false;
if (!p_env->gen.init) init_solaris(p_env);
if (!p_env->gen.toc_init) read_toc_solaris (p_env) ;
if (i_track >= p_env->gen.i_tracks+p_env->gen.i_first_track
|| i_track < p_env->gen.i_first_track)
return false;
i_track -= p_env->gen.i_first_track;
/* FIXME: Dunno if this is the right way, but it's what
I was using in cd-info for a while.
*/
return ((p_env->tocent[i_track].cdte_ctrl & 2) != 0);
}
/*!
Return the starting MSF (minutes/secs/frames) for track number
track_num in obj. Track numbers usually start at something
greater than 0, usually 1.
The "leadout" track is specified either by
using track_num LEADOUT_TRACK or the total tracks+1.
False is returned if there is no entry.
*/
static bool
_cdio_get_track_msf(void *p_user_data, track_t i_track, msf_t *msf)
{
_img_private_t *p_env = p_user_data;
if (NULL == msf) return false;
if (!p_env->gen.init) init_solaris(p_env);
if (!p_env->gen.toc_init) read_toc_solaris (p_env) ;
if (i_track == CDIO_CDROM_LEADOUT_TRACK)
i_track = p_env->gen.i_tracks + p_env->gen.i_first_track;
if (i_track > (p_env->gen.i_tracks+p_env->gen.i_first_track)
|| i_track < p_env->gen.i_first_track) {
return false;
} else {
struct cdrom_tocentry *msf0 = &p_env->tocent[i_track-1];
msf->m = cdio_to_bcd8(msf0->cdte_addr.msf.minute);
msf->s = cdio_to_bcd8(msf0->cdte_addr.msf.second);
msf->f = cdio_to_bcd8(msf0->cdte_addr.msf.frame);
return true;
}
}
#else
/*!
Return a string containing the default VCD device if none is specified.
*/
char *
cdio_get_default_device_solaris(void)
{
return strdup(DEFAULT_CDIO_DEVICE);
}
#endif /* HAVE_SOLARIS_CDROM */
/*!
Return an array of strings giving possible CD devices.
*/
char **
cdio_get_devices_solaris (void)
{
#ifndef HAVE_SOLARIS_CDROM
return NULL;
#else
char volpath[256];
struct stat st;
char **drives = NULL;
unsigned int i_files=0;
#ifdef HAVE_GLOB_H
unsigned int i;
glob_t globbuf;
globbuf.gl_offs = 0;
glob("/vol/dev/aliases/cdrom*", GLOB_DOOFFS, NULL, &globbuf);
for (i=0; i<globbuf.gl_pathc; i++) {
if(stat(globbuf.gl_pathv[i], &st) < 0)
continue;
/* Check if this is a directory, if so it's probably Solaris media */
if(S_ISDIR(st.st_mode)) {
sprintf(volpath, "%s/s0", globbuf.gl_pathv[i]);
if(stat(volpath, &st) == 0)
cdio_add_device_list(&drives, volpath, &i_files);
}else
cdio_add_device_list(&drives, globbuf.gl_pathv[i], &i_files);
}
globfree(&globbuf);
#else
if(stat(DEFAULT_CDIO_DEVICE, &st) == 0) {
/* Check if this is a directory, if so it's probably Solaris media */
if(S_ISDIR(st.st_mode)) {
sprintf(volpath, "%s/s0", DEFAULT_CDIO_DEVICE);
if(stat(volpath, &st) == 0)
cdio_add_device_list(&drives, volpath, &i_files);
}else
cdio_add_device_list(&drives, DEFAULT_CDIO_DEVICE, &i_files);
}
#endif /*HAVE_GLOB_H*/
cdio_add_device_list(&drives, NULL, &i_files);
return drives;
#endif /*HAVE_SOLARIS_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 *
cdio_open_solaris (const char *psz_source_name)
{
return cdio_open_am_solaris(psz_source_name, NULL);
}
/*!
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 *
cdio_open_am_solaris (const char *psz_orig_source, const char *access_mode)
{
#ifdef HAVE_SOLARIS_CDROM
CdIo *ret;
_img_private_t *_data;
char *psz_source;
cdio_funcs _funcs;
_funcs.eject_media = eject_media_solaris;
_funcs.free = cdio_generic_free;
_funcs.get_arg = get_arg_solaris;
_funcs.get_cdtext = get_cdtext_generic;
_funcs.get_default_device = cdio_get_default_device_solaris;
_funcs.get_devices = cdio_get_devices_solaris;
_funcs.get_discmode = get_discmode_solaris;
_funcs.get_drive_cap = scsi_mmc_get_drive_cap_generic;
_funcs.get_first_track_num= get_first_track_num_generic;
_funcs.get_hwinfo = NULL;
_funcs.get_mcn = scsi_mmc_get_mcn_generic,
_funcs.get_num_tracks = get_num_tracks_generic;
_funcs.get_track_format = get_track_format_solaris;
_funcs.get_track_green = _cdio_get_track_green;
_funcs.get_track_lba = NULL; /* This could be implemented if need be. */
_funcs.get_track_msf = _cdio_get_track_msf;
_funcs.lseek = cdio_generic_lseek;
_funcs.read = cdio_generic_read;
_funcs.read_audio_sectors = _read_audio_sectors_solaris;
_funcs.read_mode1_sector = _read_mode1_sector_solaris;
_funcs.read_mode1_sectors = _read_mode1_sectors_solaris;
_funcs.read_mode2_sector = _read_mode2_sector_solaris;
_funcs.read_mode2_sectors = _read_mode2_sectors_solaris;
_funcs.read_toc = read_toc_solaris;
_funcs.run_scsi_mmc_cmd = run_scsi_cmd_solaris;
_funcs.stat_size = _cdio_stat_size;
_funcs.set_arg = _set_arg_solaris;
_data = _cdio_malloc (sizeof (_img_private_t));
_data->access_mode = _AM_SUN_CTRL_SCSI;
_data->gen.init = false;
_data->gen.fd = -1;
_data->gen.toc_init = false;
_data->gen.b_cdtext_init = false;
_data->gen.b_cdtext_error = false;
if (NULL == psz_orig_source) {
psz_source = cdio_get_default_device_solaris();
if (NULL == psz_source) return NULL;
_set_arg_solaris(_data, "source", psz_source);
free(psz_source);
} else {
if (cdio_is_device_generic(psz_orig_source))
_set_arg_solaris(_data, "source", psz_orig_source);
else {
/* The below would be okay if all device drivers worked this way. */
#if 0
cdio_info ("source %s is not a device", psz_orig_source);
#endif
return NULL;
}
}
ret = cdio_new ( (void *) _data, &_funcs );
if (ret == NULL) return NULL;
if (init_solaris(_data))
return ret;
else {
cdio_generic_free (_data);
return NULL;
}
#else
return NULL;
#endif /* HAVE_SOLARIS_CDROM */
}
bool
cdio_have_solaris (void)
{
#ifdef HAVE_SOLARIS_CDROM
return true;
#else
return false;
#endif /* HAVE_SOLARIS_CDROM */
}

358
lib/driver/cd_types.c Normal file
View File

@@ -0,0 +1,358 @@
/*
$Id: cd_types.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
This tries to determine what kind of CD-image or filesystems on a
track we've got.
*/
#include "config.h"
#ifdef HAVE_STDIO_H
#include <stdio.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <cdio/cdio.h>
#include <cdio/iso9660.h>
#include <cdio/logging.h>
#include <cdio/util.h>
#include <cdio/cd_types.h>
/*
Subject: -65- How can I read an IRIX (EFS) CD-ROM on a machine which
doesn't use EFS?
Date: 18 Jun 1995 00:00:01 EST
You want 'efslook', at
ftp://viz.tamu.edu/pub/sgi/software/efslook.tar.gz.
and
! Robert E. Seastrom <rs@access4.digex.net>'s software (with source
! code) for using an SGI CD-ROM on a Macintosh is at
! ftp://bifrost.seastrom.com/pub/mac/CDROM-Jumpstart.sit151.hqx.
*/
static char buffer[6][CDIO_CD_FRAMESIZE_RAW]; /* for CD-Data */
/* Some interesting sector numbers stored in the above buffer. */
#define ISO_SUPERBLOCK_SECTOR 16 /* buffer[0] */
#define UFS_SUPERBLOCK_SECTOR 4 /* buffer[2] */
#define BOOT_SECTOR 17 /* buffer[3] */
#define VCD_INFO_SECTOR 150 /* buffer[4] */
#define XISO_SECTOR 32 /* buffer[4] */
#define UDFX_SECTOR 32 /* buffer[4] */
#define UDF_ANCHOR_SECTOR 256 /* buffer[5] */
typedef struct signature
{
unsigned int buf_num;
unsigned int offset;
const char *sig_str;
const char *description;
} signature_t;
static signature_t sigs[] =
{
/*buffer[x] off look for description */
{0, 0, "MICROSOFT*XBOX*MEDIA", "XBOX CD"},
{0, 1, "BEA01", "UDF"},
{0, 1, ISO_STANDARD_ID, "ISO 9660"},
{0, 1, "CD-I", "CD-I"},
{0, 8, "CDTV", "CDTV"},
{0, 8, "CD-RTOS", "CD-RTOS"},
{0, 9, "CDROM", "HIGH SIERRA"},
{0, 16, "CD-BRIDGE", "BRIDGE"},
{0, ISO_XA_MARKER_OFFSET, ISO_XA_MARKER_STRING, "XA"},
{1, 64, "PPPPHHHHOOOOTTTTOOOO____CCCCDDDD", "PHOTO CD"},
{1, 0x438, "\x53\xef", "EXT2 FS"},
{2, 1372, "\x54\x19\x01\x0", "UFS"},
{3, 7, "EL TORITO", "BOOTABLE"},
{4, 0, "VIDEO_CD", "VIDEO CD"},
{4, 0, "SUPERVCD", "SVCD or Chaoji VCD"},
{ 0 }
};
/* The below index into the above sigs array. Make sure things match. */
#define INDEX_XISO 0 /* Microsoft X-BOX filesystem */
#define INDEX_UDF 1
#define INDEX_ISOFS 2
#define INDEX_CD_I 3
#define INDEX_CDTV 4
#define INDEX_CD_RTOS 5
#define INDEX_HS 6
#define INDEX_BRIDGE 7
#define INDEX_XA 8
#define INDEX_PHOTO_CD 9
#define INDEX_EXT2 10
#define INDEX_UFS 11
#define INDEX_BOOTABLE 12
#define INDEX_VIDEO_CD 13 /* Video CD */
#define INDEX_SVCD 14 /* CVD *or* SVCD */
/*
Read a particular block into the global array to be used for further
analysis later.
*/
static int
_cdio_read_block(const CdIo *cdio, int superblock, uint32_t offset,
uint8_t bufnum, track_t i_track)
{
unsigned int track_sec_count = cdio_get_track_sec_count(cdio, i_track);
memset(buffer[bufnum], 0, CDIO_CD_FRAMESIZE);
if ( track_sec_count < superblock) {
cdio_debug("reading block %u skipped track %d has only %u sectors\n",
superblock, i_track, track_sec_count);
return -1;
}
cdio_debug("about to read sector %lu\n",
(long unsigned int) offset+superblock);
if (cdio_get_track_green(cdio, i_track)) {
if (0 > cdio_read_mode2_sector(cdio, buffer[bufnum],
offset+superblock, false))
return -1;
} else {
if (0 > cdio_read_mode1_sector(cdio, buffer[bufnum],
offset+superblock, false))
return -1;
}
return 0;
}
/*
Return true if the previously read-in buffer contains a "signature" that
matches index "num".
*/
static bool
_cdio_is_it(int num)
{
signature_t *sigp=&sigs[num];
int len=strlen(sigp->sig_str);
/* TODO: check that num < largest sig. */
return 0 == memcmp(&buffer[sigp->buf_num][sigp->offset], sigp->sig_str, len);
}
static int
_cdio_is_hfs(void)
{
return (0 == memcmp(&buffer[1][512],"PM",2)) ||
(0 == memcmp(&buffer[1][512],"TS",2)) ||
(0 == memcmp(&buffer[1][1024], "BD",2));
}
static int
_cdio_is_3do(void)
{
return (0 == memcmp(&buffer[1][0],"\x01\x5a\x5a\x5a\x5a\x5a\x01", 7)) &&
(0 == memcmp(&buffer[1][40], "CD-ROM", 6));
}
static int
_cdio_is_joliet(void)
{
return 2 == buffer[3][0] && buffer[3][88] == 0x25 && buffer[3][89] == 0x2f;
}
static int
_cdio_is_UDF(void)
{
return 2 == ((uint16_t)buffer[5][0] | ((uint16_t)buffer[5][1] << 8));
}
/* ISO 9660 volume space in M2F1_SECTOR_SIZE byte units */
static int
_cdio_get_iso9660_fs_sec_count(void)
{
return ((buffer[0][80] & 0xff) |
((buffer[0][81] & 0xff) << 8) |
((buffer[0][82] & 0xff) << 16) |
((buffer[0][83] & 0xff) << 24));
}
static int
_cdio_get_joliet_level( void )
{
switch (buffer[3][90]) {
case 0x40: return 1;
case 0x43: return 2;
case 0x45: return 3;
}
return 0;
}
/*
Try to determine what kind of CD-image and/or filesystem we
have at track i_track. Return information about the CD image
is returned in cdio_analysis and the return value.
*/
cdio_fs_anal_t
cdio_guess_cd_type(const CdIo *cdio, int start_session, track_t i_track,
/*out*/ cdio_iso_analysis_t *iso_analysis)
{
int ret = CDIO_FS_UNKNOWN;
bool sector0_read_ok;
if (TRACK_FORMAT_AUDIO == cdio_get_track_format(cdio, i_track))
return CDIO_FS_AUDIO;
if ( _cdio_read_block(cdio, ISO_PVD_SECTOR, start_session,
0, i_track) < 0 )
return CDIO_FS_UNKNOWN;
if ( _cdio_is_it(INDEX_XISO) )
return CDIO_FS_ANAL_XISO;
if (_cdio_read_block(cdio, ISO_SUPERBLOCK_SECTOR, start_session, 0,
i_track) < 0)
return ret;
if ( _cdio_is_it(INDEX_UDF) ) {
/* Detect UDF version
Test if we have a valid version of UDF the xbox can read natively */
if (_cdio_read_block(cdio, 35, start_session, 5, i_track) < 0)
return CDIO_FS_UNKNOWN;
iso_analysis->UDFVerMinor=(unsigned int)buffer[5][240];
iso_analysis->UDFVerMajor=(unsigned int)buffer[5][241];
/* Read disc label */
if (_cdio_read_block(cdio, 32, start_session, 5, i_track) < 0)
return CDIO_FS_UDF;
strncpy(iso_analysis->iso_label, buffer[5]+25, 33);
iso_analysis->iso_label[32] = '\0';
return CDIO_FS_UDF;
}
/* We have something that smells of a filesystem. */
if (_cdio_is_it(INDEX_CD_I) && _cdio_is_it(INDEX_CD_RTOS)
&& !_cdio_is_it(INDEX_BRIDGE) && !_cdio_is_it(INDEX_XA)) {
return CDIO_FS_INTERACTIVE;
} else {
/* read sector 0 ONLY, when NO greenbook CD-I !!!! */
sector0_read_ok =
_cdio_read_block(cdio, 0, start_session, 1, i_track) == 0;
if (_cdio_is_it(INDEX_HS))
ret |= CDIO_FS_HIGH_SIERRA;
else if (_cdio_is_it(INDEX_ISOFS)) {
if (_cdio_is_it(INDEX_CD_RTOS) && _cdio_is_it(INDEX_BRIDGE))
ret = CDIO_FS_ISO_9660_INTERACTIVE;
else if (_cdio_is_hfs())
ret = CDIO_FS_ISO_HFS;
else
ret = CDIO_FS_ISO_9660;
iso_analysis->isofs_size = _cdio_get_iso9660_fs_sec_count();
strncpy(iso_analysis->iso_label, buffer[0]+40,33);
iso_analysis->iso_label[32] = '\0';
if ( _cdio_read_block(cdio, UDF_ANCHOR_SECTOR, start_session, 5,
i_track) < 0)
return ret;
/* Maybe there is an UDF anchor in IOS session
so its ISO/UDF session and we prefere UDF */
if ( _cdio_is_UDF() ) {
/* Detect UDF version.
Test if we have a valid version of UDF the xbox can read natively */
if ( _cdio_read_block(cdio, 35, start_session, 5, i_track) < 0)
return ret;
iso_analysis->UDFVerMinor=(unsigned int)buffer[5][240];
iso_analysis->UDFVerMajor=(unsigned int)buffer[5][241];
#if 0
/* We are using ISO/UDF cd's as iso,
no need to get UDF disc label */
if (_cdio_read_block(cdio, 32, start_session, 5, i_track) < 0)
return ret;
stnrcpy(iso_analysis->iso_label, buffer[5]+25, 33);
iso_analysis->iso_label[32] = '\0';
#endif
ret=CDIO_FS_ISO_UDF;
}
#if 0
if (_cdio_is_rockridge())
ret |= CDIO_FS_ANAL_ROCKRIDGE;
#endif
if (_cdio_read_block(cdio, BOOT_SECTOR, start_session, 3, i_track) < 0)
return ret;
if (_cdio_is_joliet()) {
iso_analysis->joliet_level = _cdio_get_joliet_level();
ret |= CDIO_FS_ANAL_JOLIET;
}
if (_cdio_is_it(INDEX_BOOTABLE))
ret |= CDIO_FS_ANAL_BOOTABLE;
if ( _cdio_is_it(INDEX_XA) && _cdio_is_it(INDEX_ISOFS)
&& !(sector0_read_ok && _cdio_is_it(INDEX_PHOTO_CD)) ) {
if ( _cdio_read_block(cdio, VCD_INFO_SECTOR, start_session, 4,
i_track) < 0 )
return ret;
if (_cdio_is_it(INDEX_BRIDGE) && _cdio_is_it(INDEX_CD_RTOS)) {
if (_cdio_is_it(INDEX_VIDEO_CD)) ret |= CDIO_FS_ANAL_VIDEOCD;
else if (_cdio_is_it(INDEX_SVCD)) ret |= CDIO_FS_ANAL_SVCD;
} else if (_cdio_is_it(INDEX_SVCD)) ret |= CDIO_FS_ANAL_CVD;
}
}
else if (_cdio_is_hfs()) ret |= CDIO_FS_HFS;
else if (sector0_read_ok && _cdio_is_it(INDEX_EXT2)) ret |= CDIO_FS_EXT2;
else if (_cdio_is_3do()) ret |= CDIO_FS_3DO;
else {
if ( _cdio_read_block(cdio, UFS_SUPERBLOCK_SECTOR, start_session, 2,
i_track) < 0 )
return ret;
if (sector0_read_ok && _cdio_is_it(INDEX_UFS))
ret |= CDIO_FS_UFS;
else
ret |= CDIO_FS_UNKNOWN;
}
}
/* other checks */
if (_cdio_is_it(INDEX_XA)) ret |= CDIO_FS_ANAL_XA;
if (_cdio_is_it(INDEX_PHOTO_CD)) ret |= CDIO_FS_ANAL_PHOTO_CD;
if (_cdio_is_it(INDEX_CDTV)) ret |= CDIO_FS_ANAL_CDTV;
return ret;
}

1141
lib/driver/cdio.c Normal file

File diff suppressed because it is too large Load Diff

59
lib/driver/cdio_assert.h Normal file
View File

@@ -0,0 +1,59 @@
/*
$Id: cdio_assert.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_ASSERT_H__
#define __CDIO_ASSERT_H__
#if defined(__GNUC__)
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/types.h>
#include <cdio/logging.h>
#define cdio_assert(expr) \
{ \
if (GNUC_UNLIKELY (!(expr))) cdio_log (CDIO_LOG_ASSERT, \
"file %s: line %d (%s): assertion failed: (%s)", \
__FILE__, __LINE__, __PRETTY_FUNCTION__, #expr); \
}
#define cdio_assert_not_reached() \
{ \
cdio_log (CDIO_LOG_ASSERT, \
"file %s: line %d (%s): should not be reached", \
__FILE__, __LINE__, __PRETTY_FUNCTION__); \
}
#else /* non GNU C */
#include <assert.h>
#define cdio_assert(expr) \
assert(expr)
#define cdio_assert_not_reached() \
assert(0)
#endif
#endif /* __CDIO_ASSERT_H__ */

315
lib/driver/cdio_private.h Normal file
View File

@@ -0,0 +1,315 @@
/*
$Id: cdio_private.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Internal routines for CD I/O drivers. */
#ifndef __CDIO_PRIVATE_H__
#define __CDIO_PRIVATE_H__
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/cdio.h>
#include <cdio/cdtext.h>
#include "scsi_mmc_private.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/* Opaque type */
typedef struct _CdioDataSource CdioDataSource;
#ifdef __cplusplus
}
#endif /* __cplusplus */
#include "generic.h"
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
typedef struct {
/*!
Eject media in CD drive. If successful, as a side effect we
also free obj. Return 0 if success and 1 for failure.
*/
int (*eject_media) (void *env);
/*!
Release and free resources associated with cd.
*/
void (*free) (void *env);
/*!
Return the value associated with the key "arg".
*/
const char * (*get_arg) (void *env, const char key[]);
/*!
Get cdtext information for a CdIo object.
@param obj the CD object that may contain CD-TEXT information.
@return the CD-TEXT object or NULL if obj is NULL
or CD-TEXT information does not exist.
If i_track is 0 or CDIO_CDROM_LEADOUT_TRACK the track returned
is the information assocated with the CD.
*/
const cdtext_t * (*get_cdtext) (void *env, track_t i_track);
/*!
Return an array of device names. if CdIo is NULL (we haven't
initialized a specific device driver), then find a suitable device
driver.
NULL is returned if we couldn't return a list of devices.
*/
char ** (*get_devices) (void);
/*!
Return a string containing the default CD device if none is specified.
*/
char * (*get_default_device)(void);
/*!
Get disc mode associated with cd_obj.
*/
discmode_t (*get_discmode) (void *p_env);
/*!
Return the what kind of device we've got.
See cd_types.h for a list of bitmasks for the drive type;
*/
void (*get_drive_cap) (const void *env,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap);
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t (*get_first_track_num) (void *p_env);
/*!
Get the CD-ROM hardware info via a SCSI MMC INQUIRY command.
False is returned if we had an error getting the information.
*/
bool (*get_hwinfo) ( const CdIo *p_cdio,
/* out*/ cdio_hwinfo_t *p_hw_info );
/*!
Return the media catalog number MCN from the CD or NULL if
there is none or we don't have the ability to get it.
*/
char * (*get_mcn) (const void *env);
/*!
Return the number of tracks in the current medium.
CDIO_INVALID_TRACK is returned on error.
*/
track_t (*get_num_tracks) (void *env);
/*!
Return the starting LBA for track number
track_num in obj. Tracks numbers start at 1.
The "leadout" track is specified either by
using track_num LEADOUT_TRACK or the total tracks+1.
CDIO_INVALID_LBA is returned on error.
*/
lba_t (*get_track_lba) (void *env, track_t track_num);
/*!
Get format of track.
*/
track_format_t (*get_track_format) (void *env, track_t track_num);
/*!
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?
*/
bool (*get_track_green) (void *env, track_t track_num);
/*!
Return the starting MSF (minutes/secs/frames) for track number
track_num in obj. Tracks numbers start at 1.
The "leadout" track is specified either by
using track_num LEADOUT_TRACK or the total tracks+1.
False is returned on error.
*/
bool (*get_track_msf) (void *env, track_t track_num, msf_t *msf);
/*!
lseek - reposition read/write file offset
Returns (off_t) -1 on error.
Similar to libc's lseek()
*/
off_t (*lseek) (void *env, off_t offset, int whence);
/*!
Reads into buf the next size bytes.
Returns -1 on error.
Similar to libc's read()
*/
ssize_t (*read) (void *env, void *buf, size_t size);
/*!
Reads a single mode2 sector from cd device into buf starting
from lsn. Returns 0 if no error.
*/
int (*read_audio_sectors) (void *env, void *buf, lsn_t lsn,
unsigned int nblocks);
/*!
Reads a single mode2 sector from cd device into buf starting
from lsn. Returns 0 if no error.
*/
int (*read_mode2_sector) (void *env, void *buf, lsn_t lsn,
bool mode2_form2);
/*!
Reads nblocks of mode2 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
int (*read_mode2_sectors) (void *p_env, void *p_buf, lsn_t lsn,
bool mode2_form2, unsigned int nblocks);
/*!
Reads a single mode1 sector from cd device into buf starting
from lsn. Returns 0 if no error.
*/
int (*read_mode1_sector) (void *p_env, void *p_buf, lsn_t lsn,
bool mode1_form2);
/*!
Reads nblocks of mode1 sectors from cd device into data starting
from lsn.
Returns 0 if no error.
*/
int (*read_mode1_sectors) (void *p_env, void *p_buf, lsn_t lsn,
bool mode1_form2, unsigned int nblocks);
bool (*read_toc) ( void *p_env ) ;
/*!
Run a SCSI MMC command.
cdio CD structure set by cdio_open().
i_timeout_ms time in milliseconds we will wait for the command
to complete.
cdb_len number of bytes in cdb (6, 10, or 12).
cdb CDB bytes. All values that are needed should be set on
input.
b_return_data TRUE if the command expects data to be returned in
the buffer
len Size of buffer
buf Buffer for data, both sending and receiving
Returns 0 if command completed successfully.
*/
scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd;
/*!
Set the arg "key" with "value" in the source device.
*/
int (*set_arg) (void *env, const char key[], const char value[]);
/*!
Return the size of the CD in logical block address (LBA) units.
*/
uint32_t (*stat_size) (void *env);
} cdio_funcs;
/*! Implementation of CdIo type */
struct _CdIo {
driver_id_t driver_id; /**< Particular driver opened. */
cdio_funcs op; /**< driver-specific routines handling
implementation*/
void *env; /**< environment. Passed to routine above. */
};
/* This is used in drivers that must keep their own internal
position pointer for doing seeks. Stream-based drivers (like bincue,
nrg, toc, network) would use this.
*/
typedef struct
{
off_t buff_offset; /* buffer offset in disk-image seeks. */
track_t index; /* Current track index in tocent. */
lba_t lba; /* Current LBA */
} internal_position_t;
CdIo * cdio_new (generic_img_private_t *p_env, cdio_funcs *funcs);
/* The below structure describes a specific CD Input driver */
typedef struct
{
driver_id_t id;
unsigned int flags;
const char *name;
const char *describe;
bool (*have_driver) (void);
CdIo *(*driver_open) (const char *psz_source_name);
CdIo *(*driver_open_am) (const char *psz_source_name,
const char *psz_access_mode);
char *(*get_default_device) (void);
bool (*is_device) (const char *psz_source_name);
char **(*get_devices) (void);
} CdIo_driver_t;
/* The below array gives of the drivers that are currently available for
on a particular host. */
extern CdIo_driver_t CdIo_driver[CDIO_MAX_DRIVER];
/* The last valid entry of Cdio_driver. -1 means uninitialzed. -2
means some sort of error.
*/
extern int CdIo_last_driver;
/* The below array gives all drivers that can possibly appear.
on a particular host. */
extern CdIo_driver_t CdIo_all_drivers[CDIO_MAX_DRIVER+1];
/*!
Add/allocate a drive to the end of drives.
Use cdio_free_device_list() to free this device_list.
*/
void cdio_add_device_list(char **device_list[], const char *drive,
unsigned int *i_drives);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __CDIO_PRIVATE_H__ */

228
lib/driver/cdtext.c Normal file
View File

@@ -0,0 +1,228 @@
/*
$Id: cdtext.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
toc reading routine adapted from cuetools
Copyright (C) 2003 Svend Sanjay Sorensen <ssorensen@fastmail.fm>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/cdtext.h>
#include <cdio/logging.h>
#include "cdtext_private.h"
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_STRING_H
#include <string.h>
#endif
/*! Note: the order and number items (except CDTEXT_INVALID) should
match the cdtext_field_t enumeration. */
const char *cdtext_keywords[] =
{
"ARRANGER",
"COMPOSER",
"DISC_ID",
"GENRE",
"ISRC",
"MESSAGE",
"PERFORMER",
"SIZE_INFO",
"SONGWRITER",
"TITLE",
"TOC_INFO",
"TOC_INFO2",
"UPC_EAN",
};
/*! Return string representation of the enum values above */
const char *
cdtext_field2str (cdtext_field_t i)
{
if (i >= MAX_CDTEXT_FIELDS)
return "Invalid CDTEXT field index";
else
return cdtext_keywords[i];
}
/*! Free memory assocated with cdtext*/
void
cdtext_destroy (cdtext_t *cdtext)
{
cdtext_field_t i;
for (i=0; i < MAX_CDTEXT_FIELDS; i++) {
if (cdtext->field[i]) free(cdtext->field[i]);
}
}
/*!
returns the CDTEXT value associated with key. NULL is returned
if key is CDTEXT_INVALID or the field is not set.
*/
const char *
cdtext_get (cdtext_field_t key, const cdtext_t *cdtext)
{
if (key == CDTEXT_INVALID) return NULL;
return cdtext->field[key];
}
/*! Initialize a new cdtext structure.
When the structure is no longer needed, release the
resources using cdtext_delete.
*/
void
cdtext_init (cdtext_t *cdtext)
{
cdtext_field_t i;
for (i=0; i < MAX_CDTEXT_FIELDS; i++) {
cdtext->field[i] = NULL;
}
}
/*!
returns 0 if field is a CD-TEXT keyword, returns non-zero otherwise
*/
cdtext_field_t
cdtext_is_keyword (const char *key)
{
#if 0
char *item;
item = bsearch(key,
cdtext_keywords, 12,
sizeof (char *),
(int (*)(const void *, const void *))
strcmp);
return (NULL != item) ? 0 : 1;
#else
unsigned int i;
for (i = 0; i < 13 ; i++)
if (0 == strcmp (cdtext_keywords[i], key)) {
return i;
}
return CDTEXT_INVALID;
#endif
}
/*! sets cdtext's keyword entry to field.
*/
void
cdtext_set (cdtext_field_t key, const char *value, cdtext_t *cdtext)
{
if (NULL == value || key == CDTEXT_INVALID) return;
if (cdtext->field[key]) free (cdtext->field[key]);
cdtext->field[key] = strdup (value);
}
#define SET_CDTEXT_FIELD(FIELD) \
(*set_cdtext_field_fn)(user_data, i_track, i_first_track, FIELD, buffer);
/*
parse all CD-TEXT data retrieved.
*/
bool
cdtext_data_init(void *user_data, track_t i_first_track,
unsigned char *wdata,
set_cdtext_field_fn_t set_cdtext_field_fn)
{
CDText_data_t *pdata;
int i;
int j;
char buffer[256];
int idx;
int i_track;
bool b_ret = false;
memset( buffer, 0x00, sizeof(buffer) );
idx = 0;
pdata = (CDText_data_t *) (&wdata[4]);
for( i=0; i < CDIO_CDTEXT_MAX_PACK_DATA; i++ ) {
#if TESTED
if ( pdata->bDBC ) {
cdio_warn("Double-byte characters not supported");
return false;
}
#endif
if( pdata->seq != i )
break;
if( (pdata->type >= 0x80)
&& (pdata->type <= 0x85) && (pdata->block == 0) ) {
i_track = pdata->i_track;
for( j=0; j < CDIO_CDTEXT_MAX_TEXT_DATA; j++ ) {
if( pdata->text[j] == 0x00 ) {
bool b_field_set=true;
switch( pdata->type) {
case CDIO_CDTEXT_TITLE:
SET_CDTEXT_FIELD(CDTEXT_TITLE);
break;
case CDIO_CDTEXT_PERFORMER:
SET_CDTEXT_FIELD(CDTEXT_PERFORMER);
break;
case CDIO_CDTEXT_SONGWRITER:
SET_CDTEXT_FIELD(CDTEXT_SONGWRITER);
break;
case CDIO_CDTEXT_COMPOSER:
SET_CDTEXT_FIELD(CDTEXT_COMPOSER);
break;
case CDIO_CDTEXT_ARRANGER:
SET_CDTEXT_FIELD(CDTEXT_ARRANGER);
break;
case CDIO_CDTEXT_MESSAGE:
SET_CDTEXT_FIELD(CDTEXT_MESSAGE);
break;
case CDIO_CDTEXT_DISCID:
SET_CDTEXT_FIELD(CDTEXT_DISCID);
break;
case CDIO_CDTEXT_GENRE:
SET_CDTEXT_FIELD(CDTEXT_GENRE);
break;
default : b_field_set = false;
}
if (b_field_set) {
b_ret = true;
i_track++;
idx = 0;
}
} else {
buffer[idx++] = pdata->text[j];
}
buffer[idx] = 0x00;
}
}
pdata++;
}
return b_ret;
}

119
lib/driver/cdtext_private.h Normal file
View File

@@ -0,0 +1,119 @@
/*
$Id: cdtext_private.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef __CDIO_CDTEXT_PRIVATE_H__
#define __CDIO_CDTEXT_PRIVATE_H__
#include <cdio/cdio.h>
#include <cdio/cdtext.h>
#define CDIO_CDTEXT_MAX_PACK_DATA 255
#define CDIO_CDTEXT_MAX_TEXT_DATA 12
/* From table J.2 - Pack Type Indicator Definitions from
Working Draft NCITS XXX T10/1364-D Revision 10G. November 12, 2001.
*/
/* Title of Alubm name (ID=0) or Track Titles (ID != 0) */
#define CDIO_CDTEXT_TITLE 0x80
/* Name(s) of the performer(s) in ASCII */
#define CDIO_CDTEXT_PERFORMER 0x81
/* Name(s) of the songwriter(s) in ASCII */
#define CDIO_CDTEXT_SONGWRITER 0x82
/* Name(s) of the Composers in ASCII */
#define CDIO_CDTEXT_COMPOSER 0x83
/* Name(s) of the Arrangers in ASCII */
#define CDIO_CDTEXT_ARRANGER 0x84
/* Message(s) from content provider and/or artist in ASCII */
#define CDIO_CDTEXT_MESSAGE 0x85
/* Disc Identificatin information */
#define CDIO_CDTEXT_DISCID 0x86
/* Genre Identification and Genre Information */
#define CDIO_CDTEXT_GENRE 0x87
/* Table of Content Information */
#define CDIO_CDTEXT_TOC 0x88
/* Second Table of Content Information */
#define CDIO_CDTEXT_TOC2 0x89
/* 0x8A, 0x8B, 0x8C are reserved
0x8D Reserved for content provider only.
*/
/* UPC/EAN code of the album and ISRC code of each track */
#define CDIO_CDTEXT_UPC 0x8E
/* Size information of the Block */
#define CDIO_CDTEXT_BLOCKSIZE 0x8F
PRAGMA_BEGIN_PACKED
struct CDText_data
{
uint8_t type;
track_t i_track;
uint8_t seq;
#ifdef WORDS_BIGENDIAN
uint8_t bDBC: 1; /* double byte character */
uint8_t block: 3; /* block number 0..7 */
uint8_t characterPosition:4; /* character position */
#else
uint8_t characterPosition:4; /* character position */
uint8_t block :3; /* block number 0..7 */
uint8_t bDBC :1; /* double byte character */
#endif
char text[CDIO_CDTEXT_MAX_TEXT_DATA];
uint8_t crc[2];
} GNUC_PACKED;
PRAGMA_END_PACKED
typedef struct CDText_data CDText_data_t;
typedef void (*set_cdtext_field_fn_t) (void *user_data, track_t i_track,
track_t i_first_track,
cdtext_field_t field,
const char *buffer);
/*
Internal routine to parse all CD-TEXT data retrieved.
*/
bool cdtext_data_init(void *user_data, track_t i_first_track,
unsigned char *wdata,
set_cdtext_field_fn_t set_cdtext_field_fn);
#endif /* __CDIO_CDTEXT_PRIVATE_H__ */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

249
lib/driver/ds.c Normal file
View File

@@ -0,0 +1,249 @@
/*
$Id: ds.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <cdio/ds.h>
#include <cdio/util.h>
#include <cdio/types.h>
#include "cdio_assert.h"
static const char _rcsid[] = "$Id: ds.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
struct _CdioList
{
unsigned length;
CdioListNode *begin;
CdioListNode *end;
};
struct _CdioListNode
{
CdioList *list;
CdioListNode *next;
void *data;
};
/* impl */
CdioList *
_cdio_list_new (void)
{
CdioList *new_obj = _cdio_malloc (sizeof (CdioList));
return new_obj;
}
void
_cdio_list_free (CdioList *list, int free_data)
{
while (_cdio_list_length (list))
_cdio_list_node_free (_cdio_list_begin (list), free_data);
free (list);
}
unsigned
_cdio_list_length (const CdioList *list)
{
cdio_assert (list != NULL);
return list->length;
}
void
_cdio_list_prepend (CdioList *list, void *data)
{
CdioListNode *new_node;
cdio_assert (list != NULL);
new_node = _cdio_malloc (sizeof (CdioListNode));
new_node->list = list;
new_node->next = list->begin;
new_node->data = data;
list->begin = new_node;
if (list->length == 0)
list->end = new_node;
list->length++;
}
void
_cdio_list_append (CdioList *list, void *data)
{
cdio_assert (list != NULL);
if (list->length == 0)
{
_cdio_list_prepend (list, data);
}
else
{
CdioListNode *new_node = _cdio_malloc (sizeof (CdioListNode));
new_node->list = list;
new_node->next = NULL;
new_node->data = data;
list->end->next = new_node;
list->end = new_node;
list->length++;
}
}
void
_cdio_list_foreach (CdioList *list, _cdio_list_iterfunc func, void *user_data)
{
CdioListNode *node;
cdio_assert (list != NULL);
cdio_assert (func != 0);
for (node = _cdio_list_begin (list);
node != NULL;
node = _cdio_list_node_next (node))
func (_cdio_list_node_data (node), user_data);
}
CdioListNode *
_cdio_list_find (CdioList *list, _cdio_list_iterfunc cmp_func, void *user_data)
{
CdioListNode *node;
cdio_assert (list != NULL);
cdio_assert (cmp_func != 0);
for (node = _cdio_list_begin (list);
node != NULL;
node = _cdio_list_node_next (node))
if (cmp_func (_cdio_list_node_data (node), user_data))
break;
return node;
}
CdioListNode *
_cdio_list_begin (const CdioList *list)
{
cdio_assert (list != NULL);
return list->begin;
}
CdioListNode *
_cdio_list_end (CdioList *list)
{
cdio_assert (list != NULL);
return list->end;
}
CdioListNode *
_cdio_list_node_next (CdioListNode *node)
{
if (node)
return node->next;
return NULL;
}
void
_cdio_list_node_free (CdioListNode *node, int free_data)
{
CdioList *list;
CdioListNode *prev_node;
cdio_assert (node != NULL);
list = node->list;
cdio_assert (_cdio_list_length (list) > 0);
if (free_data)
free (_cdio_list_node_data (node));
if (_cdio_list_length (list) == 1)
{
cdio_assert (list->begin == list->end);
list->end = list->begin = NULL;
list->length = 0;
free (node);
return;
}
cdio_assert (list->begin != list->end);
if (list->begin == node)
{
list->begin = node->next;
free (node);
list->length--;
return;
}
for (prev_node = list->begin; prev_node->next; prev_node = prev_node->next)
if (prev_node->next == node)
break;
cdio_assert (prev_node->next != NULL);
if (list->end == node)
list->end = prev_node;
prev_node->next = node->next;
list->length--;
free (node);
}
void *
_cdio_list_node_data (CdioListNode *node)
{
if (node)
return node->data;
return NULL;
}
/* eof */
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

179
lib/driver/generic.h Normal file
View File

@@ -0,0 +1,179 @@
/*
$Id: generic.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* Internal routines for CD I/O drivers. */
#ifndef __CDIO_GENERIC_H__
#define __CDIO_GENERIC_H__
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/cdio.h>
#include <cdio/cdtext.h>
#include <cdio/iso9660.h>
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
/*!
Things common to private device structures. Even though not all
devices may have some of these fields, by listing common ones
we facilitate writing generic routines and even cut-and-paste
code.
*/
typedef struct {
char *source_name; /**< Name used in open. */
bool init; /**< True if structure has been initialized */
bool toc_init; /**< True if TOC read in */
bool b_cdtext_init; /**< True if CD-Text read in */
bool b_cdtext_error; /**< True if trouble reading CD-Text */
int ioctls_debugged; /**< for debugging */
/* Only one of data_source or fd is used; fd is for CD-ROM
devices and the data_source for stream reading (bincue, nrg, toc,
network).
*/
CdioDataSource *data_source;
int fd; /**< File descriptor of device */
track_t i_first_track; /**< The starting track number. */
track_t i_tracks; /**< The number of tracks. */
uint8_t i_joliet_level; /**< 0 = no Joliet extensions.
1-3: Joliet level. */
iso9660_pvd_t pvd;
iso9660_svd_t svd;
CdIo *cdio; /**< a way to call general cdio routines. */
cdtext_t cdtext; /**< CD-Text for disc. */
cdtext_t cdtext_track[CDIO_CD_MAX_TRACKS+1]; /*CD-TEXT for each track*/
} generic_img_private_t;
/*!
Bogus eject media when there is no ejectable media, e.g. a disk image
We always return 2. Should we also free resources?
*/
int cdio_generic_bogus_eject_media (void *env);
/*!
Release and free resources associated with cd.
*/
void cdio_generic_free (void *env);
/*!
Initialize CD device.
*/
bool cdio_generic_init (void *env);
/*!
Reads into buf the next size bytes.
Returns -1 on error.
Is in fact libc's read().
*/
off_t cdio_generic_lseek (void *env, off_t offset, int whence);
/*!
Reads into buf the next size bytes.
Returns -1 on error.
Is in fact libc's read().
*/
ssize_t cdio_generic_read (void *env, void *buf, size_t size);
/*!
Reads a single form1 sector from cd device into data starting
from lsn. Returns 0 if no error.
*/
int cdio_generic_read_form1_sector (void * user_data, void *data,
lsn_t lsn);
/*!
Release and free resources associated with stream or disk image.
*/
void cdio_generic_stdio_free (void *env);
/*!
Return true if source_name could be a device containing a CD-ROM on
Win32
*/
bool cdio_is_device_win32(const char *source_name);
/*!
Return true if source_name could be a device containing a CD-ROM on
most Unix servers with block and character devices.
*/
bool cdio_is_device_generic(const char *source_name);
/*!
Like above, but don't give a warning device doesn't exist.
*/
bool cdio_is_device_quiet_generic(const char *source_name);
/*!
Get cdtext information for a CdIo object .
@param obj the CD object that may contain CD-TEXT information.
@return the CD-TEXT object or NULL if obj is NULL
or CD-TEXT information does not exist.
*/
const cdtext_t *get_cdtext_generic (void *p_user_data, track_t i_track);
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
track_t get_first_track_num_generic(void *p_user_data);
/*!
Return the number of tracks in the current medium.
*/
track_t get_num_tracks_generic(void *p_user_data);
/*!
Get disc type associated with cd object.
*/
discmode_t get_discmode_generic (void *p_user_data );
/*!
Same as above but only handles CD cases
*/
discmode_t get_discmode_cd_generic (void *p_user_data );
void set_cdtext_field_generic(void *user_data, track_t i_track,
track_t i_first_track,
cdtext_field_t e_field, const char *psz_value);
/*!
Read cdtext information for a CdIo object .
return true on success, false on error or CD-Text information does
not exist.
*/
bool init_cdtext_generic (generic_img_private_t *p_env);
#ifdef __cplusplus
}
#endif /* __cplusplus */
#endif /* __CDIO_GENERIC_H__ */

75
lib/driver/image.h Normal file
View File

@@ -0,0 +1,75 @@
/*
$Id: image.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*!
Header for image drivers. In contrast to image_common.h which contains
routines, this header like most C headers does not depend on anything
defined before it is included.
*/
#ifndef __CDIO_IMAGE_H__
#define __CDIO_IMAGE_H__
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/types.h>
#include <cdio/cdtext.h>
#include "cdio_private.h"
#include <cdio/sector.h>
/*!
The universal format for information about a track for CD image readers
It may be that some fields can be derived from other fields.
Over time this structure may get cleaned up. Possibly this can be
expanded/reused for real CD formats.
*/
typedef struct {
track_t track_num; /**< Probably is index+1 */
msf_t start_msf;
lba_t start_lba;
int start_index;
lba_t length;
lba_t pregap; /**< pre-gap with zero audio data */
int sec_count; /**< Number of sectors in this track. Does not
include pregap */
int num_indices;
flag_t flags; /**< "[NO] COPY", "4CH", "[NO] PREMPAHSIS" */
char *isrc; /**< IRSC Code (5.22.4) exactly 12 bytes */
char *filename;
CdioDataSource *data_source;
track_format_t track_format;
bool track_green;
cdtext_t cdtext; /**< CD-TEXT */
trackmode_t mode;
uint16_t datasize; /**< How much is in the portion we return
back? */
uint16_t datastart; /**< Offset from begining that data starts */
uint16_t endsize; /**< How much stuff at the end to skip over.
This stuff may have error correction
(EDC, or ECC).*/
uint16_t blocksize; /**< total block size = start + size + end */
} track_info_t;
#endif /* __CDIO_IMAGE_H__ */

23
lib/driver/image/Makefile Normal file
View File

@@ -0,0 +1,23 @@
# $Id: Makefile,v 1.1 2004/12/18 17:29:32 rocky Exp $
#
# Copyright (C) 2004 Rocky Bernstein
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#######################################
# The make is done above. This boilerplate Makefile just transfers the call
all install check clean:
cd .. && $(MAKE) $@

1214
lib/driver/image/bincue.c Normal file

File diff suppressed because it is too large Load Diff

1198
lib/driver/image/cdrdao.c Normal file

File diff suppressed because it is too large Load Diff

1278
lib/driver/image/nrg.c Normal file

File diff suppressed because it is too large Load Diff

115
lib/driver/image/nrg.h Normal file
View File

@@ -0,0 +1,115 @@
/*
$Id: nrg.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
Copyright (C) 2001, 2003 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/* NERO (NRG) file format structures. */
/* this ugly image format is typical for lazy win32 programmers... at
least structure were set big endian, so at reverse
engineering wasn't such a big headache... */
PRAGMA_BEGIN_PACKED
typedef union {
struct {
uint32_t __x GNUC_PACKED;
uint32_t ID GNUC_PACKED;
uint32_t footer_ofs GNUC_PACKED;
} v50;
struct {
uint32_t ID GNUC_PACKED;
uint64_t footer_ofs GNUC_PACKED;
} v55;
} _footer_t;
typedef struct {
uint32_t start GNUC_PACKED;
uint32_t length GNUC_PACKED;
uint32_t type GNUC_PACKED; /* 0x0 -> MODE1, 0x2 -> MODE2 form1,
0x3 -> MIXED_MODE2 2336 blocksize
*/
uint32_t start_lsn GNUC_PACKED; /* does not include any pre-gaps! */
uint32_t _unknown GNUC_PACKED; /* wtf is this for? -- always zero... */
} _etnf_array_t;
/* Finally they realized that 32-bit offsets are a bit outdated for
IA64 *eg* */
typedef struct {
uint64_t start GNUC_PACKED;
uint64_t length GNUC_PACKED;
uint32_t type GNUC_PACKED; /* 0x0 -> MODE1, 0x2 -> MODE2 form1,
0x3 -> MIXED_MODE2 2336 blocksize
*/
uint32_t start_lsn GNUC_PACKED;
uint64_t _unknown GNUC_PACKED; /* wtf is this for? -- always zero... */
} _etn2_array_t;
typedef struct {
uint8_t type GNUC_PACKED; /* has track copy bit and whether audiofile
or datafile. Is often 0x41 == 'A' */
uint8_t track GNUC_PACKED; /* binary or BCD?? */
uint8_t addr_ctrl GNUC_PACKED; /* addresstype: MSF or LBA in lower 4 bits
control in upper 4 bits.
makes 0->1 transitions */
uint8_t res GNUC_PACKED; /* ?? */
uint32_t lsn GNUC_PACKED;
} _cuex_array_t;
typedef struct {
uint32_t _unknown1 GNUC_PACKED;
char psz_mcn[CDIO_MCN_SIZE] GNUC_PACKED;
uint8_t _unknown[64-CDIO_MCN_SIZE-sizeof(uint32_t)] GNUC_PACKED;
} _daox_array_t;
typedef struct {
uint32_t _unknown1 GNUC_PACKED;
char psz_mcn[CDIO_MCN_SIZE] GNUC_PACKED;
uint8_t _unknown[64-CDIO_MCN_SIZE-sizeof(uint32_t)] GNUC_PACKED;
} _daoi_array_t;
typedef struct {
uint32_t id GNUC_PACKED;
uint32_t len GNUC_PACKED;
char data[EMPTY_ARRAY_SIZE] GNUC_PACKED;
} _chunk_t;
PRAGMA_END_PACKED
/* Nero images are Big Endian. */
#define CDTX_ID 0x43445458 /* CD TEXT */
#define CUEX_ID 0x43554558 /* Nero version 5.5.x-6.x */
#define CUES_ID 0x43554553 /* Nero pre version 5.5.x-6.x */
#define DAOX_ID 0x44414f58 /* Nero version 5.5.x-6.x */
#define DAOI_ID 0x44414f49
#define END1_ID 0x454e4421
#define ETN2_ID 0x45544e32
#define ETNF_ID 0x45544e46
#define NER5_ID 0x4e455235 /* Nero version 5.5.x */
#define NERO_ID 0x4e45524f /* Nero pre 5.5.x */
#define SINF_ID 0x53494e46 /* Session information */
#define MTYP_ID 0x4d545950 /* Disc Media type? */
#define MTYP_AUDIO_CD 1 /* This isn't correct. But I don't know the
the right thing is and it sometimes works (and
sometimes is wrong). */
/* Disk track type Values gleaned from DAOX */
#define DTYP_MODE1 0
#define DTYP_MODE2_XA 2
#define DTYP_INVALID 255

225
lib/driver/image_common.h Normal file
View File

@@ -0,0 +1,225 @@
/*
$Id: image_common.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*! Common image routines.
Because _img_private_t may vary over image formats, the routines are
included into the image drivers after _img_private_t is defined. In
order for the below routines to work, there is a large part of
_img_private_t that is common among image drivers. For example, see
image.h
*/
#ifndef __CDIO_IMAGE_COMMON_H__
#define __CDIO_IMAGE_COMMON_H__
#define free_if_notnull(obj) \
if (NULL != obj) { free(obj); obj=NULL; };
/*!
We don't need the image any more. Free all memory associated with
it.
*/
static void
_free_image (void *user_data)
{
_img_private_t *p_env = user_data;
track_t i_track;
if (NULL == p_env) return;
for (i_track=0; i_track < p_env->gen.i_tracks; i_track++) {
free_if_notnull(p_env->tocent[i_track].filename);
free_if_notnull(p_env->tocent[i_track].isrc);
cdtext_destroy(&(p_env->tocent[i_track].cdtext));
}
free_if_notnull(p_env->psz_mcn);
free_if_notnull(p_env->psz_cue_name);
cdtext_destroy(&(p_env->gen.cdtext));
cdio_generic_stdio_free(p_env);
free(p_env);
}
#ifdef NEED_MEDIA_EJECT_IMAGE
/*!
Eject media -- there's nothing to do here except free resources.
We always return 2.
*/
static int
_eject_media_image(void *user_data)
{
_free_image (user_data);
return 2;
}
#endif
/*!
Return the value associated with the key "arg".
*/
static const char *
_get_arg_image (void *user_data, const char key[])
{
_img_private_t *p_env = user_data;
if (!strcmp (key, "source")) {
return p_env->gen.source_name;
} else if (!strcmp (key, "cue")) {
return p_env->psz_cue_name;
} else if (!strcmp(key, "access-mode")) {
return "image";
}
return NULL;
}
/*!
Get disc type associated with cd_obj.
*/
static discmode_t
_get_discmode_image (void *p_user_data)
{
_img_private_t *p_env = p_user_data;
return p_env->disc_mode;
}
/*!
Return the media catalog number (MCN) from the CD or NULL if there
is none or we don't have the ability to get it.
Note: string is malloc'd so caller has to free() the returned
string when done with it.
*/
static char *
_get_mcn_image(const void *user_data)
{
const _img_private_t *env = user_data;
if (NULL == env || NULL == env->psz_mcn) return NULL;
return strdup(env->psz_mcn);
}
/*!
Return the starting MSF (minutes/secs/frames) for the track number
track_num in obj. Tracks numbers start at 1.
The "leadout" track is specified either by
using track_num LEADOUT_TRACK or the total tracks+1.
*/
static bool
_get_track_msf_image(void *user_data, track_t track_num, msf_t *msf)
{
_img_private_t *env = user_data;
if (NULL == msf) return false;
if (track_num == CDIO_CDROM_LEADOUT_TRACK) track_num = env->gen.i_tracks+1;
if (track_num <= env->gen.i_tracks+1 && track_num != 0) {
*msf = env->tocent[track_num-env->gen.i_first_track].start_msf;
return true;
} else
return false;
}
/*!
Return the number of of the first track.
CDIO_INVALID_TRACK is returned on error.
*/
static track_t
_get_first_track_num_image(void *user_data)
{
_img_private_t *env = user_data;
return env->gen.i_first_track;
}
/*!
Return the number of tracks.
*/
static track_t
_get_num_tracks_image(void *user_data)
{
_img_private_t *env = user_data;
return env->gen.i_tracks;
}
/*!
Set the arg "key" with "value" in the source device.
Currently "source" to set the source device in I/O operations
is the only valid key.
0 is returned if no error was found, and nonzero if there as an error.
*/
static int
_set_arg_image (void *user_data, const char key[], const char value[])
{
_img_private_t *env = user_data;
if (!strcmp (key, "source"))
{
free_if_notnull (env->gen.source_name);
if (!value)
return -2;
env->gen.source_name = strdup (value);
}
else if (!strcmp (key, "cue"))
{
free_if_notnull (env->psz_cue_name);
if (!value)
return -2;
env->psz_cue_name = strdup (value);
}
else
return -1;
return 0;
}
/*!
Return the the kind of drive capabilities of device.
*/
static void
_get_drive_cap_image (const void *user_data,
cdio_drive_read_cap_t *p_read_cap,
cdio_drive_write_cap_t *p_write_cap,
cdio_drive_misc_cap_t *p_misc_cap)
{
*p_read_cap = CDIO_DRIVE_CAP_READ_AUDIO
| CDIO_DRIVE_CAP_READ_CD_G
| CDIO_DRIVE_CAP_READ_CD_R
| CDIO_DRIVE_CAP_READ_CD_RW
;
*p_write_cap = 0;
/* In the future we may want to simulate
LOCK, OPEN_TRAY, CLOSE_TRAY, SELECT_SPEED, etc.
*/
*p_misc_cap = CDIO_DRIVE_CAP_MISC_FILE;
}
#endif /* __CDIO_IMAGE_COMMON_H__ */

141
lib/driver/libcdio.sym Normal file
View File

@@ -0,0 +1,141 @@
_cdio_list_append
_cdio_list_begin
_cdio_list_end
_cdio_list_find
_cdio_list_foreach
_cdio_list_free
_cdio_list_length
_cdio_list_new
_cdio_list_node_data
_cdio_list_node_free
_cdio_list_node_next
_cdio_list_prepend
_cdio_malloc
_cdio_strfreev
_cdio_strsplit
cdio_debug
cdio_destroy
cdio_driver_describe
cdio_eject_media
cdio_free_device_list
cdio_from_bcd8
cdio_get_arg
cdio_get_cdtext
cdio_get_default_device
cdio_get_default_device_bincue
cdio_get_default_device_bsdi
cdio_get_default_device_cdrdao
cdio_get_default_device_freebsd
cdio_get_default_device_linux
cdio_get_default_device_nrg
cdio_get_default_device_osx
cdio_get_default_device_solaris
cdio_get_default_device_win32
cdio_get_devices
cdio_get_devices_bincue
cdio_get_devices_bsdi
cdio_get_devices_cdrdao
cdio_get_devices_freebsd
cdio_get_devices_linux
cdio_get_devices_nrg
cdio_get_devices_osx
cdio_get_devices_ret
cdio_get_devices_solaris
cdio_get_devices_win32
cdio_get_devices_with_cap
cdio_get_devices_with_cap_ret
cdio_get_discmode
cdio_get_drive_cap
cdio_get_drive_cap_dev
cdio_get_driver_id
cdio_get_driver_name
cdio_get_first_track_num
cdio_get_hwinfo
cdio_get_joliet_level
cdio_get_mcn
cdio_get_num_tracks
cdio_get_track_format
cdio_get_track_green
cdio_get_track_lba
cdio_get_track_lsn
cdio_get_track_msf
cdio_get_track_sec_count
cdio_guess_cd_type
cdio_have_bincue
cdio_have_bsdi
cdio_have_cdrdao
cdio_have_driver
cdio_have_freebsd
cdio_have_linux
cdio_have_nrg
cdio_have_osx
cdio_have_solaris
cdio_have_win32
cdio_info
cdio_init
cdio_is_binfile
cdio_is_cuefile
cdio_is_device
cdio_is_discmode_cdrom
cdio_is_nrg
cdio_is_tocfile
cdio_lba_to_lsn
cdio_lba_to_msf
cdio_lba_to_msf_str
cdio_log
cdio_log_set_handler
cdio_loglevel_default
cdio_lseek
cdio_lsn_to_lba
cdio_lsn_to_msf
cdio_msf_to_lba
cdio_msf_to_lsn
cdio_msf_to_str
cdio_open
cdio_open_am
cdio_open_am_bincue
cdio_open_am_bsdi
cdio_open_am_cd
cdio_open_am_cdrdao
cdio_open_am_freebsd
cdio_open_am_linux
cdio_open_am_nrg
cdio_open_am_osx
cdio_open_am_solaris
cdio_open_am_win32
cdio_open_bincue
cdio_open_bsdi
cdio_open_cd
cdio_open_cdrdao
cdio_open_cue
cdio_open_freebsd
cdio_open_linux
cdio_open_nrg
cdio_open_osx
cdio_open_solaris
cdio_open_win32
cdio_read
cdio_read_audio_sector
cdio_read_audio_sectors
cdio_read_mode1_sector
cdio_read_mode1_sectors
cdio_read_mode2_sector
cdio_read_mode2_sectors
cdio_set_arg
cdio_stat_size
cdio_stdio_destroy
cdio_stdio_new
cdio_stream_read
cdio_stream_seek
cdio_to_bcd8
cdio_warn
cdtext_destroy
cdtext_field2str
cdtext_get
cdtext_init
cdtext_is_keyword
cdtext_set
discmode2str
scsi_mmc_get_hwinfo
scsi_mmc_run_cmd
track_format2str

143
lib/driver/logging.c Normal file
View File

@@ -0,0 +1,143 @@
/*
$Id: logging.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
#include <cdio/logging.h>
#include "cdio_assert.h"
#include "portable.h"
static const char _rcsid[] = "$Id: logging.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
cdio_log_level_t cdio_loglevel_default = CDIO_LOG_WARN;
static void
default_cdio_log_handler (cdio_log_level_t level, const char message[])
{
switch (level)
{
case CDIO_LOG_ERROR:
if (level >= cdio_loglevel_default) {
fprintf (stderr, "**ERROR: %s\n", message);
fflush (stderr);
}
exit (EXIT_FAILURE);
break;
case CDIO_LOG_DEBUG:
if (level >= cdio_loglevel_default) {
fprintf (stdout, "--DEBUG: %s\n", message);
}
break;
case CDIO_LOG_WARN:
if (level >= cdio_loglevel_default) {
fprintf (stdout, "++ WARN: %s\n", message);
}
break;
case CDIO_LOG_INFO:
if (level >= cdio_loglevel_default) {
fprintf (stdout, " INFO: %s\n", message);
}
break;
case CDIO_LOG_ASSERT:
if (level >= cdio_loglevel_default) {
fprintf (stderr, "!ASSERT: %s\n", message);
fflush (stderr);
}
abort ();
break;
default:
cdio_assert_not_reached ();
break;
}
fflush (stdout);
}
static cdio_log_handler_t _handler = default_cdio_log_handler;
cdio_log_handler_t
cdio_log_set_handler (cdio_log_handler_t new_handler)
{
cdio_log_handler_t old_handler = _handler;
_handler = new_handler;
return old_handler;
}
static void
cdio_logv (cdio_log_level_t level, const char format[], va_list args)
{
char buf[1024] = { 0, };
static int in_recursion = 0;
if (in_recursion)
cdio_assert_not_reached ();
in_recursion = 1;
vsnprintf(buf, sizeof(buf)-1, format, args);
_handler(level, buf);
in_recursion = 0;
}
void
cdio_log (cdio_log_level_t level, const char format[], ...)
{
va_list args;
va_start (args, format);
cdio_logv (level, format, args);
va_end (args);
}
#define CDIO_LOG_TEMPLATE(level, LEVEL) \
void \
cdio_ ## level (const char format[], ...) \
{ \
va_list args; \
va_start (args, format); \
cdio_logv (CDIO_LOG_ ## LEVEL, format, args); \
va_end (args); \
}
CDIO_LOG_TEMPLATE(debug, DEBUG)
CDIO_LOG_TEMPLATE(info, INFO)
CDIO_LOG_TEMPLATE(warn, WARN)
CDIO_LOG_TEMPLATE(error, ERROR)
#undef CDIO_LOG_TEMPLATE
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

74
lib/driver/portable.h Normal file
View File

@@ -0,0 +1,74 @@
/*
$Id: portable.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/*
This file contains definitions to fill in for differences or
deficiencies to OS or compiler irregularities. If this file is
included other routines can be more portable.
*/
#ifndef __CDIO_PORTABLE_H__
#define __CDIO_PORTABLE_H__
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#if !defined(HAVE_FTRUNCATE)
# if defined ( WIN32 )
# define ftruncate chsize
# endif
#endif /*HAVE_FTRUNCATE*/
#if !defined(HAVE_SNPRINTF)
# if defined ( MSVC )
# define snprintf _snprintf
# endif
#endif /*HAVE_SNPRINTF*/
#if !defined(HAVE_VSNPRINTF)
# if defined ( MSVC )
# define snprintf _vsnprintf
# endif
#endif /*HAVE_SNPRINTF*/
#ifdef MSVC
# include <io.h>
# ifndef S_ISBLK
# define _S_IFBLK 0060000 /* Block Special */
# define S_ISBLK(x) (x & _S_IFBLK)
# endif
# ifndef S_ISCHR
# define _S_IFCHR 0020000 /* character special */
# define S_ISCHR(x) (x & _S_IFCHR)
# endif
#endif /*MSVC*/
#ifdef HAVE_MEMSET
# define BZERO(ptr, size) memset(ptr, 0, size)
#elif HAVE_BZERO
# define BZERO(ptr, size) bzero(ptr, size)
#else
Error -- you need either memset or bzero
#endif
#endif /* __CDIO_PORTABLE_H__ */

681
lib/driver/scsi_mmc.c Normal file
View File

@@ -0,0 +1,681 @@
/* Common SCSI Multimedia Command (MMC) routines.
$Id: scsi_mmc.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/cdio.h>
#include <cdio/logging.h>
#include <cdio/scsi_mmc.h>
#include "cdio_private.h"
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#ifdef HAVE_ERRNO_H
#include <errno.h>
#endif
/*!
Return the discmode as reported by the SCSI-MMC Read (FULL) TOC
command.
Information was obtained from Section 5.1.13 (Read TOC/PMA/ATIP)
pages 56-62 from the SCSI MMC draft specification, revision 10a
at http://www.t10.org/ftp/t10/drafts/mmc/mmc-r10a.pdf See
especially tables 72, 73 and 75.
*/
discmode_t
scsi_mmc_get_discmode( const CdIo *p_cdio )
{
uint8_t buf[14] = { 0, };
scsi_mmc_cdb_t cdb;
memset(&cdb, 0, sizeof(scsi_mmc_cdb_t));
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC);
cdb.field[1] = CDIO_CDROM_MSF; /* The MMC-5 spec may require this. */
cdb.field[2] = CDIO_MMC_READTOC_FMT_FULTOC;
CDIO_MMC_SET_READ_LENGTH8(cdb.field, sizeof(buf));
scsi_mmc_run_cmd(p_cdio, 2000, &cdb, SCSI_MMC_DATA_READ, sizeof(buf), buf);
if (buf[7] == 0xA0) {
if (buf[13] == 0x00) {
if (buf[5] & 0x04)
return CDIO_DISC_MODE_CD_DATA;
else
return CDIO_DISC_MODE_CD_DA;
}
else if (buf[13] == 0x10)
return CDIO_DISC_MODE_CD_I;
else if (buf[13] == 0x20)
return CDIO_DISC_MODE_CD_XA;
}
return CDIO_DISC_MODE_NO_INFO;
}
/*!
On input a MODE_SENSE command was issued and we have the results
in p. We interpret this and return a bit mask set according to the
capabilities.
*/
void
scsi_mmc_get_drive_cap_buf(const uint8_t *p,
/*out*/ cdio_drive_read_cap_t *p_read_cap,
/*out*/ cdio_drive_write_cap_t *p_write_cap,
/*out*/ cdio_drive_misc_cap_t *p_misc_cap)
{
/* Reader */
if (p[2] & 0x01) *p_read_cap |= CDIO_DRIVE_CAP_READ_CD_R;
if (p[2] & 0x02) *p_read_cap |= CDIO_DRIVE_CAP_READ_CD_RW;
if (p[2] & 0x08) *p_read_cap |= CDIO_DRIVE_CAP_READ_DVD_ROM;
if (p[4] & 0x01) *p_read_cap |= CDIO_DRIVE_CAP_READ_AUDIO;
if (p[4] & 0x10) *p_read_cap |= CDIO_DRIVE_CAP_READ_MODE2_FORM1;
if (p[4] & 0x20) *p_read_cap |= CDIO_DRIVE_CAP_READ_MODE2_FORM2;
if (p[5] & 0x01) *p_read_cap |= CDIO_DRIVE_CAP_READ_CD_DA;
if (p[5] & 0x10) *p_read_cap |= CDIO_DRIVE_CAP_READ_C2_ERRS;
if (p[5] & 0x20) *p_read_cap |= CDIO_DRIVE_CAP_READ_ISRC;
/* Writer */
if (p[3] & 0x01) *p_write_cap |= CDIO_DRIVE_CAP_WRITE_CD_R;
if (p[3] & 0x02) *p_write_cap |= CDIO_DRIVE_CAP_WRITE_CD_RW;
if (p[3] & 0x10) *p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_R;
if (p[3] & 0x20) *p_write_cap |= CDIO_DRIVE_CAP_WRITE_DVD_RAM;
if (p[4] & 0x80) *p_misc_cap |= CDIO_DRIVE_CAP_WRITE_BURN_PROOF;
/* Misc */
if (p[4] & 0x40) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_MULTI_SESSION;
if (p[6] & 0x01) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_LOCK;
if (p[6] & 0x08) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_EJECT;
if (p[6] >> 5 != 0)
*p_misc_cap |= CDIO_DRIVE_CAP_MISC_CLOSE_TRAY;
}
/*!
Return the number of length in bytes of the Command Descriptor
buffer (CDB) for a given SCSI MMC command. The length will be
either 6, 10, or 12.
*/
uint8_t
scsi_mmc_get_cmd_len(uint8_t scsi_cmd)
{
static const uint8_t scsi_cdblen[8] = {6, 10, 10, 12, 12, 12, 10, 10};
return scsi_cdblen[((scsi_cmd >> 5) & 7)];
}
/*!
Run a SCSI MMC command.
cdio CD structure set by cdio_open().
i_timeout time in milliseconds we will wait for the command
to complete. If this value is -1, use the default
time-out value.
buf Buffer for data, both sending and receiving
len 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.
We return 0 if command completed successfully and 1 if not.
*/
int
scsi_mmc_run_cmd( const CdIo *p_cdio, unsigned int i_timeout_ms,
const scsi_mmc_cdb_t *p_cdb,
scsi_mmc_direction_t e_direction, unsigned int i_buf,
/*in/out*/ void *p_buf )
{
if (p_cdio && p_cdio->op.run_scsi_mmc_cmd) {
return p_cdio->op.run_scsi_mmc_cmd(p_cdio->env, i_timeout_ms,
scsi_mmc_get_cmd_len(p_cdb->field[0]),
p_cdb, e_direction, i_buf, p_buf);
} else
return 1;
}
#define DEFAULT_TIMEOUT_MS 6000
int
scsi_mmc_get_blocksize_private ( const void *p_env,
const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd)
{
int i_status = 0;
scsi_mmc_cdb_t cdb = {{0, }};
struct
{
uint8_t reserved1;
uint8_t medium;
uint8_t reserved2;
uint8_t block_desc_length;
uint8_t density;
uint8_t number_of_blocks_hi;
uint8_t number_of_blocks_med;
uint8_t number_of_blocks_lo;
uint8_t reserved3;
uint8_t block_length_hi;
uint8_t block_length_med;
uint8_t block_length_lo;
} mh;
uint8_t *p = &mh.block_length_med;
if ( ! p_env || ! run_scsi_mmc_cmd )
return -2;
memset (&mh, 0, sizeof (mh));
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SENSE);
cdb.field[1] = 0x3F&1;
cdb.field[4] = 12;
i_status = run_scsi_mmc_cmd (p_env, DEFAULT_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]), &cdb,
SCSI_MMC_DATA_WRITE, sizeof(mh), &mh);
if (0 != i_status) return -2;
return CDIO_MMC_GET_LEN16(p);
}
int
scsi_mmc_get_blocksize ( const CdIo *p_cdio)
{
if ( ! p_cdio ) return -2;
return
scsi_mmc_get_blocksize_private (p_cdio->env, p_cdio->op.run_scsi_mmc_cmd);
}
/*!
* Eject using SCSI MMC commands. Return 0 if successful.
*/
int
scsi_mmc_eject_media( const CdIo *p_cdio )
{
int i_status = 0;
scsi_mmc_cdb_t cdb = {{0, }};
uint8_t buf[1];
scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd;
if ( ! p_cdio || ! p_cdio->op.run_scsi_mmc_cmd )
return -2;
run_scsi_mmc_cmd = p_cdio->op.run_scsi_mmc_cmd;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_ALLOW_MEDIUM_REMOVAL);
i_status = run_scsi_mmc_cmd (p_cdio->env, DEFAULT_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]), &cdb,
SCSI_MMC_DATA_WRITE, 0, &buf);
if (0 != i_status) return i_status;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_START_STOP);
cdb.field[4] = 1;
i_status = run_scsi_mmc_cmd (p_cdio->env, DEFAULT_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]), &cdb,
SCSI_MMC_DATA_WRITE, 0, &buf);
if (0 != i_status)
return i_status;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_START_STOP);
cdb.field[4] = 2; /* eject */
return run_scsi_mmc_cmd (p_cdio->env, DEFAULT_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]), &cdb,
SCSI_MMC_DATA_WRITE, 0, &buf);
}
/*! Packet driver to read mode2 sectors.
Can read only up to 25 blocks.
*/
int
scsi_mmc_read_sectors ( const CdIo *p_cdio, void *p_buf, lba_t lba,
int sector_type, unsigned int nblocks )
{
scsi_mmc_cdb_t cdb = {{0, }};
scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd;
if ( ! p_cdio || ! p_cdio->op.run_scsi_mmc_cmd )
return -2;
run_scsi_mmc_cmd = p_cdio->op.run_scsi_mmc_cmd;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_CD);
CDIO_MMC_SET_READ_TYPE (cdb.field, sector_type);
CDIO_MMC_SET_READ_LBA (cdb.field, lba);
CDIO_MMC_SET_READ_LENGTH24(cdb.field, nblocks);
CDIO_MMC_SET_MAIN_CHANNEL_SELECTION_BITS(cdb.field,
CDIO_MMC_MCSB_ALL_HEADERS);
return run_scsi_mmc_cmd (p_cdio->env, DEFAULT_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]), &cdb,
SCSI_MMC_DATA_READ,
CDIO_CD_FRAMESIZE_RAW * nblocks,
p_buf);
}
int
scsi_mmc_set_blocksize_private ( const void *p_env,
const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd,
unsigned int i_bsize)
{
scsi_mmc_cdb_t cdb = {{0, }};
struct
{
uint8_t reserved1;
uint8_t medium;
uint8_t reserved2;
uint8_t block_desc_length;
uint8_t density;
uint8_t number_of_blocks_hi;
uint8_t number_of_blocks_med;
uint8_t number_of_blocks_lo;
uint8_t reserved3;
uint8_t block_length_hi;
uint8_t block_length_med;
uint8_t block_length_lo;
} mh;
if ( ! p_env || ! run_scsi_mmc_cmd )
return -2;
memset (&mh, 0, sizeof (mh));
mh.block_desc_length = 0x08;
mh.block_length_hi = (i_bsize >> 16) & 0xff;
mh.block_length_med = (i_bsize >> 8) & 0xff;
mh.block_length_lo = (i_bsize >> 0) & 0xff;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SELECT_6);
cdb.field[1] = 1 << 4;
cdb.field[4] = 12;
return run_scsi_mmc_cmd (p_env, DEFAULT_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]), &cdb,
SCSI_MMC_DATA_WRITE, sizeof(mh), &mh);
}
int
scsi_mmc_set_blocksize ( const CdIo *p_cdio, unsigned int i_bsize)
{
if ( ! p_cdio ) return -2;
return
scsi_mmc_set_blocksize_private (p_cdio->env, p_cdio->op.run_scsi_mmc_cmd,
i_bsize);
}
/*!
Return the the kind of drive capabilities of device.
*/
void
scsi_mmc_get_drive_cap_private (const void *p_env,
const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd,
/*out*/ cdio_drive_read_cap_t *p_read_cap,
/*out*/ cdio_drive_write_cap_t *p_write_cap,
/*out*/ cdio_drive_misc_cap_t *p_misc_cap)
{
/* Largest buffer size we use. */
#define BUF_MAX 2048
uint8_t buf[BUF_MAX] = { 0, };
scsi_mmc_cdb_t cdb = {{0, }};
int i_status;
uint16_t i_data = BUF_MAX;
if ( ! p_env || ! run_scsi_mmc_cmd )
return;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_MODE_SENSE_10);
cdb.field[1] = 0x0;
cdb.field[2] = CDIO_MMC_ALL_PAGES;
retry:
CDIO_MMC_SET_READ_LENGTH16(cdb.field, 8);
/* In the first run we run MODE SENSE 10 we are trying to get the
length of the data features. */
i_status = run_scsi_mmc_cmd (p_env, DEFAULT_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
sizeof(buf), &buf);
if (0 == i_status) {
uint16_t i_data_try = (uint16_t) CDIO_MMC_GET_LEN16(buf);
if (i_data_try < BUF_MAX) i_data = i_data_try;
}
/* Now try getting all features with length set above, possibly
truncated or the default length if we couldn't get the proper
length. */
CDIO_MMC_SET_READ_LENGTH16(cdb.field, i_data);
i_status = run_scsi_mmc_cmd (p_env, DEFAULT_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
sizeof(buf), &buf);
if (0 != i_status && CDIO_MMC_CAPABILITIES_PAGE != cdb.field[2]) {
cdb.field[2] = CDIO_MMC_CAPABILITIES_PAGE;
goto retry;
}
if (0 == i_status) {
uint8_t *p;
uint8_t *p_max = buf + 256;
*p_read_cap = 0;
*p_write_cap = 0;
*p_misc_cap = 0;
/* set to first sense mask, and then walk through the masks */
p = buf + 8;
while( (p < &(buf[2+i_data])) && (p < p_max) ) {
uint8_t which_page;
which_page = p[0] & 0x3F;
switch( which_page )
{
case CDIO_MMC_AUDIO_CTL_PAGE:
case CDIO_MMC_R_W_ERROR_PAGE:
case CDIO_MMC_CDR_PARMS_PAGE:
/* Don't handle these yet. */
break;
case CDIO_MMC_CAPABILITIES_PAGE:
scsi_mmc_get_drive_cap_buf(p, p_read_cap, p_write_cap, p_misc_cap);
break;
default: ;
}
p += (p[1] + 2);
}
} else {
cdio_info("%s: %s\n", "error in MODE_SELECT", strerror(errno));
*p_read_cap = CDIO_DRIVE_CAP_ERROR;
*p_write_cap = CDIO_DRIVE_CAP_ERROR;
*p_misc_cap = CDIO_DRIVE_CAP_ERROR;
}
return;
}
void
scsi_mmc_get_drive_cap (const CdIo *p_cdio,
/*out*/ cdio_drive_read_cap_t *p_read_cap,
/*out*/ cdio_drive_write_cap_t *p_write_cap,
/*out*/ cdio_drive_misc_cap_t *p_misc_cap)
{
if ( ! p_cdio ) return;
scsi_mmc_get_drive_cap_private (p_cdio->env,
p_cdio->op.run_scsi_mmc_cmd,
p_read_cap, p_write_cap, p_misc_cap);
}
void
scsi_mmc_get_drive_cap_generic (const void *p_user_data,
/*out*/ cdio_drive_read_cap_t *p_read_cap,
/*out*/ cdio_drive_write_cap_t *p_write_cap,
/*out*/ cdio_drive_misc_cap_t *p_misc_cap)
{
const generic_img_private_t *p_env = p_user_data;
scsi_mmc_get_drive_cap( p_env->cdio,
p_read_cap, p_write_cap, p_misc_cap );
}
/*!
Get the DVD type associated with cd object.
*/
discmode_t
scsi_mmc_get_dvd_struct_physical_private ( void *p_env, const
scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd,
cdio_dvd_struct_t *s)
{
scsi_mmc_cdb_t cdb = {{0, }};
unsigned char buf[4 + 4 * 20], *base;
int i_status;
uint8_t layer_num = s->physical.layer_num;
cdio_dvd_layer_t *layer;
if ( ! p_env || ! run_scsi_mmc_cmd )
return -2;
if (layer_num >= CDIO_DVD_MAX_LAYERS)
return -EINVAL;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_DVD_STRUCTURE);
cdb.field[6] = layer_num;
cdb.field[7] = CDIO_DVD_STRUCT_PHYSICAL;
cdb.field[9] = sizeof(buf) & 0xff;
i_status = run_scsi_mmc_cmd(p_env, DEFAULT_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
sizeof(buf), &buf);
if (0 != i_status)
return CDIO_DISC_MODE_ERROR;
base = &buf[4];
layer = &s->physical.layer[layer_num];
/*
* place the data... really ugly, but at least we won't have to
* worry about endianess in userspace.
*/
memset(layer, 0, sizeof(*layer));
layer->book_version = base[0] & 0xf;
layer->book_type = base[0] >> 4;
layer->min_rate = base[1] & 0xf;
layer->disc_size = base[1] >> 4;
layer->layer_type = base[2] & 0xf;
layer->track_path = (base[2] >> 4) & 1;
layer->nlayers = (base[2] >> 5) & 3;
layer->track_density = base[3] & 0xf;
layer->linear_density = base[3] >> 4;
layer->start_sector = base[5] << 16 | base[6] << 8 | base[7];
layer->end_sector = base[9] << 16 | base[10] << 8 | base[11];
layer->end_sector_l0 = base[13] << 16 | base[14] << 8 | base[15];
layer->bca = base[16] >> 7;
return 0;
}
/*!
Get the DVD type associated with cd object.
*/
discmode_t
scsi_mmc_get_dvd_struct_physical ( const CdIo *p_cdio, cdio_dvd_struct_t *s)
{
if ( ! p_cdio ) return -2;
return
scsi_mmc_get_dvd_struct_physical_private (p_cdio->env,
p_cdio->op.run_scsi_mmc_cmd,
s);
}
/*!
Get the CD-ROM hardware info via a SCSI MMC INQUIRY command.
False is returned if we had an error getting the information.
*/
bool
scsi_mmc_get_hwinfo ( const CdIo *p_cdio,
/*out*/ cdio_hwinfo_t *hw_info )
{
int i_status; /* Result of SCSI MMC command */
char buf[36] = { 0, }; /* Place to hold returned data */
scsi_mmc_cdb_t cdb = {{0, }}; /* Command Descriptor Block */
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_INQUIRY);
cdb.field[4] = sizeof(buf);
if (! p_cdio || ! hw_info ) return false;
i_status = scsi_mmc_run_cmd(p_cdio, DEFAULT_TIMEOUT_MS,
&cdb, SCSI_MMC_DATA_READ,
sizeof(buf), &buf);
if (i_status == 0) {
memcpy(hw_info->psz_vendor,
buf + 8,
sizeof(hw_info->psz_vendor)-1);
hw_info->psz_vendor[sizeof(hw_info->psz_vendor)-1] = '\0';
memcpy(hw_info->psz_model,
buf + 8 + CDIO_MMC_HW_VENDOR_LEN,
sizeof(hw_info->psz_model)-1);
hw_info->psz_model[sizeof(hw_info->psz_model)-1] = '\0';
memcpy(hw_info->psz_revision,
buf + 8 + CDIO_MMC_HW_VENDOR_LEN + CDIO_MMC_HW_MODEL_LEN,
sizeof(hw_info->psz_revision)-1);
hw_info->psz_revision[sizeof(hw_info->psz_revision)-1] = '\0';
return true;
}
return false;
}
/*!
Return the media catalog number MCN.
Note: string is malloc'd so caller should free() then returned
string when done with it.
*/
char *
scsi_mmc_get_mcn_private ( void *p_env,
const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd
)
{
scsi_mmc_cdb_t cdb = {{0, }};
char buf[28] = { 0, };
int i_status;
if ( ! p_env || ! run_scsi_mmc_cmd )
return NULL;
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_SUBCHANNEL);
cdb.field[1] = 0x0;
cdb.field[2] = 0x40;
cdb.field[3] = CDIO_SUBCHANNEL_MEDIA_CATALOG;
CDIO_MMC_SET_READ_LENGTH16(cdb.field, sizeof(buf));
i_status = run_scsi_mmc_cmd(p_env, DEFAULT_TIMEOUT_MS,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
sizeof(buf), buf);
if(i_status == 0) {
return strdup(&buf[9]);
}
return NULL;
}
char *
scsi_mmc_get_mcn ( const CdIo *p_cdio )
{
if ( ! p_cdio ) return NULL;
return scsi_mmc_get_mcn_private (p_cdio->env,
p_cdio->op.run_scsi_mmc_cmd );
}
char *
scsi_mmc_get_mcn_generic (const void *p_user_data)
{
const generic_img_private_t *p_env = p_user_data;
return scsi_mmc_get_mcn( p_env->cdio );
}
/*
Read cdtext information for a CdIo object .
return true on success, false on error or CD-Text information does
not exist.
*/
bool
scsi_mmc_init_cdtext_private ( void *p_user_data,
const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd,
set_cdtext_field_fn_t set_cdtext_field_fn
)
{
generic_img_private_t *p_env = p_user_data;
scsi_mmc_cdb_t cdb = {{0, }};
unsigned char wdata[5000] = { 0, };
int i_status, i_errno;
if ( ! p_env || ! run_scsi_mmc_cmd || p_env->b_cdtext_error )
return false;
/* Operation code */
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_READ_TOC);
cdb.field[1] = CDIO_CDROM_MSF;
/* Format */
cdb.field[2] = CDIO_MMC_READTOC_FMT_CDTEXT;
/* Setup to read header, to get length of data */
CDIO_MMC_SET_READ_LENGTH16(cdb.field, 4);
errno = 0;
/* Set read timeout 3 minues. */
#define READ_TIMEOUT 3*60*1000
/* We may need to give CD-Text a little more time to complete. */
/* First off, just try and read the size */
i_status = run_scsi_mmc_cmd (p_env, READ_TIMEOUT,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
4, &wdata);
if (i_status != 0) {
cdio_info ("CD-Text read failed for header: %s\n", strerror(errno));
i_errno = errno;
p_env->b_cdtext_error = true;
return false;
} else {
/* Now read the CD-Text data */
int i_cdtext = CDIO_MMC_GET_LEN16(wdata);
if (i_cdtext > sizeof(wdata)) i_cdtext = sizeof(wdata);
CDIO_MMC_SET_READ_LENGTH16(cdb.field, i_cdtext);
i_status = run_scsi_mmc_cmd (p_env, READ_TIMEOUT,
scsi_mmc_get_cmd_len(cdb.field[0]),
&cdb, SCSI_MMC_DATA_READ,
i_cdtext, &wdata);
if (i_status != 0) {
cdio_info ("CD-Text read for text failed: %s\n", strerror(errno));
i_errno = errno;
p_env->b_cdtext_error = true;
return false;
}
p_env->b_cdtext_init = true;
return cdtext_data_init(p_env, p_env->i_first_track, wdata,
set_cdtext_field_fn);
}
}

View File

@@ -0,0 +1,105 @@
/* private MMC helper routines.
$Id: scsi_mmc_private.h,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <cdio/scsi_mmc.h>
#include "cdtext_private.h"
/*! Convert milliseconds to seconds taking the ceiling value, i.e.
1002 milliseconds gets rounded to 2 seconds.
*/
#define SECS2MSECS 1000
static inline unsigned int
msecs2secs(unsigned int msecs)
{
return (msecs+(SECS2MSECS-1)) / SECS2MSECS;
}
#undef SECS2MSECS
typedef
int (*scsi_mmc_run_cmd_fn_t) ( const void *p_user_data,
unsigned int i_timeout_ms,
unsigned int i_cdb,
const scsi_mmc_cdb_t *p_cdb,
scsi_mmc_direction_t e_direction,
unsigned int i_buf, /*in/out*/ void *p_buf );
int scsi_mmc_set_blocksize_mmc_private ( const void *p_env, const
scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd,
unsigned int bsize );
/*!
Get the DVD type associated with cd object.
*/
discmode_t
scsi_mmc_get_dvd_struct_physical_private ( void *p_env, const
scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd,
cdio_dvd_struct_t *s );
int
scsi_mmc_get_blocksize_private ( const void *p_env,
const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd);
char *scsi_mmc_get_mcn_private ( void *p_env,
const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd
);
char *scsi_mmc_get_mcn_generic (const void *p_user_data);
bool scsi_mmc_init_cdtext_private ( void *user_data, const
scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd,
set_cdtext_field_fn_t set_cdtext_field_fn
);
/*!
On input a MODE_SENSE command was issued and we have the results
in p. We interpret this and return a bit mask set according to the
capabilities.
*/
void scsi_mmc_get_drive_cap_buf(const uint8_t *p,
/*out*/ cdio_drive_read_cap_t *p_read_cap,
/*out*/ cdio_drive_write_cap_t *p_write_cap,
/*out*/ cdio_drive_misc_cap_t *p_misc_cap);
/*!
Return the the kind of drive capabilities of device.
Note: string is malloc'd so caller should free() then returned
string when done with it.
*/
void
scsi_mmc_get_drive_cap_private (const void *p_env,
const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd,
/*out*/ cdio_drive_read_cap_t *p_read_cap,
/*out*/ cdio_drive_write_cap_t *p_write_cap,
/*out*/ cdio_drive_misc_cap_t *p_misc_cap);
void
scsi_mmc_get_drive_cap_generic (const void *p_user_data,
/*out*/ cdio_drive_read_cap_t *p_read_cap,
/*out*/ cdio_drive_write_cap_t *p_write_cap,
/*out*/ cdio_drive_misc_cap_t *p_misc_cap);
int
scsi_mmc_set_blocksize_private ( const void *p_env,
const scsi_mmc_run_cmd_fn_t run_scsi_mmc_cmd,
unsigned int i_bsize);

290
lib/driver/sector.c Normal file
View File

@@ -0,0 +1,290 @@
/*
$Id: sector.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2004 Rocky Bernstein <rocky@panix.com>
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <cdio/sector.h>
#include <cdio/util.h>
#include <cdio/logging.h>
#include "cdio_assert.h"
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <ctype.h>
static const char _rcsid[] = "$Id: sector.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
lba_t
cdio_lba_to_lsn (lba_t lba)
{
if (CDIO_INVALID_LBA == lba) return CDIO_INVALID_LSN;
return lba - CDIO_PREGAP_SECTORS;
}
/*
The below is adapted from cdparanoia code which claims it is
straight from the MMC3 spec.
*/
void
cdio_lsn_to_msf (lsn_t lsn, msf_t *msf)
{
int m, s, f;
cdio_assert (msf != 0);
if ( lsn >= -CDIO_PREGAP_SECTORS ){
m = (lsn + CDIO_PREGAP_SECTORS) / CDIO_CD_FRAMES_PER_MIN;
lsn -= m * CDIO_CD_FRAMES_PER_MIN;
s = (lsn + CDIO_PREGAP_SECTORS) / CDIO_CD_FRAMES_PER_SEC;
lsn -= s * CDIO_CD_FRAMES_PER_SEC;
f = lsn + CDIO_PREGAP_SECTORS;
} else {
m = (lsn + CDIO_CD_MAX_LSN) / CDIO_CD_FRAMES_PER_MIN;
lsn -= m * (CDIO_CD_FRAMES_PER_MIN);
s = (lsn+CDIO_CD_MAX_LSN) / CDIO_CD_FRAMES_PER_SEC;
lsn -= s * CDIO_CD_FRAMES_PER_SEC;
f = lsn + CDIO_CD_MAX_LSN;
}
if (m > 99) {
cdio_warn ("number of minutes (%d) truncated to 99.", m);
m = 99;
}
msf->m = cdio_to_bcd8 (m);
msf->s = cdio_to_bcd8 (s);
msf->f = cdio_to_bcd8 (f);
}
/*!
Convert an LBA into a string representation of the MSF.
\warning cdio_lba_to_msf_str returns new allocated string */
char *
cdio_lba_to_msf_str (lba_t lba)
{
if (CDIO_INVALID_LBA == lba) {
return strdup("*INVALID");
} else {
msf_t msf;
msf.m = msf.s = msf.f = 0;
cdio_lba_to_msf (lba, &msf);
return cdio_msf_to_str(&msf);
}
}
/*!
Convert an LSN into the corresponding LBA.
CDIO_INVALID_LBA is returned if there is an error.
*/
lba_t
cdio_lsn_to_lba (lsn_t lsn)
{
if (CDIO_INVALID_LSN == lsn) return CDIO_INVALID_LBA;
return lsn + CDIO_PREGAP_SECTORS;
}
/*!
Convert an LBA into the corresponding MSF.
*/
void
cdio_lba_to_msf (lba_t lba, msf_t *msf)
{
cdio_assert (msf != 0);
cdio_lsn_to_msf(cdio_lba_to_lsn(lba), msf);
}
/*!
Convert a MSF into the corresponding LBA.
CDIO_INVALID_LBA is returned if there is an error.
*/
lba_t
cdio_msf_to_lba (const msf_t *msf)
{
uint32_t lba = 0;
cdio_assert (msf != 0);
lba = cdio_from_bcd8 (msf->m);
lba *= CDIO_CD_SECS_PER_MIN;
lba += cdio_from_bcd8 (msf->s);
lba *= CDIO_CD_FRAMES_PER_SEC;
lba += cdio_from_bcd8 (msf->f);
return lba;
}
/*!
Convert a MSF into the corresponding LSN.
CDIO_INVALID_LSN is returned if there is an error.
*/
lba_t
cdio_msf_to_lsn (const msf_t *msf)
{
return cdio_lba_to_lsn(cdio_msf_to_lba (msf));
}
/*!
Convert an LBA into a string representation of the MSF.
\warning cdio_lba_to_msf_str returns new allocated string */
char *
cdio_msf_to_str (const msf_t *msf)
{
char buf[16];
snprintf (buf, sizeof (buf), "%2.2x:%2.2x:%2.2x", msf->m, msf->s, msf->f);
return strdup (buf);
}
/*!
Convert a MSF - broken out as 3 integer components into the
corresponding LBA.
CDIO_INVALID_LBA is returned if there is an error.
*/
lba_t
cdio_msf3_to_lba (unsigned int minutes, unsigned int seconds,
unsigned int frames)
{
return ((minutes * CDIO_CD_SECS_PER_MIN + seconds) * CDIO_CD_FRAMES_PER_SEC
+ frames);
}
/*!
Convert a string of the form MM:SS:FF into the corresponding LBA.
CDIO_INVALID_LBA is returned if there is an error.
*/
lba_t
cdio_mmssff_to_lba (const char *psz_mmssff)
{
int psz_field;
lba_t ret;
char c;
if (0 == strcmp (psz_mmssff, "0"))
return 0;
c = *psz_mmssff++;
if(c >= '0' && c <= '9')
psz_field = (c - '0');
else
return CDIO_INVALID_LBA;
while(':' != (c = *psz_mmssff++)) {
if(c >= '0' && c <= '9')
psz_field = psz_field * 10 + (c - '0');
else
return CDIO_INVALID_LBA;
}
ret = cdio_msf3_to_lba (psz_field, 0, 0);
c = *psz_mmssff++;
if(c >= '0' && c <= '9')
psz_field = (c - '0');
else
return CDIO_INVALID_LBA;
if(':' != (c = *psz_mmssff++)) {
if(c >= '0' && c <= '9') {
psz_field = psz_field * 10 + (c - '0');
c = *psz_mmssff++;
if(c != ':')
return CDIO_INVALID_LBA;
}
else
return CDIO_INVALID_LBA;
}
if(psz_field >= CDIO_CD_SECS_PER_MIN)
return CDIO_INVALID_LBA;
ret += cdio_msf3_to_lba (0, psz_field, 0);
c = *psz_mmssff++;
if (isdigit(c))
psz_field = (c - '0');
else
return -1;
if('\0' != (c = *psz_mmssff++)) {
if (isdigit(c)) {
psz_field = psz_field * 10 + (c - '0');
c = *psz_mmssff++;
}
else
return CDIO_INVALID_LBA;
}
if('\0' != c)
return CDIO_INVALID_LBA;
if(psz_field >= CDIO_CD_FRAMES_PER_SEC)
return CDIO_INVALID_LBA;
ret += psz_field;
return ret;
}
bool
cdio_is_discmode_cdrom(discmode_t discmode)
{
switch (discmode) {
case CDIO_DISC_MODE_CD_DA:
case CDIO_DISC_MODE_CD_DATA:
case CDIO_DISC_MODE_CD_XA:
case CDIO_DISC_MODE_CD_MIXED:
case CDIO_DISC_MODE_NO_INFO:
return true;
default:
return false;
}
}
bool
cdio_is_discmode_dvd(discmode_t discmode)
{
switch (discmode) {
case CDIO_DISC_MODE_DVD_ROM:
case CDIO_DISC_MODE_DVD_RAM:
case CDIO_DISC_MODE_DVD_R:
case CDIO_DISC_MODE_DVD_RW:
case CDIO_DISC_MODE_DVD_PR:
case CDIO_DISC_MODE_DVD_PRW:
return true;
default:
return false;
}
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/

197
lib/driver/util.c Normal file
View File

@@ -0,0 +1,197 @@
/*
$Id: util.c,v 1.1 2004/12/18 17:29:32 rocky Exp $
Copyright (C) 2000 Herbert Valerio Riedel <hvr@gnu.org>
Copyright (C) 2003, 2004 Rocky Bernstein <rocky@panix.com>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#ifdef HAVE_INTTYPES_H
#include "inttypes.h"
#endif
#include "cdio_assert.h"
#include <cdio/types.h>
#include <cdio/util.h>
static const char _rcsid[] = "$Id: util.c,v 1.1 2004/12/18 17:29:32 rocky Exp $";
size_t
_cdio_strlenv(char **str_array)
{
size_t n = 0;
cdio_assert (str_array != NULL);
while(str_array[n])
n++;
return n;
}
void
_cdio_strfreev(char **strv)
{
int n;
cdio_assert (strv != NULL);
for(n = 0; strv[n]; n++)
free(strv[n]);
free(strv);
}
char *
_cdio_strjoin (char *strv[], unsigned count, const char delim[])
{
size_t len;
char *new_str;
unsigned n;
cdio_assert (strv != NULL);
cdio_assert (delim != NULL);
len = (count-1) * strlen (delim);
for (n = 0;n < count;n++)
len += strlen (strv[n]);
len++;
new_str = _cdio_malloc (len);
new_str[0] = '\0';
for (n = 0;n < count;n++)
{
if (n)
strcat (new_str, delim);
strcat (new_str, strv[n]);
}
return new_str;
}
char **
_cdio_strsplit(const char str[], char delim) /* fixme -- non-reentrant */
{
int n;
char **strv = NULL;
char *_str, *p;
char _delim[2] = { 0, 0 };
cdio_assert (str != NULL);
_str = strdup(str);
_delim[0] = delim;
cdio_assert (_str != NULL);
n = 1;
p = _str;
while(*p)
if (*(p++) == delim)
n++;
strv = _cdio_malloc (sizeof (char *) * (n+1));
n = 0;
while((p = strtok(n ? NULL : _str, _delim)) != NULL)
strv[n++] = strdup(p);
free(_str);
return strv;
}
void *
_cdio_malloc (size_t size)
{
void *new_mem = malloc (size);
cdio_assert (new_mem != NULL);
memset (new_mem, 0, size);
return new_mem;
}
void *
_cdio_memdup (const void *mem, size_t count)
{
void *new_mem = NULL;
if (mem)
{
new_mem = _cdio_malloc (count);
memcpy (new_mem, mem, count);
}
return new_mem;
}
char *
_cdio_strdup_upper (const char str[])
{
char *new_str = NULL;
if (str)
{
char *p;
p = new_str = strdup (str);
while (*p)
{
*p = toupper (*p);
p++;
}
}
return new_str;
}
uint8_t
cdio_to_bcd8 (uint8_t n)
{
/*cdio_assert (n < 100);*/
return ((n/10)<<4) | (n%10);
}
uint8_t
cdio_from_bcd8(uint8_t p)
{
return (0xf & p)+(10*(p >> 4));
}
/*
* Local variables:
* c-file-style: "gnu"
* tab-width: 8
* indent-tabs-mode: nil
* End:
*/