Home | History | Annotate | Line # | Download | only in sysmon
sysmon.c revision 1.21
      1  1.21  pgoyette /*	$NetBSD: sysmon.c,v 1.21 2015/04/24 03:35:49 pgoyette Exp $	*/
      2   1.1   thorpej 
      3   1.1   thorpej /*-
      4   1.1   thorpej  * Copyright (c) 2000 Zembu Labs, Inc.
      5   1.1   thorpej  * All rights reserved.
      6   1.1   thorpej  *
      7   1.1   thorpej  * Author: Jason R. Thorpe <thorpej (at) zembu.com>
      8   1.1   thorpej  *
      9   1.1   thorpej  * Redistribution and use in source and binary forms, with or without
     10   1.1   thorpej  * modification, are permitted provided that the following conditions
     11   1.1   thorpej  * are met:
     12   1.1   thorpej  * 1. Redistributions of source code must retain the above copyright
     13   1.1   thorpej  *    notice, this list of conditions and the following disclaimer.
     14   1.1   thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     15   1.1   thorpej  *    notice, this list of conditions and the following disclaimer in the
     16   1.1   thorpej  *    documentation and/or other materials provided with the distribution.
     17   1.1   thorpej  * 3. All advertising materials mentioning features or use of this software
     18   1.1   thorpej  *    must display the following acknowledgement:
     19   1.1   thorpej  *	This product includes software developed by Zembu Labs, Inc.
     20   1.1   thorpej  * 4. Neither the name of Zembu Labs nor the names of its employees may
     21   1.1   thorpej  *    be used to endorse or promote products derived from this software
     22   1.1   thorpej  *    without specific prior written permission.
     23   1.1   thorpej  *
     24   1.1   thorpej  * THIS SOFTWARE IS PROVIDED BY ZEMBU LABS, INC. ``AS IS'' AND ANY EXPRESS
     25   1.1   thorpej  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WAR-
     26   1.1   thorpej  * RANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DIS-
     27   1.1   thorpej  * CLAIMED.  IN NO EVENT SHALL ZEMBU LABS BE LIABLE FOR ANY DIRECT, INDIRECT,
     28   1.1   thorpej  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
     29   1.1   thorpej  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     30   1.1   thorpej  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     31   1.1   thorpej  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     32   1.1   thorpej  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
     33   1.1   thorpej  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     34   1.1   thorpej  */
     35   1.1   thorpej 
     36   1.1   thorpej /*
     37   1.4   thorpej  * Clearing house for system monitoring hardware.  We currently
     38   1.8   thorpej  * handle environmental sensors, watchdog timers, and power management.
     39   1.1   thorpej  */
     40   1.5     lukem 
     41   1.5     lukem #include <sys/cdefs.h>
     42  1.21  pgoyette __KERNEL_RCSID(0, "$NetBSD: sysmon.c,v 1.21 2015/04/24 03:35:49 pgoyette Exp $");
     43   1.1   thorpej 
     44   1.1   thorpej #include <sys/param.h>
     45   1.1   thorpej #include <sys/conf.h>
     46   1.1   thorpej #include <sys/errno.h>
     47   1.1   thorpej #include <sys/fcntl.h>
     48   1.3   thorpej #include <sys/callout.h>
     49   1.3   thorpej #include <sys/kernel.h>
     50   1.3   thorpej #include <sys/systm.h>
     51   1.3   thorpej #include <sys/proc.h>
     52  1.20  pgoyette #include <sys/module.h>
     53  1.20  pgoyette #include <sys/mutex.h>
     54  1.20  pgoyette #include <sys/device.h>
     55   1.1   thorpej 
     56   1.1   thorpej #include <dev/sysmon/sysmonvar.h>
     57   1.1   thorpej 
     58   1.6   gehenna dev_type_open(sysmonopen);
     59   1.6   gehenna dev_type_close(sysmonclose);
     60   1.6   gehenna dev_type_ioctl(sysmonioctl);
     61   1.8   thorpej dev_type_read(sysmonread);
     62   1.8   thorpej dev_type_poll(sysmonpoll);
     63   1.8   thorpej dev_type_kqfilter(sysmonkqfilter);
     64   1.6   gehenna 
     65   1.6   gehenna const struct cdevsw sysmon_cdevsw = {
     66  1.18  dholland 	.d_open = sysmonopen,
     67  1.18  dholland 	.d_close = sysmonclose,
     68  1.18  dholland 	.d_read = sysmonread,
     69  1.18  dholland 	.d_write = nowrite,
     70  1.18  dholland 	.d_ioctl = sysmonioctl,
     71  1.18  dholland 	.d_stop = nostop,
     72  1.18  dholland 	.d_tty = notty,
     73  1.18  dholland 	.d_poll = sysmonpoll,
     74  1.18  dholland 	.d_mmap = nommap,
     75  1.18  dholland 	.d_kqfilter = sysmonkqfilter,
     76  1.19  dholland 	.d_discard = nodiscard,
     77  1.18  dholland 	.d_flag = D_OTHER | D_MPSAFE
     78   1.6   gehenna };
     79   1.1   thorpej 
     80  1.20  pgoyette static int	sysmon_match(device_t, cfdata_t, void *);
     81  1.20  pgoyette static void	sysmon_attach(device_t, device_t, void *);
     82  1.20  pgoyette static int	sysmon_detach(device_t, int);
     83  1.20  pgoyette 
     84  1.20  pgoyette static int	sysmon_modcmd(modcmd_t, void *);
     85  1.20  pgoyette 
     86  1.20  pgoyette CFDRIVER_DECL(sysmon, DV_DULL, NULL);
     87  1.20  pgoyette 
     88  1.20  pgoyette /*
     89  1.20  pgoyette  * Info about our minor "devices"
     90  1.20  pgoyette  */
     91  1.20  pgoyette static struct sysmon_opvec	*sysmon_opvec_table[] = { NULL, NULL, NULL };
     92  1.20  pgoyette static int			sysmon_refcnt[] = { 0, 0, 0 };
     93  1.20  pgoyette static const char		*sysmon_mod[] = { "sysmon_envsys",
     94  1.20  pgoyette 						  "sysmon_wdog",
     95  1.20  pgoyette 						  "sysmon_power" };
     96  1.20  pgoyette 
     97  1.20  pgoyette struct sysmon_softc {
     98  1.20  pgoyette 	device_t sc_dev;
     99  1.20  pgoyette 	kmutex_t sc_minor_mtx;
    100  1.20  pgoyette };
    101  1.20  pgoyette 
    102  1.20  pgoyette static device_t sysmon_dev = NULL;
    103  1.20  pgoyette 
    104  1.20  pgoyette CFATTACH_DECL_NEW(sysmon, sizeof(struct sysmon_softc),
    105  1.20  pgoyette         sysmon_match, sysmon_attach, sysmon_detach, NULL);
    106  1.20  pgoyette extern struct cfdriver sysmon_cd;
    107  1.20  pgoyette 
    108  1.20  pgoyette static int
    109  1.20  pgoyette sysmon_match(device_t parent, cfdata_t data, void *aux)
    110  1.20  pgoyette {
    111  1.20  pgoyette 
    112  1.20  pgoyette 	return 1;
    113  1.20  pgoyette }
    114  1.20  pgoyette 
    115  1.20  pgoyette static void
    116  1.20  pgoyette sysmon_attach(device_t parent, device_t self, void *aux)
    117  1.20  pgoyette {
    118  1.20  pgoyette 
    119  1.20  pgoyette         struct sysmon_softc *sc = device_private(self);
    120  1.20  pgoyette 
    121  1.20  pgoyette         sc->sc_dev = self;
    122  1.20  pgoyette 
    123  1.20  pgoyette 	mutex_init(&sc->sc_minor_mtx, MUTEX_DEFAULT, IPL_NONE);
    124  1.20  pgoyette }
    125  1.20  pgoyette 
    126  1.20  pgoyette static int
    127  1.20  pgoyette sysmon_detach(device_t self, int flags)
    128  1.20  pgoyette {
    129  1.20  pgoyette         struct sysmon_softc *sc = device_private(self);
    130  1.20  pgoyette 
    131  1.20  pgoyette 	mutex_destroy(&sc->sc_minor_mtx);
    132  1.20  pgoyette 	return 0;
    133  1.20  pgoyette }
    134  1.20  pgoyette 
    135  1.20  pgoyette /*
    136  1.20  pgoyette  * sysmon_attach_minor
    137  1.20  pgoyette  *
    138  1.20  pgoyette  *	Attach a minor device for wdog, power, or envsys.  Manage a
    139  1.20  pgoyette  *	reference count so we can prevent the device from being
    140  1.20  pgoyette  *	detached if there are still users with the minor device opened.
    141  1.20  pgoyette  *
    142  1.20  pgoyette  *	If the opvec argument is NULL, this is a request to detach the
    143  1.20  pgoyette  *	minor device - make sure the refcnt is zero!
    144  1.20  pgoyette  */
    145  1.20  pgoyette int
    146  1.20  pgoyette sysmon_attach_minor(int minor, struct sysmon_opvec *opvec)
    147  1.20  pgoyette {
    148  1.20  pgoyette 	struct sysmon_softc *sc = device_private(sysmon_dev);
    149  1.20  pgoyette 	int ret;
    150  1.20  pgoyette 
    151  1.20  pgoyette 	mutex_enter(&sc->sc_minor_mtx);
    152  1.20  pgoyette 	if (opvec) {
    153  1.20  pgoyette 		if (sysmon_opvec_table[minor] == NULL) {
    154  1.20  pgoyette 			sysmon_refcnt[minor] = 0;
    155  1.20  pgoyette 			sysmon_opvec_table[minor] = opvec;
    156  1.20  pgoyette 			ret = 0;
    157  1.20  pgoyette 		} else
    158  1.20  pgoyette 			ret = EEXIST;
    159  1.20  pgoyette 	} else {
    160  1.20  pgoyette 		if (sysmon_refcnt[minor] == 0) {
    161  1.20  pgoyette 			sysmon_opvec_table[minor] = NULL;
    162  1.20  pgoyette 			ret = 0;
    163  1.20  pgoyette 		} else
    164  1.20  pgoyette 			ret = EBUSY;
    165  1.20  pgoyette 	}
    166  1.20  pgoyette 
    167  1.20  pgoyette 	mutex_exit(&sc->sc_minor_mtx);
    168  1.20  pgoyette 	return ret;
    169  1.20  pgoyette }
    170  1.20  pgoyette 
    171   1.1   thorpej /*
    172   1.1   thorpej  * sysmonopen:
    173   1.1   thorpej  *
    174   1.1   thorpej  *	Open the system monitor device.
    175   1.1   thorpej  */
    176   1.1   thorpej int
    177  1.11  christos sysmonopen(dev_t dev, int flag, int mode, struct lwp *l)
    178   1.1   thorpej {
    179  1.20  pgoyette 	struct sysmon_softc *sc = device_private(sysmon_dev);
    180   1.4   thorpej 	int error;
    181   1.3   thorpej 
    182  1.20  pgoyette 	mutex_enter(&sc->sc_minor_mtx);
    183  1.20  pgoyette 
    184   1.3   thorpej 	switch (minor(dev)) {
    185   1.3   thorpej 	case SYSMON_MINOR_ENVSYS:
    186   1.3   thorpej 	case SYSMON_MINOR_WDOG:
    187   1.8   thorpej 	case SYSMON_MINOR_POWER:
    188  1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL) {
    189  1.20  pgoyette 			mutex_exit(&sc->sc_minor_mtx);
    190  1.20  pgoyette 			error = module_autoload(sysmon_mod[minor(dev)],
    191  1.20  pgoyette 						MODULE_CLASS_MISC);
    192  1.20  pgoyette 			mutex_enter(&sc->sc_minor_mtx);
    193  1.20  pgoyette 			if (sysmon_opvec_table[minor(dev)] == NULL)
    194  1.20  pgoyette 				error = ENODEV;
    195  1.20  pgoyette 		}
    196  1.20  pgoyette 		error = (sysmon_opvec_table[minor(dev)]->so_open)(dev, flag,
    197  1.20  pgoyette 		    mode, l);
    198  1.20  pgoyette 		if (error == 0)
    199  1.20  pgoyette 			sysmon_refcnt[minor(dev)]++;
    200   1.8   thorpej 		break;
    201   1.3   thorpej 	default:
    202   1.3   thorpej 		error = ENODEV;
    203   1.3   thorpej 	}
    204   1.1   thorpej 
    205  1.20  pgoyette 	mutex_exit(&sc->sc_minor_mtx);
    206   1.1   thorpej 	return (error);
    207   1.1   thorpej }
    208   1.1   thorpej 
    209   1.1   thorpej /*
    210   1.1   thorpej  * sysmonclose:
    211   1.1   thorpej  *
    212   1.1   thorpej  *	Close the system monitor device.
    213   1.1   thorpej  */
    214   1.1   thorpej int
    215  1.11  christos sysmonclose(dev_t dev, int flag, int mode, struct lwp *l)
    216   1.1   thorpej {
    217   1.4   thorpej 	int error;
    218   1.3   thorpej 
    219   1.3   thorpej 	switch (minor(dev)) {
    220   1.3   thorpej 	case SYSMON_MINOR_ENVSYS:
    221   1.3   thorpej 	case SYSMON_MINOR_WDOG:
    222   1.8   thorpej 	case SYSMON_MINOR_POWER:
    223  1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL)
    224  1.20  pgoyette 			error = ENODEV;
    225  1.20  pgoyette 		else {
    226  1.20  pgoyette 			error = (sysmon_opvec_table[minor(dev)]->so_close)(dev,
    227  1.20  pgoyette 			    flag, mode, l);
    228  1.20  pgoyette 			if (error == 0) {
    229  1.20  pgoyette 				sysmon_refcnt[minor(dev)]--;
    230  1.20  pgoyette 				KASSERT(sysmon_refcnt[minor(dev)] >= 0);
    231  1.20  pgoyette 			}
    232  1.20  pgoyette 		}
    233   1.8   thorpej 		break;
    234   1.3   thorpej 	default:
    235   1.3   thorpej 		error = ENODEV;
    236   1.3   thorpej 	}
    237   1.1   thorpej 
    238   1.3   thorpej 	return (error);
    239   1.1   thorpej }
    240   1.1   thorpej 
    241   1.1   thorpej /*
    242   1.1   thorpej  * sysmonioctl:
    243   1.1   thorpej  *
    244   1.1   thorpej  *	Perform a control request.
    245   1.1   thorpej  */
    246   1.1   thorpej int
    247  1.15  christos sysmonioctl(dev_t dev, u_long cmd, void *data, int flag, struct lwp *l)
    248   1.1   thorpej {
    249   1.3   thorpej 	int error;
    250   1.3   thorpej 
    251   1.3   thorpej 	switch (minor(dev)) {
    252   1.3   thorpej 	case SYSMON_MINOR_ENVSYS:
    253   1.3   thorpej 	case SYSMON_MINOR_WDOG:
    254   1.8   thorpej 	case SYSMON_MINOR_POWER:
    255  1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL)
    256  1.20  pgoyette 			error = ENODEV;
    257  1.20  pgoyette 		else
    258  1.20  pgoyette 			error = (sysmon_opvec_table[minor(dev)]->so_ioctl)(dev,
    259  1.20  pgoyette 			    cmd, data, flag, l);
    260   1.8   thorpej 		break;
    261   1.3   thorpej 	default:
    262   1.3   thorpej 		error = ENODEV;
    263   1.8   thorpej 	}
    264   1.8   thorpej 
    265   1.8   thorpej 	return (error);
    266   1.8   thorpej }
    267   1.8   thorpej 
    268   1.8   thorpej /*
    269   1.8   thorpej  * sysmonread:
    270   1.8   thorpej  *
    271   1.8   thorpej  *	Perform a read request.
    272   1.8   thorpej  */
    273   1.8   thorpej int
    274  1.14  christos sysmonread(dev_t dev, struct uio *uio, int flags)
    275   1.8   thorpej {
    276   1.8   thorpej 	int error;
    277   1.8   thorpej 
    278   1.8   thorpej 	switch (minor(dev)) {
    279   1.8   thorpej 	case SYSMON_MINOR_POWER:
    280  1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL)
    281  1.20  pgoyette 			error = ENODEV;
    282  1.20  pgoyette 		else
    283  1.20  pgoyette 			error = (sysmon_opvec_table[minor(dev)]->so_read)(dev,
    284  1.20  pgoyette 			    uio, flags);
    285   1.8   thorpej 		break;
    286   1.8   thorpej 	default:
    287   1.8   thorpej 		error = ENODEV;
    288   1.8   thorpej 	}
    289   1.8   thorpej 
    290   1.8   thorpej 	return (error);
    291   1.8   thorpej }
    292   1.8   thorpej 
    293   1.8   thorpej /*
    294   1.8   thorpej  * sysmonpoll:
    295   1.8   thorpej  *
    296   1.8   thorpej  *	Poll the system monitor device.
    297   1.8   thorpej  */
    298   1.8   thorpej int
    299  1.14  christos sysmonpoll(dev_t dev, int events, struct lwp *l)
    300   1.8   thorpej {
    301   1.8   thorpej 	int rv;
    302   1.8   thorpej 
    303   1.8   thorpej 	switch (minor(dev)) {
    304   1.8   thorpej 	case SYSMON_MINOR_POWER:
    305  1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL)
    306  1.20  pgoyette 			rv = events;
    307  1.20  pgoyette 		else
    308  1.20  pgoyette 			rv = (sysmon_opvec_table[minor(dev)]->so_poll)(dev,
    309  1.20  pgoyette 			    events, l);
    310   1.8   thorpej 		break;
    311   1.8   thorpej 	default:
    312   1.8   thorpej 		rv = events;
    313   1.8   thorpej 	}
    314   1.8   thorpej 
    315   1.8   thorpej 	return (rv);
    316   1.8   thorpej }
    317   1.8   thorpej 
    318   1.8   thorpej /*
    319   1.8   thorpej  * sysmonkqfilter:
    320   1.8   thorpej  *
    321   1.8   thorpej  *	Kqueue filter for the system monitor device.
    322   1.8   thorpej  */
    323   1.8   thorpej int
    324  1.14  christos sysmonkqfilter(dev_t dev, struct knote *kn)
    325   1.8   thorpej {
    326   1.8   thorpej 	int error;
    327   1.8   thorpej 
    328   1.8   thorpej 	switch (minor(dev)) {
    329   1.8   thorpej 	case SYSMON_MINOR_POWER:
    330  1.20  pgoyette 		if (sysmon_opvec_table[minor(dev)] == NULL)
    331  1.20  pgoyette 			error = ENODEV;
    332  1.20  pgoyette 		else
    333  1.20  pgoyette 			error = (sysmon_opvec_table[minor(dev)]->so_filter)(dev,
    334  1.20  pgoyette 			    kn);
    335   1.8   thorpej 		break;
    336   1.8   thorpej 	default:
    337   1.8   thorpej 		error = 1;
    338   1.3   thorpej 	}
    339   1.3   thorpej 
    340   1.3   thorpej 	return (error);
    341   1.1   thorpej }
    342  1.20  pgoyette 
    343  1.20  pgoyette MODULE(MODULE_CLASS_DRIVER, sysmon, "");
    344  1.20  pgoyette 
    345  1.20  pgoyette int
    346  1.20  pgoyette sysmon_init(void)
    347  1.20  pgoyette {
    348  1.21  pgoyette #ifdef _MODULE
    349  1.20  pgoyette 	devmajor_t bmajor, cmajor;
    350  1.21  pgoyette #endif
    351  1.20  pgoyette 	static struct cfdata cf;
    352  1.20  pgoyette 	int error = 0;
    353  1.20  pgoyette 
    354  1.20  pgoyette 	if (sysmon_dev != NULL) {
    355  1.20  pgoyette 		return EEXIST;
    356  1.20  pgoyette 	}
    357  1.20  pgoyette 
    358  1.20  pgoyette 	error = config_cfdriver_attach(&sysmon_cd);
    359  1.20  pgoyette 	if (error) {
    360  1.20  pgoyette 		aprint_error("%s: unable to attach cfdriver\n",
    361  1.20  pgoyette 		    sysmon_cd.cd_name);
    362  1.20  pgoyette 		return error;
    363  1.20  pgoyette 	}
    364  1.20  pgoyette 	error = config_cfattach_attach(sysmon_cd.cd_name, &sysmon_ca);
    365  1.20  pgoyette 	if (error) {
    366  1.20  pgoyette 		config_cfdriver_detach(&sysmon_cd);
    367  1.20  pgoyette 		aprint_error("%s: unable to attach cfattach\n",
    368  1.20  pgoyette 		    sysmon_cd.cd_name);
    369  1.20  pgoyette 		return error;
    370  1.20  pgoyette 	}
    371  1.20  pgoyette 
    372  1.21  pgoyette #ifdef _MODULE
    373  1.20  pgoyette 	bmajor = cmajor = -1;
    374  1.20  pgoyette 	error = devsw_attach("sysmon", NULL, &bmajor,
    375  1.20  pgoyette 			&sysmon_cdevsw, &cmajor);
    376  1.20  pgoyette 	if (error) {
    377  1.20  pgoyette 		config_cfattach_detach(sysmon_cd.cd_name, &sysmon_ca);
    378  1.20  pgoyette 		config_cfdriver_detach(&sysmon_cd);
    379  1.20  pgoyette 		aprint_error("%s: unable to attach devsw\n",
    380  1.20  pgoyette 		    sysmon_cd.cd_name);
    381  1.20  pgoyette 		return error;
    382  1.20  pgoyette 	}
    383  1.21  pgoyette #endif
    384  1.20  pgoyette 
    385  1.20  pgoyette 	cf.cf_name = sysmon_cd.cd_name;
    386  1.20  pgoyette 	cf.cf_atname = sysmon_cd.cd_name;
    387  1.20  pgoyette 	cf.cf_unit = 0;
    388  1.20  pgoyette 	cf.cf_fstate = FSTATE_STAR;
    389  1.20  pgoyette 	cf.cf_pspec = NULL;
    390  1.20  pgoyette 	cf.cf_loc = NULL;
    391  1.20  pgoyette 	cf.cf_flags = 0;
    392  1.20  pgoyette 
    393  1.20  pgoyette 	sysmon_dev = config_attach_pseudo(&cf);
    394  1.20  pgoyette 	if (sysmon_dev == NULL) {
    395  1.20  pgoyette 		aprint_error("%s: failed to attach pseudo device\n",
    396  1.20  pgoyette 		    sysmon_cd.cd_name);
    397  1.20  pgoyette 		error = ENODEV;
    398  1.20  pgoyette 	}
    399  1.20  pgoyette 
    400  1.20  pgoyette 	return error;
    401  1.20  pgoyette }
    402  1.20  pgoyette 
    403  1.20  pgoyette int
    404  1.20  pgoyette sysmon_fini(void)
    405  1.20  pgoyette {
    406  1.20  pgoyette 	int error = 0;
    407  1.20  pgoyette 
    408  1.20  pgoyette 	if (sysmon_opvec_table[SYSMON_MINOR_ENVSYS] != NULL)
    409  1.20  pgoyette 		error = EBUSY;
    410  1.20  pgoyette 	else if (sysmon_opvec_table[SYSMON_MINOR_WDOG] != NULL)
    411  1.20  pgoyette 		error = EBUSY;
    412  1.20  pgoyette 	else if (sysmon_opvec_table[SYSMON_MINOR_POWER] != NULL)
    413  1.20  pgoyette 		error = EBUSY;
    414  1.20  pgoyette 
    415  1.20  pgoyette 	else {
    416  1.20  pgoyette 		config_detach(sysmon_dev, 0);
    417  1.20  pgoyette 		devsw_detach(NULL, &sysmon_cdevsw);
    418  1.20  pgoyette 		config_cfattach_detach(sysmon_cd.cd_name, &sysmon_ca);
    419  1.20  pgoyette 		config_cfdriver_detach(&sysmon_cd);
    420  1.20  pgoyette 	}
    421  1.20  pgoyette 	if (error == 0)
    422  1.20  pgoyette 		sysmon_dev = NULL;
    423  1.20  pgoyette 
    424  1.20  pgoyette 	return error;
    425  1.20  pgoyette }
    426  1.20  pgoyette 
    427  1.20  pgoyette static
    428  1.20  pgoyette int
    429  1.20  pgoyette sysmon_modcmd(modcmd_t cmd, void *arg)
    430  1.20  pgoyette {
    431  1.20  pgoyette 	int ret;
    432  1.20  pgoyette 
    433  1.20  pgoyette 	switch (cmd) {
    434  1.20  pgoyette 	case MODULE_CMD_INIT:
    435  1.20  pgoyette 		ret = sysmon_init();
    436  1.20  pgoyette 		break;
    437  1.20  pgoyette 
    438  1.20  pgoyette 	case MODULE_CMD_FINI:
    439  1.20  pgoyette 		ret = sysmon_fini();
    440  1.20  pgoyette 		break;
    441  1.20  pgoyette 
    442  1.20  pgoyette 	case MODULE_CMD_STAT:
    443  1.20  pgoyette 	default:
    444  1.20  pgoyette 		ret = ENOTTY;
    445  1.20  pgoyette 	}
    446  1.20  pgoyette 
    447  1.20  pgoyette 	return ret;
    448  1.20  pgoyette }
    449