V4L/DVB (7321): pvrusb2: Rework context handling and initialization
[pandora-kernel.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/kthread.h>
27 #include <linux/errno.h>
28 #include <linux/string.h>
29 #include <linux/slab.h>
30
31
32 static void pvr2_context_destroy(struct pvr2_context *mp)
33 {
34         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
35         if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
36         kfree(mp);
37 }
38
39
40 static void pvr2_context_notify(struct pvr2_context *mp)
41 {
42         mp->notify_flag = !0;
43         wake_up(&mp->wait_data);
44 }
45
46
47 static int pvr2_context_thread(void *_mp)
48 {
49         struct pvr2_channel *ch1,*ch2;
50         struct pvr2_context *mp = _mp;
51         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread start)",mp);
52
53         /* Finish hardware initialization */
54         if (pvr2_hdw_initialize(mp->hdw,
55                                 (void (*)(void *))pvr2_context_notify,mp)) {
56                 mp->video_stream.stream =
57                         pvr2_hdw_get_video_stream(mp->hdw);
58                 /* Trigger interface initialization.  By doing this here
59                    initialization runs in our own safe and cozy thread
60                    context. */
61                 if (mp->setup_func) mp->setup_func(mp);
62         } else {
63                 pvr2_trace(PVR2_TRACE_CTXT,
64                            "pvr2_context %p (thread skipping setup)",mp);
65                 /* Even though initialization did not succeed, we're still
66                    going to enter the wait loop anyway.  We need to do this
67                    in order to await the expected disconnect (which we will
68                    detect in the normal course of operation). */
69         }
70
71         /* Now just issue callbacks whenever hardware state changes or if
72            there is a disconnect.  If there is a disconnect and there are
73            no channels left, then there's no reason to stick around anymore
74            so we'll self-destruct - tearing down the rest of this driver
75            instance along the way. */
76         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread enter loop)",mp);
77         while (!mp->disconnect_flag || mp->mc_first) {
78                 if (mp->notify_flag) {
79                         mp->notify_flag = 0;
80                         pvr2_trace(PVR2_TRACE_CTXT,
81                                    "pvr2_context %p (thread notify)",mp);
82                         for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
83                                 ch2 = ch1->mc_next;
84                                 if (ch1->check_func) ch1->check_func(ch1);
85                         }
86                 }
87                 wait_event_interruptible(mp->wait_data, mp->notify_flag);
88         }
89         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread end)",mp);
90         pvr2_context_destroy(mp);
91         return 0;
92 }
93
94
95 struct pvr2_context *pvr2_context_create(
96         struct usb_interface *intf,
97         const struct usb_device_id *devid,
98         void (*setup_func)(struct pvr2_context *))
99 {
100         struct task_struct *thread;
101         struct pvr2_context *mp = NULL;
102         mp = kzalloc(sizeof(*mp),GFP_KERNEL);
103         if (!mp) goto done;
104         pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
105         init_waitqueue_head(&mp->wait_data);
106         mp->setup_func = setup_func;
107         mutex_init(&mp->mutex);
108         mp->hdw = pvr2_hdw_create(intf,devid);
109         if (!mp->hdw) {
110                 pvr2_context_destroy(mp);
111                 mp = NULL;
112                 goto done;
113         }
114         thread = kthread_run(pvr2_context_thread, mp, "pvrusb2-context");
115         if (!thread) {
116                 pvr2_context_destroy(mp);
117                 mp = NULL;
118                 goto done;
119         }
120  done:
121         return mp;
122 }
123
124
125 static void pvr2_context_enter(struct pvr2_context *mp)
126 {
127         mutex_lock(&mp->mutex);
128 }
129
130
131 static void pvr2_context_exit(struct pvr2_context *mp)
132 {
133         int destroy_flag = 0;
134         if (!(mp->mc_first || !mp->disconnect_flag)) {
135                 destroy_flag = !0;
136         }
137         mutex_unlock(&mp->mutex);
138         if (destroy_flag) pvr2_context_notify(mp);
139 }
140
141
142 void pvr2_context_disconnect(struct pvr2_context *mp)
143 {
144         pvr2_hdw_disconnect(mp->hdw);
145         mp->disconnect_flag = !0;
146         pvr2_context_notify(mp);
147 }
148
149
150 void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
151 {
152         pvr2_context_enter(mp);
153         cp->hdw = mp->hdw;
154         cp->mc_head = mp;
155         cp->mc_next = NULL;
156         cp->mc_prev = mp->mc_last;
157         if (mp->mc_last) {
158                 mp->mc_last->mc_next = cp;
159         } else {
160                 mp->mc_first = cp;
161         }
162         mp->mc_last = cp;
163         pvr2_context_exit(mp);
164 }
165
166
167 static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
168 {
169         if (!cp->stream) return;
170         pvr2_stream_kill(cp->stream->stream);
171         cp->stream->user = NULL;
172         cp->stream = NULL;
173 }
174
175
176 void pvr2_channel_done(struct pvr2_channel *cp)
177 {
178         struct pvr2_context *mp = cp->mc_head;
179         pvr2_context_enter(mp);
180         pvr2_channel_disclaim_stream(cp);
181         if (cp->mc_next) {
182                 cp->mc_next->mc_prev = cp->mc_prev;
183         } else {
184                 mp->mc_last = cp->mc_prev;
185         }
186         if (cp->mc_prev) {
187                 cp->mc_prev->mc_next = cp->mc_next;
188         } else {
189                 mp->mc_first = cp->mc_next;
190         }
191         cp->hdw = NULL;
192         pvr2_context_exit(mp);
193 }
194
195
196 int pvr2_channel_claim_stream(struct pvr2_channel *cp,
197                               struct pvr2_context_stream *sp)
198 {
199         int code = 0;
200         pvr2_context_enter(cp->mc_head); do {
201                 if (sp == cp->stream) break;
202                 if (sp && sp->user) {
203                         code = -EBUSY;
204                         break;
205                 }
206                 pvr2_channel_disclaim_stream(cp);
207                 if (!sp) break;
208                 sp->user = cp;
209                 cp->stream = sp;
210         } while (0); pvr2_context_exit(cp->mc_head);
211         return code;
212 }
213
214
215 // This is the marker for the real beginning of a legitimate mpeg2 stream.
216 static char stream_sync_key[] = {
217         0x00, 0x00, 0x01, 0xba,
218 };
219
220 struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
221         struct pvr2_context_stream *sp)
222 {
223         struct pvr2_ioread *cp;
224         cp = pvr2_ioread_create();
225         if (!cp) return NULL;
226         pvr2_ioread_setup(cp,sp->stream);
227         pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
228         return cp;
229 }
230
231
232 /*
233   Stuff for Emacs to see, in order to encourage consistent editing style:
234   *** Local Variables: ***
235   *** mode: c ***
236   *** fill-column: 75 ***
237   *** tab-width: 8 ***
238   *** c-basic-offset: 8 ***
239   *** End: ***
240   */