2005-04-17 02:20:36 +04:00
/*
* Implementation independent bits of the Floppy driver .
*
* much of this file is derived from what was originally the Q40 floppy driver .
*
* This file is subject to the terms and conditions of the GNU General Public
* License . See the file " COPYING " in the main directory of this archive
* for more details .
*
* Copyright ( C ) 1999 , 2000 , 2001
*
* Sun3x support added 2 / 4 / 2000 Sam Creasey ( sammy @ sammy . net )
*
*/
# include <asm/io.h>
# include <linux/vmalloc.h>
2006-10-07 17:16:45 +04:00
asmlinkage irqreturn_t floppy_hardint ( int irq , void * dev_id ) ;
2005-04-17 02:20:36 +04:00
/* constants... */
# undef MAX_DMA_ADDRESS
# define MAX_DMA_ADDRESS 0x00 /* nothing like that */
/*
* Again , the CMOS information doesn ' t work on m68k . .
*/
# define FLOPPY0_TYPE (MACH_IS_Q40 ? 6 : 4)
# define FLOPPY1_TYPE 0
/* basically PC init + set use_virtual_dma */
# define FDC1 m68k_floppy_init()
# define N_FDC 1
# define N_DRIVE 8
/* vdma globals adapted from asm-i386/floppy.h */
static int virtual_dma_count = 0 ;
static int virtual_dma_residue = 0 ;
2006-01-12 12:06:34 +03:00
static char * virtual_dma_addr = NULL ;
2005-04-17 02:20:36 +04:00
static int virtual_dma_mode = 0 ;
static int doing_pdma = 0 ;
# include <asm/sun3xflop.h>
extern spinlock_t dma_spin_lock ;
static __inline__ unsigned long claim_dma_lock ( void )
{
unsigned long flags ;
spin_lock_irqsave ( & dma_spin_lock , flags ) ;
return flags ;
}
static __inline__ void release_dma_lock ( unsigned long flags )
{
spin_unlock_irqrestore ( & dma_spin_lock , flags ) ;
}
static __inline__ unsigned char fd_inb ( int port )
{
if ( MACH_IS_Q40 )
return inb_p ( port ) ;
else if ( MACH_IS_SUN3X )
return sun3x_82072_fd_inb ( port ) ;
return 0 ;
}
static __inline__ void fd_outb ( unsigned char value , int port )
{
if ( MACH_IS_Q40 )
outb_p ( value , port ) ;
else if ( MACH_IS_SUN3X )
sun3x_82072_fd_outb ( value , port ) ;
}
static int fd_request_irq ( void )
{
if ( MACH_IS_Q40 )
2006-07-02 06:29:19 +04:00
return request_irq ( FLOPPY_IRQ , floppy_hardint ,
IRQF_DISABLED , " floppy " , floppy_hardint ) ;
2005-04-17 02:20:36 +04:00
else if ( MACH_IS_SUN3X )
return sun3xflop_request_irq ( ) ;
return - ENXIO ;
}
static void fd_free_irq ( void )
{
if ( MACH_IS_Q40 )
free_irq ( FLOPPY_IRQ , floppy_hardint ) ;
}
# define fd_request_dma() vdma_request_dma(FLOPPY_DMA,"floppy")
# define fd_get_dma_residue() vdma_get_dma_residue(FLOPPY_DMA)
# define fd_dma_mem_alloc(size) vdma_mem_alloc(size)
# define fd_dma_setup(addr, size, mode, io) vdma_dma_setup(addr, size, mode, io)
# define fd_enable_irq() /* nothing... */
# define fd_disable_irq() /* nothing... */
# define fd_free_dma() /* nothing */
/* No 64k boundary crossing problems on Q40 - no DMA at all */
# define CROSS_64KB(a,s) (0)
# define DMA_MODE_READ 0x44 /* i386 look-alike */
# define DMA_MODE_WRITE 0x48
static int m68k_floppy_init ( void )
{
use_virtual_dma = 1 ;
can_use_virtual_dma = 1 ;
if ( MACH_IS_Q40 )
return 0x3f0 ;
else if ( MACH_IS_SUN3X )
return sun3xflop_init ( ) ;
else
return - 1 ;
}
static int vdma_request_dma ( unsigned int dmanr , const char * device_id )
{
return 0 ;
}
static int vdma_get_dma_residue ( unsigned int dummy )
{
return virtual_dma_count + virtual_dma_residue ;
}
static unsigned long vdma_mem_alloc ( unsigned long size )
{
return ( unsigned long ) vmalloc ( size ) ;
}
static void _fd_dma_mem_free ( unsigned long addr , unsigned long size )
{
vfree ( ( void * ) addr ) ;
}
# define fd_dma_mem_free(addr,size) _fd_dma_mem_free(addr, size)
/* choose_dma_mode ???*/
static int vdma_dma_setup ( char * addr , unsigned long size , int mode , int io )
{
doing_pdma = 1 ;
virtual_dma_port = ( MACH_IS_Q40 ? io : 0 ) ;
virtual_dma_mode = ( mode = = DMA_MODE_WRITE ) ;
virtual_dma_addr = addr ;
virtual_dma_count = size ;
virtual_dma_residue = 0 ;
return 0 ;
}
static void fd_disable_dma ( void )
{
doing_pdma = 0 ;
virtual_dma_residue + = virtual_dma_count ;
virtual_dma_count = 0 ;
}
/* this is the only truly Q40 specific function */
2006-10-07 17:16:45 +04:00
asmlinkage irqreturn_t floppy_hardint ( int irq , void * dev_id )
2005-04-17 02:20:36 +04:00
{
register unsigned char st ;
# undef TRACE_FLPY_INT
# define NO_FLOPPY_ASSEMBLER
# ifdef TRACE_FLPY_INT
static int calls = 0 ;
static int bytes = 0 ;
static int dma_wait = 0 ;
# endif
if ( ! doing_pdma ) {
2006-10-07 17:16:45 +04:00
floppy_interrupt ( irq , dev_id ) ;
2005-04-17 02:20:36 +04:00
return IRQ_HANDLED ;
}
# ifdef TRACE_FLPY_INT
if ( ! calls )
bytes = virtual_dma_count ;
# endif
{
register int lcount ;
register char * lptr ;
/* serve 1st byte fast: */
st = 1 ;
for ( lcount = virtual_dma_count , lptr = virtual_dma_addr ;
lcount ; lcount - - , lptr + + ) {
st = inb ( virtual_dma_port + 4 ) & 0xa0 ;
if ( st ! = 0xa0 )
break ;
if ( virtual_dma_mode )
outb_p ( * lptr , virtual_dma_port + 5 ) ;
else
* lptr = inb_p ( virtual_dma_port + 5 ) ;
}
virtual_dma_count = lcount ;
virtual_dma_addr = lptr ;
st = inb ( virtual_dma_port + 4 ) ;
}
# ifdef TRACE_FLPY_INT
calls + + ;
# endif
if ( st = = 0x20 )
return IRQ_HANDLED ;
if ( ! ( st & 0x20 ) ) {
virtual_dma_residue + = virtual_dma_count ;
virtual_dma_count = 0 ;
# ifdef TRACE_FLPY_INT
printk ( " count=%x, residue=%x calls=%d bytes=%d dma_wait=%d \n " ,
virtual_dma_count , virtual_dma_residue , calls , bytes ,
dma_wait ) ;
calls = 0 ;
dma_wait = 0 ;
# endif
doing_pdma = 0 ;
2006-10-07 17:16:45 +04:00
floppy_interrupt ( irq , dev_id ) ;
2005-04-17 02:20:36 +04:00
return IRQ_HANDLED ;
}
# ifdef TRACE_FLPY_INT
if ( ! virtual_dma_count )
dma_wait + + ;
# endif
return IRQ_HANDLED ;
}
# define EXTRA_FLOPPY_PARAMS