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