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 }
418