This repository has been archived on 2025-05-24. You can view files and clone it, but cannot push or open issues or pull requests.
Files
libcdio-osx/lib/driver/FreeBSD/freebsd_cam.c
rocky 13245c6a55 Patch from John Wehle:
A side effect of opening the cdrom device on FreeBSD is it
locks the drive.  This makes cdio_get_media_changed less
useful and prevents you from being able to switch disks
when using things such as the audacious media player.

This patch simply unlocks the drive right after it's opened
prior to opening the cam passthrough device.
2009-04-23 03:26:00 -04:00

260 lines
7.0 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
$Id: freebsd_cam.c,v 1.12 2008/04/21 18:30:20 karl Exp $
Copyright (C) 2004, 2005, 2008, 2009 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;
}
(void)ioctl(p_env->gen.fd, CDIOCALLOW);
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 */