diff --git a/Makefile b/Makefile index 0e3471c..9ffcac0 100644 --- a/Makefile +++ b/Makefile @@ -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 \ diff --git a/drivers/fet.c b/drivers/fet.c index baaba2e..235827a 100644 --- a/drivers/fet.c +++ b/drivers/fet.c @@ -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; diff --git a/drivers/ti3410.c b/drivers/ti3410.c new file mode 100644 index 0000000..31970ac --- /dev/null +++ b/drivers/ti3410.c @@ -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 +#include +#include +#include + +#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; +} diff --git a/drivers/ti3410.h b/drivers/ti3410.h new file mode 100644 index 0000000..8ef879e --- /dev/null +++ b/drivers/ti3410.h @@ -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 diff --git a/util/usbutil.c b/util/usbutil.c index f57bc1e..7631857 100644 --- a/util/usbutil.c +++ b/util/usbutil.c @@ -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)"} };