summaryrefslogtreecommitdiffstats
path: root/drivers/block/floppy.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/block/floppy.c')
-rw-r--r--drivers/block/floppy.c680
1 files changed, 512 insertions, 168 deletions
diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c
index 7dc0ba4e1..e1501385f 100644
--- a/drivers/block/floppy.c
+++ b/drivers/block/floppy.c
@@ -81,9 +81,11 @@
* errors to allow safe writing by specialized programs.
*/
+/* 1995/8/26 -- Andreas Busse -- added Mips support.
+ * Needs some more cleanup, but seems to work so far.
+ */
+
#define CONFIG_FLOPPY_SANITY
-#undef CONFIG_FLOPPY_23
-#undef CONFIG_FLOPPY_2_FDC
#undef CONFIG_FLOPPY_SILENT_DCL_CLEAR
#define REALLY_SLOW_IO
@@ -93,27 +95,25 @@
#include <linux/config.h>
+/* do print messages for unexpected interrupts */
+static int print_unex=1;
+
#ifndef FD_MODULE
/* 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. */
-#ifdef CONFIG_FLOPPY_23
-#define ALLOWED_DRIVE_MASK 0xff
-#else
-#define ALLOWED_DRIVE_MASK 0x33
-#endif
+static int ALLOWED_DRIVE_MASK=0x33;
#define FLOPPY_IRQ 6
#define FLOPPY_DMA 2
#define FDC1 0x3f0
-#define FDC2 0x370
+static int FDC2=-1;
#endif
#define MODULE_AWARE_DRIVER
-#ifdef CONFIG_BLK_DEV_FD
#include <linux/sched.h>
#include <linux/fs.h>
#include <linux/kernel.h>
@@ -127,6 +127,7 @@
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/delay.h>
+#include <linux/mc146818rtc.h> /* CMOS defines */
#include <asm/dma.h>
#include <asm/irq.h>
@@ -140,15 +141,44 @@
static unsigned int fake_change = 0;
static int initialising=1;
+#define FLOPPY0_TYPE ((CMOS_READ(0x10) >> 4) & 15)
+#define FLOPPY1_TYPE (CMOS_READ(0x10) & 15)
-#ifdef CONFIG_FLOPPY_2_FDC
#define N_FDC 2
#define N_DRIVE 8
-#else
-#define N_FDC 1
-#define N_DRIVE 4
+
+/*
+ * Again, the CMOS information doesn't work on the alpha..
+ */
+#ifdef __alpha__
+#undef FLOPPY0_TYPE
+#undef FLOPPY1_TYPE
+#define FLOPPY0_TYPE 6
+#define FLOPPY1_TYPE 0
#endif
+/*
+ * And on Mips's it doesn't work too.
+ */
+#ifdef __mips__
+#include <asm/bootinfo.h>
+#include <asm/mipsconfig.h>
+#include <asm/jazz.h>
+#include <asm/jazzdma.h>
+#include <asm/cachectl.h>
+#undef FLOPPY0_TYPE
+#undef FLOPPY1_TYPE
+#undef FDC1
+#define FLOPPY0_TYPE 4 /* this is wrong for the Olli M700, but who cares... */
+#define FLOPPY1_TYPE 0
+#define FDC1 ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000 || \
+ boot_info.machtype == MACH_OLIVETTI_M700) ? \
+ 0xe0003000 : PORT_BASE + 0x3f0)
+#undef N_FDC
+#define N_FDC 1 /* do you *really* want a second controller ? */
+#endif /* __mips__ */
+
#define TYPE(x) ( ((x)>>2) & 0x1f )
#define DRIVE(x) ( ((x)&0x03) | (((x)&0x80 ) >> 5))
#define UNIT(x) ( (x) & 0x03 ) /* drive on fdc */
@@ -171,16 +201,16 @@ static int initialising=1;
#define USETF(x) (set_bit(x##_BIT, &UDRS->flags))
#define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags))
-#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive);
+#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive)
#define DPRINT1(x,x1) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1))
#define DPRINT2(x,x1,x2) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2))
#define DPRINT3(x,x1,x2,x3) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3))
/* read/write */
#define COMMAND raw_cmd.cmd[0]
@@ -217,6 +247,8 @@ printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3));
* Went back to the 1MB limit, as some people had problems with the floppy
* driver otherwise. It doesn't matter much for performance anyway, as most
* floppy accesses go through the track buffer.
+ * On MIPSes, this actually means that *all* transfers go thru the
+ * track buffer since 0x1000000 is always smaller than KSEG0/1.
*/
#define LAST_DMA_ADDR (0x1000000)
#define K_64 (0x10000) /* 64 k */
@@ -236,6 +268,9 @@ static int inr; /* size of reply buffer, when called from interrupt */
#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.
*/
@@ -249,38 +284,38 @@ static struct {
| | 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, 100, 300, 0, 2, 5, 80, 3*HZ, 20, {3,1,2,0,2}, 0,
- 0, { 7, 4, 8, 2, 1, 5, 3,10}, 150, 0 }, "unknown" },
-
-{{1, 300, 16, 16, 8000, 100, 300, 0, 2, 5, 40, 3*HZ, 17, {3,1,2,0,2}, 0,
- 0, { 1, 0, 0, 0, 0, 0, 0, 0}, 150, 1 }, "360K PC" }, /*5 1/4 360 KB PC*/
-
-{{2, 500, 16, 16, 6000, 40, 300, 14, 2, 6, 83, 3*HZ, 17, {3,1,2,0,2}, 0,
- 0, { 2, 5, 6,23,10,20,11, 0}, 150, 2 }, "1.2M" }, /*5 1/4 HD AT*/
-
-{{3, 250, 16, 16, 3000, 100, 300, 0, 2, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
- 0, { 4,22,21,30, 3, 0, 0, 0}, 150, 4 }, "720k" }, /*3 1/2 DD*/
-
-{{4, 500, 16, 16, 4000, 40, 300, 10, 2, 5, 83, 3*HZ, 20, {3,1,2,0,2}, 0,
- 0, { 7, 4,25,22,31,21,29,11}, 150, 7 }, "1.44M" }, /*3 1/2 HD*/
-
-{{5, 1000, 15, 8, 3000, 40, 300, 10, 2, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
- 0, { 7, 8, 4,25,28,22,31,21}, 150, 8 }, "2.88M AMI BIOS" }, /*3 1/2 ED*/
-
-{{6, 1000, 15, 8, 3000, 40, 300, 10, 2, 5, 83, 3*HZ, 40, {3,1,2,0,2}, 0,
- 0, { 7, 8, 4,25,28,22,31,21}, 150, 8 }, "2.88M" } /*3 1/2 ED*/
-/* | ---autodetected formats-- | | |
- read_track | | Name printed when booting
- | Native format
+ | | | | | 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,11, 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 */
};
@@ -339,11 +374,8 @@ static struct floppy_struct floppy_type[32] = {
/* Auto-detection: Disk type used until the next media change occurs. */
struct floppy_struct *current_type[N_DRIVE] = {
+ NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL
-#ifdef CONFIG_FLOPPY_2_FDC
- ,
- NULL, NULL, NULL, NULL
-#endif
};
/*
@@ -480,6 +512,107 @@ static inline void debugt(char *message)
}
/*
+ * Port access functions
+ */
+
+#ifdef CONFIG_MIPS_JAZZ
+static inline unsigned int fd_in(unsigned int port)
+{
+ if (port >= JAZZ_LOCAL_IO_SPACE) {
+ return (*(volatile unsigned char *)port);
+ udelay(1);
+ }
+ else
+ return inb_p(port);
+}
+
+static inline void fd_out(unsigned char value, unsigned int port)
+{
+ if (port >= JAZZ_LOCAL_IO_SPACE) {
+ *(volatile unsigned char *)port = value;
+ udelay(1);
+ }
+ else
+ outb_p(value, port);
+}
+#else /* !CONFIG_MIPS_JAZZ */
+#define fd_in(port) inb_p(port)
+#define fd_out(port,value) outb_p(port,value)
+#endif
+
+/*
+ * DMA control stuff. If MIPS_JAZZ support is compiled in, we have to
+ * check if we're running on such a board. If not, we just call the
+ * standard PC macros and functions.
+ */
+
+#ifdef CONFIG_MIPS_JAZZ
+#define fd_enable_dma() ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ vdma_enable(JAZZ_FLOPPY_DMA) : \
+ enable_dma(FLOPPY_DMA))
+#define fd_disable_dma() ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ vdma_disable(JAZZ_FLOPPY_DMA) : \
+ disable_dma(FLOPPY_DMA))
+#define fd_request_dma() ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ 0 : request_dma(FLOPPY_DMA,"floppy"))
+#define fd_free_dma() ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ : free_dma(FLOPPY_DMA))
+#define fd_clear_dma_ff() ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ : clear_dma_ff(FLOPPY_DMA))
+#define fd_set_dma_mode(mode) ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ vdma_set_mode(JAZZ_FLOPPY_DMA,mode) : \
+ set_dma_mode(FLOPPY_DMA,mode))
+#define fd_set_dma_addr(addr) ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ vdma_set_addr(JAZZ_FLOPPY_DMA, \
+ vdma_phys2log(PHYSADDR(addr))) : \
+ set_dma_addr(FLOPPY_DMA,addr))
+#define fd_set_dma_count(count) ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ vdma_set_count(JAZZ_FLOPPY_DMA,count) : \
+ set_dma_count(FLOPPY_DMA,count))
+#define fd_get_dma_residue() ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ vdma_get_residue(JAZZ_FLOPPY_DMA) : \
+ get_dma_residue(FLOPPY_DMA))
+#define fd_enable_irq() ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ : enable_irq(FLOPPY_IRQ))
+#define fd_disable_irq() ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ : disable_irq(FLOPPY_IRQ))
+#define fd_cacheflush(addr,size) \
+ ((boot_info.machtype == MACH_ACER_PICA_61 || \
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000) ? \
+ sys_cacheflush((char *)addr, size, DCACHE) : empty() )
+#else
+#define fd_enable_dma() enable_dma(FLOPPY_DMA)
+#define fd_disable_dma() disable_dma(FLOPPY_DMA)
+#define fd_request_dma() request_dma(FLOPPY_DMA,"floppy")
+#define fd_free_dma() free_dma(FLOPPY_DMA)
+#define fd_clear_dma_ff() clear_dma_ff(FLOPPY_DMA)
+#define fd_set_dma_mode(mode) set_dma_mode(FLOPPY_DMA,mode)
+#define fd_set_dma_addr(addr) set_dma_addr(FLOPPY_DMA,addr)
+#define fd_set_dma_count(count) set_dma_count(FLOPPY_DMA,count)
+#define fd_enable_irq() enable_irq(FLOPPY_IRQ)
+#define fd_disable_irq() disable_irq(FLOPPY_IRQ)
+#define fd_cacheflush(addr,size) /* nothing */
+#endif
+
+/* Just for coherency */
+
+#define fd_request_irq() request_irq(FLOPPY_IRQ, floppy_interrupt, \
+ SA_INTERRUPT, "floppy")
+#define fd_free_irq() free_irq(FLOPPY_IRQ);
+
+
+/*
* Bottom half floppy driver.
* ==========================
*
@@ -531,13 +664,13 @@ static int disk_change(int drive)
if (UDP->flags & FD_DEBUG){
DPRINT1("checking disk change line for drive %d\n",drive);
DPRINT1("jiffies=%ld\n", jiffies);
- DPRINT1("disk change line=%x\n",inb_p(FD_DIR)&0x80);
+ DPRINT1("disk change line=%x\n",fd_in(FD_DIR)&0x80);
DPRINT1("flags=%x\n",UDRS->flags);
}
#endif
if (UDP->flags & FD_BROKEN_DCL)
return UTESTF(FD_DISK_CHANGED);
- if( (inb_p(FD_DIR) ^ UDP->flags) & 0x80){
+ if( (fd_in(FD_DIR) ^ UDP->flags) & 0x80){
USETF(FD_VERIFY); /* verify write protection */
if(UDRS->maxblock){
/* mark it changed */
@@ -555,7 +688,7 @@ static int disk_change(int drive)
}
/*USETF(FD_DISK_NEWCHANGE);*/
return 1;
- } else if(jiffies >= DRS->select_date+DP->select_delay){
+ } else {
UDRS->last_checked=jiffies;
UCLEARF(FD_DISK_NEWCHANGE);
}
@@ -588,7 +721,8 @@ static int set_dor(int fdc, char mask, char data)
disk_change(drive);
}
FDCS->dor = newdor;
- outb_p(newdor, FD_DOR);
+/* printk("setting DOR to %02x\n",(unsigned)newdor); */
+ fd_out(newdor, FD_DOR);
unit = newdor & 0x3;
if(!is_selected(olddor, unit) && is_selected(newdor,unit)){
@@ -607,8 +741,8 @@ static void twaddle(void)
{
if (DP->select_delay)
return;
- outb_p(FDCS->dor & ~(0x10<<UNIT(current_drive)),FD_DOR);
- outb_p(FDCS->dor, FD_DOR);
+ fd_out(FDCS->dor & ~(0x10<<UNIT(current_drive)),FD_DOR);
+ fd_out(FDCS->dor, FD_DOR);
DRS->select_date = jiffies;
}
@@ -636,12 +770,10 @@ static void set_fdc(int drive)
current_drive = drive;
}
set_dor(fdc,~0,8);
-#ifdef CONFIG_FLOPPY_2_FDC
set_dor(1-fdc, ~8, 0);
-#endif
if ( FDCS->rawcmd == 2 )
reset_fdc_info(1);
- if( inb_p(FD_STATUS) != STATUS_READY )
+ if( fd_in(FD_STATUS) != STATUS_READY )
FDCS->reset = 1;
}
@@ -704,14 +836,11 @@ static struct timer_list motor_off_timer[N_DRIVE] = {
{ NULL, NULL, 0, 0, motor_off_callback },
{ NULL, NULL, 0, 1, motor_off_callback },
{ NULL, NULL, 0, 2, motor_off_callback },
- { NULL, NULL, 0, 3, motor_off_callback }
-#ifdef CONFIG_FLOPPY_2_FDC
- ,
+ { NULL, NULL, 0, 3, motor_off_callback },
{ NULL, NULL, 0, 4, motor_off_callback },
{ NULL, NULL, 0, 5, motor_off_callback },
{ NULL, NULL, 0, 6, motor_off_callback },
{ NULL, NULL, 0, 7, motor_off_callback }
-#endif
};
/* schedules motor off */
@@ -812,9 +941,50 @@ static int wait_for_completion(int delay, timeout_fn function)
return 0;
}
+static int hlt_disabled=0;
+static void floppy_disable_hlt(void)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ if(!hlt_disabled){
+ hlt_disabled=1;
+#ifdef HAVE_DISABLE_HLT
+ disable_hlt();
+#endif
+ }
+ restore_flags(flags);
+}
+
+static void floppy_enable_hlt(void)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+ if(hlt_disabled){
+ hlt_disabled=0;
+#ifdef HAVE_DISABLE_HLT
+ enable_hlt();
+#endif
+ }
+ restore_flags(flags);
+}
+
+
static void setup_DMA(void)
{
#ifdef CONFIG_FLOPPY_SANITY
+ if (raw_cmd.length == 0){
+ int i;
+
+ printk("zero dma transfer size:");
+ for(i=0; i< raw_cmd.cmd_count; i++)
+ printk("%x,", raw_cmd.cmd[i]);
+ printk("\n");
+ cont->done(0);
+ FDCS->reset = 1;
+ return;
+ }
if ((!CURRENT ||
CURRENT->buffer != current_addr ||
raw_cmd.length > 512 * CURRENT->nr_sectors) &&
@@ -832,14 +1002,14 @@ static void setup_DMA(void)
FDCS->reset=1;
return;
}
- if ((long) current_addr % 512 ){
+ if ((unsigned long) current_addr % 512 ){
printk("non aligned address: %p\n", current_addr );
cont->done(0);
FDCS->reset=1;
return;
}
- if ( ( (long)current_addr & ~(64*1024-1) ) !=
- ((long)(current_addr + raw_cmd.length-1) & ~(64*1024-1))){
+ if ( ( (unsigned long)current_addr & ~(64*1024-1) ) !=
+ ((unsigned long)(current_addr + raw_cmd.length-1) & ~(64*1024-1))){
printk("DMA crossing 64-K boundary %p-%p\n",
current_addr, current_addr + raw_cmd.length);
cont->done(0);
@@ -849,15 +1019,15 @@ static void setup_DMA(void)
#endif
cli();
- disable_dma(FLOPPY_DMA);
- clear_dma_ff(FLOPPY_DMA);
- set_dma_mode(FLOPPY_DMA,
- (raw_cmd.flags & FD_RAW_READ)?
- DMA_MODE_READ : DMA_MODE_WRITE);
- set_dma_addr(FLOPPY_DMA, (long) current_addr);
- set_dma_count(FLOPPY_DMA, raw_cmd.length);
- enable_dma(FLOPPY_DMA);
+ fd_disable_dma();
+ fd_clear_dma_ff();
+ fd_set_dma_mode((raw_cmd.flags & FD_RAW_READ)?
+ DMA_MODE_READ : DMA_MODE_WRITE);
+ fd_set_dma_addr((long) current_addr);
+ fd_set_dma_count(raw_cmd.length);
+ fd_enable_dma();
sti();
+ floppy_disable_hlt();
}
/* sends a command byte to the fdc */
@@ -868,12 +1038,13 @@ static int output_byte(char byte)
if (FDCS->reset)
return -1;
- for(counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
- status = inb_p(FD_STATUS) &(STATUS_READY|STATUS_DIR|STATUS_DMA);
+/* for(counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) { */
+ for(counter = 0 ; counter < 100000 && !FDCS->reset ; counter++) {
+ status = fd_in(FD_STATUS) &(STATUS_READY|STATUS_DIR|STATUS_DMA);
if (!(status & STATUS_READY))
continue;
if (status == STATUS_READY){
- outb_p(byte,FD_DATA);
+ fd_out(byte,FD_DATA);
return 0;
} else
break;
@@ -894,7 +1065,7 @@ static int result(void)
if (FDCS->reset)
return -1;
for (counter = 0 ; counter < 10000 && !FDCS->reset ; counter++) {
- status = inb_p(FD_STATUS)&
+ status = fd_in(FD_STATUS)&
(STATUS_DIR|STATUS_READY|STATUS_BUSY|STATUS_DMA);
if (!(status & STATUS_READY))
continue;
@@ -907,7 +1078,7 @@ static int result(void)
DPRINT("floppy_stat reply overrun\n");
break;
}
- reply_buffer[i++] = inb_p(FD_DATA);
+ reply_buffer[i++] = fd_in(FD_DATA);
}
}
FDCS->reset = 1;
@@ -993,7 +1164,7 @@ static void fdc_specify(void)
/* TODO: lock this in via LOCK during initialization */
output_byte(FD_CONFIGURE);
output_byte(0);
- output_byte(0x1A); /* FIFO on, polling off, 10 byte threshold */
+ output_byte(0x2A); /* FIFO on, polling off, 10 byte threshold */
output_byte(0); /* precompensation from track 0 upwards */
if ( FDCS->reset ){
FDCS->has_fifo=0;
@@ -1063,7 +1234,7 @@ static int fdc_dtr(void)
return 0;
/* Set dtr */
- outb_p(raw_cmd.rate, FD_DCR);
+ fd_out(raw_cmd.rate, FD_DCR);
/* TODO: some FDC/drive combinations (C&T 82C711 with TEAC 1.2MB)
* need a stabilization period of several milliseconds to be
@@ -1398,18 +1569,22 @@ static void unexpected_floppy_interrupt(void)
int i;
if ( initialising )
return;
- DPRINT("unexpected interrupt\n");
- if ( inr >= 0 )
- for(i=0; i<inr; i++)
- printk("%d %x\n", i, reply_buffer[i] );
+ if(print_unex){
+ DPRINT("unexpected interrupt\n");
+ if ( inr >= 0 )
+ for(i=0; i<inr; i++)
+ printk("%d %x\n", i, reply_buffer[i] );
+ }
while(1){
output_byte(FD_SENSEI);
inr=result();
if ( inr != 2 )
break;
- printk("sensei\n");
- for(i=0; i<inr; i++)
- printk("%d %x\n", i, reply_buffer[i] );
+ if(print_unex){
+ printk("sensei\n");
+ for(i=0; i<inr; i++)
+ printk("%d %x\n", i, reply_buffer[i] );
+ }
}
FDCS->reset = 1;
}
@@ -1418,10 +1593,11 @@ struct tq_struct floppy_tq =
{ 0, 0, (void *) (void *) unexpected_floppy_interrupt, 0 };
/* interrupt handler */
-static void floppy_interrupt(int unused)
+static void floppy_interrupt(int irq, struct pt_regs * regs)
{
void (*handler)(void) = DEVICE_INTR;
+ floppy_enable_hlt();
CLEAR_INTR;
if ( fdc >= N_FDC || FDCS->address == -1){
/* we don't even know which FDC is the culprit */
@@ -1476,15 +1652,16 @@ static void reset_interrupt(void)
*/
static void reset_fdc(void)
{
+/* printk("in reset_fdc()\n"); */
SET_INTR(reset_interrupt);
FDCS->reset = 0;
reset_fdc_info(0);
if ( FDCS->version >= FDC_82077 )
- outb_p(0x80 | ( FDCS->dtr &3), FD_STATUS);
+ fd_out(0x80 | ( FDCS->dtr &3), FD_STATUS);
else {
- outb_p(FDCS->dor & ~0x04, FD_DOR);
+ fd_out(FDCS->dor & ~0x04, FD_DOR);
udelay(FD_RESET_DELAY);
- outb(FDCS->dor, FD_DOR);
+ fd_out(FDCS->dor, FD_DOR);
}
}
@@ -1500,11 +1677,13 @@ void show_floppy(void)
printk("floppy driver state\n");
printk("-------------------\n");
for(i=0; i<N_FDC; i++){
- printk("dor %d = %x\n", i, fdc_state[i].dor );
- outb_p(fdc_state[i].address+2, fdc_state[i].dor);
- udelay(1000); /* maybe we'll catch an interrupt... */
+ if(FDCS->address != -1){
+ printk("dor %d = %x\n", i, fdc_state[i].dor );
+ fd_out(fdc_state[i].address+2, fdc_state[i].dor);
+ udelay(1000); /* maybe we'll catch an interrupt... */
+ }
}
- printk("status=%x\n", inb_p(FD_STATUS));
+ printk("status=%x\n", fd_in(FD_STATUS));
printk("fdc_busy=%d\n", fdc_busy);
if( DEVICE_INTR)
printk("DEVICE_INTR=%p\n", DEVICE_INTR);
@@ -1529,7 +1708,8 @@ static void floppy_shutdown(void)
floppy_tq.routine = (void *)(void *) empty;
del_timer( &fd_timer);
- disable_dma(FLOPPY_DMA);
+ floppy_enable_hlt();
+ fd_disable_dma();
/* avoid dma going to a random drive after shutdown */
if(!initialising)
@@ -1710,9 +1890,10 @@ static void failure_and_wakeup(void)
static int next_valid_format(void)
{
int probed_format;
+
+ probed_format = DRS->probed_format;
while(1){
- probed_format = DRS->probed_format;
- if ( probed_format > N_DRIVE ||
+ if ( probed_format >= 8 ||
! DP->autodetect[probed_format] ){
DRS->probed_format = 0;
return 1;
@@ -2098,7 +2279,7 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
floppy_track_buffer + (max_buffer_sectors << 10) ||
dma_buffer < floppy_track_buffer ){
DPRINT1("buffer overrun in copy buffer %d\n",
- (floppy_track_buffer - dma_buffer) >>9);
+ (int) ((floppy_track_buffer - dma_buffer) >>9));
printk("sector_t=%d buffer_min=%d\n",
sector_t, buffer_min);
printk("current_count_sectors=%ld\n",
@@ -2109,13 +2290,17 @@ static void copy_buffer(int ssize, int max_sector, int max_sector_2)
printk("write\n");
break;
}
- if ( ((int)buffer) % 512 )
+ if ( ((unsigned long)buffer) % 512 )
DPRINT1("%p buffer not aligned\n", buffer);
#endif
- if ( CT(COMMAND) == FD_READ )
+ if ( CT(COMMAND) == FD_READ ) {
+ fd_cacheflush(dma_buffer, size);
memcpy( buffer, dma_buffer, size);
- else
+ }
+ else {
memcpy( dma_buffer, buffer, size);
+ fd_cacheflush(dma_buffer, size);
+ }
remaining -= size;
if ( !remaining)
break;
@@ -2246,19 +2431,19 @@ static int make_raw_rw_request(void)
raw_cmd.flags &= ~FD_RAW_WRITE;
raw_cmd.flags |= FD_RAW_READ;
COMMAND = FM_MODE(floppy,FD_READ);
- } else if ((long)CURRENT->buffer <= LAST_DMA_ADDR ) {
+ } else if ((unsigned long)CURRENT->buffer <= LAST_DMA_ADDR ) {
int direct, indirect;
indirect= transfer_size(ssize,max_sector,max_buffer_sectors*2) -
sector_t;
max_size = buffer_chain_size();
- if ( max_size > ( LAST_DMA_ADDR - ((long) CURRENT->buffer))>>9)
- max_size=(LAST_DMA_ADDR - ((long)CURRENT->buffer))>>9;
+ if ( max_size > ( LAST_DMA_ADDR - ((unsigned long) CURRENT->buffer))>>9)
+ max_size=(LAST_DMA_ADDR - ((unsigned long)CURRENT->buffer))>>9;
/* 64 kb boundaries */
- if ( ((max_size << 9) + ((long) CURRENT->buffer)) / K_64 !=
- ((long) CURRENT->buffer ) / K_64 )
- max_size = ( K_64 - ((long) CURRENT->buffer) % K_64)>>9;
+ if ( ((max_size << 9) + ((unsigned long) CURRENT->buffer)) / K_64 !=
+ ((unsigned long) CURRENT->buffer ) / K_64 )
+ max_size = ( K_64 - ((unsigned long) CURRENT->buffer) % K_64)>>9;
direct = transfer_size(ssize,max_sector,max_size) - sector_t;
/*
* We try to read tracks, but if we get too many errors, we
@@ -2267,15 +2452,21 @@ static int make_raw_rw_request(void)
* This means we should be able to read a sector even if there
* are other bad sectors on this track.
*/
- if ((indirect - sector_t) * 2 > (direct - sector_t) * 3 &&
- *errors < DP->max_errors.read_track &&
- /*!TESTF( FD_NEED_TWADDLE) &&*/
- ( ( !probing || (DP->read_track &
- (1 <<DRS->probed_format))))){
+ if (!direct ||
+ (indirect * 2 > direct * 3 &&
+ *errors < DP->max_errors.read_track &&
+ /*!TESTF( FD_NEED_TWADDLE) &&*/
+ ((!probing || (DP->read_track&(1<<DRS->probed_format)))))){
max_size = CURRENT->nr_sectors;
} else {
current_addr = CURRENT->buffer;
raw_cmd.length = current_count_sectors << 9;
+ if (raw_cmd.length == 0){
+ DPRINT("zero dma transfer attempted from make_raw_request\n");
+ DPRINT3("indirect=%d direct=%d sector_t=%d",
+ indirect, direct, sector_t);
+ return 0;
+ }
return 2;
}
}
@@ -2286,6 +2477,7 @@ static int make_raw_rw_request(void)
/* claim buffer track if needed */
if (buffer_track != raw_cmd.track || /* bad track */
buffer_drive !=current_drive || /* bad drive */
+ sector_t > buffer_max ||
sector_t < buffer_min ||
((CT(COMMAND) == FD_READ ||
(aligned_sector_t == sector_t && CURRENT->nr_sectors >= ssize ))&&
@@ -2330,7 +2522,7 @@ static int make_raw_rw_request(void)
raw_cmd.length, current_count_sectors);
if ( current_addr != CURRENT->buffer )
printk("addr=%d, length=%ld\n",
- (current_addr - floppy_track_buffer ) >> 9,
+ (int) ((current_addr - floppy_track_buffer ) >> 9),
current_count_sectors);
printk("st=%d ast=%d mse=%d msi=%d\n",
sector_t, aligned_sector_t, max_sector, max_size);
@@ -2371,6 +2563,10 @@ static int make_raw_rw_request(void)
printk("bytes=%ld\n", raw_cmd.length >> 9 );
printk("sectors=%ld\n", current_count_sectors);
}
+ if (raw_cmd.length == 0){
+ DPRINT("zero dma transfer attempted from make_raw_request\n");
+ return 0;
+ }
#endif
return 2;
}
@@ -2551,6 +2747,9 @@ static int fd_copyout(void *param, volatile void *address, int size)
i = verify_area(VERIFY_WRITE,param,size);
if (i)
return i;
+ fd_cacheflush(address, size); /* is this necessary ??? */
+ /* Ralf: Yes; only the l2 cache is completly chipset
+ controlled */
memcpy_tofs(param,(void *) address, size);
return 0;
}
@@ -2612,6 +2811,10 @@ static int raw_cmd_ioctl(void *param)
if (raw_cmd.flags & (FD_RAW_WRITE | FD_RAW_READ)){
if(count > max_buffer_sectors * 1024 )
return -ENOMEM;
+ if(count == 0){
+ printk("attempt to do a 0 byte dma transfer\n");
+ return -EINVAL;
+ }
buffer_track = -1;
}
if ( raw_cmd.flags & FD_RAW_WRITE ){
@@ -2619,6 +2822,7 @@ static int raw_cmd_ioctl(void *param)
if (i)
return i;
memcpy_fromfs(floppy_track_buffer, raw_cmd.data, count);
+ fd_cacheflush(floppy_track_buffer, count);
}
current_addr = floppy_track_buffer;
@@ -2649,6 +2853,7 @@ static int raw_cmd_ioctl(void *param)
return ret;
if ( raw_cmd.flags & FD_RAW_READ ){
+ fd_cacheflush(floppy_track_buffer, count);
i=fd_copyout( raw_cmd.data, floppy_track_buffer, count);
if (i)
return i;
@@ -2784,9 +2989,7 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
cnt < (type << 2 ) + 4 ;
cnt++)
floppy_sizes[cnt]=
-#ifdef CONFIG_FLOPPY_2_FDC
floppy_sizes[cnt+0x80]=
-#endif
floppy_type[type].size>>1;
process_fd_request();
for ( cnt = 0; cnt < N_DRIVE; cnt++){
@@ -2854,41 +3057,44 @@ static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd,
#undef IOCTL_ALLOWED
}
-#define CMOS_READ(addr) ({ \
-outb_p(addr,0x70); \
-inb_p(0x71); \
-})
-
-static void set_base_type(int drive,int code)
-{
- if (code > 0 && code <= NUMBER(default_drive_params)) {
- memcpy((char *) UDP,
- (char *) (&default_drive_params[code].params),
- sizeof( struct floppy_drive_params ));
- printk("fd%d is %s", drive, default_drive_params[code].name);
- return;
- } else if (!code)
- printk("fd%d is not installed", drive);
- else
- printk("fd%d is unknown type %d",drive,code);
-}
-
static void config_types(void)
{
+ int first=1;
int drive;
- for (drive=0; drive<N_DRIVE ; drive++){
- /* default type for unidentifiable drives */
- memcpy((char *) UDP, (char *) (&default_drive_params->params),
- sizeof( struct floppy_drive_params ));
- }
- printk("Floppy drive(s): ");
- set_base_type(0, (CMOS_READ(0x10) >> 4) & 15);
- if (CMOS_READ(0x10) & 15) {
- printk(", ");
- set_base_type(1, CMOS_READ(0x10) & 15);
+ /* read drive info out of physical cmos */
+ drive=0;
+ if (!UDP->cmos )
+ UDP->cmos= FLOPPY0_TYPE;
+ drive=1;
+ if (!UDP->cmos && FLOPPY1_TYPE)
+ UDP->cmos = FLOPPY1_TYPE;
+
+ /* XXX */
+ /* additional physical CMOS drive detection should go here */
+
+ for (drive=0; drive < N_DRIVE; drive++){
+ if (UDP->cmos >= 0 && UDP->cmos <= NUMBER(default_drive_params))
+ memcpy((char *) UDP,
+ (char *) (&default_drive_params[(int)UDP->cmos].params),
+ sizeof(struct floppy_drive_params));
+ if (UDP->cmos){
+ if (first)
+ printk("Floppy drive(s): ");
+ else
+ printk(", ");
+ first=0;
+ if (UDP->cmos > 0 ){
+ ALLOWED_DRIVE_MASK |= 1 << drive;
+ printk("fd%d is %s", drive,
+ default_drive_params[(int)UDP->cmos].name);
+ } else
+ printk("fd%d is unknown type %d",drive,
+ UDP->cmos);
+ }
}
- printk("\n");
+ if(!first)
+ printk("\n");
}
static int floppy_read(struct inode * inode, struct file * filp,
@@ -3000,7 +3206,7 @@ static int floppy_open(struct inode * inode, struct file * filp)
}
/* Allow ioctls if we have write-permissions even if read-only open */
- if ((filp->f_mode & 2) || permission(inode,2))
+ if ((filp->f_mode & 2) || (permission(inode,2) == 0))
filp->f_mode |= IOCTL_MODE_BIT;
if (filp->f_mode & 2)
filp->f_mode |= OPEN_WRITE_BIT;
@@ -3163,6 +3369,130 @@ static char get_fdc_version(void)
return FDC_82077; /* Revised 82077AA passes all the tests */
} /* get_fdc_version */
+/* lilo configuration */
+
+/* we make the invert_dcl function global. One day, somebody might
+want to centralize all thinkpad related options into one lilo option,
+there are just so many thinkpad related quirks! */
+void floppy_invert_dcl(int *ints,int param)
+{
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
+ if (param)
+ default_drive_params[i].params.flags |= 0x80;
+ else
+ default_drive_params[i].params.flags &= ~0x80;
+ }
+ DPRINT("Configuring drives for inverted dcl\n");
+}
+
+static void daring(int *ints,int param)
+{
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
+ if (param){
+ default_drive_params[i].params.select_delay = 0;
+ default_drive_params[i].params.flags |= FD_SILENT_DCL_CLEAR;
+ } else {
+ default_drive_params[i].params.select_delay = 2*HZ/100;
+ default_drive_params[i].params.flags &= ~FD_SILENT_DCL_CLEAR;
+ }
+ }
+ DPRINT1("Assuming %s floppy hardware\n", param ? "standard" : "broken");
+}
+
+static void allow_drives(int *ints, int param)
+{
+ ALLOWED_DRIVE_MASK=param;
+ DPRINT1("setting allowed_drive_mask to 0x%x\n", param);
+}
+
+static void fdc2_adr(int *ints, int param)
+{
+ FDC2 = param;
+ if(param)
+ DPRINT1("enabling second fdc at address 0x%3x\n", FDC2);
+ else
+ DPRINT("disabling second fdc\n");
+}
+
+static void unex(int *ints,int param)
+{
+ print_unex = param;
+ DPRINT1("%sprinting messages for unexpected interrupts\n",
+ param ? "" : "not ");
+}
+
+static void set_cmos(int *ints, int dummy)
+{
+ int current_drive=0;
+
+ if ( ints[0] != 2 ){
+ DPRINT("wrong number of parameter for cmos\n");
+ return;
+ }
+ current_drive = ints[1];
+ if (current_drive < 0 || current_drive >= 8 ){
+ DPRINT("bad drive for set_cmos\n");
+ return;
+ }
+ if(ints[2] <= 0 || ints[2] >= NUMBER(default_drive_params)){
+ DPRINT1("bad cmos code %d\n", ints[2]);
+ return;
+ }
+ DP->cmos = ints[2];
+ DPRINT1("setting cmos code to %d\n", ints[2]);
+}
+
+static struct param_table {
+ char *name;
+ void (*fn)(int *ints, int param);
+ int def_param;
+} config_params[]={
+{ "allowed_drive_mask", allow_drives, 0xff },
+{ "all_drives", allow_drives, 0xff },
+{ "asus_pci", allow_drives, 0x33 },
+
+{ "daring", daring, 1},
+
+{ "two_fdc", fdc2_adr, 0x370 },
+{ "one_fdc", fdc2_adr, 0 },
+
+{ "thinkpad", floppy_invert_dcl, 1 },
+
+{ "cmos", set_cmos, 0 },
+
+{ "unexpected_interrupts", unex, 1 },
+{ "no_unexpected_interrupts", unex, 0 },
+{ "L40SX", unex, 0 } };
+
+#define FLOPPY_SETUP
+void floppy_setup(char *str, int *ints)
+{
+ int i;
+ int param;
+ if(!str)
+ return;
+ for(i=0; i< ARRAY_SIZE(config_params); i++){
+ if (strcmp(str,config_params[i].name) == 0 ){
+ if (ints[0] )
+ param = ints[1];
+ else
+ param = config_params[i].def_param;
+ config_params[i].fn(ints,param);
+ return;
+ }
+ }
+ DPRINT1("unknown floppy option %s\n", str);
+ DPRINT("allowed options are:");
+ for(i=0; i< ARRAY_SIZE(config_params); i++)
+ printk(" %s",config_params[i].name);
+ printk("\n");
+ DPRINT("Read linux/drivers/block/README.fd\n");
+}
+
#ifdef FD_MODULE
static
#endif
@@ -3230,12 +3560,16 @@ int new_floppy_init(void)
if (FDCS->address == -1 )
continue;
FDCS->rawcmd = 2;
- if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0))
+ if(user_reset_fdc(-1,FD_RESET_IF_NEEDED,0)){
+ FDCS->address = -1;
continue;
+ }
/* Try to determine the floppy controller type */
FDCS->version = get_fdc_version();
- if (FDCS->version == FDC_NONE)
+ if (FDCS->version == FDC_NONE){
+ FDCS->address = -1;
continue;
+ }
have_no_fdc = 0;
/* Not all FDCs seem to be able to handle the version command
@@ -3251,6 +3585,14 @@ int new_floppy_init(void)
initialising=0;
if(have_no_fdc)
unregister_blkdev(MAJOR_NR,"fd");
+#ifdef CONFIG_MIPS_JAZZ
+ else {
+ if (boot_info.machtype == MACH_ACER_PICA_61 ||
+ boot_info.machtype == MACH_MIPS_MAGNUM_4000)
+ vdma_alloc(PHYSADDR(floppy_track_buffer),
+ 512*2*MAX_BUFFER_SECTORS);
+ }
+#endif
return have_no_fdc;
}
@@ -3272,29 +3614,32 @@ static int floppy_grab_irq_and_dma(void)
#ifdef FD_MODULE
MOD_INC_USE_COUNT;
#endif
- for(i=0; i< N_FDC; i++){
- fdc = i;
- reset_fdc_info(1);
- outb_p(FDCS->dor, FD_DOR);
+ for(i=0; i< N_FDC; i++){
+ if(FDCS->address != -1){
+ fdc = i;
+ reset_fdc_info(1);
+ fd_out(FDCS->dor, FD_DOR);
+ }
}
set_dor(0, ~0, 8); /* avoid immediate interrupt */
- if (request_irq(FLOPPY_IRQ, floppy_interrupt, SA_INTERRUPT, "floppy")) {
+ if (fd_request_irq()) {
DPRINT1("Unable to grab IRQ%d for the floppy driver\n",
FLOPPY_IRQ);
return -1;
}
- if (request_dma(FLOPPY_DMA,"floppy")) {
+ if (fd_request_dma()) {
DPRINT1("Unable to grab DMA%d for the floppy driver\n",
FLOPPY_DMA);
- free_irq(FLOPPY_IRQ);
+ fd_free_irq();
return -1;
}
for(fdc = 0; fdc < N_FDC ; fdc++)
if(FDCS->address != -1)
- outb_p(FDCS->dor, FD_DOR);
+ fd_out(FDCS->dor, FD_DOR);
fdc = 0;
- enable_irq(FLOPPY_IRQ);
+/* printk("enable irq %d\n",FLOPPY_IRQ); */
+ fd_enable_irq();
return 0;
}
@@ -3312,16 +3657,16 @@ static void floppy_release_irq_and_dma(void)
#ifdef FD_MODULE
MOD_DEC_USE_COUNT;
#endif
- disable_dma(FLOPPY_DMA);
- free_dma(FLOPPY_DMA);
- disable_irq(FLOPPY_IRQ);
- free_irq(FLOPPY_IRQ);
+ fd_disable_dma();
+ fd_free_dma();
+ fd_disable_irq();
+ fd_free_irq();
set_dor(0, ~0, 8);
#if N_FDC > 1
set_dor(1, ~8, 0);
#endif
-
+ floppy_enable_hlt();
#ifdef CONFIG_FLOPPY_SANITY
for(drive=0; drive < N_FDC * 4; drive++)
if( motor_off_timer[drive].next )
@@ -3336,4 +3681,3 @@ static void floppy_release_irq_and_dma(void)
#endif
}
-#endif