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