xref: /linux/drivers/media/usb/as102/as102_drv.c (revision a4eb44a6435d6d8f9e642407a4a06f65eb90ca04)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3  * Abilis Systems Single DVB-T Receiver
4  * Copyright (C) 2008 Pierrick Hascoet <pierrick.hascoet@abilis.com>
5  * Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
6  */
7 #include <linux/kernel.h>
8 #include <linux/errno.h>
9 #include <linux/slab.h>
10 #include <linux/module.h>
11 #include <linux/mm.h>
12 #include <linux/kref.h>
13 #include <linux/uaccess.h>
14 #include <linux/usb.h>
15 
16 /* header file for usb device driver*/
17 #include "as102_drv.h"
18 #include "as10x_cmd.h"
19 #include "as102_fe.h"
20 #include "as102_fw.h"
21 #include <media/dvbdev.h>
22 
23 int dual_tuner;
24 module_param_named(dual_tuner, dual_tuner, int, 0644);
25 MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)");
26 
27 static int fw_upload = 1;
28 module_param_named(fw_upload, fw_upload, int, 0644);
29 MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)");
30 
31 static int pid_filtering;
32 module_param_named(pid_filtering, pid_filtering, int, 0644);
33 MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)");
34 
35 static int ts_auto_disable;
36 module_param_named(ts_auto_disable, ts_auto_disable, int, 0644);
37 MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)");
38 
39 int elna_enable = 1;
40 module_param_named(elna_enable, elna_enable, int, 0644);
41 MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");
42 
43 DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
44 
45 static void as102_stop_stream(struct as102_dev_t *dev)
46 {
47 	struct as10x_bus_adapter_t *bus_adap;
48 
49 	if (dev != NULL)
50 		bus_adap = &dev->bus_adap;
51 	else
52 		return;
53 
54 	if (bus_adap->ops->stop_stream != NULL)
55 		bus_adap->ops->stop_stream(dev);
56 
57 	if (ts_auto_disable) {
58 		if (mutex_lock_interruptible(&dev->bus_adap.lock))
59 			return;
60 
61 		if (as10x_cmd_stop_streaming(bus_adap) < 0)
62 			dev_dbg(&dev->bus_adap.usb_dev->dev,
63 				"as10x_cmd_stop_streaming failed\n");
64 
65 		mutex_unlock(&dev->bus_adap.lock);
66 	}
67 }
68 
69 static int as102_start_stream(struct as102_dev_t *dev)
70 {
71 	struct as10x_bus_adapter_t *bus_adap;
72 	int ret = -EFAULT;
73 
74 	if (dev != NULL)
75 		bus_adap = &dev->bus_adap;
76 	else
77 		return ret;
78 
79 	if (bus_adap->ops->start_stream != NULL)
80 		ret = bus_adap->ops->start_stream(dev);
81 
82 	if (ts_auto_disable) {
83 		if (mutex_lock_interruptible(&dev->bus_adap.lock))
84 			return -EFAULT;
85 
86 		ret = as10x_cmd_start_streaming(bus_adap);
87 
88 		mutex_unlock(&dev->bus_adap.lock);
89 	}
90 
91 	return ret;
92 }
93 
94 static int as10x_pid_filter(struct as102_dev_t *dev,
95 			    int index, u16 pid, int onoff) {
96 
97 	struct as10x_bus_adapter_t *bus_adap = &dev->bus_adap;
98 	int ret = -EFAULT;
99 
100 	if (mutex_lock_interruptible(&dev->bus_adap.lock)) {
101 		dev_dbg(&dev->bus_adap.usb_dev->dev,
102 			"amutex_lock_interruptible(lock) failed !\n");
103 		return -EBUSY;
104 	}
105 
106 	switch (onoff) {
107 	case 0:
108 		ret = as10x_cmd_del_PID_filter(bus_adap, (uint16_t) pid);
109 		dev_dbg(&dev->bus_adap.usb_dev->dev,
110 			"DEL_PID_FILTER([%02d] 0x%04x) ret = %d\n",
111 			index, pid, ret);
112 		break;
113 	case 1:
114 	{
115 		struct as10x_ts_filter filter;
116 
117 		filter.type = TS_PID_TYPE_TS;
118 		filter.idx = 0xFF;
119 		filter.pid = pid;
120 
121 		ret = as10x_cmd_add_PID_filter(bus_adap, &filter);
122 		dev_dbg(&dev->bus_adap.usb_dev->dev,
123 			"ADD_PID_FILTER([%02d -> %02d], 0x%04x) ret = %d\n",
124 			index, filter.idx, filter.pid, ret);
125 		break;
126 	}
127 	}
128 
129 	mutex_unlock(&dev->bus_adap.lock);
130 	return ret;
131 }
132 
133 static int as102_dvb_dmx_start_feed(struct dvb_demux_feed *dvbdmxfeed)
134 {
135 	int ret = 0;
136 	struct dvb_demux *demux = dvbdmxfeed->demux;
137 	struct as102_dev_t *as102_dev = demux->priv;
138 
139 	if (mutex_lock_interruptible(&as102_dev->sem))
140 		return -ERESTARTSYS;
141 
142 	if (pid_filtering)
143 		as10x_pid_filter(as102_dev, dvbdmxfeed->index,
144 				 dvbdmxfeed->pid, 1);
145 
146 	if (as102_dev->streaming++ == 0)
147 		ret = as102_start_stream(as102_dev);
148 
149 	mutex_unlock(&as102_dev->sem);
150 	return ret;
151 }
152 
153 static int as102_dvb_dmx_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
154 {
155 	struct dvb_demux *demux = dvbdmxfeed->demux;
156 	struct as102_dev_t *as102_dev = demux->priv;
157 
158 	if (mutex_lock_interruptible(&as102_dev->sem))
159 		return -ERESTARTSYS;
160 
161 	if (--as102_dev->streaming == 0)
162 		as102_stop_stream(as102_dev);
163 
164 	if (pid_filtering)
165 		as10x_pid_filter(as102_dev, dvbdmxfeed->index,
166 				 dvbdmxfeed->pid, 0);
167 
168 	mutex_unlock(&as102_dev->sem);
169 	return 0;
170 }
171 
172 static int as102_set_tune(void *priv, struct as10x_tune_args *tune_args)
173 {
174 	struct as10x_bus_adapter_t *bus_adap = priv;
175 	int ret;
176 
177 	/* Set frontend arguments */
178 	if (mutex_lock_interruptible(&bus_adap->lock))
179 		return -EBUSY;
180 
181 	ret =  as10x_cmd_set_tune(bus_adap, tune_args);
182 	if (ret != 0)
183 		dev_dbg(&bus_adap->usb_dev->dev,
184 			"as10x_cmd_set_tune failed. (err = %d)\n", ret);
185 
186 	mutex_unlock(&bus_adap->lock);
187 
188 	return ret;
189 }
190 
191 static int as102_get_tps(void *priv, struct as10x_tps *tps)
192 {
193 	struct as10x_bus_adapter_t *bus_adap = priv;
194 	int ret;
195 
196 	if (mutex_lock_interruptible(&bus_adap->lock))
197 		return -EBUSY;
198 
199 	/* send abilis command: GET_TPS */
200 	ret = as10x_cmd_get_tps(bus_adap, tps);
201 
202 	mutex_unlock(&bus_adap->lock);
203 
204 	return ret;
205 }
206 
207 static int as102_get_status(void *priv, struct as10x_tune_status *tstate)
208 {
209 	struct as10x_bus_adapter_t *bus_adap = priv;
210 	int ret;
211 
212 	if (mutex_lock_interruptible(&bus_adap->lock))
213 		return -EBUSY;
214 
215 	/* send abilis command: GET_TUNE_STATUS */
216 	ret = as10x_cmd_get_tune_status(bus_adap, tstate);
217 	if (ret < 0) {
218 		dev_dbg(&bus_adap->usb_dev->dev,
219 			"as10x_cmd_get_tune_status failed (err = %d)\n",
220 			ret);
221 	}
222 
223 	mutex_unlock(&bus_adap->lock);
224 
225 	return ret;
226 }
227 
228 static int as102_get_stats(void *priv, struct as10x_demod_stats *demod_stats)
229 {
230 	struct as10x_bus_adapter_t *bus_adap = priv;
231 	int ret;
232 
233 	if (mutex_lock_interruptible(&bus_adap->lock))
234 		return -EBUSY;
235 
236 	/* send abilis command: GET_TUNE_STATUS */
237 	ret = as10x_cmd_get_demod_stats(bus_adap, demod_stats);
238 	if (ret < 0) {
239 		dev_dbg(&bus_adap->usb_dev->dev,
240 			"as10x_cmd_get_demod_stats failed (probably not tuned)\n");
241 	} else {
242 		dev_dbg(&bus_adap->usb_dev->dev,
243 			"demod status: fc: 0x%08x, bad fc: 0x%08x, bytes corrected: 0x%08x , MER: 0x%04x\n",
244 			demod_stats->frame_count,
245 			demod_stats->bad_frame_count,
246 			demod_stats->bytes_fixed_by_rs,
247 			demod_stats->mer);
248 	}
249 	mutex_unlock(&bus_adap->lock);
250 
251 	return ret;
252 }
253 
254 static int as102_stream_ctrl(void *priv, int acquire, uint32_t elna_cfg)
255 {
256 	struct as10x_bus_adapter_t *bus_adap = priv;
257 	int ret;
258 
259 	if (mutex_lock_interruptible(&bus_adap->lock))
260 		return -EBUSY;
261 
262 	if (acquire) {
263 		if (elna_enable)
264 			as10x_cmd_set_context(bus_adap,
265 					      CONTEXT_LNA, elna_cfg);
266 
267 		ret = as10x_cmd_turn_on(bus_adap);
268 	} else {
269 		ret = as10x_cmd_turn_off(bus_adap);
270 	}
271 
272 	mutex_unlock(&bus_adap->lock);
273 
274 	return ret;
275 }
276 
277 static const struct as102_fe_ops as102_fe_ops = {
278 	.set_tune = as102_set_tune,
279 	.get_tps  = as102_get_tps,
280 	.get_status = as102_get_status,
281 	.get_stats = as102_get_stats,
282 	.stream_ctrl = as102_stream_ctrl,
283 };
284 
285 int as102_dvb_register(struct as102_dev_t *as102_dev)
286 {
287 	struct device *dev = &as102_dev->bus_adap.usb_dev->dev;
288 	int ret;
289 
290 	ret = dvb_register_adapter(&as102_dev->dvb_adap,
291 			   as102_dev->name, THIS_MODULE,
292 			   dev, adapter_nr);
293 	if (ret < 0) {
294 		dev_err(dev, "%s: dvb_register_adapter() failed: %d\n",
295 			__func__, ret);
296 		return ret;
297 	}
298 
299 	as102_dev->dvb_dmx.priv = as102_dev;
300 	as102_dev->dvb_dmx.filternum = pid_filtering ? 16 : 256;
301 	as102_dev->dvb_dmx.feednum = 256;
302 	as102_dev->dvb_dmx.start_feed = as102_dvb_dmx_start_feed;
303 	as102_dev->dvb_dmx.stop_feed = as102_dvb_dmx_stop_feed;
304 
305 	as102_dev->dvb_dmx.dmx.capabilities = DMX_TS_FILTERING |
306 					      DMX_SECTION_FILTERING;
307 
308 	as102_dev->dvb_dmxdev.filternum = as102_dev->dvb_dmx.filternum;
309 	as102_dev->dvb_dmxdev.demux = &as102_dev->dvb_dmx.dmx;
310 	as102_dev->dvb_dmxdev.capabilities = 0;
311 
312 	ret = dvb_dmx_init(&as102_dev->dvb_dmx);
313 	if (ret < 0) {
314 		dev_err(dev, "%s: dvb_dmx_init() failed: %d\n", __func__, ret);
315 		goto edmxinit;
316 	}
317 
318 	ret = dvb_dmxdev_init(&as102_dev->dvb_dmxdev, &as102_dev->dvb_adap);
319 	if (ret < 0) {
320 		dev_err(dev, "%s: dvb_dmxdev_init() failed: %d\n",
321 			__func__, ret);
322 		goto edmxdinit;
323 	}
324 
325 	/* Attach the frontend */
326 	as102_dev->dvb_fe = dvb_attach(as102_attach, as102_dev->name,
327 				       &as102_fe_ops,
328 				       &as102_dev->bus_adap,
329 				       as102_dev->elna_cfg);
330 	if (!as102_dev->dvb_fe) {
331 		ret = -ENODEV;
332 		dev_err(dev, "%s: as102_attach() failed: %d",
333 		    __func__, ret);
334 		goto efereg;
335 	}
336 
337 	ret =  dvb_register_frontend(&as102_dev->dvb_adap, as102_dev->dvb_fe);
338 	if (ret < 0) {
339 		dev_err(dev, "%s: as102_dvb_register_frontend() failed: %d",
340 		    __func__, ret);
341 		goto efereg;
342 	}
343 
344 	/* init bus mutex for token locking */
345 	mutex_init(&as102_dev->bus_adap.lock);
346 
347 	/* init start / stop stream mutex */
348 	mutex_init(&as102_dev->sem);
349 
350 	/*
351 	 * try to load as102 firmware. If firmware upload failed, we'll be
352 	 * able to upload it later.
353 	 */
354 	if (fw_upload)
355 		try_then_request_module(as102_fw_upload(&as102_dev->bus_adap),
356 				"firmware_class");
357 
358 	pr_info("Registered device %s", as102_dev->name);
359 	return 0;
360 
361 efereg:
362 	dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
363 edmxdinit:
364 	dvb_dmx_release(&as102_dev->dvb_dmx);
365 edmxinit:
366 	dvb_unregister_adapter(&as102_dev->dvb_adap);
367 	return ret;
368 }
369 
370 void as102_dvb_unregister(struct as102_dev_t *as102_dev)
371 {
372 	/* unregister as102 frontend */
373 	dvb_unregister_frontend(as102_dev->dvb_fe);
374 
375 	/* detach frontend */
376 	dvb_frontend_detach(as102_dev->dvb_fe);
377 
378 	/* unregister demux device */
379 	dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
380 	dvb_dmx_release(&as102_dev->dvb_dmx);
381 
382 	/* unregister dvb adapter */
383 	dvb_unregister_adapter(&as102_dev->dvb_adap);
384 
385 	pr_info("Unregistered device %s", as102_dev->name);
386 }
387 
388 module_usb_driver(as102_usb_driver);
389 
390 /* modinfo details */
391 MODULE_DESCRIPTION(DRIVER_FULL_NAME);
392 MODULE_LICENSE("GPL");
393 MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
394