13c5656bfSArchie Cobbs 23c5656bfSArchie Cobbs /* 33c5656bfSArchie Cobbs * ichsmb.c 43c5656bfSArchie Cobbs * 53c5656bfSArchie Cobbs * Copyright (c) 2000 Whistle Communications, Inc. 63c5656bfSArchie Cobbs * All rights reserved. 73c5656bfSArchie Cobbs * 83c5656bfSArchie Cobbs * Subject to the following obligations and disclaimer of warranty, use and 93c5656bfSArchie Cobbs * redistribution of this software, in source or object code forms, with or 103c5656bfSArchie Cobbs * without modifications are expressly permitted by Whistle Communications; 113c5656bfSArchie Cobbs * provided, however, that: 123c5656bfSArchie Cobbs * 1. Any and all reproductions of the source or object code must include the 133c5656bfSArchie Cobbs * copyright notice above and the following disclaimer of warranties; and 143c5656bfSArchie Cobbs * 2. No rights are granted, in any manner or form, to use Whistle 153c5656bfSArchie Cobbs * Communications, Inc. trademarks, including the mark "WHISTLE 163c5656bfSArchie Cobbs * COMMUNICATIONS" on advertising, endorsements, or otherwise except as 173c5656bfSArchie Cobbs * such appears in the above copyright notice or in the software. 183c5656bfSArchie Cobbs * 193c5656bfSArchie Cobbs * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND 203c5656bfSArchie Cobbs * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO 213c5656bfSArchie Cobbs * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE, 223c5656bfSArchie Cobbs * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF 233c5656bfSArchie Cobbs * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT. 243c5656bfSArchie Cobbs * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY 253c5656bfSArchie Cobbs * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS 263c5656bfSArchie Cobbs * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE. 273c5656bfSArchie Cobbs * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES 283c5656bfSArchie Cobbs * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING 293c5656bfSArchie Cobbs * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 303c5656bfSArchie Cobbs * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR 313c5656bfSArchie Cobbs * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY 323c5656bfSArchie Cobbs * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 333c5656bfSArchie Cobbs * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 343c5656bfSArchie Cobbs * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY 353c5656bfSArchie Cobbs * OF SUCH DAMAGE. 363c5656bfSArchie Cobbs * 373c5656bfSArchie Cobbs * Author: Archie Cobbs <archie@freebsd.org> 383c5656bfSArchie Cobbs * 393c5656bfSArchie Cobbs * $FreeBSD$ 403c5656bfSArchie Cobbs */ 413c5656bfSArchie Cobbs 423c5656bfSArchie Cobbs /* 433c5656bfSArchie Cobbs * Support for the SMBus controller logical device which is part of the 443c5656bfSArchie Cobbs * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips. 453c5656bfSArchie Cobbs */ 463c5656bfSArchie Cobbs 473c5656bfSArchie Cobbs #include <sys/param.h> 483c5656bfSArchie Cobbs #include <sys/systm.h> 493c5656bfSArchie Cobbs #include <sys/kernel.h> 503c5656bfSArchie Cobbs #include <sys/errno.h> 513c5656bfSArchie Cobbs #include <sys/syslog.h> 523c5656bfSArchie Cobbs #include <sys/bus.h> 533c5656bfSArchie Cobbs 543c5656bfSArchie Cobbs #include <machine/bus.h> 553c5656bfSArchie Cobbs #include <sys/rman.h> 563c5656bfSArchie Cobbs #include <machine/resource.h> 573c5656bfSArchie Cobbs 583c5656bfSArchie Cobbs #include <dev/smbus/smbconf.h> 593c5656bfSArchie Cobbs 603c5656bfSArchie Cobbs #include <dev/ichsmb/ichsmb_var.h> 613c5656bfSArchie Cobbs #include <dev/ichsmb/ichsmb_reg.h> 623c5656bfSArchie Cobbs 633c5656bfSArchie Cobbs /* 643c5656bfSArchie Cobbs * Enable debugging by defining ICHSMB_DEBUG to a non-zero value. 653c5656bfSArchie Cobbs */ 663c5656bfSArchie Cobbs #define ICHSMB_DEBUG 0 673c5656bfSArchie Cobbs #if ICHSMB_DEBUG != 0 && defined(__GNUC__) 683c5656bfSArchie Cobbs #define DBG(fmt, args...) \ 693c5656bfSArchie Cobbs do { log(LOG_DEBUG, "%s: " fmt, __FUNCTION__ , ## args); } while (0) 703c5656bfSArchie Cobbs #else 713c5656bfSArchie Cobbs #define DBG(fmt, args...) do { } while (0) 723c5656bfSArchie Cobbs #endif 733c5656bfSArchie Cobbs 743c5656bfSArchie Cobbs /* 753c5656bfSArchie Cobbs * Our child device driver name 763c5656bfSArchie Cobbs */ 773c5656bfSArchie Cobbs #define DRIVER_SMBUS "smbus" 783c5656bfSArchie Cobbs 793c5656bfSArchie Cobbs /* 803c5656bfSArchie Cobbs * Internal functions 813c5656bfSArchie Cobbs */ 823c5656bfSArchie Cobbs static int ichsmb_wait(sc_p sc); 833c5656bfSArchie Cobbs 843c5656bfSArchie Cobbs /******************************************************************** 853c5656bfSArchie Cobbs BUS-INDEPENDENT BUS METHODS 863c5656bfSArchie Cobbs ********************************************************************/ 873c5656bfSArchie Cobbs 883c5656bfSArchie Cobbs /* 893c5656bfSArchie Cobbs * Handle probe-time duties that are independent of the bus 903c5656bfSArchie Cobbs * our device lives on. 913c5656bfSArchie Cobbs */ 923c5656bfSArchie Cobbs int 933c5656bfSArchie Cobbs ichsmb_probe(device_t dev) 943c5656bfSArchie Cobbs { 953c5656bfSArchie Cobbs device_t smb; 963c5656bfSArchie Cobbs 973c5656bfSArchie Cobbs /* Add child: an instance of the "smbus" device */ 983c5656bfSArchie Cobbs if ((smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) { 993c5656bfSArchie Cobbs log(LOG_ERR, "%s: no \"%s\" child found\n", 1003c5656bfSArchie Cobbs device_get_nameunit(dev), DRIVER_SMBUS); 1013c5656bfSArchie Cobbs return (ENXIO); 1023c5656bfSArchie Cobbs } 1033c5656bfSArchie Cobbs return (0); 1043c5656bfSArchie Cobbs } 1053c5656bfSArchie Cobbs 1063c5656bfSArchie Cobbs /* 1073c5656bfSArchie Cobbs * Handle attach-time duties that are independent of the bus 1083c5656bfSArchie Cobbs * our device lives on. 1093c5656bfSArchie Cobbs */ 1103c5656bfSArchie Cobbs int 1113c5656bfSArchie Cobbs ichsmb_attach(device_t dev) 1123c5656bfSArchie Cobbs { 1133c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 1143c5656bfSArchie Cobbs int error; 1153c5656bfSArchie Cobbs 1163c5656bfSArchie Cobbs /* Clear interrupt conditions */ 1173c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, 0xff); 1183c5656bfSArchie Cobbs 1193c5656bfSArchie Cobbs /* Add "smbus" child */ 1203c5656bfSArchie Cobbs if ((error = bus_generic_attach(dev)) != 0) { 1213c5656bfSArchie Cobbs log(LOG_ERR, "%s: failed to attach child: %d\n", 1223c5656bfSArchie Cobbs device_get_nameunit(dev), error); 1233c5656bfSArchie Cobbs error = ENXIO; 1243c5656bfSArchie Cobbs } 1253c5656bfSArchie Cobbs 1263c5656bfSArchie Cobbs /* Done */ 1273c5656bfSArchie Cobbs return (error); 1283c5656bfSArchie Cobbs } 1293c5656bfSArchie Cobbs 1303c5656bfSArchie Cobbs /******************************************************************** 1313c5656bfSArchie Cobbs SMBUS METHODS 1323c5656bfSArchie Cobbs ********************************************************************/ 1333c5656bfSArchie Cobbs 1343c5656bfSArchie Cobbs int 1353c5656bfSArchie Cobbs ichsmb_callback(device_t dev, int index, caddr_t data) 1363c5656bfSArchie Cobbs { 1373c5656bfSArchie Cobbs int smb_error = 0; 1383c5656bfSArchie Cobbs 1393c5656bfSArchie Cobbs DBG("index=%d how=%d\n", index, data ? *(int *)data : -1); 1403c5656bfSArchie Cobbs switch (index) { 1413c5656bfSArchie Cobbs case SMB_REQUEST_BUS: 1423c5656bfSArchie Cobbs break; 1433c5656bfSArchie Cobbs case SMB_RELEASE_BUS: 1443c5656bfSArchie Cobbs break; 1453c5656bfSArchie Cobbs default: 1463c5656bfSArchie Cobbs smb_error = SMB_EABORT; /* XXX */ 1473c5656bfSArchie Cobbs break; 1483c5656bfSArchie Cobbs } 1493c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 1503c5656bfSArchie Cobbs return (smb_error); 1513c5656bfSArchie Cobbs } 1523c5656bfSArchie Cobbs 1533c5656bfSArchie Cobbs int 1543c5656bfSArchie Cobbs ichsmb_quick(device_t dev, u_char slave, int how) 1553c5656bfSArchie Cobbs { 1563c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 1573c5656bfSArchie Cobbs int smb_error; 1583c5656bfSArchie Cobbs int s; 1593c5656bfSArchie Cobbs 1603c5656bfSArchie Cobbs DBG("slave=0x%02x how=%d\n", slave, how); 1613c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 1623c5656bfSArchie Cobbs ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); 1633c5656bfSArchie Cobbs switch (how) { 1643c5656bfSArchie Cobbs case SMB_QREAD: 1653c5656bfSArchie Cobbs case SMB_QWRITE: 1663c5656bfSArchie Cobbs s = splhigh(); 1673c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK; 1683c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 1693c5656bfSArchie Cobbs (slave << 1) | (how == SMB_QREAD ? 1703c5656bfSArchie Cobbs ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE)); 1713c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 1723c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 1733c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 1743c5656bfSArchie Cobbs splx(s); 1753c5656bfSArchie Cobbs break; 1763c5656bfSArchie Cobbs default: 1773c5656bfSArchie Cobbs smb_error = SMB_ENOTSUPP; 1783c5656bfSArchie Cobbs } 1793c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 1803c5656bfSArchie Cobbs return (smb_error); 1813c5656bfSArchie Cobbs } 1823c5656bfSArchie Cobbs 1833c5656bfSArchie Cobbs int 1843c5656bfSArchie Cobbs ichsmb_sendb(device_t dev, u_char slave, char byte) 1853c5656bfSArchie Cobbs { 1863c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 1873c5656bfSArchie Cobbs int smb_error; 1883c5656bfSArchie Cobbs int s; 1893c5656bfSArchie Cobbs 1903c5656bfSArchie Cobbs DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte); 1913c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 1923c5656bfSArchie Cobbs ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); 1933c5656bfSArchie Cobbs s = splhigh(); 1943c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 1953c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 1963c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 1973c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, byte); 1983c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 1993c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2003c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2013c5656bfSArchie Cobbs splx(s); 2023c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2033c5656bfSArchie Cobbs return (smb_error); 2043c5656bfSArchie Cobbs } 2053c5656bfSArchie Cobbs 2063c5656bfSArchie Cobbs int 2073c5656bfSArchie Cobbs ichsmb_recvb(device_t dev, u_char slave, char *byte) 2083c5656bfSArchie Cobbs { 2093c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2103c5656bfSArchie Cobbs int smb_error; 2113c5656bfSArchie Cobbs int s; 2123c5656bfSArchie Cobbs 2133c5656bfSArchie Cobbs DBG("slave=0x%02x\n", slave); 2143c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2153c5656bfSArchie Cobbs ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); 2163c5656bfSArchie Cobbs s = splhigh(); 2173c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 2183c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2193c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 2203c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2213c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2223c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 2233c5656bfSArchie Cobbs *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0); 2243c5656bfSArchie Cobbs splx(s); 2253c5656bfSArchie Cobbs DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 2263c5656bfSArchie Cobbs return (smb_error); 2273c5656bfSArchie Cobbs } 2283c5656bfSArchie Cobbs 2293c5656bfSArchie Cobbs int 2303c5656bfSArchie Cobbs ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 2313c5656bfSArchie Cobbs { 2323c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2333c5656bfSArchie Cobbs int smb_error; 2343c5656bfSArchie Cobbs int s; 2353c5656bfSArchie Cobbs 2363c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n", 2373c5656bfSArchie Cobbs slave, (u_char)cmd, (u_char)byte); 2383c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2393c5656bfSArchie Cobbs ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); 2403c5656bfSArchie Cobbs s = splhigh(); 2413c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 2423c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2433c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 2443c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 2453c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, byte); 2463c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2473c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2483c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2493c5656bfSArchie Cobbs splx(s); 2503c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2513c5656bfSArchie Cobbs return (smb_error); 2523c5656bfSArchie Cobbs } 2533c5656bfSArchie Cobbs 2543c5656bfSArchie Cobbs int 2553c5656bfSArchie Cobbs ichsmb_writew(device_t dev, u_char slave, char cmd, short word) 2563c5656bfSArchie Cobbs { 2573c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2583c5656bfSArchie Cobbs int smb_error; 2593c5656bfSArchie Cobbs int s; 2603c5656bfSArchie Cobbs 2613c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n", 2623c5656bfSArchie Cobbs slave, (u_char)cmd, (u_int16_t)word); 2633c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2643c5656bfSArchie Cobbs ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); 2653c5656bfSArchie Cobbs s = splhigh(); 2663c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 2673c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2683c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 2693c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 2703c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, word & 0xff); 2713c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, word >> 8); 2723c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2733c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2743c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2753c5656bfSArchie Cobbs splx(s); 2763c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2773c5656bfSArchie Cobbs return (smb_error); 2783c5656bfSArchie Cobbs } 2793c5656bfSArchie Cobbs 2803c5656bfSArchie Cobbs int 2813c5656bfSArchie Cobbs ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 2823c5656bfSArchie Cobbs { 2833c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2843c5656bfSArchie Cobbs int smb_error; 2853c5656bfSArchie Cobbs int s; 2863c5656bfSArchie Cobbs 2873c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 2883c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2893c5656bfSArchie Cobbs ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); 2903c5656bfSArchie Cobbs s = splhigh(); 2913c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 2923c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 2933c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 2943c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 2953c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 2963c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2973c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 2983c5656bfSArchie Cobbs *byte = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_D0); 2993c5656bfSArchie Cobbs splx(s); 3003c5656bfSArchie Cobbs DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 3013c5656bfSArchie Cobbs return (smb_error); 3023c5656bfSArchie Cobbs } 3033c5656bfSArchie Cobbs 3043c5656bfSArchie Cobbs int 3053c5656bfSArchie Cobbs ichsmb_readw(device_t dev, u_char slave, char cmd, short *word) 3063c5656bfSArchie Cobbs { 3073c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3083c5656bfSArchie Cobbs int smb_error; 3093c5656bfSArchie Cobbs int s; 3103c5656bfSArchie Cobbs 3113c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 3123c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3133c5656bfSArchie Cobbs ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); 3143c5656bfSArchie Cobbs s = splhigh(); 3153c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 3163c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 3173c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 3183c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 3193c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 3203c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 3213c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 3223c5656bfSArchie Cobbs *word = (bus_space_read_1(sc->io_bst, 3233c5656bfSArchie Cobbs sc->io_bsh, ICH_D0) & 0xff) 3243c5656bfSArchie Cobbs | (bus_space_read_1(sc->io_bst, 3253c5656bfSArchie Cobbs sc->io_bsh, ICH_D1) << 8); 3263c5656bfSArchie Cobbs } 3273c5656bfSArchie Cobbs splx(s); 3283c5656bfSArchie Cobbs DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word); 3293c5656bfSArchie Cobbs return (smb_error); 3303c5656bfSArchie Cobbs } 3313c5656bfSArchie Cobbs 3323c5656bfSArchie Cobbs int 3333c5656bfSArchie Cobbs ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 3343c5656bfSArchie Cobbs { 3353c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3363c5656bfSArchie Cobbs int smb_error; 3373c5656bfSArchie Cobbs int s; 3383c5656bfSArchie Cobbs 3393c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n", 3403c5656bfSArchie Cobbs slave, (u_char)cmd, (u_int16_t)sdata); 3413c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3423c5656bfSArchie Cobbs ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); 3433c5656bfSArchie Cobbs s = splhigh(); 3443c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL; 3453c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 3463c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 3473c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 3483c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, sdata & 0xff); 3493c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D1, sdata >> 8); 3503c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 3513c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 3523c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 3533c5656bfSArchie Cobbs *rdata = (bus_space_read_1(sc->io_bst, 3543c5656bfSArchie Cobbs sc->io_bsh, ICH_D0) & 0xff) 3553c5656bfSArchie Cobbs | (bus_space_read_1(sc->io_bst, 3563c5656bfSArchie Cobbs sc->io_bsh, ICH_D1) << 8); 3573c5656bfSArchie Cobbs } 3583c5656bfSArchie Cobbs splx(s); 3593c5656bfSArchie Cobbs DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata); 3603c5656bfSArchie Cobbs return (smb_error); 3613c5656bfSArchie Cobbs } 3623c5656bfSArchie Cobbs 3633c5656bfSArchie Cobbs int 3643c5656bfSArchie Cobbs ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 3653c5656bfSArchie Cobbs { 3663c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3673c5656bfSArchie Cobbs int smb_error; 3683c5656bfSArchie Cobbs int s; 3693c5656bfSArchie Cobbs 3703c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 3713c5656bfSArchie Cobbs #if ICHSMB_DEBUG 3723c5656bfSArchie Cobbs #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 3733c5656bfSArchie Cobbs { 3743c5656bfSArchie Cobbs u_char *p; 3753c5656bfSArchie Cobbs 3763c5656bfSArchie Cobbs for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 3773c5656bfSArchie Cobbs DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 3783c5656bfSArchie Cobbs " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 3793c5656bfSArchie Cobbs p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 3803c5656bfSArchie Cobbs DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 3813c5656bfSArchie Cobbs DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 3823c5656bfSArchie Cobbs } 3833c5656bfSArchie Cobbs } 3843c5656bfSArchie Cobbs #undef DISP 3853c5656bfSArchie Cobbs #endif 3863c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3873c5656bfSArchie Cobbs ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); 3883c5656bfSArchie Cobbs if (count < 1 || count > 32) 3893c5656bfSArchie Cobbs return (EINVAL); 3903c5656bfSArchie Cobbs bcopy(buf, sc->block_data, count); 3913c5656bfSArchie Cobbs sc->block_count = count; 3923c5656bfSArchie Cobbs sc->block_index = 1; 3933c5656bfSArchie Cobbs sc->block_write = 1; 3943c5656bfSArchie Cobbs 3953c5656bfSArchie Cobbs s = splhigh(); 3963c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 3973c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 3983c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_WRITE); 3993c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 4003c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count); 4013c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_BLOCK_DB, buf[0]); 4023c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 4033c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 4043c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 4053c5656bfSArchie Cobbs splx(s); 4063c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 4073c5656bfSArchie Cobbs return (smb_error); 4083c5656bfSArchie Cobbs } 4093c5656bfSArchie Cobbs 4103c5656bfSArchie Cobbs int 4113c5656bfSArchie Cobbs ichsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) 4123c5656bfSArchie Cobbs { 4133c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 4143c5656bfSArchie Cobbs int smb_error; 4153c5656bfSArchie Cobbs int s; 4163c5656bfSArchie Cobbs 4173c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 4183c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 4193c5656bfSArchie Cobbs ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); 4203c5656bfSArchie Cobbs if (count < 1 || count > 32) 4213c5656bfSArchie Cobbs return (EINVAL); 4223c5656bfSArchie Cobbs bzero(sc->block_data, sizeof(sc->block_data)); 4233c5656bfSArchie Cobbs sc->block_count = count; 4243c5656bfSArchie Cobbs sc->block_index = 0; 4253c5656bfSArchie Cobbs sc->block_write = 0; 4263c5656bfSArchie Cobbs 4273c5656bfSArchie Cobbs s = splhigh(); 4283c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 4293c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_XMIT_SLVA, 4303c5656bfSArchie Cobbs (slave << 1) | ICH_XMIT_SLVA_READ); 4313c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CMD, cmd); 4323c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_D0, count); /* XXX? */ 4333c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_CNT, 4343c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 4353c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 4363c5656bfSArchie Cobbs bcopy(sc->block_data, buf, sc->block_count); 4373c5656bfSArchie Cobbs splx(s); 4383c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 4393c5656bfSArchie Cobbs #if ICHSMB_DEBUG 4403c5656bfSArchie Cobbs #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 4413c5656bfSArchie Cobbs { 4423c5656bfSArchie Cobbs u_char *p; 4433c5656bfSArchie Cobbs 4443c5656bfSArchie Cobbs for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 4453c5656bfSArchie Cobbs DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 4463c5656bfSArchie Cobbs " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 4473c5656bfSArchie Cobbs p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 4483c5656bfSArchie Cobbs DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 4493c5656bfSArchie Cobbs DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 4503c5656bfSArchie Cobbs } 4513c5656bfSArchie Cobbs } 4523c5656bfSArchie Cobbs #undef DISP 4533c5656bfSArchie Cobbs #endif 4543c5656bfSArchie Cobbs return (smb_error); 4553c5656bfSArchie Cobbs } 4563c5656bfSArchie Cobbs 4573c5656bfSArchie Cobbs /******************************************************************** 4583c5656bfSArchie Cobbs OTHER FUNCTIONS 4593c5656bfSArchie Cobbs ********************************************************************/ 4603c5656bfSArchie Cobbs 4613c5656bfSArchie Cobbs /* 4623c5656bfSArchie Cobbs * This table describes what interrupts we should ever expect to 4633c5656bfSArchie Cobbs * see after each ICH command, not including the SMBALERT interrupt. 4643c5656bfSArchie Cobbs */ 4653c5656bfSArchie Cobbs static const u_int8_t ichsmb_state_irqs[] = { 4663c5656bfSArchie Cobbs /* quick */ 4673c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4683c5656bfSArchie Cobbs /* byte */ 4693c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4703c5656bfSArchie Cobbs /* byte data */ 4713c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4723c5656bfSArchie Cobbs /* word data */ 4733c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4743c5656bfSArchie Cobbs /* process call */ 4753c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4763c5656bfSArchie Cobbs /* block */ 4773c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR 4783c5656bfSArchie Cobbs | ICH_HST_STA_BYTE_DONE_STS), 4793c5656bfSArchie Cobbs /* i2c read (not used) */ 4803c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR 4813c5656bfSArchie Cobbs | ICH_HST_STA_BYTE_DONE_STS) 4823c5656bfSArchie Cobbs }; 4833c5656bfSArchie Cobbs 4843c5656bfSArchie Cobbs /* 4853c5656bfSArchie Cobbs * Interrupt handler. This handler is bus-independent. Note that our 4863c5656bfSArchie Cobbs * interrupt may be shared, so we must handle "false" interrupts. 4873c5656bfSArchie Cobbs */ 4883c5656bfSArchie Cobbs void 4893c5656bfSArchie Cobbs ichsmb_device_intr(void *cookie) 4903c5656bfSArchie Cobbs { 4913c5656bfSArchie Cobbs const sc_p sc = cookie; 4923c5656bfSArchie Cobbs const device_t dev = sc->dev; 4933c5656bfSArchie Cobbs const int maxloops = 16; 4943c5656bfSArchie Cobbs u_int8_t status; 4953c5656bfSArchie Cobbs u_int8_t ok_bits; 4963c5656bfSArchie Cobbs int cmd_index; 4973c5656bfSArchie Cobbs int count; 4983c5656bfSArchie Cobbs int s; 4993c5656bfSArchie Cobbs 5003c5656bfSArchie Cobbs s = splhigh(); 5013c5656bfSArchie Cobbs for (count = 0; count < maxloops; count++) { 5023c5656bfSArchie Cobbs 5033c5656bfSArchie Cobbs /* Get and reset status bits */ 5043c5656bfSArchie Cobbs status = bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA); 5053c5656bfSArchie Cobbs #if ICHSMB_DEBUG 5063c5656bfSArchie Cobbs if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY)) 5073c5656bfSArchie Cobbs || count > 0) { 5083c5656bfSArchie Cobbs DBG("%d stat=0x%02x\n", count, status); 5093c5656bfSArchie Cobbs } 5103c5656bfSArchie Cobbs #endif 5113c5656bfSArchie Cobbs status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY); 5123c5656bfSArchie Cobbs if (status == 0) 5133c5656bfSArchie Cobbs break; 5143c5656bfSArchie Cobbs 5153c5656bfSArchie Cobbs /* Check for unexpected interrupt */ 5163c5656bfSArchie Cobbs ok_bits = ICH_HST_STA_SMBALERT_STS; 5173c5656bfSArchie Cobbs cmd_index = sc->ich_cmd >> 2; 5183c5656bfSArchie Cobbs if (sc->ich_cmd != -1) { 5193c5656bfSArchie Cobbs KASSERT(cmd_index < sizeof(ichsmb_state_irqs), 5203c5656bfSArchie Cobbs ("%s: ich_cmd=%d", device_get_nameunit(dev), 5213c5656bfSArchie Cobbs sc->ich_cmd)); 5223c5656bfSArchie Cobbs ok_bits |= ichsmb_state_irqs[cmd_index]; 5233c5656bfSArchie Cobbs } 5243c5656bfSArchie Cobbs if ((status & ~ok_bits) != 0) { 5253c5656bfSArchie Cobbs log(LOG_ERR, "%s: irq 0x%02x during %d\n", 5263c5656bfSArchie Cobbs device_get_nameunit(dev), status, cmd_index); 5273c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, 5283c5656bfSArchie Cobbs ICH_HST_STA, (status & ~ok_bits)); 5293c5656bfSArchie Cobbs continue; 5303c5656bfSArchie Cobbs } 5313c5656bfSArchie Cobbs 5323c5656bfSArchie Cobbs /* Handle SMBALERT interrupt */ 5333c5656bfSArchie Cobbs if (status & ICH_HST_STA_SMBALERT_STS) { 5343c5656bfSArchie Cobbs static int smbalert_count = 16; 5353c5656bfSArchie Cobbs if (smbalert_count > 0) { 5363c5656bfSArchie Cobbs log(LOG_WARNING, "%s: SMBALERT# rec'd\n", 5373c5656bfSArchie Cobbs device_get_nameunit(dev)); 5383c5656bfSArchie Cobbs if (--smbalert_count == 0) { 5393c5656bfSArchie Cobbs log(LOG_WARNING, 5403c5656bfSArchie Cobbs "%s: not logging anymore\n", 5413c5656bfSArchie Cobbs device_get_nameunit(dev)); 5423c5656bfSArchie Cobbs } 5433c5656bfSArchie Cobbs } 5443c5656bfSArchie Cobbs } 5453c5656bfSArchie Cobbs 5463c5656bfSArchie Cobbs /* Check for bus error */ 5473c5656bfSArchie Cobbs if (status & ICH_HST_STA_BUS_ERR) { 5483c5656bfSArchie Cobbs sc->smb_error = SMB_ECOLLI; /* XXX SMB_EBUSERR? */ 5493c5656bfSArchie Cobbs goto finished; 5503c5656bfSArchie Cobbs } 5513c5656bfSArchie Cobbs 5523c5656bfSArchie Cobbs /* Check for device error */ 5533c5656bfSArchie Cobbs if (status & ICH_HST_STA_DEV_ERR) { 5543c5656bfSArchie Cobbs sc->smb_error = SMB_ENOACK; /* or SMB_ETIMEOUT? */ 5553c5656bfSArchie Cobbs goto finished; 5563c5656bfSArchie Cobbs } 5573c5656bfSArchie Cobbs 5583c5656bfSArchie Cobbs /* Check for byte completion in block transfer */ 5593c5656bfSArchie Cobbs if (status & ICH_HST_STA_BYTE_DONE_STS) { 5603c5656bfSArchie Cobbs if (sc->block_write) { 5613c5656bfSArchie Cobbs if (sc->block_index < sc->block_count) { 5623c5656bfSArchie Cobbs 5633c5656bfSArchie Cobbs /* Write next byte */ 5643c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, 5653c5656bfSArchie Cobbs sc->io_bsh, ICH_BLOCK_DB, 5663c5656bfSArchie Cobbs sc->block_data[sc->block_index++]); 5673c5656bfSArchie Cobbs } 5683c5656bfSArchie Cobbs } else { 5693c5656bfSArchie Cobbs 5703c5656bfSArchie Cobbs /* First interrupt, get the count also */ 5713c5656bfSArchie Cobbs if (sc->block_index == 0) { 5723c5656bfSArchie Cobbs sc->block_count = bus_space_read_1( 5733c5656bfSArchie Cobbs sc->io_bst, sc->io_bsh, ICH_D0); 5743c5656bfSArchie Cobbs } 5753c5656bfSArchie Cobbs 5763c5656bfSArchie Cobbs /* Get next byte, if any */ 5773c5656bfSArchie Cobbs if (sc->block_index < sc->block_count) { 5783c5656bfSArchie Cobbs 5793c5656bfSArchie Cobbs /* Read next byte */ 5803c5656bfSArchie Cobbs sc->block_data[sc->block_index++] = 5813c5656bfSArchie Cobbs bus_space_read_1(sc->io_bst, 5823c5656bfSArchie Cobbs sc->io_bsh, ICH_BLOCK_DB); 5833c5656bfSArchie Cobbs 5843c5656bfSArchie Cobbs /* Set "LAST_BYTE" bit before reading 5853c5656bfSArchie Cobbs the last byte of block data */ 5863c5656bfSArchie Cobbs if (sc->block_index 5873c5656bfSArchie Cobbs >= sc->block_count - 1) { 5883c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, 5893c5656bfSArchie Cobbs sc->io_bsh, ICH_HST_CNT, 5903c5656bfSArchie Cobbs ICH_HST_CNT_LAST_BYTE 5913c5656bfSArchie Cobbs | ICH_HST_CNT_INTREN 5923c5656bfSArchie Cobbs | sc->ich_cmd); 5933c5656bfSArchie Cobbs } 5943c5656bfSArchie Cobbs } 5953c5656bfSArchie Cobbs } 5963c5656bfSArchie Cobbs } 5973c5656bfSArchie Cobbs 5983c5656bfSArchie Cobbs /* Check command completion */ 5993c5656bfSArchie Cobbs if (status & ICH_HST_STA_INTR) { 6003c5656bfSArchie Cobbs sc->smb_error = SMB_ENOERR; 6013c5656bfSArchie Cobbs finished: 6023c5656bfSArchie Cobbs sc->ich_cmd = -1; 6033c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, 6043c5656bfSArchie Cobbs ICH_HST_STA, status); 6053c5656bfSArchie Cobbs wakeup(sc); 6063c5656bfSArchie Cobbs break; 6073c5656bfSArchie Cobbs } 6083c5656bfSArchie Cobbs 6093c5656bfSArchie Cobbs /* Clear status bits and try again */ 6103c5656bfSArchie Cobbs bus_space_write_1(sc->io_bst, sc->io_bsh, ICH_HST_STA, status); 6113c5656bfSArchie Cobbs } 6123c5656bfSArchie Cobbs splx(s); 6133c5656bfSArchie Cobbs 6143c5656bfSArchie Cobbs /* Too many loops? */ 6153c5656bfSArchie Cobbs if (count == maxloops) { 6163c5656bfSArchie Cobbs log(LOG_ERR, "%s: interrupt loop, status=0x%02x\n", 6173c5656bfSArchie Cobbs device_get_nameunit(dev), 6183c5656bfSArchie Cobbs bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA)); 6193c5656bfSArchie Cobbs } 6203c5656bfSArchie Cobbs } 6213c5656bfSArchie Cobbs 6223c5656bfSArchie Cobbs /* 6233c5656bfSArchie Cobbs * Wait for command completion. Assumes splhigh(). 6243c5656bfSArchie Cobbs * Returns an SMB_* error code. 6253c5656bfSArchie Cobbs */ 6263c5656bfSArchie Cobbs static int 6273c5656bfSArchie Cobbs ichsmb_wait(sc_p sc) 6283c5656bfSArchie Cobbs { 6293c5656bfSArchie Cobbs const device_t dev = sc->dev; 6303c5656bfSArchie Cobbs int error, smb_error; 6313c5656bfSArchie Cobbs 6323c5656bfSArchie Cobbs KASSERT(sc->ich_cmd != -1, 6333c5656bfSArchie Cobbs ("%s: ich_cmd=%d\n", __FUNCTION__ , sc->ich_cmd)); 6343c5656bfSArchie Cobbs sleep: 6353c5656bfSArchie Cobbs error = tsleep(sc, PZERO | PCATCH, "ichsmb", hz / 4); 6363c5656bfSArchie Cobbs DBG("tsleep -> %d\n", error); 6373c5656bfSArchie Cobbs switch (error) { 6383c5656bfSArchie Cobbs case ERESTART: 6393c5656bfSArchie Cobbs if (sc->ich_cmd != -1) 6403c5656bfSArchie Cobbs goto sleep; 6413c5656bfSArchie Cobbs /* FALLTHROUGH */ 6423c5656bfSArchie Cobbs case 0: 6433c5656bfSArchie Cobbs smb_error = sc->smb_error; 6443c5656bfSArchie Cobbs break; 6453c5656bfSArchie Cobbs case EWOULDBLOCK: 6463c5656bfSArchie Cobbs log(LOG_ERR, "%s: device timeout, status=0x%02x\n", 6473c5656bfSArchie Cobbs device_get_nameunit(dev), 6483c5656bfSArchie Cobbs bus_space_read_1(sc->io_bst, sc->io_bsh, ICH_HST_STA)); 6493c5656bfSArchie Cobbs sc->ich_cmd = -1; 6503c5656bfSArchie Cobbs smb_error = SMB_ETIMEOUT; 6513c5656bfSArchie Cobbs break; 6523c5656bfSArchie Cobbs default: 6533c5656bfSArchie Cobbs smb_error = SMB_EABORT; 6543c5656bfSArchie Cobbs break; 6553c5656bfSArchie Cobbs } 6563c5656bfSArchie Cobbs return (smb_error); 6573c5656bfSArchie Cobbs } 6583c5656bfSArchie Cobbs 6593c5656bfSArchie Cobbs /* 6603c5656bfSArchie Cobbs * Release resources associated with device. 6613c5656bfSArchie Cobbs */ 6623c5656bfSArchie Cobbs void 6633c5656bfSArchie Cobbs ichsmb_release_resources(sc_p sc) 6643c5656bfSArchie Cobbs { 6653c5656bfSArchie Cobbs const device_t dev = sc->dev; 6663c5656bfSArchie Cobbs 6673c5656bfSArchie Cobbs if (sc->irq_handle != NULL) { 6683c5656bfSArchie Cobbs bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 6693c5656bfSArchie Cobbs sc->irq_handle = NULL; 6703c5656bfSArchie Cobbs } 6713c5656bfSArchie Cobbs if (sc->irq_res != NULL) { 6723c5656bfSArchie Cobbs bus_release_resource(dev, 6733c5656bfSArchie Cobbs SYS_RES_IRQ, sc->irq_rid, sc->irq_res); 6743c5656bfSArchie Cobbs sc->irq_res = NULL; 6753c5656bfSArchie Cobbs } 6763c5656bfSArchie Cobbs if (sc->io_res != NULL) { 6773c5656bfSArchie Cobbs bus_release_resource(dev, 6783c5656bfSArchie Cobbs SYS_RES_IOPORT, sc->io_rid, sc->io_res); 6793c5656bfSArchie Cobbs sc->io_res = NULL; 6803c5656bfSArchie Cobbs } 6813c5656bfSArchie Cobbs } 6823c5656bfSArchie Cobbs 683