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

📄 fd1772.c

📁 上传linux-jx2410的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  linux/kernel/arch/arm/drivers/block/fd1772.c *  Based on ataflop.c in the m68k Linux *  Copyright (C) 1993  Greg Harp *  Atari Support by Bjoern Brauel, Roman Hodek *  Archimedes Support by Dave Gilbert (linux@treblig.org) * *  Big cleanup Sep 11..14 1994 Roman Hodek: *   - Driver now works interrupt driven *   - Support for two drives; should work, but I cannot test that :-( *   - Reading is done in whole tracks and buffered to speed up things *   - Disk change detection and drive deselecting after motor-off *     similar to TOS *   - Autodetection of disk format (DD/HD); untested yet, because I *     don't have an HD drive :-( * *  Fixes Nov 13 1994 Martin Schaller: *   - Autodetection works now *   - Support for 5 1/4" disks *   - Removed drive type (unknown on atari) *   - Do seeks with 8 Mhz * *  Changes by Andreas Schwab: *   - After errors in multiple read mode try again reading single sectors *  (Feb 1995): *   - Clean up error handling *   - Set blk_size for proper size checking *   - Initialize track register when testing presence of floppy *   - Implement some ioctl's * *  Changes by Torsten Lang: *   - When probing the floppies we should add the FDC1772CMDADD_H flag since *     the FDC1772 will otherwise wait forever when no disk is inserted... * *  Things left to do: *   - Formatting *   - Maybe a better strategy for disk change detection (does anyone *     know one?) *   - There are some strange problems left: The strangest one is *     that, at least on my TT (4+4MB), the first 2 Bytes of the last *     page of the TT-Ram (!) change their contents (some bits get *     set) while a floppy DMA is going on. But there are no accesses *     to these memory locations from the kernel... (I tested that by *     making the page read-only). I cannot explain what's going on... *   - Sometimes the drive-change-detection stops to work. The *     function is still called, but the WP bit always reads as 0... *     Maybe a problem with the status reg mode or a timing problem. *     Note 10/12/94: The change detection now seems to work reliably. *     There is no proof, but I've seen no hang for a long time... * * ARCHIMEDES changes: (gilbertd@cs.man.ac.uk) *     26/12/95 - Changed all names starting with FDC to FDC1772 *                Removed all references to clock speed of FDC - we're stuck with 8MHz *                Modified disk_type structure to remove HD formats * *      7/ 1/96 - Wrote FIQ code, removed most remaining atariisms * *     13/ 1/96 - Well I think its read a single sector; but there is a problem *                fd_rwsec_done which is called in FIQ mode starts another transfer *                off (in fd_rwsec) while still in FIQ mode.  Because its still in *                FIQ mode it can't service the DMA and loses data. So need to *                heavily restructure. *     14/ 1/96 - Found that the definitions of the register numbers of the *                FDC were multiplied by 2 in the header for the 16bit words *                of the atari so half the writes were going in the wrong place. *                Also realised that the FIQ entry didn't make any attempt to *                preserve registers or return correctly; now in assembler. * *     11/ 2/96 - Hmm - doesn't work on real machine.  Auto detect doesn't *                and hacking that past seems to wait forever - check motor *                being turned on. * *     17/ 2/96 - still having problems - forcing track to -1 when selecting *                new drives seems to allow it to read first few sectors *                but then we get solid hangs at apparently random places *                which change depending what is happening. * *      9/ 3/96 - Fiddled a lot of stuff around to move to kernel 1.3.35 *                A lot of fiddling in DMA stuff. Having problems with it *                constnatly thinking its timeing out. Ah - its timeout *                was set to (6*HZ) rather than jiffies+(6*HZ).  Now giving *                duff data! * *      5/ 4/96 - Made it use the new IOC_ macros rather than *ioc *                Hmm - giving unexpected FIQ and then timeouts *     18/ 8/96 - Ran through indent -kr -i8 *                Some changes to disc change detect; don't know how well it *                works. *     24/ 8/96 - Put all the track buffering code back in from the atari *                code - I wonder if it will still work... No :-) *                Still works if I turn off track buffering. *     25/ 8/96 - Changed the timer expires that I'd added back to be  *                jiffies + ....; and it all sprang to life! Got 2.8K/sec *                off a cp -r of a 679K disc (showed 94% cpu usage!) *                (PC gets 14.3K/sec - 0% CPU!) Hmm - hard drive corrupt! *                Also perhaps that compile was with cache off. *                changed cli in fd_readtrack_check to cliIF *                changed vmallocs to kmalloc (whats the difference!!) *                Removed the busy wait loop in do_fd_request and replaced *                by a routine on tq_immediate; only 11% cpu on a dd off the *                raw disc - but the speed is the same. *	1/ 9/96 - Idea (failed!) - set the 'disable spin-up seqeunce' *		  when we read the track if we know the motor is on; didn't *		  help - perhaps we have to do it in stepping as well. *		  Nope. Still doesn't help. *		  Hmm - what seems to be happening is that fd_readtrack_check *		  is never getting called. Its job is to terminate the read *		  just after we think we should have got the data; otherwise *		  the fdc takes 1 second to timeout; which is what's happening *		  Now I can see 'readtrack_timer' being set (which should do the *		  call); but it never seems to be called - hmm! *		  OK - I've moved the check to my tq_immediate code - *		  and it WORKS! 13.95K/second at 19% CPU. *		  I wish I knew why that timer didn't work..... * *     16/11/96 - Fiddled and frigged for 2.0.18 * * DAG 30/01/99 - Started frobbing for 2.2.1 * DAG 20/06/99 - A little more frobbing: *		  Included include/asm/uaccess.h for get_user/put_user * * DAG  1/09/00 - Dusted off for 2.4.0-test7 *                MAX_SECTORS was name clashing so it is now FD1772_... *                Minor parameter, name layouts for 2.4.x differences */#include <linux/sched.h>#include <linux/fs.h>#include <linux/fcntl.h>#include <linux/slab.h>#include <linux/kernel.h>#include <linux/interrupt.h>#include <linux/timer.h>#include <linux/tqueue.h>#include <linux/fd.h>#include <linux/fd1772.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/mm.h>#include <asm/arch/oldlatches.h>#include <asm/bitops.h>#include <asm/dma.h>#include <asm/hardware.h>#include <asm/hardware/ioc.h>#include <asm/io.h>#include <asm/irq.h>#include <asm/mach-types.h>#include <asm/pgtable.h>#include <asm/system.h>#include <asm/uaccess.h>#define MAJOR_NR FLOPPY_MAJOR#define FLOPPY_DMA 0#include <linux/blk.h>/* Note: FD_MAX_UNITS could be redefined to 2 for the Atari (with * little additional rework in this file). But I'm not yet sure if * some other code depends on the number of floppies... (It is defined * in a public header!) */#if 0#undef FD_MAX_UNITS#define	FD_MAX_UNITS	2#endif/* Ditto worries for Arc - DAG */#define FD_MAX_UNITS 4#define TRACKBUFFER 0/*#define DEBUG*/#ifdef DEBUG#define DPRINT(a)	printk a#else#define DPRINT(a)#endif/* Disk types: DD */static struct archy_disk_type {	const char *name;	unsigned spt;		/* sectors per track */	unsigned blocks;	/* total number of blocks */	unsigned stretch;	/* track doubling ? */} disk_type[] = {	{ "d360", 9, 720, 0 },			/* 360kB diskette */	{ "D360", 9, 720, 1 },			/* 360kb in 720kb drive */	{ "D720", 9, 1440, 0 },			/* 720kb diskette (DD) */	/*{ "D820", 10,1640, 0}, *//* DD disk with 82 tracks/10 sectors 	                              - DAG - can't see how type detect can distinguish this				      from 720K until it reads block 4 by which time its too late! */};#define	NUM_DISK_TYPES (sizeof(disk_type)/sizeof(*disk_type))/* * Maximum disk size (in kilobytes). This default is used whenever the * current disk size is unknown. */#define MAX_DISK_SIZE 720static int floppy_sizes[256];static int floppy_blocksizes[256];/* current info on each unit */static struct archy_floppy_struct {	int connected;		/* !=0 : drive is connected */	int autoprobe;		/* !=0 : do autoprobe       */	struct archy_disk_type *disktype;	/* current type of disk */	int track;		/* current head position or -1				   * if unknown */	unsigned int steprate;	/* steprate setting */	unsigned int wpstat;	/* current state of WP signal				   * (for disk change detection) */} unit[FD_MAX_UNITS];/* DAG: On Arc we spin on a flag being cleared by fdc1772_comendhandler which   is an assembler routine */extern void fdc1772_comendhandler(void);	/* Actually doens't have these parameters - see fd1772.S */extern volatile int fdc1772_comendstatus;extern volatile int fdc1772_fdc_int_done;#define FDC1772BASE ((0x210000>>2)|0x80000000)#define FDC1772_READ(reg) inb(FDC1772BASE+(reg/2))/* DAG: You wouldn't be silly to ask why FDC1772_WRITE is a function rather   than the #def below - well simple - the #def won't compile - and I   don't understand why (__outwc not defined) *//* NOTE: Reg is 0,2,4,6 as opposed to 0,1,2,3 or 0,4,8,12 to keep compatibility   with the ST version of fd1772.h *//*#define FDC1772_WRITE(reg,val) outw(val,(reg+FDC1772BASE)); */void FDC1772_WRITE(int reg, unsigned char val){	if (reg == FDC1772REG_CMD) {		DPRINT(("FDC1772_WRITE new command 0x%x @ %d\n", val,jiffies));		if (fdc1772_fdc_int_done) {			DPRINT(("FDC1772_WRITE: Hmm fdc1772_fdc_int_done true - resetting\n"));			fdc1772_fdc_int_done = 0;		};	};	outb(val, (reg / 2) + FDC1772BASE);};#define	FD1772_MAX_SECTORS	22unsigned char *DMABuffer;	/* buffer for writes *//*static unsigned long PhysDMABuffer; *//* physical address *//* DAG: On Arc we just go straight for the DMA buffer */#define PhysDMABuffer DMABuffer#ifdef TRACKBUFFER   unsigned char *TrackBuffer;       /* buffer for reads */#define PhysTrackBuffer TrackBuffer /* physical address */static int BufferDrive, BufferSide, BufferTrack;static int read_track;    /* non-zero if we are reading whole tracks */  #define SECTOR_BUFFER(sec)  (TrackBuffer + ((sec)-1)*512)#define IS_BUFFERED(drive,side,track) \    (BufferDrive == (drive) && BufferSide == (side) && BufferTrack == (track))#endif/* * These are global variables, as that's the easiest way to give * information to interrupts. They are the data used for the current * request. */static int SelectedDrive = 0;static int ReqCmd, ReqBlock;static int ReqSide, ReqTrack, ReqSector, ReqCnt;static int HeadSettleFlag = 0;static unsigned char *ReqData, *ReqBuffer;static int MotorOn = 0, MotorOffTrys;/* Synchronization of FDC1772 access. */static volatile int fdc_busy = 0;static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);/* long req'd for set_bit --RR */static unsigned long changed_floppies = 0xff, fake_change = 0;#define	CHECK_CHANGE_DELAY	HZ/2/* DAG - increased to 30*HZ - not sure if this is the correct thing to do */#define	FD_MOTOR_OFF_DELAY	(10*HZ)#define	FD_MOTOR_OFF_MAXTRY	(10*20)#define FLOPPY_TIMEOUT		(6*HZ)#define RECALIBRATE_ERRORS	4	/* After this many errors the drive					 * will be recalibrated. */#define MAX_ERRORS		8	/* After this many errors the driver					 * will give up. */#define	START_MOTOR_OFF_TIMER(delay)				\	do {							\		motor_off_timer.expires = jiffies + (delay);	\		add_timer( &motor_off_timer );			\		MotorOffTrys = 0;				\	} while(0)#define	START_CHECK_CHANGE_TIMER(delay)				\	do {							\	        mod_timer(&fd_timer, jiffies + (delay));	\	} while(0)#define	START_TIMEOUT()						\	do {							\		mod_timer(&timeout_timer, jiffies+FLOPPY_TIMEOUT); \	} while(0)#define	STOP_TIMEOUT()						\	do {							\		del_timer( &timeout_timer );			\	} while(0)#define ENABLE_IRQ() enable_irq(FIQ_FD1772+64);#define DISABLE_IRQ() disable_irq(FIQ_FD1772+64);static void fd1772_checkint(void);struct tq_struct fd1772_tq = { 0,0, (void *)fd1772_checkint, 0 };/* * The driver is trying to determine the correct media format * while Probing is set. fd_rwsec_done() clears it after a * successful access. */static int Probing = 0;/* This flag is set when a dummy seek is necesary to make the WP * status bit accessible. */static int NeedSeek = 0;/***************************** Prototypes *****************************/static void fd_select_side(int side);static void fd_select_drive(int drive);static void fd_deselect(void);static void fd_motor_off_timer(unsigned long dummy);static void check_change(unsigned long dummy);static __inline__ void set_head_settle_flag(void);static __inline__ int get_head_settle_flag(void);static void floppy_irqconsequencehandler(void);static void fd_error(void);static void do_fd_action(int drive);static void fd_calibrate(void);static void fd_calibrate_done(int status);static void fd_seek(void);static void fd_seek_done(int status);static void fd_rwsec(void);#ifdef TRACKBUFFER   static void fd_readtrack_check( unsigned long dummy );  #endifstatic void fd_rwsec_done(int status);static void fd_times_out(unsigned long dummy);static void finish_fdc(void);static void finish_fdc_done(int dummy);static void floppy_off(unsigned int nr);static __inline__ void copy_buffer(void *from, void *to);static void setup_req_params(int drive);static void redo_fd_request(void);static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int		    cmd, unsigned long param);static void fd_probe(int drive);static int fd_test_drive_present(int drive);static void config_types(void);static int floppy_open(struct inode *inode, struct file *filp);static int floppy_release(struct inode *inode, struct file *filp);/************************* End of Prototypes **************************/static struct timer_list motor_off_timer = {	function:	fd_motor_off_timer,};#ifdef TRACKBUFFERstatic struct timer_list readtrack_timer = {	function: 	fd_readtrack_check,};#endifstatic struct timer_list timeout_timer = {	function:	fd_times_out,};static struct timer_list fd_timer = {	function:	check_change,};/* DAG: Haven't got a clue what this is? */int stdma_islocked(void){	return 0;};/* Select the side to use. */static void fd_select_side(int side){	oldlatch_aupdate(LATCHA_SIDESEL, side ? 0 : LATCHA_SIDESEL);}/* Select a drive, update the FDC1772's track register */static void fd_select_drive(int drive){#ifdef DEBUG	printk("fd_select_drive:%d\n", drive);#endif	/* Hmm - nowhere do we seem to turn the motor on - I'm going to do it here! */	oldlatch_aupdate(LATCHA_MOTOR | LATCHA_INUSE, 0);	if (drive == SelectedDrive)		return;	oldlatch_aupdate(LATCHA_FDSELALL, 0xf - (1 << drive));	/* restore track register to saved value */	FDC1772_WRITE(FDC1772REG_TRACK, unit[drive].track);	udelay(25);	SelectedDrive = drive;}/* Deselect both drives. */static void fd_deselect(void){	unsigned long flags;	DPRINT(("fd_deselect\n"));	oldlatch_aupdate(LATCHA_FDSELALL | LATCHA_MOTOR | LATCHA_INUSE, 0xf | LATCHA_MOTOR | LATCHA_INUSE);	SelectedDrive = -1;}/* This timer function deselects the drives when the FDC1772 switched the * motor off. The deselection cannot happen earlier because the FDC1772 * counts the index signals, which arrive only if one drive is selected. */static void fd_motor_off_timer(unsigned long dummy){	unsigned long flags;	unsigned char status;	int delay;	del_timer(&motor_off_timer);	if (SelectedDrive < 0)		/* no drive selected, needn't deselect anyone */		return;	save_flags(flags);	cli();	if (fdc_busy)		/* was stdma_islocked */		goto retry;	status = FDC1772_READ(FDC1772REG_STATUS);	if (!(status & 0x80)) {		/*		 * motor already turned off by FDC1772 -> deselect drives		 * In actual fact its this deselection which turns the motor		 * off on the Arc, since the motor control is actually on		 * Latch A		 */		DPRINT(("fdc1772: deselecting in fd_motor_off_timer\n"));		fd_deselect();		MotorOn = 0;		restore_flags(flags);		return;	}	/* not yet off, try again */retry:	restore_flags(flags);	/* Test again later; if tested too often, it seems there is no disk	 * in the drive and the FDC1772 will leave the motor on forever (or,	 * at least until a disk is inserted). So we'll test only twice	 * per second from then on...	 */	delay = (MotorOffTrys < FD_MOTOR_OFF_MAXTRY) ?	    (++MotorOffTrys, HZ / 20) : HZ / 2;	START_MOTOR_OFF_TIMER(delay);}/* This function is repeatedly called to detect disk changes (as good * as possible) and keep track of the current state of the write protection. */static void check_change(unsigned long dummy){	static int drive = 0;	unsigned long flags;	int stat;	if (fdc_busy)		return;		/* Don't start poking about if the fdc is busy */	return;			/* let's just forget it for the mo DAG */	if (++drive > 1 || !unit[drive].connected)		drive = 0;	save_flags(flags);	cli();	if (!stdma_islocked()) {		stat = !!(FDC1772_READ(FDC1772REG_STATUS) & FDC1772STAT_WPROT);		/* The idea here is that if the write protect line has changed then		the disc must have changed */		if (stat != unit[drive].wpstat) {			DPRINT(("wpstat[%d] = %d\n", drive, stat));			unit[drive].wpstat = stat;			set_bit(drive, &changed_floppies);		}	}	restore_flags(flags);	START_CHECK_CHANGE_TIMER(CHECK_CHANGE_DELAY);}/* Handling of the Head Settling Flag: This flag should be set after each * seek operation, because we don't use seeks with verify. */

⌨️ 快捷键说明

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