aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/drivers/usb/gadget/function/u_serial.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2020-06-07 09:42:16 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2020-06-07 09:42:16 -0700
commite611c0fe318c6d6827ee2bba660fbc23cf73f7dc (patch)
tree00854551e810b32cceab84157882eab147f2a98c /drivers/usb/gadget/function/u_serial.c
parentMerge tag 'sh-for-5.8' of git://git.libc.org/linux-sh (diff)
parentusb: dwc3: meson-g12a: fix USB2 PHY initialization on G12A and A1 SoCs (diff)
downloadwireguard-linux-e611c0fe318c6d6827ee2bba660fbc23cf73f7dc.tar.xz
wireguard-linux-e611c0fe318c6d6827ee2bba660fbc23cf73f7dc.zip
Merge tag 'usb-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb
Pull USB/PHY driver updates from Greg KH: "Here are the large set of USB and PHY driver updates for 5.8-rc1. Nothing huge, just lots of little things: - USB gadget fixes and additions all over the place - new PHY drivers - PHY driver fixes and updates - XHCI driver updates - musb driver updates - more USB-serial driver ids added - various USB quirks added - thunderbolt minor updates and fixes - typec updates and additions All of these have been in linux-next for a while with no reported issues" * tag 'usb-5.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/usb: (245 commits) usb: dwc3: meson-g12a: fix USB2 PHY initialization on G12A and A1 SoCs usb: dwc3: meson-g12a: fix error path when fetching the reset line fails Revert "dt-bindings: usb: qcom,dwc3: Convert USB DWC3 bindings" Revert "dt-bindings: usb: qcom,dwc3: Add compatible for SC7180" Revert "dt-bindings: usb: qcom,dwc3: Introduce interconnect properties for Qualcomm DWC3 driver" USB: serial: ch341: fix lockup of devices with limited prescaler USB: serial: ch341: add basis for quirk detection CDC-ACM: heed quirk also in error handling USB: serial: option: add Telit LE910C1-EUX compositions usb: musb: Fix runtime PM imbalance on error usb: musb: jz4740: Prevent lockup when CONFIG_SMP is set usb: musb: mediatek: add reset FADDR to zero in reset interrupt handle usb: musb: use true for 'use_dma' usb: musb: start session in resume for host port usb: musb: return -ESHUTDOWN in urb when three-strikes error happened USB: serial: qcserial: add DW5816e QDL support thunderbolt: Add trivial .shutdown usb: dwc3: keystone: Turn on USB3 PHY before controller dt-bindings: usb: ti,keystone-dwc3.yaml: Add USB3.0 PHY property dt-bindings: usb: convert keystone-usb.txt to YAML ...
Diffstat (limited to 'drivers/usb/gadget/function/u_serial.c')
-rw-r--r--drivers/usb/gadget/function/u_serial.c57
1 files changed, 49 insertions, 8 deletions
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index 8167d379e115..3cfc6e2eba71 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -120,6 +120,8 @@ struct gs_port {
wait_queue_head_t drain_wait; /* wait while writes drain */
bool write_busy;
wait_queue_head_t close_wait;
+ bool suspended; /* port suspended */
+ bool start_delayed; /* delay start when suspended */
/* REVISIT this state ... */
struct usb_cdc_line_coding port_line_coding; /* 8-N-1 etc */
@@ -630,13 +632,19 @@ static int gs_open(struct tty_struct *tty, struct file *file)
/* if connected, start the I/O stream */
if (port->port_usb) {
- struct gserial *gser = port->port_usb;
-
- pr_debug("gs_open: start ttyGS%d\n", port->port_num);
- gs_start_io(port);
-
- if (gser->connect)
- gser->connect(gser);
+ /* if port is suspended, wait resume to start I/0 stream */
+ if (!port->suspended) {
+ struct gserial *gser = port->port_usb;
+
+ pr_debug("gs_open: start ttyGS%d\n", port->port_num);
+ gs_start_io(port);
+
+ if (gser->connect)
+ gser->connect(gser);
+ } else {
+ pr_debug("delay start of ttyGS%d\n", port->port_num);
+ port->start_delayed = true;
+ }
}
pr_debug("gs_open: ttyGS%d (%p,%p)\n", port->port_num, tty, file);
@@ -680,7 +688,7 @@ raced_with_open:
pr_debug("gs_close: ttyGS%d (%p,%p) ...\n", port->port_num, tty, file);
gser = port->port_usb;
- if (gser && gser->disconnect)
+ if (gser && !port->suspended && gser->disconnect)
gser->disconnect(gser);
/* wait for circular write buffer to drain, disconnect, or at
@@ -708,6 +716,7 @@ raced_with_open:
else
kfifo_reset(&port->port_write_buf);
+ port->start_delayed = false;
port->port.count = 0;
port->port.tty = NULL;
@@ -1403,6 +1412,38 @@ void gserial_disconnect(struct gserial *gser)
}
EXPORT_SYMBOL_GPL(gserial_disconnect);
+void gserial_suspend(struct gserial *gser)
+{
+ struct gs_port *port = gser->ioport;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->suspended = true;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gserial_suspend);
+
+void gserial_resume(struct gserial *gser)
+{
+ struct gs_port *port = gser->ioport;
+ unsigned long flags;
+
+ spin_lock_irqsave(&port->port_lock, flags);
+ port->suspended = false;
+ if (!port->start_delayed) {
+ spin_unlock_irqrestore(&port->port_lock, flags);
+ return;
+ }
+
+ pr_debug("delayed start ttyGS%d\n", port->port_num);
+ gs_start_io(port);
+ if (gser->connect)
+ gser->connect(gser);
+ port->start_delayed = false;
+ spin_unlock_irqrestore(&port->port_lock, flags);
+}
+EXPORT_SYMBOL_GPL(gserial_resume);
+
static int userial_init(void)
{
unsigned i;