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