Merge tag 'regmap-fix-v5.11-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux/fpc-iii.git] / drivers / media / usb / pvrusb2 / pvrusb2-context.c
blob14170a5d72b350852632f946d88377ba374be1b4
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
4 * Copyright (C) 2005 Mike Isely <isely@pobox.com>
5 */
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>
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;
30 static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
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;
45 mp->notify_flag = !0;
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;
55 if (mp->notify_prev) {
56 mp->notify_prev->notify_next = mp->notify_next;
57 } else {
58 pvr2_context_notify_first = mp->notify_next;
62 mutex_unlock(&pvr2_context_mutex);
63 if (signal_flag) wake_up(&pvr2_context_sync_data);
67 static void pvr2_context_destroy(struct pvr2_context *mp)
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;
78 if (mp->exist_prev) {
79 mp->exist_prev->exist_next = mp->exist_next;
80 } else {
81 pvr2_context_exist_first = mp->exist_next;
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);
88 mutex_unlock(&pvr2_context_mutex);
89 kfree(mp);
93 static void pvr2_context_notify(struct pvr2_context *mp)
95 pvr2_context_set_notify(mp,!0);
99 static void pvr2_context_check(struct pvr2_context *mp)
101 struct pvr2_channel *ch1, *ch2;
102 pvr2_trace(PVR2_TRACE_CTXT,
103 "pvr2_context %p (notify)", mp);
104 if (!mp->initialized_flag && !mp->disconnect_flag) {
105 mp->initialized_flag = !0;
106 pvr2_trace(PVR2_TRACE_CTXT,
107 "pvr2_context %p (initialize)", mp);
108 /* Finish hardware initialization */
109 if (pvr2_hdw_initialize(mp->hdw,
110 (void (*)(void *))pvr2_context_notify,
111 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). */
130 for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
131 ch2 = ch1->mc_next;
132 if (ch1->check_func) ch1->check_func(ch1);
135 if (mp->disconnect_flag && !mp->mc_first) {
136 /* Go away... */
137 pvr2_context_destroy(mp);
138 return;
143 static int pvr2_context_shutok(void)
145 return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
149 static int pvr2_context_thread_func(void *foo)
151 struct pvr2_context *mp;
153 pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");
155 do {
156 while ((mp = pvr2_context_notify_first) != NULL) {
157 pvr2_context_set_notify(mp, 0);
158 pvr2_context_check(mp);
160 wait_event_interruptible(
161 pvr2_context_sync_data,
162 ((pvr2_context_notify_first != NULL) ||
163 pvr2_context_shutok()));
164 } while (!pvr2_context_shutok());
166 pvr2_context_cleaned_flag = !0;
167 wake_up(&pvr2_context_cleanup_data);
169 pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");
171 wait_event_interruptible(
172 pvr2_context_sync_data,
173 kthread_should_stop());
175 pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
177 return 0;
181 int pvr2_context_global_init(void)
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;
190 void pvr2_context_global_done(void)
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);
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 *))
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;
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;
228 pvr2_context_set_notify(mp, !0);
229 done:
230 return mp;
234 static void pvr2_context_reset_input_limits(struct pvr2_context *mp)
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;
245 pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
246 pvr2_hdw_commit_ctl(hdw);
250 static void pvr2_context_enter(struct pvr2_context *mp)
252 mutex_lock(&mp->mutex);
256 static void pvr2_context_exit(struct pvr2_context *mp)
258 int destroy_flag = 0;
259 if (!(mp->mc_first || !mp->disconnect_flag)) {
260 destroy_flag = !0;
262 mutex_unlock(&mp->mutex);
263 if (destroy_flag) pvr2_context_notify(mp);
267 void pvr2_context_disconnect(struct pvr2_context *mp)
269 pvr2_hdw_disconnect(mp->hdw);
270 mp->disconnect_flag = !0;
271 pvr2_context_notify(mp);
275 void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
277 pvr2_context_enter(mp);
278 cp->hdw = mp->hdw;
279 cp->mc_head = mp;
280 cp->mc_next = NULL;
281 cp->mc_prev = mp->mc_last;
282 if (mp->mc_last) {
283 mp->mc_last->mc_next = cp;
284 } else {
285 mp->mc_first = cp;
287 mp->mc_last = cp;
288 pvr2_context_exit(mp);
292 static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
294 if (!cp->stream) return;
295 pvr2_stream_kill(cp->stream->stream);
296 cp->stream->user = NULL;
297 cp->stream = NULL;
301 void pvr2_channel_done(struct pvr2_channel *cp)
303 struct pvr2_context *mp = cp->mc_head;
304 pvr2_context_enter(mp);
305 cp->input_mask = 0;
306 pvr2_channel_disclaim_stream(cp);
307 pvr2_context_reset_input_limits(mp);
308 if (cp->mc_next) {
309 cp->mc_next->mc_prev = cp->mc_prev;
310 } else {
311 mp->mc_last = cp->mc_prev;
313 if (cp->mc_prev) {
314 cp->mc_prev->mc_next = cp->mc_next;
315 } else {
316 mp->mc_first = cp->mc_next;
318 cp->hdw = NULL;
319 pvr2_context_exit(mp);
323 int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
325 unsigned int tmsk,mmsk;
326 int ret = 0;
327 struct pvr2_channel *p2;
328 struct pvr2_hdw *hdw = cp->hdw;
330 mmsk = pvr2_hdw_get_input_available(hdw);
331 cmsk &= mmsk;
332 if (cmsk == cp->input_mask) {
333 /* No change; nothing to do */
334 return 0;
337 pvr2_context_enter(cp->mc_head);
338 do {
339 if (!cmsk) {
340 cp->input_mask = 0;
341 pvr2_context_reset_input_limits(cp->mc_head);
342 break;
344 tmsk = mmsk;
345 for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
346 if (p2 == cp) continue;
347 if (!p2->input_mask) continue;
348 tmsk &= p2->input_mask;
350 if (!(tmsk & cmsk)) {
351 ret = -EPERM;
352 break;
354 tmsk &= cmsk;
355 if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
356 /* Internal failure changing allowed list; probably
357 should not happen, but react if it does. */
358 break;
360 cp->input_mask = cmsk;
361 pvr2_hdw_commit_ctl(hdw);
362 } while (0);
363 pvr2_context_exit(cp->mc_head);
364 return ret;
368 unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
370 return cp->input_mask;
374 int pvr2_channel_claim_stream(struct pvr2_channel *cp,
375 struct pvr2_context_stream *sp)
377 int code = 0;
378 pvr2_context_enter(cp->mc_head); do {
379 if (sp == cp->stream) break;
380 if (sp && sp->user) {
381 code = -EBUSY;
382 break;
384 pvr2_channel_disclaim_stream(cp);
385 if (!sp) break;
386 sp->user = cp;
387 cp->stream = sp;
388 } while (0);
389 pvr2_context_exit(cp->mc_head);
390 return code;
394 // This is the marker for the real beginning of a legitimate mpeg2 stream.
395 static char stream_sync_key[] = {
396 0x00, 0x00, 0x01, 0xba,
399 struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
400 struct pvr2_context_stream *sp)
402 struct pvr2_ioread *cp;
403 cp = pvr2_ioread_create();
404 if (!cp) return NULL;
405 pvr2_ioread_setup(cp,sp->stream);
406 pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
407 return cp;