videocodec.c 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404
  1. /*
  2. * VIDEO MOTION CODECs internal API for video devices
  3. *
  4. * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's
  5. * bound to a master device.
  6. *
  7. * (c) 2002 Wolfgang Scherr <scherr@net4you.at>
  8. *
  9. * $Id: videocodec.c,v 1.1.2.8 2003/03/29 07:16:04 rbultje Exp $
  10. *
  11. * ------------------------------------------------------------------------
  12. *
  13. * This program is free software; you can redistribute it and/or modify
  14. * it under the terms of the GNU General Public License as published by
  15. * the Free Software Foundation; either version 2 of the License, or
  16. * (at your option) any later version.
  17. *
  18. * This program is distributed in the hope that it will be useful,
  19. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  20. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  21. * GNU General Public License for more details.
  22. *
  23. * ------------------------------------------------------------------------
  24. */
  25. #define VIDEOCODEC_VERSION "v0.2"
  26. #include <linux/kernel.h>
  27. #include <linux/module.h>
  28. #include <linux/init.h>
  29. #include <linux/types.h>
  30. #include <linux/slab.h>
  31. // kernel config is here (procfs flag)
  32. #ifdef CONFIG_PROC_FS
  33. #include <linux/proc_fs.h>
  34. #include <linux/seq_file.h>
  35. #include <linux/uaccess.h>
  36. #endif
  37. #include "videocodec.h"
  38. static int debug;
  39. module_param(debug, int, 0);
  40. MODULE_PARM_DESC(debug, "Debug level (0-4)");
  41. #define dprintk(num, format, args...) \
  42. do { \
  43. if (debug >= num) \
  44. printk(format, ##args); \
  45. } while (0)
  46. struct attached_list {
  47. struct videocodec *codec;
  48. struct attached_list *next;
  49. };
  50. struct codec_list {
  51. const struct videocodec *codec;
  52. int attached;
  53. struct attached_list *list;
  54. struct codec_list *next;
  55. };
  56. static struct codec_list *codeclist_top = NULL;
  57. /* ================================================= */
  58. /* function prototypes of the master/slave interface */
  59. /* ================================================= */
  60. struct videocodec *
  61. videocodec_attach (struct videocodec_master *master)
  62. {
  63. struct codec_list *h = codeclist_top;
  64. struct attached_list *a, *ptr;
  65. struct videocodec *codec;
  66. int res;
  67. if (!master) {
  68. dprintk(1, KERN_ERR "videocodec_attach: no data\n");
  69. return NULL;
  70. }
  71. dprintk(2,
  72. "videocodec_attach: '%s', flags %lx, magic %lx\n",
  73. master->name, master->flags, master->magic);
  74. if (!h) {
  75. dprintk(1,
  76. KERN_ERR
  77. "videocodec_attach: no device available\n");
  78. return NULL;
  79. }
  80. while (h) {
  81. // attach only if the slave has at least the flags
  82. // expected by the master
  83. if ((master->flags & h->codec->flags) == master->flags) {
  84. dprintk(4, "videocodec_attach: try '%s'\n",
  85. h->codec->name);
  86. if (!try_module_get(h->codec->owner))
  87. return NULL;
  88. codec = kmemdup(h->codec, sizeof(struct videocodec),
  89. GFP_KERNEL);
  90. if (!codec) {
  91. dprintk(1,
  92. KERN_ERR
  93. "videocodec_attach: no mem\n");
  94. goto out_module_put;
  95. }
  96. res = strlen(codec->name);
  97. snprintf(codec->name + res, sizeof(codec->name) - res,
  98. "[%d]", h->attached);
  99. codec->master_data = master;
  100. res = codec->setup(codec);
  101. if (res == 0) {
  102. dprintk(3, "videocodec_attach '%s'\n",
  103. codec->name);
  104. ptr = kzalloc(sizeof(struct attached_list), GFP_KERNEL);
  105. if (!ptr) {
  106. dprintk(1,
  107. KERN_ERR
  108. "videocodec_attach: no memory\n");
  109. goto out_kfree;
  110. }
  111. ptr->codec = codec;
  112. a = h->list;
  113. if (!a) {
  114. h->list = ptr;
  115. dprintk(4,
  116. "videocodec: first element\n");
  117. } else {
  118. while (a->next)
  119. a = a->next; // find end
  120. a->next = ptr;
  121. dprintk(4,
  122. "videocodec: in after '%s'\n",
  123. h->codec->name);
  124. }
  125. h->attached += 1;
  126. return codec;
  127. } else {
  128. kfree(codec);
  129. }
  130. }
  131. h = h->next;
  132. }
  133. dprintk(1, KERN_ERR "videocodec_attach: no codec found!\n");
  134. return NULL;
  135. out_module_put:
  136. module_put(h->codec->owner);
  137. out_kfree:
  138. kfree(codec);
  139. return NULL;
  140. }
  141. int
  142. videocodec_detach (struct videocodec *codec)
  143. {
  144. struct codec_list *h = codeclist_top;
  145. struct attached_list *a, *prev;
  146. int res;
  147. if (!codec) {
  148. dprintk(1, KERN_ERR "videocodec_detach: no data\n");
  149. return -EINVAL;
  150. }
  151. dprintk(2,
  152. "videocodec_detach: '%s', type: %x, flags %lx, magic %lx\n",
  153. codec->name, codec->type, codec->flags, codec->magic);
  154. if (!h) {
  155. dprintk(1,
  156. KERN_ERR "videocodec_detach: no device left...\n");
  157. return -ENXIO;
  158. }
  159. while (h) {
  160. a = h->list;
  161. prev = NULL;
  162. while (a) {
  163. if (codec == a->codec) {
  164. res = a->codec->unset(a->codec);
  165. if (res >= 0) {
  166. dprintk(3,
  167. "videocodec_detach: '%s'\n",
  168. a->codec->name);
  169. a->codec->master_data = NULL;
  170. } else {
  171. dprintk(1,
  172. KERN_ERR
  173. "videocodec_detach: '%s'\n",
  174. a->codec->name);
  175. a->codec->master_data = NULL;
  176. }
  177. if (prev == NULL) {
  178. h->list = a->next;
  179. dprintk(4,
  180. "videocodec: delete first\n");
  181. } else {
  182. prev->next = a->next;
  183. dprintk(4,
  184. "videocodec: delete middle\n");
  185. }
  186. module_put(a->codec->owner);
  187. kfree(a->codec);
  188. kfree(a);
  189. h->attached -= 1;
  190. return 0;
  191. }
  192. prev = a;
  193. a = a->next;
  194. }
  195. h = h->next;
  196. }
  197. dprintk(1, KERN_ERR "videocodec_detach: given codec not found!\n");
  198. return -EINVAL;
  199. }
  200. int
  201. videocodec_register (const struct videocodec *codec)
  202. {
  203. struct codec_list *ptr, *h = codeclist_top;
  204. if (!codec) {
  205. dprintk(1, KERN_ERR "videocodec_register: no data!\n");
  206. return -EINVAL;
  207. }
  208. dprintk(2,
  209. "videocodec: register '%s', type: %x, flags %lx, magic %lx\n",
  210. codec->name, codec->type, codec->flags, codec->magic);
  211. ptr = kzalloc(sizeof(struct codec_list), GFP_KERNEL);
  212. if (!ptr) {
  213. dprintk(1, KERN_ERR "videocodec_register: no memory\n");
  214. return -ENOMEM;
  215. }
  216. ptr->codec = codec;
  217. if (!h) {
  218. codeclist_top = ptr;
  219. dprintk(4, "videocodec: hooked in as first element\n");
  220. } else {
  221. while (h->next)
  222. h = h->next; // find the end
  223. h->next = ptr;
  224. dprintk(4, "videocodec: hooked in after '%s'\n",
  225. h->codec->name);
  226. }
  227. return 0;
  228. }
  229. int
  230. videocodec_unregister (const struct videocodec *codec)
  231. {
  232. struct codec_list *prev = NULL, *h = codeclist_top;
  233. if (!codec) {
  234. dprintk(1, KERN_ERR "videocodec_unregister: no data!\n");
  235. return -EINVAL;
  236. }
  237. dprintk(2,
  238. "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n",
  239. codec->name, codec->type, codec->flags, codec->magic);
  240. if (!h) {
  241. dprintk(1,
  242. KERN_ERR
  243. "videocodec_unregister: no device left...\n");
  244. return -ENXIO;
  245. }
  246. while (h) {
  247. if (codec == h->codec) {
  248. if (h->attached) {
  249. dprintk(1,
  250. KERN_ERR
  251. "videocodec: '%s' is used\n",
  252. h->codec->name);
  253. return -EBUSY;
  254. }
  255. dprintk(3, "videocodec: unregister '%s' is ok.\n",
  256. h->codec->name);
  257. if (prev == NULL) {
  258. codeclist_top = h->next;
  259. dprintk(4,
  260. "videocodec: delete first element\n");
  261. } else {
  262. prev->next = h->next;
  263. dprintk(4,
  264. "videocodec: delete middle element\n");
  265. }
  266. kfree(h);
  267. return 0;
  268. }
  269. prev = h;
  270. h = h->next;
  271. }
  272. dprintk(1,
  273. KERN_ERR
  274. "videocodec_unregister: given codec not found!\n");
  275. return -EINVAL;
  276. }
  277. #ifdef CONFIG_PROC_FS
  278. static int proc_videocodecs_show(struct seq_file *m, void *v)
  279. {
  280. struct codec_list *h = codeclist_top;
  281. struct attached_list *a;
  282. seq_printf(m, "<S>lave or attached <M>aster name type flags magic ");
  283. seq_printf(m, "(connected as)\n");
  284. h = codeclist_top;
  285. while (h) {
  286. seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n",
  287. h->codec->name, h->codec->type,
  288. h->codec->flags, h->codec->magic);
  289. a = h->list;
  290. while (a) {
  291. seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n",
  292. a->codec->master_data->name,
  293. a->codec->master_data->type,
  294. a->codec->master_data->flags,
  295. a->codec->master_data->magic,
  296. a->codec->name);
  297. a = a->next;
  298. }
  299. h = h->next;
  300. }
  301. return 0;
  302. }
  303. static int proc_videocodecs_open(struct inode *inode, struct file *file)
  304. {
  305. return single_open(file, proc_videocodecs_show, NULL);
  306. }
  307. static const struct file_operations videocodecs_proc_fops = {
  308. .owner = THIS_MODULE,
  309. .open = proc_videocodecs_open,
  310. .read = seq_read,
  311. .llseek = seq_lseek,
  312. .release = single_release,
  313. };
  314. #endif
  315. /* ===================== */
  316. /* hook in driver module */
  317. /* ===================== */
  318. static int __init
  319. videocodec_init (void)
  320. {
  321. #ifdef CONFIG_PROC_FS
  322. static struct proc_dir_entry *videocodec_proc_entry;
  323. #endif
  324. printk(KERN_INFO "Linux video codec intermediate layer: %s\n",
  325. VIDEOCODEC_VERSION);
  326. #ifdef CONFIG_PROC_FS
  327. videocodec_proc_entry = proc_create("videocodecs", 0, NULL, &videocodecs_proc_fops);
  328. if (!videocodec_proc_entry) {
  329. dprintk(1, KERN_ERR "videocodec: can't init procfs.\n");
  330. }
  331. #endif
  332. return 0;
  333. }
  334. static void __exit
  335. videocodec_exit (void)
  336. {
  337. #ifdef CONFIG_PROC_FS
  338. remove_proc_entry("videocodecs", NULL);
  339. #endif
  340. }
  341. EXPORT_SYMBOL(videocodec_attach);
  342. EXPORT_SYMBOL(videocodec_detach);
  343. EXPORT_SYMBOL(videocodec_register);
  344. EXPORT_SYMBOL(videocodec_unregister);
  345. module_init(videocodec_init);
  346. module_exit(videocodec_exit);
  347. MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>");
  348. MODULE_DESCRIPTION("Intermediate API module for video codecs "
  349. VIDEOCODEC_VERSION);
  350. MODULE_LICENSE("GPL");