From 49fc27a23e0f5ca46337493cdac02ee116f786e3 Mon Sep 17 00:00:00 2001 From: Dien-Nhung Nguyen-Phu Date: Thu, 11 Jul 2024 21:23:07 +0700 Subject: usb: add hiddev and write to flash --- src/main.c | 35 +++++++ src/usb/composite/hiddev.c | 230 +++++++++++++++++++++++++++++++++++++++++++++ src/usb/setup.c | 4 + src/usb/usb.h | 4 + 4 files changed, 273 insertions(+) create mode 100644 src/usb/composite/hiddev.c (limited to 'src') diff --git a/src/main.c b/src/main.c index 4f46181..f2e788c 100644 --- a/src/main.c +++ b/src/main.c @@ -94,6 +94,40 @@ void ble_start() legacy_registerService(); } +static void usb_receive(uint8_t *buf, uint16_t len) +{ + static uint16_t rx_len, data_len; + static uint8_t *data; + + PRINT("dump first 8 bytes: %02x %02x %02x %02x %02x %02x %02x %02x\n", + buf[0], buf[1], buf[2], buf[3], + buf[4], buf[5], buf[6], buf[7]); + + if (rx_len == 0) { + if (memcmp(buf, "wang", 5)) + return; + + int init_len = len > LEGACY_HEADER_SIZE ? len : sizeof(data_legacy_t); + init_len += MAX_PACKET_SIZE; + data = malloc(init_len); + } + + memcpy(data + rx_len, buf, len); + rx_len += len; + + if (!data_len) { + data_legacy_t *d = (data_legacy_t *)data; + uint16_t n = bigendian16_sum(d->sizes, 8); + data_len = LEGACY_HEADER_SIZE + LED_ROWS * n; + data = realloc(data, data_len); + } + + if ((rx_len > LEGACY_HEADER_SIZE) && rx_len >= data_len) { + data_flatSave(data, data_len); + SYS_ResetExecute(); + } +} + void handle_mode_transition() { static int prev_mode; @@ -141,6 +175,7 @@ int main() debug_init(); PRINT("\nDebug console is on UART%d\n", DEBUG); + hiddev_onWrite(usb_receive); usb_start(); led_init(); diff --git a/src/usb/composite/hiddev.c b/src/usb/composite/hiddev.c new file mode 100644 index 0000000..bb075e5 --- /dev/null +++ b/src/usb/composite/hiddev.c @@ -0,0 +1,230 @@ +#include +#include + +#include "CH58x_common.h" + +#include "../utils.h" +#include "../debug.h" + +#define EP_NUM (1) +#define IF_NUM (0) + +static __attribute__((aligned(4))) uint8_t ep_buf[64 + 64]; +static uint8_t *const ep_out = ep_buf; +static uint8_t *const ep_in = ep_buf + 64; + +static void (*on_write)(uint8_t *buf, uint16_t len); + +static USB_ITF_DESCR if_desc = { + .bLength = sizeof(USB_ITF_DESCR), + .bDescriptorType = USB_DESCR_TYP_INTERF, + .bInterfaceNumber = IF_NUM, + .bAlternateSetting = 0, + .bNumEndpoints = 2, /* One for read, one for write */ + .bInterfaceClass = 0x03, /* HID class */ + .bInterfaceSubClass = 0, /* No subclass */ + .bInterfaceProtocol = 0, /* Not a Mouse nor Keyboard */ + .iInterface = 0 /* Index of string descriptor */ +}; + +static USB_HID_DESCR hid_desc = { + .bLength = sizeof(USB_HID_DESCR), + .bDescriptorType = USB_DESCR_TYP_HID, + .bcdHID = 0x0100, + .bCountryCode = 0x00, + .bNumDescriptors = 0x01, + .bDescriptorTypeX = 0x22, + .wDescriptorLengthL = 0x22, + .wDescriptorLengthH = 0x00 +}; + +static USB_ENDP_DESCR read_ep_desc = { + .bLength = sizeof(USB_ENDP_DESCR), + .bDescriptorType = USB_DESCR_TYP_ENDP, + .bEndpointAddress = 0x80 | EP_NUM, /* IN endpoint */ + .bmAttributes = 0x03, /* exchange data over Interrupt */ + .wMaxPacketSize = MAX_PACKET_SIZE, /* bytes */ + .bInterval = 0xff /* polling interval */ +}; + +static USB_ENDP_DESCR write_ep_desc = { + .bLength = sizeof(USB_ENDP_DESCR), + .bDescriptorType = USB_DESCR_TYP_ENDP, + .bEndpointAddress = EP_NUM, /* IN endpoint */ + .bmAttributes = 0x03, /* exchange data over Interrupt */ + .wMaxPacketSize = MAX_PACKET_SIZE, /* bytes */ + .bInterval = 8 /* polling interval */ +}; + +static const uint8_t report_desc[] = { + 0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00) + 0x09, 0x01, // Usage (0x01) + 0xA1, 0x01, // Collection (Application) + + /* IN */ + 0x09, 0x02, // Usage (0x02) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0x00, 0xFF, // Logical Maximum (-256) + 0x75, 0x08, // Report Size (8) + 0x95, 0x40, // Report Count (64) + 0x81, 0x06, // INPUT + + /* OUT */ + 0x09, 0x02, // Usage (0x02) + 0x15, 0x00, // Logical Minimum (0) + 0x26, 0x00, 0xFF, // Logical Maximum (-256) + 0x75, 0x08, // Report Size (8) + 0x95, 0x40, // Report Count (64) + 0x91, 0x06, // OUTPUT + + 0xC0, // End Collection +}; + +static void hid_request_handler(USB_SETUP_REQ * request) +{ + _TRACE(); + static uint8_t report_val, idle_val; + uint8_t req = request->bRequest; + uint16_t type = request->wValue >> 8; + + switch(req) { + case USB_GET_DESCRIPTOR: + PRINT("- USB_GET_DESCRIPTOR\n"); + PRINT("bDescriptorType: 0x%02x\n", type); + switch (type) + { + case USB_DESCR_TYP_REPORT: + PRINT("- USB_DESCR_TYP_REPORT\n"); + ctrl_start_load_block(report_desc, sizeof(report_desc)); + break; + + default: + break; + } + break; + + case HID_GET_REPORT: + PRINT("- HID_GET_REPORT\n"); + break; + + case HID_GET_IDLE: + PRINT("- HID_GET_IDLE\n"); + ctrl_start_load_block(&idle_val, 1); + break; + + case HID_GET_PROTOCOL: + PRINT("- HID_GET_PROTOCOL\n"); + ctrl_start_load_block(&report_val, 1); + break; + + case HID_SET_REPORT: + PRINT("- HID_SET_REPORT\n"); + ctrl_ack(); + break; + + case HID_SET_IDLE: + PRINT("- HID_SET_IDLE\n"); + ctrl_ack(); + break; + + case HID_SET_PROTOCOL: + PRINT("- HID_SET_PROTOCOL\n"); + break; + + default: + break; + } +} + +static volatile uint16_t transferred; + +static void ep_handler() +{ + _TRACE(); + static int tog; + uint8_t token = R8_USB_INT_ST & MASK_UIS_TOKEN; + + switch(token) { + case UIS_TOKEN_OUT: + if (on_write) + on_write(ep_out, R8_USB_RX_LEN); + set_handshake(EP_NUM, USB_ACK, tog, 0); + tog = !tog; + break; + + case UIS_TOKEN_IN: + if (transferred == 0) { + transferred = 1; + } else { + set_handshake(EP_NUM, USB_NAK, 1, 0); + } + break; + break; + + default: + break; + } +} + +// In case we want to send something to the host, +// or want to see the log over hidraw by `cat /dev/hidrawX` +void hiddev_fill_IN(uint8_t *buf, uint8_t len) +{ + if (len > read_ep_desc.wMaxPacketSize) + return; + + static int tog; + + memcpy(ep_in, buf, len); + set_handshake(EP_NUM, USB_ACK, tog, len); + + tog = !tog; + transferred = 0; +} + +static int wait_until_sent(uint16_t timeout_ms) +{ + while(timeout_ms--) { + if (transferred) { + return 0; + } + DelayMs(1); + } + return -1; +} + +int hiddev_tx_poll(uint8_t *buf, int len, uint16_t timeout_ms) +{ + int i = 0; + while (len > read_ep_desc.wMaxPacketSize) { + hiddev_fill_IN(buf + i, read_ep_desc.wMaxPacketSize); + if (wait_until_sent(timeout_ms)) + return -1; + + i += read_ep_desc.wMaxPacketSize; + len -= read_ep_desc.wMaxPacketSize; + } + hiddev_fill_IN(buf + i, len); + if (wait_until_sent(timeout_ms)) + return -1; + + return 0; +} + +void hiddev_onWrite(void (*cb)(uint8_t *buf, uint16_t len)) +{ + on_write = cb; +} + +void hiddev_init() +{ + cfg_desc_append(&if_desc); + cfg_desc_append(&hid_desc); + cfg_desc_append(&read_ep_desc); + cfg_desc_append(&write_ep_desc); + + if_cb_register(IF_NUM, hid_request_handler); + ep_cb_register(EP_NUM, ep_handler); + + dma_register(EP_NUM, ep_out); +} diff --git a/src/usb/setup.c b/src/usb/setup.c index b24fed0..609267a 100644 --- a/src/usb/setup.c +++ b/src/usb/setup.c @@ -121,6 +121,10 @@ void usb_start() { ctrl_init(); + /* This should be placed first, the python script always looks + for the first interface (not the interface number) */ + hiddev_init(); + init(); PFIC_EnableIRQ(USB_IRQn); } \ No newline at end of file diff --git a/src/usb/usb.h b/src/usb/usb.h index 5946daf..a542e68 100644 --- a/src/usb/usb.h +++ b/src/usb/usb.h @@ -3,6 +3,10 @@ #include +void hiddev_fill_IN(uint8_t *buf, uint8_t len); +int hiddev_tx_poll(uint8_t *buf, int len, uint16_t timeout_ms); +void hiddev_onWrite(void (*cb)(uint8_t *buf, uint16_t len)); + void usb_start(); #endif /* __USB_H__ */ -- cgit v1.2.3