dtv_device.c revision 1.7 1 /* $NetBSD: dtv_device.c,v 1.7 2011/07/16 12:20:01 jmcneill 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.7 2011/07/16 12:20:01 jmcneill 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
305 int
306 dtv_print(void *arg, const char *pnp)
307 {
308 if (pnp)
309 aprint_normal("dtv at %s", pnp);
310
311 return UNCONF;
312 }
313