2005-04-17 02:20:36 +04:00
/*
* tmspci . c : A generic network driver for TMS380 - based PCI token ring cards .
*
* Written 1999 by Adam Fritzler
*
* 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 ( + ) PCI ( SK - 4590 )
* - SysKonnect TR4 / 16 PCI ( SK - 4591 )
* - Compaq TR 4 / 16 PCI
* - Thomas - Conrad TC4048 4 / 16 PCI
* - 3 Com 3 C339 Token Link Velocity
*
* Maintainer ( s ) :
2008-02-03 17:36:24 +03:00
* AF Adam Fritzler
2005-04-17 02:20:36 +04:00
*
* Modification History :
* 30 - Dec - 99 AF Split off from the tms380tr driver .
* 22 - Jan - 00 AF Updated to use indirect read / writes
* 23 - Nov - 00 JG New PCI API , cleanups
*
* TODO :
* 1. See if we can use MMIO instead of port accesses
*
*/
# 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 "tms380tr.h"
static char version [ ] __devinitdata =
" tmspci.c: v1.02 23/11/2000 by Adam Fritzler \n " ;
# define TMS_PCI_IO_EXTENT 32
struct card_info {
unsigned char nselout [ 2 ] ; /* NSELOUT vals for 4mb([0]) and 16mb([1]) */
char * name ;
} ;
static struct card_info card_info_table [ ] = {
{ { 0x03 , 0x01 } , " Compaq 4/16 TR PCI " } ,
{ { 0x03 , 0x01 } , " SK NET TR 4/16 PCI " } ,
{ { 0x03 , 0x01 } , " Thomas-Conrad TC4048 PCI 4/16 " } ,
{ { 0x03 , 0x01 } , " 3Com Token Link Velocity " } ,
} ;
static struct pci_device_id tmspci_pci_tbl [ ] = {
{ PCI_VENDOR_ID_COMPAQ , PCI_DEVICE_ID_COMPAQ_TOKENRING , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 0 } ,
{ PCI_VENDOR_ID_SYSKONNECT , PCI_DEVICE_ID_SYSKONNECT_TR , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 1 } ,
{ PCI_VENDOR_ID_TCONRAD , PCI_DEVICE_ID_TCONRAD_TOKENRING , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 2 } ,
{ PCI_VENDOR_ID_3COM , PCI_DEVICE_ID_3COM_3C339 , PCI_ANY_ID , PCI_ANY_ID , 0 , 0 , 3 } ,
{ } /* Terminating entry */
} ;
MODULE_DEVICE_TABLE ( pci , tmspci_pci_tbl ) ;
MODULE_LICENSE ( " GPL " ) ;
static void tms_pci_read_eeprom ( struct net_device * dev ) ;
static unsigned short tms_pci_setnselout_pins ( struct net_device * dev ) ;
static unsigned short tms_pci_sifreadb ( struct net_device * dev , unsigned short reg )
{
return inb ( dev - > base_addr + reg ) ;
}
static unsigned short tms_pci_sifreadw ( struct net_device * dev , unsigned short reg )
{
return inw ( dev - > base_addr + reg ) ;
}
static void tms_pci_sifwriteb ( struct net_device * dev , unsigned short val , unsigned short reg )
{
outb ( val , dev - > base_addr + reg ) ;
}
static void tms_pci_sifwritew ( struct net_device * dev , unsigned short val , unsigned short reg )
{
outw ( val , dev - > base_addr + reg ) ;
}
static int __devinit tms_pci_attach ( struct pci_dev * pdev , const struct pci_device_id * ent )
{
static int versionprinted ;
struct net_device * dev ;
struct net_local * tp ;
2007-10-04 04:59:30 +04:00
int ret ;
2005-04-17 02:20:36 +04:00
unsigned int pci_irq_line ;
unsigned long pci_ioaddr ;
struct card_info * cardinfo = & card_info_table [ ent - > driver_data ] ;
2005-07-27 12:14:50 +04:00
2005-04-17 02:20:36 +04:00
if ( versionprinted + + = = 0 )
printk ( " %s " , version ) ;
if ( pci_enable_device ( pdev ) )
return - EIO ;
/* Remove I/O space marker in bit 0. */
pci_irq_line = pdev - > irq ;
pci_ioaddr = pci_resource_start ( pdev , 0 ) ;
/* At this point we have found a valid card. */
dev = alloc_trdev ( sizeof ( struct net_local ) ) ;
if ( ! dev )
return - ENOMEM ;
if ( ! request_region ( pci_ioaddr , TMS_PCI_IO_EXTENT , dev - > name ) ) {
ret = - EBUSY ;
goto err_out_trdev ;
}
dev - > base_addr = pci_ioaddr ;
dev - > irq = pci_irq_line ;
dev - > dma = 0 ;
printk ( " %s: %s \n " , dev - > name , cardinfo - > name ) ;
printk ( " %s: IO: %#4lx IRQ: %d \n " ,
dev - > name , dev - > base_addr , dev - > irq ) ;
tms_pci_read_eeprom ( dev ) ;
2008-10-28 01:59:26 +03:00
printk ( " %s: Ring Station Address: %pM \n " ,
dev - > name , dev - > dev_addr ) ;
2005-04-17 02:20:36 +04:00
2005-08-20 05:05:56 +04:00
ret = tmsdev_init ( dev , & pdev - > dev ) ;
2005-04-17 02:20:36 +04:00
if ( ret ) {
printk ( " %s: unable to get memory for dev->priv. \n " , dev - > name ) ;
2009-03-04 07:59:41 +03:00
goto err_out_region ;
2005-04-17 02:20:36 +04:00
}
2007-07-23 17:18:21 +04:00
tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
tp - > setnselout = tms_pci_setnselout_pins ;
tp - > sifreadb = tms_pci_sifreadb ;
tp - > sifreadw = tms_pci_sifreadw ;
tp - > sifwriteb = tms_pci_sifwriteb ;
tp - > sifwritew = tms_pci_sifwritew ;
memcpy ( tp - > ProductID , cardinfo - > name , PROD_ID_SIZE + 1 ) ;
tp - > tmspriv = cardinfo ;
2009-01-09 16:01:25 +03:00
dev - > netdev_ops = & tms380tr_netdev_ops ;
2009-03-04 07:59:41 +03:00
ret = request_irq ( pdev - > irq , tms380tr_interrupt , IRQF_SHARED ,
dev - > name , dev ) ;
if ( ret )
goto err_out_tmsdev ;
2005-04-17 02:20:36 +04:00
pci_set_drvdata ( pdev , dev ) ;
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
ret = register_netdev ( dev ) ;
if ( ret )
2009-03-04 07:59:41 +03:00
goto err_out_irq ;
2005-04-17 02:20:36 +04:00
return 0 ;
2009-03-04 07:59:41 +03:00
err_out_irq :
free_irq ( pdev - > irq , dev ) ;
2005-04-17 02:20:36 +04:00
err_out_tmsdev :
pci_set_drvdata ( pdev , NULL ) ;
tmsdev_term ( dev ) ;
err_out_region :
release_region ( pci_ioaddr , TMS_PCI_IO_EXTENT ) ;
err_out_trdev :
free_netdev ( dev ) ;
return ret ;
}
/*
* 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 tms_pci_read_eeprom ( struct net_device * dev )
{
int i ;
/* Address: 0000:0000 */
tms_pci_sifwritew ( dev , 0 , SIFADX ) ;
tms_pci_sifwritew ( dev , 0 , SIFADR ) ;
/* Read six byte MAC address data */
dev - > addr_len = 6 ;
for ( i = 0 ; i < 6 ; i + + )
dev - > dev_addr [ i ] = tms_pci_sifreadw ( dev , SIFINC ) > > 8 ;
}
static unsigned short tms_pci_setnselout_pins ( struct net_device * dev )
{
unsigned short val = 0 ;
2007-07-23 17:18:21 +04:00
struct net_local * tp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
struct card_info * cardinfo = tp - > tmspriv ;
if ( tp - > DataRate = = SPEED_4 )
val | = cardinfo - > nselout [ 0 ] ; /* Set 4Mbps */
else
val | = cardinfo - > nselout [ 1 ] ; /* Set 16Mbps */
return val ;
}
static void __devexit tms_pci_detach ( struct pci_dev * pdev )
{
struct net_device * dev = pci_get_drvdata ( pdev ) ;
2006-10-04 01:34:11 +04:00
BUG_ON ( ! dev ) ;
2005-04-17 02:20:36 +04:00
unregister_netdev ( dev ) ;
release_region ( dev - > base_addr , TMS_PCI_IO_EXTENT ) ;
free_irq ( dev - > irq , dev ) ;
tmsdev_term ( dev ) ;
free_netdev ( dev ) ;
pci_set_drvdata ( pdev , NULL ) ;
}
static struct pci_driver tms_pci_driver = {
. name = " tmspci " ,
. id_table = tmspci_pci_tbl ,
. probe = tms_pci_attach ,
. remove = __devexit_p ( tms_pci_detach ) ,
} ;
static int __init tms_pci_init ( void )
{
return pci_register_driver ( & tms_pci_driver ) ;
}
static void __exit tms_pci_rmmod ( void )
{
pci_unregister_driver ( & tms_pci_driver ) ;
}
module_init ( tms_pci_init ) ;
module_exit ( tms_pci_rmmod ) ;