⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 mcdx.c

📁 powerpc内核 mpc8241芯片 linux系统下cdrom驱动程序
💻 C
📖 第 1 页 / 共 4 页
字号:
/* * The Mitsumi CDROM interface * Copyright (C) 1995 1996 Heiko Schlittermann <heiko@lotte.sax.de> * VERSION: 2.14(hs) * * ... anyway, I'm back again, thanks to Marcin, he adopted * large portions of my code (at least the parts containing * my main thoughts ...) * ****************** H E L P ********************************* * If you ever plan to update your CD ROM drive and perhaps * want to sell or simply give away your Mitsumi FX-001[DS] * -- Please -- * mail me (heiko@lotte.sax.de).  When my last drive goes * ballistic no more driver support will be available from me! ************************************************************* * * 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, 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; see the file COPYING.  If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * Thanks to *  The Linux Community at all and ... *  Martin Harriss (he wrote the first Mitsumi Driver) *  Eberhard Moenkeberg (he gave me much support and the initial kick) *  Bernd Huebner, Ruediger Helsch (Unifix-Software GmbH, they *      improved the original driver) *  Jon Tombs, Bjorn Ekwall (module support) *  Daniel v. Mosnenck (he sent me the Technical and Programming Reference) *  Gerd Knorr (he lent me his PhotoCD) *  Nils Faerber and Roger E. Wolff (extensively tested the LU portion) *  Andreas Kies (testing the mysterious hang-ups) *  Heiko Eissfeldt (VERIFY_READ/WRITE) *  Marcin Dalecki (improved performance, shortened code) *  ... somebody forgotten? * */#if RCSstatic const char *mcdx_c_version		= "$Id: mcdx.c,v 1.21 1997/01/26 07:12:59 davem Exp $";#endif#include <linux/version.h>#include <linux/module.h>#include <linux/errno.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/cdrom.h>#include <linux/ioport.h>#include <linux/mm.h>#include <linux/malloc.h>#include <linux/init.h>#include <asm/io.h>#include <asm/uaccess.h>#include <linux/major.h>#define MAJOR_NR MITSUMI_X_CDROM_MAJOR#include <linux/blk.h>/* for compatible parameter passing with "insmod" */#define	mcdx_drive_map mcdx#include "mcdx.h"#ifndef HZ#error HZ not defined#endif#define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args)#if !MCDX_QUIET#define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args)#else#define xinfo(fmt, args...) { ; }#endif#if MCDX_DEBUG#define xtrace(lvl, fmt, args...) \		{ if (lvl > 0) \			{ printk(KERN_DEBUG MCDX ":: " fmt, ## args); } }#define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmt, ## args)#else#define xtrace(lvl, fmt, args...) { ; }#define xdebug(fmt, args...) { ; }#endif/* CONSTANTS *******************************************************//* Following are the number of sectors we _request_ from the drive   every time an access outside the already requested range is done.   The _direct_ size is the number of sectors we're allowed to skip   directly (performing a read instead of requesting the new sector   needed */const int REQUEST_SIZE = 800;	/* should be less then 255 * 4 */const int DIRECT_SIZE = 400;	/* should be less then REQUEST_SIZE */enum drivemodes { TOC, DATA, RAW, COOKED };enum datamodes { MODE0, MODE1, MODE2 };enum resetmodes { SOFT, HARD };const int SINGLE = 0x01;		/* single speed drive (FX001S, LU) */const int DOUBLE = 0x02;		/* double speed drive (FX001D, ..? */const int DOOR   = 0x04;		/* door locking capability */const int MULTI  = 0x08;		/* multi session capability */const unsigned char READ1X = 0xc0;const unsigned char READ2X = 0xc1;/* DECLARATIONS ****************************************************/struct s_subqcode {	unsigned char control;	unsigned char tno;	unsigned char index;	struct cdrom_msf0 tt;	struct cdrom_msf0 dt;};struct s_diskinfo {	unsigned int n_first;	unsigned int n_last;	struct cdrom_msf0 msf_leadout;	struct cdrom_msf0 msf_first;};struct s_multi {	unsigned char multi;	struct cdrom_msf0 msf_last;};struct s_version {	unsigned char code;	unsigned char ver;};/* Per drive/controller stuff **************************************/struct s_drive_stuff {	/* waitqueues */    struct wait_queue *busyq;    struct wait_queue *lockq;    struct wait_queue *sleepq; 	/* flags */    volatile int introk;	/* status of last irq operation */    volatile int busy;		/* drive performs an operation */    volatile int lock;		/* exclusive usage */	/* cd infos */	struct s_diskinfo di;	struct s_multi multi;	struct s_subqcode* toc;	/* first entry of the toc array */	struct s_subqcode start;    struct s_subqcode stop;	int xa;					/* 1 if xa disk */	int audio;				/* 1 if audio disk */	int audiostatus;	/* `buffer' control */    volatile int valid;			/* pending, ..., values are valid */    volatile int pending;		/* next sector to be read */    volatile int low_border;	/* first sector not to be skipped direct */    volatile int high_border; /* first sector `out of area' */#ifdef AK2    volatile int int_err;#endif /* AK2 */	/* adds and odds */	void* wreg_data;	/* w data */	void* wreg_reset;	/* w hardware reset */	void* wreg_hcon;	/* w hardware conf */	void* wreg_chn;		/* w channel */	void* rreg_data;	/* r data */	void* rreg_status;	/* r status */    int irq;			/* irq used by this drive */    int minor;			/* minor number of this drive */    int present;	    /* drive present and its capabilities */    unsigned char readcmd;	/* read cmd depends on single/double speed */    unsigned char playcmd;  /* play should always be single speed */    unsigned int xxx;      /* set if changed, reset while open */    unsigned int yyy;      /* set if changed, reset by media_changed */    int users;				/* keeps track of open/close */    int lastsector;			/* last block accessible */    int status;				/* last operation's error / status */	int readerrs;			/* # of blocks read w/o error */};/* Prototypes ******************************************************//*	The following prototypes are already declared elsewhere.  They are 	repeated here to show what's going on.  And to sense, if they're	changed elsewhere. *//* declared in blk.h */int mcdx_init(void);void do_mcdx_request(void);/* already declared in init/main */void mcdx_setup(char *, int *);/*	Indirect exported functions. These functions are exported by their	addresses, such as mcdx_open and mcdx_close in the	structure mcdx_dops. *//* ???  exported by the mcdx_sigaction struct */static void mcdx_intr(int, void *, struct pt_regs*);/* exported by file_ops */static int mcdx_open(struct cdrom_device_info * cdi, int purpose);static void mcdx_close(struct cdrom_device_info * cdi);static int mcdx_media_changed(struct cdrom_device_info * cdi, int disc_nr);static int mcdx_tray_move(struct cdrom_device_info * cdi, int position);static int mcdx_lockdoor(struct cdrom_device_info * cdi, int lock);static int mcdx_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,                      void * arg);/* misc internal support functions */static void log2msf(unsigned int, struct cdrom_msf0*);static unsigned int msf2log(const struct cdrom_msf0*);static unsigned int uint2bcd(unsigned int);static unsigned int bcd2uint(unsigned char);static char *port(int*);static int irq(int*);static void mcdx_delay(struct s_drive_stuff*, long jifs);static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);static int mcdx_xfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors);static int mcdx_config(struct s_drive_stuff*, int);static int mcdx_requestversion(struct s_drive_stuff*, struct s_version*, int);static int mcdx_stop(struct s_drive_stuff*, int);static int mcdx_hold(struct s_drive_stuff*, int);static int mcdx_reset(struct s_drive_stuff*, enum resetmodes, int);static int mcdx_setdrivemode(struct s_drive_stuff*, enum drivemodes, int);static int mcdx_setdatamode(struct s_drive_stuff*, enum datamodes, int);static int mcdx_requestsubqcode(struct s_drive_stuff*, struct s_subqcode*, int);static int mcdx_requestmultidiskinfo(struct s_drive_stuff*, struct s_multi*, int);static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int);static int mcdx_getstatus(struct s_drive_stuff*, int);static int mcdx_getval(struct s_drive_stuff*, int to, int delay, char*);static int mcdx_talk(struct s_drive_stuff*,		const unsigned char* cmd, size_t,        void *buffer, size_t size,        unsigned int timeout, int);static int mcdx_readtoc(struct s_drive_stuff*);static int mcdx_playtrk(struct s_drive_stuff*, const struct cdrom_ti*);static int mcdx_playmsf(struct s_drive_stuff*, const struct cdrom_msf*);static int mcdx_setattentuator(struct s_drive_stuff*, struct cdrom_volctrl*, int);/* static variables ************************************************/static int mcdx_blocksizes[MCDX_NDRIVES];static int mcdx_drive_map[][2] = MCDX_DRIVEMAP;static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES];static struct s_drive_stuff* mcdx_irq_map[16] =		{0, 0, 0, 0, 0, 0, 0, 0,		0, 0, 0, 0, 0, 0, 0, 0};MODULE_PARM(mcdx, "1-4i");static struct cdrom_device_ops mcdx_dops = {  mcdx_open,                   /* open */  mcdx_close,                  /* release */  NULL,           /* drive status */  mcdx_media_changed,         /* media changed */  mcdx_tray_move,             /* tray move */  mcdx_lockdoor,              /* lock door */  NULL,                       /* select speed */  NULL,                       /* select disc */  NULL,                       /* get last session */  NULL,                       /* get universal product code */  NULL,                       /* hard reset */  mcdx_audio_ioctl,            /* audio ioctl */  NULL,                  /* device-specific ioctl */  CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED | CDC_PLAY_AUDIO  | CDC_DRIVE_STATUS, /* capability */  0,                            /* number of minor devices */};static struct cdrom_device_info mcdx_info = {  &mcdx_dops,                    /* device operations */  NULL,                         /* link */  NULL,                         /* handle */  0,		                /* dev */  0,                            /* mask */  2,                            /* maximum speed */  1,                            /* number of discs */  0,                            /* options, not owned */  0,                            /* mc_flags, not owned */  0,                            /* use count, not owned */  "mcdx",                         /* name of the device type */};/* KERNEL INTERFACE FUNCTIONS **************************************/static int mcdx_audio_ioctl(struct cdrom_device_info * cdi, unsigned int cmd,                      void * arg){	struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(cdi->dev)];	if (!stuffp->present) return -ENXIO;	if (stuffp->xxx)	{		if(-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1))		{			stuffp->lastsector = -1;		}		else		{			stuffp->lastsector = (CD_FRAMESIZE / 512)					* msf2log(&stuffp->di.msf_leadout) - 1;		}		if (stuffp->toc)		{			kfree(stuffp->toc);			stuffp->toc = NULL;			if (-1 == mcdx_readtoc(stuffp)) return -1;		}		stuffp->xxx=0;	}	switch (cmd) {		case CDROMSTART: {       			     xtrace(IOCTL, "ioctl() START\n");		        /* Spin up the drive.  Don't think we can do this.                 * For now, ignore it.                 */			return 0;		}		case CDROMSTOP: {			xtrace(IOCTL, "ioctl() STOP\n");            stuffp->audiostatus = CDROM_AUDIO_INVALID;			if (-1 == mcdx_stop(stuffp, 1))				return -EIO;			return 0;		}		case CDROMPLAYTRKIND: {			struct cdrom_ti *ti=(struct cdrom_ti *) arg;			xtrace(IOCTL, "ioctl() PLAYTRKIND\n");			if ((ti->cdti_trk0 < stuffp->di.n_first)					|| (ti->cdti_trk0 > stuffp->di.n_last)					|| (ti->cdti_trk1 < stuffp->di.n_first))			return -EINVAL;			if (ti->cdti_trk1 > stuffp->di.n_last)					ti->cdti_trk1 = stuffp->di.n_last;            xtrace(PLAYTRK, "ioctl() track %d to %d\n", ti->cdti_trk0, ti->cdti_trk1);            return mcdx_playtrk(stuffp, ti);        }        case CDROMPLAYMSF: {            struct cdrom_msf *msf=(struct cdrom_msf *) arg;            xtrace(IOCTL, "ioctl() PLAYMSF\n");            if ((stuffp->audiostatus == CDROM_AUDIO_PLAY)                && (-1 == mcdx_hold(stuffp, 1))) return -EIO;            msf->cdmsf_min0 = uint2bcd(msf->cdmsf_min0);            msf->cdmsf_sec0 = uint2bcd(msf->cdmsf_sec0);            msf->cdmsf_frame0 = uint2bcd(msf->cdmsf_frame0);            msf->cdmsf_min1 = uint2bcd(msf->cdmsf_min1);            msf->cdmsf_sec1 = uint2bcd(msf->cdmsf_sec1);            msf->cdmsf_frame1 = uint2bcd(msf->cdmsf_frame1);            stuffp->stop.dt.minute = msf->cdmsf_min1;            stuffp->stop.dt.second = msf->cdmsf_sec1;            stuffp->stop.dt.frame = msf->cdmsf_frame1;            return mcdx_playmsf(stuffp, msf);        }        case CDROMRESUME: {            xtrace(IOCTL, "ioctl() RESUME\n");            return mcdx_playtrk(stuffp, NULL);        }		case CDROMREADTOCENTRY: {			struct cdrom_tocentry *entry=(struct cdrom_tocentry *) arg;			struct s_subqcode *tp = NULL;			xtrace(IOCTL, "ioctl() READTOCENTRY\n");            if (-1 == mcdx_readtoc(stuffp)) return -1;			if (entry->cdte_track == CDROM_LEADOUT)				tp = &stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1];			else if (entry->cdte_track > stuffp->di.n_last					|| entry->cdte_track < stuffp->di.n_first) return -EINVAL;			else tp = &stuffp->toc[entry->cdte_track - stuffp->di.n_first];			if (NULL == tp) 				return -EIO;			entry->cdte_adr = tp->control;			entry->cdte_ctrl = tp->control >> 4;            /* Always return stuff in MSF, and let the Uniform cdrom driver                worry about what the user actually wants */			entry->cdte_addr.msf.minute = bcd2uint(tp->dt.minute);			entry->cdte_addr.msf.second = bcd2uint(tp->dt.second);			entry->cdte_addr.msf.frame = bcd2uint(tp->dt.frame);			return 0;		}		case CDROMSUBCHNL: {			struct cdrom_subchnl *sub= (struct cdrom_subchnl *)arg;			struct s_subqcode q;			xtrace(IOCTL, "ioctl() SUBCHNL\n");			if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) 				return -EIO;            xtrace(SUBCHNL, "audiostatus: %x\n", stuffp->audiostatus);			sub->cdsc_audiostatus = stuffp->audiostatus;			sub->cdsc_adr = q.control;			sub->cdsc_ctrl = q.control >> 4;			sub->cdsc_trk = bcd2uint(q.tno);			sub->cdsc_ind = bcd2uint(q.index);            xtrace(SUBCHNL, "trk %d, ind %d\n",                    sub->cdsc_trk, sub->cdsc_ind);            /* Always return stuff in MSF, and let the Uniform cdrom driver                worry about what the user actually wants */			sub->cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute);			sub->cdsc_absaddr.msf.second = bcd2uint(q.dt.second);			sub->cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame);			sub->cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute);			sub->cdsc_reladdr.msf.second = bcd2uint(q.tt.second);			sub->cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame);			xtrace(SUBCHNL,					"msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n",					sub->cdsc_absaddr.msf.minute, sub->cdsc_absaddr.msf.second,

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -