summaryrefslogtreecommitdiff
path: root/xivovp/base.c
diff options
context:
space:
mode:
authorNoe Rubinstein <nrubinstein@proformatique.com>2010-09-24 10:05:31 +0200
committerNoe Rubinstein <nrubinstein@proformatique.com>2010-09-24 10:05:31 +0200
commit966533f27dfd378548f4fa4da0b46e093e812bff (patch)
tree9625ad01b5aaa643003c75e14b04a65ffa0a53e8 /xivovp/base.c
parentb3658e40e48ec7ddce38117739fe05b5e6346d3b (diff)
Still crashes but supposed to be better
Diffstat (limited to 'xivovp/base.c')
-rw-r--r--xivovp/base.c489
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,
+ &timeslot);
+ 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");