wanpipe/patches/kdrivers/src/net/sdla_bitstrm.c

5727 lines
150 KiB
C

/*****************************************************************************
* sdla_bitstrm.c WANPIPE(tm) Multiprotocol WAN Link Driver. Bit Stream module.
*
* Authors: Nenad Corbic <ncorbic@sangoma.com>
* Gideon Hack
*
* Copyright: (c) 1995-2004 Sangoma Technologies Inc.
*
* 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.
* ============================================================================
*
* Jan 03, 2004 David Rokhvarg Added new IOCTL calls for the "lineprobe".
* Aug 10, 2002 Nenad Corbic New bitstreaming code
* Sep 20, 2001 Nenad Corbic The min() function has changed for 2.4.9
* kernel. Thus using the wp_min() defined in
* wanpipe.h
* Aug 14, 2001 Nenad Corbic Inital version, based on Chdlc module.
* Using Gideons new bitstreaming firmware.
*****************************************************************************/
#include <linux/wanpipe_includes.h>
#include <linux/wanpipe_defines.h>
#include <linux/wanrouter.h> /* WAN router definitions */
#include <linux/wanpipe.h> /* WANPIPE common user API definitions */
#include <linux/sdlapci.h>
#include <linux/sdla_bitstrm.h> /* BSTRM firmware API definitions */
#include <linux/if_wanpipe_common.h> /* Socket Driver common area */
#include <linux/if_wanpipe.h>
#include <linux/wanproc.h>
#include <linux/wanpipe_syncppp.h>
/****** Defines & Macros ****************************************************/
/* reasons for enabling the timer interrupt on the adapter */
#define TMR_INT_ENABLED_UDP 0x01
#define TMR_INT_ENABLED_UPDATE 0x02
#define TMR_INT_ENABLED_CONFIG 0x10
#define TMR_INT_ENABLED_TE 0x20
#define MAX_IP_ERRORS 10
#define BSTRM_DFLT_DATA_LEN 1500 /* default MTU */
#define BSTRM_HDR_LEN 1
#define BSTRM_API 0x01
#define PORT(x) (x == 0 ? "PRIMARY" : "SECONDARY" )
#define MAX_BH_BUFF 200
#undef PRINT_DEBUG
#ifdef PRINT_DEBUG
#define dbg_printk(format, a...) printk(format, ## a)
#else
#define dbg_printk(format, a...)
#endif
#define INC_CRC_CNT(a) if (++a >= MAX_CRC_QUEUE) a=0;
#define GET_FIN_CRC_CNT(a) { if (--a < 0) a=MAX_CRC_QUEUE-1; \
if (--a < 0) a=MAX_CRC_QUEUE-1; }
#define FLIP_CRC(a,b) { b=0; \
b |= (a&0x000F)<<12 ; \
b |= (a&0x00F0) << 4; \
b |= (a&0x0F00) >> 4; \
b |= (a&0xF000) >> 12; }
#define DECODE_CRC(a) { a=( (((~a)&0x000F)<<4) | \
(((~a)&0x00F0)>>4) | \
(((~a)&0x0F00)<<4) | \
(((~a)&0xF000)>>4) ); }
#define BITSINBYTE 8
#define MAX_CRC_QUEUE 3
#define NO_FLAG 0
#define OPEN_FLAG 1
#define CLOSING_FLAG 2
#define HDLC_ENCODE 0
#define HDLC_ENCODE_IDLE_UPDATE 0
#define HDLC_DECODE 0
#define MAX_TX_QUEUE_SIZE 50
#define MAX_RX_FREE_SKB 10
#define MAX_MTU_SIZE 1600
#define MAX_CHAN_TX_UP_SIZE 1200
#define MAX_T1_CHAN_TX_UP_SIZE 50*NUM_OF_T1_CHANNELS //1200 bytes
#define MAX_E1_CHAN_TX_UP_SIZE 40*(NUM_OF_E1_CHANNELS-1) //1240 bytes
#define MAX_E1_UNFRM_CHAN_TX_UP_SIZE 40*(NUM_OF_E1_CHANNELS) //1240 bytes
//(MAX_MTU_SIZE-100)
#define SWITCH_TX_UP_DFLT 240*3
//Max Rx Pkt
#define TX_QUEUE_LOW (MAX_TX_QUEUE_SIZE*1/10)
#define TX_QUEUE_MID (MAX_TX_QUEUE_SIZE*5/10)
#define TX_QUEUE_HIGH (MAX_TX_QUEUE_SIZE*9/10)
#define TX_BH_CRIT 1
#define RX_BH_CRIT 0
#define TX_IDLE_FLAG 0x04
#define BRD_IDLE_FLAG 0x02
#define QUEUE_SYNC 0
#define QUEUE_LOW 1
#define QUEUE_HIGH 2
/* chan->tq_control fileds */
#define WAIT_DEVICE_BUFFERS 0
#define WAIT_DEVICE_FAST 1
#define WAIT_DEVICE_SLOW 2
atomic_t intr_cnt;
atomic_t intr_skip;
atomic_t tx_data;
atomic_t rx_data;
#define HDLC_ENG_BUF_LEN 5000
#if 0
# define HDLC_IDLE_ABORT 1
#else
# undef HDLC_IDLE_ABORT
#endif
/******Data Structures*****************************************************/
/* This structure is placed in the private data area of the device structure.
* The card structure used to occupy the private area but now the following
* structure will incorporate the card structure along with BSTRM specific data
*/
typedef struct bitstrm_private_area
{
wanpipe_common_t common;
sdla_t *card;
// netdevice_t *dev;
char if_name[WAN_IFNAME_SZ+1];
unsigned long router_start_time;
unsigned long router_up_time;
unsigned long tick_counter; /* For 5s timeout counter */
u8 config_bstrm;
unsigned char mc; /* Mulitcast support on/off */
char udp_pkt_src;
char update_comms_stats; /* updating comms stats */
u8 true_if_encoding;
unsigned char rx_decode_buf[HDLC_ENG_BUF_LEN];
unsigned int rx_decode_len;
unsigned char rx_decode_bit_cnt;
unsigned char rx_decode_onecnt;
unsigned char tx_decode_buf[HDLC_ENG_BUF_LEN];
unsigned int tx_decode_len;
unsigned char tx_decode_bit_cnt;
unsigned char tx_decode_onecnt;
unsigned long hdlc_flag;
unsigned short rx_orig_crc;
unsigned short rx_crc[MAX_CRC_QUEUE];
unsigned short crc_fin;
unsigned short tx_crc_fin;
unsigned short rx_crc_tmp;
unsigned short tx_crc_tmp;
int crc_cur;
int crc_prv;
unsigned short tx_crc;
unsigned char tx_flag;
unsigned char tx_flag_offset;
unsigned char tx_flag_offset_data;
unsigned char tx_flag_idle;
struct sk_buff_head rx_free_queue;
struct sk_buff_head rx_used_queue;
struct sk_buff_head tx_queue;
unsigned long time_slot_map;
unsigned int time_slots;
struct sk_buff *rx_skb;
struct sk_buff *tx_skb;
unsigned long rx_timeout;
unsigned short rx_max_timeout;
unsigned char tx_idle_flag;
struct net_device_stats ifstats;
netdevice_t *sw_dev;
unsigned char sw_if_name[WAN_IFNAME_SZ+1];
unsigned int max_tx_up_size;
unsigned long tq_control;
unsigned char hdlc_eng;
unsigned short max_tx_queue_sz;
unsigned char ignore_modem;
unsigned int protocol;
unsigned char udp_pkt_data[sizeof(wan_udp_pkt_t)+10];
atomic_t udp_pkt_len;
unsigned char seven_bit_hdlc;
unsigned char bits_in_byte;
unsigned char debug_stream;
unsigned char debug_stream_1;
unsigned char debug_char;
wan_bitstrm_conf_if_t cfg;
unsigned char rbs_on;
unsigned char rbs_chan;
unsigned char rbs_sig;
//FIXME: add driver stats as per frame relay!
} bitstrm_private_area_t;
/* Route Status options */
#define NO_ROUTE 0x00
#define ADD_ROUTE 0x01
#define ROUTE_ADDED 0x02
#define REMOVE_ROUTE 0x03
/* variable for tracking how many interfaces to open for WANPIPE on the
two ports */
extern void disable_irq(unsigned int);
extern void enable_irq(unsigned int);
/****** Function Prototypes *************************************************/
/* WAN link driver entry points. These are called by the WAN router module. */
static int update (wan_device_t* wandev);
static int new_if (wan_device_t* wandev, netdevice_t* dev,
wanif_conf_t* conf);
static int del_if(wan_device_t *wandev, netdevice_t *dev);
/* Network device interface */
static int if_init (netdevice_t* dev);
static int if_open (netdevice_t* dev);
static int if_close (netdevice_t* dev);
static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd);
static struct net_device_stats* if_stats (netdevice_t* dev);
static int if_send (struct sk_buff* skb, netdevice_t* dev);
/* BSTRM Firmware interface functions */
static int bstrm_configure (sdla_t* card, void* data);
static int bstrm_comm_enable (sdla_t* card);
static int bstrm_read_version (sdla_t* card, char* str);
static int bstrm_set_intr_mode (sdla_t* card, unsigned mode);
static int set_adapter_config (sdla_t* card);
static int bstrm_send (sdla_t* card, void* data, unsigned len, unsigned char flag);
static int bstrm_read_comm_err_stats (sdla_t* card);
static int bstrm_read_op_stats (sdla_t* card);
static int bstrm_error (sdla_t *card, int err, wan_mbox_t *mb);
static int bstrm_disable_comm_shutdown (sdla_t *card);
static void if_tx_timeout (netdevice_t *dev);
/* Miscellaneous BSTRM Functions */
static int set_bstrm_config (sdla_t* card);
static void init_bstrm_tx_rx_buff( sdla_t* card);
static int process_bstrm_exception(sdla_t *card);
static int process_global_exception(sdla_t *card);
static int update_comms_stats(sdla_t* card,
bitstrm_private_area_t* bstrm_priv_area);
static void port_set_state (sdla_t *card, int);
static int config_bstrm (sdla_t *card);
static void disable_comm (sdla_t *card);
static int bstrm_comm_disable (sdla_t *card);
static int bstrm_set_FE_config (sdla_t *card);
/* Interrupt handlers */
static WAN_IRQ_RETVAL wpbit_isr (sdla_t* card);
static void rx_intr (sdla_t* card);
static void timer_intr(sdla_t *);
/* Bottom half handlers */
static void bstrm_rx_bh (unsigned long data);
static void bstrm_tx_bh (unsigned long data);
static int bstrm_bh_cleanup (sdla_t *card, struct sk_buff *skb);
static struct sk_buff * bh_enqueue (sdla_t *card);
/* Miscellaneous functions */
static int intr_test( sdla_t* card);
static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev,
bitstrm_private_area_t* bstrm_priv_area,
char local);
/* Bitstream decoding functions */
static void init_crc(void);
static void calc_rx_crc(bitstrm_private_area_t *chan);
static void calc_tx_crc(bitstrm_private_area_t *chan, unsigned char byte);
static void decode_byte (bitstrm_private_area_t *chan, unsigned char *byte);
static void hdlc_decode (bitstrm_private_area_t *chan, unsigned char *buf, int len);
static void tx_up_decode_pkt(bitstrm_private_area_t *chan);
static void init_rx_hdlc_eng(sdla_t *card, bitstrm_private_area_t *chan, int hard);
static int hdlc_encode(bitstrm_private_area_t *chan,struct sk_buff **skb);
static void encode_byte (bitstrm_private_area_t *chan, unsigned char *byte, int flag);
static int bstrm_get_config_info(void* priv, struct seq_file* m, int*);
static void
wanpipe_switch_datascope_tx_up(bitstrm_private_area_t *chan,struct sk_buff *skb);
/* TE1 */
static WRITE_FRONT_END_REG_T write_front_end_reg;
static READ_FRONT_END_REG_T read_front_end_reg;
static void bstrm_enable_timer (void* card_id);
static void bstrm_handle_front_end_state(void* card_id);
static int bstrm_bh_data_tx_up(sdla_t *card, struct sk_buff *skb, bitstrm_private_area_t * chan);
static void bstrm_switch_send(sdla_t *card, bitstrm_private_area_t * chan, struct sk_buff *skb);
static int bstrm_bind_dev_switch (sdla_t *card, bitstrm_private_area_t *chan, char *sw_dev_name);
static int bstrm_unbind_dev_switch (sdla_t *card, bitstrm_private_area_t *chan);
static int protocol_init (sdla_t*card,netdevice_t *dev,
bitstrm_private_area_t*chan,
wanif_conf_t* conf);
static int protocol_stop (sdla_t *card, netdevice_t *dev);
static int protocol_start (sdla_t *card, netdevice_t *dev);
static int protocol_shutdown (sdla_t *card, netdevice_t *dev);
static void send_ppp_term_request (netdevice_t *dev);
static int bstrm_set_te_signaling_config (void* card_id,unsigned long ts_sig_map);
static int bstrm_disable_te_signaling (void* card,unsigned long);
static int bstrm_read_te_signaling_config (void* card);
static int send_rbs_oob_msg (sdla_t *card, bitstrm_private_area_t *chan);
#define LINEPROBE
#ifdef LINEPROBE
static int api_enable_comms(sdla_t * card);
static int api_disable_comms(sdla_t* card);
static int setup_api_timeslots(sdla_t* card);
#endif
const int MagicNums[8] = { 0x1189, 0x2312, 0x4624, 0x8C48, 0x1081, 0x2102, 0x4204, 0x8408 };
unsigned short CRC_TABLE[256];
const char FLAG[]={ 0x7E, 0xFC, 0xF9, 0xF3, 0xE7, 0xCF, 0x9F, 0x3F };
/****** Public Functions ****************************************************/
/*============================================================================
* Cisco HDLC protocol initialization routine.
*
* This routine is called by the main WANPIPE module during setup. At this
* point adapter is completely initialized and firmware is running.
* o read firmware version (to make sure it's alive)
* o configure adapter
* o initialize protocol-specific fields of the adapter data space.
*
* Return: 0 o.k.
* < 0 failure.
*/
int wpbit_init (sdla_t* card, wandev_conf_t* conf)
{
unsigned char port_num;
int i,err;
struct sk_buff *skb;
unsigned long max_permitted_baud = 0;
unsigned long smp_flags;
union
{
char str[80];
} u;
volatile wan_mbox_t* mb;
wan_mbox_t* mb1;
unsigned long timeout;
/* Verify configuration ID */
if (conf->config_id != WANCONFIG_BITSTRM) {
DEBUG_EVENT( "%s: invalid configuration ID %u!\n",
card->devname, conf->config_id);
return -EINVAL;
}
/* Find out which Port to use */
if ((conf->comm_port == WANOPT_PRI) || (conf->comm_port == WANOPT_SEC)){
if (card->next){
if (conf->comm_port != card->next->u.b.comm_port){
card->u.b.comm_port = conf->comm_port;
}else{
DEBUG_EVENT( "%s: ERROR - %s port used!\n",
card->wandev.name, PORT(conf->comm_port));
return -EINVAL;
}
}else{
card->u.b.comm_port = conf->comm_port;
}
}else{
DEBUG_EVENT( "%s: ERROR - Invalid Port Selected!\n",
card->wandev.name);
return -EINVAL;
}
/* Initialize protocol-specific fields */
if (card->type != SDLA_S514){
DEBUG_EVENT( "%s: ERROR - T1/E1 Bitstrm doesn't support S508 cards!\n",
card->devname);
return -EOPNOTSUPP;
}else{
/* for a S514 adapter, set a pointer to the actual mailbox in the */
/* allocated virtual memory area */
if (card->u.b.comm_port == WANOPT_PRI){
card->mbox_off = PRI_BASE_ADDR_MB_STRUCT;
}else{
card->mbox_off = SEC_BASE_ADDR_MB_STRUCT;
}
}
mb = &card->wan_mbox;
mb1 = &card->wan_mbox;
if (!card->configured){
unsigned char return_code = 0x00;
/* The board will place an 'I' in the return code to indicate that it is
ready to accept commands. We expect this to be completed in less
than 1 second. */
timeout = jiffies;
do {
return_code = 0x00;
card->hw_iface.peek(card->hw,
card->mbox_off+offsetof(wan_mbox_t, wan_return_code),
&return_code,
sizeof(unsigned char));
if ((jiffies - timeout) > 1*HZ) break;
}while(return_code != 'I');
if (return_code != 'I') {
DEBUG_EVENT(
"%s: Initialization not completed by adapter\n",
card->devname);
DEBUG_EVENT( "Please contact Sangoma representative.\n");
return -EIO;
}
}
card->wandev.ignore_front_end_status = conf->ignore_front_end_status;
//ALEX_TODAY err=check_conf_hw_mismatch(card,conf->te_cfg.media);
err = (card->hw_iface.check_mismatch) ?
card->hw_iface.check_mismatch(card->hw,conf->fe_cfg.media) : -EINVAL;
if (err){
return err;
}
card->u.b.serial=0;
if (IS_TE1_MEDIA(&conf->fe_cfg)){
memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t));
sdla_te_iface_init(&card->wandev.fe_iface);
card->fe.name = card->devname;
card->fe.card = card;
card->fe.write_fe_reg = write_front_end_reg;
card->fe.read_fe_reg = read_front_end_reg;
card->wandev.fe_enable_timer = bstrm_enable_timer;
card->wandev.te_link_state = bstrm_handle_front_end_state;
conf->interface =
(IS_T1_CARD(card)) ? WANOPT_V35 : WANOPT_RS232;
if (card->u.b.comm_port == WANOPT_PRI){
conf->clocking = WANOPT_EXTERNAL;
}
if (IS_FR_FEUNFRAMED(&card->fe)){
card->u.b.serial=1;
}
DEBUG_EVENT("%s: Config Media = %s\n",
card->devname, FE_MEDIA_DECODE(&card->fe));
}else if (IS_56K_MEDIA(&conf->fe_cfg)){
memcpy(&card->fe.fe_cfg, &conf->fe_cfg, sizeof(sdla_fe_cfg_t));
sdla_56k_iface_init(&card->wandev.fe_iface);
card->fe.name = card->devname;
card->fe.card = card;
card->fe.write_fe_reg = write_front_end_reg;
card->fe.read_fe_reg = read_front_end_reg;
if (card->u.c.comm_port == WANOPT_PRI){
conf->clocking = WANOPT_EXTERNAL;
}
card->u.b.serial=1;
DEBUG_EVENT("%s: Config Media = %s\n",
card->devname, FE_MEDIA_DECODE(&card->fe));
}else{
card->u.b.serial=1;
/* FIXME: Remove this line */
card->fe.fe_status = FE_CONNECTED;
DEBUG_EVENT("%s: Config Media = Unknown\n",
card->devname);
}
if (card->u.b.serial){
DEBUG_EVENT("%s: Configuring Driver for Serial Mode!\n",
card->devname);
}
/* Read firmware version. Note that when adapter initializes, it
* clears the mailbox, so it may appear that the first command was
* executed successfully when in fact it was merely erased. To work
* around this, we execute the first command twice.
*/
if (bstrm_read_version(card, u.str))
return -EIO;
DEBUG_EVENT( "%s: Running Bit Streaming firmware v%s\n",
card->devname, u.str);
if (set_adapter_config(card)) {
DEBUG_EVENT( "%s: Failed to set adapter type!\n",
card->devname);
return -EIO;
}
card->isr = &wpbit_isr;
card->poll = NULL;
card->exec = NULL;
card->wandev.update = &update;
card->wandev.new_if = &new_if;
card->wandev.del_if = &del_if;
card->wandev.udp_port = conf->udp_port;
card->wandev.new_if_cnt = 0;
// Proc fs functions
card->wandev.get_config_info = &bstrm_get_config_info;
/* Initialize Bit Stream Configuration */
memcpy(&card->u.b.cfg,&conf->u.bitstrm,sizeof(wan_bitstrm_conf_t));
#if 0
card->u.b.sync_options = conf->sync_options;
card->u.b.cfg.rx_sync_char = conf->rx_sync_char;
card->u.b.cfg.monosync_tx_time_fill_char = conf->monosync_tx_time_fill_char;
card->u.b.cfg.max_length_tx_data_block = conf->max_length_tx_data_block;
card->u.b.cfg.rx_complete_length = conf->rx_complete_length;
card->u.b.cfg.rx_complete_timer = conf->rx_complete_timer;
#endif
/* reset the number of times the 'update()' proc has been called */
card->u.b.update_call_count = 0;
card->wandev.ttl = conf->ttl;
card->wandev.interface = conf->interface;
card->wandev.clocking = conf->clocking;
port_num = card->u.b.comm_port;
/* Setup Port Bps */
if(card->wandev.clocking) {
if(port_num == WANOPT_PRI) {
/* For Primary Port 0 */
max_permitted_baud =
(card->type == SDLA_S514) ?
PRI_MAX_BAUD_RATE_S514 :
PRI_MAX_BAUD_RATE_S508;
}else if(port_num == WANOPT_SEC) {
/* For Secondary Port 1 */
max_permitted_baud =
(card->type == SDLA_S514) ?
SEC_MAX_BAUD_RATE_S514 :
SEC_MAX_BAUD_RATE_S508;
}
if(conf->bps > max_permitted_baud) {
conf->bps = max_permitted_baud;
DEBUG_EVENT( "%s: Baud too high!\n",
card->wandev.name);
DEBUG_EVENT( "%s: Baud rate set to %lu bps\n",
card->wandev.name, max_permitted_baud);
}
card->wandev.bps = conf->bps;
}else{
card->wandev.bps = 0;
}
/* Setup the Port MTU */
if(port_num == WANOPT_PRI) {
/* For Primary Port 0 */
card->wandev.mtu = wp_min(conf->mtu, PRI_MAX_LENGTH_TX_DATA_BLOCK);
} else if(port_num == WANOPT_SEC) {
/* For Secondary Port 1 */
card->wandev.mtu = wp_min(conf->mtu, SEC_MAX_LENGTH_TX_DATA_BLOCK);
}
/* Set up the interrupt status area */
/* Read the BSTRM Configuration and obtain:
* Ptr to shared memory infor struct
* Use this pointer to calculate the value of card->u.b.flags !
*/
mb1->wan_data_len = 0;
mb1->wan_command = READ_BSTRM_CONFIGURATION;
err = card->hw_iface.cmd(card->hw, card->mbox_off, mb1);
if(err != OK) {
bstrm_error(card, err, mb1);
return -EIO;
}
card->flags_off =
(((BSTRM_CONFIGURATION_STRUCT *)mb1->wan_data)->
ptr_shared_mem_info_struct);
card->intr_type_off =
card->flags_off +
offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) +
offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_type);
card->intr_perm_off =
card->flags_off +
offsetof(SHARED_MEMORY_INFO_STRUCT, interrupt_info_struct) +
offsetof(INTERRUPT_INFORMATION_STRUCT, interrupt_permission);
card->fe_status_off =
card->flags_off +
offsetof(SHARED_MEMORY_INFO_STRUCT, FT1_info_struct) +
offsetof(FT1_INFORMATION_STRUCT, parallel_port_A_input);
card->u.b.rx_discard_off =
card->flags_off +
offsetof(SHARED_MEMORY_INFO_STRUCT, BSTRM_info_struct) +
offsetof(BSTRM_INFORMATION_STRUCT, Rx_discard_count);
card->u.b.tx_idle_off =
card->flags_off +
offsetof(SHARED_MEMORY_INFO_STRUCT, BSTRM_info_struct) +
offsetof(BSTRM_INFORMATION_STRUCT, Tx_idle_count);
if (!card->wandev.piggyback){
int err;
/* This is for the ports link state */
card->wandev.state = WAN_DUALPORT;
card->u.b.state = WAN_DISCONNECTED;
/* Perform interrupt testing */
err = intr_test(card);
if(err || (card->timer_int_enabled == 0 /* MAX_INTR_TEST_COUNTER*/)) {
DEBUG_EVENT( "%s: Interrupt test failed (%i)\n",
card->devname, card->timer_int_enabled);
DEBUG_EVENT( "%s: Please choose another interrupt\n",
card->devname);
return -EIO;
}
DEBUG_EVENT( "%s: Interrupt test passed (%i)\n",
card->devname, card->timer_int_enabled);
card->configured = 1;
}
/* If we are using BSTRM in backup mode, this flag will
* indicate not to look for IP addresses in config_bstrm()*/
card->backup = conf->backup;
DEBUG_EVENT( "%s: Initializing CRC tables\n",card->devname);
init_crc();
card->u.b.tq_working=0;
/* Allocate and initialize BH circular buffer */
/* Add 1 to MAX_BH_BUFF so we don't have test with (MAX_BH_BUFF-1) */
skb_queue_head_init(&card->u.b.rx_isr_queue);
skb_queue_head_init(&card->u.b.rx_isr_free_queue);
memset(card->u.b.time_slot_map,0,sizeof(card->u.b.time_slot_map));
card->u.b.time_slots=NUM_OF_T1_CHANNELS;
if (IS_E1_CARD(card)){
card->u.b.time_slots=NUM_OF_E1_CHANNELS;
}
if (IS_TE1_MEDIA(&conf->fe_cfg)){
int tx_time_slots=card->u.b.time_slots;
if (IS_E1_CARD(card) && !IS_FR_FEUNFRAMED(&card->fe) && card->u.b.time_slots == 32){
tx_time_slots=31;
}
if (card->u.b.cfg.max_length_tx_data_block % tx_time_slots){
DEBUG_EVENT( "\n");
DEBUG_EVENT( "%s: Cfg max_length_tx_data_block : %d, time_slots: %d\n",
card->devname,
card->u.b.cfg.max_length_tx_data_block,
tx_time_slots);
card->u.b.cfg.max_length_tx_data_block-=
(card->u.b.cfg.max_length_tx_data_block%
tx_time_slots);
card->u.b.cfg.max_length_tx_data_block+=tx_time_slots;
#if 0
DEBUG_EVENT( "%s: Error: Max tx data block %i not multiple of channels %i\n",
card->devname,card->u.b.cfg.max_length_tx_data_block,
card->u.b.time_slots);
bstrm_skb_queue_purge(&card->u.b.rx_isr_free_queue);
return -EINVAL;
#else
DEBUG_EVENT( "%s: Warning: Adjusting max tx block to %i\n",
card->devname,card->u.b.cfg.max_length_tx_data_block);
#endif
}
if (card->u.b.cfg.rx_complete_length % card->u.b.time_slots){
DEBUG_EVENT( "%s: Cfg rx_complete_length : %d, time_slots: %d\n",
card->devname,
card->u.b.cfg.rx_complete_length,
card->u.b.time_slots);
card->u.b.cfg.rx_complete_length-=
(card->u.b.cfg.rx_complete_length%
card->u.b.time_slots);
card->u.b.cfg.rx_complete_length+=card->u.b.time_slots;
DEBUG_EVENT( "%s: Warning: Adjusting max rx block to %i\n",
card->devname,card->u.b.cfg.rx_complete_length);
}
if (card->u.b.cfg.max_length_tx_data_block >= MAX_E1_CHANNELS*50){
DEBUG_EVENT("%s: Error: Tx data block exceeds max=%i\n",
card->devname,MAX_E1_CHANNELS*50);
return -EINVAL;
}
}
card->u.b.tx_chan_multiple=
card->u.b.cfg.max_length_tx_data_block/card->u.b.time_slots;
DEBUG_EVENT( "\n");
DEBUG_EVENT( "%s: Configuring: \n",card->devname);
if (IS_TE1_CARD(card)){
DEBUG_EVENT( "%s: ChanNum =%i\n",
card->devname, card->u.b.time_slots);
DEBUG_EVENT( "%s: TxChanMult =%i\n",
card->devname, card->u.b.tx_chan_multiple);
}
DEBUG_EVENT( "%s: TxMTU =%i\n",
card->devname, card->u.b.cfg.max_length_tx_data_block);
DEBUG_EVENT( "%s: RxMTU =%i\n",
card->devname, card->u.b.cfg.rx_complete_length);
DEBUG_EVENT( "%s: IdleFlag =0x%x\n",
card->devname,
card->u.b.cfg.monosync_tx_time_fill_char);
/* RBS Map only supports 24 T1 channels */
card->u.b.cfg.rbs_map&=0x00FFFFFF;
if (IS_T1_CARD(card)){
DEBUG_EVENT( "%s: RBS Control =%s Map=0x%08X\n",
card->devname,
card->u.b.cfg.rbs_map?
"ON":"OFF",card->u.b.cfg.rbs_map);
}else{
if (card->u.b.cfg.rbs_map){
DEBUG_EVENT("\n");
DEBUG_EVENT("%s: Warning: Robbit only supported on T1!\n",
card->devname);
card->u.b.cfg.rbs_map=0;
}
}
DEBUG_EVENT("\n");
/* This is for the ports link state */
card->wandev.state = WAN_CONNECTING;
card->u.b.state = WAN_DISCONNECTED;
/* Initialize the task queue */
tasklet_init(&card->u.b.wanpipe_rx_task, bstrm_rx_bh, (unsigned long)card);
tasklet_init(&card->u.b.wanpipe_tx_task, bstrm_tx_bh, (unsigned long)card);
for (i=0;i<10;i++){
skb=dev_alloc_skb(card->u.b.cfg.rx_complete_length+50+sizeof(api_rx_hdr_t));
if (!skb){
DEBUG_EVENT( "%s: Failed to allocate rx isr queue mem!\n",
card->devname);
bstrm_skb_queue_purge(&card->u.b.rx_isr_free_queue);
card->wandev.state = WAN_UNCONFIGURED;
return -ENOMEM;
}
skb_queue_tail(&card->u.b.rx_isr_free_queue,skb);
}
#if 0
//NENAD
{
int x;
card->u.b.tx_scratch_buf_len=1200;
for (x=0;x<card->u.b.tx_scratch_buf_len;x++){
card->u.b.tx_scratch_buf[x]=0x7E;//(x%32);
}
}
#endif
wan_spin_lock_irq(&card->wandev.lock,&smp_flags);
err=config_bstrm(card);
wan_spin_unlock_irq(&card->wandev.lock,&smp_flags);
if (err){
DEBUG_EVENT( "%s: Failed to configure adapter!\n",card->devname);
disable_comm(card);
wan_spin_lock_irq(&card->wandev.lock,&smp_flags);
bstrm_skb_queue_purge(&card->u.b.rx_isr_free_queue);
wan_spin_unlock_irq(&card->wandev.lock,&smp_flags);
card->wandev.state = WAN_UNCONFIGURED;
return err;
}
set_bit(SEND_CRIT,&card->wandev.critical);
card->disable_comm = &disable_comm;
DEBUG_TEST("%s: Config DONE\n",card->devname);
return 0;
}
/******* WAN Device Driver Entry Points *************************************/
/*============================================================================
* Update device status & statistics
* This procedure is called when updating the PROC file system and returns
* various communications statistics. These statistics are accumulated from 3
* different locations:
* 1) The 'if_stats' recorded for the device.
* 2) Communication error statistics on the adapter.
* 3) BSTRM operational statistics on the adapter.
* The board level statistics are read during a timer interrupt. Note that we
* read the error and operational statistics during consecitive timer ticks so
* as to minimize the time that we are inside the interrupt handler.
*
*/
static int update (wan_device_t* wandev)
{
sdla_t* card = wandev->private;
netdevice_t* dev;
bitstrm_private_area_t* bstrm_priv_area;
//unsigned long smp_flags;
/* sanity checks */
if((wandev == NULL) || (wandev->private == NULL))
return -EFAULT;
if(wandev->state == WAN_UNCONFIGURED)
return -ENODEV;
/* more sanity checks */
if(test_bit(PERI_CRIT, (void*)&card->wandev.critical))
return -EAGAIN;
dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head));
if(dev == NULL)
return -ENODEV;
if((bstrm_priv_area=dev->priv) == NULL)
return -ENODEV;
if(bstrm_priv_area->update_comms_stats){
return -EAGAIN;
}
#if 0
bstrm_priv_area->ifstats.rx_fifo_errors=0;
bstrm_priv_area->ifstats.rx_frame_errors=0;
bstrm_priv_area->ifstats.tx_carrier_errors=0;
bstrm_priv_area->ifstats.rx_bytes=0;
bstrm_priv_area->ifstats.tx_bytes=0;
bstrm_priv_area->ifstats.rx_packets=0;
bstrm_priv_area->ifstats.tx_packets=0;
bstrm_priv_area->ifstats.tx_fifo_errors=0;
#endif
#if 1
DEBUG_EVENT( "%s:%s: Tx B=%i: Rx U=%i: Rx F=%i: Rx-U-BH=%i Rx-F-Bh=%i Idle 0x%x\n",
card->devname,
dev->name,
skb_queue_len(&bstrm_priv_area->tx_queue),
skb_queue_len(&bstrm_priv_area->rx_used_queue),
skb_queue_len(&bstrm_priv_area->rx_free_queue),
skb_queue_len(&card->u.b.rx_isr_queue),
skb_queue_len(&card->u.b.rx_isr_free_queue),
bstrm_priv_area->tx_idle_flag);
#endif
#if 0
DEBUG_EVENT( "%s: Tx Data = %i Rx Data = %i\n",
card->devname, atomic_read(&tx_data),atomic_read(&rx_data));
DEBUG_EVENT( "%s: Sw Dev = %s\n",
bstrm_priv_area->if_name,
bstrm_priv_area->sw_dev ?
bstrm_priv_area->sw_dev->name : "None");
DEBUG_EVENT( "%s: ISR=%li Rx=%li Tx=%li RxBh=%li RxBhBsy=%li\n",
card->devname,
card->statistics.isr_entry,
card->statistics.isr_rx,
card->statistics.isr_tx,
card->statistics.poll_entry,
card->statistics.poll_tbusy_bad_status);
#endif
#if 0
if (bstrm_priv_area->common.usedby == SWITCH && bstrm_priv_area->sw_dev){
bitstrm_private_area_t *sw_chan=
(bitstrm_private_area_t *)bstrm_priv_area->sw_dev->priv;
sdla_t *sw_card=sw_chan->card;
DEBUG_EVENT( "SWITCH DIFF: ISR=%li Rx=%li Tx=%li RxBh=%li\n",
card->statistics.isr_entry-sw_card->statistics.isr_entry,
card->statistics.isr_rx-sw_card->statistics.isr_rx,
card->statistics.isr_tx-sw_card->statistics.isr_tx,
card->statistics.poll_entry-sw_card->statistics.poll_entry);
}
DEBUG_TEST("%s: Intr cnt %i Intr skip %i Irq Equalize %i ISR SKIP=0x%x\n",
card->devname,
atomic_read(&intr_cnt),
atomic_read(&intr_skip),
card->irq_equalize,
card->u.b.wait_for_buffers);
DEBUG_EVENT( "\n");
#endif
#if 0
/* TE1 Change the update_comms_stats variable to 3,
* only for T1/E1 card, otherwise 2 for regular
* S514/S508 card.
* Each timer interrupt will update only one type
* of statistics.
*/
bstrm_priv_area->update_comms_stats =
(IS_TE1_CARD(card) || IS_56K_CARD(card)) ? 3 : 2;
wan_spin_lock_irq(&card->wandev.lock,&smp_flags);
if (test_bit(0,&card->in_isr)){
wan_spin_unlock_irq(&card->wandev.lock,&smp_flags);
return -EBUSY;
}
update_comms_stats(card, bstrm_priv_area);
bstrm_priv_area->update_comms_stats--;
update_comms_stats(card, bstrm_priv_area);
bstrm_priv_area->update_comms_stats--;
update_comms_stats(card, bstrm_priv_area);
bstrm_priv_area->update_comms_stats--;
wan_spin_unlock_irq(&card->wandev.lock,&smp_flags);
#endif
return 0;
}
/*============================================================================
* Create new logical channel.
* This routine is called by the router when ROUTER_IFNEW IOCTL is being
* handled.
* o parse media- and hardware-specific configuration
* o make sure that a new channel can be created
* o allocate resources, if necessary
* o prepare network device structure for registaration.
*
* Return: 0 o.k.
* < 0 failure (channel will not be created)
*/
static int new_if (wan_device_t* wandev, netdevice_t* dev, wanif_conf_t* conf)
{
int i;
struct sk_buff *skb;
sdla_t* card = wandev->private;
bitstrm_private_area_t* bstrm_priv_area;
unsigned long smp_flags;
int err=0;
DEBUG_EVENT( "%s: Configuring Interface: %s\n",
card->devname, conf->name);
if ((conf->name[0] == '\0') || (strlen(conf->name) > WAN_IFNAME_SZ)) {
DEBUG_EVENT( "%s: Invalid interface name!\n",
card->devname);
return -EINVAL;
}
if (card->u.b.serial && card->wandev.new_if_cnt){
DEBUG_EVENT( "%s: Error: multipe interfaces are only allowed on T1/E1 cards!\n",
card->devname);
return -EEXIST;
}
/* allocate and initialize private data */
bstrm_priv_area = kmalloc(sizeof(bitstrm_private_area_t), GFP_KERNEL);
if(bstrm_priv_area == NULL)
return -ENOMEM;
memset(bstrm_priv_area, 0, sizeof(bitstrm_private_area_t));
memcpy(&bstrm_priv_area->cfg, &conf->u.bitstrm, sizeof(wan_bitstrm_conf_if_t));
bstrm_priv_area->card = card;
bstrm_priv_area->common.sk=NULL;
bstrm_priv_area->common.state = WAN_DISCONNECTED;
bstrm_priv_area->common.dev = dev;
bstrm_priv_area->common.config_id=card->wandev.config_id;
bstrm_priv_area->debug_stream=0;
bstrm_priv_area->debug_char=0xFF;
/* Initialize circular buffers for each interface
* and allocate skb buffers. This must be done first
* because the new_if_error, tries to purge the
* rx_free_queue.
*
* THUS: DO NOT GO TO new_if_error ABOVE HERE !
*/
skb_queue_head_init(&bstrm_priv_area->rx_free_queue);
skb_queue_head_init(&bstrm_priv_area->rx_used_queue);
skb_queue_head_init(&bstrm_priv_area->tx_queue);
/* initialize interface name */
strcpy(bstrm_priv_area->if_name, conf->name);
for (i=0;i<MAX_RX_FREE_SKB;i++){
skb=dev_alloc_skb(MAX_MTU_SIZE);
if (!skb){
err=-ENOMEM;
goto new_if_error;
}
skb_queue_tail(&bstrm_priv_area->rx_free_queue,skb);
}
/* Obtain a free skb buffer that will be used to construct
* a bitstream */
bstrm_priv_area->rx_skb=skb_dequeue(&bstrm_priv_area->rx_free_queue);
if (!bstrm_priv_area->rx_skb){
/* Santiy check this should never happen because
* we just allocated it */
err=-ENOMEM;
goto new_if_error;
}
if (IS_TE1_CARD(card)){
/* Channel definition section. If not channels defined
* return error */
if (IS_E1_CARD(card) && !IS_FR_FEUNFRAMED(&card->fe)){
conf->active_ch=conf->active_ch&0x7FFFFFFF;
}
if ((bstrm_priv_area->time_slot_map=conf->active_ch) == 0){
DEBUG_EVENT( "%s: Invalid Channel Selection 0x%lX\n",
card->devname,bstrm_priv_area->time_slot_map);
err=-EINVAL;
goto new_if_error;
}
DEBUG_EVENT( "%s: %s: Iface cfg channels = 0x%08lX\n",
card->devname,conf->name,bstrm_priv_area->time_slot_map);
/* Default the max_tx_up_size */
bstrm_priv_area->max_tx_up_size=MAX_T1_CHAN_TX_UP_SIZE;
if (IS_E1_CARD(card)){
if (IS_FR_FEUNFRAMED(&card->fe)){
bstrm_priv_area->max_tx_up_size=MAX_E1_UNFRM_CHAN_TX_UP_SIZE;
}else{
bstrm_priv_area->max_tx_up_size=MAX_E1_CHAN_TX_UP_SIZE;
}
}
/* If user defined value exists, us it */
if (bstrm_priv_area->cfg.max_tx_up_size){
bstrm_priv_area->max_tx_up_size=bstrm_priv_area->cfg.max_tx_up_size;
}
for (i=0;i<card->u.b.time_slots;i++){
if (test_bit(i,&bstrm_priv_area->time_slot_map)){
bstrm_priv_area->time_slots++;
}
}
if (bstrm_priv_area->max_tx_up_size % bstrm_priv_area->time_slots){
bstrm_priv_area->max_tx_up_size-=
bstrm_priv_area->max_tx_up_size %
bstrm_priv_area->time_slots;
bstrm_priv_area->max_tx_up_size+=bstrm_priv_area->time_slots;
}
}else{
bstrm_priv_area->max_tx_up_size=MAX_T1_CHAN_TX_UP_SIZE;
if (bstrm_priv_area->cfg.max_tx_up_size){
bstrm_priv_area->max_tx_up_size=bstrm_priv_area->cfg.max_tx_up_size;
}
}
bstrm_priv_area->rx_max_timeout=HZ;
bstrm_priv_area->rx_timeout=jiffies;
bstrm_priv_area->tx_idle_flag=card->u.b.cfg.monosync_tx_time_fill_char;
bstrm_priv_area->hdlc_eng=conf->hdlc_streaming;
bstrm_priv_area->bits_in_byte=BITSINBYTE;
if (bstrm_priv_area->hdlc_eng){
bstrm_priv_area->tx_idle_flag=0x7E;
bstrm_priv_area->seven_bit_hdlc = bstrm_priv_area->cfg.seven_bit_hdlc;
if (bstrm_priv_area->seven_bit_hdlc){
bstrm_priv_area->bits_in_byte = 7;
}
}
bstrm_priv_area->max_tx_queue_sz=MAX_TX_QUEUE_SIZE;
if (bstrm_priv_area->cfg.max_tx_queue_size){
bstrm_priv_area->max_tx_queue_sz=bstrm_priv_area->cfg.max_tx_queue_size;
}
/* Setup wanpipe as a router (WANPIPE) or as an API */
if( strcmp(conf->usedby, "WANPIPE") == 0) {
bstrm_priv_area->protocol=conf->protocol;
bstrm_priv_area->common.usedby=WANPIPE;
bstrm_priv_area->hdlc_eng=1;
bstrm_priv_area->tx_idle_flag=0x7E;
DEBUG_EVENT( "%s: Running in WANPIPE mode !\n",
wandev->name);
if (conf->protocol != WANOPT_NO){
dev->priv=bstrm_priv_area;
if ((err=protocol_init(card,dev,bstrm_priv_area,conf)) != 0){
goto new_if_error;
}
if (conf->ignore_dcd == WANOPT_YES || conf->ignore_cts == WANOPT_YES){
DEBUG_EVENT( "%s: Ignore modem changes DCD/CTS\n",card->devname);
bstrm_priv_area->ignore_modem=1;
}else{
DEBUG_EVENT( "%s: Restart protocol on modem changes DCD/CTS\n",
card->devname);
}
}
} else if( strcmp(conf->usedby, "API") == 0) {
bstrm_priv_area->common.usedby=API;
bstrm_priv_area->protocol=0;
DEBUG_EVENT( "%s: Running in API mode !\n",
wandev->name);
} else if( strcmp(conf->usedby, "STACK") == 0) {
bstrm_priv_area->common.usedby=STACK;
bstrm_priv_area->protocol=0;
DEBUG_EVENT( "%s: Running in STACK mode !\n",
wandev->name);
} else if( strcmp(conf->usedby, "SWITCH") == 0) {
bstrm_priv_area->common.usedby=SWITCH;
bstrm_priv_area->protocol=0;
DEBUG_EVENT( "%s: Running in SWITCH mode !\n",
wandev->name);
#if 1
if (card->u.b.cfg.rx_complete_length != card->u.b.cfg.max_length_tx_data_block){
DEBUG_EVENT( "%s: Config Error: SWITCH tx and rx data size must be equal! (Tx=%i != Rx=%i)\n",
card->devname,
card->u.b.cfg.max_length_tx_data_block,
card->u.b.cfg.rx_complete_length);
err=-EINVAL;
goto new_if_error;
}
bstrm_priv_area->max_tx_up_size=card->u.b.cfg.rx_complete_length;
#endif
set_bit(WAIT_DEVICE_BUFFERS,&bstrm_priv_area->tq_control);
}else{
DEBUG_EVENT( "%s: Error, Invalid operation mode, API only!\n",
wandev->name);
err=-EINVAL;
goto new_if_error;
}
/* prepare network device data space for registration */
dev->init = &if_init;
dev->priv = bstrm_priv_area;
bstrm_priv_area->common.dev = dev;
bstrm_priv_area->hdlc_flag=0;
set_bit(NO_FLAG,&bstrm_priv_area->hdlc_flag);
DEBUG_EVENT( "\n");
bstrm_priv_area->rx_crc[0]=-1;
bstrm_priv_area->rx_crc[1]=-1;
bstrm_priv_area->rx_crc[2]=-1;
bstrm_priv_area->tx_crc=-1;
bstrm_priv_area->tx_flag= 0x7E; //card->u.b.cfg.monosync_tx_time_fill_char;
bstrm_priv_area->tx_flag_idle= 0x7E; //card->u.b.cfg.monosync_tx_time_fill_char;
if (bstrm_priv_area->common.usedby == SWITCH){
strncpy(bstrm_priv_area->sw_if_name,conf->sw_dev_name,WAN_IFNAME_SZ);
}
if (IS_TE1_CARD(card)){
/* Check that the time slot is not being used. If it is
* stop the interface setup. Notice, though we proceed
* to check for all timeslots before we start binding
* the channels in. This way, we don't have to go back
* and clean the time_slot_map */
for (i=0;i<card->u.b.time_slots;i++){
if (test_bit(i,&bstrm_priv_area->time_slot_map)){
DEBUG_CFG( "Configuring %s for timeslot %i\n",
conf->name, i+1);
bstrm_priv_area->rbs_chan=i+1;
if (IS_T1_CARD(card)){
if (wan_test_bit(i,&card->u.b.cfg.rbs_map)){
bstrm_priv_area->rbs_on=1;
}
}
if (IS_E1_CARD(card)){
if (card->u.b.time_slot_map[i+1]){
DEBUG_EVENT( "%s: Channel/Time Slot resource conflict!\n",
card->devname);
DEBUG_EVENT( "%s: %s: Channel %i, aready in use!\n",
card->devname,dev->name,(i+1));
err=-EEXIST;
goto new_if_error;
}
}else{
if (card->u.b.time_slot_map[i]){
DEBUG_EVENT( "%s: Channel/Time Slot resource conflict!\n",
card->devname);
DEBUG_EVENT( "%s: %s: Channel %i, aready in use!\n",
card->devname,dev->name,(i+1));
err=-EEXIST;
goto new_if_error;
}
}
}
}
if (bstrm_priv_area->rbs_on){
if (bstrm_priv_area->time_slots > 1){
DEBUG_EVENT("%s:%s: Error: Interface with multiple timeslots %i!\n",
card->devname,bstrm_priv_area->if_name,
bstrm_priv_area->time_slots);
DEBUG_EVENT("%s:%s: Configured for Robbit Signalling!!!\n",
card->devname,bstrm_priv_area->if_name);
DEBUG_EVENT("%s:%s: Config for single timeslot per iface!\n",
card->devname,bstrm_priv_area->if_name);
DEBUG_EVENT("\n");
err = -EINVAL;
goto new_if_error;
}
if (bstrm_priv_area->hdlc_eng && !bstrm_priv_area->seven_bit_hdlc){
DEBUG_EVENT("%s:%s: Warning: Forcing hdlc eng to 7bit hdlc, rbs on!\n",
card->devname,bstrm_priv_area->if_name);
bstrm_priv_area->seven_bit_hdlc=1;
}
}
/* WARNING: The new_if() function should not fail
* After this point */
wan_spin_lock_irq(&card->wandev.lock,&smp_flags);
/*Bind an interface to a time slot map. The resource
* check was done above. We need to lock this area because
* the tx isr and rx bottom half are running */
for (i=0;i<card->u.b.time_slots;i++){
if (test_bit(i,&bstrm_priv_area->time_slot_map)){
if (IS_E1_CARD(card)){
card->u.b.time_slot_map[i+1] = bstrm_priv_area;
}else{
card->u.b.time_slot_map[i] = bstrm_priv_area;
}
}
}
wan_spin_unlock_irq(&card->wandev.lock,&smp_flags);
}
DEBUG_EVENT( "\n");
DEBUG_EVENT( "%s: Configuring %s: \n",
card->devname,
bstrm_priv_area->if_name);
if (IS_TE1_CARD(card)){
DEBUG_EVENT( "%s: TimeSlot Bind Map =0x%08lX\n",
card->devname,
bstrm_priv_area->time_slot_map);
}
DEBUG_EVENT( "%s: Tx Idle Flag =0x%X\n",
card->devname,
bstrm_priv_area->tx_idle_flag);
DEBUG_EVENT( "%s: Max Tx Queue Size =%d\n",
card->devname,
bstrm_priv_area->max_tx_queue_sz);
if (IS_TE1_CARD(card)){
DEBUG_EVENT( "%s: Max Tx Up Size =%i\n",
card->devname,
bstrm_priv_area->max_tx_up_size);
}
DEBUG_EVENT( "%s: HDLC Engine =%s Bits=%d\n",
card->devname,
bstrm_priv_area->hdlc_eng?"ON":"OFF",
bstrm_priv_area->seven_bit_hdlc?7:8);
DEBUG_EVENT( "\n");
card->wandev.new_if_cnt++;
return 0;
new_if_error:
if (bstrm_priv_area){
bstrm_skb_queue_purge(&bstrm_priv_area->rx_free_queue);
if (bstrm_priv_area->rx_skb){
dev_kfree_skb_any(bstrm_priv_area->rx_skb);
bstrm_priv_area->rx_skb=NULL;
}
protocol_shutdown(card,dev);
bstrm_priv_area->common.dev=NULL;
kfree(bstrm_priv_area);
}
dev->priv=NULL;
return err;
}
/*============================================================================
* Delete logical channel.
*/
static int del_if (wan_device_t* wandev, netdevice_t* dev)
{
bitstrm_private_area_t* bstrm_priv_area = dev->priv;
sdla_t *card = wandev->private;
int i;
unsigned long smp_flags;
if (!bstrm_priv_area){
return 0;
}
wan_spin_lock_irq(&card->wandev.lock, &smp_flags);
if (test_bit(0,&card->in_isr)){
DEBUG_EVENT( "%s: Del if critical with ISR\n",
card->devname);
}
if (IS_TE1_CARD(card)){
/* Un Bind an interface to a time slot map */
for (i=0;i<card->u.b.time_slots;i++){
if (test_bit(i,&bstrm_priv_area->time_slot_map)){
if (IS_E1_CARD(card)){
card->u.b.time_slot_map[i+1] = NULL;
}else{
card->u.b.time_slot_map[i] = NULL;
}
}
}
}
if (bstrm_priv_area->rx_skb){
dev_kfree_skb_any(bstrm_priv_area->rx_skb);
bstrm_priv_area->rx_skb=NULL;
}
if (bstrm_priv_area->tx_skb){
dev_kfree_skb_any(bstrm_priv_area->tx_skb);
bstrm_priv_area->tx_skb=NULL;
}
bstrm_skb_queue_purge(&bstrm_priv_area->tx_queue);
bstrm_skb_queue_purge(&bstrm_priv_area->rx_free_queue);
bstrm_skb_queue_purge(&bstrm_priv_area->rx_used_queue);
wan_spin_unlock_irq(&card->wandev.lock, &smp_flags);
protocol_shutdown(card,dev);
card->wandev.new_if_cnt--;
return 0;
}
/****** Network Device Interface ********************************************/
/*============================================================================
* Initialize Linux network interface.
*
* This routine is called only once for each interface, during Linux network
* interface registration. Returning anything but zero will fail interface
* registration.
*/
static int if_init (netdevice_t* dev)
{
bitstrm_private_area_t* bstrm_priv_area = dev->priv;
sdla_t* card = bstrm_priv_area->card;
wan_device_t* wandev = &card->wandev;
/* Initialize device driver entry points */
dev->open = &if_open;
dev->stop = &if_close;
dev->hard_start_xmit = &if_send;
dev->get_stats = &if_stats;
#if defined(LINUX_2_4)||defined(LINUX_2_6)
dev->tx_timeout = &if_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
#endif
dev->do_ioctl = &if_do_ioctl;
/* Initialize media-specific parameters */
if (!bstrm_priv_area->protocol){
dev->flags |= IFF_POINTOPOINT;
dev->flags |= IFF_NOARP;
}
/* Enable Mulitcasting if user selected */
if (!bstrm_priv_area->protocol && bstrm_priv_area->mc == WANOPT_YES){
dev->flags |= IFF_MULTICAST;
}
if (!bstrm_priv_area->protocol){
dev->type = ARPHRD_PPP;
}
if (bstrm_priv_area->common.usedby == SWITCH){
dev->mtu = card->u.b.cfg.max_length_tx_data_block;
}else{
if (!bstrm_priv_area->protocol){
dev->mtu = card->wandev.mtu;
}
}
/* for API usage, add the API header size to the requested MTU size */
if(bstrm_priv_area->common.usedby == API) {
dev->mtu += sizeof(api_tx_hdr_t);
}
if (!bstrm_priv_area->protocol){
dev->hard_header_len = 0;
}
/* Initialize hardware parameters */
dev->irq = wandev->irq;
dev->dma = wandev->dma;
dev->base_addr = wandev->ioport;
card->hw_iface.getcfg(card->hw, SDLA_MEMBASE, &dev->mem_start); //ALEX_TODAY wandev->maddr;
card->hw_iface.getcfg(card->hw, SDLA_MEMEND, &dev->mem_end); //ALEX_TODAY wandev->maddr + wandev->msize - 1;
/* Set transmit buffer queue length
* If too low packets will not be retransmitted
* by stack.
*/
dev->tx_queue_len = 100;
return 0;
}
/**
* if_do_ioctl - Ioctl handler for fr
* @dev: Device subject to ioctl
* @ifr: Interface request block from the user
* @cmd: Command that is being issued
*
* This function handles the ioctls that may be issued by the user
* to control the settings of a FR. It does both busy
* and security checks. This function is intended to be wrapped by
* callers who wish to add additional ioctl calls of their own.
*/
/* SNMP */
static int if_do_ioctl(netdevice_t *dev, struct ifreq *ifr, int cmd)
{
bitstrm_private_area_t* chan= (bitstrm_private_area_t*)dev->priv;
unsigned long smp_flags;
sdla_t *card;
wan_udp_pkt_t *wan_udp_pkt;
int err=0;
custom_control_call_t custom_control_pkt;
if (!chan){
return -ENODEV;
}
card=chan->card;
NET_ADMIN_CHECK();
switch(cmd)
{
case SIOC_WANPIPE_GET_TIME_SLOTS:
err=card->u.b.time_slots;
break;
case SIOC_WANPIPE_GET_MEDIA_TYPE:
err=card->fe.fe_cfg.media;
break;
case SIOC_WANPIPE_BIND_SK:
if (!ifr){
err= -EINVAL;
break;
}
spin_lock_irqsave(&card->wandev.lock,smp_flags);
err=wan_bind_api_to_svc(chan,ifr->ifr_data);
spin_unlock_irqrestore(&card->wandev.lock,smp_flags);
if (!err){
chan->ifstats.tx_fifo_errors=0;
chan->ifstats.rx_errors=0;
}
break;
case SIOC_WANPIPE_UNBIND_SK:
if (!ifr){
err= -EINVAL;
break;
}
spin_lock_irqsave(&card->wandev.lock,smp_flags);
err=wan_unbind_api_from_svc(chan,ifr->ifr_data);
spin_unlock_irqrestore(&card->wandev.lock,smp_flags);
if (chan->hdlc_eng){
init_rx_hdlc_eng(card,chan,1);
}
break;
case SIOC_WANPIPE_CHECK_TX:
case SIOC_ANNEXG_CHECK_TX:
err=0;
break;
case SIOC_WANPIPE_DEV_STATE:
err = chan->common.state;
break;
case SIOC_ANNEXG_KICK:
err=0;
break;
case SIOC_WANPIPE_BITSTRM_T1E1_CFG:
DEBUG_DBG("%s: SIOC_WANPIPE_BITSTRM_T1E1_CFG\n", card->devname);
if (card->comm_enabled){
spin_lock_irqsave(&card->wandev.lock, smp_flags);
bstrm_disable_comm_shutdown (card);
spin_unlock_irqrestore(&card->wandev.lock, smp_flags);
}
if (copy_from_user(&card->fe.fe_cfg,ifr->ifr_data,sizeof(sdla_fe_cfg_t))){
DEBUG_EVENT("%s: Error: Failed to copy from user in ioctl()\n",
card->devname);
return -EFAULT;
}
spin_lock_irqsave(&card->wandev.lock, smp_flags);
if (IS_TE1_CARD(card)) {
DEBUG_DBG("%s: (IOCTL) for %s selecting : \n",
card->devname,
(IS_T1_CARD(card))?"T1":"E1");
if(IS_T1_CARD(card)){
DEBUG_DBG("INTERFACE_LEVEL_V35\n");
card->wandev.interface = WANOPT_V35;
card->u.b.cfg.rx_complete_length = 720;
card->u.b.cfg.max_length_tx_data_block = 720;
card->u.b.time_slots = NO_ACTIVE_RX_TIME_SLOTS_T1;
}else{
DEBUG_DBG("INTERFACE_LEVEL_RS232\n");
card->wandev.interface = WANOPT_RS232;
//Must be less than original 720, because
//default .conf file is for T1.
//It is max len which can be pushed into
//the "pre allocated" sock buff.
card->u.b.cfg.rx_complete_length = 704; //divisible by 32
card->u.b.cfg.max_length_tx_data_block = 682;//divisible by 31
card->u.b.time_slots = NO_ACTIVE_RX_TIME_SLOTS_E1;
}
if (card->wandev.fe_iface.unconfig){
card->wandev.fe_iface.unconfig(&card->fe);
}
}
err=config_bstrm(card);
spin_unlock_irqrestore(&card->wandev.lock, smp_flags);
return err;
case SIOC_CUSTOM_BITSTRM_COMMANDS:
DEBUG_DBG("SIOC_CUSTOM_BITSTRM_COMMANDS\n");
if(copy_from_user(&custom_control_pkt, ifr->ifr_data, sizeof(custom_control_call_t)) ){
return -EFAULT;
}
switch(custom_control_pkt.control_code) {
case SET_BIT_IN_PMC_REGISTER:
if (IS_TE1_CARD(card)){
unsigned char val = 0;
unsigned char new_val;
val = read_front_end_reg(card, 1, custom_control_pkt.reg);
DEBUG_DBG("%s: read val : 0x%02X\n", card->devname, val);
new_val = val | (0x01 << custom_control_pkt.bit_number);
err = write_front_end_reg(card, 1, custom_control_pkt.reg, new_val);
if(err){
printk( KERN_INFO
"%s:SET_BIT_IN_PMC_REGISTER command failed! err : 0x%02X\n",
card->devname, err);
}
val = read_front_end_reg(card, 1, custom_control_pkt.reg);
DEBUG_DBG("%s: read val after OR : 0x%02X\n", card->devname, val);
}else{
DEBUG_EVENT(
"%s:SET_BIT_IN_PMC_REGISTER command is invalid for the card type!\n",
card->devname);
err = 1;
}
break;
case RESET_BIT_IN_PMC_REGISTER:
if (IS_TE1_CARD(card)){
unsigned char val = 0;
unsigned char new_val;
val = read_front_end_reg(card, 1, custom_control_pkt.reg);
new_val = val &= (~(0x01 << custom_control_pkt.bit_number));
err = write_front_end_reg(card, 1, custom_control_pkt.reg, new_val);
if(err){
DEBUG_EVENT(
"%s:RESET_BIT_IN_PMC_REGISTER command failed! err : 0x%02X\n",
card->devname, err);
}
}else{
DEBUG_EVENT(
"%s:RESET_BIT_IN_PMC_REGISTER command is invalid for the card type!\n",
card->devname);
err = 1;
}
break;
}
return err;
case SIOC_WANPIPE_PIPEMON:
if (atomic_read(&chan->udp_pkt_len) != 0){
return -EBUSY;
}
atomic_set(&chan->udp_pkt_len,MAX_LGTH_UDP_MGNT_PKT);
/* For performance reasons test the critical
* here before spin lock */
if (test_bit(0,&card->in_isr)){
atomic_set(&chan->udp_pkt_len,0);
return -EBUSY;
}
wan_udp_pkt=(wan_udp_pkt_t*)chan->udp_pkt_data;
if (copy_from_user(&wan_udp_pkt->wan_udp_hdr,ifr->ifr_data,sizeof(wan_udp_hdr_t))){
atomic_set(&chan->udp_pkt_len,0);
return -EFAULT;
}
spin_lock_irqsave(&card->wandev.lock, smp_flags);
/* We have to check here again because we don't know
* what happened during spin_lock */
if (test_bit(0,&card->in_isr)) {
DEBUG_EVENT( "%s:%s Pipemon command failed, Driver busy: try again.\n",
card->devname,dev->name);
atomic_set(&chan->udp_pkt_len,0);
spin_unlock_irqrestore(&card->wandev.lock, smp_flags);
return -EBUSY;
}
process_udp_mgmt_pkt(card,dev,chan,1);
spin_unlock_irqrestore(&card->wandev.lock, smp_flags);
/* This area will still be critical to other
* PIPEMON commands due to udp_pkt_len
* thus we can release the irq */
if (atomic_read(&chan->udp_pkt_len) > sizeof(wan_udp_pkt_t)){
DEBUG_EVENT( "%s: Error: Pipemon buf too bit on the way up! %i\n",
card->devname,atomic_read(&chan->udp_pkt_len));
atomic_set(&chan->udp_pkt_len,0);
return -EINVAL;
}
if (copy_to_user(ifr->ifr_data,&wan_udp_pkt->wan_udp_hdr,sizeof(wan_udp_hdr_t))){
atomic_set(&chan->udp_pkt_len,0);
return -EFAULT;
}
atomic_set(&chan->udp_pkt_len,0);
return 0;
case SIOC_WRITE_RBS_SIG:
{
unsigned char abcd_bits;
if (!chan->rbs_on){
DEBUG_EVENT("%s: Error: Write RBS bits signalling turned off!\n",
chan->if_name);
return -EINVAL;
}
if (copy_from_user(&abcd_bits,ifr->ifr_data,1)){
return -EFAULT;
}
card->wandev.fe_iface.set_rbsbits(
&card->fe,
chan->rbs_chan,
abcd_bits);
err=0;
}
break;
case SIOC_READ_RBS_SIG:
if (!chan->rbs_on){
DEBUG_EVENT("%s: Error: Write RBS bits signalling turned off!\n",
chan->if_name);
return -EINVAL;
}
if (copy_to_user(ifr->ifr_data,&chan->rbs_sig,1)){
return -EFAULT;
}
err=0;
break;
default:
if (chan->protocol == WANCONFIG_PPP ||
chan->protocol == WANCONFIG_CHDLC){
return wp_sppp_do_ioctl(dev,ifr,cmd);
}
return -EOPNOTSUPP;
}
return err;
}
/*============================================================================
* Open network interface.
* o enable communications and interrupts.
* o prevent module from unloading by incrementing use count
*
* Return 0 if O.k. or errno.
*/
static int if_open (netdevice_t* dev)
{
bitstrm_private_area_t* bstrm_priv_area = dev->priv;
sdla_t* card = bstrm_priv_area->card;
struct timeval tv;
int err = 0;
/* Only one open per interface is allowed */
if (open_dev_check(dev))
return -EBUSY;
do_gettimeofday(&tv);
bstrm_priv_area->router_start_time = tv.tv_sec;
netif_start_queue(dev);
protocol_start(card,dev);
if (bstrm_priv_area->common.usedby == SWITCH){
int err;
err=bstrm_bind_dev_switch(card,bstrm_priv_area,bstrm_priv_area->sw_if_name);
if (err){
DEBUG_EVENT( "%s: Error: Device %s failed to bind to %s\n",
card->devname,bstrm_priv_area->if_name,
bstrm_priv_area->sw_if_name);
return err;
}else{
bitstrm_private_area_t *sw_chan;
sdla_t *sw_card;
if (bstrm_priv_area->sw_dev &&
bstrm_priv_area->common.state != WAN_CONNECTED){
sw_chan=(bitstrm_private_area_t *)bstrm_priv_area->sw_dev->priv;
sw_card=sw_chan->card;
if (!sw_card->comm_enabled || !card->comm_enabled){
DEBUG_EVENT( "%s: Switch not connected: %s \n",
bstrm_priv_area->common.dev->name,
bstrm_priv_area->sw_dev->name);
}else{
unsigned long smp_flags;
DEBUG_EVENT( "%s: Setting switch to connected %s\n",
bstrm_priv_area->common.dev->name,
bstrm_priv_area->sw_dev->name);
wan_spin_lock_irq(&card->wandev.lock,&smp_flags);
sw_chan->common.state = WAN_CONNECTED;
bstrm_priv_area->common.state=WAN_CONNECTED;
set_bit(WAIT_DEVICE_BUFFERS,&bstrm_priv_area->tq_control);
set_bit(WAIT_DEVICE_BUFFERS,&sw_chan->tq_control);
wan_spin_unlock_irq(&card->wandev.lock,&smp_flags);
}
}
}
}else{
bstrm_priv_area->common.state=card->wandev.state;
DEBUG_EVENT( "%s: Interface %s: %s\n",
card->devname,
dev->name,
STATE_DECODE(bstrm_priv_area->common.state));
}
wanpipe_open(card);
return err;
}
/*============================================================================
* Close network interface.
* o if this is the last close, then disable communications and interrupts.
* o reset flags.
*/
static int if_close (netdevice_t* dev)
{
bitstrm_private_area_t* bstrm_priv_area = dev->priv;
sdla_t* card = bstrm_priv_area->card;
unsigned long smp_flags;
stop_net_queue(dev);
protocol_stop(card,dev);
if (bstrm_priv_area->common.usedby == SWITCH){
wan_spin_lock_irq(&card->wandev.lock,&smp_flags);
bstrm_unbind_dev_switch(card,bstrm_priv_area);
wan_spin_unlock_irq(&card->wandev.lock,&smp_flags);
}
bstrm_priv_area->common.state=WAN_DISCONNECTED;
wan_spin_lock_irq(&card->wandev.lock,&smp_flags);
wan_update_api_state(bstrm_priv_area);
wan_unbind_api_from_svc(bstrm_priv_area,bstrm_priv_area->common.sk);
wan_spin_unlock_irq(&card->wandev.lock,&smp_flags);
#if defined(LINUX_2_1)
dev->start=0;
#endif
wanpipe_close(card);
return 0;
}
static void disable_comm (sdla_t *card)
{
unsigned long smp_flags=0;
wan_spin_lock_irq(&card->wandev.lock, &smp_flags);
if (card->u.b.cfg.rbs_map){
bstrm_disable_te_signaling(card,card->u.b.cfg.rbs_map);
}
if (card->comm_enabled){
bstrm_disable_comm_shutdown (card);
}else{
card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00);
}
wan_spin_unlock_irq(&card->wandev.lock, &smp_flags);
tasklet_kill(&card->u.b.wanpipe_rx_task);
tasklet_kill(&card->u.b.wanpipe_tx_task);
wan_spin_lock_irq(&card->wandev.lock, &smp_flags);
bstrm_skb_queue_purge(&card->u.b.rx_isr_queue);
bstrm_skb_queue_purge(&card->u.b.rx_isr_free_queue);
wan_spin_unlock_irq(&card->wandev.lock, &smp_flags);
/* TE1 - Unconfiging */
if (IS_TE1_CARD(card)) {
if (card->wandev.fe_iface.unconfig){
card->wandev.fe_iface.unconfig(&card->fe);
}
}
return;
}
/*============================================================================
* Handle transmit timeout event from netif watchdog
*/
static void if_tx_timeout (netdevice_t *dev)
{
bitstrm_private_area_t* chan = dev->priv;
sdla_t *card = chan->card;
/* If our device stays busy for at least 5 seconds then we will
* kick start the device by making dev->tbusy = 0. We expect
* that our device never stays busy more than 5 seconds. So this
* is only used as a last resort.
*/
++card->wandev.stats.collisions;
printk (KERN_INFO "%s: Transmit timed out on %s\n", card->devname,dev->name);
netif_wake_queue (dev);
if (chan->common.usedby == API){
wan_wakeup_api(chan);
}else if (chan->common.usedby == STACK){
wanpipe_lip_kick(chan,0);
}
}
/*============================================================================
* Send a packet on a network interface.
* o set tbusy flag (marks start of the transmission) to block a timer-based
* transmit from overlapping.
* o check link state. If link is not up, then drop the packet.
* o execute adapter send command.
* o free socket buffer
*
* Return: 0 complete (socket buffer must be freed)
* non-0 packet may be re-transmitted (tbusy must be set)
*
* Notes:
* 1. This routine is called either by the protocol stack or by the "net
* bottom half" (with interrupts enabled).
* 2. Setting tbusy flag will inhibit further transmit requests from the
* protocol stack and can be used for flow control with protocol layer.
*/
static int if_send (struct sk_buff* skb, netdevice_t* dev)
{
bitstrm_private_area_t *bstrm_priv_area = dev->priv;
sdla_t *card = bstrm_priv_area->card;
unsigned long smp_flags;
if (skb == NULL){
/* If we get here, some higher layer thinks we've missed an
* tx-done interrupt.
*/
DEBUG_EVENT( "%s: interface %s got kicked!\n",
card->devname, dev->name);
wake_net_dev(dev);
return 0;
}
spin_lock_irqsave(&card->wandev.lock,smp_flags);
if (skb_queue_len(&bstrm_priv_area->tx_queue) > bstrm_priv_area->max_tx_queue_sz){
bstrm_priv_area->tick_counter = jiffies;
if (card->u.b.serial){
card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_BLOCK);
}
WAN_NETIF_STOP_QUEUE(dev);
spin_unlock_irqrestore(&card->wandev.lock,smp_flags);
return 1;
}
spin_unlock_irqrestore(&card->wandev.lock,smp_flags);
#if defined(LINUX_2_1)
if (dev->tbusy){
/* If our device stays busy for at least 5 seconds then we will
* kick start the device by making dev->tbusy = 0. We expect
* that our device never stays busy more than 5 seconds. So this
* is only used as a last resort.
*/
++card->wandev.stats.collisions;
if((jiffies - bstrm_priv_area->tick_counter) < (5 * HZ)) {
return 1;
}
if_tx_timeout(dev);
}
#endif
if (test_bit(WAIT_DEVICE_BUFFERS,&bstrm_priv_area->tq_control) &&
skb_queue_len(&bstrm_priv_area->tx_queue) >= TX_QUEUE_MID){
bitstrm_private_area_t *sw_chan=NULL;
if (net_ratelimit()){
DEBUG_EVENT("%s: Balancing switching devices, limiting tx!\n",
bstrm_priv_area->if_name);
}
dev_kfree_skb_any(skb);
if (bstrm_priv_area->sw_dev){
sw_chan=(bitstrm_private_area_t *)bstrm_priv_area->sw_dev->priv;
if (sw_chan){
if (test_bit(WAIT_DEVICE_BUFFERS,&sw_chan->tq_control) &&
skb_queue_len(&sw_chan->tx_queue) >= TX_QUEUE_MID){
DEBUG_EVENT("%s: Switching devices balanced %d %d\n",
sw_chan->if_name,
skb_queue_len(&bstrm_priv_area->tx_queue),
skb_queue_len(&sw_chan->tx_queue));
sw_chan->tq_control=0;
bstrm_priv_area->tq_control=0;
}
}
}
}else if(card->u.b.state != WAN_CONNECTED ||
bstrm_priv_area->common.state != WAN_CONNECTED){
++card->wandev.stats.tx_dropped;
bstrm_priv_area->ifstats.tx_carrier_errors++;
dev_kfree_skb_any(skb);
}else if(test_bit(SEND_CRIT,&card->wandev.critical)){
++card->wandev.stats.tx_dropped;
bstrm_priv_area->ifstats.tx_carrier_errors++;
DEBUG_EVENT( "SEND CRIT\n");
dev_kfree_skb_any(skb);
}else{
#if 0
//FIXME: NENAD DEBUG
dev_kfree_skb_any(skb);
dev->trans_start = jiffies;
goto if_send_exit_crit;
#endif
/* If it's an API packet pull off the API
* header. Also check that the packet size
* is larger than the API header
*/
wan_skb_unlink(skb);
if (bstrm_priv_area->common.usedby == SWITCH){
wanpipe_switch_datascope_tx_up(bstrm_priv_area,skb);
}
if (bstrm_priv_area->common.usedby == API){
if (skb->len <= sizeof(api_tx_hdr_t)){
++card->wandev.stats.tx_dropped;
bstrm_priv_area->ifstats.tx_dropped++;
dev_kfree_skb_any(skb);
goto if_send_exit_crit;
}
skb_pull(skb,sizeof(api_tx_hdr_t));
}
if (bstrm_priv_area->common.usedby != SWITCH &&
bstrm_priv_area->hdlc_eng){
if (hdlc_encode(bstrm_priv_area,&skb) != 0){
++card->wandev.stats.tx_dropped;
bstrm_priv_area->ifstats.tx_dropped++;
dev_kfree_skb_any(skb);
goto if_send_exit_crit;
}
}
#if 0
{
int i;
DEBUG_EVENT( "\n");
DEBUG_EVENT( "\n");
DEBUG_EVENT( "Tx Packet: \n");
for (i=0;i<skb->len;i++){
printk("%x ",skb->data[i]);
}
printk("\n");
}
#endif
card->wandev.stats.tx_packets++;
card->wandev.stats.tx_bytes+=skb->len;
bstrm_priv_area->ifstats.tx_packets++;
bstrm_priv_area->ifstats.tx_bytes += skb->len;
spin_lock_irqsave(&card->wandev.lock,smp_flags);
if (bstrm_priv_area->common.usedby != SWITCH &&
bstrm_priv_area->hdlc_eng){
bstrm_priv_area->tx_idle_flag = bstrm_priv_area->tx_flag_idle;
}
skb_queue_tail(&bstrm_priv_area->tx_queue,skb);
spin_unlock_irqrestore(&card->wandev.lock,smp_flags);
bstrm_priv_area->tick_counter = jiffies;
if (card->u.b.serial &&
!test_bit(WAIT_DEVICE_BUFFERS,&bstrm_priv_area->tq_control)){
card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_BLOCK);
}
#if defined(LINUX_2_4)||defined(LINUX_2_6)
dev->trans_start = jiffies;
#endif
}
if_send_exit_crit:
spin_lock_irqsave(&card->wandev.lock,smp_flags);
start_net_queue(dev);
spin_unlock_irqrestore(&card->wandev.lock,smp_flags);
return 0;
}
/*============================================================================
* Get ethernet-style interface statistics.
* Return a pointer to struct enet_statistics.
*/
static struct net_device_stats* if_stats (netdevice_t* dev)
{
bitstrm_private_area_t* bstrm_priv_area;
if ((bstrm_priv_area=dev->priv) == NULL)
return NULL;
return &bstrm_priv_area->ifstats;
}
/****** Cisco HDLC Firmware Interface Functions *******************************/
/*============================================================================
* Read firmware code version.
* Put code version as ASCII string in str.
*/
static int bstrm_read_version (sdla_t* card, char* str)
{
int data_len = 0;
wan_mbox_t* mb = &card->wan_mbox;
int rc;
memset(mb, 0, sizeof(wan_cmd_t));
mb->wan_data_len = 0;
mb->wan_command = READ_BSTRM_CODE_VERSION;
rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if (rc != WAN_CMD_TIMEOUT){
if (str) { /* is not null */
data_len = mb->wan_data_len;
memcpy(str, mb->wan_data, data_len);
str[data_len] = '\0';
}
}else{
bstrm_error(card,rc,mb);
}
return (rc);
}
/*-----------------------------------------------------------------------------
* Configure BSTRM firmware.
*/
static int bstrm_configure (sdla_t* card, void* data)
{
int err;
wan_mbox_t *mb = &card->wan_mbox;
memset(mb, 0, sizeof(wan_cmd_t));
memcpy(mb->wan_data, data, sizeof(BSTRM_CONFIGURATION_STRUCT));
mb->wan_command = SET_BSTRM_CONFIGURATION;
mb->wan_data_len = sizeof(BSTRM_CONFIGURATION_STRUCT);
err=card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if (err){
DEBUG_EVENT("%s: BSTRM CFG ERR: Len=%i Data=0x%X\n",
card->devname,mb->wan_data_len,mb->wan_data[0]);
}
return err;
}
/*============================================================================
* Set interrupt mode -- HDLC Version.
*/
static int bstrm_set_intr_mode (sdla_t* card, unsigned mode)
{
wan_mbox_t* mb = &card->wan_mbox;
int rc;
BSTRM_INT_TRIGGERS_STRUCT* int_data =
(BSTRM_INT_TRIGGERS_STRUCT *)mb->wan_data;
memset(mb, 0, sizeof(wan_cmd_t));
int_data->BSTRM_interrupt_triggers = mode;
int_data->IRQ = card->wandev.irq; //ALEX_TODAY card->hw.irq;
int_data->interrupt_timer = 1;
mb->wan_data_len = sizeof(BSTRM_INT_TRIGGERS_STRUCT);
mb->wan_command = SET_BSTRM_INTERRUPT_TRIGGERS;
rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if (rc == WAN_CMD_TIMEOUT)
bstrm_error (card, rc, mb);
return rc;
}
/*===========================================================
* bstrm_disable_comm_shutdown
*
* Shutdown() disables the communications. We must
* have a sparate functions, because we must not
* call bstrm_error() hander since the private
* area has already been replaced */
static int bstrm_disable_comm_shutdown (sdla_t *card)
{
wan_mbox_t* mb = &card->wan_mbox;
int rc;
BSTRM_INT_TRIGGERS_STRUCT* int_data =
(BSTRM_INT_TRIGGERS_STRUCT *)mb->wan_data;
memset(mb, 0, sizeof(wan_cmd_t));
/* Disable Interrutps */
int_data->BSTRM_interrupt_triggers = 0;
int_data->IRQ = card->wandev.irq; //ALEX_TODAY card->hw.irq;
int_data->interrupt_timer = 1;
mb->wan_command = SET_BSTRM_INTERRUPT_TRIGGERS;
mb->wan_data_len = sizeof(BSTRM_INT_TRIGGERS_STRUCT);
rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
/* Disable Communications */
mb->wan_command = DISABLE_BSTRM_COMMUNICATIONS;
mb->wan_data_len = 0;
rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
card->comm_enabled = 0;
return 0;
}
/*============================================================================
* Enablenications.
*/
static int bstrm_comm_enable (sdla_t* card)
{
wan_mbox_t* mb = &card->wan_mbox;
int rc;
mb->wan_data_len = 0;
mb->wan_command = ENABLE_BSTRM_COMMUNICATIONS;
rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if (rc == WAN_CMD_TIMEOUT)
bstrm_error(card, rc, mb);
else
card->comm_enabled = 1;
return rc;
}
/*============================================================================
* Read communication error statistics.
*/
static int bstrm_read_comm_err_stats (sdla_t* card)
{
int rc;
wan_mbox_t* mb = &card->wan_mbox;
mb->wan_data_len = 0;
mb->wan_command = READ_COMMS_ERROR_STATS;
rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if (rc == WAN_CMD_TIMEOUT)
bstrm_error(card,rc,mb);
return rc;
}
/*============================================================================
* Read BSTRM operational statistics.
*/
static int bstrm_read_op_stats (sdla_t* card)
{
int rc;
wan_mbox_t* mb = &card->wan_mbox;
mb->wan_data_len = 0;
mb->wan_command = READ_BSTRM_OPERATIONAL_STATS;
rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if (rc == WAN_CMD_TIMEOUT)
bstrm_error(card,rc,mb);
return rc;
}
/*============================================================================
* Update communications error and general packet statistics.
*/
static int update_comms_stats(sdla_t* card,
bitstrm_private_area_t* bstrm_priv_area)
{
wan_mbox_t* mb = &card->wan_mbox;
COMMS_ERROR_STATS_STRUCT* err_stats;
BSTRM_OPERATIONAL_STATS_STRUCT *op_stats;
if(bstrm_priv_area->update_comms_stats == 3) {
/* 1. On the first timer interrupt, update T1/E1 alarms
* and PMON counters (only for T1/E1 card) (TE1)
*/
/* TE1 Update T1/E1 alarms */
if (IS_TE1_CARD(card)) {
card->wandev.fe_iface.read_alarm(&card->fe, 0);
/* TE1 Update T1/E1 perfomance counters */
card->wandev.fe_iface.read_pmon(&card->fe, 0);
}else if (IS_56K_CARD(card)) {
/* 56K Update CSU/DSU alarms */
card->wandev.fe_iface.read_alarm(&card->fe, 1);
}
}else {
/* 2. On the second timer interrupt, read the comms error
* statistics
*/
if(bstrm_priv_area->update_comms_stats == 2) {
if(bstrm_read_comm_err_stats(card))
return 1;
err_stats = (COMMS_ERROR_STATS_STRUCT *)mb->wan_data;
card->wandev.stats.rx_over_errors =
err_stats->Rx_overrun_err_count;
card->wandev.stats.rx_fifo_errors =
err_stats->Rx_dis_pri_bfrs_full_count;
card->wandev.stats.rx_missed_errors =
card->wandev.stats.rx_fifo_errors;
} else {
/* on the third timer interrupt, read the operational
* statistics
*/
if(bstrm_read_op_stats(card))
return 1;
op_stats = (BSTRM_OPERATIONAL_STATS_STRUCT *)mb->wan_data;
}
}
return 0;
}
/*============================================================================
* Send packet.
* Return: 0 - o.k.
* 1 - no transmit buffers available
*/
static int bstrm_send (sdla_t* card, void* data, unsigned len, unsigned char flag)
{
BSTRM_DATA_TX_STATUS_EL_STRUCT txbuf;
card->hw_iface.peek(card->hw, card->u.b.txbuf_off, &txbuf, sizeof(txbuf));
if (txbuf.opp_flag)
return 1;
if (flag){
txbuf.misc_Tx_bits = (volatile unsigned char)UPDATE_TX_TIME_FILL_CHAR;
txbuf.Tx_time_fill_char = flag;
}else{
txbuf.misc_Tx_bits=0;
}
txbuf.block_length = len;
/* WARNING:
* The txbuf->block_lenght and txbuf->opp_flag should
* never execute one after another. Since opp_flag and
* block_lenght reside beside each other in memory,
* some ISA busses will write, OUT OF ORDER, to the
* oppflag before the block length is updated */
card->hw_iface.poke(card->hw, txbuf.ptr_data_bfr, data, len);
txbuf.opp_flag = 1; /* start transmission */
card->hw_iface.poke(card->hw, card->u.b.txbuf_off, &txbuf, sizeof(txbuf));
/* Update transmit buffer control fields */
card->u.b.txbuf_off += sizeof(txbuf);
if (card->u.b.txbuf_off > card->u.b.txbuf_last_off)
card->u.b.txbuf_off = card->u.b.txbuf_base_off;
return 0;
}
/*============================================================================
* TE1
* Read value from PMC register.
*/
static unsigned char read_front_end_reg (void* card1, ...)
{
va_list args;
sdla_t* card = (sdla_t*)card1;
wan_mbox_t* mb = &card->wan_mbox;
u16 reg, line_no;
int rc;
char* data = mb->wan_data;
va_start(args, card1);
line_no = (u16)va_arg(args, int);
reg = (u16)va_arg(args, int);
va_end(args);
mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT);
mb->wan_command = READ_FRONT_END_REGISTER;
((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg;
rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if (rc == WAN_CMD_TIMEOUT)
bstrm_error(card,rc,mb);
return(((FRONT_END_REG_STRUCT *)data)->register_value);
}
/*============================================================================
* TE1
* Write value to PMC register.
*/
static int write_front_end_reg (void* card1, ...)
{
va_list args;
sdla_t* card = (sdla_t*)card1;
wan_mbox_t* mb = &card->wan_mbox;
u16 reg, line_no;
u8 value;
int rc;
char* data = mb->wan_data;
int retry=10;
va_start(args, card1);
line_no = (u16)va_arg(args, int);
reg = (u16)va_arg(args, int);
value = (u8)va_arg(args, int);
va_end(args);
do {
((FRONT_END_REG_STRUCT *)data)->register_number = (unsigned short)reg;
((FRONT_END_REG_STRUCT *)data)->register_value = value;
mb->wan_data_len = sizeof(FRONT_END_REG_STRUCT);
mb->wan_command = WRITE_FRONT_END_REGISTER;
rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if (rc == WAN_CMD_TIMEOUT)
bstrm_error(card,rc,mb);
}while (rc && --retry);
return rc;
}
/*============================================================================
* Enable timer interrupt
*/
static void bstrm_enable_timer (void* card_id)
{
sdla_t* card = (sdla_t*)card_id;
card->u.b.timer_int_enabled |= TMR_INT_ENABLED_TE;
card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER);
return;
}
/****** Firmware Error Handler **********************************************/
/*============================================================================
* Firmware error handler.
* This routine is called whenever firmware command returns non-zero
* return code.
*
* Return zero if previous command has to be cancelled.
*/
static int bstrm_error (sdla_t *card, int err, wan_mbox_t *mb)
{
unsigned cmd = mb->wan_command;
switch (err) {
case CMD_TIMEOUT:
DEBUG_EVENT( "%s: command 0x%02X timed out!\n",
card->devname, cmd);
break;
case T1_E1_AMI_NOT_SUPPORTED:
DEBUG_EVENT( "%s: AMI decoding not supported\n",
card->devname);
break;
case S514_BOTH_PORTS_SAME_CLK_MODE:
if(cmd == SET_BSTRM_CONFIGURATION) {
DEBUG_EVENT(
"%s: Configure both ports for the same clock source\n",
card->devname);
break;
}
default:
DEBUG_EVENT( "%s: command 0x%02X returned 0x%02X!\n",
card->devname, cmd, err);
}
return 0;
}
/********** Bottom Half Handlers ********************************************/
/* NOTE: There is no API, BH support for Kernels lower than 2.2.X.
* DO NOT INSERT ANY CODE HERE, NOTICE THE
* PREPROCESSOR STATEMENT ABOVE, UNLESS YOU KNOW WHAT YOU ARE
* DOING
*/
static void bstrm_tx_bh (unsigned long data)
{
#define card ((sdla_t*)data)
BSTRM_DATA_TX_STATUS_EL_STRUCT txbuf;
bitstrm_private_area_t* chan;
int ch=0;
char kick_tx_isr=0;
char frame_multiple=0;
set_bit(8, &card->u.b.tq_working);
if (test_bit(SEND_CRIT,&card->wandev.critical)){
clear_bit(SEND_CRIT,&card->wandev.critical);
}
card->hw_iface.peek(card->hw, card->u.b.txbuf_off, &txbuf, sizeof(txbuf));
if (test_bit(0,(unsigned long*)&txbuf.opp_flag)){
DEBUG_EVENT( "%s: Error: Tx buffer busy in Tx intr!\n",
card->devname);
goto tx_bh_exit;
}
#if 0
//FIXME: NENAD DEBUG
goto tx_nenad_skip;
#endif
card->u.b.tx_scratch_buf_len=0;
if (card->u.b.serial){
/* For non T1/E1 cards, send a whole skb buffer
* down the stack. i.e. no channelization */
struct sk_buff *skb;
netdevice_t *dev;
dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head));
if (!dev || !(dev->flags & IFF_UP)){
DEBUG_EVENT("%s: Dev down\n",__FUNCTION__);
goto tx_bh_exit;
}
chan = (bitstrm_private_area_t *)wan_netif_priv(dev);
if (!chan){
goto tx_bh_exit;
}
if (chan->common.usedby == SWITCH &&
test_bit(WAIT_DEVICE_BUFFERS,&chan->tq_control)){
DEBUG_EVENT("%s: Warning: Tx Intr while waiting for buffers\n",
chan->common.dev->name);
}
if (is_queue_stopped(chan->common.dev)){
if (chan->common.usedby == API){
start_net_queue(chan->common.dev);
wan_wakeup_api(chan);
}else if (chan->common.usedby == SWITCH){
start_net_queue(chan->common.dev);
}else{
wake_net_dev(chan->common.dev);
}
}
skb=skb_dequeue(&chan->tx_queue);
if (!skb){
goto tx_bh_exit;
}
if (bstrm_send(card,skb->data,skb->len,chan->hdlc_eng?skb->cb[0]:0)){
DEBUG_EVENT( "%s: Error: Tx Bh: failed to send buffer busy!\n",
card->devname);
}
dev_kfree_skb_any(skb);
if (skb_queue_len(&chan->tx_queue)){
card->hw_iface.set_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_BLOCK);
}
goto tx_bh_exit;
}
for (;;){
/* Do not tx on E1 channel 0 since it is a signalling
* channel */
if (!IS_FR_FEUNFRAMED(&card->fe) && card->u.b.time_slots == NUM_OF_E1_CHANNELS && ch == 0){
goto tx_time_slot_handled;
}
chan=(bitstrm_private_area_t*)card->u.b.time_slot_map[ch];
if (!chan || !(chan->common.dev->flags & IFF_UP)){
DEBUG_TEST("%s: Timeslot %i not configured!\n",
card->devname,(ch+1));
card->u.b.tx_scratch_buf[card->u.b.tx_scratch_buf_len]=
card->u.b.cfg.monosync_tx_time_fill_char;
card->u.b.tx_scratch_buf_len++;
goto tx_time_slot_handled;
}
if (!chan->tx_skb){
if (is_queue_stopped(chan->common.dev)){
if (chan->common.usedby == API){
start_net_queue(chan->common.dev);
wan_wakeup_api(chan);
}else if (chan->common.usedby == STACK){
start_net_queue(chan->common.dev);
wanpipe_lip_kick(chan,0);
}else if (chan->common.usedby == SWITCH){
start_net_queue(chan->common.dev);
}else{
wake_net_dev(chan->common.dev);
}
}
if (chan->common.usedby == SWITCH &&
test_bit(WAIT_DEVICE_BUFFERS,&chan->tq_control)){
card->u.b.tx_scratch_buf[card->u.b.tx_scratch_buf_len]=chan->tx_idle_flag;
card->u.b.tx_scratch_buf_len++;
goto tx_time_slot_handled;
}
chan->tx_skb = skb_dequeue(&chan->tx_queue);
if (!chan->tx_skb){
#if 0
if (net_ratelimit()){
DEBUG_TEST("%s: Channel %s: no data \n",
card->devname,chan->if_name);
}
#endif
card->u.b.tx_scratch_buf[card->u.b.tx_scratch_buf_len]=chan->tx_idle_flag;
card->u.b.tx_scratch_buf_len++;
chan->ifstats.tx_fifo_errors++;
goto tx_time_slot_handled;
}
}
if (!chan->tx_skb || chan->tx_skb->len == 0){
#if 0
if (net_ratelimit()){
DEBUG_EVENT("%s: Channel %s: %i skb empty\n",
card->devname,chan->if_name,ch+1);
}
#endif
card->u.b.tx_scratch_buf[card->u.b.tx_scratch_buf_len]=chan->tx_idle_flag;
card->u.b.tx_scratch_buf_len++;
chan->ifstats.tx_fifo_errors++;
if (chan->tx_skb){
dev_kfree_skb_any(chan->tx_skb);
chan->tx_skb=NULL;
}
goto tx_time_slot_handled;
}
card->u.b.tx_scratch_buf[card->u.b.tx_scratch_buf_len]=chan->tx_skb->data[0];
card->u.b.tx_scratch_buf_len++;
skb_pull(chan->tx_skb,1);
/* We must check for existance of the pointer,
* because the channel might be unconfigued */
if (chan->tx_skb->len < 1){
dev_kfree_skb_any(chan->tx_skb);
chan->tx_skb=NULL;
}else{
kick_tx_isr=1;
}
tx_time_slot_handled:
/* How many times should we go around */
if (++ch >= card->u.b.time_slots){
ch=0;
if (++frame_multiple >= card->u.b.tx_chan_multiple){
break;
}
}
}
#if 0
//NENAD
tx_nenad_skip:
#endif
if (bstrm_send(card,&card->u.b.tx_scratch_buf[0],card->u.b.tx_scratch_buf_len,0)){
DEBUG_EVENT( "%s: Error: Tx Bh: failed to send buffer busy!\n",
card->devname);
}
tx_bh_exit:
clear_bit(8, &card->u.b.tq_working);
#undef card
}
static void bstrm_rx_bh (unsigned long data)
{
#define card ((sdla_t*)data)
struct sk_buff *skb;
bitstrm_private_area_t* chan;
int ch=0,stream_full=0;
volatile unsigned char *buf;
bstrm_test_rx_tx_discard(card);
if (!skb_queue_len(&card->u.b.rx_isr_queue)){
while(bstrm_bh_data_tx_up(card,NULL,NULL));
card->statistics.poll_tbusy_bad_status++;
return;
}
card->statistics.poll_entry++;
while ((skb=skb_dequeue(&card->u.b.rx_isr_queue)) != NULL){
if (!skb->len){
DEBUG_EVENT( "RX Error, skb=NULL or skb->len=0 \n");
bstrm_bh_cleanup(card,skb);
continue;
}
ch=0;
if (card->u.b.serial){
netdevice_t *dev;
dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head));
if (!dev || !(dev->flags&IFF_UP)){
bstrm_bh_cleanup(card,skb);
continue;
}
chan = (bitstrm_private_area_t *)wan_netif_priv(dev);
if (!chan){
bstrm_bh_cleanup(card,skb);
continue;
}
if (chan->common.usedby == SWITCH){
bstrm_bh_data_tx_up(card,skb,chan);
bstrm_switch_send(card,chan,skb);
bstrm_bh_cleanup(card,skb);
}else{
bstrm_bh_data_tx_up(card,skb,NULL);
bstrm_bh_cleanup(card,skb);
}
continue;
}
for (;;){
chan=(bitstrm_private_area_t*)card->u.b.time_slot_map[ch];
if (!chan || !(chan->common.dev->flags & IFF_UP)){
DEBUG_TEST("%s: Timeslot %i (ch=%i) not configured!\n",
card->devname,(ch+1),ch);
skb_pull(skb,1);
card->wandev.stats.rx_over_errors=ch;
card->wandev.stats.rx_fifo_errors++;
goto rx_time_slot_handled;
}
if (chan->rbs_on){
if (chan->rbs_sig != card->u.b.rbs_sig[ch]){
chan->rbs_sig=card->u.b.rbs_sig[ch];
send_rbs_oob_msg (card,chan);
DEBUG_TEST("%s: RBS Change 0x%X\n",
chan->if_name,chan->rbs_sig);
}
}
if (!chan->rx_skb){
/* The free queues might be busy, try
* here again. If we fail then we have a buffering
* problem. Increment a dropped packet */
DEBUG_TEST("%s: Rx_SKB from free queue! Free Q Len=%i\n",
card->devname,skb_queue_len(&chan->rx_free_queue));
chan->rx_skb=skb_dequeue(&chan->rx_free_queue);
if (!chan->rx_skb){
DEBUG_EVENT( "%s: Timeslot %i no rx buf!\n",
card->devname,(ch+1));
chan->ifstats.rx_dropped++;
skb_pull(skb,1);
goto rx_time_slot_handled;
}
chan->rx_timeout=jiffies;
}
if (skb_queue_len(&chan->rx_used_queue)){
stream_full=1;
}
buf=skb_put(chan->rx_skb,1);
buf[0]=skb->data[0];
skb_pull(skb,1);
#if 0
//NENAD
if (ch > 1){
if (buf[0] == 0x20+(ch-1)){
if (!chan->debug_stream){
DEBUG_EVENT("%s: Ch=%i:Got First Sync = 0x%X Len=%i\n",
chan->common.dev->name,ch,buf[0],chan->rx_skb->len);
chan->debug_stream=1;
chan->debug_char=buf[0];
}
}else{
if (chan->debug_stream){
DEBUG_EVENT("%s: Ch=%i:Out of sync First = 0x%X Idle=0x%X Len=%i\n",
chan->common.dev->name,ch,buf[0],chan->tx_idle_flag,
chan->rx_skb->len);
chan->debug_stream=0;
}
}
}
#endif
if (chan->rx_skb->len >= chan->max_tx_up_size){
/* A bit stream has reached maximum size.
* we must pass it to the next layer, ether
* HDLC decoder or API. For now just push it
* into the used queue */
if (chan->common.usedby == SWITCH){
//if (skb->len != 0){
// DEBUG_EVENT( "%s: SWITCH Sending %i, orig skb %i\n",
// card->devname,chan->rx_skb->len, skb->len);
//}
/* Try to pass the packet up the stack if
* the API is registered */
bstrm_bh_data_tx_up(card, NULL, chan);
/* Send the packet to our switched device*/
bstrm_switch_send(card,chan,chan->rx_skb);
/* Re-initialize the buffer, to be reused */
chan->rx_skb->data=(chan->rx_skb->head+16);
chan->rx_skb->len=1;
skb_trim(chan->rx_skb,0);
}else{
skb_queue_tail(&chan->rx_used_queue,chan->rx_skb);
chan->rx_skb=NULL;
chan->rx_skb=skb_dequeue(&chan->rx_free_queue);
stream_full=1;
}
chan->rx_timeout=jiffies;
if (chan->rx_skb && chan->rx_skb->len){
DEBUG_EVENT( "%s: Rx got new buffer skb len=%i\n",
chan->common.dev->name,chan->rx_skb->len);
}
}
rx_time_slot_handled:
if (skb->len < 1){
break;
}
if (++ch >= card->u.b.time_slots){
ch=0;
}
}//for(;;)
/* Initialize the rx_intr skb buffer, and get it ready
* for another use */
bstrm_bh_cleanup(card,skb);
if (!stream_full){
continue;
}
stream_full=bstrm_bh_data_tx_up(card,NULL,NULL);
}
while (stream_full){
stream_full=bstrm_bh_data_tx_up(card,NULL,NULL);
}
return;
#undef card
}
static void bstrm_switch_send(sdla_t *card, bitstrm_private_area_t * chan, struct sk_buff *skb)
{
struct sk_buff *new_skb;
if (!skb)
return;
if (chan->sw_dev && (chan->sw_dev->flags&IFF_UP)){
if (is_queue_stopped(chan->sw_dev)){
DEBUG_EVENT( "%s:%s: (Debug): Warning: dev busy %s\n",
card->devname,chan->if_name,chan->sw_dev->name);
goto switch_send_done;
}
if (!test_bit(WAIT_DEVICE_BUFFERS,&chan->tq_control)){
if (skb_queue_len(&chan->tx_queue) < TX_QUEUE_LOW){
DEBUG_EVENT("%s: Device queue low %i\n",
chan->common.dev->name,
skb_queue_len(&chan->tx_queue));
}else if (skb_queue_len(&chan->tx_queue) > TX_QUEUE_HIGH){
DEBUG_EVENT("%s: Device queue high %i\n",
chan->common.dev->name,
skb_queue_len(&chan->tx_queue));
}
}
new_skb=skb_copy(skb,GFP_ATOMIC);
if (!new_skb){
DEBUG_EVENT( "%s: ERROR: BH SW failed to allocate memory !\n",
card->devname);
card->wandev.stats.rx_errors++;
chan->ifstats.rx_errors++;
}else{
if (!chan->sw_dev->hard_start_xmit ||
chan->sw_dev->hard_start_xmit(new_skb,chan->sw_dev) != 0){
kfree(new_skb);
DEBUG_EVENT( "%s: Failed to send on SW dev %s\n",
chan->if_name,chan->sw_dev->name);
goto switch_send_done;
}
card->wandev.stats.rx_packets++;
card->wandev.stats.rx_bytes+=skb->len;
chan->ifstats.rx_packets++;
chan->ifstats.rx_bytes+=skb->len;
}
}else{
chan->ifstats.rx_fifo_errors++;
}
switch_send_done:
return;
}
static int bstrm_bh_data_tx_up(sdla_t*card, struct sk_buff *non_te1_skb, bitstrm_private_area_t *chan_ptr)
{
struct wan_dev_le *devle = NULL;
netdevice_t *dev;
bitstrm_private_area_t *chan;
struct sk_buff *new_skb,*skb;
int err=0;
int switch_dev=0;
/* Test if channel is specified */
if ((chan=chan_ptr) != NULL){
dev=chan->common.dev;
/* Channel exists, the SWITCH code is trying
* to send a packet up the stack. Thus
* check if this device is actually in SWITCH
* mode */
if (dev && chan->common.usedby == SWITCH){
/* If API socket is not bound in
* then exit */
if (chan->common.sk == NULL){
return 0;
}else{
/* API exists, then get the
* skb buffer from the rx_skb */
if (card->u.b.serial){
skb=non_te1_skb;
}else{
skb=chan->rx_skb;
}
/* During Switching, only a single
* buffer is used, not a queue */
if (skb){
/* Buffer exists, thus, set the
* switch flag, indicating below
* not to re-initialize this buffer */
switch_dev=1;
goto switch_hdlc_send;
}else{
/* This should never happen */
return 0;
}
}
}
}
/* The Serial cards, don't use queues, thus,
* they give us the skb buffer */
if (card->u.b.serial && non_te1_skb==NULL){
return err;
}
WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){
dev = WAN_DEVLE2DEV(devle);
if (dev == NULL || wan_netif_priv(dev) == NULL)
continue;
chan = wan_netif_priv(dev);
if (!card->u.b.serial){
skb = skb_dequeue(&chan->rx_used_queue);
if (!skb){
continue;
}
if (skb_queue_len(&chan->rx_used_queue)){
err=1;
}
}else{
skb = non_te1_skb;
if (!skb){
return err;
}
}
/* This is just a precaution, SWITCH device
* shouldnt be here */
if (chan->common.usedby == SWITCH){
goto tx_up_skb_recover;
}else if (chan->common.usedby == API){
/* Test if the API socket is bound in */
if (chan->common.sk == NULL){
chan->ifstats.rx_errors++;
goto tx_up_skb_recover;
}
}
switch_hdlc_send:
if (chan->hdlc_eng){
#if 0
DEBUG_EVENT("HDLC: UP\n");
DEBUG_EVENT( "PKT: ");
{
int i;
for (i=0;i<skb->len;i++){
if (skb->data[i] != 0x7E){
DEBUG_EVENT("%s: Data = 0x%X\n",card->devname,skb->data);
}
//printk("%02X ",skb->data[i]);
}
//printk("\n");
}
#endif
hdlc_decode(chan,
(skb->data),
(skb->len));
}else{
if (skb_headroom(skb) < sizeof(api_rx_hdr_t)){
new_skb=skb_copy_expand(skb,sizeof(api_rx_hdr_t),0,GFP_ATOMIC);
}else{
new_skb=skb_copy(skb,GFP_ATOMIC);
}
if (!new_skb){
DEBUG_EVENT( "%s: ERROR: Failed to clone skb buffer, no memory !\n",
card->devname);
++card->wandev.stats.rx_errors;
chan->ifstats.rx_errors++;
}else{
unsigned char *buf;
int api_err;
#if 0
//NENAD
if (chan->debug_char == 0x25){
int i,x;
static int out_of_sync_off=0;
for(i=0;i<new_skb->len;i++){
if (new_skb->data[i] == chan->debug_char){
if (!chan->debug_stream_1){
DEBUG_EVENT("%s: Got Second Sync = 0x%X Offset=%i\n",
chan->common.dev->name,new_skb->data[i],i);
chan->debug_stream_1=1;
if (out_of_sync_off && out_of_sync_off < i){
for (x=out_of_sync_off;x<=i;x++){
DEBUG_EVENT("0x%X\n",new_skb->data[x]);
}
out_of_sync_off=0;
}
}
}else{
if (chan->debug_stream_1){
DEBUG_EVENT("%s: Out of sync Sec = 0x%X Idle=0x%X Offset=%i\n",
chan->common.dev->name,new_skb->data[i],
chan->tx_idle_flag,i);
chan->debug_stream_1=0;
out_of_sync_off=i;
}
}
}
}
#endif
if (chan->common.usedby == STACK){
if (wanpipe_lip_rx(chan,new_skb) != 0){
wan_skb_free(new_skb);
++card->wandev.stats.rx_dropped;
++chan->ifstats.rx_dropped;
goto tx_up_skb_recover;
}
}else{
buf = skb_push(new_skb,sizeof(api_rx_hdr_t));
memset(buf, 0, sizeof(api_rx_hdr_t));
new_skb->protocol = htons(PVC_PROT);
wan_skb_reset_mac_header(new_skb);
new_skb->dev = dev;
new_skb->pkt_type = WAN_PACKET_DATA;
api_err=wan_api_rx(chan,new_skb);
if (api_err != 0){
/* Sock full cannot send, queue us for another
* try */
if (net_ratelimit()){
DEBUG_EVENT( "%s: Error: Rx sock full err %d used 0x%lx sk %p\n",
card->devname,\
err,
chan->common.used,
chan->common.sk);
}
wan_skb_free(new_skb);
++card->wandev.stats.rx_dropped;
++chan->ifstats.rx_dropped;
wan_wakeup_api(chan);
goto tx_up_skb_recover;
}
}
++card->wandev.stats.rx_packets;
card->wandev.stats.rx_bytes+=skb->len;
chan->ifstats.rx_packets++;
chan->ifstats.rx_bytes+=skb->len;
} //if new_skb
}//if HDLC_DECODE
tx_up_skb_recover:
if (switch_dev){
err=0;
break;
}
if (!card->u.b.serial){
skb->data=(skb->head+16);
skb->len=1;
skb_trim(skb,0);
skb_queue_tail(&chan->rx_free_queue,skb);
}else{
break;
}
}//for()
return err;
}
static int bstrm_bh_cleanup (sdla_t *card,struct sk_buff *skb)
{
if (!skb)
return 0;
/* Reset the buffer to zero */
skb->data = skb->head + 16;
/* This is a trick. The skb_trim checks if the skb->len is greater
* than the new len. Thus, fake the skb->len to 1 */
skb->len=1;
skb_trim(skb,0);
skb_queue_tail(&card->u.b.rx_isr_free_queue,skb);
return 0;
}
static struct sk_buff * bh_enqueue (sdla_t *card)
{
/* Check for full */
struct sk_buff *skb;
skb=skb_dequeue(&card->u.b.rx_isr_free_queue);
if (!skb){
DEBUG_TEST( "%s: Error: No skb in bh_enqueue\n",
card->devname);
return NULL;
}
if (skb->len){
DEBUG_EVENT( "%s: Error: Bh Enqueue Skb len %i\n",
card->devname,skb->len);
return NULL;
}
return skb;
}
/* END OF API BH Support */
/* HDLC Bitstream Decode Functions */
static void hdlc_decode (bitstrm_private_area_t *chan, unsigned char *buf, int len)
{
int i;
int word_len=len-(len%4);
int found=0;
/* Before decoding the packet, make sure that the current
* bit stream contains data. Decoding is very expensive,
* thus perform word (32bit) comparision test */
#if 1
for (i=0;i<word_len;i+=4){
if ((*(unsigned int*)&buf[i]) != *(unsigned int*)buf){
found=1;
break;
}
}
if ((len%4) && !found){
for (i=word_len;i<len;i++){
if (buf[i]!=buf[0]){
found=1;
break;
}
}
}
#if 0
{
int x,init;
init=0;
for (x=0;x<len;x++){
switch (buf[x]){
case 0xFF:
case 0x7E:
case 0xFC:
case 0xF9:
case 0xF3:
case 0xE7:
case 0xCF:
case 0x9F:
case 0x3F:
goto skip_print_p;
}
if (init == 0){
init++;
DEBUG_EVENT( "\n");
DEBUG_EVENT( "\n");
DEBUG_EVENT( "RX Packet Xoffset %i: ",x);
}
printk("%x ",buf[x]);
skip_print_p:
}
if (init){
printk("\n");
DEBUG_EVENT( "\n");
}
}
#endif
#else
found=1;
#endif
/* Data found within the bitstream, proceed to decode
* the bitstream and pull out data packets */
if (found){
// DEBUG_EVENT( "\n");
// DEBUG_EVENT( "HDLC DEC: Found packet offset%i\n ",i);
// DEBUG_EVENT( "Packet: ");
for (i=0; i<len; i++){
decode_byte(chan, &buf[i]);
}
}else{
/* Found only flags, pass few flags into
* the hdlc engine just in case the packet
* ended on block boundary */
for (i=0; i<4; i++){
decode_byte(chan, &buf[i]);
}
}
return;
}
static void decode_byte (bitstrm_private_area_t *chan, unsigned char *raw_byte)
{
int i;
unsigned long byte=*raw_byte;
sdla_t *card=chan->card;
/* Test each bit in an incoming bitstream byte. Search
* for an hdlc flag 0x7E, six 1s in a row. Once the
* flag is obtained, construct the data packets.
* The complete data packets are sent up the API stack */
for (i=0; i<BITSINBYTE; i++){
if (chan->seven_bit_hdlc && i==7){
continue;
}
if (test_bit(i,&byte)){
/* Got a 1 */
++chan->rx_decode_onecnt;
/* Make sure that we received a valid flag,
* before we start decoding incoming data */
if (!test_bit(NO_FLAG,&chan->hdlc_flag)){
chan->rx_decode_buf[chan->rx_decode_len] |= (1 << chan->rx_decode_bit_cnt);
if (++chan->rx_decode_bit_cnt >= BITSINBYTE){
/* Completed a byte of data, update the
* crc count, and start on the next
* byte. */
calc_rx_crc(chan);
#ifdef PRINT_PKT
printk(" %02X", data);
#endif
++chan->rx_decode_len;
if (chan->rx_decode_len > HDLC_ENG_BUF_LEN){
DEBUG_EVENT("%s: Error: Rx hdlc overflow\n",
chan->if_name);
init_rx_hdlc_eng(card,chan,1);
++chan->ifstats.rx_frame_errors;
++card->wandev.stats.rx_frame_errors;
}else{
chan->rx_decode_buf[chan->rx_decode_len]=0;
chan->rx_decode_bit_cnt=0;
chan->hdlc_flag=0;
set_bit(CLOSING_FLAG,&chan->hdlc_flag);
}
}
}
}else{
/* Got a zero */
if (chan->rx_decode_onecnt == 5){
/* bit stuffed zero detected,
* do not increment our decode_bit_count.
* thus, ignore this bit*/
}else if (chan->rx_decode_onecnt == 6){
/* Got a Flag */
if (test_bit(CLOSING_FLAG,&chan->hdlc_flag)){
/* Got a closing flag, thus asemble
* the packet and send it up the
* stack */
chan->hdlc_flag=0;
set_bit(OPEN_FLAG,&chan->hdlc_flag);
if (chan->rx_decode_len >= 3){
GET_FIN_CRC_CNT(chan->crc_cur);
FLIP_CRC(chan->rx_crc[chan->crc_cur],chan->crc_fin);
DECODE_CRC(chan->crc_fin);
/* Check CRC error before passing data up
* the API socket */
if (chan->crc_fin==chan->rx_orig_crc){
tx_up_decode_pkt(chan);
}else{
DEBUG_TEST("%s: Rx crc error, len=%i\n",
chan->if_name,chan->rx_decode_len);
++chan->ifstats.rx_crc_errors;
++card->wandev.stats.rx_crc_errors;
init_rx_hdlc_eng(card,chan,1);
}
}else{
DEBUG_TEST("%s: Rx abt error\n",chan->if_name);
++chan->ifstats.rx_frame_errors;
++card->wandev.stats.rx_frame_errors;
}
}else if (test_bit(NO_FLAG,&chan->hdlc_flag)){
/* Got a very first flag */
chan->hdlc_flag=0;
set_bit(OPEN_FLAG,&chan->hdlc_flag);
}
/* After a flag, initialize the decode and
* crc buffers and get ready for the next
* data packet */
init_rx_hdlc_eng(card,chan,0);
}else{
/* Got a valid zero, thus increment the
* rx_decode_bit_cnt, as a result of which
* a zero is left in the consturcted
* byte. NOTE: we must have a valid flag */
if (!test_bit(NO_FLAG,&chan->hdlc_flag)){
if (++chan->rx_decode_bit_cnt >= BITSINBYTE){
calc_rx_crc(chan);
#ifdef PRINT_PKT
printk(" %02X", data);
#endif
++chan->rx_decode_len;
if (chan->rx_decode_len > HDLC_ENG_BUF_LEN){
DEBUG_EVENT("%s: Error: Rx hdlc overflow\n",
chan->if_name);
init_rx_hdlc_eng(card,chan,1);
++chan->ifstats.rx_frame_errors;
++card->wandev.stats.rx_frame_errors;
}else{
chan->rx_decode_buf[chan->rx_decode_len]=0;
chan->rx_decode_bit_cnt=0;
chan->hdlc_flag=0;
set_bit(CLOSING_FLAG,&chan->hdlc_flag);
}
}
}
}
chan->rx_decode_onecnt=0;
}
}
return;
}
static void init_crc(void)
{
int i,j;
for(i=0;i<256;i++){
CRC_TABLE[i]=0;
for (j=0;j<BITSINBYTE;j++){
if (i & (1<<j)){
CRC_TABLE[i] ^= MagicNums[j];
}
}
}
}
static void calc_rx_crc(bitstrm_private_area_t *chan)
{
INC_CRC_CNT(chan->crc_cur);
/* Save the incoming CRC value, so it can be checked
* against the calculated one */
chan->rx_orig_crc = (((chan->rx_orig_crc<<8)&0xFF00) | chan->rx_decode_buf[chan->rx_decode_len]);
chan->rx_crc_tmp = (chan->rx_decode_buf[chan->rx_decode_len] ^ chan->rx_crc[chan->crc_prv]) & 0xFF;
chan->rx_crc[chan->crc_cur] = chan->rx_crc[chan->crc_prv] >> 8;
chan->rx_crc[chan->crc_cur] &= 0x00FF;
chan->rx_crc[chan->crc_cur] ^= CRC_TABLE[chan->rx_crc_tmp];
chan->rx_crc[chan->crc_cur] &= 0xFFFF;
INC_CRC_CNT(chan->crc_prv);
}
static void calc_tx_crc(bitstrm_private_area_t *chan,unsigned char byte)
{
chan->tx_crc_tmp = (byte ^ chan->tx_crc) & 0xFF;
chan->tx_crc = chan->tx_crc >> 8;
chan->tx_crc &= 0x00FF;
chan->tx_crc ^= CRC_TABLE[chan->tx_crc_tmp];
chan->tx_crc &= 0xFFFF;
}
static void tx_up_decode_pkt(bitstrm_private_area_t *chan)
{
unsigned char *buf;
struct sk_buff *skb = dev_alloc_skb(chan->rx_decode_len+sizeof(api_rx_hdr_t));
if (!skb){
DEBUG_EVENT( "%s: HDLC Tx up: failed to allocate memory!\n",
chan->card->devname);
chan->card->wandev.stats.rx_dropped++;
chan->ifstats.rx_dropped++;
return;
}
if (chan->common.usedby==STACK){
if (wanpipe_lip_rx(chan,skb) != 0){
dev_kfree_skb_any(skb);
chan->card->wandev.stats.rx_dropped++;
chan->ifstats.rx_dropped++;
}else{
chan->card->wandev.stats.rx_packets++;
chan->card->wandev.stats.rx_bytes += chan->rx_decode_len;
chan->ifstats.rx_packets++;
chan->ifstats.rx_bytes+=chan->rx_decode_len;
}
}else if (chan->common.usedby==API || chan->common.usedby==SWITCH){
buf = skb_put(skb,sizeof(api_rx_hdr_t));
memset(buf, 0, sizeof(api_rx_hdr_t));
buf = skb_put(skb,chan->rx_decode_len);
memcpy(buf,
chan->rx_decode_buf,
chan->rx_decode_len);
skb->protocol = htons(PVC_PROT);
wan_skb_reset_mac_header(skb);
skb->dev = chan->common.dev;
skb->pkt_type = WAN_PACKET_DATA;
if (wan_api_rx(chan,skb) != 0){
dev_kfree_skb_any(skb);
chan->card->wandev.stats.rx_dropped++;
chan->ifstats.rx_dropped++;
}else{
chan->card->wandev.stats.rx_packets++;
chan->card->wandev.stats.rx_bytes += chan->rx_decode_len;
chan->ifstats.rx_packets++;
chan->ifstats.rx_bytes+=chan->rx_decode_len;
}
}else{
if (chan->rx_decode_len <= 2){
dev_kfree_skb_any(skb);
chan->card->wandev.stats.rx_frame_errors++;
chan->ifstats.rx_frame_errors++;
}else{
skb_reserve(skb,4);
buf=skb_put(skb,(chan->rx_decode_len-2));
memcpy(buf,
chan->rx_decode_buf,
chan->rx_decode_len-2);
chan->card->wandev.stats.rx_packets++;
chan->card->wandev.stats.rx_bytes += chan->rx_decode_len;
chan->ifstats.rx_packets++;
chan->ifstats.rx_bytes+=chan->rx_decode_len;
wan_skb_reset_mac_header(skb);
skb->dev = chan->common.dev;
if (chan->protocol == WANCONFIG_PPP ||
chan->protocol == WANCONFIG_CHDLC){
skb->protocol = htons(ETH_P_WAN_PPP);
wp_sppp_input(chan->common.dev,skb);
}else{
skb->protocol = htons(ETH_P_IP);
netif_rx(skb);
}
}
}
return;
}
static void init_rx_hdlc_eng(sdla_t *card, bitstrm_private_area_t *bstrm_priv_area, int hard)
{
if (hard){
bstrm_priv_area->hdlc_flag=0;
set_bit(NO_FLAG,&bstrm_priv_area->hdlc_flag);
}
bstrm_priv_area->rx_decode_len=0;
bstrm_priv_area->rx_decode_buf[bstrm_priv_area->rx_decode_len]=0;
bstrm_priv_area->rx_decode_bit_cnt=0;
bstrm_priv_area->rx_decode_onecnt=0;
bstrm_priv_area->rx_crc[0]=-1;
bstrm_priv_area->rx_crc[1]=-1;
bstrm_priv_area->rx_crc[2]=-1;
bstrm_priv_area->crc_cur=0;
bstrm_priv_area->crc_prv=0;
}
static int hdlc_encode(bitstrm_private_area_t *chan,struct sk_buff **skb_ptr)
{
struct sk_buff *skb=*skb_ptr;
unsigned char crc_tmp;
int i;
unsigned char *data_ptr;
#if 0
chan->tx_decode_len=0;
/* First byte of the outgoing bit stream must be a flag.
* The current flag has been properly bit shifted based on the
* last packet we sent */
DEBUG_TX("TX: Flag Idle 0x%02X, Offset Data 0x%02X, BitCnt %i\n",
chan->tx_flag_idle,chan->tx_flag_offset_data,chan->tx_flag_offset);
chan->tx_decode_buf[chan->tx_decode_len] = chan->tx_flag_idle;
chan->tx_decode_len++;
chan->tx_decode_buf[chan->tx_decode_len] = chan->tx_flag_idle;
chan->tx_decode_len++;
/* Initialize the next byte in the encode buffer as
* well as the crc bytes */
chan->tx_decode_buf[chan->tx_decode_len]=0;
chan->tx_crc=-1;
chan->tx_crc_fin=0;
/* Before encoding data bytes, we must update the bit
* shift offset, casued by previous bit suffing. This,
* will shift the whole data packet by maximum of 7 bits */
chan->tx_decode_bit_cnt=chan->tx_flag_offset;
chan->tx_decode_buf[chan->tx_decode_len]=chan->tx_flag_offset_data;
chan->tx_decode_onecnt=0;
#else
chan->tx_decode_len=0;
chan->tx_crc=-1;
chan->tx_crc_fin=0;
chan->tx_decode_onecnt=0;
memset(&chan->tx_decode_buf[0],0,3);
chan->tx_decode_bit_cnt=0;
#ifdef HDLC_IDLE_ABORT
chan->tx_flag_idle=0x7E;
chan->tx_flag_offset_data=0;
chan->tx_flag_offset=0;
encode_byte(chan,&chan->tx_flag_idle,2);
#else
encode_byte(chan,&chan->tx_flag_idle,2);
encode_byte(chan,&chan->tx_flag_idle,2);
encode_byte(chan,&chan->tx_flag_offset_data,2);
if (!chan->seven_bit_hdlc || chan->tx_flag_offset < 5){
chan->tx_decode_len--;
}
#endif
DEBUG_TX("TX: Flag Idle 0x%02X, Offset Data 0x%02X, FlagBitCnt %i, DataBitCnt %i\n",
chan->tx_flag_idle,
chan->tx_flag_offset_data,
chan->tx_flag_offset,
chan->tx_decode_bit_cnt);
if (chan->seven_bit_hdlc){
chan->tx_decode_bit_cnt=
((chan->tx_flag_offset+2)%chan->bits_in_byte);
}else{
chan->tx_decode_bit_cnt=chan->tx_flag_offset;
}
DEBUG_TX("TX: DataBitCnt %i\n",
chan->tx_decode_bit_cnt);
chan->tx_decode_onecnt=0;
#endif
/* For all bytes in an incoming data packet, calculate
* crc bytes, and encode each byte into the outgoing
* bit stream (encoding buffer). */
for (i=0;i<skb->len;i++){
calc_tx_crc(chan,skb->data[i]);
encode_byte(chan,&skb->data[i],0);
}
/* Decode and bit shift the calculated CRC values */
FLIP_CRC(chan->tx_crc,chan->tx_crc_fin);
DECODE_CRC(chan->tx_crc_fin);
/* Encode the crc values into the bit stream
* encode buffer */
crc_tmp=(chan->tx_crc_fin>>8)&0xFF;
encode_byte(chan,&crc_tmp,0);
crc_tmp=(chan->tx_crc_fin)&0xFF;
encode_byte(chan,&crc_tmp,0);
/* End the bit stream encode buffer with the
* closing flag */
encode_byte(chan,&chan->tx_flag,1);
#ifdef HDLC_IDLE_ABORT
chan->tx_flag_idle=0xFF;
chan->tx_flag_offset_data=0;
encode_byte(chan,&chan->tx_flag_idle,2);
#endif
/* We will re-use the incoming skb buffer to
* store the newly created encoded bit stream.
* Therefore, reset the skb buffer to 0, thus
* erasing the incoming data packet */
skb_trim(skb,0);
/* Make sure that the current skb buffer has
* enough room to hold the newly created encoded
* bit stream. Due to bit stuffing, hdlc headers
* and crc the encoded bit stream is bigger than
* the incoming data packet. If we need more room
* reallocate a new buffer */
if (skb_tailroom(skb) < chan->tx_decode_len){
struct sk_buff *skb2 = NULL;
skb2 = dev_alloc_skb(chan->tx_decode_len+15);
if (!skb2){
return -ENOMEM;
}
wan_dev_kfree_skb(skb,FREE_WRITE);
skb=skb2;
*skb_ptr=skb2;
wan_skb_unlink(skb);
}
/* Copy the encoded bit stream into the skb buffer which will be
* sent down to the card */
data_ptr=skb_put(skb,chan->tx_decode_len);
memcpy(data_ptr,chan->tx_decode_buf,chan->tx_decode_len);
#if 0
{
int i;
DEBUG_EVENT( "ENCPKT: ");
for (i=0;i<chan->tx_decode_len;i++){
printk("%02X ", chan->tx_decode_buf[i]);
}
printk("\n");
DEBUG_EVENT( "\n");
}
#endif
/* Reset the encode buffer */
chan->tx_decode_len=0;
/* Record the tx idle flag that
* should follow after this packet
* is sent out the port */
skb->cb[0]=chan->tx_flag_idle;
#if 0
{
int i;
unsigned char *data=wan_skb_data(skb);
DEBUG_EVENT("PKT: ");
for (i=0;i<wan_skb_len(skb);i++){
printk("%02X ",data[i]);
}
printk("\n");
}
#endif
return 0;
}
static void encode_byte (bitstrm_private_area_t *chan, unsigned char *byte_ptr, int flag)
{
int j;
unsigned long byte=*byte_ptr;
for (j=0;j<BITSINBYTE;j++){
if (test_bit(j,&byte)){
/* Got 1 */
chan->tx_decode_buf[chan->tx_decode_len] |= (1<< chan->tx_decode_bit_cnt);
if (++chan->tx_decode_bit_cnt >= chan->bits_in_byte){
++chan->tx_decode_len;
chan->tx_decode_buf[chan->tx_decode_len]=0;
chan->tx_decode_bit_cnt=0;
}
if (++chan->tx_decode_onecnt == 5){
/* Stuff a zero bit */
if (!flag){
if (++chan->tx_decode_bit_cnt >= chan->bits_in_byte){
++chan->tx_decode_len;
chan->tx_decode_buf[chan->tx_decode_len]=0;
chan->tx_decode_bit_cnt=0;
}
}
chan->tx_decode_onecnt=0;
}
}else{
/* Got 0 */
chan->tx_decode_onecnt=0;
if (++chan->tx_decode_bit_cnt >= chan->bits_in_byte){
++chan->tx_decode_len;
chan->tx_decode_buf[chan->tx_decode_len]=0;
chan->tx_decode_bit_cnt=0;
}
}
}
if (flag == 1){
/* The closing flag has been encoded into the
* buffer. We must check how much has the last flag
* bit shifted due to bit stuffing of previous data.
* The maximum bit shift is 7 bits, thus a standard
* flag 0x7E can be have 7 different values. The
* FLAG buffer will give us a correct flag, based
* on the bit shift count. */
chan->tx_flag_idle = FLAG[chan->tx_decode_bit_cnt];
chan->tx_flag_offset=chan->tx_decode_bit_cnt;
/* The bit shifted part of the flag, that crossed the byte
* boudary, must be saved, and inserted at the beginning of
* the next outgoing packet */
chan->tx_flag_offset_data=chan->tx_decode_buf[chan->tx_decode_len];
}
return;
}
/****** Interrupt Handlers **************************************************/
/*============================================================================
* Cisco HDLC interrupt service routine.
*/
static WAN_IRQ_RETVAL wpbit_isr (sdla_t* card)
{
unsigned char intr_type = 0x00;
GLOBAL_INFORMATION_STRUCT global_info;
int i;
if (!card->hw){
WAN_IRQ_RETURN(WAN_IRQ_HANDLED);
}
card->statistics.isr_entry++;
/* if critical due to peripheral operations
* ie. update() or getstats() then reset the interrupt and
* wait for the board to retrigger.
*/
if(test_bit(PERI_CRIT, (void*)&card->wandev.critical)) {
DEBUG_EVENT( "ISR CRIT TO PERI\n");
goto isr_done;
}
card->hw_iface.peek(card->hw, card->intr_type_off, &intr_type, 1);
switch(intr_type) {
case RX_APP_INT_PEND: /* 0x01: receive interrupt */
card->statistics.isr_rx++;
rx_intr(card);
break;
case TX_APP_INT_PEND: /* 0x02: transmit interrupt */
card->statistics.isr_tx++;
// Do not disable Tx interrupt
// for TE1 cards.
if(card->u.b.serial) {
card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TX_BLOCK);
}
if (!card->u.b.sw_card){
tasklet_hi_schedule(&card->u.b.wanpipe_tx_task);
}else{
bstrm_tx_bh((unsigned long)card);
}
break;
case COMMAND_COMPLETE_APP_INT_PEND:/* 0x04: cmd cplt */
++ card->timer_int_enabled;
break;
case BSTRM_EXCEP_COND_APP_INT_PEND: /* 0x20 */
process_bstrm_exception(card);
break;
case GLOBAL_EXCEP_COND_APP_INT_PEND:
process_global_exception(card);
if (IS_56K_CARD(card) || IS_TE1_CARD(card)) {
FRONT_END_STATUS_STRUCT FE_status;
card->hw_iface.peek(card->hw, card->fe_status_off,
&FE_status, sizeof(FE_status));
FE_status.opp_flag = 0x01;
card->hw_iface.poke(card->hw, card->fe_status_off,
&FE_status, sizeof(FE_status));
}
break;
case TIMER_APP_INT_PEND:
timer_intr(card);
break;
default:
card->statistics.isr_spurious++;
DEBUG_EVENT( "%s: spurious interrupt 0x%02X!\n",
card->devname, intr_type);
card->hw_iface.peek(card->hw, card->flags_off + offsetof(SHARED_MEMORY_INFO_STRUCT, global_info_struct),
&global_info, sizeof(global_info));
DEBUG_EVENT( "Code name: ");
for(i = 0; i < 4; i ++){
printk("%c", global_info.code_name[i]);
}
printk("\n");
DEBUG_EVENT( "\nCode version: ");
for(i = 0; i < 4; i ++){
printk("%c", global_info.code_version[i]);
}
printk("\n");
break;
}
isr_done:
clear_bit(0,&card->in_isr);
card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00);
WAN_IRQ_RETURN(WAN_IRQ_HANDLED);
}
/*============================================================================
* Receive interrupt handler.
*/
static void rx_intr (sdla_t* card)
{
BSTRM_DATA_RX_STATUS_EL_STRUCT rxbuf;
struct sk_buff *skb;
unsigned len;
unsigned addr;
unsigned char *buf;
int i;
card->hw_iface.peek(card->hw, card->u.b.rxmb_off, &rxbuf, sizeof(rxbuf));
addr = rxbuf.ptr_data_bfr;
if (rxbuf.opp_flag != 0x01) {
GLOBAL_INFORMATION_STRUCT global_info;
card->hw_iface.peek(card->hw, card->flags_off + offsetof(SHARED_MEMORY_INFO_STRUCT, global_info_struct),
&global_info, sizeof(global_info));
DEBUG_EVENT(
"%s: corrupted Rx buffer @ 0x%X, flag = 0x%02X!\n",
card->devname, (unsigned)card->u.b.rxmb_off, rxbuf.opp_flag);
DEBUG_EVENT( "Code name: ");
for(i = 0; i < 4; i ++)
DEBUG_EVENT( "%c",
global_info.code_name[i]);
DEBUG_EVENT( "\nCode version: ");
for(i = 0; i < 4; i ++)
DEBUG_EVENT( "%c",
global_info.code_version[i]);
DEBUG_EVENT( "\n");
/* Bug Fix: Mar 6 2000
* If we get a corrupted mailbox, it measn that driver
* is out of sync with the firmware. There is no recovery.
* If we don't turn off all interrupts for this card
* the machine will crash.
*/
DEBUG_EVENT( "%s: Critical router failure ...!!!\n", card->devname);
DEBUG_EVENT( "Please contact Sangoma Technologies !\n");
bstrm_set_intr_mode(card,0);
return;
}
len = rxbuf.block_length;
if (len != card->u.b.cfg.rx_complete_length){
DEBUG_EVENT( "%s: Invalid rx packet: Len=%i < %i\n",
card->devname,len,card->u.b.cfg.rx_complete_length);
}
/* Obtain a free skb packet from the bh rx queue.
* The packet has been pre allocated to the max rx
* size */
skb = bh_enqueue(card);
if (!skb){
++card->wandev.stats.rx_dropped;
if (net_ratelimit()){
DEBUG_EVENT( "%s: Critical Error! Rx dropped Rx CH Free=%i Full=%i\n",
card->devname,
wan_skb_queue_len(&card->u.b.rx_isr_queue),
wan_skb_queue_len(&card->u.b.rx_isr_free_queue));
}
goto kick_rx_bh;
}
buf = skb_put(skb, len);
card->hw_iface.peek(card->hw, addr, buf, len);
// DEBUG_EVENT( "PKT (rxbug=%lX, addr=%X, len=%d): ", (unsigned long)card->u.b.rxmb, addr,len);
// {
// int i, flag;
// for (i=0;i<len;i++){
// if (i < 10) printk("%02X ",buf[i]);
// }
// printk("\n");
// }
if (card->u.b.cfg.rbs_map){
int channel_range = GET_TE_CHANNEL_RANGE(&card->fe);
card->hw_iface.peek(card->hw, card->fe.te_param.ptr_te_Rx_sig_off,
&card->u.b.rbs_sig[0], channel_range);
//card->hw_iface.peek(card->hw, card->u_fe.te_iface.ptr_te_Rx_sig_off,
// &card->u.b.rbs_sig[0], channel_range);
}
skb_queue_tail(&card->u.b.rx_isr_queue,skb);
kick_rx_bh:
if (!card->u.b.sw_card){
tasklet_hi_schedule(&card->u.b.wanpipe_rx_task);
}else{
bstrm_rx_bh((u32)card);
}
/* Release buffer element and calculate a pointer to the next one */
rxbuf.opp_flag = 0x00;
card->hw_iface.poke(card->hw, card->u.b.rxmb_off, &rxbuf, sizeof(rxbuf));
card->u.b.rxmb_off += sizeof(rxbuf);
if (card->u.b.rxmb_off > card->u.b.rxbuf_last_off){
card->u.b.rxmb_off = card->u.b.rxbuf_base_off;
}
}
/*============================================================================
* Timer interrupt handler.
* The timer interrupt is used for two purposes:
* 1) Processing udp calls from 'cpipemon'.
* 2) Reading board-level statistics for updating the proc file system.
*/
void timer_intr(sdla_t *card)
{
netdevice_t* dev;
bitstrm_private_area_t* bstrm_priv_area = NULL;
/* TE timer interrupt */
if (card->u.b.timer_int_enabled & TMR_INT_ENABLED_TE) {
card->wandev.fe_iface.polling(&card->fe);
bstrm_handle_front_end_state(card);
card->u.b.timer_int_enabled &= ~TMR_INT_ENABLED_TE;
}
dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head));
if (dev == NULL){
card->u.b.timer_int_enabled = 0;
goto timer_intr_exit;
}
bstrm_priv_area = dev->priv;
/* process a udp call if pending */
#if 0
if(card->u.b.timer_int_enabled & TMR_INT_ENABLED_UDP) {
process_udp_mgmt_pkt(card, dev, bstrm_priv_area);
card->u.b.timer_int_enabled &= ~TMR_INT_ENABLED_UDP;
}
#endif
/* read the communications statistics if required */
if(card->u.b.timer_int_enabled & TMR_INT_ENABLED_UPDATE) {
update_comms_stats(card, bstrm_priv_area);
if(!(--bstrm_priv_area->update_comms_stats)) {
card->u.b.timer_int_enabled &=
~TMR_INT_ENABLED_UPDATE;
}
}
timer_intr_exit:
/* only disable the timer interrupt if there are no udp or statistic */
/* updates pending */
if(!card->u.b.timer_int_enabled) {
card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER);
}
}
/*------------------------------------------------------------------------------
Miscellaneous Functions
- set_bstrm_config() used to set configuration options on the board
------------------------------------------------------------------------------*/
static int set_bstrm_config(sdla_t* card)
{
BSTRM_CONFIGURATION_STRUCT cfg;
int rc;
//wan_mbox_t* mb = &card->wan_mbox;
memset(&cfg, 0, sizeof(BSTRM_CONFIGURATION_STRUCT));
if(card->wandev.clocking){
cfg.baud_rate = card->wandev.bps;
}
cfg.line_config_options = (card->wandev.interface == WANOPT_RS232) ?
INTERFACE_LEVEL_RS232 : INTERFACE_LEVEL_V35;
cfg.modem_config_options = 0;
cfg.modem_status_timer = 500;
cfg.API_options = 0; /*PERMIT_APP_INT_TX_RX_BFR_ERR*/
DEBUG_EVENT("%s: Sync Options = 0x%X\n",
card->devname, card->u.b.cfg.sync_options);
cfg.SYNC_options = card->u.b.cfg.sync_options;
cfg.Rx_sync_char = card->u.b.cfg.rx_sync_char;
cfg.monosync_Tx_time_fill_char = card->u.b.cfg.monosync_tx_time_fill_char;
cfg.buffer_options=0;
cfg.max_length_Tx_data_block = card->u.b.cfg.max_length_tx_data_block;
cfg.Rx_complete_length = card->u.b.cfg.rx_complete_length;
cfg.Rx_complete_timer = card->u.b.cfg.rx_complete_timer;
cfg.statistics_options = TX_DATA_BYTE_COUNT_STAT |
RX_DATA_BYTE_COUNT_STAT |
TX_THROUGHPUT_STAT |
RX_THROUGHPUT_STAT;
rc = bstrm_configure(card, &cfg);
return rc;
}
/*============================================================================
* Process global exception condition
*/
static int process_global_exception(sdla_t *card)
{
wan_mbox_t* mbox = &card->wan_mbox;
int rc;
mbox->wan_data_len = 0;
mbox->wan_command = READ_GLOBAL_EXCEPTION_CONDITION;
rc = card->hw_iface.cmd(card->hw, card->mbox_off, mbox);
if(rc != WAN_CMD_TIMEOUT ){
switch(mbox->wan_return_code) {
case EXCEP_MODEM_STATUS_CHANGE:
if (IS_TE1_CARD(card)){
card->wandev.fe_iface.isr(&card->fe);
bstrm_handle_front_end_state(card);
break;
}
if (IS_56K_CARD(card)) {
FRONT_END_STATUS_STRUCT FE_status;
card->hw_iface.peek(card->hw,
card->fe_status_off,
&FE_status,
sizeof(FE_status));
card->fe.fe_param.k56_param.RR8_reg_56k =
FE_status.FE_U.stat_56k.RR8_56k;
card->fe.fe_param.k56_param.RRA_reg_56k =
FE_status.FE_U.stat_56k.RRA_56k;
card->fe.fe_param.k56_param.RRC_reg_56k =
FE_status.FE_U.stat_56k.RRC_56k;
card->wandev.fe_iface.read_alarm(&card->fe, 0);
bstrm_handle_front_end_state(card);
break;
}
DEBUG_EVENT( "%s: Modem status change\n",
card->devname);
switch(mbox->wan_data[0] & (DCD_HIGH | CTS_HIGH)) {
case (DCD_HIGH):
DEBUG_EVENT( "%s: DCD high, CTS low\n",card->devname);
break;
case (CTS_HIGH):
DEBUG_EVENT( "%s: DCD low, CTS high\n",card->devname);
break;
case ((DCD_HIGH | CTS_HIGH)):
DEBUG_EVENT( "%s: DCD high, CTS high\n",card->devname);
break;
default:
DEBUG_EVENT( "%s: DCD low, CTS low\n",card->devname);
break;
}
break;
default:
DEBUG_EVENT( "%s: Global exception %x\n",
card->devname, mbox->wan_return_code);
break;
}
}
return 0;
}
/*============================================================================
* Process chdlc exception condition
*/
static int process_bstrm_exception(sdla_t *card)
{
wan_mbox_t* mb = &card->wan_mbox;
int rc;
mb->wan_data_len = 0;
mb->wan_command = READ_BSTRM_EXCEPTION_CONDITION;
rc = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if(rc != WAN_CMD_TIMEOUT) {
switch (rc) {
case NO_BSTRM_EXCEP_COND_TO_REPORT:
DEBUG_EVENT( "%s: No exceptions reported.\n",
card->devname);
break;
case EXCEP_RX_DISCARD:
case EXCEP_TX_IDLE:
{
RX_DISC_TX_IDLE_EXCEP_STRUCT *idle_strct =
(RX_DISC_TX_IDLE_EXCEP_STRUCT *)mb->wan_data;
if (idle_strct->Rx_discard_count){
DEBUG_EVENT( "%s: Error Rx discard %lu\n",
card->devname,idle_strct->Rx_discard_count);
}
if (idle_strct->Tx_idle_count){
DEBUG_EVENT( "%s: Error Tx idle count %lu\n",
card->devname,idle_strct->Tx_idle_count);
}
}
break;
case EXCEP_SYNC_LOST:
DEBUG_EVENT("%s: Bitstrm Exception: Sync Lost!\n",card->devname);
break;
case EXCEP_SYNC_ACHIEVED:
DEBUG_EVENT("%s: Bitstrm Exception: Sync Achieved!\n",card->devname);
break;
default:
DEBUG_EVENT( "%s: Bstrm Exception condition 0x%X\n",
card->devname,rc);
break;
}
}
return 0;
}
/*=============================================================================
* Process UDP management packet.
*/
static int process_udp_mgmt_pkt(sdla_t* card, netdevice_t* dev,
bitstrm_private_area_t* bstrm_priv_area,
char local_dev)
{
unsigned char *buf;
unsigned int len;
struct sk_buff *new_skb;
int udp_mgmt_req_valid = 1;
wan_udp_pkt_t *wan_udp_pkt;
wan_mbox_t *mb = &card->wan_mbox;
struct timeval tv;
int err;
wan_udp_pkt = (wan_udp_pkt_t *) bstrm_priv_area->udp_pkt_data;
if(!local_dev){
if(bstrm_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){
/* Only these commands are support for remote debugging.
* All others are not */
switch(wan_udp_pkt->wan_udp_command){
case READ_GLOBAL_STATISTICS:
case READ_MODEM_STATUS:
case READ_BSTRM_STATUS:
case READ_COMMS_ERROR_STATS:
case READ_BSTRM_OPERATIONAL_STATS:
case BPIPE_ROUTER_UP_TIME:
/* These two commands are executed for
* each request */
case READ_BSTRM_CONFIGURATION:
case READ_BSTRM_CODE_VERSION:
udp_mgmt_req_valid = 1;
break;
default:
udp_mgmt_req_valid = 0;
break;
}
}
}else{
udp_mgmt_req_valid=1;
}
if(!udp_mgmt_req_valid) {
/* set length to 0 */
wan_udp_pkt->wan_udp_data_len = 0;
/* set return code */
wan_udp_pkt->wan_udp_return_code = 0xCD;
if (net_ratelimit()){
DEBUG_EVENT(
"%s: Warning, Illegal UDP command attempted from network: %x\n",
card->devname,wan_udp_pkt->wan_udp_command);
}
} else {
switch(wan_udp_pkt->wan_udp_command) {
case BPIPE_ROUTER_UP_TIME:
do_gettimeofday( &tv );
bstrm_priv_area->router_up_time = tv.tv_sec -
bstrm_priv_area->router_start_time;
*(unsigned long *)&wan_udp_pkt->wan_udp_data =
bstrm_priv_area->router_up_time;
mb->wan_data_len = sizeof(unsigned long);
wan_udp_pkt->wan_udp_data_len = sizeof(unsigned long);
wan_udp_pkt->wan_udp_return_code = 0;
break;
case WAN_GET_MEDIA_TYPE:
case WAN_FE_GET_STAT:
case WAN_FE_SET_LB_MODE:
case WAN_FE_FLUSH_PMON:
case WAN_FE_GET_CFG:
if (IS_TE1_CARD(card)){
card->wandev.fe_iface.process_udp(
&card->fe,
&wan_udp_pkt->wan_udp_cmd,
&wan_udp_pkt->wan_udp_data[0]);
}else if (IS_56K_CARD(card)){
card->wandev.fe_iface.process_udp(
&card->fe,
&wan_udp_pkt->wan_udp_cmd,
&wan_udp_pkt->wan_udp_data[0]);
}else{
if (wan_udp_pkt->wan_udp_command == WAN_GET_MEDIA_TYPE){
wan_udp_pkt->wan_udp_data_len = sizeof(unsigned char);
wan_udp_pkt->wan_udp_return_code = CMD_OK;
}else{
wan_udp_pkt->wan_udp_return_code = WAN_UDP_INVALID_CMD;
}
}
mb->wan_data_len = wan_udp_pkt->wan_udp_data_len;
break;
case WAN_GET_PROTOCOL:
wan_udp_pkt->wan_udp_chdlc_num_frames = card->wandev.config_id;
wan_udp_pkt->wan_udp_return_code = CMD_OK;
mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1;
break;
case WAN_GET_PLATFORM:
wan_udp_pkt->wan_udp_data[0] = WAN_LINUX_PLATFORM;
wan_udp_pkt->wan_udp_return_code = CMD_OK;
mb->wan_data_len = wan_udp_pkt->wan_udp_data_len = 1;
break;
#ifdef LINEPROBE
case ENABLE_BSTRM_COMMUNICATIONS:
DEBUG_DBG("%s: process_udp_mgmt_pkt(): ENABLE_BSTRM_COMMUNICATIONS\n",card->devname);
if (IS_TE1_CARD(card)){
/*
* If application enables communications, there
* must be no alarms.If no alarms, manualy (arg
* 2 is 1) poll the alarms again to set the
* Front End to the correct state. */
card->wandev.fe_iface.read_alarm(&card->fe, 1);
setup_api_timeslots(card);
}
wan_udp_pkt->wan_udp_return_code = api_enable_comms(card);
break;
case DISABLE_BSTRM_COMMUNICATIONS:
DEBUG_DBG("%s: process_udp_mgmt_pkt():DISABLE_BSTRM_COMMUNICATIONS\n",card->devname);
wan_udp_pkt->wan_udp_return_code = api_disable_comms(card);
break;
#endif //LINEPROBE
default:
/* it's a board command */
mb->wan_command = wan_udp_pkt->wan_udp_command;
mb->wan_data_len = wan_udp_pkt->wan_udp_data_len;
if (mb->wan_data_len) {
memcpy(&mb->wan_data,
(unsigned char *)wan_udp_pkt->wan_udp_data,
mb->wan_data_len);
}
/* run the command on the board */
err = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if (err == OK) {
/* copy the result back to our buffer */
memcpy(&wan_udp_pkt->wan_udp_cmd, mb, sizeof(wan_cmd_t));
if (mb->wan_data_len) {
memcpy(&wan_udp_pkt->wan_udp_data,
&mb->wan_data,
mb->wan_data_len);
}
}
}
} /* end of else */
/* Fill UDP TTL */
wan_udp_pkt->wan_ip_ttl= card->wandev.ttl;
if (local_dev){
wan_udp_pkt->wan_udp_request_reply = UDPMGMT_REPLY;
return 0;
}
len = wan_reply_udp(card,bstrm_priv_area->udp_pkt_data, mb->wan_data_len);
if(bstrm_priv_area->udp_pkt_src == UDP_PKT_FRM_NETWORK){
/* Must check if we interrupted if_send() routine. The
* tx buffers might be used. If so drop the packet */
//if (!test_bit(SEND_CRIT,&card->wandev.critical)) {
//
// if(!bstrm_send(card, bstrm_priv_area->udp_pkt_data, len)) {
// ++ card->wandev.stats.tx_packets;
// card->wandev.stats.tx_bytes += len;
// }
//}
} else {
/* Pass it up the stack
Allocate socket buffer */
if ((new_skb = dev_alloc_skb(len)) != NULL) {
/* copy data into new_skb */
buf = skb_put(new_skb, len);
memcpy(buf, bstrm_priv_area->udp_pkt_data, len);
/* Decapsulate pkt and pass it up the protocol stack */
new_skb->protocol = htons(ETH_P_IP);
new_skb->dev = dev;
wan_skb_reset_mac_header(new_skb);
netif_rx(new_skb);
} else {
DEBUG_EVENT( "%s: no socket buffers available!\n",
card->devname);
}
}
atomic_set(&bstrm_priv_area->udp_pkt_len,0);
return 0;
}
#ifdef LINEPROBE
static int api_enable_comms(sdla_t * card)
{
int rc;
if (IS_TE1_CARD(card)){
if (card->fe.fe_status == FE_CONNECTED) {
if (card->u.b.state != WAN_CONNECTED) {
if(card->comm_enabled == 0) {
rc = bstrm_comm_enable (card);
if (rc == 0){
port_set_state(card, WAN_CONNECTED);
}
}else{
rc = COMMS_ALREADY_ENABLED;
}
}else{
rc = IF_IN_DISCONNECED_STATE;
}
}else{
rc = FRONT_END_IN_DISCONNECTED_STATE;
}
}else{
rc = 0;
/* FIXME: Remove this line */
card->fe.fe_status = FE_CONNECTED;
card->u.b.state = WAN_DISCONNECTED;
port_set_state(card, WAN_CONNECTED);
}
DEBUG_DBG("api_enable_comms(): rc : 0x%X\n", rc);
return rc;
}
static int api_disable_comms(sdla_t* card)
{
int rc;
port_set_state(card, WAN_DISCONNECTED);
if(card->comm_enabled != 0) {
rc = bstrm_comm_disable (card);
}else{
rc = COMMS_ALREADY_DISABLED;
}
DEBUG_DBG("api_disable_comms(): rc : 0x%X\n", rc);
return rc;
}
static int setup_api_timeslots(sdla_t* card)
{
int i;
bitstrm_private_area_t* bstrm_priv_area;
netdevice_t* dev;
dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head));
if (!dev) return -EINVAL;
bstrm_priv_area = dev->priv;
memset(card->u.b.time_slot_map,0,sizeof(card->u.b.time_slot_map));
bstrm_priv_area->time_slot_map = 0xFFFFFFFF;
card->u.b.time_slots=NUM_OF_T1_CHANNELS;
if (IS_E1_CARD(card)){
bstrm_priv_area->time_slot_map &= 0x7FFFFFFF;
card->u.b.time_slots=NUM_OF_E1_CHANNELS;
}
bstrm_priv_area->max_tx_up_size=MAX_T1_CHAN_TX_UP_SIZE;
if (IS_E1_CARD(card)){
//must be divisible by 31 and less than MAX_T1_CHAN_TX_UP_SIZE.
bstrm_priv_area->max_tx_up_size =
MAX_T1_CHAN_TX_UP_SIZE - (MAX_T1_CHAN_TX_UP_SIZE % (NUM_OF_E1_CHANNELS-1));//1178
}
bstrm_priv_area->time_slots = 0;
for (i=0;i<card->u.b.time_slots;i++){
if (test_bit(i,&bstrm_priv_area->time_slot_map)){
bstrm_priv_area->time_slots++;
}
}
if (bstrm_priv_area->max_tx_up_size % bstrm_priv_area->time_slots){
bstrm_priv_area->max_tx_up_size-=
bstrm_priv_area->max_tx_up_size %
bstrm_priv_area->time_slots;
bstrm_priv_area->max_tx_up_size+=bstrm_priv_area->time_slots;
}
DEBUG_DBG("\n");
DEBUG_DBG("%s: Configuring %s: \n",
card->devname,
bstrm_priv_area->if_name);
DEBUG_DBG("%s: Tx Idle Flag =0x%X\n",
card->devname,
bstrm_priv_area->tx_idle_flag);
DEBUG_DBG("%s: Max Tx Up Size =%i\n",
card->devname,
bstrm_priv_area->max_tx_up_size);
DEBUG_DBG("%s: HDLC Enc/Dec =%s Bits=%d\n",
card->devname,
bstrm_priv_area->hdlc_eng?"ON":"OFF",
bstrm_priv_area->seven_bit_hdlc?7:8);
bstrm_priv_area->hdlc_flag=0;
set_bit(NO_FLAG,&bstrm_priv_area->hdlc_flag);
DEBUG_DBG("\n");
bstrm_priv_area->rx_crc[0]=-1;
bstrm_priv_area->rx_crc[1]=-1;
bstrm_priv_area->rx_crc[2]=-1;
bstrm_priv_area->tx_crc=-1;
bstrm_priv_area->tx_flag= 0x7E; //card->u.b.cfg.monosync_tx_time_fill_char;
bstrm_priv_area->tx_flag_idle= 0x7E; //card->u.b.cfg.monosync_tx_time_fill_char;
if (IS_TE1_CARD(card)){
DEBUG_DBG("%s: entering bind loop (card->u.b.time_slots : %d).\n",
card->devname, card->u.b.time_slots);
/*Bind an interface to a time slot map.*/
for (i=0;i<card->u.b.time_slots;i++){
if (test_bit(i,&bstrm_priv_area->time_slot_map)){
if (IS_E1_CARD(card)){
DEBUG_DBG("Binding interface %s for timeslot %i\n",
bstrm_priv_area->if_name, i+1);
card->u.b.time_slot_map[i+1] = bstrm_priv_area;
}else{
DEBUG_DBG("Binding interface %s for timeslot %i\n",
bstrm_priv_area->if_name, i);
card->u.b.time_slot_map[i] = bstrm_priv_area;
}
bstrm_priv_area->time_slots++;
}
}
}
card->u.b.tx_chan_multiple = 30;
DEBUG_DBG("%s: Configuring: \n",card->devname);
if (IS_TE1_CARD(card)){
DEBUG_DBG("%s: ChanNum =%i\n",
card->devname, card->u.b.time_slots);
DEBUG_DBG("%s: TxChanMult =%i\n",
card->devname, card->u.b.tx_chan_multiple);
}
DEBUG_DBG("%s: TxMTU =%i\n",
card->devname, card->u.b.cfg.max_length_tx_data_block);
DEBUG_DBG("%s: RxMTU =%i\n",
card->devname, card->u.b.cfg.rx_complete_length);
DEBUG_DBG("%s: IdleFlag =0x%x\n",
card->devname,
card->u.b.cfg.monosync_tx_time_fill_char);
return 0;
}
#endif //LINEPROBE
/*============================================================================
* Initialize Receive and Transmit Buffers.
*/
static void init_bstrm_tx_rx_buff( sdla_t* card)
{
wan_mbox_t* mb = &card->wan_mbox;
unsigned long tx_config_off = 0;
unsigned long rx_config_off = 0;
BSTRM_TX_STATUS_EL_CFG_STRUCT tx_config;
BSTRM_RX_STATUS_EL_CFG_STRUCT rx_config;
char err;
mb->wan_data_len = 0;
mb->wan_command = READ_BSTRM_CONFIGURATION;
err = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if(err != OK) {
netdevice_t *dev;
dev = WAN_DEVLE2DEV(WAN_LIST_FIRST(&card->wandev.dev_head));
if (dev){
bstrm_error(card,err,mb);
}
return;
}
tx_config_off = ((BSTRM_CONFIGURATION_STRUCT *)mb->wan_data)->
ptr_Tx_stat_el_cfg_struct;
card->hw_iface.peek(card->hw, tx_config_off, &tx_config, sizeof(tx_config));
rx_config_off = ((BSTRM_CONFIGURATION_STRUCT *)mb->wan_data)->
ptr_Rx_stat_el_cfg_struct;
card->hw_iface.peek(card->hw, rx_config_off, &rx_config, sizeof(rx_config));
/* Setup Head and Tails for buffers */
card->u.b.txbuf_base_off = tx_config.base_addr_Tx_status_elements;
card->u.b.txbuf_last_off =
card->u.b.txbuf_base_off +
(tx_config.number_Tx_status_elements - 1) * sizeof(BSTRM_DATA_TX_STATUS_EL_STRUCT);
card->u.b.rxbuf_base_off = rx_config.base_addr_Rx_status_elements;
card->u.b.rxbuf_last_off =
card->u.b.rxbuf_base_off +
(rx_config.number_Rx_status_elements - 1) * sizeof(BSTRM_DATA_RX_STATUS_EL_STRUCT);
/* Set up next pointer to be used */
card->u.b.txbuf_off = tx_config.next_Tx_status_element_to_use;
card->u.b.rxmb_off = rx_config.next_Rx_status_element_to_use;
/* Setup Actual Buffer Start and end addresses */
card->u.b.rx_base_off = rx_config.base_addr_Rx_status_elements;
}
/*=============================================================================
* Perform Interrupt Test by running READ_BSTRM_CODE_VERSION command MAX_INTR
* _TEST_COUNTER times.
*/
static int intr_test( sdla_t* card)
{
wan_mbox_t* mb = &card->wan_mbox;
int err,i;
card->timer_int_enabled = 0;
err = bstrm_set_intr_mode(card, APP_INT_ON_COMMAND_COMPLETE);
if (err == CMD_OK) {
for (i = 0; i < MAX_INTR_TEST_COUNTER; i ++) {
mb->wan_data_len = 0;
mb->wan_command = READ_BSTRM_CODE_VERSION;
err = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if (err != CMD_OK)
bstrm_error(card, err, mb);
}
}
else {
return err;
}
err = bstrm_set_intr_mode(card, 0);
if (err != CMD_OK)
return err;
return 0;
}
/*============================================================================
* Set PORT state.
*/
static void port_set_state (sdla_t *card, int state)
{
struct wan_dev_le *devle;
netdevice_t *dev;
bitstrm_private_area_t *bstrm_priv_area;
if (card->u.b.state != state)
{
switch (state)
{
case WAN_CONNECTED:
printk (KERN_INFO "%s: Link connected!\n",
card->devname);
break;
case WAN_CONNECTING:
printk (KERN_INFO "%s: Link connecting...\n",
card->devname);
break;
case WAN_DISCONNECTED:
printk (KERN_INFO "%s: Link disconnected!\n",
card->devname);
break;
}
card->wandev.state = card->u.b.state = state;
WAN_LIST_FOREACH(devle, &card->wandev.dev_head, dev_link){
dev = WAN_DEVLE2DEV(devle);
if (!dev || !wan_netif_priv(dev)) continue;
bstrm_priv_area = wan_netif_priv(dev);
if (IS_TE1_CARD(card) &&
bstrm_priv_area->common.usedby == SWITCH &&
state == WAN_CONNECTED){
bitstrm_private_area_t *sw_chan;
sdla_t *sw_card;
if (!bstrm_priv_area->sw_dev){
DEBUG_EVENT( "%s: Switch not present: Skip connect \n",
bstrm_priv_area->common.dev->name);
continue;
}
sw_chan=(bitstrm_private_area_t *)bstrm_priv_area->sw_dev->priv;
sw_card=sw_chan->card;
if (!sw_card->comm_enabled){
DEBUG_EVENT( "%s: Switch not connected: %s \n",
bstrm_priv_area->common.dev->name,
bstrm_priv_area->sw_dev->name);
continue;
}else{
DEBUG_EVENT( "%s: Setting switch to connected %s\n",
bstrm_priv_area->common.dev->name,
bstrm_priv_area->sw_dev->name);
set_bit(WAIT_DEVICE_SLOW,&bstrm_priv_area->tq_control);
set_bit(WAIT_DEVICE_FAST,&sw_chan->tq_control);
sw_chan->common.state = WAN_CONNECTED;
}
}
bstrm_priv_area->common.state = state;
if (bstrm_priv_area->common.usedby == STACK){
if (state == WAN_CONNECTED){
wanpipe_lip_connect(bstrm_priv_area,0);
}else{
wanpipe_lip_disconnect(bstrm_priv_area,0);
}
}else if (bstrm_priv_area->common.usedby == API){
wan_wakeup_api(bstrm_priv_area);
wan_update_api_state(bstrm_priv_area);
}else if (bstrm_priv_area->common.usedby == WANPIPE){
wake_net_dev(dev);
}
/* Reset the T1 channel tx idle flag, on T1 restart,
* when HDLC engine is running */
if (bstrm_priv_area->hdlc_eng && state == WAN_DISCONNECTED){
bstrm_priv_area->tx_idle_flag=0x7E;
}
if (bstrm_priv_area->protocol == WANCONFIG_PPP && state == WAN_DISCONNECTED){
send_ppp_term_request(dev);
}
if (IS_TE1_CARD(card) &&
state == WAN_DISCONNECTED){
struct sk_buff *skb;
bstrm_skb_queue_purge(&bstrm_priv_area->tx_queue);
while((skb = skb_dequeue(&bstrm_priv_area->rx_used_queue))!=NULL){
skb->data=(skb->head+16);
skb->len=1;
skb_trim(skb,0);
skb_queue_tail(&bstrm_priv_area->rx_free_queue,skb);
}
if (bstrm_priv_area->common.usedby==SWITCH){
set_bit(WAIT_DEVICE_BUFFERS,&bstrm_priv_area->tq_control);
}
}
}
}
}
/*===========================================================================
* config_bstrm
*
* Configure the chdlc protocol and enable communications.
*
* The if_open() function binds this function to the poll routine.
* Therefore, this function will run every time the chdlc interface
* is brought up. We cannot run this function from the if_open
* because if_open does not have access to the remote IP address.
*
* If the communications are not enabled, proceed to configure
* the card and enable communications.
*
* If the communications are enabled, it means that the interface
* was shutdown by ether the user or driver. In this case, we
* have to check that the IP addresses have not changed. If
* the IP addresses have changed, we have to reconfigure the firmware
* and update the changed IP addresses. Otherwise, just exit.
*
*/
static int config_bstrm (sdla_t *card)
{
int err;
if (card->comm_enabled){
return 0;
}
card->hw_iface.poke_byte(card->hw, card->intr_type_off, 0x00);
card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00);
/* Setup the Board for BSTRM */
if ((err=set_bstrm_config(card))) {
printk (KERN_INFO "%s: Failed BSTRM configuration! rc=0x%X\n",
card->devname,err);
return -EINVAL;
}
if (IS_TE1_CARD(card)) {
if (bstrm_set_FE_config(card)){
DEBUG_EVENT( "%s: Failed Rx discard/Tx idle configuration!\n",
card->devname);
return -EINVAL;
}
if (IS_T1_CARD(card) && card->u.b.cfg.rbs_map){
err=bstrm_set_te_signaling_config(card,card->u.b.cfg.rbs_map);
if (err){
return -EINVAL;
}
err=bstrm_read_te_signaling_config(card);
if (err){
return -EINVAL;
}
}
DEBUG_EVENT( "%s: Configuring onboard %s CSU/DSU\n",
card->devname,
(IS_T1_CARD(card))?"T1":"E1");
err = -EINVAL;
if (card->wandev.fe_iface.config){
err = card->wandev.fe_iface.config(&card->fe);
}
if (err){
DEBUG_EVENT("%s: Failed %s configuration!\n",
card->devname,
(IS_T1_CARD(card))?"T1":"E1");
return -EINVAL;
}
}
if (IS_56K_CARD(card)) {
printk(KERN_INFO "%s: Configuring 56K onboard CSU/DSU\n",
card->devname);
err = -EINVAL;
if (card->wandev.fe_iface.config){
err = card->wandev.fe_iface.config(&card->fe);
}
if (err){
DEBUG_EVENT("%s: Failed 56K configuration!\n",
card->devname);
return -EINVAL;
}
}
if (card->u.b.serial){
/* Set interrupt mode and mask */
if (bstrm_set_intr_mode(card, APP_INT_ON_RX_BLOCK |
APP_INT_ON_GLOBAL_EXCEP_COND |
APP_INT_ON_BSTRM_EXCEP_COND | APP_INT_ON_TIMER)){
printk (KERN_INFO "%s: Failed to set interrupt triggers!\n",
card->devname);
return -EINVAL;
}
}else{
/* Set interrupt mode and mask */
if (bstrm_set_intr_mode(card, APP_INT_ON_RX_BLOCK |
APP_INT_ON_GLOBAL_EXCEP_COND |
APP_INT_ON_TX_BLOCK |
APP_INT_ON_BSTRM_EXCEP_COND | APP_INT_ON_TIMER)){
printk (KERN_INFO "%s: Failed to set interrupt triggers!\n",
card->devname);
return -EINVAL;
}
}
/* Initialize Rx/Tx buffer control fields */
init_bstrm_tx_rx_buff(card);
if(IS_TE1_CARD(card) && card->wandev.ignore_front_end_status == WANOPT_NO) {
port_set_state(card, WAN_DISCONNECTED);
}else if (IS_56K_CARD(card) && card->wandev.ignore_front_end_status == WANOPT_NO) {
port_set_state(card, WAN_DISCONNECTED);
}else{
if (bstrm_comm_enable(card) != 0) {
DEBUG_EVENT("%s: Failed to enable bitstrm communications!\n",
card->devname);
card->hw_iface.poke_byte(card->hw, card->intr_perm_off, 0x00);
card->comm_enabled=0;
bstrm_set_intr_mode(card,0);
return -EINVAL;
}
port_set_state(card, WAN_CONNECTED);
DEBUG_EVENT("%s: Communications enabled on startup\n",
card->devname);
}
/* Manually poll the 56K CSU/DSU to get the status */
if (IS_56K_CARD(card)) {
/* 56K Update CSU/DSU alarms */
card->wandev.fe_iface.read_alarm(&card->fe, 1);
}
/* For TE1 cards, do not mask out the TX interrupt.
* The Tx interrupt must send idle data for
* each DS0 channel */
if (!card->u.b.serial){
card->hw_iface.clear_bit(card->hw, card->intr_perm_off, APP_INT_ON_TIMER);
}else{
card->hw_iface.clear_bit(card->hw, card->intr_perm_off,
(APP_INT_ON_TIMER | APP_INT_ON_TX_BLOCK));
}
DEBUG_EVENT("%s: Config complete\n",card->devname);
return 0;
}
static int bstrm_get_config_info(void* priv, struct seq_file* m, int* stop_cnt)
{
wan_device_t* wandev = (wan_device_t*)priv;
sdla_t* card = NULL;
if (wandev == NULL || wandev->private == NULL)
return 0;
card = (sdla_t*)wandev->private;
if (!card->comm_enabled){
DEBUG_EVENT( "DEBUG: Enable communication for Bit Streaming protocol\n");
bstrm_comm_enable (card);
}else{
DEBUG_EVENT( "DEBUG: Communication is already enabled\n");
}
return m->count;
}
// TE1
static int set_adapter_config (sdla_t* card)
{
wan_mbox_t* mb = &card->wan_mbox;
ADAPTER_CONFIGURATION_STRUCT* cfg = (ADAPTER_CONFIGURATION_STRUCT*)mb->wan_data;
int err;
card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &cfg->adapter_type);
if (IS_TE1_CARD(card) && card->u.b.serial){
DEBUG_EVENT("%s: Configuring Front End in Unframed Mode!\n",
card->devname);
cfg->adapter_type|=OPERATE_T1E1_AS_SERIAL;
}
cfg->adapter_config = 0x00;
cfg->operating_frequency = 00;
mb->wan_data_len = sizeof(ADAPTER_CONFIGURATION_STRUCT);
mb->wan_command = SET_ADAPTER_CONFIGURATION;
err = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if(err != OK) {
bstrm_error(card,err,mb);
}
return (err);
}
static void bstrm_handle_front_end_state(void* card_id)
{
sdla_t* card = (sdla_t*)card_id;
if (card->wandev.ignore_front_end_status == WANOPT_YES) {
return;
}
if (card->fe.fe_status == FE_CONNECTED) {
if (card->u.b.state != WAN_CONNECTED) {
if(card->comm_enabled == 0) {
if (bstrm_comm_enable (card) == 0){
DEBUG_EVENT( "%s: Communications enabled\n",
card->devname);
port_set_state(card, WAN_CONNECTED);
}else{
DEBUG_EVENT( "%s: Failed to enable communications\n",
card->devname);
}
}
}
}else{
port_set_state(card, WAN_DISCONNECTED);
if(card->comm_enabled != 0) {
DEBUG_EVENT( "%s: Communications disabled\n",
card->devname);
bstrm_comm_disable (card);
}
}
}
static int bstrm_comm_disable (sdla_t *card)
{
wan_mbox_t* mb = &card->wan_mbox;
int err;
mb->wan_command = DISABLE_BSTRM_COMMUNICATIONS;
mb->wan_data_len = 0;
err = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
card->comm_enabled = 0;
return 0;
}
#define WAN_BSTRM_CHUNK 8
static int bstrm_set_FE_config (sdla_t *card)
{
wan_mbox_t* mb = &card->wan_mbox;
int err;
FE_RX_DISC_TX_IDLE_STRUCT FE_str;
int i;
if (IS_FR_FEUNFRAMED(&card->fe)){
return 0;
}
if (IS_T1_CARD(card)){
FE_str.lgth_Rx_disc_bfr = card->u.b.time_slots * WAN_BSTRM_CHUNK;
FE_str.lgth_Tx_idle_bfr = card->u.b.time_slots * WAN_BSTRM_CHUNK;
}else{
FE_str.lgth_Rx_disc_bfr = card->u.b.time_slots * WAN_BSTRM_CHUNK;
FE_str.lgth_Tx_idle_bfr = (card->u.b.time_slots-1) * WAN_BSTRM_CHUNK;
}
FE_str.Tx_idle_data_bfr[0]=card->u.b.cfg.monosync_tx_time_fill_char;
for(i = 1; i < NO_ACTIVE_TX_TIME_SLOTS_E1; i ++) {
FE_str.Tx_idle_data_bfr[i] = card->u.b.cfg.monosync_tx_time_fill_char;
}
mb->wan_data_len = sizeof(FE_RX_DISC_TX_IDLE_STRUCT);
memcpy(mb->wan_data, &FE_str.lgth_Rx_disc_bfr, mb->wan_data_len);
mb->wan_command = SET_FE_RX_DISC_TX_IDLE_CFG;
err = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if(err != OK){
bstrm_error(card,err,mb);
}
return err;
}
static int bstrm_bind_dev_switch (sdla_t *card, bitstrm_private_area_t*chan, char *sw_dev_name)
{
bitstrm_private_area_t *sw_chan;
netdevice_t *sw_dev;
sdla_t *sw_card;
unsigned long smp_flags;
if (chan->sw_dev){
return 0;
}
sw_dev = dev_get_by_name(sw_dev_name);
if (!sw_dev){
DEBUG_EVENT( "%s: Device %s waiting for switch device %s\n",
card->devname, chan->if_name,sw_dev_name);
DEBUG_EVENT( "%s: Device %s not found\n",
card->devname, sw_dev_name);
return 0;
}
if (!sw_dev->priv){
DEBUG_EVENT( "%s: Error: Invalid switch device %s: not wanpipe device!\n",
card->devname, sw_dev->name);
dev_put(sw_dev);
return -EINVAL;
}
if (((wanpipe_common_t*)sw_dev->priv)->usedby != SWITCH){
DEBUG_EVENT( "%s: Error: Device %s not configured for switching\n",
card->devname, sw_dev->name);
dev_put(sw_dev);
return -EINVAL;
}
if (((wanpipe_common_t*)sw_dev->priv)->config_id != card->wandev.config_id){
DEBUG_EVENT( "%s: Error: Invalid switch device (%s) config id 0x%x\n",
card->devname, sw_dev->name,((wanpipe_common_t*)sw_dev->priv)->config_id);
dev_put(sw_dev);
return -EINVAL;
}
sw_chan = (bitstrm_private_area_t *)sw_dev->priv;
sw_card = sw_chan->card;
if ((strcmp(sw_chan->sw_if_name,chan->if_name)) != 0){
DEBUG_EVENT( "%s: Error: Config mismatch: SW dev %s is not configured for switching!\n",
card->devname, sw_chan->if_name);
dev_put(sw_dev);
return -EINVAL;
}
DEBUG_EVENT( "%s:%s Device (ch=0x%lx) mapped to %s (ch=0x%lx)\n",
card->devname, chan->if_name, chan->time_slot_map,
sw_chan->if_name, sw_chan->time_slot_map);
wan_spin_lock_irq(&card->wandev.lock,&smp_flags);
if (!card->u.b.sw_card){
sw_card->u.b.sw_card = card;
card->u.b.sw_card=sw_card;
}
sw_chan->sw_dev = chan->common.dev;
chan->sw_dev = sw_dev;
wan_spin_unlock_irq(&card->wandev.lock,&smp_flags);
dev_hold(chan->common.dev);
return 0;
}
static int bstrm_unbind_dev_switch (sdla_t *card, bitstrm_private_area_t *chan)
{
if (chan->sw_dev){
bitstrm_private_area_t *sw_chan=chan->sw_dev->priv;
if (sw_chan){
if (sw_chan->sw_dev){
DEBUG_EVENT( "%s: Unbinding SW dev %s from %s\n",
card->devname, sw_chan->if_name, sw_chan->sw_dev->name);
dev_put(sw_chan->sw_dev);
sw_chan->sw_dev=NULL;
}
}
DEBUG_EVENT( "%s: Unbinding SW dev %s from %s\n",
card->devname, chan->if_name, chan->sw_dev->name);
dev_put(chan->sw_dev);
chan->sw_dev=NULL;
}
if (card->open_cnt == 1){
if (card->u.b.sw_card){
sdla_t *sw_card=card->u.b.sw_card;
sw_card->u.b.sw_card=NULL;
card->u.b.sw_card=NULL;
}
}
return 0;
}
static int protocol_init (sdla_t *card, netdevice_t *dev,
bitstrm_private_area_t *chan,
wanif_conf_t* conf)
{
struct ppp_device *pppdev;
struct sppp *sp;
if (chan->protocol != WANCONFIG_PPP &&
chan->protocol != WANCONFIG_CHDLC){
DEBUG_EVENT( "%s:%s: Unsupported protocol %i\n",
card->devname,chan->if_name,chan->protocol);
return -EPROTONOSUPPORT;
}
pppdev=kmalloc(sizeof(struct ppp_device),GFP_KERNEL);
if (!pppdev){
chan->protocol=0;
return -ENOMEM;
}
memset(pppdev,0,sizeof(struct ppp_device));
chan->common.prot_ptr=(void*)pppdev;
pppdev->dev=dev;
/* Get authentication info. */
if(conf->pap == WANOPT_YES){
pppdev->sppp.myauth.proto = PPP_PAP;
}else if(conf->chap == WANOPT_YES){
pppdev->sppp.myauth.proto = PPP_CHAP;
}else{
pppdev->sppp.myauth.proto = 0;
}
if(pppdev->sppp.myauth.proto){
memcpy(pppdev->sppp.myauth.name, conf->userid, AUTHNAMELEN);
memcpy(pppdev->sppp.myauth.secret, conf->passwd, AUTHNAMELEN);
}
pppdev->sppp.gateway = conf->gateway;
if (conf->if_down){
pppdev->sppp.dynamic_ip = 1;
}
sprintf(pppdev->sppp.hwdevname,"%s",card->devname);
wp_sppp_attach(pppdev);
sp = &pppdev->sppp;
dev->type = ARPHRD_PPP;
if (chan->protocol == WANCONFIG_CHDLC){
DEBUG_EVENT( "%s: Starting Kernel CISCO HDLC protocol\n",
card->devname);
sp->pp_flags |= PP_CISCO;
}else{
DEBUG_EVENT( "%s: Starting Kernel Sync PPP protocol\n",
card->devname);
sp->pp_flags &= ~PP_CISCO;
}
return 0;
}
static int protocol_start (sdla_t *card, netdevice_t *dev)
{
int err=0;
bitstrm_private_area_t *chan=dev->priv;
if (!chan)
return 0;
if (chan->protocol == WANCONFIG_PPP ||
chan->protocol == WANCONFIG_CHDLC){
if ((err=wp_sppp_open(dev)) != 0){
return err;
}
}
return err;
}
static int protocol_stop (sdla_t *card, netdevice_t *dev)
{
bitstrm_private_area_t *chan=dev->priv;
if (!chan)
return 0;
if (chan->protocol == WANCONFIG_PPP ||
chan->protocol == WANCONFIG_CHDLC){
wp_sppp_close(dev);
}
return 0;
}
static int protocol_shutdown (sdla_t *card, netdevice_t *dev)
{
bitstrm_private_area_t *chan=dev->priv;
if (!chan)
return 0;
if (chan->protocol == WANCONFIG_PPP ||
chan->protocol == WANCONFIG_CHDLC){
wp_sppp_detach(dev);
dev->do_ioctl = NULL;
dev->hard_header = NULL;
dev->rebuild_header = NULL;
if (chan->common.prot_ptr){
kfree(chan->common.prot_ptr);
chan->common.prot_ptr= NULL;
}
}
return 0;
}
static void send_ppp_term_request (netdevice_t *dev)
{
struct sk_buff *new_skb;
unsigned char *buf;
bitstrm_private_area_t *chan=dev->priv;
if (chan->ignore_modem)
return;
DEBUG_EVENT( "%s: (Debug) Wanpipe sending PPP TERM\n",dev->name);
if ((new_skb = dev_alloc_skb(8)) != NULL) {
/* copy data into new_skb */
buf = skb_put(new_skb, 8);
sprintf(buf,"%c%c%c%c%c%c%c%c", 0xFF,0x03,0xC0,0x21,0x05,0x98,0x00,0x07);
/* Decapsulate pkt and pass it up the protocol stack */
new_skb->protocol = htons(ETH_P_WAN_PPP);
new_skb->dev = dev;
wan_skb_reset_mac_header(new_skb);
wp_sppp_input(dev,new_skb);
}
}
static void
wanpipe_switch_datascope_tx_up(bitstrm_private_area_t *chan,struct sk_buff *skb)
{
struct sk_buff *new_skb;
sdla_t*card=chan->card;
api_rx_hdr_t *buf;
if (chan->common.sk == NULL){
return;
}
if (skb_headroom(skb) < sizeof(api_rx_hdr_t)){
new_skb=skb_copy_expand(skb,sizeof(api_rx_hdr_t),0,GFP_ATOMIC);
}else{
new_skb=skb_copy(skb,GFP_ATOMIC);
}
if (!new_skb){
DEBUG_EVENT( "%s: ERROR: Failed to clone skb buffer, no memory !\n",
card->devname);
return;
}
buf = (api_rx_hdr_t*)skb_push(new_skb,sizeof(api_rx_hdr_t));
memset(buf, 0, sizeof(api_rx_hdr_t));
buf->direction = 1;
new_skb->protocol = htons(PVC_PROT);
wan_skb_reset_mac_header(new_skb);
new_skb->dev = chan->common.dev;
new_skb->pkt_type = WAN_PACKET_DATA;
if (wan_api_rx(chan,new_skb) != 0){
/* Sock full cannot send, queue us for another
* try */
dev_kfree_skb_any(new_skb);
wan_wakeup_api(chan);
}
return;
}
static int bstrm_set_te_signaling_config (void* card_id, unsigned long ts_sig_map)
{
sdla_t* card = (sdla_t*)card_id;
wan_mbox_t* mb = &card->wan_mbox;
char* data = mb->wan_data;
int channel_range = (IS_T1_CARD(card)) ?
NUM_OF_T1_CHANNELS : NUM_OF_E1_CHANNELS;
int err, i;
DEBUG_TEST("%s: Set signalling config...\n",
card->devname);
memset((char *)&((te_signaling_cfg_t*)data)->sig_perm.time_slot[0],
TE_SIG_DISABLED,
sizeof(te_signaling_perm_t));
for(i = 0; i < channel_range; i ++) {
if (test_bit(i, (void*)&ts_sig_map)){
((te_signaling_cfg_t*)data)->sig_perm.time_slot[i]
= (TE_RX_SIG_ENABLED | TE_TX_SIG_ENABLED);
//= TE_RX_SIG_ENABLED;
}
}
((te_signaling_cfg_t *)data)->sig_processing_counter = 1;
mb->wan_data_len = sizeof(te_signaling_cfg_t);
mb->wan_command = SET_TE1_SIGNALING_CFG;
err = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if(err != OK){
DEBUG_EVENT("%s: Error: Failed Robbit SetCfg (map=0x%lX) (rc=0x%X)\n",
card->devname,ts_sig_map,err);
bstrm_error(card,err,mb);
}
return (err);
}
static int bstrm_disable_te_signaling (void* card_id, unsigned long ts_map)
{
sdla_t* card = (sdla_t*)card_id;
unsigned char ts_sig_perm[32];
int channel_range = GET_TE_CHANNEL_RANGE(&card->fe);
int i;
memset(ts_sig_perm, 0, sizeof(ts_sig_perm));
DEBUG_EVENT("%s: Disableing Robbit Signalling\n", card->devname);
for(i = 0; i < channel_range; i++){
if (test_bit(i, &ts_map)){
ts_sig_perm[i] = TE_SIG_DISABLED;
}
}
if (card->fe.te_param.ptr_te_sig_perm_off){
card->hw_iface.poke(card->hw, card->fe.te_param.ptr_te_sig_perm_off,
ts_sig_perm, channel_range);
}
// REMOVE it later!!
//if (card->u_fe.te_iface.ptr_te_sig_perm_off){
// card->hw_iface.poke(card->hw, card->u_fe.te_iface.ptr_te_sig_perm_off,
// ts_sig_perm, channel_range);
//}
return 0;
}
static int bstrm_read_te_signaling_config (void* card_id)
{
sdla_t* card = (sdla_t*)card_id;
wan_mbox_t* mb = &card->wan_mbox;
char* data = mb->wan_data;
int err;
DEBUG_CFG("%s: Read TE Signalling config...\n", card->devname);
((te_signaling_cfg_t *)data)->sig_processing_counter = 1;
mb->wan_data_len = 0;
mb->wan_command = READ_TE1_SIGNALING_CFG;
err = card->hw_iface.cmd(card->hw, card->mbox_off, mb);
if(err != OK) {
DEBUG_EVENT("%s: Failed to Read Robbit Signalling! (rc=0x%X)\n",
card->devname,err);
bstrm_error(card,err,mb);
}else{
//card->u_fe.te_iface.ptr_te_sig_perm_off =
card->fe.te_param.ptr_te_sig_perm_off =
((te_signaling_cfg_t *)data)->ptr_te_sig_perm_struct;
//card->u_fe.te_iface.ptr_te_Rx_sig_off =
card->fe.te_param.ptr_te_Rx_sig_off =
((te_signaling_cfg_t *)data)->ptr_te_Rx_sig_struct;
//card->u_fe.te_iface.ptr_te_Tx_sig_off =
card->fe.te_param.ptr_te_Tx_sig_off =
((te_signaling_cfg_t *)data)->ptr_te_Tx_sig_struct;
}
return (err);
}
/*===============================================================
* send_rbs_oob_msg
*
* Construct an OOB Robbit Signalling Message and pass it
* up the connected sock. If the sock is not bounded discard
* the NEM.
*
*===============================================================*/
static int send_rbs_oob_msg (sdla_t *card, bitstrm_private_area_t *chan)
{
unsigned char *buf;
api_rx_hdr_t *api_rx_el;
struct sk_buff *skb;
int err=0, len=5;
if (chan->common.usedby != API){
return -ENODEV;
}
if (!chan->common.sk){
return -ENODEV;
}
skb=wan_skb_alloc(sizeof(api_rx_hdr_t)+len);
if (!skb){
return -ENOMEM;
}
api_rx_el=(api_rx_hdr_t *)skb_put(skb,sizeof(api_rx_hdr_t));
memset(api_rx_el,0,sizeof(api_rx_hdr_t));
api_rx_el->channel=chan->rbs_chan;
buf = skb_put(skb,1);
if (!buf){
wan_skb_free(skb);
return -ENOMEM;
}
buf[0]=chan->rbs_sig;
skb->pkt_type = WAN_PACKET_ERR;
skb->protocol=htons(PVC_PROT);
skb->dev=chan->common.dev;
DEBUG_TEST("%s: Sending OOB message len=%i\n",
chan->if_name,skb->len);
if (wan_api_rx(chan,skb)!=0){
err=-ENODEV;
wan_skb_free(skb);
}
return err;
}