diff options
author | jhb <jhb@FreeBSD.org> | 2008-08-04 20:46:15 +0000 |
---|---|---|
committer | jhb <jhb@FreeBSD.org> | 2008-08-04 20:46:15 +0000 |
commit | 9b394a3293bfa4397c24c6649034b411994dbb72 (patch) | |
tree | 2a244ae80de29ad3e4b277353b095b09dc4a9aba /sys/dev/pcf/pcf.c | |
parent | 6f12163ca676979b992a474aab9c999d288f57ed (diff) | |
download | FreeBSD-src-9b394a3293bfa4397c24c6649034b411994dbb72.zip FreeBSD-src-9b394a3293bfa4397c24c6649034b411994dbb72.tar.gz |
Add locking to the various iicbus(4) bridge drivers:
- Just grab Giant in the ixp425_iic(4) driver since this driver uses
a shared address/data register window pair to access the actual
I2C registers. None of the other ixp425 drivers lock access to these
shared address/data registers yet and that would need to be done before
this could use any meaningful locking.
- Add locking to the interrupt handler and 'iicbus_reset' methods of the
at91_twi(4) driver.
- Add locking to the pcf(4) driver. Other pcf(4) fixes include:
- Don't needlessly zero the softc.
- Use bus_foo rather than bus_space_foo and remove bus space tag and
handle from softc.
- The lpbb(4) driver just grabs Giant for now. This will be refined later
when ppbus(4) is locked.
- As was done with smbus earlier, move the DRIVER_MODULE() lines to match
the bus driver (either iicbus or iicbb) to the bridge driver into the
bridge drivers.
Tested by: sam (arm/ixp425)
Diffstat (limited to 'sys/dev/pcf/pcf.c')
-rw-r--r-- | sys/dev/pcf/pcf.c | 63 |
1 files changed, 48 insertions, 15 deletions
diff --git a/sys/dev/pcf/pcf.c b/sys/dev/pcf/pcf.c index 0320958..e6c9967 100644 --- a/sys/dev/pcf/pcf.c +++ b/sys/dev/pcf/pcf.c @@ -29,10 +29,12 @@ __FBSDID("$FreeBSD$"); #include <sys/param.h> -#include <sys/systm.h> +#include <sys/bus.h> +#include <sys/lock.h> #include <sys/kernel.h> #include <sys/module.h> -#include <sys/bus.h> +#include <sys/mutex.h> +#include <sys/systm.h> #include <machine/bus.h> #include <machine/resource.h> @@ -48,16 +50,18 @@ __FBSDID("$FreeBSD$"); static int pcf_wait_byte(struct pcf_softc *pcf); static int pcf_noack(struct pcf_softc *pcf, int timeout); +static void pcf_stop_locked(struct pcf_softc *pcf); /* * Polling mode for master operations wait for a new - * byte incomming or outgoing + * byte incoming or outgoing */ -int +static int pcf_wait_byte(struct pcf_softc *sc) { int counter = TIMEOUT; + PCF_ASSERT_LOCKED(sc); while (counter--) { if ((pcf_get_S1(sc) & PIN) == 0) @@ -71,11 +75,11 @@ pcf_wait_byte(struct pcf_softc *sc) return (IIC_ETIMEOUT); } -int -pcf_stop(device_t dev) +static void +pcf_stop_locked(struct pcf_softc *sc) { - struct pcf_softc *sc = DEVTOSOFTC(dev); + PCF_ASSERT_LOCKED(sc); #ifdef PCFDEBUG device_printf(dev, " >> stop\n"); #endif @@ -91,17 +95,15 @@ pcf_stop(device_t dev) sc->pcf_started = 0; } - - return (0); } - -int +static int pcf_noack(struct pcf_softc *sc, int timeout) { int noack; int k = timeout/10; + PCF_ASSERT_LOCKED(sc); do { noack = pcf_get_S1(sc) & LRB; if (!noack) @@ -118,6 +120,7 @@ pcf_repeated_start(device_t dev, u_char slave, int timeout) struct pcf_softc *sc = DEVTOSOFTC(dev); int error = 0; + PCF_LOCK(sc); #ifdef PCFDEBUG device_printf(dev, " >> repeated start for slave %#x\n", (unsigned)slave); @@ -142,10 +145,12 @@ pcf_repeated_start(device_t dev, u_char slave, int timeout) goto error; } + PCF_UNLOCK(sc); return (0); error: - pcf_stop(dev); + pcf_stop_locked(sc); + PCF_UNLOCK(sc); return (error); } @@ -155,6 +160,7 @@ pcf_start(device_t dev, u_char slave, int timeout) struct pcf_softc *sc = DEVTOSOFTC(dev); int error = 0; + PCF_LOCK(sc); #ifdef PCFDEBUG device_printf(dev, " >> start for slave %#x\n", (unsigned)slave); #endif @@ -162,6 +168,7 @@ pcf_start(device_t dev, u_char slave, int timeout) #ifdef PCFDEBUG printf("pcf: busy!\n"); #endif + PCF_UNLOCK(sc); return (IIC_EBUSBSY); } @@ -187,13 +194,30 @@ pcf_start(device_t dev, u_char slave, int timeout) goto error; } + PCF_UNLOCK(sc); return (0); error: - pcf_stop(dev); + pcf_stop_locked(sc); + PCF_UNLOCK(sc); return (error); } +int +pcf_stop(device_t dev) +{ + struct pcf_softc *sc = DEVTOSOFTC(dev); + +#ifdef PCFDEBUG + device_printf(dev, " >> stop\n"); +#endif + PCF_LOCK(sc); + pcf_stop_locked(sc); + PCF_UNLOCK(sc); + + return (0); +} + void pcf_intr(void *arg) { @@ -201,6 +225,7 @@ pcf_intr(void *arg) char data, status, addr; char error = 0; + PCF_LOCK(sc); status = pcf_get_S1(sc); if (status & PIN) { @@ -288,6 +313,7 @@ pcf_intr(void *arg) } } while ((pcf_get_S1(sc) & PIN) == 0); + PCF_UNLOCK(sc); return; @@ -296,6 +322,7 @@ error: pcf_set_S1(sc, PIN|ESO|ENI|ACK); sc->pcf_slave_mode = SLAVE_RECEIVER; + PCF_UNLOCK(sc); return; } @@ -305,6 +332,7 @@ pcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr) { struct pcf_softc *sc = DEVTOSOFTC(dev); + PCF_LOCK(sc); if (oldaddr) *oldaddr = sc->pcf_addr; @@ -343,6 +371,7 @@ pcf_rst_card(device_t dev, u_char speed, u_char addr, u_char *oldaddr) pcf_set_S1(sc, PIN|ESO|ENI|ACK); sc->pcf_slave_mode = SLAVE_RECEIVER; + PCF_UNLOCK(sc); return (0); } @@ -359,6 +388,7 @@ pcf_write(device_t dev, char *buf, int len, int *sent, int timeout /* us */) #endif bytes = 0; + PCF_LOCK(sc); while (len) { pcf_set_S0(sc, *buf++); @@ -379,6 +409,7 @@ pcf_write(device_t dev, char *buf, int len, int *sent, int timeout /* us */) error: *sent = bytes; + PCF_UNLOCK(sc); #ifdef PCFDEBUG device_printf(dev, " >> %d bytes written (%d)\n", bytes, error); @@ -399,6 +430,7 @@ pcf_read(device_t dev, char *buf, int len, int *read, int last, device_printf(dev, " << reading %d bytes\n", len); #endif + PCF_LOCK(sc); /* trig the bus to get the first data byte in S0 */ if (len) { if (len == 1 && last) @@ -415,14 +447,14 @@ pcf_read(device_t dev, char *buf, int len, int *read, int last, /* wait for trigged byte */ if ((error = pcf_wait_byte(sc))) { - pcf_stop(dev); + pcf_stop_locked(sc); goto error; } if (len == 1 && last) /* ok, last data byte already in S0, no I2C activity * on next pcf_get_S0() */ - pcf_stop(dev); + pcf_stop_locked(sc); else if (len == 2 && last) /* next trigged byte with no ack */ @@ -437,6 +469,7 @@ pcf_read(device_t dev, char *buf, int len, int *read, int last, error: *read = bytes; + PCF_UNLOCK(sc); #ifdef PCFDEBUG device_printf(dev, " << %d bytes read (%d): %#x%s\n", bytes, error, |