?? arlan.c
字號:
/* * Copyright (C) 1997 Cullen Jennings * Copyright (C) 1998 Elmer Joandiu, elmer@ylenurme.ee * GNU General Public License applies * This module provides support for the Arlan 655 card made by Aironet */#include <linux/config.h>#include "arlan.h"#if BITS_PER_LONG != 32# error FIXME: this driver requires a 32-bit platform#endifstatic const char *arlan_version = "C.Jennigs 97 & Elmer.Joandi@ut.ee Oct'98, http://www.ylenurme.ee/~elmer/655/";struct net_device *arlan_device[MAX_ARLANS];int last_arlan;static int SID = SIDUNKNOWN;static int radioNodeId = radioNodeIdUNKNOWN;static char encryptionKey[12] = {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h'};static char *siteName = siteNameUNKNOWN;static int mem = memUNKNOWN;int arlan_debug = debugUNKNOWN;static int probe = probeUNKNOWN;static int numDevices = numDevicesUNKNOWN;static int spreadingCode = spreadingCodeUNKNOWN;static int channelNumber = channelNumberUNKNOWN;static int channelSet = channelSetUNKNOWN;static int systemId = systemIdUNKNOWN;static int registrationMode = registrationModeUNKNOWN;static int keyStart;static int tx_delay_ms;static int retries = 5;static int async = 1;static int tx_queue_len = 1;static int arlan_EEPROM_bad;#ifdef ARLAN_DEBUGGINGstatic int arlan_entry_debug;static int arlan_exit_debug;static int testMemory = testMemoryUNKNOWN;static int irq = irqUNKNOWN;static int txScrambled = 1;static int mdebug;#endif#if LINUX_VERSION_CODE > 0x20100MODULE_PARM(irq, "i");MODULE_PARM(mem, "i");MODULE_PARM(probe, "i");MODULE_PARM(arlan_debug, "i");MODULE_PARM(numDevices, "i");MODULE_PARM(testMemory, "i");MODULE_PARM(spreadingCode, "i");MODULE_PARM(channelNumber, "i");MODULE_PARM(channelSet, "i");MODULE_PARM(systemId, "i");MODULE_PARM(registrationMode, "i");MODULE_PARM(radioNodeId, "i");MODULE_PARM(SID, "i");MODULE_PARM(txScrambled, "i");MODULE_PARM(keyStart, "i");MODULE_PARM(mdebug, "i");MODULE_PARM(tx_delay_ms, "i");MODULE_PARM(retries, "i");MODULE_PARM(async, "i");MODULE_PARM(tx_queue_len, "i");MODULE_PARM(arlan_entry_debug, "i");MODULE_PARM(arlan_exit_debug, "i");MODULE_PARM(arlan_entry_and_exit_debug, "i");MODULE_PARM(arlan_EEPROM_bad, "i");MODULE_PARM_DESC(irq, "(unused)");MODULE_PARM_DESC(mem, "Arlan memory address for single device probing");MODULE_PARM_DESC(probe, "Arlan probe at initialization (0-1)");MODULE_PARM_DESC(arlan_debug, "Arlan debug enable (0-1)");MODULE_PARM_DESC(numDevices, "Number of Arlan devices; ignored if >1");MODULE_PARM_DESC(testMemory, "(unused)");MODULE_PARM_DESC(mdebug, "Arlan multicast debugging (0-1)");MODULE_PARM_DESC(retries, "Arlan maximum packet retransmisions");#ifdef ARLAN_ENTRY_EXIT_DEBUGGINGMODULE_PARM_DESC(arlan_entry_debug, "Arlan driver function entry debugging");MODULE_PARM_DESC(arlan_exit_debug, "Arlan driver function exit debugging");MODULE_PARM_DESC(arlan_entry_and_exit_debug, "Arlan driver function entry and exit debugging");#elseMODULE_PARM_DESC(arlan_entry_debug, "(ignored)");MODULE_PARM_DESC(arlan_exit_debug, "(ignored)");MODULE_PARM_DESC(arlan_entry_and_exit_debug, "(ignored)");#endifEXPORT_SYMBOL(arlan_device);EXPORT_SYMBOL(arlan_conf);EXPORT_SYMBOL(last_arlan);// #warning kernel 2.1.110 tested#define myATOMIC_INIT(a,b) atomic_set(&(a),b)#else#define test_and_set_bit set_bit#if LINUX_VERSION_CODE != 0x20024 // #warning kernel 2.0.36 tested#endif#define myATOMIC_INIT(a,b) a = b;#endifstruct arlan_conf_stru arlan_conf[MAX_ARLANS];static int arlans_found;static int arlan_probe_here(struct net_device *dev, int ioaddr);static int arlan_open(struct net_device *dev);static int arlan_tx(struct sk_buff *skb, struct net_device *dev);static void arlan_interrupt(int irq, void *dev_id, struct pt_regs *regs);static int arlan_close(struct net_device *dev);static struct net_device_stats * arlan_statistics (struct net_device *dev);static void arlan_set_multicast (struct net_device *dev);static int arlan_hw_tx (struct net_device* dev, char *buf, int length );static int arlan_hw_config (struct net_device * dev);static void arlan_tx_done_interrupt (struct net_device * dev, int status);static void arlan_rx_interrupt (struct net_device * dev, u_char rxStatus, u_short, u_short);static void arlan_process_interrupt (struct net_device * dev);static void arlan_tx_timeout (struct net_device *dev);int arlan_command(struct net_device * dev, int command);EXPORT_SYMBOL(arlan_command);extern inline long long arlan_time(void){ struct timeval timev; do_gettimeofday(&timev); return ((long long) timev.tv_sec * 1000000 + timev.tv_usec);};#ifdef ARLAN_ENTRY_EXIT_DEBUGGING#define ARLAN_DEBUG_ENTRY(name) \ {\ struct timeval timev;\ do_gettimeofday(&timev);\ if (arlan_entry_debug || arlan_entry_and_exit_debug)\ printk("--->>>" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec));\ }#define ARLAN_DEBUG_EXIT(name) \ {\ struct timeval timev;\ do_gettimeofday(&timev);\ if (arlan_exit_debug || arlan_entry_and_exit_debug)\ printk("<<<---" name " %ld " "\n",((long int) timev.tv_sec * 1000000 + timev.tv_usec) );\ }#else#define ARLAN_DEBUG_ENTRY(name)#define ARLAN_DEBUG_EXIT(name)#endif#define arlan_interrupt_ack(dev)\ clearClearInterrupt(dev);\ setClearInterrupt(dev);#define ARLAN_COMMAND_LOCK(dev) \ if (atomic_dec_and_test(&((struct arlan_private * )dev->priv)->card_users))\ arlan_wait_command_complete_short(dev,__LINE__);#define ARLAN_COMMAND_UNLOCK(dev) \ atomic_inc(&((struct arlan_private * )dev->priv)->card_users);#define ARLAN_COMMAND_INC(dev) \ {((struct arlan_private *) dev->priv)->under_command++;}#define ARLAN_COMMAND_ZERO(dev) \ {((struct arlan_private *) dev->priv)->under_command =0;}#define ARLAN_UNDER_COMMAND(dev)\ (((struct arlan_private *) dev->priv)->under_command)#define ARLAN_COMMAND_START(dev) ARLAN_COMMAND_INC(dev)#define ARLAN_COMMAND_END(dev) ARLAN_COMMAND_ZERO(dev)#define ARLAN_TOGGLE_START(dev)\ {((struct arlan_private *) dev->priv)->under_toggle++;}#define ARLAN_TOGGLE_END(dev)\ {((struct arlan_private *) dev->priv)->under_toggle=0;}#define ARLAN_UNDER_TOGGLE(dev)\ (((struct arlan_private *) dev->priv)->under_toggle)extern inline int arlan_drop_tx(struct net_device *dev){ struct arlan_private *priv = ((struct arlan_private *) dev->priv); priv->stats.tx_errors++; if (priv->Conf->tx_delay_ms) { priv->tx_done_delayed = jiffies + priv->Conf->tx_delay_ms * HZ / 1000 + 1; } else { priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; TXHEAD(dev).offset = 0; TXTAIL(dev).offset = 0; priv->txLast = 0; priv->txOffset = 0; priv->bad = 0; if (!priv->under_reset && !priv->under_config) netif_wake_queue (dev); } return 1;};int arlan_command(struct net_device *dev, int command_p){ volatile struct arlan_shmem *arlan = ((struct arlan_private *) dev->priv)->card; struct arlan_conf_stru *conf = ((struct arlan_private *) dev->priv)->Conf; struct arlan_private *priv = (struct arlan_private *) dev->priv; int udelayed = 0; int i = 0; long long time_mks = arlan_time(); ARLAN_DEBUG_ENTRY("arlan_command"); if (priv->card_polling_interval) priv->card_polling_interval = 1; if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) printk(KERN_DEBUG "arlan_command, %lx lock %lx commandByte %x waiting %x incoming %x \n", jiffies, priv->command_lock, READSHMB(arlan->commandByte), priv->waiting_command_mask, command_p); priv->waiting_command_mask |= command_p; if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) if (jiffies - priv->lastReset < 5 * HZ) priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ACK) { arlan_interrupt_ack(dev); priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ACK; } if (priv->waiting_command_mask & ARLAN_COMMAND_INT_ENABLE) { setInterruptEnable(dev); priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_ENABLE; } /* Card access serializing lock */ if (test_and_set_bit(0, (void *) &priv->command_lock)) { if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) printk(KERN_DEBUG "arlan_command: entered when command locked \n"); goto command_busy_end; } /* Check cards status and waiting */ if (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) { while (priv->waiting_command_mask & (ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW)) { if (READSHMB(arlan->resetFlag) || READSHMB(arlan->commandByte)) /* || (readControlRegister(dev) & ARLAN_ACCESS)) */ udelay(40); else priv->waiting_command_mask &= ~(ARLAN_COMMAND_LONG_WAIT_NOW | ARLAN_COMMAND_WAIT_NOW); udelayed++; if (priv->waiting_command_mask & ARLAN_COMMAND_LONG_WAIT_NOW) { if (udelayed * 40 > 1000000) { printk(KERN_ERR "%s long wait too long \n", dev->name); priv->waiting_command_mask |= ARLAN_COMMAND_RESET; break; } } else if (priv->waiting_command_mask & ARLAN_COMMAND_WAIT_NOW) { if (udelayed * 40 > 1000) { printk(KERN_ERR "%s short wait too long \n", dev->name); goto bad_end; } } } } else { i = 0; while ((READSHMB(arlan->resetFlag) || READSHMB(arlan->commandByte)) && conf->pre_Command_Wait > (i++) * 10) udelay(10); if ((READSHMB(arlan->resetFlag) || READSHMB(arlan->commandByte)) && !(priv->waiting_command_mask & ARLAN_COMMAND_RESET)) { goto card_busy_end; } } if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) priv->under_reset = 1; if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) priv->under_config = 1; /* Issuing command */ arlan_lock_card_access(dev); if (priv->waiting_command_mask & ARLAN_COMMAND_POWERUP) { // if (readControlRegister(dev) & (ARLAN_ACCESS && ARLAN_POWER)) setPowerOn(dev); arlan_interrupt_lancpu(dev); priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERUP; priv->waiting_command_mask |= ARLAN_COMMAND_RESET; priv->card_polling_interval = HZ / 10; } else if (priv->waiting_command_mask & ARLAN_COMMAND_ACTIVATE) { WRITESHMB(arlan->commandByte, ARLAN_COM_ACTIVATE); arlan_interrupt_lancpu(dev); priv->waiting_command_mask &= ~ARLAN_COMMAND_ACTIVATE; priv->card_polling_interval = HZ / 10; } else if (priv->waiting_command_mask & ARLAN_COMMAND_RX_ABORT) { if (priv->rx_command_given) { WRITESHMB(arlan->commandByte, ARLAN_COM_RX_ABORT); arlan_interrupt_lancpu(dev); priv->rx_command_given = 0; } priv->waiting_command_mask &= ~ARLAN_COMMAND_RX_ABORT; priv->card_polling_interval = 1; } else if (priv->waiting_command_mask & ARLAN_COMMAND_TX_ABORT) { if (priv->tx_command_given) { WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ABORT); arlan_interrupt_lancpu(dev); priv->tx_command_given = 0; } priv->waiting_command_mask &= ~ARLAN_COMMAND_TX_ABORT; priv->card_polling_interval = 1; } else if (priv->waiting_command_mask & ARLAN_COMMAND_RESET) { priv->under_reset=1; netif_stop_queue (dev); arlan_drop_tx(dev); if (priv->tx_command_given || priv->rx_command_given) { printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); }; netif_stop_queue (dev); if (arlan_debug & ARLAN_DEBUG_RESET) printk(KERN_ERR "%s: Doing chip reset\n", dev->name); priv->lastReset = jiffies; WRITESHM(arlan->commandByte, 0, u_char); /* hold card in reset state */ setHardwareReset(dev); /* set reset flag and then release reset */ WRITESHM(arlan->resetFlag, 0xff, u_char); clearChannelAttention(dev); clearHardwareReset(dev); priv->numResets++; priv->card_polling_interval = HZ / 4; priv->waiting_command_mask &= ~ARLAN_COMMAND_RESET; priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK;// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RENABLE; // priv->waiting_command_mask |= ARLAN_COMMAND_RX; } else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RACK) { clearHardwareReset(dev); clearClearInterrupt(dev); setClearInterrupt(dev); setInterruptEnable(dev); priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RACK; priv->waiting_command_mask |= ARLAN_COMMAND_CONF; priv->under_config = 1; priv->under_reset = 0; } else if (priv->waiting_command_mask & ARLAN_COMMAND_INT_RENABLE) { setInterruptEnable(dev); priv->waiting_command_mask &= ~ARLAN_COMMAND_INT_RENABLE; } else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF) { if (priv->tx_command_given || priv->rx_command_given) { printk(KERN_ERR "%s: Reset under tx or rx command \n", dev->name); } arlan_drop_tx(dev); setInterruptEnable(dev); arlan_hw_config(dev); arlan_interrupt_lancpu(dev); priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF; priv->card_polling_interval = HZ / 10;// priv->waiting_command_mask |= ARLAN_COMMAND_INT_RACK; // priv->waiting_command_mask |= ARLAN_COMMAND_INT_ENABLE; priv->waiting_command_mask |= ARLAN_COMMAND_CONF_WAIT; } else if (priv->waiting_command_mask & ARLAN_COMMAND_CONF_WAIT) { if (READSHMB(arlan->configuredStatusFlag) != 0 && READSHMB(arlan->diagnosticInfo) == 0xff) { priv->waiting_command_mask &= ~ARLAN_COMMAND_CONF_WAIT; priv->waiting_command_mask |= ARLAN_COMMAND_RX; priv->waiting_command_mask |= ARLAN_COMMAND_TBUSY_CLEAR; priv->card_polling_interval = HZ / 10; priv->tx_command_given = 0; priv->under_config = 0; } else { priv->card_polling_interval = 1; if (arlan_debug & ARLAN_DEBUG_TIMING) printk(KERN_ERR "configure delayed \n"); } } else if (priv->waiting_command_mask & ARLAN_COMMAND_RX) { if (!registrationBad(dev)) { setInterruptEnable(dev); memset_io((void *) arlan->commandParameter, 0, 0xf); WRITESHMB(arlan->commandByte, ARLAN_COM_INT | ARLAN_COM_RX_ENABLE); WRITESHMB(arlan->commandParameter[0], conf->rxParameter); arlan_interrupt_lancpu(dev); priv->rx_command_given = 0; // mnjah, bad priv->last_rx_time = arlan_time(); priv->waiting_command_mask &= ~ARLAN_COMMAND_RX; priv->card_polling_interval = 1; } else priv->card_polling_interval = 2; } else if (priv->waiting_command_mask & ARLAN_COMMAND_TBUSY_CLEAR) { if ( !registrationBad(dev) && (netif_queue_stopped(dev) || !netif_running(dev)) ) { priv->waiting_command_mask &= ~ARLAN_COMMAND_TBUSY_CLEAR; netif_wake_queue (dev); }; } else if (priv->waiting_command_mask & ARLAN_COMMAND_TX) { if (!test_and_set_bit(0, (void *) &priv->tx_command_given)) { if ((time_mks - priv->last_tx_time > conf->rx_tweak1) || (time_mks - priv->last_rx_int_ack_time < conf->rx_tweak2)) { setInterruptEnable(dev); memset_io((void *) arlan->commandParameter, 0, 0xf); WRITESHMB(arlan->commandByte, ARLAN_COM_TX_ENABLE | ARLAN_COM_INT); memcpy_toio((void *) arlan->commandParameter, &TXLAST(dev), 14);// for ( i=1 ; i < 15 ; i++) printk("%02x:",READSHMB(arlan->commandParameter[i])); priv->last_command_was_rx = 0; priv->tx_last_sent = jiffies; arlan_interrupt_lancpu(dev); priv->last_tx_time = arlan_time(); priv->tx_command_given = 1; priv->waiting_command_mask &= ~ARLAN_COMMAND_TX; priv->card_polling_interval = 1; } else { priv->tx_command_given = 0; priv->card_polling_interval = 1; } } else if (arlan_debug & ARLAN_DEBUG_CHAIN_LOCKS) printk(KERN_ERR "tx command when tx chain locked \n"); } else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOPINT) { { WRITESHMB(arlan->commandByte, ARLAN_COM_NOP | ARLAN_COM_INT); } arlan_interrupt_lancpu(dev); priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOPINT; priv->card_polling_interval = HZ / 3; } else if (priv->waiting_command_mask & ARLAN_COMMAND_NOOP) { WRITESHMB(arlan->commandByte, ARLAN_COM_NOP); arlan_interrupt_lancpu(dev); priv->waiting_command_mask &= ~ARLAN_COMMAND_NOOP; priv->card_polling_interval = HZ / 3; } else if (priv->waiting_command_mask & ARLAN_COMMAND_SLOW_POLL) { WRITESHMB(arlan->commandByte, ARLAN_COM_GOTO_SLOW_POLL); arlan_interrupt_lancpu(dev); priv->waiting_command_mask &= ~ARLAN_COMMAND_SLOW_POLL; priv->card_polling_interval = HZ / 3; } else if (priv->waiting_command_mask & ARLAN_COMMAND_POWERDOWN) { setPowerOff(dev); if (arlan_debug & ARLAN_DEBUG_CARD_STATE) printk(KERN_WARNING "%s: Arlan Going Standby\n", dev->name); priv->waiting_command_mask &= ~ARLAN_COMMAND_POWERDOWN; priv->card_polling_interval = 3 * HZ; } arlan_unlock_card_access(dev); for (i = 0; READSHMB(arlan->commandByte) && i < 20; i++) udelay(10); if (READSHMB(arlan->commandByte))
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -