]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/media/video/pvrusb2/pvrusb2-context.c
V4L/DVB (7718): pvrusb2-dvb: update Kbuild selections
[mirror_ubuntu-artful-kernel.git] / drivers / media / video / pvrusb2 / pvrusb2-context.c
CommitLineData
d855497e
MI
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"
e5be15c6 26#include <linux/wait.h>
794b1607 27#include <linux/kthread.h>
d855497e
MI
28#include <linux/errno.h>
29#include <linux/string.h>
30#include <linux/slab.h>
d855497e 31
e5be15c6
MI
32static struct pvr2_context *pvr2_context_exist_first;
33static struct pvr2_context *pvr2_context_exist_last;
34static struct pvr2_context *pvr2_context_notify_first;
35static struct pvr2_context *pvr2_context_notify_last;
36static DEFINE_MUTEX(pvr2_context_mutex);
37static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
18ecbb47
MI
38static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
39static int pvr2_context_cleanup_flag;
40static int pvr2_context_cleaned_flag;
e5be15c6
MI
41static struct task_struct *pvr2_context_thread_ptr;
42
43
44static 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
d855497e
MI
80
81static void pvr2_context_destroy(struct pvr2_context *mp)
82{
794b1607 83 pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
681c7399 84 if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
e5be15c6
MI
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);
d855497e
MI
103 kfree(mp);
104}
105
106
794b1607 107static void pvr2_context_notify(struct pvr2_context *mp)
d855497e 108{
e5be15c6 109 pvr2_context_set_notify(mp,!0);
794b1607
MI
110}
111
112
e5be15c6 113static void pvr2_context_check(struct pvr2_context *mp)
794b1607 114{
e5be15c6
MI
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;
794b1607 120 pvr2_trace(PVR2_TRACE_CTXT,
e5be15c6
MI
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 {
794b1607 133 pvr2_trace(PVR2_TRACE_CTXT,
e5be15c6
MI
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). */
d855497e 141 }
794b1607 142 }
e5be15c6
MI
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
157static int pvr2_context_shutok(void)
158{
18ecbb47 159 return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
e5be15c6
MI
160}
161
162
163static 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
18ecbb47
MI
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
e5be15c6
MI
189 pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
190
794b1607
MI
191 return 0;
192}
d855497e
MI
193
194
e5be15c6
MI
195int 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
204void pvr2_context_global_done(void)
205{
18ecbb47
MI
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);
e5be15c6
MI
211 kthread_stop(pvr2_context_thread_ptr);
212}
213
214
d855497e
MI
215struct 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{
a0fd1cb1 220 struct pvr2_context *mp = NULL;
ca545f7c 221 mp = kzalloc(sizeof(*mp),GFP_KERNEL);
d855497e 222 if (!mp) goto done;
794b1607 223 pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
d855497e
MI
224 mp->setup_func = setup_func;
225 mutex_init(&mp->mutex);
e5be15c6
MI
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);
d855497e
MI
236 mp->hdw = pvr2_hdw_create(intf,devid);
237 if (!mp->hdw) {
238 pvr2_context_destroy(mp);
a0fd1cb1 239 mp = NULL;
d855497e
MI
240 goto done;
241 }
e5be15c6 242 pvr2_context_set_notify(mp, !0);
d855497e
MI
243 done:
244 return mp;
245}
246
247
794b1607 248static void pvr2_context_enter(struct pvr2_context *mp)
d855497e
MI
249{
250 mutex_lock(&mp->mutex);
d855497e
MI
251}
252
253
794b1607 254static void pvr2_context_exit(struct pvr2_context *mp)
d855497e
MI
255{
256 int destroy_flag = 0;
257 if (!(mp->mc_first || !mp->disconnect_flag)) {
258 destroy_flag = !0;
259 }
d855497e 260 mutex_unlock(&mp->mutex);
794b1607 261 if (destroy_flag) pvr2_context_notify(mp);
d855497e
MI
262}
263
264
265void pvr2_context_disconnect(struct pvr2_context *mp)
266{
794b1607
MI
267 pvr2_hdw_disconnect(mp->hdw);
268 mp->disconnect_flag = !0;
269 pvr2_context_notify(mp);
d855497e
MI
270}
271
272
273void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
274{
794b1607 275 pvr2_context_enter(mp);
d855497e
MI
276 cp->hdw = mp->hdw;
277 cp->mc_head = mp;
a0fd1cb1 278 cp->mc_next = NULL;
d855497e
MI
279 cp->mc_prev = mp->mc_last;
280 if (mp->mc_last) {
281 mp->mc_last->mc_next = cp;
282 } else {
283 mp->mc_first = cp;
284 }
285 mp->mc_last = cp;
794b1607 286 pvr2_context_exit(mp);
d855497e
MI
287}
288
289
290static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
291{
292 if (!cp->stream) return;
293 pvr2_stream_kill(cp->stream->stream);
a0fd1cb1
MI
294 cp->stream->user = NULL;
295 cp->stream = NULL;
d855497e
MI
296}
297
298
299void pvr2_channel_done(struct pvr2_channel *cp)
300{
301 struct pvr2_context *mp = cp->mc_head;
794b1607 302 pvr2_context_enter(mp);
d855497e
MI
303 pvr2_channel_disclaim_stream(cp);
304 if (cp->mc_next) {
305 cp->mc_next->mc_prev = cp->mc_prev;
306 } else {
307 mp->mc_last = cp->mc_prev;
308 }
309 if (cp->mc_prev) {
310 cp->mc_prev->mc_next = cp->mc_next;
311 } else {
312 mp->mc_first = cp->mc_next;
313 }
a0fd1cb1 314 cp->hdw = NULL;
794b1607 315 pvr2_context_exit(mp);
d855497e
MI
316}
317
318
319int pvr2_channel_claim_stream(struct pvr2_channel *cp,
320 struct pvr2_context_stream *sp)
321{
322 int code = 0;
323 pvr2_context_enter(cp->mc_head); do {
324 if (sp == cp->stream) break;
99a6acf9 325 if (sp && sp->user) {
d855497e
MI
326 code = -EBUSY;
327 break;
328 }
329 pvr2_channel_disclaim_stream(cp);
330 if (!sp) break;
331 sp->user = cp;
332 cp->stream = sp;
333 } while (0); pvr2_context_exit(cp->mc_head);
334 return code;
335}
336
337
338// This is the marker for the real beginning of a legitimate mpeg2 stream.
339static char stream_sync_key[] = {
340 0x00, 0x00, 0x01, 0xba,
341};
342
343struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
344 struct pvr2_context_stream *sp)
345{
346 struct pvr2_ioread *cp;
347 cp = pvr2_ioread_create();
a0fd1cb1 348 if (!cp) return NULL;
d855497e
MI
349 pvr2_ioread_setup(cp,sp->stream);
350 pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
351 return cp;
352}
353
354
355/*
356 Stuff for Emacs to see, in order to encourage consistent editing style:
357 *** Local Variables: ***
358 *** mode: c ***
359 *** fill-column: 75 ***
360 *** tab-width: 8 ***
361 *** c-basic-offset: 8 ***
362 *** End: ***
363 */