NET: usb: cdc_mbim: add quirk for supporting Telit LE922A
authorDaniele Palmas <dnlplm@gmail.com>
Wed, 7 Dec 2016 13:07:48 +0000 (14:07 +0100)
committerDavid S. Miller <davem@davemloft.net>
Thu, 8 Dec 2016 18:02:25 +0000 (13:02 -0500)
Telit LE922A MBIM based composition does not work properly
with altsetting toggle done in cdc_ncm_bind_common.

This patch adds CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE quirk
to avoid this procedure that, instead, is mandatory for
other modems.

Signed-off-by: Daniele Palmas <dnlplm@gmail.com>
Reviewed-by: Bjørn Mork <bjorn@mork.no>
Signed-off-by: David S. Miller <davem@davemloft.net>
drivers/net/usb/cdc_mbim.c
drivers/net/usb/cdc_ncm.c
include/linux/usb/cdc_ncm.h

index 96a5028621c8b320c2d6feca5911f40cde10771e..3a98f3762a4c81debc023d04b9c01876c6cbdc5f 100644 (file)
@@ -602,6 +602,21 @@ static const struct driver_info cdc_mbim_info_ndp_to_end = {
        .data = CDC_NCM_FLAG_NDP_TO_END,
 };
 
+/* Some modems (e.g. Telit LE922A6) do not work properly with altsetting
+ * toggle done in cdc_ncm_bind_common. CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE
+ * flag is used to avoid this procedure.
+ */
+static const struct driver_info cdc_mbim_info_avoid_altsetting_toggle = {
+       .description = "CDC MBIM",
+       .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN,
+       .bind = cdc_mbim_bind,
+       .unbind = cdc_mbim_unbind,
+       .manage_power = cdc_mbim_manage_power,
+       .rx_fixup = cdc_mbim_rx_fixup,
+       .tx_fixup = cdc_mbim_tx_fixup,
+       .data = CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE,
+};
+
 static const struct usb_device_id mbim_devs[] = {
        /* This duplicate NCM entry is intentional. MBIM devices can
         * be disguised as NCM by default, and this is necessary to
@@ -626,6 +641,12 @@ static const struct usb_device_id mbim_devs[] = {
        { USB_VENDOR_AND_INTERFACE_INFO(0x12d1, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
          .driver_info = (unsigned long)&cdc_mbim_info_ndp_to_end,
        },
+
+       /* Telit LE922A6 in MBIM composition */
+       { USB_DEVICE_AND_INTERFACE_INFO(0x1bc7, 0x1041, USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
+         .driver_info = (unsigned long)&cdc_mbim_info_avoid_altsetting_toggle,
+       },
+
        /* default entry */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MBIM, USB_CDC_PROTO_NONE),
          .driver_info = (unsigned long)&cdc_mbim_info_zlp,
index 877c9516e78174dc41bd1e9d3f4c506d193134a9..afbfc0f656f331e82d4c8a528134ff892e2a8635 100644 (file)
@@ -839,11 +839,18 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
 
        iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
 
+       /* Device-specific flags */
+       ctx->drvflags = drvflags;
+
        /* Reset data interface. Some devices will not reset properly
         * unless they are configured first.  Toggle the altsetting to
-        * force a reset
+        * force a reset.
+        * Some other devices do not work properly with this procedure
+        * that can be avoided using quirk CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE
         */
-       usb_set_interface(dev->udev, iface_no, data_altsetting);
+       if (!(ctx->drvflags & CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE))
+               usb_set_interface(dev->udev, iface_no, data_altsetting);
+
        temp = usb_set_interface(dev->udev, iface_no, 0);
        if (temp) {
                dev_dbg(&intf->dev, "set interface failed\n");
@@ -890,9 +897,6 @@ int cdc_ncm_bind_common(struct usbnet *dev, struct usb_interface *intf, u8 data_
        /* finish setting up the device specific data */
        cdc_ncm_setup(dev);
 
-       /* Device-specific flags */
-       ctx->drvflags = drvflags;
-
        /* Allocate the delayed NDP if needed. */
        if (ctx->drvflags & CDC_NCM_FLAG_NDP_TO_END) {
                ctx->delayed_ndp16 = kzalloc(ctx->max_ndp_size, GFP_KERNEL);
index 3a375d07d0dc0284441133228af266956ed94f89..00d232406f18dbd1b6c27d1d24ca4c417d200530 100644 (file)
@@ -81,7 +81,8 @@
 #define CDC_NCM_TIMER_INTERVAL_MAX             (U32_MAX / NSEC_PER_USEC)
 
 /* Driver flags */
-#define CDC_NCM_FLAG_NDP_TO_END        0x02            /* NDP is placed at end of frame */
+#define CDC_NCM_FLAG_NDP_TO_END                        0x02    /* NDP is placed at end of frame */
+#define CDC_MBIM_FLAG_AVOID_ALTSETTING_TOGGLE  0x04    /* Avoid altsetting toggle during init */
 
 #define cdc_ncm_comm_intf_is_mbim(x)  ((x)->desc.bInterfaceSubClass == USB_CDC_SUBCLASS_MBIM && \
                                       (x)->desc.bInterfaceProtocol == USB_CDC_PROTO_NONE)