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