summaryrefslogtreecommitdiff
path: root/kernel/xpp/card_global.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2009-03-19 20:08:29 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2009-03-19 20:08:29 +0000
commitd8562c778088ff6ab3383df5ceead41eff4bf124 (patch)
tree43e394ae225fd7183018c2ae08d3fb1e5bcb12cb /kernel/xpp/card_global.c
parentb6b3226735f5e3b3fb000fa92daa7a574265c817 (diff)
xpp: a massive backport from DAHDI. From Xorcom branch-rel-6839-r6908 .
Sun Mar 1 2009 Oron Peled <oron@actcom.co.il> - xpp.r6795 * Fix cases where the command_queue overflowed during initialization. - Also add a 'command_queue_length' parameter to xpp.ko * More migrations to sysfs: - Add a 'transport' attribute to our astribank devices which points to the usb device we use. E.g: /sys/bus/astribanks/devices/xbus-00/transport is symlinked to ../../../../../../devices/pci0000:00/0000:00:10.4/usb5/5-4 - Move /proc/xpp/XBUS-??/XPD-??/span to /sys/bus/xpds/devices/??:?:?/span - Migrate from /proc/xpp/sync to: /sys/bus/astribanks/drivers/xppdrv/sync - New 'offhook' attribute in: /sys/bus/xpds/devices/??:?:?/offhook * PRI: change the "timing" priority to match the convention used by other PRI cards -- I.e: lower numbers (not 0) have higher priority. * FXO: - Power denial: create two module parameters instead of hard-coded constants (power_denial_safezone, power_denial_minlen). For sites that get non-standard power-denial signals from central office on offhook. - Don't hangup on power-denial, just notify Dahdi and wait for - Fix caller-id detection for the case central office sends it before first ring without any indication before. Asterisk's desicion. Mon, Dec 8 2008 Oron Peled <oron@actcom.co.il> - xpp.r6430 * PRI: - Match our span clocking priorities (in system.conf) to Digium -- this is a reversal of the previous state. Now lower numbers (greater than 0) are better. - Synchronization fixes for PRI ports other than 0. - Fix T1 CRC for some countries (e.g: China). * FXS: fix bug in VMWI detection if using old asterisk which does not provide ZT_VMWI ioctl(). * FXO: - Improve caller_id_style module parameter. This provide a workaround for countries that send this information without any notification (reverse polarity, ring, etc.) - Don't force on-hook upon power-denial. So, loopstart devices would ignore these as expected. * Implement a flow-control to prevent user space (init_card_* scripts) from pressuring our command queue. git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.4@4631 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'kernel/xpp/card_global.c')
-rw-r--r--kernel/xpp/card_global.c98
1 files changed, 55 insertions, 43 deletions
diff --git a/kernel/xpp/card_global.c b/kernel/xpp/card_global.c
index d3a7a66..88b9f60 100644
--- a/kernel/xpp/card_global.c
+++ b/kernel/xpp/card_global.c
@@ -40,6 +40,7 @@ extern int debug;
/*---------------- GLOBAL PROC handling -----------------------------------*/
+#ifdef OLD_PROC
static int proc_xpd_register_read(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0;
@@ -51,6 +52,8 @@ static int proc_xpd_register_read(char *page, char **start, off_t off, int count
if(!xpd)
return -ENODEV;
+ XPD_NOTICE(xpd, "%s: DEPRECATED: %s[%d] read from /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
spin_lock_irqsave(&xpd->lock, flags);
info = &xpd->last_reply;
len += sprintf(page + len, "# Writing bad data into this file may damage your hardware!\n");
@@ -88,6 +91,7 @@ static int proc_xpd_register_read(char *page, char **start, off_t off, int count
len = 0;
return len;
}
+#endif
static int parse_hexbyte(const char *buf)
{
@@ -289,7 +293,7 @@ out:
return ret;
}
-static int parse_chip_command(xpd_t *xpd, char *cmdline)
+int parse_chip_command(xpd_t *xpd, char *cmdline)
{
xbus_t *xbus;
int ret = -EBADR;
@@ -303,8 +307,9 @@ static int parse_chip_command(xpd_t *xpd, char *cmdline)
BUG_ON(!xpd);
xbus = xpd->xbus;
- if(!XBUS_GET(xbus)) {
- XBUS_DBG(GENERAL, xbus, "Dropped packet. Is shutting down.\n");
+ if(XBUS_IS(xbus, DISCONNECTED)) {
+ XBUS_DBG(GENERAL, xbus, "Dropped packet. In state %s.\n",
+ xbus_statename(XBUS_STATE(xbus)));
return -EBUSY;
}
strlcpy(buf, cmdline, MAX_PROC_WRITE); /* Save a copy */
@@ -335,11 +340,10 @@ static int parse_chip_command(xpd_t *xpd, char *cmdline)
else
ret = 0; /* empty command - no op */
out:
- XBUS_PUT(xbus);
return ret;
}
-
+#ifdef OLD_PROC
static int proc_xpd_register_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
{
xpd_t *xpd = data;
@@ -350,6 +354,8 @@ static int proc_xpd_register_write(struct file *file, const char __user *buffer,
if(!xpd)
return -ENODEV;
+ XPD_NOTICE(xpd, "%s: DEPRECATED: %s[%d] wrote to /proc interface instead of /sys\n",
+ __FUNCTION__, current->comm, current->tgid);
for(i = 0; i < count; /* noop */) {
for(p = buf; p < buf + MAX_PROC_WRITE; p++) { /* read a line */
if(i >= count)
@@ -368,7 +374,9 @@ static int proc_xpd_register_write(struct file *file, const char __user *buffer,
XPD_NOTICE(xpd, "Failed writing command: '%s'\n", buf);
return ret;
}
- msleep(1); /* don't overflow command queue */
+ /* Don't flood command_queue */
+ if(xframe_queue_count(&xpd->xbus->command_queue) > 5)
+ msleep(6);
}
return count;
}
@@ -405,6 +413,7 @@ err:
chip_proc_remove(xbus, xpd);
return -EINVAL;
}
+#endif
/*---------------- GLOBAL Protocol Commands -------------------------------*/
@@ -415,7 +424,7 @@ static void global_packet_dump(const char *msg, xpacket_t *pack);
/* 0x07 */ HOSTCMD(GLOBAL, AB_REQUEST)
{
- int ret = 0;
+ int ret = -ENODEV;
xframe_t *xframe;
xpacket_t *pack;
@@ -427,7 +436,8 @@ static void global_packet_dump(const char *msg, xpacket_t *pack);
RPACKET_FIELD(pack, GLOBAL, AB_REQUEST, rev) = XPP_PROTOCOL_VERSION;
RPACKET_FIELD(pack, GLOBAL, AB_REQUEST, reserved) = 0;
XBUS_DBG(DEVICES, xbus, "Protocol Version %d\n", XPP_PROTOCOL_VERSION);
- ret = send_cmd_frame(xbus, xframe);
+ if(xbus_setstate(xbus, XBUS_STATE_SENT_REQUEST))
+ ret = send_cmd_frame(xbus, xframe);
return ret;
}
@@ -474,6 +484,12 @@ int xpp_register_request(xbus_t *xbus, xpd_t *xpd, xportno_t portno,
dump_reg_cmd("REG_REQ", 1, xbus, xpd->addr.unit, reg_cmd->portnum, reg_cmd);
dump_packet("REG_REQ", pack, 1);
}
+ if(!xframe->usec_towait) { /* default processing time of SPI */
+ if(subreg)
+ xframe->usec_towait = 2000;
+ else
+ xframe->usec_towait = 1000;
+ }
ret = send_cmd_frame(xbus, xframe);
return ret;
}
@@ -590,6 +606,10 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */
ret = -EPROTO;
goto proto_err;
}
+ if(!xbus_setstate(xbus, XBUS_STATE_RECVD_DESC)) {
+ ret = -EPROTO;
+ goto proto_err;
+ }
XBUS_INFO(xbus, "DESCRIPTOR: %d cards, protocol revision %d\n", count_units, rev);
xbus->revision = rev;
if(!worker) {
@@ -631,19 +651,8 @@ HANDLER_DEF(GLOBAL, AB_DESCRIPTION) /* 0x08 */
list_add_tail(&card_desc->card_list, &worker->card_list);
spin_unlock_irqrestore(&worker->worker_lock, flags);
}
- /* Initialize the work. (adapt to kernel API changes). */
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,20)
- INIT_WORK(&worker->xpds_init_work, xbus_populate);
-#else
- INIT_WORK(&worker->xpds_init_work, xbus_populate, worker);
-#endif
- xbus = get_xbus(xbus->num); /* released in xbus_populate() */
- BUG_ON(!xbus);
- /* Now send it */
- if(!queue_work(worker->wq, &worker->xpds_init_work)) {
- XBUS_ERR(xbus, "Failed to queue xpd initialization work\n");
+ if(!xbus_process_worker(xbus))
return -ENODEV;
- }
return 0;
proto_err:
dump_packet("AB_DESCRIPTION", pack, DBG_ANY);
@@ -690,34 +699,24 @@ HANDLER_DEF(GLOBAL, SYNC_REPLY)
HANDLER_DEF(GLOBAL, ERROR_CODE)
{
- byte errorcode;
char tmp_name[TMP_NAME_LEN];
static long rate_limit;
- const char *msg;
- const static char *fw_messages[] = {
- [1] = "Packet too short",
- [2] = "Len field is too small",
- [3] = "Premature packet end",
- [4] = "Invalid op code",
- [5] = "Invalid packet len",
- [6] = "SPI fifo full",
- };
+ byte category_code;
+ byte errorbits;
BUG_ON(!xbus);
if((rate_limit++ % 5003) > 200)
return 0;
- errorcode = RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, errorcode);
- msg = (errorcode < ARRAY_SIZE(fw_messages))
- ? fw_messages[errorcode]
- : "UNKNOWN CODE";
+ category_code = RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, category_code);
+ errorbits = RPACKET_FIELD(pack, GLOBAL, ERROR_CODE, errorbits);
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 (%s) (rate_limit=%ld)\n",
- tmp_name, cmd->name, errorcode, msg, rate_limit);
+ NOTICE("%s: FIRMWARE %s: category=%d errorbits=0x%02X (rate_limit=%ld)\n",
+ tmp_name, cmd->name, category_code, errorbits, rate_limit);
dump_packet("FIRMWARE: ", pack, 1);
/*
* FIXME: Should implement an error recovery plan
@@ -755,19 +754,21 @@ static void global_packet_dump(const char *msg, xpacket_t *pack)
}
#define MAX_ENV_STR 40
-#define MAX_PATH_STR 60
+#define MAX_PATH_STR 128
int run_initialize_registers(xpd_t *xpd)
{
int ret;
xbus_t *xbus;
char busstr[MAX_ENV_STR];
+ char busnumstr[MAX_ENV_STR];
char unitstr[MAX_ENV_STR];
char subunitsstr[MAX_ENV_STR];
char typestr[MAX_ENV_STR];
char directionstr[MAX_ENV_STR];
char revstr[MAX_ENV_STR];
char connectorstr[MAX_ENV_STR];
+ char xbuslabel[MAX_ENV_STR];
char init_card[MAX_PATH_STR];
byte direction_mask;
int i;
@@ -777,12 +778,14 @@ int run_initialize_registers(xpd_t *xpd)
};
char *envp[] = {
busstr,
+ busnumstr,
unitstr,
subunitsstr,
typestr,
directionstr,
revstr,
connectorstr,
+ xbuslabel,
NULL
};
@@ -792,6 +795,10 @@ int run_initialize_registers(xpd_t *xpd)
XPD_NOTICE(xpd, "Missing initdir parameter\n");
return -EINVAL;
}
+ if(!xpd_setstate(xpd, XPD_STATE_INIT_REGS)) {
+ ret = -EINVAL;
+ goto err;
+ }
direction_mask = 0;
for(i = 0; i < xpd->subunits; i++) {
xpd_t *su = xpd_byaddr(xbus, xpd->addr.unit, i);
@@ -805,20 +812,25 @@ int run_initialize_registers(xpd_t *xpd)
direction_mask |= (su->direction == TO_PHONE) ? BIT(i) : 0;
}
snprintf(busstr, MAX_ENV_STR, "XBUS_NAME=%s", xbus->busname);
+ snprintf(busnumstr, MAX_ENV_STR, "XBUS_NUMBER=%d", xbus->num);
snprintf(unitstr, MAX_ENV_STR, "UNIT_NUMBER=%d", xpd->addr.unit);
snprintf(typestr, MAX_ENV_STR, "UNIT_TYPE=%d", xpd->type);
snprintf(subunitsstr, MAX_ENV_STR, "UNIT_SUBUNITS=%d", xpd->subunits);
snprintf(directionstr, MAX_ENV_STR, "UNIT_SUBUNITS_DIR=%d", direction_mask);
snprintf(revstr, MAX_ENV_STR, "XBUS_REVISION=%d", xbus->revision);
- snprintf(connectorstr, MAX_ENV_STR, "XBUS_CONNECTOR=%s", xbus->location);
+ snprintf(connectorstr, MAX_ENV_STR, "XBUS_CONNECTOR=%s", xbus->connector);
+ snprintf(xbuslabel, MAX_ENV_STR, "XBUS_LABEL=%s", xbus->label);
if(snprintf(init_card, MAX_PATH_STR, "%s/init_card_%d_%d",
initdir, xpd->type, xbus->revision) > MAX_PATH_STR) {
XPD_NOTICE(xpd, "Cannot initialize. pathname is longer than %d characters.\n", MAX_PATH_STR);
- return -E2BIG;
+ ret = -E2BIG;
+ goto err;
}
- if(!XBUS_GET(xbus)) {
- XBUS_ERR(xbus, "Skipped register initialization. XBUS is going down\n");
- return -ENODEV;
+ if(!XBUS_IS(xbus, RECVD_DESC)) {
+ XBUS_ERR(xbus, "Skipped register initialization. In state %s.\n",
+ xbus_statename(XBUS_STATE(xbus)));
+ ret = -ENODEV;
+ goto err;
}
XPD_DBG(DEVICES, xpd, "running '%s' for type=%d revision=%d\n",
init_card, xpd->type, xbus->revision);
@@ -841,7 +853,7 @@ int run_initialize_registers(xpd_t *xpd)
}
ret = -EINVAL;
}
- XBUS_PUT(xbus);
+err:
return ret;
}