aboutsummaryrefslogtreecommitdiff
path: root/src/jtag/drivers/versaloon/versaloon.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/jtag/drivers/versaloon/versaloon.c')
-rw-r--r--src/jtag/drivers/versaloon/versaloon.c398
1 files changed, 398 insertions, 0 deletions
diff --git a/src/jtag/drivers/versaloon/versaloon.c b/src/jtag/drivers/versaloon/versaloon.c
new file mode 100644
index 00000000..dbb8e4fb
--- /dev/null
+++ b/src/jtag/drivers/versaloon/versaloon.c
@@ -0,0 +1,398 @@
+/***************************************************************************
+ * Copyright (C) 2009 - 2010 by Simon Qian <SimonQian@SimonQian.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., *
+ * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
+ ***************************************************************************/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <string.h>
+
+#include "versaloon_include.h"
+#include "versaloon.h"
+#include "versaloon_internal.h"
+#include "usbtoxxx/usbtoxxx.h"
+
+uint8_t *versaloon_buf = NULL;
+uint8_t *versaloon_cmd_buf = NULL;
+uint16_t versaloon_buf_size;
+
+struct versaloon_pending_t versaloon_pending[VERSALOON_MAX_PENDING_NUMBER];
+uint16_t versaloon_pending_idx = 0;
+
+usb_dev_handle *versaloon_usb_device_handle = NULL;
+static uint32_t versaloon_usb_to = VERSALOON_TIMEOUT;
+
+RESULT versaloon_init(void);
+RESULT versaloon_fini(void);
+RESULT versaloon_get_target_voltage(uint16_t *voltage);
+RESULT versaloon_set_target_voltage(uint16_t voltage);
+RESULT versaloon_delay_ms(uint16_t ms);
+RESULT versaloon_delay_us(uint16_t us);
+struct versaloon_interface_t versaloon_interface =
+{
+ .init = versaloon_init,
+ .fini = versaloon_fini,
+ {// adaptors
+ {// target_voltage
+ .get = versaloon_get_target_voltage,
+ .set = versaloon_set_target_voltage,
+ },
+ {// gpio
+ .init = usbtogpio_init,
+ .fini = usbtogpio_fini,
+ .config = usbtogpio_config,
+ .out = usbtogpio_out,
+ .in = usbtogpio_in,
+ },
+ {// delay
+ .delayms = versaloon_delay_ms,
+ .delayus = versaloon_delay_us,
+ },
+ {// swd
+ .init = usbtoswd_init,
+ .fini = usbtoswd_fini,
+ .config = usbtoswd_config,
+ .seqout = usbtoswd_seqout,
+ .seqin = usbtoswd_seqin,
+ .transact = usbtoswd_transact,
+ },
+ {// jtag_raw
+ .init = usbtojtagraw_init,
+ .fini = usbtojtagraw_fini,
+ .config = usbtojtagraw_config,
+ .execute = usbtojtagraw_execute,
+ },
+ .peripheral_commit = usbtoxxx_execute_command,
+ },
+ {// usb_setting
+ .vid = VERSALOON_VID,
+ .pid = VERSALOON_PID,
+ .ep_out = VERSALOON_OUTP,
+ .ep_in = VERSALOON_INP,
+ .interface = VERSALOON_IFACE,
+ .serialstring = NULL,
+ .buf_size = 256,
+ }
+};
+
+// programmer_cmd
+static uint32_t versaloon_pending_id = 0;
+static versaloon_callback_t versaloon_callback = NULL;
+static void *versaloon_extra_data = NULL;
+static struct versaloon_want_pos_t *versaloon_want_pos = NULL;
+void versaloon_set_pending_id(uint32_t id)
+{
+ versaloon_pending_id = id;
+}
+void versaloon_set_callback(versaloon_callback_t callback)
+{
+ versaloon_callback = callback;
+}
+void versaloon_set_extra_data(void * p)
+{
+ versaloon_extra_data = p;
+}
+
+void versaloon_free_want_pos(void)
+{
+ uint16_t i;
+ struct versaloon_want_pos_t *tmp, *free_tmp;
+
+ tmp = versaloon_want_pos;
+ while (tmp != NULL)
+ {
+ free_tmp = tmp;
+ tmp = tmp->next;
+ free(free_tmp);
+ }
+ versaloon_want_pos = NULL;
+
+ for (i = 0; i < dimof(versaloon_pending); i++)
+ {
+ tmp = versaloon_pending[i].pos;
+ while (tmp != NULL)
+ {
+ free_tmp = tmp;
+ tmp = tmp->next;
+ free(free_tmp);
+ }
+ versaloon_pending[i].pos = NULL;
+ }
+}
+
+RESULT versaloon_add_want_pos(uint16_t offset, uint16_t size, uint8_t *buff)
+{
+ struct versaloon_want_pos_t *new_pos = NULL;
+
+ new_pos = (struct versaloon_want_pos_t *)malloc(sizeof(*new_pos));
+ if (NULL == new_pos)
+ {
+ LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
+ return ERRCODE_NOT_ENOUGH_MEMORY;
+ }
+ new_pos->offset = offset;
+ new_pos->size = size;
+ new_pos->buff = buff;
+ new_pos->next = NULL;
+
+ if (NULL == versaloon_want_pos)
+ {
+ versaloon_want_pos = new_pos;
+ }
+ else
+ {
+ struct versaloon_want_pos_t *tmp = versaloon_want_pos;
+
+ while (tmp->next != NULL)
+ {
+ tmp = tmp->next;
+ }
+ tmp->next = new_pos;
+ }
+
+ return ERROR_OK;
+}
+
+RESULT versaloon_add_pending(uint8_t type, uint8_t cmd, uint16_t actual_szie,
+ uint16_t want_pos, uint16_t want_size, uint8_t *buffer, uint8_t collect)
+{
+#if PARAM_CHECK
+ if (versaloon_pending_idx >= VERSALOON_MAX_PENDING_NUMBER)
+ {
+ LOG_BUG(ERRMSG_INVALID_INDEX, versaloon_pending_idx,
+ "versaloon pending data");
+ return ERROR_FAIL;
+ }
+#endif
+
+ versaloon_pending[versaloon_pending_idx].type = type;
+ versaloon_pending[versaloon_pending_idx].cmd = cmd;
+ versaloon_pending[versaloon_pending_idx].actual_data_size = actual_szie;
+ versaloon_pending[versaloon_pending_idx].want_data_pos = want_pos;
+ versaloon_pending[versaloon_pending_idx].want_data_size = want_size;
+ versaloon_pending[versaloon_pending_idx].data_buffer = buffer;
+ versaloon_pending[versaloon_pending_idx].collect = collect;
+ versaloon_pending[versaloon_pending_idx].id = versaloon_pending_id;
+ versaloon_pending_id = 0;
+ versaloon_pending[versaloon_pending_idx].extra_data = versaloon_extra_data;
+ versaloon_extra_data = NULL;
+ versaloon_pending[versaloon_pending_idx].callback = versaloon_callback;
+ versaloon_callback = NULL;
+ versaloon_pending[versaloon_pending_idx].pos = versaloon_want_pos;
+ versaloon_want_pos = NULL;
+ versaloon_pending_idx++;
+
+ return ERROR_OK;
+}
+
+RESULT versaloon_send_command(uint16_t out_len, uint16_t *inlen)
+{
+ int ret;
+
+#if PARAM_CHECK
+ if (NULL == versaloon_buf)
+ {
+ LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
+ return ERRCODE_INVALID_BUFFER;
+ }
+ if ((0 == out_len) || (out_len > versaloon_interface.usb_setting.buf_size))
+ {
+ LOG_BUG(ERRMSG_INVALID_PARAMETER, __FUNCTION__);
+ return ERRCODE_INVALID_PARAMETER;
+ }
+#endif
+
+ ret = usb_bulk_write(versaloon_usb_device_handle,
+ versaloon_interface.usb_setting.ep_out, (char *)versaloon_buf,
+ out_len, versaloon_usb_to);
+ if (ret != out_len)
+ {
+ LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "send usb data",
+ usb_strerror());
+ return ERRCODE_FAILURE_OPERATION;
+ }
+
+ if (inlen != NULL)
+ {
+ ret = usb_bulk_read(versaloon_usb_device_handle,
+ versaloon_interface.usb_setting.ep_in, (char *)versaloon_buf,
+ versaloon_interface.usb_setting.buf_size, versaloon_usb_to);
+ if (ret > 0)
+ {
+ *inlen = (uint16_t)ret;
+ return ERROR_OK;
+ }
+ else
+ {
+ LOG_ERROR(ERRMSG_FAILURE_OPERATION_ERRSTRING, "receive usb data",
+ usb_strerror());
+ return ERROR_FAIL;
+ }
+ }
+ else
+ {
+ return ERROR_OK;
+ }
+}
+
+#define VERSALOON_RETRY_CNT 10
+RESULT versaloon_init(void)
+{
+ uint16_t ret = 0;
+ uint8_t retry;
+ uint32_t timeout_tmp;
+
+ // malloc temporary buffer
+ versaloon_buf =
+ (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size);
+ if (NULL == versaloon_buf)
+ {
+ LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
+ return ERRCODE_NOT_ENOUGH_MEMORY;
+ }
+
+ // connect to versaloon
+ timeout_tmp = versaloon_usb_to;
+ // not output error message when connectting
+ // 100ms delay when connect
+ versaloon_usb_to = 100;
+ for (retry = 0; retry < VERSALOON_RETRY_CNT; retry++)
+ {
+ versaloon_buf[0] = VERSALOON_GET_INFO;
+ if ((ERROR_OK == versaloon_send_command(1, &ret)) && (ret >= 3))
+ {
+ break;
+ }
+ }
+ versaloon_usb_to = timeout_tmp;
+ if (VERSALOON_RETRY_CNT == retry)
+ {
+ versaloon_fini();
+ LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
+ return ERRCODE_FAILURE_OPERATION;
+ }
+
+ versaloon_buf[ret] = 0;
+ versaloon_buf_size = versaloon_buf[0] + (versaloon_buf[1] << 8);
+ versaloon_interface.usb_setting.buf_size = versaloon_buf_size;
+ LOG_INFO("%s", versaloon_buf + 2);
+
+ // free temporary buffer
+ free(versaloon_buf);
+ versaloon_buf = NULL;
+
+ versaloon_buf =
+ (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size);
+ if (NULL == versaloon_buf)
+ {
+ versaloon_fini();
+ LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
+ return ERRCODE_NOT_ENOUGH_MEMORY;
+ }
+ versaloon_cmd_buf =
+ (uint8_t *)malloc(versaloon_interface.usb_setting.buf_size - 3);
+ if (NULL == versaloon_cmd_buf)
+ {
+ versaloon_fini();
+ LOG_ERROR(ERRMSG_NOT_ENOUGH_MEMORY);
+ return ERRCODE_NOT_ENOUGH_MEMORY;
+ }
+ if (ERROR_OK != usbtoxxx_init())
+ {
+ LOG_ERROR(ERRMSG_FAILURE_OPERATION, "initialize usbtoxxx");
+ return ERROR_FAIL;
+ }
+ return versaloon_get_target_voltage(&ret);
+}
+
+RESULT versaloon_fini(void)
+{
+ if (versaloon_usb_device_handle != NULL)
+ {
+ usbtoxxx_fini();
+ versaloon_free_want_pos();
+
+ versaloon_usb_device_handle = NULL;
+
+ if (versaloon_buf != NULL)
+ {
+ free(versaloon_buf);
+ versaloon_buf = NULL;
+ }
+ if (versaloon_cmd_buf != NULL)
+ {
+ free(versaloon_cmd_buf);
+ versaloon_cmd_buf = NULL;
+ }
+ }
+
+ return ERROR_OK;
+}
+
+RESULT versaloon_set_target_voltage(uint16_t voltage)
+{
+ usbtopwr_init(0);
+ usbtopwr_config(0);
+ usbtopwr_output(0, voltage);
+ usbtopwr_fini(0);
+
+ return usbtoxxx_execute_command();
+}
+
+RESULT versaloon_get_target_voltage(uint16_t *voltage)
+{
+ uint16_t inlen;
+
+#if PARAM_CHECK
+ if (NULL == versaloon_buf)
+ {
+ LOG_BUG(ERRMSG_INVALID_BUFFER, TO_STR(versaloon_buf));
+ return ERRCODE_INVALID_BUFFER;
+ }
+ if (NULL == voltage)
+ {
+ LOG_BUG(ERRMSG_INVALID_PARAMETER, __FUNCTION__);
+ return ERRCODE_INVALID_PARAMETER;
+ }
+#endif
+
+ versaloon_buf[0] = VERSALOON_GET_TVCC;
+
+ if ((ERROR_OK != versaloon_send_command(1, &inlen)) || (inlen != 2))
+ {
+ LOG_ERROR(ERRMSG_FAILURE_OPERATION, "communicate with versaloon");
+ return ERRCODE_FAILURE_OPERATION;
+ }
+ else
+ {
+ *voltage = versaloon_buf[0] + (versaloon_buf[1] << 8);
+ return ERROR_OK;
+ }
+}
+
+RESULT versaloon_delay_ms(uint16_t ms)
+{
+ return usbtodelay_delay(ms | 0x8000);
+}
+
+RESULT versaloon_delay_us(uint16_t us)
+{
+ return usbtodelay_delay(us & 0x7FFF);
+}
+