Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  *
0004  *  Copyright (C) 2005 Mike Isely <isely@pobox.com>
0005  */
0006 
0007 #include "pvrusb2-context.h"
0008 #include "pvrusb2-io.h"
0009 #include "pvrusb2-ioread.h"
0010 #include "pvrusb2-hdw.h"
0011 #include "pvrusb2-debug.h"
0012 #include <linux/wait.h>
0013 #include <linux/kthread.h>
0014 #include <linux/errno.h>
0015 #include <linux/string.h>
0016 #include <linux/slab.h>
0017 
0018 static struct pvr2_context *pvr2_context_exist_first;
0019 static struct pvr2_context *pvr2_context_exist_last;
0020 static struct pvr2_context *pvr2_context_notify_first;
0021 static struct pvr2_context *pvr2_context_notify_last;
0022 static DEFINE_MUTEX(pvr2_context_mutex);
0023 static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
0024 static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
0025 static int pvr2_context_cleanup_flag;
0026 static int pvr2_context_cleaned_flag;
0027 static struct task_struct *pvr2_context_thread_ptr;
0028 
0029 
0030 static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
0031 {
0032     int signal_flag = 0;
0033     mutex_lock(&pvr2_context_mutex);
0034     if (fl) {
0035         if (!mp->notify_flag) {
0036             signal_flag = (pvr2_context_notify_first == NULL);
0037             mp->notify_prev = pvr2_context_notify_last;
0038             mp->notify_next = NULL;
0039             pvr2_context_notify_last = mp;
0040             if (mp->notify_prev) {
0041                 mp->notify_prev->notify_next = mp;
0042             } else {
0043                 pvr2_context_notify_first = mp;
0044             }
0045             mp->notify_flag = !0;
0046         }
0047     } else {
0048         if (mp->notify_flag) {
0049             mp->notify_flag = 0;
0050             if (mp->notify_next) {
0051                 mp->notify_next->notify_prev = mp->notify_prev;
0052             } else {
0053                 pvr2_context_notify_last = mp->notify_prev;
0054             }
0055             if (mp->notify_prev) {
0056                 mp->notify_prev->notify_next = mp->notify_next;
0057             } else {
0058                 pvr2_context_notify_first = mp->notify_next;
0059             }
0060         }
0061     }
0062     mutex_unlock(&pvr2_context_mutex);
0063     if (signal_flag) wake_up(&pvr2_context_sync_data);
0064 }
0065 
0066 
0067 static void pvr2_context_destroy(struct pvr2_context *mp)
0068 {
0069     pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
0070     pvr2_hdw_destroy(mp->hdw);
0071     pvr2_context_set_notify(mp, 0);
0072     mutex_lock(&pvr2_context_mutex);
0073     if (mp->exist_next) {
0074         mp->exist_next->exist_prev = mp->exist_prev;
0075     } else {
0076         pvr2_context_exist_last = mp->exist_prev;
0077     }
0078     if (mp->exist_prev) {
0079         mp->exist_prev->exist_next = mp->exist_next;
0080     } else {
0081         pvr2_context_exist_first = mp->exist_next;
0082     }
0083     if (!pvr2_context_exist_first) {
0084         /* Trigger wakeup on control thread in case it is waiting
0085            for an exit condition. */
0086         wake_up(&pvr2_context_sync_data);
0087     }
0088     mutex_unlock(&pvr2_context_mutex);
0089     kfree(mp);
0090 }
0091 
0092 
0093 static void pvr2_context_notify(struct pvr2_context *mp)
0094 {
0095     pvr2_context_set_notify(mp,!0);
0096 }
0097 
0098 
0099 static void pvr2_context_check(struct pvr2_context *mp)
0100 {
0101     struct pvr2_channel *ch1, *ch2;
0102     pvr2_trace(PVR2_TRACE_CTXT,
0103            "pvr2_context %p (notify)", mp);
0104     if (!mp->initialized_flag && !mp->disconnect_flag) {
0105         mp->initialized_flag = !0;
0106         pvr2_trace(PVR2_TRACE_CTXT,
0107                "pvr2_context %p (initialize)", mp);
0108         /* Finish hardware initialization */
0109         if (pvr2_hdw_initialize(mp->hdw,
0110                     (void (*)(void *))pvr2_context_notify,
0111                     mp)) {
0112             mp->video_stream.stream =
0113                 pvr2_hdw_get_video_stream(mp->hdw);
0114             /* Trigger interface initialization.  By doing this
0115                here initialization runs in our own safe and
0116                cozy thread context. */
0117             if (mp->setup_func) mp->setup_func(mp);
0118         } else {
0119             pvr2_trace(PVR2_TRACE_CTXT,
0120                    "pvr2_context %p (thread skipping setup)",
0121                    mp);
0122             /* Even though initialization did not succeed,
0123                we're still going to continue anyway.  We need
0124                to do this in order to await the expected
0125                disconnect (which we will detect in the normal
0126                course of operation). */
0127         }
0128     }
0129 
0130     for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
0131         ch2 = ch1->mc_next;
0132         if (ch1->check_func) ch1->check_func(ch1);
0133     }
0134 
0135     if (mp->disconnect_flag && !mp->mc_first) {
0136         /* Go away... */
0137         pvr2_context_destroy(mp);
0138         return;
0139     }
0140 }
0141 
0142 
0143 static int pvr2_context_shutok(void)
0144 {
0145     return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
0146 }
0147 
0148 
0149 static int pvr2_context_thread_func(void *foo)
0150 {
0151     struct pvr2_context *mp;
0152 
0153     pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");
0154 
0155     do {
0156         while ((mp = pvr2_context_notify_first) != NULL) {
0157             pvr2_context_set_notify(mp, 0);
0158             pvr2_context_check(mp);
0159         }
0160         wait_event_interruptible(
0161             pvr2_context_sync_data,
0162             ((pvr2_context_notify_first != NULL) ||
0163              pvr2_context_shutok()));
0164     } while (!pvr2_context_shutok());
0165 
0166     pvr2_context_cleaned_flag = !0;
0167     wake_up(&pvr2_context_cleanup_data);
0168 
0169     pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");
0170 
0171     wait_event_interruptible(
0172         pvr2_context_sync_data,
0173         kthread_should_stop());
0174 
0175     pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
0176 
0177     return 0;
0178 }
0179 
0180 
0181 int pvr2_context_global_init(void)
0182 {
0183     pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
0184                           NULL,
0185                           "pvrusb2-context");
0186     return IS_ERR(pvr2_context_thread_ptr) ? -ENOMEM : 0;
0187 }
0188 
0189 
0190 void pvr2_context_global_done(void)
0191 {
0192     pvr2_context_cleanup_flag = !0;
0193     wake_up(&pvr2_context_sync_data);
0194     wait_event_interruptible(
0195         pvr2_context_cleanup_data,
0196         pvr2_context_cleaned_flag);
0197     kthread_stop(pvr2_context_thread_ptr);
0198 }
0199 
0200 
0201 struct pvr2_context *pvr2_context_create(
0202     struct usb_interface *intf,
0203     const struct usb_device_id *devid,
0204     void (*setup_func)(struct pvr2_context *))
0205 {
0206     struct pvr2_context *mp = NULL;
0207     mp = kzalloc(sizeof(*mp),GFP_KERNEL);
0208     if (!mp) goto done;
0209     pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
0210     mp->setup_func = setup_func;
0211     mutex_init(&mp->mutex);
0212     mutex_lock(&pvr2_context_mutex);
0213     mp->exist_prev = pvr2_context_exist_last;
0214     mp->exist_next = NULL;
0215     pvr2_context_exist_last = mp;
0216     if (mp->exist_prev) {
0217         mp->exist_prev->exist_next = mp;
0218     } else {
0219         pvr2_context_exist_first = mp;
0220     }
0221     mutex_unlock(&pvr2_context_mutex);
0222     mp->hdw = pvr2_hdw_create(intf,devid);
0223     if (!mp->hdw) {
0224         pvr2_context_destroy(mp);
0225         mp = NULL;
0226         goto done;
0227     }
0228     pvr2_context_set_notify(mp, !0);
0229  done:
0230     return mp;
0231 }
0232 
0233 
0234 static void pvr2_context_reset_input_limits(struct pvr2_context *mp)
0235 {
0236     unsigned int tmsk,mmsk;
0237     struct pvr2_channel *cp;
0238     struct pvr2_hdw *hdw = mp->hdw;
0239     mmsk = pvr2_hdw_get_input_available(hdw);
0240     tmsk = mmsk;
0241     for (cp = mp->mc_first; cp; cp = cp->mc_next) {
0242         if (!cp->input_mask) continue;
0243         tmsk &= cp->input_mask;
0244     }
0245     pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
0246     pvr2_hdw_commit_ctl(hdw);
0247 }
0248 
0249 
0250 static void pvr2_context_enter(struct pvr2_context *mp)
0251 {
0252     mutex_lock(&mp->mutex);
0253 }
0254 
0255 
0256 static void pvr2_context_exit(struct pvr2_context *mp)
0257 {
0258     int destroy_flag = 0;
0259     if (!(mp->mc_first || !mp->disconnect_flag)) {
0260         destroy_flag = !0;
0261     }
0262     mutex_unlock(&mp->mutex);
0263     if (destroy_flag) pvr2_context_notify(mp);
0264 }
0265 
0266 
0267 void pvr2_context_disconnect(struct pvr2_context *mp)
0268 {
0269     pvr2_hdw_disconnect(mp->hdw);
0270     mp->disconnect_flag = !0;
0271     pvr2_context_notify(mp);
0272 }
0273 
0274 
0275 void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
0276 {
0277     pvr2_context_enter(mp);
0278     cp->hdw = mp->hdw;
0279     cp->mc_head = mp;
0280     cp->mc_next = NULL;
0281     cp->mc_prev = mp->mc_last;
0282     if (mp->mc_last) {
0283         mp->mc_last->mc_next = cp;
0284     } else {
0285         mp->mc_first = cp;
0286     }
0287     mp->mc_last = cp;
0288     pvr2_context_exit(mp);
0289 }
0290 
0291 
0292 static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
0293 {
0294     if (!cp->stream) return;
0295     pvr2_stream_kill(cp->stream->stream);
0296     cp->stream->user = NULL;
0297     cp->stream = NULL;
0298 }
0299 
0300 
0301 void pvr2_channel_done(struct pvr2_channel *cp)
0302 {
0303     struct pvr2_context *mp = cp->mc_head;
0304     pvr2_context_enter(mp);
0305     cp->input_mask = 0;
0306     pvr2_channel_disclaim_stream(cp);
0307     pvr2_context_reset_input_limits(mp);
0308     if (cp->mc_next) {
0309         cp->mc_next->mc_prev = cp->mc_prev;
0310     } else {
0311         mp->mc_last = cp->mc_prev;
0312     }
0313     if (cp->mc_prev) {
0314         cp->mc_prev->mc_next = cp->mc_next;
0315     } else {
0316         mp->mc_first = cp->mc_next;
0317     }
0318     cp->hdw = NULL;
0319     pvr2_context_exit(mp);
0320 }
0321 
0322 
0323 int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
0324 {
0325     unsigned int tmsk,mmsk;
0326     int ret = 0;
0327     struct pvr2_channel *p2;
0328     struct pvr2_hdw *hdw = cp->hdw;
0329 
0330     mmsk = pvr2_hdw_get_input_available(hdw);
0331     cmsk &= mmsk;
0332     if (cmsk == cp->input_mask) {
0333         /* No change; nothing to do */
0334         return 0;
0335     }
0336 
0337     pvr2_context_enter(cp->mc_head);
0338     do {
0339         if (!cmsk) {
0340             cp->input_mask = 0;
0341             pvr2_context_reset_input_limits(cp->mc_head);
0342             break;
0343         }
0344         tmsk = mmsk;
0345         for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
0346             if (p2 == cp) continue;
0347             if (!p2->input_mask) continue;
0348             tmsk &= p2->input_mask;
0349         }
0350         if (!(tmsk & cmsk)) {
0351             ret = -EPERM;
0352             break;
0353         }
0354         tmsk &= cmsk;
0355         if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
0356             /* Internal failure changing allowed list; probably
0357                should not happen, but react if it does. */
0358             break;
0359         }
0360         cp->input_mask = cmsk;
0361         pvr2_hdw_commit_ctl(hdw);
0362     } while (0);
0363     pvr2_context_exit(cp->mc_head);
0364     return ret;
0365 }
0366 
0367 
0368 unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
0369 {
0370     return cp->input_mask;
0371 }
0372 
0373 
0374 int pvr2_channel_claim_stream(struct pvr2_channel *cp,
0375                   struct pvr2_context_stream *sp)
0376 {
0377     int code = 0;
0378     pvr2_context_enter(cp->mc_head); do {
0379         if (sp == cp->stream) break;
0380         if (sp && sp->user) {
0381             code = -EBUSY;
0382             break;
0383         }
0384         pvr2_channel_disclaim_stream(cp);
0385         if (!sp) break;
0386         sp->user = cp;
0387         cp->stream = sp;
0388     } while (0);
0389     pvr2_context_exit(cp->mc_head);
0390     return code;
0391 }
0392 
0393 
0394 // This is the marker for the real beginning of a legitimate mpeg2 stream.
0395 static char stream_sync_key[] = {
0396     0x00, 0x00, 0x01, 0xba,
0397 };
0398 
0399 struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
0400     struct pvr2_context_stream *sp)
0401 {
0402     struct pvr2_ioread *cp;
0403     cp = pvr2_ioread_create();
0404     if (!cp) return NULL;
0405     pvr2_ioread_setup(cp,sp->stream);
0406     pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
0407     return cp;
0408 }