[coreboot-gerrit] New patch to review for coreboot: 2cbc13c libpayload: Add zero length packet support to UDC framework

Patrick Georgi (pgeorgi@google.com) gerrit at coreboot.org
Fri Apr 17 13:16:09 CEST 2015


Patrick Georgi (pgeorgi at google.com) just uploaded a new patch set to gerrit, which you can find at http://review.coreboot.org/9784

-gerrit

commit 2cbc13c4cd31b1ff8c77b6f19402c46da91760cf
Author: Patrick Georgi <pgeorgi at google.com>
Date:   Mon Feb 16 17:00:59 2015 +0100

    libpayload: Add zero length packet support to UDC framework
    
    Some IN transfers must be terminated by an empty packet
    because otherwise the host wouldn't know.
    
    The zlp() function determines this requirement in
    accordance to USB rules: If the transfer's size is aligned
    to the maximum packet size, and the host expects a larger
    transfer, add the empty packet as a hint.
    
    BRANCH=none
    BUG=none
    TEST=USB device mode still works
    
    Change-Id: Ia69f3d017f72a3a0e0b21bac72fe97be184c7daa
    Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Commit-Id: fd0e946e4948a74a9ed15a5eed6ce827b7672a56
    Original-Change-Id: I8153cc5bd2ff1c88e383c1dbcddaf1bf72f9194c
    Original-Signed-off-by: Patrick Georgi <pgeorgi at chromium.org>
    Original-Reviewed-on: https://chromium-review.googlesource.com/250790
    Original-Reviewed-by: Furquan Shaikh <furquan at chromium.org>
---
 payloads/libpayload/drivers/udc/chipidea.c |  9 +++++++++
 payloads/libpayload/drivers/udc/udc.c      | 28 ++++++++++++++++++++++++----
 payloads/libpayload/include/udc/udc.h      |  2 ++
 3 files changed, 35 insertions(+), 4 deletions(-)

diff --git a/payloads/libpayload/drivers/udc/chipidea.c b/payloads/libpayload/drivers/udc/chipidea.c
index e06f0d2..58bea06 100644
--- a/payloads/libpayload/drivers/udc/chipidea.c
+++ b/payloads/libpayload/drivers/udc/chipidea.c
@@ -153,6 +153,7 @@ static void chipidea_start_ep(struct usbdev_ctrl *this,
 	setbits_le32(&p->opreg->epctrl[ep],
 		((1 << 7) | (1 << 6) | (ep_type << 2)) << (in_dir*16));
 	p->ep_busy[ep][in_dir] = 0;
+	this->ep_mps[ep][in_dir] = mps;
 }
 
 static void advance_endpoint(struct chipidea_pdata *p, int endpoint, int in_dir)
@@ -463,6 +464,14 @@ struct usbdev_ctrl *chipidea_init(device_descriptor_t *dd)
 	ctrl->free_data = chipidea_free;
 	ctrl->initialized = 0;
 
+	int i;
+	ctrl->ep_mps[0][0] = 64;
+	ctrl->ep_mps[0][1] = 64;
+	for (i = 1; i < 16; i++) {
+		ctrl->ep_mps[i][0] = 512;
+		ctrl->ep_mps[i][1] = 512;
+	}
+
 	if (!chipidea_hw_init(ctrl, (void *)0x7d000000, dd)) {
 		free(ctrl->pdata);
 		free(ctrl);
diff --git a/payloads/libpayload/drivers/udc/udc.c b/payloads/libpayload/drivers/udc/udc.c
index cdc2b29..89a7d1d 100644
--- a/payloads/libpayload/drivers/udc/udc.c
+++ b/payloads/libpayload/drivers/udc/udc.c
@@ -47,8 +47,26 @@
 
 #define min(a, b) (((a) < (b)) ? (a) : (b))
 
-// TODO: make this right
-#define ZLP(len, explen) 0
+/* determine if an additional zero length packet is necessary for
+ * a transfer */
+static unsigned int zlp(struct usbdev_ctrl *this, const int epnum,
+	const int len, const int explen)
+{
+	const unsigned int mps = this->ep_mps[epnum][1];
+
+	/* zero length transfers are handled explicitly */
+	if (len == 0)
+		return 0;
+	/* host expects exactly the right amount, so no zlp necessary */
+	if (len == explen)
+		return 0;
+	/* last packet will be short -> host knows that transfer is over */
+	if ((len % mps) != 0)
+		return 0;
+
+	/* otherwise we need an extra zero length packet */
+	return 1;
+}
 
 static struct usbdev_configuration *fetch_config(struct usbdev_ctrl *this,
 	int id)
@@ -90,6 +108,8 @@ static void enable_interface(struct usbdev_ctrl *this, int iface_num)
 		this->start_ep(this, ep, in_dir, ep_type, mps);
 	}
 
+	this->current_iface = iface;
+
 	// gadget specific configuration
 	if (iface->init)
 		iface->init(this);
@@ -268,7 +288,7 @@ static int setup_ep0(struct usbdev_ctrl *this, dev_req_t *dr)
 		/* data phase IN */
 		this->enqueue_packet(this, 0, 1, data,
 			min(size, dr->wLength),
-			ZLP(size, dr->wLength), 1);
+			zlp(this, 0, size, dr->wLength), 1);
 
 		/* status phase OUT */
 		this->enqueue_packet(this, 0, 0, NULL, 0, 0, 0);
@@ -284,7 +304,7 @@ static int setup_ep0(struct usbdev_ctrl *this, dev_req_t *dr)
 		/* data phase IN */
 		this->enqueue_packet(this, 0, 1, (void *)dd,
 			min(sizeof(*dd), dr->wLength),
-			ZLP(sizeof(*dd), dr->wLength), 1);
+			zlp(this, 0, sizeof(*dd), dr->wLength), 1);
 
 		/* status phase OUT */
 		this->enqueue_packet(this, 0, 0, NULL, 0, 0, 0);
diff --git a/payloads/libpayload/include/udc/udc.h b/payloads/libpayload/include/udc/udc.h
index 48e73f4..7987c51 100644
--- a/payloads/libpayload/include/udc/udc.h
+++ b/payloads/libpayload/include/udc/udc.h
@@ -80,6 +80,7 @@ struct usbdev_ctrl {
 	int remote_wakeup;
 
 	struct usbdev_configuration *current_config;
+	struct usbdev_interface *current_iface;
 	int current_config_id;
 
 	struct configuration_list configs;
@@ -87,6 +88,7 @@ struct usbdev_ctrl {
 	device_descriptor_t device_descriptor;
 
 	int ep_halted[16][2];
+	int ep_mps[16][2];
 
 	/** returns 0 if an error occurred */
 	int (*poll)(struct usbdev_ctrl *);



More information about the coreboot-gerrit mailing list