0001
0002
0003
0004
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
0085
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
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
0115
0116
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
0123
0124
0125
0126
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
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
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
0357
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
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 }