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
depends on PCI && HERMES && EXPERIMENTAL
help
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
PCI <-> PCMCIA bridge. Several vendors sell such adaptors so that
802.11b PCMCIA cards can be used in desktop machines. The Netgear
......@@ -212,6 +212,19 @@ config PLX_HERMES
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
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
tristate "Prism 2.5 PCI 802.11b adaptor support (EXPERIMENTAL)"
depends on PCI && HERMES && EXPERIMENTAL
......
......@@ -15,6 +15,7 @@ obj-$(CONFIG_PCMCIA_HERMES) += orinoco_cs.o
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_AIRO) += 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
* card.
......@@ -12,6 +12,7 @@
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
......@@ -20,7 +21,6 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
......@@ -95,7 +95,7 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
netif_device_detach(dev);
priv->hw_unavailable = 1;
priv->hw_unavailable++;
orinoco_unlock(priv, &flags);
......@@ -121,14 +121,15 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
netif_device_attach(dev);
if (priv->open) {
priv->hw_unavailable--;
if (priv->open && (! priv->hw_unavailable)) {
err = __orinoco_up(dev);
if (err)
printk(KERN_ERR "%s: Error %d restarting card on PBOOK_WAKE\n",
dev->name, err);
}
priv->hw_unavailable = 0;
spin_unlock_irqrestore(&priv->lock, flags);
......@@ -138,6 +139,37 @@ airport_sleep_notify(struct pmu_sleep_notifier *self, int when)
}
#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 *
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 */
dev = alloc_orinocodev(sizeof(*card), NULL);
dev = alloc_orinocodev(sizeof(*card), airport_hard_reset);
if (! dev) {
printk(KERN_ERR "airport: can't allocate device datas\n");
return NULL;
......@@ -195,7 +227,7 @@ airport_attach(struct device_node *of_node)
/* Reset it before we get the interrupt */
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);
goto failed;
}
......@@ -209,11 +241,6 @@ airport_attach(struct device_node *of_node)
printk(KERN_DEBUG "airport: card registered for interface %s\n", dev->name);
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
pmu_register_sleep_notifier(&airport_sleep_notifier);
#endif
......@@ -234,9 +261,6 @@ airport_detach(struct net_device *dev)
struct orinoco_private *priv = dev->priv;
struct airport *card = priv->card;
/* Unregister proc entry */
orinoco_proc_dev_cleanup(dev);
#ifdef CONFIG_PMAC_PBOOK
pmu_unregister_sleep_notifier(&airport_sleep_notifier);
#endif
......@@ -245,7 +269,7 @@ airport_detach(struct net_device *dev)
card->ndev_registered = 0;
if (card->irq_requested)
free_irq(dev->irq, priv);
free_irq(dev->irq, dev);
card->irq_requested = 0;
if (card->vaddr)
......@@ -263,7 +287,7 @@ airport_detach(struct net_device *dev)
kfree(dev);
} /* 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_DESCRIPTION("Driver for the Apple Airport wireless card.");
MODULE_LICENSE("Dual MPL/GPL");
......
......@@ -52,7 +52,6 @@
#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_AUTHOR("David Gibson <hermes@gibson.dropbear.id.au>");
#ifdef MODULE_LICENSE
......@@ -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
*
* 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 k;
......@@ -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
*/
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)
{
int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
......@@ -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
*/
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)
{
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,
* practice.
*
* 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)
{
int err = 0;
int dreg = bap ? HERMES_DATA1 : HERMES_DATA0;
u16 rlength, rtype;
int nwords;
unsigned nwords;
if ( (bufsize < 0) || (bufsize % 2) )
return -EINVAL;
err = hermes_docmd_wait(hw, HERMES_CMD_ACCESS, rid, NULL);
if (err)
goto out;
return err;
err = hermes_bap_seek(hw, bap, rid, 0);
if (err)
goto out;
return err;
rlength = hermes_read_reg(hw, dreg);
if (! rlength)
return -ENOENT;
rtype = hermes_read_reg(hw, dreg);
if (length)
......@@ -492,11 +496,10 @@ int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, int bufsize,
IO_TYPE(hw), hw->iobase,
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);
out:
return err;
return 0;
}
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 err = 0;
int count;
unsigned count;
if (length == 0)
return -EINVAL;
err = hermes_bap_seek(hw, bap, rid, 0);
if (err)
goto out;
return err;
hermes_write_reg(hw, dreg, length);
hermes_write_reg(hw, dreg, 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,
rid, NULL);
out:
return err;
}
......@@ -536,9 +541,12 @@ EXPORT_SYMBOL(hermes_write_ltv);
static int __init init_hermes(void)
{
printk(KERN_DEBUG "%s\n", version);
return 0;
}
static void __exit exit_hermes(void)
{
}
module_init(init_hermes);
module_exit(exit_hermes);
......@@ -250,7 +250,6 @@ struct hermes_scan_frame {
u16 scanreason; /* ??? */
struct hermes_scan_apinfo aps[35]; /* Scan result */
} __attribute__ ((packed));
#define HERMES_LINKSTATUS_NOT_CONNECTED (0x0000)
#define HERMES_LINKSTATUS_CONNECTED (0x0001)
#define HERMES_LINKSTATUS_DISCONNECTED (0x0002)
......@@ -278,7 +277,7 @@ struct hermes_debug_entry {
/* Basic control structure */
typedef struct hermes {
ulong iobase;
unsigned long iobase;
int io_space; /* 1 if we IO-mapped IO, 0 for memory-mapped IO? */
#define HERMES_IO 1
#define HERMES_MEM 0
......@@ -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_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);
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);
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);
int hermes_write_ltv(hermes_t *hw, int bap, u16 rid,
u16 length, const void *value);
......@@ -361,42 +360,61 @@ static inline int hermes_inquire(hermes_t *hw, u16 rid)
#define HERMES_RECLEN_TO_BYTES(n) ( ((n)-1) * 2 )
/* 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;;
if (hw->io_space) {
insw(hw->iobase + off, buf, count);
} else {
int i;
unsigned i;
u16 *p;
/* This need to *not* byteswap (like insw()) but
* readw() does byteswap hence the conversion */
/* This needs to *not* byteswap (like insw()) but
* 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++) {
*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;;
if (hw->io_space) {
outsw(hw->iobase + off, buf, count);
} else {
int i;
unsigned i;
const u16 *p;
/* This need to *not* byteswap (like outsw()) but
* writew() does byteswap hence the conversion */
/* This needs to *not* byteswap (like outsw()) but
* 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++) {
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) \
(hermes_read_ltv((hw),(bap),(rid), sizeof(*buf), NULL, (buf)))
#define HERMES_WRITE_RECORD(hw, bap, rid, buf) \
......
......@@ -2,9 +2,15 @@
#define _IEEE802_11_H
#define IEEE802_11_DATA_LEN 2304
/* Actually, the standard seems to be inconsistent about what the
maximum frame size really is. Section 6.2.1.1.2 says 2304 octets,
but the figure in Section 7.1.2 says 2312 octects. */
/* Maximum size for the MA-UNITDATA primitive, 802.11 standard section
6.2.1.1.2.
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_FRAME_LEN (IEEE802_11_DATA_LEN + IEEE802_11_HLEN)
......
This diff is collapsed.
......@@ -11,9 +11,29 @@
#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/wireless.h>
#include <linux/workqueue.h>
#include <linux/version.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 */
//#define ORINOCO_DEBUG 3
......@@ -42,9 +62,12 @@ struct orinoco_private {
/* Synchronisation stuff */
spinlock_t lock;
int hw_unavailable;
struct work_struct timeout_task;
struct work_struct reset_work;
/* driver state */
int open;
u16 last_linkstatus;
int connected;
/* Net device stuff */
struct net_device *ndev;
......@@ -55,6 +78,7 @@ struct orinoco_private {
hermes_t hw;
u16 txfid;
/* Capabilities of the hardware/firmware */
int firmware_type;
#define FIRMWARE_TYPE_AGERE 1
......@@ -68,6 +92,7 @@ struct orinoco_private {
int has_sensitivity;
int nicbuf_size;
u16 channel_mask;
int broken_disableport;
/* Configuration paramaters */
u32 iw_mode;
......@@ -91,9 +116,6 @@ struct orinoco_private {
/* Configuration dependent variables */
int port_type, createibss;
int promiscuous, mc_count;
/* /proc based debugging stuff */
struct proc_dir_entry *dir_dev;
};
#ifdef ORINOCO_DEBUG
......@@ -110,10 +132,8 @@ extern struct net_device *alloc_orinocodev(int sizeof_card,
int (*hard_reset)(struct orinoco_private *));
extern int __orinoco_up(struct net_device *dev);
extern int __orinoco_down(struct net_device *dev);
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 int orinoco_stop(struct net_device *dev);
extern int orinoco_reinit_firmware(struct net_device *dev);
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
* as the Lucent WavelanIEEE/Orinoco cards and their OEM (Cabletron/
......@@ -14,6 +14,7 @@
#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>
......@@ -21,9 +22,7 @@
#include <linux/ptrace.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
......@@ -90,8 +89,9 @@ struct orinoco_pccard {
dev_node_t node;
/* Used to handle hard reset */
wait_queue_head_t hard_reset_queue;
int hard_reset_flag;
/* yuck, we need this hack to work around the insanity of the
* PCMCIA layer */
unsigned long hard_reset_in_progress;
};
/*
......@@ -128,14 +128,14 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
dev_link_t *link = &card->link;
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);
if (err)
return err;
wait_event_interruptible(card->hard_reset_queue,
card->hard_reset_flag);
clear_bit(0, &card->hard_reset_in_progress);
return 0;
}
......@@ -144,6 +144,16 @@ orinoco_cs_hard_reset(struct orinoco_private *priv)
/* 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) */
static void
flush_stale_links(void)
......@@ -187,7 +197,6 @@ orinoco_cs_attach(void)
return NULL;
priv = dev->priv;
card = priv->card;
init_waitqueue_head(&card->hard_reset_queue);
/* Link both structures together */
link = &card->link;
......@@ -233,7 +242,7 @@ orinoco_cs_attach(void)
ret = CardServices(RegisterClient, &link->handle, &client_reg);
if (ret != CS_SUCCESS) {
cs_error(link->handle, RegisterClient, ret);
orinoco_cs_error(link->handle, RegisterClient, ret);
orinoco_cs_detach(link);
return NULL;
}
......@@ -262,19 +271,12 @@ orinoco_cs_detach(dev_link_t * link)
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) {
#ifdef PCMCIA_DEBUG
printk(KERN_DEBUG "orinoco_cs: detach postponed, '%s' "
"still locked\n", link->dev->dev_name);
#endif
link->state |= DEV_STALE_LINK;
return;
orinoco_cs_release((u_long)link);
if (link->state & DEV_CONFIG) {
link->state |= DEV_STALE_LINK;
return;
}
}
/* Break the link with Card Services */
......@@ -465,7 +467,7 @@ orinoco_cs_config(dev_link_t *link)
link->irq.IRQInfo2 |= 1 << irq_list[i];
link->irq.Handler = orinoco_interrupt;
link->irq.Instance = priv;
link->irq.Instance = dev;
CS_CHECK(RequestIRQ, link->handle, &link->irq);
}
......@@ -522,18 +524,10 @@ orinoco_cs_config(dev_link_t *link)
link->io.BasePort2 + link->io.NumPorts2 - 1);
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;
cs_failed:
cs_error(link->handle, last_fn, last_ret);
orinoco_cs_error(link->handle, last_fn, last_ret);
failed:
orinoco_cs_release((u_long) link);
......@@ -550,21 +544,13 @@ orinoco_cs_release(u_long arg)
dev_link_t *link = (dev_link_t *) arg;
struct net_device *dev = link->priv;
struct orinoco_private *priv = dev->priv;
unsigned long flags;
/*
If the device is currently in use, we won't release until it
is actually closed, because until then, we can't be sure that
no one will try to access the device or its data structures.
*/
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);
/* We're committed to taking the device away now, so mark the
* hardware as unavailable */
spin_lock_irqsave(&priv->lock, flags);
priv->hw_unavailable++;
spin_unlock_irqrestore(&priv->lock, flags);
/* Don't bother checking to see if these succeed or not */
CardServices(ReleaseConfiguration, link->handle);
......@@ -586,6 +572,7 @@ orinoco_cs_event(event_t event, int priority,
dev_link_t *link = args->client_data;
struct net_device *dev = link->priv;
struct orinoco_private *priv = dev->priv;
struct orinoco_pccard *card = priv->card;
int err = 0;
unsigned long flags;
......@@ -596,14 +583,9 @@ orinoco_cs_event(event_t event, int priority,
orinoco_lock(priv, &flags);
netif_device_detach(dev);
priv->hw_unavailable = 1;
priv->hw_unavailable++;
orinoco_unlock(priv, &flags);
/* if (link->open) */
/* orinoco_cs_stop(dev); */
mod_timer(&link->release, jiffies + HZ / 20);
}
break;
......@@ -618,24 +600,24 @@ orinoco_cs_event(event_t event, int priority,
case CS_EVENT_RESET_PHYSICAL:
/* Mark the device as stopped, to block IO until later */
if (link->state & DEV_CONFIG) {
err = orinoco_lock(priv, &flags);
if (err) {
printk(KERN_ERR "%s: hw_unavailable on SUSPEND/RESET_PHYSICAL\n",
dev->name);
break;
}
err = __orinoco_down(dev);
if (err)
printk(KERN_WARNING "%s: %s: Error %d downing interface\n",
dev->name,
event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL",
err);
netif_device_detach(dev);
priv->hw_unavailable = 1;
/* This is probably racy, but I can't think of
a better way, short of rewriting the PCMCIA
layer to not suck :-( */
if (! test_bit(0, &card->hard_reset_in_progress)) {
spin_lock_irqsave(&priv->lock, flags);
orinoco_unlock(priv, &flags);
err = __orinoco_down(dev);
if (err)
printk(KERN_WARNING "%s: %s: Error %d downing interface\n",
dev->name,
event == CS_EVENT_PM_SUSPEND ? "SUSPEND" : "RESET_PHYSICAL",
err);
netif_device_detach(dev);
priv->hw_unavailable++;
spin_unlock_irqrestore(&priv->lock, flags);
}
CardServices(ReleaseConfiguration, link->handle);
}
......@@ -646,32 +628,34 @@ orinoco_cs_event(event_t event, int priority,
/* Fall through... */
case CS_EVENT_CARD_RESET:
if (link->state & DEV_CONFIG) {
CardServices(RequestConfiguration, link->handle,
&link->conf);
/* FIXME: should we double check that this is
* the same card as we had before */
err = orinoco_reinit_firmware(dev);
if (err) {
printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
dev->name, err);
break;
}
spin_lock_irqsave(&priv->lock, flags);
netif_device_attach(dev);
priv->hw_unavailable = 0;
CardServices(RequestConfiguration, link->handle,
&link->conf);
if (priv->open) {
err = __orinoco_up(dev);
if (err)
printk(KERN_ERR "%s: Error %d restarting card\n",
if (! test_bit(0, &card->hard_reset_in_progress)) {
err = orinoco_reinit_firmware(dev);
if (err) {
printk(KERN_ERR "%s: Error %d re-initializing firmware\n",
dev->name, err);
break;
}
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\n",
dev->name, err);
}
spin_unlock_irqrestore(&priv->lock, flags);
}
orinoco_unlock(priv, &flags);
}
break;
}
......@@ -685,7 +669,7 @@ orinoco_cs_event(event_t event, int priority,
/* Can't be declared "const" or the whole __initdata section will
* 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 = {
.owner = THIS_MODULE,
......@@ -712,7 +696,6 @@ exit_orinoco_cs(void)
if (dev_list)
DEBUG(0, "orinoco_cs: Removing leftover devices.\n");
while (dev_list != NULL) {
del_timer(&dev_list->release);
if (dev_list->state & DEV_CONFIG)
orinoco_cs_release((u_long) 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
* (i.e., not in a Pcmcia or PLX bridge)
......@@ -10,8 +10,10 @@
* 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 rest is :
* This file originally written by:
* 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
* Version 1.1 (the "License"); you may not use this file except in
......@@ -84,6 +86,7 @@
*/
#include <linux/config.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
......@@ -93,7 +96,6 @@
#include <linux/string.h>
#include <linux/timer.h>
#include <linux/ioport.h>
#include <linux/proc_fs.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
......@@ -142,8 +144,6 @@ orinoco_pci_cor_reset(struct orinoco_private *priv)
unsigned long timeout;
u16 reg;
TRACE_ENTER(priv->ndev->name);
/* Assert the reset until the card notice */
hermes_write_regn(hw, PCI_COR, HERMES_PCI_COR_MASK);
printk(KERN_NOTICE "Reset done");
......@@ -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);
TRACE_EXIT(priv->ndev->name);
return 0;
}
......@@ -197,7 +195,6 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
unsigned long pci_iolen;
struct orinoco_private *priv = NULL;
struct net_device *dev = NULL;
int netdev_registered = 0;
err = pci_enable_device(pdev);
if (err)
......@@ -218,9 +215,9 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
}
priv = dev->priv;
dev->base_addr = (int) pci_ioaddr;
dev->mem_start = (unsigned long) pci_iorange;
dev->mem_end = ((unsigned long) pci_iorange) + pci_iolen - 1;
dev->base_addr = (unsigned long) pci_ioaddr;
dev->mem_start = pci_iorange;
dev->mem_end = pci_iorange + pci_iolen - 1;
SET_MODULE_OWNER(dev);
......@@ -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",
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);
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) {
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;
goto fail;
}
......@@ -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);
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 */
fail:
if (dev) {
orinoco_proc_dev_cleanup(dev);
if (netdev_registered)
unregister_netdev(dev);
if (dev->irq)
free_irq(dev->irq, priv);
free_irq(dev->irq, dev);
kfree(dev);
}
......@@ -279,6 +267,8 @@ static int orinoco_pci_init_one(struct pci_dev *pdev,
if (pci_ioaddr)
iounmap(pci_ioaddr);
pci_disable_device(pdev);
return err;
}
......@@ -290,21 +280,85 @@ static void __devexit orinoco_pci_remove_one(struct pci_dev *pdev)
if (! dev)
BUG();
orinoco_proc_dev_cleanup(dev);
unregister_netdev(dev);
if (dev->irq)
free_irq(dev->irq, priv);
free_irq(dev->irq, dev);
if (priv->hw.iobase)
iounmap((unsigned char *) priv->hw.iobase);
pci_set_drvdata(pdev, NULL);
kfree(dev);
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 = {
{0x1260, 0x3873, PCI_ANY_ID, PCI_ANY_ID,},
{0,},
......@@ -317,12 +371,12 @@ static struct pci_driver orinoco_pci_driver = {
.id_table = orinoco_pci_pci_id_table,
.probe = orinoco_pci_init_one,
.remove = __devexit_p(orinoco_pci_remove_one),
.suspend = 0,
.resume = 0
.suspend = orinoco_pci_suspend,
.resume = orinoco_pci_resume,
};
static char version[] __initdata = "orinoco_pci.c 0.13a (Jean Tourrilhes <jt@hpl.hp.com>)";
MODULE_AUTHOR("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("David Gibson <hermes@gibson.dropbear.id.au>");
MODULE_DESCRIPTION("Driver for wireless LAN cards using direct PCI interface");
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,
* but are connected to the PCI bus by a PLX9052.
......@@ -119,7 +119,6 @@ not have time for a while..
#include <asm/uaccess.h>
#include <asm/io.h>
#include <asm/system.h>
#include <linux/proc_fs.h>
#include <linux/netdevice.h>
#include <linux/if_arp.h>
#include <linux/etherdevice.h>
......@@ -156,7 +155,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
unsigned long pccard_ioaddr = 0;
unsigned long pccard_iolen = 0;
struct net_device *dev = NULL;
int netdev_registered = 0;
int i;
err = pci_enable_device(pdev);
......@@ -201,7 +199,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
addr = pci_resource_start(pdev, 1);
reg = 0;
reg = inl(addr+PLX_INTCSR);
if(reg & PLX_INTCSR_INTEN)
if (reg & PLX_INTCSR_INTEN)
printk(KERN_DEBUG "orinoco_plx: "
"Local Interrupt already enabled\n");
else {
......@@ -244,7 +242,7 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
HERMES_IO, HERMES_16BIT_REGSPACING);
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) {
printk(KERN_ERR "orinoco_plx: Error allocating IRQ %d.\n", pdev->irq);
err = -EBUSY;
......@@ -253,11 +251,6 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
dev->irq = pdev->irq;
err = register_netdev(dev);
if (err)
goto fail;
netdev_registered = 1;
err = orinoco_proc_dev_init(dev);
if (err)
goto fail;
......@@ -266,16 +259,11 @@ static int orinoco_plx_init_one(struct pci_dev *pdev,
fail:
printk(KERN_DEBUG "orinoco_plx: init_one(), FAIL!\n");
if (priv) {
orinoco_proc_dev_cleanup(dev);
if (netdev_registered)
unregister_netdev(dev);
if (dev) {
if (dev->irq)
free_irq(dev->irq, priv);
free_irq(dev->irq, dev);
kfree(priv);
kfree(dev);
}
if (pccard_ioaddr)
......@@ -292,18 +280,17 @@ static int orinoco_plx_init_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 orinoco_private *priv = dev->priv;
if (! dev)
BUG();
orinoco_proc_dev_cleanup(dev);
unregister_netdev(dev);
if (dev->irq)
free_irq(dev->irq, priv);
free_irq(dev->irq, dev);
pci_set_drvdata(pdev, NULL);
kfree(dev);
release_region(pci_resource_start(pdev, 3), pci_resource_len(pdev, 3));
......@@ -341,7 +328,7 @@ static struct pci_driver orinoco_plx_driver = {
.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_DESCRIPTION("Driver for wireless LAN cards using the PLX9052 PCI bridge");
#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