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(&timestamp, 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

Reply via email to