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/pci/intpm.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  * Copyright (c) 1998, 1999 Takanori Watanabe
    3  * All rights reserved.
    4  *
    5  * Redistribution and use in source and binary forms, with or without
    6  * modification, are permitted provided that the following conditions
    7  * are met:
    8  * 1. Redistributions of source code must retain the above copyright
    9  *        notice, this list of conditions and the following disclaimer.
   10  * 2. Redistributions in binary form must reproduce the above copyright
   11  *        notice, this list of conditions and the following disclaimer in the
   12  *        documentation and/or other materials provided with the distribution.
   13  *
   14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17  * ARE DISCLAIMED.    IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   24  * SUCH DAMAGE.
   25  */
   26 
   27 #include <sys/cdefs.h>
   28 __FBSDID("$FreeBSD$");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/bus.h>
   33 #include <sys/kernel.h>
   34 #include <sys/lock.h>
   35 #include <sys/module.h>
   36 #include <sys/mutex.h>
   37 #include <sys/rman.h>
   38 #include <machine/bus.h>
   39 #include <dev/smbus/smbconf.h>
   40 
   41 #include "smbus_if.h"
   42 
   43 #include <dev/pci/pcireg.h>
   44 #include <dev/pci/pcivar.h>
   45 #include <pci/intpmreg.h>
   46 
   47 #include "opt_intpm.h"
   48 
   49 struct intsmb_softc {
   50         device_t                dev;
   51         struct resource         *io_res;
   52         struct resource         *irq_res;
   53         void                    *irq_hand;
   54         device_t                smbus;
   55         int                     isbusy;
   56         struct mtx              lock;
   57 };
   58 
   59 #define INTSMB_LOCK(sc)         mtx_lock(&(sc)->lock)
   60 #define INTSMB_UNLOCK(sc)       mtx_unlock(&(sc)->lock)
   61 #define INTSMB_LOCK_ASSERT(sc)  mtx_assert(&(sc)->lock, MA_OWNED)
   62 
   63 static int intsmb_probe(device_t);
   64 static int intsmb_attach(device_t);
   65 static int intsmb_detach(device_t);
   66 static int intsmb_intr(struct intsmb_softc *sc);
   67 static int intsmb_slvintr(struct intsmb_softc *sc);
   68 static void intsmb_alrintr(struct intsmb_softc *sc);
   69 static int intsmb_callback(device_t dev, int index, void *data);
   70 static int intsmb_quick(device_t dev, u_char slave, int how);
   71 static int intsmb_sendb(device_t dev, u_char slave, char byte);
   72 static int intsmb_recvb(device_t dev, u_char slave, char *byte);
   73 static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
   74 static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
   75 static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
   76 static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
   77 static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
   78 static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
   79 static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf);
   80 static void intsmb_start(struct intsmb_softc *sc, u_char cmd, int nointr);
   81 static int intsmb_stop(struct intsmb_softc *sc);
   82 static int intsmb_stop_poll(struct intsmb_softc *sc);
   83 static int intsmb_free(struct intsmb_softc *sc);
   84 static void intsmb_rawintr(void *arg);
   85 
   86 static int
   87 intsmb_probe(device_t dev)
   88 {
   89 
   90         switch (pci_get_devid(dev)) {
   91         case 0x71138086:        /* Intel 82371AB */
   92         case 0x719b8086:        /* Intel 82443MX */
   93 #if 0
   94         /* Not a good idea yet, this stops isab0 functioning */
   95         case 0x02001166:        /* ServerWorks OSB4 */
   96 #endif
   97                 device_set_desc(dev, "Intel PIIX4 SMBUS Interface");
   98                 break;
   99         default:
  100                 return (ENXIO);
  101         }
  102 
  103         return (BUS_PROBE_DEFAULT);
  104 }
  105 
  106 static int
  107 intsmb_attach(device_t dev)
  108 {
  109         struct intsmb_softc *sc = device_get_softc(dev);
  110         int error, rid, value;
  111         char *str;
  112 
  113         mtx_init(&sc->lock, device_get_nameunit(dev), "intsmb", MTX_DEF);
  114 
  115         rid = PCI_BASE_ADDR_SMB;
  116         sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
  117             RF_ACTIVE);
  118         if (sc->io_res == NULL) {
  119                 device_printf(dev, "Could not allocate I/O space\n");
  120                 error = ENXIO;
  121                 goto fail;
  122         }
  123 
  124 #ifndef NO_CHANGE_PCICONF
  125         pci_write_config(dev, PCIR_INTLINE, 0x9, 1);
  126         pci_write_config(dev, PCI_HST_CFG_SMB,
  127             PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1);
  128 #endif
  129         value = pci_read_config(dev, PCI_HST_CFG_SMB, 1);
  130         switch (value & 0xe) {
  131         case PCI_INTR_SMB_SMI:
  132                 str = "SMI";
  133                 break;
  134         case PCI_INTR_SMB_IRQ9:
  135                 str = "IRQ 9";
  136                 break;
  137         default:
  138                 str = "BOGUS";
  139         }
  140         device_printf(dev, "intr %s %s ", str,
  141             (value & 1) ? "enabled" : "disabled");
  142         printf("revision %d\n", pci_read_config(dev, PCI_REVID_SMB, 1));
  143 
  144         if ((value & 0xe) != PCI_INTR_SMB_IRQ9) {
  145                 device_printf(dev, "Unsupported interrupt mode\n");
  146                 error = ENXIO;
  147                 goto fail;
  148         }
  149 
  150         /* Force IRQ 9. */
  151         rid = 0;
  152         bus_set_resource(dev, SYS_RES_IRQ, rid, 9, 1);
  153         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  154             RF_SHAREABLE | RF_ACTIVE);
  155         if (sc->irq_res == NULL) {
  156                 device_printf(dev, "Could not allocate irq\n");
  157                 error = ENXIO;
  158                 goto fail;
  159         }
  160 
  161         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, NULL, 
  162             intsmb_rawintr, sc, &sc->irq_hand);
  163         if (error) {
  164                 device_printf(dev, "Failed to map intr\n");
  165                 goto fail;
  166         }
  167 
  168         value = pci_read_config(dev, PCI_BASE_ADDR_PM, 4);
  169         device_printf(dev, "PM %s %x\n", (value & 1) ? "I/O mapped" : "Memory",
  170             value & 0xfffe);
  171 
  172         sc->isbusy = 0;
  173         sc->smbus = device_add_child(dev, "smbus", -1);
  174         if (sc->smbus == NULL) {
  175                 error = ENXIO;
  176                 goto fail;
  177         }
  178         error = device_probe_and_attach(sc->smbus);
  179         if (error)
  180                 goto fail;
  181 
  182 #ifdef ENABLE_ALART
  183         /* Enable Arart */
  184         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN);
  185 #endif
  186         return (0);
  187 
  188 fail:
  189         intsmb_detach(dev);
  190         return (error);
  191 }
  192 
  193 static int
  194 intsmb_detach(device_t dev)
  195 {
  196         struct intsmb_softc *sc = device_get_softc(dev);
  197         int error;
  198 
  199         error = bus_generic_detach(dev);
  200         if (error)
  201                 return (error);
  202 
  203         if (sc->smbus)
  204                 device_delete_child(dev, sc->smbus);
  205         if (sc->irq_hand)
  206                 bus_teardown_intr(dev, sc->irq_res, sc->irq_hand);
  207         if (sc->irq_res)
  208                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
  209         if (sc->io_res)
  210                 bus_release_resource(dev, SYS_RES_IOPORT, PCI_BASE_ADDR_SMB,
  211                     sc->io_res);
  212         mtx_destroy(&sc->lock);
  213         return (0);
  214 }
  215 
  216 static void
  217 intsmb_rawintr(void *arg)
  218 {
  219         struct intsmb_softc *sc = arg;
  220 
  221         INTSMB_LOCK(sc);
  222         intsmb_intr(sc);
  223         intsmb_slvintr(sc);
  224         INTSMB_UNLOCK(sc);
  225 }
  226 
  227 static int
  228 intsmb_callback(device_t dev, int index, void *data)
  229 {
  230         int error = 0;
  231 
  232         switch (index) {
  233         case SMB_REQUEST_BUS:
  234                 break;
  235         case SMB_RELEASE_BUS:
  236                 break;
  237         default:
  238                 error = EINVAL;
  239         }
  240 
  241         return (error);
  242 }
  243 
  244 /* Counterpart of smbtx_smb_free(). */
  245 static int
  246 intsmb_free(struct intsmb_softc *sc)
  247 {
  248 
  249         INTSMB_LOCK_ASSERT(sc);
  250         if ((bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) & PIIX4_SMBHSTSTAT_BUSY) ||
  251 #ifdef ENABLE_ALART
  252             (bus_read_1(sc->io_res, PIIX4_SMBSLVSTS) & PIIX4_SMBSLVSTS_BUSY) ||
  253 #endif
  254             sc->isbusy)
  255                 return (SMB_EBUSY);
  256 
  257         sc->isbusy = 1;
  258         /* Disable Interrupt in slave part. */
  259 #ifndef ENABLE_ALART
  260         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 0);
  261 #endif
  262         /* Reset INTR Flag to prepare INTR. */
  263         bus_write_1(sc->io_res, PIIX4_SMBHSTSTS,
  264             PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
  265             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL);
  266         return (0);
  267 }
  268 
  269 static int
  270 intsmb_intr(struct intsmb_softc *sc)
  271 {
  272         int status, tmp;
  273 
  274         status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
  275         if (status & PIIX4_SMBHSTSTAT_BUSY)
  276                 return (1);
  277 
  278         if (status & (PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
  279             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL)) {
  280 
  281                 tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  282                 bus_write_1(sc->io_res, PIIX4_SMBHSTCNT,
  283                     tmp & ~PIIX4_SMBHSTCNT_INTREN);
  284                 if (sc->isbusy) {
  285                         sc->isbusy = 0;
  286                         wakeup(sc);
  287                 }
  288                 return (0);
  289         }
  290         return (1); /* Not Completed */
  291 }
  292 
  293 static int
  294 intsmb_slvintr(struct intsmb_softc *sc)
  295 {
  296         int status;
  297 
  298         status = bus_read_1(sc->io_res, PIIX4_SMBSLVSTS);
  299         if (status & PIIX4_SMBSLVSTS_BUSY)
  300                 return (1);
  301         if (status & PIIX4_SMBSLVSTS_ALART)
  302                 intsmb_alrintr(sc);
  303         else if (status & ~(PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2
  304                 | PIIX4_SMBSLVSTS_SDW1)) {
  305         }
  306 
  307         /* Reset Status Register */
  308         bus_write_1(sc->io_res, PIIX4_SMBSLVSTS,
  309             PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 |
  310             PIIX4_SMBSLVSTS_SDW1 | PIIX4_SMBSLVSTS_SLV);
  311         return (0);
  312 }
  313 
  314 static void
  315 intsmb_alrintr(struct intsmb_softc *sc)
  316 {
  317         int slvcnt;
  318 #ifdef ENABLE_ALART
  319         int error;
  320         uint8_t addr;
  321 #endif
  322 
  323         /* Stop generating INTR from ALART. */
  324         slvcnt = bus_read_1(sc->io_res, PIIX4_SMBSLVCNT);
  325 #ifdef ENABLE_ALART
  326         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
  327             slvcnt & ~PIIX4_SMBSLVCNT_ALTEN);
  328 #endif
  329         DELAY(5);
  330 
  331         /* Ask bus who asserted it and then ask it what's the matter. */
  332 #ifdef ENABLE_ALART
  333         error = intsmb_free(sc);
  334         if (error)
  335                 return;
  336 
  337         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, SMBALTRESP | LSB);
  338         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 1);
  339         error = intsmb_stop_poll(sc);
  340         if (error)
  341                 device_printf(sc->dev, "ALART: ERROR\n");
  342         else {
  343                 addr = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  344                 device_printf(sc->dev, "ALART_RESPONSE: 0x%x\n", addr);
  345         }
  346 
  347         /* Re-enable INTR from ALART. */
  348         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
  349             slvcnt | PIIX4_SMBSLVCNT_ALTEN);
  350         DELAY(5);
  351 #endif
  352 }
  353 
  354 static void
  355 intsmb_start(struct intsmb_softc *sc, unsigned char cmd, int nointr)
  356 {
  357         unsigned char tmp;
  358 
  359         INTSMB_LOCK_ASSERT(sc);
  360         tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  361         tmp &= 0xe0;
  362         tmp |= cmd;
  363         tmp |= PIIX4_SMBHSTCNT_START;
  364 
  365         /* While not in autoconfiguration enable interrupts. */
  366         if (!cold || !nointr)
  367                 tmp |= PIIX4_SMBHSTCNT_INTREN;
  368         bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp);
  369 }
  370 
  371 static int
  372 intsmb_error(int status)
  373 {
  374         int error = 0;
  375 
  376         if (status & PIIX4_SMBHSTSTAT_ERR)
  377                 error |= SMB_EBUSERR;
  378         if (status & PIIX4_SMBHSTSTAT_BUSC)
  379                 error |= SMB_ECOLLI;
  380         if (status & PIIX4_SMBHSTSTAT_FAIL)
  381                 error |= SMB_ENOACK;
  382         return (error);
  383 }
  384 
  385 /*
  386  * Polling Code.
  387  *
  388  * Polling is not encouraged because it requires waiting for the
  389  * device if it is busy.
  390  * (29063505.pdf from Intel) But during boot, interrupt cannot be used, so use
  391  * polling code then.
  392  */
  393 static int
  394 intsmb_stop_poll(struct intsmb_softc *sc)
  395 {
  396         int error, i, status, tmp;
  397 
  398         INTSMB_LOCK_ASSERT(sc);
  399 
  400         /* First, wait for busy to be set. */
  401         for (i = 0; i < 0x7fff; i++)
  402                 if (bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) &
  403                     PIIX4_SMBHSTSTAT_BUSY)
  404                         break;
  405 
  406         /* Wait for busy to clear. */
  407         for (i = 0; i < 0x7fff; i++) {
  408                 status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
  409                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
  410                         sc->isbusy = 0;
  411                         error = intsmb_error(status);
  412                         if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
  413                                 device_printf(sc->dev, "unknown cause why?");
  414                         return (error);
  415                 }
  416         }
  417 
  418         /* Timed out waiting for busy to clear. */
  419         sc->isbusy = 0;
  420         tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  421         bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp & ~PIIX4_SMBHSTCNT_INTREN);
  422         return (SMB_ETIMEOUT);
  423 }
  424 
  425 /*
  426  * Wait for completion and return result.
  427  */
  428 static int
  429 intsmb_stop(struct intsmb_softc *sc)
  430 {
  431         int error, status;
  432 
  433         INTSMB_LOCK_ASSERT(sc);
  434 
  435         if (cold)
  436                 /* So that it can use device during device probe on SMBus. */
  437                 return (intsmb_stop_poll(sc));
  438 
  439         error = msleep(sc, &sc->lock, PWAIT | PCATCH, "SMBWAI", hz / 8);
  440         if (error == 0) {
  441                 status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
  442                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
  443                         error = intsmb_error(status);
  444                         if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
  445                                 device_printf(sc->dev, "unknown cause why?\n");
  446 #ifdef ENABLE_ALART
  447                         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
  448                             PIIX4_SMBSLVCNT_ALTEN);
  449 #endif
  450                         return (error);
  451                 }
  452         }
  453 
  454         /* Timeout Procedure. */
  455         sc->isbusy = 0;
  456 
  457         /* Re-enable supressed interrupt from slave part. */
  458         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN);
  459         if (error == EWOULDBLOCK)
  460                 return (SMB_ETIMEOUT);
  461         else
  462                 return (SMB_EABORT);
  463 }
  464 
  465 static int
  466 intsmb_quick(device_t dev, u_char slave, int how)
  467 {
  468         struct intsmb_softc *sc = device_get_softc(dev);
  469         int error;
  470         u_char data;
  471 
  472         data = slave;
  473 
  474         /* Quick command is part of Address, I think. */
  475         switch(how) {
  476         case SMB_QWRITE:
  477                 data &= ~LSB;
  478                 break;
  479         case SMB_QREAD:
  480                 data |= LSB;
  481                 break;
  482         default:
  483                 return (EINVAL);
  484         }
  485 
  486         INTSMB_LOCK(sc);
  487         error = intsmb_free(sc);
  488         if (error) {
  489                 INTSMB_UNLOCK(sc);
  490                 return (error);
  491         }
  492         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, data);
  493         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_QUICK, 0);
  494         error = intsmb_stop(sc);
  495         INTSMB_UNLOCK(sc);
  496         return (error);
  497 }
  498 
  499 static int
  500 intsmb_sendb(device_t dev, u_char slave, char byte)
  501 {
  502         struct intsmb_softc *sc = device_get_softc(dev);
  503         int error;
  504 
  505         INTSMB_LOCK(sc);
  506         error = intsmb_free(sc);
  507         if (error) {
  508                 INTSMB_UNLOCK(sc);
  509                 return (error);
  510         }
  511         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  512         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, byte);
  513         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
  514         error = intsmb_stop(sc);
  515         INTSMB_UNLOCK(sc);
  516         return (error);
  517 }
  518 
  519 static int
  520 intsmb_recvb(device_t dev, u_char slave, char *byte)
  521 {
  522         struct intsmb_softc *sc = device_get_softc(dev);
  523         int error;
  524 
  525         INTSMB_LOCK(sc);
  526         error = intsmb_free(sc);
  527         if (error) {
  528                 INTSMB_UNLOCK(sc);
  529                 return (error);
  530         }
  531         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  532         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
  533         error = intsmb_stop(sc);
  534         if (error == 0) {
  535 #ifdef RECV_IS_IN_CMD
  536                 /*
  537                  * Linux SMBus stuff also troubles
  538                  * Because Intel's datasheet does not make clear.
  539                  */
  540                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTCMD);
  541 #else
  542                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  543 #endif
  544         }
  545         INTSMB_UNLOCK(sc);
  546         return (error);
  547 }
  548 
  549 static int
  550 intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  551 {
  552         struct intsmb_softc *sc = device_get_softc(dev);
  553         int error;
  554 
  555         INTSMB_LOCK(sc);
  556         error = intsmb_free(sc);
  557         if (error) {
  558                 INTSMB_UNLOCK(sc);
  559                 return (error);
  560         }
  561         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  562         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  563         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, byte);
  564         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
  565         error = intsmb_stop(sc);
  566         INTSMB_UNLOCK(sc);
  567         return (error);
  568 }
  569 
  570 static int
  571 intsmb_writew(device_t dev, u_char slave, char cmd, short word)
  572 {
  573         struct intsmb_softc *sc = device_get_softc(dev);
  574         int error;
  575 
  576         INTSMB_LOCK(sc);
  577         error = intsmb_free(sc);
  578         if (error) {
  579                 INTSMB_UNLOCK(sc);
  580                 return (error);
  581         }
  582         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  583         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  584         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, word & 0xff);
  585         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (word >> 8) & 0xff);
  586         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
  587         error = intsmb_stop(sc);
  588         INTSMB_UNLOCK(sc);
  589         return (error);
  590 }
  591 
  592 static int
  593 intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  594 {
  595         struct intsmb_softc *sc = device_get_softc(dev);
  596         int error;
  597 
  598         INTSMB_LOCK(sc);
  599         error = intsmb_free(sc);
  600         if (error) {
  601                 INTSMB_UNLOCK(sc);
  602                 return (error);
  603         }
  604         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  605         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  606         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
  607         error = intsmb_stop(sc);
  608         if (error == 0)
  609                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  610         INTSMB_UNLOCK(sc);
  611         return (error);
  612 }
  613 
  614 static int
  615 intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  616 {
  617         struct intsmb_softc *sc = device_get_softc(dev);
  618         int error;
  619 
  620         INTSMB_LOCK(sc);
  621         error = intsmb_free(sc);
  622         if (error) {
  623                 INTSMB_UNLOCK(sc);
  624                 return (error);
  625         }
  626         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  627         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  628         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
  629         error = intsmb_stop(sc);
  630         if (error == 0) {
  631                 *word = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  632                 *word |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8;
  633         }
  634         INTSMB_UNLOCK(sc);
  635         return (error);
  636 }
  637 
  638 /*
  639  * Data sheet claims that it implements all function, but also claims
  640  * that it implements 7 function and not mention PCALL. So I don't know
  641  * whether it will work.
  642  */
  643 static int
  644 intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
  645 {
  646 #ifdef PROCCALL_TEST
  647         struct intsmb_softc *sc = device_get_softc(dev);
  648         int error;
  649 
  650         INTSMB_LOCK(sc);
  651         error = intsmb_free(sc);
  652         if (error) {
  653                 INTSMB_UNLOCK(sc);
  654                 return (error);
  655         }
  656         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  657         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  658         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, sdata & 0xff);
  659         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (sdata & 0xff) >> 8);
  660         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
  661         error = intsmb_stop(sc);
  662         if (error == 0) {
  663                 *rdata = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  664                 *rdata |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8;
  665         }
  666         INTSMB_UNLOCK(sc);
  667         return (error);
  668 #else
  669         return (SMB_ENOTSUPP);
  670 #endif
  671 }
  672 
  673 static int
  674 intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  675 {
  676         struct intsmb_softc *sc = device_get_softc(dev);
  677         int error, i;
  678 
  679         if (count > SMBBLOCKTRANS_MAX || count == 0)
  680                 return (SMB_EINVAL);
  681 
  682         INTSMB_LOCK(sc);
  683         error = intsmb_free(sc);
  684         if (error) {
  685                 INTSMB_UNLOCK(sc);
  686                 return (error);
  687         }
  688 
  689         /* Reset internal array index. */
  690         bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  691 
  692         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  693         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  694         for (i = 0; i < count; i++)
  695                 bus_write_1(sc->io_res, PIIX4_SMBBLKDAT, buf[i]);
  696         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, count);
  697         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
  698         error = intsmb_stop(sc);
  699         INTSMB_UNLOCK(sc);
  700         return (error);
  701 }
  702 
  703 static int
  704 intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
  705 {
  706         struct intsmb_softc *sc = device_get_softc(dev);
  707         int error, i;
  708         u_char data, nread;
  709 
  710         if (*count > SMBBLOCKTRANS_MAX || *count == 0)
  711                 return (SMB_EINVAL);
  712 
  713         INTSMB_LOCK(sc);
  714         error = intsmb_free(sc);
  715         if (error) {
  716                 INTSMB_UNLOCK(sc);
  717                 return (error);
  718         }
  719 
  720         /* Reset internal array index. */
  721         bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  722 
  723         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  724         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  725         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, *count);
  726         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
  727         error = intsmb_stop(sc);
  728         if (error == 0) {
  729                 nread = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  730                 if (nread != 0 && nread <= SMBBLOCKTRANS_MAX) {
  731                         for (i = 0; i < nread; i++) {
  732                                 data = bus_read_1(sc->io_res, PIIX4_SMBBLKDAT);
  733                                 if (i < *count)
  734                                         buf[i] = data;
  735                         }
  736                         *count = nread;
  737                 } else
  738                         error = EIO;
  739         }
  740         INTSMB_UNLOCK(sc);
  741         return (error);
  742 }
  743 
  744 static devclass_t intsmb_devclass;
  745 
  746 static device_method_t intsmb_methods[] = {
  747         /* Device interface */
  748         DEVMETHOD(device_probe,         intsmb_probe),
  749         DEVMETHOD(device_attach,        intsmb_attach),
  750         DEVMETHOD(device_detach,        intsmb_detach),
  751 
  752         /* Bus interface */
  753         DEVMETHOD(bus_print_child,      bus_generic_print_child),
  754 
  755         /* SMBus interface */
  756         DEVMETHOD(smbus_callback,       intsmb_callback),
  757         DEVMETHOD(smbus_quick,          intsmb_quick),
  758         DEVMETHOD(smbus_sendb,          intsmb_sendb),
  759         DEVMETHOD(smbus_recvb,          intsmb_recvb),
  760         DEVMETHOD(smbus_writeb,         intsmb_writeb),
  761         DEVMETHOD(smbus_writew,         intsmb_writew),
  762         DEVMETHOD(smbus_readb,          intsmb_readb),
  763         DEVMETHOD(smbus_readw,          intsmb_readw),
  764         DEVMETHOD(smbus_pcall,          intsmb_pcall),
  765         DEVMETHOD(smbus_bwrite,         intsmb_bwrite),
  766         DEVMETHOD(smbus_bread,          intsmb_bread),
  767 
  768         { 0, 0 }
  769 };
  770 
  771 static driver_t intsmb_driver = {
  772         "intsmb",
  773         intsmb_methods,
  774         sizeof(struct intsmb_softc),
  775 };
  776 
  777 DRIVER_MODULE(intsmb, pci, intsmb_driver, intsmb_devclass, 0, 0);
  778 DRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, 0, 0);
  779 MODULE_DEPEND(intsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  780 MODULE_VERSION(intsmb, 1);

Cache object: 7360f6bfa3350d68f21a0eb8415eb856


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