Implemented TI3410 transport.

This allows direct libusb access to FET430UIF and eZ430 devices. It
doesn't yet implement the initial firmware download required to get
the 3410 working.
This commit is contained in:
Daniel Beer 2011-09-16 14:40:40 +12:00
parent 33ea3aa5e7
commit 7de9854661
5 changed files with 431 additions and 5 deletions

View File

@ -100,6 +100,7 @@ OBJ=\
drivers/rf2500.o \
drivers/sim.o \
drivers/uif.o \
drivers/ti3410.o \
formats/binfile.o \
formats/coff.o \
formats/elf32.o \

View File

@ -37,6 +37,7 @@
#include "uif.h"
#include "olimex.h"
#include "rf2500.h"
#include "ti3410.h"
/* Send data in separate packets, as in the RF2500 */
#define FET_PROTO_SEPARATE_DATA 0x01
@ -1145,12 +1146,11 @@ static device_t fet_open_uif(const struct device_args *args)
{
transport_t trans;
if (!(args->flags & DEVICE_FLAG_TTY)) {
printc_err("This driver does not support raw USB access.\n");
return NULL;
}
if (args->flags & DEVICE_FLAG_TTY)
trans = uif_open(args->path, UIF_TYPE_FET);
else
trans = ti3410_open(args->path, args->requested_serial);
trans = uif_open(args->path, UIF_TYPE_FET);
if (!trans)
return NULL;

395
drivers/ti3410.c Normal file
View File

@ -0,0 +1,395 @@
/* MSPDebug - debugging tool for the eZ430
* Copyright (C) 2009, 2010 Daniel Beer
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <usb.h>
#include "ti3410.h"
#include "util.h"
#include "usbutil.h"
#include "output.h"
/************************************************************************
* Definitions taken from drivers/usb/serial/ti_usb_3410_5052.h in the
* Linux kernel (GPLv2+).
*/
/* Configuration ids */
#define TI_BOOT_CONFIG 1
#define TI_ACTIVE_CONFIG 2
/* Pipe transfer mode and timeout */
#define TI_PIPE_MODE_CONTINOUS 0x01
#define TI_PIPE_MODE_MASK 0x03
#define TI_PIPE_TIMEOUT_MASK 0x7C
#define TI_PIPE_TIMEOUT_ENABLE 0x80
/* Module identifiers */
#define TI_I2C_PORT 0x01
#define TI_IEEE1284_PORT 0x02
#define TI_UART1_PORT 0x03
#define TI_UART2_PORT 0x04
#define TI_RAM_PORT 0x05
/* Purge modes */
#define TI_PURGE_OUTPUT 0x00
#define TI_PURGE_INPUT 0x80
/* Commands */
#define TI_GET_VERSION 0x01
#define TI_GET_PORT_STATUS 0x02
#define TI_GET_PORT_DEV_INFO 0x03
#define TI_GET_CONFIG 0x04
#define TI_SET_CONFIG 0x05
#define TI_OPEN_PORT 0x06
#define TI_CLOSE_PORT 0x07
#define TI_START_PORT 0x08
#define TI_STOP_PORT 0x09
#define TI_TEST_PORT 0x0A
#define TI_PURGE_PORT 0x0B
#define TI_RESET_EXT_DEVICE 0x0C
#define TI_WRITE_DATA 0x80
#define TI_READ_DATA 0x81
#define TI_REQ_TYPE_CLASS 0x82
/* Bits per character */
#define TI_UART_5_DATA_BITS 0x00
#define TI_UART_6_DATA_BITS 0x01
#define TI_UART_7_DATA_BITS 0x02
#define TI_UART_8_DATA_BITS 0x03
/* Parity */
#define TI_UART_NO_PARITY 0x00
#define TI_UART_ODD_PARITY 0x01
#define TI_UART_EVEN_PARITY 0x02
#define TI_UART_MARK_PARITY 0x03
#define TI_UART_SPACE_PARITY 0x04
/* Stop bits */
#define TI_UART_1_STOP_BITS 0x00
#define TI_UART_1_5_STOP_BITS 0x01
#define TI_UART_2_STOP_BITS 0x02
/* Modem control */
#define TI_MCR_LOOP 0x04
#define TI_MCR_DTR 0x10
#define TI_MCR_RTS 0x20
/* Read/Write data */
#define TI_RW_DATA_ADDR_SFR 0x10
#define TI_RW_DATA_ADDR_IDATA 0x20
#define TI_RW_DATA_ADDR_XDATA 0x30
#define TI_RW_DATA_ADDR_CODE 0x40
#define TI_RW_DATA_ADDR_GPIO 0x50
#define TI_RW_DATA_ADDR_I2C 0x60
#define TI_RW_DATA_ADDR_FLASH 0x70
#define TI_RW_DATA_ADDR_DSP 0x80
#define TI_RW_DATA_UNSPECIFIED 0x00
#define TI_RW_DATA_BYTE 0x01
#define TI_RW_DATA_WORD 0x02
#define TI_RW_DATA_DOUBLE_WORD 0x04
#define TI_TRANSFER_TIMEOUT 2
/************************************************************************/
struct ti3410_transport {
struct transport base;
struct usb_dev_handle *hnd;
};
#define USB_FET_VENDOR 0x0451
#define USB_FET_PRODUCT 0xf430
#define USB_FET_INTERFACE 0
#define USB_FET_IN_EP 0x81
#define USB_FET_OUT_EP 0x01
#define USB_FET_INT_EP 0x83
#define TIMEOUT 1000
#define READ_TIMEOUT 5000
static int open_device(struct ti3410_transport *tr,
struct usb_device *dev)
{
struct usb_dev_handle *hnd;
hnd = usb_open(dev);
if (!hnd) {
pr_error("ti3410: failed to open USB device");
return -1;
}
#if defined(__linux__)
if (usb_detach_kernel_driver_np(hnd, USB_FET_INTERFACE) < 0)
pr_error("ti3410: warning: can't "
"detach kernel driver");
#endif
/* This device has two configurations -- we need the one which
* has two bulk endpoints and a control.
*/
if (dev->config->bConfigurationValue == TI_BOOT_CONFIG) {
printc_dbg("TI3410 device is in boot config, "
"setting active\n");
if (usb_set_configuration(hnd, TI_ACTIVE_CONFIG) < 0) {
pr_error("ti3410: failed to set active config");
usb_close(hnd);
return -1;
}
}
if (usb_claim_interface(hnd, USB_FET_INTERFACE) < 0) {
pr_error("ti3410: can't claim interface");
usb_close(hnd);
return -1;
}
tr->hnd = hnd;
return 0;
}
static int set_termios(struct ti3410_transport *tr)
{
static const uint8_t tios_data[10] = {
0x00, 0x02, /* 460800 bps */
0x60, 0x00, /* flags = ENABLE_MS_INTS | AUTO_START_DMA */
TI_UART_8_DATA_BITS,
TI_UART_NO_PARITY,
TI_UART_1_STOP_BITS,
0x00, /* cXon */
0x00, /* cXoff */
0x00 /* UART mode = RS232 */
};
if (usb_control_msg(tr->hnd,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
TI_SET_CONFIG,
0,
TI_UART1_PORT, (char *)tios_data, sizeof(tios_data), TIMEOUT) < 0) {
pr_error("ti3410: TI_SET_CONFIG failed");
return -1;
}
return 0;
}
static int set_mcr(struct ti3410_transport *tr)
{
static const uint8_t wb_data[9] = {
TI_RW_DATA_ADDR_XDATA,
TI_RW_DATA_BYTE,
1, /* byte count */
0x00, 0x00, 0xff, 0xa4, /* base address */
TI_MCR_LOOP | TI_MCR_RTS | TI_MCR_DTR, /* mask */
TI_MCR_RTS | TI_MCR_DTR /* data */
};
if (usb_control_msg(tr->hnd,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
TI_WRITE_DATA,
0,
TI_RAM_PORT, (char *)wb_data, sizeof(wb_data), TIMEOUT) < 0) {
pr_error("ti3410: TI_SET_CONFIG failed");
return -1;
}
return 0;
}
static int do_open_start(struct ti3410_transport *tr)
{
if (set_termios(tr) < 0)
return -1;
if (set_mcr(tr) < 0)
return -1;
if (usb_control_msg(tr->hnd,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
TI_OPEN_PORT,
TI_PIPE_MODE_CONTINOUS | TI_PIPE_TIMEOUT_ENABLE |
(TI_TRANSFER_TIMEOUT << 2),
TI_UART1_PORT, NULL, 0, TIMEOUT) < 0) {
pr_error("ti3410: TI_OPEN_PORT failed");
return -1;
}
if (usb_control_msg(tr->hnd,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
TI_START_PORT,
0,
TI_UART1_PORT, NULL, 0, TIMEOUT) < 0) {
pr_error("ti3410: TI_START_PORT failed");
return -1;
}
return 0;
}
static int interrupt_flush(struct ti3410_transport *tr)
{
uint8_t buf[2];
return usb_interrupt_read(tr->hnd, USB_FET_INT_EP,
(char *)buf, 2, TIMEOUT);
}
static int setup_port(struct ti3410_transport *tr)
{
interrupt_flush(tr);
if (do_open_start(tr) < 0)
return -1;
if (usb_control_msg(tr->hnd,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
TI_PURGE_PORT,
TI_PURGE_INPUT,
TI_UART1_PORT, NULL, 0, TIMEOUT) < 0) {
pr_error("ti3410: TI_PURGE_PORT (input) failed");
return -1;
}
interrupt_flush(tr);
interrupt_flush(tr);
if (usb_control_msg(tr->hnd,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
TI_PURGE_PORT,
TI_PURGE_OUTPUT,
TI_UART1_PORT, NULL, 0, TIMEOUT) < 0) {
pr_error("ti3410: TI_PURGE_PORT (output) failed");
return -1;
}
interrupt_flush(tr);
if (usb_clear_halt(tr->hnd, USB_FET_IN_EP) < 0 ||
usb_clear_halt(tr->hnd, USB_FET_OUT_EP) < 0) {
pr_error("ti3410: failed to clear halt status");
return -1;
}
if (do_open_start(tr) < 0)
return -1;
return 0;
}
static void teardown_port(struct ti3410_transport *tr)
{
if (usb_control_msg(tr->hnd,
USB_TYPE_VENDOR | USB_RECIP_DEVICE,
TI_CLOSE_PORT,
0,
TI_UART1_PORT, NULL, 0, TIMEOUT) < 0)
pr_error("ti3410: warning: TI_CLOSE_PORT failed");
}
static int ti3410_send(transport_t tr_base, const uint8_t *data, int len)
{
struct ti3410_transport *tr = (struct ti3410_transport *)tr_base;
int sent;
while (len) {
sent = usb_bulk_write(tr->hnd, USB_FET_OUT_EP,
(char *)data, len, TIMEOUT);
if (sent < 0) {
pr_error("ti3410: can't send data");
return -1;
}
len -= sent;
}
return 0;
}
static int ti3410_recv(transport_t tr_base, uint8_t *databuf, int max_len)
{
struct ti3410_transport *tr = (struct ti3410_transport *)tr_base;
int rlen;
rlen = usb_bulk_read(tr->hnd, USB_FET_IN_EP, (char *)databuf,
max_len, READ_TIMEOUT);
if (rlen < 0) {
pr_error("ti3410: can't receive data");
return -1;
}
return rlen;
}
static void ti3410_destroy(transport_t tr_base)
{
struct ti3410_transport *tr = (struct ti3410_transport *)tr_base;
teardown_port(tr);
free(tr);
}
transport_t ti3410_open(const char *devpath, const char *requested_serial)
{
struct ti3410_transport *tr = malloc(sizeof(*tr));
struct usb_device *dev;
if (!tr) {
pr_error("ti3410: can't allocate memory");
return NULL;
}
tr->base.destroy = ti3410_destroy;
tr->base.send = ti3410_send;
tr->base.recv = ti3410_recv;
usb_init();
usb_find_busses();
usb_find_devices();
if (devpath)
dev = usbutil_find_by_loc(devpath);
else
dev = usbutil_find_by_id(USB_FET_VENDOR, USB_FET_PRODUCT,
requested_serial);
if (!dev) {
free(tr);
return NULL;
}
if (open_device(tr, dev) < 0) {
printc_err("ti3410: failed to open TI3410 device\n");
return NULL;
}
if (setup_port(tr) < 0) {
printc_err("ti3410: failed to set up port\n");
teardown_port(tr);
usb_close(tr->hnd);
free(tr);
return NULL;
}
return (transport_t)tr;
}

29
drivers/ti3410.h Normal file
View File

@ -0,0 +1,29 @@
/* MSPDebug - debugging tool for MSP430 MCUs
* Copyright (C) 2009-2011 Daniel Beer
*
* 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
*/
#ifndef TI3410_H_
#define TI3410_H_
#include "transport.h"
/* This function is for opening an eZ430-F2013 or FET430UIF device via
* libusb.
*/
transport_t ti3410_open(const char *dev_path, const char *requested_serial);
#endif

View File

@ -31,6 +31,7 @@ static const char *device_help(const struct usb_device *dev)
const char *help;
} info[] = {
{0x0451, 0xf432, "eZ430-RF2500"},
{0x0451, 0xf430, "FET430UIF"},
{0x15ba, 0x0002, "Olimex MSP-JTAG-TINY (v1)"},
{0x15ba, 0x0031, "Olimex MSP-JTAG-TINY (v2)"}
};