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 * You should have received a copy of the GNU General Public License 24 * along with this program; if not, write to the Free Software 25 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 26 * 27 * ------------------------------------------------------------------------ 28 */ 29 30 #define VIDEOCODEC_VERSION "v0.2" 31 32 #include <linux/kernel.h> 33 #include <linux/module.h> 34 #include <linux/init.h> 35 #include <linux/types.h> 36 #include <linux/slab.h> 37 38 // kernel config is here (procfs flag) 39 40 #ifdef CONFIG_PROC_FS 41 #include <linux/proc_fs.h> 42 #include <linux/seq_file.h> 43 #include <asm/uaccess.h> 44 #endif 45 46 #include "videocodec.h" 47 48 static int debug; 49 module_param(debug, int, 0); 50 MODULE_PARM_DESC(debug, "Debug level (0-4)"); 51 52 #define dprintk(num, format, args...) \ 53 do { \ 54 if (debug >= num) \ 55 printk(format, ##args); \ 56 } while (0) 57 58 struct attached_list { 59 struct videocodec *codec; 60 struct attached_list *next; 61 }; 62 63 struct codec_list { 64 const struct videocodec *codec; 65 int attached; 66 struct attached_list *list; 67 struct codec_list *next; 68 }; 69 70 static struct codec_list *codeclist_top = NULL; 71 72 /* ================================================= */ 73 /* function prototypes of the master/slave interface */ 74 /* ================================================= */ 75 76 struct videocodec * 77 videocodec_attach (struct videocodec_master *master) 78 { 79 struct codec_list *h = codeclist_top; 80 struct attached_list *a, *ptr; 81 struct videocodec *codec; 82 int res; 83 84 if (!master) { 85 dprintk(1, KERN_ERR "videocodec_attach: no data\n"); 86 return NULL; 87 } 88 89 dprintk(2, 90 "videocodec_attach: '%s', flags %lx, magic %lx\n", 91 master->name, master->flags, master->magic); 92 93 if (!h) { 94 dprintk(1, 95 KERN_ERR 96 "videocodec_attach: no device available\n"); 97 return NULL; 98 } 99 100 while (h) { 101 // attach only if the slave has at least the flags 102 // expected by the master 103 if ((master->flags & h->codec->flags) == master->flags) { 104 dprintk(4, "videocodec_attach: try '%s'\n", 105 h->codec->name); 106 107 if (!try_module_get(h->codec->owner)) 108 return NULL; 109 110 codec = kmemdup(h->codec, sizeof(struct videocodec), 111 GFP_KERNEL); 112 if (!codec) { 113 dprintk(1, 114 KERN_ERR 115 "videocodec_attach: no mem\n"); 116 goto out_module_put; 117 } 118 119 res = strlen(codec->name); 120 snprintf(codec->name + res, sizeof(codec->name) - res, 121 "[%d]", h->attached); 122 codec->master_data = master; 123 res = codec->setup(codec); 124 if (res == 0) { 125 dprintk(3, "videocodec_attach '%s'\n", 126 codec->name); 127 ptr = kzalloc(sizeof(struct attached_list), GFP_KERNEL); 128 if (!ptr) { 129 dprintk(1, 130 KERN_ERR 131 "videocodec_attach: no memory\n"); 132 goto out_kfree; 133 } 134 ptr->codec = codec; 135 136 a = h->list; 137 if (!a) { 138 h->list = ptr; 139 dprintk(4, 140 "videocodec: first element\n"); 141 } else { 142 while (a->next) 143 a = a->next; // find end 144 a->next = ptr; 145 dprintk(4, 146 "videocodec: in after '%s'\n", 147 h->codec->name); 148 } 149 150 h->attached += 1; 151 return codec; 152 } else { 153 kfree(codec); 154 } 155 } 156 h = h->next; 157 } 158 159 dprintk(1, KERN_ERR "videocodec_attach: no codec found!\n"); 160 return NULL; 161 162 out_module_put: 163 module_put(h->codec->owner); 164 out_kfree: 165 kfree(codec); 166 return NULL; 167 } 168 169 int 170 videocodec_detach (struct videocodec *codec) 171 { 172 struct codec_list *h = codeclist_top; 173 struct attached_list *a, *prev; 174 int res; 175 176 if (!codec) { 177 dprintk(1, KERN_ERR "videocodec_detach: no data\n"); 178 return -EINVAL; 179 } 180 181 dprintk(2, 182 "videocodec_detach: '%s', type: %x, flags %lx, magic %lx\n", 183 codec->name, codec->type, codec->flags, codec->magic); 184 185 if (!h) { 186 dprintk(1, 187 KERN_ERR "videocodec_detach: no device left...\n"); 188 return -ENXIO; 189 } 190 191 while (h) { 192 a = h->list; 193 prev = NULL; 194 while (a) { 195 if (codec == a->codec) { 196 res = a->codec->unset(a->codec); 197 if (res >= 0) { 198 dprintk(3, 199 "videocodec_detach: '%s'\n", 200 a->codec->name); 201 a->codec->master_data = NULL; 202 } else { 203 dprintk(1, 204 KERN_ERR 205 "videocodec_detach: '%s'\n", 206 a->codec->name); 207 a->codec->master_data = NULL; 208 } 209 if (prev == NULL) { 210 h->list = a->next; 211 dprintk(4, 212 "videocodec: delete first\n"); 213 } else { 214 prev->next = a->next; 215 dprintk(4, 216 "videocodec: delete middle\n"); 217 } 218 module_put(a->codec->owner); 219 kfree(a->codec); 220 kfree(a); 221 h->attached -= 1; 222 return 0; 223 } 224 prev = a; 225 a = a->next; 226 } 227 h = h->next; 228 } 229 230 dprintk(1, KERN_ERR "videocodec_detach: given codec not found!\n"); 231 return -EINVAL; 232 } 233 234 int 235 videocodec_register (const struct videocodec *codec) 236 { 237 struct codec_list *ptr, *h = codeclist_top; 238 239 if (!codec) { 240 dprintk(1, KERN_ERR "videocodec_register: no data!\n"); 241 return -EINVAL; 242 } 243 244 dprintk(2, 245 "videocodec: register '%s', type: %x, flags %lx, magic %lx\n", 246 codec->name, codec->type, codec->flags, codec->magic); 247 248 ptr = kzalloc(sizeof(struct codec_list), GFP_KERNEL); 249 if (!ptr) { 250 dprintk(1, KERN_ERR "videocodec_register: no memory\n"); 251 return -ENOMEM; 252 } 253 ptr->codec = codec; 254 255 if (!h) { 256 codeclist_top = ptr; 257 dprintk(4, "videocodec: hooked in as first element\n"); 258 } else { 259 while (h->next) 260 h = h->next; // find the end 261 h->next = ptr; 262 dprintk(4, "videocodec: hooked in after '%s'\n", 263 h->codec->name); 264 } 265 266 return 0; 267 } 268 269 int 270 videocodec_unregister (const struct videocodec *codec) 271 { 272 struct codec_list *prev = NULL, *h = codeclist_top; 273 274 if (!codec) { 275 dprintk(1, KERN_ERR "videocodec_unregister: no data!\n"); 276 return -EINVAL; 277 } 278 279 dprintk(2, 280 "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n", 281 codec->name, codec->type, codec->flags, codec->magic); 282 283 if (!h) { 284 dprintk(1, 285 KERN_ERR 286 "videocodec_unregister: no device left...\n"); 287 return -ENXIO; 288 } 289 290 while (h) { 291 if (codec == h->codec) { 292 if (h->attached) { 293 dprintk(1, 294 KERN_ERR 295 "videocodec: '%s' is used\n", 296 h->codec->name); 297 return -EBUSY; 298 } 299 dprintk(3, "videocodec: unregister '%s' is ok.\n", 300 h->codec->name); 301 if (prev == NULL) { 302 codeclist_top = h->next; 303 dprintk(4, 304 "videocodec: delete first element\n"); 305 } else { 306 prev->next = h->next; 307 dprintk(4, 308 "videocodec: delete middle element\n"); 309 } 310 kfree(h); 311 return 0; 312 } 313 prev = h; 314 h = h->next; 315 } 316 317 dprintk(1, 318 KERN_ERR 319 "videocodec_unregister: given codec not found!\n"); 320 return -EINVAL; 321 } 322 323 #ifdef CONFIG_PROC_FS 324 static int proc_videocodecs_show(struct seq_file *m, void *v) 325 { 326 struct codec_list *h = codeclist_top; 327 struct attached_list *a; 328 329 seq_printf(m, "<S>lave or attached <M>aster name type flags magic "); 330 seq_printf(m, "(connected as)\n"); 331 332 h = codeclist_top; 333 while (h) { 334 seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n", 335 h->codec->name, h->codec->type, 336 h->codec->flags, h->codec->magic); 337 a = h->list; 338 while (a) { 339 seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n", 340 a->codec->master_data->name, 341 a->codec->master_data->type, 342 a->codec->master_data->flags, 343 a->codec->master_data->magic, 344 a->codec->name); 345 a = a->next; 346 } 347 h = h->next; 348 } 349 350 return 0; 351 } 352 353 static int proc_videocodecs_open(struct inode *inode, struct file *file) 354 { 355 return single_open(file, proc_videocodecs_show, NULL); 356 } 357 358 static const struct file_operations videocodecs_proc_fops = { 359 .owner = THIS_MODULE, 360 .open = proc_videocodecs_open, 361 .read = seq_read, 362 .llseek = seq_lseek, 363 .release = single_release, 364 }; 365 #endif 366 367 /* ===================== */ 368 /* hook in driver module */ 369 /* ===================== */ 370 static int __init 371 videocodec_init (void) 372 { 373 #ifdef CONFIG_PROC_FS 374 static struct proc_dir_entry *videocodec_proc_entry; 375 #endif 376 377 printk(KERN_INFO "Linux video codec intermediate layer: %s\n", 378 VIDEOCODEC_VERSION); 379 380 #ifdef CONFIG_PROC_FS 381 videocodec_proc_entry = proc_create("videocodecs", 0, NULL, &videocodecs_proc_fops); 382 if (!videocodec_proc_entry) { 383 dprintk(1, KERN_ERR "videocodec: can't init procfs.\n"); 384 } 385 #endif 386 return 0; 387 } 388 389 static void __exit 390 videocodec_exit (void) 391 { 392 #ifdef CONFIG_PROC_FS 393 remove_proc_entry("videocodecs", NULL); 394 #endif 395 } 396 397 EXPORT_SYMBOL(videocodec_attach); 398 EXPORT_SYMBOL(videocodec_detach); 399 EXPORT_SYMBOL(videocodec_register); 400 EXPORT_SYMBOL(videocodec_unregister); 401 402 module_init(videocodec_init); 403 module_exit(videocodec_exit); 404 405 MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>"); 406 MODULE_DESCRIPTION("Intermediate API module for video codecs " 407 VIDEOCODEC_VERSION); 408 MODULE_LICENSE("GPL"); 409