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

📄 mcdx.c

📁 还有没有人研究过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? * *  9 November 1999 -- Make kernel-parameter implementation work with 2.3.x  *	               Removed init_module & cleanup_module in favor of  *		       module_init & module_exit. *		       Torben Mathiasen <tmm@image.dk> */#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/slab.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>#include <linux/devfs_fs_kernel.h>/* for compatible parameter passing with "insmod" */#define	mcdx_drive_map mcdx#include "mcdx.h"#if BITS_PER_LONG != 32#  error FIXME: this driver only works on 32-bit platforms#endif#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 */	wait_queue_head_t busyq;	wait_queue_head_t lockq;	wait_queue_head_t 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(request_queue_t * q);struct block_device_operations mcdx_bdops ={	owner:			THIS_MODULE,	open:			cdrom_open,	release:		cdrom_release,	ioctl:			cdrom_ioctl,	check_media_change:	cdrom_media_changed,};/*	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 = {	open:mcdx_open,	release:mcdx_close,	media_changed:mcdx_media_changed,	tray_move:mcdx_tray_move,	lock_door:mcdx_lockdoor,	audio_ioctl:mcdx_audio_ioctl,	capability:CDC_OPEN_TRAY | CDC_LOCK | CDC_MEDIA_CHANGED |	    CDC_PLAY_AUDIO | CDC_DRIVE_STATUS,};static struct cdrom_device_info mcdx_info = {	ops:&mcdx_dops,	speed:2,	capacity:1,	name:"mcdx",};/* 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,			       sub->cdsc_absaddr.msf.frame,			       sub->cdsc_reladdr.msf.minute,			       sub->cdsc_reladdr.msf.second,			       sub->cdsc_reladdr.msf.frame);			return 0;		}	case CDROMREADTOCHDR:{			struct cdrom_tochdr *toc =			    (struct cdrom_tochdr *) arg;			xtrace(IOCTL, "ioctl() READTOCHDR\n");

⌨️ 快捷键说明

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