diff options
-rw-r--r-- | tdm/xivo_tdm.c | 169 | ||||
-rw-r--r-- | tdm/xivo_tdm_api.h | 17 | ||||
-rw-r--r-- | xivovp/base.c | 46 |
3 files changed, 107 insertions, 125 deletions
diff --git a/tdm/xivo_tdm.c b/tdm/xivo_tdm.c index 2f96b5a..067dcbf 100644 --- a/tdm/xivo_tdm.c +++ b/tdm/xivo_tdm.c @@ -30,16 +30,20 @@ MODULE_LICENSE("GPL"); typedef unsigned char bool; enum { false = 0, true = 1 }; -struct xivo_tdm_port; +struct xivo_tdm_callbacks_struct { -struct xivo_tdm_cb_chan { - struct xivo_tdm_port *xtp; - unsigned int hss_chan_id; - unsigned int timeslot; - u8 *rx_buf; /* 8 bytes */ - u8 *tx_buf; /* 8 bytes */ - int must_start_tx; + /* all contexts including irq */ + void (*tick)(void *data); + void *tick_data; + + /* process context */ + void (*port0_started)(void *data); + void *port0_started_data; }; +static struct xivo_tdm_callbacks_struct xivo_tdm_callbacks; + +static void xivo_tdm_audio_work_func(void *data); +static DECLARE_WORK(xivo_tdm_audio_work, xivo_tdm_audio_work_func, NULL); struct xivo_tdm_port { int port_num; @@ -50,7 +54,6 @@ struct xivo_tdm_port { unsigned int hss_chan_ids[XIVO_TDM_TS_NUM]; spinlock_t lock; - struct work_struct work; /* WARNING: this file is a big hack, coherency of following chunks is * not guaranteed. Blame Intel for their shitty nearly unusable code. @@ -58,12 +61,6 @@ struct xivo_tdm_port { u8 tx_bufs[XIVO_TDM_TS_NUM][8]; u8 rx_bufs[XIVO_TDM_TS_NUM][8]; - struct xivo_tdm_cb_chan cb_chans[XIVO_TDM_TS_NUM]; - - int cb_cnum_trigger; - void (*cb)(void *data); - void *cb_data; - unsigned tx_errs; }; @@ -220,7 +217,7 @@ static int xivo_tdm_common_rx( static void xivo_tdm_common_tx( struct xivo_tdm_port* xtp, const unsigned int cnum, - u8 *tx_buf) + const u8 *tx_buf) { IX_OSAL_MBUF *osal_buf = NULL; icp_status_t status; @@ -262,71 +259,17 @@ static void xivo_tdm_common_tx( KERN_ERR, __func__, (int) status, cnum, xtp->tx_errs); free_osal_buf(osal_buf); - if (status != ICP_STATUS_OVERFLOW) - xtp->cb_chans[cnum].must_start_tx = 1; - } else - xtp->cb_chans[cnum].must_start_tx = 0; -} - -static void xivo_tdm_rx_cb(icp_user_context_t userContext) -{ - struct xivo_tdm_cb_chan *cb_chan = - (struct xivo_tdm_cb_chan *) userContext; - struct xivo_tdm_port *xtp = cb_chan->xtp; - unsigned int cnum; - - if (xtp->cb_cnum_trigger == cb_chan->timeslot) - if (likely(xtp->cb)) - xtp->cb(xtp->cb_data); - - cnum = cb_chan->timeslot; - - if (unlikely(cb_chan->must_start_tx)) - xivo_tdm_common_tx(xtp, cnum, cb_chan->tx_buf); - - (void) xivo_tdm_common_rx(xtp, cnum, cb_chan->rx_buf); -} - -static void xivo_tdm_tx_cb(icp_user_context_t userContext) -{ - struct xivo_tdm_cb_chan *cb_chan = - (struct xivo_tdm_cb_chan *) userContext; - - xivo_tdm_common_tx(cb_chan->xtp, cb_chan->timeslot, cb_chan->tx_buf); + } } static int start_one_chan( struct xivo_tdm_port* xtp, - const int cnum, - struct xivo_tdm_cb_struct *cb_struct) + const int cnum) { const unsigned int hss_chan_id = xtp->hss_chan_ids[cnum]; unsigned long flags; icp_status_t status; - if (cb_struct) { - struct xivo_tdm_cb_chan *cb_chan = &(xtp->cb_chans[cnum]); - - cb_chan->hss_chan_id = hss_chan_id; - cb_chan->rx_buf = cb_struct->rx_bufs[cnum]; - cb_chan->tx_buf = cb_struct->tx_bufs[cnum]; - - status = icp_HssAccChannelCallbacksRegister( - hss_chan_id, - (icp_user_context_t) cb_chan, - xivo_tdm_rx_cb, - xivo_tdm_tx_cb); - if (status != ICP_STATUS_SUCCESS) { - printk(KERN_ERR "%s: icp_HssAccChannelCallbacksRegister " - "returned error %d \n", - __func__, status); - cb_chan->hss_chan_id = 0; - cb_chan->rx_buf = NULL; - cb_chan->tx_buf = NULL; - return -EIO; - } - } - status = icp_HssAccChannelUp(hss_chan_id); if (status != ICP_STATUS_SUCCESS) { printk(KERN_ERR "%s: icp_HssAccChannelUp returned error %d \n", @@ -452,14 +395,12 @@ static void xivo_tdm_deferred_transmit( struct xivo_tdm_port* xtp, const unsigned int cnum) { - u8 *tx_buf = xtp->tx_bufs[cnum]; + const u8 *tx_buf = xtp->tx_bufs[cnum]; xivo_tdm_common_tx(xtp, cnum, tx_buf); } -static void xivo_tdm_work(void *arg) +static void xivo_tdm_work_port(struct xivo_tdm_port *xtp) { - struct xivo_tdm_port *xtp = arg; - unsigned long flags; u32 ts_started; u32 scan; @@ -478,6 +419,17 @@ static void xivo_tdm_work(void *arg) } } +static void xivo_tdm_audio_work_func(void *data) +{ + int i; + + (void) data; + + for (i = 0; i < (int)ARRAY_SIZE(xivo_tdm_ports); i++) { + xivo_tdm_work_port(&xivo_tdm_ports[i]); + } +} + /* EXPORTED FUNCS */ @@ -583,11 +535,28 @@ int xivo_tdm_config_port( } EXPORT_SYMBOL(xivo_tdm_config_port); +void xivo_tdm_register_port0_started( + struct xivo_tdm_port* xtp, + void (*port0_started)(void *), + void *port0_started_data) +{ + unsigned long flags; + + (void) xtp; + + spin_lock_irqsave(&xivo_tdm_ports[0].lock, flags); + xivo_tdm_callbacks.port0_started = port0_started; + xivo_tdm_callbacks.port0_started_data = port0_started_data; + spin_unlock_irqrestore(&xivo_tdm_ports[0].lock, flags); +} +EXPORT_SYMBOL(xivo_tdm_register_port0_started); + int xivo_tdm_start_chans( struct xivo_tdm_port* xtp, const u32 chans, - struct xivo_tdm_cb_struct *cb_struct) + struct xivo_tdm_tick_cb_struct *tick_cb) { + unsigned long flags; u32 scan; int cnum; @@ -599,26 +568,27 @@ int xivo_tdm_start_chans( } } - if (cb_struct) { - xtp->cb = cb_struct->xivo_tdm_cb; - xtp->cb_data = cb_struct->xivo_tdm_cb_data; + if (tick_cb) { + spin_lock_irqsave(&xtp->lock, flags); + xivo_tdm_callbacks.tick = tick_cb->tick; + xivo_tdm_callbacks.tick_data = tick_cb->tick_data; + spin_unlock_irqrestore(&xtp->lock, flags); } for (cnum = 0, scan = 1; scan; scan <<= 1, cnum++) { if (scan & chans) { printk(KERN_INFO "%s: starting chan %d\n", __func__, cnum); - if (cb_struct) { - if (xtp->cb_cnum_trigger < 0) - xtp->cb_cnum_trigger = cnum; - } - /* XXX retval */ (void) start_one_chan( - xtp, cnum, cb_struct); + /* XXX retval */ (void) start_one_chan(xtp, cnum); } } printk(KERN_INFO "%s: DONE\n", __func__); + if (xivo_tdm_callbacks.port0_started) + xivo_tdm_callbacks.port0_started( + xivo_tdm_callbacks.port0_started_data); + return 0; } EXPORT_SYMBOL(xivo_tdm_start_chans); @@ -663,10 +633,14 @@ void xivo_tdm_transmit( } EXPORT_SYMBOL(xivo_tdm_transmit); +/* hardirq: yes -- softirq: yes -- user: yes */ void xivo_tdm_tick( struct xivo_tdm_port* xtp) { - queue_work(xivo_tdm_wq, &xtp->work); + if (xivo_tdm_callbacks.tick) + xivo_tdm_callbacks.tick(xivo_tdm_callbacks.tick_data); + + queue_work(xivo_tdm_wq, &xivo_tdm_audio_work); } EXPORT_SYMBOL(xivo_tdm_tick); @@ -684,7 +658,7 @@ static void xivo_internal_cleanup(void) static int __init xivo_internal_init(void) { - int i, ts; + int i; xivo_tdm_wq = create_singlethread_workqueue("xivo_tdm"); if (!xivo_tdm_wq) { @@ -703,31 +677,12 @@ static int __init xivo_internal_init(void) sizeof xivo_tdm_ports[i].hss_chan_ids); spin_lock_init(&xivo_tdm_ports[i].lock); - INIT_WORK(&xivo_tdm_ports[i].work, - xivo_tdm_work, - &xivo_tdm_ports[i]); memset(xivo_tdm_ports[i].tx_bufs, 0xD5, sizeof xivo_tdm_ports[i].tx_bufs); memset(xivo_tdm_ports[i].rx_bufs, 0xD5, sizeof xivo_tdm_ports[i].rx_bufs); - for (ts = 0; - ts < (int)ARRAY_SIZE(xivo_tdm_ports[i].cb_chans); - ts++) { - struct xivo_tdm_cb_chan *cb_chan = &(xivo_tdm_ports[i].cb_chans[ts]); - cb_chan->xtp = &xivo_tdm_ports[i]; - cb_chan->hss_chan_id = 0; - cb_chan->timeslot = ts; - cb_chan->rx_buf = NULL; - cb_chan->tx_buf = NULL; - cb_chan->must_start_tx = 1; - } - - xivo_tdm_ports[i].cb_cnum_trigger = -1; - xivo_tdm_ports[i].cb = NULL; - xivo_tdm_ports[i].cb_data = NULL; - xivo_tdm_ports[i].tx_errs = 0; } diff --git a/tdm/xivo_tdm_api.h b/tdm/xivo_tdm_api.h index cde2269..9191653 100644 --- a/tdm/xivo_tdm_api.h +++ b/tdm/xivo_tdm_api.h @@ -12,12 +12,9 @@ /* for audio propagation, xivo_tdm_cb will be called every ms (hopefully...) */ -struct xivo_tdm_cb_struct { - u8 *rx_bufs[XIVO_TDM_TS_NUM]; - u8 *tx_bufs[XIVO_TDM_TS_NUM]; - - void (*xivo_tdm_cb)(void *data); - void *xivo_tdm_cb_data; +struct xivo_tdm_tick_cb_struct { + void (*tick)(void *data); + void *tick_data; }; @@ -40,10 +37,16 @@ int xivo_tdm_config_port( unsigned int port_config); /* hardirq: no -- softirq: no -- user: yes */ +void xivo_tdm_register_port0_started( + struct xivo_tdm_port* xtp, + void (*port0_started)(void *), + void *port0_started_data); + +/* hardirq: no -- softirq: no -- user: yes */ int xivo_tdm_start_chans( struct xivo_tdm_port* xtp, u32 chans, - struct xivo_tdm_cb_struct *cb_struct); // optional, can be null + struct xivo_tdm_tick_cb_struct *cb_struct); // optional, can be null void xivo_tdm_stop_chans( struct xivo_tdm_port* xtp); diff --git a/xivovp/base.c b/xivovp/base.c index da69740..96f5d55 100644 --- a/xivovp/base.c +++ b/xivovp/base.c @@ -84,13 +84,23 @@ static struct xivovp { struct xivo_tdm_port *tdm_port; } xivovp; -static void xivovp_transmit_and_receive(void *data) +static void xivovp_receive_and_transmit(void *data) { (void) data; + xivo_tdm_receive(xivovp.tdm_port, FXS_TIMESLOT, + xivovp.chans[FXS_LINE]->readchunk); + xivo_tdm_receive(xivovp.tdm_port, FXO_TIMESLOT, + xivovp.chans[FXO_LINE]->readchunk); + dahdi_receive(&xivovp.span); dahdi_transmit(&xivovp.span); dahdi_ec_span(&xivovp.span); + + xivo_tdm_transmit(xivovp.tdm_port, FXS_TIMESLOT, + xivovp.chans[FXS_LINE]->writechunk); + xivo_tdm_transmit(xivovp.tdm_port, FXO_TIMESLOT, + xivovp.chans[FXO_LINE]->writechunk); } /* Shouldn't there be something better there? TOTHINK */ @@ -644,10 +654,13 @@ vp_init(void) return rc; } +/* process context */ +static void +xivovp_port0_started_cb(void *data); + static int test_evb_ve890_init(void) { - struct xivo_tdm_cb_struct cb_struct; // 264 bytes int rc; printk(KERN_INFO DRV_NAME ": entering %s\n", __func__); @@ -672,15 +685,11 @@ test_evb_ve890_init(void) goto err_dahdi_init; } - memset(&cb_struct, 0, sizeof cb_struct); - cb_struct.rx_bufs[FXS_TIMESLOT] = xivovp.chans[FXS_LINE]->readchunk; - cb_struct.tx_bufs[FXS_TIMESLOT] = xivovp.chans[FXS_LINE]->writechunk; - cb_struct.rx_bufs[FXO_TIMESLOT] = xivovp.chans[FXO_LINE]->readchunk; - cb_struct.tx_bufs[FXO_TIMESLOT] = xivovp.chans[FXO_LINE]->writechunk; - cb_struct.xivo_tdm_cb = xivovp_transmit_and_receive; - cb_struct.xivo_tdm_cb_data = NULL; - /* XXX */ (void) xivo_tdm_start_chans( - xivovp.tdm_port, TS_MASK, &cb_struct); + /* UGLY EVIL HACK */ + xivo_tdm_register_port0_started( + xivovp.tdm_port, + xivovp_port0_started_cb, + NULL); mod_timer(&xivovp.vp_tick_timer, jiffies + VP_TICK_JIFFIES); @@ -696,6 +705,21 @@ test_evb_ve890_init(void) return rc; } +/* process context */ +static void +xivovp_port0_started_cb(void *data) +{ + struct xivo_tdm_tick_cb_struct tick_cb = { + .tick = xivovp_receive_and_transmit, + .tick_data = NULL, + }; + + printk(KERN_ERR "%s\n", __func__); + + /* XXX */ (void) xivo_tdm_start_chans( + xivovp.tdm_port, TS_MASK, &tick_cb); +} + static void test_evb_ve890_exit(void) { |