Reported by Trent Creekmore
[dahdi/tools.git] / xpp / pic_loader.c
1 /*
2  * Written by Oron Peled <oron@actcom.co.il>
3  * Copyright (C) 2008, Xorcom
4  *
5  * All rights reserved.
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20  *
21  */
22
23 #include <assert.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <errno.h>
27 #include <regex.h>
28 #include <xtalk/debug.h>
29 #include <xtalk/xusb.h>
30 #include "hexfile.h"
31 #include "pic_loader.h"
32
33 #define DBG_MASK        0x20
34 #define MAX_HEX_LINES   10000
35 #define TIMEOUT         500
36
37 enum xpp_packet_types {
38         PIC_REQ_XOP     = 0x09,
39         PIC_REP_XOP     = 0x0A
40 };
41
42 struct xpp_packet_header {
43         struct {
44                 uint16_t        len;
45                 uint8_t         op;
46                 uint8_t         unit;
47         } PACKED header;
48         union {
49                 struct {
50                         struct {
51                                 uint8_t         flags;
52                                 uint8_t         card_type;
53                                 uint16_t        offs;
54                         } pic_header;
55                         uint8_t         data[3];
56                 } PACKED pic_packet;
57         } d;
58 } PACKED;
59
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         int                             recv_answer = 0;
63         char                            buf[PACKET_SIZE];
64         struct xpp_packet_header        *phead = (struct xpp_packet_header *)buf;
65         int                             pack_len;
66         int                             ret;
67
68         assert(ab != NULL);
69         pack_len = data_len + sizeof(phead->header) + sizeof(phead->d.pic_packet.pic_header);
70         phead->header.len               = pack_len;
71         phead->header.op                = PIC_REQ_XOP;
72         phead->header.unit              = 0x00;
73         phead->d.pic_packet.pic_header.flags = pcmd; 
74         phead->d.pic_packet.pic_header.card_type = card_type;
75         phead->d.pic_packet.pic_header.offs = offs;
76         if(data)
77                 memcpy(phead->d.pic_packet.data, data, data_len);
78         switch (pcmd) {
79                 case PIC_START_FLAG:
80                         break;
81                 case PIC_DATA_FLAG:
82                         break;
83                 case PIC_END_FLAG:
84                         recv_answer = 1;
85                         break;
86                 case PIC_ENDS_FLAG:
87                         break;
88         }
89
90         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                 return ret;
97         }
98         DBG("astribank_send: Written %d bytes\n", ret);
99         if (recv_answer) {
100                 ret = astribank_recv(ab, 0, buf, sizeof(buf), TIMEOUT);
101                 if(ret <= 0) {
102                         ERR("No USB packs to read\n");
103                         return ret;
104                 } else {
105                         phead = (struct xpp_packet_header *)buf;
106                         if(phead->header.op != PIC_REP_XOP) {
107                                 ERR("Got unexpected reply OP=0x%02X\n", phead->header.op);
108                                 dump_packet(LOG_ERR, DBG_MASK, "hexline[ERR]", buf, ret);
109                                 return -EINVAL;
110                         }
111                         DBG("received OP=0x%02X, checksum=%02X\n", phead->header.op, phead->d.pic_packet.data[0]);
112                         if(phead->d.pic_packet.data[0] != 0) {
113                                 ERR("PIC burning, bad checksum\n");
114                                 return -EINVAL;
115                         }
116                 }
117         }
118         return 0;
119 }
120
121 static const char *pic_basename(const char *fname, uint8_t *card_type)
122 {
123         const char      *basename;
124         regex_t         regex;
125         char            ebuf[BUFSIZ];
126         const char      re[] = "PIC_TYPE_([0-9]+)\\.hex";
127         regmatch_t      pmatch[2];      /* One for the whole match, one for the number */
128         int             nmatch = (sizeof(pmatch)/sizeof(pmatch[0]));
129         int             len;
130         int             ret;
131
132         basename = strrchr(fname, '/');
133         if(!basename)
134                 basename = fname;
135         if((ret = regcomp(&regex, re, REG_ICASE | REG_EXTENDED)) != 0) {
136                 regerror(ret, &regex, ebuf, sizeof(ebuf));
137                 ERR("regcomp: %s\n", ebuf);
138                 return NULL;
139         }
140         if((ret = regexec(&regex, basename, nmatch, pmatch, 0)) != 0) {
141                 regerror(ret, &regex, ebuf, sizeof(ebuf));
142                 ERR("regexec: %s\n", ebuf);
143                 regfree(&regex);
144                 return NULL;
145         }
146         /*
147          * Should have both complete match and a parentheses match
148          */
149         if(pmatch[0].rm_so == -1 || pmatch[1].rm_so == -1) {
150                 ERR("pic_basename: Bad match: pmatch[0].rm_so=%d pmatch[1].rm_so=%d\n",
151                         pmatch[0].rm_so, pmatch[1].rm_so == -1);
152                 regfree(&regex);
153                 return NULL;
154         }
155         len = pmatch[1].rm_eo - pmatch[1].rm_so;
156         if(len >= sizeof(ebuf) - 1)
157                 len = sizeof(ebuf) - 1;
158         memcpy(ebuf, basename + pmatch[1].rm_so, len);
159         ebuf[len] = '\0';
160         DBG("match: %s\n", ebuf);
161         ret = atoi(ebuf);
162         if(ret <= 0 || ret > 9) {
163                 ERR("pic_basename: Bad type number %d\n", ret);
164                 regfree(&regex);
165                 return NULL;
166         }
167         *card_type = ret;
168         regfree(&regex);
169         return basename;
170 }
171
172 /*
173  * Returns: true on success, false on failure
174  */
175 static int pic_burn(struct astribank *ab, const struct hexdata *hexdata)
176 {
177         const char              *v = hexdata->version_info;
178         const char              *basename;
179         uint8_t                 *data;
180         unsigned char           check_sum = 0;
181         uint8_t                 card_type;
182         int                     ret;
183         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         xusb = xusb_dev_of_astribank(ab);
191         devstr = xusb_devpath(xusb);
192         i = xusb_packet_size(xusb);
193         if(i != 512) {
194                 ERR("%s: Skip PIC burning (not USB2)\n", devstr);
195                 return 0;
196         }
197         INFO("%s [%s]: Loading PIC Firmware: %s (version %s)\n",
198                 devstr,
199                 xusb_serial(xusb),
200                 hexdata->fname,
201                 hexdata->version_info);
202         basename = pic_basename(hexdata->fname, &card_type);
203         if(!basename) {
204                 ERR("%s: Bad PIC filename '%s'. Abort.\n", devstr, hexdata->fname);
205                 return 0;
206         }
207         DBG("basename=%s card_type=%d maxlines=%d\n",
208                 basename, card_type, hexdata->maxlines);
209         /*
210          * Try to read extra left-overs from USB controller
211          */
212         for(i = 2; i; i--) {
213                 char    buf[PACKET_SIZE];
214
215                 if (astribank_recv(ab, 0, buf, sizeof(buf), TIMEOUT) <= 0)
216                         break;
217         }
218         if((ret = send_picline(ab, card_type, PIC_START_FLAG, 0, NULL, 0)) != 0) {
219                 perror("Failed sending start hexline");
220                 return 0;
221         }
222         for(i = 0; i < hexdata->maxlines; i++) { 
223                 struct hexline  *hexline;
224                 unsigned int    len;
225
226                 hexline = hexdata->lines[i];
227                 if(!hexline) {
228                         ERR("%s: hexdata finished early (line %d)", devstr, i);
229                         return 0;
230                 }
231                 if(hexline->d.content.header.tt == TT_DATA) {
232                         len = hexline->d.content.header.ll;     /* don't send checksum */
233                         if(len != 3) {
234                                 ERR("%s: Bad line len %d\n", devstr, len);
235                                 return 0;
236                         }
237                         data = hexline->d.content.tt_data.data;
238                         check_sum ^= data[0] ^ data[1] ^ data[2];
239                         ret = send_picline(ab, card_type, PIC_DATA_FLAG,
240                                         hexline->d.content.header.offset, data, len);
241                         if(ret) {
242                                 perror("Failed sending data hexline");
243                                 return 0;
244                         }
245                 } else if(hexline->d.content.header.tt == TT_EOF) {
246                         break;
247                 } else {
248                         ERR("%s: Unexpected TT = %d in line %d\n",
249                                         devstr, hexline->d.content.header.tt, i);
250                         return 0;
251                 }
252         }
253         if((ret = send_picline(ab, card_type, PIC_END_FLAG, 0, &check_sum, 1)) != 0) {
254                 perror("Failed sending end hexline");
255                 return 0;
256         }
257         DBG("Finished...\n");
258         return 1;
259 }
260
261 int load_pic(struct astribank *ab, int numfiles, char *filelist[])
262 {
263         int             i;
264         const char      *devstr;
265
266         devstr = xusb_devpath(xusb_dev_of_astribank(ab));
267         DBG("%s: Loading %d PIC files...\n", devstr, numfiles);
268         for(i = 0; i < numfiles; i++) {
269                 struct hexdata  *picdata;
270                 const char      *curr = filelist[i];
271
272                 DBG("%s\n", curr);
273                 if((picdata = parse_hexfile(curr, MAX_HEX_LINES)) == NULL) {
274                         perror(curr);
275                         return -errno;
276                 }
277                 if(!pic_burn(ab, picdata)) {
278                         ERR("%s: PIC %s burning failed\n", devstr, curr);
279                         return -ENODEV;
280                 }
281                 free_hexdata(picdata);
282         }
283         if((i = send_picline(ab, 0, PIC_ENDS_FLAG, 0, NULL, 0)) != 0) {
284                 ERR("%s: PIC end burning failed\n", devstr);
285                 return -ENODEV;
286         }
287         return 0;
288 }