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