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