📄 interface.c
字号:
/* @(#)interface.c 1.3 00/01/25 Copyright 1998,1999 Heiko Eissfeldt */#ifndef lintstatic char sccsid[] ="@(#)interface.c 1.3 00/01/25 Copyright 1998,1999 Heiko Eissfeldt";#endif/*** * CopyPolicy: GNU Public License 2 applies * Copyright (C) 1994-1997 Heiko Eissfeldt heiko@colossus.escape.de * * Interface module for cdrom drive access * * Two interfaces are possible. * * 1. using 'cooked' ioctls() (Linux only) * : available for atapi, sbpcd and cdu31a drives only. * * 2. using the generic scsi device (for details see SCSI Prog. HOWTO). * NOTE: a bug/misfeature in the kernel requires blocking signal * SIGINT during SCSI command handling. Once this flaw has * been removed, the sigprocmask SIG_BLOCK and SIG_UNBLOCK calls * should removed, thus saving context switches. * * For testing purposes I have added a third simulation interface. * * Version 0.8: used experiences of Jochen Karrer. * SparcLinux port fixes * AlphaLinux port fixes * */#if 0#define SIM_CD#endif#include "config.h"#include <stdio.h>#include <standard.h>#include <stdlib.h>#include <unixstd.h>#include <strdefs.h>#include <errno.h>#include <signal.h>#include <fcntl.h>#include <assert.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <statdefs.h>#include "mycdrom.h"#include "lowlevel.h"/* some include file locations have changed with newer kernels */#if defined (__linux__)# if LINUX_VERSION_CODE > 0x10300 + 97# if LINUX_VERSION_CODE < 0x200ff# include <linux/sbpcd.h># include <linux/ucdrom.h># endif# if !defined(CDROM_SELECT_SPEED)# include <linux/ucdrom.h># endif# endif#endif#include <scg/scsitransp.h>#include "mytype.h"#include "byteorder.h"#include "interface.h"#include "cdda2wav.h"#include "semshm.h"#include "setuid.h"#include "ringbuff.h"#include "toc.h"#include "global.h"#include "ioctl.h"#include "scsi_cmds.h"#include <utypes.h>#include <cdrecord.h>unsigned interface;int trackindex_disp = 0;TOC g_toc [MAXTRK]; /* 100 */unsigned char MCN[14]; /* including a zero string terminator */void (*EnableCdda) __PR((SCSI *, int Switch));unsigned (*ReadToc) __PR(( SCSI *scgp, TOC *ptoc ));void (*ReadTocText) __PR(( SCSI *scgp ));unsigned (*ReadLastAudio) __PR(( SCSI *scgp, unsigned tracks ));void (*ReadCdRom) __PR((SCSI *scgp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal ));void (*ReadCdRomData) __PR((SCSI *scgp, unsigned char *p, unsigned lSector, unsigned SectorBurstVal ));subq_chnl *(*ReadSubQ) __PR(( SCSI *scgp, unsigned char sq_format, unsigned char track ));void (*SelectSpeed) __PR(( SCSI *scgp, unsigned speed ));int (*Play_at) __PR(( SCSI *scgp, unsigned int from_sector, unsigned int sectors));int (*StopPlay) __PR(( SCSI *scgp));void (*trash_cache) __PR((UINT4 *p, unsigned lSector, unsigned SectorBurstVal));typedef struct string_len { char *str; unsigned int sl;} mystring;static mystring drv_is_not_mmc[] = { {"SONY CD-ROM CDU625 1.0",28}, {NULL,0} /* must be last entry */};static mystring drv_has_mmc_cdda[] = { {NULL,0} /* must be last entry */};static int Is_a_Toshiba3401;int Toshiba3401 __PR((void));int Toshiba3401 ( ) { return Is_a_Toshiba3401;}/* hook */static void Dummy __PR(( void ));static void Dummy ( ){}static SCSI *scgp;SCSI * get_scsi_p __PR((void));SCSI * get_scsi_p( ){ return scgp;}#if !defined(SIM_CD)static void trash_cache_SCSI __PR((UINT4 *p, unsigned lSector, unsigned SectorBurstVal));static void trash_cache_SCSI(p, lSector, SectorBurstVal) UINT4 *p; unsigned lSector; unsigned SectorBurstVal;{ /* trash the cache */ ReadCdRom(get_scsi_p(), p, find_an_off_sector(lSector, SectorBurstVal), min(global.nsectors,6));}static void Check_interface_for_device __PR((struct stat *statstruct, char *pdev_name));static int OpenCdRom __PR((char *pdev_name));static void SetupSCSI __PR((void));static void SetupSCSI( ){ unsigned char *p; if (interface != GENERIC_SCSI) { /* unfortunately we have the wrong interface and are * not able to change on the fly */ fprintf(stderr, "The generic SCSI interface and devices are required\n"); exit(1); } /* do a test unit ready to 'init' the device. */ TestForMedium(scgp); /* check for the correct type of unit. */ p = Inquiry(scgp);#undef TYPE_ROM#define TYPE_ROM 5#undef TYPE_WORM#define TYPE_WORM 4 if (p == NULL) { fprintf(stderr, "Inquiry command failed. Aborting...\n"); exit(1); } if ((*p != TYPE_ROM && *p != TYPE_WORM)) { fprintf(stderr, "this is neither a scsi cdrom nor a worm device\n"); exit(1); } /* generic Sony type defaults */ density = 0x0; accepts_fua_bit = -1; accepts_fua_bit = -1; EnableCdda = (void (*) __PR((SCSI *, int)))Dummy; ReadCdRom = ReadCdda12; ReadCdRomData = (void (*) __PR((SCSI *, unsigned char *, unsigned, unsigned ))) ReadStandard; ReadLastAudio = ReadFirstSessionTOCSony; SelectSpeed = SpeedSelectSCSISony; Play_at = Play_atSCSI; StopPlay = StopPlaySCSI; trash_cache = trash_cache_SCSI; ReadTocText = ReadTocTextSCSIMMC; /* check for brands and adjust special peculiaritites */ /* If your drive is not treated correctly, you can adjust some things here: *in_leendian: should be to 1, if the CDROM drive or CD-Writer delivers the samples in the native byteorder of the audio cd (LSB first). HP CD-Writers need it set to 0. NOTE: If you get correct wav files when using sox with the '-x' option, the endianess is wrong. You can use the -C option to specify the value of (*in_lendian). */ { int mmc_code; allow_atapi(scgp, 1); if (*p == TYPE_ROM) { mmc_code = heiko_mmc(scgp); } else { mmc_code = 0; } /* Exceptions for drives that report incorrect MMC capability */ if (mmc_code != 0) { /* these drives are NOT capable of MMC commands */ mystring *pp = drv_is_not_mmc; while (pp->str != NULL) { if (!strncmp(pp->str, (char *)p+8,pp->sl)) { mmc_code = 0; break; } pp++; } } { /* these drives flag themselves as non-MMC, but offer CDDA reading only with a MMC method. */ mystring *pp = drv_has_mmc_cdda; while (pp->str != NULL) { if (!strncmp(pp->str, (char *)p+8,pp->sl)) { mmc_code = 1; break; } pp++; } } switch (mmc_code) { case 2: /* SCSI-3 cdrom drive with accurate audio stream */ if ( (*in_lendian) == -1 ) (*in_lendian) = 1; global.overlap = 0; ReadCdRom = ReadCddaMMC12; ReadLastAudio = ReadFirstSessionTOCMMC; global.speed = 0xffff; SelectSpeed = SpeedSelectSCSIMMC; ReadTocText = ReadTocTextSCSIMMC; break; case 1: /* SCSI-3 cdrom drive with no accurate audio stream */ if ( (*in_lendian) == -1 ) (*in_lendian) = 1; global.overlap = 1; ReadCdRom = ReadCddaMMC12; ReadLastAudio = ReadFirstSessionTOCMMC; global.speed = 0xffff; SelectSpeed = SpeedSelectSCSIMMC; break; case -1: /* "MMC drive does not support cdda reading, sorry\n." */ /* fall through */ case 0: /* non SCSI-3 cdrom drive */ ReadLastAudio = NULL; if (!memcmp(p+8,"TOSHIBA", 7) || !memcmp(p+8,"IBM", 3) || !memcmp(p+8,"DEC", 3)) { density = 0x82; EnableCdda = EnableCddaModeSelect; ReadCdRom = ReadStandard; SelectSpeed = SpeedSelectSCSIToshiba; if (!memcmp(p+16, "CD-ROM XM-3401",14)) { Is_a_Toshiba3401 = 1; } if ( (*in_lendian) == -1 ) (*in_lendian) = 1; } else if (!memcmp(p+8,"IMS",3) || !memcmp(p+8,"KODAK",5) || !memcmp(p+8,"RICOH",5) || !memcmp(p+8,"HP",2) || !memcmp(p+8,"PHILIPS",7) || !memcmp(p+8,"PLASMON",7) || !memcmp(p+8,"GRUNDIG CDR100IPW",17) || !memcmp(p+8,"MITSUMI CD-R ",13)) { EnableCdda = EnableCddaModeSelect; ReadCdRom = ReadStandard; SelectSpeed = SpeedSelectSCSIPhilipsCDD2600; /* treat all of these as bigendian */ if ( (*in_lendian) == -1 ) (*in_lendian) = 0; /* no overlap reading for cd-writers */ global.overlap = 0; } else if (!memcmp(p+8,"NRC",3)) { SelectSpeed = NULL; } else if (!memcmp(p+8,"YAMAHA",6)) { EnableCdda = EnableCddaModeSelect; SelectSpeed = SpeedSelectSCSIYamaha; /* no overlap reading for cd-writers */ global.overlap = 0; if ( (*in_lendian) == -1 ) (*in_lendian) = 1; } else if (!memcmp(p+8,"PLEXTOR",7)) { if ( (*in_lendian) == -1 ) (*in_lendian) = 1; global.overlap = 0; ReadLastAudio = ReadFirstSessionTOCSony; ReadTocText = ReadTocTextSCSIMMC; } else if (!memcmp(p+8,"SONY",4)) { if ( (*in_lendian) == -1 ) (*in_lendian) = 1; if (!memcmp(p+16, "CD-ROM CDU55E",13)) { ReadCdRom = ReadCddaMMC12; } ReadLastAudio = ReadFirstSessionTOCSony; ReadTocText = ReadTocTextSCSIMMC; } else if (!memcmp(p+8,"NEC",3)) { ReadCdRom = ReadCdda10; ReadTocText = NULL; SelectSpeed = SpeedSelectSCSINEC; if ( (*in_lendian) == -1 ) (*in_lendian) = 1; if (!memcmp(p+29,"5022.0r",3)) /* I assume all versions of the 502 require this? */ global.overlap = 0; /* no overlap reading for NEC CD-ROM 502 */ } else if (!memcmp(p+8,"MATSHITA",8)) { ReadCdRom = ReadCdda12Matsushita; if ( (*in_lendian) == -1 ) (*in_lendian) = 1; } } /* switch (get_mmc) */ } ReadToc = ReadTocSCSI; ReadSubQ = ReadSubQSCSI; /* look if caddy is loaded */ if (interface == GENERIC_SCSI) while (!wait_unit_ready(scgp, 60)) { fprintf(stderr,"load cdrom please and press enter"); getchar(); }}/********************** General setup *******************************//* As the name implies, interfaces and devices are checked. We also adjust nsectors, overlap, and interface for the first time here. Any unnecessary privileges (setuid, setgid) are also dropped here.*/static void Check_interface_for_device( statstruct, pdev_name) struct stat *statstruct; char *pdev_name;{#if !defined (STAT_MACROS_BROKEN) || (STAT_MACROS_BROKEN != 1) if (!S_ISCHR(statstruct->st_mode) && !S_ISBLK(statstruct->st_mode)) { fprintf(stderr, "%s is not a device\n",pdev_name); exit(1); }#endif#if defined (HAVE_ST_RDEV) && (HAVE_ST_RDEV == 1) switch ((int) (statstruct->st_rdev >> 8L)) {#if defined (__linux__) case SCSI_GENERIC_MAJOR: /* generic */#else default: /* ??? what is the proper value here */#endif#if !defined (STAT_MACROS_BROKEN) || (STAT_MACROS_BROKEN != 1)#if defined (__linux__) if (!S_ISCHR(statstruct->st_mode)) { fprintf(stderr, "%s is not a char device\n",pdev_name); exit(1); } if (interface != GENERIC_SCSI) { fprintf(stderr, "wrong interface (cooked_ioctl) for this device (%s)\nset to generic_scsi\n", pdev_name); interface = GENERIC_SCSI; }#endif#endif break;#if defined (__linux__) || defined (__FreeBSD__)#if defined (__linux__) case SCSI_CDROM_MAJOR: /* scsi cd */ default: /* for example ATAPI cds */#else#if defined (__FreeBSD__) case 117: if (!S_ISCHR(statstruct->st_mode)) { fprintf(stderr, "%s is not a char device\n",pdev_name); exit(1); } if (interface != COOKED_IOCTL) { fprintf(stderr, "cdrom device (%s) is not of type generic SCSI. " "Setting interface to cooked_ioctl.\n", pdev_name); interface = COOKED_IOCTL; } break; case 19: /* first atapi cd */#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -