From 18c6813f2c788b603dab363b9138d65d24252167 Mon Sep 17 00:00:00 2001 From: tzafrir Date: Wed, 27 May 2009 10:01:24 +0000 Subject: Big dump of newer xpp code. For finer details and separate commits, you are advised to look into the commit log of dahdi-{linux,tools}. xpp.r7150 * 116x Astribanks: - Support for the TwinStar capability and for FXO and (BRI|PRI) on same device. - New control protocol ("MPP"). - astribank_hextool - a low-level firmware loading tool instead of fpga_load . - astribank_tool - Other MPP activities . - Can still reset (but just that) through older protocol. - astribank_hexload is required for loading FPGA firmware for USB_FW.hex rev > 6885. - USB_FW rev. 7071 . - More modular FPGA firmware (1161 only). - FPGA_1161.hex rev. 7131. PIC_TYPE_* rev. 7107. - software-settings of some capabilities with astribank_allow . * XPP: - init_card_* script are less verbose. - Reduced rate of "Is a DAHDI sync master" message. - Replace member bus_id with dev_name() and set_dev_name() for building with 2.6.30. - Conditionally remove 'owner' property of procfs was dropped in 2.6.30. - astribank_hook now enabled by default. - Has an optional hook for TwinStar. * BRI: - hardhdlc support: The bri_dchan patch is no longer needed. - If bri_dchan patch applied: old code is used, and "dchan" is used. - If not: new code and "hardhdlc" is used. - zapconf will generate the right configuration, depending on the new sysfs driver attribute bri_hardhdlc, but default to "dchan" as before if not explicitly told. - Bugfix: explicitly turn off leds on startup. * FXS: - Initialization and calibration fixes. - Notify the user just one about wrong VMWI config * Dahdi-perl: - Fix detection of empty slots in wctdm. - Fix working with ethmf's extra file in /proc/zaptel - Improved detection of Rhino cards. - dahdi_genconf's generated text better explains files are generated. - /etc/xpp_order - allow specifiying an explicit order for Astribanks to register with Zaptel. - Dahdi::Xpp::Mpp - A wrapper around astribank_tool . * dahdi.init: - A separate waitfor_xpds script. May now have a wait-loop in some cases. - xpp_sync needs to only be called after dahdi_cfg . (for the PRI module). git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@4641 5390a7c7-147a-4af0-8ec9-7488f05a26cb --- kernel/xpp/utils/mpp_funcs.c | 1028 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1028 insertions(+) create mode 100644 kernel/xpp/utils/mpp_funcs.c (limited to 'kernel/xpp/utils/mpp_funcs.c') diff --git a/kernel/xpp/utils/mpp_funcs.c b/kernel/xpp/utils/mpp_funcs.c new file mode 100644 index 0000000..c52397f --- /dev/null +++ b/kernel/xpp/utils/mpp_funcs.c @@ -0,0 +1,1028 @@ +/* + * Written by Oron Peled + * Copyright (C) 2008, Xorcom + * + * All rights reserved. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +#include +#include +#include +#include +#include +#include "hexfile.h" +#include "astribank_usb.h" +#include "mpp_funcs.h" +#include "debug.h" + +static const char rcsid[] = "$Id$"; + +#define DBG_MASK 0x02 + +const char *ack_status_msg(uint8_t status) +{ + const static char *msgs[] = { + [STAT_OK] = "Acknowledges previous command", + [STAT_FAIL] = "Last command failed", + [STAT_RESET_FAIL] = "Reset failed", + [STAT_NODEST] = "No destination is selected", + [STAT_MISMATCH] = "Data mismatch", + [STAT_NOACCESS] = "No access", + [STAT_BAD_CMD] = "Bad command", + [STAT_TOO_SHORT] = "Packet is too short", + [STAT_ERROFFS] = "Offset error", + [STAT_NOCODE] = "Source was not burned before", + [STAT_NO_LEEPROM] = "Large EEPROM was not found", + [STAT_NO_EEPROM] = "No EEPROM was found", + [STAT_WRITE_FAIL] = "Writing to device failed", + [STAT_FPGA_ERR] = "FPGA error", + [STAT_KEY_ERR] = "Bad Capabilities Key", + [STAT_NOCAPS_ERR] = "No matching capability", + [STAT_NOPWR_ERR] = "No power on USB connector", + [STAT_CAPS_FPGA_ERR] = "Setting of the capabilities while FPGA is loaded", + }; + if(status > sizeof(msgs)/sizeof(msgs[0])) + return "ERROR CODE TOO LARGE"; + if(!msgs[status]) + return "MISSING ERROR CODE"; + return msgs[status]; +} + +const char *eeprom_type2str(enum eeprom_type et) +{ + const static char *msgs[] = { + [EEPROM_TYPE_NONE] = "NONE", + [EEPROM_TYPE_SMALL] = "SMALL", + [EEPROM_TYPE_LARGE] = "LARGE", + [EEPROM_TYPE_UNUSED] = "UNUSED", + }; + if(et > sizeof(msgs)/sizeof(msgs[0])) + return NULL; + return msgs[et]; +}; + +struct command_desc { + uint8_t op; + const char *name; + uint16_t len; +}; + +#define CMD_RECV(o) [MPP_ ## o] { \ + .op = MPP_ ## o, \ + .name = #o, \ + .len = sizeof(struct mpp_header) + sizeof(struct d_ ## o), \ + } + +#define CMD_SEND(o) [MPP_ ## o] { \ + .op = MPP_ ## o, \ + .name = #o, \ + .len = sizeof(struct mpp_header) + sizeof(struct d_ ## o), \ + } + +static const struct command_desc command_table[] = { + CMD_RECV(ACK), + CMD_SEND(PROTO_QUERY), + CMD_SEND(STATUS_GET), + CMD_SEND(STATUS_GET_REPLY), + CMD_SEND(EEPROM_SET), + CMD_SEND(CAPS_GET), + CMD_RECV(CAPS_GET_REPLY), + CMD_SEND(CAPS_SET), + CMD_SEND(EXTRAINFO_GET), + CMD_SEND(EXTRAINFO_GET_REPLY), + CMD_SEND(EXTRAINFO_SET), + CMD_RECV(PROTO_REPLY), + CMD_SEND(RENUM), + CMD_SEND(EEPROM_BLK_RD), + CMD_RECV(EEPROM_BLK_RD_REPLY), + CMD_SEND(DEV_SEND_SEG), + CMD_SEND(DEV_SEND_START), + CMD_SEND(DEV_SEND_END), + CMD_SEND(RESET), + CMD_SEND(HALF_RESET), + CMD_SEND(SER_SEND), + CMD_SEND(SER_RECV), + /* Twinstar */ + CMD_SEND(TWS_WD_MODE_SET), + CMD_SEND(TWS_WD_MODE_GET), + CMD_RECV(TWS_WD_MODE_GET_REPLY), + CMD_SEND(TWS_PORT_SET), + CMD_SEND(TWS_PORT_GET), + CMD_RECV(TWS_PORT_GET_REPLY), + CMD_SEND(TWS_PWR_GET), + CMD_RECV(TWS_PWR_GET_REPLY), +}; +#undef CMD_SEND +#undef CMD_RECV + +struct cmd_queue { + struct cmd_queue *next; + struct cmd_queue *prev; + struct mpp_command *cmd; +}; + +static struct cmd_queue output_queue = { + .next = &output_queue, + .prev = &output_queue, + .cmd = NULL + }; + +void free_command(struct mpp_command *cmd) +{ + memset(cmd, 0, cmd->header.len); + free(cmd); +} + +struct mpp_command *new_command(uint8_t op, uint16_t extra_data) +{ + struct mpp_command *cmd; + const struct command_desc *desc; + uint16_t len; + + DBG("OP=0x%X (extra_data %d)\n", op, extra_data); + if(op > sizeof(command_table)/sizeof(command_table[0])) { + ERR("Invalid op=0x%X. Bigger than max valid op\n", op); + return NULL; + } + desc = &command_table[op]; + if(!desc->name) { + ERR("Unknown op=0x%X.\n", op); + return NULL; + } + len = desc->len + extra_data; + if((cmd = malloc(len)) == NULL) { + ERR("Out of memory\n"); + return NULL; + } + cmd->header.op = op; + cmd->header.len = len; + cmd->header.seq = 0; /* Overwritten in send_usb() */ + return cmd; +} + +const struct command_desc *get_command_desc(uint8_t op) +{ + const struct command_desc *desc; + + if(op > sizeof(command_table)/sizeof(command_table[0])) { + //ERR("Invalid op=0x%X. Bigger than max valid op\n", op); + return NULL; + } + desc = &command_table[op]; + if(!desc->name) + return NULL; + return desc; +} + +const char *get_command_name(uint8_t op) +{ + const struct command_desc *desc; + + if((desc = get_command_desc(op)) == NULL) + return NULL; + return desc->name; +} + +void dump_command(struct mpp_command *cmd) +{ + uint16_t len; + int i; + + len = cmd->header.len; + if(len < sizeof(struct mpp_header)) { + ERR("Command too short (%d)\n", len); + return; + } + INFO("DUMP: OP=0x%X len=%d seq=%d\n", + cmd->header.op, cmd->header.len, cmd->header.seq); + for(i = 0; i < len - sizeof(struct mpp_header); i++) { + INFO(" %2d. 0x%X\n", i, cmd->alt.raw_data[i]); + } +} + +int send_command(struct astribank_device *astribank, struct mpp_command *cmd, int timeout) +{ + int ret; + int len; + char *buf; + + len = cmd->header.len; + cmd->header.seq = astribank->tx_sequenceno; + + buf = (char *)cmd; + //printf("%s: len=%d\n", __FUNCTION__, len); +#if 0 + extern FILE *fp; + if(fp) { + int i; + + fprintf(fp, "%05d:", cmd->header.seq); + for(i = 0; i < len; i++) + fprintf(fp, " %02X", (uint8_t)buf[i]); + fprintf(fp, "\n"); + } +#endif + ret = send_usb(astribank, (char *)cmd, len, timeout); + if(ret < 0) { + ERR("send_usb failed ret=%d\n", ret); + } + astribank->tx_sequenceno++; + return ret; +} + +struct mpp_command *recv_command(struct astribank_device *astribank, int timeout) +{ + struct mpp_command *reply; + int ret; + + if((reply = malloc(PACKET_SIZE)) == NULL) { + ERR("Out of memory\n"); + goto err; + } + reply->header.len = 0; + ret = recv_usb(astribank, (char *)reply, PACKET_SIZE, timeout); + if(ret < 0) { + ERR("Receive from usb failed.\n"); + goto err; + } + if(ret != reply->header.len) { + ERR("Wrong length received: got %d bytes, but length field says %d bytes%s\n", + ret, reply->header.len, + (ret == 1)? ". Old USB firmware?": ""); + goto err; + } + //dump_packet(LOG_DEBUG, __FUNCTION__, (char *)reply, ret); + return reply; +err: + if(reply) { + memset(reply, 0, PACKET_SIZE); + free_command(reply); + } + return NULL; +} + + +int process_command(struct astribank_device *astribank, struct mpp_command *cmd, struct mpp_command **reply_ref) +{ + struct mpp_command *reply = NULL; + const struct command_desc *reply_desc; + const struct command_desc *expected; + uint8_t reply_op; + int ret; + + if(reply_ref) + *reply_ref = NULL; /* So the caller knows if a reply was received */ + reply_op = cmd->header.op | 0x80; + expected = get_command_desc(reply_op); + //printf("%s: len=%d\n", __FUNCTION__, cmd->header.len); + ret = send_command(astribank, cmd, TIMEOUT); + if(ret < 0) { + ERR("send_command failed: %d\n", ret); + goto out; + } + if(!reply_ref) { + DBG("No reply requested\n"); + goto out; + } + reply = recv_command(astribank, TIMEOUT); + if(!reply) { + ERR("recv_command failed\n"); + ret = -EPROTO; + goto out; + } + *reply_ref = reply; + if((reply->header.op & 0x80) != 0x80) { + ERR("Unexpected reply op=0x%02X, should have MSB set.\n", reply->header.op); + ret = -EPROTO; + goto out; + } + DBG("REPLY OP: 0x%X\n", reply->header.op); + reply_desc = get_command_desc(reply->header.op); + if(!reply_desc) { + ERR("Unknown reply op=0x%02X\n", reply->header.op); + ret = -EPROTO; + goto out; + } + DBG("REPLY NAME: %s\n", reply_desc->name); + if(reply->header.op == MPP_ACK) { + int status = CMD_FIELD(reply, ACK, stat); + + if(expected) { + ERR("Expected OP=0x%02X: Got ACK(%d): %s\n", + reply_op, status, ack_status_msg(status)); + ret = -EPROTO; + goto out; + } else if(status != STAT_OK) { + + ERR("Got ACK (for OP=0x%X): %d - %s\n", + cmd->header.op, + status, + ack_status_msg(status)); +#if 0 + extern FILE *fp; + if(fp) { + fprintf(fp, "Got ACK(%d)\n", status); + } +#endif + ret = -EPROTO; + goto out; + } + /* Good expected ACK ... */ + } else if(reply->header.op != reply_op) { + ERR("Expected OP=0x%02X: Got OP=0x%02X\n", + reply_op, reply->header.op); + ret = -EPROTO; + goto out; + } + if(expected && expected->op != MPP_SER_RECV && expected->len != reply->header.len) { + ERR("Expected len=%d: Got len=%d\n", + expected->len, reply->header.len); + ret = -EPROTO; + goto out; + } + if(cmd->header.seq != reply->header.seq) { + ERR("Expected seq=%d: Got seq=%d\n", + cmd->header.seq, reply->header.seq); + ret = -EPROTO; + goto out; + } + ret = reply->header.len; /* All good, return the length */ + DBG("returning reply op 0x%X (%d bytes)\n", reply->header.op, ret); +out: + free_command(cmd); + if(!reply_ref && reply) + free_command(reply); + return ret; +} + +/* + * Protocol Commands + */ + +int mpp_proto_query(struct astribank_device *astribank) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_PROTO_QUERY, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + CMD_FIELD(cmd, PROTO_QUERY, proto_version) = MPP_PROTOCOL_VERSION; /* Protocol Version */ + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + astribank->mpp_proto_version = CMD_FIELD(reply, PROTO_REPLY, proto_version); + if(astribank->mpp_proto_version != MPP_PROTOCOL_VERSION) { + ERR("Got mpp protocol version: %02x (expected %02x)\n", + astribank->mpp_proto_version, + MPP_PROTOCOL_VERSION); + ret = -EPROTO; + goto out; + } + INFO("Protocol version: %02x\n", astribank->mpp_proto_version); + free_command(reply); +out: + return ret; +} + +int mpp_status_query(struct astribank_device *astribank) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_STATUS_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + astribank->eeprom_type = 0x3 & (CMD_FIELD(reply, STATUS_GET_REPLY, i2cs_data) >> 3); + astribank->status = CMD_FIELD(reply, STATUS_GET_REPLY, status); + DBG("EEPROM TYPE: %02x\n", astribank->eeprom_type); + DBG("FPGA Firmware: %s\n", (astribank->status & 0x1) ? "Loaded" : "Empty"); + free_command(reply); + return ret; +} + +int mpp_eeprom_set(struct astribank_device *astribank, const struct eeprom_table *et) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_EEPROM_SET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + memcpy(&CMD_FIELD(cmd, EEPROM_SET, data), et, sizeof(*et)); + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + free_command(reply); + return 0; +} + +int mpp_renumerate(struct astribank_device *astribank) +{ + struct mpp_command *cmd; + int ret; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_RENUM, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(astribank, cmd, NULL); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + return 0; +} + +int mpp_caps_get(struct astribank_device *astribank, + struct eeprom_table *eeprom_table, + struct capabilities *capabilities, + struct capkey *key) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_CAPS_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + assert(reply->header.op == MPP_CAPS_GET_REPLY); + if(eeprom_table) { + memcpy(eeprom_table, (void *)&CMD_FIELD(reply, CAPS_GET_REPLY, data), sizeof(*eeprom_table)); + } + if(capabilities) { + const struct capabilities *cap = &CMD_FIELD(reply, CAPS_GET_REPLY, capabilities); + + memcpy(capabilities, cap, sizeof(*capabilities)); + } + if(key) { + const struct capkey *k = &CMD_FIELD(reply, CAPS_GET_REPLY, key); + + memcpy(key, k, sizeof(*key)); + } + free_command(reply); + return 0; +} + +int mpp_caps_set(struct astribank_device *astribank, + const struct eeprom_table *eeprom_table, + const struct capabilities *capabilities, + const struct capkey *key) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_CAPS_SET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + memcpy(&CMD_FIELD(cmd, CAPS_SET, data), eeprom_table, sizeof(*eeprom_table)); + memcpy(&CMD_FIELD(cmd, CAPS_SET, capabilities), capabilities, sizeof(*capabilities)); + memcpy(&CMD_FIELD(cmd, CAPS_SET, key), key, sizeof(*key)); + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + free_command(reply); + return 0; +} + +int mpp_extrainfo_get(struct astribank_device *astribank, struct extrainfo *info) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_EXTRAINFO_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + assert(reply->header.op == MPP_EXTRAINFO_GET_REPLY); + if(info) { + memcpy(info, (void *)&CMD_FIELD(reply, EXTRAINFO_GET_REPLY, info), sizeof(*info)); + } + free_command(reply); + return 0; +} + +int mpp_extrainfo_set(struct astribank_device *astribank, const struct extrainfo *info) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_EXTRAINFO_SET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + memcpy(&CMD_FIELD(cmd, EXTRAINFO_SET, info), info, sizeof(*info)); + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + free_command(reply); + return 0; +} + +int mpp_eeprom_blk_rd(struct astribank_device *astribank, uint8_t *buf, uint16_t offset, uint16_t len) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + int size; + + DBG("len = %d, offset = %d\n", len, offset); + assert(astribank != NULL); + if((cmd = new_command(MPP_EEPROM_BLK_RD, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + CMD_FIELD(cmd, EEPROM_BLK_RD, len) = len; + CMD_FIELD(cmd, EEPROM_BLK_RD, offset) = offset; + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + size = ret; + goto out; + } + INFO("size=%d offset=0x%X\n", size, CMD_FIELD(reply, EEPROM_BLK_RD_REPLY, offset)); + dump_packet(LOG_DEBUG, "BLK_RD", (char *)reply, ret); + size = reply->header.len - sizeof(struct mpp_header) - sizeof(struct d_EEPROM_BLK_RD_REPLY); + if(size > len) { + ERR("Truncating reply (was %d, now %d)\n", size, len); + size = len; + } + memcpy(buf, CMD_FIELD(reply, EEPROM_BLK_RD_REPLY, data), size); +out: + free_command(reply); + return size; +} + +int mpp_send_start(struct astribank_device *astribank, enum dev_dest dest) +{ + struct mpp_command *cmd; + struct mpp_command *reply = NULL; + int ret = 0; + + DBG("dest = %d\n", dest); + assert(astribank != NULL); + if((cmd = new_command(MPP_DEV_SEND_START, 0)) == NULL) { + ERR("new_command failed\n"); + ret = -ENOMEM; + goto out; + } + CMD_FIELD(cmd, DEV_SEND_START, dest) = dest; + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + goto out; + } +out: + if(reply) + free_command(reply); + astribank->burn_state = (ret == 0) + ? BURN_STATE_STARTED + : BURN_STATE_FAILED; + return ret; +} + +int mpp_send_end(struct astribank_device *astribank) +{ + struct mpp_command *cmd; + struct mpp_command *reply = NULL; + int ret = 0; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_DEV_SEND_END, 0)) == NULL) { + ERR("new_command failed\n"); + ret = -ENOMEM; + goto out; + } + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + goto out; + } +out: + if(reply) + free_command(reply); + astribank->burn_state = (ret == 0) + ? BURN_STATE_ENDED + : BURN_STATE_FAILED; + return ret; +} + +int mpp_send_seg(struct astribank_device *astribank, const uint8_t *data, uint16_t offset, uint16_t len) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + if(!astribank->burn_state == BURN_STATE_STARTED) { + ERR("Tried to send a segment while burn_state=%d\n", + astribank->burn_state); + return -EINVAL; + } + DBG("len = %d, offset = %d (0x%02X, 0x%02X)\n", len, offset, *data, *(data + 1)); + assert(astribank != NULL); + if((cmd = new_command(MPP_DEV_SEND_SEG, len)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + CMD_FIELD(cmd, DEV_SEND_SEG, offset) = offset; + memcpy(CMD_FIELD(cmd, DEV_SEND_SEG, data), data, len); +#if 0 + { + FILE *fp; + if((fp = fopen("seg_data.bin", "a")) == NULL) { + perror("seg_data.bin"); + exit(1); + } + if(fwrite(CMD_FIELD(cmd, DEV_SEND_SEG, data), len, 1, fp) != 1) { + perror("fwrite"); + exit(1); + } + fclose(fp); + } +#endif + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + free_command(reply); + return 0; +} + +int mpp_reset(struct astribank_device *astribank, int full_reset) +{ + struct mpp_command *cmd; + int ret; + int op = (full_reset) ? MPP_RESET: MPP_HALF_RESET; + + DBG("full = %s\n", (full_reset) ? "YES" : "NO"); + assert(astribank != NULL); + if((cmd = new_command(op, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(astribank, cmd, NULL); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + return 0; +} + +int mpp_serial_cmd(struct astribank_device *astribank, const uint8_t *in, uint8_t *out, uint16_t len) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + uint8_t *data; + + DBG("len=%d\n", len); + assert(astribank != NULL); + if((cmd = new_command(MPP_SER_SEND, len)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + data = CMD_FIELD(cmd, SER_SEND, data); + memcpy(data, in, len); + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + assert(reply->header.op == MPP_SER_RECV); + data = CMD_FIELD(reply, SER_RECV, data); + memcpy(out, data, len); + free_command(reply); + return 0; +} + +int mpps_card_info(struct astribank_device *astribank, int unit, uint8_t *card_type, uint8_t *card_status) +{ + struct card_info_send { + uint8_t ser_op; + uint8_t addr; + } *card_info_send; + struct card_info_recv { + uint8_t ser_op_undef; /* invalid data */ + uint8_t addr; + uint8_t card_full_type; /* (type << 4 | subtype) */ + uint8_t card_status; /* BIT(0) - PIC burned */ + } *card_info_recv; + uint8_t in[sizeof(struct card_info_recv)]; + uint8_t out[sizeof(struct card_info_recv)]; + int len; + int ret; + + len = sizeof(struct card_info_recv); + memset(in, 0, len); + memset(out, 0, len); + card_info_send = (struct card_info_send *)∈ + card_info_recv = (struct card_info_recv *)&out; + card_info_send->ser_op = SER_CARD_INFO_GET; + card_info_send->addr = (unit << 4); /* low nibble is subunit */ + ret = mpp_serial_cmd(astribank, in, out, len); + if(ret < 0) + return ret; + *card_type = card_info_recv->card_full_type; + *card_status = card_info_recv->card_status; + return 0; +} + +int mpp_tws_watchdog(struct astribank_device *astribank) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_TWS_WD_MODE_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + ret = CMD_FIELD(reply, TWS_WD_MODE_GET_REPLY, wd_active); + DBG("wd_active=0x%X\n", ret); + free_command(reply); + return ret == 1; +} + +int mpp_tws_setwatchdog(struct astribank_device *astribank, int yes) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + DBG("%s\n", (yes) ? "YES" : "NO"); + assert(astribank != NULL); + if((cmd = new_command(MPP_TWS_WD_MODE_SET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + CMD_FIELD(cmd, TWS_WD_MODE_SET, wd_active) = (yes) ? 1 : 0; + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + free_command(reply); + return 0; +} + +int mpp_tws_powerstate(struct astribank_device *astribank) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_TWS_PWR_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + ret = CMD_FIELD(reply, TWS_PWR_GET_REPLY, power); + DBG("power=0x%X\n", ret); + free_command(reply); + return ret; +} + +int mpp_tws_portnum(struct astribank_device *astribank) +{ + struct mpp_command *cmd; + struct mpp_command *reply; + int ret; + + DBG("\n"); + assert(astribank != NULL); + if((cmd = new_command(MPP_TWS_PORT_GET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + ret = CMD_FIELD(reply, TWS_PORT_GET_REPLY, portnum); + DBG("portnum=0x%X\n", ret); + free_command(reply); + return ret; +} + +int mpp_tws_setportnum(struct astribank_device *astribank, uint8_t portnum) +{ + struct mpp_command *cmd; + int ret; + struct mpp_command *reply; + + DBG("\n"); + assert(astribank != NULL); + if(portnum >= 2) { + ERR("Invalid portnum (%d)\n", portnum); + return -EINVAL; + } + if((cmd = new_command(MPP_TWS_PORT_SET, 0)) == NULL) { + ERR("new_command failed\n"); + return -ENOMEM; + } + CMD_FIELD(cmd, TWS_PORT_SET, portnum) = portnum; + ret = process_command(astribank, cmd, &reply); + if(ret < 0) { + ERR("process_command failed: %d\n", ret); + return ret; + } + free_command(reply); + return 0; +} + +/* + * Wrappers + */ + +struct astribank_device *mpp_init(const char devpath[]) +{ + struct astribank_device *astribank; + int ret; + + DBG("devpath='%s'\n", devpath); + if((astribank = astribank_open(devpath, 1)) == NULL) { + ERR("Opening astribank failed\n"); + return NULL; + } + ret = mpp_proto_query(astribank); + if(ret < 0) { + ERR("Protocol handshake failed: %d\n", ret); + goto err; + } + ret = mpp_status_query(astribank); + if(ret < 0) { + ERR("Status query failed: %d\n", ret); + goto err; + } + return astribank; + +err: + if (astribank) + astribank_close(astribank, 0); + return NULL; +} + +void mpp_exit(struct astribank_device *astribank) +{ + DBG("\n"); + astribank_close(astribank, 0); +} + +/* + * data structures + */ + +void show_eeprom(const struct eeprom_table *eprm, FILE *fp) +{ + int rmajor = (eprm->release >> 8) & 0xFF; + int rminor = eprm->release & 0xFF;; + char buf[BUFSIZ]; + + memset(buf, 0, LABEL_SIZE + 1); + memcpy(buf, eprm->label, LABEL_SIZE); + fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Source", eprm->source); + fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Vendor", eprm->vendor); + fprintf(fp, "EEPROM: %-15s: 0x%04X\n", "Product", eprm->product); + fprintf(fp, "EEPROM: %-15s: %d.%d\n", "Release", rmajor, rminor); + fprintf(fp, "EEPROM: %-15s: 0x%02X\n", "Config", eprm->config_byte); + fprintf(fp, "EEPROM: %-15s: '%s'\n", "Label", buf); +} + +void show_capabilities(const struct capabilities *capabilities, FILE *fp) +{ + fprintf(fp, "Capabilities: FXS ports: %2d\n", capabilities->ports_fxs); + fprintf(fp, "Capabilities: FXO ports: %2d\n", capabilities->ports_fxo); + fprintf(fp, "Capabilities: BRI ports: %2d\n", capabilities->ports_bri); + fprintf(fp, "Capabilities: PRI ports: %2d\n", capabilities->ports_pri); + fprintf(fp, "Capabilities: TwinStar : %s\n", + (CAP_EXTRA_TWINSTAR(capabilities)) ? "Yes" : "No"); +} + +void show_astribank_status(struct astribank_device *astribank, FILE *fp) +{ + fprintf(fp, "Astribank: EEPROM : %s\n", eeprom_type2str(astribank->eeprom_type)); + fprintf(fp, "Astribank: FPGA status : %s\n", + STATUS_FPGA_LOADED(astribank->status) ? "Loaded" : "Empty"); +} + +void show_extrainfo(const struct extrainfo *extrainfo, FILE *fp) +{ + fprintf(fp, "Extrainfo: : %s\n", (const char *)(extrainfo->text)); +} + +int twinstar_show(struct astribank_device *astribank, FILE *fp) +{ + int watchdog; + int powerstate; + int portnum; + int i; + + if(!astribank_has_twinstar(astribank)) { + fprintf(fp, "TwinStar: NO\n"); + return 0; + } + if((watchdog = mpp_tws_watchdog(astribank)) < 0) { + ERR("Failed getting TwinStar information\n"); + return watchdog; + } + if((powerstate = mpp_tws_powerstate(astribank)) < 0) { + ERR("Failed getting TwinStar powerstate\n"); + return powerstate; + } + if((portnum = mpp_tws_portnum(astribank)) < 0) { + ERR("Failed getting TwinStar portnum\n"); + return portnum; + } + fprintf(fp, "TwinStar: Connected to : USB-%1d\n", portnum); + fprintf(fp, "TwinStar: Watchdog : %s\n", + (watchdog) ? "on-guard" : "off-guard"); + for(i = 0; i < 2; i++) { + int pw = (1 << i) & powerstate; + + fprintf(fp, "TwinStar: USB-%1d POWER : %s\n", + i, (pw) ? "ON" : "OFF"); + } + return 0; +} + -- cgit v1.2.3