enable start-stop-daemon by default, i want to use this to clean up a few init script...
[openwrt/staging/dedeckeh.git] / target / linux / rdc-2.6 / files / drivers / net / r6040.c
index 95210d9ce64268202983bf79d26256e499f99d79..376b6ecfe9f7f30bf13e1bcb592df281303890fa 100644 (file)
@@ -139,6 +139,7 @@ struct r6040_private {
        u16     mcr0, mcr1;
        dma_addr_t desc_dma;
        char    *desc_pool;
+       u16     switch_sig;
 };
 
 struct r6040_chip_info {
@@ -164,10 +165,15 @@ static struct r6040_chip_info r6040_chip_info[] __devinitdata =
 {
        { "RDC R6040 Knight", R6040_PCI_CMD, R6040_IO_SIZE, 0}
 };
+static char *parent = NULL;
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
 static int NUM_MAC_TABLE = 2 ;
+module_param(parent, charp, 0444);
+#else
+MODULE_PARM(parent, "s");
 #endif
+MODULE_PARM_DESC(parent, "Parent network device name");
 
 static int phy_table[] = { 0x1, 0x2};
 static u8 adr_table[2][8] = {{0x00, 0x00, 0x60, 0x00, 0x00, 0x01}, {0x00, 0x00, 0x60, 0x00, 0x00, 0x02}};
@@ -183,7 +189,7 @@ MODULE_PARM_DESC(adr_table, "MAC Address (assigned)");
 
 static int r6040_open(struct net_device *dev);
 static int r6040_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static irqreturn_t r6040_interrupt(int irq, void *dev_id, struct pt_regs *regs);
+static irqreturn_t r6040_interrupt(int irq, void *dev_id);
 static struct net_device_stats *r6040_get_stats(struct net_device *dev);
 static int r6040_close(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
@@ -264,6 +270,7 @@ static int __devinit r6040_init_one (struct pci_dev *pdev,
        /* Init RDC private data */
        lp->mcr0 = 0x1002;
        lp->phy_addr = phy_table[card_idx];
+       lp->switch_sig = 0;
 
        /* The RDC-specific entries in the device structure. */
        dev->open = &r6040_open;
@@ -330,13 +337,15 @@ r6040_open(struct net_device *dev)
 
        netif_start_queue(dev);
 
+       if (lp->switch_sig != 0x0243)
+       {
        /* set and active a timer process */
        init_timer(&lp->timer);
        lp->timer.expires = TIMER_WUT;
        lp->timer.data = (unsigned long)dev;
        lp->timer.function = &r6040_timer;
        add_timer(&lp->timer);
-
+       }
        return 0;
 }
 
@@ -418,7 +427,7 @@ r6040_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
 /* The RDC interrupt handler. */
 static irqreturn_t
-r6040_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+r6040_interrupt(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
        struct r6040_private *lp;
@@ -608,12 +617,29 @@ r6040_close(struct net_device *dev)
        return 0;
 }
 
-/**
- */
 static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
 {
+       struct r6040_private *lp = dev->priv;
+
        RDC_DBUG("netdev_ioctl()", 0);
-       return 0;
+       if (lp->switch_sig == 0x0243 && cmd == SIOCDEVPRIVATE)
+       {
+               unsigned long *data = (unsigned long *)rq->ifr_data, args[4];
+               int ioaddr = dev->base_addr;
+               unsigned int val;
+
+               data = (unsigned long *)rq->ifr_data;
+               if (copy_from_user(args, data, 4*sizeof(unsigned long)))
+                       return -EFAULT;
+
+               /* port priority */
+               if(args[0]&(1<<31))phy_write(ioaddr,29,19,(phy_read(ioaddr,29,19)|0x2000));     /* port 0 */
+               if(args[0]&(1<<29))phy_write(ioaddr,29,19,(phy_read(ioaddr,29,19)|0x0020));     /* port 1 */
+               if(args[0]&(1<<27))phy_write(ioaddr,29,20,(phy_read(ioaddr,29,20)|0x2000));     /* port 2 */
+               if(args[0]&(1<<25))phy_write(ioaddr,29,20,(phy_read(ioaddr,29,20)|0x0020));     /* port 3 */
+
+       } 
+       return -EOPNOTSUPP;
 }
 
 /**
@@ -812,14 +838,20 @@ for (i = 0; i < RX_DCNT; i++) {
        /* Buffer Size Register */
        outw(MAX_BUF_SIZE, ioaddr+0x18);
 
-       /* PHY Mode Check */
-       phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
-       phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
-
-       if (PHY_MODE == 0x3100) 
-               lp->phy_mode = phy_mode_chk(dev);
-       else lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
-
+       if ((lp->switch_sig = phy_read(ioaddr, 0, 2)) == 0x0243)        // ICPlus IP175C Signature
+       {
+               phy_write(ioaddr, 29,31, 0x175C);       //Enable registers
+               lp->phy_mode = 0x8000;
+       } else {
+               /* PHY Mode Check */
+               phy_write(ioaddr, lp->phy_addr, 4, PHY_CAP);
+               phy_write(ioaddr, lp->phy_addr, 0, PHY_MODE);
+
+               if (PHY_MODE == 0x3100)
+                       lp->phy_mode = phy_mode_chk(dev);
+               else
+                       lp->phy_mode = (PHY_MODE & 0x0100) ? 0x8000:0x0;
+       }
        /* MAC Bus Control Register */
        outw(MBCR_DEFAULT, ioaddr+0x8);
 
@@ -827,6 +859,16 @@ for (i = 0; i < RX_DCNT; i++) {
        lp->mcr0 |= lp->phy_mode;
        outw(lp->mcr0, ioaddr);
 
+       /* set interrupt waiting time and packet numbers */
+       outw(0x0802, ioaddr + 0x0C);
+       outw(0x0802, ioaddr + 0x10);
+
+       /* upgrade performance (by RDC guys) */
+       phy_write(ioaddr,30,17,(phy_read(ioaddr,30,17)|0x4000));        //bit 14=1
+       phy_write(ioaddr,30,17,~((~phy_read(ioaddr,30,17))|0x2000));    //bit 13=0
+       phy_write(ioaddr,0,19,0x0000);
+       phy_write(ioaddr,0,30,0x01F0);
+
        /* Interrupt Mask Register */
        outw(R6040_INT_MASK, ioaddr + 0x40);
 }
@@ -962,7 +1004,20 @@ static int __init r6040_init (void)
        printk(version);
        printed_version = 1;
 
-       return pci_module_init (&r6040_driver);
+       if (parent != NULL)
+       {
+               struct net_device *the_parent = dev_get_by_name(parent);
+
+               if (the_parent == NULL)
+               {
+                       printk (KERN_ERR DRV_NAME ": Unknown device \"%s\" specified.\n", parent);
+                       return -EINVAL;
+               }
+               memcpy((u8 *)&adr_table[0][0], the_parent->dev_addr, 6);
+               memcpy((u8 *)&adr_table[1][0], the_parent->dev_addr, 6);
+               ++*(u8 *)&adr_table[0][5];
+       }
+       return pci_register_driver (&r6040_driver);
 }