intpm.c revision 49064
143166Snsouch/*-
243166Snsouch * Copyright (c) 1998, 1999 Takanori Watanabe
343166Snsouch * All rights reserved.
443166Snsouch *
543166Snsouch * Redistribution and use in source and binary forms, with or without
643166Snsouch * modification, are permitted provided that the following conditions
743166Snsouch * are met:
843166Snsouch * 1. Redistributions of source code must retain the above copyright
943166Snsouch *        notice, this list of conditions and the following disclaimer.
1043166Snsouch * 2. Redistributions in binary form must reproduce the above copyright
1143166Snsouch *        notice, this list of conditions and the following disclaimer in the
1243166Snsouch *        documentation and/or other materials provided with the distribution.
1343166Snsouch *
1443166Snsouch * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1543166Snsouch * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1643166Snsouch * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1743166Snsouch * ARE DISCLAIMED.    IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1843166Snsouch * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1943166Snsouch * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2043166Snsouch * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2143166Snsouch * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2243166Snsouch * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2343166Snsouch * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2443166Snsouch * SUCH DAMAGE.
2543166Snsouch *
2649064Snsouch *	$Id: intpm.c,v 1.11 1999/07/03 20:17:06 peter Exp $
2743166Snsouch */
2843166Snsouch
2943166Snsouch#include <sys/param.h>
3043166Snsouch#include <sys/systm.h>
3143166Snsouch#include <sys/kernel.h>
3243166Snsouch#include <machine/bus_pio.h>
3343166Snsouch#include <machine/bus_memio.h>
3443166Snsouch#include <machine/bus.h>
3543166Snsouch
3643166Snsouch#include <machine/clock.h>
3743166Snsouch#include <sys/uio.h>
3843166Snsouch#include <sys/module.h>
3943166Snsouch#include <sys/bus.h>
4043166Snsouch#include <sys/conf.h>
4143166Snsouch#include <sys/malloc.h>
4243166Snsouch#include <sys/buf.h>
4346651Speter#include <sys/rman.h>
4446651Speter#include <machine/resource.h>
4543166Snsouch#include <dev/smbus/smbconf.h>
4643166Snsouch
4743166Snsouch#include "smbus_if.h"
4843166Snsouch
4943166Snsouch/*This should be removed if force_pci_map_int supported*/
5043166Snsouch#include <sys/interrupt.h>
5143166Snsouch
5243166Snsouch#include <pci/pcireg.h>
5343166Snsouch#include <pci/pcivar.h>
5443166Snsouch#include <pci/intpmreg.h>
5543166Snsouch
5643166Snsouch#include "opt_intpm.h"
5743166Snsouch
5843166Snsouchstatic struct _pcsid
5943166Snsouch{
6043166Snsouch        pcidi_t type;
6143166Snsouch	char	*desc;
6243166Snsouch} pci_ids[] =
6343166Snsouch{
6443166Snsouch	{ 0x71138086,"Intel 82371AB Power management controller"},
6543166Snsouch
6643166Snsouch	{ 0x00000000,	NULL					}
6743166Snsouch};
6843166Snsouchstatic int intsmb_probe(device_t);
6943166Snsouchstatic int intsmb_attach(device_t);
7043166Snsouchstatic void intsmb_print_child(device_t, device_t);
7143166Snsouch
7243166Snsouchstatic int intsmb_intr(device_t dev);
7343166Snsouchstatic int intsmb_slvintr(device_t dev);
7443166Snsouchstatic void  intsmb_alrintr(device_t dev);
7543166Snsouchstatic int intsmb_callback(device_t dev, int index, caddr_t data);
7643166Snsouchstatic int intsmb_quick(device_t dev, u_char slave, int how);
7743166Snsouchstatic int intsmb_sendb(device_t dev, u_char slave, char byte);
7843166Snsouchstatic int intsmb_recvb(device_t dev, u_char slave, char *byte);
7943166Snsouchstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
8043166Snsouchstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
8143166Snsouchstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
8243166Snsouchstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
8343166Snsouchstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
8443166Snsouchstatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
8543166Snsouchstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
8643166Snsouchstatic void intsmb_start(device_t dev,u_char cmd,int nointr);
8743166Snsouchstatic int intsmb_stop(device_t dev);
8843166Snsouchstatic int intsmb_stop_poll(device_t dev);
8943166Snsouchstatic int intsmb_free(device_t dev);
9046651Speterstatic int intpm_probe (device_t dev);
9146651Speterstatic int intpm_attach (device_t dev);
9243166Snsouchstatic devclass_t intsmb_devclass;
9343166Snsouch
9443166Snsouchstatic device_method_t intpm_methods[]={
9543166Snsouch        DEVMETHOD(device_probe,intsmb_probe),
9643166Snsouch        DEVMETHOD(device_attach,intsmb_attach),
9743166Snsouch
9843166Snsouch        DEVMETHOD(bus_print_child, intsmb_print_child),
9943166Snsouch
10043166Snsouch        DEVMETHOD(smbus_callback,intsmb_callback),
10143166Snsouch        DEVMETHOD(smbus_quick,intsmb_quick),
10243166Snsouch        DEVMETHOD(smbus_sendb,intsmb_sendb),
10343166Snsouch        DEVMETHOD(smbus_recvb,intsmb_recvb),
10443166Snsouch        DEVMETHOD(smbus_writeb,intsmb_writeb),
10543166Snsouch        DEVMETHOD(smbus_writew,intsmb_writew),
10643166Snsouch        DEVMETHOD(smbus_readb,intsmb_readb),
10743166Snsouch        DEVMETHOD(smbus_readw,intsmb_readw),
10843166Snsouch        DEVMETHOD(smbus_pcall,intsmb_pcall),
10943166Snsouch        DEVMETHOD(smbus_bwrite,intsmb_bwrite),
11043166Snsouch        DEVMETHOD(smbus_bread,intsmb_bread),
11143166Snsouch        {0,0}
11243166Snsouch};
11343166Snsouch
11446651Speterstruct intpm_pci_softc{
11543166Snsouch        bus_space_tag_t smbst;
11643166Snsouch        bus_space_handle_t smbsh;
11743166Snsouch	bus_space_tag_t pmst;
11843166Snsouch	bus_space_handle_t pmsh;
11943166Snsouch        pcici_t cfg;
12043166Snsouch	device_t  smbus;
12146651Speter};
12243166Snsouch
12343166Snsouch
12443166Snsouchstruct intsmb_softc{
12543166Snsouch        struct intpm_pci_softc *pci_sc;
12643166Snsouch        bus_space_tag_t st;
12743166Snsouch        bus_space_handle_t sh;
12843166Snsouch        device_t smbus;
12943166Snsouch        int isbusy;
13043166Snsouch};
13146651Speter
13243166Snsouchstatic driver_t intpm_driver = {
13343166Snsouch        "intsmb",
13443166Snsouch        intpm_methods,
13543166Snsouch        sizeof(struct intsmb_softc),
13643166Snsouch};
13743166Snsouch
13846651Speterstatic devclass_t intpm_devclass;
13946651Speterstatic device_method_t intpm_pci_methods[] = {
14046651Speter  DEVMETHOD(device_probe,intpm_probe),
14146651Speter  DEVMETHOD(device_attach,intpm_attach),
14246651Speter  {0,0}
14343166Snsouch};
14446651Speterstatic driver_t intpm_pci_driver = {
14546651Speter  "intpm",
14646651Speter  intpm_pci_methods,
14746651Speter  sizeof(struct intpm_pci_softc)
14846651Speter};
14943166Snsouch
15043166Snsouchstatic int
15143166Snsouchintsmb_probe(device_t dev)
15243166Snsouch{
15343166Snsouch        struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
15443166Snsouch        sc->smbus=smbus_alloc_bus(dev);
15543166Snsouch        if (!sc->smbus)
15643166Snsouch                return (EINVAL);    /* XXX don't know what to return else */
15743166Snsouch        device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
15843166Snsouch
15943166Snsouch        return (0);          /* XXX don't know what to return else */
16043166Snsouch}
16143166Snsouchstatic int
16243166Snsouchintsmb_attach(device_t dev)
16343166Snsouch{
16443166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
16546651Speter        sc->pci_sc=device_get_softc(device_get_parent(dev));
16643166Snsouch        sc->isbusy=0;
16743166Snsouch	sc->sh=sc->pci_sc->smbsh;
16843166Snsouch	sc->st=sc->pci_sc->smbst;
16943166Snsouch	sc->pci_sc->smbus=dev;
17043166Snsouch        device_probe_and_attach(sc->smbus);
17143166Snsouch#ifdef ENABLE_ALART
17243166Snsouch	/*Enable Arart*/
17343166Snsouch	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
17443166Snsouch			  PIIX4_SMBSLVCNT_ALTEN);
17543166Snsouch#endif
17643166Snsouch        return (0);
17743166Snsouch}
17843166Snsouch
17943166Snsouchstatic void
18043166Snsouchintsmb_print_child(device_t bus, device_t dev)
18143166Snsouch{
18243166Snsouch	printf(" on %s%d", device_get_name(bus), device_get_unit(bus));
18343166Snsouch	return;
18443166Snsouch}
18543166Snsouchstatic int
18643166Snsouchintsmb_callback(device_t dev, int index, caddr_t data)
18743166Snsouch{
18843166Snsouch	int error = 0;
18943166Snsouch	intrmask_t s;
19043166Snsouch	s=splnet();
19143166Snsouch	switch (index) {
19243166Snsouch	case SMB_REQUEST_BUS:
19343166Snsouch		break;
19443166Snsouch	case SMB_RELEASE_BUS:
19543166Snsouch		break;
19643166Snsouch	default:
19743166Snsouch		error = EINVAL;
19843166Snsouch	}
19943166Snsouch	splx(s);
20043166Snsouch	return (error);
20143166Snsouch}
20243166Snsouch/*counterpart of smbtx_smb_free*/
20343166Snsouchstatic        int
20443166Snsouchintsmb_free(device_t dev){
20546651Speter        intrmask_t s;
20643166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
20743166Snsouch        if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)&
20843166Snsouch	    PIIX4_SMBHSTSTAT_BUSY)
20943166Snsouch#ifdef ENABLE_ALART
21043166Snsouch	   ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)&
21143166Snsouch	      PIIX4_SMBSLVSTS_BUSY)
21243166Snsouch#endif
21343166Snsouch	   || sc->isbusy)
21443166Snsouch                return EBUSY;
21546651Speter	s=splhigh();
21643166Snsouch        sc->isbusy=1;
21743166Snsouch	/*Disable Intrrupt in slave part*/
21843166Snsouch#ifndef ENABLE_ALART
21943166Snsouch	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0);
22043166Snsouch#endif
22143166Snsouch        /*Reset INTR Flag to prepare INTR*/
22243166Snsouch	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS,
22343166Snsouch			  (PIIX4_SMBHSTSTAT_INTR|
22443166Snsouch			   PIIX4_SMBHSTSTAT_ERR|
22543166Snsouch			   PIIX4_SMBHSTSTAT_BUSC|
22643166Snsouch			   PIIX4_SMBHSTSTAT_FAIL)
22743166Snsouch		);
22846651Speter	splx(s);
22943166Snsouch        return 0;
23043166Snsouch}
23143166Snsouch
23243166Snsouchstatic int
23343166Snsouchintsmb_intr(device_t dev)
23443166Snsouch{
23543166Snsouch	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
23643166Snsouch	int status;
23743166Snsouch	status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
23843166Snsouch	if(status&PIIX4_SMBHSTSTAT_BUSY){
23943166Snsouch		return 1;
24043166Snsouch
24143166Snsouch	}
24249064Snsouch	if(status&(PIIX4_SMBHSTSTAT_INTR|
24343166Snsouch				PIIX4_SMBHSTSTAT_ERR|
24443166Snsouch				PIIX4_SMBHSTSTAT_BUSC|
24549064Snsouch				PIIX4_SMBHSTSTAT_FAIL)){
24643166Snsouch		int tmp;
24743166Snsouch		tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
24843166Snsouch		bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
24943166Snsouch				  tmp&~PIIX4_SMBHSTCNT_INTREN);
25049064Snsouch		if(sc->isbusy){
25149064Snsouch		  sc->isbusy=0;
25249064Snsouch		  wakeup(sc);
25349064Snsouch		}
25443166Snsouch		return 0;
25543166Snsouch	}
25643166Snsouch	return 1;/* Not Completed*/
25743166Snsouch}
25843166Snsouchstatic int
25943166Snsouchintsmb_slvintr(device_t dev)
26043166Snsouch{
26143166Snsouch	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
26243166Snsouch        int status,retval;
26343166Snsouch	retval=1;
26443166Snsouch        status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS);
26543166Snsouch	if(status&PIIX4_SMBSLVSTS_BUSY)
26643166Snsouch		return retval;
26743166Snsouch	if(status&PIIX4_SMBSLVSTS_ALART){
26843166Snsouch		intsmb_alrintr(dev);
26943166Snsouch		retval=0;
27043166Snsouch	}else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2
27143166Snsouch			  |PIIX4_SMBSLVSTS_SDW1)){
27243166Snsouch		retval=0;
27343166Snsouch	}
27443166Snsouch	/*Reset Status Register*/
27543166Snsouch	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART|
27643166Snsouch			  PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1|
27743166Snsouch			  PIIX4_SMBSLVSTS_SLV);
27843166Snsouch	return retval;
27943166Snsouch}
28043166Snsouch
28143166Snsouchstatic void intsmb_alrintr(device_t dev)
28243166Snsouch{
28343166Snsouch	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
28443166Snsouch	int slvcnt;
28543288Sdillon#ifdef ENABLE_ALART
28643288Sdillon	int error;
28743288Sdillon#endif
28843288Sdillon
28943166Snsouch	/*stop generating INTR from ALART*/
29043166Snsouch	slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT);
29143166Snsouch#ifdef ENABLE_ALART
29243166Snsouch	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
29343166Snsouch			  slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ;
29443166Snsouch#endif
29543166Snsouch	DELAY(5);
29643166Snsouch	/*ask bus who assert it and then ask it what's the matter. */
29743166Snsouch#ifdef ENABLE_ALART
29843166Snsouch	error=intsmb_free(dev);
29943166Snsouch	if(!error){
30043166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP
30143166Snsouch                                  |LSB);
30243166Snsouch		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1);
30343166Snsouch		if(!(error=intsmb_stop_poll(dev))){
30443288Sdillon			volatile u_int8_t *addr;
30543166Snsouch			addr=bus_space_read_1(sc->st,sc->sh,
30643166Snsouch					      PIIX4_SMBHSTDAT0);
30743311Sdillon			printf("ALART_RESPONSE: %p\n", addr);
30843166Snsouch		}
30943166Snsouch	}else{
31043166Snsouch	        printf("ERROR\n");
31143166Snsouch	}
31243166Snsouch
31343166Snsouch	/*Re-enable INTR from ALART*/
31443166Snsouch	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
31543166Snsouch			  slvcnt|PIIX4_SMBSLVCNT_ALTEN) ;
31643166Snsouch	DELAY(5);
31743166Snsouch#endif
31843166Snsouch
31943166Snsouch	return;
32043166Snsouch}
32143166Snsouchstatic void
32243166Snsouchintsmb_start(device_t dev,unsigned char cmd,int nointr)
32343166Snsouch{
32443166Snsouch	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
32543166Snsouch	unsigned char tmp;
32643166Snsouch	tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
32743166Snsouch	tmp&= 0xe0;
32843166Snsouch	tmp |= cmd;
32943166Snsouch	tmp |=PIIX4_SMBHSTCNT_START;
33043166Snsouch	/*While not in autoconfiguration Intrrupt Enabled*/
33143166Snsouch	if(!cold||!nointr)
33243166Snsouch		tmp |=PIIX4_SMBHSTCNT_INTREN;
33343166Snsouch	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp);
33443166Snsouch}
33543166Snsouch
33643166Snsouch/*Polling Code. Polling is not encouraged
33743166Snsouch * because It is required to wait for the device get busy.
33843166Snsouch *(29063505.pdf from Intel)
33943166Snsouch * But during boot,intrrupt cannot be used.
34043166Snsouch * so use polling code while in autoconfiguration.
34143166Snsouch */
34243166Snsouch
34343166Snsouchstatic        int
34443166Snsouchintsmb_stop_poll(device_t dev){
34543166Snsouch        int error,i;
34643166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
34749064Snsouch
34843166Snsouch	/*
34943166Snsouch	 *  In smbtx driver ,Simply waiting.
35043166Snsouch	 *  This loops 100-200 times.
35143166Snsouch	 */
35243166Snsouch	for(i=0;i<0x7fff;i++){
35343166Snsouch                if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)
35443166Snsouch		    &PIIX4_SMBHSTSTAT_BUSY)){
35543166Snsouch                        break;
35643166Snsouch                }
35743166Snsouch	}
35843166Snsouch	for(i=0;i<0x7fff;i++){
35943166Snsouch		int status;
36043166Snsouch		status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
36143166Snsouch		if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
36243166Snsouch			sc->isbusy=0;
36343166Snsouch			error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
36443166Snsouch				(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
36543166Snsouch				(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
36643166Snsouch			if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
36743166Snsouch				printf("unknown cause why?");
36843166Snsouch			}
36943166Snsouch			return error;
37043166Snsouch		}
37143166Snsouch	}
37249064Snsouch	{
37349064Snsouch	  int tmp;
37449064Snsouch	  sc->isbusy=0;
37549064Snsouch	  tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
37649064Snsouch	  bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
37749064Snsouch			    tmp&~PIIX4_SMBHSTCNT_INTREN);
37849064Snsouch	}
37943166Snsouch	return EIO;
38043166Snsouch}
38143166Snsouch/*
38243166Snsouch *wait for completion and return result.
38343166Snsouch */
38443166Snsouchstatic        int
38543166Snsouchintsmb_stop(device_t dev){
38643166Snsouch        int error;
38746651Speter	intrmask_t s;
38843166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
38943166Snsouch	if(cold){
39043166Snsouch		/*So that it can use device during probing device on SMBus.*/
39143166Snsouch		error=intsmb_stop_poll(dev);
39243166Snsouch		return error;
39343166Snsouch	}else{
39443166Snsouch		if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){
39543166Snsouch			int status;
39643166Snsouch			status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
39743166Snsouch			if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
39843166Snsouch				error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
39943166Snsouch					(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
40043166Snsouch					(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
40143166Snsouch				if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
40243166Snsouch					printf("intsmb%d:unknown cause why?\n",
40343166Snsouch					       device_get_unit(dev));
40443166Snsouch				}
40543166Snsouch#ifdef ENABLE_ALART
40643166Snsouch				bus_space_write_1(sc->st,sc->sh,
40743166Snsouch						  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
40843166Snsouch#endif
40943166Snsouch				return error;
41043166Snsouch			}
41143166Snsouch		}
41243166Snsouch	}
41343166Snsouch	/*Timeout Procedure*/
41446651Speter	s=splhigh();
41543166Snsouch	sc->isbusy=0;
41643166Snsouch	/*Re-enable supressed intrrupt from slave part*/
41743166Snsouch	bus_space_write_1(sc->st,sc->sh,
41843166Snsouch			  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
41946651Speter	splx(s);
42043166Snsouch        return EIO;
42143166Snsouch}
42243166Snsouch
42343166Snsouchstatic int
42443166Snsouchintsmb_quick(device_t dev, u_char slave, int how)
42543166Snsouch{
42643166Snsouch        int error=0;
42743166Snsouch        u_char data;
42843166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
42943166Snsouch        data=slave;
43043166Snsouch	/*Quick command is part of Address, I think*/
43143166Snsouch        switch(how){
43243166Snsouch        case SMB_QWRITE:
43343166Snsouch                data&=~LSB;
43443166Snsouch		break;
43543166Snsouch        case SMB_QREAD:
43643166Snsouch                data|=LSB;
43743166Snsouch                break;
43843166Snsouch        default:
43943166Snsouch                error=EINVAL;
44043166Snsouch        }
44143166Snsouch        if(!error){
44243166Snsouch	        error=intsmb_free(dev);
44343166Snsouch                if(!error){
44443166Snsouch                        bus_space_write_1(sc->st,sc->sh,
44543166Snsouch					  PIIX4_SMBHSTADD,data);
44643166Snsouch			intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0);
44743166Snsouch                        error=intsmb_stop(dev);
44843166Snsouch                }
44943166Snsouch        }
45043166Snsouch
45143166Snsouch        return (error);
45243166Snsouch}
45343166Snsouch
45443166Snsouchstatic int
45543166Snsouchintsmb_sendb(device_t dev, u_char slave, char byte)
45643166Snsouch{
45743166Snsouch        int error;
45843166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
45943166Snsouch        error=intsmb_free(dev);
46043166Snsouch        if(!error){
46143166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
46243166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte);
46343166Snsouch		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
46443166Snsouch                error=intsmb_stop(dev);
46543166Snsouch        }
46643166Snsouch        return (error);
46743166Snsouch}
46843166Snsouchstatic int
46943166Snsouchintsmb_recvb(device_t dev, u_char slave, char *byte)
47043166Snsouch{
47143166Snsouch        int error;
47243166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
47343166Snsouch        error=intsmb_free(dev);
47443166Snsouch        if(!error){
47543166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave
47643166Snsouch				  |LSB);
47743166Snsouch                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
47843166Snsouch                if(!(error=intsmb_stop(dev))){
47943166Snsouch#ifdef RECV_IS_IN_CMD
48043166Snsouch		        /*Linux SMBus stuff also troubles
48143166Snsouch			  Because Intel's datasheet will not make clear.
48243166Snsouch			 */
48343166Snsouch                        *byte=bus_space_read_1(sc->st,sc->sh,
48443166Snsouch					       PIIX4_SMBHSTCMD);
48543166Snsouch#else
48643166Snsouch                        *byte=bus_space_read_1(sc->st,sc->sh,
48743166Snsouch					       PIIX4_SMBHSTDAT0);
48843166Snsouch#endif
48943166Snsouch                }
49043166Snsouch        }
49143166Snsouch        return (error);
49243166Snsouch}
49343166Snsouchstatic int
49443166Snsouchintsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
49543166Snsouch{
49643166Snsouch        int error;
49743166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
49843166Snsouch        error=intsmb_free(dev);
49943166Snsouch        if(!error){
50043166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
50143166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
50243166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte);
50343166Snsouch		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
50443166Snsouch                error=intsmb_stop(dev);
50543166Snsouch        }
50643166Snsouch        return (error);
50743166Snsouch}
50843166Snsouchstatic int
50943166Snsouchintsmb_writew(device_t dev, u_char slave, char cmd, short word)
51043166Snsouch{
51143166Snsouch        int error;
51243166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
51343166Snsouch        error=intsmb_free(dev);
51443166Snsouch        if(!error){
51543166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
51643166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
51743166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,
51843166Snsouch				  word&0xff);
51943166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,
52043166Snsouch				  (word>>8)&0xff);
52143166Snsouch		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
52243166Snsouch                error=intsmb_stop(dev);
52343166Snsouch        }
52443166Snsouch        return (error);
52543166Snsouch}
52643166Snsouch
52743166Snsouchstatic int
52843166Snsouchintsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
52943166Snsouch{
53043166Snsouch        int error;
53143166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
53243166Snsouch        error=intsmb_free(dev);
53343166Snsouch        if(!error){
53443166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
53543166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
53643166Snsouch		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
53743166Snsouch                if(!(error=intsmb_stop(dev))){
53843166Snsouch		        *byte=bus_space_read_1(sc->st,sc->sh,
53943166Snsouch					       PIIX4_SMBHSTDAT0);
54043166Snsouch                }
54143166Snsouch        }
54243166Snsouch        return (error);
54343166Snsouch}
54443166Snsouchstatic int
54543166Snsouchintsmb_readw(device_t dev, u_char slave, char cmd, short *word)
54643166Snsouch{
54743166Snsouch        int error;
54843166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
54943166Snsouch        error=intsmb_free(dev);
55043166Snsouch        if(!error){
55143166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
55243166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
55343166Snsouch		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
55443166Snsouch                if(!(error=intsmb_stop(dev))){
55543166Snsouch                        *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
55643166Snsouch                        *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
55743166Snsouch                }
55843166Snsouch        }
55943166Snsouch        return (error);
56043166Snsouch}
56143166Snsouch/*
56243166Snsouch * Data sheet claims that it implements all function, but also claims
56343166Snsouch * that it implements 7 function and not mention PCALL. So I don't know
56443166Snsouch * whether it will work.
56543166Snsouch */
56643166Snsouchstatic int
56743166Snsouchintsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
56843166Snsouch{
56943166Snsouch#ifdef PROCCALL_TEST
57043166Snsouch        int error;
57143166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
57243166Snsouch        error=intsmb_free(dev);
57343166Snsouch        if(!error){
57443166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
57543166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
57643166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff);
57743166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8);
57843166Snsouch                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
57943166Snsouch        }
58043166Snsouch        if(!(error=intsmb_stop(dev))){
58143166Snsouch                *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
58243166Snsouch                *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
58343166Snsouch        }
58443166Snsouch        return error;
58543166Snsouch#else
58643166Snsouch	return 0;
58743166Snsouch#endif
58843166Snsouch}
58943166Snsouchstatic int
59043166Snsouchintsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
59143166Snsouch{
59243166Snsouch        int error,i;
59343166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
59443166Snsouch        error=intsmb_free(dev);
59543166Snsouch        if(count>SMBBLOCKTRANS_MAX||count==0)
59643166Snsouch                error=EINVAL;
59743166Snsouch        if(!error){
59843166Snsouch                /*Reset internal array index*/
59943166Snsouch                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
60043166Snsouch
60143166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
60243166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
60343166Snsouch                for(i=0;i<count;i++){
60443166Snsouch                        bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]);
60543166Snsouch                }
60643166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
60743166Snsouch                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
60843166Snsouch                error=intsmb_stop(dev);
60943166Snsouch        }
61043166Snsouch        return (error);
61143166Snsouch}
61243166Snsouch
61343166Snsouchstatic int
61443166Snsouchintsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
61543166Snsouch{
61643166Snsouch        int error,i;
61743166Snsouch        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
61843166Snsouch        error=intsmb_free(dev);
61943166Snsouch        if(count>SMBBLOCKTRANS_MAX||count==0)
62043166Snsouch                error=EINVAL;
62143166Snsouch        if(!error){
62243166Snsouch                /*Reset internal array index*/
62343166Snsouch                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
62443166Snsouch
62543166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
62643166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
62743166Snsouch                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
62843166Snsouch                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
62943166Snsouch                error=intsmb_stop(dev);
63043166Snsouch                if(!error){
63143166Snsouch                        bzero(buf,count);/*Is it needed?*/
63243166Snsouch                        count= bus_space_read_1(sc->st,sc->sh,
63343166Snsouch						PIIX4_SMBHSTDAT0);
63443166Snsouch                        if(count!=0&&count<=SMBBLOCKTRANS_MAX){
63543166Snsouch			        for(i=0;i<count;i++){
63643166Snsouch				        buf[i]=bus_space_read_1(sc->st,
63743166Snsouch								sc->sh,
63843166Snsouch								PIIX4_SMBBLKDAT);
63943166Snsouch				}
64043166Snsouch			}
64143166Snsouch                        else{
64243166Snsouch				error=EIO;
64343166Snsouch                        }
64443166Snsouch		}
64543166Snsouch	}
64643166Snsouch        return (error);
64743166Snsouch}
64843166Snsouch
64946651SpeterDRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0);
65043166Snsouch
65143166Snsouch
65243166Snsouchstatic void intpm_intr __P((void *arg));
65346651Speterstatic int
65446651Speterintpm_attach(device_t dev)
65543166Snsouch{
65643166Snsouch        int value;
65746651Speter        int unit=device_get_unit(dev);
65846651Speter	void *ih;
65946651Speter	int error;
66043166Snsouch        char * str;
66143166Snsouch        {
66243166Snsouch                struct intpm_pci_softc *sciic;
66343166Snsouch                device_t smbinterface;
66446651Speter		int rid;
66546651Speter		struct resource *res;
66646651Speter
66746651Speter                sciic=device_get_softc(dev);
66843166Snsouch                if(sciic==NULL){
66946651Speter                        return ENOMEM;
67043166Snsouch                }
67143166Snsouch
67246651Speter		rid=PCI_BASE_ADDR_SMB;
67346651Speter#if 0
67446651Speter		res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,
67546651Speter				       0,~0,1,RF_ACTIVE);
67646651Speter		if(res==NULL){
67746651Speter		  device_printf(dev,"IO FAILED Trying Memory\n");
67846651Speter		  res=bus_alloc_resource(dev,SYS_RES_MEMORY,&rid,0,~0,
67946651Speter					 1,RF_ACTIVE);
68046651Speter		}
68146651Speter#else
68246651Speter		/*Do as I tell!*/
68346651Speter		value=pci_read_config(dev,rid,4);
68446651Speter		res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,value&(~1),
68546651Speter				       (value&(~1))+256,256,RF_ACTIVE);
68646651Speter#endif
68746651Speter		if(res==NULL){
68846651Speter		  device_printf(dev,"Could not allocate Bus space\n");
68946651Speter		  return ENXIO;
69046651Speter		}
69146651Speter		sciic->smbst=rman_get_bustag(res);
69246651Speter		sciic->smbsh=rman_get_bushandle(res);
69346651Speter
69446651Speter		device_printf(dev,"%s %x\n",
69546651Speter			      (sciic->smbst==I386_BUS_SPACE_IO)?
69646651Speter			      "I/O mapped":"Memory",
69746651Speter			      sciic->smbsh);
69846651Speter
69943166Snsouch
70043166Snsouch#ifndef NO_CHANGE_PCICONF
70146651Speter		pci_write_config(dev,PCIR_INTLINE,0x9,1);
70246651Speter		pci_write_config(dev,PCI_HST_CFG_SMB,
70346651Speter				 PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1);
70443166Snsouch#endif
70546651Speter                value=pci_read_config(dev,PCI_HST_CFG_SMB,1);
70643166Snsouch                switch(value&0xe){
70743166Snsouch                case PCI_INTR_SMB_SMI:
70846651Speter		        str="SMI";
70943166Snsouch                        break;
71043166Snsouch                case PCI_INTR_SMB_IRQ9:
71143166Snsouch                        str="IRQ 9";
71243166Snsouch                        break;
71343166Snsouch                default:
71443166Snsouch                        str="BOGUS";
71543166Snsouch                }
71646651Speter                device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled"));
71746651Speter                value=pci_read_config(dev,PCI_REVID_SMB,1);
71843166Snsouch                printf("revision %d\n",value);
71943166Snsouch                /*
72043166Snsouch                 * Install intr HANDLER here
72143166Snsouch                 */
72246651Speter		rid=0;
72346651Speter		res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE);
72446651Speter		if(res==NULL){
72546651Speter		  device_printf(dev,"could not allocate irq");
72646651Speter		  return ENOMEM;
72746651Speter		}
72846777Sphk		error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih);
72946651Speter                if(error){
73046651Speter                        device_printf(dev,"Failed to map intr\n");
73146651Speter			return error;
73243166Snsouch                }
73346651Speter                smbinterface=device_add_child(dev,"intsmb",unit,NULL);
73446651Speter		if(!smbinterface){
73546651Speter		     printf("intsmb%d:could not add SMBus device\n",unit);
73646651Speter		}
73743166Snsouch                device_probe_and_attach(smbinterface);
73843166Snsouch        }
73946651Speter
74046651Speter        value=pci_read_config(dev,PCI_BASE_ADDR_PM,4);
74143166Snsouch        printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe);
74246651Speter        return 0;
74343166Snsouch}
74446651Speterstatic int
74546651Speterintpm_probe(device_t dev)
74646651Speter{
74746651Speter    struct _pcsid *ep =pci_ids;
74846651Speter    u_int32_t device_id=pci_get_devid(dev);
74949064Snsouch
75046651Speter    while (ep->type && ep->type != device_id)
75146651Speter	  ++ep;
75246651Speter    if(ep->desc!=NULL){
75346651Speter      device_set_desc(dev,ep->desc);
75446651Speter      return 0;
75546651Speter    }else{
75646651Speter      return ENXIO;
75746651Speter    }
75846651Speter}
75946651SpeterDRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0);
76046651Speter
76143166Snsouchstatic void intpm_intr(void *arg)
76243166Snsouch{
76343166Snsouch        struct intpm_pci_softc *sc;
76443166Snsouch        sc=(struct intpm_pci_softc *)arg;
76543166Snsouch	intsmb_intr(sc->smbus);
76643166Snsouch	intsmb_slvintr(sc->smbus);
76749064Snsouch
76843166Snsouch}
769