xref: /netbsd-src/sys/dev/dtv/dtv_demux.c (revision e7cfc031b76a88e8db60402ec09155a3c9629c2b)
1*e7cfc031Sjdolecek /* $NetBSD: dtv_demux.c,v 1.11 2020/05/30 13:15:10 jdolecek Exp $ */
2d3ea21c0Sjmcneill 
3d3ea21c0Sjmcneill /*-
4d3ea21c0Sjmcneill  * Copyright (c) 2011 Jared D. McNeill <jmcneill@invisible.ca>
5d3ea21c0Sjmcneill  * All rights reserved.
6d3ea21c0Sjmcneill  *
7d3ea21c0Sjmcneill  * Redistribution and use in source and binary forms, with or without
8d3ea21c0Sjmcneill  * modification, are permitted provided that the following conditions
9d3ea21c0Sjmcneill  * are met:
10d3ea21c0Sjmcneill  * 1. Redistributions of source code must retain the above copyright
11d3ea21c0Sjmcneill  *    notice, this list of conditions and the following disclaimer.
12d3ea21c0Sjmcneill  * 2. Redistributions in binary form must reproduce the above copyright
13d3ea21c0Sjmcneill  *    notice, this list of conditions and the following disclaimer in the
14d3ea21c0Sjmcneill  *    documentation and/or other materials provided with the distribution.
15d3ea21c0Sjmcneill  * 3. All advertising materials mentioning features or use of this software
16d3ea21c0Sjmcneill  *    must display the following acknowledgement:
17d3ea21c0Sjmcneill  *        This product includes software developed by Jared D. McNeill.
18d3ea21c0Sjmcneill  * 4. Neither the name of The NetBSD Foundation nor the names of its
19d3ea21c0Sjmcneill  *    contributors may be used to endorse or promote products derived
20d3ea21c0Sjmcneill  *    from this software without specific prior written permission.
21d3ea21c0Sjmcneill  *
22d3ea21c0Sjmcneill  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23d3ea21c0Sjmcneill  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24d3ea21c0Sjmcneill  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25d3ea21c0Sjmcneill  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26d3ea21c0Sjmcneill  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27d3ea21c0Sjmcneill  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28d3ea21c0Sjmcneill  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29d3ea21c0Sjmcneill  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30d3ea21c0Sjmcneill  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31d3ea21c0Sjmcneill  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32d3ea21c0Sjmcneill  * POSSIBILITY OF SUCH DAMAGE.
33d3ea21c0Sjmcneill  */
34d3ea21c0Sjmcneill 
35e1214af8Sjmcneill /*
36e1214af8Sjmcneill  * This file contains support for the /dev/dvb/adapter<n>/demux0 device.
37e1214af8Sjmcneill  *
38e1214af8Sjmcneill  * The demux device is implemented as a cloning device. Each instance can
39e1214af8Sjmcneill  * be in one of three modes: unconfigured (NONE), section filter (SECTION),
40e1214af8Sjmcneill  * or PID filter (PES).
41e1214af8Sjmcneill  *
42e1214af8Sjmcneill  * An instance in section filter mode extracts PSI sections based on a
43e1214af8Sjmcneill  * filter configured by the DMX_SET_FILTER ioctl. When an entire section is
44e1214af8Sjmcneill  * received, it is made available to userspace via read method. Data is fed
45e1214af8Sjmcneill  * into the section filter using the dtv_demux_write function.
46e1214af8Sjmcneill  *
47e1214af8Sjmcneill  * An instance in PID filter mode extracts TS packets that match the
48e1214af8Sjmcneill  * specified PID filter configured by the DMX_SET_PES_FILTER, DMX_ADD_PID,
49e1214af8Sjmcneill  * and DMX_REMOVE_PID ioctls. As this driver only implements the
50e1214af8Sjmcneill  * DMX_OUT_TS_TAP output, these TS packets are made available to userspace
51e1214af8Sjmcneill  * by calling read on the /dev/dvb/adapter<n>/dvr0 device.
52e1214af8Sjmcneill  */
53e1214af8Sjmcneill 
54d3ea21c0Sjmcneill #include <sys/cdefs.h>
55*e7cfc031Sjdolecek __KERNEL_RCSID(0, "$NetBSD: dtv_demux.c,v 1.11 2020/05/30 13:15:10 jdolecek Exp $");
56d3ea21c0Sjmcneill 
57d3ea21c0Sjmcneill #include <sys/param.h>
58d3ea21c0Sjmcneill #include <sys/types.h>
59d3ea21c0Sjmcneill #include <sys/conf.h>
60d3ea21c0Sjmcneill #include <sys/kmem.h>
61d3ea21c0Sjmcneill #include <sys/device.h>
62d3ea21c0Sjmcneill #include <sys/select.h>
63d3ea21c0Sjmcneill #include <sys/filedesc.h>
64d3ea21c0Sjmcneill #include <sys/file.h>
65d3ea21c0Sjmcneill #include <sys/poll.h>
66d3ea21c0Sjmcneill #include <sys/vnode.h>
67d3ea21c0Sjmcneill #include <sys/queue.h>
68d3ea21c0Sjmcneill 
69d3ea21c0Sjmcneill #include <dev/dtv/dtvvar.h>
70d3ea21c0Sjmcneill 
71d3ea21c0Sjmcneill static int	dtv_demux_read(struct file *, off_t *, struct uio *,
72d3ea21c0Sjmcneill 		    kauth_cred_t, int);
73d3ea21c0Sjmcneill static int	dtv_demux_ioctl(struct file *, u_long, void *);
74d3ea21c0Sjmcneill static int	dtv_demux_poll(struct file *, int);
75d3ea21c0Sjmcneill static int	dtv_demux_close(struct file *);
76d3ea21c0Sjmcneill 
77d3ea21c0Sjmcneill static const struct fileops dtv_demux_fileops = {
78ea05286dSchristos 	.fo_name = "dtv_demux",
79d3ea21c0Sjmcneill 	.fo_read = dtv_demux_read,
80d3ea21c0Sjmcneill 	.fo_write = fbadop_write,
81d3ea21c0Sjmcneill 	.fo_ioctl = dtv_demux_ioctl,
82d3ea21c0Sjmcneill 	.fo_fcntl = fnullop_fcntl,
83d3ea21c0Sjmcneill 	.fo_poll = dtv_demux_poll,
84d3ea21c0Sjmcneill 	.fo_stat = fbadop_stat,
85d3ea21c0Sjmcneill 	.fo_close = dtv_demux_close,
86d3ea21c0Sjmcneill 	.fo_kqfilter = fnullop_kqfilter,
87d3ea21c0Sjmcneill 	.fo_restart = fnullop_restart,
88d3ea21c0Sjmcneill };
89d3ea21c0Sjmcneill 
90d3ea21c0Sjmcneill static uint32_t crc_table[256] = {
91d3ea21c0Sjmcneill 	0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
92d3ea21c0Sjmcneill 	0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
93d3ea21c0Sjmcneill 	0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
94d3ea21c0Sjmcneill 	0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
95d3ea21c0Sjmcneill 	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
96d3ea21c0Sjmcneill 	0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
97d3ea21c0Sjmcneill 	0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
98d3ea21c0Sjmcneill 	0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
99d3ea21c0Sjmcneill 	0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
100d3ea21c0Sjmcneill 	0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
101d3ea21c0Sjmcneill 	0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
102d3ea21c0Sjmcneill 	0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
103d3ea21c0Sjmcneill 	0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
104d3ea21c0Sjmcneill 	0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
105d3ea21c0Sjmcneill 	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
106d3ea21c0Sjmcneill 	0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
107d3ea21c0Sjmcneill 	0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
108d3ea21c0Sjmcneill 	0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
109d3ea21c0Sjmcneill 	0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
110d3ea21c0Sjmcneill 	0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
111d3ea21c0Sjmcneill 	0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
112d3ea21c0Sjmcneill 	0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
113d3ea21c0Sjmcneill 	0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
114d3ea21c0Sjmcneill 	0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
115d3ea21c0Sjmcneill 	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
116d3ea21c0Sjmcneill 	0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
117d3ea21c0Sjmcneill 	0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
118d3ea21c0Sjmcneill 	0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
119d3ea21c0Sjmcneill 	0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
120d3ea21c0Sjmcneill 	0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
121d3ea21c0Sjmcneill 	0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
122d3ea21c0Sjmcneill 	0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
123d3ea21c0Sjmcneill 	0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
124d3ea21c0Sjmcneill 	0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
125d3ea21c0Sjmcneill 	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
126d3ea21c0Sjmcneill 	0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
127d3ea21c0Sjmcneill 	0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
128d3ea21c0Sjmcneill 	0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
129d3ea21c0Sjmcneill 	0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
130d3ea21c0Sjmcneill 	0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
131d3ea21c0Sjmcneill 	0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
132d3ea21c0Sjmcneill 	0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
133d3ea21c0Sjmcneill 	0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
134d3ea21c0Sjmcneill 	0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
135d3ea21c0Sjmcneill 	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
136d3ea21c0Sjmcneill 	0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
137d3ea21c0Sjmcneill 	0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
138d3ea21c0Sjmcneill 	0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
139d3ea21c0Sjmcneill 	0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
140d3ea21c0Sjmcneill 	0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
141d3ea21c0Sjmcneill 	0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
142d3ea21c0Sjmcneill 	0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
143d3ea21c0Sjmcneill 	0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
144d3ea21c0Sjmcneill 	0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
145d3ea21c0Sjmcneill 	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
146d3ea21c0Sjmcneill 	0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
147d3ea21c0Sjmcneill 	0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
148d3ea21c0Sjmcneill 	0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
149d3ea21c0Sjmcneill 	0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
150d3ea21c0Sjmcneill 	0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
151d3ea21c0Sjmcneill 	0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
152d3ea21c0Sjmcneill 	0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
153d3ea21c0Sjmcneill 	0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
154d3ea21c0Sjmcneill 	0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
155d3ea21c0Sjmcneill };
156d3ea21c0Sjmcneill 
157e1214af8Sjmcneill /* ISO/IEC 13818-1 Annex A "CRC Decoder Model" */
158d3ea21c0Sjmcneill static uint32_t
dtv_demux_crc32(uint8_t * buf,int len)159d3ea21c0Sjmcneill dtv_demux_crc32(uint8_t *buf, int len)
160d3ea21c0Sjmcneill {
161d3ea21c0Sjmcneill 	const uint32_t *crc_tab = crc_table;
162d3ea21c0Sjmcneill 	uint32_t CRC = 0xffffffff;
163d3ea21c0Sjmcneill 	int i;
164d3ea21c0Sjmcneill 
165d3ea21c0Sjmcneill 	for (i = 0; i < len; i++)
166d3ea21c0Sjmcneill 	      	CRC = (CRC << 8) ^ crc_tab[((CRC >> 24) ^ *buf++) & 0xff];
167d3ea21c0Sjmcneill 
168d3ea21c0Sjmcneill 	return CRC;
169d3ea21c0Sjmcneill }
170d3ea21c0Sjmcneill 
171e1214af8Sjmcneill /*
172e1214af8Sjmcneill  * Start running the demux.
173e1214af8Sjmcneill  */
174e1214af8Sjmcneill static int
dtv_demux_start(struct dtv_demux * demux)175e1214af8Sjmcneill dtv_demux_start(struct dtv_demux *demux)
176e1214af8Sjmcneill {
177e1214af8Sjmcneill 	struct dtv_softc *sc = demux->dd_sc;
178e1214af8Sjmcneill 	int error = 0;
179e1214af8Sjmcneill 	bool dostart = false;
180e1214af8Sjmcneill 
181e1214af8Sjmcneill 	/*
182e1214af8Sjmcneill 	 * If the demux is not running, mark it as running and update the
183e1214af8Sjmcneill 	 * global demux run counter.
184e1214af8Sjmcneill 	 */
185e1214af8Sjmcneill 	mutex_enter(&sc->sc_lock);
186e1214af8Sjmcneill 	KASSERT(sc->sc_demux_runcnt >= 0);
187e1214af8Sjmcneill 	if (demux->dd_running == false) {
188e1214af8Sjmcneill 		sc->sc_demux_runcnt++;
189e1214af8Sjmcneill 		demux->dd_running = true;
190e1214af8Sjmcneill 		/* If this is the first demux running, trigger device start */
191e1214af8Sjmcneill 		dostart = sc->sc_demux_runcnt == 1;
192e1214af8Sjmcneill 	}
193e1214af8Sjmcneill 	mutex_exit(&sc->sc_lock);
194e1214af8Sjmcneill 
195e1214af8Sjmcneill 	if (dostart) {
196e1214af8Sjmcneill 		/* Setup receive buffers and trigger device start */
197e1214af8Sjmcneill 		error = dtv_buffer_setup(sc);
198e1214af8Sjmcneill 		if (error == 0)
199e1214af8Sjmcneill 			error = dtv_device_start_transfer(sc);
200e1214af8Sjmcneill 	}
201e1214af8Sjmcneill 
202e1214af8Sjmcneill 	/*
203e1214af8Sjmcneill 	 * If something went wrong, restore the run counter and mark this
204e1214af8Sjmcneill 	 * demux instance as halted.
205e1214af8Sjmcneill 	 */
206e1214af8Sjmcneill 	if (error) {
207e1214af8Sjmcneill 		mutex_enter(&sc->sc_lock);
208e1214af8Sjmcneill 		sc->sc_demux_runcnt--;
209e1214af8Sjmcneill 		demux->dd_running = false;
210e1214af8Sjmcneill 		mutex_exit(&sc->sc_lock);
211e1214af8Sjmcneill 	}
212e1214af8Sjmcneill 
213e1214af8Sjmcneill 	return error;
214e1214af8Sjmcneill }
215e1214af8Sjmcneill 
216e1214af8Sjmcneill /*
217e1214af8Sjmcneill  * Stop running the demux.
218e1214af8Sjmcneill  */
219e1214af8Sjmcneill static int
dtv_demux_stop(struct dtv_demux * demux)220e1214af8Sjmcneill dtv_demux_stop(struct dtv_demux *demux)
221e1214af8Sjmcneill {
222e1214af8Sjmcneill 	struct dtv_softc *sc = demux->dd_sc;
223e1214af8Sjmcneill 	int error = 0;
224e1214af8Sjmcneill 	bool dostop = false;
225e1214af8Sjmcneill 
226e1214af8Sjmcneill 	/*
227e1214af8Sjmcneill 	 * If the demux is running, mark it as halted and update the
228e1214af8Sjmcneill 	 * global demux run counter.
229e1214af8Sjmcneill 	 */
230e1214af8Sjmcneill 	mutex_enter(&sc->sc_lock);
231e1214af8Sjmcneill 	if (demux->dd_running == true) {
232e1214af8Sjmcneill 		KASSERT(sc->sc_demux_runcnt > 0);
233e1214af8Sjmcneill 		demux->dd_running = false;
234e1214af8Sjmcneill 		sc->sc_demux_runcnt--;
235e1214af8Sjmcneill 		/* If this was the last demux running, trigger device stop */
236e1214af8Sjmcneill 		dostop = sc->sc_demux_runcnt == 0;
237e1214af8Sjmcneill 	}
238e1214af8Sjmcneill 	mutex_exit(&sc->sc_lock);
239e1214af8Sjmcneill 
240e1214af8Sjmcneill 	if (dostop) {
241e1214af8Sjmcneill 		/* Trigger device stop */
242e1214af8Sjmcneill 		error = dtv_device_stop_transfer(sc);
243e1214af8Sjmcneill 	}
244e1214af8Sjmcneill 
245e1214af8Sjmcneill 	/*
246e1214af8Sjmcneill 	 * If something went wrong, restore the run counter and mark this
247e1214af8Sjmcneill 	 * demux instance as running.
248e1214af8Sjmcneill 	 */
249e1214af8Sjmcneill 	if (error) {
250e1214af8Sjmcneill 		mutex_enter(&sc->sc_lock);
251e1214af8Sjmcneill 		sc->sc_demux_runcnt++;
252e1214af8Sjmcneill 		demux->dd_running = true;
253e1214af8Sjmcneill 		mutex_exit(&sc->sc_lock);
254e1214af8Sjmcneill 	}
255e1214af8Sjmcneill 
256e1214af8Sjmcneill 	return error;
257e1214af8Sjmcneill }
258e1214af8Sjmcneill 
259e1214af8Sjmcneill /*
260e1214af8Sjmcneill  * Put the demux into PID filter mode and update the PID filter table.
261e1214af8Sjmcneill  */
262e1214af8Sjmcneill static int
dtv_demux_set_pidfilter(struct dtv_demux * demux,uint16_t pid,bool onoff)263e1214af8Sjmcneill dtv_demux_set_pidfilter(struct dtv_demux *demux, uint16_t pid, bool onoff)
264e1214af8Sjmcneill {
265e1214af8Sjmcneill 	struct dtv_softc *sc = demux->dd_sc;
266e1214af8Sjmcneill 
267e1214af8Sjmcneill 	/*
268e1214af8Sjmcneill 	 * TS PID is 13 bits; demux device uses special PID 0x2000 to mean
269e1214af8Sjmcneill 	 * "all PIDs". Verify that the requested PID is in range.
270e1214af8Sjmcneill 	 */
271e1214af8Sjmcneill 	if (pid > 0x2000)
272e1214af8Sjmcneill 		return EINVAL;
273e1214af8Sjmcneill 
274e1214af8Sjmcneill 	/* Set demux mode */
275e1214af8Sjmcneill 	demux->dd_mode = DTV_DEMUX_MODE_PES;
276e1214af8Sjmcneill 	/*
277e1214af8Sjmcneill 	 * If requesting "all PIDs", set the on/off flag for all PIDs in
278e1214af8Sjmcneill 	 * the PID map, otherwise set the on/off flag for the requested
279e1214af8Sjmcneill 	 * PID.
280e1214af8Sjmcneill 	 */
281e1214af8Sjmcneill 	if (pid == 0x2000) {
2823de82c23Sjmcneill 		memset(sc->sc_ts.ts_pidfilter, onoff ? 0xff : 0,
283e1214af8Sjmcneill 		    sizeof(sc->sc_ts.ts_pidfilter));
284e1214af8Sjmcneill 	} else {
285e1214af8Sjmcneill 		sc->sc_ts.ts_pidfilter[pid] = onoff;
286e1214af8Sjmcneill 	}
287e1214af8Sjmcneill 
288e1214af8Sjmcneill 	return 0;
289e1214af8Sjmcneill }
290e1214af8Sjmcneill 
291e1214af8Sjmcneill /*
292e1214af8Sjmcneill  * Open a new instance of the demux cloning device.
293e1214af8Sjmcneill  */
294d3ea21c0Sjmcneill int
dtv_demux_open(struct dtv_softc * sc,int flags,int mode,lwp_t * l)295d3ea21c0Sjmcneill dtv_demux_open(struct dtv_softc *sc, int flags, int mode, lwp_t *l)
296d3ea21c0Sjmcneill {
297d3ea21c0Sjmcneill 	struct file *fp;
298d3ea21c0Sjmcneill 	struct dtv_demux *demux;
299d3ea21c0Sjmcneill 	int error, fd;
300d3ea21c0Sjmcneill 
301e1214af8Sjmcneill 	/* Allocate private storage */
302d3ea21c0Sjmcneill 	demux = kmem_zalloc(sizeof(*demux), KM_SLEEP);
303d3ea21c0Sjmcneill 	demux->dd_sc = sc;
304e1214af8Sjmcneill 	/* Default operation mode is unconfigured */
305d3ea21c0Sjmcneill 	demux->dd_mode = DTV_DEMUX_MODE_NONE;
306d3ea21c0Sjmcneill 	selinit(&demux->dd_sel);
30706726bf7Sjmcneill 	mutex_init(&demux->dd_lock, MUTEX_DEFAULT, IPL_SCHED);
308d3ea21c0Sjmcneill 	cv_init(&demux->dd_section_cv, "dtvsec");
309d3ea21c0Sjmcneill 
310d3ea21c0Sjmcneill 	error = fd_allocfile(&fp, &fd);
311d3ea21c0Sjmcneill 	if (error) {
312d3ea21c0Sjmcneill 		kmem_free(demux, sizeof(*demux));
313d3ea21c0Sjmcneill 		return error;
314d3ea21c0Sjmcneill 	}
315d3ea21c0Sjmcneill 
316e1214af8Sjmcneill 	/* Add the demux to the list of demux instances */
317d3ea21c0Sjmcneill 	mutex_enter(&sc->sc_demux_lock);
318d3ea21c0Sjmcneill 	TAILQ_INSERT_TAIL(&sc->sc_demux_list, demux, dd_entries);
319d3ea21c0Sjmcneill 	mutex_exit(&sc->sc_demux_lock);
320d3ea21c0Sjmcneill 
321d3ea21c0Sjmcneill 	return fd_clone(fp, fd, flags, &dtv_demux_fileops, demux);
322d3ea21c0Sjmcneill }
323d3ea21c0Sjmcneill 
324e1214af8Sjmcneill /*
325e1214af8Sjmcneill  * Close the instance of the demux cloning device.
326e1214af8Sjmcneill  */
327d3ea21c0Sjmcneill int
dtv_demux_close(struct file * fp)328d3ea21c0Sjmcneill dtv_demux_close(struct file *fp)
329d3ea21c0Sjmcneill {
330d3ea21c0Sjmcneill 	struct dtv_demux *demux = fp->f_data;
331d3ea21c0Sjmcneill 	struct dtv_softc *sc;
332e1214af8Sjmcneill 	int error;
333d3ea21c0Sjmcneill 
334d3ea21c0Sjmcneill 	if (demux == NULL)
335d3ea21c0Sjmcneill 		return ENXIO;
336d3ea21c0Sjmcneill 
337d3ea21c0Sjmcneill 	fp->f_data = NULL;
338d3ea21c0Sjmcneill 
339d3ea21c0Sjmcneill 	sc = demux->dd_sc;
340d3ea21c0Sjmcneill 
341e1214af8Sjmcneill 	/* If the demux is still running, stop it */
342e1214af8Sjmcneill 	if (demux->dd_running) {
343e1214af8Sjmcneill 		error = dtv_demux_stop(demux);
344e1214af8Sjmcneill 		if (error)
345e1214af8Sjmcneill 			return error;
346e1214af8Sjmcneill 	}
347e1214af8Sjmcneill 
348e1214af8Sjmcneill 	/* Remove the demux from the list of demux instances */
349d3ea21c0Sjmcneill 	mutex_enter(&sc->sc_demux_lock);
350d3ea21c0Sjmcneill 	TAILQ_REMOVE(&sc->sc_demux_list, demux, dd_entries);
351d3ea21c0Sjmcneill 	mutex_exit(&sc->sc_demux_lock);
352d3ea21c0Sjmcneill 
353d3ea21c0Sjmcneill 	mutex_destroy(&demux->dd_lock);
354d3ea21c0Sjmcneill 	cv_destroy(&demux->dd_section_cv);
355d3ea21c0Sjmcneill 	kmem_free(demux, sizeof(*demux));
356d3ea21c0Sjmcneill 
357e1214af8Sjmcneill 	/* Update the global device open count */
358e1214af8Sjmcneill 	dtv_common_close(sc);
359d3ea21c0Sjmcneill 
360d3ea21c0Sjmcneill 	return 0;
361d3ea21c0Sjmcneill }
362d3ea21c0Sjmcneill 
363e1214af8Sjmcneill /*
364e1214af8Sjmcneill  * Handle demux ioctl requests
365e1214af8Sjmcneill  */
366d3ea21c0Sjmcneill static int
dtv_demux_ioctl(struct file * fp,u_long cmd,void * data)367e1214af8Sjmcneill dtv_demux_ioctl(struct file *fp, u_long cmd, void *data)
368d3ea21c0Sjmcneill {
369e1214af8Sjmcneill 	struct dtv_demux *demux = fp->f_data;
370d3ea21c0Sjmcneill 	struct dmx_pes_filter_params *pesfilt;
371d3ea21c0Sjmcneill 	struct dmx_sct_filter_params *sctfilt;
372d3ea21c0Sjmcneill 	uint16_t pid;
373d3ea21c0Sjmcneill 	int error;
374d3ea21c0Sjmcneill 
375d3ea21c0Sjmcneill 	if (demux == NULL)
376d3ea21c0Sjmcneill 		return ENXIO;
377d3ea21c0Sjmcneill 
378d3ea21c0Sjmcneill 	switch (cmd) {
379d3ea21c0Sjmcneill 	case DMX_START:
380e1214af8Sjmcneill 		return dtv_demux_start(demux);
381d3ea21c0Sjmcneill 	case DMX_STOP:
382e1214af8Sjmcneill 		return dtv_demux_stop(demux);
383d3ea21c0Sjmcneill 	case DMX_SET_BUFFER_SIZE:
384e1214af8Sjmcneill 		/*
385e1214af8Sjmcneill 		 * The demux driver doesn't support configurable buffer sizes,
386e1214af8Sjmcneill 		 * but software relies on this command succeeding.
387e1214af8Sjmcneill 		 */
388d3ea21c0Sjmcneill 		return 0;
389d3ea21c0Sjmcneill 	case DMX_SET_FILTER:
390d3ea21c0Sjmcneill 		sctfilt = data;
391d3ea21c0Sjmcneill 
392e1214af8Sjmcneill 		/* Verify that the requested PID is in range. */
393d3ea21c0Sjmcneill 		if (sctfilt->pid >= 0x2000)
394d3ea21c0Sjmcneill 			return EINVAL;
395d3ea21c0Sjmcneill 
396e1214af8Sjmcneill 		/*
397e1214af8Sjmcneill 		 * Update section filter parameters, reset read/write ptrs,
398e1214af8Sjmcneill 		 * clear section count and overflow flag, and set the
399e1214af8Sjmcneill 		 * demux instance mode to section filter.
400e1214af8Sjmcneill 		 */
401d3ea21c0Sjmcneill 		demux->dd_secfilt.params = *sctfilt;
402d3ea21c0Sjmcneill 		demux->dd_secfilt.rp = demux->dd_secfilt.wp = 0;
403d3ea21c0Sjmcneill 		demux->dd_secfilt.nsections = 0;
404d3ea21c0Sjmcneill 		demux->dd_secfilt.overflow = false;
405d3ea21c0Sjmcneill 		demux->dd_mode = DTV_DEMUX_MODE_SECTION;
406d3ea21c0Sjmcneill 
407e1214af8Sjmcneill 		/*
408e1214af8Sjmcneill 		 * If the DMX_IMMEDIATE_START flag is present in the request,
409e1214af8Sjmcneill 		 * start running the demux immediately (no need for a
410e1214af8Sjmcneill 		 * subsequent DMX_START ioctl).
411e1214af8Sjmcneill 		 */
412d3ea21c0Sjmcneill 		if (sctfilt->flags & DMX_IMMEDIATE_START) {
413e1214af8Sjmcneill 			error = dtv_demux_start(demux);
414d3ea21c0Sjmcneill 			if (error)
415d3ea21c0Sjmcneill 				return error;
416d3ea21c0Sjmcneill 		}
417d3ea21c0Sjmcneill 
418d3ea21c0Sjmcneill 		return 0;
419d3ea21c0Sjmcneill 	case DMX_SET_PES_FILTER:
420d3ea21c0Sjmcneill 		pesfilt = data;
421d3ea21c0Sjmcneill 
422e1214af8Sjmcneill 		/* The driver only supports input from the frontend */
423d3ea21c0Sjmcneill 		if (pesfilt->input != DMX_IN_FRONTEND)
424d3ea21c0Sjmcneill 			return EINVAL;
425e1214af8Sjmcneill 		/*
426e1214af8Sjmcneill 		 * The driver only supports output to the TS TAP in PID
427e1214af8Sjmcneill 		 * filter mode.
428e1214af8Sjmcneill 		 */
429d3ea21c0Sjmcneill 		if (pesfilt->output != DMX_OUT_TS_TAP)
430d3ea21c0Sjmcneill 			return EINVAL;
431d3ea21c0Sjmcneill 
432e1214af8Sjmcneill 		/* Update PID filter table */
433e1214af8Sjmcneill 		error = dtv_demux_set_pidfilter(demux, pesfilt->pid, true);
434d3ea21c0Sjmcneill 		if (error)
435d3ea21c0Sjmcneill 			return error;
436d3ea21c0Sjmcneill 
437e1214af8Sjmcneill 		/*
438e1214af8Sjmcneill 		 * If the DMX_IMMEDIATE_START flag is present in the request,
439e1214af8Sjmcneill 		 * start running the demux immediately (no need for a
440e1214af8Sjmcneill 		 * subsequent DMX_START ioctl).
441e1214af8Sjmcneill 		 */
442d3ea21c0Sjmcneill 		if (pesfilt->flags & DMX_IMMEDIATE_START) {
443e1214af8Sjmcneill 			error = dtv_demux_start(demux);
444d3ea21c0Sjmcneill 			if (error)
445d3ea21c0Sjmcneill 				return error;
446d3ea21c0Sjmcneill 		}
447d3ea21c0Sjmcneill 		return 0;
448d3ea21c0Sjmcneill 	case DMX_ADD_PID:
449d3ea21c0Sjmcneill 		pid = *(uint16_t *)data;
450e1214af8Sjmcneill 		return dtv_demux_set_pidfilter(demux, pid, true);
451d3ea21c0Sjmcneill 	case DMX_REMOVE_PID:
452d3ea21c0Sjmcneill 		pid = *(uint16_t *)data;
453e1214af8Sjmcneill 		return dtv_demux_set_pidfilter(demux, pid, false);
454d3ea21c0Sjmcneill 	default:
455d3ea21c0Sjmcneill 		return EINVAL;
456d3ea21c0Sjmcneill 	}
457d3ea21c0Sjmcneill }
458d3ea21c0Sjmcneill 
459e1214af8Sjmcneill /*
460e1214af8Sjmcneill  * Test for I/O readiness
461e1214af8Sjmcneill  */
462d3ea21c0Sjmcneill static int
dtv_demux_poll(struct file * fp,int events)463d3ea21c0Sjmcneill dtv_demux_poll(struct file *fp, int events)
464d3ea21c0Sjmcneill {
465d3ea21c0Sjmcneill 	struct dtv_demux *demux = fp->f_data;
466d3ea21c0Sjmcneill 	int revents = 0;
467d3ea21c0Sjmcneill 
468d3ea21c0Sjmcneill 	if (demux == NULL)
469d3ea21c0Sjmcneill 		return POLLERR;
470d3ea21c0Sjmcneill 
471e1214af8Sjmcneill 	/*
472e1214af8Sjmcneill 	 * If the demux instance is in section filter mode, wait for an
473e1214af8Sjmcneill 	 * entire section to become ready.
474e1214af8Sjmcneill 	 */
475d3ea21c0Sjmcneill 	mutex_enter(&demux->dd_lock);
476e1214af8Sjmcneill 	if (demux->dd_mode == DTV_DEMUX_MODE_SECTION &&
477e1214af8Sjmcneill 	    demux->dd_secfilt.nsections > 0) {
478d3ea21c0Sjmcneill 		revents |= POLLIN;
479d3ea21c0Sjmcneill 	} else {
480d3ea21c0Sjmcneill 		selrecord(curlwp, &demux->dd_sel);
481d3ea21c0Sjmcneill 	}
482d3ea21c0Sjmcneill 	mutex_exit(&demux->dd_lock);
483d3ea21c0Sjmcneill 
484d3ea21c0Sjmcneill 	return revents;
485d3ea21c0Sjmcneill }
486d3ea21c0Sjmcneill 
487e1214af8Sjmcneill /*
488e1214af8Sjmcneill  * Read from the demux instance
489e1214af8Sjmcneill  */
490d3ea21c0Sjmcneill static int
dtv_demux_read(struct file * fp,off_t * offp,struct uio * uio,kauth_cred_t cred,int flags)491d3ea21c0Sjmcneill dtv_demux_read(struct file *fp, off_t *offp, struct uio *uio,
492d3ea21c0Sjmcneill     kauth_cred_t cred, int flags)
493d3ea21c0Sjmcneill {
494d3ea21c0Sjmcneill 	struct dtv_demux *demux = fp->f_data;
495*e7cfc031Sjdolecek 	struct dtv_ts_section *sec;
496d3ea21c0Sjmcneill 	int error;
497d3ea21c0Sjmcneill 
498d3ea21c0Sjmcneill 	if (demux == NULL)
499d3ea21c0Sjmcneill 		return ENXIO;
500d3ea21c0Sjmcneill 
501e1214af8Sjmcneill 	/* Only support read if the instance is in section filter mode */
502d3ea21c0Sjmcneill 	if (demux->dd_mode != DTV_DEMUX_MODE_SECTION)
503d3ea21c0Sjmcneill 		return EIO;
504d3ea21c0Sjmcneill 
505*e7cfc031Sjdolecek 	sec = kmem_alloc(sizeof(*sec), KM_SLEEP);
506*e7cfc031Sjdolecek 
507e1214af8Sjmcneill 	/* Wait for a complete PSI section */
508d3ea21c0Sjmcneill 	mutex_enter(&demux->dd_lock);
509d3ea21c0Sjmcneill 	while (demux->dd_secfilt.nsections == 0) {
510d3ea21c0Sjmcneill 		if (flags & IO_NDELAY) {
511d3ea21c0Sjmcneill 			mutex_exit(&demux->dd_lock);
512e1214af8Sjmcneill 			/* No data available */
513*e7cfc031Sjdolecek 			error = EWOULDBLOCK;
514*e7cfc031Sjdolecek 			goto out;
515d3ea21c0Sjmcneill 		}
516d3ea21c0Sjmcneill 		error = cv_wait_sig(&demux->dd_section_cv, &demux->dd_lock);
517d3ea21c0Sjmcneill 		if (error) {
518d3ea21c0Sjmcneill 			mutex_exit(&demux->dd_lock);
519*e7cfc031Sjdolecek 			goto out;
520d3ea21c0Sjmcneill 		}
521d3ea21c0Sjmcneill 	}
522e1214af8Sjmcneill 	/* Copy the completed PSI section */
523*e7cfc031Sjdolecek 	*sec = demux->dd_secfilt.section[demux->dd_secfilt.rp];
524e1214af8Sjmcneill 	/* Update read pointer */
525d3ea21c0Sjmcneill 	demux->dd_secfilt.rp++;
526d3ea21c0Sjmcneill 	if (demux->dd_secfilt.rp >= __arraycount(demux->dd_secfilt.section))
527d3ea21c0Sjmcneill 		demux->dd_secfilt.rp = 0;
528e1214af8Sjmcneill 	/* Update section count */
529d3ea21c0Sjmcneill 	demux->dd_secfilt.nsections--;
530d3ea21c0Sjmcneill 	mutex_exit(&demux->dd_lock);
531d3ea21c0Sjmcneill 
532e1214af8Sjmcneill 	/*
533e1214af8Sjmcneill 	 * If the filter parameters specify the DMX_ONESHOT flag, stop
534e1214af8Sjmcneill 	 * the demux after one PSI section is received.
535e1214af8Sjmcneill 	 */
536e1214af8Sjmcneill 	if (demux->dd_secfilt.params.flags & DMX_ONESHOT)
537e1214af8Sjmcneill 		dtv_demux_stop(demux);
538e1214af8Sjmcneill 
539e1214af8Sjmcneill 	/*
540e1214af8Sjmcneill 	 * Copy the PSI section to userspace. If the receiving buffer is
541e1214af8Sjmcneill 	 * too small, the rest of the payload will be discarded. Although
542e1214af8Sjmcneill 	 * this behaviour differs from the Linux implementation, in practice
543e1214af8Sjmcneill 	 * it should not be an issue as PSI sections have a max size of 4KB
544e1214af8Sjmcneill 	 * (and callers will generally provide a big enough buffer).
545e1214af8Sjmcneill 	 */
546*e7cfc031Sjdolecek 	error = uiomove(sec->sec_buf, sec->sec_length, uio);
547*e7cfc031Sjdolecek 
548*e7cfc031Sjdolecek out:
549*e7cfc031Sjdolecek 	kmem_free(sec, sizeof(*sec));
550*e7cfc031Sjdolecek 	return error;
551*e7cfc031Sjdolecek 
552d3ea21c0Sjmcneill }
553d3ea21c0Sjmcneill 
554e1214af8Sjmcneill /*
555e1214af8Sjmcneill  * Verify the CRC of a PSI section.
556e1214af8Sjmcneill  */
557d3ea21c0Sjmcneill static bool
dtv_demux_check_crc(struct dtv_demux * demux,struct dtv_ts_section * sec)558d3ea21c0Sjmcneill dtv_demux_check_crc(struct dtv_demux *demux, struct dtv_ts_section *sec)
559d3ea21c0Sjmcneill {
560d3ea21c0Sjmcneill 	uint32_t crc, sec_crc;
561d3ea21c0Sjmcneill 
562e1214af8Sjmcneill 	/*
563e1214af8Sjmcneill 	 * If section_syntax_indicator is not set, the PSI section does
564e1214af8Sjmcneill 	 * not include a CRC field.
565e1214af8Sjmcneill 	 */
566d3ea21c0Sjmcneill 	if ((sec->sec_buf[1] & 0x80) == 0)
567d3ea21c0Sjmcneill 		return false;
568d3ea21c0Sjmcneill 
569d3ea21c0Sjmcneill 	sec_crc = be32dec(&sec->sec_buf[sec->sec_length - 4]);
570d3ea21c0Sjmcneill 	crc = dtv_demux_crc32(&sec->sec_buf[0], sec->sec_length - 4);
571d3ea21c0Sjmcneill 
572d3ea21c0Sjmcneill 	return crc == sec_crc;
573d3ea21c0Sjmcneill }
574d3ea21c0Sjmcneill 
575e1214af8Sjmcneill /*
576e1214af8Sjmcneill  * Process a single TS packet and extract PSI sections based on the
577e1214af8Sjmcneill  * instance's section filter.
578e1214af8Sjmcneill  */
579e1214af8Sjmcneill static int
dtv_demux_process(struct dtv_demux * demux,const uint8_t * tspkt,size_t tspktlen)580e1214af8Sjmcneill dtv_demux_process(struct dtv_demux *demux, const uint8_t *tspkt,
581e1214af8Sjmcneill     size_t tspktlen)
582d3ea21c0Sjmcneill {
583d3ea21c0Sjmcneill 	struct dtv_ts_section *sec;
584d3ea21c0Sjmcneill 	dmx_filter_t *dmxfilt = &demux->dd_secfilt.params.filter;
585d3ea21c0Sjmcneill 	const uint8_t *p;
586d3ea21c0Sjmcneill 	uint16_t section_length;
587d3ea21c0Sjmcneill 	int brem, avail;
588d3ea21c0Sjmcneill 
589d3ea21c0Sjmcneill 	KASSERT(tspktlen == TS_PKTLEN);
590d3ea21c0Sjmcneill 
591e1214af8Sjmcneill 	/* If the demux instance is not running, ignore the packet */
592e1214af8Sjmcneill 	if (demux->dd_running == false)
593e1214af8Sjmcneill 		return 0;
594e1214af8Sjmcneill 
595e1214af8Sjmcneill 	/*
596e1214af8Sjmcneill 	 * If the demux instance is not in section filter mode, ignore
597e1214af8Sjmcneill 	 * the packet
598e1214af8Sjmcneill 	 */
599d3ea21c0Sjmcneill 	if (demux->dd_mode != DTV_DEMUX_MODE_SECTION)
600d3ea21c0Sjmcneill 		return 0;
601e1214af8Sjmcneill 	/*
602e1214af8Sjmcneill 	 * If the packet's TS PID does not match the section filter PID,
603e1214af8Sjmcneill 	 * ignore the packet
604e1214af8Sjmcneill 	 */
605d3ea21c0Sjmcneill 	if (TS_PID(tspkt) != demux->dd_secfilt.params.pid)
606d3ea21c0Sjmcneill 		return 0;
607e1214af8Sjmcneill 	/*
608e1214af8Sjmcneill 	 * If the TS packet does not contain a payload, ignore the packet
609e1214af8Sjmcneill 	 */
610d3ea21c0Sjmcneill 	if (TS_HAS_PAYLOAD(tspkt) == 0)
611d3ea21c0Sjmcneill 		return 0;
612d3ea21c0Sjmcneill 
613d3ea21c0Sjmcneill 	mutex_enter(&demux->dd_lock);
614e1214af8Sjmcneill 
615e1214af8Sjmcneill 	/* If the section buffer is full, set the overflow flag and return */
616d3ea21c0Sjmcneill 	if (demux->dd_secfilt.nsections ==
617d3ea21c0Sjmcneill 	    __arraycount(demux->dd_secfilt.section)) {
618d3ea21c0Sjmcneill 		demux->dd_secfilt.overflow = true;
619d3ea21c0Sjmcneill 		goto done;
620d3ea21c0Sjmcneill 	}
621d3ea21c0Sjmcneill 	sec = &demux->dd_secfilt.section[demux->dd_secfilt.wp];
622d3ea21c0Sjmcneill 	/* If we have no bytes in our buffer, wait for payload unit start */
623d3ea21c0Sjmcneill 	if (sec->sec_bytesused == 0 && TS_HAS_PUSI(tspkt) == 0)
624d3ea21c0Sjmcneill 		goto done;
625d3ea21c0Sjmcneill 
626d3ea21c0Sjmcneill 	/* find payload start */
627d3ea21c0Sjmcneill 	p = tspkt + 4;
628d3ea21c0Sjmcneill 	if (TS_HAS_AF(tspkt)) {
629d3ea21c0Sjmcneill 		if (*p > 182)	/* AF length with payload is between 0-182 */
630d3ea21c0Sjmcneill 			goto done;
631d3ea21c0Sjmcneill 		p += (1 + *p);
632d3ea21c0Sjmcneill 	}
633d3ea21c0Sjmcneill 	if (TS_HAS_PUSI(tspkt)) {
634d3ea21c0Sjmcneill 		p += (1 + *p);
635d3ea21c0Sjmcneill 	}
636d3ea21c0Sjmcneill 
637d3ea21c0Sjmcneill 	brem = tspktlen - (p - tspkt);
638d3ea21c0Sjmcneill 
639d3ea21c0Sjmcneill 	if (TS_HAS_PUSI(tspkt)) {
640d3ea21c0Sjmcneill 		if (brem < 16)
641677961abSjmcneill 			goto done;
642d3ea21c0Sjmcneill 
643d3ea21c0Sjmcneill 		section_length = ((p[1] & 0xf) << 8) | p[2];
644d3ea21c0Sjmcneill 
645d3ea21c0Sjmcneill 		/* table_id filter */
646d3ea21c0Sjmcneill 		if (dmxfilt->mask[0]) {
647d3ea21c0Sjmcneill 			if ((p[0] & dmxfilt->mask[0]) != dmxfilt->filter[0])
648d3ea21c0Sjmcneill 				goto done;
649d3ea21c0Sjmcneill 		}
650d3ea21c0Sjmcneill 		/* table_id_ext filter */
651d3ea21c0Sjmcneill 		if (dmxfilt->mask[1] && dmxfilt->mask[2]) {
652e1214af8Sjmcneill 			/*
653e1214af8Sjmcneill 			 * table_id_ext is only valid if
654e1214af8Sjmcneill 			 * section_syntax_indicator is set
655e1214af8Sjmcneill 			 */
656d3ea21c0Sjmcneill 			if (section_length < 2 || (p[1] & 0x80) == 0)
657d3ea21c0Sjmcneill 				goto done;
658d3ea21c0Sjmcneill 			if ((p[3] & dmxfilt->mask[1]) != dmxfilt->filter[1])
659d3ea21c0Sjmcneill 				goto done;
660d3ea21c0Sjmcneill 			if ((p[4] & dmxfilt->mask[2]) != dmxfilt->filter[2])
661d3ea21c0Sjmcneill 				goto done;
662d3ea21c0Sjmcneill 		}
663d3ea21c0Sjmcneill 
664d3ea21c0Sjmcneill 		sec->sec_length = section_length + 3;
6650546d048Sjmcneill 
6660546d048Sjmcneill 		/* maximum section length is 4KB */
6670546d048Sjmcneill 		if (sec->sec_length > sizeof(sec->sec_buf)) {
6680546d048Sjmcneill 			sec->sec_bytesused = sec->sec_length = 0;
6690546d048Sjmcneill 			goto done;
6700546d048Sjmcneill 		}
6710546d048Sjmcneill 
672d3ea21c0Sjmcneill 	}
673d3ea21c0Sjmcneill 
674d3ea21c0Sjmcneill 	/* If we have bytes pending and we see payload unit start, flush buf */
675d3ea21c0Sjmcneill 	if (sec->sec_bytesused > 0 && TS_HAS_PUSI(tspkt))
676d3ea21c0Sjmcneill 		sec->sec_bytesused = sec->sec_length = 0;
677d3ea21c0Sjmcneill 
678e1214af8Sjmcneill 	/* Copy data into section buffer */
679d1579b2dSriastradh 	avail = uimin(sec->sec_length - sec->sec_bytesused, brem);
680d3ea21c0Sjmcneill 	if (avail < 0)
681677961abSjmcneill 		goto done;
682d3ea21c0Sjmcneill 	memcpy(&sec->sec_buf[sec->sec_bytesused], p, avail);
683d3ea21c0Sjmcneill 	sec->sec_bytesused += avail;
684d3ea21c0Sjmcneill 
685e1214af8Sjmcneill 	/*
686e1214af8Sjmcneill 	 * If a complete section has been received, update section count
687e1214af8Sjmcneill 	 * and notify readers.
688e1214af8Sjmcneill 	 */
689d3ea21c0Sjmcneill 	if (sec->sec_bytesused == sec->sec_length) {
690e1214af8Sjmcneill 		/*
691e1214af8Sjmcneill 		 * If the DMX_CHECK_CRC flag was present in the DMX_SET_FILTER
692e1214af8Sjmcneill 		 * parameters, verify the PSI section checksum. If the
693e1214af8Sjmcneill 		 * checksum is invalid, discard the entire corrupt section.
694e1214af8Sjmcneill 		 */
695d3ea21c0Sjmcneill 		if ((demux->dd_secfilt.params.flags & DMX_CHECK_CRC) &&
696d3ea21c0Sjmcneill 		    dtv_demux_check_crc(demux, sec) == false) {
697e1214af8Sjmcneill 			/* discard section */
698d3ea21c0Sjmcneill 			sec->sec_bytesused = sec->sec_length = 0;
699d3ea21c0Sjmcneill 			goto done;
700d3ea21c0Sjmcneill 		}
701d3ea21c0Sjmcneill 
702d3ea21c0Sjmcneill 		demux->dd_secfilt.wp++;
703d3ea21c0Sjmcneill 		if (demux->dd_secfilt.wp >=
704d3ea21c0Sjmcneill 		    __arraycount(demux->dd_secfilt.section))
705d3ea21c0Sjmcneill 			demux->dd_secfilt.wp = 0;
706d3ea21c0Sjmcneill 		demux->dd_secfilt.nsections++;
707d3ea21c0Sjmcneill 		cv_broadcast(&demux->dd_section_cv);
708d3ea21c0Sjmcneill 		selnotify(&demux->dd_sel, 0, 0);
709d3ea21c0Sjmcneill 	}
710d3ea21c0Sjmcneill 
711d3ea21c0Sjmcneill done:
712d3ea21c0Sjmcneill 	mutex_exit(&demux->dd_lock);
713d3ea21c0Sjmcneill 	return 0;
714d3ea21c0Sjmcneill }
715d3ea21c0Sjmcneill 
716e1214af8Sjmcneill /*
717e1214af8Sjmcneill  * Submit TS data to all demux instances
718e1214af8Sjmcneill  */
719e1214af8Sjmcneill void
dtv_demux_write(struct dtv_softc * sc,const uint8_t * tspkt,size_t tspktlen)720e1214af8Sjmcneill dtv_demux_write(struct dtv_softc *sc, const uint8_t *tspkt, size_t tspktlen)
721e1214af8Sjmcneill {
722e1214af8Sjmcneill 	struct dtv_demux *demux;
723e1214af8Sjmcneill 
724e1214af8Sjmcneill 	mutex_enter(&sc->sc_demux_lock);
725e1214af8Sjmcneill 	TAILQ_FOREACH(demux, &sc->sc_demux_list, dd_entries) {
726e1214af8Sjmcneill 		dtv_demux_process(demux, tspkt, tspktlen);
727e1214af8Sjmcneill 	}
728e1214af8Sjmcneill 	mutex_exit(&sc->sc_demux_lock);
729e1214af8Sjmcneill }
730