S: S-114 53 Stockholm
S: Sweden
-N: Stephane Eranian
-E: eranian@hpl.hp.com
-D: Linux/ia64
-S: 1501 Page Mill Rd, MS 1U17
-S: Palo Alto, CA 94304
-S: USA
-
N: Paal-Kristian Engstad
E: engstad@intermetrics.com
D: Kernel smbfs (to mount WfW, NT and OS/2 network drives.)
S: Huntington Beach, California 92649
S: USA
+N: Stephane Eranian
+E: eranian@hpl.hp.com
+D: Linux/ia64
+S: 1501 Page Mill Rd, MS 1U17
+S: Palo Alto, CA 94304
+S: USA
+
N: Johannes Erdfelt
E: jerdfelt@valinux.com
D: Linux/IA-64 bootloader and kernel goop, USB
S: 13349 Berlin
S: Germany
-N: Nicolas Pitre
-E: nico@cam.org
-D: StrongARM SA1100 support integrator & hacker
-S: Montreal, Quebec, Canada
-
N: Emanuel Pirker
E: epirker@edu.uni-klu.ac.at
D: AIC5800 IEEE 1394, RAW I/O on 1394
D: Starter of Linux1394 effort
S: ask per mail for current address
+N: Nicolas Pitre
+E: nico@cam.org
+D: StrongARM SA1100 support integrator & hacker
+S: Montreal, Quebec, Canada
+
N: Ken Pizzini
E: ken@halcyon.com
D: CDROM driver "sonycd535" (Sony CDU-535/531)
D: ISAPnP fixes in sb_card.c
S: Italy
-N: Alessandro Zummo
-E: azummo@ita.flashnet.it
-W: http://freepage.logicom.it/azummo/
-D: CMI8330 support is sb_card.c
-D: ISAPnP fixes in sb_card.c
-S: Italy
-
N: Marc Zyngier
E: maz@wild-wind.fr.eu.org
D: MD driver
CONFIG_NET_PCI=y
# CONFIG_PCNET32 is not set
# CONFIG_APRICOT is not set
-# CONFIG_CS89x0 is not set
# CONFIG_DE4X5 is not set
# CONFIG_TULIP is not set
# CONFIG_DGRS is not set
if((vma->vm_flags & (VM_WRITE|VM_SHARED)) == (VM_WRITE|VM_SHARED)) {
struct vm_area_struct *vmaring;
struct file *file;
- struct inode *inode;
+ struct address_space *mapping;
unsigned long flags, offset, vaddr, start;
int alias_found = 0;
pgd_t *pgdp;
file = vma->vm_file;
if (!file)
goto done;
- inode = file->f_dentry->d_inode;
+ mapping = file->f_dentry->d_inode->i_mapping;
offset = (address & PAGE_MASK) - vma->vm_start;
- spin_lock(&inode->i_shared_lock);
- vmaring = inode->i_mmap;
+ spin_lock(&mapping->i_shared_lock);
+ vmaring = mapping->i_mmap;
do {
/* Do not mistake ourselves as another mapping. */
if(vmaring == vma)
}
}
} while ((vmaring = vmaring->vm_next_share) != NULL);
- spin_unlock(&inode->i_shared_lock);
+ spin_unlock(&mapping->i_shared_lock);
if(alias_found && ((pte_val(pte) & SRMMU_CACHE) != 0)) {
pgdp = srmmu_pgd_offset(vma->vm_mm, address);
if(dentry)
inode = dentry->d_inode;
if(inode) {
+ struct address_space *mapping = inode->i_mapping;
unsigned long offset = (address & PAGE_MASK) - vma->vm_start;
struct vm_area_struct *vmaring;
int alias_found = 0;
- spin_lock(&inode->i_shared_lock);
- vmaring = inode->i_mmap;
+ spin_lock(&mapping->i_shared_lock);
+ vmaring = mapping->i_mmap;
do {
unsigned long vaddr = vmaring->vm_start + offset;
unsigned long start;
}
}
} while ((vmaring = vmaring->vm_next_share) != NULL);
- spin_unlock(&inode->i_shared_lock);
+ spin_unlock(&mapping->i_shared_lock);
if (alias_found && !(pte_val(pte) & _SUN4C_PAGE_NOCACHE)) {
pgdp = sun4c_pgd_offset(vma->vm_mm, address);
/*
- * linux/drivers/block/cs5530.c Version 0.2 Jan 30, 2000
+ * linux/drivers/block/cs5530.c Version 0.5 Feb 13, 2000
*
* Copyright (C) 2000 Mark Lord <mlord@pobox.com>
* May be copied or modified under the terms of the GNU General Public License
}
outb(inb(hwif->dma_base+2)|(unit?0x40:0x20), hwif->dma_base+2); /* set DMA_capable bit */
- if (!strcmp(drive->name, "hdc")) /* FIXME */
- return 0;
/*
* Finally, turn DMA on in software, and exit.
*/
#include <linux/in.h>
#include <linux/malloc.h>
#include <linux/ioport.h>
+#include <linux/spinlock.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
static inline void prime_rx(struct net_device *dev)
{
elp_device *adapter = dev->priv;
- while (adapter->rx_active < ELP_RX_PCBS && dev->start) {
+ while (adapter->rx_active < ELP_RX_PCBS && test_bit(LINK_STATE_START, &dev->state)) {
if (!start_receive(dev, &adapter->itx_pcb))
break;
}
elp_device *adapter;
int timeout;
- if (irq < 0 || irq > 15) {
- printk("elp_interrupt(): illegal IRQ number found in interrupt routine (%i)\n", irq);
- return;
- }
dev = dev_id;
-
- if (dev == NULL) {
- printk("elp_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
adapter = (elp_device *) dev->priv;
-
- if (dev->interrupt) {
- printk("%s: re-entering the interrupt handler!\n", dev->name);
- return;
- }
- dev->interrupt = 1;
+
+ spin_lock(&adapter->lock);
do {
/*
printk("%s: %s DMA complete, status %02x\n", dev->name, adapter->current_dma.direction ? "tx" : "rx", inb_status(dev->base_addr));
}
- outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR),
- dev);
+ outb_control(adapter->hcr_val & ~(DMAE | TCEN | DIR), dev);
if (adapter->current_dma.direction) {
dev_kfree_skb_irq(adapter->current_dma.skb);
} else {
struct sk_buff *skb = adapter->current_dma.skb;
if (skb) {
- if (adapter->current_dma.target) {
- /* have already done the skb_put() */
- memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
- }
- skb->protocol = eth_type_trans(skb,dev);
- adapter->stats.rx_bytes += skb->len;
- netif_rx(skb);
+ if (adapter->current_dma.target) {
+ /* have already done the skb_put() */
+ memcpy(adapter->current_dma.target, adapter->dma_buffer, adapter->current_dma.length);
+ }
+ skb->protocol = eth_type_trans(skb,dev);
+ adapter->stats.rx_bytes += skb->len;
+ netif_rx(skb);
}
}
adapter->dmaing = 0;
check_3c505_dma(dev);
}
- sti();
-
/*
* receive a PCB from the adapter
*/
timeout = jiffies + 3*HZ/100;
while ((inb_status(dev->base_addr) & ACRF) != 0 && time_before(jiffies, timeout)) {
if (receive_pcb(dev, &adapter->irx_pcb)) {
- switch (adapter->irx_pcb.command) {
+ switch (adapter->irx_pcb.command)
+ {
case 0:
break;
/*
case 0xff:
case CMD_RECEIVE_PACKET_COMPLETE:
/* if the device isn't open, don't pass packets up the stack */
- if (dev->start == 0)
+ if (test_bit(LINK_STATE_START, &dev->state) == 0)
break;
- cli();
len = adapter->irx_pcb.data.rcv_resp.pkt_len;
dlen = adapter->irx_pcb.data.rcv_resp.buf_len;
if (adapter->irx_pcb.data.rcv_resp.timeout != 0) {
- printk("%s: interrupt - packet not received correctly\n", dev->name);
- sti();
+ printk(KERN_ERR "%s: interrupt - packet not received correctly\n", dev->name);
} else {
if (elp_debug >= 3) {
- sti();
printk("%s: interrupt - packet received of length %i (%i)\n", dev->name, len, dlen);
- cli();
}
if (adapter->irx_pcb.command == 0xff) {
if (elp_debug >= 2)
} else {
receive_packet(dev, dlen);
}
- sti();
if (elp_debug >= 3)
printk("%s: packet received\n", dev->name);
}
case CMD_TRANSMIT_PACKET_COMPLETE:
if (elp_debug >= 3)
printk("%s: interrupt - packet sent\n", dev->name);
- if (dev->start == 0)
+ if (test_bit(LINK_STATE_START, &dev->state) == 0)
break;
switch (adapter->irx_pcb.data.xmit_resp.c_stat) {
case 0xffff:
printk(KERN_INFO "%s: transmit timed out, FIFO underrun\n", dev->name);
break;
}
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
break;
/*
/*
* indicate no longer in interrupt routine
*/
- dev->interrupt = 0;
+ spin_unlock(&adapter->lock);
}
inb_command(dev->base_addr);
adapter_reset(dev);
- /*
- * interrupt routine not entered
- */
- dev->interrupt = 0;
-
- /*
- * transmitter not busy
- */
- dev->tbusy = 0;
-
/*
* no receive PCBs active
*/
adapter->send_pcb_semaphore = 0;
adapter->rx_backlog.in = 0;
adapter->rx_backlog.out = 0;
+
+ spin_lock_init(&adapter->lock);
/*
* install our interrupt service routine
/*
* device is now officially open!
*/
- dev->start = 1;
+ netif_wake_queue(dev);
MOD_INC_USE_COUNT;
return 0; /* Always succeed */
return TRUE;
}
+/*
+ * The upper layer thinks we timed out
+ */
+
+static void elp_timeout(struct net_device *dev)
+{
+ unsigned long flags;
+ elp_device *adapter = dev->priv;
+ int stat;
+
+ stat = inb_status(dev->base_addr);
+ printk(KERN_WARNING "%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command");
+ if (elp_debug >= 1)
+ printk("%s: status %#02x\n", dev->name, stat);
+ dev->trans_start = jiffies;
+ adapter->stats.tx_dropped++;
+ netif_wake_queue(dev);
+}
+
/******************************************************
*
* start the transmitter
static int elp_start_xmit(struct sk_buff *skb, struct net_device *dev)
{
- if (dev->interrupt) {
- printk("%s: start_xmit aborted (in irq)\n", dev->name);
- return 1;
- }
-
+ unsigned long flags;
+ elp_device *adapter = dev->priv;
+
+ spin_lock_irqsave(&adapter->lock, flags);
check_3c505_dma(dev);
- /*
- * if the transmitter is still busy, we have a transmit timeout...
- */
- if (dev->tbusy) {
- elp_device *adapter = dev->priv;
- int tickssofar = jiffies - dev->trans_start;
- int stat;
-
- if (tickssofar < 1000)
- return 1;
-
- stat = inb_status(dev->base_addr);
- printk("%s: transmit timed out, lost %s?\n", dev->name, (stat & ACRF) ? "interrupt" : "command");
- if (elp_debug >= 1)
- printk("%s: status %#02x\n", dev->name, stat);
- dev->trans_start = jiffies;
- dev->tbusy = 0;
- adapter->stats.tx_dropped++;
- }
-
if (elp_debug >= 3)
printk("%s: request to send packet of length %d\n", dev->name, (int) skb->len);
- if (test_and_set_bit(0, (void *) &dev->tbusy)) {
- printk("%s: transmitter access conflict\n", dev->name);
- return 1;
- }
+ netif_stop_queue(dev);
+
/*
* send the packet at skb->data for skb->len
*/
if (elp_debug >= 2) {
printk("%s: failed to transmit packet\n", dev->name);
}
- dev->tbusy = 0;
+ spin_unlock_irqrestore(&adapter->lock, flags);
return 1;
}
if (elp_debug >= 3)
dev->trans_start = jiffies;
prime_rx(dev);
-
+ spin_unlock_irqrestore(&adapter->lock, flags);
+ netif_start_queue(dev);
return 0;
}
/* If the device is closed, just return the latest stats we have,
- we cannot ask from the adapter without interrupts */
- if (!dev->start)
+ if (!test_bit(LINK_STATE_START, &dev->state))
return &adapter->stats;
/* send a get statistics command to the board */
if (elp_debug >= 3)
printk("%s: request to close device\n", dev->name);
+ netif_stop_queue(dev);
+
/* Someone may request the device statistic information even when
* the interface is closed. The following will update the statistics
* structure in the driver, so we'll be able to give current statistics.
*/
outb_control(0, dev);
- /*
- * flag transmitter as busy (i.e. not available)
- */
- dev->tbusy = 1;
-
- /*
- * indicate device is closed
- */
- dev->start = 0;
-
/*
* release the IRQ
*/
elp_device *adapter = (elp_device *) dev->priv;
struct dev_mc_list *dmi = dev->mc_list;
int i;
+ unsigned long flags;
if (elp_debug >= 3)
printk("%s: request to set multicast list\n", dev->name);
+ spin_lock_irqsave(&adapter->lock, flags);
+
if (!(dev->flags & (IFF_PROMISC | IFF_ALLMULTI))) {
/* send a "load multicast list" command to the board, max 10 addrs/cmd */
/* if num_addrs==0 the list will be cleared */
adapter->tx_pcb.length = 2;
adapter->got[CMD_CONFIGURE_82586] = 0;
if (!send_pcb(dev, &adapter->tx_pcb))
+ {
+ spin_unlock_irqrestore(&lp->lock, flags);
printk("%s: couldn't send 82586 configure command\n", dev->name);
+ }
else {
int timeout = jiffies + TIMEOUT;
+ spin_unlock_irqrestore(&lp->lock, flags);
while (adapter->got[CMD_CONFIGURE_82586] == 0 && time_before(jiffies, timeout));
if (time_after_eq(jiffies, timeout))
TIMEOUT_MSG(__LINE__);
/*
* set ptrs to various functions
*/
- dev->open = elp_open; /* local */
- dev->stop = elp_close; /* local */
- dev->get_stats = elp_get_stats; /* local */
- dev->hard_start_xmit = elp_start_xmit; /* local */
+ dev->open = elp_open; /* local */
+ dev->stop = elp_close; /* local */
+ dev->get_stats = elp_get_stats; /* local */
+ dev->hard_start_xmit = elp_start_xmit; /* local */
+ dev->tx_timeout = elp_timeout; /* local */
+ dev->watchdog_timeo = 10*HZ;
dev->set_multicast_list = elp_set_mc_list; /* local */
/* Setup the generic properties */
unsigned int rx_active; /* number of receive PCBs */
volatile unsigned char hcr_val; /* what we think the HCR contains */
+ spinlock_t lock; /* Interrupt v tx lock */
} elp_device;
fi
tristate ' SMC Ultra support' CONFIG_ULTRA
tristate ' SMC Ultra32 EISA support' CONFIG_ULTRA32
- tristate ' SMC 9194 support' CONFIG_SMC9194
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' SMC 9194 support' CONFIG_SMC9194
+ fi
fi
bool ' Racal-Interlan (Micom) NI cards' CONFIG_NET_VENDOR_RACAL
if [ "$CONFIG_NET_VENDOR_RACAL" = "y" ]; then
bool ' Other ISA cards' CONFIG_NET_ISA
if [ "$CONFIG_NET_ISA" = "y" ]; then
tristate ' Cabletron E21xx support' CONFIG_E2100
- tristate ' EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' EtherWORKS 3 (DE203, DE204, DE205) support' CONFIG_EWRK3
+ fi
tristate ' EtherExpress 16 support' CONFIG_EEXPRESS
tristate ' EtherExpressPro support' CONFIG_EEXPRESS_PRO
- tristate ' FMV-181/182/183/184 support' CONFIG_FMV18X
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' FMV-181/182/183/184 support' CONFIG_FMV18X
+ fi
tristate ' HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS
tristate ' HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN
tristate ' HP 10/100VG PCLAN (ISA, EISA, PCI) support' CONFIG_HP100
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
- tristate ' ICL EtherTeam 16i/32 support (EXPERIMENTAL)' CONFIG_ETH16I
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' ICL EtherTeam 16i/32 support' CONFIG_ETH16I
fi
tristate ' NE2000/NE1000 support' CONFIG_NE2000
- if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
tristate ' SEEQ8005 support (EXPERIMENTAL)' CONFIG_SEEQ8005
fi
bool ' SK_G16 support' CONFIG_SK_G16
fi
tristate ' Apricot Xen-II on board Ethernet' CONFIG_APRICOT
- tristate ' CS89x0 support' CONFIG_CS89x0
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' CS89x0 support' CONFIG_CS89x0
+ fi
tristate ' Generic DECchip & DIGITAL EtherWORKS PCI/EISA' CONFIG_DE4X5
tristate ' DECchip Tulip (dc21x4x) PCI support' CONFIG_TULIP
tristate ' Digi Intl. RightSwitch SE-X support' CONFIG_DGRS
if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
tristate ' Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210
tristate ' SMC EtherPower II (EXPERIMENTAL)' CONFIG_EPIC100
+ fi
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
bool ' Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET
fi
fi
bool ' Pocket and portable adapters' CONFIG_NET_POCKET
if [ "$CONFIG_NET_POCKET" = "y" ]; then
- bool ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
+ tristate ' AT-LAN-TEC/RealTek pocket adapter support' CONFIG_ATP
tristate ' D-Link DE600 pocket adapter support' CONFIG_DE600
tristate ' D-Link DE620 pocket adapter support' CONFIG_DE620
fi
bool 'Wireless LAN (non-hamradio)' CONFIG_NET_RADIO
if [ "$CONFIG_NET_RADIO" = "y" ]; then
dep_tristate ' STRIP (Metricom starmode radio IP)' CONFIG_STRIP $CONFIG_INET
- tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+ if [ "$CONFIG_OBSOLETE" = "y" ]; then
+ tristate ' AT&T WaveLAN & DEC RoamAbout DS support' CONFIG_WAVELAN
+ fi
tristate ' Aironet Arlan 655 & IC2200 DS support' CONFIG_ARLAN
tristate ' Aironet 4500/4800 series adapters' CONFIG_AIRONET4500
dep_tristate ' Aironet 4500/4800 ISA/PCI/PNP/365 support ' CONFIG_AIRONET4500_NONCS $CONFIG_AIRONET4500
Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771
The timer-based reset code was written by Bill Carlson, wwc@super.org.
+
+ Modular support/softnet added by Alan Cox.
*/
static const char *version =
*/
#include <linux/kernel.h>
+#include <linux/module.h>
#include <linux/sched.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
+#include <linux/spinlock.h>
#include "atp.h"
static unsigned short eeprom_op(short ioaddr, unsigned int cmd);
static int net_open(struct net_device *dev);
static void hardware_init(struct net_device *dev);
+static void tx_timeout(struct net_device *dev);
static void write_packet(short ioaddr, int length, unsigned char *packet, int mode);
static void trigger_send(short ioaddr, int length);
-static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev);
static void net_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void net_rx(struct net_device *dev);
static void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode);
If dev->base_addr == 2, allocate space for the device and return success
(detachable devices only).
*/
-int __init
-atp_init(struct net_device *dev)
+
+int __init atp_init(struct net_device *dev)
{
int *port, ports[] = {0x378, 0x278, 0x3bc, 0};
int base_addr = dev->base_addr;
dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]);
/* Leave the hardware in a reset state. */
- write_reg_high(ioaddr, CMR1, CMR1h_RESET);
+ write_reg_high(ioaddr, CMR1, CMR1h_RESET);
if (net_debug)
printk(version);
if (dev->priv == NULL)
return -ENOMEM;
memset(dev->priv, 0, sizeof(struct net_local));
-
-
{
struct net_local *lp = (struct net_local *)dev->priv;
lp->addr_mode = CMR2h_Normal;
+ spin_lock_init(&lp->lock);
}
/* For the ATP adapter the "if_port" is really the data transfer mode. */
dev->open = net_open;
dev->stop = net_close;
- dev->hard_start_xmit = net_send_packet;
- dev->get_stats = net_get_stats;
- dev->set_multicast_list = &set_multicast_list;
+ dev->hard_start_xmit = net_send_packet;
+ dev->get_stats = net_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+ dev->tx_timeout = tx_timeout;
+ dev->watchdog_timeo = HZ/20;
#ifdef TIMED_CHECKER
del_timer(&atp_timer);
/* The interrupt line is turned off (tri-stated) when the device isn't in
use. That's especially important for "attached" interfaces where the
port or interrupt may be shared. */
+
if (request_irq(dev->irq, &net_interrupt, 0, "ATP", dev)) {
return -EAGAIN;
}
-
hardware_init(dev);
- dev->start = 1;
+ netif_start_queue(dev);
return 0;
}
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
- int i;
+ int i;
write_reg_high(ioaddr, CMR1, CMR1h_RESET);
- for (i = 0; i < 6; i++)
+ for (i = 0; i < 6; i++)
write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]);
write_reg_high(ioaddr, CMR2, lp->addr_mode);
(read_nibble(ioaddr, CMR2_h) >> 3) & 0x0f);
}
- write_reg(ioaddr, CMR2, CMR2_IRQOUT);
- write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);
+ write_reg(ioaddr, CMR2, CMR2_IRQOUT);
+ write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE);
/* Enable the interrupt line from the serial port. */
outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
/* Unmask the interesting interrupts. */
- write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
- write_reg_high(ioaddr, IMR, ISRh_RxErr);
+ write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
+ write_reg_high(ioaddr, IMR, ISRh_RxErr);
lp->tx_unit_busy = 0;
- lp->pac_cnt_in_tx_buf = 0;
+ lp->pac_cnt_in_tx_buf = 0;
lp->saved_tx_size = 0;
-
- dev->tbusy = 0;
- dev->interrupt = 0;
}
static void trigger_send(short ioaddr, int length)
static void write_packet(short ioaddr, int length, unsigned char *packet, int data_mode)
{
- length = (length + 1) & ~1; /* Round up to word length. */
- outb(EOC+MAR, ioaddr + PAR_DATA);
- if ((data_mode & 1) == 0) {
+ length = (length + 1) & ~1; /* Round up to word length. */
+ outb(EOC+MAR, ioaddr + PAR_DATA);
+ if ((data_mode & 1) == 0) {
/* Write the packet out, starting with the write addr. */
outb(WrAddr+MAR, ioaddr + PAR_DATA);
do {
write_byte_mode0(ioaddr, *packet++);
} while (--length > 0) ;
- } else {
+ } else {
/* Write the packet out in slow mode. */
unsigned char outbyte = *packet++;
outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
while (--length > 0)
write_byte_mode1(ioaddr, *packet++);
- }
- /* Terminate the Tx frame. End of write: ECB. */
- outb(0xff, ioaddr + PAR_DATA);
- outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL);
+ }
+ /* Terminate the Tx frame. End of write: ECB. */
+ outb(0xff, ioaddr + PAR_DATA);
+ outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL);
}
-static int
-net_send_packet(struct sk_buff *skb, struct net_device *dev)
+static void tx_timeout(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
+ /* If we get here, some higher level has decided we are broken. */
+ printk(KERN_WARNING "%s: transmit timed out, %s?\n", dev->name,
+ inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"
+ : "IRQ conflict");
+ lp->stats.tx_errors++;
+ /* Try to restart the adapter. */
+ hardware_init(dev);
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
- if (dev->tbusy) {
- /* If we get here, some higher level has decided we are broken.
- There should really be a "kick me" function call instead. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk("%s: transmit timed out, %s?\n", dev->name,
- inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem"
- : "IRQ conflict");
- lp->stats.tx_errors++;
- /* Try to restart the adapter. */
- hardware_init(dev);
- dev->tbusy=0;
- dev->trans_start = jiffies;
- }
+static int net_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+ unsigned long flags;
+
+ netif_stop_queue(dev);
+
+ /* Disable interrupts by writing 0x00 to the Interrupt Mask Register.
+ This sequence must not be interrupted by an incoming packet. */
+
+ spin_lock_irqsave(&lp->lock, flags);
+ write_reg(ioaddr, IMR, 0);
+ write_reg_high(ioaddr, IMR, 0);
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ write_packet(ioaddr, length, buf, dev->if_port);
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
- else {
- short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
- int flags;
-
- /* Disable interrupts by writing 0x00 to the Interrupt Mask Register.
- This sequence must not be interrupted by an incoming packet. */
- save_flags(flags);
- cli();
- write_reg(ioaddr, IMR, 0);
- write_reg_high(ioaddr, IMR, 0);
- restore_flags(flags);
-
- write_packet(ioaddr, length, buf, dev->if_port);
-
- lp->pac_cnt_in_tx_buf++;
- if (lp->tx_unit_busy == 0) {
- trigger_send(ioaddr, length);
- lp->saved_tx_size = 0; /* Redundant */
- lp->re_tx = 0;
+ lp->pac_cnt_in_tx_buf++;
+ if (lp->tx_unit_busy == 0) {
+ trigger_send(ioaddr, length);
+ lp->saved_tx_size = 0; /* Redundant */
+ lp->re_tx = 0;
lp->tx_unit_busy = 1;
- } else
- lp->saved_tx_size = length;
-
- dev->trans_start = jiffies;
- /* Re-enable the LPT interrupts. */
- write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
- write_reg_high(ioaddr, IMR, ISRh_RxErr);
- }
+ } else
+ lp->saved_tx_size = length;
+ dev->trans_start = jiffies;
+ /* Re-enable the LPT interrupts. */
+ write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
+ write_reg_high(ioaddr, IMR, ISRh_RxErr);
dev_kfree_skb (skb);
-
return 0;
}
\f
int ioaddr, status, boguscount = 20;
static int num_tx_since_rx = 0;
- if (dev == NULL) {
- printk ("ATP_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
- dev->interrupt = 1;
-
ioaddr = dev->base_addr;
lp = (struct net_local *)dev->priv;
+
+ spin_lock(&lp->lock);
/* Disable additional spurious interrupts. */
outb(Ctrl_SelData, ioaddr + PAR_CONTROL);
write_reg(ioaddr, CMR2, CMR2_NULL);
write_reg(ioaddr, IMR, 0);
- if (net_debug > 5) printk("%s: In interrupt ", dev->name);
- while (--boguscount > 0) {
+ if (net_debug > 5)
+ printk("%s: In interrupt ", dev->name);
+
+ while (--boguscount > 0)
+ {
status = read_nibble(ioaddr, ISR);
- if (net_debug > 5) printk("loop status %02x..", status);
+ if (net_debug > 5)
+ printk("loop status %02x..", status);
if (status & (ISR_RxOK<<3)) {
write_reg(ioaddr, ISR, ISR_RxOK); /* Clear the Rx interrupt. */
break;
}
/* Attempt to retransmit. */
- if (net_debug > 6) printk("attempting to ReTx");
+ if (net_debug > 6)
+ printk("attempting to ReTx");
write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit);
} else {
/* Finish up the transmit. */
lp->re_tx = 0;
} else
lp->tx_unit_busy = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue(dev); /* Inform upper layers. */
}
num_tx_since_rx++;
} else if (num_tx_since_rx > 8
break;
} else
break;
- }
+ }
/* This following code fixes a rare (and very difficult to track down)
problem where the adapter forgets its ethernet address. */
}
/* Tell the adapter that it can go back to using the output line as IRQ. */
- write_reg(ioaddr, CMR2, CMR2_IRQOUT);
+ write_reg(ioaddr, CMR2, CMR2_IRQOUT);
/* Enable the physical interrupt line, which is sure to be low until.. */
outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL);
/* .. we enable the interrupt sources. */
write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK);
write_reg_high(ioaddr, IMR, ISRh_RxErr); /* Hmmm, really needed? */
- if (net_debug > 5) printk("exiting interrupt.\n");
-
- dev->interrupt = 0;
-
+ if (net_debug > 5)
+ printk("exiting interrupt.\n");
+
+ spin_unlock(&lp->lock);
return;
}
problem where the adapter forgets its ethernet address. */
static void atp_timed_checker(unsigned long ignored)
{
- int i;
- int ioaddr = atp_timed_dev->base_addr;
+ int i;
+ struct net_local *lp = (struct net_local *)atp_timed_dev->priv;
+ int ioaddr = atp_timed_dev->base_addr;
- if (!atp_timed_dev->interrupt)
- {
- for (i = 0; i < 6; i++)
-#if 0
- if (read_cmd_byte(ioaddr, PAR0 + i) != atp_timed_dev->dev_addr[i])
- {
- struct net_local *lp = (struct net_local *)atp_timed_dev->priv;
- write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
- if (i == 2)
- lp->stats.tx_errors++;
- else if (i == 3)
- lp->stats.tx_dropped++;
- else if (i == 4)
- lp->stats.collisions++;
- else
- lp->stats.rx_errors++;
- }
-#else
- write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
-#endif
- }
- del_timer(&atp_timer);
- atp_timer.expires = jiffies + TIMED_CHECKER;
- add_timer(&atp_timer);
+ spin_lock(&lp->lock);
+ for (i = 0; i < 6; i++)
+ write_reg_byte(ioaddr, PAR0 + i, atp_timed_dev->dev_addr[i]);
+ spin_unlock(&lp->lock);
+ del_timer(&atp_timer);
+ atp_timer.expires = jiffies + TIMED_CHECKER;
+ add_timer(&atp_timer);
}
#endif
else
do *p++ = read_byte_mode6(ioaddr); while (--length > 0);
- outb(EOC+HNib+MAR, ioaddr + PAR_DATA);
+ outb(EOC+HNib+MAR, ioaddr + PAR_DATA);
outb(Ctrl_SelData, ioaddr + PAR_CONTROL);
}
/* The inverse routine to net_open(). */
-static int
-net_close(struct net_device *dev)
+static int net_close(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
int ioaddr = dev->base_addr;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
/* Flush the Tx and disable Rx here. */
lp->addr_mode = CMR2h_OFF;
free_irq(dev->irq, dev);
/* Leave the hardware in a reset state. */
- write_reg_high(ioaddr, CMR1, CMR1h_RESET);
+ write_reg_high(ioaddr, CMR1, CMR1h_RESET);
return 0;
}
* tab-width: 4
* End:
*/
+
+#ifdef MODULE
+
+static int io = 0;
+static char nullname[8] = "";
+static struct net_device atp_dev = {
+ nullname, 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, atp_probe };
+
+MODULE_PARM(io, "I/O port of the pocket adapter");
+
+int init_module(void)
+{
+ atp_dev.base_addr = io;
+ if (register_netdev(&atp_dev) != 0)
+ return -EIO;
+ return 0;
+}
+
+void cleanup_module(void)
+{
+ unregister_netdev(&atp_dev);
+}
+
+#endif
struct net_local
{
-#ifdef __KERNEL__
struct net_device_stats stats;
-#endif
ushort saved_tx_size;
unsigned char
re_tx, /* Number of packet retransmissions. */
tx_unit_busy,
addr_mode, /* Current Rx filter e.g. promiscuous, etc. */
pac_cnt_in_tx_buf;
+ spinlock_t lock; /* Safety lock */
};
struct rx_header {
CMR2_h = 0x1d,
};
-enum eepage_regs
-{ PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */
+enum eepage_regs { PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */
#define ISR_TxOK 0x01
static void dfx_int_pr_halt_id(DFX_board_t *bp);
static void dfx_int_type_0_process(DFX_board_t *bp);
-static void dfx_int_common(DFX_board_t *bp);
+static void dfx_int_common(struct net_device *dev);
static void dfx_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static struct net_device_stats *dfx_ctl_get_stats(struct net_device *dev);
static void dfx_rcv_queue_process(DFX_board_t *bp);
static int dfx_xmt_queue_pkt(struct sk_buff *skb, struct net_device *dev);
-static void dfx_xmt_done(DFX_board_t *bp);
+static int dfx_xmt_done(DFX_board_t *bp);
static void dfx_xmt_flush(DFX_board_t *bp);
/* Define module-wide (static) variables */
/* Set device structure info */
- dev->tbusy = 0;
- dev->interrupt = DFX_UNMASK_INTERRUPTS;
- dev->start = 1;
+ netif_start_queue(dev);
return(0);
}
/* Clear device structure flags */
- dev->start = 0;
- dev->tbusy = 1;
-
+ netif_stop_queue(dev);
+
/* Deregister (free) IRQ */
free_irq(dev->irq, dev);
* or updating completion indices.
*/
-void dfx_int_common(
- DFX_board_t *bp
- )
-
- {
+void dfx_int_common(struct net_device *dev)
+{
+ DFX_board_t *bp = (DFX_board_t *) dev->priv;
PI_UINT32 port_status; /* Port Status register */
/* Process xmt interrupts - frequent case, so always call this routine */
- dfx_xmt_done(bp); /* free consumed xmt packets */
+ if(dfx_xmt_done(bp)) /* free consumed xmt packets */
+ netif_wake_queue(dev);
/* Process rcv interrupts - frequent case, so always call this routine */
/* Get board pointer only if device structure is valid */
- if (dev == NULL)
- {
- printk("dfx_interrupt(): irq %d for unknown device!\n", irq);
- return;
- }
bp = (DFX_board_t *) dev->priv;
spin_lock(&bp->lock);
/* See if we're already servicing an interrupt */
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler!\n", dev->name);
- dev->interrupt = DFX_MASK_INTERRUPTS; /* ensure non reentrancy */
-
/* Service adapter interrupts */
if (bp->bus_type == DFX_BUS_TYPE_PCI)
/* Call interrupt service routine for this adapter */
- dfx_int_common(bp);
+ dfx_int_common(dev);
/* Clear PDQ interrupt status bit and reenable interrupts */
/* Call interrupt service routine for this adapter */
- dfx_int_common(bp);
+ dfx_int_common(dev);
/* Reenable interrupts at the ESIC */
dfx_port_write_byte(bp, PI_ESIC_K_IO_CONFIG_STAT_0, tmp);
}
- dev->interrupt = DFX_UNMASK_INTERRUPTS;
spin_unlock(&bp->lock);
return;
}
XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */
unsigned long flags;
+ netif_stop_queue(dev);
+
/*
* Verify that incoming transmit request is OK
*
printk("%s: Invalid packet length - %u bytes\n",
dev->name, skb->len);
bp->xmt_length_errors++; /* bump error counter */
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
dev_kfree_skb(skb);
return(0); /* return "success" */
}
{
bp->xmt_discards++; /* bump error counter */
dev_kfree_skb(skb); /* free sk_buff now */
+ netif_wake_queue(dev);
return(0); /* return "success" */
}
}
bp->rcv_xmt_reg.index.xmt_prod = prod;
dfx_port_write_long(bp, PI_PDQ_K_REG_TYPE_2_PROD, bp->rcv_xmt_reg.lword);
spin_unlock_irqrestore(&bp->lock, flags);
+ netif_wake_queue(dev);
return(0); /* packet queued to adapter */
}
* None
*/
-void dfx_xmt_done(
+int dfx_xmt_done(
DFX_board_t *bp
)
{
XMT_DRIVER_DESCR *p_xmt_drv_descr; /* ptr to transmit driver descriptor */
PI_TYPE_2_CONSUMER *p_type_2_cons; /* ptr to rcv/xmt consumer block register */
+ int freed = 0; /* buffers freed */
/* Service all consumed transmit frames */
*/
bp->rcv_xmt_reg.index.xmt_comp += 1;
+ freed++;
}
- return;
+ return freed;
}
\f
-/* drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux. */
/*
- NOTICE: this version tested with kernels 1.3.72 and later only!
+
+ drivers/net/eepro100.c: An Intel i82557-559 Ethernet driver for Linux
+
Written 1996-1999 by Donald Becker.
+ Modified 2000 by Linux Kernel Team
This software may be used and distributed according to the terms
of the GNU Public License, incorporated herein by reference.
http://cesdis.gsfc.nasa.gov/linux/misc/modules.html
There is a Majordomo mailing list based at
linux-eepro100@cesdis.gsfc.nasa.gov
-*/
-
-static const char *version =
-"eepro100.c:v1.09j 7/27/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
-
-/* A few user-configurable values that apply to all boards.
- First set is undocumented and spelled per Intel recommendations. */
-
-static int congenb = 0; /* Enable congestion control in the DP83840. */
-static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */
-static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */
-/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
-static int txdmacount = 128;
-static int rxdmacount = 0;
-
-/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
- Lower values use more memory, but are faster. */
-static int rx_copybreak = 200;
-
-/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
-
-/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
-static int multicast_filter_limit = 64;
-
-/* 'options' is used to pass a transceiver override or full-duplex flag
- e.g. "options=16" for FD, "options=32" for 100mbps-only. */
-static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
-static int debug = -1; /* The debug level */
-
-/* A few values that may be tweaked. */
-/* The ring sizes should be a power of two for efficiency. */
-#define TX_RING_SIZE 32 /* Effectively 2 entries fewer. */
-#define RX_RING_SIZE 32
-/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */
-#define TX_QUEUE_LIMIT 12
-
-/* Operational parameters that usually are not changed. */
-
-/* Time in jiffies before concluding the transmitter is hung. */
-#define TX_TIMEOUT (2*HZ)
-/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
-#define PKT_BUF_SZ 1536
-
-#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
-#warning You must compile this file with the correct options!
-#warning See the last lines of the source file.
-#error You must compile this driver with "-O".
-#endif
-
-#include <linux/version.h>
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/malloc.h>
-#include <linux/interrupt.h>
-#include <linux/timer.h>
-#include <linux/pci.h>
-#include <linux/spinlock.h>
-#include <linux/init.h>
-#include <asm/bitops.h>
-#include <asm/io.h>
-
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/delay.h>
-MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
-MODULE_PARM(debug, "i");
-MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
-MODULE_PARM(congenb, "i");
-MODULE_PARM(txfifo, "i");
-MODULE_PARM(rxfifo, "i");
-MODULE_PARM(txdmacount, "i");
-MODULE_PARM(rxdmacount, "i");
-MODULE_PARM(rx_copybreak, "i");
-MODULE_PARM(max_interrupt_work, "i");
-MODULE_PARM(multicast_filter_limit, "i");
-#define RUN_AT(x) (jiffies + (x))
+ Version history:
+ v1.09j+LK1.0 - Jeff Garzik <jgarzik@mandrakesoft.com>
+ Convert to new PCI driver interface
-/* The total I/O port extent of the board.
- The registers beyond 0x18 only exist on the i82558. */
-#define SPEEDO3_TOTAL_SIZE 0x20
-int speedo_debug = 1;
-/*
Theory of Operation
I. Board Compatibility
*/
-/* This table drives the PCI probe routines. */
-static struct net_device *speedo_found1(struct pci_dev *pdev, long ioaddr,
- int irq, int chip_idx, int fnd_cnt);
-#ifdef USE_IO
-#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_IO|PCI_ADDR1
-#define SPEEDO_SIZE 32
-#else
-#define SPEEDO_IOTYPE PCI_USES_MASTER|PCI_USES_MEM|PCI_ADDR0
-#define SPEEDO_SIZE 0x1000
+static const char *version =
+"eepro100.c:v1.09j+LK1.0 Feb 13, 2000 Linux Kernel Team http://cesdis.gsfc.nasa.gov/linux/drivers/eepro100.html\n";
+
+/* A few user-configurable values that apply to all boards.
+ First set is undocumented and spelled per Intel recommendations. */
+
+static int congenb = 0; /* Enable congestion control in the DP83840. */
+static int txfifo = 8; /* Tx FIFO threshold in 4 byte units, 0-15 */
+static int rxfifo = 8; /* Rx FIFO threshold, default 32 bytes. */
+/* Tx/Rx DMA burst length, 0-127, 0 == no preemption, tx==128 -> disabled. */
+static int txdmacount = 128;
+static int rxdmacount = 0;
+
+/* Set the copy breakpoint for the copy-only-tiny-buffer Rx method.
+ Lower values use more memory, but are faster. */
+static int rx_copybreak = 200;
+
+/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
+static int max_interrupt_work = 20;
+
+/* Maximum number of multicast addresses to filter (vs. rx-all-multicast) */
+static int multicast_filter_limit = 64;
+
+/* 'options' is used to pass a transceiver override or full-duplex flag
+ e.g. "options=16" for FD, "options=32" for 100mbps-only. */
+#if MODULE_SETUP_FIXED
+static int full_duplex[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+static int options[] = {-1, -1, -1, -1, -1, -1, -1, -1};
+#endif
+static int debug = -1; /* The debug level */
+
+/* A few values that may be tweaked. */
+/* The ring sizes should be a power of two for efficiency. */
+#define TX_RING_SIZE 32 /* Effectively 2 entries fewer. */
+#define RX_RING_SIZE 32
+/* Actual number of TX packets queued, must be <= TX_RING_SIZE-2. */
+#define TX_QUEUE_LIMIT 12
+
+/* Operational parameters that usually are not changed. */
+
+/* Time in jiffies before concluding the transmitter is hung. */
+#define TX_TIMEOUT (2*HZ)
+/* Size of an pre-allocated Rx buffer: <Ethernet MTU> + slack.*/
+#define PKT_BUF_SZ 1536
+
+#if !defined(__OPTIMIZE__) || !defined(__KERNEL__)
+#warning You must compile this file with the correct options!
+#warning See the last lines of the source file.
+#error You must compile this driver with "-O".
#endif
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/pci.h>
+#include <linux/spinlock.h>
+#include <linux/init.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/delay.h>
+
+MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
+MODULE_DESCRIPTION("Intel i82557/i82558 PCI EtherExpressPro driver");
+MODULE_PARM(debug, "i");
+
+#if MODULE_OPTIONS_FIXED
+MODULE_PARM(options, "1-" __MODULE_STRING(8) "i");
+MODULE_PARM(full_duplex, "1-" __MODULE_STRING(8) "i");
+#endif
+
+MODULE_PARM(congenb, "i");
+MODULE_PARM(txfifo, "i");
+MODULE_PARM(rxfifo, "i");
+MODULE_PARM(txdmacount, "i");
+MODULE_PARM(rxdmacount, "i");
+MODULE_PARM(rx_copybreak, "i");
+MODULE_PARM(max_interrupt_work, "i");
+MODULE_PARM(multicast_filter_limit, "i");
+
+#define EEPRO100_MODULE_NAME "eepro100"
+#define PFX EEPRO100_MODULE_NAME ": "
+
+#define RUN_AT(x) (jiffies + (x))
+
+int speedo_debug = 1;
+
+
enum pci_flags_bit {
PCI_USES_IO=1, PCI_USES_MEM=2, PCI_USES_MASTER=4,
PCI_ADDR0=0x10<<0, PCI_ADDR1=0x10<<1, PCI_ADDR2=0x10<<2, PCI_ADDR3=0x10<<3,
};
-struct pci_id_info {
- const char *name;
- u16 vendor_id, device_id, device_id_mask, flags;
- int io_size;
- struct net_device *(*probe1)(struct pci_dev *pdev, long ioaddr, int irq, int chip_idx, int fnd_cnt);
-} static pci_tbl[] = {
- { "Intel PCI EtherExpress Pro100",
- 0x8086, 0x1229, 0xffff, PCI_USES_IO|PCI_USES_MASTER, 32, speedo_found1 },
- {0,}, /* 0 terminated list. */
-};
#ifndef USE_IO
#define inb readb
#endif
enum SCBCmdBits {
- SCBMaskCmdDone=0x8000, SCBMaskRxDone=0x4000, SCBMaskCmdIdle=0x2000,
- SCBMaskRxSuspend=0x1000, SCBMaskEarlyRx=0x0800, SCBMaskFlowCtl=0x0400,
- SCBTriggerIntr=0x0200, SCBMaskAll=0x0100,
- /* The rest are Rx and Tx commands. */
- CUStart=0x0010, CUResume=0x0020, CUStatsAddr=0x0040, CUShowStats=0x0050,
- CUCmdBase=0x0060, /* CU Base address (set to zero) . */
- CUDumpStats=0x0070, /* Dump then reset stats counters. */
- RxStart=0x0001, RxResume=0x0002, RxAbort=0x0004, RxAddrLoad=0x0006,
- RxResumeNoResources=0x0007,
+ SCBMaskCmdDone = 0x8000,
+ SCBMaskRxDone = 0x4000,
+ SCBMaskCmdIdle = 0x2000,
+ SCBMaskRxSuspend = 0x1000,
+ SCBMaskEarlyRx = 0x0800,
+ SCBMaskFlowCtl = 0x0400,
+ SCBTriggerIntr = 0x0200,
+ SCBMaskAll = 0x0100,
+ /* The rest are Rx and Tx commands. */
+ CUStart = 0x0010,
+ CUResume = 0x0020,
+ CUStatsAddr = 0x0040,
+ CUShowStats = 0x0050,
+ CUCmdBase = 0x0060, /* CU Base address (set to zero) . */
+ CUDumpStats = 0x0070, /* Dump then reset stats counters. */
+ RxStart = 0x0001,
+ RxResume = 0x0002,
+ RxAbort = 0x0004,
+ RxAddrLoad = 0x0006,
+ RxResumeNoResources = 0x0007,
};
enum SCBPort_cmds {
- PortReset=0, PortSelfTest=1, PortPartialReset=2, PortDump=3,
+ PortReset = 0,
+ PortSelfTest = 1,
+ PortPartialReset = 2,
+ PortDump = 3,
};
/* The Speedo3 Rx and Tx frame/buffer descriptors. */
-struct descriptor { /* A generic descriptor. */
- s32 cmd_status; /* All command and status fields. */
- u32 link; /* struct descriptor * */
+struct descriptor { /* A generic descriptor. */
+ s32 cmd_status; /* All command and status fields. */
+ u32 link; /* struct descriptor * */
unsigned char params[0];
};
/* The Speedo3 Rx and Tx buffer descriptors. */
-struct RxFD { /* Receive frame descriptor. */
+struct RxFD { /* Receive frame descriptor. */
s32 status;
- u32 link; /* struct RxFD * */
- u32 rx_buf_addr; /* void * */
+ u32 link; /* struct RxFD * */
+ u32 rx_buf_addr; /* void * */
u32 count;
};
/* Selected elements of the Tx/RxFD.status word. */
enum RxFD_bits {
- RxComplete=0x8000, RxOK=0x2000,
- RxErrCRC=0x0800, RxErrAlign=0x0400, RxErrTooBig=0x0200, RxErrSymbol=0x0010,
- RxEth2Type=0x0020, RxNoMatch=0x0004, RxNoIAMatch=0x0002,
- TxUnderrun=0x1000, StatusComplete=0x8000,
+ RxComplete = 0x8000,
+ RxOK = 0x2000,
+ RxErrCRC = 0x0800,
+ RxErrAlign = 0x0400,
+ RxErrTooBig = 0x0200,
+ RxErrSymbol = 0x0010,
+ RxEth2Type = 0x0020,
+ RxNoMatch = 0x0004,
+ RxNoIAMatch = 0x0002,
+ TxUnderrun = 0x1000,
+ StatusComplete = 0x8000,
};
-struct TxFD { /* Transmit frame descriptor set. */
+struct TxFD { /* Transmit frame descriptor set. */
s32 status;
- u32 link; /* void * */
- u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
- s32 count; /* # of TBD (=1), Tx start thresh., etc. */
+ u32 link; /* void * */
+ u32 tx_desc_addr; /* Always points to the tx_buf_addr element. */
+ s32 count; /* # of TBD (=1), Tx start thresh., etc. */
/* This constitutes two "TBD" entries -- we only use one. */
- u32 tx_buf_addr0; /* void *, frame to be transmitted. */
- s32 tx_buf_size0; /* Length of Tx frame. */
- u32 tx_buf_addr1; /* void *, frame to be transmitted. */
- s32 tx_buf_size1; /* Length of Tx frame. */
+ u32 tx_buf_addr0; /* void *, frame to be transmitted. */
+ s32 tx_buf_size0; /* Length of Tx frame. */
+ u32 tx_buf_addr1; /* void *, frame to be transmitted. */
+ s32 tx_buf_size1; /* Length of Tx frame. */
};
/* Elements of the dump_statistics block. This block must be lword aligned. */
/* Do not change the position (alignment) of the first few elements!
The later elements are grouped for cache locality. */
struct speedo_private {
- struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */
- struct RxFD *rx_ringp[RX_RING_SIZE]; /* Rx descriptor, used as ring. */
+ struct TxFD *tx_ring; /* Commands (usually CmdTxPacket). */
+ struct RxFD *rx_ringp[RX_RING_SIZE];/* Rx descriptor, used as ring. */
/* The addresses of a Tx/Rx-in-place packets/buffers. */
- struct sk_buff* tx_skbuff[TX_RING_SIZE];
- struct sk_buff* rx_skbuff[RX_RING_SIZE];
- dma_addr_t rx_ring_dma[RX_RING_SIZE];
- dma_addr_t tx_ring_dma;
- struct descriptor *last_cmd; /* Last command sent. */
+ struct sk_buff *tx_skbuff[TX_RING_SIZE];
+ struct sk_buff *rx_skbuff[RX_RING_SIZE];
+ dma_addr_t rx_ring_dma[RX_RING_SIZE];
+ dma_addr_t tx_ring_dma;
+ struct descriptor *last_cmd; /* Last command sent. */
unsigned int cur_tx, dirty_tx; /* The ring entries to be free()ed. */
- spinlock_t lock; /* Group with Tx control cache line. */
- u32 tx_threshold; /* The value for txdesc.count. */
- struct RxFD *last_rxf; /* Last command sent. */
- unsigned int cur_rx, dirty_rx; /* The next free ring entry */
- long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
+ spinlock_t lock; /* Group with Tx control cache line. */
+ u32 tx_threshold; /* The value for txdesc.count. */
+ struct RxFD *last_rxf; /* Last command sent. */
+ unsigned int cur_rx, dirty_rx; /* The next free ring entry */
+ long last_rx_time; /* Last Rx, in jiffies, to handle Rx hang. */
const char *product_name;
- struct net_device *next_module;
- void *priv_addr; /* Unaligned address for kfree */
struct enet_statistics stats;
struct speedo_stats *lstats;
int chip_id;
unsigned char acpi_pwr;
struct pci_dev *pdev;
struct timer_list timer; /* Media selection timer. */
- int mc_setup_frm_len; /* The length of an allocated.. */
- struct descriptor *mc_setup_frm; /* ..multicast setup frame. */
- int mc_setup_busy; /* Avoid double-use of setup frame. */
+ int mc_setup_frm_len; /* The length of an allocated.. */
+ struct descriptor *mc_setup_frm;/* ..multicast setup frame. */
+ int mc_setup_busy; /* Avoid double-use of setup frame. */
dma_addr_t mc_setup_dma;
- char rx_mode; /* Current PROMISC/ALLMULTI setting. */
- unsigned int tx_full:1; /* The Tx queue is full. */
- unsigned int full_duplex:1; /* Full-duplex operation requested. */
- unsigned int flow_ctrl:1; /* Use 802.3x flow control. */
- unsigned int rx_bug:1; /* Work around receiver hang errata. */
- unsigned int rx_bug10:1; /* Receiver might hang at 10mbps. */
- unsigned int rx_bug100:1; /* Receiver might hang at 100mbps. */
- unsigned char default_port:8; /* Last dev->if_port value. */
- unsigned short phy[2]; /* PHY media interfaces available. */
- unsigned short advertising; /* Current PHY advertised caps. */
- unsigned short partner; /* Link partner caps. */
+ char rx_mode; /* Current PROMISC/ALLMULTI setting. */
+ unsigned int tx_full:1; /* The Tx queue is full. */
+ unsigned int full_duplex:1; /* Full-duplex operation requested. */
+ unsigned int flow_ctrl:1; /* Use 802.3x flow control. */
+ unsigned int rx_bug:1; /* Work around receiver hang errata. */
+ unsigned int rx_bug10:1; /* Receiver might hang at 10mbps. */
+ unsigned int rx_bug100:1; /* Receiver might hang at 100mbps. */
+ unsigned char default_port:8; /* Last dev->if_port value. */
+ unsigned short phy[2]; /* PHY media interfaces available. */
+ unsigned short advertising; /* Current PHY advertised caps. */
+ unsigned short partner; /* Link partner caps. */
};
-
/* The parameters for a CmdConfigure operation.
There are so many options that it would be difficult to document each bit.
We mostly use the default or recommended settings. */
0x2000, 0x2100, 0x0400, 0x3100};
#endif
-/* A list of all installed Speedo devices, for removing the driver module. */
-static struct net_device *root_speedo_dev = NULL;
-
-static int __init eepro100_init (void)
-{
- int cards_found = 0;
- struct pci_dev *pdev = NULL;
- long ioaddr;
- int irq;
-
- while ((pdev = pci_find_device (PCI_VENDOR_ID_INTEL,
- PCI_DEVICE_ID_INTEL_82557, pdev))) {
-#ifdef USE_IO
- ioaddr = pdev->resource[1].start;
-#else
- ioaddr = pdev->resource[0].start;
-#endif
- irq = pdev->irq;
-
- /* Remove I/O space marker in bit 0. */
-#ifdef USE_IO
- if (check_region(ioaddr, 32)) {
- printk(KERN_ERR "eepro100: %ld mem region busy\n", ioaddr);
- continue;
- }
-#else
- {
- unsigned long orig_ioaddr = ioaddr;
-
- if (check_mem_region(ioaddr, 32)) {
- printk(KERN_ERR "eepro100: %ld mem region busy\n",
- ioaddr);
- continue;
- }
-
- if ((ioaddr = (long)ioremap(orig_ioaddr, 0x1000)) == 0) {
- printk(KERN_INFO "Failed to map PCI address %#lx.\n",
- orig_ioaddr);
- continue;
- }
- }
-#endif
- if (speedo_debug > 2)
- printk("Found Intel i82557 PCI Speedo at I/O %#lx, IRQ %d.\n",
- ioaddr, irq);
-
- if(speedo_found1(pdev, ioaddr, irq, 0,cards_found))
- cards_found++;
- }
-
- return cards_found;
-}
-static struct net_device *speedo_found1(struct pci_dev *pdev,
- long ioaddr, int irq, int chip_idx, int card_idx)
+static int __devinit eepro100_init_one (struct pci_dev *pdev,
+ const struct pci_device_id *ent)
{
struct net_device *dev;
struct speedo_private *sp;
const char *product;
int i, option;
u16 eeprom[0x100];
- int acpi_idle_state = 0, pm;
+ int acpi_idle_state = 0, pm, irq;
+ unsigned long ioaddr;
static int did_version = 0; /* Already printed version info. */
+
+#ifdef USE_IO
+ ioaddr = pci_resource_start (pdev, 0);
+#else
+ ioaddr = pci_resource_start (pdev, 1);
+#endif
+ irq = pdev->irq;
+
+ if (!request_region (pci_resource_start (pdev, 1),
+ pci_resource_len (pdev, 1),
+ EEPRO100_MODULE_NAME)) {
+ printk (KERN_ERR PFX "cannot reserve I/O ports\n");
+ goto err_out_none;
+ }
+ if (!request_mem_region (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0),
+ EEPRO100_MODULE_NAME)) {
+ printk (KERN_ERR PFX "cannot reserve MMIO region\n");
+ goto err_out_free_pio_region;
+ }
+
+#ifndef USE_IO
+ ioaddr = (unsigned long) ioremap (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0));
+ if (!ioaddr) {
+ printk (KERN_ERR PFX "cannot remap MMIO region %lx @ %lx\n",
+ pci_resource_len (pdev, 0),
+ pci_resource_start (pdev, 0));
+ goto err_out_free_mmio_region;
+ }
+#endif
+
if (speedo_debug > 0 && did_version++ == 0)
printk(version);
tx_ring = pci_alloc_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
+ sizeof(struct speedo_stats), &tx_ring_dma);
if (!tx_ring) {
- printk(KERN_ERR "Could not allocate DMA memory.\n");
- return NULL;
+ printk(KERN_ERR PFX "Could not allocate DMA memory.\n");
+ goto err_out_iounmap;
}
dev = init_etherdev(NULL, sizeof(struct speedo_private));
if (dev == NULL) {
- pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
- + sizeof(struct speedo_stats),
- tx_ring, tx_ring_dma);
- return NULL;
+ printk(KERN_ERR PFX "Could not allocate ethernet device.\n");
+ goto err_out_free_tx_ring;
+ }
+ if (dev->priv == NULL) {
+ printk(KERN_ERR PFX "Could not allocate ethernet device private info.\n");
+ goto err_out_free_netdev;
}
if (dev->mem_start > 0)
option = dev->mem_start;
+#if MODULE_SETUP_FIXED
else if (card_idx >= 0 && options[card_idx] >= 0)
option = options[card_idx];
+#endif
else
option = 0;
if (eeprom[3] & 0x0100)
product = "OEM i82557/i82558 10/100 Ethernet";
else
- product = pci_tbl[chip_idx].name;
+ product = "Intel PCI EtherExpress Pro100";
printk(KERN_INFO "%s: %s at %#3lx, ", dev->name, product, ioaddr);
/* Return the chip to its original power state. */
pci_set_power_state (pdev, acpi_idle_state);
-#ifdef USE_IO
- request_region(ioaddr, SPEEDO3_TOTAL_SIZE, "Intel Speedo3 Ethernet");
-#else
- request_mem_region(ioaddr, 0x1000, "Intel Speedo3 Ethernet");
-#endif
-
dev->base_addr = ioaddr;
dev->irq = irq;
sp = dev->priv;
- if (dev->priv == NULL) {
- void *mem = kmalloc(sizeof(*sp), GFP_KERNEL);
- dev->priv = sp = mem; /* Cache align here if kmalloc does not. */
- sp->priv_addr = mem;
- }
memset(sp, 0, sizeof(*sp));
- sp->next_module = root_speedo_dev;
- root_speedo_dev = dev;
sp->pdev = pdev;
- sp->chip_id = chip_idx;
sp->acpi_pwr = acpi_idle_state;
sp->tx_ring = (struct TxFD *)tx_ring;
sp->tx_ring_dma = tx_ring_dma;
sp->lstats = (struct speedo_stats *)(sp->tx_ring + TX_RING_SIZE);
sp->full_duplex = option >= 0 && (option & 0x10) ? 1 : 0;
+
+#if MODULE_SETUP_FIXED
if (card_idx >= 0) {
if (full_duplex[card_idx] >= 0)
sp->full_duplex = full_duplex[card_idx];
}
+#endif
+
sp->default_port = option >= 0 ? (option & 0x0f) : 0;
sp->phy[0] = eeprom[6];
dev->set_multicast_list = &set_rx_mode;
dev->do_ioctl = &speedo_ioctl;
- return dev;
+ return 0;
+
+err_out_free_netdev:
+ unregister_netdevice (dev);
+ kfree (dev);
+err_out_free_tx_ring:
+ pci_free_consistent(pdev, TX_RING_SIZE * sizeof(struct TxFD)
+ + sizeof(struct speedo_stats),
+ tx_ring, tx_ring_dma);
+err_out_iounmap:
+#ifndef USE_IO
+ iounmap ((void *)ioaddr);
+#endif
+err_out_free_mmio_region:
+ release_mem_region (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0));
+err_out_free_pio_region:
+ release_region (pci_resource_start (pdev, 1),
+ pci_resource_len (pdev, 1));
+err_out_none:
+ return -ENODEV;
}
-\f
+
+
/* Serial EEPROM section.
A "bit" grungy, but we work our way through bit-by-bit :->. */
/* EEPROM_Ctrl bits. */
}
+static void eepro100_suspend (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ long ioaddr = dev->base_addr;
+
+ netif_stop_queue (dev);
+ outl(PortPartialReset, ioaddr + SCBPort);
+}
+
+
+static void eepro100_resume (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ struct speedo_private *np = (struct speedo_private *)dev->priv;
+
+ speedo_resume(dev);
+ np->rx_mode = -1;
+ np->flow_ctrl = np->partner = 0;
+ set_rx_mode(dev);
+}
+
+
+static void __devexit eepro100_remove_one (struct pci_dev *pdev)
+{
+ struct net_device *dev = pdev->driver_data;
+ struct speedo_private *sp = (struct speedo_private *)dev->priv;
+
+ unregister_netdev (dev);
+
+ release_region (pci_resource_start (pdev, 1),
+ pci_resource_len (pdev, 1));
+ release_mem_region (pci_resource_start (pdev, 0),
+ pci_resource_len (pdev, 0));
+
+#ifndef USE_IO
+ iounmap ((char *) dev->base_addr);
+#endif
+
+ pci_set_power_state (pdev, sp->acpi_pwr);
+
+ kfree (dev);
+}
+
+
+static struct pci_device_id eepro100_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82557,
+ PCI_ANY_ID, PCI_ANY_ID, },
+ { 0,},
+};
+MODULE_DEVICE_TABLE (pci, eepro100_pci_tbl);
+
+
+static struct pci_driver eepro100_driver = {
+ name: EEPRO100_MODULE_NAME,
+ id_table: eepro100_pci_tbl,
+ probe: eepro100_init_one,
+ remove: eepro100_remove_one,
+ suspend: eepro100_suspend,
+ resume: eepro100_resume,
+};
+
+
static int __init eepro100_init_module(void)
{
int cards_found;
if (debug >= 0)
speedo_debug = debug;
+
/* Always emit the version message. */
if (speedo_debug)
printk(KERN_INFO "%s", version);
- cards_found = eepro100_init();
+ cards_found = pci_register_driver (&eepro100_driver);
if (cards_found <= 0) {
- printk(KERN_INFO "eepro100: No cards found, driver not installed.\n");
+ printk(KERN_INFO PFX "No cards found, driver not installed.\n");
return -ENODEV;
}
+
return 0;
}
+
static void __exit eepro100_cleanup_module(void)
{
- struct net_device *next_dev;
-
- /* No need to check MOD_IN_USE, as sys_delete_module() checks. */
- while (root_speedo_dev) {
- struct speedo_private *sp = (void *)root_speedo_dev->priv;
- unregister_netdev(root_speedo_dev);
-#ifdef USE_IO
- release_region(root_speedo_dev->base_addr, SPEEDO3_TOTAL_SIZE);
-#else
- release_mem_region(root_speedo_dev->base_addr, 0x1000);
- iounmap((char *)root_speedo_dev->base_addr);
-#endif
- pci_set_power_state(sp->pdev, sp->acpi_pwr);
- next_dev = sp->next_module;
- if (sp->priv_addr)
- kfree(sp->priv_addr);
- kfree(root_speedo_dev);
- root_speedo_dev = next_dev;
- }
+ pci_unregister_driver (&eepro100_driver);
}
+
module_init(eepro100_init_module);
module_exit(eepro100_cleanup_module);
dev->do_ioctl = &mii_ioctl;
dev->tx_timeout = epic_tx_timeout;
dev->watchdog_timeo = TX_TIMEOUT;
+
+ netif_stop_queue (dev);
return dev;
}
int mii_reg5;
ep->full_duplex = ep->force_fd;
+ MOD_INC_USE_COUNT;
+
/* Soft reset the chip. */
outl(0x4001, ioaddr + GENCTL);
- if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, "SMC EPIC/100", dev))
- return -EAGAIN;
-
- MOD_INC_USE_COUNT;
+ if (request_irq(dev->irq, &epic_interrupt, SA_SHIRQ, "SMC EPIC/100", dev)) {
+ MOD_DEC_USE_COUNT;
+ return -EBUSY;
+ }
epic_init_ring(dev);
set_rx_mode(dev);
outl(0x000A, ioaddr + COMMAND);
- netif_start_queue(dev);
-
/* Enable interrupts by setting the interrupt mask. */
outl((ep->chip_id == 6 ? PCIBusErr175 : PCIBusErr170)
| CntFull | TxUnderrun | TxDone
dev->name, ioaddr, dev->irq, inl(ioaddr + GENCTL),
ep->full_duplex ? "full" : "half");
+ netif_start_queue(dev);
+
/* Set the timer to switch to check for link beat and perhaps switch
to an alternate media type. */
init_timer(&ep->timer);
- ep->timer.expires = RUN_AT((24*HZ)/10); /* 2.4 sec. */
+ ep->timer.expires = RUN_AT(3*HZ); /* 3 sec. */
ep->timer.data = (unsigned long)dev;
ep->timer.function = &epic_timer; /* timer handler */
add_timer(&ep->timer);
long ioaddr = dev->base_addr;
struct epic_private *ep = (struct epic_private *)dev->priv;
+ netif_stop_queue (dev);
+
/* Disable interrupts by clearing the interrupt mask. */
outl(0x00000000, ioaddr + INTMASK);
/* Stop the chip's Tx and Rx DMA processes. */
| CntFull | TxUnderrun | TxDone
| RxError | RxOverflow | RxFull | RxHeader | RxDone,
ioaddr + INTMASK);
+
+ netif_start_queue (dev);
+
printk(KERN_DEBUG "%s: epic_restart() done, cmd status %4.4x, ctl %4.4x"
" interrupt %4.4x.\n",
dev->name, inl(ioaddr + COMMAND), inl(ioaddr + GENCTL),
inl(ioaddr + INTSTAT));
- return;
}
static void epic_timer(unsigned long data)
dev->trans_start = jiffies;
ep->stats.tx_errors++;
- return;
+
+ netif_start_queue (dev);
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
int entry;
u32 flag;
+ netif_stop_queue (dev);
+
/* Caution: the write order is important here, set the base address
with the "ownership" bits last. */
if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE/2) {/* Typical path */
flag = 0x10; /* No interrupt */
- netif_start_queue(dev);
} else if (ep->cur_tx - ep->dirty_tx == TX_RING_SIZE/2) {
flag = 0x14; /* Tx-done intr. */
- netif_start_queue(dev);
} else if (ep->cur_tx - ep->dirty_tx < TX_RING_SIZE - 2) {
flag = 0x10; /* No Tx-done intr. */
- netif_start_queue(dev);
} else {
/* Leave room for two additional entries. */
flag = 0x14; /* Tx-done intr. */
outl(0x0004, dev->base_addr + COMMAND);
dev->trans_start = jiffies;
+
+ if (! ep->tx_full)
+ netif_start_queue (dev);
+
if (epic_debug > 4)
printk(KERN_DEBUG "%s: Queued Tx packet size %d to slot %d, "
"flag %2.2x Tx status %8.8x.\n",
dirty_tx > ep->cur_tx - TX_RING_SIZE + 2) {
/* The ring is no longer full, clear tbusy. */
ep->tx_full = 0;
- netif_wake_queue (dev);
}
+
+ if (ep->tx_full)
+ netif_stop_queue (dev);
+ else
+ netif_wake_queue (dev);
ep->dirty_tx = dirty_tx;
}
#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <asm/io.h>
#include <asm/dma.h>
-#ifndef LINUX_VERSION_CODE
-#include <linux/version.h>
-#endif
-
-#if LINUX_VERSION_CODE >= 0x20123
-#include <linux/init.h>
-#else
-#define __init
-#define __initdata
-#endif
-#if LINUX_VERSION_CODE < 0x20138
-#define test_and_set_bit(val,addr) set_bit(val,addr)
-#endif
-
-#if LINUX_VERSION_CODE < 0x020100
-typedef struct enet_statistics eth16i_stats_type;
-#else
-typedef struct net_device_stats eth16i_stats_type;
-#endif
/* Few macros */
#define BIT(a) ( (1 << (a)) )
#define RESET ID_ROM_0
/* This is the I/O address list to be probed when seeking the card */
-static unsigned int eth16i_portlist[] =
- { 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0 };
+static unsigned int eth16i_portlist[] = {
+ 0x260, 0x280, 0x2A0, 0x240, 0x340, 0x320, 0x380, 0x300, 0
+};
-static unsigned int eth32i_portlist[] =
- { 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
- 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0 };
+static unsigned int eth32i_portlist[] = {
+ 0x1000, 0x2000, 0x3000, 0x4000, 0x5000, 0x6000, 0x7000, 0x8000,
+ 0x9000, 0xA000, 0xB000, 0xC000, 0xD000, 0xE000, 0xF000, 0
+};
/* This is the Interrupt lookup table for Eth16i card */
static unsigned int eth16i_irqmap[] = { 9, 10, 5, 15, 0 };
/* Information for each board */
struct eth16i_local {
- eth16i_stats_type stats;
+ struct net_device_stats stats;
unsigned char tx_started;
unsigned char tx_buf_busy;
unsigned short tx_queue; /* Number of packets in transmit buffer */
unsigned long tx_buffered_packets;
unsigned long tx_buffered_bytes;
unsigned long col_16;
+ spinlock_t lock;
};
/* Function prototypes */
static int eth16i_close(struct net_device *dev);
static int eth16i_tx(struct sk_buff *skb, struct net_device *dev);
static void eth16i_rx(struct net_device *dev);
+static void eth16i_timeout(struct net_device *dev);
static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs);
static void eth16i_reset(struct net_device *dev);
+static void eth16i_timeout(struct net_device *dev);
static void eth16i_skip_packet(struct net_device *dev);
static void eth16i_multicast(struct net_device *dev);
static void eth16i_select_regbank(unsigned char regbank, int ioaddr);
static ushort eth16i_parse_mediatype(const char* s);
#endif
-static struct enet_statistics *eth16i_get_stats(struct net_device *dev);
+static struct net_device_stats *eth16i_get_stats(struct net_device *dev);
static char *cardname = "ICL EtherTeam 16i/32";
-#ifdef HAVE_DEVLIST
-
-/* Support for alternate probe manager */
-/struct netdev_entry eth16i_drv =
- {"eth16i", eth16i_probe1, ETH16I_IO_EXTENT, eth16i_probe_list};
-
-#else /* Not HAVE_DEVLIST */
-
int __init eth16i_probe(struct net_device *dev)
{
int i;
return ENODEV;
}
-#endif /* Not HAVE_DEVLIST */
static int __init eth16i_probe1(struct net_device *dev, int ioaddr)
{
+ struct eth16i_local *lp;
+
static unsigned version_printed = 0;
boot = 1; /* To inform initilization that we are in boot probe */
printk(KERN_INFO "%s", version);
dev->base_addr = ioaddr;
-
-#if 0
- if(dev->irq) {
- if(eth16i_set_irq(dev)) {
- dev->irq = eth16i_get_irq(ioaddr);
- }
-
- }
- else {
-#endif
-
dev->irq = eth16i_get_irq(ioaddr);
/* Try to obtain interrupt vector */
return -EAGAIN;
}
-#if 0
- irq2dev_map[dev->irq] = dev;
-#endif
-
printk(KERN_INFO "%s: %s at %#3x, IRQ %d, ",
dev->name, cardname, ioaddr, dev->irq);
}
memset(dev->priv, 0, sizeof(struct eth16i_local));
-
dev->open = eth16i_open;
dev->stop = eth16i_close;
dev->hard_start_xmit = eth16i_tx;
dev->get_stats = eth16i_get_stats;
- dev->set_multicast_list = ð16i_multicast;
+ dev->set_multicast_list = eth16i_multicast;
+ dev->tx_timeout = eth16i_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+
+ lp = (struct eth16i_local *)dev->priv;
+ spin_lock_init(&lp->lock);
/* Fill in the fields of the device structure with ethernet values. */
ether_setup(dev);
/* Turn on interrupts*/
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
/* Turn off interrupts*/
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- dev->start = 0;
- dev->tbusy = 1;
-
+ netif_stop_queue(dev);
+
lp->open_time = 0;
/* Disable transmit and receive */
return 0;
}
-static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
+static void eth16i_timeout(struct net_device *dev)
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
int ioaddr = dev->base_addr;
- int status = 0;
+ /*
+ If we get here, some higher level has decided that
+ we are broken. There should really be a "kick me"
+ function call instead.
+ */
- if(dev->tbusy) {
-
- /*
- If we get here, some higher level has decided that
- we are broken. There should really be a "kick me"
- function call instead.
- */
-
- int tickssofar = jiffies - dev->trans_start;
- if(tickssofar < TX_TIMEOUT)
- return 1;
-
- outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
-
- printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
- dev->name,
- inw(ioaddr + TX_STATUS_REG),
- (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
+ outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+ printk(KERN_WARNING "%s: transmit timed out with status %04x, %s ?\n",
+ dev->name,
+ inw(ioaddr + TX_STATUS_REG), (inb(ioaddr + TX_STATUS_REG) & TX_DONE) ?
"IRQ conflict" : "network cable problem");
- dev->trans_start = jiffies;
-
- /* Let's dump all registers */
- if(eth16i_debug > 0) {
- printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
- dev->name, inb(ioaddr + 0),
- inb(ioaddr + 1), inb(ioaddr + 2),
- inb(ioaddr + 3), inb(ioaddr + 4),
- inb(ioaddr + 5),
- inb(ioaddr + 6), inb(ioaddr + 7));
+ dev->trans_start = jiffies;
- printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
- dev->name, inb(ioaddr + TRANSMIT_START_REG),
- inb(ioaddr + COL_16_REG));
+ /* Let's dump all registers */
+ if(eth16i_debug > 0) {
+ printk(KERN_DEBUG "%s: timeout: %02x %02x %02x %02x %02x %02x %02x %02x.\n",
+ dev->name, inb(ioaddr + 0),
+ inb(ioaddr + 1), inb(ioaddr + 2),
+ inb(ioaddr + 3), inb(ioaddr + 4),
+ inb(ioaddr + 5),
+ inb(ioaddr + 6), inb(ioaddr + 7));
+ printk(KERN_DEBUG "%s: transmit start reg: %02x. collision reg %02x\n",
+ dev->name, inb(ioaddr + TRANSMIT_START_REG),
+ inb(ioaddr + COL_16_REG));
printk(KERN_DEBUG "lp->tx_queue = %d\n", lp->tx_queue);
- printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
- printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
-
- }
-
- lp->stats.tx_errors++;
-
- eth16i_reset(dev);
-
- dev->trans_start = jiffies;
-
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
+ printk(KERN_DEBUG "lp->tx_queue_len = %d\n", lp->tx_queue_len);
+ printk(KERN_DEBUG "lp->tx_started = %d\n", lp->tx_started);
}
+ lp->stats.tx_errors++;
+ eth16i_reset(dev);
+ dev->trans_start = jiffies;
+ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+ netif_wake_queue(dev);
+}
- /*
- If some higher layer thinks we've missed an tx-done interrupt
- we are passed NULL. Caution: dev_tint() handles the cli()/sti()
- itself
- */
-
- if(skb == NULL) {
-#if LINUX_VERSION_CODE < 0x020100
- dev_tint(dev);
-#endif
- if(eth16i_debug > 0)
- printk(KERN_WARNING "%s: Missed tx-done interrupt.\n", dev->name);
- return 0;
- }
+static int eth16i_tx(struct sk_buff *skb, struct net_device *dev)
+{
+ struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int status = 0;
+ ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = skb->data;
+ unsigned long flags;
- /* Block a timer based transmitter from overlapping.
- This could better be done with atomic_swap(1, dev->tbusy),
- but set_bit() works as well. */
- set_bit(0, (void *)&lp->tx_buf_busy);
-
+ netif_stop_queue(dev);
+
/* Turn off TX interrupts */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
+
+ /* We would be better doing the disable_irq tricks the 3c509 does,
+ that would make this suck a lot less */
+
+ spin_lock_irqsave(&lp->lock, flags);
- if(test_and_set_bit(0, (void *)&dev->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name);
- status = -1;
- }
+ if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
+ if(eth16i_debug > 0)
+ printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
+ }
else {
- ushort length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
- unsigned char *buf = skb->data;
+ outw(length, ioaddr + DATAPORT);
- if( (length + 2) > (lp->tx_buf_size - lp->tx_queue_len)) {
- if(eth16i_debug > 0)
- printk(KERN_WARNING "%s: Transmit buffer full.\n", dev->name);
- }
+ if( ioaddr < 0x1000 )
+ outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
else {
- outw(length, ioaddr + DATAPORT);
-
- if( ioaddr < 0x1000 )
- outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1);
- else {
- unsigned char frag = length % 4;
-
- outsl(ioaddr + DATAPORT, buf, length >> 2);
-
- if( frag != 0 ) {
- outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
- if( frag == 3 )
- outsw(ioaddr + DATAPORT,
- (buf + (length & 0xFFFC) + 2), 1);
- }
+ unsigned char frag = length % 4;
+ outsl(ioaddr + DATAPORT, buf, length >> 2);
+ if( frag != 0 ) {
+ outsw(ioaddr + DATAPORT, (buf + (length & 0xFFFC)), 1);
+ if( frag == 3 )
+ outsw(ioaddr + DATAPORT,
+ (buf + (length & 0xFFFC) + 2), 1);
}
-
- lp->tx_buffered_packets++;
- lp->tx_buffered_bytes = length;
- lp->tx_queue++;
- lp->tx_queue_len += length + 2;
- }
-
- lp->tx_buf_busy = 0;
-
- if(lp->tx_started == 0) {
- /* If the transmitter is idle..always trigger a transmit */
- outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
- lp->tx_queue = 0;
- lp->tx_queue_len = 0;
- dev->trans_start = jiffies;
- lp->tx_started = 1;
- dev->tbusy = 0;
- }
- else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
- /* There is still more room for one more packet in tx buffer */
- dev->tbusy = 0;
}
-
- outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
-
- /* Turn TX interrupts back on */
- /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
- status = 0;
- }
+ lp->tx_buffered_packets++;
+ lp->tx_buffered_bytes = length;
+ lp->tx_queue++;
+ lp->tx_queue_len += length + 2;
+ }
+ lp->tx_buf_busy = 0;
-#if LINUX_VERSION_CODE >= 0x020100
+ if(lp->tx_started == 0) {
+ /* If the transmitter is idle..always trigger a transmit */
+ outb(TX_START | lp->tx_queue, ioaddr + TRANSMIT_START_REG);
+ lp->tx_queue = 0;
+ lp->tx_queue_len = 0;
+ dev->trans_start = jiffies;
+ lp->tx_started = 1;
+ netif_wake_queue(dev);
+ }
+ else if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
+ /* There is still more room for one more packet in tx buffer */
+ netif_wake_queue(dev);
+ }
+
+ spin_unlock_irqrestore(&lp->lock, flags);
+
+ outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
+ /* Turn TX interrupts back on */
+ /* outb(TX_INTR_DONE | TX_INTR_16_COL, ioaddr + TX_INTR_REG); */
+ status = 0;
dev_kfree_skb(skb);
-#else
- dev_kfree_skb(skb, FREE_WRITE);
-#endif
-
- return status;
+ return 0;
}
static void eth16i_rx(struct net_device *dev)
break;
} /* while */
-
-#if 0
- {
- int i;
-
- for(i = 0; i < 20; i++) {
- if( (inb(ioaddr+RECEIVE_MODE_REG) & RX_BUFFER_EMPTY) ==
- RX_BUFFER_EMPTY)
- break;
- inw(ioaddr + DATAPORT);
- outb(SKIP_RX_PACKET, ioaddr + FILTER_SELF_RX_REG);
- }
-
- if(eth16i_debug > 1)
- printk(KERN_DEBUG "%s: Flushed receive buffer.\n", dev->name);
- }
-#endif
-
- return;
}
static void eth16i_interrupt(int irq, void *dev_id, struct pt_regs *regs)
{
struct net_device *dev = dev_id;
struct eth16i_local *lp;
- int ioaddr = 0,
- status;
+ int ioaddr = 0, status;
- if(dev == NULL) {
- printk(KERN_WARNING "eth16i_interrupt(): irq %d for unknown device. \n", irq);
- return;
- }
+ ioaddr = dev->base_addr;
+ lp = (struct eth16i_local *)dev->priv;
/* Turn off all interrupts from adapter */
outw(ETH16I_INTR_OFF, ioaddr + TX_INTR_REG);
- set_bit(0, (void *)&dev->tbusy); /* Set the device busy so that */
/* eth16i_tx wont be called */
+ spin_lock(&lp->lock);
- if(dev->interrupt)
- printk(KERN_WARNING "%s: Re-entering the interrupt handler.\n", dev->name);
- dev->interrupt = 1;
-
- ioaddr = dev->base_addr;
- lp = (struct eth16i_local *)dev->priv;
status = inw(ioaddr + TX_STATUS_REG); /* Get the status */
outw(status, ioaddr + TX_STATUS_REG); /* Clear status bits */
lp->tx_queue = 0;
lp->tx_queue_len = 0;
lp->tx_started = 1;
- dev->trans_start = jiffies;
- mark_bh(NET_BH);
}
else {
lp->tx_started = 0;
- mark_bh(NET_BH);
}
+ netif_wake_queue(dev);
}
}
eth16i_rx(dev); /* We have packet in receive buffer */
}
- dev->interrupt = 0;
-
/* Turn interrupts back on */
outw(ETH16I_INTR_ON, ioaddr + TX_INTR_REG);
if(lp->tx_queue_len < lp->tx_buf_size - (ETH_FRAME_LEN + 2)) {
/* There is still more room for one more packet in tx buffer */
- dev->tbusy = 0;
+ netif_wake_queue(dev);
}
+ spin_unlock(&lp->lock);
+
return;
}
lp->tx_buf_busy = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
-
- dev->interrupt = 0;
- dev->start = 1;
- dev->tbusy = 0;
BITCLR(ioaddr + CONFIG_REG_0, DLC_EN);
}
}
}
-static struct enet_statistics *eth16i_get_stats(struct net_device *dev)
+static struct net_device_stats *eth16i_get_stats(struct net_device *dev)
{
struct eth16i_local *lp = (struct eth16i_local *)dev->priv;
-
return &lp->stats;
}
static void ewrk3_init(struct net_device *dev);
static int ewrk3_rx(struct net_device *dev);
static int ewrk3_tx(struct net_device *dev);
+static void ewrk3_timeout(struct net_device *dev);
static void EthwrkSignature(char *name, char *eeprom_image);
static int DevicePresent(u_long iobase);
printk(version);
}
/* The EWRK3-specific entries in the device structure. */
- dev->open = &ewrk3_open;
- dev->hard_start_xmit = &ewrk3_queue_pkt;
- dev->stop = &ewrk3_close;
- dev->get_stats = &ewrk3_get_stats;
- dev->set_multicast_list = &set_multicast_list;
- dev->do_ioctl = &ewrk3_ioctl;
+ dev->open = ewrk3_open;
+ dev->hard_start_xmit = ewrk3_queue_pkt;
+ dev->stop = ewrk3_close;
+ dev->get_stats = ewrk3_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+ dev->do_ioctl = ewrk3_ioctl;
+ dev->tx_timeout = ewrk3_timeout;
+ dev->watchdog_timeo = QUEUE_PKT_TIMEOUT;
dev->mem_start = 0;
} else {
status = -ENXIO;
}
-
return status;
}
\f
printk(" cmr: 0x%02x\n", inb(EWRK3_CMR));
printk(" fmqc: 0x%02x\n", inb(EWRK3_FMQC));
}
- dev->tbusy = 0;
- dev->start = 1;
- dev->interrupt = UNMASK_INTERRUPTS;
-
+ netif_start_queue(dev);
/*
** Unmask EWRK3 board interrupts
*/
}
} else {
- dev->start = 0;
- dev->tbusy = 1;
- printk("%s: ewrk3 available for hard strapped set up only.\n", dev->name);
- printk(" Run the 'ewrk3setup' utility or remove the hard straps.\n");
+ printk(KERN_ERR "%s: ewrk3 available for hard strapped set up only.\n", dev->name);
+ printk(KERN_ERR " Run the 'ewrk3setup' utility or remove the hard straps.\n");
+ return -EINVAL;
}
MOD_INC_USE_COUNT;
}
/*
- ** Writes a socket buffer to the free page queue
+ * Transmit timeout
*/
-static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev)
+
+static void ewrk3_timeout(struct net_device *dev)
{
struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
- u_long iobase = dev->base_addr;
- int status = 0;
u_char icr, csr;
+ u_long iobase = dev->base_addr;
+
+ if (!lp->hard_strapped)
+ {
+ printk(KERN_WARNING"%s: transmit timed/locked out, status %04x, resetting.\n",
+ dev->name, inb(EWRK3_CSR));
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy || lp->lock) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < QUEUE_PKT_TIMEOUT) {
- status = -1;
- } else if (!lp->hard_strapped) {
- printk("%s: transmit timed/locked out, status %04x, resetting.\n",
- dev->name, inb(EWRK3_CSR));
-
- /*
- ** Mask all board interrupts
- */
- DISABLE_IRQs;
-
- /*
- ** Stop the TX and RX...
- */
- STOP_EWRK3;
-
- ewrk3_init(dev);
-
- /*
- ** Unmask EWRK3 board interrupts
- */
- ENABLE_IRQs;
-
- dev->tbusy = 0;
- dev->trans_start = jiffies;
- }
- } else if (skb->len > 0) {
+ /*
+ ** Mask all board interrupts
+ */
+ DISABLE_IRQs;
/*
- ** Block a timer-based transmit from overlapping. This could better be
- ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
+ ** Stop the TX and RX...
*/
- if (test_and_set_bit(0, (void *) &dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
+ STOP_EWRK3;
- DISABLE_IRQs; /* So that the page # remains correct */
+ ewrk3_init(dev);
/*
- ** Get a free page from the FMQ when resources are available
+ ** Unmask EWRK3 board interrupts
*/
- if (inb(EWRK3_FMQC) > 0) {
- u_long buf = 0;
- u_char page;
+ ENABLE_IRQs;
- if ((page = inb(EWRK3_FMQ)) < lp->mPage) {
- /*
- ** Set up shared memory window and pointer into the window
- */
- while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */
- if (lp->shmem_length == IO_ONLY) {
- outb(page, EWRK3_IOPR);
- } else if (lp->shmem_length == SHMEM_2K) {
- buf = lp->shmem_base;
- outb(page, EWRK3_MPR);
- } else if (lp->shmem_length == SHMEM_32K) {
- buf = ((((short) page << 11) & 0x7800) + lp->shmem_base);
- outb((page >> 4), EWRK3_MPR);
- } else if (lp->shmem_length == SHMEM_64K) {
- buf = ((((short) page << 11) & 0xf800) + lp->shmem_base);
- outb((page >> 5), EWRK3_MPR);
- } else {
- status = -1;
- printk("%s: Oops - your private data area is hosed!\n", dev->name);
- }
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+ }
+}
- if (!status) {
+/*
+ ** Writes a socket buffer to the free page queue
+ */
+static int ewrk3_queue_pkt(struct sk_buff *skb, struct net_device *dev)
+{
+ struct ewrk3_private *lp = (struct ewrk3_private *) dev->priv;
+ u_long iobase = dev->base_addr;
+ int status = 0;
+ u_char icr;
- /*
- ** Set up the buffer control structures and copy the data from
- ** the socket buffer to the shared memory .
- */
+ netif_stop_queue(dev);
+#ifdef CONFIG_SMP
+#error "This needs spinlocks"
+#endif
+ DISABLE_IRQs; /* So that the page # remains correct */
- if (lp->shmem_length == IO_ONLY) {
- int i;
- u_char *p = skb->data;
+ /*
+ ** Get a free page from the FMQ when resources are available
+ */
+ if (inb(EWRK3_FMQC) > 0)
+ {
+ u_long buf = 0;
+ u_char page;
+ if ((page = inb(EWRK3_FMQ)) < lp->mPage) {
+ /*
+ ** Set up shared memory window and pointer into the window
+ */
+ while (test_and_set_bit(0, (void *) &lp->lock) != 0); /* Wait for lock to free */
+ if (lp->shmem_length == IO_ONLY) {
+ outb(page, EWRK3_IOPR);
+ } else if (lp->shmem_length == SHMEM_2K) {
+ buf = lp->shmem_base;
+ outb(page, EWRK3_MPR);
+ } else if (lp->shmem_length == SHMEM_32K) {
+ buf = ((((short) page << 11) & 0x7800) + lp->shmem_base);
+ outb((page >> 4), EWRK3_MPR);
+ } else if (lp->shmem_length == SHMEM_64K) {
+ buf = ((((short) page << 11) & 0xf800) + lp->shmem_base);
+ outb((page >> 5), EWRK3_MPR);
+ } else {
+ status = -1;
+ printk(KERN_ERR "%s: Oops - your private data area is hosed!\n", dev->name);
+ }
+
+ if (!status) {
+ /*
+ ** Set up the buffer control structures and copy the data from
+ ** the socket buffer to the shared memory .
+ */
+ if (lp->shmem_length == IO_ONLY) {
+ int i;
+ u_char *p = skb->data;
outb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), EWRK3_DATA);
- outb((char) (skb->len & 0xff), EWRK3_DATA);
- outb((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);
- outb((char) 0x04, EWRK3_DATA);
- for (i = 0; i < skb->len; i++) {
- outb(*p++, EWRK3_DATA);
- }
+ outb((char) (skb->len & 0xff), EWRK3_DATA);
+ outb((char) ((skb->len >> 8) & 0xff), EWRK3_DATA);
+ outb((char) 0x04, EWRK3_DATA);
+ for (i = 0; i < skb->len; i++) {
+ outb(*p++, EWRK3_DATA);
+ }
+ outb(page, EWRK3_TQ); /* Start sending pkt */
+ } else {
+ writeb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), (char *) buf); /* ctrl byte */
+ buf += 1;
+ writeb((char) (skb->len & 0xff), (char *) buf); /* length (16 bit xfer) */
+ buf += 1;
+ if (lp->txc) {
+ writeb((char) (((skb->len >> 8) & 0xff) | XCT), (char *) buf);
+ buf += 1;
+ writeb(0x04, (char *) buf); /* index byte */
+ buf += 1;
+ writeb(0x00, (char *) (buf + skb->len)); /* Write the XCT flag */
+ isa_memcpy_toio(buf, skb->data, PRELOAD); /* Write PRELOAD bytes */
outb(page, EWRK3_TQ); /* Start sending pkt */
+ isa_memcpy_toio(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD);
+ writeb(0xff, (char *) (buf + skb->len)); /* Write the XCT flag */
} else {
- writeb((char) (TCR_QMODE | TCR_PAD | TCR_IFC), (char *) buf); /* ctrl byte */
+ writeb((char) ((skb->len >> 8) & 0xff), (char *) buf);
buf += 1;
- writeb((char) (skb->len & 0xff), (char *) buf); /* length (16 bit xfer) */
+ writeb(0x04, (char *) buf); /* index byte */
buf += 1;
- if (lp->txc) {
- writeb((char) (((skb->len >> 8) & 0xff) | XCT), (char *) buf);
- buf += 1;
- writeb(0x04, (char *) buf); /* index byte */
- buf += 1;
- writeb(0x00, (char *) (buf + skb->len)); /* Write the XCT flag */
- isa_memcpy_toio(buf, skb->data, PRELOAD); /* Write PRELOAD bytes */
- outb(page, EWRK3_TQ); /* Start sending pkt */
- isa_memcpy_toio(buf + PRELOAD, skb->data + PRELOAD, skb->len - PRELOAD);
- writeb(0xff, (char *) (buf + skb->len)); /* Write the XCT flag */
- } else {
- writeb((char) ((skb->len >> 8) & 0xff), (char *) buf);
- buf += 1;
- writeb(0x04, (char *) buf); /* index byte */
- buf += 1;
- isa_memcpy_toio(buf, skb->data, skb->len); /* Write data bytes */
- outb(page, EWRK3_TQ); /* Start sending pkt */
- }
+ isa_memcpy_toio(buf, skb->data, skb->len); /* Write data bytes */
+ outb(page, EWRK3_TQ); /* Start sending pkt */
}
-
- dev->trans_start = jiffies;
- dev_kfree_skb(skb);
-
- } else { /* return unused page to the free memory queue */
- outb(page, EWRK3_FMQ);
}
- lp->lock = 0; /* unlock the page register */
- } else {
- printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
- (u_char) page);
+
+ dev->trans_start = jiffies;
+ dev_kfree_skb(skb);
+ } else { /* return unused page to the free memory queue */
+ outb(page, EWRK3_FMQ);
}
+ lp->lock = 0; /* unlock the page register */
} else {
- printk("ewrk3_queue_pkt(): No free resources...\n");
- printk("ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));
+ printk("ewrk3_queue_pkt(): Invalid free memory page (%d).\n",
+ (u_char) page);
}
+ } else {
+ printk(KERN_WARNING "%s: ewrk3_queue_pkt(): No free resources...\n", dev->name);
+ printk(KERN_WARNING "%s: ewrk3_queue_pkt(): CSR: %02x ICR: %02x FMQC: %02x\n", dev->name, inb(EWRK3_CSR), inb(EWRK3_ICR), inb(EWRK3_FMQC));
+ }
- /* Check for free resources: clear 'tbusy' if there are some */
- if (inb(EWRK3_FMQC) > 0) {
- dev->tbusy = 0;
- }
- ENABLE_IRQs;
+ /* Check for free resources: clear 'tbusy' if there are some */
+ if (inb(EWRK3_FMQC) > 0) {
+ netif_wake_queue(dev);
}
+ ENABLE_IRQs;
return status;
}
u_long iobase;
u_char icr, cr, csr;
- if (dev == NULL) {
- printk("ewrk3_interrupt(): irq %d for unknown device.\n", irq);
- } else {
- lp = (struct ewrk3_private *) dev->priv;
- iobase = dev->base_addr;
-
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
-
- dev->interrupt = MASK_INTERRUPTS;
+ lp = (struct ewrk3_private *) dev->priv;
+ iobase = dev->base_addr;
- /* get the interrupt information */
- csr = inb(EWRK3_CSR);
-
- /*
- ** Mask the EWRK3 board interrupts and turn on the LED
- */
- DISABLE_IRQs;
-
- cr = inb(EWRK3_CR);
- cr |= CR_LED;
- outb(cr, EWRK3_CR);
+ /* get the interrupt information */
+ csr = inb(EWRK3_CSR);
- if (csr & CSR_RNE) /* Rx interrupt (packet[s] arrived) */
- ewrk3_rx(dev);
+ /*
+ ** Mask the EWRK3 board interrupts and turn on the LED
+ */
+ DISABLE_IRQs;
- if (csr & CSR_TNE) /* Tx interrupt (packet sent) */
- ewrk3_tx(dev);
+ cr = inb(EWRK3_CR);
+ cr |= CR_LED;
+ outb(cr, EWRK3_CR);
- /*
- ** Now deal with the TX/RX disable flags. These are set when there
- ** are no more resources. If resources free up then enable these
- ** interrupts, otherwise mask them - failure to do this will result
- ** in the system hanging in an interrupt loop.
- */
- if (inb(EWRK3_FMQC)) { /* any resources available? */
- lp->irq_mask |= ICR_TXDM | ICR_RXDM; /* enable the interrupt source */
- csr &= ~(CSR_TXD | CSR_RXD); /* ensure restart of a stalled TX or RX */
- outb(csr, EWRK3_CSR);
- dev->tbusy = 0; /* clear TX busy flag */
- mark_bh(NET_BH);
- } else {
- lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM); /* disable the interrupt source */
- }
+ if (csr & CSR_RNE) /* Rx interrupt (packet[s] arrived) */
+ ewrk3_rx(dev);
- /* Unmask the EWRK3 board interrupts and turn off the LED */
- cr &= ~CR_LED;
- outb(cr, EWRK3_CR);
+ if (csr & CSR_TNE) /* Tx interrupt (packet sent) */
+ ewrk3_tx(dev);
- dev->interrupt = UNMASK_INTERRUPTS;
- ENABLE_IRQs;
+ /*
+ ** Now deal with the TX/RX disable flags. These are set when there
+ ** are no more resources. If resources free up then enable these
+ ** interrupts, otherwise mask them - failure to do this will result
+ ** in the system hanging in an interrupt loop.
+ */
+ if (inb(EWRK3_FMQC)) { /* any resources available? */
+ lp->irq_mask |= ICR_TXDM | ICR_RXDM; /* enable the interrupt source */
+ csr &= ~(CSR_TXD | CSR_RXD); /* ensure restart of a stalled TX or RX */
+ outb(csr, EWRK3_CSR);
+ netif_wake_queue(dev);
+ } else {
+ lp->irq_mask &= ~(ICR_TXDM | ICR_RXDM); /* disable the interrupt source */
}
- return;
+ /* Unmask the EWRK3 board interrupts and turn off the LED */
+ cr &= ~CR_LED;
+ outb(cr, EWRK3_CR);
+ ENABLE_IRQs;
}
static int ewrk3_rx(struct net_device *dev)
u_long iobase = dev->base_addr;
u_char icr, csr;
- dev->start = 0;
- dev->tbusy = 1;
-
+ netif_stop_queue(dev);
+
if (ewrk3_debug > 1) {
printk("%s: Shutting down ethercard, status was %2.2x.\n",
dev->name, inb(EWRK3_CSR));
** are not available then insert a new device structure at the end of
** the current list.
*/
-static struct net_device * __init
-alloc_device(struct net_device *dev, u_long iobase)
+static struct net_device * __init alloc_device(struct net_device *dev, u_long iobase)
{
struct net_device *adev = NULL;
int fixed = 0, new_dev = 0;
/* An IP frame was transmitted to a Bad AL_PA. Free up
* the skb used.
*/
- dev_kfree_skb((struct sk_buff *)(bus_to_virt(transaction_id)));
+ dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id)));
+ netif_wake_queue(fi->dev);
}
} /* End of IP frame timing out. */
} /* End of frame timing out. */
* Free the skb that was used for this IP frame.
*/
if ((status == 0) && (seq_count > 1)) {
- dev_kfree_skb((struct sk_buff *)(bus_to_virt(transaction_id)));
+ dev_kfree_skb_irq((struct sk_buff *)(bus_to_virt(transaction_id)));
+ netif_wake_queue(fi->dev);
}
}
}
static int iph5526_open(struct net_device *dev)
{
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
}
static int iph5526_close(struct net_device *dev)
{
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue(dev);
MOD_DEC_USE_COUNT;
return 0;
}
+static void iph5526_timeout(struct net_device *dev)
+{
+ struct fc_info *fi = (struct fc_info*)dev->priv;
+ printk(KERN_WARNING "%s: timed out on send.\n", dev->name);
+ fi->fc_stats.rx_dropped++;
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
+
static int iph5526_send_packet(struct sk_buff *skb, struct net_device *dev)
{
-struct fc_info *fi = (struct fc_info*)dev->priv;
-int status = 0;
-short type = 0;
-u_long flags;
+ struct fc_info *fi = (struct fc_info*)dev->priv;
+ int status = 0;
+ short type = 0;
+ u_long flags;
+ struct fcllc *fcllc;
+
ENTER("iph5526_send_packet");
- if (dev->tbusy) {
- printk(KERN_WARNING "%s: DEVICE BUSY\n", dev->name);
- dev->tbusy = 0;
- fi->fc_stats.rx_dropped++;
- dev->trans_start = jiffies;
- return 0;
- }
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk(KERN_WARNING "%s: Transmitter access conflict.\n",
-dev->name);
- fi->fc_stats.rx_dropped++;
- return 1;
- }
- else {
- struct fcllc *fcllc;
- /* Strip off the pseudo header.
- */
- skb->data = skb->data + 2*FC_ALEN;
- skb->len = skb->len - 2*FC_ALEN;
- fcllc = (struct fcllc *)skb->data;
- type = ntohs(fcllc->ethertype);
-
- spin_lock_irqsave(&fi->fc_lock, flags);
- switch(type) {
- case ETH_P_IP:
- status = tx_ip_packet(skb, skb->len, fi);
- break;
- case ETH_P_ARP:
- status = tx_arp_packet(skb->data, skb->len, fi);
- break;
- default:
- T_MSG("WARNING!!! Received Unknown Packet Type... Discarding...");
- fi->fc_stats.rx_dropped++;
- break;
- }
- spin_unlock_irqrestore(&fi->fc_lock, flags);
+
+ netif_stop_queue(dev);
+ /* Strip off the pseudo header.
+ */
+ skb->data = skb->data + 2*FC_ALEN;
+ skb->len = skb->len - 2*FC_ALEN;
+ fcllc = (struct fcllc *)skb->data;
+ type = ntohs(fcllc->ethertype);
+
+ spin_lock_irqsave(&fi->fc_lock, flags);
+ switch(type) {
+ case ETH_P_IP:
+ status = tx_ip_packet(skb, skb->len, fi);
+ break;
+ case ETH_P_ARP:
+ status = tx_arp_packet(skb->data, skb->len, fi);
+ break;
+ default:
+ T_MSG("WARNING!!! Received Unknown Packet Type... Discarding...");
+ fi->fc_stats.rx_dropped++;
+ break;
}
+ spin_unlock_irqrestore(&fi->fc_lock, flags);
if (status) {
fi->fc_stats.tx_bytes += skb->len;
else
fi->fc_stats.rx_dropped++;
dev->trans_start = jiffies;
- dev->tbusy = 0;
/* We free up the IP buffers in the OCI_interrupt handler.
* status == 0 implies that the frame was not transmitted. So the
* skb is freed here.
*/
if ((type == ETH_P_ARP) || (status == 0))
dev_kfree_skb(skb);
- mark_bh(NET_BH);
+ else
+ netif_wake_queue(dev);
LEAVE("iph5526_send_packet");
return 0;
}
#include <linux/skbuff.h>
#include <linux/delay.h>
-static int fmv18x_probe_list[] __initdata =
-{0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0};
+static int fmv18x_probe_list[] __initdata = {
+ 0x220, 0x240, 0x260, 0x280, 0x2a0, 0x2c0, 0x300, 0x340, 0
+};
/* use 0 for production, 1 for verification, >2 for debug */
#ifndef NET_DEBUG
If dev->base_addr == 2, allocate space for the device and return success
(detachable devices only).
*/
-#ifdef HAVE_DEVLIST
-/* Support for an alternate probe manager, which will eliminate the
- boilerplate below. */
-struct netdev_entry fmv18x_drv =
-{"fmv18x", fmv18x_probe1, FMV18X_IO_EXTENT, fmv18x_probe_list};
-#else
-int __init
-fmv18x_probe(struct net_device *dev)
+
+int __init fmv18x_probe(struct net_device *dev)
{
int i;
int base_addr = dev ? dev->base_addr : 0;
return ENODEV;
}
-#endif
/* The Fujitsu datasheet suggests that the NIC be probed for by checking its
"signature", the default bit pattern after a reset. This *doesn't* work --
static struct net_device_stats *net_get_stats(struct net_device *dev)
{
struct net_local *lp = (struct net_local *)dev->priv;
-
- cli();
- /* ToDo: Update the statistics from the device registers. */
- sti();
-
return &lp->stats;
}
dev = bpq_get_ax25_dev(dev);
- if (dev == NULL || dev->start == 0) {
+ if (dev == NULL || test_bit(LINK_STATE_START, &dev->state) == 0) {
kfree_skb(skb);
return 0;
}
* Just to be *really* sure not to send anything if the interface
* is down, the ethernet device may have gone.
*/
- if (!dev->start) {
+ if (!test_bit(LINK_STATE_START, &dev->state)) {
bpq_check_devices(dev);
kfree_skb(skb);
return -ENODEV;
{
if (bpq_check_devices(dev))
return -ENODEV; /* oops, it's gone */
-
- dev->tbusy = 0;
- dev->start = 1;
-
MOD_INC_USE_COUNT;
-
+ netif_start_queue(dev);
return 0;
}
static int bpq_close(struct net_device *dev)
{
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
MOD_DEC_USE_COUNT;
-
return 0;
}
}
/* Initialize local variables */
- dev->tbusy = 0;
priv->rx_ptr = 0;
priv->rx_over = 0;
priv->rx_head = priv->rx_tail = priv->rx_count = 0;
/* Configure PI2 DMA */
if (info->type <= TYPE_PI2) outb_p(1, io + PI_DREQ_MASK);
- dev->start = 1;
+ netif_start_queue(dev);
info->open++;
MOD_INC_USE_COUNT;
int io = dev->base_addr;
int cmd = priv->cmd;
- dev->start = 0;
+ netif_stop_queue(dev);
info->open--;
- MOD_DEC_USE_COUNT;
if (info->type == TYPE_TWIN)
/* Drop DTR */
if (info->type <= TYPE_PI2) outb_p(0, io + PI_DREQ_MASK);
free_irq(dev->irq, info);
}
+ MOD_DEC_USE_COUNT;
return 0;
}
switch (cmd) {
case SIOCGSCCPARAM:
- rc = verify_area(VERIFY_WRITE, ifr->ifr_data, sizeof(struct scc_param));
- if (rc) return rc;
- copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param));
+ if(copy_to_user(ifr->ifr_data, &priv->param, sizeof(struct scc_param)))
+ return -EFAULT;
return 0;
case SIOCSSCCPARAM:
- if (!suser()) return -EPERM;
- rc = verify_area(VERIFY_READ, ifr->ifr_data, sizeof(struct scc_param));
- if (rc) return rc;
- if (dev->start) return -EAGAIN;
- copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param));
+ if (!capable(CAP_NET_ADMIN))
+ return -EPERM;
+ if (test_bit(LINK_STATE_START, &dev->state))
+ return -EAGAIN;
+ if(copy_from_user(&priv->param, ifr->ifr_data, sizeof(struct scc_param)))
+ return -EFAULT;
dev->dma = priv->param.dma;
return 0;
default:
int i;
/* Block a timer-based transmit from overlapping */
- if (test_and_set_bit(0, (void *) &priv->tx_sem) != 0) {
- atomic_inc((void *) &priv->stats.tx_dropped);
- dev_kfree_skb(skb);
- return 0;
- }
-
- /* Return with an error if we cannot accept more data */
- if (dev->tbusy) {
- priv->tx_sem = 0;
- return -1;
- }
-
+ netif_stop_queue(dev);
+
/* Transfer data to DMA buffer */
i = priv->tx_head;
memcpy(priv->tx_buf[i], skb->data+1, skb->len-1);
/* Set the busy flag if we just filled up the last buffer */
priv->tx_head = (i + 1) % NUM_TX_BUF;
priv->tx_count++;
- if (priv->tx_count == NUM_TX_BUF) dev->tbusy = 1;
+ if (priv->tx_count != NUM_TX_BUF)
+ netif_wake_queue(dev);
/* Set new TX state */
if (priv->tx_state == TX_IDLE) {
/* Remove frame from FIFO */
priv->tx_tail = (i + 1) % NUM_TX_BUF;
priv->tx_count--;
- dev->tbusy = 0;
/* Check if another frame is available and we are allowed to transmit */
if (priv->tx_count && (jiffies - priv->tx_start) < priv->param.txtime) {
if (dev->dma) {
priv->stats.tx_packets++;
}
/* Inform upper layers */
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
/* DCD transition */
static inline void scc_lock_dev(struct scc_channel *scc)
{
- scc->dev->tbusy = 1;
+ netif_stop_queue(scc->dev);
}
static inline void scc_unlock_dev(struct scc_channel *scc)
{
- scc->dev->tbusy = 0;
+ netif_wake_queue(scc->dev);
}
static inline void scc_discard_buffers(struct scc_channel *scc)
init_channel(scc);
- dev->tbusy = 0;
- dev->start = 1;
-
+ netif_start_queue(dev);
return 0;
}
scc_discard_buffers(scc);
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
return 0;
}
unsigned long flags;
char kisscmd;
- if (scc == NULL || scc->magic != SCC_MAGIC || dev->tbusy)
+ if (scc == NULL || scc->magic != SCC_MAGIC)
{
dev_kfree_skb(skb);
return 0;
return 0;
}
- save_flags(flags);
+ save_flags(flags);
cli();
if (skb_queue_len(&scc->tx_queue) > scc->dev->tx_queue_len)
for (i = 0; i < NR_PORTS; i++) {
struct net_device *dev = &yam_ports[i].dev;
- if (dev->start)
+ if (test_bit(LINK_STATE_START, &dev->state))
yam_arbitrate(dev);
}
yam_timer.expires = jiffies + HZ / 100;
yp = &yam_ports[i];
dev = &yp->dev;
- if (!dev->start)
+ if (!test_bit(LINK_STATE_START, &dev->state))
continue;
while ((iir = IIR_MASK & inb(IIR(dev->base_addr))) != IIR_NOPEND) {
if (yam_ports[i].iobase == 0 || yam_ports[i].irq == 0)
continue;
len += sprintf(buffer + len, "Device %s\n", yam_ports[i].name);
- len += sprintf(buffer + len, " Up %d\n", yam_ports[i].dev.start);
+ len += sprintf(buffer + len, " Up %d\n", test_bit(LINK_STATE_START, &yam_ports[i].dev.state));
len += sprintf(buffer + len, " Speed %u\n", yam_ports[i].bitrate);
len += sprintf(buffer + len, " IoBase 0x%x\n", yam_ports[i].iobase);
len += sprintf(buffer + len, " BaudRate %u\n", yam_ports[i].baudrate);
request_region(dev->base_addr, YAM_EXTENT, dev->name);
yam_set_uart(dev);
- dev->start = 1;
+
+ netif_start_queue(dev);
+
yp->slotcnt = yp->slot / 10;
/* Reset overruns for all ports - FPGA programming makes overruns */
/* Remove IRQ handler if last */
free_irq(dev->irq, NULL);
release_region(dev->base_addr, YAM_EXTENT);
- dev->start = 0;
- dev->tbusy = 1;
+ netif_stop_queue(dev);
while ((skb = skb_dequeue(&yp->send_queue)))
dev_kfree_skb(skb);
return -EINVAL; /* unused */
case SIOCYAMSMCS:
- if (dev->start)
+ if (test_bit(LINK_STATE_START, &dev->state))
return -EINVAL; /* Cannot change this parameter when up */
ym = kmalloc(sizeof(struct yamdrv_ioctl_mcs), GFP_ATOMIC);
ym->bitrate = 9600;
if (copy_from_user(&yi, ifr->ifr_data, sizeof(struct yamdrv_ioctl_cfg)))
return -EFAULT;
- if ((yi.cfg.mask & YAM_IOBASE) && dev->start)
+ if ((yi.cfg.mask & YAM_IOBASE) && test_bit(LINK_STATE_START, &dev->state))
return -EINVAL; /* Cannot change this parameter when up */
- if ((yi.cfg.mask & YAM_IRQ) && dev->start)
+ if ((yi.cfg.mask & YAM_IRQ) && test_bit(LINK_STATE_START, &dev->state))
return -EINVAL; /* Cannot change this parameter when up */
- if ((yi.cfg.mask & YAM_BITRATE) && dev->start)
+ if ((yi.cfg.mask & YAM_BITRATE) && test_bit(LINK_STATE_START, &dev->state))
return -EINVAL; /* Cannot change this parameter when up */
- if ((yi.cfg.mask & YAM_BAUDRATE) && dev->start)
+ if ((yi.cfg.mask & YAM_BAUDRATE) && test_bit(LINK_STATE_START, &dev->state))
return -EINVAL; /* Cannot change this parameter when up */
if (yi.cfg.mask & YAM_IOBASE) {
dev->irq = yam_ports[i].irq;
dev->init = yam_probe;
dev->if_port = 0;
- dev->start = 0;
- dev->tbusy = 1;
if (register_netdev(dev)) {
printk(KERN_WARNING "yam: cannot register net device %s\n", dev->name);
struct net_device *dev = &yam_ports[i].dev;
if (!dev->priv)
continue;
- if (dev->start)
+ if (test_bit(LINK_STATE_START, &dev->state))
yam_close(dev);
unregister_netdev(dev);
}
static int ni65_lance_reinit(struct net_device *dev);
static void ni65_init_lance(struct priv *p,unsigned char*,int,int);
static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev);
+static void ni65_timeout(struct net_device *dev);
static int ni65_close(struct net_device *dev);
static int ni65_alloc_buffer(struct net_device *dev);
static void ni65_free_buffer(struct priv *p);
if(ni65_lance_reinit(dev))
{
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
+ netif_start_queue(dev);
MOD_INC_USE_COUNT;
return 0;
}
else
{
free_irq(dev->irq,dev);
- dev->start = 0;
return -EAGAIN;
}
}
{
struct priv *p = (struct priv *) dev->priv;
+ netif_stop_queue(dev);
+
outw(inw(PORT+L_RESET),PORT+L_RESET); /* that's the hard way */
#ifdef XMT_VIA_SKB
}
#endif
free_irq(dev->irq,dev);
- dev->tbusy = 1;
- dev->start = 0;
MOD_DEC_USE_COUNT;
return 0;
}
dev->open = ni65_open;
dev->stop = ni65_close;
dev->hard_start_xmit = ni65_send_packet;
+ dev->tx_timeout = ni65_timeout;
+ dev->watchdog_timeo = HZ/2;
dev->get_stats = ni65_get_stats;
dev->set_multicast_list = set_multicast_list;
ether_setup(dev);
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 0;
-
return 0; /* everything is OK */
}
}
p->rmdnum = p->tmdlast = 0;
if(!p->lock)
- dev->tbusy = (p->tmdnum || !p->xmit_queued) ? 0 : 1;
+ if (p->tmdnum || !p->xmit_queued)
+ netif_wake_queue(dev);
dev->trans_start = jiffies;
}
else
struct priv *p;
int bcnt = 32;
- if (dev == NULL) {
- printk (KERN_ERR "ni65_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
-
- if(test_and_set_bit(0,(int *) &dev->interrupt)) {
- printk("ni65: oops .. interrupt while proceeding interrupt\n");
- return;
- }
p = (struct priv *) dev->priv;
while(--bcnt) {
else
writedatareg(CSR0_INEA);
- dev->interrupt = 0;
-
return;
}
#ifdef XMT_VIA_SKB
if(p->tmd_skb[p->tmdlast]) {
- dev_kfree_skb(p->tmd_skb[p->tmdlast]);
+ dev_kfree_skb_irq(p->tmd_skb[p->tmdlast]);
p->tmd_skb[p->tmdlast] = NULL;
}
#endif
if(p->tmdlast == p->tmdnum)
p->xmit_queued = 0;
}
- dev->tbusy = 0;
- mark_bh(NET_BH);
+ netif_wake_queue(dev);
}
/*
/*
* kick xmitter ..
*/
-static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
+
+static void ni65_timeout(struct net_device *dev)
{
+ int i;
struct priv *p = (struct priv *) dev->priv;
- if(dev->tbusy)
- {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 50)
- return 1;
+ printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
+ for(i=0;i<TMDNUM;i++)
+ printk("%02x ",p->tmdhead[i].u.s.status);
+ printk("\n");
+ ni65_lance_reinit(dev);
+ dev->trans_start = jiffies;
+ netif_wake_queue(dev);
+}
- printk(KERN_ERR "%s: xmitter timed out, try to restart!\n",dev->name);
- {
- int i;
- for(i=0;i<TMDNUM;i++)
- printk("%02x ",p->tmdhead[i].u.s.status);
- printk("\n");
- }
- ni65_lance_reinit(dev);
- dev->tbusy=0;
- dev->trans_start = jiffies;
- }
+/*
+ * Send a packet
+ */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0) {
- printk(KERN_ERR "%s: Transmitter access conflict.\n", dev->name);
- return 1;
- }
+static int ni65_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+
+ netif_stop_queue(dev);
+
if (test_and_set_bit(0, (void*)&p->lock)) {
printk(KERN_ERR "%s: Queue was locked.\n", dev->name);
return 1;
p->xmit_queued = 1;
p->tmdnum = (p->tmdnum + 1) & (TMDNUM-1);
- dev->tbusy = (p->tmdnum == p->tmdlast) ? 1 : 0;
+ if(p->tmdnum != p->tmdlast)
+ netif_wake_queue(dev);
+
p->lock = 0;
dev->trans_start = jiffies;
{
if(!ni65_lance_reinit(dev))
printk(KERN_ERR "%s: Can't switch card into MC mode!\n",dev->name);
- dev->tbusy = 0;
+ netif_wake_queue(dev);
}
#ifdef MODULE
static void fjn_reset(struct net_device *dev);
static struct net_device_stats *fjn_get_stats(struct net_device *dev);
static void set_rx_mode(struct net_device *dev);
+static void fjn_tx_timeout (struct net_device *dev);
static dev_info_t dev_info = "fmvj18x_cs";
static dev_link_t *dev_list = NULL;
cardtype_t cardtype;
u_short sent;
u_char mc_filter[8];
+ spinlock_t lock;
} local_info_t;
#define MC_FILTERBREAK 64
#define INTR_OFF 0x0d /* LAN controler ignores interrupts */
#define INTR_ON 0x1d /* LAN controler will catch interrupts */
+#define TX_TIMEOUT 10
+
/*======================================================================
This bit of code is used to avoid unregistering network devices
lp = kmalloc(sizeof(*lp), GFP_KERNEL);
if (!lp) return NULL;
memset(lp, 0, sizeof(*lp));
+
+ lp->lock = SPIN_LOCK_UNLOCKED;
link = &lp->link; dev = &lp->dev;
link->priv = dev->priv = link->irq.Instance = lp;
dev->init = &fmvj18x_init;
dev->open = &fjn_open;
dev->stop = &fjn_close;
- dev->tbusy = 0xFF;
+ dev->tx_timeout = fjn_tx_timeout;
+ dev->watchdog_timeo = TX_TIMEOUT;
+ netif_start_queue (dev);
/* Register with Card Services */
link->next = dev_list;
CS_CHECK(RequestConfiguration, link->handle, &link->conf);
dev->irq = link->irq.AssignedIRQ;
dev->base_addr = link->io.BasePort1;
- dev->tbusy = 0;
+ netif_start_queue (dev);
if (register_netdev(dev) != 0) {
printk(KERN_NOTICE "fmvj18x_cs: register_netdev() failed\n");
goto failed;
case CS_EVENT_CARD_REMOVAL:
link->state &= ~DEV_PRESENT;
if (link->state & DEV_CONFIG) {
- dev->tbusy = 0xFF;
- dev->start = 0;
+ netif_stop_queue (dev);
link->release.expires = jiffies + HZ/20;
add_timer(&link->release);
}
case CS_EVENT_RESET_PHYSICAL:
if (link->state & DEV_CONFIG) {
if (link->open) {
- dev->tbusy = 0xFF;
- dev->start = 0;
+ netif_stop_queue (dev);
}
CardServices(ReleaseConfiguration, link->handle);
}
if (link->state & DEV_CONFIG) {
CardServices(RequestConfiguration, link->handle, &link->conf);
if (link->open) {
- dev->tbusy = 0;
- dev->start = 1;
fjn_reset(dev);
+ netif_start_queue (dev);
}
}
break;
"unknown device.\n", irq);
return;
}
- if (dev->interrupt) {
- printk(KERN_NOTICE "%s: re-entering the interrupt handler.\n",
- dev->name);
- return;
- }
- dev->interrupt = 1;
+
+ spin_lock (&lp->lock);
+
ioaddr = dev->base_addr;
/* avoid multiple interrupts */
lp->tx_queue = 0;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_wake_queue (dev);
} else {
lp->tx_started = 0;
- dev->tbusy = 0;
- mark_bh(NET_BH); /* Inform upper layers. */
+ netif_stop_queue (dev);
}
}
DEBUG(4, "%s: exiting interrupt,\n", dev->name);
DEBUG(4, " tx_status %02x, rx_status %02x.\n", tx_stat, rx_stat);
- dev->interrupt = 0;
outb(D_TX_INTR, ioaddr + TX_INTR);
outb(D_RX_INTR, ioaddr + RX_INTR);
- return;
+ spin_unlock (&lp->lock);
+
} /* fjn_interrupt */
/*====================================================================*/
-
-static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
+static void fjn_tx_timeout (struct net_device *dev)
{
- struct local_info_t *lp = (struct local_info_t *)dev->priv;
- ioaddr_t ioaddr = dev->base_addr;
-
- if (dev->tbusy) {
- /* If we get here, some higher level has decided we are broken.
- There should really be a "kick me" function call instead. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 10)
- return 1;
- printk(KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
- dev->name, htons(inw(ioaddr + TX_STATUS)),
- inb(ioaddr + TX_STATUS) & F_TMT_RDY
- ? "IRQ conflict" : "network cable problem");
- printk(KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
- "%04x %04x %04x %04x %04x.\n",
- dev->name, htons(inw(ioaddr + 0)),
- htons(inw(ioaddr + 2)), htons(inw(ioaddr + 4)),
- htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
- htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
- htons(inw(ioaddr +14)));
+ struct local_info_t *lp = (struct local_info_t *) dev->priv;
+ ioaddr_t ioaddr = dev->base_addr;
+ unsigned long flags;
+
+ printk (KERN_NOTICE "%s: transmit timed out with status %04x, %s?\n",
+ dev->name, htons (inw (ioaddr + TX_STATUS)),
+ inb (ioaddr + TX_STATUS) & F_TMT_RDY
+ ? "IRQ conflict" : "network cable problem");
+ printk (KERN_NOTICE "%s: timeout registers: %04x %04x %04x "
+ "%04x %04x %04x %04x %04x.\n",
+ dev->name, htons (inw (ioaddr + 0)),
+ htons (inw (ioaddr + 2)), htons (inw (ioaddr + 4)),
+ htons (inw (ioaddr + 6)), htons (inw (ioaddr + 8)),
+ htons (inw (ioaddr + 10)), htons (inw (ioaddr + 12)),
+ htons (inw (ioaddr + 14)));
lp->stats.tx_errors++;
+
/* ToDo: We should try to restart the adaptor... */
- cli();
+ spin_lock_irqsave (&lp->lock, flags);
- fjn_reset(dev);
+ fjn_reset (dev);
lp->tx_started = 0;
lp->tx_queue = 0;
lp->tx_queue_len = 0;
lp->sent = 0;
lp->open_time = jiffies;
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 1;
-
- sti();
- }
+ netif_start_queue (dev);
+
+ spin_unlock_irqrestore (&lp->lock, flags);
+}
+
+
+static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+ struct local_info_t *lp = (struct local_info_t *)dev->priv;
+ ioaddr_t ioaddr = dev->base_addr;
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (test_and_set_bit(0, (void*)&dev->tbusy) != 0)
- printk(KERN_NOTICE "%s: Transmitter access conflict.\n", dev->name);
- else {
+ netif_stop_queue (dev);
+ if (1) {
short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
unsigned char *buf = skb->data;
lp->tx_queue_len = 0;
dev->trans_start = jiffies;
lp->tx_started = 1;
- dev->tbusy = 0;
+ netif_start_queue (dev);
} else {
if( sram_config == 0 ) {
if (lp->tx_queue_len < (4096 - (ETH_FRAME_LEN +2)) )
/* Yes, there is room for one more packet. */
- dev->tbusy = 0;
+ netif_start_queue (dev);
} else {
if (lp->tx_queue_len < (8192 - (ETH_FRAME_LEN +2)) &&
lp->tx_queue < 127 )
/* Yes, there is room for one more packet. */
- dev->tbusy = 0;
+ netif_start_queue (dev);
}
}
lp->tx_queue = 0;
lp->tx_queue_len = 0;
lp->open_time = jiffies;
- dev->interrupt = 0;
- dev->tbusy = 0;
- dev->start = 1;
+ netif_start_queue (dev);
MOD_INC_USE_COUNT;
DEBUG(4, "fjn_close('%s').\n", dev->name);
lp->open_time = 0;
- dev->tbusy = 1;
- dev->start = 0;
+ netif_stop_queue (dev);
/* Set configuration register 0 to disable Tx and Rx. */
if( sram_config == 0 )
outb(INTR_OFF, ioaddr + LAN_CTRL);
link->open--;
- dev->start = 0;
if (link->state & DEV_STALE_CONFIG) {
link->release.expires = jiffies + HZ/20;
link->state |= DEV_RELEASE_PENDING;
#endif
#include <linux/version.h>
-#ifdef MODULE
-#ifdef MODVERSIONS
-#include <linux/modversions.h>
-#endif
#include <linux/module.h>
-#else
-#define MOD_INC_USE_COUNT
-#define MOD_DEC_USE_COUNT
-#endif
-
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#define RUN_AT(x) (jiffies + (x))
-#define NETSTATS_VER2
-#define PCI_SUPPORT_VER3
-
#define tulip_debug debug
#ifdef TULIP_DEBUG
static int tulip_debug = TULIP_DEBUG;
outl(0, ioaddr + CSR1);
dev->trans_start = jiffies;
+ netif_wake_queue (dev);
tp->stats.tx_errors++;
- return;
}
/* Initialize the Rx and Tx rings, along with various 'dev' bits. */
-/* rtl8139.c: A RealTek RTL8129/8139 Fast Ethernet driver for Linux. */
+/* rtl8129.c: A RealTek RTL8129 Fast Ethernet driver for Linux. */
/*
Written 1997-1999 by Donald Becker.
of the GNU Public License, incorporated herein by reference.
All other rights reserved.
- This driver is for boards based on the RTL8129 and RTL8139 PCI ethernet
- chips.
+ This driver is for boards based on the RTL8129 PCI ethernet chip.
The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O
Center of Excellence in Space Data and Information Sciences
*/
static const char *version =
-"rtl8139.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
+"rtl8129.c:v1.07 5/6/99 Donald Becker http://cesdis.gsfc.nasa.gov/linux/drivers/rtl8139.html\n";
/* A few user-configurable values. */
/* Maximum events (Rx packets, etc.) to handle at each interrupt. */
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
+#include <linux/init.h>
#include <linux/pci.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
unsigned int mediasense:1; /* Media sensing in progress. */
};
-#ifdef MODULE
-#if LINUX_VERSION_CODE > 0x20115
MODULE_AUTHOR("Donald Becker <becker@cesdis.gsfc.nasa.gov>");
-MODULE_DESCRIPTION("RealTek RTL8129/8139 Fast Ethernet driver");
+MODULE_DESCRIPTION("RealTek RTL8129 Fast Ethernet driver");
MODULE_PARM(options, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(full_duplex, "1-" __MODULE_STRING(MAX_UNITS) "i");
MODULE_PARM(multicast_filter_limit, "i");
MODULE_PARM(max_interrupt_work, "i");
MODULE_PARM(debug, "i");
-#endif
-#endif
static int rtl8129_open(struct net_device *dev);
static int read_eeprom(long ioaddr, int location);
well when dynamically adding drivers. So instead we detect just the
Rtl81*9 cards in slot order. */
-int rtl8139_probe(void)
+static int __init rtl8129_probe(void)
{
int cards_found = 0;
int pci_index = 0;
if (inw(ioaddr + IntrStatus) & (TxOK | RxOK)) {
int status = inw(ioaddr + IntrStatus);
if (status & (TxOK | RxOK)) { /* Double check */
- printk(KERN_ERR "%s: RTL8139 Interrupt line blocked, status %x.\n",
+ printk(KERN_ERR "%s: RTL8129 Interrupt line blocked, status %x.\n",
dev->name, status);
rtl8129_interrupt(dev->irq, dev, 0);
}
return;
}
\f
-#ifdef MODULE
-int init_module(void)
-{
- return rtl8139_probe();
-}
-void
-cleanup_module(void)
+static void __exit rtl8129_cleanup (void)
{
struct net_device *next_dev;
}
}
-#endif /* MODULE */
-\f
+module_init(rtl8129_probe);
+module_exit(rtl8129_cleanup);
+
/*
* Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
- * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8139.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
+ * SMP-compile-command: "gcc -D__SMP__ -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -c rtl8129.c `[ -f /usr/include/linux/modversions.h ] && echo -DMODVERSIONS`"
* c-indent-level: 4
* c-basic-offset: 4
* tab-width: 4
/* sis900.c: A SiS 900/7016 PCI Fast Ethernet driver for Linux.
Copyright 1999 Silicon Integrated System Corporation
- Revision: 1.06.03 Dec 23 1999
+ Revision: 1.06.04 Feb 11 2000
Modified from the driver which is originally written by Donald Becker.
int LinkOn;
};
-MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>");
+MODULE_AUTHOR("Jim Huang <cmhuang@sis.com.tw>, Ollie Lho <ollie@sis.com.tw>");
MODULE_DESCRIPTION("SiS 900 PCI Fast Ethernet driver");
MODULE_PARM(multicast_filter_limit, "i");
MODULE_PARM(max_interrupt_work, "i");
net_dev->irq = irq;
sis_priv->pci_dev = pci_dev;
sis_priv->mac = mac;
- sis_priv->lock = SPIN_LOCK_UNLOCKED;
+ spin_lock_init(&sis_priv->lock);
/* probe for mii transciver */
if (sis900_mii_probe(net_dev) == 0) {
next_tick = 5*HZ;
/* change what cur_phy means */
if (mii_phy->phy_addr != sis_priv->cur_phy) {
- printk(KERN_INFO "%s: Changing transceiver to %s\n", net_dev->name,
- mii_phy->chip_info->name);
+ printk(KERN_INFO "%s: Changing transceiver to %s\n",
+ net_dev->name, mii_phy->chip_info->name);
status = mdio_read(net_dev, sis_priv->cur_phy, MII_CONTROL);
mdio_write(net_dev, sis_priv->cur_phy,
MII_CONTROL, status | MII_CNTL_ISOLATE);
/* Disable interrupts by clearing the interrupt mask. */
outl(0x0000, ioaddr + imr);
- /* discard unsent packets, should this code section be protected by
- cli(), sti() ?? */
+ /* use spinlock to prevent interrupt handler accessing buffer ring */
spin_lock_irqsave(&sis_priv->lock, flags);
+
+ /* discard unsent packets */
sis_priv->dirty_tx = sis_priv->cur_tx = 0;
for (i = 0; i < NUM_TX_DESC; i++) {
if (sis_priv->tx_skbuff[i] != NULL) {
sis_priv->stats.tx_dropped++;
}
}
+ sis_priv->tx_full = 0;
+ netif_wake_queue(net_dev);
+
spin_unlock_irqrestore(&sis_priv->lock, flags);
net_dev->trans_start = jiffies;
- sis_priv->tx_full = 0;
- netif_start_queue(net_dev);
/* FIXME: Should we restart the transmission thread here ?? */
+ outl(TxENA, ioaddr + cr);
/* Enable all known interrupts by setting the interrupt mask. */
outl((RxSOVR|RxORN|RxERR|RxOK|TxURN|TxERR|TxIDLE), ioaddr + imr);
struct sis900_private *sis_priv = (struct sis900_private *)net_dev->priv;
long ioaddr = net_dev->base_addr;
unsigned int entry;
+ unsigned long flags;
+
+ spin_lock_irqsave(&sis_priv->lock, flags);
/* Calculate the next Tx descriptor entry. */
entry = sis_priv->cur_tx % NUM_TX_DESC;
outl(TxENA, ioaddr + cr);
if (++sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC) {
- /* Typical path, clear tbusy to indicate more
- transmission is possible */
+ /* Typical path, tell upper layer that more transmission is possible */
netif_start_queue(net_dev);
} else {
- /* no more transmit descriptor avaiable, tbusy remain set */
+ /* buffer full, tell upper layer no more transmission */
sis_priv->tx_full = 1;
+ netif_stop_queue(net_dev);
}
+ spin_unlock_irqrestore(&sis_priv->lock, flags);
+
net_dev->trans_start = jiffies;
if (sis900_debug > 3)
if (sis900_debug > 3)
printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d "
"status:0x%8.8x\n",
- sis_priv->cur_rx, sis_priv->dirty_rx,rx_status);
+ sis_priv->cur_rx, sis_priv->dirty_rx, rx_status);
while (rx_status & OWN) {
unsigned int rx_size;
if (sis_priv->tx_full && test_bit(LINK_STATE_XOFF, &net_dev->flags) &&
sis_priv->cur_tx - sis_priv->dirty_tx < NUM_TX_DESC - 4) {
- /* The ring is no longer full, clear tbusy, tx_full and
- schedule more transmission by marking NET_BH */
+ /* The ring is no longer full, clear tx_full and schedule more transmission
+ by netif_wake_queue(net_dev) */
sis_priv->tx_full = 0;
netif_wake_queue (net_dev);
}
int SK_init(struct net_device *dev);
static int SK_probe(struct net_device *dev, short ioaddr);
+static void SK_timeout(struct net_device *dev);
static int SK_open(struct net_device *dev);
static int SK_send_packet(struct sk_buff *skb, struct net_device *dev);
static void SK_interrupt(int irq, void *dev_id, struct pt_regs * regs);
/* Assign our Device Driver functions */
- dev->open = &SK_open;
- dev->stop = &SK_close;
- dev->hard_start_xmit = &SK_send_packet;
- dev->get_stats = &SK_get_stats;
- dev->set_multicast_list = &set_multicast_list;
+ dev->open = SK_open;
+ dev->stop = SK_close;
+ dev->hard_start_xmit = SK_send_packet;
+ dev->get_stats = SK_get_stats;
+ dev->set_multicast_list = set_multicast_list;
+ dev->tx_timeout = SK_timeout;
+ dev->watchdog_timeo = HZ/7;
/* Set the generic fields of the device structure */
* YY/MM/DD uid Description
-*/
-static int SK_send_packet(struct sk_buff *skb, struct net_device *dev)
+static int SK_timeout(struct net_device *dev)
{
- struct priv *p = (struct priv *) dev->priv;
- struct tmd *tmdp;
-
- if (test_bit(LINK_STATE_XOFF, &dev->flags))
- {
- /* if Transmitter more than 150ms busy -> time_out */
-
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 15)
- {
- return 1; /* We have to try transmit later */
- }
-
- printk("%s: xmitter timed out, try to restart!\n", dev->name);
-
+ printk(KERN_WARNING "%s: xmitter timed out, try to restart!\n", dev->name);
SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */
-
netif_start_queue(dev); /* Clear Transmitter flag */
-
dev->trans_start = jiffies; /* Mark Start of transmission */
+}
- }
+static int SK_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+ struct priv *p = (struct priv *) dev->priv;
+ struct tmd *tmdp;
PRINTK2(("## %s: SK_send_packet() called, CSR0 %#04x.\n",
SK_NAME, SK_read_reg(CSR0)));
#define IRQ(irq, dev_id, pt_regs) (irq, pt_regs)
#endif
-/* This my implementation of shared IRQs, now only used for 1.2.13. */
-#ifdef HAVE_SHARED_IRQ
-#define USE_SHARED_IRQ
-#include <linux/shared_irq.h>
-#endif
-
/* The total size is unusually large: The 21040 aligns each of its 16
longword-wide registers on a quadword boundary. */
#define TULIP_TOTAL_SIZE 0x80
/* This is an extension of the 'struct net_device' we create for each network
interface to keep the rest of X.25 channel-specific data. */
typedef struct x25_channel {
+ /* This member must be first. */
+ struct net_device *slave; /* WAN slave */
+
char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */
char *local_addr; /* local media address, ASCIIZ -
static struct net_device *get_dev_by_lcn (wan_device_t *wandev, s16 lcn)
{
struct net_device *dev = wandev->dev;
+ x25_channel_t *chan;
- for (; dev; dev = dev->slave)
- if (((x25_channel_t*)dev->priv)->lcn == lcn)
+ while (dev) {
+ if (chan->lcn == lcn)
break;
-
+ dev = chan->slave;
+ }
return dev;
}
static struct net_device *get_dev_by_dte_addr (wan_device_t *wandev, char *dte)
{
struct net_device *dev = wandev->dev;
+ x25_channel_t *chan;
- for (; dev; dev = dev->slave)
- if (!strcmp(((x25_channel_t*)dev->priv)->addr, dte))
+ while (dev) {
+ if (!strcmp(chan->addr, dte))
break;
-
+ dev = chan->slave;
+ }
return dev;
}
printk(KERN_INFO "name: addr: txoff: protocol:\n");
printk(KERN_INFO "---------------------------------------\n");
- for (; dev; dev = dev->slave) {
+ while(dev) {
x25_channel_t *chan = dev->priv;
printk(KERN_INFO "%-5.5s %-15.15s %d ETH_P_%s\n",
chan->name, chan->addr, test_bit(LINK_STATE_XOFF, &dev->state),
chan->protocol == ETH_P_IP ? "IP" : "X25");
+ dev = chan->slave;
}
}
typedef struct chdlc_private_area
{
+ /* This member must be first. */
+ struct net_device *slave; /* WAN slave */
+
sdla_t *card;
int TracingEnabled; /* For enabling Tracing */
unsigned long curr_trace_addr; /* Used for Tracing */
*/
typedef struct fr_channel
{
+ /* This member must be first. */
+ struct net_device *slave; /* WAN slave */
+
char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
unsigned dlci_configured ; /* check whether configured or not */
unsigned cir_status; /* check whether CIR enabled or not */
// Used to send inarp request at given interval
if (card->wandev.state == WAN_CONNECTED) {
int num_remaining = 0;
- for (dev=card->wandev.dev;dev;dev=dev->slave) {
+
+ dev = card->wandev.dev;
+ while (dev) {
fr_channel_t *chan = dev->priv;
if (chan->inarp == INARP_REQUEST &&
chan->inarp_tick = jiffies;
}
}
+ dev = chan->slave;
}
if (!num_remaining) { // no more to process
flags->imask &= ~FR_INTR_TIMER;
/* Dynamic Route adding/removing */
- for (dev = card->wandev.dev; dev ; dev = dev->slave) {
- if ( ((fr_channel_t*)dev->priv)->route_flag == ADD_ROUTE ||
- ((fr_channel_t*)dev->priv)->route_flag == REMOVE_ROUTE ) {
- fs = get_fs();
+ dev = card->wandev.dev;
+ while (dev) {
+ fr_channel_t *chan = dev->priv;
+
+ if (chan->route_flag == ADD_ROUTE ||
+ chan->route_flag == REMOVE_ROUTE ) {
+ fs = get_fs();
- in_dev = dev->ip_ptr;
-
- if( in_dev != NULL && in_dev->ifa_list != NULL) {
- memset(&route, 0, sizeof(route));
- route.rt_dev = dev->name;
- route.rt_flags = 0;
-
- ((struct sockaddr_in *) &(route.rt_dst)) ->
- sin_addr.s_addr=in_dev->ifa_list->ifa_address;
- ((struct sockaddr_in *) &(route.rt_dst)) ->
- sin_family = AF_INET;
- ((struct sockaddr_in *) &(route.rt_genmask)) ->
- sin_addr.s_addr = 0xFFFFFFFF;
- ((struct sockaddr_in *) &(route.rt_genmask)) ->
- sin_family = AF_INET;
-
- switch(((fr_channel_t*)dev->priv)->route_flag) {
-
- case ADD_ROUTE:
- set_fs(get_ds()); /* get user space block */
- err = ip_rt_ioctl( SIOCADDRT, &route);
- set_fs(fs); /* restore old block */
-
- if (err) {
- printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err);
- printk(KERN_INFO "%s: Address: %s\n",
- ((fr_channel_t*)dev->priv)->name,
- in_ntoa(in_dev->ifa_list->ifa_address) );
- }
- else {
- ((fr_channel_t*)dev->priv)->
- route_flag = ROUTE_ADDED;
- }
- break;
+ in_dev = dev->ip_ptr;
+
+ if( in_dev != NULL && in_dev->ifa_list != NULL) {
+ memset(&route, 0, sizeof(route));
+ route.rt_dev = dev->name;
+ route.rt_flags = 0;
+
+ ((struct sockaddr_in *) &(route.rt_dst)) ->
+ sin_addr.s_addr=in_dev->ifa_list->ifa_address;
+ ((struct sockaddr_in *) &(route.rt_dst)) ->
+ sin_family = AF_INET;
+ ((struct sockaddr_in *) &(route.rt_genmask)) ->
+ sin_addr.s_addr = 0xFFFFFFFF;
+ ((struct sockaddr_in *) &(route.rt_genmask)) ->
+ sin_family = AF_INET;
+
+ switch(chan->route_flag) {
+
+ case ADD_ROUTE:
+ set_fs(get_ds()); /* get user space block */
+ err = ip_rt_ioctl( SIOCADDRT, &route);
+ set_fs(fs); /* restore old block */
+
+ if (err) {
+ printk(KERN_INFO "%s: Adding of route failed. Error: %d\n", card->devname,err);
+ printk(KERN_INFO "%s: Address: %s\n",
+ chan->name,
+ in_ntoa(in_dev->ifa_list->ifa_address) );
+ } else {
+ chan->route_flag = ROUTE_ADDED;
+ }
+ break;
- case REMOVE_ROUTE:
- set_fs(get_ds()); /* get user space block */
- err = ip_rt_ioctl( SIOCDELRT, &route);
- set_fs(fs); /* restore old block */
+ case REMOVE_ROUTE:
+ set_fs(get_ds()); /* get user space block */
+ err = ip_rt_ioctl( SIOCDELRT, &route);
+ set_fs(fs); /* restore old block */
+
+ if (err) {
+ printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err);
+ printk(KERN_INFO "%s: Address: %s\n",
+ dev->name,in_ntoa(in_dev->ifa_list->ifa_address) );
+ } else {
+ printk(KERN_INFO "%s: Removed route.\n",
+ chan->name);
+ chan->route_flag = NO_ROUTE;
+ }
+ break;
+ } /* Case Statement */
+ }
+ } /* If ADD/DELETE ROUTE */
- if (err) {
- printk(KERN_INFO "%s: Deleting of route failed. Error: %d\n", card->devname,err);
- printk(KERN_INFO "%s: Address: %s\n",
- dev->name,in_ntoa(in_dev->ifa_list->ifa_address) );
- } else {
- printk(KERN_INFO "%s: Removed route.\n",
- ((fr_channel_t*)dev->priv)->name);
- ((fr_channel_t*)dev->priv)->route_flag = NO_ROUTE;
- }
- break;
- } /* Case Statement */
- }
- } /* If ADD/DELETE ROUTE */
- } /* Device 'For' Loop */
+ dev = chan->slave;
+ } /* Device 'While' Loop */
card->poll = NULL;
}
struct net_device *dev;
/* Remove all routes from associated DLCI's */
- for (dev = card->wandev.dev; dev; dev = dev->slave) {
+ dev = card->wandev.dev;
+ while (dev) {
fr_channel_t *chan = dev->priv;
if (chan->route_flag == ROUTE_ADDED) {
chan->route_flag = REMOVE_ROUTE;
if (chan->inarp == INARP_CONFIGURED) {
chan->inarp = INARP_REQUEST;
}
+
+ dev = chan->slave;
}
wanpipe_set_state(card, WAN_DISCONNECTED);
int num_requests = 0;
/* Remove all routes from associated DLCI's */
- for (dev = card->wandev.dev; dev; dev = dev->slave) {
+ dev = card->wandev.dev;
+ while (dev) {
fr_channel_t *chan = dev->priv;
if( chan->inarp == INARP_REQUEST ){
num_requests++;
chan->inarp_tick = jiffies;
}
+ dev = chan->slave;
}
/* Allow timer interrupts */
}
}
- for (dev2 =card->wandev.dev; dev2; dev2 = dev2->slave){
-
+ dev2 = card->wandev.dev;
+ while (dev2) {
chan = dev2->priv;
if (chan->dlci_configured == DLCI_CONFIG_PENDING) {
}
}
+ dev2 = chan->slave;
}
return 1;
}
typedef struct ppp_private_area
{
+ /* This member must be first. */
+ struct net_device *slave; /* WAN slave */
+
sdla_t* card;
unsigned long router_start_time; /*router start time in sec */
unsigned long tick_counter; /*used for 5 second counter*/
*/
typedef struct x25_channel
{
+ /* This member must be first. */
+ struct net_device *slave; /* WAN slave */
+
char name[WAN_IFNAME_SZ+1]; /* interface name, ASCIIZ */
char addr[WAN_ADDRESS_SZ+1]; /* media address, ASCIIZ */
unsigned lcn; /* logical channel number */
return dev->tbusy;
}
printk(KERN_INFO "%s: Transmit time out %s!\n",
- card->devname, dev->name)
- ;
- for( dev2 = card->wandev.dev; dev2; dev2 = dev2->slave)
- {
+ card->devname, dev->name);
+
+ dev2 = card->wandev.dev;
+ while (dev2) {
+ x25_channel_t *chan2 = dev2->priv;
dev2->tbusy = 0;
+ dev2 = chan2->slave;
}
}
chan->tick_counter = jiffies;
if(card->buff_int_mode_unbusy)
{
- for(dev = card->wandev.dev; dev; dev = dev->slave)
- {
- if(((x25_channel_t*)dev->priv)->devtint)
- {
+ x25_channel_t *chan;
+
+ dev = card->wandev.dev;
+ while (dev) {
+ chan = dev->priv;
+ if(chan->devtint) {
mark_bh(NET_BH);
return;
}
+
+ dev = chan->slave;
}
}
}
static void tx_intr (sdla_t* card)
{
struct net_device *dev;
+ x25_channel_t *chan;
/* unbusy all devices and then dev_tint(); */
- for(dev = card->wandev.dev; dev; dev = dev->slave)
- {
- ((x25_channel_t*)dev->priv)->devtint = dev->tbusy;
+ dev = card->wandev.dev;
+ while (dev) {
+ chan->devtint = dev->tbusy;
dev->tbusy = 0;
+
+ dev = chan->slave;
}
}
/* Fetch X.25 asynchronous events */
x25_fetch_events(card);
- for (dev = card->wandev.dev; dev; dev = dev->slave)
- {
+ dev = card->wandev.dev;
+ while (dev) {
x25_channel_t* chan = dev->priv;
struct sk_buff* skb = chan->tx_skb;
chan_disc(dev);
}
}
+
+ dev = chan->slave;
}
}
card->devname, new_lcn, mb->data);
/* Find available channel */
- for (dev = wandev->dev; dev; dev = dev->slave)
- {
+ dev = wandev->dev;
+ while (dev) {
chan = dev->priv;
if (!chan->svc || (chan->state != WAN_DISCONNECTED))
/* If just an '@' is specified, accept all incoming calls */
if (strcmp(chan->addr, "") == 0)
break;
+
+ dev = chan->slave;
}
if (dev == NULL)
card->devname, mb->cmd.cause, mb->cmd.diagn);
/* down all logical channels */
- for (dev = wandev->dev; dev; dev = dev->slave)
+ dev = wandev->dev;
+ while (dev) {
+ x25_channel_t *chan = dev->priv;
+
set_chan_state(dev, WAN_DISCONNECTED);
+ dev = chan->slave;
+ }
+
return (cmd == X25_WRITE) ? 0 : 1;
}
static struct net_device* get_dev_by_lcn (wan_device_t* wandev, unsigned lcn)
{
struct net_device* dev;
+ x25_channel_t *chan;
- for (dev = wandev->dev; dev; dev = dev->slave)
- if (((x25_channel_t*)dev->priv)->lcn == lcn)
+ dev = wandev->dev;
+ while (dev) {
+ if (chan->lcn == lcn)
break;
+ dev = chan->slave;
+ }
return dev;
}
if (info.sign != EATA_SIGNATURE) return FALSE;
if (DEV2H(info.data_len) < EATA_2_0A_SIZE) {
- printk("%s: config structure size (%ld bytes) too short, detaching.\n",
+ printk("%s: config structure size (%d bytes) too short, detaching.\n",
name, DEV2H(info.data_len));
return FALSE;
}
* tackle the character devices first, as there aren't any locking implications
* in the block device layer. The block devices will require more work.
*/
+#ifndef CONFIG_SD_EXTRA_DEVS
+#define CONFIG_SD_EXTRA_DEVS 2
+#endif
+#ifndef CONFIG_ST_EXTRA_DEVS
+#define CONFIG_ST_EXTRA_DEVS 2
+#endif
+#ifndef CONFIG_SR_EXTRA_DEVS
+#define CONFIG_SR_EXTRA_DEVS 2
+#endif
#define SD_EXTRA_DEVS CONFIG_SD_EXTRA_DEVS
#define ST_EXTRA_DEVS CONFIG_ST_EXTRA_DEVS
#define SR_EXTRA_DEVS CONFIG_SR_EXTRA_DEVS
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * History
- * Jan 14 2000 Ollie Lho <ollie@sis.com.tw>
- * Isloated from trident.c to support multiple ac97 codec
+ * History
+ * v0.2 Feb 10 2000 Ollie Lho
+ * add ac97_read_proc for /proc/driver/vnedor/ac97
+ * v0.1 Jan 14 2000 Ollie Lho <ollie@sis.com.tw>
+ * Isolated from trident.c to support multiple ac97 codec
*/
#include <linux/module.h>
#include <linux/version.h>
unsigned int id;
char *name;
int (*init) (struct ac97_codec *codec);
-} snd_ac97_codec_ids[] = {
+} ac97_codec_ids[] = {
{0x414B4D00, "Asahi Kasei AK4540" , NULL},
{0x41445340, "Analog Devices AD1881" , NULL},
{0x43525900, "Cirrus Logic CS4297" , NULL},
{0x83847605, "SigmaTel STAC9704" , NULL},
{0x83847608, "SigmaTel STAC9708" , NULL},
{0x83847609, "SigmaTel STAC9721/23" , NULL},
+ {0x54524108, "TriTech TR28028" , NULL},
+ {0x574D4C00, "Wolfson WM9704" , NULL},
{0x00000000, NULL, NULL}
};
+static const char *ac97_stereo_enhancements[] =
+{
+ /* 0 */ "No 3D Stereo Enhancement",
+ /* 1 */ "Analog Devices Phat Stereo",
+ /* 2 */ "Creative Stereo Enhancement",
+ /* 3 */ "National Semi 3D Stereo Enhancement",
+ /* 4 */ "YAMAHA Ymersion",
+ /* 5 */ "BBE 3D Stereo Enhancement",
+ /* 6 */ "Crystal Semi 3D Stereo Enhancement",
+ /* 7 */ "Qsound QXpander",
+ /* 8 */ "Spatializer 3D Stereo Enhancement",
+ /* 9 */ "SRS 3D Stereo Enhancement",
+ /* 10 */ "Platform Tech 3D Stereo Enhancement",
+ /* 11 */ "AKM 3D Audio",
+ /* 12 */ "Aureal Stereo Enhancement",
+ /* 13 */ "Aztech 3D Enhancement",
+ /* 14 */ "Binaura 3D Audio Enhancement",
+ /* 15 */ "ESS Technology Stereo Enhancement",
+ /* 16 */ "Harman International VMAx",
+ /* 17 */ "Nvidea 3D Stereo Enhancement",
+ /* 18 */ "Philips Incredible Sound",
+ /* 19 */ "Texas Instruments 3D Stereo Enhancement",
+ /* 20 */ "VLSI Technology 3D Stereo Enhancement",
+ /* 21 */ "TriTech 3D Stereo Enhancement",
+ /* 22 */ "Realtek 3D Stereo Enhancement",
+ /* 23 */ "Samsung 3D Stereo Enhancement",
+ /* 24 */ "Wolfson Microelectronics 3D Enhancement",
+ /* 25 */ "Delta Integration 3D Enhancement",
+ /* 26 */ "SigmaTel 3D Enhancement",
+ /* 27 */ "Reserved 27",
+ /* 28 */ "Rockwell 3D Stereo Enhancement",
+ /* 29 */ "Reserved 29",
+ /* 30 */ "Reserved 30",
+ /* 31 */ "Reserved 31"
+};
/* this table has default mixer values for all OSS mixers. */
static struct mixer_defaults {
} ac97_hw[SOUND_MIXER_NRDEVICES]= {
[SOUND_MIXER_VOLUME] = {AC97_MASTER_VOL_STEREO,63},
[SOUND_MIXER_BASS] = {AC97_MASTER_TONE, 15},
- [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15},
+ [SOUND_MIXER_TREBLE] = {AC97_MASTER_TONE, 15},
[SOUND_MIXER_PCM] = {AC97_PCMOUT_VOL, 31},
- [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15},
+ [SOUND_MIXER_SPEAKER] = {AC97_PCBEEP_VOL, 15},
[SOUND_MIXER_LINE] = {AC97_LINEIN_VOL, 31},
[SOUND_MIXER_MIC] = {AC97_MIC_VOL, 31},
[SOUND_MIXER_CD] = {AC97_CD_VOL, 31},
right = 100 - ((right * 100) / mh->scale);
left = 100 - ((left * 100) / mh->scale);
}
-
ret = left | (right << 8);
} else if (oss_channel == SOUND_MIXER_SPEAKER) {
ret = 100 - ((((val & 0x1e)>>1) * 100) / mh->scale);
+ } else if (oss_channel == SOUND_MIXER_PHONEIN) {
+ ret = 100 - (((val & 0x1f) * 100) / mh->scale);
+ } else if (oss_channel == SOUND_MIXER_PHONEOUT) {
+ ret = 100 - (((val & 0x1f) * 100) / mh->scale);
} else if (oss_channel == SOUND_MIXER_MIC) {
ret = 100 - (((val & 0x1f) * 100) / mh->scale);
/* the low bit is optional in the tone sliders and masking
} else {
right = ((100 - right) * mh->scale) / 100;
left = ((100 - left) * mh->scale) / 100;
- }
+ }
val = (left << 8) | right;
} else if (oss_channel == SOUND_MIXER_SPEAKER) {
val = (((100 - left) * mh->scale) / 100) << 1;
+ } else if (oss_channel == SOUND_MIXER_PHONEIN) {
+ val = (((100 - left) * mh->scale) / 100);
+ } else if (oss_channel == SOUND_MIXER_PHONEOUT) {
+ val = (((100 - left) * mh->scale) / 100);
} else if (oss_channel == SOUND_MIXER_MIC) {
val = codec->codec_read(codec , mh->offset) & ~0x801f;
val |= (((100 - left) * mh->scale) / 100);
} else if (oss_channel == SOUND_MIXER_BASS) {
val = codec->codec_read(codec , mh->offset) & ~0x0f00;
val |= ((((100 - left) * mh->scale) / 100) << 8) & 0x0e00;
- } else if (oss_channel == SOUND_MIXER_TREBLE) {
+ } else if (oss_channel == SOUND_MIXER_TREBLE) {
val = codec->codec_read(codec , mh->offset) & ~0x000f;
val |= (((100 - left) * mh->scale) / 100) & 0x000e;
}
-
#ifdef DEBUG
printk(" 0x%04x", val);
#endif
return -EINVAL;
/* do we ever want to touch the hardware? */
- /* val = codec->read_mixer(card,i); */
- val = codec->mixer_state[i];
+ val = codec->read_mixer(card, i);
+ /* val = codec->mixer_state[i]; */
break;
}
- return put_user(val,(int *)arg);
+ return put_user(val, (int *)arg);
}
if (_IOC_DIR(cmd) == (_IOC_WRITE|_IOC_READ)) {
return -EINVAL;
}
+/* entry point for /proc/driver/controller_vendor/ac97/%d */
+int ac97_read_proc (char *page, char **start, off_t off,
+ int count, int *eof, void *data)
+{
+ int len = 0, cap, extid, val, id1, id2;
+ struct ac97_codec *codec;
+
+ if ((codec = data) == NULL)
+ return -ENODEV;
+
+ id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
+ id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
+ len += sprintf (page+len, "Vendor name : %s\n", codec->name);
+ len += sprintf (page+len, "Vendor id : %04X %04X\n", id1, id2);
+
+ extid = codec->codec_read(codec, AC97_EXTENDED_ID);
+ extid &= ~((1<<2)|(1<<4)|(1<<5)|(1<<10)|(1<<11)|(1<<12)|(1<<13));
+ len += sprintf (page+len, "AC97 Version : %s\n",
+ extid ? "2.0 or later" : "1.0");
+
+ cap = codec->codec_read(codec, AC97_RESET);
+ len += sprintf (page+len, "Capabilities :%s%s%s%s%s%s\n",
+ cap & 0x0001 ? " -dedicated MIC PCM IN channel-" : "",
+ cap & 0x0002 ? " -reserved1-" : "",
+ cap & 0x0004 ? " -bass & treble-" : "",
+ cap & 0x0008 ? " -simulated stereo-" : "",
+ cap & 0x0010 ? " -headphone out-" : "",
+ cap & 0x0020 ? " -loudness-" : "");
+ val = cap & 0x00c0;
+ len += sprintf (page+len, "DAC resolutions :%s%s%s\n",
+ " -16-bit-",
+ val & 0x0040 ? " -18-bit-" : "",
+ val & 0x0080 ? " -20-bit-" : "");
+ val = cap & 0x0300;
+ len += sprintf (page+len, "ADC resolutions :%s%s%s\n",
+ " -16-bit-",
+ val & 0x0100 ? " -18-bit-" : "",
+ val & 0x0200 ? " -20-bit-" : "");
+ len += sprintf (page+len, "3D enhancement : %s\n",
+ ac97_stereo_enhancements[(cap >> 10) & 0x1f]);
+
+ val = codec->codec_read(codec, AC97_GENERAL_PURPOSE);
+ len += sprintf (page+len, "POP path : %s 3D\n"
+ "Sim. stereo : %s\n"
+ "3D enhancement : %s\n"
+ "Loudness : %s\n"
+ "Mono output : %s\n"
+ "MIC select : %s\n"
+ "ADC/DAC loopback : %s\n",
+ val & 0x8000 ? "post" : "pre",
+ val & 0x4000 ? "on" : "off",
+ val & 0x2000 ? "on" : "off",
+ val & 0x1000 ? "on" : "off",
+ val & 0x0200 ? "MIC" : "MIX",
+ val & 0x0100 ? "MIC2" : "MIC1",
+ val & 0x0080 ? "on" : "off");
+
+ cap = extid;
+ len += sprintf (page+len, "Ext Capabilities :%s%s%s%s%s%s%s\n",
+ cap & 0x0001 ? " -var rate PCM audio-" : "",
+ cap & 0x0002 ? " -2x PCM audio out-" : "",
+ cap & 0x0008 ? " -var rate MIC in-" : "",
+ cap & 0x0040 ? " -PCM center DAC-" : "",
+ cap & 0x0080 ? " -PCM surround DAC-" : "",
+ cap & 0x0100 ? " -PCM LFE DAC-" : "",
+ cap & 0x0200 ? " -slot/DAC mappings-" : "");
+
+ return len;
+}
+
int ac97_probe_codec(struct ac97_codec *codec)
{
u16 id1, id2, cap;
id1 = codec->codec_read(codec, AC97_VENDOR_ID1);
id2 = codec->codec_read(codec, AC97_VENDOR_ID2);
- for (i = 0; i < sizeof (snd_ac97_codec_ids); i++) {
- if (snd_ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
- codec->name = snd_ac97_codec_ids[i].name;
- codec->codec_init = snd_ac97_codec_ids[i].init;
+ for (i = 0, codec->name = NULL; i < arraysize (ac97_codec_ids[i]); i++) {
+ if (ac97_codec_ids[i].id == ((id1 << 16) | id2)) {
+ codec->name = ac97_codec_ids[i].name;
+ codec->codec_init = ac97_codec_ids[i].init;
break;
}
}
codec->name = "Unknown";
printk(KERN_INFO "ac97_codec: ac97 vendor id1: 0x%04x, id2: 0x%04x (%s)\n",
id1, id2, codec->name);
- printk(KERN_INFO "ac97_codec: capability: 0x%04x\n", cap);
/* mixer masks */
codec->supported_mixers = AC97_SUPPORTED_MASK;
return 1;
}
+EXPORT_SYMBOL(ac97_read_proc);
EXPORT_SYMBOL(ac97_probe_codec);
SOUND_MIXER_PHONEIN|SOUND_MIXER_PHONEOUT)
#define AC97_RECORD_MASK (SOUND_MASK_MIC|\
- SOUND_MASK_CD| SOUND_MASK_VIDEO| SOUND_MASK_LINE1| SOUND_MASK_LINE|\
+ SOUND_MASK_CD|SOUND_MASK_VIDEO|\
+ SOUND_MASK_LINE1| SOUND_MASK_LINE|\
SOUND_MASK_PHONEIN)
#define supported_mixer(CODEC,FOO) ( CODEC->supported_mixers & (1<<FOO) )
unsigned int mixer_state[SOUND_MIXER_NRDEVICES];
};
+extern int ac97_read_proc (char *page_out, char **start, off_t off,
+ int count, int *eof, void *data);
extern int ac97_probe_codec(struct ac97_codec *);
#endif /* _AC97_CODEC_H_ */
tristate 'UDF filesystem support (read only)' CONFIG_UDF_FS
if [ "$CONFIG_UDF_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then
- dep_bool ' UDF write support (DANGEROUS)' CONFIG_UDF_RW
+ bool ' UDF write support (DANGEROUS)' CONFIG_UDF_RW
fi
tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS
if (error)
goto out;
- if (ia_valid & ATTR_SIZE)
+ if (ia_valid & ATTR_SIZE) {
inode->i_size = attr->ia_size;
+ vmtruncate(inode, attr->ia_size);
+ }
if (ia_valid & ATTR_MTIME) {
inode->i_mtime = attr->ia_mtime;
adfs_unix2adfs_time(inode, attr->ia_mtime);
if (attr->ia_valid & ATTR_MODE)
inode->u.affs_i.i_protect = mode_to_prot(attr->ia_mode);
- inode_setattr(inode, attr);
- mark_inode_dirty(inode);
error = 0;
+ inode_setattr(inode, attr);
out:
return error;
}
inode->i_uid = attr->ia_uid;
if (ia_valid & ATTR_GID)
inode->i_gid = attr->ia_gid;
- if (ia_valid & ATTR_SIZE)
+ if (ia_valid & ATTR_SIZE) {
inode->i_size = attr->ia_size;
+ vmtruncate(inode, attr->ia_size);
+ }
if (ia_valid & ATTR_ATIME)
inode->i_atime = attr->ia_atime;
if (ia_valid & ATTR_MTIME)
if (!error)
inode_setattr(inode, attr);
}
- if (!error && (attr->ia_valid & ATTR_SIZE))
- vmtruncate(inode, attr->ia_size);
return error;
}
return 0;
return sector+sb->dir_start;
}
- if (sector >= MSDOS_I(inode)->mmu_private>>9)
+ if (sector >= (MSDOS_I(inode)->mmu_private+511)>>9)
return 0;
cluster = sector/sb->cluster_size;
offset = sector % sb->cluster_size;
INIT_LIST_HEAD(&inode->i_data.pages);
INIT_LIST_HEAD(&inode->i_dentry);
sema_init(&inode->i_sem, 1);
- spin_lock_init(&inode->i_shared_lock);
+ spin_lock_init(&inode->i_data.i_shared_lock);
}
}
inode = list_entry(inode_entry, struct inode, i_list);
if (inode->i_data.nrpages)
- truncate_inode_pages(inode, 0);
+ truncate_inode_pages(&inode->i_data, 0);
clear_inode(inode);
destroy_inode(inode);
}
void (*delete)(struct inode *) = op->delete_inode;
spin_unlock(&inode_lock);
if (inode->i_data.nrpages)
- truncate_inode_pages(inode, 0);
+ truncate_inode_pages(&inode->i_data, 0);
delete(inode);
spin_lock(&inode_lock);
}
if (IS_MANDLOCK(inode) &&
(inode->i_mode & (S_ISGID | S_IXGRP)) == S_ISGID) {
struct vm_area_struct *vma;
- spin_lock(&inode->i_shared_lock);
- for(vma = inode->i_mmap;vma;vma = vma->vm_next_share) {
+ struct address_space *mapping = inode->i_mapping;
+ spin_lock(&mapping->i_shared_lock);
+ for(vma = mapping->i_mmap;vma;vma = vma->vm_next_share) {
if (!(vma->vm_flags & VM_MAYSHARE))
continue;
- spin_unlock(&inode->i_shared_lock);
+ spin_unlock(&mapping->i_shared_lock);
error = -EAGAIN;
goto out_putf;
}
- spin_unlock(&inode->i_shared_lock);
+ spin_unlock(&mapping->i_shared_lock);
}
error = -EINVAL;
/* According to ndir, the changes only take effect after
closing the file */
result = ncp_make_closed(inode);
+ if (!result)
+ vmtruncate(inode, attr->ia_size);
}
out:
return result;
if (attr->ia_valid & ATTR_MTIME)
inode->i_mtime = fattr.mtime.seconds;
error = nfs_refresh_inode(inode, &fattr);
+ if (!error && (attr->ia_valid & ATTR_SIZE))
+ vmtruncate(inode, attr->ia_size);
out:
return error;
}
*/
if (attr->ia_size < inode->i_size)
{
- truncate_inode_pages(inode, attr->ia_size);
+ /* must die */
+ truncate_inode_pages(inode->i_mapping, attr->ia_size);
inode->i_size = attr->ia_size;
}
refresh = 1;
out:
if (refresh)
smb_refresh_inode(dentry);
+ if (!error && (attr->ia_valid & ATTR_SIZE))
+ vmtruncate(inode, attr->ia_size);
return error;
}
int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
{
struct inode *dir = dentry->d_parent->d_inode;
+ struct inode *inode = dentry->d_inode;
int ret;
+ ret = inode_change_ok (inode, attr);
+ if (ret)
+ goto out;
+
down(&dir->i_sem);
ret = umsdos_notify_change_locked(dentry, attr);
up(&dir->i_sem);
+ if (ret == 0)
+ inode_setattr (inode, attr);
+out:
return ret;
}
{
struct inode *inode = dentry->d_inode;
struct dentry *demd;
- int ret;
+ int ret = 0;
struct file filp;
struct umsdos_dirent entry;
Printk(("UMSDOS_notify_change: entering for %s/%s (%d)\n",
dentry->d_parent->d_name.name, dentry->d_name.name, inode->u.umsdos_i.i_patched));
- ret = inode_change_ok (inode, attr);
- if (ret) {
-printk("UMSDOS_notify_change: %s/%s change not OK, ret=%d\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, ret);
- goto out;
- }
-
if (inode->i_nlink == 0)
goto out;
if (inode->i_ino == UMSDOS_ROOT_INO)
out_dput:
dput(demd);
out:
- if (ret == 0)
- inode_setattr (inode, attr);
return ret;
}
oldinode->i_ino, oldinode->i_nlink));
newattrs.ia_valid = 0;
ret = umsdos_notify_change_locked(olddentry, &newattrs);
+ if (ret == 0)
+ mark_inode_dirty(olddentry->d_inode);
}
if (olddir != dir)
up(&olddir->i_sem);
inode->i_nlink--;
newattrs.ia_valid = 0;
ret = umsdos_notify_change_locked(link, &newattrs);
+ if (!ret)
+ mark_inode_dirty(link->d_inode);
}
out_cleanup:
unsigned long nrpages; /* number of pages */
struct address_space_operations *a_ops; /* methods */
void *host; /* owner: inode, block_device */
- void *private; /* private data */
+ struct vm_area_struct *i_mmap; /* list of mappings */
+ spinlock_t i_shared_lock; /* and spinlock protecting it */
};
struct block_device {
struct super_block *i_sb;
wait_queue_head_t i_wait;
struct file_lock *i_flock;
- struct vm_area_struct *i_mmap;
- struct address_space *i_mapping;
+ struct address_space *i_mapping;
struct address_space i_data;
- spinlock_t i_shared_lock;
struct dquot *i_dquot[MAXQUOTAS];
struct pipe_inode_info *i_pipe;
struct block_device *i_bdev;
extern void remove_inode_page(struct page *);
extern unsigned long page_unuse(struct page *);
extern int shrink_mmap(int, int, zone_t *);
-extern void truncate_inode_pages(struct inode *, loff_t);
+extern void truncate_inode_pages(struct address_space *, loff_t);
/* generic vm_area_ops exported for stackable file systems */
extern int filemap_swapout(struct page * page, struct file *file);
tmp->vm_next = NULL;
file = tmp->vm_file;
if (file) {
+ struct inode *inode = file->f_dentry->d_inode;
get_file(file);
if (tmp->vm_flags & VM_DENYWRITE)
- atomic_dec(&file->f_dentry->d_inode->i_writecount);
+ atomic_dec(&inode->i_writecount);
/* insert tmp into the share list, just after mpnt */
- spin_lock(&file->f_dentry->d_inode->i_shared_lock);
+ spin_lock(&inode->i_mapping->i_shared_lock);
if((tmp->vm_next_share = mpnt->vm_next_share) != NULL)
mpnt->vm_next_share->vm_pprev_share =
&tmp->vm_next_share;
mpnt->vm_next_share = tmp;
tmp->vm_pprev_share = &mpnt->vm_next_share;
- spin_unlock(&file->f_dentry->d_inode->i_shared_lock);
+ spin_unlock(&inode->i_mapping->i_shared_lock);
}
/* Copy the pages, but defer checking for errors */
* Truncate the page cache at a set offset, removing the pages
* that are beyond that offset (and zeroing out partial pages).
*/
-void truncate_inode_pages(struct inode * inode, loff_t lstart)
+void truncate_inode_pages(struct address_space * mapping, loff_t lstart)
{
struct list_head *head, *curr;
struct page * page;
start = (lstart + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
repeat:
- head = &inode->i_mapping->pages;
+ head = &mapping->pages;
spin_lock(&pagecache_lock);
curr = head->next;
while (curr != head) {
{
unsigned long partial, pgoff;
struct vm_area_struct * mpnt;
+ struct address_space *mapping = inode->i_mapping;
- truncate_inode_pages(inode, offset);
- spin_lock(&inode->i_shared_lock);
- if (!inode->i_mmap)
+ truncate_inode_pages(mapping, offset);
+ spin_lock(&mapping->i_shared_lock);
+ if (!mapping->i_mmap)
goto out_unlock;
pgoff = (offset + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
partial = (unsigned long)offset & (PAGE_CACHE_SIZE - 1);
- mpnt = inode->i_mmap;
+ mpnt = mapping->i_mmap;
do {
struct mm_struct *mm = mpnt->vm_mm;
unsigned long start = mpnt->vm_start;
flush_tlb_range(mm, start, end);
} while ((mpnt = mpnt->vm_next_share) != NULL);
out_unlock:
- spin_unlock(&inode->i_shared_lock);
+ spin_unlock(&mapping->i_shared_lock);
if (inode->i_op && inode->i_op->truncate)
inode->i_op->truncate(inode);
}
struct file * file = vma->vm_file;
if (file) {
+ struct inode *inode = file->f_dentry->d_inode;
if (vma->vm_flags & VM_DENYWRITE)
- atomic_inc(&file->f_dentry->d_inode->i_writecount);
- spin_lock(&file->f_dentry->d_inode->i_shared_lock);
+ atomic_inc(&inode->i_writecount);
+ spin_lock(&inode->i_mapping->i_shared_lock);
if(vma->vm_next_share)
vma->vm_next_share->vm_pprev_share = vma->vm_pprev_share;
*vma->vm_pprev_share = vma->vm_next_share;
- spin_unlock(&file->f_dentry->d_inode->i_shared_lock);
+ spin_unlock(&inode->i_mapping->i_shared_lock);
}
}
file = vmp->vm_file;
if (file) {
struct inode * inode = file->f_dentry->d_inode;
+ struct address_space *mapping = inode->i_mapping;
if (vmp->vm_flags & VM_DENYWRITE)
atomic_dec(&inode->i_writecount);
/* insert vmp into inode's share list */
- spin_lock(&inode->i_shared_lock);
- if((vmp->vm_next_share = inode->i_mmap) != NULL)
- inode->i_mmap->vm_pprev_share = &vmp->vm_next_share;
- inode->i_mmap = vmp;
- vmp->vm_pprev_share = &inode->i_mmap;
- spin_unlock(&inode->i_shared_lock);
+ spin_lock(&mapping->i_shared_lock);
+ if((vmp->vm_next_share = mapping->i_mmap) != NULL)
+ mapping->i_mmap->vm_pprev_share = &vmp->vm_next_share;
+ mapping->i_mmap = vmp;
+ vmp->vm_pprev_share = &mapping->i_mmap;
+ spin_unlock(&mapping->i_shared_lock);
}
}
memset(dev->broadcast, 0xff, 4);
dev->mtu = 2048;
- dev->tbusy = 1;
-
dev_init_buffers(dev);
-
dev->flags = IFF_NOARP;
-
return 0;
}
* is up, that means that the "user" really wants to connect. If not
* we notify the user about the possibility of an IrLAN connection
*/
- if (self->dev.start) {
+ if (test_bit(LINK_STATE_START, &self->dev.state)) {
/* Open TSAPs */
irlan_client_open_ctrl_tsap(self);
irlan_open_data_tsap(self);
ASSERT(self->magic == IRLAN_MAGIC, return;);
/* Check if device still configured */
- if (self->dev.start) {
+ if (test_bit(LINK_STATE_START, &self->dev.state)) {
IRDA_DEBUG(0, __FUNCTION__
"(), notifying irmanager to stop irlan!\n");
mgr_event.event = EVENT_IRLAN_STOP;
ASSERT(self->magic == IRLAN_MAGIC, return;);
/* Check if device is still configured */
- if (self->dev.start) {
+ if (test_bit(LINK_STATE_START, &self->dev.state)) {
IRDA_DEBUG(0, __FUNCTION__
"(), Device still configured, closing later!\n");
irlan_open_unicast_addr(self);
}
/* Ready to transfer Ethernet frames (at last) */
- self->dev.tbusy = 0;
+ netif_start_queue(&self->dev);
}
void irlan_connect_confirm(void *instance, void *sap, struct qos_info *qos,
irlan_set_multicast_filter(self, TRUE);
/* Ready to transfer Ethernet frames */
- self->dev.tbusy = 0;
-
+ netif_start_queue(&self->dev);
irlan_eth_send_gratuitous_arp(&self->dev);
}
buf+len);
len += sprintf(buf+len, "tx busy: %s\n",
- self->dev.tbusy ? "TRUE" : "FALSE");
+ test_bit(LINK_STATE_XOFF, &self->dev.state) ? "TRUE" : "FALSE");
len += sprintf(buf+len, "\n");
}
dev->get_stats = irlan_eth_get_stats;
dev->set_multicast_list = irlan_eth_set_multicast_list;
- dev->tbusy = 1;
-
ether_setup(dev);
/*
ASSERT(self != NULL, return -1;);
/* Ready to play! */
-/* dev->tbusy = 0; */ /* Wait until data link is ready */
- dev->interrupt = 0;
- dev->start = 1;
+/* netif_start_queue(dev) */ /* Wait until data link is ready */
self->notify_irmanager = TRUE;
IRDA_DEBUG(2, __FUNCTION__ "()\n");
/* Stop device */
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
+
irlan_mod_dec_use_count();
irlan_close_data_channel(self);
ASSERT(self != NULL, return 0;);
ASSERT(self->magic == IRLAN_MAGIC, return 0;);
- /* Check if IrTTP can accept more frames */
- if (dev->tbusy)
- return -EBUSY;
-
/* skb headroom large enough to contain all IrDA-headers? */
if ((skb_headroom(skb) < self->max_header_size) || (skb_shared(skb))) {
struct sk_buff *new_skb =
* Function irlan_eth_flow (status)
*
* Do flow control between IP/Ethernet and IrLAN/IrTTP. This is done by
- * controlling the dev->tbusy variable.
+ * controlling the queue stop/start.
*/
void irlan_eth_flow_indication(void *instance, void *sap, LOCAL_FLOW flow)
{
switch (flow) {
case FLOW_STOP:
- dev->tbusy = 1;
+ netif_stop_queue(dev);
break;
case FLOW_START:
default:
/* Tell upper layers that its time to transmit frames again */
- dev->tbusy = 0;
-
/* Schedule network layer */
- mark_bh(NET_BH);
+ netif_start_queue(dev);
break;
}
}
{
struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
- if (!dev->start) {
+ if (!test_bit(LINK_STATE_START, &dev->state)) {
stats->rx_errors++;
return 0;
}
static int nr_open(struct net_device *dev)
{
- dev->tbusy = 0;
- dev->start = 1;
-
MOD_INC_USE_COUNT;
-
+ netif_start_queue(dev);
ax25_listen_register((ax25_address *)dev->dev_addr, NULL);
-
return 0;
}
static int nr_close(struct net_device *dev)
{
- dev->tbusy = 1;
- dev->start = 0;
-
+ netif_stop_queue(dev);
ax25_listen_release((ax25_address *)dev->dev_addr, NULL);
-
MOD_DEC_USE_COUNT;
-
return 0;
}
static int nr_xmit(struct sk_buff *skb, struct net_device *dev)
{
struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
-
- if (skb == NULL || dev == NULL)
- return 0;
-
- if (!dev->start) {
- printk(KERN_ERR "NET/ROM: nr_xmit - called when iface is down\n");
- return 1;
- }
-
- cli();
-
- if (dev->tbusy != 0) {
- sti();
- stats->tx_errors++;
- return 1;
- }
-
- dev->tbusy = 1;
-
- sti();
-
- kfree_skb(skb);
-
+ dev_kfree_skb(skb);
stats->tx_errors++;
-
- dev->tbusy = 0;
-
- mark_bh(NET_BH);
-
return 0;
}
int nr_init(struct net_device *dev)
{
dev->mtu = NR_MAX_PACKET_SIZE;
- dev->tbusy = 0;
dev->hard_start_xmit = nr_xmit;
dev->open = nr_open;
dev->stop = nr_close;
struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
#ifdef CONFIG_INET
- if (!dev->start) {
+ if (!test_bit(LINK_STATE_START, &dev->state)) {
stats->rx_errors++;
return 0;
}
static int rose_open(struct net_device *dev)
{
- dev->tbusy = 0;
- dev->start = 1;
-
MOD_INC_USE_COUNT;
-
+ netif_start_queue(dev);
rose_add_loopback_node((rose_address *)dev->dev_addr);
-
return 0;
}
static int rose_close(struct net_device *dev)
{
- dev->tbusy = 1;
- dev->start = 0;
-
- MOD_DEC_USE_COUNT;
-
+ netif_stop_queue(dev);
rose_del_loopback_node((rose_address *)dev->dev_addr);
-
+ MOD_DEC_USE_COUNT;
return 0;
}
{
struct net_device_stats *stats = (struct net_device_stats *)dev->priv;
- if (skb == NULL || dev == NULL)
- return 0;
-
- if (!dev->start) {
+ if (!test_bit(LINK_STATE_START, &dev->state)) {
printk(KERN_ERR "ROSE: rose_xmit - called when iface is down\n");
return 1;
}
-
- cli();
-
- if (dev->tbusy != 0) {
- sti();
- stats->tx_errors++;
- return 1;
- }
-
- dev->tbusy = 1;
-
- sti();
-
- kfree_skb(skb);
-
+ dev_kfree_skb(skb);
stats->tx_errors++;
-
- dev->tbusy = 0;
-
- mark_bh(NET_BH);
-
return 0;
}
int rose_init(struct net_device *dev)
{
dev->mtu = ROSE_MAX_PACKET_SIZE - 2;
- dev->tbusy = 0;
dev->hard_start_xmit = rose_xmit;
dev->open = rose_open;
dev->stop = rose_close;
for (dev = wandev->dev; dev;)
{
if (delete_interface(wandev, dev->name, 0))
- dev = dev->slave;
+ {
+ struct net_device **slave = dev->priv;
+ dev = *slave;
+ }
}
if (wandev->ndev)
return -EBUSY; /* there are opened interfaces */
#endif
err = register_netdev(dev);
if (!err) {
+ struct net_device **slave = dev->priv;
+
cli(); /***** critical section start *****/
- dev->slave = wandev->dev;
+ *slave = wandev->dev;
wandev->dev = dev;
++wandev->ndev;
sti(); /****** critical section end ******/
{
struct net_device *dev, *prev;
- for (dev = wandev->dev, prev = NULL;
- dev && strcmp(name, dev->name);
- prev = dev, dev = dev->slave);
+ dev = wandev->dev;
+ prev = NULL;
+ while (dev && strcmp(name, dev->name)) {
+ struct net_device **slave = dev->priv;
+
+ prev = dev;
+ dev = *slave;
+ }
if (dev == NULL)
return -ENODEV; /* interface not found */
- if (dev->start) {
+ if (test_bit(LINK_STATE_START, &dev->state)) {
if (force) {
printk(KERN_WARNING
"%s: deleting opened interface %s!\n",
wandev->del_if(wandev, dev);
cli(); /***** critical section start *****/
- if (prev)
- prev->slave = dev->slave;
- else
- wandev->dev = dev->slave;
+ if (prev) {
+ struct net_device **prev_slave = prev->priv;
+ struct net_device **slave = dev->priv;
+
+ *prev_slave = *slave;
+ } else {
+ struct net_device **slave = dev->priv;
+
+ wandev->dev = *slave;
+ }
--wandev->ndev;
sti(); /****** critical section end ******/