diff options
author | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2006-09-09 15:24:12 +0000 |
---|---|---|
committer | tzafrir <tzafrir@5390a7c7-147a-4af0-8ec9-7488f05a26cb> | 2006-09-09 15:24:12 +0000 |
commit | acb7444dd7e5b951169967232fa3a02c949b51a7 (patch) | |
tree | 9e5d8323cbc6a81748c7433433b55c71a0cfe1a3 /xpp/xbus-core.c | |
parent | ebffdceebe9a9de3e2e8f2f3211f526a2715b964 (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.c | 186 |
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(); |