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  *  You should have received a copy of the GNU General Public License
15  *  along with this program; if not, write to the Free Software
16  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
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 
31 static struct pvr2_context *pvr2_context_exist_first;
32 static struct pvr2_context *pvr2_context_exist_last;
33 static struct pvr2_context *pvr2_context_notify_first;
34 static struct pvr2_context *pvr2_context_notify_last;
35 static DEFINE_MUTEX(pvr2_context_mutex);
36 static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
37 static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
38 static int pvr2_context_cleanup_flag;
39 static int pvr2_context_cleaned_flag;
40 static struct task_struct *pvr2_context_thread_ptr;
41 
42 
43 static 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 
80 static 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 		/* Trigger wakeup on control thread in case it is waiting
98 		   for an exit condition. */
99 		wake_up(&pvr2_context_sync_data);
100 	}
101 	mutex_unlock(&pvr2_context_mutex);
102 	kfree(mp);
103 }
104 
105 
106 static void pvr2_context_notify(struct pvr2_context *mp)
107 {
108 	pvr2_context_set_notify(mp,!0);
109 }
110 
111 
112 static 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 		/* Finish hardware initialization */
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 			/* Trigger interface initialization.  By doing this
128 			   here initialization runs in our own safe and
129 			   cozy thread context. */
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 			/* Even though initialization did not succeed,
136 			   we're still going to continue anyway.  We need
137 			   to do this in order to await the expected
138 			   disconnect (which we will detect in the normal
139 			   course of operation). */
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 		/* Go away... */
150 		pvr2_context_destroy(mp);
151 		return;
152 	}
153 }
154 
155 
156 static int pvr2_context_shutok(void)
157 {
158 	return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
159 }
160 
161 
162 static 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 
194 int 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 
203 void 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 
214 struct 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 
247 static 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 
263 static void pvr2_context_enter(struct pvr2_context *mp)
264 {
265 	mutex_lock(&mp->mutex);
266 }
267 
268 
269 static 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 
280 void 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 
288 void 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 
305 static 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 
314 void 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 
336 int 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 		/* No change; nothing to do */
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 			/* Internal failure changing allowed list; probably
370 			   should not happen, but react if it does. */
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 
381 unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
382 {
383 	return cp->input_mask;
384 }
385 
386 
387 int 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 // This is the marker for the real beginning of a legitimate mpeg2 stream.
407 static char stream_sync_key[] = {
408 	0x00, 0x00, 0x01, 0xba,
409 };
410 
411 struct 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   Stuff for Emacs to see, in order to encourage consistent editing style:
425   *** Local Variables: ***
426   *** mode: c ***
427   *** fill-column: 75 ***
428   *** tab-width: 8 ***
429   *** c-basic-offset: 8 ***
430   *** End: ***
431   */
432