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