pic_loader.c 7.47 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
/*
 * Written by Oron Peled <oron@actcom.co.il>
 * Copyright (C) 2008, Xorcom
 *
 * All rights reserved.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#include <regex.h>
28 29
#include <xtalk/debug.h>
#include <xtalk/xusb.h>
30 31 32
#include "hexfile.h"
#include "pic_loader.h"

33
#define	DBG_MASK	0x20
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
#define	MAX_HEX_LINES	10000
#define	TIMEOUT		500

enum xpp_packet_types {
	PIC_REQ_XOP 	= 0x09,
	PIC_REP_XOP 	= 0x0A
};

struct xpp_packet_header {
	struct {
		uint16_t	len;
		uint8_t		op;
		uint8_t		unit;
	} PACKED header;
	union {
		struct {
			struct {
				uint8_t		flags;
				uint8_t		card_type;
				uint16_t	offs;
			} pic_header;
			uint8_t		data[3];
		} PACKED pic_packet;
	} d;
} PACKED;

60
int send_picline(struct astribank *ab, uint8_t card_type, enum pic_command pcmd, int offs, uint8_t *data, int data_len)
61 62 63 64 65 66 67
{
	int				recv_answer = 0;
	char				buf[PACKET_SIZE];
	struct xpp_packet_header	*phead = (struct xpp_packet_header *)buf;
	int				pack_len;
	int				ret;

68
	assert(ab != NULL);
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
	pack_len = data_len + sizeof(phead->header) + sizeof(phead->d.pic_packet.pic_header);
	phead->header.len 		= pack_len;
	phead->header.op 		= PIC_REQ_XOP;
	phead->header.unit 		= 0x00;
	phead->d.pic_packet.pic_header.flags = pcmd; 
	phead->d.pic_packet.pic_header.card_type = card_type;
	phead->d.pic_packet.pic_header.offs = offs;
	if(data)
		memcpy(phead->d.pic_packet.data, data, data_len);
	switch (pcmd) {
		case PIC_START_FLAG:
			break;
		case PIC_DATA_FLAG:
			break;
		case PIC_END_FLAG:
			recv_answer = 1;
			break;
		case PIC_ENDS_FLAG:
			break;
	}

	DBG("PICLINE: pack_len=%d pcmd=%d\n", pack_len, pcmd);
91
	dump_packet(LOG_DEBUG, DBG_MASK, "dump:picline[W]", (char *)phead, pack_len);
92

93
	ret = astribank_send(ab, 0, buf, pack_len, TIMEOUT);
94
	if(ret < 0) {
95
		ERR("astribank_send failed: %d\n", ret);
96 97
		return ret;
	}
98
	DBG("astribank_send: Written %d bytes\n", ret);
99
	if (recv_answer) {
100
		ret = astribank_recv(ab, 0, buf, sizeof(buf), TIMEOUT);
101 102 103 104 105 106 107
		if(ret <= 0) {
			ERR("No USB packs to read\n");
			return ret;
		} else {
			phead = (struct xpp_packet_header *)buf;
			if(phead->header.op != PIC_REP_XOP) {
				ERR("Got unexpected reply OP=0x%02X\n", phead->header.op);
108
				dump_packet(LOG_ERR, DBG_MASK, "hexline[ERR]", buf, ret);
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174
				return -EINVAL;
			}
			DBG("received OP=0x%02X, checksum=%02X\n", phead->header.op, phead->d.pic_packet.data[0]);
			if(phead->d.pic_packet.data[0] != 0) {
				ERR("PIC burning, bad checksum\n");
				return -EINVAL;
			}
		}
	}
	return 0;
}

static const char *pic_basename(const char *fname, uint8_t *card_type)
{
	const char	*basename;
	regex_t		regex;
	char		ebuf[BUFSIZ];
	const char	re[] = "PIC_TYPE_([0-9]+)\\.hex";
	regmatch_t	pmatch[2];	/* One for the whole match, one for the number */
	int		nmatch = (sizeof(pmatch)/sizeof(pmatch[0]));
	int		len;
	int		ret;

	basename = strrchr(fname, '/');
	if(!basename)
		basename = fname;
	if((ret = regcomp(&regex, re, REG_ICASE | REG_EXTENDED)) != 0) {
		regerror(ret, &regex, ebuf, sizeof(ebuf));
		ERR("regcomp: %s\n", ebuf);
		return NULL;
	}
	if((ret = regexec(&regex, basename, nmatch, pmatch, 0)) != 0) {
		regerror(ret, &regex, ebuf, sizeof(ebuf));
		ERR("regexec: %s\n", ebuf);
		regfree(&regex);
		return NULL;
	}
	/*
	 * Should have both complete match and a parentheses match
	 */
	if(pmatch[0].rm_so == -1 || pmatch[1].rm_so == -1) {
		ERR("pic_basename: Bad match: pmatch[0].rm_so=%d pmatch[1].rm_so=%d\n",
			pmatch[0].rm_so, pmatch[1].rm_so == -1);
		regfree(&regex);
		return NULL;
	}
	len = pmatch[1].rm_eo - pmatch[1].rm_so;
	if(len >= sizeof(ebuf) - 1)
		len = sizeof(ebuf) - 1;
	memcpy(ebuf, basename + pmatch[1].rm_so, len);
	ebuf[len] = '\0';
	DBG("match: %s\n", ebuf);
	ret = atoi(ebuf);
	if(ret <= 0 || ret > 9) {
		ERR("pic_basename: Bad type number %d\n", ret);
		regfree(&regex);
		return NULL;
	}
	*card_type = ret;
	regfree(&regex);
	return basename;
}

/*
 * Returns: true on success, false on failure
 */
175
static int pic_burn(struct astribank *ab, const struct hexdata *hexdata)
176 177 178 179 180 181 182 183
{
	const char		*v = hexdata->version_info;
	const char		*basename;
	uint8_t			*data;
	unsigned char		check_sum = 0;
	uint8_t			card_type;
	int			ret;
	unsigned int		i;
184
	const char		*devstr;
185
	const struct xusb_device *xusb;
186 187

	v = (v[0]) ? v : "Unknown";
188
	assert(ab != NULL);
189
	assert(hexdata != NULL);
190 191 192 193
	xusb = xusb_dev_of_astribank(ab);
	devstr = xusb_devpath(xusb);
	i = xusb_packet_size(xusb);
	if(i != 512) {
194
		ERR("%s: Skip PIC burning (not USB2)\n", devstr);
195 196
		return 0;
	}
197 198
	INFO("%s [%s]: Loading PIC Firmware: %s (version %s)\n",
		devstr,
199
		xusb_serial(xusb),
200 201
		hexdata->fname,
		hexdata->version_info);
202 203
	basename = pic_basename(hexdata->fname, &card_type);
	if(!basename) {
204
		ERR("%s: Bad PIC filename '%s'. Abort.\n", devstr, hexdata->fname);
205 206 207 208 209 210 211 212
		return 0;
	}
	DBG("basename=%s card_type=%d maxlines=%d\n",
		basename, card_type, hexdata->maxlines);
	/*
	 * Try to read extra left-overs from USB controller
	 */
	for(i = 2; i; i--) {
213
		char    buf[PACKET_SIZE];
214

215
		if (astribank_recv(ab, 0, buf, sizeof(buf), TIMEOUT) <= 0)
216 217
			break;
	}
218
	if((ret = send_picline(ab, card_type, PIC_START_FLAG, 0, NULL, 0)) != 0) {
219 220 221 222 223 224 225 226 227
		perror("Failed sending start hexline");
		return 0;
	}
	for(i = 0; i < hexdata->maxlines; i++) { 
		struct hexline	*hexline;
		unsigned int	len;

		hexline = hexdata->lines[i];
		if(!hexline) {
228
			ERR("%s: hexdata finished early (line %d)", devstr, i);
229 230 231 232 233
			return 0;
		}
		if(hexline->d.content.header.tt == TT_DATA) {
			len = hexline->d.content.header.ll;	/* don't send checksum */
			if(len != 3) {
234
				ERR("%s: Bad line len %d\n", devstr, len);
235 236 237 238
				return 0;
			}
			data = hexline->d.content.tt_data.data;
			check_sum ^= data[0] ^ data[1] ^ data[2];
239
			ret = send_picline(ab, card_type, PIC_DATA_FLAG,
240 241 242 243 244 245 246 247
					hexline->d.content.header.offset, data, len);
			if(ret) {
				perror("Failed sending data hexline");
				return 0;
			}
		} else if(hexline->d.content.header.tt == TT_EOF) {
			break;
		} else {
248 249
			ERR("%s: Unexpected TT = %d in line %d\n",
					devstr, hexline->d.content.header.tt, i);
250 251 252
			return 0;
		}
	}
253
	if((ret = send_picline(ab, card_type, PIC_END_FLAG, 0, &check_sum, 1)) != 0) {
254 255 256 257 258 259 260
		perror("Failed sending end hexline");
		return 0;
	}
	DBG("Finished...\n");
	return 1;
}

261
int load_pic(struct astribank *ab, int numfiles, char *filelist[])
262
{
263 264
	int		i;
	const char	*devstr;
265

266
	devstr = xusb_devpath(xusb_dev_of_astribank(ab));
267
	DBG("%s: Loading %d PIC files...\n", devstr, numfiles);
268 269 270 271 272 273 274 275 276
	for(i = 0; i < numfiles; i++) {
		struct hexdata	*picdata;
		const char	*curr = filelist[i];

		DBG("%s\n", curr);
		if((picdata = parse_hexfile(curr, MAX_HEX_LINES)) == NULL) {
			perror(curr);
			return -errno;
		}
277
		if(!pic_burn(ab, picdata)) {
278
			ERR("%s: PIC %s burning failed\n", devstr, curr);
279 280 281 282
			return -ENODEV;
		}
		free_hexdata(picdata);
	}
283
	if((i = send_picline(ab, 0, PIC_ENDS_FLAG, 0, NULL, 0)) != 0) {
284
		ERR("%s: PIC end burning failed\n", devstr);
285 286 287 288
		return -ENODEV;
	}
	return 0;
}