summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/interface/Makefile.am27
-rw-r--r--src/interface/bitbang.c151
-rw-r--r--src/interface/bitbang.h27
-rw-r--r--src/interface/interface.c203
-rw-r--r--src/interface/interface.h52
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