xref: /netbsd-src/sys/dev/wscons/wsbell.c (revision 97f8debd624665fdeaf9373bf4602036de3fcd85)
1*97f8debdSpgoyette /* $NetBSD: wsbell.c,v 1.14 2022/03/31 19:30:17 pgoyette Exp $ */
2b377bbb3Snat 
3b377bbb3Snat /*-
4b377bbb3Snat  * Copyright (c) 2017 Nathanial Sloss <nathanialsloss@yahoo.com.au>
5b377bbb3Snat  * All rights reserved.
6b377bbb3Snat  *
7b377bbb3Snat  * Copyright (c) 2006 The NetBSD Foundation, Inc.
8b377bbb3Snat  * All rights reserved.
9b377bbb3Snat  *
10b377bbb3Snat  * This code is derived from software contributed to The NetBSD Foundation
11b377bbb3Snat  * by Julio M. Merino Vidal.
12b377bbb3Snat  *
13b377bbb3Snat  * Redistribution and use in source and binary forms, with or without
14b377bbb3Snat  * modification, are permitted provided that the following conditions
15b377bbb3Snat  * are met:
16b377bbb3Snat  * 1. Redistributions of source code must retain the above copyright
17b377bbb3Snat  *    notice, this list of conditions and the following disclaimer.
18b377bbb3Snat  * 2. Redistributions in binary form must reproduce the above copyright
19b377bbb3Snat  *    notice, this list of conditions and the following disclaimer in the
20b377bbb3Snat  *    documentation and/or other materials provided with the distribution.
21b377bbb3Snat  *
22b377bbb3Snat  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
23b377bbb3Snat  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
24b377bbb3Snat  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
25b377bbb3Snat  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
26b377bbb3Snat  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
27b377bbb3Snat  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
28b377bbb3Snat  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
29b377bbb3Snat  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
30b377bbb3Snat  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
31b377bbb3Snat  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32b377bbb3Snat  * POSSIBILITY OF SUCH DAMAGE.
33b377bbb3Snat  */
34b377bbb3Snat 
35b377bbb3Snat /*
36b377bbb3Snat  * Copyright (c) 1996, 1997 Christopher G. Demetriou.  All rights reserved.
37b377bbb3Snat  *
38b377bbb3Snat  * Redistribution and use in source and binary forms, with or without
39b377bbb3Snat  * modification, are permitted provided that the following conditions
40b377bbb3Snat  * are met:
41b377bbb3Snat  * 1. Redistributions of source code must retain the above copyright
42b377bbb3Snat  *    notice, this list of conditions and the following disclaimer.
43b377bbb3Snat  * 2. Redistributions in binary form must reproduce the above copyright
44b377bbb3Snat  *    notice, this list of conditions and the following disclaimer in the
45b377bbb3Snat  *    documentation and/or other materials provided with the distribution.
46b377bbb3Snat  * 3. All advertising materials mentioning features or use of this software
47b377bbb3Snat  *    must display the following acknowledgement:
48b377bbb3Snat  *      This product includes software developed by Christopher G. Demetriou
49b377bbb3Snat  *	for the NetBSD Project.
50b377bbb3Snat  * 4. The name of the author may not be used to endorse or promote products
51b377bbb3Snat  *    derived from this software without specific prior written permission
52b377bbb3Snat  *
53b377bbb3Snat  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
54b377bbb3Snat  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
55b377bbb3Snat  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
56b377bbb3Snat  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
57b377bbb3Snat  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
58b377bbb3Snat  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
59b377bbb3Snat  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
60b377bbb3Snat  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
61b377bbb3Snat  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
62b377bbb3Snat  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
63b377bbb3Snat  */
64b377bbb3Snat 
65b377bbb3Snat /*
66b377bbb3Snat  * Copyright (c) 1992, 1993
67b377bbb3Snat  *	The Regents of the University of California.  All rights reserved.
68b377bbb3Snat  *
69b377bbb3Snat  * This software was developed by the Computer Systems Engineering group
70b377bbb3Snat  * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and
71b377bbb3Snat  * contributed to Berkeley.
72b377bbb3Snat  *
73b377bbb3Snat  * All advertising materials mentioning features or use of this software
74b377bbb3Snat  * must display the following acknowledgement:
75b377bbb3Snat  *	This product includes software developed by the University of
76b377bbb3Snat  *	California, Lawrence Berkeley Laboratory.
77b377bbb3Snat  *
78b377bbb3Snat  * Redistribution and use in source and binary forms, with or without
79b377bbb3Snat  * modification, are permitted provided that the following conditions
80b377bbb3Snat  * are met:
81b377bbb3Snat  * 1. Redistributions of source code must retain the above copyright
82b377bbb3Snat  *    notice, this list of conditions and the following disclaimer.
83b377bbb3Snat  * 2. Redistributions in binary form must reproduce the above copyright
84b377bbb3Snat  *    notice, this list of conditions and the following disclaimer in the
85b377bbb3Snat  *    documentation and/or other materials provided with the distribution.
86b377bbb3Snat  * 3. Neither the name of the University nor the names of its contributors
87b377bbb3Snat  *    may be used to endorse or promote products derived from this software
88b377bbb3Snat  *    without specific prior written permission.
89b377bbb3Snat  *
90b377bbb3Snat  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
91b377bbb3Snat  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
92b377bbb3Snat  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
93b377bbb3Snat  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
94b377bbb3Snat  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
95b377bbb3Snat  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
96b377bbb3Snat  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
97b377bbb3Snat  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
98b377bbb3Snat  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
99b377bbb3Snat  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
100b377bbb3Snat  * SUCH DAMAGE.
101b377bbb3Snat  *
102b377bbb3Snat  *	@(#)ms.c	8.1 (Berkeley) 6/11/93
103b377bbb3Snat  */
104b377bbb3Snat 
105b377bbb3Snat /*
106b377bbb3Snat  * Keyboard Bell driver.
107b377bbb3Snat  */
108b377bbb3Snat 
109b377bbb3Snat #include <sys/cdefs.h>
110*97f8debdSpgoyette __KERNEL_RCSID(0, "$NetBSD: wsbell.c,v 1.14 2022/03/31 19:30:17 pgoyette Exp $");
111b377bbb3Snat 
11218b626fcSpgoyette #if defined(_KERNEL_OPT)
113b377bbb3Snat #include "wsmux.h"
11418b626fcSpgoyette #endif
115b377bbb3Snat 
116b377bbb3Snat #include <sys/param.h>
117b377bbb3Snat #include <sys/conf.h>
118b377bbb3Snat #include <sys/ioctl.h>
119b377bbb3Snat #include <sys/poll.h>
120b377bbb3Snat #include <sys/fcntl.h>
121b377bbb3Snat #include <sys/kernel.h>
122b377bbb3Snat #include <sys/condvar.h>
123b377bbb3Snat #include <sys/mutex.h>
1240e2e153aSnat #include <sys/kauth.h>
125b377bbb3Snat #include <sys/kthread.h>
126b377bbb3Snat #include <sys/proc.h>
127b377bbb3Snat #include <sys/syslog.h>
128b377bbb3Snat #include <sys/systm.h>
129b377bbb3Snat #include <sys/tty.h>
130b377bbb3Snat #include <sys/signalvar.h>
131b377bbb3Snat #include <sys/device.h>
132b377bbb3Snat #include <sys/vnode.h>
133b377bbb3Snat #include <sys/callout.h>
13418b626fcSpgoyette #include <sys/module.h>
135b377bbb3Snat 
136b377bbb3Snat #include <dev/wscons/wsconsio.h>
137b377bbb3Snat #include <dev/wscons/wsbellvar.h>
138b377bbb3Snat #include <dev/wscons/wsbellmuxvar.h>
139b377bbb3Snat #include <dev/wscons/wsbelldata.h>
140b377bbb3Snat 
141b377bbb3Snat #include <dev/spkrio.h>
142b377bbb3Snat 
14318b626fcSpgoyette #include "ioconf.h"
14418b626fcSpgoyette 
145b377bbb3Snat #if defined(WSMUX_DEBUG) && NWSMUX > 0
146b377bbb3Snat #define DPRINTF(x)	if (wsmuxdebug) printf x
147b377bbb3Snat #define DPRINTFN(n,x)	if (wsmuxdebug > (n)) printf x
148b377bbb3Snat extern int wsmuxdebug;
149b377bbb3Snat #else
150b377bbb3Snat #define DPRINTF(x)
151b377bbb3Snat #define DPRINTFN(n,x)
152b377bbb3Snat #endif
153b377bbb3Snat 
154b377bbb3Snat static void bell_thread(void *);
155b377bbb3Snat static inline void spkr_audio_play(struct wsbell_softc *, u_int, u_int, u_int);
156b377bbb3Snat 
157b377bbb3Snat static int  wsbell_match(device_t, cfdata_t, void *);
158b377bbb3Snat static void wsbell_attach(device_t, device_t, void *);
159b377bbb3Snat static int  wsbell_detach(device_t, int);
160b377bbb3Snat static int  wsbell_activate(device_t, enum devact);
161b377bbb3Snat 
162b377bbb3Snat #if NWSMUX > 0
163b377bbb3Snat static int  wsbell_mux_open(struct wsevsrc *, struct wseventvar *);
164b377bbb3Snat static int  wsbell_mux_close(struct wsevsrc *);
165b377bbb3Snat 
166b377bbb3Snat static int  wsbelldoopen(struct wsbell_softc *, struct wseventvar *);
167b377bbb3Snat static int  wsbelldoioctl(device_t, u_long, void *, int, struct lwp *);
168b377bbb3Snat 
169b377bbb3Snat static int  wsbell_do_ioctl(struct wsbell_softc *, u_long, void *,
170b377bbb3Snat 			     int, struct lwp *);
171b377bbb3Snat 
172b377bbb3Snat #endif
173b377bbb3Snat 
174b377bbb3Snat CFATTACH_DECL_NEW(wsbell, sizeof (struct wsbell_softc),
175b377bbb3Snat     wsbell_match, wsbell_attach, wsbell_detach, wsbell_activate);
176b377bbb3Snat 
177b377bbb3Snat extern dev_type_open(spkropen);
178b377bbb3Snat extern dev_type_close(spkrclose);
179b377bbb3Snat extern dev_type_ioctl(spkrioctl);
180b377bbb3Snat 
181b377bbb3Snat const struct cdevsw wsbell_cdevsw = {
182b377bbb3Snat 	.d_open = noopen,
183b377bbb3Snat 	.d_close = noclose,
184b377bbb3Snat 	.d_read = noread,
185b377bbb3Snat 	.d_write = nowrite,
186b377bbb3Snat 	.d_ioctl = noioctl,
187b377bbb3Snat 	.d_stop = nostop,
188b377bbb3Snat 	.d_tty = notty,
189b377bbb3Snat 	.d_poll = nopoll,
190b377bbb3Snat 	.d_mmap = nommap,
191b377bbb3Snat 	.d_kqfilter = nokqfilter,
192b377bbb3Snat 	.d_discard = nodiscard,
193b377bbb3Snat 	.d_flag = D_OTHER
194b377bbb3Snat };
195b377bbb3Snat 
196b377bbb3Snat #if NWSMUX > 0
197b377bbb3Snat struct wssrcops wsbell_srcops = {
198b377bbb3Snat 	WSMUX_BELL,
199b377bbb3Snat 	wsbell_mux_open, wsbell_mux_close, wsbelldoioctl, wsbelldoioctl, NULL
200b377bbb3Snat };
201b377bbb3Snat #endif
202b377bbb3Snat 
203b377bbb3Snat int
wsbell_match(device_t parent,cfdata_t match,void * aux)204b377bbb3Snat wsbell_match(device_t parent, cfdata_t match, void *aux)
205b377bbb3Snat {
206b377bbb3Snat 	return (1);
207b377bbb3Snat }
208b377bbb3Snat 
209b377bbb3Snat void
wsbell_attach(device_t parent,device_t self,void * aux)210b377bbb3Snat wsbell_attach(device_t parent, device_t self, void *aux)
211b377bbb3Snat {
212b377bbb3Snat 	struct wsbell_softc *sc = device_private(self);
213b377bbb3Snat 	struct wsbelldev_attach_args *ap = aux;
214b377bbb3Snat #if NWSMUX > 0
215b377bbb3Snat 	int mux, error;
216b377bbb3Snat #endif
217b377bbb3Snat 
218b377bbb3Snat 	sc->sc_base.me_dv = self;
219b377bbb3Snat 	sc->sc_accesscookie = ap->accesscookie;
220b377bbb3Snat 
2215e64cb49Snat 	sc->sc_dying = false;
222b377bbb3Snat 	sc->sc_spkr = device_unit(parent);
223b377bbb3Snat 	sc->sc_bell_data = wskbd_default_bell_data;
224b377bbb3Snat #if NWSMUX > 0
225b377bbb3Snat 	sc->sc_base.me_ops = &wsbell_srcops;
226b377bbb3Snat 	mux = device_cfdata(self)->wsbelldevcf_mux;
227b377bbb3Snat 	if (mux >= 0) {
228b377bbb3Snat 		error = wsmux_attach_sc(wsmux_getmux(mux), &sc->sc_base);
229b377bbb3Snat 		if (error)
230b377bbb3Snat 			aprint_error(" attach error=%d", error);
231b377bbb3Snat 		else
232b377bbb3Snat 			aprint_normal(" mux %d", mux);
233b377bbb3Snat 	}
234b377bbb3Snat #else
235b377bbb3Snat 	if (device_cfdata(self)->wsbelldevcf_mux >= 0)
236b377bbb3Snat 		aprint_normal(" (mux ignored)");
237b377bbb3Snat #endif
238b377bbb3Snat 
239b377bbb3Snat 	aprint_naive("\n");
240b377bbb3Snat 	aprint_normal("\n");
241b377bbb3Snat 
242b377bbb3Snat 	if (!pmf_device_register(self, NULL, NULL))
243b377bbb3Snat 		aprint_error_dev(self, "couldn't establish power handler\n");
244b377bbb3Snat 
245b377bbb3Snat 	mutex_init(&sc->sc_bellock, MUTEX_DEFAULT, IPL_SCHED);
246b377bbb3Snat 	cv_init(&sc->sc_bellcv, "bellcv");
247b377bbb3Snat 
248b377bbb3Snat 	kthread_create(PRI_BIO, KTHREAD_MPSAFE | KTHREAD_MUSTJOIN, NULL,
249b377bbb3Snat 	    bell_thread, sc, &sc->sc_bellthread, "%s", device_xname(self));
250b377bbb3Snat }
251b377bbb3Snat 
252b377bbb3Snat int
wsbell_activate(device_t self,enum devact act)253b377bbb3Snat wsbell_activate(device_t self, enum devact act)
254b377bbb3Snat {
255b377bbb3Snat 	struct wsbell_softc *sc = device_private(self);
256b377bbb3Snat 
257b377bbb3Snat 	if (act == DVACT_DEACTIVATE)
2585e64cb49Snat 		sc->sc_dying = true;
259b377bbb3Snat 	return (0);
260b377bbb3Snat }
261b377bbb3Snat 
262b377bbb3Snat int
wsbell_detach(device_t self,int flags)263b377bbb3Snat wsbell_detach(device_t self, int flags)
264b377bbb3Snat {
265b377bbb3Snat 	struct wsbell_softc *sc = device_private(self);
266b377bbb3Snat 	struct wseventvar *evar;
267b377bbb3Snat 	int maj, mn;
268b377bbb3Snat 	int s;
269b377bbb3Snat 
270b377bbb3Snat #if NWSMUX > 0
271b377bbb3Snat 	/* Tell parent mux we're leaving. */
272b377bbb3Snat 	if (sc->sc_base.me_parent != NULL) {
273b377bbb3Snat 		DPRINTF(("wsbell_detach:\n"));
274b377bbb3Snat 		wsmux_detach_sc(&sc->sc_base);
275b377bbb3Snat 	}
276b377bbb3Snat #endif
277b377bbb3Snat 
278b377bbb3Snat 	/* If we're open ... */
279b377bbb3Snat 	evar = sc->sc_base.me_evp;
280b377bbb3Snat 	if (evar != NULL && evar->io != NULL) {
281b377bbb3Snat 		s = spltty();
282b377bbb3Snat 		if (--sc->sc_refcnt >= 0) {
283b377bbb3Snat 			struct wscons_event event;
284b377bbb3Snat 
285b377bbb3Snat 			/* Wake everyone by generating a dummy event. */
286b377bbb3Snat 			event.type = 0;
287b377bbb3Snat 			event.value = 0;
288b377bbb3Snat 			if (wsevent_inject(evar, &event, 1) != 0)
289b377bbb3Snat 				wsevent_wakeup(evar);
290b377bbb3Snat 
291b377bbb3Snat 			/* Wait for processes to go away. */
292b377bbb3Snat 			if (tsleep(sc, PZERO, "wsmdet", hz * 60))
293b377bbb3Snat 				printf("wsbell_detach: %s didn't detach\n",
294b377bbb3Snat 				       device_xname(self));
295b377bbb3Snat 		}
296b377bbb3Snat 		splx(s);
297b377bbb3Snat 	}
298b377bbb3Snat 
299b377bbb3Snat 	/* locate the major number */
300b377bbb3Snat 	maj = cdevsw_lookup_major(&wsbell_cdevsw);
301b377bbb3Snat 
302b377bbb3Snat 	/* Nuke the vnodes for any open instances (calls close). */
303b377bbb3Snat 	mn = device_unit(self);
304b377bbb3Snat 	vdevgone(maj, mn, mn, VCHR);
305b377bbb3Snat 
306b377bbb3Snat 	mutex_enter(&sc->sc_bellock);
3075e64cb49Snat 	sc->sc_dying = true;
308b377bbb3Snat 
309b377bbb3Snat 	cv_broadcast(&sc->sc_bellcv);
310b377bbb3Snat 	mutex_exit(&sc->sc_bellock);
311b377bbb3Snat 
312b377bbb3Snat 	kthread_join(sc->sc_bellthread);
313b377bbb3Snat 	cv_destroy(&sc->sc_bellcv);
314b377bbb3Snat 	mutex_destroy(&sc->sc_bellock);
315b377bbb3Snat 
316b377bbb3Snat 	return (0);
317b377bbb3Snat }
318b377bbb3Snat 
319b377bbb3Snat #if NWSMUX > 0
320b377bbb3Snat int
wsbelldoopen(struct wsbell_softc * sc,struct wseventvar * evp)321b377bbb3Snat wsbelldoopen(struct wsbell_softc *sc, struct wseventvar *evp)
322b377bbb3Snat {
323b377bbb3Snat 	return (0);
324b377bbb3Snat }
325b377bbb3Snat 
326b377bbb3Snat /* A wrapper around the ioctl() workhorse to make reference counting easy. */
327b377bbb3Snat int
wsbelldoioctl(device_t dv,u_long cmd,void * data,int flag,struct lwp * l)328b377bbb3Snat wsbelldoioctl(device_t dv, u_long cmd, void *data, int flag,
329b377bbb3Snat 	       struct lwp *l)
330b377bbb3Snat {
331b377bbb3Snat 	struct wsbell_softc *sc = device_private(dv);
332b377bbb3Snat 	int error;
333b377bbb3Snat 
334b377bbb3Snat 	sc->sc_refcnt++;
335b377bbb3Snat 	error = wsbell_do_ioctl(sc, cmd, data, flag, l);
336b377bbb3Snat 	if (--sc->sc_refcnt < 0)
337b377bbb3Snat 		wakeup(sc);
338b377bbb3Snat 	return (error);
339b377bbb3Snat }
340b377bbb3Snat 
341b377bbb3Snat int
wsbell_do_ioctl(struct wsbell_softc * sc,u_long cmd,void * data,int flag,struct lwp * l)342b377bbb3Snat wsbell_do_ioctl(struct wsbell_softc *sc, u_long cmd, void *data,
343b377bbb3Snat 		 int flag, struct lwp *l)
344b377bbb3Snat {
345b377bbb3Snat 	struct wskbd_bell_data *ubdp, *kbdp;
3460e2e153aSnat 	int error;
3470e2e153aSnat 
3485e64cb49Snat 	if (sc->sc_dying == true)
349b377bbb3Snat 		return (EIO);
350b377bbb3Snat 
351b377bbb3Snat 	/*
352b377bbb3Snat 	 * Try the wsbell specific ioctls.
353b377bbb3Snat 	 */
354b377bbb3Snat 	switch (cmd) {
355b377bbb3Snat 	case WSKBDIO_SETBELL:
356b377bbb3Snat 		if ((flag & FWRITE) == 0)
357b377bbb3Snat 			return (EACCES);
358b377bbb3Snat 		kbdp = &sc->sc_bell_data;
3590e2e153aSnat setbell:
360b377bbb3Snat 		ubdp = (struct wskbd_bell_data *)data;
361b377bbb3Snat 		SETBELL(kbdp, ubdp, kbdp);
362b377bbb3Snat 		return (0);
363b377bbb3Snat 
364b377bbb3Snat 	case WSKBDIO_GETBELL:
365b377bbb3Snat 		kbdp = &sc->sc_bell_data;
3660e2e153aSnat getbell:
367b377bbb3Snat 		ubdp = (struct wskbd_bell_data *)data;
368b377bbb3Snat 		SETBELL(ubdp, kbdp, kbdp);
369b377bbb3Snat 		return (0);
370b377bbb3Snat 
3710e2e153aSnat 	case WSKBDIO_SETDEFAULTBELL:
3720e2e153aSnat 		if ((error = kauth_authorize_device(l->l_cred,
3730e2e153aSnat 		    KAUTH_DEVICE_WSCONS_KEYBOARD_BELL, NULL, NULL,
3740e2e153aSnat 		    NULL, NULL)) != 0)
3750e2e153aSnat 			return (error);
3760e2e153aSnat 		kbdp = &wskbd_default_bell_data;
3770e2e153aSnat 		goto setbell;
3780e2e153aSnat 
3790e2e153aSnat 
3800e2e153aSnat 	case WSKBDIO_GETDEFAULTBELL:
3810e2e153aSnat 		kbdp = &wskbd_default_bell_data;
3820e2e153aSnat 		goto getbell;
3830e2e153aSnat 
384b377bbb3Snat 	case WSKBDIO_BELL:
385b377bbb3Snat 		if ((flag & FWRITE) == 0)
386b377bbb3Snat 			return (EACCES);
387b377bbb3Snat 		spkr_audio_play(sc, sc->sc_bell_data.pitch,
388b377bbb3Snat 		    sc->sc_bell_data.period, sc->sc_bell_data.volume);
389b377bbb3Snat 
390b377bbb3Snat 		return 0;
391b377bbb3Snat 
392b377bbb3Snat 	case WSKBDIO_COMPLEXBELL:
393b377bbb3Snat 		if ((flag & FWRITE) == 0)
394b377bbb3Snat 			return (EACCES);
395b377bbb3Snat 		if (data == NULL)
396b377bbb3Snat 			return 0;
3978931eb3bSisaki 		ubdp = (struct wskbd_bell_data *)data;
3988931eb3bSisaki 		SETBELL(ubdp, ubdp, &sc->sc_bell_data);
3998931eb3bSisaki 		spkr_audio_play(sc, ubdp->pitch, ubdp->period, ubdp->volume);
400b377bbb3Snat 		return 0;
401b377bbb3Snat 	}
402b377bbb3Snat 
403b377bbb3Snat 	return (EPASSTHROUGH);
404b377bbb3Snat }
405b377bbb3Snat #endif
406b377bbb3Snat 
407b377bbb3Snat static void
bell_thread(void * arg)408b377bbb3Snat bell_thread(void *arg)
409b377bbb3Snat {
410b377bbb3Snat 	struct wsbell_softc *sc = arg;
411b377bbb3Snat 	struct vbell_args *vb = &sc->sc_bell_args;
412b377bbb3Snat 	tone_t tone;
413b377bbb3Snat 	u_int vol;
414b377bbb3Snat 
415b377bbb3Snat 	for (;;) {
416b377bbb3Snat 		mutex_enter(&sc->sc_bellock);
417b377bbb3Snat 		cv_wait_sig(&sc->sc_bellcv, &sc->sc_bellock);
418b377bbb3Snat 
4195e64cb49Snat 		if (sc->sc_dying == true) {
420b377bbb3Snat 			mutex_exit(&sc->sc_bellock);
421b377bbb3Snat 			kthread_exit(0);
422b377bbb3Snat 		}
423b377bbb3Snat 
424b377bbb3Snat 		tone.frequency = vb->pitch;
425e3f9b603Sisaki 		/*
426e3f9b603Sisaki 		 * period (derived from wskbd) is in msec.
427e3f9b603Sisaki 		 * duration (derived from spkr) is in units of 10msec.
428e3f9b603Sisaki 		 */
429e3f9b603Sisaki 		tone.duration = vb->period / 10;
430b377bbb3Snat 		vol = vb->volume;
431b377bbb3Snat 		mutex_exit(&sc->sc_bellock);
432b377bbb3Snat 
433b377bbb3Snat 		if (spkropen(sc->sc_spkr, FWRITE, 0, NULL) != 0)
434b377bbb3Snat 			continue;
435b377bbb3Snat 		spkrioctl(sc->sc_spkr, SPKRSETVOL, &vol, 0, curlwp);
436b377bbb3Snat 		spkrioctl(sc->sc_spkr, SPKRTONE, &tone, 0, curlwp);
437b377bbb3Snat 		spkrclose(sc->sc_spkr, FWRITE, 0, curlwp);
438b377bbb3Snat 	}
439b377bbb3Snat }
440b377bbb3Snat 
441b377bbb3Snat static inline void
spkr_audio_play(struct wsbell_softc * sc,u_int pitch,u_int period,u_int volume)442b377bbb3Snat spkr_audio_play(struct wsbell_softc *sc, u_int pitch, u_int period, u_int volume)
443b377bbb3Snat {
444b377bbb3Snat 
445b377bbb3Snat 	mutex_enter(&sc->sc_bellock);
446b377bbb3Snat 	sc->sc_bell_args.pitch = pitch;
447e3f9b603Sisaki 	sc->sc_bell_args.period = period;
448b377bbb3Snat 	sc->sc_bell_args.volume = volume;
449b377bbb3Snat 
450b377bbb3Snat 	cv_broadcast(&sc->sc_bellcv);
451b377bbb3Snat 	mutex_exit(&sc->sc_bellock);
452b377bbb3Snat }
453b377bbb3Snat 
454b377bbb3Snat #if NWSMUX > 0
455b377bbb3Snat int
wsbell_mux_open(struct wsevsrc * me,struct wseventvar * evp)456b377bbb3Snat wsbell_mux_open(struct wsevsrc *me, struct wseventvar *evp)
457b377bbb3Snat {
458b377bbb3Snat 	struct wsbell_softc *sc = (struct wsbell_softc *)me;
459b377bbb3Snat 
460b377bbb3Snat 	if (sc->sc_base.me_evp != NULL)
461b377bbb3Snat 		return (EBUSY);
462b377bbb3Snat 
463b377bbb3Snat 	return wsbelldoopen(sc, evp);
464b377bbb3Snat }
465b377bbb3Snat 
466b377bbb3Snat int
wsbell_mux_close(struct wsevsrc * me)467b377bbb3Snat wsbell_mux_close(struct wsevsrc *me)
468b377bbb3Snat {
469b377bbb3Snat 	struct wsbell_softc *sc = (struct wsbell_softc *)me;
470b377bbb3Snat 
471b377bbb3Snat 	sc->sc_base.me_evp = NULL;
472b377bbb3Snat 
473b377bbb3Snat 	return (0);
474b377bbb3Snat }
475b377bbb3Snat #endif /* NWSMUX > 0 */
47618b626fcSpgoyette 
47718b626fcSpgoyette MODULE(MODULE_CLASS_DRIVER, wsbell, "spkr");
47818b626fcSpgoyette 
47918b626fcSpgoyette #ifdef _MODULE
48018b626fcSpgoyette int wsbell_bmajor = -1, wsbell_cmajor = -1;
48118b626fcSpgoyette 
48218b626fcSpgoyette #include "ioconf.c"
48318b626fcSpgoyette #endif
48418b626fcSpgoyette 
48518b626fcSpgoyette static int
wsbell_modcmd(modcmd_t cmd,void * arg)48618b626fcSpgoyette wsbell_modcmd(modcmd_t cmd, void *arg)
48718b626fcSpgoyette {
48818b626fcSpgoyette 	int error = 0;
48918b626fcSpgoyette 
49018b626fcSpgoyette 	switch (cmd) {
49118b626fcSpgoyette 	case MODULE_CMD_INIT:
49218b626fcSpgoyette #ifdef _MODULE
49318b626fcSpgoyette 		error = devsw_attach("wsbell", NULL, &wsbell_bmajor,
49418b626fcSpgoyette 		    &wsbell_cdevsw, &wsbell_cmajor);
49518b626fcSpgoyette 		if (error)
49618b626fcSpgoyette 			break;
49718b626fcSpgoyette 
49818b626fcSpgoyette 		error = config_init_component(cfdriver_ioconf_wsbell,
49918b626fcSpgoyette 		    cfattach_ioconf_wsbell, cfdata_ioconf_wsbell);
50018b626fcSpgoyette 		if (error)
50118b626fcSpgoyette 			devsw_detach(NULL, &wsbell_cdevsw);
50218b626fcSpgoyette #endif
50318b626fcSpgoyette 		break;
50418b626fcSpgoyette 
50518b626fcSpgoyette 	case MODULE_CMD_FINI:
50618b626fcSpgoyette #ifdef _MODULE
50718b626fcSpgoyette 		error = config_fini_component(cfdriver_ioconf_wsbell,
50818b626fcSpgoyette 		    cfattach_ioconf_wsbell, cfdata_ioconf_wsbell);
509*97f8debdSpgoyette 		if (error == 0)
510*97f8debdSpgoyette 			devsw_detach(NULL, &wsbell_cdevsw);
51118b626fcSpgoyette #endif
51218b626fcSpgoyette 		break;
51318b626fcSpgoyette 
51418b626fcSpgoyette 	default:
51518b626fcSpgoyette 		error = ENOTTY;
51618b626fcSpgoyette 		break;
51718b626fcSpgoyette 	}
51818b626fcSpgoyette 
51918b626fcSpgoyette 	return error;
52018b626fcSpgoyette }
521