diff options
Diffstat (limited to 'payloads/libpayload/drivers')
-rw-r--r-- | payloads/libpayload/drivers/udc/chipidea.c | 9 | ||||
-rw-r--r-- | payloads/libpayload/drivers/udc/udc.c | 28 |
2 files changed, 33 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); |