Index: dev/spibus/spibusvar.h =================================================================== --- dev/spibus/spibusvar.h (revision 240418) +++ dev/spibus/spibusvar.h (working copy) @@ -5,7 +5,9 @@ struct spibus_softc { - device_t dev; + device_t sc_dev; + device_t sc_owner; + struct mtx sc_mtx; }; struct spibus_ivar Index: dev/spibus/spibus.c =================================================================== --- dev/spibus/spibus.c (revision 240418) +++ dev/spibus/spibus.c (working copy) @@ -3,8 +3,10 @@ #include #include +#include #include #include +#include #include #include #include @@ -19,6 +21,15 @@ #include #include "spibus_if.h" +#define SPIBUS_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define SPIBUS_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define SPIBUS_LOCK_INIT(_sc) \ + mtx_init(&_sc->sc_mtx, device_get_nameunit(_sc->sc_dev), \ + "spibus", MTX_DEF) +#define SPIBUS_LOCK_DESTROY(_sc) mtx_destroy(&_sc->sc_mtx) +#define SPIBUS_ASSERT_LOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_OWNED) +#define SPIBUS_ASSERT_UNLOCKED(_sc) mtx_assert(&_sc->sc_mtx, MA_NOTOWNED) + static int spibus_probe(device_t dev) { @@ -31,7 +42,8 @@ { struct spibus_softc *sc = SPIBUS_SOFTC(dev); - sc->dev = dev; + sc->sc_dev = dev; + SPIBUS_LOCK_INIT(sc); bus_enumerate_hinted_children(dev); return (bus_generic_attach(dev)); } @@ -43,6 +55,7 @@ static int spibus_detach(device_t dev) { + struct spibus_softc *sc = SPIBUS_SOFTC(dev); int err, ndevs, i; device_t *devlist; @@ -54,6 +67,8 @@ device_delete_child(dev, devlist[i]); free(devlist, M_TEMP); + SPIBUS_LOCK_DESTROY(sc); + return (0); } @@ -155,9 +170,53 @@ resource_int_value(dname, dunit, "cs", &devi->cs); } +static void +spibus_acquire_bus_impl(device_t dev, device_t child) +{ + struct spibus_softc *sc = SPIBUS_SOFTC(dev); + + SPIBUS_ASSERT_UNLOCKED(sc); + + /* Wait until bus is free and then set the new bus owner. */ + SPIBUS_LOCK(sc); + while (sc->sc_owner != NULL) { + mtx_sleep(sc, &sc->sc_mtx, 0, "spibus", 0); + } + sc->sc_owner = child; + SPIBUS_UNLOCK(sc); + + /* Select the SPI device. */ + SPIBUS_ACQUIRE_BUS(device_get_parent(dev), child); +} + +static void +spibus_release_bus_impl(device_t dev, device_t child) +{ + struct spibus_softc *sc = SPIBUS_SOFTC(dev); + + SPIBUS_ASSERT_UNLOCKED(sc); + + /* Free the SPI BUS. */ + SPIBUS_LOCK(sc); + if (sc->sc_owner == NULL) + panic("spibus: releasing unowned bus."); + if (sc->sc_owner != child) + panic("spibus: you don't own the bus. game over."); + sc->sc_owner = NULL; + SPIBUS_UNLOCK(sc); + + /* Deselect the SPI device. */ + SPIBUS_RELEASE_BUS(device_get_parent(dev), child); + + wakeup(sc); +} + static int spibus_transfer_impl(device_t dev, device_t child, struct spi_command *cmd) { + struct spibus_softc *sc = SPIBUS_SOFTC(dev); + + KASSERT(sc->sc_owner != NULL, ("SPI transfer on unowned bus")); return (SPIBUS_TRANSFER(device_get_parent(dev), child, cmd)); } @@ -180,6 +239,8 @@ DEVMETHOD(bus_hinted_child, spibus_hinted_child), /* spibus interface */ + DEVMETHOD(spibus_acquire_bus, spibus_acquire_bus_impl), + DEVMETHOD(spibus_release_bus, spibus_release_bus_impl), DEVMETHOD(spibus_transfer, spibus_transfer_impl), DEVMETHOD_END Index: dev/spibus/spibus_if.m =================================================================== --- dev/spibus/spibus_if.m (revision 240418) +++ dev/spibus/spibus_if.m (working copy) @@ -32,6 +32,37 @@ INTERFACE spibus; # +# Default implementation +# +CODE { + static void + null_acquire_bus(device_t dev, device_t child) + { + } + + static void + null_release_bus(device_t dev, device_t child) + { + } +}; + +# +# Acquire bus and select the device +# +METHOD void acquire_bus { + device_t dev; + device_t child; +} DEFAULT null_acquire_bus; + +# +# Release bus and deselect the device +# +METHOD void release_bus { + device_t dev; + device_t child; +} DEFAULT null_release_bus; + +# # Do a spi command # METHOD int transfer {