162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * dsp_hwec.c:
462306a36Sopenharmony_ci * builtin mISDN dsp pipeline element for enabling the hw echocanceller
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2007, Nadi Sarrar
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci * Nadi Sarrar <nadi@beronet.com>
962306a36Sopenharmony_ci */
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include <linux/kernel.h>
1262306a36Sopenharmony_ci#include <linux/string.h>
1362306a36Sopenharmony_ci#include <linux/mISDNdsp.h>
1462306a36Sopenharmony_ci#include <linux/mISDNif.h>
1562306a36Sopenharmony_ci#include "core.h"
1662306a36Sopenharmony_ci#include "dsp.h"
1762306a36Sopenharmony_ci#include "dsp_hwec.h"
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_cistatic struct mISDN_dsp_element_arg args[] = {
2062306a36Sopenharmony_ci	{ "deftaps", "128", "Set the number of taps of cancellation." },
2162306a36Sopenharmony_ci};
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_cistatic struct mISDN_dsp_element dsp_hwec_p = {
2462306a36Sopenharmony_ci	.name = "hwec",
2562306a36Sopenharmony_ci	.new = NULL,
2662306a36Sopenharmony_ci	.free = NULL,
2762306a36Sopenharmony_ci	.process_tx = NULL,
2862306a36Sopenharmony_ci	.process_rx = NULL,
2962306a36Sopenharmony_ci	.num_args = ARRAY_SIZE(args),
3062306a36Sopenharmony_ci	.args = args,
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_cistruct mISDN_dsp_element *dsp_hwec = &dsp_hwec_p;
3362306a36Sopenharmony_ci
3462306a36Sopenharmony_civoid dsp_hwec_enable(struct dsp *dsp, const char *arg)
3562306a36Sopenharmony_ci{
3662306a36Sopenharmony_ci	int deftaps = 128,
3762306a36Sopenharmony_ci		len;
3862306a36Sopenharmony_ci	struct mISDN_ctrl_req	cq;
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_ci	if (!dsp) {
4162306a36Sopenharmony_ci		printk(KERN_ERR "%s: failed to enable hwec: dsp is NULL\n",
4262306a36Sopenharmony_ci		       __func__);
4362306a36Sopenharmony_ci		return;
4462306a36Sopenharmony_ci	}
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci	if (!arg)
4762306a36Sopenharmony_ci		goto _do;
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	len = strlen(arg);
5062306a36Sopenharmony_ci	if (!len)
5162306a36Sopenharmony_ci		goto _do;
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci	{
5462306a36Sopenharmony_ci		char *dup, *tok, *name, *val;
5562306a36Sopenharmony_ci		int tmp;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci		dup = kstrdup(arg, GFP_ATOMIC);
5862306a36Sopenharmony_ci		if (!dup)
5962306a36Sopenharmony_ci			return;
6062306a36Sopenharmony_ci
6162306a36Sopenharmony_ci		while ((tok = strsep(&dup, ","))) {
6262306a36Sopenharmony_ci			if (!strlen(tok))
6362306a36Sopenharmony_ci				continue;
6462306a36Sopenharmony_ci			name = strsep(&tok, "=");
6562306a36Sopenharmony_ci			val = tok;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci			if (!val)
6862306a36Sopenharmony_ci				continue;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci			if (!strcmp(name, "deftaps")) {
7162306a36Sopenharmony_ci				if (sscanf(val, "%d", &tmp) == 1)
7262306a36Sopenharmony_ci					deftaps = tmp;
7362306a36Sopenharmony_ci			}
7462306a36Sopenharmony_ci		}
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci		kfree(dup);
7762306a36Sopenharmony_ci	}
7862306a36Sopenharmony_ci
7962306a36Sopenharmony_ci_do:
8062306a36Sopenharmony_ci	printk(KERN_DEBUG "%s: enabling hwec with deftaps=%d\n",
8162306a36Sopenharmony_ci	       __func__, deftaps);
8262306a36Sopenharmony_ci	memset(&cq, 0, sizeof(cq));
8362306a36Sopenharmony_ci	cq.op = MISDN_CTRL_HFC_ECHOCAN_ON;
8462306a36Sopenharmony_ci	cq.p1 = deftaps;
8562306a36Sopenharmony_ci	if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) {
8662306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n",
8762306a36Sopenharmony_ci		       __func__);
8862306a36Sopenharmony_ci		return;
8962306a36Sopenharmony_ci	}
9062306a36Sopenharmony_ci}
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_civoid dsp_hwec_disable(struct dsp *dsp)
9362306a36Sopenharmony_ci{
9462306a36Sopenharmony_ci	struct mISDN_ctrl_req	cq;
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci	if (!dsp) {
9762306a36Sopenharmony_ci		printk(KERN_ERR "%s: failed to disable hwec: dsp is NULL\n",
9862306a36Sopenharmony_ci		       __func__);
9962306a36Sopenharmony_ci		return;
10062306a36Sopenharmony_ci	}
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	printk(KERN_DEBUG "%s: disabling hwec\n", __func__);
10362306a36Sopenharmony_ci	memset(&cq, 0, sizeof(cq));
10462306a36Sopenharmony_ci	cq.op = MISDN_CTRL_HFC_ECHOCAN_OFF;
10562306a36Sopenharmony_ci	if (!dsp->ch.peer->ctrl(&dsp->ch, CONTROL_CHANNEL, &cq)) {
10662306a36Sopenharmony_ci		printk(KERN_DEBUG "%s: CONTROL_CHANNEL failed\n",
10762306a36Sopenharmony_ci		       __func__);
10862306a36Sopenharmony_ci		return;
10962306a36Sopenharmony_ci	}
11062306a36Sopenharmony_ci}
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ciint dsp_hwec_init(void)
11362306a36Sopenharmony_ci{
11462306a36Sopenharmony_ci	mISDN_dsp_element_register(dsp_hwec);
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return 0;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_civoid dsp_hwec_exit(void)
12062306a36Sopenharmony_ci{
12162306a36Sopenharmony_ci	mISDN_dsp_element_unregister(dsp_hwec);
12262306a36Sopenharmony_ci}
123