dsp_pipeline.c 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  1. /*
  2. * dsp_pipeline.c: pipelined audio processing
  3. *
  4. * Copyright (C) 2007, Nadi Sarrar
  5. *
  6. * Nadi Sarrar <nadi@beronet.com>
  7. *
  8. * This program is free software; you can redistribute it and/or modify it
  9. * under the terms of the GNU General Public License as published by the Free
  10. * Software Foundation; either version 2 of the License, or (at your option)
  11. * any later version.
  12. *
  13. * This program is distributed in the hope that it will be useful, but WITHOUT
  14. * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  15. * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  16. * more details.
  17. *
  18. * You should have received a copy of the GNU General Public License along with
  19. * this program; if not, write to the Free Software Foundation, Inc., 59
  20. * Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  21. *
  22. * The full GNU General Public License is included in this distribution in the
  23. * file called LICENSE.
  24. *
  25. */
  26. #include <linux/kernel.h>
  27. #include <linux/list.h>
  28. #include <linux/string.h>
  29. #include <linux/mISDNif.h>
  30. #include <linux/mISDNdsp.h>
  31. #include "dsp.h"
  32. #include "dsp_hwec.h"
  33. /* uncomment for debugging */
  34. /*#define PIPELINE_DEBUG*/
  35. struct dsp_pipeline_entry {
  36. struct mISDN_dsp_element *elem;
  37. void *p;
  38. struct list_head list;
  39. };
  40. struct dsp_element_entry {
  41. struct mISDN_dsp_element *elem;
  42. struct device dev;
  43. struct list_head list;
  44. };
  45. static LIST_HEAD(dsp_elements);
  46. /* sysfs */
  47. static struct class *elements_class;
  48. static ssize_t
  49. attr_show_args(struct device *dev, struct device_attribute *attr, char *buf)
  50. {
  51. struct mISDN_dsp_element *elem = dev_get_drvdata(dev);
  52. ssize_t len = 0;
  53. int i = 0;
  54. *buf = 0;
  55. for (; i < elem->num_args; ++i)
  56. len = sprintf(buf, "%sName: %s\n%s%s%sDescription: %s\n"
  57. "\n", buf,
  58. elem->args[i].name,
  59. elem->args[i].def ? "Default: " : "",
  60. elem->args[i].def ? elem->args[i].def : "",
  61. elem->args[i].def ? "\n" : "",
  62. elem->args[i].desc);
  63. return len;
  64. }
  65. static struct device_attribute element_attributes[] = {
  66. __ATTR(args, 0444, attr_show_args, NULL),
  67. };
  68. int mISDN_dsp_element_register(struct mISDN_dsp_element *elem)
  69. {
  70. struct dsp_element_entry *entry;
  71. int ret, i;
  72. if (!elem)
  73. return -EINVAL;
  74. entry = kzalloc(sizeof(struct dsp_element_entry), GFP_KERNEL);
  75. if (!entry)
  76. return -ENOMEM;
  77. entry->elem = elem;
  78. entry->dev.class = elements_class;
  79. dev_set_drvdata(&entry->dev, elem);
  80. snprintf(entry->dev.bus_id, BUS_ID_SIZE, elem->name);
  81. ret = device_register(&entry->dev);
  82. if (ret) {
  83. printk(KERN_ERR "%s: failed to register %s\n",
  84. __func__, elem->name);
  85. goto err1;
  86. }
  87. for (i = 0; i < (sizeof(element_attributes)
  88. / sizeof(struct device_attribute)); ++i)
  89. ret = device_create_file(&entry->dev,
  90. &element_attributes[i]);
  91. if (ret) {
  92. printk(KERN_ERR "%s: failed to create device file\n",
  93. __func__);
  94. goto err2;
  95. }
  96. list_add_tail(&entry->list, &dsp_elements);
  97. printk(KERN_DEBUG "%s: %s registered\n", __func__, elem->name);
  98. return 0;
  99. err2:
  100. device_unregister(&entry->dev);
  101. err1:
  102. kfree(entry);
  103. return ret;
  104. }
  105. EXPORT_SYMBOL(mISDN_dsp_element_register);
  106. void mISDN_dsp_element_unregister(struct mISDN_dsp_element *elem)
  107. {
  108. struct dsp_element_entry *entry, *n;
  109. if (!elem)
  110. return;
  111. list_for_each_entry_safe(entry, n, &dsp_elements, list)
  112. if (entry->elem == elem) {
  113. list_del(&entry->list);
  114. device_unregister(&entry->dev);
  115. kfree(entry);
  116. printk(KERN_DEBUG "%s: %s unregistered\n",
  117. __func__, elem->name);
  118. return;
  119. }
  120. printk(KERN_ERR "%s: element %s not in list.\n", __func__, elem->name);
  121. }
  122. EXPORT_SYMBOL(mISDN_dsp_element_unregister);
  123. int dsp_pipeline_module_init(void)
  124. {
  125. elements_class = class_create(THIS_MODULE, "dsp_pipeline");
  126. if (IS_ERR(elements_class))
  127. return PTR_ERR(elements_class);
  128. #ifdef PIPELINE_DEBUG
  129. printk(KERN_DEBUG "%s: dsp pipeline module initialized\n", __func__);
  130. #endif
  131. dsp_hwec_init();
  132. return 0;
  133. }
  134. void dsp_pipeline_module_exit(void)
  135. {
  136. struct dsp_element_entry *entry, *n;
  137. dsp_hwec_exit();
  138. class_destroy(elements_class);
  139. list_for_each_entry_safe(entry, n, &dsp_elements, list) {
  140. list_del(&entry->list);
  141. printk(KERN_WARNING "%s: element was still registered: %s\n",
  142. __func__, entry->elem->name);
  143. kfree(entry);
  144. }
  145. printk(KERN_DEBUG "%s: dsp pipeline module exited\n", __func__);
  146. }
  147. int dsp_pipeline_init(struct dsp_pipeline *pipeline)
  148. {
  149. if (!pipeline)
  150. return -EINVAL;
  151. INIT_LIST_HEAD(&pipeline->list);
  152. #ifdef PIPELINE_DEBUG
  153. printk(KERN_DEBUG "%s: dsp pipeline ready\n", __func__);
  154. #endif
  155. return 0;
  156. }
  157. static inline void _dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
  158. {
  159. struct dsp_pipeline_entry *entry, *n;
  160. list_for_each_entry_safe(entry, n, &pipeline->list, list) {
  161. list_del(&entry->list);
  162. if (entry->elem == dsp_hwec)
  163. dsp_hwec_disable(container_of(pipeline, struct dsp,
  164. pipeline));
  165. else
  166. entry->elem->free(entry->p);
  167. kfree(entry);
  168. }
  169. }
  170. void dsp_pipeline_destroy(struct dsp_pipeline *pipeline)
  171. {
  172. if (!pipeline)
  173. return;
  174. _dsp_pipeline_destroy(pipeline);
  175. #ifdef PIPELINE_DEBUG
  176. printk(KERN_DEBUG "%s: dsp pipeline destroyed\n", __func__);
  177. #endif
  178. }
  179. int dsp_pipeline_build(struct dsp_pipeline *pipeline, const char *cfg)
  180. {
  181. int len, incomplete = 0, found = 0;
  182. char *dup, *tok, *name, *args;
  183. struct dsp_element_entry *entry, *n;
  184. struct dsp_pipeline_entry *pipeline_entry;
  185. struct mISDN_dsp_element *elem;
  186. if (!pipeline)
  187. return -EINVAL;
  188. if (!list_empty(&pipeline->list))
  189. _dsp_pipeline_destroy(pipeline);
  190. if (!cfg)
  191. return 0;
  192. len = strlen(cfg);
  193. if (!len)
  194. return 0;
  195. dup = kmalloc(len + 1, GFP_KERNEL);
  196. if (!dup)
  197. return 0;
  198. strcpy(dup, cfg);
  199. while ((tok = strsep(&dup, "|"))) {
  200. if (!strlen(tok))
  201. continue;
  202. name = strsep(&tok, "(");
  203. args = strsep(&tok, ")");
  204. if (args && !*args)
  205. args = 0;
  206. list_for_each_entry_safe(entry, n, &dsp_elements, list)
  207. if (!strcmp(entry->elem->name, name)) {
  208. elem = entry->elem;
  209. pipeline_entry = kmalloc(sizeof(struct
  210. dsp_pipeline_entry), GFP_KERNEL);
  211. if (!pipeline_entry) {
  212. printk(KERN_DEBUG "%s: failed to add "
  213. "entry to pipeline: %s (out of "
  214. "memory)\n", __func__, elem->name);
  215. incomplete = 1;
  216. goto _out;
  217. }
  218. pipeline_entry->elem = elem;
  219. if (elem == dsp_hwec) {
  220. /* This is a hack to make the hwec
  221. available as a pipeline module */
  222. dsp_hwec_enable(container_of(pipeline,
  223. struct dsp, pipeline), args);
  224. list_add_tail(&pipeline_entry->list,
  225. &pipeline->list);
  226. } else {
  227. pipeline_entry->p = elem->new(args);
  228. if (pipeline_entry->p) {
  229. list_add_tail(&pipeline_entry->
  230. list, &pipeline->list);
  231. #ifdef PIPELINE_DEBUG
  232. printk(KERN_DEBUG "%s: created "
  233. "instance of %s%s%s\n",
  234. __func__, name, args ?
  235. " with args " : "", args ?
  236. args : "");
  237. #endif
  238. } else {
  239. printk(KERN_DEBUG "%s: failed "
  240. "to add entry to pipeline: "
  241. "%s (new() returned NULL)\n",
  242. __func__, elem->name);
  243. kfree(pipeline_entry);
  244. incomplete = 1;
  245. }
  246. }
  247. found = 1;
  248. break;
  249. }
  250. if (found)
  251. found = 0;
  252. else {
  253. printk(KERN_DEBUG "%s: element not found, skipping: "
  254. "%s\n", __func__, name);
  255. incomplete = 1;
  256. }
  257. }
  258. _out:
  259. if (!list_empty(&pipeline->list))
  260. pipeline->inuse = 1;
  261. else
  262. pipeline->inuse = 0;
  263. #ifdef PIPELINE_DEBUG
  264. printk(KERN_DEBUG "%s: dsp pipeline built%s: %s\n",
  265. __func__, incomplete ? " incomplete" : "", cfg);
  266. #endif
  267. kfree(dup);
  268. return 0;
  269. }
  270. void dsp_pipeline_process_tx(struct dsp_pipeline *pipeline, u8 *data, int len)
  271. {
  272. struct dsp_pipeline_entry *entry;
  273. if (!pipeline)
  274. return;
  275. list_for_each_entry(entry, &pipeline->list, list)
  276. if (entry->elem->process_tx)
  277. entry->elem->process_tx(entry->p, data, len);
  278. }
  279. void dsp_pipeline_process_rx(struct dsp_pipeline *pipeline, u8 *data, int len)
  280. {
  281. struct dsp_pipeline_entry *entry;
  282. if (!pipeline)
  283. return;
  284. list_for_each_entry_reverse(entry, &pipeline->list, list)
  285. if (entry->elem->process_rx)
  286. entry->elem->process_rx(entry->p, data, len);
  287. }