[PATCH 2/3] drivers: net: usb: sierra_net - upgrade to 3.2

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



driver was upgraded from 2.0 to 3.2
source of the driver at the time of this change:
http://www.sierrawireless.com/resources/support/drivers/linux/v3.2_1740_kernel-3.0.directIP.tar

The driver compiles (monolithic and module)
I have not tested it on any device

Signed-off-by: Autif Khan <autifk@xxxxxxxxx>
---
 drivers/net/usb/sierra_net.c |  205 ++++++++++++++++++++++++++++++++++--------
 1 files changed, 168 insertions(+), 37 deletions(-)

diff --git a/drivers/net/usb/sierra_net.c b/drivers/net/usb/sierra_net.c
index b59cf20..f6057d9 100644
--- a/drivers/net/usb/sierra_net.c
+++ b/drivers/net/usb/sierra_net.c
@@ -1,7 +1,7 @@
 /*
  * USB-to-WWAN Driver for Sierra Wireless modems
  *
- * Copyright (C) 2008, 2009, 2010 Paxton Smith, Matthew Safar, Rory Filer
+ * Copyright (C) 2008 - 2011 Paxton Smith, Matthew Safar, Rory Filer
  *                          <linux@xxxxxxxxxxxxxxxxxx>
  *
  * Portions of this based on the cdc_ether driver by David Brownell (2003-2005)
@@ -25,13 +25,17 @@
  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  */
 
-#define DRIVER_VERSION "v.2.0"
+#define DRIVER_VERSION "v.3.2"
 #define DRIVER_AUTHOR "Paxton Smith, Matthew Safar, Rory Filer"
 #define DRIVER_DESC "USB-to-WWAN Driver for Sierra Wireless modems"
 static const char driver_name[] = "sierra_net";
 
 /* if defined debug messages enabled */
 /*#define	DEBUG*/
+/* more debug messages */
+/*#define	VERBOSE*/
+/* Uncomment to force power level set to auto when attaching a device */
+/*#define POWER_LEVEL_AUTO*/
 
 #include <linux/module.h>
 #include <linux/etherdevice.h>
@@ -48,6 +52,7 @@ static const char driver_name[] = "sierra_net";
 
 #define SWI_USB_REQUEST_GET_FW_ATTR	0x06
 #define SWI_GET_FW_ATTR_MASK		0x08
+#define SWI_GET_FW_ATTR_APM			0x2
 
 /* atomic counter partially included in MAC address to make sure 2 devices
  * do not end up with the same MAC - concept breaks in case of > 255 ifaces
@@ -68,6 +73,11 @@ static	atomic_t iface_counter = ATOMIC_INIT(0);
  */
 #define SIERRA_NET_USBCTL_BUF_LEN	1024
 
+/* The SIERRA_NET_RX_URB_SZ defines the receive urb size
+ * for optimal throughput.
+ */
+#define SIERRA_NET_RX_URB_SZ		1540
+
 /* list of interface numbers - used for constructing interface lists */
 struct sierra_net_iface_info {
 	const u32 infolen;	/* number of interface numbers on list */
@@ -139,6 +149,7 @@ struct param {
 #define SIERRA_NET_SESSION_IDLE       0x00
 /* LSI Link types */
 #define SIERRA_NET_AS_LINK_TYPE_IPv4  0x00
+#define SIERRA_NET_AS_LINK_TYPE_IPv6  0x02
 
 struct lsi_umts {
 	u8 protocol;
@@ -200,10 +211,11 @@ static inline void sierra_net_set_private(struct usbnet *dev,
 	dev->data[0] = (unsigned long)priv;
 }
 
-/* is packet IPv4 */
+/* is packet IP */
 static inline int is_ip(struct sk_buff *skb)
 {
-	return skb->protocol == cpu_to_be16(ETH_P_IP);
+	return ((skb->protocol == cpu_to_be16(ETH_P_IP)) ||
+			(skb->protocol == cpu_to_be16(ETH_P_IPV6)));
 }
 
 /*
@@ -312,6 +324,24 @@ static void build_hip(u8 *buf, const u16 payloadlen,
 /*----------------------------------------------------------------------------*
  *                              END HIP                                       *
  *----------------------------------------------------------------------------*/
+/* This should come out before going to kernel.org */
+static void sierra_net_printk_buf(u8 *buf, u16 len)
+{
+#ifdef VERBOSE
+	u16 i;
+	u16 k;
+
+	for (i = k = 0; i < len / 4; i++, k += 4) {
+		printk(KERN_DEBUG "%02x%02x%02x%02x ",
+			buf[k+0], buf[k+1], buf[k+2], buf[k+3]);
+	}
+
+	for (; k < len;  k++)
+		printk(KERN_DEBUG "%02x", buf[k]);
+
+	printk("\n");
+#endif
+}
 
 static int sierra_net_send_cmd(struct usbnet *dev,
 		u8 *cmd, int cmdlen, const char * cmd_name)
@@ -319,10 +349,12 @@ static int sierra_net_send_cmd(struct usbnet *dev,
 	struct sierra_net_data *priv = sierra_net_get_private(dev);
 	int  status;
 
+	usb_autopm_get_interface(dev->intf);
 	status = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
 			USB_CDC_SEND_ENCAPSULATED_COMMAND,
 			USB_DIR_OUT|USB_TYPE_CLASS|USB_RECIP_INTERFACE,	0,
 			priv->ifnum, cmd, cmdlen, USB_CTRL_SET_TIMEOUT);
+	usb_autopm_put_interface(dev->intf);
 
 	if (status != cmdlen && status != -ENODEV)
 		netdev_err(dev->net, "Submit %s failed %d\n", cmd_name, status);
@@ -339,8 +371,17 @@ static int sierra_net_send_sync(struct usbnet *dev)
 
 	status = sierra_net_send_cmd(dev, priv->sync_msg,
 			sizeof(priv->sync_msg), "SYNC");
+    return status;
+}
 
-	return status;
+static void sierra_net_send_shutdown(struct usbnet *dev)
+{
+	struct sierra_net_data *priv = sierra_net_get_private(dev);
+
+	dev_dbg(&dev->udev->dev, "%s", __func__);
+
+	sierra_net_send_cmd(dev, priv->shdwn_msg,
+			sizeof(priv->shdwn_msg), "Shutdown");
 }
 
 static void sierra_net_set_ctx_index(struct sierra_net_data *priv, u8 ctx_ix)
@@ -354,7 +395,7 @@ static void sierra_net_set_ctx_index(struct sierra_net_data *priv, u8 ctx_ix)
 
 static inline int sierra_net_is_valid_addrlen(u8 len)
 {
-	return len == sizeof(struct in_addr);
+	return (len == sizeof(struct in_addr));
 }
 
 static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen)
@@ -383,10 +424,11 @@ static int sierra_net_parse_lsi(struct usbnet *dev, char *data, int datalen)
 	}
 
 	/* Validate the link type */
-	if (lsi->link_type != SIERRA_NET_AS_LINK_TYPE_IPv4) {
-		netdev_err(dev->net, "Link type unsupported: 0x%02x\n",
+	if ((lsi->link_type != SIERRA_NET_AS_LINK_TYPE_IPv4) &&
+		(lsi->link_type != SIERRA_NET_AS_LINK_TYPE_IPv6)) {
+		netdev_err(dev->net, "Link unavailable: 0x%02x",
 			lsi->link_type);
-		return -1;
+		return 0;
 	}
 
 	/* Validate the coverage */
@@ -474,13 +516,15 @@ static void sierra_net_kevent(struct work_struct *work)
 			return;
 		}
 		ifnum = priv->ifnum;
+		usb_autopm_get_interface(dev->intf);
 		len = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
 				USB_CDC_GET_ENCAPSULATED_RESPONSE,
 				USB_DIR_IN|USB_TYPE_CLASS|USB_RECIP_INTERFACE,
 				0, ifnum, buf, SIERRA_NET_USBCTL_BUF_LEN,
 				USB_CTRL_SET_TIMEOUT);
+		usb_autopm_put_interface(dev->intf);
 
-		if (len < 0) {
+		if (unlikely(len < 0)) {
 			netdev_err(dev->net,
 				"usb_control_msg failed, status %d\n", len);
 		} else {
@@ -488,6 +532,7 @@ static void sierra_net_kevent(struct work_struct *work)
 
 			dev_dbg(&dev->udev->dev, "%s: Received status message,"
 				" %04x bytes", __func__, len);
+			sierra_net_printk_buf(buf, len);
 
 			err = parse_hip(buf, len, &hh);
 			if (err) {
@@ -534,7 +579,10 @@ static void sierra_net_kevent(struct work_struct *work)
 					"extmsgid 0x%04x\n", hh.extmsgid.word);
 				break;
 			case SIERRA_NET_HIP_RCGI:
-				/* Ignored */
+				/* Ignored. It is a firmware
+				 * workaround to solve a  Windows driver bug and
+				 * may be removed in the future. 
+				 */
 				break;
 			default:
 				netdev_err(dev->net, "Unrecognized HIP msg, "
@@ -561,7 +609,10 @@ static void sierra_net_defer_kevent(struct usbnet *dev, int work)
 	struct sierra_net_data *priv = sierra_net_get_private(dev);
 
 	set_bit(work, &priv->kevent_flags);
-	schedule_work(&priv->sierra_net_kevent);
+	if (!schedule_work(&priv->sierra_net_kevent))
+		dev_dbg(&dev->udev->dev, "sierra_net_kevent %d may have been dropped", work);
+	else
+		dev_dbg(&dev->udev->dev, "sierra_net_kevent %d scheduled", work);
 }
 
 /*
@@ -581,6 +632,7 @@ static void sierra_net_status(struct usbnet *dev, struct urb *urb)
 	struct usb_cdc_notification *event;
 
 	dev_dbg(&dev->udev->dev, "%s", __func__);
+	sierra_net_printk_buf(urb->transfer_buffer, urb->actual_length);
 
 	if (urb->actual_length < sizeof *event)
 		return;
@@ -618,7 +670,7 @@ static u32 sierra_net_get_link(struct net_device *net)
 	return sierra_net_get_private(dev)->link_up && netif_running(net);
 }
 
-static const struct ethtool_ops sierra_net_ethtool_ops = {
+static struct ethtool_ops sierra_net_ethtool_ops = {
 	.get_drvinfo = sierra_net_get_drvinfo,
 	.get_link = sierra_net_get_link,
 	.get_msglevel = usbnet_get_msglevel,
@@ -661,6 +713,7 @@ static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap)
 	if (!attrdata)
 		return -ENOMEM;
 
+	usb_autopm_get_interface(dev->intf);
 	result = usb_control_msg(
 			dev->udev,
 			usb_rcvctrlpipe(dev->udev, 0),
@@ -672,6 +725,7 @@ static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap)
 			attrdata,	/* char *data */
 			sizeof(*attrdata),		/* __u16 size */
 			USB_CTRL_SET_TIMEOUT);	/* int timeout */
+	usb_autopm_put_interface(dev->intf);
 
 	if (result < 0) {
 		kfree(attrdata);
@@ -684,6 +738,12 @@ static int sierra_net_get_fw_attr(struct usbnet *dev, u16 *datap)
 	return result;
 }
 
+static int sierra_net_manage_power(struct usbnet *dev, int on)
+{
+	dev->intf->needs_remote_wakeup = on;
+	return 0;
+}
+
 /*
  * collects the bulk endpoints, the status endpoint.
  */
@@ -735,6 +795,10 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
 
 	priv->usbnet = dev;
 	priv->ifnum = ifacenum;
+	/* override change_mtu with our own routine - need to bound check */
+	/* replace structure to our own structure where we have our own
+	 *  routine - need to bound check
+	 */
 	dev->net->netdev_ops = &sierra_net_device_ops;
 
 	/* change MAC addr to include, ifacenum, and to be unique */
@@ -761,6 +825,7 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
 
 	/* Set up the netdev */
 	dev->net->flags |= IFF_NOARP;
+	dev->net->flags |= IFF_MULTICAST;
 	dev->net->ethtool_ops = &sierra_net_ethtool_ops;
 	netif_carrier_off(dev->net);
 
@@ -773,11 +838,23 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
 
 	/* Only need to do this once */
 	init_timer(&priv->sync_timer);
-
 	/* verify fw attributes */
 	status = sierra_net_get_fw_attr(dev, &fwattr);
-	dev_dbg(&dev->udev->dev, "Fw attr: %x\n", fwattr);
-
+	dev_dbg(&dev->udev->dev, "Fw attr: %x\n", fwattr); 
+	if (status == sizeof(fwattr) && (fwattr & SWI_GET_FW_ATTR_APM)) {
+/******************************************************************************* 
+ * If you want the default /sys/bus/usb/devices/.../.../power/level to be forced
+ * to auto, the following needs to be compiled in.
+ */ 
+#ifdef POWER_LEVEL_AUTO
+		/* make power level default be 'auto' */
+		dev_dbg(&dev->udev->dev, "Enabling APM");
+		usb_enable_autosuspend(dev->udev);
+#endif
+	} else {
+		dev_info(&intf->dev, "Disabling APM - not supported");
+		usb_disable_autosuspend(dev->udev);
+	}
 	/* test whether firmware supports DHCP */
 	if (!(status == sizeof(fwattr) && (fwattr & SWI_GET_FW_ATTR_MASK))) {
 		/* found incompatible firmware version */
@@ -789,33 +866,45 @@ static int sierra_net_bind(struct usbnet *dev, struct usb_interface *intf)
 	/* prepare sync message from template */
 	memcpy(priv->sync_msg, sync_tmplate, sizeof(priv->sync_msg));
 
+	return 0;
+}
+
+static void sierra_net_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+	struct sierra_net_data *priv = sierra_net_get_private(dev);
+
+	dev_dbg(&dev->udev->dev, "%s", __func__);
+
+	sierra_net_set_private(dev, NULL);
+
+	kfree(priv);
+}
+
+static int sierra_net_open(struct usbnet *dev)
+{
+	dev_dbg(&dev->udev->dev, "%s", __func__);
+
 	/* initiate the sync sequence */
 	sierra_net_dosync(dev);
 
 	return 0;
 }
 
-static void sierra_net_unbind(struct usbnet *dev, struct usb_interface *intf)
+static int sierra_net_stop(struct usbnet *dev)
 {
-	int status;
 	struct sierra_net_data *priv = sierra_net_get_private(dev);
 
 	dev_dbg(&dev->udev->dev, "%s", __func__);
 
-	/* kill the timer and work */
+	/* Kill the timer then flush the work queue */
 	del_timer_sync(&priv->sync_timer);
+
 	cancel_work_sync(&priv->sierra_net_kevent);
 
 	/* tell modem we are going away */
-	status = sierra_net_send_cmd(dev, priv->shdwn_msg,
-			sizeof(priv->shdwn_msg), "Shutdown");
-	if (status < 0)
-		netdev_err(dev->net,
-			"usb_control_msg failed, status %d\n", status);
-
-	sierra_net_set_private(dev, NULL);
+	sierra_net_send_shutdown(dev);
 
-	kfree(priv);
+	return 0;
 }
 
 static struct sk_buff *sierra_net_skb_clone(struct usbnet *dev,
@@ -847,9 +936,13 @@ static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 	int err;
 	struct hip_hdr  hh;
 	struct sk_buff *new_skb;
+	struct ethhdr *eth;
+	struct iphdr *ip;
 
 	dev_dbg(&dev->udev->dev, "%s", __func__);
 
+	sierra_net_printk_buf(skb->data, skb->len);
+
 	/* could contain multiple packets */
 	while (likely(skb->len)) {
 		err = parse_hip(skb->data, skb->len, &hh);
@@ -879,6 +972,12 @@ static int sierra_net_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
 		memcpy(skb->data, sierra_net_get_private(dev)->ethr_hdr_tmpl,
 			ETH_HLEN);
 
+		ip = (struct iphdr *)((char *)skb->data + ETH_HLEN);
+		if(ip->version == 6) {
+			eth = (struct ethhdr *)skb->data;
+			eth->h_proto = cpu_to_be16(ETH_P_IPV6);
+		}
+
 		/* Last packet in batch handled by usbnet */
 		if (hh.payload_len.word == skb->len)
 			return 1;
@@ -900,9 +999,6 @@ struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
 	u16 len;
 	bool need_tail;
 
-	BUILD_BUG_ON(FIELD_SIZEOF(struct usbnet, data)
-				< sizeof(struct cdc_state));
-
 	dev_dbg(&dev->udev->dev, "%s", __func__);
 	if (priv->link_up && check_ethip_packet(skb, dev) && is_ip(skb)) {
 		/* enough head room as is? */
@@ -926,6 +1022,8 @@ struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
 				}
 			}
 			build_hip(skb->data, len, priv);
+
+            sierra_net_printk_buf(skb->data, skb->len);
 			return skb;
 		} else {
 			/*
@@ -945,16 +1043,24 @@ struct sk_buff *sierra_net_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
 	return NULL;
 }
 
+static int sierra_net_reset_resume(struct usb_interface *intf)
+{
+	struct usbnet	*dev = usb_get_intfdata(intf);
+	netdev_err(dev->net, "%s\n", __func__);
+	return usbnet_resume(intf);
+}
+
 static const u8 sierra_net_ifnum_list[] = { 7, 10, 11 };
-static const struct sierra_net_info_data sierra_net_info_data_68A3 = {
-	.rx_urb_size = 8 * 1024,
+static const struct sierra_net_info_data sierra_net_info_data_direct_ip = {
+	/* .rx_urb_size = 8 * 1024, */
+	.rx_urb_size = SIERRA_NET_RX_URB_SZ,
 	.whitelist = {
 		.infolen = ARRAY_SIZE(sierra_net_ifnum_list),
 		.ifaceinfo = sierra_net_ifnum_list
 	}
 };
 
-static const struct driver_info sierra_net_info_68A3 = {
+static const struct driver_info sierra_net_info_direct_ip = {
 	.description = "Sierra Wireless USB-to-WWAN Modem",
 	.flags = FLAG_WWAN | FLAG_SEND_ZLP,
 	.bind = sierra_net_bind,
@@ -962,12 +1068,21 @@ static const struct driver_info sierra_net_info_68A3 = {
 	.status = sierra_net_status,
 	.rx_fixup = sierra_net_rx_fixup,
 	.tx_fixup = sierra_net_tx_fixup,
-	.data = (unsigned long)&sierra_net_info_data_68A3,
+	.manage_power = sierra_net_manage_power,
+	.stop = sierra_net_stop,
+	.check_connect = sierra_net_open,
+	.data = (unsigned long)&sierra_net_info_data_direct_ip,
 };
 
 static const struct usb_device_id products[] = {
-	{USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless USB-to-WWAN modem */
-	.driver_info = (unsigned long) &sierra_net_info_68A3},
+	{USB_DEVICE(0x1199, 0x68A3), /* Sierra Wireless Direct IP modem */
+	.driver_info = (unsigned long) &sierra_net_info_direct_ip},
+	{USB_DEVICE(0xF3D, 0x68A3), /* AT&T Direct IP modem */
+	.driver_info = (unsigned long) &sierra_net_info_direct_ip},
+	{USB_DEVICE(0x1199, 0x68AA), /* Sierra Wireless Direct IP LTE modem */
+	.driver_info = (unsigned long) &sierra_net_info_direct_ip},
+	{USB_DEVICE(0xF3D, 0x68AA), /* AT&T Direct IP LTE modem */
+	.driver_info = (unsigned long) &sierra_net_info_direct_ip},
 
 	{}, /* last item */
 };
@@ -981,10 +1096,26 @@ static struct usb_driver sierra_net_driver = {
 	.disconnect = usbnet_disconnect,
 	.suspend = usbnet_suspend,
 	.resume = usbnet_resume,
+	.reset_resume = sierra_net_reset_resume,
 	.no_dynamic_id = 1,
+	.supports_autosuspend = 1,
 };
 
-module_usb_driver(sierra_net_driver);
+static int __init sierra_net_init(void)
+{
+	BUILD_BUG_ON(FIELD_SIZEOF(struct usbnet, data)
+				< sizeof(struct cdc_state));
+
+	return usb_register(&sierra_net_driver);
+}
+
+static void __exit sierra_net_exit(void)
+{
+	usb_deregister(&sierra_net_driver);
+}
+
+module_exit(sierra_net_exit);
+module_init(sierra_net_init);
 
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(DRIVER_DESC);
-- 
1.7.5.4

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


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux