2005-04-17 02:20:36 +04:00
/*======================================================================
A PCMCIA token - ring driver for IBM - based cards
This driver supports the IBM PCMCIA Token - Ring Card .
Written by Steve Kipisz , kipisz @ vnet . ibm . com or
bungy @ ibm . net
Written 1995 , 1996.
This code is based on pcnet_cs . c from David Hinds .
V2 .2 .0 February 1999 - Mike Phillips phillim @ amtrak . com
Linux V2 .2 . x presented significant changes to the underlying
ibmtr . c code . Mainly the code became a lot more organized and
modular .
This caused the old PCMCIA Token Ring driver to give up and go
home early . Instead of just patching the old code to make it
work , the PCMCIA code has been streamlined , updated and possibly
improved .
This code now only contains code required for the Card Services .
All we do here is set the card up enough so that the real ibmtr . c
driver can find it and work with it properly .
i . e . We set up the io port , irq , mmio memory and shared ram
memory . This enables ibmtr_probe in ibmtr . c to find the card and
configure it as though it was a normal ISA and / or PnP card .
CHANGES
v2 .2 .5 April 1999 Mike Phillips ( phillim @ amtrak . com )
Obscure bug fix , required changed to ibmtr . c not ibmtr_cs . c
v2 .2 .7 May 1999 Mike Phillips ( phillim @ amtrak . com )
Updated to version 2.2 .7 to match the first version of the kernel
that the modification to ibmtr . c were incorporated into .
v2 .2 .17 July 2000 Burt Silverman ( burts @ us . ibm . com )
Address translation feature of PCMCIA controller is usable so
memory windows can be placed in High memory ( meaning above
0xFFFFF . )
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
2010-08-12 16:22:51 +04:00
# define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2005-04-17 02:20:36 +04:00
# 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/module.h>
# include <linux/netdevice.h>
# include <linux/trdevice.h>
# include <linux/ibmtr.h>
# include <pcmcia/cistpl.h>
# include <pcmcia/ds.h>
# include <asm/uaccess.h>
# include <asm/io.h>
# include <asm/system.h>
# define PCMCIA
2011-08-23 04:37:03 +04:00
# include "ibmtr.c"
2005-04-17 02:20:36 +04:00
/*====================================================================*/
/* Parameters that can be set with 'insmod' */
/* MMIO base address */
static u_long mmiobase = 0xce000 ;
/* SRAM base address */
static u_long srambase = 0xd0000 ;
/* SRAM size 8,16,32,64 */
static u_long sramsize = 64 ;
/* Ringspeed 4,16 */
static int ringspeed = 16 ;
module_param ( mmiobase , ulong , 0 ) ;
module_param ( srambase , ulong , 0 ) ;
module_param ( sramsize , ulong , 0 ) ;
module_param ( ringspeed , int , 0 ) ;
MODULE_LICENSE ( " GPL " ) ;
/*====================================================================*/
2006-03-31 19:26:06 +04:00
static int ibmtr_config ( struct pcmcia_device * link ) ;
2005-04-17 02:20:36 +04:00
static void ibmtr_hw_setup ( struct net_device * dev , u_int mmiobase ) ;
2006-03-31 19:21:06 +04:00
static void ibmtr_release ( struct pcmcia_device * link ) ;
2005-11-14 23:23:14 +03:00
static void ibmtr_detach ( struct pcmcia_device * p_dev ) ;
2005-04-17 02:20:36 +04:00
/*====================================================================*/
typedef struct ibmtr_dev_t {
2006-03-05 12:45:09 +03:00
struct pcmcia_device * p_dev ;
2010-07-28 12:59:06 +04:00
struct net_device * dev ;
struct tok_info * ti ;
2005-04-17 02:20:36 +04:00
} ibmtr_dev_t ;
2009-11-08 19:24:46 +03:00
static irqreturn_t ibmtr_interrupt ( int irq , void * dev_id ) {
ibmtr_dev_t * info = dev_id ;
struct net_device * dev = info - > dev ;
return tok_interrupt ( irq , dev ) ;
} ;
2007-03-14 12:04:21 +03:00
static int __devinit ibmtr_attach ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
ibmtr_dev_t * info ;
struct net_device * dev ;
2006-03-31 19:21:06 +04:00
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " ibmtr_attach() \n " ) ;
2005-04-17 02:20:36 +04:00
/* Create new token-ring 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 ( * info ) , GFP_KERNEL ) ;
2005-11-14 23:25:51 +03:00
if ( ! info ) return - ENOMEM ;
2005-04-17 02:20:36 +04:00
dev = alloc_trdev ( sizeof ( struct tok_info ) ) ;
2005-11-14 23:25:51 +03:00
if ( ! dev ) {
kfree ( info ) ;
return - ENOMEM ;
}
2005-04-17 02:20:36 +04:00
2006-03-31 19:21:06 +04:00
info - > p_dev = link ;
2005-04-17 02:20:36 +04:00
link - > priv = info ;
info - > ti = netdev_priv ( dev ) ;
2010-07-24 19:23:51 +04:00
link - > resource [ 0 ] - > flags | = IO_DATA_PATH_WIDTH_8 ;
link - > resource [ 0 ] - > end = 4 ;
2010-07-29 21:27:09 +04:00
link - > config_flags | = CONF_ENABLE_IRQ ;
2010-07-29 20:35:47 +04:00
link - > config_regs = PRESENT_OPTION ;
2005-04-17 02:20:36 +04:00
2009-11-08 19:24:46 +03:00
info - > dev = dev ;
2005-04-17 02:20:36 +04:00
2006-03-31 19:26:06 +04:00
return ibmtr_config ( link ) ;
2005-04-17 02:20:36 +04:00
} /* ibmtr_attach */
2006-03-31 19:21:06 +04:00
static void ibmtr_detach ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
struct ibmtr_dev_t * info = link - > priv ;
2005-11-14 23:25:35 +03:00
struct net_device * dev = info - > dev ;
2007-05-09 20:47:16 +04:00
struct tok_info * ti = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " ibmtr_detach \n " ) ;
2007-05-09 20:47:16 +04:00
/*
* When the card removal interrupt hits tok_interrupt ( ) ,
* bail out early , so we don ' t crash the machine
*/
ti - > sram_phys | = 1 ;
2005-04-17 02:20:36 +04:00
2010-03-20 21:39:26 +03:00
unregister_netdev ( dev ) ;
2007-05-09 20:47:16 +04:00
del_timer_sync ( & ( ti - > tr_timer ) ) ;
2006-03-02 02:09:29 +03:00
ibmtr_release ( link ) ;
2005-04-17 02:20:36 +04:00
free_netdev ( dev ) ;
2005-11-14 23:25:35 +03:00
kfree ( info ) ;
2005-04-17 02:20:36 +04:00
} /* ibmtr_detach */
2007-03-14 12:04:21 +03:00
static int __devinit ibmtr_config ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
ibmtr_dev_t * info = link - > priv ;
struct net_device * dev = info - > dev ;
struct tok_info * ti = netdev_priv ( dev ) ;
2009-10-24 17:51:05 +04:00
int i , ret ;
2005-04-17 02:20:36 +04:00
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " ibmtr_config \n " ) ;
2005-04-17 02:20:36 +04:00
2010-07-24 19:23:51 +04:00
link - > io_lines = 16 ;
2010-07-29 20:35:47 +04:00
link - > config_index = 0x61 ;
2005-04-17 02:20:36 +04:00
/* Determine if this is PRIMARY or ALTERNATE. */
/* Try PRIMARY card at 0xA20-0xA23 */
2010-07-24 19:23:51 +04:00
link - > resource [ 0 ] - > start = 0xA20 ;
i = pcmcia_request_io ( link ) ;
2008-08-03 12:07:45 +04:00
if ( i ! = 0 ) {
2005-04-17 02:20:36 +04:00
/* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
2010-07-24 19:23:51 +04:00
link - > resource [ 0 ] - > start = 0xA24 ;
ret = pcmcia_request_io ( link ) ;
2009-10-24 17:51:05 +04:00
if ( ret )
goto failed ;
2005-04-17 02:20:36 +04:00
}
2010-07-24 17:58:54 +04:00
dev - > base_addr = link - > resource [ 0 ] - > start ;
2005-04-17 02:20:36 +04:00
2010-03-07 14:21:16 +03:00
ret = pcmcia_request_exclusive_irq ( link , ibmtr_interrupt ) ;
2009-10-24 17:51:05 +04:00
if ( ret )
goto failed ;
2010-03-07 14:21:16 +03:00
dev - > irq = link - > irq ;
ti - > irq = link - > irq ;
2005-04-17 02:20:36 +04:00
ti - > global_int_enable = GLOBAL_INT_ENABLE + ( ( dev - > irq = = 9 ) ? 2 : dev - > irq ) ;
/* Allocate the MMIO memory window */
2010-07-28 12:59:06 +04:00
link - > resource [ 2 ] - > flags | = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE ;
link - > resource [ 2 ] - > flags | = WIN_USE_WAIT ;
link - > resource [ 2 ] - > start = 0 ;
link - > resource [ 2 ] - > end = 0x2000 ;
ret = pcmcia_request_window ( link , link - > resource [ 2 ] , 250 ) ;
2009-10-24 17:51:05 +04:00
if ( ret )
goto failed ;
2005-04-17 02:20:36 +04:00
2010-07-28 12:59:06 +04:00
ret = pcmcia_map_mem_page ( link , link - > resource [ 2 ] , mmiobase ) ;
2009-10-24 17:51:05 +04:00
if ( ret )
goto failed ;
2010-07-28 12:59:06 +04:00
ti - > mmio = ioremap ( link - > resource [ 2 ] - > start ,
resource_size ( link - > resource [ 2 ] ) ) ;
2005-04-17 02:20:36 +04:00
/* Allocate the SRAM memory window */
2010-07-28 12:59:06 +04:00
link - > resource [ 3 ] - > flags = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE ;
link - > resource [ 3 ] - > flags | = WIN_USE_WAIT ;
link - > resource [ 3 ] - > start = 0 ;
link - > resource [ 3 ] - > end = sramsize * 1024 ;
ret = pcmcia_request_window ( link , link - > resource [ 3 ] , 250 ) ;
2009-10-24 17:51:05 +04:00
if ( ret )
goto failed ;
2005-04-17 02:20:36 +04:00
2010-07-28 12:59:06 +04:00
ret = pcmcia_map_mem_page ( link , link - > resource [ 3 ] , srambase ) ;
2009-10-24 17:51:05 +04:00
if ( ret )
goto failed ;
2005-04-17 02:20:36 +04:00
2010-07-24 20:46:42 +04:00
ti - > sram_base = srambase > > 12 ;
2010-07-28 12:59:06 +04:00
ti - > sram_virt = ioremap ( link - > resource [ 3 ] - > start ,
resource_size ( link - > resource [ 3 ] ) ) ;
ti - > sram_phys = link - > resource [ 3 ] - > start ;
2005-04-17 02:20:36 +04:00
2010-07-29 21:27:09 +04:00
ret = pcmcia_enable_device ( link ) ;
2009-10-24 17:51:05 +04:00
if ( ret )
goto failed ;
2005-04-17 02:20:36 +04:00
/* Set up the Token-Ring Controller Configuration Register and
turn on the card . Check the " Local Area Network Credit Card
Adapters Technical Reference " SC30-3585 for this info. */
ibmtr_hw_setup ( dev , mmiobase ) ;
2009-11-03 12:27:34 +03:00
SET_NETDEV_DEV ( dev , & link - > dev ) ;
2005-04-17 02:20:36 +04:00
i = ibmtr_probe_card ( dev ) ;
if ( i ! = 0 ) {
2010-08-12 16:22:51 +04:00
pr_notice ( " register_netdev() failed \n " ) ;
2005-04-17 02:20:36 +04:00
goto failed ;
}
2010-08-12 16:22:51 +04:00
netdev_info ( dev , " port %#3lx, irq %d, mmio %#5lx, sram %#5lx, hwaddr=%pM \n " ,
dev - > base_addr , dev - > irq ,
( u_long ) ti - > mmio , ( u_long ) ( ti - > sram_base < < 12 ) ,
dev - > dev_addr ) ;
2006-03-31 19:26:06 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
failed :
ibmtr_release ( link ) ;
2006-03-31 19:26:06 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
} /* ibmtr_config */
2006-03-31 19:21:06 +04:00
static void ibmtr_release ( struct pcmcia_device * link )
2005-04-17 02:20:36 +04:00
{
2006-01-15 11:32:39 +03:00
ibmtr_dev_t * info = link - > priv ;
struct net_device * dev = info - > dev ;
2005-04-17 02:20:36 +04:00
2009-10-24 17:51:05 +04:00
dev_dbg ( & link - > dev , " ibmtr_release \n " ) ;
2005-04-17 02:20:36 +04:00
2010-07-28 12:59:06 +04:00
if ( link - > resource [ 2 ] - > end ) {
2006-01-15 11:32:39 +03:00
struct tok_info * ti = netdev_priv ( dev ) ;
iounmap ( ti - > mmio ) ;
}
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 ibmtr_suspend ( struct pcmcia_device * link )
2005-11-14 23:21:18 +03:00
{
ibmtr_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 ;
}
2008-11-22 20:35:44 +03:00
static int __devinit ibmtr_resume ( struct pcmcia_device * link )
2005-11-14 23:21:18 +03:00
{
ibmtr_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
ibmtr_probe ( dev ) ; /* really? */
netif_device_attach ( dev ) ;
}
2005-11-14 23:21:18 +03:00
return 0 ;
}
2005-04-17 02:20:36 +04:00
/*====================================================================*/
static void ibmtr_hw_setup ( struct net_device * dev , u_int mmiobase )
{
int i ;
/* Bizarre IBM behavior, there are 16 bits of information we
need to set , but the card only allows us to send 4 bits at a
time . For each byte sent to base_addr , bits 7 - 4 tell the
card which part of the 16 bits we are setting , bits 3 - 0 contain
the actual information */
/* First nibble provides 4 bits of mmio */
i = ( mmiobase > > 16 ) & 0x0F ;
outb ( i , dev - > base_addr ) ;
/* Second nibble provides 3 bits of mmio */
i = 0x10 | ( ( mmiobase > > 12 ) & 0x0E ) ;
outb ( i , dev - > base_addr ) ;
/* Third nibble, hard-coded values */
i = 0x26 ;
outb ( i , dev - > base_addr ) ;
/* Fourth nibble sets shared ram page size */
/* 8 = 00, 16 = 01, 32 = 10, 64 = 11 */
i = ( sramsize > > 4 ) & 0x07 ;
i = ( ( i = = 4 ) ? 3 : i ) < < 2 ;
i | = 0x30 ;
if ( ringspeed = = 16 )
i | = 2 ;
if ( dev - > base_addr = = 0xA24 )
i | = 1 ;
outb ( i , dev - > base_addr ) ;
/* 0x40 will release the card for use */
outb ( 0x40 , dev - > base_addr ) ;
}
2011-05-04 06:29:01 +04:00
static const struct pcmcia_device_id ibmtr_ids [ ] = {
2005-06-28 03:28:22 +04:00
PCMCIA_DEVICE_PROD_ID12 ( " 3Com " , " TokenLink Velocity PC Card " , 0x41240e5b , 0x82c3734e ) ,
PCMCIA_DEVICE_PROD_ID12 ( " IBM " , " TOKEN RING " , 0xb569a6e5 , 0xbf8eed47 ) ,
PCMCIA_DEVICE_NULL ,
} ;
MODULE_DEVICE_TABLE ( pcmcia , ibmtr_ids ) ;
2005-04-17 02:20:36 +04:00
static struct pcmcia_driver ibmtr_cs_driver = {
. owner = THIS_MODULE ,
2010-08-08 13:36:26 +04:00
. name = " ibmtr_cs " ,
2005-11-14 23:25:51 +03:00
. probe = ibmtr_attach ,
2005-11-14 23:23:14 +03:00
. remove = ibmtr_detach ,
2005-06-28 03:28:22 +04:00
. id_table = ibmtr_ids ,
2005-11-14 23:21:18 +03:00
. suspend = ibmtr_suspend ,
. resume = ibmtr_resume ,
2005-04-17 02:20:36 +04:00
} ;
static int __init init_ibmtr_cs ( void )
{
return pcmcia_register_driver ( & ibmtr_cs_driver ) ;
}
static void __exit exit_ibmtr_cs ( void )
{
pcmcia_unregister_driver ( & ibmtr_cs_driver ) ;
}
module_init ( init_ibmtr_cs ) ;
module_exit ( exit_ibmtr_cs ) ;