2005-04-16 15:20:36 -07:00
/*
* proteon . c : A network driver for Proteon ISA token ring cards .
*
* Based on tmspci written 1999 by Adam Fritzler
*
* Written 2003 by Jochen Friedrich
*
* 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 :
* - Proteon 1392 , 1392 +
*
* Maintainer ( s ) :
* AF Adam Fritzler mid @ auk . cx
* JF Jochen Friedrich jochen @ scram . de
*
* Modification History :
* 02 - Jan - 03 JF Created
*
*/
static const char version [ ] = " proteon.c: v1.00 02/01/2003 by Jochen Friedrich \n " ;
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/delay.h>
# include <linux/errno.h>
# include <linux/pci.h>
# include <linux/init.h>
# include <linux/netdevice.h>
# include <linux/trdevice.h>
2005-10-29 19:07:23 +01:00
# include <linux/platform_device.h>
2005-04-16 15:20:36 -07:00
# include <asm/system.h>
# include <asm/io.h>
# include <asm/irq.h>
# include <asm/pci.h>
# include <asm/dma.h>
# include "tms380tr.h"
# define PROTEON_IO_EXTENT 32
/* A zero-terminated list of I/O addresses to be probed. */
static unsigned int portlist [ ] __initdata = {
0x0A20 , 0x0E20 , 0x1A20 , 0x1E20 , 0x2A20 , 0x2E20 , 0x3A20 , 0x3E20 , // Prot.
0x4A20 , 0x4E20 , 0x5A20 , 0x5E20 , 0x6A20 , 0x6E20 , 0x7A20 , 0x7E20 , // Prot.
0x8A20 , 0x8E20 , 0x9A20 , 0x9E20 , 0xAA20 , 0xAE20 , 0xBA20 , 0xBE20 , // Prot.
0xCA20 , 0xCE20 , 0xDA20 , 0xDE20 , 0xEA20 , 0xEE20 , 0xFA20 , 0xFE20 , // Prot.
0
} ;
/* A zero-terminated list of IRQs to be probed. */
static unsigned short irqlist [ ] = {
7 , 6 , 5 , 4 , 3 , 12 , 11 , 10 , 9 ,
0
} ;
/* A zero-terminated list of DMAs to be probed. */
static int dmalist [ ] __initdata = {
5 , 6 , 7 ,
0
} ;
static char cardname [ ] = " Proteon 1392 \0 " ;
2005-07-27 01:14:50 -07:00
static u64 dma_mask = ISA_MAX_ADDRESS ;
2005-04-16 15:20:36 -07:00
static int proteon_open ( struct net_device * dev ) ;
static void proteon_read_eeprom ( struct net_device * dev ) ;
static unsigned short proteon_setnselout_pins ( struct net_device * dev ) ;
static unsigned short proteon_sifreadb ( struct net_device * dev , unsigned short reg )
{
return inb ( dev - > base_addr + reg ) ;
}
static unsigned short proteon_sifreadw ( struct net_device * dev , unsigned short reg )
{
return inw ( dev - > base_addr + reg ) ;
}
static void proteon_sifwriteb ( struct net_device * dev , unsigned short val , unsigned short reg )
{
outb ( val , dev - > base_addr + reg ) ;
}
static void proteon_sifwritew ( struct net_device * dev , unsigned short val , unsigned short reg )
{
outw ( val , dev - > base_addr + reg ) ;
}
static int __init proteon_probe1 ( struct net_device * dev , int ioaddr )
{
unsigned char chk1 , chk2 ;
int i ;
if ( ! request_region ( ioaddr , PROTEON_IO_EXTENT , cardname ) )
return - ENODEV ;
chk1 = inb ( ioaddr + 0x1f ) ; /* Get Proteon ID reg 1 */
if ( chk1 ! = 0x1f )
goto nodev ;
chk1 = inb ( ioaddr + 0x1e ) & 0x07 ; /* Get Proteon ID reg 0 */
for ( i = 0 ; i < 16 ; i + + ) {
chk2 = inb ( ioaddr + 0x1e ) & 0x07 ;
if ( ( ( chk1 + 1 ) & 0x07 ) ! = chk2 )
goto nodev ;
chk1 = chk2 ;
}
dev - > base_addr = ioaddr ;
return ( 0 ) ;
nodev :
release_region ( ioaddr , PROTEON_IO_EXTENT ) ;
return - ENODEV ;
}
2005-07-27 01:14:50 -07:00
static int __init setup_card ( struct net_device * dev , struct device * pdev )
2005-04-16 15:20:36 -07:00
{
struct net_local * tp ;
static int versionprinted ;
const unsigned * port ;
int j , err = 0 ;
2007-10-03 17:59:30 -07:00
DECLARE_MAC_BUF ( mac ) ;
2005-04-16 15:20:36 -07:00
if ( ! dev )
return - ENOMEM ;
if ( dev - > base_addr ) /* probe specific location */
err = proteon_probe1 ( dev , dev - > base_addr ) ;
else {
for ( port = portlist ; * port ; port + + ) {
err = proteon_probe1 ( dev , * port ) ;
if ( ! err )
break ;
}
}
if ( err )
2005-07-27 01:14:50 -07:00
goto out5 ;
2005-04-16 15:20:36 -07:00
/* At this point we have found a valid card. */
if ( versionprinted + + = = 0 )
printk ( KERN_DEBUG " %s " , version ) ;
err = - EIO ;
2005-07-27 01:14:50 -07:00
pdev - > dma_mask = & dma_mask ;
2005-08-19 21:05:56 -04:00
if ( tmsdev_init ( dev , pdev ) )
2005-04-16 15:20:36 -07:00
goto out4 ;
dev - > base_addr & = ~ 3 ;
proteon_read_eeprom ( dev ) ;
2007-10-03 17:59:30 -07:00
printk ( KERN_DEBUG " proteon.c: Ring Station Address: %s \n " ,
print_mac ( mac , dev - > dev_addr ) ) ;
2005-04-16 15:20:36 -07:00
tp = netdev_priv ( dev ) ;
tp - > setnselout = proteon_setnselout_pins ;
tp - > sifreadb = proteon_sifreadb ;
tp - > sifreadw = proteon_sifreadw ;
tp - > sifwriteb = proteon_sifwriteb ;
tp - > sifwritew = proteon_sifwritew ;
memcpy ( tp - > ProductID , cardname , PROD_ID_SIZE + 1 ) ;
tp - > tmspriv = NULL ;
dev - > open = proteon_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 ,
cardname , dev ) )
break ;
}
if ( irqlist [ j ] = = 0 )
{
2005-07-27 01:14:50 -07:00
printk ( KERN_INFO " proteon.c: AutoSelect no IRQ available \n " ) ;
2005-04-16 15:20:36 -07:00
goto out3 ;
}
}
else
{
for ( j = 0 ; irqlist [ j ] ! = 0 ; j + + )
if ( irqlist [ j ] = = dev - > irq )
break ;
if ( irqlist [ j ] = = 0 )
{
2005-07-27 01:14:50 -07:00
printk ( KERN_INFO " proteon.c: Illegal IRQ %d specified \n " ,
dev - > irq ) ;
2005-04-16 15:20:36 -07:00
goto out3 ;
}
if ( request_irq ( dev - > irq , tms380tr_interrupt , 0 ,
cardname , dev ) )
{
2005-07-27 01:14:50 -07:00
printk ( KERN_INFO " proteon.c: Selected IRQ %d not available \n " ,
dev - > irq ) ;
2005-04-16 15:20:36 -07:00
goto out3 ;
}
}
if ( dev - > dma = = 0 )
{
for ( j = 0 ; dmalist [ j ] ! = 0 ; j + + )
{
dev - > dma = dmalist [ j ] ;
if ( ! request_dma ( dev - > dma , cardname ) )
break ;
}
if ( dmalist [ j ] = = 0 )
{
2005-07-27 01:14:50 -07:00
printk ( KERN_INFO " proteon.c: AutoSelect no DMA available \n " ) ;
2005-04-16 15:20:36 -07:00
goto out2 ;
}
}
else
{
for ( j = 0 ; dmalist [ j ] ! = 0 ; j + + )
if ( dmalist [ j ] = = dev - > dma )
break ;
if ( dmalist [ j ] = = 0 )
{
2005-07-27 01:14:50 -07:00
printk ( KERN_INFO " proteon.c: Illegal DMA %d specified \n " ,
dev - > dma ) ;
2005-04-16 15:20:36 -07:00
goto out2 ;
}
if ( request_dma ( dev - > dma , cardname ) )
{
2005-07-27 01:14:50 -07:00
printk ( KERN_INFO " proteon.c: Selected DMA %d not available \n " ,
dev - > dma ) ;
2005-04-16 15:20:36 -07:00
goto out2 ;
}
}
err = register_netdev ( dev ) ;
if ( err )
goto out ;
2005-07-27 01:14:50 -07:00
printk ( KERN_DEBUG " %s: IO: %#4lx IRQ: %d DMA: %d \n " ,
dev - > name , dev - > base_addr , dev - > irq , dev - > dma ) ;
2005-04-16 15:20:36 -07:00
return 0 ;
out :
free_dma ( dev - > dma ) ;
out2 :
free_irq ( dev - > irq , dev ) ;
out3 :
tmsdev_term ( dev ) ;
out4 :
2005-07-27 01:14:50 -07:00
release_region ( dev - > base_addr , PROTEON_IO_EXTENT ) ;
out5 :
2005-04-16 15:20:36 -07: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 proteon_read_eeprom ( struct net_device * dev )
{
int i ;
/* Address: 0000:0000 */
proteon_sifwritew ( dev , 0 , SIFADX ) ;
proteon_sifwritew ( dev , 0 , SIFADR ) ;
/* Read six byte MAC address data */
dev - > addr_len = 6 ;
for ( i = 0 ; i < 6 ; i + + )
dev - > dev_addr [ i ] = proteon_sifreadw ( dev , SIFINC ) > > 8 ;
}
unsigned short proteon_setnselout_pins ( struct net_device * dev )
{
return 0 ;
}
static int proteon_open ( struct net_device * dev )
{
struct net_local * tp = netdev_priv ( dev ) ;
unsigned short val = 0 ;
int i ;
/* Proteon reset sequence */
outb ( 0 , dev - > base_addr + 0x11 ) ;
mdelay ( 20 ) ;
outb ( 0x04 , dev - > base_addr + 0x11 ) ;
mdelay ( 20 ) ;
outb ( 0 , dev - > base_addr + 0x11 ) ;
mdelay ( 100 ) ;
/* set control/status reg */
val = inb ( dev - > base_addr + 0x11 ) ;
val | = 0x78 ;
val & = 0xf9 ;
if ( tp - > DataRate = = SPEED_4 )
val | = 0x20 ;
else
val & = ~ 0x20 ;
outb ( val , dev - > base_addr + 0x11 ) ;
outb ( 0xff , dev - > base_addr + 0x12 ) ;
for ( i = 0 ; irqlist [ i ] ! = 0 ; i + + )
{
if ( irqlist [ i ] = = dev - > irq )
break ;
}
val = i ;
i = ( 7 - dev - > dma ) < < 4 ;
val | = i ;
outb ( val , dev - > base_addr + 0x13 ) ;
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 01:14:50 -07:00
static struct platform_device * proteon_dev [ ISATR_MAX_ADAPTERS ] ;
2005-11-09 22:32:44 +00:00
static struct platform_driver proteon_driver = {
. driver = {
. name = " proteon " ,
} ,
2005-07-27 01:14:50 -07:00
} ;
2005-04-16 15:20:36 -07:00
2005-07-27 01:14:50 -07:00
static int __init proteon_init ( void )
2005-04-16 15:20:36 -07:00
{
struct net_device * dev ;
2005-07-27 01:14:50 -07:00
struct platform_device * pdev ;
2005-04-16 15:20:36 -07:00
int i , num = 0 , err = 0 ;
2005-11-09 22:32:44 +00:00
err = platform_driver_register ( & proteon_driver ) ;
2005-07-27 01:14:50 -07:00
if ( err )
return err ;
2005-04-16 15:20:36 -07: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 01:14:50 -07:00
pdev = platform_device_register_simple ( " proteon " ,
i , NULL , 0 ) ;
2006-10-29 03:52:14 +09:00
if ( IS_ERR ( pdev ) ) {
free_netdev ( dev ) ;
continue ;
}
2005-07-27 01:14:50 -07:00
err = setup_card ( dev , & pdev - > dev ) ;
2005-04-16 15:20:36 -07:00
if ( ! err ) {
2005-07-27 01:14:50 -07:00
proteon_dev [ i ] = pdev ;
2005-11-09 22:32:44 +00:00
platform_set_drvdata ( pdev , dev ) ;
2005-04-16 15:20:36 -07:00
+ + num ;
} else {
2005-07-27 01:14:50 -07:00
platform_device_unregister ( pdev ) ;
2005-04-16 15:20:36 -07:00
free_netdev ( dev ) ;
}
}
printk ( KERN_NOTICE " proteon.c: %d cards found. \n " , num ) ;
/* Probe for cards. */
if ( num = = 0 ) {
printk ( KERN_NOTICE " proteon.c: No cards found. \n " ) ;
2006-10-29 03:52:14 +09:00
platform_driver_unregister ( & proteon_driver ) ;
return - ENODEV ;
2005-04-16 15:20:36 -07:00
}
2006-10-29 03:52:14 +09:00
return 0 ;
2005-04-16 15:20:36 -07:00
}
2005-07-27 01:14:50 -07:00
static void __exit proteon_cleanup ( void )
2005-04-16 15:20:36 -07:00
{
2005-07-27 01:14:50 -07:00
struct net_device * dev ;
2005-04-16 15:20:36 -07:00
int i ;
for ( i = 0 ; i < ISATR_MAX_ADAPTERS ; i + + ) {
2005-07-27 01:14:50 -07:00
struct platform_device * pdev = proteon_dev [ i ] ;
2005-04-16 15:20:36 -07:00
2005-07-27 01:14:50 -07:00
if ( ! pdev )
2005-04-16 15:20:36 -07:00
continue ;
2005-11-09 22:32:44 +00:00
dev = platform_get_drvdata ( pdev ) ;
2005-04-16 15:20:36 -07:00
unregister_netdev ( dev ) ;
release_region ( dev - > base_addr , PROTEON_IO_EXTENT ) ;
free_irq ( dev - > irq , dev ) ;
free_dma ( dev - > dma ) ;
tmsdev_term ( dev ) ;
free_netdev ( dev ) ;
2005-11-09 22:32:44 +00:00
platform_set_drvdata ( pdev , NULL ) ;
2005-07-27 01:14:50 -07:00
platform_device_unregister ( pdev ) ;
2005-04-16 15:20:36 -07:00
}
2005-11-09 22:32:44 +00:00
platform_driver_unregister ( & proteon_driver ) ;
2005-04-16 15:20:36 -07:00
}
2005-07-27 01:14:50 -07:00
module_init ( proteon_init ) ;
module_exit ( proteon_cleanup ) ;