#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/in.h>
-#include <linux/slab.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/crc32.h>
/* store this information for the driver.. */
struct smc_local {
/*
- these are things that the kernel wants me to keep, so users
- can find out semi-useless statistics of how well the card is
- performing
- */
- struct net_device_stats stats;
-
- /*
If I have to wait until memory is available to send
a packet, I will store the skbuff here, until I get the
desired memory. Then, I'll send it out and free it.
static int smc_close(struct net_device *dev);
/*
- . This routine allows the proc file system to query the driver's
- . statistics.
-*/
-static struct net_device_stats * smc_query_statistics( struct net_device *dev);
-
-/*
. Finally, a call to set promiscuous mode ( for TCPDUMP and related
. programs ) and multicast modes.
*/
/*
. Handles the actual interrupt
*/
-static irqreturn_t smc_interrupt(int irq, void *, struct pt_regs *regs);
+static irqreturn_t smc_interrupt(int irq, void *);
/*
. This is a separate procedure to handle the receipt of a packet, to
. leave the interrupt code looking slightly cleaner
. to store the packet, I call this routine, which either sends it
. now, or generates an interrupt when the card is ready for the
. packet */
-static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device *dev );
+static netdev_tx_t smc_wait_to_send_packet( struct sk_buff * skb,
+ struct net_device *dev );
/* this does a soft reset on the device */
static void smc_reset( int ioaddr );
/*
- . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds )
+ . Function: smc_setmulticast( int ioaddr, struct net_device *dev )
. Purpose:
. This sets the internal hardware table to filter out unwanted multicast
. packets before they take up memory.
*/
-static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) {
+static void smc_setmulticast(int ioaddr, struct net_device *dev)
+{
int i;
unsigned char multicast_table[ 8 ];
- struct dev_mc_list * cur_addr;
+ struct netdev_hw_addr *ha;
/* table for flipping the order of 3 bits */
unsigned char invert3[] = { 0, 4, 2, 6, 1, 5, 3, 7 };
/* start with a table of all zeros: reject all */
memset( multicast_table, 0, sizeof( multicast_table ) );
- cur_addr = addrs;
- for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) {
+ netdev_for_each_mc_addr(ha, dev) {
int position;
- /* do we have a pointer here? */
- if ( !cur_addr )
- break;
/* make sure this is a multicast address - shouldn't this
be a given if we have it here ? */
- if ( !( *cur_addr->dmi_addr & 1 ) )
+ if (!(*ha->addr & 1))
continue;
/* only use the low order bits */
- position = ether_crc_le(6, cur_addr->dmi_addr) & 0x3f;
+ position = ether_crc_le(6, ha->addr) & 0x3f;
/* do some messy swapping to put the bit in the right spot */
multicast_table[invert3[position&7]] |=
. o (NO): Enable interrupts and let the interrupt handler deal with it.
. o (YES):Send it now.
*/
-static int smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * dev )
+static netdev_tx_t smc_wait_to_send_packet(struct sk_buff *skb,
+ struct net_device *dev)
{
struct smc_local *lp = netdev_priv(dev);
unsigned int ioaddr = dev->base_addr;
if ( lp->saved_skb) {
/* THIS SHOULD NEVER HAPPEN. */
- lp->stats.tx_aborted_errors++;
+ dev->stats.tx_aborted_errors++;
printk(CARDNAME": Bad Craziness - sent packet while busy.\n" );
- return 1;
+ return NETDEV_TX_BUSY;
}
lp->saved_skb = skb;
if (length < ETH_ZLEN) {
if (skb_padto(skb, ETH_ZLEN)) {
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
length = ETH_ZLEN;
}
-
+
/*
** The MMU wants the number of pages to be the number of 256 bytes
** 'pages', minus 1 ( since a packet can't ever have 0 pages :) )
numPages = ((length & 0xfffe) + 6) / 256;
if (numPages > 7 ) {
- printk(CARDNAME": Far too big packet error. \n");
+ printk(CARDNAME": Far too big packet error.\n");
/* freeing the packet is a good thing here... but should
. any packets of this size get down here? */
dev_kfree_skb (skb);
lp->saved_skb = NULL;
/* this IS an error, but, i don't want the skb saved */
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/* either way, a packet is waiting now */
lp->packets_waiting++;
if ( !time_out ) {
/* oh well, wait until the chip finds memory later */
SMC_ENABLE_INT( IM_ALLOC_INT );
- PRINTK2((CARDNAME": memory allocation deferred. \n"));
+ PRINTK2((CARDNAME": memory allocation deferred.\n"));
/* it's deferred, but I'll handle it later */
- return 0;
+ return NETDEV_TX_OK;
}
/* or YES! I can send the packet now.. */
smc_hardware_send_packet(dev);
netif_wake_queue(dev);
- return 0;
+ return NETDEV_TX_OK;
}
/*
ioaddr = dev->base_addr;
if ( !skb ) {
- PRINTK((CARDNAME": In XMIT with no packet to send \n"));
+ PRINTK((CARDNAME": In XMIT with no packet to send\n"));
return;
}
length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
packet_no = inb( ioaddr + PNR_ARR + 1 );
if ( packet_no & 0x80 ) {
/* or isn't there? BAD CHIP! */
- printk(KERN_DEBUG CARDNAME": Memory allocation failed. \n");
+ printk(KERN_DEBUG CARDNAME": Memory allocation failed.\n");
dev_kfree_skb_any(skb);
lp->saved_skb = NULL;
netif_wake_queue(dev);
/* and let the chipset deal with it */
outw( MC_ENQUEUE , ioaddr + MMU_CMD );
- PRINTK2((CARDNAME": Sent packet of length %d \n",length));
+ PRINTK2((CARDNAME": Sent packet of length %d\n", length));
lp->saved_skb = NULL;
dev_kfree_skb_any (skb);
/* we can send another packet */
netif_wake_queue(dev);
-
- return;
}
/*-------------------------------------------------------------------------
irq = dev->irq;
}
- SET_MODULE_OWNER(dev);
-
if (io > 0x1ff) { /* Check a single specified location. */
err = smc_probe(dev, io);
} else if (io != 0) { /* Don't probe at all. */
. interrupt, so an auto-detect routine can detect it, and find the IRQ,
------------------------------------------------------------------------
*/
-int __init smc_findirq( int ioaddr )
+static int __init smc_findirq(int ioaddr)
{
#ifndef NO_AUTOPROBE
int timeout = 20;
#endif
}
+static const struct net_device_ops smc_netdev_ops = {
+ .ndo_open = smc_open,
+ .ndo_stop = smc_close,
+ .ndo_start_xmit = smc_wait_to_send_packet,
+ .ndo_tx_timeout = smc_timeout,
+ .ndo_set_multicast_list = smc_set_multicast_list,
+ .ndo_change_mtu = eth_change_mtu,
+ .ndo_set_mac_address = eth_mac_addr,
+ .ndo_validate_addr = eth_validate_addr,
+};
+
/*----------------------------------------------------------------------
. Function: smc_probe( int ioaddr )
.
SMC_SELECT_BANK(1);
base_address_register = inw( ioaddr + BASE );
if ( ioaddr != ( base_address_register >> 3 & 0x3E0 ) ) {
- printk(CARDNAME ": IOADDR %x doesn't match configuration (%x)."
+ printk(CARDNAME ": IOADDR %x doesn't match configuration (%x). "
"Probably not a SMC chip\n",
ioaddr, base_address_register >> 3 & 0x3E0 );
/* well, the base address register didn't match. Must not have
if ( !chip_ids[ ( revision_register >> 4 ) & 0xF ] ) {
/* I don't recognize this chip, so... */
printk(CARDNAME ": IO %x: Unrecognized revision register:"
- " %x, Contact author. \n", ioaddr, revision_register );
+ " %x, Contact author.\n", ioaddr, revision_register);
retval = -ENODEV;
goto err_out;
/*
. Print the Ethernet address
*/
- printk("ADDR: ");
- for (i = 0; i < 5; i++)
- printk("%2.2x:", dev->dev_addr[i] );
- printk("%2.2x \n", dev->dev_addr[5] );
-
- /* set the private data to zero by default */
- memset(dev->priv, 0, sizeof(struct smc_local));
+ printk("ADDR: %pM\n", dev->dev_addr);
/* Grab the IRQ */
- retval = request_irq(dev->irq, &smc_interrupt, 0, DRV_NAME, dev);
+ retval = request_irq(dev->irq, smc_interrupt, 0, DRV_NAME, dev);
if (retval) {
printk("%s: unable to get IRQ %d (irqval=%d).\n", DRV_NAME,
dev->irq, retval);
goto err_out;
}
- dev->open = smc_open;
- dev->stop = smc_close;
- dev->hard_start_xmit = smc_wait_to_send_packet;
- dev->tx_timeout = smc_timeout;
+ dev->netdev_ops = &smc_netdev_ops;
dev->watchdog_timeo = HZ/20;
- dev->get_stats = smc_query_statistics;
- dev->set_multicast_list = smc_set_multicast_list;
return 0;
int remainder;
int lines;
- printk("Packet of length %d \n", length );
+ printk("Packet of length %d\n", length);
lines = length / 16;
remainder = length % 16;
int i; /* used to set hw ethernet address */
/* clear out all the junk that was put here before... */
- memset(dev->priv, 0, sizeof(struct smc_local));
+ memset(netdev_priv(dev), 0, sizeof(struct smc_local));
/* reset the hardware */
address |= dev->dev_addr[ i ];
outw( address, ioaddr + ADDR0 + i );
}
-
+
netif_start_queue(dev);
return 0;
}
/* "kick" the adaptor */
smc_reset( dev->base_addr );
smc_enable( dev->base_addr );
- dev->trans_start = jiffies;
+ dev->trans_start = jiffies; /* prevent tx timeout */
/* clear anything saved */
- ((struct smc_local *)dev->priv)->saved_skb = NULL;
+ ((struct smc_local *)netdev_priv(dev))->saved_skb = NULL;
netif_wake_queue(dev);
}
*/
static void smc_rcv(struct net_device *dev)
{
- struct smc_local *lp = netdev_priv(dev);
int ioaddr = dev->base_addr;
int packet_number;
word status;
if ( packet_number & FP_RXEMPTY ) {
/* we got called , but nothing was on the FIFO */
- PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO. \n"));
+ PRINTK((CARDNAME ": WARNING: smc_rcv with nothing on FIFO.\n"));
/* don't need to restore anything */
return;
}
/* set multicast stats */
if ( status & RS_MULTICAST )
- lp->stats.multicast++;
+ dev->stats.multicast++;
skb = dev_alloc_skb( packet_length + 5);
if ( skb == NULL ) {
printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n");
- lp->stats.rx_dropped++;
+ dev->stats.rx_dropped++;
goto done;
}
skb_reserve( skb, 2 ); /* 16 bit alignment */
- skb->dev = dev;
data = skb_put( skb, packet_length);
#ifdef USE_32_BIT
to send the DWORDs or the bytes first, or some
mixture. A mixture might improve already slow PIO
performance */
- PRINTK3((" Reading %d dwords (and %d bytes) \n",
+ PRINTK3((" Reading %d dwords (and %d bytes)\n",
packet_length >> 2, packet_length & 3 ));
insl(ioaddr + DATA_1 , data, packet_length >> 2 );
/* read the left over bytes */
insb( ioaddr + DATA_1, data + (packet_length & 0xFFFFFC),
packet_length & 0x3 );
#else
- PRINTK3((" Reading %d words and %d byte(s) \n",
+ PRINTK3((" Reading %d words and %d byte(s)\n",
(packet_length >> 1 ), packet_length & 1 ));
insw(ioaddr + DATA_1 , data, packet_length >> 1);
if ( packet_length & 1 ) {
skb->protocol = eth_type_trans(skb, dev );
netif_rx(skb);
- dev->last_rx = jiffies;
- lp->stats.rx_packets++;
- lp->stats.rx_bytes += packet_length;
+ dev->stats.rx_packets++;
+ dev->stats.rx_bytes += packet_length;
} else {
/* error ... */
- lp->stats.rx_errors++;
+ dev->stats.rx_errors++;
- if ( status & RS_ALGNERR ) lp->stats.rx_frame_errors++;
+ if ( status & RS_ALGNERR ) dev->stats.rx_frame_errors++;
if ( status & (RS_TOOSHORT | RS_TOOLONG ) )
- lp->stats.rx_length_errors++;
- if ( status & RS_BADCRC) lp->stats.rx_crc_errors++;
+ dev->stats.rx_length_errors++;
+ if ( status & RS_BADCRC) dev->stats.rx_crc_errors++;
}
done:
outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER );
tx_status = inw( ioaddr + DATA_1 );
- PRINTK3((CARDNAME": TX DONE STATUS: %4x \n", tx_status ));
+ PRINTK3((CARDNAME": TX DONE STATUS: %4x\n", tx_status));
- lp->stats.tx_errors++;
- if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++;
+ dev->stats.tx_errors++;
+ if ( tx_status & TS_LOSTCAR ) dev->stats.tx_carrier_errors++;
if ( tx_status & TS_LATCOL ) {
printk(KERN_DEBUG CARDNAME
": Late collision occurred on last xmit.\n");
- lp->stats.tx_window_errors++;
+ dev->stats.tx_window_errors++;
}
#if 0
if ( tx_status & TS_16COL ) { ... }
#endif
if ( tx_status & TS_SUCCESS ) {
- printk(CARDNAME": Successful packet caused interrupt \n");
+ printk(CARDNAME": Successful packet caused interrupt\n");
}
/* re-enable transmit */
SMC_SELECT_BANK( 0 );
lp->packets_waiting--;
outb( saved_packet, ioaddr + PNR_ARR );
- return;
}
/*--------------------------------------------------------------------
.
---------------------------------------------------------------------*/
-static irqreturn_t smc_interrupt(int irq, void * dev_id, struct pt_regs * regs)
+static irqreturn_t smc_interrupt(int irq, void * dev_id)
{
struct net_device *dev = dev_id;
int ioaddr = dev->base_addr;
int handled = 0;
- PRINTK3((CARDNAME": SMC interrupt started \n"));
+ PRINTK3((CARDNAME": SMC interrupt started\n"));
saved_bank = inw( ioaddr + BANK_SELECT );
/* set a timeout value, so I don't stay here forever */
timeout = 4;
- PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x \n", mask ));
+ PRINTK2((KERN_WARNING CARDNAME ": MASK IS %x\n", mask));
do {
/* read the status flag, and mask it */
status = inb( ioaddr + INTERRUPT ) & mask;
handled = 1;
PRINTK3((KERN_WARNING CARDNAME
- ": Handling interrupt status %x \n", status ));
+ ": Handling interrupt status %x\n", status));
if (status & IM_RCV_INT) {
/* Got a packet(s). */
SMC_SELECT_BANK( 0 );
card_stats = inw( ioaddr + COUNTER );
/* single collisions */
- lp->stats.collisions += card_stats & 0xF;
+ dev->stats.collisions += card_stats & 0xF;
card_stats >>= 4;
/* multiple collisions */
- lp->stats.collisions += card_stats & 0xF;
+ dev->stats.collisions += card_stats & 0xF;
/* these are for when linux supports these statistics */
": TX_BUFFER_EMPTY handled\n"));
outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT );
mask &= ~IM_TX_EMPTY_INT;
- lp->stats.tx_packets += lp->packets_waiting;
+ dev->stats.tx_packets += lp->packets_waiting;
lp->packets_waiting = 0;
} else if (status & IM_ALLOC_INT ) {
PRINTK2((KERN_DEBUG CARDNAME
- ": Allocation interrupt \n"));
+ ": Allocation interrupt\n"));
/* clear this interrupt so it doesn't happen again */
mask &= ~IM_ALLOC_INT;
PRINTK2((CARDNAME": Handoff done successfully.\n"));
} else if (status & IM_RX_OVRN_INT ) {
- lp->stats.rx_errors++;
- lp->stats.rx_fifo_errors++;
+ dev->stats.rx_errors++;
+ dev->stats.rx_fifo_errors++;
outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT );
} else if (status & IM_EPH_INT ) {
- PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n"));
+ PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT\n"));
} else if (status & IM_ERCV_INT ) {
- PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n"));
+ PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT\n"));
outb( IM_ERCV_INT, ioaddr + INTERRUPT );
}
} while ( timeout -- );
SMC_SELECT_BANK( 2 );
outb( mask, ioaddr + INT_MASK );
- PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask ));
+ PRINTK3((KERN_WARNING CARDNAME ": MASK is now %x\n", mask));
outw( saved_pointer, ioaddr + POINTER );
SMC_SELECT_BANK( saved_bank );
return 0;
}
-/*------------------------------------------------------------
- . Get the current statistics.
- . This may be called with the card open or closed.
- .-------------------------------------------------------------*/
-static struct net_device_stats* smc_query_statistics(struct net_device *dev) {
- struct smc_local *lp = netdev_priv(dev);
-
- return &lp->stats;
-}
-
/*-----------------------------------------------------------
. smc_set_multicast_list
.
/* We just get all multicast packets even if we only want them
. from one source. This will be changed at some future
. point. */
- else if (dev->mc_count ) {
+ else if (!netdev_mc_empty(dev)) {
/* support hardware multicasting */
/* be sure I get rid of flags I might have set */
ioaddr + RCR );
/* NOTE: this has to set the bank, so make sure it is the
last thing called. The bank is set to zero at the top */
- smc_setmulticast( ioaddr, dev->mc_count, dev->mc_list );
+ smc_setmulticast(ioaddr, dev);
}
else {
outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL),
return 0;
}
-void cleanup_module(void)
+void __exit cleanup_module(void)
{
unregister_netdev(devSMC9194);
free_irq(devSMC9194->irq, devSMC9194);