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: releng/6.1/sys/pci/intpm.c 146734 2005-05-29 04:42:30Z nyan $");
   29 
   30 #include <sys/param.h>
   31 #include <sys/systm.h>
   32 #include <sys/kernel.h>
   33 #include <machine/bus.h>
   34 
   35 #include <sys/uio.h>
   36 #include <sys/module.h>
   37 #include <sys/bus.h>
   38 #include <sys/rman.h>
   39 #include <machine/resource.h>
   40 #include <dev/smbus/smbconf.h>
   41 
   42 #include "smbus_if.h"
   43 
   44 /*This should be removed if force_pci_map_int supported*/
   45 #include <sys/interrupt.h>
   46 
   47 #include <dev/pci/pcireg.h>
   48 #include <dev/pci/pcivar.h>
   49 #include <pci/intpmreg.h>
   50 
   51 #include "opt_intpm.h"
   52 
   53 static struct _pcsid
   54 {
   55         u_int32_t type;
   56         char    *desc;
   57 } pci_ids[] =
   58 {
   59         { 0x71138086,"Intel 82371AB Power management controller"},
   60         { 0x719b8086,"Intel 82443MX Power management controller"},
   61 #if 0
   62         /* Not a good idea yet, this stops isab0 functioning */
   63         { 0x02001166,"ServerWorks OSB4 PCI to ISA Bridge"},
   64 #endif
   65         
   66         { 0x00000000,   NULL                                    }
   67 };
   68 static int intsmb_probe(device_t);
   69 static int intsmb_attach(device_t);
   70 
   71 static int intsmb_intr(device_t dev);
   72 static int intsmb_slvintr(device_t dev);
   73 static void  intsmb_alrintr(device_t dev);
   74 static int intsmb_callback(device_t dev, int index, caddr_t data);
   75 static int intsmb_quick(device_t dev, u_char slave, int how);
   76 static int intsmb_sendb(device_t dev, u_char slave, char byte);
   77 static int intsmb_recvb(device_t dev, u_char slave, char *byte);
   78 static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
   79 static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
   80 static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
   81 static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
   82 static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
   83 static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
   84 static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
   85 static void intsmb_start(device_t dev,u_char cmd,int nointr);
   86 static int intsmb_stop(device_t dev);
   87 static int intsmb_stop_poll(device_t dev);
   88 static int intsmb_free(device_t dev);
   89 static int intpm_probe (device_t dev);
   90 static int intpm_attach (device_t dev);
   91 static devclass_t intsmb_devclass;
   92 
   93 static device_method_t intpm_methods[]={
   94         DEVMETHOD(device_probe,intsmb_probe),
   95         DEVMETHOD(device_attach,intsmb_attach),
   96 
   97         DEVMETHOD(bus_print_child, bus_generic_print_child),
   98         
   99         DEVMETHOD(smbus_callback,intsmb_callback),
  100         DEVMETHOD(smbus_quick,intsmb_quick),
  101         DEVMETHOD(smbus_sendb,intsmb_sendb),
  102         DEVMETHOD(smbus_recvb,intsmb_recvb),
  103         DEVMETHOD(smbus_writeb,intsmb_writeb),
  104         DEVMETHOD(smbus_writew,intsmb_writew),
  105         DEVMETHOD(smbus_readb,intsmb_readb),
  106         DEVMETHOD(smbus_readw,intsmb_readw),
  107         DEVMETHOD(smbus_pcall,intsmb_pcall),
  108         DEVMETHOD(smbus_bwrite,intsmb_bwrite),
  109         DEVMETHOD(smbus_bread,intsmb_bread),
  110         {0,0}
  111 };
  112 
  113 struct intpm_pci_softc{
  114         bus_space_tag_t smbst;
  115         bus_space_handle_t smbsh;
  116         bus_space_tag_t pmst;
  117         bus_space_handle_t pmsh;
  118         device_t  smbus;
  119 };
  120 
  121 
  122 struct intsmb_softc{
  123         struct intpm_pci_softc *pci_sc;
  124         bus_space_tag_t st;
  125         bus_space_handle_t sh;
  126         device_t smbus;
  127         int isbusy;
  128 };
  129 
  130 static driver_t intpm_driver = {
  131         "intsmb",
  132         intpm_methods,
  133         sizeof(struct intsmb_softc),
  134 };
  135 
  136 static devclass_t intpm_devclass;
  137 static device_method_t intpm_pci_methods[] = {
  138   DEVMETHOD(device_probe,intpm_probe),
  139   DEVMETHOD(device_attach,intpm_attach),
  140   {0,0}
  141 };
  142 static driver_t intpm_pci_driver = {
  143   "intpm",
  144   intpm_pci_methods,
  145   sizeof(struct intpm_pci_softc)
  146 };
  147 
  148 static int 
  149 intsmb_probe(device_t dev)
  150 {
  151         struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
  152         sc->smbus=device_add_child(dev, "smbus", -1);
  153         if (!sc->smbus)
  154                 return (EINVAL);    /* XXX don't know what to return else */
  155         device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
  156         
  157         return (BUS_PROBE_DEFAULT); /* XXX don't know what to return else */
  158 }
  159 static int
  160 intsmb_attach(device_t dev)
  161 {
  162         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  163         sc->pci_sc=device_get_softc(device_get_parent(dev));
  164         sc->isbusy=0;
  165         sc->sh=sc->pci_sc->smbsh;
  166         sc->st=sc->pci_sc->smbst;
  167         sc->pci_sc->smbus=dev;
  168         device_probe_and_attach(sc->smbus);
  169 #ifdef ENABLE_ALART
  170         /*Enable Arart*/
  171         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
  172                           PIIX4_SMBSLVCNT_ALTEN);
  173 #endif 
  174         return (0);
  175 }
  176 
  177 static int 
  178 intsmb_callback(device_t dev, int index, caddr_t data)
  179 {
  180         int error = 0;
  181         intrmask_t s;
  182         s=splnet();
  183         switch (index) {
  184         case SMB_REQUEST_BUS:
  185                 break;
  186         case SMB_RELEASE_BUS:
  187                 break;
  188         default:
  189                 error = EINVAL;
  190         }
  191         splx(s);
  192         return (error);
  193 }
  194 /*counterpart of smbtx_smb_free*/
  195 static        int
  196 intsmb_free(device_t dev){
  197         intrmask_t s;
  198         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  199         if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)&
  200             PIIX4_SMBHSTSTAT_BUSY)
  201 #ifdef ENABLE_ALART
  202            ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)&
  203               PIIX4_SMBSLVSTS_BUSY)
  204 #endif
  205            || sc->isbusy)
  206                 return EBUSY;
  207         s=splhigh();
  208         sc->isbusy=1;
  209         /*Disable Intrrupt in slave part*/
  210 #ifndef ENABLE_ALART
  211         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0);
  212 #endif
  213         /*Reset INTR Flag to prepare INTR*/
  214         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS,
  215                           (PIIX4_SMBHSTSTAT_INTR|
  216                            PIIX4_SMBHSTSTAT_ERR|
  217                            PIIX4_SMBHSTSTAT_BUSC|
  218                            PIIX4_SMBHSTSTAT_FAIL)
  219                 );
  220         splx(s);
  221         return 0;
  222 }
  223 
  224 static int
  225 intsmb_intr(device_t dev)
  226 {
  227         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  228         int status;
  229         status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
  230         if(status&PIIX4_SMBHSTSTAT_BUSY){
  231                 return 1;
  232                 
  233         }
  234         if(status&(PIIX4_SMBHSTSTAT_INTR|
  235                                 PIIX4_SMBHSTSTAT_ERR|
  236                                 PIIX4_SMBHSTSTAT_BUSC|
  237                                 PIIX4_SMBHSTSTAT_FAIL)){
  238                 int tmp;
  239                 tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
  240                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
  241                                   tmp&~PIIX4_SMBHSTCNT_INTREN);
  242                 if(sc->isbusy){
  243                   sc->isbusy=0;
  244                   wakeup(sc);
  245                 }
  246                 return 0;
  247         }
  248         return 1;/* Not Completed*/
  249 }
  250 static int
  251 intsmb_slvintr(device_t dev)
  252 {
  253         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  254         int status,retval;
  255         retval=1;
  256         status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS);
  257         if(status&PIIX4_SMBSLVSTS_BUSY)
  258                 return retval;
  259         if(status&PIIX4_SMBSLVSTS_ALART){
  260                 intsmb_alrintr(dev);
  261                 retval=0;
  262         }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2
  263                           |PIIX4_SMBSLVSTS_SDW1)){
  264                 retval=0;
  265         }
  266         /*Reset Status Register*/
  267         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART|
  268                           PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1|
  269                           PIIX4_SMBSLVSTS_SLV);
  270         return retval;
  271 }
  272 
  273 static void intsmb_alrintr(device_t dev)
  274 {
  275         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  276         int slvcnt;
  277 #ifdef ENABLE_ALART
  278         int error;
  279 #endif
  280 
  281         /*stop generating INTR from ALART*/
  282         slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT);
  283 #ifdef ENABLE_ALART
  284         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
  285                           slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ;
  286 #endif
  287         DELAY(5);
  288         /*ask bus who assert it and then ask it what's the matter. */   
  289 #ifdef ENABLE_ALART
  290         error=intsmb_free(dev);
  291         if(!error){
  292                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP
  293                                   |LSB);
  294                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1);
  295                 if(!(error=intsmb_stop_poll(dev))){
  296                         u_int8_t addr;
  297                         addr=bus_space_read_1(sc->st,sc->sh,
  298                                               PIIX4_SMBHSTDAT0);
  299                         printf("ALART_RESPONSE: 0x%x\n", addr);
  300                 }
  301         }else{
  302                 printf("ERROR\n");
  303         }
  304 
  305         /*Re-enable INTR from ALART*/
  306         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
  307                           slvcnt|PIIX4_SMBSLVCNT_ALTEN) ;
  308         DELAY(5);
  309 #endif
  310 
  311         return;
  312 }
  313 static void
  314 intsmb_start(device_t dev,unsigned char cmd,int nointr)
  315 {
  316         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  317         unsigned char tmp;
  318         tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
  319         tmp&= 0xe0;
  320         tmp |= cmd;
  321         tmp |=PIIX4_SMBHSTCNT_START;
  322         /*While not in autoconfiguration Intrrupt Enabled*/
  323         if(!cold||!nointr)
  324                 tmp |=PIIX4_SMBHSTCNT_INTREN;
  325         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp);
  326 }
  327 
  328 /*Polling Code. Polling is not encouraged 
  329  * because It is required to wait for the device get busy.
  330  *(29063505.pdf from Intel)
  331  * But during boot,intrrupt cannot be used.
  332  * so use polling code while in autoconfiguration.
  333  */
  334 
  335 static        int
  336 intsmb_stop_poll(device_t dev){
  337         int error,i;
  338         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  339         
  340         /*
  341          *  In smbtx driver ,Simply waiting.
  342          *  This loops 100-200 times.
  343          */
  344         for(i=0;i<0x7fff;i++){
  345                 if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)
  346                     &PIIX4_SMBHSTSTAT_BUSY)){
  347                         break;
  348                 }
  349         }
  350         for(i=0;i<0x7fff;i++){
  351                 int status;
  352                 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
  353                 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
  354                         sc->isbusy=0;
  355                         error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
  356                                 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
  357                                 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
  358                         if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
  359                                 printf("unknown cause why?");
  360                         }
  361                         return error;
  362                 }
  363         }
  364         {
  365           int tmp;
  366           sc->isbusy=0;
  367           tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
  368           bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
  369                             tmp&~PIIX4_SMBHSTCNT_INTREN);
  370         }
  371         return EIO;
  372 }
  373 /*
  374  *wait for completion and return result.
  375  */
  376 static        int
  377 intsmb_stop(device_t dev){
  378         int error;
  379         intrmask_t s;
  380         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  381         if(cold){
  382                 /*So that it can use device during probing device on SMBus.*/
  383                 error=intsmb_stop_poll(dev);
  384                 return error;
  385         }else{
  386                 if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){
  387                         int status;
  388                         status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
  389                         if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
  390                                 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
  391                                         (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
  392                                         (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
  393                                 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
  394                                         printf("intsmb%d:unknown cause why?\n",
  395                                                device_get_unit(dev));
  396                                 }
  397 #ifdef ENABLE_ALART
  398                                 bus_space_write_1(sc->st,sc->sh,
  399                                                   PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
  400 #endif
  401                                 return error;
  402                         }
  403                 }
  404         }
  405         /*Timeout Procedure*/
  406         s=splhigh();
  407         sc->isbusy=0;
  408         /*Re-enable supressed intrrupt from slave part*/
  409         bus_space_write_1(sc->st,sc->sh,
  410                           PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
  411         splx(s);
  412         return EIO;
  413 }
  414 
  415 static int
  416 intsmb_quick(device_t dev, u_char slave, int how)
  417 {
  418         int error=0;
  419         u_char data;
  420         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  421         data=slave;
  422         /*Quick command is part of Address, I think*/
  423         switch(how){
  424         case SMB_QWRITE:
  425                 data&=~LSB;
  426                 break;
  427         case SMB_QREAD:
  428                 data|=LSB;
  429                 break;
  430         default:
  431                 error=EINVAL;
  432         }
  433         if(!error){
  434                 error=intsmb_free(dev);
  435                 if(!error){
  436                         bus_space_write_1(sc->st,sc->sh,
  437                                           PIIX4_SMBHSTADD,data);
  438                         intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0);
  439                         error=intsmb_stop(dev);
  440                 }
  441         }
  442 
  443         return (error);
  444 }
  445 
  446 static int
  447 intsmb_sendb(device_t dev, u_char slave, char byte)
  448 {
  449         int error;
  450         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  451         error=intsmb_free(dev);
  452         if(!error){
  453                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
  454                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte);
  455                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
  456                 error=intsmb_stop(dev);
  457         }
  458         return (error);
  459 }
  460 static int
  461 intsmb_recvb(device_t dev, u_char slave, char *byte)
  462 {
  463         int error;
  464         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  465         error=intsmb_free(dev);
  466         if(!error){
  467                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave
  468                                   |LSB);
  469                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
  470                 if(!(error=intsmb_stop(dev))){
  471 #ifdef RECV_IS_IN_CMD
  472                         /*Linux SMBus stuff also troubles
  473                           Because Intel's datasheet will not make clear.
  474                          */
  475                         *byte=bus_space_read_1(sc->st,sc->sh,
  476                                                PIIX4_SMBHSTCMD);
  477 #else
  478                         *byte=bus_space_read_1(sc->st,sc->sh,
  479                                                PIIX4_SMBHSTDAT0);
  480 #endif
  481                 }
  482         }
  483         return (error);
  484 }
  485 static int
  486 intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
  487 {
  488         int error;
  489         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  490         error=intsmb_free(dev);
  491         if(!error){
  492                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
  493                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  494                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte);
  495                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
  496                 error=intsmb_stop(dev);
  497         }
  498         return (error);
  499 }
  500 static int
  501 intsmb_writew(device_t dev, u_char slave, char cmd, short word)
  502 {
  503         int error;
  504         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  505         error=intsmb_free(dev);
  506         if(!error){
  507                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
  508                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  509                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,
  510                                   word&0xff);
  511                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,
  512                                   (word>>8)&0xff);
  513                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
  514                 error=intsmb_stop(dev);
  515         }
  516         return (error);
  517 }
  518 
  519 static int
  520 intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
  521 {
  522         int error;
  523         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  524         error=intsmb_free(dev);
  525         if(!error){
  526                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
  527                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  528                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
  529                 if(!(error=intsmb_stop(dev))){
  530                         *byte=bus_space_read_1(sc->st,sc->sh,
  531                                                PIIX4_SMBHSTDAT0);
  532                 }
  533         }
  534         return (error);
  535 }
  536 static int
  537 intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
  538 {
  539         int error;
  540         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  541         error=intsmb_free(dev);
  542         if(!error){
  543                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
  544                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  545                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
  546                 if(!(error=intsmb_stop(dev))){
  547                         *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
  548                         *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
  549                 }
  550         }
  551         return (error);
  552 }
  553 /*
  554  * Data sheet claims that it implements all function, but also claims
  555  * that it implements 7 function and not mention PCALL. So I don't know
  556  * whether it will work.
  557  */
  558 static int
  559 intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
  560 {
  561 #ifdef PROCCALL_TEST
  562         int error;
  563         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  564         error=intsmb_free(dev);
  565         if(!error){
  566                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
  567                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  568                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff);
  569                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8);
  570                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
  571         }
  572         if(!(error=intsmb_stop(dev))){
  573                 *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
  574                 *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
  575         }
  576         return error;
  577 #else
  578         return 0;
  579 #endif
  580 }
  581 static int
  582 intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  583 {
  584         int error,i;
  585         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  586         error=intsmb_free(dev);
  587         if(count>SMBBLOCKTRANS_MAX||count==0)
  588                 error=EINVAL;
  589         if(!error){
  590                 /*Reset internal array index*/
  591                 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
  592                 
  593                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
  594                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  595                 for(i=0;i<count;i++){
  596                         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]);
  597                 }
  598                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
  599                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
  600                 error=intsmb_stop(dev);
  601         }
  602         return (error);
  603 }
  604 
  605 static int
  606 intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
  607 {
  608         int error,i;
  609         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
  610         error=intsmb_free(dev);
  611         if(count>SMBBLOCKTRANS_MAX||count==0)
  612                 error=EINVAL;
  613         if(!error){
  614                 /*Reset internal array index*/
  615                 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
  616                 
  617                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
  618                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
  619                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
  620                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
  621                 error=intsmb_stop(dev);
  622                 if(!error){
  623                         bzero(buf,count);/*Is it needed?*/
  624                         count= bus_space_read_1(sc->st,sc->sh,
  625                                                 PIIX4_SMBHSTDAT0);
  626                         if(count!=0&&count<=SMBBLOCKTRANS_MAX){
  627                                 for(i=0;i<count;i++){
  628                                         buf[i]=bus_space_read_1(sc->st,
  629                                                                 sc->sh,
  630                                                                 PIIX4_SMBBLKDAT);
  631                                 }
  632                         }
  633                         else{
  634                                 error=EIO;
  635                         }
  636                 }
  637         }
  638         return (error);
  639 }
  640 
  641 DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0);
  642 
  643 
  644 static void intpm_intr(void *arg);
  645 static int
  646 intpm_attach(device_t dev)
  647 {
  648         int value;
  649         int unit=device_get_unit(dev);
  650         void *ih;
  651         int error;
  652         char * str;
  653         {
  654                 struct intpm_pci_softc *sciic;
  655                 device_t smbinterface;
  656                 int rid;
  657                 struct resource *res;
  658 
  659                 sciic=device_get_softc(dev);
  660                 if(sciic==NULL){
  661                         return ENOMEM;
  662                 }
  663 
  664                 rid=PCI_BASE_ADDR_SMB;
  665                 res=bus_alloc_resource_any(dev,SYS_RES_IOPORT,&rid,RF_ACTIVE);
  666                 if(res==NULL){
  667                   device_printf(dev,"Could not allocate Bus space\n");
  668                   return ENXIO;
  669                 }
  670                 sciic->smbst=rman_get_bustag(res);
  671                 sciic->smbsh=rman_get_bushandle(res);
  672                 
  673 #ifdef __i386__
  674                 device_printf(dev,"%s %lx\n",
  675                               (sciic->smbst==I386_BUS_SPACE_IO)?
  676                               "I/O mapped":"Memory",
  677                               rman_get_start(res));
  678 #endif
  679                 
  680 
  681 #ifndef NO_CHANGE_PCICONF
  682                 pci_write_config(dev,PCIR_INTLINE,0x9,1);
  683                 pci_write_config(dev,PCI_HST_CFG_SMB,
  684                                  PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1);
  685 #endif
  686                 value=pci_read_config(dev,PCI_HST_CFG_SMB,1);
  687                 switch(value&0xe){
  688                 case PCI_INTR_SMB_SMI:
  689                         str="SMI";
  690                         break;
  691                 case PCI_INTR_SMB_IRQ9:
  692                         str="IRQ 9";
  693                         break;
  694                 default:
  695                         str="BOGUS";
  696                 }
  697                 device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled"));
  698                 value=pci_read_config(dev,PCI_REVID_SMB,1);
  699                 printf("revision %d\n",value);                
  700                 /*
  701                  * Install intr HANDLER here
  702                  */
  703                 rid=0;
  704                 res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE);
  705                 if(res==NULL){
  706                   device_printf(dev,"could not allocate irq");
  707                   return ENOMEM;
  708                 }
  709                 error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih);
  710                 if(error){
  711                         device_printf(dev,"Failed to map intr\n");
  712                         return error;
  713                 }
  714                 smbinterface=device_add_child(dev,"intsmb",unit);
  715                 if(!smbinterface){
  716                      printf("intsmb%d:could not add SMBus device\n",unit);
  717                 }
  718                 device_probe_and_attach(smbinterface);
  719         }
  720               
  721         value=pci_read_config(dev,PCI_BASE_ADDR_PM,4);
  722         printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe);
  723         return 0;
  724 }
  725 static int 
  726 intpm_probe(device_t dev)
  727 {
  728     struct _pcsid *ep =pci_ids;
  729     u_int32_t device_id=pci_get_devid(dev);
  730 
  731     while (ep->type && ep->type != device_id)
  732           ++ep;
  733     if(ep->desc!=NULL){
  734       device_set_desc(dev,ep->desc);
  735       bus_set_resource(dev,SYS_RES_IRQ,0,9,1); /* XXX setup intr resource */
  736       return (BUS_PROBE_DEFAULT);
  737     }else{
  738       return ENXIO;
  739     }
  740 }
  741 DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0);
  742 MODULE_DEPEND(intpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
  743 MODULE_VERSION(intpm, 1);
  744 
  745 static void intpm_intr(void *arg)
  746 {
  747         struct intpm_pci_softc *sc;
  748         sc=(struct intpm_pci_softc *)arg;
  749         intsmb_intr(sc->smbus);
  750         intsmb_slvintr(sc->smbus);
  751         
  752 }

Cache object: fc1b66d407c51ff6ede549a66f1ec345


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