]> www.pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - drivers/net/usb/pegasus.c
pegasus: minor resource shrinkage
[linux-2.6-omap-h63xx.git] / drivers / net / usb / pegasus.c
index c073929c4d7528c3ac77ae2d2ccc41e5b2903249..075e8e94225e29aae6f4ed9a0c13bcc358392d31 100644 (file)
@@ -1213,7 +1213,7 @@ static void pegasus_set_multicast(struct net_device *net)
                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;
@@ -1273,6 +1273,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)
 
@@ -1301,6 +1302,18 @@ static int pegasus_blacklisted(struct usb_device *udev)
        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)
 {
@@ -1310,12 +1323,17 @@ static int pegasus_probe(struct usb_interface *intf,
        int dev_index = id - pegasus_ids;
        int res = -ENOMEM;
 
-       usb_get_dev(dev);
+       if (pegasus_blacklisted(dev))
+               return -ENODEV;
 
-       if (pegasus_blacklisted(dev)) {
-               res = -ENODEV;
-               goto out;
+       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) {
@@ -1400,6 +1418,7 @@ out1:
        free_netdev(net);
 out:
        usb_put_dev(dev);
+       pegasus_dec_workqueue();
        return res;
 }
 
@@ -1425,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)
@@ -1468,7 +1488,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;
@@ -1504,15 +1524,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);
 }