1 // SPDX-License-Identifier: GPL-2.0-only
3 * ngene-dvb.c: nGene PCIe bridge driver - DVB functions
5 * Copyright (C) 2005-2007 Micronas
7 * Copyright (C) 2008-2009 Ralph Metzler <rjkm@metzlerbros.de>
8 * Modifications for new nGene firmware,
9 * support for EEPROM-copying,
10 * support for new dual DVB-S2 card prototype
13 #include <linux/module.h>
14 #include <linux/init.h>
15 #include <linux/delay.h>
16 #include <linux/slab.h>
17 #include <linux/poll.h>
19 #include <asm/div64.h>
20 #include <linux/pci.h>
21 #include <linux/timer.h>
22 #include <linux/byteorder/generic.h>
23 #include <linux/firmware.h>
24 #include <linux/vmalloc.h>
28 static int ci_tsfix
= 1;
29 module_param(ci_tsfix
, int, 0444);
30 MODULE_PARM_DESC(ci_tsfix
, "Detect and fix TS buffer offset shifts in conjunction with CI expansions (default: 1/enabled)");
32 /****************************************************************************/
33 /* COMMAND API interface ****************************************************/
34 /****************************************************************************/
36 static ssize_t
ts_write(struct file
*file
, const char __user
*buf
,
37 size_t count
, loff_t
*ppos
)
39 struct dvb_device
*dvbdev
= file
->private_data
;
40 struct ngene_channel
*chan
= dvbdev
->priv
;
41 struct ngene
*dev
= chan
->dev
;
43 if (wait_event_interruptible(dev
->tsout_rbuf
.queue
,
45 (&dev
->tsout_rbuf
) >= count
) < 0)
48 dvb_ringbuffer_write_user(&dev
->tsout_rbuf
, buf
, count
);
53 static ssize_t
ts_read(struct file
*file
, char __user
*buf
,
54 size_t count
, loff_t
*ppos
)
56 struct dvb_device
*dvbdev
= file
->private_data
;
57 struct ngene_channel
*chan
= dvbdev
->priv
;
58 struct ngene
*dev
= chan
->dev
;
63 if (wait_event_interruptible(
65 dvb_ringbuffer_avail(&dev
->tsin_rbuf
) > 0) < 0)
67 avail
= dvb_ringbuffer_avail(&dev
->tsin_rbuf
);
70 dvb_ringbuffer_read_user(&dev
->tsin_rbuf
, buf
, avail
);
77 static __poll_t
ts_poll(struct file
*file
, poll_table
*wait
)
79 struct dvb_device
*dvbdev
= file
->private_data
;
80 struct ngene_channel
*chan
= dvbdev
->priv
;
81 struct ngene
*dev
= chan
->dev
;
82 struct dvb_ringbuffer
*rbuf
= &dev
->tsin_rbuf
;
83 struct dvb_ringbuffer
*wbuf
= &dev
->tsout_rbuf
;
86 poll_wait(file
, &rbuf
->queue
, wait
);
87 poll_wait(file
, &wbuf
->queue
, wait
);
89 if (!dvb_ringbuffer_empty(rbuf
))
90 mask
|= EPOLLIN
| EPOLLRDNORM
;
91 if (dvb_ringbuffer_free(wbuf
) >= 188)
92 mask
|= EPOLLOUT
| EPOLLWRNORM
;
97 static const struct file_operations ci_fops
= {
101 .open
= dvb_generic_open
,
102 .release
= dvb_generic_release
,
107 struct dvb_device ngene_dvbdev_ci
= {
116 /****************************************************************************/
117 /* DVB functions and API interface ******************************************/
118 /****************************************************************************/
120 static void swap_buffer(u32
*p
, u32 len
)
129 /* start of filler packet */
130 static u8 fill_ts
[] = { 0x47, 0x1f, 0xff, 0x10, TS_FILLER
};
132 static int tsin_find_offset(void *buf
, u32 len
)
136 l
= len
- sizeof(fill_ts
);
140 for (i
= 0; i
< l
; i
++) {
141 if (((char *)buf
)[i
] == 0x47) {
142 if (!memcmp(buf
+ i
, fill_ts
, sizeof(fill_ts
)))
150 static inline void tsin_copy_stripped(struct ngene
*dev
, void *buf
)
152 if (memcmp(buf
, fill_ts
, sizeof(fill_ts
)) != 0) {
153 if (dvb_ringbuffer_free(&dev
->tsin_rbuf
) >= 188) {
154 dvb_ringbuffer_write(&dev
->tsin_rbuf
, buf
, 188);
155 wake_up(&dev
->tsin_rbuf
.queue
);
160 void *tsin_exchange(void *priv
, void *buf
, u32 len
, u32 clock
, u32 flags
)
162 struct ngene_channel
*chan
= priv
;
163 struct ngene
*dev
= chan
->dev
;
166 if (flags
& DF_SWAP32
)
167 swap_buffer(buf
, len
);
169 if (dev
->ci
.en
&& chan
->number
== 2) {
170 /* blindly copy buffers if ci_tsfix is disabled */
173 tsin_copy_stripped(dev
, buf
);
184 * since the remainder of the TS packet which got cut off
185 * in the previous tsin_exchange() run is at the beginning
186 * of the new TS buffer, append this to the temp buffer and
187 * send it to the DVB ringbuffer afterwards.
189 if (chan
->tsin_offset
) {
190 memcpy(&chan
->tsin_buffer
[(188 - chan
->tsin_offset
)],
191 buf
, chan
->tsin_offset
);
192 tsin_copy_stripped(dev
, &chan
->tsin_buffer
);
194 buf
+= chan
->tsin_offset
;
195 len
-= chan
->tsin_offset
;
199 * copy TS packets to the DVB ringbuffer and detect new offset
200 * shifts by checking for a valid TS SYNC byte
203 if (*((char *)buf
) != 0x47) {
205 * no SYNC header, find new offset shift
206 * (max. 188 bytes, tsoff will be mod 188)
208 tsoff
= tsin_find_offset(buf
, len
);
210 chan
->tsin_offset
+= tsoff
;
211 chan
->tsin_offset
%= 188;
216 dev_info(&dev
->pci_dev
->dev
,
217 "%s(): tsin_offset shift by %d on channel %d\n",
222 * offset corrected. re-check remaining
223 * len for a full TS frame, break and
224 * skip to fragment handling if < 188.
231 tsin_copy_stripped(dev
, buf
);
238 * if a fragment is left, copy to temp buffer. The remainder
239 * will be appended in the next tsin_exchange() iteration.
241 if (len
> 0 && len
< 188)
242 memcpy(&chan
->tsin_buffer
, buf
, len
);
248 dvb_dmx_swfilter(&chan
->demux
, buf
, len
);
253 void *tsout_exchange(void *priv
, void *buf
, u32 len
, u32 clock
, u32 flags
)
255 struct ngene_channel
*chan
= priv
;
256 struct ngene
*dev
= chan
->dev
;
259 alen
= dvb_ringbuffer_avail(&dev
->tsout_rbuf
);
263 FillTSBuffer(buf
+ alen
, len
- alen
, flags
);
266 dvb_ringbuffer_read(&dev
->tsout_rbuf
, buf
, alen
);
267 if (flags
& DF_SWAP32
)
268 swap_buffer((u32
*)buf
, alen
);
269 wake_up_interruptible(&dev
->tsout_rbuf
.queue
);
275 int ngene_start_feed(struct dvb_demux_feed
*dvbdmxfeed
)
277 struct dvb_demux
*dvbdmx
= dvbdmxfeed
->demux
;
278 struct ngene_channel
*chan
= dvbdmx
->priv
;
280 if (chan
->users
== 0) {
281 if (!chan
->dev
->cmd_timeout_workaround
|| !chan
->running
)
282 set_transfer(chan
, 1);
285 return ++chan
->users
;
288 int ngene_stop_feed(struct dvb_demux_feed
*dvbdmxfeed
)
290 struct dvb_demux
*dvbdmx
= dvbdmxfeed
->demux
;
291 struct ngene_channel
*chan
= dvbdmx
->priv
;
296 if (!chan
->dev
->cmd_timeout_workaround
)
297 set_transfer(chan
, 0);
302 int my_dvb_dmx_ts_card_init(struct dvb_demux
*dvbdemux
, char *id
,
303 int (*start_feed
)(struct dvb_demux_feed
*),
304 int (*stop_feed
)(struct dvb_demux_feed
*),
307 dvbdemux
->priv
= priv
;
309 dvbdemux
->filternum
= 256;
310 dvbdemux
->feednum
= 256;
311 dvbdemux
->start_feed
= start_feed
;
312 dvbdemux
->stop_feed
= stop_feed
;
313 dvbdemux
->write_to_decoder
= NULL
;
314 dvbdemux
->dmx
.capabilities
= (DMX_TS_FILTERING
|
315 DMX_SECTION_FILTERING
|
316 DMX_MEMORY_BASED_FILTERING
);
317 return dvb_dmx_init(dvbdemux
);
320 int my_dvb_dmxdev_ts_card_init(struct dmxdev
*dmxdev
,
321 struct dvb_demux
*dvbdemux
,
322 struct dmx_frontend
*hw_frontend
,
323 struct dmx_frontend
*mem_frontend
,
324 struct dvb_adapter
*dvb_adapter
)
328 dmxdev
->filternum
= 256;
329 dmxdev
->demux
= &dvbdemux
->dmx
;
330 dmxdev
->capabilities
= 0;
331 ret
= dvb_dmxdev_init(dmxdev
, dvb_adapter
);
335 hw_frontend
->source
= DMX_FRONTEND_0
;
336 dvbdemux
->dmx
.add_frontend(&dvbdemux
->dmx
, hw_frontend
);
337 mem_frontend
->source
= DMX_MEMORY_FE
;
338 dvbdemux
->dmx
.add_frontend(&dvbdemux
->dmx
, mem_frontend
);
339 return dvbdemux
->dmx
.connect_frontend(&dvbdemux
->dmx
, hw_frontend
);