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