root/drivers/media/usb/pvrusb2/pvrusb2-context.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. pvr2_context_set_notify
  2. pvr2_context_destroy
  3. pvr2_context_notify
  4. pvr2_context_check
  5. pvr2_context_shutok
  6. pvr2_context_thread_func
  7. pvr2_context_global_init
  8. pvr2_context_global_done
  9. pvr2_context_create
  10. pvr2_context_reset_input_limits
  11. pvr2_context_enter
  12. pvr2_context_exit
  13. pvr2_context_disconnect
  14. pvr2_channel_init
  15. pvr2_channel_disclaim_stream
  16. pvr2_channel_done
  17. pvr2_channel_limit_inputs
  18. pvr2_channel_get_limited_inputs
  19. pvr2_channel_claim_stream
  20. pvr2_channel_create_mpeg_stream

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

/* [<][>][^][v][top][bottom][index][help] */