This source file includes following definitions.
- pvr2_context_set_notify
- pvr2_context_destroy
- pvr2_context_notify
- pvr2_context_check
- pvr2_context_shutok
- pvr2_context_thread_func
- pvr2_context_global_init
- pvr2_context_global_done
- pvr2_context_create
- pvr2_context_reset_input_limits
- pvr2_context_enter
- pvr2_context_exit
- pvr2_context_disconnect
- pvr2_channel_init
- pvr2_channel_disclaim_stream
- pvr2_channel_done
- pvr2_channel_limit_inputs
- pvr2_channel_get_limited_inputs
- pvr2_channel_claim_stream
- pvr2_channel_create_mpeg_stream
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
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
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
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
85
86 wake_up(&pvr2_context_sync_data);
87 }
88 mutex_unlock(&pvr2_context_mutex);
89 kfree(mp);
90 }
91
92
93 static void pvr2_context_notify(struct pvr2_context *mp)
94 {
95 pvr2_context_set_notify(mp,!0);
96 }
97
98
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
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
143 static int pvr2_context_shutok(void)
144 {
145 return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
146 }
147
148
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
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
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
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
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
250 static void pvr2_context_enter(struct pvr2_context *mp)
251 {
252 mutex_lock(&mp->mutex);
253 }
254
255
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
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
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
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
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
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
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
368 unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
369 {
370 return cp->input_mask;
371 }
372
373
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
395 static char stream_sync_key[] = {
396 0x00, 0x00, 0x01, 0xba,
397 };
398
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 }