diff options
| author | Bdale Garbee <bdale@gag.com> | 2009-08-18 14:03:16 -0600 | 
|---|---|---|
| committer | Bdale Garbee <bdale@gag.com> | 2009-08-18 14:03:16 -0600 | 
| commit | 0fcc426f96577ebbaf0c2d009cd2708e974de315 (patch) | |
| tree | 45db638cca0c9af293b30981f78f8a17e5c7cc03 /ao-tools/lib | |
| parent | 91b85929df6a3464396702fd177a6f74c6f28c7a (diff) | |
| parent | 9789ca5e8caa9a013e804f307b9da380e147bd75 (diff) | |
Merge branch 'master' into debian
Diffstat (limited to 'ao-tools/lib')
| -rw-r--r-- | ao-tools/lib/Makefile.am | 22 | ||||
| -rw-r--r-- | ao-tools/lib/cc-bitbang.c | 237 | ||||
| -rw-r--r-- | ao-tools/lib/cc-bitbang.h | 94 | ||||
| -rw-r--r-- | ao-tools/lib/cc-usb.c | 360 | ||||
| -rw-r--r-- | ao-tools/lib/cc-usb.h | 59 | ||||
| -rw-r--r-- | ao-tools/lib/ccdbg-command.c | 176 | ||||
| -rw-r--r-- | ao-tools/lib/ccdbg-debug.c | 63 | ||||
| -rw-r--r-- | ao-tools/lib/ccdbg-debug.h | 44 | ||||
| -rw-r--r-- | ao-tools/lib/ccdbg-flash.c | 356 | ||||
| -rw-r--r-- | ao-tools/lib/ccdbg-hex.c | 330 | ||||
| -rw-r--r-- | ao-tools/lib/ccdbg-io.c | 137 | ||||
| -rw-r--r-- | ao-tools/lib/ccdbg-manual.c | 77 | ||||
| -rw-r--r-- | ao-tools/lib/ccdbg-memory.c | 179 | ||||
| -rw-r--r-- | ao-tools/lib/ccdbg-rom.c | 63 | ||||
| -rw-r--r-- | ao-tools/lib/ccdbg-state.c | 128 | ||||
| -rw-r--r-- | ao-tools/lib/ccdbg.h | 341 | ||||
| -rw-r--r-- | ao-tools/lib/cp-usb-async.c | 188 | ||||
| -rw-r--r-- | ao-tools/lib/cp-usb-async.h | 38 | 
18 files changed, 2892 insertions, 0 deletions
| diff --git a/ao-tools/lib/Makefile.am b/ao-tools/lib/Makefile.am new file mode 100644 index 00000000..9584e216 --- /dev/null +++ b/ao-tools/lib/Makefile.am @@ -0,0 +1,22 @@ +noinst_LIBRARIES = libao-tools.a + +AM_CFLAGS=$(WARN_CFLAGS) $(LIBUSB_CFLAGS) + +libao_tools_a_SOURCES = \ +	ccdbg-command.c \ +	ccdbg-debug.c \ +	ccdbg-debug.h \ +	ccdbg-flash.c \ +	ccdbg.h \ +	ccdbg-hex.c \ +	ccdbg-io.c \ +	ccdbg-manual.c \ +	ccdbg-memory.c \ +	ccdbg-rom.c \ +	ccdbg-state.c \ +	cc-usb.c \ +	cc-usb.h \ +	cc-bitbang.c \ +	cc-bitbang.h \ +	cp-usb-async.c \ +	cp-usb-async.h diff --git a/ao-tools/lib/cc-bitbang.c b/ao-tools/lib/cc-bitbang.c new file mode 100644 index 00000000..a5d15739 --- /dev/null +++ b/ao-tools/lib/cc-bitbang.c @@ -0,0 +1,237 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include "ccdbg-debug.h" +#include "cc-bitbang.h" + +#include "cp-usb-async.h" + +struct cc_bitbang { +	struct cp_usb_async *cp_async; +}; + +static uint32_t	cc_clock_us = CC_CLOCK_US; +static uint32_t	cc_reset_us = CC_RESET_US; + +void +cc_bitbang_set_clock(uint32_t us) +{ +	cc_clock_us = us; +} + +void +cc_bitbang_half_clock(struct cc_bitbang *bb) +{ +	struct timespec	req, rem; +	req.tv_sec = (cc_clock_us / 2) / 1000000; +	req.tv_nsec = ((cc_clock_us / 2) % 1000000) * 1000; +	nanosleep(&req, &rem); +} + +void +cc_bitbang_wait_reset(struct cc_bitbang *bb) +{ +	struct timespec	req, rem; + +	cc_bitbang_sync(bb); +	req.tv_sec = (cc_reset_us) / 1000000; +	req.tv_nsec = ((cc_reset_us) % 1000000) * 1000; +	nanosleep(&req, &rem); +} + +struct cc_bitbang * +cc_bitbang_open(void) +{ +	struct cc_bitbang *bb; + +	bb = calloc(sizeof (struct cc_bitbang), 1); +	if (!bb) { +		perror("calloc"); +		return NULL; +	} +	bb->cp_async = cp_usb_async_open(); +	if (!bb->cp_async) { +		free (bb); +		return NULL; +	} +	return bb; +} + +void +cc_bitbang_close(struct cc_bitbang *bb) +{ +	cp_usb_async_close(bb->cp_async); +	free (bb); +} + +void +cc_bitbang_debug_mode(struct cc_bitbang *bb) +{ +	/* force two rising clocks while holding RESET_N low */ +	ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); +	ccdbg_debug(CC_DEBUG_COMMAND, "# Debug mode\n"); +	ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N,          CC_DATA           ); +	cc_bitbang_wait_reset(bb); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA           ); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N,          CC_DATA           ); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA           ); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N,          CC_DATA|CC_RESET_N); +	cc_bitbang_wait_reset(bb); +} + +void +cc_bitbang_reset(struct cc_bitbang *bb) +{ +	ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); +	ccdbg_debug(CC_DEBUG_COMMAND, "# Reset\n"); +	ccdbg_debug(CC_DEBUG_COMMAND, "#\n"); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA           ); +	cc_bitbang_wait_reset(bb); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA           ); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA           ); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA           ); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); +	cc_bitbang_wait_reset(bb); +} + +int +cc_bitbang_write(struct cc_bitbang *bb, uint8_t mask, uint8_t value) +{ +	cp_usb_async_write(bb->cp_async, mask, value); +	return 0; +} + +void +cc_bitbang_read(struct cc_bitbang *bb, uint8_t *valuep) +{ +	cp_usb_async_read(bb->cp_async, valuep); +} + +void +cc_bitbang_sync(struct cc_bitbang *bb) +{ +	cp_usb_async_sync(bb->cp_async); +} + +static char +is_bit(uint8_t get, uint8_t mask, char on, uint8_t bit) +{ +	if (mask&bit) { +		if (get&bit) +			return on; +		else +			return '.'; +	} else +		return '-'; +} + +void +cc_bitbang_print(char *format, uint8_t mask, uint8_t set) +{ +	ccdbg_debug (CC_DEBUG_BITBANG, format, +		     is_bit(set, mask, 'C', CC_CLOCK), +		     is_bit(set, mask, 'D', CC_DATA), +		     is_bit(set, mask, 'R', CC_RESET_N)); +} + +void +cc_bitbang_send(struct cc_bitbang *bb, uint8_t mask, uint8_t set) +{ +	cc_bitbang_write(bb, mask, set); +	cc_bitbang_print("%c %c %c\n", mask, set); +	cc_bitbang_half_clock(bb); +} + +void +cc_bitbang_send_bit(struct cc_bitbang *bb, uint8_t bit) +{ +	if (bit) bit = CC_DATA; +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N, CC_CLOCK|bit|CC_RESET_N); +	cc_bitbang_send(bb, CC_CLOCK|CC_DATA|CC_RESET_N,          bit|CC_RESET_N); +} + +void +cc_bitbang_send_byte(struct cc_bitbang *bb, uint8_t byte) +{ +	int bit; +	ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Send Byte 0x%02x\n#\n", byte); +	for (bit = 7; bit >= 0; bit--) { +		cc_bitbang_send_bit(bb, (byte >> bit) & 1); +		if (bit == 3) +			ccdbg_debug(CC_DEBUG_BITBANG, "\n"); +	} +	cc_bitbang_sync(bb); +} + +void +cc_bitbang_send_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes) +{ +	while (nbytes--) +		cc_bitbang_send_byte(bb, *bytes++); +} + +void +cc_bitbang_recv_bit(struct cc_bitbang *bb, int first, uint8_t *bit) +{ +	uint8_t mask = first ? CC_DATA : 0; + +	cc_bitbang_send(bb, CC_CLOCK|mask|CC_RESET_N, CC_CLOCK|CC_DATA|CC_RESET_N); +	cc_bitbang_read(bb, bit); +	cc_bitbang_send(bb, CC_CLOCK|     CC_RESET_N,                  CC_RESET_N); +} + +void +cc_bitbang_recv_byte(struct cc_bitbang *bb, int first, uint8_t *bytep) +{ +	uint8_t byte = 0; +	uint8_t bits[8]; +	int	bit; + +	ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv byte\n#\n"); +	for (bit = 0; bit < 8; bit++) { +		cc_bitbang_recv_bit(bb, first, &bits[bit]); +		first = 0; +	} +	cc_bitbang_sync(bb); +	for (bit = 0; bit < 8; bit++) { +		byte = byte << 1; +		byte |= (bits[bit] & CC_DATA) ? 1 : 0; +		cc_bitbang_print("#\t%c %c %c\n", CC_DATA, bits[bit]); +		if (bit == 3) +			ccdbg_debug(CC_DEBUG_BITBANG, "\n"); +	} +	ccdbg_debug(CC_DEBUG_BITBANG, "#\n# Recv 0x%02x\n#\n", byte); +	*bytep = byte; +} + +void +cc_bitbang_recv_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes) +{ +	int i; +	int first = 1; +	for (i = 0; i < nbytes; i++) { +		cc_bitbang_recv_byte(bb, first, &bytes[i]); +		first = 0; +	} +} diff --git a/ao-tools/lib/cc-bitbang.h b/ao-tools/lib/cc-bitbang.h new file mode 100644 index 00000000..54b20e2c --- /dev/null +++ b/ao-tools/lib/cc-bitbang.h @@ -0,0 +1,94 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * 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 _CC_BITBANG_H_ +#define _CC_BITBANG_H_ + +#include <stdint.h> + +#define CC_CLOCK	0x1 +#define CC_DATA		0x2 +#define CC_RESET_N	0x4 +#define CC_CLOCK_US	(2) + +/* Telemetrum has a 10k pull-up to 3.3v, a 0.001uF cap to ground + * and a 2.7k resistor to the reset line. This takes about 6us + * to settle, so we'll wait longer than that after changing the reset line + */ +#define CC_RESET_US	(12) + +struct cc_bitbang; + +void +cc_bitbang_set_clock(uint32_t us); + +void +cc_bitbang_half_clock(struct cc_bitbang *bb); + +void +cc_bitbang_wait_reset(struct cc_bitbang *bb); + +struct cc_bitbang * +cc_bitbang_open(void); + +void +cc_bitbang_close(struct cc_bitbang *bb); + +void +cc_bitbang_debug_mode(struct cc_bitbang *bb); + +void +cc_bitbang_reset(struct cc_bitbang *bb); + +int +cc_bitbang_write(struct cc_bitbang *bb, uint8_t mask, uint8_t value); + +void +cc_bitbang_read(struct cc_bitbang *bb, uint8_t *valuep); + +void +cc_bitbang_sync(struct cc_bitbang *bb); + +void +cc_bitbang_print(char *format, uint8_t mask, uint8_t set); + +void +cc_bitbang_print(char *format, uint8_t mask, uint8_t set); + +void +cc_bitbang_send(struct cc_bitbang *bb, uint8_t mask, uint8_t set); + +void +cc_bitbang_send_bit(struct cc_bitbang *bb, uint8_t bit); + +void +cc_bitbang_send_byte(struct cc_bitbang *bb, uint8_t byte); + +void +cc_bitbang_send_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes); + +void +cc_bitbang_recv_bit(struct cc_bitbang *bb, int first, uint8_t *bit); + +void +cc_bitbang_recv_byte(struct cc_bitbang *bb, int first, uint8_t *bytep); + +void +cc_bitbang_recv_bytes(struct cc_bitbang *bb, uint8_t *bytes, int nbytes); + +#endif /* _CC_BITBANG_H_ */ diff --git a/ao-tools/lib/cc-usb.c b/ao-tools/lib/cc-usb.c new file mode 100644 index 00000000..81309983 --- /dev/null +++ b/ao-tools/lib/cc-usb.c @@ -0,0 +1,360 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <stdarg.h> +#include <poll.h> +#include <stdlib.h> +#include <stdio.h> +#include <unistd.h> +#include <string.h> +#include <termios.h> +#include "ccdbg-debug.h" +#include "cc-usb.h" + + +#define CC_NUM_READ		16 +/* + * AltOS has different buffer sizes for in/out packets + */ +#define CC_IN_BUF		256 +#define CC_OUT_BUF		64 +#define DEFAULT_TTY		"/dev/ttyACM0" + +struct cc_read { +	uint8_t	*buf; +	int	len; +}; + +struct cc_usb { +	int		fd; +	uint8_t		in_buf[CC_IN_BUF]; +	int		in_count; +	uint8_t		out_buf[CC_OUT_BUF]; +	int		out_count; +	struct cc_read	read_buf[CC_NUM_READ]; +	int		read_count; +}; + +#define NOT_HEX	0xff + +static uint8_t +cc_hex_nibble(uint8_t c) +{ +	if ('0' <= c && c <= '9') +		return c - '0'; +	if ('a' <= c && c <= 'f') +		return c - 'a' + 10; +	if ('A' <= c && c <= 'F') +		return c - 'A' + 10; +	return NOT_HEX; +} + +/* + * Take raw input bytes, parse them as hex + * and write them to the waiting buffer + */ +static void +cc_handle_in(struct cc_usb *cc) +{ +	uint8_t	h, l; +	int	in_pos; +	int	read_pos; + +	in_pos = 0; +	read_pos = 0; +	while (read_pos < cc->read_count && in_pos < cc->in_count) { +		/* +		 * Skip to next hex character +		 */ +		while (in_pos < cc->in_count && +		       cc_hex_nibble(cc->in_buf[in_pos]) == NOT_HEX) +			in_pos++; +		/* +		 * Make sure we have two characters left +		 */ +		if (cc->in_count - in_pos < 2) +			break; +		/* +		 * Parse hex number +		 */ +		h = cc_hex_nibble(cc->in_buf[in_pos]); +		l = cc_hex_nibble(cc->in_buf[in_pos+1]); +		if (h == NOT_HEX || l == NOT_HEX) { +			fprintf(stderr, "hex read error\n"); +			break; +		} +		in_pos += 2; +		/* +		 * Store hex number +		 */ +		*cc->read_buf[read_pos].buf++ = (h << 4) | l; +		if (--cc->read_buf[read_pos].len <= 0) +			read_pos++; +	} + +	/* Move remaining bytes to the start of the input buffer */ +	if (in_pos) { +		memmove(cc->in_buf, cc->in_buf + in_pos, +			cc->in_count - in_pos); +		cc->in_count -= in_pos; +	} + +	/* Move pending reads to the start of the array */ +	if (read_pos) { +		memmove(cc->read_buf, cc->read_buf + read_pos, +			(cc->read_count - read_pos) * sizeof (cc->read_buf[0])); +		cc->read_count -= read_pos; +	} + +	/* Once we're done reading, flush any pending input */ +	if (cc->read_count == 0) +		cc->in_count = 0; +} + +static void +cc_usb_dbg(int indent, uint8_t *bytes, int len) +{ +	int	eol = 1; +	int	i; +	uint8_t	c; +	while (len--) { +		c = *bytes++; +		if (eol) { +			for (i = 0; i < indent; i++) +				ccdbg_debug(CC_DEBUG_BITBANG, " "); +			eol = 0; +		} +		switch (c) { +		case '\r': +			ccdbg_debug(CC_DEBUG_BITBANG, "^M"); +			break; +		case '\n': +			eol = 1; +		default: +			ccdbg_debug(CC_DEBUG_BITBANG, "%c", c); +		} +	} +} + +/* + * Flush pending writes, fill pending reads + */ +void +cc_usb_sync(struct cc_usb *cc) +{ +	int		ret; +	struct pollfd	fds; +	int		timeout; + +	fds.fd = cc->fd; +	for (;;) { +		if (cc->read_count || cc->out_count) +			timeout = -1; +		else +			timeout = 0; +		fds.events = 0; +		if (cc->in_count < CC_IN_BUF) +			fds.events |= POLLIN; +		if (cc->out_count) +			fds.events |= POLLOUT; +		ret = poll(&fds, 1, timeout); +		if (ret == 0) +			break; +		if (ret < 0) { +			perror("poll"); +			break; +		} +		if (fds.revents & POLLIN) { +			ret = read(cc->fd, cc->in_buf + cc->in_count, +				   CC_IN_BUF - cc->in_count); +			if (ret > 0) { +				cc_usb_dbg(24, cc->in_buf + cc->in_count, ret); +				cc->in_count += ret; +				cc_handle_in(cc); +			} else if (ret < 0) +				perror("read"); +		} +		if (fds.revents & POLLOUT) { +			ret = write(cc->fd, cc->out_buf, +				    cc->out_count); +			if (ret > 0) { +				cc_usb_dbg(0, cc->out_buf, ret); +				memmove(cc->out_buf, +					cc->out_buf + ret, +					cc->out_count - ret); +				cc->out_count -= ret; +			} else if (ret < 0) +				perror("write"); +		} +	} +} + +void +cc_usb_printf(struct cc_usb *cc, char *format, ...) +{ +	char	buf[1024], *b; +	va_list	ap; +	int	ret, this_time; + +	/* sprintf to a local buffer */ +	va_start(ap, format); +	ret = vsnprintf(buf, sizeof(buf), format, ap); +	va_end(ap); +	if (ret > sizeof(buf)) { +		fprintf(stderr, "printf overflow for format %s\n", +			format); +	} + +	/* flush local buffer to the wire */ +	b = buf; +	while (ret > 0) { +		this_time = ret; +		if (this_time > CC_OUT_BUF - cc->out_count) +			this_time = CC_OUT_BUF - cc->out_count; +		memcpy(cc->out_buf + cc->out_count, b, this_time); +		cc->out_count += this_time; +		ret -= this_time; +		b += this_time; +		while (cc->out_count >= CC_OUT_BUF) +			cc_usb_sync(cc); +	} +} + +int +cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len) +{ +	int	this_len; +	int	ret = len; + +	while (len) { +		this_len = len; +		if (this_len > 8) +			this_len = 8; +		len -= this_len; +		cc_usb_printf(cc, "P"); +		while (this_len--) +			cc_usb_printf (cc, " %02x", (*bytes++) & 0xff); +		cc_usb_printf(cc, "\n"); +	} +	return ret; +} + +void +cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len) +{ +	struct cc_read	*read_buf; +	while (cc->read_count >= CC_NUM_READ) +		cc_usb_sync(cc); +	read_buf = &cc->read_buf[cc->read_count++]; +	read_buf->buf = buf; +	read_buf->len = len; +} + +int +cc_usb_recv_bytes(struct cc_usb *cc, uint8_t *buf, int len) +{ +	cc_queue_read(cc, buf, len); +	cc_usb_printf(cc, "G %x\n", len); +	return len; +} + +int +cc_usb_write_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len) +{ +	cc_usb_printf(cc, "O %x %x\n", len, addr); +	while (len--) +		cc_usb_printf(cc, "%02x", *bytes++); +	cc_usb_sync(cc); +	return 0; +} + +int +cc_usb_read_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len) +{ +	int	i; +	cc_queue_read(cc, bytes, len); +	cc_usb_printf(cc, "I %x %x\n", len, addr); +	cc_usb_sync(cc); +	for (i = 0; i < len; i++) { +		if ((i & 15) == 0) { +			if (i) +				ccdbg_debug(CC_DEBUG_MEMORY, "\n"); +			ccdbg_debug(CC_DEBUG_MEMORY, "\t%04x", addr + i); +		} +		ccdbg_debug(CC_DEBUG_MEMORY, " %02x", bytes[i]); +	} +	ccdbg_debug(CC_DEBUG_MEMORY, "\n"); +	return 0; +} + +int +cc_usb_debug_mode(struct cc_usb *cc) +{ +	cc_usb_sync(cc); +	cc_usb_printf(cc, "D\n"); +	return 1; +} + +int +cc_usb_reset(struct cc_usb *cc) +{ +	cc_usb_sync(cc); +	cc_usb_printf(cc, "R\n"); +	return 1; +} + +static struct termios	save_termios; + +struct cc_usb * +cc_usb_open(char *tty) +{ +	struct cc_usb	*cc; +	struct termios	termios; + +	if (!tty) +		tty = DEFAULT_TTY; +	cc = calloc (sizeof (struct cc_usb), 1); +	if (!cc) +		return NULL; +	cc->fd = open(tty, O_RDWR | O_NONBLOCK); +	if (cc->fd < 0) { +		perror(tty); +		free (cc); +		return NULL; +	} +	tcgetattr(cc->fd, &termios); +	save_termios = termios; +	cfmakeraw(&termios); +	tcsetattr(cc->fd, TCSAFLUSH, &termios); +	cc_usb_printf(cc, "E 0\nm 0\n"); +	cc_usb_sync(cc); +	sleep(1); +	cc_usb_sync(cc); +	return cc; +} + +void +cc_usb_close(struct cc_usb *cc) +{ +	tcsetattr(cc->fd, TCSAFLUSH, &save_termios); +	close (cc->fd); +	free (cc); +} diff --git a/ao-tools/lib/cc-usb.h b/ao-tools/lib/cc-usb.h new file mode 100644 index 00000000..d7acfbd2 --- /dev/null +++ b/ao-tools/lib/cc-usb.h @@ -0,0 +1,59 @@ +/* + * Copyright © 2009 Keith Packard <keithp@keithp.com> + * + * 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 _CC_USB_H_ +#define _CC_USB_H_ + +#include <stdint.h> + +struct cc_usb; + +struct cc_usb * +cc_usb_open(char *tty); + +void +cc_usb_close(struct cc_usb *cc); + +int +cc_usb_send_bytes(struct cc_usb *cc, uint8_t *bytes, int len); + +int +cc_usb_recv_bytes(struct cc_usb *cc, uint8_t *bytes, int len); + +int +cc_usb_write_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len); + +int +cc_usb_read_memory(struct cc_usb *cc, uint16_t addr, uint8_t *bytes, int len); + +int +cc_usb_debug_mode(struct cc_usb *cc); + +int +cc_usb_reset(struct cc_usb *cc); + +void +cc_usb_sync(struct cc_usb *cc); + +void +cc_queue_read(struct cc_usb *cc, uint8_t *buf, int len); + +void +cc_usb_printf(struct cc_usb *cc, char *format, ...); + +#endif /* _CC_USB_H_ */ diff --git a/ao-tools/lib/ccdbg-command.c b/ao-tools/lib/ccdbg-command.c new file mode 100644 index 00000000..a1002879 --- /dev/null +++ b/ao-tools/lib/ccdbg-command.c @@ -0,0 +1,176 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include "ccdbg.h" + +uint8_t +ccdbg_chip_erase(struct ccdbg *dbg) +{ +	return ccdbg_cmd_write_read8(dbg, CC_CHIP_ERASE, NULL, 0); +} + +uint8_t +ccdbg_wr_config(struct ccdbg *dbg, uint8_t config) +{ +	return ccdbg_cmd_write_read8(dbg, CC_WR_CONFIG, &config, 1); +} + +uint8_t +ccdbg_rd_config(struct ccdbg *dbg) +{ +	return ccdbg_cmd_write_read8(dbg, CC_RD_CONFIG, NULL, 0); +} + +uint16_t +ccdbg_get_pc(struct ccdbg *dbg) +{ +	uint16_t	pc1, pc2; + +	pc1 = ccdbg_cmd_write_read16(dbg, CC_GET_PC, NULL, 0); +	pc2 = ccdbg_cmd_write_read16(dbg, CC_GET_PC, NULL, 0); +	if (pc1 != pc2) +		fprintf (stderr, "Invalid pc %04x != %04x\n", +			 pc1, pc2); +	return pc2; +} + +uint8_t +ccdbg_read_status(struct ccdbg *dbg) +{ +	return ccdbg_cmd_write_read8(dbg, CC_READ_STATUS, NULL, 0); +} + +uint8_t +ccdbg_set_hw_brkpnt(struct ccdbg *dbg, uint8_t number, uint8_t enable, uint16_t addr) +{ +	uint8_t	data[3]; + +	data[0] = (number << 3) | (enable << 2); +	data[1] = (addr >> 8); +	data[2] = addr; +	return ccdbg_cmd_write_read8(dbg, CC_SET_HW_BRKPNT, data, 3); +} + +uint8_t +ccdbg_halt(struct ccdbg *dbg) +{ +	return ccdbg_cmd_write_read8(dbg, CC_HALT, NULL, 0); +} + +uint8_t +ccdbg_resume(struct ccdbg *dbg) +{ +	return ccdbg_cmd_write_read8(dbg, CC_RESUME, NULL, 0); +} + +uint8_t +ccdbg_debug_instr(struct ccdbg *dbg, uint8_t *instr, int nbytes) +{ +	return ccdbg_cmd_write_read8(dbg, CC_DEBUG_INSTR(nbytes), instr, nbytes); +} + +void +ccdbg_debug_instr_discard(struct ccdbg *dbg, uint8_t *instr, int nbytes) +{ +	static uint8_t	discard; +	ccdbg_cmd_write_queue8(dbg, CC_DEBUG_INSTR(nbytes), +			       instr, nbytes, &discard); +} + +void +ccdbg_debug_instr_queue(struct ccdbg *dbg, uint8_t *instr, int nbytes, +			uint8_t *reply) +{ +	return ccdbg_cmd_write_queue8(dbg, CC_DEBUG_INSTR(nbytes), +				      instr, nbytes, reply); +} + +uint8_t +ccdbg_step_instr(struct ccdbg *dbg) +{ +	return ccdbg_cmd_write_read8(dbg, CC_STEP_INSTR, NULL, 0); +} + +uint8_t +ccdbg_step_replace(struct ccdbg *dbg, uint8_t *instr, int nbytes) +{ +	return ccdbg_cmd_write_read8(dbg, CC_STEP_REPLACE(nbytes), instr, nbytes); +} + +uint16_t +ccdbg_get_chip_id(struct ccdbg *dbg) +{ +	return ccdbg_cmd_write_read16(dbg, CC_GET_CHIP_ID, NULL, 0); +} + +/* + * Execute a sequence of instructions + */ +uint8_t +ccdbg_execute(struct ccdbg *dbg, uint8_t *inst) +{ +	uint8_t status = 0; +	while(inst[0] != 0) { +		uint8_t	len = inst[0]; +		int i; +		ccdbg_debug(CC_DEBUG_INSTRUCTIONS, "\t%02x", inst[1]); +		for (i = 0; i < len - 1; i++) +			ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " %02x", inst[i+2]); +		ccdbg_debug_instr_queue(dbg, inst+1, len, &status); +		for (; i < 3; i++) +			ccdbg_debug(CC_DEBUG_INSTRUCTIONS, "   "); +		ccdbg_debug(CC_DEBUG_INSTRUCTIONS, " -> %02x\n", status); +		inst += len + 1; +	} +	ccdbg_sync(dbg); +	return status; +} + +static uint8_t jump_mem[] = { +	3, LJMP, 0xf0, 0x00, +#define PC_HIGH	2 +#define PC_LOW	3 +	0 +}; + +uint8_t +ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc) +{ +	jump_mem[PC_HIGH] = pc >> 8; +	jump_mem[PC_LOW] = pc & 0xff; +	return ccdbg_execute(dbg, jump_mem); +} + +uint8_t +ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image) +{ +	uint16_t pc; +	uint8_t status; + +	if (image->address < 0xf000) { +		fprintf(stderr, "Cannot execute program starting at 0x%04x\n", image->address); +		return -1; +	} +	ccdbg_write_hex_image(dbg, image, 0); +	ccdbg_set_pc(dbg, image->address); +	pc = ccdbg_get_pc(dbg); +	ccdbg_debug(CC_DEBUG_EXECUTE, "pc starts at 0x%04x\n", pc); +	status = ccdbg_resume(dbg); +	ccdbg_debug(CC_DEBUG_EXECUTE, "resume status: 0x%02x\n", status); +	return 0; +} diff --git a/ao-tools/lib/ccdbg-debug.c b/ao-tools/lib/ccdbg-debug.c new file mode 100644 index 00000000..6eb4e0c5 --- /dev/null +++ b/ao-tools/lib/ccdbg-debug.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include "ccdbg.h" +#include <stdarg.h> + +int +ccdbg_level = 0; + +void +ccdbg_add_debug(int level) +{ +	ccdbg_level |= level; +} + +void +ccdbg_clear_debug(int level) +{ +	ccdbg_level &= ~level; +} + +static int initialized; + +void +ccdbg_debug(int level, char *format, ...) +{ +	va_list	ap; + +	if (!initialized) { +		char *level; +		initialized = 1; +		level = getenv("CCDEBUG"); +		if (level) +			ccdbg_level |= strtoul(level, NULL, 0); +	} +	if (ccdbg_level & level) { +		va_start(ap, format); +		vprintf(format, ap); +		va_end(ap); +	} +} + +void +ccdbg_flush(int level) +{ +	if (ccdbg_level & level) +		fflush(stdout); +} diff --git a/ao-tools/lib/ccdbg-debug.h b/ao-tools/lib/ccdbg-debug.h new file mode 100644 index 00000000..0b5b44c1 --- /dev/null +++ b/ao-tools/lib/ccdbg-debug.h @@ -0,0 +1,44 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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 _CCDBG_DEBUG_H_ +#define _CCDBG_DEBUG_H_ +/* Debug levels + */ +#define CC_DEBUG_BITBANG	0x00000001 +#define CC_DEBUG_COMMAND	0x00000002 +#define CC_DEBUG_INSTRUCTIONS	0x00000004 +#define CC_DEBUG_EXECUTE	0x00000008 +#define CC_DEBUG_FLASH		0x00000010 +#define CC_DEBUG_MEMORY		0x00000020 +#define CC_DEBUG_USB_ASYNC	0x00000040 + +/* ccdbg-debug.c */ +void +ccdbg_debug(int level, char *format, ...); + +void +ccdbg_add_debug(int level); + +void +ccdbg_clear_debug(int level); + +void +ccdbg_flush(int level); + +#endif /* _CCDBG_DEBUG_H_ */ diff --git a/ao-tools/lib/ccdbg-flash.c b/ao-tools/lib/ccdbg-flash.c new file mode 100644 index 00000000..3e672985 --- /dev/null +++ b/ao-tools/lib/ccdbg-flash.c @@ -0,0 +1,356 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include "ccdbg.h" + +/* From SWRA124 section 3.1.6 */ + +static uint8_t flash_page[] = { + +	MOV_direct_data, P1DIR, 0x02, +	MOV_direct_data, P1,	0xFF, + +	MOV_direct_data, FADDRH, 0, +#define FLASH_ADDR_HIGH	8 + +	MOV_direct_data, FADDRL, 0, +#define FLASH_ADDR_LOW	11 + +	MOV_DPTR_data16, 0, 0, +#define RAM_ADDR_HIGH	13 +#define RAM_ADDR_LOW	14 + +	MOV_Rn_data(7), 0, +#define FLASH_WORDS_HIGH	16 + +	MOV_Rn_data(6), 0, +#define FLASH_WORDS_LOW		18 + +	MOV_direct_data, FWT, 0x20, +#define FLASH_TIMING		21 + +	MOV_direct_data, FCTL, FCTL_ERASE, +/* eraseWaitLoop: */ +		MOV_A_direct,		FCTL, +	JB, ACC(FCTL_BUSY_BIT), 0xfb, + +	MOV_direct_data, P1, 0xfd, + +	MOV_direct_data, FCTL, FCTL_WRITE, +/* writeLoop: */ +		MOV_Rn_data(5), 2, +/* writeWordLoop: */ +			MOVX_A_atDPTR, +			INC_DPTR, +			MOV_direct_A, FWDATA, +		DJNZ_Rn_rel(5), 0xfa,		/* writeWordLoop */ +/* writeWaitLoop: */ +			MOV_A_direct, FCTL, +		JB, ACC(FCTL_SWBSY_BIT), 0xfb,		/* writeWaitLoop */ +	DJNZ_Rn_rel(6), 0xf1,			/* writeLoop */ +	DJNZ_Rn_rel(7), 0xef,			/* writeLoop */ + +	MOV_direct_data, P1DIR, 0x00, +	MOV_direct_data, P1,	0xFF, +	TRAP, +}; + +#define FLASH_RAM	0xf000 + +#if 0 +static uint8_t	flash_erase_page[] = { +	3,	MOV_direct_data, FADDRH, 0, +#define ERASE_PAGE_HIGH	3 + +	3,	MOV_direct_data, FADDRL, 0, +#define ERASE_PAGE_LOW	7 + +	3,	MOV_direct_data, FWT, 0x2A, +	3,	MOV_direct_data, FCTL, FCTL_ERASE, +	0 +}; + +static uint8_t	flash_read_control[] = { +	2,	MOV_A_direct,	FCTL, +	0 +}; +#endif + +#if 0 +static uint8_t	flash_control_clear[] = { +	3,	MOV_direct_data,	FCTL, 0, +	2,	MOV_A_direct,		FCTL, +	0 +}; +#endif + +#if 0 +static uint8_t +ccdbg_flash_erase_page(struct ccdbg *dbg, uint16_t addr) +{ +	uint16_t	page_addr = addr >> 1; +	uint8_t		status; +	uint8_t		old[0x10], new[0x10]; +	int		i; + +	ccdbg_read_memory(dbg, addr, old, 0x10); +	flash_erase_page[ERASE_PAGE_HIGH] = page_addr >> 8; +	flash_erase_page[ERASE_PAGE_LOW] = page_addr & 0xff; +	status = ccdbg_execute(dbg, flash_erase_page); +	ccdbg_debug(CC_DEBUG_FLASH, "erase status 0x%02x\n", status); +	do { +		status = ccdbg_execute(dbg, flash_read_control); +		ccdbg_debug(CC_DEBUG_FLASH, "fctl 0x%02x\n", status); +	} while (status & FCTL_BUSY); +	ccdbg_read_memory(dbg, addr, new, 0x10); +	for (i = 0; i < 0x10; i++) +		ccdbg_debug(CC_DEBUG_FLASH, "0x%02x -> 0x%02x\n", old[i], new[i]); +	status = ccdbg_execute(dbg, flash_control_clear); +	ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status); +	return 0; +} +#endif + +#if 0 +static uint8_t flash_write[] = { +	MOV_direct_data, P1DIR, 0x02, +	MOV_direct_data, P1,	0xFD, + +	MOV_A_direct, FCTL, +	JB,	ACC(FCTL_BUSY_BIT), 0xf1, + +	MOV_direct_data, FCTL, 0x20, + +	MOV_direct_data, FADDRH, 0, +#define WRITE_PAGE_HIGH	16 + +	MOV_direct_data, FADDRL, 0, +#define WRITE_PAGE_LOW	19 + +	MOV_direct_data, FCTL, FCTL_WRITE, +	MOV_direct_data, FWDATA, 0, +#define WRITE_BYTE_0	25 +	MOV_direct_data, FWDATA, 0, +#define WRITE_BYTE_1	28 +	MOV_A_direct, FCTL, +	JB,	ACC(FCTL_SWBSY_BIT), 0xf1, + +	MOV_direct_data, P1,	0xFF, +	TRAP, +}; +#endif + +static uint8_t +ccdbg_clock_init(struct ccdbg *dbg) +{ +	static uint8_t set_clkcon_fast[] = { +		3,	MOV_direct_data,	CLKCON, 0x00, +		0 +	}; + +	static uint8_t get_sleep[] = { +		2,	MOV_A_direct, SLEEP, +		0 +	}; + +	uint8_t status; + +	ccdbg_execute(dbg, set_clkcon_fast); +	do { +		status = ccdbg_execute(dbg, get_sleep); +	} while (!(status & 0x40)); +	return 0; +} + +#if 0 +static uint8_t +ccdbg_flash_write_word(struct ccdbg *dbg, uint16_t addr, uint8_t data[2]) +{ +	uint16_t page_addr = addr >> 1; +	uint8_t check[2]; +	uint8_t status; +	int i; + +	flash_write[WRITE_PAGE_HIGH] = page_addr >> 8; +	flash_write[WRITE_PAGE_LOW] = page_addr & 0xff; +	flash_write[WRITE_BYTE_0] = data[0]; +	flash_write[WRITE_BYTE_1] = data[1]; +	ccdbg_debug(CC_DEBUG_FLASH, "upload flash write\n"); +	ccdbg_write_memory(dbg, 0xf000, flash_write, sizeof(flash_write)); +	ccdbg_set_pc(dbg, 0xf000); +	ccdbg_resume(dbg); +	for (;;) { +		status = ccdbg_read_status(dbg); +		ccdbg_debug(CC_DEBUG_FLASH, "waiting for write 0x%02x\n", status); +		if ((status & CC_STATUS_CPU_HALTED) != 0) +			break; +		sleep (1); +	} +	status = ccdbg_execute(dbg, flash_control_clear); +	ccdbg_debug(CC_DEBUG_FLASH, "clear fctl 0x%02x\n", status); +	ccdbg_read_memory(dbg, addr, check, 2); +	for (i = 0; i < 2; i++) +		ccdbg_debug(CC_DEBUG_FLASH, "0x%02x : 0x%02x\n", data[i], check[i]); +	return 0; +} +#endif + +#define TIMERS_OFF		0x08 +#define DMA_PAUSE		0x04 +#define TIMER_SUSPEND		0x02 +#define SEL_FLASH_INFO_PAGE	0x01 + +#if 0 +static uint8_t +ccdbg_flash_lock(struct ccdbg *dbg, uint8_t lock) +{ +	uint8_t	config; +	uint8_t bytes[2]; +	uint8_t	old[1], new[1]; + +	config = ccdbg_rd_config(dbg); +	ccdbg_wr_config(dbg, config|SEL_FLASH_INFO_PAGE); +	bytes[0] = lock; +	bytes[1] = 0; +	ccdbg_flash_erase_page(dbg, 0); +	ccdbg_read_memory(dbg, 0, old, 1); +	ccdbg_flash_write_word(dbg, 0, bytes); +	ccdbg_read_memory(dbg, 0, new, 1); +	ccdbg_debug(CC_DEBUG_FLASH, "flash lock 0x%02x -> 0x%02x\n", old[0], new[0]); +	ccdbg_wr_config(dbg, config & ~SEL_FLASH_INFO_PAGE); +	return 0; +} +#endif + +uint8_t +ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image) +{ +	uint16_t offset; +	uint16_t flash_prog; +	uint16_t flash_len; +	uint8_t	fwt; +	uint16_t flash_addr; +	uint16_t flash_word_addr; +	uint16_t flash_words; +	uint8_t flash_words_high, flash_words_low; +	uint16_t ram_addr; +	uint16_t pc; +	uint8_t status; +	uint16_t remain, this_time, start; +	uint8_t verify[0x400]; +	int times; + +	ccdbg_clock_init(dbg); +	if (image->address + image->length > 0x8000) { +		fprintf(stderr, "cannot flash image from 0x%04x to 0x%04x\n", +			image->address, image->address + image->length); +		return 1; +	} +	if (image->address & 0x3ff) { +		fprintf(stderr, "flash image must start on page boundary\n"); +		return 1; +	} +	ram_addr = 0xf000; + + +	flash_prog = 0xf400; + +	fwt = 0x20; + +	flash_page[FLASH_TIMING] = fwt; +	ccdbg_debug(CC_DEBUG_FLASH, "Upload %d flash program bytes to 0x%04x\n", +	       sizeof (flash_page), flash_prog); +	ccdbg_write_memory(dbg, flash_prog, flash_page, sizeof(flash_page)); + +	remain = image->length; +	start = 0; +	while (remain) { +		this_time = remain; +		if (this_time > 0x400) +			this_time = 0x400; + +		offset = ram_addr - (image->address + start); + +		ccdbg_debug(CC_DEBUG_FLASH, "Upload %d bytes at 0x%04x\n", this_time, ram_addr); +		ccdbg_write_memory(dbg, ram_addr, image->data + start, this_time); +#if 0 +		ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes in ram\n", this_time); +		ccdbg_read_memory(dbg, ram_addr, verify, this_time); +		if (memcmp (image->data + start, verify, this_time) != 0) { +			fprintf(stderr, "ram verify failed\n"); +			return 1; +		} +#endif + +		flash_addr = image->address + start; +		flash_word_addr = flash_addr >> 1; +		flash_len = this_time + (this_time & 1); +		flash_words = flash_len >> 1; + +		flash_words_low = flash_words & 0xff; +		flash_words_high = flash_words >> 8; + +		/* The flash code above is lame */ +		if (flash_words_low) +			flash_words_high++; + +		ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_HIGH, flash_word_addr >> 8); +		ccdbg_write_uint8(dbg, flash_prog + FLASH_ADDR_LOW, flash_word_addr & 0xff); + +		ccdbg_write_uint8(dbg, flash_prog + RAM_ADDR_HIGH, ram_addr >> 8); +		ccdbg_write_uint8(dbg, flash_prog + RAM_ADDR_LOW, ram_addr & 0xff); + +		ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_HIGH, flash_words_high); +		ccdbg_write_uint8(dbg, flash_prog + FLASH_WORDS_LOW, flash_words_low); + +		ccdbg_set_pc(dbg, flash_prog); +		pc = ccdbg_get_pc(dbg); +		ccdbg_debug(CC_DEBUG_FLASH, "Flashing %d bytes at 0x%04x\n", +			    this_time, flash_addr); +		status = ccdbg_resume(dbg); +		for (times = 0; times < 10; times++) { +			status = ccdbg_read_status(dbg); +			ccdbg_debug(CC_DEBUG_FLASH, "."); +			ccdbg_flush(CC_DEBUG_FLASH); +			if ((status & CC_STATUS_CPU_HALTED) != 0) +				break; +			usleep(10000); +		} +		ccdbg_debug(CC_DEBUG_FLASH, "\n"); +		if (times == 10) { +			fprintf(stderr, "flash page timed out\n"); +			return 1; +		} + +		ccdbg_debug(CC_DEBUG_FLASH, "Verify %d bytes in flash\n", this_time); +		ccdbg_read_memory(dbg, flash_addr, verify, this_time); +		if (memcmp (image->data + start, verify, this_time) != 0) { +			int i; +			fprintf(stderr, "flash verify failed\n"); +			for (i = 0; i < this_time; i++) { +				if (image->data[start + i] != verify[i]) +					fprintf(stderr, "0x%04x: 0x%02x != 0x%02x\n", +						start + i, image->data[start+i], verify[i]); +			} +			return 1; +		} +		remain -= this_time; +		start += this_time; +	} +	return 0; +} diff --git a/ao-tools/lib/ccdbg-hex.c b/ao-tools/lib/ccdbg-hex.c new file mode 100644 index 00000000..dfea9156 --- /dev/null +++ b/ao-tools/lib/ccdbg-hex.c @@ -0,0 +1,330 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include "ccdbg.h" +#include <stdarg.h> +#include <ctype.h> + +struct hex_input { +	FILE	*file; +	int	line; +	char	*name; +}; + +enum hex_read_state { +	read_marker, +	read_length, +	read_address, +	read_type, +	read_data, +	read_checksum, +	read_newline, +	read_white, +	read_done, +}; + + +static void +ccdbg_hex_error(struct hex_input *input, char *format, ...) +{ +	va_list ap; + +	va_start(ap, format); +	fprintf(stderr, "Hex error %s:%d: ", input->name, input->line); +	vfprintf(stderr, format, ap); +	fprintf(stderr, "\n"); +	va_end(ap); +} + +static void +ccdbg_hex_free(struct hex_record *record) +{ +	if (!record) return; +	free(record); +} + +static struct hex_record * +ccdbg_hex_alloc(uint8_t length) +{ +	struct hex_record *record; + +	record = calloc(1, sizeof(struct hex_record) + length); +	record->length = length; +	return record; +} + +static int +ishex(char c) +{ +	return isdigit(c) || ('a' <= c && c <= 'f') || ('A' <= c && c <= 'F'); +} + +static int +fromhex(char c) +{ +	if (isdigit(c)) +		return c - '0'; +	if ('a' <= c && c <= 'f') +		return c - 'a' + 10; +	if ('A' <= c && c <= 'F') +		return c - 'A' + 10; +	abort(); +	return 0; +} + +static uint8_t +ccdbg_hex_checksum(struct hex_record *record) +{ +	uint8_t	checksum = 0; +	int i; + +	checksum += record->length; +	checksum += record->address >> 8; +	checksum += record->address & 0xff; +	checksum += record->type; +	for (i = 0; i < record->length; i++) +		checksum += record->data[i]; +	return -checksum; +} + +static struct hex_record * +ccdbg_hex_read_record(struct hex_input *input) +{ +	struct hex_record *record = NULL; +	enum hex_read_state state = read_marker; +	char c; +	int nhexbytes; +	uint32_t hex; +	uint32_t ndata; +	uint8_t checksum; + +	while (state != read_done) { +		c = getc(input->file); +		if (c == EOF && state != read_white) { +			ccdbg_hex_error(input, "Unexpected EOF"); +			goto bail; +		} +		if (c == ' ') +			continue; +		if (c == '\n') +			input->line++; +		switch (state) { +		case read_marker: +			if (c != ':') { +				ccdbg_hex_error(input, "Missing ':'"); +				goto bail; +			} +			state = read_length; +			nhexbytes = 2; +			hex = 0; +			break; +		case read_length: +		case read_address: +		case read_type: +		case read_data: +		case read_checksum: +			if (!ishex(c)) { +				ccdbg_hex_error(input, "Non-hex char '%c'", +						c); +				goto bail; +			} +			hex = hex << 4 | fromhex(c); +			--nhexbytes; +			if (nhexbytes != 0) +				break; + +			switch (state) { +			case read_length: +				record = ccdbg_hex_alloc(hex); +				if (!record) { +					ccdbg_hex_error(input, "Out of memory"); +					goto bail; +				} +				state = read_address; +				nhexbytes = 4; +				break; +			case read_address: +				record->address = hex; +				state = read_type; +				nhexbytes = 2; +				break; +			case read_type: +				record->type = hex; +				state = read_data; +				nhexbytes = 2; +				ndata = 0; +				break; +			case read_data: +				record->data[ndata] = hex; +				ndata++; +				nhexbytes = 2; +				break; +			case read_checksum: +				record->checksum = hex; +				state = read_newline; +				break; +			default: +				break; +			} +			if (state == read_data) +				if (ndata == record->length) { +					nhexbytes = 2; +					state = read_checksum; +				} +			hex = 0; +			break; +		case read_newline: +			if (c != '\n' && c != '\r') { +				ccdbg_hex_error(input, "Missing newline"); +				goto bail; +			} +			state = read_white; +			break; +		case read_white: +			if (!isspace(c)) { +				if (c == '\n') +					input->line--; +				if (c != EOF) +					ungetc(c, input->file); +				state = read_done; +			} +			break; +		case read_done: +			break; +		} +	} +	checksum = ccdbg_hex_checksum(record); +	if (checksum != record->checksum) { +		ccdbg_hex_error(input, "Invalid checksum (read 0x%02x computed 0x%02x)\n", +				record->checksum, checksum); +		goto bail; +	} +	return record; + +bail: +	ccdbg_hex_free(record); +	return NULL; +} + +void +ccdbg_hex_file_free(struct hex_file *hex) +{ +	int	i; + +	if (!hex) +		return; +	for (i = 0; i < hex->nrecord; i++) +		ccdbg_hex_free(hex->records[i]); +	free(hex); +} + +static int +ccdbg_hex_record_compar(const void *av, const void *bv) +{ +	const struct hex_record *a = *(struct hex_record **) av; +	const struct hex_record *b = *(struct hex_record **) bv; + +	return (int) a->address - (int) b->address; +} + +struct hex_file * +ccdbg_hex_file_read(FILE *file, char *name) +{ +	struct hex_input input; +	struct hex_file	*hex = NULL, *newhex; +	struct hex_record *record; +	int srecord = 1; +	int done = 0; + +	hex = calloc(sizeof (struct hex_file) + sizeof (struct hex_record *), 1); +	input.name = name; +	input.line = 1; +	input.file = file; +	while (!done) { +		record = ccdbg_hex_read_record(&input); +		if (!record) +			goto bail; +		if (hex->nrecord == srecord) { +			srecord *= 2; +			newhex = realloc(hex, +					 sizeof (struct hex_file) + +					 srecord * sizeof (struct hex_record *)); +			if (!newhex) +				goto bail; +			hex = newhex; +		} +		hex->records[hex->nrecord++] = record; +		if (record->type == HEX_RECORD_EOF) +			done = 1; +	} +	/* +	 * Sort them into increasing addresses, except for EOF +	 */ +	qsort(hex->records, hex->nrecord - 1, sizeof (struct hex_record *), +	      ccdbg_hex_record_compar); +	return hex; + +bail: +	ccdbg_hex_file_free(hex); +	return NULL; +} + +struct hex_image * +ccdbg_hex_image_create(struct hex_file *hex) +{ +	struct hex_image *image; +	struct hex_record *first, *last, *record; +	int i; +	uint32_t base, bound; +	uint32_t offset; +	int length; + +	first = hex->records[0]; +	last = hex->records[hex->nrecord - 2];	/* skip EOF */ +	base = (uint32_t) first->address; +	bound = (uint32_t) last->address + (uint32_t) last->length; +	length = bound - base; +	image = calloc(sizeof(struct hex_image) + length, 1); +	if (!image) +		return NULL; +	image->address = base; +	image->length = length; +	memset(image->data, 0xff, length); +	for (i = 0; i < hex->nrecord - 1; i++) { +		record = hex->records[i]; +		offset = record->address - base; +		memcpy(image->data + offset, record->data, record->length); +	} +	return image; +} + +void +ccdbg_hex_image_free(struct hex_image *image) +{ +	free(image); +} + +int +ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b) +{ +	if (a->length != b->length) +		return 0; +	if (memcmp(a->data, b->data, a->length) != 0) +		return 0; +	return 1; +} diff --git a/ao-tools/lib/ccdbg-io.c b/ao-tools/lib/ccdbg-io.c new file mode 100644 index 00000000..9c6693cd --- /dev/null +++ b/ao-tools/lib/ccdbg-io.c @@ -0,0 +1,137 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include "ccdbg.h" +#include <time.h> +#include "cc-usb.h" +#include "cc-bitbang.h" + +struct ccdbg * +ccdbg_open(void) +{ +	struct ccdbg *dbg; +	char *tty; + +	dbg = calloc(sizeof (struct ccdbg), 1); +	if (!dbg) { +		perror("calloc"); +		return NULL; +	} +	tty = getenv("CCDBG_TTY"); +	if (!tty || tty[0] == '/') +		dbg->usb = cc_usb_open(tty); +	if (!dbg->usb) { +		dbg->bb = cc_bitbang_open(); +		if (!dbg->bb) { +			free(dbg); +			return NULL; +		} +	} +	return dbg; +} + +void +ccdbg_close(struct ccdbg *dbg) +{ +	if (dbg->usb) +		cc_usb_close(dbg->usb); +	if (dbg->bb) +		cc_bitbang_close(dbg->bb); +	free (dbg); +} + +void +ccdbg_debug_mode(struct ccdbg *dbg) +{ +	if (dbg->usb) +		cc_usb_debug_mode(dbg->usb); +	else if (dbg->bb) +		cc_bitbang_debug_mode(dbg->bb); +} + +void +ccdbg_reset(struct ccdbg *dbg) +{ +	if (dbg->usb) +		cc_usb_reset(dbg->usb); +	else if (dbg->bb) +		cc_bitbang_reset(dbg->bb); +} + +void +ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) +{ +	if (dbg->usb) +		cc_usb_send_bytes(dbg->usb, bytes, nbytes); +	else if (dbg->bb) +		cc_bitbang_send_bytes(dbg->bb, bytes, nbytes); +} + +void +ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes) +{ +	if (dbg->usb) +		cc_usb_recv_bytes(dbg->usb, bytes, nbytes); +	else if (dbg->bb) +		cc_bitbang_recv_bytes(dbg->bb, bytes, nbytes); +} + +void +ccdbg_sync(struct ccdbg *dbg) +{ +	if (dbg->usb) +		cc_usb_sync(dbg->usb); +	else if (dbg->bb) +		cc_bitbang_sync(dbg->bb); +} + +void +ccdbg_cmd_write(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) +{ +	ccdbg_send_bytes(dbg, &cmd, 1); +	ccdbg_send_bytes(dbg, data, len); +} + +uint8_t +ccdbg_cmd_write_read8(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) +{ +	uint8_t	byte[1]; +	ccdbg_cmd_write(dbg, cmd, data, len); +	ccdbg_recv_bytes(dbg, byte, 1); +	ccdbg_sync(dbg); +	return byte[0]; +} + +uint16_t +ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len) +{ +	uint8_t	byte[2]; +	ccdbg_cmd_write(dbg, cmd, data, len); +	ccdbg_recv_bytes(dbg, byte, 2); +	ccdbg_sync(dbg); +	return (byte[0] << 8) | byte[1]; +} + +void +ccdbg_cmd_write_queue8(struct ccdbg *dbg, uint8_t cmd, +		       uint8_t *data, int len, +		       uint8_t *reply) +{ +	ccdbg_cmd_write(dbg, cmd, data, len); +	ccdbg_recv_bytes(dbg, reply, 1); +} diff --git a/ao-tools/lib/ccdbg-manual.c b/ao-tools/lib/ccdbg-manual.c new file mode 100644 index 00000000..0e811b76 --- /dev/null +++ b/ao-tools/lib/ccdbg-manual.c @@ -0,0 +1,77 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include "ccdbg.h" +#include "cc-bitbang.h" + +/* + * Manual bit-banging to debug the low level protocol + */ + +static void +get_bit(char *line, int i, char on, uint8_t bit, uint8_t *bits, uint8_t *masks) +{ +	if (line[i] == on) { +		*bits |= bit; +		*masks |= bit; +		return; +	} +	if (line[i] == '.') { +		*masks |= bit; +		return; +	} +	if (line[i] == '-') { +		return; +	} +	fprintf(stderr, "bad line %s\n", line); +	exit (1); +} + +void +ccdbg_manual(struct ccdbg *dbg, FILE *input) +{ +	char	line[80]; +	uint8_t	set, mask; + +	if (dbg->bb == NULL) { +		fprintf(stderr, "Must use bitbang API for manual mode\n"); +		return; +	} +	while (fgets(line, sizeof line, input)) { +		if (line[0] == '#' || line[0] == '\n') { +			printf ("%s", line); +			continue; +		} +		set = 0; +		mask = 0; +		get_bit(line, 0, 'C', CC_CLOCK, &set, &mask); +		get_bit(line, 2, 'D', CC_DATA, &set, &mask); +		get_bit(line, 4, 'R', CC_RESET_N, &set, &mask); +		if (mask != (CC_CLOCK|CC_DATA|CC_RESET_N)) { +			uint8_t	read; +			cc_bitbang_read(dbg->bb, &read); +			cc_bitbang_sync(dbg->bb); +			cc_bitbang_print("\t%c %c %c", CC_CLOCK|CC_DATA|CC_RESET_N, read); +			if ((set & CC_CLOCK) == 0) +				printf ("\t%d", (read&CC_DATA) ? 1 : 0); +			printf ("\n"); +		} +		cc_bitbang_send(dbg->bb, mask, set); +		cc_bitbang_sync(dbg->bb); +	} +} diff --git a/ao-tools/lib/ccdbg-memory.c b/ao-tools/lib/ccdbg-memory.c new file mode 100644 index 00000000..554ac637 --- /dev/null +++ b/ao-tools/lib/ccdbg-memory.c @@ -0,0 +1,179 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include "ccdbg.h" + +/* + * Read and write arbitrary memory through the debug port + */ + +static uint8_t	memory_init[] = { +	3,	MOV_DPTR_data16,	0,	0, +#define HIGH_START	2 +#define LOW_START	3 +	0, +}; + + +static uint8_t write8[] = { +	2,	MOV_A_data,	0, +#define DATA_BYTE	2 +	1,	MOVX_atDPTR_A, +	1,	INC_DPTR, +	0 +}; + +static uint8_t read8[] = { +	1,	MOVX_A_atDPTR, +	1,	INC_DPTR, +	0, +}; + +uint8_t +ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) +{ +	int i, nl = 0; +	struct ccstate state; + +	if (dbg->usb) +		return cc_usb_write_memory(dbg->usb, addr, bytes, nbytes); +	ccdbg_state_save(dbg, &state, CC_STATE_ACC | CC_STATE_PSW | CC_STATE_DP); +	memory_init[HIGH_START] = addr >> 8; +	memory_init[LOW_START] = addr; +	(void) ccdbg_execute(dbg, memory_init); +	for (i = 0; i < nbytes; i++) { +		write8[DATA_BYTE] = *bytes++; +		ccdbg_execute(dbg, write8); +		if ((i & 0xf) == 0xf) { +			ccdbg_debug(CC_DEBUG_MEMORY, "."); +			ccdbg_flush(CC_DEBUG_MEMORY); +			nl = 1; +		} +		if ((i & 0xff) == 0xff) { +			ccdbg_debug(CC_DEBUG_MEMORY, "\n"); +			nl = 0; +		} +	} +	ccdbg_state_restore(dbg, &state); +	if (nl) +		ccdbg_debug(CC_DEBUG_MEMORY, "\n"); +	return 0; +} + +uint8_t +ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes) +{ +	int i, nl = 0; +	struct ccstate state; + +	if (ccdbg_rom_contains(dbg, addr, nbytes)) { +		ccdbg_rom_replace_xmem(dbg, addr, bytes, nbytes); +		return 0; +	} +	if (dbg->usb) +		return cc_usb_read_memory(dbg->usb, addr, bytes, nbytes); +	ccdbg_state_save(dbg, &state, CC_STATE_ACC | CC_STATE_PSW | CC_STATE_DP); +	memory_init[HIGH_START] = addr >> 8; +	memory_init[LOW_START] = addr; +	(void) ccdbg_execute(dbg, memory_init); +	for (i = 0; i < nbytes; i++) { +		*bytes++ = ccdbg_execute(dbg, read8); +		if ((i & 0xf) == 0xf) { +			ccdbg_debug(CC_DEBUG_MEMORY, "."); +			ccdbg_flush(CC_DEBUG_MEMORY); +			nl = 1; +		} +		if ((i & 0xff) == 0xff) { +			ccdbg_debug(CC_DEBUG_MEMORY, "\n"); +			nl = 0; +		} +	} +	ccdbg_state_replace_xmem(dbg, &state, addr, bytes, nbytes); +	ccdbg_state_restore(dbg, &state); +	if (nl) +		ccdbg_debug(CC_DEBUG_MEMORY, "\n"); +	return 0; +} + +uint8_t +ccdbg_write_uint8(struct ccdbg *dbg, uint16_t addr, uint8_t byte) +{ +	return ccdbg_write_memory(dbg, addr, &byte, 1); +} + +uint8_t +ccdbg_write_hex_image(struct ccdbg *dbg, struct hex_image *image, uint16_t offset) +{ +	ccdbg_write_memory(dbg, image->address + offset, image->data, image->length); +	return 0; +} + +struct hex_image * +ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length) +{ +	struct hex_image *image; + +	image = calloc(sizeof(struct hex_image) + length, 1); +	image->address = address; +	image->length = length; +	memset(image->data, 0xff, length); +	ccdbg_read_memory(dbg, address, image->data, length); +	return image; +} + +static uint8_t sfr_read[] = { +	2,	MOV_A_direct,		0, +#define SFR_READ_ADDR	2 +	0, +}; + +static uint8_t sfr_write[] = { +	3,	MOV_direct_data,	0,	0, +#define SFR_WRITE_ADDR	2 +#define SFR_WRITE_DATA	3 +	0, +}; + +uint8_t +ccdbg_read_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes) +{ +	int	i; +	struct ccstate state; + +	ccdbg_state_save(dbg, &state, CC_STATE_ACC); +	for (i = 0; i < nbytes; i++) { +		sfr_read[SFR_READ_ADDR] = addr + i; +		*bytes++ = ccdbg_execute(dbg, sfr_read); +	} +	ccdbg_state_replace_sfr(dbg, &state, addr, bytes, nbytes); +	ccdbg_state_restore(dbg, &state); +	return 0; +} + +uint8_t +ccdbg_write_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes) +{ +	int	i; + +	for (i = 0; i < nbytes; i++) { +		sfr_write[SFR_WRITE_ADDR] = addr + i; +		sfr_write[SFR_WRITE_DATA] = *bytes++; +		ccdbg_execute(dbg, sfr_write); +	} +	return 0; +} diff --git a/ao-tools/lib/ccdbg-rom.c b/ao-tools/lib/ccdbg-rom.c new file mode 100644 index 00000000..71bed220 --- /dev/null +++ b/ao-tools/lib/ccdbg-rom.c @@ -0,0 +1,63 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include "ccdbg.h" + +uint8_t +ccdbg_set_rom(struct ccdbg *dbg, struct hex_image *rom) +{ +	if (dbg->rom) +		ccdbg_hex_image_free(dbg->rom); +	dbg->rom = rom; +	return 0; +} + +uint8_t +ccdbg_rom_contains(struct ccdbg *dbg, uint16_t addr, int nbytes) +{ +	struct hex_image *rom = dbg->rom; +	if (!rom) +		return 0; +	if (addr < rom->address || rom->address + rom->length < addr + nbytes) +		return 0; +	return 1; +} + +uint8_t +ccdbg_rom_replace_xmem(struct ccdbg *dbg, +		       uint16_t addr, uint8_t *bytes, int nbytes) +{ +	struct hex_image *rom = dbg->rom; +	if (!rom) +		return 0; + +	if (rom->address < addr + nbytes && addr < rom->address + rom->length) { +		int	start, stop; + +		start = addr; +		if (addr < rom->address) +			start = rom->address; +		stop = addr + nbytes; +		if (rom->address + rom->length < stop) +			stop = rom->address + rom->length; +		memcpy(bytes + start - addr, rom->data + start - rom->address, +		       stop - start); +		return 1; +	} +	return 0; +} diff --git a/ao-tools/lib/ccdbg-state.c b/ao-tools/lib/ccdbg-state.c new file mode 100644 index 00000000..9aca8d2e --- /dev/null +++ b/ao-tools/lib/ccdbg-state.c @@ -0,0 +1,128 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include "ccdbg.h" + +static uint8_t save_acc[] = { +	1,	NOP, +	0 +}; + +static uint8_t save_sfr[] = { +	2,	MOV_A_direct,	0, +#define SAVE_SFR_ADDR	2 +	0, +}; + +struct sfr_state { +	uint8_t		address; +	uint16_t	mask; +	char		*name; +}; + +static struct sfr_state	sfrs[CC_STATE_NSFR] = { +	{ SFR_DPL0,	CC_STATE_DP,	"dpl0" }, +	{ SFR_DPH0,	CC_STATE_DP,	"dph0" }, +	{ SFR_DPL1,	CC_STATE_DP,	"dpl1" }, +	{ SFR_DPH1,	CC_STATE_DP,	"dph1" }, +	{ PSW(0),	CC_STATE_PSW,	"psw"  }, +}; + +uint8_t +ccdbg_state_save(struct ccdbg *dbg, struct ccstate *state, unsigned int mask) +{ +	int	i; + +	mask |= CC_STATE_ACC; +	if (mask & CC_STATE_ACC) +		state->acc = ccdbg_execute(dbg, save_acc); +	for (i = 0; i < CC_STATE_NSFR; i++) { +		if (sfrs[i].mask & mask) { +			save_sfr[SAVE_SFR_ADDR] = sfrs[i].address; +			state->sfr[i] = ccdbg_execute(dbg, save_sfr); +		} +	} +	state->mask = mask; +	return 0; +} + +static uint8_t restore_sfr[] = { +	3,	MOV_direct_data,	0,	0, +#define RESTORE_SFR_ADDR	2 +#define RESTORE_SFR_DATA	3 +	0 +}; + +static uint8_t restore_acc[] = { +	2,	MOV_A_data,	0, +#define RESTORE_ACC_DATA	2 +	0 +}; + +uint8_t +ccdbg_state_restore(struct ccdbg *dbg, struct ccstate *state) +{ +	int i; +	for (i = CC_STATE_NSFR - 1; i >= 0; i--) { +		if (sfrs[i].mask & state->mask) { +			restore_sfr[RESTORE_SFR_ADDR] = sfrs[i].address; +			restore_sfr[RESTORE_SFR_DATA] = state->sfr[i]; +			ccdbg_execute(dbg, restore_sfr); +		} +	} +	if (state->mask & CC_STATE_ACC) { +		restore_acc[RESTORE_ACC_DATA] = state->acc; +		ccdbg_execute(dbg, restore_acc); +	} +	state->mask = 0; +	return 0; +} + +static void +ccdbg_state_replace(uint16_t sfr_addr, uint8_t sfr, char *name, +		    uint16_t addr, uint8_t *bytes, int nbytes) +{ +	sfr_addr += 0xdf00; + +	if (addr <= sfr_addr && sfr_addr < addr + nbytes) { +		fprintf(stderr, "replacing %s at 0x%04x - read 0x%02x saved 0x%02x\n", +			name, sfr_addr, bytes[sfr_addr - addr], sfr); +		bytes[sfr_addr - addr] = sfr; +	} +} + +void +ccdbg_state_replace_xmem(struct ccdbg *dbg, struct ccstate *state, +			 uint16_t addr, uint8_t *bytes, int nbytes) +{ +	int i; +	if (state->mask & CC_STATE_ACC) +		ccdbg_state_replace(ACC(0), state->acc, "acc", +				    addr, bytes, nbytes); +	for (i = 0; i < CC_STATE_NSFR; i++) +		if (state->mask & sfrs[i].mask) +			ccdbg_state_replace(sfrs[i].address, state->sfr[i], +					    sfrs[i].name, addr, bytes, nbytes); +} + +void +ccdbg_state_replace_sfr(struct ccdbg *dbg, struct ccstate *state, +			uint8_t addr, uint8_t *bytes, int nbytes) +{ +	ccdbg_state_replace_xmem(dbg, state, (uint16_t) addr + 0xdf00, bytes, nbytes); +} diff --git a/ao-tools/lib/ccdbg.h b/ao-tools/lib/ccdbg.h new file mode 100644 index 00000000..4a2e3b9f --- /dev/null +++ b/ao-tools/lib/ccdbg.h @@ -0,0 +1,341 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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 _CCDBG_H_ +#define _CCDBG_H_ + +#include <stdint.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <stdio.h> +#include <stdint.h> +#include <assert.h> +#include <fcntl.h> +#include <sys/types.h> +#include <sys/ioctl.h> +#include <sys/stat.h> +#include "ccdbg-debug.h" +#include "cc-bitbang.h" +#include "cc-usb.h" + +/* 8051 instructions + */ +#define NOP			0x00 +#define MOV_direct_data		0x75 +#define LJMP			0x02 +#define MOV_Rn_data(n)		(0x78 | (n)) +#define DJNZ_Rn_rel(n)		(0xd8 | (n)) +#define MOV_A_direct		0xe5 +#define MOV_direct1_direct2	0x85 +#define MOV_direct_A		0xf5 +#define MOV_DPTR_data16		0x90 +#define MOV_A_data		0x74 +#define MOVX_atDPTR_A		0xf0 +#define MOVX_A_atDPTR		0xe0 +#define INC_DPTR		0xa3 +#define TRAP			0xa5 +#define SJMP			0x80 +#define JB			0x20 + +/* 8051 special function registers + */ + +#define SFR_P0			0x80 +#define SFR_SP			0x81 +#define SFR_DPL0		0x82 +#define SFR_DPH0		0x83 +#define SFR_DPL1		0x84 +#define SFR_DPH1		0x85 + +/* flash controller */ +#define FWT			0xAB +#define FADDRL			0xAC +#define FADDRH			0xAD +#define FCTL			0xAE +# define FCTL_BUSY		0x80 +# define FCTL_BUSY_BIT		7 +# define FCTL_SWBSY		0x40 +# define FCTL_SWBSY_BIT		6 +# define FCTL_CONTRD		0x10 +# define FCTL_WRITE		0x02 +# define FCTL_ERASE		0x01 +#define FWDATA			0xAF + +#define SLEEP			0xBE + +/* clock controller */ +#define CLKCON			0xC6 +#define  CLKCON_OSC32K		0x80 +#define  CLKCON_OSC		0x40 +#define  CLKCON_TICKSPD		0x38 +#define  CLKCON_CLKSPD		0x07 + +/* I/O pins */ +#define P0			0x80 +#define P1			0x90 +#define P2			0xA0 +#define P0DIR			0xFD +#define P1DIR			0xFE +#define P2DIR			0xFF + +/* Bit-addressable accumulator */ +#define ACC(bit)		(0xE0 | (bit)) + +/* Bit-addressable status word */ +#define PSW(bit)		(0xD0 | (bit)) + +struct ccdbg { +	struct cc_bitbang	*bb; +	struct cc_usb		*usb; +	struct hex_image	*rom; +}; + +/* Intel hex file format data + */ +struct hex_record { +	uint8_t	length; +	uint16_t address; +	uint8_t type; +	uint8_t checksum; +	uint8_t data[0]; +}; + +struct hex_file { +	int			nrecord; +	struct hex_record	*records[0]; +}; + +struct hex_image { +	uint16_t	address; +	uint16_t	length; +	uint8_t		data[0]; +}; + +#define CC_STATE_ACC	0x1 +#define CC_STATE_PSW	0x2 +#define CC_STATE_DP	0x4 + +#define CC_STATE_NSFR	5 + +struct ccstate { +	uint16_t	mask; +	uint8_t		acc; +	uint8_t		sfr[CC_STATE_NSFR]; +}; + +#define HEX_RECORD_NORMAL		0x00 +#define HEX_RECORD_EOF			0x01 +#define HEX_RECORD_EXTENDED_ADDRESS	0x02 + +/* CC1111 debug port commands + */ +#define CC_CHIP_ERASE		0x14 + +#define CC_WR_CONFIG		0x1d +#define CC_RD_CONFIG		0x24 +# define CC_CONFIG_TIMERS_OFF		(1 << 3) +# define CC_CONFIG_DMA_PAUSE		(1 << 2) +# define CC_CONFIG_TIMER_SUSPEND	(1 << 1) +# define CC_SET_FLASH_INFO_PAGE		(1 << 0) + +#define CC_GET_PC		0x28 +#define CC_READ_STATUS		0x34 +# define CC_STATUS_CHIP_ERASE_DONE	(1 << 7) +# define CC_STATUS_PCON_IDLE		(1 << 6) +# define CC_STATUS_CPU_HALTED		(1 << 5) +# define CC_STATUS_POWER_MODE_0		(1 << 4) +# define CC_STATUS_HALT_STATUS		(1 << 3) +# define CC_STATUS_DEBUG_LOCKED		(1 << 2) +# define CC_STATUS_OSCILLATOR_STABLE	(1 << 1) +# define CC_STATUS_STACK_OVERFLOW	(1 << 0) + +#define CC_SET_HW_BRKPNT	0x3b +# define CC_HW_BRKPNT_N(n)	((n) << 3) +# define CC_HW_BRKPNT_N_MASK	(0x3 << 3) +# define CC_HW_BRKPNT_ENABLE	(1 << 2) + +#define CC_HALT			0x44 +#define CC_RESUME		0x4c +#define CC_DEBUG_INSTR(n)	(0x54|(n)) +#define CC_STEP_INSTR		0x5c +#define CC_STEP_REPLACE(n)	(0x64|(n)) +#define CC_GET_CHIP_ID		0x68 + +/* ccdbg-command.c */ +void +ccdbg_debug_mode(struct ccdbg *dbg); + +void +ccdbg_reset(struct ccdbg *dbg); + +uint8_t +ccdbg_chip_erase(struct ccdbg *dbg); + +uint8_t +ccdbg_wr_config(struct ccdbg *dbg, uint8_t config); + +uint8_t +ccdbg_rd_config(struct ccdbg *dbg); + +uint16_t +ccdbg_get_pc(struct ccdbg *dbg); + +uint8_t +ccdbg_read_status(struct ccdbg *dbg); + +uint8_t +ccdbg_set_hw_brkpnt(struct ccdbg *dbg, uint8_t number, uint8_t enable, uint16_t addr); + +uint8_t +ccdbg_halt(struct ccdbg *dbg); + +uint8_t +ccdbg_resume(struct ccdbg *dbg); + +uint8_t +ccdbg_debug_instr(struct ccdbg *dbg, uint8_t *instr, int nbytes); + +void +ccdbg_debug_instr_discard(struct ccdbg *dbg, uint8_t *instr, int nbytes); + +void +ccdbg_debug_instr_queue(struct ccdbg *dbg, uint8_t *instr, int nbytes, +			uint8_t *reply); + +uint8_t +ccdbg_step_instr(struct ccdbg *dbg); + +uint8_t +ccdbg_step_replace(struct ccdbg *dbg, uint8_t *instr, int nbytes); + +uint16_t +ccdbg_get_chip_id(struct ccdbg *dbg); + +uint8_t +ccdbg_execute(struct ccdbg *dbg, uint8_t *inst); + +uint8_t +ccdbg_set_pc(struct ccdbg *dbg, uint16_t pc); + +uint8_t +ccdbg_execute_hex_image(struct ccdbg *dbg, struct hex_image *image); + +/* ccdbg-flash.c */ +uint8_t +ccdbg_flash_hex_image(struct ccdbg *dbg, struct hex_image *image); + +/* ccdbg-hex.c */ +struct hex_file * +ccdbg_hex_file_read(FILE *file, char *name); + +void +ccdbg_hex_file_free(struct hex_file *hex); + +struct hex_image * +ccdbg_hex_image_create(struct hex_file *hex); + +void +ccdbg_hex_image_free(struct hex_image *image); + +int +ccdbg_hex_image_equal(struct hex_image *a, struct hex_image *b); + +/* ccdbg-io.c */ +struct ccdbg * +ccdbg_open(void); + +void +ccdbg_close(struct ccdbg *dbg); + +void +ccdbg_cmd_write(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); + +uint8_t +ccdbg_cmd_write_read8(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); + +void +ccdbg_cmd_write_queue8(struct ccdbg *dbg, uint8_t cmd, +		       uint8_t *data, int len, uint8_t *reply); + +uint16_t +ccdbg_cmd_write_read16(struct ccdbg *dbg, uint8_t cmd, uint8_t *data, int len); + +void +ccdbg_send_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); + +void +ccdbg_recv_bytes(struct ccdbg *dbg, uint8_t *bytes, int nbytes); + +void +ccdbg_sync(struct ccdbg *dbg); + +/* ccdbg-manual.c */ + +void +ccdbg_manual(struct ccdbg *dbg, FILE *input); + +/* ccdbg-memory.c */ +uint8_t +ccdbg_write_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes); + +uint8_t +ccdbg_read_memory(struct ccdbg *dbg, uint16_t addr, uint8_t *bytes, int nbytes); + +uint8_t +ccdbg_write_uint8(struct ccdbg *dbg, uint16_t addr, uint8_t byte); + +uint8_t +ccdbg_write_hex_image(struct ccdbg *dbg, struct hex_image *image, uint16_t offset); + +struct hex_image * +ccdbg_read_hex_image(struct ccdbg *dbg, uint16_t address, uint16_t length); + +uint8_t +ccdbg_read_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes); + +uint8_t +ccdbg_write_sfr(struct ccdbg *dbg, uint8_t addr, uint8_t *bytes, int nbytes); + +/* ccdbg-rom.c */ +uint8_t +ccdbg_set_rom(struct ccdbg *dbg, struct hex_image *rom); + +uint8_t +ccdbg_rom_contains(struct ccdbg *dbg, uint16_t addr, int nbytes); + +uint8_t +ccdbg_rom_replace_xmem(struct ccdbg *dbg, +		       uint16_t addrp, uint8_t *bytesp, int nbytes); + +/* ccdbg-state.c */ +uint8_t +ccdbg_state_save(struct ccdbg *dbg, struct ccstate *state, unsigned int mask); + +uint8_t +ccdbg_state_restore(struct ccdbg *dbg, struct ccstate *state); + +void +ccdbg_state_replace_xmem(struct ccdbg *dbg, struct ccstate *state, +			 uint16_t addr, uint8_t *bytes, int nbytes); + +void +ccdbg_state_replace_sfr(struct ccdbg *dbg, struct ccstate *state, +			uint8_t addr, uint8_t *bytes, int nbytes); + +#endif /* _CCDBG_H_ */ diff --git a/ao-tools/lib/cp-usb-async.c b/ao-tools/lib/cp-usb-async.c new file mode 100644 index 00000000..6539394b --- /dev/null +++ b/ao-tools/lib/cp-usb-async.c @@ -0,0 +1,188 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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. + */ + +#include <stdio.h> +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include "cp-usb-async.h" +#include "ccdbg-debug.h" + +#define MAX_OUTSTANDING		256 +#define CP_TIMEOUT		1000	/* ms */ + +struct cp_usb_packet { +	struct libusb_transfer	*transfer; +	enum { packet_read, packet_write } direction; +	unsigned char		data[9]; +	uint8_t			*valuep; +}; + +struct cp_usb_async { +	libusb_context		*ctx; +	libusb_device_handle	*handle; +	struct cp_usb_packet	packet[MAX_OUTSTANDING]; +	int			p, ack; +	uint8_t			value; +	uint8_t			set; +}; + +struct cp_usb_async * +cp_usb_async_open(void) +{ +	struct cp_usb_async *cp; +	int ret; + +	cp = calloc(sizeof (struct cp_usb_async), 1); +	if (!cp) +		return NULL; +	ret = libusb_init(&cp->ctx); +	if (ret) { +		free(cp); +		return NULL; +	} +	cp->handle = libusb_open_device_with_vid_pid(cp->ctx, +						     0x10c4, 0xea60); +	cp->ack = -1; +	if (!cp->handle) { +		libusb_exit(cp->ctx); +		free(cp); +		return NULL; +	} +	cp->value = 0; +	cp->set = 0; +	return cp; +} + +void +cp_usb_async_close(struct cp_usb_async *cp) +{ +	libusb_close(cp->handle); +	libusb_exit(cp->ctx); +	free(cp); +} + +static void +cp_usb_async_transfer_callback(struct libusb_transfer *transfer) +{ +	struct cp_usb_async *cp = transfer->user_data; +	int p; + +	for (p = 0; p < cp->p; p++) +		if (cp->packet[p].transfer == transfer) +			break; +	if (p == cp->p) { +		fprintf(stderr, "unknown transfer\n"); +		return; +	} +	switch (cp->packet[p].direction) { +	case packet_read: +		ccdbg_debug(CC_DEBUG_USB_ASYNC, "ack read %d 0x%02x\n", +			    p, cp->packet[p].data[8]); +		*cp->packet[p].valuep = cp->packet[p].data[8]; +		break; +	case packet_write: +		ccdbg_debug(CC_DEBUG_USB_ASYNC, "ack write %d\n", p); +		break; +	} +	if (p > cp->ack) +		cp->ack = p; +} + +void +cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value) +{ +	int	p; +	uint16_t gpio_set; +	int	ret; + +	if (cp->set) { +		value = (cp->value & ~mask) | (value & mask); +		mask = value ^ cp->value; +	} +	cp->set = 1; +	cp->value = value; +	gpio_set = ((uint16_t) value << 8) | mask; +	if (cp->p == MAX_OUTSTANDING) +		cp_usb_async_sync(cp); +	p = cp->p; +	if (!cp->packet[p].transfer) +		cp->packet[p].transfer = libusb_alloc_transfer(0); +	cp->packet[p].direction = packet_write; +	libusb_fill_control_setup(cp->packet[p].data, +				  0x40,			/* request */ +				  0xff,			/* request type */ +				  0x37e1,		/* value */ +				  gpio_set,		/* index */ +				  0);			/* length */ + +	libusb_fill_control_transfer(cp->packet[p].transfer, +				     cp->handle, +				     cp->packet[p].data, +				     cp_usb_async_transfer_callback, +				     cp, +				     CP_TIMEOUT); +	ccdbg_debug(CC_DEBUG_USB_ASYNC, "Write packet %d 0x%x 0x%x\n", p, mask, value); +	ret = libusb_submit_transfer(cp->packet[p].transfer); +	if (ret) +		fprintf(stderr, "libusb_submit_transfer failed %d\n", ret); +	cp->p++; +} + +void +cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep) +{ +	int	p; +	int	ret; + +	if (cp->p == MAX_OUTSTANDING) +		cp_usb_async_sync(cp); +	p = cp->p; +	if (!cp->packet[p].transfer) +		cp->packet[p].transfer = libusb_alloc_transfer(0); +	cp->packet[p].valuep = valuep; +	cp->packet[p].direction = packet_read; +	libusb_fill_control_setup(cp->packet[p].data, +				  0xc0,			/* request */ +				  0xff,			/* request type */ +				  0x00c2,		/* value */ +				  0,			/* index */ +				  1);			/* length */ + +	libusb_fill_control_transfer(cp->packet[p].transfer, +				     cp->handle, +				     cp->packet[p].data, +				     cp_usb_async_transfer_callback, +				     cp, +				     CP_TIMEOUT); +	ccdbg_debug(CC_DEBUG_USB_ASYNC, "Read packet %d\n", p); +	ret = libusb_submit_transfer(cp->packet[p].transfer); +	if (ret) +		fprintf(stderr, "libusb_submit_transfer failed %d\n", ret); +	cp->p++; +} + +void +cp_usb_async_sync(struct cp_usb_async *cp) +{ +	while (cp->ack < cp->p - 1) { +		libusb_handle_events(cp->ctx); +	} +	cp->p = 0; +	cp->ack = -1; +} diff --git a/ao-tools/lib/cp-usb-async.h b/ao-tools/lib/cp-usb-async.h new file mode 100644 index 00000000..976a320e --- /dev/null +++ b/ao-tools/lib/cp-usb-async.h @@ -0,0 +1,38 @@ +/* + * Copyright © 2008 Keith Packard <keithp@keithp.com> + * + * 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 _CP_USB_ASYNC_H_ +#define _CP_USB_ASYNC_H_ +#include <libusb.h> + +struct cp_usb_async * +cp_usb_async_open(void); + +void +cp_usb_async_close(struct cp_usb_async *cp); + +void +cp_usb_async_write(struct cp_usb_async *cp, uint8_t mask, uint8_t value); + +void +cp_usb_async_read(struct cp_usb_async *cp, uint8_t *valuep); + +void +cp_usb_async_sync(struct cp_usb_async *cp); + +#endif | 
