📄 fastvnet_cs.c
字号:
/***************************************************************************//* *//* Copyright (c) 1999-2000 by Atmel Corporation *//* *//* This software is copyrighted by and is the sole property of Atmel *//* Corporation. All rights, title, ownership, or other interests *//* in the software remain the property of Atmel Corporation. This *//* software may only be used in accordance with the corresponding *//* license agreement. Any un-authorized use, duplication, transmission, *//* distribution, or disclosure of this software is expressly forbidden. *//* *//* This Copyright notice may not be removed or modified without prior *//* written consent of Atmel Corporation. *//* *//* Atmel Corporation, Inc. reserves the right to modify this software *//* without notice. *//* *//* Atmel Corporation. *//* 2325 Orchard Parkway literature@atmel.com *//* San Jose, CA 95131 http://www.atmel.com *//* *//***************************************************************************//***************************************************************************//***************************************************************************//** *//** FastVNET (PCMCIA) Linux Driver *//** *//***************************************************************************//***************************************************************************/#include "vnet.h"#include "vnetioctl.h"#include "interrupt.h"/******************************************************************** * Module parameters, Globals and miscelenious definitions ********************************************************************/static char *version = "4.0.0.3";static dev_info_t dev_info = "fastvnet_cs";static dev_link_t *dev_list = NULL;static u_int irq_mask = 0xdeb8; // Interrupt maskstatic int irq_list[4] = { -1 }; // Interrupt list (alternative)static int mtu = 1500;static int eth = 1;static UCHAR channel = 4;static UCHAR TxRate = 3;static USHORT RTSThreshold = 2347;static USHORT FragThreshold = 2346;static UCHAR OpMode = INFRASTRUCTURE_MODE;static char ESSID[MAX_SSID_LENGTH+1] = "ANY\0"; static UCHAR WepKeyToUse = 0;static char WepKey1[(SHORT_WEP_KEY_SIZE*2)+1]= "0000000000\0";static char WepKey2[(SHORT_WEP_KEY_SIZE*2)+1] = "0000000000\0";static char WepKey3[(SHORT_WEP_KEY_SIZE*2)+1] = "0000000000\0";static char WepKey4[(SHORT_WEP_KEY_SIZE*2)+1] = "0000000000\0";static UCHAR WepMode = WEP_MODE_MANDATORY;static UCHAR EncryptionLevel = WEP_DISABLED;static UCHAR AuthenticationType = C80211_MGMT_AAN_OPENSYSTEM;static UCHAR PreambleType = LONG_PREAMBLE;static UCHAR PwrMgmtMode = ACTIVE_MODE;static int pc_debug = 0;MODULE_PARM(pc_debug, "i");MODULE_PARM(irq_mask, "i");MODULE_PARM(irq_list, "1-4i");MODULE_PARM(mtu, "i");MODULE_PARM(eth, "i");MODULE_PARM(channel, "i");MODULE_PARM(TxRate, "i");MODULE_PARM(RTSThreshold, "i");MODULE_PARM(FragThreshold, "i");MODULE_PARM(OpMode, "i");MODULE_PARM(ESSID, "c" __MODULE_STRING(MAX_SSID_LENGTH));MODULE_PARM(WepKeyToUse,"i");MODULE_PARM(WepKey1, "c" __MODULE_STRING(11));MODULE_PARM(WepKey2, "c" __MODULE_STRING(11));MODULE_PARM(WepKey3, "c" __MODULE_STRING(11));MODULE_PARM(WepKey4, "c" __MODULE_STRING(11));MODULE_PARM(WepMode, "i");MODULE_PARM(EncryptionLevel, "i");MODULE_PARM(AuthenticationType, "i");MODULE_PARM(PreambleType, "i");MODULE_PARM(PwrMgmtMode, "i");// Macros not included in kernel#ifndef __IN_PCMCIA_PACKAGE__#define DEV_KFREE_SKB(skb) dev_kfree_skb(skb);#define skb_tx_check(dev, skb)#define add_rx_bytes(stats, n) (stats)->rx_bytes += n;#define add_tx_bytes(stats, n) (stats)->tx_bytes += n;#endif// Ethernet timeout is ((400*HZ)/1000), but we should use a higher// value, because wireless transmissions are much slower#define TX_TIMEOUT ((4000*HZ)/1000)#define MAX_VNET_CARDS 16static struct net_device *vnet_index[MAX_VNET_CARDS];//// Local data for netdevice//struct net_local { dev_node_t node; struct net_device *dev; // backtrack device dev_link_t *link; // backtrack link spinlock_t slock; // spinlock int interrupt; // interrupt struct net_device_stats stats; // device stats#ifdef WIRELESS_EXT#ifdef WIRELESS_SPY int spy_number; u_char spy_address[IW_MAX_SPY][VNet_LENGTH_OF_ADDRESS]; struct iw_quality spy_stat[IW_MAX_SPY];#endif struct iw_statistics wstats;#endif VNet_ADAPTER Adapter;};// Driver Info/******************************************************************** * Function Prototypes ********************************************************************/static int vnet_tx (struct sk_buff *skb, struct net_device *dev);static int vnet_open (struct net_device *dev);static int vnet_close (struct net_device *dev);static void vnet_interrupt (int irq, void *dev_id, struct pt_regs *regs);static int vnet_config (dev_link_t *link);static void vnet_release (u_long arg);static dev_link_t *vnet_attach (void);static void vnet_detach (dev_link_t *link);static int vnet_event (event_t event, int priority, event_callback_args_t *args);static void cs_error (client_handle_t handle, int func, int ret);extern int init_module (void);extern void cleanup_module (void);struct net_device_stats *vnet_get_stats (struct net_device *dev);#ifdef WIRELESS_EXTstatic int vnet_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);struct iw_statistics *vnet_get_wireless_stats (struct net_device *dev);#endif /******************************************************************** * PCMCIA CONFIG / RELEASE ********************************************************************/#define CS_CHECK(fn, args...) while ((last_ret=CardServices(last_fn=(fn),args))!=0) goto cs_failed#define CFG_CHECK(fn, args...) if (CardServices(fn, args) != 0) goto next_entrystatic int vnet_config (dev_link_t *link){ client_handle_t handle = link->handle; tuple_t tuple; cisparse_t parse; struct net_device *dev = (struct net_device *) link->priv; struct net_local *local = (struct net_local *) dev->priv; int last_fn, last_ret; u_char buf[64]; win_req_t req; memreq_t map; int rc, i, cs_r; config_info_t config;// cistpl_cftable_entry_t dflt = { 0 }; PVNet_ADAPTER Adapter = (PVNet_ADAPTER)&local->Adapter; IF_VERY_LOUD(DbgPrint("-> vnet_config(0x%p)\n", link);) // This reads the card's CONFIG tuple to find its configuration registers. tuple.DesiredTuple = CISTPL_CONFIG; tuple.Attributes = 0; tuple.TupleData = buf; tuple.TupleDataMax = sizeof(buf); tuple.TupleOffset = 0; CS_CHECK(GetFirstTuple, handle, &tuple); CS_CHECK(GetTupleData, handle, &tuple); CS_CHECK(ParseTuple, handle, &tuple, &parse); link->conf.ConfigBase = parse.config.base; link->conf.Present = parse.config.rmask[0]; // Configure card link->state |= DEV_CONFIG; // 2-05-2001 Test : Added GetConfigurationInfo. Check if needed CS_CHECK(GetConfigurationInfo, handle, &config); link->conf.Vcc = config.Vcc; // In this loop, we scan the CIS for configuration table entries, // each of which describes a valid card configuration, including // voltage, IO window, memory window, and interrupt settings. // We make no assumptions about the card to be configured: we use // just the information available in the CIS. In an ideal world, // this would work for any PCMCIA card, but it requires a complete // and accurate CIS. In practice, a driver usually "knows" most of // these things without consulting the CIS, and most client drivers // will only use the CIS to fill in implementation-defined details. tuple.DesiredTuple = CISTPL_CFTABLE_ENTRY; CS_CHECK(GetFirstTuple, handle, &tuple); while (1) { cistpl_cftable_entry_t dflt = { 0 }; cistpl_cftable_entry_t *cfg = &(parse.cftable_entry); CFG_CHECK(GetTupleData, handle, &tuple); CFG_CHECK(ParseTuple, handle, &tuple, &parse); if (cfg->index == 0) goto next_entry; link->conf.ConfigIndex = cfg->index; // Does this card need audio output? if (cfg->flags & CISTPL_CFTABLE_AUDIO) { link->conf.Attributes |= CONF_ENABLE_SPKR; link->conf.Status = CCSR_AUDIO_ENA; } // Use power settings for Vcc and Vpp if present // Note that the CIS values need to be rescaled if (cfg->vcc.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vcc = cfg->vcc.param[CISTPL_POWER_VNOM]/10000; else if (dflt.vcc.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vcc = dflt.vcc.param[CISTPL_POWER_VNOM]/10000; if (cfg->vpp1.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vpp1 = link->conf.Vpp2 = cfg->vpp1.param[CISTPL_POWER_VNOM]/10000; else if (dflt.vpp1.present & (1<<CISTPL_POWER_VNOM)) link->conf.Vpp1 = link->conf.Vpp2 = dflt.vpp1.param[CISTPL_POWER_VNOM]/10000; // Do we need to allocate an interrupt? if (cfg->irq.IRQInfo1 || dflt.irq.IRQInfo1) link->conf.Attributes |= CONF_ENABLE_IRQ; // IO window settings link->io.NumPorts1 = link->io.NumPorts2 = 0; if ((cfg->io.nwin > 0) || (dflt.io.nwin > 0)) { cistpl_io_t *io = (cfg->io.nwin) ? &cfg->io : &dflt.io; link->io.Attributes1 = IO_DATA_PATH_WIDTH_AUTO; if (!(io->flags & CISTPL_IO_8BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_16; if (!(io->flags & CISTPL_IO_16BIT)) link->io.Attributes1 = IO_DATA_PATH_WIDTH_8; link->io.BasePort1 = io->win[0].base; link->io.NumPorts1 = io->win[0].len; if (io->nwin > 1) { link->io.Attributes2 = link->io.Attributes1; link->io.BasePort2 = io->win[1].base; link->io.NumPorts2 = io->win[1].len; } } // This reserves IO space but doesn't actually enable it CFG_CHECK(RequestIO, link->handle, &link->io); // Now set up a common memory window, if needed. There is room // in the dev_link_t structure for one memory window handle, // but if the base addresses need to be saved, or if multiple // windows are needed, the info should go in the private data // structure for this device. // Note that the memory window base is a physical address, and // needs to be mapped to virtual space with ioremap() before it // is used. if ((cfg->mem.nwin > 0) || (dflt.mem.nwin > 0)) { cistpl_mem_t *mem = (cfg->mem.nwin) ? &cfg->mem : &dflt.mem; req.Attributes = WIN_DATA_WIDTH_16|WIN_MEMORY_TYPE_CM; req.Base = mem->win[0].host_addr; req.Size = mem->win[0].len; req.AccessSpeed = 0; link->win = (window_handle_t)link->handle; CFG_CHECK(RequestWindow, &link->win, &req); map.Page = 0; map.CardOffset = mem->win[0].card_addr; CFG_CHECK(MapMemPage, link->win, &map); } break;next_entry: if (cfg->flags & CISTPL_CFTABLE_DEFAULT) dflt = *cfg; CS_CHECK(GetNextTuple, handle, &tuple); } // Allocate an interrupt line. Note that this does not assign a // handler to the interrupt, unless the 'Handler' member of the // irq structure is initialized. if (link->conf.Attributes & CONF_ENABLE_IRQ) { link->irq.Attributes = IRQ_TYPE_EXCLUSIVE | IRQ_HANDLE_PRESENT; link->irq.IRQInfo1 = IRQ_INFO2_VALID | IRQ_LEVEL_ID; if (irq_list[0] == -1) link->irq.IRQInfo2 = irq_mask; else for (i=0; i<4; i++) link->irq.IRQInfo2 |= 1 << irq_list[i]; link->irq.Handler = vnet_interrupt; link->irq.Instance = dev; CS_CHECK(RequestIRQ, link->handle, &link->irq); } // This actually configures the PCMCIA socket -- setting up // the I/O windows and the interrupt mapping, and putting the // card and host interface into "Memory and IO" mode. CS_CHECK(RequestConfiguration, link->handle, &link->conf); // Feed the netdevice with this info dev->irq = link->irq.AssignedIRQ; dev->base_addr = link->io.BasePort1; netif_start_queue(dev); // Report what we've done IF_LOUD(DbgPrint("%s: index 0x%02x: Vcc %d.%d", dev_info, link->conf.ConfigIndex, link->conf.Vcc/10, link->conf.Vcc%10);) if (link->conf.Vpp1) { IF_LOUD(DbgPrint(", Vpp %d.%d", link->conf.Vpp1/10, link->conf.Vpp1%10);) } if (link->conf.Attributes & CONF_ENABLE_IRQ) { IF_LOUD(DbgPrint(", irq %d", link->irq.AssignedIRQ);) } if (link->io.NumPorts1) { IF_LOUD(DbgPrint(", io 0x%04x-0x%04x", link->io.BasePort1, link->io.BasePort1+link->io.NumPorts1-1);) } if (link->io.NumPorts2) { IF_LOUD(DbgPrint(" & 0x%04x-0x%04x", link->io.BasePort2, link->io.BasePort2+link->io.NumPorts2-1);) } if (link->win) { IF_LOUD(DbgPrint(", mem 0x%06lx-0x%06lx", req.Base, req.Base+req.Size-1);) } IF_LOUD(DbgPrint("\n");) link->state &= ~DEV_CONFIG_PENDING; if(!eth) { for (i=0; i<MAX_VNET_CARDS; ++i) if (!vnet_index[i]) { sprintf(dev->name, "vnet%d",i); vnet_index[i]=dev; break; } } // Register the netdevice rc = register_netdev(dev); if (rc) { IF_DEBUG_ERRORS(DbgPrint("%s: register_netdev() failed!\n", dev_info);) vnet_release((u_long)link); return 0; } IF_LOUD(DbgPrint("%s: Registered netdevice %s\n", dev_info, dev->name);) copy_dev_name(local->node, dev); local->Adapter.dev = dev; local->Adapter.IoBase = dev->base_addr; link->dev = &local->node; IF_VERY_LOUD(DbgPrint("<- vnet_config()\n");) return 1;cs_failed: cs_error(link->handle, last_fn, last_ret); vnet_release((u_long)link); IF_VERY_LOUD(DbgPrint("<- vnet_config()\n");) return 0;}static void vnet_release (u_long arg){ dev_link_t *link = (dev_link_t *) arg; struct net_device *dev = (struct net_device *) link->priv; struct net_local *local = (struct net_local *) dev->priv; PVNet_ADAPTER Adapter = &local->Adapter; IF_VERY_LOUD(DbgPrint("-> vnet_release(0x%p)\n", link);) // If the device is currently in use, we won't release // until it's actually closed. if (link->open) { IF_VERY_LOUD(DbgPrint("%s: vnet_release: release postponed, %s still locked\n", dev_info, link->dev->dev_name);) link->state |= DEV_STALE_CONFIG; return; } del_timer(&Adapter->MgmtTimer); CardStop(Adapter); Adapter->IsUp = FALSE; if (link->win) CardServices(ReleaseWindow, link->win); CardServices(ReleaseConfiguration, link->handle); if (link->io.NumPorts1) CardServices(ReleaseIO, link->handle, &link->io); if (link->irq.AssignedIRQ) CardServices(ReleaseIRQ, link->handle, &link->irq); link->state &= ~DEV_CONFIG; IF_VERY_LOUD(DbgPrint("<- vnet_release()\n");)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -