/* * This file has been modified for the cdrkit suite. * * The behaviour and appearence of the program code below can differ to a major * extent from the version distributed by the original author(s). * * For details, see Changelog file distributed with the cdrkit package. If you * received this file from another source then ask the distributing person for * a log of modifications. * */ /* @(#)interface.c 1.40 06/02/19 Copyright 1998-2002 Heiko Eissfeldt, Copyright 2006 J. Schilling */ /*** * 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 #include #include #include #include #include #include #include #include #include #include #include #include #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 # include # endif # if !defined(CDROM_SELECT_SPEED) # include # endif # endif #endif #include #include "mytype.h" #include "byteorder.h" #include "interface.h" #include "icedax.h" #include "semshm.h" #include "setuid.h" #include "ringbuff.h" #include "toc.h" #include "global.h" #include "ioctl.h" #include "exitcodes.h" #include "scsi_cmds.h" #include #include #include "scsi_scan.h" unsigned interface; int trackindex_disp = 0; void priv_init(void); void priv_on(void); void priv_off(void); void (*EnableCdda)(SCSI *, int Switch, unsigned uSectorsize); unsigned (*doReadToc)(SCSI *usalp); void (*ReadTocText)(SCSI *usalp); unsigned (*ReadLastAudio)(SCSI *usalp); int (*ReadCdRom)(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal); int (*ReadCdRomData)(SCSI *usalp, unsigned char *p, unsigned lSector, unsigned SectorBurstVal); int (*ReadCdRomSub)(SCSI *usalp, UINT4 *p, unsigned lSector, unsigned SectorBurstVal); subq_chnl *(*ReadSubChannels)(SCSI *usalp, unsigned lSector); subq_chnl *(*ReadSubQ)(SCSI *usalp, unsigned char sq_format, unsigned char track); void (*SelectSpeed)(SCSI *usalp, unsigned speed); int (*Play_at)(SCSI *usalp, unsigned int from_sector, unsigned int sectors); int (*StopPlay)(SCSI *usalp); void (*trash_cache)(UINT4 *p, unsigned lSector, unsigned SectorBurstVal); #if defined USE_PARANOIA long cdda_read(void *d, void *buffer, long beginsector, long sectors); long cdda_read(void *d, void *buffer, long beginsector, long sectors) { long ret = ReadCdRom(d, buffer, beginsector, sectors); return ret; } #endif typedef struct string_len { char *str; unsigned int sl; } mystring; static mystring drv_is_not_mmc[] = { {"DEC RRD47 (C) DEC ",24}, /* {"SONY CD-ROM CDU625 1.0",28}, */ {NULL,0} /* must be last entry */ }; static mystring drv_has_mmc_cdda[] = { {"HITACHI CDR-7930",16}, /* {"TOSHIBA CD-ROM XM-5402TA3605",28}, */ {NULL,0} /* must be last entry */ }; static int Is_a_Toshiba3401; int Toshiba3401(void); int Toshiba3401() { return Is_a_Toshiba3401; } /* hook */ static void Dummy(void); static void Dummy() { } static SCSI *usalp; SCSI *get_scsi_p(void); SCSI *get_scsi_p() { return usalp; } #if !defined(SIM_CD) static void trash_cache_SCSI(UINT4 *p, unsigned lSector, unsigned SectorBurstVal); static void trash_cache_SCSI(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(struct stat *statstruct, char *pdev_name); static int OpenCdRom(char *pdev_name); static void SetupSCSI(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(SYNTAX_ERROR); } /* do a test unit ready to 'init' the device. */ TestForMedium(usalp); /* check for the correct type of unit. */ p = Inquiry(usalp); #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(DEVICE_ERROR); } if ((*p != TYPE_ROM && *p != TYPE_WORM)) { fprintf(stderr, "this is neither a scsi cdrom nor a worm device\n"); exit(SYNTAX_ERROR); } if (global.quiet == 0) { fprintf(stderr, "Type: %s, Vendor '%8.8s' Model '%16.16s' Revision '%4.4s' ", *p == TYPE_ROM ? "ROM" : "WORM" ,p+8 ,p+16 ,p+32); } /* generic Sony type defaults */ density = 0x0; accepts_fua_bit = -1; EnableCdda = (void (*)(SCSI *, int, unsigned))Dummy; ReadCdRom = ReadCdda12; ReadCdRomSub = ReadCddaSubSony; ReadCdRomData = (int (*)(SCSI *, unsigned char *, unsigned, unsigned))ReadStandardData; ReadLastAudio = ReadFirstSessionTOCSony; SelectSpeed = SpeedSelectSCSISony; Play_at = Play_atSCSI; StopPlay = StopPlaySCSI; trash_cache = trash_cache_SCSI; ReadTocText = ReadTocTextSCSIMMC; doReadToc = ReadTocSCSI; ReadSubQ = ReadSubQSCSI; ReadSubChannels = NULL; /* check for brands and adjust special peculiaritites */ /* If your drive is not treated correctly, you can adjust some things here: global.in_lendian: 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 global.in_lendian. */ { int mmc_code; usalp->silent ++; allow_atapi(usalp, 1); if (*p == TYPE_ROM) { mmc_code = heiko_mmc(usalp); } else { mmc_code = 0; } usalp->silent --; /* 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 */ /* fall through */ case 1: /* SCSI-3 cdrom drive with no accurate audio stream */ /* fall through */ lost_toshibas: global.in_lendian = 1; if (mmc_code == 2) global.overlap = 0; else global.overlap = 1; ReadCdRom = ReadCddaFallbackMMC; ReadCdRomSub = ReadCddaSubSony; ReadLastAudio = ReadFirstSessionTOCMMC; SelectSpeed = SpeedSelectSCSIMMC; ReadTocText = ReadTocTextSCSIMMC; doReadToc = ReadTocMMC; ReadSubChannels = ReadSubChannelsFallbackMMC; if (!memcmp(p+8,"SONY CD-RW CRX100E 1.0", 27)) ReadTocText = NULL; if (!global.quiet) fprintf(stderr, "MMC+CDDA\n"); break; case -1: /* "MMC drive does not support cdda reading, sorry\n." */ doReadToc = ReadTocMMC; if (!global.quiet) fprintf(stderr, "MMC-CDDA\n"); /* FALLTHROUGH */ case 0: /* non SCSI-3 cdrom drive */ if (!global.quiet) fprintf(stderr, "no MMC\n"); ReadLastAudio = NULL; if (!memcmp(p+8,"TOSHIBA", 7) || !memcmp(p+8,"IBM", 3) || !memcmp(p+8,"DEC", 3)) { /* * older Toshiba ATAPI drives don't identify themselves as MMC. * The last digit of the model number is '2' for ATAPI drives. * These are treated as MMC. */ if (!memcmp(p+15, " CD-ROM XM-", 11) && p[29] == '2') { goto lost_toshibas; } density = 0x82; EnableCdda = EnableCddaModeSelect; ReadSubChannels = ReadStandardSub; ReadCdRom = ReadStandard; SelectSpeed = SpeedSelectSCSIToshiba; if (!memcmp(p+15, " CD-ROM XM-3401",15)) { Is_a_Toshiba3401 = 1; } global.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 */ global.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; global.in_lendian = 1; } else if (!memcmp(p+8,"PLEXTOR",7)) { global.in_lendian = 1; global.overlap = 0; ReadLastAudio = ReadFirstSessionTOCSony; ReadTocText = ReadTocTextSCSIMMC; doReadToc = ReadTocSony; ReadSubChannels = ReadSubChannelsSony; } else if (!memcmp(p+8,"SONY",4)) { global.in_lendian = 1; if (!memcmp(p+16, "CD-ROM CDU55E",13)) { ReadCdRom = ReadCddaMMC12; } ReadLastAudio = ReadFirstSessionTOCSony; ReadTocText = ReadTocTextSCSIMMC; doReadToc = ReadTocSony; ReadSubChannels = ReadSubChannelsSony; } else if (!memcmp(p+8,"NEC",3)) { ReadCdRom = ReadCdda10; ReadTocText = NULL; SelectSpeed = SpeedSelectSCSINEC; global.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; global.in_lendian = 1; } } /* switch (get_mmc) */ } /* look if caddy is loaded */ if (interface == GENERIC_SCSI) { usalp->silent++; while (!wait_unit_ready(usalp, 60)) { fprintf(stderr,"load cdrom please and press enter"); getchar(); } usalp->silent--; } } /* Check to see if the device will support SCSI generic commands. A * better check than simply looking at the device name. Open the * device, issue an inquiry. If they both succeed, there's a good * chance that the device works... */ #if defined(__linux__) static int check_linux_scsi_interface(char *pdev_name) { SCSI *dev = NULL; unsigned char *p = NULL; char errstr[80]; dev = usal_open(pdev_name, errstr, sizeof(errstr), 0, 0); if (NULL == dev) return EINVAL; p = Inquiry(dev); if (p) { usal_close(dev); return 0; } usal_close(dev); return EINVAL; } #endif /********************** 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(struct stat *statstruct, char *pdev_name) { #if defined(__linux__) int is_scsi = 1; #endif #ifndef STAT_MACROS_BROKEN if (!S_ISCHR(statstruct->st_mode) && !S_ISBLK(statstruct->st_mode)) { fprintf(stderr, "%s is not a device\n",pdev_name); exit(SYNTAX_ERROR); } #endif /* Check what type of device we have */ #if defined (__linux__) if (check_linux_scsi_interface(pdev_name)) is_scsi = 0; if (interface == GENERIC_SCSI && !is_scsi) { fprintf(stderr, "device %s does not support generic_scsi; falling back to cooked_ioctl instead\n", pdev_name); interface = COOKED_IOCTL; } if ((interface == COOKED_IOCTL) && is_scsi && (SCSI_GENERIC_MAJOR == major(statstruct->st_rdev))) { fprintf(stderr, "device %s is generic_scsi NOT cooked_ioctl\n", pdev_name); interface = GENERIC_SCSI; } #else #if defined (HAVE_ST_RDEV) switch (major(statstruct->st_rdev)) { #if defined (__linux__) case SCSI_GENERIC_MAJOR: /* generic */ #else default: /* ??? what is the proper value here */ #endif #ifndef STAT_MACROS_BROKEN #if defined (__linux__) if (!S_ISCHR(statstruct->st_mode)) { fprintf(stderr, "%s is not a char device\n",pdev_name); exit(SYNTAX_ERROR); } 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 #else default: /* ??? what is the proper value here */ #endif break; #if defined (__linux__) || defined (__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) #if defined (__linux__) case SCSI_CDROM_MAJOR: /* scsi cd */ default: /* for example ATAPI cds */ #else #if defined (__FreeBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__) #if __FreeBSD_version >= 600021 case 0: /* majors abandoned */ /* FALLTHROUGH */ #endif #if __FreeBSD_version >= 501113 case 4: /* GEOM */ /* FALLTHROUGH */ #endif case 117: /* pre-GEOM atapi cd */ if (!S_ISCHR(statstruct->st_mode)) { fprintf(stderr, "%s is not a char device\n",pdev_name); exit(SYNTAX_ERROR); } 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 #endif if (!S_ISBLK(statstruct->st_mode)) { fprintf(stderr, "%s is not a block device\n",pdev_name); exit(SYNTAX_ERROR); } #if defined (__linux__) #if LINUX_VERSION_CODE >= 0x20600 /* In Linux kernel 2.6 it is better to use the SCSI interface * with the device. */ break; #endif #endif 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; } if (interface == COOKED_IOCTL) { fprintf(stderr, "\nW: The cooked_ioctl interface is functionally very limited!!\n"); #if defined (__linux__) fprintf(stderr, "\nW: For good sampling quality simply use the generic SCSI interface!\n" "For example dev=ATA:1,0,0\n"); #endif } break; #endif } #endif #endif if (global.overlap >= global.nsectors) global.overlap = global.nsectors-1; } /* open the cdrom device */ static int OpenCdRom(char *pdev_name) { int retval = 0; struct stat fstatstruct; /* The device (given by pdevname) can be: a. an SCSI device specified with a /dev/xxx name, b. an SCSI device specified with bus,target,lun numbers, c. a non-SCSI device such as ATAPI or proprietary CDROM devices. */ #ifdef HAVE_IOCTL_INTERFACE struct stat statstruct; int have_named_device = 0; have_named_device = FALSE; if (pdev_name) { have_named_device = strchr(pdev_name, ':') == NULL && memcmp(pdev_name, "/dev/", 5) == 0; } if (have_named_device) { if (stat(pdev_name, &statstruct)) { fprintf(stderr, "cannot stat device %s\n", pdev_name); exit(STAT_ERROR); } else { Check_interface_for_device( &statstruct, pdev_name ); } } #endif if (interface == GENERIC_SCSI) { char errstr[80]; priv_on(); needroot(0); needgroup(0); /* * Call usal_remote() to force loading the remote SCSI transport library * code that is located in librusal instead of the dummy remote routines * that are located inside libusal. */ usal_remote(); if (pdev_name != NULL && ((strncmp(pdev_name, "HELP", 4) == 0) || (strncmp(pdev_name, "help", 4) == 0))) { usal_help(stderr); exit(NO_ERROR); } if (global.scandevs) { list_devices(usalp, stdout, 0); exit(0); } /* device name, debug, verboseopen */ usalp = usal_open(pdev_name, errstr, sizeof(errstr), 0, 0); if (usalp == NULL) { int err = geterrno(); errmsgno(err, "%s%sCannot open SCSI driver.\n", errstr, errstr[0]?". ":""); errmsgno(EX_BAD, "For possible targets try 'wodim -scanbus'.%s\n", geteuid() ? " Make sure you are root.":""); priv_off(); dontneedgroup(); dontneedroot(); #if defined(sun) || defined(__sun) fprintf(stderr, "On SunOS/Solaris make sure you have Joerg Schillings usal SCSI driver installed.\n"); #endif #if defined (__linux__) fprintf(stderr, "Use the script scan_scsi.linux to find out more.\n"); #endif fprintf(stderr, "Probably you did not define your SCSI device.\n"); fprintf(stderr, "Set the CDDA_DEVICE environment variable or use the -D option.\n"); fprintf(stderr, "You can also define the default device in the Makefile.\n"); fprintf(stderr, "For possible transport specifiers try 'wodim dev=help'.\n"); exit(SYNTAX_ERROR); } usal_settimeout(usalp, 300); usal_settimeout(usalp, 60); usalp->silent = global.scsi_silent; usalp->verbose = global.scsi_verbose; if (global.nsectors > (unsigned) usal_bufsize(usalp, 3*1024*1024)/CD_FRAMESIZE_RAW) global.nsectors = usal_bufsize(usalp, 3*1024*1024)/CD_FRAMESIZE_RAW; if (global.overlap >= global.nsectors) global.overlap = global.nsectors-1; /* * Newer versions of Linux seem to introduce an incompatible change * and require root privileges or limit RLIMIT_MEMLOCK infinity * in order to get a SCSI buffer in case we did call mlockall(MCL_FUTURE). */ init_scsibuf(usalp, global.nsectors*CD_FRAMESIZE_RAW); priv_off(); dontneedgroup(); dontneedroot(); if (global.scanbus) { select_target(usalp, stdout); exit(0); } } else { needgroup(0); retval = open(pdev_name,O_RDONLY #ifdef linux | O_NONBLOCK #endif ); dontneedgroup(); if (retval < 0) { fprintf(stderr, "while opening %s :", pdev_name); perror(""); exit(DEVICEOPEN_ERROR); } /* Do final security checks here */ if (fstat(retval, &fstatstruct)) { fprintf(stderr, "Could not fstat %s (fd %d): ", pdev_name, retval); perror(""); exit(STAT_ERROR); } Check_interface_for_device( &fstatstruct, pdev_name ); #if defined HAVE_IOCTL_INTERFACE /* Watch for race conditions */ if (have_named_device && (fstatstruct.st_dev != statstruct.st_dev || fstatstruct.st_ino != statstruct.st_ino)) { fprintf(stderr,"Race condition attempted in OpenCdRom. Exiting now.\n"); exit(RACE_ERROR); } #endif /* * The structure looks like a desaster :-( * We do this more than once as it is impossible to understand where * the right place would be to do this.... */ if (usalp != NULL) { usalp->verbose = global.scsi_verbose; } } return retval; } #endif /* SIM_CD */ /******************* Simulation interface *****************/ #if defined SIM_CD #include "toc.h" static unsigned long sim_pos=0; /* read 'SectorBurst' adjacent sectors of audio sectors * to Buffer '*p' beginning at sector 'lSector' */ static int ReadCdRom_sim(SCSI *x, UINT4 *p, unsigned lSector, unsigned SectorBurstVal); static int ReadCdRom_sim(SCSI *x, UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { unsigned int loop=0; Int16_t *q = (Int16_t *) p; int joffset = 0; if (lSector > g_toc[cdtracks].dwStartSector || lSector + SectorBurstVal > g_toc[cdtracks].dwStartSector + 1) { fprintf(stderr, "Read request out of bounds: %u - %u (%d - %d allowed)\n", lSector, lSector + SectorBurstVal, 0, g_toc[cdtracks].dwStartSector); } #if 0 /* jitter with a probability of jprob */ if (random() <= jprob) { /* jitter up to jmax samples */ joffset = random(); } #endif #ifdef DEBUG_SHM fprintf(stderr, ", last_b = %p\n", *last_buffer); #endif for (loop = lSector*CD_FRAMESAMPLES + joffset; loop < (lSector+SectorBurstVal)*CD_FRAMESAMPLES + joffset; loop++) { *q++ = loop; *q++ = ~loop; } #ifdef DEBUG_SHM fprintf(stderr, "sim wrote from %p upto %p - 4 (%d), last_b = %p\n", p, q, SectorBurstVal*CD_FRAMESAMPLES, *last_buffer); #endif sim_pos = (lSector+SectorBurstVal)*CD_FRAMESAMPLES + joffset; return SectorBurstVal; } static int Play_at_sim(SCSI *x, unsigned int from_sector, unsigned int sectors); static int Play_at_sim(SCSI *x, unsigned int from_sector, unsigned int sectors) { sim_pos = from_sector*CD_FRAMESAMPLES; return 0; } static unsigned sim_indices; /* read the table of contents (toc) via the ioctl interface */ static unsigned ReadToc_sim(SCSI *x, TOC *toc); static unsigned ReadToc_sim(SCSI *x, TOC *toc) { unsigned int scenario; int scen[12][3] = { {1,1,500}, {1,2,500}, {1,99,150*99}, {2,1,500}, {2,2,500}, {2,99,150*99}, {2,1,500}, {5,2,500}, {5,99,150*99}, {99,1,1000}, {99,2,1000}, {99,99,150*99}, }; unsigned int i; unsigned trcks; #if 0 fprintf(stderr, "select one of the following TOCs\n" "0 : 1 track with 1 index\n" "1 : 1 track with 2 indices\n" "2 : 1 track with 99 indices\n" "3 : 2 tracks with 1 index each\n" "4 : 2 tracks with 2 indices each\n" "5 : 2 tracks with 99 indices each\n" "6 : 2 tracks (data and audio) with 1 index each\n" "7 : 5 tracks with 2 indices each\n" "8 : 5 tracks with 99 indices each\n" "9 : 99 tracks with 1 index each\n" "10: 99 tracks with 2 indices each\n" "11: 99 tracks with 99 indices each\n" ); do { scanf("%u", &scenario); } while (scenario > sizeof(scen)/2/sizeof(int)); #else scenario = 6; #endif /* build table of contents */ #if 0 trcks = scen[scenario][0] + 1; sim_indices = scen[scenario][1]; for (i = 0; i < trcks; i++) { toc[i].bFlags = (scenario == 6 && i == 0) ? 0x40 : 0xb1; toc[i].bTrack = i + 1; toc[i].dwStartSector = i * scen[scenario][2]; toc[i].mins = (toc[i].dwStartSector+150) / (60*75); toc[i].secs = (toc[i].dwStartSector+150 / 75) % (60); toc[i].frms = (toc[i].dwStartSector+150) % (75); } toc[i].bTrack = 0xaa; toc[i].dwStartSector = i * scen[scenario][2]; toc[i].mins = (toc[i].dwStartSector+150) / (60*75); toc[i].secs = (toc[i].dwStartSector+150 / 75) % (60); toc[i].frms = (toc[i].dwStartSector+150) % (75); #else { int starts[15] = { 23625, 30115, 39050, 51777, 67507, 88612, 112962, 116840, 143387, 162662, 173990, 186427, 188077, 209757, 257120}; trcks = 14 + 1; sim_indices = 1; for (i = 0; i < trcks; i++) { toc[i].bFlags = 0x0; toc[i].bTrack = i + 1; toc[i].dwStartSector = starts[i]; toc[i].mins = (starts[i]+150) / (60*75); toc[i].secs = (starts[i]+150 / 75) % (60); toc[i].frms = (starts[i]+150) % (75); } toc[i].bTrack = 0xaa; toc[i].dwStartSector = starts[i]; toc[i].mins = (starts[i]) / (60*75); toc[i].secs = (starts[i] / 75) % (60); toc[i].frms = (starts[i]) % (75); } #endif return --trcks; /* without lead-out */ } static subq_chnl *ReadSubQ_sim(SCSI *usalp, unsigned char sq_format, unsigned char track); /* request sub-q-channel information. This function may cause confusion * for a drive, when called in the sampling process. */ static subq_chnl *ReadSubQ_sim(SCSI *usalp, unsigned char sq_format, unsigned char track) { subq_chnl *SQp = (subq_chnl *) (SubQbuffer); subq_position *SQPp = (subq_position *) &SQp->data; unsigned long sim_pos1; unsigned long sim_pos2; if ( sq_format != GET_POSITIONDATA ) return NULL; /* not supported by sim */ /* simulate CDROMSUBCHNL ioctl */ /* copy to SubQbuffer */ SQp->audio_status = 0; SQp->format = 0xff; SQp->control_adr = 0xff; sim_pos1 = sim_pos/CD_FRAMESAMPLES; sim_pos2 = sim_pos1 % 150; SQp->track = (sim_pos1 / 5000) + 1; SQp->index = ((sim_pos1 / 150) % sim_indices) + 1; sim_pos1 += 150; SQPp->abs_min = sim_pos1 / (75*60); SQPp->abs_sec = (sim_pos1 / 75) % 60; SQPp->abs_frame = sim_pos1 % 75; SQPp->trel_min = sim_pos2 / (75*60); SQPp->trel_sec = (sim_pos2 / 75) % 60; SQPp->trel_frame = sim_pos2 % 75; return (subq_chnl *)(SubQbuffer); } static void SelectSpeed_sim(SCSI *x, unsigned sp); /* ARGSUSED */ static void SelectSpeed_sim(SCSI *x, unsigned sp) { } static void trash_cache_sim(UINT4 *p, unsigned lSector, unsigned SectorBurstVal); /* ARGSUSED */ static void trash_cache_sim(UINT4 *p, unsigned lSector, unsigned SectorBurstVal) { } static void SetupSimCd(void); static void SetupSimCd() { EnableCdda = (void (*)(SCSI *, int, unsigned))Dummy; ReadCdRom = ReadCdRom_sim; ReadCdRomData = (int (*)(SCSI *, unsigned char *, unsigned, unsigned))ReadCdRom_sim; doReadToc = ReadToc_sim; ReadTocText = NULL; ReadSubQ = ReadSubQ_sim; ReadSubChannels = NULL; ReadLastAudio = NULL; SelectSpeed = SelectSpeed_sim; Play_at = Play_at_sim; StopPlay = (int (*)(SCSI *))Dummy; trash_cache = trash_cache_sim; } #endif /* def SIM_CD */ /* perform initialization depending on the interface used. */ void SetupInterface() { #if defined SIM_CD fprintf( stderr, "SIMULATION MODE !!!!!!!!!!!\n"); #else /* ensure interface is setup correctly */ global.cooked_fd = OpenCdRom ( global.dev_name ); #endif global.pagesize = getpagesize(); /* request one sector for table of contents */ bufferTOC = malloc( CD_FRAMESIZE_RAW + 96 ); /* assumes sufficient aligned addresses */ /* SubQchannel buffer */ SubQbuffer = malloc( 48 ); /* assumes sufficient aligned addresses */ cmd = malloc( 18 ); /* assumes sufficient aligned addresses */ if ( !bufferTOC || !SubQbuffer || !cmd ) { fprintf( stderr, "Too low on memory. Giving up.\n"); exit(NOMEM_ERROR); } #if defined SIM_CD usalp = malloc(sizeof(* usalp)); if (usalp == NULL) { FatalError("No memory for SCSI structure.\n"); } usalp->silent = 0; SetupSimCd(); #else /* if drive is of type scsi, get vendor name */ if (interface == GENERIC_SCSI) { unsigned sector_size; SetupSCSI(); sector_size = get_orig_sectorsize(usalp, &orgmode4, &orgmode10, &orgmode11); if (!SCSI_emulated_ATAPI_on(usalp)) { if ( sector_size != 2048 && set_sectorsize(usalp, 2048) ) { fprintf( stderr, "Could not change sector size from %d to 2048\n", sector_size ); } } else { sector_size = 2048; } /* get cache setting */ /* set cache to zero */ } else { #if defined (HAVE_IOCTL_INTERFACE) usalp = malloc(sizeof(* usalp)); if (usalp == NULL) { FatalError("No memory for SCSI structure.\n"); } usalp->silent = 0; SetupCookedIoctl( global.dev_name ); #else FatalError("Sorry, there is no known method to access the device.\n"); #endif } #endif /* if def SIM_CD */ /* * The structure looks like a desaster :-( * We do this more than once as it is impossible to understand where * the right place would be to do this.... */ if (usalp != NULL) { usalp->verbose = global.scsi_verbose; } } #ifdef HAVE_PRIV_H #include #endif void priv_init() { #ifdef HAVE_PRIV_SET /* * Give up privs we do not need anymore. * We no longer need: * file_dac_read,sys_devices,proc_priocntl,net_privaddr */ priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL, PRIV_NET_PRIVADDR, NULL); priv_set(PRIV_OFF, PRIV_INHERITABLE, PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL, PRIV_NET_PRIVADDR, PRIV_SYS_DEVICES, NULL); #endif } void priv_on() { #ifdef HAVE_PRIV_SET /* * Get back privs we may need now. * We need: * file_dac_read,sys_devices,proc_priocntl,net_privaddr */ priv_set(PRIV_ON, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL, PRIV_NET_PRIVADDR, NULL); #endif } void priv_off() { #ifdef HAVE_PRIV_SET /* * Give up privs we do not need anymore. * We no longer need: * file_dac_read,sys_devices,proc_priocntl,net_privaddr */ priv_set(PRIV_OFF, PRIV_EFFECTIVE, PRIV_FILE_DAC_READ, PRIV_PROC_PRIOCNTL, PRIV_NET_PRIVADDR, NULL); #endif }