From cb01267f42eba7bc5a572235e5d2571cc9b60303 Mon Sep 17 00:00:00 2001 From: Tzafrir Cohen Date: Thu, 2 Apr 2009 20:56:42 +0000 Subject: Support for Astribanks 116x: tools part * New USB firmware loading mechanism. - Incompatible with previous one: upgrade using fxload or hard reset - astribank_hexload is the new low-level loading tool - fpga_load remains for backward compatibility. - xpp/astribank_upgrade: automate upgrading using fxload * Much enhanced control protocol ("MPP") - astribank_tool is the low-level tool for that. * Support for the TwinStar (dual USB port) - Managed through astribank_tool - Wrapper perl modules and scripts provided * Allow explicit ordering of Astribanks - /etc/dahdi/xpp_order - explicit order of Astribanks on the system - The default sorter is now to use those and fall back to connectors (previous default). - An option to dahdi_registration to change sorting. git-svn-id: http://svn.asterisk.org/svn/dahdi/tools/trunk@6313 a0bf4364-ded3-4de4-8d8a-66a801d63aff --- xpp/pic_loader.c | 275 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 275 insertions(+) create mode 100644 xpp/pic_loader.c (limited to 'xpp/pic_loader.c') diff --git a/xpp/pic_loader.c b/xpp/pic_loader.c new file mode 100644 index 0000000..c74718e --- /dev/null +++ b/xpp/pic_loader.c @@ -0,0 +1,275 @@ +/* + * Written by Oron Peled + * 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 +#include +#include +#include +#include "hexfile.h" +#include "pic_loader.h" +#include "debug.h" + +#define DBG_MASK 0x03 +#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; + +int send_picline(struct astribank_device *astribank, uint8_t card_type, enum pic_command pcmd, int offs, uint8_t *data, int data_len) +{ + int recv_answer = 0; + char buf[PACKET_SIZE]; + struct xpp_packet_header *phead = (struct xpp_packet_header *)buf; + int pack_len; + int ret; + + assert(astribank != NULL); + 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); + dump_packet(LOG_DEBUG, "dump:picline[W]", (char *)phead, pack_len); + + ret = send_usb(astribank, buf, pack_len, TIMEOUT); + if(ret < 0) { + ERR("send_usb failed: %d\n", ret); + return ret; + } + DBG("send_usb: Written %d bytes\n", ret); + if (recv_answer) { + ret = recv_usb(astribank, buf, sizeof(buf), TIMEOUT); + 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); + dump_packet(LOG_ERR, "hexline[ERR]", buf, ret); + 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(®ex, re, REG_ICASE | REG_EXTENDED)) != 0) { + regerror(ret, ®ex, ebuf, sizeof(ebuf)); + ERR("regcomp: %s\n", ebuf); + return NULL; + } + if((ret = regexec(®ex, basename, nmatch, pmatch, 0)) != 0) { + regerror(ret, ®ex, ebuf, sizeof(ebuf)); + ERR("regexec: %s\n", ebuf); + regfree(®ex); + 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(®ex); + 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(®ex); + return NULL; + } + *card_type = ret; + regfree(®ex); + return basename; +} + +/* + * Returns: true on success, false on failure + */ +static int pic_burn(struct astribank_device *astribank, const struct hexdata *hexdata) +{ + 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; + + v = (v[0]) ? v : "Unknown"; + assert(astribank != NULL); + assert(hexdata != NULL); + if(!astribank->is_usb2) { + ERR("Skip PIC burning (not USB2)\n"); + return 0; + } + INFO("Load PIC: %s\n", hexdata->fname); + basename = pic_basename(hexdata->fname, &card_type); + if(!basename) { + ERR("Bad PIC filename '%s'. Abort.\n", hexdata->fname); + 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--) { + char buf[PACKET_SIZE]; + + if(usb_bulk_read(astribank->handle, astribank->my_ep_in, buf, sizeof(buf), 1) <= 0) + break; + } + if((ret = send_picline(astribank, card_type, PIC_START_FLAG, 0, NULL, 0)) != 0) { + 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) { + ERR("hexdata finished early (line %d)", i); + return 0; + } + if(hexline->d.content.header.tt == TT_DATA) { + len = hexline->d.content.header.ll; /* don't send checksum */ + if(len != 3) { + ERR("Bad line len %d\n", len); + return 0; + } + data = hexline->d.content.tt_data.data; + check_sum ^= data[0] ^ data[1] ^ data[2]; + ret = send_picline(astribank, card_type, PIC_DATA_FLAG, + 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 { + ERR("Unexpected TT = %d in line %d\n", + hexline->d.content.header.tt, i); + return 0; + } + } + if((ret = send_picline(astribank, card_type, PIC_END_FLAG, 0, &check_sum, 1)) != 0) { + perror("Failed sending end hexline"); + return 0; + } + DBG("Finished...\n"); + return 1; +} + +int load_pic(struct astribank_device *astribank, int numfiles, char *filelist[]) +{ + int i; + + INFO("Loading %d PIC files...\n", numfiles); + 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; + } + if(!pic_burn(astribank, picdata)) { + ERR("PIC %s burning failed\n", curr); + return -ENODEV; + } + free_hexdata(picdata); + } + if((i = send_picline(astribank, 0, PIC_ENDS_FLAG, 0, NULL, 0)) != 0) { + ERR("PIC end burning failed\n"); + return -ENODEV; + } + return 0; +} -- cgit v1.2.3