Hi !
This is a simple jtag-driver over the serial cable (it is rare, but
was given to me :)
TCK == !RTS (out);
TMS == !DTR (out);
TDI == TXD (out, control by break-signal);
TDO == !CTS (in);
led and reset - not available.
This code is working (tested on Linux - ARM7TDMI core-id was
indicated), but currently mainly for reviewing.
I think it can't break anyone, nevertheless configure-patch is separated.
Windows-part also should work, it is copy-paste from other my project.
But now I can't test it without Windows.
diff --git a/src/jtag/Makefile.am b/src/jtag/Makefile.am
index ba722c6..7db62a0 100644
--- a/src/jtag/Makefile.am
+++ b/src/jtag/Makefile.am
@@ -29,6 +29,9 @@ endif
if PARPORT
DRIVERFILES += parport.c
endif
+if SERPORT
+DRIVERFILES += serport.c
+endif
if DUMMY
DRIVERFILES += dummy.c
endif
diff --git a/src/jtag/interfaces.c b/src/jtag/interfaces.c
index 778c4e3..0a7847c 100644
--- a/src/jtag/interfaces.c
+++ b/src/jtag/interfaces.c
@@ -49,6 +49,9 @@ extern jtag_interface_t minidummy_interface;
#if BUILD_PARPORT == 1
extern jtag_interface_t parport_interface;
#endif
+#if BUILD_SERPORT == 1
+extern jtag_interface_t serport_interface;
+#endif
#if BUILD_DUMMY == 1
extern jtag_interface_t dummy_interface;
#endif
@@ -103,6 +106,9 @@ jtag_interface_t *jtag_interfaces[] = {
#elif defined(BUILD_MINIDRIVER_DUMMY)
&minidummy_interface,
#else // standard drivers
+#if BUILD_SERPORT == 1
+ &serport_interface,
+#endif
#if BUILD_PARPORT == 1
&parport_interface,
#endif
diff --git a/src/jtag/serport.c b/src/jtag/serport.c
new file mode 100644
index 0000000..6150f95
--- /dev/null
+++ b/src/jtag/serport.c
@@ -0,0 +1,834 @@
+/**************************************************************************
+ * Copyright (C) 2009 by Leo Yuriev, Cronyx Engineering *
+ * [email protected], [email protected] *
+ * *
+ * 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 3 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, see <http://www.gnu.org/licenses/>. *
+ * *
+ **************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "interface.h"
+#include "bitbang.h"
+
+/* low level command set
+ */
+static int serport_read(void);
+static void serport_write(int tck, int tms, int tdi);
+static void serport_reset(int trst, int srst);
+static void serport_led(int on);
+
+static int serport_speed(int speed);
+static int serport_register_commands(struct command_context_s* cmd_ctx);
+static int serport_init(void);
+static int serport_quit(void);
+
+/* interface commands */
+static int serport_handle_port_command(struct command_context_s* cmd_ctx, char* cmd, char** args, int argc);
+static int serport_handle_delay_command(struct command_context_s* cmd_ctx, char* cmd, char** args, int argc);
+
+jtag_interface_t serport_interface =
+{
+ .name = "serport",
+
+ .execute_queue = bitbang_execute_queue,
+
+ .speed = serport_speed,
+ .register_commands = serport_register_commands,
+ .init = serport_init,
+ .quit = serport_quit,
+};
+
+static bitbang_interface_t serport_bitbang =
+{
+ .read = serport_read,
+ .write = serport_write,
+ .reset = serport_reset,
+ .blink = serport_led
+};
+
+/* ----------------------------------------------------------------------- */
+
+#if defined(__WIN32__) || defined(WIN32)
+HINSTANCE hNtDll;
+int (__stdcall * pNtQueryPerformanceCounter)(LARGE_INTEGER* PerformanceCounter,
+ LARGE_INTEGER* PerformanceFrequency);
+LARGE_INTEGER PerformanceFrequency;
+
+/* iotcls without parameters */
+# define IOCTL_SERIAL_SET_BREAK_ON 0x001b0010ul
+# define IOCTL_SERIAL_SET_BREAK_OFF 0x001b0014ul
+# define IOCTL_SERIAL_SET_DTR 0x001b0024ul
+# define IOCTL_SERIAL_CLR_DTR 0x001b0028ul
+# define IOCTL_SERIAL_SET_RTS 0x001b0030ul
+# define IOCTL_SERIAL_CLR_RTS 0x001b0034ul
+
+/* need a pointer to ulong */
+# define IOCTL_SERIAL_GET_MODEMSTATUS 0x001b0068
+
+/* bits for IOCTL_SERIAL_GET_MODEMSTATUS */
+# define SERIAL_DTR_STATE 0x00000001ul
+# define SERIAL_RTS_STATE 0x00000002ul
+# define SERIAL_CTS_STATE 0x00000010ul
+# define SERIAL_DSR_STATE 0x00000020ul
+# define SERIAL_RI_STATE 0x00000040ul
+# define SERIAL_DCD_STATE 0x00000080ul
+
+static int jtag_serialxp_flag, serport_is_nt;
+# if 0 /* LY: TODO - SerialXp TAP-minidriver */
+int serialxp_tap_probe(HANDLE h);
+int serialxp_set_delay_100ns(int ns);
+
+/* SerialXp driver http://leo.yuriev.ru/serialxp */
+# define IOCTL_SERIALXP_SIGN 0x001b24c4ul
+# define IOCTL_SERIALXP_AVR_IO 0x001b24c8ul
+# define IOCTL_SERIALXP_AVR_DELAY 0x001b24ccul
+# define IOCTL_SERIALXP_JTAG_DELAY 0x001be4d8ul
+# define IOCTL_SERIALXP_JTAG_RESET 0x001be4dcul
+# define IOCTL_SERIALXP_JTAG_STEP 0x001be4e0ul
+# define IOCTL_SERIALXP_JTAG_IOP 0x001be4e4ul
+# define IOCTL_SERIALXP_JTAG_DATA 0x001be4e8ul
+# define IOCTL_SERIALXP_JTAG_SC1 0x001be4ecul
+# define IOCTL_SERIALXP_JTAG_SC1_DATA 0x001be4f0ul
+# define IOCTL_SERIALXP_JTAG_BYPASS 0x001be4f8ul
+# else
+# define serialxp_tap_probe(handle) (0)
+# endif /* SerialXp */
+#elif defined(__DJGPP__)
+# include <pc.h>
+static __inline unsigned char serport_inb(unsigned short port)
+{
+ return inportb(port);
+}
+
+
+static __inline void serport_outb(unsigned char data, unsigned short port)
+{
+ outportb(port, data);
+}
+
+
+#else
+# include <sys/io.h>
+# if 0 /* LY: avoid linking with libcap. */
+# include <sys/capability.h>
+# endif
+# include <sys/ioctl.h>
+# include <termios.h>
+# if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+# include <machine/sysarch.h>
+# include <machine/cpufunc.h>
+# define ioperm(startport, length, enable) \
+ i386_set_ioperm( (startport), (length), (enable) )
+# define serport_outb(data, port) outb(port, data)
+# else
+# define serport_outb(data, port) outb(data, port)
+# endif /* __FreeBSD__ */
+# define serport_inb(port) inb(port)
+#endif
+
+/* configuration */
+static int serport_ioport, serport_portnum = -1, jtag_delay_100ns = 25;
+
+/* interface variables
+ */
+static uint64_t jtag_delay_timestamp;
+static uint8_t serport_tms, serport_tdi, serport_tck;
+
+#if defined(__WIN32__) || defined(WIN32)
+static HANDLE device_handle;
+static DCB saved_mode;
+#else
+uint8_t serport_lcr, serport_mcr;
+uint8_t saved_lcr, saved_mcr, saved_ier;
+# ifdef __DJGPP__
+# define DIRECT_IO_OK(c) 1
+# else
+# define DIRECT_IO_OK(c) (serport_ioport)
+int device_handle;
+struct termios saved_mode;
+# endif /* __DJGPP__ */
+#endif
+
+/* -----------------------------------------------------------------------
+ * 16550 UART registers
+ */
+#define DATA(p) ( (p) + 0 )
+#define IER(p) ( (p) + 1 ) /* RW- interrupt enable register */
+#define IIR(p) ( (p) + 2 ) /* R - interrupt identification */
+#define LCR(p) ( (p) + 3 ) /* RW- line control register */
+#define MCR(p) ( (p) + 4 ) /* RW- modem control register */
+#define LSR(p) ( (p) + 5 ) /* RW- line status register */
+#define MSR(p) ( (p) + 6 ) /* RW- modem status register */
+
+/*
+ * Line control register
+ */
+#define LCR_5BITS 0x00 /* character length: 5 bits */
+#define LCR_6BITS 0x01 /* character length: 6 bits */
+#define LCR_7BITS 0x02 /* character length: 7 bits */
+#define LCR_8BITS 0x03 /* character length: 8 bits */
+
+#define LCR_STOPB 0x04 /* use 2 stop bits */
+#define LCR_PENAB 0x08 /* parity enable */
+#define LCR_PEVEN 0x10 /* even parity */
+#define LCR_PFORCE 0x20 /* force parity */
+#define LCR_SBREAK 0x40 /* break control */
+#define LCR_DLAB 0x80 /* divisor latch access bit */
+
+/*
+ * Modem control register
+ */
+#define MCR_DTR 0x01 /* control DTR output */
+#define MCR_RTS 0x02 /* control RTS output */
+#define MCR_DRS 0x04 /* control OUT1 output */
+#define MCR_IENABLE 0x08 /* control OUT2 output, used as
+ * global interrupt enable in PCs */
+#define MCR_LOOPBACK 0x10 /* set local loopback mode */
+
+/*
+ * Modem status register
+ */
+#define MSR_DCTS 0x01 /* CTS changed */
+#define MSR_DDSR 0x02 /* DSR changed */
+#define MSR_TERI 0x04 /* RI changed from 0 to 1 */
+#define MSR_DDCD 0x08 /* DCD changed */
+#define MSR_CTS 0x10 /* CTS input */
+#define MSR_DSR 0x20 /* DSR input */
+#define MSR_RI 0x40 /* RI input */
+#define MSR_DCD 0x80 /* DCD input */
+
+static uint64_t serport_get_100ns(void)
+{
+#if defined(__WIN32__) || defined(WIN32)
+ LARGE_INTEGER timestamp;
+ if (pNtQueryPerformanceCounter)
+ {
+ pNtQueryPerformanceCounter(×tamp, 0);
+ }
+ else
+ {
+ FILETIME filetime;
+ GetSystemTimeAsFileTime(&filetime);
+ timestamp.HighPart = filetime.dwHighDateTime;
+ timestamp.LowPart = filetime.dwLowDateTime;
+ }
+ return timestamp.QuadPart;
+#else
+ struct timeval tv;
+
+ gettimeofday(&tv, NULL);
+ return tv.tv_sec * 10000000ull + tv.tv_usec * 10;
+#endif
+}
+
+
+static uint64_t serport_delay(void)
+{
+ if (jtag_delay_100ns > 0)
+ {
+ uint64_t target = jtag_delay_timestamp + jtag_delay_100ns;
+ for ( ; ;)
+ {
+ int64_t now, delta;
+
+ now = serport_get_100ns();
+ delta = target - now;
+ if (delta <= 0)
+ return now;
+ if (delta > 10000 /* LY: TODO - use sched_rr_get_interval(). */)
+ {
+#if defined(__WIN32__) || defined(WIN32)
+ Sleep(delta / 10000);
+#else
+ usleep(delta / 10);
+#endif
+ }
+ /* LY: TODO - be more portable in busy-loop... */
+ __asm __volatile("pause");
+ __asm __volatile("pause");
+ __asm __volatile("pause");
+ __asm __volatile("pause");
+ }
+ }
+ return serport_get_100ns();
+}
+
+
+/* ----------------------------------------------------------------------- */
+
+static int serport_read(void)
+{
+ serport_delay();
+
+ /* LY: TDO (inverted CTS). */
+#if defined(__WIN32__) || defined(WIN32)
+ if (serport_is_nt)
+ {
+ DWORD val, unused;
+ DeviceIoControl(device_handle, IOCTL_SERIAL_GET_MODEMSTATUS, NULL, 0, &val, sizeof(val), &unused, NULL);
+ return !(val & SERIAL_CTS_STATE);
+ }
+ else
+ {
+ DWORD val;
+ GetCommModemStatus(device_handle, &val);
+ return !(val & MS_CTS_ON);
+ }
+#else
+ if ( DIRECT_IO_OK(c) )
+ {
+ unsigned msr = serport_inb( MSR(serport_ioport) );
+ return !(msr & MSR_CTS);
+ }
+ else
+ {
+ int val;
+ ioctl(device_handle, TIOCMGET, &val);
+ return !(val & TIOCM_CTS);
+ }
+#endif
+}
+
+
+static void serport_write(int tck, int tms, int tdi)
+{
+#if defined(__WIN32__) || defined(WIN32)
+ if (!serport_tck && tck)
+ {
+ serport_tck = 1;
+ /* LY: TCK (0->1) signal control (negated RTS). */
+ serport_delay();
+ if (serport_is_nt)
+ {
+ DWORD unused;
+ DeviceIoControl(device_handle, IOCTL_SERIAL_CLR_RTS, NULL, 0, NULL, 0, &unused, NULL);
+ }
+ else
+ {
+ EscapeCommFunction(device_handle, CLRRTS);
+ }
+ jtag_delay_timestamp = serport_get_100ns();
+ }
+ if ( (tms != 0) != serport_tms )
+ {
+ serport_tms ^= 1;
+ /* LY: TMS (negated DTR). */
+ if (serport_is_nt)
+ {
+ DWORD unused;
+ DeviceIoControl(device_handle, serport_tms ? IOCTL_SERIAL_CLR_DTR : IOCTL_SERIAL_SET_DTR, NULL, 0, NULL, 0,
+ &unused, NULL);
+ }
+ else
+ {
+ EscapeCommFunction(device_handle, serport_tms ? CLRDTR : SETDTR);
+ }
+ }
+ if ( (tdi != 0) != serport_tdi )
+ {
+ serport_tdi ^= 1;
+ /* LY: TDI (from TXD, no invertion). */
+ if (serport_is_nt)
+ {
+ DWORD unused;
+ DeviceIoControl(device_handle, serport_tdi ? IOCTL_SERIAL_SET_BREAK_OFF : IOCTL_SERIAL_SET_BREAK_ON, NULL,
+ 0, NULL, 0, &unused, NULL);
+ }
+ else
+ {
+ EscapeCommFunction(device_handle, serport_tdi ? CLRBREAK : SETBREAK);
+ }
+ }
+ if (serport_tck && !tck)
+ {
+ serport_tck = 0;
+ /* LY: TCK (1->0) signal control (negated RTS). */
+ serport_delay();
+ if (serport_is_nt)
+ {
+ DWORD unused;
+ DeviceIoControl(device_handle, IOCTL_SERIAL_SET_RTS, NULL, 0, NULL, 0, &unused, NULL);
+ }
+ else
+ {
+ EscapeCommFunction(device_handle, SETRTS);
+ }
+ jtag_delay_timestamp = serport_get_100ns();
+ }
+#else
+ if (!serport_tck && tck)
+ {
+ serport_tck = 1;
+ /* LY: TCK (0->1) signal control (negated RTS). */
+ serport_delay();
+ if ( DIRECT_IO_OK(c) )
+ {
+ serport_mcr &= ~MCR_RTS;
+ serport_outb( serport_mcr, MCR(serport_ioport) );
+ }
+ else
+ {
+ int val = TIOCM_RTS;
+ ioctl(device_handle, TIOCMBIC, &val);
+ }
+ jtag_delay_timestamp = serport_get_100ns();
+ }
+ if ( (tms != 0) != serport_tms )
+ {
+ serport_tms ^= 1;
+ /* LY: TMS (negated DTR). */
+ if ( DIRECT_IO_OK(c) )
+ {
+ serport_mcr ^= MCR_DTR;
+ serport_outb( serport_mcr, MCR(serport_ioport) );
+ }
+ else
+ {
+ int val = TIOCM_DTR;
+ ioctl(device_handle, serport_tms ? TIOCMBIC : TIOCMBIS, &val);
+ }
+ }
+ if ( (tdi != 0) != serport_tdi )
+ {
+ serport_tdi ^= 1;
+ /* LY: TDI (from TXD, no invertion). */
+ if ( DIRECT_IO_OK(c) )
+ {
+ serport_lcr ^= LCR_SBREAK;
+ serport_outb( serport_lcr, LCR(serport_ioport) );
+ }
+ else
+ {
+ ioctl(device_handle, serport_tdi ? TIOCCBRK : TIOCSBRK, 0);
+ }
+ }
+ if (serport_tck && !tck)
+ {
+ serport_tck = 0;
+ /* LY: TCK (1->0) signal control (negated RTS). */
+ serport_delay();
+ if ( DIRECT_IO_OK(c) )
+ {
+ serport_mcr |= MCR_RTS;
+ serport_outb( serport_mcr, MCR(serport_ioport) );
+ }
+ else
+ {
+ int val = TIOCM_RTS;
+ ioctl(device_handle, TIOCMBIS, &val);
+ }
+ jtag_delay_timestamp = serport_get_100ns();
+ }
+#endif
+}
+
+
+/* (1) assert or (0) deassert reset lines */
+static void serport_reset(int trst, int srst)
+{
+ LOG_DEBUG("trst: %i, srst: %i", trst, srst);
+ /* LY: TODO ? */
+}
+
+
+/* turn LED on serport adapter on (1) or off (0) */
+static void serport_led(int on)
+{
+ /* LY: TODO ? */
+}
+
+
+static int serport_speed(int speed)
+{
+ return ERROR_OK;
+}
+
+
+static int serport_register_commands(struct command_context_s* cmd_ctx)
+{
+ register_command(cmd_ctx, NULL, "serport_port", serport_handle_port_command,
+#if defined(__WIN32__) || defined(WIN32) || defined(__DJGPP__)
+ COMMAND_CONFIG, "either the address of the I/O port or the number of the 'COM#' device");
+#else
+ COMMAND_CONFIG, "either the address of the I/O port or the number of the '/dev/ttyS#' device");
+#endif
+ register_command(cmd_ctx, NULL, "serport_delay", serport_handle_delay_command,
+ COMMAND_CONFIG, "I/O-delay in 100ns ticks");
+ return ERROR_OK;
+}
+
+
+#if SERPORT_USE_GIVEIO == 1
+static int serport_get_giveio_access(void)
+{
+ HANDLE h;
+ OSVERSIONINFO version;
+
+ version.dwOSVersionInfoSize = sizeof version;
+ if ( !GetVersionEx(&version) )
+ {
+ errno = EINVAL;
+ return -1;
+ }
+ if (version.dwPlatformId != VER_PLATFORM_WIN32_NT)
+ return 0;
+
+ h = CreateFile("\\\\.\\giveio", GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
+ if (h == INVALID_HANDLE_VALUE)
+ {
+ errno = ENODEV;
+ return -1;
+ }
+
+ CloseHandle(h);
+
+ return 0;
+}
+#endif
+
+static int serport_init(void)
+{
+ char devname[256];
+
+ if (device_handle > 0)
+ {
+ LOG_ERROR("device is already opened");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ LOG_DEBUG("...open");
+
+#if defined(__WIN32__) || defined(WIN32)
+ DCB new_mode;
+ OSVERSIONINFO win_version;
+#elif !defined(__DJGPP__)
+ struct termios new_mode;
+#endif
+#if defined(__WIN32__) || defined(WIN32)
+ jtag_serialxp_flag = 0;
+ serport_is_nt = 0;
+ win_version.dwOSVersionInfoSize = sizeof(win_version);
+ if (GetVersionEx(&win_version)
+ && win_version.dwPlatformId == VER_PLATFORM_WIN32_NT)
+ {
+ serport_is_nt = 1;
+ LOG_INFO("Using Windows NT/2000/XP interface");
+
+ hNtDll = LoadLibrary("ntdll.dll");
+ if (hNtDll)
+ {
+ pNtQueryPerformanceCounter = ( int (__stdcall*)(LARGE_INTEGER *, LARGE_INTEGER*) )
+ GetProcAddress(hNtDll, "NtQueryPerformanceCounter");
+
+ if (pNtQueryPerformanceCounter)
+ {
+ LARGE_INTEGER unused;
+ if (pNtQueryPerformanceCounter(&unused,
+ &PerformanceFrequency) < 0 || PerformanceFrequency.QuadPart == 0)
+ pNtQueryPerformanceCounter = 0;
+ else
+ {
+ LOG_INFO("Using ntdll.NtQueryPerformanceCounter");
+ }
+ }
+ }
+ }
+ else
+ {
+ LOG_INFO("Using Windows 95/98/Me interface");
+ }
+
+ if (serport_portnum < 1)
+ {
+ /* LY: TODO - direct i/o */
+ LOG_ERROR("COM-port number not configured!");
+ return ERROR_JTAG_INIT_FAILED;
+#if SERPORT_USE_GIVEIO == 1
+ if (serport_get_giveio_access() != 0)
+ {
+ }
+#endif
+ }
+ else
+ {
+ /* Open port */
+ sprintf(devname, "\\\\.\\COM%u", serport_portnum);
+ device_handle = CreateFile(devname, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
+ if (device_handle == INVALID_HANDLE_VALUE)
+ {
+ LOG_ERROR("cannot open device. check it exists and that user read and write rights are set. errno=%d", err);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ /* Look for SerialXp driver. */
+ if ( serport_is_nt && serialxp_tap_probe(device_handle) )
+ {
+ jtag_serialxp_flag = 1;
+ LOG_INFO("SerialXP driver detected");
+ }
+
+ /* Set serial attributes */
+ memset( &saved_mode, 0, sizeof(saved_mode) );
+ if ( !GetCommState(device_handle, &saved_mode) )
+ {
+ LOG_ERROR("%s: failed GetCommState()", devname);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+
+ new_mode = saved_mode;
+ new_mode.BaudRate = CBR_115200;
+ new_mode.ByteSize = 8;
+ new_mode.StopBits = ONESTOPBIT;
+ new_mode.Parity = 0;
+ new_mode.fParity = FALSE;
+ new_mode.fOutX = FALSE;
+ new_mode.fInX = FALSE;
+ new_mode.fOutxCtsFlow = FALSE;
+ new_mode.fOutxDsrFlow = FALSE;
+ new_mode.fRtsControl = RTS_CONTROL_ENABLE;
+ new_mode.fNull = FALSE;
+ new_mode.fAbortOnError = FALSE;
+ new_mode.fBinary = TRUE;
+ if ( !SetCommState(device_handle, &new_mode) )
+ {
+ LOG_ERROR("%s: failed SetCommState()", devname);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+ }
+#elif defined(__DJGPP__)
+ /* Open port */
+ if (serport_ioport == 0)
+ {
+ static const unsigned four[4] = { 0x3f8, 0x2f8, 0x3e8, 0x2e8 };
+ if (serport_portnum == 0)
+ {
+ LOG_ERROR("COM-port not configured!");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+ if (serport_portnum > 4)
+ {
+ LOG_ERROR("COM-ports higher than COM4 should be configured by i/o-adress");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+ serport_ioport = four[serport_portnum - 1];
+ }
+
+ /* Set serial attributes */
+ serport_outb( 0, IER(serport_ioport) );
+ serport_outb( serport_lcr = LCR_8BITS, LCR(serport_ioport) );
+ serport_outb( serport_mcr = MCR_IENABLE | MCR_RTS, MCR(serport_ioport) );
+#else
+ device_handle = -1;
+ if (serport_ioport)
+ {
+#ifdef CAP_SYS_RAWIO
+ cap_t cap;
+ cap_flag_value_t value;
+
+ cap = cap_get_proc();
+ if (!cap)
+ {
+ LOG_ERROR("cap_get_proc() failed, err %d", errno);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+ if (cap_get_flag(cap, CAP_SYS_RAWIO, CAP_PERMITTED, &value) < 0)
+ {
+ LOG_ERROR("cap_get_flag() failed, err %d", errno);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+ if (value != CAP_SET)
+ {
+ LOG_ERROR("missing privileges for direct I/O");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+#endif /* CAP_SYS_RAWIO */
+ if ( ( (serport_ioport > 0x400 - 8) ? iopl(3) : ioperm(serport_ioport, 8, 1) ) != 0 )
+ {
+ LOG_ERROR("missing privileges for direct I/O");
+ return ERROR_JTAG_INIT_FAILED;
+ }
+ LOG_INFO("Try using direct UART-I/O at 0x%04x", serport_ioport);
+ saved_mcr = serport_inb( MCR(serport_ioport) );
+ saved_lcr = serport_inb( LCR(serport_ioport) );
+ saved_ier = serport_inb( IER(serport_ioport) );
+ serport_outb( 0, IER(serport_ioport) );
+ serport_outb( serport_lcr = LCR_8BITS, LCR(serport_ioport) );
+ serport_outb( serport_mcr = MCR_IENABLE | MCR_RTS, MCR(serport_ioport) );
+ }
+ else
+ {
+ /* Open port */
+ sprintf(devname, "/dev/ttyS%u", serport_portnum);
+ device_handle = open(devname, O_RDWR | O_NONBLOCK);
+ if (device_handle < 0)
+ {
+ LOG_ERROR("cannot open device. check it exists and that user read and write rights are set. errno=%d",
+ errno);
+ return ERROR_JTAG_INIT_FAILED;
+ }
+ /* Set serial attributes */
+ memset( &saved_mode, 0, sizeof(saved_mode) );
+ tcgetattr(device_handle, &saved_mode);
+ new_mode = saved_mode;
+ cfmakeraw(&new_mode);
+ new_mode.c_iflag |= IGNBRK;
+ tcsetattr(device_handle, TCSANOW, &new_mode);
+ }
+#endif
+ jtag_delay_timestamp = serport_get_100ns();
+ serport_reset(0, 0);
+ serport_write(0, 0, 0);
+ serport_led(1);
+
+ bitbang_interface = &serport_bitbang;
+
+ return ERROR_OK;
+}
+
+
+static int serport_quit(void)
+{
+ serport_write(0, 1, 1);
+ serport_led(0);
+
+#if defined(__WIN32__) || defined(WIN32)
+ if (pNtQueryPerformanceCounter)
+ pNtQueryPerformanceCounter = 0;
+ if (hNtDll)
+ {
+ FreeLibrary(hNtDll);
+ hNtDll = 0;
+ }
+ if (device_handle != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(device_handle);
+ device_handle = INVALID_HANDLE_VALUE;
+ }
+#elif !defined(__DJGPP__)
+ if ( DIRECT_IO_OK(c) )
+ {
+ unsigned dummy, i;
+ serport_outb( saved_mcr, MCR(serport_ioport) );
+ serport_outb( saved_lcr, MCR(serport_ioport) );
+ for (i = 0; i < 128; i++)
+ {
+ dummy = serport_inb( MSR(serport_ioport) );
+ dummy = serport_inb( LSR(serport_ioport) );
+ dummy = serport_inb( DATA(serport_ioport) );
+ dummy = serport_inb( IIR(serport_ioport) );
+ if (dummy & 1)
+ break;
+ }
+
+ serport_outb( saved_ier, MCR(serport_ioport) );
+ if (serport_ioport > 0x400 - 8)
+ iopl(0);
+ else
+ ioperm(serport_ioport, 8, 0);
+ serport_ioport = 0;
+ }
+
+ if (device_handle > -1)
+ {
+ close(device_handle);
+ device_handle = -1;
+ }
+#else
+#endif
+ return ERROR_OK;
+}
+
+
+static int serport_handle_port_command(struct command_context_s* cmd_ctx, char* cmd, char** args, int argc)
+{
+ if (argc == 1)
+ {
+ /* only if the port wasn't overwritten by cmdline */
+ if (serport_ioport == 0 && serport_portnum < 0)
+ {
+ uint16_t val;
+ int retval = parse_u16(args[0], &val);
+ if (ERROR_OK != retval)
+ return retval;
+ if (val > 100 && (val & 7) == 0 && val < 0xfff8u)
+ {
+ serport_ioport = val;
+ }
+#if defined(__WIN32__) || defined(WIN32) || defined(__DJGPP__)
+ else if (val >= 1 && val <= 100)
+ {
+ serport_portnum = val;
+ }
+ else
+ {
+ LOG_ERROR("Invalid serport COM-port number (1..100) or port-address (0x3f8) was specified: %s", args[0]);
+ return ERROR_FAIL;
+ }
+#else
+ else if (val <= 99)
+ {
+ serport_portnum = val;
+ }
+ else
+ {
+ LOG_ERROR("Invalid serport tty-dev number (0..99) or port-address (0x3f8) was specified: %s", args[0]);
+ return ERROR_FAIL;
+ }
+#endif
+ }
+ else
+ {
+ LOG_ERROR("The serport port was already configured!");
+ return ERROR_FAIL;
+ }
+ }
+
+ if (serport_ioport)
+ command_print(cmd_ctx, "serport i/o-port = 0x%04x", serport_ioport);
+ else if (serport_portnum >= 0)
+#if defined(__WIN32__) || defined(WIN32) || defined(__DJGPP__)
+
+ command_print(cmd_ctx, "serport port = COM%u", serport_portnum);
+#else
+
+ command_print(cmd_ctx, "serport port = /dev/ttyS%u", serport_portnum);
+#endif
+ return ERROR_OK;
+}
+
+
+static int serport_handle_delay_command(struct command_context_s* cmd_ctx, char* cmd, char** args, int argc)
+{
+ if (argc == 1)
+ {
+ int val, retval = parse_int(args[0], &val);
+ if (ERROR_OK != retval)
+ return retval;
+ if (val < 0 || val > 1000)
+ {
+ LOG_ERROR("Invalid serport delay-100ns (0..1000) was specified: %s", args[0]);
+ return ERROR_FAIL;
+ }
+ jtag_delay_100ns = val;
+ }
+
+ if (jtag_delay_100ns < 0)
+ command_print(cmd_ctx, "serport delay = auto");
+ else
+ command_print(cmd_ctx, "serport delay = %u.%u us", jtag_delay_100ns / 10, jtag_delay_100ns % 10);
+ return ERROR_OK;
+}
diff --git a/configure.in b/configure.in
index 99f97da..8235d05 100644
--- a/configure.in
+++ b/configure.in
@@ -315,6 +315,20 @@ AC_ARG_ENABLE(parport_giveio,
[Enable use of giveio for parport (for CygWin only)]),
[parport_use_giveio=$enableval], [parport_use_giveio=])
+AC_ARG_ENABLE(serport,
+ AS_HELP_STRING([--enable-serport], [Enable building the pc serial port driver]),
+ [build_serport=$enableval], [build_serrport=no])
+
+AC_ARG_ENABLE(serport_serialxp,
+ AS_HELP_STRING([--disable-serport-serialxp],
+ [Disable use of SerialXp-extensions for serport (for Windows-2000/XP/2003 x86 only)]),
+ [serport_use_serialxp=$enableval], [serport_use_serialxp=yes])
+
+AC_ARG_ENABLE(serport_giveio,
+ AS_HELP_STRING([--enable-serport-giveio],
+ [Enable use of giveio for serport (for CygWin only)]),
+ [serport_use_giveio=$enableval], [serport_use_giveio=])
+
AC_ARG_ENABLE(ft2232_libftdi,
AS_HELP_STRING([--enable-ft2232_libftdi], [Enable building support for FT2232 based devices using the libftdi driver, opensource alternate of FTD2XX]),
[build_ft2232_libftdi=$enableval], [build_ft2232_libftdi=no])
@@ -512,6 +526,13 @@ case $host in
;;
esac
+if test $build_serport = yes; then
+ build_bitbang=yes
+ AC_DEFINE(BUILD_SERPORT, 1, [1 if you want serport.])
+else
+ AC_DEFINE(BUILD_SERPORT, 0, [0 if you don't want serport.])
+fi
+
if test $build_parport = yes; then
build_bitbang=yes
AC_DEFINE(BUILD_PARPORT, 1, [1 if you want parport.])
@@ -576,6 +597,12 @@ else
AC_DEFINE(PARPORT_USE_GIVEIO, 0, [0 if you don't want parport to use giveio.])
fi
+if test x$serport_use_giveio = xyes; then
+ AC_DEFINE(SERPORT_USE_GIVEIO, 1, [1 if you want serport to use giveio.])
+else
+ AC_DEFINE(SERPORT_USE_GIVEIO, 0, [0 if you don't want serport to use giveio.])
+fi
+
if test $build_bitbang = yes; then
AC_DEFINE(BUILD_BITBANG, 1, [1 if you want a bitbang interface.])
else
@@ -930,6 +957,7 @@ then
fi
AM_CONDITIONAL(RELEASE, test $build_release = yes)
+AM_CONDITIONAL(SERPORT, test $build_serport = yes)
AM_CONDITIONAL(PARPORT, test $build_parport = yes)
AM_CONDITIONAL(DUMMY, test $build_dummy = yes)
AM_CONDITIONAL(GIVEIO, test x$parport_use_giveio = xyes)
_______________________________________________
Openocd-development mailing list
[email protected]
https://lists.berlios.de/mailman/listinfo/openocd-development