Commit 91bf5ec3 authored by Jens Axboe's avatar Jens Axboe

Merge tag 'floppy-for-5.8' of https://github.com/evdenis/linux-floppy into for-5.8/drivers

Floppy patches for 5.8

Cleanups:
  - symbolic register names for x86,sparc64,sparc32,powerpc,parisc,m68k
  - split of local/global variables for drive,fdc
  - UBSAN warning suppress in setup_rw_floppy()

Changes were compile tested on arm, sparc64, powerpc, m68k. Many patches
introduce no binary changes by using defines instead of magic numbers.
The patches were also tested with syzkaller and simple write/read/format
tests on real hardware.
Signed-off-by: default avatarDenis Efremov <efremov@linux.com>
Signed-off-by: default avatarJens Axboe <axboe@kernel.dk>

* tag 'floppy-for-5.8' of https://github.com/evdenis/linux-floppy: (31 commits)
  floppy: suppress UBSAN warning in setup_rw_floppy()
  floppy: add defines for sizes of cmd & reply buffers of floppy_raw_cmd
  floppy: add FD_AUTODETECT_SIZE define for struct floppy_drive_params
  floppy: use print_hex_dump() in setup_DMA()
  floppy: cleanup: make set_fdc() always set current_drive and current_fd
  floppy: cleanup: get rid of current_reqD in favor of current_drive
  floppy: make sure to reset all FDCs upon resume()
  floppy: cleanup: do not iterate on current_fdc in do_floppy_init()
  floppy: cleanup: add a few comments about expectations in certain functions
  floppy: cleanup: do not iterate on current_fdc in DMA grab/release functions
  floppy: cleanup: make get_fdc_version() not rely on current_fdc anymore
  floppy: cleanup: make next_valid_format() not rely on current_drive anymore
  floppy: cleanup: make check_wp() not rely on current_{fdc,drive} anymore
  floppy: cleanup: make fdc_specify() not rely on current_{fdc,drive} anymore
  floppy: cleanup: make fdc_configure() not rely on current_fdc anymore
  floppy: cleanup: make perpendicular_mode() not rely on current_fdc anymore
  floppy: cleanup: make need_more_output() not rely on current_fdc anymore
  floppy: cleanup: make result() not rely on current_fdc anymore
  floppy: cleanup: make output_byte() not rely on current_fdc anymore
  floppy: cleanup: make wait_til_ready() not rely on current_fdc anymore
  ...
parents 92decf11 0836275d
......@@ -11,8 +11,8 @@
#define __ASM_ALPHA_FLOPPY_H
#define fd_inb(port) inb_p(port)
#define fd_outb(value,port) outb_p(value,port)
#define fd_inb(base, reg) inb_p((base) + (reg))
#define fd_outb(value, base, reg) outb_p(value, (base) + (reg))
#define fd_enable_dma() enable_dma(FLOPPY_DMA)
#define fd_disable_dma() disable_dma(FLOPPY_DMA)
......
......@@ -9,20 +9,20 @@
#ifndef __ASM_ARM_FLOPPY_H
#define __ASM_ARM_FLOPPY_H
#define fd_outb(val,port) \
#define fd_outb(val, base, reg) \
do { \
int new_val = (val); \
if (((port) & 7) == FD_DOR) { \
if ((reg) == FD_DOR) { \
if (new_val & 0xf0) \
new_val = (new_val & 0x0c) | \
floppy_selects[new_val & 3]; \
else \
new_val &= 0x0c; \
} \
outb(new_val, (port)); \
outb(new_val, (base) + (reg)); \
} while(0)
#define fd_inb(port) inb((port))
#define fd_inb(base, reg) inb((base) + (reg))
#define fd_request_irq() request_irq(IRQ_FLOPPYDISK,floppy_interrupt,\
0,"floppy",NULL)
#define fd_free_irq() free_irq(IRQ_FLOPPYDISK,NULL)
......
......@@ -63,21 +63,21 @@ static __inline__ void release_dma_lock(unsigned long flags)
}
static __inline__ unsigned char fd_inb(int port)
static __inline__ unsigned char fd_inb(int base, int reg)
{
if(MACH_IS_Q40)
return inb_p(port);
return inb_p(base + reg);
else if(MACH_IS_SUN3X)
return sun3x_82072_fd_inb(port);
return sun3x_82072_fd_inb(base + reg);
return 0;
}
static __inline__ void fd_outb(unsigned char value, int port)
static __inline__ void fd_outb(unsigned char value, int base, int reg)
{
if(MACH_IS_Q40)
outb_p(value, port);
outb_p(value, base + reg);
else if(MACH_IS_SUN3X)
sun3x_82072_fd_outb(value, port);
sun3x_82072_fd_outb(value, base + reg);
}
......@@ -211,26 +211,27 @@ asmlinkage irqreturn_t floppy_hardint(int irq, void *dev_id)
st=1;
for(lcount=virtual_dma_count, lptr=virtual_dma_addr;
lcount; lcount--, lptr++) {
st=inb(virtual_dma_port+4) & 0xa0 ;
if(st != 0xa0)
st = inb(virtual_dma_port + FD_STATUS);
st &= STATUS_DMA | STATUS_READY;
if (st != (STATUS_DMA | STATUS_READY))
break;
if(virtual_dma_mode)
outb_p(*lptr, virtual_dma_port+5);
outb_p(*lptr, virtual_dma_port + FD_DATA);
else
*lptr = inb_p(virtual_dma_port+5);
*lptr = inb_p(virtual_dma_port + FD_DATA);
}
virtual_dma_count = lcount;
virtual_dma_addr = lptr;
st = inb(virtual_dma_port+4);
st = inb(virtual_dma_port + FD_STATUS);
}
#ifdef TRACE_FLPY_INT
calls++;
#endif
if(st == 0x20)
if (st == STATUS_DMA)
return IRQ_HANDLED;
if(!(st & 0x20)) {
if (!(st & STATUS_DMA)) {
virtual_dma_residue += virtual_dma_count;
virtual_dma_count=0;
#ifdef TRACE_FLPY_INT
......
......@@ -26,14 +26,14 @@
/*
* How to access the FDC's registers.
*/
static inline unsigned char fd_inb(unsigned int port)
static inline unsigned char fd_inb(unsigned int base, unsigned int reg)
{
return inb_p(port);
return inb_p(base + reg);
}
static inline void fd_outb(unsigned char value, unsigned int port)
static inline void fd_outb(unsigned char value, unsigned int base, unsigned int reg)
{
outb_p(value, port);
outb_p(value, base + reg);
}
/*
......
......@@ -17,19 +17,19 @@
#include <asm/jazzdma.h>
#include <asm/pgtable.h>
static inline unsigned char fd_inb(unsigned int port)
static inline unsigned char fd_inb(unsigned int base, unsigned int reg)
{
unsigned char c;
c = *(volatile unsigned char *) port;
c = *(volatile unsigned char *) (base + reg);
udelay(1);
return c;
}
static inline void fd_outb(unsigned char value, unsigned int port)
static inline void fd_outb(unsigned char value, unsigned int base, unsigned int reg)
{
*(volatile unsigned char *) port = value;
*(volatile unsigned char *) (base + reg) = value;
}
/*
......
......@@ -29,8 +29,8 @@
#define CSW fd_routine[can_use_virtual_dma & 1]
#define fd_inb(port) readb(port)
#define fd_outb(value, port) writeb(value, port)
#define fd_inb(base, reg) readb((base) + (reg))
#define fd_outb(value, base, reg) writeb(value, (base) + (reg))
#define fd_request_dma() CSW._request_dma(FLOPPY_DMA,"floppy")
#define fd_free_dma() CSW._free_dma(FLOPPY_DMA)
......@@ -75,27 +75,28 @@ static void floppy_hardint(int irq, void *dev_id, struct pt_regs * regs)
register char *lptr = virtual_dma_addr;
for (lcount = virtual_dma_count; lcount; lcount--) {
st = fd_inb(virtual_dma_port+4) & 0xa0 ;
if (st != 0xa0)
st = fd_inb(virtual_dma_port, FD_STATUS);
st &= STATUS_DMA | STATUS_READY;
if (st != (STATUS_DMA | STATUS_READY))
break;
if (virtual_dma_mode) {
fd_outb(*lptr, virtual_dma_port+5);
fd_outb(*lptr, virtual_dma_port, FD_DATA);
} else {
*lptr = fd_inb(virtual_dma_port+5);
*lptr = fd_inb(virtual_dma_port, FD_DATA);
}
lptr++;
}
virtual_dma_count = lcount;
virtual_dma_addr = lptr;
st = fd_inb(virtual_dma_port+4);
st = fd_inb(virtual_dma_port, FD_STATUS);
}
#ifdef TRACE_FLPY_INT
calls++;
#endif
if (st == 0x20)
if (st == STATUS_DMA)
return;
if (!(st & 0x20)) {
if (!(st & STATUS_DMA)) {
virtual_dma_residue += virtual_dma_count;
virtual_dma_count = 0;
#ifdef TRACE_FLPY_INT
......
......@@ -13,8 +13,8 @@
#include <asm/machdep.h>
#define fd_inb(port) inb_p(port)
#define fd_outb(value,port) outb_p(value,port)
#define fd_inb(base, reg) inb_p((base) + (reg))
#define fd_outb(value, base, reg) outb_p(value, (base) + (reg))
#define fd_enable_dma() enable_dma(FLOPPY_DMA)
#define fd_disable_dma() fd_ops->_disable_dma(FLOPPY_DMA)
......@@ -61,21 +61,22 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id)
st = 1;
for (lcount=virtual_dma_count, lptr=virtual_dma_addr;
lcount; lcount--, lptr++) {
st=inb(virtual_dma_port+4) & 0xa0 ;
if (st != 0xa0)
st = inb(virtual_dma_port + FD_STATUS);
st &= STATUS_DMA | STATUS_READY;
if (st != (STATUS_DMA | STATUS_READY))
break;
if (virtual_dma_mode)
outb_p(*lptr, virtual_dma_port+5);
outb_p(*lptr, virtual_dma_port + FD_DATA);
else
*lptr = inb_p(virtual_dma_port+5);
*lptr = inb_p(virtual_dma_port + FD_DATA);
}
virtual_dma_count = lcount;
virtual_dma_addr = lptr;
st = inb(virtual_dma_port+4);
st = inb(virtual_dma_port + FD_STATUS);
if (st == 0x20)
if (st == STATUS_DMA)
return IRQ_HANDLED;
if (!(st & 0x20)) {
if (!(st & STATUS_DMA)) {
virtual_dma_residue += virtual_dma_count;
virtual_dma_count=0;
doing_vdma = 0;
......
......@@ -59,8 +59,8 @@ struct sun_floppy_ops {
static struct sun_floppy_ops sun_fdops;
#define fd_inb(port) sun_fdops.fd_inb(port)
#define fd_outb(value,port) sun_fdops.fd_outb(value,port)
#define fd_inb(base, reg) sun_fdops.fd_inb(reg)
#define fd_outb(value, base, reg) sun_fdops.fd_outb(value, reg)
#define fd_enable_dma() sun_fd_enable_dma()
#define fd_disable_dma() sun_fd_disable_dma()
#define fd_request_dma() (0) /* nothing... */
......@@ -114,15 +114,15 @@ static unsigned char sun_read_dir(void)
static unsigned char sun_82072_fd_inb(int port)
{
udelay(5);
switch(port & 7) {
switch (port) {
default:
printk("floppy: Asked to read unknown port %d\n", port);
panic("floppy: Port bolixed.");
case 4: /* FD_STATUS */
case FD_STATUS:
return sun_fdc->status_82072 & ~STATUS_DMA;
case 5: /* FD_DATA */
case FD_DATA:
return sun_fdc->data_82072;
case 7: /* FD_DIR */
case FD_DIR:
return sun_read_dir();
}
panic("sun_82072_fd_inb: How did I get here?");
......@@ -131,20 +131,20 @@ static unsigned char sun_82072_fd_inb(int port)
static void sun_82072_fd_outb(unsigned char value, int port)
{
udelay(5);
switch(port & 7) {
switch (port) {
default:
printk("floppy: Asked to write to unknown port %d\n", port);
panic("floppy: Port bolixed.");
case 2: /* FD_DOR */
case FD_DOR:
sun_set_dor(value, 0);
break;
case 5: /* FD_DATA */
case FD_DATA:
sun_fdc->data_82072 = value;
break;
case 7: /* FD_DCR */
case FD_DCR:
sun_fdc->dcr_82072 = value;
break;
case 4: /* FD_STATUS */
case FD_DSR:
sun_fdc->status_82072 = value;
break;
}
......@@ -154,23 +154,23 @@ static void sun_82072_fd_outb(unsigned char value, int port)
static unsigned char sun_82077_fd_inb(int port)
{
udelay(5);
switch(port & 7) {
switch (port) {
default:
printk("floppy: Asked to read unknown port %d\n", port);
panic("floppy: Port bolixed.");
case 0: /* FD_STATUS_0 */
case FD_SRA:
return sun_fdc->status1_82077;
case 1: /* FD_STATUS_1 */
case FD_SRB:
return sun_fdc->status2_82077;
case 2: /* FD_DOR */
case FD_DOR:
return sun_fdc->dor_82077;
case 3: /* FD_TDR */
case FD_TDR:
return sun_fdc->tapectl_82077;
case 4: /* FD_STATUS */
case FD_STATUS:
return sun_fdc->status_82077 & ~STATUS_DMA;
case 5: /* FD_DATA */
case FD_DATA:
return sun_fdc->data_82077;
case 7: /* FD_DIR */
case FD_DIR:
return sun_read_dir();
}
panic("sun_82077_fd_inb: How did I get here?");
......@@ -179,23 +179,23 @@ static unsigned char sun_82077_fd_inb(int port)
static void sun_82077_fd_outb(unsigned char value, int port)
{
udelay(5);
switch(port & 7) {
switch (port) {
default:
printk("floppy: Asked to write to unknown port %d\n", port);
panic("floppy: Port bolixed.");
case 2: /* FD_DOR */
case FD_DOR:
sun_set_dor(value, 1);
break;
case 5: /* FD_DATA */
case FD_DATA:
sun_fdc->data_82077 = value;
break;
case 7: /* FD_DCR */
case FD_DCR:
sun_fdc->dcr_82077 = value;
break;
case 4: /* FD_STATUS */
case FD_DSR:
sun_fdc->status_82077 = value;
break;
case 3: /* FD_TDR */
case FD_TDR:
sun_fdc->tapectl_82077 = value;
break;
}
......
......@@ -47,8 +47,9 @@ unsigned long fdc_status;
static struct platform_device *floppy_op = NULL;
struct sun_floppy_ops {
unsigned char (*fd_inb) (unsigned long port);
void (*fd_outb) (unsigned char value, unsigned long port);
unsigned char (*fd_inb) (unsigned long port, unsigned int reg);
void (*fd_outb) (unsigned char value, unsigned long base,
unsigned int reg);
void (*fd_enable_dma) (void);
void (*fd_disable_dma) (void);
void (*fd_set_dma_mode) (int);
......@@ -62,8 +63,8 @@ struct sun_floppy_ops {
static struct sun_floppy_ops sun_fdops;
#define fd_inb(port) sun_fdops.fd_inb(port)
#define fd_outb(value,port) sun_fdops.fd_outb(value,port)
#define fd_inb(base, reg) sun_fdops.fd_inb(base, reg)
#define fd_outb(value, base, reg) sun_fdops.fd_outb(value, base, reg)
#define fd_enable_dma() sun_fdops.fd_enable_dma()
#define fd_disable_dma() sun_fdops.fd_disable_dma()
#define fd_request_dma() (0) /* nothing... */
......@@ -97,42 +98,43 @@ static int sun_floppy_types[2] = { 0, 0 };
/* No 64k boundary crossing problems on the Sparc. */
#define CROSS_64KB(a,s) (0)
static unsigned char sun_82077_fd_inb(unsigned long port)
static unsigned char sun_82077_fd_inb(unsigned long base, unsigned int reg)
{
udelay(5);
switch(port & 7) {
switch (reg) {
default:
printk("floppy: Asked to read unknown port %lx\n", port);
printk("floppy: Asked to read unknown port %x\n", reg);
panic("floppy: Port bolixed.");
case 4: /* FD_STATUS */
case FD_STATUS:
return sbus_readb(&sun_fdc->status_82077) & ~STATUS_DMA;
case 5: /* FD_DATA */
case FD_DATA:
return sbus_readb(&sun_fdc->data_82077);
case 7: /* FD_DIR */
case FD_DIR:
/* XXX: Is DCL on 0x80 in sun4m? */
return sbus_readb(&sun_fdc->dir_82077);
}
panic("sun_82072_fd_inb: How did I get here?");
}
static void sun_82077_fd_outb(unsigned char value, unsigned long port)
static void sun_82077_fd_outb(unsigned char value, unsigned long base,
unsigned int reg)
{
udelay(5);
switch(port & 7) {
switch (reg) {
default:
printk("floppy: Asked to write to unknown port %lx\n", port);
printk("floppy: Asked to write to unknown port %x\n", reg);
panic("floppy: Port bolixed.");
case 2: /* FD_DOR */
case FD_DOR:
/* Happily, the 82077 has a real DOR register. */
sbus_writeb(value, &sun_fdc->dor_82077);
break;
case 5: /* FD_DATA */
case FD_DATA:
sbus_writeb(value, &sun_fdc->data_82077);
break;
case 7: /* FD_DCR */
case FD_DCR:
sbus_writeb(value, &sun_fdc->dcr_82077);
break;
case 4: /* FD_STATUS */
case FD_DSR:
sbus_writeb(value, &sun_fdc->status_82077);
break;
}
......@@ -298,19 +300,21 @@ static struct sun_pci_dma_op sun_pci_dma_pending = { -1U, 0, 0, NULL};
irqreturn_t floppy_interrupt(int irq, void *dev_id);
static unsigned char sun_pci_fd_inb(unsigned long port)
static unsigned char sun_pci_fd_inb(unsigned long base, unsigned int reg)
{
udelay(5);
return inb(port);
return inb(base + reg);
}
static void sun_pci_fd_outb(unsigned char val, unsigned long port)
static void sun_pci_fd_outb(unsigned char val, unsigned long base,
unsigned int reg)
{
udelay(5);
outb(val, port);
outb(val, base + reg);
}
static void sun_pci_fd_broken_outb(unsigned char val, unsigned long port)
static void sun_pci_fd_broken_outb(unsigned char val, unsigned long base,
unsigned int reg)
{
udelay(5);
/*
......@@ -320,16 +324,17 @@ static void sun_pci_fd_broken_outb(unsigned char val, unsigned long port)
* this does not hurt correct hardware like the AXmp.
* (Eddie, Sep 12 1998).
*/
if (port == ((unsigned long)sun_fdc) + 2) {
if (reg == FD_DOR) {
if (((val & 0x03) == sun_pci_broken_drive) && (val & 0x20)) {
val |= 0x10;
}
}
outb(val, port);
outb(val, base + reg);
}
#ifdef PCI_FDC_SWAP_DRIVES
static void sun_pci_fd_lde_broken_outb(unsigned char val, unsigned long port)
static void sun_pci_fd_lde_broken_outb(unsigned char val, unsigned long base,
unsigned int reg)
{
udelay(5);
/*
......@@ -339,13 +344,13 @@ static void sun_pci_fd_lde_broken_outb(unsigned char val, unsigned long port)
* this does not hurt correct hardware like the AXmp.
* (Eddie, Sep 12 1998).
*/
if (port == ((unsigned long)sun_fdc) + 2) {
if (reg == FD_DOR) {
if (((val & 0x03) == sun_pci_broken_drive) && (val & 0x10)) {
val &= ~(0x03);
val |= 0x21;
}
}
outb(val, port);
outb(val, base + reg);
}
#endif /* PCI_FDC_SWAP_DRIVES */
......
......@@ -31,8 +31,8 @@
#define CSW fd_routine[can_use_virtual_dma & 1]
#define fd_inb(port) inb_p(port)
#define fd_outb(value, port) outb_p(value, port)
#define fd_inb(base, reg) inb_p((base) + (reg))
#define fd_outb(value, base, reg) outb_p(value, (base) + (reg))
#define fd_request_dma() CSW._request_dma(FLOPPY_DMA, "floppy")
#define fd_free_dma() CSW._free_dma(FLOPPY_DMA)
......@@ -77,25 +77,26 @@ static irqreturn_t floppy_hardint(int irq, void *dev_id)
st = 1;
for (lcount = virtual_dma_count, lptr = virtual_dma_addr;
lcount; lcount--, lptr++) {
st = inb(virtual_dma_port + 4) & 0xa0;
if (st != 0xa0)
st = inb(virtual_dma_port + FD_STATUS);
st &= STATUS_DMA | STATUS_READY;
if (st != (STATUS_DMA | STATUS_READY))
break;
if (virtual_dma_mode)
outb_p(*lptr, virtual_dma_port + 5);
outb_p(*lptr, virtual_dma_port + FD_DATA);
else
*lptr = inb_p(virtual_dma_port + 5);
*lptr = inb_p(virtual_dma_port + FD_DATA);
}
virtual_dma_count = lcount;
virtual_dma_addr = lptr;
st = inb(virtual_dma_port + 4);
st = inb(virtual_dma_port + FD_STATUS);
}
#ifdef TRACE_FLPY_INT
calls++;
#endif
if (st == 0x20)
if (st == STATUS_DMA)
return IRQ_HANDLED;
if (!(st & 0x20)) {
if (!(st & STATUS_DMA)) {
virtual_dma_residue += virtual_dma_count;
virtual_dma_count = 0;
#ifdef TRACE_FLPY_INT
......
......@@ -337,8 +337,7 @@ static bool initialized;
/*
* globals used by 'result()'
*/
#define MAX_REPLIES 16
static unsigned char reply_buffer[MAX_REPLIES];
static unsigned char reply_buffer[FD_RAW_REPLY_SIZE];
static int inr; /* size of reply buffer, when called from interrupt */
#define ST0 0
#define ST1 1
......@@ -595,12 +594,12 @@ static unsigned char in_sector_offset; /* offset within physical sector,
static inline unsigned char fdc_inb(int fdc, int reg)
{
return fd_inb(fdc_state[fdc].address + reg);
return fd_inb(fdc_state[fdc].address, reg);
}
static inline void fdc_outb(unsigned char value, int fdc, int reg)
{
fd_outb(value, fdc_state[fdc].address + reg);
fd_outb(value, fdc_state[fdc].address, reg);
}
static inline bool drive_no_geom(int drive)
......@@ -668,16 +667,12 @@ static struct output_log {
static int output_log_pos;
#define current_reqD -1
#define MAXTIMEOUT -2
static void __reschedule_timeout(int drive, const char *message)
{
unsigned long delay;
if (drive == current_reqD)
drive = current_drive;
if (drive < 0 || drive >= N_DRIVE) {
delay = 20UL * HZ;
drive = 0;
......@@ -827,59 +822,70 @@ static int set_dor(int fdc, char mask, char data)
return olddor;
}
static void twaddle(void)
static void twaddle(int fdc, int drive)
{
if (drive_params[current_drive].select_delay)
if (drive_params[drive].select_delay)
return;
fdc_outb(fdc_state[current_fdc].dor & ~(0x10 << UNIT(current_drive)),
current_fdc, FD_DOR);
fdc_outb(fdc_state[current_fdc].dor, current_fdc, FD_DOR);
drive_state[current_drive].select_date = jiffies;
fdc_outb(fdc_state[fdc].dor & ~(0x10 << UNIT(drive)),
fdc, FD_DOR);
fdc_outb(fdc_state[fdc].dor, fdc, FD_DOR);
drive_state[drive].select_date = jiffies;
}
/*
* Reset all driver information about the current fdc.
* Reset all driver information about the specified fdc.
* This is needed after a reset, and after a raw command.
*/
static void reset_fdc_info(int mode)
static void reset_fdc_info(int fdc, int mode)
{
int drive;
fdc_state[current_fdc].spec1 = fdc_state[current_fdc].spec2 = -1;
fdc_state[current_fdc].need_configure = 1;
fdc_state[current_fdc].perp_mode = 1;
fdc_state[current_fdc].rawcmd = 0;
fdc_state[fdc].spec1 = fdc_state[fdc].spec2 = -1;
fdc_state[fdc].need_configure = 1;
fdc_state[fdc].perp_mode = 1;
fdc_state[fdc].rawcmd = 0;
for (drive = 0; drive < N_DRIVE; drive++)
if (FDC(drive) == current_fdc &&
if (FDC(drive) == fdc &&
(mode || drive_state[drive].track != NEED_1_RECAL))
drive_state[drive].track = NEED_2_RECAL;
}
/* selects the fdc and drive, and enables the fdc's input/dma. */
/*
* selects the fdc and drive, and enables the fdc's input/dma.
* Both current_drive and current_fdc are changed to match the new drive.
*/
static void set_fdc(int drive)
{
unsigned int new_fdc = current_fdc;
unsigned int fdc;
if (drive >= 0 && drive < N_DRIVE) {
new_fdc = FDC(drive);
current_drive = drive;
if (drive < 0 || drive >= N_DRIVE) {
pr_info("bad drive value %d\n", drive);
return;
}
if (new_fdc >= N_FDC) {
fdc = FDC(drive);
if (fdc >= N_FDC) {
pr_info("bad fdc value\n");
return;
}
current_fdc = new_fdc;
set_dor(current_fdc, ~0, 8);
set_dor(fdc, ~0, 8);
#if N_FDC > 1
set_dor(1 - current_fdc, ~8, 0);
set_dor(1 - fdc, ~8, 0);
#endif
if (fdc_state[current_fdc].rawcmd == 2)
reset_fdc_info(1);
if (fdc_inb(current_fdc, FD_STATUS) != STATUS_READY)
fdc_state[current_fdc].reset = 1;
if (fdc_state[fdc].rawcmd == 2)
reset_fdc_info(fdc, 1);
if (fdc_inb(fdc, FD_STATUS) != STATUS_READY)
fdc_state[fdc].reset = 1;
current_drive = drive;
current_fdc = fdc;
}
/* locks the driver */
/*
* locks the driver.
* Both current_drive and current_fdc are changed to match the new drive.
*/
static int lock_fdc(int drive)
{
if (WARN(atomic_read(&usage_count) == 0,
......@@ -1062,12 +1068,9 @@ static void setup_DMA(void)
unsigned long f;
if (raw_cmd->length == 0) {
int i;
pr_info("zero dma transfer size:");
for (i = 0; i < raw_cmd->cmd_count; i++)
pr_cont("%x,", raw_cmd->cmd[i]);
pr_cont("\n");
print_hex_dump(KERN_INFO, "zero dma transfer size: ",
DUMP_PREFIX_NONE, 16, 1,
raw_cmd->fullcmd, raw_cmd->cmd_count, false);
cont->done(0);
fdc_state[current_fdc].reset = 1;
return;
......@@ -1104,62 +1107,62 @@ static void setup_DMA(void)
#endif
}
static void show_floppy(void);
static void show_floppy(int fdc);
/* waits until the fdc becomes ready */
static int wait_til_ready(void)
static int wait_til_ready(int fdc)
{
int status;
int counter;
if (fdc_state[current_fdc].reset)
if (fdc_state[fdc].reset)
return -1;
for (counter = 0; counter < 10000; counter++) {
status = fdc_inb(current_fdc, FD_STATUS);
status = fdc_inb(fdc, FD_STATUS);
if (status & STATUS_READY)
return status;
}
if (initialized) {
DPRINT("Getstatus times out (%x) on fdc %d\n", status, current_fdc);
show_floppy();
DPRINT("Getstatus times out (%x) on fdc %d\n", status, fdc);
show_floppy(fdc);
}
fdc_state[current_fdc].reset = 1;
fdc_state[fdc].reset = 1;
return -1;
}
/* sends a command byte to the fdc */
static int output_byte(char byte)
static int output_byte(int fdc, char byte)
{
int status = wait_til_ready();
int status = wait_til_ready(fdc);
if (status < 0)
return -1;
if (is_ready_state(status)) {
fdc_outb(byte, current_fdc, FD_DATA);
fdc_outb(byte, fdc, FD_DATA);
output_log[output_log_pos].data = byte;
output_log[output_log_pos].status = status;
output_log[output_log_pos].jiffies = jiffies;
output_log_pos = (output_log_pos + 1) % OLOGSIZE;
return 0;
}
fdc_state[current_fdc].reset = 1;
fdc_state[fdc].reset = 1;
if (initialized) {
DPRINT("Unable to send byte %x to FDC. Fdc=%x Status=%x\n",
byte, current_fdc, status);
show_floppy();
byte, fdc, status);
show_floppy(fdc);
}
return -1;
}
/* gets the response from the fdc */
static int result(void)
static int result(int fdc)
{
int i;
int status = 0;
for (i = 0; i < MAX_REPLIES; i++) {
status = wait_til_ready();
for (i = 0; i < FD_RAW_REPLY_SIZE; i++) {
status = wait_til_ready(fdc);
if (status < 0)
break;
status &= STATUS_DIR | STATUS_READY | STATUS_BUSY | STATUS_DMA;
......@@ -1169,24 +1172,24 @@ static int result(void)
return i;
}
if (status == (STATUS_DIR | STATUS_READY | STATUS_BUSY))
reply_buffer[i] = fdc_inb(current_fdc, FD_DATA);
reply_buffer[i] = fdc_inb(fdc, FD_DATA);
else
break;
}
if (initialized) {
DPRINT("get result error. Fdc=%d Last status=%x Read bytes=%d\n",
current_fdc, status, i);
show_floppy();
fdc, status, i);
show_floppy(fdc);
}
fdc_state[current_fdc].reset = 1;
fdc_state[fdc].reset = 1;
return -1;
}
#define MORE_OUTPUT -2
/* does the fdc need more output? */
static int need_more_output(void)
static int need_more_output(int fdc)
{
int status = wait_til_ready();
int status = wait_til_ready(fdc);
if (status < 0)
return -1;
......@@ -1194,13 +1197,13 @@ static int need_more_output(void)
if (is_ready_state(status))
return MORE_OUTPUT;
return result();
return result(fdc);
}
/* Set perpendicular mode as required, based on data rate, if supported.
* 82077 Now tested. 1Mbps data rate only possible with 82077-1.
*/
static void perpendicular_mode(void)
static void perpendicular_mode(int fdc)
{
unsigned char perp_mode;
......@@ -1215,7 +1218,7 @@ static void perpendicular_mode(void)
default:
DPRINT("Invalid data rate for perpendicular mode!\n");
cont->done(0);
fdc_state[current_fdc].reset = 1;
fdc_state[fdc].reset = 1;
/*
* convenient way to return to
* redo without too much hassle
......@@ -1226,12 +1229,12 @@ static void perpendicular_mode(void)
} else
perp_mode = 0;
if (fdc_state[current_fdc].perp_mode == perp_mode)
if (fdc_state[fdc].perp_mode == perp_mode)
return;
if (fdc_state[current_fdc].version >= FDC_82077_ORIG) {
output_byte(FD_PERPENDICULAR);
output_byte(perp_mode);
fdc_state[current_fdc].perp_mode = perp_mode;
if (fdc_state[fdc].version >= FDC_82077_ORIG) {
output_byte(fdc, FD_PERPENDICULAR);
output_byte(fdc, perp_mode);
fdc_state[fdc].perp_mode = perp_mode;
} else if (perp_mode) {
DPRINT("perpendicular mode not supported by this FDC.\n");
}
......@@ -1240,16 +1243,15 @@ static void perpendicular_mode(void)
static int fifo_depth = 0xa;
static int no_fifo;
static int fdc_configure(void)
static int fdc_configure(int fdc)
{
/* Turn on FIFO */
output_byte(FD_CONFIGURE);
if (need_more_output() != MORE_OUTPUT)
output_byte(fdc, FD_CONFIGURE);
if (need_more_output(fdc) != MORE_OUTPUT)
return 0;
output_byte(0);
output_byte(0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
output_byte(0); /* pre-compensation from track
0 upwards */
output_byte(fdc, 0);
output_byte(fdc, 0x10 | (no_fifo & 0x20) | (fifo_depth & 0xf));
output_byte(fdc, 0); /* pre-compensation from track 0 upwards */
return 1;
}
......@@ -1274,7 +1276,7 @@ static int fdc_configure(void)
*
* These values are rounded up to the next highest available delay time.
*/
static void fdc_specify(void)
static void fdc_specify(int fdc, int drive)
{
unsigned char spec1;
unsigned char spec2;
......@@ -1286,10 +1288,10 @@ static void fdc_specify(void)
int hlt_max_code = 0x7f;
int hut_max_code = 0xf;
if (fdc_state[current_fdc].need_configure &&
fdc_state[current_fdc].version >= FDC_82072A) {
fdc_configure();
fdc_state[current_fdc].need_configure = 0;
if (fdc_state[fdc].need_configure &&
fdc_state[fdc].version >= FDC_82072A) {
fdc_configure(fdc);
fdc_state[fdc].need_configure = 0;
}
switch (raw_cmd->rate & 0x03) {
......@@ -1298,13 +1300,13 @@ static void fdc_specify(void)
break;
case 1:
dtr = 300;
if (fdc_state[current_fdc].version >= FDC_82078) {
if (fdc_state[fdc].version >= FDC_82078) {
/* chose the default rate table, not the one
* where 1 = 2 Mbps */
output_byte(FD_DRIVESPEC);
if (need_more_output() == MORE_OUTPUT) {
output_byte(UNIT(current_drive));
output_byte(0xc0);
output_byte(fdc, FD_DRIVESPEC);
if (need_more_output(fdc) == MORE_OUTPUT) {
output_byte(fdc, UNIT(drive));
output_byte(fdc, 0xc0);
}
}
break;
......@@ -1313,14 +1315,14 @@ static void fdc_specify(void)
break;
}
if (fdc_state[current_fdc].version >= FDC_82072) {
if (fdc_state[fdc].version >= FDC_82072) {
scale_dtr = dtr;
hlt_max_code = 0x00; /* 0==256msec*dtr0/dtr (not linear!) */
hut_max_code = 0x0; /* 0==256msec*dtr0/dtr (not linear!) */
}
/* Convert step rate from microseconds to milliseconds and 4 bits */
srt = 16 - DIV_ROUND_UP(drive_params[current_drive].srt * scale_dtr / 1000,
srt = 16 - DIV_ROUND_UP(drive_params[drive].srt * scale_dtr / 1000,
NOMINAL_DTR);
if (slow_floppy)
srt = srt / 4;
......@@ -1328,14 +1330,14 @@ static void fdc_specify(void)
SUPBOUND(srt, 0xf);
INFBOUND(srt, 0);
hlt = DIV_ROUND_UP(drive_params[current_drive].hlt * scale_dtr / 2,
hlt = DIV_ROUND_UP(drive_params[drive].hlt * scale_dtr / 2,
NOMINAL_DTR);
if (hlt < 0x01)
hlt = 0x01;
else if (hlt > 0x7f)
hlt = hlt_max_code;
hut = DIV_ROUND_UP(drive_params[current_drive].hut * scale_dtr / 16,
hut = DIV_ROUND_UP(drive_params[drive].hut * scale_dtr / 16,
NOMINAL_DTR);
if (hut < 0x1)
hut = 0x1;
......@@ -1346,12 +1348,12 @@ static void fdc_specify(void)
spec2 = (hlt << 1) | (use_virtual_dma & 1);
/* If these parameters did not change, just return with success */
if (fdc_state[current_fdc].spec1 != spec1 ||
fdc_state[current_fdc].spec2 != spec2) {
if (fdc_state[fdc].spec1 != spec1 ||
fdc_state[fdc].spec2 != spec2) {
/* Go ahead and set spec1 and spec2 */
output_byte(FD_SPECIFY);
output_byte(fdc_state[current_fdc].spec1 = spec1);
output_byte(fdc_state[current_fdc].spec2 = spec2);
output_byte(fdc, FD_SPECIFY);
output_byte(fdc, fdc_state[fdc].spec1 = spec1);
output_byte(fdc, fdc_state[fdc].spec2 = spec2);
}
} /* fdc_specify */
......@@ -1513,7 +1515,7 @@ static void setup_rw_floppy(void)
r = 0;
for (i = 0; i < raw_cmd->cmd_count; i++)
r |= output_byte(raw_cmd->cmd[i]);
r |= output_byte(current_fdc, raw_cmd->fullcmd[i]);
debugt(__func__, "rw_command");
......@@ -1524,7 +1526,7 @@ static void setup_rw_floppy(void)
}
if (!(flags & FD_RAW_INTR)) {
inr = result();
inr = result(current_fdc);
cont->interrupt();
} else if (flags & FD_RAW_NEED_DISK)
fd_watchdog();
......@@ -1562,29 +1564,29 @@ static void seek_interrupt(void)
floppy_ready();
}
static void check_wp(void)
static void check_wp(int fdc, int drive)
{
if (test_bit(FD_VERIFY_BIT, &drive_state[current_drive].flags)) {
if (test_bit(FD_VERIFY_BIT, &drive_state[drive].flags)) {
/* check write protection */
output_byte(FD_GETSTATUS);
output_byte(UNIT(current_drive));
if (result() != 1) {
fdc_state[current_fdc].reset = 1;
output_byte(fdc, FD_GETSTATUS);
output_byte(fdc, UNIT(drive));
if (result(fdc) != 1) {
fdc_state[fdc].reset = 1;
return;
}
clear_bit(FD_VERIFY_BIT, &drive_state[current_drive].flags);
clear_bit(FD_VERIFY_BIT, &drive_state[drive].flags);
clear_bit(FD_NEED_TWADDLE_BIT,
&drive_state[current_drive].flags);
debug_dcl(drive_params[current_drive].flags,
&drive_state[drive].flags);
debug_dcl(drive_params[drive].flags,
"checking whether disk is write protected\n");
debug_dcl(drive_params[current_drive].flags, "wp=%x\n",
debug_dcl(drive_params[drive].flags, "wp=%x\n",
reply_buffer[ST3] & 0x40);
if (!(reply_buffer[ST3] & 0x40))
set_bit(FD_DISK_WRITABLE_BIT,
&drive_state[current_drive].flags);
&drive_state[drive].flags);
else
clear_bit(FD_DISK_WRITABLE_BIT,
&drive_state[current_drive].flags);
&drive_state[drive].flags);
}
}
......@@ -1628,7 +1630,7 @@ static void seek_floppy(void)
track = 1;
}
} else {
check_wp();
check_wp(current_fdc, current_drive);
if (raw_cmd->track != drive_state[current_drive].track &&
(raw_cmd->flags & FD_RAW_NEED_SEEK))
track = raw_cmd->track;
......@@ -1639,9 +1641,9 @@ static void seek_floppy(void)
}
do_floppy = seek_interrupt;
output_byte(FD_SEEK);
output_byte(UNIT(current_drive));
if (output_byte(track) < 0) {
output_byte(current_fdc, FD_SEEK);
output_byte(current_fdc, UNIT(current_drive));
if (output_byte(current_fdc, track) < 0) {
reset_fdc();
return;
}
......@@ -1742,14 +1744,14 @@ irqreturn_t floppy_interrupt(int irq, void *dev_id)
do_print = !handler && print_unex && initialized;
inr = result();
inr = result(current_fdc);
if (do_print)
print_result("unexpected interrupt", inr);
if (inr == 0) {
int max_sensei = 4;
do {
output_byte(FD_SENSEI);
inr = result();
output_byte(current_fdc, FD_SENSEI);
inr = result(current_fdc);
if (do_print)
print_result("sensei", inr);
max_sensei--;
......@@ -1771,8 +1773,8 @@ static void recalibrate_floppy(void)
{
debugt(__func__, "");
do_floppy = recal_interrupt;
output_byte(FD_RECALIBRATE);
if (output_byte(UNIT(current_drive)) < 0)
output_byte(current_fdc, FD_RECALIBRATE);
if (output_byte(current_fdc, UNIT(current_drive)) < 0)
reset_fdc();
}
......@@ -1782,7 +1784,7 @@ static void recalibrate_floppy(void)
static void reset_interrupt(void)
{
debugt(__func__, "");
result(); /* get the status ready for set_fdc */
result(current_fdc); /* get the status ready for set_fdc */
if (fdc_state[current_fdc].reset) {
pr_info("reset set in interrupt, calling %ps\n", cont->error);
cont->error(); /* a reset just after a reset. BAD! */
......@@ -1792,7 +1794,9 @@ static void reset_interrupt(void)
/*
* reset is done by pulling bit 2 of DOR low for a while (old FDCs),
* or by setting the self clearing bit 7 of STATUS (newer FDCs)
* or by setting the self clearing bit 7 of STATUS (newer FDCs).
* This WILL trigger an interrupt, causing the handlers in the current
* cont's ->redo() to be called via reset_interrupt().
*/
static void reset_fdc(void)
{
......@@ -1800,7 +1804,7 @@ static void reset_fdc(void)
do_floppy = reset_interrupt;
fdc_state[current_fdc].reset = 0;
reset_fdc_info(0);
reset_fdc_info(current_fdc, 0);
/* Pseudo-DMA may intercept 'reset finished' interrupt. */
/* Irrelevant for systems with true DMA (i386). */
......@@ -1819,7 +1823,7 @@ static void reset_fdc(void)
}
}
static void show_floppy(void)
static void show_floppy(int fdc)
{
int i;
......@@ -1842,7 +1846,7 @@ static void show_floppy(void)
print_hex_dump(KERN_INFO, "", DUMP_PREFIX_NONE, 16, 1,
reply_buffer, resultsize, true);
pr_info("status=%x\n", fdc_inb(current_fdc, FD_STATUS));
pr_info("status=%x\n", fdc_inb(fdc, FD_STATUS));
pr_info("fdc_busy=%lu\n", fdc_busy);
if (do_floppy)
pr_info("do_floppy=%ps\n", do_floppy);
......@@ -1868,7 +1872,7 @@ static void floppy_shutdown(struct work_struct *arg)
unsigned long flags;
if (initialized)
show_floppy();
show_floppy(current_fdc);
cancel_activity();
flags = claim_dma_lock();
......@@ -1934,7 +1938,7 @@ static void floppy_ready(void)
"calling disk change from floppy_ready\n");
if (!(raw_cmd->flags & FD_RAW_NO_MOTOR) &&
disk_change(current_drive) && !drive_params[current_drive].select_delay)
twaddle(); /* this clears the dcl on certain
twaddle(current_fdc, current_drive); /* this clears the dcl on certain
* drive/controller combinations */
#ifdef fd_chose_dma_mode
......@@ -1946,20 +1950,20 @@ static void floppy_ready(void)
#endif
if (raw_cmd->flags & (FD_RAW_NEED_SEEK | FD_RAW_NEED_DISK)) {
perpendicular_mode();
fdc_specify(); /* must be done here because of hut, hlt ... */
perpendicular_mode(current_fdc);
fdc_specify(current_fdc, current_drive); /* must be done here because of hut, hlt ... */
seek_floppy();
} else {
if ((raw_cmd->flags & FD_RAW_READ) ||
(raw_cmd->flags & FD_RAW_WRITE))
fdc_specify();
fdc_specify(current_fdc, current_drive);
setup_rw_floppy();
}
}
static void floppy_start(void)
{
reschedule_timeout(current_reqD, "floppy start");
reschedule_timeout(current_drive, "floppy start");
scandrives();
debug_dcl(drive_params[current_drive].flags,
......@@ -2004,6 +2008,9 @@ static const struct cont_t intr_cont = {
.done = (done_f)empty
};
/* schedules handler, waiting for completion. May be interrupted, will then
* return -EINTR, in which case the driver will automatically be unlocked.
*/
static int wait_til_done(void (*handler)(void), bool interruptible)
{
int ret;
......@@ -2059,18 +2066,19 @@ static void success_and_wakeup(void)
* ==========================
*/
static int next_valid_format(void)
static int next_valid_format(int drive)
{
int probed_format;
probed_format = drive_state[current_drive].probed_format;
probed_format = drive_state[drive].probed_format;
while (1) {
if (probed_format >= 8 || !drive_params[current_drive].autodetect[probed_format]) {
drive_state[current_drive].probed_format = 0;
if (probed_format >= FD_AUTODETECT_SIZE ||
!drive_params[drive].autodetect[probed_format]) {
drive_state[drive].probed_format = 0;
return 1;
}
if (floppy_type[drive_params[current_drive].autodetect[probed_format]].sect) {
drive_state[current_drive].probed_format = probed_format;
if (floppy_type[drive_params[drive].autodetect[probed_format]].sect) {
drive_state[drive].probed_format = probed_format;
return 0;
}
probed_format++;
......@@ -2083,7 +2091,7 @@ static void bad_flp_intr(void)
if (probing) {
drive_state[current_drive].probed_format++;
if (!next_valid_format())
if (!next_valid_format(current_drive))
return;
}
err_count = ++(*errors);
......@@ -2843,6 +2851,9 @@ static int set_next_request(void)
return current_req != NULL;
}
/* Starts or continues processing request. Will automatically unlock the
* driver at end of request.
*/
static void redo_fd_request(void)
{
int drive;
......@@ -2867,7 +2878,7 @@ static void redo_fd_request(void)
}
drive = (long)current_req->rq_disk->private_data;
set_fdc(drive);
reschedule_timeout(current_reqD, "redo fd request");
reschedule_timeout(current_drive, "redo fd request");
set_floppy(drive);
raw_cmd = &default_raw_cmd;
......@@ -2885,7 +2896,7 @@ static void redo_fd_request(void)
if (!_floppy) { /* Autodetection */
if (!probing) {
drive_state[current_drive].probed_format = 0;
if (next_valid_format()) {
if (next_valid_format(current_drive)) {
DPRINT("no autodetectable formats\n");
_floppy = NULL;
request_done(0);
......@@ -2904,7 +2915,7 @@ static void redo_fd_request(void)
}
if (test_bit(FD_NEED_TWADDLE_BIT, &drive_state[current_drive].flags))
twaddle();
twaddle(current_fdc, current_drive);
schedule_bh(floppy_start);
debugt(__func__, "queue fd request");
return;
......@@ -2917,6 +2928,7 @@ static const struct cont_t rw_cont = {
.done = request_done
};
/* schedule the request and automatically unlock the driver on completion */
static void process_fd_request(void)
{
cont = &rw_cont;
......@@ -2996,6 +3008,10 @@ static const struct cont_t reset_cont = {
.done = generic_done
};
/*
* Resets the FDC connected to drive <drive>.
* Both current_drive and current_fdc are changed to match the new drive.
*/
static int user_reset_fdc(int drive, int arg, bool interruptible)
{
int ret;
......@@ -3006,6 +3022,9 @@ static int user_reset_fdc(int drive, int arg, bool interruptible)
if (arg == FD_RESET_ALWAYS)
fdc_state[current_fdc].reset = 1;
if (fdc_state[current_fdc].reset) {
/* note: reset_fdc will take care of unlocking the driver
* on completion.
*/
cont = &reset_cont;
ret = wait_til_done(reset_fdc, interruptible);
if (ret == -EINTR)
......@@ -3059,7 +3078,7 @@ static void raw_cmd_done(int flag)
raw_cmd->flags |= FD_RAW_HARDFAILURE;
} else {
raw_cmd->reply_count = inr;
if (raw_cmd->reply_count > MAX_REPLIES)
if (raw_cmd->reply_count > FD_RAW_REPLY_SIZE)
raw_cmd->reply_count = 0;
for (i = 0; i < raw_cmd->reply_count; i++)
raw_cmd->reply[i] = reply_buffer[i];
......@@ -3170,18 +3189,10 @@ static int raw_cmd_copyin(int cmd, void __user *param,
if (ret)
return -EFAULT;
param += sizeof(struct floppy_raw_cmd);
if (ptr->cmd_count > 33)
/* the command may now also take up the space
* initially intended for the reply & the
* reply count. Needed for long 82078 commands
* such as RESTORE, which takes ... 17 command
* bytes. Murphy's law #137: When you reserve
* 16 bytes for a structure, you'll one day
* discover that you really need 17...
*/
if (ptr->cmd_count > FD_RAW_CMD_FULLSIZE)
return -EINVAL;
for (i = 0; i < 16; i++)
for (i = 0; i < FD_RAW_REPLY_SIZE; i++)
ptr->reply[i] = 0;
ptr->resultcode = 0;
......@@ -3423,13 +3434,13 @@ static int fd_getgeo(struct block_device *bdev, struct hd_geometry *geo)
return 0;
}
static bool valid_floppy_drive_params(const short autodetect[8],
static bool valid_floppy_drive_params(const short autodetect[FD_AUTODETECT_SIZE],
int native_format)
{
size_t floppy_type_size = ARRAY_SIZE(floppy_type);
size_t i = 0;
for (i = 0; i < 8; ++i) {
for (i = 0; i < FD_AUTODETECT_SIZE; ++i) {
if (autodetect[i] < 0 ||
autodetect[i] >= floppy_type_size)
return false;
......@@ -3610,7 +3621,7 @@ static int fd_locked_ioctl(struct block_device *bdev, fmode_t mode, unsigned int
case FDTWADDLE:
if (lock_fdc(drive))
return -EINTR;
twaddle();
twaddle(current_fdc, current_drive);
process_fd_request();
return 0;
default:
......@@ -3654,7 +3665,7 @@ struct compat_floppy_drive_params {
struct floppy_max_errors max_errors;
char flags;
char read_track;
short autodetect[8];
short autodetect[FD_AUTODETECT_SIZE];
compat_int_t checkfreq;
compat_int_t native_format;
};
......@@ -4298,79 +4309,79 @@ static const struct block_device_operations floppy_fops = {
/* Determine the floppy disk controller type */
/* This routine was written by David C. Niemi */
static char __init get_fdc_version(void)
static char __init get_fdc_version(int fdc)
{
int r;
output_byte(FD_DUMPREGS); /* 82072 and better know DUMPREGS */
if (fdc_state[current_fdc].reset)
output_byte(fdc, FD_DUMPREGS); /* 82072 and better know DUMPREGS */
if (fdc_state[fdc].reset)
return FDC_NONE;
r = result();
r = result(fdc);
if (r <= 0x00)
return FDC_NONE; /* No FDC present ??? */
if ((r == 1) && (reply_buffer[0] == 0x80)) {
pr_info("FDC %d is an 8272A\n", current_fdc);
pr_info("FDC %d is an 8272A\n", fdc);
return FDC_8272A; /* 8272a/765 don't know DUMPREGS */
}
if (r != 10) {
pr_info("FDC %d init: DUMPREGS: unexpected return of %d bytes.\n",
current_fdc, r);
fdc, r);
return FDC_UNKNOWN;
}
if (!fdc_configure()) {
pr_info("FDC %d is an 82072\n", current_fdc);
if (!fdc_configure(fdc)) {
pr_info("FDC %d is an 82072\n", fdc);
return FDC_82072; /* 82072 doesn't know CONFIGURE */
}
output_byte(FD_PERPENDICULAR);
if (need_more_output() == MORE_OUTPUT) {
output_byte(0);
output_byte(fdc, FD_PERPENDICULAR);
if (need_more_output(fdc) == MORE_OUTPUT) {
output_byte(fdc, 0);
} else {
pr_info("FDC %d is an 82072A\n", current_fdc);
pr_info("FDC %d is an 82072A\n", fdc);
return FDC_82072A; /* 82072A as found on Sparcs. */
}
output_byte(FD_UNLOCK);
r = result();
output_byte(fdc, FD_UNLOCK);
r = result(fdc);
if ((r == 1) && (reply_buffer[0] == 0x80)) {
pr_info("FDC %d is a pre-1991 82077\n", current_fdc);
pr_info("FDC %d is a pre-1991 82077\n", fdc);
return FDC_82077_ORIG; /* Pre-1991 82077, doesn't know
* LOCK/UNLOCK */
}
if ((r != 1) || (reply_buffer[0] != 0x00)) {
pr_info("FDC %d init: UNLOCK: unexpected return of %d bytes.\n",
current_fdc, r);
fdc, r);
return FDC_UNKNOWN;
}
output_byte(FD_PARTID);
r = result();
output_byte(fdc, FD_PARTID);
r = result(fdc);
if (r != 1) {
pr_info("FDC %d init: PARTID: unexpected return of %d bytes.\n",
current_fdc, r);
fdc, r);
return FDC_UNKNOWN;
}
if (reply_buffer[0] == 0x80) {
pr_info("FDC %d is a post-1991 82077\n", current_fdc);
pr_info("FDC %d is a post-1991 82077\n", fdc);
return FDC_82077; /* Revised 82077AA passes all the tests */
}
switch (reply_buffer[0] >> 5) {
case 0x0:
/* Either a 82078-1 or a 82078SL running at 5Volt */
pr_info("FDC %d is an 82078.\n", current_fdc);
pr_info("FDC %d is an 82078.\n", fdc);
return FDC_82078;
case 0x1:
pr_info("FDC %d is a 44pin 82078\n", current_fdc);
pr_info("FDC %d is a 44pin 82078\n", fdc);
return FDC_82078;
case 0x2:
pr_info("FDC %d is a S82078B\n", current_fdc);
pr_info("FDC %d is a S82078B\n", fdc);
return FDC_S82078B;
case 0x3:
pr_info("FDC %d is a National Semiconductor PC87306\n", current_fdc);
pr_info("FDC %d is a National Semiconductor PC87306\n", fdc);
return FDC_87306;
default:
pr_info("FDC %d init: 82078 variant with unknown PARTID=%d.\n",
current_fdc, reply_buffer[0] >> 5);
fdc, reply_buffer[0] >> 5);
return FDC_82078_UNKN;
}
} /* get_fdc_version */
......@@ -4534,11 +4545,13 @@ static void floppy_device_release(struct device *dev)
static int floppy_resume(struct device *dev)
{
int fdc;
int saved_drive;
saved_drive = current_drive;
for (fdc = 0; fdc < N_FDC; fdc++)
if (fdc_state[fdc].address != -1)
user_reset_fdc(-1, FD_RESET_ALWAYS, false);
user_reset_fdc(REVDRIVE(fdc, 0), FD_RESET_ALWAYS, false);
set_fdc(saved_drive);
return 0;
}
......@@ -4646,16 +4659,15 @@ static int __init do_floppy_init(void)
config_types();
for (i = 0; i < N_FDC; i++) {
current_fdc = i;
memset(&fdc_state[current_fdc], 0, sizeof(*fdc_state));
fdc_state[current_fdc].dtr = -1;
fdc_state[current_fdc].dor = 0x4;
memset(&fdc_state[i], 0, sizeof(*fdc_state));
fdc_state[i].dtr = -1;
fdc_state[i].dor = 0x4;
#if defined(__sparc__) || defined(__mc68000__)
/*sparcs/sun3x don't have a DOR reset which we can fall back on to */
#ifdef __mc68000__
if (MACH_IS_SUN3X)
#endif
fdc_state[current_fdc].version = FDC_82072A;
fdc_state[i].version = FDC_82072A;
#endif
}
......@@ -4697,30 +4709,29 @@ static int __init do_floppy_init(void)
msleep(10);
for (i = 0; i < N_FDC; i++) {
current_fdc = i;
fdc_state[current_fdc].driver_version = FD_DRIVER_VERSION;
fdc_state[i].driver_version = FD_DRIVER_VERSION;
for (unit = 0; unit < 4; unit++)
fdc_state[current_fdc].track[unit] = 0;
if (fdc_state[current_fdc].address == -1)
fdc_state[i].track[unit] = 0;
if (fdc_state[i].address == -1)
continue;
fdc_state[current_fdc].rawcmd = 2;
if (user_reset_fdc(-1, FD_RESET_ALWAYS, false)) {
fdc_state[i].rawcmd = 2;
if (user_reset_fdc(REVDRIVE(i, 0), FD_RESET_ALWAYS, false)) {
/* free ioports reserved by floppy_grab_irq_and_dma() */
floppy_release_regions(current_fdc);
fdc_state[current_fdc].address = -1;
fdc_state[current_fdc].version = FDC_NONE;
floppy_release_regions(i);
fdc_state[i].address = -1;
fdc_state[i].version = FDC_NONE;
continue;
}
/* Try to determine the floppy controller type */
fdc_state[current_fdc].version = get_fdc_version();
if (fdc_state[current_fdc].version == FDC_NONE) {
fdc_state[i].version = get_fdc_version(i);
if (fdc_state[i].version == FDC_NONE) {
/* free ioports reserved by floppy_grab_irq_and_dma() */
floppy_release_regions(current_fdc);
fdc_state[current_fdc].address = -1;
floppy_release_regions(i);
fdc_state[i].address = -1;
continue;
}
if (can_use_virtual_dma == 2 &&
fdc_state[current_fdc].version < FDC_82072A)
fdc_state[i].version < FDC_82072A)
can_use_virtual_dma = 0;
have_no_fdc = 0;
......@@ -4728,7 +4739,7 @@ static int __init do_floppy_init(void)
* properly, so force a reset for the standard FDC clones,
* to avoid interrupt garbage.
*/
user_reset_fdc(-1, FD_RESET_ALWAYS, false);
user_reset_fdc(REVDRIVE(i, 0), FD_RESET_ALWAYS, false);
}
current_fdc = 0;
cancel_delayed_work(&fd_timeout);
......@@ -4855,6 +4866,8 @@ static void floppy_release_regions(int fdc)
static int floppy_grab_irq_and_dma(void)
{
int fdc;
if (atomic_inc_return(&usage_count) > 1)
return 0;
......@@ -4882,24 +4895,24 @@ static int floppy_grab_irq_and_dma(void)
}
}
for (current_fdc = 0; current_fdc < N_FDC; current_fdc++) {
if (fdc_state[current_fdc].address != -1) {
if (floppy_request_regions(current_fdc))
for (fdc = 0; fdc < N_FDC; fdc++) {
if (fdc_state[fdc].address != -1) {
if (floppy_request_regions(fdc))
goto cleanup;
}
}
for (current_fdc = 0; current_fdc < N_FDC; current_fdc++) {
if (fdc_state[current_fdc].address != -1) {
reset_fdc_info(1);
fdc_outb(fdc_state[current_fdc].dor, current_fdc, FD_DOR);
for (fdc = 0; fdc < N_FDC; fdc++) {
if (fdc_state[fdc].address != -1) {
reset_fdc_info(fdc, 1);
fdc_outb(fdc_state[fdc].dor, fdc, FD_DOR);
}
}
current_fdc = 0;
set_dor(0, ~0, 8); /* avoid immediate interrupt */
for (current_fdc = 0; current_fdc < N_FDC; current_fdc++)
if (fdc_state[current_fdc].address != -1)
fdc_outb(fdc_state[current_fdc].dor, current_fdc, FD_DOR);
for (fdc = 0; fdc < N_FDC; fdc++)
if (fdc_state[fdc].address != -1)
fdc_outb(fdc_state[fdc].dor, fdc, FD_DOR);
/*
* The driver will try and free resources and relies on us
* to know if they were allocated or not.
......@@ -4910,15 +4923,16 @@ static int floppy_grab_irq_and_dma(void)
cleanup:
fd_free_irq();
fd_free_dma();
while (--current_fdc >= 0)
floppy_release_regions(current_fdc);
while (--fdc >= 0)
floppy_release_regions(fdc);
current_fdc = 0;
atomic_dec(&usage_count);
return -1;
}
static void floppy_release_irq_and_dma(void)
{
int old_fdc;
int fdc;
#ifndef __sparc__
int drive;
#endif
......@@ -4959,11 +4973,9 @@ static void floppy_release_irq_and_dma(void)
pr_info("auxiliary floppy timer still active\n");
if (work_pending(&floppy_work))
pr_info("work still pending\n");
old_fdc = current_fdc;
for (current_fdc = 0; current_fdc < N_FDC; current_fdc++)
if (fdc_state[current_fdc].address != -1)
floppy_release_regions(current_fdc);
current_fdc = old_fdc;
for (fdc = 0; fdc < N_FDC; fdc++)
if (fdc_state[fdc].address != -1)
floppy_release_regions(fdc);
}
#ifdef MODULE
......
......@@ -172,7 +172,10 @@ struct floppy_drive_params {
* used in succession to try to read the disk. If the FDC cannot lock onto
* the disk, the next format is tried. This uses the variable 'probing'.
*/
short autodetect[8]; /* autodetected formats */
#define FD_AUTODETECT_SIZE 8
short autodetect[FD_AUTODETECT_SIZE]; /* autodetected formats */
int checkfreq; /* how often should the drive be checked for disk
* changes */
......@@ -357,10 +360,25 @@ struct floppy_raw_cmd {
int buffer_length; /* length of allocated buffer */
unsigned char rate;
#define FD_RAW_CMD_SIZE 16
#define FD_RAW_REPLY_SIZE 16
#define FD_RAW_CMD_FULLSIZE (FD_RAW_CMD_SIZE + 1 + FD_RAW_REPLY_SIZE)
/* The command may take up the space initially intended for the reply
* and the reply count. Needed for long 82078 commands such as RESTORE,
* which takes 17 command bytes.
*/
unsigned char cmd_count;
unsigned char cmd[16];
unsigned char reply_count;
unsigned char reply[16];
union {
struct {
unsigned char cmd[FD_RAW_CMD_SIZE];
unsigned char reply_count;
unsigned char reply[FD_RAW_REPLY_SIZE];
};
unsigned char fullcmd[FD_RAW_CMD_FULLSIZE];
};
int track;
int resultcode;
......
......@@ -7,13 +7,23 @@
* Handbook", Sanches and Canton.
*/
/* Fd controller regs. S&C, about page 340 */
#define FD_STATUS 4
#define FD_DATA 5
/* 82077's auxiliary status registers A & B (R) */
#define FD_SRA 0
#define FD_SRB 1
/* Digital Output Register */
#define FD_DOR 2
/* 82077's tape drive register (R/W) */
#define FD_TDR 3
/* 82077's data rate select register (W) */
#define FD_DSR 4
/* Fd controller regs. S&C, about page 340 */
#define FD_STATUS 4
#define FD_DATA 5
/* Digital Input Register (read) */
#define FD_DIR 7
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment