Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 404e2e98 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "usb: gadget: Do not drop the request upon suspend"

parents 6531b522 2941284e
Loading
Loading
Loading
Loading
+44 −0
Original line number Diff line number Diff line
@@ -619,6 +619,48 @@ static void gser_disable(struct usb_function *f)
	gser->online = 0;
}

static void gser_suspend(struct usb_function *f)
{
	struct f_gser	*gser = func_to_gser(f);
	unsigned port_num;

	port_num = gserial_ports[gser->port_num].client_port_num;

	pr_debug("%s: transport: %s f_gser: %p gserial: %p port_num: %d\n",
			__func__, xport_to_str(gser->transport),
			gser, &gser->port, gser->port_num);

	switch (gser->transport) {
	case USB_GADGET_XPORT_SMD:
		gsmd_suspend(&gser->port, port_num);
		break;
	default:
		pr_err("%s: Un-supported transport: %s\n", __func__,
			xport_to_str(gser->transport));
	}
}

static void gser_resume(struct usb_function *f)
{
	struct f_gser	*gser = func_to_gser(f);
	unsigned port_num;

	port_num = gserial_ports[gser->port_num].client_port_num;

	pr_debug("%s: transport: %s f_gser: %p gserial: %p port_num: %d\n",
			__func__, xport_to_str(gser->transport),
			gser, &gser->port, gser->port_num);

	switch (gser->transport) {
	case USB_GADGET_XPORT_SMD:
		gsmd_resume(&gser->port, port_num);
		break;
	default:
		pr_err("%s: Un-supported transport: %s\n", __func__,
			xport_to_str(gser->transport));
	}
}

static int gser_notify(struct f_gser *gser, u8 type, u16 value,
		void *data, unsigned length)
{
@@ -1056,6 +1098,8 @@ static struct usb_function *gser_alloc(struct usb_function_instance *fi)
	else
		gser->port.func.name = "modem2";
	gser->port.func.setup = gser_setup;
	gser->port.func.suspend = gser_suspend;
	gser->port.func.resume = gser_resume;
	gser->port.connect = gser_connect;
	gser->port.get_dtr = gser_get_dtr;
	gser->port.get_rts = gser_get_rts;
+2 −0
Original line number Diff line number Diff line
@@ -81,6 +81,8 @@ void gserial_disconnect(struct gserial *);
int gsmd_setup(struct usb_gadget *g, unsigned n_ports);
int gsmd_connect(struct gserial *, u8 port_num);
void gsmd_disconnect(struct gserial *, u8 portno);
void gsmd_suspend(struct gserial *, u8 port_num);
void gsmd_resume(struct gserial *, u8 port_num);
int gsmd_write(u8 portno, char *buf, unsigned int size);

/* functions are bound to configurations by a config or gadget driver */
+50 −0
Original line number Diff line number Diff line
@@ -92,6 +92,7 @@ struct gsmd_port {
	/* pkt counters */
	unsigned long		nbytes_tomodem;
	unsigned long		nbytes_tolaptop;
	bool			is_suspended;
};

static struct smd_portmaster {
@@ -299,7 +300,10 @@ static void gsmd_tx_pull(struct work_struct *w)
	struct gsmd_port *port = container_of(w, struct gsmd_port, pull);
	struct list_head *pool = &port->write_pool;
	struct smd_port_info *pi = port->pi;
	struct usb_function *func;
	struct usb_gadget	*gadget;
	struct usb_ep *in;
	int ret;

	pr_debug("%s: port:%p port#%d pool:%p\n", __func__,
			port, port->port_num, pool);
@@ -314,6 +318,27 @@ static void gsmd_tx_pull(struct work_struct *w)
	}

	in = port->port_usb->in;
	func = &port->port_usb->func;
	gadget = func->config->cdev->gadget;
	if (port->is_suspended) {
		spin_unlock_irq(&port->port_lock);
		ret = usb_gadget_wakeup(gadget);
		spin_lock_irq(&port->port_lock);

		if (ret)
			pr_err("Failed to wake up the USB core. ret=%d.\n",
				ret);

		if (!port->port_usb) {
			pr_debug("%s: USB disconnected\n", __func__);
			spin_unlock_irq(&port->port_lock);
			gsmd_read_pending(port);
			return;
		}
		spin_unlock_irq(&port->port_lock);
		return;
	}

	while (pi->ch && !list_empty(pool)) {
		struct usb_request *req;
		int avail;
@@ -1003,6 +1028,31 @@ free_smd_ports:
	return ret;
}

void gsmd_suspend(struct gserial *gser, u8 portno)
{
	struct gsmd_port *port;

	pr_debug("%s: gserial:%p portno:%u\n", __func__, gser, portno);

	port = smd_ports[portno].port;
	spin_lock(&port->port_lock);
	port->is_suspended = true;
	spin_unlock(&port->port_lock);
}

void gsmd_resume(struct gserial *gser, u8 portno)
{
	struct gsmd_port *port;

	pr_debug("%s: gserial:%p portno:%u\n", __func__, gser, portno);

	port = smd_ports[portno].port;
	spin_lock(&port->port_lock);
	port->is_suspended = false;
	spin_unlock(&port->port_lock);
	queue_work(gsmd_wq, &port->pull);
}

void gsmd_cleanup(struct usb_gadget *g, unsigned count)
{
	/* TBD */