1 /* qcusbnet.c - gobi network device
2 * Copyright (c) 2011, Code Aurora Forum. All rights reserved.
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
6 * only version 2 as published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 #include "qmidevice.h"
24 #include <linux/module.h>
25 #include <linux/ctype.h>
27 #define DRIVER_VERSION "1.0.110+google"
28 #define DRIVER_AUTHOR "Qualcomm Innovation Center"
29 #define DRIVER_DESC "gobi"
31 static LIST_HEAD(qcusbnet_list);
32 static DEFINE_MUTEX(qcusbnet_lock);
35 static struct class *devclass;
37 static void free_dev(struct kref *ref)
39 struct qcusbnet *dev = container_of(ref, struct qcusbnet, refcount);
44 void qcusbnet_put(struct qcusbnet *dev)
46 mutex_lock(&qcusbnet_lock);
47 kref_put(&dev->refcount, free_dev);
48 mutex_unlock(&qcusbnet_lock);
51 struct qcusbnet *qcusbnet_get(struct qcusbnet *key)
53 /* Given a putative qcusbnet struct, return either the struct itself
54 * (with a ref taken) if the struct is still visible, or NULL if it's
55 * not. This prevents object-visibility races where someone is looking
56 * up an object as the last ref gets dropped; dropping the last ref and
57 * removing the object from the list are atomic with respect to getting
59 struct qcusbnet *entry;
60 mutex_lock(&qcusbnet_lock);
61 list_for_each_entry(entry, &qcusbnet_list, node) {
63 kref_get(&entry->refcount);
64 mutex_unlock(&qcusbnet_lock);
68 mutex_unlock(&qcusbnet_lock);
72 int qc_suspend(struct usb_interface *iface, pm_message_t event)
74 struct usbnet *usbnet;
80 usbnet = usb_get_intfdata(iface);
82 if (!usbnet || !usbnet->net) {
83 DBG("failed to get netdevice\n");
87 dev = (struct qcusbnet *)usbnet->data[0];
89 DBG("failed to get QMIDevice\n");
93 if (!(event.event & PM_EVENT_AUTO)) {
94 DBG("device suspended to power level %d\n",
96 qc_setdown(dev, DOWN_DRIVER_SUSPENDED);
98 DBG("device autosuspend\n");
101 if (event.event & PM_EVENT_SUSPEND) {
103 usbnet->udev->reset_resume = 0;
104 iface->dev.power.power_state.event = event.event;
106 usbnet->udev->reset_resume = 1;
109 return usbnet_suspend(iface, event);
112 static int qc_resume(struct usb_interface *iface)
114 struct usbnet *usbnet;
115 struct qcusbnet *dev;
122 usbnet = usb_get_intfdata(iface);
124 if (!usbnet || !usbnet->net) {
125 DBG("failed to get netdevice\n");
129 dev = (struct qcusbnet *)usbnet->data[0];
131 DBG("failed to get QMIDevice\n");
135 oldstate = iface->dev.power.power_state.event;
136 iface->dev.power.power_state.event = PM_EVENT_ON;
137 DBG("resuming from power mode %d\n", oldstate);
139 if (oldstate & PM_EVENT_SUSPEND) {
140 qc_cleardown(dev, DOWN_DRIVER_SUSPENDED);
142 ret = usbnet_resume(iface);
144 DBG("usbnet_resume error %d\n", ret);
148 ret = qc_startread(dev);
150 DBG("qc_startread error %d\n", ret);
154 complete(&dev->worker.work);
156 DBG("nothing to resume\n");
163 static int qcnet_bind(struct usbnet *usbnet, struct usb_interface *iface)
167 struct usb_host_endpoint *endpoint = NULL;
168 struct usb_host_endpoint *in = NULL;
169 struct usb_host_endpoint *out = NULL;
171 if (iface->num_altsetting != 1) {
172 DBG("invalid num_altsetting %u\n", iface->num_altsetting);
176 if (iface->cur_altsetting->desc.bInterfaceNumber != 0
177 && iface->cur_altsetting->desc.bInterfaceNumber != 5) {
178 DBG("invalid interface %d\n",
179 iface->cur_altsetting->desc.bInterfaceNumber);
183 numends = iface->cur_altsetting->desc.bNumEndpoints;
184 for (i = 0; i < numends; i++) {
185 endpoint = iface->cur_altsetting->endpoint + i;
187 DBG("invalid endpoint %u\n", i);
191 if (usb_endpoint_dir_in(&endpoint->desc)
192 && !usb_endpoint_xfer_int(&endpoint->desc)) {
194 } else if (!usb_endpoint_dir_out(&endpoint->desc)) {
200 DBG("invalid endpoints\n");
204 if (usb_set_interface(usbnet->udev,
205 iface->cur_altsetting->desc.bInterfaceNumber, 0)) {
206 DBG("unable to set interface\n");
210 usbnet->in = usb_rcvbulkpipe(usbnet->udev, in->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
211 usbnet->out = usb_sndbulkpipe(usbnet->udev, out->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
213 DBG("in %x, out %x\n",
214 in->desc.bEndpointAddress,
215 out->desc.bEndpointAddress);
220 static void qcnet_unbind(struct usbnet *usbnet, struct usb_interface *iface)
222 struct qcusbnet *dev = (struct qcusbnet *)usbnet->data[0];
224 netif_carrier_off(usbnet->net);
227 kfree(usbnet->net->netdev_ops);
228 usbnet->net->netdev_ops = NULL;
229 /* drop the list's ref */
233 static void qcnet_urbhook(struct urb *urb)
236 struct worker *worker = urb->context;
238 DBG("bad context\n");
243 DBG("urb finished with error %d\n", urb->status);
246 spin_lock_irqsave(&worker->active_lock, flags);
247 worker->active = ERR_PTR(-EAGAIN);
248 spin_unlock_irqrestore(&worker->active_lock, flags);
249 /* XXX-fix race against qcnet_stop()? */
250 complete(&worker->work);
254 static void qcnet_txtimeout(struct net_device *netdev)
256 struct list_head *node, *tmp;
257 struct qcusbnet *dev;
258 struct worker *worker;
260 unsigned long activeflags, listflags;
261 struct usbnet *usbnet = netdev_priv(netdev);
263 if (!usbnet || !usbnet->net) {
264 DBG("failed to get usbnet device\n");
268 dev = (struct qcusbnet *)usbnet->data[0];
270 DBG("failed to get QMIDevice\n");
273 worker = &dev->worker;
277 spin_lock_irqsave(&worker->active_lock, activeflags);
279 usb_kill_urb(worker->active);
280 spin_unlock_irqrestore(&worker->active_lock, activeflags);
282 spin_lock_irqsave(&worker->urbs_lock, listflags);
283 list_for_each_safe(node, tmp, &worker->urbs) {
284 req = list_entry(node, struct urbreq, node);
285 usb_free_urb(req->urb);
286 list_del(&req->node);
289 spin_unlock_irqrestore(&worker->urbs_lock, listflags);
291 complete(&worker->work);
294 static int qcnet_worker(void *arg)
296 struct list_head *node, *tmp;
297 unsigned long activeflags, listflags;
300 struct usb_device *usbdev;
301 struct worker *worker = arg;
303 DBG("passed null pointer\n");
307 usbdev = interface_to_usbdev(worker->iface);
309 DBG("traffic thread started\n");
311 while (!worker->exit && !kthread_should_stop()) {
312 wait_for_completion_interruptible(&worker->work);
314 if (worker->exit || kthread_should_stop()) {
315 spin_lock_irqsave(&worker->active_lock, activeflags);
316 if (worker->active) {
317 usb_kill_urb(worker->active);
319 spin_unlock_irqrestore(&worker->active_lock, activeflags);
321 spin_lock_irqsave(&worker->urbs_lock, listflags);
322 list_for_each_safe(node, tmp, &worker->urbs) {
323 req = list_entry(node, struct urbreq, node);
324 usb_free_urb(req->urb);
325 list_del(&req->node);
328 spin_unlock_irqrestore(&worker->urbs_lock, listflags);
333 spin_lock_irqsave(&worker->active_lock, activeflags);
334 if (IS_ERR(worker->active) && PTR_ERR(worker->active) == -EAGAIN) {
335 worker->active = NULL;
336 spin_unlock_irqrestore(&worker->active_lock, activeflags);
337 usb_autopm_put_interface(worker->iface);
338 spin_lock_irqsave(&worker->active_lock, activeflags);
341 if (worker->active) {
342 spin_unlock_irqrestore(&worker->active_lock, activeflags);
346 spin_lock_irqsave(&worker->urbs_lock, listflags);
347 if (list_empty(&worker->urbs)) {
348 spin_unlock_irqrestore(&worker->urbs_lock, listflags);
349 spin_unlock_irqrestore(&worker->active_lock, activeflags);
353 req = list_first_entry(&worker->urbs, struct urbreq, node);
354 list_del(&req->node);
355 spin_unlock_irqrestore(&worker->urbs_lock, listflags);
357 worker->active = req->urb;
358 spin_unlock_irqrestore(&worker->active_lock, activeflags);
360 status = usb_autopm_get_interface(worker->iface);
362 DBG("unable to autoresume interface: %d\n", status);
363 if (status == -EPERM) {
364 qc_suspend(worker->iface, PMSG_SUSPEND);
367 spin_lock_irqsave(&worker->urbs_lock, listflags);
368 list_add(&req->node, &worker->urbs);
369 spin_unlock_irqrestore(&worker->urbs_lock, listflags);
371 spin_lock_irqsave(&worker->active_lock, activeflags);
372 worker->active = NULL;
373 spin_unlock_irqrestore(&worker->active_lock, activeflags);
378 status = usb_submit_urb(worker->active, GFP_KERNEL);
380 DBG("Failed to submit URB: %d. Packet dropped\n", status);
381 spin_lock_irqsave(&worker->active_lock, activeflags);
382 usb_free_urb(worker->active);
383 worker->active = NULL;
384 spin_unlock_irqrestore(&worker->active_lock, activeflags);
385 usb_autopm_put_interface(worker->iface);
386 complete(&worker->work);
392 DBG("traffic thread exiting\n");
393 worker->thread = NULL;
397 static int qcnet_startxmit(struct sk_buff *skb, struct net_device *netdev)
399 unsigned long listflags;
400 struct qcusbnet *dev;
401 struct worker *worker;
404 struct usbnet *usbnet = netdev_priv(netdev);
408 if (!usbnet || !usbnet->net) {
409 DBG("failed to get usbnet device\n");
410 return NETDEV_TX_BUSY;
413 dev = (struct qcusbnet *)usbnet->data[0];
415 DBG("failed to get QMIDevice\n");
416 return NETDEV_TX_BUSY;
418 worker = &dev->worker;
420 if (qc_isdown(dev, DOWN_DRIVER_SUSPENDED)) {
421 DBG("device is suspended\n");
423 return NETDEV_TX_BUSY;
426 req = kmalloc(sizeof(*req), GFP_ATOMIC);
428 DBG("unable to allocate URBList memory\n");
429 return NETDEV_TX_BUSY;
432 req->urb = usb_alloc_urb(0, GFP_ATOMIC);
436 DBG("unable to allocate URB\n");
437 return NETDEV_TX_BUSY;
440 data = kmalloc(skb->len, GFP_ATOMIC);
442 usb_free_urb(req->urb);
444 DBG("unable to allocate URB data\n");
445 return NETDEV_TX_BUSY;
447 memcpy(data, skb->data, skb->len);
449 usb_fill_bulk_urb(req->urb, dev->usbnet->udev, dev->usbnet->out,
450 data, skb->len, qcnet_urbhook, worker);
452 spin_lock_irqsave(&worker->urbs_lock, listflags);
453 list_add_tail(&req->node, &worker->urbs);
454 spin_unlock_irqrestore(&worker->urbs_lock, listflags);
456 complete(&worker->work);
458 netdev->trans_start = jiffies;
459 dev_kfree_skb_any(skb);
464 static int qcnet_open(struct net_device *netdev)
467 struct qcusbnet *dev;
468 struct usbnet *usbnet = netdev_priv(netdev);
471 DBG("failed to get usbnet device\n");
475 dev = (struct qcusbnet *)usbnet->data[0];
477 DBG("failed to get QMIDevice\n");
483 dev->worker.iface = dev->iface;
484 INIT_LIST_HEAD(&dev->worker.urbs);
485 dev->worker.active = NULL;
486 spin_lock_init(&dev->worker.urbs_lock);
487 spin_lock_init(&dev->worker.active_lock);
488 init_completion(&dev->worker.work);
490 dev->worker.exit = 0;
491 dev->worker.thread = kthread_run(qcnet_worker, &dev->worker, "qcnet_worker");
492 if (IS_ERR(dev->worker.thread)) {
493 DBG("AutoPM thread creation error\n");
494 return PTR_ERR(dev->worker.thread);
497 qc_cleardown(dev, DOWN_NET_IFACE_STOPPED);
499 status = dev->open(netdev);
501 usb_autopm_put_interface(dev->iface);
504 DBG("no USBNetOpen defined\n");
510 int qcnet_stop(struct net_device *netdev)
512 struct qcusbnet *dev;
513 struct usbnet *usbnet = netdev_priv(netdev);
515 if (!usbnet || !usbnet->net) {
516 DBG("failed to get netdevice\n");
520 dev = (struct qcusbnet *)usbnet->data[0];
522 DBG("failed to get QMIDevice\n");
526 qc_setdown(dev, DOWN_NET_IFACE_STOPPED);
527 dev->worker.exit = 1;
528 complete(&dev->worker.work);
529 kthread_stop(dev->worker.thread);
530 DBG("thread stopped\n");
532 if (dev->stop != NULL)
533 return dev->stop(netdev);
537 static const struct driver_info qc_netinfo = {
538 .description = "QCUSBNet Ethernet Device",
541 .unbind = qcnet_unbind,
545 #define MKVIDPID(v, p) \
548 .driver_info = (unsigned long)&qc_netinfo, \
551 static const struct usb_device_id qc_vidpids[] = {
552 MKVIDPID(0x05c6, 0x9215), /* Acer Gobi 2000 */
553 MKVIDPID(0x05c6, 0x9265), /* Asus Gobi 2000 */
554 MKVIDPID(0x16d8, 0x8002), /* CMOTech Gobi 2000 */
555 MKVIDPID(0x413c, 0x8186), /* Dell Gobi 2000 */
556 MKVIDPID(0x1410, 0xa010), /* Entourage Gobi 2000 */
557 MKVIDPID(0x1410, 0xa011), /* Entourage Gobi 2000 */
558 MKVIDPID(0x1410, 0xa012), /* Entourage Gobi 2000 */
559 MKVIDPID(0x1410, 0xa013), /* Entourage Gobi 2000 */
560 MKVIDPID(0x03f0, 0x251d), /* HP Gobi 2000 */
561 MKVIDPID(0x05c6, 0x9205), /* Lenovo Gobi 2000 */
562 MKVIDPID(0x05c6, 0x920b), /* Generic Gobi 2000 */
563 MKVIDPID(0x04da, 0x250f), /* Panasonic Gobi 2000 */
564 MKVIDPID(0x05c6, 0x9245), /* Samsung Gobi 2000 */
565 MKVIDPID(0x1199, 0x9001), /* Sierra Wireless Gobi 2000 */
566 MKVIDPID(0x1199, 0x9002), /* Sierra Wireless Gobi 2000 */
567 MKVIDPID(0x1199, 0x9003), /* Sierra Wireless Gobi 2000 */
568 MKVIDPID(0x1199, 0x9004), /* Sierra Wireless Gobi 2000 */
569 MKVIDPID(0x1199, 0x9005), /* Sierra Wireless Gobi 2000 */
570 MKVIDPID(0x1199, 0x9006), /* Sierra Wireless Gobi 2000 */
571 MKVIDPID(0x1199, 0x9007), /* Sierra Wireless Gobi 2000 */
572 MKVIDPID(0x1199, 0x9008), /* Sierra Wireless Gobi 2000 */
573 MKVIDPID(0x1199, 0x9009), /* Sierra Wireless Gobi 2000 */
574 MKVIDPID(0x1199, 0x900a), /* Sierra Wireless Gobi 2000 */
575 MKVIDPID(0x05c6, 0x9225), /* Sony Gobi 2000 */
576 MKVIDPID(0x05c6, 0x9235), /* Top Global Gobi 2000 */
577 MKVIDPID(0x05c6, 0x9275), /* iRex Technologies Gobi 2000 */
579 MKVIDPID(0x05c6, 0x920d), /* Qualcomm Gobi 3000 */
580 MKVIDPID(0x1410, 0xa021), /* Novatel Gobi 3000 */
584 MODULE_DEVICE_TABLE(usb, qc_vidpids);
586 static u8 nibble(unsigned char c)
588 if (likely(isdigit(c)))
591 if (likely(isxdigit(c)))
596 int qcnet_probe(struct usb_interface *iface, const struct usb_device_id *vidpids)
599 struct usbnet *usbnet;
600 struct qcusbnet *dev;
601 struct net_device_ops *netdevops;
605 status = usbnet_probe(iface, vidpids);
607 DBG("usbnet_probe failed %d\n", status);
611 usbnet = usb_get_intfdata(iface);
613 if (!usbnet || !usbnet->net) {
614 DBG("failed to get netdevice\n");
618 dev = kmalloc(sizeof(struct qcusbnet), GFP_KERNEL);
620 DBG("failed to allocate device buffers\n");
624 usbnet->data[0] = (unsigned long)dev;
626 dev->usbnet = usbnet;
628 netdevops = kmalloc(sizeof(struct net_device_ops), GFP_KERNEL);
630 DBG("failed to allocate net device ops\n");
633 memcpy(netdevops, usbnet->net->netdev_ops, sizeof(struct net_device_ops));
635 dev->open = netdevops->ndo_open;
636 netdevops->ndo_open = qcnet_open;
637 dev->stop = netdevops->ndo_stop;
638 netdevops->ndo_stop = qcnet_stop;
639 netdevops->ndo_start_xmit = qcnet_startxmit;
640 netdevops->ndo_tx_timeout = qcnet_txtimeout;
642 usbnet->net->netdev_ops = netdevops;
644 memset(&(dev->usbnet->net->stats), 0, sizeof(struct net_device_stats));
647 memset(&(dev->meid), '0', 14);
650 memset(&dev->qmi, 0, sizeof(dev->qmi));
652 dev->qmi.devclass = devclass;
654 kref_init(&dev->refcount);
655 INIT_LIST_HEAD(&dev->node);
656 INIT_LIST_HEAD(&dev->qmi.clients);
657 init_completion(&dev->worker.work);
658 spin_lock_init(&dev->qmi.clients_lock);
661 qc_setdown(dev, DOWN_NO_NDIS_CONNECTION);
662 qc_setdown(dev, DOWN_NET_IFACE_STOPPED);
664 status = qc_register(dev);
668 mutex_lock(&qcusbnet_lock);
669 /* Give our initial ref to the list */
670 list_add(&dev->node, &qcusbnet_list);
671 mutex_unlock(&qcusbnet_lock);
673 /* After calling qc_register, MEID is valid */
674 addr = &usbnet->net->dev_addr[0];
675 for (i = 0; i < 6; i++)
676 addr[i] = (nibble(dev->meid[i*2+2]) << 4)+
677 nibble(dev->meid[i*2+3]);
678 addr[0] &= 0xfe; /* clear multicast bit */
679 addr[0] |= 0x02; /* set local assignment bit (IEEE802) */
683 EXPORT_SYMBOL_GPL(qcnet_probe);
685 static struct usb_driver qcusbnet = {
687 .id_table = qc_vidpids,
688 .probe = qcnet_probe,
689 .disconnect = usbnet_disconnect,
690 .suspend = qc_suspend,
692 .supports_autosuspend = true,
695 static int __init modinit(void)
697 devclass = class_create(THIS_MODULE, "QCQMI");
698 if (IS_ERR(devclass)) {
699 DBG("error at class_create %ld\n", PTR_ERR(devclass));
702 printk(KERN_INFO "%s: %s\n", DRIVER_DESC, DRIVER_VERSION);
703 return usb_register(&qcusbnet);
705 module_init(modinit);
707 static void __exit modexit(void)
709 usb_deregister(&qcusbnet);
710 class_destroy(devclass);
712 module_exit(modexit);
714 MODULE_VERSION(DRIVER_VERSION);
715 MODULE_AUTHOR(DRIVER_AUTHOR);
716 MODULE_DESCRIPTION(DRIVER_DESC);
717 MODULE_LICENSE("Dual BSD/GPL");
719 module_param(qcusbnet_debug, bool, S_IRUGO | S_IWUSR);
720 MODULE_PARM_DESC(qcusbnet_debug, "Debugging enabled or not");