]> pilppa.org Git - linux-2.6-omap-h63xx.git/blob - drivers/media/video/pvrusb2/pvrusb2-context.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[linux-2.6-omap-h63xx.git] / drivers / media / video / pvrusb2 / pvrusb2-context.c
1 /*
2  *  $Id$
3  *
4  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
5  *
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
9  *
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.
14  *
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
18  *
19  */
20
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>
31
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;
42
43
44 static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
45 {
46         int signal_flag = 0;
47         mutex_lock(&pvr2_context_mutex);
48         if (fl) {
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;
56                         } else {
57                                 pvr2_context_notify_first = mp;
58                         }
59                         mp->notify_flag = !0;
60                 }
61         } else {
62                 if (mp->notify_flag) {
63                         mp->notify_flag = 0;
64                         if (mp->notify_next) {
65                                 mp->notify_next->notify_prev = mp->notify_prev;
66                         } else {
67                                 pvr2_context_notify_last = mp->notify_prev;
68                         }
69                         if (mp->notify_prev) {
70                                 mp->notify_prev->notify_next = mp->notify_next;
71                         } else {
72                                 pvr2_context_notify_first = mp->notify_next;
73                         }
74                 }
75         }
76         mutex_unlock(&pvr2_context_mutex);
77         if (signal_flag) wake_up(&pvr2_context_sync_data);
78 }
79
80
81 static void pvr2_context_destroy(struct pvr2_context *mp)
82 {
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);
87         if (mp->exist_next) {
88                 mp->exist_next->exist_prev = mp->exist_prev;
89         } else {
90                 pvr2_context_exist_last = mp->exist_prev;
91         }
92         if (mp->exist_prev) {
93                 mp->exist_prev->exist_next = mp->exist_next;
94         } else {
95                 pvr2_context_exist_first = mp->exist_next;
96         }
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);
101         }
102         mutex_unlock(&pvr2_context_mutex);
103         kfree(mp);
104 }
105
106
107 static void pvr2_context_notify(struct pvr2_context *mp)
108 {
109         pvr2_context_set_notify(mp,!0);
110 }
111
112
113 static void pvr2_context_check(struct pvr2_context *mp)
114 {
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,
125                                         mp)) {
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);
132                 } else {
133                         pvr2_trace(PVR2_TRACE_CTXT,
134                                    "pvr2_context %p (thread skipping setup)",
135                                    mp);
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). */
141                 }
142         }
143
144         for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
145                 ch2 = ch1->mc_next;
146                 if (ch1->check_func) ch1->check_func(ch1);
147         }
148
149         if (mp->disconnect_flag && !mp->mc_first) {
150                 /* Go away... */
151                 pvr2_context_destroy(mp);
152                 return;
153         }
154 }
155
156
157 static int pvr2_context_shutok(void)
158 {
159         return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
160 }
161
162
163 static int pvr2_context_thread_func(void *foo)
164 {
165         struct pvr2_context *mp;
166
167         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");
168
169         do {
170                 while ((mp = pvr2_context_notify_first) != NULL) {
171                         pvr2_context_set_notify(mp, 0);
172                         pvr2_context_check(mp);
173                 }
174                 wait_event_interruptible(
175                         pvr2_context_sync_data,
176                         ((pvr2_context_notify_first != NULL) ||
177                          pvr2_context_shutok()));
178         } while (!pvr2_context_shutok());
179
180         pvr2_context_cleaned_flag = !0;
181         wake_up(&pvr2_context_cleanup_data);
182
183         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");
184
185         wait_event_interruptible(
186                 pvr2_context_sync_data,
187                 kthread_should_stop());
188
189         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
190
191         return 0;
192 }
193
194
195 int pvr2_context_global_init(void)
196 {
197         pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
198                                               0,
199                                               "pvrusb2-context");
200         return (pvr2_context_thread_ptr ? 0 : -ENOMEM);
201 }
202
203
204 void pvr2_context_global_done(void)
205 {
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);
212 }
213
214
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 *))
219 {
220         struct pvr2_context *mp = NULL;
221         mp = kzalloc(sizeof(*mp),GFP_KERNEL);
222         if (!mp) goto done;
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;
232         } else {
233                 pvr2_context_exist_first = mp;
234         }
235         mutex_unlock(&pvr2_context_mutex);
236         mp->hdw = pvr2_hdw_create(intf,devid);
237         if (!mp->hdw) {
238                 pvr2_context_destroy(mp);
239                 mp = NULL;
240                 goto done;
241         }
242         pvr2_context_set_notify(mp, !0);
243  done:
244         return mp;
245 }
246
247
248 static void pvr2_context_reset_input_limits(struct pvr2_context *mp)
249 {
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);
254         tmsk = mmsk;
255         for (cp = mp->mc_first; cp; cp = cp->mc_next) {
256                 if (!cp->input_mask) continue;
257                 tmsk &= cp->input_mask;
258         }
259         pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
260         pvr2_hdw_commit_ctl(hdw);
261 }
262
263
264 static void pvr2_context_enter(struct pvr2_context *mp)
265 {
266         mutex_lock(&mp->mutex);
267 }
268
269
270 static void pvr2_context_exit(struct pvr2_context *mp)
271 {
272         int destroy_flag = 0;
273         if (!(mp->mc_first || !mp->disconnect_flag)) {
274                 destroy_flag = !0;
275         }
276         mutex_unlock(&mp->mutex);
277         if (destroy_flag) pvr2_context_notify(mp);
278 }
279
280
281 void pvr2_context_disconnect(struct pvr2_context *mp)
282 {
283         pvr2_hdw_disconnect(mp->hdw);
284         mp->disconnect_flag = !0;
285         pvr2_context_notify(mp);
286 }
287
288
289 void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
290 {
291         pvr2_context_enter(mp);
292         cp->hdw = mp->hdw;
293         cp->mc_head = mp;
294         cp->mc_next = NULL;
295         cp->mc_prev = mp->mc_last;
296         if (mp->mc_last) {
297                 mp->mc_last->mc_next = cp;
298         } else {
299                 mp->mc_first = cp;
300         }
301         mp->mc_last = cp;
302         pvr2_context_exit(mp);
303 }
304
305
306 static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
307 {
308         if (!cp->stream) return;
309         pvr2_stream_kill(cp->stream->stream);
310         cp->stream->user = NULL;
311         cp->stream = NULL;
312 }
313
314
315 void pvr2_channel_done(struct pvr2_channel *cp)
316 {
317         struct pvr2_context *mp = cp->mc_head;
318         pvr2_context_enter(mp);
319         cp->input_mask = 0;
320         pvr2_channel_disclaim_stream(cp);
321         pvr2_context_reset_input_limits(mp);
322         if (cp->mc_next) {
323                 cp->mc_next->mc_prev = cp->mc_prev;
324         } else {
325                 mp->mc_last = cp->mc_prev;
326         }
327         if (cp->mc_prev) {
328                 cp->mc_prev->mc_next = cp->mc_next;
329         } else {
330                 mp->mc_first = cp->mc_next;
331         }
332         cp->hdw = NULL;
333         pvr2_context_exit(mp);
334 }
335
336
337 int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
338 {
339         unsigned int tmsk,mmsk;
340         int ret = 0;
341         struct pvr2_channel *p2;
342         struct pvr2_hdw *hdw = cp->hdw;
343
344         mmsk = pvr2_hdw_get_input_available(hdw);
345         cmsk &= mmsk;
346         if (cmsk == cp->input_mask) {
347                 /* No change; nothing to do */
348                 return 0;
349         }
350
351         pvr2_context_enter(cp->mc_head);
352         do {
353                 if (!cmsk) {
354                         cp->input_mask = 0;
355                         pvr2_context_reset_input_limits(cp->mc_head);
356                         break;
357                 }
358                 tmsk = mmsk;
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;
363                 }
364                 if (!(tmsk & cmsk)) {
365                         ret = -EPERM;
366                         break;
367                 }
368                 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. */
372                         break;
373                 }
374                 cp->input_mask = cmsk;
375                 pvr2_hdw_commit_ctl(hdw);
376         } while (0);
377         pvr2_context_exit(cp->mc_head);
378         return ret;
379 }
380
381
382 unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
383 {
384         return cp->input_mask;
385 }
386
387
388 int pvr2_channel_claim_stream(struct pvr2_channel *cp,
389                               struct pvr2_context_stream *sp)
390 {
391         int code = 0;
392         pvr2_context_enter(cp->mc_head); do {
393                 if (sp == cp->stream) break;
394                 if (sp && sp->user) {
395                         code = -EBUSY;
396                         break;
397                 }
398                 pvr2_channel_disclaim_stream(cp);
399                 if (!sp) break;
400                 sp->user = cp;
401                 cp->stream = sp;
402         } while (0); 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
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
423
424 /*
425   Stuff for Emacs to see, in order to encourage consistent editing style:
426   *** Local Variables: ***
427   *** mode: c ***
428   *** fill-column: 75 ***
429   *** tab-width: 8 ***
430   *** c-basic-offset: 8 ***
431   *** End: ***
432   */