4 * Copyright (C) 2005 Mike Isely <isely@pobox.com>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "pvrusb2-context.h"
22 #include "pvrusb2-io.h"
23 #include "pvrusb2-ioread.h"
24 #include "pvrusb2-hdw.h"
25 #include "pvrusb2-debug.h"
26 #include <linux/wait.h>
27 #include <linux/kthread.h>
28 #include <linux/errno.h>
29 #include <linux/string.h>
30 #include <linux/slab.h>
32 static struct pvr2_context *pvr2_context_exist_first;
33 static struct pvr2_context *pvr2_context_exist_last;
34 static struct pvr2_context *pvr2_context_notify_first;
35 static struct pvr2_context *pvr2_context_notify_last;
36 static DEFINE_MUTEX(pvr2_context_mutex);
37 static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
38 static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
39 static int pvr2_context_cleanup_flag;
40 static int pvr2_context_cleaned_flag;
41 static struct task_struct *pvr2_context_thread_ptr;
44 static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
47 mutex_lock(&pvr2_context_mutex);
49 if (!mp->notify_flag) {
50 signal_flag = (pvr2_context_notify_first == NULL);
51 mp->notify_prev = pvr2_context_notify_last;
52 mp->notify_next = NULL;
53 pvr2_context_notify_last = mp;
54 if (mp->notify_prev) {
55 mp->notify_prev->notify_next = mp;
57 pvr2_context_notify_first = mp;
62 if (mp->notify_flag) {
64 if (mp->notify_next) {
65 mp->notify_next->notify_prev = mp->notify_prev;
67 pvr2_context_notify_last = mp->notify_prev;
69 if (mp->notify_prev) {
70 mp->notify_prev->notify_next = mp->notify_next;
72 pvr2_context_notify_first = mp->notify_next;
76 mutex_unlock(&pvr2_context_mutex);
77 if (signal_flag) wake_up(&pvr2_context_sync_data);
81 static void pvr2_context_destroy(struct pvr2_context *mp)
83 pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
84 if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
85 pvr2_context_set_notify(mp, 0);
86 mutex_lock(&pvr2_context_mutex);
88 mp->exist_next->exist_prev = mp->exist_prev;
90 pvr2_context_exist_last = mp->exist_prev;
93 mp->exist_prev->exist_next = mp->exist_next;
95 pvr2_context_exist_first = mp->exist_next;
97 if (!pvr2_context_exist_first) {
98 /* Trigger wakeup on control thread in case it is waiting
99 for an exit condition. */
100 wake_up(&pvr2_context_sync_data);
102 mutex_unlock(&pvr2_context_mutex);
107 static void pvr2_context_notify(struct pvr2_context *mp)
109 pvr2_context_set_notify(mp,!0);
113 static void pvr2_context_check(struct pvr2_context *mp)
115 struct pvr2_channel *ch1, *ch2;
116 pvr2_trace(PVR2_TRACE_CTXT,
117 "pvr2_context %p (notify)", mp);
118 if (!mp->initialized_flag && !mp->disconnect_flag) {
119 mp->initialized_flag = !0;
120 pvr2_trace(PVR2_TRACE_CTXT,
121 "pvr2_context %p (initialize)", mp);
122 /* Finish hardware initialization */
123 if (pvr2_hdw_initialize(mp->hdw,
124 (void (*)(void *))pvr2_context_notify,
126 mp->video_stream.stream =
127 pvr2_hdw_get_video_stream(mp->hdw);
128 /* Trigger interface initialization. By doing this
129 here initialization runs in our own safe and
130 cozy thread context. */
131 if (mp->setup_func) mp->setup_func(mp);
133 pvr2_trace(PVR2_TRACE_CTXT,
134 "pvr2_context %p (thread skipping setup)",
136 /* Even though initialization did not succeed,
137 we're still going to continue anyway. We need
138 to do this in order to await the expected
139 disconnect (which we will detect in the normal
140 course of operation). */
144 for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
146 if (ch1->check_func) ch1->check_func(ch1);
149 if (mp->disconnect_flag && !mp->mc_first) {
151 pvr2_context_destroy(mp);
157 static int pvr2_context_shutok(void)
159 return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
163 static int pvr2_context_thread_func(void *foo)
165 struct pvr2_context *mp;
167 pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");
170 while ((mp = pvr2_context_notify_first) != NULL) {
171 pvr2_context_set_notify(mp, 0);
172 pvr2_context_check(mp);
174 wait_event_interruptible(
175 pvr2_context_sync_data,
176 ((pvr2_context_notify_first != NULL) ||
177 pvr2_context_shutok()));
178 } while (!pvr2_context_shutok());
180 pvr2_context_cleaned_flag = !0;
181 wake_up(&pvr2_context_cleanup_data);
183 pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");
185 wait_event_interruptible(
186 pvr2_context_sync_data,
187 kthread_should_stop());
189 pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
195 int pvr2_context_global_init(void)
197 pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
200 return (pvr2_context_thread_ptr ? 0 : -ENOMEM);
204 void pvr2_context_global_done(void)
206 pvr2_context_cleanup_flag = !0;
207 wake_up(&pvr2_context_sync_data);
208 wait_event_interruptible(
209 pvr2_context_cleanup_data,
210 pvr2_context_cleaned_flag);
211 kthread_stop(pvr2_context_thread_ptr);
215 struct pvr2_context *pvr2_context_create(
216 struct usb_interface *intf,
217 const struct usb_device_id *devid,
218 void (*setup_func)(struct pvr2_context *))
220 struct pvr2_context *mp = NULL;
221 mp = kzalloc(sizeof(*mp),GFP_KERNEL);
223 pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
224 mp->setup_func = setup_func;
225 mutex_init(&mp->mutex);
226 mutex_lock(&pvr2_context_mutex);
227 mp->exist_prev = pvr2_context_exist_last;
228 mp->exist_next = NULL;
229 pvr2_context_exist_last = mp;
230 if (mp->exist_prev) {
231 mp->exist_prev->exist_next = mp;
233 pvr2_context_exist_first = mp;
235 mutex_unlock(&pvr2_context_mutex);
236 mp->hdw = pvr2_hdw_create(intf,devid);
238 pvr2_context_destroy(mp);
242 pvr2_context_set_notify(mp, !0);
248 static void pvr2_context_reset_input_limits(struct pvr2_context *mp)
250 unsigned int tmsk,mmsk;
251 struct pvr2_channel *cp;
252 struct pvr2_hdw *hdw = mp->hdw;
253 mmsk = pvr2_hdw_get_input_available(hdw);
255 for (cp = mp->mc_first; cp; cp = cp->mc_next) {
256 if (!cp->input_mask) continue;
257 tmsk &= cp->input_mask;
259 pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
260 pvr2_hdw_commit_ctl(hdw);
264 static void pvr2_context_enter(struct pvr2_context *mp)
266 mutex_lock(&mp->mutex);
270 static void pvr2_context_exit(struct pvr2_context *mp)
272 int destroy_flag = 0;
273 if (!(mp->mc_first || !mp->disconnect_flag)) {
276 mutex_unlock(&mp->mutex);
277 if (destroy_flag) pvr2_context_notify(mp);
281 void pvr2_context_disconnect(struct pvr2_context *mp)
283 pvr2_hdw_disconnect(mp->hdw);
284 mp->disconnect_flag = !0;
285 pvr2_context_notify(mp);
289 void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
291 pvr2_context_enter(mp);
295 cp->mc_prev = mp->mc_last;
297 mp->mc_last->mc_next = cp;
302 pvr2_context_exit(mp);
306 static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
308 if (!cp->stream) return;
309 pvr2_stream_kill(cp->stream->stream);
310 cp->stream->user = NULL;
315 void pvr2_channel_done(struct pvr2_channel *cp)
317 struct pvr2_context *mp = cp->mc_head;
318 pvr2_context_enter(mp);
320 pvr2_channel_disclaim_stream(cp);
321 pvr2_context_reset_input_limits(mp);
323 cp->mc_next->mc_prev = cp->mc_prev;
325 mp->mc_last = cp->mc_prev;
328 cp->mc_prev->mc_next = cp->mc_next;
330 mp->mc_first = cp->mc_next;
333 pvr2_context_exit(mp);
337 int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
339 unsigned int tmsk,mmsk;
341 struct pvr2_channel *p2;
342 struct pvr2_hdw *hdw = cp->hdw;
344 mmsk = pvr2_hdw_get_input_available(hdw);
346 if (cmsk == cp->input_mask) {
347 /* No change; nothing to do */
351 pvr2_context_enter(cp->mc_head);
355 pvr2_context_reset_input_limits(cp->mc_head);
359 for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
360 if (p2 == cp) continue;
361 if (!p2->input_mask) continue;
362 tmsk &= p2->input_mask;
364 if (!(tmsk & cmsk)) {
369 if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
370 /* Internal failure changing allowed list; probably
371 should not happen, but react if it does. */
374 cp->input_mask = cmsk;
375 pvr2_hdw_commit_ctl(hdw);
377 pvr2_context_exit(cp->mc_head);
382 unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
384 return cp->input_mask;
388 int pvr2_channel_claim_stream(struct pvr2_channel *cp,
389 struct pvr2_context_stream *sp)
392 pvr2_context_enter(cp->mc_head); do {
393 if (sp == cp->stream) break;
394 if (sp && sp->user) {
398 pvr2_channel_disclaim_stream(cp);
402 } while (0); pvr2_context_exit(cp->mc_head);
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,
412 struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
413 struct pvr2_context_stream *sp)
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));
425 Stuff for Emacs to see, in order to encourage consistent editing style:
426 *** Local Variables: ***
428 *** fill-column: 75 ***
430 *** c-basic-offset: 8 ***