First commit after CVS conversion. Should be just administrative changes.
This commit is contained in:
3
lib/driver/.gitignore
vendored
Normal file
3
lib/driver/.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
/.deps
|
||||
/Makefile
|
||||
/Makefile.in
|
||||
22
lib/driver/FreeBSD/Makefile
Normal file
22
lib/driver/FreeBSD/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# $Id: Makefile,v 1.2 2008/04/21 18:30:19 karl Exp $
|
||||
#
|
||||
# Copyright (C) 2004, 2008 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# The make is done above. This boilerplate Makefile just transfers the call
|
||||
|
||||
|
||||
all install check clean:
|
||||
cd .. && $(MAKE) $@
|
||||
893
lib/driver/FreeBSD/freebsd.c
Normal file
893
lib/driver/FreeBSD/freebsd.c
Normal file
@@ -0,0 +1,893 @@
|
||||
/*
|
||||
$Id: freebsd.c,v 1.38 2008/04/21 18:30:20 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file contains 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.38 2008/04/21 18:30:20 karl Exp $";
|
||||
|
||||
#include "freebsd.h"
|
||||
|
||||
#ifdef HAVE_FREEBSD_CDROM
|
||||
|
||||
#ifdef HAVE_SYS_PARAM_H
|
||||
#include <sys/param.h>
|
||||
#endif
|
||||
|
||||
#include <netinet/in.h>
|
||||
|
||||
#include <cdio/sector.h>
|
||||
|
||||
static lba_t get_track_lba_freebsd(void *p_user_data, track_t i_track);
|
||||
|
||||
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 *p_obj)
|
||||
{
|
||||
_img_private_t *p_env = p_obj;
|
||||
|
||||
if (NULL == p_env) return;
|
||||
|
||||
if (NULL != p_env->device) free(p_env->device);
|
||||
|
||||
if (_AM_CAM == p_env->access_mode)
|
||||
return free_freebsd_cam(p_env);
|
||||
else
|
||||
return cdio_generic_free(p_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 i_blocks of audio sectors from cd device into data starting from lsn.
|
||||
Returns 0 if no error.
|
||||
*/
|
||||
static driver_return_code_t
|
||||
read_audio_sectors_freebsd (void *p_user_data, void *p_buf, lsn_t i_lsn,
|
||||
unsigned int i_blocks)
|
||||
{
|
||||
_img_private_t *p_env = p_user_data;
|
||||
if ( p_env->access_mode == _AM_CAM ) {
|
||||
return mmc_read_sectors( p_env->gen.cdio, p_buf, i_lsn,
|
||||
CDIO_MMC_READ_TYPE_CDDA, i_blocks);
|
||||
} else
|
||||
return read_audio_sectors_freebsd_ioctl(p_user_data, p_buf, i_lsn,
|
||||
i_blocks);
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads a single mode2 sector from cd device into data starting
|
||||
from i_lsn. Returns 0 if no error.
|
||||
*/
|
||||
static driver_return_code_t
|
||||
read_mode2_sector_freebsd (void *p_user_data, void *data, lsn_t i_lsn,
|
||||
bool b_form2)
|
||||
{
|
||||
_img_private_t *p_env = p_user_data;
|
||||
|
||||
if ( p_env->access_mode == _AM_CAM )
|
||||
return read_mode2_sector_freebsd_cam(p_env, data, i_lsn, b_form2);
|
||||
else
|
||||
return read_mode2_sector_freebsd_ioctl(p_env, data, i_lsn, b_form2);
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads i_blocks of mode2 sectors from cd device into data starting
|
||||
from lsn.
|
||||
*/
|
||||
static driver_return_code_t
|
||||
read_mode2_sectors_freebsd (void *p_user_data, void *p_data, lsn_t i_lsn,
|
||||
bool b_form2, unsigned int i_blocks)
|
||||
{
|
||||
_img_private_t *p_env = p_user_data;
|
||||
|
||||
if ( p_env->access_mode == _AM_CAM && b_form2 ) {
|
||||
/* We have a routine that covers this case without looping. */
|
||||
return read_mode2_sectors_freebsd_cam(p_env, p_data, i_lsn, i_blocks);
|
||||
} else {
|
||||
unsigned int i;
|
||||
uint16_t i_blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE;
|
||||
|
||||
/* For each frame, pick out the data part we need */
|
||||
for (i = 0; i < i_blocks; i++) {
|
||||
int retval = read_mode2_sector_freebsd (p_env,
|
||||
((char *)p_data) +
|
||||
(i_blocksize * i),
|
||||
i_lsn + i, b_form2);
|
||||
if (retval) return retval;
|
||||
}
|
||||
}
|
||||
return DRIVER_OP_SUCCESS;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the size of the CD in logical block address (LBA) units.
|
||||
@return the lsn. On error return CDIO_INVALID_LSN.
|
||||
*/
|
||||
static lsn_t
|
||||
get_disc_last_lsn_freebsd (void *p_obj)
|
||||
{
|
||||
_img_private_t *p_env = p_obj;
|
||||
|
||||
if (!p_env) return CDIO_INVALID_LSN;
|
||||
|
||||
if (_AM_CAM == p_env->access_mode)
|
||||
return get_disc_last_lsn_mmc(p_env);
|
||||
else
|
||||
return get_disc_last_lsn_freebsd_ioctl(p_env);
|
||||
}
|
||||
|
||||
/*!
|
||||
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
|
||||
|
||||
DRIVER_OP_SUCCESS is returned if no error was found,
|
||||
and nonzero if there as an error.
|
||||
*/
|
||||
static driver_return_code_t
|
||||
set_arg_freebsd (void *p_user_data, const char key[], const char value[])
|
||||
{
|
||||
_img_private_t *p_env = p_user_data;
|
||||
|
||||
if (!strcmp (key, "source"))
|
||||
{
|
||||
if (!value) return DRIVER_OP_ERROR;
|
||||
free (p_env->gen.source_name);
|
||||
p_env->gen.source_name = strdup (value);
|
||||
}
|
||||
else if (!strcmp (key, "access-mode"))
|
||||
{
|
||||
p_env->access_mode = str_to_access_mode_freebsd(value);
|
||||
if (p_env->access_mode == _AM_CAM && !p_env->b_cam_init)
|
||||
return init_freebsd_cam(p_env)
|
||||
? DRIVER_OP_SUCCESS : DRIVER_OP_ERROR;
|
||||
}
|
||||
else return DRIVER_OP_ERROR;
|
||||
|
||||
return DRIVER_OP_SUCCESS;
|
||||
|
||||
}
|
||||
|
||||
/* Set CD-ROM drive speed */
|
||||
static int
|
||||
set_speed_freebsd (void *p_user_data, int i_speed)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
|
||||
if (!p_env) return -1;
|
||||
#ifdef CDRIOCREADSPEED
|
||||
i_speed *= 177;
|
||||
return ioctl(p_env->gen.fd, CDRIOCREADSPEED, &i_speed);
|
||||
#else
|
||||
return -2;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*!
|
||||
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++) {
|
||||
struct ioc_read_toc_single_entry *p_toc =
|
||||
&(p_env->tocent[i-p_env->gen.i_first_track]);
|
||||
p_toc->track = i;
|
||||
p_toc->address_format = CD_LBA_FORMAT;
|
||||
|
||||
if ( ioctl(p_env->gen.fd, CDIOREADTOCENTRY, p_toc) ) {
|
||||
cdio_warn("%s %d: %s\n",
|
||||
"error in ioctl CDROMREADTOCENTRY for track",
|
||||
i, strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
set_track_flags(&(p_env->gen.track_flags[i]), p_toc->entry.control);
|
||||
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/*!
|
||||
Get the volume of an audio CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
*/
|
||||
static driver_return_code_t
|
||||
audio_get_volume_freebsd (void *p_user_data,
|
||||
/*out*/ cdio_audio_volume_t *p_volume)
|
||||
{
|
||||
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
return ioctl(p_env->gen.fd, CDIOCGETVOL, p_volume);
|
||||
}
|
||||
|
||||
/*!
|
||||
Pause playing CD through analog output
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
*/
|
||||
static driver_return_code_t
|
||||
audio_pause_freebsd (void *p_user_data)
|
||||
{
|
||||
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
return ioctl(p_env->gen.fd, CDIOCPAUSE);
|
||||
}
|
||||
|
||||
/*!
|
||||
Playing starting at given MSF through analog output
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
*/
|
||||
static driver_return_code_t
|
||||
audio_play_msf_freebsd (void *p_user_data, msf_t *p_start_msf,
|
||||
msf_t *p_end_msf)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
struct ioc_play_msf freebsd_play_msf;
|
||||
|
||||
freebsd_play_msf.start_m = cdio_from_bcd8(p_start_msf->m);
|
||||
freebsd_play_msf.start_s = cdio_from_bcd8(p_start_msf->s);
|
||||
freebsd_play_msf.start_f = cdio_from_bcd8(p_start_msf->f);
|
||||
|
||||
freebsd_play_msf.end_m = cdio_from_bcd8(p_end_msf->m);
|
||||
freebsd_play_msf.end_s = cdio_from_bcd8(p_end_msf->s);
|
||||
freebsd_play_msf.end_f = cdio_from_bcd8(p_end_msf->f);
|
||||
|
||||
return ioctl(p_env->gen.fd, CDIOCPLAYMSF, &freebsd_play_msf);
|
||||
}
|
||||
|
||||
/*!
|
||||
Playing CD through analog output at the desired track and index
|
||||
|
||||
@param p_user_data the CD object to be acted upon.
|
||||
@param p_track_index location to start/end.
|
||||
*/
|
||||
static driver_return_code_t
|
||||
audio_play_track_index_freebsd (void *p_user_data,
|
||||
cdio_track_index_t *p_track_index)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
msf_t start_msf;
|
||||
msf_t end_msf;
|
||||
struct ioc_play_msf freebsd_play_msf;
|
||||
lsn_t i_lsn = get_track_lba_freebsd(p_user_data,
|
||||
p_track_index->i_start_track);
|
||||
|
||||
cdio_lsn_to_msf(i_lsn, &start_msf);
|
||||
i_lsn = get_track_lba_freebsd(p_user_data, p_track_index->i_end_track);
|
||||
cdio_lsn_to_msf(i_lsn, &end_msf);
|
||||
|
||||
freebsd_play_msf.start_m = start_msf.m;
|
||||
freebsd_play_msf.start_s = start_msf.s;
|
||||
freebsd_play_msf.start_f = start_msf.f;
|
||||
|
||||
freebsd_play_msf.end_m = end_msf.m;
|
||||
freebsd_play_msf.end_s = end_msf.s;
|
||||
freebsd_play_msf.end_f = end_msf.f;
|
||||
|
||||
return ioctl(p_env->gen.fd, CDIOCPLAYMSF, &freebsd_play_msf);
|
||||
|
||||
}
|
||||
|
||||
/*!
|
||||
Read Audio Subchannel information
|
||||
|
||||
@param p_user_data the CD object to be acted upon.
|
||||
@param p_subchannel returned information
|
||||
*/
|
||||
#if 1
|
||||
static driver_return_code_t
|
||||
audio_read_subchannel_freebsd (void *p_user_data,
|
||||
/*out*/ cdio_subchannel_t *p_subchannel)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
int i_rc;
|
||||
struct cd_sub_channel_info bsdinfo;
|
||||
struct ioc_read_subchannel read_subchannel;
|
||||
memset(& bsdinfo, 0, sizeof(struct cd_sub_channel_info));
|
||||
read_subchannel.address_format = CD_MSF_FORMAT;
|
||||
read_subchannel.data_format = CD_CURRENT_POSITION;
|
||||
read_subchannel.track = 0;
|
||||
read_subchannel.data_len = sizeof(struct cd_sub_channel_info);
|
||||
read_subchannel.data = & bsdinfo;
|
||||
i_rc = ioctl(p_env->gen.fd, CDIOCREADSUBCHANNEL, &read_subchannel);
|
||||
if (0 == i_rc) {
|
||||
p_subchannel->audio_status = bsdinfo.header.audio_status;
|
||||
p_subchannel->address = bsdinfo.what.position.addr_type;
|
||||
|
||||
p_subchannel->control = bsdinfo.what.position.control;
|
||||
p_subchannel->track = bsdinfo.what.position.track_number;
|
||||
p_subchannel->index = bsdinfo.what.position.index_number;
|
||||
|
||||
p_subchannel->abs_addr.m = cdio_to_bcd8 (bsdinfo.what.position.absaddr.msf.minute);
|
||||
p_subchannel->abs_addr.s = cdio_to_bcd8 (bsdinfo.what.position.absaddr.msf.second);
|
||||
p_subchannel->abs_addr.f = cdio_to_bcd8 (bsdinfo.what.position.absaddr.msf.frame);
|
||||
p_subchannel->rel_addr.m = cdio_to_bcd8 (bsdinfo.what.position.reladdr.msf.minute);
|
||||
p_subchannel->rel_addr.s = cdio_to_bcd8 (bsdinfo.what.position.reladdr.msf.second);
|
||||
p_subchannel->rel_addr.f = cdio_to_bcd8 (bsdinfo.what.position.reladdr.msf.frame);
|
||||
}
|
||||
return i_rc;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Resume playing an audio CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
static driver_return_code_t
|
||||
audio_resume_freebsd (void *p_user_data)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
return ioctl(p_env->gen.fd, CDIOCRESUME, 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the volume of an audio CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
static driver_return_code_t
|
||||
audio_set_volume_freebsd (void *p_user_data,
|
||||
cdio_audio_volume_t *p_volume)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
return ioctl(p_env->gen.fd, CDIOCSETVOL, p_volume);
|
||||
}
|
||||
|
||||
/*!
|
||||
Eject media. Return 1 if successful, 0 otherwise.
|
||||
*/
|
||||
static int
|
||||
eject_media_freebsd (void *p_user_data)
|
||||
{
|
||||
_img_private_t *p_env = p_user_data;
|
||||
|
||||
return (p_env->access_mode == _AM_IOCTL)
|
||||
? eject_media_freebsd_ioctl(p_env)
|
||||
: eject_media_freebsd_cam(p_env);
|
||||
}
|
||||
|
||||
/*!
|
||||
Stop playing an audio CD.
|
||||
|
||||
@param p_user_data the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
static driver_return_code_t
|
||||
audio_stop_freebsd (void *p_user_data)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
return ioctl(p_env->gen.fd, CDIOCSTOP);
|
||||
}
|
||||
|
||||
/*!
|
||||
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)
|
||||
: 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)
|
||||
get_drive_cap_mmc (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
|
||||
*/
|
||||
static driver_return_code_t
|
||||
run_mmc_cmd_freebsd( void *p_user_data, unsigned int i_timeout_ms,
|
||||
unsigned int i_cdb, const mmc_cdb_t *p_cdb,
|
||||
cdio_mmc_direction_t e_direction,
|
||||
unsigned int i_buf, /*in/out*/ void *p_buf )
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
|
||||
if (p_env->access_mode == _AM_CAM)
|
||||
return run_mmc_cmd_freebsd_cam( p_user_data, i_timeout_ms, i_cdb, p_cdb,
|
||||
e_direction, i_buf, p_buf );
|
||||
else
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*!
|
||||
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*/
|
||||
}
|
||||
|
||||
/*!
|
||||
Close tray on CD-ROM.
|
||||
|
||||
@param psz_device the CD-ROM drive to be closed.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
close_tray_freebsd (const char *psz_device)
|
||||
{
|
||||
#ifdef HAVE_FREEBSD_CDROM
|
||||
int fd = open (psz_device, O_RDONLY|O_NONBLOCK, 0);
|
||||
int i_rc;
|
||||
|
||||
if((i_rc = ioctl(fd, CDIOCCLOSE)) != 0) {
|
||||
cdio_warn ("ioctl CDIOCCLOSE failed: %s\n", strerror(errno));
|
||||
return DRIVER_OP_ERROR;
|
||||
}
|
||||
close(fd);
|
||||
return DRIVER_OP_SUCCESS;
|
||||
#else
|
||||
return DRIVER_OP_NO_DRIVER;
|
||||
#endif /*HAVE_FREEBSD_CDROM*/
|
||||
}
|
||||
|
||||
#ifdef HAVE_FREEBSD_CDROM
|
||||
/*! Find out if media has changed since the last call. @param
|
||||
p_user_data the environment of the CD object to be acted upon.
|
||||
@return 1 if media has changed since last call, 0 if not. Error
|
||||
return codes are the same as driver_return_code_t
|
||||
*/
|
||||
static int
|
||||
get_media_changed_freebsd (const void *p_user_data)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
if ( p_env->access_mode == _AM_CAM ) {
|
||||
return mmc_get_media_changed( p_env->gen.cdio );
|
||||
}
|
||||
else
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
#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_t _funcs = {
|
||||
.audio_get_volume = audio_get_volume_freebsd,
|
||||
.audio_pause = audio_pause_freebsd,
|
||||
.audio_play_msf = audio_play_msf_freebsd,
|
||||
.audio_play_track_index = audio_play_track_index_freebsd,
|
||||
.audio_read_subchannel = audio_read_subchannel_freebsd,
|
||||
.audio_resume = audio_resume_freebsd,
|
||||
.audio_set_volume = audio_set_volume_freebsd,
|
||||
.audio_stop = audio_stop_freebsd,
|
||||
.eject_media = eject_media_freebsd,
|
||||
.free = free_freebsd,
|
||||
.get_arg = get_arg_freebsd,
|
||||
.get_blocksize = get_blocksize_mmc,
|
||||
.get_cdtext = get_cdtext_generic,
|
||||
.get_default_device = cdio_get_default_device_freebsd,
|
||||
.get_devices = cdio_get_devices_freebsd,
|
||||
.get_disc_last_lsn = get_disc_last_lsn_freebsd,
|
||||
.get_discmode = get_discmode_generic,
|
||||
.get_drive_cap = get_drive_cap_freebsd,
|
||||
.get_first_track_num = get_first_track_num_generic,
|
||||
.get_media_changed = get_media_changed_freebsd,
|
||||
.get_mcn = get_mcn_freebsd,
|
||||
.get_num_tracks = get_num_tracks_generic,
|
||||
.get_track_channels = get_track_channels_generic,
|
||||
.get_track_copy_permit = get_track_copy_permit_generic,
|
||||
.get_track_format = get_track_format_freebsd,
|
||||
.get_track_green = get_track_green_freebsd,
|
||||
.get_track_lba = get_track_lba_freebsd,
|
||||
.get_track_preemphasis = get_track_preemphasis_generic,
|
||||
.get_track_msf = NULL,
|
||||
.lseek = cdio_generic_lseek,
|
||||
.read = cdio_generic_read,
|
||||
.read_audio_sectors = read_audio_sectors_freebsd,
|
||||
.read_data_sectors = read_data_sectors_mmc,
|
||||
.read_mode2_sector = read_mode2_sector_freebsd,
|
||||
.read_mode2_sectors = read_mode2_sectors_freebsd,
|
||||
.read_toc = read_toc_freebsd,
|
||||
.run_mmc_cmd = run_mmc_cmd_freebsd,
|
||||
.set_arg = set_arg_freebsd,
|
||||
.set_blocksize = set_blocksize_mmc,
|
||||
.set_speed = set_speed_freebsd,
|
||||
};
|
||||
|
||||
_data = calloc(1, 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
|
||||
free(_data);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ret = cdio_new ((void *)_data, &_funcs);
|
||||
if (ret == NULL) return NULL;
|
||||
|
||||
if (cdio_generic_init(_data, O_RDONLY))
|
||||
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 */
|
||||
}
|
||||
232
lib/driver/FreeBSD/freebsd.h
Normal file
232
lib/driver/FreeBSD/freebsd.h
Normal file
@@ -0,0 +1,232 @@
|
||||
/*
|
||||
$Id: freebsd.h,v 1.10 2008/05/11 09:50:54 rocky Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file contains 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 DEFAULT_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) && (__FreeBSD_kernel_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);
|
||||
|
||||
driver_return_code_t eject_media_freebsd_ioctl (_img_private_t *p_env);
|
||||
driver_return_code_t eject_media_freebsd_cam (_img_private_t *p_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);
|
||||
|
||||
static int get_media_changed_freebsd (const void *p_user_data);
|
||||
|
||||
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_mmc_cmd_freebsd_cam( const void *p_user_data,
|
||||
unsigned int i_timeout_ms,
|
||||
unsigned int i_cdb,
|
||||
const mmc_cdb_t *p_cdb,
|
||||
cdio_mmc_direction_t e_direction,
|
||||
unsigned int i_buf,
|
||||
/*in/out*/ void *p_buf );
|
||||
|
||||
/*!
|
||||
Return the size of the CD in logical block address (LBA) units.
|
||||
*/
|
||||
lsn_t get_disc_last_lsn_freebsd_ioctl (_img_private_t *_obj);
|
||||
|
||||
bool init_freebsd_cam (_img_private_t *env);
|
||||
void free_freebsd_cam (void *user_data);
|
||||
|
||||
#endif /*HAVE_FREEBSD_CDROM*/
|
||||
257
lib/driver/FreeBSD/freebsd_cam.c
Normal file
257
lib/driver/FreeBSD/freebsd_cam.c
Normal file
@@ -0,0 +1,257 @@
|
||||
/*
|
||||
$Id: freebsd_cam.c,v 1.12 2008/04/21 18:30:20 karl Exp $
|
||||
|
||||
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file contains 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.12 2008/04/21 18:30:20 karl Exp $";
|
||||
|
||||
#ifdef HAVE_FREEBSD_CDROM
|
||||
|
||||
#include "freebsd.h"
|
||||
#include <cdio/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_mmc_cmd_freebsd_cam( const void *p_user_data, unsigned int i_timeout_ms,
|
||||
unsigned int i_cdb, const mmc_cdb_t *p_cdb,
|
||||
cdio_mmc_direction_t e_direction,
|
||||
unsigned int i_buf, /*in/out*/ void *p_buf )
|
||||
{
|
||||
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_buf)
|
||||
direction |= CAM_DIR_NONE;
|
||||
else
|
||||
direction |= (e_direction == SCSI_MMC_DATA_READ)?CAM_DIR_IN : CAM_DIR_OUT;
|
||||
|
||||
|
||||
memcpy(ccb.csio.cdb_io.cdb_bytes, p_cdb->field, i_cdb);
|
||||
ccb.csio.cdb_len =
|
||||
mmc_get_cmd_len(ccb.csio.cdb_io.cdb_bytes[0]);
|
||||
|
||||
cam_fill_csio (&(ccb.csio), 1, NULL,
|
||||
direction | CAM_DEV_QFRZDIS, MSG_SIMPLE_Q_TAG, p_buf, i_buf,
|
||||
sizeof(ccb.csio.sense_data), ccb.csio.cdb_len, 30*1000);
|
||||
|
||||
if (cam_send_ccb(p_env->cam, &ccb) < 0)
|
||||
{
|
||||
cdio_warn ("transport failed: %s", strerror(errno));
|
||||
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);
|
||||
}
|
||||
|
||||
driver_return_code_t
|
||||
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 DRIVER_OP_SUCCESS;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
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)
|
||||
{
|
||||
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 = mmc_set_blocksize (p_env->gen.cdio, M2RAW_SECTOR_SIZE)))
|
||||
return retval;
|
||||
|
||||
if ((retval = run_mmc_cmd_freebsd_cam (p_env, 0,
|
||||
mmc_get_cmd_len(cdb.field[0]),
|
||||
&cdb,
|
||||
SCSI_MMC_DATA_READ,
|
||||
M2RAW_SECTOR_SIZE * nblocks,
|
||||
p_buf)))
|
||||
{
|
||||
mmc_set_blocksize (p_env->gen.cdio, CDIO_CD_FRAMESIZE);
|
||||
return retval;
|
||||
}
|
||||
|
||||
return mmc_set_blocksize (p_env->gen.cdio, CDIO_CD_FRAMESIZE);
|
||||
} 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_mmc_cmd_freebsd_cam (p_env, 0,
|
||||
mmc_get_cmd_len(cdb.field[0]),
|
||||
&cdb,
|
||||
SCSI_MMC_DATA_READ,
|
||||
M2RAW_SECTOR_SIZE * nblocks, p_buf);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Eject media in CD-ROM drive. Return DRIVER_OP_SUCCESS if successful,
|
||||
DRIVER_OP_ERROR on error.
|
||||
*/
|
||||
driver_return_code_t
|
||||
eject_media_freebsd_cam (_img_private_t *p_env)
|
||||
{
|
||||
int i_status;
|
||||
mmc_cdb_t cdb = {{0, }};
|
||||
uint8_t buf[1];
|
||||
|
||||
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_ALLOW_MEDIUM_REMOVAL);
|
||||
|
||||
i_status = run_mmc_cmd_freebsd_cam (p_env, DEFAULT_TIMEOUT_MSECS,
|
||||
mmc_get_cmd_len(cdb.field[0]),
|
||||
&cdb, SCSI_MMC_DATA_WRITE, 0, &buf);
|
||||
if (i_status) return i_status;
|
||||
|
||||
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_START_STOP);
|
||||
cdb.field[4] = 1;
|
||||
i_status = run_mmc_cmd_freebsd_cam (p_env, DEFAULT_TIMEOUT_MSECS,
|
||||
mmc_get_cmd_len(cdb.field[0]), &cdb,
|
||||
SCSI_MMC_DATA_WRITE, 0, &buf);
|
||||
if (i_status) return i_status;
|
||||
|
||||
CDIO_MMC_SET_COMMAND(cdb.field, CDIO_MMC_GPCMD_START_STOP);
|
||||
cdb.field[4] = 2; /* eject */
|
||||
|
||||
return run_mmc_cmd_freebsd_cam (p_env, DEFAULT_TIMEOUT_MSECS,
|
||||
mmc_get_cmd_len(cdb.field[0]),
|
||||
&cdb,
|
||||
SCSI_MMC_DATA_WRITE, 0, &buf);
|
||||
}
|
||||
|
||||
#endif /* HAVE_FREEBSD_CDROM */
|
||||
262
lib/driver/FreeBSD/freebsd_ioctl.c
Normal file
262
lib/driver/FreeBSD/freebsd_ioctl.c
Normal file
@@ -0,0 +1,262 @@
|
||||
/*
|
||||
$Id: freebsd_ioctl.c,v 1.7 2008/04/21 18:30:20 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file contains 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.7 2008/04/21 18:30:20 karl 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 *p_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 (p_env, buf, lsn);
|
||||
|
||||
if ( (retval = read_audio_sectors_freebsd_ioctl (p_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.
|
||||
*/
|
||||
lsn_t
|
||||
get_disc_last_lsn_freebsd_ioctl (_img_private_t *p_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 (p_obj->gen.fd, CDIOREADTOCENTRY, &tocent) == -1)
|
||||
{
|
||||
perror ("ioctl(CDROMREADTOCENTRY)");
|
||||
exit (EXIT_FAILURE);
|
||||
}
|
||||
|
||||
size = tocent.entry.addr.lba;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
/*!
|
||||
Eject media in CD-ROM drive. Return DRIVER_OP_SUCCESS if successful,
|
||||
DRIVER_OP_ERROR on error.
|
||||
*/
|
||||
driver_return_code_t
|
||||
eject_media_freebsd_ioctl (_img_private_t *p_env)
|
||||
{
|
||||
_img_private_t *p_obj = p_env;
|
||||
int ret=DRIVER_OP_ERROR;
|
||||
|
||||
if (ioctl(p_obj->gen.fd, CDIOCALLOW) == -1) {
|
||||
cdio_warn("ioctl(fd, CDIOCALLOW) failed: %s\n", strerror(errno));
|
||||
} else if (ioctl(p_obj->gen.fd, CDIOCEJECT) == -1) {
|
||||
cdio_warn("ioctl(CDIOCEJECT) failed: %s\n", strerror(errno));
|
||||
} else {
|
||||
ret=DRIVER_OP_SUCCESS;;
|
||||
}
|
||||
|
||||
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 *p_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(p_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 *p_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(p_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 *p_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(p_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 */
|
||||
22
lib/driver/MSWindows/Makefile
Normal file
22
lib/driver/MSWindows/Makefile
Normal file
@@ -0,0 +1,22 @@
|
||||
# $Id: Makefile,v 1.2 2008/04/21 18:30:21 karl Exp $
|
||||
#
|
||||
# Copyright (C) 2004, 2008 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# The make is done above. This boilerplate Makefile just transfers the call
|
||||
|
||||
|
||||
all install check clean:
|
||||
cd .. && $(MAKE) $@
|
||||
808
lib/driver/MSWindows/aspi32.c
Normal file
808
lib/driver/MSWindows/aspi32.c
Normal file
@@ -0,0 +1,808 @@
|
||||
/*
|
||||
$Id: aspi32.c,v 1.11 2008/04/21 18:30:21 karl Exp $
|
||||
|
||||
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file contains 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.11 2008/04/21 18:30:21 karl Exp $";
|
||||
|
||||
#include <cdio/cdio.h>
|
||||
#include <cdio/sector.h>
|
||||
#include <cdio/util.h>
|
||||
#include <cdio/mmc.h>
|
||||
#include "cdio_assert.h"
|
||||
|
||||
#include <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;
|
||||
}
|
||||
|
||||
*lpGetSupport = (void *) GetProcAddress( *hASPI,
|
||||
"GetASPI32SupportInfo" );
|
||||
*lpSendCommand = (void *) 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 == mmc_get_dvd_struct_physical_private (p_env, &run_mmc_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_mmc_cmd_aspi( void *p_user_data, unsigned int i_timeout_ms,
|
||||
unsigned int i_cdb, const mmc_cdb_t * p_cdb,
|
||||
cdio_mmc_direction_t e_direction,
|
||||
unsigned int i_buf, /*in/out*/ void *p_buf )
|
||||
{
|
||||
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 (_img_private_t *p_env, void *data, lsn_t lsn,
|
||||
int sector_type, unsigned int nblocks)
|
||||
{
|
||||
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_mmc_cmd_aspi(p_env, OP_TIMEOUT_MS,
|
||||
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 *p_env, void *data, lsn_t lsn,
|
||||
unsigned int i_blocks)
|
||||
{
|
||||
if (read_sectors_aspi(p_env, data, lsn, CDIO_MMC_READ_TYPE_CDDA, i_blocks)) {
|
||||
return read_sectors_aspi(p_env, data, lsn,
|
||||
CDIO_MMC_READ_TYPE_ANY, i_blocks);
|
||||
}
|
||||
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 (_img_private_t *p_env, void *data, lsn_t lsn,
|
||||
bool b_form2)
|
||||
{
|
||||
return read_sectors_aspi(p_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 (_img_private_t *p_env, void *data, lsn_t lsn,
|
||||
bool b_form2)
|
||||
{
|
||||
return read_sectors_aspi(p_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)
|
||||
{
|
||||
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_mmc_cmd_aspi (p_env, OP_TIMEOUT_MS,
|
||||
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, j, 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_mmc_cmd_aspi (p_env, OP_TIMEOUT_MS,
|
||||
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;
|
||||
}
|
||||
|
||||
j = p_env->gen.i_first_track;
|
||||
|
||||
for( i = 0 ; i <= p_env->gen.i_tracks ; i++, j++ ) {
|
||||
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 ];
|
||||
|
||||
set_track_flags(&(p_env->gen.track_flags[j]), p_env->tocent[i].Control);
|
||||
|
||||
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 */
|
||||
248
lib/driver/MSWindows/aspi32.h
Normal file
248
lib/driver/MSWindows/aspi32.h
Normal file
@@ -0,0 +1,248 @@
|
||||
/* Win32 aspi specific */
|
||||
/*
|
||||
$Id: aspi32.h,v 1.6 2008/04/21 18:30:21 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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 (_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 (_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_mmc_cmd_aspi( void *p_user_data,
|
||||
unsigned int i_timeout,
|
||||
unsigned int i_cdb,
|
||||
const mmc_cdb_t * p_cdb,
|
||||
cdio_mmc_direction_t e_direction,
|
||||
unsigned int i_buf, /*in/out*/ void *p_buf );
|
||||
|
||||
1003
lib/driver/MSWindows/win32.c
Normal file
1003
lib/driver/MSWindows/win32.c
Normal file
File diff suppressed because it is too large
Load Diff
239
lib/driver/MSWindows/win32.h
Normal file
239
lib/driver/MSWindows/win32.h
Normal file
@@ -0,0 +1,239 @@
|
||||
/*
|
||||
$Id: win32.h,v 1.11 2008/04/21 18:30:21 karl Exp $
|
||||
|
||||
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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;
|
||||
|
||||
/*!
|
||||
Pause playing CD through analog output
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
*/
|
||||
driver_return_code_t audio_pause_win32ioctl (void *p_user_data);
|
||||
|
||||
/*!
|
||||
Playing starting at given MSF through analog output
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
*/
|
||||
driver_return_code_t audio_play_msf_win32ioctl (void *p_user_data,
|
||||
msf_t *p_start_msf,
|
||||
msf_t *p_end_msf);
|
||||
/*!
|
||||
Resume playing an audio CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t audio_resume_win32ioctl (void *p_user_data);
|
||||
|
||||
/*!
|
||||
Get disc type associated with cd object.
|
||||
*/
|
||||
discmode_t get_discmode_win32ioctl (_img_private_t *p_env);
|
||||
|
||||
/*!
|
||||
Get the volume settings of an audio CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
audio_get_volume_win32ioctl ( void *p_user_data,
|
||||
/*out*/ cdio_audio_volume_t *p_volume);
|
||||
|
||||
/*!
|
||||
Read Audio Subchannel information
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
audio_read_subchannel_win32ioctl (void *p_user_data,
|
||||
cdio_subchannel_t *p_subchannel);
|
||||
|
||||
/*!
|
||||
Set the volume of an audio CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
audio_stop_win32ioctl ( void *p_user_data );
|
||||
|
||||
/*!
|
||||
Set the volume of an audio CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
audio_set_volume_win32ioctl ( void *p_user_data,
|
||||
cdio_audio_volume_t *p_volume);
|
||||
|
||||
/*!
|
||||
Close the tray of a CD-ROM
|
||||
|
||||
@param p_user_data the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t close_tray_win32ioctl (const char *psz_win32_drive);
|
||||
|
||||
/*!
|
||||
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 *p_obj, void *p_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 (_img_private_t *p_env, void *p_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 (_img_private_t *p_env, void *p_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_mmc_cmd_win32ioctl( void *p_user_data,
|
||||
unsigned int i_timeout,
|
||||
unsigned int i_cdb,
|
||||
const mmc_cdb_t * p_cdb,
|
||||
cdio_mmc_direction_t e_direction,
|
||||
unsigned int i_buf, /*in/out*/ void *p_buf );
|
||||
|
||||
/*!
|
||||
Initialize internal structures for CD device.
|
||||
*/
|
||||
bool init_win32ioctl (_img_private_t *p_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 *p_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 *p_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 *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.
|
||||
|
||||
*/
|
||||
void get_drive_cap_aspi (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);
|
||||
|
||||
/*!
|
||||
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 *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);
|
||||
|
||||
/*!
|
||||
Get the format (XA, DATA, AUDIO) of a track.
|
||||
*/
|
||||
track_format_t get_track_format_win32ioctl(const _img_private_t *p_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);
|
||||
|
||||
1067
lib/driver/MSWindows/win32_ioctl.c
Normal file
1067
lib/driver/MSWindows/win32_ioctl.c
Normal file
File diff suppressed because it is too large
Load Diff
183
lib/driver/Makefile.am
Normal file
183
lib/driver/Makefile.am
Normal file
@@ -0,0 +1,183 @@
|
||||
# $Id: Makefile.am,v 1.28 2008/10/20 01:25:15 rocky Exp $
|
||||
#
|
||||
# Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008
|
||||
# Rocky Bernstein <rocky@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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
########################################################
|
||||
# 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 = 10
|
||||
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_generic.c \
|
||||
_cdio_stdio.c \
|
||||
_cdio_stdio.h \
|
||||
_cdio_stream.c \
|
||||
_cdio_stream.h \
|
||||
aix.c \
|
||||
bsdi.c \
|
||||
audio.c \
|
||||
cd_types.c \
|
||||
cdio.c \
|
||||
cdtext.c \
|
||||
cdtext_private.h \
|
||||
device.c \
|
||||
disc.c \
|
||||
ds.c \
|
||||
FreeBSD/freebsd.c \
|
||||
FreeBSD/freebsd.h \
|
||||
FreeBSD/freebsd_cam.c \
|
||||
FreeBSD/freebsd_ioctl.c \
|
||||
generic.h \
|
||||
gnu_linux.c \
|
||||
image.h \
|
||||
image/bincue.c \
|
||||
image/cdrdao.c \
|
||||
image_common.c \
|
||||
image_common.h \
|
||||
image/nrg.c \
|
||||
image/nrg.h \
|
||||
logging.c \
|
||||
mmc.c \
|
||||
mmc_private.h \
|
||||
MSWindows/aspi32.c \
|
||||
MSWindows/aspi32.h \
|
||||
MSWindows/win32_ioctl.c \
|
||||
MSWindows/win32.c \
|
||||
MSWindows/win32.h \
|
||||
netbsd.c \
|
||||
osx.c \
|
||||
read.c \
|
||||
sector.c \
|
||||
solaris.c \
|
||||
track.c \
|
||||
utf8.c \
|
||||
util.c
|
||||
|
||||
lib_LTLIBRARIES = libcdio.la
|
||||
libcdio_la_LIBADD = $(LTLIBICONV)
|
||||
|
||||
libcdio_la_SOURCES = $(libcdio_sources)
|
||||
libcdio_la_ldflags = -version-info $(libcdio_la_CURRENT):$(libcdio_la_REVISION):$(libcdio_la_AGE) @LT_NO_UNDEFINED@
|
||||
|
||||
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) { ' > $@
|
||||
objs=`for obj in $(libcdio_la_OBJECTS); do sed -ne "s/^pic_object='\(.*\)'$$/\1/p" $$obj; done`; \
|
||||
if test -n "$${objs}" ; then \
|
||||
nm $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio.sym; then if test $$first = true; then echo " global:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \
|
||||
nm $${objs} | sed -n -e 's/^.*[ ][ABCDGIRSTW][ABCDGIRSTW]*[ ][ ]*\([_A-Za-z][_A-Za-z0-9]*\)$$/\1/p' | sort -u | { first=true; while read symbol; do if grep -q "^$${symbol}\$$" $(srcdir)/libcdio.sym; then :; else if test $$first = true; then echo " local:"; first=false; fi; echo " $${symbol};"; fi; done; } >> $@; \
|
||||
fi
|
||||
echo '};' >> $@
|
||||
else
|
||||
libcdio_la_LDFLAGS = $(libcdio_la_ldflags)
|
||||
endif
|
||||
|
||||
MOSTLYCLEANFILES = libcdio.la.ver
|
||||
513
lib/driver/_cdio_generic.c
Normal file
513
lib/driver/_cdio_generic.c
Normal file
@@ -0,0 +1,513 @@
|
||||
/*
|
||||
$Id: _cdio_generic.c,v 1.27 2008/04/22 15:29:11 karl Exp $
|
||||
|
||||
Copyright (C) 2004, 2005, 2006, 2007, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* This file contains generic implementations of device-driver routines.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
static const char _rcsid[] = "$Id: _cdio_generic.c,v 1.27 2008/04/22 15:29:11 karl 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 <limits.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_unimplemented_eject_media (void *p_user_data) {
|
||||
/* Sort of a stub here. Perhaps log a message? */
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the blocksize for subsequent reads.
|
||||
*/
|
||||
int
|
||||
cdio_generic_unimplemented_set_blocksize (void *p_user_data,
|
||||
uint16_t i_blocksize) {
|
||||
/* Sort of a stub here. Perhaps log a message? */
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the drive speed.
|
||||
*/
|
||||
int
|
||||
cdio_generic_unimplemented_set_speed (void *p_user_data, int i_speed) {
|
||||
/* Sort of a stub here. Perhaps log a message? */
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
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;
|
||||
if (p_env->source_name) free (p_env->source_name);
|
||||
|
||||
if (p_env->b_cdtext_init) {
|
||||
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, int open_flags)
|
||||
{
|
||||
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, open_flags, 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.
|
||||
*/
|
||||
driver_return_code_t
|
||||
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 DRIVER_OP_ERROR;
|
||||
return cdio_generic_read(user_data, data, CDIO_CD_FRAMESIZE);
|
||||
}
|
||||
|
||||
/*!
|
||||
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 *p_user_data)
|
||||
{
|
||||
generic_img_private_t *p_env = p_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;
|
||||
char real_device_1[PATH_MAX];
|
||||
char real_device_2[PATH_MAX];
|
||||
cdio_follow_symlink(drive, real_device_1);
|
||||
/* Check if drive is already in list. */
|
||||
for (j=0; j<*num_drives; j++) {
|
||||
cdio_follow_symlink((*device_list)[j], real_device_2);
|
||||
if (strcmp(real_device_1, real_device_2) == 0) break;
|
||||
}
|
||||
|
||||
if (j==*num_drives) {
|
||||
/* Drive not in list. Add it. */
|
||||
(*num_drives)++;
|
||||
*device_list = realloc(*device_list, (*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 in p_user_data for track i_track.
|
||||
For disc information i_track is 0.
|
||||
|
||||
Return the CD-TEXT or NULL if obj is NULL, CD-TEXT information does
|
||||
not exist, or we don't know how to get this implemented.
|
||||
*/
|
||||
cdtext_t *
|
||||
get_cdtext_generic (void *p_user_data, track_t i_track)
|
||||
{
|
||||
generic_img_private_t *p_env = p_user_data;
|
||||
|
||||
if (!p_env) return NULL;
|
||||
if (!p_env->toc_init)
|
||||
p_env->cdio->op.read_toc (p_user_data);
|
||||
|
||||
if ( (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 == 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_CDI:
|
||||
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)
|
||||
{
|
||||
const 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 *p_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 *p_env = p_user_data;
|
||||
|
||||
if( i_track == 0 )
|
||||
pp_field = &(p_env->cdtext.field[e_field]);
|
||||
|
||||
else
|
||||
pp_field = &(p_env->cdtext_track[i_track-i_first_track].field[e_field]);
|
||||
|
||||
if (*pp_field) free(*pp_field);
|
||||
*pp_field = (psz_value) ? strdup(psz_value) : NULL;
|
||||
}
|
||||
|
||||
/*!
|
||||
Read CD-Text information for a CdIo_t 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 mmc_init_cdtext_private( p_env,
|
||||
p_env->cdio->op.run_mmc_cmd,
|
||||
set_cdtext_field_generic
|
||||
);
|
||||
}
|
||||
|
||||
/*! Return number of channels in track: 2 or 4; -2 if not
|
||||
implemented or -1 for error.
|
||||
Not meaningful if track is not an audio track.
|
||||
*/
|
||||
int
|
||||
get_track_channels_generic(const void *p_user_data, track_t i_track)
|
||||
{
|
||||
const generic_img_private_t *p_env = p_user_data;
|
||||
return p_env->track_flags[i_track].channels;
|
||||
}
|
||||
|
||||
/*! Return 1 if copy is permitted on the track, 0 if not, or -1 for error.
|
||||
Is this meaningful if not an audio track?
|
||||
*/
|
||||
track_flag_t
|
||||
get_track_copy_permit_generic(void *p_user_data, track_t i_track)
|
||||
{
|
||||
const generic_img_private_t *p_env = p_user_data;
|
||||
return p_env->track_flags[i_track].copy_permit;
|
||||
}
|
||||
|
||||
/*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error.
|
||||
Is this meaningful if not an audio track?
|
||||
|
||||
pre-emphasis is a non linear frequency response.
|
||||
*/
|
||||
track_flag_t
|
||||
get_track_preemphasis_generic(const void *p_user_data, track_t i_track)
|
||||
{
|
||||
const generic_img_private_t *p_env = p_user_data;
|
||||
return p_env->track_flags[i_track].preemphasis;
|
||||
}
|
||||
|
||||
void
|
||||
set_track_flags(track_flags_t *p_track_flag, uint8_t i_flag)
|
||||
{
|
||||
p_track_flag->preemphasis = ( i_flag & CDIO_TRACK_FLAG_PRE_EMPHASIS )
|
||||
? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
|
||||
|
||||
p_track_flag->copy_permit = ( i_flag & CDIO_TRACK_FLAG_COPY_PERMITTED )
|
||||
? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
|
||||
|
||||
p_track_flag->channels = ( i_flag & CDIO_TRACK_FLAG_FOUR_CHANNEL_AUDIO )
|
||||
? 4 : 2;
|
||||
}
|
||||
|
||||
driver_return_code_t
|
||||
read_data_sectors_generic (void *p_user_data, void *p_buf, lsn_t i_lsn,
|
||||
uint16_t i_blocksize, uint32_t i_blocks)
|
||||
{
|
||||
int rc;
|
||||
if (0 > cdio_generic_lseek(p_user_data, i_blocksize*i_lsn, SEEK_SET))
|
||||
return DRIVER_OP_ERROR;
|
||||
rc = cdio_generic_read(p_user_data, p_buf, i_blocksize*i_blocks);
|
||||
if (rc > 0) return DRIVER_OP_SUCCESS;
|
||||
return DRIVER_OP_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "gnu"
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
224
lib/driver/_cdio_stdio.c
Normal file
224
lib/driver/_cdio_stdio.c
Normal file
@@ -0,0 +1,224 @@
|
||||
/*
|
||||
$Id: _cdio_stdio.c,v 1.6 2008/04/22 15:29:11 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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.6 2008/04/22 15:29:11 karl 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 = calloc (1, 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 upon successful completion, DRIVER_OP_SUCCESS, else,
|
||||
DRIVER_OP_ERROR is returned and the global variable errno is set to
|
||||
indicate the error.
|
||||
*/
|
||||
static driver_return_code_t
|
||||
_stdio_seek(void *p_user_data, long i_offset, int whence)
|
||||
{
|
||||
_UserData *const ud = p_user_data;
|
||||
|
||||
if ( (i_offset=fseek (ud->fd, i_offset, whence)) ) {
|
||||
cdio_error ("fseek (): %s", strerror (errno));
|
||||
}
|
||||
|
||||
return i_offset;
|
||||
}
|
||||
|
||||
static long int
|
||||
_stdio_stat(void *p_user_data)
|
||||
{
|
||||
const _UserData *const ud = p_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_t *p_obj)
|
||||
{
|
||||
cdio_stream_destroy(p_obj);
|
||||
}
|
||||
|
||||
CdioDataSource_t *
|
||||
cdio_stdio_new(const char pathname[])
|
||||
{
|
||||
CdioDataSource_t *new_obj = NULL;
|
||||
cdio_stream_io_functions funcs = { NULL, NULL, NULL, NULL, NULL, NULL };
|
||||
_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 = calloc (1, 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:
|
||||
*/
|
||||
51
lib/driver/_cdio_stdio.h
Normal file
51
lib/driver/_cdio_stdio.h
Normal file
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
$Id: _cdio_stdio.h,v 1.3 2008/04/22 15:29:11 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#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_t * cdio_stdio_new(const char psz_path[]);
|
||||
|
||||
/*!
|
||||
Deallocate resources assocaited with obj. After this obj is unusable.
|
||||
*/
|
||||
void cdio_stdio_destroy(CdioDataSource_t *p_obj);
|
||||
|
||||
|
||||
#endif /* __CDIO_STREAM_STDIO_H__ */
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "gnu"
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
214
lib/driver/_cdio_stream.c
Normal file
214
lib/driver/_cdio_stream.c
Normal file
@@ -0,0 +1,214 @@
|
||||
/*
|
||||
$Id: _cdio_stream.c,v 1.9 2008/04/22 15:29:11 karl Exp $
|
||||
|
||||
Copyright (C) 2005, 2006, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
Copyright (C) 2000, 2004, 2005 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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.9 2008/04/22 15:29:11 karl Exp $";
|
||||
|
||||
/*
|
||||
* DataSource implementations
|
||||
*/
|
||||
|
||||
struct _CdioDataSource {
|
||||
void* user_data;
|
||||
cdio_stream_io_functions op;
|
||||
int is_open;
|
||||
long position;
|
||||
};
|
||||
|
||||
void
|
||||
cdio_stream_close(CdioDataSource_t *p_obj)
|
||||
{
|
||||
if (!p_obj) return;
|
||||
|
||||
if (p_obj->is_open) {
|
||||
cdio_debug ("closed source...");
|
||||
p_obj->op.close(p_obj->user_data);
|
||||
p_obj->is_open = 0;
|
||||
p_obj->position = 0;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
cdio_stream_destroy(CdioDataSource_t *p_obj)
|
||||
{
|
||||
if (!p_obj) return;
|
||||
|
||||
cdio_stream_close(p_obj);
|
||||
|
||||
p_obj->op.free(p_obj->user_data);
|
||||
|
||||
free(p_obj);
|
||||
}
|
||||
|
||||
/**
|
||||
Like 3 fgetpos.
|
||||
|
||||
This function gets the current file position indicator for the stream
|
||||
pointed to by stream.
|
||||
|
||||
@return unpon successful completion, return value is positive, else,
|
||||
the global variable errno is set to indicate the error.
|
||||
*/
|
||||
ssize_t
|
||||
cdio_stream_getpos(CdioDataSource_t* p_obj, /*out*/ ssize_t *i_offset)
|
||||
{
|
||||
if (!p_obj || !p_obj->is_open) return DRIVER_OP_UNINIT;
|
||||
return *i_offset = p_obj->position;
|
||||
}
|
||||
|
||||
CdioDataSource_t *
|
||||
cdio_stream_new(void *user_data, const cdio_stream_io_functions *funcs)
|
||||
{
|
||||
CdioDataSource_t *new_obj;
|
||||
|
||||
new_obj = calloc (1, sizeof (CdioDataSource_t));
|
||||
|
||||
new_obj->user_data = user_data;
|
||||
memcpy(&(new_obj->op), funcs, sizeof(cdio_stream_io_functions));
|
||||
|
||||
return new_obj;
|
||||
}
|
||||
|
||||
/*
|
||||
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_t *p_obj)
|
||||
{
|
||||
if (!p_obj) return false;
|
||||
|
||||
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 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.
|
||||
*/
|
||||
ssize_t
|
||||
cdio_stream_read(CdioDataSource_t* p_obj, void *ptr, long size, long nmemb)
|
||||
{
|
||||
long read_bytes;
|
||||
|
||||
if (!p_obj) return 0;
|
||||
if (!_cdio_stream_open_if_necessary(p_obj)) return 0;
|
||||
|
||||
read_bytes = (p_obj->op.read)(p_obj->user_data, ptr, size*nmemb);
|
||||
p_obj->position += read_bytes;
|
||||
|
||||
return read_bytes;
|
||||
}
|
||||
|
||||
/**
|
||||
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 unpon successful completion, return value is positive, else,
|
||||
the global variable errno is set to indicate the error.
|
||||
*/
|
||||
ssize_t
|
||||
cdio_stream_seek(CdioDataSource_t* p_obj, ssize_t offset, int whence)
|
||||
{
|
||||
if (!p_obj) return DRIVER_OP_UNINIT;
|
||||
|
||||
if (!_cdio_stream_open_if_necessary(p_obj))
|
||||
/* errno is set by _cdio_stream_open_if necessary. */
|
||||
return DRIVER_OP_ERROR;
|
||||
|
||||
if (offset < 0) return DRIVER_OP_ERROR;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
Return whatever size of stream reports, I guess unit size is bytes.
|
||||
On error return -1;
|
||||
*/
|
||||
ssize_t
|
||||
cdio_stream_stat(CdioDataSource_t *p_obj)
|
||||
{
|
||||
if (!p_obj) return -1;
|
||||
if (!_cdio_stream_open_if_necessary(p_obj)) return -1;
|
||||
|
||||
return p_obj->op.stat(p_obj->user_data);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "gnu"
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
139
lib/driver/_cdio_stream.h
Normal file
139
lib/driver/_cdio_stream.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
$Id: _cdio_stream.h,v 1.5 2008/04/22 15:29:11 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2006, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#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 driver_return_code_t(*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;
|
||||
|
||||
/**
|
||||
Like 3 fgetpos.
|
||||
|
||||
This function gets the current file position indicator for the stream
|
||||
pointed to by stream.
|
||||
|
||||
@return unpon successful completion, return value is positive, else,
|
||||
the global variable errno is set to indicate the error.
|
||||
*/
|
||||
ssize_t cdio_stream_getpos(CdioDataSource_t* p_obj,
|
||||
/*out*/ ssize_t *i_offset);
|
||||
|
||||
CdioDataSource_t *
|
||||
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.
|
||||
*/
|
||||
ssize_t cdio_stream_read(CdioDataSource_t* p_obj, void *ptr, long i_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 upon successful completion, DRIVER_OP_SUCCESS, else,
|
||||
DRIVER_OP_ERROR is returned and the global variable errno is set to
|
||||
indicate the error.
|
||||
*/
|
||||
ssize_t cdio_stream_seek(CdioDataSource_t *p_obj, ssize_t i_offset,
|
||||
int whence);
|
||||
|
||||
/**
|
||||
Return whatever size of stream reports, I guess unit size is bytes.
|
||||
On error return -1;
|
||||
*/
|
||||
ssize_t cdio_stream_stat(CdioDataSource_t *p_obj);
|
||||
|
||||
/**
|
||||
Deallocate resources associated with p_obj. After this p_obj is unusable.
|
||||
*/
|
||||
void cdio_stream_destroy(CdioDataSource_t *p_obj);
|
||||
|
||||
void cdio_stream_close(CdioDataSource_t *p_obj);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __CDIO_STREAM_H__ */
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "gnu"
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
1026
lib/driver/aix.c
Normal file
1026
lib/driver/aix.c
Normal file
File diff suppressed because it is too large
Load Diff
188
lib/driver/audio.c
Normal file
188
lib/driver/audio.c
Normal file
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
$Id: audio.c,v 1.9 2008/04/22 15:29:11 karl Exp $
|
||||
|
||||
Copyright (C) 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*! Audio (via line output) related routines. */
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <cdio/cdio.h>
|
||||
#include <cdio/util.h>
|
||||
#include <cdio/audio.h>
|
||||
#include "cdio_private.h"
|
||||
|
||||
/* Return the number of seconds (discarding frame portion) of an MSF */
|
||||
uint32_t
|
||||
cdio_audio_get_msf_seconds(msf_t *p_msf)
|
||||
{
|
||||
return
|
||||
cdio_from_bcd8(p_msf->m)*CDIO_CD_SECS_PER_MIN + cdio_from_bcd8(p_msf->s);
|
||||
}
|
||||
|
||||
/*!
|
||||
Get volume of an audio CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_audio_get_volume (CdIo_t *p_cdio, /*out*/ cdio_audio_volume_t *p_volume)
|
||||
{
|
||||
cdio_audio_volume_t temp_audio_volume;
|
||||
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT;
|
||||
|
||||
if (!p_volume) p_volume = &temp_audio_volume;
|
||||
if (p_cdio->op.audio_get_volume) {
|
||||
return p_cdio->op.audio_get_volume (p_cdio->env, p_volume);
|
||||
} else {
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
/*!
|
||||
Playing CD through analog output
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_audio_pause (CdIo_t *p_cdio)
|
||||
{
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT;
|
||||
|
||||
if (p_cdio->op.audio_pause) {
|
||||
return p_cdio->op.audio_pause (p_cdio->env);
|
||||
} else {
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Playing CD through analog output at the given MSF.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_audio_play_msf (CdIo_t *p_cdio, msf_t *p_start_msf, msf_t *p_end_msf)
|
||||
{
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT;
|
||||
|
||||
if (p_cdio->op.audio_play_msf) {
|
||||
return p_cdio->op.audio_play_msf (p_cdio->env, p_start_msf, p_end_msf);
|
||||
} else {
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Playing CD through analog output
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_audio_play_track_index (CdIo_t *p_cdio, cdio_track_index_t *p_track_index)
|
||||
{
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT;
|
||||
|
||||
if (p_cdio->op.audio_play_track_index) {
|
||||
return p_cdio->op.audio_play_track_index (p_cdio->env, p_track_index);
|
||||
} else {
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Get subchannel information.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_audio_read_subchannel (CdIo_t *p_cdio, cdio_subchannel_t *p_subchannel)
|
||||
{
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT;
|
||||
|
||||
if (p_cdio->op.audio_read_subchannel) {
|
||||
return p_cdio->op.audio_read_subchannel(p_cdio->env, p_subchannel);
|
||||
} else {
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Resume playing an audio CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_audio_resume (CdIo_t *p_cdio)
|
||||
{
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT;
|
||||
|
||||
if (p_cdio->op.audio_resume) {
|
||||
return p_cdio->op.audio_resume(p_cdio->env);
|
||||
} else {
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Set volume of an audio CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_audio_set_volume (CdIo_t *p_cdio, cdio_audio_volume_t *p_volume)
|
||||
{
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT;
|
||||
|
||||
if (p_cdio->op.audio_set_volume) {
|
||||
return p_cdio->op.audio_set_volume(p_cdio->env, p_volume);
|
||||
} else {
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Resume playing an audio CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_audio_stop (CdIo_t *p_cdio)
|
||||
{
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT;
|
||||
|
||||
if (p_cdio->op.audio_stop) {
|
||||
return p_cdio->op.audio_stop(p_cdio->env);
|
||||
} else {
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "gnu"
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
1079
lib/driver/bsdi.c
Normal file
1079
lib/driver/bsdi.c
Normal file
File diff suppressed because it is too large
Load Diff
360
lib/driver/cd_types.c
Normal file
360
lib/driver/cd_types.c
Normal file
@@ -0,0 +1,360 @@
|
||||
/*
|
||||
$Id: cd_types.c,v 1.9 2008/06/16 19:39:30 flameeyes Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2006, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*
|
||||
This 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.
|
||||
|
||||
*/
|
||||
|
||||
/** The below variables are trickery to force enum symbol values to be
|
||||
recorded in debug symbol tables. They are used to allow one to refer
|
||||
to the enumeration value names in the typedefs above in a debugger
|
||||
and debugger expressions.
|
||||
*/
|
||||
cdio_fs_cap_t debug_cdio_fs_cap;
|
||||
cdio_fs_t debug_cdio_fs;
|
||||
|
||||
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;
|
||||
char sig_str[60];
|
||||
char description[60];
|
||||
} signature_t;
|
||||
|
||||
static const 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"}
|
||||
};
|
||||
|
||||
|
||||
/* 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 driver_return_code_t
|
||||
_cdio_read_block(const CdIo_t *p_cdio, int superblock, uint32_t offset,
|
||||
uint8_t bufnum, track_t i_track)
|
||||
{
|
||||
unsigned int track_sec_count = cdio_get_track_sec_count(p_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 DRIVER_OP_ERROR;
|
||||
}
|
||||
|
||||
cdio_debug("about to read sector %lu\n",
|
||||
(long unsigned int) offset+superblock);
|
||||
|
||||
return cdio_read_data_sectors (p_cdio, buffer[bufnum], offset+superblock,
|
||||
ISO_BLOCKSIZE, 1);
|
||||
}
|
||||
|
||||
/*
|
||||
Return true if the previously read-in buffer contains a "signature" that
|
||||
matches index "num".
|
||||
*/
|
||||
static bool
|
||||
_cdio_is_it(int num)
|
||||
{
|
||||
const 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_t *p_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(p_cdio, i_track))
|
||||
return CDIO_FS_AUDIO;
|
||||
|
||||
if ( DRIVER_OP_SUCCESS !=
|
||||
_cdio_read_block(p_cdio, ISO_PVD_SECTOR, start_session, 0, i_track) )
|
||||
return CDIO_FS_UNKNOWN;
|
||||
|
||||
if ( _cdio_is_it(INDEX_XISO) )
|
||||
return CDIO_FS_ANAL_XISO;
|
||||
|
||||
if ( DRIVER_OP_SUCCESS != _cdio_read_block(p_cdio, ISO_SUPERBLOCK_SECTOR,
|
||||
start_session, 0, i_track) )
|
||||
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(p_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(p_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 | CDIO_FS_ANAL_ISO9660_ANY);
|
||||
} else {
|
||||
/* read sector 0 ONLY, when NO greenbook CD-I !!!! */
|
||||
|
||||
sector0_read_ok =
|
||||
_cdio_read_block(p_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 | CDIO_FS_ANAL_ISO9660_ANY);
|
||||
else if (_cdio_is_hfs())
|
||||
ret = CDIO_FS_ISO_HFS;
|
||||
else
|
||||
ret = (CDIO_FS_ISO_9660 | CDIO_FS_ANAL_ISO9660_ANY);
|
||||
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(p_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(p_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(p_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(p_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 | CDIO_FS_ANAL_ISO9660_ANY);
|
||||
}
|
||||
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(p_cdio, VCD_INFO_SECTOR, start_session, 4,
|
||||
i_track) < 0 )
|
||||
return ret;
|
||||
|
||||
if (_cdio_is_it(INDEX_BRIDGE) && _cdio_is_it(INDEX_CD_RTOS)) {
|
||||
ret |= CDIO_FS_ANAL_ISO9660_ANY;
|
||||
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 | CDIO_FS_ANAL_ISO9660_ANY);
|
||||
else if (_cdio_is_3do()) ret |= CDIO_FS_3DO;
|
||||
else {
|
||||
if ( _cdio_read_block(p_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 | CDIO_FS_ANAL_ISO9660_ANY);
|
||||
if (_cdio_is_it(INDEX_PHOTO_CD))
|
||||
ret |= (CDIO_FS_ANAL_PHOTO_CD | CDIO_FS_ANAL_ISO9660_ANY);
|
||||
if (_cdio_is_it(INDEX_CDTV))
|
||||
ret |= CDIO_FS_ANAL_CDTV;
|
||||
return ret;
|
||||
}
|
||||
112
lib/driver/cdio.c
Normal file
112
lib/driver/cdio.c
Normal file
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
$Id: cdio.c,v 1.14 2008/04/22 15:29:11 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
Copyright (C) 2001 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include "cdio_assert.h"
|
||||
#include <cdio/cdio.h>
|
||||
#include <cdio/util.h>
|
||||
#include "cdio_private.h"
|
||||
|
||||
static const char _rcsid[] = "$Id: cdio.c,v 1.14 2008/04/22 15:29:11 karl Exp $";
|
||||
|
||||
|
||||
/*!
|
||||
Return the value associatied with key. NULL is returned if obj is NULL
|
||||
or "key" does not exist.
|
||||
*/
|
||||
const char *
|
||||
cdio_get_arg (const CdIo *obj, const char key[])
|
||||
{
|
||||
if (obj == NULL) return NULL;
|
||||
|
||||
if (obj->op.get_arg) {
|
||||
return obj->op.get_arg (obj->env, key);
|
||||
} else {
|
||||
return 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.
|
||||
*/
|
||||
cdtext_t *
|
||||
cdio_get_cdtext (CdIo *obj, track_t i_track)
|
||||
{
|
||||
if (obj == NULL) return NULL;
|
||||
|
||||
if (obj->op.get_cdtext) {
|
||||
return obj->op.get_cdtext (obj->env, i_track);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
CdIo_t *
|
||||
cdio_new (generic_img_private_t *p_env, cdio_funcs_t *p_funcs)
|
||||
{
|
||||
CdIo_t *p_new_cdio = calloc(1, sizeof (CdIo_t));
|
||||
|
||||
if (NULL == p_new_cdio) return NULL;
|
||||
|
||||
p_new_cdio->env = p_env; /* This is the private "environment" that
|
||||
driver-dependent routines use. */
|
||||
p_new_cdio->op = *p_funcs;
|
||||
p_env->cdio = p_new_cdio; /* A way for the driver-dependent routines
|
||||
to access the higher-level general cdio
|
||||
object. */
|
||||
return p_new_cdio;
|
||||
}
|
||||
|
||||
/*!
|
||||
Set the arg "key" with "value" in the source device.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_set_arg (CdIo_t *p_cdio, const char key[], const char value[])
|
||||
{
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT;
|
||||
if (!p_cdio->op.set_arg) return DRIVER_OP_UNSUPPORTED;
|
||||
if (!key) return DRIVER_OP_ERROR;
|
||||
|
||||
return p_cdio->op.set_arg (p_cdio->env, key, value);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "gnu"
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
59
lib/driver/cdio_assert.h
Normal file
59
lib/driver/cdio_assert.h
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
$Id: cdio_assert.h,v 1.2 2008/04/22 15:29:11 karl Exp $
|
||||
|
||||
Copyright (C) 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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__ */
|
||||
547
lib/driver/cdio_private.h
Normal file
547
lib/driver/cdio_private.h
Normal file
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
$Id: cdio_private.h,v 1.37 2008/04/22 15:29:11 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Internal routines for CD I/O drivers. */
|
||||
|
||||
|
||||
#ifndef __CDIO_PRIVATE_H__
|
||||
#define __CDIO_PRIVATE_H__
|
||||
|
||||
#if defined(HAVE_CONFIG_H) && !defined(LIBCDIO_CONFIG_H)
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <cdio/cdio.h>
|
||||
#include <cdio/audio.h>
|
||||
#include <cdio/cdtext.h>
|
||||
#include "mmc_private.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
/* Opaque type */
|
||||
typedef struct _CdioDataSource CdioDataSource_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include "generic.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
typedef struct {
|
||||
|
||||
/*!
|
||||
Get volume of an audio CD.
|
||||
|
||||
@param p_env the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t (*audio_get_volume)
|
||||
(void *p_env, /*out*/ cdio_audio_volume_t *p_volume);
|
||||
|
||||
/*!
|
||||
Pause playing CD through analog output
|
||||
|
||||
@param p_env the CD object to be acted upon.
|
||||
*/
|
||||
driver_return_code_t (*audio_pause) (void *p_env);
|
||||
|
||||
/*!
|
||||
Playing CD through analog output
|
||||
|
||||
@param p_env the CD object to be acted upon.
|
||||
*/
|
||||
driver_return_code_t (*audio_play_msf) ( void *p_env,
|
||||
msf_t *p_start_msf,
|
||||
msf_t *p_end_msf );
|
||||
|
||||
/*!
|
||||
Playing CD through analog output
|
||||
|
||||
@param p_env the CD object to be acted upon.
|
||||
*/
|
||||
driver_return_code_t (*audio_play_track_index)
|
||||
( void *p_env, cdio_track_index_t *p_track_index );
|
||||
|
||||
/*!
|
||||
Get subchannel information.
|
||||
|
||||
@param p_env the CD object to be acted upon.
|
||||
*/
|
||||
driver_return_code_t (*audio_read_subchannel)
|
||||
( void *p_env, cdio_subchannel_t *subchannel );
|
||||
|
||||
/*!
|
||||
Resume playing an audio CD.
|
||||
|
||||
@param p_env the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t (*audio_resume) ( void *p_env );
|
||||
|
||||
/*!
|
||||
Set volume of an audio CD.
|
||||
|
||||
@param p_env the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t (*audio_set_volume)
|
||||
( void *p_env, cdio_audio_volume_t *p_volume );
|
||||
|
||||
/*!
|
||||
Stop playing an audio CD.
|
||||
|
||||
@param p_env the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t (*audio_stop) ( void *p_env );
|
||||
|
||||
/*!
|
||||
Eject media in CD drive. If successful, as a side effect we
|
||||
also free p_env.
|
||||
|
||||
@param p_env the CD object to be acted upon.
|
||||
If the CD is ejected *p_env is freed and p_env set to NULL.
|
||||
*/
|
||||
driver_return_code_t (*eject_media) ( void *p_env );
|
||||
|
||||
/*!
|
||||
Release and free resources associated with cd.
|
||||
*/
|
||||
void (*free) (void *p_env);
|
||||
|
||||
/*!
|
||||
Return the value associated with the key "arg".
|
||||
*/
|
||||
const char * (*get_arg) (void *p_env, const char key[]);
|
||||
|
||||
/*!
|
||||
Get the block size for subsequest read requests, via a SCSI MMC
|
||||
MODE_SENSE 6 command.
|
||||
*/
|
||||
int (*get_blocksize) ( void *p_env );
|
||||
|
||||
/*!
|
||||
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.
|
||||
*/
|
||||
cdtext_t * (*get_cdtext) ( void *p_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 );
|
||||
|
||||
/*!
|
||||
Get the default CD device.
|
||||
|
||||
@return a string containing the default CD device or NULL is
|
||||
if we couldn't get a default device.
|
||||
|
||||
In some situations of drivers or OS's we can't find a CD device if
|
||||
there is no media in it and it is possible for this routine to return
|
||||
NULL even though there may be a hardware CD-ROM.
|
||||
*/
|
||||
char * (*get_default_device) ( void );
|
||||
|
||||
/*!
|
||||
Return the size of the CD in logical block address (LBA) units.
|
||||
@return the lsn. On error 0 or CDIO_INVALD_LSN.
|
||||
*/
|
||||
lsn_t (*get_disc_last_lsn) ( void *p_env );
|
||||
|
||||
/*!
|
||||
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 *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);
|
||||
/*!
|
||||
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_t *p_cdio, /* out*/ cdio_hwinfo_t *p_hw_info );
|
||||
|
||||
/*! Get the LSN of the first track of the last session of
|
||||
on the CD.
|
||||
|
||||
@param p_cdio the CD object to be acted upon.
|
||||
@param i_last_session pointer to the session number to be returned.
|
||||
*/
|
||||
driver_return_code_t (*get_last_session)
|
||||
( void *p_env, /*out*/ lsn_t *i_last_session );
|
||||
|
||||
/*!
|
||||
Find out if media has changed since the last call.
|
||||
@param p_env the CD object to be acted upon.
|
||||
@return 1 if media has changed since last call, 0 if not. Error
|
||||
return codes are the same as driver_return_code_t
|
||||
*/
|
||||
int (*get_media_changed) ( const void *p_env );
|
||||
|
||||
/*!
|
||||
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 *p_env );
|
||||
|
||||
/*!
|
||||
Return the number of tracks in the current medium.
|
||||
CDIO_INVALID_TRACK is returned on error.
|
||||
*/
|
||||
track_t (*get_num_tracks) ( void *p_env );
|
||||
|
||||
/*! Return number of channels in track: 2 or 4; -2 if not
|
||||
implemented or -1 for error.
|
||||
Not meaningful if track is not an audio track.
|
||||
*/
|
||||
int (*get_track_channels) ( const void *p_env, track_t i_track );
|
||||
|
||||
/*! Return 0 if track is copy protected, 1 if not, or -1 for error
|
||||
or -2 if not implimented (yet). Is this meaningful if not an
|
||||
audio track?
|
||||
*/
|
||||
track_flag_t (*get_track_copy_permit) ( void *p_env, track_t i_track );
|
||||
|
||||
/*!
|
||||
Return the starting LBA for track number
|
||||
i_track in p_env. 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 *p_env, track_t i_track );
|
||||
|
||||
/*!
|
||||
Return the starting LBA for the pregap for track number
|
||||
i_track in p_env. Tracks numbers start at 1.
|
||||
CDIO_INVALID_LBA is returned on error.
|
||||
*/
|
||||
lba_t (*get_track_pregap_lba) ( const void *p_env, track_t i_track );
|
||||
|
||||
/*!
|
||||
Return the International Standard Recording Code (ISRC) for track number
|
||||
i_track in p_cdio. Track numbers start at 1.
|
||||
|
||||
Note: string is malloc'd so caller has to free() the returned
|
||||
string when done with it.
|
||||
*/
|
||||
char * (*get_track_isrc) ( const void *p_env, track_t i_track );
|
||||
|
||||
/*!
|
||||
Get format of track.
|
||||
*/
|
||||
track_format_t (*get_track_format) ( void *p_env, track_t 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?
|
||||
*/
|
||||
bool (*get_track_green) ( void *p_env, track_t i_track );
|
||||
|
||||
/*!
|
||||
Return the starting MSF (minutes/secs/frames) for track number
|
||||
i_track in p_env. Tracks numbers start at 1.
|
||||
The "leadout" track is specified either by
|
||||
using i_track LEADOUT_TRACK or the total tracks+1.
|
||||
False is returned on error.
|
||||
*/
|
||||
bool (*get_track_msf) ( void *p_env, track_t i_track, msf_t *p_msf );
|
||||
|
||||
/*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error
|
||||
or -2 if not implimented (yet). Is this meaningful if not an
|
||||
audio track?
|
||||
*/
|
||||
track_flag_t (*get_track_preemphasis)
|
||||
( const void *p_env, track_t i_track );
|
||||
|
||||
/*!
|
||||
lseek - reposition read/write file offset
|
||||
Returns (off_t) -1 on error.
|
||||
Similar to libc's lseek()
|
||||
*/
|
||||
off_t (*lseek) ( void *p_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 *p_env, void *p_buf, size_t i_size );
|
||||
|
||||
/*!
|
||||
Reads a single mode2 sector from cd device into buf starting
|
||||
from lsn. Returns 0 if no error.
|
||||
*/
|
||||
int (*read_audio_sectors) ( void *p_env, void *p_buf, lsn_t i_lsn,
|
||||
unsigned int i_blocks );
|
||||
|
||||
/*!
|
||||
Read a data sector
|
||||
|
||||
@param p_env environment to read from
|
||||
|
||||
@param p_buf place to read data into. The caller should make sure
|
||||
this location can store at least CDIO_CD_FRAMESIZE,
|
||||
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE depending
|
||||
on the kind of sector getting read. If you don't
|
||||
know whether you have a Mode 1/2, Form 1/ Form 2/Formless
|
||||
sector best to reserve space for the maximum,
|
||||
M2RAW_SECTOR_SIZE.
|
||||
|
||||
@param i_lsn sector to read
|
||||
@param i_blocksize size of block. Should be either CDIO_CD_FRAMESIZE,
|
||||
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE. See comment above under p_buf.
|
||||
*/
|
||||
driver_return_code_t (*read_data_sectors)
|
||||
( void *p_env, void *p_buf, lsn_t i_lsn, uint16_t i_blocksize,
|
||||
uint32_t i_blocks );
|
||||
|
||||
/*!
|
||||
Reads a single mode2 sector from cd device into buf starting
|
||||
from lsn. Returns 0 if no error.
|
||||
*/
|
||||
int (*read_mode2_sector)
|
||||
( void *p_env, void *p_buf, lsn_t i_lsn, bool b_mode2_form2 );
|
||||
|
||||
/*!
|
||||
Reads i_blocks 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 i_lsn, bool b_mode2_form2,
|
||||
unsigned int i_blocks );
|
||||
|
||||
/*!
|
||||
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 i_lsn, bool mode1_form2 );
|
||||
|
||||
/*!
|
||||
Reads i_blocks 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 i_lsn, bool mode1_form2,
|
||||
unsigned int i_blocks );
|
||||
|
||||
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.
|
||||
*/
|
||||
mmc_run_cmd_fn_t run_mmc_cmd;
|
||||
|
||||
/*!
|
||||
Set the arg "key" with "value" in the source device.
|
||||
*/
|
||||
int (*set_arg) ( void *p_env, const char key[], const char value[] );
|
||||
|
||||
/*!
|
||||
Set the blocksize for subsequent reads.
|
||||
*/
|
||||
driver_return_code_t (*set_blocksize) ( void *p_env,
|
||||
uint16_t i_blocksize );
|
||||
|
||||
/*!
|
||||
Set the drive speed.
|
||||
|
||||
@return 0 if everything went okay, -1 if we had an error. is -2
|
||||
returned if this is not implemented for the current driver.
|
||||
*/
|
||||
int (*set_speed) ( void *p_env, int i_speed );
|
||||
|
||||
} cdio_funcs_t;
|
||||
|
||||
|
||||
/*! Implementation of CdIo type */
|
||||
struct _CdIo {
|
||||
driver_id_t driver_id; /**< Particular driver opened. */
|
||||
cdio_funcs_t 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_t * cdio_new (generic_img_private_t *p_env, cdio_funcs_t *p_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_t *(*driver_open) (const char *psz_source_name);
|
||||
CdIo_t *(*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);
|
||||
driver_return_code_t (*close_tray) (const char *psz_device);
|
||||
} 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 *psz_drive,
|
||||
unsigned int *i_drives);
|
||||
|
||||
driver_return_code_t close_tray_bsdi (const char *psz_drive);
|
||||
driver_return_code_t close_tray_freebsd (const char *psz_drive);
|
||||
driver_return_code_t close_tray_linux (const char *psz_drive);
|
||||
driver_return_code_t close_tray_netbsd (const char *psz_drive);
|
||||
driver_return_code_t close_tray_osx (const char *psz_drive);
|
||||
driver_return_code_t close_tray_solaris (const char *psz_drive);
|
||||
driver_return_code_t close_tray_win32 (const char *psz_drive);
|
||||
|
||||
bool cdio_have_netbsd(void);
|
||||
CdIo_t * cdio_open_netbsd (const char *psz_source);
|
||||
char * cdio_get_default_device_netbsd(void);
|
||||
char **cdio_get_devices_netbsd(void);
|
||||
/*! Set up CD-ROM for reading using the NetBSD driver. The device_name is
|
||||
the some sort of device name.
|
||||
|
||||
NULL is returned on error or there is no FreeBSD driver.
|
||||
|
||||
@see cdio_open_cd, cdio_open
|
||||
*/
|
||||
CdIo_t * cdio_open_am_netbsd (const char *psz_source,
|
||||
const char *psz_access_mode);
|
||||
|
||||
/*! DEPRICATED: use cdio_have_driver().
|
||||
True if AIX driver is available. */
|
||||
bool cdio_have_aix (void);
|
||||
|
||||
/*! DEPRICATED: use cdio_have_driver().
|
||||
True if BSDI driver is available. */
|
||||
bool cdio_have_bsdi (void);
|
||||
|
||||
/*! DEPRICATED: use cdio_have_driver().
|
||||
True if FreeBSD driver is available. */
|
||||
bool cdio_have_freebsd (void);
|
||||
|
||||
/*! DEPRICATED: use cdio_have_driver().
|
||||
True if GNU/Linux driver is available. */
|
||||
bool cdio_have_linux (void);
|
||||
|
||||
/*! DEPRICATED: use cdio_have_driver().
|
||||
True if Sun Solaris driver is available. */
|
||||
bool cdio_have_solaris (void);
|
||||
|
||||
/*! DEPRICATED: use cdio_have_driver().
|
||||
True if Apple OSX driver is available. */
|
||||
bool cdio_have_osx (void);
|
||||
|
||||
/*! DEPRICATED: use cdio_have_driver().
|
||||
True if Microsoft Windows driver is available. */
|
||||
bool cdio_have_win32 (void);
|
||||
|
||||
/*! True if Nero driver is available. */
|
||||
bool cdio_have_nrg (void);
|
||||
|
||||
/*! True if BIN/CUE driver is available. */
|
||||
bool cdio_have_bincue (void);
|
||||
|
||||
/*! True if cdrdao CDRDAO driver is available. */
|
||||
bool cdio_have_cdrdao (void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __CDIO_PRIVATE_H__ */
|
||||
253
lib/driver/cdtext.c
Normal file
253
lib/driver/cdtext.c
Normal file
@@ -0,0 +1,253 @@
|
||||
/*
|
||||
$Id: cdtext.c,v 1.7 2008/06/16 22:41:44 flameeyes Exp $
|
||||
|
||||
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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. */
|
||||
static const char cdtext_keywords[][16] =
|
||||
{
|
||||
"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 *p_cdtext)
|
||||
{
|
||||
cdtext_field_t i;
|
||||
|
||||
if (!p_cdtext) return;
|
||||
for (i=0; i < MAX_CDTEXT_FIELDS; i++) {
|
||||
if (p_cdtext->field[i]) {
|
||||
free(p_cdtext->field[i]);
|
||||
p_cdtext->field[i] = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
returns the CDTEXT value associated with key. NULL is returned
|
||||
if key is CDTEXT_INVALID or the field is not set.
|
||||
*/
|
||||
char *
|
||||
cdtext_get (cdtext_field_t key, const cdtext_t *p_cdtext)
|
||||
{
|
||||
if ((key == CDTEXT_INVALID) || (!p_cdtext->field[key])) return NULL;
|
||||
return strdup(p_cdtext->field[key]);
|
||||
}
|
||||
|
||||
const char *
|
||||
cdtext_get_const (cdtext_field_t key, const cdtext_t *p_cdtext)
|
||||
{
|
||||
if (key == CDTEXT_INVALID) return NULL;
|
||||
return p_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 *p_cdtext)
|
||||
{
|
||||
cdtext_field_t i;
|
||||
|
||||
for (i=0; i < MAX_CDTEXT_FIELDS; i++) {
|
||||
p_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 *p_value, cdtext_t *p_cdtext)
|
||||
{
|
||||
if (NULL == p_value || key == CDTEXT_INVALID) return;
|
||||
|
||||
if (p_cdtext->field[key]) free (p_cdtext->field[key]);
|
||||
p_cdtext->field[key] = strdup (p_value);
|
||||
|
||||
}
|
||||
|
||||
#define SET_CDTEXT_FIELD(FIELD) \
|
||||
(*set_cdtext_field_fn)(p_user_data, i_track, i_first_track, FIELD, buffer);
|
||||
|
||||
/*
|
||||
parse all CD-TEXT data retrieved.
|
||||
*/
|
||||
bool
|
||||
cdtext_data_init(void *p_user_data, track_t i_first_track,
|
||||
unsigned char *wdata, int i_data,
|
||||
set_cdtext_field_fn_t set_cdtext_field_fn)
|
||||
{
|
||||
CDText_data_t *p_data;
|
||||
int i = -1;
|
||||
int j;
|
||||
char buffer[256];
|
||||
int idx;
|
||||
int i_track;
|
||||
bool b_ret = false;
|
||||
|
||||
memset( buffer, 0x00, sizeof(buffer) );
|
||||
idx = 0;
|
||||
|
||||
p_data = (CDText_data_t *) (&wdata[4]);
|
||||
|
||||
/* For reasons I don't understand - incorrect CDROM TOC reading?
|
||||
we are off sometimes by 4.
|
||||
*/
|
||||
if( (p_data->type < 0x80) || (p_data->type > 0x85)
|
||||
|| (p_data->block == 0) ) {
|
||||
CDText_data_t *p_data_test = (CDText_data_t *) (&wdata[8]);
|
||||
if( (p_data_test->type >= 0x80)
|
||||
&& (p_data_test->type <= 0x85) && (p_data_test->block == 0) ) {
|
||||
p_data = p_data_test;
|
||||
i_data -= 4;
|
||||
}
|
||||
}
|
||||
|
||||
for( ; i_data > 0;
|
||||
i_data -= sizeof(CDText_data_t), p_data++ ) {
|
||||
|
||||
#if TESTED
|
||||
if ( p_data->bDBC ) {
|
||||
cdio_warn("Double-byte characters not supported");
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if( (p_data->type >= 0x80)
|
||||
&& (p_data->type <= 0x85) && (p_data->block == 0) ) {
|
||||
i_track = p_data->i_track;
|
||||
|
||||
i++;
|
||||
if( p_data->seq != i ) break;
|
||||
|
||||
for( j=0; j < CDIO_CDTEXT_MAX_TEXT_DATA; j++ ) {
|
||||
if( p_data->text[j] == 0x00 ) {
|
||||
bool b_field_set=true;
|
||||
switch( p_data->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++] = p_data->text[j];
|
||||
}
|
||||
buffer[idx] = 0x00;
|
||||
}
|
||||
}
|
||||
}
|
||||
return b_ret;
|
||||
}
|
||||
|
||||
139
lib/driver/cdtext_private.h
Normal file
139
lib/driver/cdtext_private.h
Normal file
@@ -0,0 +1,139 @@
|
||||
/*
|
||||
$Id: cdtext_private.h,v 1.3 2008/04/22 15:29:11 karl Exp $
|
||||
|
||||
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef __CDIO_CDTEXT_PRIVATE_H__
|
||||
#define __CDIO_CDTEXT_PRIVATE_H__
|
||||
|
||||
#include <cdio/cdio.h>
|
||||
#include <cdio/cdtext.h>
|
||||
|
||||
/*! An enumeration for some of the CDIO_CDTEXT_* #defines below. This isn't
|
||||
really an enumeration one would really use in a program it is here
|
||||
to be helpful in debuggers where wants just to refer to the
|
||||
ISO_*_ names and get something.
|
||||
*/
|
||||
extern enum cdtext_enum1_s {
|
||||
CDIO_CDTEXT_MAX_PACK_DATA = 255,
|
||||
CDIO_CDTEXT_MAX_TEXT_DATA = 12,
|
||||
CDIO_CDTEXT_TITLE = 0x80,
|
||||
CDIO_CDTEXT_PERFORMER = 0x81,
|
||||
CDIO_CDTEXT_SONGWRITER = 0x82,
|
||||
CDIO_CDTEXT_COMPOSER = 0x83,
|
||||
CDIO_CDTEXT_ARRANGER = 0x84,
|
||||
CDIO_CDTEXT_MESSAGE = 0x85,
|
||||
CDIO_CDTEXT_DISCID = 0x86,
|
||||
CDIO_CDTEXT_GENRE = 0x87,
|
||||
CDIO_CDTEXT_TOC = 0x88,
|
||||
CDIO_CDTEXT_TOC2 = 0x89,
|
||||
CDIO_CDTEXT_UPC = 0x8E,
|
||||
CDIO_CDTEXT_BLOCKSIZE = 0x8F
|
||||
} cdtext_enums1;
|
||||
|
||||
#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, int i_data,
|
||||
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:
|
||||
*/
|
||||
1038
lib/driver/device.c
Normal file
1038
lib/driver/device.c
Normal file
File diff suppressed because it is too large
Load Diff
119
lib/driver/disc.c
Normal file
119
lib/driver/disc.c
Normal file
@@ -0,0 +1,119 @@
|
||||
/*
|
||||
$Id: disc.c,v 1.6 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
Copyright (C) 2001 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <cdio/cdio.h>
|
||||
#include "cdio_private.h"
|
||||
|
||||
/* Must match discmode enumeration */
|
||||
const char *discmode2str[] = {
|
||||
"CD-DA",
|
||||
"CD-DATA (Mode 1)",
|
||||
"CD DATA (Mode 2)",
|
||||
"CD-ROM Mixed",
|
||||
"DVD-ROM",
|
||||
"DVD-RAM",
|
||||
"DVD-R",
|
||||
"DVD-RW",
|
||||
"DVD+R",
|
||||
"DVD+RW",
|
||||
"Unknown/unclassified DVD",
|
||||
"No information",
|
||||
"Error in getting information",
|
||||
"CD-i"
|
||||
};
|
||||
|
||||
/*!
|
||||
Get the size of the CD in logical block address (LBA) units.
|
||||
|
||||
@param p_cdio the CD object queried
|
||||
@return the lsn. On error 0 or CDIO_INVALD_LSN.
|
||||
*/
|
||||
lsn_t
|
||||
cdio_get_disc_last_lsn(const CdIo_t *p_cdio)
|
||||
{
|
||||
if (!p_cdio) return CDIO_INVALID_LSN;
|
||||
return p_cdio->op.get_disc_last_lsn (p_cdio->env);
|
||||
}
|
||||
|
||||
/*!
|
||||
Get medium associated with cd_obj.
|
||||
*/
|
||||
discmode_t
|
||||
cdio_get_discmode (CdIo_t *cd_obj)
|
||||
{
|
||||
if (!cd_obj) return CDIO_DISC_MODE_ERROR;
|
||||
|
||||
if (cd_obj->op.get_discmode) {
|
||||
return cd_obj->op.get_discmode (cd_obj->env);
|
||||
} else {
|
||||
return CDIO_DISC_MODE_NO_INFO;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return a string containing the name of the driver in use.
|
||||
if CdIo is NULL (we haven't initialized a specific device driver),
|
||||
then return NULL.
|
||||
*/
|
||||
char *
|
||||
cdio_get_mcn (const CdIo_t *p_cdio)
|
||||
{
|
||||
if (p_cdio->op.get_mcn) {
|
||||
return p_cdio->op.get_mcn (p_cdio->env);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
251
lib/driver/ds.c
Normal file
251
lib/driver/ds.c
Normal file
@@ -0,0 +1,251 @@
|
||||
/*
|
||||
$Id: ds.c,v 1.4 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2005, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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.4 2008/04/22 15:29:12 karl Exp $";
|
||||
|
||||
struct _CdioList
|
||||
{
|
||||
unsigned length;
|
||||
|
||||
CdioListNode_t *begin;
|
||||
CdioListNode_t *end;
|
||||
};
|
||||
|
||||
struct _CdioListNode
|
||||
{
|
||||
CdioList_t *list;
|
||||
|
||||
CdioListNode_t *next;
|
||||
|
||||
void *data;
|
||||
};
|
||||
|
||||
/* impl */
|
||||
|
||||
CdioList_t *
|
||||
_cdio_list_new (void)
|
||||
{
|
||||
CdioList_t *p_new_obj = calloc (1, sizeof (CdioList_t));
|
||||
|
||||
return p_new_obj;
|
||||
}
|
||||
|
||||
void
|
||||
_cdio_list_free (CdioList_t *p_list, int free_data)
|
||||
{
|
||||
while (_cdio_list_length (p_list))
|
||||
_cdio_list_node_free (_cdio_list_begin (p_list), free_data);
|
||||
|
||||
free (p_list);
|
||||
}
|
||||
|
||||
unsigned
|
||||
_cdio_list_length (const CdioList_t *p_list)
|
||||
{
|
||||
cdio_assert (p_list != NULL);
|
||||
|
||||
return p_list->length;
|
||||
}
|
||||
|
||||
void
|
||||
_cdio_list_prepend (CdioList_t *p_list, void *p_data)
|
||||
{
|
||||
CdioListNode_t *p_new_node;
|
||||
|
||||
cdio_assert (p_list != NULL);
|
||||
|
||||
p_new_node = calloc (1, sizeof (CdioListNode_t));
|
||||
|
||||
p_new_node->list = p_list;
|
||||
p_new_node->next = p_list->begin;
|
||||
p_new_node->data = p_data;
|
||||
|
||||
p_list->begin = p_new_node;
|
||||
if (p_list->length == 0)
|
||||
p_list->end = p_new_node;
|
||||
|
||||
p_list->length++;
|
||||
}
|
||||
|
||||
void
|
||||
_cdio_list_append (CdioList_t *p_list, void *p_data)
|
||||
{
|
||||
cdio_assert (p_list != NULL);
|
||||
|
||||
if (p_list->length == 0)
|
||||
{
|
||||
_cdio_list_prepend (p_list, p_data);
|
||||
}
|
||||
else
|
||||
{
|
||||
CdioListNode_t *p_new_node = calloc (1, sizeof (CdioListNode_t));
|
||||
|
||||
p_new_node->list = p_list;
|
||||
p_new_node->next = NULL;
|
||||
p_new_node->data = p_data;
|
||||
|
||||
p_list->end->next = p_new_node;
|
||||
p_list->end = p_new_node;
|
||||
|
||||
p_list->length++;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_cdio_list_foreach (CdioList_t *p_list, _cdio_list_iterfunc_t func,
|
||||
void *p_user_data)
|
||||
{
|
||||
CdioListNode_t *node;
|
||||
|
||||
cdio_assert (p_list != NULL);
|
||||
cdio_assert (func != 0);
|
||||
|
||||
for (node = _cdio_list_begin (p_list);
|
||||
node != NULL;
|
||||
node = _cdio_list_node_next (node))
|
||||
func (_cdio_list_node_data (node), p_user_data);
|
||||
}
|
||||
|
||||
CdioListNode_t *
|
||||
_cdio_list_find (CdioList_t *p_list, _cdio_list_iterfunc_t cmp_func,
|
||||
void *p_user_data)
|
||||
{
|
||||
CdioListNode_t *p_node;
|
||||
|
||||
cdio_assert (p_list != NULL);
|
||||
cdio_assert (cmp_func != 0);
|
||||
|
||||
for (p_node = _cdio_list_begin (p_list);
|
||||
p_node != NULL;
|
||||
p_node = _cdio_list_node_next (p_node))
|
||||
if (cmp_func (_cdio_list_node_data (p_node), p_user_data))
|
||||
break;
|
||||
|
||||
return p_node;
|
||||
}
|
||||
|
||||
CdioListNode_t *
|
||||
_cdio_list_begin (const CdioList_t *p_list)
|
||||
{
|
||||
cdio_assert (p_list != NULL);
|
||||
|
||||
return p_list->begin;
|
||||
}
|
||||
|
||||
CdioListNode_t *
|
||||
_cdio_list_end (CdioList_t *p_list)
|
||||
{
|
||||
cdio_assert (p_list != NULL);
|
||||
|
||||
return p_list->end;
|
||||
}
|
||||
|
||||
CdioListNode_t *
|
||||
_cdio_list_node_next (CdioListNode_t *p_node)
|
||||
{
|
||||
if (p_node)
|
||||
return p_node->next;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
_cdio_list_node_free (CdioListNode_t *p_node, int free_data)
|
||||
{
|
||||
CdioList_t *p_list;
|
||||
CdioListNode_t *prev_node;
|
||||
|
||||
cdio_assert (p_node != NULL);
|
||||
|
||||
p_list = p_node->list;
|
||||
|
||||
cdio_assert (_cdio_list_length (p_list) > 0);
|
||||
|
||||
if (free_data)
|
||||
free (_cdio_list_node_data (p_node));
|
||||
|
||||
if (_cdio_list_length (p_list) == 1)
|
||||
{
|
||||
cdio_assert (p_list->begin == p_list->end);
|
||||
|
||||
p_list->end = p_list->begin = NULL;
|
||||
p_list->length = 0;
|
||||
free (p_node);
|
||||
return;
|
||||
}
|
||||
|
||||
cdio_assert (p_list->begin != p_list->end);
|
||||
|
||||
if (p_list->begin == p_node)
|
||||
{
|
||||
p_list->begin = p_node->next;
|
||||
free (p_node);
|
||||
p_list->length--;
|
||||
return;
|
||||
}
|
||||
|
||||
for (prev_node = p_list->begin; prev_node->next; prev_node = prev_node->next)
|
||||
if (prev_node->next == p_node)
|
||||
break;
|
||||
|
||||
cdio_assert (prev_node->next != NULL);
|
||||
|
||||
if (p_list->end == p_node)
|
||||
p_list->end = prev_node;
|
||||
|
||||
prev_node->next = p_node->next;
|
||||
|
||||
p_list->length--;
|
||||
|
||||
free (p_node);
|
||||
}
|
||||
|
||||
void *
|
||||
_cdio_list_node_data (CdioListNode_t *p_node)
|
||||
{
|
||||
if (p_node)
|
||||
return p_node->data;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* eof */
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "gnu"
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
|
||||
222
lib/driver/generic.h
Normal file
222
lib/driver/generic.h
Normal file
@@ -0,0 +1,222 @@
|
||||
/*
|
||||
$Id: generic.h,v 1.16 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2004, 2005, 2006, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Internal routines for CD I/O drivers. */
|
||||
|
||||
|
||||
#ifndef __CDIO_GENERIC_H__
|
||||
#define __CDIO_GENERIC_H__
|
||||
|
||||
#if defined(HAVE_CONFIG_H) && !defined(LIBCDIO_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_t *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_t *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*/
|
||||
track_flags_t track_flags[CDIO_CD_MAX_TRACKS+1];
|
||||
} 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?
|
||||
*/
|
||||
driver_return_code_t cdio_generic_unimplemented_eject_media (void *p_env);
|
||||
|
||||
/*!
|
||||
Set the blocksize for subsequent reads.
|
||||
|
||||
@return -2 since it's not implemented.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_generic_unimplemented_set_blocksize (void *p_user_data,
|
||||
uint16_t i_blocksize);
|
||||
|
||||
/*!
|
||||
Set the drive speed.
|
||||
|
||||
@return -2 since it's not implemented.
|
||||
*/
|
||||
driver_return_code_t cdio_generic_unimplemented_set_speed (void *p_user_data,
|
||||
int i_speed);
|
||||
|
||||
/*!
|
||||
Release and free resources associated with cd.
|
||||
*/
|
||||
void cdio_generic_free (void *p_env);
|
||||
|
||||
/*!
|
||||
Initialize CD device.
|
||||
*/
|
||||
bool cdio_generic_init (void *p_env, int open_mode);
|
||||
|
||||
/*!
|
||||
Reads into buf the next size bytes.
|
||||
Returns -1 on error.
|
||||
Is in fact libc's read().
|
||||
*/
|
||||
off_t cdio_generic_lseek (void *p_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 *p_env, void *p_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.
|
||||
*/
|
||||
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 );
|
||||
|
||||
/*! Return number of channels in track: 2 or 4; -2 if not
|
||||
implemented or -1 for error.
|
||||
Not meaningful if track is not an audio track.
|
||||
*/
|
||||
int get_track_channels_generic(const void *p_user_data, track_t i_track);
|
||||
|
||||
/*! Return 1 if copy is permitted on the track, 0 if not, or -1 for error.
|
||||
Is this meaningful if not an audio track?
|
||||
*/
|
||||
track_flag_t get_track_copy_permit_generic(void *p_user_data,
|
||||
track_t i_track);
|
||||
|
||||
/*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error.
|
||||
Is this meaningful if not an audio track?
|
||||
|
||||
pre-emphasis is a non linear frequency response.
|
||||
*/
|
||||
track_flag_t get_track_preemphasis_generic(const void *p_user_data,
|
||||
track_t i_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);
|
||||
/*!
|
||||
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);
|
||||
|
||||
void set_track_flags(track_flags_t *p_track_flag, uint8_t flag);
|
||||
|
||||
/*! Read mode 1 or mode2 sectors (using cooked mode). */
|
||||
driver_return_code_t read_data_sectors_generic (void *p_user_data,
|
||||
void *p_buf, lsn_t i_lsn,
|
||||
uint16_t i_blocksize,
|
||||
uint32_t i_blocks);
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#endif /* __CDIO_GENERIC_H__ */
|
||||
1671
lib/driver/gnu_linux.c
Normal file
1671
lib/driver/gnu_linux.c
Normal file
File diff suppressed because it is too large
Load Diff
81
lib/driver/image.h
Normal file
81
lib/driver/image.h
Normal file
@@ -0,0 +1,81 @@
|
||||
/*
|
||||
$Id: image.h,v 1.9 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*!
|
||||
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 pregap; /**< pre-gap */
|
||||
lba_t silence; /**< 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_t *data_source;
|
||||
off_t offset; /**< byte offset into data_start of track
|
||||
beginning. In cdrdao for example, one
|
||||
filename may cover many tracks and
|
||||
each track would then have a different
|
||||
offset.
|
||||
*/
|
||||
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 of frame
|
||||
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__ */
|
||||
21
lib/driver/image/Makefile
Normal file
21
lib/driver/image/Makefile
Normal file
@@ -0,0 +1,21 @@
|
||||
# $Id: Makefile,v 1.2 2008/04/21 18:30:22 karl Exp $
|
||||
#
|
||||
# Copyright (C) 2004, 2008 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 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# The make is done above. This boilerplate Makefile just transfers the call
|
||||
|
||||
|
||||
all install check clean:
|
||||
cd .. && $(MAKE) $@
|
||||
1217
lib/driver/image/bincue.c
Normal file
1217
lib/driver/image/bincue.c
Normal file
File diff suppressed because it is too large
Load Diff
1341
lib/driver/image/cdrdao.c
Normal file
1341
lib/driver/image/cdrdao.c
Normal file
File diff suppressed because it is too large
Load Diff
1352
lib/driver/image/nrg.c
Normal file
1352
lib/driver/image/nrg.c
Normal file
File diff suppressed because it is too large
Load Diff
155
lib/driver/image/nrg.h
Normal file
155
lib/driver/image/nrg.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/*
|
||||
$Id: nrg.h,v 1.7 2008/06/10 00:45:08 pjcreath Exp $
|
||||
|
||||
Copyright (C) 2004, 2006, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* 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; /* has track copy bit and whether audiofile
|
||||
or datafile. Is often 0x41 == 'A' */
|
||||
uint8_t track; /* binary or BCD?? */
|
||||
uint8_t addr_ctrl; /* addresstype: MSF or LBA in lower 4 bits
|
||||
control in upper 4 bits.
|
||||
makes 0->1 transitions */
|
||||
uint8_t res; /* ?? */
|
||||
uint32_t lsn GNUC_PACKED;
|
||||
} _cuex_array_t;
|
||||
|
||||
/* New DAO[XI] Information from http://en.wikipedia.org/wiki/NRG_(file_format)
|
||||
*/
|
||||
|
||||
typedef struct {
|
||||
char psz_isrc[CDIO_ISRC_SIZE];
|
||||
uint8_t unknown[6];
|
||||
} _dao_array_common_t;
|
||||
|
||||
typedef struct {
|
||||
_dao_array_common_t common;
|
||||
uint64_t index0 GNUC_PACKED;
|
||||
uint64_t index1 GNUC_PACKED;
|
||||
uint64_t end_of_track GNUC_PACKED;
|
||||
} _daox_array_t;
|
||||
|
||||
typedef struct {
|
||||
_dao_array_common_t common;
|
||||
uint32_t index0 GNUC_PACKED;
|
||||
uint32_t index1 GNUC_PACKED;
|
||||
uint32_t end_of_track GNUC_PACKED;
|
||||
} _daoi_array_t;
|
||||
|
||||
typedef struct GNUC_PACKED {
|
||||
uint32_t chunk_size_le GNUC_PACKED;
|
||||
char psz_mcn[CDIO_MCN_SIZE];
|
||||
uint8_t unknown[3];
|
||||
uint8_t first_track;
|
||||
uint8_t last_track;
|
||||
} _dao_common_t;
|
||||
|
||||
typedef struct {
|
||||
_dao_common_t common;
|
||||
_daox_array_t track_info[EMPTY_ARRAY_SIZE];
|
||||
} _daox_t;
|
||||
|
||||
typedef struct {
|
||||
_dao_common_t common;
|
||||
_daoi_array_t track_info[EMPTY_ARRAY_SIZE];
|
||||
} _daoi_t;
|
||||
|
||||
typedef struct {
|
||||
uint32_t id GNUC_PACKED;
|
||||
uint32_t len GNUC_PACKED;
|
||||
char data[EMPTY_ARRAY_SIZE];
|
||||
} _chunk_t;
|
||||
|
||||
PRAGMA_END_PACKED
|
||||
|
||||
/* Nero images are Big Endian. */
|
||||
typedef enum {
|
||||
CDTX_ID = 0x43445458, /* CD TEXT */
|
||||
CUEX_ID = 0x43554558, /* Nero version 5.5.x-6.x */
|
||||
CUES_ID = 0x43554553, /* Nero pre version 5.5.x-6.x */
|
||||
DAOX_ID = 0x44414f58, /* Nero version 5.5.x-6.x */
|
||||
DAOI_ID = 0x44414f49,
|
||||
END1_ID = 0x454e4421,
|
||||
ETN2_ID = 0x45544e32,
|
||||
ETNF_ID = 0x45544e46,
|
||||
NER5_ID = 0x4e455235, /* Nero version 5.5.x */
|
||||
NERO_ID = 0x4e45524f, /* Nero pre 5.5.x */
|
||||
SINF_ID = 0x53494e46, /* Session information */
|
||||
MTYP_ID = 0x4d545950, /* Disc Media type? */
|
||||
} nero_id_t;
|
||||
|
||||
#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 */
|
||||
typedef enum {
|
||||
DTYP_MODE1 = 0,
|
||||
DTYP_MODE2_XA = 2,
|
||||
DTYP_INVALID = 255
|
||||
} nero_dtype_t;
|
||||
|
||||
/** The below variables are trickery to force the above enum symbol
|
||||
values to be recorded in debug symbol tables. They are used to
|
||||
allow one to refer to the enumeration value names in the typedefs
|
||||
above in a debugger and debugger expressions.
|
||||
*/
|
||||
extern nero_id_t nero_id;
|
||||
extern nero_dtype_t nero_dtype;
|
||||
|
||||
373
lib/driver/image_common.c
Normal file
373
lib/driver/image_common.c
Normal file
@@ -0,0 +1,373 @@
|
||||
/*
|
||||
$Id: image_common.c,v 1.15 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*! 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
|
||||
*/
|
||||
|
||||
#include "image.h"
|
||||
#include "image_common.h"
|
||||
#include "_cdio_stdio.h"
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Eject media -- there's nothing to do here except free resources.
|
||||
We always return DRIVER_OP_UNSUPPORTED.
|
||||
*/
|
||||
driver_return_code_t
|
||||
_eject_media_image(void *p_user_data)
|
||||
{
|
||||
_free_image (p_user_data);
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*!
|
||||
We don't need the image any more. Free all memory associated with
|
||||
it.
|
||||
*/
|
||||
void
|
||||
_free_image (void *p_user_data)
|
||||
{
|
||||
_img_private_t *p_env = p_user_data;
|
||||
track_t i_track;
|
||||
|
||||
if (NULL == p_env) return;
|
||||
|
||||
for (i_track=0; i_track < p_env->gen.i_tracks; i_track++) {
|
||||
track_info_t *p_tocent = &(p_env->tocent[i_track]);
|
||||
free_if_notnull(p_tocent->filename);
|
||||
free_if_notnull(p_tocent->isrc);
|
||||
cdtext_destroy(&(p_tocent->cdtext));
|
||||
if (p_tocent->data_source) cdio_stdio_destroy(p_tocent->data_source);
|
||||
}
|
||||
|
||||
free_if_notnull(p_env->psz_mcn);
|
||||
free_if_notnull(p_env->psz_cue_name);
|
||||
free_if_notnull(p_env->psz_access_mode);
|
||||
cdtext_destroy(&(p_env->gen.cdtext));
|
||||
cdio_generic_stdio_free(p_env);
|
||||
free(p_env);
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the value associated with the key "arg".
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
discmode_t
|
||||
_get_discmode_image (void *p_user_data)
|
||||
{
|
||||
_img_private_t *p_env = p_user_data;
|
||||
return p_env->disc_mode;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the the kind of drive capabilities of device.
|
||||
|
||||
*/
|
||||
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_CD_DA
|
||||
| CDIO_DRIVE_CAP_READ_CD_G
|
||||
| CDIO_DRIVE_CAP_READ_CD_R
|
||||
| CDIO_DRIVE_CAP_READ_CD_RW
|
||||
| CDIO_DRIVE_CAP_READ_MODE2_FORM1
|
||||
| CDIO_DRIVE_CAP_READ_MODE2_FORM2
|
||||
| CDIO_DRIVE_CAP_READ_MCN
|
||||
;
|
||||
|
||||
*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;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the number of of the first track.
|
||||
CDIO_INVALID_TRACK is returned on error.
|
||||
*/
|
||||
track_t
|
||||
_get_first_track_num_image(void *p_user_data)
|
||||
{
|
||||
_img_private_t *p_env = p_user_data;
|
||||
|
||||
return p_env->gen.i_first_track;
|
||||
}
|
||||
|
||||
/*!
|
||||
Find out if media has changed since the last call.
|
||||
@param p_user_data the CD object to be acted upon.
|
||||
@return 1 if media has changed since last call, 0 if not. Error
|
||||
return codes are the same as driver_return_code_t
|
||||
There is no such thing as changing a media image so we will
|
||||
always return 0 - no change.
|
||||
*/
|
||||
int
|
||||
get_media_changed_image(const void *p_user_data)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
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.
|
||||
*/
|
||||
char *
|
||||
_get_mcn_image(const void *p_user_data)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
|
||||
if (!p_env || !p_env->psz_mcn) return NULL;
|
||||
return strdup(p_env->psz_mcn);
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the number of tracks.
|
||||
*/
|
||||
track_t
|
||||
_get_num_tracks_image(void *p_user_data)
|
||||
{
|
||||
_img_private_t *p_env = p_user_data;
|
||||
|
||||
return p_env->gen.i_tracks;
|
||||
}
|
||||
|
||||
/*!
|
||||
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.
|
||||
|
||||
*/
|
||||
bool
|
||||
_get_track_msf_image(void *p_user_data, track_t i_track, msf_t *msf)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
|
||||
if (NULL == msf) return false;
|
||||
|
||||
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) {
|
||||
*msf = p_env->tocent[i_track-p_env->gen.i_first_track].start_msf;
|
||||
return true;
|
||||
} else
|
||||
return false;
|
||||
}
|
||||
|
||||
/*! Return number of channels in track: 2 or 4; -2 if not
|
||||
implemented or -1 for error.
|
||||
Not meaningful if track is not an audio track.
|
||||
*/
|
||||
int
|
||||
get_track_channels_image(const void *p_user_data, track_t i_track)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
return ( p_env->tocent[i_track-p_env->gen.i_first_track].flags
|
||||
& FOUR_CHANNEL_AUDIO ) ? 4 : 2;
|
||||
}
|
||||
|
||||
/*! Return 1 if copy is permitted on the track, 0 if not, or -1 for error.
|
||||
Is this meaningful if not an audio track?
|
||||
*/
|
||||
track_flag_t
|
||||
get_track_copy_permit_image(void *p_user_data, track_t i_track)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
return ( p_env->tocent[i_track-p_env->gen.i_first_track].flags
|
||||
& COPY_PERMITTED ) ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
|
||||
}
|
||||
|
||||
/*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error.
|
||||
Is this meaningful if not an audio track?
|
||||
|
||||
pre-emphasis is a non linear frequency response.
|
||||
*/
|
||||
track_flag_t
|
||||
get_track_preemphasis_image(const void *p_user_data, track_t i_track)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
return ( p_env->tocent[i_track-p_env->gen.i_first_track].flags
|
||||
& PRE_EMPHASIS ) ? CDIO_TRACK_FLAG_TRUE : CDIO_TRACK_FLAG_FALSE;
|
||||
}
|
||||
|
||||
/*! Return the starting LBA for the pregap for track number i_track.
|
||||
Track numbers start at 1.
|
||||
CDIO_INVALID_LBA is returned on error.
|
||||
*/
|
||||
lba_t
|
||||
get_track_pregap_lba_image(const void *p_user_data, track_t i_track)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
lba_t pregap, start_lba;
|
||||
|
||||
pregap = p_env->tocent[i_track-p_env->gen.i_first_track].pregap;
|
||||
start_lba = p_env->tocent[i_track-p_env->gen.i_first_track].start_lba;
|
||||
|
||||
/* avoid initializing pregap to CDIO_INVALID_LBA by letting calloc
|
||||
do the work. also, nero files have the pregap set equal
|
||||
to the start of the track when there is no pregap
|
||||
*/
|
||||
if (!pregap || pregap == start_lba) {
|
||||
pregap = CDIO_INVALID_LBA;
|
||||
}
|
||||
|
||||
return pregap;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the International Standard Recording Code (ISRC) for track number
|
||||
i_track in p_cdio. Track numbers start at 1.
|
||||
|
||||
Note: string is malloc'd so caller has to free() the returned
|
||||
string when done with it.
|
||||
*/
|
||||
char *
|
||||
get_track_isrc_image(const void *p_user_data, track_t i_track)
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
char *isrc = p_env->tocent[i_track-p_env->gen.i_first_track].isrc;
|
||||
|
||||
if (isrc && isrc[0]) {
|
||||
return strdup(isrc);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Read a data sector
|
||||
|
||||
@param p_cdio object to read from
|
||||
|
||||
@param p_buf place to read data into. The caller should make sure
|
||||
this location can store at least ISO_BLOCKSIZE, M2RAW_SECTOR_SIZE,
|
||||
or M2F2_SECTOR_SIZE depending on the kind of sector getting read. If
|
||||
you don't know whether you have a Mode 1/2, Form 1/ Form 2/Formless
|
||||
sector best to reserve space for the maximum, M2RAW_SECTOR_SIZE.
|
||||
|
||||
@param i_lsn sector to read
|
||||
|
||||
@param i_blocksize size of block. Should be either ISO_BLOCKSIZE
|
||||
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE. See comment above under
|
||||
p_buf.
|
||||
*/
|
||||
driver_return_code_t
|
||||
read_data_sectors_image ( void *p_user_data, void *p_buf,
|
||||
lsn_t i_lsn, uint16_t i_blocksize,
|
||||
uint32_t i_blocks )
|
||||
{
|
||||
const _img_private_t *p_env = p_user_data;
|
||||
|
||||
if (!p_env || !p_env->gen.cdio) return DRIVER_OP_UNINIT;
|
||||
|
||||
{
|
||||
CdIo_t *p_cdio = p_env->gen.cdio;
|
||||
track_t i_track = cdio_get_track(p_cdio, i_lsn);
|
||||
track_format_t e_track_format = cdio_get_track_format(p_cdio, i_track);
|
||||
|
||||
switch(e_track_format) {
|
||||
case TRACK_FORMAT_PSX:
|
||||
case TRACK_FORMAT_AUDIO:
|
||||
case TRACK_FORMAT_ERROR:
|
||||
return DRIVER_OP_ERROR;
|
||||
case TRACK_FORMAT_DATA:
|
||||
return cdio_read_mode1_sectors (p_cdio, p_buf, i_lsn, false, i_blocks);
|
||||
case TRACK_FORMAT_CDI:
|
||||
case TRACK_FORMAT_XA:
|
||||
return cdio_read_mode2_sectors (p_cdio, p_buf, i_lsn, false, i_blocks);
|
||||
}
|
||||
}
|
||||
return DRIVER_OP_ERROR;
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
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.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
_set_arg_image (void *p_user_data, const char key[], const char value[])
|
||||
{
|
||||
_img_private_t *p_env = p_user_data;
|
||||
|
||||
if (!strcmp (key, "source"))
|
||||
{
|
||||
free_if_notnull (p_env->gen.source_name);
|
||||
if (!value) return DRIVER_OP_ERROR;
|
||||
p_env->gen.source_name = strdup (value);
|
||||
}
|
||||
else if (!strcmp (key, "cue"))
|
||||
{
|
||||
free_if_notnull (p_env->psz_cue_name);
|
||||
if (!value) return DRIVER_OP_ERROR;
|
||||
p_env->psz_cue_name = strdup (value);
|
||||
}
|
||||
else if (!strcmp (key, "access-mode"))
|
||||
{
|
||||
free_if_notnull (p_env->psz_access_mode);
|
||||
if (!value) return DRIVER_OP_ERROR;
|
||||
p_env->psz_access_mode = strdup (value);
|
||||
}
|
||||
else
|
||||
return DRIVER_OP_ERROR;
|
||||
|
||||
return DRIVER_OP_SUCCESS;
|
||||
}
|
||||
|
||||
202
lib/driver/image_common.h
Normal file
202
lib/driver/image_common.h
Normal file
@@ -0,0 +1,202 @@
|
||||
/*
|
||||
$Id: image_common.h,v 1.13 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2004, 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*! 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__
|
||||
|
||||
typedef struct {
|
||||
/* Things common to all drivers like this.
|
||||
This must be first. */
|
||||
generic_img_private_t gen;
|
||||
internal_position_t pos;
|
||||
|
||||
char *psz_cue_name;
|
||||
char *psz_access_mode; /* Just the name of the driver.
|
||||
We add this for regularity with other
|
||||
real CD drivers which has an access mode.
|
||||
*/
|
||||
char *psz_mcn; /* Media Catalog Number (5.22.3)
|
||||
exactly 13 bytes */
|
||||
track_info_t tocent[CDIO_CD_MAX_TRACKS+1]; /* entry info for each track
|
||||
add 1 for leadout. */
|
||||
discmode_t disc_mode;
|
||||
|
||||
#ifdef NEED_NERO_STRUCT
|
||||
/* Nero Specific stuff. Note: for the image_free to work, this *must*
|
||||
be last. */
|
||||
bool is_dao; /* True if some of disk at once. False
|
||||
if some sort of track at once. */
|
||||
uint32_t mtyp; /* Value of MTYP (media type?) tag */
|
||||
uint8_t dtyp; /* Value of DAOX media type tag */
|
||||
|
||||
/* This is a hack because I don't really understnad NERO better. */
|
||||
bool is_cues;
|
||||
|
||||
CdioList_t *mapping; /* List of track information */
|
||||
uint32_t size;
|
||||
#endif
|
||||
} _img_private_t;
|
||||
|
||||
#define free_if_notnull(p_obj) \
|
||||
if (NULL != p_obj) { free(p_obj); p_obj=NULL; };
|
||||
|
||||
/*!
|
||||
We don't need the image any more. Free all memory associated with
|
||||
it.
|
||||
*/
|
||||
void _free_image (void *p_user_data);
|
||||
|
||||
int _eject_media_image(void *p_user_data);
|
||||
|
||||
/*!
|
||||
Return the value associated with the key "arg".
|
||||
*/
|
||||
const char * _get_arg_image (void *user_data, const char key[]);
|
||||
|
||||
/*!
|
||||
Get disc type associated with cd_obj.
|
||||
*/
|
||||
discmode_t _get_discmode_image (void *p_user_data);
|
||||
|
||||
/*!
|
||||
Return the the kind of drive capabilities of device.
|
||||
|
||||
*/
|
||||
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);
|
||||
|
||||
/*!
|
||||
Return the number of of the first track.
|
||||
CDIO_INVALID_TRACK is returned on error.
|
||||
*/
|
||||
track_t _get_first_track_num_image(void *p_user_data);
|
||||
|
||||
/*!
|
||||
Find out if media has changed since the last call.
|
||||
@param p_user_data the CD object to be acted upon.
|
||||
@return 1 if media has changed since last call, 0 if not. Error
|
||||
return codes are the same as driver_return_code_t
|
||||
We always return DRIVER_OP_UNSUPPORTED.
|
||||
*/
|
||||
int get_media_changed_image(const void *p_user_data);
|
||||
|
||||
/*!
|
||||
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.
|
||||
*/
|
||||
char * _get_mcn_image(const void *p_user_data);
|
||||
|
||||
/*!
|
||||
Return the number of tracks.
|
||||
*/
|
||||
track_t _get_num_tracks_image(void *p_user_data);
|
||||
|
||||
|
||||
/*!
|
||||
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.
|
||||
|
||||
*/
|
||||
bool _get_track_msf_image(void *p_user_data, track_t i_track, msf_t *msf);
|
||||
|
||||
/*! Return number of channels in track: 2 or 4; -2 if not
|
||||
implemented or -1 for error.
|
||||
Not meaningful if track is not an audio track.
|
||||
*/
|
||||
int get_track_channels_image(const void *p_user_data, track_t i_track);
|
||||
|
||||
/*! Return 1 if copy is permitted on the track, 0 if not, or -1 for error.
|
||||
Is this meaningful if not an audio track?
|
||||
*/
|
||||
track_flag_t get_track_copy_permit_image(void *p_user_data, track_t i_track);
|
||||
|
||||
/*! Return 1 if track has pre-emphasis, 0 if not, or -1 for error.
|
||||
Is this meaningful if not an audio track?
|
||||
|
||||
pre-emphasis is a non linear frequency response.
|
||||
*/
|
||||
track_flag_t get_track_preemphasis_image(const void *p_user_data,
|
||||
track_t i_track);
|
||||
|
||||
/*! Return the starting LBA for the pregap for track number i_track.
|
||||
Track numbers start at 1.
|
||||
CDIO_INVALID_LBA is returned on error.
|
||||
*/
|
||||
lba_t get_track_pregap_lba_image(const void *p_user_data, track_t i_track);
|
||||
|
||||
/*!
|
||||
Return the International Standard Recording Code (ISRC) for track number
|
||||
i_track in p_cdio. Track numbers start at 1.
|
||||
|
||||
Note: string is malloc'd so caller has to free() the returned
|
||||
string when done with it.
|
||||
*/
|
||||
char *get_track_isrc_image(const void *p_user_data, track_t i_track);
|
||||
|
||||
/*!
|
||||
Read a data sector
|
||||
|
||||
@param p_cdio object to read from
|
||||
|
||||
@param p_buf place to read data into. The caller should make sure
|
||||
this location can store at least ISO_BLOCKSIZE, M2RAW_SECTOR_SIZE,
|
||||
or M2F2_SECTOR_SIZE depending on the kind of sector getting read. If
|
||||
you don't know whether you have a Mode 1/2, Form 1/ Form 2/Formless
|
||||
sector best to reserve space for the maximum, M2RAW_SECTOR_SIZE.
|
||||
|
||||
@param i_lsn sector to read
|
||||
|
||||
@param i_blocksize size of block. Should be either ISO_BLOCKSIZE
|
||||
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE. See comment above under
|
||||
p_buf.
|
||||
|
||||
@param i_blocks number of blocks to read.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
read_data_sectors_image ( void *p_user_data, void *p_buf,
|
||||
lsn_t i_lsn, uint16_t i_blocksize,
|
||||
uint32_t i_blocks );
|
||||
|
||||
/*!
|
||||
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.
|
||||
*/
|
||||
int _set_arg_image (void *user_data, const char key[], const char value[]);
|
||||
|
||||
#endif /* __CDIO_IMAGE_COMMON_H__ */
|
||||
220
lib/driver/libcdio.sym
Normal file
220
lib/driver/libcdio.sym
Normal file
@@ -0,0 +1,220 @@
|
||||
CDIO_SECTOR_SYNC_HEADER
|
||||
_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_audio_get_msf_seconds
|
||||
cdio_audio_get_volume
|
||||
cdio_audio_pause
|
||||
cdio_audio_play_msf
|
||||
cdio_audio_play_track_index
|
||||
cdio_audio_read_subchannel
|
||||
cdio_audio_resume
|
||||
cdio_audio_set_volume
|
||||
cdio_audio_stop
|
||||
cdio_close_tray
|
||||
cdio_debug
|
||||
cdio_destroy
|
||||
cdio_driver_describe
|
||||
cdio_driver_errmsg
|
||||
cdio_eject_media
|
||||
cdio_eject_media_drive
|
||||
cdio_error
|
||||
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_driver
|
||||
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_disc_last_lsn
|
||||
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_last_session
|
||||
cdio_get_last_track_num
|
||||
cdio_get_mcn
|
||||
cdio_get_media_changed
|
||||
cdio_get_num_tracks
|
||||
cdio_get_track
|
||||
cdio_get_track_channels
|
||||
cdio_get_track_copy_permit
|
||||
cdio_get_track_format
|
||||
cdio_get_track_green
|
||||
cdio_get_track_last_lsn
|
||||
cdio_get_track_lba
|
||||
cdio_get_track_pregap_lba
|
||||
cdio_get_track_pregap_lsn
|
||||
cdio_get_track_isrc
|
||||
cdio_get_track_lsn
|
||||
cdio_get_track_msf
|
||||
cdio_get_track_preemphasis
|
||||
cdio_get_track_sec_count
|
||||
cdio_guess_cd_type
|
||||
cdio_have_atapi
|
||||
cdio_have_bincue
|
||||
cdio_have_bsdi
|
||||
cdio_have_cdrdao
|
||||
cdio_have_driver
|
||||
cdio_have_freebsd
|
||||
cdio_have_linux
|
||||
cdio_have_netbsd
|
||||
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_discmode_dvd
|
||||
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_netbsd
|
||||
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_netbsd
|
||||
cdio_open_nrg
|
||||
cdio_open_osx
|
||||
cdio_open_solaris
|
||||
cdio_open_win32
|
||||
cdio_os_driver
|
||||
cdio_read
|
||||
cdio_read_audio_sector
|
||||
cdio_read_audio_sectors
|
||||
cdio_read_data_sectors
|
||||
cdio_read_mode1_sector
|
||||
cdio_read_mode1_sectors
|
||||
cdio_read_mode2_sector
|
||||
cdio_read_mode2_sectors
|
||||
cdio_read_sector
|
||||
cdio_read_sectors
|
||||
cdio_set_arg
|
||||
cdio_set_blocksize
|
||||
cdio_set_drive_speed
|
||||
cdio_set_speed
|
||||
cdio_stdio_destroy
|
||||
cdio_stdio_new
|
||||
cdio_stream_getpos
|
||||
cdio_stream_read
|
||||
cdio_stream_seek
|
||||
cdio_to_bcd8
|
||||
cdio_warn
|
||||
cdtext_destroy
|
||||
cdtext_field2str
|
||||
cdtext_get
|
||||
cdtext_get_const
|
||||
cdtext_init
|
||||
cdtext_is_keyword
|
||||
cdtext_set
|
||||
debug_cdio_mmc_feature
|
||||
debug_cdio_mmc_feature_interface
|
||||
debug_cdio_mmc_feature_profile
|
||||
debug_cdio_mmc_get_conf
|
||||
debug_cdio_mmc_gpcmd
|
||||
debug_cdio_mmc_read_sub_state
|
||||
discmode2str
|
||||
mmc_audio_read_subchannel
|
||||
mmc_audio_state2str
|
||||
mmc_close_tray
|
||||
mmc_eject_media
|
||||
mmc_feature2str
|
||||
mmc_feature_profile2str
|
||||
mmc_get_blocksize
|
||||
mmc_get_cmd_len
|
||||
mmc_get_discmode
|
||||
mmc_get_drive_mmc_cap
|
||||
mmc_get_dvd_struct_physical
|
||||
mmc_get_hwinfo
|
||||
mmc_get_last_lsn
|
||||
mmc_get_mcn
|
||||
mmc_get_media_changed
|
||||
mmc_get_tray_status
|
||||
mmc_have_interface
|
||||
mmc_mode_sense
|
||||
mmc_mode_sense_10
|
||||
mmc_mode_sense_6
|
||||
mmc_read_cd
|
||||
mmc_read_data_sectors
|
||||
mmc_read_sectors
|
||||
mmc_read_timeout_ms
|
||||
mmc_run_cmd
|
||||
mmc_run_cmd_len
|
||||
mmc_set_blocksize
|
||||
mmc_set_speed
|
||||
mmc_start_stop_media
|
||||
mmc_timeout_ms
|
||||
track_format2str
|
||||
cdio_charset_converter_create
|
||||
cdio_charset_converter_destroy
|
||||
cdio_charset_convert
|
||||
cdio_charset_from_utf8
|
||||
cdio_charset_to_utf8
|
||||
142
lib/driver/logging.c
Normal file
142
lib/driver/logging.c
Normal file
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
$Id: logging.c,v 1.2 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#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.2 2008/04/22 15:29:12 karl 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:
|
||||
*/
|
||||
1468
lib/driver/mmc.c
Normal file
1468
lib/driver/mmc.c
Normal file
File diff suppressed because it is too large
Load Diff
155
lib/driver/mmc_private.h
Normal file
155
lib/driver/mmc_private.h
Normal file
@@ -0,0 +1,155 @@
|
||||
/* private MMC helper routines.
|
||||
|
||||
$Id: mmc_private.h,v 1.12 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2004, 2005, 2006, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cdio/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
|
||||
|
||||
/***********************************************************
|
||||
MMC CdIo Operations which a driver may use.
|
||||
These are not directly user-accessible.
|
||||
************************************************************/
|
||||
/*!
|
||||
Read Audio Subchannel information
|
||||
|
||||
@param p_user_data the CD object to be acted upon.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
audio_read_subchannel_mmc ( void *p_user_data,
|
||||
cdio_subchannel_t *p_subchannel);
|
||||
|
||||
/*!
|
||||
Get the block size for subsequest read requests, via a SCSI MMC
|
||||
MODE_SENSE 6 command.
|
||||
*/
|
||||
int get_blocksize_mmc (void *p_user_data);
|
||||
|
||||
/*!
|
||||
Get the lsn of the end of the CD
|
||||
|
||||
@return the lsn. On error return CDIO_INVALID_LSN.
|
||||
*/
|
||||
lsn_t get_disc_last_lsn_mmc( void *p_user_data );
|
||||
|
||||
void get_drive_cap_mmc (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 get_media_changed_mmc (const void *p_user_data);
|
||||
|
||||
char *get_mcn_mmc (const void *p_user_data);
|
||||
|
||||
driver_return_code_t get_tray_status (const void *p_user_data);
|
||||
|
||||
/*! Read just the user data part of some sort of data sector (via
|
||||
mmc_read_cd).
|
||||
|
||||
@param p_user_data object to read from
|
||||
|
||||
@param p_buf place to read data into. The caller should make sure
|
||||
this location can store at least CDIO_CD_FRAMESIZE,
|
||||
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE depending on
|
||||
the kind of sector getting read. If you don't know
|
||||
whether you have a Mode 1/2, Form 1/ Form 2/Formless
|
||||
sector best to reserve space for the maximum,
|
||||
M2RAW_SECTOR_SIZE.
|
||||
|
||||
@param i_lsn sector to read
|
||||
@param i_blocksize size of block. Should be either CDIO_CD_FRAMESIZE,
|
||||
M2RAW_SECTOR_SIZE, or M2F2_SECTOR_SIZE. See comment above under p_buf.
|
||||
|
||||
*/
|
||||
driver_return_code_t read_data_sectors_mmc ( void *p_user_data,
|
||||
void *p_buf, lsn_t i_lsn,
|
||||
uint16_t i_blocksize,
|
||||
uint32_t i_blocks );
|
||||
char *get_mcn_mmc (const void *p_user_data);
|
||||
|
||||
/* Set read blocksize (via MMC) */
|
||||
driver_return_code_t set_blocksize_mmc (void *p_user_data,
|
||||
uint16_t i_blocksize);
|
||||
|
||||
/* Set the drive speed in CD-ROM speed units (via MMC). */
|
||||
driver_return_code_t set_drive_speed_mmc (void *p_user_data, int i_speed);
|
||||
|
||||
/* Set CD-ROM drive speed in K bytes per second. (via MMC) */
|
||||
driver_return_code_t set_speed_mmc (void *p_user_data, int i_Kbs_speed);
|
||||
|
||||
/***********************************************************
|
||||
Miscellaenous other "private" routines. Probably need
|
||||
to better classify these.
|
||||
************************************************************/
|
||||
|
||||
typedef driver_return_code_t (*mmc_run_cmd_fn_t)
|
||||
( void *p_user_data,
|
||||
unsigned int i_timeout_ms,
|
||||
unsigned int i_cdb,
|
||||
const mmc_cdb_t *p_cdb,
|
||||
cdio_mmc_direction_t e_direction,
|
||||
unsigned int i_buf, /*in/out*/ void *p_buf );
|
||||
|
||||
int mmc_set_blocksize_mmc_private ( const void *p_env, const
|
||||
mmc_run_cmd_fn_t run_mmc_cmd,
|
||||
uint16_t i_blocksize );
|
||||
|
||||
/*!
|
||||
Get the DVD type associated with cd object.
|
||||
*/
|
||||
discmode_t
|
||||
mmc_get_dvd_struct_physical_private ( void *p_env,
|
||||
mmc_run_cmd_fn_t run_mmc_cmd,
|
||||
cdio_dvd_struct_t *s );
|
||||
|
||||
|
||||
char *mmc_get_mcn_private ( void *p_env,
|
||||
mmc_run_cmd_fn_t run_mmc_cmd
|
||||
);
|
||||
|
||||
bool mmc_init_cdtext_private ( void *p_user_data,
|
||||
mmc_run_cmd_fn_t run_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 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);
|
||||
|
||||
driver_return_code_t
|
||||
mmc_set_blocksize_private ( void *p_env,
|
||||
const mmc_run_cmd_fn_t run_mmc_cmd,
|
||||
uint16_t i_blocksize);
|
||||
656
lib/driver/netbsd.c
Normal file
656
lib/driver/netbsd.c
Normal file
@@ -0,0 +1,656 @@
|
||||
/*
|
||||
$Id: netbsd.c,v 1.4 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Changes up to version 0.76 */
|
||||
/*
|
||||
* Copyright (c) 2003
|
||||
* Matthias Drochner. All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <cdio/sector.h>
|
||||
#include <cdio/util.h>
|
||||
#include "cdio_assert.h"
|
||||
#include "cdio_private.h"
|
||||
|
||||
#ifdef __i386__
|
||||
#define DEFAULT_CDIO_DEVICE "/dev/rcd0d"
|
||||
#else
|
||||
#define DEFAULT_CDIO_DEVICE "/dev/rcd0c"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETBSD_CDROM
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/cdio.h>
|
||||
#include <sys/scsiio.h>
|
||||
|
||||
#define TOTAL_TRACKS (_obj->tochdr.ending_track \
|
||||
- _obj->tochdr.starting_track + 1)
|
||||
#define FIRST_TRACK_NUM (_obj->tochdr.starting_track)
|
||||
|
||||
typedef struct {
|
||||
generic_img_private_t gen;
|
||||
|
||||
bool toc_valid;
|
||||
struct ioc_toc_header tochdr;
|
||||
struct cd_toc_entry tocent[100];
|
||||
|
||||
bool sessionformat_valid;
|
||||
int sessionformat[100]; /* format of the session the track is in */
|
||||
} _img_private_t;
|
||||
|
||||
static driver_return_code_t
|
||||
run_scsi_cmd_netbsd(void *p_user_data, unsigned int i_timeout_ms,
|
||||
unsigned int i_cdb, const mmc_cdb_t *p_cdb,
|
||||
cdio_mmc_direction_t e_direction,
|
||||
unsigned int i_buf, void *p_buf )
|
||||
{
|
||||
const _img_private_t *_obj = p_user_data;
|
||||
scsireq_t req;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
memcpy(&req.cmd[0], p_cdb, i_cdb);
|
||||
req.cmdlen = i_cdb;
|
||||
req.datalen = i_buf;
|
||||
req.databuf = p_buf;
|
||||
req.timeout = i_timeout_ms;
|
||||
req.flags = e_direction == SCSI_MMC_DATA_READ ? SCCMD_READ : SCCMD_WRITE;
|
||||
|
||||
if (ioctl(_obj->gen.fd, SCIOCCOMMAND, &req) < 0) {
|
||||
perror("SCIOCCOMMAND");
|
||||
return -1;
|
||||
}
|
||||
if (req.retsts != SCCMD_OK) {
|
||||
fprintf(stderr, "SCIOCCOMMAND cmd 0x%02x sts %d\n", req.cmd[0], req.retsts);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
read_audio_sectors_netbsd(void *user_data, void *data, lsn_t lsn,
|
||||
unsigned int nblocks)
|
||||
{
|
||||
scsireq_t req;
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.cmd[0] = 0xbe;
|
||||
req.cmd[1] = 0;
|
||||
req.cmd[2] = (lsn >> 24) & 0xff;
|
||||
req.cmd[3] = (lsn >> 16) & 0xff;
|
||||
req.cmd[4] = (lsn >> 8) & 0xff;
|
||||
req.cmd[5] = (lsn >> 0) & 0xff;
|
||||
req.cmd[6] = (nblocks >> 16) & 0xff;
|
||||
req.cmd[7] = (nblocks >> 8) & 0xff;
|
||||
req.cmd[8] = (nblocks >> 0) & 0xff;
|
||||
req.cmd[9] = 0x78;
|
||||
req.cmdlen = 10;
|
||||
|
||||
req.datalen = nblocks * CDIO_CD_FRAMESIZE_RAW;
|
||||
req.databuf = data;
|
||||
req.timeout = 10000;
|
||||
req.flags = SCCMD_READ;
|
||||
|
||||
if (ioctl(_obj->gen.fd, SCIOCCOMMAND, &req) < 0) {
|
||||
perror("SCIOCCOMMAND");
|
||||
return 1;
|
||||
}
|
||||
if (req.retsts != SCCMD_OK) {
|
||||
fprintf(stderr, "SCIOCCOMMAND cmd 0xbe sts %d\n", req.retsts);
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
read_mode2_sector_netbsd(void *user_data, void *data, lsn_t lsn,
|
||||
bool mode2_form2)
|
||||
{
|
||||
scsireq_t req;
|
||||
_img_private_t *_obj = user_data;
|
||||
char buf[M2RAW_SECTOR_SIZE] = { 0, };
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.cmd[0] = 0xbe;
|
||||
req.cmd[1] = 0;
|
||||
req.cmd[2] = (lsn >> 24) & 0xff;
|
||||
req.cmd[3] = (lsn >> 16) & 0xff;
|
||||
req.cmd[4] = (lsn >> 8) & 0xff;
|
||||
req.cmd[5] = (lsn >> 0) & 0xff;
|
||||
req.cmd[6] = 0;
|
||||
req.cmd[7] = 0;
|
||||
req.cmd[8] = 1;
|
||||
req.cmd[9] = 0x58; /* subheader + userdata + ECC */
|
||||
req.cmdlen = 10;
|
||||
|
||||
req.datalen = M2RAW_SECTOR_SIZE;
|
||||
req.databuf = buf;
|
||||
req.timeout = 10000;
|
||||
req.flags = SCCMD_READ;
|
||||
|
||||
if (ioctl(_obj->gen.fd, SCIOCCOMMAND, &req) < 0) {
|
||||
perror("SCIOCCOMMAND");
|
||||
return 1;
|
||||
}
|
||||
if (req.retsts != SCCMD_OK) {
|
||||
fprintf(stderr, "SCIOCCOMMAND cmd 0xbe sts %d\n", req.retsts);
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (mode2_form2)
|
||||
memcpy(data, buf, M2RAW_SECTOR_SIZE);
|
||||
else
|
||||
memcpy(data, buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
read_mode2_sectors_netbsd(void *user_data, void *data, lsn_t lsn,
|
||||
bool mode2_form2, unsigned int nblocks)
|
||||
{
|
||||
int i, res;
|
||||
char *buf = data;
|
||||
|
||||
for (i = 0; i < nblocks; i++) {
|
||||
res = read_mode2_sector_netbsd(user_data, buf, lsn, mode2_form2);
|
||||
if (res)
|
||||
return res;
|
||||
|
||||
buf += (mode2_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE);
|
||||
lsn++;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
set_arg_netbsd(void *user_data, const char key[], const char value[])
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!strcmp(key, "source")) {
|
||||
if (!value)
|
||||
return -2;
|
||||
|
||||
free(_obj->gen.source_name);
|
||||
_obj->gen.source_name = strdup(value);
|
||||
} else if (!strcmp(key, "access-mode")) {
|
||||
if (strcmp(value, "READ_CD"))
|
||||
cdio_error("unknown access type: %s ignored.", value);
|
||||
} else
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
_cdio_read_toc(_img_private_t *_obj)
|
||||
{
|
||||
int res;
|
||||
struct ioc_read_toc_entry req;
|
||||
|
||||
res = ioctl(_obj->gen.fd, CDIOREADTOCHEADER, &_obj->tochdr);
|
||||
if (res < 0) {
|
||||
cdio_error("error in ioctl(CDIOREADTOCHEADER): %s\n",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
req.address_format = CD_MSF_FORMAT;
|
||||
req.starting_track = FIRST_TRACK_NUM;
|
||||
req.data_len = (TOTAL_TRACKS + 1) /* leadout! */
|
||||
* sizeof(struct cd_toc_entry);
|
||||
req.data = _obj->tocent;
|
||||
|
||||
res = ioctl(_obj->gen.fd, CDIOREADTOCENTRIES, &req);
|
||||
if (res < 0) {
|
||||
cdio_error("error in ioctl(CDROMREADTOCENTRIES): %s\n",
|
||||
strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
_obj->toc_valid = 1;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
read_toc_netbsd (void *p_user_data)
|
||||
{
|
||||
|
||||
return _cdio_read_toc(p_user_data);
|
||||
}
|
||||
|
||||
static int
|
||||
_cdio_read_discinfo(_img_private_t *_obj)
|
||||
{
|
||||
scsireq_t req;
|
||||
#define FULLTOCBUF (4 + 1000*11)
|
||||
unsigned char buf[FULLTOCBUF] = { 0, };
|
||||
int i, j;
|
||||
|
||||
memset(&req, 0, sizeof(req));
|
||||
req.cmd[0] = 0x43; /* READ TOC/PMA/ATIP */
|
||||
req.cmd[1] = 0x02;
|
||||
req.cmd[2] = 0x02; /* full TOC */
|
||||
req.cmd[3] = 0;
|
||||
req.cmd[4] = 0;
|
||||
req.cmd[5] = 0;
|
||||
req.cmd[6] = 0;
|
||||
req.cmd[7] = FULLTOCBUF / 256;
|
||||
req.cmd[8] = FULLTOCBUF % 256;
|
||||
req.cmd[9] = 0;
|
||||
req.cmdlen = 10;
|
||||
|
||||
req.datalen = FULLTOCBUF;
|
||||
req.databuf = buf;
|
||||
req.timeout = 10000;
|
||||
req.flags = SCCMD_READ;
|
||||
|
||||
if (ioctl(_obj->gen.fd, SCIOCCOMMAND, &req) < 0) {
|
||||
perror("SCIOCCOMMAND");
|
||||
return 1;
|
||||
}
|
||||
if (req.retsts != SCCMD_OK) {
|
||||
fprintf(stderr, "SCIOCCOMMAND cmd 0x43 sts %d\n", req.retsts);
|
||||
return 1;
|
||||
}
|
||||
#if 1
|
||||
printf("discinfo:");
|
||||
for (i = 0; i < 4; i++)
|
||||
printf(" %02x", buf[i]);
|
||||
printf("\n");
|
||||
for (i = 0; i < buf[1] - 2; i++) {
|
||||
printf(" %02x", buf[i + 4]);
|
||||
if (!((i + 1) % 11))
|
||||
printf("\n");
|
||||
}
|
||||
#endif
|
||||
|
||||
for (i = 4; i < req.datalen_used; i += 11) {
|
||||
if (buf[i + 3] == 0xa0) { /* POINT */
|
||||
/* XXX: assume entry 0xa1 follows */
|
||||
for (j = buf[i + 8] - 1; j <= buf[i + 11 + 8] - 1; j++)
|
||||
_obj->sessionformat[j] = buf[i + 9];
|
||||
}
|
||||
}
|
||||
|
||||
_obj->sessionformat_valid = true;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
eject_media_netbsd(void *user_data) {
|
||||
|
||||
_img_private_t *_obj = user_data;
|
||||
int fd, res, ret = 0;
|
||||
|
||||
fd = open(_obj->gen.source_name, O_RDONLY|O_NONBLOCK);
|
||||
if (fd < 0)
|
||||
return 2;
|
||||
|
||||
res = ioctl(fd, CDIOCALLOW);
|
||||
if (res < 0) {
|
||||
cdio_error("ioctl(fd, CDIOCALLOW) failed: %s\n",
|
||||
strerror(errno));
|
||||
/* go on... */
|
||||
}
|
||||
res = ioctl(fd, CDIOCEJECT);
|
||||
if (res < 0) {
|
||||
cdio_error("ioctl(CDIOCEJECT) failed: %s\n",
|
||||
strerror(errno));
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the value associated with the key "arg".
|
||||
*/
|
||||
static const char *
|
||||
get_arg_netbsd(void *user_data, const char key[])
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
|
||||
if (!strcmp(key, "source")) {
|
||||
return _obj->gen.source_name;
|
||||
} else if (!strcmp(key, "access-mode")) {
|
||||
return "READ_CD";
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static track_t
|
||||
get_first_track_num_netbsd(void *user_data)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
int res;
|
||||
|
||||
if (!_obj->toc_valid) {
|
||||
res = _cdio_read_toc(_obj);
|
||||
if (!res)
|
||||
return CDIO_INVALID_TRACK;
|
||||
}
|
||||
|
||||
return FIRST_TRACK_NUM;
|
||||
}
|
||||
|
||||
static track_t
|
||||
get_num_tracks_netbsd(void *user_data)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
int res;
|
||||
|
||||
if (!_obj->toc_valid) {
|
||||
res = _cdio_read_toc(_obj);
|
||||
if (!res)
|
||||
return CDIO_INVALID_TRACK;
|
||||
}
|
||||
|
||||
return TOTAL_TRACKS;
|
||||
}
|
||||
|
||||
/*!
|
||||
Get format of track.
|
||||
*/
|
||||
static track_format_t
|
||||
get_track_format_netbsd(void *user_data, track_t track_num)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
int res;
|
||||
|
||||
if (!_obj->toc_valid) {
|
||||
res = _cdio_read_toc(_obj);
|
||||
if (!res)
|
||||
return CDIO_INVALID_TRACK;
|
||||
}
|
||||
|
||||
if (track_num > TOTAL_TRACKS || track_num == 0)
|
||||
return TRACK_FORMAT_ERROR;
|
||||
|
||||
if (_obj->tocent[track_num - 1].control & 0x04) {
|
||||
if (!_obj->sessionformat_valid) {
|
||||
res = _cdio_read_discinfo(_obj);
|
||||
if (res)
|
||||
return CDIO_INVALID_TRACK;
|
||||
}
|
||||
|
||||
if (_obj->sessionformat[track_num - 1] == 0x10)
|
||||
return TRACK_FORMAT_CDI;
|
||||
else if (_obj->sessionformat[track_num - 1] == 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?
|
||||
*/
|
||||
static bool
|
||||
get_track_green_netbsd(void *user_data, track_t track_num)
|
||||
{
|
||||
|
||||
return (get_track_format_netbsd(user_data, track_num)
|
||||
== TRACK_FORMAT_XA);
|
||||
}
|
||||
|
||||
/*!
|
||||
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 i_track LEADOUT_TRACK or the total tracks+1.
|
||||
False is returned if there is no track entry.
|
||||
*/
|
||||
static bool
|
||||
get_track_msf_netbsd(void *user_data, track_t track_num, msf_t *msf)
|
||||
{
|
||||
_img_private_t *_obj = user_data;
|
||||
int res;
|
||||
|
||||
if (!msf)
|
||||
return false;
|
||||
|
||||
if (!_obj->toc_valid) {
|
||||
res = _cdio_read_toc(_obj);
|
||||
if (!res)
|
||||
return CDIO_INVALID_TRACK;
|
||||
}
|
||||
|
||||
if (track_num == CDIO_CDROM_LEADOUT_TRACK)
|
||||
track_num = TOTAL_TRACKS + 1;
|
||||
|
||||
if (track_num > TOTAL_TRACKS + 1 || track_num == 0)
|
||||
return false;
|
||||
|
||||
msf->m = cdio_to_bcd8(_obj->tocent[track_num - 1].addr.msf.minute);
|
||||
msf->s = cdio_to_bcd8(_obj->tocent[track_num - 1].addr.msf.second);
|
||||
msf->f = cdio_to_bcd8(_obj->tocent[track_num - 1].addr.msf.frame);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the size of the CD in logical block address (LBA) units.
|
||||
@return the lsn. On error return CDIO_INVALID_LSN.
|
||||
|
||||
Also note that in one at least one test the corresponding MMC gives
|
||||
a different answer, so there may be some disagreement about what is in
|
||||
fact the last lsn.
|
||||
*/
|
||||
static lsn_t
|
||||
get_disc_last_lsn_netbsd(void *user_data)
|
||||
{
|
||||
msf_t msf;
|
||||
|
||||
get_track_msf_netbsd(user_data, CDIO_CDROM_LEADOUT_TRACK, &msf);
|
||||
|
||||
return (((msf.m * 60) + msf.s) * CDIO_CD_FRAMES_PER_SEC + msf.f);
|
||||
}
|
||||
#endif /* HAVE_NETBSD_CDROM */
|
||||
|
||||
char **
|
||||
cdio_get_devices_netbsd (void)
|
||||
{
|
||||
#ifndef HAVE_NETBSD_CDROM
|
||||
return NULL;
|
||||
#else
|
||||
return NULL;
|
||||
#endif /* HAVE_NETBSD_CDROM */
|
||||
}
|
||||
|
||||
/*!
|
||||
Return a string containing the default CD device.
|
||||
*/
|
||||
char *
|
||||
cdio_get_default_device_netbsd()
|
||||
{
|
||||
return strdup(DEFAULT_CDIO_DEVICE);
|
||||
}
|
||||
|
||||
/*!
|
||||
Close tray on CD-ROM.
|
||||
|
||||
@param psz_device the CD-ROM drive to be closed.
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
close_tray_netbsd (const char *psz_device)
|
||||
{
|
||||
#ifdef HAVE_NETBSD_CDROM
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
#else
|
||||
return DRIVER_OP_NO_DRIVER;
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef HAVE_NETBSD_CDROM
|
||||
static cdio_funcs_t _funcs = {
|
||||
.audio_read_subchannel = audio_read_subchannel_mmc,
|
||||
.eject_media = eject_media_netbsd,
|
||||
.free = cdio_generic_free,
|
||||
.get_arg = get_arg_netbsd,
|
||||
.get_blocksize = get_blocksize_mmc,
|
||||
.get_cdtext = get_cdtext_generic,
|
||||
.get_default_device = cdio_get_default_device_netbsd,
|
||||
.get_devices = cdio_get_devices_netbsd,
|
||||
.get_disc_last_lsn = get_disc_last_lsn_netbsd,
|
||||
.get_discmode = get_discmode_generic,
|
||||
.get_drive_cap = get_drive_cap_mmc,
|
||||
.get_first_track_num = get_first_track_num_netbsd,
|
||||
.get_hwinfo = NULL,
|
||||
.get_mcn = get_mcn_mmc,
|
||||
.get_num_tracks = get_num_tracks_netbsd,
|
||||
.get_track_channels = get_track_channels_generic,
|
||||
.get_track_copy_permit = get_track_copy_permit_generic,
|
||||
.get_track_format = get_track_format_netbsd,
|
||||
.get_track_green = get_track_green_netbsd,
|
||||
.get_track_lba = NULL, /* This could be implemented if need be. */
|
||||
.get_track_preemphasis = get_track_preemphasis_generic,
|
||||
.get_track_msf = get_track_msf_netbsd,
|
||||
.lseek = cdio_generic_lseek,
|
||||
.read = cdio_generic_read,
|
||||
.read_audio_sectors = read_audio_sectors_netbsd,
|
||||
.read_data_sectors = read_data_sectors_generic,
|
||||
.read_mode2_sector = read_mode2_sector_netbsd,
|
||||
.read_mode2_sectors = read_mode2_sectors_netbsd,
|
||||
.read_toc = read_toc_netbsd,
|
||||
#if 1
|
||||
.run_mmc_cmd = run_scsi_cmd_netbsd,
|
||||
#endif
|
||||
.set_arg = set_arg_netbsd,
|
||||
};
|
||||
#endif /*HAVE_NETBSD_CDROM*/
|
||||
|
||||
/*!
|
||||
Initialization routine. This is the only thing that doesn't
|
||||
get called via a function pointer. In fact *we* are the
|
||||
ones to set that up.
|
||||
*/
|
||||
CdIo_t *
|
||||
cdio_open_netbsd(const char *source_name)
|
||||
{
|
||||
#ifdef HAVE_NETBSD_CDROM
|
||||
CdIo_t *ret;
|
||||
_img_private_t *_data;
|
||||
|
||||
_data = calloc(1, sizeof(_img_private_t));
|
||||
_data->gen.init = false;
|
||||
_data->gen.fd = -1;
|
||||
_data->toc_valid = false;
|
||||
_data->sessionformat_valid = false;
|
||||
|
||||
set_arg_netbsd(_data, "source",
|
||||
(source_name ? source_name : DEFAULT_CDIO_DEVICE));
|
||||
|
||||
if (source_name && !cdio_is_device_generic(source_name))
|
||||
return (NULL);
|
||||
|
||||
ret = cdio_new(&_data->gen, &_funcs);
|
||||
if (!ret)
|
||||
return NULL;
|
||||
|
||||
if (cdio_generic_init(_data, O_RDONLY)) {
|
||||
return ret;
|
||||
} else {
|
||||
cdio_generic_free(_data);
|
||||
return NULL;
|
||||
}
|
||||
#else
|
||||
return NULL;
|
||||
#endif /* HAVE_BSDI_CDROM */
|
||||
}
|
||||
|
||||
/*!
|
||||
Initialization routine. This is the only thing that doesn't
|
||||
get called via a function pointer. In fact *we* are the
|
||||
ones to set that up.
|
||||
*/
|
||||
CdIo_t *
|
||||
cdio_open_am_netbsd(const char *source_name, const char *am)
|
||||
{
|
||||
return (cdio_open_netbsd(source_name));
|
||||
}
|
||||
|
||||
bool
|
||||
cdio_have_netbsd (void)
|
||||
{
|
||||
#ifdef HAVE_NETBSD_CDROM
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif /* HAVE_NETBSD_CDROM */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "gnu"
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
1979
lib/driver/osx.c
Normal file
1979
lib/driver/osx.c
Normal file
File diff suppressed because it is too large
Load Diff
77
lib/driver/portable.h
Normal file
77
lib/driver/portable.h
Normal file
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
$Id: portable.h,v 1.4 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2006, 2008 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/*
|
||||
This file contains 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*/
|
||||
|
||||
#if !defined(HAVE_DRAND48) && defined(HAVE_RAND)
|
||||
# define drand48() (rand() / (double)RAND_MAX)
|
||||
#endif
|
||||
|
||||
#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__ */
|
||||
329
lib/driver/read.c
Normal file
329
lib/driver/read.c
Normal file
@@ -0,0 +1,329 @@
|
||||
/*
|
||||
$Id: read.c,v 1.12 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2005, 2008 Rocky Bernstein <rocky@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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/** \file read.h
|
||||
*
|
||||
* \brief sector (block, frame)-related libcdio routines.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <cdio/cdio.h>
|
||||
#include <cdio/logging.h>
|
||||
#include "cdio_private.h"
|
||||
#include "cdio_assert.h"
|
||||
|
||||
#ifdef HAVE_STRING_H
|
||||
#include <string.h>
|
||||
#endif
|
||||
|
||||
#define check_read_parms(p_cdio, p_buf, i_lsn) \
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT; \
|
||||
if (!p_buf || CDIO_INVALID_LSN == i_lsn) \
|
||||
return DRIVER_OP_ERROR;
|
||||
|
||||
#define check_lsn(i_lsn) \
|
||||
check_read_parms(p_cdio, p_buf, i_lsn); \
|
||||
{ \
|
||||
lsn_t end_lsn = \
|
||||
cdio_get_track_lsn(p_cdio, CDIO_CDROM_LEADOUT_TRACK); \
|
||||
if ( i_lsn > end_lsn ) { \
|
||||
cdio_info("Trying to access past end of disk lsn: %ld, end lsn: %ld", \
|
||||
(long int) i_lsn, (long int) end_lsn); \
|
||||
return DRIVER_OP_ERROR; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define check_lsn_blocks(i_lsn, i_blocks) \
|
||||
check_read_parms(p_cdio, p_buf, i_lsn); \
|
||||
{ \
|
||||
lsn_t end_lsn = \
|
||||
cdio_get_track_lsn(p_cdio, CDIO_CDROM_LEADOUT_TRACK); \
|
||||
if ( i_lsn > end_lsn ) { \
|
||||
cdio_info("Trying to access past end of disk lsn: %ld, end lsn: %ld", \
|
||||
(long int) i_lsn, (long int) end_lsn); \
|
||||
return DRIVER_OP_ERROR; \
|
||||
} \
|
||||
/* Care is used in the expression below to be correct with */ \
|
||||
/* respect to unsigned integers. */ \
|
||||
if ( i_lsn + i_blocks > end_lsn + 1 ) { \
|
||||
cdio_info("Request truncated to end disk; lsn: %ld, end lsn: %ld", \
|
||||
(long int) i_lsn, (long int) end_lsn); \
|
||||
i_blocks = end_lsn - i_lsn + 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
/*!
|
||||
lseek - reposition read/write file offset
|
||||
Returns (off_t) -1 on error.
|
||||
Similar to (if not the same as) libc's lseek()
|
||||
*/
|
||||
off_t
|
||||
cdio_lseek (const CdIo_t *p_cdio, off_t offset, int whence)
|
||||
{
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT;
|
||||
|
||||
if (p_cdio->op.lseek)
|
||||
return (p_cdio->op.lseek) (p_cdio->env, offset, whence);
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*! Reads into buf the next size bytes. Similar to (if not the
|
||||
same as) libc's read(). This is a "cooked" read, or one handled by
|
||||
the OS. It probably won't work on audio data. For that use
|
||||
cdio_read_audio_sector(s).
|
||||
|
||||
@param p_cdio object to read from
|
||||
@param p_buf place to read data into. The caller should make sure
|
||||
this location can store at least i_size bytes.
|
||||
@param i_size number of bytes to read
|
||||
|
||||
@return (ssize_t) -1 on error.
|
||||
*/
|
||||
ssize_t
|
||||
cdio_read (const CdIo_t *p_cdio, void *p_buf, size_t i_size)
|
||||
{
|
||||
if (!p_cdio) return DRIVER_OP_UNINIT;
|
||||
|
||||
if (p_cdio->op.read)
|
||||
return (p_cdio->op.read) (p_cdio->env, p_buf, i_size);
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads an audio sector from cd device into data starting
|
||||
from lsn. Returns DRIVER_OP_SUCCESS if no error.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_read_audio_sector (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn)
|
||||
{
|
||||
check_lsn(i_lsn);
|
||||
if (p_cdio->op.read_audio_sectors)
|
||||
return p_cdio->op.read_audio_sectors (p_cdio->env, p_buf, i_lsn, 1);
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads audio sectors from cd device into data starting
|
||||
from lsn. Returns DRIVER_OP_SUCCESS if no error.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_read_audio_sectors (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
|
||||
uint32_t i_blocks)
|
||||
{
|
||||
check_lsn_blocks(i_lsn, i_blocks);
|
||||
|
||||
if (0 == i_blocks) return DRIVER_OP_SUCCESS;
|
||||
|
||||
if (p_cdio->op.read_audio_sectors)
|
||||
return (p_cdio->op.read_audio_sectors) (p_cdio->env, p_buf, i_lsn,
|
||||
i_blocks);
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads an audio sector from cd device into data starting
|
||||
from lsn. Returns DRIVER_OP_SUCCESS if no error.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_read_data_sectors (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
|
||||
uint16_t i_blocksize, uint32_t i_blocks)
|
||||
{
|
||||
check_lsn(i_lsn);
|
||||
|
||||
if (0 == i_blocks) return DRIVER_OP_SUCCESS;
|
||||
|
||||
if (p_cdio->op.read_data_sectors)
|
||||
return p_cdio->op.read_data_sectors (p_cdio->env, p_buf, i_lsn,
|
||||
i_blocksize, i_blocks);
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
|
||||
#ifndef SEEK_SET
|
||||
#define SEEK_SET 0
|
||||
#endif
|
||||
|
||||
/*!
|
||||
Reads a single mode1 form1 or form2 sector from cd device
|
||||
into data starting from lsn. Returns DRIVER_OP_SUCCESS if no error.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_read_mode1_sector (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
|
||||
bool b_form2)
|
||||
{
|
||||
uint32_t size = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE ;
|
||||
|
||||
check_lsn(i_lsn);
|
||||
if (p_cdio->op.read_mode1_sector) {
|
||||
return p_cdio->op.read_mode1_sector(p_cdio->env, p_buf, i_lsn, b_form2);
|
||||
} else if (p_cdio->op.lseek && p_cdio->op.read) {
|
||||
char buf[CDIO_CD_FRAMESIZE] = { 0, };
|
||||
if (0 > cdio_lseek(p_cdio, CDIO_CD_FRAMESIZE*i_lsn, SEEK_SET))
|
||||
return -1;
|
||||
if (0 > cdio_read(p_cdio, buf, CDIO_CD_FRAMESIZE))
|
||||
return -1;
|
||||
memcpy (p_buf, buf, size);
|
||||
return DRIVER_OP_SUCCESS;
|
||||
}
|
||||
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads mode 1 sectors
|
||||
|
||||
@param p_cdio object to read from
|
||||
@param buf place to read data into
|
||||
@param lsn sector to read
|
||||
@param b_form2 true for reading mode 1 form 2 sectors or false for
|
||||
mode 1 form 1 sectors.
|
||||
@param i_blocks number of sectors to read
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_read_mode1_sectors (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
|
||||
bool b_form2, uint32_t i_blocks)
|
||||
{
|
||||
check_lsn_blocks(i_lsn, i_blocks);
|
||||
|
||||
if (0 == i_blocks) return DRIVER_OP_SUCCESS;
|
||||
|
||||
if (p_cdio->op.read_mode1_sectors)
|
||||
return (p_cdio->op.read_mode1_sectors) (p_cdio->env, p_buf, i_lsn, b_form2,
|
||||
i_blocks);
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads a mode 2 sector
|
||||
|
||||
@param p_cdio object to read from
|
||||
@param buf place to read data into
|
||||
@param lsn sector to read
|
||||
@param b_form2 true for reading mode 2 form 2 sectors or false for
|
||||
mode 2 form 1 sectors.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_read_mode2_sector (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
|
||||
bool b_form2)
|
||||
{
|
||||
check_lsn(i_lsn);
|
||||
if (p_cdio->op.read_mode2_sector)
|
||||
return p_cdio->op.read_mode2_sector (p_cdio->env, p_buf, i_lsn, b_form2);
|
||||
|
||||
/* fallback */
|
||||
if (p_cdio->op.read_mode2_sectors != NULL)
|
||||
return cdio_read_mode2_sectors (p_cdio, p_buf, i_lsn, b_form2, 1);
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads mode 2 sectors
|
||||
|
||||
@param p_cdio object to read from
|
||||
@param buf place to read data into
|
||||
@param lsn sector to read
|
||||
@param b_form2 true for reading mode2 form 2 sectors or false for
|
||||
mode 2 form 1 sectors.
|
||||
@param i_blocks number of sectors to read
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_read_mode2_sectors (const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
|
||||
bool b_form2, uint32_t i_blocks)
|
||||
{
|
||||
check_lsn_blocks(i_lsn, i_blocks);
|
||||
|
||||
if (0 == i_blocks) return DRIVER_OP_SUCCESS;
|
||||
|
||||
if (p_cdio->op.read_mode2_sectors)
|
||||
return (p_cdio->op.read_mode2_sectors) (p_cdio->env, p_buf, i_lsn,
|
||||
b_form2, i_blocks);
|
||||
return DRIVER_OP_UNSUPPORTED;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/** The special case of reading a single block is a common one so we
|
||||
provide a routine for that as a convenience.
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_read_sector(const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
|
||||
cdio_read_mode_t read_mode)
|
||||
{
|
||||
return cdio_read_sectors(p_cdio, p_buf, i_lsn, read_mode, 1);
|
||||
}
|
||||
|
||||
/*!
|
||||
Reads a number of sectors (AKA blocks).
|
||||
|
||||
@param p_buf place to read data into. The caller should make sure
|
||||
this location is large enough. See below for size information.
|
||||
@param read_mode the kind of "mode" to use in reading.
|
||||
@param i_lsn sector to read
|
||||
@param i_blocks number of sectors to read
|
||||
@return DRIVER_OP_SUCCESS (0) if no error, other (negative) enumerations
|
||||
are returned on error.
|
||||
|
||||
If read_mode is CDIO_MODE_AUDIO,
|
||||
*p_buf should hold at least CDIO_FRAMESIZE_RAW * i_blocks bytes.
|
||||
|
||||
If read_mode is CDIO_MODE_DATA,
|
||||
*p_buf should hold at least i_blocks times either ISO_BLOCKSIZE,
|
||||
M1RAW_SECTOR_SIZE or M2F2_SECTOR_SIZE depending on the kind of
|
||||
sector getting read. If you don't know whether you have a Mode 1/2,
|
||||
Form 1/ Form 2/Formless sector best to reserve space for the maximum
|
||||
which is M2RAW_SECTOR_SIZE.
|
||||
|
||||
If read_mode is CDIO_MODE_M2F1,
|
||||
*p_buf should hold at least M2RAW_SECTOR_SIZE * i_blocks bytes.
|
||||
|
||||
If read_mode is CDIO_MODE_M2F2,
|
||||
*p_buf should hold at least CDIO_CD_FRAMESIZE * i_blocks bytes.
|
||||
|
||||
|
||||
*/
|
||||
driver_return_code_t
|
||||
cdio_read_sectors(const CdIo_t *p_cdio, void *p_buf, lsn_t i_lsn,
|
||||
cdio_read_mode_t read_mode, uint32_t i_blocks)
|
||||
{
|
||||
switch(read_mode) {
|
||||
case CDIO_READ_MODE_AUDIO:
|
||||
return cdio_read_audio_sectors (p_cdio, p_buf, i_lsn, i_blocks);
|
||||
case CDIO_READ_MODE_M1F1:
|
||||
return cdio_read_mode1_sectors (p_cdio, p_buf, i_lsn, false, i_blocks);
|
||||
case CDIO_READ_MODE_M1F2:
|
||||
return cdio_read_mode1_sectors (p_cdio, p_buf, i_lsn, true, i_blocks);
|
||||
case CDIO_READ_MODE_M2F1:
|
||||
return cdio_read_mode2_sectors (p_cdio, p_buf, i_lsn, false, i_blocks);
|
||||
case CDIO_READ_MODE_M2F2:
|
||||
return cdio_read_mode2_sectors (p_cdio, p_buf, i_lsn, true, i_blocks);
|
||||
}
|
||||
/* Can't happen. Just to shut up gcc. */
|
||||
return DRIVER_OP_ERROR;
|
||||
}
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "gnu"
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
268
lib/driver/sector.c
Normal file
268
lib/driver/sector.c
Normal file
@@ -0,0 +1,268 @@
|
||||
/*
|
||||
$Id: sector.c,v 1.5 2005/02/06 04:20:25 rocky Exp $
|
||||
|
||||
Copyright (C) 2004, 2005 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.5 2005/02/06 04:20:25 rocky Exp $";
|
||||
|
||||
/*! String of bytes used to identify the beginning of a Mode 1 or
|
||||
Mode 2 sector. */
|
||||
const uint8_t CDIO_SECTOR_SYNC_HEADER[CDIO_CD_SYNC_SIZE] =
|
||||
{0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0};
|
||||
|
||||
/* Variables to hold debugger-helping enumerations */
|
||||
enum cdio_cd_enums;
|
||||
enum m2_sector_enums;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "gnu"
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
1174
lib/driver/solaris.c
Normal file
1174
lib/driver/solaris.c
Normal file
File diff suppressed because it is too large
Load Diff
361
lib/driver/track.c
Normal file
361
lib/driver/track.c
Normal file
@@ -0,0 +1,361 @@
|
||||
/*
|
||||
$Id: track.c,v 1.7 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
Copyright (C) 2001 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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/*! Track-related routines. */
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <cdio/cdio.h>
|
||||
#include "cdio_private.h"
|
||||
|
||||
const char *track_format2str[6] =
|
||||
{
|
||||
"audio", "CD-i", "XA", "data", "PSX", "error"
|
||||
};
|
||||
|
||||
/* Variables to hold debugger-helping enumerations */
|
||||
enum cdio_track_enums;
|
||||
|
||||
/*!
|
||||
Return the number of the first track.
|
||||
CDIO_INVALID_TRACK is returned on error.
|
||||
*/
|
||||
track_t
|
||||
cdio_get_first_track_num (const CdIo_t *p_cdio)
|
||||
{
|
||||
if (NULL == p_cdio) return CDIO_INVALID_TRACK;
|
||||
|
||||
if (p_cdio->op.get_first_track_num) {
|
||||
return p_cdio->op.get_first_track_num (p_cdio->env);
|
||||
} else {
|
||||
return CDIO_INVALID_TRACK;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the last track number.
|
||||
CDIO_INVALID_TRACK is returned on error.
|
||||
*/
|
||||
track_t
|
||||
cdio_get_last_track_num (const CdIo_t *p_cdio)
|
||||
{
|
||||
if (NULL == p_cdio) return CDIO_INVALID_TRACK;
|
||||
{
|
||||
const track_t i_first_track = cdio_get_first_track_num(p_cdio);
|
||||
if ( CDIO_INVALID_TRACK != i_first_track ) {
|
||||
const track_t i_tracks = cdio_get_num_tracks(p_cdio);
|
||||
if ( CDIO_INVALID_TRACK != i_tracks )
|
||||
return i_first_track + i_tracks - 1;
|
||||
}
|
||||
return CDIO_INVALID_TRACK;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Return number of channels in track: 2 or 4; -2 if not
|
||||
implemented or -1 for error.
|
||||
Not meaningful if track is not an audio track.
|
||||
*/
|
||||
int
|
||||
cdio_get_track_channels(const CdIo_t *p_cdio, track_t i_track)
|
||||
{
|
||||
if (p_cdio->op.get_track_channels) {
|
||||
return p_cdio->op.get_track_channels (p_cdio->env, i_track);
|
||||
} else {
|
||||
return -2;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Return copy protection status on a track. Is this meaningful
|
||||
if not an audio track?
|
||||
*/
|
||||
track_flag_t
|
||||
cdio_get_track_copy_permit(const CdIo_t *p_cdio, track_t i_track)
|
||||
{
|
||||
if (p_cdio->op.get_track_copy_permit) {
|
||||
return p_cdio->op.get_track_copy_permit (p_cdio->env, i_track);
|
||||
} else {
|
||||
return CDIO_TRACK_FLAG_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Get format of track.
|
||||
*/
|
||||
track_format_t
|
||||
cdio_get_track_format(const CdIo_t *p_cdio, track_t i_track)
|
||||
{
|
||||
if (!p_cdio) return TRACK_FORMAT_ERROR;
|
||||
|
||||
if (p_cdio->op.get_track_format) {
|
||||
return p_cdio->op.get_track_format (p_cdio->env, i_track);
|
||||
} else {
|
||||
return TRACK_FORMAT_ERROR;
|
||||
}
|
||||
}
|
||||
/*!
|
||||
Return the Joliet level recognized for p_cdio.
|
||||
*/
|
||||
uint8_t
|
||||
cdio_get_joliet_level(const CdIo_t *p_cdio)
|
||||
{
|
||||
if (!p_cdio) return 0;
|
||||
{
|
||||
const generic_img_private_t *p_env
|
||||
= (generic_img_private_t *) (p_cdio->env);
|
||||
return p_env->i_joliet_level;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the number of tracks in the current medium.
|
||||
CDIO_INVALID_TRACK is returned on error.
|
||||
*/
|
||||
track_t
|
||||
cdio_get_num_tracks (const CdIo_t *p_cdio)
|
||||
{
|
||||
if (p_cdio == NULL) return CDIO_INVALID_TRACK;
|
||||
|
||||
if (p_cdio->op.get_num_tracks) {
|
||||
return p_cdio->op.get_num_tracks (p_cdio->env);
|
||||
} else {
|
||||
return CDIO_INVALID_TRACK;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Find the track which contans lsn.
|
||||
CDIO_INVALID_TRACK is returned if the lsn outside of the CD or
|
||||
if there was some error.
|
||||
|
||||
If the lsn is before the pregap of the first track 0 is returned.
|
||||
Otherwise we return the track that spans the lsn.
|
||||
*/
|
||||
track_t
|
||||
cdio_get_track(const CdIo_t *p_cdio, lsn_t lsn)
|
||||
{
|
||||
if (!p_cdio) return CDIO_INVALID_TRACK;
|
||||
|
||||
{
|
||||
track_t i_low_track = cdio_get_first_track_num(p_cdio);
|
||||
track_t i_high_track = cdio_get_last_track_num(p_cdio)+1; /* LEADOUT */
|
||||
|
||||
if (CDIO_INVALID_TRACK == i_low_track
|
||||
|| CDIO_INVALID_TRACK == i_high_track ) return CDIO_INVALID_TRACK;
|
||||
|
||||
if (lsn < cdio_get_track_lsn(p_cdio, i_low_track))
|
||||
return 0; /* We're in the pre-gap of first track */
|
||||
|
||||
if (lsn > cdio_get_track_lsn(p_cdio, i_high_track))
|
||||
return CDIO_INVALID_TRACK; /* We're beyond the end. */
|
||||
|
||||
do {
|
||||
const track_t i_mid = (i_low_track + i_high_track) / 2;
|
||||
const lsn_t i_mid_lsn = cdio_get_track_lsn(p_cdio, i_mid);
|
||||
if (lsn <= i_mid_lsn) i_high_track = i_mid - 1;
|
||||
if (lsn >= i_mid_lsn) i_low_track = i_mid + 1;
|
||||
} while ( i_low_track <= i_high_track );
|
||||
|
||||
return (i_low_track > i_high_track + 1)
|
||||
? i_high_track + 1 : i_high_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?
|
||||
*/
|
||||
bool
|
||||
cdio_get_track_green(const CdIo_t *p_cdio, track_t i_track)
|
||||
{
|
||||
if (p_cdio == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (p_cdio->op.get_track_green) {
|
||||
return p_cdio->op.get_track_green (p_cdio->env, i_track);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the starting LBA for track number
|
||||
track_num in cdio. 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
|
||||
cdio_get_track_lba(const CdIo_t *p_cdio, track_t i_track)
|
||||
{
|
||||
if (!p_cdio) return CDIO_INVALID_LBA;
|
||||
|
||||
if (p_cdio->op.get_track_lba) {
|
||||
return p_cdio->op.get_track_lba (p_cdio->env, i_track);
|
||||
} else {
|
||||
msf_t msf;
|
||||
if (p_cdio->op.get_track_msf)
|
||||
if (cdio_get_track_msf(p_cdio, i_track, &msf))
|
||||
return cdio_msf_to_lba(&msf);
|
||||
return CDIO_INVALID_LBA;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the starting LSN for track number
|
||||
i_track in cdio. Tracks numbers start at 1.
|
||||
The "leadout" track is specified either by
|
||||
using i_track LEADOUT_TRACK or the total tracks+1.
|
||||
CDIO_INVALID_LSN is returned on error.
|
||||
*/
|
||||
lsn_t
|
||||
cdio_get_track_lsn(const CdIo_t *p_cdio, track_t i_track)
|
||||
{
|
||||
if (p_cdio == NULL) return CDIO_INVALID_LSN;
|
||||
|
||||
if (p_cdio->op.get_track_lba) {
|
||||
return cdio_lba_to_lsn(p_cdio->op.get_track_lba (p_cdio->env, i_track));
|
||||
} else {
|
||||
msf_t msf;
|
||||
if (cdio_get_track_msf(p_cdio, i_track, &msf))
|
||||
return cdio_msf_to_lsn(&msf);
|
||||
return CDIO_INVALID_LSN;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the International Standard Recording Code (ISRC) for track number
|
||||
i_track in p_cdio. Track numbers start at 1.
|
||||
|
||||
Note: string is malloc'd so caller has to free() the returned
|
||||
string when done with it.
|
||||
*/
|
||||
char *
|
||||
cdio_get_track_isrc (const CdIo_t *p_cdio, track_t i_track)
|
||||
{
|
||||
if (p_cdio == NULL) return NULL;
|
||||
|
||||
if (p_cdio->op.get_track_isrc) {
|
||||
return p_cdio->op.get_track_isrc (p_cdio->env, i_track);
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the starting LBA for the pregap for track number
|
||||
i_track in cdio. Track numbers start at 1.
|
||||
CDIO_INVALID_LBA is returned on error.
|
||||
*/
|
||||
lba_t
|
||||
cdio_get_track_pregap_lba(const CdIo_t *p_cdio, track_t i_track)
|
||||
{
|
||||
if (p_cdio == NULL) return CDIO_INVALID_LBA;
|
||||
|
||||
if (p_cdio->op.get_track_pregap_lba) {
|
||||
return p_cdio->op.get_track_pregap_lba (p_cdio->env, i_track);
|
||||
} else {
|
||||
return CDIO_INVALID_LBA;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the starting LSN for the pregap for track number
|
||||
i_track in cdio. Track numbers start at 1.
|
||||
CDIO_INVALID_LSN is returned on error.
|
||||
*/
|
||||
lsn_t
|
||||
cdio_get_track_pregap_lsn(const CdIo_t *p_cdio, track_t i_track)
|
||||
{
|
||||
return cdio_lba_to_lsn(cdio_get_track_pregap_lba(p_cdio, i_track));
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the ending LSN for track number
|
||||
i_track in cdio. CDIO_INVALID_LSN is returned on error.
|
||||
*/
|
||||
lsn_t
|
||||
cdio_get_track_last_lsn(const CdIo_t *p_cdio, track_t i_track)
|
||||
{
|
||||
lsn_t lsn = cdio_get_track_lsn(p_cdio, i_track+1);
|
||||
|
||||
if (CDIO_INVALID_LSN == lsn) return CDIO_INVALID_LSN;
|
||||
/* Safe, we've always the leadout. */
|
||||
return lsn - 1;
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the starting MSF (minutes/secs/frames) for track number
|
||||
i_track in cdio. 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.
|
||||
*/
|
||||
bool
|
||||
cdio_get_track_msf(const CdIo_t *p_cdio, track_t i_track, /*out*/ msf_t *msf)
|
||||
{
|
||||
if (!p_cdio) return false;
|
||||
|
||||
if (p_cdio->op.get_track_msf) {
|
||||
return p_cdio->op.get_track_msf (p_cdio->env, i_track, msf);
|
||||
} else if (p_cdio->op.get_track_lba) {
|
||||
lba_t lba = p_cdio->op.get_track_lba (p_cdio->env, i_track);
|
||||
if (lba == CDIO_INVALID_LBA) return false;
|
||||
cdio_lba_to_msf(lba, msf);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/*! Return copy protection status on a track. Is this meaningful
|
||||
if not an audio track?
|
||||
*/
|
||||
track_flag_t
|
||||
cdio_get_track_preemphasis(const CdIo *p_cdio, track_t i_track)
|
||||
{
|
||||
if (p_cdio->op.get_track_preemphasis) {
|
||||
return p_cdio->op.get_track_preemphasis (p_cdio->env, i_track);
|
||||
} else {
|
||||
return CDIO_TRACK_FLAG_UNKNOWN;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
Return the number of sectors between this track an the next. This
|
||||
includes any pregap sectors before the start of the next track.
|
||||
Tracks start at 1.
|
||||
0 is returned if there is an error.
|
||||
*/
|
||||
unsigned int
|
||||
cdio_get_track_sec_count(const CdIo_t *p_cdio, track_t i_track)
|
||||
{
|
||||
const track_t i_tracks = cdio_get_num_tracks(p_cdio);
|
||||
|
||||
if (i_track >=1 && i_track <= i_tracks)
|
||||
return ( cdio_get_track_lba(p_cdio, i_track+1)
|
||||
- cdio_get_track_lba(p_cdio, i_track) );
|
||||
return 0;
|
||||
}
|
||||
210
lib/driver/utf8.c
Normal file
210
lib/driver/utf8.c
Normal file
@@ -0,0 +1,210 @@
|
||||
/*
|
||||
$Id: utf8.c,v 1.5 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2006, 2008 Burkhard Plaum <plaum@ipf.uni-stuttgart.de>
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
/* UTF-8 support */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_JOLIET
|
||||
#ifdef HAVE_STRING_H
|
||||
# include <string.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_STDLIB_H
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ICONV
|
||||
# include <iconv.h>
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_ERRNO_H
|
||||
#include <errno.h>
|
||||
#endif
|
||||
|
||||
#include <cdio/utf8.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
|
||||
struct cdio_charset_coverter_s
|
||||
{
|
||||
iconv_t ic;
|
||||
};
|
||||
|
||||
cdio_charset_coverter_t *
|
||||
cdio_charset_converter_create(const char * src_charset,
|
||||
const char * dst_charset)
|
||||
{
|
||||
cdio_charset_coverter_t * ret;
|
||||
ret = calloc(1, sizeof(*ret));
|
||||
ret->ic = iconv_open(dst_charset, src_charset);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#if 0
|
||||
static void bgav_hexdump(uint8_t * data, int len, int linebreak)
|
||||
{
|
||||
int i;
|
||||
int bytes_written = 0;
|
||||
int imax;
|
||||
|
||||
while(bytes_written < len)
|
||||
{
|
||||
imax = (bytes_written + linebreak > len) ? len - bytes_written : linebreak;
|
||||
for(i = 0; i < imax; i++)
|
||||
fprintf(stderr, "%02x ", data[bytes_written + i]);
|
||||
for(i = imax; i < linebreak; i++)
|
||||
fprintf(stderr, " ");
|
||||
for(i = 0; i < imax; i++)
|
||||
{
|
||||
if(!(data[bytes_written + i] & 0x80) && (data[bytes_written + i] >= 32))
|
||||
fprintf(stderr, "%c", data[bytes_written + i]);
|
||||
else
|
||||
fprintf(stderr, ".");
|
||||
}
|
||||
bytes_written += imax;
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void cdio_charset_converter_destroy(cdio_charset_coverter_t*cnv)
|
||||
{
|
||||
iconv_close(cnv->ic);
|
||||
free(cnv);
|
||||
}
|
||||
|
||||
#define BYTES_INCREMENT 16
|
||||
|
||||
static bool
|
||||
do_convert(iconv_t cd, char * src, int src_len,
|
||||
char ** dst, int *dst_len)
|
||||
{
|
||||
char * ret;
|
||||
|
||||
char *inbuf;
|
||||
char *outbuf;
|
||||
int alloc_size;
|
||||
int output_pos;
|
||||
size_t inbytesleft;
|
||||
size_t outbytesleft;
|
||||
|
||||
if(src_len < 0)
|
||||
src_len = strlen(src);
|
||||
#if 0
|
||||
fprintf(stderr, "Converting:\n");
|
||||
bgav_hexdump(src, src_len, 16);
|
||||
#endif
|
||||
alloc_size = src_len + BYTES_INCREMENT;
|
||||
|
||||
inbytesleft = src_len;
|
||||
|
||||
/* We reserve space here to add a final '\0' */
|
||||
outbytesleft = alloc_size-1;
|
||||
|
||||
ret = malloc(alloc_size);
|
||||
|
||||
inbuf = src;
|
||||
outbuf = ret;
|
||||
|
||||
while(1)
|
||||
{
|
||||
|
||||
if(iconv(cd, &inbuf, &inbytesleft,
|
||||
&outbuf, &outbytesleft) == (size_t)-1)
|
||||
{
|
||||
switch(errno)
|
||||
{
|
||||
case E2BIG:
|
||||
output_pos = (int)(outbuf - ret);
|
||||
|
||||
alloc_size += BYTES_INCREMENT;
|
||||
outbytesleft += BYTES_INCREMENT;
|
||||
|
||||
ret = realloc(ret, alloc_size);
|
||||
if (ret == NULL)
|
||||
{
|
||||
fprintf(stderr, "Can't realloc(%d).\n", alloc_size);
|
||||
return false;
|
||||
}
|
||||
outbuf = ret + output_pos;
|
||||
break;
|
||||
default:
|
||||
fprintf(stderr, "Iconv failed: %s\n", strerror(errno));
|
||||
if (ret != NULL)
|
||||
free(ret);
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(!inbytesleft)
|
||||
break;
|
||||
}
|
||||
/* Zero terminate */
|
||||
*outbuf = '\0';
|
||||
|
||||
/* Set return values */
|
||||
*dst = ret;
|
||||
if(dst_len)
|
||||
*dst_len = (int)(outbuf - ret);
|
||||
#if 0
|
||||
fprintf(stderr, "Conversion done, src:\n");
|
||||
bgav_hexdump(src, src_len, 16);
|
||||
fprintf(stderr, "dst:\n");
|
||||
bgav_hexdump((uint8_t*)(ret), (int)(outbuf - ret), 16);
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
bool cdio_charset_convert(cdio_charset_coverter_t*cnv,
|
||||
char * src, int src_len,
|
||||
char ** dst, int * dst_len)
|
||||
{
|
||||
return do_convert(cnv->ic, src, src_len, dst, dst_len);
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool cdio_charset_from_utf8(cdio_utf8_t * src, char ** dst,
|
||||
int * dst_len, const char * dst_charset)
|
||||
{
|
||||
iconv_t ic;
|
||||
bool result;
|
||||
ic = iconv_open(dst_charset, "UTF-8");
|
||||
result = do_convert(ic, src, -1, dst, dst_len);
|
||||
iconv_close(ic);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool cdio_charset_to_utf8(char *src, size_t src_len, cdio_utf8_t **dst,
|
||||
const char * src_charset)
|
||||
{
|
||||
iconv_t ic;
|
||||
bool result;
|
||||
ic = iconv_open("UTF-8", src_charset);
|
||||
result = do_convert(ic, src, src_len, dst, NULL);
|
||||
iconv_close(ic);
|
||||
return result;
|
||||
}
|
||||
#endif /* HAVE_JOLIET */
|
||||
189
lib/driver/util.c
Normal file
189
lib/driver/util.c
Normal file
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
$Id: util.c,v 1.6 2008/04/22 15:29:12 karl Exp $
|
||||
|
||||
Copyright (C) 2003, 2004, 2005, 2008 Rocky Bernstein <rocky@gnu.org>
|
||||
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 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
# include "config.h"
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef HAVE_UNISTD_H // readlink
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#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.6 2008/04/22 15:29:12 karl 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_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 = calloc (1, sizeof (char *) * (n+1));
|
||||
|
||||
n = 0;
|
||||
while((p = strtok(n ? NULL : _str, _delim)) != NULL)
|
||||
strv[n++] = strdup(p);
|
||||
|
||||
free(_str);
|
||||
|
||||
return strv;
|
||||
}
|
||||
|
||||
void *
|
||||
_cdio_memdup (const void *mem, size_t count)
|
||||
{
|
||||
void *new_mem = NULL;
|
||||
|
||||
if (mem)
|
||||
{
|
||||
new_mem = calloc (1, 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));
|
||||
}
|
||||
|
||||
/*!
|
||||
Follow symlinks until we have the real device file
|
||||
(idea taken from libunieject).
|
||||
*/
|
||||
|
||||
void cdio_follow_symlink (const char * src, char * dst) {
|
||||
#ifdef HAVE_READLINK
|
||||
char tmp_src[PATH_MAX+1];
|
||||
char tmp_dst[PATH_MAX+1];
|
||||
|
||||
int len;
|
||||
|
||||
strcpy(tmp_src, src);
|
||||
while(1) {
|
||||
len = readlink(tmp_src, tmp_dst, PATH_MAX);
|
||||
if(len < 0) {
|
||||
strncpy(dst, tmp_src, PATH_MAX);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
tmp_dst[len] = '\0';
|
||||
strncpy(tmp_src, tmp_dst, PATH_MAX);
|
||||
}
|
||||
}
|
||||
#else
|
||||
strncpy(dst, src, PATH_MAX);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* c-file-style: "gnu"
|
||||
* tab-width: 8
|
||||
* indent-tabs-mode: nil
|
||||
* End:
|
||||
*/
|
||||
Reference in New Issue
Block a user