--- zzzz-none-000/linux-2.4.17/drivers/net/smc9194.c 2001-10-17 04:56:29.000000000 +0000 +++ sangam-fb-322/linux-2.4.17/drivers/net/smc9194.c 2004-11-24 13:23:36.000000000 +0000 @@ -12,8 +12,8 @@ . AUI/TP selection ( mine has 10Base2/10BaseT select ) . . Arguments: - . io = for the base address - . irq = for the IRQ + . io = for the base address + . irq = for the IRQ . ifport = 0 for autodetect, 1 for TP, 2 for AUI ( or 10base2 ) . . author: @@ -51,11 +51,20 @@ . allocation . 08/20/00 Arnaldo Melo fix kfree(skb) in smc_hardware_send_packet . 12/15/00 Christian Jullien fix "Warning: kfree_skb on hard IRQ" + . 06/23/01 Russell King Separate out IO functions for different bus + . types. + . Use dev->name instead of CARDNAME for printk + . Add ethtool support, full duplex support + . Add LAN91C96 support. ----------------------------------------------------------------------------*/ +#define DRV_NAME "smc9194" +#define DRV_VERSION "0.15" + static const char version[] = - "smc9194.c:v0.14 12/15/00 by Erik Stahlman (erik@vt.edu)\n"; + DRV_NAME ".c:v" DRV_VERSION " 12/15/00 by Erik Stahlman (erik@vt.edu)\n"; +#include #include #include #include @@ -68,16 +77,28 @@ #include #include #include +#include #include -#include -#include #include +#include #include #include #include +#include +#include +#include +#include + +#if defined(CONFIG_ARCH_SA1100) || \ + defined(CONFIG_ARCH_COTULLA) +#include +#endif + #include "smc9194.h" + + /*------------------------------------------------------------------------ . . Configuration options, for the experienced user to change. @@ -94,6 +115,13 @@ #define USE_32_BIT 1 #endif +#if !defined(CONFIG_SA1100_GRAPHICSCLIENT) && \ + !defined(CONFIG_SA1100_PFS168) && \ + !defined(CONFIG_SA1100_FLEXANET) && \ + !defined(CONFIG_SA1100_GRAPHICSMASTER) && \ + !defined(CONFIG_ASSABET_NEPONSET) && \ + !defined(CONFIG_ARCH_LUBBOCK) && \ + !defined(CONFIG_ARCH_COTULLA_IDP) /* .the SMC9194 can be at any of the following port addresses. To change, .for a slightly different card, you can add it to the array. Keep in @@ -103,6 +131,7 @@ 0x200, 0x220, 0x240, 0x260, 0x280, 0x2A0, 0x2C0, 0x2E0, 0x300, 0x320, 0x340, 0x360, 0x380, 0x3A0, 0x3C0, 0x3E0, 0 }; +#endif /* . Wait time for memory to be free. This probably shouldn't be @@ -150,29 +179,27 @@ -------------------------------------------------------------------------*/ #define CARDNAME "SMC9194" +static const char *chip_ids[15] = { + NULL, + NULL, + NULL, + "SMC91C90/91C92", /* 3 */ + "SMC91C94/91C96", /* 4 */ + "SMC91C95", /* 5 */ + NULL, + "SMC91C100", /* 7 */ + "SMC91C100FD", /* 8 */ + NULL, + NULL, + NULL, + NULL, + NULL, + NULL +}; -/* 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. - */ - struct sk_buff * saved_skb; - - /* - . This keeps track of how many packets that I have - . sent out. When an TX_EMPTY interrupt comes, I know - . that all of these have been sent. - */ - int packets_waiting; +static const char * interfaces[2] = { + "TP", + "AUI" }; @@ -200,6 +227,11 @@ static int smc_open(struct net_device *dev); /* + . This handles the ethtool interface +*/ +static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd); + +/* . Our watchdog timed out. Called by the networking layer */ static void smc_timeout(struct net_device *dev); @@ -215,18 +247,18 @@ . 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); +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. + . Finally, a call to set promiscuous mode (for TCPDUMP and related + . programs) and multicast modes. */ static void smc_set_multicast_list(struct net_device *dev); /* . CRC compute */ -static int crc32( char * s, int length ); +static int crc32(char * s, int length); /*--------------------------------------------------------------- . @@ -242,12 +274,12 @@ . This is a separate procedure to handle the receipt of a packet, to . leave the interrupt code looking slightly cleaner */ -static inline void smc_rcv( struct net_device *dev ); +static inline void smc_rcv(struct net_device *dev); /* . This handles a TX interrupt, which is only called when an error . relating to a packet is sent. */ -static inline void smc_tx( struct net_device * dev ); +static inline void smc_tx(struct net_device * dev); /* ------------------------------------------------------------ @@ -263,39 +295,397 @@ */ static int smc_probe(struct net_device *dev, int ioaddr); -/* - . A rather simple routine to print out a packet for debugging purposes. -*/ -#if SMC_DEBUG > 2 -static void print_packet( byte *, int ); -#endif - -#define tx_done(dev) 1 - /* this is called to actually send the packet to the chip */ -static void smc_hardware_send_packet( struct net_device * dev ); +static void smc_hardware_send_packet(struct net_device * dev); /* Since I am not sure if I will have enough room in the chip's ram . 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 int 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 ); +static void smc_reset(struct net_device *dev); /* Enable Interrupts, Receive, and Transmit */ -static void smc_enable( int ioaddr ); +static void smc_enable(struct net_device *dev); /* this puts the device in an inactive state */ -static void smc_shutdown( int ioaddr ); +static void smc_shutdown(struct net_device *dev); /* This routine will find the IRQ of the driver if one is not . specified in the input to the device. */ -static int smc_findirq( int ioaddr ); +static int smc_findirq(struct net_device *dev); + +#if defined(CONFIG_ASSABET_NEPONSET) + +#undef SMC_IO_EXTENT +#define SMC_IO_EXTENT (16 << 2) + +/* + * These functions allow us to handle IO addressing as we wish - this + * ethernet controller can be connected to a variety of busses. Some + * busses do not support 16 bit or 32 bit transfers. --rmk + */ +static inline u8 smc_inb(u_int base, u_int reg) +{ + u_int port = base + reg * 4; + + return readb(port); +} + +static inline u16 smc_inw(u_int base, u_int reg) +{ + u_int port = base + reg * 4; + + return readb(port) | readb(port + 4) << 8; +} + +static inline void smc_ins(u_int base, u_int reg, u8 *data, u_int len) +{ + u_int port = base + reg * 4; + + insb(port, data, len); +} + +static inline void smc_outb(u8 val, u_int base, u_int reg) +{ + u_int port = base + reg * 4; + + writeb(val, port); +} + +static inline void smc_outw(u16 val, u_int base, u_int reg) +{ + u_int port = base + reg * 4; + + writeb(val, port); + writeb(val >> 8, port + 4); +} + +static inline void smc_outl(u32 val, u_int base, u_int reg) +{ + u_int port = base + reg * 4; + + writeb(val, port); + writeb(val >> 8, port + 4); + writeb(val >> 16, port + 8); + writeb(val >> 24, port + 12); +} + +static inline void smc_outs(u_int base, u_int reg, u8 *data, u_int len) +{ + u_int port = base + reg * 4; + + outsb(port, data, len & ~1); +} + +/*------------------------------------------------------------------------- + . I define some macros to make it easier to do somewhat common + . or slightly complicated, repeated tasks. + --------------------------------------------------------------------------*/ + +/* select a register bank, 0 to 3 */ + +#define SMC_SELECT_BANK(x) \ + { \ + smc_outb(x, ioaddr, BANK_SELECT); \ + } + +/* define a small delay for the reset */ +#define SMC_DELAY() \ + { \ + smc_inb(ioaddr, RCR); \ + smc_inb(ioaddr, RCR); \ + smc_inb(ioaddr, RCR); \ + } + +/* this enables an interrupt in the interrupt mask register */ +#define SMC_ENABLE_INT(x) \ + { \ + byte mask; \ + mask = smc_inb(ioaddr, INT_MASK); \ + mask |= (x); \ + smc_outb(mask, ioaddr, INT_MASK); \ + } + +/* this sets the absolutel interrupt mask */ +#define SMC_SET_INT(x) \ + { \ + smc_outb((x), ioaddr, INT_MASK); \ + } + +#elif defined(CONFIG_SA1100_GRAPHICSCLIENT) || \ + defined(CONFIG_SA1100_PFS168) || \ + defined(CONFIG_SA1100_FLEXANET) || \ + defined(CONFIG_SA1100_GRAPHICSMASTER) || \ + defined(CONFIG_ARCH_LUBBOCK) || \ + defined(CONFIG_ARCH_COTULLA_IDP) + +/* + * We can only do 16-bit reads and writes in the static memory space. + * Byte reads must read 16 bits and return the correct byte. + * Byte writes must do a read/modify/write. + */ + +/* The first two address lines aren't connected... */ +#undef SMC_IO_EXTENT +#define SMC_IO_EXTENT (16 << 2) + +static inline u8 smc_inb(u_int base, u_int reg) +{ + u_int port = base + (reg & ~1) * 4; + u_int res = readw(port); + if (reg & 1) + res >>= 8; + return res; +} + +static inline u16 smc_inw(u_int base, u_int reg) +{ + u_int port = base + reg * 4; + return readw(port); +} + +static inline void smc_ins(u_int base, u_int reg, u8 *data, u_int len) +{ + u_int port = base + reg * 4; + + insw(port, data, len>>1); + if (len & 1) + data[len-1] = readw(port); +} + +static inline void smc_outb(u8 val, u_int base, u_int reg) +{ + u_int port = base + (reg & ~1) * 4; + u_int res = readw(port); + if (reg & 1) { + res &= 0xff; + res |= val << 8; + } else { + res &= 0xff00; + res |= val; + } + writew(res, port); +} + +static inline void smc_outw(u16 val, u_int base, u_int reg) +{ + u_int port = base + reg * 4; + writew(val, port); +} + +static inline void smc_outl(u32 val, u_int base, u_int reg) +{ + u_int port = base + reg * 4; + writew(val, port); + writew(val >> 16, port + 8); +} + +static inline void smc_outs(u_int base, u_int reg, u8 *data, u_int len) +{ + u_int port = base + reg * 4; + outsw(port, data, len>>1); +} + +/*------------------------------------------------------------------------- + . I define some macros to make it easier to do somewhat common + . or slightly complicated, repeated tasks. + --------------------------------------------------------------------------*/ + +/* select a register bank, 0 to 3 */ + +#define SMC_SELECT_BANK(x) \ + { \ + smc_outw(x, ioaddr, BANK_SELECT); \ + } + +/* define a small delay for the reset */ +#define SMC_DELAY() \ + { \ + smc_inw(ioaddr, RCR); \ + smc_inw(ioaddr, RCR); \ + smc_inw(ioaddr, RCR); \ + } + +/* this enables an interrupt in the interrupt mask register */ +#define SMC_ENABLE_INT(x) \ + { \ + word mask; \ + mask = smc_inw(ioaddr, INTERRUPT); \ + mask |= (x) << 8; \ + smc_outw(mask, ioaddr, INT_MASK); \ + } + +/* this sets the absolutel interrupt mask */ +#define SMC_SET_INT(x) \ + { \ + smc_outw((x) << 8, ioaddr, INTERRUPT); \ + } + +#else /* Assume default is CONFIG_ISA */ /* - . Function: smc_reset( int ioaddr ) + * These functions allow us to handle IO addressing as we wish - this + * ethernet controller can be connected to a variety of busses. Some + * busses do not support 16 bit or 32 bit transfers. --rmk + */ +static inline u8 smc_inb(u_int base, u_int reg) +{ + return inb(base + reg); +} + +static inline u16 smc_inw(u_int base, u_int reg) +{ + return inw(base + reg); +} + +static inline void smc_ins(u_int base, u_int reg, u8 *data, u_int len) +{ + u_int port = base + reg; +#ifdef USE_32_BIT + /* QUESTION: Like in the TX routine, do I want + 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", + len >> 2, len & 3)); + insl(port, data, len >> 2); + /* read the left over bytes */ + insb(port, data + (len & ~3), len & 3); +#else + PRINTK3((" Reading %d words and %d byte(s) \n", + len >> 1, len & 1)); + insw(port, data, len >> 1); + if (len & 1) { + data += len & ~1; + *data = inb(port); + } +#endif +} + +static inline void smc_outb(u8 val, u_int base, u_int reg) +{ + outb(val, base + reg); +} + +static inline void smc_outw(u16 val, u_int base, u_int reg) +{ + outw(val, base + reg); +} + +static inline void smc_outl(u32 val, u_int base, u_int reg) +{ + u_int port = base + reg; +#ifdef USE_32_BIT + outl(val, port); +#else + outw(val, port); + outw(val >> 16, port); +#endif +} + +static inline void smc_outs(u_int base, u_int reg, u8 *data, u_int len) +{ + u_int port = base + reg; +#ifdef USE_32_BIT + if (len & 2) { + outsl(port, data, len >> 2); + outw(*((word *)(data + (len & ~3))), port); + } + else + outsl(port, data, len >> 2); +#else + outsw(port, data, len >> 1); +#endif +} + + +/*------------------------------------------------------------------------- + . I define some macros to make it easier to do somewhat common + . or slightly complicated, repeated tasks. + --------------------------------------------------------------------------*/ + +/* select a register bank, 0 to 3 */ + +#define SMC_SELECT_BANK(x) \ + { \ + smc_outw(x, ioaddr, BANK_SELECT); \ + } + +/* define a small delay for the reset */ +#define SMC_DELAY() \ + { \ + smc_inw(ioaddr, RCR); \ + smc_inw(ioaddr, RCR); \ + smc_inw(ioaddr, RCR); \ + } + +/* this enables an interrupt in the interrupt mask register */ +#define SMC_ENABLE_INT(x) \ + { \ + byte mask; \ + mask = smc_inb(ioaddr, INT_MASK); \ + mask |= (x); \ + smc_outb(mask, ioaddr, INT_MASK); \ + } + +/* this sets the absolutel interrupt mask */ +#define SMC_SET_INT(x) \ + { \ + smc_outw((x), INT_MASK); \ + } + +#endif /* Assume default is CONFIG_ISA */ + +/* + . A rather simple routine to print out a packet for debugging purposes. +*/ +#if SMC_DEBUG > 2 +static void print_packet(byte * buf, int length) +{ + int i; + int remainder; + int lines; + + printk("Packet of length %d \n", length); + lines = length / 16; + remainder = length % 16; + + for (i = 0; i < lines ; i ++) { + int cur; + + for (cur = 0; cur < 8; cur ++) { + byte a, b; + + a = *(buf ++); + b = *(buf ++); + printk("%02x%02x ", a, b); + } + printk("\n"); + } + for (i = 0; i < remainder/2 ; i++) { + byte a, b; + + a = *(buf ++); + b = *(buf ++); + printk("%02x%02x ", a, b); + } + if (remainder & 1) { + byte a; + + a = *buf++; + printk("%02x", a); + } + printk("\n"); +} +#else +#define print_packet(buf,len) do { } while (0) +#endif + +/* + . Function: smc_reset(struct net_device *dev) . Purpose: . This sets the SMC91xx chip to its normal state, hopefully from whatever . mess that any other DOS driver has put it in. @@ -311,36 +701,37 @@ . 5. clear all interrupts . */ -static void smc_reset( int ioaddr ) +static void smc_reset(struct net_device *dev) { + u_int ioaddr = dev->base_addr; + /* This resets the registers mostly to defaults, but doesn't affect EEPROM. That seems unnecessary */ - SMC_SELECT_BANK( 0 ); - outw( RCR_SOFTRESET, ioaddr + RCR ); + SMC_SELECT_BANK(0); + smc_outw(RCR_SOFTRESET, ioaddr, RCR); /* this should pause enough for the chip to be happy */ - SMC_DELAY( ); + SMC_DELAY(); /* Set the transmit and receive configuration registers to default values */ - outw( RCR_CLEAR, ioaddr + RCR ); - outw( TCR_CLEAR, ioaddr + TCR ); + smc_outw(RCR_CLEAR, ioaddr, RCR); + smc_outw(TCR_CLEAR, ioaddr, TCR); /* set the control register to automatically release successfully transmitted packets, to make the best use out of our limited memory */ - SMC_SELECT_BANK( 1 ); - outw( inw( ioaddr + CONTROL ) | CTL_AUTO_RELEASE , ioaddr + CONTROL ); + SMC_SELECT_BANK(1); + smc_outw(smc_inw(ioaddr, CONTROL) | CTL_AUTO_RELEASE, ioaddr, CONTROL); /* Reset the MMU */ - SMC_SELECT_BANK( 2 ); - outw( MC_RESET, ioaddr + MMU_CMD ); + SMC_SELECT_BANK(2); + smc_outw(MC_RESET, ioaddr, MMU_CMD); /* Note: It doesn't seem that waiting for the MMU busy is needed here, but this is a place where future chipsets _COULD_ break. Be wary of issuing another MMU command right after this */ - - outb( 0, ioaddr + INT_MASK ); + SMC_SET_INT(0); } /* @@ -351,20 +742,21 @@ . 2. Enable the receiver . 3. Enable interrupts */ -static void smc_enable( int ioaddr ) +static void smc_enable(struct net_device *dev) { - SMC_SELECT_BANK( 0 ); + u_int ioaddr = dev->base_addr; + SMC_SELECT_BANK(0); /* see the header file for options in TCR/RCR NORMAL*/ - outw( TCR_NORMAL, ioaddr + TCR ); - outw( RCR_NORMAL, ioaddr + RCR ); + smc_outw(TCR_NORMAL, ioaddr, TCR); + smc_outw(RCR_NORMAL, ioaddr, RCR); /* now, enable interrupts */ - SMC_SELECT_BANK( 2 ); - outb( SMC_INTERRUPT_MASK, ioaddr + INT_MASK ); + SMC_SELECT_BANK(2); + SMC_SET_INT(SMC_INTERRUPT_MASK); } /* - . Function: smc_shutdown + . Function: smc_shutdown(struct net_device *dev) . Purpose: closes down the SMC91xxx chip. . Method: . 1. zero the interrupt mask @@ -377,26 +769,28 @@ . the manual says that it will wake up in response to any I/O requests . in the register space. Empirical results do not show this working. */ -static void smc_shutdown( int ioaddr ) +static void smc_shutdown(struct net_device *dev) { + u_int ioaddr = dev->base_addr; + /* no more interrupts for me */ - SMC_SELECT_BANK( 2 ); - outb( 0, ioaddr + INT_MASK ); + SMC_SELECT_BANK(2); + SMC_SET_INT(0); /* and tell the card to stay away from that nasty outside world */ - SMC_SELECT_BANK( 0 ); - outb( RCR_CLEAR, ioaddr + RCR ); - outb( TCR_CLEAR, ioaddr + TCR ); + SMC_SELECT_BANK(0); + smc_outb(RCR_CLEAR, ioaddr, RCR); + smc_outb(TCR_CLEAR, ioaddr, TCR); #if 0 /* finally, shut the chip down */ - SMC_SELECT_BANK( 1 ); - outw( inw( ioaddr + CONTROL ), CTL_POWERDOWN, ioaddr + CONTROL ); + SMC_SELECT_BANK(1); + smc_outw(smc_inw(ioaddr, CONTROL), CTL_POWERDOWN, ioaddr, CONTROL); #endif } /* - . Function: smc_setmulticast( int ioaddr, int count, dev_mc_list * adds ) + . Function: smc_setmulticast(int ioaddr, int count, dev_mc_list * adds) . Purpose: . This sets the internal hardware table to filter out unwanted multicast . packets before they take up memory. @@ -413,30 +807,32 @@ */ -static void smc_setmulticast( int ioaddr, int count, struct dev_mc_list * addrs ) { +static void smc_setmulticast(struct net_device *dev, int count, struct dev_mc_list * addrs) +{ + u_int ioaddr = dev->base_addr; int i; - unsigned char multicast_table[ 8 ]; + unsigned char multicast_table[8]; struct dev_mc_list * cur_addr; /* 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 ) ); + memset(multicast_table, 0, sizeof(multicast_table)); cur_addr = addrs; - for ( i = 0; i < count ; i ++, cur_addr = cur_addr->next ) { + for (i = 0; i < count ; i ++, cur_addr = cur_addr->next) { int position; /* do we have a pointer here? */ - if ( !cur_addr ) + 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 (!(*cur_addr->dmi_addr & 1)) continue; /* only use the low order bits */ - position = crc32( cur_addr->dmi_addr, 6 ) & 0x3f; + position = crc32(cur_addr->dmi_addr, 6) & 0x3f; /* do some messy swapping to put the bit in the right spot */ multicast_table[invert3[position&7]] |= @@ -444,10 +840,10 @@ } /* now, the table can be loaded into the chipset */ - SMC_SELECT_BANK( 3 ); + SMC_SELECT_BANK(3); - for ( i = 0; i < 8 ; i++ ) { - outb( multicast_table[i], ioaddr + MULTICAST1 + i ); + for (i = 0; i < 8 ; i++) { + smc_outb(multicast_table[i], ioaddr, MULTICAST1 + i); } } @@ -455,7 +851,8 @@ Finds the CRC32 of a set of bytes. Again, from Peter Cammaert's code. */ -static int crc32( char * s, int length ) { +static int crc32(char * s, int length) +{ /* indices */ int perByte; int perBit; @@ -464,11 +861,11 @@ /* crc value - preinitialized to all 1's */ unsigned long crc_value = 0xffffffff; - for ( perByte = 0; perByte < length; perByte ++ ) { + for (perByte = 0; perByte < length; perByte ++) { unsigned char c; c = *(s++); - for ( perBit = 0; perBit < 8; perBit++ ) { + for (perBit = 0; perBit < 8; perBit++) { crc_value = (crc_value>>1)^ (((crc_value^c)&0x01)?poly:0); c >>= 1; @@ -479,7 +876,7 @@ /* - . Function: smc_wait_to_send_packet( struct sk_buff * skb, struct net_device * ) + . Function: smc_wait_to_send_packet(struct sk_buff * skb, struct net_device *) . Purpose: . Attempt to allocate memory for a packet, if chip-memory is not . available, then tell the card to generate an interrupt when it @@ -494,10 +891,10 @@ . 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 int smc_wait_to_send_packet(struct sk_buff * skb, struct net_device * dev) { struct smc_local *lp = (struct smc_local *)dev->priv; - unsigned short ioaddr = dev->base_addr; + u_int ioaddr = dev->base_addr; word length; unsigned short numPages; word time_out; @@ -506,28 +903,28 @@ /* Well, I want to send the packet.. but I don't know if I can send it right now... */ - if ( lp->saved_skb) { + if (lp->saved_skb) { /* THIS SHOULD NEVER HAPPEN. */ lp->stats.tx_aborted_errors++; - printk(CARDNAME": Bad Craziness - sent packet while busy.\n" ); + printk("%s: Bad Craziness - sent packet while busy.\n", + dev->name); return 1; } lp->saved_skb = skb; length = ETH_ZLEN < skb->len ? skb->len : 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 :) ) + ** 'pages', minus 1 (since a packet can't ever have 0 pages :)) ** ** Pkt size for allocating is data length +6 (for additional status words, ** length and ctl!) If odd size last byte is included in this header. */ - numPages = ((length & 0xfffe) + 6) / 256; + numPages = ((length & 0xfffe) + 6) / 256; - if (numPages > 7 ) { - printk(CARDNAME": Far too big packet error. \n"); + if (numPages > 7) { + printk("%s: Far too big packet error.\n", dev->name); /* freeing the packet is a good thing here... but should . any packets of this size get down here? */ dev_kfree_skb (skb); @@ -536,12 +933,13 @@ netif_wake_queue(dev); return 0; } + /* either way, a packet is waiting now */ lp->packets_waiting++; /* now, try to allocate the memory */ - SMC_SELECT_BANK( 2 ); - outw( MC_ALLOC | numPages, ioaddr + MMU_CMD ); + SMC_SELECT_BANK(2); + smc_outw(MC_ALLOC | numPages, ioaddr, MMU_CMD); /* . Performance Hack . @@ -558,21 +956,21 @@ do { word status; - status = inb( ioaddr + INTERRUPT ); - if ( status & IM_ALLOC_INT ) { + status = smc_inb(ioaddr, INTERRUPT); + if (status & IM_ALLOC_INT) { /* acknowledge the interrupt */ - outb( IM_ALLOC_INT, ioaddr + INTERRUPT ); - break; + smc_outb(IM_ALLOC_INT, ioaddr, INTERRUPT); + break; } - } while ( -- time_out ); + } while (-- time_out); - if ( !time_out ) { + if (!time_out) { /* oh well, wait until the chip finds memory later */ - SMC_ENABLE_INT( IM_ALLOC_INT ); - PRINTK2((CARDNAME": memory allocation deferred. \n")); + SMC_ENABLE_INT(IM_ALLOC_INT); + PRINTK2(("%s: memory allocation deferred.\n", dev->name)); /* it's deferred, but I'll handle it later */ - return 0; - } + return 0; + } /* or YES! I can send the packet now.. */ smc_hardware_send_packet(dev); netif_wake_queue(dev); @@ -580,46 +978,46 @@ } /* - . Function: smc_hardware_send_packet(struct net_device * ) + . Function: smc_hardware_send_packet(struct net_device *) . Purpose: . This sends the actual packet to the SMC9xxx chip. . . Algorithm: . First, see if a saved_skb is available. - . ( this should NOT be called if there is no 'saved_skb' + . (this should NOT be called if there is no 'saved_skb' . Now, find the packet number that the chip allocated . Point the data pointers at it in memory . Set the length word in the chip's memory . Dump the packet to chip memory - . Check if a last byte is needed ( odd length packet ) + . Check if a last byte is needed (odd length packet) . if so, set the control flag right . Tell the card to send it . Enable the transmit interrupt, so I know if it failed . Free the kernel data if I actually sent it. */ -static void smc_hardware_send_packet( struct net_device * dev ) +static void smc_hardware_send_packet(struct net_device *dev) { struct smc_local *lp = (struct smc_local *)dev->priv; - byte packet_no; - struct sk_buff * skb = lp->saved_skb; - word length; - unsigned short ioaddr; - byte * buf; - - ioaddr = dev->base_addr; + struct sk_buff *skb = lp->saved_skb; + word length, lastword; + u_int ioaddr = dev->base_addr; + byte packet_no; + byte *buf; - if ( !skb ) { - PRINTK((CARDNAME": In XMIT with no packet to send \n")); + if (!skb) { + PRINTK(("%s: In XMIT with no packet to send\n", dev->name)); return; } + length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; buf = skb->data; /* If I get here, I _know_ there is a packet slot waiting for me */ - packet_no = inb( ioaddr + PNR_ARR + 1 ); - if ( packet_no & 0x80 ) { + packet_no = smc_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 "%s: Memory allocation failed.\n", + dev->name); dev_kfree_skb_any(skb); lp->saved_skb = NULL; netif_wake_queue(dev); @@ -627,26 +1025,19 @@ } /* we have a packet address, so tell the card to use it */ - outb( packet_no, ioaddr + PNR_ARR ); + smc_outb(packet_no, ioaddr, PNR_ARR); /* point to the beginning of the packet */ - outw( PTR_AUTOINC , ioaddr + POINTER ); + smc_outw(PTR_AUTOINC, ioaddr, POINTER); - PRINTK3((CARDNAME": Trying to xmit packet of length %x\n", length )); -#if SMC_DEBUG > 2 - print_packet( buf, length ); -#endif + PRINTK3(("%s: Trying to xmit packet of length %x\n", + dev->name, length)); - /* send the packet length ( +6 for status, length and ctl byte ) - and the status word ( set to zeros ) */ -#ifdef USE_32_BIT - outl( (length +6 ) << 16 , ioaddr + DATA_1 ); -#else - outw( 0, ioaddr + DATA_1 ); - /* send the packet length ( +6 for status words, length, and ctl*/ - outb( (length+6) & 0xFF,ioaddr + DATA_1 ); - outb( (length+6) >> 8 , ioaddr + DATA_1 ); -#endif + print_packet(buf, length); + + /* send the packet length (+6 for status, length and ctl byte) + and the status word (set to zeros) */ + smc_outl((length + 6) << 16, ioaddr, DATA_1); /* send the actual data . I _think_ it's faster to send the longs first, and then @@ -655,32 +1046,22 @@ . a good idea to check which is optimal? But that could take . almost as much time as is saved? */ -#ifdef USE_32_BIT - if ( length & 0x2 ) { - outsl(ioaddr + DATA_1, buf, length >> 2 ); - outw( *((word *)(buf + (length & 0xFFFFFFFC))),ioaddr +DATA_1); - } - else - outsl(ioaddr + DATA_1, buf, length >> 2 ); -#else - outsw(ioaddr + DATA_1 , buf, (length ) >> 1); -#endif - /* Send the last byte, if there is one. */ + smc_outs(ioaddr, DATA_1, buf, length); - if ( (length & 1) == 0 ) { - outw( 0, ioaddr + DATA_1 ); - } else { - outb( buf[length -1 ], ioaddr + DATA_1 ); - outb( 0x20, ioaddr + DATA_1); - } + /* Send the last byte, if there is one. */ + if ((length & 1) == 0) + lastword = 0; + else + lastword = 0x2000 | buf[length - 1]; + smc_outw(lastword, ioaddr, DATA_1); /* enable the interrupts */ - SMC_ENABLE_INT( (IM_TX_INT | IM_TX_EMPTY_INT) ); + SMC_ENABLE_INT(IM_TX_INT | IM_TX_EMPTY_INT); /* and let the chipset deal with it */ - outw( MC_ENQUEUE , ioaddr + MMU_CMD ); + smc_outw(MC_ENQUEUE, ioaddr, MMU_CMD); - PRINTK2((CARDNAME": Sent packet of length %d \n",length)); + PRINTK2(("%s: Sent packet of length %d\n", dev->name, length)); lp->saved_skb = NULL; dev_kfree_skb_any (skb); @@ -695,7 +1076,7 @@ /*------------------------------------------------------------------------- | - | smc_init( struct net_device * dev ) + | smc_init(struct net_device * dev) | Input parameters: | dev->base_addr == 0, try to find all possible locations | dev->base_addr == 1, return failure code @@ -710,6 +1091,176 @@ */ int __init smc_init(struct net_device *dev) { + int ret = -ENODEV; + +#if defined(CONFIG_ASSABET_NEPONSET) + + if (machine_is_assabet() && machine_has_neponset()) { + unsigned int *addr; + unsigned char ecor; + unsigned long flags; + + NCR_0 |= NCR_ENET_OSC_EN; + dev->irq = IRQ_NEPONSET_SMC9196; + + /* + * Map the attribute space. This is overkill, but clean. + */ + addr = ioremap(0x18000000 + (1 << 25), 64 * 1024 * 4); + if (!addr) + return -ENOMEM; + + /* + * Reset the device. We must disable IRQs around this. + */ + local_irq_save(flags); + ecor = readl(addr + ECOR) & ~ECOR_RESET; + writel(ecor | ECOR_RESET, addr + ECOR); + udelay(100); + + /* + * The device will ignore all writes to the enable bit while + * reset is asserted, even if the reset bit is cleared in the + * same write. Must clear reset first, then enable the device. + */ + writel(ecor, addr + ECOR); + writel(ecor | ECOR_ENABLE, addr + ECOR); + + /* + * Force byte mode. + */ + writel(readl(addr + ECSR) | ECSR_IOIS8, addr + ECSR); + local_irq_restore(flags); + + iounmap(addr); + + /* + * Wait for the chip to wake up. + */ + mdelay(1); + + /* + * Map the real registers. + */ + addr = ioremap(0x18000000, 8 * 1024); + if (!addr) + return -ENOMEM; + + ret = smc_probe(dev, (int)addr); + if (ret) + iounmap(addr); + } + +#elif defined(CONFIG_SA1100_GRAPHICSCLIENT) || \ + defined(CONFIG_SA1100_GRAPHICSMASTER) + + if (machine_is_graphicsclient() || machine_is_graphicsmaster()) { + int base_addr = ADS_ETHERNET; + + // Max recovery timing + MSC1 &= ~0xFFFF; + MSC1 |= 0x8649; + + ret = smc_probe(dev, base_addr); + } + +#elif defined(CONFIG_SA1100_FLEXANET) + + if (machine_is_flexanet()) { + volatile unsigned *attaddr; + int ioaddr; + unsigned flags; + + /* Get the I/O and attribute base addresses + * declared in flexanet.h */ + ioaddr = FHH_ETH_IOBASE; + attaddr = (unsigned *) FHH_ETH_MMBASE; + + /* Ethernet IRQ setup (GPIO is input, falling edge) */ + GPDR &= ~(GPIO_ETH_IRQ); + set_GPIO_IRQ_edge( GPIO_ETH_IRQ, GPIO_FALLING_EDGE ); + dev->irq = IRQ_GPIO_ETH; + + local_irq_save(flags); + + /* first reset, then enable the device. Sequence is critical */ + attaddr[ECOR] |= ECOR_RESET; + udelay(100); + attaddr[ECOR] &= ~ECOR_RESET; + attaddr[ECOR] |= ECOR_ENABLE; + + local_irq_restore(flags); + + /* force 16-bit mode */ + attaddr[ECSR] &= ~ECSR_IOIS8; + + ret = smc_probe(dev, ioaddr); + } + +#elif defined(CONFIG_ARCH_LUBBOCK) || \ + defined(CONFIG_ARCH_COTULLA_IDP) + + if (machine_is_lubbock() || machine_is_cotulla_idp()) { + int ioaddr = ETH_BASE; + volatile unsigned *attaddr = (unsigned *) (ETH_BASE + 0x100000); + unsigned flags; + + /* first reset, then enable the device. Sequence is critical */ + local_irq_save(flags); + attaddr[ECOR] |= ECOR_RESET; + udelay(100); + attaddr[ECOR] &= ~ECOR_RESET; + attaddr[ECOR] |= ECOR_ENABLE; + + /* force 16-bit mode */ + attaddr[ECSR] &= ~ECSR_IOIS8; + mdelay(1); + local_irq_restore(flags); + + dev->irq = LUBBOCK_ETH_IRQ; + ret = smc_probe(dev, ioaddr); + } + +#elif defined(CONFIG_SA1100_PFS168) + + if (machine_is_pfs168()) { + volatile u_int * ioaddr; + u_long flags; + + /* First, enable access to the SMC91C96 via some undocumented + * black magic register bit flipping. + */ + ioaddr = (volatile u_int *)ioremap(0x1a020000, 8*1024); + if (!ioaddr) + return -ENOMEM; + ((u_char *)(ioaddr))[0] = 0x41; + udelay(100); + ((u_char *)(ioaddr))[8] = 0x00; + udelay(100); + iounmap(ioaddr); /* don't need this anymore... */ + + /* + * The PFS-168 uses GPIO26 for the SMC9196 interrupts. + * So set up GPIO26 for edge triggered interrupts now. + */ + /* Set GPIO 26 to input */ + GPDR &= ~(GPIO_GPIO(26)); + /* Set transition detect */ + set_GPIO_IRQ_edge( GPIO_GPIO(26), GPIO_RISING_EDGE ); + + ioaddr = (volatile u_int *)ioremap(0x18000000, 8*1024); + if (!ioaddr) + return -ENOMEM; + + dev->irq = IRQ_GPIO26; + + ret = smc_probe(dev, (int)ioaddr); + if (ret) + iounmap(ioaddr); + } + +#else /* Assume default is CONFIG_ISA */ + int i; int base_addr = dev->base_addr; @@ -727,7 +1278,9 @@ return 0; /* couldn't find anything */ - return -ENODEV; +#endif /* Assume default is CONFIG_ISA */ + + return ret; } /*---------------------------------------------------------------------- @@ -737,10 +1290,11 @@ . interrupt, so an auto-detect routine can detect it, and find the IRQ, ------------------------------------------------------------------------ */ -int __init smc_findirq( int ioaddr ) +int __init smc_findirq(struct net_device *dev) { int timeout = 20; unsigned long cookie; + u_int ioaddr = dev->base_addr; /* I have to do a STI() here, because this is called from @@ -756,26 +1310,25 @@ * when done. */ - + /* enable ALLOCation interrupts ONLY. */ SMC_SELECT_BANK(2); - /* enable ALLOCation interrupts ONLY */ - outb( IM_ALLOC_INT, ioaddr + INT_MASK ); + SMC_SET_INT(IM_ALLOC_INT); /* . Allocate 512 bytes of memory. Note that the chip was just . reset so all the memory is available */ - outw( MC_ALLOC | 1, ioaddr + MMU_CMD ); + smc_outw(MC_ALLOC | 1, ioaddr, MMU_CMD); /* . Wait until positive that the interrupt has been generated */ - while ( timeout ) { + while (timeout) { byte int_status; - int_status = inb( ioaddr + INTERRUPT ); + int_status = smc_inb(ioaddr, INTERRUPT); - if ( int_status & IM_ALLOC_INT ) + if (int_status & IM_ALLOC_INT) break; /* got the interrupt */ timeout--; } @@ -794,7 +1347,7 @@ SMC_DELAY(); /* and disable all interrupts again */ - outb( 0, ioaddr + INT_MASK ); + SMC_SET_INT(0); /* clear hardware interrupts again, because that's how it was when I was called... */ @@ -804,8 +1357,95 @@ return probe_irq_off(cookie); } +static int __init smc_probe_chip(struct net_device *dev, int ioaddr) +{ + unsigned int temp; + + /* First, see if the high byte is 0x33 */ + temp = smc_inw(ioaddr, BANK_SELECT); + if ((temp & 0xFF00) != 0x3300) + return -ENODEV; + + /* The above MIGHT indicate a device, but I need to write to further + test this. */ + smc_outw(0, ioaddr, BANK_SELECT); + temp = smc_inw(ioaddr, BANK_SELECT); + if ((temp & 0xFF00) != 0x3300) + return -ENODEV; + +#if !defined(CONFIG_SA1100_GRAPHICSCLIENT) && \ + !defined(CONFIG_SA1100_PFS168) && \ + !defined(CONFIG_SA1100_FLEXANET) && \ + !defined(CONFIG_SA1100_GRAPHICSMASTER) && \ + !defined(CONFIG_ASSABET_NEPONSET) && \ + !defined(CONFIG_ARCH_LUBBOCK) && \ + !defined(CONFIG_ARCH_COTULLA_IDP) + + /* well, we've already written once, so hopefully another time won't + hurt. This time, I need to switch the bank register to bank 1, + so I can access the base address register */ + SMC_SELECT_BANK(1); + temp = smc_inw(ioaddr, BASE); + if (ioaddr != (temp >> 3 & 0x3E0)) { + printk("%s: IOADDR %x doesn't match configuration (%x)." + "Probably not a SMC chip\n", dev->name, + ioaddr, (base_address_register >> 3) & 0x3E0); + /* well, the base address register didn't match. Must not have + been a SMC chip after all. */ + return -ENODEV; + } + +#endif + + return 0; +} + +/* + . If dev->irq is 0, then the device has to be banged on to see + . what the IRQ is. + . + . This banging doesn't always detect the IRQ, for unknown reasons. + . a workaround is to reset the chip and try again. + . + . Interestingly, the DOS packet driver *SETS* the IRQ on the card to + . be what is requested on the command line. I don't do that, mostly + . because the card that I have uses a non-standard method of accessing + . the IRQs, and because this _should_ work in most configurations. + . + . Specifying an IRQ is done with the assumption that the user knows + . what (s)he is doing. No checking is done!!!! + . +*/ +static int __init smc_probe_irq(struct net_device *dev) +{ + if (dev->irq < 2) { + int trials; + + trials = 3; + while (trials--) { + dev->irq = smc_findirq(dev); + if (dev->irq) + break; + /* kick the card and try again */ + smc_reset(dev); + } + } + if (dev->irq == 0) { + printk("%s: Couldn't autodetect your IRQ. Use irq=xx.\n", + dev->name); + return -ENODEV; + } + + /* + * Some machines (eg, PCs) need to cannonicalize their IRQs. + */ + dev->irq = irq_cannonicalize(dev->irq); + + return 0; +} + /*---------------------------------------------------------------------- - . Function: smc_probe( int ioaddr ) + . Function: smc_probe(struct net_device *dev, int ioaddr) . . Purpose: . Tests to see if a given ioaddr points to an SMC9xxx chip. @@ -835,16 +1475,14 @@ */ static int __init smc_probe(struct net_device *dev, int ioaddr) { + struct smc_local *smc; int i, memory, retval; static unsigned version_printed; - unsigned int bank; const char *version_string; - const char *if_string; /* registers */ word revision_register; - word base_address_register; word configuration_register; word memory_info_register; word memory_cfg_register; @@ -853,44 +1491,24 @@ if (!request_region(ioaddr, SMC_IO_EXTENT, dev->name)) return -EBUSY; - /* First, see if the high byte is 0x33 */ - bank = inw( ioaddr + BANK_SELECT ); - if ( (bank & 0xFF00) != 0x3300 ) { - retval = -ENODEV; - goto err_out; - } - /* The above MIGHT indicate a device, but I need to write to further - test this. */ - outw( 0x0, ioaddr + BANK_SELECT ); - bank = inw( ioaddr + BANK_SELECT ); - if ( (bank & 0xFF00 ) != 0x3300 ) { - retval = -ENODEV; - goto err_out; - } - /* well, we've already written once, so hopefully another time won't - hurt. This time, I need to switch the bank register to bank 1, - so I can access the base address register */ - 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)." - "Probably not a SMC chip\n", - ioaddr, base_address_register >> 3 & 0x3E0 ); - /* well, the base address register didn't match. Must not have - been a SMC chip after all. */ - retval = -ENODEV; + /* + * Do the basic probes. + */ + retval = smc_probe_chip(dev, ioaddr); + if (retval) goto err_out; - } /* check if the revision register is something that I recognize. These might need to be added to later, as future revisions could be added. */ SMC_SELECT_BANK(3); - revision_register = inw( ioaddr + REVISION ); - if ( !chip_ids[ ( revision_register >> 4 ) & 0xF ] ) { + revision_register = smc_inw(ioaddr, REVISION); + version_string = chip_ids[(revision_register >> 4) & 15]; + if (!version_string) { /* I don't recognize this chip, so... */ - printk(CARDNAME ": IO %x: Unrecognized revision register:" - " %x, Contact author. \n", ioaddr, revision_register ); + printk("%s: IO %x: unrecognized revision register: %x, " + "contact author.\n", dev->name, ioaddr, + revision_register); retval = -ENODEV; goto err_out; @@ -901,138 +1519,134 @@ against the hardware address, or do some other tests. */ if (version_printed++ == 0) - printk("%s", version); + printk(KERN_INFO "%s", version); /* fill in some of the fields */ dev->base_addr = ioaddr; /* - . Get the MAC address ( bank 1, regs 4 - 9 ) + . Get the MAC address (bank 1, regs 4 - 9) */ - SMC_SELECT_BANK( 1 ); - for ( i = 0; i < 6; i += 2 ) { + SMC_SELECT_BANK(1); + for (i = 0; i < 6; i += 2) { word address; - address = inw( ioaddr + ADDR0 + i ); - dev->dev_addr[ i + 1] = address >> 8; - dev->dev_addr[ i ] = address & 0xFF; + address = smc_inw(ioaddr, ADDR0 + i); + dev->dev_addr[i + 1] = address >> 8; + dev->dev_addr[i] = address & 0xFF; + } + + if (dev->dev_addr[0] != 0) { + /* + * Possibly a multicast MAC which is not good. + * Some people apparently defined it backwards in the eprom. + */ + for (i = 0; i < 3; i++) { + unsigned char tmp = dev->dev_addr[i]; + dev->dev_addr[i] = dev->dev_addr[5-i]; + dev->dev_addr[5-i] = tmp; + } } + if (!is_valid_ether_addr(dev->dev_addr)) + printk("%s: Invalid ethernet MAC address. Please set using " + "ifconfig\n", dev->name); + /* get the memory information */ - SMC_SELECT_BANK( 0 ); - memory_info_register = inw( ioaddr + MIR ); - memory_cfg_register = inw( ioaddr + MCR ); - memory = ( memory_cfg_register >> 9 ) & 0x7; /* multiplier */ - memory *= 256 * ( memory_info_register & 0xFF ); + SMC_SELECT_BANK(0); + memory_info_register = smc_inw(ioaddr, MIR); + memory_cfg_register = smc_inw(ioaddr, MCR); + memory = (memory_cfg_register >> 9) & 0x7; /* multiplier */ + memory *= 256 * (memory_info_register & 0xFF); + + /* now, reset the chip, and put it into a known state */ + smc_reset(dev); /* - Now, I want to find out more about the chip. This is sort of - redundant, but it's cleaner to have it in both, rather than having - one VERY long probe procedure. - */ - SMC_SELECT_BANK(3); - revision_register = inw( ioaddr + REVISION ); - version_string = chip_ids[ ( revision_register >> 4 ) & 0xF ]; - if ( !version_string ) { - /* I shouldn't get here because this call was done before.... */ - retval = -ENODEV; + * Ok, now that we have everything in a + * sane state, probe for the interrupt. + */ + retval = smc_probe_irq(dev); + if (retval) goto err_out; - } - /* is it using AUI or 10BaseT ? */ - if ( dev->if_port == 0 ) { - SMC_SELECT_BANK(1); - configuration_register = inw( ioaddr + CONFIG ); - if ( configuration_register & CFG_AUI_SELECT ) - dev->if_port = 2; - else - dev->if_port = 1; + /* Initialize the private structure. */ + if (dev->priv == NULL) { + dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL); + if (dev->priv == NULL) { + retval = -ENOMEM; + goto err_out; + } } - if_string = interfaces[ dev->if_port - 1 ]; - /* now, reset the chip, and put it into a known state */ - smc_reset( ioaddr ); + smc = dev->priv; + + /* set the private data to zero by default */ + memset(smc, 0, sizeof(struct smc_local)); /* - . If dev->irq is 0, then the device has to be banged on to see - . what the IRQ is. - . - . This banging doesn't always detect the IRQ, for unknown reasons. - . a workaround is to reset the chip and try again. - . - . Interestingly, the DOS packet driver *SETS* the IRQ on the card to - . be what is requested on the command line. I don't do that, mostly - . because the card that I have uses a non-standard method of accessing - . the IRQs, and because this _should_ work in most configurations. - . - . Specifying an IRQ is done with the assumption that the user knows - . what (s)he is doing. No checking is done!!!! - . - */ - if ( dev->irq < 2 ) { - int trials; + * Get the interface characteristics. + * is it using AUI or 10BaseT ? + */ + switch (dev->if_port) { + case IF_PORT_10BASET: + smc->port = PORT_TP; + break; + + case IF_PORT_AUI: + smc->port = PORT_AUI; + break; - trials = 3; - while ( trials-- ) { - dev->irq = smc_findirq( ioaddr ); - if ( dev->irq ) - break; - /* kick the card and try again */ - smc_reset( ioaddr ); + default: + SMC_SELECT_BANK(1); + configuration_register = smc_inw(ioaddr, CONFIG); + if (configuration_register & CFG_AUI_SELECT) { + dev->if_port = IF_PORT_AUI; + smc->port = PORT_AUI; + } else { + dev->if_port = IF_PORT_10BASET; + smc->port = PORT_TP; } - } - if (dev->irq == 0 ) { - printk(CARDNAME": Couldn't autodetect your IRQ. Use irq=xx.\n"); - retval = -ENODEV; - goto err_out; + break; } - /* now, print out the card info, in a short format.. */ + /* all interfaces are half-duplex by default */ + smc->duplex = DUPLEX_HALF; - printk("%s: %s(r:%d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name, - version_string, revision_register & 0xF, ioaddr, dev->irq, - if_string, memory ); + /* now, print out the card info, in a short format.. */ + printk("%s: %s (rev %d) at %#3x IRQ:%d INTF:%s MEM:%db ", dev->name, + version_string, revision_register & 15, ioaddr, dev->irq, + interfaces[smc->port], memory); /* . 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] ); - - - /* Initialize the private structure. */ - if (dev->priv == NULL) { - dev->priv = kmalloc(sizeof(struct smc_local), GFP_KERNEL); - if (dev->priv == NULL) { - retval = -ENOMEM; - goto err_out; - } - } - /* set the private data to zero by default */ - memset(dev->priv, 0, sizeof(struct smc_local)); + printk("%2.2x:", dev->dev_addr[i]); + printk("%2.2x\n", dev->dev_addr[5]); /* Fill in the fields of the device structure with ethernet values. */ ether_setup(dev); /* Grab the IRQ */ - retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); - if (retval) { + retval = request_irq(dev->irq, &smc_interrupt, 0, dev->name, dev); + if (retval) { printk("%s: unable to get IRQ %d (irqval=%d).\n", dev->name, dev->irq, retval); kfree(dev->priv); dev->priv = NULL; - goto err_out; - } + 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->watchdog_timeo = HZ/20; - dev->get_stats = smc_query_statistics; - dev->set_multicast_list = smc_set_multicast_list; + dev->open = smc_open; + dev->stop = smc_close; + dev->hard_start_xmit = smc_wait_to_send_packet; + dev->tx_timeout = smc_timeout; + dev->watchdog_timeo = HZ/20; + dev->get_stats = smc_query_statistics; + dev->set_multicast_list = smc_set_multicast_list; + dev->do_ioctl = smc_ioctl; return 0; @@ -1041,42 +1655,43 @@ return retval; } -#if SMC_DEBUG > 2 -static void print_packet( byte * buf, int length ) +/* + * This is responsible for setting the chip appropriately + * for the interface type. This should only be called while + * the interface is up and running. + */ +static void smc_set_port(struct net_device *dev) { -#if 0 - int i; - int remainder; - int lines; - - printk("Packet of length %d \n", length ); - lines = length / 16; - remainder = length % 16; + struct smc_local *smc = dev->priv; + u_int ioaddr = dev->base_addr; + u_int val; - for ( i = 0; i < lines ; i ++ ) { - int cur; - - for ( cur = 0; cur < 8; cur ++ ) { - byte a, b; - - a = *(buf ++ ); - b = *(buf ++ ); - printk("%02x%02x ", a, b ); - } - printk("\n"); + SMC_SELECT_BANK(1); + val = smc_inw(ioaddr, CONFIG); + switch (smc->port) { + case PORT_TP: + val &= ~CFG_AUI_SELECT; + break; + + case PORT_AUI: + val |= CFG_AUI_SELECT; + break; } - for ( i = 0; i < remainder/2 ; i++ ) { - byte a, b; + smc_outw(val, ioaddr, CONFIG); - a = *(buf ++ ); - b = *(buf ++ ); - printk("%02x%02x ", a, b ); + SMC_SELECT_BANK(0); + val = smc_inw(ioaddr, TCR); + switch (smc->duplex) { + case DUPLEX_HALF: + val &= ~TCR_FDSE; + break; + + case DUPLEX_FULL: + val |= TCR_FDSE; + break; } - printk("\n"); -#endif + smc_outw(val, ioaddr, TCR); } -#endif - /* * Open and Initialize the board @@ -1086,48 +1701,141 @@ */ static int smc_open(struct net_device *dev) { - int ioaddr = dev->base_addr; + struct smc_local *smc = dev->priv; + u_int ioaddr = dev->base_addr; + int i; - int i; /* used to set hw ethernet address */ + /* + * Check that the address is valid. If its not, refuse + * to bring the device up. The user must specify an + * address using ifconfig eth0 hw ether xx:xx:xx:xx:xx:xx + */ + if (!is_valid_ether_addr(dev->dev_addr)) + return -EINVAL; /* clear out all the junk that was put here before... */ - memset(dev->priv, 0, sizeof(struct smc_local)); + smc->saved_skb = NULL; + smc->packets_waiting = 0; /* reset the hardware */ - - smc_reset( ioaddr ); - smc_enable( ioaddr ); + smc_reset(dev); + smc_enable(dev); /* Select which interface to use */ - - SMC_SELECT_BANK( 1 ); - if ( dev->if_port == 1 ) { - outw( inw( ioaddr + CONFIG ) & ~CFG_AUI_SELECT, - ioaddr + CONFIG ); - } - else if ( dev->if_port == 2 ) { - outw( inw( ioaddr + CONFIG ) | CFG_AUI_SELECT, - ioaddr + CONFIG ); - } + smc_set_port(dev); /* - According to Becker, I have to set the hardware address + According to Becker, I have to set the hardware address at this point, because the (l)user can set it with an ioctl. Easily done... */ - SMC_SELECT_BANK( 1 ); - for ( i = 0; i < 6; i += 2 ) { + SMC_SELECT_BANK(1); + for (i = 0; i < 6; i += 2) { word address; - address = dev->dev_addr[ i + 1 ] << 8 ; - address |= dev->dev_addr[ i ]; - outw( address, ioaddr + ADDR0 + i ); + address = dev->dev_addr[i + 1] << 8 ; + address |= dev->dev_addr[i]; + smc_outw(address, ioaddr, ADDR0 + i); } netif_start_queue(dev); return 0; } +/* + * This is our template. Fill the rest in at run-time + */ +static const struct ethtool_cmd ecmd_template = { + supported: SUPPORTED_10baseT_Half | + SUPPORTED_10baseT_Full | + SUPPORTED_TP | + SUPPORTED_AUI, + speed: SPEED_10, + autoneg: AUTONEG_DISABLE, + maxtxpkt: 1, + maxrxpkt: 1, + transceiver: XCVR_INTERNAL, +}; + +static int smc_ioctl(struct net_device *dev, struct ifreq *rq, int cmd) +{ + struct smc_local *smc = dev->priv; + u32 etcmd; + int ret = -EINVAL; + + if (cmd != SIOCETHTOOL) + return -EOPNOTSUPP; + + if (get_user(etcmd, (u32 *)rq->ifr_data)) + return -EFAULT; + + switch (etcmd) { + case ETHTOOL_GSET: { + struct ethtool_cmd ecmd = ecmd_template; + + ecmd.cmd = etcmd; + ecmd.port = smc->port; + ecmd.duplex = smc->duplex; + + ret = copy_to_user(rq->ifr_data, &ecmd, sizeof(ecmd)) + ? -EFAULT : 0; + break; + } + + case ETHTOOL_SSET: { + struct ethtool_cmd ecmd; + + ret = -EPERM; + if (!capable(CAP_NET_ADMIN)) + break; + + ret = -EFAULT; + if (copy_from_user(&ecmd, rq->ifr_data, sizeof(ecmd))) + break; + + /* + * Sanity-check the arguments. + */ + ret = -EINVAL; + if (ecmd.autoneg != AUTONEG_DISABLE) + break; + if (ecmd.speed != SPEED_10) + break; + if (ecmd.duplex != DUPLEX_HALF && ecmd.duplex != DUPLEX_FULL) + break; + if (ecmd.port != PORT_TP && ecmd.port != PORT_AUI) + break; + + smc->port = ecmd.port; + smc->duplex = ecmd.duplex; + + if (netif_running(dev)) + smc_set_port(dev); + + ret = 0; + break; + } + + case ETHTOOL_GDRVINFO: { + struct ethtool_drvinfo edrv; + + memset(&edrv, 0, sizeof(edrv)); + + edrv.cmd = etcmd; + strcpy(edrv.driver, DRV_NAME); + strcpy(edrv.version, DRV_VERSION); + sprintf(edrv.bus_info, "ISA:%8.8lx:%d", + dev->base_addr, dev->irq); + + ret = copy_to_user(rq->ifr_data, &edrv, sizeof(edrv)) + ? -EFAULT : 0; + break; + } + } + + return ret; +} + /*-------------------------------------------------------- . Called by the kernel to send a packet out into the void . of the net. This routine is largely based on @@ -1139,12 +1847,10 @@ { /* If we get here, some higher level has decided we are broken. There should really be a "kick me" function call instead. */ - printk(KERN_WARNING CARDNAME": transmit timed out, %s?\n", - tx_done(dev) ? "IRQ conflict" : - "network cable problem"); + printk(KERN_WARNING "%s: transmit timed out\n", dev->name); /* "kick" the adaptor */ - smc_reset( dev->base_addr ); - smc_enable( dev->base_addr ); + smc_reset(dev); + smc_enable(dev); dev->trans_start = jiffies; /* clear anything saved */ ((struct smc_local *)dev->priv)->saved_skb = NULL; @@ -1164,10 +1870,10 @@ . ---------------------------------------------------------------------*/ -static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) +static void smc_interrupt(int irq, void * dev_id, struct pt_regs * regs) { struct net_device *dev = dev_id; - int ioaddr = dev->base_addr; + u_int ioaddr = dev->base_addr; struct smc_local *lp = (struct smc_local *)dev->priv; byte status; @@ -1180,45 +1886,45 @@ - PRINTK3((CARDNAME": SMC interrupt started \n")); + PRINTK3(("%s: SMC interrupt started\n", dev->name)); - saved_bank = inw( ioaddr + BANK_SELECT ); + saved_bank = smc_inw(ioaddr, BANK_SELECT); SMC_SELECT_BANK(2); - saved_pointer = inw( ioaddr + POINTER ); + saved_pointer = smc_inw(ioaddr, POINTER); - mask = inb( ioaddr + INT_MASK ); + mask = smc_inb(ioaddr, INT_MASK); /* clear all interrupts */ - outb( 0, ioaddr + INT_MASK ); + SMC_SET_INT(0); /* 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 "%s: MASK IS %x\n", dev->name, mask)); do { /* read the status flag, and mask it */ - status = inb( ioaddr + INTERRUPT ) & mask; - if (!status ) + status = smc_inb(ioaddr, INTERRUPT) & mask; + if (!status) break; - PRINTK3((KERN_WARNING CARDNAME - ": Handling interrupt status %x \n", status )); + PRINTK3((KERN_WARNING "%s: handling interrupt status %x\n", + dev->name, status)); if (status & IM_RCV_INT) { /* Got a packet(s). */ - PRINTK2((KERN_WARNING CARDNAME - ": Receive Interrupt\n")); + PRINTK2((KERN_WARNING "%s: receive interrupt\n", + dev->name)); smc_rcv(dev); - } else if (status & IM_TX_INT ) { - PRINTK2((KERN_WARNING CARDNAME - ": TX ERROR handled\n")); + } else if (status & IM_TX_INT) { + PRINTK2((KERN_WARNING "%s: TX ERROR handled\n", + dev->name)); smc_tx(dev); - outb(IM_TX_INT, ioaddr + INTERRUPT ); - } else if (status & IM_TX_EMPTY_INT ) { + smc_outb(IM_TX_INT, ioaddr, INTERRUPT); + } else if (status & IM_TX_EMPTY_INT) { /* update stats */ - SMC_SELECT_BANK( 0 ); - card_stats = inw( ioaddr + COUNTER ); + SMC_SELECT_BANK(0); + card_stats = smc_inw(ioaddr, COUNTER); /* single collisions */ lp->stats.collisions += card_stats & 0xF; card_stats >>= 4; @@ -1227,60 +1933,63 @@ /* these are for when linux supports these statistics */ - SMC_SELECT_BANK( 2 ); - PRINTK2((KERN_WARNING CARDNAME - ": TX_BUFFER_EMPTY handled\n")); - outb( IM_TX_EMPTY_INT, ioaddr + INTERRUPT ); + SMC_SELECT_BANK(2); + PRINTK2((KERN_WARNING "%s: TX_BUFFER_EMPTY handled\n", + dev->name)); + smc_outb(IM_TX_EMPTY_INT, ioaddr, INTERRUPT); mask &= ~IM_TX_EMPTY_INT; lp->stats.tx_packets += lp->packets_waiting; lp->packets_waiting = 0; - } else if (status & IM_ALLOC_INT ) { - PRINTK2((KERN_DEBUG CARDNAME - ": Allocation interrupt \n")); + } else if (status & IM_ALLOC_INT) { + PRINTK2((KERN_DEBUG "%s: Allocation interrupt\n", + dev->name)); /* clear this interrupt so it doesn't happen again */ mask &= ~IM_ALLOC_INT; - smc_hardware_send_packet( dev ); + smc_hardware_send_packet(dev); /* enable xmit interrupts based on this */ - mask |= ( IM_TX_EMPTY_INT | IM_TX_INT ); + mask |= (IM_TX_EMPTY_INT | IM_TX_INT); /* and let the card send more packets to me */ netif_wake_queue(dev); - PRINTK2((CARDNAME": Handoff done successfully.\n")); - } else if (status & IM_RX_OVRN_INT ) { + PRINTK2(("%s: Handoff done successfully.\n", + dev->name)); + } else if (status & IM_RX_OVRN_INT) { lp->stats.rx_errors++; lp->stats.rx_fifo_errors++; - outb( IM_RX_OVRN_INT, ioaddr + INTERRUPT ); - } else if (status & IM_EPH_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: EPH INTERRUPT \n")); - } else if (status & IM_ERCV_INT ) { - PRINTK((CARDNAME ": UNSUPPORTED: ERCV INTERRUPT \n")); - outb( IM_ERCV_INT, ioaddr + INTERRUPT ); + smc_outb(IM_RX_OVRN_INT, ioaddr, INTERRUPT); + } else if (status & IM_EPH_INT) { + PRINTK(("%s: UNSUPPORTED: EPH INTERRUPT\n", + dev->name)); + } else if (status & IM_ERCV_INT) { + PRINTK(("%s: UNSUPPORTED: ERCV INTERRUPT\n", + dev->name)); + smc_outb(IM_ERCV_INT, ioaddr, INTERRUPT); } - } while ( timeout -- ); + } while (timeout --); /* restore state register */ - SMC_SELECT_BANK( 2 ); - outb( mask, ioaddr + INT_MASK ); + SMC_SELECT_BANK(2); + SMC_SET_INT(mask); - PRINTK3(( KERN_WARNING CARDNAME ": MASK is now %x \n", mask )); - outw( saved_pointer, ioaddr + POINTER ); + PRINTK3((KERN_WARNING "%s: MASK is now %x\n", dev->name, mask)); + smc_outw(saved_pointer, ioaddr, POINTER); - SMC_SELECT_BANK( saved_bank ); + SMC_SELECT_BANK(saved_bank); - PRINTK3((CARDNAME ": Interrupt done\n")); + PRINTK3(("%s: Interrupt done\n", dev->name)); return; } /*------------------------------------------------------------- . - . smc_rcv - receive a packet from the card + . smc_rcv - receive a packet from the card . - . There is ( at least ) a packet waiting to be read from + . There is (at least) a packet waiting to be read from . chip-memory. . . o Read the status @@ -1291,55 +2000,57 @@ static void smc_rcv(struct net_device *dev) { struct smc_local *lp = (struct smc_local *)dev->priv; - int ioaddr = dev->base_addr; + u_int ioaddr = dev->base_addr; int packet_number; word status; word packet_length; /* assume bank 2 */ - packet_number = inw( ioaddr + FIFO_PORTS ); + packet_number = smc_inw(ioaddr, FIFO_PORTS); - if ( packet_number & FP_RXEMPTY ) { + 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(("%s: WARNING: smc_rcv with nothing on FIFO.\n", + dev->name)); /* don't need to restore anything */ return; } /* start reading from the start of the packet */ - outw( PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr + POINTER ); + smc_outw(PTR_READ | PTR_RCV | PTR_AUTOINC, ioaddr, POINTER); /* First two words are status and packet_length */ - status = inw( ioaddr + DATA_1 ); - packet_length = inw( ioaddr + DATA_1 ); + status = smc_inw(ioaddr, DATA_1); + packet_length = smc_inw(ioaddr, DATA_1); packet_length &= 0x07ff; /* mask off top bits */ - PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length )); + PRINTK2(("RCV: STATUS %4x LENGTH %4x\n", status, packet_length)); /* . the packet length contains 3 extra words : . status, length, and an extra word with an odd byte . */ packet_length -= 6; - if ( !(status & RS_ERRORS ) ){ + if (!(status & RS_ERRORS)){ /* do stuff to make a new packet */ struct sk_buff * skb; byte * data; /* read one extra byte */ - if ( status & RS_ODDFRAME ) + if (status & RS_ODDFRAME) packet_length++; /* set multicast stats */ - if ( status & RS_MULTICAST ) + if (status & RS_MULTICAST) lp->stats.multicast++; - skb = dev_alloc_skb( packet_length + 5); + skb = dev_alloc_skb(packet_length + 5); - if ( skb == NULL ) { - printk(KERN_NOTICE CARDNAME ": Low memory, packet dropped.\n"); + if (skb == NULL) { + printk(KERN_NOTICE "%s: Low memory, packet dropped.\n", + dev->name); lp->stats.rx_dropped++; goto done; } @@ -1349,36 +2060,15 @@ ! in the worse case */ - skb_reserve( skb, 2 ); /* 16 bit alignment */ + skb_reserve(skb, 2); /* 16 bit alignment */ skb->dev = dev; - data = skb_put( skb, packet_length); + data = skb_put(skb, packet_length); -#ifdef USE_32_BIT - /* QUESTION: Like in the TX routine, do I want - 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", - 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", - (packet_length >> 1 ), packet_length & 1 )); - insw(ioaddr + DATA_1 , data, packet_length >> 1); - if ( packet_length & 1 ) { - data += packet_length & ~1; - *(data++) = inb( ioaddr + DATA_1 ); - } -#endif -#if SMC_DEBUG > 2 - print_packet( data, packet_length ); -#endif + smc_ins(ioaddr, DATA_1, data, packet_length); + print_packet(data, packet_length); - skb->protocol = eth_type_trans(skb, dev ); + skb->protocol = eth_type_trans(skb, dev); netif_rx(skb); dev->last_rx = jiffies; lp->stats.rx_packets++; @@ -1387,15 +2077,17 @@ /* error ... */ lp->stats.rx_errors++; - if ( status & RS_ALGNERR ) lp->stats.rx_frame_errors++; - if ( status & (RS_TOOSHORT | RS_TOOLONG ) ) + if (status & RS_ALGNERR) + lp->stats.rx_frame_errors++; + if (status & (RS_TOOSHORT | RS_TOOLONG)) lp->stats.rx_length_errors++; - if ( status & RS_BADCRC) lp->stats.rx_crc_errors++; + if (status & RS_BADCRC) + lp->stats.rx_crc_errors++; } done: /* error or good, tell the card to get rid of this packet */ - outw( MC_RELEASE, ioaddr + MMU_CMD ); + smc_outw(MC_RELEASE, ioaddr, MMU_CMD); } @@ -1408,62 +2100,64 @@ . Algorithm: . Save pointer and packet no . Get the packet no from the top of the queue - . check if it's valid ( if not, is this an error??? ) + . check if it's valid (if not, is this an error???) . read the status word . record the error - . ( resend? Not really, since we don't want old packets around ) + . (resend? Not really, since we don't want old packets around) . Restore saved values ************************************************************************/ -static void smc_tx( struct net_device * dev ) +static void smc_tx(struct net_device * dev) { - int ioaddr = dev->base_addr; + u_int ioaddr = dev->base_addr; struct smc_local *lp = (struct smc_local *)dev->priv; byte saved_packet; byte packet_no; word tx_status; - /* assume bank 2 */ + /* assume bank 2 */ - saved_packet = inb( ioaddr + PNR_ARR ); - packet_no = inw( ioaddr + FIFO_PORTS ); + saved_packet = smc_inb(ioaddr, PNR_ARR); + packet_no = smc_inw(ioaddr, FIFO_PORTS); packet_no &= 0x7F; /* select this as the packet to read from */ - outb( packet_no, ioaddr + PNR_ARR ); + smc_outb(packet_no, ioaddr, PNR_ARR); /* read the first word from this packet */ - outw( PTR_AUTOINC | PTR_READ, ioaddr + POINTER ); + smc_outw(PTR_AUTOINC | PTR_READ, ioaddr, POINTER); - tx_status = inw( ioaddr + DATA_1 ); - PRINTK3((CARDNAME": TX DONE STATUS: %4x \n", tx_status )); + tx_status = smc_inw(ioaddr, DATA_1); + PRINTK3(("%s: TX DONE STATUS: %4x\n", dev->name, tx_status)); lp->stats.tx_errors++; - if ( tx_status & TS_LOSTCAR ) lp->stats.tx_carrier_errors++; - if ( tx_status & TS_LATCOL ) { - printk(KERN_DEBUG CARDNAME - ": Late collision occurred on last xmit.\n"); + if (tx_status & TS_LOSTCAR) + lp->stats.tx_carrier_errors++; + if (tx_status & TS_LATCOL) { + printk(KERN_DEBUG "%s: Late collision occurred on " + "last xmit.\n", dev->name); lp->stats.tx_window_errors++; } #if 0 - if ( tx_status & TS_16COL ) { ... } + if (tx_status & TS_16COL) { ... } #endif - if ( tx_status & TS_SUCCESS ) { - printk(CARDNAME": Successful packet caused interrupt \n"); + if (tx_status & TS_SUCCESS) { + printk("%s: Successful packet caused interrupt\n", + dev->name); } /* re-enable transmit */ - SMC_SELECT_BANK( 0 ); - outw( inw( ioaddr + TCR ) | TCR_ENABLE, ioaddr + TCR ); + SMC_SELECT_BANK(0); + smc_outw(smc_inw(ioaddr, TCR) | TCR_ENABLE, ioaddr, TCR); /* kill the packet */ - SMC_SELECT_BANK( 2 ); - outw( MC_FREEPKT, ioaddr + MMU_CMD ); + SMC_SELECT_BANK(2); + smc_outw(MC_FREEPKT, ioaddr, MMU_CMD); /* one less packet waiting for me */ lp->packets_waiting--; - outb( saved_packet, ioaddr + PNR_ARR ); + smc_outb(saved_packet, ioaddr, PNR_ARR); return; } @@ -1479,7 +2173,7 @@ { netif_stop_queue(dev); /* clear everything */ - smc_shutdown( dev->base_addr ); + smc_shutdown(dev); /* Update the statistics here. */ return 0; @@ -1500,16 +2194,16 @@ . . This routine will, depending on the values passed to it, . either make it accept multicast packets, go into - . promiscuous mode ( for TCPDUMP and cousins ) or accept + . promiscuous mode (for TCPDUMP and cousins) or accept . a select set of multicast packets */ static void smc_set_multicast_list(struct net_device *dev) { - short ioaddr = dev->base_addr; + u_int ioaddr = dev->base_addr; SMC_SELECT_BANK(0); - if ( dev->flags & IFF_PROMISC ) - outw( inw(ioaddr + RCR ) | RCR_PROMISC, ioaddr + RCR ); + if (dev->flags & IFF_PROMISC) + smc_outw(smc_inw(ioaddr, RCR) | RCR_PROMISC, ioaddr, RCR); /* BUG? I never disable promiscuous mode if multicasting was turned on. Now, I turn off promiscuous mode, but I don't do anything to multicasting @@ -1521,34 +2215,34 @@ checked before the table is */ else if (dev->flags & IFF_ALLMULTI) - outw( inw(ioaddr + RCR ) | RCR_ALMUL, ioaddr + RCR ); + smc_outw(smc_inw(ioaddr, RCR) | RCR_ALMUL, ioaddr, RCR); /* 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 (dev->mc_count) { /* support hardware multicasting */ /* be sure I get rid of flags I might have set */ - outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), - ioaddr + RCR ); + smc_outw(smc_inw(ioaddr, RCR) & ~(RCR_PROMISC | RCR_ALMUL), + 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(dev, dev->mc_count, dev->mc_list); } - else { - outw( inw( ioaddr + RCR ) & ~(RCR_PROMISC | RCR_ALMUL), - ioaddr + RCR ); + else { + smc_outw(smc_inw(ioaddr, RCR) & ~(RCR_PROMISC | RCR_ALMUL), + ioaddr, RCR); /* since I'm disabling all multicast entirely, I need to clear the multicast list */ - SMC_SELECT_BANK( 3 ); - outw( 0, ioaddr + MULTICAST1 ); - outw( 0, ioaddr + MULTICAST2 ); - outw( 0, ioaddr + MULTICAST3 ); - outw( 0, ioaddr + MULTICAST4 ); + SMC_SELECT_BANK(3); + smc_outw(0, ioaddr, MULTICAST1); + smc_outw(0, ioaddr, MULTICAST2); + smc_outw(0, ioaddr, MULTICAST3); + smc_outw(0, ioaddr, MULTICAST4); } } @@ -1569,21 +2263,26 @@ int init_module(void) { - int result; - if (io == 0) - printk(KERN_WARNING - CARDNAME": You shouldn't use auto-probing with insmod!\n" ); + printk(KERN_WARNING CARDNAME + ": You shouldn't use auto-probing with insmod!\n"); + + /* + * Note: dev->if_port has changed to be 2.4 compliant. + * We keep the ifport insmod parameter the same though. + */ + switch (ifport) { + case 1: devSMC9194.if_port = IF_PORT_10BASET; break; + case 2: devSMC9194.if_port = IF_PORT_AUI; break; + default: devSMC9194.if_port = 0; break; + } /* copy the parameters from insmod into the device structure */ devSMC9194.base_addr = io; devSMC9194.irq = irq; - devSMC9194.if_port = ifport; - devSMC9194.init = smc_init; - if ((result = register_netdev(&devSMC9194)) != 0) - return result; + devSMC9194.init = smc_init; - return 0; + return register_netdev(&devSMC9194); } void cleanup_module(void)