1d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely/*
2d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *
3d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
4d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *
5d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *  This program is free software; you can redistribute it and/or modify
6d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *  it under the terms of the GNU General Public License as published by
7d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *  the Free Software Foundation; either version 2 of the License
8d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *
9d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *  This program is distributed in the hope that it will be useful,
10d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *  GNU General Public License for more details.
13d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *
14d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *  You should have received a copy of the GNU General Public License
15d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *  along with this program; if not, write to the Free Software
16d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *
18d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely */
19d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
20d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include "pvrusb2-context.h"
21d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include "pvrusb2-io.h"
22d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include "pvrusb2-ioread.h"
23d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include "pvrusb2-hdw.h"
24d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include "pvrusb2-debug.h"
25e5be15c63804e05b5a94197524023702a259e308Mike Isely#include <linux/wait.h>
26794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely#include <linux/kthread.h>
27d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include <linux/errno.h>
28d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include <linux/string.h>
29d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include <linux/slab.h>
30d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
31e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic struct pvr2_context *pvr2_context_exist_first;
32e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic struct pvr2_context *pvr2_context_exist_last;
33e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic struct pvr2_context *pvr2_context_notify_first;
34e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic struct pvr2_context *pvr2_context_notify_last;
35e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic DEFINE_MUTEX(pvr2_context_mutex);
36e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
3718ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Iselystatic DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
3818ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Iselystatic int pvr2_context_cleanup_flag;
3918ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Iselystatic int pvr2_context_cleaned_flag;
40e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic struct task_struct *pvr2_context_thread_ptr;
41e5be15c63804e05b5a94197524023702a259e308Mike Isely
42e5be15c63804e05b5a94197524023702a259e308Mike Isely
43e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
44e5be15c63804e05b5a94197524023702a259e308Mike Isely{
45e5be15c63804e05b5a94197524023702a259e308Mike Isely	int signal_flag = 0;
46e5be15c63804e05b5a94197524023702a259e308Mike Isely	mutex_lock(&pvr2_context_mutex);
47e5be15c63804e05b5a94197524023702a259e308Mike Isely	if (fl) {
48e5be15c63804e05b5a94197524023702a259e308Mike Isely		if (!mp->notify_flag) {
49e5be15c63804e05b5a94197524023702a259e308Mike Isely			signal_flag = (pvr2_context_notify_first == NULL);
50e5be15c63804e05b5a94197524023702a259e308Mike Isely			mp->notify_prev = pvr2_context_notify_last;
51e5be15c63804e05b5a94197524023702a259e308Mike Isely			mp->notify_next = NULL;
52e5be15c63804e05b5a94197524023702a259e308Mike Isely			pvr2_context_notify_last = mp;
53e5be15c63804e05b5a94197524023702a259e308Mike Isely			if (mp->notify_prev) {
54e5be15c63804e05b5a94197524023702a259e308Mike Isely				mp->notify_prev->notify_next = mp;
55e5be15c63804e05b5a94197524023702a259e308Mike Isely			} else {
56e5be15c63804e05b5a94197524023702a259e308Mike Isely				pvr2_context_notify_first = mp;
57e5be15c63804e05b5a94197524023702a259e308Mike Isely			}
58e5be15c63804e05b5a94197524023702a259e308Mike Isely			mp->notify_flag = !0;
59e5be15c63804e05b5a94197524023702a259e308Mike Isely		}
60e5be15c63804e05b5a94197524023702a259e308Mike Isely	} else {
61e5be15c63804e05b5a94197524023702a259e308Mike Isely		if (mp->notify_flag) {
62e5be15c63804e05b5a94197524023702a259e308Mike Isely			mp->notify_flag = 0;
63e5be15c63804e05b5a94197524023702a259e308Mike Isely			if (mp->notify_next) {
64e5be15c63804e05b5a94197524023702a259e308Mike Isely				mp->notify_next->notify_prev = mp->notify_prev;
65e5be15c63804e05b5a94197524023702a259e308Mike Isely			} else {
66e5be15c63804e05b5a94197524023702a259e308Mike Isely				pvr2_context_notify_last = mp->notify_prev;
67e5be15c63804e05b5a94197524023702a259e308Mike Isely			}
68e5be15c63804e05b5a94197524023702a259e308Mike Isely			if (mp->notify_prev) {
69e5be15c63804e05b5a94197524023702a259e308Mike Isely				mp->notify_prev->notify_next = mp->notify_next;
70e5be15c63804e05b5a94197524023702a259e308Mike Isely			} else {
71e5be15c63804e05b5a94197524023702a259e308Mike Isely				pvr2_context_notify_first = mp->notify_next;
72e5be15c63804e05b5a94197524023702a259e308Mike Isely			}
73e5be15c63804e05b5a94197524023702a259e308Mike Isely		}
74e5be15c63804e05b5a94197524023702a259e308Mike Isely	}
75e5be15c63804e05b5a94197524023702a259e308Mike Isely	mutex_unlock(&pvr2_context_mutex);
76e5be15c63804e05b5a94197524023702a259e308Mike Isely	if (signal_flag) wake_up(&pvr2_context_sync_data);
77e5be15c63804e05b5a94197524023702a259e308Mike Isely}
78e5be15c63804e05b5a94197524023702a259e308Mike Isely
79d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
80d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselystatic void pvr2_context_destroy(struct pvr2_context *mp)
81d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{
82794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
83681c739944018d80dbcf7f19997eba97676c7116Mike Isely	if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
84e5be15c63804e05b5a94197524023702a259e308Mike Isely	pvr2_context_set_notify(mp, 0);
85e5be15c63804e05b5a94197524023702a259e308Mike Isely	mutex_lock(&pvr2_context_mutex);
86e5be15c63804e05b5a94197524023702a259e308Mike Isely	if (mp->exist_next) {
87e5be15c63804e05b5a94197524023702a259e308Mike Isely		mp->exist_next->exist_prev = mp->exist_prev;
88e5be15c63804e05b5a94197524023702a259e308Mike Isely	} else {
89e5be15c63804e05b5a94197524023702a259e308Mike Isely		pvr2_context_exist_last = mp->exist_prev;
90e5be15c63804e05b5a94197524023702a259e308Mike Isely	}
91e5be15c63804e05b5a94197524023702a259e308Mike Isely	if (mp->exist_prev) {
92e5be15c63804e05b5a94197524023702a259e308Mike Isely		mp->exist_prev->exist_next = mp->exist_next;
93e5be15c63804e05b5a94197524023702a259e308Mike Isely	} else {
94e5be15c63804e05b5a94197524023702a259e308Mike Isely		pvr2_context_exist_first = mp->exist_next;
95e5be15c63804e05b5a94197524023702a259e308Mike Isely	}
96e5be15c63804e05b5a94197524023702a259e308Mike Isely	if (!pvr2_context_exist_first) {
97e5be15c63804e05b5a94197524023702a259e308Mike Isely		/* Trigger wakeup on control thread in case it is waiting
98e5be15c63804e05b5a94197524023702a259e308Mike Isely		   for an exit condition. */
99e5be15c63804e05b5a94197524023702a259e308Mike Isely		wake_up(&pvr2_context_sync_data);
100e5be15c63804e05b5a94197524023702a259e308Mike Isely	}
101e5be15c63804e05b5a94197524023702a259e308Mike Isely	mutex_unlock(&pvr2_context_mutex);
102d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	kfree(mp);
103d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely}
104d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
105d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
106794b16072e00d0a40a8c773dd4319fb1e460a632Mike Iselystatic void pvr2_context_notify(struct pvr2_context *mp)
107d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{
108e5be15c63804e05b5a94197524023702a259e308Mike Isely	pvr2_context_set_notify(mp,!0);
109794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely}
110794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely
111794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely
112e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic void pvr2_context_check(struct pvr2_context *mp)
113794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely{
114e5be15c63804e05b5a94197524023702a259e308Mike Isely	struct pvr2_channel *ch1, *ch2;
115e5be15c63804e05b5a94197524023702a259e308Mike Isely	pvr2_trace(PVR2_TRACE_CTXT,
116e5be15c63804e05b5a94197524023702a259e308Mike Isely		   "pvr2_context %p (notify)", mp);
117e5be15c63804e05b5a94197524023702a259e308Mike Isely	if (!mp->initialized_flag && !mp->disconnect_flag) {
118e5be15c63804e05b5a94197524023702a259e308Mike Isely		mp->initialized_flag = !0;
119794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely		pvr2_trace(PVR2_TRACE_CTXT,
120e5be15c63804e05b5a94197524023702a259e308Mike Isely			   "pvr2_context %p (initialize)", mp);
121e5be15c63804e05b5a94197524023702a259e308Mike Isely		/* Finish hardware initialization */
122e5be15c63804e05b5a94197524023702a259e308Mike Isely		if (pvr2_hdw_initialize(mp->hdw,
123e5be15c63804e05b5a94197524023702a259e308Mike Isely					(void (*)(void *))pvr2_context_notify,
124e5be15c63804e05b5a94197524023702a259e308Mike Isely					mp)) {
125e5be15c63804e05b5a94197524023702a259e308Mike Isely			mp->video_stream.stream =
126e5be15c63804e05b5a94197524023702a259e308Mike Isely				pvr2_hdw_get_video_stream(mp->hdw);
127e5be15c63804e05b5a94197524023702a259e308Mike Isely			/* Trigger interface initialization.  By doing this
128e5be15c63804e05b5a94197524023702a259e308Mike Isely			   here initialization runs in our own safe and
129e5be15c63804e05b5a94197524023702a259e308Mike Isely			   cozy thread context. */
130e5be15c63804e05b5a94197524023702a259e308Mike Isely			if (mp->setup_func) mp->setup_func(mp);
131e5be15c63804e05b5a94197524023702a259e308Mike Isely		} else {
132794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely			pvr2_trace(PVR2_TRACE_CTXT,
133e5be15c63804e05b5a94197524023702a259e308Mike Isely				   "pvr2_context %p (thread skipping setup)",
134e5be15c63804e05b5a94197524023702a259e308Mike Isely				   mp);
135e5be15c63804e05b5a94197524023702a259e308Mike Isely			/* Even though initialization did not succeed,
136e5be15c63804e05b5a94197524023702a259e308Mike Isely			   we're still going to continue anyway.  We need
137e5be15c63804e05b5a94197524023702a259e308Mike Isely			   to do this in order to await the expected
138e5be15c63804e05b5a94197524023702a259e308Mike Isely			   disconnect (which we will detect in the normal
139e5be15c63804e05b5a94197524023702a259e308Mike Isely			   course of operation). */
140d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		}
141794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	}
142e5be15c63804e05b5a94197524023702a259e308Mike Isely
143e5be15c63804e05b5a94197524023702a259e308Mike Isely	for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
144e5be15c63804e05b5a94197524023702a259e308Mike Isely		ch2 = ch1->mc_next;
145e5be15c63804e05b5a94197524023702a259e308Mike Isely		if (ch1->check_func) ch1->check_func(ch1);
146e5be15c63804e05b5a94197524023702a259e308Mike Isely	}
147e5be15c63804e05b5a94197524023702a259e308Mike Isely
148e5be15c63804e05b5a94197524023702a259e308Mike Isely	if (mp->disconnect_flag && !mp->mc_first) {
149e5be15c63804e05b5a94197524023702a259e308Mike Isely		/* Go away... */
150e5be15c63804e05b5a94197524023702a259e308Mike Isely		pvr2_context_destroy(mp);
151e5be15c63804e05b5a94197524023702a259e308Mike Isely		return;
152e5be15c63804e05b5a94197524023702a259e308Mike Isely	}
153e5be15c63804e05b5a94197524023702a259e308Mike Isely}
154e5be15c63804e05b5a94197524023702a259e308Mike Isely
155e5be15c63804e05b5a94197524023702a259e308Mike Isely
156e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic int pvr2_context_shutok(void)
157e5be15c63804e05b5a94197524023702a259e308Mike Isely{
15818ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely	return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
159e5be15c63804e05b5a94197524023702a259e308Mike Isely}
160e5be15c63804e05b5a94197524023702a259e308Mike Isely
161e5be15c63804e05b5a94197524023702a259e308Mike Isely
162e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic int pvr2_context_thread_func(void *foo)
163e5be15c63804e05b5a94197524023702a259e308Mike Isely{
164e5be15c63804e05b5a94197524023702a259e308Mike Isely	struct pvr2_context *mp;
165e5be15c63804e05b5a94197524023702a259e308Mike Isely
166e5be15c63804e05b5a94197524023702a259e308Mike Isely	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");
167e5be15c63804e05b5a94197524023702a259e308Mike Isely
168e5be15c63804e05b5a94197524023702a259e308Mike Isely	do {
169e5be15c63804e05b5a94197524023702a259e308Mike Isely		while ((mp = pvr2_context_notify_first) != NULL) {
170e5be15c63804e05b5a94197524023702a259e308Mike Isely			pvr2_context_set_notify(mp, 0);
171e5be15c63804e05b5a94197524023702a259e308Mike Isely			pvr2_context_check(mp);
172e5be15c63804e05b5a94197524023702a259e308Mike Isely		}
173e5be15c63804e05b5a94197524023702a259e308Mike Isely		wait_event_interruptible(
174e5be15c63804e05b5a94197524023702a259e308Mike Isely			pvr2_context_sync_data,
175e5be15c63804e05b5a94197524023702a259e308Mike Isely			((pvr2_context_notify_first != NULL) ||
176e5be15c63804e05b5a94197524023702a259e308Mike Isely			 pvr2_context_shutok()));
177e5be15c63804e05b5a94197524023702a259e308Mike Isely	} while (!pvr2_context_shutok());
178e5be15c63804e05b5a94197524023702a259e308Mike Isely
17918ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely	pvr2_context_cleaned_flag = !0;
18018ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely	wake_up(&pvr2_context_cleanup_data);
18118ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely
18218ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");
18318ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely
18418ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely	wait_event_interruptible(
18518ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely		pvr2_context_sync_data,
18618ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely		kthread_should_stop());
18718ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely
188e5be15c63804e05b5a94197524023702a259e308Mike Isely	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
189e5be15c63804e05b5a94197524023702a259e308Mike Isely
190794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	return 0;
191794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely}
192d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
193d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
194e5be15c63804e05b5a94197524023702a259e308Mike Iselyint pvr2_context_global_init(void)
195e5be15c63804e05b5a94197524023702a259e308Mike Isely{
196e5be15c63804e05b5a94197524023702a259e308Mike Isely	pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
197a6a3a17b7fdaf824e6d73e8e4a94c9d149302f74Harvey Harrison					      NULL,
198e5be15c63804e05b5a94197524023702a259e308Mike Isely					      "pvrusb2-context");
199e5be15c63804e05b5a94197524023702a259e308Mike Isely	return (pvr2_context_thread_ptr ? 0 : -ENOMEM);
200e5be15c63804e05b5a94197524023702a259e308Mike Isely}
201e5be15c63804e05b5a94197524023702a259e308Mike Isely
202e5be15c63804e05b5a94197524023702a259e308Mike Isely
203e5be15c63804e05b5a94197524023702a259e308Mike Iselyvoid pvr2_context_global_done(void)
204e5be15c63804e05b5a94197524023702a259e308Mike Isely{
20518ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely	pvr2_context_cleanup_flag = !0;
20618ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely	wake_up(&pvr2_context_sync_data);
20718ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely	wait_event_interruptible(
20818ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely		pvr2_context_cleanup_data,
20918ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely		pvr2_context_cleaned_flag);
210e5be15c63804e05b5a94197524023702a259e308Mike Isely	kthread_stop(pvr2_context_thread_ptr);
211e5be15c63804e05b5a94197524023702a259e308Mike Isely}
212e5be15c63804e05b5a94197524023702a259e308Mike Isely
213e5be15c63804e05b5a94197524023702a259e308Mike Isely
214d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselystruct pvr2_context *pvr2_context_create(
215d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	struct usb_interface *intf,
216d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	const struct usb_device_id *devid,
217d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	void (*setup_func)(struct pvr2_context *))
218d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{
219a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely	struct pvr2_context *mp = NULL;
220ca545f7c39476c6c4c6e639452180a2b38342669Mike Isely	mp = kzalloc(sizeof(*mp),GFP_KERNEL);
221d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	if (!mp) goto done;
222794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
223d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	mp->setup_func = setup_func;
224d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	mutex_init(&mp->mutex);
225e5be15c63804e05b5a94197524023702a259e308Mike Isely	mutex_lock(&pvr2_context_mutex);
226e5be15c63804e05b5a94197524023702a259e308Mike Isely	mp->exist_prev = pvr2_context_exist_last;
227e5be15c63804e05b5a94197524023702a259e308Mike Isely	mp->exist_next = NULL;
228e5be15c63804e05b5a94197524023702a259e308Mike Isely	pvr2_context_exist_last = mp;
229e5be15c63804e05b5a94197524023702a259e308Mike Isely	if (mp->exist_prev) {
230e5be15c63804e05b5a94197524023702a259e308Mike Isely		mp->exist_prev->exist_next = mp;
231e5be15c63804e05b5a94197524023702a259e308Mike Isely	} else {
232e5be15c63804e05b5a94197524023702a259e308Mike Isely		pvr2_context_exist_first = mp;
233e5be15c63804e05b5a94197524023702a259e308Mike Isely	}
234e5be15c63804e05b5a94197524023702a259e308Mike Isely	mutex_unlock(&pvr2_context_mutex);
235d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	mp->hdw = pvr2_hdw_create(intf,devid);
236d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	if (!mp->hdw) {
237d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		pvr2_context_destroy(mp);
238a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely		mp = NULL;
239d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		goto done;
240d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	}
241e5be15c63804e05b5a94197524023702a259e308Mike Isely	pvr2_context_set_notify(mp, !0);
242d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely done:
243d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	return mp;
244d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely}
245d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
246d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
2471cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Iselystatic void pvr2_context_reset_input_limits(struct pvr2_context *mp)
2481cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely{
2491cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	unsigned int tmsk,mmsk;
2501cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	struct pvr2_channel *cp;
2511cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	struct pvr2_hdw *hdw = mp->hdw;
2521cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	mmsk = pvr2_hdw_get_input_available(hdw);
2531cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	tmsk = mmsk;
2541cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	for (cp = mp->mc_first; cp; cp = cp->mc_next) {
2551cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		if (!cp->input_mask) continue;
2561cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		tmsk &= cp->input_mask;
2571cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	}
2581cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
2591cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	pvr2_hdw_commit_ctl(hdw);
2601cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely}
2611cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely
2621cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely
263794b16072e00d0a40a8c773dd4319fb1e460a632Mike Iselystatic void pvr2_context_enter(struct pvr2_context *mp)
264d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{
265d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	mutex_lock(&mp->mutex);
266d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely}
267d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
268d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
269794b16072e00d0a40a8c773dd4319fb1e460a632Mike Iselystatic void pvr2_context_exit(struct pvr2_context *mp)
270d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{
271d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	int destroy_flag = 0;
272d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	if (!(mp->mc_first || !mp->disconnect_flag)) {
273d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		destroy_flag = !0;
274d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	}
275d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	mutex_unlock(&mp->mutex);
276794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	if (destroy_flag) pvr2_context_notify(mp);
277d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely}
278d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
279d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
280d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselyvoid pvr2_context_disconnect(struct pvr2_context *mp)
281d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{
282794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	pvr2_hdw_disconnect(mp->hdw);
283794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	mp->disconnect_flag = !0;
284794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	pvr2_context_notify(mp);
285d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely}
286d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
287d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
288d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselyvoid pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
289d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{
290794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	pvr2_context_enter(mp);
291d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	cp->hdw = mp->hdw;
292d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	cp->mc_head = mp;
293a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely	cp->mc_next = NULL;
294d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	cp->mc_prev = mp->mc_last;
295d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	if (mp->mc_last) {
296d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		mp->mc_last->mc_next = cp;
297d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	} else {
298d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		mp->mc_first = cp;
299d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	}
300d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	mp->mc_last = cp;
301794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	pvr2_context_exit(mp);
302d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely}
303d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
304d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
305d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselystatic void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
306d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{
307d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	if (!cp->stream) return;
308d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	pvr2_stream_kill(cp->stream->stream);
309a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely	cp->stream->user = NULL;
310a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely	cp->stream = NULL;
311d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely}
312d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
313d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
314d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselyvoid pvr2_channel_done(struct pvr2_channel *cp)
315d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{
316d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	struct pvr2_context *mp = cp->mc_head;
317794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	pvr2_context_enter(mp);
3181cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	cp->input_mask = 0;
319d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	pvr2_channel_disclaim_stream(cp);
3201cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	pvr2_context_reset_input_limits(mp);
321d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	if (cp->mc_next) {
322d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		cp->mc_next->mc_prev = cp->mc_prev;
323d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	} else {
324d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		mp->mc_last = cp->mc_prev;
325d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	}
326d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	if (cp->mc_prev) {
327d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		cp->mc_prev->mc_next = cp->mc_next;
328d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	} else {
329d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		mp->mc_first = cp->mc_next;
330d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	}
331a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely	cp->hdw = NULL;
332794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely	pvr2_context_exit(mp);
333d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely}
334d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
335d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
3361cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Iselyint pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
3371cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely{
3381cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	unsigned int tmsk,mmsk;
3391cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	int ret = 0;
3401cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	struct pvr2_channel *p2;
3411cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	struct pvr2_hdw *hdw = cp->hdw;
3421cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely
3431cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	mmsk = pvr2_hdw_get_input_available(hdw);
3441cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	cmsk &= mmsk;
3451cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	if (cmsk == cp->input_mask) {
3461cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		/* No change; nothing to do */
3471cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		return 0;
3481cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	}
3491cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely
3501cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	pvr2_context_enter(cp->mc_head);
3511cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	do {
3521cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		if (!cmsk) {
3531cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely			cp->input_mask = 0;
3541cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely			pvr2_context_reset_input_limits(cp->mc_head);
3551cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely			break;
3561cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		}
3571cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		tmsk = mmsk;
3581cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
3591cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely			if (p2 == cp) continue;
3601cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely			if (!p2->input_mask) continue;
3611cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely			tmsk &= p2->input_mask;
3621cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		}
3631cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		if (!(tmsk & cmsk)) {
3641cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely			ret = -EPERM;
3651cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely			break;
3661cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		}
3671cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		tmsk &= cmsk;
3681cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
3691cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely			/* Internal failure changing allowed list; probably
3701cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely			   should not happen, but react if it does. */
3711cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely			break;
3721cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		}
3731cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		cp->input_mask = cmsk;
3741cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely		pvr2_hdw_commit_ctl(hdw);
3751cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	} while (0);
3761cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	pvr2_context_exit(cp->mc_head);
3771cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	return ret;
3781cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely}
3791cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely
3801cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely
3811cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Iselyunsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
3821cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely{
3831cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely	return cp->input_mask;
3841cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely}
3851cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely
3861cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely
387d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselyint pvr2_channel_claim_stream(struct pvr2_channel *cp,
388d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely			      struct pvr2_context_stream *sp)
389d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{
390d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	int code = 0;
391d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	pvr2_context_enter(cp->mc_head); do {
392d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		if (sp == cp->stream) break;
39399a6acf9a7a80da49e85be964b15ffed9ab7643eMike Isely		if (sp && sp->user) {
394d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely			code = -EBUSY;
395d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely			break;
396d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		}
397d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		pvr2_channel_disclaim_stream(cp);
398d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		if (!sp) break;
399d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		sp->user = cp;
400d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely		cp->stream = sp;
401d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	} while (0); pvr2_context_exit(cp->mc_head);
402d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	return code;
403d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely}
404d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
405d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
406d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely// This is the marker for the real beginning of a legitimate mpeg2 stream.
407d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselystatic char stream_sync_key[] = {
408d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	0x00, 0x00, 0x01, 0xba,
409d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely};
410d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
411d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselystruct pvr2_ioread *pvr2_channel_create_mpeg_stream(
412d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	struct pvr2_context_stream *sp)
413d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{
414d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	struct pvr2_ioread *cp;
415d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	cp = pvr2_ioread_create();
416a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely	if (!cp) return NULL;
417d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	pvr2_ioread_setup(cp,sp->stream);
418d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
419d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely	return cp;
420d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely}
421d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
422d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely
423d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely/*
424d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely  Stuff for Emacs to see, in order to encourage consistent editing style:
425d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely  *** Local Variables: ***
426d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely  *** mode: c ***
427d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely  *** fill-column: 75 ***
428d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely  *** tab-width: 8 ***
429d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely  *** c-basic-offset: 8 ***
430d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely  *** End: ***
431d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely  */
432