📄 ioctl.c
字号:
/* @(#)ioctl.c 1.4 00/01/25 Copyright 1998,1999 Heiko Eissfeldt */#ifndef lintstatic char sccsid[] ="@(#)ioctl.c 1.4 00/01/25 Copyright 1998,1999 Heiko Eissfeldt";#endif/*** * CopyPolicy: GNU Public License 2 applies * Copyright (C) 1999 Heiko Eissfeldt heiko@colossus.escape.de * * Ioctl interface module for cdrom drive access * * Solaris ATAPI cdrom drives are untested! * */#include "config.h"#include <stdio.h>#include <standard.h>#include <stdlib.h>#if defined (HAVE_UNISTD_H) && (HAVE_UNISTD_H == 1)#include <sys/types.h>#include <unistd.h>#endif#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 <scg/scsitransp.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 "mytype.h"#include "byteorder.h"#include "interface.h"#include "toc.h"#include "cdda2wav.h"#include "ioctl.h"#include "global.h"#include <utypes.h>#include <cdrecord.h>#if defined (HAVE_IOCTL_INTERFACE)#if !defined sun && !defined __sunstatic struct cdrom_read_audio arg;#endifstatic struct cdrom_tochdr hdr;static struct cdrom_tocentry entry[100];static int err;static void EnableCdda_cooked __PR((SCSI *scgp, int fAudioMode));static void EnableCdda_cooked (scgp, fAudioMode) SCSI *scgp; int fAudioMode;{#if defined CDIOCSETCDDA ioctl(global.cooked_fd, CDIOCSETCDDA, &fAudioMode);#else PRETEND_TO_USE(fAudioMode);#endif PRETEND_TO_USE(scgp);}static unsigned ReadToc_cooked __PR(( SCSI *x, TOC *toc ));/* read the table of contents (toc) via the ioctl interface */static unsigned ReadToc_cooked ( x, toc ) SCSI *x; TOC *toc;{ unsigned i; unsigned tracks; PRETEND_TO_USE(x); /* get TocHeader to find out how many entries there are */ err = ioctl( global.cooked_fd, CDROMREADTOCHDR, &hdr ); if ( err != 0 ) { /* error handling */ if (err == -1) { if (errno == EPERM) fprintf( stderr, "Please run this program setuid root.\n"); perror("cooked: Read TOC "); exit( err ); } else { fprintf( stderr, "can't get TocHeader (error %d).\n", err ); exit( -1 ); } } /* get all TocEntries */ for ( i = 0; i < hdr.cdth_trk1; i++ ) { entry[i].cdte_track = 1+i; entry[i].cdte_format = CDROM_MSF; err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entry[i] ); if ( err != 0 ) { /* error handling */ fprintf( stderr, "can't get TocEntry #%d (error %d).\n", i+1, err ); exit( -1 ); } } entry[i].cdte_track = CDROM_LEADOUT; entry[i].cdte_format = CDROM_MSF; err = ioctl( global.cooked_fd, CDROMREADTOCENTRY, &entry[i] ); if ( err != 0 ) { /* error handling */ fprintf( stderr, "can't get TocEntry LEADOUT (error %d).\n", err ); exit( -1 ); } tracks = hdr.cdth_trk1+1; for (i = 0; i < tracks; i++) { toc[i].bFlags = (entry[i].cdte_adr << 4) | (entry[i].cdte_ctrl & 0x0f); toc[i].bTrack = entry[i].cdte_track; toc[i].dwStartSector = -150 + 75*60*entry[i].cdte_addr.msf.minute+ 75* entry[i].cdte_addr.msf.second+ entry[i].cdte_addr.msf.frame; } bufferTOC[0] = '\0'; bufferTOC[1] = '\0'; return --tracks; /* without lead-out */}static void trash_cache_cooked __PR((UINT4 *p, unsigned lSector, unsigned SectorBurstVal));static void trash_cache_cooked(p, lSector, SectorBurstVal) UINT4 *p; unsigned lSector; unsigned SectorBurstVal;{ /* trash the cache */#if defined __FreeBSD__ static struct cdrom_read_audio arg2; arg2.address.lba = find_an_off_sector(lSector, SectorBurstVal); arg2.addr_format = CDROM_LBA; arg2.nframes = 3; arg2.buffer = (unsigned char *) &p[0]; ioctl(global.cooked_fd, CDROMREADAUDIO, &arg2);#endif#if defined __linux__ static struct cdrom_read_audio arg2; arg2.addr.lba = find_an_off_sector(lSector, SectorBurstVal); arg2.addr_format = CDROM_LBA; arg2.nframes = 3; arg2.buf = (unsigned char *) &p[0]; ioctl(global.cooked_fd, CDROMREADAUDIO, &arg2);#endif#if defined __sun struct cdrom_cdda suncdda; suncdda.cdda_addr = lSector; suncdda.cdda_length = SectorBurstVal*CD_FRAMESIZE_RAW; suncdda.cdda_data = (char *) &p[0]; suncdda.cdda_subcode = CDROM_DA_NO_SUBCODE; ioctl(global.cooked_fd, CDROMCDDA, &suncdda);#endif}static void ReadCdRomData_cooked __PR(( SCSI *x, UINT4 *p, unsigned lSector, unsigned SectorBurstVal));/* read 'SectorBurst' adjacent sectors of data sectors * to Buffer '*p' beginning at sector 'lSector' */static void ReadCdRomData_cooked (x, p, lSector, SectorBurstVal ) SCSI *x; UINT4 *p; unsigned lSector; unsigned SectorBurstVal;{ int retval; if ((retval = lseek(global.cooked_fd, lSector*CD_FRAMESIZE, SEEK_SET)) != lSector*CD_FRAMESIZE) { perror("cannot seek sector"); } if ((retval = read(global.cooked_fd, p, SectorBurstVal*CD_FRAMESIZE)) != SectorBurstVal*CD_FRAMESIZE) { perror("cannot read sector"); } PRETEND_TO_USE(x); return;}static void ReadCdRom_cooked __PR(( SCSI *x, UINT4 *p, unsigned lSector, unsigned SectorBurstVal));/* read 'SectorBurst' adjacent sectors of audio sectors * to Buffer '*p' beginning at sector 'lSector' */static void ReadCdRom_cooked (x, p, lSector, SectorBurstVal ) SCSI *x; UINT4 *p; unsigned lSector; unsigned SectorBurstVal;{ int retry_count=0; static int nothing_read = 1;/* read 2352 bytes audio data */#if defined __FreeBSD__ arg.address.lba = lSector; arg.addr_format = CDROM_LBA; arg.nframes = SectorBurstVal; arg.buffer = (unsigned char *) &p[0]; do { err = ioctl(global.cooked_fd, CDROMREADAUDIO, &arg);#endif#if defined __linux__ arg.addr.lba = lSector; arg.addr_format = CDROM_LBA; arg.nframes = SectorBurstVal; arg.buf = (unsigned char *) &p[0]; do { err = ioctl(global.cooked_fd, CDROMREADAUDIO, &arg);#endif#if defined sun || defined __sun struct cdrom_cdda suncdda; suncdda.cdda_addr = lSector; suncdda.cdda_length = SectorBurstVal*CD_FRAMESIZE_RAW; suncdda.cdda_data = (char *) &p[0]; suncdda.cdda_subcode = CDROM_DA_NO_SUBCODE; do { err = ioctl(global.cooked_fd, CDROMCDDA, &suncdda);#endif retry_count++; if (err) { trash_cache_cooked(p, lSector, SectorBurstVal); } } while ((err) && (retry_count < 30)); if (err != 0) { /* error handling */ if (err == -1) { if (nothing_read && (errno == EINVAL || errno == EIO)) fprintf( stderr, "Sorry, this driver and/or drive does not support cdda reading.\n"); perror("cooked: Read cdda "); fprintf(stderr, " sector %u + %u, buffer %p + %x\n", lSector, SectorBurstVal, p, global.shmsize); } else { fprintf(stderr, "can't read frame #%u (error %d).\n", lSector, err); } } else { nothing_read = 0; } PRETEND_TO_USE(x);}static int StopPlay_cooked __PR(( SCSI *x));static int StopPlay_cooked( x ) SCSI *x;{ PRETEND_TO_USE(x); return ioctl( global.cooked_fd, CDROMSTOP, 0 ) ? 0 : -1; }static int Play_at_cooked __PR(( SCSI *x, unsigned int from_sector, unsigned int sectors));static int Play_at_cooked( x, from_sector, sectors) SCSI *x; unsigned int from_sector; unsigned int sectors;{ struct cdrom_msf cmsf; PRETEND_TO_USE(x); cmsf.cdmsf_min0 = (from_sector + 150) / (60*75); cmsf.cdmsf_sec0 = ((from_sector + 150) / 75) % 60; cmsf.cdmsf_frame0 = (from_sector + 150) % 75; cmsf.cdmsf_min1 = (from_sector + 150 + sectors) / (60*75); cmsf.cdmsf_sec1 = ((from_sector + 150 + sectors) / 75) % 60; cmsf.cdmsf_frame1 = (from_sector + 150 + sectors) % 75; ioctl( global.cooked_fd, CDROMSTART, 0 ); return ioctl( global.cooked_fd, CDROMPLAYMSF, &cmsf ) ? 0 : -1; }#if defined PROTOTYPESstatic subq_chnl *ReadSubQ_cooked __PR(( SCSI *x, unsigned char sq_format, unsigned char track ))#else/* request sub-q-channel information. This function may cause confusion * for a drive, when called in the sampling process. */static subq_chnl *ReadSubQ_cooked ( x, sq_format, track ) SCSI *x; unsigned char sq_format; unsigned char track;#endif{ struct cdrom_subchnl sub_ch;#if defined __FreeBSD__ struct cd_sub_channel_info sub_ch_info; PRETEND_TO_USE(x); sub_ch.address_format = CD_MSF_FORMAT; sub_ch.track = track; sub_ch.data_len = sizeof(struct cd_sub_channel_info); sub_ch.data = &sub_ch_info; switch (sq_format) { case GET_CATALOGNUMBER: sub_ch.data_format = CD_MEDIA_CATALOG;#else PRETEND_TO_USE(x); switch (sq_format) { case GET_CATALOGNUMBER:#endif#if defined CDROM_GET_MCN if (!(err = ioctl(global.cooked_fd, CDROM_GET_MCN, (struct cdrom_mcn *) SubQbuffer))) { subq_chnl *SQp = (subq_chnl *) SubQbuffer; subq_catalog *SQPp = (subq_catalog *) &SQp->data; movebytes(SQp, SQPp->media_catalog_number, sizeof (SQPp->media_catalog_number)); SQPp->zero = 0; SQPp->mc_valid = 0x80; break; } else#endif { return NULL; } case GET_POSITIONDATA:#if defined __FreeBSD__ sub_ch.data_format = CD_CURRENT_POSITION;#endif if (!(err = ioctl(global.cooked_fd, CDROMSUBCHNL, &sub_ch))) { /* copy to SubQbuffer */ subq_chnl *SQp = (subq_chnl *) (SubQbuffer); subq_position *SQPp = (subq_position *) SQp->data; SQp->audio_status = sub_ch.cdsc_audiostatus; SQp->format = sub_ch.cdsc_format; SQp->control_adr = (sub_ch.cdsc_adr << 4) | (sub_ch.cdsc_ctrl & 0x0f); SQp->track = sub_ch.cdsc_trk; SQp->index = sub_ch.cdsc_ind; SQPp->abs_min = sub_ch.cdsc_absaddr.msf.minute; SQPp->abs_sec = sub_ch.cdsc_absaddr.msf.second; SQPp->abs_frame = sub_ch.cdsc_absaddr.msf.frame; SQPp->trel_min = sub_ch.cdsc_reladdr.msf.minute; SQPp->trel_sec = sub_ch.cdsc_reladdr.msf.second; SQPp->trel_frame = sub_ch.cdsc_reladdr.msf.frame; } else { if (err == -1) { if (errno == EPERM) fprintf( stderr, "Please run this program setuid root.\n"); perror("cooked: Read subq "); exit( err ); } else { fprintf(stderr, "can't read sub q channel (error %d).\n", err); exit( -1 ); } } break; default: return NULL; } /* switch */ return (subq_chnl *)(SubQbuffer);}/* Speed control */static void SpeedSelect_cooked __PR(( SCSI *x, unsigned speed));static void SpeedSelect_cooked( x, speed ) SCSI *x; unsigned speed;{ PRETEND_TO_USE(x);#ifdef CDROM_SELECT_SPEED /* CAUTION!!!!! Non standard ioctl parameter types here!!!! */ if (!(err = ioctl(global.cooked_fd, CDROM_SELECT_SPEED, speed))) { } else { if (err == -1) { if (errno == EPERM) fprintf( stderr, "Please run this program setuid root.\n"); perror("cooked: Speed select "); /*exit( err ); */ } else { fprintf(stderr, "can't set speed %d (error %d).\n", speed, err); exit( -1 ); } }#else PRETEND_TO_USE(speed);#endif}/* set function pointers to use the ioctl routines */void SetupCookedIoctl( pdev_name ) char *pdev_name;{#if (HAVE_ST_RDEV == 1) struct stat statstruct; if (fstat(global.cooked_fd, &statstruct)) { fprintf(stderr, "cannot stat cd %d (%s)\n",global.cooked_fd, pdev_name); exit(1); }#if defined __linux__ switch ((int)(statstruct.st_rdev >> 8L)) { case CDU31A_CDROM_MAJOR: /* sony cdu-31a/33a */ global.nsectors = 13; if (global.nsectors >= 14) { global.overlap = 10; } break; case MATSUSHITA_CDROM_MAJOR: /* sbpcd 1 */ case MATSUSHITA_CDROM2_MAJOR: /* sbpcd 2 */ case MATSUSHITA_CDROM3_MAJOR: /* sbpcd 3 */ case MATSUSHITA_CDROM4_MAJOR: /* sbpcd 4 */ /* some are more compatible than others */ global.nsectors = 13; break; default: } err = ioctl(global.cooked_fd, CDROMAUDIOBUFSIZ, global.nsectors); switch ((int)(statstruct.st_rdev >> 8L)) { case MATSUSHITA_CDROM_MAJOR: /* sbpcd 1 */ case MATSUSHITA_CDROM2_MAJOR: /* sbpcd 2 */ case MATSUSHITA_CDROM3_MAJOR: /* sbpcd 3 */ case MATSUSHITA_CDROM4_MAJOR: /* sbpcd 4 */ if (err == -1) { perror("ioctl(CDROMAUDIOBUFSIZ)"); } }#endif#endif EnableCdda = EnableCdda_cooked; ReadCdRom = ReadCdRom_cooked; ReadCdRomData = (void (*) __PR((SCSI *, unsigned char *, unsigned, unsigned ))) ReadCdRomData_cooked; ReadToc = ReadToc_cooked; ReadTocText = NULL; ReadSubQ = ReadSubQ_cooked; SelectSpeed = SpeedSelect_cooked; Play_at = Play_at_cooked; StopPlay = StopPlay_cooked; trash_cache = trash_cache_cooked; ReadLastAudio = NULL;}#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -