/*- * Copyright (c) 1998, 1999 Takanori Watanabe * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $Id$ */ #include "pci.h" #include "intpm.h" #if NPCI > 0 #if NINTPM >0 /* I don't think the chip is used in other architecture. :-)*/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "smbus_if.h" /*This should be removed if force_pci_map_int supported*/ #include #include #include #include #include "opt_intpm.h" static struct _pcsid { pcidi_t type; char *desc; } pci_ids[] = { { 0x71138086,"Intel 82371AB Power management controller"}, { 0x00000000, NULL } }; static int intsmb_probe(device_t); static int intsmb_attach(device_t); static void intsmb_print_child(device_t, device_t); static int intsmb_intr(device_t dev); static int intsmb_slvintr(device_t dev); static void intsmb_alrintr(device_t dev); static int intsmb_callback(device_t dev, int index, caddr_t data); static int intsmb_quick(device_t dev, u_char slave, int how); static int intsmb_sendb(device_t dev, u_char slave, char byte); static int intsmb_recvb(device_t dev, u_char slave, char *byte); static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); static int intsmb_writew(device_t dev, u_char slave, char cmd, short word); static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); static void intsmb_start(device_t dev,u_char cmd,int nointr); static int intsmb_stop(device_t dev); static int intsmb_stop_poll(device_t dev); static int intsmb_free(device_t dev); static struct intpm_pci_softc *intpm_alloc(int unit); static const char* intpm_probe __P((pcici_t tag, pcidi_t type)); static void intpm_attach __P((pcici_t config_id, int unit)); static devclass_t intsmb_devclass; static device_method_t intpm_methods[]={ DEVMETHOD(device_probe,intsmb_probe), DEVMETHOD(device_attach,intsmb_attach), DEVMETHOD(bus_print_child, intsmb_print_child), DEVMETHOD(smbus_callback,intsmb_callback), DEVMETHOD(smbus_quick,intsmb_quick), DEVMETHOD(smbus_sendb,intsmb_sendb), DEVMETHOD(smbus_recvb,intsmb_recvb), DEVMETHOD(smbus_writeb,intsmb_writeb), DEVMETHOD(smbus_writew,intsmb_writew), DEVMETHOD(smbus_readb,intsmb_readb), DEVMETHOD(smbus_readw,intsmb_readw), DEVMETHOD(smbus_pcall,intsmb_pcall), DEVMETHOD(smbus_bwrite,intsmb_bwrite), DEVMETHOD(smbus_bread,intsmb_bread), {0,0} }; static struct intpm_pci_softc{ bus_space_tag_t smbst; bus_space_handle_t smbsh; bus_space_tag_t pmst; bus_space_handle_t pmsh; pcici_t cfg; device_t smbus; }intpm_pci[NINTPM]; struct intsmb_softc{ struct intpm_pci_softc *pci_sc; bus_space_tag_t st; bus_space_handle_t sh; device_t smbus; int isbusy; }; static driver_t intpm_driver = { "intsmb", intpm_methods, DRIVER_TYPE_MISC, sizeof(struct intsmb_softc), }; static u_long intpm_count ; static struct pci_device intpm_device = { "intpm", intpm_probe, intpm_attach, &intpm_count }; DATA_SET (pcidevice_set, intpm_device); static int intsmb_probe(device_t dev) { struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev); sc->smbus=smbus_alloc_bus(dev); if (!sc->smbus) return (EINVAL); /* XXX don't know what to return else */ device_set_desc(dev,"Intel PIIX4 SMBUS Interface"); return (0); /* XXX don't know what to return else */ } static int intsmb_attach(device_t dev) { struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); sc->pci_sc=&intpm_pci[device_get_unit(dev)]; sc->isbusy=0; sc->sh=sc->pci_sc->smbsh; sc->st=sc->pci_sc->smbst; sc->pci_sc->smbus=dev; device_probe_and_attach(sc->smbus); #ifdef ENABLE_ALART /*Enable Arart*/ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, PIIX4_SMBSLVCNT_ALTEN); #endif return (0); } static void intsmb_print_child(device_t bus, device_t dev) { printf(" on %s%d", device_get_name(bus), device_get_unit(bus)); return; } static int intsmb_callback(device_t dev, int index, caddr_t data) { int error = 0; intrmask_t s; s=splnet(); switch (index) { case SMB_REQUEST_BUS: break; case SMB_RELEASE_BUS: break; default: error = EINVAL; } splx(s); return (error); } /*counterpart of smbtx_smb_free*/ static int intsmb_free(device_t dev){ struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)& PIIX4_SMBHSTSTAT_BUSY) #ifdef ENABLE_ALART ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)& PIIX4_SMBSLVSTS_BUSY) #endif || sc->isbusy) return EBUSY; sc->isbusy=1; /*Disable Intrrupt in slave part*/ #ifndef ENABLE_ALART bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0); #endif /*Reset INTR Flag to prepare INTR*/ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS, (PIIX4_SMBHSTSTAT_INTR| PIIX4_SMBHSTSTAT_ERR| PIIX4_SMBHSTSTAT_BUSC| PIIX4_SMBHSTSTAT_FAIL) ); return 0; } static int intsmb_intr(device_t dev) { struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); int status; intrmask_t s; status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); if(status&PIIX4_SMBHSTSTAT_BUSY){ return 1; } s=splhigh(); if(sc->isbusy&&(status&(PIIX4_SMBHSTSTAT_INTR| PIIX4_SMBHSTSTAT_ERR| PIIX4_SMBHSTSTAT_BUSC| PIIX4_SMBHSTSTAT_FAIL))){ int tmp; sc->isbusy=0; tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT, tmp&~PIIX4_SMBHSTCNT_INTREN); splx(s); wakeup(sc); return 0; } splx(s); return 1;/* Not Completed*/ } static int intsmb_slvintr(device_t dev) { struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); int status,retval; retval=1; status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS); if(status&PIIX4_SMBSLVSTS_BUSY) return retval; if(status&PIIX4_SMBSLVSTS_ALART){ intsmb_alrintr(dev); retval=0; }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2 |PIIX4_SMBSLVSTS_SDW1)){ retval=0; } /*Reset Status Register*/ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART| PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1| PIIX4_SMBSLVSTS_SLV); return retval; } static void intsmb_alrintr(device_t dev) { struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); int slvcnt; /*stop generating INTR from ALART*/ slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT); #ifdef ENABLE_ALART bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ; #endif DELAY(5); /*ask bus who assert it and then ask it what's the matter. */ #ifdef ENABLE_ALART error=intsmb_free(dev); if(!error){ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP |LSB); intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1); if(!(error=intsmb_stop_poll(dev))){ addr=bus_space_read_1(sc->st,sc->sh, PIIX4_SMBHSTDAT0); printf("ALART_RESPONSE: %x\n",(int) addr); } }else{ printf("ERROR\n"); } /*Re-enable INTR from ALART*/ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT, slvcnt|PIIX4_SMBSLVCNT_ALTEN) ; DELAY(5); #endif return; } static void intsmb_start(device_t dev,unsigned char cmd,int nointr) { struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); unsigned char tmp; tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); tmp&= 0xe0; tmp |= cmd; tmp |=PIIX4_SMBHSTCNT_START; /*While not in autoconfiguration Intrrupt Enabled*/ if(!cold||!nointr) tmp |=PIIX4_SMBHSTCNT_INTREN; bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp); } /*Polling Code. Polling is not encouraged * because It is required to wait for the device get busy. *(29063505.pdf from Intel) * But during boot,intrrupt cannot be used. * so use polling code while in autoconfiguration. */ static int intsmb_stop_poll(device_t dev){ int error,i; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); /* * In smbtx driver ,Simply waiting. * This loops 100-200 times. */ for(i=0;i<0x7fff;i++){ if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS) &PIIX4_SMBHSTSTAT_BUSY)){ break; } } for(i=0;i<0x7fff;i++){ int status; status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ sc->isbusy=0; error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ printf("unknown cause why?"); } return error; } } sc->isbusy=0; return EIO; } /* *wait for completion and return result. */ static int intsmb_stop(device_t dev){ int error; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); if(cold){ /*So that it can use device during probing device on SMBus.*/ error=intsmb_stop_poll(dev); return error; }else{ if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){ int status; status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS); if(!(status&PIIX4_SMBHSTSTAT_BUSY)){ error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO : (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY: (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0; if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){ printf("intsmb%d:unknown cause why?\n", device_get_unit(dev)); } #ifdef ENABLE_ALART bus_space_write_1(sc->st,sc->sh, PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); #endif return error; } } } /*Timeout Procedure*/ sc->isbusy=0; /*Re-enable supressed intrrupt from slave part*/ bus_space_write_1(sc->st,sc->sh, PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN); return EIO; } static int intsmb_quick(device_t dev, u_char slave, int how) { int error=0; u_char data; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); data=slave; /*Quick command is part of Address, I think*/ switch(how){ case SMB_QWRITE: data&=~LSB; break; case SMB_QREAD: data|=LSB; break; default: error=EINVAL; } if(!error){ error=intsmb_free(dev); if(!error){ bus_space_write_1(sc->st,sc->sh, PIIX4_SMBHSTADD,data); intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0); error=intsmb_stop(dev); } } return (error); } static int intsmb_sendb(device_t dev, u_char slave, char byte) { int error; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); error=intsmb_free(dev); if(!error){ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte); intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); error=intsmb_stop(dev); } return (error); } static int intsmb_recvb(device_t dev, u_char slave, char *byte) { int error; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); error=intsmb_free(dev); if(!error){ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave |LSB); intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0); if(!(error=intsmb_stop(dev))){ #ifdef RECV_IS_IN_CMD /*Linux SMBus stuff also troubles Because Intel's datasheet will not make clear. */ *byte=bus_space_read_1(sc->st,sc->sh, PIIX4_SMBHSTCMD); #else *byte=bus_space_read_1(sc->st,sc->sh, PIIX4_SMBHSTDAT0); #endif } } return (error); } static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte) { int error; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); error=intsmb_free(dev); if(!error){ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte); intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); error=intsmb_stop(dev); } return (error); } static int intsmb_writew(device_t dev, u_char slave, char cmd, short word) { int error; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); error=intsmb_free(dev); if(!error){ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0, word&0xff); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1, (word>>8)&0xff); intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); error=intsmb_stop(dev); } return (error); } static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte) { int error; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); error=intsmb_free(dev); if(!error){ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0); if(!(error=intsmb_stop(dev))){ *byte=bus_space_read_1(sc->st,sc->sh, PIIX4_SMBHSTDAT0); } } return (error); } static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word) { int error; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); error=intsmb_free(dev); if(!error){ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); if(!(error=intsmb_stop(dev))){ *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; } } return (error); } /* * Data sheet claims that it implements all function, but also claims * that it implements 7 function and not mention PCALL. So I don't know * whether it will work. */ static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata) { #ifdef PROCCALL_TEST int error; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); error=intsmb_free(dev); if(!error){ bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8); intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0); } if(!(error=intsmb_stop(dev))){ *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff; *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8; } return error; #else return 0; #endif } static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf) { int error,i; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); error=intsmb_free(dev); if(count>SMBBLOCKTRANS_MAX||count==0) error=EINVAL; if(!error){ /*Reset internal array index*/ bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); for(i=0;ist,sc->sh,PIIX4_SMBBLKDAT,buf[i]); } bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); error=intsmb_stop(dev); } return (error); } static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf) { int error,i; struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev); error=intsmb_free(dev); if(count>SMBBLOCKTRANS_MAX||count==0) error=EINVAL; if(!error){ /*Reset internal array index*/ bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd); bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count); intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0); error=intsmb_stop(dev); if(!error){ bzero(buf,count);/*Is it needed?*/ count= bus_space_read_1(sc->st,sc->sh, PIIX4_SMBHSTDAT0); if(count!=0&&count<=SMBBLOCKTRANS_MAX){ for(i=0;ist, sc->sh, PIIX4_SMBBLKDAT); } } else{ error=EIO; } } } return (error); } DRIVER_MODULE(intsmb, root , intpm_driver, intsmb_devclass, 0, 0); static void intpm_intr __P((void *arg)); static const char* intpm_probe (pcici_t tag, pcidi_t type) { struct _pcsid *ep =pci_ids; while (ep->type && ep->type != type) ++ep; return (ep->desc); } static struct intpm_pci_softc *intpm_alloc(int unit){ if(unitdevdata */ void *idesc; idesc = intr_create(dev_instance, irq, func, arg, maskptr, 0); error = intr_connect(idesc); if (error != 0) return 0; #ifdef APIC_IO nextpin = next_apic_irq(irq); if (nextpin < 0) return 1; /* * Attempt handling of some broken mp tables. * * It's OK to yell (since the mp tables are broken). * * Hanging in the boot is not OK */ muxcnt = 2; nextpin = next_apic_irq(nextpin); while (muxcnt < 5 && nextpin >= 0) { muxcnt++; nextpin = next_apic_irq(nextpin); } if (muxcnt >= 5) { printf("bogus MP table, more than 4 IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n"); return 0; } printf("bogus MP table, %d IO APIC pins connected to the same PCI device or ISA/EISA interrupt\n", muxcnt); nextpin = next_apic_irq(irq); while (nextpin >= 0) { idesc = intr_create(dev_instance, nextpin, func, arg, maskptr, 0); error = intr_connect(idesc); if (error != 0) return 0; printf("Registered extra interrupt handler for int %d (in addition to int %d)\n", nextpin, irq); nextpin = next_apic_irq(nextpin); } #endif return 1; } static void intpm_attach(config_id, unit) pcici_t config_id; int unit; { int value; char * str; { struct intpm_pci_softc *sciic; device_t smbinterface; value=pci_cfgread(config_id,PCI_BASE_ADDR_SMB,4); sciic=intpm_alloc(unit); if(sciic==NULL){ return; } sciic->smbst=(value&1)?I386_BUS_SPACE_IO:I386_BUS_SPACE_MEM; /*Calling pci_map_port is better.But bus_space_handle_t != * pci_port_t, so I don't call support routine while * bus_space_??? support routine will be appear. */ sciic->smbsh=value&(~1); if(sciic->smbsh==I386_BUS_SPACE_MEM){ /*According to the spec, this will not occur*/ int dummy; pci_map_mem(config_id,PCI_BASE_ADDR_SMB,&sciic->smbsh,&dummy); } printf("intpm%d: %s %x ",unit, (sciic->smbst==I386_BUS_SPACE_IO)?"I/O mapped":"Memory", sciic->smbsh); #ifndef NO_CHANGE_PCICONF pci_cfgwrite(config_id,PCIR_INTLINE,0x09,1); pci_cfgwrite(config_id,PCI_HST_CFG_SMB, PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); #endif config_id->intline=pci_cfgread(config_id,PCIR_INTLINE,1); printf("ALLOCED IRQ %d ",config_id->intline); value=pci_cfgread(config_id,PCI_HST_CFG_SMB,1); switch(value&0xe){ case PCI_INTR_SMB_SMI: str="SMI"; break; case PCI_INTR_SMB_IRQ9: str="IRQ 9"; break; default: str="BOGUS"; } printf("intr %s %s ",str,((value&1)? "enabled":"disabled")); value=pci_cfgread(config_id,PCI_REVID_SMB,1); printf("revision %d\n",value); /* * Install intr HANDLER here */ if(force_pci_map_int(config_id,intpm_intr,sciic,&net_imask)==0){ printf("intpm%d: Failed to map intr\n",unit); } smbinterface=device_add_child(root_bus,"intsmb",unit,NULL); device_probe_and_attach(smbinterface); } value=pci_cfgread(config_id,PCI_BASE_ADDR_PM,4); printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); return; } static void intpm_intr(void *arg) { struct intpm_pci_softc *sc; sc=(struct intpm_pci_softc *)arg; intsmb_intr(sc->smbus); intsmb_slvintr(sc->smbus); } #endif /* NPCI > 0 */ #endif