1 /*
2 * Copyright (c) 2024, sakumisu
3 *
4 * SPDX-License-Identifier: Apache-2.0
5 */
6 #include "usbd_core.h"
7 #include "usbd_adb.h"
8
9 #define ADB_OUT_EP_IDX 0
10 #define ADB_IN_EP_IDX 1
11
12 #define ADB_STATE_READ_MSG 0
13 #define ADB_STATE_READ_DATA 1
14 #define ADB_STATE_WRITE_MSG 2
15 #define ADB_STATE_WRITE_DATA 3
16 #define ADB_STATE_AWRITE_MSG 4
17 #define ADB_STATE_AWRITE_DATA 5
18
19 #define MAX_PAYLOAD_V1 (4 * 1024)
20 #define MAX_PAYLOAD_V2 (256 * 1024)
21 #define MAX_PAYLOAD MAX_PAYLOAD_V1
22 #define A_VERSION 0x01000000
23
24 #define A_SYNC 0x434e5953
25 #define A_CNXN 0x4e584e43
26 #define A_OPEN 0x4e45504f
27 #define A_OKAY 0x59414b4f
28 #define A_CLSE 0x45534c43
29 #define A_WRTE 0x45545257
30 #define A_AUTH 0x48545541
31
32 struct adb_msg {
33 uint32_t command; /* command identifier constant (A_CNXN, ...) */
34 uint32_t arg0; /* first argument */
35 uint32_t arg1; /* second argument */
36 uint32_t data_length; /* length of payload (0 is allowed) */
37 uint32_t data_crc32; /* crc32 of data payload */
38 uint32_t magic; /* command ^ 0xffffffff */
39 };
40
41 struct adb_packet {
42 USB_MEM_ALIGNX struct adb_msg msg;
43 USB_MEM_ALIGNX uint8_t payload[USB_ALIGN_UP(MAX_PAYLOAD, CONFIG_USB_ALIGN_SIZE)];
44 };
45
46 struct usbd_adb {
47 uint8_t state;
48 uint8_t common_state;
49 uint8_t write_state;
50 bool writable;
51 uint32_t localid;
52 uint32_t shell_remoteid;
53 uint32_t file_remoteid;
54 } adb_client;
55
56 static struct usbd_endpoint adb_ep_data[2];
57
58 USB_NOCACHE_RAM_SECTION struct adb_packet tx_packet;
59 USB_NOCACHE_RAM_SECTION struct adb_packet rx_packet;
60
adb_packet_checksum(struct adb_packet * packet)61 static inline uint32_t adb_packet_checksum(struct adb_packet *packet)
62 {
63 uint32_t sum = 0;
64 uint32_t i;
65
66 for (i = 0; i < packet->msg.data_length; ++i) {
67 sum += (uint32_t)(packet->payload[i]);
68 }
69
70 return sum;
71 }
72
usbd_adb_get_remoteid(uint32_t localid)73 static uint32_t usbd_adb_get_remoteid(uint32_t localid)
74 {
75 if (localid == ADB_SHELL_LOALID) {
76 return adb_client.shell_remoteid;
77 } else {
78 return adb_client.file_remoteid;
79 }
80 }
81
adb_send_msg(struct adb_packet * packet)82 static void adb_send_msg(struct adb_packet *packet)
83 {
84 adb_client.common_state = ADB_STATE_WRITE_MSG;
85
86 packet->msg.data_crc32 = adb_packet_checksum(packet);
87 packet->msg.magic = packet->msg.command ^ 0xffffffff;
88
89 usbd_ep_start_write(0, adb_ep_data[ADB_IN_EP_IDX].ep_addr, (uint8_t *)&packet->msg, sizeof(struct adb_msg));
90 }
91
adb_send_okay(struct adb_packet * packet,uint32_t localid)92 static void adb_send_okay(struct adb_packet *packet, uint32_t localid)
93 {
94 packet->msg.command = A_OKAY;
95 packet->msg.arg0 = localid;
96 packet->msg.arg1 = usbd_adb_get_remoteid(localid);
97 packet->msg.data_length = 0;
98
99 adb_send_msg(&tx_packet);
100 }
101
adb_send_close(struct adb_packet * packet,uint32_t localid,uint32_t remoteid)102 static void adb_send_close(struct adb_packet *packet, uint32_t localid, uint32_t remoteid)
103 {
104 packet->msg.command = A_CLSE;
105 packet->msg.arg0 = localid;
106 packet->msg.arg1 = remoteid;
107 packet->msg.data_length = 0;
108
109 adb_send_msg(&tx_packet);
110 }
111
usbd_adb_bulk_out(uint8_t busid,uint8_t ep,uint32_t nbytes)112 void usbd_adb_bulk_out(uint8_t busid, uint8_t ep, uint32_t nbytes)
113 {
114 (void)ep;
115
116 if (adb_client.common_state == ADB_STATE_READ_MSG) {
117 if (nbytes != sizeof(struct adb_msg)) {
118 USB_LOG_ERR("invalid adb msg size:%d\r\n", (unsigned int)nbytes);
119 return;
120 }
121
122 USB_LOG_DBG("command:%x arg0:%x arg1:%x len:%d\r\n",
123 rx_packet.msg.command,
124 rx_packet.msg.arg0,
125 rx_packet.msg.arg1,
126 rx_packet.msg.data_length);
127
128 if (rx_packet.msg.data_length) {
129 /* setup next out ep read transfer */
130 adb_client.common_state = ADB_STATE_READ_DATA;
131 usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, rx_packet.payload, rx_packet.msg.data_length);
132 } else {
133 if (rx_packet.msg.command == A_CLSE) {
134 adb_client.writable = false;
135 usbd_adb_notify_write_done();
136 USB_LOG_INFO("Close remoteid:%x\r\n", rx_packet.msg.arg0);
137 }
138 adb_client.common_state = ADB_STATE_READ_MSG;
139 /* setup first out ep read transfer */
140 usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
141 }
142 } else if (adb_client.common_state == ADB_STATE_READ_DATA) {
143 switch (rx_packet.msg.command) {
144 case A_SYNC:
145
146 break;
147 case A_CNXN: /* CONNECT(version, maxdata, "system-id-string") */
148 char *support_feature = "device::"
149 "ro.product.name=cherryadb;"
150 "ro.product.model=cherrysh;"
151 "ro.product.device=cherryadb;"
152 "features=cmd,shell_v1";
153
154 tx_packet.msg.command = A_CNXN;
155 tx_packet.msg.arg0 = A_VERSION;
156 tx_packet.msg.arg1 = MAX_PAYLOAD;
157 tx_packet.msg.data_length = strlen(support_feature);
158 memcpy(tx_packet.payload, support_feature, strlen(support_feature));
159
160 adb_send_msg(&tx_packet);
161
162 adb_client.writable = false;
163 break;
164 case A_OPEN: /* OPEN(local-id, 0, "destination") */
165 rx_packet.payload[rx_packet.msg.data_length] = '\0';
166
167 if (strncmp((const char *)rx_packet.payload, "shell:", 6) == 0) {
168 adb_client.localid = ADB_SHELL_LOALID;
169 adb_client.shell_remoteid = rx_packet.msg.arg0;
170 adb_send_okay(&tx_packet, ADB_SHELL_LOALID);
171
172 USB_LOG_INFO("Open shell service, remoteid:%x\r\n", rx_packet.msg.arg0);
173 } else if (strncmp((const char *)rx_packet.payload, "sync:", 5) == 0) {
174 adb_client.localid = ADB_FILE_LOALID;
175 adb_client.file_remoteid = rx_packet.msg.arg0;
176 adb_send_okay(&tx_packet, ADB_FILE_LOALID);
177 USB_LOG_INFO("Open file service, remoteid:%x\r\n", rx_packet.msg.arg0);
178 }
179 break;
180 case A_OKAY:
181
182 break;
183 case A_CLSE:
184
185 break;
186 case A_WRTE: /* WRITE(local-id, remote-id, "data") */
187 if ((rx_packet.msg.arg0 == adb_client.shell_remoteid) && (rx_packet.msg.arg1 == ADB_SHELL_LOALID)) {
188 adb_send_okay(&tx_packet, rx_packet.msg.arg1);
189 } else if ((rx_packet.msg.arg0 == adb_client.file_remoteid) && (rx_packet.msg.arg1 == ADB_FILE_LOALID)) {
190 adb_send_okay(&tx_packet, rx_packet.msg.arg1);
191 } else {
192 adb_send_close(&tx_packet, 0, rx_packet.msg.arg0);
193 }
194 break;
195 case A_AUTH:
196
197 break;
198
199 default:
200 break;
201 }
202 }
203 }
204
usbd_adb_bulk_in(uint8_t busid,uint8_t ep,uint32_t nbytes)205 void usbd_adb_bulk_in(uint8_t busid, uint8_t ep, uint32_t nbytes)
206 {
207 (void)ep;
208 (void)nbytes;
209
210 if (adb_client.common_state == ADB_STATE_WRITE_MSG) {
211 if (tx_packet.msg.data_length) {
212 adb_client.common_state = ADB_STATE_WRITE_DATA;
213 usbd_ep_start_write(busid, adb_ep_data[ADB_IN_EP_IDX].ep_addr, tx_packet.payload, tx_packet.msg.data_length);
214 } else {
215 if (rx_packet.msg.command == A_WRTE) {
216 adb_client.writable = true;
217 if (adb_client.localid == ADB_SHELL_LOALID) {
218 usbd_adb_notify_shell_read(rx_packet.payload, rx_packet.msg.data_length);
219 } else {
220 }
221 }
222 adb_client.common_state = ADB_STATE_READ_MSG;
223 /* setup first out ep read transfer */
224 usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
225 }
226 } else if (adb_client.common_state == ADB_STATE_WRITE_DATA) {
227 adb_client.common_state = ADB_STATE_READ_MSG;
228 /* setup first out ep read transfer */
229 usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
230 } else if (adb_client.write_state == ADB_STATE_AWRITE_MSG) {
231 if (tx_packet.msg.data_length) {
232 adb_client.write_state = ADB_STATE_AWRITE_DATA;
233 usbd_ep_start_write(busid, adb_ep_data[ADB_IN_EP_IDX].ep_addr, tx_packet.payload, tx_packet.msg.data_length);
234 } else {
235 }
236 } else if (adb_client.write_state == ADB_STATE_AWRITE_DATA) {
237 usbd_adb_notify_write_done();
238 }
239 }
240
adb_notify_handler(uint8_t busid,uint8_t event,void * arg)241 void adb_notify_handler(uint8_t busid, uint8_t event, void *arg)
242 {
243 (void)arg;
244
245 switch (event) {
246 case USBD_EVENT_INIT:
247 break;
248 case USBD_EVENT_DEINIT:
249 break;
250 case USBD_EVENT_RESET:
251 break;
252 case USBD_EVENT_CONFIGURED:
253 adb_client.common_state = ADB_STATE_READ_MSG;
254 /* setup first out ep read transfer */
255 usbd_ep_start_read(busid, adb_ep_data[ADB_OUT_EP_IDX].ep_addr, (uint8_t *)&rx_packet.msg, sizeof(struct adb_msg));
256 break;
257
258 default:
259 break;
260 }
261 }
262
usbd_adb_init_intf(uint8_t busid,struct usbd_interface * intf,uint8_t in_ep,uint8_t out_ep)263 struct usbd_interface *usbd_adb_init_intf(uint8_t busid, struct usbd_interface *intf, uint8_t in_ep, uint8_t out_ep)
264 {
265 (void)busid;
266
267 intf->class_interface_handler = NULL;
268 intf->class_endpoint_handler = NULL;
269 intf->vendor_handler = NULL;
270 intf->notify_handler = adb_notify_handler;
271
272 adb_ep_data[ADB_OUT_EP_IDX].ep_addr = out_ep;
273 adb_ep_data[ADB_OUT_EP_IDX].ep_cb = usbd_adb_bulk_out;
274 adb_ep_data[ADB_IN_EP_IDX].ep_addr = in_ep;
275 adb_ep_data[ADB_IN_EP_IDX].ep_cb = usbd_adb_bulk_in;
276
277 usbd_add_endpoint(busid, &adb_ep_data[ADB_OUT_EP_IDX]);
278 usbd_add_endpoint(busid, &adb_ep_data[ADB_IN_EP_IDX]);
279
280 return intf;
281 }
282
usbd_adb_can_write(void)283 bool usbd_adb_can_write(void)
284 {
285 return adb_client.writable;
286 }
287
usbd_abd_write(uint32_t localid,const uint8_t * data,uint32_t len)288 int usbd_abd_write(uint32_t localid, const uint8_t *data, uint32_t len)
289 {
290 struct adb_packet *packet;
291
292 packet = &tx_packet;
293 packet->msg.command = A_WRTE;
294 packet->msg.arg0 = localid;
295 packet->msg.arg1 = usbd_adb_get_remoteid(localid);
296 packet->msg.data_length = len;
297 memcpy(packet->payload, data, len);
298
299 packet->msg.data_crc32 = adb_packet_checksum(packet);
300 packet->msg.magic = packet->msg.command ^ 0xffffffff;
301
302 adb_client.write_state = ADB_STATE_AWRITE_MSG;
303 usbd_ep_start_write(0, adb_ep_data[ADB_IN_EP_IDX].ep_addr, (uint8_t *)&packet->msg, sizeof(struct adb_msg));
304 return 0;
305 }
306
usbd_adb_close(uint32_t localid)307 void usbd_adb_close(uint32_t localid)
308 {
309 adb_send_close(&tx_packet, 0, usbd_adb_get_remoteid(localid));
310 }