diff options
Diffstat (limited to 'drivers/net/usb')
-rw-r--r-- | drivers/net/usb/pegasus.c | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/drivers/net/usb/pegasus.c b/drivers/net/usb/pegasus.c index c073929c4d75..075e8e94225e 100644 --- a/drivers/net/usb/pegasus.c +++ b/drivers/net/usb/pegasus.c | |||
@@ -1213,7 +1213,7 @@ static void pegasus_set_multicast(struct net_device *net) | |||
1213 | pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; | 1213 | pegasus->eth_regs[EthCtrl0] |= RX_MULTICAST; |
1214 | pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; | 1214 | pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; |
1215 | if (netif_msg_link(pegasus)) | 1215 | if (netif_msg_link(pegasus)) |
1216 | pr_info("%s: set allmulti\n", net->name); | 1216 | pr_debug("%s: set allmulti\n", net->name); |
1217 | } else { | 1217 | } else { |
1218 | pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; | 1218 | pegasus->eth_regs[EthCtrl0] &= ~RX_MULTICAST; |
1219 | pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; | 1219 | pegasus->eth_regs[EthCtrl2] &= ~RX_PROMISCUOUS; |
@@ -1273,6 +1273,7 @@ static inline void setup_pegasus_II(pegasus_t * pegasus) | |||
1273 | } | 1273 | } |
1274 | 1274 | ||
1275 | 1275 | ||
1276 | static int pegasus_count; | ||
1276 | static struct workqueue_struct *pegasus_workqueue = NULL; | 1277 | static struct workqueue_struct *pegasus_workqueue = NULL; |
1277 | #define CARRIER_CHECK_DELAY (2 * HZ) | 1278 | #define CARRIER_CHECK_DELAY (2 * HZ) |
1278 | 1279 | ||
@@ -1301,6 +1302,18 @@ static int pegasus_blacklisted(struct usb_device *udev) | |||
1301 | return 0; | 1302 | return 0; |
1302 | } | 1303 | } |
1303 | 1304 | ||
1305 | /* we rely on probe() and remove() being serialized so we | ||
1306 | * don't need extra locking on pegasus_count. | ||
1307 | */ | ||
1308 | static void pegasus_dec_workqueue(void) | ||
1309 | { | ||
1310 | pegasus_count--; | ||
1311 | if (pegasus_count == 0) { | ||
1312 | destroy_workqueue(pegasus_workqueue); | ||
1313 | pegasus_workqueue = NULL; | ||
1314 | } | ||
1315 | } | ||
1316 | |||
1304 | static int pegasus_probe(struct usb_interface *intf, | 1317 | static int pegasus_probe(struct usb_interface *intf, |
1305 | const struct usb_device_id *id) | 1318 | const struct usb_device_id *id) |
1306 | { | 1319 | { |
@@ -1310,12 +1323,17 @@ static int pegasus_probe(struct usb_interface *intf, | |||
1310 | int dev_index = id - pegasus_ids; | 1323 | int dev_index = id - pegasus_ids; |
1311 | int res = -ENOMEM; | 1324 | int res = -ENOMEM; |
1312 | 1325 | ||
1313 | usb_get_dev(dev); | 1326 | if (pegasus_blacklisted(dev)) |
1327 | return -ENODEV; | ||
1314 | 1328 | ||
1315 | if (pegasus_blacklisted(dev)) { | 1329 | if (pegasus_count == 0) { |
1316 | res = -ENODEV; | 1330 | pegasus_workqueue = create_singlethread_workqueue("pegasus"); |
1317 | goto out; | 1331 | if (!pegasus_workqueue) |
1332 | return -ENOMEM; | ||
1318 | } | 1333 | } |
1334 | pegasus_count++; | ||
1335 | |||
1336 | usb_get_dev(dev); | ||
1319 | 1337 | ||
1320 | net = alloc_etherdev(sizeof(struct pegasus)); | 1338 | net = alloc_etherdev(sizeof(struct pegasus)); |
1321 | if (!net) { | 1339 | if (!net) { |
@@ -1400,6 +1418,7 @@ out1: | |||
1400 | free_netdev(net); | 1418 | free_netdev(net); |
1401 | out: | 1419 | out: |
1402 | usb_put_dev(dev); | 1420 | usb_put_dev(dev); |
1421 | pegasus_dec_workqueue(); | ||
1403 | return res; | 1422 | return res; |
1404 | } | 1423 | } |
1405 | 1424 | ||
@@ -1425,6 +1444,7 @@ static void pegasus_disconnect(struct usb_interface *intf) | |||
1425 | pegasus->rx_skb = NULL; | 1444 | pegasus->rx_skb = NULL; |
1426 | } | 1445 | } |
1427 | free_netdev(pegasus->net); | 1446 | free_netdev(pegasus->net); |
1447 | pegasus_dec_workqueue(); | ||
1428 | } | 1448 | } |
1429 | 1449 | ||
1430 | static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) | 1450 | static int pegasus_suspend (struct usb_interface *intf, pm_message_t message) |
@@ -1468,7 +1488,7 @@ static struct usb_driver pegasus_driver = { | |||
1468 | .resume = pegasus_resume, | 1488 | .resume = pegasus_resume, |
1469 | }; | 1489 | }; |
1470 | 1490 | ||
1471 | static void parse_id(char *id) | 1491 | static void __init parse_id(char *id) |
1472 | { | 1492 | { |
1473 | unsigned int vendor_id=0, device_id=0, flags=0, i=0; | 1493 | unsigned int vendor_id=0, device_id=0, flags=0, i=0; |
1474 | char *token, *name=NULL; | 1494 | char *token, *name=NULL; |
@@ -1504,15 +1524,11 @@ static int __init pegasus_init(void) | |||
1504 | pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION); | 1524 | pr_info("%s: %s, " DRIVER_DESC "\n", driver_name, DRIVER_VERSION); |
1505 | if (devid) | 1525 | if (devid) |
1506 | parse_id(devid); | 1526 | parse_id(devid); |
1507 | pegasus_workqueue = create_singlethread_workqueue("pegasus"); | ||
1508 | if (!pegasus_workqueue) | ||
1509 | return -ENOMEM; | ||
1510 | return usb_register(&pegasus_driver); | 1527 | return usb_register(&pegasus_driver); |
1511 | } | 1528 | } |
1512 | 1529 | ||
1513 | static void __exit pegasus_exit(void) | 1530 | static void __exit pegasus_exit(void) |
1514 | { | 1531 | { |
1515 | destroy_workqueue(pegasus_workqueue); | ||
1516 | usb_deregister(&pegasus_driver); | 1532 | usb_deregister(&pegasus_driver); |
1517 | } | 1533 | } |
1518 | 1534 | ||