2005-04-17 02:20:36 +04:00
/*
* skisa . c : A network driver for SK - NET TMS380 - based ISA token ring cards .
*
* Based on tmspci written 1999 by Adam Fritzler
*
* Written 2000 by Jochen Friedrich
* Dedicated to my girlfriend Steffi Bopp
*
* This software may be used and distributed according to the terms
* of the GNU General Public License , incorporated herein by reference .
*
* This driver module supports the following cards :
* - SysKonnect TR4 / 16 ( + ) ISA ( SK - 4190 )
*
* Maintainer ( s ) :
* AF Adam Fritzler mid @ auk . cx
* JF Jochen Friedrich jochen @ scram . de
*
* Modification History :
* 14 - Jan - 01 JF Created
* 28 - Oct - 02 JF Fixed probe of card for static compilation .
* Fixed module init to not make hotplug go wild .
* 09 - Nov - 02 JF Fixed early bail out on out of memory
* situations if multiple cards are found .
* Cleaned up some unnecessary console SPAM .
* 09 - Dec - 02 JF Fixed module reference counting .
* 02 - Jan - 03 JF Renamed to skisa . c
*
*/
static const char version [ ] = " skisa.c: v1.03 09/12/2002 by Jochen Friedrich \n " ;
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/errno.h>
# include <linux/pci.h>
# include <linux/init.h>
# include <linux/netdevice.h>
# include <linux/trdevice.h>
# include <asm/system.h>
# include <asm/io.h>
# include <asm/irq.h>
# include <asm/pci.h>
# include <asm/dma.h>
# include "tms380tr.h"
# define SK_ISA_IO_EXTENT 32
/* A zero-terminated list of I/O addresses to be probed. */
static unsigned int portlist [ ] __initdata = {
0x0A20 , 0x1A20 , 0x0B20 , 0x1B20 , 0x0980 , 0x1980 , 0x0900 , 0x1900 , // SK
0
} ;
/* A zero-terminated list of IRQs to be probed.
* Used again after initial probe for sktr_chipset_init , called from sktr_open .
*/
static const unsigned short irqlist [ ] = {
3 , 5 , 9 , 10 , 11 , 12 , 15 ,
0
} ;
/* A zero-terminated list of DMAs to be probed. */
static int dmalist [ ] __initdata = {
5 , 6 , 7 ,
0
} ;
static char isa_cardname [ ] = " SK NET TR 4/16 ISA \0 " ;
2005-07-27 12:14:50 +04:00
static u64 dma_mask = ISA_MAX_ADDRESS ;
2005-04-17 02:20:36 +04:00
static int sk_isa_open ( struct net_device * dev ) ;
static void sk_isa_read_eeprom ( struct net_device * dev ) ;
static unsigned short sk_isa_setnselout_pins ( struct net_device * dev ) ;
static unsigned short sk_isa_sifreadb ( struct net_device * dev , unsigned short reg )
{
return inb ( dev - > base_addr + reg ) ;
}
static unsigned short sk_isa_sifreadw ( struct net_device * dev , unsigned short reg )
{
return inw ( dev - > base_addr + reg ) ;
}
static void sk_isa_sifwriteb ( struct net_device * dev , unsigned short val , unsigned short reg )
{
outb ( val , dev - > base_addr + reg ) ;
}
static void sk_isa_sifwritew ( struct net_device * dev , unsigned short val , unsigned short reg )
{
outw ( val , dev - > base_addr + reg ) ;
}
static int __init sk_isa_probe1 ( struct net_device * dev , int ioaddr )
{
unsigned char old , chk1 , chk2 ;
if ( ! request_region ( ioaddr , SK_ISA_IO_EXTENT , isa_cardname ) )
return - ENODEV ;
old = inb ( ioaddr + SIFADR ) ; /* Get the old SIFADR value */
chk1 = 0 ; /* Begin with check value 0 */
do {
/* Write new SIFADR value */
outb ( chk1 , ioaddr + SIFADR ) ;
/* Read, invert and write */
chk2 = inb ( ioaddr + SIFADD ) ;
chk2 ^ = 0x0FE ;
outb ( chk2 , ioaddr + SIFADR ) ;
/* Read, invert and compare */
chk2 = inb ( ioaddr + SIFADD ) ;
chk2 ^ = 0x0FE ;
if ( chk1 ! = chk2 ) {
release_region ( ioaddr , SK_ISA_IO_EXTENT ) ;
return - ENODEV ;
}
chk1 - = 2 ;
} while ( chk1 ! = 0 ) ; /* Repeat 128 times (all byte values) */
/* Restore the SIFADR value */
outb ( old , ioaddr + SIFADR ) ;
dev - > base_addr = ioaddr ;
return 0 ;
}
2005-07-27 12:14:50 +04:00
static int __init setup_card ( struct net_device * dev , struct device * pdev )
2005-04-17 02:20:36 +04:00
{
struct net_local * tp ;
static int versionprinted ;
const unsigned * port ;
int j , err = 0 ;
if ( ! dev )
return - ENOMEM ;
SET_MODULE_OWNER ( dev ) ;
if ( dev - > base_addr ) /* probe specific location */
err = sk_isa_probe1 ( dev , dev - > base_addr ) ;
else {
for ( port = portlist ; * port ; port + + ) {
err = sk_isa_probe1 ( dev , * port ) ;
if ( ! err )
break ;
}
}
if ( err )
2005-07-27 12:14:50 +04:00
goto out5 ;
2005-04-17 02:20:36 +04:00
/* At this point we have found a valid card. */
if ( versionprinted + + = = 0 )
printk ( KERN_DEBUG " %s " , version ) ;
err = - EIO ;
2005-07-27 12:14:50 +04:00
pdev - > dma_mask = & dma_mask ;
2005-08-20 05:05:56 +04:00
if ( tmsdev_init ( dev , pdev ) )
2005-04-17 02:20:36 +04:00
goto out4 ;
dev - > base_addr & = ~ 3 ;
sk_isa_read_eeprom ( dev ) ;
2005-07-27 12:14:50 +04:00
printk ( KERN_DEBUG " skisa.c: Ring Station Address: " ) ;
2005-04-17 02:20:36 +04:00
printk ( " %2.2x " , dev - > dev_addr [ 0 ] ) ;
for ( j = 1 ; j < 6 ; j + + )
printk ( " :%2.2x " , dev - > dev_addr [ j ] ) ;
printk ( " \n " ) ;
tp = netdev_priv ( dev ) ;
tp - > setnselout = sk_isa_setnselout_pins ;
tp - > sifreadb = sk_isa_sifreadb ;
tp - > sifreadw = sk_isa_sifreadw ;
tp - > sifwriteb = sk_isa_sifwriteb ;
tp - > sifwritew = sk_isa_sifwritew ;
memcpy ( tp - > ProductID , isa_cardname , PROD_ID_SIZE + 1 ) ;
tp - > tmspriv = NULL ;
dev - > open = sk_isa_open ;
dev - > stop = tms380tr_close ;
if ( dev - > irq = = 0 )
{
for ( j = 0 ; irqlist [ j ] ! = 0 ; j + + )
{
dev - > irq = irqlist [ j ] ;
if ( ! request_irq ( dev - > irq , tms380tr_interrupt , 0 ,
isa_cardname , dev ) )
break ;
}
if ( irqlist [ j ] = = 0 )
{
2005-07-27 12:14:50 +04:00
printk ( KERN_INFO " skisa.c: AutoSelect no IRQ available \n " ) ;
2005-04-17 02:20:36 +04:00
goto out3 ;
}
}
else
{
for ( j = 0 ; irqlist [ j ] ! = 0 ; j + + )
if ( irqlist [ j ] = = dev - > irq )
break ;
if ( irqlist [ j ] = = 0 )
{
2005-07-27 12:14:50 +04:00
printk ( KERN_INFO " skisa.c: Illegal IRQ %d specified \n " ,
dev - > irq ) ;
2005-04-17 02:20:36 +04:00
goto out3 ;
}
if ( request_irq ( dev - > irq , tms380tr_interrupt , 0 ,
isa_cardname , dev ) )
{
2005-07-27 12:14:50 +04:00
printk ( KERN_INFO " skisa.c: Selected IRQ %d not available \n " ,
dev - > irq ) ;
2005-04-17 02:20:36 +04:00
goto out3 ;
}
}
if ( dev - > dma = = 0 )
{
for ( j = 0 ; dmalist [ j ] ! = 0 ; j + + )
{
dev - > dma = dmalist [ j ] ;
if ( ! request_dma ( dev - > dma , isa_cardname ) )
break ;
}
if ( dmalist [ j ] = = 0 )
{
2005-07-27 12:14:50 +04:00
printk ( KERN_INFO " skisa.c: AutoSelect no DMA available \n " ) ;
2005-04-17 02:20:36 +04:00
goto out2 ;
}
}
else
{
for ( j = 0 ; dmalist [ j ] ! = 0 ; j + + )
if ( dmalist [ j ] = = dev - > dma )
break ;
if ( dmalist [ j ] = = 0 )
{
2005-07-27 12:14:50 +04:00
printk ( KERN_INFO " skisa.c: Illegal DMA %d specified \n " ,
dev - > dma ) ;
2005-04-17 02:20:36 +04:00
goto out2 ;
}
if ( request_dma ( dev - > dma , isa_cardname ) )
{
2005-07-27 12:14:50 +04:00
printk ( KERN_INFO " skisa.c: Selected DMA %d not available \n " ,
dev - > dma ) ;
2005-04-17 02:20:36 +04:00
goto out2 ;
}
}
err = register_netdev ( dev ) ;
if ( err )
goto out ;
2005-07-27 12:14:50 +04:00
printk ( KERN_DEBUG " %s: IO: %#4lx IRQ: %d DMA: %d \n " ,
dev - > name , dev - > base_addr , dev - > irq , dev - > dma ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
out :
free_dma ( dev - > dma ) ;
out2 :
free_irq ( dev - > irq , dev ) ;
out3 :
tmsdev_term ( dev ) ;
out4 :
2005-07-27 12:14:50 +04:00
release_region ( dev - > base_addr , SK_ISA_IO_EXTENT ) ;
out5 :
2005-04-17 02:20:36 +04:00
return err ;
}
/*
* Reads MAC address from adapter RAM , which should ' ve read it from
* the onboard ROM .
*
* Calling this on a board that does not support it can be a very
* dangerous thing . The Madge board , for instance , will lock your
* machine hard when this is called . Luckily , its supported in a
* separate driver . - - ASF
*/
static void sk_isa_read_eeprom ( struct net_device * dev )
{
int i ;
/* Address: 0000:0000 */
sk_isa_sifwritew ( dev , 0 , SIFADX ) ;
sk_isa_sifwritew ( dev , 0 , SIFADR ) ;
/* Read six byte MAC address data */
dev - > addr_len = 6 ;
for ( i = 0 ; i < 6 ; i + + )
dev - > dev_addr [ i ] = sk_isa_sifreadw ( dev , SIFINC ) > > 8 ;
}
unsigned short sk_isa_setnselout_pins ( struct net_device * dev )
{
return 0 ;
}
static int sk_isa_open ( struct net_device * dev )
{
struct net_local * tp = netdev_priv ( dev ) ;
unsigned short val = 0 ;
unsigned short oldval ;
int i ;
val = 0 ;
for ( i = 0 ; irqlist [ i ] ! = 0 ; i + + )
{
if ( irqlist [ i ] = = dev - > irq )
break ;
}
val | = CYCLE_TIME < < 2 ;
val | = i < < 4 ;
i = dev - > dma - 5 ;
val | = i ;
if ( tp - > DataRate = = SPEED_4 )
val | = LINE_SPEED_BIT ;
else
val & = ~ LINE_SPEED_BIT ;
oldval = sk_isa_sifreadb ( dev , POSREG ) ;
/* Leave cycle bits alone */
oldval | = 0xf3 ;
val & = oldval ;
sk_isa_sifwriteb ( dev , val , POSREG ) ;
return tms380tr_open ( dev ) ;
}
# define ISATR_MAX_ADAPTERS 3
static int io [ ISATR_MAX_ADAPTERS ] ;
static int irq [ ISATR_MAX_ADAPTERS ] ;
static int dma [ ISATR_MAX_ADAPTERS ] ;
MODULE_LICENSE ( " GPL " ) ;
module_param_array ( io , int , NULL , 0 ) ;
module_param_array ( irq , int , NULL , 0 ) ;
module_param_array ( dma , int , NULL , 0 ) ;
2005-07-27 12:14:50 +04:00
static struct platform_device * sk_isa_dev [ ISATR_MAX_ADAPTERS ] ;
2005-04-17 02:20:36 +04:00
2005-07-27 12:14:50 +04:00
static struct device_driver sk_isa_driver = {
. name = " skisa " ,
. bus = & platform_bus_type ,
} ;
static int __init sk_isa_init ( void )
2005-04-17 02:20:36 +04:00
{
struct net_device * dev ;
2005-07-27 12:14:50 +04:00
struct platform_device * pdev ;
2005-04-17 02:20:36 +04:00
int i , num = 0 , err = 0 ;
2005-07-27 12:14:50 +04:00
err = driver_register ( & sk_isa_driver ) ;
if ( err )
return err ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < ISATR_MAX_ADAPTERS ; i + + ) {
dev = alloc_trdev ( sizeof ( struct net_local ) ) ;
if ( ! dev )
continue ;
dev - > base_addr = io [ i ] ;
dev - > irq = irq [ i ] ;
dev - > dma = dma [ i ] ;
2005-07-27 12:14:50 +04:00
pdev = platform_device_register_simple ( " skisa " ,
i , NULL , 0 ) ;
err = setup_card ( dev , & pdev - > dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! err ) {
2005-07-27 12:14:50 +04:00
sk_isa_dev [ i ] = pdev ;
dev_set_drvdata ( & sk_isa_dev [ i ] - > dev , dev ) ;
2005-04-17 02:20:36 +04:00
+ + num ;
} else {
2005-07-27 12:14:50 +04:00
platform_device_unregister ( pdev ) ;
2005-04-17 02:20:36 +04:00
free_netdev ( dev ) ;
}
}
printk ( KERN_NOTICE " skisa.c: %d cards found. \n " , num ) ;
/* Probe for cards. */
if ( num = = 0 ) {
printk ( KERN_NOTICE " skisa.c: No cards found. \n " ) ;
return ( - ENODEV ) ;
}
return ( 0 ) ;
}
2005-07-27 12:14:50 +04:00
static void __exit sk_isa_cleanup ( void )
2005-04-17 02:20:36 +04:00
{
2005-07-27 12:14:50 +04:00
struct net_device * dev ;
2005-04-17 02:20:36 +04:00
int i ;
for ( i = 0 ; i < ISATR_MAX_ADAPTERS ; i + + ) {
2005-07-27 12:14:50 +04:00
struct platform_device * pdev = sk_isa_dev [ i ] ;
2005-04-17 02:20:36 +04:00
2005-07-27 12:14:50 +04:00
if ( ! pdev )
2005-04-17 02:20:36 +04:00
continue ;
2005-07-27 12:14:50 +04:00
dev = dev_get_drvdata ( & pdev - > dev ) ;
2005-04-17 02:20:36 +04:00
unregister_netdev ( dev ) ;
release_region ( dev - > base_addr , SK_ISA_IO_EXTENT ) ;
free_irq ( dev - > irq , dev ) ;
free_dma ( dev - > dma ) ;
tmsdev_term ( dev ) ;
free_netdev ( dev ) ;
2005-07-27 12:14:50 +04:00
dev_set_drvdata ( & pdev - > dev , NULL ) ;
platform_device_unregister ( pdev ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-27 12:14:50 +04:00
driver_unregister ( & sk_isa_driver ) ;
2005-04-17 02:20:36 +04:00
}
2005-07-27 12:14:50 +04:00
module_init ( sk_isa_init ) ;
module_exit ( sk_isa_cleanup ) ;