linux/drivers/media/pci/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 * 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
  48static int debug;
  49module_param(debug, int, 0);
  50MODULE_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
  58struct attached_list {
  59        struct videocodec *codec;
  60        struct attached_list *next;
  61};
  62
  63struct codec_list {
  64        const struct videocodec *codec;
  65        int attached;
  66        struct attached_list *list;
  67        struct codec_list *next;
  68};
  69
  70static struct codec_list *codeclist_top = NULL;
  71
  72/* ================================================= */
  73/* function prototypes of the master/slave interface */
  74/* ================================================= */
  75
  76struct videocodec *
  77videocodec_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                        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
 323static int proc_videocodecs_show(struct seq_file *m, void *v)
 324{
 325        struct codec_list *h = codeclist_top;
 326        struct attached_list *a;
 327
 328        seq_printf(m, "<S>lave or attached <M>aster name  type flags    magic    ");
 329        seq_printf(m, "(connected as)\n");
 330
 331        h = codeclist_top;
 332        while (h) {
 333                seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n",
 334                              h->codec->name, h->codec->type,
 335                              h->codec->flags, h->codec->magic);
 336                a = h->list;
 337                while (a) {
 338                        seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n",
 339                                      a->codec->master_data->name,
 340                                      a->codec->master_data->type,
 341                                      a->codec->master_data->flags,
 342                                      a->codec->master_data->magic,
 343                                      a->codec->name);
 344                        a = a->next;
 345                }
 346                h = h->next;
 347        }
 348
 349        return 0;
 350}
 351
 352static int proc_videocodecs_open(struct inode *inode, struct file *file)
 353{
 354        return single_open(file, proc_videocodecs_show, NULL);
 355}
 356
 357static const struct file_operations videocodecs_proc_fops = {
 358        .owner          = THIS_MODULE,
 359        .open           = proc_videocodecs_open,
 360        .read           = seq_read,
 361        .llseek         = seq_lseek,
 362        .release        = single_release,
 363};
 364#endif
 365
 366/* ===================== */
 367/* hook in driver module */
 368/* ===================== */
 369static int __init
 370videocodec_init (void)
 371{
 372#ifdef CONFIG_PROC_FS
 373        static struct proc_dir_entry *videocodec_proc_entry;
 374#endif
 375
 376        printk(KERN_INFO "Linux video codec intermediate layer: %s\n",
 377               VIDEOCODEC_VERSION);
 378
 379#ifdef CONFIG_PROC_FS
 380        videocodec_proc_entry = proc_create("videocodecs", 0, NULL, &videocodecs_proc_fops);
 381        if (!videocodec_proc_entry) {
 382                dprintk(1, KERN_ERR "videocodec: can't init procfs.\n");
 383        }
 384#endif
 385        return 0;
 386}
 387
 388static void __exit
 389videocodec_exit (void)
 390{
 391#ifdef CONFIG_PROC_FS
 392        remove_proc_entry("videocodecs", NULL);
 393#endif
 394}
 395
 396EXPORT_SYMBOL(videocodec_attach);
 397EXPORT_SYMBOL(videocodec_detach);
 398EXPORT_SYMBOL(videocodec_register);
 399EXPORT_SYMBOL(videocodec_unregister);
 400
 401module_init(videocodec_init);
 402module_exit(videocodec_exit);
 403
 404MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>");
 405MODULE_DESCRIPTION("Intermediate API module for video codecs "
 406                   VIDEOCODEC_VERSION);
 407MODULE_LICENSE("GPL");
 408