Re: IPWireless serial modem has bandwidth limited to 56 kB/s

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

 



Am Mittwoch, 13. Juli 2011, 11:11:44 schrieb Michal Hybner:
> Hi Oliver,
> on Win I reached about the same speed. I tested both patches only
> briefly on small 5 MB test file and it fluctuated between roughly
> 100~150 kB/s, mostly around 120 kB/s. And because I have 1 MB/s
> service from operator, I am satisfied with these numbers. I can do
> some more tests with larger files later, if it helps you. But due to
> my 1 MB service limit I doubt that I can give you some better results.

Hi,

would you like to do even more testing?
This patch is supposed to reduce the power consumption
of your device. However, it is quite experimental.

	Regards
		Oliver

>From ff4562066a1353a2fe1b3329c6f8ff747f08ab80 Mon Sep 17 00:00:00 2001
From: Oliver Neukum <oliver@xxxxxxxxxx>
Date: Wed, 13 Jul 2011 14:47:17 +0200
Subject: [PATCH] USB: ipw: Implement suspend/resume

This implements basic suspend/resume and runtime power
management using the functionality provided by the usb-wwan
framework.

Signed-off-by: Oliver Neukum <oneukum@xxxxxxx>
---
 drivers/usb/serial/ipw.c |  154 +++++++++++++++++++++++++++++++++-------------
 1 files changed, 110 insertions(+), 44 deletions(-)

diff --git a/drivers/usb/serial/ipw.c b/drivers/usb/serial/ipw.c
index 5170799..d6c2d8b 100644
--- a/drivers/usb/serial/ipw.c
+++ b/drivers/usb/serial/ipw.c
@@ -143,50 +143,31 @@ static struct usb_driver usb_ipw_driver = {
 	.name =		"ipwtty",
 	.probe =	usb_serial_probe,
 	.disconnect =	usb_serial_disconnect,
+#ifdef CONFIG_PM
+	.suspend =	usb_serial_suspend,
+	.resume =	usb_serial_resume,
+#endif
 	.id_table =	usb_ipw_ids,
 	.no_dynamic_id = 	1,
+	.supports_autosuspend =	1,
+};
+
+struct usb_wwan_ipw_private{
+	struct usb_wwan_intf_private priv;
+	unsigned int stopped:1;
 };
 
 static int debug;
 
-static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
+static void ipw_start_transmissions(struct usb_device *dev)
 {
-	struct usb_device *dev = port->serial->dev;
 	u8 buf_flow_static[16] = IPW_BYTES_FLOWINIT;
 	u8 *buf_flow_init;
 	int result;
 
-	dbg("%s", __func__);
-
 	buf_flow_init = kmemdup(buf_flow_static, 16, GFP_KERNEL);
 	if (!buf_flow_init)
-		return -ENOMEM;
-
-	/* --1: Tell the modem to initialize (we think) From sniffs this is
-	 *	always the first thing that gets sent to the modem during
-	 *	opening of the device */
-	dbg("%s: Sending SIO_INIT (we guess)", __func__);
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
-			 IPW_SIO_INIT,
-			 USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
-			 0,
-			 0, /* index */
-			 NULL,
-			 0,
-			 100000);
-	if (result < 0)
-		dev_err(&port->dev,
-			"Init of modem failed (error = %d)\n", result);
-
-	/* reset the bulk pipes */
-	usb_clear_halt(dev,
-			usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress));
-	usb_clear_halt(dev,
-			usb_sndbulkpipe(dev, port->bulk_out_endpointAddress));
-
-	/*--2: Start reading from the device */
-	dbg("%s: setting up bulk read callback", __func__);
-	usb_wwan_open(tty, port);
+		return;
 
 	/*--3: Tell the modem to open the floodgates on the rx bulk channel */
 	dbg("%s:asking modem for RxRead (RXBULK_ON)", __func__);
@@ -199,7 +180,7 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
 			 0,
 			 100000);
 	if (result < 0)
-		dev_err(&port->dev,
+		dev_err(&dev->dev,
 			"Enabling bulk RxRead failed (error = %d)\n", result);
 
 	/*--4: setup the initial flowcontrol */
@@ -213,10 +194,46 @@ static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
 			 0x10,
 			 200000);
 	if (result < 0)
-		dev_err(&port->dev,
+		dev_err(&dev->dev,
 			"initial flowcontrol failed (error = %d)\n", result);
 
 	kfree(buf_flow_init);
+}
+
+static int ipw_open(struct tty_struct *tty, struct usb_serial_port *port)
+{
+	struct usb_device *dev = port->serial->dev;
+	int result;
+
+	dbg("%s", __func__);
+
+	/* --1: Tell the modem to initialize (we think) From sniffs this is
+	 *	always the first thing that gets sent to the modem during
+	 *	opening of the device */
+	dbg("%s: Sending SIO_INIT (we guess)", __func__);
+	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+			 IPW_SIO_INIT,
+			 USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
+			 0,
+			 0, /* index */
+			 NULL,
+			 0,
+			 100000);
+	if (result < 0)
+		dev_err(&port->dev,
+			"Init of modem failed (error = %d)\n", result);
+
+	/* reset the bulk pipes */
+	usb_clear_halt(dev,
+			usb_rcvbulkpipe(dev, port->bulk_in_endpointAddress));
+	usb_clear_halt(dev,
+			usb_sndbulkpipe(dev, port->bulk_out_endpointAddress));
+
+	/*--2: Start reading from the device */
+	dbg("%s: setting up bulk read callback", __func__);
+	usb_wwan_open(tty, port);
+
+	ipw_start_transmissions(dev);
 	return 0;
 }
 
@@ -225,22 +242,24 @@ static int ipw_probe(struct usb_serial *serial, const struct usb_device_id *id)
 {
 	struct usb_wwan_intf_private *data;
 
-	data = kzalloc(sizeof(struct usb_wwan_intf_private), GFP_KERNEL);
+	data = kzalloc(sizeof(struct usb_wwan_ipw_private), GFP_KERNEL);
 	if (!data)
 		return -ENOMEM;
 
 	spin_lock_init(&data->susp_lock);
 	usb_set_serial_data(serial, data);
+	usb_enable_autosuspend(serial->dev);
 	return 0;
 }
 
 static void ipw_release(struct usb_serial *serial)
 {
-	struct usb_wwan_intf_private *data = usb_get_serial_data(serial);
+	struct usb_wwan_intf_private *priv = usb_get_serial_data(serial);
 
+	
 	usb_wwan_release(serial);
 	usb_set_serial_data(serial, NULL);
-	kfree(data);
+	kfree(priv);
 }
 
 static void ipw_dtr_rts(struct usb_serial_port *port, int on)
@@ -275,10 +294,9 @@ static void ipw_dtr_rts(struct usb_serial_port *port, int on)
 								result);
 }
 
-static void ipw_close(struct usb_serial_port *port)
+static int ipw_stop_transmissions(struct usb_device *dev)
 {
-	struct usb_device *dev = port->serial->dev;
-	int result;
+	int result, result2;
 
 	/*--3: purge */
 	dbg("%s:sending purge", __func__);
@@ -291,12 +309,12 @@ static void ipw_close(struct usb_serial_port *port)
 			 0,
 			 200000);
 	if (result < 0)
-		dev_err(&port->dev, "purge failed (error = %d)\n", result);
+		dev_err(&dev->dev, "purge failed (error = %d)\n", result);
 
 
 	/* send RXBULK_off (tell modem to stop transmitting bulk data on
 	   rx chan) */
-	result = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+	result2 = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
 			 IPW_SIO_RXCTL,
 			 USB_TYPE_VENDOR | USB_RECIP_INTERFACE | USB_DIR_OUT,
 			 IPW_RXBULK_OFF,
@@ -305,13 +323,57 @@ static void ipw_close(struct usb_serial_port *port)
 			 0,
 			 100000);
 
-	if (result < 0)
-		dev_err(&port->dev,
-			"Disabling bulk RxRead failed (error = %d)\n", result);
+	if (result2 < 0)
+		dev_err(&dev->dev,
+			"Disabling bulk RxRead failed (error = %d)\n", result2);
+
+	return result < 0 ? result : result2;
+}
 
+static void ipw_close(struct usb_serial_port *port)
+{
+	struct usb_device *dev = port->serial->dev;
+
+	ipw_stop_transmissions(dev);
 	usb_wwan_close(port);
 }
 
+#ifdef CONFIG_PM
+static int ipw_suspend(struct usb_serial *serial, pm_message_t message)
+{
+	struct usb_wwan_ipw_private *priv = usb_get_serial_data(serial);
+	int result;
+
+	result = usb_wwan_suspend(serial, message);
+	if (result < 0)
+		return result;
+
+	if (!(message.event & PM_EVENT_AUTO)) {
+		result = ipw_stop_transmissions(serial->dev);
+		if (result < 0) {
+			ipw_start_transmissions(serial->dev);
+			usb_wwan_resume(serial);
+			return result;
+		}
+		priv->stopped = true;
+	}
+	return 0;
+}
+
+static int ipw_resume(struct usb_serial *serial)
+{
+	struct usb_wwan_ipw_private *priv = usb_get_serial_data(serial);
+	int result;
+
+	if (priv->stopped) {
+		priv->stopped = false;
+		ipw_start_transmissions(serial->dev);
+	}
+	result = usb_wwan_resume(serial);
+	return result;
+}
+#endif
+
 static struct usb_serial_driver ipw_device = {
 	.driver = {
 		.owner =	THIS_MODULE,
@@ -322,6 +384,10 @@ static struct usb_serial_driver ipw_device = {
 	.id_table =		usb_ipw_ids,
 	.num_ports =		1,
 	.disconnect =		usb_wwan_disconnect,
+#ifdef CONFIG_PM
+	.suspend =		ipw_suspend,
+	.resume =		ipw_resume,
+#endif
 	.open =			ipw_open,
 	.close =		ipw_close,
 	.probe =		ipw_probe,
-- 
1.7.1

--
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