diff --git a/Kconfig b/Kconfig index a630e73c..c2b2ab4c 100644 --- a/Kconfig +++ b/Kconfig @@ -105,6 +105,11 @@ if CHERRYUSB prompt "Enable usb dfu device" default n + config CHERRYUSB_DEVICE_ADB + bool + prompt "Enable usb adb device" + default n + choice prompt "Select usb device template" default CHERRYUSB_DEVICE_TEMPLATE_NONE diff --git a/README.md b/README.md index a0645bbc..5e817c4c 100644 --- a/README.md +++ b/README.md @@ -68,6 +68,7 @@ CherryUSB Device Stack has the following functions: - Support WINUSB1.0、WINUSB2.0、WEBUSB、BOS - Support Vendor class - Support UF2 +- Support Android Debug Bridge (Only support shell) - Support multi device with the same USB IP CherryUSB Device Stack resource usage (GCC 10.2 with -O2): diff --git a/README_zh.md b/README_zh.md index 6552acab..091b5cad 100644 --- a/README_zh.md +++ b/README_zh.md @@ -68,6 +68,7 @@ CherryUSB Device 协议栈当前实现以下功能: - 支持 WINUSB1.0、WINUSB2.0、WEBUSB、BOS - 支持 Vendor 类 class - 支持 UF2 +- 支持 Android Debug Bridge (Only support shell) - 支持相同 USB IP 的多从机 CherryUSB Device 协议栈资源占用说明(GCC 10.2 with -O2): diff --git a/cherryusb.cmake b/cherryusb.cmake index f5d6fa51..beec519c 100644 --- a/cherryusb.cmake +++ b/cherryusb.cmake @@ -36,6 +36,7 @@ ${CMAKE_CURRENT_LIST_DIR}/class/audio ${CMAKE_CURRENT_LIST_DIR}/class/video ${CMAKE_CURRENT_LIST_DIR}/class/wireless ${CMAKE_CURRENT_LIST_DIR}/class/midi +${CMAKE_CURRENT_LIST_DIR}/class/adb ${CMAKE_CURRENT_LIST_DIR}/class/vendor/net ${CMAKE_CURRENT_LIST_DIR}/class/vendor/serial ${CMAKE_CURRENT_LIST_DIR}/class/vendor/wifi @@ -70,6 +71,9 @@ if(CONFIG_CHERRYUSB_DEVICE) if(CONFIG_CHERRYUSB_DEVICE_DFU) list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/dfu/usbd_dfu.c) endif() + if(CONFIG_CHERRYUSB_DEVICE_ADB) + list(APPEND cherryusb_srcs ${CMAKE_CURRENT_LIST_DIR}/class/adb/usbd_adb.c) + endif() if(DEFINED CONFIG_CHERRYUSB_DEVICE_DCD) if("${CONFIG_CHERRYUSB_DEVICE_DCD}" STREQUAL "fsdev") diff --git a/class/adb/usbd_adb.c b/class/adb/usbd_adb.c new file mode 100644 index 00000000..b193e35f --- /dev/null +++ b/class/adb/usbd_adb.c @@ -0,0 +1,301 @@ +/* + * Copyright (c) 2024, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "usbd_core.h" +#include "usbd_adb.h" + +#define ADB_OUT_EP_IDX 0 +#define ADB_IN_EP_IDX 1 + +#define ADB_STATE_READ_MSG 0 +#define ADB_STATE_READ_DATA 1 +#define ADB_STATE_WRITE_MSG 2 +#define ADB_STATE_WRITE_DATA 3 +#define ADB_STATE_AWRITE_MSG 4 +#define ADB_STATE_AWRITE_DATA 5 + +#define MAX_PAYLOAD_V1 (4 * 1024) +#define MAX_PAYLOAD_V2 (256 * 1024) +#define MAX_PAYLOAD MAX_PAYLOAD_V1 +#define A_VERSION 0x01000000 + +#define A_SYNC 0x434e5953 +#define A_CNXN 0x4e584e43 +#define A_OPEN 0x4e45504f +#define A_OKAY 0x59414b4f +#define A_CLSE 0x45534c43 +#define A_WRTE 0x45545257 +#define A_AUTH 0x48545541 + +struct adb_msg { + uint32_t command; /* command identifier constant (A_CNXN, ...) */ + uint32_t arg0; /* first argument */ + uint32_t arg1; /* second argument */ + uint32_t data_length; /* length of payload (0 is allowed) */ + uint32_t data_crc32; /* crc32 of data payload */ + uint32_t magic; /* command ^ 0xffffffff */ +}; + +struct adb_packet { + struct adb_msg msg; + uint8_t payload[MAX_PAYLOAD]; +}; + +struct usbd_adb { + uint8_t state; + uint8_t common_state; + uint8_t write_state; + bool writable; + uint32_t localid; + uint32_t shell_remoteid; + uint32_t file_remoteid; +} adb_client; + +static struct usbd_endpoint adb_ep_data[2]; + +USB_NOCACHE_RAM_SECTION struct adb_packet tx_packet; +USB_NOCACHE_RAM_SECTION struct adb_packet rx_packet; + +static inline uint32_t adb_packet_checksum(struct adb_packet *packet) +{ + uint32_t sum = 0; + int i; + + for (i = 0; i < packet->msg.data_length; ++i) { + sum += (uint32_t)(packet->payload[i]); + } + + return sum; +} + +static uint32_t usbd_adb_get_remoteid(uint32_t localid) +{ + if (localid == ADB_SHELL_LOALID) { + return adb_client.shell_remoteid; + } else { + return adb_client.file_remoteid; + } +} + +static void adb_send_msg(struct adb_packet *packet) +{ + adb_client.common_state = ADB_STATE_WRITE_MSG; + + packet->msg.data_crc32 = adb_packet_checksum(packet); + packet->msg.magic = packet->msg.command ^ 0xffffffff; + + usbd_ep_start_write(0, adb_ep_data[ADB_IN_EP_IDX].ep_addr, (uint8_t *)&packet->msg, sizeof(struct adb_msg)); +} + +static void adb_send_okay(struct adb_packet *packet, uint32_t localid) +{ + packet->msg.command = A_OKAY; + packet->msg.arg0 = localid; + packet->msg.arg1 = usbd_adb_get_remoteid(localid); + packet->msg.data_length = 0; + + adb_send_msg(&tx_packet); +} + +static void adb_send_close(struct adb_packet *packet, uint32_t localid, uint32_t remoteid) +{ + packet->msg.command = A_CLSE; + packet->msg.arg0 = localid; + packet->msg.arg1 = remoteid; + packet->msg.data_length = 0; + + adb_send_msg(&tx_packet); +} + +void usbd_adb_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + if (adb_client.common_state == ADB_STATE_READ_MSG) { + if (nbytes != sizeof(struct adb_msg)) { + USB_LOG_ERR("invalid adb msg size:%d\r\n", nbytes); + return; + } + + USB_LOG_DBG("command:%x arg0:%x arg1:%x len:%d\r\n", + rx_packet.msg.command, + rx_packet.msg.arg0, + rx_packet.msg.arg1, + rx_packet.msg.data_length); + + if (rx_packet.msg.data_length) { + /* setup next out ep read transfer */ + adb_client.common_state = ADB_STATE_READ_DATA; + usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, rx_packet.payload, rx_packet.msg.data_length); + } else { + if (rx_packet.msg.command == A_CLSE) { + adb_client.writable = false; + usbd_adb_notify_write_done(); + USB_LOG_INFO("Close remoteid:%x\r\n", rx_packet.msg.arg0); + } + adb_client.common_state = ADB_STATE_READ_MSG; + /* setup first out ep read transfer */ + usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg)); + } + } else if (adb_client.common_state == ADB_STATE_READ_DATA) { + switch (rx_packet.msg.command) { + case A_SYNC: + + break; + case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */ + char *support_feature = "device::" + "ro.product.name=cherryadb;" + "ro.product.model=cherrysh;" + "ro.product.device=cherryadb;" + "features=cmd,shell_v1"; + + tx_packet.msg.command = A_CNXN; + tx_packet.msg.arg0 = A_VERSION; + tx_packet.msg.arg1 = MAX_PAYLOAD; + tx_packet.msg.data_length = strlen(support_feature); + memcpy(tx_packet.payload, support_feature, strlen(support_feature)); + + adb_send_msg(&tx_packet); + + adb_client.writable = false; + break; + case A_OPEN: /* OPEN(local-id, 0, "destination") */ + rx_packet.payload[rx_packet.msg.data_length] = '\0'; + + if (strncmp((const char *)rx_packet.payload, "shell:", 6) == 0) { + adb_client.localid = ADB_SHELL_LOALID; + adb_client.shell_remoteid = rx_packet.msg.arg0; + adb_send_okay(&tx_packet, ADB_SHELL_LOALID); + + USB_LOG_INFO("Open shell service, remoteid:%x\r\n", rx_packet.msg.arg0); + } else if (strncmp((const char *)rx_packet.payload, "sync:", 5) == 0) { + adb_client.localid = ADB_FILE_LOALID; + adb_client.file_remoteid = rx_packet.msg.arg0; + adb_send_okay(&tx_packet, ADB_FILE_LOALID); + USB_LOG_INFO("Open file service, remoteid:%x\r\n", rx_packet.msg.arg0); + } + break; + case A_OKAY: + + break; + case A_CLSE: + + break; + case A_WRTE: /* WRITE(local-id, remote-id, "data") */ + if ((rx_packet.msg.arg0 == adb_client.shell_remoteid) && (rx_packet.msg.arg1 == ADB_SHELL_LOALID)) { + adb_send_okay(&tx_packet, rx_packet.msg.arg1); + } else if ((rx_packet.msg.arg0 == adb_client.file_remoteid) && (rx_packet.msg.arg1 == ADB_FILE_LOALID)) { + adb_send_okay(&tx_packet, rx_packet.msg.arg1); + } else { + adb_send_close(&tx_packet, 0, rx_packet.msg.arg0); + } + break; + case A_AUTH: + + break; + + default: + break; + } + } +} + +void usbd_adb_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes) +{ + if (adb_client.common_state == ADB_STATE_WRITE_MSG) { + if (tx_packet.msg.data_length) { + adb_client.common_state = ADB_STATE_WRITE_DATA; + usbd_ep_start_write(busid, adb_ep_data[ADB_IN_EP_IDX].ep_addr, tx_packet.payload, tx_packet.msg.data_length); + } else { + if (rx_packet.msg.command == A_WRTE) { + adb_client.writable = true; + if (adb_client.localid == ADB_SHELL_LOALID) { + usbd_adb_notify_shell_read(rx_packet.payload, rx_packet.msg.data_length); + } else { + } + } + adb_client.common_state = ADB_STATE_READ_MSG; + /* setup first out ep read transfer */ + usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg)); + } + } else if (adb_client.common_state == ADB_STATE_WRITE_DATA) { + adb_client.common_state = ADB_STATE_READ_MSG; + /* setup first out ep read transfer */ + usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg)); + } else if (adb_client.write_state == ADB_STATE_AWRITE_MSG) { + if (tx_packet.msg.data_length) { + adb_client.write_state = ADB_STATE_AWRITE_DATA; + usbd_ep_start_write(busid, adb_ep_data[ADB_IN_EP_IDX].ep_addr, tx_packet.payload, tx_packet.msg.data_length); + } else { + } + } else if (adb_client.write_state == ADB_STATE_AWRITE_DATA) { + usbd_adb_notify_write_done(); + } +} + +void adb_notify_handler(uint8_t busid, uint8_t event, void *arg) +{ + switch (event) { + case USBD_EVENT_INIT: + break; + case USBD_EVENT_DEINIT: + break; + case USBD_EVENT_RESET: + break; + case USBD_EVENT_CONFIGURED: + adb_client.common_state = ADB_STATE_READ_MSG; + /* setup first out ep read transfer */ + usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg)); + break; + + default: + break; + } +} + +struct usbd_interface *usbd_adb_init_intf(uint8_t busid, struct usbd_interface *intf, uint8_t in_ep, uint8_t out_ep) +{ + intf->class_interface_handler = NULL; + intf->class_endpoint_handler = NULL; + intf->vendor_handler = NULL; + intf->notify_handler = adb_notify_handler; + + adb_ep_data[ADB_OUT_EP_IDX].ep_addr = out_ep; + adb_ep_data[ADB_OUT_EP_IDX].ep_cb = usbd_adb_bulk_out; + adb_ep_data[ADB_IN_EP_IDX].ep_addr = in_ep; + adb_ep_data[ADB_IN_EP_IDX].ep_cb = usbd_adb_bulk_in; + + usbd_add_endpoint(busid, &adb_ep_data[ADB_OUT_EP_IDX]); + usbd_add_endpoint(busid, &adb_ep_data[ADB_IN_EP_IDX]); + + return intf; +} + +bool usbd_adb_can_write(void) +{ + return adb_client.writable; +} + +int usbd_abd_write(uint32_t localid, const uint8_t *data, uint32_t len) +{ + struct adb_packet *packet; + + packet = &tx_packet; + packet->msg.command = A_WRTE; + packet->msg.arg0 = localid; + packet->msg.arg1 = usbd_adb_get_remoteid(localid); + packet->msg.data_length = len; + memcpy(packet->payload, data, len); + + packet->msg.data_crc32 = adb_packet_checksum(packet); + packet->msg.magic = packet->msg.command ^ 0xffffffff; + + adb_client.write_state = ADB_STATE_AWRITE_MSG; + usbd_ep_start_write(0, adb_ep_data[ADB_IN_EP_IDX].ep_addr, (uint8_t *)&packet->msg, sizeof(struct adb_msg)); + return 0; +} + +void usbd_adb_close(uint32_t localid) +{ + adb_send_close(&tx_packet, 0, usbd_adb_get_remoteid(localid)); +} \ No newline at end of file diff --git a/class/adb/usbd_adb.h b/class/adb/usbd_adb.h new file mode 100644 index 00000000..4dbc730f --- /dev/null +++ b/class/adb/usbd_adb.h @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2024, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#ifndef USBD_ADB_H +#define USBD_ADB_H + +#include + +#define ADB_SHELL_LOALID 0x01 +#define ADB_FILE_LOALID 0x02 + +// clang-format off +#define ADB_DESCRIPTOR_INIT(bFirstInterface, in_ep, out_ep, wMaxPacketSize) \ + USB_INTERFACE_DESCRIPTOR_INIT(bFirstInterface, 0x00, 0x02, 0xff, 0x42, 0x01, 0x02), \ + USB_ENDPOINT_DESCRIPTOR_INIT(in_ep, 0x02, wMaxPacketSize, 0x00), \ + USB_ENDPOINT_DESCRIPTOR_INIT(out_ep, 0x02, wMaxPacketSize, 0x00) +// clang-format on + +#ifdef __cplusplus +extern "C" { +#endif + +struct usbd_interface *usbd_adb_init_intf(uint8_t busid, struct usbd_interface *intf, uint8_t in_ep, uint8_t out_ep); + +void usbd_adb_notify_shell_read(uint8_t *data, uint32_t len); +void usbd_adb_notify_file_read(uint8_t *data, uint32_t len); +void usbd_adb_notify_write_done(void); +bool usbd_adb_can_write(void); +int usbd_abd_write(uint32_t localid, const uint8_t *data, uint32_t len); +void usbd_adb_close(uint32_t localid); + +#ifdef __cplusplus +} +#endif + +#endif /* USBD_ADB_H */ \ No newline at end of file diff --git a/demo/adb/cherryadb.png b/demo/adb/cherryadb.png new file mode 100644 index 00000000..512586b9 Binary files /dev/null and b/demo/adb/cherryadb.png differ diff --git a/demo/adb/cherrysh_port.c b/demo/adb/cherrysh_port.c new file mode 100644 index 00000000..85971724 --- /dev/null +++ b/demo/adb/cherrysh_port.c @@ -0,0 +1,330 @@ +/* + * Copyright (c) 2024, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "FreeRTOS.h" +#include "task.h" +#include "event_groups.h" +#include "csh.h" +#include "usbd_core.h" +#include "usbd_adb.h" +#include "chry_ringbuffer.h" + +static chry_ringbuffer_t shell_rb; +static uint8_t mempool[1024]; + +#ifndef task_repl_PRIORITY +#define task_repl_PRIORITY (configMAX_PRIORITIES - 4U) +#endif + +#ifndef task_exec_PRIORITY +#define task_exec_PRIORITY (configMAX_PRIORITIES - 5U) +#endif + +static chry_shell_t csh; +static volatile bool login = false; + +static StaticTask_t task_buffer_repl; +static StaticTask_t task_buffer_exec; + +static StackType_t task_stack_repl[1024]; +static StackType_t task_stack_exec[1024]; + +static TaskHandle_t task_hdl_repl = NULL; +static TaskHandle_t task_hdl_exec = NULL; + +static EventGroupHandle_t event_hdl; +static StaticEventGroup_t event_grp; + +void usbd_adb_notify_shell_read(uint8_t *data, uint32_t len) +{ + chry_ringbuffer_write(&shell_rb, data, len); + + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xEventGroupSetBitsFromISR(event_hdl, 0x10, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +void usbd_adb_notify_write_done(void) +{ + BaseType_t xHigherPriorityTaskWoken = pdFALSE; + xEventGroupSetBitsFromISR(event_hdl, 0x20, &xHigherPriorityTaskWoken); + portYIELD_FROM_ISR(xHigherPriorityTaskWoken); +} + +static uint16_t csh_sput_cb(chry_readline_t *rl, const void *data, uint16_t size) +{ + (void)rl; + + if (!usb_device_is_configured(0)) { + return size; + } + + if (usbd_adb_can_write() && size) { + usbd_abd_write(ADB_SHELL_LOALID, data, size); + xEventGroupWaitBits(event_hdl, 0x20, pdTRUE, pdFALSE, portMAX_DELAY); + } + + return size; +} + +static uint16_t csh_sget_cb(chry_readline_t *rl, void *data, uint16_t size) +{ + (void)rl; + + return chry_ringbuffer_read(&shell_rb, data, size); +} + +static void wait_char(void) +{ + EventBits_t event; +wait: + /* In order to lock the log from being disrupted , wait for REPL task execution to complete */ + event = xEventGroupWaitBits(event_hdl, (0x10 | 0x01 | 0x04), pdTRUE, pdFALSE, portMAX_DELAY); + if ((event & 0x10) == 0) { + if (event & 0x01) { + chry_readline_erase_line(&csh.rl); + xEventGroupSetBits(event_hdl, 0x02); + } + if (event & 0x04) { + chry_readline_edit_refresh(&csh.rl); + xEventGroupSetBits(event_hdl, 0x08); + } + + goto wait; + } +} + +static void task_repl(void *param) +{ + (void)param; + int ret; + volatile uint8_t *pexec = (void *)&csh.exec; + + for (;;) { + restart: + if (login) { + goto repl; + } else { + } + + ret = csh_login(&csh); + if (ret == 0) { + login = true; + } else if (ret == 1) { + /*!< no enough char */ + wait_char(); + continue; + } else { + continue; + } + + repl: + ret = chry_shell_task_repl(&csh); + + if (ret == -1) { + /*!< error */ + goto restart; + } else if (ret == 1) { + /*!< no enough char */ + wait_char(); + } else { + /*!< restart */ + } + + /*!< check flag */ + if (*pexec == CSH_STATUS_EXEC_DONE) { + *pexec = CSH_STATUS_EXEC_IDLE; + chry_readline_auto_refresh(&csh.rl, true); + chry_readline_ignore(&csh.rl, false); + chry_readline_edit_refresh(&csh.rl); + } + + if (login == false) { + chry_readline_erase_line(&csh.rl); + csh.rl.noblock = false; + } + } +} + +static void task_exec(void *param) +{ + (void)param; + + /*!< execute shell command */ + chry_shell_task_exec(&csh); + + /*!< notify REPL task execute done */ + xEventGroupSetBits(event_hdl, 0x10); + + /*!< wait for REPL task delete */ + vTaskSuspend(NULL); +} + +int chry_shell_port_create_context(chry_shell_t *csh, int argc, const char **argv) +{ + volatile TaskHandle_t *p_task_hdl_exec = (void *)&task_hdl_exec; + (void)csh; + (void)argc; + (void)argv; + + if (*p_task_hdl_exec != NULL) { + vTaskDelete(*p_task_hdl_exec); + } + + *p_task_hdl_exec = xTaskCreateStatic(task_exec, "task_exec", 1024U, NULL, task_exec_PRIORITY, task_stack_exec, &task_buffer_exec); + return 0; +} + +void chry_shell_port_default_handler(chry_shell_t *csh, int sig) +{ + volatile uint8_t *pexec = (void *)&csh->exec; + volatile TaskHandle_t *p_task_hdl_exec = (void *)&task_hdl_exec; + + switch (sig) { + case CSH_SIGINT: + case CSH_SIGQUIT: + case CSH_SIGKILL: + case CSH_SIGTERM: + break; + default: + return; + } + + /*!< force delete task */ + if (*p_task_hdl_exec != NULL) { + vTaskDelete(task_hdl_exec); + *p_task_hdl_exec = NULL; + } + + switch (sig) { + case CSH_SIGINT: + csh->rl.sput(&csh->rl, "^SIGINT" CONFIG_CSH_NEWLINE, sizeof("^SIGINT" CONFIG_CSH_NEWLINE) - 1); + break; + case CSH_SIGQUIT: + csh->rl.sput(&csh->rl, "^SIGQUIT" CONFIG_CSH_NEWLINE, sizeof("^SIGQUIT" CONFIG_CSH_NEWLINE) - 1); + break; + case CSH_SIGKILL: + csh->rl.sput(&csh->rl, "^SIGKILL" CONFIG_CSH_NEWLINE, sizeof("^SIGKILL" CONFIG_CSH_NEWLINE) - 1); + break; + case CSH_SIGTERM: + csh->rl.sput(&csh->rl, "^SIGTERM" CONFIG_CSH_NEWLINE, sizeof("^SIGTERM" CONFIG_CSH_NEWLINE) - 1); + break; + default: + return; + } + + *pexec = CSH_STATUS_EXEC_IDLE; + chry_readline_auto_refresh(&csh->rl, true); + chry_readline_ignore(&csh->rl, false); + chry_readline_edit_refresh(&csh->rl); +} + +int shell_init(bool need_login) +{ + chry_shell_init_t csh_init; + + if (chry_ringbuffer_init(&shell_rb, mempool, sizeof(mempool))) { + return -1; + } + + if (need_login) { + login = false; + } else { + login = true; + } + + /*!< I/O callback */ + csh_init.sput = csh_sput_cb; + csh_init.sget = csh_sget_cb; + +#if defined(CONFIG_CSH_SYMTAB) && CONFIG_CSH_SYMTAB + extern const int __fsymtab_start; + extern const int __fsymtab_end; + extern const int __vsymtab_start; + extern const int __vsymtab_end; + + /*!< get table from ld symbol */ + csh_init.command_table_beg = &__fsymtab_start; + csh_init.command_table_end = &__fsymtab_end; + csh_init.variable_table_beg = &__vsymtab_start; + csh_init.variable_table_end = &__vsymtab_end; +#endif + +#if defined(CONFIG_CSH_PROMPTEDIT) && CONFIG_CSH_PROMPTEDIT + static char csh_prompt_buffer[128]; + + /*!< set prompt buffer */ + csh_init.prompt_buffer = csh_prompt_buffer; + csh_init.prompt_buffer_size = sizeof(csh_prompt_buffer); +#endif + +#if defined(CONFIG_CSH_HISTORY) && CONFIG_CSH_HISTORY + static char csh_history_buffer[128]; + + /*!< set history buffer */ + csh_init.history_buffer = csh_history_buffer; + csh_init.history_buffer_size = sizeof(csh_history_buffer); +#endif + +#if defined(CONFIG_CSH_LNBUFF_STATIC) && CONFIG_CSH_LNBUFF_STATIC + static char csh_line_buffer[128]; + + /*!< set linebuffer */ + csh_init.line_buffer = csh_line_buffer; + csh_init.line_buffer_size = sizeof(csh_line_buffer); +#endif + + csh_init.uid = 0; + csh_init.user[0] = "cherry"; + + /*!< The port hash function is required, + and the strcmp attribute is used weakly by default, + int chry_shell_port_hash_strcmp(const char *hash, const char *str); */ + csh_init.hash[0] = "12345678"; /*!< If there is no password, set to NULL */ + csh_init.host = "cherryadb"; + csh_init.user_data = NULL; + + int ret = chry_shell_init(&csh, &csh_init); + if (ret) { + return -1; + } + + task_hdl_exec = NULL; + event_hdl = xEventGroupCreateStatic(&event_grp); + task_hdl_repl = xTaskCreateStatic(task_repl, "task_repl", 1024U, NULL, task_repl_PRIORITY, task_stack_repl, &task_buffer_repl); + + return 0; +} + +void shell_lock(void) +{ + xEventGroupSetBits(event_hdl, 0x01); + xEventGroupWaitBits(event_hdl, 0x02, pdTRUE, pdTRUE, portMAX_DELAY); +} + +void shell_unlock(void) +{ + xEventGroupSetBits(event_hdl, 0x04); + xEventGroupWaitBits(event_hdl, 0x08, pdTRUE, pdTRUE, portMAX_DELAY); +} + +static int csh_exit(int argc, char **argv) +{ + (void)argc; + (void)argv; + + usbd_adb_close(ADB_SHELL_LOALID); + + return 0; +} +CSH_SCMD_EXPORT_ALIAS(csh_exit, exit, ); + +#define __ENV_PATH "/sbin:/bin" +const char ENV_PATH[] = __ENV_PATH; +CSH_RVAR_EXPORT(ENV_PATH, PATH, sizeof(__ENV_PATH)); + +#define __ENV_ZERO "" +const char ENV_ZERO[] = __ENV_ZERO; +CSH_RVAR_EXPORT(ENV_ZERO, ZERO, sizeof(__ENV_ZERO)); diff --git a/demo/adb/usbd_adb_template.c b/demo/adb/usbd_adb_template.c new file mode 100644 index 00000000..0c367d8a --- /dev/null +++ b/demo/adb/usbd_adb_template.c @@ -0,0 +1,228 @@ +/* + * Copyright (c) 2024, sakumisu + * + * SPDX-License-Identifier: Apache-2.0 + */ +#include "usbd_core.h" +#include "usbd_adb.h" + +/*!< endpoint address */ +#define WINUSB_IN_EP 0x81 +#define WINUSB_OUT_EP 0x02 + +#define USBD_VID 0xFFFF +#define USBD_PID 0xFFFF +#define USBD_MAX_POWER 100 +#define USBD_LANGID_STRING 1033 + +/*!< config descriptor size */ +#define USB_CONFIG_SIZE (9 + 9 + 7 + 7) + +#ifdef CONFIG_USB_HS +#define WINUSB_MAX_MPS 512 +#else +#define WINUSB_MAX_MPS 64 +#endif + +#define WCID_VENDOR_CODE 0x17 +#define ADB_INTF_NUM 0 + +__ALIGN_BEGIN const uint8_t WCID_StringDescriptor_MSOS[18] __ALIGN_END = { + /////////////////////////////////////// + /// MS OS string descriptor + /////////////////////////////////////// + 0x12, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + /* MSFT100 */ + 'M', 0x00, 'S', 0x00, 'F', 0x00, 'T', 0x00, /* wcChar_7 */ + '1', 0x00, '0', 0x00, '0', 0x00, /* wcChar_7 */ + WCID_VENDOR_CODE, /* bVendorCode */ + 0x00, /* bReserved */ +}; + +__ALIGN_BEGIN const uint8_t WINUSB_WCIDDescriptor[40] __ALIGN_END = { + /////////////////////////////////////// + /// WCID descriptor + /////////////////////////////////////// + 0x28, 0x00, 0x00, 0x00, /* dwLength */ + 0x00, 0x01, /* bcdVersion */ + 0x04, 0x00, /* wIndex */ + 0x01, /* bCount */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* bReserved_7 */ + + /////////////////////////////////////// + /// WCID function descriptor + /////////////////////////////////////// + ADB_INTF_NUM, /* bFirstInterfaceNumber */ + 0x01, /* bReserved */ + /* Compatible ID */ + 'W', 'I', 'N', 'U', 'S', 'B', 0x00, 0x00, /* cCID_8: WINUSB */ + /* */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* cSubCID_8 */ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* bReserved_6 */ +}; + +__ALIGN_BEGIN const uint8_t WINUSB_IF0_WCIDProperties[142] __ALIGN_END = { + /////////////////////////////////////// + /// WCID property descriptor + /////////////////////////////////////// + 0x8e, 0x00, 0x00, 0x00, /* dwLength */ + 0x00, 0x01, /* bcdVersion */ + 0x05, 0x00, /* wIndex */ + 0x01, 0x00, /* wCount */ + + /////////////////////////////////////// + /// registry propter descriptor + /////////////////////////////////////// + 0x84, 0x00, 0x00, 0x00, /* dwSize */ + 0x01, 0x00, 0x00, 0x00, /* dwPropertyDataType */ + 0x28, 0x00, /* wPropertyNameLength */ + /* DeviceInterfaceGUID */ + 'D', 0x00, 'e', 0x00, 'v', 0x00, 'i', 0x00, /* wcName_20 */ + 'c', 0x00, 'e', 0x00, 'I', 0x00, 'n', 0x00, /* wcName_20 */ + 't', 0x00, 'e', 0x00, 'r', 0x00, 'f', 0x00, /* wcName_20 */ + 'a', 0x00, 'c', 0x00, 'e', 0x00, 'G', 0x00, /* wcName_20 */ + 'U', 0x00, 'I', 0x00, 'D', 0x00, 0x00, 0x00, /* wcName_20 */ + 0x4e, 0x00, 0x00, 0x00, /* dwPropertyDataLength */ + /* {1D4B2365-4749-48EA-B38A-7C6FDDDD7E26} */ + '{', 0x00, '1', 0x00, 'D', 0x00, '4', 0x00, /* wcData_39 */ + 'B', 0x00, '2', 0x00, '3', 0x00, '6', 0x00, /* wcData_39 */ + '5', 0x00, '-', 0x00, '4', 0x00, '7', 0x00, /* wcData_39 */ + '4', 0x00, '9', 0x00, '-', 0x00, '4', 0x00, /* wcData_39 */ + '8', 0x00, 'E', 0x00, 'A', 0x00, '-', 0x00, /* wcData_39 */ + 'B', 0x00, '3', 0x00, '8', 0x00, 'A', 0x00, /* wcData_39 */ + '-', 0x00, '7', 0x00, 'C', 0x00, '6', 0x00, /* wcData_39 */ + 'F', 0x00, 'D', 0x00, 'D', 0x00, 'D', 0x00, /* wcData_39 */ + 'D', 0x00, '7', 0x00, 'E', 0x00, '2', 0x00, /* wcData_39 */ + '6', 0x00, '}', 0x00, 0x00, 0x00, /* wcData_39 */ +}; + +const uint8_t *WINUSB_IFx_WCIDProperties[] = { + WINUSB_IF0_WCIDProperties, +}; + +struct usb_msosv1_descriptor msosv1_desc = { + .string = WCID_StringDescriptor_MSOS, + .vendor_code = WCID_VENDOR_CODE, + .compat_id = WINUSB_WCIDDescriptor, + .comp_id_property = WINUSB_IFx_WCIDProperties, +}; + +/*!< global descriptor */ +static const uint8_t adb_descriptor[] = { + USB_DEVICE_DESCRIPTOR_INIT(USB_2_0, 0x00, 0x00, 0x00, USBD_VID, USBD_PID, 0x0100, 0x01), + USB_CONFIG_DESCRIPTOR_INIT(USB_CONFIG_SIZE, 0x01, 0x01, USB_CONFIG_BUS_POWERED, USBD_MAX_POWER), + ADB_DESCRIPTOR_INIT(ADB_INTF_NUM, WINUSB_IN_EP, WINUSB_OUT_EP, WINUSB_MAX_MPS), + /////////////////////////////////////// + /// string0 descriptor + /////////////////////////////////////// + USB_LANGID_INIT(USBD_LANGID_STRING), + /////////////////////////////////////// + /// string1 descriptor + /////////////////////////////////////// + 0x14, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'U', 0x00, /* wcChar6 */ + 'S', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + /////////////////////////////////////// + /// string2 descriptor + /////////////////////////////////////// + 0x14, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'A', 0x00, /* wcChar6 */ + 'D', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + /////////////////////////////////////// + /// string3 descriptor + /////////////////////////////////////// + 0x1C, /* bLength */ + USB_DESCRIPTOR_TYPE_STRING, /* bDescriptorType */ + 'C', 0x00, /* wcChar0 */ + 'h', 0x00, /* wcChar1 */ + 'e', 0x00, /* wcChar2 */ + 'r', 0x00, /* wcChar3 */ + 'r', 0x00, /* wcChar4 */ + 'y', 0x00, /* wcChar5 */ + 'A', 0x00, /* wcChar6 */ + 'D', 0x00, /* wcChar7 */ + 'B', 0x00, /* wcChar8 */ + '2', 0x00, /* wcChar9 */ + '0', 0x00, /* wcChar10 */ + '2', 0x00, /* wcChar11 */ + '4', 0x00, /* wcChar12 */ +#ifdef CONFIG_USB_HS + /////////////////////////////////////// + /// device qualifier descriptor + /////////////////////////////////////// + 0x0a, + USB_DESCRIPTOR_TYPE_DEVICE_QUALIFIER, + 0x00, + 0x02, + 0x02, + 0x02, + 0x01, + 0x40, + 0x01, + 0x00, +#endif + 0x00 +}; + +static void usbd_event_handler(uint8_t busid, uint8_t event) +{ + switch (event) { + case USBD_EVENT_RESET: + break; + case USBD_EVENT_CONNECTED: + break; + case USBD_EVENT_DISCONNECTED: + break; + case USBD_EVENT_RESUME: + break; + case USBD_EVENT_SUSPEND: + break; + case USBD_EVENT_CONFIGURED: + + break; + case USBD_EVENT_SET_REMOTE_WAKEUP: + break; + case USBD_EVENT_CLR_REMOTE_WAKEUP: + break; + + default: + break; + } +} + +static struct usbd_interface intf0; + +extern int shell_init(bool need_login); +void cherryadb_init(uint8_t busid, uint32_t reg_base) +{ + /* default password is : 12345678 */ + /* shell_init() must be called in-task */ + if (0 != shell_init(false)) { + /* shell failed to be initialized */ + printf("Failed to initialize shell\r\n"); + for (;;) { + ; + } + } + + usbd_desc_register(busid, adb_descriptor); + usbd_add_interface(busid, usbd_adb_init_intf(busid, &intf0, WINUSB_IN_EP, WINUSB_OUT_EP)); + usbd_initialize(busid, reg_base, usbd_event_handler); +} \ No newline at end of file