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

📄 floppy.c

📁 GNU Mach 微内核源代码, 基于美国卡内基美隆大学的 Mach 研究项目
💻 C
📖 第 1 页 / 共 5 页
字号:
/* *  linux/kernel/floppy.c * *  Copyright (C) 1991, 1992  Linus Torvalds *  Copyright (C) 1993, 1994  Alain Knaff *//* * 02.12.91 - Changed to static variables to indicate need for reset * and recalibrate. This makes some things easier (output_byte reset * checking etc), and means less interrupt jumping in case of errors, * so the code is hopefully easier to understand. *//* * This file is certainly a mess. I've tried my best to get it working, * but I don't like programming floppies, and I have only one anyway. * Urgel. I should check for more errors, and do more graceful error * recovery. Seems there are problems with several drives. I've tried to * correct them. No promises. *//* * As with hd.c, all routines within this file can (and will) be called * by interrupts, so extreme caution is needed. A hardware interrupt * handler may not sleep, or a kernel panic will happen. Thus I cannot * call "floppy-on" directly, but have to set a special timer interrupt * etc. *//* * 28.02.92 - made track-buffering routines, based on the routines written * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus. *//* * Automatic floppy-detection and formatting written by Werner Almesberger * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with * the floppy-change signal detection. *//* * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed * FDC data overrun bug, added some preliminary stuff for vertical * recording support. * * 1992/9/17: Added DMA allocation & DMA functions. -- hhb. * * TODO: Errors are still not counted properly. *//* 1992/9/20 * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl) * modeled after the freeware MS-DOS program fdformat/88 V1.8 by * Christoph H. Hochst\"atter. * I have fixed the shift values to the ones I always use. Maybe a new * ioctl() should be created to be able to modify them. * There is a bug in the driver that makes it impossible to format a * floppy as the first thing after bootup. *//* * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and * this helped the floppy driver as well. Much cleaner, and still seems to * work. *//* 1994/6/24 --bbroad-- added the floppy table entries and made * minor modifications to allow 2.88 floppies to be run. *//* 1994/7/13 -- Paul Vojta -- modified the probing code to allow three or more * disk types. *//* * 1994/8/8 -- Alain Knaff -- Switched to fdpatch driver: Support for bigger * format bug fixes, but unfortunately some new bugs too... *//* 1994/9/17 -- Koen Holtman -- added logging of physical floppy write * errors to allow safe writing by specialized programs. *//* 1995/4/24 -- Dan Fandrich -- added support for Commodore 1581 3.5" disks * by defining bit 1 of the "stretch" parameter to mean put sectors on the * opposite side of the disk, leaving the sector IDs alone (i.e. Commodore's * drives are "upside-down"). *//* * 1995/8/26 -- Andreas Busse -- added Mips support. *//* * 1995/10/18 -- Ralf Baechle -- Portability cleanup; move machine dependent * features to asm/floppy.h. */#define FLOPPY_SANITY_CHECK#undef  FLOPPY_SILENT_DCL_CLEAR#define REALLY_SLOW_IO#define DEBUGT 2#define DCL_DEBUG /* debug disk change line *//* do print messages for unexpected interrupts */static int print_unex=1;#include <linux/utsname.h>#include <linux/module.h>/* the following is the mask of allowed drives. By default units 2 and * 3 of both floppy controllers are disabled, because switching on the * motor of these drives causes system hangs on some PCI computers. drive * 0 is the low bit (0x1), and drive 7 is the high bit (0x80). Bits are on if * a drive is allowed. */static int FLOPPY_IRQ=6;static int FLOPPY_DMA=2;static int allowed_drive_mask = 0x33;static int irqdma_allocated = 0; #include <linux/sched.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/timer.h>#include <linux/tqueue.h>#define FDPATCHES#include <linux/fdreg.h>#include <linux/fd.h>#define OLDFDRAWCMD 0x020d /* send a raw command to the FDC */struct old_floppy_raw_cmd {  void *data;  long length;  unsigned char rate;  unsigned char flags;  unsigned char cmd_count;  unsigned char cmd[9];  unsigned char reply_count;  unsigned char reply[7];  int track;};#include <linux/errno.h>#include <linux/malloc.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/fcntl.h>#include <linux/delay.h>#include <linux/mc146818rtc.h> /* CMOS defines */#include <linux/ioport.h>#include <linux/interrupt.h>#include <asm/dma.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/io.h>#include <asm/segment.h>static int use_virtual_dma=0; /* virtual DMA for Intel */static unsigned short virtual_dma_port=0x3f0;void floppy_interrupt(int irq, void *dev_id, struct pt_regs * regs);static int set_dor(int fdc, char mask, char data);static inline int __get_order(unsigned long size);#include <asm/floppy.h>#define MAJOR_NR FLOPPY_MAJOR#include <linux/blk.h>#include <linux/cdrom.h> /* for the compatibility eject ioctl */#ifndef FLOPPY_MOTOR_MASK#define FLOPPY_MOTOR_MASK 0xf0#endif#ifndef fd_get_dma_residue#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)#endif/* Dma Memory related stuff *//* Pure 2^n version of get_order */static inline int __get_order(unsigned long size){	int order;	size = (size-1) >> (PAGE_SHIFT-1);	order = -1;	do {		size >>= 1;		order++;	} while (size);	return order;}#ifndef fd_dma_mem_free#define fd_dma_mem_free(addr, size) free_pages(addr, __get_order(size))#endif#ifndef fd_dma_mem_alloc#define fd_dma_mem_alloc(size) __get_dma_pages(GFP_KERNEL,__get_order(size))#endif/* End dma memory related stuff */static unsigned int fake_change = 0;static int initialising=1;static inline int TYPE(kdev_t x) {	return  (MINOR(x)>>2) & 0x1f;}static inline int DRIVE(kdev_t x) {	return (MINOR(x)&0x03) | ((MINOR(x)&0x80) >> 5);}#define ITYPE(x) (((x)>>2) & 0x1f)#define TOMINOR(x) ((x & 3) | ((x & 4) << 5))#define UNIT(x) ((x) & 0x03)		/* drive on fdc */#define FDC(x) (((x) & 0x04) >> 2)  /* fdc of drive */#define REVDRIVE(fdc, unit) ((unit) + ((fdc) << 2))				/* reverse mapping from unit and fdc to drive */#define DP (&drive_params[current_drive])#define DRS (&drive_state[current_drive])#define DRWE (&write_errors[current_drive])#define FDCS (&fdc_state[fdc])#define CLEARF(x) (clear_bit(x##_BIT, &DRS->flags))#define SETF(x) (set_bit(x##_BIT, &DRS->flags))#define TESTF(x) (test_bit(x##_BIT, &DRS->flags))#define UDP (&drive_params[drive])#define UDRS (&drive_state[drive])#define UDRWE (&write_errors[drive])#define UFDCS (&fdc_state[FDC(drive)])#define UCLEARF(x) (clear_bit(x##_BIT, &UDRS->flags))#define USETF(x) (set_bit(x##_BIT, &UDRS->flags))#define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags))#define DPRINT(format, args...) printk(DEVICE_NAME "%d: " format, current_drive , ## args)#define PH_HEAD(floppy,head) (((((floppy)->stretch & 2) >>1) ^ head) << 2)#define STRETCH(floppy) ((floppy)->stretch & FD_STRETCH)#define CLEARSTRUCT(x) memset((x), 0, sizeof(*(x)))#define INT_OFF save_flags(flags); cli()#define INT_ON  restore_flags(flags)/* read/write */#define COMMAND raw_cmd->cmd[0]#define DR_SELECT raw_cmd->cmd[1]#define TRACK raw_cmd->cmd[2]#define HEAD raw_cmd->cmd[3]#define SECTOR raw_cmd->cmd[4]#define SIZECODE raw_cmd->cmd[5]#define SECT_PER_TRACK raw_cmd->cmd[6]#define GAP raw_cmd->cmd[7]#define SIZECODE2 raw_cmd->cmd[8]#define NR_RW 9/* format */#define F_SIZECODE raw_cmd->cmd[2]#define F_SECT_PER_TRACK raw_cmd->cmd[3]#define F_GAP raw_cmd->cmd[4]#define F_FILL raw_cmd->cmd[5]#define NR_F 6/* * Maximum disk size (in kilobytes). This default is used whenever the * current disk size is unknown. * [Now it is rather a minimum] */#define MAX_DISK_SIZE 4 /* 3984*/#define K_64	0x10000		/* 64KB *//* * globals used by 'result()' */#define MAX_REPLIES 16static unsigned char reply_buffer[MAX_REPLIES];static int inr; /* size of reply buffer, when called from interrupt */#define ST0 (reply_buffer[0])#define ST1 (reply_buffer[1])#define ST2 (reply_buffer[2])#define ST3 (reply_buffer[0]) /* result of GETSTATUS */#define R_TRACK (reply_buffer[3])#define R_HEAD (reply_buffer[4])#define R_SECTOR (reply_buffer[5])#define R_SIZECODE (reply_buffer[6])#define SEL_DLY (2*HZ/100)#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))/* * this struct defines the different floppy drive types. */static struct {	struct floppy_drive_params params;	const char *name; /* name printed while booting */} default_drive_params[]= {/* NOTE: the time values in jiffies should be in msec! CMOS drive type  |     Maximum data rate supported by drive type  |     |   Head load time, msec  |     |   |   Head unload time, msec (not used)  |     |   |   |     Step rate interval, usec  |     |   |   |     |       Time needed for spinup time (jiffies)  |     |   |   |     |       |      Timeout for spinning down (jiffies)  |     |   |   |     |       |      |   Spindown offset (where disk stops)  |     |   |   |     |       |      |   |     Select delay  |     |   |   |     |       |      |   |     |     RPS  |     |   |   |     |       |      |   |     |     |    Max number of tracks  |     |   |   |     |       |      |   |     |     |    |     Interrupt timeout  |     |   |   |     |       |      |   |     |     |    |     |   Max nonintlv. sectors  |     |   |   |     |       |      |   |     |     |    |     |   | -Max Errors- flags */{{0,  500, 16, 16, 8000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  80, 3*HZ, 20, {3,1,2,0,2}, 0,      0, { 7, 4, 8, 2, 1, 5, 3,10}, 3*HZ/2, 0 }, "unknown" },{{1,  300, 16, 16, 8000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  40, 3*HZ, 17, {3,1,2,0,2}, 0,      0, { 1, 0, 0, 0, 0, 0, 0, 0}, 3*HZ/2, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/{{2,  500, 16, 16, 6000, 4*HZ/10, 3*HZ, 14, SEL_DLY, 6,  83, 3*HZ, 17, {3,1,2,0,2}, 0,      0, { 2, 5, 6,23,10,20,12, 0}, 3*HZ/2, 2 }, "1.2M" }, /*5 1/4 HD AT*/{{3,  250, 16, 16, 3000,    1*HZ, 3*HZ,  0, SEL_DLY, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,      0, { 4,22,21,30, 3, 0, 0, 0}, 3*HZ/2, 4 }, "720k" }, /*3 1/2 DD*/{{4,  500, 16, 16, 4000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 20, {3,1,2,0,2}, 0,      0, { 7, 4,25,22,31,21,29,11}, 3*HZ/2, 7 }, "1.44M" }, /*3 1/2 HD*/{{5, 1000, 15,  8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,      0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/{{6, 1000, 15,  8, 3000, 4*HZ/10, 3*HZ, 10, SEL_DLY, 5,  83, 3*HZ, 40, {3,1,2,0,2}, 0,      0, { 7, 8, 4,25,28,22,31,21}, 3*HZ/2, 8 }, "2.88M" } /*3 1/2 ED*//*    |  --autodetected formats---    |      |      | *    read_track                      |      |    Name printed when booting *				      |     Native format *	            Frequency of disk change checks */};static struct floppy_drive_params drive_params[N_DRIVE];static struct floppy_drive_struct drive_state[N_DRIVE];static struct floppy_write_errors write_errors[N_DRIVE];static struct floppy_raw_cmd *raw_cmd, default_raw_cmd;/* * This struct defines the different floppy types. * * Bit 0 of 'stretch' tells if the tracks need to be doubled for some * types (e.g. 360kB diskette in 1.2MB drive, etc.).  Bit 1 of 'stretch' * tells if the disk is in Commodore 1581 format, which means side 0 sectors * are located on side 1 of the disk but with a side 0 ID, and vice-versa. * This is the same as the Sharp MZ-80 5.25" CP/M disk format, except that the * 1581's logical side 0 is on physical side 1, whereas the Sharp's logical * side 0 is on physical side 0 (but with the misnamed sector IDs). * 'stretch' should probably be renamed to something more general, like * 'options'.  Other parameters should be self-explanatory (see also * setfdprm(8)). */static struct floppy_struct floppy_type[32] = {	{    0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL    },	/*  0 no testing    */	{  720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"d360"  }, /*  1 360KB PC      */	{ 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"h1200" },	/*  2 1.2MB AT      */	{  720, 9,1,80,0,0x2A,0x02,0xDF,0x50,"D360"  },	/*  3 360KB SS 3.5" */	{ 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"D720"  },	/*  4 720KB 3.5"    */	{  720, 9,2,40,1,0x23,0x01,0xDF,0x50,"h360"  },	/*  5 360KB AT      */	{ 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,"h720"  },	/*  6 720KB AT      */	{ 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"H1440" },	/*  7 1.44MB 3.5"   */	{ 5760,36,2,80,0,0x1B,0x43,0xAF,0x54,"E2880" },	/*  8 2.88MB 3.5"   */	{ 6240,39,2,80,0,0x1B,0x43,0xAF,0x28,"E3120"},	/*  9 3.12MB 3.5"   */	{ 2880,18,2,80,0,0x25,0x00,0xDF,0x02,"h1440" }, /* 10 1.44MB 5.25"  */	{ 3360,21,2,80,0,0x1C,0x00,0xCF,0x0C,"H1680" }, /* 11 1.68MB 3.5"   */	{  820,10,2,41,1,0x25,0x01,0xDF,0x2E,"h410"  },	/* 12 410KB 5.25"   */	{ 1640,10,2,82,0,0x25,0x02,0xDF,0x2E,"H820"  },	/* 13 820KB 3.5"    */	{ 2952,18,2,82,0,0x25,0x00,0xDF,0x02,"h1476" },	/* 14 1.48MB 5.25"  */	{ 3444,21,2,82,0,0x25,0x00,0xDF,0x0C,"H1722" },	/* 15 1.72MB 3.5"   */	{  840,10,2,42,1,0x25,0x01,0xDF,0x2E,"h420"  },	/* 16 420KB 5.25"   */	{ 1660,10,2,83,0,0x25,0x02,0xDF,0x2E,"H830"  },	/* 17 830KB 3.5"    */	{ 2988,18,2,83,0,0x25,0x00,0xDF,0x02,"h1494" },	/* 18 1.49MB 5.25"  */	{ 3486,21,2,83,0,0x25,0x00,0xDF,0x0C,"H1743" }, /* 19 1.74 MB 3.5"  */	{ 1760,11,2,80,0,0x1C,0x09,0xCF,0x00,"h880"  }, /* 20 880KB 5.25"   */	{ 2080,13,2,80,0,0x1C,0x01,0xCF,0x00,"D1040" }, /* 21 1.04MB 3.5"   */	{ 2240,14,2,80,0,0x1C,0x19,0xCF,0x00,"D1120" }, /* 22 1.12MB 3.5"   */	{ 3200,20,2,80,0,0x1C,0x20,0xCF,0x2C,"h1600" }, /* 23 1.6MB 5.25"   */	{ 3520,22,2,80,0,0x1C,0x08,0xCF,0x2e,"H1760" }, /* 24 1.76MB 3.5"   */	{ 3840,24,2,80,0,0x1C,0x20,0xCF,0x00,"H1920" }, /* 25 1.92MB 3.5"   */	{ 6400,40,2,80,0,0x25,0x5B,0xCF,0x00,"E3200" }, /* 26 3.20MB 3.5"   */	{ 7040,44,2,80,0,0x25,0x5B,0xCF,0x00,"E3520" }, /* 27 3.52MB 3.5"   */	{ 7680,48,2,80,0,0x25,0x63,0xCF,0x00,"E3840" }, /* 28 3.84MB 3.5"   */	{ 3680,23,2,80,0,0x1C,0x10,0xCF,0x00,"H1840" }, /* 29 1.84MB 3.5"   */	{ 1600,10,2,80,0,0x25,0x02,0xDF,0x2E,"D800"  },	/* 30 800KB 3.5"    */	{ 3200,20,2,80,0,0x1C,0x00,0xCF,0x2C,"H1600" }, /* 31 1.6MB 3.5"    */};#define	NUMBER(x)	(sizeof(x) / sizeof(*(x)))#define SECTSIZE (_FD_SECTSIZE(*floppy))/* Auto-detection: Disk type used until the next media change occurs. */static struct floppy_struct *current_type[N_DRIVE] = {	NULL, NULL, NULL, NULL,	NULL, NULL, NULL, NULL};/* * User-provided type information. current_type points to * the respective entry of this array. */static struct floppy_struct user_params[N_DRIVE];static int floppy_sizes[256];static int floppy_blocksizes[256] = { 0, };/* * The driver is trying to determine the correct media format * while probing is set. rw_interrupt() clears it after a * successful access. */static int probing = 0;/* Synchronization of FDC access. */#define FD_COMMAND_NONE -1#define FD_COMMAND_ERROR 2#define FD_COMMAND_OKAY 3static volatile int command_status = FD_COMMAND_NONE, fdc_busy = 0;static struct wait_queue *fdc_wait = NULL, *command_done = NULL;#ifdef MACHextern int issig (void);#define NO_SIGNAL (! issig () || ! interruptible)#else#define NO_SIGNAL (!(current->signal & ~current->blocked) || !interruptible)#endif#define CALL(x) if ((x) == -EINTR) return -EINTR#define ECALL(x) if ((ret = (x))) return ret;#define _WAIT(x,i) CALL(ret=wait_til_done((x),i))#define WAIT(x) _WAIT((x),interruptible)#define IWAIT(x) _WAIT((x),1)/* Errors during formatting are counted here. */static int format_errors;/* Format request descriptor. */static struct format_descr format_req;/* * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), * H is head unload time (1=16ms, 2=32ms, etc) *//* * Track buffer * Because these are written to by the DMA controller, they must * not contain a 64k byte boundary crossing, or data will be * corrupted/lost. */static char *floppy_track_buffer=0;static int max_buffer_sectors=0;static int *errors;typedef void (*done_f)(int);static struct cont_t {	void (*interrupt)(void); /* this is called after the interrupt of the				  * main command */	void (*redo)(void); /* this is called to retry the operation */	void (*error)(void); /* this is called to tally an error */	done_f done; /* this is called to say if the operation has 		      * succeeded/failed */} *cont=NULL;static void floppy_ready(void);static void floppy_start(void);static void process_fd_request(void);static void recalibrate_floppy(void);static void floppy_shutdown(void);static int floppy_grab_irq_and_dma(void);static void floppy_release_irq_and_dma(void);/* * The "reset" variable should be tested whenever an interrupt is scheduled, * after the commands have been sent. This is to ensure that the driver doesn't * get wedged when the interrupt doesn't come because of a failed command. * reset doesn't need to be tested before sending commands, because * output_byte is automatically disabled when reset is set. */#define CHECK_RESET { if (FDCS->reset){ reset_fdc(); return; } }static void reset_fdc(void);

⌨️ 快捷键说明

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