1
2
3
4
5
6
7
8
9
10
11
12
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
27static struct pvr2_context *pvr2_context_exist_first;
28static struct pvr2_context *pvr2_context_exist_last;
29static struct pvr2_context *pvr2_context_notify_first;
30static struct pvr2_context *pvr2_context_notify_last;
31static DEFINE_MUTEX(pvr2_context_mutex);
32static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
33static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
34static int pvr2_context_cleanup_flag;
35static int pvr2_context_cleaned_flag;
36static struct task_struct *pvr2_context_thread_ptr;
37
38
39static 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
76static 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
94
95 wake_up(&pvr2_context_sync_data);
96 }
97 mutex_unlock(&pvr2_context_mutex);
98 kfree(mp);
99}
100
101
102static void pvr2_context_notify(struct pvr2_context *mp)
103{
104 pvr2_context_set_notify(mp,!0);
105}
106
107
108static 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
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
124
125
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
132
133
134
135
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
146 pvr2_context_destroy(mp);
147 return;
148 }
149}
150
151
152static int pvr2_context_shutok(void)
153{
154 return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
155}
156
157
158static 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
190int 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
199void 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
210struct 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
243static 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
259static void pvr2_context_enter(struct pvr2_context *mp)
260{
261 mutex_lock(&mp->mutex);
262}
263
264
265static 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
276void 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
284void 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
301static 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
310void 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
332int 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
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
366
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
377unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
378{
379 return cp->input_mask;
380}
381
382
383int 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
404static char stream_sync_key[] = {
405 0x00, 0x00, 0x01, 0xba,
406};
407
408struct 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}
418