diff options
author | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-06 00:47:18 -0700 |
---|---|---|
committer | Linus Torvalds <torvalds@evo.osdl.org> | 2005-09-06 00:47:18 -0700 |
commit | 5bcaa155797ab62ed363932ec0f02fbcb5db1ef1 (patch) | |
tree | 1db633712bd47ce72ac5a1aed62b3417733ac63a /drivers/net/wireless | |
parent | 1e231efe50ffe4d291be24d2fe393188de9c4b08 (diff) | |
parent | 3a48c4c2d52a08e12319ab7caacad0a9b88e6cb4 (diff) |
Merge branch 'upstream' of master.kernel.org:/pub/scm/linux/kernel/git/jgarzik/netdev-2.6
Diffstat (limited to 'drivers/net/wireless')
-rw-r--r-- | drivers/net/wireless/Kconfig | 38 | ||||
-rw-r--r-- | drivers/net/wireless/Makefile | 2 | ||||
-rw-r--r-- | drivers/net/wireless/ipw2100.c | 69 | ||||
-rw-r--r-- | drivers/net/wireless/ipw2200.h | 1 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco.c | 93 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco_cs.c | 1 | ||||
-rw-r--r-- | drivers/net/wireless/orinoco_nortel.c | 324 | ||||
-rw-r--r-- | drivers/net/wireless/spectrum_cs.c | 1120 |
8 files changed, 1566 insertions, 82 deletions
diff --git a/drivers/net/wireless/Kconfig b/drivers/net/wireless/Kconfig index dd7dbf7b14d..00a07f32a81 100644 --- a/drivers/net/wireless/Kconfig +++ b/drivers/net/wireless/Kconfig @@ -289,8 +289,8 @@ config APPLE_AIRPORT a non-standard interface config PLX_HERMES - tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.) (EXPERIMENTAL)" - depends on PCI && HERMES && EXPERIMENTAL + tristate "Hermes in PLX9052 based PCI adaptor support (Netgear MA301 etc.)" + depends on PCI && HERMES help Enable support for PCMCIA cards supported by the "Hermes" (aka orinoco) driver when used in PLX9052 based PCI adaptors. These @@ -299,12 +299,9 @@ config PLX_HERMES 802.11b PCMCIA cards can be used in desktop machines. The Netgear MA301 is such an adaptor. - Support for these adaptors is so far still incomplete and buggy. - You have been warned. - config TMD_HERMES - tristate "Hermes in TMD7160 based PCI adaptor support (EXPERIMENTAL)" - depends on PCI && HERMES && EXPERIMENTAL + tristate "Hermes in TMD7160 based PCI adaptor support" + depends on PCI && HERMES help Enable support for PCMCIA cards supported by the "Hermes" (aka orinoco) driver when used in TMD7160 based PCI adaptors. These @@ -312,12 +309,18 @@ config TMD_HERMES PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that 802.11b PCMCIA cards can be used in desktop machines. - Support for these adaptors is so far still incomplete and buggy. - You have been warned. +config NORTEL_HERMES + tristate "Nortel emobility PCI adaptor support" + depends on PCI && HERMES + help + Enable support for PCMCIA cards supported by the "Hermes" (aka + orinoco) driver when used in Nortel emobility PCI adaptors. These + adaptors are not full PCMCIA controllers, but act as a more limited + PCI <-> PCMCIA bridge. config PCI_HERMES - tristate "Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)" - depends on PCI && HERMES && EXPERIMENTAL + tristate "Prism 2.5 PCI 802.11b adaptor support" + depends on PCI && HERMES help Enable support for PCI and mini-PCI 802.11b wireless NICs based on the Prism 2.5 chipset. These are true PCI cards, not the 802.11b @@ -372,6 +375,19 @@ config PCMCIA_HERMES configure your card and that /etc/pcmcia/wireless.opts works: <http://www.hpl.hp.com/personal/Jean_Tourrilhes/Linux/Tools.html>. +config PCMCIA_SPECTRUM + tristate "Symbol Spectrum24 Trilogy PCMCIA card support" + depends on NET_RADIO && PCMCIA && HERMES + ---help--- + + This is a driver for 802.11b cards using RAM-loadable Symbol + firmware, such as Symbol Wireless Networker LA4100, CompactFlash + cards by Socket Communications and Intel PRO/Wireless 2011B. + + This driver requires firmware download on startup. Utilities + for downloading Symbol firmware are available at + <http://sourceforge.net/projects/orinoco/> + config AIRO_CS tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards" depends on NET_RADIO && PCMCIA && (BROKEN || !M32R) diff --git a/drivers/net/wireless/Makefile b/drivers/net/wireless/Makefile index 0953cc0cdee..3a6f7ba326c 100644 --- a/drivers/net/wireless/Makefile +++ b/drivers/net/wireless/Makefile @@ -22,6 +22,8 @@ obj-$(CONFIG_APPLE_AIRPORT) += airport.o obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o +obj-$(CONFIG_NORTEL_HERMES) += orinoco_nortel.o +obj-$(CONFIG_PCMCIA_SPECTRUM) += spectrum_cs.o obj-$(CONFIG_AIRO) += airo.o obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o diff --git a/drivers/net/wireless/ipw2100.c b/drivers/net/wireless/ipw2100.c index a47fce4bead..2414e6493aa 100644 --- a/drivers/net/wireless/ipw2100.c +++ b/drivers/net/wireless/ipw2100.c @@ -327,38 +327,38 @@ static struct iw_handler_def ipw2100_wx_handler_def; static inline void read_register(struct net_device *dev, u32 reg, u32 *val) { - *val = readl((void *)(dev->base_addr + reg)); + *val = readl((void __iomem *)(dev->base_addr + reg)); IPW_DEBUG_IO("r: 0x%08X => 0x%08X\n", reg, *val); } static inline void write_register(struct net_device *dev, u32 reg, u32 val) { - writel(val, (void *)(dev->base_addr + reg)); + writel(val, (void __iomem *)(dev->base_addr + reg)); IPW_DEBUG_IO("w: 0x%08X <= 0x%08X\n", reg, val); } static inline void read_register_word(struct net_device *dev, u32 reg, u16 *val) { - *val = readw((void *)(dev->base_addr + reg)); + *val = readw((void __iomem *)(dev->base_addr + reg)); IPW_DEBUG_IO("r: 0x%08X => %04X\n", reg, *val); } static inline void read_register_byte(struct net_device *dev, u32 reg, u8 *val) { - *val = readb((void *)(dev->base_addr + reg)); + *val = readb((void __iomem *)(dev->base_addr + reg)); IPW_DEBUG_IO("r: 0x%08X => %02X\n", reg, *val); } static inline void write_register_word(struct net_device *dev, u32 reg, u16 val) { - writew(val, (void *)(dev->base_addr + reg)); + writew(val, (void __iomem *)(dev->base_addr + reg)); IPW_DEBUG_IO("w: 0x%08X <= %04X\n", reg, val); } static inline void write_register_byte(struct net_device *dev, u32 reg, u8 val) { - writeb(val, (void *)(dev->base_addr + reg)); + writeb(val, (void __iomem *)(dev->base_addr + reg)); IPW_DEBUG_IO("w: 0x%08X =< %02X\n", reg, val); } @@ -498,7 +498,7 @@ static inline void read_nic_memory(struct net_device *dev, u32 addr, u32 len, static inline int ipw2100_hw_is_adapter_in_system(struct net_device *dev) { return (dev->base_addr && - (readl((void *)(dev->base_addr + IPW_REG_DOA_DEBUG_AREA_START)) + (readl((void __iomem *)(dev->base_addr + IPW_REG_DOA_DEBUG_AREA_START)) == IPW_DATA_DOA_DEBUG_VALUE)); } @@ -2125,19 +2125,19 @@ static void isr_indicate_scanning(struct ipw2100_priv *priv, u32 status) } static const struct ipw2100_status_indicator status_handlers[] = { - IPW2100_HANDLER(IPW_STATE_INITIALIZED, 0), - IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, 0), + IPW2100_HANDLER(IPW_STATE_INITIALIZED, NULL), + IPW2100_HANDLER(IPW_STATE_COUNTRY_FOUND, NULL), IPW2100_HANDLER(IPW_STATE_ASSOCIATED, isr_indicate_associated), IPW2100_HANDLER(IPW_STATE_ASSN_LOST, isr_indicate_association_lost), - IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, 0), + IPW2100_HANDLER(IPW_STATE_ASSN_CHANGED, NULL), IPW2100_HANDLER(IPW_STATE_SCAN_COMPLETE, isr_scan_complete), - IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, 0), - IPW2100_HANDLER(IPW_STATE_LEFT_PSP, 0), + IPW2100_HANDLER(IPW_STATE_ENTERED_PSP, NULL), + IPW2100_HANDLER(IPW_STATE_LEFT_PSP, NULL), IPW2100_HANDLER(IPW_STATE_RF_KILL, isr_indicate_rf_kill), - IPW2100_HANDLER(IPW_STATE_DISABLED, 0), - IPW2100_HANDLER(IPW_STATE_POWER_DOWN, 0), + IPW2100_HANDLER(IPW_STATE_DISABLED, NULL), + IPW2100_HANDLER(IPW_STATE_POWER_DOWN, NULL), IPW2100_HANDLER(IPW_STATE_SCANNING, isr_indicate_scanning), - IPW2100_HANDLER(-1, 0) + IPW2100_HANDLER(-1, NULL) }; @@ -6327,7 +6327,7 @@ static void ipw2100_irq_tasklet(struct ipw2100_priv *priv); static struct net_device *ipw2100_alloc_device( struct pci_dev *pci_dev, - char *base_addr, + void __iomem *base_addr, unsigned long mem_start, unsigned long mem_len) { @@ -6474,7 +6474,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, const struct pci_device_id *ent) { unsigned long mem_start, mem_len, mem_flags; - char *base_addr = NULL; + void __iomem *base_addr = NULL; struct net_device *dev = NULL; struct ipw2100_priv *priv = NULL; int err = 0; @@ -6664,7 +6664,7 @@ static int ipw2100_pci_init_one(struct pci_dev *pci_dev, } if (base_addr) - iounmap((char*)base_addr); + iounmap(base_addr); pci_release_regions(pci_dev); pci_disable_device(pci_dev); @@ -6714,7 +6714,7 @@ static void __devexit ipw2100_pci_remove_one(struct pci_dev *pci_dev) free_irq(dev->irq, priv); if (dev->base_addr) - iounmap((unsigned char *)dev->base_addr); + iounmap((void __iomem *)dev->base_addr); free_ieee80211(dev); } @@ -8574,6 +8574,7 @@ static int ipw2100_ucode_download(struct ipw2100_priv *priv, struct net_device *dev = priv->net_dev; const unsigned char *microcode_data = fw->uc.data; unsigned int microcode_data_left = fw->uc.size; + void __iomem *reg = (void __iomem *)dev->base_addr; struct symbol_alive_response response; int i, j; @@ -8581,23 +8582,23 @@ static int ipw2100_ucode_download(struct ipw2100_priv *priv, /* Symbol control */ write_nic_word(dev, IPW2100_CONTROL_REG, 0x703); - readl((void *)(dev->base_addr)); + readl(reg); write_nic_word(dev, IPW2100_CONTROL_REG, 0x707); - readl((void *)(dev->base_addr)); + readl(reg); /* HW config */ write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */ - readl((void *)(dev->base_addr)); + readl(reg); write_nic_byte(dev, 0x210014, 0x72); /* fifo width =16 */ - readl((void *)(dev->base_addr)); + readl(reg); /* EN_CS_ACCESS bit to reset control store pointer */ write_nic_byte(dev, 0x210000, 0x40); - readl((void *)(dev->base_addr)); + readl(reg); write_nic_byte(dev, 0x210000, 0x0); - readl((void *)(dev->base_addr)); + readl(reg); write_nic_byte(dev, 0x210000, 0x40); - readl((void *)(dev->base_addr)); + readl(reg); /* copy microcode from buffer into Symbol */ @@ -8609,31 +8610,31 @@ static int ipw2100_ucode_download(struct ipw2100_priv *priv, /* EN_CS_ACCESS bit to reset the control store pointer */ write_nic_byte(dev, 0x210000, 0x0); - readl((void *)(dev->base_addr)); + readl(reg); /* Enable System (Reg 0) * first enable causes garbage in RX FIFO */ write_nic_byte(dev, 0x210000, 0x0); - readl((void *)(dev->base_addr)); + readl(reg); write_nic_byte(dev, 0x210000, 0x80); - readl((void *)(dev->base_addr)); + readl(reg); /* Reset External Baseband Reg */ write_nic_word(dev, IPW2100_CONTROL_REG, 0x703); - readl((void *)(dev->base_addr)); + readl(reg); write_nic_word(dev, IPW2100_CONTROL_REG, 0x707); - readl((void *)(dev->base_addr)); + readl(reg); /* HW Config (Reg 5) */ write_nic_byte(dev, 0x210014, 0x72); // fifo width =16 - readl((void *)(dev->base_addr)); + readl(reg); write_nic_byte(dev, 0x210014, 0x72); // fifo width =16 - readl((void *)(dev->base_addr)); + readl(reg); /* Enable System (Reg 0) * second enable should be OK */ write_nic_byte(dev, 0x210000, 0x00); // clear enable system - readl((void *)(dev->base_addr)); + readl(reg); write_nic_byte(dev, 0x210000, 0x80); // set enable system /* check Symbol is enabled - upped this from 5 as it wasn't always diff --git a/drivers/net/wireless/ipw2200.h b/drivers/net/wireless/ipw2200.h index dc3e7bc805f..66bb5903537 100644 --- a/drivers/net/wireless/ipw2200.h +++ b/drivers/net/wireless/ipw2200.h @@ -42,6 +42,7 @@ #include <linux/etherdevice.h> #include <linux/delay.h> #include <linux/random.h> +#include <linux/dma-mapping.h> #include <linux/firmware.h> #include <linux/wireless.h> diff --git a/drivers/net/wireless/orinoco.c b/drivers/net/wireless/orinoco.c index d7947358e49..8de49fe5723 100644 --- a/drivers/net/wireless/orinoco.c +++ b/drivers/net/wireless/orinoco.c @@ -1053,8 +1053,9 @@ static void orinoco_join_ap(struct net_device *dev) u16 channel; } __attribute__ ((packed)) req; const int atom_len = offsetof(struct prism2_scan_apinfo, atim); - struct prism2_scan_apinfo *atom; + struct prism2_scan_apinfo *atom = NULL; int offset = 4; + int found = 0; u8 *buf; u16 len; @@ -1089,15 +1090,18 @@ static void orinoco_join_ap(struct net_device *dev) * we were requested to join */ for (; offset + atom_len <= len; offset += atom_len) { atom = (struct prism2_scan_apinfo *) (buf + offset); - if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) - goto found; + if (memcmp(&atom->bssid, priv->desired_bssid, ETH_ALEN) == 0) { + found = 1; + break; + } } - DEBUG(1, "%s: Requested AP not found in scan results\n", - dev->name); - goto out; + if (! found) { + DEBUG(1, "%s: Requested AP not found in scan results\n", + dev->name); + goto out; + } - found: memcpy(req.bssid, priv->desired_bssid, ETH_ALEN); req.channel = atom->channel; /* both are little-endian */ err = HERMES_WRITE_RECORD(hw, USER_BAP, HERMES_RID_CNFJOINREQUEST, @@ -1284,8 +1288,10 @@ static void __orinoco_ev_info(struct net_device *dev, hermes_t *hw) /* Read scan data */ err = hermes_bap_pread(hw, IRQ_BAP, (void *) buf, len, infofid, sizeof(info)); - if (err) + if (err) { + kfree(buf); break; + } #ifdef ORINOCO_DEBUG { @@ -4021,7 +4027,8 @@ static int orinoco_ioctl_setscan(struct net_device *dev, } /* Translate scan data returned from the card to a card independant - * format that the Wireless Tools will understand - Jean II */ + * format that the Wireless Tools will understand - Jean II + * Return message length or -errno for fatal errors */ static inline int orinoco_translate_scan(struct net_device *dev, char *buffer, char *scan, @@ -4061,13 +4068,19 @@ static inline int orinoco_translate_scan(struct net_device *dev, break; case FIRMWARE_TYPE_INTERSIL: offset = 4; - if (priv->has_hostscan) - atom_len = scan[0] + (scan[1] << 8); - else + if (priv->has_hostscan) { + atom_len = le16_to_cpup((u16 *)scan); + /* Sanity check for atom_len */ + if (atom_len < sizeof(struct prism2_scan_apinfo)) { + printk(KERN_ERR "%s: Invalid atom_len in scan data: %d\n", + dev->name, atom_len); + return -EIO; + } + } else atom_len = offsetof(struct prism2_scan_apinfo, atim); break; default: - return 0; + return -EOPNOTSUPP; } /* Check that we got an whole number of atoms */ @@ -4075,7 +4088,7 @@ static inline int orinoco_translate_scan(struct net_device *dev, printk(KERN_ERR "%s: Unexpected scan data length %d, " "atom_len %d, offset %d\n", dev->name, scan_len, atom_len, offset); - return 0; + return -EIO; } /* Read the entries one by one */ @@ -4210,33 +4223,41 @@ static int orinoco_ioctl_getscan(struct net_device *dev, /* We have some results to push back to user space */ /* Translate to WE format */ - srq->length = orinoco_translate_scan(dev, extra, - priv->scan_result, - priv->scan_len); - - /* Return flags */ - srq->flags = (__u16) priv->scan_mode; + int ret = orinoco_translate_scan(dev, extra, + priv->scan_result, + priv->scan_len); + + if (ret < 0) { + err = ret; + kfree(priv->scan_result); + priv->scan_result = NULL; + } else { + srq->length = ret; - /* Results are here, so scan no longer in progress */ - priv->scan_inprogress = 0; + /* Return flags */ + srq->flags = (__u16) priv->scan_mode; - /* In any case, Scan results will be cleaned up in the - * reset function and when exiting the driver. - * The person triggering the scanning may never come to - * pick the results, so we need to do it in those places. - * Jean II */ + /* In any case, Scan results will be cleaned up in the + * reset function and when exiting the driver. + * The person triggering the scanning may never come to + * pick the results, so we need to do it in those places. + * Jean II */ #ifdef SCAN_SINGLE_READ - /* If you enable this option, only one client (the first - * one) will be able to read the result (and only one - * time). If there is multiple concurent clients that - * want to read scan results, this behavior is not - * advisable - Jean II */ - kfree(priv->scan_result); - priv->scan_result = NULL; + /* If you enable this option, only one client (the first + * one) will be able to read the result (and only one + * time). If there is multiple concurent clients that + * want to read scan results, this behavior is not + * advisable - Jean II */ + kfree(priv->scan_result); + priv->scan_result = NULL; #endif /* SCAN_SINGLE_READ */ - /* Here, if too much time has elapsed since last scan, - * we may want to clean up scan results... - Jean II */ + /* Here, if too much time has elapsed since last scan, + * we may want to clean up scan results... - Jean II */ + } + + /* Scan is no longer in progress */ + priv->scan_inprogress = 0; } orinoco_unlock(priv, &flags); diff --git a/drivers/net/wireless/orinoco_cs.c b/drivers/net/wireless/orinoco_cs.c index 1cc1492083c..d1fb1bab8aa 100644 --- a/drivers/net/wireless/orinoco_cs.c +++ b/drivers/net/wireless/orinoco_cs.c @@ -604,7 +604,6 @@ static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION static struct pcmcia_device_id orinoco_cs_ids[] = { PCMCIA_DEVICE_MANF_CARD(0x000b, 0x7300), - PCMCIA_DEVICE_MANF_CARD(0x0089, 0x0001), PCMCIA_DEVICE_MANF_CARD(0x0138, 0x0002), PCMCIA_DEVICE_MANF_CARD(0x0156, 0x0002), PCMCIA_DEVICE_MANF_CARD(0x01eb, 0x080a), diff --git a/drivers/net/wireless/orinoco_nortel.c b/drivers/net/wireless/orinoco_nortel.c new file mode 100644 index 00000000000..86fa58e5cfa --- /dev/null +++ b/drivers/net/wireless/orinoco_nortel.c @@ -0,0 +1,324 @@ +/* orinoco_nortel.c + * + * Driver for Prism II devices which would usually be driven by orinoco_cs, + * but are connected to the PCI bus by a Nortel PCI-PCMCIA-Adapter. + * + * Copyright (C) 2002 Tobias Hoffmann + * (C) 2003 Christoph Jungegger <disdos@traum404.de> + * + * Some of this code is borrowed from orinoco_plx.c + * Copyright (C) 2001 Daniel Barlow + * Some of this code is borrowed from orinoco_pci.c + * Copyright (C) 2001 Jean Tourrilhes + * Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing + * has been copied from it. linux-wlan-ng-0.1.10 is originally : + * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. + * + * The contents of this file are subject to the Mozilla Public License + * Version 1.1 (the "License"); you may not use this file except in + * compliance with the License. You may obtain a copy of the License + * at http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and + * limitations under the License. + * + * Alternatively, the contents of this file may be used under the + * terms of the GNU General Public License version 2 (the "GPL"), in + * which case the provisions of the GPL are applicable instead of the + * above. If you wish to allow the use of your version of this file + * only under the terms of the GPL and not to allow others to use your + * version of this file under the MPL, indicate your decision by + * deleting the provisions above and replace them with the notice and + * other provisions required by the GPL. If you do not delete the + * provisions above, a recipient may use your version of this file + * under either the MPL or the GPL. + */ + +#define DRIVER_NAME "orinoco_nortel" +#define PFX DRIVER_NAME ": " + +#include <linux/config.h> + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/timer.h> +#include <linux/ioport.h> +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/system.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/etherdevice.h> +#include <linux/list.h> +#include <linux/pci.h> +#include <linux/fcntl.h> + +#include <pcmcia/cisreg.h> + +#include "hermes.h" +#include "orinoco.h" + +#define COR_OFFSET (0xe0) /* COR attribute offset of Prism2 PC card */ +#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA) /* Enable PC card with interrupt in level trigger */ + + +/* Nortel specific data */ +struct nortel_pci_card { + unsigned long iobase1; + unsigned long iobase2; +}; + +/* + * Do a soft reset of the PCI card using the Configuration Option Register + * We need this to get going... + * This is the part of the code that is strongly inspired from wlan-ng + * + * Note bis : Don't try to access HERMES_CMD during the reset phase. + * It just won't work ! + */ +static int nortel_pci_cor_reset(struct orinoco_private *priv) +{ + struct nortel_pci_card *card = priv->card; + + /* Assert the reset until the card notice */ + outw_p(8, card->iobase1 + 2); + inw(card->iobase2 + COR_OFFSET); + outw_p(0x80, card->iobase2 + COR_OFFSET); + mdelay(1); + + /* Give time for the card to recover from this hard effort */ + outw_p(0, card->iobase2 + COR_OFFSET); + outw_p(0, card->iobase2 + COR_OFFSET); + mdelay(1); + + /* set COR as usual */ + outw_p(COR_VALUE, card->iobase2 + COR_OFFSET); + outw_p(COR_VALUE, card->iobase2 + COR_OFFSET); + mdelay(1); + + outw_p(0x228, card->iobase1 + 2); + + return 0; +} + +int nortel_pci_hw_init(struct nortel_pci_card *card) +{ + int i; + u32 reg; + + /* setup bridge */ + if (inw(card->iobase1) & 1) { + printk(KERN_ERR PFX "brg1 answer1 wrong\n"); + return -EBUSY; + } + outw_p(0x118, card->iobase1 + 2); + outw_p(0x108, card->iobase1 + 2); + mdelay(30); + outw_p(0x8, card->iobase1 + 2); + for (i = 0; i < 30; i++) { + mdelay(30); + if (inw(card->iobase1) & 0x10) { + break; + } + } + if (i == 30) { + printk(KERN_ERR PFX "brg1 timed out\n"); + return -EBUSY; + } + if (inw(card->iobase2 + 0xe0) & 1) { + printk(KERN_ERR PFX "brg2 answer1 wrong\n"); + return -EBUSY; + } + if (inw(card->iobase2 + 0xe2) & 1) { + printk(KERN_ERR PFX "brg2 answer2 wrong\n"); + return -EBUSY; + } + if (inw(card->iobase2 + 0xe4) & 1) { + printk(KERN_ERR PFX "brg2 answer3 wrong\n"); + return -EBUSY; + } + + /* set the PCMCIA COR-Register */ + outw_p(COR_VALUE, card->iobase2 + COR_OFFSET); + mdelay(1); + reg = inw(card->iobase2 + COR_OFFSET); + if (reg != COR_VALUE) { + printk(KERN_ERR PFX "Error setting COR value (reg=%x)\n", + reg); + return -EBUSY; + } + + /* set leds */ + outw_p(1, card->iobase1 + 10); + return 0; +} + +static int nortel_pci_init_one(struct pci_dev *pdev, + const struct pci_device_id *ent) +{ + int err; + struct orinoco_private *priv; + struct nortel_pci_card *card; + struct net_device *dev; + void __iomem *iomem; + + err = pci_enable_device(pdev); + if (err) { + printk(KERN_ERR PFX "Cannot enable PCI device\n"); + return err; + } + + err = pci_request_regions(pdev, DRIVER_NAME); + if (err != 0) { + printk(KERN_ERR PFX "Cannot obtain PCI resources\n"); + goto fail_resources; + } + + iomem = pci_iomap(pdev, 3, 0); + if (!iomem) { + err = -ENOMEM; + goto fail_map_io; + } + + /* Allocate network device */ + dev = alloc_orinocodev(sizeof(*card), nortel_pci_cor_reset); + if (!dev) { + printk(KERN_ERR PFX "Cannot allocate network device\n"); + err = -ENOMEM; + goto fail_alloc; + } + + priv = netdev_priv(dev); + card = priv->card; + card->iobase1 = pci_resource_start(pdev, 0); + card->iobase2 = pci_resource_start(pdev, 1); + dev->base_addr = pci_resource_start(pdev, 2); + SET_MODULE_OWNER(dev); + SET_NETDEV_DEV(dev, &pdev->dev); + + hermes_struct_init(&priv->hw, iomem, HERMES_16BIT_REGSPACING); + + printk(KERN_DEBUG PFX "Detected Nortel PCI device at %s irq:%d, " + "io addr:0x%lx\n", pci_name(pdev), pdev->irq, dev->base_addr); + + err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, + dev->name, dev); + if (err) { + printk(KERN_ERR PFX "Cannot allocate IRQ %d\n", pdev->irq); + err = -EBUSY; + goto fail_irq; + } + dev->irq = pdev->irq; + + err = nortel_pci_hw_init(card); + if (err) { + printk(KERN_ERR PFX "Hardware initialization failed\n"); + goto fail; + } + + err = nortel_pci_cor_reset(priv); + if (err) { + printk(KERN_ERR PFX "Initial reset failed\n"); + goto fail; + } + + + err = register_netdev(dev); + if (err) { + printk(KERN_ERR PFX "Cannot register network device\n"); + goto fail; + } + + pci_set_drvdata(pdev, dev); + + return 0; + + fail: + free_irq(pdev->irq, dev); + + fail_irq: + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); + + fail_alloc: + pci_iounmap(pdev, iomem); + + fail_map_io: + pci_release_regions(pdev); + + fail_resources: + pci_disable_device(pdev); + + return err; +} + +static void __devexit nortel_pci_remove_one(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct orinoco_private *priv = netdev_priv(dev); + struct nortel_pci_card *card = priv->card; + + /* clear leds */ + outw_p(0, card->iobase1 + 10); + + unregister_netdev(dev); + free_irq(dev->irq, dev); + pci_set_drvdata(pdev, NULL); + free_orinocodev(dev); + pci_iounmap(pdev, priv->hw.iobase); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + + +static struct pci_device_id nortel_pci_id_table[] = { + /* Nortel emobility PCI */ + {0x126c, 0x8030, PCI_ANY_ID, PCI_ANY_ID,}, + {0,}, +}; + +MODULE_DEVICE_TABLE(pci, nortel_pci_id_table); + +static struct pci_driver nortel_pci_driver = { + .name = DRIVER_NAME, + .id_table = nortel_pci_id_table, + .probe = nortel_pci_init_one, + .remove = __devexit_p(nortel_pci_remove_one), +}; + +static char version[] __initdata = DRIVER_NAME " " DRIVER_VERSION + " (Tobias Hoffmann & Christoph Jungegger <disdos@traum404.de>)"; +MODULE_AUTHOR("Christoph Jungegger <disdos@traum404.de>"); +MODULE_DESCRIPTION + ("Driver for wireless LAN cards using the Nortel PCI bridge"); +MODULE_LICENSE("Dual MPL/GPL"); + +static int __init nortel_pci_init(void) +{ + printk(KERN_DEBUG "%s\n", version); + return pci_module_init(&nortel_pci_driver); +} + +static void __exit nortel_pci_exit(void) +{ + pci_unregister_driver(&nortel_pci_driver); + ssleep(1); +} + +module_init(nortel_pci_init); +module_exit(nortel_pci_exit); + +/* + * Local variables: + * c-indent-level: 8 + * c-basic-offset: 8 + * tab-width: 8 + * End: + */ diff --git a/drivers/net/wireless/spectrum_cs.c b/drivers/net/wireless/spectrum_cs.c new file mode 100644 index 00000000000..39c6cdf7f3f --- /dev/null +++ b/drivers/net/wireless/spectrum_cs.c @@ -0,0 +1,1120 @@ +/* + * Driver for 802.11b cards using RAM-loadable Symbol firmware, such as + * Symbol Wireless Networker LA4100, CompactFlash cards by Socket + * Communications and Intel PRO/Wireless 2011B. + * + * The driver implements Symbol firmware download. The rest is handled + * in hermes.c and orinoco.c. + * + * Utilities for downloading the Symbol firmware are available at + * http://sourceforge.net/projects/orinoco/ + * + * Copyright (C) 2002-2005 Pavel Roskin <proski@gnu.org> + * Portions based on orinoco_cs.c: + * Copyright (C) David Gibson, Linuxcare Australia + * Portions based on Spectrum24tDnld.c from original spectrum24 driver: + * Copyright (C) Symbol Technologies. + * + * See copyright notice in file orinoco.c. + */ + +#define DRIVER_NAME "spectrum_cs" +#define PFX DRIVER_NAME ": " + +#include <linux/config.h> +#ifdef __IN_PCMCIA_PACKAGE__ +#include <pcmcia/k_compat.h> +#endif /* __IN_PCMCIA_PACKAGE__ */ + +#include <linux/module.h> +#include <linux/kernel.h> +#include <linux/init.h> +#include <linux/sched.h> +#include <linux/ptrace.h> +#include <linux/slab.h> +#include <linux/string.h> +#include <linux/ioport.h> +#include <linux/netdevice.h> +#include <linux/if_arp.h> +#include <linux/etherdevice.h> +#include <linux/wireless.h> + +#include <pcmcia/cs_types.h> +#include <pcmcia/cs.h> +#include <pcmcia/cistpl.h> +#include <pcmcia/cisreg.h> +#include <pcmcia/ds.h> + +#include <asm/uaccess.h> +#include <asm/io.h> +#include <asm/system.h> + +#include "orinoco.h" + +/* + * If SPECTRUM_FW_INCLUDED is defined, the firmware is hardcoded into + * the driver. Use get_symbol_fw script to generate spectrum_fw.h and + * copy it to the same directory as spectrum_cs.c. + * + * If SPECTRUM_FW_INCLUDED is not defined, the firmware is loaded at the + * runtime using hotplug. Use the same get_symbol_fw script to generate + * files symbol_sp24t_prim_fw symbol_sp24t_sec_fw, copy them to the + * hotplug firmware directory (typically /usr/lib/hotplug/firmware) and + * make sure that you have hotplug installed and enabled in the kernel. + */ +/* #define SPECTRUM_FW_INCLUDED 1 */ + +#ifdef SPECTRUM_FW_INCLUDED +/* Header with the firmware */ +#include "spectrum_fw.h" +#else /* !SPECTRUM_FW_INCLUDED */ +#include <linux/firmware.h> +static unsigned char *primsym; +static unsigned char *secsym; +static const char primary_fw_name[] = "symbol_sp24t_prim_fw"; +static const char secondary_fw_name[] = "symbol_sp24t_sec_fw"; +#endif /* !SPECTRUM_FW_INCLUDED */ + +/********************************************************************/ +/* Module stuff */ +/********************************************************************/ + +MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>"); +MODULE_DESCRIPTION("Driver for Symbol Spectrum24 Trilogy cards with firmware downloader"); +MODULE_LICENSE("Dual MPL/GPL"); + +/* Module parameters */ + +/* Some D-Link cards have buggy CIS. They do work at 5v properly, but + * don't have any CIS entry for it. This workaround it... */ +static int ignore_cis_vcc; /* = 0 */ +module_param(ignore_cis_vcc, int, 0); +MODULE_PARM_DESC(ignore_cis_vcc, "Allow voltage mismatch between card and socket"); + +/********************************************************************/ +/* Magic constants */ +/********************************************************************/ + +/* + * The dev_info variable is the "key" that is used to match up this + * device driver with appropriate cards, through the card + * configuration database. + */ +static dev_info_t dev_info = DRIVER_NAME; + +/********************************************************************/ +/* Data structures */ +/********************************************************************/ + +/* PCMCIA specific device information (goes in the card field of + * struct orinoco_private */ +struct orinoco_pccard { + dev_link_t link; + dev_node_t node; +}; + +/* + * A linked list of "instances" of the device. Each actual PCMCIA + * card corresponds to one device instance, and is described by one + * dev_link_t structure (defined in ds.h). + */ +static dev_link_t *dev_list; /* = NULL */ + +/********************************************************************/ +/* Function prototypes */ +/********************************************************************/ + +/* device methods */ +static int spectrum_cs_hard_reset(struct orinoco_private *priv); + +/* PCMCIA gumpf */ +static void spectrum_cs_config(dev_link_t * link); +static void spectrum_cs_release(dev_link_t * link); +static int spectrum_cs_event(event_t event, int priority, + event_callback_args_t * args); + +static dev_link_t *spectrum_cs_attach(void); +static void spectrum_cs_detach(dev_link_t *); + +/********************************************************************/ +/* Firmware downloader */ +/********************************************************************/ + +/* Position of PDA in the adapter memory */ +#define EEPROM_ADDR 0x3000 +#define EEPROM_LEN 0x200 +#define PDA_OFFSET 0x100 + +#define PDA_ADDR (EEPROM_ADDR + PDA_OFFSET) +#define PDA_WORDS ((EEPROM_LEN - PDA_OFFSET) / 2) + +/* Constants for the CISREG_CCSR register */ +#define HCR_RUN 0x07 /* run firmware after reset */ +#define HCR_IDLE 0x0E /* don't run firmware after reset */ +#define HCR_MEM16 0x10 /* memory width bit, should be preserved */ + +/* + * AUX port access. To unlock the AUX port write the access keys to the + * PARAM0-2 registers, then write HERMES_AUX_ENABLE to the HERMES_CONTROL + * register. Then read it and make sure it's HERMES_AUX_ENABLED. + */ +#define HERMES_AUX_ENABLE 0x8000 /* Enable auxiliary port access */ +#define HERMES_AUX_DISABLE 0x4000 /* Disable to auxiliary port access */ +#define HERMES_AUX_ENABLED 0xC000 /* Auxiliary port is open */ + +#define HERMES_AUX_PW0 0xFE01 +#define HERMES_AUX_PW1 0xDC23 +#define HERMES_AUX_PW2 0xBA45 + +/* End markers */ +#define PDI_END 0x00000000 /* End of PDA */ +#define BLOCK_END 0xFFFFFFFF /* Last image block */ +#define TEXT_END |