18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *
48c2ecf20Sopenharmony_ci *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include "pvrusb2-context.h"
88c2ecf20Sopenharmony_ci#include "pvrusb2-io.h"
98c2ecf20Sopenharmony_ci#include "pvrusb2-ioread.h"
108c2ecf20Sopenharmony_ci#include "pvrusb2-hdw.h"
118c2ecf20Sopenharmony_ci#include "pvrusb2-debug.h"
128c2ecf20Sopenharmony_ci#include <linux/wait.h>
138c2ecf20Sopenharmony_ci#include <linux/kthread.h>
148c2ecf20Sopenharmony_ci#include <linux/errno.h>
158c2ecf20Sopenharmony_ci#include <linux/string.h>
168c2ecf20Sopenharmony_ci#include <linux/slab.h>
178c2ecf20Sopenharmony_ci
188c2ecf20Sopenharmony_cistatic struct pvr2_context *pvr2_context_exist_first;
198c2ecf20Sopenharmony_cistatic struct pvr2_context *pvr2_context_exist_last;
208c2ecf20Sopenharmony_cistatic struct pvr2_context *pvr2_context_notify_first;
218c2ecf20Sopenharmony_cistatic struct pvr2_context *pvr2_context_notify_last;
228c2ecf20Sopenharmony_cistatic DEFINE_MUTEX(pvr2_context_mutex);
238c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
248c2ecf20Sopenharmony_cistatic DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
258c2ecf20Sopenharmony_cistatic int pvr2_context_cleanup_flag;
268c2ecf20Sopenharmony_cistatic int pvr2_context_cleaned_flag;
278c2ecf20Sopenharmony_cistatic struct task_struct *pvr2_context_thread_ptr;
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci
308c2ecf20Sopenharmony_cistatic void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
318c2ecf20Sopenharmony_ci{
328c2ecf20Sopenharmony_ci	int signal_flag = 0;
338c2ecf20Sopenharmony_ci	mutex_lock(&pvr2_context_mutex);
348c2ecf20Sopenharmony_ci	if (fl) {
358c2ecf20Sopenharmony_ci		if (!mp->notify_flag) {
368c2ecf20Sopenharmony_ci			signal_flag = (pvr2_context_notify_first == NULL);
378c2ecf20Sopenharmony_ci			mp->notify_prev = pvr2_context_notify_last;
388c2ecf20Sopenharmony_ci			mp->notify_next = NULL;
398c2ecf20Sopenharmony_ci			pvr2_context_notify_last = mp;
408c2ecf20Sopenharmony_ci			if (mp->notify_prev) {
418c2ecf20Sopenharmony_ci				mp->notify_prev->notify_next = mp;
428c2ecf20Sopenharmony_ci			} else {
438c2ecf20Sopenharmony_ci				pvr2_context_notify_first = mp;
448c2ecf20Sopenharmony_ci			}
458c2ecf20Sopenharmony_ci			mp->notify_flag = !0;
468c2ecf20Sopenharmony_ci		}
478c2ecf20Sopenharmony_ci	} else {
488c2ecf20Sopenharmony_ci		if (mp->notify_flag) {
498c2ecf20Sopenharmony_ci			mp->notify_flag = 0;
508c2ecf20Sopenharmony_ci			if (mp->notify_next) {
518c2ecf20Sopenharmony_ci				mp->notify_next->notify_prev = mp->notify_prev;
528c2ecf20Sopenharmony_ci			} else {
538c2ecf20Sopenharmony_ci				pvr2_context_notify_last = mp->notify_prev;
548c2ecf20Sopenharmony_ci			}
558c2ecf20Sopenharmony_ci			if (mp->notify_prev) {
568c2ecf20Sopenharmony_ci				mp->notify_prev->notify_next = mp->notify_next;
578c2ecf20Sopenharmony_ci			} else {
588c2ecf20Sopenharmony_ci				pvr2_context_notify_first = mp->notify_next;
598c2ecf20Sopenharmony_ci			}
608c2ecf20Sopenharmony_ci		}
618c2ecf20Sopenharmony_ci	}
628c2ecf20Sopenharmony_ci	mutex_unlock(&pvr2_context_mutex);
638c2ecf20Sopenharmony_ci	if (signal_flag) wake_up(&pvr2_context_sync_data);
648c2ecf20Sopenharmony_ci}
658c2ecf20Sopenharmony_ci
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_cistatic void pvr2_context_destroy(struct pvr2_context *mp)
688c2ecf20Sopenharmony_ci{
698c2ecf20Sopenharmony_ci	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
708c2ecf20Sopenharmony_ci	pvr2_hdw_destroy(mp->hdw);
718c2ecf20Sopenharmony_ci	pvr2_context_set_notify(mp, 0);
728c2ecf20Sopenharmony_ci	mutex_lock(&pvr2_context_mutex);
738c2ecf20Sopenharmony_ci	if (mp->exist_next) {
748c2ecf20Sopenharmony_ci		mp->exist_next->exist_prev = mp->exist_prev;
758c2ecf20Sopenharmony_ci	} else {
768c2ecf20Sopenharmony_ci		pvr2_context_exist_last = mp->exist_prev;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci	if (mp->exist_prev) {
798c2ecf20Sopenharmony_ci		mp->exist_prev->exist_next = mp->exist_next;
808c2ecf20Sopenharmony_ci	} else {
818c2ecf20Sopenharmony_ci		pvr2_context_exist_first = mp->exist_next;
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci	if (!pvr2_context_exist_first) {
848c2ecf20Sopenharmony_ci		/* Trigger wakeup on control thread in case it is waiting
858c2ecf20Sopenharmony_ci		   for an exit condition. */
868c2ecf20Sopenharmony_ci		wake_up(&pvr2_context_sync_data);
878c2ecf20Sopenharmony_ci	}
888c2ecf20Sopenharmony_ci	mutex_unlock(&pvr2_context_mutex);
898c2ecf20Sopenharmony_ci	kfree(mp);
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_ci
938c2ecf20Sopenharmony_cistatic void pvr2_context_notify(struct pvr2_context *mp)
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	pvr2_context_set_notify(mp,!0);
968c2ecf20Sopenharmony_ci}
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci
998c2ecf20Sopenharmony_cistatic void pvr2_context_check(struct pvr2_context *mp)
1008c2ecf20Sopenharmony_ci{
1018c2ecf20Sopenharmony_ci	struct pvr2_channel *ch1, *ch2;
1028c2ecf20Sopenharmony_ci	pvr2_trace(PVR2_TRACE_CTXT,
1038c2ecf20Sopenharmony_ci		   "pvr2_context %p (notify)", mp);
1048c2ecf20Sopenharmony_ci	if (!mp->initialized_flag && !mp->disconnect_flag) {
1058c2ecf20Sopenharmony_ci		mp->initialized_flag = !0;
1068c2ecf20Sopenharmony_ci		pvr2_trace(PVR2_TRACE_CTXT,
1078c2ecf20Sopenharmony_ci			   "pvr2_context %p (initialize)", mp);
1088c2ecf20Sopenharmony_ci		/* Finish hardware initialization */
1098c2ecf20Sopenharmony_ci		if (pvr2_hdw_initialize(mp->hdw,
1108c2ecf20Sopenharmony_ci					(void (*)(void *))pvr2_context_notify,
1118c2ecf20Sopenharmony_ci					mp)) {
1128c2ecf20Sopenharmony_ci			mp->video_stream.stream =
1138c2ecf20Sopenharmony_ci				pvr2_hdw_get_video_stream(mp->hdw);
1148c2ecf20Sopenharmony_ci			/* Trigger interface initialization.  By doing this
1158c2ecf20Sopenharmony_ci			   here initialization runs in our own safe and
1168c2ecf20Sopenharmony_ci			   cozy thread context. */
1178c2ecf20Sopenharmony_ci			if (mp->setup_func) mp->setup_func(mp);
1188c2ecf20Sopenharmony_ci		} else {
1198c2ecf20Sopenharmony_ci			pvr2_trace(PVR2_TRACE_CTXT,
1208c2ecf20Sopenharmony_ci				   "pvr2_context %p (thread skipping setup)",
1218c2ecf20Sopenharmony_ci				   mp);
1228c2ecf20Sopenharmony_ci			/* Even though initialization did not succeed,
1238c2ecf20Sopenharmony_ci			   we're still going to continue anyway.  We need
1248c2ecf20Sopenharmony_ci			   to do this in order to await the expected
1258c2ecf20Sopenharmony_ci			   disconnect (which we will detect in the normal
1268c2ecf20Sopenharmony_ci			   course of operation). */
1278c2ecf20Sopenharmony_ci		}
1288c2ecf20Sopenharmony_ci	}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_ci	for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
1318c2ecf20Sopenharmony_ci		ch2 = ch1->mc_next;
1328c2ecf20Sopenharmony_ci		if (ch1->check_func) ch1->check_func(ch1);
1338c2ecf20Sopenharmony_ci	}
1348c2ecf20Sopenharmony_ci
1358c2ecf20Sopenharmony_ci	if (mp->disconnect_flag && !mp->mc_first) {
1368c2ecf20Sopenharmony_ci		/* Go away... */
1378c2ecf20Sopenharmony_ci		pvr2_context_destroy(mp);
1388c2ecf20Sopenharmony_ci		return;
1398c2ecf20Sopenharmony_ci	}
1408c2ecf20Sopenharmony_ci}
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci
1438c2ecf20Sopenharmony_cistatic int pvr2_context_shutok(void)
1448c2ecf20Sopenharmony_ci{
1458c2ecf20Sopenharmony_ci	return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_ci
1498c2ecf20Sopenharmony_cistatic int pvr2_context_thread_func(void *foo)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	struct pvr2_context *mp;
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	do {
1568c2ecf20Sopenharmony_ci		while ((mp = pvr2_context_notify_first) != NULL) {
1578c2ecf20Sopenharmony_ci			pvr2_context_set_notify(mp, 0);
1588c2ecf20Sopenharmony_ci			pvr2_context_check(mp);
1598c2ecf20Sopenharmony_ci		}
1608c2ecf20Sopenharmony_ci		wait_event_interruptible(
1618c2ecf20Sopenharmony_ci			pvr2_context_sync_data,
1628c2ecf20Sopenharmony_ci			((pvr2_context_notify_first != NULL) ||
1638c2ecf20Sopenharmony_ci			 pvr2_context_shutok()));
1648c2ecf20Sopenharmony_ci	} while (!pvr2_context_shutok());
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	pvr2_context_cleaned_flag = !0;
1678c2ecf20Sopenharmony_ci	wake_up(&pvr2_context_cleanup_data);
1688c2ecf20Sopenharmony_ci
1698c2ecf20Sopenharmony_ci	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	wait_event_interruptible(
1728c2ecf20Sopenharmony_ci		pvr2_context_sync_data,
1738c2ecf20Sopenharmony_ci		kthread_should_stop());
1748c2ecf20Sopenharmony_ci
1758c2ecf20Sopenharmony_ci	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
1768c2ecf20Sopenharmony_ci
1778c2ecf20Sopenharmony_ci	return 0;
1788c2ecf20Sopenharmony_ci}
1798c2ecf20Sopenharmony_ci
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ciint pvr2_context_global_init(void)
1828c2ecf20Sopenharmony_ci{
1838c2ecf20Sopenharmony_ci	pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
1848c2ecf20Sopenharmony_ci					      NULL,
1858c2ecf20Sopenharmony_ci					      "pvrusb2-context");
1868c2ecf20Sopenharmony_ci	return IS_ERR(pvr2_context_thread_ptr) ? -ENOMEM : 0;
1878c2ecf20Sopenharmony_ci}
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_civoid pvr2_context_global_done(void)
1918c2ecf20Sopenharmony_ci{
1928c2ecf20Sopenharmony_ci	pvr2_context_cleanup_flag = !0;
1938c2ecf20Sopenharmony_ci	wake_up(&pvr2_context_sync_data);
1948c2ecf20Sopenharmony_ci	wait_event_interruptible(
1958c2ecf20Sopenharmony_ci		pvr2_context_cleanup_data,
1968c2ecf20Sopenharmony_ci		pvr2_context_cleaned_flag);
1978c2ecf20Sopenharmony_ci	kthread_stop(pvr2_context_thread_ptr);
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci
2018c2ecf20Sopenharmony_cistruct pvr2_context *pvr2_context_create(
2028c2ecf20Sopenharmony_ci	struct usb_interface *intf,
2038c2ecf20Sopenharmony_ci	const struct usb_device_id *devid,
2048c2ecf20Sopenharmony_ci	void (*setup_func)(struct pvr2_context *))
2058c2ecf20Sopenharmony_ci{
2068c2ecf20Sopenharmony_ci	struct pvr2_context *mp = NULL;
2078c2ecf20Sopenharmony_ci	mp = kzalloc(sizeof(*mp),GFP_KERNEL);
2088c2ecf20Sopenharmony_ci	if (!mp) goto done;
2098c2ecf20Sopenharmony_ci	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
2108c2ecf20Sopenharmony_ci	mp->setup_func = setup_func;
2118c2ecf20Sopenharmony_ci	mutex_init(&mp->mutex);
2128c2ecf20Sopenharmony_ci	mutex_lock(&pvr2_context_mutex);
2138c2ecf20Sopenharmony_ci	mp->exist_prev = pvr2_context_exist_last;
2148c2ecf20Sopenharmony_ci	mp->exist_next = NULL;
2158c2ecf20Sopenharmony_ci	pvr2_context_exist_last = mp;
2168c2ecf20Sopenharmony_ci	if (mp->exist_prev) {
2178c2ecf20Sopenharmony_ci		mp->exist_prev->exist_next = mp;
2188c2ecf20Sopenharmony_ci	} else {
2198c2ecf20Sopenharmony_ci		pvr2_context_exist_first = mp;
2208c2ecf20Sopenharmony_ci	}
2218c2ecf20Sopenharmony_ci	mutex_unlock(&pvr2_context_mutex);
2228c2ecf20Sopenharmony_ci	mp->hdw = pvr2_hdw_create(intf,devid);
2238c2ecf20Sopenharmony_ci	if (!mp->hdw) {
2248c2ecf20Sopenharmony_ci		pvr2_context_destroy(mp);
2258c2ecf20Sopenharmony_ci		mp = NULL;
2268c2ecf20Sopenharmony_ci		goto done;
2278c2ecf20Sopenharmony_ci	}
2288c2ecf20Sopenharmony_ci	pvr2_context_set_notify(mp, !0);
2298c2ecf20Sopenharmony_ci done:
2308c2ecf20Sopenharmony_ci	return mp;
2318c2ecf20Sopenharmony_ci}
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_cistatic void pvr2_context_reset_input_limits(struct pvr2_context *mp)
2358c2ecf20Sopenharmony_ci{
2368c2ecf20Sopenharmony_ci	unsigned int tmsk,mmsk;
2378c2ecf20Sopenharmony_ci	struct pvr2_channel *cp;
2388c2ecf20Sopenharmony_ci	struct pvr2_hdw *hdw = mp->hdw;
2398c2ecf20Sopenharmony_ci	mmsk = pvr2_hdw_get_input_available(hdw);
2408c2ecf20Sopenharmony_ci	tmsk = mmsk;
2418c2ecf20Sopenharmony_ci	for (cp = mp->mc_first; cp; cp = cp->mc_next) {
2428c2ecf20Sopenharmony_ci		if (!cp->input_mask) continue;
2438c2ecf20Sopenharmony_ci		tmsk &= cp->input_mask;
2448c2ecf20Sopenharmony_ci	}
2458c2ecf20Sopenharmony_ci	pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
2468c2ecf20Sopenharmony_ci	pvr2_hdw_commit_ctl(hdw);
2478c2ecf20Sopenharmony_ci}
2488c2ecf20Sopenharmony_ci
2498c2ecf20Sopenharmony_ci
2508c2ecf20Sopenharmony_cistatic void pvr2_context_enter(struct pvr2_context *mp)
2518c2ecf20Sopenharmony_ci{
2528c2ecf20Sopenharmony_ci	mutex_lock(&mp->mutex);
2538c2ecf20Sopenharmony_ci}
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci
2568c2ecf20Sopenharmony_cistatic void pvr2_context_exit(struct pvr2_context *mp)
2578c2ecf20Sopenharmony_ci{
2588c2ecf20Sopenharmony_ci	int destroy_flag = 0;
2598c2ecf20Sopenharmony_ci	if (!(mp->mc_first || !mp->disconnect_flag)) {
2608c2ecf20Sopenharmony_ci		destroy_flag = !0;
2618c2ecf20Sopenharmony_ci	}
2628c2ecf20Sopenharmony_ci	mutex_unlock(&mp->mutex);
2638c2ecf20Sopenharmony_ci	if (destroy_flag) pvr2_context_notify(mp);
2648c2ecf20Sopenharmony_ci}
2658c2ecf20Sopenharmony_ci
2668c2ecf20Sopenharmony_ci
2678c2ecf20Sopenharmony_civoid pvr2_context_disconnect(struct pvr2_context *mp)
2688c2ecf20Sopenharmony_ci{
2698c2ecf20Sopenharmony_ci	pvr2_hdw_disconnect(mp->hdw);
2708c2ecf20Sopenharmony_ci	mp->disconnect_flag = !0;
2718c2ecf20Sopenharmony_ci	if (!pvr2_context_shutok())
2728c2ecf20Sopenharmony_ci		pvr2_context_notify(mp);
2738c2ecf20Sopenharmony_ci}
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci
2768c2ecf20Sopenharmony_civoid pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
2778c2ecf20Sopenharmony_ci{
2788c2ecf20Sopenharmony_ci	pvr2_context_enter(mp);
2798c2ecf20Sopenharmony_ci	cp->hdw = mp->hdw;
2808c2ecf20Sopenharmony_ci	cp->mc_head = mp;
2818c2ecf20Sopenharmony_ci	cp->mc_next = NULL;
2828c2ecf20Sopenharmony_ci	cp->mc_prev = mp->mc_last;
2838c2ecf20Sopenharmony_ci	if (mp->mc_last) {
2848c2ecf20Sopenharmony_ci		mp->mc_last->mc_next = cp;
2858c2ecf20Sopenharmony_ci	} else {
2868c2ecf20Sopenharmony_ci		mp->mc_first = cp;
2878c2ecf20Sopenharmony_ci	}
2888c2ecf20Sopenharmony_ci	mp->mc_last = cp;
2898c2ecf20Sopenharmony_ci	pvr2_context_exit(mp);
2908c2ecf20Sopenharmony_ci}
2918c2ecf20Sopenharmony_ci
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_cistatic void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
2948c2ecf20Sopenharmony_ci{
2958c2ecf20Sopenharmony_ci	if (!cp->stream) return;
2968c2ecf20Sopenharmony_ci	pvr2_stream_kill(cp->stream->stream);
2978c2ecf20Sopenharmony_ci	cp->stream->user = NULL;
2988c2ecf20Sopenharmony_ci	cp->stream = NULL;
2998c2ecf20Sopenharmony_ci}
3008c2ecf20Sopenharmony_ci
3018c2ecf20Sopenharmony_ci
3028c2ecf20Sopenharmony_civoid pvr2_channel_done(struct pvr2_channel *cp)
3038c2ecf20Sopenharmony_ci{
3048c2ecf20Sopenharmony_ci	struct pvr2_context *mp = cp->mc_head;
3058c2ecf20Sopenharmony_ci	pvr2_context_enter(mp);
3068c2ecf20Sopenharmony_ci	cp->input_mask = 0;
3078c2ecf20Sopenharmony_ci	pvr2_channel_disclaim_stream(cp);
3088c2ecf20Sopenharmony_ci	pvr2_context_reset_input_limits(mp);
3098c2ecf20Sopenharmony_ci	if (cp->mc_next) {
3108c2ecf20Sopenharmony_ci		cp->mc_next->mc_prev = cp->mc_prev;
3118c2ecf20Sopenharmony_ci	} else {
3128c2ecf20Sopenharmony_ci		mp->mc_last = cp->mc_prev;
3138c2ecf20Sopenharmony_ci	}
3148c2ecf20Sopenharmony_ci	if (cp->mc_prev) {
3158c2ecf20Sopenharmony_ci		cp->mc_prev->mc_next = cp->mc_next;
3168c2ecf20Sopenharmony_ci	} else {
3178c2ecf20Sopenharmony_ci		mp->mc_first = cp->mc_next;
3188c2ecf20Sopenharmony_ci	}
3198c2ecf20Sopenharmony_ci	cp->hdw = NULL;
3208c2ecf20Sopenharmony_ci	pvr2_context_exit(mp);
3218c2ecf20Sopenharmony_ci}
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ciint pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
3258c2ecf20Sopenharmony_ci{
3268c2ecf20Sopenharmony_ci	unsigned int tmsk,mmsk;
3278c2ecf20Sopenharmony_ci	int ret = 0;
3288c2ecf20Sopenharmony_ci	struct pvr2_channel *p2;
3298c2ecf20Sopenharmony_ci	struct pvr2_hdw *hdw = cp->hdw;
3308c2ecf20Sopenharmony_ci
3318c2ecf20Sopenharmony_ci	mmsk = pvr2_hdw_get_input_available(hdw);
3328c2ecf20Sopenharmony_ci	cmsk &= mmsk;
3338c2ecf20Sopenharmony_ci	if (cmsk == cp->input_mask) {
3348c2ecf20Sopenharmony_ci		/* No change; nothing to do */
3358c2ecf20Sopenharmony_ci		return 0;
3368c2ecf20Sopenharmony_ci	}
3378c2ecf20Sopenharmony_ci
3388c2ecf20Sopenharmony_ci	pvr2_context_enter(cp->mc_head);
3398c2ecf20Sopenharmony_ci	do {
3408c2ecf20Sopenharmony_ci		if (!cmsk) {
3418c2ecf20Sopenharmony_ci			cp->input_mask = 0;
3428c2ecf20Sopenharmony_ci			pvr2_context_reset_input_limits(cp->mc_head);
3438c2ecf20Sopenharmony_ci			break;
3448c2ecf20Sopenharmony_ci		}
3458c2ecf20Sopenharmony_ci		tmsk = mmsk;
3468c2ecf20Sopenharmony_ci		for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
3478c2ecf20Sopenharmony_ci			if (p2 == cp) continue;
3488c2ecf20Sopenharmony_ci			if (!p2->input_mask) continue;
3498c2ecf20Sopenharmony_ci			tmsk &= p2->input_mask;
3508c2ecf20Sopenharmony_ci		}
3518c2ecf20Sopenharmony_ci		if (!(tmsk & cmsk)) {
3528c2ecf20Sopenharmony_ci			ret = -EPERM;
3538c2ecf20Sopenharmony_ci			break;
3548c2ecf20Sopenharmony_ci		}
3558c2ecf20Sopenharmony_ci		tmsk &= cmsk;
3568c2ecf20Sopenharmony_ci		if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
3578c2ecf20Sopenharmony_ci			/* Internal failure changing allowed list; probably
3588c2ecf20Sopenharmony_ci			   should not happen, but react if it does. */
3598c2ecf20Sopenharmony_ci			break;
3608c2ecf20Sopenharmony_ci		}
3618c2ecf20Sopenharmony_ci		cp->input_mask = cmsk;
3628c2ecf20Sopenharmony_ci		pvr2_hdw_commit_ctl(hdw);
3638c2ecf20Sopenharmony_ci	} while (0);
3648c2ecf20Sopenharmony_ci	pvr2_context_exit(cp->mc_head);
3658c2ecf20Sopenharmony_ci	return ret;
3668c2ecf20Sopenharmony_ci}
3678c2ecf20Sopenharmony_ci
3688c2ecf20Sopenharmony_ci
3698c2ecf20Sopenharmony_ciunsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
3708c2ecf20Sopenharmony_ci{
3718c2ecf20Sopenharmony_ci	return cp->input_mask;
3728c2ecf20Sopenharmony_ci}
3738c2ecf20Sopenharmony_ci
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_ciint pvr2_channel_claim_stream(struct pvr2_channel *cp,
3768c2ecf20Sopenharmony_ci			      struct pvr2_context_stream *sp)
3778c2ecf20Sopenharmony_ci{
3788c2ecf20Sopenharmony_ci	int code = 0;
3798c2ecf20Sopenharmony_ci	pvr2_context_enter(cp->mc_head); do {
3808c2ecf20Sopenharmony_ci		if (sp == cp->stream) break;
3818c2ecf20Sopenharmony_ci		if (sp && sp->user) {
3828c2ecf20Sopenharmony_ci			code = -EBUSY;
3838c2ecf20Sopenharmony_ci			break;
3848c2ecf20Sopenharmony_ci		}
3858c2ecf20Sopenharmony_ci		pvr2_channel_disclaim_stream(cp);
3868c2ecf20Sopenharmony_ci		if (!sp) break;
3878c2ecf20Sopenharmony_ci		sp->user = cp;
3888c2ecf20Sopenharmony_ci		cp->stream = sp;
3898c2ecf20Sopenharmony_ci	} while (0);
3908c2ecf20Sopenharmony_ci	pvr2_context_exit(cp->mc_head);
3918c2ecf20Sopenharmony_ci	return code;
3928c2ecf20Sopenharmony_ci}
3938c2ecf20Sopenharmony_ci
3948c2ecf20Sopenharmony_ci
3958c2ecf20Sopenharmony_ci// This is the marker for the real beginning of a legitimate mpeg2 stream.
3968c2ecf20Sopenharmony_cistatic char stream_sync_key[] = {
3978c2ecf20Sopenharmony_ci	0x00, 0x00, 0x01, 0xba,
3988c2ecf20Sopenharmony_ci};
3998c2ecf20Sopenharmony_ci
4008c2ecf20Sopenharmony_cistruct pvr2_ioread *pvr2_channel_create_mpeg_stream(
4018c2ecf20Sopenharmony_ci	struct pvr2_context_stream *sp)
4028c2ecf20Sopenharmony_ci{
4038c2ecf20Sopenharmony_ci	struct pvr2_ioread *cp;
4048c2ecf20Sopenharmony_ci	cp = pvr2_ioread_create();
4058c2ecf20Sopenharmony_ci	if (!cp) return NULL;
4068c2ecf20Sopenharmony_ci	pvr2_ioread_setup(cp,sp->stream);
4078c2ecf20Sopenharmony_ci	pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
4088c2ecf20Sopenharmony_ci	return cp;
4098c2ecf20Sopenharmony_ci}
410