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
MIPS-32-based Baget embedded system. This chipset is better known
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
This is the driver for the onboard card of MIPS Magnum 4000,
Acer PICA, Olivetti M700-10 and a few other identical OEM systems.
......@@ -214,6 +218,12 @@ CONFIG_PPPOE
pppd, along with binaries of a patched pppd package can be found at:
<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
Support for wireless LANs and everything having to do with radio,
but not with amateur radio or FM broadcasting.
......@@ -853,6 +863,10 @@ CONFIG_LANCE
say M here and read <file:Documentation/modules.txt>. This is
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
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
......@@ -1326,6 +1340,24 @@ CONFIG_DE4X5
module, say M here and read <file:Documentation/modules.txt> as well
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
This driver is developed for the SMC EtherPower series Ethernet
cards and also works with cards based on the DECchip
......@@ -1344,6 +1376,20 @@ CONFIG_TULIP
module, say M here and read <file:Documentation/modules.txt> as well
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
This is support for the Digi International RightSwitch series of
PCI/EISA Ethernet switch cards. These include the SE-4 and the SE-6
......@@ -1374,6 +1420,11 @@ CONFIG_FEALNX
cards. Specifications and data at
<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
If you have a network (Ethernet) card of this type, say Y and read
the Ethernet-HOWTO, available from
......@@ -1413,6 +1464,16 @@ CONFIG_VIA_RHINE
a module, say M here and read <file:Documentation/modules.txt> as
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
This driver is for DM9102(A)/DM9132/DM9801 compatible PCI cards from
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)
/* get link status */
case 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;
if (copy_to_user(useraddr, &edata, sizeof(edata)))
return -EFAULT;
......
......@@ -133,7 +133,7 @@ CONFIG_PCMCIA_XIRCOM
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 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
<file:Documentation/modules.txt>. If unsure, say N.
......
......@@ -433,8 +433,6 @@ static int olympic_open(struct net_device *dev)
do {
int i;
save_flags(flags);
cli();
for(i=0;i<SRB_COMMAND_SIZE;i+=4)
writel(0,init_srb+i);
if(SRB_COMMAND_SIZE & 2)
......@@ -466,9 +464,11 @@ static int olympic_open(struct net_device *dev)
}
writeb(1,init_srb+30);
spin_lock_irqsave(&olympic_priv->olympic_lock,flags);
olympic_priv->srb_queued=1;
writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
t = jiffies ;
......@@ -496,7 +496,6 @@ static int olympic_open(struct net_device *dev)
remove_wait_queue(&olympic_priv->srb_wait,&wait) ;
set_current_state(TASK_RUNNING) ;
restore_flags(flags);
#if OLYMPIC_DEBUG
printk("init_srb(%p): ",init_srb);
for(i=0;i<20;i++)
......@@ -1058,12 +1057,11 @@ static int olympic_close(struct net_device *dev)
writeb(0,srb+1);
writeb(OLYMPIC_CLEAR_RET_CODE,srb+2);
save_flags(flags);
cli();
spin_lock_irqsave(&olympic_priv->olympic_lock,flags);
olympic_priv->srb_queued=1;
writel(LISR_SRB_CMD,olympic_mmio+LISR_SUM);
spin_unlock_irqrestore(&olympic_priv->olympic_lock,flags);
t = jiffies ;
......@@ -1088,7 +1086,6 @@ static int olympic_close(struct net_device *dev)
remove_wait_queue(&olympic_priv->srb_wait,&wait) ;
set_current_state(TASK_RUNNING) ;
restore_flags(flags) ;
olympic_priv->rx_status_last_received++;
olympic_priv->rx_status_last_received&=OLYMPIC_RX_RING_SIZE-1;
......
......@@ -63,6 +63,9 @@
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h>
#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
#endif /* WIRELESS_EXT > 12 */
#endif
#include <pcmcia/version.h>
......@@ -269,6 +272,16 @@ static dev_link_t *dev_list;
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
* If the new wireless device private ioctl range is not defined,
* default to standard device private ioctl range */
......@@ -276,8 +289,11 @@ static dev_link_t *dev_list;
#define SIOCIWFIRSTPRIV SIOCDEVPRIVATE
#endif /* SIOCIWFIRSTPRIV */
#define SIOCGIPSNAP SIOCIWFIRSTPRIV /* Site Survey Snapshot */
/*#define SIOCGIPQTHR SIOCIWFIRSTPRIV + 1*/
#else /* WIRELESS_EXT <= 12 */
static const struct iw_handler_def netwave_handler_def;
#endif /* WIRELESS_EXT <= 12 */
#define SIOCGIPSNAP SIOCIWFIRSTPRIV + 1 /* Site Survey Snapshot */
#define MAX_ESA 10
......@@ -483,7 +499,10 @@ static dev_link_t *netwave_attach(void)
/* wireless extensions */
#ifdef WIRELESS_EXT
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->tx_timeout = &netwave_watchdog;
......@@ -595,6 +614,303 @@ static void netwave_flush_stale_links(void)
}
} /* 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)
*
......@@ -606,56 +922,28 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
struct ifreq *rq, /* Data passed */
int cmd) /* Ioctl number */
{
unsigned long flags;
int ret = 0;
#ifdef WIRELESS_EXT
ioaddr_t iobase = dev->base_addr;
netwave_private *priv = (netwave_private *) dev->priv;
u_char *ramBase = priv->ramBase;
#if WIRELESS_EXT <= 12
struct iwreq *wrq = (struct iwreq *) rq;
#endif
#endif
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 */
switch(cmd) {
/* --------------- WIRELESS EXTENSIONS --------------- */
#ifdef WIRELESS_EXT
#if WIRELESS_EXT <= 12
case SIOCGIWNAME:
/* Get name */
strcpy(wrq->u.name, "Netwave");
netwave_get_name(dev, NULL, &(wrq->u), NULL);
break;
case SIOCSIWNWID:
/* Set domain */
#if WIRELESS_EXT > 8
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;
ret = netwave_set_nwid(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIWNWID:
/* Read domain*/
#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 */
ret = netwave_get_nwid(dev, NULL, &(wrq->u), NULL);
break;
#if WIRELESS_EXT > 8 /* Note : The API did change... */
case SIOCGIWENCODE:
......@@ -663,10 +951,7 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
if(wrq->u.encoding.pointer != (caddr_t) 0)
{
char key[2];
key[1] = scramble_key & 0xff;
key[0] = (scramble_key>>8) & 0xff;
wrq->u.encoding.flags = IW_ENCODE_ENABLED;
wrq->u.encoding.length = 2;
ret = netwave_get_scramble(dev, NULL, &(wrq->u), key);
if(copy_to_user(wrq->u.encoding.pointer, key, 2))
ret = -EFAULT;
}
......@@ -681,79 +966,31 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
ret = -EFAULT;
break;
}
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);
ret = netwave_set_scramble(dev, NULL, &(wrq->u), key);
}
break;
case SIOCGIWMODE:
/* Mode of operation */
if(domain & 0x100)
wrq->u.mode = IW_MODE_INFRA;
else
wrq->u.mode = IW_MODE_ADHOC;
ret = netwave_get_mode(dev, NULL, &(wrq->u), NULL);
break;
#else /* WIRELESS_EXT > 8 */
case SIOCGIWENCODE:
/* Get scramble key */
wrq->u.encoding.code = scramble_key;
wrq->u.encoding.method = 1;
ret = netwave_get_scramble(dev, NULL, &(wrq->u),
(char *) &wrq->u.encoding.code);
break;
case SIOCSIWENCODE:
/* Set scramble key */
scramble_key = wrq->u.encoding.code;
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);
ret = netwave_set_scramble(dev, NULL, &(wrq->u),
(char *) &wrq->u.encoding.code);
break;
#endif /* WIRELESS_EXT > 8 */
case SIOCGIWRANGE:
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0) {
struct iw_range range;
/* Set the length (very important for backward 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));
#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,
ret = netwave_get_range(dev, NULL, &(wrq->u), (char *) &range);
if (copy_to_user(wrq->u.data.pointer, &range,
sizeof(struct iw_range)))
ret = -EFAULT;
}
......@@ -761,47 +998,36 @@ static int netwave_ioctl(struct net_device *dev, /* ioctl device */
case SIOCGIWPRIV:
/* Basic checking... */
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 */
wrq->u.data.length = 1;
wrq->u.data.length = sizeof(netwave_private_args) / sizeof(netwave_private_args[0]);
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
sizeof(priv)))
if(copy_to_user(wrq->u.data.pointer,
(u_char *) netwave_private_args,
sizeof(netwave_private_args)))
ret = -EFAULT;
}
break;
case SIOCGIPSNAP:
if(wrq->u.data.pointer != (caddr_t) 0) {
/* Take snapshot of environment */
netwave_snapshot( priv, ramBase, iobase);
wrq->u.data.length = priv->nss.length;
char buffer[sizeof( struct site_survey)];
ret = netwave_get_snap(dev, NULL, &(wrq->u), buffer);
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer,
(u_char *) &priv->nss,
buffer,
sizeof( struct site_survey)))
{
printk(KERN_DEBUG "Bad buffer!\n");
break;
}
priv->lastExec = jiffies;
}
break;
#endif
#endif /* WIRELESS_EXT <= 12 */
#endif /* WIRELESS_EXT */
default:
ret = -EOPNOTSUPP;
}
/* ReEnable interrupts & restore flags */
restore_flags(flags);
return ret;
}
......
......@@ -22,28 +22,6 @@
* (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
......@@ -870,10 +848,10 @@ static inline void wv_82586_reconfig(device * dev)
/* Check if we can do it now ! */
if((netif_running(dev)) && !(netif_queue_stopped(dev))) {
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
/* May fail */
wv_82586_config(dev);
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
}
else {
#ifdef DEBUG_CONFIG_INFO
......@@ -1786,45 +1764,41 @@ static inline void wl_his_gather(device * dev, u8 * stats)
/*------------------------------------------------------------------*/
/*
* Perform ioctl for configuration and information.
* It is here that the wireless extensions are treated (iwconfig).
* Wireless Handler : get protocol name
*/
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 */
struct ifreq *rq, /* data passed */
int cmd)
{ /* ioctl number */
static int wavelan_set_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 */
struct iwreq *wrq = (struct iwreq *) rq;
psa_t psa;
mm_t m;
unsigned long flags;
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. */
wv_splhi(lp, &flags);
/* Look what is the request */
switch (cmd) {
/* --------------- WIRELESS EXTENSIONS --------------- */
case SIOCGIWNAME:
strcpy(wrq->u.name, "WaveLAN");
break;
spin_lock_irqsave(&lp->spinlock, flags);
case SIOCSIWNWID:
/* Set NWID in WaveLAN. */
if (!wrq->u.nwid.disabled) {
if (!wrqu->nwid.disabled) {
/* Set NWID in psa */
psa.psa_nwid[0] =
(wrq->u.nwid.value & 0xFF00) >> 8;
psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8;
psa.psa_nwid[1] = wrqu->nwid.value & 0xFF;
psa.psa_nwid_select = 0x01;
psa_write(ioaddr, lp->hacr,
(char *) psa.psa_nwid - (char *) &psa,
......@@ -1853,29 +1827,93 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
}
/* update the Wavelan checksum */
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. */
psa_read(ioaddr, lp->hacr,
(char *) psa.psa_nwid - (char *) &psa,
(unsigned char *) psa.psa_nwid, 3);
wrq->u.nwid.value =
(psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrq->u.nwid.disabled = !(psa.psa_nwid_select);
wrq->u.nwid.fixed = 1; /* Superfluous */
break;
wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrqu->nwid.disabled = !(psa.psa_nwid_select);
wrqu->nwid.fixed = 1; /* Superfluous */
/* 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). */
if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY)))
ret = wv_set_frequency(ioaddr, &(wrq->u.freq));
ret = wv_set_frequency(ioaddr, &(wrqu->freq));
else
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).
* Does it work for everybody, especially old cards? */
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
/* Ask the EEPROM to read the frequency from the first area. */
fee_read(ioaddr, 0x00, &freq, 1);
wrq->u.freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrq->u.freq.e = 1;
wrqu->freq.m = ((freq >> 5) * 5 + 24000L) * 10000;
wrqu->freq.e = 1;
} else {
psa_read(ioaddr, lp->hacr,
(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];
wrq->u.freq.e = (psa.psa_subband != 0);
wrqu->freq.m = fixed_bands[psa.psa_subband];
wrqu->freq.e = (psa.psa_subband != 0);
} else
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. */
/* 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... */
psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
psa.psa_thr_pre_set = wrqu->sens.value & 0x3F;
psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_thr_pre_set - (char *) &psa,
(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
update_psa_checksum(dev, ioaddr, lp->hacr);
mmc_out(ioaddr, mmwoff(0, mmw_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. */
psa_read(ioaddr, lp->hacr,
(char *) &psa.psa_thr_pre_set - (char *) &psa,
(unsigned char *) &psa.psa_thr_pre_set, 1);
wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
wrq->u.sens.fixed = 1;
break;
wrqu->sens.value = psa.psa_thr_pre_set & 0x3F;
wrqu->sens.fixed = 1;
/* 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:
/* Set encryption key */
/* Check if capable of encryption */
if (!mmc_encr(ioaddr)) {
ret = -EOPNOTSUPP;
break;
}
/* Basic checking... */
if (wrq->u.encoding.pointer != (caddr_t) 0) {
/* Check the size of the key */
if (wrq->u.encoding.length != 8) {
if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) {
ret = -EINVAL;
break;
}
if(!ret) {
/* Basic checking... */
if (wrqu->encoding.length == 8) {
/* Copy the key in the driver */
wv_splx(lp, &flags);
err = copy_from_user(psa.psa_encryption_key,
wrq->u.encoding.pointer,
wrq->u.encoding.length);
wv_splhi(lp, &flags);
if (err) {
ret = -EFAULT;
break;
}
memcpy(psa.psa_encryption_key, extra,
wrqu->encoding.length);
psa.psa_encryption_select = 1;
psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select -
(char *) &psa,
......@@ -1963,7 +2058,8 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
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_write(ioaddr, lp->hacr,
(char *) &psa.psa_encryption_select -
......@@ -1975,30 +2071,37 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
}
/* update the Wavelan checksum */
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 */
if (!capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
/* Basic checking... */
if (wrq->u.encoding.pointer != (caddr_t) 0) {
/* Verify the user buffer */
ret =
verify_area(VERIFY_WRITE,
wrq->u.encoding.pointer, 8);
if (ret)
break;
return ret;
}
/*------------------------------------------------------------------*/
/*
* 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)
{
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,
(char *) &psa.psa_encryption_select -
(char *) &psa,
......@@ -2007,168 +2110,126 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
/* encryption is enabled ? */
if (psa.psa_encryption_select)
wrq->u.encoding.flags = IW_ENCODE_ENABLED;
wrqu->encoding.flags = IW_ENCODE_ENABLED;
else
wrq->u.encoding.flags = IW_ENCODE_DISABLED;
wrq->u.encoding.flags |= mmc_encr(ioaddr);
wrqu->encoding.flags = IW_ENCODE_DISABLED;
wrqu->encoding.flags |= mmc_encr(ioaddr);
/* Copy the key to the user buffer */
wrq->u.encoding.length = 8;
wv_splx(lp, &flags);
if (copy_to_user(wrq->u.encoding.pointer,
psa.psa_encryption_key, 8))
ret = -EFAULT;
wv_splhi(lp, &flags);
wrqu->encoding.length = 8;
memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length);
}
break;
case SIOCGIWRANGE:
/* basic checking */
if (wrq->u.data.pointer != (caddr_t) 0) {
struct iw_range range;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
/* Set the length (very important for backward
* compatibility) */
wrq->u.data.length = sizeof(struct iw_range);
return ret;
}
/* 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 */
range.we_version_compiled = WIRELESS_EXT;
range.we_version_source = 9;
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 9;
/* Set information in the range struct. */
range.throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */
range.min_nwid = 0x0000;
range.max_nwid = 0xFFFF;
range->throughput = 1.6 * 1000 * 1000; /* don't argue on this ! */
range->min_nwid = 0x0000;
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). */
if (!(mmc_in(ioaddr, mmroff(0, mmr_fee_status)) &
(MMR_FEE_STATUS_DWLD | MMR_FEE_STATUS_BUSY))) {
range.num_channels = 10;
range.num_frequency =
wv_frequency_list(ioaddr, range.freq,
range->num_channels = 10;
range->num_frequency = wv_frequency_list(ioaddr, 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;
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 */
range->num_channels = range->num_frequency = 0;
/* Encryption supported ? */
if (mmc_encr(ioaddr)) {
range.encoding_size[0] = 8; /* DES = 64 bits key */
range.num_encoding_sizes = 1;
range.max_encoding_tokens = 1; /* Only one key possible */
range->encoding_size[0] = 8; /* DES = 64 bits key */
range->num_encoding_sizes = 1;
range->max_encoding_tokens = 1; /* Only one key possible */
} else {
range.num_encoding_sizes = 0;
range.max_encoding_tokens = 0;
range->num_encoding_sizes = 0;
range->max_encoding_tokens = 0;
}
/* Copy structure to the user buffer. */
wv_splx(lp, &flags);
if (copy_to_user(wrq->u.data.pointer,
&range,
sizeof(struct iw_range)))
ret = -EFAULT;
wv_splhi(lp, &flags);
}
break;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
case SIOCGIWPRIV:
/* 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;
return ret;
}
#ifdef WIRELESS_SPY
case SIOCSIWSPY:
/* Set the spy list */
/* Check the number of addresses. */
if (wrq->u.data.length > IW_MAX_SPY) {
ret = -E2BIG;
break;
}
lp->spy_number = wrq->u.data.length;
/* Are there are addresses to copy? */
if (lp->spy_number > 0) {
struct sockaddr address[IW_MAX_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;
/* Copy addresses to the driver. */
wv_splx(lp, &flags);
err = copy_from_user(address,
wrq->u.data.pointer,
sizeof(struct sockaddr)
* lp->spy_number);
wv_splhi(lp, &flags);
if (err) {
ret = -EFAULT;
break;
}
/* 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 < lp->spy_number; i++) {
memcpy(lp->spy_address[i],
address[i].sa_data,
for (i = 0; i < wrqu->data.length; i++) {
memcpy(lp->spy_address[i], address[i].sa_data,
WAVELAN_ADDR_SIZE);
}
/* Reset structure. */
memset(lp->spy_stat, 0x00,
sizeof(iw_qual) * IW_MAX_SPY);
memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
#ifdef DEBUG_IOCTL_INFO
printk(KERN_DEBUG
"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
"%02X:%02X:%02X:%02X:%02X:%02X \n",
lp->spy_address[i][0],
......@@ -2180,20 +2241,28 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
#endif /* DEBUG_IOCTL_INFO */
}
break;
/* Now we can set the number of addresses */
lp->spy_number = wrqu->data.length;
case SIOCGIWSPY:
/* Get the spy list and spy stats. */
/* Set the number of addresses */
wrq->u.data.length = lp->spy_number;
return ret;
}
/* Does the user want to have the addresses back? */
if ((lp->spy_number > 0)
&& (wrq->u.data.pointer != (caddr_t) 0)) {
struct sockaddr address[IW_MAX_SPY];
/*------------------------------------------------------------------*/
/*
* 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,
......@@ -2201,42 +2270,37 @@ static int wavelan_ioctl(struct net_device *dev, /* device on which the ioctl is
WAVELAN_ADDR_SIZE);
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). */
err |= copy_to_user(wrq->u.data.pointer
+ (sizeof(struct sockaddr)
* lp->spy_number),
lp->spy_stat,
sizeof(iw_qual) * lp->spy_number);
wv_splhi(lp, &flags);
if (err) {
ret = -EFAULT;
break;
}
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;
}
/* if(pointer != NULL) */
break;
return(0);
}
#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:
if (!capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
psa.psa_quality_thr = *(wrq->u.name) & 0x0F;
psa.psa_quality_thr = *(extra) & 0x0F;
psa_write(ioaddr, lp->hacr,
(char *) &psa.psa_quality_thr - (char *) &psa,
(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
update_psa_checksum(dev, ioaddr, lp->hacr);
mmc_out(ioaddr, mmwoff(0, mmw_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,
(char *) &psa.psa_quality_thr - (char *) &psa,
(unsigned char *) &psa.psa_quality_thr, 1);
*(wrq->u.name) = psa.psa_quality_thr & 0x0F;
break;
*(extra) = psa.psa_quality_thr & 0x0F;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return 0;
}
#ifdef HISTOGRAM
case SIOCSIPHISTO:
/* Verify that the user is root. */
if (!capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
/*------------------------------------------------------------------*/
/*
* 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 (wrq->u.data.length > 16) {
ret = -E2BIG;
break;
if (wrqu->data.length > 16) {
return(-E2BIG);
}
lp->his_number = wrq->u.data.length;
/* Are there addresses to copy? */
if (lp->his_number > 0) {
/* 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 */
wv_splx(lp, &flags);
err = copy_from_user(lp->his_range,
wrq->u.data.pointer,
sizeof(char) * lp->his_number);
wv_splhi(lp, &flags);
if (err) {
ret = -EFAULT;
break;
memcpy(lp->his_range, extra, wrqu->data.length);
{
int i;
printk(KERN_DEBUG "Histo :");
for(i = 0; i < wrqu->data.length; i++)
printk(" %d", lp->his_range[i]);
printk("\n");
}
/* Reset structure. */
/* Reset result structure. */
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. */
wrq->u.data.length = lp->his_number;
wrqu->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. */
wv_splx(lp, &flags);
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;
if(lp->his_number > 0)
memcpy(extra, lp->his_sum, sizeof(long) * lp->his_number);
return(0);
}
#endif /* HISTOGRAM */
/* ------------------- OTHER IOCTL ------------------- */
/*------------------------------------------------------------------*/
/*
* Structures to export the Wireless Handlers
*/
default:
ret = -EOPNOTSUPP;
} /* switch (cmd) */
static const iw_handler wavelan_handler[] =
{
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. */
wv_splx(lp, &flags);
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" },
{ 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
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
#endif
return ret;
}
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,
};
/*------------------------------------------------------------------*/
/*
......@@ -2343,7 +2519,7 @@ static iw_stats *wavelan_get_wireless_stats(device * dev)
return (iw_stats *) NULL;
/* Disable interrupts and save flags. */
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
wstats = &lp->wstats;
......@@ -2371,7 +2547,7 @@ static iw_stats *wavelan_get_wireless_stats(device * dev)
wstats->discard.misc = 0L;
/* Enable interrupts and restore flags. */
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_IOCTL_TRACE
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)
if (clen < ETH_ZLEN)
clen = ETH_ZLEN;
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
/* Check nothing bad has happened */
if (lp->tx_n_in_use == (NTXBLOCKS - 1)) {
......@@ -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",
dev->name);
#endif
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
return 1;
}
......@@ -2791,7 +2967,7 @@ static inline int wv_packet_write(device * dev, void *buf, short length)
if (lp->tx_n_in_use < NTXBLOCKS - 1)
netif_wake_queue(dev);
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_TX_INFO
wv_packet_info((u8 *) buf, length, dev->name,
......@@ -2832,9 +3008,9 @@ static int wavelan_packet_xmit(struct sk_buff *skb, device * dev)
* we can do it now.
*/
if (lp->reconfig_82586) {
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
wv_82586_config(dev);
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
/* Check that we can continue */
if (lp->tx_n_in_use == (NTXBLOCKS - 1))
return 1;
......@@ -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
* 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. */
spin_lock(&lp->spinlock);
......@@ -3822,7 +3998,7 @@ static void wavelan_watchdog(device * dev)
return;
}
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
/* Try to see if some buffers are not free (in case we missed
* an interrupt */
......@@ -3862,7 +4038,7 @@ static void wavelan_watchdog(device * dev)
if (lp->tx_n_in_use < NTXBLOCKS - 1)
netif_wake_queue(dev);
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_INTERRUPT_TRACE
printk(KERN_DEBUG "%s: <-wavelan_watchdog()\n", dev->name);
......@@ -3909,7 +4085,7 @@ static int wavelan_open(device * dev)
return -EAGAIN;
}
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
if (wv_hw_reset(dev) != -1) {
netif_start_queue(dev);
......@@ -3920,10 +4096,10 @@ static int wavelan_open(device * dev)
"%s: wavelan_open(): impossible to start the card\n",
dev->name);
#endif
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
return -EAGAIN;
}
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_CALLBACK_TRACE
printk(KERN_DEBUG "%s: <-wavelan_open()\n", dev->name);
......@@ -3951,9 +4127,9 @@ static int wavelan_close(device * dev)
/*
* Flush the Tx and disable Rx.
*/
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
wv_82586_stop(dev);
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
free_irq(dev->irq, dev);
......@@ -4069,8 +4245,8 @@ static int __init wavelan_config(device * dev)
#endif /* SET_MAC_ADDRESS */
#ifdef WIRELESS_EXT /* if wireless extension exists in the kernel */
dev->do_ioctl = wavelan_ioctl;
dev->get_wireless_stats = wavelan_get_wireless_stats;
dev->wireless_handlers = (struct iw_handler_def *)&wavelan_handler_def;
#endif
dev->mtu = WAVELAN_MTU;
......
......@@ -345,6 +345,12 @@
* - Fix spinlock stupid bugs that I left in. The driver is now SMP
* 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:
* ----------------
* - roaming (see Pcmcia driver)
......@@ -379,6 +385,7 @@
#include <linux/init.h>
#include <linux/wireless.h> /* Wireless extensions */
#include <net/iw_handler.h> /* Wireless handlers */
/* WaveLAN declarations */
#include "i82586.h"
......@@ -436,7 +443,7 @@
/************************ CONSTANTS & MACROS ************************/
#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
/* Watchdog temporisation */
......@@ -449,11 +456,9 @@ static const char *version = "wavelan.c : v23 (SMP + wireless extensions) 05/10/
#define SIOCSIPQTHR SIOCIWFIRSTPRIV /* Set 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 SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 2 /* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 3 /* Get histogram values */
/****************************** TYPES ******************************/
......@@ -516,12 +521,6 @@ struct net_local
/**************************** PROTOTYPES ****************************/
/* ----------------------- 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
wv_irq_to_psa(int);
static int
......
......@@ -64,34 +64,6 @@
* (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
......@@ -591,7 +563,7 @@ void wv_nwid_filter(unsigned char mode, net_local *lp)
#endif
/* 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;
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)
lp->cell_search=0;
/* 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 */
......@@ -771,7 +743,7 @@ void wv_roam_handover(wavepoint_history *wavepoint, net_local *lp)
#endif
/* 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_h = (wavepoint->nwid & 0xFF00) >> 8;
......@@ -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);
/* ReEnable interrupts & restore flags */
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
wv_nwid_filter(!NWID_PROMISC,lp);
lp->curr_point=wavepoint;
......@@ -1049,9 +1021,9 @@ wv_82593_reconfig(device * dev)
/* Check if we can do it now ! */
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_splx(lp, &flags); /* Re-enable interrupts */
spin_unlock_irqrestore(&lp->spinlock, flags); /* Re-enable interrupts */
}
else
{
......@@ -1179,7 +1151,7 @@ wv_mmc_show(device * dev)
return;
}
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
/* Read the mmc */
mmc_out(base, mmwoff(0, mmw_freeze), 1);
......@@ -1191,7 +1163,7 @@ wv_mmc_show(device * dev)
lp->wstats.discard.nwid += (m.mmr_wrong_nwid_h << 8) | m.mmr_wrong_nwid_l;
#endif /* WIRELESS_EXT */
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
printk(KERN_DEBUG "##### wavelan modem status registers: #####\n");
#ifdef DEBUG_SHOW_UNUSED
......@@ -1884,269 +1856,415 @@ wl_his_gather(device * dev,
/*------------------------------------------------------------------*/
/*
* Perform ioctl : config & info stuff
* This is here that are treated the wireless extensions (iwconfig)
* Wireless Handler : get protocol name
*/
static int
wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
struct ifreq * rq, /* Data passed */
int cmd) /* Ioctl number */
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_set_nwid(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 iwreq * wrq = (struct iwreq *) rq;
net_local *lp = (net_local *) dev->priv; /* lp is not unused */
psa_t psa;
mm_t m;
unsigned long flags;
int ret = 0;
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: ->wavelan_ioctl(cmd=0x%X)\n", dev->name, cmd);
#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;
/* Disable interrupts and save flags. */
spin_lock_irqsave(&lp->spinlock, flags);
case SIOCSIWNWID:
/* Set NWID in wavelan */
/* Set NWID in WaveLAN. */
#if WIRELESS_EXT > 8
if(!wrq->u.nwid.disabled)
{
if (!wrqu->nwid.disabled) {
/* Set NWID in psa */
psa.psa_nwid[0] = (wrq->u.nwid.value & 0xFF00) >> 8;
psa.psa_nwid[1] = wrq->u.nwid.value & 0xFF;
psa.psa_nwid[0] = (wrqu->nwid.value & 0xFF00) >> 8;
psa.psa_nwid[1] = wrqu->nwid.value & 0xFF;
#else /* WIRELESS_EXT > 8 */
if(wrq->u.nwid.on)
{
if(wrq->u.nwid.on) {
/* Set NWID in psa */
psa.psa_nwid[0] = (wrq->u.nwid.nwid & 0xFF00) >> 8;
psa.psa_nwid[1] = wrq->u.nwid.nwid & 0xFF;
#endif /* WIRELESS_EXT > 8 */
psa.psa_nwid_select = 0x01;
psa_write(dev, (char *)psa.psa_nwid - (char *)&psa,
(unsigned char *)psa.psa_nwid, 3);
psa_write(dev,
(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_h = psa.psa_nwid[0];
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);
mmc_out(base, mmwoff(0, mmw_loopt_sel), 0x00);
}
else
{
/* Disable nwid in the psa */
} else {
/* Disable NWID in the psa. */
psa.psa_nwid_select = 0x00;
psa_write(dev, (char *)&psa.psa_nwid_select - (char *)&psa,
(unsigned char *)&psa.psa_nwid_select, 1);
psa_write(dev,
(char *) &psa.psa_nwid_select -
(char *) &psa,
(unsigned char *) &psa.psa_nwid_select,
1);
/* Disable nwid in the mmc (no filtering) */
mmc_out(base, mmwoff(0, mmw_loopt_sel), MMW_LOOPT_SEL_DIS_NWID);
/* Disable NWID in the mmc (no filtering). */
mmc_out(base, mmwoff(0, mmw_loopt_sel),
MMW_LOOPT_SEL_DIS_NWID);
}
/* update the Wavelan checksum */
update_psa_checksum(dev);
break;
case SIOCGIWNWID:
/* Read the NWID */
psa_read(dev, (char *)psa.psa_nwid - (char *)&psa,
(unsigned char *)psa.psa_nwid, 3);
/* 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)
{
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
wrq->u.nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrq->u.nwid.disabled = !(psa.psa_nwid_select);
wrq->u.nwid.fixed = 1; /* Superfluous */
wrqu->nwid.value = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrqu->nwid.disabled = !(psa.psa_nwid_select);
wrqu->nwid.fixed = 1; /* Superfluous */
#else /* WIRELESS_EXT > 8 */
wrq->u.nwid.nwid = (psa.psa_nwid[0] << 8) + psa.psa_nwid[1];
wrq->u.nwid.on = psa.psa_nwid_select;
#endif /* WIRELESS_EXT > 8 */
break;
case SIOCSIWFREQ:
/* Attempt to recognise 2.00 cards (2.4 GHz frequency selectable) */
if(!(mmc_in(base, mmroff(0, mmr_fee_status)) &
/* 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)
{
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)))
ret = wv_set_frequency(base, &(wrq->u.freq));
ret = wv_set_frequency(base, &(wrqu->freq));
else
ret = -EOPNOTSUPP;
break;
case SIOCGIWFREQ:
/* 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;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
/* Ask the EEprom to read the frequency from the first area */
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);
return ret;
}
if(psa.psa_subband <= 4)
{
wrq->u.freq.m = fixed_bands[psa.psa_subband];
wrq->u.freq.e = (psa.psa_subband != 0);
}
else
/*------------------------------------------------------------------*/
/*
* Wireless Handler : get frequency
*/
static int wavelan_get_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 */
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;
}
break;
case SIOCSIWSENS:
/* Set the level threshold */
/* 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)
{
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
/* 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... */
psa.psa_thr_pre_set = wrq->u.sens.value & 0x3F;
psa.psa_thr_pre_set = wrqu->sens.value & 0x3F;
#else /* WIRELESS_EXT > 7 */
psa.psa_thr_pre_set = wrq->u.sensitivity & 0x3F;
#endif /* WIRELESS_EXT > 7 */
psa_write(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
(unsigned char *)&psa.psa_thr_pre_set, 1);
psa_write(dev,
(char *) &psa.psa_thr_pre_set - (char *) &psa,
(unsigned char *) &psa.psa_thr_pre_set, 1);
/* update the Wavelan checksum */
update_psa_checksum(dev);
mmc_out(base, mmwoff(0, mmw_thr_pre_set), psa.psa_thr_pre_set);
break;
mmc_out(base, mmwoff(0, mmw_thr_pre_set),
psa.psa_thr_pre_set);
case SIOCGIWSENS:
/* Read the level threshold */
psa_read(dev, (char *)&psa.psa_thr_pre_set - (char *)&psa,
(unsigned char *)&psa.psa_thr_pre_set, 1);
/* 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)
{
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
wrq->u.sens.value = psa.psa_thr_pre_set & 0x3F;
wrq->u.sens.fixed = 1;
wrqu->sens.value = psa.psa_thr_pre_set & 0x3F;
wrqu->sens.fixed = 1;
#else /* WIRELESS_EXT > 7 */
wrq->u.sensitivity = psa.psa_thr_pre_set & 0x3F;
#endif /* WIRELESS_EXT > 7 */
break;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
#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;
break;
}
/* Basic checking... */
if(wrq->u.encoding.pointer != (caddr_t) 0)
{
/* Check the size of the key */
if(wrq->u.encoding.length != 8)
{
if((wrqu->encoding.length != 8) && (wrqu->encoding.length != 0)) {
ret = -EINVAL;
break;
}
if(!ret) {
/* Basic checking... */
if (wrqu->encoding.length == 8) {
/* Copy the key in the driver */
if(copy_from_user(psa.psa_encryption_key, wrq->u.encoding.pointer,
wrq->u.encoding.length))
{
ret = -EFAULT;
break;
}
memcpy(psa.psa_encryption_key, extra,
wrqu->encoding.length);
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),
MMW_ENCR_ENABLE_EN | MMW_ENCR_ENABLE_MODE);
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_write(dev, (char *) &psa.psa_encryption_select - (char *) &psa,
(unsigned char *) &psa.psa_encryption_select, 1);
psa_write(dev,
(char *) &psa.psa_encryption_select -
(char *) &psa,
(unsigned char *) &psa.
psa_encryption_select, 1);
mmc_out(base, mmwoff(0, mmw_encr_enable), 0);
}
/* update the Wavelan checksum */
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 */
if(!capable(CAP_NET_ADMIN))
{
ret = -EPERM;
break;
}
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
/* Basic checking... */
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);
return ret;
}
/*------------------------------------------------------------------*/
/*
* 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 ? */
if(psa.psa_encryption_select)
wrq->u.encoding.flags = IW_ENCODE_ENABLED;
if (psa.psa_encryption_select)
wrqu->encoding.flags = IW_ENCODE_ENABLED;
else
wrq->u.encoding.flags = IW_ENCODE_DISABLED;
wrq->u.encoding.flags |= mmc_encr(base);
wrqu->encoding.flags = IW_ENCODE_DISABLED;
wrqu->encoding.flags |= mmc_encr(base);
/* Copy the key to the user buffer */
wrq->u.encoding.length = 8;
if(copy_to_user(wrq->u.encoding.pointer, psa.psa_encryption_key, 8))
ret = -EFAULT;
wrqu->encoding.length = 8;
memcpy(extra, psa.psa_encryption_key, wrqu->encoding.length);
}
break;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
#endif /* WIRELESS_EXT > 8 */
#ifdef WAVELAN_ROAMING_EXT
#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 */
if(wrq->u.data.flags == 0)
if(wrqu->data.flags == 0)
lp->filter_domains = 0;
else
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0)
{
else {
char essid[IW_ESSID_MAX_SIZE + 1];
char * endp;
/* Check the size of the string */
if(wrq->u.data.length > IW_ESSID_MAX_SIZE + 1)
{
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;
}
/* Terminate the string */
memcpy(essid, extra, wrqu->data.length);
essid[IW_ESSID_MAX_SIZE] = '\0';
#ifdef DEBUG_IOCTL_INFO
......@@ -2158,76 +2276,111 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
/* Has it worked ? */
if(endp > essid)
lp->filter_domains = 1;
else
{
else {
lp->filter_domains = 0;
ret = -EINVAL;
}
}
break;
case SIOCGIWESSID:
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0)
{
char essid[IW_ESSID_MAX_SIZE + 1];
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
return ret;
}
/*------------------------------------------------------------------*/
/*
* 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 ? */
wrq->u.data.flags = lp->filter_domains;
wrqu->data.flags = lp->filter_domains;
/* Copy Domain ID into a string (Wavelan specific) */
/* Sound crazy, be we can't have a snprintf in the kernel !!! */
sprintf(essid, "%lX", lp->domain_id);
essid[IW_ESSID_MAX_SIZE] = '\0';
sprintf(extra, "%lX", lp->domain_id);
extra[IW_ESSID_MAX_SIZE] = '\0';
/* Set the length */
wrq->u.data.length = strlen(essid) + 1;
wrqu->data.length = strlen(extra) + 1;
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, essid, wrq->u.data.length))
ret = -EFAULT;
}
break;
return 0;
}
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
printk(KERN_DEBUG "Set AP to : %02X:%02X:%02X:%02X:%02X:%02X\n",
wrq->u.ap_addr.sa_data[0],
wrq->u.ap_addr.sa_data[1],
wrq->u.ap_addr.sa_data[2],
wrq->u.ap_addr.sa_data[3],
wrq->u.ap_addr.sa_data[4],
wrq->u.ap_addr.sa_data[5]);
wrqu->ap_addr.sa_data[0],
wrqu->ap_addr.sa_data[1],
wrqu->ap_addr.sa_data[2],
wrqu->ap_addr.sa_data[3],
wrqu->ap_addr.sa_data[4],
wrqu->ap_addr.sa_data[5]);
#endif /* DEBUG_IOCTL_INFO */
ret = -EOPNOTSUPP; /* Not supported yet */
break;
return -EOPNOTSUPP;
}
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 */
memcpy(wrq->u.ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE);
wrq->u.ap_addr.sa_family = ARPHRD_ETHER;
memcpy(wrqu->ap_addr.sa_data, dev->dev_addr, WAVELAN_ADDR_SIZE);
wrqu->ap_addr.sa_family = ARPHRD_ETHER;
ret = -EOPNOTSUPP; /* Not supported yet */
break;
return -EOPNOTSUPP;
}
#endif /* WIRELESS_EXT > 5 */
#endif /* WAVELAN_ROAMING_EXT */
#if WIRELESS_EXT > 8
#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:
if(do_roaming)
{
if(do_roaming) {
wv_roam_cleanup(dev);
do_roaming = 0;
}
break;
case IW_MODE_INFRA:
if(!do_roaming)
{
if(!do_roaming) {
wv_roam_init(dev);
do_roaming = 1;
}
......@@ -2235,206 +2388,702 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
default:
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)
wrq->u.mode = IW_MODE_INFRA;
wrqu->mode = IW_MODE_INFRA;
else
wrq->u.mode = IW_MODE_ADHOC;
break;
wrqu->mode = IW_MODE_ADHOC;
return 0;
}
#endif /* WAVELAN_ROAMING */
#endif /* WIRELESS_EXT > 8 */
case SIOCGIWRANGE:
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0)
{
struct iw_range 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)
{
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) */
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 */
memset(&range, 0, sizeof(range));
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 */
range->we_version_compiled = WIRELESS_EXT;
range->we_version_source = 9;
#endif /* WIRELESS_EXT > 10 */
/* Set information in the range struct */
range.throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */
range.min_nwid = 0x0000;
range.max_nwid = 0xFFFF;
/* Set information in the range struct. */
range->throughput = 1.4 * 1000 * 1000; /* don't argue on this ! */
range->min_nwid = 0x0000;
range->max_nwid = 0xFFFF;
/* 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;
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->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
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 */
range.avg_qual.level = 30;
range.avg_qual.noise = 8;
range->avg_qual.level = 30;
range->avg_qual.noise = 8;
#endif /* WIRELESS_EXT > 11 */
#if WIRELESS_EXT > 7
range.num_bitrates = 1;
range.bitrate[0] = 2000000; /* 2 Mb/s */
range->num_bitrates = 1;
range->bitrate[0] = 2000000; /* 2 Mb/s */
#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
/* Encryption supported ? */
if(mmc_encr(base))
{
range.encoding_size[0] = 8; /* DES = 64 bits key */
range.num_encoding_sizes = 1;
range.max_encoding_tokens = 1; /* Only one key possible */
}
else
{
range.num_encoding_sizes = 0;
range.max_encoding_tokens = 0;
if (mmc_encr(base)) {
range->encoding_size[0] = 8; /* DES = 64 bits key */
range->num_encoding_sizes = 1;
range->max_encoding_tokens = 1; /* Only one key possible */
} else {
range->num_encoding_sizes = 0;
range->max_encoding_tokens = 0;
}
#endif /* WIRELESS_EXT > 8 */
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, &range,
sizeof(struct iw_range)))
ret = -EFAULT;
/* Enable interrupts and restore flags. */
spin_unlock_irqrestore(&lp->spinlock, flags);
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:
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0)
/* Reset structure. */
memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
#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[] =
{ /* cmd, set_args, get_args, name */
int i;
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" },
{ 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" },
{ 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 */
wrq->u.data.length = 6;
#if WIRELESS_EXT > 12
/* Copy structure to the user buffer */
if(copy_to_user(wrq->u.data.pointer, (u_char *) priv,
sizeof(priv)))
ret = -EFAULT;
}
static const iw_handler wavelan_handler[] =
{
NULL, /* SIOCSIWNAME */
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;
#ifdef WIRELESS_SPY
case SIOCSIWSPY:
/* Set the spy list */
case SIOCSIWNWID:
ret = wavelan_set_nwid(dev, NULL, &(wrq->u), NULL);
break;
/* Check the number of addresses */
if(wrq->u.data.length > IW_MAX_SPY)
case SIOCGIWNWID:
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;
}
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 */
if(lp->spy_number > 0)
case SIOCGIWENCODE:
if (! capable(CAP_NET_ADMIN)) {
ret = -EPERM;
break;
}
{
struct sockaddr address[IW_MAX_SPY];
int i;
char keybuf[8];
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 */
if(copy_from_user(address, wrq->u.data.pointer,
sizeof(struct sockaddr) * lp->spy_number))
#ifdef WAVELAN_ROAMING_EXT
#if WIRELESS_EXT > 5
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;
break;
}
ret = wavelan_set_essid(dev, NULL,
&(wrq->u),
essidbuf);
}
break;
/* Copy addresses to the lp structure */
for(i = 0; i < lp->spy_number; i++)
case SIOCGIWESSID:
{
memcpy(lp->spy_address[i], address[i].sa_data,
WAVELAN_ADDR_SIZE);
char essidbuf[IW_ESSID_MAX_SIZE+1];
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... */
memset(lp->spy_stat, 0x00, sizeof(iw_qual) * IW_MAX_SPY);
#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 SIOCSIWAP:
ret = wavelan_set_wap(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIWAP:
ret = wavelan_get_wap(dev, NULL, &(wrq->u), NULL);
break;
#endif /* WIRELESS_EXT > 5 */
#endif /* WAVELAN_ROAMING_EXT */
case SIOCGIWSPY:
/* Get the spy list and spy stats */
#if WIRELESS_EXT > 8
#ifdef WAVELAN_ROAMING
case SIOCSIWMODE:
ret = wavelan_set_mode(dev, NULL, &(wrq->u), NULL);
break;
/* Set the number of addresses */
wrq->u.data.length = lp->spy_number;
case SIOCGIWMODE:
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... */
if((lp->spy_number > 0) && (wrq->u.data.pointer != (caddr_t) 0))
case SIOCGIWRANGE:
{
struct sockaddr address[IW_MAX_SPY];
int i;
struct iw_range range;
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 */
for(i = 0; i < lp->spy_number; i++)
case SIOCGIWPRIV:
/* Basic checking... */
if(wrq->u.data.pointer != (caddr_t) 0)
{
memcpy(address[i].sa_data, lp->spy_address[i],
WAVELAN_ADDR_SIZE);
address[i].sa_family = ARPHRD_ETHER;
/* Set the number of ioctl available */
wrq->u.data.length = sizeof(wavelan_private_args) / sizeof(wavelan_private_args[0]);
/* 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 */
if(copy_to_user(wrq->u.data.pointer, address,
sizeof(struct sockaddr) * lp->spy_number))
#ifdef WIRELESS_SPY
case SIOCSIWSPY:
{
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;
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) */
if(copy_to_user(wrq->u.data.pointer +
(sizeof(struct sockaddr) * lp->spy_number),
lp->spy_stat, sizeof(iw_qual) * lp->spy_number))
case SIOCGIWSPY:
{
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;
break;
}
/* Reset updated flags */
for(i = 0; i < lp->spy_number; i++)
lp->spy_stat[i].updated = 0x0;
} /* if(pointer != NULL) */
}
break;
#endif /* WIRELESS_SPY */
......@@ -2446,34 +3095,21 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
ret = -EPERM;
break;
}
psa.psa_quality_thr = *(wrq->u.name) & 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);
ret = wavelan_set_qthr(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIPQTHR:
psa_read(dev, (char *)&psa.psa_quality_thr - (char *)&psa,
(unsigned char *)&psa.psa_quality_thr, 1);
*(wrq->u.name) = psa.psa_quality_thr & 0x0F;
ret = wavelan_get_qthr(dev, NULL, &(wrq->u), NULL);
break;
#ifdef WAVELAN_ROAMING
case SIOCSIPROAM:
/* Note : should check if user == root */
if(do_roaming && (*wrq->u.name)==0)
wv_roam_cleanup(dev);
else if(do_roaming==0 && (*wrq->u.name)!=0)
wv_roam_init(dev);
do_roaming = (*wrq->u.name);
ret = wavelan_set_roam(dev, NULL, &(wrq->u), NULL);
break;
case SIOCGIPROAM:
*(wrq->u.name) = do_roaming;
ret = wavelan_get_roam(dev, NULL, &(wrq->u), NULL);
break;
#endif /* WAVELAN_ROAMING */
......@@ -2484,44 +3120,44 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
{
ret = -EPERM;
}
{
char buffer[16];
/* Check the number of intervals */
if(wrq->u.data.length > 16)
{
ret = -E2BIG;
break;
}
lp->his_number = wrq->u.data.length;
/* If there is some addresses to copy */
if(lp->his_number > 0)
{
/* Copy interval ranges to the driver */
if(copy_from_user(lp->his_range, wrq->u.data.pointer,
sizeof(char) * lp->his_number))
{
/* Get the data in the driver */
if (wrq->u.data.pointer) {
if (copy_from_user(buffer,
wrq->u.data.pointer,
sizeof(struct sockaddr) *
wrq->u.data.length)) {
ret = -EFAULT;
break;
}
/* Reset structure... */
memset(lp->his_sum, 0x00, sizeof(long) * 16);
} else if (wrq->u.data.length != 0) {
ret = -EINVAL;
break;
}
ret = wavelan_set_histo(dev, NULL, &(wrq->u),
buffer);
}
break;
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 */
if(copy_to_user(wrq->u.data.pointer, lp->his_sum,
sizeof(long) * lp->his_number))
long buffer[16];
ret = wavelan_get_histo(dev, NULL, &(wrq->u),
(char *) buffer);
if (wrq->u.data.pointer) {
if (copy_to_user(wrq->u.data.pointer,
buffer,
(wrq->u.data.length * sizeof(long))))
ret = -EFAULT;
} /* if(pointer != NULL) */
}
}
break;
#endif /* HISTOGRAM */
......@@ -2531,14 +3167,12 @@ wavelan_ioctl(struct net_device * dev, /* Device on wich the ioctl apply */
ret = -EOPNOTSUPP;
}
/* ReEnable interrupts & restore flags */
wv_splx(lp, &flags);
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_ioctl()\n", dev->name);
#endif
return ret;
}
#endif /* WIRELESS_EXT > 12 */
/*------------------------------------------------------------------*/
/*
......@@ -2559,7 +3193,7 @@ wavelan_get_wireless_stats(device * dev)
#endif
/* Disable interrupts & save flags */
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
wstats = &lp->wstats;
......@@ -2585,7 +3219,7 @@ wavelan_get_wireless_stats(device * dev)
wstats->discard.misc = 0L;
/* ReEnable interrupts & restore flags */
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_IOCTL_TRACE
printk(KERN_DEBUG "%s: <-wavelan_get_wireless_stats()\n", dev->name);
......@@ -2921,7 +3555,7 @@ wv_packet_write(device * dev,
printk(KERN_DEBUG "%s: ->wv_packet_write(%d)\n", dev->name, length);
#endif
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
/* Check if we need some padding */
if(clen < ETH_ZLEN)
......@@ -2951,7 +3585,7 @@ wv_packet_write(device * dev,
/* Keep stats up to date */
lp->stats.tx_bytes += length;
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_TX_INFO
wv_packet_info((u_char *) buf, length, dev->name, "wv_packet_write");
......@@ -2991,9 +3625,9 @@ wavelan_packet_xmit(struct sk_buff * skb,
* we can do it now */
if(lp->reconfig_82593)
{
wv_splhi(lp, &flags); /* Disable interrupts */
spin_lock_irqsave(&lp->spinlock, flags); /* Disable interrupts */
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,
* so the Tx buffer is now free */
}
......@@ -3230,7 +3864,7 @@ wv_ru_stop(device * dev)
printk(KERN_DEBUG "%s: ->wv_ru_stop()\n", dev->name);
#endif
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
/* First, send the LAN controller a stop receive command */
wv_82593_cmd(dev, "wv_graceful_shutdown(): stop-rcv",
......@@ -3255,7 +3889,7 @@ wv_ru_stop(device * dev)
}
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(spin <= 0)
......@@ -3299,7 +3933,7 @@ wv_ru_start(device * dev)
if(!wv_ru_stop(dev))
return FALSE;
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
/* Now we know that no command is being executed. */
......@@ -3354,7 +3988,7 @@ wv_ru_start(device * dev)
}
#endif
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: <-wv_ru_start()\n", dev->name);
......@@ -3630,7 +4264,7 @@ wv_hw_config(device * dev)
return FALSE;
/* Disable interrupts */
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
/* Disguised goto ;-) */
do
......@@ -3695,7 +4329,7 @@ wv_hw_config(device * dev)
while(0);
/* Re-enable interrupts */
wv_splx(lp, &flags);
spin_unlock_irqrestore(&lp->spinlock, flags);
#ifdef DEBUG_CONFIG_TRACE
printk(KERN_DEBUG "%s: <-wv_hw_config()\n", dev->name);
......@@ -4021,7 +4655,7 @@ wavelan_interrupt(int irq,
/* Prevent reentrancy. We need to do that because we may have
* 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. */
spin_lock(&lp->spinlock);
......@@ -4254,7 +4888,7 @@ wavelan_watchdog(device * dev)
dev->name);
#endif
wv_splhi(lp, &flags);
spin_lock_irqsave(&lp->spinlock, flags);
/* Ask to abort the current command */
outb(OP0_ABORT, LCCR(base));
......@@ -4265,7 +4899,7 @@ wavelan_watchdog(device * dev)
aborted = TRUE;
/* 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 */
if(!aborted)
......@@ -4530,7 +5164,11 @@ wavelan_attach(void)
dev->watchdog_timeo = WATCHDOG_JIFFIES;
#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 */
#endif /* WIRELESS_EXT > 12 */
dev->get_wireless_stats = wavelan_get_wireless_stats;
#endif
......
......@@ -394,6 +394,12 @@
* o control first busy loop in wv_82593_cmd()
* 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:
* ----------------
* - Cleanup and integrate the roaming code
......@@ -430,6 +436,9 @@
#ifdef CONFIG_NET_RADIO
#include <linux/wireless.h> /* Wireless extensions */
#if WIRELESS_EXT > 12
#include <net/iw_handler.h>
#endif /* WIRELESS_EXT > 12 */
#endif
/* Pcmcia headers that we need */
......@@ -498,7 +507,7 @@
/************************ CONSTANTS & MACROS ************************/
#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
/* Watchdog temporisation */
......@@ -523,8 +532,8 @@ static const char *version = "wavelan_cs.c : v23 (SMP + wireless extensions) 20/
#define SIOCSIPROAM SIOCIWFIRSTPRIV + 2 /* Set roaming state */
#define SIOCGIPROAM SIOCIWFIRSTPRIV + 3 /* Get roaming state */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 6 /* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 7 /* Get histogram values */
#define SIOCSIPHISTO SIOCIWFIRSTPRIV + 4 /* Set histogram ranges */
#define SIOCGIPHISTO SIOCIWFIRSTPRIV + 5 /* Get histogram values */
/*************************** WaveLAN Roaming **************************/
#ifdef WAVELAN_ROAMING /* Conditional compile, see above in options */
......@@ -589,6 +598,16 @@ typedef struct iw_freq iw_freq;
typedef struct net_local net_local;
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 */
typedef u_char mac_addr[WAVELAN_ADDR_SIZE]; /* Hardware address */
......@@ -661,12 +680,6 @@ void wv_roam_cleanup(struct net_device *dev);
#endif /* WAVELAN_ROAMING */
/* ----------------------- 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
cs_error(client_handle_t, /* Report error to cardmgr */
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