Commit 88c3cbad authored by Linus Torvalds's avatar Linus Torvalds

Merge bk://gkernel.bkbits.net/net-drivers-2.6

into ppc970.osdl.org:/home/torvalds/v2.6/linux
parents 4e0162be 4bef4172
Linux* Base Driver for the Intel(R) PRO/100 Family of Adapters
==============================================================
November 19, 2002
March 15, 2004
Contents
......@@ -9,9 +9,6 @@ Contents
- In This Release
- Supported Adapters
- Command Line Parameters
- CPU Cycle Saver
- Additional Configurations
- Support
......@@ -19,64 +16,13 @@ In This Release
===============
This file describes the Linux* Base Driver for the Intel(R) PRO/100 Family of
Adapters, version 2.2.x. This driver includes support for Itanium(TM)-based
Adapters, version 3.x.x. This driver includes support for Itanium(TM)-based
systems.
Supported Adapters
==================
The following Intel network adapters are compatible with the drivers
in this release:
Controller Adapter Name Board IDs
---------- ------------ ---------
82558 PRO/100+ PCI Adapter 668081-xxx, 689661-xxx
82558 PRO/100+ Management Adapter 691334-xxx, 701738-xxx,
721383-xxx
82558 PRO/100+ Dual Port Server Adapter 714303-xxx, 711269-xxx,
A28276-xxx
82558 PRO/100+ PCI Server Adapter 710550-xxx
82550 PRO/100 S Server Adapter 752438-xxx (82550)
82559 A56831-xxx, A10563-xxx,
A12171-xxx, A12321-xxx,
A12320-xxx, A12170-xxx
748568-xxx (82559)
748565-xxx (82559)
82550 PRO/100 S Desktop Adapter 751767-xxx (82550)
82559 748592-xxx, A12167-xxx,
A12318-xxx, A12317-xxx,
A12165-xxx
748569-xxx (82559)
82559 PRO/100+ Server Adapter 729757-xxx
82559 PRO/100 S Management Adapter 748566-xxx, 748564-xxx
82550 PRO/100 S Dual Port Server Adapter A56831-xxx
82551 PRO/100 M Desktop Adapter A80897-xxx
PRO/100 S Advanced Management Adapter 747842-xxx, 745171-xxx
CNR PRO/100 VE Desktop Adapter A10386-xxx, A10725-xxx,
A23801-xxx, A19716-xxx
PRO/100 VM Desktop Adapter A14323-xxx, A19725-xxx,
A23801-xxx, A22220-xxx,
A23796-xxx
To verify that your adapter is supported, find the board ID number on the
adapter. Look for a label that has a barcode and a number in the format
A12345-001. Match this to the list of numbers above.
......@@ -91,143 +37,6 @@ For the latest Intel PRO/100 network driver for Linux, see:
http://downloadfinder.intel.com/scripts-df/support_intel.asp
Command Line Parameters
=======================
If the driver is built as a module, the following optional parameters are
used by entering them on the command line with the modprobe or insmod command
using this syntax:
modprobe e100 [<option>=<VAL1>,<VAL2>,...]
insmod e100 [<option>=<VAL1>,<VAL2>,...]
For example, with two Intel PRO/100 PCI adapters, entering:
modprobe e100 TxDescriptors=32,128
loads the e100 driver with 32 TX resources for the first adapter and 128 TX
resources for the second adapter. This configuration favors the second
adapter. The driver supports up to 16 network adapters concurrently.
The default value for each parameter is generally the recommended setting,
unless otherwise noted.
NOTE: Giving any command line option the value "-1" causes the driver to use
the appropriate default value for that option, as if no value was
specified.
BundleMax
Valid Range: 1-65535
Default Value: 6
This parameter holds the maximum number of small packets (less than 128
bytes) in a bundle. Suggested values range from 2 to 10. See "CPU Cycle
Saver."
BundleSmallFr
Valid Range: 0-1 (0=off, 1=on)
Default Value: 0
The value 1 (on) causes small packets (less than 128 bytes) to be bundled.
See "CPU Cycle Saver."
e100_speed_duplex
Valid Range: 0-4 (1=10half;2=10full;3=100half;4=100full)
Default Value: 0
The default value of 0 sets the adapter to auto-negotiate. Other values
set the adapter to forced speed and duplex.
Example usage: insmod e100.o e100_speed_duplex=4,4 (for two adapters)
flow_control
Valid Range: 0-1 (0=off, 1=on)
Default Value: 0
This parameter controls the automatic generation(Tx) and response(Rx) to
Ethernet PAUSE frames. flow_control should NOT be set to 1 when the
adapter is connected to an interface that does not support Ethernet PAUSE
frames and when the e100_speed_duplex parameter is NOT set to zero.
IntDelay
Valid Range: 0-65535 (0=off)
Default Value: 1536
This parameter holds the number of time units (in adapter terminology)
until the adapter generates an interrupt. The recommended value for
IntDelay is 1536 (upon initialization). Suggested values range from
512 to 2048. See "CPU Cycle Saver."
IFS
Valid Range: 0-1 (0=off, 1=on)
Default Value: 1
Inter Frame Spacing (IFS) aims to reduce the number of Ethernet frame
collisions by altering the time between frame transmissions. When IFS is
enabled the driver tries to find an optimal IFS value. It is used only at
half duplex.
RxDescriptors
Valid Range: 8-1024
Default Value: 64
This parameter defines the number of receive descriptors allocated by
the driver. Increasing this value allows the driver to buffer more
incoming packets before the driver is required to service an interrupt.
The maximum value for Itanium-based systems is 64.
TxDescriptors
Valid Range: 19-1024
Default Value: 64
This value is the number of transmit descriptors allocated by the driver.
Increasing this value allows the protocol stack to queue more transmits at
the driver level. The maximum value for Itanium-based systems is 64.
ucode
Valid Range: 0-1 (0=off, 1=on)
Default Value: 0 for 82558-based adapters
1 for 82559, 82550, and 82551-based adapters
On uploads the micro code to the adapter, which enables CPU Cycle Saver.
See the section "CPU Cycle Saver" below.
Example usage: insmod e100.o ucode=1
Not available on 82557-based adapters.
XsumRX
Valid Range: 0-1 (0=off, 1=on)
Default Value: 1
On allows Rx checksum offloading for TCP/UDP packets. Requires that the
hardware support this feature.
Not available on 82557 and 82558-based adapters.
CPU Cycle Saver
================
CPU Cycle Saver reduces CPU utilization by reducing the number of interrupts
that the adapter generates.
When CPU Cycle Saver is turned off, the adapter generates one interrupt for
every frame that is received. This means that the operating system stops what
it is doing and switches to the network driver in order to process the
receive.
When CPU Cycle Saver is on, the adapter does not generate an interrupt for
every frame it receives. Instead, it waits until it receives several frames
before generating an interrupt. This reduces the amount of time spent
switching to and from the driver.
CPU Cycle Saver consists of these arguments: IntDelay, BundleMax and
BundleSmallFr. When IntDelay is increased, the adapter waits longer for
frames to arrive before generating the interrupt. By increasing BundleMax,
the network adapter waits for the number of small frames (less than 128 bytes)
specified to arrive before generating the interrupt. When BundleSmallFr is
disabled, the adapter does not bundle small packets. Such small packets are
often, but not always, control packets that are better served immediately;
therefore, BundleSmallFr is disabled by default.
For most users, it is recommended that CPU Cycle Saver be used with the
default values specified in the Command Line Parameters section. However, in
some cases, performance problems may occur with CPU Cycle Saver. If such
problems are observed, we recommend turning off this feature by setting
ucode=0.
Support
=======
......
......@@ -3,15 +3,13 @@
* devices like TTY. It interfaces between a raw TTY and the
* kernel's AX.25 protocol layers.
*
* Version: @(#)6pack.c 0.3.0 04/07/98
*
* Authors: Andreas Knsgen <ajk@iehk.rwth-aachen.de>
* Ralf Baechle DO1GRB <ralf@linux-mips.org>
*
* Quite a lot of stuff "stolen" by Jrg Reuter from slip.c, written by
* Quite a lot of stuff "stolen" by Joerg Reuter from slip.c, written by
*
* Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
*
*/
#include <linux/config.h>
......@@ -31,10 +29,13 @@
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/rtnetlink.h>
#include <linux/spinlock.h>
#include <linux/if_arp.h>
#include <linux/init.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <asm/semaphore.h>
#include <asm/atomic.h>
#define SIXPACK_VERSION "Revision: 0.3.0"
......@@ -78,13 +79,10 @@
#define SIXP_MTU 256 /* Default MTU */
enum sixpack_flags {
SIXPF_INUSE, /* Channel in use */
SIXPF_ERROR, /* Parity, etc. error */
};
struct sixpack {
int magic;
/* Various fields. */
struct tty_struct *tty; /* ptr to TTY structure */
struct net_device *dev; /* easy for intr handling */
......@@ -93,7 +91,7 @@ struct sixpack {
unsigned char *rbuff; /* receiver buffer */
int rcount; /* received chars counter */
unsigned char *xbuff; /* transmitter buffer */
unsigned char *xhead; /* pointer to next byte to XMIT */
unsigned char *xhead; /* next byte to XMIT */
int xleft; /* bytes left in XMIT queue */
unsigned char raw_buf[4];
......@@ -125,194 +123,110 @@ struct sixpack {
struct timer_list tx_t;
struct timer_list resync_t;
atomic_t refcnt;
struct semaphore dead_sem;
spinlock_t lock;
};
#define AX25_6PACK_HEADER_LEN 0
#define SIXPACK_MAGIC 0x5304
typedef struct sixpack_ctrl {
struct sixpack ctrl; /* 6pack things */
struct net_device dev; /* the device */
} sixpack_ctrl_t;
static sixpack_ctrl_t **sixpack_ctrls;
int sixpack_maxdev = SIXP_NRUNIT; /* Can be overridden with insmod! */
MODULE_PARM(sixpack_maxdev, "i");
MODULE_PARM_DESC(sixpack_maxdev, "number of 6PACK devices");
static void sp_start_tx_timer(struct sixpack *);
static void sp_xmit_on_air(unsigned long);
static void resync_tnc(unsigned long);
static void sixpack_decode(struct sixpack *, unsigned char[], int);
static int encode_sixpack(unsigned char *, unsigned char *, int, unsigned char);
static int sixpack_init(struct net_device *dev);
static void decode_prio_command(unsigned char, struct sixpack *);
static void decode_std_command(unsigned char, struct sixpack *);
static void decode_data(unsigned char, struct sixpack *);
static int tnc_init(struct sixpack *);
/*
* perform the persistence/slottime algorithm for CSMA access. If the
* persistence check was successful, write the data to the serial driver.
* Note that in case of DAMA operation, the data is not sent here.
*/
/* Find a free 6pack channel, and link in this `tty' line. */
static inline struct sixpack *sp_alloc(void)
static void sp_xmit_on_air(unsigned long channel)
{
sixpack_ctrl_t *spp = NULL;
int i;
for (i = 0; i < sixpack_maxdev; i++) {
spp = sixpack_ctrls[i];
if (spp == NULL)
break;
if (!test_and_set_bit(SIXPF_INUSE, &spp->ctrl.flags))
break;
}
/* Too many devices... */
if (i >= sixpack_maxdev)
return NULL;
/* If no channels are available, allocate one */
if (!spp &&
(sixpack_ctrls[i] = (sixpack_ctrl_t *)kmalloc(sizeof(sixpack_ctrl_t),
GFP_KERNEL)) != NULL) {
spp = sixpack_ctrls[i];
}
memset(spp, 0, sizeof(sixpack_ctrl_t));
/* Initialize channel control data */
set_bit(SIXPF_INUSE, &spp->ctrl.flags);
spp->ctrl.tty = NULL;
sprintf(spp->dev.name, "sp%d", i);
spp->dev.base_addr = i;
spp->dev.priv = (void *) &spp->ctrl;
spp->dev.next = NULL;
spp->dev.init = sixpack_init;
if (spp != NULL) {
/* register device so that it can be ifconfig'ed */
/* sixpack_init() will be called as a side-effect */
/* SIDE-EFFECT WARNING: sixpack_init() CLEARS spp->ctrl ! */
if (register_netdev(&spp->dev) == 0) {
set_bit(SIXPF_INUSE, &spp->ctrl.flags);
spp->ctrl.dev = &spp->dev;
spp->dev.priv = (void *) &spp->ctrl;
SET_MODULE_OWNER(&spp->dev);
return &spp->ctrl;
} else {
clear_bit(SIXPF_INUSE, &spp->ctrl.flags);
printk(KERN_WARNING "sp_alloc() - register_netdev() failure.\n");
}
}
return NULL;
}
struct sixpack *sp = (struct sixpack *) channel;
int actual;
static unsigned char random;
random = random * 17 + 41;
/* Free a 6pack channel. */
static inline void sp_free(struct sixpack *sp)
{
/* Free all 6pack frame buffers. */
if (sp->rbuff)
kfree(sp->rbuff);
sp->rbuff = NULL;
if (sp->xbuff)
kfree(sp->xbuff);
sp->xbuff = NULL;
if (!test_and_clear_bit(SIXPF_INUSE, &sp->flags))
printk(KERN_WARNING "%s: sp_free for already free unit.\n", sp->dev->name);
if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
sp->led_state = 0x70;
sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
sp->tx_enable = 1;
actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, sp->status2);
sp->xleft -= actual;
sp->xhead += actual;
sp->led_state = 0x60;
sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
sp->status2 = 0;
} else
sp_start_tx_timer(sp);
}
/* Send one completely decapsulated IP datagram to the IP layer. */
/* This is the routine that sends the received data to the kernel AX.25.
'cmd' is the KISS command. For AX.25 data, it is zero. */
static void sp_bump(struct sixpack *sp, char cmd)
/* ----> 6pack timer interrupt handler and friends. <---- */
static void sp_start_tx_timer(struct sixpack *sp)
{
struct sk_buff *skb;
int count;
unsigned char *ptr;
count = sp->rcount+1;
sp->stats.rx_bytes += count;
if ((skb = dev_alloc_skb(count)) == NULL) {
printk(KERN_DEBUG "%s: memory squeeze, dropping packet.\n", sp->dev->name);
sp->stats.rx_dropped++;
return;
}
skb->dev = sp->dev;
ptr = skb_put(skb, count);
*ptr++ = cmd; /* KISS command */
int when = sp->slottime;
memcpy(ptr, (sp->cooked_buf)+1, count);
skb->mac.raw = skb->data;
skb->protocol = htons(ETH_P_AX25);
netif_rx(skb);
sp->dev->last_rx = jiffies;
sp->stats.rx_packets++;
del_timer(&sp->tx_t);
sp->tx_t.data = (unsigned long) sp;
sp->tx_t.function = sp_xmit_on_air;
sp->tx_t.expires = jiffies + ((when + 1) * HZ) / 100;
add_timer(&sp->tx_t);
}
/* ----------------------------------------------------------------------- */
/* Encapsulate one AX.25 frame and stuff into a TTY queue. */
static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
{
unsigned char *p;
unsigned char *msg, *p = icp;
int actual, count;
if (len > sp->mtu) { /* sp->mtu = AX25_MTU = max. PACLEN = 256 */
printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n", sp->dev->name);
sp->stats.tx_dropped++;
netif_start_queue(sp->dev);
return;
msg = "oversized transmit packet!";
goto out_drop;
}
p = icp;
if (p[0] > 5) {
printk(KERN_DEBUG "%s: invalid KISS command -- dropped\n", sp->dev->name);
netif_start_queue(sp->dev);
return;
msg = "invalid KISS command";
goto out_drop;
}
if ((p[0] != 0) && (len > 2)) {
printk(KERN_DEBUG "%s: KISS control packet too long -- dropped\n", sp->dev->name);
netif_start_queue(sp->dev);
return;
msg = "KISS control packet too long";
goto out_drop;
}
if ((p[0] == 0) && (len < 15)) {
printk(KERN_DEBUG "%s: bad AX.25 packet to transmit -- dropped\n", sp->dev->name);
netif_start_queue(sp->dev);
sp->stats.tx_dropped++;
return;
msg = "bad AX.25 packet to transmit";
goto out_drop;
}
count = encode_sixpack(p, (unsigned char *) sp->xbuff, len, sp->tx_delay);
sp->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP);
count = encode_sixpack(p, sp->xbuff, len, sp->tx_delay);
set_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);
switch (p[0]) {
case 1: sp->tx_delay = p[1]; return;
case 2: sp->persistence = p[1]; return;
case 3: sp->slottime = p[1]; return;
case 4: /* ignored */ return;
case 5: sp->duplex = p[1]; return;
case 1: sp->tx_delay = p[1];
return;
case 2: sp->persistence = p[1];
return;
case 3: sp->slottime = p[1];
return;
case 4: /* ignored */
return;
case 5: sp->duplex = p[1];
return;
}
if (p[0] == 0) {
/* in case of fullduplex or DAMA operation, we don't take care
about the state of the DCD or of any timers, as the determination
of the correct time to send is the job of the AX.25 layer. We send
immediately after data has arrived. */
if (p[0] != 0)
return;
/*
* In case of fullduplex or DAMA operation, we don't take care about the
* state of the DCD or of any timers, as the determination of the
* correct time to send is the job of the AX.25 layer. We send
* immediately after data has arrived.
*/
if (sp->duplex == 1) {
sp->led_state = 0x70;
sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
......@@ -329,87 +243,62 @@ static void sp_encaps(struct sixpack *sp, unsigned char *icp, int len)
if (sp->duplex == 0)
sp_start_tx_timer(sp);
}
}
}
/*
* Called by the TTY driver when there's room for more data. If we have
* more packets to send, we send them here.
*/
static void sixpack_write_wakeup(struct tty_struct *tty)
{
int actual;
struct sixpack *sp = (struct sixpack *) tty->disc_data;
/* First make sure we're connected. */
if (!sp || sp->magic != SIXPACK_MAGIC ||
!netif_running(sp->dev))
return;
if (sp->xleft <= 0) {
/* Now serial buffer is almost free & we can start
* transmission of another packet */
sp->stats.tx_packets++;
tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
sp->tx_enable = 0;
netif_wake_queue(sp->dev);
out_drop:
sp->stats.tx_dropped++;
netif_start_queue(sp->dev);
printk(KERN_DEBUG "%s: %s - dropped.\n", sp->dev->name, msg);
return;
}
if (sp->tx_enable == 1) {
actual = tty->driver->write(tty, 0, sp->xhead, sp->xleft);
sp->xleft -= actual;
sp->xhead += actual;
}
}
/* ----------------------------------------------------------------------- */
/* Encapsulate an IP datagram and kick it into a TTY queue. */
static int sp_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct sixpack *sp = (struct sixpack *) dev->priv;
struct sixpack *sp = netdev_priv(dev);
spin_lock_bh(&sp->lock);
/* We were not busy, so we are now... :-) */
netif_stop_queue(dev);
sp->stats.tx_bytes += skb->len;
sp_encaps(sp, skb->data, skb->len);
spin_unlock_bh(&sp->lock);
dev_kfree_skb(skb);
return 0;
}
static int sp_open_dev(struct net_device *dev)
{
struct sixpack *sp = netdev_priv(dev);
/* perform the persistence/slottime algorithm for CSMA access. If the persistence
check was successful, write the data to the serial driver. Note that in case
of DAMA operation, the data is not sent here. */
if (sp->tty == NULL)
return -ENODEV;
return 0;
}
static void sp_xmit_on_air(unsigned long channel)
/* Close the low-level part of the 6pack channel. */
static int sp_close(struct net_device *dev)
{
struct sixpack *sp = (struct sixpack *) channel;
int actual;
static unsigned char random;
struct sixpack *sp = netdev_priv(dev);
random = random * 17 + 41;
spin_lock_bh(&sp->lock);
if (sp->tty) {
/* TTY discipline is running. */
clear_bit(TTY_DO_WRITE_WAKEUP, &sp->tty->flags);
}
netif_stop_queue(dev);
spin_unlock_bh(&sp->lock);
if (((sp->status1 & SIXP_DCD_MASK) == 0) && (random < sp->persistence)) {
sp->led_state = 0x70;
sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
sp->tx_enable = 1;
actual = sp->tty->driver->write(sp->tty, 0, sp->xbuff, sp->status2);
sp->xleft -= actual;
sp->xhead += actual;
sp->led_state = 0x60;
sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
sp->status2 = 0;
} else
sp_start_tx_timer(sp);
return 0;
}
/* Return the frame type ID */
static int sp_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
void *daddr, void *saddr, unsigned len)
static int sp_header(struct sk_buff *skb, struct net_device *dev,
unsigned short type, void *daddr, void *saddr, unsigned len)
{
#ifdef CONFIG_INET
if (type != htons(ETH_P_AX25))
......@@ -418,6 +307,18 @@ static int sp_header(struct sk_buff *skb, struct net_device *dev, unsigned short
return 0;
}
static struct net_device_stats *sp_get_stats(struct net_device *dev)
{
struct sixpack *sp = netdev_priv(dev);
return &sp->stats;
}
static int sp_set_dev_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *sa = addr;
memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN);
return 0;
}
static int sp_rebuild_header(struct sk_buff *skb)
{
......@@ -428,13 +329,203 @@ static int sp_rebuild_header(struct sk_buff *skb)
#endif
}
static void sp_setup(struct net_device *dev)
{
static char ax25_bcast[AX25_ADDR_LEN] =
{'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
static char ax25_test[AX25_ADDR_LEN] =
{'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
/* Finish setting up the DEVICE info. */
dev->init = sixpack_init;
dev->mtu = SIXP_MTU;
dev->hard_start_xmit = sp_xmit;
dev->open = sp_open_dev;
dev->destructor = free_netdev;
dev->stop = sp_close;
dev->hard_header = sp_header;
dev->get_stats = sp_get_stats;
dev->set_mac_address = sp_set_dev_mac_address;
dev->hard_header_len = AX25_MAX_HEADER_LEN;
dev->addr_len = AX25_ADDR_LEN;
dev->type = ARPHRD_AX25;
dev->tx_queue_len = 10;
dev->rebuild_header = sp_rebuild_header;
dev->tx_timeout = NULL;
/* Only activated in AX.25 mode */
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN);
memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN);
SET_MODULE_OWNER(dev);
/* New-style flags. */
dev->flags = 0;
}
/* Find a free 6pack channel, and link in this `tty' line. */
static inline struct sixpack *sp_alloc(void)
{
struct sixpack *sp = NULL;
struct net_device *dev = NULL;
dev = alloc_netdev(sizeof(struct sixpack), "sp%d", sp_setup);
if (!dev)
return NULL;
sp = netdev_priv(dev);
sp->dev = dev;
spin_lock_init(&sp->lock);
if (register_netdev(dev))
goto out_free;
return sp;
out_free:
printk(KERN_WARNING "sp_alloc() - register_netdev() failure.\n");
free_netdev(dev);
return NULL;
}
/* Free a 6pack channel. */
static inline void sp_free(struct sixpack *sp)
{
void * tmp;
/* Free all 6pack frame buffers. */
if ((tmp = xchg(&sp->rbuff, NULL)) != NULL)
kfree(tmp);
if ((tmp = xchg(&sp->xbuff, NULL)) != NULL)
kfree(tmp);
}
/* Send one completely decapsulated IP datagram to the IP layer. */
/*
* This is the routine that sends the received data to the kernel AX.25.
* 'cmd' is the KISS command. For AX.25 data, it is zero.
*/
static void sp_bump(struct sixpack *sp, char cmd)
{
struct sk_buff *skb;
int count;
unsigned char *ptr;
count = sp->rcount + 1;
sp->stats.rx_bytes += count;
if ((skb = dev_alloc_skb(count)) == NULL)
goto out_mem;
skb->dev = sp->dev;
ptr = skb_put(skb, count);
*ptr++ = cmd; /* KISS command */
memcpy(ptr, sp->cooked_buf + 1, count);
skb->mac.raw = skb->data;
skb->protocol = htons(ETH_P_AX25);
netif_rx(skb);
sp->dev->last_rx = jiffies;
sp->stats.rx_packets++;
return;
out_mem:
sp->stats.rx_dropped++;
}
/* ----------------------------------------------------------------------- */
/*
* We have a potential race on dereferencing tty->disc_data, because the tty
* layer provides no locking at all - thus one cpu could be running
* sixpack_receive_buf while another calls sixpack_close, which zeroes
* tty->disc_data and frees the memory that sixpack_receive_buf is using. The
* best way to fix this is to use a rwlock in the tty struct, but for now we
* use a single global rwlock for all ttys in ppp line discipline.
*/
static rwlock_t disc_data_lock = RW_LOCK_UNLOCKED;
static struct sixpack *sp_get(struct tty_struct *tty)
{
struct sixpack *sp;
read_lock(&disc_data_lock);
sp = tty->disc_data;
if (sp)
atomic_inc(&sp->refcnt);
read_unlock(&disc_data_lock);
return sp;
}
static void sp_put(struct sixpack *sp)
{
if (atomic_dec_and_test(&sp->refcnt))
up(&sp->dead_sem);
}
/*
* Called by the TTY driver when there's room for more data. If we have
* more packets to send, we send them here.
*/
static void sixpack_write_wakeup(struct tty_struct *tty)
{
struct sixpack *sp = sp_get(tty);
int actual;
if (sp->xleft <= 0) {
/* Now serial buffer is almost free & we can start
* transmission of another packet */
sp->stats.tx_packets++;
clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
sp->tx_enable = 0;
netif_wake_queue(sp->dev);
goto out;
}
if (sp->tx_enable == 1) {
actual = tty->driver->write(tty, 0, sp->xhead, sp->xleft);
sp->xleft -= actual;
sp->xhead += actual;
}
out:
sp_put(sp);
}
/* ----------------------------------------------------------------------- */
/* Open the low-level part of the 6pack channel. */
static int sp_open(struct net_device *dev)
{
struct sixpack *sp = (struct sixpack *) dev->priv;
struct sixpack *sp = netdev_priv(dev);
char *rbuff, *xbuff = NULL;
int err = -ENOBUFS;
unsigned long len;
/* !!! length of the buffers. MTU is IP MTU, not PACLEN! */
len = dev->mtu * 2;
rbuff = kmalloc(len + 4, GFP_KERNEL);
if (rbuff == NULL)
goto err_exit;
xbuff = kmalloc(len + 4, GFP_KERNEL);
if (xbuff == NULL)
goto err_exit;
spin_lock_bh(&sp->lock);
if (sp->tty == NULL)
return -ENODEV;
......@@ -445,18 +536,8 @@ static int sp_open(struct net_device *dev)
* xbuff Transmit buffer.
*/
/* !!! length of the buffers. MTU is IP MTU, not PACLEN!
*/
len = dev->mtu * 2;
if ((sp->rbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL)
return -ENOMEM;
if ((sp->xbuff = kmalloc(len + 4, GFP_KERNEL)) == NULL) {
kfree(sp->rbuff);
return -ENOMEM;
}
rbuff = xchg(&sp->rbuff, rbuff);
xbuff = xchg(&sp->xbuff, xbuff);
sp->mtu = AX25_MTU + 73;
sp->buffsize = len;
......@@ -465,7 +546,7 @@ static int sp_open(struct net_device *dev)
sp->rx_count_cooked = 0;
sp->xleft = 0;
sp->flags &= (1 << SIXPF_INUSE); /* Clear ESCAPE & ERROR flags */
sp->flags = 0; /* Clear ESCAPE & ERROR flags */
sp->duplex = 0;
sp->tx_delay = SIXP_TXDELAY;
......@@ -482,62 +563,121 @@ static int sp_open(struct net_device *dev)
init_timer(&sp->tx_t);
init_timer(&sp->resync_t);
return 0;
}
spin_unlock_bh(&sp->lock);
/* Close the low-level part of the 6pack channel. */
static int sp_close(struct net_device *dev)
{
struct sixpack *sp = (struct sixpack *) dev->priv;
err = 0;
if (sp->tty == NULL)
return -EBUSY;
err_exit:
if (xbuff)
kfree(xbuff);
if (rbuff)
kfree(rbuff);
sp->tty->flags &= ~(1 << TTY_DO_WRITE_WAKEUP);
netif_stop_queue(dev);
return 0;
return err;
}
static int sixpack_receive_room(struct tty_struct *tty)
{
return 65536; /* We can handle an infinite amount of data. :-) */
}
/* !!! receive state machine */
/*
* Handle the 'receiver data ready' interrupt.
* This function is called by the 'tty_io' module in the kernel when
* a block of 6pack data has been received, which can now be decapsulated
* and sent on to some IP layer for further processing.
*/
static void sixpack_receive_buf(struct tty_struct *tty,
const unsigned char *cp, char *fp, int count)
{
struct sixpack *sp;
unsigned char buf[512];
int count1;
if (!count)
return;
sp = sp_get(tty);
if (!sp)
return;
memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf));
/* Read the characters out of the buffer */
count1 = count;
while (count) {
count--;
if (fp && *fp++) {
if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))
sp->stats.rx_errors++;
continue;
}
}
sixpack_decode(sp, buf, count1);
sp_put(sp);
if (test_and_clear_bit(TTY_THROTTLED, &tty->flags)
&& tty->driver->unthrottle)
tty->driver->unthrottle(tty);
}
/*
* Try to resync the TNC. Called by the resync timer defined in
* decode_prio_command
*/
static void resync_tnc(unsigned long channel)
{
struct sixpack *sp = (struct sixpack *) channel;
struct net_device *dev = sp->dev;
static char resync_cmd = 0xe8;
printk(KERN_INFO "%s: resyncing TNC\n", dev->name);
/* clear any data that might have been received */
sp->rx_count = 0;
sp->rx_count_cooked = 0;
/* reset state machine */
sp->status = 1;
sp->status1 = 1;
sp->status2 = 0;
sp->tnc_ok = 0;
/* resync the TNC */
sp->led_state = 0x60;
sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
sp->tty->driver->write(sp->tty, 0, &resync_cmd, 1);
/*
* Handle the 'receiver data ready' interrupt.
* This function is called by the 'tty_io' module in the kernel when
* a block of 6pack data has been received, which can now be decapsulated
* and sent on to some IP layer for further processing.
*/
static void sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
{
unsigned char buf[512];
int count1;
struct sixpack *sp = (struct sixpack *) tty->disc_data;
/* Start resync timer again -- the TNC might be still absent */
if (!sp || sp->magic != SIXPACK_MAGIC ||
!netif_running(sp->dev) || !count)
return;
del_timer(&sp->resync_t);
sp->resync_t.data = (unsigned long) sp;
sp->resync_t.function = resync_tnc;
sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
add_timer(&sp->resync_t);
}
memcpy(buf, cp, count<sizeof(buf)? count:sizeof(buf));
static inline int tnc_init(struct sixpack *sp)
{
unsigned char inbyte = 0xe8;
/* Read the characters out of the buffer */
sp->tty->driver->write(sp->tty, 0, &inbyte, 1);
count1 = count;
while (count) {
count--;
if (fp && *fp++) {
if (!test_and_set_bit(SIXPF_ERROR, &sp->flags))
sp->stats.rx_errors++;
continue;
}
}
sixpack_decode(sp, buf, count1);
del_timer(&sp->resync_t);
sp->resync_t.data = (unsigned long) sp;
sp->resync_t.function = resync_tnc;
sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
add_timer(&sp->resync_t);
return 0;
}
/*
......@@ -549,37 +689,33 @@ static void sixpack_receive_buf(struct tty_struct *tty, const unsigned char *cp,
*/
static int sixpack_open(struct tty_struct *tty)
{
struct sixpack *sp = (struct sixpack *) tty->disc_data;
int err;
struct sixpack *sp;
int err = 0;
/* First make sure we're not already connected. */
if (!capable(CAP_NET_ADMIN))
return -EPERM;
if (sp && sp->magic == SIXPACK_MAGIC)
return -EEXIST;
sp = sp_alloc();
if (!sp) {
err = -ENOMEM;
goto out;
}
/* OK. Find a free 6pack channel to use. */
if ((sp = sp_alloc()) == NULL)
return -ENFILE;
sp->tty = tty;
tty->disc_data = sp;
if (tty->driver->flush_buffer)
tty->driver->flush_buffer(tty);
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
/* Restore default settings */
sp->dev->type = ARPHRD_AX25;
atomic_set(&sp->refcnt, 1);
init_MUTEX_LOCKED(&sp->dead_sem);
/* Perform the low-level 6pack initialization. */
if ((err = sp_open(sp->dev)))
return err;
goto out;
/* Done. We have linked the TTY line to a channel. */
tty->disc_data = sp;
tnc_init(sp);
return sp->dev->base_addr;
out:
return err;
}
......@@ -593,102 +729,93 @@ static void sixpack_close(struct tty_struct *tty)
{
struct sixpack *sp = (struct sixpack *) tty->disc_data;
/* First make sure we're connected. */
if (!sp || sp->magic != SIXPACK_MAGIC)
write_lock(&disc_data_lock);
sp = tty->disc_data;
tty->disc_data = 0;
write_unlock(&disc_data_lock);
if (sp == 0)
return;
rtnl_lock();
dev_close(sp->dev);
/*
* We have now ensured that nobody can start using ap from now on, but
* we have to wait for all existing users to finish.
*/
if (!atomic_dec_and_test(&sp->refcnt))
down(&sp->dead_sem);
del_timer(&sp->tx_t);
del_timer(&sp->resync_t);
tty->disc_data = 0;
sp->tty = NULL;
sp_free(sp);
unregister_netdevice(sp->dev);
rtnl_unlock();
}
static struct net_device_stats *sp_get_stats(struct net_device *dev)
{
struct sixpack *sp = (struct sixpack *) dev->priv;
return &sp->stats;
unregister_netdev(sp->dev);
}
static int sp_set_mac_address(struct net_device *dev, void *addr)
{
return copy_from_user(dev->dev_addr, addr, AX25_ADDR_LEN) ? -EFAULT : 0;
}
static int sp_set_dev_mac_address(struct net_device *dev, void *addr)
{
struct sockaddr *sa = addr;
memcpy(dev->dev_addr, sa->sa_data, AX25_ADDR_LEN);
return 0;
}
/* Perform I/O control on an active 6pack channel. */
static int sixpack_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg)
static int sixpack_ioctl(struct tty_struct *tty, struct file *file,
unsigned int cmd, unsigned long arg)
{
struct sixpack *sp = (struct sixpack *) tty->disc_data;
unsigned int tmp;
struct sixpack *sp = sp_get(tty);
unsigned int tmp, err;
/* First make sure we're connected. */
if (!sp || sp->magic != SIXPACK_MAGIC)
return -EINVAL;
if (!sp)
return -ENXIO;
switch(cmd) {
case SIOCGIFNAME:
return copy_to_user(arg, sp->dev->name, strlen(sp->dev->name) + 1) ? -EFAULT : 0;
err = copy_to_user((void *) arg, sp->dev->name,
strlen(sp->dev->name) + 1) ? -EFAULT : 0;
break;
case SIOCGIFENCAP:
return put_user(0, (int *)arg);
err = put_user(0, (int *)arg);
break;
case SIOCSIFENCAP:
if (get_user(tmp, (int *) arg))
return -EFAULT;
if (get_user(tmp, (int *) arg)) {
err = -EFAULT;
break;
}
sp->mode = tmp;
sp->dev->addr_len = AX25_ADDR_LEN; /* sizeof an AX.25 addr */
sp->dev->hard_header_len = AX25_KISS_HEADER_LEN + AX25_MAX_HEADER_LEN + 3;
sp->dev->type = ARPHRD_AX25;
return 0;
err = 0;
break;
case SIOCSIFHWADDR:
return sp_set_mac_address(sp->dev, arg);
err = sp_set_mac_address(sp->dev, (void *) arg);
break;
/* Allow stty to read, but not set, the serial port */
case TCGETS:
case TCGETA:
return n_tty_ioctl(tty, (struct file *) file, cmd, (unsigned long) arg);
err = n_tty_ioctl(tty, (struct file *) file, cmd, arg);
break;
default:
return -ENOIOCTLCMD;
}
}
static int sp_open_dev(struct net_device *dev)
{
struct sixpack *sp = (struct sixpack *) dev->priv;
if (sp->tty == NULL)
return -ENODEV;
return 0;
sp_put(sp);
return err;
}
/* Fill in our line protocol discipline */
static struct tty_ldisc sp_ldisc = {
.owner = THIS_MODULE,
.magic = TTY_LDISC_MAGIC,
.name = "6pack",
.open = sixpack_open,
.close = sixpack_close,
.ioctl = (int (*)(struct tty_struct *, struct file *,
unsigned int, unsigned long)) sixpack_ioctl,
.ioctl = sixpack_ioctl,
.receive_buf = sixpack_receive_buf,
.receive_room = sixpack_receive_room,
.write_wakeup = sixpack_write_wakeup,
......@@ -696,34 +823,18 @@ static struct tty_ldisc sp_ldisc = {
/* Initialize 6pack control device -- register 6pack line discipline */
static char msg_banner[] __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION " (dynamic channels, max=%d)\n";
static char msg_nomem[] __initdata = KERN_ERR "6pack: can't allocate sixpack_ctrls[] array! No 6pack available.\n";
static char msg_banner[] __initdata = KERN_INFO "AX.25: 6pack driver, " SIXPACK_VERSION "\n";
static char msg_regfail[] __initdata = KERN_ERR "6pack: can't register line discipline (err = %d)\n";
static int __init sixpack_init_driver(void)
{
int status;
/* Do sanity checks on maximum device parameter. */
if (sixpack_maxdev < 4)
sixpack_maxdev = 4;
printk(msg_banner, sixpack_maxdev);
sixpack_ctrls = (sixpack_ctrl_t **) kmalloc(sizeof(void*)*sixpack_maxdev, GFP_KERNEL);
if (sixpack_ctrls == NULL) {
printk(msg_nomem);
return -ENOMEM;
}
/* Clear the pointer array, we allocate devices when we need them */
memset(sixpack_ctrls, 0, sizeof(void*)*sixpack_maxdev); /* Pointers */
printk(msg_banner);
/* Register the provided line protocol discipline */
if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0) {
if ((status = tty_register_ldisc(N_6PACK, &sp_ldisc)) != 0)
printk(msg_regfail, status);
kfree(sixpack_ctrls);
}
return status;
}
......@@ -732,36 +843,16 @@ static const char msg_unregfail[] __exitdata = KERN_ERR "6pack: can't unregister
static void __exit sixpack_exit_driver(void)
{
int i;
if ((i = tty_register_ldisc(N_6PACK, NULL)))
printk(msg_unregfail, i);
for (i = 0; i < sixpack_maxdev; i++) {
if (sixpack_ctrls[i]) {
/*
* VSV = if dev->start==0, then device
* unregistered while close proc.
*/
if (netif_running(&sixpack_ctrls[i]->dev))
unregister_netdev(&sixpack_ctrls[i]->dev);
int ret;
kfree(sixpack_ctrls[i]);
}
}
kfree(sixpack_ctrls);
if ((ret = tty_register_ldisc(N_6PACK, NULL)))
printk(msg_unregfail, ret);
}
/* Initialize the 6pack driver. Called by DDI. */
static int sixpack_init(struct net_device *dev)
{
struct sixpack *sp = (struct sixpack *) dev->priv;
static char ax25_bcast[AX25_ADDR_LEN] =
{'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1};
static char ax25_test[AX25_ADDR_LEN] =
{'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1};
struct sixpack *sp = netdev_priv(dev);
if (sp == NULL) /* Allocation failed ?? */
return -ENODEV;
......@@ -769,52 +860,15 @@ static int sixpack_init(struct net_device *dev)
/* Set up the "6pack Control Block". (And clear statistics) */
memset(sp, 0, sizeof (struct sixpack));
sp->magic = SIXPACK_MAGIC;
sp->dev = dev;
/* Finish setting up the DEVICE info. */
dev->mtu = SIXP_MTU;
dev->hard_start_xmit = sp_xmit;
dev->open = sp_open_dev;
dev->stop = sp_close;
dev->hard_header = sp_header;
dev->get_stats = sp_get_stats;
dev->set_mac_address = sp_set_dev_mac_address;
dev->hard_header_len = AX25_MAX_HEADER_LEN;
dev->addr_len = AX25_ADDR_LEN;
dev->type = ARPHRD_AX25;
dev->tx_queue_len = 10;
dev->rebuild_header = sp_rebuild_header;
dev->tx_timeout = NULL;
memcpy(dev->broadcast, ax25_bcast, AX25_ADDR_LEN); /* Only activated in AX.25 mode */
memcpy(dev->dev_addr, ax25_test, AX25_ADDR_LEN); /* "" "" "" "" */
/* New-style flags. */
dev->flags = 0;
return 0;
}
/* ----> 6pack timer interrupt handler and friends. <---- */
static void sp_start_tx_timer(struct sixpack *sp)
{
int when = sp->slottime;
del_timer(&sp->tx_t);
sp->tx_t.data = (unsigned long) sp;
sp->tx_t.function = sp_xmit_on_air;
sp->tx_t.expires = jiffies + ((when+1)*HZ)/100;
add_timer(&sp->tx_t);
}
/* encode an AX.25 packet into 6pack */
static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, int length, unsigned char tx_delay)
static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw,
int length, unsigned char tx_delay)
{
int count = 0;
unsigned char checksum = 0, buf[400];
......@@ -849,47 +903,28 @@ static int encode_sixpack(unsigned char *tx_buf, unsigned char *tx_buf_raw, int
return raw_count;
}
/* decode 4 sixpack-encoded bytes into 3 data bytes */
/* decode a 6pack packet */
static void
sixpack_decode(struct sixpack *sp, unsigned char pre_rbuff[], int count)
{
unsigned char inbyte;
int count1;
for (count1 = 0; count1 < count; count1++) {
inbyte = pre_rbuff[count1];
if (inbyte == SIXP_FOUND_TNC) {
printk(KERN_INFO "6pack: TNC found.\n");
sp->tnc_ok = 1;
del_timer(&sp->resync_t);
}
if ((inbyte & SIXP_PRIO_CMD_MASK) != 0)
decode_prio_command(inbyte, sp);
else if ((inbyte & SIXP_STD_CMD_MASK) != 0)
decode_std_command(inbyte, sp);
else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)
decode_data(inbyte, sp);
}
}
static int tnc_init(struct sixpack *sp)
static void decode_data(unsigned char inbyte, struct sixpack *sp)
{
unsigned char inbyte = 0xe8;
unsigned char *buf;
sp->tty->driver->write(sp->tty, 0, &inbyte, 1);
if (sp->rx_count != 3) {
sp->raw_buf[sp->rx_count++] = inbyte;
del_timer(&sp->resync_t);
sp->resync_t.data = (unsigned long) sp;
sp->resync_t.function = resync_tnc;
sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
add_timer(&sp->resync_t);
return;
}
return 0;
buf = sp->raw_buf;
sp->cooked_buf[sp->rx_count_cooked++] =
buf[0] | ((buf[1] << 2) & 0xc0);
sp->cooked_buf[sp->rx_count_cooked++] =
(buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0);
sp->cooked_buf[sp->rx_count_cooked++] =
(buf[2] & 0x03) | (inbyte << 2);
sp->rx_count = 0;
}
/* identify and execute a 6pack priority command byte */
static void decode_prio_command(unsigned char cmd, struct sixpack *sp)
......@@ -916,8 +951,7 @@ static void decode_prio_command(unsigned char cmd, struct sixpack *sp)
cmd &= !SIXP_RX_DCD_MASK;
}
sp->status = cmd & SIXP_PRIO_DATA_MASK;
}
else { /* output watchdog char if idle */
} else { /* output watchdog char if idle */
if ((sp->status2 != 0) && (sp->duplex == 1)) {
sp->led_state = 0x70;
sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
......@@ -948,46 +982,6 @@ static void decode_prio_command(unsigned char cmd, struct sixpack *sp)
sp->status1 = cmd & SIXP_PRIO_DATA_MASK;
}
/* try to resync the TNC. Called by the resync timer defined in
decode_prio_command */
static void resync_tnc(unsigned long channel)
{
static char resync_cmd = 0xe8;
struct sixpack *sp = (struct sixpack *) channel;
printk(KERN_INFO "6pack: resyncing TNC\n");
/* clear any data that might have been received */
sp->rx_count = 0;
sp->rx_count_cooked = 0;
/* reset state machine */
sp->status = 1;
sp->status1 = 1;
sp->status2 = 0;
sp->tnc_ok = 0;
/* resync the TNC */
sp->led_state = 0x60;
sp->tty->driver->write(sp->tty, 0, &sp->led_state, 1);
sp->tty->driver->write(sp->tty, 0, &resync_cmd, 1);
/* Start resync timer again -- the TNC might be still absent */
del_timer(&sp->resync_t);
sp->resync_t.data = (unsigned long) sp;
sp->resync_t.function = resync_tnc;
sp->resync_t.expires = jiffies + SIXP_RESYNC_TIMEOUT;
add_timer(&sp->resync_t);
}
/* identify and execute a standard 6pack command byte */
static void decode_std_command(unsigned char cmd, struct sixpack *sp)
......@@ -1036,28 +1030,31 @@ static void decode_std_command(unsigned char cmd, struct sixpack *sp)
}
}
/* decode 4 sixpack-encoded bytes into 3 data bytes */
/* decode a 6pack packet */
static void decode_data(unsigned char inbyte, struct sixpack *sp)
static void
sixpack_decode(struct sixpack *sp, unsigned char pre_rbuff[], int count)
{
unsigned char *buf;
unsigned char inbyte;
int count1;
if (sp->rx_count != 3)
sp->raw_buf[sp->rx_count++] = inbyte;
else {
buf = sp->raw_buf;
sp->cooked_buf[sp->rx_count_cooked++] =
buf[0] | ((buf[1] << 2) & 0xc0);
sp->cooked_buf[sp->rx_count_cooked++] =
(buf[1] & 0x0f) | ((buf[2] << 2) & 0xf0);
sp->cooked_buf[sp->rx_count_cooked++] =
(buf[2] & 0x03) | (inbyte << 2);
sp->rx_count = 0;
for (count1 = 0; count1 < count; count1++) {
inbyte = pre_rbuff[count1];
if (inbyte == SIXP_FOUND_TNC) {
printk(KERN_INFO "6pack: TNC found.\n");
sp->tnc_ok = 1;
del_timer(&sp->resync_t);
}
if ((inbyte & SIXP_PRIO_CMD_MASK) != 0)
decode_prio_command(inbyte, sp);
else if ((inbyte & SIXP_STD_CMD_MASK) != 0)
decode_std_command(inbyte, sp);
else if ((sp->status & SIXP_RX_DCD_MASK) == SIXP_RX_DCD_MASK)
decode_data(inbyte, sp);
}
}
MODULE_AUTHOR("Andreas Knsgen <ajk@ccac.rwth-aachen.de>");
MODULE_AUTHOR("Ralf Baechle DO1GRB <ralf@linux-mips.org>");
MODULE_DESCRIPTION("6pack driver for AX.25");
MODULE_LICENSE("GPL");
MODULE_ALIAS_LDISC(N_6PACK);
......
......@@ -123,7 +123,7 @@ static void emulate_large_send_offload(struct sk_buff *skb)
*/
static int loopback_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct net_device_stats *stats = netdev_priv(dev);
struct net_device_stats *stats = dev->priv;
skb_orphan(skb);
......
......@@ -28,8 +28,8 @@
*/
#define DRV_NAME "de2104x"
#define DRV_VERSION "0.6"
#define DRV_RELDATE "Sep 1, 2003"
#define DRV_VERSION "0.7"
#define DRV_RELDATE "Mar 17, 2004"
#include <linux/config.h>
#include <linux/module.h>
......@@ -303,7 +303,6 @@ struct de_private {
struct net_device_stats net_stats;
struct pci_dev *pdev;
u32 macmode;
u16 setup_frame[DE_SETUP_FRAME_WORDS];
......@@ -732,7 +731,7 @@ static void __de_set_rx_mode (struct net_device *dev)
struct de_desc *txd;
struct de_desc *dummy_txd = NULL;
macmode = de->macmode & ~(AcceptAllMulticast | AcceptAllPhys);
macmode = dr32(MacMode) & ~(AcceptAllMulticast | AcceptAllPhys);
if (dev->flags & IFF_PROMISC) { /* Set promiscuous. */
macmode |= AcceptAllMulticast | AcceptAllPhys;
......@@ -805,10 +804,8 @@ static void __de_set_rx_mode (struct net_device *dev)
dw32(TxPoll, NormalTxPoll);
out:
if (macmode != de->macmode) {
dw32 (MacMode, macmode);
de->macmode = macmode;
}
if (macmode != dr32(MacMode))
dw32(MacMode, macmode);
}
static void de_set_rx_mode (struct net_device *dev)
......@@ -923,6 +920,7 @@ static void de_link_down(struct de_private *de)
static void de_set_media (struct de_private *de)
{
unsigned media = de->media_type;
u32 macmode = dr32(MacMode);
if (de_is_running(de))
BUG();
......@@ -940,9 +938,9 @@ static void de_set_media (struct de_private *de)
mdelay(10);
if (media == DE_MEDIA_TP_FD)
de->macmode |= FullDuplex;
macmode |= FullDuplex;
else
de->macmode &= ~FullDuplex;
macmode &= ~FullDuplex;
if (netif_msg_link(de)) {
printk(KERN_INFO "%s: set link %s\n"
......@@ -951,9 +949,11 @@ static void de_set_media (struct de_private *de)
de->dev->name, media_name[media],
de->dev->name, dr32(MacMode), dr32(SIAStatus),
dr32(CSR13), dr32(CSR14), dr32(CSR15),
de->dev->name, de->macmode, de->media[media].csr13,
de->dev->name, macmode, de->media[media].csr13,
de->media[media].csr14, de->media[media].csr15);
}
if (macmode != dr32(MacMode))
dw32(MacMode, macmode);
}
static void de_next_media (struct de_private *de, u32 *media,
......@@ -1173,18 +1173,18 @@ static int de_reset_mac (struct de_private *de)
u32 status, tmp;
/*
* Reset MAC. Copied from de4x5.c.
* Reset MAC. de4x5.c and tulip.c examined for "advice"
* in this area.
*/
tmp = dr32 (BusMode);
if (tmp == 0xffffffff)
return -ENODEV;
mdelay (1);
if (dr32(BusMode) == 0xffffffff)
return -EBUSY;
dw32 (BusMode, tmp | CmdReset);
/* Reset the chip, holding bit 0 set at least 50 PCI cycles. */
dw32 (BusMode, CmdReset);
mdelay (1);
dw32 (BusMode, tmp);
dw32 (BusMode, de_bus_mode);
mdelay (1);
for (tmp = 0; tmp < 5; tmp++) {
......@@ -1235,11 +1235,12 @@ static void de_adapter_sleep (struct de_private *de)
static int de_init_hw (struct de_private *de)
{
struct net_device *dev = de->dev;
u32 macmode;
int rc;
de_adapter_wake(de);
de->macmode = dr32(MacMode) & ~MacModeClear;
macmode = dr32(MacMode) & ~MacModeClear;
rc = de_reset_mac(de);
if (rc)
......@@ -1250,7 +1251,7 @@ static int de_init_hw (struct de_private *de)
dw32(RxRingAddr, de->ring_dma);
dw32(TxRingAddr, de->ring_dma + (sizeof(struct de_desc) * DE_RX_RING_SIZE));
dw32(MacMode, RxTx | de->macmode);
dw32(MacMode, RxTx | macmode);
dr32(RxMissed); /* self-clearing */
......@@ -1501,7 +1502,7 @@ static int __de_get_settings(struct de_private *de, struct ethtool_cmd *ecmd)
break;
}
if (de->macmode & FullDuplex)
if (dr32(MacMode) & FullDuplex)
ecmd->duplex = DUPLEX_FULL;
else
ecmd->duplex = DUPLEX_HALF;
......
......@@ -253,8 +253,9 @@ static void tulip_down(struct net_device *dev);
static struct net_device_stats *tulip_get_stats(struct net_device *dev);
static int private_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
static void set_rx_mode(struct net_device *dev);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void poll_tulip(struct net_device *dev);
#endif
static void tulip_set_power_state (struct tulip_private *tp,
int sleep, int snooze)
......
......@@ -307,10 +307,10 @@ config PCMCIA_WL3501
It has basic support for Linux wireless extensions and initial
micro support for ethtool.
comment "Prism GT/Duette 802.11(a/b/g) PCI/PCMCIA support"
comment "Prism GT/Duette 802.11(a/b/g) PCI/Cardbus support"
depends on NET_RADIO && PCI
config PRISM54
tristate 'Intersil Prism GT/Duette/Indigo PCI/PCMCIA'
tristate 'Intersil Prism GT/Duette/Indigo PCI/Cardbus'
depends on PCI && NET_RADIO && EXPERIMENTAL && HOTPLUG
select FW_LOADER
---help---
......@@ -337,6 +337,7 @@ config PRISM54
Sitecom WL-110i PCI Card
SMC2802W - EZ Connect g 2.4GHz 54 Mbps Wireless PCI Card
SMC2835W - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card
SMC2835W-V2 - EZ Connect g 2.4GHz 54 Mbps Wireless Cardbus Card
Z-Com XG-900 PCI Card
Zyxel G-100 Cardbus Card
......
......@@ -25,6 +25,7 @@
#include <linux/kernel.h>
#include <linux/if_arp.h>
#include <linux/pci.h>
#include <linux/moduleparam.h>
#include <asm/uaccess.h>
......@@ -44,26 +45,26 @@ static int init_dot1x = CARD_DEFAULT_DOT1X;
static int init_conformance = CARD_DEFAULT_CONFORMANCE;
static int init_mlme = CARD_DEFAULT_MLME_MODE;
MODULE_PARM(init_mode, "i");
module_param(init_mode, int, 0);
MODULE_PARM_DESC(init_mode,
"Set card mode:\n0: Auto\n1: Ad-Hoc\n2: Managed Client (Default)\n3: Master / Access Point\n4: Repeater (Not supported yet)\n5: Secondary (Not supported yet)\n6: Monitor");
MODULE_PARM(init_channel, "i");
module_param(init_channel, int, 0);
MODULE_PARM_DESC(init_channel,
"Check `iwpriv ethx channel` for available channels");
MODULE_PARM(init_wep, "i");
MODULE_PARM(init_filter, "i");
module_param(init_wep, int, 0);
module_param(init_filter, int, 0);
MODULE_PARM(init_authen, "i");
module_param(init_authen, int, 0);
MODULE_PARM_DESC(init_authen,
"Authentication method. Can be of seven types:\n0 0x0000: None\n1 0x0001: DOT11_AUTH_OS (Default)\n2 0x0002: DOT11_AUTH_SK\n3 0x0003: DOT11_AUTH_BOTH");
MODULE_PARM(init_dot1x, "i");
module_param(init_dot1x, int, 0);
MODULE_PARM_DESC(init_dot1x,
"\n0: None/not set (Default)\n1: DOT11_DOT1X_AUTHENABLED\n2: DOT11_DOT1X_KEYTXENABLED");
MODULE_PARM(init_mlme, "i");
module_param(init_mlme, int, 0);
MODULE_PARM_DESC(init_mlme,
"Sets the MAC layer management entity (MLME) mode of operation,\n0: DOT11_MLME_AUTO (Default)\n1: DOT11_MLME_INTERMEDIATE\n2: DOT11_MLME_EXTENDED");
......@@ -250,7 +251,7 @@ prism54_update_stats(islpci_private *priv)
struct iw_statistics *
prism54_get_wireless_stats(struct net_device *ndev)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
/* If the stats are being updated return old data */
if (down_trylock(&priv->stats_sem) == 0) {
......@@ -277,7 +278,7 @@ static int
prism54_commit(struct net_device *ndev, struct iw_request_info *info,
char *cwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
/* simply re-set the last set SSID, this should commit most stuff */
......@@ -293,7 +294,7 @@ static int
prism54_get_name(struct net_device *ndev, struct iw_request_info *info,
char *cwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
char *capabilities;
union oid_res_t r;
int rvalue;
......@@ -324,7 +325,7 @@ static int
prism54_set_freq(struct net_device *ndev, struct iw_request_info *info,
struct iw_freq *fwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
int rvalue;
u32 c = 0;
......@@ -363,7 +364,7 @@ static int
prism54_get_freq(struct net_device *ndev, struct iw_request_info *info,
struct iw_freq *fwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
union oid_res_t r;
int rvalue;
......@@ -379,7 +380,7 @@ static int
prism54_set_mode(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
u32 mlmeautolevel = CARD_DEFAULT_MLME_MODE;
/* Let's see if the user passed a valid Linux Wireless mode */
......@@ -420,7 +421,7 @@ static int
prism54_get_mode(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
BUG_ON((priv->iw_mode < IW_MODE_AUTO) || (priv->iw_mode >
IW_MODE_MONITOR));
......@@ -438,7 +439,7 @@ static int
prism54_set_sens(struct net_device *ndev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
u32 sens;
/* by default the card sets this to 20. */
......@@ -452,7 +453,7 @@ static int
prism54_get_sens(struct net_device *ndev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
union oid_res_t r;
int rvalue;
......@@ -470,7 +471,7 @@ prism54_get_range(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
struct iw_range *range = (struct iw_range *) extra;
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
char *data;
int i, m, rvalue;
struct obj_frequencies *freq;
......@@ -576,7 +577,7 @@ static int
prism54_set_wap(struct net_device *ndev, struct iw_request_info *info,
struct sockaddr *awrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
char bssid[6];
int rvalue;
......@@ -598,7 +599,7 @@ static int
prism54_get_wap(struct net_device *ndev, struct iw_request_info *info,
struct sockaddr *awrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
union oid_res_t r;
int rvalue;
......@@ -630,7 +631,7 @@ prism54_translate_bss(struct net_device *ndev, char *current_ev,
{
struct iw_event iwe; /* Temporary buffer */
short cap;
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
/* The first entry must be the MAC address */
memcpy(iwe.u.ap_addr.sa_data, bss->address, 6);
......@@ -721,7 +722,7 @@ int
prism54_get_scan(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
int i, rvalue;
struct obj_bsslist *bsslist;
u32 noise = 0;
......@@ -762,7 +763,7 @@ static int
prism54_set_essid(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
struct obj_ssid essid;
memset(essid.octets, 0, 33);
......@@ -789,7 +790,7 @@ static int
prism54_get_essid(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
struct obj_ssid *essid;
union oid_res_t r;
int rvalue;
......@@ -819,7 +820,7 @@ static int
prism54_set_nick(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
if (dwrq->length > IW_ESSID_MAX_SIZE)
return -E2BIG;
......@@ -836,7 +837,7 @@ static int
prism54_get_nick(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
dwrq->length = 0;
......@@ -856,7 +857,7 @@ prism54_set_rate(struct net_device *ndev,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
u32 rate, profile;
char *data;
int ret, i;
......@@ -924,7 +925,7 @@ prism54_get_rate(struct net_device *ndev,
struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
int rvalue;
char *data;
union oid_res_t r;
......@@ -948,7 +949,7 @@ static int
prism54_set_rts(struct net_device *ndev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
return mgt_set_request(priv, DOT11_OID_RTSTHRESH, 0, &vwrq->value);
}
......@@ -957,7 +958,7 @@ static int
prism54_get_rts(struct net_device *ndev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
union oid_res_t r;
int rvalue;
......@@ -972,7 +973,7 @@ static int
prism54_set_frag(struct net_device *ndev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
return mgt_set_request(priv, DOT11_OID_FRAGTHRESH, 0, &vwrq->value);
}
......@@ -981,7 +982,7 @@ static int
prism54_get_frag(struct net_device *ndev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
union oid_res_t r;
int rvalue;
......@@ -1004,7 +1005,7 @@ static int
prism54_set_retry(struct net_device *ndev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
u32 slimit = 0, llimit = 0; /* short and long limit */
u32 lifetime = 0;
int rvalue = 0;
......@@ -1048,7 +1049,7 @@ static int
prism54_get_retry(struct net_device *ndev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
union oid_res_t r;
int rvalue = 0;
vwrq->disabled = 0; /* It cannot be disabled */
......@@ -1080,7 +1081,7 @@ static int
prism54_set_encode(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
int rvalue = 0, force = 0;
int authen = DOT11_AUTH_OS, invoke = 0, exunencrypt = 0;
union oid_res_t r;
......@@ -1170,7 +1171,7 @@ static int
prism54_get_encode(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
struct obj_key *key;
u32 devindex, index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
u32 authen = 0, invoke = 0, exunencrypt = 0;
......@@ -1218,7 +1219,7 @@ static int
prism54_get_txpower(struct net_device *ndev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
union oid_res_t r;
int rvalue;
......@@ -1238,7 +1239,7 @@ static int
prism54_set_txpower(struct net_device *ndev, struct iw_request_info *info,
struct iw_param *vwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
s32 u = vwrq->value;
/* intersil firmware operates in 0.25 dBm (1/4) */
......@@ -1264,7 +1265,7 @@ static int
prism54_reset(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
islpci_reset(ndev->priv, 0);
islpci_reset(netdev_priv(ndev), 0);
return 0;
}
......@@ -1273,7 +1274,7 @@ static int
prism54_set_beacon(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
int rvalue = mgt_set_request((islpci_private *) ndev->priv,
int rvalue = mgt_set_request((islpci_private *) netdev_priv(ndev),
DOT11_OID_BEACONPERIOD, 0, uwrq);
return (rvalue ? rvalue : -EINPROGRESS);
......@@ -1287,7 +1288,7 @@ prism54_get_beacon(struct net_device *ndev, struct iw_request_info *info,
int rvalue;
rvalue =
mgt_get_request((islpci_private *) ndev->priv,
mgt_get_request((islpci_private *) netdev_priv(ndev),
DOT11_OID_BEACONPERIOD, 0, NULL, &r);
*uwrq = r.u;
......@@ -1337,7 +1338,7 @@ static int
prism54_add_mac(struct net_device *ndev, struct iw_request_info *info,
struct sockaddr *awrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
struct islpci_acl *acl = &priv->acl;
struct mac_entry *entry;
struct sockaddr *addr = (struct sockaddr *) extra;
......@@ -1366,7 +1367,7 @@ static int
prism54_del_mac(struct net_device *ndev, struct iw_request_info *info,
struct sockaddr *awrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
struct islpci_acl *acl = &priv->acl;
struct mac_entry *entry;
struct list_head *ptr;
......@@ -1396,7 +1397,7 @@ static int
prism54_get_mac(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *dwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
struct islpci_acl *acl = &priv->acl;
struct mac_entry *entry;
struct list_head *ptr;
......@@ -1427,7 +1428,7 @@ static int
prism54_set_policy(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
struct islpci_acl *acl = &priv->acl;
u32 mlmeautolevel;
......@@ -1460,7 +1461,7 @@ static int
prism54_get_policy(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
struct islpci_acl *acl = &priv->acl;
*uwrq = acl->policy;
......@@ -1511,7 +1512,7 @@ prism54_kick_all(struct net_device *ndev, struct iw_request_info *info,
/* Tell the card to kick every client */
mlme->id = cpu_to_le16(0);
rvalue = mgt_set_request(ndev->priv, DOT11_OID_DISASSOCIATE, 0, mlme);
rvalue = mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
kfree(mlme);
return rvalue;
......@@ -1535,7 +1536,7 @@ prism54_kick_mac(struct net_device *ndev, struct iw_request_info *info,
/* Tell the card to only kick the corresponding bastard */
memcpy(mlme->address, addr->sa_data, ETH_ALEN);
mlme->id = cpu_to_le16(-1);
rvalue = mgt_set_request(ndev->priv, DOT11_OID_DISASSOCIATE, 0, mlme);
rvalue = mgt_set_request(netdev_priv(ndev), DOT11_OID_DISASSOCIATE, 0, mlme);
kfree(mlme);
......@@ -1595,7 +1596,7 @@ send_simple_event(islpci_private *priv, const char *str)
static void
link_changed(struct net_device *ndev, u32 bitrate)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
if (le32_to_cpu(bitrate)) {
if (priv->iw_mode == IW_MODE_INFRA) {
......@@ -1604,9 +1605,9 @@ link_changed(struct net_device *ndev, u32 bitrate)
NULL);
wireless_send_event(ndev, SIOCGIWAP, &uwrq, NULL);
} else
send_simple_event(ndev->priv, "Link established");
send_simple_event(netdev_priv(ndev), "Link established");
} else
send_simple_event(ndev->priv, "Link lost");
send_simple_event(netdev_priv(ndev), "Link lost");
}
/* Beacon/ProbeResp payload header */
......@@ -1889,16 +1890,17 @@ void
prism54_process_trap(void *data)
{
struct islpci_mgmtframe *frame = data;
struct net_device *ndev = frame->ndev;
enum oid_num_t n = mgt_oidtonum(frame->header->oid);
prism54_process_trap_helper(frame->ndev->priv, n, frame->data);
prism54_process_trap_helper(netdev_priv(ndev), n, frame->data);
islpci_mgt_release(frame);
}
int
prism54_set_mac_address(struct net_device *ndev, void *addr)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
int ret;
if (ndev->addr_len != 6)
......@@ -1923,7 +1925,7 @@ int
prism54_set_wpa(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
down_write(&priv->mib_sem);
......@@ -1943,16 +1945,70 @@ int
prism54_get_wpa(struct net_device *ndev, struct iw_request_info *info,
__u32 * uwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
*uwrq = priv->wpa;
return 0;
}
int
prism54_set_maxframeburst(struct net_device *ndev, struct iw_request_info *info,
__u32 *uwrq, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
u32 max_burst;
max_burst = (*uwrq) ? *uwrq : CARD_DEFAULT_MAXFRAMEBURST;
mgt_set_request(priv, DOT11_OID_MAXFRAMEBURST, 0, &max_burst);
return -EINPROGRESS; /* Call commit handler */
}
int
prism54_get_maxframeburst(struct net_device *ndev, struct iw_request_info *info,
__u32 *uwrq, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
union oid_res_t r;
int rvalue;
rvalue = mgt_get_request(priv, DOT11_OID_MAXFRAMEBURST, 0, NULL, &r);
*uwrq = r.u;
return rvalue;
}
int
prism54_set_profile(struct net_device *ndev, struct iw_request_info *info,
__u32 *uwrq, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
u32 profile;
profile = (*uwrq) ? *uwrq : CARD_DEFAULT_PROFILE;
mgt_set_request(priv, DOT11_OID_PROFILES, 0, &profile);
return -EINPROGRESS; /* Call commit handler */
}
int
prism54_get_profile(struct net_device *ndev, struct iw_request_info *info,
__u32 *uwrq, char *extra)
{
islpci_private *priv = netdev_priv(ndev);
union oid_res_t r;
int rvalue;
rvalue = mgt_get_request(priv, DOT11_OID_PROFILES, 0, NULL, &r);
*uwrq = r.u;
return rvalue;
}
int
prism54_oid(struct net_device *ndev, struct iw_request_info *info,
__u32 *uwrq, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
priv->priv_oid = *uwrq;
printk("%s: oid 0x%08X\n", ndev->name, *uwrq);
......@@ -1964,7 +2020,7 @@ int
prism54_get_oid(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *data, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
struct islpci_mgmtframe *response = NULL;
int ret = -EIO, response_op = PIMFOR_OP_ERROR;
......@@ -1998,7 +2054,7 @@ int
prism54_set_oid(struct net_device *ndev, struct iw_request_info *info,
struct iw_point *data, char *extra)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
struct islpci_mgmtframe *response = NULL;
int ret = 0, response_op = PIMFOR_OP_ERROR;
......
/*
* $Id: isl_oid.h,v 1.2 2004/01/30 16:24:00 ajfa Exp $
* $Id: isl_oid.h,v 1.3 2004/03/09 09:05:27 mcgrof Exp $
*
* Copyright (C) 2003 Herbert Valerio Riedel <hvr@gnu.org>
* Copyright (C) 2004 Luis R. Rodriguez <mcgrof@ruslug.rutgers.edu>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
......@@ -142,14 +143,130 @@ enum dot11_priv_t {
DOT11_PRIV_TKIP = 1
};
/* Prism "Nitro" / Frameburst / "Packet Frame Grouping"
* Value is in microseconds. Represents the # microseconds
* the firmware will take to group frames before sending out then out
* together with a CSMA contention. Without this all frames are
* sent with a CSMA contention.
* Bibliography:
* http://www.hpl.hp.com/personal/Jean_Tourrilhes/Papers/Packet.Frame.Grouping.html
*/
enum dot11_maxframeburst_t {
/* Values for DOT11_OID_MAXFRAMEBURST */
DOT11_MAXFRAMEBURST_OFF = 0, /* Card firmware default */
DOT11_MAXFRAMEBURST_MIXED_SAFE = 650, /* 802.11 a,b,g safe */
DOT11_MAXFRAMEBURST_IDEAL = 1300, /* Theoretical ideal level */
DOT11_MAXFRAMEBURST_MAX = 5000, /* Use this as max,
* Note: firmware allows for greater values. This is a
* recommended max. I'll update this as I find
* out what the real MAX is. Also note that you don't necessarily
* get better results with a greater value here.
*/
};
/* Support for 802.11 long and short frame preambles.
* Long preamble uses 128-bit sync field, 8-bit CRC
* Short preamble uses 56-bit sync field, 16-bit CRC
*
* 802.11a -- not sure, both optionally ?
* 802.11b supports long and optionally short
* 802.11g supports both */
enum dot11_preamblesettings_t {
DOT11_PREAMBLESETTING_LONG = 0,
/* Allows *only* long 802.11 preambles */
DOT11_PREAMBLESETTING_SHORT = 1,
/* Allows *only* short 802.11 preambles */
DOT11_PREAMBLESETTING_DYNAMIC = 2
/* AutomatiGically set */
};
/* Support for 802.11 slot timing (time between packets).
*
* Long uses 802.11a slot timing (9 usec ?)
* Short uses 802.11b slot timing (20 use ?) */
enum dot11_slotsettings_t {
DOT11_SLOTSETTINGS_LONG = 0,
/* Allows *only* long 802.11b slot timing */
DOT11_SLOTSETTINGS_SHORT = 1,
/* Allows *only* long 802.11a slot timing */
DOT11_SLOTSETTINGS_DYNAMIC = 2
/* AutomatiGically set */
};
/* All you need to know, ERP is "Extended Rate PHY".
* An Extended Rate PHY (ERP) STA or AP shall support three different
* preamble and header formats:
* Long preamble (refer to above)
* Short preamble (refer to above)
* OFDM preamble ( ? )
*
* I'm assuming here Protection tells the AP
* to be careful, a STA which cannot handle the long pre-amble
* has joined.
*/
enum do11_nonerpstatus_t {
DOT11_ERPSTAT_NONEPRESENT = 0,
DOT11_ERPSTAT_USEPROTECTION = 1
};
/* (ERP is "Extended Rate PHY") Way to read NONERP is NON-ERP-*
* The key here is DOT11 NON ERP NEVER protects against
* NON ERP STA's. You *don't* want this unless
* you know what you are doing. It means you will only
* get Extended Rate capabilities */
enum dot11_nonerpprotection_t {
DOT11_NONERP_NEVER = 0,
DOT11_NONERP_ALWAYS = 1,
DOT11_NONERP_DYNAMIC = 2
};
/* Preset OID configuration for 802.11 modes
* Note: DOT11_OID_CW[MIN|MAX] hold the values of the
* DCS MIN|MAX backoff used */
enum dot11_profile_t { /* And set/allowed values */
/* Allowed values for DOT11_OID_PROFILES */
DOT11_PROFILE_B_ONLY = 0,
/* DOT11_OID_RATES: 1, 2, 5.5, 11Mbps
* DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC
* DOT11_OID_CWMIN: 31
* DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC
* DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_LONG
*/
DOT11_PROFILE_MIXED_G_WIFI = 1,
/* DOT11_OID_RATES: 1, 2, 5.5, 11, 6, 9, 12, 18, 24, 36, 48, 54Mbs
* DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_DYNAMIC
* DOT11_OID_CWMIN: 15
* DOT11_OID_NONEPROTECTION: DOT11_NOERP_DYNAMIC
* DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_DYNAMIC
*/
DOT11_PROFILE_MIXED_LONG = 2, /* "Long range" */
/* Same as Profile MIXED_G_WIFI */
DOT11_PROFILE_G_ONLY = 3,
/* Same as Profile MIXED_G_WIFI */
DOT11_PROFILE_TEST = 4,
/* Same as Profile MIXED_G_WIFI except:
* DOT11_OID_PREAMBLESETTINGS: DOT11_PREAMBLESETTING_SHORT
* DOT11_OID_NONEPROTECTION: DOT11_NOERP_NEVER
* DOT11_OID_SLOTSETTINGS: DOT11_SLOTSETTINGS_SHORT
*/
DOT11_PROFILE_B_WIFI = 5,
/* Same as Profile B_ONLY */
DOT11_PROFILE_A_ONLY = 6,
/* Same as Profile MIXED_G_WIFI except:
* DOT11_OID_RATES: 6, 9, 12, 18, 24, 36, 48, 54Mbs
*/
DOT11_PROFILE_MIXED_SHORT = 7
/* Same as MIXED_G_WIFI */
};
/* The dot11d conformance level configures the 802.11d conformance levels.
* The following conformance levels exist:*/
enum oid_inl_conformance_t {
OID_INL_CONFORMANCE_NONE = 0, /* Perform active scanning */
OID_INL_CONFORMANCE_STRICT = 1, /* Strictly adhere to 802.11d */
OID_INL_CONFORMANCE_FLEXIBLE = 2, /* Use passed 802.11d info to
* determine channel AND/OR just make
* assumption that active
* determine channel AND/OR just make assumption that active
* channels are valid channels */
};
......@@ -176,6 +293,7 @@ enum oid_inl_phycap_t {
INL_PHYCAP_FAA = 0x80000000, /* Means card supports the FAA switch */
};
enum oid_num_t {
GEN_OID_MACADDRESS = 0,
GEN_OID_LINKSTATE,
......@@ -269,8 +387,8 @@ enum oid_num_t {
DOT11_OID_FRAMEABORTSPHY,
DOT11_OID_SLOTTIME,
DOT11_OID_CWMIN,
DOT11_OID_CWMAX,
DOT11_OID_CWMIN, /* MIN DCS backoff */
DOT11_OID_CWMAX, /* MAX DCS backoff */
DOT11_OID_ACKWINDOW,
DOT11_OID_ANTENNARX,
DOT11_OID_ANTENNATX,
......
......@@ -245,7 +245,7 @@ static int
islpci_open(struct net_device *ndev)
{
u32 rc;
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
printk(KERN_DEBUG "%s: islpci_open()\n", ndev->name);
......@@ -265,7 +265,7 @@ islpci_open(struct net_device *ndev)
static int
islpci_close(struct net_device *ndev)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
printk(KERN_DEBUG "%s: islpci_close ()\n", ndev->name);
......@@ -491,7 +491,7 @@ islpci_reset(islpci_private *priv, int reload_firmware)
struct net_device_stats *
islpci_statistics(struct net_device *ndev)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
#if VERBOSE > SHOW_ERROR_MESSAGES
DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics \n");
......
......@@ -63,6 +63,7 @@ islpci_eth_cleanup_transmit(islpci_private *priv,
priv->pci_map_tx_address[index],
skb->len, PCI_DMA_TODEVICE);
dev_kfree_skb_irq(skb);
skb = NULL;
}
/* increment the free data low queue pointer */
priv->free_data_tx++;
......@@ -72,7 +73,7 @@ islpci_eth_cleanup_transmit(islpci_private *priv,
int
islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
isl38xx_control_block *cb = priv->control_block;
u32 index;
dma_addr_t pci_map_address;
......@@ -238,6 +239,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
drop_free:
/* free the skbuf structure before aborting */
dev_kfree_skb(skb);
skb = NULL;
priv->statistics.tx_dropped++;
spin_unlock_irqrestore(&priv->slock, flags);
......@@ -346,8 +348,10 @@ islpci_eth_receive(islpci_private *priv)
skb->data[0], skb->data[1], skb->data[2], skb->data[3],
skb->data[4], skb->data[5]);
#endif
if (discard)
if (discard) {
dev_kfree_skb(skb);
skb = NULL;
}
else
netif_rx(skb);
......@@ -388,6 +392,7 @@ islpci_eth_receive(islpci_private *priv)
/* free the skbuf structure before aborting */
dev_kfree_skb((struct sk_buff *) skb);
skb = NULL;
break;
}
/* update the fragment address */
......@@ -411,7 +416,7 @@ islpci_eth_receive(islpci_private *priv)
void
islpci_eth_tx_timeout(struct net_device *ndev)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
struct net_device_stats *statistics = &priv->statistics;
/* increment the transmit error counter */
......
......@@ -29,10 +29,10 @@
#include "isl_oid.h"
#define DRV_NAME "prism54"
#define DRV_VERSION "1.0.2.2"
#define DRV_VERSION "1.1"
MODULE_AUTHOR("W.Termorshuizen, R.Bastings, H.V.Riedel, prism54.org team");
MODULE_DESCRIPTION("Intersil 802.11 Wireless LAN adapter");
MODULE_AUTHOR("[Intersil] R.Bastings and W.Termorshuizen, The prism54.org Development Team <prism54-devel@prism54.org>");
MODULE_DESCRIPTION("The Prism54 802.11 Wireless LAN adapter");
MODULE_LICENSE("GPL");
/* In this order: vendor, device, subvendor, subdevice, class, class_mask,
......@@ -96,6 +96,11 @@ static const struct pci_device_id prism54_id_tbl[] = {
PCIVENDOR_ACCTON, 0xee03UL,
0, 0,
(unsigned long) "SMC 2802Wv2"},
{
PCIVENDOR_INTERSIL, PCIDEVICE_ISL3890,
PCIVENDOR_SMC, 0xa835UL,
0, 0,
(unsigned long) "SMC 2835Wv2"},
{
PCIVENDOR_INTERSIL, PCIDEVICE_ISL3877,
PCI_ANY_ID, PCI_ANY_ID,
......@@ -133,7 +138,7 @@ prism54_get_card_model(struct net_device *ndev)
islpci_private *priv;
char *modelp;
priv = ndev->priv;
priv = netdev_priv(ndev);
switch (priv->pdev->subsystem_device) {
case PCIDEVICE_ISL3877:
modelp = "PRISM Indigo";
......@@ -159,6 +164,9 @@ prism54_get_card_model(struct net_device *ndev)
case 0x2835UL:
modelp = "SMC2835W";
break;
case 0xa835UL:
modelp = "SMC2835W V2";
break;
/* Let's leave this one out for now since it seems bogus/wrong
* Even if the manufacturer did use 0x0000UL it may not be correct
* by their part, therefore deserving no name ;) */
......@@ -269,7 +277,7 @@ prism54_probe(struct pci_dev *pdev, const struct pci_device_id *id)
goto do_pci_release_regions;
}
priv = ndev->priv;
priv = netdev_priv(ndev);
islpci_set_state(priv, PRV_STATE_PREBOOT); /* we are attempting to boot */
/* card is in unknown state yet, might have some interrupts pending */
......@@ -314,7 +322,7 @@ void
prism54_remove(struct pci_dev *pdev)
{
struct net_device *ndev = pci_get_drvdata(pdev);
islpci_private *priv = ndev ? ndev->priv : 0;
islpci_private *priv = ndev ? netdev_priv(ndev) : 0;
BUG_ON(!priv);
if (!__in_cleanup_module) {
......@@ -355,7 +363,7 @@ int
prism54_suspend(struct pci_dev *pdev, u32 state)
{
struct net_device *ndev = pci_get_drvdata(pdev);
islpci_private *priv = ndev ? ndev->priv : 0;
islpci_private *priv = ndev ? netdev_priv(ndev) : 0;
BUG_ON(!priv);
printk(KERN_NOTICE "%s: got suspend request (state %d)\n",
......@@ -380,7 +388,7 @@ int
prism54_resume(struct pci_dev *pdev)
{
struct net_device *ndev = pci_get_drvdata(pdev);
islpci_private *priv = ndev ? ndev->priv : 0;
islpci_private *priv = ndev ? netdev_priv(ndev) : 0;
BUG_ON(!priv);
printk(KERN_NOTICE "%s: got resume request\n", ndev->name);
......
......@@ -22,6 +22,7 @@
#include <linux/netdevice.h>
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/moduleparam.h>
#include <asm/io.h>
#include <asm/system.h>
......@@ -38,7 +39,7 @@
Global variable definition section
******************************************************************************/
int pc_debug = VERBOSE;
MODULE_PARM(pc_debug, "i");
module_param(pc_debug, int, 0);
/******************************************************************************
Driver general functions
......@@ -106,7 +107,7 @@ pimfor_decode_header(void *data, int len)
int
islpci_mgmt_rx_fill(struct net_device *ndev)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
isl38xx_control_block *cb = /* volatile not needed */
(isl38xx_control_block *) priv->control_block;
u32 curr = le32_to_cpu(cb->driver_curr_frag[ISL38XX_CB_RX_MGMTQ]);
......@@ -165,7 +166,7 @@ static int
islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid,
void *data, int length)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
isl38xx_control_block *cb =
(isl38xx_control_block *) priv->control_block;
void *p;
......@@ -271,7 +272,7 @@ islpci_mgt_transmit(struct net_device *ndev, int operation, unsigned long oid,
int
islpci_mgt_receive(struct net_device *ndev)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
isl38xx_control_block *cb =
(isl38xx_control_block *) priv->control_block;
u32 curr_frag;
......@@ -414,7 +415,7 @@ n",
void
islpci_mgt_cleanup_transmit(struct net_device *ndev)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
isl38xx_control_block *cb = /* volatile not needed */
(isl38xx_control_block *) priv->control_block;
u32 curr_frag;
......@@ -451,7 +452,7 @@ islpci_mgt_transaction(struct net_device *ndev,
void *senddata, int sendlen,
struct islpci_mgmtframe **recvframe)
{
islpci_private *priv = ndev->priv;
islpci_private *priv = netdev_priv(ndev);
const long wait_cycle_jiffies = (ISL38XX_WAIT_CYCLE * 10 * HZ) / 1000;
long timeout_left = ISL38XX_MAX_WAIT_CYCLES * wait_cycle_jiffies;
int err;
......
......@@ -87,11 +87,13 @@ static const int init_wds = 0; /* help compiler optimize away dead code */
#define CARD_DEFAULT_KEY4 "default_key_4"
#define CARD_DEFAULT_WEP 0
#define CARD_DEFAULT_FILTER 0
# define CARD_DEFAULT_WDS 0
#define CARD_DEFAULT_WDS 0
#define CARD_DEFAULT_AUTHEN DOT11_AUTH_OS
#define CARD_DEFAULT_DOT1X 0
#define CARD_DEFAULT_MLME_MODE DOT11_MLME_AUTO
#define CARD_DEFAULT_CONFORMANCE OID_INL_CONFORMANCE_NONE
#define CARD_DEFAULT_PROFILE DOT11_PROFILE_MIXED_G_WIFI
#define CARD_DEFAULT_MAXFRAMEBURST DOT11_MAXFRAMEBURST_MIXED_SAFE
/* PIMFOR package definitions */
#define PIMFOR_ETHERTYPE 0x8828
......
......@@ -97,7 +97,7 @@ struct oid_t isl_oid[] = {
[DOT11_OID_ALOFT_CONFIG] = OID_UNKNOWN(0x1d000006),
[DOT11_OID_VDCFX] = {0x1b000000, 7, 0, 0},
[DOT11_OID_MAXFRAMEBURST] = OID_U32(0x1b000008),
[DOT11_OID_MAXFRAMEBURST] = OID_U32(0x1b000008), /* in microseconds */
[DOT11_OID_PSM] = OID_U32(0x14000000),
[DOT11_OID_CAMTIMEOUT] = OID_U32(0x14000001),
......
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