Path: blob/master/drivers/media/dvb/firewire/firedtv-dvb.c
15112 views
/*1* FireDTV driver (formerly known as FireSAT)2*3* Copyright (C) 2004 Andreas Monitzer <[email protected]>4* Copyright (C) 2008 Henrik Kurelid <[email protected]>5*6* This program is free software; you can redistribute it and/or7* modify it under the terms of the GNU General Public License as8* published by the Free Software Foundation; either version 2 of9* the License, or (at your option) any later version.10*/1112#include <linux/bitops.h>13#include <linux/device.h>14#include <linux/errno.h>15#include <linux/kernel.h>16#include <linux/module.h>17#include <linux/mutex.h>18#include <linux/types.h>1920#include <dmxdev.h>21#include <dvb_demux.h>22#include <dvbdev.h>23#include <dvb_frontend.h>2425#include "firedtv.h"2627static int alloc_channel(struct firedtv *fdtv)28{29int i;3031for (i = 0; i < 16; i++)32if (!__test_and_set_bit(i, &fdtv->channel_active))33break;34return i;35}3637static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])38{39int i, n;4041for (i = 0, n = 0; i < 16; i++)42if (test_bit(i, &fdtv->channel_active))43pid[n++] = fdtv->channel_pid[i];44*pidc = n;45}4647static inline void dealloc_channel(struct firedtv *fdtv, int i)48{49__clear_bit(i, &fdtv->channel_active);50}5152int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)53{54struct firedtv *fdtv = dvbdmxfeed->demux->priv;55int pidc, c, ret;56u16 pids[16];5758switch (dvbdmxfeed->type) {59case DMX_TYPE_TS:60case DMX_TYPE_SEC:61break;62default:63dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",64dvbdmxfeed->type);65return -EINVAL;66}6768if (mutex_lock_interruptible(&fdtv->demux_mutex))69return -EINTR;7071if (dvbdmxfeed->type == DMX_TYPE_TS) {72switch (dvbdmxfeed->pes_type) {73case DMX_TS_PES_VIDEO:74case DMX_TS_PES_AUDIO:75case DMX_TS_PES_TELETEXT:76case DMX_TS_PES_PCR:77case DMX_TS_PES_OTHER:78c = alloc_channel(fdtv);79break;80default:81dev_err(fdtv->device,82"can't start dmx feed: invalid pes type %u\n",83dvbdmxfeed->pes_type);84ret = -EINVAL;85goto out;86}87} else {88c = alloc_channel(fdtv);89}9091if (c > 15) {92dev_err(fdtv->device, "can't start dmx feed: busy\n");93ret = -EBUSY;94goto out;95}9697dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;98fdtv->channel_pid[c] = dvbdmxfeed->pid;99collect_channels(fdtv, &pidc, pids);100101if (dvbdmxfeed->pid == 8192) {102ret = avc_tuner_get_ts(fdtv);103if (ret) {104dealloc_channel(fdtv, c);105dev_err(fdtv->device, "can't get TS\n");106goto out;107}108} else {109ret = avc_tuner_set_pids(fdtv, pidc, pids);110if (ret) {111dealloc_channel(fdtv, c);112dev_err(fdtv->device, "can't set PIDs\n");113goto out;114}115}116out:117mutex_unlock(&fdtv->demux_mutex);118119return ret;120}121122int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)123{124struct dvb_demux *demux = dvbdmxfeed->demux;125struct firedtv *fdtv = demux->priv;126int pidc, c, ret;127u16 pids[16];128129if (dvbdmxfeed->type == DMX_TYPE_TS &&130!((dvbdmxfeed->ts_type & TS_PACKET) &&131(demux->dmx.frontend->source != DMX_MEMORY_FE))) {132133if (dvbdmxfeed->ts_type & TS_DECODER) {134if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||135!demux->pesfilter[dvbdmxfeed->pes_type])136return -EINVAL;137138demux->pids[dvbdmxfeed->pes_type] |= 0x8000;139demux->pesfilter[dvbdmxfeed->pes_type] = NULL;140}141142if (!(dvbdmxfeed->ts_type & TS_DECODER &&143dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))144return 0;145}146147if (mutex_lock_interruptible(&fdtv->demux_mutex))148return -EINTR;149150c = (unsigned long)dvbdmxfeed->priv;151dealloc_channel(fdtv, c);152collect_channels(fdtv, &pidc, pids);153154ret = avc_tuner_set_pids(fdtv, pidc, pids);155156mutex_unlock(&fdtv->demux_mutex);157158return ret;159}160161DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);162163int fdtv_dvb_register(struct firedtv *fdtv, const char *name)164{165int err;166167err = dvb_register_adapter(&fdtv->adapter, name,168THIS_MODULE, fdtv->device, adapter_nr);169if (err < 0)170goto fail_log;171172/*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/173fdtv->demux.dmx.capabilities = 0;174175fdtv->demux.priv = fdtv;176fdtv->demux.filternum = 16;177fdtv->demux.feednum = 16;178fdtv->demux.start_feed = fdtv_start_feed;179fdtv->demux.stop_feed = fdtv_stop_feed;180fdtv->demux.write_to_decoder = NULL;181182err = dvb_dmx_init(&fdtv->demux);183if (err)184goto fail_unreg_adapter;185186fdtv->dmxdev.filternum = 16;187fdtv->dmxdev.demux = &fdtv->demux.dmx;188fdtv->dmxdev.capabilities = 0;189190err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);191if (err)192goto fail_dmx_release;193194fdtv->frontend.source = DMX_FRONTEND_0;195196err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);197if (err)198goto fail_dmxdev_release;199200err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,201&fdtv->frontend);202if (err)203goto fail_rem_frontend;204205dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);206207fdtv_frontend_init(fdtv, name);208err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);209if (err)210goto fail_net_release;211212err = fdtv_ca_register(fdtv);213if (err)214dev_info(fdtv->device,215"Conditional Access Module not enabled\n");216return 0;217218fail_net_release:219dvb_net_release(&fdtv->dvbnet);220fdtv->demux.dmx.close(&fdtv->demux.dmx);221fail_rem_frontend:222fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);223fail_dmxdev_release:224dvb_dmxdev_release(&fdtv->dmxdev);225fail_dmx_release:226dvb_dmx_release(&fdtv->demux);227fail_unreg_adapter:228dvb_unregister_adapter(&fdtv->adapter);229fail_log:230dev_err(fdtv->device, "DVB initialization failed\n");231return err;232}233234void fdtv_dvb_unregister(struct firedtv *fdtv)235{236fdtv_ca_release(fdtv);237dvb_unregister_frontend(&fdtv->fe);238dvb_net_release(&fdtv->dvbnet);239fdtv->demux.dmx.close(&fdtv->demux.dmx);240fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);241dvb_dmxdev_release(&fdtv->dmxdev);242dvb_dmx_release(&fdtv->demux);243dvb_unregister_adapter(&fdtv->adapter);244}245246247