linux/drivers/staging/media/zoran/videocodec.c
<<
>>
Prefs
   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
  44static int debug;
  45module_param(debug, int, 0);
  46MODULE_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
  54struct attached_list {
  55        struct videocodec *codec;
  56        struct attached_list *next;
  57};
  58
  59struct codec_list {
  60        const struct videocodec *codec;
  61        int attached;
  62        struct attached_list *list;
  63        struct codec_list *next;
  64};
  65
  66static struct codec_list *codeclist_top = NULL;
  67
  68/* ================================================= */
  69/* function prototypes of the master/slave interface */
  70/* ================================================= */
  71
  72struct videocodec *
  73videocodec_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
 165int
 166videocodec_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
 230int
 231videocodec_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
 265int
 266videocodec_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
 320static 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#endif
 348
 349/* ===================== */
 350/* hook in driver module */
 351/* ===================== */
 352static int __init
 353videocodec_init (void)
 354{
 355#ifdef CONFIG_PROC_FS
 356        static struct proc_dir_entry *videocodec_proc_entry;
 357#endif
 358
 359        printk(KERN_INFO "Linux video codec intermediate layer: %s\n",
 360               VIDEOCODEC_VERSION);
 361
 362#ifdef CONFIG_PROC_FS
 363        videocodec_proc_entry = proc_create_single("videocodecs", 0, NULL,
 364                        proc_videocodecs_show);
 365        if (!videocodec_proc_entry) {
 366                dprintk(1, KERN_ERR "videocodec: can't init procfs.\n");
 367        }
 368#endif
 369        return 0;
 370}
 371
 372static void __exit
 373videocodec_exit (void)
 374{
 375#ifdef CONFIG_PROC_FS
 376        remove_proc_entry("videocodecs", NULL);
 377#endif
 378}
 379
 380EXPORT_SYMBOL(videocodec_attach);
 381EXPORT_SYMBOL(videocodec_detach);
 382EXPORT_SYMBOL(videocodec_register);
 383EXPORT_SYMBOL(videocodec_unregister);
 384
 385module_init(videocodec_init);
 386module_exit(videocodec_exit);
 387
 388MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>");
 389MODULE_DESCRIPTION("Intermediate API module for video codecs "
 390                   VIDEOCODEC_VERSION);
 391MODULE_LICENSE("GPL");
 392