1098ca2bdSWarner Losh /*- 23c5656bfSArchie Cobbs * ichsmb.c 33c5656bfSArchie Cobbs * 4aad970f1SDavid E. O'Brien * Author: Archie Cobbs <archie@freebsd.org> 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 38aad970f1SDavid E. O'Brien #include <sys/cdefs.h> 39aad970f1SDavid E. O'Brien __FBSDID("$FreeBSD$"); 40aad970f1SDavid E. O'Brien 413c5656bfSArchie Cobbs /* 423c5656bfSArchie Cobbs * Support for the SMBus controller logical device which is part of the 433c5656bfSArchie Cobbs * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips. 443a50ed55SArchie Cobbs * 453a50ed55SArchie Cobbs * This driver assumes that the generic SMBus code will ensure that 463a50ed55SArchie Cobbs * at most one process at a time calls into the SMBus methods below. 473c5656bfSArchie Cobbs */ 483c5656bfSArchie Cobbs 493c5656bfSArchie Cobbs #include <sys/param.h> 503c5656bfSArchie Cobbs #include <sys/systm.h> 513c5656bfSArchie Cobbs #include <sys/kernel.h> 523c5656bfSArchie Cobbs #include <sys/errno.h> 53f34fa851SJohn Baldwin #include <sys/lock.h> 547048a99cSJohn Baldwin #include <sys/module.h> 553a50ed55SArchie Cobbs #include <sys/mutex.h> 563c5656bfSArchie Cobbs #include <sys/syslog.h> 573c5656bfSArchie Cobbs #include <sys/bus.h> 583c5656bfSArchie Cobbs 593c5656bfSArchie Cobbs #include <machine/bus.h> 603c5656bfSArchie Cobbs #include <sys/rman.h> 613c5656bfSArchie Cobbs #include <machine/resource.h> 623c5656bfSArchie Cobbs 633c5656bfSArchie Cobbs #include <dev/smbus/smbconf.h> 643c5656bfSArchie Cobbs 653c5656bfSArchie Cobbs #include <dev/ichsmb/ichsmb_var.h> 663c5656bfSArchie Cobbs #include <dev/ichsmb/ichsmb_reg.h> 673c5656bfSArchie Cobbs 683c5656bfSArchie Cobbs /* 693c5656bfSArchie Cobbs * Enable debugging by defining ICHSMB_DEBUG to a non-zero value. 703c5656bfSArchie Cobbs */ 713c5656bfSArchie Cobbs #define ICHSMB_DEBUG 0 72*87445068SJohn Baldwin #if ICHSMB_DEBUG != 0 733c5656bfSArchie Cobbs #define DBG(fmt, args...) \ 7485064e68SJohn Baldwin do { printf("%s: " fmt, __func__ , ## args); } while (0) 753c5656bfSArchie Cobbs #else 763c5656bfSArchie Cobbs #define DBG(fmt, args...) do { } while (0) 773c5656bfSArchie Cobbs #endif 783c5656bfSArchie Cobbs 793c5656bfSArchie Cobbs /* 803c5656bfSArchie Cobbs * Our child device driver name 813c5656bfSArchie Cobbs */ 823c5656bfSArchie Cobbs #define DRIVER_SMBUS "smbus" 833c5656bfSArchie Cobbs 843c5656bfSArchie Cobbs /* 853c5656bfSArchie Cobbs * Internal functions 863c5656bfSArchie Cobbs */ 873c5656bfSArchie Cobbs static int ichsmb_wait(sc_p sc); 883c5656bfSArchie Cobbs 893c5656bfSArchie Cobbs /******************************************************************** 903c5656bfSArchie Cobbs BUS-INDEPENDENT BUS METHODS 913c5656bfSArchie Cobbs ********************************************************************/ 923c5656bfSArchie Cobbs 933c5656bfSArchie Cobbs /* 943c5656bfSArchie Cobbs * Handle probe-time duties that are independent of the bus 953c5656bfSArchie Cobbs * our device lives on. 963c5656bfSArchie Cobbs */ 973c5656bfSArchie Cobbs int 983c5656bfSArchie Cobbs ichsmb_probe(device_t dev) 993c5656bfSArchie Cobbs { 100b77e575eSWarner Losh return (BUS_PROBE_DEFAULT); 1013c5656bfSArchie Cobbs } 1023c5656bfSArchie Cobbs 1033c5656bfSArchie Cobbs /* 1043c5656bfSArchie Cobbs * Handle attach-time duties that are independent of the bus 1053c5656bfSArchie Cobbs * our device lives on. 1063c5656bfSArchie Cobbs */ 1073c5656bfSArchie Cobbs int 1083c5656bfSArchie Cobbs ichsmb_attach(device_t dev) 1093c5656bfSArchie Cobbs { 1103c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 1113c5656bfSArchie Cobbs int error; 1122e6e32daSTakanori Watanabe 11385064e68SJohn Baldwin /* Create mutex */ 11485064e68SJohn Baldwin mtx_init(&sc->mutex, device_get_nameunit(dev), "ichsmb", MTX_DEF); 11585064e68SJohn Baldwin 1162e6e32daSTakanori Watanabe /* Add child: an instance of the "smbus" device */ 117fa6e2680SBrian Somers if ((sc->smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) { 11885064e68SJohn Baldwin device_printf(dev, "no \"%s\" child found\n", DRIVER_SMBUS); 11985064e68SJohn Baldwin error = ENXIO; 12085064e68SJohn Baldwin goto fail; 1212e6e32daSTakanori Watanabe } 1223c5656bfSArchie Cobbs 1233c5656bfSArchie Cobbs /* Clear interrupt conditions */ 12432d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_STA, 0xff); 1253c5656bfSArchie Cobbs 12685064e68SJohn Baldwin /* Set up interrupt handler */ 12732d8ea84SJohn Baldwin error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE, 128ef544f63SPaolo Pisati NULL, ichsmb_device_intr, sc, &sc->irq_handle); 12985064e68SJohn Baldwin if (error != 0) { 13085064e68SJohn Baldwin device_printf(dev, "can't setup irq\n"); 13185064e68SJohn Baldwin goto fail; 1323c5656bfSArchie Cobbs } 1333c5656bfSArchie Cobbs 134b832a7e5SWarner Losh /* Attach children when interrupts are available */ 135b832a7e5SWarner Losh return (bus_delayed_attach_children(dev)); 13685064e68SJohn Baldwin fail: 13785064e68SJohn Baldwin mtx_destroy(&sc->mutex); 13885064e68SJohn Baldwin return (error); 1393c5656bfSArchie Cobbs } 1403c5656bfSArchie Cobbs 1413c5656bfSArchie Cobbs /******************************************************************** 1423c5656bfSArchie Cobbs SMBUS METHODS 1433c5656bfSArchie Cobbs ********************************************************************/ 1443c5656bfSArchie Cobbs 1453c5656bfSArchie Cobbs int 1467048a99cSJohn Baldwin ichsmb_callback(device_t dev, int index, void *data) 1473c5656bfSArchie Cobbs { 1483c5656bfSArchie Cobbs int smb_error = 0; 1493c5656bfSArchie Cobbs 1503c5656bfSArchie Cobbs DBG("index=%d how=%d\n", index, data ? *(int *)data : -1); 1513c5656bfSArchie Cobbs switch (index) { 1523c5656bfSArchie Cobbs case SMB_REQUEST_BUS: 1533c5656bfSArchie Cobbs break; 1543c5656bfSArchie Cobbs case SMB_RELEASE_BUS: 1553c5656bfSArchie Cobbs break; 1563c5656bfSArchie Cobbs default: 1573c5656bfSArchie Cobbs smb_error = SMB_EABORT; /* XXX */ 1583c5656bfSArchie Cobbs break; 1593c5656bfSArchie Cobbs } 1603c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 1613c5656bfSArchie Cobbs return (smb_error); 1623c5656bfSArchie Cobbs } 1633c5656bfSArchie Cobbs 1643c5656bfSArchie Cobbs int 1653c5656bfSArchie Cobbs ichsmb_quick(device_t dev, u_char slave, int how) 1663c5656bfSArchie Cobbs { 1673c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 1683c5656bfSArchie Cobbs int smb_error; 1693c5656bfSArchie Cobbs 1703c5656bfSArchie Cobbs DBG("slave=0x%02x how=%d\n", slave, how); 1713c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 1726e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 1733c5656bfSArchie Cobbs switch (how) { 1743c5656bfSArchie Cobbs case SMB_QREAD: 1753c5656bfSArchie Cobbs case SMB_QWRITE: 1769ed346baSBosko Milekic mtx_lock(&sc->mutex); 1773c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK; 17832d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_XMIT_SLVA, 179bb6bb7feSJohn Baldwin slave | (how == SMB_QREAD ? 1803c5656bfSArchie Cobbs ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE)); 18132d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CNT, 1823c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 1833c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 1849ed346baSBosko Milekic mtx_unlock(&sc->mutex); 1853c5656bfSArchie Cobbs break; 1863c5656bfSArchie Cobbs default: 1873c5656bfSArchie Cobbs smb_error = SMB_ENOTSUPP; 1883c5656bfSArchie Cobbs } 1893c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 1903c5656bfSArchie Cobbs return (smb_error); 1913c5656bfSArchie Cobbs } 1923c5656bfSArchie Cobbs 1933c5656bfSArchie Cobbs int 1943c5656bfSArchie Cobbs ichsmb_sendb(device_t dev, u_char slave, char byte) 1953c5656bfSArchie Cobbs { 1963c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 1973c5656bfSArchie Cobbs int smb_error; 1983c5656bfSArchie Cobbs 1993c5656bfSArchie Cobbs DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte); 2003c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2016e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2029ed346baSBosko Milekic mtx_lock(&sc->mutex); 2033c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 20432d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_XMIT_SLVA, 205bb6bb7feSJohn Baldwin slave | ICH_XMIT_SLVA_WRITE); 20632d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CMD, byte); 20732d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CNT, 2083c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2093c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2109ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2113c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2123c5656bfSArchie Cobbs return (smb_error); 2133c5656bfSArchie Cobbs } 2143c5656bfSArchie Cobbs 2153c5656bfSArchie Cobbs int 2163c5656bfSArchie Cobbs ichsmb_recvb(device_t dev, u_char slave, char *byte) 2173c5656bfSArchie Cobbs { 2183c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2193c5656bfSArchie Cobbs int smb_error; 2203c5656bfSArchie Cobbs 2213c5656bfSArchie Cobbs DBG("slave=0x%02x\n", slave); 2223c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2236e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2249ed346baSBosko Milekic mtx_lock(&sc->mutex); 2253c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE; 22632d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_XMIT_SLVA, 227bb6bb7feSJohn Baldwin slave | ICH_XMIT_SLVA_READ); 22832d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CNT, 2293c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2303c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 23132d8ea84SJohn Baldwin *byte = bus_read_1(sc->io_res, ICH_D0); 2329ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2333c5656bfSArchie Cobbs DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 2343c5656bfSArchie Cobbs return (smb_error); 2353c5656bfSArchie Cobbs } 2363c5656bfSArchie Cobbs 2373c5656bfSArchie Cobbs int 2383c5656bfSArchie Cobbs ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte) 2393c5656bfSArchie Cobbs { 2403c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2413c5656bfSArchie Cobbs int smb_error; 2423c5656bfSArchie Cobbs 2433c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n", 2443c5656bfSArchie Cobbs slave, (u_char)cmd, (u_char)byte); 2453c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2466e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2479ed346baSBosko Milekic mtx_lock(&sc->mutex); 2483c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 24932d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_XMIT_SLVA, 250bb6bb7feSJohn Baldwin slave | ICH_XMIT_SLVA_WRITE); 25132d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 25232d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_D0, byte); 25332d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CNT, 2543c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2553c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2569ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2573c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2583c5656bfSArchie Cobbs return (smb_error); 2593c5656bfSArchie Cobbs } 2603c5656bfSArchie Cobbs 2613c5656bfSArchie Cobbs int 2623c5656bfSArchie Cobbs ichsmb_writew(device_t dev, u_char slave, char cmd, short word) 2633c5656bfSArchie Cobbs { 2643c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2653c5656bfSArchie Cobbs int smb_error; 2663c5656bfSArchie Cobbs 2673c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n", 2683c5656bfSArchie Cobbs slave, (u_char)cmd, (u_int16_t)word); 2693c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2706e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2719ed346baSBosko Milekic mtx_lock(&sc->mutex); 2723c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 27332d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_XMIT_SLVA, 274bb6bb7feSJohn Baldwin slave | ICH_XMIT_SLVA_WRITE); 27532d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 27632d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_D0, word & 0xff); 27732d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_D1, word >> 8); 27832d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CNT, 2793c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 2803c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 2819ed346baSBosko Milekic mtx_unlock(&sc->mutex); 2823c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 2833c5656bfSArchie Cobbs return (smb_error); 2843c5656bfSArchie Cobbs } 2853c5656bfSArchie Cobbs 2863c5656bfSArchie Cobbs int 2873c5656bfSArchie Cobbs ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte) 2883c5656bfSArchie Cobbs { 2893c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 2903c5656bfSArchie Cobbs int smb_error; 2913c5656bfSArchie Cobbs 2923c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 2933c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 2946e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 2959ed346baSBosko Milekic mtx_lock(&sc->mutex); 2963c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA; 29732d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_XMIT_SLVA, 298bb6bb7feSJohn Baldwin slave | ICH_XMIT_SLVA_READ); 29932d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 30032d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CNT, 3013c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 3023c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) 30332d8ea84SJohn Baldwin *byte = bus_read_1(sc->io_res, ICH_D0); 3049ed346baSBosko Milekic mtx_unlock(&sc->mutex); 3053c5656bfSArchie Cobbs DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte); 3063c5656bfSArchie Cobbs return (smb_error); 3073c5656bfSArchie Cobbs } 3083c5656bfSArchie Cobbs 3093c5656bfSArchie Cobbs int 3103c5656bfSArchie Cobbs ichsmb_readw(device_t dev, u_char slave, char cmd, short *word) 3113c5656bfSArchie Cobbs { 3123c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3133c5656bfSArchie Cobbs int smb_error; 3143c5656bfSArchie Cobbs 3153c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd); 3163c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3176e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 3189ed346baSBosko Milekic mtx_lock(&sc->mutex); 3193c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA; 32032d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_XMIT_SLVA, 321bb6bb7feSJohn Baldwin slave | ICH_XMIT_SLVA_READ); 32232d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 32332d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CNT, 3243c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 3253c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 32632d8ea84SJohn Baldwin *word = (bus_read_1(sc->io_res, 32732d8ea84SJohn Baldwin ICH_D0) & 0xff) 32832d8ea84SJohn Baldwin | (bus_read_1(sc->io_res, 32932d8ea84SJohn Baldwin ICH_D1) << 8); 3303c5656bfSArchie Cobbs } 3319ed346baSBosko Milekic mtx_unlock(&sc->mutex); 3323c5656bfSArchie Cobbs DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word); 3333c5656bfSArchie Cobbs return (smb_error); 3343c5656bfSArchie Cobbs } 3353c5656bfSArchie Cobbs 3363c5656bfSArchie Cobbs int 3373c5656bfSArchie Cobbs ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) 3383c5656bfSArchie Cobbs { 3393c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3403c5656bfSArchie Cobbs int smb_error; 3413c5656bfSArchie Cobbs 3423c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n", 3433c5656bfSArchie Cobbs slave, (u_char)cmd, (u_int16_t)sdata); 3443c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3456e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 3469ed346baSBosko Milekic mtx_lock(&sc->mutex); 3473c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL; 34832d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_XMIT_SLVA, 349bb6bb7feSJohn Baldwin slave | ICH_XMIT_SLVA_WRITE); 35032d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 35132d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_D0, sdata & 0xff); 35232d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_D1, sdata >> 8); 35332d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CNT, 3543c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 3553c5656bfSArchie Cobbs if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 35632d8ea84SJohn Baldwin *rdata = (bus_read_1(sc->io_res, 35732d8ea84SJohn Baldwin ICH_D0) & 0xff) 35832d8ea84SJohn Baldwin | (bus_read_1(sc->io_res, 35932d8ea84SJohn Baldwin ICH_D1) << 8); 3603c5656bfSArchie Cobbs } 3619ed346baSBosko Milekic mtx_unlock(&sc->mutex); 3623c5656bfSArchie Cobbs DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata); 3633c5656bfSArchie Cobbs return (smb_error); 3643c5656bfSArchie Cobbs } 3653c5656bfSArchie Cobbs 3663c5656bfSArchie Cobbs int 3673c5656bfSArchie Cobbs ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) 3683c5656bfSArchie Cobbs { 3693c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 3703c5656bfSArchie Cobbs int smb_error; 3713c5656bfSArchie Cobbs 3723c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 3733c5656bfSArchie Cobbs #if ICHSMB_DEBUG 3743c5656bfSArchie Cobbs #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 3753c5656bfSArchie Cobbs { 3763c5656bfSArchie Cobbs u_char *p; 3773c5656bfSArchie Cobbs 3783c5656bfSArchie Cobbs for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 3793c5656bfSArchie Cobbs DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 3803c5656bfSArchie Cobbs " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 3813c5656bfSArchie Cobbs p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 3823c5656bfSArchie Cobbs DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 3833c5656bfSArchie Cobbs DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 3843c5656bfSArchie Cobbs } 3853c5656bfSArchie Cobbs } 3863c5656bfSArchie Cobbs #undef DISP 3873c5656bfSArchie Cobbs #endif 3883c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 3896e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 3903c5656bfSArchie Cobbs if (count < 1 || count > 32) 3917048a99cSJohn Baldwin return (SMB_EINVAL); 3923c5656bfSArchie Cobbs bcopy(buf, sc->block_data, count); 3933c5656bfSArchie Cobbs sc->block_count = count; 3943c5656bfSArchie Cobbs sc->block_index = 1; 3953c5656bfSArchie Cobbs sc->block_write = 1; 3963c5656bfSArchie Cobbs 3979ed346baSBosko Milekic mtx_lock(&sc->mutex); 3983c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 39932d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_XMIT_SLVA, 400bb6bb7feSJohn Baldwin slave | ICH_XMIT_SLVA_WRITE); 40132d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 40232d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_D0, count); 40332d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_BLOCK_DB, buf[0]); 40432d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CNT, 4053c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 4063c5656bfSArchie Cobbs smb_error = ichsmb_wait(sc); 4079ed346baSBosko Milekic mtx_unlock(&sc->mutex); 4083c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 4093c5656bfSArchie Cobbs return (smb_error); 4103c5656bfSArchie Cobbs } 4113c5656bfSArchie Cobbs 4123c5656bfSArchie Cobbs int 4137048a99cSJohn Baldwin ichsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 4143c5656bfSArchie Cobbs { 4153c5656bfSArchie Cobbs const sc_p sc = device_get_softc(dev); 4163c5656bfSArchie Cobbs int smb_error; 4173c5656bfSArchie Cobbs 4183c5656bfSArchie Cobbs DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count); 4193c5656bfSArchie Cobbs KASSERT(sc->ich_cmd == -1, 4206e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 4217048a99cSJohn Baldwin if (*count < 1 || *count > 32) 4227048a99cSJohn Baldwin return (SMB_EINVAL); 4233c5656bfSArchie Cobbs bzero(sc->block_data, sizeof(sc->block_data)); 4247048a99cSJohn Baldwin sc->block_count = 0; 4253c5656bfSArchie Cobbs sc->block_index = 0; 4263c5656bfSArchie Cobbs sc->block_write = 0; 4273c5656bfSArchie Cobbs 4289ed346baSBosko Milekic mtx_lock(&sc->mutex); 4293c5656bfSArchie Cobbs sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK; 43032d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_XMIT_SLVA, 431bb6bb7feSJohn Baldwin slave | ICH_XMIT_SLVA_READ); 43232d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CMD, cmd); 43332d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_D0, *count); /* XXX? */ 43432d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_CNT, 4353c5656bfSArchie Cobbs ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd); 4367048a99cSJohn Baldwin if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) { 4377048a99cSJohn Baldwin bcopy(sc->block_data, buf, min(sc->block_count, *count)); 4387048a99cSJohn Baldwin *count = sc->block_count; 4397048a99cSJohn Baldwin } 4409ed346baSBosko Milekic mtx_unlock(&sc->mutex); 4413c5656bfSArchie Cobbs DBG("smb_error=%d\n", smb_error); 4423c5656bfSArchie Cobbs #if ICHSMB_DEBUG 4433c5656bfSArchie Cobbs #define DISP(ch) (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch)) 4443c5656bfSArchie Cobbs { 4453c5656bfSArchie Cobbs u_char *p; 4463c5656bfSArchie Cobbs 4473c5656bfSArchie Cobbs for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) { 4483c5656bfSArchie Cobbs DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x" 4493c5656bfSArchie Cobbs " %c%c%c%c%c%c%c%c", (p - (u_char *)buf), 4503c5656bfSArchie Cobbs p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], 4513c5656bfSArchie Cobbs DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 4523c5656bfSArchie Cobbs DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7])); 4533c5656bfSArchie Cobbs } 4543c5656bfSArchie Cobbs } 4553c5656bfSArchie Cobbs #undef DISP 4563c5656bfSArchie Cobbs #endif 4573c5656bfSArchie Cobbs return (smb_error); 4583c5656bfSArchie Cobbs } 4593c5656bfSArchie Cobbs 4603c5656bfSArchie Cobbs /******************************************************************** 4613c5656bfSArchie Cobbs OTHER FUNCTIONS 4623c5656bfSArchie Cobbs ********************************************************************/ 4633c5656bfSArchie Cobbs 4643c5656bfSArchie Cobbs /* 4653c5656bfSArchie Cobbs * This table describes what interrupts we should ever expect to 4663c5656bfSArchie Cobbs * see after each ICH command, not including the SMBALERT interrupt. 4673c5656bfSArchie Cobbs */ 4683c5656bfSArchie Cobbs static const u_int8_t ichsmb_state_irqs[] = { 4693c5656bfSArchie Cobbs /* quick */ 4703c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4713c5656bfSArchie Cobbs /* byte */ 4723c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4733c5656bfSArchie Cobbs /* byte data */ 4743c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4753c5656bfSArchie Cobbs /* word data */ 4763c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4773c5656bfSArchie Cobbs /* process call */ 4783c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR), 4793c5656bfSArchie Cobbs /* block */ 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 /* i2c read (not used) */ 4833c5656bfSArchie Cobbs (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR 4843c5656bfSArchie Cobbs | ICH_HST_STA_BYTE_DONE_STS) 4853c5656bfSArchie Cobbs }; 4863c5656bfSArchie Cobbs 4873c5656bfSArchie Cobbs /* 4883c5656bfSArchie Cobbs * Interrupt handler. This handler is bus-independent. Note that our 4893c5656bfSArchie Cobbs * interrupt may be shared, so we must handle "false" interrupts. 4903c5656bfSArchie Cobbs */ 4913c5656bfSArchie Cobbs void 4923c5656bfSArchie Cobbs ichsmb_device_intr(void *cookie) 4933c5656bfSArchie Cobbs { 4943c5656bfSArchie Cobbs const sc_p sc = cookie; 4953c5656bfSArchie Cobbs const device_t dev = sc->dev; 4963c5656bfSArchie Cobbs const int maxloops = 16; 4973c5656bfSArchie Cobbs u_int8_t status; 4983c5656bfSArchie Cobbs u_int8_t ok_bits; 4993c5656bfSArchie Cobbs int cmd_index; 5003c5656bfSArchie Cobbs int count; 5013c5656bfSArchie Cobbs 5029ed346baSBosko Milekic mtx_lock(&sc->mutex); 5033c5656bfSArchie Cobbs for (count = 0; count < maxloops; count++) { 5043c5656bfSArchie Cobbs 5053c5656bfSArchie Cobbs /* Get and reset status bits */ 50632d8ea84SJohn Baldwin status = bus_read_1(sc->io_res, ICH_HST_STA); 5073c5656bfSArchie Cobbs #if ICHSMB_DEBUG 5083c5656bfSArchie Cobbs if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY)) 5093c5656bfSArchie Cobbs || count > 0) { 5103c5656bfSArchie Cobbs DBG("%d stat=0x%02x\n", count, status); 5113c5656bfSArchie Cobbs } 5123c5656bfSArchie Cobbs #endif 5133c5656bfSArchie Cobbs status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY); 5143c5656bfSArchie Cobbs if (status == 0) 5153c5656bfSArchie Cobbs break; 5163c5656bfSArchie Cobbs 5173c5656bfSArchie Cobbs /* Check for unexpected interrupt */ 5183c5656bfSArchie Cobbs ok_bits = ICH_HST_STA_SMBALERT_STS; 5193c5656bfSArchie Cobbs cmd_index = sc->ich_cmd >> 2; 5203c5656bfSArchie Cobbs if (sc->ich_cmd != -1) { 5213c5656bfSArchie Cobbs KASSERT(cmd_index < sizeof(ichsmb_state_irqs), 5223c5656bfSArchie Cobbs ("%s: ich_cmd=%d", device_get_nameunit(dev), 5233c5656bfSArchie Cobbs sc->ich_cmd)); 5243c5656bfSArchie Cobbs ok_bits |= ichsmb_state_irqs[cmd_index]; 5253c5656bfSArchie Cobbs } 5263c5656bfSArchie Cobbs if ((status & ~ok_bits) != 0) { 52785064e68SJohn Baldwin device_printf(dev, "irq 0x%02x during %d\n", status, 52885064e68SJohn Baldwin cmd_index); 52932d8ea84SJohn Baldwin bus_write_1(sc->io_res, 5303c5656bfSArchie Cobbs ICH_HST_STA, (status & ~ok_bits)); 5313c5656bfSArchie Cobbs continue; 5323c5656bfSArchie Cobbs } 5333c5656bfSArchie Cobbs 5343c5656bfSArchie Cobbs /* Handle SMBALERT interrupt */ 5353c5656bfSArchie Cobbs if (status & ICH_HST_STA_SMBALERT_STS) { 5363c5656bfSArchie Cobbs static int smbalert_count = 16; 5373c5656bfSArchie Cobbs if (smbalert_count > 0) { 53885064e68SJohn Baldwin device_printf(dev, "SMBALERT# rec'd\n"); 5393c5656bfSArchie Cobbs if (--smbalert_count == 0) { 54085064e68SJohn Baldwin device_printf(dev, 54185064e68SJohn Baldwin "not logging anymore\n"); 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 */ 56432d8ea84SJohn Baldwin bus_write_1(sc->io_res, 56532d8ea84SJohn Baldwin 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) { 57232d8ea84SJohn Baldwin sc->block_count = bus_read_1( 57332d8ea84SJohn Baldwin sc->io_res, 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++] = 58132d8ea84SJohn Baldwin bus_read_1(sc->io_res, 58232d8ea84SJohn Baldwin 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) { 58832d8ea84SJohn Baldwin bus_write_1(sc->io_res, 58932d8ea84SJohn Baldwin 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; 60332d8ea84SJohn Baldwin bus_write_1(sc->io_res, 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 */ 61032d8ea84SJohn Baldwin bus_write_1(sc->io_res, ICH_HST_STA, status); 6113c5656bfSArchie Cobbs } 6129ed346baSBosko Milekic mtx_unlock(&sc->mutex); 6133c5656bfSArchie Cobbs 6143c5656bfSArchie Cobbs /* Too many loops? */ 6153c5656bfSArchie Cobbs if (count == maxloops) { 61685064e68SJohn Baldwin device_printf(dev, "interrupt loop, status=0x%02x\n", 61732d8ea84SJohn Baldwin bus_read_1(sc->io_res, ICH_HST_STA)); 6183c5656bfSArchie Cobbs } 6193c5656bfSArchie Cobbs } 6203c5656bfSArchie Cobbs 6213c5656bfSArchie Cobbs /* 6223a50ed55SArchie Cobbs * Wait for command completion. Assumes mutex is held. 6233c5656bfSArchie Cobbs * Returns an SMB_* error code. 6243c5656bfSArchie Cobbs */ 6253c5656bfSArchie Cobbs static int 6263c5656bfSArchie Cobbs ichsmb_wait(sc_p sc) 6273c5656bfSArchie Cobbs { 6283c5656bfSArchie Cobbs const device_t dev = sc->dev; 6293c5656bfSArchie Cobbs int error, smb_error; 6303c5656bfSArchie Cobbs 6313c5656bfSArchie Cobbs KASSERT(sc->ich_cmd != -1, 6326e551fb6SDavid E. O'Brien ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd)); 6333a50ed55SArchie Cobbs mtx_assert(&sc->mutex, MA_OWNED); 6340d107412SBrian Somers error = msleep(sc, &sc->mutex, PZERO, "ichsmb", hz / 4); 6353a50ed55SArchie Cobbs DBG("msleep -> %d\n", error); 6363c5656bfSArchie Cobbs switch (error) { 6373c5656bfSArchie Cobbs case 0: 6383c5656bfSArchie Cobbs smb_error = sc->smb_error; 6393c5656bfSArchie Cobbs break; 6403c5656bfSArchie Cobbs case EWOULDBLOCK: 64185064e68SJohn Baldwin device_printf(dev, "device timeout, status=0x%02x\n", 64232d8ea84SJohn Baldwin bus_read_1(sc->io_res, ICH_HST_STA)); 6433c5656bfSArchie Cobbs sc->ich_cmd = -1; 6443c5656bfSArchie Cobbs smb_error = SMB_ETIMEOUT; 6453c5656bfSArchie Cobbs break; 6463c5656bfSArchie Cobbs default: 6473c5656bfSArchie Cobbs smb_error = SMB_EABORT; 6483c5656bfSArchie Cobbs break; 6493c5656bfSArchie Cobbs } 6503c5656bfSArchie Cobbs return (smb_error); 6513c5656bfSArchie Cobbs } 6523c5656bfSArchie Cobbs 6533c5656bfSArchie Cobbs /* 6543c5656bfSArchie Cobbs * Release resources associated with device. 6553c5656bfSArchie Cobbs */ 6563c5656bfSArchie Cobbs void 6573c5656bfSArchie Cobbs ichsmb_release_resources(sc_p sc) 6583c5656bfSArchie Cobbs { 6593c5656bfSArchie Cobbs const device_t dev = sc->dev; 6603c5656bfSArchie Cobbs 6613c5656bfSArchie Cobbs if (sc->irq_handle != NULL) { 6623c5656bfSArchie Cobbs bus_teardown_intr(dev, sc->irq_res, sc->irq_handle); 6633c5656bfSArchie Cobbs sc->irq_handle = NULL; 6643c5656bfSArchie Cobbs } 6653c5656bfSArchie Cobbs if (sc->irq_res != NULL) { 6663c5656bfSArchie Cobbs bus_release_resource(dev, 6673c5656bfSArchie Cobbs SYS_RES_IRQ, sc->irq_rid, sc->irq_res); 6683c5656bfSArchie Cobbs sc->irq_res = NULL; 6693c5656bfSArchie Cobbs } 6703c5656bfSArchie Cobbs if (sc->io_res != NULL) { 6713c5656bfSArchie Cobbs bus_release_resource(dev, 6723c5656bfSArchie Cobbs SYS_RES_IOPORT, sc->io_rid, sc->io_res); 6733c5656bfSArchie Cobbs sc->io_res = NULL; 6743c5656bfSArchie Cobbs } 6753c5656bfSArchie Cobbs } 6763c5656bfSArchie Cobbs 6777048a99cSJohn Baldwin int 6787048a99cSJohn Baldwin ichsmb_detach(device_t dev) 6792e6e32daSTakanori Watanabe { 6802e6e32daSTakanori Watanabe const sc_p sc = device_get_softc(dev); 6817048a99cSJohn Baldwin int error; 682fa6e2680SBrian Somers 6837048a99cSJohn Baldwin error = bus_generic_detach(dev); 6847048a99cSJohn Baldwin if (error) 6857048a99cSJohn Baldwin return (error); 6862e6e32daSTakanori Watanabe device_delete_child(dev, sc->smb); 6872e6e32daSTakanori Watanabe ichsmb_release_resources(sc); 6887048a99cSJohn Baldwin mtx_destroy(&sc->mutex); 6892e6e32daSTakanori Watanabe 6902e6e32daSTakanori Watanabe return 0; 6912e6e32daSTakanori Watanabe } 6927048a99cSJohn Baldwin 6937048a99cSJohn Baldwin DRIVER_MODULE(smbus, ichsmb, smbus_driver, smbus_devclass, 0, 0); 694