diff options
author | Noe Rubinstein <nrubinstein@proformatique.com> | 2010-09-24 10:05:31 +0200 |
---|---|---|
committer | Noe Rubinstein <nrubinstein@proformatique.com> | 2010-09-24 10:05:31 +0200 |
commit | 966533f27dfd378548f4fa4da0b46e093e812bff (patch) | |
tree | 9625ad01b5aaa643003c75e14b04a65ffa0a53e8 /xivovp/base.c | |
parent | b3658e40e48ec7ddce38117739fe05b5e6346d3b (diff) |
Still crashes but supposed to be better
Diffstat (limited to 'xivovp/base.c')
-rw-r--r-- | xivovp/base.c | 489 |
1 files changed, 489 insertions, 0 deletions
diff --git a/xivovp/base.c b/xivovp/base.c new file mode 100644 index 0000000..4f0b703 --- /dev/null +++ b/xivovp/base.c @@ -0,0 +1,489 @@ +#include <linux/kernel.h> +#include <linux/module.h> +#include <linux/errno.h> +#include <linux/timer.h> +#include <linux/compiler.h> +#include <linux/stringify.h> + +#include <dahdi/kernel.h> + +#include "vp_api.h" +#include "EVB_Le71HR8921G_rev_E_2M048.h" + +#define TICK_MS 5 /* matches with device profile configuration */ + +#include "tolapai_spi.h" + +#define DRV_NAME KBUILD_BASENAME + +#define TRACES_VANISH_DEFAULT 2000 +#define TXQUEUE_LEN 5 + +static int traces_vanish = TRACES_VANISH_DEFAULT; +module_param(traces_vanish, int, 0444); +MODULE_PARM_DESC(traces_vanish, + "number of " __stringify(TICK_MS) "ms ticks after device init complete " + "event at which point VP-API II Lite traces will be reduced to only " + "ERROR/WARNING/INFO (default: " __stringify(TRACES_VANISH_DEFAULT) ")"); + + +#define NB_LINES 1 //XXX +#define TICK_JIFFIES DIV_ROUND_UP(TICK_MS * HZ, 1000) +#define DEBUG_SELECT_RUNNING (VP_DBG_ERROR \ + | VP_DBG_WARNING \ + | VP_DBG_INFO) + +enum xivovp_line_type { FXS_LINE = 0, FXO_LINE = 1 }; + +struct xivovp_line { + enum xivovp_line_type type; + + int ready; + + Vp890LineObjectType line_obj; + VpLineCtxType vp_ctx; + + struct dahdi_chan chan; + enum dahdi_txsig txsig_queue[TXQUEUE_LEN]; + int txsig_queue_len; // is there a better/canonical way to write that? + + spinlock_t vp_lock; + + //int reverse_polarity; +}; + +static struct xivovp { + struct dahdi_span span; + struct timer_list vp_tick_timer; + + struct xivovp_line line[NB_LINES]; + struct dahdi_chan *chans[NB_LINES]; + + Vp890DeviceObjectType ve890_dev_obj; + VpDevCtxType dev_ctx; +} xivovp; + +static int +xivovp_hooksig_pvt(struct xivovp_line* line, enum dahdi_txsig txsig); + +/* Shouldn't there be something better there? TOTHINK */ +static struct xivovp_line* xivovp_line_from_ctx(VpLineCtxType* line_ctx) +{ + Vp890LineObjectType* line_obj = line_ctx->pLineObj; + int i; + + for(i = 0; i < ARRAY_SIZE(xivovp.line); i++) + if(&xivovp.line[i].line_obj == line_obj) + return &xivovp.line[i]; + + printk(KERN_ERR DRV_NAME ": a FX line we don't know of? This certainly shouldn't happen.\n"); + return NULL; +} + +static void vp_set_debug_select_running(void) +{ + int i; + uint32 debug_select; + + for(i = 0; i < ARRAY_SIZE(xivovp.line); i++) { + debug_select = DEBUG_SELECT_RUNNING; + VpSetOption(&xivovp.line[i].vp_ctx, NULL, VP_OPTION_ID_DEBUG_SELECT, + &debug_select); + } + + debug_select = DEBUG_SELECT_RUNNING; + VpSetOption(NULL, &xivovp.dev_ctx, VP_OPTION_ID_DEBUG_SELECT, &debug_select); + + debug_select = DEBUG_SELECT_RUNNING; + VpSetOption(NULL, NULL, VP_OPTION_ID_DEBUG_SELECT, &debug_select); +} + +static void vp_tick(const unsigned long data) +{ + int i, j; + static VpEventType event; + static VpResultsType result; + struct xivovp_line* line; + bool ev_pending; + VpStatusType vpst; + static bool count_and_stop_traces = FALSE; + + (void)data; + + vpst = VpApiTick(&xivovp.dev_ctx, &ev_pending); + if (vpst != VP_STATUS_SUCCESS) { + printk(KERN_ERR DRV_NAME ": VpApiTick returned %d\n", + (int)vpst); + return; + } + + while (ev_pending) { + ev_pending = VpGetEvent(&xivovp.dev_ctx, &event); + if (event.status != VP_STATUS_SUCCESS) { + printk(KERN_ERR DRV_NAME ": VpGetEvent returned event.status == %d\n", + (int)event.status); + return; + } + + if (ev_pending) { + printk(KERN_INFO "vp evt: %d %d\n", + (int)event.eventCategory, + (int)event.eventId); + + switch ((int)event.eventCategory) { + case VP_EVCAT_RESPONSE: + switch (event.eventId) { + case VP_DEV_EVID_DEV_INIT_CMP: { + VpOptionTimeslotType timeslot = { + .tx = 12, + .rx = 12, + }; + VpOptionEventMaskType event_mask = { + .faults = 0, + .signaling = 0, + .response = 0, + .test = 0, + .process = 0, + .fxo = 0, + }; + printk(KERN_INFO DRV_NAME ": vp dev init complete\n"); + vpst = VpSetOption(NULL, event.pDevCtx, + VP_OPTION_ID_EVENT_MASK, &event_mask); + if (vpst != VP_STATUS_SUCCESS) { + printk(KERN_ERR DRV_NAME ": VpSetOption VP_OPTION_ID_EVENT_MASK returned %d\n", + (int)vpst); + return; + } + vpst = VpSetOption(NULL, event.pDevCtx, + VP_OPTION_ID_TIMESLOT, + ×lot); + if (vpst != VP_STATUS_SUCCESS) { + printk(KERN_ERR DRV_NAME ": VpSetOption VP_OPTION_ID_TIMESLOT returned %d\n", + (int)vpst); + return; + } + + vpst = VpSetLineState(&xivovp.line[FXS_LINE].vp_ctx, + VP_LINE_OHT); + if (vpst != VP_STATUS_SUCCESS) { + printk(KERN_ERR DRV_NAME ": VpSetLineState returned %d\n", + (int)vpst); + return; + } + + //TODO: VpSetLineState for FXO_LINE + //TODO: VpCalLine for FXO_LINE + // What happens if lines aren't connected? + + vpst = VpCalLine(&xivovp.line[FXS_LINE].vp_ctx); + if (vpst != VP_STATUS_SUCCESS) { + printk(KERN_ERR DRV_NAME ": VpCalLine returned %d\n", + (int)vpst); + return; + } + count_and_stop_traces = TRUE; + break; + } + + case VP_EVID_CAL_CMP: + printk(KERN_INFO DRV_NAME ": calibration succeeded\n"); + xivovp_line_from_ctx(event.pLineCtx)->ready = 1; + vp_set_debug_select_running(); + break; + + case VP_EVID_CAL_BUSY: + printk(KERN_WARNING DRV_NAME ": calibration failed (returned VP_EVID_CAL_BUSY)\n"); + vp_set_debug_select_running(); + break; + } + break; + case VP_EVCAT_FAULT: + break; + case VP_EVCAT_SIGNALING: + if(!(line = xivovp_line_from_ctx(event.pLineCtx))) + break; + + switch (event.eventId) { + case VP_LINE_EVID_HOOK_OFF: + dahdi_hooksig(&line->chan, + DAHDI_RXSIG_OFFHOOK); + break; + case VP_LINE_EVID_HOOK_ON: + dahdi_hooksig(&line->chan, + DAHDI_RXSIG_ONHOOK); + break; + } + break; + case VP_EVCAT_TEST: + break; + case VP_EVCAT_PROCESS: + break; + case VP_EVCAT_FXO: + break; + } + + if (event.hasResults) { + printk(KERN_INFO "VpGetResults\n"); + vpst = VpGetResults(&event, &result); + if (vpst != VP_STATUS_SUCCESS) { + printk(KERN_ERR DRV_NAME ": VpGetResults returned %d\n", (int) vpst); + return; + } + } + } + } + + + for(i = 0; i < ARRAY_SIZE(xivovp.line); i++) { + if(xivovp.line[i].ready) { + for(j = 0; j < xivovp.line[i].txsig_queue_len; j++) { + xivovp_hooksig_pvt(&xivovp.line[i], + xivovp.line[i].txsig_queue[j]); + } + xivovp.line[i].txsig_queue_len = 0; + } + } + + if (count_and_stop_traces) { + if (traces_vanish >= 0 && --traces_vanish < 0) + vp_set_debug_select_running(); + } + + mod_timer(&xivovp.vp_tick_timer, jiffies + TICK_JIFFIES); +} + +static int +xivovp_hooksig(struct dahdi_chan *chan, enum dahdi_txsig txsig) +{ + struct xivovp_line* line = chan->pvt; + + if(line->txsig_queue_len >= ARRAY_SIZE(line->txsig_queue)) { + printk(KERN_WARNING DRV_NAME "(chan %d): txsig overrun", chan->chanpos); + return -1; + } + + line->txsig_queue[line->txsig_queue_len++] = txsig; + return 0; +} + +/* + * hooksig transmits sig from DAHDI to VP. + * sig from VP is handled in vp_tick and transmitted to DAHDI with + * dahdi_hooksig + */ +static int +xivovp_hooksig_pvt(struct xivovp_line* line, enum dahdi_txsig txsig) +{ + int chanpos = line->chan.chanpos; + if(line->type == FXO_LINE) { + switch(txsig) { + case DAHDI_TXSIG_START: + case DAHDI_TXSIG_OFFHOOK: + printk(KERN_WARNING DRV_NAME "(chan %d): transmitting %s state on FXO, setting to TALK.\n", chanpos, txsig == DAHDI_TXSIG_START ? "START" : "OFFHOOK"); + VpSetLineState(&line->vp_ctx, VP_LINE_FXO_TALK); + break; + case DAHDI_TXSIG_ONHOOK: + printk(KERN_WARNING DRV_NAME "(chan %d): transmitting ONHOOK on FXO, setting to OHT.\n", chanpos); + VpSetLineState(&line->vp_ctx, VP_LINE_FXO_OHT); + break; + default: + printk(KERN_WARNING DRV_NAME "(chan %d): unsupported tx state for FXO: %d\n", chanpos, txsig); + } + } else /* FXS */ { + switch(txsig) { + case DAHDI_TXSIG_START: + printk(KERN_WARNING DRV_NAME "(chan %d): transmitting START on FXS, setting to RINGING.\n", chanpos); + VpSetLineState(&line->vp_ctx, VP_LINE_RINGING); + break; + case DAHDI_TXSIG_OFFHOOK: + printk(KERN_WARNING DRV_NAME "(chan %d): transmitting OFFHOOK on FXS, setting to TALK.\n", chanpos); + VpSetLineState(&line->vp_ctx, VP_LINE_TALK); + break; + case DAHDI_TXSIG_ONHOOK: + printk(KERN_WARNING DRV_NAME "(chan %d): transmitting ONHOOK on FXS, setting to OHT.\n", chanpos); + VpSetLineState(&line->vp_ctx, VP_LINE_OHT); + break; + case DAHDI_TXSIG_KEWL: + printk(KERN_WARNING DRV_NAME "(chan %d): requested to transmit DAHDI_TXSIG_KEWL but I have no idea what it means.\n", chanpos); + //VpSetLineState(line->vp_ctx, ); + return -1; + default: + printk(KERN_WARNING DRV_NAME "(chan %d): unsupported tx state for FXS: %d\n", chanpos, txsig); + return -1; + } + } + + return 0; +} + +static const struct dahdi_span_ops xivovp_span_ops = { + .owner = THIS_MODULE, + .hooksig = xivovp_hooksig, +}; + +static int +span_init(void) +{ + dahdi_copy_string(xivovp.span.name, "XiVO_FX", sizeof(xivovp.span.name)); + dahdi_copy_string(xivovp.span.desc, + "FXO/FXS driver for Avencall's XiVO IPBX OpenHardware " + "platform", sizeof(xivovp.span.desc)); + xivovp.span.manufacturer = "Avencall"; + dahdi_copy_string(xivovp.span.devicetype, "Ve890", + sizeof(xivovp.span.devicetype)); + xivovp.span.ops = &xivovp_span_ops; + xivovp.span.chans = xivovp.chans; + + init_waitqueue_head(&xivovp.span.maintq); /* still dunno what this is */ + + return 0; +} + +static int +xivovp_init(void) +{ + int i; + /* this is simple because no dynamic alloc */ + + init_timer(&xivovp.vp_tick_timer); + xivovp.vp_tick_timer.function = vp_tick; + xivovp.vp_tick_timer.data = 42; + + xivovp.line[FXS_LINE].type = FXS_LINE; + xivovp.line[FXO_LINE].type = FXO_LINE; + + for(i = 0; i < NB_LINES; i++) { + xivovp.chans[i] = &xivovp.line[i].chan; + xivovp.line[i].chan.pvt = &xivovp.line[i].chan; + spin_lock_init(&xivovp.line[i].vp_lock); + } + + return 0; +} + +static int +vp_init(void) +{ + int rc; + VpStatusType vpst; + + vpst = VpMakeDeviceObject( + VP_DEV_890_SERIES, + /* deviceId */ 0, + &xivovp.dev_ctx, + (void*)&xivovp.ve890_dev_obj); + if (vpst != VP_STATUS_SUCCESS) { + printk(KERN_ERR DRV_NAME ": VpMakeDeviceObject failed (%d)\n", vpst); + rc = -EIO; + goto err_vp_make_device_object; + } + + vpst = VpMakeLineObject( + VP_TERM_FXS_GENERIC, + FXS_LINE, + &xivovp.line[FXS_LINE].vp_ctx, + (void*)&xivovp.line[FXS_LINE].line_obj, + &xivovp.dev_ctx); + if (vpst != VP_STATUS_SUCCESS) { + printk(KERN_ERR DRV_NAME ": VpMakeLineObject (FXS) failed (%d)\n", vpst); + rc = -EIO; + goto err_vp_make_line_object; + } + +#if 0 + vpst = VpMakeLineObject( + VP_TERM_FXO_GENERIC, + FXO_LINE, + &xivovp.line[1].vp_ctx, + (void*)&xivovp.line[1].line_obj, + &xivovp.dev_ctx); + if (vpst != VP_STATUS_SUCCESS) { + printk(KERN_ERR DRV_NAME ": VpMakeLineObject (FXO) failed (%d)\n", vpst); + rc = -EIO; + goto err_vp_make_line_object; + } +#endif + + vpst = VpInitDevice( + &xivovp.dev_ctx, + DEV_PROFILE_Buck_Boost, + AC_FXS_RF50_FR, + DC_FXS_DEF, + RING_FR, + AC_FXO_LC_FR, + FXO_DIALING_FR); + if (vpst != VP_STATUS_SUCCESS) { + printk(KERN_ERR DRV_NAME ": VpInitDevice failed (%d)\n", vpst); + rc = -EIO; + goto err_vp_init_device; + } + + return 0; + + /* nothing */ + err_vp_init_device: + /* nothing */ + err_vp_make_line_object: + /* nothing */ + err_vp_make_device_object: + return rc; +} + +static int +test_evb_ve890_init(void) +{ + int rc; + printk(KERN_INFO DRV_NAME ": entering %s\n", __func__); + + rc = tlp_spidev_init(); + if (rc < 0) { + printk(KERN_ERR DRV_NAME ": tlp_spidev_init failed (%d)\n", rc); + goto err_spidev_init; + } + + rc = xivovp_init(); + if(rc < 0) + goto err_xivovp_init; + + + rc = vp_init(); + if(rc < 0) + goto err_vp_init; + + rc = span_init(); + if(rc < 0) { + printk(KERN_ERR DRV_NAME ": ve890_dahdi_init failed\n"); + goto err_dahdi_init; + } + + mod_timer(&xivovp.vp_tick_timer, jiffies + TICK_JIFFIES); + + return 0; + + err_dahdi_init: + /* nothing */ + err_xivovp_init: + /* nothing */ + err_vp_init: + tlp_spidev_exit(); + err_spidev_init: + return rc; +} + +static void +test_evb_ve890_exit(void) +{ + printk(KERN_INFO DRV_NAME ": %s\n", __func__); + + del_timer_sync(&xivovp.vp_tick_timer); /* XXX : TODO update upstream Linux doc of del_timer_sync */ + + tlp_spidev_exit(); +} + +module_init(test_evb_ve890_init); +module_exit(test_evb_ve890_exit); + +MODULE_DESCRIPTION("Test driver for EVB Ve890"); +MODULE_AUTHOR("Guillaume Knispel"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("48"); |