configure.ac: add libusb/libusbx support (for xpp)
[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 "hexfile.h"
29 #include "pic_loader.h"
30 #include <debug.h>
31 #include <xusb.h>
32
33 #define DBG_MASK        0x03
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_device *astribank, 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(astribank != 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 = xusb_send(astribank->xusb, buf, pack_len, TIMEOUT);
94         if(ret < 0) {
95                 ERR("xusb_send failed: %d\n", ret);
96                 return ret;
97         }
98         DBG("xusb_send: Written %d bytes\n", ret);
99         if (recv_answer) {
100                 ret = xusb_recv(astribank->xusb, 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_device *astribank, 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
186         v = (v[0]) ? v : "Unknown";
187         assert(astribank != NULL);
188         assert(hexdata != NULL);
189         devstr = xusb_devpath(astribank->xusb);
190         if(!astribank->is_usb2) {
191                 ERR("%s: Skip PIC burning (not USB2)\n", devstr);
192                 return 0;
193         }
194         INFO("%s [%s]: Loading PIC Firmware: %s (version %s)\n",
195                 devstr,
196                 xusb_serial(astribank->xusb),
197                 hexdata->fname,
198                 hexdata->version_info);
199         basename = pic_basename(hexdata->fname, &card_type);
200         if(!basename) {
201                 ERR("%s: Bad PIC filename '%s'. Abort.\n", devstr, hexdata->fname);
202                 return 0;
203         }
204         DBG("basename=%s card_type=%d maxlines=%d\n",
205                 basename, card_type, hexdata->maxlines);
206         /*
207          * Try to read extra left-overs from USB controller
208          */
209         for(i = 2; i; i--) {
210                 char    buf[PACKET_SIZE];
211
212                 if(xusb_recv(astribank->xusb, buf, sizeof(buf), 1) <= 0)
213                         break;
214         }
215         if((ret = send_picline(astribank, card_type, PIC_START_FLAG, 0, NULL, 0)) != 0) {
216                 perror("Failed sending start hexline");
217                 return 0;
218         }
219         for(i = 0; i < hexdata->maxlines; i++) { 
220                 struct hexline  *hexline;
221                 unsigned int    len;
222
223                 hexline = hexdata->lines[i];
224                 if(!hexline) {
225                         ERR("%s: hexdata finished early (line %d)", devstr, i);
226                         return 0;
227                 }
228                 if(hexline->d.content.header.tt == TT_DATA) {
229                         len = hexline->d.content.header.ll;     /* don't send checksum */
230                         if(len != 3) {
231                                 ERR("%s: Bad line len %d\n", devstr, len);
232                                 return 0;
233                         }
234                         data = hexline->d.content.tt_data.data;
235                         check_sum ^= data[0] ^ data[1] ^ data[2];
236                         ret = send_picline(astribank, card_type, PIC_DATA_FLAG,
237                                         hexline->d.content.header.offset, data, len);
238                         if(ret) {
239                                 perror("Failed sending data hexline");
240                                 return 0;
241                         }
242                 } else if(hexline->d.content.header.tt == TT_EOF) {
243                         break;
244                 } else {
245                         ERR("%s: Unexpected TT = %d in line %d\n",
246                                         devstr, hexline->d.content.header.tt, i);
247                         return 0;
248                 }
249         }
250         if((ret = send_picline(astribank, card_type, PIC_END_FLAG, 0, &check_sum, 1)) != 0) {
251                 perror("Failed sending end hexline");
252                 return 0;
253         }
254         DBG("Finished...\n");
255         return 1;
256 }
257
258 int load_pic(struct astribank_device *astribank, int numfiles, char *filelist[])
259 {
260         int             i;
261         const char      *devstr;
262
263         devstr = xusb_devpath(astribank->xusb);
264         DBG("%s: Loading %d PIC files...\n", devstr, numfiles);
265         for(i = 0; i < numfiles; i++) {
266                 struct hexdata  *picdata;
267                 const char      *curr = filelist[i];
268
269                 DBG("%s\n", curr);
270                 if((picdata = parse_hexfile(curr, MAX_HEX_LINES)) == NULL) {
271                         perror(curr);
272                         return -errno;
273                 }
274                 if(!pic_burn(astribank, picdata)) {
275                         ERR("%s: PIC %s burning failed\n", devstr, curr);
276                         return -ENODEV;
277                 }
278                 free_hexdata(picdata);
279         }
280         if((i = send_picline(astribank, 0, PIC_ENDS_FLAG, 0, NULL, 0)) != 0) {
281                 ERR("%s: PIC end burning failed\n", devstr);
282                 return -ENODEV;
283         }
284         return 0;
285 }