11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/*
21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * VIDEO MOTION CODECs internal API for video devices
31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's
51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * bound to a master device.
61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (c) 2002 Wolfgang Scherr <scherr@net4you.at>
81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * $Id: videocodec.c,v 1.1.2.8 2003/03/29 07:16:04 rbultje Exp $
101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------------------
121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is free software; you can redistribute it and/or modify
141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * it under the terms of the GNU General Public License as published by
151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * the Free Software Foundation; either version 2 of the License, or
161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * (at your option) any later version.
171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * This program is distributed in the hope that it will be useful,
191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * but WITHOUT ANY WARRANTY; without even the implied warranty of
201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * GNU General Public License for more details.
221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * You should have received a copy of the GNU General Public License
241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * along with this program; if not, write to the Free Software
251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds *
271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds * ------------------------------------------------------------------------
281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds */
291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define VIDEOCODEC_VERSION "v0.2"
311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h>
331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h>
341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h>
351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/types.h>
361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/slab.h>
371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds// kernel config is here (procfs flag)
391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/proc_fs.h>
429faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan#include <linux/seq_file.h>
431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <asm/uaccess.h>
441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include "videocodec.h"
471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
48ff699e6bd02eb1c6d02c7c2b576c2ee6caab201cDouglas Schilling Landgrafstatic int debug;
491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(debug, int, 0);
501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(debug, "Debug level (0-4)");
511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#define dprintk(num, format, args...) \
531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	do { \
541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (debug >= num) \
551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			printk(format, ##args); \
561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} while (0)
571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct attached_list {
591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct videocodec *codec;
601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct attached_list *next;
611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct codec_list {
641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	const struct videocodec *codec;
651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int attached;
661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct attached_list *list;
671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct codec_list *next;
681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds};
691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic struct codec_list *codeclist_top = NULL;
711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ================================================= */
731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* function prototypes of the master/slave interface */
741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ================================================= */
751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstruct videocodec *
771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvideocodec_attach (struct videocodec_master *master)
781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct codec_list *h = codeclist_top;
801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct attached_list *a, *ptr;
811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct videocodec *codec;
821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res;
831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!master) {
851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk(1, KERN_ERR "videocodec_attach: no data\n");
861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(2,
9022c4a4e98ece0eaff13b3d0ac73c5283013eb6b1Mauro Carvalho Chehab		"videocodec_attach: '%s', flags %lx, magic %lx\n",
9122c4a4e98ece0eaff13b3d0ac73c5283013eb6b1Mauro Carvalho Chehab		master->name, master->flags, master->magic);
921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!h) {
941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk(1,
951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			KERN_ERR
961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"videocodec_attach: no device available\n");
971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return NULL;
981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (h) {
1011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// attach only if the slave has at least the flags
1021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		// expected by the master
1031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if ((master->flags & h->codec->flags) == master->flags) {
1041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dprintk(4, "videocodec_attach: try '%s'\n",
1051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				h->codec->name);
1061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!try_module_get(h->codec->owner))
1081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return NULL;
1091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1107a12f4b50dad4fdffd218c6fba6b9564bf86185eJulia Lawall			codec = kmemdup(h->codec, sizeof(struct videocodec),
1117a12f4b50dad4fdffd218c6fba6b9564bf86185eJulia Lawall					GFP_KERNEL);
1121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (!codec) {
1131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dprintk(1,
1141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					KERN_ERR
1151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"videocodec_attach: no mem\n");
1161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				goto out_module_put;
1171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			snprintf(codec->name, sizeof(codec->name),
1201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				 "%s[%d]", codec->name, h->attached);
1211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			codec->master_data = master;
1221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			res = codec->setup(codec);
1231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (res == 0) {
1241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dprintk(3, "videocodec_attach '%s'\n",
1251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					codec->name);
1267408187d223f63d46a13b6a35b8f96b032c2f623Panagiotis Issaris				ptr = kzalloc(sizeof(struct attached_list), GFP_KERNEL);
1271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!ptr) {
1281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dprintk(1,
1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						KERN_ERR
1301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"videocodec_attach: no memory\n");
1311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					goto out_kfree;
1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				ptr->codec = codec;
1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				a = h->list;
1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (!a) {
1371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					h->list = ptr;
1381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dprintk(4,
1391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"videocodec: first element\n");
1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
1411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					while (a->next)
1421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						a = a->next;	// find end
1431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					a->next = ptr;
1441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dprintk(4,
1451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"videocodec: in after '%s'\n",
1461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						h->codec->name);
1471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
1481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				h->attached += 1;
1501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return codec;
1511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
1521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				kfree(codec);
1531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
1541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
1551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		h = h->next;
1561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(1, KERN_ERR "videocodec_attach: no codec found!\n");
1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_module_put:
1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	module_put(h->codec->owner);
1631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds out_kfree:
1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	kfree(codec);
1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return NULL;
1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvideocodec_detach (struct videocodec *codec)
1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct codec_list *h = codeclist_top;
1721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct attached_list *a, *prev;
1731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	int res;
1741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!codec) {
1761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk(1, KERN_ERR "videocodec_detach: no data\n");
1771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
1781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(2,
1811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"videocodec_detach: '%s', type: %x, flags %lx, magic %lx\n",
1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		codec->name, codec->type, codec->flags, codec->magic);
1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!h) {
1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk(1,
1861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			KERN_ERR "videocodec_detach: no device left...\n");
1871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
1881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
1891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
1901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (h) {
1911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		a = h->list;
1921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prev = NULL;
1931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (a) {
1941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (codec == a->codec) {
1951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				res = a->codec->unset(a->codec);
1961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (res >= 0) {
1971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dprintk(3,
1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"videocodec_detach: '%s'\n",
1991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						a->codec->name);
2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					a->codec->master_data = NULL;
2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dprintk(1,
2031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						KERN_ERR
2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"videocodec_detach: '%s'\n",
2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						a->codec->name);
2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					a->codec->master_data = NULL;
2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				if (prev == NULL) {
2091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					h->list = a->next;
2101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dprintk(4,
2111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"videocodec: delete first\n");
2121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				} else {
2131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					prev->next = a->next;
2141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					dprintk(4,
2151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds						"videocodec: delete middle\n");
2161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				}
2171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				module_put(a->codec->owner);
2181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				kfree(a->codec);
2191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				kfree(a);
2201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				h->attached -= 1;
2211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return 0;
2221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			prev = a;
2241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			a = a->next;
2251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
2261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		h = h->next;
2271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(1, KERN_ERR "videocodec_detach: given codec not found!\n");
2301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
2311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
2341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvideocodec_register (const struct videocodec *codec)
2351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct codec_list *ptr, *h = codeclist_top;
2371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2381da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!codec) {
2391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk(1, KERN_ERR "videocodec_register: no data!\n");
2401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
2411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(2,
2441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"videocodec: register '%s', type: %x, flags %lx, magic %lx\n",
2451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		codec->name, codec->type, codec->flags, codec->magic);
2461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2477408187d223f63d46a13b6a35b8f96b032c2f623Panagiotis Issaris	ptr = kzalloc(sizeof(struct codec_list), GFP_KERNEL);
2481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!ptr) {
2491da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk(1, KERN_ERR "videocodec_register: no memory\n");
2501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENOMEM;
2511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	ptr->codec = codec;
2531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!h) {
2551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		codeclist_top = ptr;
2561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk(4, "videocodec: hooked in as first element\n");
2571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	} else {
2581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (h->next)
2591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			h = h->next;	// find the end
2601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		h->next = ptr;
2611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk(4, "videocodec: hooked in after '%s'\n",
2621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			h->codec->name);
2631da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
2661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
2671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsint
2691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvideocodec_unregister (const struct videocodec *codec)
2701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
2711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct codec_list *prev = NULL, *h = codeclist_top;
2721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!codec) {
2741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk(1, KERN_ERR "videocodec_unregister: no data!\n");
2751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -EINVAL;
2761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(2,
2791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n",
2801da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		codec->name, codec->type, codec->flags, codec->magic);
2811da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	if (!h) {
2831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk(1,
2841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			KERN_ERR
2851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			"videocodec_unregister: no device left...\n");
2861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		return -ENXIO;
2871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
2881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
2891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (h) {
2901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		if (codec == h->codec) {
2911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (h->attached) {
2921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dprintk(1,
2931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					KERN_ERR
2941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"videocodec: '%s' is used\n",
2951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					h->codec->name);
2961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				return -EBUSY;
2971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
2981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			dprintk(3, "videocodec: unregister '%s' is ok.\n",
2991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				h->codec->name);
3001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			if (prev == NULL) {
3011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				codeclist_top = h->next;
3021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dprintk(4,
3031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"videocodec: delete first element\n");
3041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			} else {
3051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				prev->next = h->next;
3061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				dprintk(4,
3071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds					"videocodec: delete middle element\n");
3081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			}
3091da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			kfree(h);
3101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			return 0;
3111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		prev = h;
3131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		h = h->next;
3141da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	dprintk(1,
3171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		KERN_ERR
3181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		"videocodec_unregister: given codec not found!\n");
3191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return -EINVAL;
3201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
3239faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyanstatic int proc_videocodecs_show(struct seq_file *m, void *v)
3241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct codec_list *h = codeclist_top;
3261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	struct attached_list *a;
3271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3289faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan	seq_printf(m, "<S>lave or attached <M>aster name  type flags    magic    ");
3299faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan	seq_printf(m, "(connected as)\n");
3301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	h = codeclist_top;
3321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	while (h) {
3339faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan		seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n",
3341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      h->codec->name, h->codec->type,
3351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			      h->codec->flags, h->codec->magic);
3361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		a = h->list;
3371da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		while (a) {
3389faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan			seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n",
3391da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      a->codec->master_data->name,
3401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      a->codec->master_data->type,
3411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      a->codec->master_data->flags,
3421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      a->codec->master_data->magic,
3431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds				      a->codec->name);
3441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds			a = a->next;
3451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		}
3461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		h = h->next;
3471da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3499faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan	return 0;
3501da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3529faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyanstatic int proc_videocodecs_open(struct inode *inode, struct file *file)
3531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3549faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan	return single_open(file, proc_videocodecs_show, NULL);
3551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3569faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan
3579faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyanstatic const struct file_operations videocodecs_proc_fops = {
3589faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan	.owner		= THIS_MODULE,
3599faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan	.open		= proc_videocodecs_open,
3609faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan	.read		= seq_read,
3619faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan	.llseek		= seq_lseek,
3629faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan	.release	= single_release,
3639faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan};
3641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ===================== */
3671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* hook in driver module */
3681da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* ===================== */
3691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init
3701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvideocodec_init (void)
3711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3721da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
3731da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	static struct proc_dir_entry *videocodec_proc_entry;
3741da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3751da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3761da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	printk(KERN_INFO "Linux video codec intermediate layer: %s\n",
3771da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	       VIDEOCODEC_VERSION);
3781da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3791da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
3809faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan	videocodec_proc_entry = proc_create("videocodecs", 0, NULL, &videocodecs_proc_fops);
3819faa2d75822e1950b3aacc8ccbdf0cdb595e47deAlexey Dobriyan	if (!videocodec_proc_entry) {
3821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		dprintk(1, KERN_ERR "videocodec: can't init procfs.\n");
3831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	}
3841da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	return 0;
3861da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3871da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3881da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit
3891da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsvideocodec_exit (void)
3901da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{
3911da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#ifdef CONFIG_PROC_FS
3921da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds	remove_proc_entry("videocodecs", NULL);
3931da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#endif
3941da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds}
3951da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
3961da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(videocodec_attach);
3971da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(videocodec_detach);
3981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(videocodec_register);
3991da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsEXPORT_SYMBOL(videocodec_unregister);
4001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(videocodec_init);
4021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(videocodec_exit);
4031da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds
4041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_AUTHOR("Wolfgang Scherr <scherr@net4you.at>");
4051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_DESCRIPTION("Intermediate API module for video codecs "
4061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds		   VIDEOCODEC_VERSION);
4071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL");
408