USB: ipw: Implement suspend/resume

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

 



Hi Oliver,
yes, I will have time to test at Saturday. But I have a few questions
- how can I measure, that it has reduced power consumption? Or should
I only test if connection works properly with this patch? And it is
really possible that it can consume less power even if it's not USB
dogle (like most 3G modems), but powered-on with separate AC adapter?

Best regards
Michal

PS: I think it's better to split this to another thread. Hope I did it right.

2011/7/13 Oliver Neukum <oneukum@xxxxxxx>:
> 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
>
>
��.n��������+%������w��{.n�����{���)��jg��������ݢj����G�������j:+v���w�m������w�������h�����٥



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

  Powered by Linux