xref: /linux/drivers/media/pci/ngene/ngene-dvb.c (revision e58e871becec2d3b04ed91c0c16fe8deac9c9dfa)
1 /*
2  * ngene-dvb.c: nGene PCIe bridge driver - DVB functions
3  *
4  * Copyright (C) 2005-2007 Micronas
5  *
6  * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
7  *                         Modifications for new nGene firmware,
8  *                         support for EEPROM-copying,
9  *                         support for new dual DVB-S2 card prototype
10  *
11  *
12  * This program is free software; you can redistribute it and/or
13  * modify it under the terms of the GNU General Public License
14  * version 2 only, as published by the Free Software Foundation.
15  *
16  *
17  * This program is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * To obtain the license, point your browser to
23  * http://www.gnu.org/copyleft/gpl.html
24  */
25 
26 #include <linux/module.h>
27 #include <linux/init.h>
28 #include <linux/delay.h>
29 #include <linux/slab.h>
30 #include <linux/poll.h>
31 #include <linux/io.h>
32 #include <asm/div64.h>
33 #include <linux/pci.h>
34 #include <linux/timer.h>
35 #include <linux/byteorder/generic.h>
36 #include <linux/firmware.h>
37 #include <linux/vmalloc.h>
38 
39 #include "ngene.h"
40 
41 
42 /****************************************************************************/
43 /* COMMAND API interface ****************************************************/
44 /****************************************************************************/
45 
46 static ssize_t ts_write(struct file *file, const char __user *buf,
47 			size_t count, loff_t *ppos)
48 {
49 	struct dvb_device *dvbdev = file->private_data;
50 	struct ngene_channel *chan = dvbdev->priv;
51 	struct ngene *dev = chan->dev;
52 
53 	if (wait_event_interruptible(dev->tsout_rbuf.queue,
54 				     dvb_ringbuffer_free
55 				     (&dev->tsout_rbuf) >= count) < 0)
56 		return 0;
57 
58 	dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count);
59 
60 	return count;
61 }
62 
63 static ssize_t ts_read(struct file *file, char __user *buf,
64 		       size_t count, loff_t *ppos)
65 {
66 	struct dvb_device *dvbdev = file->private_data;
67 	struct ngene_channel *chan = dvbdev->priv;
68 	struct ngene *dev = chan->dev;
69 	int left, avail;
70 
71 	left = count;
72 	while (left) {
73 		if (wait_event_interruptible(
74 			    dev->tsin_rbuf.queue,
75 			    dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0)
76 			return -EAGAIN;
77 		avail = dvb_ringbuffer_avail(&dev->tsin_rbuf);
78 		if (avail > left)
79 			avail = left;
80 		dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail);
81 		left -= avail;
82 		buf += avail;
83 	}
84 	return count;
85 }
86 
87 static const struct file_operations ci_fops = {
88 	.owner   = THIS_MODULE,
89 	.read    = ts_read,
90 	.write   = ts_write,
91 	.open    = dvb_generic_open,
92 	.release = dvb_generic_release,
93 };
94 
95 struct dvb_device ngene_dvbdev_ci = {
96 	.readers = -1,
97 	.writers = -1,
98 	.users   = -1,
99 	.fops    = &ci_fops,
100 };
101 
102 
103 /****************************************************************************/
104 /* DVB functions and API interface ******************************************/
105 /****************************************************************************/
106 
107 static void swap_buffer(u32 *p, u32 len)
108 {
109 	while (len) {
110 		*p = swab32(*p);
111 		p++;
112 		len -= 4;
113 	}
114 }
115 
116 /* start of filler packet */
117 static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
118 
119 /* #define DEBUG_CI_XFER */
120 #ifdef DEBUG_CI_XFER
121 static u32 ok;
122 static u32 overflow;
123 static u32 stripped;
124 #endif
125 
126 void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
127 {
128 	struct ngene_channel *chan = priv;
129 	struct ngene *dev = chan->dev;
130 
131 
132 	if (flags & DF_SWAP32)
133 		swap_buffer(buf, len);
134 
135 	if (dev->ci.en && chan->number == 2) {
136 		while (len >= 188) {
137 			if (memcmp(buf, fill_ts, sizeof fill_ts) != 0) {
138 				if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) {
139 					dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188);
140 					wake_up(&dev->tsin_rbuf.queue);
141 #ifdef DEBUG_CI_XFER
142 					ok++;
143 #endif
144 				}
145 #ifdef DEBUG_CI_XFER
146 				else
147 					overflow++;
148 #endif
149 			}
150 #ifdef DEBUG_CI_XFER
151 			else
152 				stripped++;
153 
154 			if (ok % 100 == 0 && overflow)
155 				printk(KERN_WARNING "%s: ok %u overflow %u dropped %u\n", __func__, ok, overflow, stripped);
156 #endif
157 			buf += 188;
158 			len -= 188;
159 		}
160 		return NULL;
161 	}
162 
163 	if (chan->users > 0)
164 		dvb_dmx_swfilter(&chan->demux, buf, len);
165 
166 	return NULL;
167 }
168 
169 void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
170 {
171 	struct ngene_channel *chan = priv;
172 	struct ngene *dev = chan->dev;
173 	u32 alen;
174 
175 	alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);
176 	alen -= alen % 188;
177 
178 	if (alen < len)
179 		FillTSBuffer(buf + alen, len - alen, flags);
180 	else
181 		alen = len;
182 	dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);
183 	if (flags & DF_SWAP32)
184 		swap_buffer((u32 *)buf, alen);
185 	wake_up_interruptible(&dev->tsout_rbuf.queue);
186 	return buf;
187 }
188 
189 
190 
191 int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
192 {
193 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
194 	struct ngene_channel *chan = dvbdmx->priv;
195 
196 	if (chan->users == 0) {
197 		if (!chan->dev->cmd_timeout_workaround || !chan->running)
198 			set_transfer(chan, 1);
199 	}
200 
201 	return ++chan->users;
202 }
203 
204 int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
205 {
206 	struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
207 	struct ngene_channel *chan = dvbdmx->priv;
208 
209 	if (--chan->users)
210 		return chan->users;
211 
212 	if (!chan->dev->cmd_timeout_workaround)
213 		set_transfer(chan, 0);
214 
215 	return 0;
216 }
217 
218 int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
219 			    int (*start_feed)(struct dvb_demux_feed *),
220 			    int (*stop_feed)(struct dvb_demux_feed *),
221 			    void *priv)
222 {
223 	dvbdemux->priv = priv;
224 
225 	dvbdemux->filternum = 256;
226 	dvbdemux->feednum = 256;
227 	dvbdemux->start_feed = start_feed;
228 	dvbdemux->stop_feed = stop_feed;
229 	dvbdemux->write_to_decoder = NULL;
230 	dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
231 				      DMX_SECTION_FILTERING |
232 				      DMX_MEMORY_BASED_FILTERING);
233 	return dvb_dmx_init(dvbdemux);
234 }
235 
236 int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
237 			       struct dvb_demux *dvbdemux,
238 			       struct dmx_frontend *hw_frontend,
239 			       struct dmx_frontend *mem_frontend,
240 			       struct dvb_adapter *dvb_adapter)
241 {
242 	int ret;
243 
244 	dmxdev->filternum = 256;
245 	dmxdev->demux = &dvbdemux->dmx;
246 	dmxdev->capabilities = 0;
247 	ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
248 	if (ret < 0)
249 		return ret;
250 
251 	hw_frontend->source = DMX_FRONTEND_0;
252 	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
253 	mem_frontend->source = DMX_MEMORY_FE;
254 	dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
255 	return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
256 }
257