Reported by Trent Creekmore
[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 <xtalk/debug.h>
30 #include <xtalk/proto.h>
31 #include "hexfile.h"
32 #include "mpptalk.h"
33
34 #define DBG_MASK        0x04
35
36 enum eeprom_burn_state {
37         BURN_STATE_NONE         = 0,
38         BURN_STATE_STARTED      = 1,
39         BURN_STATE_ENDED        = 2,
40         BURN_STATE_FAILED       = 3,
41 };
42
43 const char *eeprom_type2str(int et)
44 {
45         const static char       *msgs[] = {
46                 [EEPROM_TYPE_NONE]      = "NONE",
47                 [EEPROM_TYPE_SMALL]     = "SMALL",
48                 [EEPROM_TYPE_LARGE]     = "LARGE",
49                 [EEPROM_TYPE_UNUSED]    = "UNUSED",
50         };
51         if(et > sizeof(msgs)/sizeof(msgs[0]))
52                 return NULL;
53         return msgs[et];
54 };
55
56 const char *dev_dest2str(int dest)
57 {
58         const static char       *msgs[] = {
59                 [DEST_NONE]     = "NONE",
60                 [DEST_FPGA]     = "FPGA",
61                 [DEST_EEPROM]   = "EEPROM",
62         };
63         if(dest > sizeof(msgs)/sizeof(msgs[0]))
64                 return NULL;
65         return msgs[dest];
66 };
67
68 /*
69  * OP Codes:
70  * MSB of op signifies a reply from device
71  */
72 #define MPP_RENUM                       0x0B    /* Trigger USB renumeration */
73 #define MPP_EEPROM_SET                  0x0D
74
75 /* AB capabilities      */
76 #define MPP_CAPS_GET                    0x0E
77 #define MPP_CAPS_GET_REPLY              0x8E
78 #define MPP_CAPS_SET                    0x0F
79
80 #define MPP_DEV_SEND_START              0x05
81 #define MPP_DEV_SEND_SEG                0x07
82 #define MPP_DEV_SEND_END                0x09
83
84 /* Astribank Status     */
85 #define MPP_STATUS_GET                  0x11
86 #define MPP_STATUS_GET_REPLY            0x91
87 #define MPP_STATUS_GET_REPLY_V13        0x91    /* backward compat */
88
89 /* Get extra vendor information */
90 #define MPP_EXTRAINFO_GET               0x13
91 #define MPP_EXTRAINFO_GET_REPLY         0x93
92 #define MPP_EXTRAINFO_SET               0x15    /* Set extra vendor information */
93
94 #define MPP_EEPROM_BLK_RD               0x27
95 #define MPP_EEPROM_BLK_RD_REPLY         0xA7
96
97 #define MPP_SER_SEND                    0x37
98 #define MPP_SER_RECV                    0xB7
99
100 #define MPP_RESET                       0x45    /* Reset both FPGA and USB firmwares */
101 #define MPP_HALF_RESET                  0x47    /* Reset only FPGA firmware */
102
103 /* Twinstar */
104 #define MPP_TWS_WD_MODE_SET             0x31    /* Set watchdog off/on guard    */
105 #define MPP_TWS_WD_MODE_GET             0x32    /* Current watchdog mode        */
106 #define MPP_TWS_WD_MODE_GET_REPLY       0xB2    /* Current watchdog mode        */
107 #define MPP_TWS_PORT_SET                0x34    /* USB-[0/1]                    */
108 #define MPP_TWS_PORT_GET                0x35    /* USB-[0/1]                    */
109 #define MPP_TWS_PORT_GET_REPLY          0xB5    /* USB-[0/1]                    */
110 #define MPP_TWS_PWR_GET                 0x36    /* Power: bits -> USB ports     */
111 #define MPP_TWS_PWR_GET_REPLY           0xB6    /* Power: bits -> USB ports     */
112
113 CMD_DEF(MPP, STATUS_GET);
114
115 CMD_DEF(MPP, STATUS_GET_REPLY,
116         uint8_t i2cs_data;
117
118 #define STATUS_FPGA_LOADED(x)   ((x) & 0x01)
119         uint8_t status;         /* BIT(0) - FPGA is loaded */
120         struct firmware_versions fw_versions;
121         );
122
123
124 CMD_DEF(MPP, EEPROM_SET,
125         struct eeprom_table     data;
126         );
127
128 CMD_DEF(MPP, CAPS_GET);
129
130 CMD_DEF(MPP, CAPS_GET_REPLY,
131         struct eeprom_table     data;
132         struct capabilities     capabilities;
133         struct capkey           key;
134         );
135
136 CMD_DEF(MPP, CAPS_SET,
137         struct eeprom_table     data;
138         struct capabilities     capabilities;
139         struct capkey           key;
140         );
141
142 CMD_DEF(MPP, EXTRAINFO_GET);
143
144 CMD_DEF(MPP, EXTRAINFO_GET_REPLY,
145         struct extrainfo        info;
146         );
147
148 CMD_DEF(MPP, EXTRAINFO_SET,
149         struct extrainfo        info;
150         );
151
152 CMD_DEF(MPP, RENUM);
153
154 CMD_DEF(MPP, EEPROM_BLK_RD,
155         uint16_t        offset;
156         uint16_t        len;
157         );
158
159 CMD_DEF(MPP, EEPROM_BLK_RD_REPLY,
160         uint16_t        offset;
161         uint8_t         data[0];
162         );
163
164 CMD_DEF(MPP, DEV_SEND_START,
165         uint8_t         dest;
166         char            ihex_version[VERSION_LEN];
167         );
168
169 CMD_DEF(MPP, DEV_SEND_END);
170
171 CMD_DEF(MPP, DEV_SEND_SEG,
172         uint16_t        offset;
173         uint8_t         data[0];
174         );
175
176 CMD_DEF(MPP, RESET);
177 CMD_DEF(MPP, HALF_RESET);
178
179 CMD_DEF(MPP, SER_SEND,
180         uint8_t data[0];
181         );
182
183 CMD_DEF(MPP, SER_RECV,
184         uint8_t data[0];
185         );
186
187 CMD_DEF(MPP, TWS_WD_MODE_SET,
188         uint8_t         wd_active;
189         );
190
191 CMD_DEF(MPP, TWS_WD_MODE_GET);
192 CMD_DEF(MPP, TWS_WD_MODE_GET_REPLY,
193         uint8_t         wd_active;
194         );
195
196 CMD_DEF(MPP, TWS_PORT_SET,
197         uint8_t         portnum;
198         );
199
200 CMD_DEF(MPP, TWS_PORT_GET);
201 CMD_DEF(MPP, TWS_PORT_GET_REPLY,
202         uint8_t         portnum;
203         );
204
205 CMD_DEF(MPP, TWS_PWR_GET);
206 CMD_DEF(MPP, TWS_PWR_GET_REPLY,
207         uint8_t         power;
208         );
209
210
211 union XTALK_PDATA(MPP) {
212                 MEMBER(MPP, STATUS_GET);
213                 MEMBER(MPP, STATUS_GET_REPLY);
214                 MEMBER(MPP, EEPROM_SET);
215                 MEMBER(MPP, CAPS_GET);
216                 MEMBER(MPP, CAPS_GET_REPLY);
217                 MEMBER(MPP, CAPS_SET);
218                 MEMBER(MPP, EXTRAINFO_GET);
219                 MEMBER(MPP, EXTRAINFO_GET_REPLY);
220                 MEMBER(MPP, EXTRAINFO_SET);
221                 MEMBER(MPP, RENUM);
222                 MEMBER(MPP, EEPROM_BLK_RD);
223                 MEMBER(MPP, EEPROM_BLK_RD_REPLY);
224                 MEMBER(MPP, DEV_SEND_SEG);
225                 MEMBER(MPP, DEV_SEND_START);
226                 MEMBER(MPP, DEV_SEND_END);
227                 MEMBER(MPP, RESET);
228                 MEMBER(MPP, HALF_RESET);
229                 MEMBER(MPP, SER_SEND);
230                 MEMBER(MPP, SER_RECV);
231                 /* Twinstar */
232                 MEMBER(MPP, TWS_WD_MODE_SET);
233                 MEMBER(MPP, TWS_WD_MODE_GET);
234                 MEMBER(MPP, TWS_WD_MODE_GET_REPLY);
235                 MEMBER(MPP, TWS_PORT_SET);
236                 MEMBER(MPP, TWS_PORT_GET);
237                 MEMBER(MPP, TWS_PORT_GET_REPLY);
238                 MEMBER(MPP, TWS_PWR_GET);
239                 MEMBER(MPP, TWS_PWR_GET_REPLY);
240 } PACKED members;
241
242 /*
243  * Statuses
244  */
245 #define STAT_OK         0x00    /* acknowledges previous command        */
246 #define STAT_FAIL       0x01    /* Last command failed          */
247 #define STAT_RESET_FAIL 0x02    /* reset failed                         */
248 #define STAT_NODEST     0x03    /* No destination is selected           */
249 #define STAT_MISMATCH   0x04    /* Data mismatch                        */
250 #define STAT_NOACCESS   0x05    /* No access                            */
251 #define STAT_BAD_CMD    0x06    /* Bad command                          */
252 #define STAT_TOO_SHORT  0x07    /* Packet is too short                  */
253 #define STAT_ERROFFS    0x08    /* Offset error                         */
254 #define STAT_NOCODE     0x09    /* Source was not burned before         */
255 #define STAT_NO_LEEPROM 0x0A    /* Large EEPROM was not found           */
256 #define STAT_NO_EEPROM  0x0B    /* No EEPROM was found                  */
257 #define STAT_WRITE_FAIL 0x0C    /* Writing to device failed             */
258 #define STAT_FPGA_ERR   0x0D    /* FPGA error                           */
259 #define STAT_KEY_ERR    0x0E    /* Bad Capabilities Key                 */
260 #define STAT_NOCAPS_ERR 0x0F    /* No matching capability               */
261 #define STAT_NOPWR_ERR  0x10    /* No power on USB connector            */
262 #define STAT_CAPS_FPGA_ERR      0x11    /* Setting of the capabilities while FPGA is loaded */
263
264 struct xtalk_protocol   mpp_proto = {
265         .name   = "MPP",
266         .proto_version = 0x14,
267         .commands = {
268                 CMD_SEND(MPP, STATUS_GET),
269                 CMD_RECV(MPP, STATUS_GET_REPLY),
270                 CMD_SEND(MPP, EEPROM_SET),
271                 CMD_SEND(MPP, CAPS_GET),
272                 CMD_RECV(MPP, CAPS_GET_REPLY),
273                 CMD_SEND(MPP, CAPS_SET),
274                 CMD_SEND(MPP, EXTRAINFO_GET),
275                 CMD_RECV(MPP, EXTRAINFO_GET_REPLY),
276                 CMD_SEND(MPP, EXTRAINFO_SET),
277                 CMD_SEND(MPP, RENUM),
278                 CMD_SEND(MPP, EEPROM_BLK_RD),
279                 CMD_RECV(MPP, EEPROM_BLK_RD_REPLY),
280                 CMD_SEND(MPP, DEV_SEND_SEG),
281                 CMD_SEND(MPP, DEV_SEND_START),
282                 CMD_SEND(MPP, DEV_SEND_END),
283                 CMD_SEND(MPP, RESET),
284                 CMD_SEND(MPP, HALF_RESET),
285                 CMD_SEND(MPP, SER_SEND),
286                 CMD_SEND(MPP, SER_RECV),
287                 /* Twinstar */
288                 CMD_SEND(MPP, TWS_WD_MODE_SET),
289                 CMD_SEND(MPP, TWS_WD_MODE_GET),
290                 CMD_RECV(MPP, TWS_WD_MODE_GET_REPLY),
291                 CMD_SEND(MPP, TWS_PORT_SET),
292                 CMD_SEND(MPP, TWS_PORT_GET),
293                 CMD_RECV(MPP, TWS_PORT_GET_REPLY),
294                 CMD_SEND(MPP, TWS_PWR_GET),
295                 CMD_RECV(MPP, TWS_PWR_GET_REPLY),
296         },
297         .ack_statuses = {
298                 [STAT_OK] = "Acknowledges previous command",
299                 [STAT_FAIL] = "Last command failed",
300                 [STAT_RESET_FAIL] = "Reset failed",
301                 [STAT_NODEST] = "No destination is selected",
302                 [STAT_MISMATCH] = "Data mismatch",
303                 [STAT_NOACCESS] = "No access",
304                 [STAT_BAD_CMD] = "Bad command",
305                 [STAT_TOO_SHORT] = "Packet is too short",
306                 [STAT_ERROFFS] = "Offset error",
307                 [STAT_NOCODE] = "Source was not burned before",
308                 [STAT_NO_LEEPROM] = "Large EEPROM was not found",
309                 [STAT_NO_EEPROM] = "No EEPROM was found",
310                 [STAT_WRITE_FAIL] = "Writing to device failed",
311                 [STAT_FPGA_ERR] = "FPGA error",
312                 [STAT_KEY_ERR] = "Bad Capabilities Key",
313                 [STAT_NOCAPS_ERR]       = "No matching capability",
314                 [STAT_NOPWR_ERR]        = "No power on USB connector",
315                 [STAT_CAPS_FPGA_ERR]    = "Setting of the capabilities while FPGA is loaded",
316         }
317 };
318
319 struct mpp_device {
320         struct xtalk_base *xtalk_base;
321         struct xtalk_sync *xtalk_sync;
322         enum eeprom_burn_state burn_state;
323         int eeprom_type;
324         int status;
325         struct firmware_versions fw_versions;
326 };
327
328 struct xusb_iface *xubs_iface_of_mpp(struct mpp_device *mpp)
329 {
330         return xusb_iface_of_xtalk_base(mpp->xtalk_base);
331 }
332
333 struct mpp_device *mpp_new(struct xusb_iface *iface)
334 {
335         struct mpp_device *mpp_dev;
336         int ret;
337
338         mpp_dev = calloc(sizeof(*mpp_dev), 1);
339         if (!mpp_dev) {
340                 ERR("Out of memory\n");
341                 goto err;
342         }
343         mpp_dev->xtalk_base = xtalk_base_new_on_xusb(iface);
344         mpp_dev->xtalk_sync = xtalk_sync_new(mpp_dev->xtalk_base);
345         ret = xtalk_sync_set_protocol(mpp_dev->xtalk_sync, &mpp_proto);
346         if(ret < 0) {
347                 ERR("MPP Protocol registration failed: %d\n", ret);
348                 goto err;
349         }
350         return mpp_dev;
351 err:
352         if (mpp_dev)
353                 free(mpp_dev);
354         return NULL;
355 }
356
357 void mpp_delete(struct mpp_device *dev)
358 {
359         xtalk_sync_delete(dev->xtalk_sync);
360         dev->xtalk_base = NULL;
361         free(dev);
362 }
363
364 struct xtalk_sync *xtalk_of_mpp(const struct mpp_device *dev)
365 {
366         return dev->xtalk_sync;
367 }
368
369 struct cmd_queue {
370         struct cmd_queue        *next;
371         struct cmd_queue        *prev;
372         struct xtalk_command    *cmd;
373 };
374
375 static struct cmd_queue output_queue = {
376         .next = &output_queue,
377         .prev = &output_queue,
378         .cmd = NULL
379         };
380
381 void dump_command(struct xtalk_command *cmd)
382 {
383         uint16_t        len;
384         int             i;
385
386         len = cmd->header.len;
387         if(len < sizeof(struct mpp_header)) {
388                 ERR("Command too short (%d)\n", len);
389                 return;
390         }
391         INFO("DUMP: OP=0x%X len=%d seq=%d\n",
392                 cmd->header.op, cmd->header.len, cmd->header.seq);
393         for(i = 0; i < len - sizeof(struct mpp_header); i++) {
394                 INFO("  %2d. 0x%X\n", i, cmd->alt.raw_data[i]);
395         }
396 }
397
398
399 static int set_ihex_version(char *dst, const char *src)
400 {
401         memcpy(dst, src, VERSION_LEN);
402         return 0;
403 }
404
405 enum eeprom_type mpp_eeprom_type(struct mpp_device *mpp_dev)
406 {
407         return mpp_dev->eeprom_type;
408 }
409
410 /*
411  * Protocol Commands
412  */
413 int mpp_status_query(struct mpp_device *mpp_dev)
414 {
415         struct xtalk_command *cmd;
416         struct xtalk_command *reply;
417         struct xtalk_sync *xtalk_sync;
418         struct xtalk_base *xtalk_base;
419         uint16_t tx_seq;
420         int ret;
421
422         DBG("\n");
423         assert(mpp_dev != NULL);
424         xtalk_sync = mpp_dev->xtalk_sync;
425         xtalk_base = mpp_dev->xtalk_base;
426         if((cmd = new_command(xtalk_base, XTALK_OP(MPP, STATUS_GET), 0)) == NULL) {
427                 ERR("new_command failed\n");
428                 return -ENOMEM;
429         }
430         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
431         if(ret < 0) {
432                 ERR("process_command failed: %d\n", ret);
433                 return ret;
434         }
435         mpp_dev->eeprom_type = 0x3 & (CMD_FIELD(reply, MPP, STATUS_GET_REPLY, i2cs_data) >> 3);
436         mpp_dev->status = CMD_FIELD(reply, MPP, STATUS_GET_REPLY, status);
437         mpp_dev->fw_versions = CMD_FIELD(reply, MPP, STATUS_GET_REPLY, fw_versions);
438         DBG("EEPROM TYPE: %02x\n", mpp_dev->eeprom_type);
439         DBG("FPGA Firmware: %s\n", (mpp_dev->status & 0x1) ? "Loaded" : "Empty");
440         DBG("Firmware Versions: USB='%s' FPGA='%s' EEPROM='%s'\n",
441                         mpp_dev->fw_versions.usb,
442                         mpp_dev->fw_versions.fpga,
443                         mpp_dev->fw_versions.eeprom);
444         free_command(reply);
445         return ret;
446 }
447
448 int mpp_eeprom_set(struct mpp_device *mpp_dev, const struct eeprom_table *et)
449 {
450         struct xtalk_command    *cmd;
451         struct xtalk_command    *reply;
452         struct xtalk_sync *xtalk_sync;
453         struct xtalk_base *xtalk_base;
454         uint16_t tx_seq;
455         int                     ret;
456
457         DBG("\n");
458         assert(mpp_dev != NULL);
459         xtalk_sync = mpp_dev->xtalk_sync;
460         xtalk_base = mpp_dev->xtalk_base;
461         if((cmd = new_command(xtalk_base, MPP_EEPROM_SET, 0)) == NULL) {
462                 ERR("new_command failed\n");
463                 return -ENOMEM;
464         }
465         memcpy(&CMD_FIELD(cmd, MPP, EEPROM_SET, data), et, sizeof(*et));
466         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
467         if(ret < 0) {
468                 ERR("process_command failed: %d\n", ret);
469                 return ret;
470         }
471         free_command(reply);
472         return 0;
473 }
474
475 int mpp_renumerate(struct mpp_device *mpp_dev)
476 {
477         struct xtalk_command    *cmd;
478         struct xtalk_sync *xtalk_sync;
479         struct xtalk_base *xtalk_base;
480         uint16_t tx_seq;
481         int                     ret;
482
483         DBG("\n");
484         assert(mpp_dev != NULL);
485         xtalk_sync = mpp_dev->xtalk_sync;
486         xtalk_base = mpp_dev->xtalk_base;
487         if((cmd = new_command(xtalk_base, MPP_RENUM, 0)) == NULL) {
488                 ERR("new_command failed\n");
489                 return -ENOMEM;
490         }
491         ret = process_command(xtalk_sync, cmd, NULL, &tx_seq);
492         if(ret < 0) {
493                 ERR("process_command failed: %d\n", ret);
494                 return ret;
495         }
496         return 0;
497 }
498
499 int mpp_caps_get(struct mpp_device *mpp_dev,
500         struct eeprom_table *eeprom_table,
501         struct capabilities *capabilities,
502         struct capkey *key)
503 {
504         struct xtalk_command    *cmd;
505         struct xtalk_command    *reply;
506         struct xtalk_sync *xtalk_sync;
507         struct xtalk_base *xtalk_base;
508         uint16_t tx_seq;
509         int                     ret;
510
511         DBG("\n");
512         assert(mpp_dev != NULL);
513         xtalk_sync = mpp_dev->xtalk_sync;
514         xtalk_base = mpp_dev->xtalk_base;
515         if((cmd = new_command(xtalk_base, MPP_CAPS_GET, 0)) == NULL) {
516                 ERR("new_command failed\n");
517                 return -ENOMEM;
518         }
519         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
520         if(ret < 0) {
521                 ERR("process_command failed: %d\n", ret);
522                 return ret;
523         }
524         assert(reply->header.op == MPP_CAPS_GET_REPLY);
525         if(eeprom_table) {
526                 memcpy(eeprom_table, (void *)&CMD_FIELD(reply, MPP, CAPS_GET_REPLY, data), sizeof(*eeprom_table));
527         }
528         if(capabilities) {
529                 const struct capabilities       *cap = &CMD_FIELD(reply, MPP, CAPS_GET_REPLY, capabilities);
530
531                 memcpy(capabilities, cap, sizeof(*capabilities));
532         }
533         if(key) {
534                 const struct capkey     *k = &CMD_FIELD(reply, MPP, CAPS_GET_REPLY, key);
535
536                 memcpy(key, k, sizeof(*key));
537         }
538         free_command(reply);
539         return 0;
540 }
541
542 int mpp_caps_set(struct mpp_device *mpp_dev,
543         const struct eeprom_table *eeprom_table,
544         const struct capabilities *capabilities,
545         const struct capkey *key)
546 {
547         struct xtalk_command    *cmd;
548         struct xtalk_command    *reply;
549         struct xtalk_sync *xtalk_sync;
550         struct xtalk_base *xtalk_base;
551         uint16_t tx_seq;
552         int                     ret;
553
554         DBG("\n");
555         assert(mpp_dev != NULL);
556         xtalk_sync = mpp_dev->xtalk_sync;
557         xtalk_base = mpp_dev->xtalk_base;
558         if((cmd = new_command(xtalk_base, MPP_CAPS_SET, 0)) == NULL) {
559                 ERR("new_command failed\n");
560                 return -ENOMEM;
561         }
562         memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, data), eeprom_table, sizeof(*eeprom_table));
563         memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, capabilities), capabilities, sizeof(*capabilities));
564         memcpy(&CMD_FIELD(cmd, MPP, CAPS_SET, key), key, sizeof(*key));
565         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
566         if(ret < 0) {
567                 ERR("process_command failed: %d\n", ret);
568                 return ret;
569         }
570         free_command(reply);
571         return 0;
572 }
573
574 int mpp_extrainfo_get(struct mpp_device *mpp_dev, struct extrainfo *info)
575 {
576         struct xtalk_command    *cmd;
577         struct xtalk_command    *reply;
578         struct xtalk_sync *xtalk_sync;
579         struct xtalk_base *xtalk_base;
580         uint16_t tx_seq;
581         int                     ret;
582
583         DBG("\n");
584         assert(mpp_dev != NULL);
585         xtalk_sync = mpp_dev->xtalk_sync;
586         xtalk_base = mpp_dev->xtalk_base;
587         if((cmd = new_command(xtalk_base, MPP_EXTRAINFO_GET, 0)) == NULL) {
588                 ERR("new_command failed\n");
589                 return -ENOMEM;
590         }
591         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
592         if(ret < 0) {
593                 ERR("process_command failed: %d\n", ret);
594                 return ret;
595         }
596         assert(reply->header.op == MPP_EXTRAINFO_GET_REPLY);
597         if(info) {
598                 int i;
599
600                 memcpy(info, (void *)&CMD_FIELD(reply, MPP, EXTRAINFO_GET_REPLY, info), sizeof(*info));
601                 /*
602                  * clean non-printing characters
603                  */
604                 for (i = sizeof(*info) - 1; i >= 0; i--) {
605                         if (info->text[i] != (char)0xFF)
606                                 break;
607                         info->text[i] = '\0';
608                 }
609         }
610         free_command(reply);
611         return 0;
612 }
613
614 int mpp_extrainfo_set(struct mpp_device *mpp_dev, const struct extrainfo *info)
615 {
616         struct xtalk_command    *cmd;
617         struct xtalk_command    *reply;
618         struct xtalk_sync *xtalk_sync;
619         struct xtalk_base *xtalk_base;
620         uint16_t tx_seq;
621         int                     ret;
622
623         DBG("\n");
624         assert(mpp_dev != NULL);
625         xtalk_sync = mpp_dev->xtalk_sync;
626         xtalk_base = mpp_dev->xtalk_base;
627         if((cmd = new_command(xtalk_base, MPP_EXTRAINFO_SET, 0)) == NULL) {
628                 ERR("new_command failed\n");
629                 return -ENOMEM;
630         }
631         memcpy(&CMD_FIELD(cmd, MPP, EXTRAINFO_SET, info), info, sizeof(*info));
632         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
633         if(ret < 0) {
634                 ERR("process_command failed: %d\n", ret);
635                 return ret;
636         }
637         free_command(reply);
638         return 0;
639 }
640
641 int mpp_eeprom_blk_rd(struct mpp_device *mpp_dev, uint8_t *buf, uint16_t offset, uint16_t len)
642 {
643         struct xtalk_command    *cmd;
644         struct xtalk_command    *reply;
645         struct xtalk_sync *xtalk_sync;
646         struct xtalk_base *xtalk_base;
647         uint16_t tx_seq;
648         int                     ret;
649         int                     size;
650
651         DBG("len = %d, offset = %d\n", len, offset);
652         assert(mpp_dev != NULL);
653         xtalk_sync = mpp_dev->xtalk_sync;
654         xtalk_base = mpp_dev->xtalk_base;
655         if((cmd = new_command(xtalk_base, MPP_EEPROM_BLK_RD, 0)) == NULL) {
656                 ERR("new_command failed\n");
657                 return -ENOMEM;
658         }
659         CMD_FIELD(cmd, MPP, EEPROM_BLK_RD, len) = len;
660         CMD_FIELD(cmd, MPP, EEPROM_BLK_RD, offset) = offset;
661         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
662         if(ret < 0) {
663                 ERR("process_command failed: %d\n", ret);
664                 size = ret;
665                 goto out;
666         }
667         size = reply->header.len - sizeof(struct mpp_header) - sizeof(XTALK_STRUCT(MPP, EEPROM_BLK_RD_REPLY));
668         INFO("size=%d offset=0x%X\n", size, CMD_FIELD(reply, MPP, EEPROM_BLK_RD_REPLY, offset));
669         dump_packet(LOG_DEBUG, DBG_MASK, "BLK_RD", (char *)reply, ret);
670         if(size > len) {
671                 ERR("Truncating reply (was %d, now %d)\n", size, len);
672                 size = len;
673         }
674         memcpy(buf, CMD_FIELD(reply, MPP, EEPROM_BLK_RD_REPLY, data), size);
675 out:
676         free_command(reply);
677         return size;
678 }
679
680 int mpp_send_start(struct mpp_device *mpp_dev, int dest, const char *ihex_version)
681 {
682         struct xtalk_command    *cmd;
683         struct xtalk_command    *reply = NULL;
684         struct xtalk_sync *xtalk_sync;
685         struct xtalk_base *xtalk_base;
686         uint16_t tx_seq;
687         int                     ret = 0;
688
689         DBG("dest = %s ihex_version = '%s'\n", dev_dest2str(dest), ihex_version);
690         assert(mpp_dev != NULL);
691         xtalk_sync = mpp_dev->xtalk_sync;
692         xtalk_base = mpp_dev->xtalk_base;
693         if((cmd = new_command(xtalk_base, MPP_DEV_SEND_START, 0)) == NULL) {
694                 ERR("new_command failed\n");
695                 ret = -ENOMEM;
696                 goto out;
697         }
698         CMD_FIELD(cmd, MPP, DEV_SEND_START, dest) = dest;
699         set_ihex_version(CMD_FIELD(cmd, MPP, DEV_SEND_START, ihex_version), ihex_version);
700         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
701         if(ret < 0) {
702                 ERR("process_command failed: %d\n", ret);
703                 goto out;
704         }
705 out:
706         if(reply)
707                 free_command(reply);
708         mpp_dev->burn_state = (ret > 0)
709                 ? BURN_STATE_STARTED
710                 : BURN_STATE_FAILED;
711         return ret;
712 }
713
714 int mpp_send_end(struct mpp_device *mpp_dev)
715 {
716         struct xtalk_command    *cmd;
717         struct xtalk_command    *reply = NULL;
718         struct xtalk_sync *xtalk_sync;
719         struct xtalk_base *xtalk_base;
720         uint16_t tx_seq;
721         int                     ret = 0;
722
723         DBG("\n");
724         assert(mpp_dev != NULL);
725         xtalk_sync = mpp_dev->xtalk_sync;
726         xtalk_base = mpp_dev->xtalk_base;
727         if((cmd = new_command(xtalk_base, MPP_DEV_SEND_END, 0)) == NULL) {
728                 ERR("new_command failed\n");
729                 ret = -ENOMEM;
730                 goto out;
731         }
732         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
733         if(ret < 0) {
734                 ERR("process_command failed: %d\n", ret);
735                 goto out;
736         }
737 out:
738         if(reply)
739                 free_command(reply);
740         mpp_dev->burn_state = (ret > 0)
741                 ? BURN_STATE_ENDED
742                 : BURN_STATE_FAILED;
743         return ret;
744 }
745
746 int mpp_send_seg(struct mpp_device *mpp_dev, const uint8_t *data, uint16_t offset, uint16_t len)
747 {
748         struct xtalk_command    *cmd;
749         struct xtalk_command    *reply;
750         struct xtalk_sync *xtalk_sync;
751         struct xtalk_base *xtalk_base;
752         uint16_t tx_seq;
753         int                     ret;
754
755         assert(mpp_dev != NULL);
756         xtalk_sync = mpp_dev->xtalk_sync;
757         xtalk_base = mpp_dev->xtalk_base;
758         if(mpp_dev->burn_state != BURN_STATE_STARTED) {
759                 ERR("Tried to send a segment while burn_state=%d\n",
760                                 mpp_dev->burn_state);
761                 return -EINVAL;
762         }
763         DBG("len = %d, offset = %d (0x%02X, 0x%02X)\n", len, offset, *data, *(data + 1));
764         if((cmd = new_command(xtalk_base, MPP_DEV_SEND_SEG, len)) == NULL) {
765                 ERR("new_command failed\n");
766                 return -ENOMEM;
767         }
768         CMD_FIELD(cmd, MPP, DEV_SEND_SEG, offset) = offset;
769         memcpy(CMD_FIELD(cmd, MPP, DEV_SEND_SEG, data), data, len);
770 #if 0
771         {
772                 FILE                    *fp;
773                 if((fp = fopen("seg_data.bin", "a")) == NULL) {
774                         perror("seg_data.bin");
775                         exit(1);
776                 }
777                 if(fwrite(CMD_FIELD(cmd, MPP, DEV_SEND_SEG, data), len, 1, fp) != 1) {
778                         perror("fwrite");
779                         exit(1);
780                 }
781                 fclose(fp);
782         }
783 #endif
784         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
785         if(ret < 0) {
786                 ERR("process_command failed: %d\n", ret);
787                 return ret;
788         }
789         free_command(reply);
790         return 0;
791 }
792
793 int mpp_reset(struct mpp_device *mpp_dev, int full_reset)
794 {
795         struct xtalk_command    *cmd;
796         struct xtalk_sync *xtalk_sync;
797         struct xtalk_base *xtalk_base;
798         uint16_t tx_seq;
799         int                     ret;
800         int                     op = (full_reset) ? MPP_RESET: MPP_HALF_RESET;
801
802         DBG("full = %s\n", (full_reset) ? "YES" : "NO");
803         assert(mpp_dev != NULL);
804         xtalk_sync = mpp_dev->xtalk_sync;
805         xtalk_base = mpp_dev->xtalk_base;
806         if((cmd = new_command(xtalk_base, op, 0)) == NULL) {
807                 ERR("new_command failed\n");
808                 return -ENOMEM;
809         }
810         ret = process_command(xtalk_sync, cmd, NULL, &tx_seq);
811         if(ret < 0) {
812                 ERR("process_command failed: %d\n", ret);
813                 return ret;
814         }
815         return 0;
816 }
817
818 int mpp_serial_cmd(struct mpp_device *mpp_dev, const uint8_t *in, uint8_t *out, uint16_t len)
819 {
820         struct xtalk_command    *cmd;
821         struct xtalk_command    *reply;
822         struct xtalk_sync *xtalk_sync;
823         struct xtalk_base *xtalk_base;
824         uint16_t tx_seq;
825         int                     ret;
826         uint8_t                 *data;
827
828         DBG("len=%d\n", len);
829         assert(mpp_dev != NULL);
830         xtalk_sync = mpp_dev->xtalk_sync;
831         xtalk_base = mpp_dev->xtalk_base;
832         if((cmd = new_command(xtalk_base, MPP_SER_SEND, len)) == NULL) {
833                 ERR("new_command failed\n");
834                 return -ENOMEM;
835         }
836         data = CMD_FIELD(cmd, MPP, SER_SEND, data);
837         memcpy(data, in, len);
838         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
839         if(ret < 0) {
840                 ERR("process_command failed: %d\n", ret);
841                 return ret;
842         }
843         assert(reply->header.op == MPP_SER_RECV);
844         data = CMD_FIELD(reply, MPP, SER_RECV, data);
845         memcpy(out, data, len);
846         free_command(reply);
847         return 0;
848 }
849
850 int mpps_card_info(struct mpp_device *mpp_dev, int unit, uint8_t *card_type, uint8_t *card_status)
851 {
852         /*
853          * Serial commands must have equal send/receive size
854          */
855         struct card_info_command {
856                 uint8_t ser_op;
857                 uint8_t addr;
858                 uint8_t card_full_type; /* (type << 4 | subtype) */
859                 uint8_t card_status;    /* BIT(0) - PIC burned */
860         } PACKED;
861         struct card_info_command ci_send;
862         struct card_info_command ci_recv;
863         int ret;
864
865         memset(&ci_send, 0, sizeof(ci_send));
866         memset(&ci_recv, 0, sizeof(ci_recv));
867         ci_send.ser_op = SER_CARD_INFO_GET;
868         ci_send.addr = (unit << 4);     /* low nibble is subunit */
869         ret = mpp_serial_cmd(mpp_dev,
870                 (uint8_t *)&ci_send,
871                 (uint8_t *)&ci_recv,
872                 sizeof(struct card_info_command));
873         if (ret < 0)
874                 return ret;
875         *card_type = ci_recv.card_full_type;
876         *card_status = ci_recv.card_status;
877         return 0;
878 }
879
880 int mpps_stat(struct mpp_device *mpp_dev, int unit, uint8_t *fpga_configuration, uint8_t *status)
881 {
882         /*
883          * Serial commands must have equal send/receive size
884          */
885         struct fpga_stat_command {
886                 uint8_t ser_op;
887                 uint8_t fpga_configuration;
888                 uint8_t status; /* BIT(0) - Watchdog timer status */
889         } PACKED;
890         struct fpga_stat_command fs_send;
891         struct fpga_stat_command fs_recv;
892         int ret;
893
894         memset(&fs_send, 0, sizeof(fs_send));
895         memset(&fs_recv, 0, sizeof(fs_recv));
896         fs_send.ser_op = SER_STAT_GET;
897         ret = mpp_serial_cmd(mpp_dev,
898                 (uint8_t *)&fs_send,
899                 (uint8_t *)&fs_recv,
900                 sizeof(struct fpga_stat_command));
901         if(ret < 0)
902                 return ret;
903         *fpga_configuration = fs_recv.fpga_configuration;
904         *status = fs_recv.status;
905         return 0;
906 }
907
908 int mpp_tws_watchdog(struct mpp_device *mpp_dev)
909 {
910         struct xtalk_command    *cmd;
911         struct xtalk_command    *reply;
912         struct xtalk_sync *xtalk_sync;
913         struct xtalk_base *xtalk_base;
914         uint16_t tx_seq;
915         int                     ret;
916
917         DBG("\n");
918         assert(mpp_dev != NULL);
919         xtalk_sync = mpp_dev->xtalk_sync;
920         xtalk_base = mpp_dev->xtalk_base;
921         if((cmd = new_command(xtalk_base, MPP_TWS_WD_MODE_GET, 0)) == NULL) {
922                 ERR("new_command failed\n");
923                 return -ENOMEM;
924         }
925         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
926         if(ret < 0) {
927                 ERR("process_command failed: %d\n", ret);
928                 return ret;
929         }
930         ret = CMD_FIELD(reply, MPP, TWS_WD_MODE_GET_REPLY, wd_active);
931         DBG("wd_active=0x%X\n", ret);
932         free_command(reply);
933         return ret == 1;
934 }
935
936 int mpp_tws_setwatchdog(struct mpp_device *mpp_dev, int yes)
937 {
938         struct xtalk_command    *cmd;
939         struct xtalk_command    *reply;
940         struct xtalk_sync *xtalk_sync;
941         struct xtalk_base *xtalk_base;
942         uint16_t tx_seq;
943         int                     ret;
944
945         DBG("%s\n", (yes) ? "YES" : "NO");
946         assert(mpp_dev != NULL);
947         xtalk_sync = mpp_dev->xtalk_sync;
948         xtalk_base = mpp_dev->xtalk_base;
949         if((cmd = new_command(xtalk_base, MPP_TWS_WD_MODE_SET, 0)) == NULL) {
950                 ERR("new_command failed\n");
951                 return -ENOMEM;
952         }
953         CMD_FIELD(cmd, MPP, TWS_WD_MODE_SET, wd_active) = (yes) ? 1 : 0;
954         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
955         if(ret < 0) {
956                 ERR("process_command failed: %d\n", ret);
957                 return ret;
958         }
959         free_command(reply);
960         return 0;
961 }
962
963 int mpp_tws_powerstate(struct mpp_device *mpp_dev)
964 {
965         struct xtalk_command    *cmd;
966         struct xtalk_command    *reply;
967         struct xtalk_sync *xtalk_sync;
968         struct xtalk_base *xtalk_base;
969         uint16_t tx_seq;
970         int                     ret;
971
972         DBG("\n");
973         assert(mpp_dev != NULL);
974         xtalk_sync = mpp_dev->xtalk_sync;
975         xtalk_base = mpp_dev->xtalk_base;
976         if((cmd = new_command(xtalk_base, MPP_TWS_PWR_GET, 0)) == NULL) {
977                 ERR("new_command failed\n");
978                 return -ENOMEM;
979         }
980         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
981         if(ret < 0) {
982                 ERR("process_command failed: %d\n", ret);
983                 return ret;
984         }
985         ret = CMD_FIELD(reply, MPP, TWS_PWR_GET_REPLY, power);
986         DBG("power=0x%X\n", ret);
987         free_command(reply);
988         return ret;
989 }
990
991 int mpp_tws_portnum(struct mpp_device *mpp_dev)
992 {
993         struct xtalk_command    *cmd;
994         struct xtalk_command    *reply;
995         struct xtalk_sync *xtalk_sync;
996         struct xtalk_base *xtalk_base;
997         uint16_t tx_seq;
998         int                     ret;
999
1000         DBG("\n");
1001         assert(mpp_dev != NULL);
1002         xtalk_sync = mpp_dev->xtalk_sync;
1003         xtalk_base = mpp_dev->xtalk_base;
1004         if((cmd = new_command(xtalk_base, MPP_TWS_PORT_GET, 0)) == NULL) {
1005                 ERR("new_command failed\n");
1006                 return -ENOMEM;
1007         }
1008         ret = process_command(xtalk_sync, cmd, &reply, &tx_seq);
1009         if(ret < 0) {
1010                 ERR("process_command failed: %d\n", ret);
1011                 return ret;
1012         }
1013         ret = CMD_FIELD(reply, MPP, TWS_PORT_GET_REPLY, portnum);
1014         DBG("portnum=0x%X\n", ret);
1015         free_command(reply);
1016         return ret;
1017 }
1018
1019 int mpp_tws_setportnum(struct mpp_device *mpp_dev, uint8_t portnum)
1020 {
1021         struct xtalk_command    *cmd;
1022         struct xtalk_sync *xtalk_sync;
1023         struct xtalk_base *xtalk_base;
1024         uint16_t tx_seq;
1025         int                     ret;
1026
1027         DBG("\n");
1028         assert(mpp_dev != NULL);
1029         xtalk_sync = mpp_dev->xtalk_sync;
1030         xtalk_base = mpp_dev->xtalk_base;
1031         if(portnum >= 2) {
1032                 ERR("Invalid portnum (%d)\n", portnum);
1033                 return -EINVAL;
1034         }
1035         if((cmd = new_command(xtalk_base, MPP_TWS_PORT_SET, 0)) == NULL) {
1036                 ERR("new_command failed\n");
1037                 return -ENOMEM;
1038         }
1039         CMD_FIELD(cmd, MPP, TWS_PORT_SET, portnum) = portnum;
1040         ret = process_command(xtalk_sync, cmd, NULL, &tx_seq);
1041         if(ret < 0) {
1042                 ERR("process_command failed: %d\n", ret);
1043                 return ret;
1044         }
1045         return 0;
1046 }
1047
1048 /*
1049  * data structures
1050  */
1051
1052 void show_eeprom(const struct eeprom_table *eprm, FILE *fp)
1053 {
1054         int     rmajor;
1055         int     rminor;
1056         char    buf[BUFSIZ];
1057
1058         rmajor = (eprm->release >> 8) & 0xFF;
1059         rminor = eprm->release & 0xFF;;
1060         memset(buf, 0, LABEL_SIZE + 1);
1061         memcpy(buf, eprm->label, LABEL_SIZE);
1062         fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Source", eprm->source);
1063         fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Vendor", eprm->vendor);
1064         fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Product", eprm->product);
1065         fprintf(fp, "EEPROM: %-15s: %d.%d\n", "Release", rmajor, rminor);
1066         fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Config", eprm->config_byte);
1067         fprintf(fp, "EEPROM: %-15s: '%s'\n", "Label", buf);
1068 }
1069
1070 void show_capabilities(const struct capabilities *capabilities, FILE *fp)
1071 {
1072         fprintf(fp, "Capabilities: FXS ports: %2d\n", capabilities->ports_fxs);
1073         fprintf(fp, "Capabilities: FXO ports: %2d\n", capabilities->ports_fxo);
1074         fprintf(fp, "Capabilities: BRI ports: %2d\n", capabilities->ports_bri);
1075         fprintf(fp, "Capabilities: PRI ports: %2d\n", capabilities->ports_pri);
1076         fprintf(fp, "Capabilities: ECHO ports: %2d\n", capabilities->ports_echo);
1077         fprintf(fp, "Capabilities: TwinStar : %s\n",
1078                 (CAP_EXTRA_TWINSTAR(capabilities)) ? "Yes" : "No");
1079 }
1080
1081 void show_astribank_status(struct mpp_device *mpp_dev, FILE *fp)
1082 {
1083         char    version_buf[BUFSIZ];
1084         int     is_loaded = STATUS_FPGA_LOADED(mpp_dev->status);
1085
1086         fprintf(fp, "Astribank: EEPROM      : %s\n",
1087                 eeprom_type2str(mpp_dev->eeprom_type));
1088         fprintf(fp, "Astribank: FPGA status : %s\n",
1089                 is_loaded ? "Loaded" : "Empty");
1090         if(is_loaded) {
1091                 memset(version_buf, 0, sizeof(version_buf));
1092                 memcpy(version_buf, mpp_dev->fw_versions.fpga, VERSION_LEN);
1093                 fprintf(fp, "Astribank: FPGA version: %s\n",
1094                         version_buf);
1095         }
1096 }
1097
1098 void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp)
1099 {
1100         char    buf[EXTRAINFO_SIZE + 1];
1101
1102         memcpy(buf, extrainfo->text, EXTRAINFO_SIZE);
1103         buf[EXTRAINFO_SIZE] = '\0';     /* assure null termination */
1104         fprintf(fp, "Extrainfo:             : '%s'\n", buf);
1105 }
1106
1107 int twinstar_show(struct mpp_device *mpp, FILE *fp)
1108 {
1109         int     watchdog;
1110         int     powerstate;
1111         int     portnum;
1112         int     i;
1113
1114         if((watchdog = mpp_tws_watchdog(mpp)) < 0) {
1115                 ERR("Failed getting TwinStar information\n");
1116                 return watchdog;
1117         }
1118         if((powerstate = mpp_tws_powerstate(mpp)) < 0) {
1119                 ERR("Failed getting TwinStar powerstate\n");
1120                 return powerstate;
1121         }
1122         if((portnum = mpp_tws_portnum(mpp)) < 0) {
1123                 ERR("Failed getting TwinStar portnum\n");
1124                 return portnum;
1125         }
1126         fprintf(fp, "TwinStar: Connected to : USB-%1d\n", portnum);
1127         fprintf(fp, "TwinStar: Watchdog     : %s\n",
1128                 (watchdog) ? "on-guard" : "off-guard");
1129         for(i = 0; i < 2; i++) {
1130                 int     pw = (1 << i) & powerstate;
1131
1132                 fprintf(fp, "TwinStar: USB-%1d POWER  : %s\n",
1133                         i, (pw) ? "ON" : "OFF");
1134         }
1135         return 0;
1136 }
1137
1138 int show_hardware(struct mpp_device *mpp_dev)
1139 {
1140         int     ret;
1141         struct eeprom_table     eeprom_table;
1142         struct capabilities     capabilities;
1143         struct extrainfo        extrainfo;
1144
1145         ret = mpp_caps_get(mpp_dev, &eeprom_table, &capabilities, NULL);
1146         if(ret < 0)
1147                 return ret;
1148         show_eeprom(&eeprom_table, stdout);
1149         show_astribank_status(mpp_dev, stdout);
1150         if(mpp_dev->eeprom_type == EEPROM_TYPE_LARGE) {
1151                 show_capabilities(&capabilities, stdout);
1152                 if(STATUS_FPGA_LOADED(mpp_dev->status)) {
1153                         uint8_t unit;
1154                         uint8_t card_status;
1155                         uint8_t card_type;
1156                         uint8_t fpga_configuration;
1157                         uint8_t status;
1158
1159                         for(unit = 0; unit < 5; unit++) {
1160                                 ret = mpps_card_info(mpp_dev, unit, &card_type, &card_status);
1161                                 if(ret < 0)
1162                                         return ret;
1163                                 printf("CARD %d: type=%x.%x %s\n", unit,
1164                                                 ((card_type >> 4) & 0xF), (card_type & 0xF),
1165                                                 ((card_status & 0x1) ? "PIC" : "NOPIC"));
1166                         }
1167                         ret = mpps_stat(mpp_dev, unit, &fpga_configuration, &status);
1168                         if (ret < 0)
1169                                 return ret;
1170                         printf("FPGA: %-17s: %d\n", "Configuration num", fpga_configuration);
1171                         printf("FPGA: %-17s: %s\n", "Watchdog Timer",
1172                                 (SER_STAT_WATCHDOG_READY(status)) ? "ready" : "expired");
1173                         printf("FPGA: %-17s: %s\n", "XPD Alive",
1174                                 (SER_STAT_XPD_ALIVE(status)) ? "yes" : "no");
1175                 }
1176                 ret = mpp_extrainfo_get(mpp_dev, &extrainfo);
1177                 if(ret < 0)
1178                         return ret;
1179                 show_extrainfo(&extrainfo, stdout);
1180                 if(CAP_EXTRA_TWINSTAR(&capabilities)) {
1181                         if ((eeprom_table.product & 0xFFF0) != 0x1160)
1182                                 printf("TwinStar: NO\n");
1183                         else
1184                                 twinstar_show(mpp_dev, stdout);
1185                 }
1186         }
1187         return 0;
1188 }
1189