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