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
23int dual_tuner;
24module_param_named(dual_tuner, dual_tuner, int, 0644);
25MODULE_PARM_DESC(dual_tuner, "Activate Dual-Tuner config (default: off)");
26
27static int fw_upload = 1;
28module_param_named(fw_upload, fw_upload, int, 0644);
29MODULE_PARM_DESC(fw_upload, "Turn on/off default FW upload (default: on)");
30
31static int pid_filtering;
32module_param_named(pid_filtering, pid_filtering, int, 0644);
33MODULE_PARM_DESC(pid_filtering, "Activate HW PID filtering (default: off)");
34
35static int ts_auto_disable;
36module_param_named(ts_auto_disable, ts_auto_disable, int, 0644);
37MODULE_PARM_DESC(ts_auto_disable, "Stream Auto Enable on FW (default: off)");
38
39int elna_enable = 1;
40module_param_named(elna_enable, elna_enable, int, 0644);
41MODULE_PARM_DESC(elna_enable, "Activate eLNA (default: on)");
42
43DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
44
45static 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
69static 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
94static 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
133static 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
153static 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
172static 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
191static 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
207static 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
228static 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
254static 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
277static 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
285int 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
361efereg:
362	dvb_dmxdev_release(&as102_dev->dvb_dmxdev);
363edmxdinit:
364	dvb_dmx_release(&as102_dev->dvb_dmx);
365edmxinit:
366	dvb_unregister_adapter(&as102_dev->dvb_adap);
367	return ret;
368}
369
370void 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
388module_usb_driver(as102_usb_driver);
389
390/* modinfo details */
391MODULE_DESCRIPTION(DRIVER_FULL_NAME);
392MODULE_LICENSE("GPL");
393MODULE_AUTHOR("Pierrick Hascoet <pierrick.hascoet@abilis.com>");
394