Prevent the ioctl from handling even unsupported ioctls
[openwrt.git] / target / linux / rdc-2.6 / files / drivers / net / r6040.c
index 2398031..376b6ec 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}};
@@ -188,6 +194,7 @@ 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);
 static struct ethtool_ops netdev_ethtool_ops;
+static int netdev_ioctl (struct net_device *dev, struct ifreq *rq, int cmd);
 static void r6040_down(struct net_device *dev);
 static void r6040_up(struct net_device *dev);
 static void r6040_tx_timeout (struct net_device *dev);
@@ -263,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;
@@ -270,6 +278,7 @@ static int __devinit r6040_init_one (struct pci_dev *pdev,
        dev->stop = &r6040_close;
        dev->get_stats = &r6040_get_stats;
        dev->set_multicast_list = &set_multicast_list;
+       dev->do_ioctl = &netdev_ioctl;
        dev->ethtool_ops = &netdev_ethtool_ops;
        dev->tx_timeout = &r6040_tx_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
@@ -328,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;
 }
 
@@ -606,6 +617,31 @@ 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);
+       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;
+}
+
 /**
        Stop RDC MAC and Free the allocated resource
  */
@@ -802,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);
 
@@ -817,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);
 }
@@ -952,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);
 }
 
 
This page took 0.02942 seconds and 4 git commands to generate.