linux/drivers/media/video/pvrusb2/pvrusb2-context.c
<<
>>
Prefs
   1/*
   2 *  $Id$
   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        if (mp->workqueue) {
  37                flush_workqueue(mp->workqueue);
  38                destroy_workqueue(mp->workqueue);
  39        }
  40        kfree(mp);
  41}
  42
  43
  44static void pvr2_context_trigger_poll(struct pvr2_context *mp)
  45{
  46        queue_work(mp->workqueue,&mp->workpoll);
  47}
  48
  49
  50static void pvr2_context_poll(struct work_struct *work)
  51{
  52        struct pvr2_context *mp =
  53                container_of(work, struct pvr2_context, workpoll);
  54        pvr2_context_enter(mp); do {
  55                pvr2_hdw_poll(mp->hdw);
  56        } while (0); pvr2_context_exit(mp);
  57}
  58
  59
  60static void pvr2_context_setup(struct work_struct *work)
  61{
  62        struct pvr2_context *mp =
  63                container_of(work, struct pvr2_context, workinit);
  64
  65        pvr2_context_enter(mp); do {
  66                if (!pvr2_hdw_dev_ok(mp->hdw)) break;
  67                pvr2_hdw_setup(mp->hdw);
  68                pvr2_hdw_setup_poll_trigger(
  69                        mp->hdw,
  70                        (void (*)(void *))pvr2_context_trigger_poll,
  71                        mp);
  72                if (!pvr2_hdw_dev_ok(mp->hdw)) break;
  73                if (!pvr2_hdw_init_ok(mp->hdw)) break;
  74                mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw);
  75                if (mp->setup_func) {
  76                        mp->setup_func(mp);
  77                }
  78        } while (0); pvr2_context_exit(mp);
  79}
  80
  81
  82struct pvr2_context *pvr2_context_create(
  83        struct usb_interface *intf,
  84        const struct usb_device_id *devid,
  85        void (*setup_func)(struct pvr2_context *))
  86{
  87        struct pvr2_context *mp = NULL;
  88        mp = kzalloc(sizeof(*mp),GFP_KERNEL);
  89        if (!mp) goto done;
  90        pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
  91        mp->setup_func = setup_func;
  92        mutex_init(&mp->mutex);
  93        mp->hdw = pvr2_hdw_create(intf,devid);
  94        if (!mp->hdw) {
  95                pvr2_context_destroy(mp);
  96                mp = NULL;
  97                goto done;
  98        }
  99
 100        mp->workqueue = create_singlethread_workqueue("pvrusb2");
 101        INIT_WORK(&mp->workinit, pvr2_context_setup);
 102        INIT_WORK(&mp->workpoll, pvr2_context_poll);
 103        queue_work(mp->workqueue,&mp->workinit);
 104 done:
 105        return mp;
 106}
 107
 108
 109void pvr2_context_enter(struct pvr2_context *mp)
 110{
 111        mutex_lock(&mp->mutex);
 112        pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_enter(id=%p)",mp);
 113}
 114
 115
 116void pvr2_context_exit(struct pvr2_context *mp)
 117{
 118        int destroy_flag = 0;
 119        if (!(mp->mc_first || !mp->disconnect_flag)) {
 120                destroy_flag = !0;
 121        }
 122        pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_exit(id=%p) outside",mp);
 123        mutex_unlock(&mp->mutex);
 124        if (destroy_flag) pvr2_context_destroy(mp);
 125}
 126
 127
 128static void pvr2_context_run_checks(struct pvr2_context *mp)
 129{
 130        struct pvr2_channel *ch1,*ch2;
 131        for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
 132                ch2 = ch1->mc_next;
 133                if (ch1->check_func) {
 134                        ch1->check_func(ch1);
 135                }
 136        }
 137}
 138
 139
 140void pvr2_context_disconnect(struct pvr2_context *mp)
 141{
 142        pvr2_context_enter(mp); do {
 143                pvr2_hdw_disconnect(mp->hdw);
 144                mp->disconnect_flag = !0;
 145                pvr2_context_run_checks(mp);
 146        } while (0); pvr2_context_exit(mp);
 147}
 148
 149
 150void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
 151{
 152        cp->hdw = mp->hdw;
 153        cp->mc_head = mp;
 154        cp->mc_next = NULL;
 155        cp->mc_prev = mp->mc_last;
 156        if (mp->mc_last) {
 157                mp->mc_last->mc_next = cp;
 158        } else {
 159                mp->mc_first = cp;
 160        }
 161        mp->mc_last = cp;
 162}
 163
 164
 165static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
 166{
 167        if (!cp->stream) return;
 168        pvr2_stream_kill(cp->stream->stream);
 169        cp->stream->user = NULL;
 170        cp->stream = NULL;
 171}
 172
 173
 174void pvr2_channel_done(struct pvr2_channel *cp)
 175{
 176        struct pvr2_context *mp = cp->mc_head;
 177        pvr2_channel_disclaim_stream(cp);
 178        if (cp->mc_next) {
 179                cp->mc_next->mc_prev = cp->mc_prev;
 180        } else {
 181                mp->mc_last = cp->mc_prev;
 182        }
 183        if (cp->mc_prev) {
 184                cp->mc_prev->mc_next = cp->mc_next;
 185        } else {
 186                mp->mc_first = cp->mc_next;
 187        }
 188        cp->hdw = NULL;
 189}
 190
 191
 192int pvr2_channel_claim_stream(struct pvr2_channel *cp,
 193                              struct pvr2_context_stream *sp)
 194{
 195        int code = 0;
 196        pvr2_context_enter(cp->mc_head); do {
 197                if (sp == cp->stream) break;
 198                if (sp->user) {
 199                        code = -EBUSY;
 200                        break;
 201                }
 202                pvr2_channel_disclaim_stream(cp);
 203                if (!sp) break;
 204                sp->user = cp;
 205                cp->stream = sp;
 206        } while (0); pvr2_context_exit(cp->mc_head);
 207        return code;
 208}
 209
 210
 211// This is the marker for the real beginning of a legitimate mpeg2 stream.
 212static char stream_sync_key[] = {
 213        0x00, 0x00, 0x01, 0xba,
 214};
 215
 216struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
 217        struct pvr2_context_stream *sp)
 218{
 219        struct pvr2_ioread *cp;
 220        cp = pvr2_ioread_create();
 221        if (!cp) return NULL;
 222        pvr2_ioread_setup(cp,sp->stream);
 223        pvr2_ioread_set_sync_key(cp,stream_sync_key,sizeof(stream_sync_key));
 224        return cp;
 225}
 226
 227
 228/*
 229  Stuff for Emacs to see, in order to encourage consistent editing style:
 230  *** Local Variables: ***
 231  *** mode: c ***
 232  *** fill-column: 75 ***
 233  *** tab-width: 8 ***
 234  *** c-basic-offset: 8 ***
 235  *** End: ***
 236  */
 237