/* * $Id$ * * Copyright (C) 2005 Mike Isely * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * */ #include "pvrusb2-context.h" #include "pvrusb2-io.h" #include "pvrusb2-ioread.h" #include "pvrusb2-hdw.h" #include "pvrusb2-debug.h" #include #include #include #include static void pvr2_context_destroy(struct pvr2_context *mp) { if (mp->hdw) pvr2_hdw_destroy(mp->hdw); pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp); flush_workqueue(mp->workqueue); destroy_workqueue(mp->workqueue); kfree(mp); } static void pvr2_context_trigger_poll(struct pvr2_context *mp) { queue_work(mp->workqueue,&mp->workpoll); } static void pvr2_context_poll(struct pvr2_context *mp) { pvr2_context_enter(mp); do { pvr2_hdw_poll(mp->hdw); } while (0); pvr2_context_exit(mp); } static void pvr2_context_setup(struct pvr2_context *mp) { pvr2_context_enter(mp); do { if (!pvr2_hdw_dev_ok(mp->hdw)) break; pvr2_hdw_setup(mp->hdw); pvr2_hdw_setup_poll_trigger( mp->hdw, (void (*)(void *))pvr2_context_trigger_poll, mp); if (!pvr2_hdw_dev_ok(mp->hdw)) break; if (!pvr2_hdw_init_ok(mp->hdw)) break; mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw); if (mp->setup_func) { mp->setup_func(mp); } } while (0); pvr2_context_exit(mp); } struct pvr2_context *pvr2_context_create( struct usb_interface *intf, const struct usb_device_id *devid, void (*setup_func)(struct pvr2_context *)) { struct pvr2_context *mp = NULL; mp = kmalloc(sizeof(*mp),GFP_KERNEL); if (!mp) goto done; memset(mp,0,sizeof(*mp)); pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp); mp->setup_func = setup_func; mutex_init(&mp->mutex); mp->hdw = pvr2_hdw_create(intf,devid); if (!mp->hdw) { pvr2_context_destroy(mp); mp = NULL; goto done; } mp->workqueue = create_singlethread_workqueue("pvrusb2"); INIT_WORK(&mp->workinit,(void (*)(void*))pvr2_context_setup,mp); INIT_WORK(&mp->workpoll,(void (*)(void*))pvr2_context_poll,mp); queue_work(mp->workqueue,&mp->workinit); done: return mp; } void pvr2_context_enter(struct pvr2_context *mp) { mutex_lock(&mp->mutex); pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_enter(id=%p)",mp); } void pvr2_context_exit(struct pvr2_context *mp) { int destroy_flag = 0; if (!(mp->mc_first || !mp->disconnect_flag)) { destroy_flag = !0; } pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_exit(id=%p) outside",mp); mutex_unlock(&mp->mutex); if (destroy_flag) pvr2_context_destroy(mp); } static void pvr2_context_run_checks(struct pvr2_context *mp) { struct pvr2_channel *ch1,*ch2; for (ch1 = mp->mc_first; ch1; ch1 = ch2) { ch2 = ch1->mc_next; if (ch1->check_func) { ch1->check_func(ch1); } } } void pvr2_context_disconnect(struct pvr2_context *mp) { pvr2_context_enter(mp); do { pvr2_hdw_disconnect(mp->hdw); mp->disconnect_flag = !0; pvr2_context_run_checks(mp); } while (0); pvr2_context_exit(mp); } void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp) { cp->hdw = mp->hdw; cp->mc_head = mp; cp->mc_next = NULL; cp->mc_prev = mp->mc_last; if (mp->mc_last) { mp->mc_last->mc_next = cp; } else { mp->mc_first = cp; } mp->mc_last = cp; } static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp) { if (!cp->stream) return; pvr2_stream_kill(cp->stream->stream); cp->stream->user = NULL; cp->stream = NULL; } void pvr2_channel_done(struct pvr2_channel *cp) { struct pvr2_context *mp = cp->mc_head; pvr2_channel_disclaim_stream(cp); if (cp->mc_next) { cp->mc_next->mc_prev = cp->mc_prev; } else { mp->mc_last = cp->mc_prev; } if (cp->mc_prev) { cp->mc_prev->mc_next = cp->mc_next; } else { mp->mc_first = cp->mc_next; } cp->hdw = NULL; } int pvr2_channel_claim_stream(struct pvr2_channel *cp, struct pvr2_context_stream *sp) { int code = 0; pvr2_context_enter(cp->mc_head); do { if (sp == cp->stream) break; if (sp->user) { code = -EBUSY; break; } pvr2_channel_disclaim_stream(cp); if (!sp) break; sp->user = cp; cp->stream = sp; } while (0); pvr2_context_exit(cp->mc_head); return code; } // This is the marker for the real beginning of a legitimate mpeg2 stream. static char stream_sync_key[] = { 0x00, 0x00, 0x01, 0xba, }; struct pvr2_ioread *pvr2_channel_create_mpeg_stream( struct pvr2_context_stream *sp) { struct pvr2_ioread *cp; cp = pvr2_ioread_create(); if (!cp) return NULL; pvr2_ioread_setup(cp,sp->stream); pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key)); return cp; } /* Stuff for Emacs to see, in order to encourage consistent editing style: *** Local Variables: *** *** mode: c *** *** fill-column: 75 *** *** tab-width: 8 *** *** c-basic-offset: 8 *** *** End: *** */