net: convert pegasus driver to net_device_ops
[safe/jmp/linux-2.6] / drivers / net / usb / pegasus.c
index a05fd97..a8228d8 100644 (file)
@@ -93,17 +93,19 @@ module_param (msg_level, int, 0);
 MODULE_PARM_DESC (msg_level, "Override default message level");
 
 MODULE_DEVICE_TABLE(usb, pegasus_ids);
+static const struct net_device_ops pegasus_netdev_ops;
 
 static int update_eth_regs_async(pegasus_t *);
 /* Aargh!!! I _really_ hate such tweaks */
 static void ctrl_callback(struct urb *urb)
 {
        pegasus_t *pegasus = urb->context;
+       int status = urb->status;
 
        if (!pegasus)
                return;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                if (pegasus->flags & ETH_REGS_CHANGE) {
                        pegasus->flags &= ~ETH_REGS_CHANGE;
@@ -117,9 +119,9 @@ static void ctrl_callback(struct urb *urb)
        case -ENOENT:
                break;
        default:
-               if (netif_msg_drv(pegasus))
+               if (netif_msg_drv(pegasus) && printk_ratelimit())
                        dev_dbg(&pegasus->intf->dev, "%s, status %d\n",
-                               __FUNCTION__, urb->status);
+                               __func__, status);
        }
        pegasus->flags &= ~ETH_REGS_CHANGED;
        wake_up(&pegasus->ctrl_wait);
@@ -136,7 +138,7 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
        if (!buffer) {
                if (netif_msg_drv(pegasus))
                        dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
-                                       __FUNCTION__);
+                                       __func__);
                return -ENOMEM;
        }
        add_wait_queue(&pegasus->ctrl_wait, &wait);
@@ -149,8 +151,8 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
        pegasus->dr.bRequestType = PEGASUS_REQT_READ;
        pegasus->dr.bRequest = PEGASUS_REQ_GET_REGS;
        pegasus->dr.wValue = cpu_to_le16(0);
-       pegasus->dr.wIndex = cpu_to_le16p(&indx);
-       pegasus->dr.wLength = cpu_to_le16p(&size);
+       pegasus->dr.wIndex = cpu_to_le16(indx);
+       pegasus->dr.wLength = cpu_to_le16(size);
        pegasus->ctrl_urb->transfer_buffer_length = size;
 
        usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb,
@@ -166,9 +168,9 @@ static int get_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
                set_current_state(TASK_RUNNING);
                if (ret == -ENODEV)
                        netif_device_detach(pegasus->net);
-               if (netif_msg_drv(pegasus))
+               if (netif_msg_drv(pegasus) && printk_ratelimit())
                        dev_err(&pegasus->intf->dev, "%s, status %d\n",
-                                       __FUNCTION__, ret);
+                                       __func__, ret);
                goto out;
        }
 
@@ -192,7 +194,7 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
        if (!buffer) {
                if (netif_msg_drv(pegasus))
                        dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
-                                       __FUNCTION__);
+                                       __func__);
                return -ENOMEM;
        }
        memcpy(buffer, data, size);
@@ -207,8 +209,8 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
        pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
        pegasus->dr.bRequest = PEGASUS_REQ_SET_REGS;
        pegasus->dr.wValue = cpu_to_le16(0);
-       pegasus->dr.wIndex = cpu_to_le16p(&indx);
-       pegasus->dr.wLength = cpu_to_le16p(&size);
+       pegasus->dr.wIndex = cpu_to_le16(indx);
+       pegasus->dr.wLength = cpu_to_le16(size);
        pegasus->ctrl_urb->transfer_buffer_length = size;
 
        usb_fill_control_urb(pegasus->ctrl_urb, pegasus->usb,
@@ -224,7 +226,7 @@ static int set_registers(pegasus_t * pegasus, __u16 indx, __u16 size,
                        netif_device_detach(pegasus->net);
                if (netif_msg_drv(pegasus))
                        dev_err(&pegasus->intf->dev, "%s, status %d\n",
-                                       __FUNCTION__, ret);
+                                       __func__, ret);
                goto out;
        }
 
@@ -246,7 +248,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
        if (!tmp) {
                if (netif_msg_drv(pegasus))
                        dev_warn(&pegasus->intf->dev, "out of memory in %s\n",
-                                       __FUNCTION__);
+                                       __func__);
                return -ENOMEM;
        }
        memcpy(tmp, &data, 1);
@@ -260,7 +262,7 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
        pegasus->dr.bRequestType = PEGASUS_REQT_WRITE;
        pegasus->dr.bRequest = PEGASUS_REQ_SET_REG;
        pegasus->dr.wValue = cpu_to_le16(data);
-       pegasus->dr.wIndex = cpu_to_le16p(&indx);
+       pegasus->dr.wIndex = cpu_to_le16(indx);
        pegasus->dr.wLength = cpu_to_le16(1);
        pegasus->ctrl_urb->transfer_buffer_length = 1;
 
@@ -275,9 +277,9 @@ static int set_register(pegasus_t * pegasus, __u16 indx, __u8 data)
        if ((ret = usb_submit_urb(pegasus->ctrl_urb, GFP_ATOMIC))) {
                if (ret == -ENODEV)
                        netif_device_detach(pegasus->net);
-               if (netif_msg_drv(pegasus))
+               if (netif_msg_drv(pegasus) && printk_ratelimit())
                        dev_err(&pegasus->intf->dev, "%s, status %d\n",
-                                       __FUNCTION__, ret);
+                                       __func__, ret);
                goto out;
        }
 
@@ -310,7 +312,7 @@ static int update_eth_regs_async(pegasus_t * pegasus)
                        netif_device_detach(pegasus->net);
                if (netif_msg_drv(pegasus))
                        dev_err(&pegasus->intf->dev, "%s, status %d\n",
-                                       __FUNCTION__, ret);
+                                       __func__, ret);
        }
 
        return ret;
@@ -341,7 +343,7 @@ static int read_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 * regd)
        }
 fail:
        if (netif_msg_drv(pegasus))
-               dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+               dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
 
        return ret;
 }
@@ -378,7 +380,7 @@ static int write_mii_word(pegasus_t * pegasus, __u8 phy, __u8 indx, __u16 regd)
 
 fail:
        if (netif_msg_drv(pegasus))
-               dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+               dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
        return -ETIMEDOUT;
 }
 
@@ -415,7 +417,7 @@ static int read_eprom_word(pegasus_t * pegasus, __u8 index, __u16 * retdata)
 
 fail:
        if (netif_msg_drv(pegasus))
-               dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+               dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
        return -ETIMEDOUT;
 }
 
@@ -463,7 +465,7 @@ static int write_eprom_word(pegasus_t * pegasus, __u8 index, __u16 data)
                return ret;
 fail:
        if (netif_msg_drv(pegasus))
-               dev_warn(&pegasus->intf->dev, "%s failed\n", __FUNCTION__);
+               dev_warn(&pegasus->intf->dev, "%s failed\n", __func__);
        return -ETIMEDOUT;
 }
 #endif                         /* PEGASUS_WRITE_EEPROM */
@@ -475,7 +477,7 @@ static inline void get_node_id(pegasus_t * pegasus, __u8 * id)
 
        for (i = 0; i < 3; i++) {
                read_eprom_word(pegasus, i, &w16);
-               ((__le16 *) id)[i] = cpu_to_le16p(&w16);
+               ((__le16 *) id)[i] = cpu_to_le16(w16);
        }
 }
 
@@ -611,6 +613,7 @@ static void read_bulk_callback(struct urb *urb)
        pegasus_t *pegasus = urb->context;
        struct net_device *net;
        int rx_status, count = urb->actual_length;
+       int status = urb->status;
        u8 *buf = urb->transfer_buffer;
        __u16 pkt_len;
 
@@ -621,7 +624,7 @@ static void read_bulk_callback(struct urb *urb)
        if (!netif_device_present(net) || !netif_running(net))
                return;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                break;
        case -ETIME:
@@ -639,11 +642,11 @@ static void read_bulk_callback(struct urb *urb)
        case -ECONNRESET:
        case -ESHUTDOWN:
                if (netif_msg_ifdown(pegasus))
-                       pr_debug("%s: rx unlink, %d\n", net->name, urb->status);
+                       pr_debug("%s: rx unlink, %d\n", net->name, status);
                return;
        default:
                if (netif_msg_rx_err(pegasus))
-                       pr_debug("%s: RX status %d\n", net->name, urb->status);
+                       pr_debug("%s: RX status %d\n", net->name, status);
                goto goon;
        }
 
@@ -768,15 +771,18 @@ done:
 static void write_bulk_callback(struct urb *urb)
 {
        pegasus_t *pegasus = urb->context;
-       struct net_device *net = pegasus->net;
+       struct net_device *net;
+       int status = urb->status;
 
        if (!pegasus)
                return;
 
+       net = pegasus->net;
+
        if (!netif_device_present(net) || !netif_running(net))
                return;
 
-       switch (urb->status) {
+       switch (status) {
        case -EPIPE:
                /* FIXME schedule_work() to clear the tx halt */
                netif_stop_queue(net);
@@ -788,11 +794,11 @@ static void write_bulk_callback(struct urb *urb)
        case -ECONNRESET:
        case -ESHUTDOWN:
                if (netif_msg_ifdown(pegasus))
-                       pr_debug("%s: tx unlink, %d\n", net->name, urb->status);
+                       pr_debug("%s: tx unlink, %d\n", net->name, status);
                return;
        default:
                if (netif_msg_tx_err(pegasus))
-                       pr_info("%s: TX status %d\n", net->name, urb->status);
+                       pr_info("%s: TX status %d\n", net->name, status);
                /* FALL THROUGH */
        case 0:
                break;
@@ -806,13 +812,13 @@ static void intr_callback(struct urb *urb)
 {
        pegasus_t *pegasus = urb->context;
        struct net_device *net;
-       int status;
+       int res, status = urb->status;
 
        if (!pegasus)
                return;
        net = pegasus->net;
 
-       switch (urb->status) {
+       switch (status) {
        case 0:
                break;
        case -ECONNRESET:       /* unlink */
@@ -825,7 +831,7 @@ static void intr_callback(struct urb *urb)
                 */
                if (netif_msg_timer(pegasus))
                        pr_debug("%s: intr status %d\n", net->name,
-                                       urb->status);
+                                       status);
        }
 
        if (urb->actual_length >= 6) {
@@ -852,12 +858,12 @@ static void intr_callback(struct urb *urb)
                pegasus->stats.rx_missed_errors += ((d[3] & 0x7f) << 8) | d[4];
        }
 
-       status = usb_submit_urb(urb, GFP_ATOMIC);
-       if (status == -ENODEV)
+       res = usb_submit_urb(urb, GFP_ATOMIC);
+       if (res == -ENODEV)
                netif_device_detach(pegasus->net);
-       if (status && netif_msg_timer(pegasus))
+       if (res && netif_msg_timer(pegasus))
                printk(KERN_ERR "%s: can't resubmit interrupt urb, %d\n",
-                               net->name, status);
+                               net->name, res);
 }
 
 static void pegasus_tx_timeout(struct net_device *net)
@@ -1126,12 +1132,8 @@ pegasus_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
        pegasus_t *pegasus;
 
-       if (in_atomic())
-               return 0;
-
        pegasus = netdev_priv(dev);
        mii_ethtool_gset(&pegasus->mii, ecmd);
-
        return 0;
 }
 
@@ -1211,17 +1213,18 @@ static void pegasus_set_multicast(struct net_device *net)
                pegasus->eth_regs[EthCtrl2] |= RX_PROMISCUOUS;
                if (netif_msg_link(pegasus))
                        pr_info("%s: Promiscuous mode enabled.\n", net->name);
-       } else if (net->mc_count ||
-                  (net->flags & IFF_ALLMULTI)) {
+       } else if (net->mc_count || (net->flags & IFF_ALLMULTI)) {
                pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST;
                pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
                if (netif_msg_link(pegasus))
-                       pr_info("%s: set allmulti\n", net->name);
+                       pr_debug("%s: set allmulti\n", net->name);
        } else {
                pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST;
                pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS;
        }
 
+       pegasus->ctrl_urb->status = 0;
+
        pegasus->flags |= ETH_REGS_CHANGE;
        ctrl_callback(pegasus->ctrl_urb);
 }
@@ -1274,6 +1277,7 @@ static inline void setup_pegasus_II(pegasus_t * pegasus)
 }
 
 
+static int pegasus_count;
 static struct workqueue_struct *pegasus_workqueue = NULL;
 #define CARRIER_CHECK_DELAY (2 * HZ)
 
@@ -1287,6 +1291,33 @@ static void check_carrier(struct work_struct *work)
        }
 }
 
+static int pegasus_blacklisted(struct usb_device *udev)
+{
+       struct usb_device_descriptor *udd = &udev->descriptor;
+
+       /* Special quirk to keep the driver from handling the Belkin Bluetooth
+        * dongle which happens to have the same ID.
+        */
+       if ((udd->idVendor == VENDOR_BELKIN && udd->idProduct == 0x0121) &&
+           (udd->bDeviceClass == USB_CLASS_WIRELESS_CONTROLLER) &&
+           (udd->bDeviceProtocol == 1))
+               return 1;
+
+       return 0;
+}
+
+/* we rely on probe() and remove() being serialized so we
+ * don't need extra locking on pegasus_count.
+ */
+static void pegasus_dec_workqueue(void)
+{
+       pegasus_count--;
+       if (pegasus_count == 0) {
+               destroy_workqueue(pegasus_workqueue);
+               pegasus_workqueue = NULL;
+       }
+}
+
 static int pegasus_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -1296,7 +1327,18 @@ static int pegasus_probe(struct usb_interface *intf,
        int dev_index = id - pegasus_ids;
        int res = -ENOMEM;
 
+       if (pegasus_blacklisted(dev))
+               return -ENODEV;
+
+       if (pegasus_count == 0) {
+               pegasus_workqueue = create_singlethread_workqueue("pegasus");
+               if (!pegasus_workqueue)
+                       return -ENOMEM;
+       }
+       pegasus_count++;
+
        usb_get_dev(dev);
+
        net = alloc_etherdev(sizeof(struct pegasus));
        if (!net) {
                dev_err(&intf->dev, "can't allocate %s\n", "device");
@@ -1304,7 +1346,6 @@ static int pegasus_probe(struct usb_interface *intf,
        }
 
        pegasus = netdev_priv(net);
-       memset(pegasus, 0, sizeof (struct pegasus));
        pegasus->dev_index = dev_index;
        init_waitqueue_head(&pegasus->ctrl_wait);
 
@@ -1320,15 +1361,10 @@ static int pegasus_probe(struct usb_interface *intf,
        pegasus->intf = intf;
        pegasus->usb = dev;
        pegasus->net = net;
-       SET_MODULE_OWNER(net);
-       net->open = pegasus_open;
-       net->stop = pegasus_close;
+
+
        net->watchdog_timeo = PEGASUS_TX_TIMEOUT;
-       net->tx_timeout = pegasus_tx_timeout;
-       net->do_ioctl = pegasus_ioctl;
-       net->hard_start_xmit = pegasus_start_xmit;
-       net->set_multicast_list = pegasus_set_multicast;
-       net->get_stats = pegasus_netdev_stats;
+       net->netdev_ops = &pegasus_netdev_ops;
        SET_ETHTOOL_OPS(net, &ops);
        pegasus->mii.dev = net;
        pegasus->mii.mdio_read = mdio_read;
@@ -1367,12 +1403,10 @@ static int pegasus_probe(struct usb_interface *intf,
        queue_delayed_work(pegasus_workqueue, &pegasus->carrier_check,
                                CARRIER_CHECK_DELAY);
 
-       dev_info(&intf->dev, "%s, %s, %02x:%02x:%02x:%02x:%02x:%02x\n",
-               net->name,
-               usb_dev_id[dev_index].name,
-               net->dev_addr [0], net->dev_addr [1],
-               net->dev_addr [2], net->dev_addr [3],
-               net->dev_addr [4], net->dev_addr [5]);
+       dev_info(&intf->dev, "%s, %s, %pM\n",
+                net->name,
+                usb_dev_id[dev_index].name,
+                net->dev_addr);
        return 0;
 
 out3:
@@ -1384,6 +1418,7 @@ out1:
        free_netdev(net);
 out:
        usb_put_dev(dev);
+       pegasus_dec_workqueue();
        return res;
 }
 
@@ -1409,6 +1444,7 @@ static void pegasus_disconnect(struct usb_interface *intf)
                pegasus->rx_skb = NULL;
        }
        free_netdev(pegasus->net);
+       pegasus_dec_workqueue();
 }
 
 static int pegasus_suspend (struct usb_interface *intf, pm_message_t message)
@@ -1443,6 +1479,16 @@ static int pegasus_resume (struct usb_interface *intf)
        return 0;
 }
 
+static const struct net_device_ops pegasus_netdev_ops = {
+       .ndo_open =                     pegasus_open,
+       .ndo_stop =                     pegasus_close,
+       .ndo_do_ioctl =                 pegasus_ioctl,
+       .ndo_start_xmit =               pegasus_start_xmit,
+       .ndo_set_multicast_list =       pegasus_set_multicast,
+       .ndo_get_stats =                pegasus_netdev_stats,
+       .ndo_tx_timeout =               pegasus_tx_timeout,
+};
+
 static struct usb_driver pegasus_driver = {
        .name = driver_name,
        .probe = pegasus_probe,
@@ -1452,7 +1498,7 @@ static struct usb_driver pegasus_driver = {
        .resume = pegasus_resume,
 };
 
-static void parse_id(char *id)
+static void __init parse_id(char *id)
 {
        unsigned int vendor_id=0, device_id=0, flags=0, i=0;
        char *token, *name=NULL;
@@ -1488,15 +1534,11 @@ static int __init pegasus_init(void)
        pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION);
        if (devid)
                parse_id(devid);
-       pegasus_workqueue = create_singlethread_workqueue("pegasus");
-       if (!pegasus_workqueue)
-               return -ENOMEM;
        return usb_register(&pegasus_driver);
 }
 
 static void __exit pegasus_exit(void)
 {
-       destroy_workqueue(pegasus_workqueue);
        usb_deregister(&pegasus_driver);
 }