• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
pvr2_context_set_notify(struct pvr2_context * mp,int fl)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 
pvr2_context_destroy(struct pvr2_context * mp)80 static void pvr2_context_destroy(struct pvr2_context *mp)
81 {
82 	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
83 	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 
pvr2_context_notify(struct pvr2_context * mp)106 static void pvr2_context_notify(struct pvr2_context *mp)
107 {
108 	pvr2_context_set_notify(mp,!0);
109 }
110 
111 
pvr2_context_check(struct pvr2_context * mp)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 
pvr2_context_shutok(void)156 static int pvr2_context_shutok(void)
157 {
158 	return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
159 }
160 
161 
pvr2_context_thread_func(void * foo)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 
pvr2_context_global_init(void)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 
pvr2_context_global_done(void)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 
pvr2_context_create(struct usb_interface * intf,const struct usb_device_id * devid,void (* setup_func)(struct pvr2_context *))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 
pvr2_context_reset_input_limits(struct pvr2_context * mp)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 
pvr2_context_enter(struct pvr2_context * mp)263 static void pvr2_context_enter(struct pvr2_context *mp)
264 {
265 	mutex_lock(&mp->mutex);
266 }
267 
268 
pvr2_context_exit(struct pvr2_context * mp)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 
pvr2_context_disconnect(struct pvr2_context * mp)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 
pvr2_channel_init(struct pvr2_channel * cp,struct pvr2_context * mp)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 
pvr2_channel_disclaim_stream(struct pvr2_channel * cp)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 
pvr2_channel_done(struct pvr2_channel * cp)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 
pvr2_channel_limit_inputs(struct pvr2_channel * cp,unsigned int cmsk)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 
pvr2_channel_get_limited_inputs(struct pvr2_channel * cp)381 unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
382 {
383 	return cp->input_mask;
384 }
385 
386 
pvr2_channel_claim_stream(struct pvr2_channel * cp,struct pvr2_context_stream * sp)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);
402 	pvr2_context_exit(cp->mc_head);
403 	return code;
404 }
405 
406 
407 // This is the marker for the real beginning of a legitimate mpeg2 stream.
408 static char stream_sync_key[] = {
409 	0x00, 0x00, 0x01, 0xba,
410 };
411 
pvr2_channel_create_mpeg_stream(struct pvr2_context_stream * sp)412 struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
413 	struct pvr2_context_stream *sp)
414 {
415 	struct pvr2_ioread *cp;
416 	cp = pvr2_ioread_create();
417 	if (!cp) return NULL;
418 	pvr2_ioread_setup(cp,sp->stream);
419 	pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
420 	return cp;
421 }
422