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