Lock spic(4) and mark it MPSAFE:
- Add a per-softc mutex as a driver lock. - Use callout(9) instead of timeout(9). - Set softc pointer in si_drv1 of cdev instead of looking softc up via devclass in cdev methods. Tested by: no one
This commit is contained in:
parent
7e88c64c79
commit
87c4a62333
@ -87,7 +87,6 @@ static d_poll_t spicpoll;
|
|||||||
|
|
||||||
static struct cdevsw spic_cdevsw = {
|
static struct cdevsw spic_cdevsw = {
|
||||||
.d_version = D_VERSION,
|
.d_version = D_VERSION,
|
||||||
.d_flags = D_NEEDGIANT,
|
|
||||||
.d_open = spicopen,
|
.d_open = spicopen,
|
||||||
.d_close = spicclose,
|
.d_close = spicclose,
|
||||||
.d_read = spicread,
|
.d_read = spicread,
|
||||||
@ -106,8 +105,10 @@ struct spic_softc {
|
|||||||
int sc_opened;
|
int sc_opened;
|
||||||
int sc_sleeping;
|
int sc_sleeping;
|
||||||
int sc_buttonlast;
|
int sc_buttonlast;
|
||||||
struct callout_handle sc_timeout_ch;
|
struct callout sc_timeout;
|
||||||
|
struct mtx sc_lock;
|
||||||
device_t sc_dev;
|
device_t sc_dev;
|
||||||
|
struct cdev *sc_cdev;
|
||||||
struct selinfo sc_rsel;
|
struct selinfo sc_rsel;
|
||||||
u_char sc_buf[SCBUFLEN];
|
u_char sc_buf[SCBUFLEN];
|
||||||
int sc_count;
|
int sc_count;
|
||||||
@ -337,6 +338,8 @@ spic_attach(device_t dev)
|
|||||||
sc = device_get_softc(dev);
|
sc = device_get_softc(dev);
|
||||||
|
|
||||||
sc->sc_dev = dev;
|
sc->sc_dev = dev;
|
||||||
|
mtx_init(&sc->sc_lock, "spic", NULL, MTX_DEF);
|
||||||
|
callout_init_mtx(&sc->sc_timeout, &sc->sc_lock, 0);
|
||||||
|
|
||||||
spic_pollrate = (hz/50); /* Every 50th of a second */
|
spic_pollrate = (hz/50); /* Every 50th of a second */
|
||||||
|
|
||||||
@ -345,7 +348,8 @@ spic_attach(device_t dev)
|
|||||||
spic_call1(sc, 0x92);
|
spic_call1(sc, 0x92);
|
||||||
|
|
||||||
/* There can be only one */
|
/* There can be only one */
|
||||||
make_dev(&spic_cdevsw, 0, 0, 0, 0600, "jogdial");
|
sc->sc_cdev = make_dev(&spic_cdevsw, 0, 0, 0, 0600, "jogdial");
|
||||||
|
sc->sc_cdev->si_drv1 = sc;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -357,6 +361,7 @@ spictimeout(void *arg)
|
|||||||
u_char b, event, param;
|
u_char b, event, param;
|
||||||
int j;
|
int j;
|
||||||
|
|
||||||
|
mtx_assert(&sc->sc_lock, MA_OWNED);
|
||||||
if (!sc->sc_opened) {
|
if (!sc->sc_opened) {
|
||||||
device_printf(sc->sc_dev, "timeout called while closed!\n");
|
device_printf(sc->sc_dev, "timeout called while closed!\n");
|
||||||
return;
|
return;
|
||||||
@ -426,7 +431,7 @@ spictimeout(void *arg)
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
/* No event. Wait some more */
|
/* No event. Wait some more */
|
||||||
sc->sc_timeout_ch = timeout(spictimeout, sc, spic_pollrate);
|
callout_reset(&sc->sc_timeout, spic_pollrate, spictimeout, sc);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -439,7 +444,7 @@ spictimeout(void *arg)
|
|||||||
}
|
}
|
||||||
spic_call2(sc, 0x81, 0xff); /* Clear event */
|
spic_call2(sc, 0x81, 0xff); /* Clear event */
|
||||||
|
|
||||||
sc->sc_timeout_ch = timeout(spictimeout, sc, spic_pollrate);
|
callout_reset(&sc->sc_timeout, spic_pollrate, spictimeout, sc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -447,17 +452,21 @@ spicopen(struct cdev *dev, int flag, int fmt, struct thread *td)
|
|||||||
{
|
{
|
||||||
struct spic_softc *sc;
|
struct spic_softc *sc;
|
||||||
|
|
||||||
sc = devclass_get_softc(spic_devclass, 0);
|
sc = dev->si_drv1;
|
||||||
|
|
||||||
if (sc->sc_opened)
|
mtx_lock(&sc->sc_lock);
|
||||||
return EBUSY;
|
if (sc->sc_opened) {
|
||||||
|
mtx_unlock(&sc->sc_lock);
|
||||||
|
return (EBUSY);
|
||||||
|
}
|
||||||
|
|
||||||
sc->sc_opened++;
|
sc->sc_opened++;
|
||||||
sc->sc_count=0;
|
sc->sc_count=0;
|
||||||
|
|
||||||
/* Start the polling */
|
/* Start the polling */
|
||||||
timeout(spictimeout, sc, spic_pollrate);
|
callout_reset(&sc->sc_timeout, spic_pollrate, spictimeout, sc);
|
||||||
return 0;
|
mtx_unlock(&sc->sc_lock);
|
||||||
|
return (0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -465,11 +474,13 @@ spicclose(struct cdev *dev, int flag, int fmt, struct thread *td)
|
|||||||
{
|
{
|
||||||
struct spic_softc *sc;
|
struct spic_softc *sc;
|
||||||
|
|
||||||
sc = devclass_get_softc(spic_devclass, 0);
|
sc = dev->si_drv1;
|
||||||
|
mtx_lock(&sc->sc_lock);
|
||||||
|
|
||||||
/* Stop polling */
|
/* Stop polling */
|
||||||
untimeout(spictimeout, sc, sc->sc_timeout_ch);
|
callout_stop(&sc->sc_timeout);
|
||||||
sc->sc_opened = 0;
|
sc->sc_opened = 0;
|
||||||
|
mtx_unlock(&sc->sc_lock);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -477,34 +488,31 @@ static int
|
|||||||
spicread(struct cdev *dev, struct uio *uio, int flag)
|
spicread(struct cdev *dev, struct uio *uio, int flag)
|
||||||
{
|
{
|
||||||
struct spic_softc *sc;
|
struct spic_softc *sc;
|
||||||
int l, s, error;
|
int l, error;
|
||||||
u_char buf[SCBUFLEN];
|
u_char buf[SCBUFLEN];
|
||||||
|
|
||||||
sc = devclass_get_softc(spic_devclass, 0);
|
sc = dev->si_drv1;
|
||||||
|
|
||||||
if (uio->uio_resid <= 0) /* What kind of a read is this?! */
|
if (uio->uio_resid <= 0) /* What kind of a read is this?! */
|
||||||
return 0;
|
return (0);
|
||||||
|
|
||||||
s = spltty();
|
mtx_lock(&sc->sc_lock);
|
||||||
while (!(sc->sc_count)) {
|
while (!(sc->sc_count)) {
|
||||||
sc->sc_sleeping=1;
|
sc->sc_sleeping=1;
|
||||||
error = tsleep( sc, PZERO | PCATCH, "jogrea", 0);
|
error = mtx_sleep(sc, &sc->sc_lock, PZERO | PCATCH, "jogrea", 0);
|
||||||
sc->sc_sleeping=0;
|
sc->sc_sleeping=0;
|
||||||
if (error) {
|
if (error) {
|
||||||
splx(s);
|
mtx_unlock(&sc->sc_lock);
|
||||||
return error;
|
return (error);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
splx(s);
|
|
||||||
|
|
||||||
s = spltty();
|
|
||||||
l = min(uio->uio_resid, sc->sc_count);
|
l = min(uio->uio_resid, sc->sc_count);
|
||||||
bcopy(sc->sc_buf, buf, l);
|
bcopy(sc->sc_buf, buf, l);
|
||||||
sc->sc_count -= l;
|
sc->sc_count -= l;
|
||||||
bcopy(sc->sc_buf + l, sc->sc_buf, l);
|
bcopy(sc->sc_buf + l, sc->sc_buf, l);
|
||||||
splx(s);
|
mtx_unlock(&sc->sc_lock);
|
||||||
return uiomove(buf, l, uio);
|
return (uiomove(buf, l, uio));
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -512,28 +520,28 @@ spicioctl(struct cdev *dev, u_long cmd, caddr_t addr, int flag, struct thread *t
|
|||||||
{
|
{
|
||||||
struct spic_softc *sc;
|
struct spic_softc *sc;
|
||||||
|
|
||||||
sc = devclass_get_softc(spic_devclass, 0);
|
sc = dev->si_drv1;
|
||||||
|
|
||||||
return EIO;
|
return (EIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
spicpoll(struct cdev *dev, int events, struct thread *td)
|
spicpoll(struct cdev *dev, int events, struct thread *td)
|
||||||
{
|
{
|
||||||
struct spic_softc *sc;
|
struct spic_softc *sc;
|
||||||
int revents = 0, s;
|
int revents = 0;
|
||||||
|
|
||||||
sc = devclass_get_softc(spic_devclass, 0);
|
sc = dev->si_drv1;
|
||||||
s = spltty();
|
mtx_lock(&sc->sc_lock);
|
||||||
if (events & (POLLIN | POLLRDNORM)) {
|
if (events & (POLLIN | POLLRDNORM)) {
|
||||||
if (sc->sc_count)
|
if (sc->sc_count)
|
||||||
revents |= events & (POLLIN | POLLRDNORM);
|
revents |= events & (POLLIN | POLLRDNORM);
|
||||||
else
|
else
|
||||||
selrecord(td, &sc->sc_rsel); /* Who shall we wake? */
|
selrecord(td, &sc->sc_rsel); /* Who shall we wake? */
|
||||||
}
|
}
|
||||||
splx(s);
|
mtx_unlock(&sc->sc_lock);
|
||||||
|
|
||||||
return revents;
|
return (revents);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user