GNU Linux-libre 4.19.264-gnu1
[releases.git] / drivers / media / pci / ngene / ngene-dvb.c
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 static int ci_tsfix = 1;
42 module_param(ci_tsfix, int, 0444);
43 MODULE_PARM_DESC(ci_tsfix, "Detect and fix TS buffer offset shifts in conjunction with CI expansions (default: 1/enabled)");
44
45 /****************************************************************************/
46 /* COMMAND API interface ****************************************************/
47 /****************************************************************************/
48
49 static ssize_t ts_write(struct file *file, const char __user *buf,
50                         size_t count, loff_t *ppos)
51 {
52         struct dvb_device *dvbdev = file->private_data;
53         struct ngene_channel *chan = dvbdev->priv;
54         struct ngene *dev = chan->dev;
55
56         if (wait_event_interruptible(dev->tsout_rbuf.queue,
57                                      dvb_ringbuffer_free
58                                      (&dev->tsout_rbuf) >= count) < 0)
59                 return 0;
60
61         dvb_ringbuffer_write_user(&dev->tsout_rbuf, buf, count);
62
63         return count;
64 }
65
66 static ssize_t ts_read(struct file *file, char __user *buf,
67                        size_t count, loff_t *ppos)
68 {
69         struct dvb_device *dvbdev = file->private_data;
70         struct ngene_channel *chan = dvbdev->priv;
71         struct ngene *dev = chan->dev;
72         int left, avail;
73
74         left = count;
75         while (left) {
76                 if (wait_event_interruptible(
77                             dev->tsin_rbuf.queue,
78                             dvb_ringbuffer_avail(&dev->tsin_rbuf) > 0) < 0)
79                         return -EAGAIN;
80                 avail = dvb_ringbuffer_avail(&dev->tsin_rbuf);
81                 if (avail > left)
82                         avail = left;
83                 dvb_ringbuffer_read_user(&dev->tsin_rbuf, buf, avail);
84                 left -= avail;
85                 buf += avail;
86         }
87         return count;
88 }
89
90 static __poll_t ts_poll(struct file *file, poll_table *wait)
91 {
92         struct dvb_device *dvbdev = file->private_data;
93         struct ngene_channel *chan = dvbdev->priv;
94         struct ngene *dev = chan->dev;
95         struct dvb_ringbuffer *rbuf = &dev->tsin_rbuf;
96         struct dvb_ringbuffer *wbuf = &dev->tsout_rbuf;
97         __poll_t mask = 0;
98
99         poll_wait(file, &rbuf->queue, wait);
100         poll_wait(file, &wbuf->queue, wait);
101
102         if (!dvb_ringbuffer_empty(rbuf))
103                 mask |= EPOLLIN | EPOLLRDNORM;
104         if (dvb_ringbuffer_free(wbuf) >= 188)
105                 mask |= EPOLLOUT | EPOLLWRNORM;
106
107         return mask;
108 }
109
110 static const struct file_operations ci_fops = {
111         .owner   = THIS_MODULE,
112         .read    = ts_read,
113         .write   = ts_write,
114         .open    = dvb_generic_open,
115         .release = dvb_generic_release,
116         .poll    = ts_poll,
117         .mmap    = NULL,
118 };
119
120 struct dvb_device ngene_dvbdev_ci = {
121         .priv    = NULL,
122         .readers = 1,
123         .writers = 1,
124         .users   = 2,
125         .fops    = &ci_fops,
126 };
127
128
129 /****************************************************************************/
130 /* DVB functions and API interface ******************************************/
131 /****************************************************************************/
132
133 static void swap_buffer(u32 *p, u32 len)
134 {
135         while (len) {
136                 *p = swab32(*p);
137                 p++;
138                 len -= 4;
139         }
140 }
141
142 /* start of filler packet */
143 static u8 fill_ts[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER };
144
145 static int tsin_find_offset(void *buf, u32 len)
146 {
147         int i, l;
148
149         l = len - sizeof(fill_ts);
150         if (l <= 0)
151                 return -1;
152
153         for (i = 0; i < l; i++) {
154                 if (((char *)buf)[i] == 0x47) {
155                         if (!memcmp(buf + i, fill_ts, sizeof(fill_ts)))
156                                 return i % 188;
157                 }
158         }
159
160         return -1;
161 }
162
163 static inline void tsin_copy_stripped(struct ngene *dev, void *buf)
164 {
165         if (memcmp(buf, fill_ts, sizeof(fill_ts)) != 0) {
166                 if (dvb_ringbuffer_free(&dev->tsin_rbuf) >= 188) {
167                         dvb_ringbuffer_write(&dev->tsin_rbuf, buf, 188);
168                         wake_up(&dev->tsin_rbuf.queue);
169                 }
170         }
171 }
172
173 void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
174 {
175         struct ngene_channel *chan = priv;
176         struct ngene *dev = chan->dev;
177         int tsoff;
178
179         if (flags & DF_SWAP32)
180                 swap_buffer(buf, len);
181
182         if (dev->ci.en && chan->number == 2) {
183                 /* blindly copy buffers if ci_tsfix is disabled */
184                 if (!ci_tsfix) {
185                         while (len >= 188) {
186                                 tsin_copy_stripped(dev, buf);
187
188                                 buf += 188;
189                                 len -= 188;
190                         }
191                         return NULL;
192                 }
193
194                 /* ci_tsfix = 1 */
195
196                 /*
197                  * since the remainder of the TS packet which got cut off
198                  * in the previous tsin_exchange() run is at the beginning
199                  * of the new TS buffer, append this to the temp buffer and
200                  * send it to the DVB ringbuffer afterwards.
201                  */
202                 if (chan->tsin_offset) {
203                         memcpy(&chan->tsin_buffer[(188 - chan->tsin_offset)],
204                                buf, chan->tsin_offset);
205                         tsin_copy_stripped(dev, &chan->tsin_buffer);
206
207                         buf += chan->tsin_offset;
208                         len -= chan->tsin_offset;
209                 }
210
211                 /*
212                  * copy TS packets to the DVB ringbuffer and detect new offset
213                  * shifts by checking for a valid TS SYNC byte
214                  */
215                 while (len >= 188) {
216                         if (*((char *)buf) != 0x47) {
217                                 /*
218                                  * no SYNC header, find new offset shift
219                                  * (max. 188 bytes, tsoff will be mod 188)
220                                  */
221                                 tsoff = tsin_find_offset(buf, len);
222                                 if (tsoff > 0) {
223                                         chan->tsin_offset += tsoff;
224                                         chan->tsin_offset %= 188;
225
226                                         buf += tsoff;
227                                         len -= tsoff;
228
229                                         dev_info(&dev->pci_dev->dev,
230                                                  "%s(): tsin_offset shift by %d on channel %d\n",
231                                                  __func__, tsoff,
232                                                  chan->number);
233
234                                         /*
235                                          * offset corrected. re-check remaining
236                                          * len for a full TS frame, break and
237                                          * skip to fragment handling if < 188.
238                                          */
239                                         if (len < 188)
240                                                 break;
241                                 }
242                         }
243
244                         tsin_copy_stripped(dev, buf);
245
246                         buf += 188;
247                         len -= 188;
248                 }
249
250                 /*
251                  * if a fragment is left, copy to temp buffer. The remainder
252                  * will be appended in the next tsin_exchange() iteration.
253                  */
254                 if (len > 0 && len < 188)
255                         memcpy(&chan->tsin_buffer, buf, len);
256
257                 return NULL;
258         }
259
260         if (chan->users > 0)
261                 dvb_dmx_swfilter(&chan->demux, buf, len);
262
263         return NULL;
264 }
265
266 void *tsout_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
267 {
268         struct ngene_channel *chan = priv;
269         struct ngene *dev = chan->dev;
270         u32 alen;
271
272         alen = dvb_ringbuffer_avail(&dev->tsout_rbuf);
273         alen -= alen % 188;
274
275         if (alen < len)
276                 FillTSBuffer(buf + alen, len - alen, flags);
277         else
278                 alen = len;
279         dvb_ringbuffer_read(&dev->tsout_rbuf, buf, alen);
280         if (flags & DF_SWAP32)
281                 swap_buffer((u32 *)buf, alen);
282         wake_up_interruptible(&dev->tsout_rbuf.queue);
283         return buf;
284 }
285
286
287
288 int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
289 {
290         struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
291         struct ngene_channel *chan = dvbdmx->priv;
292
293         if (chan->users == 0) {
294                 if (!chan->dev->cmd_timeout_workaround || !chan->running)
295                         set_transfer(chan, 1);
296         }
297
298         return ++chan->users;
299 }
300
301 int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
302 {
303         struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
304         struct ngene_channel *chan = dvbdmx->priv;
305
306         if (--chan->users)
307                 return chan->users;
308
309         if (!chan->dev->cmd_timeout_workaround)
310                 set_transfer(chan, 0);
311
312         return 0;
313 }
314
315 int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
316                             int (*start_feed)(struct dvb_demux_feed *),
317                             int (*stop_feed)(struct dvb_demux_feed *),
318                             void *priv)
319 {
320         dvbdemux->priv = priv;
321
322         dvbdemux->filternum = 256;
323         dvbdemux->feednum = 256;
324         dvbdemux->start_feed = start_feed;
325         dvbdemux->stop_feed = stop_feed;
326         dvbdemux->write_to_decoder = NULL;
327         dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
328                                       DMX_SECTION_FILTERING |
329                                       DMX_MEMORY_BASED_FILTERING);
330         return dvb_dmx_init(dvbdemux);
331 }
332
333 int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
334                                struct dvb_demux *dvbdemux,
335                                struct dmx_frontend *hw_frontend,
336                                struct dmx_frontend *mem_frontend,
337                                struct dvb_adapter *dvb_adapter)
338 {
339         int ret;
340
341         dmxdev->filternum = 256;
342         dmxdev->demux = &dvbdemux->dmx;
343         dmxdev->capabilities = 0;
344         ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
345         if (ret < 0)
346                 return ret;
347
348         hw_frontend->source = DMX_FRONTEND_0;
349         dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
350         mem_frontend->source = DMX_MEMORY_FE;
351         dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
352         return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
353 }