Merge tag 'trace-v6.9-2' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux...
[sfrench/cifs-2.6.git] / drivers / media / usb / pvrusb2 / pvrusb2-context.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *
4  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
5  */
6
7 #include "pvrusb2-context.h"
8 #include "pvrusb2-io.h"
9 #include "pvrusb2-ioread.h"
10 #include "pvrusb2-hdw.h"
11 #include "pvrusb2-debug.h"
12 #include <linux/wait.h>
13 #include <linux/kthread.h>
14 #include <linux/errno.h>
15 #include <linux/string.h>
16 #include <linux/slab.h>
17
18 static struct pvr2_context *pvr2_context_exist_first;
19 static struct pvr2_context *pvr2_context_exist_last;
20 static struct pvr2_context *pvr2_context_notify_first;
21 static struct pvr2_context *pvr2_context_notify_last;
22 static DEFINE_MUTEX(pvr2_context_mutex);
23 static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
24 static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
25 static int pvr2_context_cleanup_flag;
26 static int pvr2_context_cleaned_flag;
27 static struct task_struct *pvr2_context_thread_ptr;
28
29
30 static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
31 {
32         int signal_flag = 0;
33         mutex_lock(&pvr2_context_mutex);
34         if (fl) {
35                 if (!mp->notify_flag) {
36                         signal_flag = (pvr2_context_notify_first == NULL);
37                         mp->notify_prev = pvr2_context_notify_last;
38                         mp->notify_next = NULL;
39                         pvr2_context_notify_last = mp;
40                         if (mp->notify_prev) {
41                                 mp->notify_prev->notify_next = mp;
42                         } else {
43                                 pvr2_context_notify_first = mp;
44                         }
45                         mp->notify_flag = !0;
46                 }
47         } else {
48                 if (mp->notify_flag) {
49                         mp->notify_flag = 0;
50                         if (mp->notify_next) {
51                                 mp->notify_next->notify_prev = mp->notify_prev;
52                         } else {
53                                 pvr2_context_notify_last = mp->notify_prev;
54                         }
55                         if (mp->notify_prev) {
56                                 mp->notify_prev->notify_next = mp->notify_next;
57                         } else {
58                                 pvr2_context_notify_first = mp->notify_next;
59                         }
60                 }
61         }
62         mutex_unlock(&pvr2_context_mutex);
63         if (signal_flag) wake_up(&pvr2_context_sync_data);
64 }
65
66
67 static void pvr2_context_destroy(struct pvr2_context *mp)
68 {
69         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
70         pvr2_hdw_destroy(mp->hdw);
71         pvr2_context_set_notify(mp, 0);
72         mutex_lock(&pvr2_context_mutex);
73         if (mp->exist_next) {
74                 mp->exist_next->exist_prev = mp->exist_prev;
75         } else {
76                 pvr2_context_exist_last = mp->exist_prev;
77         }
78         if (mp->exist_prev) {
79                 mp->exist_prev->exist_next = mp->exist_next;
80         } else {
81                 pvr2_context_exist_first = mp->exist_next;
82         }
83         if (!pvr2_context_exist_first) {
84                 /* Trigger wakeup on control thread in case it is waiting
85                    for an exit condition. */
86                 wake_up(&pvr2_context_sync_data);
87         }
88         mutex_unlock(&pvr2_context_mutex);
89         kfree(mp);
90 }
91
92
93 static void pvr2_context_notify(void *ptr)
94 {
95         struct pvr2_context *mp = ptr;
96
97         pvr2_context_set_notify(mp,!0);
98 }
99
100
101 static void pvr2_context_check(struct pvr2_context *mp)
102 {
103         struct pvr2_channel *ch1, *ch2;
104         pvr2_trace(PVR2_TRACE_CTXT,
105                    "pvr2_context %p (notify)", mp);
106         if (!mp->initialized_flag && !mp->disconnect_flag) {
107                 mp->initialized_flag = !0;
108                 pvr2_trace(PVR2_TRACE_CTXT,
109                            "pvr2_context %p (initialize)", mp);
110                 /* Finish hardware initialization */
111                 if (pvr2_hdw_initialize(mp->hdw, pvr2_context_notify, mp)) {
112                         mp->video_stream.stream =
113                                 pvr2_hdw_get_video_stream(mp->hdw);
114                         /* Trigger interface initialization.  By doing this
115                            here initialization runs in our own safe and
116                            cozy thread context. */
117                         if (mp->setup_func) mp->setup_func(mp);
118                 } else {
119                         pvr2_trace(PVR2_TRACE_CTXT,
120                                    "pvr2_context %p (thread skipping setup)",
121                                    mp);
122                         /* Even though initialization did not succeed,
123                            we're still going to continue anyway.  We need
124                            to do this in order to await the expected
125                            disconnect (which we will detect in the normal
126                            course of operation). */
127                 }
128         }
129
130         for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
131                 ch2 = ch1->mc_next;
132                 if (ch1->check_func) ch1->check_func(ch1);
133         }
134
135         if (mp->disconnect_flag && !mp->mc_first) {
136                 /* Go away... */
137                 pvr2_context_destroy(mp);
138                 return;
139         }
140 }
141
142
143 static int pvr2_context_shutok(void)
144 {
145         return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
146 }
147
148
149 static int pvr2_context_thread_func(void *foo)
150 {
151         struct pvr2_context *mp;
152
153         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");
154
155         do {
156                 while ((mp = pvr2_context_notify_first) != NULL) {
157                         pvr2_context_set_notify(mp, 0);
158                         pvr2_context_check(mp);
159                 }
160                 wait_event_interruptible(
161                         pvr2_context_sync_data,
162                         ((pvr2_context_notify_first != NULL) ||
163                          pvr2_context_shutok()));
164         } while (!pvr2_context_shutok());
165
166         pvr2_context_cleaned_flag = !0;
167         wake_up(&pvr2_context_cleanup_data);
168
169         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");
170
171         wait_event_interruptible(
172                 pvr2_context_sync_data,
173                 kthread_should_stop());
174
175         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
176
177         return 0;
178 }
179
180
181 int pvr2_context_global_init(void)
182 {
183         pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
184                                               NULL,
185                                               "pvrusb2-context");
186         return IS_ERR(pvr2_context_thread_ptr) ? -ENOMEM : 0;
187 }
188
189
190 void pvr2_context_global_done(void)
191 {
192         pvr2_context_cleanup_flag = !0;
193         wake_up(&pvr2_context_sync_data);
194         wait_event_interruptible(
195                 pvr2_context_cleanup_data,
196                 pvr2_context_cleaned_flag);
197         kthread_stop(pvr2_context_thread_ptr);
198 }
199
200
201 struct pvr2_context *pvr2_context_create(
202         struct usb_interface *intf,
203         const struct usb_device_id *devid,
204         void (*setup_func)(struct pvr2_context *))
205 {
206         struct pvr2_context *mp = NULL;
207         mp = kzalloc(sizeof(*mp),GFP_KERNEL);
208         if (!mp) goto done;
209         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
210         mp->setup_func = setup_func;
211         mutex_init(&mp->mutex);
212         mutex_lock(&pvr2_context_mutex);
213         mp->exist_prev = pvr2_context_exist_last;
214         mp->exist_next = NULL;
215         pvr2_context_exist_last = mp;
216         if (mp->exist_prev) {
217                 mp->exist_prev->exist_next = mp;
218         } else {
219                 pvr2_context_exist_first = mp;
220         }
221         mutex_unlock(&pvr2_context_mutex);
222         mp->hdw = pvr2_hdw_create(intf,devid);
223         if (!mp->hdw) {
224                 pvr2_context_destroy(mp);
225                 mp = NULL;
226                 goto done;
227         }
228         pvr2_context_set_notify(mp, !0);
229  done:
230         return mp;
231 }
232
233
234 static void pvr2_context_reset_input_limits(struct pvr2_context *mp)
235 {
236         unsigned int tmsk,mmsk;
237         struct pvr2_channel *cp;
238         struct pvr2_hdw *hdw = mp->hdw;
239         mmsk = pvr2_hdw_get_input_available(hdw);
240         tmsk = mmsk;
241         for (cp = mp->mc_first; cp; cp = cp->mc_next) {
242                 if (!cp->input_mask) continue;
243                 tmsk &= cp->input_mask;
244         }
245         pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
246         pvr2_hdw_commit_ctl(hdw);
247 }
248
249
250 static void pvr2_context_enter(struct pvr2_context *mp)
251 {
252         mutex_lock(&mp->mutex);
253 }
254
255
256 static void pvr2_context_exit(struct pvr2_context *mp)
257 {
258         int destroy_flag = 0;
259         if (!(mp->mc_first || !mp->disconnect_flag)) {
260                 destroy_flag = !0;
261         }
262         mutex_unlock(&mp->mutex);
263         if (destroy_flag) pvr2_context_notify(mp);
264 }
265
266
267 void pvr2_context_disconnect(struct pvr2_context *mp)
268 {
269         pvr2_hdw_disconnect(mp->hdw);
270         if (!pvr2_context_shutok())
271                 pvr2_context_notify(mp);
272         mp->disconnect_flag = !0;
273 }
274
275
276 void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
277 {
278         pvr2_context_enter(mp);
279         cp->hdw = mp->hdw;
280         cp->mc_head = mp;
281         cp->mc_next = NULL;
282         cp->mc_prev = mp->mc_last;
283         if (mp->mc_last) {
284                 mp->mc_last->mc_next = cp;
285         } else {
286                 mp->mc_first = cp;
287         }
288         mp->mc_last = cp;
289         pvr2_context_exit(mp);
290 }
291
292
293 static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
294 {
295         if (!cp->stream) return;
296         pvr2_stream_kill(cp->stream->stream);
297         cp->stream->user = NULL;
298         cp->stream = NULL;
299 }
300
301
302 void pvr2_channel_done(struct pvr2_channel *cp)
303 {
304         struct pvr2_context *mp = cp->mc_head;
305         pvr2_context_enter(mp);
306         cp->input_mask = 0;
307         pvr2_channel_disclaim_stream(cp);
308         pvr2_context_reset_input_limits(mp);
309         if (cp->mc_next) {
310                 cp->mc_next->mc_prev = cp->mc_prev;
311         } else {
312                 mp->mc_last = cp->mc_prev;
313         }
314         if (cp->mc_prev) {
315                 cp->mc_prev->mc_next = cp->mc_next;
316         } else {
317                 mp->mc_first = cp->mc_next;
318         }
319         cp->hdw = NULL;
320         pvr2_context_exit(mp);
321 }
322
323
324 int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
325 {
326         unsigned int tmsk,mmsk;
327         int ret = 0;
328         struct pvr2_channel *p2;
329         struct pvr2_hdw *hdw = cp->hdw;
330
331         mmsk = pvr2_hdw_get_input_available(hdw);
332         cmsk &= mmsk;
333         if (cmsk == cp->input_mask) {
334                 /* No change; nothing to do */
335                 return 0;
336         }
337
338         pvr2_context_enter(cp->mc_head);
339         do {
340                 if (!cmsk) {
341                         cp->input_mask = 0;
342                         pvr2_context_reset_input_limits(cp->mc_head);
343                         break;
344                 }
345                 tmsk = mmsk;
346                 for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
347                         if (p2 == cp) continue;
348                         if (!p2->input_mask) continue;
349                         tmsk &= p2->input_mask;
350                 }
351                 if (!(tmsk & cmsk)) {
352                         ret = -EPERM;
353                         break;
354                 }
355                 tmsk &= cmsk;
356                 if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
357                         /* Internal failure changing allowed list; probably
358                            should not happen, but react if it does. */
359                         break;
360                 }
361                 cp->input_mask = cmsk;
362                 pvr2_hdw_commit_ctl(hdw);
363         } while (0);
364         pvr2_context_exit(cp->mc_head);
365         return ret;
366 }
367
368
369 unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
370 {
371         return cp->input_mask;
372 }
373
374
375 int pvr2_channel_claim_stream(struct pvr2_channel *cp,
376                               struct pvr2_context_stream *sp)
377 {
378         int code = 0;
379         pvr2_context_enter(cp->mc_head); do {
380                 if (sp == cp->stream) break;
381                 if (sp && sp->user) {
382                         code = -EBUSY;
383                         break;
384                 }
385                 pvr2_channel_disclaim_stream(cp);
386                 if (!sp) break;
387                 sp->user = cp;
388                 cp->stream = sp;
389         } while (0);
390         pvr2_context_exit(cp->mc_head);
391         return code;
392 }
393
394
395 // This is the marker for the real beginning of a legitimate mpeg2 stream.
396 static char stream_sync_key[] = {
397         0x00, 0x00, 0x01, 0xba,
398 };
399
400 struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
401         struct pvr2_context_stream *sp)
402 {
403         struct pvr2_ioread *cp;
404         cp = pvr2_ioread_create();
405         if (!cp) return NULL;
406         pvr2_ioread_setup(cp,sp->stream);
407         pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
408         return cp;
409 }