convert aruba to the new structure
[openwrt/svn-archive/archive.git] / target / linux / aruba-2.6 / files / drivers / net / rc32434_eth.c
diff --git a/target/linux/aruba-2.6/files/drivers/net/rc32434_eth.c b/target/linux/aruba-2.6/files/drivers/net/rc32434_eth.c
new file mode 100644 (file)
index 0000000..0acb8f9
--- /dev/null
@@ -0,0 +1,1273 @@
+/**************************************************************************
+ *
+ *  BRIEF MODULE DESCRIPTION
+ *     Driver for the IDT RC32434 on-chip ethernet controller.
+ *
+ *  Copyright 2004 IDT Inc. (rischelp@idt.com)
+ *         
+ *  This program is free software; you can redistribute  it and/or modify it
+ *  under  the terms of  the GNU General  Public License as published by the
+ *  Free Software Foundation;  either version 2 of the  License, or (at your
+ *  option) any later version.
+ *
+ *  THIS  SOFTWARE  IS PROVIDED   ``AS  IS'' AND   ANY  EXPRESS OR IMPLIED
+ *  WARRANTIES,   INCLUDING, BUT NOT  LIMITED  TO, THE IMPLIED WARRANTIES OF
+ *  MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN
+ *  NO  EVENT  SHALL   THE AUTHOR  BE    LIABLE FOR ANY   DIRECT, INDIRECT,
+ *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ *  NOT LIMITED   TO, PROCUREMENT OF  SUBSTITUTE GOODS  OR SERVICES; LOSS OF
+ *  USE, DATA,  OR PROFITS; OR  BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ *  ANY THEORY OF LIABILITY, WHETHER IN  CONTRACT, STRICT LIABILITY, OR TORT
+ *  (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ *  THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *  You should have received a copy of the  GNU General Public License along
+ *  with this program; if not, write  to the Free Software Foundation, Inc.,
+ *  675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ **************************************************************************
+ * May 2004 rkt, neb
+ *
+ * Based on the driver developed by B. Maruthanayakam, H. Kou and others.
+ *
+ * Aug 2004 Sadik
+ *
+ * Added NAPI
+ *
+ **************************************************************************
+ */
+
+#include <linux/autoconf.h>
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/sched.h>
+#include <linux/ctype.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/init.h>
+#include <linux/ioport.h>
+#include <linux/proc_fs.h>
+#include <linux/in.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/delay.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/errno.h>
+#include <asm/bootinfo.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/pgtable.h>
+#include <asm/segment.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+
+#include "rc32434_eth.h"
+
+#define DRIVER_VERSION "(mar2904)"
+
+#define DRIVER_NAME "rc32434 Ethernet driver. " DRIVER_VERSION
+
+
+#define STATION_ADDRESS_HIGH(dev) (((dev)->dev_addr[0] << 8) | \
+                                  ((dev)->dev_addr[1]))
+#define STATION_ADDRESS_LOW(dev)  (((dev)->dev_addr[2] << 24) | \
+                                  ((dev)->dev_addr[3] << 16) | \
+                                  ((dev)->dev_addr[4] << 8)  | \
+                                  ((dev)->dev_addr[5]))
+
+#define MII_CLOCK 1250000                              /* no more than 2.5MHz */
+static char mac0[18] = "08:00:06:05:40:01"; 
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,5,52)
+module_param_string(mac0, mac0, 18, 0);
+#else
+MODULE_PARM(mac0, "c18");
+#endif
+MODULE_PARM_DESC(mac0, "MAC address for RC32434 ethernet0");
+
+static struct rc32434_if_t {
+       char *name;
+       struct net_device *dev;
+       char* mac_str;
+       int weight;
+       u32 iobase;
+       u32 rxdmabase;
+       u32 txdmabase;
+       int rx_dma_irq;
+       int tx_dma_irq;
+       int rx_ovr_irq;
+       int tx_und_irq;                 
+} rc32434_iflist[] = 
+{
+       {
+               "rc32434_eth0",      NULL,       mac0, 
+               64,
+               ETH0_PhysicalAddress,
+               ETH0_RX_DMA_ADDR,
+               ETH0_TX_DMA_ADDR,
+               ETH0_DMA_RX_IRQ,
+               ETH0_DMA_TX_IRQ,
+               ETH0_RX_OVR_IRQ,
+               ETH0_TX_UND_IRQ
+       }
+};
+
+
+static int parse_mac_addr(struct net_device *dev, char* macstr)
+{
+       int i, j;
+       unsigned char result, value;
+       
+       for (i=0; i<6; i++) {
+               result = 0;
+               if (i != 5 && *(macstr+2) != ':') {
+                       ERR("invalid mac address format: %d %c\n",
+                           i, *(macstr+2));
+                       return -EINVAL;
+               }                               
+               for (j=0; j<2; j++) {
+                       if (isxdigit(*macstr) && (value = isdigit(*macstr) ? *macstr-'0' : 
+                                                 toupper(*macstr)-'A'+10) < 16) {
+                               result = result*16 + value;
+                               macstr++;
+                       } 
+                       else {
+                               ERR("invalid mac address "
+                                   "character: %c\n", *macstr);
+                               return -EINVAL;
+                       }
+               }
+               
+               macstr++; 
+               dev->dev_addr[i] = result;
+       }
+       
+       return 0;
+}
+
+
+
+static inline void rc32434_abort_tx(struct net_device *dev)
+{
+       struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
+       rc32434_abort_dma(dev, lp->tx_dma_regs);
+       
+}
+
+static inline void rc32434_abort_rx(struct net_device *dev)
+{
+       struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
+       rc32434_abort_dma(dev, lp->rx_dma_regs);
+       
+}
+
+static inline void rc32434_start_tx(struct rc32434_local *lp,  volatile DMAD_t td)
+{
+       rc32434_start_dma(lp->tx_dma_regs, CPHYSADDR(td));
+}
+
+static inline void rc32434_start_rx(struct rc32434_local *lp, volatile DMAD_t rd)
+{
+       rc32434_start_dma(lp->rx_dma_regs, CPHYSADDR(rd));
+}
+
+static inline void rc32434_chain_tx(struct rc32434_local *lp, volatile DMAD_t td)
+{
+       rc32434_chain_dma(lp->tx_dma_regs, CPHYSADDR(td));
+}
+
+static inline void rc32434_chain_rx(struct rc32434_local *lp, volatile DMAD_t rd)
+{
+       rc32434_chain_dma(lp->rx_dma_regs, CPHYSADDR(rd));
+}
+
+#ifdef RC32434_PROC_DEBUG
+static int rc32434_read_proc(char *buf, char **start, off_t fpos,
+                            int length, int *eof, void *data)
+{
+       struct net_device *dev = (struct net_device *)data;
+       struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
+       int len = 0;
+       
+       /* print out header */
+       len += sprintf(buf + len, "\n\tRC32434 Ethernet Debug\n\n");
+       len += sprintf (buf + len,
+                       "DMA halt count      = %10d, DMA run count = %10d\n",
+                       lp->dma_halt_cnt, lp->dma_run_cnt);
+       
+       if (fpos >= len) {
+               *start = buf;
+               *eof = 1;
+               return 0;
+       }
+       *start = buf + fpos;
+       
+       if ((len -= fpos) > length) 
+               return length;  
+       *eof = 1;
+       
+       return len;
+       
+}
+#endif
+
+
+/*
+ * Restart the RC32434 ethernet controller. 
+ */
+static int rc32434_restart(struct net_device *dev)
+{
+       struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
+       
+       /*
+        * Disable interrupts
+        */
+       disable_irq(lp->rx_irq);
+       disable_irq(lp->tx_irq);
+#ifdef RC32434_REVISION
+       disable_irq(lp->ovr_irq);
+#endif 
+       disable_irq(lp->und_irq);
+       
+       /* Mask F E bit in Tx DMA */
+       rc32434_writel(rc32434_readl(&lp->tx_dma_regs->dmasm) | DMASM_f_m | DMASM_e_m, &lp->tx_dma_regs->dmasm);
+       /* Mask D H E bit in Rx DMA */
+       rc32434_writel(rc32434_readl(&lp->rx_dma_regs->dmasm) | DMASM_d_m | DMASM_h_m | DMASM_e_m, &lp->rx_dma_regs->dmasm);
+       
+       rc32434_init(dev);
+       rc32434_multicast_list(dev);
+       
+       enable_irq(lp->und_irq);
+#ifdef RC32434_REVISION
+       enable_irq(lp->ovr_irq);
+#endif
+       enable_irq(lp->tx_irq);
+       enable_irq(lp->rx_irq);
+       
+       return 0;
+}
+
+int rc32434_init_module(void)
+{
+#ifdef CONFIG_MACH_ARUBA
+       if (mips_machtype != MACH_ARUBA_AP70)
+               return 1;
+#endif
+
+       printk(KERN_INFO DRIVER_NAME " \n");
+       return rc32434_probe(0);
+}
+
+static int rc32434_probe(int port_num)
+{
+       struct rc32434_if_t *bif = &rc32434_iflist[port_num];
+       struct rc32434_local *lp = NULL;
+       struct net_device *dev = NULL;
+       int i, retval,err;
+       
+       dev = alloc_etherdev(sizeof(struct rc32434_local));
+       if(!dev) {
+               ERR("rc32434_eth: alloc_etherdev failed\n");
+               return -1;
+       }
+       
+       SET_MODULE_OWNER(dev);
+       bif->dev = dev;
+
+#ifdef CONFIG_MACH_ARUBA
+       {
+               extern char * getenv(char *e);
+               memcpy(bif->mac_str, getenv("ethaddr"), 17);
+       }
+#endif
+       
+       printk("mac: %s\n", bif->mac_str);
+       if ((retval = parse_mac_addr(dev, bif->mac_str))) {
+               ERR("MAC address parse failed\n");
+               free_netdev(dev);
+               return -1;
+       }
+       
+       
+       /* Initialize the device structure. */
+       if (dev->priv == NULL) {
+               lp = (struct rc32434_local *)kmalloc(sizeof(*lp), GFP_KERNEL);
+               memset(lp, 0, sizeof(struct rc32434_local));
+       } 
+       else {
+               lp = (struct rc32434_local *)dev->priv;
+       }
+       
+       lp->rx_irq = bif->rx_dma_irq;
+       lp->tx_irq = bif->tx_dma_irq;
+       lp->ovr_irq = bif->rx_ovr_irq;
+       lp->und_irq = bif->tx_und_irq;
+       
+       lp->eth_regs = ioremap_nocache(bif->iobase, sizeof(*lp->eth_regs));
+
+       if (!lp->eth_regs) {
+               ERR("Can't remap eth registers\n");
+               retval = -ENXIO;
+               goto probe_err_out;
+       }
+       
+       lp->rx_dma_regs = ioremap_nocache(bif->rxdmabase, sizeof(struct DMA_Chan_s));
+       
+       if (!lp->rx_dma_regs) {
+               ERR("Can't remap Rx DMA registers\n");
+               retval = -ENXIO;
+               goto probe_err_out;
+       }
+       lp->tx_dma_regs = ioremap_nocache(bif->txdmabase,sizeof(struct DMA_Chan_s));
+       
+       if (!lp->tx_dma_regs) {
+               ERR("Can't remap Tx DMA registers\n");
+               retval = -ENXIO;
+               goto probe_err_out;
+       }
+       
+#ifdef RC32434_PROC_DEBUG
+       lp->ps = create_proc_read_entry (bif->name, 0, proc_net,
+                                        rc32434_read_proc, dev);
+#endif
+       
+       lp->td_ring =   (DMAD_t)kmalloc(TD_RING_SIZE + RD_RING_SIZE, GFP_KERNEL);
+       if (!lp->td_ring) {
+               ERR("Can't allocate descriptors\n");
+               retval = -ENOMEM;
+               goto probe_err_out;
+       }
+       
+       dma_cache_inv((unsigned long)(lp->td_ring), TD_RING_SIZE + RD_RING_SIZE);
+       
+       /* now convert TD_RING pointer to KSEG1 */
+       lp->td_ring = (DMAD_t )KSEG1ADDR(lp->td_ring);
+       lp->rd_ring = &lp->td_ring[RC32434_NUM_TDS];
+       
+       
+       spin_lock_init(&lp->lock);
+       
+       dev->base_addr = bif->iobase;
+       /* just use the rx dma irq */
+       dev->irq = bif->rx_dma_irq; 
+       
+       dev->priv = lp;
+       
+       dev->open = rc32434_open;
+       dev->stop = rc32434_close;
+       dev->hard_start_xmit = rc32434_send_packet;
+       dev->get_stats  = rc32434_get_stats;
+       dev->set_multicast_list = &rc32434_multicast_list;
+       dev->tx_timeout = rc32434_tx_timeout;
+       dev->watchdog_timeo = RC32434_TX_TIMEOUT;
+
+#ifdef CONFIG_IDT_USE_NAPI
+       dev->poll = rc32434_poll;
+       dev->weight = bif->weight;
+       printk("Using NAPI with weight %d\n",dev->weight);
+#else
+       lp->rx_tasklet = kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+       tasklet_init(lp->rx_tasklet, rc32434_rx_tasklet, (unsigned long)dev);
+#endif
+       lp->tx_tasklet = kmalloc(sizeof(struct tasklet_struct), GFP_KERNEL);
+       tasklet_init(lp->tx_tasklet, rc32434_tx_tasklet, (unsigned long)dev);
+       
+       if ((err = register_netdev(dev))) {
+               printk(KERN_ERR "rc32434 ethernet. Cannot register net device %d\n", err);
+               free_netdev(dev);
+               retval = -EINVAL;
+               goto probe_err_out;
+       }
+       
+       INFO("Rx IRQ %d, Tx IRQ %d, ", bif->rx_dma_irq, bif->tx_dma_irq);
+       for (i = 0; i < 6; i++) {
+               printk("%2.2x", dev->dev_addr[i]);
+               if (i<5)
+                       printk(":");
+       }
+       printk("\n");
+       
+       return 0;
+       
+ probe_err_out:
+       rc32434_cleanup_module();
+       ERR(" failed.  Returns %d\n", retval);
+       return retval;
+       
+}
+
+
+static void rc32434_cleanup_module(void)
+{
+       int i;
+       
+       for (i = 0; rc32434_iflist[i].iobase; i++) {
+               struct rc32434_if_t * bif = &rc32434_iflist[i];
+               if (bif->dev != NULL) {
+                       struct rc32434_local *lp = (struct rc32434_local *)bif->dev->priv;
+                       if (lp != NULL) {
+                               if (lp->eth_regs)
+                                       iounmap((void*)lp->eth_regs);
+                               if (lp->rx_dma_regs)
+                                       iounmap((void*)lp->rx_dma_regs);
+                               if (lp->tx_dma_regs)
+                                       iounmap((void*)lp->tx_dma_regs);
+                               if (lp->td_ring)
+                                       kfree((void*)KSEG0ADDR(lp->td_ring));
+                               
+#ifdef RC32434_PROC_DEBUG
+                               if (lp->ps) {
+                                       remove_proc_entry(bif->name, proc_net);
+                               }
+#endif
+                               kfree(lp);
+                       }
+                       
+                       unregister_netdev(bif->dev);
+                       free_netdev(bif->dev);
+                       kfree(bif->dev);
+               }
+       }
+}
+
+
+
+static int rc32434_open(struct net_device *dev)
+{
+       struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
+       
+       /* Initialize */
+       if (rc32434_init(dev)) {
+               ERR("Error: cannot open the Ethernet device\n");
+               return -EAGAIN;
+       }
+       
+       /* Install the interrupt handler that handles the Done Finished Ovr and Und Events */   
+       if (request_irq(lp->rx_irq, &rc32434_rx_dma_interrupt,
+                 SA_SHIRQ | SA_INTERRUPT,
+                       "rc32434 ethernet Rx", dev)) {
+               ERR(": unable to get Rx DMA IRQ %d\n",
+                   lp->rx_irq);
+               return -EAGAIN;
+       }
+       if (request_irq(lp->tx_irq, &rc32434_tx_dma_interrupt,
+                 SA_SHIRQ | SA_INTERRUPT,
+                       "rc32434 ethernet Tx", dev)) {
+               ERR(": unable to get Tx DMA IRQ %d\n",
+                   lp->tx_irq);
+               free_irq(lp->rx_irq, dev);
+               return -EAGAIN;
+       }
+       
+#ifdef RC32434_REVISION
+       /* Install handler for overrun error. */
+       if (request_irq(lp->ovr_irq, &rc32434_ovr_interrupt,
+                       SA_SHIRQ | SA_INTERRUPT,
+                       "Ethernet Overflow", dev)) {
+               ERR(": unable to get OVR IRQ %d\n",
+                   lp->ovr_irq);
+               free_irq(lp->rx_irq, dev);
+               free_irq(lp->tx_irq, dev);
+               return -EAGAIN;
+       }
+#endif
+       
+       /* Install handler for underflow error. */
+       if (request_irq(lp->und_irq, &rc32434_und_interrupt,
+                       SA_SHIRQ | SA_INTERRUPT,
+                       "Ethernet Underflow", dev)) {
+               ERR(": unable to get UND IRQ %d\n",
+                   lp->und_irq);
+               free_irq(lp->rx_irq, dev);
+               free_irq(lp->tx_irq, dev);
+#ifdef RC32434_REVISION                
+               free_irq(lp->ovr_irq, dev);             
+#endif
+               return -EAGAIN;
+       }
+       
+       
+       return 0;
+}
+
+
+
+
+static int rc32434_close(struct net_device *dev)
+{
+       struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
+       u32 tmp;
+       
+       /* Disable interrupts */
+       disable_irq(lp->rx_irq);
+       disable_irq(lp->tx_irq);
+#ifdef RC32434_REVISION
+       disable_irq(lp->ovr_irq);
+#endif
+       disable_irq(lp->und_irq);
+       
+       tmp = rc32434_readl(&lp->tx_dma_regs->dmasm);
+       tmp = tmp | DMASM_f_m | DMASM_e_m;
+       rc32434_writel(tmp, &lp->tx_dma_regs->dmasm);
+       
+       tmp = rc32434_readl(&lp->rx_dma_regs->dmasm);
+       tmp = tmp | DMASM_d_m | DMASM_h_m | DMASM_e_m;
+       rc32434_writel(tmp, &lp->rx_dma_regs->dmasm);
+       
+       free_irq(lp->rx_irq, dev);
+       free_irq(lp->tx_irq, dev);
+#ifdef RC32434_REVISION        
+       free_irq(lp->ovr_irq, dev);
+#endif
+       free_irq(lp->und_irq, dev);
+       return 0;
+}
+
+
+/* transmit packet */
+static int rc32434_send_packet(struct sk_buff *skb, struct net_device *dev)
+{
+       struct rc32434_local            *lp = (struct rc32434_local *)dev->priv;
+       unsigned long                   flags;
+       u32                                     length;
+       DMAD_t                          td;
+       
+       
+       spin_lock_irqsave(&lp->lock, flags);
+       
+       td = &lp->td_ring[lp->tx_chain_tail];
+       
+       /* stop queue when full, drop pkts if queue already full */
+       if(lp->tx_count >= (RC32434_NUM_TDS - 2)) {
+               lp->tx_full = 1;
+               
+               if(lp->tx_count == (RC32434_NUM_TDS - 2)) {
+                       netif_stop_queue(dev);
+               }
+               else {
+                       lp->stats.tx_dropped++;
+                       dev_kfree_skb_any(skb);
+                       spin_unlock_irqrestore(&lp->lock, flags);
+                       return 1;
+               }          
+       }        
+       
+       lp->tx_count ++;
+       
+       lp->tx_skb[lp->tx_chain_tail] = skb;
+       
+       length = skb->len;
+       
+       /* Setup the transmit descriptor. */
+       td->ca = CPHYSADDR(skb->data);
+       
+       if(rc32434_readl(&(lp->tx_dma_regs->dmandptr)) == 0) {
+               if( lp->tx_chain_status == empty ) {
+                       td->control = DMA_COUNT(length) |DMAD_cof_m |DMAD_iof_m;                                /*  Update tail      */
+                       lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK;                          /*   Move tail       */
+                       rc32434_writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]), &(lp->tx_dma_regs->dmandptr)); /* Write to NDPTR    */
+                       lp->tx_chain_head = lp->tx_chain_tail;                                                  /* Move head to tail */
+               }
+               else {
+                       td->control = DMA_COUNT(length) |DMAD_cof_m|DMAD_iof_m;                                 /* Update tail */
+                       lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].control &=  ~(DMAD_cof_m);          /* Link to prev */
+                       lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].link =  CPHYSADDR(td);              /* Link to prev */
+                       lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK;                          /* Move tail */
+                       rc32434_writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]), &(lp->tx_dma_regs->dmandptr)); /* Write to NDPTR */
+                       lp->tx_chain_head = lp->tx_chain_tail;                                                  /* Move head to tail */
+                       lp->tx_chain_status = empty;
+               }
+       }
+       else {
+               if( lp->tx_chain_status == empty ) {
+                       td->control = DMA_COUNT(length) |DMAD_cof_m |DMAD_iof_m;                                /* Update tail */
+                       lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK;                          /* Move tail */
+                       lp->tx_chain_status = filled;
+               }
+               else {
+                       td->control = DMA_COUNT(length) |DMAD_cof_m |DMAD_iof_m;                                /* Update tail */
+                       lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].control &=  ~(DMAD_cof_m);          /* Link to prev */
+                       lp->td_ring[(lp->tx_chain_tail-1)& RC32434_TDS_MASK].link =  CPHYSADDR(td);              /* Link to prev */
+                       lp->tx_chain_tail = (lp->tx_chain_tail + 1) & RC32434_TDS_MASK;                          /* Move tail */
+               }
+       }
+       
+       dev->trans_start = jiffies;                             
+       
+       spin_unlock_irqrestore(&lp->lock, flags);
+       
+       return 0;
+}
+
+
+/* Ethernet MII-PHY Handler */
+static void rc32434_mii_handler(unsigned long data)
+{
+       struct net_device *dev = (struct net_device *)data;             
+       struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
+       unsigned long   flags;
+       unsigned long duplex_status;
+       int port_addr = (lp->rx_irq == 0x2c? 1:0) << 8;
+       
+       spin_lock_irqsave(&lp->lock, flags);
+       
+       /* Two ports are using the same MII, the difference is the PHY address */
+       rc32434_writel(0, &rc32434_eth0_regs->miimcfg);  
+       rc32434_writel(0, &rc32434_eth0_regs->miimcmd);  
+       rc32434_writel(port_addr |0x05, &rc32434_eth0_regs->miimaddr);  
+       rc32434_writel(MIIMCMD_scn_m, &rc32434_eth0_regs->miimcmd);  
+       while(rc32434_readl(&rc32434_eth0_regs->miimind) & MIIMIND_nv_m);
+       
+       ERR("irq:%x             port_addr:%x    RDD:%x\n", 
+           lp->rx_irq, port_addr, rc32434_readl(&rc32434_eth0_regs->miimrdd));
+       duplex_status = (rc32434_readl(&rc32434_eth0_regs->miimrdd) & 0x140)? ETHMAC2_fd_m: 0;
+       if(duplex_status != lp->duplex_mode) {
+               ERR("The MII-PHY is Auto-negotiated to %s-Duplex mode for Eth-%x\n", duplex_status? "Full":"Half", lp->rx_irq == 0x2c? 1:0);            
+               lp->duplex_mode = duplex_status;
+               rc32434_restart(dev);           
+       }
+       
+       lp->mii_phy_timer.expires = jiffies + 10 * HZ;  
+       add_timer(&lp->mii_phy_timer);
+       
+       spin_unlock_irqrestore(&lp->lock, flags);
+       
+}
+
+#ifdef RC32434_REVISION        
+/* Ethernet Rx Overflow interrupt */
+static irqreturn_t
+rc32434_ovr_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct rc32434_local *lp;
+       unsigned int ovr;
+       irqreturn_t retval = IRQ_NONE;
+       
+       ASSERT(dev != NULL);
+       
+       lp = (struct rc32434_local *)dev->priv;
+       spin_lock(&lp->lock);
+       ovr = rc32434_readl(&lp->eth_regs->ethintfc);
+       
+       if(ovr & ETHINTFC_ovr_m) {
+               netif_stop_queue(dev);
+               
+               /* clear OVR bit */
+               rc32434_writel((ovr & ~ETHINTFC_ovr_m), &lp->eth_regs->ethintfc);
+               
+               /* Restart interface */
+               rc32434_restart(dev);
+               retval = IRQ_HANDLED;
+       }
+       spin_unlock(&lp->lock);
+       
+       return retval;
+}
+
+#endif
+
+
+/* Ethernet Tx Underflow interrupt */
+static irqreturn_t
+rc32434_und_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct rc32434_local *lp;
+       unsigned int und;
+       irqreturn_t retval = IRQ_NONE;
+       
+       ASSERT(dev != NULL);
+       
+       lp = (struct rc32434_local *)dev->priv;
+       
+       spin_lock(&lp->lock);
+       
+       und = rc32434_readl(&lp->eth_regs->ethintfc);
+       
+       if(und & ETHINTFC_und_m) {
+               netif_stop_queue(dev);
+               
+               rc32434_writel((und & ~ETHINTFC_und_m), &lp->eth_regs->ethintfc);
+               
+               /* Restart interface */
+               rc32434_restart(dev);
+               retval = IRQ_HANDLED;
+       }
+       
+       spin_unlock(&lp->lock);
+       
+       return retval;
+}
+
+
+/* Ethernet Rx DMA interrupt */
+static irqreturn_t
+rc32434_rx_dma_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct rc32434_local* lp;
+       volatile u32 dmas,dmasm;
+       irqreturn_t retval;
+       
+       ASSERT(dev != NULL);
+       
+       lp = (struct rc32434_local *)dev->priv;
+       
+       spin_lock(&lp->lock);
+       dmas = rc32434_readl(&lp->rx_dma_regs->dmas);
+       if(dmas & (DMAS_d_m|DMAS_h_m|DMAS_e_m)) {
+               /* Mask D H E bit in Rx DMA */
+               dmasm = rc32434_readl(&lp->rx_dma_regs->dmasm);
+               rc32434_writel(dmasm | (DMASM_d_m | DMASM_h_m | DMASM_e_m), &lp->rx_dma_regs->dmasm);
+#ifdef CONFIG_IDT_USE_NAPI
+               if(netif_rx_schedule_prep(dev))
+                        __netif_rx_schedule(dev);
+#else
+               tasklet_hi_schedule(lp->rx_tasklet);
+#endif
+               
+               if (dmas & DMAS_e_m)
+                       ERR(": DMA error\n");
+               
+               retval = IRQ_HANDLED;
+       }
+       else
+               retval = IRQ_NONE;
+       
+       spin_unlock(&lp->lock);
+       return retval;
+}
+
+#ifdef CONFIG_IDT_USE_NAPI
+static int rc32434_poll(struct net_device *rx_data_dev, int *budget)
+#else
+static void rc32434_rx_tasklet(unsigned long rx_data_dev)
+#endif
+{
+       struct net_device *dev = (struct net_device *)rx_data_dev;      
+       struct rc32434_local* lp = netdev_priv(dev);
+       volatile DMAD_t  rd = &lp->rd_ring[lp->rx_next_done];
+       struct sk_buff *skb, *skb_new;
+       u8* pkt_buf;
+       u32 devcs, count, pkt_len, pktuncrc_len;
+       volatile u32 dmas;
+#ifdef CONFIG_IDT_USE_NAPI
+       u32 received = 0;
+       int rx_work_limit = min(*budget,dev->quota);
+#else
+       unsigned long   flags;
+       spin_lock_irqsave(&lp->lock, flags);
+#endif
+       
+       while ( (count = RC32434_RBSIZE - (u32)DMA_COUNT(rd->control)) != 0) {
+#ifdef CONFIG_IDT_USE_NAPI
+               if(--rx_work_limit <0)
+                {
+                        break;
+                }
+#endif
+               /* init the var. used for the later operations within the while loop */
+               skb_new = NULL;
+               devcs = rd->devcs;
+               pkt_len = RCVPKT_LENGTH(devcs);
+               skb = lp->rx_skb[lp->rx_next_done];
+      
+               if (count < 64) {
+                       lp->stats.rx_errors++;
+                       lp->stats.rx_dropped++;                 
+               }
+               else if ((devcs & ( ETHRX_ld_m)) !=     ETHRX_ld_m) {
+                       /* check that this is a whole packet */
+                       /* WARNING: DMA_FD bit incorrectly set in Rc32434 (errata ref #077) */
+                       lp->stats.rx_errors++;
+                       lp->stats.rx_dropped++;
+               }
+               else if ( (devcs & ETHRX_rok_m)  ) {
+                       
+                       {
+                               /* must be the (first and) last descriptor then */
+                               pkt_buf = (u8*)lp->rx_skb[lp->rx_next_done]->data;
+                               
+                               pktuncrc_len = pkt_len - 4;
+                               /* invalidate the cache */
+                               dma_cache_inv((unsigned long)pkt_buf, pktuncrc_len);
+                               
+                               /* Malloc up new buffer. */                                       
+                               skb_new = dev_alloc_skb(RC32434_RBSIZE + 2);                                                    
+                               
+                               if (skb_new != NULL){
+                                       /* Make room */
+                                       skb_put(skb, pktuncrc_len);                 
+                                       
+                                       skb->protocol = eth_type_trans(skb, dev);
+                                       
+                                       /* pass the packet to upper layers */
+#ifdef CONFIG_IDT_USE_NAPI
+                                       netif_receive_skb(skb);
+#else
+                                       netif_rx(skb);
+#endif
+                                       
+                                       dev->last_rx = jiffies;
+                                       lp->stats.rx_packets++;
+                                       lp->stats.rx_bytes += pktuncrc_len;
+                                       
+                                       if (IS_RCV_MP(devcs))
+                                               lp->stats.multicast++;
+                                       
+                                       /* 16 bit align */                                                
+                                       skb_reserve(skb_new, 2);        
+                                       
+                                       skb_new->dev = dev;
+                                       lp->rx_skb[lp->rx_next_done] = skb_new;
+                               }
+                               else {
+                                       ERR("no memory, dropping rx packet.\n");
+                                       lp->stats.rx_errors++;          
+                                       lp->stats.rx_dropped++;                                 
+                               }
+                       }
+                       
+               }                       
+               else {
+                       /* This should only happen if we enable accepting broken packets */
+                       lp->stats.rx_errors++;
+                       lp->stats.rx_dropped++;
+                       
+                       /* add statistics counters */
+                       if (IS_RCV_CRC_ERR(devcs)) {
+                               DBG(2, "RX CRC error\n");
+                               lp->stats.rx_crc_errors++;
+                       } 
+                       else if (IS_RCV_LOR_ERR(devcs)) {
+                               DBG(2, "RX LOR error\n");
+                               lp->stats.rx_length_errors++;
+                       }                               
+                       else if (IS_RCV_LE_ERR(devcs)) {
+                               DBG(2, "RX LE error\n");
+                               lp->stats.rx_length_errors++;
+                       }
+                       else if (IS_RCV_OVR_ERR(devcs)) {
+                               lp->stats.rx_over_errors++;
+                       }
+                       else if (IS_RCV_CV_ERR(devcs)) {
+                               /* code violation */
+                               DBG(2, "RX CV error\n");
+                               lp->stats.rx_frame_errors++;
+                       }
+                       else if (IS_RCV_CES_ERR(devcs)) {
+                               DBG(2, "RX Preamble error\n");
+                       }
+               }
+               
+               rd->devcs = 0;
+               
+               /* restore descriptor's curr_addr */
+               if(skb_new)
+                       rd->ca = CPHYSADDR(skb_new->data); 
+               else
+                       rd->ca = CPHYSADDR(skb->data);
+               
+               rd->control = DMA_COUNT(RC32434_RBSIZE) |DMAD_cod_m |DMAD_iod_m;
+               lp->rd_ring[(lp->rx_next_done-1)& RC32434_RDS_MASK].control &=  ~(DMAD_cod_m);  
+               
+               lp->rx_next_done = (lp->rx_next_done + 1) & RC32434_RDS_MASK;
+               rd = &lp->rd_ring[lp->rx_next_done];
+               rc32434_writel( ~DMAS_d_m, &lp->rx_dma_regs->dmas);
+       }       
+#ifdef CONFIG_IDT_USE_NAPI
+        dev->quota -= received;
+        *budget =- received;
+        if(rx_work_limit < 0)
+                goto not_done;
+#endif
+       
+       dmas = rc32434_readl(&lp->rx_dma_regs->dmas);
+       
+       if(dmas & DMAS_h_m) {
+               rc32434_writel( ~(DMAS_h_m | DMAS_e_m), &lp->rx_dma_regs->dmas);
+#ifdef RC32434_PROC_DEBUG
+               lp->dma_halt_cnt++;
+#endif
+               rd->devcs = 0;
+               skb = lp->rx_skb[lp->rx_next_done];
+               rd->ca = CPHYSADDR(skb->data);
+               rc32434_chain_rx(lp,rd);
+       }
+       
+#ifdef CONFIG_IDT_USE_NAPI
+       netif_rx_complete(dev);
+#endif
+       /* Enable D H E bit in Rx DMA */
+       rc32434_writel(rc32434_readl(&lp->rx_dma_regs->dmasm) & ~(DMASM_d_m | DMASM_h_m |DMASM_e_m), &lp->rx_dma_regs->dmasm); 
+#ifdef CONFIG_IDT_USE_NAPI
+       return 0;
+ not_done:
+       return 1;
+#else
+       spin_unlock_irqrestore(&lp->lock, flags);
+       return;
+#endif
+
+       
+}      
+
+
+
+/* Ethernet Tx DMA interrupt */
+static irqreturn_t
+rc32434_tx_dma_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct rc32434_local *lp;
+       volatile u32 dmas,dmasm;
+       irqreturn_t retval;
+       
+       ASSERT(dev != NULL);
+       
+       lp = (struct rc32434_local *)dev->priv;
+       
+       spin_lock(&lp->lock);
+       
+       dmas = rc32434_readl(&lp->tx_dma_regs->dmas);
+       
+       if (dmas & (DMAS_f_m | DMAS_e_m)) {
+               dmasm = rc32434_readl(&lp->tx_dma_regs->dmasm);
+               /* Mask F E bit in Tx DMA */
+               rc32434_writel(dmasm | (DMASM_f_m | DMASM_e_m), &lp->tx_dma_regs->dmasm);
+               
+               tasklet_hi_schedule(lp->tx_tasklet);
+               
+               if(lp->tx_chain_status == filled && (rc32434_readl(&(lp->tx_dma_regs->dmandptr)) == 0)) {
+                       rc32434_writel(CPHYSADDR(&lp->td_ring[lp->tx_chain_head]), &(lp->tx_dma_regs->dmandptr));                       
+                       lp->tx_chain_status = empty;
+                       lp->tx_chain_head = lp->tx_chain_tail;
+                       dev->trans_start = jiffies;
+               }
+               
+               if (dmas & DMAS_e_m)
+                       ERR(": DMA error\n");
+               
+               retval = IRQ_HANDLED;
+       }
+       else
+               retval = IRQ_NONE;
+       
+       spin_unlock(&lp->lock);
+       
+       return retval;
+}
+
+
+static void rc32434_tx_tasklet(unsigned long tx_data_dev)
+{
+       struct net_device *dev = (struct net_device *)tx_data_dev;      
+       struct rc32434_local* lp = (struct rc32434_local *)dev->priv;
+       volatile DMAD_t td = &lp->td_ring[lp->tx_next_done];
+       u32 devcs;
+       unsigned long   flags;
+       volatile u32 dmas;
+       
+       spin_lock_irqsave(&lp->lock, flags);
+       
+       /* process all desc that are done */
+       while(IS_DMA_FINISHED(td->control)) {
+               if(lp->tx_full == 1) {
+                       netif_wake_queue(dev);
+                       lp->tx_full = 0;
+               }
+               
+               devcs = lp->td_ring[lp->tx_next_done].devcs;    
+               if ((devcs & (ETHTX_fd_m | ETHTX_ld_m)) != (ETHTX_fd_m | ETHTX_ld_m)) {
+                       lp->stats.tx_errors++;
+                       lp->stats.tx_dropped++;                         
+                       
+                       /* should never happen */
+                       DBG(1, __FUNCTION__ ": split tx ignored\n");
+               }
+               else if (IS_TX_TOK(devcs)) {
+                       lp->stats.tx_packets++;
+               }
+               else {
+                       lp->stats.tx_errors++;
+                       lp->stats.tx_dropped++;                         
+                       
+                       /* underflow */
+                       if (IS_TX_UND_ERR(devcs)) 
+                               lp->stats.tx_fifo_errors++;
+                       
+                       /* oversized frame */
+                       if (IS_TX_OF_ERR(devcs))
+                               lp->stats.tx_aborted_errors++;
+                       
+                       /* excessive deferrals */
+                       if (IS_TX_ED_ERR(devcs))
+                               lp->stats.tx_carrier_errors++;
+                       
+                       /* collisions: medium busy */
+                       if (IS_TX_EC_ERR(devcs))
+                               lp->stats.collisions++;
+                       
+                       /* late collision */
+                       if (IS_TX_LC_ERR(devcs))
+                               lp->stats.tx_window_errors++;
+                       
+               }
+               
+               /* We must always free the original skb */
+               if (lp->tx_skb[lp->tx_next_done] != NULL) {
+                       dev_kfree_skb_any(lp->tx_skb[lp->tx_next_done]);
+                       lp->tx_skb[lp->tx_next_done] = NULL;
+               }
+               
+               lp->td_ring[lp->tx_next_done].control = DMAD_iof_m;
+               lp->td_ring[lp->tx_next_done].devcs = ETHTX_fd_m | ETHTX_ld_m;  
+               lp->td_ring[lp->tx_next_done].link = 0;
+               lp->td_ring[lp->tx_next_done].ca = 0;
+               lp->tx_count --;
+               
+               /* go on to next transmission */
+               lp->tx_next_done = (lp->tx_next_done + 1) & RC32434_TDS_MASK;
+               td = &lp->td_ring[lp->tx_next_done];
+               
+       }
+       
+       dmas = rc32434_readl(&lp->tx_dma_regs->dmas);
+       rc32434_writel( ~dmas, &lp->tx_dma_regs->dmas);
+       
+       /* Enable F E bit in Tx DMA */
+       rc32434_writel(rc32434_readl(&lp->tx_dma_regs->dmasm) & ~(DMASM_f_m | DMASM_e_m), &lp->tx_dma_regs->dmasm); 
+       spin_unlock_irqrestore(&lp->lock, flags);
+       
+}
+
+
+static struct net_device_stats * rc32434_get_stats(struct net_device *dev)
+{
+       struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
+       return &lp->stats;
+}
+
+
+/*
+ * Set or clear the multicast filter for this adaptor.
+ */
+static void rc32434_multicast_list(struct net_device *dev)
+{   
+       /* listen to broadcasts always and to treat     */
+       /*       IFF bits independantly */
+       struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
+       unsigned long flags;
+       u32 recognise = ETHARC_ab_m;            /* always accept broadcasts */
+       
+       if (dev->flags & IFF_PROMISC)                   /* set promiscuous mode */
+               recognise |= ETHARC_pro_m;
+       
+       if ((dev->flags & IFF_ALLMULTI) || (dev->mc_count > 15))
+               recognise |= ETHARC_am_m;               /* all multicast & bcast */
+       else if (dev->mc_count > 0) {
+               DBG(2, __FUNCTION__ ": mc_count %d\n", dev->mc_count);
+               recognise |= ETHARC_am_m;               /* for the time being */
+       }
+       
+       spin_lock_irqsave(&lp->lock, flags);
+       rc32434_writel(recognise, &lp->eth_regs->etharc);
+       spin_unlock_irqrestore(&lp->lock, flags);
+}
+
+
+static void rc32434_tx_timeout(struct net_device *dev)
+{
+       struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
+       unsigned long flags;
+       
+       spin_lock_irqsave(&lp->lock, flags);
+       rc32434_restart(dev);
+       spin_unlock_irqrestore(&lp->lock, flags);
+       
+}
+
+
+/*
+ * Initialize the RC32434 ethernet controller.
+ */
+static int rc32434_init(struct net_device *dev)
+{
+       struct rc32434_local *lp = (struct rc32434_local *)dev->priv;
+       int i, j;
+       
+       /* Disable DMA */       
+       rc32434_abort_tx(dev);
+       rc32434_abort_rx(dev); 
+       
+       /* reset ethernet logic */ 
+       rc32434_writel(0, &lp->eth_regs->ethintfc);
+       while((rc32434_readl(&lp->eth_regs->ethintfc) & ETHINTFC_rip_m))
+               dev->trans_start = jiffies;     
+       
+       /* Enable Ethernet Interface */ 
+       rc32434_writel(ETHINTFC_en_m, &lp->eth_regs->ethintfc); 
+       
+#ifndef CONFIG_IDT_USE_NAPI
+       tasklet_disable(lp->rx_tasklet);
+#endif
+       tasklet_disable(lp->tx_tasklet);
+       
+       /* Initialize the transmit Descriptors */
+       for (i = 0; i < RC32434_NUM_TDS; i++) {
+               lp->td_ring[i].control = DMAD_iof_m;
+               lp->td_ring[i].devcs = ETHTX_fd_m | ETHTX_ld_m;
+               lp->td_ring[i].ca = 0;
+               lp->td_ring[i].link = 0;
+               if (lp->tx_skb[i] != NULL) {
+                       dev_kfree_skb_any(lp->tx_skb[i]);
+                       lp->tx_skb[i] = NULL;
+               }
+       }
+       lp->tx_next_done = lp->tx_chain_head = lp->tx_chain_tail =      lp->tx_full = lp->tx_count = 0;
+       lp->    tx_chain_status = empty;
+       
+       /*
+        * Initialize the receive descriptors so that they
+        * become a circular linked list, ie. let the last
+        * descriptor point to the first again.
+        */
+       for (i=0; i<RC32434_NUM_RDS; i++) {
+               struct sk_buff *skb = lp->rx_skb[i];
+               
+               if (lp->rx_skb[i] == NULL) {
+                       skb = dev_alloc_skb(RC32434_RBSIZE + 2);
+                       if (skb == NULL) {
+                               ERR("No memory in the system\n");
+                               for (j = 0; j < RC32434_NUM_RDS; j ++)
+                                       if (lp->rx_skb[j] != NULL) 
+                                               dev_kfree_skb_any(lp->rx_skb[j]);
+                               
+                               return 1;
+                       }
+                       else {
+                               skb->dev = dev;
+                               skb_reserve(skb, 2);
+                               lp->rx_skb[i] = skb;
+                               lp->rd_ring[i].ca = CPHYSADDR(skb->data); 
+                               
+                       }
+               }
+               lp->rd_ring[i].control =        DMAD_iod_m | DMA_COUNT(RC32434_RBSIZE);
+               lp->rd_ring[i].devcs = 0;
+               lp->rd_ring[i].ca = CPHYSADDR(skb->data);
+               lp->rd_ring[i].link = CPHYSADDR(&lp->rd_ring[i+1]);
+               
+       }
+       /* loop back */
+       lp->rd_ring[RC32434_NUM_RDS-1].link = CPHYSADDR(&lp->rd_ring[0]);
+       lp->rx_next_done   = 0;
+       
+       lp->rd_ring[RC32434_NUM_RDS-1].control |= DMAD_cod_m;
+       lp->rx_chain_head = 0;
+       lp->rx_chain_tail = 0;
+       lp->rx_chain_status = empty;
+       
+       rc32434_writel(0, &lp->rx_dma_regs->dmas);
+       /* Start Rx DMA */
+       rc32434_start_rx(lp, &lp->rd_ring[0]);
+       
+       /* Enable F E bit in Tx DMA */
+       rc32434_writel(rc32434_readl(&lp->tx_dma_regs->dmasm) & ~(DMASM_f_m | DMASM_e_m), &lp->tx_dma_regs->dmasm); 
+       /* Enable D H E bit in Rx DMA */
+       rc32434_writel(rc32434_readl(&lp->rx_dma_regs->dmasm) & ~(DMASM_d_m | DMASM_h_m | DMASM_e_m), &lp->rx_dma_regs->dmasm); 
+       
+       /* Accept only packets destined for this Ethernet device address */
+       rc32434_writel(ETHARC_ab_m, &lp->eth_regs->etharc); 
+       
+       /* Set all Ether station address registers to their initial values */ 
+       rc32434_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal0); 
+       rc32434_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah0);
+       
+       rc32434_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal1); 
+       rc32434_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah1);
+       
+       rc32434_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal2); 
+       rc32434_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah2);
+       
+       rc32434_writel(STATION_ADDRESS_LOW(dev), &lp->eth_regs->ethsal3); 
+       rc32434_writel(STATION_ADDRESS_HIGH(dev), &lp->eth_regs->ethsah3); 
+       
+       
+       /* Frame Length Checking, Pad Enable, CRC Enable, Full Duplex set */ 
+       rc32434_writel(ETHMAC2_pe_m | ETHMAC2_cen_m | ETHMAC2_fd_m, &lp->eth_regs->ethmac2);  
+       //ETHMAC2_flc_m         ETHMAC2_fd_m    lp->duplex_mode
+       
+       /* Back to back inter-packet-gap */ 
+       rc32434_writel(0x15, &lp->eth_regs->ethipgt); 
+       /* Non - Back to back inter-packet-gap */ 
+       rc32434_writel(0x12, &lp->eth_regs->ethipgr); 
+       
+       /* Management Clock Prescaler Divisor */
+       /* Clock independent setting */
+       rc32434_writel(((idt_cpu_freq)/MII_CLOCK+1) & ~1,
+                      &lp->eth_regs->ethmcp);
+       
+       /* don't transmit until fifo contains 48b */
+       rc32434_writel(48, &lp->eth_regs->ethfifott);
+       
+       rc32434_writel(ETHMAC1_re_m, &lp->eth_regs->ethmac1);
+       
+#ifndef CONFIG_IDT_USE_NAPI
+       tasklet_enable(lp->rx_tasklet);
+#endif
+       tasklet_enable(lp->tx_tasklet);
+       
+       netif_start_queue(dev);
+       
+       
+       return 0; 
+       
+}
+
+
+#ifndef MODULE
+
+static int __init rc32434_setup(char *options)
+{
+       /* no options yet */
+       return 1;
+}
+
+static int __init rc32434_setup_ethaddr0(char *options)
+{
+       memcpy(mac0, options, 17);
+       mac0[17]= '\0';
+       return 1;
+}
+
+__setup("rc32434eth=", rc32434_setup);
+__setup("ethaddr0=", rc32434_setup_ethaddr0);
+
+
+#endif /* MODULE */
+
+module_init(rc32434_init_module);
+module_exit(rc32434_cleanup_module);
+
+
+
+
+
+
+
+
+
+
+
+
+
+