summaryrefslogtreecommitdiff
path: root/tdm
diff options
context:
space:
mode:
Diffstat (limited to 'tdm')
-rw-r--r--tdm/xivo_tdm.c169
-rw-r--r--tdm/xivo_tdm_api.h17
2 files changed, 72 insertions, 114 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);