File Index
Files and directories
Sign in
FILE

videocodec.c

File preview with syntax highlighting.

linux-6.19.14/drivers/media/pci/zoran/videocodec.c C
  1// SPDX-License-Identifier: GPL-2.0-or-later
  2/*
  3 * VIDEO MOTION CODECs internal API for video devices
  4 *
  5 * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's
  6 * bound to a master device.
  7 *
  8 * (c) 2002 Wolfgang Scherr <scherr@net4you.at>
  9 */
 10
 11#include <linux/kernel.h>
 12#include <linux/module.h>
 13#include <linux/init.h>
 14#include <linux/types.h>
 15#include <linux/slab.h>
 16
 17#include "videocodec.h"
 18
 19struct attached_list {
 20	struct videocodec *codec;
 21	struct attached_list *next;
 22};
 23
 24struct codec_list {
 25	const struct videocodec *codec;
 26	int attached;
 27	struct attached_list *list;
 28	struct codec_list *next;
 29};
 30
 31static struct codec_list *codeclist_top;
 32
 33/* ================================================= */
 34/* function prototypes of the master/slave interface */
 35/* ================================================= */
 36
 37struct videocodec *videocodec_attach(struct videocodec_master *master)
 38{
 39	struct codec_list *h = codeclist_top;
 40	struct zoran *zr;
 41	struct attached_list *a, *ptr;
 42	struct videocodec *codec;
 43	int res;
 44
 45	if (!master) {
 46		pr_err("%s: no data\n", __func__);
 47		return NULL;
 48	}
 49
 50	zr = videocodec_master_to_zoran(master);
 51
 52	zrdev_dbg(zr, "%s: '%s', flags %lx, magic %lx\n", __func__,
 53		  master->name, master->flags, master->magic);
 54
 55	if (!h) {
 56		zrdev_err(zr, "%s: no device available\n", __func__);
 57		return NULL;
 58	}
 59
 60	while (h) {
 61		// attach only if the slave has at least the flags
 62		// expected by the master
 63		if ((master->flags & h->codec->flags) == master->flags) {
 64			zrdev_dbg(zr, "%s: try '%s'\n", __func__, h->codec->name);
 65
 66			codec = kmemdup(h->codec, sizeof(struct videocodec), GFP_KERNEL);
 67			if (!codec)
 68				goto out_kfree;
 69
 70			res = strlen(codec->name);
 71			snprintf(codec->name + res, sizeof(codec->name) - res, "[%d]", h->attached);
 72			codec->master_data = master;
 73			res = codec->setup(codec);
 74			if (res == 0) {
 75				zrdev_dbg(zr, "%s: '%s'\n", __func__, codec->name);
 76				ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
 77				if (!ptr)
 78					goto out_kfree;
 79				ptr->codec = codec;
 80
 81				a = h->list;
 82				if (!a) {
 83					h->list = ptr;
 84					zrdev_dbg(zr, "videocodec: first element\n");
 85				} else {
 86					while (a->next)
 87						a = a->next;	// find end
 88					a->next = ptr;
 89					zrdev_dbg(zr, "videocodec: in after '%s'\n",
 90						  h->codec->name);
 91				}
 92
 93				h->attached += 1;
 94				return codec;
 95			}
 96			kfree(codec);
 97		}
 98		h = h->next;
 99	}
100
101	zrdev_err(zr, "%s: no codec found!\n", __func__);
102	return NULL;
103
104 out_kfree:
105	kfree(codec);
106	return NULL;
107}
108
109int videocodec_detach(struct videocodec *codec)
110{
111	struct codec_list *h = codeclist_top;
112	struct zoran *zr;
113	struct attached_list *a, *prev;
114	int res;
115
116	if (!codec) {
117		pr_err("%s: no data\n", __func__);
118		return -EINVAL;
119	}
120
121	zr = videocodec_to_zoran(codec);
122
123	zrdev_dbg(zr, "%s: '%s', type: %x, flags %lx, magic %lx\n", __func__,
124		  codec->name, codec->type, codec->flags, codec->magic);
125
126	if (!h) {
127		zrdev_err(zr, "%s: no device left...\n", __func__);
128		return -ENXIO;
129	}
130
131	while (h) {
132		a = h->list;
133		prev = NULL;
134		while (a) {
135			if (codec == a->codec) {
136				res = a->codec->unset(a->codec);
137				if (res >= 0) {
138					zrdev_dbg(zr, "%s: '%s'\n", __func__,
139						  a->codec->name);
140					a->codec->master_data = NULL;
141				} else {
142					zrdev_err(zr, "%s: '%s'\n", __func__, a->codec->name);
143					a->codec->master_data = NULL;
144				}
145				if (!prev) {
146					h->list = a->next;
147					zrdev_dbg(zr, "videocodec: delete first\n");
148				} else {
149					prev->next = a->next;
150					zrdev_dbg(zr, "videocodec: delete middle\n");
151				}
152				kfree(a->codec);
153				kfree(a);
154				h->attached -= 1;
155				return 0;
156			}
157			prev = a;
158			a = a->next;
159		}
160		h = h->next;
161	}
162
163	zrdev_err(zr, "%s: given codec not found!\n", __func__);
164	return -EINVAL;
165}
166
167int videocodec_register(const struct videocodec *codec)
168{
169	struct codec_list *ptr, *h = codeclist_top;
170	struct zoran *zr;
171
172	if (!codec) {
173		pr_err("%s: no data!\n", __func__);
174		return -EINVAL;
175	}
176
177	zr = videocodec_to_zoran((struct videocodec *)codec);
178
179	zrdev_dbg(zr,
180		  "videocodec: register '%s', type: %x, flags %lx, magic %lx\n",
181		  codec->name, codec->type, codec->flags, codec->magic);
182
183	ptr = kzalloc(sizeof(*ptr), GFP_KERNEL);
184	if (!ptr)
185		return -ENOMEM;
186	ptr->codec = codec;
187
188	if (!h) {
189		codeclist_top = ptr;
190		zrdev_dbg(zr, "videocodec: hooked in as first element\n");
191	} else {
192		while (h->next)
193			h = h->next;	// find the end
194		h->next = ptr;
195		zrdev_dbg(zr, "videocodec: hooked in after '%s'\n",
196			  h->codec->name);
197	}
198
199	return 0;
200}
201
202int videocodec_unregister(const struct videocodec *codec)
203{
204	struct codec_list *prev = NULL, *h = codeclist_top;
205	struct zoran *zr;
206
207	if (!codec) {
208		pr_err("%s: no data!\n", __func__);
209		return -EINVAL;
210	}
211
212	zr = videocodec_to_zoran((struct videocodec *)codec);
213
214	zrdev_dbg(zr,
215		  "videocodec: unregister '%s', type: %x, flags %lx, magic %lx\n",
216		  codec->name, codec->type, codec->flags, codec->magic);
217
218	if (!h) {
219		zrdev_err(zr, "%s: no device left...\n", __func__);
220		return -ENXIO;
221	}
222
223	while (h) {
224		if (codec == h->codec) {
225			if (h->attached) {
226				zrdev_err(zr, "videocodec: '%s' is used\n",
227					  h->codec->name);
228				return -EBUSY;
229			}
230			zrdev_dbg(zr, "videocodec: unregister '%s' is ok.\n",
231				  h->codec->name);
232			if (!prev) {
233				codeclist_top = h->next;
234				zrdev_dbg(zr,
235					  "videocodec: delete first element\n");
236			} else {
237				prev->next = h->next;
238				zrdev_dbg(zr,
239					  "videocodec: delete middle element\n");
240			}
241			kfree(h);
242			return 0;
243		}
244		prev = h;
245		h = h->next;
246	}
247
248	zrdev_err(zr, "%s: given codec not found!\n", __func__);
249	return -EINVAL;
250}
251
252int videocodec_debugfs_show(struct seq_file *m)
253{
254	struct codec_list *h = codeclist_top;
255	struct attached_list *a;
256
257	seq_puts(m, "<S>lave or attached <M>aster name  type flags    magic    ");
258	seq_puts(m, "(connected as)\n");
259
260	while (h) {
261		seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n",
262			   h->codec->name, h->codec->type,
263			      h->codec->flags, h->codec->magic);
264		a = h->list;
265		while (a) {
266			seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n",
267				   a->codec->master_data->name,
268				      a->codec->master_data->type,
269				      a->codec->master_data->flags,
270				      a->codec->master_data->magic,
271				      a->codec->name);
272			a = a->next;
273		}
274		h = h->next;
275	}
276
277	return 0;
278}
~/ Read-only file preview.