0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/tty.h>
0011 #include <linux/tty_flip.h>
0012 #include <linux/module.h>
0013 #include <linux/usb.h>
0014 #include <linux/usb/serial.h>
0015 #include <linux/slab.h>
0016 #include "usb-wwan.h"
0017
0018 #define DRIVER_AUTHOR "Qualcomm Inc"
0019 #define DRIVER_DESC "Qualcomm USB Serial driver"
0020
0021 #define QUECTEL_EC20_PID 0x9215
0022
0023
0024 enum qcserial_layouts {
0025 QCSERIAL_G2K = 0,
0026 QCSERIAL_G1K = 1,
0027 QCSERIAL_SWI = 2,
0028 QCSERIAL_HWI = 3,
0029 };
0030
0031 #define DEVICE_G1K(v, p) \
0032 USB_DEVICE(v, p), .driver_info = QCSERIAL_G1K
0033 #define DEVICE_SWI(v, p) \
0034 USB_DEVICE(v, p), .driver_info = QCSERIAL_SWI
0035 #define DEVICE_HWI(v, p) \
0036 USB_DEVICE(v, p), .driver_info = QCSERIAL_HWI
0037
0038 static const struct usb_device_id id_table[] = {
0039
0040 {DEVICE_G1K(0x05c6, 0x9211)},
0041 {DEVICE_G1K(0x05c6, 0x9212)},
0042 {DEVICE_G1K(0x03f0, 0x1f1d)},
0043 {DEVICE_G1K(0x03f0, 0x201d)},
0044 {DEVICE_G1K(0x04da, 0x250d)},
0045 {DEVICE_G1K(0x04da, 0x250c)},
0046 {DEVICE_G1K(0x413c, 0x8172)},
0047 {DEVICE_G1K(0x413c, 0x8171)},
0048 {DEVICE_G1K(0x1410, 0xa001)},
0049 {DEVICE_G1K(0x1410, 0xa002)},
0050 {DEVICE_G1K(0x1410, 0xa003)},
0051 {DEVICE_G1K(0x1410, 0xa004)},
0052 {DEVICE_G1K(0x1410, 0xa005)},
0053 {DEVICE_G1K(0x1410, 0xa006)},
0054 {DEVICE_G1K(0x1410, 0xa007)},
0055 {DEVICE_G1K(0x1410, 0xa008)},
0056 {DEVICE_G1K(0x0b05, 0x1776)},
0057 {DEVICE_G1K(0x0b05, 0x1774)},
0058 {DEVICE_G1K(0x19d2, 0xfff3)},
0059 {DEVICE_G1K(0x19d2, 0xfff2)},
0060 {DEVICE_G1K(0x1557, 0x0a80)},
0061 {DEVICE_G1K(0x05c6, 0x9001)},
0062 {DEVICE_G1K(0x05c6, 0x9002)},
0063 {DEVICE_G1K(0x05c6, 0x9202)},
0064 {DEVICE_G1K(0x05c6, 0x9203)},
0065 {DEVICE_G1K(0x05c6, 0x9222)},
0066 {DEVICE_G1K(0x05c6, 0x9008)},
0067 {DEVICE_G1K(0x05c6, 0x9009)},
0068 {DEVICE_G1K(0x05c6, 0x9201)},
0069 {DEVICE_G1K(0x05c6, 0x9221)},
0070 {DEVICE_G1K(0x05c6, 0x9231)},
0071 {DEVICE_G1K(0x1f45, 0x0001)},
0072 {DEVICE_G1K(0x1bc7, 0x900e)},
0073
0074
0075 {USB_DEVICE(0x1410, 0xa010)},
0076 {USB_DEVICE(0x1410, 0xa011)},
0077 {USB_DEVICE(0x1410, 0xa012)},
0078 {USB_DEVICE(0x1410, 0xa013)},
0079 {USB_DEVICE(0x1410, 0xa014)},
0080 {USB_DEVICE(0x413c, 0x8185)},
0081 {USB_DEVICE(0x413c, 0x8186)},
0082 {USB_DEVICE(0x05c6, 0x9208)},
0083 {USB_DEVICE(0x05c6, 0x920b)},
0084 {USB_DEVICE(0x05c6, 0x9224)},
0085 {USB_DEVICE(0x05c6, 0x9225)},
0086 {USB_DEVICE(0x05c6, 0x9244)},
0087 {USB_DEVICE(0x05c6, 0x9245)},
0088 {USB_DEVICE(0x03f0, 0x241d)},
0089 {USB_DEVICE(0x03f0, 0x251d)},
0090 {USB_DEVICE(0x05c6, 0x9214)},
0091 {USB_DEVICE(0x05c6, 0x9215)},
0092 {USB_DEVICE(0x05c6, 0x9264)},
0093 {USB_DEVICE(0x05c6, 0x9265)},
0094 {USB_DEVICE(0x05c6, 0x9234)},
0095 {USB_DEVICE(0x05c6, 0x9235)},
0096 {USB_DEVICE(0x05c6, 0x9274)},
0097 {USB_DEVICE(0x05c6, 0x9275)},
0098 {USB_DEVICE(0x1199, 0x9000)},
0099 {USB_DEVICE(0x1199, 0x9001)},
0100 {USB_DEVICE(0x1199, 0x9002)},
0101 {USB_DEVICE(0x1199, 0x9003)},
0102 {USB_DEVICE(0x1199, 0x9004)},
0103 {USB_DEVICE(0x1199, 0x9005)},
0104 {USB_DEVICE(0x1199, 0x9006)},
0105 {USB_DEVICE(0x1199, 0x9007)},
0106 {USB_DEVICE(0x1199, 0x9008)},
0107 {USB_DEVICE(0x1199, 0x9009)},
0108 {USB_DEVICE(0x1199, 0x900a)},
0109 {USB_DEVICE(0x1199, 0x9011)},
0110 {USB_DEVICE(0x16d8, 0x8001)},
0111 {USB_DEVICE(0x16d8, 0x8002)},
0112 {USB_DEVICE(0x05c6, 0x9204)},
0113 {USB_DEVICE(0x05c6, 0x9205)},
0114
0115
0116 {USB_DEVICE(0x03f0, 0x371d)},
0117 {USB_DEVICE(0x05c6, 0x920c)},
0118 {USB_DEVICE(0x05c6, 0x920d)},
0119 {USB_DEVICE(0x1410, 0xa020)},
0120 {USB_DEVICE(0x1410, 0xa021)},
0121 {USB_DEVICE(0x413c, 0x8193)},
0122 {USB_DEVICE(0x413c, 0x8194)},
0123 {USB_DEVICE(0x413c, 0x81a6)},
0124 {USB_DEVICE(0x1199, 0x68a4)},
0125 {USB_DEVICE(0x1199, 0x68a5)},
0126 {USB_DEVICE(0x1199, 0x68a8)},
0127 {USB_DEVICE(0x1199, 0x68a9)},
0128 {USB_DEVICE(0x1199, 0x9010)},
0129 {USB_DEVICE(0x1199, 0x9012)},
0130 {USB_DEVICE(0x1199, 0x9013)},
0131 {USB_DEVICE(0x1199, 0x9014)},
0132 {USB_DEVICE(0x1199, 0x9015)},
0133 {USB_DEVICE(0x1199, 0x9018)},
0134 {USB_DEVICE(0x1199, 0x9019)},
0135 {USB_DEVICE(0x1199, 0x901b)},
0136 {USB_DEVICE(0x12D1, 0x14F0)},
0137 {USB_DEVICE(0x12D1, 0x14F1)},
0138 {USB_DEVICE(0x0AF0, 0x8120)},
0139
0140
0141 {DEVICE_SWI(0x03f0, 0x4e1d)},
0142 {DEVICE_SWI(0x0f3d, 0x68a2)},
0143 {DEVICE_SWI(0x114f, 0x68a2)},
0144 {DEVICE_SWI(0x1199, 0x68a2)},
0145 {DEVICE_SWI(0x1199, 0x68c0)},
0146 {DEVICE_SWI(0x1199, 0x901c)},
0147 {DEVICE_SWI(0x1199, 0x901e)},
0148 {DEVICE_SWI(0x1199, 0x901f)},
0149 {DEVICE_SWI(0x1199, 0x9040)},
0150 {DEVICE_SWI(0x1199, 0x9041)},
0151 {DEVICE_SWI(0x1199, 0x9051)},
0152 {DEVICE_SWI(0x1199, 0x9053)},
0153 {DEVICE_SWI(0x1199, 0x9054)},
0154 {DEVICE_SWI(0x1199, 0x9055)},
0155 {DEVICE_SWI(0x1199, 0x9056)},
0156 {DEVICE_SWI(0x1199, 0x9060)},
0157 {DEVICE_SWI(0x1199, 0x9061)},
0158 {DEVICE_SWI(0x1199, 0x9062)},
0159 {DEVICE_SWI(0x1199, 0x9063)},
0160 {DEVICE_SWI(0x1199, 0x9070)},
0161 {DEVICE_SWI(0x1199, 0x9071)},
0162 {DEVICE_SWI(0x1199, 0x9078)},
0163 {DEVICE_SWI(0x1199, 0x9079)},
0164 {DEVICE_SWI(0x1199, 0x907a)},
0165 {DEVICE_SWI(0x1199, 0x907b)},
0166 {DEVICE_SWI(0x1199, 0x9090)},
0167 {DEVICE_SWI(0x1199, 0x9091)},
0168 {DEVICE_SWI(0x1199, 0x90d2)},
0169 {DEVICE_SWI(0x1199, 0xc080)},
0170 {DEVICE_SWI(0x1199, 0xc081)},
0171 {DEVICE_SWI(0x413c, 0x81a2)},
0172 {DEVICE_SWI(0x413c, 0x81a3)},
0173 {DEVICE_SWI(0x413c, 0x81a4)},
0174 {DEVICE_SWI(0x413c, 0x81a8)},
0175 {DEVICE_SWI(0x413c, 0x81a9)},
0176 {DEVICE_SWI(0x413c, 0x81b1)},
0177 {DEVICE_SWI(0x413c, 0x81b3)},
0178 {DEVICE_SWI(0x413c, 0x81b5)},
0179 {DEVICE_SWI(0x413c, 0x81b6)},
0180 {DEVICE_SWI(0x413c, 0x81cb)},
0181 {DEVICE_SWI(0x413c, 0x81cc)},
0182 {DEVICE_SWI(0x413c, 0x81cf)},
0183 {DEVICE_SWI(0x413c, 0x81d0)},
0184 {DEVICE_SWI(0x413c, 0x81d1)},
0185 {DEVICE_SWI(0x413c, 0x81d2)},
0186
0187
0188 {DEVICE_HWI(0x03f0, 0x581d)},
0189
0190 { }
0191 };
0192 MODULE_DEVICE_TABLE(usb, id_table);
0193
0194 static int handle_quectel_ec20(struct device *dev, int ifnum)
0195 {
0196 int altsetting = 0;
0197
0198
0199
0200
0201
0202
0203
0204
0205
0206 switch (ifnum) {
0207 case 0:
0208 dev_dbg(dev, "Quectel EC20 DM/DIAG interface found\n");
0209 break;
0210 case 1:
0211 dev_dbg(dev, "Quectel EC20 NMEA GPS interface found\n");
0212 break;
0213 case 2:
0214 case 3:
0215 dev_dbg(dev, "Quectel EC20 Modem port found\n");
0216 break;
0217 case 4:
0218
0219 altsetting = -1;
0220 break;
0221 }
0222
0223 return altsetting;
0224 }
0225
0226 static int qcprobe(struct usb_serial *serial, const struct usb_device_id *id)
0227 {
0228 struct usb_host_interface *intf = serial->interface->cur_altsetting;
0229 struct device *dev = &serial->dev->dev;
0230 int retval = -ENODEV;
0231 __u8 nintf;
0232 __u8 ifnum;
0233 int altsetting = -1;
0234 bool sendsetup = false;
0235
0236
0237 if (intf->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
0238 goto done;
0239
0240 nintf = serial->dev->actconfig->desc.bNumInterfaces;
0241 dev_dbg(dev, "Num Interfaces = %d\n", nintf);
0242 ifnum = intf->desc.bInterfaceNumber;
0243 dev_dbg(dev, "This Interface = %d\n", ifnum);
0244
0245 if (nintf == 1) {
0246
0247
0248 if (serial->interface->num_altsetting == 2)
0249 intf = usb_altnum_to_altsetting(serial->interface, 1);
0250 else if (serial->interface->num_altsetting > 2)
0251 goto done;
0252
0253 if (intf && intf->desc.bNumEndpoints == 2 &&
0254 usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) &&
0255 usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) {
0256 dev_dbg(dev, "QDL port found\n");
0257
0258 if (serial->interface->num_altsetting == 1)
0259 retval = 0;
0260 else
0261 altsetting = 1;
0262 }
0263 goto done;
0264
0265 }
0266
0267
0268 altsetting = 0;
0269
0270
0271
0272
0273
0274
0275 switch (id->driver_info) {
0276 case QCSERIAL_G1K:
0277
0278
0279
0280
0281
0282
0283
0284 if (nintf < 3 || nintf > 4) {
0285 dev_err(dev, "unknown number of interfaces: %d\n", nintf);
0286 altsetting = -1;
0287 goto done;
0288 }
0289
0290 if (ifnum == 0) {
0291 dev_dbg(dev, "Gobi 1K DM/DIAG interface found\n");
0292 altsetting = 1;
0293 } else if (ifnum == 2)
0294 dev_dbg(dev, "Modem port found\n");
0295 else
0296 altsetting = -1;
0297 break;
0298 case QCSERIAL_G2K:
0299
0300 if (nintf == 5 && id->idProduct == QUECTEL_EC20_PID) {
0301 altsetting = handle_quectel_ec20(dev, ifnum);
0302 goto done;
0303 }
0304
0305
0306
0307
0308
0309
0310
0311
0312 if (nintf < 3 || nintf > 4) {
0313 dev_err(dev, "unknown number of interfaces: %d\n", nintf);
0314 altsetting = -1;
0315 goto done;
0316 }
0317
0318 switch (ifnum) {
0319 case 0:
0320
0321 altsetting = -1;
0322 break;
0323 case 1:
0324 dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n");
0325 break;
0326 case 2:
0327 dev_dbg(dev, "Modem port found\n");
0328 break;
0329 case 3:
0330
0331
0332
0333
0334
0335 dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n");
0336 break;
0337 }
0338 break;
0339 case QCSERIAL_SWI:
0340
0341
0342
0343
0344
0345
0346
0347 switch (ifnum) {
0348 case 0:
0349 dev_dbg(dev, "DM/DIAG interface found\n");
0350 break;
0351 case 2:
0352 dev_dbg(dev, "NMEA GPS interface found\n");
0353 sendsetup = true;
0354 break;
0355 case 3:
0356 dev_dbg(dev, "Modem port found\n");
0357 sendsetup = true;
0358 break;
0359 default:
0360
0361 altsetting = -1;
0362 break;
0363 }
0364 break;
0365 case QCSERIAL_HWI:
0366
0367
0368
0369
0370
0371
0372
0373
0374
0375 switch (intf->desc.bInterfaceProtocol) {
0376
0377 case 0x07:
0378 case 0x37:
0379 case 0x67:
0380
0381 case 0x08:
0382 case 0x38:
0383 case 0x68:
0384
0385 case 0x09:
0386 case 0x39:
0387 case 0x69:
0388
0389 case 0x16:
0390 case 0x46:
0391 case 0x76:
0392 altsetting = -1;
0393 break;
0394 default:
0395 dev_dbg(dev, "Huawei type serial port found (%02x/%02x/%02x)\n",
0396 intf->desc.bInterfaceClass,
0397 intf->desc.bInterfaceSubClass,
0398 intf->desc.bInterfaceProtocol);
0399 }
0400 break;
0401 default:
0402 dev_err(dev, "unsupported device layout type: %lu\n",
0403 id->driver_info);
0404 break;
0405 }
0406
0407 done:
0408 if (altsetting >= 0) {
0409 retval = usb_set_interface(serial->dev, ifnum, altsetting);
0410 if (retval < 0) {
0411 dev_err(dev,
0412 "Could not set interface, error %d\n",
0413 retval);
0414 retval = -ENODEV;
0415 }
0416 }
0417
0418 if (!retval)
0419 usb_set_serial_data(serial, (void *)(unsigned long)sendsetup);
0420
0421 return retval;
0422 }
0423
0424 static int qc_attach(struct usb_serial *serial)
0425 {
0426 struct usb_wwan_intf_private *data;
0427 bool sendsetup;
0428
0429 data = kzalloc(sizeof(*data), GFP_KERNEL);
0430 if (!data)
0431 return -ENOMEM;
0432
0433 sendsetup = !!(unsigned long)(usb_get_serial_data(serial));
0434 if (sendsetup)
0435 data->use_send_setup = 1;
0436
0437 spin_lock_init(&data->susp_lock);
0438
0439 usb_set_serial_data(serial, data);
0440
0441 return 0;
0442 }
0443
0444 static void qc_release(struct usb_serial *serial)
0445 {
0446 struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
0447
0448 usb_set_serial_data(serial, NULL);
0449 kfree(priv);
0450 }
0451
0452 static struct usb_serial_driver qcdevice = {
0453 .driver = {
0454 .owner = THIS_MODULE,
0455 .name = "qcserial",
0456 },
0457 .description = "Qualcomm USB modem",
0458 .id_table = id_table,
0459 .num_ports = 1,
0460 .probe = qcprobe,
0461 .open = usb_wwan_open,
0462 .close = usb_wwan_close,
0463 .dtr_rts = usb_wwan_dtr_rts,
0464 .write = usb_wwan_write,
0465 .write_room = usb_wwan_write_room,
0466 .chars_in_buffer = usb_wwan_chars_in_buffer,
0467 .tiocmget = usb_wwan_tiocmget,
0468 .tiocmset = usb_wwan_tiocmset,
0469 .attach = qc_attach,
0470 .release = qc_release,
0471 .port_probe = usb_wwan_port_probe,
0472 .port_remove = usb_wwan_port_remove,
0473 #ifdef CONFIG_PM
0474 .suspend = usb_wwan_suspend,
0475 .resume = usb_wwan_resume,
0476 #endif
0477 };
0478
0479 static struct usb_serial_driver * const serial_drivers[] = {
0480 &qcdevice, NULL
0481 };
0482
0483 module_usb_serial_driver(serial_drivers, id_table);
0484
0485 MODULE_AUTHOR(DRIVER_AUTHOR);
0486 MODULE_DESCRIPTION(DRIVER_DESC);
0487 MODULE_LICENSE("GPL v2");