123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536 |
- /*
- * This file is part of the flashrom project.
- *
- * Copyright (C) 2011 asbokid <ballymunboy@gmail.com>
- * Copyright (C) 2014 Pluto Yang <yangyj.ee@gmail.com>
- * Copyright (C) 2015-2016 Stefan Tauner
- * Copyright (C) 2015 Urja Rannikko <urjaman@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
- #include <string.h>
- #include <libusb.h>
- #include "flash.h"
- #include "programmer.h"
- /* LIBUSB_CALL ensures the right calling conventions on libusb callbacks.
- * However, the macro is not defined everywhere. m(
- */
- #ifndef LIBUSB_CALL
- #define LIBUSB_CALL
- #endif
- #define USB_TIMEOUT 1000 /* 1000 ms is plenty and we have no backup strategy anyway. */
- #define WRITE_EP 0x02
- #define READ_EP 0x82
- #define CH341_PACKET_LENGTH 0x20
- #define CH341_MAX_PACKETS 256
- #define CH341_MAX_PACKET_LEN (CH341_PACKET_LENGTH * CH341_MAX_PACKETS)
- #define CH341A_CMD_SET_OUTPUT 0xA1
- #define CH341A_CMD_IO_ADDR 0xA2
- #define CH341A_CMD_PRINT_OUT 0xA3
- #define CH341A_CMD_SPI_STREAM 0xA8
- #define CH341A_CMD_SIO_STREAM 0xA9
- #define CH341A_CMD_I2C_STREAM 0xAA
- #define CH341A_CMD_UIO_STREAM 0xAB
- #define CH341A_CMD_I2C_STM_START 0x74
- #define CH341A_CMD_I2C_STM_STOP 0x75
- #define CH341A_CMD_I2C_STM_OUT 0x80
- #define CH341A_CMD_I2C_STM_IN 0xC0
- #define CH341A_CMD_I2C_STM_MAX ( min( 0x3F, CH341_PACKET_LENGTH ) )
- #define CH341A_CMD_I2C_STM_SET 0x60 // bit 2: SPI with two data pairs D5,D4=out, D7,D6=in
- #define CH341A_CMD_I2C_STM_US 0x40
- #define CH341A_CMD_I2C_STM_MS 0x50
- #define CH341A_CMD_I2C_STM_DLY 0x0F
- #define CH341A_CMD_I2C_STM_END 0x00
- #define CH341A_CMD_UIO_STM_IN 0x00
- #define CH341A_CMD_UIO_STM_DIR 0x40
- #define CH341A_CMD_UIO_STM_OUT 0x80
- #define CH341A_CMD_UIO_STM_US 0xC0
- #define CH341A_CMD_UIO_STM_END 0x20
- #define CH341A_STM_I2C_20K 0x00
- #define CH341A_STM_I2C_100K 0x01
- #define CH341A_STM_I2C_400K 0x02
- #define CH341A_STM_I2C_750K 0x03
- #define CH341A_STM_SPI_DBL 0x04
- /* Number of parallel IN transfers. 32 seems to produce the most stable throughput on Windows. */
- #define USB_IN_TRANSFERS 32
- /* We need to use many queued IN transfers for any resemblance of performance (especially on Windows)
- * because USB spec says that transfers end on non-full packets and the device sends the 31 reply
- * data bytes to each 32-byte packet with command + 31 bytes of data... */
- static struct libusb_transfer *transfer_out = NULL;
- static struct libusb_transfer *transfer_ins[USB_IN_TRANSFERS] = {0};
- /* Accumulate delays to be plucked between CS deassertion and CS assertions. */
- static unsigned int stored_delay_us = 0;
- static struct libusb_device_handle *handle = NULL;
- const struct dev_entry devs_ch341a_spi[] = {
- {0x1A86, 0x5512, OK, "Winchiphead (WCH)", "CH341A"},
- {0},
- };
- enum trans_state {TRANS_ACTIVE = -2, TRANS_ERR = -1, TRANS_IDLE = 0};
- static void print_hex(const void *buf, size_t len)
- {
- size_t i;
- for (i = 0; i < len; i++) {
- msg_pspew(" %02x", ((uint8_t *)buf)[i]);
- if (i % CH341_PACKET_LENGTH == CH341_PACKET_LENGTH - 1)
- msg_pspew("\n");
- }
- }
- static void cb_common(const char *func, struct libusb_transfer *transfer)
- {
- int *transfer_cnt = (int*)transfer->user_data;
- if (transfer->status == LIBUSB_TRANSFER_CANCELLED) {
- /* Silently ACK and exit. */
- *transfer_cnt = TRANS_IDLE;
- return;
- }
- if (transfer->status != LIBUSB_TRANSFER_COMPLETED) {
- msg_perr("\n%s: error: %s\n", func, libusb_error_name(transfer->status));
- *transfer_cnt = TRANS_ERR;
- } else {
- *transfer_cnt = transfer->actual_length;
- }
- }
- /* callback for bulk out async transfer */
- static void LIBUSB_CALL cb_out(struct libusb_transfer *transfer)
- {
- cb_common(__func__, transfer);
- }
- /* callback for bulk in async transfer */
- static void LIBUSB_CALL cb_in(struct libusb_transfer *transfer)
- {
- cb_common(__func__, transfer);
- }
- static int32_t usb_transfer(const char *func, unsigned int writecnt, unsigned int readcnt, const uint8_t *writearr, uint8_t *readarr)
- {
- if (handle == NULL)
- return -1;
- int state_out = TRANS_IDLE;
- transfer_out->buffer = (uint8_t*)writearr;
- transfer_out->length = writecnt;
- transfer_out->user_data = &state_out;
- /* Schedule write first */
- if (writecnt > 0) {
- state_out = TRANS_ACTIVE;
- int ret = libusb_submit_transfer(transfer_out);
- if (ret) {
- msg_perr("%s: failed to submit OUT transfer: %s\n", func, libusb_error_name(ret));
- state_out = TRANS_ERR;
- goto err;
- }
- }
- /* Handle all asynchronous packets as long as we have stuff to write or read. The write(s) simply need
- * to complete but we need to scheduling reads as long as we are not done. */
- unsigned int free_idx = 0; /* The IN transfer we expect to be free next. */
- unsigned int in_idx = 0; /* The IN transfer we expect to be completed next. */
- unsigned int in_done = 0;
- unsigned int in_active = 0;
- unsigned int out_done = 0;
- uint8_t *in_buf = readarr;
- int state_in[USB_IN_TRANSFERS] = {0};
- do {
- /* Schedule new reads as long as there are free transfers and unscheduled bytes to read. */
- while ((in_done + in_active) < readcnt && state_in[free_idx] == TRANS_IDLE) {
- unsigned int cur_todo = min(CH341_PACKET_LENGTH - 1, readcnt - in_done - in_active);
- transfer_ins[free_idx]->length = cur_todo;
- transfer_ins[free_idx]->buffer = in_buf;
- transfer_ins[free_idx]->user_data = &state_in[free_idx];
- int ret = libusb_submit_transfer(transfer_ins[free_idx]);
- if (ret) {
- state_in[free_idx] = TRANS_ERR;
- msg_perr("%s: failed to submit IN transfer: %s\n",
- func, libusb_error_name(ret));
- goto err;
- }
- in_buf += cur_todo;
- in_active += cur_todo;
- state_in[free_idx] = TRANS_ACTIVE;
- free_idx = (free_idx + 1) % USB_IN_TRANSFERS; /* Increment (and wrap around). */
- }
- /* Actually get some work done. */
- libusb_handle_events_timeout(NULL, &(struct timeval){1, 0});
- /* Check for the write */
- if (out_done < writecnt) {
- if (state_out == TRANS_ERR) {
- goto err;
- } else if (state_out > 0) {
- out_done += state_out;
- state_out = TRANS_IDLE;
- }
- }
- /* Check for completed transfers. */
- while (state_in[in_idx] != TRANS_IDLE && state_in[in_idx] != TRANS_ACTIVE) {
- if (state_in[in_idx] == TRANS_ERR) {
- goto err;
- }
- /* If a transfer is done, record the number of bytes read and reuse it later. */
- in_done += state_in[in_idx];
- in_active -= state_in[in_idx];
- state_in[in_idx] = TRANS_IDLE;
- in_idx = (in_idx + 1) % USB_IN_TRANSFERS; /* Increment (and wrap around). */
- }
- } while ((out_done < writecnt) || (in_done < readcnt));
- if (out_done > 0) {
- msg_pspew("Wrote %d bytes:\n", out_done);
- print_hex(writearr, out_done);
- msg_pspew("\n\n");
- }
- if (in_done > 0) {
- msg_pspew("Read %d bytes:\n", in_done);
- print_hex(readarr, in_done);
- msg_pspew("\n\n");
- }
- return 0;
- err:
- /* Clean up on errors. */
- msg_perr("%s: Failed to %s %d bytes\n", func, (state_out == TRANS_ERR) ? "write" : "read",
- (state_out == TRANS_ERR) ? writecnt : readcnt);
- /* First, we must cancel any ongoing requests and wait for them to be canceled. */
- if ((writecnt > 0) && (state_out == TRANS_ACTIVE)) {
- if (libusb_cancel_transfer(transfer_out) != 0)
- state_out = TRANS_ERR;
- }
- if (readcnt > 0) {
- unsigned int i;
- for (i = 0; i < USB_IN_TRANSFERS; i++) {
- if (state_in[i] == TRANS_ACTIVE)
- if (libusb_cancel_transfer(transfer_ins[i]) != 0)
- state_in[i] = TRANS_ERR;
- }
- }
- /* Wait for cancellations to complete. */
- while (1) {
- bool finished = true;
- if ((writecnt > 0) && (state_out == TRANS_ACTIVE))
- finished = false;
- if (readcnt > 0) {
- unsigned int i;
- for (i = 0; i < USB_IN_TRANSFERS; i++) {
- if (state_in[i] == TRANS_ACTIVE)
- finished = false;
- }
- }
- if (finished)
- break;
- libusb_handle_events_timeout(NULL, &(struct timeval){1, 0});
- }
- return -1;
- }
- /* Set the I2C bus speed (speed(b1b0): 0 = 20kHz; 1 = 100kHz, 2 = 400kHz, 3 = 750kHz).
- * Set the SPI bus data width (speed(b2): 0 = Single, 1 = Double). */
- static int32_t config_stream(uint32_t speed)
- {
- if (handle == NULL)
- return -1;
- uint8_t buf[] = {
- CH341A_CMD_I2C_STREAM,
- CH341A_CMD_I2C_STM_SET | (speed & 0x7),
- CH341A_CMD_I2C_STM_END
- };
- int32_t ret = usb_transfer(__func__, sizeof(buf), 0, buf, NULL);
- if (ret < 0) {
- msg_perr("Could not configure stream interface.\n");
- }
- return ret;
- }
- /* ch341 requires LSB first, swap the bit order before send and after receive */
- static uint8_t swap_byte(uint8_t x)
- {
- x = ((x >> 1) & 0x55) | ((x << 1) & 0xaa);
- x = ((x >> 2) & 0x33) | ((x << 2) & 0xcc);
- x = ((x >> 4) & 0x0f) | ((x << 4) & 0xf0);
- return x;
- }
- /* The assumed map between UIO command bits, pins on CH341A chip and pins on SPI chip:
- * UIO CH341A SPI CH341A SPI name
- * 0 D0/15 CS/1 (CS0)
- * 1 D1/16 unused (CS1)
- * 2 D2/17 unused (CS2)
- * 3 D3/18 SCK/6 (DCK)
- * 4 D4/19 unused (DOUT2)
- * 5 D5/20 SI/5 (DOUT)
- * - The UIO stream commands seem to only have 6 bits of output, and D6/D7 are the SPI inputs,
- * mapped as follows:
- * D6/21 unused (DIN2)
- * D7/22 SO/2 (DIN)
- */
- static int32_t enable_pins(bool enable)
- {
- uint8_t buf[] = {
- CH341A_CMD_UIO_STREAM,
- CH341A_CMD_UIO_STM_OUT | 0x37, // CS high (all of them), SCK=0, DOUT*=1
- CH341A_CMD_UIO_STM_DIR | (enable ? 0x3F : 0x00), // Interface output enable / disable
- CH341A_CMD_UIO_STM_END,
- };
- int32_t ret = usb_transfer(__func__, sizeof(buf), 0, buf, NULL);
- if (ret < 0) {
- msg_perr("Could not %sable output pins.\n", enable ? "en" : "dis");
- }
- return ret;
- }
- /* De-assert and assert CS in one operation. */
- static void pluck_cs(uint8_t *ptr)
- {
- /* This was measured to give a minumum deassertion time of 2.25 us,
- * >20x more than needed for most SPI chips (100ns). */
- int delay_cnt = 2;
- if (stored_delay_us) {
- delay_cnt = (stored_delay_us * 4) / 3;
- stored_delay_us = 0;
- }
- *ptr++ = CH341A_CMD_UIO_STREAM;
- *ptr++ = CH341A_CMD_UIO_STM_OUT | 0x37; /* deasserted */
- int i;
- for (i = 0; i < delay_cnt; i++)
- *ptr++ = CH341A_CMD_UIO_STM_OUT | 0x37; /* "delay" */
- *ptr++ = CH341A_CMD_UIO_STM_OUT | 0x36; /* asserted */
- *ptr++ = CH341A_CMD_UIO_STM_END;
- }
- void ch341a_spi_delay(unsigned int usecs)
- {
- /* There is space for 28 bytes instructions of 750 ns each in the CS packet (32 - 4 for the actual CS
- * instructions), thus max 21 us, but we avoid getting too near to this boundary and use
- * internal_delay() for durations over 20 us. */
- if ((usecs + stored_delay_us) > 20) {
- unsigned int inc = 20 - stored_delay_us;
- internal_delay(usecs - inc);
- usecs = inc;
- }
- stored_delay_us += usecs;
- }
- static int ch341a_spi_spi_send_command(struct flashctx *flash, unsigned int writecnt, unsigned int readcnt, const unsigned char *writearr, unsigned char *readarr)
- {
- if (handle == NULL)
- return -1;
- /* How many packets ... */
- const size_t packets = (writecnt + readcnt + CH341_PACKET_LENGTH - 2) / (CH341_PACKET_LENGTH - 1);
- /* We pluck CS/timeout handling into the first packet thus we need to allocate one extra package. */
- uint8_t wbuf[packets+1][CH341_PACKET_LENGTH];
- uint8_t rbuf[writecnt + readcnt];
- /* Initialize the write buffer to zero to prevent writing random stack contents to device. */
- memset(wbuf[0], 0, CH341_PACKET_LENGTH);
- uint8_t *ptr = wbuf[0];
- /* CS usage is optimized by doing both transitions in one packet.
- * Final transition to deselected state is in the pin disable. */
- pluck_cs(ptr);
- unsigned int write_left = writecnt;
- unsigned int read_left = readcnt;
- unsigned int p;
- for (p = 0; p < packets; p++) {
- unsigned int write_now = min(CH341_PACKET_LENGTH - 1, write_left);
- unsigned int read_now = min ((CH341_PACKET_LENGTH - 1) - write_now, read_left);
- ptr = wbuf[p+1];
- *ptr++ = CH341A_CMD_SPI_STREAM;
- unsigned int i;
- for (i = 0; i < write_now; ++i)
- *ptr++ = swap_byte(*writearr++);
- if (read_now) {
- memset(ptr, 0xFF, read_now);
- read_left -= read_now;
- }
- write_left -= write_now;
- }
- int32_t ret = usb_transfer(__func__, CH341_PACKET_LENGTH + packets + writecnt + readcnt,
- writecnt + readcnt, wbuf[0], rbuf);
- if (ret < 0)
- return -1;
- unsigned int i;
- for (i = 0; i < readcnt; i++) {
- *readarr++ = swap_byte(rbuf[writecnt + i]);
- }
- return 0;
- }
- static const struct spi_master spi_master_ch341a_spi = {
- .type = SPI_CONTROLLER_CH341A_SPI,
- /* flashrom's current maximum is 256 B. CH341A was tested on Linux and Windows to accept atleast
- * 128 kB. Basically there should be no hard limit because transfers are broken up into USB packets
- * sent to the device and most of their payload streamed via SPI. */
- .max_data_read = 4 * 1024,
- .max_data_write = 4 * 1024,
- .command = ch341a_spi_spi_send_command,
- .multicommand = default_spi_send_multicommand,
- .read = default_spi_read,
- .write_256 = default_spi_write_256,
- .write_aai = default_spi_write_aai,
- };
- static int ch341a_spi_shutdown(void *data)
- {
- if (handle == NULL)
- return -1;
- enable_pins(false);
- libusb_free_transfer(transfer_out);
- transfer_out = NULL;
- int i;
- for (i = 0; i < USB_IN_TRANSFERS; i++) {
- libusb_free_transfer(transfer_ins[i]);
- transfer_ins[i] = NULL;
- }
- libusb_release_interface(handle, 0);
- libusb_close(handle);
- libusb_exit(NULL);
- handle = NULL;
- return 0;
- }
- int ch341a_spi_init(void)
- {
- if (handle != NULL) {
- msg_cerr("%s: handle already set! Please report a bug at flashrom@flashrom.org\n", __func__);
- return -1;
- }
- int32_t ret = libusb_init(NULL);
- if (ret < 0) {
- msg_perr("Couldnt initialize libusb!\n");
- return -1;
- }
- libusb_set_debug(NULL, 3); // Enable information, warning and error messages (only).
- uint16_t vid = devs_ch341a_spi[0].vendor_id;
- uint16_t pid = devs_ch341a_spi[0].device_id;
- handle = libusb_open_device_with_vid_pid(NULL, vid, pid);
- if (handle == NULL) {
- msg_perr("Couldn't open device %04x:%04x.\n", vid, pid);
- return -1;
- }
- /* libusb_detach_kernel_driver() and friends basically only work on Linux. We simply try to detach on Linux
- * without a lot of passion here. If that works fine else we will fail on claiming the interface anyway. */
- #if IS_LINUX
- ret = libusb_detach_kernel_driver(handle, 0);
- if (ret == LIBUSB_ERROR_NOT_SUPPORTED) {
- msg_pwarn("Detaching kernel drivers is not supported. Further accesses may fail.\n");
- } else if (ret != 0 && ret != LIBUSB_ERROR_NOT_FOUND) {
- msg_pwarn("Failed to detach kernel driver: '%s'. Further accesses will probably fail.\n",
- libusb_error_name(ret));
- }
- #endif
- ret = libusb_claim_interface(handle, 0);
- if (ret != 0) {
- msg_perr("Failed to claim interface 0: '%s'\n", libusb_error_name(ret));
- goto close_handle;
- }
- struct libusb_device *dev;
- if (!(dev = libusb_get_device(handle))) {
- msg_perr("Failed to get device from device handle.\n");
- goto close_handle;
- }
- struct libusb_device_descriptor desc;
- ret = libusb_get_device_descriptor(dev, &desc);
- if (ret < 0) {
- msg_perr("Failed to get device descriptor: '%s'\n", libusb_error_name(ret));
- goto release_interface;
- }
- msg_pdbg("Device revision is %d.%01d.%01d\n",
- (desc.bcdDevice >> 8) & 0x00FF,
- (desc.bcdDevice >> 4) & 0x000F,
- (desc.bcdDevice >> 0) & 0x000F);
- /* Allocate and pre-fill transfer structures. */
- transfer_out = libusb_alloc_transfer(0);
- if (!transfer_out) {
- msg_perr("Failed to alloc libusb OUT transfer\n");
- goto release_interface;
- }
- int i;
- for (i = 0; i < USB_IN_TRANSFERS; i++) {
- transfer_ins[i] = libusb_alloc_transfer(0);
- if (transfer_ins[i] == NULL) {
- msg_perr("Failed to alloc libusb IN transfer %d\n", i);
- goto dealloc_transfers;
- }
- }
- /* We use these helpers but dont fill the actual buffer yet. */
- libusb_fill_bulk_transfer(transfer_out, handle, WRITE_EP, NULL, 0, cb_out, NULL, USB_TIMEOUT);
- for (i = 0; i < USB_IN_TRANSFERS; i++)
- libusb_fill_bulk_transfer(transfer_ins[i], handle, READ_EP, NULL, 0, cb_in, NULL, USB_TIMEOUT);
- if ((config_stream(CH341A_STM_I2C_100K) < 0) || (enable_pins(true) < 0))
- goto dealloc_transfers;
- register_shutdown(ch341a_spi_shutdown, NULL);
- register_spi_master(&spi_master_ch341a_spi);
- return 0;
- dealloc_transfers:
- for (i = 0; i < USB_IN_TRANSFERS; i++) {
- if (transfer_ins[i] == NULL)
- break;
- libusb_free_transfer(transfer_ins[i]);
- transfer_ins[i] = NULL;
- }
- libusb_free_transfer(transfer_out);
- transfer_out = NULL;
- release_interface:
- libusb_release_interface(handle, 0);
- close_handle:
- libusb_close(handle);
- handle = NULL;
- return -1;
- }
|