linux/drivers/usb/serial/qcserial.c History
<<
>>
Prefs
   1/*
   2 * Qualcomm Serial USB driver
   3 *
   4 *      Copyright (c) 2008 QUALCOMM Incorporated.
   5 *      Copyright (c) 2009 Greg Kroah-Hartman <gregkh@suse.de>
   6 *      Copyright (c) 2009 Novell Inc.
   7 *
   8 *      This program is free software; you can redistribute it and/or
   9 *      modify it under the terms of the GNU General Public License version
  10 *      2 as published by the Free Software Foundation.
  11 *
  12 */
  13
  14#include <linux/tty.h>
  15#include <linux/tty_flip.h>
  16#include <linux/usb.h>
  17#include <linux/usb/serial.h>
  18
  19#define DRIVER_AUTHOR "Qualcomm Inc"
  20#define DRIVER_DESC "Qualcomm USB Serial driver"
  21
  22static int debug;
  23
  24static const struct usb_device_id id_table[] = {
  25        {USB_DEVICE(0x05c6, 0x9211)},   /* Acer Gobi QDL device */
  26        {USB_DEVICE(0x05c6, 0x9212)},   /* Acer Gobi Modem Device */
  27        {USB_DEVICE(0x03f0, 0x1f1d)},   /* HP un2400 Gobi Modem Device */
  28        {USB_DEVICE(0x03f0, 0x201d)},   /* HP un2400 Gobi QDL Device */
  29        {USB_DEVICE(0x04da, 0x250d)},   /* Panasonic Gobi Modem device */
  30        {USB_DEVICE(0x04da, 0x250c)},   /* Panasonic Gobi QDL device */
  31        {USB_DEVICE(0x413c, 0x8172)},   /* Dell Gobi Modem device */
  32        {USB_DEVICE(0x413c, 0x8171)},   /* Dell Gobi QDL device */
  33        {USB_DEVICE(0x1410, 0xa001)},   /* Novatel Gobi Modem device */
  34        {USB_DEVICE(0x1410, 0xa008)},   /* Novatel Gobi QDL device */
  35        {USB_DEVICE(0x0b05, 0x1776)},   /* Asus Gobi Modem device */
  36        {USB_DEVICE(0x0b05, 0x1774)},   /* Asus Gobi QDL device */
  37        {USB_DEVICE(0x19d2, 0xfff3)},   /* ONDA Gobi Modem device */
  38        {USB_DEVICE(0x19d2, 0xfff2)},   /* ONDA Gobi QDL device */
  39        {USB_DEVICE(0x1557, 0x0a80)},   /* OQO Gobi QDL device */
  40        {USB_DEVICE(0x05c6, 0x9001)},   /* Generic Gobi Modem device */
  41        {USB_DEVICE(0x05c6, 0x9002)},   /* Generic Gobi Modem device */
  42        {USB_DEVICE(0x05c6, 0x9202)},   /* Generic Gobi Modem device */
  43        {USB_DEVICE(0x05c6, 0x9203)},   /* Generic Gobi Modem device */
  44        {USB_DEVICE(0x05c6, 0x9222)},   /* Generic Gobi Modem device */
  45        {USB_DEVICE(0x05c6, 0x9008)},   /* Generic Gobi QDL device */
  46        {USB_DEVICE(0x05c6, 0x9201)},   /* Generic Gobi QDL device */
  47        {USB_DEVICE(0x05c6, 0x9221)},   /* Generic Gobi QDL device */
  48        {USB_DEVICE(0x05c6, 0x9231)},   /* Generic Gobi QDL device */
  49        {USB_DEVICE(0x1f45, 0x0001)},   /* Unknown Gobi QDL device */
  50        {USB_DEVICE(0x413c, 0x8185)},   /* Dell Gobi 2000 QDL device (N0218, VU936) */
  51        {USB_DEVICE(0x413c, 0x8186)},   /* Dell Gobi 2000 Modem device (N0218, VU936) */
  52        {USB_DEVICE(0x05c6, 0x9224)},   /* Sony Gobi 2000 QDL device (N0279, VU730) */
  53        {USB_DEVICE(0x05c6, 0x9225)},   /* Sony Gobi 2000 Modem device (N0279, VU730) */
  54        {USB_DEVICE(0x05c6, 0x9244)},   /* Samsung Gobi 2000 QDL device (VL176) */
  55        {USB_DEVICE(0x05c6, 0x9245)},   /* Samsung Gobi 2000 Modem device (VL176) */
  56        {USB_DEVICE(0x03f0, 0x241d)},   /* HP Gobi 2000 QDL device (VP412) */
  57        {USB_DEVICE(0x03f0, 0x251d)},   /* HP Gobi 2000 Modem device (VP412) */
  58        {USB_DEVICE(0x05c6, 0x9214)},   /* Acer Gobi 2000 QDL device (VP413) */
  59        {USB_DEVICE(0x05c6, 0x9215)},   /* Acer Gobi 2000 Modem device (VP413) */
  60        {USB_DEVICE(0x05c6, 0x9264)},   /* Asus Gobi 2000 QDL device (VR305) */
  61        {USB_DEVICE(0x05c6, 0x9265)},   /* Asus Gobi 2000 Modem device (VR305) */
  62        {USB_DEVICE(0x05c6, 0x9234)},   /* Top Global Gobi 2000 QDL device (VR306) */
  63        {USB_DEVICE(0x05c6, 0x9235)},   /* Top Global Gobi 2000 Modem device (VR306) */
  64        {USB_DEVICE(0x05c6, 0x9274)},   /* iRex Technologies Gobi 2000 QDL device (VR307) */
  65        {USB_DEVICE(0x05c6, 0x9275)},   /* iRex Technologies Gobi 2000 Modem device (VR307) */
  66        {USB_DEVICE(0x1199, 0x9000)},   /* Sierra Wireless Gobi 2000 QDL device (VT773) */
  67        {USB_DEVICE(0x1199, 0x9001)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
  68        {USB_DEVICE(0x1199, 0x9002)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
  69        {USB_DEVICE(0x1199, 0x9003)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
  70        {USB_DEVICE(0x1199, 0x9004)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
  71        {USB_DEVICE(0x1199, 0x9005)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
  72        {USB_DEVICE(0x1199, 0x9006)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
  73        {USB_DEVICE(0x1199, 0x9007)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
  74        {USB_DEVICE(0x1199, 0x9008)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
  75        {USB_DEVICE(0x1199, 0x9009)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
  76        {USB_DEVICE(0x1199, 0x900a)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
  77        {USB_DEVICE(0x16d8, 0x8001)},   /* CMDTech Gobi 2000 QDL device (VU922) */
  78        {USB_DEVICE(0x16d8, 0x8002)},   /* CMDTech Gobi 2000 Modem device (VU922) */
  79        { }                             /* Terminating entry */
  80};
  81MODULE_DEVICE_TABLE(usb, id_table);
  82
  83static struct usb_driver qcdriver = {
  84        .name                   = "qcserial",
  85        .probe                  = usb_serial_probe,
  86        .disconnect             = usb_serial_disconnect,
  87        .id_table               = id_table,
  88        .suspend                = usb_serial_suspend,
  89        .resume                 = usb_serial_resume,
  90        .supports_autosuspend   = true,
  91};
  92
  93static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
  94{
  95        int retval = -ENODEV;
  96        __u8 nintf;
  97        __u8 ifnum;
  98
  99        dbg("%s", __func__);
 100
 101        nintf = serial->dev->actconfig->desc.bNumInterfaces;
 102        dbg("Num Interfaces = %d", nintf);
 103        ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
 104        dbg("This Interface = %d", ifnum);
 105
 106        switch (nintf) {
 107        case 1:
 108                /* QDL mode */
 109                if (serial->interface->num_altsetting == 2) {
 110                        struct usb_host_interface *intf;
 111
 112                        intf = &serial->interface->altsetting[1];
 113                        if (intf->desc.bNumEndpoints == 2) {
 114                                if (usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) &&
 115                                    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
 116                                        dbg("QDL port found");
 117                                        retval = usb_set_interface(serial->dev, ifnum, 1);
 118                                        if (retval < 0) {
 119                                                dev_err(&serial->dev->dev,
 120                                                        "Could not set interface, error %d\n",
 121                                                        retval);
 122                                                retval = -ENODEV;
 123                                        }
 124                                        return retval;
 125                                }
 126                        }
 127                }
 128                break;
 129
 130        case 4:
 131                /* Composite mode */
 132                if (ifnum == 2) {
 133                        dbg("Modem port found");
 134                        retval = usb_set_interface(serial->dev, ifnum, 0);
 135                        if (retval < 0) {
 136                                dev_err(&serial->dev->dev,
 137                                        "Could not set interface, error %d\n",
 138                                        retval);
 139                                retval = -ENODEV;
 140                        }
 141                        return retval;
 142                }
 143                break;
 144
 145        default:
 146                dev_err(&serial->dev->dev,
 147                        "unknown number of interfaces: %d\n", nintf);
 148                return -ENODEV;
 149        }
 150
 151        return retval;
 152}
 153
 154static struct usb_serial_driver qcdevice = {
 155        .driver = {
 156                .owner     = THIS_MODULE,
 157                .name      = "qcserial",
 158        },
 159        .description         = "Qualcomm USB modem",
 160        .id_table            = id_table,
 161        .usb_driver          = &qcdriver,
 162        .num_ports           = 1,
 163        .probe               = qcprobe,
 164};
 165
 166static int __init qcinit(void)
 167{
 168        int retval;
 169
 170        retval = usb_serial_register(&qcdevice);
 171        if (retval)
 172                return retval;
 173
 174        retval = usb_register(&qcdriver);
 175        if (retval) {
 176                usb_serial_deregister(&qcdevice);
 177                return retval;
 178        }
 179
 180        return 0;
 181}
 182
 183static void __exit qcexit(void)
 184{
 185        usb_deregister(&qcdriver);
 186        usb_serial_deregister(&qcdevice);
 187}
 188
 189module_init(qcinit);
 190module_exit(qcexit);
 191
 192MODULE_AUTHOR(DRIVER_AUTHOR);
 193MODULE_DESCRIPTION(DRIVER_DESC);
 194MODULE_LICENSE("GPL v2");
 195
 196module_param(debug, bool, S_IRUGO | S_IWUSR);
 197MODULE_PARM_DESC(debug, "Debug enabled or not");
 198
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.