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 . )
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# 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/ethtool.h>
# include <linux/netdevice.h>
# include <linux/trdevice.h>
# include <linux/ibmtr.h>
# include <pcmcia/cs_types.h>
# include <pcmcia/cs.h>
# include <pcmcia/cistpl.h>
# include <pcmcia/ds.h>
# include <asm/uaccess.h>
# include <asm/io.h>
# include <asm/system.h>
# define PCMCIA
# include "../tokenring/ibmtr.c"
# ifdef PCMCIA_DEBUG
static int pc_debug = PCMCIA_DEBUG ;
module_param ( pc_debug , int , 0 ) ;
# define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args)
static char * version =
" ibmtr_cs.c 1.10 1996/01/06 05:19:00 (Steve Kipisz) \n "
" 2.2.7 1999/05/03 12:00:00 (Mike Phillips) \n "
" 2.4.2 2001/30/28 Midnight (Burt Silverman) \n " ;
# else
# define DEBUG(n, args...)
# endif
/*====================================================================*/
/* 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 ;
2005-04-17 02:20:36 +04:00
struct net_device * dev ;
dev_node_t node ;
window_handle_t sram_win_handle ;
struct tok_info * ti ;
} ibmtr_dev_t ;
static void netdev_get_drvinfo ( struct net_device * dev ,
struct ethtool_drvinfo * info )
{
strcpy ( info - > driver , " ibmtr_cs " ) ;
}
2006-09-13 22:30:00 +04:00
static const struct ethtool_ops netdev_ethtool_ops = {
2005-04-17 02:20:36 +04:00
. get_drvinfo = netdev_get_drvinfo ,
} ;
/*======================================================================
ibmtr_attach ( ) creates an " instance " of the driver , allocating
local data structures for one device . The device is registered
with Card Services .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
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
2005-04-17 02:20:36 +04:00
DEBUG ( 0 , " ibmtr_attach() \n " ) ;
/* 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 ) ;
link - > io . Attributes1 = IO_DATA_PATH_WIDTH_8 ;
link - > io . NumPorts1 = 4 ;
link - > io . IOAddrLines = 16 ;
link - > irq . Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT ;
link - > irq . IRQInfo1 = IRQ_LEVEL_ID ;
link - > irq . Handler = & tok_interrupt ;
link - > conf . Attributes = CONF_ENABLE_IRQ ;
link - > conf . IntType = INT_MEMORY_AND_IO ;
link - > conf . Present = PRESENT_OPTION ;
link - > irq . Instance = info - > dev = dev ;
2006-03-05 12:45:09 +03:00
SET_ETHTOOL_OPS ( dev , & netdev_ethtool_ops ) ;
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 */
/*======================================================================
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 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
DEBUG ( 0 , " ibmtr_detach(0x%p) \n " , link ) ;
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
2006-03-05 12:45:09 +03:00
if ( link - > dev_node )
2005-04-17 02:20:36 +04: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 */
/*======================================================================
ibmtr_config ( ) is scheduled to run after a CARD_INSERTION event
is received , to configure the PCMCIA socket , and to make the
token - ring device available to the system .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
# define CS_CHECK(fn, ret) \
do { last_fn = ( fn ) ; if ( ( last_ret = ( ret ) ) ! = 0 ) goto cs_failed ; } while ( 0 )
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 ) ;
win_req_t req ;
memreq_t mem ;
int i , last_ret , last_fn ;
DEBUG ( 0 , " ibmtr_config(0x%p) \n " , link ) ;
link - > conf . ConfigIndex = 0x61 ;
/* Determine if this is PRIMARY or ALTERNATE. */
/* Try PRIMARY card at 0xA20-0xA23 */
link - > io . BasePort1 = 0xA20 ;
2006-03-31 19:21:06 +04:00
i = pcmcia_request_io ( link , & link - > io ) ;
2005-04-17 02:20:36 +04:00
if ( i ! = CS_SUCCESS ) {
/* Couldn't get 0xA20-0xA23. Try ALTERNATE at 0xA24-0xA27. */
link - > io . BasePort1 = 0xA24 ;
2006-03-31 19:21:06 +04:00
CS_CHECK ( RequestIO , pcmcia_request_io ( link , & link - > io ) ) ;
2005-04-17 02:20:36 +04:00
}
dev - > base_addr = link - > io . BasePort1 ;
2006-03-31 19:21:06 +04:00
CS_CHECK ( RequestIRQ , pcmcia_request_irq ( link , & link - > irq ) ) ;
2005-04-17 02:20:36 +04:00
dev - > irq = link - > irq . AssignedIRQ ;
ti - > irq = link - > irq . AssignedIRQ ;
ti - > global_int_enable = GLOBAL_INT_ENABLE + ( ( dev - > irq = = 9 ) ? 2 : dev - > irq ) ;
/* Allocate the MMIO memory window */
req . Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE ;
req . Attributes | = WIN_USE_WAIT ;
req . Base = 0 ;
req . Size = 0x2000 ;
req . AccessSpeed = 250 ;
2006-03-31 19:21:06 +04:00
CS_CHECK ( RequestWindow , pcmcia_request_window ( & link , & req , & link - > win ) ) ;
2005-04-17 02:20:36 +04:00
mem . CardOffset = mmiobase ;
mem . Page = 0 ;
CS_CHECK ( MapMemPage , pcmcia_map_mem_page ( link - > win , & mem ) ) ;
ti - > mmio = ioremap ( req . Base , req . Size ) ;
/* Allocate the SRAM memory window */
req . Attributes = WIN_DATA_WIDTH_16 | WIN_MEMORY_TYPE_CM | WIN_ENABLE ;
req . Attributes | = WIN_USE_WAIT ;
req . Base = 0 ;
req . Size = sramsize * 1024 ;
req . AccessSpeed = 250 ;
2006-03-31 19:21:06 +04:00
CS_CHECK ( RequestWindow , pcmcia_request_window ( & link , & req , & info - > sram_win_handle ) ) ;
2005-04-17 02:20:36 +04:00
mem . CardOffset = srambase ;
mem . Page = 0 ;
CS_CHECK ( MapMemPage , pcmcia_map_mem_page ( info - > sram_win_handle , & mem ) ) ;
ti - > sram_base = mem . CardOffset > > 12 ;
ti - > sram_virt = ioremap ( req . Base , req . Size ) ;
ti - > sram_phys = req . Base ;
2006-03-31 19:21:06 +04:00
CS_CHECK ( RequestConfiguration , pcmcia_request_configuration ( link , & link - > conf ) ) ;
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 ) ;
2006-03-05 12:45:09 +03:00
link - > dev_node = & info - > node ;
2006-03-31 19:21:06 +04:00
SET_NETDEV_DEV ( dev , & handle_to_dev ( link ) ) ;
2005-04-17 02:20:36 +04:00
i = ibmtr_probe_card ( dev ) ;
if ( i ! = 0 ) {
printk ( KERN_NOTICE " ibmtr_cs: register_netdev() failed \n " ) ;
2006-03-05 12:45:09 +03:00
link - > dev_node = NULL ;
2005-04-17 02:20:36 +04:00
goto failed ;
}
strcpy ( info - > node . dev_name , dev - > name ) ;
printk ( KERN_INFO " %s: port %#3lx, irq %d, " ,
dev - > name , dev - > base_addr , dev - > irq ) ;
printk ( " mmio %#5lx, " , ( u_long ) ti - > mmio ) ;
printk ( " sram %#5lx, " , ( u_long ) ti - > sram_base < < 12 ) ;
printk ( " \n " KERN_INFO " hwaddr= " ) ;
for ( i = 0 ; i < TR_ALEN ; i + + )
printk ( " %02X " , dev - > dev_addr [ i ] ) ;
printk ( " \n " ) ;
2006-03-31 19:26:06 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
cs_failed :
2006-03-31 19:21:06 +04:00
cs_error ( link , last_fn , last_ret ) ;
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 */
/*======================================================================
After a card is removed , ibmtr_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 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
2006-01-15 11:32:39 +03:00
DEBUG ( 0 , " ibmtr_release(0x%p) \n " , link ) ;
2005-04-17 02:20:36 +04:00
2006-01-15 11:32:39 +03:00
if ( link - > win ) {
struct tok_info * ti = netdev_priv ( dev ) ;
iounmap ( ti - > mmio ) ;
pcmcia_release_window ( info - > sram_win_handle ) ;
}
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 ;
}
2006-03-31 19:21:06 +04:00
static int 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 ) ;
return ;
}
2005-06-28 03:28:22 +04:00
static struct pcmcia_device_id ibmtr_ids [ ] = {
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 ,
. drv = {
. 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 ) ;