summaryrefslogtreecommitdiff
path: root/kernel/xpp/card_global.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-02-04 23:00:48 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2008-02-04 23:00:48 +0000
commit7e068801fbf82413ac0a5e63e586c268bd457434 (patch)
tree9b61e9a4e07167e0b7d347e4336245724befa29c /kernel/xpp/card_global.c
parent29daeebad888269fa0ee2ca7e54e238c8498ca2d (diff)
Move kernel stuff to under kernel/
(merged branch /zaptel/team/tzafrir/move ) Closes issue #7117. git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@3793 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'kernel/xpp/card_global.c')
-rw-r--r--kernel/xpp/card_global.c342
1 files changed, 342 insertions, 0 deletions
diff --git a/kernel/xpp/card_global.c b/kernel/xpp/card_global.c
new file mode 100644
index 0000000..05f4008
--- /dev/null
+++ b/kernel/xpp/card_global.c
@@ -0,0 +1,342 @@
+/*
+ * Written by Oron Peled <oron@actcom.co.il>
+ * Copyright (C) 2004-2006, 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 <linux/module.h>
+#include "xdefs.h"
+#include "xpd.h"
+#include "xpp_zap.h"
+#include "xproto.h"
+#include "zap_debug.h"
+#include "xbus-core.h"
+#include "parport_debug.h"
+
+static const char rcsid[] = "$Id$";
+
+DEF_PARM(charp,initdir, "/usr/share/zaptel", 0644, "The directory of card initialization scripts");
+
+extern int print_dbg;
+
+/*---------------- GLOBAL Protocol Commands -------------------------------*/
+
+static bool global_packet_is_valid(xpacket_t *pack);
+static void global_packet_dump(const char *msg, xpacket_t *pack);
+
+/*---------------- GLOBAL: HOST COMMANDS ----------------------------------*/
+
+/* 0x04 */ HOSTCMD(GLOBAL, DESC_REQ, int xpd_num)
+{
+ int ret = 0;
+ xframe_t *xframe;
+ xpacket_t *pack;
+
+ if(!xbus) {
+ DBG(GENERAL, "NO XBUS\n");
+ return -EINVAL;
+ }
+ XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, DESC_REQ, xpd_num);
+ XBUS_DBG(GENERAL, xbus, "to %1d%1d\n", XBUS_UNIT(xpd_num), XBUS_SUBUNIT(xpd_num));
+ ret = send_cmd_frame(xbus, xframe);
+ XBUS_COUNTER(xbus, DESC_REQ)++;
+ return ret;
+}
+
+int xpp_register_request(xbus_t *xbus, xpd_t *xpd,
+ byte chipsel, bool writing, bool do_subreg, byte regnum, byte subreg, byte data_low, byte data_high)
+{
+ int ret = 0;
+ xframe_t *xframe;
+ xpacket_t *pack;
+ reg_cmd_t *reg_cmd;
+
+ if(!xbus) {
+ DBG(REGS, "NO XBUS\n");
+ return -EINVAL;
+ }
+ XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, REGISTER_REQUEST, xpd->xbus_idx);
+ LINE_DBG(REGS, xpd, chipsel, "%c%c R%02X S%02X %02X %02X\n",
+ (writing)?'W':'R',
+ (do_subreg)?'S':'D',
+ regnum, subreg, data_low, data_high);
+ reg_cmd = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REQUEST, reg_cmd);
+ reg_cmd->bytes = sizeof(*reg_cmd) - 1; // do not count the 'bytes' field
+ reg_cmd->eoframe = 0;
+ reg_cmd->multibyte = 0;
+ REG_FIELD(reg_cmd, chipsel) = chipsel;
+ REG_FIELD(reg_cmd, reserved) = 0; /* force reserved bits to 0 */
+ REG_FIELD(reg_cmd, read_request) = (writing) ? 0 : 1;
+ REG_FIELD(reg_cmd, do_subreg) = do_subreg;
+ REG_FIELD(reg_cmd, regnum) = regnum;
+ REG_FIELD(reg_cmd, subreg) = subreg;
+ REG_FIELD(reg_cmd, data_low) = data_low;
+ REG_FIELD(reg_cmd, data_high) = data_high;
+ ret = send_cmd_frame(xbus, xframe);
+ return ret;
+}
+
+/*
+ * The XPD parameter is totaly ignored by the driver and firmware as well.
+ */
+/* 0x19 */ HOSTCMD(GLOBAL, SYNC_SOURCE, enum sync_mode mode, int drift)
+{
+ xframe_t *xframe;
+ xpacket_t *pack;
+ const char *mode_name;
+
+ BUG_ON(!xbus);
+ if((mode_name = sync_mode_name(mode)) == NULL) {
+ XBUS_ERR(xbus, "SYNC_SOURCE: bad sync_mode=0x%X\n", mode);
+ return -EINVAL;
+ }
+ XBUS_DBG(SYNC, xbus, "%s (0x%X), drift=%d\n", mode_name, mode, drift);
+ XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, SYNC_SOURCE, 0);
+ RPACKET_FIELD(pack, GLOBAL, SYNC_SOURCE, sync_mode) = mode;
+ RPACKET_FIELD(pack, GLOBAL, SYNC_SOURCE, drift) = drift;
+ send_cmd_frame(xbus, xframe);
+ return 0;
+}
+
+/* 0x23 */ HOSTCMD(GLOBAL, RESET_SYNC_COUNTERS)
+{
+ xframe_t *xframe;
+ xpacket_t *pack;
+
+ BUG_ON(!xbus);
+ //XBUS_DBG(SYNC, xbus, "\n");
+ XFRAME_NEW_CMD(xframe, pack, xbus, GLOBAL, RESET_SYNC_COUNTERS, 0);
+ RPACKET_FIELD(pack, GLOBAL, RESET_SYNC_COUNTERS, mask) = 0x10;
+ send_cmd_frame(xbus, xframe);
+ return 0;
+}
+
+/*---------------- GLOBAL: Astribank Reply Handlers -----------------------*/
+
+HANDLER_DEF(GLOBAL, NULL_REPLY)
+{
+ XBUS_DBG(GENERAL, xbus, "got len=%d\n", XPACKET_LEN(pack));
+ return 0;
+}
+
+HANDLER_DEF(GLOBAL, DEV_DESC)
+{
+ struct card_desc_struct *card_desc;
+
+ BUG_ON(!xbus);
+ if((card_desc = KZALLOC(sizeof(struct card_desc_struct), GFP_ATOMIC)) == NULL) {
+ XBUS_ERR(xbus, "Card description allocation failed.\n");
+ return -ENOMEM;
+ }
+ card_desc->magic = CARD_DESC_MAGIC;
+ INIT_LIST_HEAD(&card_desc->card_list);
+ card_desc->xbus = xbus;
+ card_desc->type = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, type);
+ card_desc->subtype = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, subtype);
+ card_desc->rev = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, rev);
+ card_desc->xpd_addr = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, head.addr);
+ card_desc->line_status = RPACKET_FIELD(pack, GLOBAL, DEV_DESC, line_status);
+ XBUS_DBG(GENERAL, xbus, "XPD=%d%d type=%d.%d rev=%d line_status=0x%04X\n",
+ card_desc->xpd_addr.unit,
+ card_desc->xpd_addr.subunit,
+ card_desc->type,
+ card_desc->subtype,
+ card_desc->rev,
+ card_desc->line_status);
+ xbus_poller_notify(xbus, card_desc);
+ return 0;
+}
+
+HANDLER_DEF(GLOBAL, REGISTER_REPLY)
+{
+ reg_cmd_t *reg = &RPACKET_FIELD(pack, GLOBAL, REGISTER_REPLY, regcmd);
+
+ if(!xpd) {
+ XBUS_NOTICE(xbus, "%s: received %s for non-existing unit (%1d%1d)\n",
+ __FUNCTION__, cmd->name,
+ XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack));
+ return -EPROTO;
+ }
+ return CALL_XMETHOD(card_register_reply, xbus, xpd, reg);
+}
+
+HANDLER_DEF(GLOBAL, SYNC_REPLY)
+{
+ byte mode = RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, sync_mode);
+ byte drift = RPACKET_FIELD(pack, GLOBAL, SYNC_REPLY, drift);
+ const char *mode_name;
+
+ BUG_ON(!xbus);
+ if((mode_name = sync_mode_name(mode)) == NULL) {
+ XBUS_ERR(xbus, "SYNC_REPLY: bad sync_mode=0x%X\n", mode);
+ return -EINVAL;
+ }
+ XBUS_DBG(SYNC, xbus, "%s (0x%X), drift=%d\n", mode_name, mode, drift);
+ //dump_packet("SYNC_REPLY", pack, print_dbg & DBG_SYNC);
+ got_new_syncer(xbus, mode, drift);
+ return 0;
+}
+
+#define TMP_NAME_LEN (XBUS_NAMELEN + XPD_NAMELEN + 5)
+
+HANDLER_DEF(GLOBAL, ERROR_CODE)
+{
+ byte errorcode = RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, errorcode);
+ reg_cmd_t *bad_cmd;
+ char tmp_name[TMP_NAME_LEN];
+ static long rate_limit;
+
+ BUG_ON(!xbus);
+ if((rate_limit++ % 5003) > 200)
+ return 0;
+ if(!xpd) {
+ snprintf(tmp_name, TMP_NAME_LEN, "%s(%1d%1d)", xbus->busname,
+ XPACKET_ADDR_UNIT(pack), XPACKET_ADDR_SUBUNIT(pack));
+ } else {
+ snprintf(tmp_name, TMP_NAME_LEN, "%s/%s", xbus->busname, xpd->xpdname);
+ }
+ NOTICE("%s: FIRMWARE: %s CODE = 0x%X (rate_limit=%ld)\n",
+ tmp_name, cmd->name, errorcode, rate_limit);
+ switch(errorcode) {
+ case 1:
+ bad_cmd = &RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, info.bad_spi_cmd);
+ dump_packet("FIRMWARE: BAD_SPI_CMD", pack, 1);
+ break;
+ case 0xAB:
+ dump_packet("FIRMWARE: BAD_PACKET_LEN", pack, 1);
+ break;
+ default:
+ NOTICE("%s: FIRMWARE: %s UNKNOWN CODE = 0x%X\n", tmp_name, cmd->name, errorcode);
+ dump_packet("PACKET", pack, 1);
+ }
+ /*
+ * FIXME: Should implement an error recovery plan
+ */
+ return 0;
+}
+
+
+xproto_table_t PROTO_TABLE(GLOBAL) = {
+ .entries = {
+ /* Prototable Card Opcode */
+ XENTRY( GLOBAL, GLOBAL, NULL_REPLY ),
+ XENTRY( GLOBAL, GLOBAL, DEV_DESC ),
+ XENTRY( GLOBAL, GLOBAL, SYNC_REPLY ),
+ XENTRY( GLOBAL, GLOBAL, ERROR_CODE ),
+ XENTRY( GLOBAL, GLOBAL, REGISTER_REPLY ),
+ },
+ .name = "GLOBAL",
+ .packet_is_valid = global_packet_is_valid,
+ .packet_dump = global_packet_dump,
+};
+
+static bool global_packet_is_valid(xpacket_t *pack)
+{
+ const xproto_entry_t *xe;
+
+ //DBG(GENERAL, "\n");
+ xe = xproto_global_entry(XPACKET_OP(pack));
+ return xe != NULL;
+}
+
+static void global_packet_dump(const char *msg, xpacket_t *pack)
+{
+ DBG(GENERAL, "%s\n", msg);
+}
+
+#define MAX_ENV_STR 40
+#define MAX_PATH_STR 60
+
+int run_initialize_registers(xpd_t *xpd)
+{
+ int ret;
+ xbus_t *xbus;
+ char busstr[MAX_ENV_STR];
+ char xpdstr[MAX_ENV_STR];
+ char unitstr[MAX_ENV_STR];
+ char subunitstr[MAX_ENV_STR];
+ char typestr[MAX_ENV_STR];
+ char revstr[MAX_ENV_STR];
+ char connectorstr[MAX_ENV_STR];
+ char init_card[MAX_PATH_STR];
+ char *argv[] = {
+ init_card,
+ NULL
+ };
+ char *envp[] = {
+ busstr,
+ xpdstr,
+ unitstr,
+ subunitstr,
+ typestr,
+ revstr,
+ connectorstr,
+ NULL
+ };
+
+ BUG_ON(!xpd);
+ xbus = xpd->xbus;
+ if(!initdir || !initdir[0]) {
+ XPD_NOTICE(xpd, "Missing initdir parameter\n");
+ return -EINVAL;
+ }
+ snprintf(busstr, MAX_ENV_STR, "XPD_BUS=%s", xbus->busname);
+ snprintf(xpdstr, MAX_ENV_STR, "XPD_NAME=%s", xpd->xpdname);
+ snprintf(unitstr, MAX_ENV_STR, "XPD_UNIT=%d", xpd->addr.unit);
+ snprintf(subunitstr, MAX_ENV_STR, "XPD_SUBUNIT=%d", xpd->addr.subunit);
+ snprintf(typestr, MAX_ENV_STR, "XPD_TYPE=%d", xpd->type);
+ snprintf(revstr, MAX_ENV_STR, "XPD_REVISION=%d", xpd->revision);
+ snprintf(connectorstr, MAX_ENV_STR, "XBUS_CONNECTOR=%s", xbus->busdesc);
+ if(snprintf(init_card, MAX_PATH_STR, "%s/init_card_%d_%d",
+ initdir, xpd->type, xpd->revision) > MAX_PATH_STR) {
+ XPD_NOTICE(xpd, "Cannot initialize. pathname is longer than %d characters.\n", MAX_PATH_STR);
+ return -E2BIG;
+ }
+ if(!XBUS_GET(xbus)) {
+ XBUS_ERR(xbus, "Skipped register initialization. XBUS is going down\n");
+ return -ENODEV;
+ }
+ XPD_DBG(GENERAL, xpd, "running '%s' for type=%d revision=%d\n",
+ init_card, xpd->type, xpd->revision);
+ ret = call_usermodehelper(init_card, argv, envp, 1);
+ /*
+ * Carefully report results
+ */
+ if(ret == 0)
+ XPD_DBG(GENERAL, xpd, "'%s' finished OK\n", init_card);
+ else if(ret < 0) {
+ XPD_ERR(xpd, "Failed running '%s' (errno %d)\n", init_card, ret);
+ } else {
+ byte exitval = ((unsigned)ret >> 8) & 0xFF;
+ byte sigval = ret & 0xFF;
+
+ if(!exitval) {
+ XPD_ERR(xpd, "'%s' killed by signal %d\n", init_card, sigval);
+ } else {
+ XPD_ERR(xpd, "'%s' aborted with exitval %d\n", init_card, exitval);
+ }
+ ret = -EINVAL;
+ }
+ XBUS_PUT(xbus);
+ return ret;
+}
+
+EXPORT_SYMBOL(sync_mode_name);
+EXPORT_SYMBOL(run_initialize_registers);
+EXPORT_SYMBOL(xpp_register_request);