📄 floppy.c
字号:
/* * 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 + -