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
pvr2_context_set_notify(struct pvr2_context * mp,int fl)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
pvr2_context_destroy(struct pvr2_context * mp)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
pvr2_context_notify(struct pvr2_context * mp)93 static void pvr2_context_notify(struct pvr2_context *mp)
94 {
95 pvr2_context_set_notify(mp,!0);
96 }
97
98
pvr2_context_check(struct pvr2_context * mp)99 static void pvr2_context_check(struct pvr2_context *mp)
100 {
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). */
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
pvr2_context_shutok(void)143 static int pvr2_context_shutok(void)
144 {
145 return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
146 }
147
148
pvr2_context_thread_func(void * foo)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
pvr2_context_global_init(void)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
pvr2_context_global_done(void)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
pvr2_context_create(struct usb_interface * intf,const struct usb_device_id * devid,void (* setup_func)(struct pvr2_context *))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
pvr2_context_reset_input_limits(struct pvr2_context * mp)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
pvr2_context_enter(struct pvr2_context * mp)250 static void pvr2_context_enter(struct pvr2_context *mp)
251 {
252 mutex_lock(&mp->mutex);
253 }
254
255
pvr2_context_exit(struct pvr2_context * mp)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
pvr2_context_disconnect(struct pvr2_context * mp)267 void pvr2_context_disconnect(struct pvr2_context *mp)
268 {
269 pvr2_hdw_disconnect(mp->hdw);
270 mp->disconnect_flag = !0;
271 pvr2_context_notify(mp);
272 }
273
274
pvr2_channel_init(struct pvr2_channel * cp,struct pvr2_context * mp)275 void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
276 {
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;
286 }
287 mp->mc_last = cp;
288 pvr2_context_exit(mp);
289 }
290
291
pvr2_channel_disclaim_stream(struct pvr2_channel * cp)292 static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
293 {
294 if (!cp->stream) return;
295 pvr2_stream_kill(cp->stream->stream);
296 cp->stream->user = NULL;
297 cp->stream = NULL;
298 }
299
300
pvr2_channel_done(struct pvr2_channel * cp)301 void pvr2_channel_done(struct pvr2_channel *cp)
302 {
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;
312 }
313 if (cp->mc_prev) {
314 cp->mc_prev->mc_next = cp->mc_next;
315 } else {
316 mp->mc_first = cp->mc_next;
317 }
318 cp->hdw = NULL;
319 pvr2_context_exit(mp);
320 }
321
322
pvr2_channel_limit_inputs(struct pvr2_channel * cp,unsigned int cmsk)323 int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
324 {
325 unsigned int tmsk,mmsk;
326 int ret = 0;
327 struct pvr2_channel *p2;
328 struct pvr2_hdw *hdw = cp->hdw;
329
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;
335 }
336
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;
343 }
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;
349 }
350 if (!(tmsk & cmsk)) {
351 ret = -EPERM;
352 break;
353 }
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;
359 }
360 cp->input_mask = cmsk;
361 pvr2_hdw_commit_ctl(hdw);
362 } while (0);
363 pvr2_context_exit(cp->mc_head);
364 return ret;
365 }
366
367
pvr2_channel_get_limited_inputs(struct pvr2_channel * cp)368 unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
369 {
370 return cp->input_mask;
371 }
372
373
pvr2_channel_claim_stream(struct pvr2_channel * cp,struct pvr2_context_stream * sp)374 int pvr2_channel_claim_stream(struct pvr2_channel *cp,
375 struct pvr2_context_stream *sp)
376 {
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;
383 }
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;
391 }
392
393
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,
397 };
398
pvr2_channel_create_mpeg_stream(struct pvr2_context_stream * sp)399 struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
400 struct pvr2_context_stream *sp)
401 {
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;
408 }
409