diff mbox

[RFC,3/3] huawei_cdc_ncm base skeleton

Message ID alpine.LNX.2.02.1307022213380.26010@eeeadesso
State Superseded, archived
Delegated to: David Miller
Headers show

Commit Message

Enrico Mioso July 2, 2013, 8:15 p.m. UTC
This is more an RFC than a patch.
This is the huawei_cdc_ncm driver skeleton - it handles the embedded AT channel 
on my device, and is stable upon usage, installing and removal.
The wwan interface is not functional - and surely there are lots of errors!

Signed-off-by: Enrico Mioso <mrkiko.rs@gmail.com>


--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Comments

Enrico Mioso July 3, 2013, 6:40 a.m. UTC | #1
Hi guys!
there's a problem ... I don't understand why even looking at the code (sure, I 
will look at it again): but, bringing up the wwan0 interface simply works. So 
now I'm sending this mail via the device's wwan interface and while looking and 
typing to the wdm character device, without any apparent problem.
I did not implement the status handler, but the driver seems to be able to 
work, probably missing some notifications?
This needs to be EXTRENSIVELY polished and reviewed - but it's encouraging!
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Enrico Mioso July 3, 2013, 7:11 a.m. UTC | #2
Ok ... As Bjorn stated, cdc-wdm is handling the notifications now - or, better: 
is not handling them, as it is not made to do these things! The connection 
stays up and the character device seems to work properly. Obviously cdc-wdm 
notices me about one single unknown notifications.
We're ignoring all the notifications from the NCM erspective, but all works 
because the device probably doesn't rely on them so much.

Aniway - now I'm conscious about why it works. Now it's time to improve the 
situation of the driver, and might be the api. Waiting for suggestions and 
injuries! :)

thank you everybody for the help...
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bjørn Mork July 3, 2013, 7:13 a.m. UTC | #3
Enrico Mioso <mrkiko.rs@gmail.com> writes:

> Hi guys!
> there's a problem ... I don't understand why even looking at the code (sure, I 
> will look at it again): but, bringing up the wwan0 interface simply works. So 
> now I'm sending this mail via the device's wwan interface and while looking and 
> typing to the wdm character device, without any apparent problem.
> I did not implement the status handler, but the driver seems to be able to 
> work, probably missing some notifications?
> This needs to be EXTRENSIVELY polished and reviewed - but it's encouraging!


Great work!

The NCM notifications should be handled, but I don't think it is crucial
to have that in place for the initial version of the driver. Adding that
support means changing the cdc-wdm API, which need some careful planning
and time because cdc-wdm is in another subsystem (usb vs net).

Since this driver is not dealing with NCM conformant devices, but only
implementing a NCM like vendor specific protocol, I believe it is
acceptable to handle the notifcations as "phase 2" of the driver.

In my opinion, all you need to do before submitting is fixup the device
list, moving the Huawei vendor specific entries from cdc_ncm to this
driver.  You might as well do that as part of introducing the driver.
Or make it a separate final patch if you prefer.



Bjørn
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bjørn Mork July 3, 2013, 7:38 a.m. UTC | #4
Enrico Mioso <mrkiko.rs@gmail.com> writes:

> This is more an RFC than a patch.

It looks pretty complete to me :)

> + * This code is based on the original cdc_ncm implementation, that is:
> + * Copyright (C) ST-Ericsson 2010-2012
> + * Contact: Alexey Orishko <alexey.orishko@stericsson.com>
> + * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com>
> + *
> + * USB Host Driver for Network Control Model (NCM)
> + * http://www.usb.org/developers/devclass_docs/NCM10.zip
> + *
> + * The NCM encoding, decoding and initialization logic
> + * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h
> + *
> + * This software is available to you under a choice of one of two
> + * licenses. You may choose this file to be licensed under the terms
> + * of the GNU General Public License (GPL) Version 2 or the 2-clause
> + * BSD license listed below:

This text does not match the MODULE_LICENSE you have used. You should
probably take a few minutes to think about how you want your work to be
licensed and use the appropriate combination of license comment and
MODULE_LICENSE.

You do in any case not need to copy all this from the cdc_ncm driver.
You reuse code via the exported API, but the code in this driver is
mostly your own.  A small note of cdc_ncm use is nice, but I don't think
it's any more necessary than for other kernel code you use via #includes.


> +/* Bind our driver to needed interfaces. Heavily inspired by cdc_mbim.c one! */

Many of your comments look mostly like notes for yourself.  Which they
probably are, given that you sent this as a RFC :)

You should go over all these comments and think about whether they are
useful for others reading this code.  I don't think this one is, for
example.

> +static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev, struct usb_interface *intf) {
> +
> +	/* Some general use variables */
> +	struct cdc_ncm_ctx *ctx;
> +	struct usb_driver *subdriver = ERR_PTR(-ENODEV);
> +	int ret = -ENODEV;
> +	struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
> +	
> +	/* Actually binds us to the device: use standard ncm function */
> +	ret = cdc_ncm_bind_common(usbnet_dev, intf, 1); /* altsetting should be 1 */
> +	
> +	/* Did the ncm bind function fail? */
> +	if (ret)
> +		goto err;
> +	
> +	/* Let cdc data ctx pointer point to our state structure */
> +	ctx = drvstate->ctx;
> +	
> +	if (usbnet_dev->status) 
> +		subdriver = usb_cdc_wdm_register(ctx->control, &usbnet_dev->status->desc, 4096, huawei_cdc_ncm_wdm_manage_power); /* a smarter way to calculate that constant? */

Yes, we were going to revisit that constant as soon as you discovered
the protocol.  Now you found that it is AT commands, which doesn't
really provide an absolute answer.  But AT commands is actually the
normal usecase for cdc-wdm, so I believe using the defaults from that
specification makes some sense.  As noted on the cdc-wdm driver:

  CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)"

Maybe 256 is enough here? Or are there Huawei specific AT commands with
larger responses than that?  I don't know.  Choose some number and
change the comment to explain the reasoning behind that choice.


> +	if (IS_ERR(subdriver)) {
> +	 ret = PTR_ERR(subdriver);
> +	 cdc_ncm_unbind(usbnet_dev, intf);
> +   goto err;
> +	}
> +	
> +	/* Prevent usbnet from using the status descriptor */
> +	usbnet_dev->status = NULL;
> +	
> +	drvstate->subdriver = subdriver;
> +	
> +	/* FIXME: should we handle the vlan header in some way? */

No, that is in cdc_mbim because it maps multiplexed MBIM IP sessions to
ethernet VLAN interfaces.  The devices supported by this driver cannot
support more than one IP session per USB function, so there is
absolutely nothing you or the firmware can map a VLAN to.  Just drop the
comment. 

> +	/* FIXME2: in my opinion we also could not do ARP, hoping somebody can help... */

The firmware obviously does ARP as it works whether you disable it or
not.  The usefulness can be discussed, but you cannot drop it without
testing that it does in fact work.  The firmware most likely use either
DHCP or ARP requests to figure out your MAC address, so the ARP requests
might be required even if they look silly.


> +static const struct usb_device_id huawei_cdc_ncm_devs[] = {
> +	/* The correct NCM handling will be implemented. For now, only my dongle
> +		will be handled.
> +		*/
> +	{ USB_DEVICE_INTERFACE_NUMBER(0x12d1, 0x1506, 1), \
> +		.driver_info = (unsigned long)&huawei_cdc_ncm_info,
> +	},
> +
> +	{
> +		/* Terminating entry */
> +	},
> +};


As you note, that table needs to match on class codes.  Just move the
Huawei vendor specific entries from cdc_ncm.



Bjørn
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Bjørn Mork July 3, 2013, 8:15 a.m. UTC | #5
Enrico Mioso <mrkiko.rs@gmail.com> writes:

> Ok ... As Bjorn stated, cdc-wdm is handling the notifications now - or, better: 
> is not handling them, as it is not made to do these things! The connection 
> stays up and the character device seems to work properly. Obviously cdc-wdm 
> notices me about one single unknown notifications.
> We're ignoring all the notifications from the NCM erspective, but all works 
> because the device probably doesn't rely on them so much.
> Aniway - now I'm conscious about why it works. Now it's time to improve the 
> situation of the driver, and might be the api. Waiting for suggestions and 
> injuries! :)

The only notification actually used for anything by cdc_ncm is
USB_CDC_NOTIFY_NETWORK_CONNECTION, which it uses to set the link up or
down. That functionality is disabled in your driver, leaving the link
always up.

This is of course not entirely correct if we apply a strict NCM
specification to this driver. But it does no harm either.  You have
added support for the embedded management channel, which must be used to
configure and connect the device.  Connection status will also be
reported here, and the managing userspace application (for example
ModemManager) will use this to pick up the actual network connection
state.  So the link state reported by NCM is redundant for these
devices.

The issue is that the few simple notifications standardized in CDC NCM
are sufficient for management of ethernet connections, but not for
3G/LTE connections.  That's why you need access to the additional vendor
specific management channel in the first place.  And when you have that
channel, then the additional NCM notifications are redundant at best.
Or confusing at worst.

The second notification implemented by cdc_ncm is
USB_CDC_NOTIFY_SPEED_CHANGE, which is shown in your logs.  But there is
nothing cdc_ncm can do with this, so it will just log it.  That's mostly
useless, both for wired and wireless devices.  3G/LTE management
applications will pick up the same information via the appropriate
management channel instead.

So the main reason why you should implement support for these
notifications eventually is not so much to handle them, but to silence
cdc-wdm. It will otherwise complain, which will confuse some users.  But
this is a really minor issue, and I see no reason why it should hold
back this driver.  It is perfectly usable as it is, and all necessary
features are implemented.


Bjørn
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Enrico Mioso July 3, 2013, 10:16 a.m. UTC | #6
First of all - thank you for all your comments and suggestions!




On Wed, 3 Jul 2013, Bj?rn Mork wrote:

==Date: Wed, 03 Jul 2013 09:38:40 +0200
==From: Bj?rn Mork <bjorn@mork.no>
==To: Enrico Mioso <mrkiko.rs@gmail.com>
==Cc: netdev@vger.kernel.org
==Subject: Re: [PATCH RFC 3/3] huawei_cdc_ncm base skeleton
==
==Enrico Mioso <mrkiko.rs@gmail.com> writes:
==
==> This is more an RFC than a patch.
==
==It looks pretty complete to me :)
==
==> + * This code is based on the original cdc_ncm implementation, that is:
==> + * Copyright (C) ST-Ericsson 2010-2012
==> + * Contact: Alexey Orishko <alexey.orishko@stericsson.com>
==> + * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com>
==> + *
==> + * USB Host Driver for Network Control Model (NCM)
==> + * http://www.usb.org/developers/devclass_docs/NCM10.zip
==> + *
==> + * The NCM encoding, decoding and initialization logic
==> + * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h
==> + *
==> + * This software is available to you under a choice of one of two
==> + * licenses. You may choose this file to be licensed under the terms
==> + * of the GNU General Public License (GPL) Version 2 or the 2-clause
==> + * BSD license listed below:
==
==This text does not match the MODULE_LICENSE you have used. You should
==probably take a few minutes to think about how you want your work to be
==licensed and use the appropriate combination of license comment and
==MODULE_LICENSE.
==
==You do in any case not need to copy all this from the cdc_ncm driver.
==You reuse code via the exported API, but the code in this driver is
==mostly your own.  A small note of cdc_ncm use is nice, but I don't think
==it's any more necessary than for other kernel code you use via #includes.
==
==

Thank you - right. I want my code to be GPL, no bsd license. Yes, I understand 
it're purely a personal choice, but wanted to be sincere.

==> +/* Bind our driver to needed interfaces. Heavily inspired by cdc_mbim.c one! */
==
==Many of your comments look mostly like notes for yourself.  Which they
==probably are, given that you sent this as a RFC :)
==
==You should go over all these comments and think about whether they are
==useful for others reading this code.  I don't think this one is, for
==example.
==
Yeah !! :) I'll remove them - they where here to help me understand the logic 
structure.

==> +static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev, struct usb_interface *intf) {
==> +
==> +	/* Some general use variables */
==> +	struct cdc_ncm_ctx *ctx;
==> +	struct usb_driver *subdriver = ERR_PTR(-ENODEV);
==> +	int ret = -ENODEV;
==> +	struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
==> +	
==> +	/* Actually binds us to the device: use standard ncm function */
==> +	ret = cdc_ncm_bind_common(usbnet_dev, intf, 1); /* altsetting should be 1 */
==> +	
==> +	/* Did the ncm bind function fail? */
==> +	if (ret)
==> +		goto err;
==> +	
==> +	/* Let cdc data ctx pointer point to our state structure */
==> +	ctx = drvstate->ctx;
==> +	
==> +	if (usbnet_dev->status) 
==> +		subdriver = usb_cdc_wdm_register(ctx->control, &usbnet_dev->status->desc, 4096, huawei_cdc_ncm_wdm_manage_power); /* a smarter way to calculate that constant? */
==
==Yes, we were going to revisit that constant as soon as you discovered
==the protocol.  Now you found that it is AT commands, which doesn't
==really provide an absolute answer.  But AT commands is actually the
==normal usecase for cdc-wdm, so I believe using the defaults from that
==specification makes some sense.  As noted on the cdc-wdm driver:
==
==  CDC-WMC r1.1 requires wMaxCommand to be "at least 256 decimal (0x100)"
==
==Maybe 256 is enough here? Or are there Huawei specific AT commands with
==larger responses than that?  I don't know.  Choose some number and
==change the comment to explain the reasoning behind that choice.
==
==
I don't know - a word from Huawei would be very helpful in this context. 
Aniway, I would think there are commands with very large payloads and messages.
What you think if we set this to 512?

==> +	if (IS_ERR(subdriver)) {
==> +	 ret = PTR_ERR(subdriver);
==> +	 cdc_ncm_unbind(usbnet_dev, intf);
==> +   goto err;
==> +	}
==> +	
==> +	/* Prevent usbnet from using the status descriptor */
==> +	usbnet_dev->status = NULL;
==> +	
==> +	drvstate->subdriver = subdriver;
==> +	
==> +	/* FIXME: should we handle the vlan header in some way? */
==
==No, that is in cdc_mbim because it maps multiplexed MBIM IP sessions to
==ethernet VLAN interfaces.  The devices supported by this driver cannot
==support more than one IP session per USB function, so there is
==absolutely nothing you or the firmware can map a VLAN to.  Just drop the
==comment. 
==
Fine!
==> +	/* FIXME2: in my opinion we also could not do ARP, hoping somebody can help... */
==
==The firmware obviously does ARP as it works whether you disable it or
==not.  The usefulness can be discussed, but you cannot drop it without
==testing that it does in fact work.  The firmware most likely use either
==DHCP or ARP requests to figure out your MAC address, so the ARP requests
==might be required even if they look silly.
==
==
I will proceed with the test in some minutes!

==> +static const struct usb_device_id huawei_cdc_ncm_devs[] = {
==> +	/* The correct NCM handling will be implemented. For now, only my dongle
==> +		will be handled.
==> +		*/
==> +	{ USB_DEVICE_INTERFACE_NUMBER(0x12d1, 0x1506, 1), \
==> +		.driver_info = (unsigned long)&huawei_cdc_ncm_info,
==> +	},
==> +
==> +	{
==> +		/* Terminating entry */
==> +	},
==> +};
==
==
==As you note, that table needs to match on class codes.  Just move the
==Huawei vendor specific entries from cdc_ncm.
==
Here I'm a little bit confused - it seems there are device exporting QMI inside 
ncm, devices exporting AT and even devices exporting other unspecified 
protocol... or at least this was what I understood from google and various 
reports.
I will move all the entries - hoping not to cause regressions for cdc_ncm 
users!!

==
==
==Bj?rn
==
Thank you again for your help.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
diff mbox

Patch

diff --git a/drivers/net/usb/huawei_cdc_ncm.c b/drivers/net/usb/huawei_cdc_ncm.c
new file mode 100644
index 0000000..2e76c87
--- /dev/null
+++ b/drivers/net/usb/huawei_cdc_ncm.c
@@ -0,0 +1,239 @@ 
+/*
+ * huawei_cdc_ncm.c - handles hawei-style NCM devices.
+ * Copyright (C) Enrico Mioso <mrkiko.rs@gmail.com>
+ * This driver handles devices resembling the CDC NCM standard, but 
+ * encapsulating another protocl inside it. An example are some Huawei modems.
+ * This code is based on the original cdc_ncm implementation, that is:
+ * Copyright (C) ST-Ericsson 2010-2012
+ * Contact: Alexey Orishko <alexey.orishko@stericsson.com>
+ * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com>
+ *
+ * USB Host Driver for Network Control Model (NCM)
+ * http://www.usb.org/developers/devclass_docs/NCM10.zip
+ *
+ * The NCM encoding, decoding and initialization logic
+ * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose this file to be licensed under the terms
+ * of the GNU General Public License (GPL) Version 2 or the 2-clause
+ * BSD license listed below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/ip.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/usb/cdc.h>
+#include <linux/usb/usbnet.h>
+#include <linux/usb/cdc-wdm.h>
+#include <linux/usb/cdc_ncm.h>
+
+/* Specific driver data */
+struct huawei_cdc_ncm_state {
+	struct cdc_ncm_ctx *ctx;
+	atomic_t pmcount;
+	struct usb_driver *subdriver;
+	struct usb_interface *control;
+	struct usb_interface *data;
+};
+
+static int huawei_cdc_ncm_manage_power(struct usbnet *usbnet_dev, int on)
+{
+	struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
+	int rv = 0;
+
+	if ((on && atomic_add_return(1, &drvstate->pmcount) == 1) || (!on && atomic_dec_and_test(&drvstate->pmcount))) {
+		rv = usb_autopm_get_interface(usbnet_dev->intf);
+		if (rv < 0)
+			goto err;
+		usbnet_dev->intf->needs_remote_wakeup = on;
+		usb_autopm_put_interface(usbnet_dev->intf);
+	}
+err:
+	return rv;
+}
+
+static int huawei_cdc_ncm_wdm_manage_power(struct usb_interface *intf, int status)
+{
+	struct usbnet *usbnet_dev = usb_get_intfdata(intf);
+
+	/* can be called while disconnecting */
+	if (!usbnet_dev)
+		return 0;
+
+	return huawei_cdc_ncm_manage_power(usbnet_dev, status);
+}
+
+
+/* Bind our driver to needed interfaces. Heavily inspired by cdc_mbim.c one! */
+static int huawei_cdc_ncm_bind(struct usbnet *usbnet_dev, struct usb_interface *intf) {
+
+	/* Some general use variables */
+	struct cdc_ncm_ctx *ctx;
+	struct usb_driver *subdriver = ERR_PTR(-ENODEV);
+	int ret = -ENODEV;
+	struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
+	
+	/* Actually binds us to the device: use standard ncm function */
+	ret = cdc_ncm_bind_common(usbnet_dev, intf, 1); /* altsetting should be 1 */
+	
+	/* Did the ncm bind function fail? */
+	if (ret)
+		goto err;
+	
+	/* Let cdc data ctx pointer point to our state structure */
+	ctx = drvstate->ctx;
+	
+	if (usbnet_dev->status) 
+		subdriver = usb_cdc_wdm_register(ctx->control, &usbnet_dev->status->desc, 4096, huawei_cdc_ncm_wdm_manage_power); /* a smarter way to calculate that constant? */
+	if (IS_ERR(subdriver)) {
+	 ret = PTR_ERR(subdriver);
+	 cdc_ncm_unbind(usbnet_dev, intf);
+   goto err;
+	}
+	
+	/* Prevent usbnet from using the status descriptor */
+	usbnet_dev->status = NULL;
+	
+	drvstate->subdriver = subdriver;
+	
+	/* FIXME: should we handle the vlan header in some way? */
+	/* FIXME2: in my opinion we also could not do ARP, hoping somebody can help... */
+err:
+	return ret; /* ret = -ENODEV if not changed in the meanwhile */
+}
+
+static void huawei_cdc_ncm_unbind(struct usbnet *usbnet_dev, struct usb_interface *intf) {
+	struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
+	struct cdc_ncm_ctx *ctx = drvstate->ctx;
+	
+	/* Bye cdc-wdm! And see you soon! :) */
+	if (drvstate->subdriver && drvstate->subdriver->disconnect)
+		drvstate->subdriver->disconnect(ctx->control);
+	drvstate->subdriver = NULL;
+	
+	/* Unbind from both control and data interface */
+	cdc_ncm_unbind(usbnet_dev, intf);
+}
+
+/* Suspend function - the logic has been taken from cdc_mbim.c directly. */
+static int huawei_cdc_ncm_suspend(struct usb_interface *intf, pm_message_t message)
+{
+	int ret = 0;
+	struct usbnet *usbnet_dev = usb_get_intfdata(intf);
+	struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
+	struct cdc_ncm_ctx *ctx = drvstate->ctx;
+
+	if (ctx == NULL) {
+		ret = -1;
+		goto error;
+	}
+
+	/*
+	 * Both usbnet_suspend() and subdriver->suspend() MUST return 0
+	 * in system sleep context, otherwise, the resume callback has
+	 * to recover device from previous suspend failure.
+	 */
+	ret = usbnet_suspend(intf, message);
+	if (ret < 0)
+		goto error;
+
+	if (intf == ctx->control && drvstate->subdriver && drvstate->subdriver->suspend)
+		ret = drvstate->subdriver->suspend(intf, message);
+	if (ret < 0)
+		usbnet_resume(intf);
+
+error:
+	return ret;
+}
+
+/* Resume function - logic took completely from huawei_cdc.c */
+static int huawei_cdc_ncm_resume(struct usb_interface *intf)
+{
+	int ret = 0;
+	struct usbnet *usbnet_dev = usb_get_intfdata(intf);
+	struct huawei_cdc_ncm_state *drvstate = (void *)&usbnet_dev->data;
+	struct cdc_ncm_ctx *ctx = drvstate->ctx;
+	bool callsub = (intf == ctx->control && drvstate->subdriver && drvstate->subdriver->resume); /* should we call subdriver's resume? ? */
+
+	if (callsub)
+		ret = drvstate->subdriver->resume(intf);
+	if (ret < 0)
+		goto err;
+	ret = usbnet_resume(intf);
+	if (ret < 0 && callsub && drvstate->subdriver->suspend)
+		drvstate->subdriver->suspend(intf, PMSG_SUSPEND);
+err:
+	return ret;
+}
+
+
+/* General driver informations, exposed partly to modutils */
+static const struct driver_info huawei_cdc_ncm_info = {
+	.description = "Huawei-style CDC NCM",
+	.flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET | FLAG_WWAN,
+	.bind = huawei_cdc_ncm_bind,
+	.unbind = huawei_cdc_ncm_unbind,
+	.manage_power = huawei_cdc_ncm_manage_power,
+	/* NCM RX and TX fixup functions work properly on these devices */
+	.rx_fixup = cdc_ncm_rx_fixup,
+	.tx_fixup = cdc_ncm_tx_fixup,
+};
+
+static const struct usb_device_id huawei_cdc_ncm_devs[] = {
+	/* The correct NCM handling will be implemented. For now, only my dongle
+		will be handled.
+		*/
+	{ USB_DEVICE_INTERFACE_NUMBER(0x12d1, 0x1506, 1), \
+		.driver_info = (unsigned long)&huawei_cdc_ncm_info,
+	},
+
+	{
+		/* Terminating entry */
+	},
+};
+/* Expose table in module info */
+MODULE_DEVICE_TABLE(usb, huawei_cdc_ncm_devs);
+
+
+/* USB driver struct - used by USB stack */
+static struct usb_driver huawei_cdc_ncm_driver = {
+	.name = "huawei_cdc_ncm",
+	.id_table = huawei_cdc_ncm_devs,
+	.probe = usbnet_probe,
+	.disconnect = usbnet_disconnect,
+	.suspend = huawei_cdc_ncm_suspend,
+	.resume = huawei_cdc_ncm_resume,
+	.reset_resume = huawei_cdc_ncm_resume,
+	.supports_autosuspend = 1,
+	.disable_hub_initiated_lpm = 1,
+};
+module_usb_driver(huawei_cdc_ncm_driver);
+MODULE_AUTHOR("Enrico Mioso <mrkiko.rs@gmail.com>");
+MODULE_DESCRIPTION("USB CDC NCM host driver with encapsulated protocol support");
+MODULE_LICENSE("GPL");