📄 floppy.c
字号:
/* * linux/drivers/block/floppy.c * * Copyright (C) 1991, 1992 Linus Torvalds * Copyright (C) 1993, 1994 Alain Knaff * Copyright (C) 1998 Alan Cox *//* * 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. *//* * 1998/05/07 -- Russell King -- More portability cleanups; moved definition of * interrupt and dma channel to asm/floppy.h. Cleaned up some formatting & * use of '0' for NULL. */ /* * 1998/06/07 -- Alan Cox -- Merged the 2.0.34 fixes for resource allocation * failures. *//* * 1998/09/20 -- David Weinehall -- Added slow-down code for buggy PS/2-drives. *//* * 1999/08/13 -- Paul Slootman -- floppy stopped working on Alpha after 24 * days, 6 hours, 32 minutes and 32 seconds (i.e. MAXINT jiffies; ints were * being used to store jiffies, which are unsigned longs). *//* * 2000/08/28 -- Arnaldo Carvalho de Melo <acme@conectiva.com.br> * - get rid of check_region * - s/suser/capable/ *//* * 2001/08/26 -- Paul Gortmaker - fix insmod oops on machines with no * floppy controller (lingering task on list after module is gone... boom.) */#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/module.h>#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>/* * 1998/1/21 -- Richard Gooch <rgooch@atnf.csiro.au> -- devfs support */#include <linux/fd.h>#include <linux/hdreg.h>#include <linux/errno.h>#include <linux/slab.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 <linux/init.h>#include <linux/devfs_fs_kernel.h>/* * PS/2 floppies have much slower step rates than regular floppies. * It's been recommended that take about 1/4 of the default speed * in some more extreme cases. */static int slow_floppy;#include <asm/dma.h>#include <asm/irq.h>#include <asm/system.h>#include <asm/io.h>#include <asm/uaccess.h>static int FLOPPY_IRQ=6;static int FLOPPY_DMA=2;static int can_use_virtual_dma=2;/* ======= * can use virtual DMA: * 0 = use of virtual DMA disallowed by config * 1 = use of virtual DMA prescribed by config * 2 = no virtual DMA preference configured. By default try hard DMA, * but fall back on virtual DMA when not enough memory available */static int use_virtual_dma;/* ======= * use virtual DMA * 0 using hard DMA * 1 using virtual DMA * This variable is set to virtual when a DMA mem problem arises, and * reset back in floppy_grab_irq_and_dma. * It is not safe to reset it in other circumstances, because the floppy * driver may have several buffers in use at once, and we do currently not * record each buffers capabilities */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 void register_devfs_entries (int drive) __init;static devfs_handle_t devfs_handle;#define K_64 0x10000 /* 64KB *//* 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. * * NOTE: This must come before we include the arch floppy header because * some ports reference this variable from there. -DaveM */static int allowed_drive_mask = 0x33;#include <asm/floppy.h>static int irqdma_allocated;#define MAJOR_NR FLOPPY_MAJOR#include <linux/blk.h>#include <linux/blkpg.h>#include <linux/cdrom.h> /* for the compatibility eject ioctl */#ifndef fd_get_dma_residue#define fd_get_dma_residue() get_dma_residue(FLOPPY_DMA)#endif/* Dma Memory related stuff */#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))#endifstatic inline void fallback_on_nodma_alloc(char **addr, size_t l){#ifdef FLOPPY_CAN_FALLBACK_ON_NODMA if (*addr) return; /* we have the memory */ if (can_use_virtual_dma != 2) return; /* no fallback allowed */ printk("DMA memory shortage. Temporarily falling back on virtual DMA\n"); *addr = (char *) nodma_mem_alloc(l);#else return;#endif}/* End dma memory related stuff */static unsigned long fake_change;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)))/* 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*//* * 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)/* * 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 timer_list motor_off_timer[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)). *//* Size | Sectors per track | | Head | | | Tracks | | | | Stretch | | | | | Gap 1 size | | | | | | Data rate, | 0x40 for perp | | | | | | | Spec1 (stepping rate, head unload | | | | | | | | /fmt gap (gap2) */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];/* * 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];/* * 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;/* 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;static unsigned long fdc_busy;static DECLARE_WAIT_QUEUE_HEAD(fdc_wait);static DECLARE_WAIT_QUEUE_HEAD(command_done);#define NO_SIGNAL (!interruptible || !signal_pending(current))#define CALL(x) if ((x) == -EINTR) return -EINTR
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -