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

938 lines
26 KiB
C

/*****************************************************************************
* sdla_edu.c WANPIPE(tm) Multiprotocol WAN Link Driver. Educational kit module.
*
* Authors: David Rokhvarg <drokhvarg@sangoma.com>
*
*
* Copyright: (c) 2001 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.
* ============================================================================
* Sep 18, 2001 David Rokhvarg Initial version.
*
* Jul 30, 2003 David Rokhvarg v 1.0
* 1. sdla_load() is not used anymore,
* all the loading is done from user mode instead.
* All IOCTLs used for loading are not valid anymore.
* 2. New IOCTLs added for starting and stopping
* the card.
*
* Nov 17, 2004 David Rokhvarg v 2.0
* 1. Removed globals and put into private area
* 2. New IOCTLs added for TCP/IP handling.
*
******************************************************************************/
#include <linux/wanpipe_includes.h>
#include <linux/wanpipe_defines.h>
#include <linux/wanpipe.h> // sdla_t
#include <linux/sdla_chdlc.h> // for 'edu_kit.sfm' (which is actually CHDLC) firmware API definitions
#include <linux/sdla_edu.h> // educational package definitions
#include <linux/sdlapci.h> // S514_CPU_START
#include <linux/if_wanpipe_common.h> // Socket Driver common area
#include <linux/wanpipe_debug.h> // Socket Driver common area
/****** Defines & Macros ****************************************************/
//#define DEBUG //define this to get output when running general IOCTLs
//#define DEBUG_RW //define this to get output when reading/writing
/******Data Structures*****************************************************/
typedef struct edu_private_area
{
sdla_t* card;
unsigned char mc; /* Mulitcast support on/off */
unsigned long update_comms_stats; /* updating comms stats */
unsigned long router_start_time;
unsigned long interface_down;
unsigned long tick_counter; /* For 5s timeout counter */
u8 gateway;
u8 true_if_encoding;
/* Entry in proc fs per each interface */
struct proc_dir_entry* dent;
char if_name[WAN_IFNAME_SZ+1];
//the one and only network interface created
netdevice_t *net_dev;
//these 2 used to copy data from/to user mode
unsigned char data_buffer[MAX_TX_RX_DATA_SIZE];
edu_exec_cmd_t ioctl_cmd;
//temporary buffer for tx data. stored until 'EduKit' or
//if_tx_timeout() frees it.
TX_RX_DATA tmp_tx_data;
unsigned char tmp_tx_buff_state; //0 - free, 1 - busy
}edu_private_area_t;
/******** Globals *********************************************************/
/****** Function Prototypes *************************************************/
/* WAN link driver entry points. These are called by the WAN router module. */
static int wpedu_exec (struct sdla *card, void *u_cmd, void *u_data);
static void DoIoctl(sdla_t *card);
static void read_block(sdla_t *card);
static void write_block(sdla_t * card);
/* 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);
static void if_tx_timeout (netdevice_t *dev);
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);
static int edu_send ( sdla_t* card, edu_private_area_t *edu_priv_area,
void* data, unsigned len, unsigned char tx_bits);
static void handle_rx_data(sdla_t* card, TX_RX_DATA* rx_data);
/****** Public Functions ****************************************************/
/*============================================================================
* Module initialization routine.
*
* This routine is called by the main WANPIPE module during setup. At this
* point adapter is completely initialized and CHDLC 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 wpedu_init (sdla_t* card, wandev_conf_t* conf)
{
unsigned char port_num;
#ifdef DEBUG
volatile wan_mbox_t* mb;
wan_mbox_t* mb1;
DEBUG_CFG("%s: %s\n", __FUNCTION__, card->devname);
#endif
/* Verify configuration ID */
if (conf->config_id != WANCONFIG_EDUKIT) {
DEBUG_EVENT("%s: invalid configuration ID %u!\n",
card->devname, conf->config_id);
return -EINVAL;
}
/* runs only on S514, check it */
if(card->type != SDLA_S514){
DEBUG_EVENT("%s:Invalid card type! 0x%X\n",
card->devname , card->type);
return -EFAULT;
}
/* Use primary port */
card->u.c.comm_port = 0;
#ifdef DEBUG
/* Initialize protocol-specific fields */
card->mbox_off = PRI_BASE_ADDR_MB_STRUCT;
mb = mb1 = &card->wan_mbox;
#endif
card->isr = NULL;
card->poll = NULL;
card->exec = &wpedu_exec;
card->wandev.update = NULL;
card->wandev.new_if = &new_if;
card->wandev.del_if = &del_if;
card->wandev.state = WAN_DUALPORT;
card->wandev.udp_port = conf->udp_port;
card->wandev.new_if_cnt = 0;
/* This is for the ports link state */
card->u.c.state = WAN_DISCONNECTED;
/* reset the number of times the 'update()' proc has been called */
card->u.c.update_call_count = 0;
DEBUG_CFG("conf->ttl: %d\n", conf->ttl);
DEBUG_CFG("conf->mtu: %d\n", conf->mtu);
if(conf->ttl == 0){
card->wandev.ttl = 0x7F;
}else{
card->wandev.ttl = conf->ttl;
}
if(conf->mtu == 0){
card->wandev.mtu = 1500;
}else{
card->wandev.mtu = conf->mtu;
}
card->wandev.interface = 0;
card->wandev.clocking = 0;
port_num = card->u.c.comm_port;
/* Setup Port Bps */
card->wandev.bps = 0;
card->wandev.state = WAN_FT1_READY;
DEBUG_EVENT("%s: Educational Kit Module Ready!\n",card->devname);
return 0;
}
/*============================================================================
* new_if - Create new logical channel.
*
* &wandev: Wanpipe device pointer
* &dev: Network device pointer
* &conf: User configuration options pointer
*
* This routine is called by the ROUTER_IFNEW ioctl,
* in wanmain.c. The ioctl passes us the user configuration
* options which we use to configure the driver and
* firmware.
*
* This functions main purpose is to allocate the
* private structure for CHDLC protocol and bind it
* to dev->priv pointer.
*
* Also the dev->init pointer should also be initialized
* to the if_init() function.
*
* Any allocation necessary for the private strucutre
* should be done here, as well as proc/ file initializetion
* for the network interface.
*
* 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.
* o add network interface to the /proc/net/wanrouter
*
* The opposite of this function is del_if()
*
* 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)
{
sdla_t* card = wandev->private;
edu_private_area_t* edu_private_area;
int err = 0;
DEBUG_CFG("%s: Configuring Card: %s, Interface: %s\n",
__FUNCTION__, 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;
}
/* allocate and initialize private data */
edu_private_area = kmalloc(sizeof(edu_private_area_t), GFP_KERNEL);
if(edu_private_area == NULL){
WAN_MEM_ASSERT(card->devname);
return -ENOMEM;
}
memset(edu_private_area, 0, sizeof(edu_private_area_t));
edu_private_area->card = card;
strcpy(edu_private_area->if_name, conf->name);
//edukit always has only one interface, re-use 'tty_buf'
//to keep the pointer to the private area.
card->tty_buf = (unsigned char*)edu_private_area;
if (atomic_read(&card->wandev.if_cnt) > 0){
err=-EEXIST;
goto new_if_error;
}
/* Setup wanpipe as a router (WANPIPE) or as an API */
if( strcmp(conf->usedby, "WANPIPE") == 0) {
DEBUG_EVENT("%s: Running in WANPIPE mode!\n", wandev->name);
}else if( strcmp(conf->usedby, "API") == 0) {
DEBUG_EVENT("%s: Running in API mode!\n", wandev->name);
}else{
DEBUG_EVENT("%s:%s: Error: Invalid operation mode should be one of: [WANPIPE|API]\n",
card->devname,edu_private_area->if_name);
err=-EINVAL;
goto new_if_error;
}
/*
* Create interface file in proc fs.
* Once the proc file system is created, the new_if() function
* should exit successfuly.
*
* DO NOT place code under this function that can return
* anything else but 0.
*/
err = wanrouter_proc_add_interface(wandev,
&edu_private_area->dent,
edu_private_area->if_name,
dev);
if (err){
DEBUG_EVENT("%s: can't create /proc/net/router/edu/%s entry!\n",
card->devname, edu_private_area->if_name);
goto new_if_error;
}
/* Only setup the dev pointer once the new_if function has
* finished successfully. DO NOT place any code below that
* can return an error */
dev->init = &if_init;
dev->priv = edu_private_area;
edu_private_area->net_dev = dev;//pointer back to network device
atomic_inc(&card->wandev.if_cnt);
DEBUG_EVENT("\n");
return 0;
new_if_error:
kfree(edu_private_area);
dev->priv=NULL;
return err;
}
/*============================================================================
* del_if - Delete logical channel.
*
* @wandev: Wanpipe private device pointer
* @dev: Netowrk interface pointer
*
* This function is called by ROUTER_DELIF ioctl call
* to deallocate the network interface.
*
* The network interface and the private structure are
* about to be deallocated by the upper layer.
* We have to clean and deallocate any allocated memory.
*
*/
static int del_if (wan_device_t* wandev, netdevice_t* dev)
{
edu_private_area_t* edu_priv_area = dev->priv;
sdla_t* card = edu_priv_area->card;
DEBUG_CFG("%s: deleting: %s, %s\n", __FUNCTION__,
card->devname, dev->name);
/* Delete interface name from proc fs. */
wanrouter_proc_delete_interface(wandev, edu_priv_area->if_name);
atomic_dec(&card->wandev.if_cnt);
return 0;
}
/*============================================================================
* if_init - Initialize Linux network interface.
*
* @dev: Network interface pointer
*
* During "ifconfig up" the upper layer calls this function
* to initialize dev access pointers. Such as transmit,
* stats and header.
*
* It 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)
{
edu_private_area_t* edu_private_area = dev->priv;
sdla_t* card = edu_private_area->card;
//wan_device_t* wandev = &card->wandev;
DEBUG_CFG("%s: initializing %s, %s\n", __FUNCTION__,
card->devname, dev->name);
/* 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 */
dev->flags |= IFF_POINTOPOINT;
dev->flags |= IFF_NOARP;
/* Enable Mulitcasting if user selected */
if (edu_private_area->mc == WANOPT_YES){
dev->flags |= (IFF_MULTICAST|IFF_ALLMULTI);
}
if (edu_private_area->true_if_encoding){
dev->type = ARPHRD_HDLC; /* This breaks the tcpdump */
}else{
dev->type = ARPHRD_PPP;
}
dev->mtu = card->wandev.mtu;
dev->hard_header_len = 0;
dev->tx_queue_len = 100;
return 0;
}
/*============================================================================
* if_open - Open network interface.
*
* @dev: Network device pointer
*
* On ifconfig up, this function gets called in order
* to initialize and configure the private area.
* Driver should be configured to send and receive data.
*
* This functions starts a timer that will call
* chdlc_config() function. This function must be called
* because the IP addresses could have been changed
* for this interface.
*
* Return 0 if O.k. or errno.
*/
static int if_open (netdevice_t* dev)
{
edu_private_area_t* edu_priv_area = dev->priv;
sdla_t* card = edu_priv_area->card;
struct timeval tv;
int err = 0;
DEBUG_CFG("%s: opening %s, %s\n", __FUNCTION__,
card->devname, dev->name);
/* Only one open per interface is allowed */
if (open_dev_check(dev)){
DEBUG_CFG("%s: if_open(): open_dev_check() failed!\n", dev->name);
return -EBUSY;
}
do_gettimeofday(&tv);
edu_priv_area->router_start_time = tv.tv_sec;
netif_start_queue(dev);
/* Increment the module usage count */
wanpipe_open(card);
return err;
}
/*============================================================================
* if_close - Close network interface.
*
* @dev: Network device pointer
*
* On ifconfig down, this function gets called in order
* to cleanup interace private area.
*
* IMPORTANT:
*
* No deallocation or unconfiguration should ever occur in this
* function, because the interface can come back up
* (via ifconfig up).
*
* Furthermore, in dynamic interfacace configuration mode, the
* interface will come up and down to reflect the protocol state.
*
* Any private deallocation and cleanup can occur in del_if()
* function. That function is called before the dev interface
* itself is deallocated.
*
* Thus, we should only stop the net queue and decrement
* the wanpipe usage counter via wanpipe_close() function.
*/
static int if_close (netdevice_t* dev)
{
edu_private_area_t* edu_priv_area = dev->priv;
sdla_t* card = edu_priv_area->card;
DEBUG_CFG("%s: closing %s, %s\n", __FUNCTION__,
card->devname, dev->name);
stop_net_queue(dev);
#if defined(LINUX_2_1)
dev->start=0;
#endif
wanpipe_close(card);
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)
{
int err=0;
DEBUG_EVENT("%s: ioctl for: %s - Not implemented.\n",
__FUNCTION__, dev->name);
return err;
}
/*============================================================================
* Get ethernet-style interface statistics.
* Return a pointer to struct enet_statistics.
*/
static struct net_device_stats* if_stats (netdevice_t* dev)
{
sdla_t *my_card;
edu_private_area_t* edu_priv_area;
DEBUG_CFG("%s: stats for: %s\n", __FUNCTION__, dev->name);
if ((edu_priv_area=dev->priv) == NULL){
return NULL;
}
my_card = edu_priv_area->card;
return &my_card->wandev.stats;
}
/*============================================================================
* if_send - Send a packet on a network interface.
*
* @dev: Network interface pointer
* @skb: Packet obtained from the stack or API
* that should be sent out the port.
*
* 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 if the send is successful, otherwise
* return non zero value and push the packet back into
* the stack. Also set the tx interrupt to wake up the
* stack when the firmware is able to send.
*
* 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)
{
edu_private_area_t *edu_priv_area = dev->priv;
sdla_t *card = edu_priv_area->card;
int err = 0;
unsigned char misc_Tx_bits = 0;
void* data = skb->data;
unsigned len = skb->len;
DEBUG_TX("%s: tx called for: %s: interface %s.\n", __FUNCTION__,
card->devname, dev->name);
#if defined(LINUX_2_4)||defined(LINUX_2_6)
netif_stop_queue(dev);
#endif
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;
}
#if defined(LINUX_2_1)
if (dev->tbusy){
++card->wandev.stats.collisions;
if((jiffies - edu_priv_area->tick_counter) < (5 * HZ)) {
return 1;
}
if_tx_timeout (dev);
}
#endif
if(test_and_set_bit(SEND_CRIT, (void*)&card->wandev.critical)) {
DEBUG_EVENT("%s: Critical in if_send: %lx\n",
card->wandev.name,card->wandev.critical);
++card->wandev.stats.tx_dropped;
goto if_send_exit_crit;
}
err = edu_send(card, edu_priv_area, data, len, misc_Tx_bits);
if(err) {
err=-1;
}else{
#if defined(LINUX_2_4)||defined(LINUX_2_6)
dev->trans_start = jiffies;
#endif
}
if_send_exit_crit:
if (err==0){
wan_skb_free(skb);
start_net_queue(dev);
}else{
stop_net_queue(dev);
edu_priv_area->tick_counter = jiffies;
}
clear_bit(SEND_CRIT, (void*)&card->wandev.critical);
return err;
}
/*============================================================================
* Send packet.
* Return: 0 - o.k.
* 1 - no transmit buffers available
*/
static int edu_send ( sdla_t* card, edu_private_area_t *edu_priv_area,
void* data, unsigned len, unsigned char tx_bits)
{
unsigned char* ptr_data;
ptr_data = (unsigned char*)data;
DEBUG_TX("%s: called for: %s.\n", __FUNCTION__, card->devname);
//check data length
if(len >= MAX_TX_RX_DATA_SIZE){
DEBUG_EVENT("%s: tx data length (%u) greater than maximum (%u)!\n",
card->devname, len, MAX_TX_RX_DATA_SIZE);
return 1;
}
#if 0
//print out contents of the tx buffer passed from the stack
{
int i;
for(i=0; i < len; i++){
DEBUG_TX("data[%d]: 0x%02X\n", i, ptr_data[i]);
}
DEBUG_TX("\n");
}
#endif
if(edu_priv_area->tmp_tx_buff_state == 1){
//the buffer was not freed yet by the "edukut" app.
DEBUG_TX("%s: tx buff busy!!\n", card->devname);
return 2;
}
//set to busy
edu_priv_area->tmp_tx_buff_state = 1;
//store tx data for "edukit" app
memcpy(edu_priv_area->tmp_tx_data.data, data, len);
//store tx data length
edu_priv_area->tmp_tx_data.buffer_length = len;
return 0;
}
/*============================================================================
* Handle transmit timeout event from netif watchdog
*/
static void if_tx_timeout (netdevice_t *dev)
{
edu_private_area_t* chan = dev->priv;
sdla_t *card = chan->card;
DEBUG_TX("%s: called for: %s: interface %s.\n", __FUNCTION__,
card->devname, dev->name);
chan->tmp_tx_buff_state = 0;
/* 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;
DEBUG_EVENT("%s: Transmit timed out on %s\n", card->devname,dev->name);
netif_wake_queue (dev);
}
static int wpedu_exec(sdla_t *card, void *u_cmd, void *u_data)
{
edu_private_area_t* edu_private_area = (edu_private_area_t*)card->tty_buf;
edu_exec_cmd_t* ioctl_cmd = &edu_private_area->ioctl_cmd;
unsigned char* data_buffer = edu_private_area->data_buffer;
//copy command area
if (copy_from_user((void*)ioctl_cmd, u_cmd, sizeof(edu_exec_cmd_t))){
DEBUG_EVENT("copy_from_user((void*)&ioctl_cmd...) Failed!\n");
return -EFAULT;
}
//copy data
if (copy_from_user((void*)data_buffer, u_data, MAX_TX_RX_DATA_SIZE)){
DEBUG_EVENT("wpedu_exec():copy_from_user((void*)data_buffer...) Failed!\n");
return -EFAULT;
}
DoIoctl(card);
// return result
if( copy_to_user(u_cmd, (void*)ioctl_cmd, sizeof(edu_exec_cmd_t))){
DEBUG_EVENT("wpedu_exec():copy_to_user(u_cmd, ...) Failed!\n");
return -EFAULT;
}
if( copy_to_user(u_data, (void*)data_buffer, MAX_TX_RX_DATA_SIZE)){
DEBUG_EVENT("wpedu_exec():copy_to_user(u_data, ...) Failed!\n");
return -EFAULT;
}
return 0;
}
/*============================================================================
* Receive data handler.
*/
static void handle_rx_data(sdla_t* card, TX_RX_DATA* rx_data)
{
netdevice_t *dev;
edu_private_area_t* edu_private_area;
struct sk_buff *skb;
void *buf;
edu_private_area = (edu_private_area_t*)card->tty_buf;
dev = edu_private_area->net_dev;
/* Allocate socket buffer */
skb = dev_alloc_skb(rx_data->buffer_length + 2);
if (skb == NULL) {
DEBUG_EVENT("%s: no socket buffers available!\n",
card->devname);
++card->wandev.stats.rx_dropped;
goto rx_exit;
}
/* Align IP on 16 byte */
skb_reserve(skb, 2);
/* Copy data to the socket buffer */
buf = skb_put(skb, rx_data->buffer_length);
memcpy(buf, rx_data->data, rx_data->buffer_length);
skb->protocol = htons(ETH_P_IP);
/* Pass it up the protocol stack */
card->wandev.stats.rx_packets ++;
card->wandev.stats.rx_bytes += skb->len;
skb->protocol = htons(ETH_P_IP);
skb->dev = dev;
wan_skb_reset_mac_header(skb);
netif_rx(skb);
rx_exit:
return;
}
static void DoIoctl(sdla_t *card)
{
edu_private_area_t* edu_private_area = (edu_private_area_t*)card->tty_buf;
edu_exec_cmd_t* ioctl_cmd = &edu_private_area->ioctl_cmd;
TX_RX_DATA* tx_data = (TX_RX_DATA*)edu_private_area->data_buffer;
TX_RX_DATA* rx_data = (TX_RX_DATA*)edu_private_area->data_buffer;
unsigned short adapter_type;
switch(ioctl_cmd->ioctl)
{
case SDLA_CMD_READ_BLOCK:
DEBUG_IOCTL("SDLA_CMD_READ_BLOCK\n");
read_block(card);
break;
case SDLA_CMD_WRITE_BLOCK:
DEBUG_IOCTL("SDLA_CMD_WRITE_BLOCK\n");
write_block(card);
break;
case SDLA_CMD_REGISTER:
DEBUG_IOCTL("SDLA_CMD_REGISTER\n");
//This field will be used as a flag for determining if
//it is safe to (re)load the card.
//The flag is set to one before an application will load the card.
//No application will be able to reload the card until the flag is reset by
//SDLA_CMD_DEREGISTER.
if(card->wandev.interface == 0)
{ card->wandev.interface = 1;
ioctl_cmd->return_code = 0;
}else
{ //indicate failure to the caller
ioctl_cmd->return_code = 1;
}
break;
case SDLA_CMD_DEREGISTER:
DEBUG_IOCTL("SDLA_CMD_DEREGISTER\n");
card->wandev.interface = 0;
ioctl_cmd->return_code = 0;
break;
case SDLA_CMD_START_S514:
DEBUG_IOCTL("SDLA_CMD_START_S514\n");
//start the CPU directly
card->hw_iface.start(card->hw, 0x100);
// ALEX writeb (S514_CPU_START, card->hw.vector);
break;
case SDLA_CMD_STOP_S514:
DEBUG_IOCTL("SDLA_CMD_STOP_S514\n");
ioctl_cmd->return_code = card->hw_iface.hw_halt(card->hw);
break;
case SDLA_CMD_IS_TX_DATA_AVAILABLE:
DEBUG_IOCTL("SDLA_CMD_IS_TX_DATA_AVAILABLE\n");
if(edu_private_area->tmp_tx_buff_state == 1){
tx_data->status = TX_SUCCESS;
tx_data->buffer_length = edu_private_area->tmp_tx_data.buffer_length;
memcpy(tx_data->data, edu_private_area->tmp_tx_data.data,
edu_private_area->tmp_tx_data.buffer_length);
}
break;
case SDLA_CMD_COPLETE_TX_REQUEST:
DEBUG_IOCTL("SDLA_CMD_COPLETE_TX_REQUEST\n");
if(edu_private_area->tmp_tx_buff_state == 1){
DEBUG_IOCTL("tx reseting internal state...\n");
++card->wandev.stats.tx_packets;
card->wandev.stats.tx_bytes += edu_private_area->tmp_tx_data.buffer_length;
edu_private_area->tmp_tx_buff_state = 0;
netif_wake_queue (edu_private_area->net_dev);
}
break;
case SDLA_CMD_INDICATE_RX_DATA_AVAILABLE:
DEBUG_IOCTL("SDLA_CMD_INDICATE_RX_DATA_AVAILABLE\n");
handle_rx_data(card, rx_data);
break;
case SDLA_CMD_GET_PCI_ADAPTER_TYPE:
DEBUG_IOCTL("SDLA_CMD_GET_PCI_ADAPTER_TYPE\n");
card->hw_iface.getcfg(card->hw, SDLA_ADAPTERTYPE, &adapter_type);
DEBUG_IOCTL("adapter_type: 0x%X (%d)\n", adapter_type, adapter_type);
if(adapter_type == S5147_ADPTR_2_CPU_T1E1){
//for TE1 code to work adjust the card type
adapter_type = S5144_ADPTR_1_CPU_T1E1;
}
*(unsigned short*)edu_private_area->data_buffer = adapter_type;
DEBUG_IOCTL("Returning 0x%02X from SDLA_CMD_GET_PCI_ADAPTER_TYPE.\n",
*(unsigned short*)edu_private_area->data_buffer);
break;
default:
DEBUG_EVENT("%s: ********* Unknown IOCTL : 0x%x *********\n",
card->devname, ioctl_cmd->ioctl);
ioctl_cmd->return_code = 1;
break;
}
}
static void read_block(sdla_t *card)
{
edu_private_area_t* edu_private_area = (edu_private_area_t*)card->tty_buf;
edu_exec_cmd_t* ioctl_cmd = &edu_private_area->ioctl_cmd;
unsigned char* data_buffer = edu_private_area->data_buffer;
if(ioctl_cmd->buffer_length <= MAX_TX_RX_DATA_SIZE){
card->hw_iface.peek(card->hw, ioctl_cmd->offset, data_buffer, ioctl_cmd->buffer_length);
ioctl_cmd->return_code = 0;
}else{
DEBUG_EVENT("%s: SDLA_CMD_READ_BLOCK: invalid data length of %u!\n",
card->devname,
ioctl_cmd->buffer_length
);
ioctl_cmd->return_code = 1;
}
}
static void write_block(sdla_t * card)
{
edu_private_area_t* edu_private_area = (edu_private_area_t*)card->tty_buf;
edu_exec_cmd_t* ioctl_cmd = &edu_private_area->ioctl_cmd;
unsigned char* data_buffer = edu_private_area->data_buffer;
if( ioctl_cmd->buffer_length <= MAX_TX_RX_DATA_SIZE){
card->hw_iface.poke(card->hw, ioctl_cmd->offset, data_buffer, ioctl_cmd->buffer_length);
ioctl_cmd->return_code = 0;
}else{
DEBUG_EVENT("%s: SDLA_CMD_WRITE_BLOCK: invalid data length of %u!\n",
card->devname,
ioctl_cmd->buffer_length
);
ioctl_cmd->return_code = 1;
}
}