xref: /linux/drivers/media/firewire/firedtv-dvb.c (revision 0be3ff0c)
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 
24 static 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 
34 static 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 
44 static inline void dealloc_channel(struct firedtv *fdtv, int i)
45 {
46 	__clear_bit(i, &fdtv->channel_active);
47 }
48 
49 int 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 	}
113 out:
114 	mutex_unlock(&fdtv->demux_mutex);
115 
116 	return ret;
117 }
118 
119 int 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 
158 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
159 
160 int 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 
217 fail_net_release:
218 	dvb_net_release(&fdtv->dvbnet);
219 fail_disconnect_frontend:
220 	fdtv->demux.dmx.close(&fdtv->demux.dmx);
221 fail_rem_frontend:
222 	fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
223 fail_dmxdev_release:
224 	dvb_dmxdev_release(&fdtv->dmxdev);
225 fail_dmx_release:
226 	dvb_dmx_release(&fdtv->demux);
227 fail_unreg_adapter:
228 	dvb_unregister_adapter(&fdtv->adapter);
229 fail_log:
230 	dev_err(fdtv->device, "DVB initialization failed\n");
231 	return err;
232 }
233 
234 void 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