📄 _cdio_linux.c
字号:
/* $Id: _cdio_linux.c,v 1.4 2006/09/26 22:18:44 dgp85 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 Linux-specific code and implements low-level control of the CD drive.*/#ifdef HAVE_CONFIG_H# include "config.h"#endifstatic const char _rcsid[] = "$Id: _cdio_linux.c,v 1.4 2006/09/26 22:18:44 dgp85 Exp $";#include <string.h>#include <cdio/sector.h>#include <cdio/util.h>#include <cdio/types.h>#include <cdio/scsi_mmc.h>#include <cdio/cdtext.h>#include "cdtext_private.h"#include "cdio_assert.h"#include "cdio_private.h"#ifdef HAVE_LINUX_CDROM#if defined(HAVE_LINUX_VERSION_H)# include <linux/version.h># if LINUX_VERSION_CODE >= KERNEL_VERSION(2,2,16)# define __CDIO_LINUXCD_BUILD# else# error "You need a kernel greater than 2.2.16 to have CDROM support"# endif#else # error "You need <linux/version.h> to have CDROM support"#endif#include <stdio.h>#include <stdlib.h>#include <errno.h>#include <unistd.h>#include <fcntl.h>#include <mntent.h>#include <linux/cdrom.h>#include <scsi/scsi.h>#include <scsi/sg.h>#include <scsi/scsi_ioctl.h>#include <sys/mount.h>#include <sys/stat.h>#include <sys/types.h>#include <sys/ioctl.h>typedef enum { _AM_NONE, _AM_IOCTL, _AM_READ_CD, _AM_READ_10} access_mode_t;typedef struct { /* Things common to all drivers like this. This must be first. */ generic_img_private_t gen; access_mode_t access_mode; /* Some of the more OS specific things. */ /* Entry info for each track, add 1 for leadout. */ struct cdrom_tocentry tocent[CDIO_CD_MAX_TRACKS+1]; struct cdrom_tochdr tochdr;} _img_private_t;/* Some ioctl() errno values which occur when the tray is empty */#define ERRNO_TRAYEMPTY(errno) \ ((errno == EIO) || (errno == ENOENT) || (errno == EINVAL))/**** prototypes for static functions ****/static bool is_cdrom_linux(const char *drive, char *mnttype);static bool read_toc_linux (void *p_user_data);static int run_scsi_cmd_linux( const void *p_user_data, unsigned int i_timeout, unsigned int i_cdb, const scsi_mmc_cdb_t *p_cdb, scsi_mmc_direction_t e_direction, unsigned int i_buf, /*in/out*/ void *p_buf );static access_mode_t str_to_access_mode_linux(const char *psz_access_mode) { const access_mode_t default_access_mode = _AM_IOCTL; if (NULL==psz_access_mode) return default_access_mode; if (!strcmp(psz_access_mode, "IOCTL")) return _AM_IOCTL; else if (!strcmp(psz_access_mode, "READ_CD")) return _AM_READ_CD; else if (!strcmp(psz_access_mode, "READ_10")) return _AM_READ_10; else { cdio_warn ("unknown access type: %s. Default IOCTL used.", psz_access_mode); return default_access_mode; }}static char *check_mounts_linux(const char *mtab){ FILE *mntfp; struct mntent *mntent; mntfp = setmntent(mtab, "r"); if ( mntfp != NULL ) { char *tmp; char *mnt_type; char *mnt_dev; while ( (mntent=getmntent(mntfp)) != NULL ) { mnt_type = malloc(strlen(mntent->mnt_type) + 1); if (mnt_type == NULL) continue; /* maybe you'll get lucky next time. */ mnt_dev = malloc(strlen(mntent->mnt_fsname) + 1); if (mnt_dev == NULL) { free(mnt_type); continue; } strcpy(mnt_type, mntent->mnt_type); strcpy(mnt_dev, mntent->mnt_fsname); /* Handle "supermount" filesystem mounts */ if ( strcmp(mnt_type, "supermount") == 0 ) { tmp = strstr(mntent->mnt_opts, "fs="); if ( tmp ) { free(mnt_type); mnt_type = strdup(tmp + strlen("fs=")); if ( mnt_type ) { tmp = strchr(mnt_type, ','); if ( tmp ) { *tmp = '\0'; } } } tmp = strstr(mntent->mnt_opts, "dev="); if ( tmp ) { free(mnt_dev); mnt_dev = strdup(tmp + strlen("dev=")); if ( mnt_dev ) { tmp = strchr(mnt_dev, ','); if ( tmp ) { *tmp = '\0'; } } } } if ( strcmp(mnt_type, "iso9660") == 0 ) { if (is_cdrom_linux(mnt_dev, mnt_type) > 0) { free(mnt_type); endmntent(mntfp); return mnt_dev; } } free(mnt_dev); free(mnt_type); } endmntent(mntfp); } return NULL;}/*! Return the value associated with the key "arg".*/static const char *get_arg_linux (void *env, const char key[]){ _img_private_t *_obj = env; if (!strcmp (key, "source")) { return _obj->gen.source_name; } else if (!strcmp (key, "access-mode")) { switch (_obj->access_mode) { case _AM_IOCTL: return "ioctl"; case _AM_READ_CD: return "READ_CD"; case _AM_READ_10: return "READ_10"; case _AM_NONE: return "no access method"; } } return NULL;}#undef USE_LINUX_CAP#ifdef USE_LINUX_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. */static voidget_drive_cap_linux (const void *p_user_data, /*out*/ cdio_drive_read_cap_t *p_read_cap, /*out*/ cdio_drive_write_cap_t *p_write_cap, /*out*/ cdio_drive_misc_cap_t *p_misc_cap){ const _img_private_t *p_env = p_user_data; int32_t i_drivetype; i_drivetype = ioctl (p_env->gen.fd, CDROM_GET_CAPABILITY, CDSL_CURRENT); if (i_drivetype < 0) { *p_read_cap = CDIO_DRIVE_CAP_ERROR; *p_write_cap = CDIO_DRIVE_CAP_ERROR; *p_misc_cap = CDIO_DRIVE_CAP_ERROR; return; } *p_read_cap = 0; *p_write_cap = 0; *p_misc_cap = 0; /* Reader */ if (i_drivetype & CDC_PLAY_AUDIO) *p_read_cap |= CDIO_DRIVE_CAP_READ_AUDIO; if (i_drivetype & CDC_CD_R) *p_read_cap |= CDIO_DRIVE_CAP_READ_CD_R; if (i_drivetype & CDC_CD_RW) *p_read_cap |= CDIO_DRIVE_CAP_READ_CD_RW; if (i_drivetype & CDC_DVD) *p_read_cap |= CDIO_DRIVE_CAP_READ_DVD_ROM; /* Writer */ if (i_drivetype & CDC_CD_RW) *p_read_cap |= CDIO_DRIVE_CAP_WRITE_CD_RW; if (i_drivetype & CDC_DVD_R) *p_read_cap |= CDIO_DRIVE_CAP_WRITE_DVD_R; if (i_drivetype & CDC_DVD_RAM) *p_read_cap |= CDIO_DRIVE_CAP_WRITE_DVD_RAM; /* Misc */ if (i_drivetype & CDC_CLOSE_TRAY) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_CLOSE_TRAY; if (i_drivetype & CDC_OPEN_TRAY) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_EJECT; if (i_drivetype & CDC_LOCK) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_LOCK; if (i_drivetype & CDC_SELECT_SPEED) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_SELECT_SPEED; if (i_drivetype & CDC_SELECT_DISC) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_SELECT_DISC; if (i_drivetype & CDC_MULTI_SESSION) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_MULTI_SESSION; if (i_drivetype & CDC_MEDIA_CHANGED) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_MEDIA_CHANGED; if (i_drivetype & CDC_RESET) *p_misc_cap |= CDIO_DRIVE_CAP_MISC_RESET;}#endif/*! Return the media catalog number MCN. Note: string is malloc'd so caller should free() then returned string when done with it. */static char *get_mcn_linux (const void *p_user_data) { struct cdrom_mcn mcn; const _img_private_t *p_env = p_user_data; memset(&mcn, 0, sizeof(mcn)); if (ioctl(p_env->gen.fd, CDROM_GET_MCN, &mcn) != 0) return NULL; return strdup(mcn.medium_catalog_number);}/*! Get format of track. */static track_format_tget_track_format_linux(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_linux (p_user_data) ; if (i_track > (p_env->gen.i_tracks+p_env->gen.i_first_track) || i_track < p_env->gen.i_first_track) return TRACK_FORMAT_ERROR; i_track -= p_env->gen.i_first_track; /* This is pretty much copied from the "badly broken" cdrom_count_tracks in linux/cdrom.c. */ if (p_env->tocent[i_track].cdte_ctrl & CDIO_CDROM_DATA_TRACK) { if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_CDI_TRACK) return TRACK_FORMAT_CDI; else if (p_env->tocent[i_track].cdte_format == CDIO_CDROM_XA_TRACK) return TRACK_FORMAT_XA; else return TRACK_FORMAT_DATA; } else return TRACK_FORMAT_AUDIO; }/*! Return true if we have XA data (green, mode2 form1) or XA data (green, mode2 form2). That is track begins: sync - header - subheader 12 4 - 8 FIXME: there's gotta be a better design for this and get_track_format?*/static boolget_track_green_linux(void *p_user_data, track_t i_track) { _img_private_t *p_env = p_user_data; if (!p_env->gen.toc_init) read_toc_linux (p_user_data) ; if (i_track >= (p_env->gen.i_tracks+p_env->gen.i_first_track) || i_track < p_env->gen.i_first_track) return false; i_track -= p_env->gen.i_first_track; /* FIXME: Dunno if this is the right way, but it's what I was using in cd-info for a while. */ return ((p_env->tocent[i_track].cdte_ctrl & 2) != 0);}/*! Return the starting MSF (minutes/secs/frames) for track number track_num in obj. Track numbers usually start at something greater than 0, usually 1. The "leadout" track is specified either by using i_track LEADOUT_TRACK or the total tracks+1. False is returned if there is no track entry.*/static boolget_track_msf_linux(void *p_user_data, track_t i_track, msf_t *msf){ _img_private_t *p_env = p_user_data; if (NULL == msf) return false; if (!p_env->gen.toc_init) read_toc_linux (p_user_data) ; if (i_track == CDIO_CDROM_LEADOUT_TRACK) i_track = p_env->gen.i_tracks + p_env->gen.i_first_track; if (i_track > (p_env->gen.i_tracks+p_env->gen.i_first_track) || i_track < p_env->gen.i_first_track) { return false; } else { struct cdrom_msf0 *msf0= &p_env->tocent[i_track-p_env->gen.i_first_track].cdte_addr.msf; msf->m = cdio_to_bcd8(msf0->minute); msf->s = cdio_to_bcd8(msf0->second); msf->f = cdio_to_bcd8(msf0->frame); return true; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -