279 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * VIDEO MOTION CODECs internal API for video devices4 *5 * Interface for MJPEG (and maybe later MPEG/WAVELETS) codec's6 * 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 flags62 // expected by the master63 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 end88 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 end194 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}279