Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Qualcomm Serial USB driver
0004  *
0005  *  Copyright (c) 2008 QUALCOMM Incorporated.
0006  *  Copyright (c) 2009 Greg Kroah-Hartman <gregkh@suse.de>
0007  *  Copyright (c) 2009 Novell Inc.
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 /* standard device layouts supported by this driver */
0024 enum qcserial_layouts {
0025     QCSERIAL_G2K = 0,   /* Gobi 2000 */
0026     QCSERIAL_G1K = 1,   /* Gobi 1000 */
0027     QCSERIAL_SWI = 2,   /* Sierra Wireless */
0028     QCSERIAL_HWI = 3,   /* Huawei */
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     /* Gobi 1000 devices */
0040     {DEVICE_G1K(0x05c6, 0x9211)},   /* Acer Gobi QDL device */
0041     {DEVICE_G1K(0x05c6, 0x9212)},   /* Acer Gobi Modem Device */
0042     {DEVICE_G1K(0x03f0, 0x1f1d)},   /* HP un2400 Gobi Modem Device */
0043     {DEVICE_G1K(0x03f0, 0x201d)},   /* HP un2400 Gobi QDL Device */
0044     {DEVICE_G1K(0x04da, 0x250d)},   /* Panasonic Gobi Modem device */
0045     {DEVICE_G1K(0x04da, 0x250c)},   /* Panasonic Gobi QDL device */
0046     {DEVICE_G1K(0x413c, 0x8172)},   /* Dell Gobi Modem device */
0047     {DEVICE_G1K(0x413c, 0x8171)},   /* Dell Gobi QDL device */
0048     {DEVICE_G1K(0x1410, 0xa001)},   /* Novatel/Verizon USB-1000 */
0049     {DEVICE_G1K(0x1410, 0xa002)},   /* Novatel Gobi Modem device */
0050     {DEVICE_G1K(0x1410, 0xa003)},   /* Novatel Gobi Modem device */
0051     {DEVICE_G1K(0x1410, 0xa004)},   /* Novatel Gobi Modem device */
0052     {DEVICE_G1K(0x1410, 0xa005)},   /* Novatel Gobi Modem device */
0053     {DEVICE_G1K(0x1410, 0xa006)},   /* Novatel Gobi Modem device */
0054     {DEVICE_G1K(0x1410, 0xa007)},   /* Novatel Gobi Modem device */
0055     {DEVICE_G1K(0x1410, 0xa008)},   /* Novatel Gobi QDL device */
0056     {DEVICE_G1K(0x0b05, 0x1776)},   /* Asus Gobi Modem device */
0057     {DEVICE_G1K(0x0b05, 0x1774)},   /* Asus Gobi QDL device */
0058     {DEVICE_G1K(0x19d2, 0xfff3)},   /* ONDA Gobi Modem device */
0059     {DEVICE_G1K(0x19d2, 0xfff2)},   /* ONDA Gobi QDL device */
0060     {DEVICE_G1K(0x1557, 0x0a80)},   /* OQO Gobi QDL device */
0061     {DEVICE_G1K(0x05c6, 0x9001)},   /* Generic Gobi Modem device */
0062     {DEVICE_G1K(0x05c6, 0x9002)},   /* Generic Gobi Modem device */
0063     {DEVICE_G1K(0x05c6, 0x9202)},   /* Generic Gobi Modem device */
0064     {DEVICE_G1K(0x05c6, 0x9203)},   /* Generic Gobi Modem device */
0065     {DEVICE_G1K(0x05c6, 0x9222)},   /* Generic Gobi Modem device */
0066     {DEVICE_G1K(0x05c6, 0x9008)},   /* Generic Gobi QDL device */
0067     {DEVICE_G1K(0x05c6, 0x9009)},   /* Generic Gobi Modem device */
0068     {DEVICE_G1K(0x05c6, 0x9201)},   /* Generic Gobi QDL device */
0069     {DEVICE_G1K(0x05c6, 0x9221)},   /* Generic Gobi QDL device */
0070     {DEVICE_G1K(0x05c6, 0x9231)},   /* Generic Gobi QDL device */
0071     {DEVICE_G1K(0x1f45, 0x0001)},   /* Unknown Gobi QDL device */
0072     {DEVICE_G1K(0x1bc7, 0x900e)},   /* Telit Gobi QDL device */
0073 
0074     /* Gobi 2000 devices */
0075     {USB_DEVICE(0x1410, 0xa010)},   /* Novatel Gobi 2000 QDL device */
0076     {USB_DEVICE(0x1410, 0xa011)},   /* Novatel Gobi 2000 QDL device */
0077     {USB_DEVICE(0x1410, 0xa012)},   /* Novatel Gobi 2000 QDL device */
0078     {USB_DEVICE(0x1410, 0xa013)},   /* Novatel Gobi 2000 QDL device */
0079     {USB_DEVICE(0x1410, 0xa014)},   /* Novatel Gobi 2000 QDL device */
0080     {USB_DEVICE(0x413c, 0x8185)},   /* Dell Gobi 2000 QDL device (N0218, VU936) */
0081     {USB_DEVICE(0x413c, 0x8186)},   /* Dell Gobi 2000 Modem device (N0218, VU936) */
0082     {USB_DEVICE(0x05c6, 0x9208)},   /* Generic Gobi 2000 QDL device */
0083     {USB_DEVICE(0x05c6, 0x920b)},   /* Generic Gobi 2000 Modem device */
0084     {USB_DEVICE(0x05c6, 0x9224)},   /* Sony Gobi 2000 QDL device (N0279, VU730) */
0085     {USB_DEVICE(0x05c6, 0x9225)},   /* Sony Gobi 2000 Modem device (N0279, VU730) */
0086     {USB_DEVICE(0x05c6, 0x9244)},   /* Samsung Gobi 2000 QDL device (VL176) */
0087     {USB_DEVICE(0x05c6, 0x9245)},   /* Samsung Gobi 2000 Modem device (VL176) */
0088     {USB_DEVICE(0x03f0, 0x241d)},   /* HP Gobi 2000 QDL device (VP412) */
0089     {USB_DEVICE(0x03f0, 0x251d)},   /* HP Gobi 2000 Modem device (VP412) */
0090     {USB_DEVICE(0x05c6, 0x9214)},   /* Acer Gobi 2000 QDL device (VP413) */
0091     {USB_DEVICE(0x05c6, 0x9215)},   /* Acer Gobi 2000 Modem device (VP413) */
0092     {USB_DEVICE(0x05c6, 0x9264)},   /* Asus Gobi 2000 QDL device (VR305) */
0093     {USB_DEVICE(0x05c6, 0x9265)},   /* Asus Gobi 2000 Modem device (VR305) */
0094     {USB_DEVICE(0x05c6, 0x9234)},   /* Top Global Gobi 2000 QDL device (VR306) */
0095     {USB_DEVICE(0x05c6, 0x9235)},   /* Top Global Gobi 2000 Modem device (VR306) */
0096     {USB_DEVICE(0x05c6, 0x9274)},   /* iRex Technologies Gobi 2000 QDL device (VR307) */
0097     {USB_DEVICE(0x05c6, 0x9275)},   /* iRex Technologies Gobi 2000 Modem device (VR307) */
0098     {USB_DEVICE(0x1199, 0x9000)},   /* Sierra Wireless Gobi 2000 QDL device (VT773) */
0099     {USB_DEVICE(0x1199, 0x9001)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
0100     {USB_DEVICE(0x1199, 0x9002)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
0101     {USB_DEVICE(0x1199, 0x9003)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
0102     {USB_DEVICE(0x1199, 0x9004)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
0103     {USB_DEVICE(0x1199, 0x9005)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
0104     {USB_DEVICE(0x1199, 0x9006)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
0105     {USB_DEVICE(0x1199, 0x9007)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
0106     {USB_DEVICE(0x1199, 0x9008)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
0107     {USB_DEVICE(0x1199, 0x9009)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
0108     {USB_DEVICE(0x1199, 0x900a)},   /* Sierra Wireless Gobi 2000 Modem device (VT773) */
0109     {USB_DEVICE(0x1199, 0x9011)},   /* Sierra Wireless Gobi 2000 Modem device (MC8305) */
0110     {USB_DEVICE(0x16d8, 0x8001)},   /* CMDTech Gobi 2000 QDL device (VU922) */
0111     {USB_DEVICE(0x16d8, 0x8002)},   /* CMDTech Gobi 2000 Modem device (VU922) */
0112     {USB_DEVICE(0x05c6, 0x9204)},   /* Gobi 2000 QDL device */
0113     {USB_DEVICE(0x05c6, 0x9205)},   /* Gobi 2000 Modem device */
0114 
0115     /* Gobi 3000 devices */
0116     {USB_DEVICE(0x03f0, 0x371d)},   /* HP un2430 Gobi 3000 QDL */
0117     {USB_DEVICE(0x05c6, 0x920c)},   /* Gobi 3000 QDL */
0118     {USB_DEVICE(0x05c6, 0x920d)},   /* Gobi 3000 Composite */
0119     {USB_DEVICE(0x1410, 0xa020)},   /* Novatel Gobi 3000 QDL */
0120     {USB_DEVICE(0x1410, 0xa021)},   /* Novatel Gobi 3000 Composite */
0121     {USB_DEVICE(0x413c, 0x8193)},   /* Dell Gobi 3000 QDL */
0122     {USB_DEVICE(0x413c, 0x8194)},   /* Dell Gobi 3000 Composite */
0123     {USB_DEVICE(0x413c, 0x81a6)},   /* Dell DW5570 QDL (MC8805) */
0124     {USB_DEVICE(0x1199, 0x68a4)},   /* Sierra Wireless QDL */
0125     {USB_DEVICE(0x1199, 0x68a5)},   /* Sierra Wireless Modem */
0126     {USB_DEVICE(0x1199, 0x68a8)},   /* Sierra Wireless QDL */
0127     {USB_DEVICE(0x1199, 0x68a9)},   /* Sierra Wireless Modem */
0128     {USB_DEVICE(0x1199, 0x9010)},   /* Sierra Wireless Gobi 3000 QDL */
0129     {USB_DEVICE(0x1199, 0x9012)},   /* Sierra Wireless Gobi 3000 QDL */
0130     {USB_DEVICE(0x1199, 0x9013)},   /* Sierra Wireless Gobi 3000 Modem device (MC8355) */
0131     {USB_DEVICE(0x1199, 0x9014)},   /* Sierra Wireless Gobi 3000 QDL */
0132     {USB_DEVICE(0x1199, 0x9015)},   /* Sierra Wireless Gobi 3000 Modem device */
0133     {USB_DEVICE(0x1199, 0x9018)},   /* Sierra Wireless Gobi 3000 QDL */
0134     {USB_DEVICE(0x1199, 0x9019)},   /* Sierra Wireless Gobi 3000 Modem device */
0135     {USB_DEVICE(0x1199, 0x901b)},   /* Sierra Wireless MC7770 */
0136     {USB_DEVICE(0x12D1, 0x14F0)},   /* Sony Gobi 3000 QDL */
0137     {USB_DEVICE(0x12D1, 0x14F1)},   /* Sony Gobi 3000 Composite */
0138     {USB_DEVICE(0x0AF0, 0x8120)},   /* Option GTM681W */
0139 
0140     /* non-Gobi Sierra Wireless devices */
0141     {DEVICE_SWI(0x03f0, 0x4e1d)},   /* HP lt4111 LTE/EV-DO/HSPA+ Gobi 4G Module */
0142     {DEVICE_SWI(0x0f3d, 0x68a2)},   /* Sierra Wireless MC7700 */
0143     {DEVICE_SWI(0x114f, 0x68a2)},   /* Sierra Wireless MC7750 */
0144     {DEVICE_SWI(0x1199, 0x68a2)},   /* Sierra Wireless MC7710 */
0145     {DEVICE_SWI(0x1199, 0x68c0)},   /* Sierra Wireless MC7304/MC7354 */
0146     {DEVICE_SWI(0x1199, 0x901c)},   /* Sierra Wireless EM7700 */
0147     {DEVICE_SWI(0x1199, 0x901e)},   /* Sierra Wireless EM7355 QDL */
0148     {DEVICE_SWI(0x1199, 0x901f)},   /* Sierra Wireless EM7355 */
0149     {DEVICE_SWI(0x1199, 0x9040)},   /* Sierra Wireless Modem */
0150     {DEVICE_SWI(0x1199, 0x9041)},   /* Sierra Wireless MC7305/MC7355 */
0151     {DEVICE_SWI(0x1199, 0x9051)},   /* Netgear AirCard 340U */
0152     {DEVICE_SWI(0x1199, 0x9053)},   /* Sierra Wireless Modem */
0153     {DEVICE_SWI(0x1199, 0x9054)},   /* Sierra Wireless Modem */
0154     {DEVICE_SWI(0x1199, 0x9055)},   /* Netgear AirCard 341U */
0155     {DEVICE_SWI(0x1199, 0x9056)},   /* Sierra Wireless Modem */
0156     {DEVICE_SWI(0x1199, 0x9060)},   /* Sierra Wireless Modem */
0157     {DEVICE_SWI(0x1199, 0x9061)},   /* Sierra Wireless Modem */
0158     {DEVICE_SWI(0x1199, 0x9062)},   /* Sierra Wireless EM7305 QDL */
0159     {DEVICE_SWI(0x1199, 0x9063)},   /* Sierra Wireless EM7305 */
0160     {DEVICE_SWI(0x1199, 0x9070)},   /* Sierra Wireless MC74xx */
0161     {DEVICE_SWI(0x1199, 0x9071)},   /* Sierra Wireless MC74xx */
0162     {DEVICE_SWI(0x1199, 0x9078)},   /* Sierra Wireless EM74xx */
0163     {DEVICE_SWI(0x1199, 0x9079)},   /* Sierra Wireless EM74xx */
0164     {DEVICE_SWI(0x1199, 0x907a)},   /* Sierra Wireless EM74xx QDL */
0165     {DEVICE_SWI(0x1199, 0x907b)},   /* Sierra Wireless EM74xx */
0166     {DEVICE_SWI(0x1199, 0x9090)},   /* Sierra Wireless EM7565 QDL */
0167     {DEVICE_SWI(0x1199, 0x9091)},   /* Sierra Wireless EM7565 */
0168     {DEVICE_SWI(0x1199, 0x90d2)},   /* Sierra Wireless EM9191 QDL */
0169     {DEVICE_SWI(0x1199, 0xc080)},   /* Sierra Wireless EM7590 QDL */
0170     {DEVICE_SWI(0x1199, 0xc081)},   /* Sierra Wireless EM7590 */
0171     {DEVICE_SWI(0x413c, 0x81a2)},   /* Dell Wireless 5806 Gobi(TM) 4G LTE Mobile Broadband Card */
0172     {DEVICE_SWI(0x413c, 0x81a3)},   /* Dell Wireless 5570 HSPA+ (42Mbps) Mobile Broadband Card */
0173     {DEVICE_SWI(0x413c, 0x81a4)},   /* Dell Wireless 5570e HSPA+ (42Mbps) Mobile Broadband Card */
0174     {DEVICE_SWI(0x413c, 0x81a8)},   /* Dell Wireless 5808 Gobi(TM) 4G LTE Mobile Broadband Card */
0175     {DEVICE_SWI(0x413c, 0x81a9)},   /* Dell Wireless 5808e Gobi(TM) 4G LTE Mobile Broadband Card */
0176     {DEVICE_SWI(0x413c, 0x81b1)},   /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card */
0177     {DEVICE_SWI(0x413c, 0x81b3)},   /* Dell Wireless 5809e Gobi(TM) 4G LTE Mobile Broadband Card (rev3) */
0178     {DEVICE_SWI(0x413c, 0x81b5)},   /* Dell Wireless 5811e QDL */
0179     {DEVICE_SWI(0x413c, 0x81b6)},   /* Dell Wireless 5811e QDL */
0180     {DEVICE_SWI(0x413c, 0x81cb)},   /* Dell Wireless 5816e QDL */
0181     {DEVICE_SWI(0x413c, 0x81cc)},   /* Dell Wireless 5816e */
0182     {DEVICE_SWI(0x413c, 0x81cf)},   /* Dell Wireless 5819 */
0183     {DEVICE_SWI(0x413c, 0x81d0)},   /* Dell Wireless 5819 */
0184     {DEVICE_SWI(0x413c, 0x81d1)},   /* Dell Wireless 5818 */
0185     {DEVICE_SWI(0x413c, 0x81d2)},   /* Dell Wireless 5818 */
0186 
0187     /* Huawei devices */
0188     {DEVICE_HWI(0x03f0, 0x581d)},   /* HP lt4112 LTE/HSPA+ Gobi 4G Modem (Huawei me906e) */
0189 
0190     { }             /* Terminating entry */
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      * Quectel EC20 Mini PCIe LTE module layout:
0200      * 0: DM/DIAG (use libqcdm from ModemManager for communication)
0201      * 1: NMEA
0202      * 2: AT-capable modem port
0203      * 3: Modem interface
0204      * 4: NDIS
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         /* Don't claim the QMI/net interface */
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     /* we only support vendor specific functions */
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         /* QDL mode */
0247         /* Gobi 2000 has a single altsetting, older ones have two */
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; /* Success */
0260             else
0261                 altsetting = 1;
0262         }
0263         goto done;
0264 
0265     }
0266 
0267     /* default to enabling interface */
0268     altsetting = 0;
0269 
0270     /*
0271      * Composite mode; don't bind to the QMI/net interface as that
0272      * gets handled by other drivers.
0273      */
0274 
0275     switch (id->driver_info) {
0276     case QCSERIAL_G1K:
0277         /*
0278          * Gobi 1K USB layout:
0279          * 0: DM/DIAG (use libqcdm from ModemManager for communication)
0280          * 1: serial port (doesn't respond)
0281          * 2: AT-capable modem port
0282          * 3: QMI/net
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         /* handle non-standard layouts */
0300         if (nintf == 5 && id->idProduct == QUECTEL_EC20_PID) {
0301             altsetting = handle_quectel_ec20(dev, ifnum);
0302             goto done;
0303         }
0304 
0305         /*
0306          * Gobi 2K+ USB layout:
0307          * 0: QMI/net
0308          * 1: DM/DIAG (use libqcdm from ModemManager for communication)
0309          * 2: AT-capable modem port
0310          * 3: NMEA
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             /* Don't claim the QMI/net interface */
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              * NMEA (serial line 9600 8N1)
0332              * # echo "\$GPS_START" > /dev/ttyUSBx
0333              * # echo "\$GPS_STOP"  > /dev/ttyUSBx
0334              */
0335             dev_dbg(dev, "Gobi 2K+ NMEA GPS interface found\n");
0336             break;
0337         }
0338         break;
0339     case QCSERIAL_SWI:
0340         /*
0341          * Sierra Wireless layout:
0342          * 0: DM/DIAG (use libqcdm from ModemManager for communication)
0343          * 2: NMEA
0344          * 3: AT-capable modem port
0345          * 8: QMI/net
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             /* don't claim any unsupported interface */
0361             altsetting = -1;
0362             break;
0363         }
0364         break;
0365     case QCSERIAL_HWI:
0366         /*
0367          * Huawei devices map functions by subclass + protocol
0368          * instead of interface numbers. The protocol identify
0369          * a specific function, while the subclass indicate a
0370          * specific firmware source
0371          *
0372          * This is a list of functions known to be non-serial.  The rest
0373          * are assumed to be serial and will be handled by this driver
0374          */
0375         switch (intf->desc.bInterfaceProtocol) {
0376             /* QMI combined (qmi_wwan) */
0377         case 0x07:
0378         case 0x37:
0379         case 0x67:
0380             /* QMI data (qmi_wwan) */
0381         case 0x08:
0382         case 0x38:
0383         case 0x68:
0384             /* QMI control (qmi_wwan) */
0385         case 0x09:
0386         case 0x39:
0387         case 0x69:
0388             /* NCM like (huawei_cdc_ncm) */
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");