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

Cache object: 3f564389f85483e3cb5e232f491820ba


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