Commit 2e3d689f authored by David Gibson's avatar David Gibson Committed by David S. Miller

[PATCH] Update orinoco driver to 0.13e

This updates the orinoco driver, fixing many bugs and adding some minor
features.  It also adds a new module, orinoco_tmd for devices based on
the TMD7168 PCI<->PCMCIA adaptor.
parent 63aff461
...@@ -203,7 +203,7 @@ config PLX_HERMES ...@@ -203,7 +203,7 @@ config PLX_HERMES
depends on PCI && HERMES && EXPERIMENTAL depends on PCI && HERMES && EXPERIMENTAL
help help
Enable support for PCMCIA cards supported by the "Hermes" (aka Enable support for PCMCIA cards supported by the "Hermes" (aka
orinoco_cs) driver when used in PLX9052 based PCI adaptors. These orinoco) driver when used in PLX9052 based PCI adaptors. These
adaptors are not a full PCMCIA controller but act as a more limited adaptors are not a full PCMCIA controller but act as a more limited
PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
802.11b PCMCIA cards can be used in desktop machines. The Netgear 802.11b PCMCIA cards can be used in desktop machines. The Netgear
...@@ -212,6 +212,19 @@ config PLX_HERMES ...@@ -212,6 +212,19 @@ config PLX_HERMES
Support for these adaptors is so far still incomplete and buggy. Support for these adaptors is so far still incomplete and buggy.
You have been warned. You have been warned.
config TMD_HERMES
tristate "Hermes in TMD7160 based PCI adaptor support (EXPERIMENTAL)"
depends on PCI && HERMES && EXPERIMENTAL
help
Enable support for PCMCIA cards supported by the "Hermes" (aka
orinoco) driver when used in TMD7160 based PCI adaptors. These
adaptors are not a full PCMCIA controller but act as a more limited
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 PCI_HERMES config PCI_HERMES
tristate "Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)" tristate "Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)"
depends on PCI && HERMES && EXPERIMENTAL depends on PCI && HERMES && EXPERIMENTAL
......
...@@ -15,6 +15,7 @@ obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o ...@@ -15,6 +15,7 @@ obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
obj-$(CONFIG_APPLE_AIRPORT) += airport.o obj-$(CONFIG_APPLE_AIRPORT) += airport.o
obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o obj-$(CONFIG_PLX_HERMES) += orinoco_plx.o
obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o obj-$(CONFIG_PCI_HERMES) += orinoco_pci.o
obj-$(CONFIG_TMD_HERMES) += orinoco_tmd.o
obj-$(CONFIG_AIRO) += airo.o obj-$(CONFIG_AIRO) += airo.o
obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o obj-$(CONFIG_AIRO_CS) += airo_cs.o airo.o
......
/* airport.c 0.13a /* airport.c 0.13e
* *
* A driver for "Hermes" chipset based Apple Airport wireless * A driver for "Hermes" chipset based Apple Airport wireless
* card. * card.
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -20,7 +21,6 @@ ...@@ -20,7 +21,6 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
...@@ -95,7 +95,7 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when) ...@@ -95,7 +95,7 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
netif_device_detach(dev); netif_device_detach(dev);
priv->hw_unavailable = 1; priv->hw_unavailable++;
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
...@@ -121,14 +121,15 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when) ...@@ -121,14 +121,15 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
netif_device_attach(dev); netif_device_attach(dev);
if (priv->open) { priv->hw_unavailable--;
if (priv->open && (! priv->hw_unavailable)) {
err = __orinoco_up(dev); err = __orinoco_up(dev);
if (err) if (err)
printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n", printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
dev->name, err); dev->name, err);
} }
priv->hw_unavailable = 0;
spin_unlock_irqrestore(&priv->lock, flags); spin_unlock_irqrestore(&priv->lock, flags);
...@@ -138,6 +139,37 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when) ...@@ -138,6 +139,37 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
} }
#endif /* CONFIG_PMAC_PBOOK */ #endif /* CONFIG_PMAC_PBOOK */
static int airport_hard_reset(struct orinoco_private *priv)
{
/* It would be nice to power cycle the Airport for a real hard
* reset, but for some reason although it appears to
* re-initialize properly, it falls in a screaming heap
* shortly afterwards. */
#if 0
struct net_device *dev = priv->ndev;
struct airport *card = priv->card;
/* Vitally important. If we don't do this it seems we get an
* interrupt somewhere during the power cycle, since
* hw_unavailable is already set it doesn't get ACKed, we get
* into an interrupt loop and the the PMU decides to turn us
* off. */
disable_irq(dev->irq);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 0);
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ);
pmac_call_feature(PMAC_FTR_AIRPORT_ENABLE, card->node, 0, 1);
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ);
enable_irq(dev->irq);
schedule_timeout(HZ);
#endif
return 0;
}
static struct net_device * static struct net_device *
airport_attach(struct device_node *of_node) airport_attach(struct device_node *of_node)
{ {
...@@ -153,7 +185,7 @@ airport_attach(struct device_node *of_node) ...@@ -153,7 +185,7 @@ airport_attach(struct device_node *of_node)
} }
/* Allocate space for private device-specific data */ /* Allocate space for private device-specific data */
dev = alloc_orinocodev(sizeof(*card), NULL); dev = alloc_orinocodev(sizeof(*card), airport_hard_reset);
if (! dev) { if (! dev) {
printk(KERN_ERR "airport: can't allocate device datas\n"); printk(KERN_ERR "airport: can't allocate device datas\n");
return NULL; return NULL;
...@@ -195,7 +227,7 @@ airport_attach(struct device_node *of_node) ...@@ -195,7 +227,7 @@ airport_attach(struct device_node *of_node)
/* Reset it before we get the interrupt */ /* Reset it before we get the interrupt */
hermes_init(hw); hermes_init(hw);
if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", (void *)priv)) { if (request_irq(dev->irq, orinoco_interrupt, 0, "Airport", dev)) {
printk(KERN_ERR "airport: Couldn't get IRQ %d\n", dev->irq); printk(KERN_ERR "airport: Couldn't get IRQ %d\n", dev->irq);
goto failed; goto failed;
} }
...@@ -209,11 +241,6 @@ airport_attach(struct device_node *of_node) ...@@ -209,11 +241,6 @@ airport_attach(struct device_node *of_node)
printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name); printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name);
card->ndev_registered = 1; card->ndev_registered = 1;
/* And give us the proc nodes for debugging */
if (orinoco_proc_dev_init(dev) != 0)
printk(KERN_ERR "airport: Failed to create /proc node for %s\n",
dev->name);
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
pmu_register_sleep_notifier(&airport_sleep_notifier); pmu_register_sleep_notifier(&airport_sleep_notifier);
#endif #endif
...@@ -234,9 +261,6 @@ airport_detach(struct net_device *dev) ...@@ -234,9 +261,6 @@ airport_detach(struct net_device *dev)
struct orinoco_private *priv = dev->priv; struct orinoco_private *priv = dev->priv;
struct airport *card = priv->card; struct airport *card = priv->card;
/* Unregister proc entry */
orinoco_proc_dev_cleanup(dev);
#ifdef CONFIG_PMAC_PBOOK #ifdef CONFIG_PMAC_PBOOK
pmu_unregister_sleep_notifier(&airport_sleep_notifier); pmu_unregister_sleep_notifier(&airport_sleep_notifier);
#endif #endif
...@@ -245,7 +269,7 @@ airport_detach(struct net_device *dev) ...@@ -245,7 +269,7 @@ airport_detach(struct net_device *dev)
card->ndev_registered = 0; card->ndev_registered = 0;
if (card->irq_requested) if (card->irq_requested)
free_irq(dev->irq, priv); free_irq(dev->irq, dev);
card->irq_requested = 0; card->irq_requested = 0;
if (card->vaddr) if (card->vaddr)
...@@ -263,7 +287,7 @@ airport_detach(struct net_device *dev) ...@@ -263,7 +287,7 @@ airport_detach(struct net_device *dev)
kfree(dev); kfree(dev);
} /* airport_detach */ } /* airport_detach */
static char version[] __initdata = "airport.c 0.13a (Benjamin Herrenschmidt <benh@kernel.crashing.org>)"; static char version[] __initdata = "airport.c 0.13e (Benjamin Herrenschmidt <benh@kernel.crashing.org>)";
MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>"); MODULE_AUTHOR("Benjamin Herrenschmidt <benh@kernel.crashing.org>");
MODULE_DESCRIPTION("Driver for the Apple Airport wireless card."); MODULE_DESCRIPTION("Driver for the Apple Airport wireless card.");
MODULE_LICENSE("Dual MPL/GPL"); MODULE_LICENSE("Dual MPL/GPL");
......
...@@ -52,7 +52,6 @@ ...@@ -52,7 +52,6 @@
#include "hermes.h" #include "hermes.h"
static char version[] __initdata = "hermes.c: 4 Jul 2002 David Gibson <hermes@gibson.dropbear.id.au>";
MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller"); MODULE_DESCRIPTION("Low-level driver helper for Lucent Hermes chipset and Prism II HFA384x wireless MAC controller");
MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>"); MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
#ifdef MODULE_LICENSE #ifdef MODULE_LICENSE
...@@ -226,7 +225,8 @@ int hermes_init(hermes_t *hw) ...@@ -226,7 +225,8 @@ int hermes_init(hermes_t *hw)
* Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware * Returns: < 0 on internal error, 0 on success, > 0 on error returned by the firmware
* *
* Callable from any context, but locking is your problem. */ * Callable from any context, but locking is your problem. */
int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp) int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0,
hermes_response_t *resp)
{ {
int err; int err;
int k; int k;
...@@ -402,7 +402,7 @@ static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset) ...@@ -402,7 +402,7 @@ static int hermes_bap_seek(hermes_t *hw, int bap, u16 id, u16 offset)
* *
* Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
*/ */
int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len,
u16 id, u16 offset) u16 id, u16 offset)
{ {
int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
...@@ -428,7 +428,7 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, ...@@ -428,7 +428,7 @@ int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len,
* *
* Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware
*/ */
int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
u16 id, u16 offset) u16 id, u16 offset)
{ {
int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
...@@ -456,26 +456,30 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, ...@@ -456,26 +456,30 @@ int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len,
* practice. * practice.
* *
* Callable from user or bh context. */ * Callable from user or bh context. */
int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int bufsize, int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned bufsize,
u16 *length, void *buf) u16 *length, void *buf)
{ {
int err = 0; int err = 0;
int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
u16 rlength, rtype; u16 rlength, rtype;
int nwords; unsigned nwords;
if ( (bufsize < 0) || (bufsize % 2) ) if ( (bufsize < 0) || (bufsize % 2) )
return -EINVAL; return -EINVAL;
err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL); err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
if (err) if (err)
goto out; return err;
err = hermes_bap_seek(hw, bap, rid, 0); err = hermes_bap_seek(hw, bap, rid, 0);
if (err) if (err)
goto out; return err;
rlength = hermes_read_reg(hw, dreg); rlength = hermes_read_reg(hw, dreg);
if (! rlength)
return -ENOENT;
rtype = hermes_read_reg(hw, dreg); rtype = hermes_read_reg(hw, dreg);
if (length) if (length)
...@@ -492,11 +496,10 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int bufsize, ...@@ -492,11 +496,10 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int bufsize,
IO_TYPE(hw), hw->iobase, IO_TYPE(hw), hw->iobase,
HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength); HERMES_RECLEN_TO_BYTES(rlength), bufsize, rid, rlength);
nwords = min_t(int, rlength - 1, bufsize / 2); nwords = min((unsigned)rlength - 1, bufsize / 2);
hermes_read_words(hw, dreg, buf, nwords); hermes_read_words(hw, dreg, buf, nwords);
out: return 0;
return err;
} }
int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
...@@ -504,11 +507,14 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, ...@@ -504,11 +507,14 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
{ {
int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
int err = 0; int err = 0;
int count; unsigned count;
if (length == 0)
return -EINVAL;
err = hermes_bap_seek(hw, bap, rid, 0); err = hermes_bap_seek(hw, bap, rid, 0);
if (err) if (err)
goto out; return err;
hermes_write_reg(hw, dreg, length); hermes_write_reg(hw, dreg, length);
hermes_write_reg(hw, dreg, rid); hermes_write_reg(hw, dreg, rid);
...@@ -520,7 +526,6 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, ...@@ -520,7 +526,6 @@ int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE, err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS | HERMES_CMD_WRITE,
rid, NULL); rid, NULL);
out:
return err; return err;
} }
...@@ -536,9 +541,12 @@ EXPORT_SYMBOL(hermes_write_ltv); ...@@ -536,9 +541,12 @@ EXPORT_SYMBOL(hermes_write_ltv);
static int __init init_hermes(void) static int __init init_hermes(void)
{ {
printk(KERN_DEBUG "%s\n", version);
return 0; return 0;
} }
static void __exit exit_hermes(void)
{
}
module_init(init_hermes); module_init(init_hermes);
module_exit(exit_hermes);
...@@ -250,7 +250,6 @@ struct hermes_scan_frame { ...@@ -250,7 +250,6 @@ struct hermes_scan_frame {
u16 scanreason; /* ??? */ u16 scanreason; /* ??? */
struct hermes_scan_apinfo aps[35]; /* Scan result */ struct hermes_scan_apinfo aps[35]; /* Scan result */
} __attribute__ ((packed)); } __attribute__ ((packed));
#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000) #define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
#define HERMES_LINKSTATUS_CONNECTED (0x0001) #define HERMES_LINKSTATUS_CONNECTED (0x0001)
#define HERMES_LINKSTATUS_DISCONNECTED (0x0002) #define HERMES_LINKSTATUS_DISCONNECTED (0x0002)
...@@ -278,7 +277,7 @@ struct hermes_debug_entry { ...@@ -278,7 +277,7 @@ struct hermes_debug_entry {
/* Basic control structure */ /* Basic control structure */
typedef struct hermes { typedef struct hermes {
ulong iobase; unsigned long iobase;
int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */ int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */
#define HERMES_IO 1 #define HERMES_IO 1
#define HERMES_MEM 0 #define HERMES_MEM 0
...@@ -316,11 +315,11 @@ int hermes_init(hermes_t *hw); ...@@ -316,11 +315,11 @@ int hermes_init(hermes_t *hw);
int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp); int hermes_docmd_wait(hermes_t *hw, u16 cmd, u16 parm0, hermes_response_t *resp);
int hermes_allocate(hermes_t *hw, u16 size, u16 *fid); int hermes_allocate(hermes_t *hw, u16 size, u16 *fid);
int hermes_bap_pread(hermes_t *hw, int bap, void *buf, int len, int hermes_bap_pread(hermes_t *hw, int bap, void *buf, unsigned len,
u16 id, u16 offset); u16 id, u16 offset);
int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, int len, int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len,
u16 id, u16 offset); u16 id, u16 offset);
int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int buflen, int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen,
u16 *length, void *buf); u16 *length, void *buf);
int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
u16 length, const void *value); u16 length, const void *value);
...@@ -361,42 +360,61 @@ static inline int hermes_inquire(hermes_t *hw, u16 rid) ...@@ -361,42 +360,61 @@ static inline int hermes_inquire(hermes_t *hw, u16 rid)
#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 ) #define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 )
/* Note that for the next two, the count is in 16-bit words, not bytes */ /* Note that for the next two, the count is in 16-bit words, not bytes */
static inline void hermes_read_words(struct hermes *hw, int off, void *buf, int count) static inline void hermes_read_words(struct hermes *hw, int off, void *buf, unsigned count)
{ {
off = off << hw->reg_spacing;; off = off << hw->reg_spacing;;
if (hw->io_space) { if (hw->io_space) {
insw(hw->iobase + off, buf, count); insw(hw->iobase + off, buf, count);
} else { } else {
int i; unsigned i;
u16 *p; u16 *p;
/* This need to *not* byteswap (like insw()) but /* This needs to *not* byteswap (like insw()) but
* readw() does byteswap hence the conversion */ * readw() does byteswap hence the conversion. I hope
* gcc is smart enough to fold away the two swaps on
* big-endian platforms. */
for (i = 0, p = buf; i < count; i++) { for (i = 0, p = buf; i < count; i++) {
*p++ = cpu_to_le16(readw(hw->iobase + off)); *p++ = cpu_to_le16(readw(hw->iobase + off));
} }
} }
} }
static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, int count) static inline void hermes_write_words(struct hermes *hw, int off, const void *buf, unsigned count)
{ {
off = off << hw->reg_spacing;; off = off << hw->reg_spacing;;
if (hw->io_space) { if (hw->io_space) {
outsw(hw->iobase + off, buf, count); outsw(hw->iobase + off, buf, count);
} else { } else {
int i; unsigned i;
const u16 *p; const u16 *p;
/* This need to *not* byteswap (like outsw()) but /* This needs to *not* byteswap (like outsw()) but
* writew() does byteswap hence the conversion */ * writew() does byteswap hence the conversion. I
* hope gcc is smart enough to fold away the two swaps
* on big-endian platforms. */
for (i = 0, p = buf; i < count; i++) { for (i = 0, p = buf; i < count; i++) {
writew(le16_to_cpu(*p++), hw->iobase + off); writew(le16_to_cpu(*p++), hw->iobase + off);
} }
} }
} }
static inline void hermes_clear_words(struct hermes *hw, int off, unsigned count)
{
unsigned i;
off = off << hw->reg_spacing;;
if (hw->io_space) {
for (i = 0; i < count; i++)
outw(0, hw->iobase + off);
} else {
for (i = 0; i < count; i++)
writew(0, hw->iobase + off);
}
}
#define HERMES_READ_RECORD(hw, bap, rid, buf) \ #define HERMES_READ_RECORD(hw, bap, rid, buf) \
(hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf))) (hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf)))
#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \ #define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
......
...@@ -2,9 +2,15 @@ ...@@ -2,9 +2,15 @@
#define _IEEE802_11_H #define _IEEE802_11_H
#define IEEE802_11_DATA_LEN 2304 #define IEEE802_11_DATA_LEN 2304
/* Actually, the standard seems to be inconsistent about what the /* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
maximum frame size really is. Section 6.2.1.1.2 says 2304 octets, 6.2.1.1.2.
but the figure in Section 7.1.2 says 2312 octects. */
The figure in section 7.1.2 suggests a body size of up to 2312
bytes is allowed, which is a bit confusing, I suspect this
represents the 2304 bytes of real data, plus a possible 8 bytes of
WEP IV and ICV. (this interpretation suggested by Ramiro Barreiro) */
#define IEEE802_11_HLEN 30 #define IEEE802_11_HLEN 30
#define IEEE802_11_FRAME_LEN (IEEE802_11_DATA_LEN + IEEE802_11_HLEN) #define IEEE802_11_FRAME_LEN (IEEE802_11_DATA_LEN + IEEE802_11_HLEN)
......
This diff is collapsed.
...@@ -11,9 +11,29 @@ ...@@ -11,9 +11,29 @@
#include <linux/spinlock.h> #include <linux/spinlock.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/wireless.h> #include <linux/wireless.h>
#include <linux/workqueue.h> #include <linux/version.h>
#include "hermes.h" #include "hermes.h"
/* Workqueue / task queue backwards compatibility stuff */
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,5,41)
#include <linux/workqueue.h>
#else
#include <linux/tqueue.h>
#define work_struct tq_struct
#define INIT_WORK INIT_TQUEUE
#define schedule_work schedule_task
#endif
/* Interrupt handler backwards compatibility stuff */
#ifndef IRQ_NONE
#define IRQ_NONE
#define IRQ_HANDLED
typedef void irqreturn_t;
#endif
/* To enable debug messages */ /* To enable debug messages */
//#define ORINOCO_DEBUG 3 //#define ORINOCO_DEBUG 3
...@@ -42,9 +62,12 @@ struct orinoco_private { ...@@ -42,9 +62,12 @@ struct orinoco_private {
/* Synchronisation stuff */ /* Synchronisation stuff */
spinlock_t lock; spinlock_t lock;
int hw_unavailable; int hw_unavailable;
struct work_struct timeout_task; struct work_struct reset_work;
/* driver state */
int open; int open;
u16 last_linkstatus;
int connected;
/* Net device stuff */ /* Net device stuff */
struct net_device *ndev; struct net_device *ndev;
...@@ -55,6 +78,7 @@ struct orinoco_private { ...@@ -55,6 +78,7 @@ struct orinoco_private {
hermes_t hw; hermes_t hw;
u16 txfid; u16 txfid;
/* Capabilities of the hardware/firmware */ /* Capabilities of the hardware/firmware */
int firmware_type; int firmware_type;
#define FIRMWARE_TYPE_AGERE 1 #define FIRMWARE_TYPE_AGERE 1
...@@ -68,6 +92,7 @@ struct orinoco_private { ...@@ -68,6 +92,7 @@ struct orinoco_private {
int has_sensitivity; int has_sensitivity;
int nicbuf_size; int nicbuf_size;
u16 channel_mask; u16 channel_mask;
int broken_disableport;
/* Configuration paramaters */ /* Configuration paramaters */
u32 iw_mode; u32 iw_mode;
...@@ -91,9 +116,6 @@ struct orinoco_private { ...@@ -91,9 +116,6 @@ struct orinoco_private {
/* Configuration dependent variables */ /* Configuration dependent variables */
int port_type, createibss; int port_type, createibss;
int promiscuous, mc_count; int promiscuous, mc_count;
/* /proc based debugging stuff */
struct proc_dir_entry *dir_dev;
}; };
#ifdef ORINOCO_DEBUG #ifdef ORINOCO_DEBUG
...@@ -110,10 +132,8 @@ extern struct net_device *alloc_orinocodev(int sizeof_card, ...@@ -110,10 +132,8 @@ extern struct net_device *alloc_orinocodev(int sizeof_card,
int (*hard_reset)(struct orinoco_private *)); int (*hard_reset)(struct orinoco_private *));
extern int __orinoco_up(struct net_device *dev); extern int __orinoco_up(struct net_device *dev);
extern int __orinoco_down(struct net_device *dev); extern int __orinoco_down(struct net_device *dev);
int orinoco_reinit_firmware(struct net_device *dev); extern int orinoco_stop(struct net_device *dev);
extern int orinoco_reinit_firmware(struct net_device *dev);
extern int orinoco_proc_dev_init(struct net_device *dev);
extern void orinoco_proc_dev_cleanup(struct net_device *dev);
extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs); extern irqreturn_t orinoco_interrupt(int irq, void * dev_id, struct pt_regs *regs);
/********************************************************************/ /********************************************************************/
......
/* orinoco_cs.c 0.13a - (formerly known as dldwd_cs.c) /* orinoco_cs.c 0.13e - (formerly known as dldwd_cs.c)
* *
* A driver for "Hermes" chipset based PCMCIA wireless adaptors, such * A driver for "Hermes" chipset based PCMCIA wireless adaptors, such
* as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/ * as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#ifdef __IN_PCMCIA_PACKAGE__ #ifdef __IN_PCMCIA_PACKAGE__
#include <pcmcia/k_compat.h> #include <pcmcia/k_compat.h>
#endif /* __IN_PCMCIA_PACKAGE__ */ #endif /* __IN_PCMCIA_PACKAGE__ */
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -21,9 +22,7 @@ ...@@ -21,9 +22,7 @@
#include <linux/ptrace.h> #include <linux/ptrace.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
...@@ -90,8 +89,9 @@ struct orinoco_pccard { ...@@ -90,8 +89,9 @@ struct orinoco_pccard {
dev_node_t node; dev_node_t node;
/* Used to handle hard reset */ /* Used to handle hard reset */
wait_queue_head_t hard_reset_queue; /* yuck, we need this hack to work around the insanity of the
int hard_reset_flag; * PCMCIA layer */
unsigned long hard_reset_in_progress;
}; };
/* /*
...@@ -128,14 +128,14 @@ orinoco_cs_hard_reset(struct orinoco_private *priv) ...@@ -128,14 +128,14 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
dev_link_t *link = &card->link; dev_link_t *link = &card->link;
int err; int err;
card->hard_reset_flag = 0; /* We need atomic ops here, because we're not holding the lock */
set_bit(0, &card->hard_reset_in_progress);
err = CardServices(ResetCard, link->handle, NULL); err = CardServices(ResetCard, link->handle, NULL);
if (err) if (err)
return err; return err;
wait_event_interruptible(card->hard_reset_queue, clear_bit(0, &card->hard_reset_in_progress);
card->hard_reset_flag);
return 0; return 0;
} }
...@@ -144,6 +144,16 @@ orinoco_cs_hard_reset(struct orinoco_private *priv) ...@@ -144,6 +144,16 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
/* PCMCIA stuff */ /* PCMCIA stuff */
/********************************************************************/ /********************************************************************/
/* In 2.5 (as of 2.5.69 at least) there is a cs_error exported which
* does this, but it's not in 2.4 so we do our own for now. */
static void
orinoco_cs_error(client_handle_t handle, int func, int ret)
{
error_info_t err = { func, ret };
CardServices(ReportError, handle, &err);
}
/* Remove zombie instances (card removed, detach pending) */ /* Remove zombie instances (card removed, detach pending) */
static void static void
flush_stale_links(void) flush_stale_links(void)
...@@ -187,7 +197,6 @@ orinoco_cs_attach(void) ...@@ -187,7 +197,6 @@ orinoco_cs_attach(void)
return NULL; return NULL;
priv = dev->priv; priv = dev->priv;
card = priv->card; card = priv->card;
init_waitqueue_head(&card->hard_reset_queue);
/* Link both structures together */ /* Link both structures together */
link = &card->link; link = &card->link;
...@@ -233,7 +242,7 @@ orinoco_cs_attach(void) ...@@ -233,7 +242,7 @@ orinoco_cs_attach(void)
ret = CardServices(RegisterClient, &link->handle, &client_reg); ret = CardServices(RegisterClient, &link->handle, &client_reg);
if (ret != CS_SUCCESS) { if (ret != CS_SUCCESS) {
cs_error(link->handle, RegisterClient, ret); orinoco_cs_error(link->handle, RegisterClient, ret);
orinoco_cs_detach(link); orinoco_cs_detach(link);
return NULL; return NULL;
} }
...@@ -262,20 +271,13 @@ orinoco_cs_detach(dev_link_t * link) ...@@ -262,20 +271,13 @@ orinoco_cs_detach(dev_link_t * link)
return; return;
} }
/*
If the device is currently configured and active, we won't
actually delete it yet. Instead, it is marked so that when
the release() function is called, that will trigger a proper
detach().
*/
if (link->state & DEV_CONFIG) { if (link->state & DEV_CONFIG) {
#ifdef PCMCIA_DEBUG orinoco_cs_release((u_long)link);
printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' " if (link->state & DEV_CONFIG) {
"still locked\n", link->dev->dev_name);
#endif
link->state |= DEV_STALE_LINK; link->state |= DEV_STALE_LINK;
return; return;
} }
}
/* Break the link with Card Services */ /* Break the link with Card Services */
if (link->handle) if (link->handle)
...@@ -465,7 +467,7 @@ orinoco_cs_config(dev_link_t *link) ...@@ -465,7 +467,7 @@ orinoco_cs_config(dev_link_t *link)
link->irq.IRQInfo2 |= 1 << irq_list[i]; link->irq.IRQInfo2 |= 1 << irq_list[i];
link->irq.Handler = orinoco_interrupt; link->irq.Handler = orinoco_interrupt;
link->irq.Instance = priv; link->irq.Instance = dev;
CS_CHECK(RequestIRQ, link->handle, &link->irq); CS_CHECK(RequestIRQ, link->handle, &link->irq);
} }
...@@ -522,18 +524,10 @@ orinoco_cs_config(dev_link_t *link) ...@@ -522,18 +524,10 @@ orinoco_cs_config(dev_link_t *link)
link->io.BasePort2 + link->io.NumPorts2 - 1); link->io.BasePort2 + link->io.NumPorts2 - 1);
printk("\n"); printk("\n");
/* And give us the proc nodes for debugging */
if (orinoco_proc_dev_init(dev) != 0) {
printk(KERN_ERR "orinoco_cs: Failed to create /proc node for %s\n",
dev->name);
goto failed;
}
return; return;
cs_failed: cs_failed:
cs_error(link->handle, last_fn, last_ret); orinoco_cs_error(link->handle, last_fn, last_ret);
failed: failed:
orinoco_cs_release((u_long) link); orinoco_cs_release((u_long) link);
...@@ -550,21 +544,13 @@ orinoco_cs_release(u_long arg) ...@@ -550,21 +544,13 @@ orinoco_cs_release(u_long arg)
dev_link_t *link = (dev_link_t *) arg; dev_link_t *link = (dev_link_t *) arg;
struct net_device *dev = link->priv; struct net_device *dev = link->priv;
struct orinoco_private *priv = dev->priv; struct orinoco_private *priv = dev->priv;
unsigned long flags;
/* /* We're committed to taking the device away now, so mark the
If the device is currently in use, we won't release until it * hardware as unavailable */
is actually closed, because until then, we can't be sure that spin_lock_irqsave(&priv->lock, flags);
no one will try to access the device or its data structures. priv->hw_unavailable++;
*/ spin_unlock_irqrestore(&priv->lock, flags);
if (priv->open) {
DEBUG(0, "orinoco_cs: release postponed, '%s' still open\n",
link->dev->dev_name);
link->state |= DEV_STALE_CONFIG;
return;
}
/* Unregister proc entry */
orinoco_proc_dev_cleanup(dev);
/* Don't bother checking to see if these succeed or not */ /* Don't bother checking to see if these succeed or not */
CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseConfiguration, link->handle);
...@@ -586,6 +572,7 @@ orinoco_cs_event(event_t event, int priority, ...@@ -586,6 +572,7 @@ orinoco_cs_event(event_t event, int priority,
dev_link_t *link = args->client_data; dev_link_t *link = args->client_data;
struct net_device *dev = link->priv; struct net_device *dev = link->priv;
struct orinoco_private *priv = dev->priv; struct orinoco_private *priv = dev->priv;
struct orinoco_pccard *card = priv->card;
int err = 0; int err = 0;
unsigned long flags; unsigned long flags;
...@@ -596,14 +583,9 @@ orinoco_cs_event(event_t event, int priority, ...@@ -596,14 +583,9 @@ orinoco_cs_event(event_t event, int priority,
orinoco_lock(priv, &flags); orinoco_lock(priv, &flags);
netif_device_detach(dev); netif_device_detach(dev);
priv->hw_unavailable = 1; priv->hw_unavailable++;
orinoco_unlock(priv, &flags); orinoco_unlock(priv, &flags);
/* if (link->open) */
/* orinoco_cs_stop(dev); */
mod_timer(&link->release, jiffies + HZ / 20);
} }
break; break;
...@@ -618,12 +600,11 @@ orinoco_cs_event(event_t event, int priority, ...@@ -618,12 +600,11 @@ orinoco_cs_event(event_t event, int priority,
case CS_EVENT_RESET_PHYSICAL: case CS_EVENT_RESET_PHYSICAL:
/* Mark the device as stopped, to block IO until later */ /* Mark the device as stopped, to block IO until later */
if (link->state & DEV_CONFIG) { if (link->state & DEV_CONFIG) {
err = orinoco_lock(priv, &flags); /* This is probably racy, but I can't think of
if (err) { a better way, short of rewriting the PCMCIA
printk(KERN_ERR "%s: hw_unavailable on SUSPEND/RESET_PHYSICAL\n", layer to not suck :-( */
dev->name); if (! test_bit(0, &card->hard_reset_in_progress)) {
break; spin_lock_irqsave(&priv->lock, flags);
}
err = __orinoco_down(dev); err = __orinoco_down(dev);
if (err) if (err)
...@@ -633,9 +614,10 @@ orinoco_cs_event(event_t event, int priority, ...@@ -633,9 +614,10 @@ orinoco_cs_event(event_t event, int priority,
err); err);
netif_device_detach(dev); netif_device_detach(dev);
priv->hw_unavailable = 1; priv->hw_unavailable++;
orinoco_unlock(priv, &flags); spin_unlock_irqrestore(&priv->lock, flags);
}
CardServices(ReleaseConfiguration, link->handle); CardServices(ReleaseConfiguration, link->handle);
} }
...@@ -646,11 +628,12 @@ orinoco_cs_event(event_t event, int priority, ...@@ -646,11 +628,12 @@ orinoco_cs_event(event_t event, int priority,
/* Fall through... */ /* Fall through... */
case CS_EVENT_CARD_RESET: case CS_EVENT_CARD_RESET:
if (link->state & DEV_CONFIG) { if (link->state & DEV_CONFIG) {
/* FIXME: should we double check that this is
* the same card as we had before */
CardServices(RequestConfiguration, link->handle, CardServices(RequestConfiguration, link->handle,
&link->conf); &link->conf);
/* FIXME: should we double check that this is if (! test_bit(0, &card->hard_reset_in_progress)) {
* the same card as we had before */
err = orinoco_reinit_firmware(dev); err = orinoco_reinit_firmware(dev);
if (err) { if (err) {
printk(KERN_ERR "%s: Error %d re-initializing firmware\n", printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
...@@ -661,9 +644,9 @@ orinoco_cs_event(event_t event, int priority, ...@@ -661,9 +644,9 @@ orinoco_cs_event(event_t event, int priority,
spin_lock_irqsave(&priv->lock, flags); spin_lock_irqsave(&priv->lock, flags);
netif_device_attach(dev); netif_device_attach(dev);
priv->hw_unavailable = 0; priv->hw_unavailable--;
if (priv->open) { if (priv->open && ! priv->hw_unavailable) {
err = __orinoco_up(dev); err = __orinoco_up(dev);
if (err) if (err)
printk(KERN_ERR "%s: Error %d restarting card\n", printk(KERN_ERR "%s: Error %d restarting card\n",
...@@ -671,7 +654,8 @@ orinoco_cs_event(event_t event, int priority, ...@@ -671,7 +654,8 @@ orinoco_cs_event(event_t event, int priority,
} }
orinoco_unlock(priv, &flags); spin_unlock_irqrestore(&priv->lock, flags);
}
} }
break; break;
} }
...@@ -685,7 +669,7 @@ orinoco_cs_event(event_t event, int priority, ...@@ -685,7 +669,7 @@ orinoco_cs_event(event_t event, int priority,
/* Can't be declared "const" or the whole __initdata section will /* Can't be declared "const" or the whole __initdata section will
* become const */ * become const */
static char version[] __initdata = "orinoco_cs.c 0.13a (David Gibson <hermes@gibson.dropbear.id.au> and others)"; static char version[] __initdata = "orinoco_cs.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> and others)";
static struct pcmcia_driver orinoco_driver = { static struct pcmcia_driver orinoco_driver = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
...@@ -712,7 +696,6 @@ exit_orinoco_cs(void) ...@@ -712,7 +696,6 @@ exit_orinoco_cs(void)
if (dev_list) if (dev_list)
DEBUG(0, "orinoco_cs: Removing leftover devices.\n"); DEBUG(0, "orinoco_cs: Removing leftover devices.\n");
while (dev_list != NULL) { while (dev_list != NULL) {
del_timer(&dev_list->release);
if (dev_list->state & DEV_CONFIG) if (dev_list->state & DEV_CONFIG)
orinoco_cs_release((u_long) dev_list); orinoco_cs_release((u_long) dev_list);
orinoco_cs_detach(dev_list); orinoco_cs_detach(dev_list);
......
/* orinoco_pci.c 0.13a /* orinoco_pci.c 0.13e
* *
* Driver for Prism II devices that have a direct PCI interface * Driver for Prism II devices that have a direct PCI interface
* (i.e., not in a Pcmcia or PLX bridge) * (i.e., not in a Pcmcia or PLX bridge)
...@@ -10,8 +10,10 @@ ...@@ -10,8 +10,10 @@
* Some of this code is "inspired" by linux-wlan-ng-0.1.10, but nothing * 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 : * has been copied from it. linux-wlan-ng-0.1.10 is originally :
* Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved. * Copyright (C) 1999 AbsoluteValue Systems, Inc. All Rights Reserved.
* The rest is : * This file originally written by:
* Copyright (C) 2001 Jean Tourrilhes <jt@hpl.hp.com> * Copyright (C) 2001 Jean Tourrilhes <jt@hpl.hp.com>
* And is now maintained by:
* Copyright (C) 2002 David Gibson, IBM Corporation <herme@gibson.dropbear.id.au>
* *
* The contents of this file are subject to the Mozilla Public License * 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 * Version 1.1 (the "License"); you may not use this file except in
...@@ -84,6 +86,7 @@ ...@@ -84,6 +86,7 @@
*/ */
#include <linux/config.h> #include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/init.h> #include <linux/init.h>
...@@ -93,7 +96,6 @@ ...@@ -93,7 +96,6 @@
#include <linux/string.h> #include <linux/string.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/ioport.h> #include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
...@@ -142,8 +144,6 @@ orinoco_pci_cor_reset(struct orinoco_private *priv) ...@@ -142,8 +144,6 @@ orinoco_pci_cor_reset(struct orinoco_private *priv)
unsigned long timeout; unsigned long timeout;
u16 reg; u16 reg;
TRACE_ENTER(priv->ndev->name);
/* Assert the reset until the card notice */ /* Assert the reset until the card notice */
hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK); hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
printk(KERN_NOTICE "Reset done"); printk(KERN_NOTICE "Reset done");
...@@ -180,8 +180,6 @@ orinoco_pci_cor_reset(struct orinoco_private *priv) ...@@ -180,8 +180,6 @@ orinoco_pci_cor_reset(struct orinoco_private *priv)
} }
printk(KERN_NOTICE "pci_cor : reg = 0x%X - %lX - %lX\n", reg, timeout, jiffies); printk(KERN_NOTICE "pci_cor : reg = 0x%X - %lX - %lX\n", reg, timeout, jiffies);
TRACE_EXIT(priv->ndev->name);
return 0; return 0;
} }
...@@ -197,7 +195,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, ...@@ -197,7 +195,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
unsigned long pci_iolen; unsigned long pci_iolen;
struct orinoco_private *priv = NULL; struct orinoco_private *priv = NULL;
struct net_device *dev = NULL; struct net_device *dev = NULL;
int netdev_registered = 0;
err = pci_enable_device(pdev); err = pci_enable_device(pdev);
if (err) if (err)
...@@ -218,9 +215,9 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, ...@@ -218,9 +215,9 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
} }
priv = dev->priv; priv = dev->priv;
dev->base_addr = (int) pci_ioaddr; dev->base_addr = (unsigned long) pci_ioaddr;
dev->mem_start = (unsigned long) pci_iorange; dev->mem_start = pci_iorange;
dev->mem_end = ((unsigned long) pci_iorange) + pci_iolen - 1; dev->mem_end = pci_iorange + pci_iolen - 1;
SET_MODULE_OWNER(dev); SET_MODULE_OWNER(dev);
...@@ -228,12 +225,15 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, ...@@ -228,12 +225,15 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
"Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n", "Detected Orinoco/Prism2 PCI device at %s, mem:0x%lX to 0x%lX -> 0x%p, irq:%d\n",
pdev->slot_name, dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq); pdev->slot_name, dev->mem_start, dev->mem_end, pci_ioaddr, pdev->irq);
hermes_struct_init(&(priv->hw), dev->base_addr, HERMES_MEM, HERMES_32BIT_REGSPACING); hermes_struct_init(&priv->hw, dev->base_addr,
HERMES_MEM, HERMES_32BIT_REGSPACING);
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, priv); err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ,
dev->name, dev);
if (err) { if (err) {
printk(KERN_ERR "orinoco_pci: Error allocating IRQ %d.\n", pdev->irq); printk(KERN_ERR "orinoco_pci: Error allocating IRQ %d.\n",
pdev->irq);
err = -EBUSY; err = -EBUSY;
goto fail; goto fail;
} }
...@@ -254,24 +254,12 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, ...@@ -254,24 +254,12 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
printk(KERN_ERR "%s: Failed to register net device\n", dev->name); printk(KERN_ERR "%s: Failed to register net device\n", dev->name);
goto fail; goto fail;
} }
netdev_registered = 1;
err = orinoco_proc_dev_init(dev);
if (err) {
printk(KERN_ERR "%s: Failed to create /proc node\n", dev->name);
err = -EIO;
goto fail;
}
return 0; /* succeeded */ return 0; /* succeeded */
fail: fail:
if (dev) { if (dev) {
orinoco_proc_dev_cleanup(dev);
if (netdev_registered)
unregister_netdev(dev);
if (dev->irq) if (dev->irq)
free_irq(dev->irq, priv); free_irq(dev->irq, dev);
kfree(dev); kfree(dev);
} }
...@@ -279,6 +267,8 @@ static int orinoco_pci_init_one(struct pci_dev *pdev, ...@@ -279,6 +267,8 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
if (pci_ioaddr) if (pci_ioaddr)
iounmap(pci_ioaddr); iounmap(pci_ioaddr);
pci_disable_device(pdev);
return err; return err;
} }
...@@ -290,21 +280,85 @@ static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev) ...@@ -290,21 +280,85 @@ static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
if (! dev) if (! dev)
BUG(); BUG();
orinoco_proc_dev_cleanup(dev);
unregister_netdev(dev); unregister_netdev(dev);
if (dev->irq) if (dev->irq)
free_irq(dev->irq, priv); free_irq(dev->irq, dev);
if (priv->hw.iobase) if (priv->hw.iobase)
iounmap((unsigned char *) priv->hw.iobase); iounmap((unsigned char *) priv->hw.iobase);
pci_set_drvdata(pdev, NULL);
kfree(dev); kfree(dev);
pci_disable_device(pdev); pci_disable_device(pdev);
} }
static int orinoco_pci_suspend(struct pci_dev *pdev, u32 state)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = dev->priv;
unsigned long flags;
int err;
printk(KERN_DEBUG "%s: Orinoco-PCI entering sleep mode (state=%d)\n",
dev->name, state);
err = orinoco_lock(priv, &flags);
if (err) {
printk(KERN_ERR "%s: hw_unavailable on orinoco_pci_suspend\n",
dev->name);
return err;
}
err = __orinoco_down(dev);
if (err)
printk(KERN_WARNING "%s: orinoco_pci_suspend(): Error %d downing interface\n",
dev->name, err);
netif_device_detach(dev);
priv->hw_unavailable++;
orinoco_unlock(priv, &flags);
return 0;
}
static int orinoco_pci_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = dev->priv;
unsigned long flags;
int err;
printk(KERN_DEBUG "%s: Orinoco-PCI waking up\n", dev->name);
err = orinoco_reinit_firmware(dev);
if (err) {
printk(KERN_ERR "%s: Error %d re-initializing firmware on orinoco_pci_resume()\n",
dev->name, err);
return err;
}
spin_lock_irqsave(&priv->lock, flags);
netif_device_attach(dev);
priv->hw_unavailable--;
if (priv->open && (! priv->hw_unavailable)) {
err = __orinoco_up(dev);
if (err)
printk(KERN_ERR "%s: Error %d restarting card on orinoco_pci_resume()\n",
dev->name, err);
}
spin_unlock_irqrestore(&priv->lock, flags);
return 0;
}
static struct pci_device_id orinoco_pci_pci_id_table[] __devinitdata = { static struct pci_device_id orinoco_pci_pci_id_table[] __devinitdata = {
{0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,}, {0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
{0,}, {0,},
...@@ -317,12 +371,12 @@ static struct pci_driver orinoco_pci_driver = { ...@@ -317,12 +371,12 @@ static struct pci_driver orinoco_pci_driver = {
.id_table = orinoco_pci_pci_id_table, .id_table = orinoco_pci_pci_id_table,
.probe = orinoco_pci_init_one, .probe = orinoco_pci_init_one,
.remove = __devexit_p(orinoco_pci_remove_one), .remove = __devexit_p(orinoco_pci_remove_one),
.suspend = 0, .suspend = orinoco_pci_suspend,
.resume = 0 .resume = orinoco_pci_resume,
}; };
static char version[] __initdata = "orinoco_pci.c 0.13a (Jean Tourrilhes <jt@hpl.hp.com>)"; static char version[] __initdata = "orinoco_pci.c 0.13e (David Gibson <hermes@gibson.dropbear.id.au> & Jean Tourrilhes <jt@hpl.hp.com>)";
MODULE_AUTHOR("Jean Tourrilhes <jt@hpl.hp.com>"); MODULE_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface"); MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
MODULE_LICENSE("Dual MPL/GPL"); MODULE_LICENSE("Dual MPL/GPL");
......
/* orinoco_plx.c 0.13a /* orinoco_plx.c 0.13e
* *
* Driver for Prism II devices which would usually be driven by orinoco_cs, * Driver for Prism II devices which would usually be driven by orinoco_cs,
* but are connected to the PCI bus by a PLX9052. * but are connected to the PCI bus by a PLX9052.
...@@ -119,7 +119,6 @@ not have time for a while.. ...@@ -119,7 +119,6 @@ not have time for a while..
#include <asm/uaccess.h> #include <asm/uaccess.h>
#include <asm/io.h> #include <asm/io.h>
#include <asm/system.h> #include <asm/system.h>
#include <linux/proc_fs.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/if_arp.h> #include <linux/if_arp.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
...@@ -156,7 +155,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, ...@@ -156,7 +155,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
unsigned long pccard_ioaddr = 0; unsigned long pccard_ioaddr = 0;
unsigned long pccard_iolen = 0; unsigned long pccard_iolen = 0;
struct net_device *dev = NULL; struct net_device *dev = NULL;
int netdev_registered = 0;
int i; int i;
err = pci_enable_device(pdev); err = pci_enable_device(pdev);
...@@ -201,7 +199,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, ...@@ -201,7 +199,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
addr = pci_resource_start(pdev, 1); addr = pci_resource_start(pdev, 1);
reg = 0; reg = 0;
reg = inl(addr+PLX_INTCSR); reg = inl(addr+PLX_INTCSR);
if(reg & PLX_INTCSR_INTEN) if (reg & PLX_INTCSR_INTEN)
printk(KERN_DEBUG "orinoco_plx: " printk(KERN_DEBUG "orinoco_plx: "
"Local Interrupt already enabled\n"); "Local Interrupt already enabled\n");
else { else {
...@@ -244,7 +242,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, ...@@ -244,7 +242,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
HERMES_IO, HERMES_16BIT_REGSPACING); HERMES_IO, HERMES_16BIT_REGSPACING);
pci_set_drvdata(pdev, dev); pci_set_drvdata(pdev, dev);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, priv); err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name, dev);
if (err) { if (err) {
printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq); printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq);
err = -EBUSY; err = -EBUSY;
...@@ -253,11 +251,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, ...@@ -253,11 +251,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
dev->irq = pdev->irq; dev->irq = pdev->irq;
err = register_netdev(dev); err = register_netdev(dev);
if (err)
goto fail;
netdev_registered = 1;
err = orinoco_proc_dev_init(dev);
if (err) if (err)
goto fail; goto fail;
...@@ -266,16 +259,11 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, ...@@ -266,16 +259,11 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
fail: fail:
printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n"); printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n");
if (priv) { if (dev) {
orinoco_proc_dev_cleanup(dev);
if (netdev_registered)
unregister_netdev(dev);
if (dev->irq) if (dev->irq)
free_irq(dev->irq, priv); free_irq(dev->irq, dev);
kfree(priv); kfree(dev);
} }
if (pccard_ioaddr) if (pccard_ioaddr)
...@@ -292,17 +280,16 @@ static int orinoco_plx_init_one(struct pci_dev *pdev, ...@@ -292,17 +280,16 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev) static void __devexit orinoco_plx_remove_one(struct pci_dev *pdev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct net_device *dev = pci_get_drvdata(pdev);
struct orinoco_private *priv = dev->priv;
if (! dev) if (! dev)
BUG(); BUG();
orinoco_proc_dev_cleanup(dev);
unregister_netdev(dev); unregister_netdev(dev);
if (dev->irq) if (dev->irq)
free_irq(dev->irq, priv); free_irq(dev->irq, dev);
pci_set_drvdata(pdev, NULL);
kfree(dev); kfree(dev);
...@@ -341,7 +328,7 @@ static struct pci_driver orinoco_plx_driver = { ...@@ -341,7 +328,7 @@ static struct pci_driver orinoco_plx_driver = {
.resume = 0, .resume = 0,
}; };
static char version[] __initdata = "orinoco_plx.c 0.13a (Daniel Barlow <dan@telent.net>, David Gibson <hermes@gibson.dropbear.id.au>)"; static char version[] __initdata = "orinoco_plx.c 0.13e (Daniel Barlow <dan@telent.net>, David Gibson <hermes@gibson.dropbear.id.au>)";
MODULE_AUTHOR("Daniel Barlow <dan@telent.net>"); MODULE_AUTHOR("Daniel Barlow <dan@telent.net>");
MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge"); MODULE_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
#ifdef MODULE_LICENSE #ifdef MODULE_LICENSE
......
/* orinoco_tmd.c 0.01
*
* Driver for Prism II devices which would usually be driven by orinoco_cs,
* but are connected to the PCI bus by a TMD7160.
*
* Copyright (C) 2003 Joerg Dorchain <joerg@dorchain.net>
* based heavily upon orinoco_plx.c Copyright (C) 2001 Daniel Barlow <dan@telent.net>
*
* 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.
* Caution: this is experimental and probably buggy. For success and
* failure reports for different cards and adaptors, see
* orinoco_tmd_pci_id_table near the end of the file. If you have a
* card we don't have the PCI id for, and looks like it should work,
* drop me mail with the id and "it works"/"it doesn't work".
*
* Note: if everything gets detected fine but it doesn't actually send
* or receive packets, your first port of call should probably be to
* try newer firmware in the card. Especially if you're doing Ad-Hoc
* modes
*
* The actual driving is done by orinoco.c, this is just resource
* allocation stuff.
*
* This driver is modeled after the orinoco_plx driver. The main
* difference is that the TMD chip has only IO port ranges and no
* memory space, i.e. no access to the CIS. Compared to the PLX chip,
* the io range functionalities are exchanged.
*
* Pheecom sells cards with the TMD chip as "ASIC version"
*/
#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/wireless.h>
#include <linux/list.h>
#include <linux/pci.h>
#include <linux/wireless.h>
#include <linux/fcntl.h>
#include <pcmcia/cisreg.h>
#include "hermes.h"
#include "orinoco.h"
static char dev_info[] = "orinoco_tmd";
#define COR_VALUE (COR_LEVEL_REQ | COR_FUNC_ENA | COR_FUNC_ENA) /* Enable PC card with level triggered irqs and irq requests */
static int orinoco_tmd_init_one(struct pci_dev *pdev,
const struct pci_device_id *ent)
{
int err = 0;
u32 reg, addr;
struct orinoco_private *priv = NULL;
unsigned long pccard_ioaddr = 0;
unsigned long pccard_iolen = 0;
struct net_device *dev = NULL;
err = pci_enable_device(pdev);
if (err)
return -EIO;
printk(KERN_DEBUG "TMD setup\n");
pccard_ioaddr = pci_resource_start(pdev, 2);
pccard_iolen = pci_resource_len(pdev, 2);
if (! request_region(pccard_ioaddr, pccard_iolen, dev_info)) {
printk(KERN_ERR "orinoco_tmd: I/O resource at 0x%lx len 0x%lx busy\n",
pccard_ioaddr, pccard_iolen);
pccard_ioaddr = 0;
err = -EBUSY;
goto fail;
}
addr = pci_resource_start(pdev, 1);
outb(COR_VALUE, addr);
mdelay(1);
reg = inb(addr);
if (reg != COR_VALUE) {
printk(KERN_ERR "orinoco_tmd: Error setting TMD COR values %x should be %x\n", reg, COR_VALUE);
err = -EIO;
goto fail;
}
dev = alloc_orinocodev(0, NULL);
if (! dev) {
err = -ENOMEM;
goto fail;
}
priv = dev->priv;
dev->base_addr = pccard_ioaddr;
SET_MODULE_OWNER(dev);
printk(KERN_DEBUG
"Detected Orinoco/Prism2 TMD device at %s irq:%d, io addr:0x%lx\n",
pdev->slot_name, pdev->irq, pccard_ioaddr);
hermes_struct_init(&(priv->hw), dev->base_addr,
HERMES_IO, HERMES_16BIT_REGSPACING);
pci_set_drvdata(pdev, dev);
err = request_irq(pdev->irq, orinoco_interrupt, SA_SHIRQ, dev->name,
dev);
if (err) {
printk(KERN_ERR "orinoco_tmd: Error allocating IRQ %d.\n",
pdev->irq);
err = -EBUSY;
goto fail;
}
dev->irq = pdev->irq;
err = register_netdev(dev);
if (err)
goto fail;
return 0; /* succeeded */
fail:
printk(KERN_DEBUG "orinoco_tmd: init_one(), FAIL!\n");
if (dev) {
if (dev->irq)
free_irq(dev->irq, dev);
kfree(dev);
}
if (pccard_ioaddr)
release_region(pccard_ioaddr, pccard_iolen);
pci_disable_device(pdev);
return err;
}
static void __devexit orinoco_tmd_remove_one(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
if (! dev)
BUG();
unregister_netdev(dev);
if (dev->irq)
free_irq(dev->irq, dev);
pci_set_drvdata(pdev, NULL);
kfree(dev);
release_region(pci_resource_start(pdev, 2), pci_resource_len(pdev, 2));
pci_disable_device(pdev);
}
static struct pci_device_id orinoco_tmd_pci_id_table[] __devinitdata = {
{0x15e8, 0x0131, PCI_ANY_ID, PCI_ANY_ID,}, /* NDC and OEMs, e.g. pheecom */
{0,},
};
MODULE_DEVICE_TABLE(pci, orinoco_tmd_pci_id_table);
static struct pci_driver orinoco_tmd_driver = {
.name = "orinoco_tmd",
.id_table = orinoco_tmd_pci_id_table,
.probe = orinoco_tmd_init_one,
.remove = __devexit_p(orinoco_tmd_remove_one),
.suspend = 0,
.resume = 0,
};
static char version[] __initdata = "orinoco_tmd.c 0.01 (Joerg Dorchain <joerg@dorchain.net>)";
MODULE_AUTHOR("Joerg Dorchain <joerg@dorchain.net>");
MODULE_DESCRIPTION("Driver for wireless LAN cards using the TMD7160 PCI bridge");
#ifdef MODULE_LICENSE
MODULE_LICENSE("Dual MPL/GPL");
#endif
static int __init orinoco_tmd_init(void)
{
printk(KERN_DEBUG "%s\n", version);
return pci_module_init(&orinoco_tmd_driver);
}
extern void __exit orinoco_tmd_exit(void)
{
pci_unregister_driver(&orinoco_tmd_driver);
current->state = TASK_UNINTERRUPTIBLE;
schedule_timeout(HZ);
}
module_init(orinoco_tmd_init);
module_exit(orinoco_tmd_exit);
/*
* Local variables:
* c-indent-level: 8
* c-basic-offset: 8
* tab-width: 8
* End:
*/
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment