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:
parent
15d8e3db1c
commit
cb2f2b6a2b
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user