brintos

brintos / linux-shallow public Read only

0
0
Text · 6.5 KiB · b4ed0bb Raw
301 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * dsp_pipeline.c: pipelined audio processing4 *5 * Copyright (C) 2007, Nadi Sarrar6 *7 * Nadi Sarrar <nadi@beronet.com>8 */9 10#include <linux/kernel.h>11#include <linux/slab.h>12#include <linux/list.h>13#include <linux/string.h>14#include <linux/mISDNif.h>15#include <linux/mISDNdsp.h>16#include <linux/export.h>17#include "dsp.h"18#include "dsp_hwec.h"19 20struct dsp_pipeline_entry {21	struct mISDN_dsp_element *elem;22	void                *p;23	struct list_head     list;24};25struct dsp_element_entry {26	struct mISDN_dsp_element *elem;27	struct device	     dev;28	struct list_head     list;29};30 31static LIST_HEAD(dsp_elements);32 33/* sysfs */34static const struct class elements_class = {35	.name = "dsp_pipeline",36};37 38static ssize_t39attr_show_args(struct device *dev, struct device_attribute *attr, char *buf)40{41	struct mISDN_dsp_element *elem = dev_get_drvdata(dev);42	int i;43	char *p = buf;44 45	*buf = 0;46	for (i = 0; i < elem->num_args; i++)47		p += sprintf(p, "Name:        %s\n%s%s%sDescription: %s\n\n",48			     elem->args[i].name,49			     elem->args[i].def ? "Default:     " : "",50			     elem->args[i].def ? elem->args[i].def : "",51			     elem->args[i].def ? "\n" : "",52			     elem->args[i].desc);53 54	return p - buf;55}56 57static struct device_attribute element_attributes[] = {58	__ATTR(args, 0444, attr_show_args, NULL),59};60 61static void62mISDN_dsp_dev_release(struct device *dev)63{64	struct dsp_element_entry *entry =65		container_of(dev, struct dsp_element_entry, dev);66	list_del(&entry->list);67	kfree(entry);68}69 70int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)71{72	struct dsp_element_entry *entry;73	int ret, i;74 75	if (!elem)76		return -EINVAL;77 78	entry = kzalloc(sizeof(struct dsp_element_entry), GFP_ATOMIC);79	if (!entry)80		return -ENOMEM;81 82	INIT_LIST_HEAD(&entry->list);83	entry->elem = elem;84 85	entry->dev.class = &elements_class;86	entry->dev.release = mISDN_dsp_dev_release;87	dev_set_drvdata(&entry->dev, elem);88	dev_set_name(&entry->dev, "%s", elem->name);89	ret = device_register(&entry->dev);90	if (ret) {91		printk(KERN_ERR "%s: failed to register %s\n",92		       __func__, elem->name);93		goto err1;94	}95	list_add_tail(&entry->list, &dsp_elements);96 97	for (i = 0; i < ARRAY_SIZE(element_attributes); ++i) {98		ret = device_create_file(&entry->dev,99					 &element_attributes[i]);100		if (ret) {101			printk(KERN_ERR "%s: failed to create device file\n",102			       __func__);103			goto err2;104		}105	}106 107	return 0;108 109err2:110	device_unregister(&entry->dev);111	return ret;112err1:113	put_device(&entry->dev);114	return ret;115}116EXPORT_SYMBOL(mISDN_dsp_element_register);117 118void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem)119{120	struct dsp_element_entry *entry, *n;121 122	if (!elem)123		return;124 125	list_for_each_entry_safe(entry, n, &dsp_elements, list)126		if (entry->elem == elem) {127			device_unregister(&entry->dev);128			return;129		}130	printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name);131}132EXPORT_SYMBOL(mISDN_dsp_element_unregister);133 134int dsp_pipeline_module_init(void)135{136	int err;137 138	err = class_register(&elements_class);139	if (err)140		return err;141 142	dsp_hwec_init();143 144	return 0;145}146 147void dsp_pipeline_module_exit(void)148{149	struct dsp_element_entry *entry, *n;150 151	dsp_hwec_exit();152 153	class_unregister(&elements_class);154 155	list_for_each_entry_safe(entry, n, &dsp_elements, list) {156		list_del(&entry->list);157		printk(KERN_WARNING "%s: element was still registered: %s\n",158		       __func__, entry->elem->name);159		kfree(entry);160	}161}162 163int dsp_pipeline_init(struct dsp_pipeline *pipeline)164{165	if (!pipeline)166		return -EINVAL;167 168	INIT_LIST_HEAD(&pipeline->list);169 170	return 0;171}172 173static inline void _dsp_pipeline_destroy(struct dsp_pipeline *pipeline)174{175	struct dsp_pipeline_entry *entry, *n;176 177	list_for_each_entry_safe(entry, n, &pipeline->list, list) {178		list_del(&entry->list);179		if (entry->elem == dsp_hwec)180			dsp_hwec_disable(container_of(pipeline, struct dsp,181						      pipeline));182		else183			entry->elem->free(entry->p);184		kfree(entry);185	}186}187 188void dsp_pipeline_destroy(struct dsp_pipeline *pipeline)189{190 191	if (!pipeline)192		return;193 194	_dsp_pipeline_destroy(pipeline);195}196 197int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)198{199	int found = 0;200	char *dup, *next, *tok, *name, *args;201	struct dsp_element_entry *entry, *n;202	struct dsp_pipeline_entry *pipeline_entry;203	struct mISDN_dsp_element *elem;204 205	if (!pipeline)206		return -EINVAL;207 208	if (!list_empty(&pipeline->list))209		_dsp_pipeline_destroy(pipeline);210 211	dup = next = kstrdup(cfg, GFP_ATOMIC);212	if (!dup)213		return 0;214	while ((tok = strsep(&next, "|"))) {215		if (!strlen(tok))216			continue;217		name = strsep(&tok, "(");218		args = strsep(&tok, ")");219		if (args && !*args)220			args = NULL;221 222		list_for_each_entry_safe(entry, n, &dsp_elements, list)223			if (!strcmp(entry->elem->name, name)) {224				elem = entry->elem;225 226				pipeline_entry = kmalloc(sizeof(struct227								dsp_pipeline_entry), GFP_ATOMIC);228				if (!pipeline_entry) {229					printk(KERN_ERR "%s: failed to add "230					       "entry to pipeline: %s (out of "231					       "memory)\n", __func__, elem->name);232					goto _out;233				}234				pipeline_entry->elem = elem;235 236				if (elem == dsp_hwec) {237					/* This is a hack to make the hwec238					   available as a pipeline module */239					dsp_hwec_enable(container_of(pipeline,240								     struct dsp, pipeline), args);241					list_add_tail(&pipeline_entry->list,242						      &pipeline->list);243				} else {244					pipeline_entry->p = elem->new(args);245					if (pipeline_entry->p) {246						list_add_tail(&pipeline_entry->247							      list, &pipeline->list);248					} else {249						printk(KERN_ERR "%s: failed "250						       "to add entry to pipeline: "251						       "%s (new() returned NULL)\n",252						       __func__, elem->name);253						kfree(pipeline_entry);254					}255				}256				found = 1;257				break;258			}259 260		if (found)261			found = 0;262		else263			printk(KERN_ERR "%s: element not found, skipping: "264			       "%s\n", __func__, name);265	}266 267_out:268	if (!list_empty(&pipeline->list))269		pipeline->inuse = 1;270	else271		pipeline->inuse = 0;272 273	kfree(dup);274	return 0;275}276 277void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len)278{279	struct dsp_pipeline_entry *entry;280 281	if (!pipeline)282		return;283 284	list_for_each_entry(entry, &pipeline->list, list)285		if (entry->elem->process_tx)286			entry->elem->process_tx(entry->p, data, len);287}288 289void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len,290			     unsigned int txlen)291{292	struct dsp_pipeline_entry *entry;293 294	if (!pipeline)295		return;296 297	list_for_each_entry_reverse(entry, &pipeline->list, list)298		if (entry->elem->process_rx)299			entry->elem->process_rx(entry->p, data, len, txlen);300}301