18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Qualcomm Serial USB driver 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright (c) 2008 QUALCOMM Incorporated. 68c2ecf20Sopenharmony_ci * Copyright (c) 2009 Greg Kroah-Hartman <gregkh@suse.de> 78c2ecf20Sopenharmony_ci * Copyright (c) 2009 Novell Inc. 88c2ecf20Sopenharmony_ci */ 98c2ecf20Sopenharmony_ci 108c2ecf20Sopenharmony_ci#include <linux/tty.h> 118c2ecf20Sopenharmony_ci#include <linux/tty_flip.h> 128c2ecf20Sopenharmony_ci#include <linux/module.h> 138c2ecf20Sopenharmony_ci#include <linux/usb.h> 148c2ecf20Sopenharmony_ci#include <linux/usb/serial.h> 158c2ecf20Sopenharmony_ci#include <linux/slab.h> 168c2ecf20Sopenharmony_ci#include "usb-wwan.h" 178c2ecf20Sopenharmony_ci 188c2ecf20Sopenharmony_ci#define DRIVER_AUTHOR "Qualcomm Inc" 198c2ecf20Sopenharmony_ci#define DRIVER_DESC "Qualcomm USB Serial driver" 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#define QUECTEL_EC20_PID 0x9215 228c2ecf20Sopenharmony_ci 238c2ecf20Sopenharmony_ci/* standard device layouts supported by this driver */ 248c2ecf20Sopenharmony_cienum qcserial_layouts { 258c2ecf20Sopenharmony_ci QCSERIAL_G2K = 0, /* Gobi 2000 */ 268c2ecf20Sopenharmony_ci QCSERIAL_G1K = 1, /* Gobi 1000 */ 278c2ecf20Sopenharmony_ci QCSERIAL_SWI = 2, /* Sierra Wireless */ 288c2ecf20Sopenharmony_ci QCSERIAL_HWI = 3, /* Huawei */ 298c2ecf20Sopenharmony_ci}; 308c2ecf20Sopenharmony_ci 318c2ecf20Sopenharmony_ci#define DEVICE_G1K(v, p) \ 328c2ecf20Sopenharmony_ci USB_DEVICE(v, p), .driver_info = QCSERIAL_G1K 338c2ecf20Sopenharmony_ci#define DEVICE_SWI(v, p) \ 348c2ecf20Sopenharmony_ci USB_DEVICE(v, p), .driver_info = QCSERIAL_SWI 358c2ecf20Sopenharmony_ci#define DEVICE_HWI(v, p) \ 368c2ecf20Sopenharmony_ci USB_DEVICE(v, p), .driver_info = QCSERIAL_HWI 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic const struct usb_device_id id_table[] = { 398c2ecf20Sopenharmony_ci /* Gobi 1000 devices */ 408c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9211)}, /* Acer Gobi QDL device */ 418c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9212)}, /* Acer Gobi Modem Device */ 428c2ecf20Sopenharmony_ci {DEVICE_G1K(0x03f0, 0x1f1d)}, /* HP un2400 Gobi Modem Device */ 438c2ecf20Sopenharmony_ci {DEVICE_G1K(0x03f0, 0x201d)}, /* HP un2400 Gobi QDL Device */ 448c2ecf20Sopenharmony_ci {DEVICE_G1K(0x04da, 0x250d)}, /* Panasonic Gobi Modem device */ 458c2ecf20Sopenharmony_ci {DEVICE_G1K(0x04da, 0x250c)}, /* Panasonic Gobi QDL device */ 468c2ecf20Sopenharmony_ci {DEVICE_G1K(0x413c, 0x8172)}, /* Dell Gobi Modem device */ 478c2ecf20Sopenharmony_ci {DEVICE_G1K(0x413c, 0x8171)}, /* Dell Gobi QDL device */ 488c2ecf20Sopenharmony_ci {DEVICE_G1K(0x1410, 0xa001)}, /* Novatel/Verizon USB-1000 */ 498c2ecf20Sopenharmony_ci {DEVICE_G1K(0x1410, 0xa002)}, /* Novatel Gobi Modem device */ 508c2ecf20Sopenharmony_ci {DEVICE_G1K(0x1410, 0xa003)}, /* Novatel Gobi Modem device */ 518c2ecf20Sopenharmony_ci {DEVICE_G1K(0x1410, 0xa004)}, /* Novatel Gobi Modem device */ 528c2ecf20Sopenharmony_ci {DEVICE_G1K(0x1410, 0xa005)}, /* Novatel Gobi Modem device */ 538c2ecf20Sopenharmony_ci {DEVICE_G1K(0x1410, 0xa006)}, /* Novatel Gobi Modem device */ 548c2ecf20Sopenharmony_ci {DEVICE_G1K(0x1410, 0xa007)}, /* Novatel Gobi Modem device */ 558c2ecf20Sopenharmony_ci {DEVICE_G1K(0x1410, 0xa008)}, /* Novatel Gobi QDL device */ 568c2ecf20Sopenharmony_ci {DEVICE_G1K(0x0b05, 0x1776)}, /* Asus Gobi Modem device */ 578c2ecf20Sopenharmony_ci {DEVICE_G1K(0x0b05, 0x1774)}, /* Asus Gobi QDL device */ 588c2ecf20Sopenharmony_ci {DEVICE_G1K(0x19d2, 0xfff3)}, /* ONDA Gobi Modem device */ 598c2ecf20Sopenharmony_ci {DEVICE_G1K(0x19d2, 0xfff2)}, /* ONDA Gobi QDL device */ 608c2ecf20Sopenharmony_ci {DEVICE_G1K(0x1557, 0x0a80)}, /* OQO Gobi QDL device */ 618c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9001)}, /* Generic Gobi Modem device */ 628c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9002)}, /* Generic Gobi Modem device */ 638c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9202)}, /* Generic Gobi Modem device */ 648c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9203)}, /* Generic Gobi Modem device */ 658c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9222)}, /* Generic Gobi Modem device */ 668c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9008)}, /* Generic Gobi QDL device */ 678c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9009)}, /* Generic Gobi Modem device */ 688c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9201)}, /* Generic Gobi QDL device */ 698c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9221)}, /* Generic Gobi QDL device */ 708c2ecf20Sopenharmony_ci {DEVICE_G1K(0x05c6, 0x9231)}, /* Generic Gobi QDL device */ 718c2ecf20Sopenharmony_ci {DEVICE_G1K(0x1f45, 0x0001)}, /* Unknown Gobi QDL device */ 728c2ecf20Sopenharmony_ci {DEVICE_G1K(0x1bc7, 0x900e)}, /* Telit Gobi QDL device */ 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci /* Gobi 2000 devices */ 758c2ecf20Sopenharmony_ci {USB_DEVICE(0x1410, 0xa010)}, /* Novatel Gobi 2000 QDL device */ 768c2ecf20Sopenharmony_ci {USB_DEVICE(0x1410, 0xa011)}, /* Novatel Gobi 2000 QDL device */ 778c2ecf20Sopenharmony_ci {USB_DEVICE(0x1410, 0xa012)}, /* Novatel Gobi 2000 QDL device */ 788c2ecf20Sopenharmony_ci {USB_DEVICE(0x1410, 0xa013)}, /* Novatel Gobi 2000 QDL device */ 798c2ecf20Sopenharmony_ci {USB_DEVICE(0x1410, 0xa014)}, /* Novatel Gobi 2000 QDL device */ 808c2ecf20Sopenharmony_ci {USB_DEVICE(0x413c, 0x8185)}, /* Dell Gobi 2000 QDL device (N0218, VU936) */ 818c2ecf20Sopenharmony_ci {USB_DEVICE(0x413c, 0x8186)}, /* Dell Gobi 2000 Modem device (N0218, VU936) */ 828c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9208)}, /* Generic Gobi 2000 QDL device */ 838c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x920b)}, /* Generic Gobi 2000 Modem device */ 848c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9224)}, /* Sony Gobi 2000 QDL device (N0279, VU730) */ 858c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9225)}, /* Sony Gobi 2000 Modem device (N0279, VU730) */ 868c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9244)}, /* Samsung Gobi 2000 QDL device (VL176) */ 878c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9245)}, /* Samsung Gobi 2000 Modem device (VL176) */ 888c2ecf20Sopenharmony_ci {USB_DEVICE(0x03f0, 0x241d)}, /* HP Gobi 2000 QDL device (VP412) */ 898c2ecf20Sopenharmony_ci {USB_DEVICE(0x03f0, 0x251d)}, /* HP Gobi 2000 Modem device (VP412) */ 908c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9214)}, /* Acer Gobi 2000 QDL device (VP413) */ 918c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9215)}, /* Acer Gobi 2000 Modem device (VP413) */ 928c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9264)}, /* Asus Gobi 2000 QDL device (VR305) */ 938c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9265)}, /* Asus Gobi 2000 Modem device (VR305) */ 948c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9234)}, /* Top Global Gobi 2000 QDL device (VR306) */ 958c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9235)}, /* Top Global Gobi 2000 Modem device (VR306) */ 968c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9274)}, /* iRex Technologies Gobi 2000 QDL device (VR307) */ 978c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9275)}, /* iRex Technologies Gobi 2000 Modem device (VR307) */ 988c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9000)}, /* Sierra Wireless Gobi 2000 QDL device (VT773) */ 998c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9001)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 1008c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9002)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 1018c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9003)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 1028c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9004)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 1038c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9005)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 1048c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9006)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 1058c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9007)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 1068c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9008)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 1078c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9009)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 1088c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x900a)}, /* Sierra Wireless Gobi 2000 Modem device (VT773) */ 1098c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9011)}, /* Sierra Wireless Gobi 2000 Modem device (MC8305) */ 1108c2ecf20Sopenharmony_ci {USB_DEVICE(0x16d8, 0x8001)}, /* CMDTech Gobi 2000 QDL device (VU922) */ 1118c2ecf20Sopenharmony_ci {USB_DEVICE(0x16d8, 0x8002)}, /* CMDTech Gobi 2000 Modem device (VU922) */ 1128c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9204)}, /* Gobi 2000 QDL device */ 1138c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x9205)}, /* Gobi 2000 Modem device */ 1148c2ecf20Sopenharmony_ci 1158c2ecf20Sopenharmony_ci /* Gobi 3000 devices */ 1168c2ecf20Sopenharmony_ci {USB_DEVICE(0x03f0, 0x371d)}, /* HP un2430 Gobi 3000 QDL */ 1178c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x920c)}, /* Gobi 3000 QDL */ 1188c2ecf20Sopenharmony_ci {USB_DEVICE(0x05c6, 0x920d)}, /* Gobi 3000 Composite */ 1198c2ecf20Sopenharmony_ci {USB_DEVICE(0x1410, 0xa020)}, /* Novatel Gobi 3000 QDL */ 1208c2ecf20Sopenharmony_ci {USB_DEVICE(0x1410, 0xa021)}, /* Novatel Gobi 3000 Composite */ 1218c2ecf20Sopenharmony_ci {USB_DEVICE(0x413c, 0x8193)}, /* Dell Gobi 3000 QDL */ 1228c2ecf20Sopenharmony_ci {USB_DEVICE(0x413c, 0x8194)}, /* Dell Gobi 3000 Composite */ 1238c2ecf20Sopenharmony_ci {USB_DEVICE(0x413c, 0x81a6)}, /* Dell DW5570 QDL (MC8805) */ 1248c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x68a4)}, /* Sierra Wireless QDL */ 1258c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x68a5)}, /* Sierra Wireless Modem */ 1268c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x68a8)}, /* Sierra Wireless QDL */ 1278c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x68a9)}, /* Sierra Wireless Modem */ 1288c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9010)}, /* Sierra Wireless Gobi 3000 QDL */ 1298c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9012)}, /* Sierra Wireless Gobi 3000 QDL */ 1308c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9013)}, /* Sierra Wireless Gobi 3000 Modem device (MC8355) */ 1318c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9014)}, /* Sierra Wireless Gobi 3000 QDL */ 1328c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9015)}, /* Sierra Wireless Gobi 3000 Modem device */ 1338c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9018)}, /* Sierra Wireless Gobi 3000 QDL */ 1348c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x9019)}, /* Sierra Wireless Gobi 3000 Modem device */ 1358c2ecf20Sopenharmony_ci {USB_DEVICE(0x1199, 0x901b)}, /* Sierra Wireless MC7770 */ 1368c2ecf20Sopenharmony_ci {USB_DEVICE(0x12D1, 0x14F0)}, /* Sony Gobi 3000 QDL */ 1378c2ecf20Sopenharmony_ci {USB_DEVICE(0x12D1, 0x14F1)}, /* Sony Gobi 3000 Composite */ 1388c2ecf20Sopenharmony_ci {USB_DEVICE(0x0AF0, 0x8120)}, /* Option GTM681W */ 1398c2ecf20Sopenharmony_ci 1408c2ecf20Sopenharmony_ci /* non-Gobi Sierra Wireless devices */ 1418c2ecf20Sopenharmony_ci {DEVICE_SWI(0x03f0, 0x4e1d)}, /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */ 1428c2ecf20Sopenharmony_ci {DEVICE_SWI(0x0f3d, 0x68a2)}, /* Sierra Wireless MC7700 */ 1438c2ecf20Sopenharmony_ci {DEVICE_SWI(0x114f, 0x68a2)}, /* Sierra Wireless MC7750 */ 1448c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x68a2)}, /* Sierra Wireless MC7710 */ 1458c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x68c0)}, /* Sierra Wireless MC7304/MC7354 */ 1468c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x901c)}, /* Sierra Wireless EM7700 */ 1478c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x901e)}, /* Sierra Wireless EM7355 QDL */ 1488c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x901f)}, /* Sierra Wireless EM7355 */ 1498c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9040)}, /* Sierra Wireless Modem */ 1508c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9041)}, /* Sierra Wireless MC7305/MC7355 */ 1518c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9051)}, /* Netgear AirCard 340U */ 1528c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9053)}, /* Sierra Wireless Modem */ 1538c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9054)}, /* Sierra Wireless Modem */ 1548c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9055)}, /* Netgear AirCard 341U */ 1558c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9056)}, /* Sierra Wireless Modem */ 1568c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9060)}, /* Sierra Wireless Modem */ 1578c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9061)}, /* Sierra Wireless Modem */ 1588c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9062)}, /* Sierra Wireless EM7305 QDL */ 1598c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9063)}, /* Sierra Wireless EM7305 */ 1608c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9070)}, /* Sierra Wireless MC74xx */ 1618c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9071)}, /* Sierra Wireless MC74xx */ 1628c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9078)}, /* Sierra Wireless EM74xx */ 1638c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9079)}, /* Sierra Wireless EM74xx */ 1648c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x907a)}, /* Sierra Wireless EM74xx QDL */ 1658c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x907b)}, /* Sierra Wireless EM74xx */ 1668c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9090)}, /* Sierra Wireless EM7565 QDL */ 1678c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x9091)}, /* Sierra Wireless EM7565 */ 1688c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0x90d2)}, /* Sierra Wireless EM9191 QDL */ 1698c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0xc080)}, /* Sierra Wireless EM7590 QDL */ 1708c2ecf20Sopenharmony_ci {DEVICE_SWI(0x1199, 0xc081)}, /* Sierra Wireless EM7590 */ 1718c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81a2)}, /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */ 1728c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81a3)}, /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */ 1738c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81a4)}, /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */ 1748c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81a8)}, /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */ 1758c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81a9)}, /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */ 1768c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81b1)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */ 1778c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81b3)}, /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */ 1788c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81b5)}, /* Dell Wireless 5811e QDL */ 1798c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81b6)}, /* Dell Wireless 5811e QDL */ 1808c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81c2)}, /* Dell Wireless 5811e */ 1818c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81cb)}, /* Dell Wireless 5816e QDL */ 1828c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81cc)}, /* Dell Wireless 5816e */ 1838c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81cf)}, /* Dell Wireless 5819 */ 1848c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81d0)}, /* Dell Wireless 5819 */ 1858c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81d1)}, /* Dell Wireless 5818 */ 1868c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x81d2)}, /* Dell Wireless 5818 */ 1878c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x8217)}, /* Dell Wireless DW5826e */ 1888c2ecf20Sopenharmony_ci {DEVICE_SWI(0x413c, 0x8218)}, /* Dell Wireless DW5826e QDL */ 1898c2ecf20Sopenharmony_ci 1908c2ecf20Sopenharmony_ci /* Huawei devices */ 1918c2ecf20Sopenharmony_ci {DEVICE_HWI(0x03f0, 0x581d)}, /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */ 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_ci { } /* Terminating entry */ 1948c2ecf20Sopenharmony_ci}; 1958c2ecf20Sopenharmony_ciMODULE_DEVICE_TABLE(usb, id_table); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_cistatic int handle_quectel_ec20(struct device *dev, int ifnum) 1988c2ecf20Sopenharmony_ci{ 1998c2ecf20Sopenharmony_ci int altsetting = 0; 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci /* 2028c2ecf20Sopenharmony_ci * Quectel EC20 Mini PCIe LTE module layout: 2038c2ecf20Sopenharmony_ci * 0: DM/DIAG (use libqcdm from ModemManager for communication) 2048c2ecf20Sopenharmony_ci * 1: NMEA 2058c2ecf20Sopenharmony_ci * 2: AT-capable modem port 2068c2ecf20Sopenharmony_ci * 3: Modem interface 2078c2ecf20Sopenharmony_ci * 4: NDIS 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci switch (ifnum) { 2108c2ecf20Sopenharmony_ci case 0: 2118c2ecf20Sopenharmony_ci dev_dbg(dev, "Quectel EC20 DM/DIAG interface found\n"); 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci case 1: 2148c2ecf20Sopenharmony_ci dev_dbg(dev, "Quectel EC20 NMEA GPS interface found\n"); 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci case 2: 2178c2ecf20Sopenharmony_ci case 3: 2188c2ecf20Sopenharmony_ci dev_dbg(dev, "Quectel EC20 Modem port found\n"); 2198c2ecf20Sopenharmony_ci break; 2208c2ecf20Sopenharmony_ci case 4: 2218c2ecf20Sopenharmony_ci /* Don't claim the QMI/net interface */ 2228c2ecf20Sopenharmony_ci altsetting = -1; 2238c2ecf20Sopenharmony_ci break; 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci return altsetting; 2278c2ecf20Sopenharmony_ci} 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_cistatic int qcprobe(struct usb_serial *serial, const struct usb_device_id *id) 2308c2ecf20Sopenharmony_ci{ 2318c2ecf20Sopenharmony_ci struct usb_host_interface *intf = serial->interface->cur_altsetting; 2328c2ecf20Sopenharmony_ci struct device *dev = &serial->dev->dev; 2338c2ecf20Sopenharmony_ci int retval = -ENODEV; 2348c2ecf20Sopenharmony_ci __u8 nintf; 2358c2ecf20Sopenharmony_ci __u8 ifnum; 2368c2ecf20Sopenharmony_ci int altsetting = -1; 2378c2ecf20Sopenharmony_ci bool sendsetup = false; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* we only support vendor specific functions */ 2408c2ecf20Sopenharmony_ci if (intf->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC) 2418c2ecf20Sopenharmony_ci goto done; 2428c2ecf20Sopenharmony_ci 2438c2ecf20Sopenharmony_ci nintf = serial->dev->actconfig->desc.bNumInterfaces; 2448c2ecf20Sopenharmony_ci dev_dbg(dev, "Num Interfaces = %d\n", nintf); 2458c2ecf20Sopenharmony_ci ifnum = intf->desc.bInterfaceNumber; 2468c2ecf20Sopenharmony_ci dev_dbg(dev, "This Interface = %d\n", ifnum); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci if (nintf == 1) { 2498c2ecf20Sopenharmony_ci /* QDL mode */ 2508c2ecf20Sopenharmony_ci /* Gobi 2000 has a single altsetting, older ones have two */ 2518c2ecf20Sopenharmony_ci if (serial->interface->num_altsetting == 2) 2528c2ecf20Sopenharmony_ci intf = usb_altnum_to_altsetting(serial->interface, 1); 2538c2ecf20Sopenharmony_ci else if (serial->interface->num_altsetting > 2) 2548c2ecf20Sopenharmony_ci goto done; 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci if (intf && intf->desc.bNumEndpoints == 2 && 2578c2ecf20Sopenharmony_ci usb_endpoint_is_bulk_in(&intf->endpoint[0].desc) && 2588c2ecf20Sopenharmony_ci usb_endpoint_is_bulk_out(&intf->endpoint[1].desc)) { 2598c2ecf20Sopenharmony_ci dev_dbg(dev, "QDL port found\n"); 2608c2ecf20Sopenharmony_ci 2618c2ecf20Sopenharmony_ci if (serial->interface->num_altsetting == 1) 2628c2ecf20Sopenharmony_ci retval = 0; /* Success */ 2638c2ecf20Sopenharmony_ci else 2648c2ecf20Sopenharmony_ci altsetting = 1; 2658c2ecf20Sopenharmony_ci } 2668c2ecf20Sopenharmony_ci goto done; 2678c2ecf20Sopenharmony_ci 2688c2ecf20Sopenharmony_ci } 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci /* default to enabling interface */ 2718c2ecf20Sopenharmony_ci altsetting = 0; 2728c2ecf20Sopenharmony_ci 2738c2ecf20Sopenharmony_ci /* 2748c2ecf20Sopenharmony_ci * Composite mode; don't bind to the QMI/net interface as that 2758c2ecf20Sopenharmony_ci * gets handled by other drivers. 2768c2ecf20Sopenharmony_ci */ 2778c2ecf20Sopenharmony_ci 2788c2ecf20Sopenharmony_ci switch (id->driver_info) { 2798c2ecf20Sopenharmony_ci case QCSERIAL_G1K: 2808c2ecf20Sopenharmony_ci /* 2818c2ecf20Sopenharmony_ci * Gobi 1K USB layout: 2828c2ecf20Sopenharmony_ci * 0: DM/DIAG (use libqcdm from ModemManager for communication) 2838c2ecf20Sopenharmony_ci * 1: serial port (doesn't respond) 2848c2ecf20Sopenharmony_ci * 2: AT-capable modem port 2858c2ecf20Sopenharmony_ci * 3: QMI/net 2868c2ecf20Sopenharmony_ci */ 2878c2ecf20Sopenharmony_ci if (nintf < 3 || nintf > 4) { 2888c2ecf20Sopenharmony_ci dev_err(dev, "unknown number of interfaces: %d\n", nintf); 2898c2ecf20Sopenharmony_ci altsetting = -1; 2908c2ecf20Sopenharmony_ci goto done; 2918c2ecf20Sopenharmony_ci } 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci if (ifnum == 0) { 2948c2ecf20Sopenharmony_ci dev_dbg(dev, "Gobi 1K DM/DIAG interface found\n"); 2958c2ecf20Sopenharmony_ci altsetting = 1; 2968c2ecf20Sopenharmony_ci } else if (ifnum == 2) 2978c2ecf20Sopenharmony_ci dev_dbg(dev, "Modem port found\n"); 2988c2ecf20Sopenharmony_ci else 2998c2ecf20Sopenharmony_ci altsetting = -1; 3008c2ecf20Sopenharmony_ci break; 3018c2ecf20Sopenharmony_ci case QCSERIAL_G2K: 3028c2ecf20Sopenharmony_ci /* handle non-standard layouts */ 3038c2ecf20Sopenharmony_ci if (nintf == 5 && id->idProduct == QUECTEL_EC20_PID) { 3048c2ecf20Sopenharmony_ci altsetting = handle_quectel_ec20(dev, ifnum); 3058c2ecf20Sopenharmony_ci goto done; 3068c2ecf20Sopenharmony_ci } 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci /* 3098c2ecf20Sopenharmony_ci * Gobi 2K+ USB layout: 3108c2ecf20Sopenharmony_ci * 0: QMI/net 3118c2ecf20Sopenharmony_ci * 1: DM/DIAG (use libqcdm from ModemManager for communication) 3128c2ecf20Sopenharmony_ci * 2: AT-capable modem port 3138c2ecf20Sopenharmony_ci * 3: NMEA 3148c2ecf20Sopenharmony_ci */ 3158c2ecf20Sopenharmony_ci if (nintf < 3 || nintf > 4) { 3168c2ecf20Sopenharmony_ci dev_err(dev, "unknown number of interfaces: %d\n", nintf); 3178c2ecf20Sopenharmony_ci altsetting = -1; 3188c2ecf20Sopenharmony_ci goto done; 3198c2ecf20Sopenharmony_ci } 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ci switch (ifnum) { 3228c2ecf20Sopenharmony_ci case 0: 3238c2ecf20Sopenharmony_ci /* Don't claim the QMI/net interface */ 3248c2ecf20Sopenharmony_ci altsetting = -1; 3258c2ecf20Sopenharmony_ci break; 3268c2ecf20Sopenharmony_ci case 1: 3278c2ecf20Sopenharmony_ci dev_dbg(dev, "Gobi 2K+ DM/DIAG interface found\n"); 3288c2ecf20Sopenharmony_ci break; 3298c2ecf20Sopenharmony_ci case 2: 3308c2ecf20Sopenharmony_ci dev_dbg(dev, "Modem port found\n"); 3318c2ecf20Sopenharmony_ci break; 3328c2ecf20Sopenharmony_ci case 3: 3338c2ecf20Sopenharmony_ci /* 3348c2ecf20Sopenharmony_ci * NMEA (serial line 9600 8N1) 3358c2ecf20Sopenharmony_ci * # echo "\$GPS_START" > /dev/ttyUSBx 3368c2ecf20Sopenharmony_ci * # echo "\$GPS_STOP" > /dev/ttyUSBx 3378c2ecf20Sopenharmony_ci */ 3388c2ecf20Sopenharmony_ci dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n"); 3398c2ecf20Sopenharmony_ci break; 3408c2ecf20Sopenharmony_ci } 3418c2ecf20Sopenharmony_ci break; 3428c2ecf20Sopenharmony_ci case QCSERIAL_SWI: 3438c2ecf20Sopenharmony_ci /* 3448c2ecf20Sopenharmony_ci * Sierra Wireless layout: 3458c2ecf20Sopenharmony_ci * 0: DM/DIAG (use libqcdm from ModemManager for communication) 3468c2ecf20Sopenharmony_ci * 2: NMEA 3478c2ecf20Sopenharmony_ci * 3: AT-capable modem port 3488c2ecf20Sopenharmony_ci * 8: QMI/net 3498c2ecf20Sopenharmony_ci */ 3508c2ecf20Sopenharmony_ci switch (ifnum) { 3518c2ecf20Sopenharmony_ci case 0: 3528c2ecf20Sopenharmony_ci dev_dbg(dev, "DM/DIAG interface found\n"); 3538c2ecf20Sopenharmony_ci break; 3548c2ecf20Sopenharmony_ci case 2: 3558c2ecf20Sopenharmony_ci dev_dbg(dev, "NMEA GPS interface found\n"); 3568c2ecf20Sopenharmony_ci sendsetup = true; 3578c2ecf20Sopenharmony_ci break; 3588c2ecf20Sopenharmony_ci case 3: 3598c2ecf20Sopenharmony_ci dev_dbg(dev, "Modem port found\n"); 3608c2ecf20Sopenharmony_ci sendsetup = true; 3618c2ecf20Sopenharmony_ci break; 3628c2ecf20Sopenharmony_ci default: 3638c2ecf20Sopenharmony_ci /* don't claim any unsupported interface */ 3648c2ecf20Sopenharmony_ci altsetting = -1; 3658c2ecf20Sopenharmony_ci break; 3668c2ecf20Sopenharmony_ci } 3678c2ecf20Sopenharmony_ci break; 3688c2ecf20Sopenharmony_ci case QCSERIAL_HWI: 3698c2ecf20Sopenharmony_ci /* 3708c2ecf20Sopenharmony_ci * Huawei devices map functions by subclass + protocol 3718c2ecf20Sopenharmony_ci * instead of interface numbers. The protocol identify 3728c2ecf20Sopenharmony_ci * a specific function, while the subclass indicate a 3738c2ecf20Sopenharmony_ci * specific firmware source 3748c2ecf20Sopenharmony_ci * 3758c2ecf20Sopenharmony_ci * This is a list of functions known to be non-serial. The rest 3768c2ecf20Sopenharmony_ci * are assumed to be serial and will be handled by this driver 3778c2ecf20Sopenharmony_ci */ 3788c2ecf20Sopenharmony_ci switch (intf->desc.bInterfaceProtocol) { 3798c2ecf20Sopenharmony_ci /* QMI combined (qmi_wwan) */ 3808c2ecf20Sopenharmony_ci case 0x07: 3818c2ecf20Sopenharmony_ci case 0x37: 3828c2ecf20Sopenharmony_ci case 0x67: 3838c2ecf20Sopenharmony_ci /* QMI data (qmi_wwan) */ 3848c2ecf20Sopenharmony_ci case 0x08: 3858c2ecf20Sopenharmony_ci case 0x38: 3868c2ecf20Sopenharmony_ci case 0x68: 3878c2ecf20Sopenharmony_ci /* QMI control (qmi_wwan) */ 3888c2ecf20Sopenharmony_ci case 0x09: 3898c2ecf20Sopenharmony_ci case 0x39: 3908c2ecf20Sopenharmony_ci case 0x69: 3918c2ecf20Sopenharmony_ci /* NCM like (huawei_cdc_ncm) */ 3928c2ecf20Sopenharmony_ci case 0x16: 3938c2ecf20Sopenharmony_ci case 0x46: 3948c2ecf20Sopenharmony_ci case 0x76: 3958c2ecf20Sopenharmony_ci altsetting = -1; 3968c2ecf20Sopenharmony_ci break; 3978c2ecf20Sopenharmony_ci default: 3988c2ecf20Sopenharmony_ci dev_dbg(dev, "Huawei type serial port found (%02x/%02x/%02x)\n", 3998c2ecf20Sopenharmony_ci intf->desc.bInterfaceClass, 4008c2ecf20Sopenharmony_ci intf->desc.bInterfaceSubClass, 4018c2ecf20Sopenharmony_ci intf->desc.bInterfaceProtocol); 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci break; 4048c2ecf20Sopenharmony_ci default: 4058c2ecf20Sopenharmony_ci dev_err(dev, "unsupported device layout type: %lu\n", 4068c2ecf20Sopenharmony_ci id->driver_info); 4078c2ecf20Sopenharmony_ci break; 4088c2ecf20Sopenharmony_ci } 4098c2ecf20Sopenharmony_ci 4108c2ecf20Sopenharmony_cidone: 4118c2ecf20Sopenharmony_ci if (altsetting >= 0) { 4128c2ecf20Sopenharmony_ci retval = usb_set_interface(serial->dev, ifnum, altsetting); 4138c2ecf20Sopenharmony_ci if (retval < 0) { 4148c2ecf20Sopenharmony_ci dev_err(dev, 4158c2ecf20Sopenharmony_ci "Could not set interface, error %d\n", 4168c2ecf20Sopenharmony_ci retval); 4178c2ecf20Sopenharmony_ci retval = -ENODEV; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci } 4208c2ecf20Sopenharmony_ci 4218c2ecf20Sopenharmony_ci if (!retval) 4228c2ecf20Sopenharmony_ci usb_set_serial_data(serial, (void *)(unsigned long)sendsetup); 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci return retval; 4258c2ecf20Sopenharmony_ci} 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic int qc_attach(struct usb_serial *serial) 4288c2ecf20Sopenharmony_ci{ 4298c2ecf20Sopenharmony_ci struct usb_wwan_intf_private *data; 4308c2ecf20Sopenharmony_ci bool sendsetup; 4318c2ecf20Sopenharmony_ci 4328c2ecf20Sopenharmony_ci data = kzalloc(sizeof(*data), GFP_KERNEL); 4338c2ecf20Sopenharmony_ci if (!data) 4348c2ecf20Sopenharmony_ci return -ENOMEM; 4358c2ecf20Sopenharmony_ci 4368c2ecf20Sopenharmony_ci sendsetup = !!(unsigned long)(usb_get_serial_data(serial)); 4378c2ecf20Sopenharmony_ci if (sendsetup) 4388c2ecf20Sopenharmony_ci data->use_send_setup = 1; 4398c2ecf20Sopenharmony_ci 4408c2ecf20Sopenharmony_ci spin_lock_init(&data->susp_lock); 4418c2ecf20Sopenharmony_ci 4428c2ecf20Sopenharmony_ci usb_set_serial_data(serial, data); 4438c2ecf20Sopenharmony_ci 4448c2ecf20Sopenharmony_ci return 0; 4458c2ecf20Sopenharmony_ci} 4468c2ecf20Sopenharmony_ci 4478c2ecf20Sopenharmony_cistatic void qc_release(struct usb_serial *serial) 4488c2ecf20Sopenharmony_ci{ 4498c2ecf20Sopenharmony_ci struct usb_wwan_intf_private *priv = usb_get_serial_data(serial); 4508c2ecf20Sopenharmony_ci 4518c2ecf20Sopenharmony_ci usb_set_serial_data(serial, NULL); 4528c2ecf20Sopenharmony_ci kfree(priv); 4538c2ecf20Sopenharmony_ci} 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_cistatic struct usb_serial_driver qcdevice = { 4568c2ecf20Sopenharmony_ci .driver = { 4578c2ecf20Sopenharmony_ci .owner = THIS_MODULE, 4588c2ecf20Sopenharmony_ci .name = "qcserial", 4598c2ecf20Sopenharmony_ci }, 4608c2ecf20Sopenharmony_ci .description = "Qualcomm USB modem", 4618c2ecf20Sopenharmony_ci .id_table = id_table, 4628c2ecf20Sopenharmony_ci .num_ports = 1, 4638c2ecf20Sopenharmony_ci .probe = qcprobe, 4648c2ecf20Sopenharmony_ci .open = usb_wwan_open, 4658c2ecf20Sopenharmony_ci .close = usb_wwan_close, 4668c2ecf20Sopenharmony_ci .dtr_rts = usb_wwan_dtr_rts, 4678c2ecf20Sopenharmony_ci .write = usb_wwan_write, 4688c2ecf20Sopenharmony_ci .write_room = usb_wwan_write_room, 4698c2ecf20Sopenharmony_ci .chars_in_buffer = usb_wwan_chars_in_buffer, 4708c2ecf20Sopenharmony_ci .tiocmget = usb_wwan_tiocmget, 4718c2ecf20Sopenharmony_ci .tiocmset = usb_wwan_tiocmset, 4728c2ecf20Sopenharmony_ci .attach = qc_attach, 4738c2ecf20Sopenharmony_ci .release = qc_release, 4748c2ecf20Sopenharmony_ci .port_probe = usb_wwan_port_probe, 4758c2ecf20Sopenharmony_ci .port_remove = usb_wwan_port_remove, 4768c2ecf20Sopenharmony_ci#ifdef CONFIG_PM 4778c2ecf20Sopenharmony_ci .suspend = usb_wwan_suspend, 4788c2ecf20Sopenharmony_ci .resume = usb_wwan_resume, 4798c2ecf20Sopenharmony_ci#endif 4808c2ecf20Sopenharmony_ci}; 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_cistatic struct usb_serial_driver * const serial_drivers[] = { 4838c2ecf20Sopenharmony_ci &qcdevice, NULL 4848c2ecf20Sopenharmony_ci}; 4858c2ecf20Sopenharmony_ci 4868c2ecf20Sopenharmony_cimodule_usb_serial_driver(serial_drivers, id_table); 4878c2ecf20Sopenharmony_ci 4888c2ecf20Sopenharmony_ciMODULE_AUTHOR(DRIVER_AUTHOR); 4898c2ecf20Sopenharmony_ciMODULE_DESCRIPTION(DRIVER_DESC); 4908c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 491