brintos

brintos / linux-shallow public Read only

0
0
Text · 5.6 KiB · 3b7e2f1 Raw
245 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*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