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-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
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         sc->dev = dev;
  114 
  115         mtx_init(&sc->lock, device_get_nameunit(dev), "intsmb", MTX_DEF);
  116 
  117         rid = PCI_BASE_ADDR_SMB;
  118         sc->io_res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid,
  119             RF_ACTIVE);
  120         if (sc->io_res == NULL) {
  121                 device_printf(dev, "Could not allocate I/O space\n");
  122                 error = ENXIO;
  123                 goto fail;
  124         }
  125 
  126 #ifndef NO_CHANGE_PCICONF
  127         pci_write_config(dev, PCIR_INTLINE, 0x9, 1);
  128         pci_write_config(dev, PCI_HST_CFG_SMB,
  129             PCI_INTR_SMB_IRQ9 | PCI_INTR_SMB_ENABLE, 1);
  130 #endif
  131         value = pci_read_config(dev, PCI_HST_CFG_SMB, 1);
  132         switch (value & 0xe) {
  133         case PCI_INTR_SMB_SMI:
  134                 str = "SMI";
  135                 break;
  136         case PCI_INTR_SMB_IRQ9:
  137                 str = "IRQ 9";
  138                 break;
  139         default:
  140                 str = "BOGUS";
  141         }
  142         device_printf(dev, "intr %s %s ", str,
  143             (value & 1) ? "enabled" : "disabled");
  144         printf("revision %d\n", pci_read_config(dev, PCI_REVID_SMB, 1));
  145 
  146         if ((value & 0xe) != PCI_INTR_SMB_IRQ9) {
  147                 device_printf(dev, "Unsupported interrupt mode\n");
  148                 error = ENXIO;
  149                 goto fail;
  150         }
  151 
  152         /* Force IRQ 9. */
  153         rid = 0;
  154         bus_set_resource(dev, SYS_RES_IRQ, rid, 9, 1);
  155         sc->irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
  156             RF_SHAREABLE | RF_ACTIVE);
  157         if (sc->irq_res == NULL) {
  158                 device_printf(dev, "Could not allocate irq\n");
  159                 error = ENXIO;
  160                 goto fail;
  161         }
  162 
  163         error = bus_setup_intr(dev, sc->irq_res, INTR_TYPE_MISC, NULL, 
  164             intsmb_rawintr, sc, &sc->irq_hand);
  165         if (error) {
  166                 device_printf(dev, "Failed to map intr\n");
  167                 goto fail;
  168         }
  169 
  170         value = pci_read_config(dev, PCI_BASE_ADDR_PM, 4);
  171         device_printf(dev, "PM %s %x\n", (value & 1) ? "I/O mapped" : "Memory",
  172             value & 0xfffe);
  173 
  174         sc->isbusy = 0;
  175         sc->smbus = device_add_child(dev, "smbus", -1);
  176         if (sc->smbus == NULL) {
  177                 error = ENXIO;
  178                 goto fail;
  179         }
  180         error = device_probe_and_attach(sc->smbus);
  181         if (error)
  182                 goto fail;
  183 
  184 #ifdef ENABLE_ALART
  185         /* Enable Arart */
  186         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN);
  187 #endif
  188         return (0);
  189 
  190 fail:
  191         intsmb_detach(dev);
  192         return (error);
  193 }
  194 
  195 static int
  196 intsmb_detach(device_t dev)
  197 {
  198         struct intsmb_softc *sc = device_get_softc(dev);
  199         int error;
  200 
  201         error = bus_generic_detach(dev);
  202         if (error)
  203                 return (error);
  204 
  205         if (sc->smbus)
  206                 device_delete_child(dev, sc->smbus);
  207         if (sc->irq_hand)
  208                 bus_teardown_intr(dev, sc->irq_res, sc->irq_hand);
  209         if (sc->irq_res)
  210                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->irq_res);
  211         if (sc->io_res)
  212                 bus_release_resource(dev, SYS_RES_IOPORT, PCI_BASE_ADDR_SMB,
  213                     sc->io_res);
  214         mtx_destroy(&sc->lock);
  215         return (0);
  216 }
  217 
  218 static void
  219 intsmb_rawintr(void *arg)
  220 {
  221         struct intsmb_softc *sc = arg;
  222 
  223         INTSMB_LOCK(sc);
  224         intsmb_intr(sc);
  225         intsmb_slvintr(sc);
  226         INTSMB_UNLOCK(sc);
  227 }
  228 
  229 static int
  230 intsmb_callback(device_t dev, int index, void *data)
  231 {
  232         int error = 0;
  233 
  234         switch (index) {
  235         case SMB_REQUEST_BUS:
  236                 break;
  237         case SMB_RELEASE_BUS:
  238                 break;
  239         default:
  240                 error = EINVAL;
  241         }
  242 
  243         return (error);
  244 }
  245 
  246 /* Counterpart of smbtx_smb_free(). */
  247 static int
  248 intsmb_free(struct intsmb_softc *sc)
  249 {
  250 
  251         INTSMB_LOCK_ASSERT(sc);
  252         if ((bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) & PIIX4_SMBHSTSTAT_BUSY) ||
  253 #ifdef ENABLE_ALART
  254             (bus_read_1(sc->io_res, PIIX4_SMBSLVSTS) & PIIX4_SMBSLVSTS_BUSY) ||
  255 #endif
  256             sc->isbusy)
  257                 return (SMB_EBUSY);
  258 
  259         sc->isbusy = 1;
  260         /* Disable Interrupt in slave part. */
  261 #ifndef ENABLE_ALART
  262         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, 0);
  263 #endif
  264         /* Reset INTR Flag to prepare INTR. */
  265         bus_write_1(sc->io_res, PIIX4_SMBHSTSTS,
  266             PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
  267             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL);
  268         return (0);
  269 }
  270 
  271 static int
  272 intsmb_intr(struct intsmb_softc *sc)
  273 {
  274         int status, tmp;
  275 
  276         status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
  277         if (status & PIIX4_SMBHSTSTAT_BUSY)
  278                 return (1);
  279 
  280         if (status & (PIIX4_SMBHSTSTAT_INTR | PIIX4_SMBHSTSTAT_ERR |
  281             PIIX4_SMBHSTSTAT_BUSC | PIIX4_SMBHSTSTAT_FAIL)) {
  282 
  283                 tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  284                 bus_write_1(sc->io_res, PIIX4_SMBHSTCNT,
  285                     tmp & ~PIIX4_SMBHSTCNT_INTREN);
  286                 if (sc->isbusy) {
  287                         sc->isbusy = 0;
  288                         wakeup(sc);
  289                 }
  290                 return (0);
  291         }
  292         return (1); /* Not Completed */
  293 }
  294 
  295 static int
  296 intsmb_slvintr(struct intsmb_softc *sc)
  297 {
  298         int status;
  299 
  300         status = bus_read_1(sc->io_res, PIIX4_SMBSLVSTS);
  301         if (status & PIIX4_SMBSLVSTS_BUSY)
  302                 return (1);
  303         if (status & PIIX4_SMBSLVSTS_ALART)
  304                 intsmb_alrintr(sc);
  305         else if (status & ~(PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2
  306                 | PIIX4_SMBSLVSTS_SDW1)) {
  307         }
  308 
  309         /* Reset Status Register */
  310         bus_write_1(sc->io_res, PIIX4_SMBSLVSTS,
  311             PIIX4_SMBSLVSTS_ALART | PIIX4_SMBSLVSTS_SDW2 |
  312             PIIX4_SMBSLVSTS_SDW1 | PIIX4_SMBSLVSTS_SLV);
  313         return (0);
  314 }
  315 
  316 static void
  317 intsmb_alrintr(struct intsmb_softc *sc)
  318 {
  319         int slvcnt;
  320 #ifdef ENABLE_ALART
  321         int error;
  322         uint8_t addr;
  323 #endif
  324 
  325         /* Stop generating INTR from ALART. */
  326         slvcnt = bus_read_1(sc->io_res, PIIX4_SMBSLVCNT);
  327 #ifdef ENABLE_ALART
  328         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
  329             slvcnt & ~PIIX4_SMBSLVCNT_ALTEN);
  330 #endif
  331         DELAY(5);
  332 
  333         /* Ask bus who asserted it and then ask it what's the matter. */
  334 #ifdef ENABLE_ALART
  335         error = intsmb_free(sc);
  336         if (error)
  337                 return;
  338 
  339         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, SMBALTRESP | LSB);
  340         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 1);
  341         error = intsmb_stop_poll(sc);
  342         if (error)
  343                 device_printf(sc->dev, "ALART: ERROR\n");
  344         else {
  345                 addr = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  346                 device_printf(sc->dev, "ALART_RESPONSE: 0x%x\n", addr);
  347         }
  348 
  349         /* Re-enable INTR from ALART. */
  350         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
  351             slvcnt | PIIX4_SMBSLVCNT_ALTEN);
  352         DELAY(5);
  353 #endif
  354 }
  355 
  356 static void
  357 intsmb_start(struct intsmb_softc *sc, unsigned char cmd, int nointr)
  358 {
  359         unsigned char tmp;
  360 
  361         INTSMB_LOCK_ASSERT(sc);
  362         tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  363         tmp &= 0xe0;
  364         tmp |= cmd;
  365         tmp |= PIIX4_SMBHSTCNT_START;
  366 
  367         /* While not in autoconfiguration enable interrupts. */
  368         if (!cold || !nointr)
  369                 tmp |= PIIX4_SMBHSTCNT_INTREN;
  370         bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp);
  371 }
  372 
  373 static int
  374 intsmb_error(int status)
  375 {
  376         int error = 0;
  377 
  378         if (status & PIIX4_SMBHSTSTAT_ERR)
  379                 error |= SMB_EBUSERR;
  380         if (status & PIIX4_SMBHSTSTAT_BUSC)
  381                 error |= SMB_ECOLLI;
  382         if (status & PIIX4_SMBHSTSTAT_FAIL)
  383                 error |= SMB_ENOACK;
  384         return (error);
  385 }
  386 
  387 /*
  388  * Polling Code.
  389  *
  390  * Polling is not encouraged because it requires waiting for the
  391  * device if it is busy.
  392  * (29063505.pdf from Intel) But during boot, interrupt cannot be used, so use
  393  * polling code then.
  394  */
  395 static int
  396 intsmb_stop_poll(struct intsmb_softc *sc)
  397 {
  398         int error, i, status, tmp;
  399 
  400         INTSMB_LOCK_ASSERT(sc);
  401 
  402         /* First, wait for busy to be set. */
  403         for (i = 0; i < 0x7fff; i++)
  404                 if (bus_read_1(sc->io_res, PIIX4_SMBHSTSTS) &
  405                     PIIX4_SMBHSTSTAT_BUSY)
  406                         break;
  407 
  408         /* Wait for busy to clear. */
  409         for (i = 0; i < 0x7fff; i++) {
  410                 status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
  411                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
  412                         sc->isbusy = 0;
  413                         error = intsmb_error(status);
  414                         if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
  415                                 device_printf(sc->dev, "unknown cause why?\n");
  416                         return (error);
  417                 }
  418         }
  419 
  420         /* Timed out waiting for busy to clear. */
  421         sc->isbusy = 0;
  422         tmp = bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  423         bus_write_1(sc->io_res, PIIX4_SMBHSTCNT, tmp & ~PIIX4_SMBHSTCNT_INTREN);
  424         return (SMB_ETIMEOUT);
  425 }
  426 
  427 /*
  428  * Wait for completion and return result.
  429  */
  430 static int
  431 intsmb_stop(struct intsmb_softc *sc)
  432 {
  433         int error, status;
  434 
  435         INTSMB_LOCK_ASSERT(sc);
  436 
  437         if (cold)
  438                 /* So that it can use device during device probe on SMBus. */
  439                 return (intsmb_stop_poll(sc));
  440 
  441         error = msleep(sc, &sc->lock, PWAIT | PCATCH, "SMBWAI", hz / 8);
  442         if (error == 0) {
  443                 status = bus_read_1(sc->io_res, PIIX4_SMBHSTSTS);
  444                 if (!(status & PIIX4_SMBHSTSTAT_BUSY)) {
  445                         error = intsmb_error(status);
  446                         if (error == 0 && !(status & PIIX4_SMBHSTSTAT_INTR))
  447                                 device_printf(sc->dev, "unknown cause why?\n");
  448 #ifdef ENABLE_ALART
  449                         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT,
  450                             PIIX4_SMBSLVCNT_ALTEN);
  451 #endif
  452                         return (error);
  453                 }
  454         }
  455 
  456         /* Timeout Procedure. */
  457         sc->isbusy = 0;
  458 
  459         /* Re-enable supressed interrupt from slave part. */
  460         bus_write_1(sc->io_res, PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN);
  461         if (error == EWOULDBLOCK)
  462                 return (SMB_ETIMEOUT);
  463         else
  464                 return (SMB_EABORT);
  465 }
  466 
  467 static int
  468 intsmb_quick(device_t dev, u_char slave, int how)
  469 {
  470         struct intsmb_softc *sc = device_get_softc(dev);
  471         int error;
  472         u_char data;
  473 
  474         data = slave;
  475 
  476         /* Quick command is part of Address, I think. */
  477         switch(how) {
  478         case SMB_QWRITE:
  479                 data &= ~LSB;
  480                 break;
  481         case SMB_QREAD:
  482                 data |= LSB;
  483                 break;
  484         default:
  485                 return (EINVAL);
  486         }
  487 
  488         INTSMB_LOCK(sc);
  489         error = intsmb_free(sc);
  490         if (error) {
  491                 INTSMB_UNLOCK(sc);
  492                 return (error);
  493         }
  494         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, data);
  495         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_QUICK, 0);
  496         error = intsmb_stop(sc);
  497         INTSMB_UNLOCK(sc);
  498         return (error);
  499 }
  500 
  501 static int
  502 intsmb_sendb(device_t dev, u_char slave, char byte)
  503 {
  504         struct intsmb_softc *sc = device_get_softc(dev);
  505         int error;
  506 
  507         INTSMB_LOCK(sc);
  508         error = intsmb_free(sc);
  509         if (error) {
  510                 INTSMB_UNLOCK(sc);
  511                 return (error);
  512         }
  513         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  514         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, byte);
  515         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
  516         error = intsmb_stop(sc);
  517         INTSMB_UNLOCK(sc);
  518         return (error);
  519 }
  520 
  521 static int
  522 intsmb_recvb(device_t dev, u_char slave, char *byte)
  523 {
  524         struct intsmb_softc *sc = device_get_softc(dev);
  525         int error;
  526 
  527         INTSMB_LOCK(sc);
  528         error = intsmb_free(sc);
  529         if (error) {
  530                 INTSMB_UNLOCK(sc);
  531                 return (error);
  532         }
  533         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  534         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BYTE, 0);
  535         error = intsmb_stop(sc);
  536         if (error == 0) {
  537 #ifdef RECV_IS_IN_CMD
  538                 /*
  539                  * Linux SMBus stuff also troubles
  540                  * Because Intel's datasheet does not make clear.
  541                  */
  542                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTCMD);
  543 #else
  544                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  545 #endif
  546         }
  547         INTSMB_UNLOCK(sc);
  548         return (error);
  549 }
  550 
  551 static int
  552 intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  553 {
  554         struct intsmb_softc *sc = device_get_softc(dev);
  555         int error;
  556 
  557         INTSMB_LOCK(sc);
  558         error = intsmb_free(sc);
  559         if (error) {
  560                 INTSMB_UNLOCK(sc);
  561                 return (error);
  562         }
  563         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  564         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  565         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, byte);
  566         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
  567         error = intsmb_stop(sc);
  568         INTSMB_UNLOCK(sc);
  569         return (error);
  570 }
  571 
  572 static int
  573 intsmb_writew(device_t dev, u_char slave, char cmd, short word)
  574 {
  575         struct intsmb_softc *sc = device_get_softc(dev);
  576         int error;
  577 
  578         INTSMB_LOCK(sc);
  579         error = intsmb_free(sc);
  580         if (error) {
  581                 INTSMB_UNLOCK(sc);
  582                 return (error);
  583         }
  584         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  585         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  586         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, word & 0xff);
  587         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (word >> 8) & 0xff);
  588         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
  589         error = intsmb_stop(sc);
  590         INTSMB_UNLOCK(sc);
  591         return (error);
  592 }
  593 
  594 static int
  595 intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  596 {
  597         struct intsmb_softc *sc = device_get_softc(dev);
  598         int error;
  599 
  600         INTSMB_LOCK(sc);
  601         error = intsmb_free(sc);
  602         if (error) {
  603                 INTSMB_UNLOCK(sc);
  604                 return (error);
  605         }
  606         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  607         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  608         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BDATA, 0);
  609         error = intsmb_stop(sc);
  610         if (error == 0)
  611                 *byte = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  612         INTSMB_UNLOCK(sc);
  613         return (error);
  614 }
  615 
  616 static int
  617 intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  618 {
  619         struct intsmb_softc *sc = device_get_softc(dev);
  620         int error;
  621 
  622         INTSMB_LOCK(sc);
  623         error = intsmb_free(sc);
  624         if (error) {
  625                 INTSMB_UNLOCK(sc);
  626                 return (error);
  627         }
  628         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  629         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  630         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
  631         error = intsmb_stop(sc);
  632         if (error == 0) {
  633                 *word = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  634                 *word |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8;
  635         }
  636         INTSMB_UNLOCK(sc);
  637         return (error);
  638 }
  639 
  640 /*
  641  * Data sheet claims that it implements all function, but also claims
  642  * that it implements 7 function and not mention PCALL. So I don't know
  643  * whether it will work.
  644  */
  645 static int
  646 intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
  647 {
  648 #ifdef PROCCALL_TEST
  649         struct intsmb_softc *sc = device_get_softc(dev);
  650         int error;
  651 
  652         INTSMB_LOCK(sc);
  653         error = intsmb_free(sc);
  654         if (error) {
  655                 INTSMB_UNLOCK(sc);
  656                 return (error);
  657         }
  658         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  659         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  660         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, sdata & 0xff);
  661         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT1, (sdata & 0xff) >> 8);
  662         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_WDATA, 0);
  663         error = intsmb_stop(sc);
  664         if (error == 0) {
  665                 *rdata = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  666                 *rdata |= bus_read_1(sc->io_res, PIIX4_SMBHSTDAT1) << 8;
  667         }
  668         INTSMB_UNLOCK(sc);
  669         return (error);
  670 #else
  671         return (SMB_ENOTSUPP);
  672 #endif
  673 }
  674 
  675 static int
  676 intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  677 {
  678         struct intsmb_softc *sc = device_get_softc(dev);
  679         int error, i;
  680 
  681         if (count > SMBBLOCKTRANS_MAX || count == 0)
  682                 return (SMB_EINVAL);
  683 
  684         INTSMB_LOCK(sc);
  685         error = intsmb_free(sc);
  686         if (error) {
  687                 INTSMB_UNLOCK(sc);
  688                 return (error);
  689         }
  690 
  691         /* Reset internal array index. */
  692         bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  693 
  694         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave & ~LSB);
  695         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  696         for (i = 0; i < count; i++)
  697                 bus_write_1(sc->io_res, PIIX4_SMBBLKDAT, buf[i]);
  698         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, count);
  699         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
  700         error = intsmb_stop(sc);
  701         INTSMB_UNLOCK(sc);
  702         return (error);
  703 }
  704 
  705 static int
  706 intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf)
  707 {
  708         struct intsmb_softc *sc = device_get_softc(dev);
  709         int error, i;
  710         u_char data, nread;
  711 
  712         if (*count > SMBBLOCKTRANS_MAX || *count == 0)
  713                 return (SMB_EINVAL);
  714 
  715         INTSMB_LOCK(sc);
  716         error = intsmb_free(sc);
  717         if (error) {
  718                 INTSMB_UNLOCK(sc);
  719                 return (error);
  720         }
  721 
  722         /* Reset internal array index. */
  723         bus_read_1(sc->io_res, PIIX4_SMBHSTCNT);
  724 
  725         bus_write_1(sc->io_res, PIIX4_SMBHSTADD, slave | LSB);
  726         bus_write_1(sc->io_res, PIIX4_SMBHSTCMD, cmd);
  727         bus_write_1(sc->io_res, PIIX4_SMBHSTDAT0, *count);
  728         intsmb_start(sc, PIIX4_SMBHSTCNT_PROT_BLOCK, 0);
  729         error = intsmb_stop(sc);
  730         if (error == 0) {
  731                 nread = bus_read_1(sc->io_res, PIIX4_SMBHSTDAT0);
  732                 if (nread != 0 && nread <= SMBBLOCKTRANS_MAX) {
  733                         for (i = 0; i < nread; i++) {
  734                                 data = bus_read_1(sc->io_res, PIIX4_SMBBLKDAT);
  735                                 if (i < *count)
  736                                         buf[i] = data;
  737                         }
  738                         *count = nread;
  739                 } else
  740                         error = EIO;
  741         }
  742         INTSMB_UNLOCK(sc);
  743         return (error);
  744 }
  745 
  746 static devclass_t intsmb_devclass;
  747 
  748 static device_method_t intsmb_methods[] = {
  749         /* Device interface */
  750         DEVMETHOD(device_probe,         intsmb_probe),
  751         DEVMETHOD(device_attach,        intsmb_attach),
  752         DEVMETHOD(device_detach,        intsmb_detach),
  753 
  754         /* Bus interface */
  755         DEVMETHOD(bus_print_child,      bus_generic_print_child),
  756 
  757         /* SMBus interface */
  758         DEVMETHOD(smbus_callback,       intsmb_callback),
  759         DEVMETHOD(smbus_quick,          intsmb_quick),
  760         DEVMETHOD(smbus_sendb,          intsmb_sendb),
  761         DEVMETHOD(smbus_recvb,          intsmb_recvb),
  762         DEVMETHOD(smbus_writeb,         intsmb_writeb),
  763         DEVMETHOD(smbus_writew,         intsmb_writew),
  764         DEVMETHOD(smbus_readb,          intsmb_readb),
  765         DEVMETHOD(smbus_readw,          intsmb_readw),
  766         DEVMETHOD(smbus_pcall,          intsmb_pcall),
  767         DEVMETHOD(smbus_bwrite,         intsmb_bwrite),
  768         DEVMETHOD(smbus_bread,          intsmb_bread),
  769 
  770         { 0, 0 }
  771 };
  772 
  773 static driver_t intsmb_driver = {
  774         "intsmb",
  775         intsmb_methods,
  776         sizeof(struct intsmb_softc),
  777 };
  778 
  779 DRIVER_MODULE(intsmb, pci, intsmb_driver, intsmb_devclass, 0, 0);
  780 DRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, 0, 0);
  781 MODULE_DEPEND(intsmb, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  782 MODULE_VERSION(intsmb, 1);

Cache object: 63241df19ab73a21b4e4042b98034812


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