linux/drivers/usb/serial/qcserial.c
<<
>>
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 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        { }                             /* Terminating entry */
  51};
  52MODULE_DEVICE_TABLE(usb, id_table);
  53
  54static struct usb_driver qcdriver = {
  55        .name                   = "qcserial",
  56        .probe                  = usb_serial_probe,
  57        .disconnect             = usb_serial_disconnect,
  58        .id_table               = id_table,
  59        .suspend                = usb_serial_suspend,
  60        .resume                 = usb_serial_resume,
  61        .supports_autosuspend   = true,
  62};
  63
  64static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
  65{
  66        int retval = -ENODEV;
  67        __u8 nintf;
  68        __u8 ifnum;
  69
  70        dbg("%s", __func__);
  71
  72        nintf = serial->dev->actconfig->desc.bNumInterfaces;
  73        dbg("Num Interfaces = %d", nintf);
  74        ifnum = serial->interface->cur_altsetting->desc.bInterfaceNumber;
  75        dbg("This Interface = %d", ifnum);
  76
  77        switch (nintf) {
  78        case 1:
  79                /* QDL mode */
  80                if (serial->interface->num_altsetting == 2) {
  81                        struct usb_host_interface *intf;
  82
  83                        intf = &serial->interface->altsetting[1];
  84                        if (intf->desc.bNumEndpoints == 2) {
  85                                if (usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) &&
  86                                    usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
  87                                        dbg("QDL port found");
  88                                        retval = usb_set_interface(serial->dev, ifnum, 1);
  89                                        if (retval < 0) {
  90                                                dev_err(&serial->dev->dev,
  91                                                        "Could not set interface, error %d\n",
  92                                                        retval);
  93                                                retval = -ENODEV;
  94                                        }
  95                                        return retval;
  96                                }
  97                        }
  98                }
  99                break;
 100
 101        case 4:
 102                /* Composite mode */
 103                if (ifnum == 2) {
 104                        dbg("Modem port found");
 105                        retval = usb_set_interface(serial->dev, ifnum, 0);
 106                        if (retval < 0) {
 107                                dev_err(&serial->dev->dev,
 108                                        "Could not set interface, error %d\n",
 109                                        retval);
 110                                retval = -ENODEV;
 111                        }
 112                        return retval;
 113                }
 114                break;
 115
 116        default:
 117                dev_err(&serial->dev->dev,
 118                        "unknown number of interfaces: %d\n", nintf);
 119                return -ENODEV;
 120        }
 121
 122        return retval;
 123}
 124
 125static struct usb_serial_driver qcdevice = {
 126        .driver = {
 127                .owner     = THIS_MODULE,
 128                .name      = "qcserial",
 129        },
 130        .description         = "Qualcomm USB modem",
 131        .id_table            = id_table,
 132        .usb_driver          = &qcdriver,
 133        .num_ports           = 1,
 134        .probe               = qcprobe,
 135};
 136
 137static int __init qcinit(void)
 138{
 139        int retval;
 140
 141        retval = usb_serial_register(&qcdevice);
 142        if (retval)
 143                return retval;
 144
 145        retval = usb_register(&qcdriver);
 146        if (retval) {
 147                usb_serial_deregister(&qcdevice);
 148                return retval;
 149        }
 150
 151        return 0;
 152}
 153
 154static void __exit qcexit(void)
 155{
 156        usb_deregister(&qcdriver);
 157        usb_serial_deregister(&qcdevice);
 158}
 159
 160module_init(qcinit);
 161module_exit(qcexit);
 162
 163MODULE_AUTHOR(DRIVER_AUTHOR);
 164MODULE_DESCRIPTION(DRIVER_DESC);
 165MODULE_LICENSE("GPL v2");
 166
 167module_param(debug, bool, S_IRUGO | S_IWUSR);
 168MODULE_PARM_DESC(debug, "Debug enabled or not");
 169