summaryrefslogtreecommitdiff
path: root/payloads/libpayload
diff options
context:
space:
mode:
Diffstat (limited to 'payloads/libpayload')
-rw-r--r--payloads/libpayload/drivers/udc/chipidea.c1
-rw-r--r--payloads/libpayload/drivers/udc/udc.c68
-rw-r--r--payloads/libpayload/include/udc/udc.h21
3 files changed, 90 insertions, 0 deletions
diff --git a/payloads/libpayload/drivers/udc/chipidea.c b/payloads/libpayload/drivers/udc/chipidea.c
index 8299a08859..16a42e45a3 100644
--- a/payloads/libpayload/drivers/udc/chipidea.c
+++ b/payloads/libpayload/drivers/udc/chipidea.c
@@ -489,6 +489,7 @@ struct usbdev_ctrl *chipidea_init(device_descriptor_t *dd)
ctrl->poll = chipidea_poll;
ctrl->add_gadget = udc_add_gadget;
+ ctrl->add_strings = udc_add_strings;
ctrl->enqueue_packet = chipidea_enqueue_packet;
ctrl->shutdown = chipidea_shutdown;
ctrl->set_address = chipidea_set_address;
diff --git a/payloads/libpayload/drivers/udc/udc.c b/payloads/libpayload/drivers/udc/udc.c
index d0683ff328..01aa4b1003 100644
--- a/payloads/libpayload/drivers/udc/udc.c
+++ b/payloads/libpayload/drivers/udc/udc.c
@@ -47,6 +47,18 @@
#define min(a, b) (((a) < (b)) ? (a) : (b))
+static unsigned short strings_lang_id = 0;
+static unsigned char strings_count = 0;
+static const char **strings;
+
+void udc_add_strings(unsigned short lang_id, unsigned char count,
+ const char **str)
+{
+ strings_lang_id = lang_id;
+ strings_count = count;
+ strings = str;
+}
+
/* determine if an additional zero length packet is necessary for
* a transfer */
static unsigned int zlp(struct usbdev_ctrl *this, const int epnum,
@@ -303,6 +315,62 @@ static int setup_ep0(struct usbdev_ctrl *this, dev_req_t *dr)
} else
if ((dr->bmRequestType == 0x80) &&
(dr->bRequest == GET_DESCRIPTOR) &&
+ ((dr->wValue & 0xff00) == 0x0300)) {
+ int id = (dr->wValue & 0xff);
+ if (id == 0) {
+ if (strings_lang_id == 0)
+ return 0;
+
+ uint8_t *data = dma_malloc(4);
+ data[0] = 0x04; // length
+ data[1] = 0x03; // string descriptor
+ data[2] = strings_lang_id & 0xff;
+ data[3] = strings_lang_id >> 8;
+ /* data phase IN */
+ this->enqueue_packet(this, 0, 1,
+ data,
+ min(data[0], dr->wLength),
+ zlp(this, 0, data[0], dr->wLength),
+ 1);
+
+ /* status phase OUT */
+ this->enqueue_packet(this, 0, 0, NULL, 0, 0, 0);
+ } else {
+ if (strings_lang_id == 0)
+ return 0;
+
+ int lang = dr->wIndex;
+ if (lang != strings_lang_id)
+ return 0;
+
+ if (id > strings_count)
+ return 0;
+
+ int s_len = strlen(strings[id]);
+ int d_len = s_len * 2;
+
+ uint8_t *data = dma_malloc(d_len + 2);
+ memset(data, 0, d_len);
+ data[0] = d_len + 2; // length
+ data[1] = 0x03; // string descriptor
+ int i;
+ for (i = 0; i < s_len; i++)
+ data[i * 2 + 2] = strings[id][i];
+
+ /* data phase IN */
+ this->enqueue_packet(this, 0, 1,
+ data,
+ min(d_len + 2, dr->wLength),
+ zlp(this, 0, d_len + 2, dr->wLength),
+ 1);
+
+ /* status phase OUT */
+ this->enqueue_packet(this, 0, 0, NULL, 0, 0, 0);
+ }
+ return 1;
+ } else
+ if ((dr->bmRequestType == 0x80) &&
+ (dr->bRequest == GET_DESCRIPTOR) &&
((dr->wValue & 0xff00) == 0x0100)) {
device_descriptor_t *dd = dma_malloc(sizeof(*dd));
memcpy(dd, &this->device_descriptor, sizeof(*dd));
diff --git a/payloads/libpayload/include/udc/udc.h b/payloads/libpayload/include/udc/udc.h
index 7987c51286..99cbb1b7eb 100644
--- a/payloads/libpayload/include/udc/udc.h
+++ b/payloads/libpayload/include/udc/udc.h
@@ -103,6 +103,22 @@ struct usbdev_ctrl {
struct usbdev_configuration *config);
/**
+ * Add a set of strings to use for string descriptors.
+ *
+ * 's' must point to an array of strings of which the first
+ * element is unused, with at most 255 elements.
+ *
+ * 'm' is the size of 'strings' (ie. the index of the last entry).
+ *
+ * 'l' is the USB language code, of which some are defined below,
+ * eg. LANG_EN_US.
+ *
+ * For now, only one language is ever exposed: Calling add_strings overwrites
+ * older configuration.
+ */
+ void (*add_strings)(unsigned short l, unsigned char m, const char **s);
+
+ /**
* Add packet to process by the controller.
* zlp: zero length packet, if such a termination is necessary
* autofree: free data after use
@@ -136,8 +152,13 @@ struct usbdev_ctrl {
void (*free_data)(void *);
};
+#define LANG_DE_DE 0x0407
+#define LANG_EN_US 0x0409
+
void udc_add_gadget(struct usbdev_ctrl *this,
struct usbdev_configuration *config);
+void udc_add_strings(unsigned short id, unsigned char count,
+ const char *strings[]);
void udc_handle_setup(struct usbdev_ctrl *this, int ep, dev_req_t *dr);
#endif