aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/usb/serial/usb_wwan.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/usb/serial/usb_wwan.c')
-rw-r--r--drivers/usb/serial/usb_wwan.c68
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;
}