diff --git a/jtag/ChangeLog b/jtag/ChangeLog index a8a14d16..61f03a48 100644 --- a/jtag/ChangeLog +++ b/jtag/ChangeLog @@ -1,3 +1,10 @@ +2003-03-18 Marcel Telka + + * configure.ac (AC_CHECK_HEADERS): Added test for linux/ppdev.h. + * src/tap/Makefile.am (libtap_a_SOURCES): Added parport/ppdev.c. + * src/tap/parport.c (parport_drivers): Added ppdev parport driver. + * src/tap/parport/ppdev.c: New file. + 2003-03-18 Marcel Telka * src/bsdl2jtag.c (endline): Removed compile warning. diff --git a/jtag/NEWS b/jtag/NEWS index 353d7619..4f71d318 100644 --- a/jtag/NEWS +++ b/jtag/NEWS @@ -1,5 +1,7 @@ $Id$ + * Added support for Linux ppdev parallel port driver. Non-root users can + use JTAG Tools now. * Added new `bsdl2jtag' conversion tool (Matan Ziv-Av). jtag-0.3 (2003-02-25): diff --git a/jtag/configure.ac b/jtag/configure.ac index 968d709c..f586066e 100644 --- a/jtag/configure.ac +++ b/jtag/configure.ac @@ -76,6 +76,8 @@ CPPFLAGS="$CPPFLAGS -I$openwince_includes_path -I$openwince_includes_path/device AC_SEARCH_LIBS([ioperm], [ioperm]) AC_CHECK_FUNCS(getline getdelim) +AC_CHECK_HEADERS(linux/ppdev.h) + # # Searches for a readline compatible library. # http://www.gnu.org/software/ac-archive/htmldoc/vl_lib_readline.html diff --git a/jtag/src/tap/Makefile.am b/jtag/src/tap/Makefile.am index 140e9679..cfb57839 100644 --- a/jtag/src/tap/Makefile.am +++ b/jtag/src/tap/Makefile.am @@ -30,6 +30,7 @@ libtap_a_SOURCES = \ chain.c \ parport.c \ parport/direct.c \ + parport/ppdev.c \ cable.c \ cable/generic.h \ cable/generic.c \ diff --git a/jtag/src/tap/parport.c b/jtag/src/tap/parport.c index 0d16b179..a3d5555f 100644 --- a/jtag/src/tap/parport.c +++ b/jtag/src/tap/parport.c @@ -29,9 +29,15 @@ #include "parport.h" extern parport_driver_t direct_parport_driver; +#ifdef HAVE_LINUX_PPDEV_H +extern parport_driver_t ppdev_parport_driver; +#endif /* HAVE_LINUX_PPDEV_H */ parport_driver_t *parport_drivers[] = { &direct_parport_driver, +#ifdef HAVE_LINUX_PPDEV_H + &ppdev_parport_driver, +#endif /* HAVE_LINUX_PPDEV_H */ NULL /* last must be NULL */ }; diff --git a/jtag/src/tap/parport/ppdev.c b/jtag/src/tap/parport/ppdev.c new file mode 100644 index 00000000..8bd619e0 --- /dev/null +++ b/jtag/src/tap/parport/ppdev.c @@ -0,0 +1,259 @@ +/* + * $Id$ + * + * Linux ppdev Driver + * Copyright (C) 2003 ETC s.r.o. + * + * 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., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * Written by Marcel Telka , 2003. + * + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_LINUX_PPDEV_H + +#include "gettext.h" +#define _(s) gettext(s) +#define N_(s) gettext_noop(s) +#define P_(s,p,n) ngettext(s,p,n) + +#include +#include +#include +#include +#include + +#include +#include + +#include "parport.h" +#include "cable.h" + +parport_driver_t ppdev_parport_driver; + +typedef struct port_node_t port_node_t; + +struct port_node_t { + parport_t *port; + port_node_t *next; +}; + +static port_node_t *ports = NULL; /* ppdev parallel ports */ + +typedef struct { + char *portname; + int fd; +} ppdev_params_t; + +static parport_t * +ppdev_parport_alloc( const char *port ) +{ + ppdev_params_t *params = malloc( sizeof *params ); + char *portname = strdup( port ); + parport_t *parport = malloc( sizeof *parport ); + port_node_t *node = malloc( sizeof *node ); + + if (!node || !parport || !params || !portname) { + free( node ); + free( parport ); + free( params ); + free( portname ); + return NULL; + } + + params->portname = portname; + params->fd = -1; + + parport->params = params; + parport->driver = &ppdev_parport_driver; + parport->cable = NULL; + + node->port = parport; + node->next = ports; + + ports = node; + + return parport; +} + +static void +ppdev_parport_free( parport_t *port ) +{ + port_node_t **prev; + + for (prev = &ports; *prev; prev = &((*prev)->next)) + if ((*prev)->port == port) + break; + + if (*prev) { + port_node_t *pn = *prev; + *prev = pn->next; + free( pn ); + } + + free( ((ppdev_params_t *) port->params)->portname ); + free( port->params ); + free( port ); +} + +static cable_t * +ppdev_connect( const char **par, int parnum ) +{ + int i; + port_node_t *pn; + parport_t *parport; + cable_t *cable; + + if (parnum != 2) { + printf( _("Syntax error!\n") ); + return NULL; + } + + for (pn = ports; pn; pn = pn->next) + if (strcmp( pn->port->params, par[0] ) == 0) { + printf( _("Disconnecting %s from ppdev port %s\n"), pn->port->cable->driver->description, par[0] ); + pn->port->cable->driver->disconnect( pn->port->cable ); + break; + } + + if (strcmp( par[1], "none" ) == 0) { + printf( _("Changed cable to 'none'\n") ); + return NULL; + } + + for (i = 0; cable_drivers[i]; i++) + if (strcmp( par[1], cable_drivers[i]->name ) == 0) + break; + + if (!cable_drivers[i]) { + printf( _("Unknown cable: %s\n"), par[1] ); + return NULL; + } + + printf( _("Initializing %s on ppdev port %s\n"), cable_drivers[i]->description, par[0] ); + + parport = ppdev_parport_alloc( par[0] ); + if (!parport) { + printf( _("%s(%d) Out of memory.\n"), __FILE__, __LINE__ ); + return NULL; + } + + cable = cable_drivers[i]->connect( cable_drivers[i], parport ); + if (!cable) + ppdev_parport_free( parport ); + + return cable; +} + +static int +ppdev_open( parport_t *parport ) +{ + ppdev_params_t *p = parport->params; + + printf( "Opening port: %s\n", p->portname ); + p->fd = open( p->portname, O_RDWR ); + printf( "Result: %d\n", p->fd ); + if (p->fd < 0) + return -1; + + if ((ioctl( p->fd, PPEXCL ) == -1) || (ioctl( p->fd, PPCLAIM ) == -1)) { + close( p->fd ); + p->fd = -1; + return -1; + } + + return 0; +} + +static int +ppdev_close( parport_t *parport ) +{ + int r = 0; + ppdev_params_t *p = parport->params; + + if (ioctl( p->fd, PPRELEASE ) == -1) + r = -1; + + if (close( p->fd ) != 0) + return -1; + + p->fd = -1; + return r; +} + +static int +ppdev_set_data( parport_t *parport, uint8_t data ) +{ + ppdev_params_t *p = parport->params; + + if (ioctl( p->fd, PPWDATA, &data ) == -1) + return -1; + + return 0; +} + +static int +ppdev_get_data( parport_t *parport ) +{ + unsigned char d; + ppdev_params_t *p = parport->params; + + if (ioctl( p->fd, PPRDATA, &d ) == -1) + return -1; + + return d; +} + +static int +ppdev_get_status( parport_t *parport ) +{ + unsigned char d; + ppdev_params_t *p = parport->params; + + if (ioctl( p->fd, PPRSTATUS, &d ) == -1) + return -1; + + return d; +} + +static int +ppdev_set_control( parport_t *parport, uint8_t data ) +{ + ppdev_params_t *p = parport->params; + + if (ioctl( p->fd, PPWCONTROL, &data ) == -1) + return -1; + + return 0; +} + +parport_driver_t ppdev_parport_driver = { + "ppdev", + ppdev_connect, + ppdev_parport_free, + ppdev_open, + ppdev_close, + ppdev_set_data, + ppdev_get_data, + ppdev_get_status, + ppdev_set_control +}; + +#endif /* HAVE_LINUX_PPDEV_H */