fedora core 6 1.2949 + vserver 2.2.0
[linux-2.6.git] / drivers / usb / net / rtl8150.c
index 640aa5b..670262a 100644 (file)
@@ -6,7 +6,6 @@
  * version 2 as published by the Free Software Foundation.
  */
 
-#include <linux/config.h>
 #include <linux/sched.h>
 #include <linux/init.h>
 #include <linux/signal.h>
@@ -20,7 +19,7 @@
 #include <asm/uaccess.h>
 
 /* Version Information */
-#define DRIVER_VERSION "v0.6.1 (2004/03/13)"
+#define DRIVER_VERSION "v0.6.2 (2004/08/27)"
 #define DRIVER_AUTHOR "Petko Manolov <petkan@users.sourceforge.net>"
 #define DRIVER_DESC "rtl8150 based usb-ethernet driver"
 
 #define        RX_URB_FAIL             3
 
 /* Define these values to match your device */
-#define VENDOR_ID_REALTEK              0x0bda
+#define        VENDOR_ID_REALTEK               0x0bda
 #define        VENDOR_ID_MELCO                 0x0411
-#define VENDOR_ID_MICRONET             0x3980
+#define        VENDOR_ID_MICRONET              0x3980
 #define        VENDOR_ID_LONGSHINE             0x07b8
+#define        VENDOR_ID_OQO                   0x1557
+#define        VENDOR_ID_ZYXEL                 0x0586
 
 #define PRODUCT_ID_RTL8150             0x8150
 #define        PRODUCT_ID_LUAKTX               0x0012
 #define        PRODUCT_ID_LCS8138TX            0x401a
 #define PRODUCT_ID_SP128AR             0x0003
+#define        PRODUCT_ID_PRESTIGE             0x401a
 
 #undef EEPROM_WRITE
 
@@ -143,6 +145,8 @@ static struct usb_device_id rtl8150_table[] = {
        {USB_DEVICE(VENDOR_ID_MELCO, PRODUCT_ID_LUAKTX)},
        {USB_DEVICE(VENDOR_ID_MICRONET, PRODUCT_ID_SP128AR)},
        {USB_DEVICE(VENDOR_ID_LONGSHINE, PRODUCT_ID_LCS8138TX)},
+       {USB_DEVICE(VENDOR_ID_OQO, PRODUCT_ID_RTL8150)},
+       {USB_DEVICE(VENDOR_ID_ZYXEL, PRODUCT_ID_PRESTIGE)},
        {}
 };
 
@@ -167,23 +171,24 @@ struct rtl8150 {
 
 typedef struct rtl8150 rtl8150_t;
 
-static unsigned long multicast_filter_limit = 32;
-
 static void fill_skb_pool(rtl8150_t *);
 static void free_skb_pool(rtl8150_t *);
 static inline struct sk_buff *pull_skb(rtl8150_t *);
 static void rtl8150_disconnect(struct usb_interface *intf);
 static int rtl8150_probe(struct usb_interface *intf,
                           const struct usb_device_id *id);
+static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message);
+static int rtl8150_resume(struct usb_interface *intf);
 
 static const char driver_name [] = "rtl8150";
 
 static struct usb_driver rtl8150_driver = {
-       .owner =        THIS_MODULE,
        .name =         driver_name,
        .probe =        rtl8150_probe,
        .disconnect =   rtl8150_disconnect,
        .id_table =     rtl8150_table,
+       .suspend =      rtl8150_suspend,
+       .resume =       rtl8150_resume
 };
 
 /*
@@ -195,17 +200,17 @@ static int get_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
 {
        return usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
                               RTL8150_REQ_GET_REGS, RTL8150_REQT_READ,
-                              indx, 0, data, size, HZ / 2);
+                              indx, 0, data, size, 500);
 }
 
 static int set_registers(rtl8150_t * dev, u16 indx, u16 size, void *data)
 {
        return usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
                               RTL8150_REQ_SET_REGS, RTL8150_REQT_WRITE,
-                              indx, 0, data, size, HZ / 2);
+                              indx, 0, data, size, 500);
 }
 
-static void ctrl_callback(struct urb *urb, struct pt_regs *regs)
+static void ctrl_callback(struct urb *urb)
 {
        rtl8150_t *dev;
 
@@ -239,9 +244,11 @@ static int async_set_registers(rtl8150_t * dev, u16 indx, u16 size)
        usb_fill_control_urb(dev->ctrl_urb, dev->udev,
                         usb_sndctrlpipe(dev->udev, 0), (char *) &dev->dr,
                         &dev->rx_creg, size, ctrl_callback, dev);
-       if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC)))
+       if ((ret = usb_submit_urb(dev->ctrl_urb, GFP_ATOMIC))) {
+               if (ret == -ENODEV)
+                       netif_device_detach(dev->netdev);
                err("control request submission failed: %d", ret);
-       else
+       else
                set_bit(RX_REG_SET, &dev->flags);
 
        return ret;
@@ -277,7 +284,8 @@ static int write_mii_word(rtl8150_t * dev, u8 phy, __u8 indx, u16 reg)
        u8 data[3], tmp;
 
        data[0] = phy;
-       *(data + 1) = cpu_to_le16p(&reg);
+       data[1] = reg & 0xff;
+       data[2] = (reg >> 8) & 0xff;
        tmp = indx | PHY_WRITE | PHY_GO;
        i = 0;
 
@@ -304,15 +312,12 @@ static inline void set_ethernet_addr(rtl8150_t * dev)
 static int rtl8150_set_mac_address(struct net_device *netdev, void *p)
 {
        struct sockaddr *addr = p;
-       rtl8150_t *dev;
+       rtl8150_t *dev = netdev_priv(netdev);
        int i;
 
        if (netif_running(netdev))
                return -EBUSY;
-       dev = netdev->priv;
-       if (dev == NULL) {
-               return -ENODEV;
-       }
+
        memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
        dbg("%s: Setting MAC address to ", netdev->name);
        for (i = 0; i < 5; i++)
@@ -392,10 +397,10 @@ static void free_all_urbs(rtl8150_t * dev)
 
 static void unlink_all_urbs(rtl8150_t * dev)
 {
-       usb_unlink_urb(dev->rx_urb);
-       usb_unlink_urb(dev->tx_urb);
-       usb_unlink_urb(dev->intr_urb);
-       usb_unlink_urb(dev->ctrl_urb);
+       usb_kill_urb(dev->rx_urb);
+       usb_kill_urb(dev->tx_urb);
+       usb_kill_urb(dev->intr_urb);
+       usb_kill_urb(dev->ctrl_urb);
 }
 
 static inline struct sk_buff *pull_skb(rtl8150_t *dev)
@@ -413,13 +418,14 @@ static inline struct sk_buff *pull_skb(rtl8150_t *dev)
        return NULL;
 }
 
-static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void read_bulk_callback(struct urb *urb)
 {
        rtl8150_t *dev;
        unsigned pkt_len, res;
        struct sk_buff *skb;
        struct net_device *netdev;
        u16 rx_stat;
+       int status;
 
        dev = urb->context;
        if (!dev)
@@ -435,7 +441,7 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
                break;
        case -ENOENT:
                return; /* the urb is in unlink state */
-       case -ETIMEDOUT:
+       case -ETIME:
                warn("may be reset is needed?..");
                goto goon;
        default:
@@ -469,7 +475,10 @@ static void read_bulk_callback(struct urb *urb, struct pt_regs *regs)
 goon:
        usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
                      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
-       if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
+       status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
+       if (status == -ENODEV)
+               netif_device_detach(dev->netdev);
+       else if (status) {
                set_bit(RX_URB_FAIL, &dev->flags);
                goto resched;
        } else {
@@ -485,6 +494,7 @@ static void rx_fixup(unsigned long data)
 {
        rtl8150_t *dev;
        struct sk_buff *skb;
+       int status;
 
        dev = (rtl8150_t *)data;
 
@@ -503,10 +513,13 @@ static void rx_fixup(unsigned long data)
        usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
                      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
 try_again:
-       if (usb_submit_urb(dev->rx_urb, GFP_ATOMIC)) {
+       status = usb_submit_urb(dev->rx_urb, GFP_ATOMIC);
+       if (status == -ENODEV) {
+               netif_device_detach(dev->netdev);
+       } else if (status) {
                set_bit(RX_URB_FAIL, &dev->flags);
                goto tlsched;
-        } else {
+       } else {
                clear_bit(RX_URB_FAIL, &dev->flags);
        }
 
@@ -515,7 +528,7 @@ tlsched:
        tasklet_schedule(&dev->tl);
 }
 
-static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
+static void write_bulk_callback(struct urb *urb)
 {
        rtl8150_t *dev;
 
@@ -531,7 +544,7 @@ static void write_bulk_callback(struct urb *urb, struct pt_regs *regs)
        netif_wake_queue(dev->netdev);
 }
 
-static void intr_callback(struct urb *urb, struct pt_regs *regs)
+static void intr_callback(struct urb *urb)
 {
        rtl8150_t *dev;
        __u8 *d;
@@ -577,13 +590,44 @@ static void intr_callback(struct urb *urb, struct pt_regs *regs)
        }
 
 resubmit:
-       status = usb_submit_urb (urb, SLAB_ATOMIC);
-       if (status)
+       status = usb_submit_urb (urb, GFP_ATOMIC);
+       if (status == -ENODEV)
+               netif_device_detach(dev->netdev);
+       else if (status)
                err ("can't resubmit intr, %s-%s/input0, status %d",
                                dev->udev->bus->bus_name,
                                dev->udev->devpath, status);
 }
 
+static int rtl8150_suspend(struct usb_interface *intf, pm_message_t message)
+{
+       rtl8150_t *dev = usb_get_intfdata(intf);
+
+       netif_device_detach(dev->netdev);
+
+       if (netif_running(dev->netdev)) {
+               usb_kill_urb(dev->rx_urb);
+               usb_kill_urb(dev->intr_urb);
+       }
+       return 0;
+}
+
+static int rtl8150_resume(struct usb_interface *intf)
+{
+       rtl8150_t *dev = usb_get_intfdata(intf);
+
+       netif_device_attach(dev->netdev);
+       if (netif_running(dev->netdev)) {
+               dev->rx_urb->status = 0;
+               dev->rx_urb->actual_length = 0;
+               read_bulk_callback(dev->rx_urb);
+
+               dev->intr_urb->status = 0;
+               dev->intr_urb->actual_length = 0;
+               intr_callback(dev->intr_urb);
+       }
+       return 0;
+}
 
 /*
 **
@@ -651,32 +695,25 @@ static void disable_net_traffic(rtl8150_t * dev)
 
 static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev)
 {
-       return &((rtl8150_t *) dev->priv)->stats;
+       return &((rtl8150_t *)netdev_priv(dev))->stats;
 }
 
 static void rtl8150_tx_timeout(struct net_device *netdev)
 {
-       rtl8150_t *dev;
-
-       dev = netdev->priv;
-       if (!dev)
-               return;
+       rtl8150_t *dev = netdev_priv(netdev);
        warn("%s: Tx timeout.", netdev->name);
-       dev->tx_urb->transfer_flags |= URB_ASYNC_UNLINK;
        usb_unlink_urb(dev->tx_urb);
        dev->stats.tx_errors++;
 }
 
 static void rtl8150_set_multicast(struct net_device *netdev)
 {
-       rtl8150_t *dev;
-
-       dev = netdev->priv;
+       rtl8150_t *dev = netdev_priv(netdev);
        netif_stop_queue(netdev);
        if (netdev->flags & IFF_PROMISC) {
                dev->rx_creg |= cpu_to_le16(0x0001);
                info("%s: promiscuous mode", netdev->name);
-       } else if ((netdev->mc_count > multicast_filter_limit) ||
+       } else if (netdev->mc_count ||
                   (netdev->flags & IFF_ALLMULTI)) {
                dev->rx_creg &= cpu_to_le16(0xfffe);
                dev->rx_creg |= cpu_to_le16(0x0002);
@@ -691,20 +728,24 @@ static void rtl8150_set_multicast(struct net_device *netdev)
 
 static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
-       rtl8150_t *dev;
+       rtl8150_t *dev = netdev_priv(netdev);
        int count, res;
 
        netif_stop_queue(netdev);
-       dev = netdev->priv;
        count = (skb->len < 60) ? 60 : skb->len;
        count = (count & 0x3f) ? count : count + 1;
        dev->tx_skb = skb;
        usb_fill_bulk_urb(dev->tx_urb, dev->udev, usb_sndbulkpipe(dev->udev, 2),
                      skb->data, count, write_bulk_callback, dev);
        if ((res = usb_submit_urb(dev->tx_urb, GFP_ATOMIC))) {
-               warn("failed tx_urb %d\n", res);
-               dev->stats.tx_errors++;
-               netif_start_queue(netdev);
+               /* Can we get/handle EPIPE here? */
+               if (res == -ENODEV)
+                       netif_device_detach(dev->netdev);
+               else {
+                       warn("failed tx_urb %d\n", res);
+                       dev->stats.tx_errors++;
+                       netif_start_queue(netdev);
+               }
        } else {
                dev->stats.tx_packets++;
                dev->stats.tx_bytes += skb->len;
@@ -717,7 +758,7 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 
 static void set_carrier(struct net_device *netdev)
 {
-       rtl8150_t *dev = netdev->priv;
+       rtl8150_t *dev = netdev_priv(netdev);
        short tmp;
 
        get_registers(dev, CSCR, 2, &tmp);
@@ -729,13 +770,9 @@ static void set_carrier(struct net_device *netdev)
 
 static int rtl8150_open(struct net_device *netdev)
 {
-       rtl8150_t *dev;
+       rtl8150_t *dev = netdev_priv(netdev);
        int res;
 
-       dev = netdev->priv;
-       if (dev == NULL) {
-               return -ENODEV;
-       }
        if (dev->rx_skb == NULL)
                dev->rx_skb = pull_skb(dev);
        if (!dev->rx_skb)
@@ -745,29 +782,34 @@ static int rtl8150_open(struct net_device *netdev)
        
        usb_fill_bulk_urb(dev->rx_urb, dev->udev, usb_rcvbulkpipe(dev->udev, 1),
                      dev->rx_skb->data, RTL8150_MTU, read_bulk_callback, dev);
-       if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL)))
+       if ((res = usb_submit_urb(dev->rx_urb, GFP_KERNEL))) {
+               if (res == -ENODEV)
+                       netif_device_detach(dev->netdev);
                warn("%s: rx_urb submit failed: %d", __FUNCTION__, res);
+               return res;
+       }
        usb_fill_int_urb(dev->intr_urb, dev->udev, usb_rcvintpipe(dev->udev, 3),
                     dev->intr_buff, INTBUFSIZE, intr_callback,
                     dev, dev->intr_interval);
-       if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL)))
+       if ((res = usb_submit_urb(dev->intr_urb, GFP_KERNEL))) {
+               if (res == -ENODEV)
+                       netif_device_detach(dev->netdev);
                warn("%s: intr_urb submit failed: %d", __FUNCTION__, res);
-       netif_start_queue(netdev);
+               usb_kill_urb(dev->rx_urb);
+               return res;
+       }
        enable_net_traffic(dev);
        set_carrier(netdev);
+       netif_start_queue(netdev);
 
        return res;
 }
 
 static int rtl8150_close(struct net_device *netdev)
 {
-       rtl8150_t *dev;
+       rtl8150_t *dev = netdev_priv(netdev);
        int res = 0;
 
-       dev = netdev->priv;
-       if (!dev)
-               return -ENODEV;
-
        netif_stop_queue(netdev);
        if (!test_bit(RTL8150_UNPLUG, &dev->flags))
                disable_net_traffic(dev);
@@ -776,93 +818,64 @@ static int rtl8150_close(struct net_device *netdev)
        return res;
 }
 
-static int rtl8150_ethtool_ioctl(struct net_device *netdev, void __user *uaddr)
+static void rtl8150_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *info)
 {
-       rtl8150_t *dev;
-       int cmd;
+       rtl8150_t *dev = netdev_priv(netdev);
+
+       strncpy(info->driver, driver_name, ETHTOOL_BUSINFO_LEN);
+       strncpy(info->version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
+       usb_make_path(dev->udev, info->bus_info, sizeof info->bus_info);
+}
 
-       dev = netdev->priv;
-       if (get_user(cmd, (int __user *) uaddr))
-               return -EFAULT;
+static int rtl8150_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+       rtl8150_t *dev = netdev_priv(netdev);
+       short lpa, bmcr;
 
-       switch (cmd) {
-       case ETHTOOL_GDRVINFO:{
-               struct ethtool_drvinfo info = { ETHTOOL_GDRVINFO };
-
-               strncpy(info.driver, driver_name, ETHTOOL_BUSINFO_LEN);
-               strncpy(info.version, DRIVER_VERSION, ETHTOOL_BUSINFO_LEN);
-               usb_make_path(dev->udev, info.bus_info, sizeof info.bus_info);
-               if (copy_to_user(uaddr, &info, sizeof(info)))
-                       return -EFAULT;
-               return 0;
-               }
-       case ETHTOOL_GSET:{
-               struct ethtool_cmd ecmd;
-               short lpa, bmcr;
-
-               if (copy_from_user(&ecmd, uaddr, sizeof(ecmd)))
-                       return -EFAULT;
-               ecmd.supported = (SUPPORTED_10baseT_Half |
-                                 SUPPORTED_10baseT_Full |
-                                 SUPPORTED_100baseT_Half |
-                                 SUPPORTED_100baseT_Full |
-                                 SUPPORTED_Autoneg |
-                                 SUPPORTED_TP | SUPPORTED_MII);
-               ecmd.port = PORT_TP;
-               ecmd.transceiver = XCVR_INTERNAL;
-               ecmd.phy_address = dev->phy;
-               get_registers(dev, BMCR, 2, &bmcr);
-               get_registers(dev, ANLP, 2, &lpa);
-               if (bmcr & BMCR_ANENABLE) {
-                       ecmd.autoneg = AUTONEG_ENABLE;
-                       ecmd.speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?
-                                    SPEED_100 : SPEED_10;
-                       if (ecmd.speed == SPEED_100)
-                               ecmd.duplex = (lpa & LPA_100FULL) ?
-                                   DUPLEX_FULL : DUPLEX_HALF;
-                       else
-                               ecmd.duplex = (lpa & LPA_10FULL) ?
-                                   DUPLEX_FULL : DUPLEX_HALF;
-               } else {
-                       ecmd.autoneg = AUTONEG_DISABLE;
-                       ecmd.speed = (bmcr & BMCR_SPEED100) ?
-                           SPEED_100 : SPEED_10;
-                       ecmd.duplex = (bmcr & BMCR_FULLDPLX) ?
+       ecmd->supported = (SUPPORTED_10baseT_Half |
+                         SUPPORTED_10baseT_Full |
+                         SUPPORTED_100baseT_Half |
+                         SUPPORTED_100baseT_Full |
+                         SUPPORTED_Autoneg |
+                         SUPPORTED_TP | SUPPORTED_MII);
+       ecmd->port = PORT_TP;
+       ecmd->transceiver = XCVR_INTERNAL;
+       ecmd->phy_address = dev->phy;
+       get_registers(dev, BMCR, 2, &bmcr);
+       get_registers(dev, ANLP, 2, &lpa);
+       if (bmcr & BMCR_ANENABLE) {
+               ecmd->autoneg = AUTONEG_ENABLE;
+               ecmd->speed = (lpa & (LPA_100HALF | LPA_100FULL)) ?
+                            SPEED_100 : SPEED_10;
+               if (ecmd->speed == SPEED_100)
+                       ecmd->duplex = (lpa & LPA_100FULL) ?
                            DUPLEX_FULL : DUPLEX_HALF;
-               }
-               if (copy_to_user(uaddr, &ecmd, sizeof(ecmd)))
-                       return -EFAULT;
-               return 0;
-               }
-       case ETHTOOL_SSET:
-               return -ENOTSUPP;
-       case ETHTOOL_GLINK:{
-               struct ethtool_value edata = { ETHTOOL_GLINK };
-
-               edata.data = netif_carrier_ok(netdev);
-               if (copy_to_user(uaddr, &edata, sizeof(edata)))
-                       return -EFAULT;
-               return 0;
-               }
-       default:
-               return -EOPNOTSUPP;
+               else
+                       ecmd->duplex = (lpa & LPA_10FULL) ?
+                           DUPLEX_FULL : DUPLEX_HALF;
+       } else {
+               ecmd->autoneg = AUTONEG_DISABLE;
+               ecmd->speed = (bmcr & BMCR_SPEED100) ?
+                   SPEED_100 : SPEED_10;
+               ecmd->duplex = (bmcr & BMCR_FULLDPLX) ?
+                   DUPLEX_FULL : DUPLEX_HALF;
        }
+       return 0;
 }
 
+static struct ethtool_ops ops = {
+       .get_drvinfo = rtl8150_get_drvinfo,
+       .get_settings = rtl8150_get_settings,
+       .get_link = ethtool_op_get_link
+};
+
 static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
 {
-       rtl8150_t *dev;
-       u16 *data;
-       int res;
-
-       dev = netdev->priv;
-       data = (u16 *) & rq->ifr_ifru;
-       res = 0;
+       rtl8150_t *dev = netdev_priv(netdev);
+       u16 *data = (u16 *) & rq->ifr_ifru;
+       int res = 0;
 
        switch (cmd) {
-       case SIOCETHTOOL:
-               res = rtl8150_ethtool_ioctl(netdev, rq->ifr_data);
-               break;
        case SIOCDEVPRIVATE:
                data[0] = dev->phy;
        case SIOCDEVPRIVATE + 1:
@@ -887,23 +900,18 @@ static int rtl8150_probe(struct usb_interface *intf,
        rtl8150_t *dev;
        struct net_device *netdev;
 
-       dev = kmalloc(sizeof(rtl8150_t), GFP_KERNEL);
-       if (!dev) {
+       netdev = alloc_etherdev(sizeof(rtl8150_t));
+       if (!netdev) {
                err("Out of memory");
                return -ENOMEM;
-       } else
-               memset(dev, 0, sizeof(rtl8150_t));
+       }
+
+       dev = netdev_priv(netdev);
+       memset(dev, 0, sizeof(rtl8150_t));
 
        dev->intr_buff = kmalloc(INTBUFSIZE, GFP_KERNEL);
        if (!dev->intr_buff) {
-               kfree(dev);
-               return -ENOMEM;
-       }
-       netdev = alloc_etherdev(0);
-       if (!netdev) {
-               kfree(dev->intr_buff);
-               kfree(dev);
-               err("Oh boy, out of memory again?!?");
+               free_netdev(netdev);
                return -ENOMEM;
        }
 
@@ -913,7 +921,6 @@ static int rtl8150_probe(struct usb_interface *intf,
        dev->udev = udev;
        dev->netdev = netdev;
        SET_MODULE_OWNER(netdev);
-       netdev->priv = dev;
        netdev->open = rtl8150_open;
        netdev->stop = rtl8150_close;
        netdev->do_ioctl = rtl8150_ioctl;
@@ -924,6 +931,7 @@ static int rtl8150_probe(struct usb_interface *intf,
        netdev->set_mac_address = rtl8150_set_mac_address;
        netdev->get_stats = rtl8150_netdev_stats;
        netdev->mtu = RTL8150_MTU;
+       SET_ETHTOOL_OPS(netdev, &ops);
        dev->intr_interval = 100;       /* 100ms */
 
        if (!alloc_all_urbs(dev)) {
@@ -936,7 +944,6 @@ static int rtl8150_probe(struct usb_interface *intf,
        }
        fill_skb_pool(dev);
        set_ethernet_addr(dev);
-       info("%s: rtl8150 is detected", netdev->name);
        
        usb_set_intfdata(intf, dev);
        SET_NETDEV_DEV(netdev, &intf->dev);
@@ -944,6 +951,9 @@ static int rtl8150_probe(struct usb_interface *intf,
                err("couldn't register the device");
                goto out2;
        }
+
+       info("%s: rtl8150 is detected", netdev->name);
+
        return 0;
 
 out2:
@@ -954,7 +964,6 @@ out1:
 out:
        kfree(dev->intr_buff);
        free_netdev(netdev);
-       kfree(dev);
        return -EIO;
 }
 
@@ -965,15 +974,16 @@ static void rtl8150_disconnect(struct usb_interface *intf)
        usb_set_intfdata(intf, NULL);
        if (dev) {
                set_bit(RTL8150_UNPLUG, &dev->flags);
+               tasklet_disable(&dev->tl);
+               tasklet_kill(&dev->tl);
                unregister_netdev(dev->netdev);
                unlink_all_urbs(dev);
                free_all_urbs(dev);
                free_skb_pool(dev);
                if (dev->rx_skb)
                        dev_kfree_skb(dev->rx_skb);
-               free_netdev(dev->netdev);
                kfree(dev->intr_buff);
-               kfree(dev);
+               free_netdev(dev->netdev);
        }
 }