OpenCores
URL https://opencores.org/ocsvn/adv_debug_sys/adv_debug_sys/trunk

Subversion Repositories adv_debug_sys

[/] [adv_debug_sys/] [trunk/] [Software/] [adv_jtag_bridge/] [cable_parallel.c] - Rev 59

Compare with Previous | Blame | View Log

/* cable_parallel.c - Parallel cable drivers (XPC3 and XESS) for the Advanced JTAG Bridge
   Copyright (C) 2001 Marko Mlinar, markom@opencores.org
   Copyright (C) 2004 Gy�rgy Jeney, nog@sdf.lonestar.org
 
   UNIX parallel port control through device file added by:
	   Copyright (C) 2011 Raul Fajardo, rfajardo@opencores.org
 
   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., 675 Mass Ave, Cambridge, MA 02139, USA. */
 
 
#include <stdio.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <time.h>
#include <string.h>
 
#ifdef __LINUX_HOST__
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <linux/ppdev.h>
#include <linux/parport.h>
#endif
 
#ifdef __CYGWIN_HOST__
#include <sys/io.h>  // for inb(), outb()
#endif
 
#ifdef __FREEBSD_HOST__
#include <fcntl.h>
#include <sys/ioctl.h>
#include <sys/dev/ppbus/ppi.h>
#include <sys/dev/ppbus/ppbconf.h>
#endif
 
#include "cable_parallel.h"
#include "errcodes.h"
 
#ifdef __PARALLEL_TIMER_BUSY_WAIT__
 #if ((_POSIX_TIMERS) && (_POSIX_CPUTIME))
 #define PARALLEL_USE_PROCESS_TIMER
 #endif
#endif
 
jtag_cable_t xpc3_cable_driver = {
    .name = "xpc3",
    .inout_func = cable_xpc3_inout,
    .out_func = cable_xpc3_out,
    .init_func = cable_parallel_init,
    .opt_func = cable_parallel_opt,
    .bit_out_func = cable_common_write_bit,
    .bit_inout_func = cable_common_read_write_bit,
    .stream_out_func = cable_common_write_stream,
    .stream_inout_func = cable_common_read_stream,
    .flush_func = NULL,
#ifdef __CYGWIN_HOST__
    .opts = "p:",
    .help = "-p [port] Which port to use when communicating with the parport hardware (eg. 0x378)\n"
#else
    .opts = "d:",
    .help = "-d [device file] Device file to use when communicating with the parport hardware (eg. /dev/parport0)\n"
#endif
    };
 
jtag_cable_t bb2_cable_driver = {
 .name = "bb2",
 .inout_func = cable_bb2_inout,
 .out_func = cable_bb2_out,
 .init_func = cable_parallel_init,
 .opt_func = cable_parallel_opt,
 .bit_out_func = cable_common_write_bit,
 .bit_inout_func = cable_common_read_write_bit,
 .stream_out_func = cable_common_write_stream,
 .stream_inout_func = cable_common_read_stream,
 .flush_func = NULL,
#ifdef __CYGWIN_HOST__
    .opts = "p:",
    .help = "-p [port] Which port to use when communicating with the parport hardware (eg. 0x378)\n"
#else
    .opts = "d:",
    .help = "-d [device file] Device file to use when communicating with the parport hardware (eg. /dev/parport0)\n"
#endif
 };
 
jtag_cable_t xess_cable_driver = {
    .name = "xess",
    .inout_func = cable_xess_inout,
    .out_func = cable_xess_out,
    .init_func = cable_parallel_init,
    .opt_func = cable_parallel_opt,
    .bit_out_func = cable_common_write_bit,
    .bit_inout_func = cable_common_read_write_bit,
    .stream_out_func = cable_common_write_stream,
    .stream_inout_func = cable_common_read_stream,
    .flush_func = NULL,
#ifdef __CYGWIN_HOST__
    .opts = "p:",
    .help = "-p [port] Which port to use when communicating with the parport hardware (eg. 0x378)\n"
#else
    .opts = "d:",
    .help = "-d [device file] Device file to use when communicating with the parport hardware (eg. /dev/parport0)\n"
#endif
    };
 
 
// Common functions used by both cable types
static int cable_parallel_out(uint8_t value);
static int cable_parallel_inout(uint8_t value, uint8_t *inval);
 
#ifdef __PARALLEL_TIMER_BUSY_WAIT__
 #ifndef PARALLEL_USE_PROCESS_TIMER
 struct timeval last_tv;
 #endif
#endif
 
// If cygwin, we use inb / outb for parallel port access
#ifdef __CYGWIN_HOST__
 
#define LPT_READ (base+1)
#define LPT_WRITE base
 
static int base = 0x378;
 
/////////////////////////////////////////////////////////////////////////////////
/*-------------------------------------[ Parallel port specific functions ]---*/
///////////////////////////////////////////////////////////////////////////////
 
int cable_parallel_init()
{
  if (ioperm(base, 3, 1)) {
    fprintf(stderr, "Couldn't get the port at %x\n", base);
    perror("Root privileges are required.\n");
    return APP_ERR_INIT_FAILED;
  }
  printf("Connected to parallel port at %x\n", base);
  printf("Dropping root privileges.\n");
  setreuid(getuid(), getuid());
 
#ifdef __PARALLEL_TIMER_BUSY_WAIT__
 #ifdef PARALLEL_USE_PROCESS_TIMER
  struct timespec ts;
  ts.tv_sec = 0;
  ts.tv_nsec = 0;
  clock_settime(CLOCK_PROCESS_CPUTIME_ID, &ts);
 #else
  gettimeofday(&last_tv, NULL);
 #endif
#endif
 
  return APP_ERR_NONE;
}
 
int cable_parallel_opt(int c, char *str)
{
  switch(c) {
  case 'p':
    if(!sscanf(str, "%x", &base)) {
      fprintf(stderr, "p parameter must have a hex number as parameter\n");
      return APP_ERR_BAD_PARAM;
    }
    break;
  default:
    fprintf(stderr, "Unknown parameter '%c'\n", c);
    return APP_ERR_BAD_PARAM;
  }
  return APP_ERR_NONE;
}
 
/*----------------------------------------------[ common helper functions ]---*/
// 'static' for internal access only
 
static int cable_parallel_out(uint8_t value)
{
  outb(value, LPT_WRITE);
  return APP_ERR_NONE;
}
 
static int cable_parallel_inout(uint8_t value, uint8_t *inval)
{
  *inval = inb(LPT_READ);
  outb(value, LPT_WRITE);
 
  return APP_ERR_NONE;
}
 
// For Linux / BSD, we use open / ioctl for parallel port access,
// so that we don't need root permissions
#else // ! defined __CYGWIN_HOST__
 
#ifdef __FREEBSD_HOST__
static int PPORT_PUT_DATA = PPISDATA;
static int PPORT_GET_DATA = PPIGSTATUS;
#else
static int PPORT_PUT_DATA = PPWDATA;
static int PPORT_GET_DATA = PPRSTATUS;
#endif
 
static int fd;
static char default_dev_str[20] = "/dev/parport0";
static char *devsys = default_dev_str;
 
 
/////////////////////////////////////////////////////////////////////////////////
/*-------------------------------------[ Parallel port specific functions ]---*/
///////////////////////////////////////////////////////////////////////////////
 
int cable_parallel_init()
{
  int mode = IEEE1284_MODE_COMPAT;
  fd = open(devsys, O_RDWR | O_NONBLOCK);
  if (fd == -1)
  {
    perror("Unable to open the device desriptor\n");
    fprintf(stderr, "Check permission of %s (eg. 'ls -la %s').\n", devsys, devsys);
    fprintf(stderr, "Your user ID can be added to %s's group to allow for unprivileged access.\n", devsys);
    return APP_ERR_INIT_FAILED;
  }
 
  // I don't know if these ioctl() are supported under FreeBSD
#ifdef __LINUX_HOST__
  if (ioctl(fd, PPCLAIM) == -1)
  {
    perror("Fail to claim the parallel port device interface.\n");
    return APP_ERR_INIT_FAILED;
  }
  if (ioctl(fd, PPSETMODE, &mode) == -1)
  {
    perror("Setting compatibility mode on parallel port device failed.\n");
    return APP_ERR_INIT_FAILED;
  }
#endif
 
#ifdef __PARALLEL_TIMER_BUSY_WAIT__
 #ifdef PARALLEL_USE_PROCESS_TIMER
  struct timespec ts;
  ts.tv_sec = 0;
  ts.tv_nsec = 0;
  clock_settime(CLOCK_PROCESS_CPUTIME_ID, &ts);
 #else
  gettimeofday(&last_tv, NULL);
 #endif
#endif
 
  return APP_ERR_NONE;
}
 
 
int cable_parallel_opt(int c, char *str)
{
  switch(c) {
  case 'd':
    devsys = strdup(str);
    break;
  default:
    fprintf(stderr, "Unknown parameter '%c'\n", c);
    return APP_ERR_BAD_PARAM;
  }
  return APP_ERR_NONE;
}
 
/*----------------------------------------------[ common helper functions ]---*/
// 'static' for internal access only
 
static int cable_parallel_out(uint8_t value)
{
  ioctl(fd, PPORT_PUT_DATA, &value);
 
  return APP_ERR_NONE;
}
 
static int cable_parallel_inout(uint8_t value, uint8_t *inval)
{
  ioctl(fd, PPORT_GET_DATA, inval);
  ioctl(fd, PPORT_PUT_DATA, &value);
 
  return APP_ERR_NONE;
}
 
#endif  // !defined __CYGWIN_HOST__
 
/*-----------------------------------------[ Physical board wait function ]---*/
 
/* Multiple users have reported poor performance of parallel cables,
 * which has been traced to various sleep functions sleeping much longer than 
 * microseconds.  The same users have reported error-free functionality
 * and an order of magnitude improvement in upload speed with no wait.
 * Other users have reported errors when running without a wait.
 * Impact apparently limits the frequency of parallel JTAG cables
 * to 200 kHz, and some clones fail at higher speeds.
 */ 
 
 
 
#ifdef __PARALLEL_SLEEP_WAIT__
void cable_parallel_phys_wait()
{
  struct timespec ts;
  ts.tv_sec = 0;
  ts.tv_nsec = 2500;
  nanosleep(&ts, NULL);
}
#else
 
 #ifdef __PARALLEL_TIMER_BUSY_WAIT__
 
  #ifndef PARALLEL_USE_PROCESS_TIMER
 
/* Helper function needed if process timer isn't implemented */
/* do x-y */
int timeval_subtract (struct timeval *result, struct timeval *x, struct timeval *y)
{
  /* Perform the carry for the later subtraction by updating y. */
  if (x->tv_usec < y->tv_usec) {
    int nsec = (y->tv_usec - x->tv_usec) / 1000000 + 1;
    y->tv_usec -= 1000000 * nsec;
    y->tv_sec += nsec;
  }
  if (x->tv_usec - y->tv_usec > 1000000) {
    int nsec = (x->tv_usec - y->tv_usec) / 1000000;
    y->tv_usec += 1000000 * nsec;
    y->tv_sec -= nsec;
  }
 
  /* Compute the time remaining to wait.
     tv_usec is certainly positive. */
  result->tv_sec = x->tv_sec - y->tv_sec;
  result->tv_usec = x->tv_usec - y->tv_usec;
 
  /* Return 1 if result is negative. */
  return x->tv_sec < y->tv_sec;
}
  #endif
 
 
void cable_parallel_phys_wait()
{
  /* This busy wait attempts to make the frequency exactly 200kHz,
   * including the processing time between ticks.
   * This means a period of 5us, or half a period of 2.5us.
   */
  #ifdef PARALLEL_USE_PROCESS_TIMER
  struct timespec ts;
  do
    {
      clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ts); 
    } while((ts.tv_sec == 0) && (ts.tv_nsec < 2500));
 
  /* Doing the set after the check means that processing time
   * is not added to the wait. */
  ts.tv_sec = 0;
  ts.tv_nsec = 0;
  clock_settime(CLOCK_PROCESS_CPUTIME_ID, &ts);
  #else
  struct timeval now_tv;
  struct timeval results_tv;
  do
    {
      gettimeofday(&now_tv, NULL);
      timeval_subtract (&results_tv, &now_tv, &last_tv);
    } while((results_tv.tv_sec == 0) && (results_tv.tv_usec < 3));
  last_tv = now_tv;
  #endif
}
 
 #else  // NO WAIT
 
void cable_parallel_phys_wait()
{
  // No wait, run max speed
}
 
 #endif
#endif
 
 
/*----------------------------------------------[ xpc3 specific functions ]---*/
jtag_cable_t *cable_xpc3_get_driver(void)
{
  return &xpc3_cable_driver; 
}
 
int cable_xpc3_out(uint8_t value)
{
  uint8_t out = 0;
 
  cable_parallel_phys_wait();  // Limit the max clock rate if necessary
 
  /* First convert the bits in value byte to the ones that the cable wants */
  if(value & TCLK_BIT)
    out |= 0x02; /* D1 pin 3 */
  if(value & TRST_BIT)
    out |= 0x10; /* Not used */
  if(value & TDI_BIT)
    out |= 0x01; /* D0 pin 2 */
  if(value & TMS_BIT)
    out |= 0x04; /* D2 pin 4 */
 
  return cable_parallel_out(out);
}
 
int cable_xpc3_inout(uint8_t value, uint8_t *inval)
{
  uint8_t in;
  int retval;
  uint8_t out = 0;
 
  cable_parallel_phys_wait();  // Limit the max clock rate if necessary
 
  /* First convert the bits in value byte to the ones that the cable wants */
  if(value & TCLK_BIT)
    out |= 0x02; /* D1 pin 3 */
  if(value & TRST_BIT)
    out |= 0x10; /* Not used */
  if(value & TDI_BIT)
    out |= 0x01; /* D0 pin 2 */
  if(value & TMS_BIT)
    out |= 0x04; /* D2 pin 4 */
 
  retval = cable_parallel_inout(out, &in);
 
  if(in & 0x10) /* S6 pin 13 */
    *inval = 1;
  else
    *inval = 0;
 
  return retval;
}
 
 
/*----------------------------------------------[ bb2 specific functions ]---*/
jtag_cable_t *cable_bb2_get_driver(void)
{
 return &bb2_cable_driver;
}
 
int cable_bb2_out(uint8_t value)
{
 uint8_t out = 0;
 
 cable_parallel_phys_wait(); // Limit the max clock rate if necessary
 
 /* First convert the bits in value byte to the ones that the cable wants */
 if(value & TCLK_BIT)
   out |= 0x01; /* D0 pin 2 */
 if(value & TDI_BIT)
   out |= 0x40; /* D7 pin 8 */
 if(value & TMS_BIT)
   out |= 0x02; /* D1 pin 3 */
 
 return cable_parallel_out(out);
}
 
int cable_bb2_inout(uint8_t value, uint8_t *inval)
{
 uint8_t in;
 int retval;
 uint8_t out = 0;
 
 cable_parallel_phys_wait(); // Limit the max clock rate if necessary
 
 /* First convert the bits in value byte to the ones that the cable wants */
 if(value & TCLK_BIT)
   out |= 0x01; /* D0 pin 2 */
 if(value & TDI_BIT)
   out |= 0x40; /* D7 pin 8 */
 if(value & TMS_BIT)
   out |= 0x02; /* D1 pin 3 */
 
 retval = cable_parallel_inout(out, &in);
 
 if(in & 0x80) /* S7 pin 11 */
 *inval = 0;
 else
 *inval = 1;
 
 return retval;
}
 
 
/*----------------------------------------------[ xess specific functions ]---*/
jtag_cable_t *cable_xess_get_driver(void)
{
  return &xess_cable_driver; 
}
 
int cable_xess_out(uint8_t value)
{
  uint8_t out = 0;
 
  cable_parallel_phys_wait();  // Limit the max clock rate if necessary
 
  /* First convert the bits in value byte to the ones that the cable wants */
  if(value & TCLK_BIT)
    out |= 0x04; /* D2 pin 4 */
  if(value & TRST_BIT)
    out |= 0x08; /* D3 pin 5 */
  if(value & TDI_BIT)
    out |= 0x10; /* D4 pin 6 */
  if(value & TMS_BIT)
    out |= 0x20; /* D3 pin 5 */
 
  return cable_parallel_out(out);
}
 
int cable_xess_inout(uint8_t value, uint8_t *inval)
{
  uint8_t in;
  int retval;
  uint8_t out = 0;
 
  cable_parallel_phys_wait();  // Limit the max clock rate if necessary
 
  /* First convert the bits in value byte to the ones that the cable wants */
  if(value & TCLK_BIT)
    out |= 0x04; /* D2 pin 4 */
  if(value & TRST_BIT)
    out |= 0x08; /* D3 pin 5 */
  if(value & TDI_BIT)
    out |= 0x10; /* D4 pin 6 */
  if(value & TMS_BIT)
    out |= 0x20; /* D3 pin 5 */
 
  retval = cable_parallel_inout(out, &in);
 
  if(in & 0x20) /* S5 pin 12*/
    *inval = 1;
  else
    *inval = 0;
 
  return retval;
}
 
 
 

Compare with Previous | Blame | View Log

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.