9bab8677b3e431b96a35f628aad2ca42df49aa0b
[dahdi/tools.git] / xpp / mpptalk.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 <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <assert.h>
27 #include <errno.h>
28 #include <arpa/inet.h>
29 #include "hexfile.h"
30 #include "astribank_usb.h"
31 #include "mpp.h"
32 #include "mpptalk.h"
33 #include <debug.h>
34 #include <xusb.h>
35 #include <xtalk.h>
36
37 static const char rcsid[] = "$Id$";
38
39 #define DBG_MASK        0x02
40
41 const char *ack_status_msg(uint8_t status)
42 {
43         const static char       *msgs[] = {
44                 [STAT_OK] = "Acknowledges previous command",
45                 [STAT_FAIL] = "Last command failed",
46                 [STAT_RESET_FAIL] = "Reset failed",
47                 [STAT_NODEST] = "No destination is selected",
48                 [STAT_MISMATCH] = "Data mismatch",
49                 [STAT_NOACCESS] = "No access",
50                 [STAT_BAD_CMD] = "Bad command",
51                 [STAT_TOO_SHORT] = "Packet is too short",
52                 [STAT_ERROFFS] = "Offset error",
53                 [STAT_NOCODE] = "Source was not burned before",
54                 [STAT_NO_LEEPROM] = "Large EEPROM was not found",
55                 [STAT_NO_EEPROM] = "No EEPROM was found",
56                 [STAT_WRITE_FAIL] = "Writing to device failed",
57                 [STAT_FPGA_ERR] = "FPGA error",
58                 [STAT_KEY_ERR] = "Bad Capabilities Key",
59                 [STAT_NOCAPS_ERR]       = "No matching capability",
60                 [STAT_NOPWR_ERR]        = "No power on USB connector",
61                 [STAT_CAPS_FPGA_ERR]    = "Setting of the capabilities while FPGA is loaded",
62         };
63         if(status > sizeof(msgs)/sizeof(msgs[0]))
64                 return "ERROR CODE TOO LARGE";
65         if(!msgs[status])
66                 return "MISSING ERROR CODE";
67         return msgs[status];
68 }
69
70 const char *eeprom_type2str(int et)
71 {
72         const static char       *msgs[] = {
73                 [EEPROM_TYPE_NONE]      = "NONE",
74                 [EEPROM_TYPE_SMALL]     = "SMALL",
75                 [EEPROM_TYPE_LARGE]     = "LARGE",
76                 [EEPROM_TYPE_UNUSED]    = "UNUSED",
77         };
78         if(et > sizeof(msgs)/sizeof(msgs[0]))
79                 return NULL;
80         return msgs[et];
81 };
82
83 const char *dev_dest2str(int dest)
84 {
85         const static char       *msgs[] = {
86                 [DEST_NONE]     = "NONE",
87                 [DEST_FPGA]     = "FPGA",
88                 [DEST_EEPROM]   = "EEPROM",
89         };
90         if(dest > sizeof(msgs)/sizeof(msgs[0]))
91                 return NULL;
92         return msgs[dest];
93 };
94
95 union XTALK_PDATA(MPP) {
96                 MEMBER(MPP, STATUS_GET);
97                 MEMBER(MPP, STATUS_GET_REPLY);
98                 MEMBER(MPP, EEPROM_SET);
99                 MEMBER(MPP, CAPS_GET);
100                 MEMBER(MPP, CAPS_GET_REPLY);
101                 MEMBER(MPP, CAPS_SET);
102                 MEMBER(MPP, EXTRAINFO_GET);
103                 MEMBER(MPP, EXTRAINFO_GET_REPLY);
104                 MEMBER(MPP, EXTRAINFO_SET);
105                 MEMBER(MPP, RENUM);
106                 MEMBER(MPP, EEPROM_BLK_RD);
107                 MEMBER(MPP, EEPROM_BLK_RD_REPLY);
108                 MEMBER(MPP, DEV_SEND_SEG);
109                 MEMBER(MPP, DEV_SEND_START);
110                 MEMBER(MPP, DEV_SEND_END);
111                 MEMBER(MPP, RESET);
112                 MEMBER(MPP, HALF_RESET);
113                 MEMBER(MPP, SER_SEND);
114                 MEMBER(MPP, SER_RECV);
115                 /* Twinstar */
116                 MEMBER(MPP, TWS_WD_MODE_SET);
117                 MEMBER(MPP, TWS_WD_MODE_GET);
118                 MEMBER(MPP, TWS_WD_MODE_GET_REPLY);
119                 MEMBER(MPP, TWS_PORT_SET);
120                 MEMBER(MPP, TWS_PORT_GET);
121                 MEMBER(MPP, TWS_PORT_GET_REPLY);
122                 MEMBER(MPP, TWS_PWR_GET);
123                 MEMBER(MPP, TWS_PWR_GET_REPLY);
124 } PACKED members;
125
126 struct xtalk_protocol   astribank_proto = {
127         .name   = "ABNK",
128         .proto_version = 0x14,
129         .commands = {
130                 CMD_SEND(MPP, STATUS_GET),
131                 CMD_RECV(MPP, STATUS_GET_REPLY, NULL),
132                 CMD_SEND(MPP, EEPROM_SET),
133                 CMD_SEND(MPP, CAPS_GET),
134                 CMD_RECV(MPP, CAPS_GET_REPLY, NULL),
135                 CMD_SEND(MPP, CAPS_SET),
136                 CMD_SEND(MPP, EXTRAINFO_GET),
137                 CMD_RECV(MPP, EXTRAINFO_GET_REPLY, NULL),
138                 CMD_SEND(MPP, EXTRAINFO_SET),
139                 CMD_SEND(MPP, RENUM),
140                 CMD_SEND(MPP, EEPROM_BLK_RD),
141                 CMD_RECV(MPP, EEPROM_BLK_RD_REPLY, NULL),
142                 CMD_SEND(MPP, DEV_SEND_SEG),
143                 CMD_SEND(MPP, DEV_SEND_START),
144                 CMD_SEND(MPP, DEV_SEND_END),
145                 CMD_SEND(MPP, RESET),
146                 CMD_SEND(MPP, HALF_RESET),
147                 CMD_SEND(MPP, SER_SEND),
148                 CMD_SEND(MPP, SER_RECV),
149                 /* Twinstar */
150                 CMD_SEND(MPP, TWS_WD_MODE_SET),
151                 CMD_SEND(MPP, TWS_WD_MODE_GET),
152                 CMD_RECV(MPP, TWS_WD_MODE_GET_REPLY, NULL),
153                 CMD_SEND(MPP, TWS_PORT_SET),
154                 CMD_SEND(MPP, TWS_PORT_GET),
155                 CMD_RECV(MPP, TWS_PORT_GET_REPLY, NULL),
156                 CMD_SEND(MPP, TWS_PWR_GET),
157                 CMD_RECV(MPP, TWS_PWR_GET_REPLY, NULL),
158         },
159         .ack_statuses = {
160         }
161 };
162
163 struct cmd_queue {
164         struct cmd_queue        *next;
165         struct cmd_queue        *prev;
166         struct xtalk_command    *cmd;
167 };
168
169 static struct cmd_queue output_queue = {
170         .next = &output_queue,
171         .prev = &output_queue,
172         .cmd = NULL
173         };
174
175 void dump_command(struct xtalk_command *cmd)
176 {
177         uint16_t        len;
178         int             i;
179
180         len = cmd->header.len;
181         if(len < sizeof(struct mpp_header)) {
182                 ERR("Command too short (%d)\n", len);
183                 return;
184         }
185         INFO("DUMP: OP=0x%X len=%d seq=%d\n",
186                 cmd->header.op, cmd->header.len, cmd->header.seq);
187         for(i = 0; i < len - sizeof(struct mpp_header); i++) {
188                 INFO("  %2d. 0x%X\n", i, cmd->alt.raw_data[i]);
189         }
190 }
191
192
193 static int set_ihex_version(char *dst, const char *src)
194 {
195         memcpy(dst, src, VERSION_LEN);
196         return 0;
197 }
198
199 /*
200  * Protocol Commands
201  */
202
203 int mpp_status_query(struct astribank_device *astribank)
204 {
205         struct xtalk_command    *cmd;
206         struct xtalk_command    *reply;
207         struct xtalk_device     *xtalk_dev;
208         int                     ret;
209
210         DBG("\n");
211         assert(astribank != NULL);
212         xtalk_dev = astribank->xtalk_dev;
213         if((cmd = new_command(xtalk_dev, MPP_STATUS_GET, 0)) == NULL) {
214                 ERR("new_command failed\n");
215                 return -ENOMEM;
216         }
217         ret = process_command(xtalk_dev, cmd, &reply);
218         if(ret < 0) {
219                 ERR("process_command failed: %d\n", ret);
220                 return ret;
221         }
222         astribank->eeprom_type = 0x3 & (CMD_FIELD(reply, MPP, STATUS_GET_REPLY, i2cs_data) >> 3);
223         astribank->status = CMD_FIELD(reply, MPP, STATUS_GET_REPLY, status);
224         astribank->fw_versions = CMD_FIELD(reply, MPP, STATUS_GET_REPLY, fw_versions);
225         DBG("EEPROM TYPE: %02x\n", astribank->eeprom_type);
226         DBG("FPGA Firmware: %s\n", (astribank->status & 0x1) ? "Loaded" : "Empty");
227         DBG("Firmware Versions: USB='%s' FPGA='%s' EEPROM='%s'\n",
228                 astribank->fw_versions.usb,
229                 astribank->fw_versions.fpga,
230                 astribank->fw_versions.eeprom);
231         free_command(reply);
232         return ret;
233 }
234
235 int mpp_eeprom_set(struct astribank_device *astribank, const struct eeprom_table *et)
236 {
237         struct xtalk_command    *cmd;
238         struct xtalk_command    *reply;
239         struct xtalk_device     *xtalk_dev;
240         int                     ret;
241
242         DBG("\n");
243         assert(astribank != NULL);
244         xtalk_dev = astribank->xtalk_dev;
245         if((cmd = new_command(xtalk_dev, MPP_EEPROM_SET, 0)) == NULL) {
246                 ERR("new_command failed\n");
247                 return -ENOMEM;
248         }
249         memcpy(&CMD_FIELD(cmd, MPP, EEPROM_SET, data), et, sizeof(*et));
250         ret = process_command(xtalk_dev, cmd, &reply);
251         if(ret < 0) {
252                 ERR("process_command failed: %d\n", ret);
253                 return ret;
254         }
255         free_command(reply);
256         return 0;
257 }
258
259 int mpp_renumerate(struct astribank_device *astribank)
260 {
261         struct xtalk_command    *cmd;
262         struct xtalk_device     *xtalk_dev;
263         int                     ret;
264
265         DBG("\n");
266         assert(astribank != NULL);
267         xtalk_dev = astribank->xtalk_dev;
268         if((cmd = new_command(xtalk_dev, MPP_RENUM, 0)) == NULL) {
269                 ERR("new_command failed\n");
270                 return -ENOMEM;
271         }
272         ret = process_command(xtalk_dev, cmd, NULL);
273         if(ret < 0) {
274                 ERR("process_command failed: %d\n", ret);
275                 return ret;
276         }
277         return 0;
278 }
279
280 int mpp_caps_get(struct astribank_device *astribank,
281         struct eeprom_table *eeprom_table,
282         struct capabilities *capabilities,
283         struct capkey *key)
284 {
285         struct xtalk_command    *cmd;
286         struct xtalk_command    *reply;
287         struct xtalk_device     *xtalk_dev;
288         int                     ret;
289
290         DBG("\n");
291         assert(astribank != NULL);
292         xtalk_dev = astribank->xtalk_dev;
293         if((cmd = new_command(xtalk_dev, MPP_CAPS_GET, 0)) == NULL) {
294                 ERR("new_command failed\n");
295                 return -ENOMEM;
296         }
297         ret = process_command(xtalk_dev, cmd, &reply);
298         if(ret < 0) {
299                 ERR("process_command failed: %d\n", ret);
300                 return ret;
301         }
302         assert(reply->header.op == MPP_CAPS_GET_REPLY);
303         if(eeprom_table) {
304                 memcpy(eeprom_table, (void *)&CMD_FIELD(reply, MPP, CAPS_GET_REPLY, data), sizeof(*eeprom_table));
305         }
306         if(capabilities) {
307                 const struct capabilities       *cap = &CMD_FIELD(reply, MPP, CAPS_GET_REPLY, capabilities);
308
309                 memcpy(capabilities, cap, sizeof(*capabilities));
310         }
311         if(key) {
312                 const struct capkey     *k = &CMD_FIELD(reply, MPP, CAPS_GET_REPLY, key);
313
314                 memcpy(key, k, sizeof(*key));
315         }
316         free_command(reply);
317         return 0;
318 }
319
320 int mpp_caps_set(struct astribank_device *astribank,
321         const struct eeprom_table *eeprom_table,
322         const struct capabilities *capabilities,
323         const struct capkey *key)
324 {
325         struct xtalk_command    *cmd;
326         struct xtalk_command    *reply;
327         struct xtalk_device     *xtalk_dev;
328         int                     ret;
329
330         DBG("\n");
331         assert(astribank != NULL);
332         xtalk_dev = astribank->xtalk_dev;
333         if((cmd = new_command(xtalk_dev, MPP_CAPS_SET, 0)) == NULL) {
334                 ERR("new_command failed\n");
335                 return -ENOMEM;
336         }
337         memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, data), eeprom_table, sizeof(*eeprom_table));
338         memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, capabilities), capabilities, sizeof(*capabilities));
339         memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, key), key, sizeof(*key));
340         ret = process_command(xtalk_dev, cmd, &reply);
341         if(ret < 0) {
342                 ERR("process_command failed: %d\n", ret);
343                 return ret;
344         }
345         free_command(reply);
346         return 0;
347 }
348
349 int mpp_extrainfo_get(struct astribank_device *astribank, struct extrainfo *info)
350 {
351         struct xtalk_command    *cmd;
352         struct xtalk_command    *reply;
353         struct xtalk_device     *xtalk_dev;
354         int                     ret;
355
356         DBG("\n");
357         assert(astribank != NULL);
358         xtalk_dev = astribank->xtalk_dev;
359         if((cmd = new_command(xtalk_dev, MPP_EXTRAINFO_GET, 0)) == NULL) {
360                 ERR("new_command failed\n");
361                 return -ENOMEM;
362         }
363         ret = process_command(xtalk_dev, cmd, &reply);
364         if(ret < 0) {
365                 ERR("process_command failed: %d\n", ret);
366                 return ret;
367         }
368         assert(reply->header.op == MPP_EXTRAINFO_GET_REPLY);
369         if(info) {
370                 int i;
371
372                 memcpy(info, (void *)&CMD_FIELD(reply, MPP, EXTRAINFO_GET_REPLY, info), sizeof(*info));
373                 /*
374                  * clean non-printing characters
375                  */
376                 for (i = sizeof(*info) - 1; i >= 0; i--) {
377                         if (info->text[i] != (char)0xFF)
378                                 break;
379                         info->text[i] = '\0';
380                 }
381         }
382         free_command(reply);
383         return 0;
384 }
385
386 int mpp_extrainfo_set(struct astribank_device *astribank, const struct extrainfo *info)
387 {
388         struct xtalk_command    *cmd;
389         struct xtalk_command    *reply;
390         struct xtalk_device     *xtalk_dev;
391         int                     ret;
392
393         DBG("\n");
394         assert(astribank != NULL);
395         xtalk_dev = astribank->xtalk_dev;
396         if((cmd = new_command(xtalk_dev, MPP_EXTRAINFO_SET, 0)) == NULL) {
397                 ERR("new_command failed\n");
398                 return -ENOMEM;
399         }
400         memcpy(&CMD_FIELD(cmd, MPP, EXTRAINFO_SET, info), info, sizeof(*info));
401         ret = process_command(xtalk_dev, cmd, &reply);
402         if(ret < 0) {
403                 ERR("process_command failed: %d\n", ret);
404                 return ret;
405         }
406         free_command(reply);
407         return 0;
408 }
409
410 int mpp_eeprom_blk_rd(struct astribank_device *astribank, uint8_t *buf, uint16_t offset, uint16_t len)
411 {
412         struct xtalk_command    *cmd;
413         struct xtalk_command    *reply;
414         struct xtalk_device     *xtalk_dev;
415         int                     ret;
416         int                     size;
417
418         DBG("len = %d, offset = %d\n", len, offset);
419         assert(astribank != NULL);
420         xtalk_dev = astribank->xtalk_dev;
421         if((cmd = new_command(xtalk_dev, MPP_EEPROM_BLK_RD, 0)) == NULL) {
422                 ERR("new_command failed\n");
423                 return -ENOMEM;
424         }
425         CMD_FIELD(cmd, MPP, EEPROM_BLK_RD, len) = len;
426         CMD_FIELD(cmd, MPP, EEPROM_BLK_RD, offset) = offset;
427         ret = process_command(xtalk_dev, cmd, &reply);
428         if(ret < 0) {
429                 ERR("process_command failed: %d\n", ret);
430                 size = ret;
431                 goto out;
432         }
433         size = reply->header.len - sizeof(struct mpp_header) - sizeof(XTALK_STRUCT(MPP, EEPROM_BLK_RD_REPLY));
434         INFO("size=%d offset=0x%X\n", size, CMD_FIELD(reply, MPP, EEPROM_BLK_RD_REPLY, offset));
435         dump_packet(LOG_DEBUG, DBG_MASK, "BLK_RD", (char *)reply, ret);
436         if(size > len) {
437                 ERR("Truncating reply (was %d, now %d)\n", size, len);
438                 size = len;
439         }
440         memcpy(buf, CMD_FIELD(reply, MPP, EEPROM_BLK_RD_REPLY, data), size);
441 out:
442         free_command(reply);
443         return size;
444 }
445
446 int mpp_send_start(struct astribank_device *astribank, int dest, const char *ihex_version)
447 {
448         struct xtalk_command    *cmd;
449         struct xtalk_command    *reply = NULL;
450         struct xtalk_device     *xtalk_dev;
451         int                     ret = 0;
452
453         DBG("dest = %s ihex_version = '%s'\n", dev_dest2str(dest), ihex_version);
454         assert(astribank != NULL);
455         xtalk_dev = astribank->xtalk_dev;
456         if((cmd = new_command(xtalk_dev, MPP_DEV_SEND_START, 0)) == NULL) {
457                 ERR("new_command failed\n");
458                 ret = -ENOMEM;
459                 goto out;
460         }
461         CMD_FIELD(cmd, MPP, DEV_SEND_START, dest) = dest;
462         set_ihex_version(CMD_FIELD(cmd, MPP, DEV_SEND_START, ihex_version), ihex_version);
463         ret = process_command(xtalk_dev, cmd, &reply);
464         if(ret < 0) {
465                 ERR("process_command failed: %d\n", ret);
466                 goto out;
467         }
468 out:
469         if(reply)
470                 free_command(reply);
471         astribank->burn_state = (ret == 0)
472                 ? BURN_STATE_STARTED
473                 : BURN_STATE_FAILED;
474         return ret;
475 }
476
477 int mpp_send_end(struct astribank_device *astribank)
478 {
479         struct xtalk_command    *cmd;
480         struct xtalk_command    *reply = NULL;
481         struct xtalk_device     *xtalk_dev;
482         int                     ret = 0;
483
484         DBG("\n");
485         assert(astribank != NULL);
486         xtalk_dev = astribank->xtalk_dev;
487         if((cmd = new_command(xtalk_dev, MPP_DEV_SEND_END, 0)) == NULL) {
488                 ERR("new_command failed\n");
489                 ret = -ENOMEM;
490                 goto out;
491         }
492         ret = process_command(xtalk_dev, cmd, &reply);
493         if(ret < 0) {
494                 ERR("process_command failed: %d\n", ret);
495                 goto out;
496         }
497 out:
498         if(reply)
499                 free_command(reply);
500         astribank->burn_state = (ret == 0)
501                 ? BURN_STATE_ENDED
502                 : BURN_STATE_FAILED;
503         return ret;
504 }
505
506 int mpp_send_seg(struct astribank_device *astribank, const uint8_t *data, uint16_t offset, uint16_t len)
507 {
508         struct xtalk_command    *cmd;
509         struct xtalk_command    *reply;
510         struct xtalk_device     *xtalk_dev;
511         int                     ret;
512
513         assert(astribank != NULL);
514         xtalk_dev = astribank->xtalk_dev;
515         if(astribank->burn_state != BURN_STATE_STARTED) {
516                 ERR("Tried to send a segment while burn_state=%d\n",
517                                 astribank->burn_state);
518                 return -EINVAL;
519         }
520         DBG("len = %d, offset = %d (0x%02X, 0x%02X)\n", len, offset, *data, *(data + 1));
521         if((cmd = new_command(xtalk_dev, MPP_DEV_SEND_SEG, len)) == NULL) {
522                 ERR("new_command failed\n");
523                 return -ENOMEM;
524         }
525         CMD_FIELD(cmd, MPP, DEV_SEND_SEG, offset) = offset;
526         memcpy(CMD_FIELD(cmd, MPP, DEV_SEND_SEG, data), data, len);
527 #if 0
528         {
529                 FILE                    *fp;
530                 if((fp = fopen("seg_data.bin", "a")) == NULL) {
531                         perror("seg_data.bin");
532                         exit(1);
533                 }
534                 if(fwrite(CMD_FIELD(cmd, MPP, DEV_SEND_SEG, data), len, 1, fp) != 1) {
535                         perror("fwrite");
536                         exit(1);
537                 }
538                 fclose(fp);
539         }
540 #endif
541         ret = process_command(xtalk_dev, cmd, &reply);
542         if(ret < 0) {
543                 ERR("process_command failed: %d\n", ret);
544                 return ret;
545         }
546         free_command(reply);
547         return 0;
548 }
549
550 int mpp_reset(struct astribank_device *astribank, int full_reset)
551 {
552         struct xtalk_command    *cmd;
553         struct xtalk_device     *xtalk_dev;
554         int                     ret;
555         int                     op = (full_reset) ? MPP_RESET: MPP_HALF_RESET;
556
557         DBG("full = %s\n", (full_reset) ? "YES" : "NO");
558         assert(astribank != NULL);
559         xtalk_dev = astribank->xtalk_dev;
560         if((cmd = new_command(xtalk_dev, op, 0)) == NULL) {
561                 ERR("new_command failed\n");
562                 return -ENOMEM;
563         }
564         ret = process_command(xtalk_dev, cmd, NULL);
565         if(ret < 0) {
566                 ERR("process_command failed: %d\n", ret);
567                 return ret;
568         }
569         return 0;
570 }
571
572 int mpp_serial_cmd(struct astribank_device *astribank, const uint8_t *in, uint8_t *out, uint16_t len)
573 {
574         struct xtalk_command    *cmd;
575         struct xtalk_command    *reply;
576         struct xtalk_device     *xtalk_dev;
577         int                     ret;
578         uint8_t                 *data;
579
580         DBG("len=%d\n", len);
581         assert(astribank != NULL);
582         xtalk_dev = astribank->xtalk_dev;
583         if((cmd = new_command(xtalk_dev, MPP_SER_SEND, len)) == NULL) {
584                 ERR("new_command failed\n");
585                 return -ENOMEM;
586         }
587         data = CMD_FIELD(cmd, MPP, SER_SEND, data);
588         memcpy(data, in, len);
589         ret = process_command(xtalk_dev, cmd, &reply);
590         if(ret < 0) {
591                 ERR("process_command failed: %d\n", ret);
592                 return ret;
593         }
594         assert(reply->header.op == MPP_SER_RECV);
595         data = CMD_FIELD(reply, MPP, SER_RECV, data);
596         memcpy(out, data, len);
597         free_command(reply);
598         return 0;
599 }
600
601 int mpps_card_info(struct astribank_device *astribank, int unit, uint8_t *card_type, uint8_t *card_status)
602 {
603         /*
604          * Serial commands must have equal send/receive size
605          */
606         struct card_info_command {
607                 uint8_t ser_op;
608                 uint8_t addr;
609                 uint8_t card_full_type; /* (type << 4 | subtype) */
610                 uint8_t card_status;    /* BIT(0) - PIC burned */
611         } PACKED;
612         struct card_info_command ci_send;
613         struct card_info_command ci_recv;
614         int ret;
615
616         memset(&ci_send, 0, sizeof(ci_send));
617         memset(&ci_recv, 0, sizeof(ci_recv));
618         ci_send.ser_op = SER_CARD_INFO_GET;
619         ci_send.addr = (unit << 4);     /* low nibble is subunit */
620         ret = mpp_serial_cmd(astribank,
621                 (uint8_t *)&ci_send,
622                 (uint8_t *)&ci_recv,
623                 sizeof(struct card_info_command));
624         if (ret < 0)
625                 return ret;
626         *card_type = ci_recv.card_full_type;
627         *card_status = ci_recv.card_status;
628         return 0;
629 }
630
631 int mpps_stat(struct astribank_device *astribank, int unit, uint8_t *fpga_configuration, uint8_t *status)
632 {
633         /*
634          * Serial commands must have equal send/receive size
635          */
636         struct fpga_stat_command {
637                 uint8_t ser_op;
638                 uint8_t fpga_configuration;
639                 uint8_t status; /* BIT(0) - Watchdog timer status */
640         } PACKED;
641         struct fpga_stat_command fs_send;
642         struct fpga_stat_command fs_recv;
643         int ret;
644
645         memset(&fs_send, 0, sizeof(fs_send));
646         memset(&fs_recv, 0, sizeof(fs_recv));
647         fs_send.ser_op = SER_STAT_GET;
648         ret = mpp_serial_cmd(astribank,
649                 (uint8_t *)&fs_send,
650                 (uint8_t *)&fs_recv,
651                 sizeof(struct fpga_stat_command));
652         if(ret < 0)
653                 return ret;
654         *fpga_configuration = fs_recv.fpga_configuration;
655         *status = fs_recv.status;
656         return 0;
657 }
658
659 int mpp_tws_watchdog(struct astribank_device *astribank)
660 {
661         struct xtalk_command    *cmd;
662         struct xtalk_command    *reply;
663         struct xtalk_device     *xtalk_dev;
664         int                     ret;
665
666         DBG("\n");
667         assert(astribank != NULL);
668         xtalk_dev = astribank->xtalk_dev;
669         if((cmd = new_command(xtalk_dev, MPP_TWS_WD_MODE_GET, 0)) == NULL) {
670                 ERR("new_command failed\n");
671                 return -ENOMEM;
672         }
673         ret = process_command(xtalk_dev, cmd, &reply);
674         if(ret < 0) {
675                 ERR("process_command failed: %d\n", ret);
676                 return ret;
677         }
678         ret = CMD_FIELD(reply, MPP, TWS_WD_MODE_GET_REPLY, wd_active);
679         DBG("wd_active=0x%X\n", ret);
680         free_command(reply);
681         return ret == 1;
682 }
683
684 int mpp_tws_setwatchdog(struct astribank_device *astribank, int yes)
685 {
686         struct xtalk_command    *cmd;
687         struct xtalk_command    *reply;
688         struct xtalk_device     *xtalk_dev;
689         int                     ret;
690
691         DBG("%s\n", (yes) ? "YES" : "NO");
692         assert(astribank != NULL);
693         xtalk_dev = astribank->xtalk_dev;
694         if((cmd = new_command(xtalk_dev, MPP_TWS_WD_MODE_SET, 0)) == NULL) {
695                 ERR("new_command failed\n");
696                 return -ENOMEM;
697         }
698         CMD_FIELD(cmd, MPP, TWS_WD_MODE_SET, wd_active) = (yes) ? 1 : 0;
699         ret = process_command(xtalk_dev, cmd, &reply);
700         if(ret < 0) {
701                 ERR("process_command failed: %d\n", ret);
702                 return ret;
703         }
704         free_command(reply);
705         return 0;
706 }
707
708 int mpp_tws_powerstate(struct astribank_device *astribank)
709 {
710         struct xtalk_command    *cmd;
711         struct xtalk_command    *reply;
712         struct xtalk_device     *xtalk_dev;
713         int                     ret;
714
715         DBG("\n");
716         assert(astribank != NULL);
717         xtalk_dev = astribank->xtalk_dev;
718         if((cmd = new_command(xtalk_dev, MPP_TWS_PWR_GET, 0)) == NULL) {
719                 ERR("new_command failed\n");
720                 return -ENOMEM;
721         }
722         ret = process_command(xtalk_dev, cmd, &reply);
723         if(ret < 0) {
724                 ERR("process_command failed: %d\n", ret);
725                 return ret;
726         }
727         ret = CMD_FIELD(reply, MPP, TWS_PWR_GET_REPLY, power);
728         DBG("power=0x%X\n", ret);
729         free_command(reply);
730         return ret;
731 }
732
733 int mpp_tws_portnum(struct astribank_device *astribank)
734 {
735         struct xtalk_command    *cmd;
736         struct xtalk_command    *reply;
737         struct xtalk_device     *xtalk_dev;
738         int                     ret;
739
740         DBG("\n");
741         assert(astribank != NULL);
742         xtalk_dev = astribank->xtalk_dev;
743         if((cmd = new_command(xtalk_dev, MPP_TWS_PORT_GET, 0)) == NULL) {
744                 ERR("new_command failed\n");
745                 return -ENOMEM;
746         }
747         ret = process_command(xtalk_dev, cmd, &reply);
748         if(ret < 0) {
749                 ERR("process_command failed: %d\n", ret);
750                 return ret;
751         }
752         ret = CMD_FIELD(reply, MPP, TWS_PORT_GET_REPLY, portnum);
753         DBG("portnum=0x%X\n", ret);
754         free_command(reply);
755         return ret;
756 }
757
758 int mpp_tws_setportnum(struct astribank_device *astribank, uint8_t portnum)
759 {
760         struct xtalk_command    *cmd;
761         struct xtalk_device     *xtalk_dev;
762         int                     ret;
763
764         DBG("\n");
765         assert(astribank != NULL);
766         xtalk_dev = astribank->xtalk_dev;
767         if(portnum >= 2) {
768                 ERR("Invalid portnum (%d)\n", portnum);
769                 return -EINVAL;
770         }
771         if((cmd = new_command(xtalk_dev, MPP_TWS_PORT_SET, 0)) == NULL) {
772                 ERR("new_command failed\n");
773                 return -ENOMEM;
774         }
775         CMD_FIELD(cmd, MPP, TWS_PORT_SET, portnum) = portnum;
776         ret = process_command(xtalk_dev, cmd, NULL);
777         if(ret < 0) {
778                 ERR("process_command failed: %d\n", ret);
779                 return ret;
780         }
781         return 0;
782 }
783
784 /* Adapters for xusb ops */
785 static inline int xusb_close_func(void *priv)
786 {
787         return xusb_close((struct xusb *)priv);
788 }
789
790 static inline int xusb_send_func(void *priv, void *data, size_t len, int timeout)
791 {
792         return xusb_send((struct xusb *)priv, data, len, timeout);
793 }
794
795 static inline int xusb_recv_func(void *priv, void *data, size_t maxlen, int timeout)
796 {
797         return xusb_recv((struct xusb *)priv, data, maxlen, timeout);
798 }
799
800
801 static struct xtalk_ops xusb_ops = {
802         .send_func      = xusb_send_func,
803         .recv_func      = xusb_recv_func,
804         .close_func     = xusb_close_func,
805 };
806
807 /*
808  * Wrappers
809  */
810
811 struct astribank_device *mpp_init(const char devpath[], int iface_num)
812 {
813         struct astribank_device *astribank = NULL;
814         struct xtalk_device     *xtalk_dev = NULL;
815         struct xusb             *xusb = NULL;
816         int                     packet_size;
817         int                     ret;
818
819         DBG("devpath='%s' iface_num=%d\n", devpath, iface_num);
820         if((astribank = astribank_open(devpath, iface_num)) == NULL) {
821                 ERR("Opening astribank failed\n");
822                 goto err;
823         }
824         xusb = astribank->xusb;
825         packet_size = xusb_packet_size(xusb);
826         if((xtalk_dev = xtalk_new(&xusb_ops, packet_size, xusb)) == NULL) {
827                 ERR("Allocating new XTALK device failed\n");
828                 goto err;
829         }
830         astribank->xtalk_dev = xtalk_dev;
831         ret = xtalk_set_protocol(xtalk_dev, &astribank_proto);
832         if(ret < 0) {
833                 ERR("MPP Protocol registration failed: %d\n", ret);
834                 goto err;
835         }
836         ret = xtalk_proto_query(xtalk_dev);
837         if(ret < 0) {
838                 ERR("Protocol handshake failed: %d\n", ret);
839                 goto err;
840         }
841         ret = mpp_status_query(astribank);
842         if(ret < 0) {
843                 ERR("Status query failed: %d\n", ret);
844                 goto err;
845         }
846         return astribank;
847
848 err:
849         if (astribank) {
850                 astribank_close(astribank, 0);
851                 astribank = NULL;
852         }
853         if(xtalk_dev) {
854                 xtalk_delete(xtalk_dev);
855                 xtalk_dev = NULL;
856         }
857         return NULL;
858 }
859
860 void mpp_exit(struct astribank_device *astribank)
861 {
862         DBG("\n");
863         astribank_close(astribank, 0);
864 }
865
866 /*
867  * data structures
868  */
869
870 void show_eeprom(const struct eeprom_table *eprm, FILE *fp)
871 {
872         int     rmajor = (eprm->release >> 8) & 0xFF;
873         int     rminor = eprm->release & 0xFF;;
874         char    buf[BUFSIZ];
875
876         memset(buf, 0, LABEL_SIZE + 1);
877         memcpy(buf, eprm->label, LABEL_SIZE);
878         fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Source", eprm->source);
879         fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Vendor", eprm->vendor);
880         fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Product", eprm->product);
881         fprintf(fp, "EEPROM: %-15s: %d.%d\n", "Release", rmajor, rminor);
882         fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Config", eprm->config_byte);
883         fprintf(fp, "EEPROM: %-15s: '%s'\n", "Label", buf);
884 }
885
886 void show_capabilities(const struct capabilities *capabilities, FILE *fp)
887 {
888         fprintf(fp, "Capabilities: FXS ports: %2d\n", capabilities->ports_fxs);
889         fprintf(fp, "Capabilities: FXO ports: %2d\n", capabilities->ports_fxo);
890         fprintf(fp, "Capabilities: BRI ports: %2d\n", capabilities->ports_bri);
891         fprintf(fp, "Capabilities: PRI ports: %2d\n", capabilities->ports_pri);
892         fprintf(fp, "Capabilities: ECHO ports: %2d\n", capabilities->ports_echo);
893         fprintf(fp, "Capabilities: TwinStar : %s\n",
894                 (CAP_EXTRA_TWINSTAR(capabilities)) ? "Yes" : "No");
895 }
896
897 void show_astribank_status(struct astribank_device *astribank, FILE *fp)
898 {
899         char    version_buf[BUFSIZ];
900         int     is_loaded = STATUS_FPGA_LOADED(astribank->status);
901
902         fprintf(fp, "Astribank: EEPROM      : %s\n",
903                 eeprom_type2str(astribank->eeprom_type));
904         fprintf(fp, "Astribank: FPGA status : %s\n",
905                 is_loaded ? "Loaded" : "Empty");
906         if(is_loaded) {
907                 memset(version_buf, 0, sizeof(version_buf));
908                 memcpy(version_buf, astribank->fw_versions.fpga, VERSION_LEN);
909                 fprintf(fp, "Astribank: FPGA version: %s\n",
910                         version_buf);
911         }
912 }
913
914 void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp)
915 {
916         char    buf[EXTRAINFO_SIZE + 1];
917
918         memcpy(buf, extrainfo->text, EXTRAINFO_SIZE);
919         buf[EXTRAINFO_SIZE] = '\0';     /* assure null termination */
920         fprintf(fp, "Extrainfo:             : '%s'\n", buf);
921 }
922
923 int twinstar_show(struct astribank_device *astribank, FILE *fp)
924 {
925         int     watchdog;
926         int     powerstate;
927         int     portnum;
928         int     i;
929
930         if(!astribank_has_twinstar(astribank)) {
931                 fprintf(fp, "TwinStar: NO\n");
932                 return 0;
933         }
934         if((watchdog = mpp_tws_watchdog(astribank)) < 0) {
935                 ERR("Failed getting TwinStar information\n");
936                 return watchdog;
937         }
938         if((powerstate = mpp_tws_powerstate(astribank)) < 0) {
939                 ERR("Failed getting TwinStar powerstate\n");
940                 return powerstate;
941         }
942         if((portnum = mpp_tws_portnum(astribank)) < 0) {
943                 ERR("Failed getting TwinStar portnum\n");
944                 return portnum;
945         }
946         fprintf(fp, "TwinStar: Connected to : USB-%1d\n", portnum);
947         fprintf(fp, "TwinStar: Watchdog     : %s\n",
948                 (watchdog) ? "on-guard" : "off-guard");
949         for(i = 0; i < 2; i++) {
950                 int     pw = (1 << i) & powerstate;
951
952                 fprintf(fp, "TwinStar: USB-%1d POWER  : %s\n",
953                         i, (pw) ? "ON" : "OFF");
954         }
955         return 0;
956 }