Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 /* qcusbnet.c - gobi network device | 1 /* qcusbnet.c - gobi network device |
| 2 * Copyright (c) 2010, Code Aurora Forum. All rights reserved. | 2 * Copyright (c) 2010, Code Aurora Forum. All rights reserved. |
| 3 | 3 |
| 4 * This program is free software; you can redistribute it and/or modify | 4 * This program is free software; you can redistribute it and/or modify |
| 5 * it under the terms of the GNU General Public License version 2 and | 5 * it under the terms of the GNU General Public License version 2 and |
| 6 * only version 2 as published by the Free Software Foundation. | 6 * only version 2 as published by the Free Software Foundation. |
| 7 | 7 |
| 8 * This program is distributed in the hope that it will be useful, | 8 * This program is distributed in the hope that it will be useful, |
| 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| (...skipping 10 matching lines...) Expand all Loading... | |
| 21 #include "qmi.h" | 21 #include "qmi.h" |
| 22 #include "qcusbnet.h" | 22 #include "qcusbnet.h" |
| 23 | 23 |
| 24 #define DRIVER_VERSION "1.0.110" | 24 #define DRIVER_VERSION "1.0.110" |
| 25 #define DRIVER_AUTHOR "Qualcomm Innovation Center" | 25 #define DRIVER_AUTHOR "Qualcomm Innovation Center" |
| 26 #define DRIVER_DESC "QCUSBNet2k" | 26 #define DRIVER_DESC "QCUSBNet2k" |
| 27 | 27 |
| 28 int qcusbnet_debug; | 28 int qcusbnet_debug; |
| 29 static struct class *devclass; | 29 static struct class *devclass; |
| 30 | 30 |
| 31 static void free_dev(struct kref *ref) | |
| 32 { | |
| 33 struct qcusbnet *dev = container_of(ref, struct qcusbnet, refcount); | |
| 34 kfree(dev); | |
| 35 } | |
| 36 | |
| 37 void qcusbnet_put(struct qcusbnet *dev) | |
| 38 { | |
| 39 kref_put(&dev->refcount, free_dev); | |
| 40 } | |
| 41 | |
| 42 struct qcusbnet *qcusbnet_get(struct qcusbnet *dev) | |
| 43 { | |
| 44 /* If we don't take dev->lock here, we can interleave with qc_deregister | |
| 45 * such that they set dying and drop their ref between our test and our | |
| 46 * kref_get(). Boo. :( */ | |
| 47 mutex_lock(&dev->lock); | |
|
Jason Glasgow
2011/03/09 23:47:55
What if the other thread "wins" the race and sets
Elly Fong-Jones
2011/03/10 18:29:13
There is something to what you say. I will meditat
| |
| 48 if (dev->dying || !dev->valid) { | |
| 49 mutex_unlock(&dev->lock); | |
| 50 return NULL; | |
| 51 } | |
| 52 kref_get(&dev->refcount); | |
| 53 mutex_unlock(&dev->lock); | |
| 54 return dev; | |
| 55 } | |
| 56 | |
| 31 int qc_suspend(struct usb_interface *iface, pm_message_t event) | 57 int qc_suspend(struct usb_interface *iface, pm_message_t event) |
| 32 { | 58 { |
| 33 struct usbnet *usbnet; | 59 struct usbnet *usbnet; |
| 34 struct qcusbnet *dev; | 60 struct qcusbnet *dev; |
| 35 | 61 |
| 36 if (!iface) | 62 if (!iface) |
| 37 return -ENOMEM; | 63 return -ENOMEM; |
| 38 | 64 |
| 39 usbnet = usb_get_intfdata(iface); | 65 usbnet = usb_get_intfdata(iface); |
| 40 | 66 |
| (...skipping 132 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 173 out->desc.bEndpointAddress); | 199 out->desc.bEndpointAddress); |
| 174 | 200 |
| 175 return 0; | 201 return 0; |
| 176 } | 202 } |
| 177 | 203 |
| 178 static void qcnet_unbind(struct usbnet *usbnet, struct usb_interface *iface) | 204 static void qcnet_unbind(struct usbnet *usbnet, struct usb_interface *iface) |
| 179 { | 205 { |
| 180 struct qcusbnet *dev = (struct qcusbnet *)usbnet->data[0]; | 206 struct qcusbnet *dev = (struct qcusbnet *)usbnet->data[0]; |
| 181 | 207 |
| 182 netif_carrier_off(usbnet->net); | 208 netif_carrier_off(usbnet->net); |
| 209 /* See the comments in qcusbnet_get() for an explanation of why we need | |
| 210 * this lock. */ | |
| 211 mutex_lock(&dev->lock); | |
| 183 qc_deregister(dev); | 212 qc_deregister(dev); |
| 213 mutex_unlock(&dev->lock); | |
| 184 | 214 |
| 215 usbnet->net->netdev_ops = NULL; | |
| 185 kfree(usbnet->net->netdev_ops); | 216 kfree(usbnet->net->netdev_ops); |
|
Jason Glasgow
2011/03/09 23:47:55
Like Olof said, kfree(NULL)?
Elly Fong-Jones
2011/03/10 18:29:13
Argh.
| |
| 186 » usbnet->net->netdev_ops = NULL; | 217 » qcusbnet_put(dev); |
| 187 | |
| 188 » kfree(dev); | |
| 189 } | 218 } |
| 190 | 219 |
| 191 static void qcnet_urbhook(struct urb *urb) | 220 static void qcnet_urbhook(struct urb *urb) |
| 192 { | 221 { |
| 193 unsigned long flags; | 222 unsigned long flags; |
| 194 struct worker *worker = urb->context; | 223 struct worker *worker = urb->context; |
| 195 if (!worker) { | 224 if (!worker) { |
| 196 DBG("bad context\n"); | 225 DBG("bad context\n"); |
| 197 return; | 226 return; |
| 198 } | 227 } |
| (...skipping 384 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 583 usbnet->net->netdev_ops = netdevops; | 612 usbnet->net->netdev_ops = netdevops; |
| 584 | 613 |
| 585 memset(&(dev->usbnet->net->stats), 0, sizeof(struct net_device_stats)); | 614 memset(&(dev->usbnet->net->stats), 0, sizeof(struct net_device_stats)); |
| 586 | 615 |
| 587 dev->iface = iface; | 616 dev->iface = iface; |
| 588 memset(&(dev->meid), '0', 14); | 617 memset(&(dev->meid), '0', 14); |
| 589 | 618 |
| 590 DBG("Mac Address: %pM\n", dev->usbnet->net->dev_addr); | 619 DBG("Mac Address: %pM\n", dev->usbnet->net->dev_addr); |
| 591 | 620 |
| 592 dev->valid = false; | 621 dev->valid = false; |
| 593 » memset(&dev->qmi, 0, sizeof(struct qmidev)); | 622 » memset(&dev->qmi, 0, sizeof(dev->qmi)); |
| 594 | 623 |
| 595 dev->qmi.devclass = devclass; | 624 dev->qmi.devclass = devclass; |
| 596 | 625 |
| 626 kref_init(&dev->refcount); | |
| 627 mutex_init(&dev->lock); | |
| 597 INIT_LIST_HEAD(&dev->qmi.clients); | 628 INIT_LIST_HEAD(&dev->qmi.clients); |
| 598 init_completion(&dev->worker.work); | 629 init_completion(&dev->worker.work); |
| 599 spin_lock_init(&dev->qmi.clients_lock); | 630 spin_lock_init(&dev->qmi.clients_lock); |
| 600 | 631 |
| 601 dev->down = 0; | 632 dev->down = 0; |
| 602 qc_setdown(dev, DOWN_NO_NDIS_CONNECTION); | 633 qc_setdown(dev, DOWN_NO_NDIS_CONNECTION); |
| 603 qc_setdown(dev, DOWN_NET_IFACE_STOPPED); | 634 qc_setdown(dev, DOWN_NET_IFACE_STOPPED); |
| 604 | 635 |
| 605 status = qc_register(dev); | 636 status = qc_register(dev); |
| 606 if (status) { | 637 if (status) { |
| (...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 640 } | 671 } |
| 641 module_exit(modexit); | 672 module_exit(modexit); |
| 642 | 673 |
| 643 MODULE_VERSION(DRIVER_VERSION); | 674 MODULE_VERSION(DRIVER_VERSION); |
| 644 MODULE_AUTHOR(DRIVER_AUTHOR); | 675 MODULE_AUTHOR(DRIVER_AUTHOR); |
| 645 MODULE_DESCRIPTION(DRIVER_DESC); | 676 MODULE_DESCRIPTION(DRIVER_DESC); |
| 646 MODULE_LICENSE("Dual BSD/GPL"); | 677 MODULE_LICENSE("Dual BSD/GPL"); |
| 647 | 678 |
| 648 module_param(qcusbnet_debug, bool, S_IRUGO | S_IWUSR); | 679 module_param(qcusbnet_debug, bool, S_IRUGO | S_IWUSR); |
| 649 MODULE_PARM_DESC(qcusbnet_debug, "Debugging enabled or not"); | 680 MODULE_PARM_DESC(qcusbnet_debug, "Debugging enabled or not"); |
| OLD | NEW |