1
2
3
4
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
18static struct pvr2_context *pvr2_context_exist_first;
19static struct pvr2_context *pvr2_context_exist_last;
20static struct pvr2_context *pvr2_context_notify_first;
21static struct pvr2_context *pvr2_context_notify_last;
22static DEFINE_MUTEX(pvr2_context_mutex);
23static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
24static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
25static int pvr2_context_cleanup_flag;
26static int pvr2_context_cleaned_flag;
27static struct task_struct *pvr2_context_thread_ptr;
28
29
30static 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
67static 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
85
86 wake_up(&pvr2_context_sync_data);
87 }
88 mutex_unlock(&pvr2_context_mutex);
89 kfree(mp);
90}
91
92
93static void pvr2_context_notify(struct pvr2_context *mp)
94{
95 pvr2_context_set_notify(mp,!0);
96}
97
98
99static 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
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
115
116
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
123
124
125
126
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
137 pvr2_context_destroy(mp);
138 return;
139 }
140}
141
142
143static int pvr2_context_shutok(void)
144{
145 return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
146}
147
148
149static 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
181int 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
190void 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
201struct 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
234static 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
250static void pvr2_context_enter(struct pvr2_context *mp)
251{
252 mutex_lock(&mp->mutex);
253}
254
255
256static 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
267void 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
275void 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
292static 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
301void 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
323int 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
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
357
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
368unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
369{
370 return cp->input_mask;
371}
372
373
374int 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
395static char stream_sync_key[] = {
396 0x00, 0x00, 0x01, 0xba,
397};
398
399struct 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