1d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely/* 2d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * 3d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * Copyright (C) 2005 Mike Isely <isely@pobox.com> 4d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * 5d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * This program is free software; you can redistribute it and/or modify 6d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * it under the terms of the GNU General Public License as published by 7d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * the Free Software Foundation; either version 2 of the License 8d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * 9d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * This program is distributed in the hope that it will be useful, 10d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * but WITHOUT ANY WARRANTY; without even the implied warranty of 11d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * GNU General Public License for more details. 13d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * 14d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * You should have received a copy of the GNU General Public License 15d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * along with this program; if not, write to the Free Software 16d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 17d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely * 18d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely */ 19d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 20d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include "pvrusb2-context.h" 21d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include "pvrusb2-io.h" 22d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include "pvrusb2-ioread.h" 23d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include "pvrusb2-hdw.h" 24d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include "pvrusb2-debug.h" 25e5be15c63804e05b5a94197524023702a259e308Mike Isely#include <linux/wait.h> 26794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely#include <linux/kthread.h> 27d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include <linux/errno.h> 28d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include <linux/string.h> 29d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely#include <linux/slab.h> 30d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 31e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic struct pvr2_context *pvr2_context_exist_first; 32e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic struct pvr2_context *pvr2_context_exist_last; 33e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic struct pvr2_context *pvr2_context_notify_first; 34e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic struct pvr2_context *pvr2_context_notify_last; 35e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic DEFINE_MUTEX(pvr2_context_mutex); 36e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data); 3718ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Iselystatic DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data); 3818ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Iselystatic int pvr2_context_cleanup_flag; 3918ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Iselystatic int pvr2_context_cleaned_flag; 40e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic struct task_struct *pvr2_context_thread_ptr; 41e5be15c63804e05b5a94197524023702a259e308Mike Isely 42e5be15c63804e05b5a94197524023702a259e308Mike Isely 43e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic void pvr2_context_set_notify(struct pvr2_context *mp, int fl) 44e5be15c63804e05b5a94197524023702a259e308Mike Isely{ 45e5be15c63804e05b5a94197524023702a259e308Mike Isely int signal_flag = 0; 46e5be15c63804e05b5a94197524023702a259e308Mike Isely mutex_lock(&pvr2_context_mutex); 47e5be15c63804e05b5a94197524023702a259e308Mike Isely if (fl) { 48e5be15c63804e05b5a94197524023702a259e308Mike Isely if (!mp->notify_flag) { 49e5be15c63804e05b5a94197524023702a259e308Mike Isely signal_flag = (pvr2_context_notify_first == NULL); 50e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->notify_prev = pvr2_context_notify_last; 51e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->notify_next = NULL; 52e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_notify_last = mp; 53e5be15c63804e05b5a94197524023702a259e308Mike Isely if (mp->notify_prev) { 54e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->notify_prev->notify_next = mp; 55e5be15c63804e05b5a94197524023702a259e308Mike Isely } else { 56e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_notify_first = mp; 57e5be15c63804e05b5a94197524023702a259e308Mike Isely } 58e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->notify_flag = !0; 59e5be15c63804e05b5a94197524023702a259e308Mike Isely } 60e5be15c63804e05b5a94197524023702a259e308Mike Isely } else { 61e5be15c63804e05b5a94197524023702a259e308Mike Isely if (mp->notify_flag) { 62e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->notify_flag = 0; 63e5be15c63804e05b5a94197524023702a259e308Mike Isely if (mp->notify_next) { 64e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->notify_next->notify_prev = mp->notify_prev; 65e5be15c63804e05b5a94197524023702a259e308Mike Isely } else { 66e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_notify_last = mp->notify_prev; 67e5be15c63804e05b5a94197524023702a259e308Mike Isely } 68e5be15c63804e05b5a94197524023702a259e308Mike Isely if (mp->notify_prev) { 69e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->notify_prev->notify_next = mp->notify_next; 70e5be15c63804e05b5a94197524023702a259e308Mike Isely } else { 71e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_notify_first = mp->notify_next; 72e5be15c63804e05b5a94197524023702a259e308Mike Isely } 73e5be15c63804e05b5a94197524023702a259e308Mike Isely } 74e5be15c63804e05b5a94197524023702a259e308Mike Isely } 75e5be15c63804e05b5a94197524023702a259e308Mike Isely mutex_unlock(&pvr2_context_mutex); 76e5be15c63804e05b5a94197524023702a259e308Mike Isely if (signal_flag) wake_up(&pvr2_context_sync_data); 77e5be15c63804e05b5a94197524023702a259e308Mike Isely} 78e5be15c63804e05b5a94197524023702a259e308Mike Isely 79d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 80d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselystatic void pvr2_context_destroy(struct pvr2_context *mp) 81d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{ 82794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp); 83681c739944018d80dbcf7f19997eba97676c7116Mike Isely if (mp->hdw) pvr2_hdw_destroy(mp->hdw); 84e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_set_notify(mp, 0); 85e5be15c63804e05b5a94197524023702a259e308Mike Isely mutex_lock(&pvr2_context_mutex); 86e5be15c63804e05b5a94197524023702a259e308Mike Isely if (mp->exist_next) { 87e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->exist_next->exist_prev = mp->exist_prev; 88e5be15c63804e05b5a94197524023702a259e308Mike Isely } else { 89e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_exist_last = mp->exist_prev; 90e5be15c63804e05b5a94197524023702a259e308Mike Isely } 91e5be15c63804e05b5a94197524023702a259e308Mike Isely if (mp->exist_prev) { 92e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->exist_prev->exist_next = mp->exist_next; 93e5be15c63804e05b5a94197524023702a259e308Mike Isely } else { 94e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_exist_first = mp->exist_next; 95e5be15c63804e05b5a94197524023702a259e308Mike Isely } 96e5be15c63804e05b5a94197524023702a259e308Mike Isely if (!pvr2_context_exist_first) { 97e5be15c63804e05b5a94197524023702a259e308Mike Isely /* Trigger wakeup on control thread in case it is waiting 98e5be15c63804e05b5a94197524023702a259e308Mike Isely for an exit condition. */ 99e5be15c63804e05b5a94197524023702a259e308Mike Isely wake_up(&pvr2_context_sync_data); 100e5be15c63804e05b5a94197524023702a259e308Mike Isely } 101e5be15c63804e05b5a94197524023702a259e308Mike Isely mutex_unlock(&pvr2_context_mutex); 102d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely kfree(mp); 103d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely} 104d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 105d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 106794b16072e00d0a40a8c773dd4319fb1e460a632Mike Iselystatic void pvr2_context_notify(struct pvr2_context *mp) 107d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{ 108e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_set_notify(mp,!0); 109794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely} 110794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely 111794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely 112e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic void pvr2_context_check(struct pvr2_context *mp) 113794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely{ 114e5be15c63804e05b5a94197524023702a259e308Mike Isely struct pvr2_channel *ch1, *ch2; 115e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_trace(PVR2_TRACE_CTXT, 116e5be15c63804e05b5a94197524023702a259e308Mike Isely "pvr2_context %p (notify)", mp); 117e5be15c63804e05b5a94197524023702a259e308Mike Isely if (!mp->initialized_flag && !mp->disconnect_flag) { 118e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->initialized_flag = !0; 119794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely pvr2_trace(PVR2_TRACE_CTXT, 120e5be15c63804e05b5a94197524023702a259e308Mike Isely "pvr2_context %p (initialize)", mp); 121e5be15c63804e05b5a94197524023702a259e308Mike Isely /* Finish hardware initialization */ 122e5be15c63804e05b5a94197524023702a259e308Mike Isely if (pvr2_hdw_initialize(mp->hdw, 123e5be15c63804e05b5a94197524023702a259e308Mike Isely (void (*)(void *))pvr2_context_notify, 124e5be15c63804e05b5a94197524023702a259e308Mike Isely mp)) { 125e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->video_stream.stream = 126e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_hdw_get_video_stream(mp->hdw); 127e5be15c63804e05b5a94197524023702a259e308Mike Isely /* Trigger interface initialization. By doing this 128e5be15c63804e05b5a94197524023702a259e308Mike Isely here initialization runs in our own safe and 129e5be15c63804e05b5a94197524023702a259e308Mike Isely cozy thread context. */ 130e5be15c63804e05b5a94197524023702a259e308Mike Isely if (mp->setup_func) mp->setup_func(mp); 131e5be15c63804e05b5a94197524023702a259e308Mike Isely } else { 132794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely pvr2_trace(PVR2_TRACE_CTXT, 133e5be15c63804e05b5a94197524023702a259e308Mike Isely "pvr2_context %p (thread skipping setup)", 134e5be15c63804e05b5a94197524023702a259e308Mike Isely mp); 135e5be15c63804e05b5a94197524023702a259e308Mike Isely /* Even though initialization did not succeed, 136e5be15c63804e05b5a94197524023702a259e308Mike Isely we're still going to continue anyway. We need 137e5be15c63804e05b5a94197524023702a259e308Mike Isely to do this in order to await the expected 138e5be15c63804e05b5a94197524023702a259e308Mike Isely disconnect (which we will detect in the normal 139e5be15c63804e05b5a94197524023702a259e308Mike Isely course of operation). */ 140d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely } 141794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely } 142e5be15c63804e05b5a94197524023702a259e308Mike Isely 143e5be15c63804e05b5a94197524023702a259e308Mike Isely for (ch1 = mp->mc_first; ch1; ch1 = ch2) { 144e5be15c63804e05b5a94197524023702a259e308Mike Isely ch2 = ch1->mc_next; 145e5be15c63804e05b5a94197524023702a259e308Mike Isely if (ch1->check_func) ch1->check_func(ch1); 146e5be15c63804e05b5a94197524023702a259e308Mike Isely } 147e5be15c63804e05b5a94197524023702a259e308Mike Isely 148e5be15c63804e05b5a94197524023702a259e308Mike Isely if (mp->disconnect_flag && !mp->mc_first) { 149e5be15c63804e05b5a94197524023702a259e308Mike Isely /* Go away... */ 150e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_destroy(mp); 151e5be15c63804e05b5a94197524023702a259e308Mike Isely return; 152e5be15c63804e05b5a94197524023702a259e308Mike Isely } 153e5be15c63804e05b5a94197524023702a259e308Mike Isely} 154e5be15c63804e05b5a94197524023702a259e308Mike Isely 155e5be15c63804e05b5a94197524023702a259e308Mike Isely 156e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic int pvr2_context_shutok(void) 157e5be15c63804e05b5a94197524023702a259e308Mike Isely{ 15818ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL); 159e5be15c63804e05b5a94197524023702a259e308Mike Isely} 160e5be15c63804e05b5a94197524023702a259e308Mike Isely 161e5be15c63804e05b5a94197524023702a259e308Mike Isely 162e5be15c63804e05b5a94197524023702a259e308Mike Iselystatic int pvr2_context_thread_func(void *foo) 163e5be15c63804e05b5a94197524023702a259e308Mike Isely{ 164e5be15c63804e05b5a94197524023702a259e308Mike Isely struct pvr2_context *mp; 165e5be15c63804e05b5a94197524023702a259e308Mike Isely 166e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start"); 167e5be15c63804e05b5a94197524023702a259e308Mike Isely 168e5be15c63804e05b5a94197524023702a259e308Mike Isely do { 169e5be15c63804e05b5a94197524023702a259e308Mike Isely while ((mp = pvr2_context_notify_first) != NULL) { 170e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_set_notify(mp, 0); 171e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_check(mp); 172e5be15c63804e05b5a94197524023702a259e308Mike Isely } 173e5be15c63804e05b5a94197524023702a259e308Mike Isely wait_event_interruptible( 174e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_sync_data, 175e5be15c63804e05b5a94197524023702a259e308Mike Isely ((pvr2_context_notify_first != NULL) || 176e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_shutok())); 177e5be15c63804e05b5a94197524023702a259e308Mike Isely } while (!pvr2_context_shutok()); 178e5be15c63804e05b5a94197524023702a259e308Mike Isely 17918ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely pvr2_context_cleaned_flag = !0; 18018ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely wake_up(&pvr2_context_cleanup_data); 18118ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely 18218ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up"); 18318ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely 18418ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely wait_event_interruptible( 18518ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely pvr2_context_sync_data, 18618ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely kthread_should_stop()); 18718ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely 188e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end"); 189e5be15c63804e05b5a94197524023702a259e308Mike Isely 190794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely return 0; 191794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely} 192d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 193d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 194e5be15c63804e05b5a94197524023702a259e308Mike Iselyint pvr2_context_global_init(void) 195e5be15c63804e05b5a94197524023702a259e308Mike Isely{ 196e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func, 197a6a3a17b7fdaf824e6d73e8e4a94c9d149302f74Harvey Harrison NULL, 198e5be15c63804e05b5a94197524023702a259e308Mike Isely "pvrusb2-context"); 199e5be15c63804e05b5a94197524023702a259e308Mike Isely return (pvr2_context_thread_ptr ? 0 : -ENOMEM); 200e5be15c63804e05b5a94197524023702a259e308Mike Isely} 201e5be15c63804e05b5a94197524023702a259e308Mike Isely 202e5be15c63804e05b5a94197524023702a259e308Mike Isely 203e5be15c63804e05b5a94197524023702a259e308Mike Iselyvoid pvr2_context_global_done(void) 204e5be15c63804e05b5a94197524023702a259e308Mike Isely{ 20518ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely pvr2_context_cleanup_flag = !0; 20618ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely wake_up(&pvr2_context_sync_data); 20718ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely wait_event_interruptible( 20818ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely pvr2_context_cleanup_data, 20918ecbb4771eb0ecf297e996966b3c42f69cd6c02Mike Isely pvr2_context_cleaned_flag); 210e5be15c63804e05b5a94197524023702a259e308Mike Isely kthread_stop(pvr2_context_thread_ptr); 211e5be15c63804e05b5a94197524023702a259e308Mike Isely} 212e5be15c63804e05b5a94197524023702a259e308Mike Isely 213e5be15c63804e05b5a94197524023702a259e308Mike Isely 214d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselystruct pvr2_context *pvr2_context_create( 215d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely struct usb_interface *intf, 216d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely const struct usb_device_id *devid, 217d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely void (*setup_func)(struct pvr2_context *)) 218d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{ 219a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely struct pvr2_context *mp = NULL; 220ca545f7c39476c6c4c6e639452180a2b38342669Mike Isely mp = kzalloc(sizeof(*mp),GFP_KERNEL); 221d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely if (!mp) goto done; 222794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp); 223d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely mp->setup_func = setup_func; 224d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely mutex_init(&mp->mutex); 225e5be15c63804e05b5a94197524023702a259e308Mike Isely mutex_lock(&pvr2_context_mutex); 226e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->exist_prev = pvr2_context_exist_last; 227e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->exist_next = NULL; 228e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_exist_last = mp; 229e5be15c63804e05b5a94197524023702a259e308Mike Isely if (mp->exist_prev) { 230e5be15c63804e05b5a94197524023702a259e308Mike Isely mp->exist_prev->exist_next = mp; 231e5be15c63804e05b5a94197524023702a259e308Mike Isely } else { 232e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_exist_first = mp; 233e5be15c63804e05b5a94197524023702a259e308Mike Isely } 234e5be15c63804e05b5a94197524023702a259e308Mike Isely mutex_unlock(&pvr2_context_mutex); 235d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely mp->hdw = pvr2_hdw_create(intf,devid); 236d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely if (!mp->hdw) { 237d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely pvr2_context_destroy(mp); 238a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely mp = NULL; 239d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely goto done; 240d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely } 241e5be15c63804e05b5a94197524023702a259e308Mike Isely pvr2_context_set_notify(mp, !0); 242d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely done: 243d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely return mp; 244d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely} 245d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 246d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 2471cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Iselystatic void pvr2_context_reset_input_limits(struct pvr2_context *mp) 2481cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely{ 2491cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely unsigned int tmsk,mmsk; 2501cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely struct pvr2_channel *cp; 2511cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely struct pvr2_hdw *hdw = mp->hdw; 2521cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely mmsk = pvr2_hdw_get_input_available(hdw); 2531cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely tmsk = mmsk; 2541cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely for (cp = mp->mc_first; cp; cp = cp->mc_next) { 2551cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely if (!cp->input_mask) continue; 2561cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely tmsk &= cp->input_mask; 2571cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely } 2581cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk); 2591cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely pvr2_hdw_commit_ctl(hdw); 2601cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely} 2611cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely 2621cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely 263794b16072e00d0a40a8c773dd4319fb1e460a632Mike Iselystatic void pvr2_context_enter(struct pvr2_context *mp) 264d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{ 265d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely mutex_lock(&mp->mutex); 266d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely} 267d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 268d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 269794b16072e00d0a40a8c773dd4319fb1e460a632Mike Iselystatic void pvr2_context_exit(struct pvr2_context *mp) 270d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{ 271d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely int destroy_flag = 0; 272d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely if (!(mp->mc_first || !mp->disconnect_flag)) { 273d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely destroy_flag = !0; 274d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely } 275d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely mutex_unlock(&mp->mutex); 276794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely if (destroy_flag) pvr2_context_notify(mp); 277d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely} 278d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 279d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 280d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselyvoid pvr2_context_disconnect(struct pvr2_context *mp) 281d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{ 282794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely pvr2_hdw_disconnect(mp->hdw); 283794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely mp->disconnect_flag = !0; 284794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely pvr2_context_notify(mp); 285d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely} 286d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 287d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 288d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselyvoid pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp) 289d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{ 290794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely pvr2_context_enter(mp); 291d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely cp->hdw = mp->hdw; 292d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely cp->mc_head = mp; 293a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely cp->mc_next = NULL; 294d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely cp->mc_prev = mp->mc_last; 295d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely if (mp->mc_last) { 296d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely mp->mc_last->mc_next = cp; 297d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely } else { 298d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely mp->mc_first = cp; 299d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely } 300d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely mp->mc_last = cp; 301794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely pvr2_context_exit(mp); 302d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely} 303d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 304d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 305d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselystatic void pvr2_channel_disclaim_stream(struct pvr2_channel *cp) 306d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{ 307d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely if (!cp->stream) return; 308d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely pvr2_stream_kill(cp->stream->stream); 309a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely cp->stream->user = NULL; 310a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely cp->stream = NULL; 311d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely} 312d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 313d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 314d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselyvoid pvr2_channel_done(struct pvr2_channel *cp) 315d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{ 316d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely struct pvr2_context *mp = cp->mc_head; 317794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely pvr2_context_enter(mp); 3181cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely cp->input_mask = 0; 319d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely pvr2_channel_disclaim_stream(cp); 3201cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely pvr2_context_reset_input_limits(mp); 321d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely if (cp->mc_next) { 322d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely cp->mc_next->mc_prev = cp->mc_prev; 323d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely } else { 324d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely mp->mc_last = cp->mc_prev; 325d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely } 326d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely if (cp->mc_prev) { 327d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely cp->mc_prev->mc_next = cp->mc_next; 328d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely } else { 329d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely mp->mc_first = cp->mc_next; 330d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely } 331a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely cp->hdw = NULL; 332794b16072e00d0a40a8c773dd4319fb1e460a632Mike Isely pvr2_context_exit(mp); 333d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely} 334d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 335d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 3361cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Iselyint pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk) 3371cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely{ 3381cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely unsigned int tmsk,mmsk; 3391cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely int ret = 0; 3401cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely struct pvr2_channel *p2; 3411cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely struct pvr2_hdw *hdw = cp->hdw; 3421cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely 3431cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely mmsk = pvr2_hdw_get_input_available(hdw); 3441cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely cmsk &= mmsk; 3451cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely if (cmsk == cp->input_mask) { 3461cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely /* No change; nothing to do */ 3471cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely return 0; 3481cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely } 3491cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely 3501cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely pvr2_context_enter(cp->mc_head); 3511cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely do { 3521cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely if (!cmsk) { 3531cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely cp->input_mask = 0; 3541cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely pvr2_context_reset_input_limits(cp->mc_head); 3551cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely break; 3561cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely } 3571cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely tmsk = mmsk; 3581cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) { 3591cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely if (p2 == cp) continue; 3601cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely if (!p2->input_mask) continue; 3611cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely tmsk &= p2->input_mask; 3621cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely } 3631cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely if (!(tmsk & cmsk)) { 3641cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely ret = -EPERM; 3651cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely break; 3661cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely } 3671cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely tmsk &= cmsk; 3681cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) { 3691cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely /* Internal failure changing allowed list; probably 3701cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely should not happen, but react if it does. */ 3711cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely break; 3721cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely } 3731cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely cp->input_mask = cmsk; 3741cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely pvr2_hdw_commit_ctl(hdw); 3751cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely } while (0); 3761cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely pvr2_context_exit(cp->mc_head); 3771cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely return ret; 3781cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely} 3791cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely 3801cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely 3811cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Iselyunsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp) 3821cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely{ 3831cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely return cp->input_mask; 3841cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely} 3851cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely 3861cb03b76d09d20accfa5c1664c16ba6566f539a0Mike Isely 387d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselyint pvr2_channel_claim_stream(struct pvr2_channel *cp, 388d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely struct pvr2_context_stream *sp) 389d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{ 390d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely int code = 0; 391d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely pvr2_context_enter(cp->mc_head); do { 392d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely if (sp == cp->stream) break; 39399a6acf9a7a80da49e85be964b15ffed9ab7643eMike Isely if (sp && sp->user) { 394d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely code = -EBUSY; 395d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely break; 396d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely } 397d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely pvr2_channel_disclaim_stream(cp); 398d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely if (!sp) break; 399d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely sp->user = cp; 400d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely cp->stream = sp; 401d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely } while (0); pvr2_context_exit(cp->mc_head); 402d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely return code; 403d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely} 404d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 405d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 406d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely// This is the marker for the real beginning of a legitimate mpeg2 stream. 407d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselystatic char stream_sync_key[] = { 408d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 0x00, 0x00, 0x01, 0xba, 409d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely}; 410d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 411d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Iselystruct pvr2_ioread *pvr2_channel_create_mpeg_stream( 412d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely struct pvr2_context_stream *sp) 413d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely{ 414d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely struct pvr2_ioread *cp; 415d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely cp = pvr2_ioread_create(); 416a0fd1cb171e8b17339a9a18ae7cf09c50022010fMike Isely if (!cp) return NULL; 417d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely pvr2_ioread_setup(cp,sp->stream); 418d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key)); 419d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely return cp; 420d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely} 421d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 422d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely 423d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely/* 424d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely Stuff for Emacs to see, in order to encourage consistent editing style: 425d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *** Local Variables: *** 426d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *** mode: c *** 427d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *** fill-column: 75 *** 428d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *** tab-width: 8 *** 429d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *** c-basic-offset: 8 *** 430d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely *** End: *** 431d855497edbfbf9e19a17f4a1154bca69cb4bd9baMike Isely */ 432