- added myself to copyright on files i remember adding large contributions for over...
[fw/openocd] / src / jtag / parport.c
index e78215e2d85112e7e0cb39d6fe81b9c2a521ebdd..0cfbd81f8bce6e3018d1e4a6a6c2e19e8cad5922 100644 (file)
@@ -2,6 +2,9 @@
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
+ *   Copyright (C) 2008 by Spencer Oliver                                  *
+ *   spen@spen-soft.co.uk                                                  *
+ *                                                                         *
  *   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     *
@@ -27,8 +30,8 @@
 #include "bitbang.h"
 
 /* system includes */
-// -ino: 060521-1036
-#ifdef __FreeBSD__
+/* -ino: 060521-1036 */
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
 
 #include <sys/types.h>
 #include <machine/sysarch.h>
@@ -38,9 +41,7 @@
 
 #else
 
-#ifndef _WIN32
-#include <sys/io.h>
-#else
+#ifdef _WIN32
 #include "errno.h"
 #endif /* _WIN32 */
 
 #include <stdio.h>
 
 #if PARPORT_USE_PPDEV == 1
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+#include <dev/ppbus/ppi.h>
+#include <dev/ppbus/ppbconf.h>
+#define PPRSTATUS      PPIGSTATUS
+#define PPWDATA                PPISDATA
+#else
 #include <linux/parport.h>
 #include <linux/ppdev.h>
+#endif
 #include <fcntl.h>
 #include <sys/ioctl.h>
+#else /* not PARPORT_USE_PPDEV */
+#ifndef _WIN32
+#include <sys/io.h>
+#endif
 #endif
 
 #if PARPORT_USE_GIVEIO == 1
 #if IS_CYGWIN == 1
 #include <windows.h>
 #include <errno.h>
-#undef ERROR
 #endif
 #endif
 
@@ -81,22 +92,40 @@ typedef struct cable_s
        u8 OUTPUT_INVERT;       /* data port bits that should be inverted */
        u8 INPUT_INVERT;        /* status port that should be inverted */
        u8 PORT_INIT;   /* initialize data port with this value */
+       u8 PORT_EXIT;   /* de-initialize data port with this value */
+       u8 LED_MASK;    /* data port bit for LED */
 } cable_t;
 
 cable_t cables[] = 
 {      
-       /* name                                 tdo   trst  tms   tck   tdi   srst  o_inv i_inv init */
-       { "wiggler",                    0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80 },
-       { "old_amt_wiggler",    0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80 },
-       { "chameleon",                  0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00 },
-       { "dlc5",                               0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10 },
-       { "triton",                             0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00 },
-       { NULL,                                 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
+       /* name                                 tdo   trst  tms   tck   tdi   srst  o_inv i_inv init  exit  led */
+       { "wiggler",                    0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x80, 0x00 },
+       { "wiggler2",                   0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x01, 0x80, 0x80, 0x00, 0x20 },
+       { "wiggler_ntrst_inverted",
+                                                       0x80, 0x10, 0x02, 0x04, 0x08, 0x01, 0x11, 0x80, 0x80, 0x80, 0x00 },
+       { "old_amt_wiggler",    0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x11, 0x80, 0x80, 0x80, 0x00 },
+       { "arm-jtag",                   0x80, 0x01, 0x02, 0x04, 0x08, 0x10, 0x01, 0x80, 0x80, 0x80, 0x00 },
+       { "chameleon",                  0x80, 0x00, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
+       { "dlc5",                               0x10, 0x00, 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x10, 0x10, 0x00 },
+       { "triton",                             0x80, 0x08, 0x04, 0x01, 0x02, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00 },
+       { "lattice",                    0x40, 0x10, 0x04, 0x02, 0x01, 0x08, 0x00, 0x00, 0x18, 0x18, 0x00 },
+       { "flashlink",                  0x20, 0x10, 0x02, 0x01, 0x04, 0x20, 0x30, 0x20, 0x00, 0x00, 0x00 },
+/* Altium Universal JTAG cable. Set the cable to Xilinx Mode and wire to target as follows:
+       HARD TCK - Target TCK
+       HARD TMS - Target TMS
+       HARD TDI - Target TDI
+       HARD TDO - Target TDO
+       SOFT TCK - Target TRST
+       SOFT TDI - Target SRST
+*/
+       { "altium",                     0x10, 0x20, 0x04, 0x02, 0x01, 0x80, 0x00, 0x00, 0x10, 0x00, 0x08 },
+       { NULL,                         0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }
 };
 
 /* configuration */
-char* parport_cable;
-unsigned long parport_port;
+char* parport_cable = NULL;
+u16 parport_port;
+static int parport_exit = 0;
 
 /* interface variables
  */
@@ -115,6 +144,7 @@ static unsigned long statusport;
 int parport_read(void);
 void parport_write(int tck, int tms, int tdi);
 void parport_reset(int trst, int srst);
+void parport_led(int on);
 
 int parport_speed(int speed);
 int parport_register_commands(struct command_context_s *cmd_ctx);
@@ -124,6 +154,7 @@ int parport_quit(void);
 /* interface commands */
 int parport_handle_parport_port_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
+int parport_handle_write_on_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc);
 
 jtag_interface_t parport_interface = 
 {
@@ -131,8 +162,6 @@ jtag_interface_t parport_interface =
        
        .execute_queue = bitbang_execute_queue,
 
-       .support_statemove = 0,
-
        .speed = parport_speed, 
        .register_commands = parport_register_commands,
        .init = parport_init,
@@ -143,7 +172,8 @@ bitbang_interface_t parport_bitbang =
 {
        .read = parport_read,
        .write = parport_write,
-       .reset = parport_reset
+       .reset = parport_reset,
+       .blink = parport_led
 };
 
 int parport_read(void)
@@ -162,9 +192,24 @@ int parport_read(void)
                return 0;
 }
 
-void parport_write(int tck, int tms, int tdi)
+static __inline__ void parport_write_data(void)
 {
        u8 output;
+       output = dataport_value ^ cable->OUTPUT_INVERT;
+
+#if PARPORT_USE_PPDEV == 1
+       ioctl(device_handle, PPWDATA, &output);
+#else
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+       outb(dataport, output);
+#else
+       outb(output, dataport);
+#endif
+#endif
+}
+
+void parport_write(int tck, int tms, int tdi)
+{
        int i = jtag_speed + 1;
        
        if (tck)
@@ -182,25 +227,14 @@ void parport_write(int tck, int tms, int tdi)
        else
                dataport_value &= ~cable->TDI_MASK;
                
-       output = dataport_value ^ cable->OUTPUT_INVERT;
-
        while (i-- > 0)
-#if PARPORT_USE_PPDEV == 1
-               ioctl(device_handle, PPWDATA, &output);
-#else
-#ifdef __FreeBSD__
-       outb(dataport, output);
-#else
-       outb(output, dataport);
-#endif
-#endif
+               parport_write_data();
 }
 
 /* (1) assert or (0) deassert reset lines */
 void parport_reset(int trst, int srst)
 {
-       u8 output;
-       DEBUG("trst: %i, srst: %i", trst, srst);
+       LOG_DEBUG("trst: %i, srst: %i", trst, srst);
 
        if (trst == 0)
                dataport_value |= cable->TRST_MASK;
@@ -212,24 +246,22 @@ void parport_reset(int trst, int srst)
        else if (srst == 1)
                dataport_value &= ~cable->SRST_MASK;
        
-       output = dataport_value ^ cable->OUTPUT_INVERT;
+       parport_write_data();
+}
        
-#if PARPORT_USE_PPDEV == 1
-       ioctl(device_handle, PPWDATA, &output);
-#else
-#ifdef __FreeBSD__
-       outb(dataport, output);
-#else
-       outb(output, dataport);
-#endif
-#endif
+/* turn LED on parport adapter on (1) or off (0) */
+void parport_led(int on)
+{
+       if (on)
+               dataport_value |= cable->LED_MASK;
+       else
+               dataport_value &= ~cable->LED_MASK;
 
+       parport_write_data();
 }
 
 int parport_speed(int speed)
 {
-       jtag_speed = speed;
-       
        return ERROR_OK;
 }
 
@@ -239,33 +271,35 @@ int parport_register_commands(struct command_context_s *cmd_ctx)
                COMMAND_CONFIG, NULL);
        register_command(cmd_ctx, NULL, "parport_cable", parport_handle_parport_cable_command,
                COMMAND_CONFIG, NULL);
+       register_command(cmd_ctx, NULL, "parport_write_on_exit", parport_handle_write_on_exit_command,
+               COMMAND_CONFIG, NULL);
 
        return ERROR_OK;
 }
 
 #if PARPORT_USE_GIVEIO == 1
-int parport_get_giveio_access()
+int parport_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;
+       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
 
@@ -282,7 +316,7 @@ int parport_init(void)
        if ((parport_cable == NULL) || (parport_cable[0] == 0))
        {
                parport_cable = "wiggler";
-               WARNING("No parport cable specified, using default 'wiggler'");
+               LOG_WARNING("No parport cable specified, using default 'wiggler'");
        }
        
        while (cur_cable->name)
@@ -297,32 +331,44 @@ int parport_init(void)
 
        if (!cable)
        {
-               ERROR("No matching cable found for %s", parport_cable);
+               LOG_ERROR("No matching cable found for %s", parport_cable);
                return ERROR_JTAG_INIT_FAILED;
        }
        
        dataport_value = cable->PORT_INIT;
        
 #if PARPORT_USE_PPDEV == 1
-       if (device_handle>0)
+       if (device_handle > 0)
        {
-               ERROR("device is already opened");
+               LOG_ERROR("device is already opened");
                return ERROR_JTAG_INIT_FAILED;
        }
 
+#if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+       LOG_DEBUG("opening /dev/ppi%d...", parport_port);
+
+       snprintf(buffer, 256, "/dev/ppi%d", parport_port);
+       device_handle = open(buffer, O_WRONLY);
+#else /* not __FreeBSD__, __FreeBSD_kernel__ */
+       LOG_DEBUG("opening /dev/parport%d...", parport_port);
+
        snprintf(buffer, 256, "/dev/parport%d", parport_port);
        device_handle = open(buffer, O_WRONLY);
-       
-       if (device_handle<0)
+#endif /* __FreeBSD__, __FreeBSD_kernel__ */
+
+       if (device_handle < 0)
        {
-               ERROR("cannot open device. check it exists and that user read and write rights are set");
+               LOG_ERROR("cannot open device. check it exists and that user read and write rights are set");
                return ERROR_JTAG_INIT_FAILED;
        }
 
+       LOG_DEBUG("...open");
+
+#if !defined(__FreeBSD__) && !defined(__FreeBSD_kernel__)
        i=ioctl(device_handle, PPCLAIM);
        if (i<0)
        {
-               ERROR("cannot claim device");
+               LOG_ERROR("cannot claim device");
                return ERROR_JTAG_INIT_FAILED;
        }
 
@@ -330,7 +376,7 @@ int parport_init(void)
        i= ioctl(device_handle, PPSETMODE, & i);
        if (i<0)
        {
-               ERROR(" cannot set compatible mode to device");
+               LOG_ERROR(" cannot set compatible mode to device");
                return ERROR_JTAG_INIT_FAILED;
        }
 
@@ -338,32 +384,45 @@ int parport_init(void)
        i = ioctl(device_handle, PPNEGOT, & i);
        if (i<0)
        {
-               ERROR("cannot set compatible 1284 mode to device");
+               LOG_ERROR("cannot set compatible 1284 mode to device");
                return ERROR_JTAG_INIT_FAILED;
        }
-#else
+#endif /* not __FreeBSD__, __FreeBSD_kernel__ */
+
+#else /* not PARPORT_USE_PPDEV */
        if (parport_port == 0)
        {
                parport_port = 0x378;
-               WARNING("No parport port specified, using default '0x378' (LPT1)");
+               LOG_WARNING("No parport port specified, using default '0x378' (LPT1)");
        }
        
        dataport = parport_port;
        statusport = parport_port + 1;
-               
+       
+       LOG_DEBUG("requesting privileges for parallel port 0x%lx...", dataport);
 #if PARPORT_USE_GIVEIO == 1
        if (parport_get_giveio_access() != 0)
 #else /* PARPORT_USE_GIVEIO */
        if (ioperm(dataport, 3, 1) != 0)
 #endif /* PARPORT_USE_GIVEIO */
        {
-               ERROR("missing privileges for direct i/o");
+               LOG_ERROR("missing privileges for direct i/o");
                return ERROR_JTAG_INIT_FAILED;
        }
+       LOG_DEBUG("...privileges granted");
+       
+       /* make sure parallel port is in right mode (clear tristate and interrupt */
+       #if defined(__FreeBSD__) || defined(__FreeBSD_kernel__)
+               outb(parport_port + 2, 0x0);
+       #else
+               outb(0x0, parport_port + 2);
+       #endif
+       
 #endif /* PARPORT_USE_PPDEV */
        
        parport_reset(0, 0);
        parport_write(0, 0, 0);
+       parport_led(1);
 
        bitbang_interface = &parport_bitbang;   
 
@@ -372,7 +431,20 @@ int parport_init(void)
 
 int parport_quit(void)
 {
+       parport_led(0);
 
+       if (parport_exit)
+       {
+               dataport_value = cable->PORT_EXIT;
+               parport_write_data();
+       }
+       
+       if (parport_cable)
+       {
+               free(parport_cable);
+               parport_cable = NULL;
+       }
+       
        return ERROR_OK;
 }
 
@@ -402,3 +474,19 @@ int parport_handle_parport_cable_command(struct command_context_s *cmd_ctx, char
 
        return ERROR_OK;
 }
+
+int parport_handle_write_on_exit_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc)
+{
+       if (argc != 1)
+       {
+               command_print(cmd_ctx, "usage: parport_write_on_exit <on|off>");
+               return ERROR_OK;
+       }
+       
+       if (strcmp(args[0], "on") == 0)
+               parport_exit = 1;
+       else if (strcmp(args[0], "off") == 0)
+               parport_exit = 0;
+       
+       return ERROR_OK;
+}