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

Cache object: a80a85dc9d5cc70162886fbc026e5d52


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