1/* 2 * $Id: pvrusb2-context.c,v 1.1.1.1 2007/08/03 18:52:41 Exp $ 3 * 4 * Copyright (C) 2005 Mike Isely <isely@pobox.com> 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation; either version 2 of the License 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 * GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA 18 * 19 */ 20 21#include "pvrusb2-context.h" 22#include "pvrusb2-io.h" 23#include "pvrusb2-ioread.h" 24#include "pvrusb2-hdw.h" 25#include "pvrusb2-debug.h" 26#include <linux/errno.h> 27#include <linux/string.h> 28#include <linux/slab.h> 29#include <asm/semaphore.h> 30 31 32static void pvr2_context_destroy(struct pvr2_context *mp) 33{ 34 if (mp->hdw) pvr2_hdw_destroy(mp->hdw); 35 pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); 36 flush_workqueue(mp->workqueue); 37 destroy_workqueue(mp->workqueue); 38 kfree(mp); 39} 40 41 42static void pvr2_context_trigger_poll(struct pvr2_context *mp) 43{ 44 queue_work(mp->workqueue,&mp->workpoll); 45} 46 47 48static void pvr2_context_poll(struct work_struct *work) 49{ 50 struct pvr2_context *mp = 51 container_of(work, struct pvr2_context, workpoll); 52 pvr2_context_enter(mp); do { 53 pvr2_hdw_poll(mp->hdw); 54 } while (0); pvr2_context_exit(mp); 55} 56 57 58static void pvr2_context_setup(struct work_struct *work) 59{ 60 struct pvr2_context *mp = 61 container_of(work, struct pvr2_context, workinit); 62 63 pvr2_context_enter(mp); do { 64 if (!pvr2_hdw_dev_ok(mp->hdw)) break; 65 pvr2_hdw_setup(mp->hdw); 66 pvr2_hdw_setup_poll_trigger( 67 mp->hdw, 68 (void (*)(void *))pvr2_context_trigger_poll, 69 mp); 70 if (!pvr2_hdw_dev_ok(mp->hdw)) break; 71 if (!pvr2_hdw_init_ok(mp->hdw)) break; 72 mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw); 73 if (mp->setup_func) { 74 mp->setup_func(mp); 75 } 76 } while (0); pvr2_context_exit(mp); 77} 78 79 80struct pvr2_context *pvr2_context_create( 81 struct usb_interface *intf, 82 const struct usb_device_id *devid, 83 void (*setup_func)(struct pvr2_context *)) 84{ 85 struct pvr2_context *mp = NULL; 86 mp = kzalloc(sizeof(*mp),GFP_KERNEL); 87 if (!mp) goto done; 88 pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp); 89 mp->setup_func = setup_func; 90 mutex_init(&mp->mutex); 91 mp->hdw = pvr2_hdw_create(intf,devid); 92 if (!mp->hdw) { 93 pvr2_context_destroy(mp); 94 mp = NULL; 95 goto done; 96 } 97 98 mp->workqueue = create_singlethread_workqueue("pvrusb2"); 99 INIT_WORK(&mp->workinit, pvr2_context_setup); 100 INIT_WORK(&mp->workpoll, pvr2_context_poll); 101 queue_work(mp->workqueue,&mp->workinit); 102 done: 103 return mp; 104} 105 106 107void pvr2_context_enter(struct pvr2_context *mp) 108{ 109 mutex_lock(&mp->mutex); 110 pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_enter(id=%p)",mp); 111} 112 113 114void pvr2_context_exit(struct pvr2_context *mp) 115{ 116 int destroy_flag = 0; 117 if (!(mp->mc_first || !mp->disconnect_flag)) { 118 destroy_flag = !0; 119 } 120 pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_exit(id=%p) outside",mp); 121 mutex_unlock(&mp->mutex); 122 if (destroy_flag) pvr2_context_destroy(mp); 123} 124 125 126static void pvr2_context_run_checks(struct pvr2_context *mp) 127{ 128 struct pvr2_channel *ch1,*ch2; 129 for (ch1 = mp->mc_first; ch1; ch1 = ch2) { 130 ch2 = ch1->mc_next; 131 if (ch1->check_func) { 132 ch1->check_func(ch1); 133 } 134 } 135} 136 137 138void pvr2_context_disconnect(struct pvr2_context *mp) 139{ 140 pvr2_context_enter(mp); do { 141 pvr2_hdw_disconnect(mp->hdw); 142 mp->disconnect_flag = !0; 143 pvr2_context_run_checks(mp); 144 } while (0); pvr2_context_exit(mp); 145} 146 147 148void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp) 149{ 150 cp->hdw = mp->hdw; 151 cp->mc_head = mp; 152 cp->mc_next = NULL; 153 cp->mc_prev = mp->mc_last; 154 if (mp->mc_last) { 155 mp->mc_last->mc_next = cp; 156 } else { 157 mp->mc_first = cp; 158 } 159 mp->mc_last = cp; 160} 161 162 163static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp) 164{ 165 if (!cp->stream) return; 166 pvr2_stream_kill(cp->stream->stream); 167 cp->stream->user = NULL; 168 cp->stream = NULL; 169} 170 171 172void pvr2_channel_done(struct pvr2_channel *cp) 173{ 174 struct pvr2_context *mp = cp->mc_head; 175 pvr2_channel_disclaim_stream(cp); 176 if (cp->mc_next) { 177 cp->mc_next->mc_prev = cp->mc_prev; 178 } else { 179 mp->mc_last = cp->mc_prev; 180 } 181 if (cp->mc_prev) { 182 cp->mc_prev->mc_next = cp->mc_next; 183 } else { 184 mp->mc_first = cp->mc_next; 185 } 186 cp->hdw = NULL; 187} 188 189 190int pvr2_channel_claim_stream(struct pvr2_channel *cp, 191 struct pvr2_context_stream *sp) 192{ 193 int code = 0; 194 pvr2_context_enter(cp->mc_head); do { 195 if (sp == cp->stream) break; 196 if (sp->user) { 197 code = -EBUSY; 198 break; 199 } 200 pvr2_channel_disclaim_stream(cp); 201 if (!sp) break; 202 sp->user = cp; 203 cp->stream = sp; 204 } while (0); pvr2_context_exit(cp->mc_head); 205 return code; 206} 207 208 209// This is the marker for the real beginning of a legitimate mpeg2 stream. 210static char stream_sync_key[] = { 211 0x00, 0x00, 0x01, 0xba, 212}; 213 214struct pvr2_ioread *pvr2_channel_create_mpeg_stream( 215 struct pvr2_context_stream *sp) 216{ 217 struct pvr2_ioread *cp; 218 cp = pvr2_ioread_create(); 219 if (!cp) return NULL; 220 pvr2_ioread_setup(cp,sp->stream); 221 pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key)); 222 return cp; 223} 224 225 226/* 227 Stuff for Emacs to see, in order to encourage consistent editing style: 228 *** Local Variables: *** 229 *** mode: c *** 230 *** fill-column: 75 *** 231 *** tab-width: 8 *** 232 *** c-basic-offset: 8 *** 233 *** End: *** 234 */ 235