linux/drivers/media/firewire/firedtv-dvb.c
<<
>>
Prefs
   1/*
   2 * FireDTV driver (formerly known as FireSAT)
   3 *
   4 * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
   5 * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
   6 *
   7 *      This program is free software; you can redistribute it and/or
   8 *      modify it under the terms of the GNU General Public License as
   9 *      published by the Free Software Foundation; either version 2 of
  10 *      the License, or (at your option) any later version.
  11 */
  12
  13#include <linux/bitops.h>
  14#include <linux/device.h>
  15#include <linux/errno.h>
  16#include <linux/kernel.h>
  17#include <linux/module.h>
  18#include <linux/mutex.h>
  19#include <linux/types.h>
  20
  21#include <media/dmxdev.h>
  22#include <media/dvb_demux.h>
  23#include <media/dvbdev.h>
  24#include <media/dvb_frontend.h>
  25
  26#include "firedtv.h"
  27
  28static int alloc_channel(struct firedtv *fdtv)
  29{
  30        int i;
  31
  32        for (i = 0; i < 16; i++)
  33                if (!__test_and_set_bit(i, &fdtv->channel_active))
  34                        break;
  35        return i;
  36}
  37
  38static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])
  39{
  40        int i, n;
  41
  42        for (i = 0, n = 0; i < 16; i++)
  43                if (test_bit(i, &fdtv->channel_active))
  44                        pid[n++] = fdtv->channel_pid[i];
  45        *pidc = n;
  46}
  47
  48static inline void dealloc_channel(struct firedtv *fdtv, int i)
  49{
  50        __clear_bit(i, &fdtv->channel_active);
  51}
  52
  53int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
  54{
  55        struct firedtv *fdtv = dvbdmxfeed->demux->priv;
  56        int pidc, c, ret;
  57        u16 pids[16];
  58
  59        switch (dvbdmxfeed->type) {
  60        case DMX_TYPE_TS:
  61        case DMX_TYPE_SEC:
  62                break;
  63        default:
  64                dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",
  65                        dvbdmxfeed->type);
  66                return -EINVAL;
  67        }
  68
  69        if (mutex_lock_interruptible(&fdtv->demux_mutex))
  70                return -EINTR;
  71
  72        if (dvbdmxfeed->type == DMX_TYPE_TS) {
  73                switch (dvbdmxfeed->pes_type) {
  74                case DMX_PES_VIDEO:
  75                case DMX_PES_AUDIO:
  76                case DMX_PES_TELETEXT:
  77                case DMX_PES_PCR:
  78                case DMX_PES_OTHER:
  79                        c = alloc_channel(fdtv);
  80                        break;
  81                default:
  82                        dev_err(fdtv->device,
  83                                "can't start dmx feed: invalid pes type %u\n",
  84                                dvbdmxfeed->pes_type);
  85                        ret = -EINVAL;
  86                        goto out;
  87                }
  88        } else {
  89                c = alloc_channel(fdtv);
  90        }
  91
  92        if (c > 15) {
  93                dev_err(fdtv->device, "can't start dmx feed: busy\n");
  94                ret = -EBUSY;
  95                goto out;
  96        }
  97
  98        dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;
  99        fdtv->channel_pid[c] = dvbdmxfeed->pid;
 100        collect_channels(fdtv, &pidc, pids);
 101
 102        if (dvbdmxfeed->pid == 8192) {
 103                ret = avc_tuner_get_ts(fdtv);
 104                if (ret) {
 105                        dealloc_channel(fdtv, c);
 106                        dev_err(fdtv->device, "can't get TS\n");
 107                        goto out;
 108                }
 109        } else {
 110                ret = avc_tuner_set_pids(fdtv, pidc, pids);
 111                if (ret) {
 112                        dealloc_channel(fdtv, c);
 113                        dev_err(fdtv->device, "can't set PIDs\n");
 114                        goto out;
 115                }
 116        }
 117out:
 118        mutex_unlock(&fdtv->demux_mutex);
 119
 120        return ret;
 121}
 122
 123int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
 124{
 125        struct dvb_demux *demux = dvbdmxfeed->demux;
 126        struct firedtv *fdtv = demux->priv;
 127        int pidc, c, ret;
 128        u16 pids[16];
 129
 130        if (dvbdmxfeed->type == DMX_TYPE_TS &&
 131            !((dvbdmxfeed->ts_type & TS_PACKET) &&
 132              (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
 133
 134                if (dvbdmxfeed->ts_type & TS_DECODER) {
 135                        if (dvbdmxfeed->pes_type >= DMX_PES_OTHER ||
 136                            !demux->pesfilter[dvbdmxfeed->pes_type])
 137                                return -EINVAL;
 138
 139                        demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
 140                        demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
 141                }
 142
 143                if (!(dvbdmxfeed->ts_type & TS_DECODER &&
 144                      dvbdmxfeed->pes_type < DMX_PES_OTHER))
 145                        return 0;
 146        }
 147
 148        if (mutex_lock_interruptible(&fdtv->demux_mutex))
 149                return -EINTR;
 150
 151        c = (unsigned long)dvbdmxfeed->priv;
 152        dealloc_channel(fdtv, c);
 153        collect_channels(fdtv, &pidc, pids);
 154
 155        ret = avc_tuner_set_pids(fdtv, pidc, pids);
 156
 157        mutex_unlock(&fdtv->demux_mutex);
 158
 159        return ret;
 160}
 161
 162DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
 163
 164int fdtv_dvb_register(struct firedtv *fdtv, const char *name)
 165{
 166        int err;
 167
 168        err = dvb_register_adapter(&fdtv->adapter, name,
 169                                   THIS_MODULE, fdtv->device, adapter_nr);
 170        if (err < 0)
 171                goto fail_log;
 172
 173        /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
 174        fdtv->demux.dmx.capabilities = 0;
 175
 176        fdtv->demux.priv        = fdtv;
 177        fdtv->demux.filternum   = 16;
 178        fdtv->demux.feednum     = 16;
 179        fdtv->demux.start_feed  = fdtv_start_feed;
 180        fdtv->demux.stop_feed   = fdtv_stop_feed;
 181        fdtv->demux.write_to_decoder = NULL;
 182
 183        err = dvb_dmx_init(&fdtv->demux);
 184        if (err)
 185                goto fail_unreg_adapter;
 186
 187        fdtv->dmxdev.filternum    = 16;
 188        fdtv->dmxdev.demux        = &fdtv->demux.dmx;
 189        fdtv->dmxdev.capabilities = 0;
 190
 191        err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
 192        if (err)
 193                goto fail_dmx_release;
 194
 195        fdtv->frontend.source = DMX_FRONTEND_0;
 196
 197        err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);
 198        if (err)
 199                goto fail_dmxdev_release;
 200
 201        err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
 202                                               &fdtv->frontend);
 203        if (err)
 204                goto fail_rem_frontend;
 205
 206        err = dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
 207        if (err)
 208                goto fail_disconnect_frontend;
 209
 210        fdtv_frontend_init(fdtv, name);
 211        err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
 212        if (err)
 213                goto fail_net_release;
 214
 215        err = fdtv_ca_register(fdtv);
 216        if (err)
 217                dev_info(fdtv->device,
 218                         "Conditional Access Module not enabled\n");
 219        return 0;
 220
 221fail_net_release:
 222        dvb_net_release(&fdtv->dvbnet);
 223fail_disconnect_frontend:
 224        fdtv->demux.dmx.close(&fdtv->demux.dmx);
 225fail_rem_frontend:
 226        fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
 227fail_dmxdev_release:
 228        dvb_dmxdev_release(&fdtv->dmxdev);
 229fail_dmx_release:
 230        dvb_dmx_release(&fdtv->demux);
 231fail_unreg_adapter:
 232        dvb_unregister_adapter(&fdtv->adapter);
 233fail_log:
 234        dev_err(fdtv->device, "DVB initialization failed\n");
 235        return err;
 236}
 237
 238void fdtv_dvb_unregister(struct firedtv *fdtv)
 239{
 240        fdtv_ca_release(fdtv);
 241        dvb_unregister_frontend(&fdtv->fe);
 242        dvb_net_release(&fdtv->dvbnet);
 243        fdtv->demux.dmx.close(&fdtv->demux.dmx);
 244        fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
 245        dvb_dmxdev_release(&fdtv->dmxdev);
 246        dvb_dmx_release(&fdtv->demux);
 247        dvb_unregister_adapter(&fdtv->adapter);
 248}
 249