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