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                        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
 169int
 170videocodec_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
 234int
 235videocodec_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
 269int
 270videocodec_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
 324static 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
 353static int proc_videocodecs_open(struct inode *inode, struct file *file)
 354{
 355        return single_open(file, proc_videocodecs_show, NULL);
 356}
 357
 358static 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/* ===================== */
 370static int __init
 371videocodec_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
 389static void __exit
 390videocodec_exit (void)
 391{
 392#ifdef CONFIG_PROC_FS
 393        remove_proc_entry("videocodecs", NULL);
 394#endif
 395}
 396
 397EXPORT_SYMBOL(videocodec_attach);
 398EXPORT_SYMBOL(videocodec_detach);
 399EXPORT_SYMBOL(videocodec_register);
 400EXPORT_SYMBOL(videocodec_unregister);
 401
 402module_init(videocodec_init);
 403module_exit(videocodec_exit);
 404
 405MODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>");
 406MODULE_DESCRIPTION("Intermediate API module for video codecs "
 407                   VIDEOCODEC_VERSION);
 408MODULE_LICENSE("GPL");
 409