The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ichsmb/ichsmb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * ichsmb.c
    3  *
    4  * Author: Archie Cobbs <archie@freebsd.org>
    5  * Copyright (c) 2000 Whistle Communications, Inc.
    6  * All rights reserved.
    7  * 
    8  * Subject to the following obligations and disclaimer of warranty, use and
    9  * redistribution of this software, in source or object code forms, with or
   10  * without modifications are expressly permitted by Whistle Communications;
   11  * provided, however, that:
   12  * 1. Any and all reproductions of the source or object code must include the
   13  *    copyright notice above and the following disclaimer of warranties; and
   14  * 2. No rights are granted, in any manner or form, to use Whistle
   15  *    Communications, Inc. trademarks, including the mark "WHISTLE
   16  *    COMMUNICATIONS" on advertising, endorsements, or otherwise except as
   17  *    such appears in the above copyright notice or in the software.
   18  * 
   19  * THIS SOFTWARE IS BEING PROVIDED BY WHISTLE COMMUNICATIONS "AS IS", AND
   20  * TO THE MAXIMUM EXTENT PERMITTED BY LAW, WHISTLE COMMUNICATIONS MAKES NO
   21  * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING THIS SOFTWARE,
   22  * INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED WARRANTIES OF
   23  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR NON-INFRINGEMENT.
   24  * WHISTLE COMMUNICATIONS DOES NOT WARRANT, GUARANTEE, OR MAKE ANY
   25  * REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS OF THE USE OF THIS
   26  * SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY, RELIABILITY OR OTHERWISE.
   27  * IN NO EVENT SHALL WHISTLE COMMUNICATIONS BE LIABLE FOR ANY DAMAGES
   28  * RESULTING FROM OR ARISING OUT OF ANY USE OF THIS SOFTWARE, INCLUDING
   29  * WITHOUT LIMITATION, ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
   30  * PUNITIVE, OR CONSEQUENTIAL DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR
   31  * SERVICES, LOSS OF USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY
   32  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   33  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   34  * THIS SOFTWARE, EVEN IF WHISTLE COMMUNICATIONS IS ADVISED OF THE POSSIBILITY
   35  * OF SUCH DAMAGE.
   36  */
   37 
   38 #include <sys/cdefs.h>
   39 __FBSDID("$FreeBSD$");
   40 
   41 /*
   42  * Support for the SMBus controller logical device which is part of the
   43  * Intel 81801AA (ICH) and 81801AB (ICH0) I/O controller hub chips.
   44  *
   45  * This driver assumes that the generic SMBus code will ensure that
   46  * at most one process at a time calls into the SMBus methods below.
   47  */
   48 
   49 #include <sys/param.h>
   50 #include <sys/systm.h>
   51 #include <sys/kernel.h>
   52 #include <sys/errno.h>
   53 #include <sys/lock.h>
   54 #include <sys/module.h>
   55 #include <sys/mutex.h>
   56 #include <sys/syslog.h>
   57 #include <sys/bus.h>
   58 
   59 #include <machine/bus.h>
   60 #include <sys/rman.h>
   61 #include <machine/resource.h>
   62 
   63 #include <dev/smbus/smbconf.h>
   64 
   65 #include <dev/ichsmb/ichsmb_var.h>
   66 #include <dev/ichsmb/ichsmb_reg.h>
   67 
   68 /*
   69  * Enable debugging by defining ICHSMB_DEBUG to a non-zero value.
   70  */
   71 #define ICHSMB_DEBUG    0
   72 #if ICHSMB_DEBUG != 0
   73 #define DBG(fmt, args...)       \
   74         do { printf("%s: " fmt, __func__ , ## args); } while (0)
   75 #else
   76 #define DBG(fmt, args...)       do { } while (0)
   77 #endif
   78 
   79 /*
   80  * Our child device driver name
   81  */
   82 #define DRIVER_SMBUS    "smbus"
   83 
   84 /*
   85  * Internal functions
   86  */
   87 static int ichsmb_wait(sc_p sc);
   88 
   89 /********************************************************************
   90                 BUS-INDEPENDENT BUS METHODS
   91 ********************************************************************/
   92 
   93 /*
   94  * Handle probe-time duties that are independent of the bus
   95  * our device lives on.
   96  */
   97 int
   98 ichsmb_probe(device_t dev)
   99 {
  100         return (BUS_PROBE_DEFAULT);
  101 }
  102 
  103 /*
  104  * Handle attach-time duties that are independent of the bus
  105  * our device lives on.
  106  */
  107 int
  108 ichsmb_attach(device_t dev)
  109 {
  110         const sc_p sc = device_get_softc(dev);
  111         int error;
  112 
  113         /* Create mutex */
  114         mtx_init(&sc->mutex, device_get_nameunit(dev), "ichsmb", MTX_DEF);
  115 
  116         /* Add child: an instance of the "smbus" device */
  117         if ((sc->smb = device_add_child(dev, DRIVER_SMBUS, -1)) == NULL) {
  118                 device_printf(dev, "no \"%s\" child found\n", DRIVER_SMBUS);
  119                 error = ENXIO;
  120                 goto fail;
  121         }
  122 
  123         /* Clear interrupt conditions */
  124         bus_write_1(sc->io_res, ICH_HST_STA, 0xff);
  125 
  126         /* Set up interrupt handler */
  127         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC | INTR_MPSAFE,
  128             NULL, ichsmb_device_intr, sc, &sc->irq_handle);
  129         if (error != 0) {
  130                 device_printf(dev, "can't setup irq\n");
  131                 goto fail;
  132         }
  133 
  134         /* Attach children when interrupts are available */
  135         return (bus_delayed_attach_children(dev));
  136 fail:
  137         mtx_destroy(&sc->mutex);
  138         return (error);
  139 }
  140 
  141 /********************************************************************
  142                         SMBUS METHODS
  143 ********************************************************************/
  144 
  145 int 
  146 ichsmb_callback(device_t dev, int index, void *data)
  147 {
  148         int smb_error = 0;
  149 
  150         DBG("index=%d how=%d\n", index, data ? *(int *)data : -1);
  151         switch (index) {
  152         case SMB_REQUEST_BUS:
  153                 break;
  154         case SMB_RELEASE_BUS:
  155                 break;
  156         default:
  157                 smb_error = SMB_EABORT; /* XXX */
  158                 break;
  159         }
  160         DBG("smb_error=%d\n", smb_error);
  161         return (smb_error);
  162 }
  163 
  164 int
  165 ichsmb_quick(device_t dev, u_char slave, int how)
  166 {
  167         const sc_p sc = device_get_softc(dev);
  168         int smb_error;
  169 
  170         DBG("slave=0x%02x how=%d\n", slave, how);
  171         KASSERT(sc->ich_cmd == -1,
  172             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  173         switch (how) {
  174         case SMB_QREAD:
  175         case SMB_QWRITE:
  176                 mtx_lock(&sc->mutex);
  177                 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK;
  178                 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  179                     slave | (how == SMB_QREAD ?
  180                         ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE));
  181                 bus_write_1(sc->io_res, ICH_HST_CNT,
  182                     ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  183                 smb_error = ichsmb_wait(sc);
  184                 mtx_unlock(&sc->mutex);
  185                 break;
  186         default:
  187                 smb_error = SMB_ENOTSUPP;
  188         }
  189         DBG("smb_error=%d\n", smb_error);
  190         return (smb_error);
  191 }
  192 
  193 int
  194 ichsmb_sendb(device_t dev, u_char slave, char byte)
  195 {
  196         const sc_p sc = device_get_softc(dev);
  197         int smb_error;
  198 
  199         DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte);
  200         KASSERT(sc->ich_cmd == -1,
  201             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  202         mtx_lock(&sc->mutex);
  203         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
  204         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  205             slave | ICH_XMIT_SLVA_WRITE);
  206         bus_write_1(sc->io_res, ICH_HST_CMD, byte);
  207         bus_write_1(sc->io_res, ICH_HST_CNT,
  208             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  209         smb_error = ichsmb_wait(sc);
  210         mtx_unlock(&sc->mutex);
  211         DBG("smb_error=%d\n", smb_error);
  212         return (smb_error);
  213 }
  214 
  215 int
  216 ichsmb_recvb(device_t dev, u_char slave, char *byte)
  217 {
  218         const sc_p sc = device_get_softc(dev);
  219         int smb_error;
  220 
  221         DBG("slave=0x%02x\n", slave);
  222         KASSERT(sc->ich_cmd == -1,
  223             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  224         mtx_lock(&sc->mutex);
  225         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
  226         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  227             slave | ICH_XMIT_SLVA_READ);
  228         bus_write_1(sc->io_res, ICH_HST_CNT,
  229             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  230         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
  231                 *byte = bus_read_1(sc->io_res, ICH_D0);
  232         mtx_unlock(&sc->mutex);
  233         DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
  234         return (smb_error);
  235 }
  236 
  237 int
  238 ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  239 {
  240         const sc_p sc = device_get_softc(dev);
  241         int smb_error;
  242 
  243         DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n",
  244             slave, (u_char)cmd, (u_char)byte);
  245         KASSERT(sc->ich_cmd == -1,
  246             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  247         mtx_lock(&sc->mutex);
  248         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
  249         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  250             slave | ICH_XMIT_SLVA_WRITE);
  251         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  252         bus_write_1(sc->io_res, ICH_D0, byte);
  253         bus_write_1(sc->io_res, ICH_HST_CNT,
  254             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  255         smb_error = ichsmb_wait(sc);
  256         mtx_unlock(&sc->mutex);
  257         DBG("smb_error=%d\n", smb_error);
  258         return (smb_error);
  259 }
  260 
  261 int
  262 ichsmb_writew(device_t dev, u_char slave, char cmd, short word)
  263 {
  264         const sc_p sc = device_get_softc(dev);
  265         int smb_error;
  266 
  267         DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n",
  268             slave, (u_char)cmd, (u_int16_t)word);
  269         KASSERT(sc->ich_cmd == -1,
  270             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  271         mtx_lock(&sc->mutex);
  272         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
  273         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  274             slave | ICH_XMIT_SLVA_WRITE);
  275         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  276         bus_write_1(sc->io_res, ICH_D0, word & 0xff);
  277         bus_write_1(sc->io_res, ICH_D1, word >> 8);
  278         bus_write_1(sc->io_res, ICH_HST_CNT,
  279             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  280         smb_error = ichsmb_wait(sc);
  281         mtx_unlock(&sc->mutex);
  282         DBG("smb_error=%d\n", smb_error);
  283         return (smb_error);
  284 }
  285 
  286 int
  287 ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  288 {
  289         const sc_p sc = device_get_softc(dev);
  290         int smb_error;
  291 
  292         DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
  293         KASSERT(sc->ich_cmd == -1,
  294             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  295         mtx_lock(&sc->mutex);
  296         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
  297         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  298             slave | ICH_XMIT_SLVA_READ);
  299         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  300         bus_write_1(sc->io_res, ICH_HST_CNT,
  301             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  302         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
  303                 *byte = bus_read_1(sc->io_res, ICH_D0);
  304         mtx_unlock(&sc->mutex);
  305         DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
  306         return (smb_error);
  307 }
  308 
  309 int
  310 ichsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  311 {
  312         const sc_p sc = device_get_softc(dev);
  313         int smb_error;
  314 
  315         DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
  316         KASSERT(sc->ich_cmd == -1,
  317             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  318         mtx_lock(&sc->mutex);
  319         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
  320         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  321             slave | ICH_XMIT_SLVA_READ);
  322         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  323         bus_write_1(sc->io_res, ICH_HST_CNT,
  324             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  325         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
  326                 *word = (bus_read_1(sc->io_res,
  327                         ICH_D0) & 0xff)
  328                   | (bus_read_1(sc->io_res,
  329                         ICH_D1) << 8);
  330         }
  331         mtx_unlock(&sc->mutex);
  332         DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word);
  333         return (smb_error);
  334 }
  335 
  336 int
  337 ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
  338 {
  339         const sc_p sc = device_get_softc(dev);
  340         int smb_error;
  341 
  342         DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n",
  343             slave, (u_char)cmd, (u_int16_t)sdata);
  344         KASSERT(sc->ich_cmd == -1,
  345             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  346         mtx_lock(&sc->mutex);
  347         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL;
  348         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  349             slave | ICH_XMIT_SLVA_WRITE);
  350         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  351         bus_write_1(sc->io_res, ICH_D0, sdata & 0xff);
  352         bus_write_1(sc->io_res, ICH_D1, sdata >> 8);
  353         bus_write_1(sc->io_res, ICH_HST_CNT,
  354             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  355         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
  356                 *rdata = (bus_read_1(sc->io_res,
  357                         ICH_D0) & 0xff)
  358                   | (bus_read_1(sc->io_res,
  359                         ICH_D1) << 8);
  360         }
  361         mtx_unlock(&sc->mutex);
  362         DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata);
  363         return (smb_error);
  364 }
  365 
  366 int
  367 ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  368 {
  369         const sc_p sc = device_get_softc(dev);
  370         int smb_error;
  371 
  372         DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count);
  373 #if ICHSMB_DEBUG
  374 #define DISP(ch)        (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
  375         {
  376             u_char *p;
  377 
  378             for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
  379                 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
  380                     "  %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
  381                     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
  382                     DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 
  383                     DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
  384             }
  385         }
  386 #undef DISP
  387 #endif
  388         KASSERT(sc->ich_cmd == -1,
  389             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  390         if (count < 1 || count > 32)
  391                 return (SMB_EINVAL);
  392         bcopy(buf, sc->block_data, count);
  393         sc->block_count = count;
  394         sc->block_index = 1;
  395         sc->block_write = 1;
  396 
  397         mtx_lock(&sc->mutex);
  398         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
  399         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  400             slave | ICH_XMIT_SLVA_WRITE);
  401         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  402         bus_write_1(sc->io_res, ICH_D0, count);
  403         bus_write_1(sc->io_res, ICH_BLOCK_DB, buf[0]);
  404         bus_write_1(sc->io_res, ICH_HST_CNT,
  405             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  406         smb_error = ichsmb_wait(sc);
  407         mtx_unlock(&sc->mutex);
  408         DBG("smb_error=%d\n", smb_error);
  409         return (smb_error);
  410 }
  411 
  412 int
  413 ichsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
  414 {
  415         const sc_p sc = device_get_softc(dev);
  416         int smb_error;
  417 
  418         DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count);
  419         KASSERT(sc->ich_cmd == -1,
  420             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  421         if (*count < 1 || *count > 32)
  422                 return (SMB_EINVAL);
  423         bzero(sc->block_data, sizeof(sc->block_data));
  424         sc->block_count = 0;
  425         sc->block_index = 0;
  426         sc->block_write = 0;
  427 
  428         mtx_lock(&sc->mutex);
  429         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
  430         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  431             slave | ICH_XMIT_SLVA_READ);
  432         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  433         bus_write_1(sc->io_res, ICH_D0, *count); /* XXX? */
  434         bus_write_1(sc->io_res, ICH_HST_CNT,
  435             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  436         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
  437                 bcopy(sc->block_data, buf, min(sc->block_count, *count));
  438                 *count = sc->block_count;
  439         }
  440         mtx_unlock(&sc->mutex);
  441         DBG("smb_error=%d\n", smb_error);
  442 #if ICHSMB_DEBUG
  443 #define DISP(ch)        (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
  444         {
  445             u_char *p;
  446 
  447             for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
  448                 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
  449                     "  %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
  450                     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
  451                     DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 
  452                     DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
  453             }
  454         }
  455 #undef DISP
  456 #endif
  457         return (smb_error);
  458 }
  459 
  460 /********************************************************************
  461                         OTHER FUNCTIONS
  462 ********************************************************************/
  463 
  464 /*
  465  * This table describes what interrupts we should ever expect to
  466  * see after each ICH command, not including the SMBALERT interrupt.
  467  */
  468 static const u_int8_t ichsmb_state_irqs[] = {
  469         /* quick */
  470         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
  471         /* byte */
  472         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
  473         /* byte data */
  474         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
  475         /* word data */
  476         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
  477         /* process call */
  478         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
  479         /* block */
  480         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
  481             | ICH_HST_STA_BYTE_DONE_STS),
  482         /* i2c read (not used) */
  483         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
  484             | ICH_HST_STA_BYTE_DONE_STS)
  485 };
  486 
  487 /*
  488  * Interrupt handler. This handler is bus-independent. Note that our
  489  * interrupt may be shared, so we must handle "false" interrupts.
  490  */
  491 void
  492 ichsmb_device_intr(void *cookie)
  493 {
  494         const sc_p sc = cookie;
  495         const device_t dev = sc->dev;
  496         const int maxloops = 16;
  497         u_int8_t status;
  498         u_int8_t ok_bits;
  499         int cmd_index;
  500         int count;
  501 
  502         mtx_lock(&sc->mutex);
  503         for (count = 0; count < maxloops; count++) {
  504 
  505                 /* Get and reset status bits */
  506                 status = bus_read_1(sc->io_res, ICH_HST_STA);
  507 #if ICHSMB_DEBUG
  508                 if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY))
  509                     || count > 0) {
  510                         DBG("%d stat=0x%02x\n", count, status);
  511                 }
  512 #endif
  513                 status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY);
  514                 if (status == 0)
  515                         break;
  516 
  517                 /* Check for unexpected interrupt */
  518                 ok_bits = ICH_HST_STA_SMBALERT_STS;
  519                 cmd_index = sc->ich_cmd >> 2;
  520                 if (sc->ich_cmd != -1) {
  521                         KASSERT(cmd_index < sizeof(ichsmb_state_irqs),
  522                             ("%s: ich_cmd=%d", device_get_nameunit(dev),
  523                             sc->ich_cmd));
  524                         ok_bits |= ichsmb_state_irqs[cmd_index];
  525                 }
  526                 if ((status & ~ok_bits) != 0) {
  527                         device_printf(dev, "irq 0x%02x during %d\n", status,
  528                             cmd_index);
  529                         bus_write_1(sc->io_res,
  530                             ICH_HST_STA, (status & ~ok_bits));
  531                         continue;
  532                 }
  533 
  534                 /* Handle SMBALERT interrupt */
  535                 if (status & ICH_HST_STA_SMBALERT_STS) {
  536                         static int smbalert_count = 16;
  537                         if (smbalert_count > 0) {
  538                                 device_printf(dev, "SMBALERT# rec'd\n");
  539                                 if (--smbalert_count == 0) {
  540                                         device_printf(dev,
  541                                             "not logging anymore\n");
  542                                 }
  543                         }
  544                 }
  545 
  546                 /* Check for bus error */
  547                 if (status & ICH_HST_STA_BUS_ERR) {
  548                         sc->smb_error = SMB_ECOLLI;     /* XXX SMB_EBUSERR? */
  549                         goto finished;
  550                 }
  551 
  552                 /* Check for device error */
  553                 if (status & ICH_HST_STA_DEV_ERR) {
  554                         sc->smb_error = SMB_ENOACK;     /* or SMB_ETIMEOUT? */
  555                         goto finished;
  556                 }
  557 
  558                 /* Check for byte completion in block transfer */
  559                 if (status & ICH_HST_STA_BYTE_DONE_STS) {
  560                         if (sc->block_write) {
  561                                 if (sc->block_index < sc->block_count) {
  562 
  563                                         /* Write next byte */
  564                                         bus_write_1(sc->io_res,
  565                                             ICH_BLOCK_DB,
  566                                             sc->block_data[sc->block_index++]);
  567                                 }
  568                         } else {
  569 
  570                                 /* First interrupt, get the count also */
  571                                 if (sc->block_index == 0) {
  572                                         sc->block_count = bus_read_1(
  573                                             sc->io_res, ICH_D0);
  574                                 }
  575 
  576                                 /* Get next byte, if any */
  577                                 if (sc->block_index < sc->block_count) {
  578 
  579                                         /* Read next byte */
  580                                         sc->block_data[sc->block_index++] =
  581                                             bus_read_1(sc->io_res,
  582                                               ICH_BLOCK_DB);
  583 
  584                                         /* Set "LAST_BYTE" bit before reading
  585                                            the last byte of block data */
  586                                         if (sc->block_index
  587                                             >= sc->block_count - 1) {
  588                                                 bus_write_1(sc->io_res,
  589                                                     ICH_HST_CNT,
  590                                                     ICH_HST_CNT_LAST_BYTE
  591                                                         | ICH_HST_CNT_INTREN
  592                                                         | sc->ich_cmd);
  593                                         }
  594                                 }
  595                         }
  596                 }
  597 
  598                 /* Check command completion */
  599                 if (status & ICH_HST_STA_INTR) {
  600                         sc->smb_error = SMB_ENOERR;
  601 finished:
  602                         sc->ich_cmd = -1;
  603                         bus_write_1(sc->io_res,
  604                             ICH_HST_STA, status);
  605                         wakeup(sc);
  606                         break;
  607                 }
  608 
  609                 /* Clear status bits and try again */
  610                 bus_write_1(sc->io_res, ICH_HST_STA, status);
  611         }
  612         mtx_unlock(&sc->mutex);
  613 
  614         /* Too many loops? */
  615         if (count == maxloops) {
  616                 device_printf(dev, "interrupt loop, status=0x%02x\n",
  617                     bus_read_1(sc->io_res, ICH_HST_STA));
  618         }
  619 }
  620 
  621 /*
  622  * Wait for command completion. Assumes mutex is held.
  623  * Returns an SMB_* error code.
  624  */
  625 static int
  626 ichsmb_wait(sc_p sc)
  627 {
  628         const device_t dev = sc->dev;
  629         int error, smb_error;
  630 
  631         KASSERT(sc->ich_cmd != -1,
  632             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  633         mtx_assert(&sc->mutex, MA_OWNED);
  634         error = msleep(sc, &sc->mutex, PZERO, "ichsmb", hz / 4);
  635         DBG("msleep -> %d\n", error);
  636         switch (error) {
  637         case 0:
  638                 smb_error = sc->smb_error;
  639                 break;
  640         case EWOULDBLOCK:
  641                 device_printf(dev, "device timeout, status=0x%02x\n",
  642                     bus_read_1(sc->io_res, ICH_HST_STA));
  643                 sc->ich_cmd = -1;
  644                 smb_error = SMB_ETIMEOUT;
  645                 break;
  646         default:
  647                 smb_error = SMB_EABORT;
  648                 break;
  649         }
  650         return (smb_error);
  651 }
  652 
  653 /*
  654  * Release resources associated with device.
  655  */
  656 void
  657 ichsmb_release_resources(sc_p sc)
  658 {
  659         const device_t dev = sc->dev;
  660 
  661         if (sc->irq_handle != NULL) {
  662                 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
  663                 sc->irq_handle = NULL;
  664         }
  665         if (sc->irq_res != NULL) {
  666                 bus_release_resource(dev,
  667                     SYS_RES_IRQ, sc->irq_rid, sc->irq_res);
  668                 sc->irq_res = NULL;
  669         }
  670         if (sc->io_res != NULL) {
  671                 bus_release_resource(dev,
  672                     SYS_RES_IOPORT, sc->io_rid, sc->io_res);
  673                 sc->io_res = NULL;
  674         }
  675 }
  676 
  677 int
  678 ichsmb_detach(device_t dev)
  679 {
  680         const sc_p sc = device_get_softc(dev);
  681         int error;
  682 
  683         error = bus_generic_detach(dev);
  684         if (error)
  685                 return (error);
  686         device_delete_child(dev, sc->smb);
  687         ichsmb_release_resources(sc);
  688         mtx_destroy(&sc->mutex);
  689         
  690         return 0;
  691 }
  692 
  693 DRIVER_MODULE(smbus, ichsmb, smbus_driver, 0, 0);

Cache object: 27a19fb91445fd73b9f69ea1dedd88bb


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.