Home | History | Annotate | Line # | Download | only in dtv
dtv_demux.c revision 1.3
      1  1.3  jmcneill /* $NetBSD: dtv_demux.c,v 1.3 2011/07/14 01:37:09 jmcneill 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.1  jmcneill #include <sys/cdefs.h>
     36  1.3  jmcneill __KERNEL_RCSID(0, "$NetBSD: dtv_demux.c,v 1.3 2011/07/14 01:37:09 jmcneill Exp $");
     37  1.1  jmcneill 
     38  1.1  jmcneill #include <sys/param.h>
     39  1.1  jmcneill #include <sys/types.h>
     40  1.1  jmcneill #include <sys/conf.h>
     41  1.1  jmcneill #include <sys/kmem.h>
     42  1.1  jmcneill #include <sys/device.h>
     43  1.1  jmcneill #include <sys/select.h>
     44  1.1  jmcneill #include <sys/filedesc.h>
     45  1.1  jmcneill #include <sys/file.h>
     46  1.1  jmcneill #include <sys/poll.h>
     47  1.1  jmcneill #include <sys/vnode.h>
     48  1.1  jmcneill #include <sys/queue.h>
     49  1.1  jmcneill 
     50  1.1  jmcneill #include <net/if.h>
     51  1.1  jmcneill #include <net/if_ether.h>	/* for ether_crc32_be */
     52  1.1  jmcneill 
     53  1.1  jmcneill #include <dev/dtv/dtvvar.h>
     54  1.1  jmcneill 
     55  1.1  jmcneill static int	dtv_demux_read(struct file *, off_t *, struct uio *,
     56  1.1  jmcneill 		    kauth_cred_t, int);
     57  1.1  jmcneill static int	dtv_demux_ioctl(struct file *, u_long, void *);
     58  1.1  jmcneill static int	dtv_demux_poll(struct file *, int);
     59  1.1  jmcneill static int	dtv_demux_close(struct file *);
     60  1.1  jmcneill 
     61  1.1  jmcneill static const struct fileops dtv_demux_fileops = {
     62  1.1  jmcneill 	.fo_read = dtv_demux_read,
     63  1.1  jmcneill 	.fo_write = fbadop_write,
     64  1.1  jmcneill 	.fo_ioctl = dtv_demux_ioctl,
     65  1.1  jmcneill 	.fo_fcntl = fnullop_fcntl,
     66  1.1  jmcneill 	.fo_poll = dtv_demux_poll,
     67  1.1  jmcneill 	.fo_stat = fbadop_stat,
     68  1.1  jmcneill 	.fo_close = dtv_demux_close,
     69  1.1  jmcneill 	.fo_kqfilter = fnullop_kqfilter,
     70  1.1  jmcneill 	.fo_restart = fnullop_restart,
     71  1.1  jmcneill };
     72  1.1  jmcneill 
     73  1.1  jmcneill static uint32_t crc_table[256] = {
     74  1.1  jmcneill 	0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,
     75  1.1  jmcneill 	0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,
     76  1.1  jmcneill 	0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,
     77  1.1  jmcneill 	0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,
     78  1.1  jmcneill 	0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,
     79  1.1  jmcneill 	0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,
     80  1.1  jmcneill 	0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,
     81  1.1  jmcneill 	0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,
     82  1.1  jmcneill 	0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,
     83  1.1  jmcneill 	0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,
     84  1.1  jmcneill 	0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,
     85  1.1  jmcneill 	0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,
     86  1.1  jmcneill 	0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,
     87  1.1  jmcneill 	0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,
     88  1.1  jmcneill 	0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,
     89  1.1  jmcneill 	0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,
     90  1.1  jmcneill 	0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,
     91  1.1  jmcneill 	0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,
     92  1.1  jmcneill 	0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,
     93  1.1  jmcneill 	0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,
     94  1.1  jmcneill 	0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,
     95  1.1  jmcneill 	0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,
     96  1.1  jmcneill 	0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,
     97  1.1  jmcneill 	0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,
     98  1.1  jmcneill 	0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,
     99  1.1  jmcneill 	0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,
    100  1.1  jmcneill 	0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,
    101  1.1  jmcneill 	0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,
    102  1.1  jmcneill 	0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,
    103  1.1  jmcneill 	0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,
    104  1.1  jmcneill 	0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,
    105  1.1  jmcneill 	0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,
    106  1.1  jmcneill 	0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,
    107  1.1  jmcneill 	0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,
    108  1.1  jmcneill 	0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,
    109  1.1  jmcneill 	0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,
    110  1.1  jmcneill 	0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,
    111  1.1  jmcneill 	0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,
    112  1.1  jmcneill 	0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,
    113  1.1  jmcneill 	0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,
    114  1.1  jmcneill 	0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,
    115  1.1  jmcneill 	0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,
    116  1.1  jmcneill 	0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,
    117  1.1  jmcneill 	0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,
    118  1.1  jmcneill 	0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,
    119  1.1  jmcneill 	0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,
    120  1.1  jmcneill 	0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,
    121  1.1  jmcneill 	0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,
    122  1.1  jmcneill 	0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,
    123  1.1  jmcneill 	0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,
    124  1.1  jmcneill 	0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,
    125  1.1  jmcneill 	0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,
    126  1.1  jmcneill 	0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,
    127  1.1  jmcneill 	0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,
    128  1.1  jmcneill 	0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,
    129  1.1  jmcneill 	0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,
    130  1.1  jmcneill 	0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,
    131  1.1  jmcneill 	0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,
    132  1.1  jmcneill 	0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,
    133  1.1  jmcneill 	0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,
    134  1.1  jmcneill 	0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,
    135  1.1  jmcneill 	0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,
    136  1.1  jmcneill 	0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,
    137  1.1  jmcneill 	0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4
    138  1.1  jmcneill };
    139  1.1  jmcneill 
    140  1.1  jmcneill static uint32_t
    141  1.1  jmcneill dtv_demux_crc32(uint8_t *buf, int len)
    142  1.1  jmcneill {
    143  1.1  jmcneill 	const uint32_t *crc_tab = crc_table;
    144  1.1  jmcneill 	uint32_t CRC = 0xffffffff;
    145  1.1  jmcneill 	int i;
    146  1.1  jmcneill 
    147  1.1  jmcneill 	for (i = 0; i < len; i++)
    148  1.1  jmcneill 	      	CRC = (CRC << 8) ^ crc_tab[((CRC >> 24) ^ *buf++) & 0xff];
    149  1.1  jmcneill 
    150  1.1  jmcneill 	return CRC;
    151  1.1  jmcneill }
    152  1.1  jmcneill 
    153  1.1  jmcneill int
    154  1.1  jmcneill dtv_demux_open(struct dtv_softc *sc, int flags, int mode, lwp_t *l)
    155  1.1  jmcneill {
    156  1.1  jmcneill 	struct file *fp;
    157  1.1  jmcneill 	struct dtv_demux *demux;
    158  1.1  jmcneill 	int error, fd;
    159  1.1  jmcneill 
    160  1.1  jmcneill 	demux = kmem_zalloc(sizeof(*demux), KM_SLEEP);
    161  1.1  jmcneill 	if (demux == NULL)
    162  1.1  jmcneill 		return ENOMEM;
    163  1.1  jmcneill 	demux->dd_sc = sc;
    164  1.1  jmcneill 	demux->dd_mode = DTV_DEMUX_MODE_NONE;
    165  1.1  jmcneill 	selinit(&demux->dd_sel);
    166  1.1  jmcneill 	mutex_init(&demux->dd_lock, MUTEX_DEFAULT, IPL_VM);
    167  1.1  jmcneill 	cv_init(&demux->dd_section_cv, "dtvsec");
    168  1.1  jmcneill 
    169  1.1  jmcneill 	error = fd_allocfile(&fp, &fd);
    170  1.1  jmcneill 	if (error) {
    171  1.1  jmcneill 		kmem_free(demux, sizeof(*demux));
    172  1.1  jmcneill 		return error;
    173  1.1  jmcneill 	}
    174  1.1  jmcneill 
    175  1.1  jmcneill 	mutex_enter(&sc->sc_demux_lock);
    176  1.1  jmcneill 	TAILQ_INSERT_TAIL(&sc->sc_demux_list, demux, dd_entries);
    177  1.1  jmcneill 	mutex_exit(&sc->sc_demux_lock);
    178  1.1  jmcneill 
    179  1.1  jmcneill 	return fd_clone(fp, fd, flags, &dtv_demux_fileops, demux);
    180  1.1  jmcneill }
    181  1.1  jmcneill 
    182  1.1  jmcneill int
    183  1.1  jmcneill dtv_demux_close(struct file *fp)
    184  1.1  jmcneill {
    185  1.1  jmcneill 	struct dtv_demux *demux = fp->f_data;
    186  1.1  jmcneill 	struct dtv_softc *sc;
    187  1.1  jmcneill 
    188  1.1  jmcneill 	if (demux == NULL)
    189  1.1  jmcneill 		return ENXIO;
    190  1.1  jmcneill 
    191  1.1  jmcneill 	fp->f_data = NULL;
    192  1.1  jmcneill 
    193  1.1  jmcneill 	sc = demux->dd_sc;
    194  1.1  jmcneill 
    195  1.1  jmcneill 	mutex_enter(&sc->sc_demux_lock);
    196  1.1  jmcneill 	TAILQ_REMOVE(&sc->sc_demux_list, demux, dd_entries);
    197  1.1  jmcneill 	mutex_exit(&sc->sc_demux_lock);
    198  1.1  jmcneill 
    199  1.1  jmcneill 	mutex_destroy(&demux->dd_lock);
    200  1.1  jmcneill 	cv_destroy(&demux->dd_section_cv);
    201  1.1  jmcneill 	kmem_free(demux, sizeof(*demux));
    202  1.1  jmcneill 
    203  1.1  jmcneill 	dtv_close_common(sc);
    204  1.1  jmcneill 
    205  1.1  jmcneill 	return 0;
    206  1.1  jmcneill }
    207  1.1  jmcneill 
    208  1.1  jmcneill static int
    209  1.1  jmcneill dtv_demux_ioctl1(struct dtv_demux *demux, u_long cmd, void *data)
    210  1.1  jmcneill {
    211  1.1  jmcneill 	struct dtv_demux *dd;
    212  1.1  jmcneill 	struct dtv_softc *sc;
    213  1.1  jmcneill 	struct dmx_pes_filter_params *pesfilt;
    214  1.1  jmcneill 	struct dmx_sct_filter_params *sctfilt;
    215  1.1  jmcneill 	uint16_t pid;
    216  1.1  jmcneill 	unsigned int demux_running;
    217  1.1  jmcneill 	int error;
    218  1.1  jmcneill 
    219  1.1  jmcneill 	if (demux == NULL)
    220  1.1  jmcneill 		return ENXIO;
    221  1.1  jmcneill 	sc = demux->dd_sc;
    222  1.1  jmcneill 
    223  1.1  jmcneill 	switch (cmd) {
    224  1.1  jmcneill 	case DMX_START:
    225  1.1  jmcneill 		error = 0;
    226  1.1  jmcneill 		demux_running = 0;
    227  1.1  jmcneill 
    228  1.1  jmcneill 		mutex_enter(&sc->sc_demux_lock);
    229  1.1  jmcneill 		TAILQ_FOREACH(dd, &sc->sc_demux_list, dd_entries) {
    230  1.1  jmcneill 			if (dd->dd_running)
    231  1.1  jmcneill 				demux_running++;
    232  1.1  jmcneill 		}
    233  1.1  jmcneill 		if (demux_running == 0) {
    234  1.1  jmcneill 			error = dtv_buffer_setup(sc);
    235  1.1  jmcneill 			if (error)
    236  1.1  jmcneill 				return error;
    237  1.1  jmcneill 			error = dtv_device_start_transfer(sc);
    238  1.1  jmcneill 		}
    239  1.1  jmcneill 		if (error == 0)
    240  1.1  jmcneill 			demux->dd_running = true;
    241  1.1  jmcneill 		mutex_exit(&sc->sc_demux_lock);
    242  1.1  jmcneill 
    243  1.1  jmcneill 		return error;
    244  1.1  jmcneill 	case DMX_STOP:
    245  1.1  jmcneill 		error = 0;
    246  1.1  jmcneill 		demux_running = 0;
    247  1.1  jmcneill 
    248  1.1  jmcneill 		mutex_enter(&sc->sc_demux_lock);
    249  1.1  jmcneill 		demux->dd_running = false;
    250  1.1  jmcneill 		TAILQ_FOREACH(dd, &sc->sc_demux_list, dd_entries) {
    251  1.1  jmcneill 			if (dd->dd_running)
    252  1.1  jmcneill 				demux_running++;
    253  1.1  jmcneill 		}
    254  1.1  jmcneill 		if (demux_running == 0)
    255  1.1  jmcneill 			error = dtv_device_stop_transfer(sc);
    256  1.1  jmcneill 		mutex_exit(&sc->sc_demux_lock);
    257  1.1  jmcneill 
    258  1.1  jmcneill 		return error;
    259  1.1  jmcneill 	case DMX_SET_BUFFER_SIZE:
    260  1.1  jmcneill 		return 0;
    261  1.1  jmcneill 	case DMX_SET_FILTER:
    262  1.1  jmcneill 		sctfilt = data;
    263  1.1  jmcneill 
    264  1.1  jmcneill 		if (sctfilt->pid >= 0x2000)
    265  1.1  jmcneill 			return EINVAL;
    266  1.1  jmcneill 
    267  1.1  jmcneill 		demux->dd_secfilt.params = *sctfilt;
    268  1.1  jmcneill 		demux->dd_secfilt.rp = demux->dd_secfilt.wp = 0;
    269  1.1  jmcneill 		demux->dd_secfilt.nsections = 0;
    270  1.1  jmcneill 		demux->dd_secfilt.overflow = false;
    271  1.1  jmcneill 		demux->dd_mode = DTV_DEMUX_MODE_SECTION;
    272  1.1  jmcneill 
    273  1.1  jmcneill 		if (sctfilt->flags & DMX_IMMEDIATE_START) {
    274  1.1  jmcneill 			error = dtv_demux_ioctl1(demux, DMX_START, NULL);
    275  1.1  jmcneill 			if (error)
    276  1.1  jmcneill 				return error;
    277  1.1  jmcneill 		}
    278  1.1  jmcneill 
    279  1.1  jmcneill 		return 0;
    280  1.1  jmcneill 	case DMX_SET_PES_FILTER:
    281  1.1  jmcneill 		pesfilt = data;
    282  1.1  jmcneill 
    283  1.1  jmcneill 		if (pesfilt->input != DMX_IN_FRONTEND)
    284  1.1  jmcneill 			return EINVAL;
    285  1.1  jmcneill 		if (pesfilt->output != DMX_OUT_TS_TAP)
    286  1.1  jmcneill 			return EINVAL;
    287  1.1  jmcneill 		if (pesfilt->pes_type != DMX_PES_OTHER)
    288  1.1  jmcneill 			return EINVAL;
    289  1.1  jmcneill 
    290  1.1  jmcneill 		error = dtv_demux_ioctl1(demux, DMX_ADD_PID, &pesfilt->pid);
    291  1.1  jmcneill 		if (error)
    292  1.1  jmcneill 			return error;
    293  1.1  jmcneill 
    294  1.1  jmcneill 		if (pesfilt->flags & DMX_IMMEDIATE_START) {
    295  1.1  jmcneill 			error = dtv_demux_ioctl1(demux, DMX_START, NULL);
    296  1.1  jmcneill 			if (error)
    297  1.1  jmcneill 				return error;
    298  1.1  jmcneill 		}
    299  1.1  jmcneill 		return 0;
    300  1.1  jmcneill 	case DMX_ADD_PID:
    301  1.1  jmcneill 		pid = *(uint16_t *)data;
    302  1.1  jmcneill 		if (pid > 0x2000)
    303  1.1  jmcneill 			return EINVAL;
    304  1.1  jmcneill 
    305  1.1  jmcneill 		demux->dd_mode = DTV_DEMUX_MODE_PES;
    306  1.1  jmcneill 		if (pid == 0x2000) {
    307  1.1  jmcneill 			memset(sc->sc_ts.ts_pidfilter, 1,
    308  1.1  jmcneill 			    sizeof(sc->sc_ts.ts_pidfilter));
    309  1.1  jmcneill 		} else {
    310  1.1  jmcneill 			sc->sc_ts.ts_pidfilter[pid] = 1;
    311  1.1  jmcneill 		}
    312  1.1  jmcneill 		return 0;
    313  1.1  jmcneill 	case DMX_REMOVE_PID:
    314  1.1  jmcneill 		pid = *(uint16_t *)data;
    315  1.1  jmcneill 		if (pid > 0x2000)
    316  1.1  jmcneill 			return EINVAL;
    317  1.1  jmcneill 
    318  1.1  jmcneill 		demux->dd_mode = DTV_DEMUX_MODE_PES;
    319  1.1  jmcneill 		if (pid == 0x2000) {
    320  1.1  jmcneill 			memset(sc->sc_ts.ts_pidfilter, 0,
    321  1.1  jmcneill 			    sizeof(sc->sc_ts.ts_pidfilter));
    322  1.1  jmcneill 		} else {
    323  1.1  jmcneill 			sc->sc_ts.ts_pidfilter[pid] = 0;
    324  1.1  jmcneill 		}
    325  1.1  jmcneill 		return 0;
    326  1.1  jmcneill 	default:
    327  1.1  jmcneill 		return EINVAL;
    328  1.1  jmcneill 	}
    329  1.1  jmcneill }
    330  1.1  jmcneill 
    331  1.1  jmcneill int
    332  1.1  jmcneill dtv_demux_ioctl(struct file *fp, u_long cmd, void *data)
    333  1.1  jmcneill {
    334  1.1  jmcneill 	return dtv_demux_ioctl1(fp->f_data, cmd, data);
    335  1.1  jmcneill }
    336  1.1  jmcneill 
    337  1.1  jmcneill static int
    338  1.1  jmcneill dtv_demux_poll(struct file *fp, int events)
    339  1.1  jmcneill {
    340  1.1  jmcneill 	struct dtv_demux *demux = fp->f_data;
    341  1.1  jmcneill 	int revents = 0;
    342  1.1  jmcneill 
    343  1.1  jmcneill 	if (demux == NULL)
    344  1.1  jmcneill 		return POLLERR;
    345  1.1  jmcneill 
    346  1.1  jmcneill 	mutex_enter(&demux->dd_lock);
    347  1.1  jmcneill 	if (demux->dd_secfilt.nsections > 0) {
    348  1.1  jmcneill 		revents |= POLLIN;
    349  1.1  jmcneill 	} else {
    350  1.1  jmcneill 		selrecord(curlwp, &demux->dd_sel);
    351  1.1  jmcneill 	}
    352  1.1  jmcneill 	mutex_exit(&demux->dd_lock);
    353  1.1  jmcneill 
    354  1.1  jmcneill 	return revents;
    355  1.1  jmcneill }
    356  1.1  jmcneill 
    357  1.1  jmcneill static int
    358  1.1  jmcneill dtv_demux_read(struct file *fp, off_t *offp, struct uio *uio,
    359  1.1  jmcneill     kauth_cred_t cred, int flags)
    360  1.1  jmcneill {
    361  1.1  jmcneill 	struct dtv_demux *demux = fp->f_data;
    362  1.1  jmcneill 	struct dtv_ts_section sec;
    363  1.1  jmcneill 	int error;
    364  1.1  jmcneill 
    365  1.1  jmcneill 	if (demux == NULL)
    366  1.1  jmcneill 		return ENXIO;
    367  1.1  jmcneill 
    368  1.1  jmcneill 	if (demux->dd_mode != DTV_DEMUX_MODE_SECTION)
    369  1.1  jmcneill 		return EIO;
    370  1.1  jmcneill 
    371  1.1  jmcneill 	mutex_enter(&demux->dd_lock);
    372  1.1  jmcneill 	while (demux->dd_secfilt.nsections == 0) {
    373  1.1  jmcneill 		if (flags & IO_NDELAY) {
    374  1.1  jmcneill 			mutex_exit(&demux->dd_lock);
    375  1.1  jmcneill 			return EWOULDBLOCK;
    376  1.1  jmcneill 		}
    377  1.1  jmcneill 		error = cv_wait_sig(&demux->dd_section_cv, &demux->dd_lock);
    378  1.1  jmcneill 		if (error) {
    379  1.1  jmcneill 			mutex_exit(&demux->dd_lock);
    380  1.1  jmcneill 			return error;
    381  1.1  jmcneill 		}
    382  1.1  jmcneill 	}
    383  1.1  jmcneill 	sec = demux->dd_secfilt.section[demux->dd_secfilt.rp];
    384  1.1  jmcneill 	demux->dd_secfilt.rp++;
    385  1.1  jmcneill 	if (demux->dd_secfilt.rp >= __arraycount(demux->dd_secfilt.section))
    386  1.1  jmcneill 		demux->dd_secfilt.rp = 0;
    387  1.1  jmcneill 	demux->dd_secfilt.nsections--;
    388  1.1  jmcneill 	mutex_exit(&demux->dd_lock);
    389  1.1  jmcneill 
    390  1.1  jmcneill 	return uiomove(sec.sec_buf, sec.sec_length, uio);
    391  1.1  jmcneill }
    392  1.1  jmcneill 
    393  1.1  jmcneill static bool
    394  1.1  jmcneill dtv_demux_check_crc(struct dtv_demux *demux, struct dtv_ts_section *sec)
    395  1.1  jmcneill {
    396  1.1  jmcneill 	uint32_t crc, sec_crc;
    397  1.1  jmcneill 
    398  1.1  jmcneill 	/* if section_syntax_indicator is not set, there is no CRC */
    399  1.1  jmcneill 	if ((sec->sec_buf[1] & 0x80) == 0)
    400  1.1  jmcneill 		return false;
    401  1.1  jmcneill 
    402  1.1  jmcneill 	sec_crc = be32dec(&sec->sec_buf[sec->sec_length - 4]);
    403  1.1  jmcneill 	crc = dtv_demux_crc32(&sec->sec_buf[0], sec->sec_length - 4);
    404  1.1  jmcneill 
    405  1.1  jmcneill 	return crc == sec_crc;
    406  1.1  jmcneill }
    407  1.1  jmcneill 
    408  1.1  jmcneill int
    409  1.1  jmcneill dtv_demux_write(struct dtv_demux *demux, const uint8_t *tspkt, size_t tspktlen)
    410  1.1  jmcneill {
    411  1.1  jmcneill 	struct dtv_ts_section *sec;
    412  1.1  jmcneill 	dmx_filter_t *dmxfilt = &demux->dd_secfilt.params.filter;
    413  1.1  jmcneill 	const uint8_t *p;
    414  1.1  jmcneill 	uint16_t section_length;
    415  1.1  jmcneill 	int brem, avail;
    416  1.1  jmcneill 
    417  1.1  jmcneill 	KASSERT(tspktlen == TS_PKTLEN);
    418  1.1  jmcneill 
    419  1.1  jmcneill 	if (demux->dd_mode != DTV_DEMUX_MODE_SECTION)
    420  1.1  jmcneill 		return 0;
    421  1.1  jmcneill 	if (TS_PID(tspkt) != demux->dd_secfilt.params.pid)
    422  1.1  jmcneill 		return 0;
    423  1.1  jmcneill 	if (TS_HAS_PAYLOAD(tspkt) == 0)
    424  1.1  jmcneill 		return 0;
    425  1.1  jmcneill 
    426  1.1  jmcneill 	mutex_enter(&demux->dd_lock);
    427  1.1  jmcneill 	if (demux->dd_secfilt.nsections ==
    428  1.1  jmcneill 	    __arraycount(demux->dd_secfilt.section)) {
    429  1.1  jmcneill 		demux->dd_secfilt.overflow = true;
    430  1.1  jmcneill 		goto done;
    431  1.1  jmcneill 	}
    432  1.1  jmcneill 	sec = &demux->dd_secfilt.section[demux->dd_secfilt.wp];
    433  1.1  jmcneill 	/* If we have no bytes in our buffer, wait for payload unit start */
    434  1.1  jmcneill 	if (sec->sec_bytesused == 0 && TS_HAS_PUSI(tspkt) == 0)
    435  1.1  jmcneill 		goto done;
    436  1.1  jmcneill 
    437  1.1  jmcneill 	/* find payload start */
    438  1.1  jmcneill 	p = tspkt + 4;
    439  1.1  jmcneill 	if (TS_HAS_AF(tspkt)) {
    440  1.1  jmcneill 		if (*p > 182)	/* AF length with payload is between 0-182 */
    441  1.1  jmcneill 			goto done;
    442  1.1  jmcneill 		p += (1 + *p);
    443  1.1  jmcneill 	}
    444  1.1  jmcneill 	if (TS_HAS_PUSI(tspkt)) {
    445  1.1  jmcneill 		p += (1 + *p);
    446  1.1  jmcneill 	}
    447  1.1  jmcneill 
    448  1.1  jmcneill 	brem = tspktlen - (p - tspkt);
    449  1.1  jmcneill 
    450  1.1  jmcneill 	if (TS_HAS_PUSI(tspkt)) {
    451  1.1  jmcneill 		if (brem < 16)
    452  1.2  jmcneill 			goto done;
    453  1.1  jmcneill 
    454  1.1  jmcneill 		section_length = ((p[1] & 0xf) << 8) | p[2];
    455  1.1  jmcneill 
    456  1.1  jmcneill 		/* table_id filter */
    457  1.1  jmcneill 		if (dmxfilt->mask[0]) {
    458  1.1  jmcneill 			if ((p[0] & dmxfilt->mask[0]) != dmxfilt->filter[0])
    459  1.1  jmcneill 				goto done;
    460  1.1  jmcneill 		}
    461  1.1  jmcneill 		/* table_id_ext filter */
    462  1.1  jmcneill 		if (dmxfilt->mask[1] && dmxfilt->mask[2]) {
    463  1.1  jmcneill 			if (section_length < 2 || (p[1] & 0x80) == 0)
    464  1.1  jmcneill 				goto done;
    465  1.1  jmcneill 			if ((p[3] & dmxfilt->mask[1]) != dmxfilt->filter[1])
    466  1.1  jmcneill 				goto done;
    467  1.1  jmcneill 			if ((p[4] & dmxfilt->mask[2]) != dmxfilt->filter[2])
    468  1.1  jmcneill 				goto done;
    469  1.1  jmcneill 		}
    470  1.1  jmcneill 
    471  1.1  jmcneill 		sec->sec_length = section_length + 3;
    472  1.3  jmcneill 
    473  1.3  jmcneill 		/* maximum section length is 4KB */
    474  1.3  jmcneill 		if (sec->sec_length > sizeof(sec->sec_buf)) {
    475  1.3  jmcneill 			sec->sec_bytesused = sec->sec_length = 0;
    476  1.3  jmcneill 			goto done;
    477  1.3  jmcneill 		}
    478  1.3  jmcneill 
    479  1.1  jmcneill 	}
    480  1.1  jmcneill 
    481  1.1  jmcneill 	/* If we have bytes pending and we see payload unit start, flush buf */
    482  1.1  jmcneill 	if (sec->sec_bytesused > 0 && TS_HAS_PUSI(tspkt))
    483  1.1  jmcneill 		sec->sec_bytesused = sec->sec_length = 0;
    484  1.1  jmcneill 
    485  1.1  jmcneill 	avail = min(sec->sec_length - sec->sec_bytesused, brem);
    486  1.1  jmcneill 	if (avail < 0)
    487  1.2  jmcneill 		goto done;
    488  1.1  jmcneill 
    489  1.1  jmcneill 	memcpy(&sec->sec_buf[sec->sec_bytesused], p, avail);
    490  1.1  jmcneill 	sec->sec_bytesused += avail;
    491  1.1  jmcneill 
    492  1.1  jmcneill 	if (sec->sec_bytesused == sec->sec_length) {
    493  1.1  jmcneill 		if ((demux->dd_secfilt.params.flags & DMX_CHECK_CRC) &&
    494  1.1  jmcneill 		    dtv_demux_check_crc(demux, sec) == false) {
    495  1.1  jmcneill 			/* discard packet */
    496  1.1  jmcneill 			sec->sec_bytesused = sec->sec_length = 0;
    497  1.1  jmcneill 			goto done;
    498  1.1  jmcneill 		}
    499  1.1  jmcneill 
    500  1.1  jmcneill 		demux->dd_secfilt.wp++;
    501  1.1  jmcneill 		if (demux->dd_secfilt.wp >=
    502  1.1  jmcneill 		    __arraycount(demux->dd_secfilt.section))
    503  1.1  jmcneill 			demux->dd_secfilt.wp = 0;
    504  1.1  jmcneill 		demux->dd_secfilt.nsections++;
    505  1.1  jmcneill 		cv_broadcast(&demux->dd_section_cv);
    506  1.1  jmcneill 		selnotify(&demux->dd_sel, 0, 0);
    507  1.1  jmcneill 
    508  1.1  jmcneill 		if (demux->dd_secfilt.params.flags & DMX_ONESHOT)
    509  1.1  jmcneill 			dtv_demux_ioctl1(demux, DMX_STOP, NULL);
    510  1.1  jmcneill 	}
    511  1.1  jmcneill 
    512  1.1  jmcneill done:
    513  1.1  jmcneill 	mutex_exit(&demux->dd_lock);
    514  1.1  jmcneill 	return 0;
    515  1.1  jmcneill }
    516  1.1  jmcneill 
    517