lkml.org 
[lkml]   [2009]   [Dec]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[17/20] USB: suspend/resume support for option driver
    2.6.27-stable review patch.  If anyone has any objections, please let us know.

    ------------------
    From: Oliver Neukum <oliver@neukum.org>
    commit 4901b2c34ecb6fc45909228ad269c8126efe4401 upstream.

    This patch implements suspend and resume methods for the
    option driver. With my hardware I can even suspend the system
    and keep up a connection for a short time.

    Signed-off-by: Oliver Neukum <oneukum@suse.de>
    Signed-Off-By: Matthias Urlichs <smurf@smurf.noris.de>
    Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>

    ---
    drivers/usb/serial/option.c | 86 ++++++++++++++++++++++++++++++++++++++++----
    1 file changed, 80 insertions(+), 6 deletions(-)
    --- a/drivers/usb/serial/option.c
    +++ b/drivers/usb/serial/option.c
    @@ -62,6 +62,8 @@ static int option_tiocmget(struct tty_s
    static int option_tiocmset(struct tty_struct *tty, struct file *file,
    unsigned int set, unsigned int clear);
    static int option_send_setup(struct tty_struct *tty, struct usb_serial_port *port);
    +static int option_suspend(struct usb_serial *serial, pm_message_t message);
    +static int option_resume(struct usb_serial *serial);

    /* Vendor and product IDs */
    #define OPTION_VENDOR_ID 0x0AF0
    @@ -511,6 +513,8 @@ static struct usb_driver option_driver =
    .name = "option",
    .probe = usb_serial_probe,
    .disconnect = usb_serial_disconnect,
    + .suspend = usb_serial_suspend,
    + .resume = usb_serial_resume,
    .id_table = option_ids,
    .no_dynamic_id = 1,
    };
    @@ -539,6 +543,8 @@ static struct usb_serial_driver option_1
    .attach = option_startup,
    .shutdown = option_shutdown,
    .read_int_callback = option_instat_callback,
    + .suspend = option_suspend,
    + .resume = option_resume,
    };

    static int debug;
    @@ -809,10 +815,10 @@ static void option_instat_callback(struc
    req_pkt->bRequestType, req_pkt->bRequest);
    }
    } else
    - dbg("%s: error %d", __func__, status);
    + err("%s: error %d", __func__, status);

    /* Resubmit urb so we continue receiving IRQ data */
    - if (status != -ESHUTDOWN) {
    + if (status != -ESHUTDOWN && status != -ENOENT) {
    urb->dev = serial->dev;
    err = usb_submit_urb(urb, GFP_ATOMIC);
    if (err)
    @@ -831,7 +837,6 @@ static int option_write_room(struct tty_

    portdata = usb_get_serial_port_data(port);

    -
    for (i = 0; i < N_OUT_URB; i++) {
    this_urb = portdata->out_urbs[i];
    if (this_urb && !test_bit(i, &portdata->out_busy))
    @@ -1090,14 +1095,12 @@ bail_out_error:
    return 1;
    }

    -static void option_shutdown(struct usb_serial *serial)
    +static void stop_read_write_urbs(struct usb_serial *serial)
    {
    int i, j;
    struct usb_serial_port *port;
    struct option_port_private *portdata;

    - dbg("%s", __func__);
    -
    /* Stop reading/writing urbs */
    for (i = 0; i < serial->num_ports; ++i) {
    port = serial->port[i];
    @@ -1107,6 +1110,17 @@ static void option_shutdown(struct usb_s
    for (j = 0; j < N_OUT_URB; j++)
    usb_kill_urb(portdata->out_urbs[j]);
    }
    +}
    +
    +static void option_shutdown(struct usb_serial *serial)
    +{
    + int i, j;
    + struct usb_serial_port *port;
    + struct option_port_private *portdata;
    +
    + dbg("%s", __func__);
    +
    + stop_read_write_urbs(serial);

    /* Now free them */
    for (i = 0; i < serial->num_ports; ++i) {
    @@ -1137,6 +1151,66 @@ static void option_shutdown(struct usb_s
    }
    }

    +static int option_suspend(struct usb_serial *serial, pm_message_t message)
    +{
    + dbg("%s entered", __func__);
    + stop_read_write_urbs(serial);
    +
    + return 0;
    +}
    +
    +static int option_resume(struct usb_serial *serial)
    +{
    + int err, i, j;
    + struct usb_serial_port *port;
    + struct urb *urb;
    + struct option_port_private *portdata;
    +
    + dbg("%s entered", __func__);
    + /* get the interrupt URBs resubmitted unconditionally */
    + for (i = 0; i < serial->num_ports; i++) {
    + port = serial->port[i];
    + if (!port->interrupt_in_urb) {
    + dbg("%s: No interrupt URB for port %d\n", __func__, i);
    + continue;
    + }
    + port->interrupt_in_urb->dev = serial->dev;
    + err = usb_submit_urb(port->interrupt_in_urb, GFP_NOIO);
    + dbg("Submitted interrupt URB for port %d (result %d)", i, err);
    + if (err < 0) {
    + err("%s: Error %d for interrupt URB of port%d",
    + __func__, err, i);
    + return err;
    + }
    + }
    +
    + for (i = 0; i < serial->num_ports; i++) {
    + /* walk all ports */
    + port = serial->port[i];
    + portdata = usb_get_serial_port_data(port);
    + mutex_lock(&port->mutex);
    +
    + /* skip closed ports */
    + if (!port->port.count) {
    + mutex_unlock(&port->mutex);
    + continue;
    + }
    +
    + for (j = 0; j < N_IN_URB; j++) {
    + urb = portdata->in_urbs[j];
    + err = usb_submit_urb(urb, GFP_NOIO);
    + if (err < 0) {
    + mutex_unlock(&port->mutex);
    + err("%s: Error %d for bulk URB %d",
    + __func__, err, i);
    + return err;
    + }
    + }
    + mutex_unlock(&port->mutex);
    + }
    + return 0;
    +}
    +
    MODULE_AUTHOR(DRIVER_AUTHOR);
    MODULE_DESCRIPTION(DRIVER_DESC);
    MODULE_VERSION(DRIVER_VERSION);



    \
     
     \ /
      Last update: 2009-12-07 00:43    [from the cache]
    ©2003-2011 Jasper Spaans