📄 _cdio_bsdi.c
字号:
/* $Id: _cdio_bsdi.c,v 1.3 2005/01/01 02:43:57 rockyb Exp $ Copyright (C) 2001 Herbert Valerio Riedel <hvr@gnu.org> Copyright (C) 2002, 2003, 2004 Rocky Bernstein <rocky@panix.com> This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA*//* This file contains BSDI-specific code and implements low-level control of the CD drive.*/#ifdef HAVE_CONFIG_H# include "config.h"#endifstatic const char _rcsid[] = "$Id: _cdio_bsdi.c,v 1.3 2005/01/01 02:43:57 rockyb Exp $";#include <cdio/logging.h>#include <cdio/sector.h>#include <cdio/util.h>#include "cdio_assert.h"#include "cdio_private.h"#define DEFAULT_CDIO_DEVICE "/dev/rsr0c"#include <string.h>#ifdef HAVE_BSDI_CDROM#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <unistd.h>#include <fcntl.h>/*#define USE_ETC_FSTAB*/#ifdef USE_ETC_FSTAB#include <fstab.h>#endif#include <dvd.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/ioctl.h>#include </sys/dev/scsi/scsi.h>#include </sys/dev/scsi/scsi_ioctl.h>#include "cdtext_private.h"typedef enum { _AM_NONE, _AM_IOCTL,} access_mode_t;typedef struct { /* Things common to all drivers like this. This must be first. */ generic_img_private_t gen; access_mode_t access_mode; /* Some of the more OS specific things. */ /* Track information */ struct cdrom_tochdr tochdr; struct cdrom_tocentry tocent[CDIO_CD_MAX_TRACKS+1]; } _img_private_t;/* Define the Cdrom Generic Command structure */typedef struct cgc{ scsi_mmc_cdb_t cdb; u_char *buf; int buflen; int rw; unsigned int timeout; scsi_user_sense_t *sus;} cgc_t;/* This code adapted from Steven M. Schultz's libdvd*/static int run_scsi_cmd_bsdi(const void *p_user_data, unsigned int i_timeout_ms, unsigned int i_cdb, const scsi_mmc_cdb_t *p_cdb, scsi_mmc_direction_t e_direction, unsigned int i_buf, /*in/out*/ void *p_buf ){ const _img_private_t *p_env = p_user_data; int i_status, i_asc; struct scsi_user_cdb suc; struct scsi_sense *sp; again: suc.suc_flags = SCSI_MMC_DATA_READ == e_direction ? SUC_READ : SUC_WRITE; suc.suc_cdblen = i_cdb; memcpy(suc.suc_cdb, p_cdb, i_cdb); suc.suc_data = p_buf; suc.suc_datalen = i_buf; suc.suc_timeout = msecs2secs(i_timeout_ms); if (ioctl(p_env->gen.fd, SCSIRAWCDB, &suc) == -1) return(errno); i_status = suc.suc_sus.sus_status;#if 0 /* * If the device returns a scsi sense error and debugging is enabled print * some hopefully useful information on stderr. */ if (i_status && debug) { unsigned char *cp; int i; cp = suc.suc_sus.sus_sense; fprintf(stderr,"i_status = %x cdb =", i_status); for (i = 0; i < cdblen; i++) fprintf(stderr, " %x", cgc->cdb[i]); fprintf(stderr, "\nsense ="); for (i = 0; i < 16; i++) fprintf(stderr, " %x", cp[i]); fprintf(stderr, "\n"); }#endif /* * HACK! Some drives return a silly "medium changed" on the first * command AND a non-zero i_status which gets turned into a fatal * (EIO) error even though the operation was a success. Retrying * the operation clears the media changed status and gets the * answer. */ sp = (struct scsi_sense *)&suc.suc_sus.sus_sense; i_asc = XSENSE_ASC(sp); if (i_status == STS_CHECKCOND && i_asc == 0x28) goto again;#if 0 if (cgc->sus) memcpy(cgc->sus, &suc.suc_sus, sizeof (struct scsi_user_sense));#endif return(i_status);}/* Check a drive to see if it is a CD-ROM Return 1 if a CD-ROM. 0 if it exists but isn't a CD-ROM drive and -1 if no device exists .*/static boolcdio_is_cdrom(char *drive, char *mnttype){ bool is_cd=false; int cdfd; struct cdrom_tochdr tochdr; /* If it doesn't exist, return -1 */ if ( !cdio_is_device_quiet_generic(drive) ) { return(false); } /* If it does exist, verify that it's an available CD-ROM */ cdfd = open(drive, (O_RDONLY|O_EXCL|O_NONBLOCK), 0); /* Should we want to test the condition in more detail: ENOENT is the error for /dev/xxxxx does not exist; ENODEV means there's no drive present. */ if ( cdfd >= 0 ) { if ( ioctl(cdfd, CDROMREADTOCHDR, &tochdr) != -1 ) { is_cd = true; } close(cdfd); } /* Even if we can't read it, it might be mounted */ else if ( mnttype && (strcmp(mnttype, "cd9660") == 0) ) { is_cd = true; } return(is_cd);}/*! Initialize CD device. */static bool_cdio_init (_img_private_t *p_env){ if (p_env->gen.init) { cdio_warn ("init called more than once"); return false; } p_env->gen.fd = open (p_env->gen.source_name, O_RDONLY, 0); if (p_env->gen.fd < 0) { cdio_warn ("open (%s): %s", p_env->gen.source_name, strerror (errno)); return false; } p_env->gen.init = true; p_env->gen.toc_init = false; return true;}/* Read audio sectors*/static int_read_audio_sectors_bsdi (void *user_data, void *data, lsn_t lsn, unsigned int nblocks){ char buf[CDIO_CD_FRAMESIZE_RAW] = { 0, }; struct cdrom_msf *msf = (struct cdrom_msf *) &buf; msf_t _msf; _img_private_t *p_env = user_data; cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf); msf->cdmsf_min0 = cdio_from_bcd8(_msf.m); msf->cdmsf_sec0 = cdio_from_bcd8(_msf.s); msf->cdmsf_frame0 = cdio_from_bcd8(_msf.f); if (p_env->gen.ioctls_debugged == 75) cdio_debug ("only displaying every 75th ioctl from now on"); if (p_env->gen.ioctls_debugged == 30 * 75) cdio_debug ("only displaying every 30*75th ioctl from now on"); if (p_env->gen.ioctls_debugged < 75 || (p_env->gen.ioctls_debugged < (30 * 75) && p_env->gen.ioctls_debugged % 75 == 0) || p_env->gen.ioctls_debugged % (30 * 75) == 0) cdio_debug ("reading %2.2d:%2.2d:%2.2d", msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0); p_env->gen.ioctls_debugged++; switch (p_env->access_mode) { case _AM_NONE: cdio_warn ("no way to read audio"); return 1; break; case _AM_IOCTL: { unsigned int i; for (i=0; i < nblocks; i++) { if (ioctl (p_env->gen.fd, CDROMREADRAW, &buf) == -1) { perror ("ioctl()"); return 1; /* exit (EXIT_FAILURE); */ } memcpy (((char *)data) + (CDIO_CD_FRAMESIZE_RAW * i), buf, CDIO_CD_FRAMESIZE_RAW); } break; } } return 0;}/*! Reads a single mode1 sector from cd device into data starting from lsn. Returns 0 if no error. */static int_read_mode1_sector_bsdi (void *user_data, void *data, lsn_t lsn, bool b_form2){#if FIXED char buf[M2RAW_SECTOR_SIZE] = { 0, }; do something here. #else return cdio_generic_read_form1_sector(user_data, data, lsn);#endif return 0;}/*! Reads nblocks of mode2 sectors from cd device into data starting from lsn. Returns 0 if no error. */static int_read_mode1_sectors_bsdi (void *user_data, void *data, lsn_t lsn, bool b_form2, unsigned int nblocks){ _img_private_t *p_env = user_data; unsigned int i; int retval; unsigned int blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE; for (i = 0; i < nblocks; i++) { if ( (retval = _read_mode1_sector_bsdi (p_env, ((char *)data) + (blocksize * i), lsn + i, b_form2)) ) return retval; } return 0;}/*! Reads a single mode2 sector from cd device into data starting from lsn. Returns 0 if no error. */static int_read_mode2_sector_bsdi (void *user_data, void *data, lsn_t lsn, bool b_form2){ char buf[M2RAW_SECTOR_SIZE] = { 0, }; struct cdrom_msf *msf = (struct cdrom_msf *) &buf; msf_t _msf; _img_private_t *p_env = user_data; cdio_lba_to_msf (cdio_lsn_to_lba(lsn), &_msf); msf->cdmsf_min0 = cdio_from_bcd8(_msf.m); msf->cdmsf_sec0 = cdio_from_bcd8(_msf.s); msf->cdmsf_frame0 = cdio_from_bcd8(_msf.f); if (p_env->gen.ioctls_debugged == 75) cdio_debug ("only displaying every 75th ioctl from now on"); if (p_env->gen.ioctls_debugged == 30 * 75) cdio_debug ("only displaying every 30*75th ioctl from now on"); if (p_env->gen.ioctls_debugged < 75 || (p_env->gen.ioctls_debugged < (30 * 75) && p_env->gen.ioctls_debugged % 75 == 0) || p_env->gen.ioctls_debugged % (30 * 75) == 0) cdio_debug ("reading %2.2d:%2.2d:%2.2d", msf->cdmsf_min0, msf->cdmsf_sec0, msf->cdmsf_frame0); p_env->gen.ioctls_debugged++; switch (p_env->access_mode) { case _AM_NONE: cdio_warn ("no way to read mode2"); return 1; break; case _AM_IOCTL: if (ioctl (p_env->gen.fd, CDROMREADMODE2, &buf) == -1) { perror ("ioctl()"); return 1; /* exit (EXIT_FAILURE); */ } break; } if (b_form2) memcpy (data, buf, M2RAW_SECTOR_SIZE); else memcpy (((char *)data), buf + CDIO_CD_SUBHEADER_SIZE, CDIO_CD_FRAMESIZE); return 0;}/*! Reads nblocks of mode2 sectors from cd device into data starting from lsn. Returns 0 if no error. */static int_read_mode2_sectors_bsdi (void *user_data, void *data, lsn_t lsn, bool b_form2, unsigned int nblocks){ _img_private_t *p_env = user_data; unsigned int i; unsigned int i_blocksize = b_form2 ? M2RAW_SECTOR_SIZE : CDIO_CD_FRAMESIZE; /* For each frame, pick out the data part we need */ for (i = 0; i < nblocks; i++) { int retval = _read_mode2_sector_bsdi(p_env, ((char *)data) + (i_blocksize * i), lsn + i, b_form2); if (retval) return retval; } return 0;}/*! Return the size of the CD in logical block address (LBA) units. */static uint32_t _stat_size_bsdi (void *user_data){ _img_private_t *p_env = user_data; struct cdrom_tocentry tocent; uint32_t size; tocent.cdte_track = CDIO_CDROM_LEADOUT_TRACK; tocent.cdte_format = CDROM_LBA; if (ioctl (p_env->gen.fd, CDROMREADTOCENTRY, &tocent) == -1) { perror ("ioctl(CDROMREADTOCENTRY)"); exit (EXIT_FAILURE); } size = tocent.cdte_addr.lba; return size;}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -