2005-04-17 02:20:36 +04:00
/*
* Linux ARCnet driver - COM20020 PCMCIA support
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 .
* Derived from ibmtr_cs . c by Steve Kipisz ( pcmcia - cs 3.1 .4 )
* which was derived from pcnet_cs . c by David Hinds .
* Some additional portions 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 .
2015-05-05 20:05:47 +03:00
*
2005-04-17 02:20:36 +04:00
* * * * * * * * * * * * * * * * * * * * * * *
* Changes :
* Arnaldo Carvalho de Melo < acme @ conectiva . com . br > - 08 / 08 / 2000
* - reorganize kmallocs in com20020_attach , checking all for failure
* and releasing the previous allocations if one fails
* * * * * * * * * * * * * * * * * * * * * * *
2015-05-05 20:05:47 +03:00
*
2005-04-17 02:20:36 +04:00
* 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/kernel.h>
# include <linux/ptrace.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/timer.h>
# include <linux/delay.h>
# include <linux/module.h>
# include <linux/netdevice.h>
2015-05-05 20:06:03 +03:00
# include <linux/io.h>
2005-04-17 02:20:36 +04:00
# include <pcmcia/cistpl.h>
# include <pcmcia/ds.h>
2015-05-05 20:06:03 +03:00
# include "arcdevice.h"
# include "com20020.h"
2005-04-17 02:20:36 +04:00
static void regdump ( struct net_device * dev )
{
2010-08-12 16:22:51 +04:00
# ifdef DEBUG
2015-05-05 20:05:47 +03:00
int ioaddr = dev - > base_addr ;
int count ;
netdev_dbg ( dev , " register dump: \n " ) ;
2015-05-05 20:06:06 +03:00
for ( count = 0 ; count < 16 ; count + + ) {
2015-05-05 20:05:47 +03:00
if ( ! ( count % 16 ) )
2015-05-05 20:06:06 +03:00
pr_cont ( " %04X: " , ioaddr + count ) ;
pr_cont ( " %02X " , arcnet_inb ( ioaddr , count ) ) ;
2015-05-05 20:05:47 +03:00
}
pr_cont ( " \n " ) ;
netdev_dbg ( dev , " buffer0 dump: \n " ) ;
2005-04-17 02:20:36 +04:00
/* set up the address register */
2015-05-05 20:05:47 +03:00
count = 0 ;
2015-05-05 20:06:06 +03:00
arcnet_outb ( ( count > > 8 ) | RDDATAflag | AUTOINCflag ,
ioaddr , com20020_REG_W_ADDR_HI ) ;
arcnet_outb ( count & 0xff , ioaddr , COM20020_REG_W_ADDR_LO ) ;
2015-05-05 20:05:47 +03:00
2015-05-05 20:05:49 +03:00
for ( count = 0 ; count < 256 + 32 ; count + + ) {
2015-05-05 20:05:47 +03:00
if ( ! ( count % 16 ) )
pr_cont ( " %04X: " , count ) ;
/* copy the data */
2015-05-05 20:06:06 +03:00
pr_cont ( " %02X " , arcnet_inb ( ioaddr , COM20020_REG_RW_MEMDATA ) ) ;
2015-05-05 20:05:47 +03:00
}
pr_cont ( " \n " ) ;
2010-08-12 16:22:51 +04:00
# endif
2005-04-17 02:20:36 +04:00
}
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
static int node ;
static int timeout = 3 ;
static int backplane ;
static int clockp ;
static int clockm ;
module_param ( node , int , 0 ) ;
module_param ( timeout , int , 0 ) ;
module_param ( backplane , int , 0 ) ;
module_param ( clockp , int , 0 ) ;
module_param ( clockm , int , 0 ) ;
MODULE_LICENSE ( " GPL " ) ;
/*====================================================================*/
2006-03-31 19:26:06 +04:00
static int com20020_config ( struct pcmcia_device * link ) ;
2006-03-31 19:21:06 +04:00
static void com20020_release ( struct pcmcia_device * link ) ;
2005-04-17 02:20:36 +04:00
2005-11-14 23:23:14 +03:00
static void com20020_detach ( struct pcmcia_device * p_dev ) ;
2005-04-17 02:20:36 +04:00
/*====================================================================*/
2006-03-31 19:26:06 +04:00
static int com20020_probe ( struct pcmcia_device * p_dev )
2005-04-17 02:20:36 +04:00
{
2015-05-05 20:05:47 +03:00
struct com20020_dev * info ;
struct net_device * dev ;
struct arcnet_local * lp ;
2005-11-14 23:25:51 +03:00
2015-05-05 20:05:47 +03:00
dev_dbg ( & p_dev - > dev , " com20020_attach() \n " ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
/* Create new network device */
info = kzalloc ( sizeof ( * info ) , GFP_KERNEL ) ;
if ( ! info )
goto fail_alloc_info ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
dev = alloc_arcdev ( " " ) ;
if ( ! dev )
goto fail_alloc_dev ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
lp = netdev_priv ( dev ) ;
lp - > timeout = timeout ;
lp - > backplane = backplane ;
lp - > clockp = clockp ;
lp - > clockm = clockm & 3 ;
lp - > hw . owner = THIS_MODULE ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
/* fill in our module parameters as defaults */
dev - > dev_addr [ 0 ] = node ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
p_dev - > resource [ 0 ] - > flags | = IO_DATA_PATH_WIDTH_8 ;
p_dev - > resource [ 0 ] - > end = 16 ;
p_dev - > config_flags | = CONF_ENABLE_IRQ ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
info - > dev = dev ;
p_dev - > priv = info ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
return com20020_config ( p_dev ) ;
2005-04-17 02:20:36 +04:00
fail_alloc_dev :
2015-05-05 20:05:47 +03:00
kfree ( info ) ;
2005-04-17 02:20:36 +04:00
fail_alloc_info :
2015-05-05 20:05:47 +03:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
} /* com20020_attach */
2006-03-31 19:21:06 +04:00
static void com20020_detach ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
2015-05-05 20:05:47 +03:00
struct com20020_dev * info = link - > priv ;
struct net_device * dev = info - > dev ;
2005-11-14 23:25:35 +03:00
2015-05-05 20:05:47 +03:00
dev_dbg ( & link - > dev , " detach... \n " ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
dev_dbg ( & link - > dev , " com20020_detach \n " ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
dev_dbg ( & link - > dev , " unregister... \n " ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
unregister_netdev ( dev ) ;
2005-11-14 23:25:35 +03:00
2015-05-05 20:05:52 +03:00
/* this is necessary because we register our IRQ separately
2015-05-05 20:05:47 +03:00
* from card services .
*/
if ( dev - > irq )
free_irq ( dev - > irq , dev ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
com20020_release ( link ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
/* Unlink device structure, free bits */
dev_dbg ( & link - > dev , " unlinking... \n " ) ;
2015-05-05 20:05:49 +03:00
if ( link - > priv ) {
2015-05-05 20:05:47 +03:00
dev = info - > dev ;
2015-05-05 20:05:49 +03:00
if ( dev ) {
2015-05-05 20:05:47 +03:00
dev_dbg ( & link - > dev , " kfree... \n " ) ;
free_netdev ( dev ) ;
}
dev_dbg ( & link - > dev , " kfree2... \n " ) ;
kfree ( info ) ;
2005-04-17 02:20:36 +04:00
}
} /* com20020_detach */
2006-03-31 19:26:06 +04:00
static int com20020_config ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
2015-05-05 20:05:47 +03:00
struct arcnet_local * lp ;
struct com20020_dev * info ;
struct net_device * dev ;
int i , ret ;
int ioaddr ;
info = link - > priv ;
dev = info - > dev ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
dev_dbg ( & link - > dev , " config... \n " ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
dev_dbg ( & link - > dev , " com20020_config \n " ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
dev_dbg ( & link - > dev , " baseport1 is %Xh \n " ,
( unsigned int ) link - > resource [ 0 ] - > start ) ;
2005-04-17 02:20:36 +04:00
2015-05-05 20:05:47 +03:00
i = - ENODEV ;
link - > io_lines = 16 ;
2010-07-24 19:23:51 +04:00
2015-05-05 20:05:49 +03:00
if ( ! link - > resource [ 0 ] - > start ) {
for ( ioaddr = 0x100 ; ioaddr < 0x400 ; ioaddr + = 0x10 ) {
2015-05-05 20:05:47 +03:00
link - > resource [ 0 ] - > start = ioaddr ;
i = pcmcia_request_io ( link ) ;
if ( i = = 0 )
break ;
}
2015-05-05 20:05:49 +03:00
} else {
2015-05-05 20:05:47 +03:00
i = pcmcia_request_io ( link ) ;
2015-05-05 20:05:49 +03:00
}
2015-05-05 20:05:47 +03:00
2015-05-05 20:05:49 +03:00
if ( i ! = 0 ) {
2015-05-05 20:05:47 +03:00
dev_dbg ( & link - > dev , " requestIO failed totally! \n " ) ;
goto failed ;
}
ioaddr = dev - > base_addr = link - > resource [ 0 ] - > start ;
dev_dbg ( & link - > dev , " got ioaddr %Xh \n " , ioaddr ) ;
dev_dbg ( & link - > dev , " request IRQ %d \n " ,
link - > irq ) ;
2015-05-05 20:05:49 +03:00
if ( ! link - > irq ) {
2015-05-05 20:05:47 +03:00
dev_dbg ( & link - > dev , " requestIRQ failed totally! \n " ) ;
goto failed ;
}
2010-07-24 19:23:51 +04:00
2015-05-05 20:05:47 +03:00
dev - > irq = link - > irq ;
ret = pcmcia_enable_device ( link ) ;
if ( ret )
goto failed ;
2015-05-05 20:05:49 +03:00
if ( com20020_check ( dev ) ) {
2015-05-05 20:05:47 +03:00
regdump ( dev ) ;
goto failed ;
2005-04-17 02:20:36 +04:00
}
2015-05-05 20:05:47 +03:00
lp = netdev_priv ( dev ) ;
lp - > card_name = " PCMCIA COM20020 " ;
lp - > card_flags = ARC_CAN_10MBIT ; /* pretend all of them can 10Mbit */
SET_NETDEV_DEV ( dev , & link - > dev ) ;
i = com20020_found ( dev , 0 ) ; /* calls register_netdev */
if ( i ! = 0 ) {
dev_notice ( & link - > dev ,
" com20020_found() failed \n " ) ;
goto failed ;
}
netdev_dbg ( dev , " port %#3lx, irq %d \n " ,
dev - > base_addr , dev - > irq ) ;
return 0 ;
2005-04-17 02:20:36 +04:00
failed :
2015-05-05 20:05:47 +03:00
dev_dbg ( & link - > dev , " com20020_config failed... \n " ) ;
com20020_release ( link ) ;
return - ENODEV ;
2005-04-17 02:20:36 +04:00
} /* com20020_config */
2006-03-31 19:21:06 +04:00
static void com20020_release ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " com20020_release \n " ) ;
2006-03-31 19:21:06 +04:00
pcmcia_disable_device ( link ) ;
2005-04-17 02:20:36 +04:00
}
2006-03-31 19:21:06 +04:00
static int com20020_suspend ( struct pcmcia_device * link )
2005-11-14 23:21:18 +03:00
{
2014-08-09 20:07:18 +04:00
struct com20020_dev * info = link - > priv ;
2005-11-14 23:21:18 +03:00
struct net_device * dev = info - > dev ;
2006-03-02 02:09:29 +03:00
if ( link - > open )
2006-03-02 02:02:33 +03:00
netif_device_detach ( dev ) ;
2005-11-14 23:21:18 +03:00
return 0 ;
}
2006-03-31 19:21:06 +04:00
static int com20020_resume ( struct pcmcia_device * link )
2005-11-14 23:21:18 +03:00
{
2014-08-09 20:07:18 +04:00
struct com20020_dev * info = link - > priv ;
2005-11-14 23:21:18 +03:00
struct net_device * dev = info - > dev ;
2006-03-02 02:09:29 +03:00
if ( link - > open ) {
2006-03-02 02:02:33 +03:00
int ioaddr = dev - > base_addr ;
2008-11-13 10:38:14 +03:00
struct arcnet_local * lp = netdev_priv ( dev ) ;
2015-05-05 20:05:48 +03:00
2015-05-05 20:06:06 +03:00
arcnet_outb ( lp - > config | 0x80 , ioaddr , COM20020_REG_W_CONFIG ) ;
udelay ( 5 ) ;
arcnet_outb ( lp - > config , ioaddr , COM20020_REG_W_CONFIG ) ;
2006-03-02 02:02:33 +03:00
}
2005-11-14 23:21:18 +03:00
return 0 ;
}
2011-05-04 06:29:01 +04:00
static const struct pcmcia_device_id com20020_ids [ ] = {
2006-06-25 12:56:24 +04:00
PCMCIA_DEVICE_PROD_ID12 ( " Contemporary Control Systems, Inc. " ,
2015-05-05 20:05:47 +03:00
" PCM20 Arcnet Adapter " , 0x59991666 , 0x95dfffaf ) ,
2006-06-25 12:56:24 +04:00
PCMCIA_DEVICE_PROD_ID12 ( " SoHard AG " ,
2015-05-05 20:05:47 +03:00
" SH ARC PCMCIA " , 0xf8991729 , 0x69dff0c7 ) ,
2005-06-28 03:28:38 +04:00
PCMCIA_DEVICE_NULL
} ;
MODULE_DEVICE_TABLE ( pcmcia , com20020_ids ) ;
2005-04-17 02:20:36 +04:00
static struct pcmcia_driver com20020_cs_driver = {
. owner = THIS_MODULE ,
2010-08-08 13:36:26 +04:00
. name = " com20020_cs " ,
2006-03-31 19:26:06 +04:00
. probe = com20020_probe ,
2005-11-14 23:23:14 +03:00
. remove = com20020_detach ,
2005-06-28 03:28:38 +04:00
. id_table = com20020_ids ,
2005-11-14 23:21:18 +03:00
. suspend = com20020_suspend ,
. resume = com20020_resume ,
2005-04-17 02:20:36 +04:00
} ;
2013-03-06 22:27:43 +04:00
module_pcmcia_driver ( com20020_cs_driver ) ;