1 /* $NetBSD: dtv_device.c,v 1.14 2022/03/31 19:30:15 pgoyette Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 Jared D. McNeill <jmcneill (at) invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. All advertising materials mentioning features or use of this software 16 * must display the following acknowledgement: 17 * This product includes software developed by Jared D. McNeill. 18 * 4. Neither the name of The NetBSD Foundation nor the names of its 19 * contributors may be used to endorse or promote products derived 20 * from this software without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __KERNEL_RCSID(0, "$NetBSD: dtv_device.c,v 1.14 2022/03/31 19:30:15 pgoyette Exp $"); 37 38 #include <sys/param.h> 39 #include <sys/types.h> 40 #include <sys/atomic.h> 41 #include <sys/conf.h> 42 #include <sys/device.h> 43 #include <sys/module.h> 44 #include <sys/poll.h> 45 #include <sys/select.h> 46 47 #include <dev/dtv/dtvvar.h> 48 49 #include "ioconf.h" 50 51 MODULE(MODULE_CLASS_DRIVER, dtv, NULL); 52 53 static dev_type_open(dtvopen); 54 static dev_type_close(dtvclose); 55 static dev_type_read(dtvread); 56 static dev_type_ioctl(dtvioctl); 57 static dev_type_poll(dtvpoll); 58 59 const struct cdevsw dtv_cdevsw = { 60 .d_open = dtvopen, 61 .d_close = dtvclose, 62 .d_read = dtvread, 63 .d_write = nowrite, 64 .d_ioctl = dtvioctl, 65 .d_stop = nostop, 66 .d_tty = notty, 67 .d_poll = dtvpoll, 68 .d_mmap = nommap, 69 .d_kqfilter = nokqfilter, 70 .d_discard = nodiscard, 71 .d_flag = D_OTHER | D_MPSAFE, 72 }; 73 74 static int dtv_match(device_t, cfdata_t, void *); 75 static void dtv_attach(device_t, device_t, void *); 76 static int dtv_detach(device_t, int); 77 78 CFATTACH_DECL_NEW(dtv, 79 sizeof(struct dtv_softc), 80 dtv_match, 81 dtv_attach, 82 dtv_detach, 83 NULL 84 ); 85 86 static int 87 dtv_match(device_t parent, cfdata_t cfdata, void *aa) 88 { 89 return 1; 90 } 91 92 static void 93 dtv_attach(device_t parent, device_t self, void *aa) 94 { 95 struct dtv_attach_args *daa = aa; 96 struct dtv_softc *sc = device_private(self); 97 struct dtv_stream *ds = &sc->sc_stream; 98 struct dvb_frontend_info info; 99 100 sc->sc_dev = self; 101 sc->sc_hw = daa->hw; 102 sc->sc_priv = daa->priv; 103 sc->sc_open = 0; 104 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 105 106 ds->ds_nbufs = 0; 107 ds->ds_buf = NULL; 108 SIMPLEQ_INIT(&ds->ds_ingress); 109 SIMPLEQ_INIT(&ds->ds_egress); 110 mutex_init(&ds->ds_egress_lock, MUTEX_DEFAULT, IPL_SCHED); 111 mutex_init(&ds->ds_ingress_lock, MUTEX_DEFAULT, IPL_SCHED); 112 cv_init(&ds->ds_sample_cv, "dtv"); 113 selinit(&ds->ds_sel); 114 dtv_scatter_buf_init(&ds->ds_data); 115 if (dtv_buffer_realloc(sc, DTV_DEFAULT_BUFSIZE) != 0) { 116 aprint_error(": no memory\n"); 117 sc->sc_dying = true; 118 return; 119 } 120 121 mutex_init(&sc->sc_demux_lock, MUTEX_DEFAULT, IPL_SCHED); 122 TAILQ_INIT(&sc->sc_demux_list); 123 sc->sc_demux_runcnt = 0; 124 125 dtv_device_get_devinfo(sc, &info); 126 127 aprint_naive("\n"); 128 aprint_normal(": %s", info.name); 129 switch (info.type) { 130 case FE_QPSK: 131 aprint_normal(" [QPSK]"); 132 break; 133 case FE_QAM: 134 aprint_normal(" [QAM]"); 135 break; 136 case FE_OFDM: 137 aprint_normal(" [OFDM]"); 138 break; 139 case FE_ATSC: 140 aprint_normal(" [ATSC]"); 141 break; 142 } 143 aprint_normal("\n"); 144 } 145 146 static int 147 dtv_detach(device_t self, int flags) 148 { 149 struct dtv_softc *sc = device_private(self); 150 struct dtv_stream *ds = &sc->sc_stream; 151 152 cv_destroy(&ds->ds_sample_cv); 153 mutex_destroy(&ds->ds_ingress_lock); 154 mutex_destroy(&ds->ds_egress_lock); 155 seldestroy(&ds->ds_sel); 156 dtv_buffer_realloc(sc, 0); 157 dtv_scatter_buf_destroy(&ds->ds_data); 158 159 mutex_destroy(&sc->sc_demux_lock); 160 mutex_destroy(&sc->sc_lock); 161 162 return 0; 163 } 164 165 #ifdef _MODULE 166 #include "ioconf.c" 167 #endif 168 169 static int 170 dtv_modcmd(modcmd_t cmd, void *arg) 171 { 172 #ifdef _MODULE 173 int error, bmaj = -1, cmaj = -1; 174 #endif 175 176 switch (cmd) { 177 case MODULE_CMD_INIT: 178 #ifdef _MODULE 179 error = devsw_attach("dtv", NULL, &bmaj, &dtv_cdevsw, &cmaj); 180 if (error) 181 return error; 182 183 error = config_init_component(cfdriver_ioconf_dtv, 184 cfattach_ioconf_dtv, cfdata_ioconf_dtv); 185 if (error) 186 devsw_detach(NULL, &dtv_cdevsw); 187 return error; 188 #else 189 return 0; 190 #endif 191 case MODULE_CMD_FINI: 192 #ifdef _MODULE 193 error = config_fini_component(cfdriver_ioconf_dtv, 194 cfattach_ioconf_dtv, cfdata_ioconf_dtv); 195 if (error == 0) 196 devsw_detach(NULL, &dtv_cdevsw); 197 198 return error; 199 #else 200 return 0; 201 #endif 202 default: 203 return ENOTTY; 204 } 205 } 206 207 static int 208 dtvopen(dev_t dev, int flags, int mode, lwp_t *l) 209 { 210 struct dtv_softc *sc; 211 struct dtv_ts *ts; 212 int error; 213 214 if ((sc = device_lookup_private(&dtv_cd, DTVUNIT(dev))) == NULL) 215 return ENXIO; 216 if (sc->sc_dying == true) 217 return ENODEV; 218 ts = &sc->sc_ts; 219 220 mutex_enter(&sc->sc_lock); 221 if (sc->sc_open == 0) { 222 error = dtv_device_open(sc, flags); 223 if (error) 224 return error; 225 sc->sc_bufsize = DTV_DEFAULT_BUFSIZE; 226 sc->sc_bufsize_chg = true; 227 memset(ts->ts_pidfilter, 0, sizeof(ts->ts_pidfilter)); 228 } 229 ++sc->sc_open; 230 mutex_exit(&sc->sc_lock); 231 232 if (ISDTVDEMUX(dev)) 233 return dtv_demux_open(sc, flags, mode, l); 234 235 return 0; 236 } 237 238 static int 239 dtvclose(dev_t dev, int flags, int mode, lwp_t *l) 240 { 241 struct dtv_softc *sc; 242 243 if ((sc = device_lookup_private(&dtv_cd, DTVUNIT(dev))) == NULL) 244 return ENXIO; 245 246 dtv_common_close(sc); 247 248 return 0; 249 } 250 251 static int 252 dtvread(dev_t dev, struct uio *uio, int flags) 253 { 254 struct dtv_softc *sc; 255 256 if ((sc = device_lookup_private(&dtv_cd, DTVUNIT(dev))) == NULL) 257 return ENXIO; 258 259 if (ISDTVDVR(dev)) 260 return dtv_buffer_read(sc, uio, flags); 261 262 return ENXIO; 263 } 264 265 static int 266 dtvioctl(dev_t dev, u_long cmd, void *ptr, int flags, lwp_t *l) 267 { 268 struct dtv_softc *sc; 269 270 if ((sc = device_lookup_private(&dtv_cd, DTVUNIT(dev))) == NULL) 271 return ENXIO; 272 273 if (ISDTVFRONTEND(dev)) { 274 return dtv_frontend_ioctl(sc, cmd, ptr, flags); 275 } 276 277 return EINVAL; 278 } 279 280 static int 281 dtvpoll(dev_t dev, int events, lwp_t *l) 282 { 283 struct dtv_softc *sc; 284 285 if ((sc = device_lookup_private(&dtv_cd, DTVUNIT(dev))) == NULL) 286 return POLLERR; 287 288 if (ISDTVFRONTEND(dev)) { 289 return POLLPRI|POLLIN; /* XXX event */ 290 } else if (ISDTVDVR(dev)) { 291 return dtv_buffer_poll(sc, events, l); 292 } 293 294 return POLLERR; 295 } 296 297 void 298 dtv_common_close(struct dtv_softc *sc) 299 { 300 mutex_enter(&sc->sc_lock); 301 KASSERT(sc->sc_open > 0); 302 --sc->sc_open; 303 if (sc->sc_open == 0) { 304 dtv_device_close(sc); 305 dtv_buffer_destroy(sc); 306 } 307 mutex_exit(&sc->sc_lock); 308 } 309