2005-04-17 02:20:36 +04:00
/*
* Linux ARCnet driver - COM20020 PCMCIA support
*
* 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 .
*
* * * * * * * * * * * * * * * * * * * * * * *
* 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
* * * * * * * * * * * * * * * * * * * * * * *
*
* For more details , see drivers / net / arcnet . c
*
* * * * * * * * * * * * * * * * * * * * * * *
*/
# include <linux/kernel.h>
# include <linux/init.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>
# include <linux/arcdevice.h>
# include <linux/com20020.h>
# include <pcmcia/cs.h>
# include <pcmcia/cistpl.h>
# include <pcmcia/ds.h>
# include <asm/io.h>
# include <asm/system.h>
# define VERSION "arcnet: COM20020 PCMCIA support loaded.\n"
2009-10-24 17:51:05 +04:00
# ifdef DEBUG
2005-04-17 02:20:36 +04:00
static void regdump ( struct net_device * dev )
{
int ioaddr = dev - > base_addr ;
int count ;
printk ( " com20020 register dump: \n " ) ;
for ( count = ioaddr ; count < ioaddr + 16 ; count + + )
{
if ( ! ( count % 16 ) )
printk ( " \n %04X: " , count ) ;
printk ( " %02X " , inb ( count ) ) ;
}
printk ( " \n " ) ;
printk ( " buffer0 dump: \n " ) ;
/* set up the address register */
count = 0 ;
outb ( ( count > > 8 ) | RDDATAflag | AUTOINCflag , _ADDR_HI ) ;
outb ( count & 0xff , _ADDR_LO ) ;
for ( count = 0 ; count < 256 + 32 ; count + + )
{
if ( ! ( count % 16 ) )
printk ( " \n %04X: " , count ) ;
/* copy the data */
printk ( " %02X " , inb ( _MEMDATA ) ) ;
}
printk ( " \n " ) ;
}
# else
static inline void regdump ( struct net_device * dev ) { }
# endif
/*====================================================================*/
/* 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
/*====================================================================*/
typedef struct com20020_dev_t {
struct net_device * dev ;
} com20020_dev_t ;
/*======================================================================
com20020_attach ( ) creates an " instance " of the driver , allocating
local data structures for one device . The device is registered
with Card Services .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
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
{
com20020_dev_t * info ;
struct net_device * dev ;
struct arcnet_local * lp ;
2005-11-14 23:25:51 +03:00
2009-10-24 17:51:05 +04:00
dev_dbg ( & p_dev - > dev , " com20020_attach() \n " ) ;
2005-04-17 02:20:36 +04:00
/* Create new network device */
some kmalloc/memset ->kzalloc (tree wide)
Transform some calls to kmalloc/memset to a single kzalloc (or kcalloc).
Here is a short excerpt of the semantic patch performing
this transformation:
@@
type T2;
expression x;
identifier f,fld;
expression E;
expression E1,E2;
expression e1,e2,e3,y;
statement S;
@@
x =
- kmalloc
+ kzalloc
(E1,E2)
... when != \(x->fld=E;\|y=f(...,x,...);\|f(...,x,...);\|x=E;\|while(...) S\|for(e1;e2;e3) S\)
- memset((T2)x,0,E1);
@@
expression E1,E2,E3;
@@
- kzalloc(E1 * E2,E3)
+ kcalloc(E1,E2,E3)
[akpm@linux-foundation.org: get kcalloc args the right way around]
Signed-off-by: Yoann Padioleau <padator@wanadoo.fr>
Cc: Richard Henderson <rth@twiddle.net>
Cc: Ivan Kokshaysky <ink@jurassic.park.msu.ru>
Acked-by: Russell King <rmk@arm.linux.org.uk>
Cc: Bryan Wu <bryan.wu@analog.com>
Acked-by: Jiri Slaby <jirislaby@gmail.com>
Cc: Dave Airlie <airlied@linux.ie>
Acked-by: Roland Dreier <rolandd@cisco.com>
Cc: Jiri Kosina <jkosina@suse.cz>
Acked-by: Dmitry Torokhov <dtor@mail.ru>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Acked-by: Mauro Carvalho Chehab <mchehab@infradead.org>
Acked-by: Pierre Ossman <drzeus-list@drzeus.cx>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: "David S. Miller" <davem@davemloft.net>
Acked-by: Greg KH <greg@kroah.com>
Cc: James Bottomley <James.Bottomley@steeleye.com>
Cc: "Antonino A. Daplas" <adaplas@pol.net>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
2007-07-19 12:49:03 +04:00
info = kzalloc ( sizeof ( struct com20020_dev_t ) , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! info )
goto fail_alloc_info ;
dev = alloc_arcdev ( " " ) ;
if ( ! dev )
goto fail_alloc_dev ;
2008-11-13 10:38:14 +03:00
lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
lp - > timeout = timeout ;
lp - > backplane = backplane ;
lp - > clockp = clockp ;
lp - > clockm = clockm & 3 ;
lp - > hw . owner = THIS_MODULE ;
/* fill in our module parameters as defaults */
dev - > dev_addr [ 0 ] = node ;
2006-03-05 12:45:09 +03:00
p_dev - > io . Attributes1 = IO_DATA_PATH_WIDTH_8 ;
p_dev - > io . NumPorts1 = 16 ;
p_dev - > io . IOAddrLines = 16 ;
p_dev - > conf . Attributes = CONF_ENABLE_IRQ ;
p_dev - > conf . IntType = INT_MEMORY_AND_IO ;
2005-04-17 02:20:36 +04:00
2009-11-08 19:24:46 +03:00
info - > dev = dev ;
2006-03-05 12:45:09 +03:00
p_dev - > priv = info ;
2005-04-17 02:20:36 +04:00
2006-03-31 19:26:06 +04:00
return com20020_config ( p_dev ) ;
2005-04-17 02:20:36 +04:00
fail_alloc_dev :
kfree ( info ) ;
fail_alloc_info :
2005-11-14 23:25:51 +03:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
} /* com20020_attach */
/*======================================================================
This deletes a driver " instance " . The device is de - registered
with Card Services . If it has been released , all local data
structures are freed . Otherwise , the structures will be freed
when the device is released .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2006-03-31 19:21:06 +04:00
static void com20020_detach ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
struct com20020_dev_t * info = link - > priv ;
2005-11-14 23:25:35 +03:00
struct net_device * dev = info - > dev ;
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " detach... \n " ) ;
2005-04-17 02:20:36 +04:00
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " com20020_detach \n " ) ;
2005-04-17 02:20:36 +04:00
2010-03-20 21:39:26 +03:00
dev_dbg ( & link - > dev , " unregister... \n " ) ;
2005-04-17 02:20:36 +04:00
2010-03-20 21:39:26 +03:00
unregister_netdev ( dev ) ;
2005-11-14 23:25:35 +03:00
2010-03-20 21:39:26 +03:00
/*
* this is necessary because we register our IRQ separately
* from card services .
*/
if ( dev - > irq )
2005-04-17 02:20:36 +04:00
free_irq ( dev - > irq , dev ) ;
2006-03-02 02:09:29 +03:00
com20020_release ( link ) ;
2005-04-17 02:20:36 +04:00
/* Unlink device structure, free bits */
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " unlinking... \n " ) ;
2005-04-17 02:20:36 +04:00
if ( link - > priv )
{
dev = info - > dev ;
if ( dev )
{
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " kfree... \n " ) ;
2005-04-17 02:20:36 +04:00
free_netdev ( dev ) ;
}
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " kfree2... \n " ) ;
2005-04-17 02:20:36 +04:00
kfree ( info ) ;
}
} /* com20020_detach */
/*======================================================================
com20020_config ( ) is scheduled to run after a CARD_INSERTION event
is received , to configure the PCMCIA socket , and to make the
device available to the system .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2006-03-31 19:26:06 +04:00
static int com20020_config ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
struct arcnet_local * lp ;
com20020_dev_t * info ;
struct net_device * dev ;
2009-10-24 17:51:05 +04:00
int i , ret ;
2005-04-17 02:20:36 +04:00
int ioaddr ;
info = link - > priv ;
dev = info - > dev ;
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " config... \n " ) ;
2005-04-17 02:20:36 +04:00
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " com20020_config \n " ) ;
2005-04-17 02:20:36 +04:00
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " baseport1 is %Xh \n " , link - > io . BasePort1 ) ;
2008-08-03 12:07:45 +04:00
i = - ENODEV ;
2005-04-17 02:20:36 +04:00
if ( ! link - > io . BasePort1 )
{
for ( ioaddr = 0x100 ; ioaddr < 0x400 ; ioaddr + = 0x10 )
{
link - > io . BasePort1 = ioaddr ;
2006-03-31 19:21:06 +04:00
i = pcmcia_request_io ( link , & link - > io ) ;
2008-08-03 12:07:45 +04:00
if ( i = = 0 )
2005-04-17 02:20:36 +04:00
break ;
}
}
else
2006-03-31 19:21:06 +04:00
i = pcmcia_request_io ( link , & link - > io ) ;
2005-04-17 02:20:36 +04:00
2008-08-03 12:07:45 +04:00
if ( i ! = 0 )
2005-04-17 02:20:36 +04:00
{
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " requestIO failed totally! \n " ) ;
2005-04-17 02:20:36 +04:00
goto failed ;
}
2010-07-24 17:58:54 +04:00
ioaddr = dev - > base_addr = link - > resource [ 0 ] - > start ;
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " got ioaddr %Xh \n " , ioaddr ) ;
2005-04-17 02:20:36 +04:00
2009-11-08 19:24:46 +03:00
dev_dbg ( & link - > dev , " request IRQ %d \n " ,
2010-03-07 14:21:16 +03:00
link - > irq ) ;
if ( ! link - > irq )
2005-04-17 02:20:36 +04:00
{
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " requestIRQ failed totally! \n " ) ;
2005-04-17 02:20:36 +04:00
goto failed ;
}
2010-03-07 14:21:16 +03:00
dev - > irq = link - > irq ;
2005-04-17 02:20:36 +04:00
2009-10-24 17:51:05 +04:00
ret = pcmcia_request_configuration ( link , & link - > conf ) ;
if ( ret )
goto failed ;
2005-04-17 02:20:36 +04:00
if ( com20020_check ( dev ) )
{
regdump ( dev ) ;
goto failed ;
}
2008-11-13 10:38:14 +03:00
lp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
lp - > card_name = " PCMCIA COM20020 " ;
lp - > card_flags = ARC_CAN_10MBIT ; /* pretend all of them can 10Mbit */
2009-11-03 12:27:34 +03:00
SET_NETDEV_DEV ( dev , & link - > dev ) ;
2005-04-17 02:20:36 +04:00
i = com20020_found ( dev , 0 ) ; /* calls register_netdev */
if ( i ! = 0 ) {
2009-10-24 17:51:05 +04:00
dev_printk ( KERN_NOTICE , & link - > dev ,
" com20020_cs: com20020_found() failed \n " ) ;
2005-04-17 02:20:36 +04:00
goto failed ;
}
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , KERN_INFO " %s: port %#3lx, irq %d \n " ,
2005-04-17 02:20:36 +04:00
dev - > name , dev - > base_addr , dev - > irq ) ;
2006-03-31 19:26:06 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
failed :
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " com20020_config failed... \n " ) ;
2005-04-17 02:20:36 +04:00
com20020_release ( link ) ;
2006-03-31 19:26:06 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
} /* com20020_config */
/*======================================================================
After a card is removed , com20020_release ( ) will unregister the net
device , and release the PCMCIA configuration . If the device is
still open , this will be postponed until it is closed .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
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
{
com20020_dev_t * info = link - > priv ;
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
{
com20020_dev_t * info = link - > priv ;
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 ) ;
2006-03-02 02:02:33 +03:00
ARCRESET ;
}
2005-11-14 23:21:18 +03:00
return 0 ;
}
2005-06-28 03:28:38 +04:00
static struct pcmcia_device_id com20020_ids [ ] = {
2006-06-25 12:56:24 +04:00
PCMCIA_DEVICE_PROD_ID12 ( " Contemporary Control Systems, Inc. " ,
" PCM20 Arcnet Adapter " , 0x59991666 , 0x95dfffaf ) ,
PCMCIA_DEVICE_PROD_ID12 ( " SoHard AG " ,
" 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 ,
. drv = {
. 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
} ;
static int __init init_com20020_cs ( void )
{
return pcmcia_register_driver ( & com20020_cs_driver ) ;
}
static void __exit exit_com20020_cs ( void )
{
pcmcia_unregister_driver ( & com20020_cs_driver ) ;
}
module_init ( init_com20020_cs ) ;
module_exit ( exit_com20020_cs ) ;