1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 	Mantis PCI bridge driver
4 	Copyright (C) Manu Abraham (abraham.manu@gmail.com)
5 
6 */
7 
8 #include <linux/kernel.h>
9 #include <linux/bitops.h>
10 
11 #include <linux/signal.h>
12 #include <linux/sched.h>
13 #include <linux/interrupt.h>
14 #include <linux/pci.h>
15 #include <linux/i2c.h>
16 
17 #include <media/dmxdev.h>
18 #include <media/dvbdev.h>
19 #include <media/dvb_demux.h>
20 #include <media/dvb_frontend.h>
21 #include <media/dvb_net.h>
22 
23 #include "mantis_common.h"
24 #include "mantis_dma.h"
25 #include "mantis_ca.h"
26 #include "mantis_ioc.h"
27 #include "mantis_dvb.h"
28 
29 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
30 
31 int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
32 {
33 	struct mantis_hwconfig *config = mantis->hwconfig;
34 
35 	switch (power) {
36 	case POWER_ON:
37 		dprintk(MANTIS_DEBUG, 1, "Power ON");
38 		mantis_gpio_set_bits(mantis, config->power, POWER_ON);
39 		msleep(100);
40 		mantis_gpio_set_bits(mantis, config->power, POWER_ON);
41 		msleep(100);
42 		break;
43 
44 	case POWER_OFF:
45 		dprintk(MANTIS_DEBUG, 1, "Power OFF");
46 		mantis_gpio_set_bits(mantis, config->power, POWER_OFF);
47 		msleep(100);
48 		break;
49 
50 	default:
51 		dprintk(MANTIS_DEBUG, 1, "Unknown state <%02x>", power);
52 		return -1;
53 	}
54 
55 	return 0;
56 }
57 EXPORT_SYMBOL_GPL(mantis_frontend_power);
58 
59 void mantis_frontend_soft_reset(struct mantis_pci *mantis)
60 {
61 	struct mantis_hwconfig *config = mantis->hwconfig;
62 
63 	dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
64 	mantis_gpio_set_bits(mantis, config->reset, 0);
65 	msleep(100);
66 	mantis_gpio_set_bits(mantis, config->reset, 0);
67 	msleep(100);
68 	mantis_gpio_set_bits(mantis, config->reset, 1);
69 	msleep(100);
70 	mantis_gpio_set_bits(mantis, config->reset, 1);
71 	msleep(100);
72 
73 	return;
74 }
75 EXPORT_SYMBOL_GPL(mantis_frontend_soft_reset);
76 
77 static int mantis_frontend_shutdown(struct mantis_pci *mantis)
78 {
79 	int err;
80 
81 	mantis_frontend_soft_reset(mantis);
82 	err = mantis_frontend_power(mantis, POWER_OFF);
83 	if (err != 0) {
84 		dprintk(MANTIS_ERROR, 1, "Frontend POWER OFF failed! <%d>", err);
85 		return 1;
86 	}
87 
88 	return 0;
89 }
90 
91 static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
92 {
93 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
94 	struct mantis_pci *mantis = dvbdmx->priv;
95 
96 	dprintk(MANTIS_DEBUG, 1, "Mantis DVB Start feed");
97 	if (!dvbdmx->dmx.frontend) {
98 		dprintk(MANTIS_DEBUG, 1, "no frontend ?");
99 		return -EINVAL;
100 	}
101 
102 	mantis->feeds++;
103 	dprintk(MANTIS_DEBUG, 1, "mantis start feed, feeds=%d",	mantis->feeds);
104 
105 	if (mantis->feeds == 1)	 {
106 		dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
107 		mantis_dma_start(mantis);
108 		tasklet_enable(&mantis->tasklet);
109 	}
110 
111 	return mantis->feeds;
112 }
113 
114 static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
115 {
116 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
117 	struct mantis_pci *mantis = dvbdmx->priv;
118 
119 	dprintk(MANTIS_DEBUG, 1, "Mantis DVB Stop feed");
120 	if (!dvbdmx->dmx.frontend) {
121 		dprintk(MANTIS_DEBUG, 1, "no frontend ?");
122 		return -EINVAL;
123 	}
124 
125 	mantis->feeds--;
126 	if (mantis->feeds == 0) {
127 		dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
128 		tasklet_disable(&mantis->tasklet);
129 		mantis_dma_stop(mantis);
130 	}
131 
132 	return 0;
133 }
134 
135 int mantis_dvb_init(struct mantis_pci *mantis)
136 {
137 	struct mantis_hwconfig *config = mantis->hwconfig;
138 	int result;
139 
140 	dprintk(MANTIS_DEBUG, 1, "dvb_register_adapter");
141 
142 	result = dvb_register_adapter(&mantis->dvb_adapter,
143 				      "Mantis DVB adapter",
144 				      THIS_MODULE,
145 				      &mantis->pdev->dev,
146 				      adapter_nr);
147 
148 	if (result < 0) {
149 
150 		dprintk(MANTIS_ERROR, 1, "Error registering adapter");
151 		return -ENODEV;
152 	}
153 
154 	mantis->dvb_adapter.priv	= mantis;
155 	mantis->demux.dmx.capabilities	= DMX_TS_FILTERING	|
156 					 DMX_SECTION_FILTERING	|
157 					 DMX_MEMORY_BASED_FILTERING;
158 
159 	mantis->demux.priv		= mantis;
160 	mantis->demux.filternum		= 256;
161 	mantis->demux.feednum		= 256;
162 	mantis->demux.start_feed	= mantis_dvb_start_feed;
163 	mantis->demux.stop_feed		= mantis_dvb_stop_feed;
164 	mantis->demux.write_to_decoder	= NULL;
165 
166 	dprintk(MANTIS_DEBUG, 1, "dvb_dmx_init");
167 	result = dvb_dmx_init(&mantis->demux);
168 	if (result < 0) {
169 		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
170 
171 		goto err0;
172 	}
173 
174 	mantis->dmxdev.filternum	= 256;
175 	mantis->dmxdev.demux		= &mantis->demux.dmx;
176 	mantis->dmxdev.capabilities	= 0;
177 	dprintk(MANTIS_DEBUG, 1, "dvb_dmxdev_init");
178 
179 	result = dvb_dmxdev_init(&mantis->dmxdev, &mantis->dvb_adapter);
180 	if (result < 0) {
181 
182 		dprintk(MANTIS_ERROR, 1, "dvb_dmxdev_init failed, ERROR=%d", result);
183 		goto err1;
184 	}
185 
186 	mantis->fe_hw.source		= DMX_FRONTEND_0;
187 	result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_hw);
188 	if (result < 0) {
189 
190 		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
191 		goto err2;
192 	}
193 
194 	mantis->fe_mem.source		= DMX_MEMORY_FE;
195 	result = mantis->demux.dmx.add_frontend(&mantis->demux.dmx, &mantis->fe_mem);
196 	if (result < 0) {
197 		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
198 		goto err3;
199 	}
200 
201 	result = mantis->demux.dmx.connect_frontend(&mantis->demux.dmx, &mantis->fe_hw);
202 	if (result < 0) {
203 		dprintk(MANTIS_ERROR, 1, "dvb_dmx_init failed, ERROR=%d", result);
204 		goto err4;
205 	}
206 
207 	dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
208 	tasklet_setup(&mantis->tasklet, mantis_dma_xfer);
209 	tasklet_disable(&mantis->tasklet);
210 	if (mantis->hwconfig) {
211 		result = config->frontend_init(mantis, mantis->fe);
212 		if (result < 0) {
213 			dprintk(MANTIS_ERROR, 1, "!!! NO Frontends found !!!");
214 			goto err5;
215 		} else {
216 			if (mantis->fe == NULL) {
217 				result = -ENOMEM;
218 				dprintk(MANTIS_ERROR, 1, "FE <NULL>");
219 				goto err5;
220 			}
221 			result = dvb_register_frontend(&mantis->dvb_adapter, mantis->fe);
222 			if (result) {
223 				dprintk(MANTIS_ERROR, 1, "ERROR: Frontend registration failed");
224 
225 				if (mantis->fe->ops.release)
226 					mantis->fe->ops.release(mantis->fe);
227 
228 				mantis->fe = NULL;
229 				goto err5;
230 			}
231 		}
232 	}
233 
234 	return 0;
235 
236 	/* Error conditions ..	*/
237 err5:
238 	tasklet_kill(&mantis->tasklet);
239 	dvb_net_release(&mantis->dvbnet);
240 	if (mantis->fe) {
241 		dvb_unregister_frontend(mantis->fe);
242 		dvb_frontend_detach(mantis->fe);
243 	}
244 err4:
245 	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
246 
247 err3:
248 	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
249 
250 err2:
251 	dvb_dmxdev_release(&mantis->dmxdev);
252 
253 err1:
254 	dvb_dmx_release(&mantis->demux);
255 
256 err0:
257 	dvb_unregister_adapter(&mantis->dvb_adapter);
258 
259 	return result;
260 }
261 EXPORT_SYMBOL_GPL(mantis_dvb_init);
262 
263 int mantis_dvb_exit(struct mantis_pci *mantis)
264 {
265 	int err;
266 
267 	if (mantis->fe) {
268 		/* mantis_ca_exit(mantis); */
269 		err = mantis_frontend_shutdown(mantis);
270 		if (err != 0)
271 			dprintk(MANTIS_ERROR, 1, "Frontend exit while POWER ON! <%d>", err);
272 		dvb_unregister_frontend(mantis->fe);
273 		dvb_frontend_detach(mantis->fe);
274 	}
275 
276 	tasklet_kill(&mantis->tasklet);
277 	dvb_net_release(&mantis->dvbnet);
278 
279 	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_mem);
280 	mantis->demux.dmx.remove_frontend(&mantis->demux.dmx, &mantis->fe_hw);
281 
282 	dvb_dmxdev_release(&mantis->dmxdev);
283 	dvb_dmx_release(&mantis->demux);
284 
285 	dprintk(MANTIS_DEBUG, 1, "dvb_unregister_adapter");
286 	dvb_unregister_adapter(&mantis->dvb_adapter);
287 
288 	return 0;
289 }
290 EXPORT_SYMBOL_GPL(mantis_dvb_exit);
291