summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--payloads/libpayload/drivers/udc/chipidea.c9
-rw-r--r--payloads/libpayload/drivers/udc/udc.c28
-rw-r--r--payloads/libpayload/include/udc/udc.h2
3 files changed, 35 insertions, 4 deletions
diff --git a/payloads/libpayload/drivers/udc/chipidea.c b/payloads/libpayload/drivers/udc/chipidea.c
index e06f0d2824..58bea063e7 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 cdc2b29f95..89a7d1dac2 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 48e73f4c56..7987c51286 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 *);