diff options
Diffstat (limited to 'drivers/usb/serial/usb_wwan.c')
-rw-r--r-- | drivers/usb/serial/usb_wwan.c | 68 |
1 files changed, 56 insertions, 12 deletions
diff --git a/drivers/usb/serial/usb_wwan.c b/drivers/usb/serial/usb_wwan.c index 2a9d21d..2e2a60d 100644 --- a/drivers/usb/serial/usb_wwan.c +++ b/drivers/usb/serial/usb_wwan.c @@ -219,6 +219,11 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, dbg("%s: write (%d chars)", __func__, count); +#ifdef CONFIG_MDM_HSIC_PM + if (port->serial->dev->actconfig->desc.bNumInterfaces == 9) + pr_info("%s: write (%d chars)", __func__, count); +#endif + i = 0; left = count; for (i = 0; left > 0 && i < N_OUT_URB; i++) { @@ -237,6 +242,8 @@ int usb_wwan_write(struct tty_struct *tty, struct usb_serial_port *port, dbg("%s: endpoint %d buf %d", __func__, usb_pipeendpoint(this_urb->pipe), i); + usb_mark_last_busy( + interface_to_usbdev(port->serial->interface)); err = usb_autopm_get_interface_async(port->serial->interface); if (err < 0) break; @@ -285,29 +292,61 @@ static void usb_wwan_indat_callback(struct urb *urb) struct tty_struct *tty; unsigned char *data = urb->transfer_buffer; int status = urb->status; + int rx_len = urb->actual_length; + struct usb_wwan_intf_private *intfdata; dbg("%s: %p", __func__, urb); endpoint = usb_pipeendpoint(urb->pipe); port = urb->context; + intfdata = port->serial->private; + usb_mark_last_busy(interface_to_usbdev(port->serial->interface)); if (status) { dbg("%s: nonzero status: %d on endpoint %02x.", __func__, status, endpoint); +#ifdef CONFIG_MDM_HSIC_PM + if (status == -ENOENT && (urb->actual_length > 0)) { + pr_info("%s: handle dropped packet\n", __func__); + goto handle_rx; + } +#endif } else { +#ifdef CONFIG_MDM_HSIC_PM +handle_rx: +#endif tty = tty_port_tty_get(&port->port); if (tty) { - if (urb->actual_length) { - tty_insert_flip_string(tty, data, - urb->actual_length); + if (urb->actual_length > 0) { +#ifdef CONFIG_MDM_HSIC_PM + struct usb_device *udev = port->serial->dev; + /* corner case : efs packet rx at rpm suspend + * it can control twice in racing condition + * rx call back and suspend, both of then ca + * call this function , so clear the packet + * length once it handled + */ + urb->status = -EINPROGRESS; + urb->actual_length = 0; + if (udev->actconfig->desc.bNumInterfaces == 9) + pr_info("%s: read urb received : %d\n", + __func__, rx_len); +#endif + tty_insert_flip_string(tty, data, rx_len); tty_flip_buffer_push(tty); } else dbg("%s: empty read urb received", __func__); tty_kref_put(tty); - } + } else + return; +#ifdef CONFIG_MDM_HSIC_PM + /* do not re-submit urb for no entry status */ + if (status == -ENOENT) + return; +#endif /* Resubmit urb so we continue receiving */ - if (status != -ESHUTDOWN) { + if (status != -ESHUTDOWN || !intfdata->suspended) { err = usb_submit_urb(urb, GFP_ATOMIC); if (err) { if (err != -EPERM) { @@ -319,6 +358,8 @@ static void usb_wwan_indat_callback(struct urb *urb) } else { usb_mark_last_busy(port->serial->dev); } + usb_mark_last_busy( + interface_to_usbdev(port->serial->interface)); } } @@ -338,6 +379,7 @@ static void usb_wwan_outdat_callback(struct urb *urb) usb_serial_port_softint(port); usb_autopm_put_interface_async(port->serial->interface); + usb_mark_last_busy(interface_to_usbdev(port->serial->interface)); portdata = usb_get_serial_port_data(port); spin_lock(&intfdata->susp_lock); intfdata->in_flight--; @@ -405,6 +447,7 @@ int usb_wwan_open(struct tty_struct *tty, struct usb_serial_port *port) portdata = usb_get_serial_port_data(port); intfdata = serial->private; + intfdata->suspended = 0; /* explicitly set the driver mode to raw */ tty->raw = 1; @@ -582,8 +625,7 @@ bail_out_error2: kfree(portdata->out_buffer[j]); bail_out_error: for (j = 0; j < N_IN_URB; j++) - if (portdata->in_buffer[j]) - free_page((unsigned long)portdata->in_buffer[j]); + kfree(portdata->in_buffer[j]); kfree(portdata); return 1; } @@ -608,8 +650,10 @@ static void stop_read_write_urbs(struct usb_serial *serial) void usb_wwan_disconnect(struct usb_serial *serial) { + struct usb_wwan_intf_private *intfdata = serial->private; dbg("%s", __func__); + intfdata->suspended = 1; stop_read_write_urbs(serial); } EXPORT_SYMBOL(usb_wwan_disconnect); @@ -629,8 +673,7 @@ void usb_wwan_release(struct usb_serial *serial) for (j = 0; j < N_IN_URB; j++) { usb_free_urb(portdata->in_urbs[j]); - free_page((unsigned long) - portdata->in_buffer[j]); + kfree(portdata->in_buffer[j]); portdata->in_urbs[j] = NULL; } for (j = 0; j < N_OUT_URB; j++) { @@ -736,6 +779,10 @@ int usb_wwan_resume(struct usb_serial *serial) } } + spin_lock_irq(&intfdata->susp_lock); + intfdata->suspended = 0; + spin_unlock_irq(&intfdata->susp_lock); + for (i = 0; i < serial->num_ports; i++) { /* walk all ports */ port = serial->port[i]; @@ -761,9 +808,6 @@ int usb_wwan_resume(struct usb_serial *serial) play_delayed(port); spin_unlock_irq(&intfdata->susp_lock); } - spin_lock_irq(&intfdata->susp_lock); - intfdata->suspended = 0; - spin_unlock_irq(&intfdata->susp_lock); err_out: return err; } |