From 249c289aa77685925da25cb9204b50ba21989779 Mon Sep 17 00:00:00 2001 From: Sean Cross Date: Tue, 1 Jan 2019 23:31:51 +0800 Subject: [PATCH] grainuum: add support libraries Add supporting files for grainuum. Signed-off-by: Sean Cross --- include/grainuum.h | 6 +- ld/linker.ld | 2 +- src/grainuum-state.c | 16 +- src/usb.c | 297 ++++++++++++++++++++++++++++++++++++- third_party/libbase/libc.c | 42 ++++++ 5 files changed, 351 insertions(+), 12 deletions(-) create mode 100644 third_party/libbase/libc.c diff --git a/include/grainuum.h b/include/grainuum.h index 4050384..07eb25c 100644 --- a/include/grainuum.h +++ b/include/grainuum.h @@ -42,6 +42,8 @@ #define GRAINUUM_STATE_EXTRA #endif /* GRAINUUM_STATE_EXTRA */ +#define GRAINUUM_PACKET_SIZE_MAX 64 + /** * @brief Extra fields for GrainuumUSB struct. * @note Use this to store context and thread information. @@ -152,9 +154,9 @@ struct usb_packet { union { struct { uint8_t pid; - uint8_t data[10]; /* Including CRC */ + uint8_t data[GRAINUUM_PACKET_SIZE_MAX + 2]; /* Including CRC */ } __attribute((packed, aligned(4))); - uint8_t raw_data[11]; + uint8_t raw_data[GRAINUUM_PACKET_SIZE_MAX + 3]; } __attribute((packed, aligned(4))); uint8_t size; /* Not including pid (so may be 0) */ /* Checksum omitted */ diff --git a/ld/linker.ld b/ld/linker.ld index 9eb4e9e..46a8c4e 100644 --- a/ld/linker.ld +++ b/ld/linker.ld @@ -31,7 +31,7 @@ SECTIONS *(.data .data.* .gnu.linkonce.d.*) *(.data1) _gp = ALIGN(16); - *(.sdata .sdata.* .gnu.linkonce.s.*) + *(.sdata .sdata.* .gnu.linkonce.s.* .sdata2 .sdata2.*) _edata = ALIGN(16); /* Make sure _edata is >= _gp. */ } > sram diff --git a/src/grainuum-state.c b/src/grainuum-state.c index 260ed0f..dbd6f6b 100644 --- a/src/grainuum-state.c +++ b/src/grainuum-state.c @@ -139,8 +139,8 @@ static void grainuum_state_process_tx(struct GrainuumState *state) } /* Keep the packet size to 8 bytes max */ - if (state->data_out_left > 8) - state->packet.size = 8; + if (state->data_out_left > GRAINUUM_PACKET_SIZE_MAX) + state->packet.size = GRAINUUM_PACKET_SIZE_MAX; else state->packet.size = state->data_out_left; @@ -172,9 +172,9 @@ static void usbStateTransferSuccess(struct GrainuumState *state) * to this function with state->data_out_left == 0. This will send * a NULL packet, which indicates end-of-transfer. */ - state->data_out_left -= 8; - state->data_out_max -= 8; - state->data_out += 8; + state->data_out_left -= GRAINUUM_PACKET_SIZE_MAX; + state->data_out_max -= GRAINUUM_PACKET_SIZE_MAX; + state->data_out += GRAINUUM_PACKET_SIZE_MAX; if ((state->data_out_left < 0) || (state->data_out_max < 0)) { grainuum_state_clear_tx(state, 0); @@ -274,7 +274,7 @@ static int grainuum_state_process_setup(struct GrainuumState *state, const uint8 } static void grainuum_state_parse_data(struct GrainuumState *state, - const uint8_t packet[10], + const uint8_t packet[GRAINUUM_PACKET_SIZE_MAX + 2], uint32_t size) { (void)size; @@ -316,10 +316,10 @@ static inline void grainuum_state_parse_token(struct GrainuumState *state, } void grainuumProcess(struct GrainuumUSB *usb, - const uint8_t packet[12]) + const uint8_t packet[GRAINUUM_PACKET_SIZE_MAX + 3]) { - uint32_t size = packet[11]; + uint32_t size = packet[GRAINUUM_PACKET_SIZE_MAX + 3]; struct GrainuumState *state = &usb->state; switch(packet[0]) { case USB_PID_SETUP: diff --git a/src/usb.c b/src/usb.c index d896b70..0099caa 100644 --- a/src/usb.c +++ b/src/usb.c @@ -1,11 +1,305 @@ #include #include #include +#include + +#define NUM_BUFFERS 4 +#define BUFFER_SIZE 64 +#define EP_INTERVAL_MS 6 -static struct GrainuumConfig cfg; static struct GrainuumUSB usb; static uint8_t usb_buf[67]; +static uint32_t rx_buffer[NUM_BUFFERS][BUFFER_SIZE / sizeof(uint32_t)]; +static uint8_t rx_buffer_head; +static uint8_t rx_buffer_tail; + +static uint32_t rx_buffer_queries = 0; + + +static void set_usb_config_num(struct GrainuumUSB *usb, int configNum) +{ + (void)usb; + (void)configNum; + ; +} + +static const uint8_t hid_report_descriptor[] = { + 0x06, 0x00, 0xFF, // (GLOBAL) USAGE_PAGE 0xFF00 Vendor-defined + 0x09, 0x00, // (LOCAL) USAGE 0xFF000000 + 0xA1, 0x01, // (MAIN) COLLECTION 0x01 Application (Usage=0xFF000000: Page=Vendor-defined, Usage=, Type=) + 0x26, 0xFF, 0x00, // (GLOBAL) LOGICAL_MAXIMUM 0x00FF (255) + 0x75, 0x08, // (GLOBAL) REPORT_SIZE 0x08 (8) Number of bits per field + 0x95, 0x08, // (GLOBAL) REPORT_COUNT 0x08 (8) Number of fields + 0x06, 0xFF, 0xFF, // (GLOBAL) USAGE_PAGE 0xFFFF Vendor-defined + 0x09, 0x01, // (LOCAL) USAGE 0xFFFF0001 + 0x81, 0x02, // (MAIN) INPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap + 0x09, 0x01, // (LOCAL) USAGE 0xFFFF0001 + 0x91, 0x02, // (MAIN) OUTPUT 0x00000002 (8 fields x 8 bits) 0=Data 1=Variable 0=Absolute 0=NoWrap 0=Linear 0=PrefState 0=NoNull 0=NonVolatile 0=Bitmap + 0xC0, // (MAIN) END_COLLECTION Application +}; + +static const struct usb_device_descriptor device_descriptor = { + .bLength = 18, //sizeof(struct usb_device_descriptor), + .bDescriptorType = DT_DEVICE, /* DEVICE */ + .bcdUSB = 0x0200, /* USB 2.0 */ + .bDeviceClass = 0x00, + .bDeviceSubClass = 0x00, + .bDeviceProtocol = 0x00, + .bMaxPacketSize0 = 0x08, /* 8-byte packets max */ + .idVendor = 0x1209, + .idProduct = 0x9317, + .bcdDevice = 0x0114, /* Device release 1.14 */ + .iManufacturer = 0x02, /* No manufacturer string */ + .iProduct = 0x01, /* Product name in string #2 */ + .iSerialNumber = 0x03, /* No serial number */ + .bNumConfigurations = 0x01, +}; + +static const struct usb_configuration_descriptor configuration_descriptor = { + .bLength = 9, //sizeof(struct usb_configuration_descriptor), + .bDescriptorType = DT_CONFIGURATION, + .wTotalLength = (9 + /*9 + 9 + 7 +*/ 9 + 9 + 7 + 7) /* + (sizeof(struct usb_configuration_descriptor) + + sizeof(struct usb_interface_descriptor) + + sizeof(struct usb_hid_descriptor) + + sizeof(struct usb_endpoint_descriptor)*/, + .bNumInterfaces = 1, + .bConfigurationValue = 1, + .iConfiguration = 5, + .bmAttributes = 0x80, /* Remote wakeup not supported */ + .bMaxPower = 100 / 2, /* 100 mA (in 2-mA units) */ + .data = { + /* struct usb_interface_descriptor { */ + /* uint8_t bLength; */ 9, + /* uint8_t bDescriptorType; */ DT_INTERFACE, + /* uint8_t bInterfaceNumber; */ 0, + /* uint8_t bAlternateSetting; */ 0, + /* uint8_t bNumEndpoints; */ 2, /* Two extra EPs */ + /* uint8_t bInterfaceClass; */ 3, /* HID class */ + /* uint8_t bInterfaceSubclass; */ 0, /* Boot Device subclass */ + /* uint8_t bInterfaceProtocol; */ 0, /* 1 == keyboard, 2 == mouse */ + /* uint8_t iInterface; */ 4, /* String index #4 */ + /* }*/ + + /* struct usb_hid_descriptor { */ + /* uint8_t bLength; */ 9, + /* uint8_t bDescriptorType; */ DT_HID, + /* uint16_t bcdHID; */ 0x11, 0x01, + /* uint8_t bCountryCode; */ 0, + /* uint8_t bNumDescriptors; */ 1, /* We have only one REPORT */ + /* uint8_t bReportDescriptorType; */ DT_HID_REPORT, + /* uint16_t wReportDescriptorLength; */ sizeof(hid_report_descriptor), + sizeof(hid_report_descriptor) >> 8, + /* } */ + + /* struct usb_endpoint_descriptor { */ + /* uint8_t bLength; */ 7, + /* uint8_t bDescriptorType; */ DT_ENDPOINT, + /* uint8_t bEndpointAddress; */ 0x81, /* EP1 (IN) */ + /* uint8_t bmAttributes; */ 3, /* Interrupt */ + /* uint16_t wMaxPacketSize; */ 0x08, 0x00, + /* uint8_t bInterval; */ EP_INTERVAL_MS, /* Every 6 ms */ + /* } */ + + /* struct usb_endpoint_descriptor { */ + /* uint8_t bLength; */ 7, + /* uint8_t bDescriptorType; */ DT_ENDPOINT, + /* uint8_t bEndpointAddress; */ 0x01, /* EP1 (OUT) */ + /* uint8_t bmAttributes; */ 3, /* Interrupt */ + /* uint16_t wMaxPacketSize; */ 0x08, 0x00, + /* uint8_t bInterval; */ EP_INTERVAL_MS, /* Every 6 ms */ + /* } */ + }, +}; + +#define USB_STR_BUF_LEN 64 + +static uint32_t str_buf_storage[USB_STR_BUF_LEN / sizeof(uint32_t)]; +static int send_string_descriptor(const char *str, const void **data) +{ + int len; + int max_len; + uint8_t *str_buf = (uint8_t *)str_buf_storage; + uint8_t *str_offset = str_buf; + + len = strlen(str); + max_len = (USB_STR_BUF_LEN / 2) - 2; + + if (len > max_len) + len = max_len; + + *str_offset++ = (len * 2) + 2; // Two bytes for length count + *str_offset++ = DT_STRING; // Sending a string descriptor + + while (len--) + { + *str_offset++ = *str++; + *str_offset++ = 0; + } + + *data = str_buf; + + // Return the size, which is stored in the first byte of the output data. + return str_buf[0]; +} + +static int get_string_descriptor(struct GrainuumUSB *usb, + uint32_t num, + const void **data) +{ + + static const uint8_t en_us[] = {0x04, DT_STRING, 0x09, 0x04}; + + (void)usb; + + if (num == 0) + { + *data = en_us; + return sizeof(en_us); + } + + // Product + if (num == 1) + return send_string_descriptor("Palawan Bootloader", data); + + if (num == 2) + return send_string_descriptor("21", data); + + if (num == 3) + return send_string_descriptor("1236", data); + + if (num == 4) + return send_string_descriptor("12345", data); + + if (num == 5) + return send_string_descriptor("54", data); + + if (num == 6) + return send_string_descriptor("12345678901234", data); + + return 0; +} + +static int get_device_descriptor(struct GrainuumUSB *usb, + uint32_t num, + const void **data) +{ + + (void)usb; + + if (num == 0) + { + *data = &device_descriptor; + return sizeof(device_descriptor); + } + return 0; +} + +static int get_hid_report_descriptor(struct GrainuumUSB *usb, + uint32_t num, + const void **data) +{ + + (void)usb; + + if (num == 0) + { + *data = &hid_report_descriptor; + return sizeof(hid_report_descriptor); + } + + return 0; +} + +static int get_configuration_descriptor(struct GrainuumUSB *usb, + uint32_t num, + const void **data) +{ + + (void)usb; + + if (num == 0) + { + *data = &configuration_descriptor; + return configuration_descriptor.wTotalLength; + } + return 0; +} + +static int get_descriptor(struct GrainuumUSB *usb, + const void *packet, + const void **response) +{ + + const struct usb_setup_packet *setup = packet; + + switch (setup->wValueH) + { + case DT_DEVICE: + return get_device_descriptor(usb, setup->wValueL, response); + + case DT_STRING: + return get_string_descriptor(usb, setup->wValueL, response); + + case DT_CONFIGURATION: + return get_configuration_descriptor(usb, setup->wValueL, response); + + case DT_HID_REPORT: + return get_hid_report_descriptor(usb, setup->wValueL, response); + } + + return 0; +} + +static void *get_usb_rx_buffer(struct GrainuumUSB *usb, + uint8_t epNum, + int32_t *size) +{ + (void)usb; + (void)epNum; + + if (size) + *size = sizeof(rx_buffer[0]); + rx_buffer_queries++; + return rx_buffer[rx_buffer_head]; +} + +static int received_data(struct GrainuumUSB *usb, + uint8_t epNum, + uint32_t bytes, + const void *data) +{ + (void)usb; + (void)epNum; + (void)bytes; + (void)data; + + if (epNum == 1) + { + rx_buffer_head = (rx_buffer_head + 1) & (NUM_BUFFERS - 1); + } + + /* Return 0, indicating this packet is complete. */ + return 0; +} + +static int send_data_finished(struct GrainuumUSB *usb, int result) +{ + (void)usb; + (void)result; + + return 0; +} + +static struct GrainuumConfig cfg = { + .getDescriptor = get_descriptor, + .getReceiveBuffer = get_usb_rx_buffer, + .receiveData = received_data, + .sendDataFinished = send_data_finished, + .setConfigNum = set_usb_config_num, +}; + void usb_isr(void) { grainuumCaptureI(&usb, usb_buf); return; @@ -13,6 +307,7 @@ void usb_isr(void) { void usb_init(void) { grainuumInit(&usb, &cfg); + grainuumConnect(&usb); return; } diff --git a/third_party/libbase/libc.c b/third_party/libbase/libc.c new file mode 100644 index 0000000..a02f4ce --- /dev/null +++ b/third_party/libbase/libc.c @@ -0,0 +1,42 @@ +/* $OpenBSD: strlen.c,v 1.8 2014/06/10 04:17:37 deraadt Exp $ */ + +/*- + * Copyright (c) 1990, 1993 + * The Regents of the University of California. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include + +size_t +strlen(const char *str) +{ + const char *s; + + for (s = str; *s; ++s) + ; + return (s - str); +} \ No newline at end of file