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