diff options
author | Archie Cobbs <archie@FreeBSD.org> | 2000-10-06 00:09:46 +0000 |
---|---|---|
committer | Archie Cobbs <archie@FreeBSD.org> | 2000-10-06 00:09:46 +0000 |
commit | 3c5656bf032a051b26a1037cf87d7d83d1ec479e (patch) | |
tree | 50b03fa74fbf273ddaf4aace956159ced8f1f0ab /sys | |
parent | d665d812e2b9ab9a715ed2a576f6fd15da71f0be (diff) | |
download | src-3c5656bf032a051b26a1037cf87d7d83d1ec479e.tar.gz src-3c5656bf032a051b26a1037cf87d7d83d1ec479e.zip |
Driver for the Intel 82801AA (ICH) SMBus controller and compatibles.
Obtained from: Whistle source tree
Notes
Notes:
svn path=/head/; revision=66703
Diffstat (limited to 'sys')
-rw-r--r-- | sys/conf/NOTES | 19 | ||||
-rw-r--r-- | sys/conf/files | 2 | ||||
-rw-r--r-- | sys/dev/ichsmb/ichsmb.c | 682 | ||||
-rw-r--r-- | sys/dev/ichsmb/ichsmb_pci.c | 204 | ||||
-rw-r--r-- | sys/dev/ichsmb/ichsmb_reg.h | 92 | ||||
-rw-r--r-- | sys/dev/ichsmb/ichsmb_var.h | 90 | ||||
-rw-r--r-- | sys/dev/smbus/smbus.c | 1 | ||||
-rw-r--r-- | sys/i386/conf/NOTES | 19 |
8 files changed, 1095 insertions, 14 deletions
diff --git a/sys/conf/NOTES b/sys/conf/NOTES index e31b26b4d929..3299cd8e05b0 100644 --- a/sys/conf/NOTES +++ b/sys/conf/NOTES @@ -2120,20 +2120,25 @@ options POWERFAIL_NMI # make it beep instead of panicing # # SMB bus # -# System Management Bus support provided by the 'smbus' device. +# System Management Bus support is provided by the 'smbus' device. +# Access to the SMBus device is via the 'smb' device (/dev/smb*), +# which is a child of the 'smbus' device. # # Supported devices: -# smb standard io +# smb standard io through /dev/smb* # -# Supported interfaces: -# iicsmb I2C to SMB bridge with any iicbus interface -# bktr brooktree848 I2C hardware interface -# intpm Intel PIIX4 Power Management Unit -# alpm Acer Aladdin-IV/V/Pro2 Power Management Unit +# Supported SMB interfaces: +# iicsmb I2C to SMB bridge with any iicbus interface +# bktr brooktree848 I2C hardware interface +# intpm Intel PIIX4 Power Management Unit +# alpm Acer Aladdin-IV/V/Pro2 Power Management Unit +# ichsmb Intel ICH SMBus controller chips (82801AA, 82801AB, 82801BA) # device smbus # Bus support, required for smb below. + device intpm device alpm 1 +device ichsmb device smb diff --git a/sys/conf/files b/sys/conf/files index 47a843ff0764..81a45de8e0fe 100644 --- a/sys/conf/files +++ b/sys/conf/files @@ -187,6 +187,8 @@ dev/hfa/fore_stats.c optional hfa dev/hfa/fore_timer.c optional hfa dev/hfa/fore_transmit.c optional hfa dev/hfa/fore_vcm.c optional hfa +dev/ichsmb/ichsmb.c optional ichsmb +dev/ichsmb/ichsmb_pci.c optional ichsmb pci dev/ida/ida.c optional ida dev/ida/ida_disk.c optional ida dev/ida/ida_eisa.c optional ida eisa diff --git a/sys/dev/ichsmb/ichsmb.c b/sys/dev/ichsmb/ichsmb.c new file mode 100644 index 000000000000..c261c02409f1 --- /dev/null +++ b/sys/dev/ichsmb/ichsmb.c @@ -0,0 +1,682 @@ + +/* + * ichsmb.c + * + * Copyright (c) 2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Archie Cobbs <archie@freebsd.org> + * + * $FreeBSD$ + */ + +/* + * Support for the SMBus controller logical device which is part of the + * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/bus.h> + +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <dev/smbus/smbconf.h> + +#include <dev/ichsmb/ichsmb_var.h> +#include <dev/ichsmb/ichsmb_reg.h> + +/* + * Enable debugging by defining ICHSMB_DEBUG to a non-zero value. + */ +#define ICHSMB_DEBUG 0 +#if ICHSMB_DEBUG != 0 && defined(__GNUC__) +#define DBG(fmt, args...) \ + do { log(LOG_DEBUG, "%s: " fmt, __FUNCTION__ , ## args); } while (0) +#else +#define DBG(fmt, args...) do { } while (0) +#endif + +/* + * Our child device driver name + */ +#define DRIVER_SMBUS "smbus" + +/* + * Internal functions + */ +static int ichsmb_wait(sc_p sc); + +/******************************************************************** + BUS-INDEPENDENT BUS METHODS +********************************************************************/ + +/* + * Handle probe-time duties that are independent of the bus + * our device lives on. + */ +int +ichsmb_probe(device_t dev) +{ + device_t smb; + + /* Add child: an instance of the "smbus" device */ + if ((smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) { + log(LOG_ERR, "%s: no \"%s\" child found\n", + device_get_nameunit(dev), DRIVER_SMBUS); + return (ENXIO); + } + return (0); +} + +/* + * Handle attach-time duties that are independent of the bus + * our device lives on. + */ +int +ichsmb_attach(device_t dev) +{ + const sc_p sc = device_get_softc(dev); + int error; + + /* Clear interrupt conditions */ + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, 0xff); + + /* Add "smbus" child */ + if ((error = bus_generic_attach(dev)) != 0) { + log(LOG_ERR, "%s: failed to attach child: %d\n", + device_get_nameunit(dev), error); + error = ENXIO; + } + + /* Done */ + return (error); +} + +/******************************************************************** + SMBUS METHODS +********************************************************************/ + +int +ichsmb_callback(device_t dev, int index, caddr_t data) +{ + int smb_error = 0; + + DBG("index=%d how=%d\n", index, data ? *(int *)data : -1); + switch (index) { + case SMB_REQUEST_BUS: + break; + case SMB_RELEASE_BUS: + break; + default: + smb_error = SMB_EABORT; /* XXX */ + break; + } + DBG("smb_error=%d\n", smb_error); + return (smb_error); +} + +int +ichsmb_quick(device_t dev, u_char slave, int how) +{ + const sc_p sc = device_get_softc(dev); + int smb_error; + int s; + + DBG("slave=0x%02x how=%d\n", slave, how); + KASSERT(sc->ich_cmd == -1, + ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); + switch (how) { + case SMB_QREAD: + case SMB_QWRITE: + s = splhigh(); + sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK; + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, + (slave << 1) | (how == SMB_QREAD ? + ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE)); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, + ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); + smb_error = ichsmb_wait(sc); + splx(s); + break; + default: + smb_error = SMB_ENOTSUPP; + } + DBG("smb_error=%d\n", smb_error); + return (smb_error); +} + +int +ichsmb_sendb(device_t dev, u_char slave, char byte) +{ + const sc_p sc = device_get_softc(dev); + int smb_error; + int s; + + DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte); + KASSERT(sc->ich_cmd == -1, + ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); + s = splhigh(); + sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, + (slave << 1) | ICH_XMIT_SLVA_WRITE); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, byte); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, + ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); + smb_error = ichsmb_wait(sc); + splx(s); + DBG("smb_error=%d\n", smb_error); + return (smb_error); +} + +int +ichsmb_recvb(device_t dev, u_char slave, char *byte) +{ + const sc_p sc = device_get_softc(dev); + int smb_error; + int s; + + DBG("slave=0x%02x\n", slave); + KASSERT(sc->ich_cmd == -1, + ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); + s = splhigh(); + sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, + (slave << 1) | ICH_XMIT_SLVA_READ); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, + ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); + if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) + *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0); + splx(s); + DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); + return (smb_error); +} + +int +ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte) +{ + const sc_p sc = device_get_softc(dev); + int smb_error; + int s; + + DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n", + slave, (u_char)cmd, (u_char)byte); + KASSERT(sc->ich_cmd == -1, + ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); + s = splhigh(); + sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, + (slave << 1) | ICH_XMIT_SLVA_WRITE); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, byte); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, + ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); + smb_error = ichsmb_wait(sc); + splx(s); + DBG("smb_error=%d\n", smb_error); + return (smb_error); +} + +int +ichsmb_writew(device_t dev, u_char slave, char cmd, short word) +{ + const sc_p sc = device_get_softc(dev); + int smb_error; + int s; + + DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n", + slave, (u_char)cmd, (u_int16_t)word); + KASSERT(sc->ich_cmd == -1, + ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); + s = splhigh(); + sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, + (slave << 1) | ICH_XMIT_SLVA_WRITE); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, word & 0xff); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, word >> 8); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, + ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); + smb_error = ichsmb_wait(sc); + splx(s); + DBG("smb_error=%d\n", smb_error); + return (smb_error); +} + +int +ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte) +{ + const sc_p sc = device_get_softc(dev); + int smb_error; + int s; + + DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); + KASSERT(sc->ich_cmd == -1, + ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); + s = splhigh(); + sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, + (slave << 1) | ICH_XMIT_SLVA_READ); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, + ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); + if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) + *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0); + splx(s); + DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); + return (smb_error); +} + +int +ichsmb_readw(device_t dev, u_char slave, char cmd, short *word) +{ + const sc_p sc = device_get_softc(dev); + int smb_error; + int s; + + DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); + KASSERT(sc->ich_cmd == -1, + ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); + s = splhigh(); + sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, + (slave << 1) | ICH_XMIT_SLVA_READ); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, + ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); + if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { + *word = (bus_space_read_1(sc->io_bst, + sc->io_bsh, ICH_D0) & 0xff) + | (bus_space_read_1(sc->io_bst, + sc->io_bsh, ICH_D1) << 8); + } + splx(s); + DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word); + return (smb_error); +} + +int +ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) +{ + const sc_p sc = device_get_softc(dev); + int smb_error; + int s; + + DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n", + slave, (u_char)cmd, (u_int16_t)sdata); + KASSERT(sc->ich_cmd == -1, + ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); + s = splhigh(); + sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL; + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, + (slave << 1) | ICH_XMIT_SLVA_WRITE); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, sdata & 0xff); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, sdata >> 8); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, + ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); + if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { + *rdata = (bus_space_read_1(sc->io_bst, + sc->io_bsh, ICH_D0) & 0xff) + | (bus_space_read_1(sc->io_bst, + sc->io_bsh, ICH_D1) << 8); + } + splx(s); + DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata); + return (smb_error); +} + +int +ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) +{ + const sc_p sc = device_get_softc(dev); + int smb_error; + int s; + + DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); +#if ICHSMB_DEBUG +#define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) + { + u_char *p; + + for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { + DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" + " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), + DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); + } + } +#undef DISP +#endif + KASSERT(sc->ich_cmd == -1, + ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); + if (count < 1 || count > 32) + return (EINVAL); + bcopy(buf, sc->block_data, count); + sc->block_count = count; + sc->block_index = 1; + sc->block_write = 1; + + s = splhigh(); + sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, + (slave << 1) | ICH_XMIT_SLVA_WRITE); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_BLOCK_DB, buf[0]); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, + ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); + smb_error = ichsmb_wait(sc); + splx(s); + DBG("smb_error=%d\n", smb_error); + return (smb_error); +} + +int +ichsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) +{ + const sc_p sc = device_get_softc(dev); + int smb_error; + int s; + + DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); + KASSERT(sc->ich_cmd == -1, + ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); + if (count < 1 || count > 32) + return (EINVAL); + bzero(sc->block_data, sizeof(sc->block_data)); + sc->block_count = count; + sc->block_index = 0; + sc->block_write = 0; + + s = splhigh(); + sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, + (slave << 1) | ICH_XMIT_SLVA_READ); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count); /* XXX? */ + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, + ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); + if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) + bcopy(sc->block_data, buf, sc->block_count); + splx(s); + DBG("smb_error=%d\n", smb_error); +#if ICHSMB_DEBUG +#define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) + { + u_char *p; + + for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { + DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" + " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), + p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], + DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), + DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); + } + } +#undef DISP +#endif + return (smb_error); +} + +/******************************************************************** + OTHER FUNCTIONS +********************************************************************/ + +/* + * This table describes what interrupts we should ever expect to + * see after each ICH command, not including the SMBALERT interrupt. + */ +static const u_int8_t ichsmb_state_irqs[] = { + /* quick */ + (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), + /* byte */ + (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), + /* byte data */ + (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), + /* word data */ + (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), + /* process call */ + (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), + /* block */ + (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR + | ICH_HST_STA_BYTE_DONE_STS), + /* i2c read (not used) */ + (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR + | ICH_HST_STA_BYTE_DONE_STS) +}; + +/* + * Interrupt handler. This handler is bus-independent. Note that our + * interrupt may be shared, so we must handle "false" interrupts. + */ +void +ichsmb_device_intr(void *cookie) +{ + const sc_p sc = cookie; + const device_t dev = sc->dev; + const int maxloops = 16; + u_int8_t status; + u_int8_t ok_bits; + int cmd_index; + int count; + int s; + + s = splhigh(); + for (count = 0; count < maxloops; count++) { + + /* Get and reset status bits */ + status = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA); +#if ICHSMB_DEBUG + if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY)) + || count > 0) { + DBG("%d stat=0x%02x\n", count, status); + } +#endif + status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY); + if (status == 0) + break; + + /* Check for unexpected interrupt */ + ok_bits = ICH_HST_STA_SMBALERT_STS; + cmd_index = sc->ich_cmd >> 2; + if (sc->ich_cmd != -1) { + KASSERT(cmd_index < sizeof(ichsmb_state_irqs), + ("%s: ich_cmd=%d", device_get_nameunit(dev), + sc->ich_cmd)); + ok_bits |= ichsmb_state_irqs[cmd_index]; + } + if ((status & ~ok_bits) != 0) { + log(LOG_ERR, "%s: irq 0x%02x during %d\n", + device_get_nameunit(dev), status, cmd_index); + bus_space_write_1(sc->io_bst, sc->io_bsh, + ICH_HST_STA, (status & ~ok_bits)); + continue; + } + + /* Handle SMBALERT interrupt */ + if (status & ICH_HST_STA_SMBALERT_STS) { + static int smbalert_count = 16; + if (smbalert_count > 0) { + log(LOG_WARNING, "%s: SMBALERT# rec'd\n", + device_get_nameunit(dev)); + if (--smbalert_count == 0) { + log(LOG_WARNING, + "%s: not logging anymore\n", + device_get_nameunit(dev)); + } + } + } + + /* Check for bus error */ + if (status & ICH_HST_STA_BUS_ERR) { + sc->smb_error = SMB_ECOLLI; /* XXX SMB_EBUSERR? */ + goto finished; + } + + /* Check for device error */ + if (status & ICH_HST_STA_DEV_ERR) { + sc->smb_error = SMB_ENOACK; /* or SMB_ETIMEOUT? */ + goto finished; + } + + /* Check for byte completion in block transfer */ + if (status & ICH_HST_STA_BYTE_DONE_STS) { + if (sc->block_write) { + if (sc->block_index < sc->block_count) { + + /* Write next byte */ + bus_space_write_1(sc->io_bst, + sc->io_bsh, ICH_BLOCK_DB, + sc->block_data[sc->block_index++]); + } + } else { + + /* First interrupt, get the count also */ + if (sc->block_index == 0) { + sc->block_count = bus_space_read_1( + sc->io_bst, sc->io_bsh, ICH_D0); + } + + /* Get next byte, if any */ + if (sc->block_index < sc->block_count) { + + /* Read next byte */ + sc->block_data[sc->block_index++] = + bus_space_read_1(sc->io_bst, + sc->io_bsh, ICH_BLOCK_DB); + + /* Set "LAST_BYTE" bit before reading + the last byte of block data */ + if (sc->block_index + >= sc->block_count - 1) { + bus_space_write_1(sc->io_bst, + sc->io_bsh, ICH_HST_CNT, + ICH_HST_CNT_LAST_BYTE + | ICH_HST_CNT_INTREN + | sc->ich_cmd); + } + } + } + } + + /* Check command completion */ + if (status & ICH_HST_STA_INTR) { + sc->smb_error = SMB_ENOERR; +finished: + sc->ich_cmd = -1; + bus_space_write_1(sc->io_bst, sc->io_bsh, + ICH_HST_STA, status); + wakeup(sc); + break; + } + + /* Clear status bits and try again */ + bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, status); + } + splx(s); + + /* Too many loops? */ + if (count == maxloops) { + log(LOG_ERR, "%s: interrupt loop, status=0x%02x\n", + device_get_nameunit(dev), + bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA)); + } +} + +/* + * Wait for command completion. Assumes splhigh(). + * Returns an SMB_* error code. + */ +static int +ichsmb_wait(sc_p sc) +{ + const device_t dev = sc->dev; + int error, smb_error; + + KASSERT(sc->ich_cmd != -1, + ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); +sleep: + error = tsleep(sc, PZERO | PCATCH, "ichsmb", hz / 4); + DBG("tsleep -> %d\n", error); + switch (error) { + case ERESTART: + if (sc->ich_cmd != -1) + goto sleep; + /* FALLTHROUGH */ + case 0: + smb_error = sc->smb_error; + break; + case EWOULDBLOCK: + log(LOG_ERR, "%s: device timeout, status=0x%02x\n", + device_get_nameunit(dev), + bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA)); + sc->ich_cmd = -1; + smb_error = SMB_ETIMEOUT; + break; + default: + smb_error = SMB_EABORT; + break; + } + return (smb_error); +} + +/* + * Release resources associated with device. + */ +void +ichsmb_release_resources(sc_p sc) +{ + const device_t dev = sc->dev; + + if (sc->irq_handle != NULL) { + bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); + sc->irq_handle = NULL; + } + if (sc->irq_res != NULL) { + bus_release_resource(dev, + SYS_RES_IRQ, sc->irq_rid, sc->irq_res); + sc->irq_res = NULL; + } + if (sc->io_res != NULL) { + bus_release_resource(dev, + SYS_RES_IOPORT, sc->io_rid, sc->io_res); + sc->io_res = NULL; + } +} + diff --git a/sys/dev/ichsmb/ichsmb_pci.c b/sys/dev/ichsmb/ichsmb_pci.c new file mode 100644 index 000000000000..8dfa6df54120 --- /dev/null +++ b/sys/dev/ichsmb/ichsmb_pci.c @@ -0,0 +1,204 @@ + +/* + * ichsmb_pci.c + * + * Copyright (c) 2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Archie Cobbs <archie@freebsd.org> + * + * $FreeBSD$ + */ + +/* + * Support for the SMBus controller logical device which is part of the + * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/errno.h> +#include <sys/syslog.h> +#include <sys/bus.h> + +#include <machine/bus.h> +#include <sys/rman.h> +#include <machine/resource.h> + +#include <pci/pcivar.h> +#include <pci/pcireg.h> + +#include <dev/smbus/smbconf.h> + +#include <dev/ichsmb/ichsmb_var.h> +#include <dev/ichsmb/ichsmb_reg.h> + +/* PCI unique identifiers */ +#define ID_81801AA 0x24138086 +#define ID_81801AB 0x24238086 +#define ID_82801BA 0x24438086 + +#define PCIS_SERIALBUS_SMBUS_PROGIF 0x00 + +/* Internal functions */ +static int ichsmb_pci_probe(device_t dev); +static int ichsmb_pci_attach(device_t dev); + +/* Device methods */ +static device_method_t ichsmb_pci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ichsmb_pci_probe), + DEVMETHOD(device_attach, ichsmb_pci_attach), + + /* Bus methods */ + DEVMETHOD(bus_print_child, bus_generic_print_child), + + /* SMBus methods */ + DEVMETHOD(smbus_callback, ichsmb_callback), + DEVMETHOD(smbus_quick, ichsmb_quick), + DEVMETHOD(smbus_sendb, ichsmb_sendb), + DEVMETHOD(smbus_recvb, ichsmb_recvb), + DEVMETHOD(smbus_writeb, ichsmb_writeb), + DEVMETHOD(smbus_writew, ichsmb_writew), + DEVMETHOD(smbus_readb, ichsmb_readb), + DEVMETHOD(smbus_readw, ichsmb_readw), + DEVMETHOD(smbus_pcall, ichsmb_pcall), + DEVMETHOD(smbus_bwrite, ichsmb_bwrite), + DEVMETHOD(smbus_bread, ichsmb_bread), + { 0, 0 } +}; + +static driver_t ichsmb_pci_driver = { + "ichsmb", + ichsmb_pci_methods, + sizeof(struct ichsmb_softc) +}; + +static devclass_t ichsmb_pci_devclass; + +DRIVER_MODULE(ichsmb, pci, ichsmb_pci_driver, ichsmb_pci_devclass, 0, 0); + +static int +ichsmb_pci_probe(device_t dev) +{ + /* Check PCI identifier */ + switch (pci_get_devid(dev)) { + case ID_81801AA: + device_set_desc(dev, "Intel 82801AA (ICH) SMBus controller"); + break; + case ID_81801AB: + device_set_desc(dev, "Intel 82801AB (ICH0) SMBus controller"); + break; + case ID_82801BA: + device_set_desc(dev, "Intel 82801BA (ICH2) SMBus controller"); + break; + default: + if (pci_get_class(dev) == PCIC_SERIALBUS + && pci_get_subclass(dev) == PCIS_SERIALBUS_SMBUS + && pci_get_progif(dev) == PCIS_SERIALBUS_SMBUS_PROGIF) { + device_set_desc(dev, "SMBus controller"); + return (-2); /* XXX */ + } + return (ENXIO); + } + + /* Done */ + return (ichsmb_probe(dev)); +} + +static int +ichsmb_pci_attach(device_t dev) +{ + const sc_p sc = device_get_softc(dev); + u_int32_t cmd; + int error; + + /* Initialize private state */ + bzero(sc, sizeof(*sc)); + sc->ich_cmd = -1; + sc->dev = dev; + + /* Allocate an I/O range */ + sc->io_rid = ICH_SMB_BASE; + sc->io_res = bus_alloc_resource(dev, SYS_RES_IOPORT, + &sc->io_rid, 0, ~0, 16, RF_ACTIVE); + if (sc->io_res == NULL) { + log(LOG_ERR, "%s: can't map I/O\n", device_get_nameunit(dev)); + error = ENXIO; + goto fail; + } + sc->io_bst = rman_get_bustag(sc->io_res); + sc->io_bsh = rman_get_bushandle(sc->io_res); + + /* Allocate interrupt */ + sc->irq_rid = 0; + sc->irq_res = bus_alloc_resource(dev, SYS_RES_IRQ, + &sc->irq_rid, 0, ~0, 1, RF_ACTIVE | RF_SHAREABLE); + if (sc->irq_res == NULL) { + log(LOG_ERR, "%s: can't get IRQ\n", device_get_nameunit(dev)); + error = ENXIO; + goto fail; + } + + /* Set up interrupt handler */ + error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, + ichsmb_device_intr, sc, &sc->irq_handle); + if (error != 0) { + log(LOG_ERR, "%s: can't setup irq\n", device_get_nameunit(dev)); + goto fail; + } + + /* Enable I/O mapping */ + cmd = pci_read_config(dev, PCIR_COMMAND, 4); + cmd |= PCIM_CMD_PORTEN; + pci_write_config(dev, PCIR_COMMAND, cmd, 4); + cmd = pci_read_config(dev, PCIR_COMMAND, 4); + if ((cmd & PCIM_CMD_PORTEN) == 0) { + log(LOG_ERR, "%s: can't enable memory map\n", + device_get_nameunit(dev)); + error = ENXIO; + goto fail; + } + + /* Enable device */ + pci_write_config(dev, ICH_HOSTC, ICH_HOSTC_HST_EN, 1); + + /* Done */ + return (ichsmb_attach(dev)); + +fail: + /* Attach failed, release resources */ + ichsmb_release_resources(sc); + return (error); +} + diff --git a/sys/dev/ichsmb/ichsmb_reg.h b/sys/dev/ichsmb/ichsmb_reg.h new file mode 100644 index 000000000000..ca0577c7d178 --- /dev/null +++ b/sys/dev/ichsmb/ichsmb_reg.h @@ -0,0 +1,92 @@ + +/* + * ichsmb_reg.h + * + * Copyright (c) 2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Archie Cobbs <archie@freebsd.org> + * + * $FreeBSD$ + */ + +#ifndef _DEV_ICHSMB_ICHSMB_REG_H_ +#define _DEV_ICHSMB_ICHSMB_REG_H_ + +/* + * Definitions for the SMBus controller logical device which is part of the + * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips. + */ + +/* + * PCI configuration registers + */ +#define ICH_SMB_BASE 0x20 /* base address register */ +#define ICH_HOSTC 0x40 /* host config register */ +#define ICH_HOSTC_I2C_EN 0x04 /* enable i2c mode */ +#define ICH_HOSTC_SMB_SMI_EN 0x02 /* SMI# instead of irq */ +#define ICH_HOSTC_HST_EN 0x01 /* enable host cntrlr */ + +/* + * I/O registers + */ +#define ICH_HST_STA 0x00 /* host status */ +#define ICH_HST_STA_BYTE_DONE_STS 0x80 /* byte send/rec'd */ +#define ICH_HST_STA_INUSE_STS 0x40 /* device access mutex */ +#define ICH_HST_STA_SMBALERT_STS 0x20 /* SMBALERT# signal */ +#define ICH_HST_STA_FAILED 0x10 /* failed bus transaction */ +#define ICH_HST_STA_BUS_ERR 0x08 /* transaction collision */ +#define ICH_HST_STA_DEV_ERR 0x04 /* misc. smb device error */ +#define ICH_HST_STA_INTR 0x02 /* command completed ok */ +#define ICH_HST_STA_HOST_BUSY 0x01 /* command is running */ +#define ICH_HST_CNT 0x02 /* host control */ +#define ICH_HST_CNT_START 0x40 /* start command */ +#define ICH_HST_CNT_LAST_BYTE 0x20 /* indicate last byte */ +#define ICH_HST_CNT_SMB_CMD_QUICK 0x00 /* command: quick */ +#define ICH_HST_CNT_SMB_CMD_BYTE 0x04 /* command: byte */ +#define ICH_HST_CNT_SMB_CMD_BYTE_DATA 0x08 /* command: byte data */ +#define ICH_HST_CNT_SMB_CMD_WORD_DATA 0x0c /* command: word data */ +#define ICH_HST_CNT_SMB_CMD_PROC_CALL 0x10 /* command: process call */ +#define ICH_HST_CNT_SMB_CMD_BLOCK 0x14 /* command: block */ +#define ICH_HST_CNT_SMB_CMD_I2C_READ 0x18 /* command: i2c read */ +#define ICH_HST_CNT_KILL 0x02 /* kill current transaction */ +#define ICH_HST_CNT_INTREN 0x01 /* enable interrupt */ +#define ICH_HST_CMD 0x03 /* host command */ +#define ICH_XMIT_SLVA 0x04 /* transmit slave address */ +#define ICH_XMIT_SLVA_READ 0x01 /* direction: read */ +#define ICH_XMIT_SLVA_WRITE 0x00 /* direction: write */ +#define ICH_D0 0x05 /* host data 0 */ +#define ICH_D1 0x06 /* host data 1 */ +#define ICH_BLOCK_DB 0x07 /* block data byte */ + +#endif /* _DEV_ICHSMB_ICHSMB_REG_H_ */ + diff --git a/sys/dev/ichsmb/ichsmb_var.h b/sys/dev/ichsmb/ichsmb_var.h new file mode 100644 index 000000000000..43c0ed04f115 --- /dev/null +++ b/sys/dev/ichsmb/ichsmb_var.h @@ -0,0 +1,90 @@ + +/* + * ichsmb_var.h + * + * Copyright (c) 2000 Whistle Communications, Inc. + * All rights reserved. + * + * Subject to the following obligations and disclaimer of warranty, use and + * redistribution of this software, in source or object code forms, with or + * without modifications are expressly permitted by Whistle Communications; + * provided, however, that: + * 1. Any and all reproductions of the source or object code must include the + * copyright notice above and the following disclaimer of warranties; and + * 2. No rights are granted, in any manner or form, to use Whistle + * Communications, Inc. trademarks, including the mark "WHISTLE + * COMMUNICATIONS" on advertising, endorsements, or otherwise except as + * such appears in the above copyright notice or in the software. + * + * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND + * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO + * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, + * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. + * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY + * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS + * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. + * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES + * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING + * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER 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 WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY + * OF SUCH DAMAGE. + * + * Author: Archie Cobbs <archie@freebsd.org> + * + * $FreeBSD$ + */ + +#ifndef _DEV_ICHSMB_ICHSMB_VAR_H +#define _DEV_ICHSMB_ICHSMB_VAR_H + +#include "smbus_if.h" + +/* Per-device private info */ +struct ichsmb_softc { + + /* Device/bus stuff */ + device_t dev; /* this device */ + struct resource *io_res; /* i/o port resource */ + int io_rid; /* i/o port bus id */ + bus_space_tag_t io_bst; /* bus space tag */ + bus_space_handle_t io_bsh; /* bus space handle */ + struct resource *irq_res; /* interrupt resource */ + int irq_rid; /* interrupt bus id */ + void *irq_handle; /* handle for interrupt code */ + + /* Device state */ + int ich_cmd; /* ich command, or -1 */ + int smb_error; /* result of smb command */ + int block_count; /* count for block read/write */ + int block_index; /* index for block read/write */ + u_char block_write; /* 0=read, 1=write */ + u_char block_data[32]; /* block read/write data */ +}; +typedef struct ichsmb_softc *sc_p; + +/* SMBus methods */ +extern smbus_callback_t ichsmb_callback; +extern smbus_quick_t ichsmb_quick; +extern smbus_sendb_t ichsmb_sendb; +extern smbus_recvb_t ichsmb_recvb; +extern smbus_writeb_t ichsmb_writeb; +extern smbus_writew_t ichsmb_writew; +extern smbus_readb_t ichsmb_readb; +extern smbus_readw_t ichsmb_readw; +extern smbus_pcall_t ichsmb_pcall; +extern smbus_bwrite_t ichsmb_bwrite; +extern smbus_bread_t ichsmb_bread; + +/* Other functions */ +extern void ichsmb_device_intr(void *cookie); +extern void ichsmb_release_resources(sc_p sc); +extern int ichsmb_probe(device_t dev); +extern int ichsmb_attach(device_t dev); + +#endif /* _DEV_ICHSMB_ICHSMB_VAR_H */ + diff --git a/sys/dev/smbus/smbus.c b/sys/dev/smbus/smbus.c index a1d3634aa7f0..3d565c23e4e3 100644 --- a/sys/dev/smbus/smbus.c +++ b/sys/dev/smbus/smbus.c @@ -149,3 +149,4 @@ DRIVER_MODULE(smbus, iicsmb, smbus_driver, smbus_devclass, 0, 0); DRIVER_MODULE(smbus, bti2c, smbus_driver, smbus_devclass, 0, 0); DRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, 0, 0); DRIVER_MODULE(smbus, alsmb, smbus_driver, smbus_devclass, 0, 0); +DRIVER_MODULE(smbus, ichsmb, smbus_driver, smbus_devclass, 0, 0); diff --git a/sys/i386/conf/NOTES b/sys/i386/conf/NOTES index e31b26b4d929..3299cd8e05b0 100644 --- a/sys/i386/conf/NOTES +++ b/sys/i386/conf/NOTES @@ -2120,20 +2120,25 @@ options POWERFAIL_NMI # make it beep instead of panicing # # SMB bus # -# System Management Bus support provided by the 'smbus' device. +# System Management Bus support is provided by the 'smbus' device. +# Access to the SMBus device is via the 'smb' device (/dev/smb*), +# which is a child of the 'smbus' device. # # Supported devices: -# smb standard io +# smb standard io through /dev/smb* # -# Supported interfaces: -# iicsmb I2C to SMB bridge with any iicbus interface -# bktr brooktree848 I2C hardware interface -# intpm Intel PIIX4 Power Management Unit -# alpm Acer Aladdin-IV/V/Pro2 Power Management Unit +# Supported SMB interfaces: +# iicsmb I2C to SMB bridge with any iicbus interface +# bktr brooktree848 I2C hardware interface +# intpm Intel PIIX4 Power Management Unit +# alpm Acer Aladdin-IV/V/Pro2 Power Management Unit +# ichsmb Intel ICH SMBus controller chips (82801AA, 82801AB, 82801BA) # device smbus # Bus support, required for smb below. + device intpm device alpm 1 +device ichsmb device smb |