aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDien-Nhung Nguyen-Phu <kein@kienlab.com>2024-07-11 21:23:07 +0700
committerDien-Nhung Nguyen-Phu <kein@kienlab.com>2024-07-11 22:18:56 +0700
commit49fc27a23e0f5ca46337493cdac02ee116f786e3 (patch)
treed46124776c6fcf295ef18a18f2f90c128e2369e0
parent4f3b6f4283e0240060c04a137175cacfb385dc16 (diff)
usb: add hiddev and write to flash
-rw-r--r--Makefile1
-rw-r--r--src/main.c35
-rw-r--r--src/usb/composite/hiddev.c230
-rw-r--r--src/usb/setup.c4
-rw-r--r--src/usb/usb.h4
5 files changed, 274 insertions, 0 deletions
diff --git a/Makefile b/Makefile
index e6ba8a6..448c201 100644
--- a/Makefile
+++ b/Makefile
@@ -62,6 +62,7 @@ src/usb/setup.c \
src/usb/ctrl.c \
src/usb/debug.c \
src/usb/dev.c \
+src/usb/composite/hiddev.c \
# ASM sources
ASM_SOURCES = \
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 <stdint.h>
+#include <memory.h>
+
+#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 <stdint.h>
+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__ */