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.1.1 2007/08/03 18:52:40 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 <asm/uaccess.h> 43#endif 44 45#include "videocodec.h" 46 47static int debug = 0; 48module_param(debug, int, 0); 49MODULE_PARM_DESC(debug, "Debug level (0-4)"); 50 51#define dprintk(num, format, args...) \ 52 do { \ 53 if (debug >= num) \ 54 printk(format, ##args); \ 55 } while (0) 56 57struct attached_list { 58 struct videocodec *codec; 59 struct attached_list *next; 60}; 61 62struct codec_list { 63 const struct videocodec *codec; 64 int attached; 65 struct attached_list *list; 66 struct codec_list *next; 67}; 68 69static struct codec_list *codeclist_top = NULL; 70 71/* ================================================= */ 72/* function prototypes of the master/slave interface */ 73/* ================================================= */ 74 75struct videocodec * 76videocodec_attach (struct videocodec_master *master) 77{ 78 struct codec_list *h = codeclist_top; 79 struct attached_list *a, *ptr; 80 struct videocodec *codec; 81 int res; 82 83 if (!master) { 84 dprintk(1, KERN_ERR "videocodec_attach: no data\n"); 85 return NULL; 86 } 87 88 dprintk(2, 89 "videocodec_attach: '%s', type: %x, flags %lx, magic %lx\n", 90 master->name, master->type, master->flags, master->magic); 91 92 if (!h) { 93 dprintk(1, 94 KERN_ERR 95 "videocodec_attach: no device available\n"); 96 return NULL; 97 } 98 99 while (h) { 100 // attach only if the slave has at least the flags 101 // expected by the master 102 if ((master->flags & h->codec->flags) == master->flags) { 103 dprintk(4, "videocodec_attach: try '%s'\n", 104 h->codec->name); 105 106 if (!try_module_get(h->codec->owner)) 107 return NULL; 108 109 codec = 110 kmalloc(sizeof(struct videocodec), GFP_KERNEL); 111 if (!codec) { 112 dprintk(1, 113 KERN_ERR 114 "videocodec_attach: no mem\n"); 115 goto out_module_put; 116 } 117 memcpy(codec, h->codec, sizeof(struct videocodec)); 118 119 snprintf(codec->name, sizeof(codec->name), 120 "%s[%d]", codec->name, h->attached); 121 codec->master_data = master; 122 res = codec->setup(codec); 123 if (res == 0) { 124 dprintk(3, "videocodec_attach '%s'\n", 125 codec->name); 126 ptr = kzalloc(sizeof(struct attached_list), GFP_KERNEL); 127 if (!ptr) { 128 dprintk(1, 129 KERN_ERR 130 "videocodec_attach: no memory\n"); 131 goto out_kfree; 132 } 133 ptr->codec = codec; 134 135 a = h->list; 136 if (!a) { 137 h->list = ptr; 138 dprintk(4, 139 "videocodec: first element\n"); 140 } else { 141 while (a->next) 142 a = a->next; // find end 143 a->next = ptr; 144 dprintk(4, 145 "videocodec: in after '%s'\n", 146 h->codec->name); 147 } 148 149 h->attached += 1; 150 return codec; 151 } else { 152 kfree(codec); 153 } 154 } 155 h = h->next; 156 } 157 158 dprintk(1, KERN_ERR "videocodec_attach: no codec found!\n"); 159 return NULL; 160 161 out_module_put: 162 module_put(h->codec->owner); 163 out_kfree: 164 kfree(codec); 165 return NULL; 166} 167 168int 169videocodec_detach (struct videocodec *codec) 170{ 171 struct codec_list *h = codeclist_top; 172 struct attached_list *a, *prev; 173 int res; 174 175 if (!codec) { 176 dprintk(1, KERN_ERR "videocodec_detach: no data\n"); 177 return -EINVAL; 178 } 179 180 dprintk(2, 181 "videocodec_detach: '%s', type: %x, flags %lx, magic %lx\n", 182 codec->name, codec->type, codec->flags, codec->magic); 183 184 if (!h) { 185 dprintk(1, 186 KERN_ERR "videocodec_detach: no device left...\n"); 187 return -ENXIO; 188 } 189 190 while (h) { 191 a = h->list; 192 prev = NULL; 193 while (a) { 194 if (codec == a->codec) { 195 res = a->codec->unset(a->codec); 196 if (res >= 0) { 197 dprintk(3, 198 "videocodec_detach: '%s'\n", 199 a->codec->name); 200 a->codec->master_data = NULL; 201 } else { 202 dprintk(1, 203 KERN_ERR 204 "videocodec_detach: '%s'\n", 205 a->codec->name); 206 a->codec->master_data = NULL; 207 } 208 if (prev == NULL) { 209 h->list = a->next; 210 dprintk(4, 211 "videocodec: delete first\n"); 212 } else { 213 prev->next = a->next; 214 dprintk(4, 215 "videocodec: delete middle\n"); 216 } 217 module_put(a->codec->owner); 218 kfree(a->codec); 219 kfree(a); 220 h->attached -= 1; 221 return 0; 222 } 223 prev = a; 224 a = a->next; 225 } 226 h = h->next; 227 } 228 229 dprintk(1, KERN_ERR "videocodec_detach: given codec not found!\n"); 230 return -EINVAL; 231} 232 233int 234videocodec_register (const struct videocodec *codec) 235{ 236 struct codec_list *ptr, *h = codeclist_top; 237 238 if (!codec) { 239 dprintk(1, KERN_ERR "videocodec_register: no data!\n"); 240 return -EINVAL; 241 } 242 243 dprintk(2, 244 "videocodec: register '%s', type: %x, flags %lx, magic %lx\n", 245 codec->name, codec->type, codec->flags, codec->magic); 246 247 ptr = kzalloc(sizeof(struct codec_list), GFP_KERNEL); 248 if (!ptr) { 249 dprintk(1, KERN_ERR "videocodec_register: no memory\n"); 250 return -ENOMEM; 251 } 252 ptr->codec = codec; 253 254 if (!h) { 255 codeclist_top = ptr; 256 dprintk(4, "videocodec: hooked in as first element\n"); 257 } else { 258 while (h->next) 259 h = h->next; // find the end 260 h->next = ptr; 261 dprintk(4, "videocodec: hooked in after '%s'\n", 262 h->codec->name); 263 } 264 265 return 0; 266} 267 268int 269videocodec_unregister (const struct videocodec *codec) 270{ 271 struct codec_list *prev = NULL, *h = codeclist_top; 272 273 if (!codec) { 274 dprintk(1, KERN_ERR "videocodec_unregister: no data!\n"); 275 return -EINVAL; 276 } 277 278 dprintk(2, 279 "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n", 280 codec->name, codec->type, codec->flags, codec->magic); 281 282 if (!h) { 283 dprintk(1, 284 KERN_ERR 285 "videocodec_unregister: no device left...\n"); 286 return -ENXIO; 287 } 288 289 while (h) { 290 if (codec == h->codec) { 291 if (h->attached) { 292 dprintk(1, 293 KERN_ERR 294 "videocodec: '%s' is used\n", 295 h->codec->name); 296 return -EBUSY; 297 } 298 dprintk(3, "videocodec: unregister '%s' is ok.\n", 299 h->codec->name); 300 if (prev == NULL) { 301 codeclist_top = h->next; 302 dprintk(4, 303 "videocodec: delete first element\n"); 304 } else { 305 prev->next = h->next; 306 dprintk(4, 307 "videocodec: delete middle element\n"); 308 } 309 kfree(h); 310 return 0; 311 } 312 prev = h; 313 h = h->next; 314 } 315 316 dprintk(1, 317 KERN_ERR 318 "videocodec_unregister: given codec not found!\n"); 319 return -EINVAL; 320} 321 322#ifdef CONFIG_PROC_FS 323/* ============ */ 324/* procfs stuff */ 325/* ============ */ 326 327static char *videocodec_buf = NULL; 328static int videocodec_bufsize = 0; 329 330static int 331videocodec_build_table (void) 332{ 333 struct codec_list *h = codeclist_top; 334 struct attached_list *a; 335 int i = 0, size; 336 337 // sum up amount of slaves plus their attached masters 338 while (h) { 339 i += h->attached + 1; 340 h = h->next; 341 } 342#define LINESIZE 100 343 size = LINESIZE * (i + 1); 344 345 dprintk(3, "videocodec_build table: %d entries, %d bytes\n", i, 346 size); 347 348 kfree(videocodec_buf); 349 videocodec_buf = kmalloc(size, GFP_KERNEL); 350 351 if (!videocodec_buf) 352 return 0; 353 354 i = 0; 355 i += scnprintf(videocodec_buf + i, size - 1, 356 "<S>lave or attached <M>aster name type flags magic "); 357 i += scnprintf(videocodec_buf + i, size -i - 1, "(connected as)\n"); 358 359 h = codeclist_top; 360 while (h) { 361 if (i > (size - LINESIZE)) 362 break; // security check 363 i += scnprintf(videocodec_buf + i, size -i -1, 364 "S %32s %04x %08lx %08lx (TEMPLATE)\n", 365 h->codec->name, h->codec->type, 366 h->codec->flags, h->codec->magic); 367 a = h->list; 368 while (a) { 369 if (i > (size - LINESIZE)) 370 break; // security check 371 i += scnprintf(videocodec_buf + i, size -i -1, 372 "M %32s %04x %08lx %08lx (%s)\n", 373 a->codec->master_data->name, 374 a->codec->master_data->type, 375 a->codec->master_data->flags, 376 a->codec->master_data->magic, 377 a->codec->name); 378 a = a->next; 379 } 380 h = h->next; 381 } 382 383 return i; 384} 385 386//The definition: 387//typedef int (read_proc_t)(char *page, char **start, off_t off, 388// int count, int *eof, void *data); 389 390static int 391videocodec_info (char *buffer, 392 char **buffer_location, 393 off_t offset, 394 int buffer_length, 395 int *eof, 396 void *data) 397{ 398 int size; 399 400 dprintk(3, "videocodec_info: offset: %ld, len %d / size %d\n", 401 offset, buffer_length, videocodec_bufsize); 402 403 if (offset == 0) { 404 videocodec_bufsize = videocodec_build_table(); 405 } 406 if ((offset < 0) || (offset >= videocodec_bufsize)) { 407 dprintk(4, 408 "videocodec_info: call delivers no result, return 0\n"); 409 *eof = 1; 410 return 0; 411 } 412 413 if (buffer_length < (videocodec_bufsize - offset)) { 414 dprintk(4, "videocodec_info: %ld needed, %d got\n", 415 videocodec_bufsize - offset, buffer_length); 416 size = buffer_length; 417 } else { 418 dprintk(4, "videocodec_info: last reading of %ld bytes\n", 419 videocodec_bufsize - offset); 420 size = videocodec_bufsize - offset; 421 *eof = 1; 422 } 423 424 memcpy(buffer, videocodec_buf + offset, size); 425 /* doesn't work... */ 426 /* copy_to_user(buffer, videocodec_buf+offset, size); */ 427 /* *buffer_location = videocodec_buf+offset; */ 428 429 return size; 430} 431#endif 432 433/* ===================== */ 434/* hook in driver module */ 435/* ===================== */ 436static int __init 437videocodec_init (void) 438{ 439#ifdef CONFIG_PROC_FS 440 static struct proc_dir_entry *videocodec_proc_entry; 441#endif 442 443 printk(KERN_INFO "Linux video codec intermediate layer: %s\n", 444 VIDEOCODEC_VERSION); 445 446#ifdef CONFIG_PROC_FS 447 videocodec_buf = NULL; 448 videocodec_bufsize = 0; 449 450 videocodec_proc_entry = create_proc_entry("videocodecs", 0, NULL); 451 if (videocodec_proc_entry) { 452 videocodec_proc_entry->read_proc = videocodec_info; 453 videocodec_proc_entry->write_proc = NULL; 454 videocodec_proc_entry->data = NULL; 455 videocodec_proc_entry->owner = THIS_MODULE; 456 } else { 457 dprintk(1, KERN_ERR "videocodec: can't init procfs.\n"); 458 } 459#endif 460 return 0; 461} 462 463static void __exit 464videocodec_exit (void) 465{ 466#ifdef CONFIG_PROC_FS 467 remove_proc_entry("videocodecs", NULL); 468 kfree(videocodec_buf); 469#endif 470} 471 472EXPORT_SYMBOL(videocodec_attach); 473EXPORT_SYMBOL(videocodec_detach); 474EXPORT_SYMBOL(videocodec_register); 475EXPORT_SYMBOL(videocodec_unregister); 476 477module_init(videocodec_init); 478module_exit(videocodec_exit); 479 480MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>"); 481MODULE_DESCRIPTION("Intermediate API module for video codecs " 482 VIDEOCODEC_VERSION); 483MODULE_LICENSE("GPL"); 484