[RFC 2/3] usb/dummy_hcd: introduce per-ep qh data structure

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Signed-off-by: Sebastian Andrzej Siewior <bigeasy@xxxxxxxxxxxxx>
---
 drivers/usb/gadget/dummy_hcd.c |  115 ++++++++++++++++++++++++++++++----------
 1 file changed, 88 insertions(+), 27 deletions(-)

diff --git a/drivers/usb/gadget/dummy_hcd.c b/drivers/usb/gadget/dummy_hcd.c
index ea702c6..2c27566 100644
--- a/drivers/usb/gadget/dummy_hcd.c
+++ b/drivers/usb/gadget/dummy_hcd.c
@@ -167,7 +167,8 @@ struct dummy_hcd {
 	unsigned long			re_timeout;
 
 	struct usb_device		*udev;
-	struct list_head		urbp_list;
+	int				active_urbs;
+	struct list_head		qh_list;
 	u32				stream_en_ep;
 	u8				num_stream[30 / 2];
 
@@ -1160,12 +1161,55 @@ static int dummy_validate_stream(struct dummy_hcd *dum_hcd, struct urb *urb)
 	return 0;
 }
 
+struct dummy_qh {
+	struct list_head urbp_list;
+	struct list_head qh_list;
+};
+
+struct dummy_qh *qh_append_urb(struct dummy_hcd *dum_hcd, struct urb *urb)
+{
+	struct dummy_qh *qh;
+
+	qh = urb->ep->hcpriv;
+	if (qh)
+		return qh;
+
+	qh = kmalloc(sizeof(*qh), GFP_ATOMIC);
+	if (!qh)
+		return qh;
+	list_add_tail(&qh->qh_list, &dum_hcd->qh_list);
+	INIT_LIST_HEAD(&qh->urbp_list);
+	urb->ep->hcpriv = qh;
+	return qh;
+}
+
+static void dummy_disable_ep(struct usb_hcd *hcd, struct usb_host_endpoint *ep)
+{
+	struct dummy_hcd *dum_hcd;
+	struct dummy_qh *qh;
+	unsigned long flags;
+
+	dum_hcd = hcd_to_dummy_hcd(hcd);
+	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
+
+	if (!ep->hcpriv)
+		goto out;
+
+	qh = ep->hcpriv;
+	list_del(&qh->qh_list);
+	kfree(ep->hcpriv);
+	ep->hcpriv = NULL;
+out:
+	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
+}
+
 static int dummy_urb_enqueue(
 	struct usb_hcd			*hcd,
 	struct urb			*urb,
 	gfp_t				mem_flags
 ) {
 	struct dummy_hcd *dum_hcd;
+	struct dummy_qh *qh;
 	struct urbp	*urbp;
 	unsigned long	flags;
 	int		rc;
@@ -1180,16 +1224,16 @@ static int dummy_urb_enqueue(
 	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
 
 	rc = dummy_validate_stream(dum_hcd, urb);
-	if (rc) {
-		kfree(urbp);
-		goto done;
-	}
+	if (rc)
+		goto err;
 
 	rc = usb_hcd_link_urb_to_ep(hcd, urb);
-	if (rc) {
-		kfree(urbp);
-		goto done;
-	}
+	if (rc)
+		goto err;
+
+	qh = qh_append_urb(dum_hcd, urb);
+	if (!qh)
+		goto err_qh;
 
 	if (!dum_hcd->udev) {
 		dum_hcd->udev = urb->dev;
@@ -1197,7 +1241,8 @@ static int dummy_urb_enqueue(
 	} else if (unlikely(dum_hcd->udev != urb->dev))
 		dev_err(dummy_dev(dum_hcd), "usb_device address has changed!\n");
 
-	list_add_tail(&urbp->urbp_list, &dum_hcd->urbp_list);
+	list_add_tail(&urbp->urbp_list, &qh->urbp_list);
+	dum_hcd->active_urbs++;
 	urb->hcpriv = urbp;
 	if (usb_pipetype(urb->pipe) == PIPE_CONTROL)
 		urb->error_count = 1;		/* mark as a new urb */
@@ -1209,6 +1254,11 @@ static int dummy_urb_enqueue(
  done:
 	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 	return rc;
+err_qh:
+	usb_hcd_unlink_urb_from_ep(hcd, urb);
+err:
+	kfree(urbp);
+	goto done;
 }
 
 static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
@@ -1224,7 +1274,7 @@ static int dummy_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 
 	rc = usb_hcd_check_unlink_urb(hcd, urb, status);
 	if (!rc && dum_hcd->rh_state != DUMMY_RH_RUNNING &&
-			!list_empty(&dum_hcd->urbp_list))
+			dum_hcd->active_urbs)
 		mod_timer(&dum_hcd->timer, jiffies);
 
 	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
@@ -1811,6 +1861,7 @@ static int handle_one_urb(struct urbp *urbp, struct dummy_hcd *dum_hcd, int *tot
 		ep->already_seen = ep->setup_stage = 0;
 
 	usb_hcd_unlink_urb_from_ep(dummy_hcd_to_hcd(dum_hcd), urb);
+	dum_hcd->active_urbs--;
 	spin_unlock(&dum->lock);
 	usb_hcd_giveback_urb(dummy_hcd_to_hcd(dum_hcd), urb, status);
 	spin_lock(&dum->lock);
@@ -1824,7 +1875,7 @@ static void dummy_timer(unsigned long _dum_hcd)
 {
 	struct dummy_hcd	*dum_hcd = (struct dummy_hcd *) _dum_hcd;
 	struct dummy		*dum = dum_hcd->dum;
-	struct urbp		*urbp, *tmp;
+	struct dummy_qh		*qh, *qh_tmp;
 	unsigned long		flags;
 	int			total;
 	int			i;
@@ -1868,16 +1919,20 @@ static void dummy_timer(unsigned long _dum_hcd)
 	}
 
 restart:
-	list_for_each_entry_safe(urbp, tmp, &dum_hcd->urbp_list, urbp_list) {
+	list_for_each_entry_safe(qh, qh_tmp, &dum_hcd->qh_list, qh_list) {
 		int ret;
+		struct urbp *urbp, *urbp_tmp;
 
-		ret = handle_one_urb(urbp, dum_hcd, &total);
-		if (!ret)
-			continue;
-		goto restart;
+		list_for_each_entry_safe(urbp, urbp_tmp, &qh->urbp_list, urbp_list) {
+
+			ret = handle_one_urb(urbp, dum_hcd, &total);
+			if (!ret)
+				continue;
+			goto restart;
+		}
 	}
 
-	if (list_empty(&dum_hcd->urbp_list)) {
+	if (!dum_hcd->active_urbs) {
 		usb_put_dev(dum_hcd->udev);
 		dum_hcd->udev = NULL;
 	} else if (dum_hcd->rh_state == DUMMY_RH_RUNNING) {
@@ -2260,7 +2315,7 @@ static int dummy_bus_resume(struct usb_hcd *hcd)
 	} else {
 		dum_hcd->rh_state = DUMMY_RH_RUNNING;
 		set_link_state(dum_hcd);
-		if (!list_empty(&dum_hcd->urbp_list))
+		if (dum_hcd->active_urbs)
 			mod_timer(&dum_hcd->timer, jiffies);
 		hcd->state = HC_STATE_RUNNING;
 	}
@@ -2319,17 +2374,22 @@ static ssize_t show_urbs(struct device *dev, struct device_attribute *attr,
 {
 	struct usb_hcd		*hcd = dev_get_drvdata(dev);
 	struct dummy_hcd	*dum_hcd = hcd_to_dummy_hcd(hcd);
-	struct urbp		*urbp;
+	struct dummy_qh		*qh;
 	size_t			size = 0;
 	unsigned long		flags;
 
 	spin_lock_irqsave(&dum_hcd->dum->lock, flags);
-	list_for_each_entry(urbp, &dum_hcd->urbp_list, urbp_list) {
-		size_t		temp;
 
-		temp = show_urb(buf, PAGE_SIZE - size, urbp->urb);
-		buf += temp;
-		size += temp;
+	list_for_each_entry(qh, &dum_hcd->qh_list, qh_list) {
+		struct urbp *urbp;
+
+		list_for_each_entry(urbp, &qh->urbp_list, urbp_list) {
+			size_t		temp;
+
+			temp = show_urb(buf, PAGE_SIZE - size, urbp->urb);
+			buf += temp;
+			size += temp;
+		}
 	}
 	spin_unlock_irqrestore(&dum_hcd->dum->lock, flags);
 
@@ -2344,7 +2404,7 @@ static int dummy_start_ss(struct dummy_hcd *dum_hcd)
 	dum_hcd->timer.data = (unsigned long)dum_hcd;
 	dum_hcd->rh_state = DUMMY_RH_RUNNING;
 	dum_hcd->stream_en_ep = 0;
-	INIT_LIST_HEAD(&dum_hcd->urbp_list);
+	INIT_LIST_HEAD(&dum_hcd->qh_list);
 	dummy_hcd_to_hcd(dum_hcd)->power_budget = POWER_BUDGET;
 	dummy_hcd_to_hcd(dum_hcd)->state = HC_STATE_RUNNING;
 	dummy_hcd_to_hcd(dum_hcd)->uses_new_polling = 1;
@@ -2375,7 +2435,7 @@ static int dummy_start(struct usb_hcd *hcd)
 	dum_hcd->timer.data = (unsigned long)dum_hcd;
 	dum_hcd->rh_state = DUMMY_RH_RUNNING;
 
-	INIT_LIST_HEAD(&dum_hcd->urbp_list);
+	INIT_LIST_HEAD(&dum_hcd->qh_list);
 
 	hcd->power_budget = POWER_BUDGET;
 	hcd->state = HC_STATE_RUNNING;
@@ -2520,6 +2580,7 @@ static struct hc_driver dummy_hcd = {
 
 	.urb_enqueue =		dummy_urb_enqueue,
 	.urb_dequeue =		dummy_urb_dequeue,
+	.endpoint_disable =	dummy_disable_ep,
 
 	.get_frame_number =	dummy_h_get_frame,
 
-- 
1.7.10.4

--
To unsubscribe from this list: send the line "unsubscribe linux-usb" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Linux Media]     [Linux Input]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]     [Old Linux USB Devel Archive]

  Powered by Linux