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

📄 amiflop.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *  linux/amiga/amiflop.c * *  Copyright (C) 1993  Greg Harp *  Portions of this driver are based on code contributed by Brad Pepers *   *  revised 28.5.95 by Joerg Dorchain *  - now no bugs(?) any more for both HD & DD *  - added support for 40 Track 5.25" drives, 80-track hopefully behaves *    like 3.5" dd (no way to test - are there any 5.25" drives out there *    that work on an A4000?) *  - wrote formatting routine (maybe dirty, but works) * *  june/july 1995 added ms-dos support by Joerg Dorchain *  (portions based on messydos.device and various contributors) *  - currently only 9 and 18 sector disks * *  - fixed a bug with the internal trackbuffer when using multiple  *    disks the same time *  - made formatting a bit safer *  - added command line and machine based default for "silent" df0 * *  december 1995 adapted for 1.2.13pl4 by Joerg Dorchain *  - works but I think it's inefficient. (look in redo_fd_request) *    But the changes were very efficient. (only three and a half lines) * *  january 1996 added special ioctl for tracking down read/write problems *  - usage ioctl(d, RAW_TRACK, ptr); the raw track buffer (MFM-encoded data *    is copied to area. (area should be large enough since no checking is *    done - 30K is currently sufficient). return the actual size of the *    trackbuffer *  - replaced udelays() by a timer (CIAA timer B) for the waits  *    needed for the disk mechanic. * *  february 1996 fixed error recovery and multiple disk access *  - both got broken the first time I tampered with the driver :-( *  - still not safe, but better than before * *  revised Marts 3rd, 1996 by Jes Sorensen for use in the 1.3.28 kernel. *  - Minor changes to accept the kdev_t. *  - Replaced some more udelays with ms_delays. Udelay is just a loop, *    and so the delay will be different depending on the given *    processor :-( *  - The driver could use a major cleanup because of the new *    major/minor handling that came with kdev_t. It seems to work for *    the time being, but I can't guarantee that it will stay like *    that when we start using 16 (24?) bit minors. * * restructured jan 1997 by Joerg Dorchain * - Fixed Bug accessing multiple disks * - some code cleanup * - added trackbuffer for each drive to speed things up * - fixed some race conditions (who finds the next may send it to me ;-) */#include <linux/module.h>#include <linux/sched.h>#include <linux/fs.h>#include <linux/fcntl.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/fd.h>#include <linux/hdreg.h>#include <linux/errno.h>#include <linux/types.h>#include <linux/delay.h>#include <linux/string.h>#include <linux/slab.h>#include <linux/init.h>#include <linux/amifdreg.h>#include <linux/amifd.h>#include <linux/ioport.h>#include <asm/setup.h>#include <asm/uaccess.h>#include <asm/amigahw.h>#include <asm/amigaints.h>#include <asm/irq.h>#define MAJOR_NR FLOPPY_MAJOR#include <linux/blk.h>#undef DEBUG /* print _LOTS_ of infos */#define RAW_IOCTL#ifdef RAW_IOCTL#define IOCTL_RAW_TRACK 0x5254524B  /* 'RTRK' */#endif/* *  Defines *//* *  Error codes */#define FD_OK		0	/* operation succeeded */#define FD_ERROR	-1	/* general error (seek, read, write, etc) */#define FD_NOUNIT	1	/* unit does not exist */#define FD_UNITBUSY	2	/* unit already active */#define FD_NOTACTIVE	3	/* unit is not active */#define FD_NOTREADY	4	/* unit is not ready (motor not on/no disk) */#define MFM_NOSYNC	1#define MFM_HEADER	2#define MFM_DATA	3#define MFM_TRACK	4/* *  Floppy ID values */#define FD_NODRIVE	0x00000000  /* response when no unit is present */#define FD_DD_3 	0xffffffff  /* double-density 3.5" (880K) drive */#define FD_HD_3 	0x55555555  /* high-density 3.5" (1760K) drive */#define FD_DD_5 	0xaaaaaaaa  /* double-density 5.25" (440K) drive */static long int fd_def_df0 = FD_DD_3;     /* default for df0 if it doesn't identify */MODULE_PARM(fd_def_df0,"l");MODULE_LICENSE("GPL");/* *  Macros */#define MOTOR_ON	(ciab.prb &= ~DSKMOTOR)#define MOTOR_OFF	(ciab.prb |= DSKMOTOR)#define SELECT(mask)    (ciab.prb &= ~mask)#define DESELECT(mask)  (ciab.prb |= mask)#define SELMASK(drive)  (1 << (3 + (drive & 3)))static struct fd_drive_type drive_types[] = {/*  code	name	   tr he   rdsz   wrsz sm pc1 pc2 sd  st st*//*  warning: times are now in milliseconds (ms)                    */{ FD_DD_3,	"DD 3.5",  80, 2, 14716, 13630, 1, 80,161, 3, 18, 1},{ FD_HD_3,	"HD 3.5",  80, 2, 28344, 27258, 2, 80,161, 3, 18, 1},{ FD_DD_5,	"DD 5.25", 40, 2, 14716, 13630, 1, 40, 81, 6, 30, 2},{ FD_NODRIVE, "No Drive", 0, 0,     0,     0, 0,  0,  0,  0,  0, 0}};static int num_dr_types = sizeof(drive_types) / sizeof(drive_types[0]);/* defaults for 3 1/2" HD-Disks */static int floppy_sizes[256]={880,880,880,880,720,720,720,720,};static int floppy_blocksizes[256];/* hardsector size assumed to be 512 */static int amiga_read(int), dos_read(int);static void amiga_write(int), dos_write(int);static struct fd_data_type data_types[] = {	{ "Amiga", 11 , amiga_read, amiga_write},	{ "MS-Dos", 9, dos_read, dos_write}};/* current info on each unit */static struct amiga_floppy_struct unit[FD_MAX_UNITS];static struct timer_list flush_track_timer[FD_MAX_UNITS];static struct timer_list post_write_timer;static struct timer_list motor_on_timer;static struct timer_list motor_off_timer[FD_MAX_UNITS];static int on_attempts;/* Synchronization of FDC access *//* request loop (trackbuffer) */static volatile int fdc_busy = -1;static volatile int fdc_nested;static DECLARE_WAIT_QUEUE_HEAD(fdc_wait); static DECLARE_WAIT_QUEUE_HEAD(motor_wait);static volatile int selected = -1;	/* currently selected drive */static int writepending;static int writefromint;static char *raw_buf;#define RAW_BUF_SIZE 30000  /* size of raw disk data *//* * 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 volatile char block_flag;static DECLARE_WAIT_QUEUE_HEAD(wait_fd_block);/* MS-Dos MFM Coding tables (should go quick and easy) */static unsigned char mfmencode[16]={	0x2a, 0x29, 0x24, 0x25, 0x12, 0x11, 0x14, 0x15,	0x4a, 0x49, 0x44, 0x45, 0x52, 0x51, 0x54, 0x55};static unsigned char mfmdecode[128];/* floppy internal millisecond timer stuff */static volatile int ms_busy = -1;static DECLARE_WAIT_QUEUE_HEAD(ms_wait);#define MS_TICKS ((amiga_eclock+50)/1000)/* * Note that MAX_ERRORS=X doesn't imply that we retry every bad read * max X times - some types of errors increase the errorcount by 2 or * even 3, so we might actually retry only X/2 times before giving up. */#define MAX_ERRORS 12/* Prevent "aliased" accesses. */static int fd_ref[4] = { 0,0,0,0 };static int fd_device[4] = { 0,0,0,0 };/* * Current device number. Taken either from the block header or from the * format request descriptor. */#define CURRENT_DEVICE (CURRENT->rq_dev)/* Current error count. */#define CURRENT_ERRORS (CURRENT->errors)/* * Here come the actual hardware access and helper functions. * They are not reentrant and single threaded because all drives * share the same hardware and the same trackbuffer. *//* Milliseconds timer */static void ms_isr(int irq, void *dummy, struct pt_regs *fp){	ms_busy = -1;	wake_up(&ms_wait);}/* all waits are queued up    A more generic routine would do a schedule a la timer.device */static void ms_delay(int ms){	unsigned long flags;	int ticks;	if (ms > 0) {		save_flags(flags);		cli();		while (ms_busy == 0)			sleep_on(&ms_wait);		ms_busy = 0;		restore_flags(flags);		ticks = MS_TICKS*ms-1;		ciaa.tblo=ticks%256;		ciaa.tbhi=ticks/256;		ciaa.crb=0x19; /*count eclock, force load, one-shoot, start */		sleep_on(&ms_wait);	}}/* Hardware semaphore *//* returns true when we would get the semaphore */static inline int try_fdc(int drive){	drive &= 3;	return ((fdc_busy < 0) || (fdc_busy == drive));}static void get_fdc(int drive){	unsigned long flags;	drive &= 3;#ifdef DEBUG	printk("get_fdc: drive %d  fdc_busy %d  fdc_nested %d\n",drive,fdc_busy,fdc_nested);#endif	save_flags(flags);	cli();	while (!try_fdc(drive))		sleep_on(&fdc_wait);	fdc_busy = drive;	fdc_nested++;	restore_flags(flags);}static inline void rel_fdc(void){#ifdef DEBUG	if (fdc_nested == 0)		printk("fd: unmatched rel_fdc\n");	printk("rel_fdc: fdc_busy %d fdc_nested %d\n",fdc_busy,fdc_nested);#endif	fdc_nested--;	if (fdc_nested == 0) {		fdc_busy = -1;		wake_up(&fdc_wait);	}}static void fd_select (int drive){	unsigned char prb = ~0;	drive&=3;#ifdef DEBUG	printk("selecting %d\n",drive);#endif	if (drive == selected)		return;	get_fdc(drive);	selected = drive;	if (unit[drive].track % 2 != 0)		prb &= ~DSKSIDE;	if (unit[drive].motor == 1)		prb &= ~DSKMOTOR;	ciab.prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));	ciab.prb = prb;	prb &= ~SELMASK(drive);	ciab.prb = prb;	rel_fdc();}static void fd_deselect (int drive){	unsigned char prb;	unsigned long flags;	drive&=3;#ifdef DEBUG	printk("deselecting %d\n",drive);#endif	if (drive != selected) {		printk(KERN_WARNING "Deselecting drive %d while %d was selected!\n",drive,selected);		return;	}	get_fdc(drive);	save_flags (flags);	sti();	selected = -1;	prb = ciab.prb;	prb |= (SELMASK(0)|SELMASK(1)|SELMASK(2)|SELMASK(3));	ciab.prb = prb;	restore_flags (flags);	rel_fdc();}static void motor_on_callback(unsigned long nr){	if (!(ciaa.pra & DSKRDY) || --on_attempts == 0) {		wake_up (&motor_wait);	} else {		motor_on_timer.expires = jiffies + HZ/10;		add_timer(&motor_on_timer);	}}static int fd_motor_on(int nr){	nr &= 3;	del_timer(motor_off_timer + nr);	if (!unit[nr].motor) {		unit[nr].motor = 1;		fd_select(nr);		del_timer(&motor_on_timer);		motor_on_timer.data = nr;		motor_on_timer.expires = jiffies + HZ/2;		add_timer(&motor_on_timer);		on_attempts = 10;		sleep_on (&motor_wait);		fd_deselect(nr);	}	if (on_attempts == 0) {		on_attempts = -1;#if 0		printk (KERN_ERR "motor_on failed, turning motor off\n");		fd_motor_off (nr);		return 0;#else		printk (KERN_WARNING "DSKRDY not set after 1.5 seconds - assuming drive is spinning notwithstanding\n");#endif	}	return 1;}static void fd_motor_off(unsigned long drive){	long calledfromint;#ifdef MODULE	long decusecount;	decusecount = drive & 0x40000000;#endif	calledfromint = drive & 0x80000000;	drive&=3;	if (calledfromint && !try_fdc(drive)) {		/* We would be blocked in an interrupt, so try again later */		motor_off_timer[drive].expires = jiffies + 1;		add_timer(motor_off_timer + drive);		return;	}	unit[drive].motor = 0;	fd_select(drive);	udelay (1);	fd_deselect(drive);#ifdef MODULE/*  this is the last interrupt for any drive access, happens after  release (from floppy_off). So we have to wait until now to decrease  the use count.*/	if (decusecount)		MOD_DEC_USE_COUNT;#endif}static void floppy_off (unsigned int nr){	int drive;	drive = nr & 3;	del_timer(motor_off_timer + drive);	motor_off_timer[drive].expires = jiffies + 3*HZ;	/* called this way it is always from interrupt */	motor_off_timer[drive].data = nr | 0x80000000;	add_timer(motor_off_timer + nr);}static int fd_calibrate(int drive){	unsigned char prb;	int n;	drive &= 3;	get_fdc(drive);	if (!fd_motor_on (drive))		return 0;	fd_select (drive);	prb = ciab.prb;	prb |= DSKSIDE;	prb &= ~DSKDIREC;	ciab.prb = prb;	for (n = unit[drive].type->tracks/2; n != 0; --n) {		if (ciaa.pra & DSKTRACK0)			break;		prb &= ~DSKSTEP;		ciab.prb = prb;		prb |= DSKSTEP;		udelay (2);		ciab.prb = prb;		ms_delay(unit[drive].type->step_delay);	}	ms_delay (unit[drive].type->settle_time);	prb |= DSKDIREC;	n = unit[drive].type->tracks + 20;	for (;;) {		prb &= ~DSKSTEP;		ciab.prb = prb;		prb |= DSKSTEP;		udelay (2);		ciab.prb = prb;		ms_delay(unit[drive].type->step_delay + 1);		if ((ciaa.pra & DSKTRACK0) == 0)			break;		if (--n == 0) {			printk (KERN_ERR "fd%d: calibrate failed, turning motor off\n", drive);			fd_motor_off (drive);			unit[drive].track = -1;			rel_fdc();

⌨️ 快捷键说明

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