[PATCH net-next/usb-next v3 0/5] cdc-wdm/qmi_wwan: subdriver support

STALE5275d

5 messages, 2 authors, 2012-03-06 · open the first message on its own page

[PATCH net-next/usb-next v3 0/5] cdc-wdm/qmi_wwan: subdriver support

From: Bjørn Mork <bjorn@mork.no>
Date: 2012-02-29 15:16:01

This patch set enables the cdc-wdm USB class driver to be used as a
subdriver, and updates the qmi_wwan usbnet minidriver to use this
new functionality.

The purpose is to support a number of 3G/LTE devices based on Qualcomm
chipsets providing a single USB interface combining usbnet and
Qualcomm Messaging Interface (QMI) protocol support.  The usbnet wwan
interface must be initialized via the QMI channel before it is usable.
This initialization is complex and depends on many user policy decisions.
By using the cdc-wdm driver to export the QMI interface as a character
device, all this complexity can be left to userspace applications.  This
makes us able to support a large number of different devices with very
different capabilities using a single relatively simple driver.

The 2 previous revisions of this set were considered work-in-progress
and were therefore only posted to the linux-usb list for discussion, to
avoid having them end up unnecessarily in netdev patchworks. 

Changes in v3:
 - move manage_power call in wdm_open() outside the section where we
   hold the wlock mutex
 - proper initialization of the pmcount counter
 - added all non-QDL Gobi device IDs from qcserial driver


Only patch 4 and 5 of this set applies to, and is crossposted to, netdev.

Note that the netdev patches still depend on the 3 first patches of this
set, and should not be applied independently. The 3 first do not yet
apply to net-next, as they depend on other patches in usb-next and
linux-next. Please let me know if this sort of cross-system
patch set should be handled otherwise.

All 5 patches are verified to apply cleanly to linux-next tag next-20120229.
Patches 1-3 are verified to apply to usb-next commit aac1fc386
Patches 4-5 are verified to apply to net-next commit 9100eb012 , but will
cause build errors there due to the lack of the required 3 first patches
as noted above.


Bjørn Mork (5):
  usb: cdc-wdm: split out reusable parts of probe
  usb: cdc-wdm: adding list lookup indirection
  usb: cdc-wdm: adding usb_cdc_wdm_register subdriver support
  net: qmi_wwan: support devices having a shared QMI/wwan interface
  net: qmi_wwan: add Gobi and Pantech UML290 device IDs

 drivers/net/usb/qmi_wwan.c  |  248 ++++++++++++++++++++++++++++++++++++++++---
 drivers/usb/class/cdc-wdm.c |  224 +++++++++++++++++++++++++++-----------
 include/linux/usb/cdc-wdm.h |   19 ++++
 3 files changed, 410 insertions(+), 81 deletions(-)
 create mode 100644 include/linux/usb/cdc-wdm.h

-- 
1.7.9

[PATCH net-next v3 4/5] net: qmi_wwan: support devices having a shared QMI/wwan interface

From: Bjørn Mork <bjorn@mork.no>
Date: 2012-02-29 15:16:04

Use the new cdc-wdm subdriver interface to create a device management
device even for USB devices having a single combined QMI/wwan USB
interface with three endpoints (int, bulk in, bulk out) instead of
separate data and control interfaces.

Some Huawei devices can be switched to a single interface mode for
use with other operating systems than Linux.  This adds support
for these devices when they run in such non-Linux modes.

Signed-off-by: Bjørn Mork <bjorn@mork.no>
---
Note that this patch requires not yet merged changes to the cdc-wdm
USB class driver (parts 1-3 of this patch set), and will cause build
errors if applied standalone to net-next.


 drivers/net/usb/qmi_wwan.c |  168 +++++++++++++++++++++++++++++++++++++++----
 1 files changed, 152 insertions(+), 16 deletions(-)
diff --git a/drivers/net/usb/qmi_wwan.c b/drivers/net/usb/qmi_wwan.c
index 739e6de..a61c7a1 100644
--- a/drivers/net/usb/qmi_wwan.c
+++ b/drivers/net/usb/qmi_wwan.c
@@ -13,6 +13,7 @@
 #include <linux/usb.h>
 #include <linux/usb/cdc.h>
 #include <linux/usb/usbnet.h>
+#include <linux/usb/cdc-wdm.h>
 
 /* The name of the CDC Device Management driver */
 #define DM_DRIVER "cdc_wdm"
@@ -64,6 +65,9 @@ static int qmi_wwan_bind(struct usbnet *dev, struct usb_interface *intf)
 	struct usb_cdc_ether_desc *cdc_ether = NULL;
 	u32 required = 1 << USB_CDC_HEADER_TYPE | 1 << USB_CDC_UNION_TYPE;
 	u32 found = 0;
+	atomic_t *pmcount = (void *)&dev->data[1];
+
+	atomic_set(pmcount, 0);
 
 	/*
 	 * assume a data interface has no additional descriptors and
@@ -170,13 +174,127 @@ err:
 	return status;
 }
 
-/* stolen from cdc_ether.c */
+/* using a counter to merge subdriver requests with our own into a combined state */
 static int qmi_wwan_manage_power(struct usbnet *dev, int on)
 {
-	dev->intf->needs_remote_wakeup = on;
-	return 0;
+	atomic_t *pmcount = (void *)&dev->data[1];
+	int rv = 0;
+
+	dev_dbg(&dev->intf->dev, "%s() pmcount=%d, on=%d\n", __func__, atomic_read(pmcount), on);
+
+	if ((on && atomic_add_return(1, pmcount) == 1) || (!on && atomic_dec_and_test(pmcount))) {
+		/* need autopm_get/put here to ensure the usbcore sees the new value */
+		rv = usb_autopm_get_interface(dev->intf);
+		if (rv < 0)
+			goto err;
+		dev->intf->needs_remote_wakeup = on;
+		usb_autopm_put_interface(dev->intf);
+	}
+err:
+	return rv;
+}
+
+static int qmi_wwan_cdc_wdm_manage_power(struct usb_interface *intf, int on)
+{
+	struct usbnet *dev = usb_get_intfdata(intf);
+	return qmi_wwan_manage_power(dev, on);
 }
 
+/* Some devices combine the "control" and "data" functions into a
+ * single interface with all three endpoints: interrupt + bulk in and
+ * out
+ *
+ * Setting up cdc-wdm as a subdriver owning the interrupt endpoint
+ * will let it provide userspace access to the encapsulated QMI
+ * protocol without interfering with the usbnet operations.
+  */
+static int qmi_wwan_bind_shared(struct usbnet *dev, struct usb_interface *intf)
+{
+	int rv;
+	struct usb_driver *subdriver = NULL;
+	atomic_t *pmcount = (void *)&dev->data[1];
+
+	atomic_set(pmcount, 0);
+
+	/* collect all three endpoints */
+	rv = usbnet_get_endpoints(dev, intf);
+	if (rv < 0)
+		goto err;
+
+	/* require interrupt endpoint for subdriver */
+	if (!dev->status) {
+		rv = -EINVAL;
+		goto err;
+	}
+
+	subdriver = usb_cdc_wdm_register(intf, &dev->status->desc, 512, &qmi_wwan_cdc_wdm_manage_power);
+	if (IS_ERR(subdriver)) {
+		rv = PTR_ERR(subdriver);
+		goto err;
+	}
+
+	/* can't let usbnet use the interrupt endpoint */
+	dev->status = NULL;
+
+	/* save subdriver struct for suspend/resume wrappers */
+	dev->data[0] = (unsigned long)subdriver;
+
+err:
+	return rv;
+}
+
+static void qmi_wwan_unbind_shared(struct usbnet *dev, struct usb_interface *intf)
+{
+	struct usb_driver *subdriver = (void *)dev->data[0];
+
+	if (subdriver && subdriver->disconnect)
+		subdriver->disconnect(intf);
+
+	dev->data[0] = (unsigned long)NULL;
+}
+
+/* suspend/resume wrappers calling both usbnet and the cdc-wdm
+ * subdriver if present.
+ *
+ * NOTE: cdc-wdm also supports pre/post_reset, but we cannot provide
+ * wrappers for those without adding usbnet reset support first.
+ */
+static int qmi_wwan_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	struct usbnet *dev = usb_get_intfdata(intf);
+	struct usb_driver *subdriver = (void *)dev->data[0];
+	int ret;
+
+	ret = usbnet_suspend(intf, message);
+	if (ret < 0)
+		goto err;
+
+	if (subdriver && subdriver->suspend)
+		ret = subdriver->suspend(intf, message);
+	if (ret < 0)
+		usbnet_resume(intf);
+err:
+	return ret;
+}
+
+static int qmi_wwan_resume(struct usb_interface *intf)
+{
+	struct usbnet *dev = usb_get_intfdata(intf);
+	struct usb_driver *subdriver = (void *)dev->data[0];
+	int ret = 0;
+
+	if (subdriver && subdriver->resume)
+		ret = subdriver->resume(intf);
+	if (ret < 0)
+		goto err;
+	ret = usbnet_resume(intf);
+	if (ret < 0 && subdriver && subdriver->resume && subdriver->suspend)
+		subdriver->suspend(intf, PMSG_SUSPEND);
+err:
+	return ret;
+}
+
+
 static const struct driver_info	qmi_wwan_info = {
 	.description	= "QMI speaking wwan device",
 	.flags		= FLAG_WWAN,
@@ -184,19 +302,37 @@ static const struct driver_info	qmi_wwan_info = {
 	.manage_power	= qmi_wwan_manage_power,
 };
 
+static const struct driver_info	qmi_wwan_shared = {
+	.description	= "QMI speaking wwan device with combined interface",
+	.flags		= FLAG_WWAN,
+	.bind		= qmi_wwan_bind_shared,
+	.unbind		= qmi_wwan_unbind_shared,
+	.manage_power	= qmi_wwan_manage_power,
+};
+
 #define HUAWEI_VENDOR_ID	0x12D1
 
 static const struct usb_device_id products[] = {
-{
-	/* Huawei E392, E398 and possibly others sharing both device id and more... */
-	.match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
-	.idVendor           = HUAWEI_VENDOR_ID,
-	.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
-	.bInterfaceSubClass = 1,
-	.bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */
-	.driver_info        = (unsigned long)&qmi_wwan_info,
-}, {
-},	/* END */
+	{	/* Huawei E392, E398 and possibly others sharing both device id and more... */
+		.match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor           = HUAWEI_VENDOR_ID,
+		.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
+		.bInterfaceSubClass = 1,
+		.bInterfaceProtocol = 8, /* NOTE: This is the *slave* interface of the CDC Union! */
+		.driver_info        = (unsigned long)&qmi_wwan_info,
+	},
+	{	/* Huawei E392, E398 and possibly others in "Windows mode"
+		 * using a combined control and data interface without any CDC
+		 * functional descriptors
+		 */
+		.match_flags        = USB_DEVICE_ID_MATCH_VENDOR | USB_DEVICE_ID_MATCH_INT_INFO,
+		.idVendor           = HUAWEI_VENDOR_ID,
+		.bInterfaceClass    = USB_CLASS_VENDOR_SPEC,
+		.bInterfaceSubClass = 1,
+		.bInterfaceProtocol = 17,
+		.driver_info        = (unsigned long)&qmi_wwan_shared,
+	},
+	{ }	/* END */
 };
 MODULE_DEVICE_TABLE(usb, products);
 
@@ -205,9 +341,9 @@ static struct usb_driver qmi_wwan_driver = {
 	.id_table	      = products,
 	.probe		      =	usbnet_probe,
 	.disconnect	      = usbnet_disconnect,
-	.suspend	      = usbnet_suspend,
-	.resume		      =	usbnet_resume,
-	.reset_resume         = usbnet_resume,
+	.suspend	      = qmi_wwan_suspend,
+	.resume		      =	qmi_wwan_resume,
+	.reset_resume         = qmi_wwan_resume,
 	.supports_autosuspend = 1,
 };
 
-- 
1.7.9

Re: [PATCH net-next/usb-next v3 0/5] cdc-wdm/qmi_wwan: subdriver support

From: Bjørn Mork <bjorn@mork.no>
Date: 2012-03-06 12:03:28

Bjørn Mork [off-list ref] writes:
Note that the netdev patches still depend on the 3 first patches of this
set, and should not be applied independently. The 3 first do not yet
apply to net-next, as they depend on other patches in usb-next and
linux-next. Please let me know if this sort of cross-system
patch set should be handled otherwise.

All 5 patches are verified to apply cleanly to linux-next tag next-20120229.
Patches 1-3 are verified to apply to usb-next commit aac1fc386
Patches 4-5 are verified to apply to net-next commit 9100eb012 , but will
cause build errors there due to the lack of the required 3 first patches
as noted above.

Bjørn Mork (5):
  usb: cdc-wdm: split out reusable parts of probe
  usb: cdc-wdm: adding list lookup indirection
  usb: cdc-wdm: adding usb_cdc_wdm_register subdriver support
  net: qmi_wwan: support devices having a shared QMI/wwan interface
  net: qmi_wwan: add Gobi and Pantech UML290 device IDs
Hello Greg,

I believe I may have promised to ping you when these patches were
ready.  Please apply patch 1-3 from this series to your usb-next branch
(for Linux 3.4). They were acked by Oliver a week ago.

Patches 4 and 5 (for netdev) will have to wait until the first 3 are
merged.


Bjørn

Re: [PATCH net-next/usb-next v3 0/5] cdc-wdm/qmi_wwan: subdriver support

From: Greg KH <gregkh@linuxfoundation.org>
Date: 2012-03-06 14:45:42

On Tue, Mar 06, 2012 at 01:03:11PM +0100, Bjørn Mork wrote:
Bjørn Mork [off-list ref] writes:
quoted
Note that the netdev patches still depend on the 3 first patches of this
set, and should not be applied independently. The 3 first do not yet
apply to net-next, as they depend on other patches in usb-next and
linux-next. Please let me know if this sort of cross-system
patch set should be handled otherwise.

All 5 patches are verified to apply cleanly to linux-next tag next-20120229.
Patches 1-3 are verified to apply to usb-next commit aac1fc386
Patches 4-5 are verified to apply to net-next commit 9100eb012 , but will
cause build errors there due to the lack of the required 3 first patches
as noted above.

Bjørn Mork (5):
  usb: cdc-wdm: split out reusable parts of probe
  usb: cdc-wdm: adding list lookup indirection
  usb: cdc-wdm: adding usb_cdc_wdm_register subdriver support
  net: qmi_wwan: support devices having a shared QMI/wwan interface
  net: qmi_wwan: add Gobi and Pantech UML290 device IDs
Hello Greg,

I believe I may have promised to ping you when these patches were
ready.  Please apply patch 1-3 from this series to your usb-next branch
(for Linux 3.4). They were acked by Oliver a week ago.
Great, can you resend them to me please, with Oliver's ack?  I don't see
them in my to-apply queue anymore as I thought they were still under
review.
Patches 4 and 5 (for netdev) will have to wait until the first 3 are
merged.
I can take them through my tree if they are dependant on the first 3,
that's not a problem.

thanks,

greg k-h

Re: [PATCH net-next/usb-next v3 0/5] cdc-wdm/qmi_wwan: subdriver support

From: Bjørn Mork <bjorn@mork.no>
Date: 2012-03-06 15:41:56

Greg KH [off-list ref] writes:
On Tue, Mar 06, 2012 at 01:03:11PM +0100, Bjørn Mork wrote:
quoted
I believe I may have promised to ping you when these patches were
ready.  Please apply patch 1-3 from this series to your usb-next branch
(for Linux 3.4). They were acked by Oliver a week ago.
Great, can you resend them to me please, with Oliver's ack?  I don't see
them in my to-apply queue anymore as I thought they were still under
review.
OK. Will do.
quoted
Patches 4 and 5 (for netdev) will have to wait until the first 3 are
merged.
I can take them through my tree if they are dependant on the first 3,
that's not a problem.
I've managed to make them dependent on not-yet-merged patches in
net-next as well (the initial addition of the qmi_wwan driver), so I
believe that will be equally difficult.  Bad planning from my side I
guess...


Bjørn
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help