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