diff options
author | nsouch <nsouch@FreeBSD.org> | 2002-03-23 15:49:15 +0000 |
---|---|---|
committer | nsouch <nsouch@FreeBSD.org> | 2002-03-23 15:49:15 +0000 |
commit | 82395b7295123f4d9a786ebd89495ef101103a61 (patch) | |
tree | f78e24d69b8d02162ae886a610fb85cac8989741 /sys/pci | |
parent | 0dcefe7b55beecbfaeba7c0b20e4b1277b781733 (diff) | |
download | FreeBSD-src-82395b7295123f4d9a786ebd89495ef101103a61.zip FreeBSD-src-82395b7295123f4d9a786ebd89495ef101103a61.tar.gz |
Major rework of the iicbus/smbus framework:
- VIA chipset SMBus controllers added
- alpm driver updated
- Support for dynamic modules added
- bktr FreeBSD smbus updated but not tested
- cleanup
Diffstat (limited to 'sys/pci')
-rw-r--r-- | sys/pci/alpm.c | 329 | ||||
-rw-r--r-- | sys/pci/intpm.c | 4 | ||||
-rw-r--r-- | sys/pci/viapm.c | 924 |
3 files changed, 1070 insertions, 187 deletions
diff --git a/sys/pci/alpm.c b/sys/pci/alpm.c index a99f5f2..ae12197f 100644 --- a/sys/pci/alpm.c +++ b/sys/pci/alpm.c @@ -37,7 +37,6 @@ #include <sys/bus.h> #include <sys/uio.h> - #include <machine/bus_pio.h> #include <machine/bus_memio.h> #include <machine/bus.h> @@ -122,107 +121,62 @@ static int alpm_debug = 0; #define SMBCLOCK_111K 0xa0 #define SMBCLOCK_55K 0xc0 -struct alpm_data { +struct alpm_softc { int base; + struct resource *res; bus_space_tag_t smbst; bus_space_handle_t smbsh; -}; - -struct alsmb_softc { - int base; device_t smbus; - struct alpm_data *alpm; }; -#define ALPM_SMBINB(alsmb,register) \ - (bus_space_read_1(alsmb->alpm->smbst, alsmb->alpm->smbsh, register)) -#define ALPM_SMBOUTB(alsmb,register,value) \ - (bus_space_write_1(alsmb->alpm->smbst, alsmb->alpm->smbsh, register, value)) - -static int alsmb_probe(device_t); -static int alsmb_attach(device_t); -static int alsmb_smb_callback(device_t, int, caddr_t *); -static int alsmb_smb_quick(device_t dev, u_char slave, int how); -static int alsmb_smb_sendb(device_t dev, u_char slave, char byte); -static int alsmb_smb_recvb(device_t dev, u_char slave, char *byte); -static int alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte); -static int alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte); -static int alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word); -static int alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word); -static int alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); -static int alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *byte); - -static devclass_t alsmb_devclass; - -static device_method_t alsmb_methods[] = { - /* device interface */ - DEVMETHOD(device_probe, alsmb_probe), - DEVMETHOD(device_attach, alsmb_attach), - - /* bus interface */ - DEVMETHOD(bus_print_child, bus_generic_print_child), - - /* smbus interface */ - DEVMETHOD(smbus_callback, alsmb_smb_callback), - DEVMETHOD(smbus_quick, alsmb_smb_quick), - DEVMETHOD(smbus_sendb, alsmb_smb_sendb), - DEVMETHOD(smbus_recvb, alsmb_smb_recvb), - DEVMETHOD(smbus_writeb, alsmb_smb_writeb), - DEVMETHOD(smbus_readb, alsmb_smb_readb), - DEVMETHOD(smbus_writew, alsmb_smb_writew), - DEVMETHOD(smbus_readw, alsmb_smb_readw), - DEVMETHOD(smbus_bwrite, alsmb_smb_bwrite), - DEVMETHOD(smbus_bread, alsmb_smb_bread), - - { 0, 0 } -}; +#define ALPM_SMBINB(alpm,register) \ + (bus_space_read_1(alpm->smbst, alpm->smbsh, register)) +#define ALPM_SMBOUTB(alpm,register,value) \ + (bus_space_write_1(alpm->smbst, alpm->smbsh, register, value)) -static driver_t alsmb_driver = { - "alsmb", - alsmb_methods, - sizeof(struct alsmb_softc), -}; +static int +alpm_probe(device_t dev) +{ +#ifdef ALPM_SMBIO_BASE_ADDR + u_int32_t l; +#endif -static int alpm_pci_probe(device_t dev); -static int alpm_pci_attach(device_t dev); + if (pci_get_devid(dev) == ACER_M1543_PMU_ID) { + device_set_desc(dev, "AcerLabs M15x3 Power Management Unit"); -static devclass_t alpm_devclass; +#ifdef ALPM_SMBIO_BASE_ADDR + if (bootverbose || alpm_debug) + device_printf(dev, "forcing base I/O at 0x%x\n", + ALPM_SMBIO_BASE_ADDR); -static device_method_t alpm_pci_methods[] = { - /* device interface */ - DEVMETHOD(device_probe, alpm_pci_probe), - DEVMETHOD(device_attach, alpm_pci_attach), - - { 0, 0 } -}; + /* disable I/O */ + l = pci_read_config(dev, COM, 2); + pci_write_config(dev, COM, l & ~COM_ENABLE_IO, 2); -static driver_t alpm_pci_driver = { - "alpm", - alpm_pci_methods, - sizeof(struct alpm_data) -}; + /* set the I/O base address */ + pci_write_config(dev, SMBBA, ALPM_SMBIO_BASE_ADDR | 0x1, 4); + /* enable I/O */ + pci_write_config(dev, COM, l | COM_ENABLE_IO, 2); -static int -alpm_pci_probe(device_t dev) -{ - if (pci_get_devid(dev) == ACER_M1543_PMU_ID) { - device_set_desc(dev, - "AcerLabs M15x3 Power Management Unit"); - return 0; - } else { - return ENXIO; + if (bus_set_resource(dev, SYS_RES_IOPORT, SMBBA, + ALPM_SMBIO_BASE_ADDR, 256)) { + device_printf(dev, "could not set bus resource\n"); + return (ENXIO); + } +#endif + return (0); } + + return (ENXIO); } static int -alpm_pci_attach(device_t dev) +alpm_attach(device_t dev) { int rid, unit; u_int32_t l; - struct alpm_data *alpm; - struct resource *res; - device_t smbinterface; + struct alpm_softc *alpm; alpm = device_get_softc(dev); unit = device_get_unit(dev); @@ -239,9 +193,9 @@ alpm_pci_attach(device_t dev) pci_write_config(dev, SMBHCBC, l, 1); */ - if (bootverbose) { + if (bootverbose || alpm_debug) { l = pci_read_config(dev, SMBHSI, 1); - printf("alsmb%d: %s/%s", unit, + device_printf(dev, "%s/%s", (l & SMBHSI_HOST) ? "host":"nohost", (l & SMBHSI_SLAVE) ? "slave":"noslave"); @@ -265,76 +219,49 @@ alpm_pci_attach(device_t dev) case SMBCLOCK_55K: printf(" 55K"); break; + default: + printf("unkown"); + break; } + printf("\n"); } -#ifdef ALPM_SMBIO_BASE_ADDR - /* XX will this even work anymore? */ - /* disable I/O */ - l = pci_read_config(dev, COM, 2); - pci_write_config(dev, COM, l & ~COM_ENABLE_IO, 2); - - /* set the I/O base address */ - pci_write_config(dev, SMBBA, ALPM_SMBIO_BASE_ADDR | 0x1, 4); - - /* enable I/O */ - pci_write_config(dev, COM, l | COM_ENABLE_IO, 2); - -#endif rid = SMBBA; - res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, - 0,~0,1,RF_ACTIVE); - if (res == NULL) { + alpm->res = bus_alloc_resource(dev, SYS_RES_IOPORT, &rid, + 0, ~0, 1, RF_ACTIVE); + + if (alpm->res == NULL) { device_printf(dev,"Could not allocate Bus space\n"); - return ENXIO; + return (ENXIO); } - alpm->smbst = rman_get_bustag(res); - alpm->smbsh = rman_get_bushandle(res); + alpm->smbst = rman_get_bustag(alpm->res); + alpm->smbsh = rman_get_bushandle(alpm->res); - if (bootverbose) - printf(" at 0x%x\n", alpm->smbsh); - - smbinterface = device_add_child(dev, "alsmb", unit); - if (!smbinterface) - device_printf(dev, "could not add SMBus device\n"); - else - device_probe_and_attach(smbinterface); - return 0; -} - -/* - * Not a real probe, we know the device exists since the device has - * been added after the successfull pci probe. - */ -static int -alsmb_probe(device_t dev) -{ - struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); - - /* allocate a new smbus device */ - sc->smbus = smbus_alloc_bus(dev); - if (!sc->smbus) - return (EINVAL); - device_set_desc(dev, "Aladdin IV/V/Pro2 SMBus controller"); + /* attach the smbus */ + alpm->smbus = device_add_child(dev, "smbus", -1); + bus_generic_attach(dev); return (0); } static int -alsmb_attach(device_t dev) +alpm_detach(device_t dev) { - struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); + struct alpm_softc *alpm = device_get_softc(dev); - sc->alpm = device_get_softc(device_get_parent(dev)); + if (alpm->smbus) { + device_delete_child(dev, alpm->smbus); + alpm->smbus = NULL; + } - /* probe and attach the smbus */ - device_probe_and_attach(sc->smbus); + if (alpm->res) + bus_release_resource(dev, SYS_RES_IOPORT, SMBBA, alpm->res); return (0); } static int -alsmb_smb_callback(device_t dev, int index, caddr_t *data) +alpm_callback(device_t dev, int index, caddr_t *data) { int error = 0; @@ -351,7 +278,7 @@ alsmb_smb_callback(device_t dev, int index, caddr_t *data) } static int -alsmb_clear(struct alsmb_softc *sc) +alpm_clear(struct alpm_softc *sc) { ALPM_SMBOUTB(sc, SMBSTS, 0xff); DELAY(10); @@ -361,7 +288,7 @@ alsmb_clear(struct alsmb_softc *sc) #if 0 static int -alsmb_abort(struct alsmb_softc *sc) +alpm_abort(struct alpm_softc *sc) { ALPM_SMBOUTB(sc, SMBCMD, T_OUT_CMD | ABORT_HOST); @@ -370,7 +297,7 @@ alsmb_abort(struct alsmb_softc *sc) #endif static int -alsmb_idle(struct alsmb_softc *sc) +alpm_idle(struct alpm_softc *sc) { u_char sts; @@ -385,7 +312,7 @@ alsmb_idle(struct alsmb_softc *sc) * Poll the SMBus controller */ static int -alsmb_wait(struct alsmb_softc *sc) +alpm_wait(struct alpm_softc *sc) { int count = 10000; u_char sts = 0; @@ -416,19 +343,19 @@ alsmb_wait(struct alsmb_softc *sc) error |= SMB_EBUSERR; if (error != SMB_ENOERR) - alsmb_clear(sc); + alpm_clear(sc); return (error); } static int -alsmb_smb_quick(device_t dev, u_char slave, int how) +alpm_quick(device_t dev, u_char slave, int how) { - struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; - alsmb_clear(sc); - if (!alsmb_idle(sc)) + alpm_clear(sc); + if (!alpm_idle(sc)) return (EBUSY); switch (how) { @@ -447,7 +374,7 @@ alsmb_smb_quick(device_t dev, u_char slave, int how) ALPM_SMBOUTB(sc, SMBCMD, SMBQUICK); ALPM_SMBOUTB(sc, SMBSTART, 0xff); - error = alsmb_wait(sc); + error = alpm_wait(sc); ALPM_DEBUG(printf(", error=0x%x\n", error)); @@ -455,13 +382,13 @@ alsmb_smb_quick(device_t dev, u_char slave, int how) } static int -alsmb_smb_sendb(device_t dev, u_char slave, char byte) +alpm_sendb(device_t dev, u_char slave, char byte) { - struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; - alsmb_clear(sc); - if (!alsmb_idle(sc)) + alpm_clear(sc); + if (!alpm_idle(sc)) return (SMB_EBUSY); ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); @@ -469,7 +396,7 @@ alsmb_smb_sendb(device_t dev, u_char slave, char byte) ALPM_SMBOUTB(sc, SMBHDATA, byte); ALPM_SMBOUTB(sc, SMBSTART, 0xff); - error = alsmb_wait(sc); + error = alpm_wait(sc); ALPM_DEBUG(printf("alpm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); @@ -477,20 +404,20 @@ alsmb_smb_sendb(device_t dev, u_char slave, char byte) } static int -alsmb_smb_recvb(device_t dev, u_char slave, char *byte) +alpm_recvb(device_t dev, u_char slave, char *byte) { - struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; - alsmb_clear(sc); - if (!alsmb_idle(sc)) + alpm_clear(sc); + if (!alpm_idle(sc)) return (SMB_EBUSY); ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); ALPM_SMBOUTB(sc, SMBCMD, SMBSRBYTE); ALPM_SMBOUTB(sc, SMBSTART, 0xff); - if ((error = alsmb_wait(sc)) == SMB_ENOERR) + if ((error = alpm_wait(sc)) == SMB_ENOERR) *byte = ALPM_SMBINB(sc, SMBHDATA); ALPM_DEBUG(printf("alpm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); @@ -499,13 +426,13 @@ alsmb_smb_recvb(device_t dev, u_char slave, char *byte) } static int -alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte) +alpm_writeb(device_t dev, u_char slave, char cmd, char byte) { - struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; - alsmb_clear(sc); - if (!alsmb_idle(sc)) + alpm_clear(sc); + if (!alpm_idle(sc)) return (SMB_EBUSY); ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); @@ -514,7 +441,7 @@ alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte) ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); - error = alsmb_wait(sc); + 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)); @@ -522,13 +449,13 @@ alsmb_smb_writeb(device_t dev, u_char slave, char cmd, char byte) } static int -alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte) +alpm_readb(device_t dev, u_char slave, char cmd, char *byte) { - struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; - alsmb_clear(sc); - if (!alsmb_idle(sc)) + alpm_clear(sc); + if (!alpm_idle(sc)) return (SMB_EBUSY); ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); @@ -536,7 +463,7 @@ alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte) ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); - if ((error = alsmb_wait(sc)) == SMB_ENOERR) + 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)); @@ -545,13 +472,13 @@ alsmb_smb_readb(device_t dev, u_char slave, char cmd, char *byte) } static int -alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word) +alpm_writew(device_t dev, u_char slave, char cmd, short word) { - struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; - alsmb_clear(sc); - if (!alsmb_idle(sc)) + alpm_clear(sc); + if (!alpm_idle(sc)) return (SMB_EBUSY); ALPM_SMBOUTB(sc, SMBHADDR, slave & ~LSB); @@ -561,7 +488,7 @@ alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word) ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); - error = alsmb_wait(sc); + 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)); @@ -569,14 +496,14 @@ alsmb_smb_writew(device_t dev, u_char slave, char cmd, short word) } static int -alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word) +alpm_readw(device_t dev, u_char slave, char cmd, short *word) { - struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); int error; u_char high, low; - alsmb_clear(sc); - if (!alsmb_idle(sc)) + alpm_clear(sc); + if (!alpm_idle(sc)) return (SMB_EBUSY); ALPM_SMBOUTB(sc, SMBHADDR, slave | LSB); @@ -584,7 +511,7 @@ alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word) ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); - if ((error = alsmb_wait(sc)) == SMB_ENOERR) { + if ((error = alpm_wait(sc)) == SMB_ENOERR) { low = ALPM_SMBINB(sc, SMBHDATA); high = ALPM_SMBINB(sc, SMBHDATB); @@ -597,14 +524,14 @@ alsmb_smb_readw(device_t dev, u_char slave, char cmd, short *word) } static int -alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) +alpm_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) { - struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); u_char remain, len, i; int error = SMB_ENOERR; - alsmb_clear(sc); - if(!alsmb_idle(sc)) + alpm_clear(sc); + if(!alpm_idle(sc)) return (SMB_EBUSY); remain = count; @@ -627,7 +554,7 @@ alsmb_smb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); - if ((error = alsmb_wait(sc)) != SMB_ENOERR) + if ((error = alpm_wait(sc)) != SMB_ENOERR) goto error; remain -= len; @@ -640,14 +567,14 @@ error: } static int -alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) +alpm_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) { - struct alsmb_softc *sc = (struct alsmb_softc *)device_get_softc(dev); + struct alpm_softc *sc = (struct alpm_softc *)device_get_softc(dev); u_char remain, len, i; int error = SMB_ENOERR; - alsmb_clear(sc); - if (!alsmb_idle(sc)) + alpm_clear(sc); + if (!alpm_idle(sc)) return (SMB_EBUSY); remain = count; @@ -661,7 +588,7 @@ alsmb_smb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) ALPM_SMBOUTB(sc, SMBHCMD, cmd); ALPM_SMBOUTB(sc, SMBSTART, 0xff); - if ((error = alsmb_wait(sc)) != SMB_ENOERR) + if ((error = alpm_wait(sc)) != SMB_ENOERR) goto error; len = ALPM_SMBINB(sc, SMBHDATA); @@ -680,5 +607,35 @@ error: return (error); } -DRIVER_MODULE(alpm, pci, alpm_pci_driver, alpm_devclass, 0, 0); -DRIVER_MODULE(alsmb, alpm, alsmb_driver, alsmb_devclass, 0, 0); +static devclass_t alpm_devclass; + +static device_method_t alpm_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, alpm_probe), + DEVMETHOD(device_attach, alpm_attach), + DEVMETHOD(device_detach, alpm_detach), + + /* smbus interface */ + DEVMETHOD(smbus_callback, alpm_callback), + DEVMETHOD(smbus_quick, alpm_quick), + DEVMETHOD(smbus_sendb, alpm_sendb), + DEVMETHOD(smbus_recvb, alpm_recvb), + DEVMETHOD(smbus_writeb, alpm_writeb), + DEVMETHOD(smbus_readb, alpm_readb), + DEVMETHOD(smbus_writew, alpm_writew), + DEVMETHOD(smbus_readw, alpm_readw), + DEVMETHOD(smbus_bwrite, alpm_bwrite), + DEVMETHOD(smbus_bread, alpm_bread), + + { 0, 0 } +}; + +static driver_t alpm_driver = { + "alpm", + alpm_methods, + sizeof(struct alpm_softc) +}; + +DRIVER_MODULE(alpm, pci, alpm_driver, alpm_devclass, 0, 0); +MODULE_DEPEND(alpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); +MODULE_VERSION(alpm, 1); diff --git a/sys/pci/intpm.c b/sys/pci/intpm.c index a3c780f..747f192 100644 --- a/sys/pci/intpm.c +++ b/sys/pci/intpm.c @@ -150,7 +150,7 @@ static int intsmb_probe(device_t dev) { struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); - sc->smbus=smbus_alloc_bus(dev); + sc->smbus=device_add_child(dev, "smbus", -1); if (!sc->smbus) return (EINVAL); /* XXX don't know what to return else */ device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); @@ -739,6 +739,8 @@ intpm_probe(device_t dev) } } DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0); +MODULE_DEPEND(intpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); +MODULE_VERSION(intpm, 1); static void intpm_intr(void *arg) { diff --git a/sys/pci/viapm.c b/sys/pci/viapm.c new file mode 100644 index 0000000..d18f64d --- /dev/null +++ b/sys/pci/viapm.c @@ -0,0 +1,924 @@ +/*- + * Copyright (c) 2001 Alcove - Nicolas Souchu + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + * + */ +#include <sys/param.h> +#include <sys/kernel.h> +#include <sys/systm.h> +#include <sys/module.h> +#include <sys/bus.h> +#include <sys/uio.h> + +#include <machine/bus_pio.h> +#include <machine/bus_memio.h> +#include <machine/bus.h> +#include <machine/clock.h> /* for DELAY */ +#include <machine/resource.h> +#include <sys/rman.h> + +#include <pci/pcivar.h> +#include <pci/pcireg.h> + +#include <dev/iicbus/iiconf.h> +#include <dev/iicbus/iicbus.h> + +#include <dev/smbus/smbconf.h> +#include <dev/smbus/smbus.h> + +#include "iicbb_if.h" +#include "smbus_if.h" + +#define VIAPM_DEBUG(x) if (viapm_debug) (x) + +#ifdef DEBUG +static int viapm_debug = 1; +#else +static int viapm_debug = 0; +#endif + +#define VIA_586B_PMU_ID 0x30401106 +#define VIA_596A_PMU_ID 0x30501106 +#define VIA_596B_PMU_ID 0x30511106 +#define VIA_686A_PMU_ID 0x30571106 +#define VIA_8233_PMU_ID 0x30741106 + +#define VIAPM_INB(port) \ + ((u_char)bus_space_read_1(viapm->st, viapm->sh, port)) +#define VIAPM_OUTB(port,val) \ + (bus_space_write_1(viapm->st, viapm->sh, port, (u_char)val)) + +#define VIAPM_TYP_UNKNOWN 0 +#define VIAPM_TYP_586B_3040E 1 +#define VIAPM_TYP_586B_3040F 2 +#define VIAPM_TYP_596B 3 +#define VIAPM_TYP_686A 4 +#define VIAPM_TYP_8233 5 + +struct viapm_softc { + int type; + u_int32_t base; + bus_space_tag_t st; + bus_space_handle_t sh; + int iorid; + int irqrid; + struct resource *iores; + struct resource *irqres; + void *irqih; + + device_t iicbb; + device_t smbus; +}; + +static devclass_t viapm_devclass; +static devclass_t viapropm_devclass; + +/* + * VT82C586B definitions + */ + +#define VIAPM_586B_REVID 0x08 + +#define VIAPM_586B_3040E_BASE 0x20 +#define VIAPM_586B_3040E_ACTIV 0x4 /* 16 bits */ + +#define VIAPM_586B_3040F_BASE 0x48 +#define VIAPM_586B_3040F_ACTIV 0x41 /* 8 bits */ + +#define VIAPM_586B_OEM_REV_E 0x00 +#define VIAPM_586B_OEM_REV_F 0x01 +#define VIAPM_586B_PROD_REV_A 0x10 + +#define VIAPM_586B_BA_MASK 0x0000ff00 + +#define GPIO_DIR 0x40 +#define GPIO_VAL 0x42 +#define EXTSMI_VAL 0x44 + +#define VIAPM_SCL 0x02 /* GPIO1_VAL */ +#define VIAPM_SDA 0x04 /* GPIO2_VAL */ + +/* + * VIAPRO common definitions + */ + +#define VIAPM_PRO_BA_MASK 0x0000fff0 +#define VIAPM_PRO_SMBCTRL 0xd2 +#define VIAPM_PRO_REVID 0xd6 + +/* + * VT82C686A definitions + */ + +#define VIAPM_PRO_BASE 0x90 + +#define SMBHST 0x0 +#define SMBHSL 0x1 +#define SMBHCTRL 0x2 +#define SMBHCMD 0x3 +#define SMBHADDR 0x4 +#define SMBHDATA0 0x5 +#define SMBHDATA1 0x6 +#define SMBHBLOCK 0x7 + +#define SMBSST 0x1 +#define SMBSCTRL 0x8 +#define SMBSSDWCMD 0x9 +#define SMBSEVENT 0xa +#define SMBSDATA 0xc + +#define SMBHST_RESERVED 0xef /* reserved bits */ +#define SMBHST_FAILED 0x10 /* failed bus transaction */ +#define SMBHST_COLLID 0x08 /* bus collision */ +#define SMBHST_ERROR 0x04 /* device error */ +#define SMBHST_INTR 0x02 /* command completed */ +#define SMBHST_BUSY 0x01 /* host busy */ + +#define SMBHCTRL_START 0x40 /* start command */ +#define SMBHCTRL_PROTO 0x1c /* command protocol mask */ +#define SMBHCTRL_QUICK 0x00 +#define SMBHCTRL_SENDRECV 0x04 +#define SMBHCTRL_BYTE 0x08 +#define SMBHCTRL_WORD 0x0c +#define SMBHCTRL_BLOCK 0x14 +#define SMBHCTRL_KILL 0x02 /* stop the current transaction */ +#define SMBHCTRL_ENABLE 0x01 /* enable interrupts */ + +#define SMBSCTRL_ENABLE 0x01 /* enable slave */ + + +/* + * VIA8233 definitions + */ + +#define VIAPM_8233_BASE 0xD0 + +static int +viapm_586b_probe(device_t dev) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + u_int32_t l; + u_int16_t s; + u_int8_t c; + + switch (pci_get_devid(dev)) { + case VIA_586B_PMU_ID: + + bzero(viapm, sizeof(struct viapm_softc)); + + l = pci_read_config(dev, VIAPM_586B_REVID, 1); + switch (l) { + case VIAPM_586B_OEM_REV_E: + viapm->type = VIAPM_TYP_586B_3040E; + viapm->iorid = VIAPM_586B_3040E_BASE; + + /* Activate IO block access */ + s = pci_read_config(dev, VIAPM_586B_3040E_ACTIV, 2); + pci_write_config(dev, VIAPM_586B_3040E_ACTIV, s | 0x1, 2); + break; + + case VIAPM_586B_OEM_REV_F: + case VIAPM_586B_PROD_REV_A: + default: + viapm->type = VIAPM_TYP_586B_3040F; + viapm->iorid = VIAPM_586B_3040F_BASE; + + /* Activate IO block access */ + c = pci_read_config(dev, VIAPM_586B_3040F_ACTIV, 1); + pci_write_config(dev, VIAPM_586B_3040F_ACTIV, c | 0x80, 1); + break; + } + + viapm->base = pci_read_config(dev, viapm->iorid, 4) & + VIAPM_586B_BA_MASK; + + /* + * We have to set the I/O resources by hand because it is + * described outside the viapmope of the traditional maps + */ + if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, + viapm->base, 256)) { + device_printf(dev, "could not set bus resource\n"); + return ENXIO; + } + device_set_desc(dev, "VIA VT82C586B Power Management Unit"); + return 0; + + default: + break; + } + + return ENXIO; +} + + +static int +viapm_pro_probe(device_t dev) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); +#ifdef VIAPM_BASE_ADDR + u_int32_t l; +#endif + u_int32_t base_cfgreg; + char *desc; + + switch (pci_get_devid(dev)) { + case VIA_596A_PMU_ID: + desc = "VIA VT82C596A Power Management Unit"; + viapm->type = VIAPM_TYP_596B; + base_cfgreg = VIAPM_PRO_BASE; + goto viapro; + + case VIA_596B_PMU_ID: + desc = "VIA VT82C596B Power Management Unit"; + viapm->type = VIAPM_TYP_596B; + base_cfgreg = VIAPM_PRO_BASE; + goto viapro; + + case VIA_686A_PMU_ID: + desc = "VIA VT82C686A Power Management Unit"; + viapm->type = VIAPM_TYP_686A; + base_cfgreg = VIAPM_PRO_BASE; + goto viapro; + + case VIA_8233_PMU_ID: + desc = "VIA VT8233 Power Management Unit"; + viapm->type = VIAPM_TYP_UNKNOWN; + base_cfgreg = VIAPM_8233_BASE; + goto viapro; + + viapro: + +#ifdef VIAPM_BASE_ADDR + /* force VIAPM I/O base address */ + + /* enable the SMBus controller function */ + l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); + pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); + + /* write the base address */ + pci_write_config(dev, base_cfgreg, + VIAPM_BASE_ADDR & VIAPM_PRO_BA_MASK, 4); +#endif + + viapm->base = pci_read_config(dev, base_cfgreg, 4) & VIAPM_PRO_BA_MASK; + + /* + * We have to set the I/O resources by hand because it is + * described outside the viapmope of the traditional maps + */ + viapm->iorid = base_cfgreg; + if (bus_set_resource(dev, SYS_RES_IOPORT, viapm->iorid, + viapm->base, 16)) { + device_printf(dev, "could not set bus resource 0x%x\n", + viapm->base); + return ENXIO; + } + + if (1 || bootverbose) { + device_printf(dev, "SMBus I/O base at 0x%x\n", viapm->base); + } + + device_set_desc(dev, desc); + return 0; + + default: + break; + } + + return ENXIO; +} + +static int +viapm_pro_attach(device_t dev) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + u_int32_t l; + + if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT, + &viapm->iorid, 0l, ~0l, 1, RF_ACTIVE))) { + device_printf(dev, "could not allocate bus space\n"); + goto error; + } + viapm->st = rman_get_bustag(viapm->iores); + viapm->sh = rman_get_bushandle(viapm->iores); + +#if notyet + /* force irq 9 */ + l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); + pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 0x80, 1); + + viapm->irqrid = 0; + if (!(viapm->irqres = bus_alloc_resource(dev, SYS_RES_IRQ, + &viapm->irqrid, 9, 9, 1, + RF_SHAREABLE | RF_ACTIVE))) { + device_printf(dev, "could not allocate irq\n"); + goto error; + } + + if (bus_setup_intr(dev, viapm->irqres, INTR_TYPE_MISC, + (driver_intr_t *) viasmb_intr, viapm, &viapm->irqih)) { + device_printf(dev, "could not setup irq\n"); + goto error; + } +#endif + + if (1 | bootverbose) { + l = pci_read_config(dev, VIAPM_PRO_REVID, 1); + device_printf(dev, "SMBus revision code 0x%x\n", l); + } + + viapm->smbus = device_add_child(dev, "smbus", -1); + + /* probe and attach the smbus */ + bus_generic_attach(dev); + + /* disable slave function */ + VIAPM_OUTB(SMBSCTRL, VIAPM_INB(SMBSCTRL) & ~SMBSCTRL_ENABLE); + + /* enable the SMBus controller function */ + l = pci_read_config(dev, VIAPM_PRO_SMBCTRL, 1); + pci_write_config(dev, VIAPM_PRO_SMBCTRL, l | 1, 1); + +#if notyet + /* enable interrupts */ + VIAPM_OUTB(SMBHCTRL, VIAPM_INB(SMBHCTRL) | SMBHCTRL_ENABLE); +#endif + + return 0; + +error: + if (viapm->iores) + bus_release_resource(dev, SYS_RES_IOPORT, viapm->iorid, viapm->iores); +#if notyet + if (viapm->irqres) + bus_release_resource(dev, SYS_RES_IRQ, viapm->irqrid, viapm->irqres); +#endif + + return ENXIO; +} + +static int +viapm_586b_attach(device_t dev) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + + if (!(viapm->iores = bus_alloc_resource(dev, SYS_RES_IOPORT, + &viapm->iorid, 0ul, ~0ul, 1, RF_ACTIVE | RF_SHAREABLE))) { + device_printf(dev, "could not allocate bus resource\n"); + return ENXIO; + } + viapm->st = rman_get_bustag(viapm->iores); + viapm->sh = rman_get_bushandle(viapm->iores); + + VIAPM_OUTB(GPIO_DIR, VIAPM_INB(GPIO_DIR) | VIAPM_SCL | VIAPM_SDA); + + /* add generic bit-banging code */ + if (!(viapm->iicbb = device_add_child(dev, "iicbb", -1))) + goto error; + + bus_generic_attach(dev); + + return 0; + +error: + if (viapm->iores) + bus_release_resource(dev, SYS_RES_IOPORT, + viapm->iorid, viapm->iores); + return ENXIO; +} + +static int +viapm_586b_detach(device_t dev) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + int error; + + bus_generic_detach(dev); + if (viapm->iicbb) { + device_delete_child(dev, viapm->iicbb); + } + + if (viapm->iores && (error = bus_release_resource(dev, SYS_RES_IOPORT, + viapm->iorid, viapm->iores))) + return (error); + + return 0; +} + +static int +viapm_pro_detach(device_t dev) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + int error; + + bus_generic_detach(dev); + if (viapm->smbus) { + device_delete_child(dev, viapm->smbus); + } + + if ((error = bus_release_resource(dev, SYS_RES_IOPORT, + viapm->iorid, viapm->iores))) + return (error); + +#if notyet + if ((error = bus_release_resource(dev, SYS_RES_IRQ, + viapm->irqrid, viapm->irqres)) + return (error); +#endif + + return 0; +} + +static int +viabb_callback(device_t dev, int index, caddr_t *data) +{ + return 0; +} + +static void +viabb_setscl(device_t dev, int ctrl) +{ + struct viapm_softc *viapm = device_get_softc(dev); + u_char val; + + val = VIAPM_INB(GPIO_VAL); + + if (ctrl) + val |= VIAPM_SCL; + else + val &= ~VIAPM_SCL; + + VIAPM_OUTB(GPIO_VAL, val); + + return; +} + +static void +viabb_setsda(device_t dev, int data) +{ + struct viapm_softc *viapm = device_get_softc(dev); + u_char val; + + val = VIAPM_INB(GPIO_VAL); + + if (data) + val |= VIAPM_SDA; + else + val &= ~VIAPM_SDA; + + VIAPM_OUTB(GPIO_VAL, val); + + return; +} + +static int +viabb_reset(device_t dev, u_char speed, u_char addr, u_char *oldaddr) +{ + /* reset bus */ + viabb_setsda(dev, 1); + viabb_setscl(dev, 1); + + return (IIC_ENOADDR); +} + +static int +viabb_getscl(device_t dev) +{ + struct viapm_softc *viapm = device_get_softc(dev); + + return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SCL) != 0); +} + +static int +viabb_getsda(device_t dev) +{ + struct viapm_softc *viapm = device_get_softc(dev); + + return ((VIAPM_INB(EXTSMI_VAL) & VIAPM_SDA) != 0); +} + +static int +viapm_abort(struct viapm_softc *viapm) +{ + VIAPM_OUTB(SMBHCTRL, SMBHCTRL_KILL); + DELAY(10); + + return (0); +} + +static int +viapm_clear(struct viapm_softc *viapm) +{ + VIAPM_OUTB(SMBHST, SMBHST_FAILED | SMBHST_COLLID | + SMBHST_ERROR | SMBHST_INTR); + DELAY(10); + + return (0); +} + +static int +viapm_busy(struct viapm_softc *viapm) +{ + u_char sts; + + sts = VIAPM_INB(SMBHST); + + VIAPM_DEBUG(printf("viapm: idle? STS=0x%x\n", sts)); + + return (sts & SMBHST_BUSY); +} + +/* + * Poll the SMBus controller + */ +static int +viapm_wait(struct viapm_softc *viapm) +{ + int count = 10000; + u_char sts = 0; + int error; + + /* wait for command to complete and SMBus controller is idle */ + while(count--) { + DELAY(10); + sts = VIAPM_INB(SMBHST); + + /* check if the controller is processing a command */ + if (!(sts & SMBHST_BUSY) && (sts & SMBHST_INTR)) + break; + } + + VIAPM_DEBUG(printf("viapm: SMBHST=0x%x\n", sts)); + + error = SMB_ENOERR; + + if (!count) + error |= SMB_ETIMEOUT; + + if (sts & SMBHST_FAILED) + error |= SMB_EABORT; + + if (sts & SMBHST_COLLID) + error |= SMB_ENOACK; + + if (sts & SMBHST_ERROR) + error |= SMB_EBUSERR; + + if (error != SMB_ENOERR) + viapm_abort(viapm); + + viapm_clear(viapm); + + return (error); +} + +static int +viasmb_callback(device_t dev, int index, caddr_t *data) +{ + int error = 0; + + switch (index) { + case SMB_REQUEST_BUS: + case SMB_RELEASE_BUS: + /* ok, bus allocation accepted */ + break; + default: + error = EINVAL; + } + + return (error); +} + +static int +viasmb_quick(device_t dev, u_char slave, int how) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + int error; + + viapm_clear(viapm); + if (viapm_busy(viapm)) + return (EBUSY); + + switch (how) { + case SMB_QWRITE: + VIAPM_DEBUG(printf("viapm: QWRITE to 0x%x", slave)); + VIAPM_OUTB(SMBHADDR, slave & ~LSB); + break; + case SMB_QREAD: + VIAPM_DEBUG(printf("viapm: QREAD to 0x%x", slave)); + VIAPM_OUTB(SMBHADDR, slave | LSB); + break; + default: + panic("%s: unknown QUICK command (%x)!", __FUNCTION__, + how); + } + + VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_QUICK); + + error = viapm_wait(viapm); + + return (error); +} + +static int +viasmb_sendb(device_t dev, u_char slave, char byte) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + int error; + + viapm_clear(viapm); + if (viapm_busy(viapm)) + return (EBUSY); + + VIAPM_OUTB(SMBHADDR, slave & ~ LSB); + VIAPM_OUTB(SMBHCMD, byte); + + VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); + + error = viapm_wait(viapm); + + VIAPM_DEBUG(printf("viapm: SENDB to 0x%x, byte=0x%x, error=0x%x\n", slave, byte, error)); + + return (error); +} + +static int +viasmb_recvb(device_t dev, u_char slave, char *byte) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + int error; + + viapm_clear(viapm); + if (viapm_busy(viapm)) + return (EBUSY); + + VIAPM_OUTB(SMBHADDR, slave | LSB); + + VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_SENDRECV); + + if ((error = viapm_wait(viapm)) == SMB_ENOERR) + *byte = VIAPM_INB(SMBHDATA0); + + VIAPM_DEBUG(printf("viapm: RECVB from 0x%x, byte=0x%x, error=0x%x\n", slave, *byte, error)); + + return (error); +} + +static int +viasmb_writeb(device_t dev, u_char slave, char cmd, char byte) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + int error; + + viapm_clear(viapm); + if (viapm_busy(viapm)) + return (EBUSY); + + VIAPM_OUTB(SMBHADDR, slave & ~ LSB); + VIAPM_OUTB(SMBHCMD, cmd); + VIAPM_OUTB(SMBHDATA0, byte); + + VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); + + error = viapm_wait(viapm); + + VIAPM_DEBUG(printf("viapm: WRITEB to 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, byte, error)); + + return (error); +} + +static int +viasmb_readb(device_t dev, u_char slave, char cmd, char *byte) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + int error; + + viapm_clear(viapm); + if (viapm_busy(viapm)) + return (EBUSY); + + VIAPM_OUTB(SMBHADDR, slave | LSB); + VIAPM_OUTB(SMBHCMD, cmd); + + VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BYTE); + + if ((error = viapm_wait(viapm)) == SMB_ENOERR) + *byte = VIAPM_INB(SMBHDATA0); + + VIAPM_DEBUG(printf("viapm: READB from 0x%x, cmd=0x%x, byte=0x%x, error=0x%x\n", slave, cmd, *byte, error)); + + return (error); +} + +static int +viasmb_writew(device_t dev, u_char slave, char cmd, short word) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + int error; + + viapm_clear(viapm); + if (viapm_busy(viapm)) + return (EBUSY); + + VIAPM_OUTB(SMBHADDR, slave & ~ LSB); + VIAPM_OUTB(SMBHCMD, cmd); + VIAPM_OUTB(SMBHDATA0, word & 0x00ff); + VIAPM_OUTB(SMBHDATA1, (word & 0xff00) >> 8); + + VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); + + error = viapm_wait(viapm); + + VIAPM_DEBUG(printf("viapm: WRITEW to 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, word, error)); + + return (error); +} + +static int +viasmb_readw(device_t dev, u_char slave, char cmd, short *word) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + int error; + u_char high, low; + + viapm_clear(viapm); + if (viapm_busy(viapm)) + return (EBUSY); + + VIAPM_OUTB(SMBHADDR, slave | LSB); + VIAPM_OUTB(SMBHCMD, cmd); + + VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_WORD); + + if ((error = viapm_wait(viapm)) == SMB_ENOERR) { + low = VIAPM_INB(SMBHDATA0); + high = VIAPM_INB(SMBHDATA1); + + *word = ((high & 0xff) << 8) | (low & 0xff); + } + + VIAPM_DEBUG(printf("viapm: READW from 0x%x, cmd=0x%x, word=0x%x, error=0x%x\n", slave, cmd, *word, error)); + + return (error); +} + +static int +viasmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + u_char remain, len, i; + int error = SMB_ENOERR; + + viapm_clear(viapm); + if (viapm_busy(viapm)) + return (EBUSY); + + remain = count; + while (remain) { + len = min(remain, 32); + + VIAPM_OUTB(SMBHADDR, slave & ~LSB); + VIAPM_OUTB(SMBHCMD, cmd); + VIAPM_OUTB(SMBHDATA0, len); + i = VIAPM_INB(SMBHCTRL); + + /* fill the 32-byte internal buffer */ + for (i=0; i<len; i++) { + VIAPM_OUTB(SMBHBLOCK, buf[count-remain+i]); + DELAY(2); + } + VIAPM_OUTB(SMBHCMD, cmd); + VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); + + if ((error = viapm_wait(viapm)) != SMB_ENOERR) + goto error; + + remain -= len; + } + +error: + VIAPM_DEBUG(printf("viapm: WRITEBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); + + return (error); + +} + +static int +viasmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) +{ + struct viapm_softc *viapm = (struct viapm_softc *)device_get_softc(dev); + u_char remain, len, i; + int error = SMB_ENOERR; + + viapm_clear(viapm); + if (viapm_busy(viapm)) + return (EBUSY); + + remain = count; + while (remain) { + VIAPM_OUTB(SMBHADDR, slave | LSB); + VIAPM_OUTB(SMBHCMD, cmd); + VIAPM_OUTB(SMBHCTRL, SMBHCTRL_START | SMBHCTRL_BLOCK); + + if ((error = viapm_wait(viapm)) != SMB_ENOERR) + goto error; + + len = VIAPM_INB(SMBHDATA0); + i = VIAPM_INB(SMBHCTRL); /* reset counter */ + + len = min(len, remain); + + /* read the 32-byte internal buffer */ + for (i=0; i<len; i++) { + buf[count-remain+i] = VIAPM_INB(SMBHBLOCK); + DELAY(2); + } + + remain -= len; + } +error: + VIAPM_DEBUG(printf("viapm: READBLK to 0x%x, count=0x%x, cmd=0x%x, error=0x%x", slave, count, cmd, error)); + + return (error); +} + +static device_method_t viapm_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, viapm_586b_probe), + DEVMETHOD(device_attach, viapm_586b_attach), + DEVMETHOD(device_detach, viapm_586b_detach), + + /* iicbb interface */ + DEVMETHOD(iicbb_callback, viabb_callback), + DEVMETHOD(iicbb_setscl, viabb_setscl), + DEVMETHOD(iicbb_setsda, viabb_setsda), + DEVMETHOD(iicbb_getscl, viabb_getscl), + DEVMETHOD(iicbb_getsda, viabb_getsda), + DEVMETHOD(iicbb_reset, viabb_reset), + + { 0, 0 } +}; + +static driver_t viapm_driver = { + "viapm", + viapm_methods, + sizeof(struct viapm_softc), +}; + +static device_method_t viapropm_methods[] = { + /* device interface */ + DEVMETHOD(device_probe, viapm_pro_probe), + DEVMETHOD(device_attach, viapm_pro_attach), + DEVMETHOD(device_detach, viapm_pro_detach), + + /* smbus interface */ + DEVMETHOD(smbus_callback, viasmb_callback), + DEVMETHOD(smbus_quick, viasmb_quick), + DEVMETHOD(smbus_sendb, viasmb_sendb), + DEVMETHOD(smbus_recvb, viasmb_recvb), + DEVMETHOD(smbus_writeb, viasmb_writeb), + DEVMETHOD(smbus_readb, viasmb_readb), + DEVMETHOD(smbus_writew, viasmb_writew), + DEVMETHOD(smbus_readw, viasmb_readw), + DEVMETHOD(smbus_bwrite, viasmb_bwrite), + DEVMETHOD(smbus_bread, viasmb_bread), + + { 0, 0 } +}; + +static driver_t viapropm_driver = { + "viapropm", + viapropm_methods, + sizeof(struct viapm_softc), +}; + +DRIVER_MODULE(viapm, pci, viapm_driver, viapm_devclass, 0, 0); +DRIVER_MODULE(viapropm, pci, viapropm_driver, viapropm_devclass, 0, 0); + +MODULE_DEPEND(viapm, iicbb, IICBB_MINVER, IICBB_PREFVER, IICBB_MAXVER); +MODULE_DEPEND(viapropm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); +MODULE_VERSION(viapm, 1); |