3c633f0b40
o re-add cdda-player o install libcdio_cdda.pc ajacoutot@ ok.
550 lines
14 KiB
C
550 lines
14 KiB
C
/* $OpenBSD: openbsd.c,v 1.3 2008/05/01 09:05:12 fgsch Exp $ */
|
|
/* $NetBSD: _cdio_netbsd.c,v 1.4 2005/05/31 17:05:36 drochner Exp $ */
|
|
|
|
/*
|
|
* Copyright (c) 2008 Federico G. Schwindt
|
|
* 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"
|
|
|
|
#include <string.h>
|
|
#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 DEFAULT_CDIO_DEVICE "/dev/rcd0c"
|
|
|
|
typedef struct {
|
|
generic_img_private_t gen;
|
|
|
|
struct ioc_toc_header tochdr;
|
|
struct cd_toc_entry tocent[CDIO_CD_MAX_TRACKS + 1];
|
|
} _img_private_t;
|
|
|
|
static driver_return_code_t
|
|
run_mmc_cmd_openbsd(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 *p_env = 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(p_env->gen.fd, SCIOCCOMMAND, &req) < 0) {
|
|
cdio_info("ioctl SCIOCCOMMAND failed: %s\n", strerror(errno));
|
|
return (DRIVER_OP_ERROR);
|
|
}
|
|
|
|
if (req.retsts != SCCMD_OK) {
|
|
cdio_info("unexpected status for SCIOCCOMMAND %#x: %#x\n",
|
|
req.cmd[0], req.retsts);
|
|
return (DRIVER_OP_ERROR);
|
|
}
|
|
|
|
return (DRIVER_OP_SUCCESS);
|
|
}
|
|
|
|
static driver_return_code_t
|
|
audio_get_volume_openbsd(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, CDIOCGETVOL, p_volume));
|
|
}
|
|
|
|
static driver_return_code_t
|
|
audio_pause_openbsd(void *p_user_data)
|
|
{
|
|
const _img_private_t *p_env = p_user_data;
|
|
return (ioctl(p_env->gen.fd, CDIOCPAUSE));
|
|
}
|
|
|
|
static driver_return_code_t
|
|
audio_play_msf_openbsd(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 a;
|
|
|
|
a.start_m = cdio_from_bcd8(p_start_msf->m);
|
|
a.start_s = cdio_from_bcd8(p_start_msf->s);
|
|
a.start_f = cdio_from_bcd8(p_start_msf->f);
|
|
a.end_m = cdio_from_bcd8(p_end_msf->m);
|
|
a.end_s = cdio_from_bcd8(p_end_msf->s);
|
|
a.end_f = cdio_from_bcd8(p_end_msf->f);
|
|
|
|
return (ioctl(p_env->gen.fd, CDIOCPLAYMSF, (char *)&a));
|
|
}
|
|
|
|
#if !USE_MMC_SUBCHANNEL
|
|
static driver_return_code_t
|
|
audio_read_subchannel_openbsd(void *p_user_data, cdio_subchannel_t *subchannel)
|
|
{
|
|
const _img_private_t *p_env = p_user_data;
|
|
struct ioc_read_subchannel s;
|
|
struct cd_sub_channel_info data;
|
|
|
|
bzero(&s, sizeof(s));
|
|
s.data = &data;
|
|
s.data_len = sizeof(data);
|
|
s.address_format = CD_MSF_FORMAT;
|
|
s.data_format = CD_CURRENT_POSITION;
|
|
|
|
if (ioctl(p_env->gen.fd, CDIOCREADSUBCHANNEL, &s) != -1) {
|
|
subchannel->control = s.data->what.position.control;
|
|
subchannel->track = s.data->what.position.track_number;
|
|
subchannel->index = s.data->what.position.index_number;
|
|
|
|
subchannel->abs_addr.m =
|
|
cdio_to_bcd8(s.data->what.position.absaddr.msf.minute);
|
|
subchannel->abs_addr.s =
|
|
cdio_to_bcd8(s.data->what.position.absaddr.msf.second);
|
|
subchannel->abs_addr.f =
|
|
cdio_to_bcd8(s.data->what.position.absaddr.msf.frame);
|
|
subchannel->rel_addr.m =
|
|
cdio_to_bcd8(s.data->what.position.reladdr.msf.minute);
|
|
subchannel->rel_addr.s =
|
|
cdio_to_bcd8(s.data->what.position.reladdr.msf.second);
|
|
subchannel->rel_addr.f =
|
|
cdio_to_bcd8(s.data->what.position.reladdr.msf.frame);
|
|
subchannel->audio_status = s.data->header.audio_status;
|
|
|
|
return (DRIVER_OP_SUCCESS);
|
|
} else {
|
|
cdio_info("ioctl CDIOCREADSUBCHANNEL failed: %s\n",
|
|
strerror(errno));
|
|
return (DRIVER_OP_ERROR);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
static driver_return_code_t
|
|
audio_resume_openbsd(void *p_user_data)
|
|
{
|
|
const _img_private_t *p_env = p_user_data;
|
|
return (ioctl(p_env->gen.fd, CDIOCRESUME));
|
|
}
|
|
|
|
static driver_return_code_t
|
|
audio_set_volume_openbsd(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));
|
|
}
|
|
|
|
static driver_return_code_t
|
|
audio_stop_openbsd(void *p_user_data)
|
|
{
|
|
const _img_private_t *p_env = p_user_data;
|
|
return (ioctl(p_env->gen.fd, CDIOCSTOP));
|
|
}
|
|
|
|
static driver_return_code_t
|
|
eject_media_openbsd(void *p_user_data)
|
|
{
|
|
_img_private_t *p_env = p_user_data;
|
|
driver_return_code_t ret = DRIVER_OP_SUCCESS;
|
|
bool was_open = false;
|
|
|
|
if (p_env->gen.fd == -1)
|
|
p_env->gen.fd = open(p_env->gen.source_name,
|
|
O_RDONLY|O_NONBLOCK, 0);
|
|
else
|
|
was_open = true;
|
|
|
|
if (p_env->gen.fd == -1)
|
|
return (DRIVER_OP_ERROR);
|
|
|
|
if (ioctl(p_env->gen.fd, CDIOCALLOW) == -1)
|
|
cdio_info("ioctl CDIOCALLOW failed: %s\n", strerror(errno));
|
|
|
|
if (ioctl(p_env->gen.fd, CDIOCEJECT) == -1) {
|
|
cdio_info("ioctl CDIOCEJECT failed: %s\n", strerror(errno));
|
|
ret = DRIVER_OP_ERROR;
|
|
}
|
|
|
|
if (!was_open) {
|
|
close(p_env->gen.fd);
|
|
p_env->gen.fd = -1;
|
|
}
|
|
|
|
return (ret);
|
|
}
|
|
|
|
static const char *
|
|
get_arg_openbsd(void *p_user_data, const char key[])
|
|
{
|
|
_img_private_t *p_env = p_user_data;
|
|
|
|
if (!strcmp(key, "source")) {
|
|
return (p_env->gen.source_name);
|
|
} else if (!strcmp(key, "access-mode")) {
|
|
return ("READ_CD");
|
|
}
|
|
|
|
return (NULL);
|
|
}
|
|
|
|
static bool
|
|
read_toc_openbsd(void *p_user_data)
|
|
{
|
|
_img_private_t *p_env = p_user_data;
|
|
struct ioc_read_toc_entry req;
|
|
|
|
if (ioctl(p_env->gen.fd, CDIOREADTOCHEADER, &p_env->tochdr) == -1) {
|
|
cdio_info("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->tochdr.starting_track) + 1;
|
|
|
|
req.address_format = CD_LBA_FORMAT;
|
|
req.starting_track = p_env->gen.i_first_track;
|
|
req.data_len = sizeof(p_env->tocent);
|
|
req.data = p_env->tocent;
|
|
|
|
if (ioctl(p_env->gen.fd, CDIOREADTOCENTRIES, &req) == -1) {
|
|
cdio_info("error in ioctl CDIOREADTOCENTRIES: %s\n",
|
|
strerror(errno));
|
|
return (false);
|
|
}
|
|
|
|
p_env->gen.toc_init = true;
|
|
return (true);
|
|
}
|
|
|
|
static lba_t
|
|
get_track_lba_openbsd(void *p_user_data, track_t i_track)
|
|
{
|
|
_img_private_t *p_env = p_user_data;
|
|
|
|
if (!p_env->gen.toc_init)
|
|
read_toc_openbsd(p_env);
|
|
|
|
if (i_track == CDIO_CDROM_LEADOUT_TRACK)
|
|
i_track = p_env->gen.i_first_track + p_env->gen.i_tracks;
|
|
|
|
if (!p_env->gen.toc_init ||
|
|
i_track > (p_env->gen.i_first_track + p_env->gen.i_tracks) ||
|
|
i_track < p_env->gen.i_first_track)
|
|
return (CDIO_INVALID_LBA);
|
|
|
|
return (p_env->tocent[i_track - p_env->gen.i_first_track].addr.lba +
|
|
CDIO_PREGAP_SECTORS);
|
|
}
|
|
|
|
static lsn_t
|
|
get_disc_last_lsn_openbsd(void *user_data)
|
|
{
|
|
return (get_track_lba_openbsd(user_data, CDIO_CDROM_LEADOUT_TRACK));
|
|
}
|
|
|
|
static driver_return_code_t
|
|
get_last_session_openbsd(void *p_user_data, lsn_t *i_last_session)
|
|
{
|
|
const _img_private_t *p_env = p_user_data;
|
|
int addr;
|
|
|
|
if (ioctl(p_env->gen.fd, CDIOREADMSADDR, &addr) == 0) {
|
|
*i_last_session = addr;
|
|
return (DRIVER_OP_SUCCESS);
|
|
} else {
|
|
cdio_info("ioctl CDIOREADMSADDR failed: %s\n",
|
|
strerror(errno));
|
|
return (DRIVER_OP_ERROR);
|
|
}
|
|
}
|
|
static track_format_t
|
|
get_track_format_openbsd(void *p_user_data, track_t i_track)
|
|
{
|
|
_img_private_t *p_env = p_user_data;
|
|
|
|
if (!p_env)
|
|
return (TRACK_FORMAT_ERROR);
|
|
|
|
if (!p_env->gen.toc_init)
|
|
read_toc_openbsd(p_env);
|
|
|
|
if (!p_env->gen.toc_init ||
|
|
i_track > (p_env->gen.i_first_track + p_env->gen.i_tracks) ||
|
|
i_track < p_env->gen.i_first_track)
|
|
return (TRACK_FORMAT_ERROR);
|
|
|
|
if (p_env->tocent[i_track - 1].control & CDIO_CDROM_DATA_TRACK)
|
|
return (TRACK_FORMAT_DATA);
|
|
else
|
|
return (TRACK_FORMAT_AUDIO);
|
|
}
|
|
|
|
static bool
|
|
get_track_green_openbsd(void *user_data, track_t i_track)
|
|
{
|
|
return (get_track_format_openbsd(user_data, i_track) ==
|
|
TRACK_FORMAT_XA);
|
|
}
|
|
|
|
static int
|
|
read_audio_sectors_openbsd(void *p_user_data, void *p_buf, lsn_t i_lsn,
|
|
unsigned int i_blocks)
|
|
{
|
|
_img_private_t *p_env = p_user_data;
|
|
return (mmc_read_sectors(p_env->gen.cdio, p_buf, i_lsn,
|
|
CDIO_MMC_READ_TYPE_CDDA, i_blocks));
|
|
}
|
|
|
|
static int
|
|
read_mode2_sector_openbsd(void *p_user_data, void *p_buf, lsn_t i_lsn,
|
|
bool b_mode2_form2)
|
|
{
|
|
scsireq_t req;
|
|
_img_private_t *p_env = p_user_data;
|
|
char buf[M2RAW_SECTOR_SIZE] = { 0, };
|
|
|
|
memset(&req, 0, sizeof(req));
|
|
req.cmd[0] = CDIO_MMC_GPCMD_READ_CD;
|
|
req.cmd[2] = (i_lsn >> 24) & 0xff;
|
|
req.cmd[3] = (i_lsn >> 16) & 0xff;
|
|
req.cmd[4] = (i_lsn >> 8) & 0xff;
|
|
req.cmd[5] = (i_lsn >> 0) & 0xff;
|
|
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(p_env->gen.fd, SCIOCCOMMAND, &req) < 0) {
|
|
cdio_info("ioctl SCIOCCOMMAND failed: %s\n", strerror(errno));
|
|
return (DRIVER_OP_ERROR);
|
|
}
|
|
|
|
if (req.retsts != SCCMD_OK) {
|
|
cdio_info("unexpected status for SCIOCCOMMAND %#x: %#x\n",
|
|
req.cmd[0], req.retsts);
|
|
return (DRIVER_OP_ERROR);
|
|
}
|
|
|
|
if (b_mode2_form2)
|
|
memcpy(p_buf, buf, M2RAW_SECTOR_SIZE);
|
|
else
|
|
memcpy(p_buf, buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE);
|
|
|
|
return (DRIVER_OP_SUCCESS);
|
|
}
|
|
|
|
static int
|
|
read_mode2_sectors_openbsd(void *p_user_data, void *p_buf, lsn_t i_lsn,
|
|
bool b_mode2_form2, unsigned int i_blocks)
|
|
{
|
|
uint16_t i_blocksize = b_mode2_form2 ? M2RAW_SECTOR_SIZE :
|
|
CDIO_CD_FRAMESIZE;
|
|
unsigned int i;
|
|
int retval;
|
|
|
|
for (i = 0; i < i_blocks; i++) {
|
|
if ((retval = read_mode2_sector_openbsd(p_user_data,
|
|
((char *)p_buf) + (i_blocksize * i), i_lsn + i,
|
|
b_mode2_form2)))
|
|
return (retval);
|
|
}
|
|
|
|
return (DRIVER_OP_SUCCESS);
|
|
}
|
|
|
|
static int
|
|
set_arg_openbsd(void *p_user_data, const char key[], const char value[])
|
|
{
|
|
_img_private_t *p_env = p_user_data;
|
|
|
|
if (!strcmp(key, "source")) {
|
|
if (!value)
|
|
return (DRIVER_OP_ERROR);
|
|
|
|
free(p_env->gen.source_name);
|
|
p_env->gen.source_name = strdup(value);
|
|
} else if (!strcmp(key, "access-mode")) {
|
|
if (strcmp(value, "READ_CD"))
|
|
cdio_info("unknown access type: %s ignored.", value);
|
|
} else
|
|
return (DRIVER_OP_ERROR);
|
|
|
|
return (DRIVER_OP_SUCCESS);
|
|
}
|
|
|
|
static cdio_funcs_t _funcs = {
|
|
.audio_get_volume = audio_get_volume_openbsd,
|
|
.audio_pause = audio_pause_openbsd,
|
|
.audio_play_msf = audio_play_msf_openbsd,
|
|
.audio_play_track_index = NULL,
|
|
#if USE_MMC_SUBCHANNEL
|
|
.audio_read_subchannel = audio_read_subchannel_mmc,
|
|
#else
|
|
.audio_read_subchannel = audio_read_subchannel_openbsd,
|
|
#endif
|
|
.audio_resume = audio_resume_openbsd,
|
|
.audio_set_volume = audio_set_volume_openbsd,
|
|
.audio_stop = audio_stop_openbsd,
|
|
.eject_media = eject_media_openbsd,
|
|
.free = cdio_generic_free,
|
|
.get_arg = get_arg_openbsd,
|
|
.get_blocksize = NULL,
|
|
.get_cdtext = get_cdtext_generic,
|
|
.get_default_device = cdio_get_default_device_openbsd,
|
|
.get_devices = cdio_get_devices_openbsd,
|
|
.get_disc_last_lsn = get_disc_last_lsn_openbsd,
|
|
.get_discmode = get_discmode_generic,
|
|
.get_drive_cap = get_drive_cap_mmc,
|
|
.get_first_track_num = get_first_track_num_generic,
|
|
.get_hwinfo = NULL,
|
|
.get_last_session = get_last_session_openbsd,
|
|
.get_media_changed = get_media_changed_mmc,
|
|
.get_mcn = get_mcn_mmc,
|
|
.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_lba = get_track_lba_openbsd,
|
|
.get_track_format = get_track_format_openbsd,
|
|
.get_track_green = get_track_green_openbsd,
|
|
.get_track_msf = NULL,
|
|
.get_track_preemphasis = get_track_preemphasis_generic,
|
|
.lseek = cdio_generic_lseek,
|
|
.read = cdio_generic_read,
|
|
.read_audio_sectors = read_audio_sectors_openbsd,
|
|
.read_data_sectors = read_data_sectors_generic,
|
|
.read_mode2_sector = read_mode2_sector_openbsd,
|
|
.read_mode2_sectors = read_mode2_sectors_openbsd,
|
|
.read_mode1_sector = NULL,
|
|
.read_mode1_sectors = NULL,
|
|
.read_toc = read_toc_openbsd,
|
|
.run_mmc_cmd = run_mmc_cmd_openbsd,
|
|
.set_arg = set_arg_openbsd,
|
|
.set_blocksize = NULL,
|
|
.set_speed = NULL,
|
|
};
|
|
|
|
bool
|
|
cdio_have_openbsd(void)
|
|
{
|
|
return (true);
|
|
}
|
|
|
|
CdIo *
|
|
cdio_open_openbsd(const char *source_name)
|
|
{
|
|
CdIo *ret;
|
|
_img_private_t *_data;
|
|
|
|
_data = calloc(1, sizeof(_img_private_t));
|
|
_data->gen.init = false;
|
|
_data->gen.toc_init = false;
|
|
_data->gen.fd = -1;
|
|
|
|
set_arg_openbsd(_data, "source",
|
|
(source_name ? source_name : DEFAULT_CDIO_DEVICE));
|
|
|
|
if (source_name && !cdio_is_device_generic(source_name))
|
|
goto error;
|
|
|
|
ret = cdio_new(_data, &_funcs);
|
|
if (!ret)
|
|
goto error;
|
|
|
|
if (!cdio_generic_init(_data, O_RDONLY))
|
|
goto error;
|
|
|
|
return (ret);
|
|
|
|
error:
|
|
cdio_generic_free(_data);
|
|
return (NULL);
|
|
}
|
|
|
|
CdIo *
|
|
cdio_open_am_openbsd(const char *source_name, const char *am)
|
|
{
|
|
return (cdio_open_openbsd(source_name));
|
|
}
|
|
|
|
char *
|
|
cdio_get_default_device_openbsd()
|
|
{
|
|
return (strdup(DEFAULT_CDIO_DEVICE));
|
|
}
|
|
|
|
char **
|
|
cdio_get_devices_openbsd(void)
|
|
{
|
|
char drive[40];
|
|
char **drives = NULL;
|
|
unsigned int num_drives = 0;
|
|
int cdfd;
|
|
int n;
|
|
|
|
for (n = 0; n <= 9; n++) {
|
|
snprintf(drive, sizeof(drive), "/dev/rcd%dc", n);
|
|
if (!cdio_is_device_quiet_generic(drive))
|
|
continue;
|
|
if ((cdfd = open(drive, O_RDONLY|O_NONBLOCK, 0)) == -1)
|
|
continue;
|
|
close(cdfd);
|
|
cdio_add_device_list(&drives, drive, &num_drives);
|
|
}
|
|
|
|
cdio_add_device_list(&drives, NULL, &num_drives);
|
|
|
|
return (drives);
|
|
}
|
|
|
|
driver_return_code_t
|
|
close_tray_openbsd(const char *psz_device)
|
|
{
|
|
return (DRIVER_OP_UNSUPPORTED);
|
|
}
|