/* bsdl.c - BSDL file handler for the advanced JTAG bridge
|
/* bsdl.c - BSDL file handler for the advanced JTAG bridge
|
Copyright(C) 2008 Nathan Yawn
|
Copyright(C) 2008 Nathan Yawn
|
|
|
This program is free software; you can redistribute it and/or modify
|
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
|
it under the terms of the GNU General Public License as published by
|
the Free Software Foundation; either version 2 of the License, or
|
the Free Software Foundation; either version 2 of the License, or
|
(at your option) any later version.
|
(at your option) any later version.
|
|
|
This program is distributed in the hope that it will be useful,
|
This program is distributed in the hope that it will be useful,
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
GNU General Public License for more details.
|
GNU General Public License for more details.
|
|
|
You should have received a copy of the GNU General Public License
|
You should have received a copy of the GNU General Public License
|
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
*/
|
*/
|
|
|
#include <sys/types.h>
|
#include <sys/types.h>
|
#include <string.h>
|
#include <string.h>
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <dirent.h>
|
#include <dirent.h>
|
#include "bsdl.h"
|
#include "bsdl.h"
|
#include "bsdl_parse.h"
|
#include "bsdl_parse.h"
|
|
|
|
|
#define debug(...) //fprintf(stderr, __VA_ARGS__ )
|
#define debug(...) //fprintf(stderr, __VA_ARGS__ )
|
|
|
// Globals to deal with directory names
|
// Globals to deal with directory names
|
#define MAX_BSDL_DIRS 64 // Any more than this would take a looooong time...
|
#define MAX_BSDL_DIRS 64 // Any more than this would take a looooong time...
|
static char *bsdl_dirs[MAX_BSDL_DIRS];
|
static char *bsdl_dirs[MAX_BSDL_DIRS];
|
static int bsdl_current_dir = 0; // We try them in reverse order
|
static int bsdl_current_dir = 0; // We try them in reverse order
|
|
|
// Globals to hold the current, open directory
|
// Globals to hold the current, open directory
|
DIR *bsdl_open_dir = NULL;
|
DIR *bsdl_open_dir = NULL;
|
|
|
// Globals to hold BSDL info
|
// Globals to hold BSDL info
|
static bsdlinfo *bsdl_head = NULL;
|
static bsdlinfo *bsdl_head = NULL;
|
static bsdlinfo *bsdl_tail = NULL;
|
static bsdlinfo *bsdl_tail = NULL;
|
static bsdlinfo *bsdl_last = NULL; // optimization: pointer to the last struct we used (not necessarily the last in the linked list)
|
static bsdlinfo *bsdl_last = NULL; // optimization: pointer to the last struct we used (not necessarily the last in the linked list)
|
|
|
// Prototypes for local functions
|
// Prototypes for local functions
|
bsdlinfo *get_bsdl_info(uint32_t idcode);
|
bsdlinfo *get_bsdl_info(uint32_t idcode);
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////
|
// API for init and config
|
// API for init and config
|
|
|
void bsdl_init(void)
|
void bsdl_init(void)
|
{
|
{
|
bsdl_dirs[0] = strdup("/opt/bsdl");
|
bsdl_dirs[0] = strdup("/opt/bsdl");
|
bsdl_dirs[1] = strdup("/usr/share/bsdl");
|
bsdl_dirs[1] = strdup("/usr/share/bsdl");
|
bsdl_dirs[2] = strdup("~/.bsdl");
|
bsdl_dirs[2] = strdup("~/.bsdl");
|
bsdl_dirs[3] = strdup(".");
|
bsdl_dirs[3] = strdup(".");
|
bsdl_current_dir = 3;
|
bsdl_current_dir = 3;
|
}
|
}
|
|
|
void bsdl_add_directory(const char *dirname)
|
void bsdl_add_directory(const char *dirname)
|
{
|
{
|
if(bsdl_current_dir >= (MAX_BSDL_DIRS-1)) {
|
if(bsdl_current_dir >= (MAX_BSDL_DIRS-1)) {
|
printf("Max BSDL dirs (%d) exceeded; failed to add directory %s\n", MAX_BSDL_DIRS, dirname);
|
printf("Max BSDL dirs (%d) exceeded; failed to add directory %s\n", MAX_BSDL_DIRS, dirname);
|
return;
|
return;
|
}
|
}
|
|
|
bsdl_current_dir++;
|
bsdl_current_dir++;
|
bsdl_dirs[bsdl_current_dir] = strdup(dirname);
|
bsdl_dirs[bsdl_current_dir] = strdup(dirname);
|
}
|
}
|
|
|
|
|
///////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////
|
// API to get device info from BSDL files, if available
|
// API to get device info from BSDL files, if available
|
|
|
|
|
const char * bsdl_get_name(uint32_t idcode)
|
const char * bsdl_get_name(uint32_t idcode)
|
{
|
{
|
bsdlinfo *info;
|
bsdlinfo *info;
|
info = get_bsdl_info(idcode);
|
info = get_bsdl_info(idcode);
|
if(info != NULL)
|
if(info != NULL)
|
return info->name;
|
return info->name;
|
|
|
return NULL;
|
return NULL;
|
|
|
|
|
}
|
}
|
|
|
// Return the IR length of the device with the given IDCODE,
|
// Return the IR length of the device with the given IDCODE,
|
// if its BSDL file is available. Returns -1 on
|
// if its BSDL file is available. Returns -1 on
|
// error, which is an invalid size.
|
// error, which is an invalid size.
|
|
|
int bsdl_get_IR_size(uint32_t idcode)
|
int bsdl_get_IR_size(uint32_t idcode)
|
{
|
{
|
bsdlinfo *info;
|
bsdlinfo *info;
|
info = get_bsdl_info(idcode);
|
info = get_bsdl_info(idcode);
|
if(info != NULL)
|
if(info != NULL)
|
return info->IR_size;
|
return info->IR_size;
|
|
|
return -1;
|
return -1;
|
}
|
}
|
|
|
|
|
// Returns the DEBUG command for the device with the gived IDCODE,
|
// Returns the DEBUG command for the device with the gived IDCODE,
|
// if its BSDL file is available. Returns 0xFFFFFFFF on error,
|
// if its BSDL file is available. Returns 0xFFFFFFFF on error,
|
// which is as invalid command (because it's the BYPASS command)
|
// which is as invalid command (because it's the BYPASS command)
|
uint32_t bsdl_get_debug_cmd(uint32_t idcode)
|
uint32_t bsdl_get_debug_cmd(uint32_t idcode)
|
{
|
{
|
bsdlinfo *info;
|
bsdlinfo *info;
|
info = get_bsdl_info(idcode);
|
info = get_bsdl_info(idcode);
|
if(info != NULL)
|
if(info != NULL)
|
return info->cmd_debug;
|
return info->cmd_debug;
|
return TAP_CMD_INVALID;
|
return TAP_CMD_INVALID;
|
}
|
}
|
|
|
// Returns the USER1 command for the device with the gived IDCODE,
|
// Returns the USER1 command for the device with the gived IDCODE,
|
// if its BSDL file is available. Returns 0xFFFFFFFF on error,
|
// if its BSDL file is available. Returns 0xFFFFFFFF on error,
|
// which is as invalid command (because it's the BYPASS command)
|
// which is as invalid command (because it's the BYPASS command)
|
uint32_t bsdl_get_user1_cmd(uint32_t idcode)
|
uint32_t bsdl_get_user1_cmd(uint32_t idcode)
|
{
|
{
|
bsdlinfo *info;
|
bsdlinfo *info;
|
info = get_bsdl_info(idcode);
|
info = get_bsdl_info(idcode);
|
if(info != NULL)
|
if(info != NULL)
|
return info->cmd_user1;
|
return info->cmd_user1;
|
return TAP_CMD_INVALID;
|
return TAP_CMD_INVALID;
|
}
|
}
|
|
|
// Returns the IDCODE command for the device with the gived IDCODE,
|
// Returns the IDCODE command for the device with the gived IDCODE,
|
// if its BSDL file is available. Returns 0xFFFFFFFF on error,
|
// if its BSDL file is available. Returns 0xFFFFFFFF on error,
|
// which is as invalid command (because it's the BYPASS command)
|
// which is as invalid command (because it's the BYPASS command)
|
uint32_t bsdl_get_idcode_cmd(uint32_t idcode)
|
uint32_t bsdl_get_idcode_cmd(uint32_t idcode)
|
{
|
{
|
bsdlinfo *info;
|
bsdlinfo *info;
|
info = get_bsdl_info(idcode);
|
info = get_bsdl_info(idcode);
|
if(info != NULL)
|
if(info != NULL)
|
return info->cmd_idcode;
|
return info->cmd_idcode;
|
return TAP_CMD_INVALID;
|
return TAP_CMD_INVALID;
|
}
|
}
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
/////////////////////////////////////////////////////////////////////////////
|
// Internal routines
|
// Internal routines
|
|
|
|
|
// This uses a lazy algorithm...first, search data we already have.
|
// This uses a lazy algorithm...first, search data we already have.
|
// Then, parse new files (storing all data) only until we find
|
// Then, parse new files (storing all data) only until we find
|
// the data we want.
|
// the data we want.
|
bsdlinfo *get_bsdl_info(uint32_t idcode)
|
bsdlinfo *get_bsdl_info(uint32_t idcode)
|
{
|
{
|
struct dirent *direntry = NULL;
|
struct dirent *direntry = NULL;
|
bsdlinfo *ptr = bsdl_head;
|
bsdlinfo *ptr = bsdl_head;
|
char *c;
|
char *c;
|
|
|
// Check the last place we looked
|
// Check the last place we looked
|
if(bsdl_last != NULL)
|
if(bsdl_last != NULL)
|
if((bsdl_last->idcode & bsdl_last->idcode_mask) == (idcode & bsdl_last->idcode_mask))
|
if((bsdl_last->idcode & bsdl_last->idcode_mask) == (idcode & bsdl_last->idcode_mask))
|
return bsdl_last;
|
return bsdl_last;
|
|
|
// First, search through the info already parsed
|
// First, search through the info already parsed
|
while(ptr != NULL)
|
while(ptr != NULL)
|
{
|
{
|
if((ptr->idcode & ptr->idcode_mask) == (idcode & ptr->idcode_mask))
|
if((ptr->idcode & ptr->idcode_mask) == (idcode & ptr->idcode_mask))
|
{
|
{
|
bsdl_last = ptr;
|
bsdl_last = ptr;
|
return ptr;
|
return ptr;
|
}
|
}
|
ptr = ptr->next;
|
ptr = ptr->next;
|
}
|
}
|
|
|
// Parse files until we get the IDCODE we want
|
// Parse files until we get the IDCODE we want
|
while(1)
|
while(1)
|
{
|
{
|
// Find and open a valid directory
|
// Find and open a valid directory
|
while(bsdl_open_dir == NULL)
|
while(bsdl_open_dir == NULL)
|
{
|
{
|
if(bsdl_current_dir < 0)
|
if(bsdl_current_dir < 0)
|
return NULL; // There are no more directories to check
|
return NULL; // There are no more directories to check
|
debug("Trying BSDL dir \'%s\'\n", bsdl_dirs[bsdl_current_dir]);
|
debug("Trying BSDL dir \'%s\'\n", bsdl_dirs[bsdl_current_dir]);
|
bsdl_open_dir = opendir(bsdl_dirs[bsdl_current_dir]);
|
bsdl_open_dir = opendir(bsdl_dirs[bsdl_current_dir]);
|
if((bsdl_open_dir == NULL) && (bsdl_current_dir > 2)) // Don't warn if default dirs not found
|
if((bsdl_open_dir == NULL) && (bsdl_current_dir > 2)) // Don't warn if default dirs not found
|
printf("Warning: unable to open BSDL directory \'%s\'\n", bsdl_dirs[bsdl_current_dir]);
|
printf("Warning: unable to open BSDL directory \'%s\'\n", bsdl_dirs[bsdl_current_dir]);
|
bsdl_current_dir--;
|
bsdl_current_dir--;
|
direntry = NULL;
|
direntry = NULL;
|
}
|
}
|
|
|
// Find a BSDL file
|
// Find a BSDL file
|
do
|
do
|
{
|
{
|
direntry = readdir(bsdl_open_dir);
|
direntry = readdir(bsdl_open_dir);
|
if(direntry == NULL)
|
if(direntry == NULL)
|
{ // We've exhausted this directory
|
{ // We've exhausted this directory
|
closedir(bsdl_open_dir);
|
closedir(bsdl_open_dir);
|
bsdl_open_dir = NULL;
|
bsdl_open_dir = NULL;
|
break;
|
break;
|
}
|
}
|
|
|
// *** If a subdirectory, continue!!
|
// *** If a subdirectory, continue!!
|
|
|
// Check if it's a BSDL file: .bsd, .bsdl, .BSD, .BSDL
|
// Check if it's a BSDL file: .bsd, .bsdl, .BSD, .BSDL
|
debug("Checking file \'%s\'\n", direntry->d_name);
|
debug("Checking file \'%s\'\n", direntry->d_name);
|
c = strrchr(direntry->d_name, '.');
|
c = strrchr(direntry->d_name, '.');
|
debug("File extension is \'%s\'\n", c);
|
debug("File extension is \'%s\'\n", c);
|
if(c == NULL)
|
if(c == NULL)
|
continue;
|
continue;
|
if(!strcmp(c, ".bsd") || !strcmp(c, ".bsdl") || !strcmp(c, ".BSD") || !strcmp(c, ".BSDL"))
|
if(!strcmp(c, ".bsd") || !strcmp(c, ".bsdl") || !strcmp(c, ".BSD") || !strcmp(c, ".BSDL"))
|
break;
|
break;
|
|
|
}
|
}
|
while(1);
|
while(1);
|
|
|
if(direntry == NULL) // We need a new directory
|
if(direntry == NULL) // We need a new directory
|
continue;
|
continue;
|
|
|
// Parse the BSDL file we found
|
// Parse the BSDL file we found
|
debug("Parsing file \'%s\'\n", direntry->d_name);
|
debug("Parsing file \'%s\'\n", direntry->d_name);
|
ptr = parse_extract_values(direntry->d_name);
|
ptr = parse_extract_values(direntry->d_name);
|
|
|
// If we got good data...
|
// If we got good data...
|
if(ptr != NULL)
|
if(ptr != NULL)
|
{
|
{
|
// Store the values...
|
// Store the values...
|
if(bsdl_head == NULL) {
|
if(bsdl_head == NULL) {
|
bsdl_head = ptr;
|
bsdl_head = ptr;
|
bsdl_tail = ptr;
|
bsdl_tail = ptr;
|
} else {
|
} else {
|
bsdl_tail->next = ptr;
|
bsdl_tail->next = ptr;
|
bsdl_tail = ptr;
|
bsdl_tail = ptr;
|
}
|
}
|
|
|
// ...and return if we got an IDCODE match
|
// ...and return if we got an IDCODE match
|
if((ptr->idcode & ptr->idcode_mask) == (idcode & ptr->idcode_mask)) {
|
if((ptr->idcode & ptr->idcode_mask) == (idcode & ptr->idcode_mask)) {
|
bsdl_last = ptr;
|
bsdl_last = ptr;
|
return ptr;
|
return ptr;
|
}
|
}
|
}
|
}
|
} // while(1), parse files until we find a match or run out of dirs / files
|
} // while(1), parse files until we find a match or run out of dirs / files
|
|
|
|
|
// If no more files to parse and not found, return NULL
|
// If no more files to parse and not found, return NULL
|
return NULL;
|
return NULL;
|
}
|
}
|
|
|