summaryrefslogtreecommitdiff
path: root/xpp/xbus-core.c
diff options
context:
space:
mode:
authortzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-09-09 15:24:12 +0000
committertzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb>2006-09-09 15:24:12 +0000
commitacb7444dd7e5b951169967232fa3a02c949b51a7 (patch)
tree9e5d8323cbc6a81748c7433433b55c71a0cfe1a3 /xpp/xbus-core.c
parentebffdceebe9a9de3e2e8f2f3211f526a2715b964 (diff)
Latest xpp driver. Backported from trunk (r1455, Xorcom r2157)
git-svn-id: http://svn.digium.com/svn/zaptel/branches/1.2@1457 5390a7c7-147a-4af0-8ec9-7488f05a26cb
Diffstat (limited to 'xpp/xbus-core.c')
-rw-r--r--xpp/xbus-core.c186
1 files changed, 158 insertions, 28 deletions
diff --git a/xpp/xbus-core.c b/xpp/xbus-core.c
index 437ea5e..961c361 100644
--- a/xpp/xbus-core.c
+++ b/xpp/xbus-core.c
@@ -29,6 +29,9 @@
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/proc_fs.h>
+#ifdef PROTOCOL_DEBUG
+#include <linux/ctype.h>
+#endif
#include <linux/device.h>
#include <linux/delay.h> /* for mdelay() to debug */
#include "xpd.h"
@@ -40,10 +43,16 @@ static const char rcsid[] = "$Id$";
/* Defines */
#define POLL_TIMEOUT (MAX_XPDS) /* in jiffies */
+#define INITIALIZATION_TIMEOUT (40*HZ) /* in jiffies */
#define PROC_XBUSES "xbuses"
#define PROC_XBUS_SUMMARY "summary"
#define PROC_XBUS_WAITFOR_XPDS "waitfor_xpds"
+#ifdef PROTOCOL_DEBUG
+#define PROC_XBUS_COMMAND "command"
+static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data);
+#endif
+
/* Command line parameters */
extern int print_dbg;
extern int max_queue_len;
@@ -94,7 +103,7 @@ static atomic_t xpacket_count = ATOMIC_INIT(0);
* Receive packets:
* - Allocated/deallocated by xbus_xmiter
*/
-xpacket_t *xbus_packet_new(xbus_t *xbus, int flags)
+xpacket_t *xbus_packet_new(xbus_t *xbus, gfp_t flags)
{
xpacket_t *pack;
@@ -302,7 +311,7 @@ out:
static int xbus_poll(void *data)
{
int id;
- int ret;
+ int ret = 0;
unsigned long flags;
struct list_head *card;
struct list_head *next_card;
@@ -313,13 +322,17 @@ static int xbus_poll(void *data)
int xpd_num;
xbus_t *xbus = data;
+ if(!down_read_trylock(&xbus->in_use)) {
+ ERR("%s is being removed...\n", xbus->busname);
+ return -EBUSY;
+ }
+ mdelay(2); /* roundtrip for older polls */
spin_lock_irqsave(&xbus->lock, flags);
DBG("%s\n", xbus->busname);
/*
* Send out the polls
*/
- atomic_set(&xbus->count_poll_answers, 0);
for(id = 0; id < MAX_XPDS; id++) {
if(!xbus->hardware_exists)
break;
@@ -328,19 +341,28 @@ static int xbus_poll(void *data)
ret = CALL_PROTO(GLOBAL, DESC_REQ, xbus, NULL, id);
spin_lock_irqsave(&xbus->lock, flags);
if(ret < 0) {
- NOTICE("xpp: %s: Failed sending DESC_REQ to XPD #%d\n", __FUNCTION__, id);
- break;
+ ERR("xpp: %s: Failed sending DESC_REQ to XPD #%d\n", __FUNCTION__, id);
+ goto out;
}
mdelay(1); /* FIXME: debugging for Dima */
}
spin_unlock_irqrestore(&xbus->lock, flags);
- DBG("%s: Polled %d XPD's. Waiting for replies\n", xbus->busname, MAX_XPDS);
- ret = wait_event_timeout(xbus->wait_for_polls, atomic_read(&xbus->count_poll_answers) >= MAX_XPDS, POLL_TIMEOUT);
- if(ret < 0) {
- ERR("%s: Poll timeout %d\n", xbus->busname, ret);
- return ret;
+ /*
+ * Wait for replies
+ */
+ DBG("%s: Polled %d XPD's. Waiting for replies max %d jiffies\n", xbus->busname, MAX_XPDS, POLL_TIMEOUT);
+ ret = wait_event_interruptible_timeout(xbus->wait_for_polls, atomic_read(&xbus->count_poll_answers) >= MAX_XPDS, POLL_TIMEOUT);
+ if(ret == 0) {
+ ERR("%s: Poll timeout\n", xbus->busname);
+ goto out;
+ } else if(ret < 0) {
+ ERR("%s: Poll interrupted %d\n", xbus->busname, ret);
+ goto out;
}
- DBG("%s: Poll finished. Start processing.\n", xbus->busname);
+ DBG("%s: Poll finished in %d jiffies. Start processing.\n", xbus->busname, POLL_TIMEOUT - ret);
+ /*
+ * Build removals/additions lists
+ */
spin_lock_irqsave(&xbus->lock, flags);
INIT_LIST_HEAD(&removal_list);
INIT_LIST_HEAD(&additions_list);
@@ -366,8 +388,12 @@ static int xbus_poll(void *data)
kfree(card_desc);
}
}
+ atomic_set(&xbus->count_xpds_to_initialize, count_added);
spin_unlock_irqrestore(&xbus->lock, flags);
INFO("%s: Poll results: removals=%d additions=%d\n", xbus->busname, count_removed, count_added);
+ /*
+ * Process removals first
+ */
list_for_each_safe(card, next_card, &removal_list) {
struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list);
xpd_t *xpd;
@@ -379,14 +405,21 @@ static int xbus_poll(void *data)
xpd_disconnect(xpd);
kfree(card);
}
+ /*
+ * Now process additions
+ */
list_for_each_safe(card, next_card, &additions_list) {
struct card_desc_struct *card_desc = list_entry(card, struct card_desc_struct, card_list);
list_del(card);
+ /* FIXME: card_detected() should have a return value for count_xpds_initialized */
card_detected(card_desc);
+ atomic_inc(&xbus->count_xpds_initialized);
}
- complete_all(&xbus->xpds_initialized);
- return 0;
+ wake_up(&xbus->wait_for_xpd_initialization);
+out:
+ up_read(&xbus->in_use);
+ return ret;
}
@@ -487,6 +520,13 @@ static void xbus_free(xbus_t *xbus)
remove_proc_entry(PROC_XBUS_WAITFOR_XPDS, xbus->proc_xbus_dir);
xbus->proc_xbus_waitfor_xpds = NULL;
}
+#ifdef PROTOCOL_DEBUG
+ if(xbus->proc_xbus_command) {
+ DBG("Removing proc '%s' for %s\n", PROC_XBUS_COMMAND, xbus->busname);
+ remove_proc_entry(PROC_XBUS_COMMAND, xbus->proc_xbus_dir);
+ xbus->proc_xbus_command = NULL;
+ }
+#endif
DBG("Removing proc directory %s\n", xbus->busname);
remove_proc_entry(xbus->busname, xpp_proc_toplevel);
xbus->proc_xbus_dir = NULL;
@@ -524,12 +564,17 @@ xbus_t *xbus_new(xbus_ops_t *ops)
INFO("New xbus: %s\n", xbus->busname);
init_waitqueue_head(&xbus->packet_cache_empty);
atomic_set(&xbus->packet_counter, 0);
+
+ /* poll related variables */
atomic_set(&xbus->count_poll_answers, 0);
- init_waitqueue_head(&xbus->wait_for_polls);
- init_rwsem(&xbus->in_use);
+ atomic_set(&xbus->count_xpds_to_initialize, 0);
+ atomic_set(&xbus->count_xpds_initialized, 0);
INIT_LIST_HEAD(&xbus->poll_results);
- init_completion(&xbus->xpds_initialized);
+ init_waitqueue_head(&xbus->wait_for_polls);
+ init_waitqueue_head(&xbus->wait_for_xpd_initialization);
xbus->num_xpds = 0;
+
+ init_rwsem(&xbus->in_use);
xbus_reset_counters(xbus);
/* Device-Model */
@@ -577,6 +622,17 @@ xbus_t *xbus_new(xbus_ops_t *ops)
goto nobus;
}
xbus->proc_xbus_waitfor_xpds->owner = THIS_MODULE;
+#ifdef PROTOCOL_DEBUG
+ xbus->proc_xbus_command = create_proc_entry(PROC_XBUS_COMMAND, 0200, xbus->proc_xbus_dir);
+ if (!xbus->proc_xbus_command) {
+ ERR("Failed to create '%s' proc file for xbus %s\n", PROC_XBUS_COMMAND, xbus->busname);
+ err = -EIO;
+ goto nobus;
+ }
+ xbus->proc_xbus_command->write_proc = proc_xbus_command_write;
+ xbus->proc_xbus_command->data = xbus;
+ xbus->proc_xbus_command->owner = THIS_MODULE;
+#endif
#endif
/* Sanity checks */
if(!ops->packet_send) {
@@ -659,8 +715,11 @@ static int xbus_read_proc(char *page, char **start, off_t off, int count, int *e
(xbus->hardware_exists) ? "connected" : "missing",
xbus->bus_type
);
- len += sprintf(page + len, "POLLS: %d/%d\n", atomic_read(&xbus->count_poll_answers), MAX_XPDS);
- len += sprintf(page + len, "XPDS_READY: %s\n", (xbus->xpds_initialized.done) ? "YES" : "NO");
+ len += sprintf(page + len, "POLLS: %d/%d\n",
+ atomic_read(&xbus->count_poll_answers), MAX_XPDS);
+ len += sprintf(page + len, "XPDS_READY: %d/%d\n",
+ atomic_read(&xbus->count_xpds_initialized),
+ atomic_read(&xbus->count_xpds_to_initialize));
len += sprintf(page + len, "\nmax_packet_size=%d open_counter=%d packet_count=%d\n",
xbus->max_packet_size,
xbus->open_counter,
@@ -688,20 +747,29 @@ out:
static int xbus_read_waitfor_xpds(char *page, char **start, off_t off, int count, int *eof, void *data)
{
- int len = 0;
- unsigned long flags;
- xbus_t *xbus = data;
- int i;
+ int len = 0;
+ unsigned long flags;
+ xbus_t *xbus = data;
+ int ret;
if(!xbus)
goto out;
- i = wait_for_completion_interruptible_timeout(&xbus->xpds_initialized, 40*HZ);
- if(i < 0) {
- NOTICE("PID=%d waiting for XPDS initialization failed: %d\n", current->pid, i);
- return i;
+ DBG("%s: Waiting for card initialization of %d XPD's max %d seconds\n", xbus->busname, MAX_XPDS, INITIALIZATION_TIMEOUT/HZ);
+ ret = wait_event_interruptible_timeout(xbus->wait_for_xpd_initialization,
+ atomic_read(&xbus->count_xpds_initialized) >= atomic_read(&xbus->count_xpds_to_initialize),
+ INITIALIZATION_TIMEOUT);
+ if(ret == 0) {
+ ERR("%s: Card Initialization Timeout\n", xbus->busname);
+ return ret;
+ } else if(ret < 0) {
+ ERR("%s: Card Initialization Interrupted %d\n", xbus->busname, ret);
+ return ret;
}
+ DBG("%s: Finished initialization of %d XPD's in %d seconds.\n", xbus->busname, MAX_XPDS, (INITIALIZATION_TIMEOUT - ret)/HZ);
spin_lock_irqsave(&xbus->lock, flags);
- len += sprintf(page + len, "XPDS_READY: %s\n", (xbus->xpds_initialized.done) ? "YES" : "NO");
+ len += sprintf(page + len, "XPDS_READY: %d/%d\n",
+ atomic_read(&xbus->count_xpds_initialized),
+ atomic_read(&xbus->count_xpds_to_initialize));
spin_unlock_irqrestore(&xbus->lock, flags);
out:
if (len <= off+count)
@@ -716,6 +784,64 @@ out:
}
+#ifdef PROTOCOL_DEBUG
+static int proc_xbus_command_write(struct file *file, const char __user *buffer, unsigned long count, void *data)
+{
+ char buf[MAX_PROC_WRITE];
+ xbus_t *xbus = data;
+ xpacket_t *pack;
+ char *p;
+ byte *pack_contents;
+ byte *q;
+
+ if(count >= MAX_PROC_WRITE) {
+ ERR("%s: line too long\n", __FUNCTION__);
+ return -EFBIG;
+ }
+ if(copy_from_user(buf, buffer, count))
+ return -EINVAL;
+ buf[count] = '\0';
+ pack = xbus->ops->packet_new(xbus, GFP_KERNEL);
+ if(!pack)
+ return -ENOMEM;
+ q = pack_contents = (byte *)&pack->content;
+ for(p = buf; *p;) {
+ int val;
+ char hexdigit[3];
+
+ while(*p && isspace(*p)) // skip whitespace
+ p++;
+ if(!(*p))
+ break;
+ if(!isxdigit(*p)) {
+ ERR("%s: %s: bad hex value ASCII='0x%X' at position %d\n",
+ __FUNCTION__, xbus->busname, *p, p - buf);
+ goto err;
+ }
+ hexdigit[0] = *p++;
+ hexdigit[1] = '\0';
+ hexdigit[2] = '\0';
+ if(isxdigit(*p))
+ hexdigit[1] = *p++;
+ if(sscanf(hexdigit, "%2X", &val) != 1) {
+ ERR("%s: %s: bad hex value '%s' at position %d\n",
+ __FUNCTION__, xbus->busname, hexdigit, p - buf);
+ goto err;
+ }
+ *q++ = val;
+ // DBG("%s: %s: '%s' val=%d\n", __FUNCTION__, xbus->busname, hexdigit, val);
+ }
+ pack->datalen = q - pack_contents -
+ sizeof(pack->content.opcode) - sizeof(pack->content.addr);
+ packet_send(xbus, pack);
+ return count;
+err:
+ xbus->ops->packet_free(xbus, pack);
+ return -EINVAL;
+}
+#endif
+
+
static int read_proc_xbuses(char *page, char **start, off_t off, int count, int *eof, void *data)
{
int len = 0;
@@ -810,6 +936,7 @@ static void xbus_core_cleanup(void)
}
#ifdef CONFIG_PROC_FS
if(proc_xbuses) {
+ DBG("Removing " PROC_XBUSES " from proc\n");
remove_proc_entry(PROC_XBUSES, xpp_proc_toplevel);
proc_xbuses = NULL;
}
@@ -822,6 +949,9 @@ int __init xbus_core_init(void)
{
int ret;
+#ifdef PROTOCOL_DEBUG
+ INFO("FEATURE: %s with PROTOCOL_DEBUG\n", THIS_MODULE->name);
+#endif
packet_cache = kmem_cache_create("xpp_packets",
sizeof(xpacket_t),
0, 0,
@@ -836,7 +966,7 @@ int __init xbus_core_init(void)
return -ENOMEM;
}
#ifdef CONFIG_PROC_FS
- proc_xbuses = create_proc_read_entry(PROC_XBUSES, 0444, xpp_proc_toplevel, read_proc_xbuses, 0);
+ proc_xbuses = create_proc_read_entry(PROC_XBUSES, 0444, xpp_proc_toplevel, read_proc_xbuses, NULL);
if (!proc_xbuses) {
ERR("Failed to create proc file %s\n", PROC_XBUSES);
xbus_core_cleanup();