1284 lines
23 KiB
C
1284 lines
23 KiB
C
/*
|
|
* Motorola Background Debug Mode Library
|
|
* Copyright (C) 1995 W. Eric Norum
|
|
* Copyright (C) 1998 Chris Johns
|
|
*
|
|
* Based on:
|
|
* 1. `A Background Debug Mode Driver Package for Motorola's
|
|
* 16-bit and 32-Bit Microcontrollers', Scott Howard, Motorola
|
|
* Canada, 1993.
|
|
* 2. `Linux device driver for public domain BDM Inteface',
|
|
* M. Schraut, Technische Universitaet Muenchen, Lehrstuhl
|
|
* fuer Prozessrechner, 1995.
|
|
*
|
|
* 31-11-1999 Chris Johns (ccj@acm.org)
|
|
* Extended to support remote operation. See bdmRemote.c for details.
|
|
*
|
|
* Extended to support the ColdFire BDM interface using the P&E module
|
|
* which comes with the EVB. Thanks to David Fiddes who has tested the
|
|
* driver with the 5206 (5V), 5206e (3.3V) and 5307 devices.
|
|
*
|
|
* 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.
|
|
*
|
|
* W. Eric Norum
|
|
* Saskatchewan Accelerator Laboratory
|
|
* University of Saskatchewan
|
|
* 107 North Road
|
|
* Saskatoon, Saskatchewan, CANADA
|
|
* S7N 5C6
|
|
*
|
|
* eric@skatter.usask.ca
|
|
*
|
|
* Coldfire support by:
|
|
* Chris Johns
|
|
* Objective Design Systems
|
|
*
|
|
* ccj@acm.org
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* If no remote/local directive is supplied, default to the
|
|
* existing local only mode.
|
|
*/
|
|
#if !defined (BDM_DEVICE_REMOTE) && !defined (BDM_DEVICE_LOCAL)
|
|
#define BDM_DEVICE_LOCAL
|
|
#endif
|
|
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <stdarg.h>
|
|
#include <stdint.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
|
|
/*
|
|
* This test should be done by autoconf. Please fix if you
|
|
* know how.
|
|
*/
|
|
#if !defined (__WIN32__) || defined (__CYGWIN__)
|
|
#define HAVE_SYSLOG 1
|
|
#include <syslog.h>
|
|
#endif
|
|
|
|
#include "BDMlib.h"
|
|
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
|
|
#include "bdmRemote.h"
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Provide the driver print interface so any debug IO
|
|
* does not end up on stdout if the library is embedded
|
|
* in a server, ie bdmd.
|
|
*/
|
|
|
|
#define PRINTF bdmPrint
|
|
|
|
/*
|
|
* If on Cygwin assume Windows.
|
|
*/
|
|
|
|
#if defined (__WIN32__) || defined (__CYGWIN__)
|
|
|
|
#include "../driver/win/win-bdm.c"
|
|
|
|
#else
|
|
|
|
/*
|
|
* See if this is an ioperm build.
|
|
*/
|
|
#if defined (BDM_IOPERM)
|
|
|
|
#include "../driver/ioperm/ioperm.c"
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
/*
|
|
* Limit of one BDM per process
|
|
*/
|
|
static int bdm_fd = -1;
|
|
static int cpu = BDM_CPU32;
|
|
static int iface = BDM_CPU32_PD;
|
|
|
|
/*
|
|
* The configuration data read from the configuration file.
|
|
*/
|
|
static char* config;
|
|
static size_t config_buffer_size = 0;
|
|
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
static int bdmRemote = 0;
|
|
#endif
|
|
|
|
/*
|
|
* Have to make global to allow the bdmBFD function have
|
|
* access.
|
|
*/
|
|
const char *bdmIO_lastErrorString = "No BDM error (yet!)";
|
|
|
|
/*
|
|
* Debugging
|
|
*/
|
|
static int debugFlag = 0;
|
|
#if HAVE_SYSLOG
|
|
static int debug_syslog = 0;
|
|
#endif
|
|
static const char *const sysregName[BDM_MAX_SYSREG] = {
|
|
"RPC", "PCC", "SR", "USP",
|
|
"SSP", "SFC", "DFC", "ATEMP",
|
|
"FAR", "VBR", "CACR", "ACR0",
|
|
"ACR1", "RAMBAR", "MBAR", "CSR",
|
|
"AATR", "TDR", "PBR", "PBMR",
|
|
"ABHR", "ABLR", "DBR", "DBMR",
|
|
};
|
|
|
|
static const char *const regName[] = {
|
|
"D0", "D1", "D2", "D3",
|
|
"D4", "D5", "D6", "D7",
|
|
"A0", "A1", "A2", "A3",
|
|
"A4", "A5", "A6", "A7",
|
|
};
|
|
|
|
void
|
|
bdmLogSyslog (void)
|
|
{
|
|
#if HAVE_SYSLOG
|
|
debug_syslog = 1;
|
|
#endif
|
|
}
|
|
|
|
void
|
|
bdmInfo (const char *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start (ap, format);
|
|
|
|
#if HAVE_SYSLOG
|
|
if (debug_syslog) {
|
|
if (debugFlag)
|
|
vsyslog (LOG_INFO, format, ap);
|
|
} else
|
|
#endif
|
|
{
|
|
vfprintf (stderr, format, ap);
|
|
fflush (stderr);
|
|
}
|
|
|
|
va_end (ap);
|
|
}
|
|
|
|
void
|
|
bdmPrint (const char *format, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start (ap, format);
|
|
|
|
if (debugFlag) {
|
|
#if HAVE_SYSLOG
|
|
if (debug_syslog) {
|
|
vsyslog (LOG_INFO, format, ap);
|
|
} else
|
|
#endif
|
|
{
|
|
fprintf (stderr, "BDM: ");
|
|
vfprintf (stderr, format, ap);
|
|
fflush (stderr);
|
|
}
|
|
}
|
|
|
|
va_end (ap);
|
|
}
|
|
|
|
void
|
|
bdmSetDebugFlag (int flag)
|
|
{
|
|
debugFlag = flag;
|
|
}
|
|
|
|
/*
|
|
* Verify that device is open
|
|
*/
|
|
int
|
|
bdmCheck (void)
|
|
{
|
|
if (bdm_fd < 0) {
|
|
bdmIO_lastErrorString = "BDM not open";
|
|
return 0;
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Like strerror(), but knows about BDM driver errors, too.
|
|
*/
|
|
static const char *
|
|
bdmStrerror (int error_no)
|
|
{
|
|
switch (error_no) {
|
|
case BDM_FAULT_UNKNOWN: return "Unknown BDM error";
|
|
case BDM_FAULT_POWER: return "No power to BDM adapter";
|
|
case BDM_FAULT_CABLE: return "BDM cable problem";
|
|
case BDM_FAULT_RESPONSE: return "No response to BDM request";
|
|
case BDM_FAULT_RESET: return "Target is in RESET state";
|
|
case BDM_FAULT_BERR: return "Target Bus Error";
|
|
case BDM_FAULT_NVC: return "Invalid target command";
|
|
case BDM_FAULT_FORCED_TA: return "Invalid target command - Forced TA";
|
|
}
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
return bdmRemoteStrerror (error_no);
|
|
#else
|
|
return strerror (error_no);
|
|
#endif
|
|
}
|
|
|
|
/*
|
|
* Do an int-argument BDM ioctl
|
|
*/
|
|
int
|
|
bdmIoctlInt (int code, int *var)
|
|
{
|
|
if (!bdmCheck ())
|
|
return -1;
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
if (bdmRemote) {
|
|
if (bdmRemoteIoctlInt (bdm_fd, code, var) < 0) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
#endif
|
|
#if defined (BDM_DEVICE_LOCAL)
|
|
if (ioctl (bdm_fd, code, var) < 0) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
return -1;
|
|
}
|
|
#endif
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Do a command (no-argument) BDM ioctl
|
|
*/
|
|
int
|
|
bdmIoctlCommand (int code)
|
|
{
|
|
if (!bdmCheck ())
|
|
return -1;
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
if (bdmRemote) {
|
|
if (bdmRemoteIoctlCommand (bdm_fd, code) < 0) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
#endif
|
|
#if defined (BDM_DEVICE_LOCAL)
|
|
if (ioctl (bdm_fd, code, NULL) < 0) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
return -1;
|
|
}
|
|
#endif
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Do a BDMioctl-argument BDM ioctl
|
|
*/
|
|
int
|
|
bdmIoctlIo (int code, struct BDMioctl *ioc)
|
|
{
|
|
if (!bdmCheck ())
|
|
return -1;
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
if (bdmRemote) {
|
|
if (bdmRemoteIoctlIo (bdm_fd, code, ioc) < 0) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
#endif
|
|
#if defined (BDM_DEVICE_LOCAL)
|
|
if (ioctl (bdm_fd, code, ioc) < 0) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
return -1;
|
|
}
|
|
#endif
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
}
|
|
#endif
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Do a BDM read
|
|
*/
|
|
int
|
|
bdmRead (unsigned char *cbuf, unsigned long nbytes)
|
|
{
|
|
if (!bdmCheck ())
|
|
return -1;
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
if (bdmRemote) {
|
|
if (bdmRemoteRead (bdm_fd, cbuf, nbytes) != nbytes) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
#endif
|
|
#if defined (BDM_DEVICE_LOCAL)
|
|
if (read (bdm_fd, (char*) cbuf, nbytes) != nbytes) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
return -1;
|
|
}
|
|
#endif
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
}
|
|
#endif
|
|
return nbytes;
|
|
}
|
|
|
|
/*
|
|
* Do a BDM write
|
|
*/
|
|
int
|
|
bdmWrite (unsigned char *cbuf, unsigned long nbytes)
|
|
{
|
|
if (!bdmCheck ())
|
|
return -1;
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
if (bdmRemote) {
|
|
if (bdmRemoteWrite (bdm_fd, cbuf, nbytes) != nbytes) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
#endif
|
|
#if defined (BDM_DEVICE_LOCAL)
|
|
if (write (bdm_fd, (char*) cbuf, nbytes) != nbytes) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
return -1;
|
|
}
|
|
#endif
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
}
|
|
#endif
|
|
return nbytes;
|
|
}
|
|
|
|
/*
|
|
* Read from the target
|
|
*/
|
|
static int
|
|
readTarget (int command, unsigned long address, unsigned long *lp)
|
|
{
|
|
struct BDMioctl ioc;
|
|
ioc.address = address;
|
|
ioc.value = 0;
|
|
if (bdmIoctlIo (command, &ioc) < 0)
|
|
return -1;
|
|
*lp = ioc.value;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write to the target
|
|
*/
|
|
static int
|
|
writeTarget (int command, unsigned long address, unsigned long l)
|
|
{
|
|
struct BDMioctl ioc;
|
|
ioc.address = address;
|
|
ioc.value = l;
|
|
if (bdmIoctlIo (command, &ioc) < 0)
|
|
return -1;
|
|
return 0;
|
|
}
|
|
|
|
static int
|
|
remoteOpen (const char *name)
|
|
{
|
|
int fd = -1;
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
if (bdmRemoteName (name)) {
|
|
bdmRemote = 1;
|
|
if ((fd = bdmRemoteOpen (name)) < 0) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
bdmRemote = 0;
|
|
}
|
|
}
|
|
#endif
|
|
return fd;
|
|
}
|
|
|
|
/*
|
|
* Return string describing most recent error
|
|
*/
|
|
const char *
|
|
bdmErrorString (void)
|
|
{
|
|
return bdmIO_lastErrorString;
|
|
}
|
|
|
|
/*
|
|
* Append the configuration data.
|
|
*/
|
|
static void
|
|
bdmAppendConfiguration (const char* fname)
|
|
{
|
|
FILE* file = fopen (fname, "r");
|
|
char line[256];
|
|
int count = 0;
|
|
|
|
if (!file)
|
|
return;
|
|
|
|
if (!config)
|
|
{
|
|
config = malloc (512);
|
|
config_buffer_size = 512;
|
|
memset (config, 0, config_buffer_size);
|
|
}
|
|
|
|
while (fgets (line, sizeof (line), file) != NULL)
|
|
{
|
|
int length;
|
|
|
|
count++;
|
|
|
|
length = strlen (line);
|
|
|
|
if (length)
|
|
{
|
|
int blank = 1;
|
|
int i;
|
|
|
|
for (i = 0; i < length; i++)
|
|
{
|
|
if (line[i] == '\r')
|
|
{
|
|
memmove (line + i, line + i + 1, length - i);
|
|
length--;
|
|
}
|
|
|
|
if (line[i] == '#')
|
|
{
|
|
if (i < (sizeof (line) - 1))
|
|
{
|
|
line[i] = '\n';
|
|
i++;
|
|
}
|
|
|
|
line[i] = '\0';
|
|
|
|
length = i;
|
|
}
|
|
}
|
|
|
|
if (length)
|
|
{
|
|
if (line[0] == '\n')
|
|
continue;
|
|
|
|
if ((line[length - 1] == '\n') && (line[length - 2] == '\\'))
|
|
{
|
|
line[length - 2] = '\0';
|
|
length -= 2;
|
|
}
|
|
}
|
|
|
|
if (!length)
|
|
continue;
|
|
|
|
if (length >= (config_buffer_size - strlen (config)))
|
|
{
|
|
char* new_config = realloc (config, config_buffer_size + 512);
|
|
|
|
if (new_config == NULL)
|
|
break;
|
|
|
|
config = new_config;
|
|
config_buffer_size += 512;
|
|
}
|
|
|
|
strcat (config, line);
|
|
}
|
|
}
|
|
|
|
fclose (file);
|
|
}
|
|
|
|
/*
|
|
* Read the configuration file.
|
|
*/
|
|
void
|
|
bdmReadConfiguration ()
|
|
{
|
|
char* env;
|
|
|
|
if (config)
|
|
return;
|
|
|
|
/*
|
|
* The configuration file is read local first then $HOME
|
|
* if $HOME is found or $M68K_BDM_INIT. If not found no
|
|
* configuration data is read.
|
|
*/
|
|
|
|
bdmAppendConfiguration (M68K_BDM_INIT_FILE);
|
|
|
|
env = getenv ("HOME");
|
|
|
|
if (env && strlen (env))
|
|
{
|
|
char* fname = malloc (strlen (env) + 2 + strlen (M68K_BDM_INIT_FILE));
|
|
|
|
if (fname)
|
|
{
|
|
char last;
|
|
|
|
strcpy (fname, env);
|
|
|
|
last = fname[strlen (fname) - 1];
|
|
|
|
if (last != '/' && last != '\\')
|
|
strcat (fname, "/");
|
|
|
|
strcat (fname, M68K_BDM_INIT_FILE);
|
|
|
|
bdmAppendConfiguration (fname);
|
|
|
|
free (fname);
|
|
}
|
|
}
|
|
|
|
env = getenv ("M68K_BDM_INIT");
|
|
|
|
if (env && strlen (env))
|
|
bdmAppendConfiguration (M68K_BDM_INIT_FILE);
|
|
}
|
|
|
|
/*
|
|
* Skip white space.
|
|
*/
|
|
const char*
|
|
bdmConfigSkipWhiteSpace (const char* text)
|
|
{
|
|
while (*text != '\n')
|
|
{
|
|
if (!isblank (*text))
|
|
break;
|
|
text++;
|
|
}
|
|
return text;
|
|
}
|
|
|
|
/*
|
|
* Find matching lines.
|
|
*/
|
|
const char*
|
|
bdmConfigGet (const char* label, const char* last)
|
|
{
|
|
const char* next = NULL;
|
|
|
|
if (config)
|
|
{
|
|
while (1)
|
|
{
|
|
if (last)
|
|
next = strchr (last, '\n') + 1;
|
|
else
|
|
next = config;
|
|
|
|
last = next;
|
|
|
|
if (*next == '\0')
|
|
{
|
|
next = NULL;
|
|
break;
|
|
}
|
|
|
|
next = bdmConfigSkipWhiteSpace (next);
|
|
|
|
if (strncmp (next, label, strlen (label)) == 0)
|
|
{
|
|
next += strlen (label);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return next;
|
|
}
|
|
|
|
/*
|
|
* Open the specified BDM device
|
|
*/
|
|
int
|
|
bdmOpen (const char *user_name)
|
|
{
|
|
#if defined (BDM_LIB_CHECKS_VERSION)
|
|
unsigned int ver;
|
|
#endif
|
|
char* name = NULL;
|
|
const char* mapping = NULL;
|
|
|
|
/*
|
|
* Load the configurations.
|
|
*/
|
|
bdmReadConfiguration ();
|
|
|
|
/*
|
|
* Map the name if a mapping is provided.
|
|
*/
|
|
while ((mapping = bdmConfigGet ("dev", mapping)))
|
|
{
|
|
mapping = bdmConfigSkipWhiteSpace (mapping);
|
|
|
|
if (strncmp (mapping, user_name, strlen (user_name)) == 0)
|
|
{
|
|
char* lf;
|
|
mapping += strlen (user_name);
|
|
name = strdup (bdmConfigSkipWhiteSpace (mapping));
|
|
lf = strchr (name, '\n');
|
|
if (lf)
|
|
*lf = '\0';
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!name)
|
|
name = strdup (user_name);
|
|
|
|
if (!name)
|
|
{
|
|
bdmIO_lastErrorString = bdmStrerror (ENOMEM);
|
|
return -1;
|
|
}
|
|
|
|
/*
|
|
* Open the interface. Name could be an ip:port address
|
|
* which results in tring to open a connection to the
|
|
* the remote server.
|
|
*
|
|
* First we try to open a remote connection if remote is
|
|
* supported. If this fails we attempt to open the driver.
|
|
*/
|
|
|
|
if (bdm_fd >= 0) {
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
if (bdmRemote)
|
|
bdmRemoteClose (bdm_fd);
|
|
#endif
|
|
#if defined (BDM_DEVICE_LOCAL)
|
|
else
|
|
close (bdm_fd);
|
|
#endif
|
|
}
|
|
|
|
bdm_fd = -1;
|
|
|
|
if ((bdm_fd = remoteOpen (name)) < 0) {
|
|
#if !defined (BDM_DEVICE_LOCAL)
|
|
bdmIO_lastErrorString = bdmStrerror (2);
|
|
free (name);
|
|
return -1;
|
|
#endif
|
|
}
|
|
|
|
#if defined (BDM_DEVICE_LOCAL)
|
|
if (bdm_fd < 0) {
|
|
if ((bdm_fd = open (name, O_RDWR)) < 0) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
free (name);
|
|
return -1;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
free (name);
|
|
|
|
#if defined (BDM_LIB_CHECKS_VERSION)
|
|
/*
|
|
* CCJ: This is better done by the user as they produce a better
|
|
* error message.
|
|
*/
|
|
/*
|
|
* Check the driver version.
|
|
*/
|
|
if (bdmGetDrvVersion (&ver) < 0) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
bdmClose ();
|
|
return -1;
|
|
}
|
|
if ((ver & 0xff00) != (BDM_DRV_VERSION & 0xff00)) {
|
|
bdmIO_lastErrorString = "invalid driver version";
|
|
bdmClose ();
|
|
return -1;
|
|
}
|
|
#endif
|
|
|
|
/*
|
|
* Get the processor and interface type
|
|
*/
|
|
if (bdmGetProcessor (&cpu) < 0) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
bdmClose ();
|
|
return -1;
|
|
}
|
|
if (bdmGetInterface (&iface) < 0) {
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
bdmClose ();
|
|
return -1;
|
|
}
|
|
|
|
return bdm_fd;
|
|
}
|
|
|
|
/*
|
|
* Close the specified BDM device
|
|
*/
|
|
int
|
|
bdmClose (void)
|
|
{
|
|
if (config)
|
|
{
|
|
free (config);
|
|
config = NULL;
|
|
config_buffer_size = 0;
|
|
}
|
|
|
|
if (!bdmCheck ())
|
|
return -1;
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
if (bdmRemote) {
|
|
bdmRemote = 0;
|
|
if (bdmRemoteClose (bdm_fd) < 0) {
|
|
bdm_fd = -1;
|
|
return -1;
|
|
}
|
|
}
|
|
else {
|
|
#endif
|
|
#if defined (BDM_DEVICE_LOCAL)
|
|
if (close (bdm_fd) < 0) {
|
|
bdm_fd = -1;
|
|
bdmIO_lastErrorString = bdmStrerror (errno);
|
|
return -1;
|
|
}
|
|
#endif
|
|
#if defined (BDM_DEVICE_REMOTE)
|
|
}
|
|
#endif
|
|
bdm_fd = -1;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Tell if interface is open
|
|
*/
|
|
int
|
|
bdmIsOpen (void)
|
|
{
|
|
return (bdm_fd >= 0);
|
|
}
|
|
|
|
/*
|
|
* Return the status of the BDM interface
|
|
*/
|
|
int
|
|
bdmStatus (void)
|
|
{
|
|
int status = 0;
|
|
if (bdmIoctlInt (BDM_GET_STATUS, &status) < 0)
|
|
return -1;
|
|
PRINTF ("Status %#x\n", status);
|
|
return status;
|
|
}
|
|
|
|
/*
|
|
* Set the delay time
|
|
*/
|
|
int
|
|
bdmSetDelay (int delay)
|
|
{
|
|
if (bdmIoctlInt (BDM_SPEED, &delay) < 0)
|
|
return -1;
|
|
PRINTF ("Set delay %d\n", delay);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Set the driver debug flag
|
|
*/
|
|
int
|
|
bdmSetDriverDebugFlag (int debugFlag)
|
|
{
|
|
if (bdmIoctlInt (BDM_DEBUG, &debugFlag) < 0)
|
|
return -1;
|
|
PRINTF ("Set driver debug flag %d\n", debugFlag);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Get the Coldfire PST enable state.
|
|
*/
|
|
int
|
|
bdmColdfireGetPST (int *pst)
|
|
{
|
|
if (bdmIoctlInt (BDM_GET_CF_PST, pst) < 0)
|
|
return -1;
|
|
PRINTF ("Get Coldfire PST state: %d\n", *pst);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Set the Coldfire PST enable state.
|
|
*/
|
|
int
|
|
bdmColdfireSetPST (int pst)
|
|
{
|
|
if (bdmIoctlInt (BDM_SET_CF_PST, &pst) < 0)
|
|
return -1;
|
|
PRINTF ("Set Coldfire PST state: %d\n", pst);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read a control register
|
|
*/
|
|
int
|
|
bdmReadControlRegister (int code, unsigned long *lp)
|
|
{
|
|
unsigned long ltmp = 0;
|
|
if (readTarget (BDM_READ_CTLREG, code, <mp) < 0)
|
|
return -1;
|
|
PRINTF ("Read control register 0x%04x: %#8lx\n", code, ltmp);
|
|
*lp = ltmp;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read a debug register
|
|
*/
|
|
int
|
|
bdmReadDebugRegister (int code, unsigned long *lp)
|
|
{
|
|
unsigned long ltmp = 0;
|
|
if (readTarget (BDM_READ_DBREG, code, <mp) < 0)
|
|
return -1;
|
|
PRINTF ("Read debug register 0x%04x: %#8lx\n", code, ltmp);
|
|
*lp = ltmp;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read a system register
|
|
*/
|
|
int
|
|
bdmReadSystemRegister (int code, unsigned long *lp)
|
|
{
|
|
unsigned long ltmp = 0;
|
|
if (readTarget (BDM_READ_SYSREG, code, <mp) < 0)
|
|
return -1;
|
|
PRINTF ("Read system register %s: %#8lx\n", sysregName[code], ltmp);
|
|
*lp = ltmp;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read a register
|
|
*/
|
|
int
|
|
bdmReadRegister (int code, unsigned long *lp)
|
|
{
|
|
unsigned long ltmp = 0;
|
|
code &= 0xF;
|
|
if (readTarget (BDM_READ_REG, code, <mp) < 0)
|
|
return -1;
|
|
PRINTF ("Read register %s: %#8lx\n", regName[code], ltmp);
|
|
*lp = ltmp;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write a control register
|
|
*/
|
|
int
|
|
bdmWriteControlRegister (int code, unsigned long l)
|
|
{
|
|
if (writeTarget (BDM_WRITE_CTLREG, code, l) < 0)
|
|
return -1;
|
|
PRINTF ("Write control register 0x%04x: %#8lx\n", code, l);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write a debug register
|
|
*/
|
|
int
|
|
bdmWriteDebugRegister (int code, unsigned long l)
|
|
{
|
|
if (writeTarget (BDM_WRITE_DBREG, code, l) < 0)
|
|
return -1;
|
|
PRINTF ("Write debug register 0x%04x: %#8lx\n", code, l);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write a system register
|
|
*/
|
|
int
|
|
bdmWriteSystemRegister (int code, unsigned long l)
|
|
{
|
|
if (writeTarget (BDM_WRITE_SYSREG, code, l) < 0)
|
|
return -1;
|
|
PRINTF ("Write system register %s: %#8lx\n",
|
|
sysregName[code], l);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write a register
|
|
*/
|
|
int
|
|
bdmWriteRegister (int code, unsigned long l)
|
|
{
|
|
if (writeTarget (BDM_WRITE_REG, code, l) < 0)
|
|
return -1;
|
|
PRINTF ("Write register %s: %#8lx\n", regName[code], l);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read a long word
|
|
*/
|
|
int
|
|
bdmReadLongWord (unsigned long address, unsigned long *lp)
|
|
{
|
|
unsigned long ltmp;
|
|
|
|
if (readTarget (BDM_READ_LONGWORD, address, <mp) < 0)
|
|
return -1;
|
|
PRINTF ("Read %#8.8lx @ %#8lx\n", ltmp, address);
|
|
*lp = ltmp;
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read a word
|
|
*/
|
|
int
|
|
bdmReadWord (unsigned long address, unsigned short *sp)
|
|
{
|
|
unsigned long ltmp;
|
|
|
|
if (readTarget (BDM_READ_WORD, address, <mp) < 0)
|
|
return -1;
|
|
*sp = ltmp;
|
|
PRINTF ("Read %#4.4x @ %#8lx\n", (unsigned short) ltmp, address);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Read a byte
|
|
*/
|
|
int
|
|
bdmReadByte (unsigned long address, unsigned char *cp)
|
|
{
|
|
unsigned long ltmp;
|
|
|
|
if (readTarget (BDM_READ_BYTE, address, <mp) < 0)
|
|
return -1;
|
|
*cp = ltmp;
|
|
PRINTF ("Read %#2.2x @ %#8lx\n", (unsigned char)ltmp, address);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write a long word
|
|
*/
|
|
int
|
|
bdmWriteLongWord (unsigned long address, unsigned long l)
|
|
{
|
|
PRINTF ("Write %#8.8lx @ %#8lx\n", l, address);
|
|
return writeTarget (BDM_WRITE_LONGWORD, address, l);
|
|
}
|
|
|
|
/*
|
|
* Write a word
|
|
*/
|
|
int
|
|
bdmWriteWord (unsigned long address, unsigned short s)
|
|
{
|
|
PRINTF ("Write %#4.4x @ %#8lx\n", s, address);
|
|
return writeTarget (BDM_WRITE_WORD, address, s);
|
|
}
|
|
|
|
/*
|
|
* Write a byte
|
|
*/
|
|
int
|
|
bdmWriteByte (unsigned long address, unsigned char c)
|
|
{
|
|
PRINTF ("Write %#2.2x @ %#8lx\n", c, address);
|
|
return writeTarget (BDM_WRITE_BYTE, address, c);
|
|
}
|
|
|
|
/*
|
|
* Read the Module Base Address Register
|
|
*/
|
|
int
|
|
bdmReadMBAR (unsigned long *lp)
|
|
{
|
|
return bdmReadSystemRegister (BDM_REG_MBAR, lp);
|
|
}
|
|
|
|
/*
|
|
* Write the Module Base Address Register
|
|
*/
|
|
int
|
|
bdmWriteMBAR (unsigned long l)
|
|
{
|
|
return bdmWriteSystemRegister (BDM_REG_MBAR, l);
|
|
}
|
|
|
|
/*
|
|
* Reset the target and disable BDM operation
|
|
*/
|
|
int
|
|
bdmRelease (void)
|
|
{
|
|
PRINTF ("Release\n");
|
|
return bdmIoctlCommand (BDM_RELEASE_CHIP);
|
|
}
|
|
|
|
/*
|
|
* Reset the target, enable BDM operation, enter BDM
|
|
*/
|
|
int
|
|
bdmReset (void)
|
|
{
|
|
PRINTF ("Reset\n");
|
|
return bdmIoctlCommand (BDM_RESET_CHIP);
|
|
}
|
|
|
|
/*
|
|
* Restart the chip.
|
|
*/
|
|
int
|
|
bdmRestart (void)
|
|
{
|
|
PRINTF ("Restart\n");
|
|
return bdmIoctlCommand (BDM_RESTART_CHIP);
|
|
}
|
|
|
|
/*
|
|
* Restart target execution
|
|
*/
|
|
int
|
|
bdmGo (void)
|
|
{
|
|
PRINTF ("Go\n");
|
|
return bdmIoctlCommand (BDM_GO);
|
|
}
|
|
|
|
/*
|
|
* Stop the target
|
|
*/
|
|
int
|
|
bdmStop (void)
|
|
{
|
|
PRINTF ("Stop\n");
|
|
return bdmIoctlCommand (BDM_STOP_CHIP);
|
|
}
|
|
|
|
/*
|
|
* Single-step the target
|
|
*/
|
|
int
|
|
bdmStep (void)
|
|
{
|
|
PRINTF ("Step\n");
|
|
return bdmIoctlCommand (BDM_STEP_CHIP);
|
|
}
|
|
|
|
/*
|
|
* Read target memory
|
|
* `cbuf' is in target byte order
|
|
*/
|
|
int
|
|
bdmReadMemory (unsigned long address, unsigned char *cbuf, unsigned long nbytes)
|
|
{
|
|
if (nbytes == 0)
|
|
return 0;
|
|
|
|
if (!bdmCheck ())
|
|
return -1;
|
|
|
|
/*
|
|
* Transfer first part and set up target address pointer
|
|
*/
|
|
if (((address & 0x3) == 0) && (nbytes >= 4)) {
|
|
unsigned long l;
|
|
|
|
if (bdmReadLongWord (address, &l) < 0)
|
|
return -1;
|
|
*cbuf++ = l >> 24;
|
|
*cbuf++ = l >> 16;
|
|
*cbuf++ = l >> 8;
|
|
*cbuf++ = l;
|
|
address += 4;
|
|
nbytes -= 4;
|
|
}
|
|
else if (((address & 0x1) == 0) && (nbytes >= 2)) {
|
|
unsigned short s;
|
|
|
|
if (bdmReadWord (address, &s) < 0)
|
|
return -1;
|
|
*cbuf++ = s >> 8;
|
|
*cbuf++ = s;
|
|
address += 2;
|
|
nbytes -= 2;
|
|
}
|
|
else {
|
|
do {
|
|
if (bdmReadByte (address, cbuf) < 0)
|
|
return -1;
|
|
cbuf++;
|
|
address++;
|
|
nbytes--;
|
|
} while (nbytes && (address & 0x3));
|
|
}
|
|
if (nbytes == 0)
|
|
return 0;
|
|
if (bdmRead (cbuf, nbytes) < 0)
|
|
return -1;
|
|
PRINTF ("Read %d byte%s\n", nbytes, nbytes == 1 ? "" : "s");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Write target memory
|
|
* `cbuf' is in target byte order
|
|
*/
|
|
int
|
|
bdmWriteMemory (unsigned long address, unsigned char *cbuf, unsigned long nbytes)
|
|
{
|
|
int ret;
|
|
|
|
if (nbytes == 0)
|
|
return 0;
|
|
|
|
if (!bdmCheck ())
|
|
return -1;
|
|
|
|
/*
|
|
* Transfer first part and set up target address pointer
|
|
*/
|
|
if (((address & 0x3) == 0) && (nbytes >= 4)) {
|
|
unsigned long l;
|
|
|
|
l = (unsigned long)*cbuf++ << 24;
|
|
l |= (unsigned long)*cbuf++ << 16;
|
|
l |= (unsigned long)*cbuf++ << 8;
|
|
l |= (unsigned long)*cbuf++;
|
|
if (bdmWriteLongWord (address, l) < 0)
|
|
return -1;
|
|
address += 4;
|
|
nbytes -= 4;
|
|
}
|
|
else if (((address & 0x1) == 0) && (nbytes >= 2)) {
|
|
unsigned short s;
|
|
|
|
s = (unsigned short)*cbuf++ << 8;
|
|
s |= (unsigned short)*cbuf++;
|
|
if (bdmWriteWord (address, s) < 0)
|
|
return -1;
|
|
address += 2;
|
|
nbytes -= 2;
|
|
}
|
|
else {
|
|
do {
|
|
if (bdmWriteByte (address, *cbuf) < 0)
|
|
return -1;
|
|
cbuf++;
|
|
address++;
|
|
nbytes--;
|
|
} while (nbytes && (address & 0x3));
|
|
}
|
|
if (nbytes == 0)
|
|
return 0;
|
|
ret = bdmWrite (cbuf, nbytes);
|
|
if (ret < 0)
|
|
return -1;
|
|
PRINTF ("Wrote %d byte%s\n", nbytes, nbytes == 1 ? "" : "s");
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Get Driver version
|
|
*/
|
|
int
|
|
bdmGetDrvVersion (unsigned int *ver)
|
|
{
|
|
if (bdmIoctlInt (BDM_GET_DRV_VER, (int*) ver) < 0)
|
|
return -1;
|
|
PRINTF ("Driver version: %d.%d\n", *ver >> 8, *ver & 0xff);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Get Processor type
|
|
*/
|
|
int
|
|
bdmGetProcessor (int *processor)
|
|
{
|
|
if (bdmIoctlInt (BDM_GET_CPU_TYPE, processor) < 0)
|
|
return -1;
|
|
PRINTF ("CPU type: %d\n", *processor);
|
|
return 0;
|
|
}
|
|
|
|
/*
|
|
* Get Interface type
|
|
*/
|
|
int
|
|
bdmGetInterface (int *iface)
|
|
{
|
|
if (bdmIoctlInt (BDM_GET_IF_TYPE, iface) < 0)
|
|
return -1;
|
|
PRINTF ("Interface type: %d\n", *iface);
|
|
return 0;
|
|
}
|