xref: /OK3568_Linux_fs/kernel/drivers/media/usb/pvrusb2/pvrusb2-context.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun  *
4*4882a593Smuzhiyun  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
5*4882a593Smuzhiyun  */
6*4882a593Smuzhiyun 
7*4882a593Smuzhiyun #include "pvrusb2-context.h"
8*4882a593Smuzhiyun #include "pvrusb2-io.h"
9*4882a593Smuzhiyun #include "pvrusb2-ioread.h"
10*4882a593Smuzhiyun #include "pvrusb2-hdw.h"
11*4882a593Smuzhiyun #include "pvrusb2-debug.h"
12*4882a593Smuzhiyun #include <linux/wait.h>
13*4882a593Smuzhiyun #include <linux/kthread.h>
14*4882a593Smuzhiyun #include <linux/errno.h>
15*4882a593Smuzhiyun #include <linux/string.h>
16*4882a593Smuzhiyun #include <linux/slab.h>
17*4882a593Smuzhiyun 
18*4882a593Smuzhiyun static struct pvr2_context *pvr2_context_exist_first;
19*4882a593Smuzhiyun static struct pvr2_context *pvr2_context_exist_last;
20*4882a593Smuzhiyun static struct pvr2_context *pvr2_context_notify_first;
21*4882a593Smuzhiyun static struct pvr2_context *pvr2_context_notify_last;
22*4882a593Smuzhiyun static DEFINE_MUTEX(pvr2_context_mutex);
23*4882a593Smuzhiyun static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
24*4882a593Smuzhiyun static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
25*4882a593Smuzhiyun static int pvr2_context_cleanup_flag;
26*4882a593Smuzhiyun static int pvr2_context_cleaned_flag;
27*4882a593Smuzhiyun static struct task_struct *pvr2_context_thread_ptr;
28*4882a593Smuzhiyun 
29*4882a593Smuzhiyun 
pvr2_context_set_notify(struct pvr2_context * mp,int fl)30*4882a593Smuzhiyun static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
31*4882a593Smuzhiyun {
32*4882a593Smuzhiyun 	int signal_flag = 0;
33*4882a593Smuzhiyun 	mutex_lock(&pvr2_context_mutex);
34*4882a593Smuzhiyun 	if (fl) {
35*4882a593Smuzhiyun 		if (!mp->notify_flag) {
36*4882a593Smuzhiyun 			signal_flag = (pvr2_context_notify_first == NULL);
37*4882a593Smuzhiyun 			mp->notify_prev = pvr2_context_notify_last;
38*4882a593Smuzhiyun 			mp->notify_next = NULL;
39*4882a593Smuzhiyun 			pvr2_context_notify_last = mp;
40*4882a593Smuzhiyun 			if (mp->notify_prev) {
41*4882a593Smuzhiyun 				mp->notify_prev->notify_next = mp;
42*4882a593Smuzhiyun 			} else {
43*4882a593Smuzhiyun 				pvr2_context_notify_first = mp;
44*4882a593Smuzhiyun 			}
45*4882a593Smuzhiyun 			mp->notify_flag = !0;
46*4882a593Smuzhiyun 		}
47*4882a593Smuzhiyun 	} else {
48*4882a593Smuzhiyun 		if (mp->notify_flag) {
49*4882a593Smuzhiyun 			mp->notify_flag = 0;
50*4882a593Smuzhiyun 			if (mp->notify_next) {
51*4882a593Smuzhiyun 				mp->notify_next->notify_prev = mp->notify_prev;
52*4882a593Smuzhiyun 			} else {
53*4882a593Smuzhiyun 				pvr2_context_notify_last = mp->notify_prev;
54*4882a593Smuzhiyun 			}
55*4882a593Smuzhiyun 			if (mp->notify_prev) {
56*4882a593Smuzhiyun 				mp->notify_prev->notify_next = mp->notify_next;
57*4882a593Smuzhiyun 			} else {
58*4882a593Smuzhiyun 				pvr2_context_notify_first = mp->notify_next;
59*4882a593Smuzhiyun 			}
60*4882a593Smuzhiyun 		}
61*4882a593Smuzhiyun 	}
62*4882a593Smuzhiyun 	mutex_unlock(&pvr2_context_mutex);
63*4882a593Smuzhiyun 	if (signal_flag) wake_up(&pvr2_context_sync_data);
64*4882a593Smuzhiyun }
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 
pvr2_context_destroy(struct pvr2_context * mp)67*4882a593Smuzhiyun static void pvr2_context_destroy(struct pvr2_context *mp)
68*4882a593Smuzhiyun {
69*4882a593Smuzhiyun 	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
70*4882a593Smuzhiyun 	pvr2_hdw_destroy(mp->hdw);
71*4882a593Smuzhiyun 	pvr2_context_set_notify(mp, 0);
72*4882a593Smuzhiyun 	mutex_lock(&pvr2_context_mutex);
73*4882a593Smuzhiyun 	if (mp->exist_next) {
74*4882a593Smuzhiyun 		mp->exist_next->exist_prev = mp->exist_prev;
75*4882a593Smuzhiyun 	} else {
76*4882a593Smuzhiyun 		pvr2_context_exist_last = mp->exist_prev;
77*4882a593Smuzhiyun 	}
78*4882a593Smuzhiyun 	if (mp->exist_prev) {
79*4882a593Smuzhiyun 		mp->exist_prev->exist_next = mp->exist_next;
80*4882a593Smuzhiyun 	} else {
81*4882a593Smuzhiyun 		pvr2_context_exist_first = mp->exist_next;
82*4882a593Smuzhiyun 	}
83*4882a593Smuzhiyun 	if (!pvr2_context_exist_first) {
84*4882a593Smuzhiyun 		/* Trigger wakeup on control thread in case it is waiting
85*4882a593Smuzhiyun 		   for an exit condition. */
86*4882a593Smuzhiyun 		wake_up(&pvr2_context_sync_data);
87*4882a593Smuzhiyun 	}
88*4882a593Smuzhiyun 	mutex_unlock(&pvr2_context_mutex);
89*4882a593Smuzhiyun 	kfree(mp);
90*4882a593Smuzhiyun }
91*4882a593Smuzhiyun 
92*4882a593Smuzhiyun 
pvr2_context_notify(struct pvr2_context * mp)93*4882a593Smuzhiyun static void pvr2_context_notify(struct pvr2_context *mp)
94*4882a593Smuzhiyun {
95*4882a593Smuzhiyun 	pvr2_context_set_notify(mp,!0);
96*4882a593Smuzhiyun }
97*4882a593Smuzhiyun 
98*4882a593Smuzhiyun 
pvr2_context_check(struct pvr2_context * mp)99*4882a593Smuzhiyun static void pvr2_context_check(struct pvr2_context *mp)
100*4882a593Smuzhiyun {
101*4882a593Smuzhiyun 	struct pvr2_channel *ch1, *ch2;
102*4882a593Smuzhiyun 	pvr2_trace(PVR2_TRACE_CTXT,
103*4882a593Smuzhiyun 		   "pvr2_context %p (notify)", mp);
104*4882a593Smuzhiyun 	if (!mp->initialized_flag && !mp->disconnect_flag) {
105*4882a593Smuzhiyun 		mp->initialized_flag = !0;
106*4882a593Smuzhiyun 		pvr2_trace(PVR2_TRACE_CTXT,
107*4882a593Smuzhiyun 			   "pvr2_context %p (initialize)", mp);
108*4882a593Smuzhiyun 		/* Finish hardware initialization */
109*4882a593Smuzhiyun 		if (pvr2_hdw_initialize(mp->hdw,
110*4882a593Smuzhiyun 					(void (*)(void *))pvr2_context_notify,
111*4882a593Smuzhiyun 					mp)) {
112*4882a593Smuzhiyun 			mp->video_stream.stream =
113*4882a593Smuzhiyun 				pvr2_hdw_get_video_stream(mp->hdw);
114*4882a593Smuzhiyun 			/* Trigger interface initialization.  By doing this
115*4882a593Smuzhiyun 			   here initialization runs in our own safe and
116*4882a593Smuzhiyun 			   cozy thread context. */
117*4882a593Smuzhiyun 			if (mp->setup_func) mp->setup_func(mp);
118*4882a593Smuzhiyun 		} else {
119*4882a593Smuzhiyun 			pvr2_trace(PVR2_TRACE_CTXT,
120*4882a593Smuzhiyun 				   "pvr2_context %p (thread skipping setup)",
121*4882a593Smuzhiyun 				   mp);
122*4882a593Smuzhiyun 			/* Even though initialization did not succeed,
123*4882a593Smuzhiyun 			   we're still going to continue anyway.  We need
124*4882a593Smuzhiyun 			   to do this in order to await the expected
125*4882a593Smuzhiyun 			   disconnect (which we will detect in the normal
126*4882a593Smuzhiyun 			   course of operation). */
127*4882a593Smuzhiyun 		}
128*4882a593Smuzhiyun 	}
129*4882a593Smuzhiyun 
130*4882a593Smuzhiyun 	for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
131*4882a593Smuzhiyun 		ch2 = ch1->mc_next;
132*4882a593Smuzhiyun 		if (ch1->check_func) ch1->check_func(ch1);
133*4882a593Smuzhiyun 	}
134*4882a593Smuzhiyun 
135*4882a593Smuzhiyun 	if (mp->disconnect_flag && !mp->mc_first) {
136*4882a593Smuzhiyun 		/* Go away... */
137*4882a593Smuzhiyun 		pvr2_context_destroy(mp);
138*4882a593Smuzhiyun 		return;
139*4882a593Smuzhiyun 	}
140*4882a593Smuzhiyun }
141*4882a593Smuzhiyun 
142*4882a593Smuzhiyun 
pvr2_context_shutok(void)143*4882a593Smuzhiyun static int pvr2_context_shutok(void)
144*4882a593Smuzhiyun {
145*4882a593Smuzhiyun 	return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
146*4882a593Smuzhiyun }
147*4882a593Smuzhiyun 
148*4882a593Smuzhiyun 
pvr2_context_thread_func(void * foo)149*4882a593Smuzhiyun static int pvr2_context_thread_func(void *foo)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	struct pvr2_context *mp;
152*4882a593Smuzhiyun 
153*4882a593Smuzhiyun 	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	do {
156*4882a593Smuzhiyun 		while ((mp = pvr2_context_notify_first) != NULL) {
157*4882a593Smuzhiyun 			pvr2_context_set_notify(mp, 0);
158*4882a593Smuzhiyun 			pvr2_context_check(mp);
159*4882a593Smuzhiyun 		}
160*4882a593Smuzhiyun 		wait_event_interruptible(
161*4882a593Smuzhiyun 			pvr2_context_sync_data,
162*4882a593Smuzhiyun 			((pvr2_context_notify_first != NULL) ||
163*4882a593Smuzhiyun 			 pvr2_context_shutok()));
164*4882a593Smuzhiyun 	} while (!pvr2_context_shutok());
165*4882a593Smuzhiyun 
166*4882a593Smuzhiyun 	pvr2_context_cleaned_flag = !0;
167*4882a593Smuzhiyun 	wake_up(&pvr2_context_cleanup_data);
168*4882a593Smuzhiyun 
169*4882a593Smuzhiyun 	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");
170*4882a593Smuzhiyun 
171*4882a593Smuzhiyun 	wait_event_interruptible(
172*4882a593Smuzhiyun 		pvr2_context_sync_data,
173*4882a593Smuzhiyun 		kthread_should_stop());
174*4882a593Smuzhiyun 
175*4882a593Smuzhiyun 	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
176*4882a593Smuzhiyun 
177*4882a593Smuzhiyun 	return 0;
178*4882a593Smuzhiyun }
179*4882a593Smuzhiyun 
180*4882a593Smuzhiyun 
pvr2_context_global_init(void)181*4882a593Smuzhiyun int pvr2_context_global_init(void)
182*4882a593Smuzhiyun {
183*4882a593Smuzhiyun 	pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
184*4882a593Smuzhiyun 					      NULL,
185*4882a593Smuzhiyun 					      "pvrusb2-context");
186*4882a593Smuzhiyun 	return IS_ERR(pvr2_context_thread_ptr) ? -ENOMEM : 0;
187*4882a593Smuzhiyun }
188*4882a593Smuzhiyun 
189*4882a593Smuzhiyun 
pvr2_context_global_done(void)190*4882a593Smuzhiyun void pvr2_context_global_done(void)
191*4882a593Smuzhiyun {
192*4882a593Smuzhiyun 	pvr2_context_cleanup_flag = !0;
193*4882a593Smuzhiyun 	wake_up(&pvr2_context_sync_data);
194*4882a593Smuzhiyun 	wait_event_interruptible(
195*4882a593Smuzhiyun 		pvr2_context_cleanup_data,
196*4882a593Smuzhiyun 		pvr2_context_cleaned_flag);
197*4882a593Smuzhiyun 	kthread_stop(pvr2_context_thread_ptr);
198*4882a593Smuzhiyun }
199*4882a593Smuzhiyun 
200*4882a593Smuzhiyun 
pvr2_context_create(struct usb_interface * intf,const struct usb_device_id * devid,void (* setup_func)(struct pvr2_context *))201*4882a593Smuzhiyun struct pvr2_context *pvr2_context_create(
202*4882a593Smuzhiyun 	struct usb_interface *intf,
203*4882a593Smuzhiyun 	const struct usb_device_id *devid,
204*4882a593Smuzhiyun 	void (*setup_func)(struct pvr2_context *))
205*4882a593Smuzhiyun {
206*4882a593Smuzhiyun 	struct pvr2_context *mp = NULL;
207*4882a593Smuzhiyun 	mp = kzalloc(sizeof(*mp),GFP_KERNEL);
208*4882a593Smuzhiyun 	if (!mp) goto done;
209*4882a593Smuzhiyun 	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
210*4882a593Smuzhiyun 	mp->setup_func = setup_func;
211*4882a593Smuzhiyun 	mutex_init(&mp->mutex);
212*4882a593Smuzhiyun 	mutex_lock(&pvr2_context_mutex);
213*4882a593Smuzhiyun 	mp->exist_prev = pvr2_context_exist_last;
214*4882a593Smuzhiyun 	mp->exist_next = NULL;
215*4882a593Smuzhiyun 	pvr2_context_exist_last = mp;
216*4882a593Smuzhiyun 	if (mp->exist_prev) {
217*4882a593Smuzhiyun 		mp->exist_prev->exist_next = mp;
218*4882a593Smuzhiyun 	} else {
219*4882a593Smuzhiyun 		pvr2_context_exist_first = mp;
220*4882a593Smuzhiyun 	}
221*4882a593Smuzhiyun 	mutex_unlock(&pvr2_context_mutex);
222*4882a593Smuzhiyun 	mp->hdw = pvr2_hdw_create(intf,devid);
223*4882a593Smuzhiyun 	if (!mp->hdw) {
224*4882a593Smuzhiyun 		pvr2_context_destroy(mp);
225*4882a593Smuzhiyun 		mp = NULL;
226*4882a593Smuzhiyun 		goto done;
227*4882a593Smuzhiyun 	}
228*4882a593Smuzhiyun 	pvr2_context_set_notify(mp, !0);
229*4882a593Smuzhiyun  done:
230*4882a593Smuzhiyun 	return mp;
231*4882a593Smuzhiyun }
232*4882a593Smuzhiyun 
233*4882a593Smuzhiyun 
pvr2_context_reset_input_limits(struct pvr2_context * mp)234*4882a593Smuzhiyun static void pvr2_context_reset_input_limits(struct pvr2_context *mp)
235*4882a593Smuzhiyun {
236*4882a593Smuzhiyun 	unsigned int tmsk,mmsk;
237*4882a593Smuzhiyun 	struct pvr2_channel *cp;
238*4882a593Smuzhiyun 	struct pvr2_hdw *hdw = mp->hdw;
239*4882a593Smuzhiyun 	mmsk = pvr2_hdw_get_input_available(hdw);
240*4882a593Smuzhiyun 	tmsk = mmsk;
241*4882a593Smuzhiyun 	for (cp = mp->mc_first; cp; cp = cp->mc_next) {
242*4882a593Smuzhiyun 		if (!cp->input_mask) continue;
243*4882a593Smuzhiyun 		tmsk &= cp->input_mask;
244*4882a593Smuzhiyun 	}
245*4882a593Smuzhiyun 	pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
246*4882a593Smuzhiyun 	pvr2_hdw_commit_ctl(hdw);
247*4882a593Smuzhiyun }
248*4882a593Smuzhiyun 
249*4882a593Smuzhiyun 
pvr2_context_enter(struct pvr2_context * mp)250*4882a593Smuzhiyun static void pvr2_context_enter(struct pvr2_context *mp)
251*4882a593Smuzhiyun {
252*4882a593Smuzhiyun 	mutex_lock(&mp->mutex);
253*4882a593Smuzhiyun }
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 
pvr2_context_exit(struct pvr2_context * mp)256*4882a593Smuzhiyun static void pvr2_context_exit(struct pvr2_context *mp)
257*4882a593Smuzhiyun {
258*4882a593Smuzhiyun 	int destroy_flag = 0;
259*4882a593Smuzhiyun 	if (!(mp->mc_first || !mp->disconnect_flag)) {
260*4882a593Smuzhiyun 		destroy_flag = !0;
261*4882a593Smuzhiyun 	}
262*4882a593Smuzhiyun 	mutex_unlock(&mp->mutex);
263*4882a593Smuzhiyun 	if (destroy_flag) pvr2_context_notify(mp);
264*4882a593Smuzhiyun }
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 
pvr2_context_disconnect(struct pvr2_context * mp)267*4882a593Smuzhiyun void pvr2_context_disconnect(struct pvr2_context *mp)
268*4882a593Smuzhiyun {
269*4882a593Smuzhiyun 	pvr2_hdw_disconnect(mp->hdw);
270*4882a593Smuzhiyun 	mp->disconnect_flag = !0;
271*4882a593Smuzhiyun 	pvr2_context_notify(mp);
272*4882a593Smuzhiyun }
273*4882a593Smuzhiyun 
274*4882a593Smuzhiyun 
pvr2_channel_init(struct pvr2_channel * cp,struct pvr2_context * mp)275*4882a593Smuzhiyun void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
276*4882a593Smuzhiyun {
277*4882a593Smuzhiyun 	pvr2_context_enter(mp);
278*4882a593Smuzhiyun 	cp->hdw = mp->hdw;
279*4882a593Smuzhiyun 	cp->mc_head = mp;
280*4882a593Smuzhiyun 	cp->mc_next = NULL;
281*4882a593Smuzhiyun 	cp->mc_prev = mp->mc_last;
282*4882a593Smuzhiyun 	if (mp->mc_last) {
283*4882a593Smuzhiyun 		mp->mc_last->mc_next = cp;
284*4882a593Smuzhiyun 	} else {
285*4882a593Smuzhiyun 		mp->mc_first = cp;
286*4882a593Smuzhiyun 	}
287*4882a593Smuzhiyun 	mp->mc_last = cp;
288*4882a593Smuzhiyun 	pvr2_context_exit(mp);
289*4882a593Smuzhiyun }
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 
pvr2_channel_disclaim_stream(struct pvr2_channel * cp)292*4882a593Smuzhiyun static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
293*4882a593Smuzhiyun {
294*4882a593Smuzhiyun 	if (!cp->stream) return;
295*4882a593Smuzhiyun 	pvr2_stream_kill(cp->stream->stream);
296*4882a593Smuzhiyun 	cp->stream->user = NULL;
297*4882a593Smuzhiyun 	cp->stream = NULL;
298*4882a593Smuzhiyun }
299*4882a593Smuzhiyun 
300*4882a593Smuzhiyun 
pvr2_channel_done(struct pvr2_channel * cp)301*4882a593Smuzhiyun void pvr2_channel_done(struct pvr2_channel *cp)
302*4882a593Smuzhiyun {
303*4882a593Smuzhiyun 	struct pvr2_context *mp = cp->mc_head;
304*4882a593Smuzhiyun 	pvr2_context_enter(mp);
305*4882a593Smuzhiyun 	cp->input_mask = 0;
306*4882a593Smuzhiyun 	pvr2_channel_disclaim_stream(cp);
307*4882a593Smuzhiyun 	pvr2_context_reset_input_limits(mp);
308*4882a593Smuzhiyun 	if (cp->mc_next) {
309*4882a593Smuzhiyun 		cp->mc_next->mc_prev = cp->mc_prev;
310*4882a593Smuzhiyun 	} else {
311*4882a593Smuzhiyun 		mp->mc_last = cp->mc_prev;
312*4882a593Smuzhiyun 	}
313*4882a593Smuzhiyun 	if (cp->mc_prev) {
314*4882a593Smuzhiyun 		cp->mc_prev->mc_next = cp->mc_next;
315*4882a593Smuzhiyun 	} else {
316*4882a593Smuzhiyun 		mp->mc_first = cp->mc_next;
317*4882a593Smuzhiyun 	}
318*4882a593Smuzhiyun 	cp->hdw = NULL;
319*4882a593Smuzhiyun 	pvr2_context_exit(mp);
320*4882a593Smuzhiyun }
321*4882a593Smuzhiyun 
322*4882a593Smuzhiyun 
pvr2_channel_limit_inputs(struct pvr2_channel * cp,unsigned int cmsk)323*4882a593Smuzhiyun int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
324*4882a593Smuzhiyun {
325*4882a593Smuzhiyun 	unsigned int tmsk,mmsk;
326*4882a593Smuzhiyun 	int ret = 0;
327*4882a593Smuzhiyun 	struct pvr2_channel *p2;
328*4882a593Smuzhiyun 	struct pvr2_hdw *hdw = cp->hdw;
329*4882a593Smuzhiyun 
330*4882a593Smuzhiyun 	mmsk = pvr2_hdw_get_input_available(hdw);
331*4882a593Smuzhiyun 	cmsk &= mmsk;
332*4882a593Smuzhiyun 	if (cmsk == cp->input_mask) {
333*4882a593Smuzhiyun 		/* No change; nothing to do */
334*4882a593Smuzhiyun 		return 0;
335*4882a593Smuzhiyun 	}
336*4882a593Smuzhiyun 
337*4882a593Smuzhiyun 	pvr2_context_enter(cp->mc_head);
338*4882a593Smuzhiyun 	do {
339*4882a593Smuzhiyun 		if (!cmsk) {
340*4882a593Smuzhiyun 			cp->input_mask = 0;
341*4882a593Smuzhiyun 			pvr2_context_reset_input_limits(cp->mc_head);
342*4882a593Smuzhiyun 			break;
343*4882a593Smuzhiyun 		}
344*4882a593Smuzhiyun 		tmsk = mmsk;
345*4882a593Smuzhiyun 		for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
346*4882a593Smuzhiyun 			if (p2 == cp) continue;
347*4882a593Smuzhiyun 			if (!p2->input_mask) continue;
348*4882a593Smuzhiyun 			tmsk &= p2->input_mask;
349*4882a593Smuzhiyun 		}
350*4882a593Smuzhiyun 		if (!(tmsk & cmsk)) {
351*4882a593Smuzhiyun 			ret = -EPERM;
352*4882a593Smuzhiyun 			break;
353*4882a593Smuzhiyun 		}
354*4882a593Smuzhiyun 		tmsk &= cmsk;
355*4882a593Smuzhiyun 		if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
356*4882a593Smuzhiyun 			/* Internal failure changing allowed list; probably
357*4882a593Smuzhiyun 			   should not happen, but react if it does. */
358*4882a593Smuzhiyun 			break;
359*4882a593Smuzhiyun 		}
360*4882a593Smuzhiyun 		cp->input_mask = cmsk;
361*4882a593Smuzhiyun 		pvr2_hdw_commit_ctl(hdw);
362*4882a593Smuzhiyun 	} while (0);
363*4882a593Smuzhiyun 	pvr2_context_exit(cp->mc_head);
364*4882a593Smuzhiyun 	return ret;
365*4882a593Smuzhiyun }
366*4882a593Smuzhiyun 
367*4882a593Smuzhiyun 
pvr2_channel_get_limited_inputs(struct pvr2_channel * cp)368*4882a593Smuzhiyun unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
369*4882a593Smuzhiyun {
370*4882a593Smuzhiyun 	return cp->input_mask;
371*4882a593Smuzhiyun }
372*4882a593Smuzhiyun 
373*4882a593Smuzhiyun 
pvr2_channel_claim_stream(struct pvr2_channel * cp,struct pvr2_context_stream * sp)374*4882a593Smuzhiyun int pvr2_channel_claim_stream(struct pvr2_channel *cp,
375*4882a593Smuzhiyun 			      struct pvr2_context_stream *sp)
376*4882a593Smuzhiyun {
377*4882a593Smuzhiyun 	int code = 0;
378*4882a593Smuzhiyun 	pvr2_context_enter(cp->mc_head); do {
379*4882a593Smuzhiyun 		if (sp == cp->stream) break;
380*4882a593Smuzhiyun 		if (sp && sp->user) {
381*4882a593Smuzhiyun 			code = -EBUSY;
382*4882a593Smuzhiyun 			break;
383*4882a593Smuzhiyun 		}
384*4882a593Smuzhiyun 		pvr2_channel_disclaim_stream(cp);
385*4882a593Smuzhiyun 		if (!sp) break;
386*4882a593Smuzhiyun 		sp->user = cp;
387*4882a593Smuzhiyun 		cp->stream = sp;
388*4882a593Smuzhiyun 	} while (0);
389*4882a593Smuzhiyun 	pvr2_context_exit(cp->mc_head);
390*4882a593Smuzhiyun 	return code;
391*4882a593Smuzhiyun }
392*4882a593Smuzhiyun 
393*4882a593Smuzhiyun 
394*4882a593Smuzhiyun // This is the marker for the real beginning of a legitimate mpeg2 stream.
395*4882a593Smuzhiyun static char stream_sync_key[] = {
396*4882a593Smuzhiyun 	0x00, 0x00, 0x01, 0xba,
397*4882a593Smuzhiyun };
398*4882a593Smuzhiyun 
pvr2_channel_create_mpeg_stream(struct pvr2_context_stream * sp)399*4882a593Smuzhiyun struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
400*4882a593Smuzhiyun 	struct pvr2_context_stream *sp)
401*4882a593Smuzhiyun {
402*4882a593Smuzhiyun 	struct pvr2_ioread *cp;
403*4882a593Smuzhiyun 	cp = pvr2_ioread_create();
404*4882a593Smuzhiyun 	if (!cp) return NULL;
405*4882a593Smuzhiyun 	pvr2_ioread_setup(cp,sp->stream);
406*4882a593Smuzhiyun 	pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
407*4882a593Smuzhiyun 	return cp;
408*4882a593Smuzhiyun }
409