When loaded as a non-built-in module, make sure we attach the cdevsw.

Without this, the i2c bus works but userland programs (such as
i2cscan(8)) cannot open /dev/iic*.

While we're here, add a ref-count to make sure that the device doesn't
get detached while it is open.
This commit is contained in:
pgoyette 2015-12-10 05:33:28 +00:00
parent 15d8e3db1c
commit cb2f2b6a2b

View File

@ -1,4 +1,4 @@
/* $NetBSD: i2c.c,v 1.49 2015/04/13 22:26:20 pgoyette Exp $ */
/* $NetBSD: i2c.c,v 1.50 2015/12/10 05:33:28 pgoyette Exp $ */
/*
* Copyright (c) 2003 Wasabi Systems, Inc.
@ -40,7 +40,7 @@
#endif
#include <sys/cdefs.h>
__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.49 2015/04/13 22:26:20 pgoyette Exp $");
__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.50 2015/12/10 05:33:28 pgoyette Exp $");
#include <sys/param.h>
#include <sys/systm.h>
@ -54,6 +54,8 @@ __KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.49 2015/04/13 22:26:20 pgoyette Exp $");
#include <sys/kernel.h>
#include <sys/fcntl.h>
#include <sys/module.h>
#include <sys/once.h>
#include <sys/mutex.h>
#include <dev/i2c/i2cvar.h>
@ -73,6 +75,13 @@ static dev_type_open(iic_open);
static dev_type_close(iic_close);
static dev_type_ioctl(iic_ioctl);
int iic_init(void);
kmutex_t iic_mtx;
int iic_refcnt;
ONCE_DECL(iic_once);
const struct cdevsw iic_cdevsw = {
.d_open = iic_open,
.d_close = iic_close,
@ -475,8 +484,13 @@ iic_open(dev_t dev, int flag, int fmt, lwp_t *l)
{
struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev));
if (sc == NULL)
mutex_enter(&iic_mtx);
if (sc == NULL) {
mutex_exit(&iic_mtx);
return ENXIO;
}
iic_refcnt++;
mutex_exit(&iic_mtx);
return 0;
}
@ -484,6 +498,11 @@ iic_open(dev_t dev, int flag, int fmt, lwp_t *l)
static int
iic_close(dev_t dev, int flag, int fmt, lwp_t *l)
{
mutex_enter(&iic_mtx);
iic_refcnt--;
mutex_exit(&iic_mtx);
return 0;
}
@ -579,27 +598,66 @@ MODULE(MODULE_CLASS_DRIVER, iic, "i2cexec");
#include "ioconf.c"
#endif
int
iic_init(void)
{
mutex_init(&iic_mtx, MUTEX_DEFAULT, IPL_NONE);
iic_refcnt = 0;
return 0;
}
static int
iic_modcmd(modcmd_t cmd, void *opaque)
{
#ifdef _MODULE
int bmajor, cmajor;
#endif
int error;
error = 0;
switch (cmd) {
case MODULE_CMD_INIT:
RUN_ONCE(&iic_once, iic_init);
#ifdef _MODULE
mutex_enter(&iic_mtx);
bmajor = cmajor = -1;
error = devsw_attach("iic", NULL, &bmajor,
&iic_cdevsw, &cmajor);
if (error != 0) {
mutex_exit(&iic_mtx);
break;
}
error = config_init_component(cfdriver_ioconf_iic,
cfattach_ioconf_iic, cfdata_ioconf_iic);
if (error)
if (error) {
aprint_error("%s: unable to init component\n",
iic_cd.cd_name);
(void)devsw_detach(NULL, &iic_cdevsw);
}
mutex_exit(&iic_mtx);
#endif
break;
case MODULE_CMD_FINI:
mutex_enter(&iic_mtx);
if (iic_refcnt != 0) {
mutex_exit(&iic_mtx);
return EBUSY;
}
#ifdef _MODULE
config_fini_component(cfdriver_ioconf_iic,
error = config_fini_component(cfdriver_ioconf_iic,
cfattach_ioconf_iic, cfdata_ioconf_iic);
if (error != 0) {
mutex_exit(&iic_mtx);
break;
}
error = devsw_detach(NULL, &iic_cdevsw);
if (error != 0)
config_init_component(cfdriver_ioconf_iic,
cfattach_ioconf_iic, cfdata_ioconf_iic);
#endif
mutex_exit(&iic_mtx);
break;
default:
error = ENOTTY;