diff options
Diffstat (limited to 'src/interface')
-rw-r--r-- | src/interface/Makefile.am | 27 | ||||
-rw-r--r-- | src/interface/bitbang.c | 151 | ||||
-rw-r--r-- | src/interface/bitbang.h | 27 | ||||
-rw-r--r-- | src/interface/interface.c | 203 | ||||
-rw-r--r-- | src/interface/interface.h | 52 |
5 files changed, 460 insertions, 0 deletions
diff --git a/src/interface/Makefile.am b/src/interface/Makefile.am new file mode 100644 index 00000000..925ec64a --- /dev/null +++ b/src/interface/Makefile.am @@ -0,0 +1,27 @@ +include $(top_srcdir)/common.mk + +METASOURCES = AUTO +noinst_LTLIBRARIES = libinterface.la + +SUBDIRS = +DRIVERFILES = +libinterface_la_LIBADD = + +CLEANFILES = + +BUILT_SOURCES = + +BUILT_SOURCES += +CLEANFILES += + +libinterface_la_SOURCES = \ + interface.c \ + bitbang.c + +noinst_HEADERS = \ + interface.h \ + bitbang.h + +EXTRA_DIST = + +MAINTAINERCLEANFILES = $(srcdir)/Makefile.in diff --git a/src/interface/bitbang.c b/src/interface/bitbang.c new file mode 100644 index 00000000..443e9aea --- /dev/null +++ b/src/interface/bitbang.c @@ -0,0 +1,151 @@ +/* + * Copyright (c) 2011 Tomasz Boleslaw CEDRO <cederom@tlen.pl> + * + * 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 + */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +/** @file Simple framework to bitbang the interface pins. + */ + +#include <helper/command.h> +#include <jtag/interface.h> +#include <interface/interface.h> +#include "bitbang.h" + +extern struct jtag_interface *jtag_interface; + +/*-----------------------------------------------------------------------*/ + +/* + * Infrastructure for Tcl interface to bitbang. + */ + +/** Bitbang framework allows operation on interface signals, operating on HEX + * values, to read and set their state. When only signal name is given then + * read operation is performed and value returned for given port mask defined + * by signal mask. Additional '=' parameter with following value with set this + * value to the port (again restricted by the signal mask). Therefore it is + * possible to set/get more than one bit/pin at once each with its own value. + * In addition label 'hi'/'set' equals value 0xFFFFFFFF, 'lo'/'clr' equals 0. + * Also note that read/write operation will affect selected port bits direction + * as reading values will switch masked bits to input while writing will make + * them outputs. This is also good way to change port behavior for some pins, + * but beware that reading output may not always bring expected results as it + * may impact device connected to that pin (i.e. Hi-Z input gives 1 undriven). + * This functionality brings new possibilities to script additional features. + */ +COMMAND_HANDLER(handle_bitbang_command) +{ + LOG_DEBUG("%s", __func__); + + if (!jtag_interface){ + LOG_ERROR("You need to setup interface first!"); + return ERROR_FAIL; + } + + if (!jtag_interface->bitbang){ + LOG_ERROR("This interface does not support bit-banging!"); + return ERROR_FAIL; + } + + if (CMD_ARGC < 1) { + LOG_ERROR("Bad syntax!"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + if (jtag_interface->signal==NULL){ + LOG_ERROR("No signals defined, see 'interface_signal' command for help."); + return ERROR_FAIL; + } + + static oocd_interface_signal_t *sig; + static unsigned int pn; + static int retval; + static char *mark, *signame, *sigval, pcmd[45]; + + // Iterate through list of command parameters + for (pn=0;pn<CMD_ARGC;pn++){ + // Make a local copy of parameter command to work on + if (!strncpy(pcmd, CMD_ARGV[pn], 45)){ + LOG_ERROR("Cannot copy parameter: %s", CMD_ARGV[pn]); + return ERROR_FAIL; + } + // Look for '=' mark to see if read or write will happen + mark=strnstr(pcmd, "=", 45); + if (!mark){ + // If no '=' was found then we read the signal value + // Check if specified signal exists + if (!(sig=oocd_interface_signal_find(pcmd))){ + LOG_ERROR("Unknown signal specified!"); + return ERROR_FAIL; + } + // Call the driver routine to do the actual signal read + retval=jtag_interface->bitbang(NULL, pcmd, 1, (int *)&sig->value); + if (retval!=ERROR_OK){ + LOG_ERROR("Unable to read signal: %s", pcmd); + return ERROR_FAIL; + } + } else { + // If '=' was found then we write specified value to the specified signal + // Get and verify the signal name first + signame=strtok(pcmd, "="); + sig=oocd_interface_signal_find(signame); + if (!sig){ + LOG_ERROR("Unknown signal specified!"); + return ERROR_FAIL; + } + // Then read the HEX value or hi (all bits one) / lo (all bits zero) + if (!(sigval=strtok(NULL, "="))){ + LOG_ERROR("No value specified! Use: hi, set, lo, clr, or HEX port value."); + return ERROR_COMMAND_SYNTAX_ERROR; + } + if (!strncmp(sigval, "hi", 2) || !strncmp(sigval, "set", 3)){ + sig->value=0xffffffff&sig->mask; + } else if (!strncmp(sigval, "lo", 2) || !strncmp(sigval, "clr", 3)){ + sig->value=0; + } else if (!sscanf(sigval, "%x", (unsigned int *)&sig->value)){ + LOG_ERROR("Bad value parameter specified (can be: hi, set, lo, clr, or direct HEX port value)"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + retval=jtag_interface->bitbang(NULL, signame, 0, (int *)&sig->value); + if (retval!=ERROR_OK){ + LOG_ERROR("Unable to write signal: %s", signame); + return ERROR_FAIL; + } + } + command_print(CMD_CTX, "%s=0x%08X", sig->name, sig->value); + } + return ERROR_OK; +} + +static const struct command_registration bitbang_commands[] = { + { + .name = "bitbang", + .handler = handle_bitbang_command, + .mode = COMMAND_ANY, + .help = "Perform bit-bang operations on interface signals (mask!).", + .usage = "'signal_name' to read, 'signal_name'='port_hex_value' to write.", + }, + COMMAND_REGISTRATION_DONE +}; + +int bitbang_register_commands(struct command_context *ctx) +{ + return register_commands(ctx, NULL, bitbang_commands); +} diff --git a/src/interface/bitbang.h b/src/interface/bitbang.h new file mode 100644 index 00000000..8d15d49c --- /dev/null +++ b/src/interface/bitbang.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2011 Tomasz Boleslaw CEDRO <cederom@tlen.pl> + * + * 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 + */ + +#ifndef OOCD_SIGNAL_H +#define OOCD_SIGNAL_H + +/** @file Simple framework to work with interface signals. + */ + +int bitbang_register_commands(struct command_context *ctx); + +#endif diff --git a/src/interface/interface.c b/src/interface/interface.c new file mode 100644 index 00000000..e19bbc5b --- /dev/null +++ b/src/interface/interface.c @@ -0,0 +1,203 @@ +/* + * Copyright (C) 2011 Tomasz Boleslaw CEDRO <cederom@tlen.pl> + * + * 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 + */ + +/** @file: Generic OpenOCD interface. */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include <interface/interface.h> +#include <jtag/interface.h> +#include <helper/log.h> + +extern struct jtag_interface *jtag_interface; + +/****************************************************************************** + * SIGNAL INFRASTRUCTURE AND OPERATIONS + ******************************************************************************/ + +/** Check if specified signal is already defined (case insensitive) and return + * its pointer if defined. + * \param *name signal name to check + * \return pointer to signal structure in memory if found, NULL otherwise. + */ +oocd_interface_signal_t *oocd_interface_signal_find(char *name){ + // Check if interface already exists + if (!jtag_interface){ + LOG_ERROR("Interface does not yet exist!"); + return NULL; + } + // Check if interface signal to work on already exists + if (!jtag_interface->signal){ + LOG_WARNING("There are no signals defined yet."); + return NULL; + } + // Check if signal name is correct + if (!name || strncmp(name, " ", 1)==0){ + LOG_ERROR("Signal name cannot be empty."); + return NULL; + } + // Check if signal name already exist + oocd_interface_signal_t *sig; + sig=jtag_interface->signal; + while (sig) { + if (!strncasecmp(sig->name, name, 32)){ + LOG_DEBUG("Signal %s already exists.", sig->name); + return sig; + } + sig=sig->next; + } + // If signal is not found return null pointer. + LOG_DEBUG("Signal %s not (yet) on the list.", name); + return NULL; +} +/** Add new signal to the interface. + * Signal will be allocated in memory with provided name and mask. + * There is no sense for giving value field at this time because signal create + * can take place during initialization where interface is not yet ready, also + * they can be used for read and write, so this is higher level script task + * to initialize their default value with appropriate 'bitbang' call. + * The default value for new signal equals provided mask to maintain Hi-Z. + * + * \param *name is the signal name (max 32 char). + * \param mask is the signal mask (unsigned int). + * \param value is the initial value for signal to set. + * \return ERROR_OK on success or ERROR_FAIL on failure. + */ +int oocd_interface_signal_add(char *name, unsigned int mask){ + // Check if interface already exists + if (!jtag_interface){ + LOG_ERROR("Interface does not yet exist!"); + return ERROR_FAIL; + } + + // Check if name is correct string + if (!name || strncmp(name, " ", 1)==0){ + LOG_ERROR("Signal name cannot be empty"); + return ERROR_FAIL; + } + + oocd_interface_signal_t *newsignal, *lastsignal; + int snlen; + + // Check signal length (min=1, max=32 characters) + snlen=strnlen(name, 32); + if (snlen<1 || snlen>32) { + LOG_ERROR("Signal name too short or too long!"); + return ERROR_FAIL; + } + + // Check if signal name already exist and return error if so + if (oocd_interface_signal_find(name)){ + LOG_ERROR("Specified signal already exist!"); + return ERROR_FAIL; + } + + // Allocate memory for new signal structure + newsignal=(oocd_interface_signal_t *)calloc(1, sizeof(oocd_interface_signal_t)); + if (!newsignal) { + LOG_ERROR("cannot allocate memory for new signal: %s", name); + return ERROR_FAIL; + } + newsignal->name=(char *)calloc(1, snlen+1); + if (!newsignal->name) { + LOG_ERROR("cannot allocate memory for signal %s name", name); + return ERROR_FAIL; + } + + // Initialize structure data and return or break on error + for(;;){ + if (!strncpy(newsignal->name, name, snlen)) { + LOG_ERROR("cannot copy signal %s name!", name); + break; + } + + newsignal->mask=mask; + newsignal->value=mask; + + if (!jtag_interface->signal){ + jtag_interface->signal=newsignal; + } else { + lastsignal=jtag_interface->signal; + while(lastsignal->next) {lastsignal=lastsignal->next;} + lastsignal->next=newsignal; + } + return ERROR_OK; + } + + // If there was an error free up resources and return error + free(newsignal->name); + free(newsignal); + return ERROR_FAIL; +} + +/** Delete interface signal. + * Removes signal from singly linked list of interface signals and free memory. + * \param name is the name of the signal to remove. + * \return ERROR_OK on success, ERROR_FAIL on failure. + */ +int oocd_interface_signal_del(char *name){ + // Check if interface already exists + if (!jtag_interface){ + LOG_ERROR("Interface does not yet exist!"); + return ERROR_FAIL; + } + // Check if interface any signal exist + if (!jtag_interface->signal){ + LOG_DEBUG("There are no signals defined yet."); + return ERROR_FAIL; + } + + // Check if signal name is correct + if (!name || strncmp(name, " ", 1)==0){ + LOG_ERROR("Signal name cannot be empty."); + return ERROR_FAIL; + } + + oocd_interface_signal_t *delsig=NULL, *prevsig=NULL; + + //look for the signal name on the list + delsig=oocd_interface_signal_find(name); + + //return error if signal is not on the list + if (!delsig){ + LOG_ERROR("Signal not found!"); + return ERROR_FAIL; + } + + //detach signal to be removed from the list + prevsig=jtag_interface->signal; + if (prevsig==delsig){ + //we need to detach first signal on the list + jtag_interface->signal=jtag_interface->signal->next; + } else { + for (;prevsig->next;prevsig=prevsig->next){ + if (prevsig->next==delsig) { + prevsig->next=prevsig->next->next; + break; + } + } + } + + //now free memory of detached element + free(delsig->name); + free(delsig); + return ERROR_OK; +} + diff --git a/src/interface/interface.h b/src/interface/interface.h new file mode 100644 index 00000000..36fbe1dd --- /dev/null +++ b/src/interface/interface.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2011 Tomasz Boleslaw CEDRO <cederom@tlen.pl> + * + * 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 + */ + + + +// THIS FILE IS UNUSABLE AT THE MOMENT BUT WILL BE USED AS GENERIC OPENOCD DRIVER STRUCTURE + +#ifndef OOCD_INTERFACE_H +#define OOCD_INTERFACE_H + +/** Some generic interface signal definitions. */ + +/// Interface Signal type declaration (single linked list element). +typedef struct oocd_interface_signal { + /// Signal name string. + char *name; + /// Mask value for selected signal. + unsigned int mask; + /// Value can be 0,1, or -1 for unknown state. + int value; + /// Pointer to the next element on the signals list. + struct oocd_interface_signal *next; +} oocd_interface_signal_t; + +typedef enum oocd_interface_operation { + UNDEFINED = 0, + READ, + WRITE, + SET, + CLEAR +} oocd_interface_operation_t; + +int oocd_interface_signal_add(char *name, unsigned int mask); +int oocd_interface_signal_del(char *name); +oocd_interface_signal_t *oocd_interface_signal_find(char *name); + +#endif |