Commit ebd627f5 authored by Linus Torvalds's avatar Linus Torvalds

Merge http://gkernel.bkbits.net/net-drivers-2.5

into penguin.transmeta.com:/home/penguin/torvalds/repositories/kernel/linux
parents ac87508c 4fd9fa2e
...@@ -3,6 +3,10 @@ CONFIG_BAGETLANCE ...@@ -3,6 +3,10 @@ CONFIG_BAGETLANCE
MIPS-32-based Baget embedded system. This chipset is better known MIPS-32-based Baget embedded system. This chipset is better known
via the NE2100 cards. via the NE2100 cards.
CONFIG_LASI_82596
Say Y here to support the on-board Intel 82596 ethernet controller
built into Hewlett-Packard PA-RISC machines.
CONFIG_MIPS_JAZZ_SONIC CONFIG_MIPS_JAZZ_SONIC
This is the driver for the onboard card of MIPS Magnum 4000, This is the driver for the onboard card of MIPS Magnum 4000,
Acer PICA, Olivetti M700-10 and a few other identical OEM systems. Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
...@@ -214,6 +218,12 @@ CONFIG_PPPOE ...@@ -214,6 +218,12 @@ CONFIG_PPPOE
pppd, along with binaries of a patched pppd package can be found at: pppd, along with binaries of a patched pppd package can be found at:
<http://www.shoshin.uwaterloo.ca/~mostrows/>. <http://www.shoshin.uwaterloo.ca/~mostrows/>.
CONFIG_PPPOATM
Support PPP (Point to Point Protocol) encapsulated in ATM frames.
This implementation does not yet comply with section 8 of RFC2364,
which can lead to bad results if the ATM peer loses state and
changes its encapsulation unilaterally.
CONFIG_NET_RADIO CONFIG_NET_RADIO
Support for wireless LANs and everything having to do with radio, Support for wireless LANs and everything having to do with radio,
but not with amateur radio or FM broadcasting. but not with amateur radio or FM broadcasting.
...@@ -853,6 +863,10 @@ CONFIG_LANCE ...@@ -853,6 +863,10 @@ CONFIG_LANCE
say M here and read <file:Documentation/modules.txt>. This is say M here and read <file:Documentation/modules.txt>. This is
recommended. The module will be called lance.o. recommended. The module will be called lance.o.
CONFIG_MIPS_AU1000_ENET
If you have an Alchemy Semi AU1000 ethernet controller
on an SGI MIPS system, say Y. Otherwise, say N.
CONFIG_SGI_IOC3_ETH CONFIG_SGI_IOC3_ETH
If you have a network (Ethernet) card of this type, say Y and read If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from the Ethernet-HOWTO, available from
...@@ -1326,6 +1340,24 @@ CONFIG_DE4X5 ...@@ -1326,6 +1340,24 @@ CONFIG_DE4X5
module, say M here and read <file:Documentation/modules.txt> as well module, say M here and read <file:Documentation/modules.txt> as well
as <file:Documentation/networking/net-modules.txt>. as <file:Documentation/networking/net-modules.txt>.
CONFIG_DE2104X
This driver is developed for the SMC EtherPower series Ethernet
cards and also works with cards based on the DECchip
21040 (Tulip series) chips. Some LinkSys PCI cards are
of this type. (If your card is NOT SMC EtherPower 10/100 PCI
(smc9332dst), you can also try the driver for "Generic DECchip"
cards, above. However, most people with a network card of this type
will say Y here.) Do read the Ethernet-HOWTO, available from
<http://www.linuxdoc.org/docs.html#howto>. More specific
information is contained in
<file:Documentation/DocBook/tulip-user.tmpl>.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called tulip.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt> as well
as <file:Documentation/networking/net-modules.txt>.
CONFIG_TULIP CONFIG_TULIP
This driver is developed for the SMC EtherPower series Ethernet This driver is developed for the SMC EtherPower series Ethernet
cards and also works with cards based on the DECchip cards and also works with cards based on the DECchip
...@@ -1344,6 +1376,20 @@ CONFIG_TULIP ...@@ -1344,6 +1376,20 @@ CONFIG_TULIP
module, say M here and read <file:Documentation/modules.txt> as well module, say M here and read <file:Documentation/modules.txt> as well
as <file:Documentation/networking/net-modules.txt>. as <file:Documentation/networking/net-modules.txt>.
CONFIG_TULIP_MWI
This configures your Tulip card specifically for the card and
system cache line size type you are using.
This is experimental code, not yet tested on many boards.
If unsure, say N.
CONFIG_TULIP_MMIO
Use PCI shared memory for the NIC registers, rather than going through
the Tulip's PIO (programmed I/O ports). Faster, but could produce
obscure bugs if your mainboard has memory controller timing issues.
If in doubt, say N.
CONFIG_DGRS CONFIG_DGRS
This is support for the Digi International RightSwitch series of This is support for the Digi International RightSwitch series of
PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6 PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6
...@@ -1374,6 +1420,11 @@ CONFIG_FEALNX ...@@ -1374,6 +1420,11 @@ CONFIG_FEALNX
cards. Specifications and data at cards. Specifications and data at
<http://www.myson.com.hk/mtd/datasheet/>. <http://www.myson.com.hk/mtd/datasheet/>.
CONFIG_LP486E
Say Y here to support the 82596-based on-board Ethernet controller
for the Panther motherboard, which is one of the two shipped in the
Intel Professional Workstation.
CONFIG_ETH16I CONFIG_ETH16I
If you have a network (Ethernet) card of this type, say Y and read If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from the Ethernet-HOWTO, available from
...@@ -1413,6 +1464,16 @@ CONFIG_VIA_RHINE ...@@ -1413,6 +1464,16 @@ CONFIG_VIA_RHINE
a module, say M here and read <file:Documentation/modules.txt> as a module, say M here and read <file:Documentation/modules.txt> as
well as <file:Documentation/networking/net-modules.txt>. well as <file:Documentation/networking/net-modules.txt>.
CONFIG_VIA_RHINE_MMIO
This instructs the driver to use PCI shared memory (MMIO) instead of
programmed I/O ports (PIO). Enabling this gives an improvement in
processing time in parts of the driver.
It is not known if this works reliably on all "rhine" based cards,
but it has been tested successfully on some DFE-530TX adapters.
If unsure, say N.
CONFIG_DM9102 CONFIG_DM9102
This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from
Davicom (<http://www.davicom.com.tw/>). If you have such a network Davicom (<http://www.davicom.com.tw/>). If you have such a network
......
...@@ -1925,6 +1925,8 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr) ...@@ -1925,6 +1925,8 @@ static int netdev_ethtool_ioctl(struct net_device *dev, void *useraddr)
/* get link status */ /* get link status */
case ETHTOOL_GLINK: { case ETHTOOL_GLINK: {
struct ethtool_value edata = {ETHTOOL_GLINK}; struct ethtool_value edata = {ETHTOOL_GLINK};
/* LSTATUS is latched low until a read - so read twice */
mdio_read(dev, 1, MII_BMSR);
edata.data = (mdio_read(dev, 1, MII_BMSR)&BMSR_LSTATUS) ? 1:0; edata.data = (mdio_read(dev, 1, MII_BMSR)&BMSR_LSTATUS) ? 1:0;
if (copy_to_user(useraddr, &edata, sizeof(edata))) if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT; return -EFAULT;
......
...@@ -133,7 +133,7 @@ CONFIG_PCMCIA_XIRCOM ...@@ -133,7 +133,7 @@ CONFIG_PCMCIA_XIRCOM
This driver is also available as a module ( = code which can be This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want). inserted in and removed from the running kernel whenever you want).
The module will be called xircom_tulip_cb.o. If you want to compile The module will be called xircom_cb.o. If you want to compile
it as a module, say M here and read it as a module, say M here and read
<file:Documentation/modules.txt>. If unsure, say N. <file:Documentation/modules.txt>. If unsure, say N.
......
...@@ -433,8 +433,6 @@ static int olympic_open(struct net_device *dev) ...@@ -433,8 +433,6 @@ static int olympic_open(struct net_device *dev)
do { do {
int i; int i;
save_flags(flags);
cli();
for(i=0;i<SRB_COMMAND_SIZE;i+=4) for(i=0;i<SRB_COMMAND_SIZE;i+=4)
writel(0,init_srb+i); writel(0,init_srb+i);
if(SRB_COMMAND_SIZE & 2) if(SRB_COMMAND_SIZE & 2)
...@@ -466,9 +464,11 @@ static int olympic_open(struct net_device *dev) ...@@ -466,9 +464,11 @@ static int olympic_open(struct net_device *dev)
} }
writeb(1,init_srb+30); writeb(1,init_srb+30);
spin_lock_irqsave(&olympic_priv->olympic_lock,flags);
olympic_priv->srb_queued=1; olympic_priv->srb_queued=1;
writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
t = jiffies ; t = jiffies ;
...@@ -496,7 +496,6 @@ static int olympic_open(struct net_device *dev) ...@@ -496,7 +496,6 @@ static int olympic_open(struct net_device *dev)
remove_wait_queue(&olympic_priv->srb_wait,&wait) ; remove_wait_queue(&olympic_priv->srb_wait,&wait) ;
set_current_state(TASK_RUNNING) ; set_current_state(TASK_RUNNING) ;
restore_flags(flags);
#if OLYMPIC_DEBUG #if OLYMPIC_DEBUG
printk("init_srb(%p): ",init_srb); printk("init_srb(%p): ",init_srb);
for(i=0;i<20;i++) for(i=0;i<20;i++)
...@@ -1058,12 +1057,11 @@ static int olympic_close(struct net_device *dev) ...@@ -1058,12 +1057,11 @@ static int olympic_close(struct net_device *dev)
writeb(0,srb+1); writeb(0,srb+1);
writeb(OLYMPIC_CLEAR_RET_CODE,srb+2); writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
save_flags(flags); spin_lock_irqsave(&olympic_priv->olympic_lock,flags);
cli();
olympic_priv->srb_queued=1; olympic_priv->srb_queued=1;
writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM); writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
t = jiffies ; t = jiffies ;
...@@ -1088,7 +1086,6 @@ static int olympic_close(struct net_device *dev) ...@@ -1088,7 +1086,6 @@ static int olympic_close(struct net_device *dev)
remove_wait_queue(&olympic_priv->srb_wait,&wait) ; remove_wait_queue(&olympic_priv->srb_wait,&wait) ;
set_current_state(TASK_RUNNING) ; set_current_state(TASK_RUNNING) ;
restore_flags(flags) ;
olympic_priv->rx_status_last_received++; olympic_priv->rx_status_last_received++;
olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1; olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
......
...@@ -63,6 +63,9 @@ ...@@ -63,6 +63,9 @@
#ifdef CONFIG_NET_RADIO #ifdef CONFIG_NET_RADIO
#include <linux/wireless.h> #include <linux/wireless.h>
#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
#endif /* WIRELESS_EXT > 12 */
#endif #endif
#include <pcmcia/version.h> #include <pcmcia/version.h>
...@@ -269,6 +272,16 @@ static dev_link_t *dev_list; ...@@ -269,6 +272,16 @@ static dev_link_t *dev_list;
because they generally can't be allocated dynamically. because they generally can't be allocated dynamically.
*/ */
#if WIRELESS_EXT <= 12
/* Wireless extensions backward compatibility */
/* Part of iw_handler prototype we need */
struct iw_request_info
{
__u16 cmd; /* Wireless Extension command */
__u16 flags; /* More to come ;-) */
};
/* Wireless Extension Backward compatibility - Jean II /* Wireless Extension Backward compatibility - Jean II
* If the new wireless device private ioctl range is not defined, * If the new wireless device private ioctl range is not defined,
* default to standard device private ioctl range */ * default to standard device private ioctl range */
...@@ -276,8 +289,11 @@ static dev_link_t *dev_list; ...@@ -276,8 +289,11 @@ static dev_link_t *dev_list;
#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE #define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
#endif /* SIOCIWFIRSTPRIV */ #endif /* SIOCIWFIRSTPRIV */
#define SIOCGIPSNAP SIOCIWFIRSTPRIV /* Site Survey Snapshot */ #else /* WIRELESS_EXT <= 12 */
/*#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1*/ static const struct iw_handler_def netwave_handler_def;
#endif /* WIRELESS_EXT <= 12 */
#define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */
#define MAX_ESA 10 #define MAX_ESA 10
...@@ -483,7 +499,10 @@ static dev_link_t *netwave_attach(void) ...@@ -483,7 +499,10 @@ static dev_link_t *netwave_attach(void)
/* wireless extensions */ /* wireless extensions */
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
dev->get_wireless_stats = &netwave_get_wireless_stats; dev->get_wireless_stats = &netwave_get_wireless_stats;
#endif #if WIRELESS_EXT > 12
dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def;
#endif /* WIRELESS_EXT > 12 */
#endif /* WIRELESS_EXT */
dev->do_ioctl = &netwave_ioctl; dev->do_ioctl = &netwave_ioctl;
dev->tx_timeout = &netwave_watchdog; dev->tx_timeout = &netwave_watchdog;
...@@ -595,6 +614,303 @@ static void netwave_flush_stale_links(void) ...@@ -595,6 +614,303 @@ static void netwave_flush_stale_links(void)
} }
} /* netwave_flush_stale_links */ } /* netwave_flush_stale_links */
/*
* Wireless Handler : get protocol name
*/
static int netwave_get_name(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
strcpy(wrqu->name, "Netwave");
return 0;
}
/*
* Wireless Handler : set Network ID
*/
static int netwave_set_nwid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long flags;
ioaddr_t iobase = dev->base_addr;
netwave_private *priv = (netwave_private *) dev->priv;
u_char *ramBase = priv->ramBase;
/* Disable interrupts & save flags */
save_flags(flags);
cli();
#if WIRELESS_EXT > 8
if(!wrqu->nwid.disabled) {
domain = wrqu->nwid.value;
#else /* WIRELESS_EXT > 8 */
if(wrqu->nwid.on) {
domain = wrqu->nwid.nwid;
#endif /* WIRELESS_EXT > 8 */
printk( KERN_DEBUG "Setting domain to 0x%x%02x\n",
(domain >> 8) & 0x01, domain & 0xff);
wait_WOC(iobase);
writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2);
writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
}
/* ReEnable interrupts & restore flags */
restore_flags(flags);
return 0;
}
/*
* Wireless Handler : get Network ID
*/
static int netwave_get_nwid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
#if WIRELESS_EXT > 8
wrqu->nwid.value = domain;
wrqu->nwid.disabled = 0;
wrqu->nwid.fixed = 1;
#else /* WIRELESS_EXT > 8 */
wrqu->nwid.nwid = domain;
wrqu->nwid.on = 1;
#endif /* WIRELESS_EXT > 8 */
return 0;
}
/*
* Wireless Handler : set scramble key
*/
static int netwave_set_scramble(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *key)
{
unsigned long flags;
ioaddr_t iobase = dev->base_addr;
netwave_private *priv = (netwave_private *) dev->priv;
u_char *ramBase = priv->ramBase;
/* Disable interrupts & save flags */
save_flags(flags);
cli();
scramble_key = (key[0] << 8) | key[1];
wait_WOC(iobase);
writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
/* ReEnable interrupts & restore flags */
restore_flags(flags);
return 0;
}
/*
* Wireless Handler : get scramble key
*/
static int netwave_get_scramble(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *key)
{
key[1] = scramble_key & 0xff;
key[0] = (scramble_key>>8) & 0xff;
#if WIRELESS_EXT > 8
wrqu->encoding.flags = IW_ENCODE_ENABLED;
wrqu->encoding.length = 2;
#else /* WIRELESS_EXT > 8 */
wrqu->encoding.method = 1;
#endif /* WIRELESS_EXT > 8 */
return 0;
}
#if WIRELESS_EXT > 8
/*
* Wireless Handler : get mode
*/
static int netwave_get_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
if(domain & 0x100)
wrqu->mode = IW_MODE_INFRA;
else
wrqu->mode = IW_MODE_ADHOC;
return 0;
}
#endif /* WIRELESS_EXT > 8 */
/*
* Wireless Handler : get range info
*/
static int netwave_get_range(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
struct iw_range *range = (struct iw_range *) extra;
int ret = 0;
/* Set the length (very important for backward compatibility) */
wrqu->data.length = sizeof(struct iw_range);
/* Set all the info we don't care or don't know about to zero */
memset(range, 0, sizeof(struct iw_range));
#if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 9; /* Nothing for us in v10 and v11 */
#endif /* WIRELESS_EXT > 10 */
/* Set information in the range struct */
range->throughput = 450 * 1000; /* don't argue on this ! */
range->min_nwid = 0x0000;
range->max_nwid = 0x01FF;
range->num_channels = range->num_frequency = 0;
range->sensitivity = 0x3F;
range->max_qual.qual = 255;
range->max_qual.level = 255;
range->max_qual.noise = 0;
#if WIRELESS_EXT > 7
range->num_bitrates = 1;
range->bitrate[0] = 1000000; /* 1 Mb/s */
#endif /* WIRELESS_EXT > 7 */
#if WIRELESS_EXT > 8
range->encoding_size[0] = 2; /* 16 bits scrambling */
range->num_encoding_sizes = 1;
range->max_encoding_tokens = 1; /* Only one key possible */
#endif /* WIRELESS_EXT > 8 */
return ret;
}
/*
* Wireless Private Handler : get snapshot
*/
static int netwave_get_snap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long flags;
ioaddr_t iobase = dev->base_addr;
netwave_private *priv = (netwave_private *) dev->priv;
u_char *ramBase = priv->ramBase;
/* Disable interrupts & save flags */
save_flags(flags);
cli();
/* Take snapshot of environment */
netwave_snapshot( priv, ramBase, iobase);
wrqu->data.length = priv->nss.length;
memcpy(extra, (u_char *) &priv->nss, sizeof( struct site_survey));
priv->lastExec = jiffies;
/* ReEnable interrupts & restore flags */
restore_flags(flags);
return(0);
}
/*
* Structures to export the Wireless Handlers
* This is the stuff that are treated the wireless extensions (iwconfig)
*/
static const struct iw_priv_args netwave_private_args[] = {
/*{ cmd, set_args, get_args, name } */
{ SIOCGIPSNAP, 0,
IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | sizeof(struct site_survey),
"getsitesurvey" },
};
#if WIRELESS_EXT > 12
static const iw_handler netwave_handler[] =
{
NULL, /* SIOCSIWNAME */
netwave_get_name, /* SIOCGIWNAME */
netwave_set_nwid, /* SIOCSIWNWID */
netwave_get_nwid, /* SIOCGIWNWID */
NULL, /* SIOCSIWFREQ */
NULL, /* SIOCGIWFREQ */
NULL, /* SIOCSIWMODE */
netwave_get_mode, /* SIOCGIWMODE */
NULL, /* SIOCSIWSENS */
NULL, /* SIOCGIWSENS */
NULL, /* SIOCSIWRANGE */
netwave_get_range, /* SIOCGIWRANGE */
NULL, /* SIOCSIWPRIV */
NULL, /* SIOCGIWPRIV */
NULL, /* SIOCSIWSTATS */
NULL, /* SIOCGIWSTATS */
NULL, /* SIOCSIWSPY */
NULL, /* SIOCGIWSPY */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWAP */
NULL, /* SIOCGIWAP */
NULL, /* -- hole -- */
NULL, /* SIOCGIWAPLIST */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWESSID */
NULL, /* SIOCGIWESSID */
NULL, /* SIOCSIWNICKN */
NULL, /* SIOCGIWNICKN */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWRATE */
NULL, /* SIOCGIWRATE */
NULL, /* SIOCSIWRTS */
NULL, /* SIOCGIWRTS */
NULL, /* SIOCSIWFRAG */
NULL, /* SIOCGIWFRAG */
NULL, /* SIOCSIWTXPOW */
NULL, /* SIOCGIWTXPOW */
NULL, /* SIOCSIWRETRY */
NULL, /* SIOCGIWRETRY */
netwave_set_scramble, /* SIOCSIWENCODE */
netwave_get_scramble, /* SIOCGIWENCODE */
};
static const iw_handler netwave_private_handler[] =
{
NULL, /* SIOCIWFIRSTPRIV */
netwave_get_snap, /* SIOCIWFIRSTPRIV + 1 */
};
static const struct iw_handler_def netwave_handler_def =
{
num_standard: sizeof(netwave_handler)/sizeof(iw_handler),
num_private: sizeof(netwave_private_handler)/sizeof(iw_handler),
num_private_args: sizeof(netwave_private_args)/sizeof(struct iw_priv_args),
standard: (iw_handler *) netwave_handler,
private: (iw_handler *) netwave_private_handler,
private_args: (struct iw_priv_args *) netwave_private_args,
};
#endif /* WIRELESS_EXT > 12 */
/* /*
* Function netwave_ioctl (dev, rq, cmd) * Function netwave_ioctl (dev, rq, cmd)
* *
...@@ -606,56 +922,28 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */ ...@@ -606,56 +922,28 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
struct ifreq *rq, /* Data passed */ struct ifreq *rq, /* Data passed */
int cmd) /* Ioctl number */ int cmd) /* Ioctl number */
{ {
unsigned long flags;
int ret = 0; int ret = 0;
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
ioaddr_t iobase = dev->base_addr; #if WIRELESS_EXT <= 12
netwave_private *priv = (netwave_private *) dev->priv;
u_char *ramBase = priv->ramBase;
struct iwreq *wrq = (struct iwreq *) rq; struct iwreq *wrq = (struct iwreq *) rq;
#endif
#endif #endif
DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd); DEBUG(0, "%s: ->netwave_ioctl(cmd=0x%X)\n", dev->name, cmd);
/* Disable interrupts & save flags */
save_flags(flags);
cli();
/* Look what is the request */ /* Look what is the request */
switch(cmd) { switch(cmd) {
/* --------------- WIRELESS EXTENSIONS --------------- */ /* --------------- WIRELESS EXTENSIONS --------------- */
#ifdef WIRELESS_EXT #ifdef WIRELESS_EXT
#if WIRELESS_EXT <= 12
case SIOCGIWNAME: case SIOCGIWNAME:
/* Get name */ netwave_get_name(dev, NULL, &(wrq->u), NULL);
strcpy(wrq->u.name, "Netwave");
break; break;
case SIOCSIWNWID: case SIOCSIWNWID:
/* Set domain */ ret = netwave_set_nwid(dev, NULL, &(wrq->u), NULL);
#if WIRELESS_EXT > 8 break;
if(!wrq->u.nwid.disabled) {
domain = wrq->u.nwid.value;
#else /* WIRELESS_EXT > 8 */
if(wrq->u.nwid.on) {
domain = wrq->u.nwid.nwid;
#endif /* WIRELESS_EXT > 8 */
printk( KERN_DEBUG "Setting domain to 0x%x%02x\n",
(domain >> 8) & 0x01, domain & 0xff);
wait_WOC(iobase);
writeb(NETWAVE_CMD_SMD, ramBase + NETWAVE_EREG_CB + 0);
writeb( domain & 0xff, ramBase + NETWAVE_EREG_CB + 1);
writeb((domain >>8 ) & 0x01,ramBase + NETWAVE_EREG_CB+2);
writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
} break;
case SIOCGIWNWID: case SIOCGIWNWID:
/* Read domain*/ ret = netwave_get_nwid(dev, NULL, &(wrq->u), NULL);
#if WIRELESS_EXT > 8
wrq->u.nwid.value = domain;
wrq->u.nwid.disabled = 0;
wrq->u.nwid.fixed = 1;
#else /* WIRELESS_EXT > 8 */
wrq->u.nwid.nwid = domain;
wrq->u.nwid.on = 1;
#endif /* WIRELESS_EXT > 8 */
break; break;
#if WIRELESS_EXT > 8 /* Note : The API did change... */ #if WIRELESS_EXT > 8 /* Note : The API did change... */
case SIOCGIWENCODE: case SIOCGIWENCODE:
...@@ -663,10 +951,7 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */ ...@@ -663,10 +951,7 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
if(wrq->u.encoding.pointer != (caddr_t) 0) if(wrq->u.encoding.pointer != (caddr_t) 0)
{ {
char key[2]; char key[2];
key[1] = scramble_key & 0xff; ret = netwave_get_scramble(dev, NULL, &(wrq->u), key);
key[0] = (scramble_key>>8) & 0xff;
wrq->u.encoding.flags = IW_ENCODE_ENABLED;
wrq->u.encoding.length = 2;
if(copy_to_user(wrq->u.encoding.pointer, key, 2)) if(copy_to_user(wrq->u.encoding.pointer, key, 2))
ret = -EFAULT; ret = -EFAULT;
} }
...@@ -681,79 +966,31 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */ ...@@ -681,79 +966,31 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
ret = -EFAULT; ret = -EFAULT;
break; break;
} }
scramble_key = (key[0] << 8) | key[1]; ret = netwave_set_scramble(dev, NULL, &(wrq->u), key);
wait_WOC(iobase);
writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
} }
break; break;
case SIOCGIWMODE: case SIOCGIWMODE:
/* Mode of operation */ /* Mode of operation */
if(domain & 0x100) ret = netwave_get_mode(dev, NULL, &(wrq->u), NULL);
wrq->u.mode = IW_MODE_INFRA;
else
wrq->u.mode = IW_MODE_ADHOC;
break; break;
#else /* WIRELESS_EXT > 8 */ #else /* WIRELESS_EXT > 8 */
case SIOCGIWENCODE: case SIOCGIWENCODE:
/* Get scramble key */ /* Get scramble key */
wrq->u.encoding.code = scramble_key; ret = netwave_get_scramble(dev, NULL, &(wrq->u),
wrq->u.encoding.method = 1; (char *) &wrq->u.encoding.code);
break; break;
case SIOCSIWENCODE: case SIOCSIWENCODE:
/* Set scramble key */ /* Set scramble key */
scramble_key = wrq->u.encoding.code; ret = netwave_set_scramble(dev, NULL, &(wrq->u),
wait_WOC(iobase); (char *) &wrq->u.encoding.code);
writeb(NETWAVE_CMD_SSK, ramBase + NETWAVE_EREG_CB + 0);
writeb(scramble_key & 0xff, ramBase + NETWAVE_EREG_CB + 1);
writeb((scramble_key>>8) & 0xff, ramBase + NETWAVE_EREG_CB + 2);
writeb(NETWAVE_CMD_EOC, ramBase + NETWAVE_EREG_CB + 3);
break; break;
#endif /* WIRELESS_EXT > 8 */ #endif /* WIRELESS_EXT > 8 */
case SIOCGIWRANGE: case SIOCGIWRANGE:
/* Basic checking... */ /* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0) { if(wrq->u.data.pointer != (caddr_t) 0) {
struct iw_range range; struct iw_range range;
ret = netwave_get_range(dev, NULL, &(wrq->u), (char *) &range);
/* Set the length (very important for backward compatibility) */ if (copy_to_user(wrq->u.data.pointer, &range,
wrq->u.data.length = sizeof(struct iw_range);
/* Set all the info we don't care or don't know about to zero */
memset(&range, 0, sizeof(range));
#if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */
range.we_version_compiled = WIRELESS_EXT;
range.we_version_source = 9; /* Nothing for us in v10 and v11 */
#endif /* WIRELESS_EXT > 10 */
/* Set information in the range struct */
range.throughput = 450 * 1000; /* don't argue on this ! */
range.min_nwid = 0x0000;
range.max_nwid = 0x01FF;
range.num_channels = range.num_frequency = 0;
range.sensitivity = 0x3F;
range.max_qual.qual = 255;
range.max_qual.level = 255;
range.max_qual.noise = 0;
#if WIRELESS_EXT > 7
range.num_bitrates = 1;
range.bitrate[0] = 1000000; /* 1 Mb/s */
#endif /* WIRELESS_EXT > 7 */
#if WIRELESS_EXT > 8
range.encoding_size[0] = 2; /* 16 bits scrambling */
range.num_encoding_sizes = 1;
range.max_encoding_tokens = 1; /* Only one key possible */
#endif /* WIRELESS_EXT > 8 */
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, &range,
sizeof(struct iw_range))) sizeof(struct iw_range)))
ret = -EFAULT; ret = -EFAULT;
} }
...@@ -761,47 +998,36 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */ ...@@ -761,47 +998,36 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
case SIOCGIWPRIV: case SIOCGIWPRIV:
/* Basic checking... */ /* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0) { if(wrq->u.data.pointer != (caddr_t) 0) {
struct iw_priv_args priv[] =
{ /* cmd, set_args, get_args, name */
{ SIOCGIPSNAP, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 0,
sizeof(struct site_survey),
"getsitesurvey" },
};
/* Set the number of ioctl available */ /* Set the number of ioctl available */
wrq->u.data.length = 1; wrq->u.data.length = sizeof(netwave_private_args) / sizeof(netwave_private_args[0]);
/* Copy structure to the user buffer */ /* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, if(copy_to_user(wrq->u.data.pointer,
sizeof(priv))) (u_char *) netwave_private_args,
sizeof(netwave_private_args)))
ret = -EFAULT; ret = -EFAULT;
} }
break; break;
case SIOCGIPSNAP: case SIOCGIPSNAP:
if(wrq->u.data.pointer != (caddr_t) 0) { if(wrq->u.data.pointer != (caddr_t) 0) {
/* Take snapshot of environment */ char buffer[sizeof( struct site_survey)];
netwave_snapshot( priv, ramBase, iobase); ret = netwave_get_snap(dev, NULL, &(wrq->u), buffer);
wrq->u.data.length = priv->nss.length;
/* Copy structure to the user buffer */ /* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, if(copy_to_user(wrq->u.data.pointer,
(u_char *) &priv->nss, buffer,
sizeof( struct site_survey))) sizeof( struct site_survey)))
{ {
printk(KERN_DEBUG "Bad buffer!\n"); printk(KERN_DEBUG "Bad buffer!\n");
break; break;
} }
priv->lastExec = jiffies;
} }
break; break;
#endif #endif /* WIRELESS_EXT <= 12 */
#endif /* WIRELESS_EXT */
default: default:
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
} }
/* ReEnable interrupts & restore flags */
restore_flags(flags);
return ret; return ret;
} }
......
...@@ -22,28 +22,6 @@ ...@@ -22,28 +22,6 @@
* (WaveLAN modem or i82586) * (WaveLAN modem or i82586)
*/ */
/*------------------------------------------------------------------*/
/*
* Wrapper for disabling interrupts and locking the driver.
* (note : inline, so optimised away)
*/
static inline void wv_splhi(net_local * lp,
unsigned long * pflags)
{
spin_lock_irqsave(&lp->spinlock, *pflags);
/* Note : above does the cli(); itself */
}
/*------------------------------------------------------------------*/
/*
* Wrapper for re-enabling interrupts and un-locking the driver.
*/
static inline void wv_splx(net_local * lp,
unsigned long * pflags)
{
spin_unlock_irqrestore(&lp->spinlock, *pflags);
}
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
* Translate irq number to PSA irq parameter * Translate irq number to PSA irq parameter
...@@ -870,10 +848,10 @@ static inline void wv_82586_reconfig(device * dev) ...@@ -870,10 +848,10 @@ static inline void wv_82586_reconfig(device * dev)
/* Check if we can do it now ! */ /* Check if we can do it now ! */
if((netif_running(dev)) && !(netif_queue_stopped(dev))) { if((netif_running(dev)) && !(netif_queue_stopped(dev))) {
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
/* May fail */ /* May fail */
wv_82586_config(dev); wv_82586_config(dev);
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
} }
else { else {
#ifdef DEBUG_CONFIG_INFO #ifdef DEBUG_CONFIG_INFO
...@@ -1786,45 +1764,41 @@ static inline void wl_his_gather(device * dev, u8 * stats) ...@@ -1786,45 +1764,41 @@ static inline void wl_his_gather(device * dev, u8 * stats)
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
* Perform ioctl for configuration and information. * Wireless Handler : get protocol name
* It is here that the wireless extensions are treated (iwconfig). */
static int wavelan_get_name(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
strcpy(wrqu->name, "WaveLAN");
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set NWID
*/ */
static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is applied */ static int wavelan_set_nwid(struct net_device *dev,
struct ifreq *rq, /* data passed */ struct iw_request_info *info,
int cmd) union iwreq_data *wrqu,
{ /* ioctl number */ char *extra)
{
unsigned long ioaddr = dev->base_addr; unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct iwreq *wrq = (struct iwreq *) rq;
psa_t psa; psa_t psa;
mm_t m; mm_t m;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
int err = 0;
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name,
cmd);
#endif
/* Disable interrupts and save flags. */ /* Disable interrupts and save flags. */
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
/* Look what is the request */
switch (cmd) {
/* --------------- WIRELESS EXTENSIONS --------------- */
case SIOCGIWNAME:
strcpy(wrq->u.name, "WaveLAN");
break;
case SIOCSIWNWID:
/* Set NWID in WaveLAN. */ /* Set NWID in WaveLAN. */
if (!wrq->u.nwid.disabled) { if (!wrqu->nwid.disabled) {
/* Set NWID in psa */ /* Set NWID in psa */
psa.psa_nwid[0] = psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8;
(wrq->u.nwid.value & 0xFF00) >> 8; psa.psa_nwid[1] = wrqu->nwid.value & 0xFF;
psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
psa.psa_nwid_select = 0x01; psa.psa_nwid_select = 0x01;
psa_write(ioaddr, lp->hacr, psa_write(ioaddr, lp->hacr,
(char *) psa.psa_nwid - (char *) &psa, (char *) psa.psa_nwid - (char *) &psa,
...@@ -1853,29 +1827,93 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is ...@@ -1853,29 +1827,93 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
} }
/* update the Wavelan checksum */ /* update the Wavelan checksum */
update_psa_checksum(dev, ioaddr, lp->hacr); update_psa_checksum(dev, ioaddr, lp->hacr);
break;
case SIOCGIWNWID: /* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get NWID
*/
static int wavelan_get_nwid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Read the NWID. */ /* Read the NWID. */
psa_read(ioaddr, lp->hacr, psa_read(ioaddr, lp->hacr,
(char *) psa.psa_nwid - (char *) &psa, (char *) psa.psa_nwid - (char *) &psa,
(unsigned char *) psa.psa_nwid, 3); (unsigned char *) psa.psa_nwid, 3);
wrq->u.nwid.value = wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
(psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; wrqu->nwid.disabled = !(psa.psa_nwid_select);
wrq->u.nwid.disabled = !(psa.psa_nwid_select); wrqu->nwid.fixed = 1; /* Superfluous */
wrq->u.nwid.fixed = 1; /* Superfluous */
break; /* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set frequency
*/
static int wavelan_set_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
int ret;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
case SIOCSIWFREQ:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
ret = wv_set_frequency(ioaddr, &(wrq->u.freq)); ret = wv_set_frequency(ioaddr, &(wrqu->freq));
else else
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break;
case SIOCGIWFREQ: /* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get frequency
*/
static int wavelan_get_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
* Does it work for everybody, especially old cards? */ * Does it work for everybody, especially old cards? */
if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
...@@ -1884,27 +1922,48 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is ...@@ -1884,27 +1922,48 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
/* Ask the EEPROM to read the frequency from the first area. */ /* Ask the EEPROM to read the frequency from the first area. */
fee_read(ioaddr, 0x00, &freq, 1); fee_read(ioaddr, 0x00, &freq, 1);
wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000; wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrq->u.freq.e = 1; wrqu->freq.e = 1;
} else { } else {
psa_read(ioaddr, lp->hacr, psa_read(ioaddr, lp->hacr,
(char *) &psa.psa_subband - (char *) &psa, (char *) &psa.psa_subband - (char *) &psa,
(unsigned char *) &psa.psa_subband, 1); (unsigned char *) &psa.psa_subband, 1);
if (psa.psa_subband <= 4) { if (psa.psa_subband <= 4) {
wrq->u.freq.m = wrqu->freq.m = fixed_bands[psa.psa_subband];
fixed_bands[psa.psa_subband]; wrqu->freq.e = (psa.psa_subband != 0);
wrq->u.freq.e = (psa.psa_subband != 0);
} else } else
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
} }
break;
case SIOCSIWSENS: /* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set level threshold
*/
static int wavelan_set_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Set the level threshold. */ /* Set the level threshold. */
/* We should complain loudly if wrq->u.sens.fixed = 0, because we /* We should complain loudly if wrqu->sens.fixed = 0, because we
* can't set auto mode... */ * can't set auto mode... */
psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; psa.psa_thr_pre_set = wrqu->sens.value & 0x3F;
psa_write(ioaddr, lp->hacr, psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_thr_pre_set - (char *) &psa, (char *) &psa.psa_thr_pre_set - (char *) &psa,
(unsigned char *) &psa.psa_thr_pre_set, 1); (unsigned char *) &psa.psa_thr_pre_set, 1);
...@@ -1912,44 +1971,80 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is ...@@ -1912,44 +1971,80 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
update_psa_checksum(dev, ioaddr, lp->hacr); update_psa_checksum(dev, ioaddr, lp->hacr);
mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set), mmc_out(ioaddr, mmwoff(0, mmw_thr_pre_set),
psa.psa_thr_pre_set); psa.psa_thr_pre_set);
break;
case SIOCGIWSENS: /* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get level threshold
*/
static int wavelan_get_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Read the level threshold. */ /* Read the level threshold. */
psa_read(ioaddr, lp->hacr, psa_read(ioaddr, lp->hacr,
(char *) &psa.psa_thr_pre_set - (char *) &psa, (char *) &psa.psa_thr_pre_set - (char *) &psa,
(unsigned char *) &psa.psa_thr_pre_set, 1); (unsigned char *) &psa.psa_thr_pre_set, 1);
wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; wrqu->sens.value = psa.psa_thr_pre_set & 0x3F;
wrq->u.sens.fixed = 1; wrqu->sens.fixed = 1;
break;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set encryption key
*/
static int wavelan_set_encode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
psa_t psa;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
case SIOCSIWENCODE: /* Check if capable of encryption */
/* Set encryption key */
if (!mmc_encr(ioaddr)) { if (!mmc_encr(ioaddr)) {
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break;
} }
/* Basic checking... */
if (wrq->u.encoding.pointer != (caddr_t) 0) {
/* Check the size of the key */ /* Check the size of the key */
if (wrq->u.encoding.length != 8) { if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) {
ret = -EINVAL; ret = -EINVAL;
break;
} }
if(!ret) {
/* Basic checking... */
if (wrqu->encoding.length == 8) {
/* Copy the key in the driver */ /* Copy the key in the driver */
wv_splx(lp, &flags); memcpy(psa.psa_encryption_key, extra,
err = copy_from_user(psa.psa_encryption_key, wrqu->encoding.length);
wrq->u.encoding.pointer,
wrq->u.encoding.length);
wv_splhi(lp, &flags);
if (err) {
ret = -EFAULT;
break;
}
psa.psa_encryption_select = 1; psa.psa_encryption_select = 1;
psa_write(ioaddr, lp->hacr, psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select - (char *) &psa.psa_encryption_select -
(char *) &psa, (char *) &psa,
...@@ -1963,7 +2058,8 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is ...@@ -1963,7 +2058,8 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
psa_encryption_key, 8); psa_encryption_key, 8);
} }
if (wrq->u.encoding.flags & IW_ENCODE_DISABLED) { /* disable encryption */ /* disable encryption */
if (wrqu->encoding.flags & IW_ENCODE_DISABLED) {
psa.psa_encryption_select = 0; psa.psa_encryption_select = 0;
psa_write(ioaddr, lp->hacr, psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select - (char *) &psa.psa_encryption_select -
...@@ -1975,30 +2071,37 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is ...@@ -1975,30 +2071,37 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
} }
/* update the Wavelan checksum */ /* update the Wavelan checksum */
update_psa_checksum(dev, ioaddr, lp->hacr); update_psa_checksum(dev, ioaddr, lp->hacr);
break;
case SIOCGIWENCODE:
/* Read the encryption key */
if (!mmc_encr(ioaddr)) {
ret = -EOPNOTSUPP;
break;
} }
/* only super-user can see encryption key */ /* Enable interrupts and restore flags. */
if (!capable(CAP_NET_ADMIN)) { spin_unlock_irqrestore(&lp->spinlock, flags);
ret = -EPERM;
break;
}
/* Basic checking... */ return ret;
if (wrq->u.encoding.pointer != (caddr_t) 0) { }
/* Verify the user buffer */
ret = /*------------------------------------------------------------------*/
verify_area(VERIFY_WRITE, /*
wrq->u.encoding.pointer, 8); * Wireless Handler : get encryption key
if (ret) */
break; static int wavelan_get_encode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Check if encryption is available */
if (!mmc_encr(ioaddr)) {
ret = -EOPNOTSUPP;
} else {
/* Read the encryption key */
psa_read(ioaddr, lp->hacr, psa_read(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select - (char *) &psa.psa_encryption_select -
(char *) &psa, (char *) &psa,
...@@ -2007,168 +2110,126 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is ...@@ -2007,168 +2110,126 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
/* encryption is enabled ? */ /* encryption is enabled ? */
if (psa.psa_encryption_select) if (psa.psa_encryption_select)
wrq->u.encoding.flags = IW_ENCODE_ENABLED; wrqu->encoding.flags = IW_ENCODE_ENABLED;
else else
wrq->u.encoding.flags = IW_ENCODE_DISABLED; wrqu->encoding.flags = IW_ENCODE_DISABLED;
wrq->u.encoding.flags |= mmc_encr(ioaddr); wrqu->encoding.flags |= mmc_encr(ioaddr);
/* Copy the key to the user buffer */ /* Copy the key to the user buffer */
wrq->u.encoding.length = 8; wrqu->encoding.length = 8;
wv_splx(lp, &flags); memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length);
if (copy_to_user(wrq->u.encoding.pointer,
psa.psa_encryption_key, 8))
ret = -EFAULT;
wv_splhi(lp, &flags);
} }
break;
case SIOCGIWRANGE: /* Enable interrupts and restore flags. */
/* basic checking */ spin_unlock_irqrestore(&lp->spinlock, flags);
if (wrq->u.data.pointer != (caddr_t) 0) {
struct iw_range range;
/* Set the length (very important for backward return ret;
* compatibility) */ }
wrq->u.data.length = sizeof(struct iw_range);
/* Set all the info we don't care or don't know /*------------------------------------------------------------------*/
* about to zero */ /*
memset(&range, 0, sizeof(range)); * Wireless Handler : get range info
*/
static int wavelan_get_range(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct iw_range *range = (struct iw_range *) extra;
unsigned long flags;
int ret = 0;
/* Set the length (very important for backward compatibility) */
wrqu->data.length = sizeof(struct iw_range);
/* Set all the info we don't care or don't know about to zero */
memset(range, 0, sizeof(struct iw_range));
/* Set the Wireless Extension versions */ /* Set the Wireless Extension versions */
range.we_version_compiled = WIRELESS_EXT; range->we_version_compiled = WIRELESS_EXT;
range.we_version_source = 9; range->we_version_source = 9;
/* Set information in the range struct. */ /* Set information in the range struct. */
range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */ range->throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */
range.min_nwid = 0x0000; range->min_nwid = 0x0000;
range.max_nwid = 0xFFFF; range->max_nwid = 0xFFFF;
range->sensitivity = 0x3F;
range->max_qual.qual = MMR_SGNL_QUAL;
range->max_qual.level = MMR_SIGNAL_LVL;
range->max_qual.noise = MMR_SILENCE_LVL;
range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
/* Need to get better values for those two */
range->avg_qual.level = 30;
range->avg_qual.noise = 8;
range->num_bitrates = 1;
range->bitrate[0] = 2000000; /* 2 Mb/s */
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */ /* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) & if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) { (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
range.num_channels = 10; range->num_channels = 10;
range.num_frequency = range->num_frequency = wv_frequency_list(ioaddr, range->freq,
wv_frequency_list(ioaddr, range.freq,
IW_MAX_FREQUENCIES); IW_MAX_FREQUENCIES);
} else } else
range.num_channels = range.num_frequency = range->num_channels = range->num_frequency = 0;
0;
range.sensitivity = 0x3F;
range.max_qual.qual = MMR_SGNL_QUAL;
range.max_qual.level = MMR_SIGNAL_LVL;
range.max_qual.noise = MMR_SILENCE_LVL;
range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
/* Need to get better values for those two */
range.avg_qual.level = 30;
range.avg_qual.noise = 8;
range.num_bitrates = 1;
range.bitrate[0] = 2000000; /* 2 Mb/s */
/* Encryption supported ? */ /* Encryption supported ? */
if (mmc_encr(ioaddr)) { if (mmc_encr(ioaddr)) {
range.encoding_size[0] = 8; /* DES = 64 bits key */ range->encoding_size[0] = 8; /* DES = 64 bits key */
range.num_encoding_sizes = 1; range->num_encoding_sizes = 1;
range.max_encoding_tokens = 1; /* Only one key possible */ range->max_encoding_tokens = 1; /* Only one key possible */
} else { } else {
range.num_encoding_sizes = 0; range->num_encoding_sizes = 0;
range.max_encoding_tokens = 0; range->max_encoding_tokens = 0;
} }
/* Copy structure to the user buffer. */ /* Enable interrupts and restore flags. */
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
if (copy_to_user(wrq->u.data.pointer,
&range,
sizeof(struct iw_range)))
ret = -EFAULT;
wv_splhi(lp, &flags);
}
break;
case SIOCGIWPRIV: return ret;
/* Basic checking */ }
if (wrq->u.data.pointer != (caddr_t) 0) {
struct iw_priv_args priv[] = {
/* { cmd,
set_args,
get_args,
name } */
{ SIOCSIPQTHR,
IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
0,
"setqualthr" },
{ SIOCGIPQTHR,
0,
IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
"getqualthr" },
{ SIOCSIPHISTO,
IW_PRIV_TYPE_BYTE | 16,
0,
"sethisto" },
{ SIOCGIPHISTO,
0,
IW_PRIV_TYPE_INT | 16,
"gethisto" },
};
/* Set the number of available ioctls. */
wrq->u.data.length = 4;
/* Copy structure to the user buffer. */
wv_splx(lp, &flags);
if (copy_to_user(wrq->u.data.pointer,
(u8 *) priv,
sizeof(priv)))
ret = -EFAULT;
wv_splhi(lp, &flags);
}
break;
#ifdef WIRELESS_SPY #ifdef WIRELESS_SPY
case SIOCSIWSPY: /*------------------------------------------------------------------*/
/* Set the spy list */ /*
* Wireless Handler : set spy list
/* Check the number of addresses. */ */
if (wrq->u.data.length > IW_MAX_SPY) { static int wavelan_set_spy(struct net_device *dev,
ret = -E2BIG; struct iw_request_info *info,
break; union iwreq_data *wrqu,
} char *extra)
lp->spy_number = wrq->u.data.length; {
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
/* Are there are addresses to copy? */ struct sockaddr *address = (struct sockaddr *) extra;
if (lp->spy_number > 0) {
struct sockaddr address[IW_MAX_SPY];
int i; int i;
int ret = 0;
/* Copy addresses to the driver. */ /* Disable spy while we copy the addresses.
wv_splx(lp, &flags); * As we don't disable interrupts, we need to do this */
err = copy_from_user(address, lp->spy_number = 0;
wrq->u.data.pointer,
sizeof(struct sockaddr)
* lp->spy_number);
wv_splhi(lp, &flags);
if (err) {
ret = -EFAULT;
break;
}
/* Are there are addresses to copy? */
if (wrqu->data.length > 0) {
/* Copy addresses to the lp structure. */ /* Copy addresses to the lp structure. */
for (i = 0; i < lp->spy_number; i++) { for (i = 0; i < wrqu->data.length; i++) {
memcpy(lp->spy_address[i], memcpy(lp->spy_address[i], address[i].sa_data,
address[i].sa_data,
WAVELAN_ADDR_SIZE); WAVELAN_ADDR_SIZE);
} }
/* Reset structure. */ /* Reset structure. */
memset(lp->spy_stat, 0x00, memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
sizeof(iw_qual) * IW_MAX_SPY);
#ifdef DEBUG_IOCTL_INFO #ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG printk(KERN_DEBUG
"SetSpy: set of new addresses is: \n"); "SetSpy: set of new addresses is: \n");
for (i = 0; i < wrq->u.data.length; i++) for (i = 0; i < wrqu->data.length; i++)
printk(KERN_DEBUG printk(KERN_DEBUG
"%02X:%02X:%02X:%02X:%02X:%02X \n", "%02X:%02X:%02X:%02X:%02X:%02X \n",
lp->spy_address[i][0], lp->spy_address[i][0],
...@@ -2180,20 +2241,28 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is ...@@ -2180,20 +2241,28 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
#endif /* DEBUG_IOCTL_INFO */ #endif /* DEBUG_IOCTL_INFO */
} }
break; /* Now we can set the number of addresses */
lp->spy_number = wrqu->data.length;
case SIOCGIWSPY: return ret;
/* Get the spy list and spy stats. */ }
/* Set the number of addresses */
wrq->u.data.length = lp->spy_number;
/* Does the user want to have the addresses back? */ /*------------------------------------------------------------------*/
if ((lp->spy_number > 0) /*
&& (wrq->u.data.pointer != (caddr_t) 0)) { * Wireless Handler : get spy list
struct sockaddr address[IW_MAX_SPY]; */
static int wavelan_get_spy(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct sockaddr *address = (struct sockaddr *) extra;
int i; int i;
/* Set the number of addresses */
wrqu->data.length = lp->spy_number;
/* Copy addresses from the lp structure. */ /* Copy addresses from the lp structure. */
for (i = 0; i < lp->spy_number; i++) { for (i = 0; i < lp->spy_number; i++) {
memcpy(address[i].sa_data, memcpy(address[i].sa_data,
...@@ -2201,42 +2270,37 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is ...@@ -2201,42 +2270,37 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
WAVELAN_ADDR_SIZE); WAVELAN_ADDR_SIZE);
address[i].sa_family = AF_UNIX; address[i].sa_family = AF_UNIX;
} }
/* Copy addresses to the user buffer. */
wv_splx(lp, &flags);
err = copy_to_user(wrq->u.data.pointer,
address,
sizeof(struct sockaddr)
* lp->spy_number);
/* Copy stats to the user buffer (just after). */ /* Copy stats to the user buffer (just after). */
err |= copy_to_user(wrq->u.data.pointer if(lp->spy_number > 0)
+ (sizeof(struct sockaddr) memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number),
* lp->spy_number), lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
lp->spy_stat,
sizeof(iw_qual) * lp->spy_number);
wv_splhi(lp, &flags);
if (err) {
ret = -EFAULT;
break;
}
/* Reset updated flags. */ /* Reset updated flags. */
for (i = 0; i < lp->spy_number; i++) for (i = 0; i < lp->spy_number; i++)
lp->spy_stat[i].updated = 0x0; lp->spy_stat[i].updated = 0x0;
}
/* if(pointer != NULL) */ return(0);
break; }
#endif /* WIRELESS_SPY */ #endif /* WIRELESS_SPY */
/* ------------------ PRIVATE IOCTL ------------------ */ /*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set quality threshold
*/
static int wavelan_set_qthr(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
case SIOCSIPQTHR: psa.psa_quality_thr = *(extra) & 0x0F;
if (!capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
psa_write(ioaddr, lp->hacr, psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_quality_thr - (char *) &psa, (char *) &psa.psa_quality_thr - (char *) &psa,
(unsigned char *) &psa.psa_quality_thr, 1); (unsigned char *) &psa.psa_quality_thr, 1);
...@@ -2244,81 +2308,193 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is ...@@ -2244,81 +2308,193 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
update_psa_checksum(dev, ioaddr, lp->hacr); update_psa_checksum(dev, ioaddr, lp->hacr);
mmc_out(ioaddr, mmwoff(0, mmw_quality_thr), mmc_out(ioaddr, mmwoff(0, mmw_quality_thr),
psa.psa_quality_thr); psa.psa_quality_thr);
break;
case SIOCGIPQTHR: /* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get quality threshold
*/
static int wavelan_get_qthr(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
unsigned long ioaddr = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
psa_read(ioaddr, lp->hacr, psa_read(ioaddr, lp->hacr,
(char *) &psa.psa_quality_thr - (char *) &psa, (char *) &psa.psa_quality_thr - (char *) &psa,
(unsigned char *) &psa.psa_quality_thr, 1); (unsigned char *) &psa.psa_quality_thr, 1);
*(wrq->u.name) = psa.psa_quality_thr & 0x0F; *(extra) = psa.psa_quality_thr & 0x0F;
break;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return 0;
}
#ifdef HISTOGRAM #ifdef HISTOGRAM
case SIOCSIPHISTO: /*------------------------------------------------------------------*/
/* Verify that the user is root. */ /*
if (!capable(CAP_NET_ADMIN)) { * Wireless Private Handler : set histogram
ret = -EPERM; */
break; static int wavelan_set_histo(struct net_device *dev,
} struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
/* Check the number of intervals. */ /* Check the number of intervals. */
if (wrq->u.data.length > 16) { if (wrqu->data.length > 16) {
ret = -E2BIG; return(-E2BIG);
break;
} }
lp->his_number = wrq->u.data.length;
/* Are there addresses to copy? */ /* Disable histo while we copy the addresses.
if (lp->his_number > 0) { * As we don't disable interrupts, we need to do this */
lp->his_number = 0;
/* Are there ranges to copy? */
if (wrqu->data.length > 0) {
/* Copy interval ranges to the driver */ /* Copy interval ranges to the driver */
wv_splx(lp, &flags); memcpy(lp->his_range, extra, wrqu->data.length);
err = copy_from_user(lp->his_range,
wrq->u.data.pointer, {
sizeof(char) * lp->his_number); int i;
wv_splhi(lp, &flags); printk(KERN_DEBUG "Histo :");
if (err) { for(i = 0; i < wrqu->data.length; i++)
ret = -EFAULT; printk(" %d", lp->his_range[i]);
break; printk("\n");
} }
/* Reset structure. */ /* Reset result structure. */
memset(lp->his_sum, 0x00, sizeof(long) * 16); memset(lp->his_sum, 0x00, sizeof(long) * 16);
} }
break;
case SIOCGIPHISTO: /* Now we can set the number of ranges */
lp->his_number = wrqu->data.length;
return(0);
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get histogram
*/
static int wavelan_get_histo(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
/* Set the number of intervals. */ /* Set the number of intervals. */
wrq->u.data.length = lp->his_number; wrqu->data.length = lp->his_number;
/* Give back the distribution statistics */ /* Give back the distribution statistics */
if ((lp->his_number > 0) if(lp->his_number > 0)
&& (wrq->u.data.pointer != (caddr_t) 0)) { memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number);
/* Copy data to the user buffer. */
wv_splx(lp, &flags); return(0);
if (copy_to_user(wrq->u.data.pointer, }
lp->his_sum,
sizeof(long) * lp->his_number);
ret = -EFAULT;
wv_splhi(lp, &flags);
} /* if(pointer != NULL) */
break;
#endif /* HISTOGRAM */ #endif /* HISTOGRAM */
/* ------------------- OTHER IOCTL ------------------- */ /*------------------------------------------------------------------*/
/*
* Structures to export the Wireless Handlers
*/
default: static const iw_handler wavelan_handler[] =
ret = -EOPNOTSUPP; {
} /* switch (cmd) */ NULL, /* SIOCSIWNAME */
wavelan_get_name, /* SIOCGIWNAME */
wavelan_set_nwid, /* SIOCSIWNWID */
wavelan_get_nwid, /* SIOCGIWNWID */
wavelan_set_freq, /* SIOCSIWFREQ */
wavelan_get_freq, /* SIOCGIWFREQ */
NULL, /* SIOCSIWMODE */
NULL, /* SIOCGIWMODE */
wavelan_set_sens, /* SIOCSIWSENS */
wavelan_get_sens, /* SIOCGIWSENS */
NULL, /* SIOCSIWRANGE */
wavelan_get_range, /* SIOCGIWRANGE */
NULL, /* SIOCSIWPRIV */
NULL, /* SIOCGIWPRIV */
NULL, /* SIOCSIWSTATS */
NULL, /* SIOCGIWSTATS */
#ifdef WIRELESS_SPY
wavelan_set_spy, /* SIOCSIWSPY */
wavelan_get_spy, /* SIOCGIWSPY */
#else /* WIRELESS_SPY */
NULL, /* SIOCSIWSPY */
NULL, /* SIOCGIWSPY */
#endif /* WIRELESS_SPY */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWAP */
NULL, /* SIOCGIWAP */
NULL, /* -- hole -- */
NULL, /* SIOCGIWAPLIST */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWESSID */
NULL, /* SIOCGIWESSID */
NULL, /* SIOCSIWNICKN */
NULL, /* SIOCGIWNICKN */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWRATE */
NULL, /* SIOCGIWRATE */
NULL, /* SIOCSIWRTS */
NULL, /* SIOCGIWRTS */
NULL, /* SIOCSIWFRAG */
NULL, /* SIOCGIWFRAG */
NULL, /* SIOCSIWTXPOW */
NULL, /* SIOCGIWTXPOW */
NULL, /* SIOCSIWRETRY */
NULL, /* SIOCGIWRETRY */
/* Bummer ! Why those are only at the end ??? */
wavelan_set_encode, /* SIOCSIWENCODE */
wavelan_get_encode, /* SIOCGIWENCODE */
};
static const iw_handler wavelan_private_handler[] =
{
wavelan_set_qthr, /* SIOCIWFIRSTPRIV */
wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */
#ifdef HISTOGRAM
wavelan_set_histo, /* SIOCIWFIRSTPRIV + 2 */
wavelan_get_histo, /* SIOCIWFIRSTPRIV + 3 */
#endif /* HISTOGRAM */
};
/* Enable interrupts and restore flags. */ static const struct iw_priv_args wavelan_private_args[] = {
wv_splx(lp, &flags); /*{ cmd, set_args, get_args, name } */
{ SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
{ SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
{ SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" },
{ SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" },
};
#ifdef DEBUG_IOCTL_TRACE static const struct iw_handler_def wavelan_handler_def =
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); {
#endif num_standard: sizeof(wavelan_handler)/sizeof(iw_handler),
return ret; num_private: sizeof(wavelan_private_handler)/sizeof(iw_handler),
} num_private_args: sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
standard: (iw_handler *) wavelan_handler,
private: (iw_handler *) wavelan_private_handler,
private_args: (struct iw_priv_args *) wavelan_private_args,
};
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
...@@ -2343,7 +2519,7 @@ static iw_stats *wavelan_get_wireless_stats(device * dev) ...@@ -2343,7 +2519,7 @@ static iw_stats *wavelan_get_wireless_stats(device * dev)
return (iw_stats *) NULL; return (iw_stats *) NULL;
/* Disable interrupts and save flags. */ /* Disable interrupts and save flags. */
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
wstats = &lp->wstats; wstats = &lp->wstats;
...@@ -2371,7 +2547,7 @@ static iw_stats *wavelan_get_wireless_stats(device * dev) ...@@ -2371,7 +2547,7 @@ static iw_stats *wavelan_get_wireless_stats(device * dev)
wstats->discard.misc = 0L; wstats->discard.misc = 0L;
/* Enable interrupts and restore flags. */ /* Enable interrupts and restore flags. */
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_IOCTL_TRACE #ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n",
...@@ -2705,7 +2881,7 @@ static inline int wv_packet_write(device * dev, void *buf, short length) ...@@ -2705,7 +2881,7 @@ static inline int wv_packet_write(device * dev, void *buf, short length)
if (clen < ETH_ZLEN) if (clen < ETH_ZLEN)
clen = ETH_ZLEN; clen = ETH_ZLEN;
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
/* Check nothing bad has happened */ /* Check nothing bad has happened */
if (lp->tx_n_in_use == (NTXBLOCKS - 1)) { if (lp->tx_n_in_use == (NTXBLOCKS - 1)) {
...@@ -2713,7 +2889,7 @@ static inline int wv_packet_write(device * dev, void *buf, short length) ...@@ -2713,7 +2889,7 @@ static inline int wv_packet_write(device * dev, void *buf, short length)
printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n", printk(KERN_INFO "%s: wv_packet_write(): Tx queue full.\n",
dev->name); dev->name);
#endif #endif
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
return 1; return 1;
} }
...@@ -2791,7 +2967,7 @@ static inline int wv_packet_write(device * dev, void *buf, short length) ...@@ -2791,7 +2967,7 @@ static inline int wv_packet_write(device * dev, void *buf, short length)
if (lp->tx_n_in_use < NTXBLOCKS - 1) if (lp->tx_n_in_use < NTXBLOCKS - 1)
netif_wake_queue(dev); netif_wake_queue(dev);
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_TX_INFO #ifdef DEBUG_TX_INFO
wv_packet_info((u8 *) buf, length, dev->name, wv_packet_info((u8 *) buf, length, dev->name,
...@@ -2832,9 +3008,9 @@ static int wavelan_packet_xmit(struct sk_buff *skb, device * dev) ...@@ -2832,9 +3008,9 @@ static int wavelan_packet_xmit(struct sk_buff *skb, device * dev)
* we can do it now. * we can do it now.
*/ */
if (lp->reconfig_82586) { if (lp->reconfig_82586) {
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
wv_82586_config(dev); wv_82586_config(dev);
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
/* Check that we can continue */ /* Check that we can continue */
if (lp->tx_n_in_use == (NTXBLOCKS - 1)) if (lp->tx_n_in_use == (NTXBLOCKS - 1))
return 1; return 1;
...@@ -3694,7 +3870,7 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs) ...@@ -3694,7 +3870,7 @@ static void wavelan_interrupt(int irq, void *dev_id, struct pt_regs *regs)
/* Prevent reentrancy. We need to do that because we may have /* Prevent reentrancy. We need to do that because we may have
* multiple interrupt handler running concurrently. * multiple interrupt handler running concurrently.
* It is safe because wv_splhi() disables interrupts before acquiring * It is safe because interrupts are disabled before acquiring
* the spinlock. */ * the spinlock. */
spin_lock(&lp->spinlock); spin_lock(&lp->spinlock);
...@@ -3822,7 +3998,7 @@ static void wavelan_watchdog(device * dev) ...@@ -3822,7 +3998,7 @@ static void wavelan_watchdog(device * dev)
return; return;
} }
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
/* Try to see if some buffers are not free (in case we missed /* Try to see if some buffers are not free (in case we missed
* an interrupt */ * an interrupt */
...@@ -3862,7 +4038,7 @@ static void wavelan_watchdog(device * dev) ...@@ -3862,7 +4038,7 @@ static void wavelan_watchdog(device * dev)
if (lp->tx_n_in_use < NTXBLOCKS - 1) if (lp->tx_n_in_use < NTXBLOCKS - 1)
netif_wake_queue(dev); netif_wake_queue(dev);
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_INTERRUPT_TRACE #ifdef DEBUG_INTERRUPT_TRACE
printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name); printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
...@@ -3909,7 +4085,7 @@ static int wavelan_open(device * dev) ...@@ -3909,7 +4085,7 @@ static int wavelan_open(device * dev)
return -EAGAIN; return -EAGAIN;
} }
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
if (wv_hw_reset(dev) != -1) { if (wv_hw_reset(dev) != -1) {
netif_start_queue(dev); netif_start_queue(dev);
...@@ -3920,10 +4096,10 @@ static int wavelan_open(device * dev) ...@@ -3920,10 +4096,10 @@ static int wavelan_open(device * dev)
"%s: wavelan_open(): impossible to start the card\n", "%s: wavelan_open(): impossible to start the card\n",
dev->name); dev->name);
#endif #endif
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
return -EAGAIN; return -EAGAIN;
} }
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_CALLBACK_TRACE #ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name); printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
...@@ -3951,9 +4127,9 @@ static int wavelan_close(device * dev) ...@@ -3951,9 +4127,9 @@ static int wavelan_close(device * dev)
/* /*
* Flush the Tx and disable Rx. * Flush the Tx and disable Rx.
*/ */
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
wv_82586_stop(dev); wv_82586_stop(dev);
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
free_irq(dev->irq, dev); free_irq(dev->irq, dev);
...@@ -4069,8 +4245,8 @@ static int __init wavelan_config(device * dev) ...@@ -4069,8 +4245,8 @@ static int __init wavelan_config(device * dev)
#endif /* SET_MAC_ADDRESS */ #endif /* SET_MAC_ADDRESS */
#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */ #ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
dev->do_ioctl = wavelan_ioctl;
dev->get_wireless_stats = wavelan_get_wireless_stats; dev->get_wireless_stats = wavelan_get_wireless_stats;
dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
#endif #endif
dev->mtu = WAVELAN_MTU; dev->mtu = WAVELAN_MTU;
......
...@@ -345,6 +345,12 @@ ...@@ -345,6 +345,12 @@
* - Fix spinlock stupid bugs that I left in. The driver is now SMP * - Fix spinlock stupid bugs that I left in. The driver is now SMP
* compliant and doesn't lockup at startup. * compliant and doesn't lockup at startup.
* *
* Changes made for release in 2.5.2 :
* ---------------------------------
* - Use new driver API for Wireless Extensions :
* o got rid of wavelan_ioctl()
* o use a bunch of iw_handler instead
*
* Wishes & dreams: * Wishes & dreams:
* ---------------- * ----------------
* - roaming (see Pcmcia driver) * - roaming (see Pcmcia driver)
...@@ -379,6 +385,7 @@ ...@@ -379,6 +385,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/wireless.h> /* Wireless extensions */ #include <linux/wireless.h> /* Wireless extensions */
#include <net/iw_handler.h> /* Wireless handlers */
/* WaveLAN declarations */ /* WaveLAN declarations */
#include "i82586.h" #include "i82586.h"
...@@ -436,7 +443,7 @@ ...@@ -436,7 +443,7 @@
/************************ CONSTANTS & MACROS ************************/ /************************ CONSTANTS & MACROS ************************/
#ifdef DEBUG_VERSION_SHOW #ifdef DEBUG_VERSION_SHOW
static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/00\n"; static const char *version = "wavelan.c : v24 (SMP + wireless extensions) 11/12/01\n";
#endif #endif
/* Watchdog temporisation */ /* Watchdog temporisation */
...@@ -449,11 +456,9 @@ static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/ ...@@ -449,11 +456,9 @@ static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/
#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */ #define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set quality threshold */
#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */ #define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1 /* Get quality threshold */
#define SIOCSIPLTHR SIOCIWFIRSTPRIV + 2 /* Set level threshold */
#define SIOCGIPLTHR SIOCIWFIRSTPRIV + 3 /* Get level threshold */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */ #define SIOCSIPHISTO SIOCIWFIRSTPRIV + 2 /* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ #define SIOCGIPHISTO SIOCIWFIRSTPRIV + 3 /* Get histogram values */
/****************************** TYPES ******************************/ /****************************** TYPES ******************************/
...@@ -516,12 +521,6 @@ struct net_local ...@@ -516,12 +521,6 @@ struct net_local
/**************************** PROTOTYPES ****************************/ /**************************** PROTOTYPES ****************************/
/* ----------------------- MISC. SUBROUTINES ------------------------ */ /* ----------------------- MISC. SUBROUTINES ------------------------ */
static inline void
wv_splhi(net_local *, /* Disable interrupts, lock driver */
unsigned long *); /* flags */
static inline void
wv_splx(net_local *, /* Enable interrupts, unlock driver */
unsigned long *); /* flags */
static u_char static u_char
wv_irq_to_psa(int); wv_irq_to_psa(int);
static int static int
......
...@@ -64,34 +64,6 @@ ...@@ -64,34 +64,6 @@
* (wavelan modem or i82593) * (wavelan modem or i82593)
*/ */
/*------------------------------------------------------------------*/
/*
* Wrapper for disabling interrupts.
* (note : inline, so optimised away)
*/
static inline void
wv_splhi(net_local * lp,
unsigned long * pflags)
{
spin_lock_irqsave(&lp->spinlock, *pflags);
/* Note : above does the cli(); itself */
}
/*------------------------------------------------------------------*/
/*
* Wrapper for re-enabling interrupts.
*/
static inline void
wv_splx(net_local * lp,
unsigned long * pflags)
{
spin_unlock_irqrestore(&lp->spinlock, *pflags);
/* Note : enabling interrupts on the hardware is done in wv_ru_start()
* via : outb(OP1_INT_ENABLE, LCCR(base));
*/
}
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
* Wrapper for reporting error to cardservices * Wrapper for reporting error to cardservices
...@@ -591,7 +563,7 @@ void wv_nwid_filter(unsigned char mode, net_local *lp) ...@@ -591,7 +563,7 @@ void wv_nwid_filter(unsigned char mode, net_local *lp)
#endif #endif
/* Disable interrupts & save flags */ /* Disable interrupts & save flags */
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00; m.w.mmw_loopt_sel = (mode==NWID_PROMISC) ? MMW_LOOPT_SEL_DIS_NWID : 0x00;
mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1); mmc_write(lp->dev->base_addr, (char *)&m.w.mmw_loopt_sel - (char *)&m, (unsigned char *)&m.w.mmw_loopt_sel, 1);
...@@ -602,7 +574,7 @@ void wv_nwid_filter(unsigned char mode, net_local *lp) ...@@ -602,7 +574,7 @@ void wv_nwid_filter(unsigned char mode, net_local *lp)
lp->cell_search=0; lp->cell_search=0;
/* ReEnable interrupts & restore flags */ /* ReEnable interrupts & restore flags */
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
} }
/* Find a record in the WavePoint table matching a given NWID */ /* Find a record in the WavePoint table matching a given NWID */
...@@ -771,7 +743,7 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) ...@@ -771,7 +743,7 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
#endif #endif
/* Disable interrupts & save flags */ /* Disable interrupts & save flags */
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF; m.w.mmw_netw_id_l = wavepoint->nwid & 0xFF;
m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8; m.w.mmw_netw_id_h = (wavepoint->nwid & 0xFF00) >> 8;
...@@ -779,7 +751,7 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp) ...@@ -779,7 +751,7 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2); mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, (unsigned char *)&m.w.mmw_netw_id_l, 2);
/* ReEnable interrupts & restore flags */ /* ReEnable interrupts & restore flags */
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
wv_nwid_filter(!NWID_PROMISC,lp); wv_nwid_filter(!NWID_PROMISC,lp);
lp->curr_point=wavepoint; lp->curr_point=wavepoint;
...@@ -1049,9 +1021,9 @@ wv_82593_reconfig(device * dev) ...@@ -1049,9 +1021,9 @@ wv_82593_reconfig(device * dev)
/* Check if we can do it now ! */ /* Check if we can do it now ! */
if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev))) if((link->open) && (netif_running(dev)) && !(netif_queue_stopped(dev)))
{ {
wv_splhi(lp, &flags); /* Disable interrupts */ spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */
wv_82593_config(dev); wv_82593_config(dev);
wv_splx(lp, &flags); /* Re-enable interrupts */ spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */
} }
else else
{ {
...@@ -1179,7 +1151,7 @@ wv_mmc_show(device * dev) ...@@ -1179,7 +1151,7 @@ wv_mmc_show(device * dev)
return; return;
} }
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
/* Read the mmc */ /* Read the mmc */
mmc_out(base, mmwoff(0, mmw_freeze), 1); mmc_out(base, mmwoff(0, mmw_freeze), 1);
...@@ -1191,7 +1163,7 @@ wv_mmc_show(device * dev) ...@@ -1191,7 +1163,7 @@ wv_mmc_show(device * dev)
lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l; lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
#endif /* WIRELESS_EXT */ #endif /* WIRELESS_EXT */
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
printk(KERN_DEBUG "##### wavelan modem status registers: #####\n"); printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
#ifdef DEBUG_SHOW_UNUSED #ifdef DEBUG_SHOW_UNUSED
...@@ -1884,269 +1856,415 @@ wl_his_gather(device * dev, ...@@ -1884,269 +1856,415 @@ wl_his_gather(device * dev,
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
* Perform ioctl : config & info stuff * Wireless Handler : get protocol name
* This is here that are treated the wireless extensions (iwconfig)
*/ */
static int static int wavelan_get_name(struct net_device *dev,
wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ struct iw_request_info *info,
struct ifreq * rq, /* Data passed */ union iwreq_data *wrqu,
int cmd) /* Ioctl number */ char *extra)
{
strcpy(wrqu->name, "WaveLAN");
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set NWID
*/
static int wavelan_set_nwid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{ {
ioaddr_t base = dev->base_addr; ioaddr_t base = dev->base_addr;
net_local * lp = (net_local *)dev->priv; /* lp is not unused */ net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct iwreq * wrq = (struct iwreq *) rq;
psa_t psa; psa_t psa;
mm_t m; mm_t m;
unsigned long flags; unsigned long flags;
int ret = 0; int ret = 0;
#ifdef DEBUG_IOCTL_TRACE /* Disable interrupts and save flags. */
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd); spin_lock_irqsave(&lp->spinlock, flags);
#endif
/* Disable interrupts & save flags */
wv_splhi(lp, &flags);
/* Look what is the request */
switch(cmd)
{
/* --------------- WIRELESS EXTENSIONS --------------- */
case SIOCGIWNAME:
strcpy(wrq->u.name, "Wavelan");
break;
case SIOCSIWNWID: /* Set NWID in WaveLAN. */
/* Set NWID in wavelan */
#if WIRELESS_EXT > 8 #if WIRELESS_EXT > 8
if(!wrq->u.nwid.disabled) if (!wrqu->nwid.disabled) {
{
/* Set NWID in psa */ /* Set NWID in psa */
psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8; psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8;
psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF; psa.psa_nwid[1] = wrqu->nwid.value & 0xFF;
#else /* WIRELESS_EXT > 8 */ #else /* WIRELESS_EXT > 8 */
if(wrq->u.nwid.on) if(wrq->u.nwid.on) {
{
/* Set NWID in psa */ /* Set NWID in psa */
psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8; psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF; psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
#endif /* WIRELESS_EXT > 8 */ #endif /* WIRELESS_EXT > 8 */
psa.psa_nwid_select = 0x01; psa.psa_nwid_select = 0x01;
psa_write(dev, (char *)psa.psa_nwid - (char *)&psa, psa_write(dev,
(unsigned char *)psa.psa_nwid, 3); (char *) psa.psa_nwid - (char *) &psa,
(unsigned char *) psa.psa_nwid, 3);
/* Set NWID in mmc */ /* Set NWID in mmc. */
m.w.mmw_netw_id_l = psa.psa_nwid[1]; m.w.mmw_netw_id_l = psa.psa_nwid[1];
m.w.mmw_netw_id_h = psa.psa_nwid[0]; m.w.mmw_netw_id_h = psa.psa_nwid[0];
mmc_write(base, (char *)&m.w.mmw_netw_id_l - (char *)&m, mmc_write(base,
(unsigned char *)&m.w.mmw_netw_id_l, 2); (char *) &m.w.mmw_netw_id_l -
(char *) &m,
(unsigned char *) &m.w.mmw_netw_id_l, 2);
mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00); mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00);
} } else {
else /* Disable NWID in the psa. */
{
/* Disable nwid in the psa */
psa.psa_nwid_select = 0x00; psa.psa_nwid_select = 0x00;
psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa, psa_write(dev,
(unsigned char *)&psa.psa_nwid_select, 1); (char *) &psa.psa_nwid_select -
(char *) &psa,
(unsigned char *) &psa.psa_nwid_select,
1);
/* Disable nwid in the mmc (no filtering) */ /* Disable NWID in the mmc (no filtering). */
mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID); mmc_out(base, mmwoff(0, mmw_loopt_sel),
MMW_LOOPT_SEL_DIS_NWID);
} }
/* update the Wavelan checksum */ /* update the Wavelan checksum */
update_psa_checksum(dev); update_psa_checksum(dev);
break;
case SIOCGIWNWID: /* Enable interrupts and restore flags. */
/* Read the NWID */ spin_unlock_irqrestore(&lp->spinlock, flags);
psa_read(dev, (char *)psa.psa_nwid - (char *)&psa,
(unsigned char *)psa.psa_nwid, 3); return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get NWID
*/
static int wavelan_get_nwid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Read the NWID. */
psa_read(dev,
(char *) psa.psa_nwid - (char *) &psa,
(unsigned char *) psa.psa_nwid, 3);
#if WIRELESS_EXT > 8 #if WIRELESS_EXT > 8
wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrq->u.nwid.disabled = !(psa.psa_nwid_select); wrqu->nwid.disabled = !(psa.psa_nwid_select);
wrq->u.nwid.fixed = 1; /* Superfluous */ wrqu->nwid.fixed = 1; /* Superfluous */
#else /* WIRELESS_EXT > 8 */ #else /* WIRELESS_EXT > 8 */
wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1]; wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrq->u.nwid.on = psa.psa_nwid_select; wrq->u.nwid.on = psa.psa_nwid_select;
#endif /* WIRELESS_EXT > 8 */ #endif /* WIRELESS_EXT > 8 */
break;
case SIOCSIWFREQ: /* Enable interrupts and restore flags. */
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ spin_unlock_irqrestore(&lp->spinlock, flags);
if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set frequency
*/
static int wavelan_set_freq(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
int ret;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if (!(mmc_in(base, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) (MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
ret = wv_set_frequency(base, &(wrq->u.freq)); ret = wv_set_frequency(base, &(wrqu->freq));
else else
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break;
case SIOCGIWFREQ: /* Enable interrupts and restore flags. */
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) spin_unlock_irqrestore(&lp->spinlock, flags);
* (does it work for everybody ? - especially old cards...) */
if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
{
unsigned short freq;
/* Ask the EEprom to read the frequency from the first area */ return ret;
fee_read(base, 0x00 /* 1st area - frequency... */, }
&freq, 1);
wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrq->u.freq.e = 1;
}
else
{
psa_read(dev, (char *)&psa.psa_subband - (char *)&psa,
(unsigned char *)&psa.psa_subband, 1);
if(psa.psa_subband <= 4) /*------------------------------------------------------------------*/
{ /*
wrq->u.freq.m = fixed_bands[psa.psa_subband]; * Wireless Handler : get frequency
wrq->u.freq.e = (psa.psa_subband != 0); */
} static int wavelan_get_freq(struct net_device *dev,
else struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable).
* Does it work for everybody, especially old cards? */
if (!(mmc_in(base, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
unsigned short freq;
/* Ask the EEPROM to read the frequency from the first area. */
fee_read(base, 0x00, &freq, 1);
wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrqu->freq.e = 1;
} else {
psa_read(dev,
(char *) &psa.psa_subband - (char *) &psa,
(unsigned char *) &psa.psa_subband, 1);
if (psa.psa_subband <= 4) {
wrqu->freq.m = fixed_bands[psa.psa_subband];
wrqu->freq.e = (psa.psa_subband != 0);
} else
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
} }
break;
case SIOCSIWSENS: /* Enable interrupts and restore flags. */
/* Set the level threshold */ spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set level threshold
*/
static int wavelan_set_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Set the level threshold. */
#if WIRELESS_EXT > 7 #if WIRELESS_EXT > 7
/* We should complain loudly if wrq->u.sens.fixed = 0, because we /* We should complain loudly if wrqu->sens.fixed = 0, because we
* can't set auto mode... */ * can't set auto mode... */
psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F; psa.psa_thr_pre_set = wrqu->sens.value & 0x3F;
#else /* WIRELESS_EXT > 7 */ #else /* WIRELESS_EXT > 7 */
psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F; psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
#endif /* WIRELESS_EXT > 7 */ #endif /* WIRELESS_EXT > 7 */
psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa, psa_write(dev,
(unsigned char *)&psa.psa_thr_pre_set, 1); (char *) &psa.psa_thr_pre_set - (char *) &psa,
(unsigned char *) &psa.psa_thr_pre_set, 1);
/* update the Wavelan checksum */ /* update the Wavelan checksum */
update_psa_checksum(dev); update_psa_checksum(dev);
mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set); mmc_out(base, mmwoff(0, mmw_thr_pre_set),
break; psa.psa_thr_pre_set);
case SIOCGIWSENS: /* Enable interrupts and restore flags. */
/* Read the level threshold */ spin_unlock_irqrestore(&lp->spinlock, flags);
psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
(unsigned char *)&psa.psa_thr_pre_set, 1); return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get level threshold
*/
static int wavelan_get_sens(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Read the level threshold. */
psa_read(dev,
(char *) &psa.psa_thr_pre_set - (char *) &psa,
(unsigned char *) &psa.psa_thr_pre_set, 1);
#if WIRELESS_EXT > 7 #if WIRELESS_EXT > 7
wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F; wrqu->sens.value = psa.psa_thr_pre_set & 0x3F;
wrq->u.sens.fixed = 1; wrqu->sens.fixed = 1;
#else /* WIRELESS_EXT > 7 */ #else /* WIRELESS_EXT > 7 */
wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F; wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
#endif /* WIRELESS_EXT > 7 */ #endif /* WIRELESS_EXT > 7 */
break;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
#if WIRELESS_EXT > 8 #if WIRELESS_EXT > 8
case SIOCSIWENCODE: /*------------------------------------------------------------------*/
/* Set encryption key */ /*
if(!mmc_encr(base)) * Wireless Handler : set encryption key
{ */
static int wavelan_set_encode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
psa_t psa;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Check if capable of encryption */
if (!mmc_encr(base)) {
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
break;
} }
/* Basic checking... */
if(wrq->u.encoding.pointer != (caddr_t) 0)
{
/* Check the size of the key */ /* Check the size of the key */
if(wrq->u.encoding.length != 8) if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) {
{
ret = -EINVAL; ret = -EINVAL;
break;
} }
if(!ret) {
/* Basic checking... */
if (wrqu->encoding.length == 8) {
/* Copy the key in the driver */ /* Copy the key in the driver */
if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer, memcpy(psa.psa_encryption_key, extra,
wrq->u.encoding.length)) wrqu->encoding.length);
{
ret = -EFAULT;
break;
}
psa.psa_encryption_select = 1; psa.psa_encryption_select = 1;
psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
(unsigned char *) &psa.psa_encryption_select, 8+1); psa_write(dev,
(char *) &psa.psa_encryption_select -
(char *) &psa,
(unsigned char *) &psa.
psa_encryption_select, 8 + 1);
mmc_out(base, mmwoff(0, mmw_encr_enable), mmc_out(base, mmwoff(0, mmw_encr_enable),
MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE); MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
mmc_write(base, mmwoff(0, mmw_encr_key), mmc_write(base, mmwoff(0, mmw_encr_key),
(unsigned char *) &psa.psa_encryption_key, 8); (unsigned char *) &psa.
psa_encryption_key, 8);
} }
if(wrq->u.encoding.flags & IW_ENCODE_DISABLED) /* disable encryption */
{ /* disable encryption */ if (wrqu->encoding.flags & IW_ENCODE_DISABLED) {
psa.psa_encryption_select = 0; psa.psa_encryption_select = 0;
psa_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa, psa_write(dev,
(unsigned char *) &psa.psa_encryption_select, 1); (char *) &psa.psa_encryption_select -
(char *) &psa,
(unsigned char *) &psa.
psa_encryption_select, 1);
mmc_out(base, mmwoff(0, mmw_encr_enable), 0); mmc_out(base, mmwoff(0, mmw_encr_enable), 0);
} }
/* update the Wavelan checksum */ /* update the Wavelan checksum */
update_psa_checksum(dev); update_psa_checksum(dev);
break;
case SIOCGIWENCODE:
/* Read the encryption key */
if(!mmc_encr(base))
{
ret = -EOPNOTSUPP;
break;
} }
/* only super-user can see encryption key */ /* Enable interrupts and restore flags. */
if(!capable(CAP_NET_ADMIN)) spin_unlock_irqrestore(&lp->spinlock, flags);
{
ret = -EPERM;
break;
}
/* Basic checking... */ return ret;
if(wrq->u.encoding.pointer != (caddr_t) 0) }
{
psa_read(dev, (char *) &psa.psa_encryption_select - (char *) &psa, /*------------------------------------------------------------------*/
(unsigned char *) &psa.psa_encryption_select, 1+8); /*
* Wireless Handler : get encryption key
*/
static int wavelan_get_encode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Check if encryption is available */
if (!mmc_encr(base)) {
ret = -EOPNOTSUPP;
} else {
/* Read the encryption key */
psa_read(dev,
(char *) &psa.psa_encryption_select -
(char *) &psa,
(unsigned char *) &psa.
psa_encryption_select, 1 + 8);
/* encryption is enabled ? */ /* encryption is enabled ? */
if(psa.psa_encryption_select) if (psa.psa_encryption_select)
wrq->u.encoding.flags = IW_ENCODE_ENABLED; wrqu->encoding.flags = IW_ENCODE_ENABLED;
else else
wrq->u.encoding.flags = IW_ENCODE_DISABLED; wrqu->encoding.flags = IW_ENCODE_DISABLED;
wrq->u.encoding.flags |= mmc_encr(base); wrqu->encoding.flags |= mmc_encr(base);
/* Copy the key to the user buffer */ /* Copy the key to the user buffer */
wrq->u.encoding.length = 8; wrqu->encoding.length = 8;
if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8)) memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length);
ret = -EFAULT;
} }
break;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
#endif /* WIRELESS_EXT > 8 */ #endif /* WIRELESS_EXT > 8 */
#ifdef WAVELAN_ROAMING_EXT #ifdef WAVELAN_ROAMING_EXT
#if WIRELESS_EXT > 5 #if WIRELESS_EXT > 5
case SIOCSIWESSID: /*------------------------------------------------------------------*/
/*
* Wireless Handler : set ESSID (domain)
*/
static int wavelan_set_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Check if disable */ /* Check if disable */
if(wrq->u.data.flags == 0) if(wrqu->data.flags == 0)
lp->filter_domains = 0; lp->filter_domains = 0;
else else {
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0)
{
char essid[IW_ESSID_MAX_SIZE + 1]; char essid[IW_ESSID_MAX_SIZE + 1];
char * endp; char * endp;
/* Check the size of the string */ /* Terminate the string */
if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1) memcpy(essid, extra, wrqu->data.length);
{
ret = -E2BIG;
break;
}
/* Copy the string in the driver */
if(copy_from_user(essid, wrq->u.data.pointer, wrq->u.data.length))
{
ret = -EFAULT;
break;
}
essid[IW_ESSID_MAX_SIZE] = '\0'; essid[IW_ESSID_MAX_SIZE] = '\0';
#ifdef DEBUG_IOCTL_INFO #ifdef DEBUG_IOCTL_INFO
...@@ -2158,76 +2276,111 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ ...@@ -2158,76 +2276,111 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
/* Has it worked ? */ /* Has it worked ? */
if(endp > essid) if(endp > essid)
lp->filter_domains = 1; lp->filter_domains = 1;
else else {
{
lp->filter_domains = 0; lp->filter_domains = 0;
ret = -EINVAL; ret = -EINVAL;
} }
} }
break;
case SIOCGIWESSID: /* Enable interrupts and restore flags. */
/* Basic checking... */ spin_unlock_irqrestore(&lp->spinlock, flags);
if(wrq->u.data.pointer != (caddr_t) 0)
{ return ret;
char essid[IW_ESSID_MAX_SIZE + 1]; }
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get ESSID (domain)
*/
static int wavelan_get_essid(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
/* Is the domain ID active ? */ /* Is the domain ID active ? */
wrq->u.data.flags = lp->filter_domains; wrqu->data.flags = lp->filter_domains;
/* Copy Domain ID into a string (Wavelan specific) */ /* Copy Domain ID into a string (Wavelan specific) */
/* Sound crazy, be we can't have a snprintf in the kernel !!! */ /* Sound crazy, be we can't have a snprintf in the kernel !!! */
sprintf(essid, "%lX", lp->domain_id); sprintf(extra, "%lX", lp->domain_id);
essid[IW_ESSID_MAX_SIZE] = '\0'; extra[IW_ESSID_MAX_SIZE] = '\0';
/* Set the length */ /* Set the length */
wrq->u.data.length = strlen(essid) + 1; wrqu->data.length = strlen(extra) + 1;
/* Copy structure to the user buffer */ return 0;
if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length)) }
ret = -EFAULT;
}
break;
case SIOCSIWAP: /*------------------------------------------------------------------*/
/*
* Wireless Handler : set AP address
*/
static int wavelan_set_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
#ifdef DEBUG_IOCTL_INFO #ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n", printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
wrq->u.ap_addr.sa_data[0], wrqu->ap_addr.sa_data[0],
wrq->u.ap_addr.sa_data[1], wrqu->ap_addr.sa_data[1],
wrq->u.ap_addr.sa_data[2], wrqu->ap_addr.sa_data[2],
wrq->u.ap_addr.sa_data[3], wrqu->ap_addr.sa_data[3],
wrq->u.ap_addr.sa_data[4], wrqu->ap_addr.sa_data[4],
wrq->u.ap_addr.sa_data[5]); wrqu->ap_addr.sa_data[5]);
#endif /* DEBUG_IOCTL_INFO */ #endif /* DEBUG_IOCTL_INFO */
ret = -EOPNOTSUPP; /* Not supported yet */ return -EOPNOTSUPP;
break; }
case SIOCGIWAP: /*------------------------------------------------------------------*/
/*
* Wireless Handler : get AP address
*/
static int wavelan_get_wap(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
/* Should get the real McCoy instead of own Ethernet address */ /* Should get the real McCoy instead of own Ethernet address */
memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE); memcpy(wrqu->ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE);
wrq->u.ap_addr.sa_family = ARPHRD_ETHER; wrqu->ap_addr.sa_family = ARPHRD_ETHER;
ret = -EOPNOTSUPP; /* Not supported yet */ return -EOPNOTSUPP;
break; }
#endif /* WIRELESS_EXT > 5 */ #endif /* WIRELESS_EXT > 5 */
#endif /* WAVELAN_ROAMING_EXT */ #endif /* WAVELAN_ROAMING_EXT */
#if WIRELESS_EXT > 8 #if WIRELESS_EXT > 8
#ifdef WAVELAN_ROAMING #ifdef WAVELAN_ROAMING
case SIOCSIWMODE: /*------------------------------------------------------------------*/
switch(wrq->u.mode) /*
{ * Wireless Handler : set mode
*/
static int wavelan_set_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
int ret = 0;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Check mode */
switch(wrqu->mode) {
case IW_MODE_ADHOC: case IW_MODE_ADHOC:
if(do_roaming) if(do_roaming) {
{
wv_roam_cleanup(dev); wv_roam_cleanup(dev);
do_roaming = 0; do_roaming = 0;
} }
break; break;
case IW_MODE_INFRA: case IW_MODE_INFRA:
if(!do_roaming) if(!do_roaming) {
{
wv_roam_init(dev); wv_roam_init(dev);
do_roaming = 1; do_roaming = 1;
} }
...@@ -2235,206 +2388,702 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ ...@@ -2235,206 +2388,702 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
default: default:
ret = -EINVAL; ret = -EINVAL;
} }
break;
case SIOCGIWMODE: /* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get mode
*/
static int wavelan_get_mode(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
if(do_roaming) if(do_roaming)
wrq->u.mode = IW_MODE_INFRA; wrqu->mode = IW_MODE_INFRA;
else else
wrq->u.mode = IW_MODE_ADHOC; wrqu->mode = IW_MODE_ADHOC;
break;
return 0;
}
#endif /* WAVELAN_ROAMING */ #endif /* WAVELAN_ROAMING */
#endif /* WIRELESS_EXT > 8 */ #endif /* WIRELESS_EXT > 8 */
case SIOCGIWRANGE: /*------------------------------------------------------------------*/
/* Basic checking... */ /*
if(wrq->u.data.pointer != (caddr_t) 0) * Wireless Handler : get range info
{ */
struct iw_range range; static int wavelan_get_range(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct iw_range *range = (struct iw_range *) extra;
unsigned long flags;
int ret = 0;
/* Set the length (very important for backward compatibility) */ /* Set the length (very important for backward compatibility) */
wrq->u.data.length = sizeof(struct iw_range); wrqu->data.length = sizeof(struct iw_range);
/* Set all the info we don't care or don't know about to zero */ /* Set all the info we don't care or don't know about to zero */
memset(&range, 0, sizeof(range)); memset(range, 0, sizeof(struct iw_range));
#if WIRELESS_EXT > 10 #if WIRELESS_EXT > 10
/* Set the Wireless Extension versions */ /* Set the Wireless Extension versions */
range.we_version_compiled = WIRELESS_EXT; range->we_version_compiled = WIRELESS_EXT;
range.we_version_source = 9; /* Nothing for us in v10 and v11 */ range->we_version_source = 9;
#endif /* WIRELESS_EXT > 10 */ #endif /* WIRELESS_EXT > 10 */
/* Set information in the range struct */ /* Set information in the range struct. */
range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */ range->throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */
range.min_nwid = 0x0000; range->min_nwid = 0x0000;
range.max_nwid = 0xFFFF; range->max_nwid = 0xFFFF;
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */ range->sensitivity = 0x3F;
if(!(mmc_in(base, mmroff(0, mmr_fee_status)) & range->max_qual.qual = MMR_SGNL_QUAL;
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) range->max_qual.level = MMR_SIGNAL_LVL;
{ range->max_qual.noise = MMR_SILENCE_LVL;
range.num_channels = 10;
range.num_frequency = wv_frequency_list(base, range.freq,
IW_MAX_FREQUENCIES);
}
else
range.num_channels = range.num_frequency = 0;
range.sensitivity = 0x3F;
range.max_qual.qual = MMR_SGNL_QUAL;
range.max_qual.level = MMR_SIGNAL_LVL;
range.max_qual.noise = MMR_SILENCE_LVL;
#if WIRELESS_EXT > 11 #if WIRELESS_EXT > 11
range.avg_qual.qual = MMR_SGNL_QUAL; /* Always max */ range->avg_qual.qual = MMR_SGNL_QUAL; /* Always max */
/* Need to get better values for those two */ /* Need to get better values for those two */
range.avg_qual.level = 30; range->avg_qual.level = 30;
range.avg_qual.noise = 8; range->avg_qual.noise = 8;
#endif /* WIRELESS_EXT > 11 */ #endif /* WIRELESS_EXT > 11 */
#if WIRELESS_EXT > 7 #if WIRELESS_EXT > 7
range.num_bitrates = 1; range->num_bitrates = 1;
range.bitrate[0] = 2000000; /* 2 Mb/s */ range->bitrate[0] = 2000000; /* 2 Mb/s */
#endif /* WIRELESS_EXT > 7 */ #endif /* WIRELESS_EXT > 7 */
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable). */
if (!(mmc_in(base, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
range->num_channels = 10;
range->num_frequency = wv_frequency_list(base, range->freq,
IW_MAX_FREQUENCIES);
} else
range->num_channels = range->num_frequency = 0;
#if WIRELESS_EXT > 8 #if WIRELESS_EXT > 8
/* Encryption supported ? */ /* Encryption supported ? */
if(mmc_encr(base)) if (mmc_encr(base)) {
{ range->encoding_size[0] = 8; /* DES = 64 bits key */
range.encoding_size[0] = 8; /* DES = 64 bits key */ range->num_encoding_sizes = 1;
range.num_encoding_sizes = 1; range->max_encoding_tokens = 1; /* Only one key possible */
range.max_encoding_tokens = 1; /* Only one key possible */ } else {
} range->num_encoding_sizes = 0;
else range->max_encoding_tokens = 0;
{
range.num_encoding_sizes = 0;
range.max_encoding_tokens = 0;
} }
#endif /* WIRELESS_EXT > 8 */ #endif /* WIRELESS_EXT > 8 */
/* Copy structure to the user buffer */ /* Enable interrupts and restore flags. */
if(copy_to_user(wrq->u.data.pointer, &range, spin_unlock_irqrestore(&lp->spinlock, flags);
sizeof(struct iw_range)))
ret = -EFAULT; return ret;
}
#ifdef WIRELESS_SPY
/*------------------------------------------------------------------*/
/*
* Wireless Handler : set spy list
*/
static int wavelan_set_spy(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct sockaddr *address = (struct sockaddr *) extra;
int i;
int ret = 0;
/* Disable spy while we copy the addresses.
* As we don't disable interrupts, we need to do this */
lp->spy_number = 0;
/* Are there are addresses to copy? */
if (wrqu->data.length > 0) {
/* Copy addresses to the lp structure. */
for (i = 0; i < wrqu->data.length; i++) {
memcpy(lp->spy_address[i], address[i].sa_data,
WAVELAN_ADDR_SIZE);
} }
break;
case SIOCGIWPRIV: /* Reset structure. */
/* Basic checking... */ memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
if(wrq->u.data.pointer != (caddr_t) 0)
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG
"SetSpy: set of new addresses is: \n");
for (i = 0; i < wrqu->data.length; i++)
printk(KERN_DEBUG
"%02X:%02X:%02X:%02X:%02X:%02X \n",
lp->spy_address[i][0],
lp->spy_address[i][1],
lp->spy_address[i][2],
lp->spy_address[i][3],
lp->spy_address[i][4],
lp->spy_address[i][5]);
#endif /* DEBUG_IOCTL_INFO */
}
/* Now we can set the number of addresses */
lp->spy_number = wrqu->data.length;
return ret;
}
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get spy list
*/
static int wavelan_get_spy(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
struct sockaddr *address = (struct sockaddr *) extra;
int i;
/* Set the number of addresses */
wrqu->data.length = lp->spy_number;
/* Copy addresses from the lp structure. */
for (i = 0; i < lp->spy_number; i++) {
memcpy(address[i].sa_data,
lp->spy_address[i],
WAVELAN_ADDR_SIZE);
address[i].sa_family = AF_UNIX;
}
/* Copy stats to the user buffer (just after). */
if(lp->spy_number > 0)
memcpy(extra + (sizeof(struct sockaddr) * lp->spy_number),
lp->spy_stat, sizeof(iw_qual) * lp->spy_number);
/* Reset updated flags. */
for (i = 0; i < lp->spy_number; i++)
lp->spy_stat[i].updated = 0x0;
return(0);
}
#endif /* WIRELESS_SPY */
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set quality threshold
*/
static int wavelan_set_qthr(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
ioaddr_t base = dev->base_addr;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
psa.psa_quality_thr = *(extra) & 0x0F;
psa_write(dev,
(char *) &psa.psa_quality_thr - (char *) &psa,
(unsigned char *) &psa.psa_quality_thr, 1);
/* update the Wavelan checksum */
update_psa_checksum(dev);
mmc_out(base, mmwoff(0, mmw_quality_thr),
psa.psa_quality_thr);
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get quality threshold
*/
static int wavelan_get_qthr(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
unsigned long flags;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
psa_read(dev,
(char *) &psa.psa_quality_thr - (char *) &psa,
(unsigned char *) &psa.psa_quality_thr, 1);
*(extra) = psa.psa_quality_thr & 0x0F;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return 0;
}
#ifdef WAVELAN_ROAMING
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set roaming
*/
static int wavelan_set_roam(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
unsigned long flags;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
/* Note : should check if user == root */
if(do_roaming && (*extra)==0)
wv_roam_cleanup(dev);
else if(do_roaming==0 && (*extra)!=0)
wv_roam_init(dev);
do_roaming = (*extra);
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return 0;
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get quality threshold
*/
static int wavelan_get_roam(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
*(extra) = do_roaming;
return 0;
}
#endif /* WAVELAN_ROAMING */
#ifdef HISTOGRAM
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : set histogram
*/
static int wavelan_set_histo(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
/* Check the number of intervals. */
if (wrqu->data.length > 16) {
return(-E2BIG);
}
/* Disable histo while we copy the addresses.
* As we don't disable interrupts, we need to do this */
lp->his_number = 0;
/* Are there ranges to copy? */
if (wrqu->data.length > 0) {
/* Copy interval ranges to the driver */
memcpy(lp->his_range, extra, wrqu->data.length);
{ {
struct iw_priv_args priv[] = int i;
{ /* cmd, set_args, get_args, name */ printk(KERN_DEBUG "Histo :");
for(i = 0; i < wrqu->data.length; i++)
printk(" %d", lp->his_range[i]);
printk("\n");
}
/* Reset result structure. */
memset(lp->his_sum, 0x00, sizeof(long) * 16);
}
/* Now we can set the number of ranges */
lp->his_number = wrqu->data.length;
return(0);
}
/*------------------------------------------------------------------*/
/*
* Wireless Private Handler : get histogram
*/
static int wavelan_get_histo(struct net_device *dev,
struct iw_request_info *info,
union iwreq_data *wrqu,
char *extra)
{
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
/* Set the number of intervals. */
wrqu->data.length = lp->his_number;
/* Give back the distribution statistics */
if(lp->his_number > 0)
memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number);
return(0);
}
#endif /* HISTOGRAM */
/*------------------------------------------------------------------*/
/*
* Structures to export the Wireless Handlers
*/
static const struct iw_priv_args wavelan_private_args[] = {
/*{ cmd, set_args, get_args, name } */
{ SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" }, { SIOCSIPQTHR, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setqualthr" },
{ SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" }, { SIOCGIPQTHR, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getqualthr" },
{ SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "setroam" },
{ SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" },
{ SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" }, { SIOCSIPHISTO, IW_PRIV_TYPE_BYTE | 16, 0, "sethisto" },
{ SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" }, { SIOCGIPHISTO, 0, IW_PRIV_TYPE_INT | 16, "gethisto" },
{ SIOCSIPROAM, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1 , 0, "setroam" }, };
{ SIOCGIPROAM, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "getroam" },
};
/* Set the number of ioctl available */ #if WIRELESS_EXT > 12
wrq->u.data.length = 6;
/* Copy structure to the user buffer */ static const iw_handler wavelan_handler[] =
if(copy_to_user(wrq->u.data.pointer, (u_char *) priv, {
sizeof(priv))) NULL, /* SIOCSIWNAME */
ret = -EFAULT; wavelan_get_name, /* SIOCGIWNAME */
} wavelan_set_nwid, /* SIOCSIWNWID */
wavelan_get_nwid, /* SIOCGIWNWID */
wavelan_set_freq, /* SIOCSIWFREQ */
wavelan_get_freq, /* SIOCGIWFREQ */
#ifdef WAVELAN_ROAMING
wavelan_set_mode, /* SIOCSIWMODE */
wavelan_get_mode, /* SIOCGIWMODE */
#else /* WAVELAN_ROAMING */
NULL, /* SIOCSIWMODE */
NULL, /* SIOCGIWMODE */
#endif /* WAVELAN_ROAMING */
wavelan_set_sens, /* SIOCSIWSENS */
wavelan_get_sens, /* SIOCGIWSENS */
NULL, /* SIOCSIWRANGE */
wavelan_get_range, /* SIOCGIWRANGE */
NULL, /* SIOCSIWPRIV */
NULL, /* SIOCGIWPRIV */
NULL, /* SIOCSIWSTATS */
NULL, /* SIOCGIWSTATS */
#ifdef WIRELESS_SPY
wavelan_set_spy, /* SIOCSIWSPY */
wavelan_get_spy, /* SIOCGIWSPY */
#else /* WIRELESS_SPY */
NULL, /* SIOCSIWSPY */
NULL, /* SIOCGIWSPY */
#endif /* WIRELESS_SPY */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
#ifdef WAVELAN_ROAMING_EXT
wavelan_set_wap, /* SIOCSIWAP */
wavelan_get_wap, /* SIOCGIWAP */
NULL, /* -- hole -- */
NULL, /* SIOCGIWAPLIST */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
wavelan_set_essid, /* SIOCSIWESSID */
wavelan_get_essid, /* SIOCGIWESSID */
#else /* WAVELAN_ROAMING_EXT */
NULL, /* SIOCSIWAP */
NULL, /* SIOCGIWAP */
NULL, /* -- hole -- */
NULL, /* SIOCGIWAPLIST */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWESSID */
NULL, /* SIOCGIWESSID */
#endif /* WAVELAN_ROAMING_EXT */
#if WIRELESS_EXT > 8
NULL, /* SIOCSIWNICKN */
NULL, /* SIOCGIWNICKN */
NULL, /* -- hole -- */
NULL, /* -- hole -- */
NULL, /* SIOCSIWRATE */
NULL, /* SIOCGIWRATE */
NULL, /* SIOCSIWRTS */
NULL, /* SIOCGIWRTS */
NULL, /* SIOCSIWFRAG */
NULL, /* SIOCGIWFRAG */
NULL, /* SIOCSIWTXPOW */
NULL, /* SIOCGIWTXPOW */
NULL, /* SIOCSIWRETRY */
NULL, /* SIOCGIWRETRY */
wavelan_set_encode, /* SIOCSIWENCODE */
wavelan_get_encode, /* SIOCGIWENCODE */
#endif /* WIRELESS_EXT > 8 */
};
static const iw_handler wavelan_private_handler[] =
{
wavelan_set_qthr, /* SIOCIWFIRSTPRIV */
wavelan_get_qthr, /* SIOCIWFIRSTPRIV + 1 */
#ifdef WAVELAN_ROAMING
wavelan_set_roam, /* SIOCIWFIRSTPRIV + 2 */
wavelan_get_roam, /* SIOCIWFIRSTPRIV + 3 */
#else /* WAVELAN_ROAMING */
NULL, /* SIOCIWFIRSTPRIV + 2 */
NULL, /* SIOCIWFIRSTPRIV + 3 */
#endif /* WAVELAN_ROAMING */
#ifdef HISTOGRAM
wavelan_set_histo, /* SIOCIWFIRSTPRIV + 4 */
wavelan_get_histo, /* SIOCIWFIRSTPRIV + 5 */
#endif /* HISTOGRAM */
};
static const struct iw_handler_def wavelan_handler_def =
{
num_standard: sizeof(wavelan_handler)/sizeof(iw_handler),
num_private: sizeof(wavelan_private_handler)/sizeof(iw_handler),
num_private_args: sizeof(wavelan_private_args)/sizeof(struct iw_priv_args),
standard: (iw_handler *) wavelan_handler,
private: (iw_handler *) wavelan_private_handler,
private_args: (struct iw_priv_args *) wavelan_private_args,
};
#else /* WIRELESS_EXT > 12 */
/*------------------------------------------------------------------*/
/*
* Perform ioctl : config & info stuff
* This is here that are treated the wireless extensions (iwconfig)
*/
static int
wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
struct ifreq * rq, /* Data passed */
int cmd) /* Ioctl number */
{
struct iwreq * wrq = (struct iwreq *) rq;
int ret = 0;
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
#endif
/* Look what is the request */
switch(cmd)
{
/* --------------- WIRELESS EXTENSIONS --------------- */
case SIOCGIWNAME:
wavelan_get_name(dev, NULL, &(wrq->u), NULL);
break; break;
#ifdef WIRELESS_SPY case SIOCSIWNWID:
case SIOCSIWSPY: ret = wavelan_set_nwid(dev, NULL, &(wrq->u), NULL);
/* Set the spy list */ break;
/* Check the number of addresses */ case SIOCGIWNWID:
if(wrq->u.data.length > IW_MAX_SPY) ret = wavelan_get_nwid(dev, NULL, &(wrq->u), NULL);
break;
case SIOCSIWFREQ:
ret = wavelan_set_freq(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIWFREQ:
ret = wavelan_get_freq(dev, NULL, &(wrq->u), NULL);
break;
case SIOCSIWSENS:
ret = wavelan_set_sens(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIWSENS:
ret = wavelan_get_sens(dev, NULL, &(wrq->u), NULL);
break;
#if WIRELESS_EXT > 8
case SIOCSIWENCODE:
{ {
ret = -E2BIG; char keybuf[8];
if (wrq->u.encoding.pointer) {
/* We actually have a key to set */
if (wrq->u.encoding.length != 8) {
ret = -EINVAL;
break;
}
if (copy_from_user(keybuf,
wrq->u.encoding.pointer,
wrq->u.encoding.length)) {
ret = -EFAULT;
break; break;
} }
lp->spy_number = wrq->u.data.length; } else if (wrq->u.encoding.length != 0) {
ret = -EINVAL;
break;
}
ret = wavelan_set_encode(dev, NULL, &(wrq->u), keybuf);
}
break;
/* If there is some addresses to copy */ case SIOCGIWENCODE:
if(lp->spy_number > 0) if (! capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
{ {
struct sockaddr address[IW_MAX_SPY]; char keybuf[8];
int i; ret = wavelan_get_encode(dev, NULL,
&(wrq->u),
keybuf);
if (wrq->u.encoding.pointer) {
if (copy_to_user(wrq->u.encoding.pointer,
keybuf,
wrq->u.encoding.length))
ret = -EFAULT;
}
}
break;
#endif /* WIRELESS_EXT > 8 */
/* Copy addresses to the driver */ #ifdef WAVELAN_ROAMING_EXT
if(copy_from_user(address, wrq->u.data.pointer, #if WIRELESS_EXT > 5
sizeof(struct sockaddr) * lp->spy_number)) case SIOCSIWESSID:
{ {
char essidbuf[IW_ESSID_MAX_SIZE+1];
if (wrq->u.essid.length > IW_ESSID_MAX_SIZE) {
ret = -E2BIG;
break;
}
if (copy_from_user(essidbuf, wrq->u.essid.pointer,
wrq->u.essid.length)) {
ret = -EFAULT; ret = -EFAULT;
break; break;
} }
ret = wavelan_set_essid(dev, NULL,
&(wrq->u),
essidbuf);
}
break;
/* Copy addresses to the lp structure */ case SIOCGIWESSID:
for(i = 0; i < lp->spy_number; i++)
{ {
memcpy(lp->spy_address[i], address[i].sa_data, char essidbuf[IW_ESSID_MAX_SIZE+1];
WAVELAN_ADDR_SIZE); ret = wavelan_get_essid(dev, NULL,
&(wrq->u),
essidbuf);
if (wrq->u.essid.pointer)
if ( copy_to_user(wrq->u.essid.pointer,
essidbuf,
wrq->u.essid.length) )
ret = -EFAULT;
} }
break;
/* Reset structure... */ case SIOCSIWAP:
memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY); ret = wavelan_set_wap(dev, NULL, &(wrq->u), NULL);
break;
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG "SetSpy - Set of new addresses is :\n");
for(i = 0; i < wrq->u.data.length; i++)
printk(KERN_DEBUG "%02X:%02X:%02X:%02X:%02X:%02X\n",
lp->spy_address[i][0],
lp->spy_address[i][1],
lp->spy_address[i][2],
lp->spy_address[i][3],
lp->spy_address[i][4],
lp->spy_address[i][5]);
#endif /* DEBUG_IOCTL_INFO */
}
case SIOCGIWAP:
ret = wavelan_get_wap(dev, NULL, &(wrq->u), NULL);
break; break;
#endif /* WIRELESS_EXT > 5 */
#endif /* WAVELAN_ROAMING_EXT */
case SIOCGIWSPY: #if WIRELESS_EXT > 8
/* Get the spy list and spy stats */ #ifdef WAVELAN_ROAMING
case SIOCSIWMODE:
ret = wavelan_set_mode(dev, NULL, &(wrq->u), NULL);
break;
/* Set the number of addresses */ case SIOCGIWMODE:
wrq->u.data.length = lp->spy_number; ret = wavelan_get_mode(dev, NULL, &(wrq->u), NULL);
break;
#endif /* WAVELAN_ROAMING */
#endif /* WIRELESS_EXT > 8 */
/* If the user want to have the addresses back... */ case SIOCGIWRANGE:
if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
{ {
struct sockaddr address[IW_MAX_SPY]; struct iw_range range;
int i; ret = wavelan_get_range(dev, NULL,
&(wrq->u),
(char *) &range);
if (copy_to_user(wrq->u.data.pointer, &range,
sizeof(struct iw_range)))
ret = -EFAULT;
}
break;
/* Copy addresses from the lp structure */ case SIOCGIWPRIV:
for(i = 0; i < lp->spy_number; i++) /* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0)
{ {
memcpy(address[i].sa_data, lp->spy_address[i], /* Set the number of ioctl available */
WAVELAN_ADDR_SIZE); wrq->u.data.length = sizeof(wavelan_private_args) / sizeof(wavelan_private_args[0]);
address[i].sa_family = ARPHRD_ETHER;
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, (u_char *) wavelan_private_args,
sizeof(wavelan_private_args)))
ret = -EFAULT;
} }
break;
/* Copy addresses to the user buffer */ #ifdef WIRELESS_SPY
if(copy_to_user(wrq->u.data.pointer, address, case SIOCSIWSPY:
sizeof(struct sockaddr) * lp->spy_number))
{ {
struct sockaddr address[IW_MAX_SPY];
/* Check the number of addresses */
if (wrq->u.data.length > IW_MAX_SPY) {
ret = -E2BIG;
break;
}
/* Get the data in the driver */
if (wrq->u.data.pointer) {
if (copy_from_user((char *) address,
wrq->u.data.pointer,
sizeof(struct sockaddr) *
wrq->u.data.length)) {
ret = -EFAULT; ret = -EFAULT;
break; break;
} }
} else if (wrq->u.data.length != 0) {
ret = -EINVAL;
break;
}
ret = wavelan_set_spy(dev, NULL, &(wrq->u),
(char *) address);
}
break;
/* Copy stats to the user buffer (just after) */ case SIOCGIWSPY:
if(copy_to_user(wrq->u.data.pointer +
(sizeof(struct sockaddr) * lp->spy_number),
lp->spy_stat, sizeof(iw_qual) * lp->spy_number))
{ {
char buffer[IW_MAX_SPY * (sizeof(struct sockaddr) +
sizeof(struct iw_quality))];
ret = wavelan_get_spy(dev, NULL, &(wrq->u),
buffer);
if (wrq->u.data.pointer) {
if (copy_to_user(wrq->u.data.pointer,
buffer,
(wrq->u.data.length *
(sizeof(struct sockaddr) +
sizeof(struct iw_quality)))
))
ret = -EFAULT; ret = -EFAULT;
break;
} }
}
/* Reset updated flags */
for(i = 0; i < lp->spy_number; i++)
lp->spy_stat[i].updated = 0x0;
} /* if(pointer != NULL) */
break; break;
#endif /* WIRELESS_SPY */ #endif /* WIRELESS_SPY */
...@@ -2446,34 +3095,21 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ ...@@ -2446,34 +3095,21 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
ret = -EPERM; ret = -EPERM;
break; break;
} }
psa.psa_quality_thr = *(wrq->u.name) & 0x0F; ret = wavelan_set_qthr(dev, NULL, &(wrq->u), NULL);
psa_write(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
(unsigned char *)&psa.psa_quality_thr, 1);
/* update the Wavelan checksum */
update_psa_checksum(dev);
mmc_out(base, mmwoff(0, mmw_quality_thr), psa.psa_quality_thr);
break; break;
case SIOCGIPQTHR: case SIOCGIPQTHR:
psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa, ret = wavelan_get_qthr(dev, NULL, &(wrq->u), NULL);
(unsigned char *)&psa.psa_quality_thr, 1);
*(wrq->u.name) = psa.psa_quality_thr & 0x0F;
break; break;
#ifdef WAVELAN_ROAMING #ifdef WAVELAN_ROAMING
case SIOCSIPROAM: case SIOCSIPROAM:
/* Note : should check if user == root */ /* Note : should check if user == root */
if(do_roaming && (*wrq->u.name)==0) ret = wavelan_set_roam(dev, NULL, &(wrq->u), NULL);
wv_roam_cleanup(dev);
else if(do_roaming==0 && (*wrq->u.name)!=0)
wv_roam_init(dev);
do_roaming = (*wrq->u.name);
break; break;
case SIOCGIPROAM: case SIOCGIPROAM:
*(wrq->u.name) = do_roaming; ret = wavelan_get_roam(dev, NULL, &(wrq->u), NULL);
break; break;
#endif /* WAVELAN_ROAMING */ #endif /* WAVELAN_ROAMING */
...@@ -2484,44 +3120,44 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ ...@@ -2484,44 +3120,44 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
{ {
ret = -EPERM; ret = -EPERM;
} }
{
char buffer[16];
/* Check the number of intervals */ /* Check the number of intervals */
if(wrq->u.data.length > 16) if(wrq->u.data.length > 16)
{ {
ret = -E2BIG; ret = -E2BIG;
break; break;
} }
lp->his_number = wrq->u.data.length; /* Get the data in the driver */
if (wrq->u.data.pointer) {
/* If there is some addresses to copy */ if (copy_from_user(buffer,
if(lp->his_number > 0) wrq->u.data.pointer,
{ sizeof(struct sockaddr) *
/* Copy interval ranges to the driver */ wrq->u.data.length)) {
if(copy_from_user(lp->his_range, wrq->u.data.pointer,
sizeof(char) * lp->his_number))
{
ret = -EFAULT; ret = -EFAULT;
break; break;
} }
} else if (wrq->u.data.length != 0) {
/* Reset structure... */ ret = -EINVAL;
memset(lp->his_sum, 0x00, sizeof(long) * 16); break;
}
ret = wavelan_set_histo(dev, NULL, &(wrq->u),
buffer);
} }
break; break;
case SIOCGIPHISTO: case SIOCGIPHISTO:
/* Set the number of intervals */
wrq->u.data.length = lp->his_number;
/* Give back the distribution statistics */
if((lp->his_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
{ {
/* Copy data to the user buffer */ long buffer[16];
if(copy_to_user(wrq->u.data.pointer, lp->his_sum, ret = wavelan_get_histo(dev, NULL, &(wrq->u),
sizeof(long) * lp->his_number)) (char *) buffer);
if (wrq->u.data.pointer) {
if (copy_to_user(wrq->u.data.pointer,
buffer,
(wrq->u.data.length * sizeof(long))))
ret = -EFAULT; ret = -EFAULT;
}
} /* if(pointer != NULL) */ }
break; break;
#endif /* HISTOGRAM */ #endif /* HISTOGRAM */
...@@ -2531,14 +3167,12 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */ ...@@ -2531,14 +3167,12 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
ret = -EOPNOTSUPP; ret = -EOPNOTSUPP;
} }
/* ReEnable interrupts & restore flags */
wv_splx(lp, &flags);
#ifdef DEBUG_IOCTL_TRACE #ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name); printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
#endif #endif
return ret; return ret;
} }
#endif /* WIRELESS_EXT > 12 */
/*------------------------------------------------------------------*/ /*------------------------------------------------------------------*/
/* /*
...@@ -2559,7 +3193,7 @@ wavelan_get_wireless_stats(device * dev) ...@@ -2559,7 +3193,7 @@ wavelan_get_wireless_stats(device * dev)
#endif #endif
/* Disable interrupts & save flags */ /* Disable interrupts & save flags */
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
wstats = &lp->wstats; wstats = &lp->wstats;
...@@ -2585,7 +3219,7 @@ wavelan_get_wireless_stats(device * dev) ...@@ -2585,7 +3219,7 @@ wavelan_get_wireless_stats(device * dev)
wstats->discard.misc = 0L; wstats->discard.misc = 0L;
/* ReEnable interrupts & restore flags */ /* ReEnable interrupts & restore flags */
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_IOCTL_TRACE #ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name); printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
...@@ -2921,7 +3555,7 @@ wv_packet_write(device * dev, ...@@ -2921,7 +3555,7 @@ wv_packet_write(device * dev,
printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length); printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
#endif #endif
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
/* Check if we need some padding */ /* Check if we need some padding */
if(clen < ETH_ZLEN) if(clen < ETH_ZLEN)
...@@ -2951,7 +3585,7 @@ wv_packet_write(device * dev, ...@@ -2951,7 +3585,7 @@ wv_packet_write(device * dev,
/* Keep stats up to date */ /* Keep stats up to date */
lp->stats.tx_bytes += length; lp->stats.tx_bytes += length;
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_TX_INFO #ifdef DEBUG_TX_INFO
wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write"); wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
...@@ -2991,9 +3625,9 @@ wavelan_packet_xmit(struct sk_buff * skb, ...@@ -2991,9 +3625,9 @@ wavelan_packet_xmit(struct sk_buff * skb,
* we can do it now */ * we can do it now */
if(lp->reconfig_82593) if(lp->reconfig_82593)
{ {
wv_splhi(lp, &flags); /* Disable interrupts */ spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */
wv_82593_config(dev); wv_82593_config(dev);
wv_splx(lp, &flags); /* Re-enable interrupts */ spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */
/* Note : the configure procedure was totally synchronous, /* Note : the configure procedure was totally synchronous,
* so the Tx buffer is now free */ * so the Tx buffer is now free */
} }
...@@ -3230,7 +3864,7 @@ wv_ru_stop(device * dev) ...@@ -3230,7 +3864,7 @@ wv_ru_stop(device * dev)
printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name); printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
#endif #endif
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
/* First, send the LAN controller a stop receive command */ /* First, send the LAN controller a stop receive command */
wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv", wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
...@@ -3255,7 +3889,7 @@ wv_ru_stop(device * dev) ...@@ -3255,7 +3889,7 @@ wv_ru_stop(device * dev)
} }
while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0)); while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
/* If there was a problem */ /* If there was a problem */
if(spin <= 0) if(spin <= 0)
...@@ -3299,7 +3933,7 @@ wv_ru_start(device * dev) ...@@ -3299,7 +3933,7 @@ wv_ru_start(device * dev)
if(!wv_ru_stop(dev)) if(!wv_ru_stop(dev))
return FALSE; return FALSE;
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
/* Now we know that no command is being executed. */ /* Now we know that no command is being executed. */
...@@ -3354,7 +3988,7 @@ wv_ru_start(device * dev) ...@@ -3354,7 +3988,7 @@ wv_ru_start(device * dev)
} }
#endif #endif
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_CONFIG_TRACE #ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name); printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
...@@ -3630,7 +4264,7 @@ wv_hw_config(device * dev) ...@@ -3630,7 +4264,7 @@ wv_hw_config(device * dev)
return FALSE; return FALSE;
/* Disable interrupts */ /* Disable interrupts */
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
/* Disguised goto ;-) */ /* Disguised goto ;-) */
do do
...@@ -3695,7 +4329,7 @@ wv_hw_config(device * dev) ...@@ -3695,7 +4329,7 @@ wv_hw_config(device * dev)
while(0); while(0);
/* Re-enable interrupts */ /* Re-enable interrupts */
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_CONFIG_TRACE #ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name); printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
...@@ -4021,7 +4655,7 @@ wavelan_interrupt(int irq, ...@@ -4021,7 +4655,7 @@ wavelan_interrupt(int irq,
/* Prevent reentrancy. We need to do that because we may have /* Prevent reentrancy. We need to do that because we may have
* multiple interrupt handler running concurently. * multiple interrupt handler running concurently.
* It is safe because wv_splhi() disable interrupts before aquiring * It is safe because interrupts are disabled before aquiring
* the spinlock. */ * the spinlock. */
spin_lock(&lp->spinlock); spin_lock(&lp->spinlock);
...@@ -4254,7 +4888,7 @@ wavelan_watchdog(device * dev) ...@@ -4254,7 +4888,7 @@ wavelan_watchdog(device * dev)
dev->name); dev->name);
#endif #endif
wv_splhi(lp, &flags); spin_lock_irqsave(&lp->spinlock, flags);
/* Ask to abort the current command */ /* Ask to abort the current command */
outb(OP0_ABORT, LCCR(base)); outb(OP0_ABORT, LCCR(base));
...@@ -4265,7 +4899,7 @@ wavelan_watchdog(device * dev) ...@@ -4265,7 +4899,7 @@ wavelan_watchdog(device * dev)
aborted = TRUE; aborted = TRUE;
/* Release spinlock here so that wv_hw_reset() can grab it */ /* Release spinlock here so that wv_hw_reset() can grab it */
wv_splx(lp, &flags); spin_unlock_irqrestore(&lp->spinlock, flags);
/* Check if we were successful in aborting it */ /* Check if we were successful in aborting it */
if(!aborted) if(!aborted)
...@@ -4530,7 +5164,11 @@ wavelan_attach(void) ...@@ -4530,7 +5164,11 @@ wavelan_attach(void)
dev->watchdog_timeo = WATCHDOG_JIFFIES; dev->watchdog_timeo = WATCHDOG_JIFFIES;
#ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */ #ifdef WIRELESS_EXT /* If wireless extension exist in the kernel */
#if WIRELESS_EXT > 12
dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
#else /* WIRELESS_EXT > 12 */
dev->do_ioctl = wavelan_ioctl; /* wireless extensions */ dev->do_ioctl = wavelan_ioctl; /* wireless extensions */
#endif /* WIRELESS_EXT > 12 */
dev->get_wireless_stats = wavelan_get_wireless_stats; dev->get_wireless_stats = wavelan_get_wireless_stats;
#endif #endif
......
...@@ -394,6 +394,12 @@ ...@@ -394,6 +394,12 @@
* o control first busy loop in wv_82593_cmd() * o control first busy loop in wv_82593_cmd()
* o Extend spinlock protection in wv_hw_config() * o Extend spinlock protection in wv_hw_config()
* *
* Changes made for release in 3.1.33 :
* ----------------------------------
* - Optional use new driver API for Wireless Extensions :
* o got rid of wavelan_ioctl()
* o use a bunch of iw_handler instead
*
* Wishes & dreams: * Wishes & dreams:
* ---------------- * ----------------
* - Cleanup and integrate the roaming code * - Cleanup and integrate the roaming code
...@@ -430,6 +436,9 @@ ...@@ -430,6 +436,9 @@
#ifdef CONFIG_NET_RADIO #ifdef CONFIG_NET_RADIO
#include <linux/wireless.h> /* Wireless extensions */ #include <linux/wireless.h> /* Wireless extensions */
#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
#endif /* WIRELESS_EXT > 12 */
#endif #endif
/* Pcmcia headers that we need */ /* Pcmcia headers that we need */
...@@ -498,7 +507,7 @@ ...@@ -498,7 +507,7 @@
/************************ CONSTANTS & MACROS ************************/ /************************ CONSTANTS & MACROS ************************/
#ifdef DEBUG_VERSION_SHOW #ifdef DEBUG_VERSION_SHOW
static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/12/00\n"; static const char *version = "wavelan_cs.c : v24 (SMP + wireless extensions) 11/1/02\n";
#endif #endif
/* Watchdog temporisation */ /* Watchdog temporisation */
...@@ -523,8 +532,8 @@ static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/ ...@@ -523,8 +532,8 @@ static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/
#define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */ #define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */
#define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */ #define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */ #define SIOCSIPHISTO SIOCIWFIRSTPRIV + 4 /* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */ #define SIOCGIPHISTO SIOCIWFIRSTPRIV + 5 /* Get histogram values */
/*************************** WaveLAN Roaming **************************/ /*************************** WaveLAN Roaming **************************/
#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */ #ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */
...@@ -589,6 +598,16 @@ typedef struct iw_freq iw_freq; ...@@ -589,6 +598,16 @@ typedef struct iw_freq iw_freq;
typedef struct net_local net_local; typedef struct net_local net_local;
typedef struct timer_list timer_list; typedef struct timer_list timer_list;
#if WIRELESS_EXT <= 12
/* Wireless extensions backward compatibility */
/* Part of iw_handler prototype we need */
struct iw_request_info
{
__u16 cmd; /* Wireless Extension command */
__u16 flags; /* More to come ;-) */
};
#endif /* WIRELESS_EXT <= 12 */
/* Basic types */ /* Basic types */
typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */ typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */
...@@ -661,12 +680,6 @@ void wv_roam_cleanup(struct net_device *dev); ...@@ -661,12 +680,6 @@ void wv_roam_cleanup(struct net_device *dev);
#endif /* WAVELAN_ROAMING */ #endif /* WAVELAN_ROAMING */
/* ----------------------- MISC SUBROUTINES ------------------------ */ /* ----------------------- MISC SUBROUTINES ------------------------ */
static inline void
wv_splhi(net_local *, /* Disable interrupts */
unsigned long *); /* flags */
static inline void
wv_splx(net_local *, /* ReEnable interrupts */
unsigned long *); /* flags */
static void static void
cs_error(client_handle_t, /* Report error to cardmgr */ cs_error(client_handle_t, /* Report error to cardmgr */
int, int,
......
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