]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - drivers/media/video/pvrusb2/pvrusb2-context.c
scsi: fix integer as NULL pointer warnings
[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
1cb03b76
MI
248static 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
794b1607 264static void pvr2_context_enter(struct pvr2_context *mp)
d855497e
MI
265{
266 mutex_lock(&mp->mutex);
d855497e
MI
267}
268
269
794b1607 270static void pvr2_context_exit(struct pvr2_context *mp)
d855497e
MI
271{
272 int destroy_flag = 0;
273 if (!(mp->mc_first || !mp->disconnect_flag)) {
274 destroy_flag = !0;
275 }
d855497e 276 mutex_unlock(&mp->mutex);
794b1607 277 if (destroy_flag) pvr2_context_notify(mp);
d855497e
MI
278}
279
280
281void pvr2_context_disconnect(struct pvr2_context *mp)
282{
794b1607
MI
283 pvr2_hdw_disconnect(mp->hdw);
284 mp->disconnect_flag = !0;
285 pvr2_context_notify(mp);
d855497e
MI
286}
287
288
289void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
290{
794b1607 291 pvr2_context_enter(mp);
d855497e
MI
292 cp->hdw = mp->hdw;
293 cp->mc_head = mp;
a0fd1cb1 294 cp->mc_next = NULL;
d855497e
MI
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;
794b1607 302 pvr2_context_exit(mp);
d855497e
MI
303}
304
305
306static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
307{
308 if (!cp->stream) return;
309 pvr2_stream_kill(cp->stream->stream);
a0fd1cb1
MI
310 cp->stream->user = NULL;
311 cp->stream = NULL;
d855497e
MI
312}
313
314
315void pvr2_channel_done(struct pvr2_channel *cp)
316{
317 struct pvr2_context *mp = cp->mc_head;
794b1607 318 pvr2_context_enter(mp);
1cb03b76 319 cp->input_mask = 0;
d855497e 320 pvr2_channel_disclaim_stream(cp);
1cb03b76 321 pvr2_context_reset_input_limits(mp);
d855497e
MI
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 }
a0fd1cb1 332 cp->hdw = NULL;
794b1607 333 pvr2_context_exit(mp);
d855497e
MI
334}
335
336
1cb03b76
MI
337int 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
382unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
383{
384 return cp->input_mask;
385}
386
387
d855497e
MI
388int 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;
99a6acf9 394 if (sp && sp->user) {
d855497e
MI
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.
408static char stream_sync_key[] = {
409 0x00, 0x00, 0x01, 0xba,
410};
411
412struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
413 struct pvr2_context_stream *sp)
414{
415 struct pvr2_ioread *cp;
416 cp = pvr2_ioread_create();
a0fd1cb1 417 if (!cp) return NULL;
d855497e
MI
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 */