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: releng/9.0/sys/dev/ichsmb/ichsmb.c 188077 2009-02-03 16:14:37Z jhb $");
   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 && defined(__CC_SUPPORTS___FUNC__)
   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 "smbus" child */
  135         if ((error = bus_generic_attach(dev)) != 0) {
  136                 device_printf(dev, "failed to attach child: %d\n", error);
  137                 goto fail;
  138         }
  139 
  140         return (0);
  141 
  142 fail:
  143         mtx_destroy(&sc->mutex);
  144         return (error);
  145 }
  146 
  147 /********************************************************************
  148                         SMBUS METHODS
  149 ********************************************************************/
  150 
  151 int 
  152 ichsmb_callback(device_t dev, int index, void *data)
  153 {
  154         int smb_error = 0;
  155 
  156         DBG("index=%d how=%d\n", index, data ? *(int *)data : -1);
  157         switch (index) {
  158         case SMB_REQUEST_BUS:
  159                 break;
  160         case SMB_RELEASE_BUS:
  161                 break;
  162         default:
  163                 smb_error = SMB_EABORT; /* XXX */
  164                 break;
  165         }
  166         DBG("smb_error=%d\n", smb_error);
  167         return (smb_error);
  168 }
  169 
  170 int
  171 ichsmb_quick(device_t dev, u_char slave, int how)
  172 {
  173         const sc_p sc = device_get_softc(dev);
  174         int smb_error;
  175 
  176         DBG("slave=0x%02x how=%d\n", slave, how);
  177         KASSERT(sc->ich_cmd == -1,
  178             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  179         switch (how) {
  180         case SMB_QREAD:
  181         case SMB_QWRITE:
  182                 mtx_lock(&sc->mutex);
  183                 sc->ich_cmd = ICH_HST_CNT_SMB_CMD_QUICK;
  184                 bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  185                     slave | (how == SMB_QREAD ?
  186                         ICH_XMIT_SLVA_READ : ICH_XMIT_SLVA_WRITE));
  187                 bus_write_1(sc->io_res, ICH_HST_CNT,
  188                     ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  189                 smb_error = ichsmb_wait(sc);
  190                 mtx_unlock(&sc->mutex);
  191                 break;
  192         default:
  193                 smb_error = SMB_ENOTSUPP;
  194         }
  195         DBG("smb_error=%d\n", smb_error);
  196         return (smb_error);
  197 }
  198 
  199 int
  200 ichsmb_sendb(device_t dev, u_char slave, char byte)
  201 {
  202         const sc_p sc = device_get_softc(dev);
  203         int smb_error;
  204 
  205         DBG("slave=0x%02x byte=0x%02x\n", slave, (u_char)byte);
  206         KASSERT(sc->ich_cmd == -1,
  207             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  208         mtx_lock(&sc->mutex);
  209         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
  210         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  211             slave | ICH_XMIT_SLVA_WRITE);
  212         bus_write_1(sc->io_res, ICH_HST_CMD, byte);
  213         bus_write_1(sc->io_res, ICH_HST_CNT,
  214             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  215         smb_error = ichsmb_wait(sc);
  216         mtx_unlock(&sc->mutex);
  217         DBG("smb_error=%d\n", smb_error);
  218         return (smb_error);
  219 }
  220 
  221 int
  222 ichsmb_recvb(device_t dev, u_char slave, char *byte)
  223 {
  224         const sc_p sc = device_get_softc(dev);
  225         int smb_error;
  226 
  227         DBG("slave=0x%02x\n", slave);
  228         KASSERT(sc->ich_cmd == -1,
  229             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  230         mtx_lock(&sc->mutex);
  231         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE;
  232         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  233             slave | ICH_XMIT_SLVA_READ);
  234         bus_write_1(sc->io_res, ICH_HST_CNT,
  235             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  236         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
  237                 *byte = bus_read_1(sc->io_res, ICH_D0);
  238         mtx_unlock(&sc->mutex);
  239         DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
  240         return (smb_error);
  241 }
  242 
  243 int
  244 ichsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  245 {
  246         const sc_p sc = device_get_softc(dev);
  247         int smb_error;
  248 
  249         DBG("slave=0x%02x cmd=0x%02x byte=0x%02x\n",
  250             slave, (u_char)cmd, (u_char)byte);
  251         KASSERT(sc->ich_cmd == -1,
  252             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  253         mtx_lock(&sc->mutex);
  254         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
  255         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  256             slave | ICH_XMIT_SLVA_WRITE);
  257         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  258         bus_write_1(sc->io_res, ICH_D0, byte);
  259         bus_write_1(sc->io_res, ICH_HST_CNT,
  260             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  261         smb_error = ichsmb_wait(sc);
  262         mtx_unlock(&sc->mutex);
  263         DBG("smb_error=%d\n", smb_error);
  264         return (smb_error);
  265 }
  266 
  267 int
  268 ichsmb_writew(device_t dev, u_char slave, char cmd, short word)
  269 {
  270         const sc_p sc = device_get_softc(dev);
  271         int smb_error;
  272 
  273         DBG("slave=0x%02x cmd=0x%02x word=0x%04x\n",
  274             slave, (u_char)cmd, (u_int16_t)word);
  275         KASSERT(sc->ich_cmd == -1,
  276             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  277         mtx_lock(&sc->mutex);
  278         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
  279         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  280             slave | ICH_XMIT_SLVA_WRITE);
  281         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  282         bus_write_1(sc->io_res, ICH_D0, word & 0xff);
  283         bus_write_1(sc->io_res, ICH_D1, word >> 8);
  284         bus_write_1(sc->io_res, ICH_HST_CNT,
  285             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  286         smb_error = ichsmb_wait(sc);
  287         mtx_unlock(&sc->mutex);
  288         DBG("smb_error=%d\n", smb_error);
  289         return (smb_error);
  290 }
  291 
  292 int
  293 ichsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  294 {
  295         const sc_p sc = device_get_softc(dev);
  296         int smb_error;
  297 
  298         DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
  299         KASSERT(sc->ich_cmd == -1,
  300             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  301         mtx_lock(&sc->mutex);
  302         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BYTE_DATA;
  303         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  304             slave | ICH_XMIT_SLVA_READ);
  305         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  306         bus_write_1(sc->io_res, ICH_HST_CNT,
  307             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  308         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR)
  309                 *byte = bus_read_1(sc->io_res, ICH_D0);
  310         mtx_unlock(&sc->mutex);
  311         DBG("smb_error=%d byte=0x%02x\n", smb_error, (u_char)*byte);
  312         return (smb_error);
  313 }
  314 
  315 int
  316 ichsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  317 {
  318         const sc_p sc = device_get_softc(dev);
  319         int smb_error;
  320 
  321         DBG("slave=0x%02x cmd=0x%02x\n", slave, (u_char)cmd);
  322         KASSERT(sc->ich_cmd == -1,
  323             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  324         mtx_lock(&sc->mutex);
  325         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_WORD_DATA;
  326         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  327             slave | ICH_XMIT_SLVA_READ);
  328         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  329         bus_write_1(sc->io_res, ICH_HST_CNT,
  330             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  331         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
  332                 *word = (bus_read_1(sc->io_res,
  333                         ICH_D0) & 0xff)
  334                   | (bus_read_1(sc->io_res,
  335                         ICH_D1) << 8);
  336         }
  337         mtx_unlock(&sc->mutex);
  338         DBG("smb_error=%d word=0x%04x\n", smb_error, (u_int16_t)*word);
  339         return (smb_error);
  340 }
  341 
  342 int
  343 ichsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
  344 {
  345         const sc_p sc = device_get_softc(dev);
  346         int smb_error;
  347 
  348         DBG("slave=0x%02x cmd=0x%02x sdata=0x%04x\n",
  349             slave, (u_char)cmd, (u_int16_t)sdata);
  350         KASSERT(sc->ich_cmd == -1,
  351             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  352         mtx_lock(&sc->mutex);
  353         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_PROC_CALL;
  354         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  355             slave | ICH_XMIT_SLVA_WRITE);
  356         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  357         bus_write_1(sc->io_res, ICH_D0, sdata & 0xff);
  358         bus_write_1(sc->io_res, ICH_D1, sdata >> 8);
  359         bus_write_1(sc->io_res, ICH_HST_CNT,
  360             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  361         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
  362                 *rdata = (bus_read_1(sc->io_res,
  363                         ICH_D0) & 0xff)
  364                   | (bus_read_1(sc->io_res,
  365                         ICH_D1) << 8);
  366         }
  367         mtx_unlock(&sc->mutex);
  368         DBG("smb_error=%d rdata=0x%04x\n", smb_error, (u_int16_t)*rdata);
  369         return (smb_error);
  370 }
  371 
  372 int
  373 ichsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  374 {
  375         const sc_p sc = device_get_softc(dev);
  376         int smb_error;
  377 
  378         DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count);
  379 #if ICHSMB_DEBUG
  380 #define DISP(ch)        (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
  381         {
  382             u_char *p;
  383 
  384             for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
  385                 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
  386                     "  %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
  387                     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
  388                     DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 
  389                     DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
  390             }
  391         }
  392 #undef DISP
  393 #endif
  394         KASSERT(sc->ich_cmd == -1,
  395             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  396         if (count < 1 || count > 32)
  397                 return (SMB_EINVAL);
  398         bcopy(buf, sc->block_data, count);
  399         sc->block_count = count;
  400         sc->block_index = 1;
  401         sc->block_write = 1;
  402 
  403         mtx_lock(&sc->mutex);
  404         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
  405         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  406             slave | ICH_XMIT_SLVA_WRITE);
  407         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  408         bus_write_1(sc->io_res, ICH_D0, count);
  409         bus_write_1(sc->io_res, ICH_BLOCK_DB, buf[0]);
  410         bus_write_1(sc->io_res, ICH_HST_CNT,
  411             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  412         smb_error = ichsmb_wait(sc);
  413         mtx_unlock(&sc->mutex);
  414         DBG("smb_error=%d\n", smb_error);
  415         return (smb_error);
  416 }
  417 
  418 int
  419 ichsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
  420 {
  421         const sc_p sc = device_get_softc(dev);
  422         int smb_error;
  423 
  424         DBG("slave=0x%02x cmd=0x%02x count=%d\n", slave, (u_char)cmd, count);
  425         KASSERT(sc->ich_cmd == -1,
  426             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  427         if (*count < 1 || *count > 32)
  428                 return (SMB_EINVAL);
  429         bzero(sc->block_data, sizeof(sc->block_data));
  430         sc->block_count = 0;
  431         sc->block_index = 0;
  432         sc->block_write = 0;
  433 
  434         mtx_lock(&sc->mutex);
  435         sc->ich_cmd = ICH_HST_CNT_SMB_CMD_BLOCK;
  436         bus_write_1(sc->io_res, ICH_XMIT_SLVA,
  437             slave | ICH_XMIT_SLVA_READ);
  438         bus_write_1(sc->io_res, ICH_HST_CMD, cmd);
  439         bus_write_1(sc->io_res, ICH_D0, *count); /* XXX? */
  440         bus_write_1(sc->io_res, ICH_HST_CNT,
  441             ICH_HST_CNT_START | ICH_HST_CNT_INTREN | sc->ich_cmd);
  442         if ((smb_error = ichsmb_wait(sc)) == SMB_ENOERR) {
  443                 bcopy(sc->block_data, buf, min(sc->block_count, *count));
  444                 *count = sc->block_count;
  445         }
  446         mtx_unlock(&sc->mutex);
  447         DBG("smb_error=%d\n", smb_error);
  448 #if ICHSMB_DEBUG
  449 #define DISP(ch)        (((ch) < 0x20 || (ch) >= 0x7e) ? '.' : (ch))
  450         {
  451             u_char *p;
  452 
  453             for (p = (u_char *)buf; p - (u_char *)buf < 32; p += 8) {
  454                 DBG("%02x: %02x %02x %02x %02x %02x %02x %02x %02x"
  455                     "  %c%c%c%c%c%c%c%c", (p - (u_char *)buf),
  456                     p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7],
  457                     DISP(p[0]), DISP(p[1]), DISP(p[2]), DISP(p[3]), 
  458                     DISP(p[4]), DISP(p[5]), DISP(p[6]), DISP(p[7]));
  459             }
  460         }
  461 #undef DISP
  462 #endif
  463         return (smb_error);
  464 }
  465 
  466 /********************************************************************
  467                         OTHER FUNCTIONS
  468 ********************************************************************/
  469 
  470 /*
  471  * This table describes what interrupts we should ever expect to
  472  * see after each ICH command, not including the SMBALERT interrupt.
  473  */
  474 static const u_int8_t ichsmb_state_irqs[] = {
  475         /* quick */
  476         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
  477         /* byte */
  478         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
  479         /* byte data */
  480         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
  481         /* word data */
  482         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
  483         /* process call */
  484         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR),
  485         /* block */
  486         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
  487             | ICH_HST_STA_BYTE_DONE_STS),
  488         /* i2c read (not used) */
  489         (ICH_HST_STA_BUS_ERR | ICH_HST_STA_DEV_ERR | ICH_HST_STA_INTR
  490             | ICH_HST_STA_BYTE_DONE_STS)
  491 };
  492 
  493 /*
  494  * Interrupt handler. This handler is bus-independent. Note that our
  495  * interrupt may be shared, so we must handle "false" interrupts.
  496  */
  497 void
  498 ichsmb_device_intr(void *cookie)
  499 {
  500         const sc_p sc = cookie;
  501         const device_t dev = sc->dev;
  502         const int maxloops = 16;
  503         u_int8_t status;
  504         u_int8_t ok_bits;
  505         int cmd_index;
  506         int count;
  507 
  508         mtx_lock(&sc->mutex);
  509         for (count = 0; count < maxloops; count++) {
  510 
  511                 /* Get and reset status bits */
  512                 status = bus_read_1(sc->io_res, ICH_HST_STA);
  513 #if ICHSMB_DEBUG
  514                 if ((status & ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY))
  515                     || count > 0) {
  516                         DBG("%d stat=0x%02x\n", count, status);
  517                 }
  518 #endif
  519                 status &= ~(ICH_HST_STA_INUSE_STS | ICH_HST_STA_HOST_BUSY);
  520                 if (status == 0)
  521                         break;
  522 
  523                 /* Check for unexpected interrupt */
  524                 ok_bits = ICH_HST_STA_SMBALERT_STS;
  525                 cmd_index = sc->ich_cmd >> 2;
  526                 if (sc->ich_cmd != -1) {
  527                         KASSERT(cmd_index < sizeof(ichsmb_state_irqs),
  528                             ("%s: ich_cmd=%d", device_get_nameunit(dev),
  529                             sc->ich_cmd));
  530                         ok_bits |= ichsmb_state_irqs[cmd_index];
  531                 }
  532                 if ((status & ~ok_bits) != 0) {
  533                         device_printf(dev, "irq 0x%02x during %d\n", status,
  534                             cmd_index);
  535                         bus_write_1(sc->io_res,
  536                             ICH_HST_STA, (status & ~ok_bits));
  537                         continue;
  538                 }
  539 
  540                 /* Handle SMBALERT interrupt */
  541                 if (status & ICH_HST_STA_SMBALERT_STS) {
  542                         static int smbalert_count = 16;
  543                         if (smbalert_count > 0) {
  544                                 device_printf(dev, "SMBALERT# rec'd\n");
  545                                 if (--smbalert_count == 0) {
  546                                         device_printf(dev,
  547                                             "not logging anymore\n");
  548                                 }
  549                         }
  550                 }
  551 
  552                 /* Check for bus error */
  553                 if (status & ICH_HST_STA_BUS_ERR) {
  554                         sc->smb_error = SMB_ECOLLI;     /* XXX SMB_EBUSERR? */
  555                         goto finished;
  556                 }
  557 
  558                 /* Check for device error */
  559                 if (status & ICH_HST_STA_DEV_ERR) {
  560                         sc->smb_error = SMB_ENOACK;     /* or SMB_ETIMEOUT? */
  561                         goto finished;
  562                 }
  563 
  564                 /* Check for byte completion in block transfer */
  565                 if (status & ICH_HST_STA_BYTE_DONE_STS) {
  566                         if (sc->block_write) {
  567                                 if (sc->block_index < sc->block_count) {
  568 
  569                                         /* Write next byte */
  570                                         bus_write_1(sc->io_res,
  571                                             ICH_BLOCK_DB,
  572                                             sc->block_data[sc->block_index++]);
  573                                 }
  574                         } else {
  575 
  576                                 /* First interrupt, get the count also */
  577                                 if (sc->block_index == 0) {
  578                                         sc->block_count = bus_read_1(
  579                                             sc->io_res, ICH_D0);
  580                                 }
  581 
  582                                 /* Get next byte, if any */
  583                                 if (sc->block_index < sc->block_count) {
  584 
  585                                         /* Read next byte */
  586                                         sc->block_data[sc->block_index++] =
  587                                             bus_read_1(sc->io_res,
  588                                               ICH_BLOCK_DB);
  589 
  590                                         /* Set "LAST_BYTE" bit before reading
  591                                            the last byte of block data */
  592                                         if (sc->block_index
  593                                             >= sc->block_count - 1) {
  594                                                 bus_write_1(sc->io_res,
  595                                                     ICH_HST_CNT,
  596                                                     ICH_HST_CNT_LAST_BYTE
  597                                                         | ICH_HST_CNT_INTREN
  598                                                         | sc->ich_cmd);
  599                                         }
  600                                 }
  601                         }
  602                 }
  603 
  604                 /* Check command completion */
  605                 if (status & ICH_HST_STA_INTR) {
  606                         sc->smb_error = SMB_ENOERR;
  607 finished:
  608                         sc->ich_cmd = -1;
  609                         bus_write_1(sc->io_res,
  610                             ICH_HST_STA, status);
  611                         wakeup(sc);
  612                         break;
  613                 }
  614 
  615                 /* Clear status bits and try again */
  616                 bus_write_1(sc->io_res, ICH_HST_STA, status);
  617         }
  618         mtx_unlock(&sc->mutex);
  619 
  620         /* Too many loops? */
  621         if (count == maxloops) {
  622                 device_printf(dev, "interrupt loop, status=0x%02x\n",
  623                     bus_read_1(sc->io_res, ICH_HST_STA));
  624         }
  625 }
  626 
  627 /*
  628  * Wait for command completion. Assumes mutex is held.
  629  * Returns an SMB_* error code.
  630  */
  631 static int
  632 ichsmb_wait(sc_p sc)
  633 {
  634         const device_t dev = sc->dev;
  635         int error, smb_error;
  636 
  637         KASSERT(sc->ich_cmd != -1,
  638             ("%s: ich_cmd=%d\n", __func__ , sc->ich_cmd));
  639         mtx_assert(&sc->mutex, MA_OWNED);
  640         error = msleep(sc, &sc->mutex, PZERO, "ichsmb", hz / 4);
  641         DBG("msleep -> %d\n", error);
  642         switch (error) {
  643         case 0:
  644                 smb_error = sc->smb_error;
  645                 break;
  646         case EWOULDBLOCK:
  647                 device_printf(dev, "device timeout, status=0x%02x\n",
  648                     bus_read_1(sc->io_res, ICH_HST_STA));
  649                 sc->ich_cmd = -1;
  650                 smb_error = SMB_ETIMEOUT;
  651                 break;
  652         default:
  653                 smb_error = SMB_EABORT;
  654                 break;
  655         }
  656         return (smb_error);
  657 }
  658 
  659 /*
  660  * Release resources associated with device.
  661  */
  662 void
  663 ichsmb_release_resources(sc_p sc)
  664 {
  665         const device_t dev = sc->dev;
  666 
  667         if (sc->irq_handle != NULL) {
  668                 bus_teardown_intr(dev, sc->irq_res, sc->irq_handle);
  669                 sc->irq_handle = NULL;
  670         }
  671         if (sc->irq_res != NULL) {
  672                 bus_release_resource(dev,
  673                     SYS_RES_IRQ, sc->irq_rid, sc->irq_res);
  674                 sc->irq_res = NULL;
  675         }
  676         if (sc->io_res != NULL) {
  677                 bus_release_resource(dev,
  678                     SYS_RES_IOPORT, sc->io_rid, sc->io_res);
  679                 sc->io_res = NULL;
  680         }
  681 }
  682 
  683 int
  684 ichsmb_detach(device_t dev)
  685 {
  686         const sc_p sc = device_get_softc(dev);
  687         int error;
  688 
  689         error = bus_generic_detach(dev);
  690         if (error)
  691                 return (error);
  692         device_delete_child(dev, sc->smb);
  693         ichsmb_release_resources(sc);
  694         mtx_destroy(&sc->mutex);
  695         
  696         return 0;
  697 }
  698 
  699 DRIVER_MODULE(smbus, ichsmb, smbus_driver, smbus_devclass, 0, 0);

Cache object: 033706149320b8e0255d26f6be92243b


[ 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.