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