准备用Arduio来实现自己的jtag adapter,so分析分析remote_bitbang驱动。
在 interfaces.c 中,有一个BUILD_REMOTE_BITBANG的开关,在make之前,由configure 加入--enable-remote-bitbang开关
#if BUILD_REMOTE_BITBANG == 1
extern struct jtag_interface remote_bitbang_interface;
#endif
随后,在后续代码中注册:
/**
* The list of built-in JTAG interfaces, containing entries for those
* drivers that were enabled by the @c configure script.
*
* The list should be defined to contain either one minidriver interface
* or some number of standard driver interfaces, never both.
*/
struct jtag_interface *jtag_interfaces[] = {
#if BUILD_ZY1000 == 1
&zy1000_interface,
#elif defined(BUILD_MINIDRIVER_DUMMY)
&minidummy_interface,
#else/* standard drivers */
#if BUILD_PARPORT == 1
&parport_interface,
#endif
// 省略其他代码
#if BUILD_REMOTE_BITBANG == 1
&remote_bitbang_interface,
#endif
// 省略其他代码
#endif /* standard drivers */
NULL,
};
然后,让我们一起来看看remote_bitbang.c里面的三个关键结构:
1.bitbang_interface
staticstruct bitbang_interface remote_bitbang_bitbang = {
.read = &remote_bitbang_read,
.write = &remote_bitbang_write,
.reset = &remote_bitbang_reset,
.blink = &remote_bitbang_blink,
};
2.command_registration
staticconststruct command_registration remote_bitbang_command_handlers[] = {
{
.name = "remote_bitbang_port",
.handler = remote_bitbang_handle_remote_bitbang_port_command,
.mode = COMMAND_CONFIG,
.help = "Set the port to use to connect to the remote jtag.\n"
" if 0 or unset, use unix sockets to connect to the remote jtag.",
.usage = "port_number",
},
{
.name = "remote_bitbang_host",
.handler = remote_bitbang_handle_remote_bitbang_host_command,
.mode = COMMAND_CONFIG,
.help = "Set the host to use to connect to the remote jtag.\n"
" if port is 0 or unset, this is the name of the unix socket to use.",
.usage = "host_name",
},
COMMAND_REGISTRATION_DONE,
};
3.jtag_interface
struct jtag_interface remote_bitbang_interface = {
.name = "remote_bitbang",
.execute_queue = &bitbang_execute_queue,
.commands = remote_bitbang_command_handlers,
.init = &remote_bitbang_init,
.quit = &remote_bitbang_quit,
};
我们从后往前分析:
jtag_interface是所有jtag的抽象接口,每一个具体的jtag实现,必须要定义自己的jtag_interface。定义好该结构后,在文章最前面提到的interfaces.c中注册,就算完成了该驱动的注册。
command_registration结构:用来注册jtag相关的命令及其handler实现。如remote_bitbang中的端口和host定义。
现在来到最关键的地方:
bitbang_interface,因为remote_bitbang也属于bitbang_interface,因此在此处定义的结构,属于该jtag专属的“业务逻辑”,系统发出的jtag命令,由该结构定义的函数来实现。
注意jtag_interface中的
.execute_queue = &bitbang_execute_queue,
所有实现了bitbang(如parallel)的jtag都调用的是相同的抽象函数bitbang_execute_queue
该函数位于bitbang.c中,代码不算长,该函数实现了真正的jtag控制逻辑:
int bitbang_execute_queue(void)
{
struct jtag_command *cmd = jtag_command_queue; /* currently processed command */
int scan_size;
enum scan_type type;
uint8_t *buffer;
int retval;
if (!bitbang_interface) {
LOG_ERROR("BUG: Bitbang interface called, but not yet initialized");
exit(-1);
}
/* return ERROR_OK, unless a jtag_read_buffer returns a failed check
* that wasn't handled by a caller-provided error handler
*/
retval = ERROR_OK;
if (bitbang_interface->blink)
bitbang_interface->blink(1);
while (cmd) {
switch (cmd->type) {
case JTAG_RESET:
#ifdef _DEBUG_JTAG_IO_
LOG_DEBUG("reset trst: %i srst %i",
cmd->cmd.reset->trst,
cmd->cmd.reset->srst);
#endif
if ((cmd->cmd.reset->trst == 1) ||
(cmd->cmd.reset->srst && (jtag_get_reset_config() & RESET_SRST_PULLS_TRST)))
tap_set_state(TAP_RESET);
bitbang_interface->reset(cmd->cmd.reset->trst, cmd->cmd.reset->srst);
break;
case JTAG_RUNTEST:
#ifdef _DEBUG_JTAG_IO_
LOG_DEBUG("runtest %i cycles, end in %s",
cmd->cmd.runtest->num_cycles,
tap_state_name(cmd->cmd.runtest->end_state));
#endif
bitbang_end_state(cmd->cmd.runtest->end_state);
bitbang_runtest(cmd->cmd.runtest->num_cycles);
break;
case JTAG_STABLECLOCKS:
/* this is only allowed while in a stable state. A check for a stable
* state was done in jtag_add_clocks()
*/
bitbang_stableclocks(cmd->cmd.stableclocks->num_cycles);
break;
case JTAG_TLR_RESET:
#ifdef _DEBUG_JTAG_IO_
LOG_DEBUG("statemove end in %s",
tap_state_name(cmd->cmd.statemove->end_state));
#endif
bitbang_end_state(cmd->cmd.statemove->end_state);
bitbang_state_move(0);
break;
case JTAG_PATHMOVE:
#ifdef _DEBUG_JTAG_IO_
LOG_DEBUG("pathmove: %i states, end in %s",
cmd->cmd.pathmove->num_states,
tap_state_name(cmd->cmd.pathmove->path[cmd->cmd.pathmove->num_states - 1]));
#endif
bitbang_path_move(cmd->cmd.pathmove);
break;
case JTAG_SCAN:
#ifdef _DEBUG_JTAG_IO_
LOG_DEBUG("%s scan end in %s",
(cmd->cmd.scan->ir_scan) ? "IR" : "DR",
tap_state_name(cmd->cmd.scan->end_state));
#endif
bitbang_end_state(cmd->cmd.scan->end_state);
scan_size = jtag_build_buffer(cmd->cmd.scan, &buffer);
type = jtag_scan_type(cmd->cmd.scan);
bitbang_scan(cmd->cmd.scan->ir_scan, type, buffer, scan_size);
if (jtag_read_buffer(buffer, cmd->cmd.scan) != ERROR_OK)
retval = ERROR_JTAG_QUEUE_FAILED;
if (buffer)
free(buffer);
break;
case JTAG_SLEEP:
#ifdef _DEBUG_JTAG_IO_
LOG_DEBUG("sleep %" PRIi32, cmd->cmd.sleep->us);
#endif
jtag_sleep(cmd->cmd.sleep->us);
break;
case JTAG_TMS:
retval = bitbang_execute_tms(cmd);
break;
default:
LOG_ERROR("BUG: unknown JTAG command type encountered");
exit(-1);
}
cmd = cmd->next;
}
if (bitbang_interface->blink)
bitbang_interface->blink(0);
return retval;
}
有如下jtag驱动是用bitbang来实现的:
./jtag/drivers/at91rm9200.c
./jtag/drivers/ep93xx.c
./jtag/drivers/bitbang.c
./jtag/drivers/dummy.c
./jtag/drivers/bcm2835gpio.c
./jtag/drivers/parport.c
./jtag/drivers/remote_bitbang.c
./jtag/drivers/sysfsgpio.c