2005-04-17 02:20:36 +04:00
/*
* SDLA An implementation of a driver for the Sangoma S502 / S508 series
* multi - protocol PC interface card . Initial offering is with
* the DLCI driver , providing Frame Relay support for linux .
*
* Global definitions for the Frame relay interface .
*
* Version : @ ( # ) sdla . c 0.30 12 Sep 1996
*
* Credits : Sangoma Technologies , for the use of 2 cards for an extended
* period of time .
* David Mandelstam < dm @ sangoma . com > for getting me started on
* this project , and incentive to complete it .
* Gene Kozen < 74604.152 @ compuserve . com > for providing me with
* important information about the cards .
*
* Author : Mike McLagan < mike . mclagan @ linux . org >
*
* Changes :
* 0.15 Mike McLagan Improved error handling , packet dropping
* 0.20 Mike McLagan New transmit / receive flags for config
* If in FR mode , don ' t accept packets from
* non DLCI devices .
* 0.25 Mike McLagan Fixed problem with rejecting packets
* from non DLCI devices .
* 0.30 Mike McLagan Fixed kernel panic when used with modified
* ifconfig
*
* This program is free software ; you can redistribute it and / or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation ; either version
* 2 of the License , or ( at your option ) any later version .
*/
# include <linux/module.h>
# include <linux/kernel.h>
# include <linux/types.h>
# include <linux/fcntl.h>
# include <linux/interrupt.h>
# include <linux/ptrace.h>
# include <linux/ioport.h>
# include <linux/in.h>
# include <linux/slab.h>
# include <linux/string.h>
# include <linux/timer.h>
# include <linux/errno.h>
# include <linux/init.h>
# include <linux/netdevice.h>
# include <linux/skbuff.h>
# include <linux/if_arp.h>
# include <linux/if_frad.h>
# include <linux/sdla.h>
# include <linux/bitops.h>
# include <asm/system.h>
# include <asm/io.h>
# include <asm/dma.h>
# include <asm/uaccess.h>
static const char * version = " SDLA driver v0.30, 12 Sep 1996, mike.mclagan@linux.org " ;
2006-06-25 16:48:37 +04:00
static unsigned int valid_port [ ] = { 0x250 , 0x270 , 0x280 , 0x300 , 0x350 , 0x360 , 0x380 , 0x390 } ;
2005-04-17 02:20:36 +04:00
2006-06-25 16:48:37 +04:00
static unsigned int valid_mem [ ] = {
2005-04-17 02:20:36 +04:00
0xA0000 , 0xA2000 , 0xA4000 , 0xA6000 , 0xA8000 , 0xAA000 , 0xAC000 , 0xAE000 ,
0xB0000 , 0xB2000 , 0xB4000 , 0xB6000 , 0xB8000 , 0xBA000 , 0xBC000 , 0xBE000 ,
0xC0000 , 0xC2000 , 0xC4000 , 0xC6000 , 0xC8000 , 0xCA000 , 0xCC000 , 0xCE000 ,
0xD0000 , 0xD2000 , 0xD4000 , 0xD6000 , 0xD8000 , 0xDA000 , 0xDC000 , 0xDE000 ,
0xE0000 , 0xE2000 , 0xE4000 , 0xE6000 , 0xE8000 , 0xEA000 , 0xEC000 , 0xEE000 } ;
static DEFINE_SPINLOCK ( sdla_lock ) ;
/*********************************************************
*
* these are the core routines that access the card itself
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
# define SDLA_WINDOW(dev,addr) outb((((addr) >> 13) & 0x1F), (dev)->base_addr + SDLA_REG_Z80_WINDOW)
static void __sdla_read ( struct net_device * dev , int addr , void * buf , short len )
{
char * temp ;
const void * base ;
int offset , bytes ;
temp = buf ;
while ( len )
{
offset = addr & SDLA_ADDR_MASK ;
bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len ;
base = ( const void * ) ( dev - > mem_start + offset ) ;
SDLA_WINDOW ( dev , addr ) ;
memcpy ( temp , base , bytes ) ;
addr + = bytes ;
temp + = bytes ;
len - = bytes ;
}
}
static void sdla_read ( struct net_device * dev , int addr , void * buf , short len )
{
unsigned long flags ;
spin_lock_irqsave ( & sdla_lock , flags ) ;
__sdla_read ( dev , addr , buf , len ) ;
spin_unlock_irqrestore ( & sdla_lock , flags ) ;
}
static void __sdla_write ( struct net_device * dev , int addr ,
const void * buf , short len )
{
const char * temp ;
void * base ;
int offset , bytes ;
temp = buf ;
while ( len )
{
offset = addr & SDLA_ADDR_MASK ;
bytes = offset + len > SDLA_WINDOW_SIZE ? SDLA_WINDOW_SIZE - offset : len ;
base = ( void * ) ( dev - > mem_start + offset ) ;
SDLA_WINDOW ( dev , addr ) ;
memcpy ( base , temp , bytes ) ;
addr + = bytes ;
temp + = bytes ;
len - = bytes ;
}
}
static void sdla_write ( struct net_device * dev , int addr ,
const void * buf , short len )
{
unsigned long flags ;
spin_lock_irqsave ( & sdla_lock , flags ) ;
__sdla_write ( dev , addr , buf , len ) ;
spin_unlock_irqrestore ( & sdla_lock , flags ) ;
}
static void sdla_clear ( struct net_device * dev )
{
unsigned long flags ;
char * base ;
int len , addr , bytes ;
len = 65536 ;
addr = 0 ;
bytes = SDLA_WINDOW_SIZE ;
base = ( void * ) dev - > mem_start ;
spin_lock_irqsave ( & sdla_lock , flags ) ;
while ( len )
{
SDLA_WINDOW ( dev , addr ) ;
memset ( base , 0 , bytes ) ;
addr + = bytes ;
len - = bytes ;
}
spin_unlock_irqrestore ( & sdla_lock , flags ) ;
}
static char sdla_byte ( struct net_device * dev , int addr )
{
unsigned long flags ;
char byte , * temp ;
temp = ( void * ) ( dev - > mem_start + ( addr & SDLA_ADDR_MASK ) ) ;
spin_lock_irqsave ( & sdla_lock , flags ) ;
SDLA_WINDOW ( dev , addr ) ;
byte = * temp ;
spin_unlock_irqrestore ( & sdla_lock , flags ) ;
2010-09-23 09:40:09 +04:00
return byte ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 10:17:28 +04:00
static void sdla_stop ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
struct frad_local * flp ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
switch ( flp - > type )
{
case SDLA_S502A :
outb ( SDLA_S502A_HALT , dev - > base_addr + SDLA_REG_CONTROL ) ;
flp - > state = SDLA_HALT ;
break ;
case SDLA_S502E :
outb ( SDLA_HALT , dev - > base_addr + SDLA_REG_Z80_CONTROL ) ;
outb ( SDLA_S502E_ENABLE , dev - > base_addr + SDLA_REG_CONTROL ) ;
flp - > state = SDLA_S502E_ENABLE ;
break ;
case SDLA_S507 :
flp - > state & = ~ SDLA_CPUEN ;
outb ( flp - > state , dev - > base_addr + SDLA_REG_CONTROL ) ;
break ;
case SDLA_S508 :
flp - > state & = ~ SDLA_CPUEN ;
outb ( flp - > state , dev - > base_addr + SDLA_REG_CONTROL ) ;
break ;
}
}
2005-09-10 10:17:28 +04:00
static void sdla_start ( struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
struct frad_local * flp ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
switch ( flp - > type )
{
case SDLA_S502A :
outb ( SDLA_S502A_NMI , dev - > base_addr + SDLA_REG_CONTROL ) ;
outb ( SDLA_S502A_START , dev - > base_addr + SDLA_REG_CONTROL ) ;
flp - > state = SDLA_S502A_START ;
break ;
case SDLA_S502E :
outb ( SDLA_S502E_CPUEN , dev - > base_addr + SDLA_REG_Z80_CONTROL ) ;
outb ( 0x00 , dev - > base_addr + SDLA_REG_CONTROL ) ;
flp - > state = 0 ;
break ;
case SDLA_S507 :
flp - > state | = SDLA_CPUEN ;
outb ( flp - > state , dev - > base_addr + SDLA_REG_CONTROL ) ;
break ;
case SDLA_S508 :
flp - > state | = SDLA_CPUEN ;
outb ( flp - > state , dev - > base_addr + SDLA_REG_CONTROL ) ;
break ;
}
}
/****************************************************
*
* this is used for the S502A / E cards to determine
* the speed of the onboard CPU . Calibration is
* necessary for the Frame Relay code uploaded
* later . Incorrect results cause timing problems
* with link checks & status messages
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
2005-09-10 10:17:28 +04:00
static int sdla_z80_poll ( struct net_device * dev , int z80_addr , int jiffs , char resp1 , char resp2 )
2005-04-17 02:20:36 +04:00
{
unsigned long start , done , now ;
char resp , * temp ;
start = now = jiffies ;
done = jiffies + jiffs ;
temp = ( void * ) dev - > mem_start ;
temp + = z80_addr & SDLA_ADDR_MASK ;
resp = ~ resp1 ;
while ( time_before ( jiffies , done ) & & ( resp ! = resp1 ) & & ( ! resp2 | | ( resp ! = resp2 ) ) )
{
if ( jiffies ! = now )
{
SDLA_WINDOW ( dev , z80_addr ) ;
now = jiffies ;
resp = * temp ;
}
}
2010-09-23 09:40:09 +04:00
return time_before ( jiffies , done ) ? jiffies - start : - 1 ;
2005-04-17 02:20:36 +04:00
}
/* constants for Z80 CPU speed */
# define Z80_READY '1' /* Z80 is ready to begin */
# define LOADER_READY '2' /* driver is ready to begin */
# define Z80_SCC_OK '3' /* SCC is on board */
# define Z80_SCC_BAD '4' /* SCC was not found */
static int sdla_cpuspeed ( struct net_device * dev , struct ifreq * ifr )
{
int jiffs ;
char data ;
sdla_start ( dev ) ;
if ( sdla_z80_poll ( dev , 0 , 3 * HZ , Z80_READY , 0 ) < 0 )
2010-09-23 09:40:09 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
data = LOADER_READY ;
sdla_write ( dev , 0 , & data , 1 ) ;
if ( ( jiffs = sdla_z80_poll ( dev , 0 , 8 * HZ , Z80_SCC_OK , Z80_SCC_BAD ) ) < 0 )
2010-09-23 09:40:09 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
sdla_stop ( dev ) ;
sdla_read ( dev , 0 , & data , 1 ) ;
if ( data = = Z80_SCC_BAD )
{
printk ( " %s: SCC bad \n " , dev - > name ) ;
2010-09-23 09:40:09 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
if ( data ! = Z80_SCC_OK )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( jiffs < 165 )
ifr - > ifr_mtu = SDLA_CPU_16M ;
else if ( jiffs < 220 )
ifr - > ifr_mtu = SDLA_CPU_10M ;
else if ( jiffs < 258 )
ifr - > ifr_mtu = SDLA_CPU_8M ;
else if ( jiffs < 357 )
ifr - > ifr_mtu = SDLA_CPU_7M ;
else if ( jiffs < 467 )
ifr - > ifr_mtu = SDLA_CPU_5M ;
else
ifr - > ifr_mtu = SDLA_CPU_3M ;
2010-09-23 09:40:09 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
/************************************************
*
* Direct interaction with the Frame Relay code
* starts here .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
struct _dlci_stat
{
2006-01-08 12:05:07 +03:00
short dlci ;
char flags ;
2010-06-02 22:10:09 +04:00
} __packed ;
2005-04-17 02:20:36 +04:00
struct _frad_stat
{
char flags ;
struct _dlci_stat dlcis [ SDLA_MAX_DLCI ] ;
} ;
static void sdla_errors ( struct net_device * dev , int cmd , int dlci , int ret , int len , void * data )
{
struct _dlci_stat * pstatus ;
short * pdlci ;
int i ;
char * state , line [ 30 ] ;
switch ( ret )
{
case SDLA_RET_MODEM :
state = data ;
if ( * state & SDLA_MODEM_DCD_LOW )
printk ( KERN_INFO " %s: Modem DCD unexpectedly low! \n " , dev - > name ) ;
if ( * state & SDLA_MODEM_CTS_LOW )
printk ( KERN_INFO " %s: Modem CTS unexpectedly low! \n " , dev - > name ) ;
/* I should probably do something about this! */
break ;
case SDLA_RET_CHANNEL_OFF :
printk ( KERN_INFO " %s: Channel became inoperative! \n " , dev - > name ) ;
/* same here */
break ;
case SDLA_RET_CHANNEL_ON :
printk ( KERN_INFO " %s: Channel became operative! \n " , dev - > name ) ;
/* same here */
break ;
case SDLA_RET_DLCI_STATUS :
printk ( KERN_INFO " %s: Status change reported by Access Node. \n " , dev - > name ) ;
len / = sizeof ( struct _dlci_stat ) ;
for ( pstatus = data , i = 0 ; i < len ; i + + , pstatus + + )
{
if ( pstatus - > flags & SDLA_DLCI_NEW )
state = " new " ;
else if ( pstatus - > flags & SDLA_DLCI_DELETED )
state = " deleted " ;
else if ( pstatus - > flags & SDLA_DLCI_ACTIVE )
state = " active " ;
else
{
sprintf ( line , " unknown status: %02X " , pstatus - > flags ) ;
state = line ;
}
printk ( KERN_INFO " %s: DLCI %i: %s. \n " , dev - > name , pstatus - > dlci , state ) ;
/* same here */
}
break ;
case SDLA_RET_DLCI_UNKNOWN :
printk ( KERN_INFO " %s: Received unknown DLCIs: " , dev - > name ) ;
len / = sizeof ( short ) ;
for ( pdlci = data , i = 0 ; i < len ; i + + , pdlci + + )
printk ( " %i " , * pdlci ) ;
printk ( " \n " ) ;
break ;
case SDLA_RET_TIMEOUT :
printk ( KERN_ERR " %s: Command timed out! \n " , dev - > name ) ;
break ;
case SDLA_RET_BUF_OVERSIZE :
printk ( KERN_INFO " %s: Bc/CIR overflow, acceptable size is %i \n " , dev - > name , len ) ;
break ;
case SDLA_RET_BUF_TOO_BIG :
printk ( KERN_INFO " %s: Buffer size over specified max of %i \n " , dev - > name , len ) ;
break ;
case SDLA_RET_CHANNEL_INACTIVE :
case SDLA_RET_DLCI_INACTIVE :
case SDLA_RET_CIR_OVERFLOW :
case SDLA_RET_NO_BUFS :
if ( cmd = = SDLA_INFORMATION_WRITE )
break ;
default :
printk ( KERN_DEBUG " %s: Cmd 0x%2.2X generated return code 0x%2.2X \n " , dev - > name , cmd , ret ) ;
/* Further processing could be done here */
break ;
}
}
static int sdla_cmd ( struct net_device * dev , int cmd , short dlci , short flags ,
void * inbuf , short inlen , void * outbuf , short * outlen )
{
static struct _frad_stat status ;
struct frad_local * flp ;
struct sdla_cmd * cmd_buf ;
unsigned long pflags ;
unsigned long jiffs ;
int ret , waiting , len ;
long window ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
window = flp - > type = = SDLA_S508 ? SDLA_508_CMD_BUF : SDLA_502_CMD_BUF ;
cmd_buf = ( struct sdla_cmd * ) ( dev - > mem_start + ( window & SDLA_ADDR_MASK ) ) ;
ret = 0 ;
len = 0 ;
jiffs = jiffies + HZ ; /* 1 second is plenty */
spin_lock_irqsave ( & sdla_lock , pflags ) ;
SDLA_WINDOW ( dev , window ) ;
cmd_buf - > cmd = cmd ;
cmd_buf - > dlci = dlci ;
cmd_buf - > flags = flags ;
if ( inbuf )
memcpy ( cmd_buf - > data , inbuf , inlen ) ;
cmd_buf - > length = inlen ;
cmd_buf - > opp_flag = 1 ;
spin_unlock_irqrestore ( & sdla_lock , pflags ) ;
waiting = 1 ;
len = 0 ;
while ( waiting & & time_before_eq ( jiffies , jiffs ) )
{
if ( waiting + + % 3 )
{
spin_lock_irqsave ( & sdla_lock , pflags ) ;
SDLA_WINDOW ( dev , window ) ;
waiting = ( ( volatile int ) ( cmd_buf - > opp_flag ) ) ;
spin_unlock_irqrestore ( & sdla_lock , pflags ) ;
}
}
if ( ! waiting )
{
spin_lock_irqsave ( & sdla_lock , pflags ) ;
SDLA_WINDOW ( dev , window ) ;
ret = cmd_buf - > retval ;
len = cmd_buf - > length ;
if ( outbuf & & outlen )
{
* outlen = * outlen > = len ? len : * outlen ;
if ( * outlen )
memcpy ( outbuf , cmd_buf - > data , * outlen ) ;
}
/* This is a local copy that's used for error handling */
if ( ret )
memcpy ( & status , cmd_buf - > data , len > sizeof ( status ) ? sizeof ( status ) : len ) ;
spin_unlock_irqrestore ( & sdla_lock , pflags ) ;
}
else
ret = SDLA_RET_TIMEOUT ;
if ( ret ! = SDLA_RET_OK )
sdla_errors ( dev , cmd , dlci , ret , len , & status ) ;
2010-09-23 09:40:09 +04:00
return ret ;
2005-04-17 02:20:36 +04:00
}
/***********************************************
*
* these functions are called by the DLCI driver
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
static int sdla_reconfig ( struct net_device * dev ) ;
2005-09-10 10:17:28 +04:00
static int sdla_activate ( struct net_device * slave , struct net_device * master )
2005-04-17 02:20:36 +04:00
{
struct frad_local * flp ;
int i ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( slave ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > master [ i ] = = master )
break ;
if ( i = = CONFIG_DLCI_MAX )
2010-09-23 09:40:09 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
flp - > dlci [ i ] = abs ( flp - > dlci [ i ] ) ;
if ( netif_running ( slave ) & & ( flp - > config . station = = FRAD_STATION_NODE ) )
sdla_cmd ( slave , SDLA_ACTIVATE_DLCI , 0 , 0 , & flp - > dlci [ i ] , sizeof ( short ) , NULL , NULL ) ;
2010-09-23 09:40:09 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 10:17:28 +04:00
static int sdla_deactivate ( struct net_device * slave , struct net_device * master )
2005-04-17 02:20:36 +04:00
{
struct frad_local * flp ;
int i ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( slave ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > master [ i ] = = master )
break ;
if ( i = = CONFIG_DLCI_MAX )
2010-09-23 09:40:09 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
flp - > dlci [ i ] = - abs ( flp - > dlci [ i ] ) ;
if ( netif_running ( slave ) & & ( flp - > config . station = = FRAD_STATION_NODE ) )
sdla_cmd ( slave , SDLA_DEACTIVATE_DLCI , 0 , 0 , & flp - > dlci [ i ] , sizeof ( short ) , NULL , NULL ) ;
2010-09-23 09:40:09 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 10:17:28 +04:00
static int sdla_assoc ( struct net_device * slave , struct net_device * master )
2005-04-17 02:20:36 +04:00
{
struct frad_local * flp ;
int i ;
if ( master - > type ! = ARPHRD_DLCI )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( slave ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
{
if ( ! flp - > master [ i ] )
break ;
if ( abs ( flp - > dlci [ i ] ) = = * ( short * ) ( master - > dev_addr ) )
2010-09-23 09:40:09 +04:00
return - EADDRINUSE ;
2005-04-17 02:20:36 +04:00
}
if ( i = = CONFIG_DLCI_MAX )
2010-09-23 09:40:09 +04:00
return - EMLINK ; /* #### Alan: Comments on this ?? */
2005-04-17 02:20:36 +04:00
flp - > master [ i ] = master ;
flp - > dlci [ i ] = - * ( short * ) ( master - > dev_addr ) ;
master - > mtu = slave - > mtu ;
if ( netif_running ( slave ) ) {
if ( flp - > config . station = = FRAD_STATION_CPE )
sdla_reconfig ( slave ) ;
else
sdla_cmd ( slave , SDLA_ADD_DLCI , 0 , 0 , master - > dev_addr , sizeof ( short ) , NULL , NULL ) ;
}
2010-09-23 09:40:09 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 10:17:28 +04:00
static int sdla_deassoc ( struct net_device * slave , struct net_device * master )
2005-04-17 02:20:36 +04:00
{
struct frad_local * flp ;
int i ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( slave ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > master [ i ] = = master )
break ;
if ( i = = CONFIG_DLCI_MAX )
2010-09-23 09:40:09 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
flp - > master [ i ] = NULL ;
flp - > dlci [ i ] = 0 ;
if ( netif_running ( slave ) ) {
if ( flp - > config . station = = FRAD_STATION_CPE )
sdla_reconfig ( slave ) ;
else
sdla_cmd ( slave , SDLA_DELETE_DLCI , 0 , 0 , master - > dev_addr , sizeof ( short ) , NULL , NULL ) ;
}
2010-09-23 09:40:09 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 10:17:28 +04:00
static int sdla_dlci_conf ( struct net_device * slave , struct net_device * master , int get )
2005-04-17 02:20:36 +04:00
{
struct frad_local * flp ;
struct dlci_local * dlp ;
int i ;
short len , ret ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( slave ) ;
2005-04-17 02:20:36 +04:00
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > master [ i ] = = master )
break ;
if ( i = = CONFIG_DLCI_MAX )
2010-09-23 09:40:09 +04:00
return - ENODEV ;
2005-04-17 02:20:36 +04:00
2008-11-13 10:38:36 +03:00
dlp = netdev_priv ( master ) ;
2005-04-17 02:20:36 +04:00
ret = SDLA_RET_OK ;
len = sizeof ( struct dlci_conf ) ;
if ( netif_running ( slave ) ) {
if ( get )
ret = sdla_cmd ( slave , SDLA_READ_DLCI_CONFIGURATION , abs ( flp - > dlci [ i ] ) , 0 ,
NULL , 0 , & dlp - > config , & len ) ;
else
ret = sdla_cmd ( slave , SDLA_SET_DLCI_CONFIGURATION , abs ( flp - > dlci [ i ] ) , 0 ,
& dlp - > config , sizeof ( struct dlci_conf ) - 4 * sizeof ( short ) , NULL , NULL ) ;
}
2010-09-23 09:40:09 +04:00
return ret = = SDLA_RET_OK ? 0 : - EIO ;
2005-04-17 02:20:36 +04:00
}
/**************************
*
* now for the Linux driver
*
* * * * * * * * * * * * * * * * * * * * * * * * * */
/* NOTE: the DLCI driver deals with freeing the SKB!! */
2009-08-31 23:50:47 +04:00
static netdev_tx_t sdla_transmit ( struct sk_buff * skb ,
2009-09-04 09:33:46 +04:00
struct net_device * dev )
2005-04-17 02:20:36 +04:00
{
struct frad_local * flp ;
int ret , addr , accept , i ;
short size ;
unsigned long flags ;
struct buf_entry * pbuf ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
ret = 0 ;
accept = 1 ;
netif_stop_queue ( dev ) ;
/*
* stupid GateD insists on setting up the multicast router thru us
* and we ' re ill equipped to handle a non Frame Relay packet at this
* time !
*/
accept = 1 ;
switch ( dev - > type )
{
case ARPHRD_FRAD :
if ( skb - > dev - > type ! = ARPHRD_DLCI )
{
printk ( KERN_WARNING " %s: Non DLCI device, type %i, tried to send on FRAD module. \n " , dev - > name , skb - > dev - > type ) ;
accept = 0 ;
}
break ;
default :
printk ( KERN_WARNING " %s: unknown firmware type 0x%4.4X \n " , dev - > name , dev - > type ) ;
accept = 0 ;
break ;
}
if ( accept )
{
/* this is frame specific, but till there's a PPP module, it's the default */
switch ( flp - > type )
{
case SDLA_S502A :
case SDLA_S502E :
ret = sdla_cmd ( dev , SDLA_INFORMATION_WRITE , * ( short * ) ( skb - > dev - > dev_addr ) , 0 , skb - > data , skb - > len , NULL , NULL ) ;
break ;
case SDLA_S508 :
size = sizeof ( addr ) ;
ret = sdla_cmd ( dev , SDLA_INFORMATION_WRITE , * ( short * ) ( skb - > dev - > dev_addr ) , 0 , NULL , skb - > len , & addr , & size ) ;
if ( ret = = SDLA_RET_OK )
{
spin_lock_irqsave ( & sdla_lock , flags ) ;
SDLA_WINDOW ( dev , addr ) ;
pbuf = ( void * ) ( ( ( int ) dev - > mem_start ) + ( addr & SDLA_ADDR_MASK ) ) ;
__sdla_write ( dev , pbuf - > buf_addr , skb - > data , skb - > len ) ;
SDLA_WINDOW ( dev , addr ) ;
pbuf - > opp_flag = 1 ;
spin_unlock_irqrestore ( & sdla_lock , flags ) ;
}
break ;
}
2009-09-04 09:33:46 +04:00
2005-04-17 02:20:36 +04:00
switch ( ret )
{
case SDLA_RET_OK :
2009-03-26 18:11:25 +03:00
dev - > stats . tx_packets + + ;
2005-04-17 02:20:36 +04:00
break ;
case SDLA_RET_CIR_OVERFLOW :
case SDLA_RET_BUF_OVERSIZE :
case SDLA_RET_NO_BUFS :
2009-03-26 18:11:25 +03:00
dev - > stats . tx_dropped + + ;
2005-04-17 02:20:36 +04:00
break ;
default :
2009-03-26 18:11:25 +03:00
dev - > stats . tx_errors + + ;
2005-04-17 02:20:36 +04:00
break ;
}
}
netif_wake_queue ( dev ) ;
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
{
if ( flp - > master [ i ] ! = NULL )
netif_wake_queue ( flp - > master [ i ] ) ;
}
2009-09-04 09:33:46 +04:00
dev_kfree_skb ( skb ) ;
2009-08-31 23:50:47 +04:00
return NETDEV_TX_OK ;
2005-04-17 02:20:36 +04:00
}
static void sdla_receive ( struct net_device * dev )
{
struct net_device * master ;
struct frad_local * flp ;
struct dlci_local * dlp ;
struct sk_buff * skb ;
struct sdla_cmd * cmd ;
struct buf_info * pbufi ;
struct buf_entry * pbuf ;
unsigned long flags ;
int i = 0 , received , success , addr , buf_base , buf_top ;
short dlci , len , len2 , split ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
success = 1 ;
received = addr = buf_top = buf_base = 0 ;
len = dlci = 0 ;
skb = NULL ;
master = NULL ;
cmd = NULL ;
pbufi = NULL ;
pbuf = NULL ;
spin_lock_irqsave ( & sdla_lock , flags ) ;
switch ( flp - > type )
{
case SDLA_S502A :
case SDLA_S502E :
cmd = ( void * ) ( dev - > mem_start + ( SDLA_502_RCV_BUF & SDLA_ADDR_MASK ) ) ;
SDLA_WINDOW ( dev , SDLA_502_RCV_BUF ) ;
success = cmd - > opp_flag ;
if ( ! success )
break ;
dlci = cmd - > dlci ;
len = cmd - > length ;
break ;
case SDLA_S508 :
pbufi = ( void * ) ( dev - > mem_start + ( SDLA_508_RXBUF_INFO & SDLA_ADDR_MASK ) ) ;
SDLA_WINDOW ( dev , SDLA_508_RXBUF_INFO ) ;
pbuf = ( void * ) ( dev - > mem_start + ( ( pbufi - > rse_base + flp - > buffer * sizeof ( struct buf_entry ) ) & SDLA_ADDR_MASK ) ) ;
success = pbuf - > opp_flag ;
if ( ! success )
break ;
buf_top = pbufi - > buf_top ;
buf_base = pbufi - > buf_base ;
dlci = pbuf - > dlci ;
len = pbuf - > length ;
addr = pbuf - > buf_addr ;
break ;
}
/* common code, find the DLCI and get the SKB */
if ( success )
{
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > dlci [ i ] = = dlci )
break ;
if ( i = = CONFIG_DLCI_MAX )
{
printk ( KERN_NOTICE " %s: Received packet from invalid DLCI %i, ignoring. " , dev - > name , dlci ) ;
2009-03-26 18:11:25 +03:00
dev - > stats . rx_errors + + ;
2005-04-17 02:20:36 +04:00
success = 0 ;
}
}
if ( success )
{
master = flp - > master [ i ] ;
skb = dev_alloc_skb ( len + sizeof ( struct frhdr ) ) ;
if ( skb = = NULL )
{
printk ( KERN_NOTICE " %s: Memory squeeze, dropping packet. \n " , dev - > name ) ;
2009-03-26 18:11:25 +03:00
dev - > stats . rx_dropped + + ;
2005-04-17 02:20:36 +04:00
success = 0 ;
}
else
skb_reserve ( skb , sizeof ( struct frhdr ) ) ;
}
/* pick up the data */
switch ( flp - > type )
{
case SDLA_S502A :
case SDLA_S502E :
if ( success )
__sdla_read ( dev , SDLA_502_RCV_BUF + SDLA_502_DATA_OFS , skb_put ( skb , len ) , len ) ;
SDLA_WINDOW ( dev , SDLA_502_RCV_BUF ) ;
cmd - > opp_flag = 0 ;
break ;
case SDLA_S508 :
if ( success )
{
/* is this buffer split off the end of the internal ring buffer */
split = addr + len > buf_top + 1 ? len - ( buf_top - addr + 1 ) : 0 ;
len2 = len - split ;
__sdla_read ( dev , addr , skb_put ( skb , len2 ) , len2 ) ;
if ( split )
__sdla_read ( dev , buf_base , skb_put ( skb , split ) , split ) ;
}
/* increment the buffer we're looking at */
SDLA_WINDOW ( dev , SDLA_508_RXBUF_INFO ) ;
flp - > buffer = ( flp - > buffer + 1 ) % pbufi - > rse_num ;
pbuf - > opp_flag = 0 ;
break ;
}
if ( success )
{
2009-03-26 18:11:25 +03:00
dev - > stats . rx_packets + + ;
2008-11-13 10:38:36 +03:00
dlp = netdev_priv ( master ) ;
2005-04-17 02:20:36 +04:00
( * dlp - > receive ) ( skb , master ) ;
}
spin_unlock_irqrestore ( & sdla_lock , flags ) ;
}
2007-10-29 12:46:16 +03:00
static irqreturn_t sdla_isr ( int dummy , void * dev_id )
2005-04-17 02:20:36 +04:00
{
struct net_device * dev ;
struct frad_local * flp ;
char byte ;
dev = dev_id ;
2006-10-06 22:56:04 +04:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! flp - > initialized )
{
2007-10-29 12:46:16 +03:00
printk ( KERN_WARNING " %s: irq %d for uninitialized device. \n " ,
dev - > name , dev - > irq ) ;
2005-04-17 02:20:36 +04:00
return IRQ_NONE ;
}
byte = sdla_byte ( dev , flp - > type = = SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE ) ;
switch ( byte )
{
case SDLA_INTR_RX :
sdla_receive ( dev ) ;
break ;
/* the command will get an error return, which is processed above */
case SDLA_INTR_MODEM :
case SDLA_INTR_STATUS :
sdla_cmd ( dev , SDLA_READ_DLC_STATUS , 0 , 0 , NULL , 0 , NULL , NULL ) ;
break ;
case SDLA_INTR_TX :
case SDLA_INTR_COMPLETE :
case SDLA_INTR_TIMER :
printk ( KERN_WARNING " %s: invalid irq flag 0x%02X. \n " , dev - > name , byte ) ;
break ;
}
/* the S502E requires a manual acknowledgement of the interrupt */
if ( flp - > type = = SDLA_S502E )
{
flp - > state & = ~ SDLA_S502E_INTACK ;
outb ( flp - > state , dev - > base_addr + SDLA_REG_CONTROL ) ;
flp - > state | = SDLA_S502E_INTACK ;
outb ( flp - > state , dev - > base_addr + SDLA_REG_CONTROL ) ;
}
/* this clears the byte, informing the Z80 we're done */
byte = 0 ;
sdla_write ( dev , flp - > type = = SDLA_S508 ? SDLA_508_IRQ_INTERFACE : SDLA_502_IRQ_INTERFACE , & byte , sizeof ( byte ) ) ;
return IRQ_HANDLED ;
}
static void sdla_poll ( unsigned long device )
{
struct net_device * dev ;
struct frad_local * flp ;
dev = ( struct net_device * ) device ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( sdla_byte ( dev , SDLA_502_RCV_BUF ) )
sdla_receive ( dev ) ;
flp - > timer . expires = 1 ;
add_timer ( & flp - > timer ) ;
}
static int sdla_close ( struct net_device * dev )
{
struct frad_local * flp ;
struct intr_info intr ;
int len , i ;
short dlcis [ CONFIG_DLCI_MAX ] ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
len = 0 ;
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > dlci [ i ] )
dlcis [ len + + ] = abs ( flp - > dlci [ i ] ) ;
len * = 2 ;
if ( flp - > config . station = = FRAD_STATION_NODE )
{
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > dlci [ i ] > 0 )
sdla_cmd ( dev , SDLA_DEACTIVATE_DLCI , 0 , 0 , dlcis , len , NULL , NULL ) ;
sdla_cmd ( dev , SDLA_DELETE_DLCI , 0 , 0 , & flp - > dlci [ i ] , sizeof ( flp - > dlci [ i ] ) , NULL , NULL ) ;
}
memset ( & intr , 0 , sizeof ( intr ) ) ;
/* let's start up the reception */
switch ( flp - > type )
{
case SDLA_S502A :
del_timer ( & flp - > timer ) ;
break ;
case SDLA_S502E :
sdla_cmd ( dev , SDLA_SET_IRQ_TRIGGER , 0 , 0 , & intr , sizeof ( char ) + sizeof ( short ) , NULL , NULL ) ;
flp - > state & = ~ SDLA_S502E_INTACK ;
outb ( flp - > state , dev - > base_addr + SDLA_REG_CONTROL ) ;
break ;
case SDLA_S507 :
break ;
case SDLA_S508 :
sdla_cmd ( dev , SDLA_SET_IRQ_TRIGGER , 0 , 0 , & intr , sizeof ( struct intr_info ) , NULL , NULL ) ;
flp - > state & = ~ SDLA_S508_INTEN ;
outb ( flp - > state , dev - > base_addr + SDLA_REG_CONTROL ) ;
break ;
}
sdla_cmd ( dev , SDLA_DISABLE_COMMUNICATIONS , 0 , 0 , NULL , 0 , NULL , NULL ) ;
netif_stop_queue ( dev ) ;
2010-09-23 09:40:09 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
struct conf_data {
struct frad_conf config ;
short dlci [ CONFIG_DLCI_MAX ] ;
} ;
static int sdla_open ( struct net_device * dev )
{
struct frad_local * flp ;
struct dlci_local * dlp ;
struct conf_data data ;
struct intr_info intr ;
int len , i ;
char byte ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! flp - > initialized )
2010-09-23 09:40:09 +04:00
return - EPERM ;
2005-04-17 02:20:36 +04:00
if ( ! flp - > configured )
2010-09-23 09:40:09 +04:00
return - EPERM ;
2005-04-17 02:20:36 +04:00
/* time to send in the configuration */
len = 0 ;
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > dlci [ i ] )
data . dlci [ len + + ] = abs ( flp - > dlci [ i ] ) ;
len * = 2 ;
memcpy ( & data . config , & flp - > config , sizeof ( struct frad_conf ) ) ;
len + = sizeof ( struct frad_conf ) ;
sdla_cmd ( dev , SDLA_DISABLE_COMMUNICATIONS , 0 , 0 , NULL , 0 , NULL , NULL ) ;
sdla_cmd ( dev , SDLA_SET_DLCI_CONFIGURATION , 0 , 0 , & data , len , NULL , NULL ) ;
if ( flp - > type = = SDLA_S508 )
flp - > buffer = 0 ;
sdla_cmd ( dev , SDLA_ENABLE_COMMUNICATIONS , 0 , 0 , NULL , 0 , NULL , NULL ) ;
/* let's start up the reception */
memset ( & intr , 0 , sizeof ( intr ) ) ;
switch ( flp - > type )
{
case SDLA_S502A :
flp - > timer . expires = 1 ;
add_timer ( & flp - > timer ) ;
break ;
case SDLA_S502E :
flp - > state | = SDLA_S502E_ENABLE ;
outb ( flp - > state , dev - > base_addr + SDLA_REG_CONTROL ) ;
flp - > state | = SDLA_S502E_INTACK ;
outb ( flp - > state , dev - > base_addr + SDLA_REG_CONTROL ) ;
byte = 0 ;
sdla_write ( dev , SDLA_502_IRQ_INTERFACE , & byte , sizeof ( byte ) ) ;
intr . flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM ;
sdla_cmd ( dev , SDLA_SET_IRQ_TRIGGER , 0 , 0 , & intr , sizeof ( char ) + sizeof ( short ) , NULL , NULL ) ;
break ;
case SDLA_S507 :
break ;
case SDLA_S508 :
flp - > state | = SDLA_S508_INTEN ;
outb ( flp - > state , dev - > base_addr + SDLA_REG_CONTROL ) ;
byte = 0 ;
sdla_write ( dev , SDLA_508_IRQ_INTERFACE , & byte , sizeof ( byte ) ) ;
intr . flags = SDLA_INTR_RX | SDLA_INTR_STATUS | SDLA_INTR_MODEM ;
intr . irq = dev - > irq ;
sdla_cmd ( dev , SDLA_SET_IRQ_TRIGGER , 0 , 0 , & intr , sizeof ( struct intr_info ) , NULL , NULL ) ;
break ;
}
if ( flp - > config . station = = FRAD_STATION_CPE )
{
byte = SDLA_ICS_STATUS_ENQ ;
sdla_cmd ( dev , SDLA_ISSUE_IN_CHANNEL_SIGNAL , 0 , 0 , & byte , sizeof ( byte ) , NULL , NULL ) ;
}
else
{
sdla_cmd ( dev , SDLA_ADD_DLCI , 0 , 0 , data . dlci , len - sizeof ( struct frad_conf ) , NULL , NULL ) ;
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > dlci [ i ] > 0 )
sdla_cmd ( dev , SDLA_ACTIVATE_DLCI , 0 , 0 , & flp - > dlci [ i ] , 2 * sizeof ( flp - > dlci [ i ] ) , NULL , NULL ) ;
}
/* configure any specific DLCI settings */
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > dlci [ i ] )
{
2008-11-13 10:38:36 +03:00
dlp = netdev_priv ( flp - > master [ i ] ) ;
2005-04-17 02:20:36 +04:00
if ( dlp - > configured )
sdla_cmd ( dev , SDLA_SET_DLCI_CONFIGURATION , abs ( flp - > dlci [ i ] ) , 0 , & dlp - > config , sizeof ( struct dlci_conf ) , NULL , NULL ) ;
}
netif_start_queue ( dev ) ;
2010-09-23 09:40:09 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int sdla_config ( struct net_device * dev , struct frad_conf __user * conf , int get )
{
struct frad_local * flp ;
struct conf_data data ;
int i ;
short size ;
if ( dev - > type = = 0xFFFF )
2010-09-23 09:40:09 +04:00
return - EUNATCH ;
2005-04-17 02:20:36 +04:00
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! get )
{
if ( netif_running ( dev ) )
2010-09-23 09:40:09 +04:00
return - EBUSY ;
2005-04-17 02:20:36 +04:00
if ( copy_from_user ( & data . config , conf , sizeof ( struct frad_conf ) ) )
return - EFAULT ;
if ( data . config . station & ~ FRAD_STATION_NODE )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( data . config . flags & ~ FRAD_VALID_FLAGS )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ( data . config . kbaud < 0 ) | |
( ( data . config . kbaud > 128 ) & & ( flp - > type ! = SDLA_S508 ) ) )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( data . config . clocking & ~ ( FRAD_CLOCK_INT | SDLA_S508_PORT_RS232 ) )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ( data . config . mtu < 0 ) | | ( data . config . mtu > SDLA_MAX_MTU ) )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ( data . config . T391 < 5 ) | | ( data . config . T391 > 30 ) )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ( data . config . T392 < 5 ) | | ( data . config . T392 > 30 ) )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ( data . config . N391 < 1 ) | | ( data . config . N391 > 255 ) )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ( data . config . N392 < 1 ) | | ( data . config . N392 > 10 ) )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ( data . config . N393 < 1 ) | | ( data . config . N393 > 10 ) )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
memcpy ( & flp - > config , & data . config , sizeof ( struct frad_conf ) ) ;
flp - > config . flags | = SDLA_DIRECT_RECV ;
if ( flp - > type = = SDLA_S508 )
flp - > config . flags | = SDLA_TX70_RX30 ;
if ( dev - > mtu ! = flp - > config . mtu )
{
/* this is required to change the MTU */
dev - > mtu = flp - > config . mtu ;
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > master [ i ] )
flp - > master [ i ] - > mtu = flp - > config . mtu ;
}
flp - > config . mtu + = sizeof ( struct frhdr ) ;
/* off to the races! */
if ( ! flp - > configured )
sdla_start ( dev ) ;
flp - > configured = 1 ;
}
else
{
/* no sense reading if the CPU isn't started */
if ( netif_running ( dev ) )
{
size = sizeof ( data ) ;
if ( sdla_cmd ( dev , SDLA_READ_DLCI_CONFIGURATION , 0 , 0 , NULL , 0 , & data , & size ) ! = SDLA_RET_OK )
2010-09-23 09:40:09 +04:00
return - EIO ;
2005-04-17 02:20:36 +04:00
}
else
if ( flp - > configured )
memcpy ( & data . config , & flp - > config , sizeof ( struct frad_conf ) ) ;
else
memset ( & data . config , 0 , sizeof ( struct frad_conf ) ) ;
memcpy ( & flp - > config , & data . config , sizeof ( struct frad_conf ) ) ;
data . config . flags & = FRAD_VALID_FLAGS ;
data . config . mtu - = data . config . mtu > sizeof ( struct frhdr ) ? sizeof ( struct frhdr ) : data . config . mtu ;
return copy_to_user ( conf , & data . config , sizeof ( struct frad_conf ) ) ? - EFAULT : 0 ;
}
2010-09-23 09:40:09 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int sdla_xfer ( struct net_device * dev , struct sdla_mem __user * info , int read )
{
struct sdla_mem mem ;
char * temp ;
if ( copy_from_user ( & mem , info , sizeof ( mem ) ) )
return - EFAULT ;
if ( read )
{
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
temp = kzalloc ( mem . len , GFP_KERNEL ) ;
2005-04-17 02:20:36 +04:00
if ( ! temp )
2010-09-23 09:40:09 +04:00
return - ENOMEM ;
2005-04-17 02:20:36 +04:00
sdla_read ( dev , mem . addr , temp , mem . len ) ;
if ( copy_to_user ( mem . data , temp , mem . len ) )
{
kfree ( temp ) ;
return - EFAULT ;
}
kfree ( temp ) ;
}
else
{
2010-05-22 02:20:26 +04:00
temp = memdup_user ( mem . data , mem . len ) ;
if ( IS_ERR ( temp ) )
return PTR_ERR ( temp ) ;
2005-04-17 02:20:36 +04:00
sdla_write ( dev , mem . addr , temp , mem . len ) ;
kfree ( temp ) ;
}
2010-09-23 09:40:09 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int sdla_reconfig ( struct net_device * dev )
{
struct frad_local * flp ;
struct conf_data data ;
int i , len ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
len = 0 ;
for ( i = 0 ; i < CONFIG_DLCI_MAX ; i + + )
if ( flp - > dlci [ i ] )
data . dlci [ len + + ] = flp - > dlci [ i ] ;
len * = 2 ;
memcpy ( & data , & flp - > config , sizeof ( struct frad_conf ) ) ;
len + = sizeof ( struct frad_conf ) ;
sdla_cmd ( dev , SDLA_DISABLE_COMMUNICATIONS , 0 , 0 , NULL , 0 , NULL , NULL ) ;
sdla_cmd ( dev , SDLA_SET_DLCI_CONFIGURATION , 0 , 0 , & data , len , NULL , NULL ) ;
sdla_cmd ( dev , SDLA_ENABLE_COMMUNICATIONS , 0 , 0 , NULL , 0 , NULL , NULL ) ;
2010-09-23 09:40:09 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
static int sdla_ioctl ( struct net_device * dev , struct ifreq * ifr , int cmd )
{
struct frad_local * flp ;
if ( ! capable ( CAP_NET_ADMIN ) )
return - EPERM ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( ! flp - > initialized )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
switch ( cmd )
{
case FRAD_GET_CONF :
case FRAD_SET_CONF :
2010-09-23 09:40:09 +04:00
return sdla_config ( dev , ifr - > ifr_data , cmd = = FRAD_GET_CONF ) ;
2005-04-17 02:20:36 +04:00
case SDLA_IDENTIFY :
ifr - > ifr_flags = flp - > type ;
break ;
case SDLA_CPUSPEED :
2010-09-23 09:40:09 +04:00
return sdla_cpuspeed ( dev , ifr ) ;
2005-04-17 02:20:36 +04:00
/* ==========================================================
NOTE : This is rather a useless action right now , as the
current driver does not support protocols other than
FR . However , Sangoma has modules for a number of
other protocols in the works .
= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
case SDLA_PROTOCOL :
if ( flp - > configured )
2010-09-23 09:40:09 +04:00
return - EALREADY ;
2005-04-17 02:20:36 +04:00
switch ( ifr - > ifr_flags )
{
case ARPHRD_FRAD :
dev - > type = ifr - > ifr_flags ;
break ;
default :
2010-09-23 09:40:09 +04:00
return - ENOPROTOOPT ;
2005-04-17 02:20:36 +04:00
}
break ;
case SDLA_CLEARMEM :
sdla_clear ( dev ) ;
break ;
case SDLA_WRITEMEM :
case SDLA_READMEM :
if ( ! capable ( CAP_SYS_RAWIO ) )
return - EPERM ;
2010-09-23 09:40:09 +04:00
return sdla_xfer ( dev , ifr - > ifr_data , cmd = = SDLA_READMEM ) ;
2005-04-17 02:20:36 +04:00
case SDLA_START :
sdla_start ( dev ) ;
break ;
case SDLA_STOP :
sdla_stop ( dev ) ;
break ;
default :
2010-09-23 09:40:09 +04:00
return - EOPNOTSUPP ;
2005-04-17 02:20:36 +04:00
}
2010-09-23 09:40:09 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 10:17:28 +04:00
static int sdla_change_mtu ( struct net_device * dev , int new_mtu )
2005-04-17 02:20:36 +04:00
{
struct frad_local * flp ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( netif_running ( dev ) )
2010-09-23 09:40:09 +04:00
return - EBUSY ;
2005-04-17 02:20:36 +04:00
/* for now, you can't change the MTU! */
2010-09-23 09:40:09 +04:00
return - EOPNOTSUPP ;
2005-04-17 02:20:36 +04:00
}
2005-09-10 10:17:28 +04:00
static int sdla_set_config ( struct net_device * dev , struct ifmap * map )
2005-04-17 02:20:36 +04:00
{
struct frad_local * flp ;
int i ;
char byte ;
unsigned base ;
int err = - EINVAL ;
2008-11-13 10:38:36 +03:00
flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
if ( flp - > initialized )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
2007-10-15 05:37:43 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( valid_port ) ; i + + )
2005-04-17 02:20:36 +04:00
if ( valid_port [ i ] = = map - > base_addr )
break ;
2007-10-15 05:37:43 +04:00
if ( i = = ARRAY_SIZE ( valid_port ) )
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
if ( ! request_region ( map - > base_addr , SDLA_IO_EXTENTS , dev - > name ) ) {
2010-03-24 10:57:36 +03:00
printk ( KERN_WARNING " SDLA: io-port 0x%04lx in use \n " , dev - > base_addr ) ;
2010-09-23 09:40:09 +04:00
return - EINVAL ;
2005-04-17 02:20:36 +04:00
}
base = map - > base_addr ;
/* test for card types, S502A, S502E, S507, S508 */
/* these tests shut down the card completely, so clear the state */
flp - > type = SDLA_UNKNOWN ;
flp - > state = 0 ;
for ( i = 1 ; i < SDLA_IO_EXTENTS ; i + + )
if ( inb ( base + i ) ! = 0xFF )
break ;
if ( i = = SDLA_IO_EXTENTS ) {
outb ( SDLA_HALT , base + SDLA_REG_Z80_CONTROL ) ;
if ( ( inb ( base + SDLA_S502_STS ) & 0x0F ) = = 0x08 ) {
outb ( SDLA_S502E_INTACK , base + SDLA_REG_CONTROL ) ;
if ( ( inb ( base + SDLA_S502_STS ) & 0x0F ) = = 0x0C ) {
outb ( SDLA_HALT , base + SDLA_REG_CONTROL ) ;
flp - > type = SDLA_S502E ;
goto got_type ;
}
}
}
for ( byte = inb ( base ) , i = 0 ; i < SDLA_IO_EXTENTS ; i + + )
if ( inb ( base + i ) ! = byte )
break ;
if ( i = = SDLA_IO_EXTENTS ) {
outb ( SDLA_HALT , base + SDLA_REG_CONTROL ) ;
if ( ( inb ( base + SDLA_S502_STS ) & 0x7E ) = = 0x30 ) {
outb ( SDLA_S507_ENABLE , base + SDLA_REG_CONTROL ) ;
if ( ( inb ( base + SDLA_S502_STS ) & 0x7E ) = = 0x32 ) {
outb ( SDLA_HALT , base + SDLA_REG_CONTROL ) ;
flp - > type = SDLA_S507 ;
goto got_type ;
}
}
}
outb ( SDLA_HALT , base + SDLA_REG_CONTROL ) ;
if ( ( inb ( base + SDLA_S508_STS ) & 0x3F ) = = 0x00 ) {
outb ( SDLA_S508_INTEN , base + SDLA_REG_CONTROL ) ;
if ( ( inb ( base + SDLA_S508_STS ) & 0x3F ) = = 0x10 ) {
outb ( SDLA_HALT , base + SDLA_REG_CONTROL ) ;
flp - > type = SDLA_S508 ;
goto got_type ;
}
}
outb ( SDLA_S502A_HALT , base + SDLA_REG_CONTROL ) ;
if ( inb ( base + SDLA_S502_STS ) = = 0x40 ) {
outb ( SDLA_S502A_START , base + SDLA_REG_CONTROL ) ;
if ( inb ( base + SDLA_S502_STS ) = = 0x40 ) {
outb ( SDLA_S502A_INTEN , base + SDLA_REG_CONTROL ) ;
if ( inb ( base + SDLA_S502_STS ) = = 0x44 ) {
outb ( SDLA_S502A_START , base + SDLA_REG_CONTROL ) ;
flp - > type = SDLA_S502A ;
goto got_type ;
}
}
}
printk ( KERN_NOTICE " %s: Unknown card type \n " , dev - > name ) ;
err = - ENODEV ;
goto fail ;
got_type :
switch ( base ) {
case 0x270 :
case 0x280 :
case 0x380 :
case 0x390 :
if ( flp - > type ! = SDLA_S508 & & flp - > type ! = SDLA_S507 )
goto fail ;
}
switch ( map - > irq ) {
case 2 :
if ( flp - > type ! = SDLA_S502E )
goto fail ;
break ;
case 10 :
case 11 :
case 12 :
case 15 :
case 4 :
if ( flp - > type ! = SDLA_S508 & & flp - > type ! = SDLA_S507 )
goto fail ;
break ;
case 3 :
case 5 :
case 7 :
if ( flp - > type = = SDLA_S502A )
goto fail ;
break ;
default :
goto fail ;
}
err = - EAGAIN ;
2009-11-19 10:29:17 +03:00
if ( request_irq ( dev - > irq , sdla_isr , 0 , dev - > name , dev ) )
2005-04-17 02:20:36 +04:00
goto fail ;
if ( flp - > type = = SDLA_S507 ) {
switch ( dev - > irq ) {
case 3 :
flp - > state = SDLA_S507_IRQ3 ;
break ;
case 4 :
flp - > state = SDLA_S507_IRQ4 ;
break ;
case 5 :
flp - > state = SDLA_S507_IRQ5 ;
break ;
case 7 :
flp - > state = SDLA_S507_IRQ7 ;
break ;
case 10 :
flp - > state = SDLA_S507_IRQ10 ;
break ;
case 11 :
flp - > state = SDLA_S507_IRQ11 ;
break ;
case 12 :
flp - > state = SDLA_S507_IRQ12 ;
break ;
case 15 :
flp - > state = SDLA_S507_IRQ15 ;
break ;
}
}
2007-10-15 05:37:43 +04:00
for ( i = 0 ; i < ARRAY_SIZE ( valid_mem ) ; i + + )
2005-04-17 02:20:36 +04:00
if ( valid_mem [ i ] = = map - > mem_start )
break ;
err = - EINVAL ;
2007-10-15 05:37:43 +04:00
if ( i = = ARRAY_SIZE ( valid_mem ) )
2005-04-17 02:20:36 +04:00
goto fail2 ;
if ( flp - > type = = SDLA_S502A & & ( map - > mem_start & 0xF000 ) > > 12 = = 0x0E )
goto fail2 ;
if ( flp - > type ! = SDLA_S507 & & map - > mem_start > > 16 = = 0x0B )
goto fail2 ;
if ( flp - > type = = SDLA_S507 & & map - > mem_start > > 16 = = 0x0D )
goto fail2 ;
byte = flp - > type ! = SDLA_S508 ? SDLA_8K_WINDOW : 0 ;
byte | = ( map - > mem_start & 0xF000 ) > > ( 12 + ( flp - > type = = SDLA_S508 ? 1 : 0 ) ) ;
switch ( flp - > type ) {
case SDLA_S502A :
case SDLA_S502E :
switch ( map - > mem_start > > 16 ) {
case 0x0A :
byte | = SDLA_S502_SEG_A ;
break ;
case 0x0C :
byte | = SDLA_S502_SEG_C ;
break ;
case 0x0D :
byte | = SDLA_S502_SEG_D ;
break ;
case 0x0E :
byte | = SDLA_S502_SEG_E ;
break ;
}
break ;
case SDLA_S507 :
switch ( map - > mem_start > > 16 ) {
case 0x0A :
byte | = SDLA_S507_SEG_A ;
break ;
case 0x0B :
byte | = SDLA_S507_SEG_B ;
break ;
case 0x0C :
byte | = SDLA_S507_SEG_C ;
break ;
case 0x0E :
byte | = SDLA_S507_SEG_E ;
break ;
}
break ;
case SDLA_S508 :
switch ( map - > mem_start > > 16 ) {
case 0x0A :
byte | = SDLA_S508_SEG_A ;
break ;
case 0x0C :
byte | = SDLA_S508_SEG_C ;
break ;
case 0x0D :
byte | = SDLA_S508_SEG_D ;
break ;
case 0x0E :
byte | = SDLA_S508_SEG_E ;
break ;
}
break ;
}
/* set the memory bits, and enable access */
outb ( byte , base + SDLA_REG_PC_WINDOW ) ;
switch ( flp - > type )
{
case SDLA_S502E :
flp - > state = SDLA_S502E_ENABLE ;
break ;
case SDLA_S507 :
flp - > state | = SDLA_MEMEN ;
break ;
case SDLA_S508 :
flp - > state = SDLA_MEMEN ;
break ;
}
outb ( flp - > state , base + SDLA_REG_CONTROL ) ;
dev - > irq = map - > irq ;
dev - > base_addr = base ;
dev - > mem_start = map - > mem_start ;
dev - > mem_end = dev - > mem_start + 0x2000 ;
flp - > initialized = 1 ;
return 0 ;
fail2 :
free_irq ( map - > irq , dev ) ;
fail :
release_region ( base , SDLA_IO_EXTENTS ) ;
return err ;
}
2009-03-26 18:11:25 +03:00
static const struct net_device_ops sdla_netdev_ops = {
. ndo_open = sdla_open ,
. ndo_stop = sdla_close ,
. ndo_do_ioctl = sdla_ioctl ,
. ndo_set_config = sdla_set_config ,
. ndo_start_xmit = sdla_transmit ,
. ndo_change_mtu = sdla_change_mtu ,
} ;
2005-04-17 02:20:36 +04:00
static void setup_sdla ( struct net_device * dev )
{
2008-11-13 10:38:36 +03:00
struct frad_local * flp = netdev_priv ( dev ) ;
2005-04-17 02:20:36 +04:00
netdev_boot_setup_check ( dev ) ;
2009-03-26 18:11:25 +03:00
dev - > netdev_ops = & sdla_netdev_ops ;
2005-04-17 02:20:36 +04:00
dev - > flags = 0 ;
dev - > type = 0xFFFF ;
dev - > hard_header_len = 0 ;
dev - > addr_len = 0 ;
dev - > mtu = SDLA_MAX_MTU ;
flp - > activate = sdla_activate ;
flp - > deactivate = sdla_deactivate ;
flp - > assoc = sdla_assoc ;
flp - > deassoc = sdla_deassoc ;
flp - > dlci_conf = sdla_dlci_conf ;
init_timer ( & flp - > timer ) ;
flp - > timer . expires = 1 ;
flp - > timer . data = ( unsigned long ) dev ;
flp - > timer . function = sdla_poll ;
}
static struct net_device * sdla ;
static int __init init_sdla ( void )
{
int err ;
printk ( " %s. \n " , version ) ;
sdla = alloc_netdev ( sizeof ( struct frad_local ) , " sdla0 " , setup_sdla ) ;
if ( ! sdla )
return - ENOMEM ;
err = register_netdev ( sdla ) ;
if ( err )
free_netdev ( sdla ) ;
return err ;
}
static void __exit exit_sdla ( void )
{
2008-11-13 10:38:36 +03:00
struct frad_local * flp = netdev_priv ( sdla ) ;
2005-04-17 02:20:36 +04:00
unregister_netdev ( sdla ) ;
if ( flp - > initialized ) {
free_irq ( sdla - > irq , sdla ) ;
release_region ( sdla - > base_addr , SDLA_IO_EXTENTS ) ;
}
del_timer_sync ( & flp - > timer ) ;
free_netdev ( sdla ) ;
}
MODULE_LICENSE ( " GPL " ) ;
module_init ( init_sdla ) ;
module_exit ( exit_sdla ) ;