diff options
author | rpaulo <rpaulo@FreeBSD.org> | 2014-09-23 06:31:15 +0000 |
---|---|---|
committer | rpaulo <rpaulo@FreeBSD.org> | 2014-09-23 06:31:15 +0000 |
commit | 9c838a1753862a349ee3e7abc47f1a9eb7d35468 (patch) | |
tree | 7741b1858d59eeed0e432d6c8b6ad479bc42b3e0 /sys/pci/intpm.c | |
parent | 68d667af8d28daefe9cfec476ee7d27ebd0deb43 (diff) | |
download | FreeBSD-src-9c838a1753862a349ee3e7abc47f1a9eb7d35468.zip FreeBSD-src-9c838a1753862a349ee3e7abc47f1a9eb7d35468.tar.gz |
Move all the power management (SMBus) drivers to their own directory,
away from sys/pci.
Diffstat (limited to 'sys/pci/intpm.c')
-rw-r--r-- | sys/pci/intpm.c | 819 |
1 files changed, 0 insertions, 819 deletions
diff --git a/sys/pci/intpm.c b/sys/pci/intpm.c deleted file mode 100644 index 48ff26e..0000000 --- a/sys/pci/intpm.c +++ /dev/null @@ -1,819 +0,0 @@ -/*- - * Copyright (c) 1998, 1999 Takanori Watanabe - * 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. - */ - -#include <sys/cdefs.h> -__FBSDID("$FreeBSD$"); - -#include <sys/param.h> -#include <sys/systm.h> -#include <sys/bus.h> -#include <sys/kernel.h> -#include <sys/lock.h> -#include <sys/module.h> -#include <sys/mutex.h> -#include <sys/rman.h> -#include <machine/bus.h> -#include <dev/smbus/smbconf.h> - -#include "smbus_if.h" - -#include <dev/pci/pcireg.h> -#include <dev/pci/pcivar.h> -#include <pci/intpmreg.h> - -#include "opt_intpm.h" - -struct intsmb_softc { - device_t dev; - struct resource *io_res; - struct resource *irq_res; - void *irq_hand; - device_t smbus; - int isbusy; - int cfg_irq9; - int poll; - struct mtx lock; -}; - -#define INTSMB_LOCK(sc) mtx_lock(&(sc)->lock) -#define INTSMB_UNLOCK(sc) mtx_unlock(&(sc)->lock) -#define INTSMB_LOCK_ASSERT(sc) mtx_assert(&(sc)->lock, MA_OWNED) - -static int intsmb_probe(device_t); -static int intsmb_attach(device_t); -static int intsmb_detach(device_t); -static int intsmb_intr(struct intsmb_softc *sc); -static int intsmb_slvintr(struct intsmb_softc *sc); -static void intsmb_alrintr(struct intsmb_softc *sc); -static int intsmb_callback(device_t dev, int index, void *data); -static int intsmb_quick(device_t dev, u_char slave, int how); -static int intsmb_sendb(device_t dev, u_char slave, char byte); -static int intsmb_recvb(device_t dev, u_char slave, char *byte); -static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); -static int intsmb_writew(device_t dev, u_char slave, char cmd, short word); -static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); -static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); -static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); -static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); -static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf); -static void intsmb_start(struct intsmb_softc *sc, u_char cmd, int nointr); -static int intsmb_stop(struct intsmb_softc *sc); -static int intsmb_stop_poll(struct intsmb_softc *sc); -static int intsmb_free(struct intsmb_softc *sc); -static void intsmb_rawintr(void *arg); - -static int -intsmb_probe(device_t dev) -{ - - switch (pci_get_devid(dev)) { - case 0x71138086: /* Intel 82371AB */ - case 0x719b8086: /* Intel 82443MX */ -#if 0 - /* Not a good idea yet, this stops isab0 functioning */ - case 0x02001166: /* ServerWorks OSB4 */ -#endif - device_set_desc(dev, "Intel PIIX4 SMBUS Interface"); - break; - case 0x43721002: - device_set_desc(dev, "ATI IXP400 SMBus Controller"); - break; - case 0x43851002: - /* SB800 and newer can not be configured in a compatible way. */ - if (pci_get_revid(dev) >= 0x40) - return (ENXIO); - device_set_desc(dev, "AMD SB600/700/710/750 SMBus Controller"); - /* XXX Maybe force polling right here? */ - break; - default: - return (ENXIO); - } - - return (BUS_PROBE_DEFAULT); -} - -static int -intsmb_attach(device_t dev) -{ - struct intsmb_softc *sc = device_get_softc(dev); - int error, rid, value; - int intr; - char *str; - - sc->dev = dev; - - mtx_init(&sc->lock, device_get_nameunit(dev), "intsmb", MTX_DEF); - - sc->cfg_irq9 = 0; -#ifndef NO_CHANGE_PCICONF - switch (pci_get_devid(dev)) { - case 0x71138086: /* Intel 82371AB */ - case 0x719b8086: /* Intel 82443MX */ - /* Changing configuration is allowed. */ - sc->cfg_irq9 = 1; - break; - } -#endif - - rid = PCI_BASE_ADDR_SMB; - sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, - RF_ACTIVE); - if (sc->io_res == NULL) { - device_printf(dev, "Could not allocate I/O space\n"); - error = ENXIO; - goto fail; - } - - if (sc->cfg_irq9) { - pci_write_config(dev, PCIR_INTLINE, 0x9, 1); - pci_write_config(dev, PCI_HST_CFG_SMB, - PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1); - } - value = pci_read_config(dev, PCI_HST_CFG_SMB, 1); - sc->poll = (value & PCI_INTR_SMB_ENABLE) == 0; - intr = value & PCI_INTR_SMB_MASK; - switch (intr) { - case PCI_INTR_SMB_SMI: - str = "SMI"; - break; - case PCI_INTR_SMB_IRQ9: - str = "IRQ 9"; - break; - case PCI_INTR_SMB_IRQ_PCI: - str = "PCI IRQ"; - break; - default: - str = "BOGUS"; - } - - device_printf(dev, "intr %s %s ", str, - sc->poll == 0 ? "enabled" : "disabled"); - printf("revision %d\n", pci_read_config(dev, PCI_REVID_SMB, 1)); - - if (!sc->poll && intr == PCI_INTR_SMB_SMI) { - device_printf(dev, - "using polling mode when configured interrupt is SMI\n"); - sc->poll = 1; - } - - if (sc->poll) - goto no_intr; - - if (intr != PCI_INTR_SMB_IRQ9 && intr != PCI_INTR_SMB_IRQ_PCI) { - device_printf(dev, "Unsupported interrupt mode\n"); - error = ENXIO; - goto fail; - } - - /* Force IRQ 9. */ - rid = 0; - if (sc->cfg_irq9) - bus_set_resource(dev, SYS_RES_IRQ, rid, 9, 1); - - sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, - RF_SHAREABLE | RF_ACTIVE); - if (sc->irq_res == NULL) { - device_printf(dev, "Could not allocate irq\n"); - error = ENXIO; - goto fail; - } - - error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, - NULL, intsmb_rawintr, sc, &sc->irq_hand); - if (error) { - device_printf(dev, "Failed to map intr\n"); - goto fail; - } - -no_intr: - sc->isbusy = 0; - sc->smbus = device_add_child(dev, "smbus", -1); - if (sc->smbus == NULL) { - error = ENXIO; - goto fail; - } - error = device_probe_and_attach(sc->smbus); - if (error) - goto fail; - -#ifdef ENABLE_ALART - /* Enable Arart */ - bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN); -#endif - return (0); - -fail: - intsmb_detach(dev); - return (error); -} - -static int -intsmb_detach(device_t dev) -{ - struct intsmb_softc *sc = device_get_softc(dev); - int error; - - error = bus_generic_detach(dev); - if (error) - return (error); - - if (sc->smbus) - device_delete_child(dev, sc->smbus); - if (sc->irq_hand) - bus_teardown_intr(dev, sc->irq_res, sc->irq_hand); - if (sc->irq_res) - bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res); - if (sc->io_res) - bus_release_resource(dev, SYS_RES_IOPORT, PCI_BASE_ADDR_SMB, - sc->io_res); - mtx_destroy(&sc->lock); - return (0); -} - -static void -intsmb_rawintr(void *arg) -{ - struct intsmb_softc *sc = arg; - - INTSMB_LOCK(sc); - intsmb_intr(sc); - intsmb_slvintr(sc); - INTSMB_UNLOCK(sc); -} - -static int -intsmb_callback(device_t dev, int index, void *data) -{ - int error = 0; - - switch (index) { - case SMB_REQUEST_BUS: - break; - case SMB_RELEASE_BUS: - break; - default: - error = SMB_EINVAL; - } - - return (error); -} - -/* Counterpart of smbtx_smb_free(). */ -static int -intsmb_free(struct intsmb_softc *sc) -{ - - INTSMB_LOCK_ASSERT(sc); - if ((bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) & PIIX4_SMBHSTSTAT_BUSY) || -#ifdef ENABLE_ALART - (bus_read_1(sc->io_res, PIIX4_SMBSLVSTS) & PIIX4_SMBSLVSTS_BUSY) || -#endif - sc->isbusy) - return (SMB_EBUSY); - - sc->isbusy = 1; - /* Disable Interrupt in slave part. */ -#ifndef ENABLE_ALART - bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 0); -#endif - /* Reset INTR Flag to prepare INTR. */ - bus_write_1(sc->io_res, PIIX4_SMBHSTSTS, - PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR | - PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL); - return (0); -} - -static int -intsmb_intr(struct intsmb_softc *sc) -{ - int status, tmp; - - status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS); - if (status & PIIX4_SMBHSTSTAT_BUSY) - return (1); - - if (status & (PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR | - PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL)) { - - tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); - bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, - tmp & ~PIIX4_SMBHSTCNT_INTREN); - if (sc->isbusy) { - sc->isbusy = 0; - wakeup(sc); - } - return (0); - } - return (1); /* Not Completed */ -} - -static int -intsmb_slvintr(struct intsmb_softc *sc) -{ - int status; - - status = bus_read_1(sc->io_res, PIIX4_SMBSLVSTS); - if (status & PIIX4_SMBSLVSTS_BUSY) - return (1); - if (status & PIIX4_SMBSLVSTS_ALART) - intsmb_alrintr(sc); - else if (status & ~(PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 - | PIIX4_SMBSLVSTS_SDW1)) { - } - - /* Reset Status Register */ - bus_write_1(sc->io_res, PIIX4_SMBSLVSTS, - PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 | - PIIX4_SMBSLVSTS_SDW1 | PIIX4_SMBSLVSTS_SLV); - return (0); -} - -static void -intsmb_alrintr(struct intsmb_softc *sc) -{ - int slvcnt; -#ifdef ENABLE_ALART - int error; - uint8_t addr; -#endif - - /* Stop generating INTR from ALART. */ - slvcnt = bus_read_1(sc->io_res, PIIX4_SMBSLVCNT); -#ifdef ENABLE_ALART - bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, - slvcnt & ~PIIX4_SMBSLVCNT_ALTEN); -#endif - DELAY(5); - - /* Ask bus who asserted it and then ask it what's the matter. */ -#ifdef ENABLE_ALART - error = intsmb_free(sc); - if (error) - return; - - bus_write_1(sc->io_res, PIIX4_SMBHSTADD, SMBALTRESP | LSB); - intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 1); - error = intsmb_stop_poll(sc); - if (error) - device_printf(sc->dev, "ALART: ERROR\n"); - else { - addr = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); - device_printf(sc->dev, "ALART_RESPONSE: 0x%x\n", addr); - } - - /* Re-enable INTR from ALART. */ - bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, - slvcnt | PIIX4_SMBSLVCNT_ALTEN); - DELAY(5); -#endif -} - -static void -intsmb_start(struct intsmb_softc *sc, unsigned char cmd, int nointr) -{ - unsigned char tmp; - - INTSMB_LOCK_ASSERT(sc); - tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); - tmp &= 0xe0; - tmp |= cmd; - tmp |= PIIX4_SMBHSTCNT_START; - - /* While not in autoconfiguration enable interrupts. */ - if (!sc->poll && !cold && !nointr) - tmp |= PIIX4_SMBHSTCNT_INTREN; - bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp); -} - -static int -intsmb_error(device_t dev, int status) -{ - int error = 0; - - if (status & PIIX4_SMBHSTSTAT_ERR) - error |= SMB_EBUSERR; - if (status & PIIX4_SMBHSTSTAT_BUSC) - error |= SMB_ECOLLI; - if (status & PIIX4_SMBHSTSTAT_FAIL) - error |= SMB_ENOACK; - - if (error != 0 && bootverbose) - device_printf(dev, "error = %d, status = %#x\n", error, status); - - return (error); -} - -/* - * Polling Code. - * - * Polling is not encouraged because it requires waiting for the - * device if it is busy. - * (29063505.pdf from Intel) But during boot, interrupt cannot be used, so use - * polling code then. - */ -static int -intsmb_stop_poll(struct intsmb_softc *sc) -{ - int error, i, status, tmp; - - INTSMB_LOCK_ASSERT(sc); - - /* First, wait for busy to be set. */ - for (i = 0; i < 0x7fff; i++) - if (bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) & - PIIX4_SMBHSTSTAT_BUSY) - break; - - /* Wait for busy to clear. */ - for (i = 0; i < 0x7fff; i++) { - status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS); - if (!(status & PIIX4_SMBHSTSTAT_BUSY)) { - sc->isbusy = 0; - error = intsmb_error(sc->dev, status); - return (error); - } - } - - /* Timed out waiting for busy to clear. */ - sc->isbusy = 0; - tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); - bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp & ~PIIX4_SMBHSTCNT_INTREN); - return (SMB_ETIMEOUT); -} - -/* - * Wait for completion and return result. - */ -static int -intsmb_stop(struct intsmb_softc *sc) -{ - int error, status; - - INTSMB_LOCK_ASSERT(sc); - - if (sc->poll || cold) - /* So that it can use device during device probe on SMBus. */ - return (intsmb_stop_poll(sc)); - - error = msleep(sc, &sc->lock, PWAIT | PCATCH, "SMBWAI", hz / 8); - if (error == 0) { - status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS); - if (!(status & PIIX4_SMBHSTSTAT_BUSY)) { - error = intsmb_error(sc->dev, status); - if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR)) - device_printf(sc->dev, "unknown cause why?\n"); -#ifdef ENABLE_ALART - bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, - PIIX4_SMBSLVCNT_ALTEN); -#endif - return (error); - } - } - - /* Timeout Procedure. */ - sc->isbusy = 0; - - /* Re-enable supressed interrupt from slave part. */ - bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN); - if (error == EWOULDBLOCK) - return (SMB_ETIMEOUT); - else - return (SMB_EABORT); -} - -static int -intsmb_quick(device_t dev, u_char slave, int how) -{ - struct intsmb_softc *sc = device_get_softc(dev); - int error; - u_char data; - - data = slave; - - /* Quick command is part of Address, I think. */ - switch(how) { - case SMB_QWRITE: - data &= ~LSB; - break; - case SMB_QREAD: - data |= LSB; - break; - default: - return (SMB_EINVAL); - } - - INTSMB_LOCK(sc); - error = intsmb_free(sc); - if (error) { - INTSMB_UNLOCK(sc); - return (error); - } - bus_write_1(sc->io_res, PIIX4_SMBHSTADD, data); - intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_QUICK, 0); - error = intsmb_stop(sc); - INTSMB_UNLOCK(sc); - return (error); -} - -static int -intsmb_sendb(device_t dev, u_char slave, char byte) -{ - struct intsmb_softc *sc = device_get_softc(dev); - int error; - - INTSMB_LOCK(sc); - error = intsmb_free(sc); - if (error) { - INTSMB_UNLOCK(sc); - return (error); - } - bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); - bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, byte); - intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0); - error = intsmb_stop(sc); - INTSMB_UNLOCK(sc); - return (error); -} - -static int -intsmb_recvb(device_t dev, u_char slave, char *byte) -{ - struct intsmb_softc *sc = device_get_softc(dev); - int error; - - INTSMB_LOCK(sc); - error = intsmb_free(sc); - if (error) { - INTSMB_UNLOCK(sc); - return (error); - } - bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); - intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0); - error = intsmb_stop(sc); - if (error == 0) { -#ifdef RECV_IS_IN_CMD - /* - * Linux SMBus stuff also troubles - * Because Intel's datasheet does not make clear. - */ - *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTCMD); -#else - *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); -#endif - } - INTSMB_UNLOCK(sc); - return (error); -} - -static int -intsmb_writeb(device_t dev, u_char slave, char cmd, char byte) -{ - struct intsmb_softc *sc = device_get_softc(dev); - int error; - - INTSMB_LOCK(sc); - error = intsmb_free(sc); - if (error) { - INTSMB_UNLOCK(sc); - return (error); - } - bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); - bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); - bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, byte); - intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0); - error = intsmb_stop(sc); - INTSMB_UNLOCK(sc); - return (error); -} - -static int -intsmb_writew(device_t dev, u_char slave, char cmd, short word) -{ - struct intsmb_softc *sc = device_get_softc(dev); - int error; - - INTSMB_LOCK(sc); - error = intsmb_free(sc); - if (error) { - INTSMB_UNLOCK(sc); - return (error); - } - bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); - bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); - bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, word & 0xff); - bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (word >> 8) & 0xff); - intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0); - error = intsmb_stop(sc); - INTSMB_UNLOCK(sc); - return (error); -} - -static int -intsmb_readb(device_t dev, u_char slave, char cmd, char *byte) -{ - struct intsmb_softc *sc = device_get_softc(dev); - int error; - - INTSMB_LOCK(sc); - error = intsmb_free(sc); - if (error) { - INTSMB_UNLOCK(sc); - return (error); - } - bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); - bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); - intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0); - error = intsmb_stop(sc); - if (error == 0) - *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); - INTSMB_UNLOCK(sc); - return (error); -} - -static int -intsmb_readw(device_t dev, u_char slave, char cmd, short *word) -{ - struct intsmb_softc *sc = device_get_softc(dev); - int error; - - INTSMB_LOCK(sc); - error = intsmb_free(sc); - if (error) { - INTSMB_UNLOCK(sc); - return (error); - } - bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); - bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); - intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0); - error = intsmb_stop(sc); - if (error == 0) { - *word = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); - *word |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8; - } - INTSMB_UNLOCK(sc); - return (error); -} - -/* - * Data sheet claims that it implements all function, but also claims - * that it implements 7 function and not mention PCALL. So I don't know - * whether it will work. - */ -static int -intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) -{ -#ifdef PROCCALL_TEST - struct intsmb_softc *sc = device_get_softc(dev); - int error; - - INTSMB_LOCK(sc); - error = intsmb_free(sc); - if (error) { - INTSMB_UNLOCK(sc); - return (error); - } - bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); - bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); - bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, sdata & 0xff); - bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (sdata & 0xff) >> 8); - intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0); - error = intsmb_stop(sc); - if (error == 0) { - *rdata = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); - *rdata |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8; - } - INTSMB_UNLOCK(sc); - return (error); -#else - return (SMB_ENOTSUPP); -#endif -} - -static int -intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) -{ - struct intsmb_softc *sc = device_get_softc(dev); - int error, i; - - if (count > SMBBLOCKTRANS_MAX || count == 0) - return (SMB_EINVAL); - - INTSMB_LOCK(sc); - error = intsmb_free(sc); - if (error) { - INTSMB_UNLOCK(sc); - return (error); - } - - /* Reset internal array index. */ - bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); - - bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB); - bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); - for (i = 0; i < count; i++) - bus_write_1(sc->io_res, PIIX4_SMBBLKDAT, buf[i]); - bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, count); - intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0); - error = intsmb_stop(sc); - INTSMB_UNLOCK(sc); - return (error); -} - -static int -intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) -{ - struct intsmb_softc *sc = device_get_softc(dev); - int error, i; - u_char data, nread; - - if (*count > SMBBLOCKTRANS_MAX || *count == 0) - return (SMB_EINVAL); - - INTSMB_LOCK(sc); - error = intsmb_free(sc); - if (error) { - INTSMB_UNLOCK(sc); - return (error); - } - - /* Reset internal array index. */ - bus_read_1(sc->io_res, PIIX4_SMBHSTCNT); - - bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB); - bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd); - bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, *count); - intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0); - error = intsmb_stop(sc); - if (error == 0) { - nread = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0); - if (nread != 0 && nread <= SMBBLOCKTRANS_MAX) { - for (i = 0; i < nread; i++) { - data = bus_read_1(sc->io_res, PIIX4_SMBBLKDAT); - if (i < *count) - buf[i] = data; - } - *count = nread; - } else - error = SMB_EBUSERR; - } - INTSMB_UNLOCK(sc); - return (error); -} - -static devclass_t intsmb_devclass; - -static device_method_t intsmb_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, intsmb_probe), - DEVMETHOD(device_attach, intsmb_attach), - DEVMETHOD(device_detach, intsmb_detach), - - /* SMBus interface */ - DEVMETHOD(smbus_callback, intsmb_callback), - DEVMETHOD(smbus_quick, intsmb_quick), - DEVMETHOD(smbus_sendb, intsmb_sendb), - DEVMETHOD(smbus_recvb, intsmb_recvb), - DEVMETHOD(smbus_writeb, intsmb_writeb), - DEVMETHOD(smbus_writew, intsmb_writew), - DEVMETHOD(smbus_readb, intsmb_readb), - DEVMETHOD(smbus_readw, intsmb_readw), - DEVMETHOD(smbus_pcall, intsmb_pcall), - DEVMETHOD(smbus_bwrite, intsmb_bwrite), - DEVMETHOD(smbus_bread, intsmb_bread), - - DEVMETHOD_END -}; - -static driver_t intsmb_driver = { - "intsmb", - intsmb_methods, - sizeof(struct intsmb_softc), -}; - -DRIVER_MODULE(intsmb, pci, intsmb_driver, intsmb_devclass, 0, 0); -DRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, 0, 0); -MODULE_DEPEND(intsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); -MODULE_VERSION(intsmb, 1); |