static int alpm_readw(device_t dev, u_char slave, char cmd, short *word) { struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; u_char high, low; ALPM_LOCK(sc); alpm_clear(sc); if (!alpm_idle(sc)) { ALPM_UNLOCK(sc); return (SMB_EBUSY); } ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); if ((error = alpm_wait(sc)) == SMB_ENOERR) { low = ALPM_SMBINB(sc, SMBHDATA); high = ALPM_SMBINB(sc, SMBHDATB); *word = ((high & 0xff) << 8) | (low & 0xff); } ALPM_DEBUG(printf("alpm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); ALPM_UNLOCK(sc); return (error); }
static int alpm_writew(device_t dev, u_char slave, char cmd, short word) { struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; ALPM_LOCK(sc); alpm_clear(sc); if (!alpm_idle(sc)) { ALPM_UNLOCK(sc); return (SMB_EBUSY); } ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); ALPM_SMBOUTB(sc, SMBCMD, SMBWRWORD); ALPM_SMBOUTB(sc, SMBHDATA, word & 0x00ff); ALPM_SMBOUTB(sc, SMBHDATB, (word & 0xff00) >> 8); ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); error = alpm_wait(sc); ALPM_DEBUG(printf("alpm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); ALPM_UNLOCK(sc); return (error); }
static int alpm_readb(device_t dev, u_char slave, char cmd, char *byte) { struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; ALPM_LOCK(sc); alpm_clear(sc); if (!alpm_idle(sc)) { ALPM_UNLOCK(sc); return (SMB_EBUSY); } ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); if ((error = alpm_wait(sc)) == SMB_ENOERR) *byte = ALPM_SMBINB(sc, SMBHDATA); ALPM_DEBUG(printf("alpm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); ALPM_UNLOCK(sc); return (error); }
static int alpm_writeb(device_t dev, u_char slave, char cmd, char byte) { struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; ALPM_LOCK(sc); alpm_clear(sc); if (!alpm_idle(sc)) { ALPM_UNLOCK(sc); return (SMB_EBUSY); } ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); ALPM_SMBOUTB(sc, SMBCMD, SMBWRBYTE); ALPM_SMBOUTB(sc, SMBHDATA, byte); ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); error = alpm_wait(sc); ALPM_DEBUG(printf("alpm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); ALPM_UNLOCK(sc); return (error); }
static int alpm_quick(device_t dev, u_char slave, int how) { struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; ALPM_LOCK(sc); alpm_clear(sc); if (!alpm_idle(sc)) { ALPM_UNLOCK(sc); return (EBUSY); } switch (how) { case SMB_QWRITE: ALPM_DEBUG(kprintf("alpm: QWRITE to 0x%x", slave)); ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); break; case SMB_QREAD: ALPM_DEBUG(kprintf("alpm: QREAD to 0x%x", slave)); ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); break; default: panic("%s: unknown QUICK command (%x)!", __func__, how); } ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK); ALPM_SMBOUTB(sc, SMBSTART, 0xff); error = alpm_wait(sc); ALPM_DEBUG(kprintf(", error=0x%x\n", error)); ALPM_UNLOCK(sc); return (error); }
static int alpm_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) { struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); u_char data, len, i; int error; if (*count < 1 || *count > 32) return (SMB_EINVAL); ALPM_LOCK(sc); alpm_clear(sc); if (!alpm_idle(sc)) { ALPM_UNLOCK(sc); return (SMB_EBUSY); } ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); /* set the cmd and reset the * 32-byte long internal buffer */ ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); if ((error = alpm_wait(sc)) != SMB_ENOERR) goto error; len = ALPM_SMBINB(sc, SMBHDATA); /* read the 32-byte internal buffer */ for (i = 0; i < len; i++) { data = ALPM_SMBINB(sc, SMBHBLOCK); if (i < *count) buf[i] = data; DELAY(2); } *count = len; error: ALPM_DEBUG(printf("alpm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, *count, cmd, error)); ALPM_UNLOCK(sc); return (error); }
static int alpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) { struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); u_char i; int error; if (count < 1 || count > 32) return (SMB_EINVAL); ALPM_LOCK(sc); alpm_clear(sc); if(!alpm_idle(sc)) { ALPM_UNLOCK(sc); return (SMB_EBUSY); } ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); /* set the cmd and reset the * 32-byte long internal buffer */ ALPM_SMBOUTB(sc, SMBCMD, SMBWRBLOCK | SMB_BLK_CLR); ALPM_SMBOUTB(sc, SMBHDATA, count); /* fill the 32-byte internal buffer */ for (i = 0; i < count; i++) { ALPM_SMBOUTB(sc, SMBHBLOCK, buf[i]); DELAY(2); } ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); error = alpm_wait(sc); ALPM_DEBUG(printf("alpm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); ALPM_UNLOCK(sc); return (error); }
/* * Poll the SMBus controller */ static int alpm_wait(struct alpm_softc *sc) { int count = 10000; u_char sts = 0; int error; /* wait for command to complete and SMBus controller is idle */ while (count--) { DELAY(10); sts = ALPM_SMBINB(sc, SMBSTS); if (sts & SMI_I_STS) break; } ALPM_DEBUG(printf("alpm: STS=0x%x\n", sts)); error = SMB_ENOERR; if (!count) error |= SMB_ETIMEOUT; if (sts & TERMINATE) error |= SMB_EABORT; if (sts & BUS_COLLI) error |= SMB_ENOACK; if (sts & DEVICE_ERR) error |= SMB_EBUSERR; if (error != SMB_ENOERR) alpm_clear(sc); return (error); }