Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pvrusb2-context.c
Go to the documentation of this file.
1 /*
2  *
3  * Copyright (C) 2005 Mike Isely <[email protected]>
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;
116  "pvr2_context %p (notify)", mp);
117  if (!mp->initialized_flag && !mp->disconnect_flag) {
118  mp->initialized_flag = !0;
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 =
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 {
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  }
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 
185  pvr2_context_sync_data,
187 
188  pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
189 
190  return 0;
191 }
192 
193 
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 
204 {
205  pvr2_context_cleanup_flag = !0;
206  wake_up(&pvr2_context_sync_data);
208  pvr2_context_cleanup_data,
209  pvr2_context_cleaned_flag);
210  kthread_stop(pvr2_context_thread_ptr);
211 }
212 
213 
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 
281 {
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 
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 
382 {
383  return cp->input_mask;
384 }
385 
386 
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 
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  */