Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

usb: gadget: u_serial: Implement remote wakeup capability

Implement the remote wakeup capability for u_serial. The newly added
function gserial_wakeup_host() wakes up the host when there is some
data to be sent while the device is suspended. Add gser_get_status()
callbacks to advertise f_serial interface as function wakeup capable.

Signed-off-by: Prashanth K <prashanth.k@oss.qualcomm.com>
Link: https://lore.kernel.org/r/20250424121142.4180241-1-prashanth.k@oss.qualcomm.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Prashanth K and committed by
Greg Kroah-Hartman
3baea29d 11e80d37

+50
+7
drivers/usb/gadget/function/f_serial.c
··· 364 364 gserial_suspend(&gser->port); 365 365 } 366 366 367 + static int gser_get_status(struct usb_function *f) 368 + { 369 + return (f->func_wakeup_armed ? USB_INTRF_STAT_FUNC_RW : 0) | 370 + USB_INTRF_STAT_FUNC_RW_CAP; 371 + } 372 + 367 373 static struct usb_function *gser_alloc(struct usb_function_instance *fi) 368 374 { 369 375 struct f_gser *gser; ··· 393 387 gser->port.func.free_func = gser_free; 394 388 gser->port.func.resume = gser_resume; 395 389 gser->port.func.suspend = gser_suspend; 390 + gser->port.func.get_status = gser_get_status; 396 391 397 392 return &gser->port.func; 398 393 }
+43
drivers/usb/gadget/function/u_serial.c
··· 592 592 return status; 593 593 } 594 594 595 + static int gserial_wakeup_host(struct gserial *gser) 596 + { 597 + struct usb_function *func = &gser->func; 598 + struct usb_gadget *gadget = func->config->cdev->gadget; 599 + 600 + if (func->func_suspended) 601 + return usb_func_wakeup(func); 602 + else 603 + return usb_gadget_wakeup(gadget); 604 + } 605 + 595 606 /*-------------------------------------------------------------------------*/ 596 607 597 608 /* TTY Driver */ ··· 757 746 { 758 747 struct gs_port *port = tty->driver_data; 759 748 unsigned long flags; 749 + int ret = 0; 750 + struct gserial *gser = port->port_usb; 760 751 761 752 pr_vdebug("gs_write: ttyGS%d (%p) writing %zu bytes\n", 762 753 port->port_num, tty, count); ··· 766 753 spin_lock_irqsave(&port->port_lock, flags); 767 754 if (count) 768 755 count = kfifo_in(&port->port_write_buf, buf, count); 756 + 757 + if (port->suspended) { 758 + spin_unlock_irqrestore(&port->port_lock, flags); 759 + ret = gserial_wakeup_host(gser); 760 + if (ret) { 761 + pr_debug("ttyGS%d: Remote wakeup failed:%d\n", port->port_num, ret); 762 + return count; 763 + } 764 + spin_lock_irqsave(&port->port_lock, flags); 765 + } 766 + 769 767 /* treat count == 0 as flush_chars() */ 770 768 if (port->port_usb) 771 769 gs_start_tx(port); ··· 805 781 { 806 782 struct gs_port *port = tty->driver_data; 807 783 unsigned long flags; 784 + int ret = 0; 785 + struct gserial *gser = port->port_usb; 808 786 809 787 pr_vdebug("gs_flush_chars: (%d,%p)\n", port->port_num, tty); 810 788 811 789 spin_lock_irqsave(&port->port_lock, flags); 790 + if (port->suspended) { 791 + spin_unlock_irqrestore(&port->port_lock, flags); 792 + ret = gserial_wakeup_host(gser); 793 + if (ret) { 794 + pr_debug("ttyGS%d: Remote wakeup failed:%d\n", port->port_num, ret); 795 + return; 796 + } 797 + spin_lock_irqsave(&port->port_lock, flags); 798 + } 799 + 812 800 if (port->port_usb) 813 801 gs_start_tx(port); 814 802 spin_unlock_irqrestore(&port->port_lock, flags); ··· 1498 1462 if (!port) { 1499 1463 spin_unlock_irqrestore(&serial_port_lock, flags); 1500 1464 return; 1465 + } 1466 + 1467 + if (port->write_busy || port->write_started) { 1468 + /* Wakeup to host if there are ongoing transfers */ 1469 + spin_unlock_irqrestore(&serial_port_lock, flags); 1470 + if (!gserial_wakeup_host(gser)) 1471 + return; 1501 1472 } 1502 1473 1503 1474 spin_lock(&port->port_lock);