blob: ca131f06e0529d2c23b47a331ba031a2b4a00503 [file] [log] [blame]
Urja Rannikko0870b022016-01-31 22:10:29 +00001/*
2 * This file is part of the flashrom project.
3 *
4 * Copyright (C) 2011 asbokid <ballymunboy@gmail.com>
5 * Copyright (C) 2014 Pluto Yang <yangyj.ee@gmail.com>
6 * Copyright (C) 2015-2016 Stefan Tauner
7 * Copyright (C) 2015 Urja Rannikko <urjaman@gmail.com>
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
Urja Rannikko0870b022016-01-31 22:10:29 +000018 */
19
20#include <string.h>
21#include <libusb.h>
22#include "flash.h"
23#include "programmer.h"
24
25/* LIBUSB_CALL ensures the right calling conventions on libusb callbacks.
26 * However, the macro is not defined everywhere. m(
27 */
28#ifndef LIBUSB_CALL
29#define LIBUSB_CALL
30#endif
31
32#define USB_TIMEOUT 1000 /* 1000 ms is plenty and we have no backup strategy anyway. */
33#define WRITE_EP 0x02
34#define READ_EP 0x82
35
36#define CH341_PACKET_LENGTH 0x20
37#define CH341_MAX_PACKETS 256
38#define CH341_MAX_PACKET_LEN (CH341_PACKET_LENGTH * CH341_MAX_PACKETS)
39
40#define CH341A_CMD_SET_OUTPUT 0xA1
41#define CH341A_CMD_IO_ADDR 0xA2
42#define CH341A_CMD_PRINT_OUT 0xA3
43#define CH341A_CMD_SPI_STREAM 0xA8
44#define CH341A_CMD_SIO_STREAM 0xA9
45#define CH341A_CMD_I2C_STREAM 0xAA
46#define CH341A_CMD_UIO_STREAM 0xAB
47
48#define CH341A_CMD_I2C_STM_START 0x74
49#define CH341A_CMD_I2C_STM_STOP 0x75
50#define CH341A_CMD_I2C_STM_OUT 0x80
51#define CH341A_CMD_I2C_STM_IN 0xC0
52#define CH341A_CMD_I2C_STM_MAX ( min( 0x3F, CH341_PACKET_LENGTH ) )
53#define CH341A_CMD_I2C_STM_SET 0x60 // bit 2: SPI with two data pairs D5,D4=out, D7,D6=in
54#define CH341A_CMD_I2C_STM_US 0x40
55#define CH341A_CMD_I2C_STM_MS 0x50
56#define CH341A_CMD_I2C_STM_DLY 0x0F
57#define CH341A_CMD_I2C_STM_END 0x00
58
59#define CH341A_CMD_UIO_STM_IN 0x00
60#define CH341A_CMD_UIO_STM_DIR 0x40
61#define CH341A_CMD_UIO_STM_OUT 0x80
62#define CH341A_CMD_UIO_STM_US 0xC0
63#define CH341A_CMD_UIO_STM_END 0x20
64
65#define CH341A_STM_I2C_20K 0x00
66#define CH341A_STM_I2C_100K 0x01
67#define CH341A_STM_I2C_400K 0x02
68#define CH341A_STM_I2C_750K 0x03
69#define CH341A_STM_SPI_DBL 0x04
70
71
72/* Number of parallel IN transfers. 32 seems to produce the most stable throughput on Windows. */
73#define USB_IN_TRANSFERS 32
74
75/* We need to use many queued IN transfers for any resemblance of performance (especially on Windows)
76 * because USB spec says that transfers end on non-full packets and the device sends the 31 reply
77 * data bytes to each 32-byte packet with command + 31 bytes of data... */
78static struct libusb_transfer *transfer_out = NULL;
79static struct libusb_transfer *transfer_ins[USB_IN_TRANSFERS] = {0};
80
81/* Accumulate delays to be plucked between CS deassertion and CS assertions. */
82static unsigned int stored_delay_us = 0;
83
84static struct libusb_device_handle *handle = NULL;
85
Thomas Heijligencc853d82021-05-04 15:32:17 +020086static const struct dev_entry devs_ch341a_spi[] = {
Urja Rannikko0870b022016-01-31 22:10:29 +000087 {0x1A86, 0x5512, OK, "Winchiphead (WCH)", "CH341A"},
88
89 {0},
90};
91
92enum trans_state {TRANS_ACTIVE = -2, TRANS_ERR = -1, TRANS_IDLE = 0};
93
94static void print_hex(const void *buf, size_t len)
95{
96 size_t i;
97 for (i = 0; i < len; i++) {
98 msg_pspew(" %02x", ((uint8_t *)buf)[i]);
99 if (i % CH341_PACKET_LENGTH == CH341_PACKET_LENGTH - 1)
100 msg_pspew("\n");
101 }
102}
103
104static void cb_common(const char *func, struct libusb_transfer *transfer)
105{
106 int *transfer_cnt = (int*)transfer->user_data;
107
108 if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
109 /* Silently ACK and exit. */
110 *transfer_cnt = TRANS_IDLE;
111 return;
112 }
113
114 if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
115 msg_perr("\n%s: error: %s\n", func, libusb_error_name(transfer->status));
116 *transfer_cnt = TRANS_ERR;
117 } else {
118 *transfer_cnt = transfer->actual_length;
119 }
120}
121
122/* callback for bulk out async transfer */
123static void LIBUSB_CALL cb_out(struct libusb_transfer *transfer)
124{
125 cb_common(__func__, transfer);
126}
127
128/* callback for bulk in async transfer */
129static void LIBUSB_CALL cb_in(struct libusb_transfer *transfer)
130{
131 cb_common(__func__, transfer);
132}
133
134static int32_t usb_transfer(const char *func, unsigned int writecnt, unsigned int readcnt, const uint8_t *writearr, uint8_t *readarr)
135{
136 if (handle == NULL)
137 return -1;
138
139 int state_out = TRANS_IDLE;
140 transfer_out->buffer = (uint8_t*)writearr;
141 transfer_out->length = writecnt;
142 transfer_out->user_data = &state_out;
143
144 /* Schedule write first */
145 if (writecnt > 0) {
146 state_out = TRANS_ACTIVE;
147 int ret = libusb_submit_transfer(transfer_out);
148 if (ret) {
149 msg_perr("%s: failed to submit OUT transfer: %s\n", func, libusb_error_name(ret));
150 state_out = TRANS_ERR;
151 goto err;
152 }
153 }
154
155 /* Handle all asynchronous packets as long as we have stuff to write or read. The write(s) simply need
156 * to complete but we need to scheduling reads as long as we are not done. */
157 unsigned int free_idx = 0; /* The IN transfer we expect to be free next. */
158 unsigned int in_idx = 0; /* The IN transfer we expect to be completed next. */
159 unsigned int in_done = 0;
160 unsigned int in_active = 0;
161 unsigned int out_done = 0;
162 uint8_t *in_buf = readarr;
163 int state_in[USB_IN_TRANSFERS] = {0};
164 do {
165 /* Schedule new reads as long as there are free transfers and unscheduled bytes to read. */
166 while ((in_done + in_active) < readcnt && state_in[free_idx] == TRANS_IDLE) {
167 unsigned int cur_todo = min(CH341_PACKET_LENGTH - 1, readcnt - in_done - in_active);
168 transfer_ins[free_idx]->length = cur_todo;
169 transfer_ins[free_idx]->buffer = in_buf;
170 transfer_ins[free_idx]->user_data = &state_in[free_idx];
171 int ret = libusb_submit_transfer(transfer_ins[free_idx]);
172 if (ret) {
173 state_in[free_idx] = TRANS_ERR;
174 msg_perr("%s: failed to submit IN transfer: %s\n",
175 func, libusb_error_name(ret));
176 goto err;
177 }
178 in_buf += cur_todo;
179 in_active += cur_todo;
180 state_in[free_idx] = TRANS_ACTIVE;
181 free_idx = (free_idx + 1) % USB_IN_TRANSFERS; /* Increment (and wrap around). */
182 }
183
184 /* Actually get some work done. */
185 libusb_handle_events_timeout(NULL, &(struct timeval){1, 0});
186
187 /* Check for the write */
188 if (out_done < writecnt) {
189 if (state_out == TRANS_ERR) {
190 goto err;
191 } else if (state_out > 0) {
192 out_done += state_out;
193 state_out = TRANS_IDLE;
194 }
195 }
196 /* Check for completed transfers. */
197 while (state_in[in_idx] != TRANS_IDLE && state_in[in_idx] != TRANS_ACTIVE) {
198 if (state_in[in_idx] == TRANS_ERR) {
199 goto err;
200 }
201 /* If a transfer is done, record the number of bytes read and reuse it later. */
202 in_done += state_in[in_idx];
203 in_active -= state_in[in_idx];
204 state_in[in_idx] = TRANS_IDLE;
205 in_idx = (in_idx + 1) % USB_IN_TRANSFERS; /* Increment (and wrap around). */
206 }
207 } while ((out_done < writecnt) || (in_done < readcnt));
208
209 if (out_done > 0) {
210 msg_pspew("Wrote %d bytes:\n", out_done);
211 print_hex(writearr, out_done);
212 msg_pspew("\n\n");
213 }
214 if (in_done > 0) {
215 msg_pspew("Read %d bytes:\n", in_done);
216 print_hex(readarr, in_done);
217 msg_pspew("\n\n");
218 }
219 return 0;
220err:
221 /* Clean up on errors. */
222 msg_perr("%s: Failed to %s %d bytes\n", func, (state_out == TRANS_ERR) ? "write" : "read",
223 (state_out == TRANS_ERR) ? writecnt : readcnt);
224 /* First, we must cancel any ongoing requests and wait for them to be canceled. */
225 if ((writecnt > 0) && (state_out == TRANS_ACTIVE)) {
226 if (libusb_cancel_transfer(transfer_out) != 0)
227 state_out = TRANS_ERR;
228 }
229 if (readcnt > 0) {
230 unsigned int i;
231 for (i = 0; i < USB_IN_TRANSFERS; i++) {
232 if (state_in[i] == TRANS_ACTIVE)
233 if (libusb_cancel_transfer(transfer_ins[i]) != 0)
234 state_in[i] = TRANS_ERR;
235 }
236 }
237
238 /* Wait for cancellations to complete. */
239 while (1) {
240 bool finished = true;
241 if ((writecnt > 0) && (state_out == TRANS_ACTIVE))
242 finished = false;
243 if (readcnt > 0) {
244 unsigned int i;
245 for (i = 0; i < USB_IN_TRANSFERS; i++) {
246 if (state_in[i] == TRANS_ACTIVE)
247 finished = false;
248 }
249 }
250 if (finished)
251 break;
252 libusb_handle_events_timeout(NULL, &(struct timeval){1, 0});
253 }
254 return -1;
255}
256
257/* Set the I2C bus speed (speed(b1b0): 0 = 20kHz; 1 = 100kHz, 2 = 400kHz, 3 = 750kHz).
258 * Set the SPI bus data width (speed(b2): 0 = Single, 1 = Double). */
259static int32_t config_stream(uint32_t speed)
260{
261 if (handle == NULL)
262 return -1;
263
264 uint8_t buf[] = {
265 CH341A_CMD_I2C_STREAM,
266 CH341A_CMD_I2C_STM_SET | (speed & 0x7),
267 CH341A_CMD_I2C_STM_END
268 };
269
270 int32_t ret = usb_transfer(__func__, sizeof(buf), 0, buf, NULL);
271 if (ret < 0) {
272 msg_perr("Could not configure stream interface.\n");
273 }
274 return ret;
275}
276
Urja Rannikko0870b022016-01-31 22:10:29 +0000277/* The assumed map between UIO command bits, pins on CH341A chip and pins on SPI chip:
278 * UIO CH341A SPI CH341A SPI name
Elyes HAOUASac01baa2018-05-28 16:52:21 +0200279 * 0 D0/15 CS/1 (CS0)
Urja Rannikko0870b022016-01-31 22:10:29 +0000280 * 1 D1/16 unused (CS1)
281 * 2 D2/17 unused (CS2)
282 * 3 D3/18 SCK/6 (DCK)
283 * 4 D4/19 unused (DOUT2)
284 * 5 D5/20 SI/5 (DOUT)
285 * - The UIO stream commands seem to only have 6 bits of output, and D6/D7 are the SPI inputs,
286 * mapped as follows:
287 * D6/21 unused (DIN2)
288 * D7/22 SO/2 (DIN)
289 */
290static int32_t enable_pins(bool enable)
291{
292 uint8_t buf[] = {
293 CH341A_CMD_UIO_STREAM,
294 CH341A_CMD_UIO_STM_OUT | 0x37, // CS high (all of them), SCK=0, DOUT*=1
295 CH341A_CMD_UIO_STM_DIR | (enable ? 0x3F : 0x00), // Interface output enable / disable
296 CH341A_CMD_UIO_STM_END,
297 };
298
299 int32_t ret = usb_transfer(__func__, sizeof(buf), 0, buf, NULL);
300 if (ret < 0) {
301 msg_perr("Could not %sable output pins.\n", enable ? "en" : "dis");
302 }
303 return ret;
304}
305
306/* De-assert and assert CS in one operation. */
307static void pluck_cs(uint8_t *ptr)
308{
Elyes HAOUASe2c90c42018-08-18 09:04:41 +0200309 /* This was measured to give a minimum deassertion time of 2.25 us,
Urja Rannikko0870b022016-01-31 22:10:29 +0000310 * >20x more than needed for most SPI chips (100ns). */
311 int delay_cnt = 2;
312 if (stored_delay_us) {
313 delay_cnt = (stored_delay_us * 4) / 3;
314 stored_delay_us = 0;
315 }
316 *ptr++ = CH341A_CMD_UIO_STREAM;
317 *ptr++ = CH341A_CMD_UIO_STM_OUT | 0x37; /* deasserted */
318 int i;
319 for (i = 0; i < delay_cnt; i++)
320 *ptr++ = CH341A_CMD_UIO_STM_OUT | 0x37; /* "delay" */
321 *ptr++ = CH341A_CMD_UIO_STM_OUT | 0x36; /* asserted */
322 *ptr++ = CH341A_CMD_UIO_STM_END;
323}
324
Thomas Heijligencc853d82021-05-04 15:32:17 +0200325static void ch341a_spi_delay(unsigned int usecs)
Urja Rannikko0870b022016-01-31 22:10:29 +0000326{
327 /* There is space for 28 bytes instructions of 750 ns each in the CS packet (32 - 4 for the actual CS
328 * instructions), thus max 21 us, but we avoid getting too near to this boundary and use
329 * internal_delay() for durations over 20 us. */
330 if ((usecs + stored_delay_us) > 20) {
331 unsigned int inc = 20 - stored_delay_us;
332 internal_delay(usecs - inc);
333 usecs = inc;
334 }
335 stored_delay_us += usecs;
336}
337
Edward O'Callaghan5eca4272020-04-12 17:27:53 +1000338static int ch341a_spi_spi_send_command(const struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr)
Urja Rannikko0870b022016-01-31 22:10:29 +0000339{
340 if (handle == NULL)
341 return -1;
342
343 /* How many packets ... */
344 const size_t packets = (writecnt + readcnt + CH341_PACKET_LENGTH - 2) / (CH341_PACKET_LENGTH - 1);
345
346 /* We pluck CS/timeout handling into the first packet thus we need to allocate one extra package. */
347 uint8_t wbuf[packets+1][CH341_PACKET_LENGTH];
348 uint8_t rbuf[writecnt + readcnt];
349 /* Initialize the write buffer to zero to prevent writing random stack contents to device. */
350 memset(wbuf[0], 0, CH341_PACKET_LENGTH);
351
352 uint8_t *ptr = wbuf[0];
353 /* CS usage is optimized by doing both transitions in one packet.
354 * Final transition to deselected state is in the pin disable. */
355 pluck_cs(ptr);
356 unsigned int write_left = writecnt;
357 unsigned int read_left = readcnt;
358 unsigned int p;
359 for (p = 0; p < packets; p++) {
360 unsigned int write_now = min(CH341_PACKET_LENGTH - 1, write_left);
361 unsigned int read_now = min ((CH341_PACKET_LENGTH - 1) - write_now, read_left);
362 ptr = wbuf[p+1];
363 *ptr++ = CH341A_CMD_SPI_STREAM;
364 unsigned int i;
365 for (i = 0; i < write_now; ++i)
Marc Schink7ecfe482016-03-17 16:07:23 +0100366 *ptr++ = reverse_byte(*writearr++);
Urja Rannikko0870b022016-01-31 22:10:29 +0000367 if (read_now) {
368 memset(ptr, 0xFF, read_now);
369 read_left -= read_now;
370 }
371 write_left -= write_now;
372 }
373
374 int32_t ret = usb_transfer(__func__, CH341_PACKET_LENGTH + packets + writecnt + readcnt,
375 writecnt + readcnt, wbuf[0], rbuf);
376 if (ret < 0)
377 return -1;
378
379 unsigned int i;
380 for (i = 0; i < readcnt; i++) {
Marc Schink7ecfe482016-03-17 16:07:23 +0100381 *readarr++ = reverse_byte(rbuf[writecnt + i]);
Urja Rannikko0870b022016-01-31 22:10:29 +0000382 }
383
384 return 0;
385}
386
Anastasia Klimchukc63d9182021-07-06 16:18:44 +1000387static int ch341a_spi_shutdown(void *data);
388
Urja Rannikko0870b022016-01-31 22:10:29 +0000389static const struct spi_master spi_master_ch341a_spi = {
Nico Huber1cf407b2017-11-10 20:18:23 +0100390 .features = SPI_MASTER_4BA,
Martin Rothf6c1cb12022-03-15 10:55:25 -0600391 /* flashrom's current maximum is 256 B. CH341A was tested on Linux and Windows to accept at least
Urja Rannikko0870b022016-01-31 22:10:29 +0000392 * 128 kB. Basically there should be no hard limit because transfers are broken up into USB packets
393 * sent to the device and most of their payload streamed via SPI. */
394 .max_data_read = 4 * 1024,
395 .max_data_write = 4 * 1024,
396 .command = ch341a_spi_spi_send_command,
397 .multicommand = default_spi_send_multicommand,
398 .read = default_spi_read,
399 .write_256 = default_spi_write_256,
400 .write_aai = default_spi_write_aai,
Anastasia Klimchukc63d9182021-07-06 16:18:44 +1000401 .shutdown = ch341a_spi_shutdown,
Urja Rannikko0870b022016-01-31 22:10:29 +0000402};
403
404static int ch341a_spi_shutdown(void *data)
405{
406 if (handle == NULL)
407 return -1;
408
409 enable_pins(false);
410 libusb_free_transfer(transfer_out);
411 transfer_out = NULL;
412 int i;
413 for (i = 0; i < USB_IN_TRANSFERS; i++) {
414 libusb_free_transfer(transfer_ins[i]);
415 transfer_ins[i] = NULL;
416 }
417 libusb_release_interface(handle, 0);
418 libusb_close(handle);
419 libusb_exit(NULL);
420 handle = NULL;
421 return 0;
422}
423
Thomas Heijligencc853d82021-05-04 15:32:17 +0200424static int ch341a_spi_init(void)
Urja Rannikko0870b022016-01-31 22:10:29 +0000425{
426 if (handle != NULL) {
Nico Huberac90af62022-12-18 00:22:47 +0000427 msg_cerr("%s: handle already set! Please report a bug at flashrom-stable@flashrom.org\n",
428 __func__);
Urja Rannikko0870b022016-01-31 22:10:29 +0000429 return -1;
430 }
431
432 int32_t ret = libusb_init(NULL);
433 if (ret < 0) {
Martin Rothf6c1cb12022-03-15 10:55:25 -0600434 msg_perr("Couldn't initialize libusb!\n");
Urja Rannikko0870b022016-01-31 22:10:29 +0000435 return -1;
436 }
437
Alex James291764a2018-04-14 22:59:57 -0500438 /* Enable information, warning, and error messages (only). */
439#if LIBUSB_API_VERSION < 0x01000106
440 libusb_set_debug(NULL, 3);
441#else
442 libusb_set_option(NULL, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_INFO);
443#endif
Urja Rannikko0870b022016-01-31 22:10:29 +0000444
445 uint16_t vid = devs_ch341a_spi[0].vendor_id;
446 uint16_t pid = devs_ch341a_spi[0].device_id;
447 handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
448 if (handle == NULL) {
449 msg_perr("Couldn't open device %04x:%04x.\n", vid, pid);
450 return -1;
451 }
452
453/* libusb_detach_kernel_driver() and friends basically only work on Linux. We simply try to detach on Linux
454 * without a lot of passion here. If that works fine else we will fail on claiming the interface anyway. */
455#if IS_LINUX
456 ret = libusb_detach_kernel_driver(handle, 0);
457 if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
458 msg_pwarn("Detaching kernel drivers is not supported. Further accesses may fail.\n");
459 } else if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND) {
460 msg_pwarn("Failed to detach kernel driver: '%s'. Further accesses will probably fail.\n",
461 libusb_error_name(ret));
462 }
463#endif
464
465 ret = libusb_claim_interface(handle, 0);
466 if (ret != 0) {
467 msg_perr("Failed to claim interface 0: '%s'\n", libusb_error_name(ret));
468 goto close_handle;
469 }
470
471 struct libusb_device *dev;
472 if (!(dev = libusb_get_device(handle))) {
473 msg_perr("Failed to get device from device handle.\n");
474 goto close_handle;
475 }
476
477 struct libusb_device_descriptor desc;
478 ret = libusb_get_device_descriptor(dev, &desc);
479 if (ret < 0) {
480 msg_perr("Failed to get device descriptor: '%s'\n", libusb_error_name(ret));
481 goto release_interface;
482 }
483
484 msg_pdbg("Device revision is %d.%01d.%01d\n",
485 (desc.bcdDevice >> 8) & 0x00FF,
486 (desc.bcdDevice >> 4) & 0x000F,
487 (desc.bcdDevice >> 0) & 0x000F);
488
489 /* Allocate and pre-fill transfer structures. */
490 transfer_out = libusb_alloc_transfer(0);
491 if (!transfer_out) {
492 msg_perr("Failed to alloc libusb OUT transfer\n");
493 goto release_interface;
494 }
495 int i;
496 for (i = 0; i < USB_IN_TRANSFERS; i++) {
497 transfer_ins[i] = libusb_alloc_transfer(0);
498 if (transfer_ins[i] == NULL) {
499 msg_perr("Failed to alloc libusb IN transfer %d\n", i);
500 goto dealloc_transfers;
501 }
502 }
503 /* We use these helpers but dont fill the actual buffer yet. */
504 libusb_fill_bulk_transfer(transfer_out, handle, WRITE_EP, NULL, 0, cb_out, NULL, USB_TIMEOUT);
505 for (i = 0; i < USB_IN_TRANSFERS; i++)
506 libusb_fill_bulk_transfer(transfer_ins[i], handle, READ_EP, NULL, 0, cb_in, NULL, USB_TIMEOUT);
507
508 if ((config_stream(CH341A_STM_I2C_100K) < 0) || (enable_pins(true) < 0))
509 goto dealloc_transfers;
510
Anastasia Klimchukc63d9182021-07-06 16:18:44 +1000511 return register_spi_master(&spi_master_ch341a_spi, NULL);
Urja Rannikko0870b022016-01-31 22:10:29 +0000512
513dealloc_transfers:
514 for (i = 0; i < USB_IN_TRANSFERS; i++) {
515 if (transfer_ins[i] == NULL)
516 break;
517 libusb_free_transfer(transfer_ins[i]);
518 transfer_ins[i] = NULL;
519 }
520 libusb_free_transfer(transfer_out);
521 transfer_out = NULL;
522release_interface:
523 libusb_release_interface(handle, 0);
524close_handle:
525 libusb_close(handle);
526 handle = NULL;
527 return -1;
528}
Thomas Heijligencc853d82021-05-04 15:32:17 +0200529
530const struct programmer_entry programmer_ch341a_spi = {
531 .name = "ch341a_spi",
532 .type = USB,
533 .devs.dev = devs_ch341a_spi,
534 .init = ch341a_spi_init,
535 .map_flash_region = fallback_map,
536 .unmap_flash_region = fallback_unmap,
537 .delay = ch341a_spi_delay,
538};