usb: add hiddev and write to flash
This commit is contained in:
1
Makefile
1
Makefile
@@ -62,6 +62,7 @@ src/usb/setup.c \
|
|||||||
src/usb/ctrl.c \
|
src/usb/ctrl.c \
|
||||||
src/usb/debug.c \
|
src/usb/debug.c \
|
||||||
src/usb/dev.c \
|
src/usb/dev.c \
|
||||||
|
src/usb/composite/hiddev.c \
|
||||||
|
|
||||||
# ASM sources
|
# ASM sources
|
||||||
ASM_SOURCES = \
|
ASM_SOURCES = \
|
||||||
|
|||||||
35
src/main.c
35
src/main.c
@@ -94,6 +94,40 @@ void ble_start()
|
|||||||
legacy_registerService();
|
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()
|
void handle_mode_transition()
|
||||||
{
|
{
|
||||||
static int prev_mode;
|
static int prev_mode;
|
||||||
@@ -141,6 +175,7 @@ int main()
|
|||||||
debug_init();
|
debug_init();
|
||||||
PRINT("\nDebug console is on UART%d\n", DEBUG);
|
PRINT("\nDebug console is on UART%d\n", DEBUG);
|
||||||
|
|
||||||
|
hiddev_onWrite(usb_receive);
|
||||||
usb_start();
|
usb_start();
|
||||||
|
|
||||||
led_init();
|
led_init();
|
||||||
|
|||||||
230
src/usb/composite/hiddev.c
Normal file
230
src/usb/composite/hiddev.c
Normal file
@@ -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);
|
||||||
|
}
|
||||||
@@ -121,6 +121,10 @@ void usb_start() {
|
|||||||
|
|
||||||
ctrl_init();
|
ctrl_init();
|
||||||
|
|
||||||
|
/* This should be placed first, the python script always looks
|
||||||
|
for the first interface (not the interface number) */
|
||||||
|
hiddev_init();
|
||||||
|
|
||||||
init();
|
init();
|
||||||
PFIC_EnableIRQ(USB_IRQn);
|
PFIC_EnableIRQ(USB_IRQn);
|
||||||
}
|
}
|
||||||
@@ -3,6 +3,10 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#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();
|
void usb_start();
|
||||||
|
|
||||||
#endif /* __USB_H__ */
|
#endif /* __USB_H__ */
|
||||||
|
|||||||
Reference in New Issue
Block a user