2005-04-17 02:20:36 +04:00
/*
* Linux ARCnet driver - COM20020 PCI support
* Contemporary Controls PCI20 and SOHARD SH - ARC PCI
2015-05-05 20:05:47 +03:00
*
2005-04-17 02:20:36 +04:00
* Written 1994 - 1999 by Avery Pennarun ,
* based on an ISA version by David Woodhouse .
* Written 1999 - 2000 by Martin Mares < mj @ ucw . cz > .
* Derived from skeleton . c by Donald Becker .
*
* Special thanks to Contemporary Controls , Inc . ( www . ccontrols . com )
* for sponsoring the further development of this driver .
*
* * * * * * * * * * * * * * * * * * * * * * *
*
* The original copyright of skeleton . c was as follows :
*
* skeleton . c Written 1993 by Donald Becker .
* Copyright 1993 United States Government as represented by the
* Director , National Security Agency . This software may only be used
* and distributed according to the terms of the GNU General Public License as
* modified by SRC , incorporated herein by reference .
*
* * * * * * * * * * * * * * * * * * * * * * *
*
* For more details , see drivers / net / arcnet . c
*
* * * * * * * * * * * * * * * * * * * * * * *
*/
2015-05-05 20:05:56 +03:00
# define pr_fmt(fmt) "arcnet:" KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# include <linux/module.h>
# include <linux/moduleparam.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/ioport.h>
# include <linux/errno.h>
# include <linux/netdevice.h>
# include <linux/init.h>
2011-06-06 14:43:46 +04:00
# include <linux/interrupt.h>
2005-04-17 02:20:36 +04:00
# include <linux/pci.h>
2014-09-29 13:55:37 +04:00
# include <linux/list.h>
2015-05-05 20:05:51 +03:00
# include <linux/io.h>
2014-09-18 02:12:50 +04:00
# include <linux/leds.h>
2005-04-17 02:20:36 +04:00
2015-05-05 20:06:03 +03:00
# include "arcdevice.h"
# include "com20020.h"
2005-04-17 02:20:36 +04:00
/* Module parameters */
static int node ;
static char device [ 9 ] ; /* use eg. device="arc1" to change name */
static int timeout = 3 ;
static int backplane ;
static int clockp ;
static int clockm ;
module_param ( node , int , 0 ) ;
module_param_string ( device , device , sizeof ( device ) , 0 ) ;
module_param ( timeout , int , 0 ) ;
module_param ( backplane , int , 0 ) ;
module_param ( clockp , int , 0 ) ;
module_param ( clockm , int , 0 ) ;
MODULE_LICENSE ( " GPL " ) ;
2014-09-18 02:12:50 +04:00
static void led_tx_set ( struct led_classdev * led_cdev ,
enum led_brightness value )
{
struct com20020_dev * card ;
struct com20020_priv * priv ;
struct com20020_pci_card_info * ci ;
card = container_of ( led_cdev , struct com20020_dev , tx_led ) ;
priv = card - > pci_priv ;
ci = priv - > ci ;
outb ( ! ! value , priv - > misc + ci - > leds [ card - > index ] . green ) ;
}
static void led_recon_set ( struct led_classdev * led_cdev ,
enum led_brightness value )
{
struct com20020_dev * card ;
struct com20020_priv * priv ;
struct com20020_pci_card_info * ci ;
card = container_of ( led_cdev , struct com20020_dev , recon_led ) ;
priv = card - > pci_priv ;
ci = priv - > ci ;
outb ( ! ! value , priv - > misc + ci - > leds [ card - > index ] . red ) ;
}
2017-06-28 19:32:19 +03:00
static ssize_t backplane_mode_show ( struct device * dev ,
struct device_attribute * attr ,
char * buf )
{
struct net_device * net_dev = to_net_dev ( dev ) ;
struct arcnet_local * lp = netdev_priv ( net_dev ) ;
return sprintf ( buf , " %s \n " , lp - > backplane ? " true " : " false " ) ;
}
static DEVICE_ATTR_RO ( backplane_mode ) ;
static struct attribute * com20020_state_attrs [ ] = {
& dev_attr_backplane_mode . attr ,
NULL ,
} ;
2017-07-18 12:45:36 +03:00
static const struct attribute_group com20020_state_group = {
2017-06-28 19:32:19 +03:00
. name = NULL ,
. attrs = com20020_state_attrs ,
} ;
2014-09-29 13:55:37 +04:00
static void com20020pci_remove ( struct pci_dev * pdev ) ;
2015-05-05 20:06:02 +03:00
static int com20020pci_probe ( struct pci_dev * pdev ,
const struct pci_device_id * id )
2005-04-17 02:20:36 +04:00
{
2014-09-29 13:55:36 +04:00
struct com20020_pci_card_info * ci ;
2014-09-18 02:12:50 +04:00
struct com20020_pci_channel_map * mm ;
2005-04-17 02:20:36 +04:00
struct net_device * dev ;
struct arcnet_local * lp ;
2014-09-29 13:55:37 +04:00
struct com20020_priv * priv ;
int i , ioaddr , ret ;
struct resource * r ;
2005-04-17 02:20:36 +04:00
if ( pci_enable_device ( pdev ) )
return - EIO ;
2009-01-09 16:01:10 +03:00
2014-09-29 13:55:37 +04:00
priv = devm_kzalloc ( & pdev - > dev , sizeof ( struct com20020_priv ) ,
GFP_KERNEL ) ;
2015-02-05 14:31:37 +03:00
if ( ! priv )
return - ENOMEM ;
2014-09-29 13:55:36 +04:00
ci = ( struct com20020_pci_card_info * ) id - > driver_data ;
2014-09-29 13:55:37 +04:00
priv - > ci = ci ;
2014-09-18 02:12:50 +04:00
mm = & ci - > misc_map ;
2014-09-29 13:55:37 +04:00
INIT_LIST_HEAD ( & priv - > list_dev ) ;
2014-09-18 02:12:50 +04:00
if ( mm - > size ) {
ioaddr = pci_resource_start ( pdev , mm - > bar ) + mm - > offset ;
r = devm_request_region ( & pdev - > dev , ioaddr , mm - > size ,
" com20020-pci " ) ;
if ( ! r ) {
pr_err ( " IO region %xh-%xh already allocated. \n " ,
ioaddr , ioaddr + mm - > size - 1 ) ;
return - EBUSY ;
}
priv - > misc = ioaddr ;
}
2014-09-29 13:55:37 +04:00
for ( i = 0 ; i < ci - > devcount ; i + + ) {
struct com20020_pci_channel_map * cm = & ci - > chan_map_tbl [ i ] ;
struct com20020_dev * card ;
2017-06-28 19:28:36 +03:00
int dev_id_mask = 0xf ;
2014-09-29 13:55:37 +04:00
dev = alloc_arcdev ( device ) ;
if ( ! dev ) {
ret = - ENOMEM ;
goto out_port ;
}
2015-03-20 17:22:24 +03:00
dev - > dev_port = i ;
2014-09-29 13:55:37 +04:00
dev - > netdev_ops = & com20020_netdev_ops ;
lp = netdev_priv ( dev ) ;
2015-05-05 20:05:55 +03:00
arc_printk ( D_NORMAL , dev , " %s Controls \n " , ci - > name ) ;
2014-09-29 13:55:37 +04:00
ioaddr = pci_resource_start ( pdev , cm - > bar ) + cm - > offset ;
r = devm_request_region ( & pdev - > dev , ioaddr , cm - > size ,
" com20020-pci " ) ;
if ( ! r ) {
2015-05-05 20:05:56 +03:00
pr_err ( " IO region %xh-%xh already allocated \n " ,
2014-09-29 13:55:37 +04:00
ioaddr , ioaddr + cm - > size - 1 ) ;
ret = - EBUSY ;
goto out_port ;
}
/* Dummy access after Reset
* ARCNET controller needs
* this access to detect bustype
*/
2015-05-05 20:06:06 +03:00
arcnet_outb ( 0x00 , ioaddr , COM20020_REG_W_COMMAND ) ;
arcnet_inb ( ioaddr , COM20020_REG_R_DIAGSTAT ) ;
2014-09-29 13:55:37 +04:00
2017-06-28 19:28:37 +03:00
SET_NETDEV_DEV ( dev , & pdev - > dev ) ;
2014-09-29 13:55:37 +04:00
dev - > base_addr = ioaddr ;
dev - > dev_addr [ 0 ] = node ;
2017-06-28 19:32:19 +03:00
dev - > sysfs_groups [ 0 ] = & com20020_state_group ;
2014-09-29 13:55:37 +04:00
dev - > irq = pdev - > irq ;
lp - > card_name = " PCI COM20020 " ;
lp - > card_flags = ci - > flags ;
lp - > backplane = backplane ;
lp - > clockp = clockp & 7 ;
lp - > clockm = clockm & 3 ;
lp - > timeout = timeout ;
lp - > hw . owner = THIS_MODULE ;
2017-06-28 19:32:20 +03:00
lp - > backplane = ( inb ( priv - > misc ) > > ( 2 + i ) ) & 0x1 ;
2017-06-28 19:32:21 +03:00
if ( ! strncmp ( ci - > name , " EAE PLX-PCI FB2 " , 15 ) )
lp - > backplane = 1 ;
2014-09-18 02:12:50 +04:00
/* Get the dev_id from the PLX rotary coder */
if ( ! strncmp ( ci - > name , " EAE PLX-PCI MA1 " , 15 ) )
2017-06-28 19:28:36 +03:00
dev_id_mask = 0x3 ;
dev - > dev_id = ( inb ( priv - > misc + ci - > rotary ) > > 4 ) & dev_id_mask ;
2014-09-18 02:12:50 +04:00
snprintf ( dev - > name , sizeof ( dev - > name ) , " arc%d-%d " , dev - > dev_id , i ) ;
2015-05-05 20:06:06 +03:00
if ( arcnet_inb ( ioaddr , COM20020_REG_R_STATUS ) = = 0xFF ) {
2014-09-29 13:55:37 +04:00
pr_err ( " IO address %Xh is empty! \n " , ioaddr ) ;
ret = - EIO ;
goto out_port ;
}
if ( com20020_check ( dev ) ) {
ret = - EIO ;
goto out_port ;
}
card = devm_kzalloc ( & pdev - > dev , sizeof ( struct com20020_dev ) ,
GFP_KERNEL ) ;
2017-07-07 07:56:16 +03:00
if ( ! card ) {
ret = - ENOMEM ;
goto out_port ;
}
2014-09-29 13:55:37 +04:00
card - > index = i ;
card - > pci_priv = priv ;
2014-09-18 02:12:50 +04:00
card - > tx_led . brightness_set = led_tx_set ;
card - > tx_led . default_trigger = devm_kasprintf ( & pdev - > dev ,
GFP_KERNEL , " arc%d-%d-tx " ,
dev - > dev_id , i ) ;
card - > tx_led . name = devm_kasprintf ( & pdev - > dev , GFP_KERNEL ,
" pci:green:tx:%d-%d " ,
dev - > dev_id , i ) ;
card - > tx_led . dev = & dev - > dev ;
card - > recon_led . brightness_set = led_recon_set ;
card - > recon_led . default_trigger = devm_kasprintf ( & pdev - > dev ,
GFP_KERNEL , " arc%d-%d-recon " ,
dev - > dev_id , i ) ;
card - > recon_led . name = devm_kasprintf ( & pdev - > dev , GFP_KERNEL ,
" pci:red:recon:%d-%d " ,
dev - > dev_id , i ) ;
card - > recon_led . dev = & dev - > dev ;
2014-09-29 13:55:37 +04:00
card - > dev = dev ;
2014-09-18 02:12:50 +04:00
ret = devm_led_classdev_register ( & pdev - > dev , & card - > tx_led ) ;
if ( ret )
goto out_port ;
ret = devm_led_classdev_register ( & pdev - > dev , & card - > recon_led ) ;
if ( ret )
goto out_port ;
2014-09-29 13:55:37 +04:00
dev_set_drvdata ( & dev - > dev , card ) ;
ret = com20020_found ( dev , IRQF_SHARED ) ;
if ( ret )
goto out_port ;
2014-09-18 02:12:50 +04:00
devm_arcnet_led_init ( dev , dev - > dev_id , i ) ;
2014-09-29 13:55:37 +04:00
list_add ( & card - > list , & priv - > list_dev ) ;
2005-04-17 02:20:36 +04:00
}
2014-09-29 13:55:37 +04:00
pci_set_drvdata ( pdev , priv ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
out_port :
2014-09-29 13:55:37 +04:00
com20020pci_remove ( pdev ) ;
return ret ;
2005-04-17 02:20:36 +04:00
}
2012-12-03 18:22:43 +04:00
static void com20020pci_remove ( struct pci_dev * pdev )
2005-04-17 02:20:36 +04:00
{
2014-09-29 13:55:37 +04:00
struct com20020_dev * card , * tmpcard ;
struct com20020_priv * priv ;
priv = pci_get_drvdata ( pdev ) ;
list_for_each_entry_safe ( card , tmpcard , & priv - > list_dev , list ) {
struct net_device * dev = card - > dev ;
unregister_netdev ( dev ) ;
free_irq ( dev - > irq , dev ) ;
2021-01-28 22:48:02 +03:00
free_arcdev ( dev ) ;
2014-09-29 13:55:37 +04:00
}
2005-04-17 02:20:36 +04:00
}
2014-09-29 13:55:36 +04:00
static struct com20020_pci_card_info card_info_10mbit = {
. name = " ARC-PCI " ,
. devcount = 1 ,
. chan_map_tbl = {
2015-03-20 17:22:02 +03:00
{
. bar = 2 ,
. offset = 0x00 ,
. size = 0x08 ,
} ,
2014-09-29 13:55:36 +04:00
} ,
. flags = ARC_CAN_10MBIT ,
} ;
static struct com20020_pci_card_info card_info_5mbit = {
. name = " ARC-PCI " ,
. devcount = 1 ,
. chan_map_tbl = {
2015-03-20 17:22:02 +03:00
{
. bar = 2 ,
. offset = 0x00 ,
. size = 0x08 ,
} ,
2014-09-29 13:55:36 +04:00
} ,
. flags = ARC_IS_5MBIT ,
} ;
static struct com20020_pci_card_info card_info_sohard = {
. name = " PLX-PCI " ,
. devcount = 1 ,
/* SOHARD needs PCI base addr 4 */
. chan_map_tbl = {
2015-03-20 17:22:02 +03:00
{
. bar = 4 ,
. offset = 0x00 ,
. size = 0x08
} ,
2014-09-29 13:55:36 +04:00
} ,
. flags = ARC_CAN_10MBIT ,
} ;
2015-02-13 15:03:50 +03:00
static struct com20020_pci_card_info card_info_eae_arc1 = {
. name = " EAE PLX-PCI ARC1 " ,
. devcount = 1 ,
. chan_map_tbl = {
2015-03-20 17:22:02 +03:00
{
. bar = 2 ,
. offset = 0x00 ,
. size = 0x08 ,
} ,
2015-02-13 15:03:50 +03:00
} ,
2014-09-18 02:12:50 +04:00
. misc_map = {
. bar = 2 ,
. offset = 0x10 ,
. size = 0x04 ,
} ,
2014-09-18 02:12:50 +04:00
. leds = {
{
. green = 0x0 ,
. red = 0x1 ,
} ,
} ,
2014-09-18 02:12:50 +04:00
. rotary = 0x0 ,
2015-02-13 15:03:50 +03:00
. flags = ARC_CAN_10MBIT ,
} ;
static struct com20020_pci_card_info card_info_eae_ma1 = {
. name = " EAE PLX-PCI MA1 " ,
2014-09-29 13:55:38 +04:00
. devcount = 2 ,
. chan_map_tbl = {
2015-03-20 17:22:02 +03:00
{
. bar = 2 ,
. offset = 0x00 ,
. size = 0x08 ,
} , {
. bar = 2 ,
. offset = 0x08 ,
. size = 0x08 ,
}
2014-09-29 13:55:38 +04:00
} ,
2014-09-18 02:12:50 +04:00
. misc_map = {
. bar = 2 ,
. offset = 0x10 ,
. size = 0x04 ,
} ,
2014-09-18 02:12:50 +04:00
. leds = {
{
. green = 0x0 ,
. red = 0x1 ,
} , {
. green = 0x2 ,
. red = 0x3 ,
} ,
} ,
2014-09-18 02:12:50 +04:00
. rotary = 0x0 ,
2014-09-29 13:55:38 +04:00
. flags = ARC_CAN_10MBIT ,
} ;
2017-06-28 19:32:21 +03:00
static struct com20020_pci_card_info card_info_eae_fb2 = {
. name = " EAE PLX-PCI FB2 " ,
. devcount = 1 ,
. chan_map_tbl = {
{
. bar = 2 ,
. offset = 0x00 ,
. size = 0x08 ,
} ,
} ,
. misc_map = {
. bar = 2 ,
. offset = 0x10 ,
. size = 0x04 ,
} ,
. leds = {
{
. green = 0x0 ,
. red = 0x1 ,
} ,
} ,
. rotary = 0x0 ,
. flags = ARC_CAN_10MBIT ,
} ;
2014-08-08 17:56:03 +04:00
static const struct pci_device_id com20020pci_id_table [ ] = {
2014-09-29 13:55:36 +04:00
{
0x1571 , 0xa001 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
0 ,
} ,
{
0x1571 , 0xa002 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
0 ,
} ,
{
0x1571 , 0xa003 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
0
} ,
{
0x1571 , 0xa004 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
0 ,
} ,
{
0x1571 , 0xa005 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
0
} ,
{
0x1571 , 0xa006 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
0
} ,
{
0x1571 , 0xa007 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
0
} ,
{
0x1571 , 0xa008 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
0
} ,
{
0x1571 , 0xa009 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_5mbit
} ,
{
0x1571 , 0xa00a ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_5mbit
} ,
{
0x1571 , 0xa00b ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_5mbit
} ,
{
0x1571 , 0xa00c ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_5mbit
} ,
{
0x1571 , 0xa00d ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_5mbit
} ,
{
0x1571 , 0xa00e ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_5mbit
} ,
{
0x1571 , 0xa201 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_10mbit
} ,
{
0x1571 , 0xa202 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_10mbit
} ,
{
0x1571 , 0xa203 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_10mbit
} ,
{
0x1571 , 0xa204 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_10mbit
} ,
{
0x1571 , 0xa205 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_10mbit
} ,
{
0x1571 , 0xa206 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_10mbit
} ,
{
0x10B5 , 0x9030 ,
0x10B5 , 0x2978 ,
0 , 0 ,
( kernel_ulong_t ) & card_info_sohard
} ,
{
0x10B5 , 0x9050 ,
0x10B5 , 0x2273 ,
0 , 0 ,
( kernel_ulong_t ) & card_info_sohard
} ,
2015-02-13 15:03:50 +03:00
{
0x10B5 , 0x9050 ,
0x10B5 , 0x3263 ,
0 , 0 ,
( kernel_ulong_t ) & card_info_eae_arc1
} ,
2014-09-29 13:55:38 +04:00
{
0x10B5 , 0x9050 ,
0x10B5 , 0x3292 ,
0 , 0 ,
2015-02-13 15:03:50 +03:00
( kernel_ulong_t ) & card_info_eae_ma1
2014-09-29 13:55:38 +04:00
} ,
2017-06-28 19:32:21 +03:00
{
0x10B5 , 0x9050 ,
0x10B5 , 0x3294 ,
0 , 0 ,
( kernel_ulong_t ) & card_info_eae_fb2
} ,
2014-09-29 13:55:36 +04:00
{
0x14BA , 0x6000 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_10mbit
} ,
{
0x10B5 , 0x2200 ,
PCI_ANY_ID , PCI_ANY_ID ,
0 , 0 ,
( kernel_ulong_t ) & card_info_10mbit
} ,
{ 0 , }
2005-04-17 02:20:36 +04:00
} ;
MODULE_DEVICE_TABLE ( pci , com20020pci_id_table ) ;
static struct pci_driver com20020pci_driver = {
. name = " com20020 " ,
. id_table = com20020pci_id_table ,
. probe = com20020pci_probe ,
2012-12-03 18:22:43 +04:00
. remove = com20020pci_remove ,
2005-04-17 02:20:36 +04:00
} ;
static int __init com20020pci_init ( void )
{
2015-05-05 20:05:54 +03:00
if ( BUGLVL ( D_NORMAL ) )
2015-05-05 20:05:56 +03:00
pr_info ( " %s \n " , " COM20020 PCI support " ) ;
2006-08-20 01:48:59 +04:00
return pci_register_driver ( & com20020pci_driver ) ;
2005-04-17 02:20:36 +04:00
}
static void __exit com20020pci_cleanup ( void )
{
pci_unregister_driver ( & com20020pci_driver ) ;
}
module_init ( com20020pci_init )
module_exit ( com20020pci_cleanup )