dsp_pipeline.c 6.5 KB

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