1 /* $NetBSD: dtv_device.c,v 1.9 2014/03/16 05:20:27 dholland Exp $ */ 2 3 /*- 4 * Copyright (c) 2011 Jared D. McNeill <jmcneill@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.9 2014/03/16 05:20:27 dholland Exp $"); 37 38 #include <sys/types.h> 39 #include <sys/conf.h> 40 #include <sys/device.h> 41 #include <sys/atomic.h> 42 #include <sys/module.h> 43 #include <sys/poll.h> 44 #include <sys/select.h> 45 46 #include <dev/dtv/dtvvar.h> 47 48 MODULE(MODULE_CLASS_DRIVER, dtv, NULL); 49 50 static dev_type_open(dtvopen); 51 static dev_type_close(dtvclose); 52 static dev_type_read(dtvread); 53 static dev_type_ioctl(dtvioctl); 54 static dev_type_poll(dtvpoll); 55 56 const struct cdevsw dtv_cdevsw = { 57 .d_open = dtvopen, 58 .d_close = dtvclose, 59 .d_read = dtvread, 60 .d_write = nowrite, 61 .d_ioctl = dtvioctl, 62 .d_stop = nostop, 63 .d_tty = notty, 64 .d_poll = dtvpoll, 65 .d_mmap = nommap, 66 .d_kqfilter = nokqfilter, 67 .d_flag = D_OTHER | D_MPSAFE, 68 }; 69 70 static int dtv_match(device_t, cfdata_t, void *); 71 static void dtv_attach(device_t, device_t, void *); 72 static int dtv_detach(device_t, int); 73 74 CFATTACH_DECL_NEW(dtv, 75 sizeof(struct dtv_softc), 76 dtv_match, 77 dtv_attach, 78 dtv_detach, 79 NULL 80 ); 81 82 extern struct cfdriver dtv_cd; 83 84 static int 85 dtv_match(device_t parent, cfdata_t cfdata, void *aa) 86 { 87 return 1; 88 } 89 90 static void 91 dtv_attach(device_t parent, device_t self, void *aa) 92 { 93 struct dtv_attach_args *daa = aa; 94 struct dtv_softc *sc = device_private(self); 95 struct dtv_stream *ds = &sc->sc_stream; 96 struct dvb_frontend_info info; 97 98 sc->sc_dev = self; 99 sc->sc_hw = daa->hw; 100 sc->sc_priv = daa->priv; 101 sc->sc_open = 0; 102 mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_NONE); 103 104 ds->ds_nbufs = 0; 105 ds->ds_buf = NULL; 106 SIMPLEQ_INIT(&ds->ds_ingress); 107 SIMPLEQ_INIT(&ds->ds_egress); 108 mutex_init(&ds->ds_egress_lock, MUTEX_DEFAULT, IPL_VM); 109 mutex_init(&ds->ds_ingress_lock, MUTEX_DEFAULT, IPL_VM); 110 cv_init(&ds->ds_sample_cv, "dtv"); 111 selinit(&ds->ds_sel); 112 dtv_scatter_buf_init(&ds->ds_data); 113 if (dtv_buffer_realloc(sc, DTV_DEFAULT_BUFSIZE) != 0) { 114 aprint_error(": no memory\n"); 115 sc->sc_dying = true; 116 return; 117 } 118 119 mutex_init(&sc->sc_demux_lock, MUTEX_DEFAULT, IPL_VM); 120 TAILQ_INIT(&sc->sc_demux_list); 121 sc->sc_demux_runcnt = 0; 122 123 dtv_device_get_devinfo(sc, &info); 124 125 aprint_naive("\n"); 126 aprint_normal(": %s", info.name); 127 switch (info.type) { 128 case FE_QPSK: 129 aprint_normal(" [QPSK]"); 130 break; 131 case FE_QAM: 132 aprint_normal(" [QAM]"); 133 break; 134 case FE_OFDM: 135 aprint_normal(" [OFDM]"); 136 break; 137 case FE_ATSC: 138 aprint_normal(" [ATSC]"); 139 break; 140 } 141 aprint_normal("\n"); 142 } 143 144 static int 145 dtv_detach(device_t self, int flags) 146 { 147 struct dtv_softc *sc = device_private(self); 148 struct dtv_stream *ds = &sc->sc_stream; 149 150 cv_destroy(&ds->ds_sample_cv); 151 mutex_destroy(&ds->ds_ingress_lock); 152 mutex_destroy(&ds->ds_egress_lock); 153 seldestroy(&ds->ds_sel); 154 dtv_buffer_realloc(sc, 0); 155 dtv_scatter_buf_destroy(&ds->ds_data); 156 157 mutex_destroy(&sc->sc_demux_lock); 158 mutex_destroy(&sc->sc_lock); 159 160 return 0; 161 } 162 163 #ifdef _MODULE 164 #include "ioconf.c" 165 #endif 166 167 static int 168 dtv_modcmd(modcmd_t cmd, void *arg) 169 { 170 #ifdef _MODULE 171 int error, bmaj = -1, cmaj = -1; 172 #endif 173 174 switch (cmd) { 175 case MODULE_CMD_INIT: 176 #ifdef _MODULE 177 error = config_init_component(cfdriver_ioconf_dtv, 178 cfattach_ioconf_dtv, cfdata_ioconf_dtv); 179 if (error) 180 return error; 181 error = devsw_attach("dtv", NULL, &bmaj, &dtv_cdevsw, &cmaj); 182 if (error) 183 config_fini_component(cfdriver_ioconf_dtv, 184 cfattach_ioconf_dtv, cfdata_ioconf_dtv); 185 return error; 186 #else 187 return 0; 188 #endif 189 case MODULE_CMD_FINI: 190 #ifdef _MODULE 191 devsw_detach(NULL, &dtv_cdevsw); 192 return config_fini_component(cfdriver_ioconf_dtv, 193 cfattach_ioconf_dtv, cfdata_ioconf_dtv); 194 #else 195 return 0; 196 #endif 197 default: 198 return ENOTTY; 199 } 200 } 201 202 static int 203 dtvopen(dev_t dev, int flags, int mode, lwp_t *l) 204 { 205 struct dtv_softc *sc; 206 struct dtv_ts *ts; 207 int error; 208 209 if ((sc = device_lookup_private(&dtv_cd, DTVUNIT(dev))) == NULL) 210 return ENXIO; 211 if (sc->sc_dying == true) 212 return ENODEV; 213 ts = &sc->sc_ts; 214 215 mutex_enter(&sc->sc_lock); 216 if (sc->sc_open == 0) { 217 error = dtv_device_open(sc, flags); 218 if (error) 219 return error; 220 sc->sc_bufsize = DTV_DEFAULT_BUFSIZE; 221 sc->sc_bufsize_chg = true; 222 memset(ts->ts_pidfilter, 0, sizeof(ts->ts_pidfilter)); 223 } 224 ++sc->sc_open; 225 mutex_exit(&sc->sc_lock); 226 227 if (ISDTVDEMUX(dev)) 228 return dtv_demux_open(sc, flags, mode, l); 229 230 return 0; 231 } 232 233 static int 234 dtvclose(dev_t dev, int flags, int mode, lwp_t *l) 235 { 236 struct dtv_softc *sc; 237 238 if ((sc = device_lookup_private(&dtv_cd, DTVUNIT(dev))) == NULL) 239 return ENXIO; 240 241 dtv_common_close(sc); 242 243 return 0; 244 } 245 246 static int 247 dtvread(dev_t dev, struct uio *uio, int flags) 248 { 249 struct dtv_softc *sc; 250 251 if ((sc = device_lookup_private(&dtv_cd, DTVUNIT(dev))) == NULL) 252 return ENXIO; 253 254 if (ISDTVDVR(dev)) 255 return dtv_buffer_read(sc, uio, flags); 256 257 return ENXIO; 258 } 259 260 static int 261 dtvioctl(dev_t dev, u_long cmd, void *ptr, int flags, lwp_t *l) 262 { 263 struct dtv_softc *sc; 264 265 if ((sc = device_lookup_private(&dtv_cd, DTVUNIT(dev))) == NULL) 266 return ENXIO; 267 268 if (ISDTVFRONTEND(dev)) { 269 return dtv_frontend_ioctl(sc, cmd, ptr, flags); 270 } 271 272 return EINVAL; 273 } 274 275 static int 276 dtvpoll(dev_t dev, int events, lwp_t *l) 277 { 278 struct dtv_softc *sc; 279 280 if ((sc = device_lookup_private(&dtv_cd, DTVUNIT(dev))) == NULL) 281 return POLLERR; 282 283 if (ISDTVFRONTEND(dev)) { 284 return POLLPRI|POLLIN; /* XXX event */ 285 } else if (ISDTVDVR(dev)) { 286 return dtv_buffer_poll(sc, events, l); 287 } 288 289 return POLLERR; 290 } 291 292 void 293 dtv_common_close(struct dtv_softc *sc) 294 { 295 mutex_enter(&sc->sc_lock); 296 KASSERT(sc->sc_open > 0); 297 --sc->sc_open; 298 if (sc->sc_open == 0) { 299 dtv_device_close(sc); 300 dtv_buffer_destroy(sc); 301 } 302 mutex_exit(&sc->sc_lock); 303 } 304