mirror of
https://github.com/RT-Thread/rt-thread.git
synced 2025-01-27 01:27:40 +08:00
310 lines
10 KiB
C
310 lines
10 KiB
C
/*
|
|
* 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;
|
|
uint32_t 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)
|
|
{
|
|
(void)ep;
|
|
|
|
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)
|
|
{
|
|
(void)ep;
|
|
(void)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)
|
|
{
|
|
(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)
|
|
{
|
|
(void)busid;
|
|
|
|
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));
|
|
} |