Merge patch series "Use composable cache instead of L2 cache"
[linux-2.6-block.git] / drivers / media / pci / zoran / videocodec.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
19 struct attached_list {
20         struct videocodec *codec;
21         struct attached_list *next;
22 };
23
24 struct codec_list {
25         const struct videocodec *codec;
26         int attached;
27         struct attached_list *list;
28         struct codec_list *next;
29 };
30
31 static struct codec_list *codeclist_top;
32
33 /* ================================================= */
34 /* function prototypes of the master/slave interface */
35 /* ================================================= */
36
37 struct 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
109 int 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
167 int 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
202 int 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
252 int 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 }