intpm.c revision 49064
126238Swpaul/*-
226238Swpaul * Copyright (c) 1998, 1999 Takanori Watanabe
326238Swpaul * All rights reserved.
426238Swpaul *
526238Swpaul * Redistribution and use in source and binary forms, with or without
626238Swpaul * modification, are permitted provided that the following conditions
726238Swpaul * are met:
826238Swpaul * 1. Redistributions of source code must retain the above copyright
926238Swpaul *        notice, this list of conditions and the following disclaimer.
1026238Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1126238Swpaul *        notice, this list of conditions and the following disclaimer in the
1226238Swpaul *        documentation and/or other materials provided with the distribution.
1326238Swpaul *
1426238Swpaul * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1526238Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1626238Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1726238Swpaul * ARE DISCLAIMED.    IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1826238Swpaul * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1926238Swpaul * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2026238Swpaul * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2126238Swpaul * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2226238Swpaul * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2326238Swpaul * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2426238Swpaul * SUCH DAMAGE.
2526238Swpaul *
2626238Swpaul *	$Id: intpm.c,v 1.11 1999/07/03 20:17:06 peter Exp $
2726238Swpaul */
2826238Swpaul
2926238Swpaul#include <sys/param.h>
3095633Smarkm#include <sys/systm.h>
3126238Swpaul#include <sys/kernel.h>
3227754Scharnier#include <machine/bus_pio.h>
3326238Swpaul#include <machine/bus_memio.h>
3426238Swpaul#include <machine/bus.h>
3527754Scharnier
3626238Swpaul#include <machine/clock.h>
3726238Swpaul#include <sys/uio.h>
3826238Swpaul#include <sys/module.h>
3926238Swpaul#include <sys/bus.h>
4026238Swpaul#include <sys/conf.h>
4126238Swpaul#include <sys/malloc.h>
4226238Swpaul#include <sys/buf.h>
4326238Swpaul#include <sys/rman.h>
4495633Smarkm#include <machine/resource.h>
4595633Smarkm#include <dev/smbus/smbconf.h>
4695633Smarkm
4787204Smarkm#include "smbus_if.h"
4887204Smarkm
4987204Smarkm/*This should be removed if force_pci_map_int supported*/
5095633Smarkm#include <sys/interrupt.h>
5126238Swpaul
5226238Swpaul#include <pci/pcireg.h>
5395633Smarkm#include <pci/pcivar.h>
5426238Swpaul#include <pci/intpmreg.h>
5587204Smarkm
5626238Swpaul#include "opt_intpm.h"
5726238Swpaul
5826238Swpaulstatic struct _pcsid
5926238Swpaul{
6095633Smarkm        pcidi_t type;
61200462Sdelphij	char	*desc;
6287204Smarkm} pci_ids[] =
6387204Smarkm{
6426238Swpaul	{ 0x71138086,"Intel 82371AB Power management controller"},
6527754Scharnier
6626238Swpaul	{ 0x00000000,	NULL					}
6787204Smarkm};
6826238Swpaulstatic int intsmb_probe(device_t);
6926238Swpaulstatic int intsmb_attach(device_t);
7026238Swpaulstatic void intsmb_print_child(device_t, device_t);
7126238Swpaul
7226238Swpaulstatic int intsmb_intr(device_t dev);
7326238Swpaulstatic int intsmb_slvintr(device_t dev);
7492921Simpstatic void  intsmb_alrintr(device_t dev);
7592921Simpstatic int intsmb_callback(device_t dev, int index, caddr_t data);
7626238Swpaulstatic int intsmb_quick(device_t dev, u_char slave, int how);
7726238Swpaulstatic int intsmb_sendb(device_t dev, u_char slave, char byte);
7826238Swpaulstatic int intsmb_recvb(device_t dev, u_char slave, char *byte);
7926238Swpaulstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
8026238Swpaulstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
8126238Swpaulstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
8287204Smarkmstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
8395633Smarkmstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
8495633Smarkmstatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
8526238Swpaulstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
8626238Swpaulstatic void intsmb_start(device_t dev,u_char cmd,int nointr);
8726238Swpaulstatic int intsmb_stop(device_t dev);
8826238Swpaulstatic int intsmb_stop_poll(device_t dev);
8926238Swpaulstatic int intsmb_free(device_t dev);
9026238Swpaulstatic int intpm_probe (device_t dev);
9126238Swpaulstatic int intpm_attach (device_t dev);
9226238Swpaulstatic devclass_t intsmb_devclass;
9326238Swpaul
9426238Swpaulstatic device_method_t intpm_methods[]={
9526238Swpaul        DEVMETHOD(device_probe,intsmb_probe),
9626238Swpaul        DEVMETHOD(device_attach,intsmb_attach),
9726238Swpaul
9826238Swpaul        DEVMETHOD(bus_print_child, intsmb_print_child),
9926238Swpaul
10026238Swpaul        DEVMETHOD(smbus_callback,intsmb_callback),
10126238Swpaul        DEVMETHOD(smbus_quick,intsmb_quick),
10226238Swpaul        DEVMETHOD(smbus_sendb,intsmb_sendb),
10326238Swpaul        DEVMETHOD(smbus_recvb,intsmb_recvb),
10426238Swpaul        DEVMETHOD(smbus_writeb,intsmb_writeb),
10526238Swpaul        DEVMETHOD(smbus_writew,intsmb_writew),
10626238Swpaul        DEVMETHOD(smbus_readb,intsmb_readb),
10726238Swpaul        DEVMETHOD(smbus_readw,intsmb_readw),
10826238Swpaul        DEVMETHOD(smbus_pcall,intsmb_pcall),
10926238Swpaul        DEVMETHOD(smbus_bwrite,intsmb_bwrite),
11026238Swpaul        DEVMETHOD(smbus_bread,intsmb_bread),
11126238Swpaul        {0,0}
11226238Swpaul};
11326238Swpaul
11426238Swpaulstruct intpm_pci_softc{
11526238Swpaul        bus_space_tag_t smbst;
11626238Swpaul        bus_space_handle_t smbsh;
11726238Swpaul	bus_space_tag_t pmst;
11826238Swpaul	bus_space_handle_t pmsh;
11926238Swpaul        pcici_t cfg;
12026238Swpaul	device_t  smbus;
12126238Swpaul};
12226238Swpaul
12326238Swpaul
12426238Swpaulstruct intsmb_softc{
12526238Swpaul        struct intpm_pci_softc *pci_sc;
12626238Swpaul        bus_space_tag_t st;
12726238Swpaul        bus_space_handle_t sh;
12826238Swpaul        device_t smbus;
12926238Swpaul        int isbusy;
13026238Swpaul};
13126238Swpaul
13226238Swpaulstatic driver_t intpm_driver = {
13326238Swpaul        "intsmb",
13426238Swpaul        intpm_methods,
13526238Swpaul        sizeof(struct intsmb_softc),
13626238Swpaul};
13726238Swpaul
13826238Swpaulstatic devclass_t intpm_devclass;
13926238Swpaulstatic device_method_t intpm_pci_methods[] = {
14026238Swpaul  DEVMETHOD(device_probe,intpm_probe),
14187204Smarkm  DEVMETHOD(device_attach,intpm_attach),
14295633Smarkm  {0,0}
14326238Swpaul};
14426238Swpaulstatic driver_t intpm_pci_driver = {
14526238Swpaul  "intpm",
14626238Swpaul  intpm_pci_methods,
14726238Swpaul  sizeof(struct intpm_pci_softc)
14826238Swpaul};
14926238Swpaul
15026238Swpaulstatic int
15126238Swpaulintsmb_probe(device_t dev)
15226238Swpaul{
15326238Swpaul        struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
15426238Swpaul        sc->smbus=smbus_alloc_bus(dev);
15526238Swpaul        if (!sc->smbus)
15626238Swpaul                return (EINVAL);    /* XXX don't know what to return else */
15726238Swpaul        device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
15826238Swpaul
15926238Swpaul        return (0);          /* XXX don't know what to return else */
16026238Swpaul}
16126238Swpaulstatic int
16226238Swpaulintsmb_attach(device_t dev)
16326238Swpaul{
16426238Swpaul        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
16526238Swpaul        sc->pci_sc=device_get_softc(device_get_parent(dev));
16626238Swpaul        sc->isbusy=0;
16726238Swpaul	sc->sh=sc->pci_sc->smbsh;
16826238Swpaul	sc->st=sc->pci_sc->smbst;
16926238Swpaul	sc->pci_sc->smbus=dev;
17026238Swpaul        device_probe_and_attach(sc->smbus);
17126238Swpaul#ifdef ENABLE_ALART
17226238Swpaul	/*Enable Arart*/
17326238Swpaul	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
17426238Swpaul			  PIIX4_SMBSLVCNT_ALTEN);
17526238Swpaul#endif
17626238Swpaul        return (0);
17726238Swpaul}
17879452Sbrian
17926238Swpaulstatic void
18026238Swpaulintsmb_print_child(device_t bus, device_t dev)
18126238Swpaul{
18226238Swpaul	printf(" on %s%d", device_get_name(bus), device_get_unit(bus));
18326238Swpaul	return;
18426238Swpaul}
18526238Swpaulstatic int
18626238Swpaulintsmb_callback(device_t dev, int index, caddr_t data)
18726238Swpaul{
18826238Swpaul	int error = 0;
18926238Swpaul	intrmask_t s;
19026238Swpaul	s=splnet();
19126238Swpaul	switch (index) {
19226238Swpaul	case SMB_REQUEST_BUS:
19326238Swpaul		break;
19426238Swpaul	case SMB_RELEASE_BUS:
19526238Swpaul		break;
19626238Swpaul	default:
19726238Swpaul		error = EINVAL;
19826238Swpaul	}
19926238Swpaul	splx(s);
20026238Swpaul	return (error);
20126238Swpaul}
20226238Swpaul/*counterpart of smbtx_smb_free*/
20326238Swpaulstatic        int
20426238Swpaulintsmb_free(device_t dev){
20526238Swpaul        intrmask_t s;
20626238Swpaul        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
20795633Smarkm        if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)&
20826238Swpaul	    PIIX4_SMBHSTSTAT_BUSY)
20926238Swpaul#ifdef ENABLE_ALART
21026238Swpaul	   ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)&
21126238Swpaul	      PIIX4_SMBSLVSTS_BUSY)
21226238Swpaul#endif
21326238Swpaul	   || sc->isbusy)
21426238Swpaul                return EBUSY;
21526238Swpaul	s=splhigh();
21626238Swpaul        sc->isbusy=1;
21726238Swpaul	/*Disable Intrrupt in slave part*/
21826238Swpaul#ifndef ENABLE_ALART
21926238Swpaul	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0);
22026238Swpaul#endif
22126238Swpaul        /*Reset INTR Flag to prepare INTR*/
22226238Swpaul	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS,
22326238Swpaul			  (PIIX4_SMBHSTSTAT_INTR|
22426238Swpaul			   PIIX4_SMBHSTSTAT_ERR|
22526238Swpaul			   PIIX4_SMBHSTSTAT_BUSC|
22626238Swpaul			   PIIX4_SMBHSTSTAT_FAIL)
22726238Swpaul		);
22895633Smarkm	splx(s);
22926238Swpaul        return 0;
23026238Swpaul}
23126238Swpaul
23226238Swpaulstatic int
23326238Swpaulintsmb_intr(device_t dev)
23426238Swpaul{
23526238Swpaul	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
236141482Sstefanf	int status;
237189169Sed	status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
238189169Sed	if(status&PIIX4_SMBHSTSTAT_BUSY){
23926238Swpaul		return 1;
24026238Swpaul
24126238Swpaul	}
24226238Swpaul	if(status&(PIIX4_SMBHSTSTAT_INTR|
24326238Swpaul				PIIX4_SMBHSTSTAT_ERR|
24426238Swpaul				PIIX4_SMBHSTSTAT_BUSC|
24526238Swpaul				PIIX4_SMBHSTSTAT_FAIL)){
24626238Swpaul		int tmp;
24726238Swpaul		tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
24826238Swpaul		bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
24926238Swpaul				  tmp&~PIIX4_SMBHSTCNT_INTREN);
25026238Swpaul		if(sc->isbusy){
25126238Swpaul		  sc->isbusy=0;
25226238Swpaul		  wakeup(sc);
25326238Swpaul		}
25426238Swpaul		return 0;
25526238Swpaul	}
25626238Swpaul	return 1;/* Not Completed*/
25726238Swpaul}
25826238Swpaulstatic int
25926238Swpaulintsmb_slvintr(device_t dev)
26026238Swpaul{
26126238Swpaul	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
26226238Swpaul        int status,retval;
26326238Swpaul	retval=1;
26426238Swpaul        status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS);
26526238Swpaul	if(status&PIIX4_SMBSLVSTS_BUSY)
26626238Swpaul		return retval;
26726238Swpaul	if(status&PIIX4_SMBSLVSTS_ALART){
26826238Swpaul		intsmb_alrintr(dev);
269344193Savos		retval=0;
270344193Savos	}else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2
27126238Swpaul			  |PIIX4_SMBSLVSTS_SDW1)){
27226238Swpaul		retval=0;
27326238Swpaul	}
274344193Savos	/*Reset Status Register*/
275344193Savos	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART|
276344193Savos			  PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1|
27726238Swpaul			  PIIX4_SMBSLVSTS_SLV);
27826238Swpaul	return retval;
27926238Swpaul}
28026238Swpaul
28126238Swpaulstatic void intsmb_alrintr(device_t dev)
28226238Swpaul{
28326238Swpaul	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
28426238Swpaul	int slvcnt;
28526238Swpaul#ifdef ENABLE_ALART
28626238Swpaul	int error;
28726238Swpaul#endif
28826238Swpaul
28926238Swpaul	/*stop generating INTR from ALART*/
29026238Swpaul	slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT);
29126238Swpaul#ifdef ENABLE_ALART
29226238Swpaul	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
29326238Swpaul			  slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ;
29426238Swpaul#endif
29526238Swpaul	DELAY(5);
29626238Swpaul	/*ask bus who assert it and then ask it what's the matter. */
29726238Swpaul#ifdef ENABLE_ALART
29826238Swpaul	error=intsmb_free(dev);
29926238Swpaul	if(!error){
30026238Swpaul                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP
30126238Swpaul                                  |LSB);
30226238Swpaul		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1);
30326238Swpaul		if(!(error=intsmb_stop_poll(dev))){
30426238Swpaul			volatile u_int8_t *addr;
30526238Swpaul			addr=bus_space_read_1(sc->st,sc->sh,
30626238Swpaul					      PIIX4_SMBHSTDAT0);
30726238Swpaul			printf("ALART_RESPONSE: %p\n", addr);
30826238Swpaul		}
30926238Swpaul	}else{
31026238Swpaul	        printf("ERROR\n");
31126238Swpaul	}
31226238Swpaul
31326238Swpaul	/*Re-enable INTR from ALART*/
31426238Swpaul	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
31526238Swpaul			  slvcnt|PIIX4_SMBSLVCNT_ALTEN) ;
316344193Savos	DELAY(5);
317344193Savos#endif
31826238Swpaul
31926238Swpaul	return;
32026238Swpaul}
321344193Savosstatic void
322344193Savosintsmb_start(device_t dev,unsigned char cmd,int nointr)
32326238Swpaul{
32426238Swpaul	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
325344193Savos	unsigned char tmp;
326344193Savos	tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
327344193Savos	tmp&= 0xe0;
32826238Swpaul	tmp |= cmd;
32926238Swpaul	tmp |=PIIX4_SMBHSTCNT_START;
33026238Swpaul	/*While not in autoconfiguration Intrrupt Enabled*/
331141482Sstefanf	if(!cold||!nointr)
33295633Smarkm		tmp |=PIIX4_SMBHSTCNT_INTREN;
33326238Swpaul	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp);
33426238Swpaul}
33526238Swpaul
33626238Swpaul/*Polling Code. Polling is not encouraged
33726238Swpaul * because It is required to wait for the device get busy.
33826238Swpaul *(29063505.pdf from Intel)
33926238Swpaul * But during boot,intrrupt cannot be used.
34026238Swpaul * so use polling code while in autoconfiguration.
341 */
342
343static        int
344intsmb_stop_poll(device_t dev){
345        int error,i;
346        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
347
348	/*
349	 *  In smbtx driver ,Simply waiting.
350	 *  This loops 100-200 times.
351	 */
352	for(i=0;i<0x7fff;i++){
353                if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)
354		    &PIIX4_SMBHSTSTAT_BUSY)){
355                        break;
356                }
357	}
358	for(i=0;i<0x7fff;i++){
359		int status;
360		status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
361		if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
362			sc->isbusy=0;
363			error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
364				(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
365				(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
366			if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
367				printf("unknown cause why?");
368			}
369			return error;
370		}
371	}
372	{
373	  int tmp;
374	  sc->isbusy=0;
375	  tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
376	  bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
377			    tmp&~PIIX4_SMBHSTCNT_INTREN);
378	}
379	return EIO;
380}
381/*
382 *wait for completion and return result.
383 */
384static        int
385intsmb_stop(device_t dev){
386        int error;
387	intrmask_t s;
388        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
389	if(cold){
390		/*So that it can use device during probing device on SMBus.*/
391		error=intsmb_stop_poll(dev);
392		return error;
393	}else{
394		if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){
395			int status;
396			status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
397			if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
398				error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
399					(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
400					(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
401				if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
402					printf("intsmb%d:unknown cause why?\n",
403					       device_get_unit(dev));
404				}
405#ifdef ENABLE_ALART
406				bus_space_write_1(sc->st,sc->sh,
407						  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
408#endif
409				return error;
410			}
411		}
412	}
413	/*Timeout Procedure*/
414	s=splhigh();
415	sc->isbusy=0;
416	/*Re-enable supressed intrrupt from slave part*/
417	bus_space_write_1(sc->st,sc->sh,
418			  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
419	splx(s);
420        return EIO;
421}
422
423static int
424intsmb_quick(device_t dev, u_char slave, int how)
425{
426        int error=0;
427        u_char data;
428        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
429        data=slave;
430	/*Quick command is part of Address, I think*/
431        switch(how){
432        case SMB_QWRITE:
433                data&=~LSB;
434		break;
435        case SMB_QREAD:
436                data|=LSB;
437                break;
438        default:
439                error=EINVAL;
440        }
441        if(!error){
442	        error=intsmb_free(dev);
443                if(!error){
444                        bus_space_write_1(sc->st,sc->sh,
445					  PIIX4_SMBHSTADD,data);
446			intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0);
447                        error=intsmb_stop(dev);
448                }
449        }
450
451        return (error);
452}
453
454static int
455intsmb_sendb(device_t dev, u_char slave, char byte)
456{
457        int error;
458        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
459        error=intsmb_free(dev);
460        if(!error){
461                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
462                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte);
463		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
464                error=intsmb_stop(dev);
465        }
466        return (error);
467}
468static int
469intsmb_recvb(device_t dev, u_char slave, char *byte)
470{
471        int error;
472        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
473        error=intsmb_free(dev);
474        if(!error){
475                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave
476				  |LSB);
477                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
478                if(!(error=intsmb_stop(dev))){
479#ifdef RECV_IS_IN_CMD
480		        /*Linux SMBus stuff also troubles
481			  Because Intel's datasheet will not make clear.
482			 */
483                        *byte=bus_space_read_1(sc->st,sc->sh,
484					       PIIX4_SMBHSTCMD);
485#else
486                        *byte=bus_space_read_1(sc->st,sc->sh,
487					       PIIX4_SMBHSTDAT0);
488#endif
489                }
490        }
491        return (error);
492}
493static int
494intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
495{
496        int error;
497        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
498        error=intsmb_free(dev);
499        if(!error){
500                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
501                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
502                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte);
503		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
504                error=intsmb_stop(dev);
505        }
506        return (error);
507}
508static int
509intsmb_writew(device_t dev, u_char slave, char cmd, short word)
510{
511        int error;
512        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
513        error=intsmb_free(dev);
514        if(!error){
515                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
516                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
517                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,
518				  word&0xff);
519                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,
520				  (word>>8)&0xff);
521		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
522                error=intsmb_stop(dev);
523        }
524        return (error);
525}
526
527static int
528intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
529{
530        int error;
531        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
532        error=intsmb_free(dev);
533        if(!error){
534                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
535                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
536		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
537                if(!(error=intsmb_stop(dev))){
538		        *byte=bus_space_read_1(sc->st,sc->sh,
539					       PIIX4_SMBHSTDAT0);
540                }
541        }
542        return (error);
543}
544static int
545intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
546{
547        int error;
548        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
549        error=intsmb_free(dev);
550        if(!error){
551                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
552                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
553		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
554                if(!(error=intsmb_stop(dev))){
555                        *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
556                        *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
557                }
558        }
559        return (error);
560}
561/*
562 * Data sheet claims that it implements all function, but also claims
563 * that it implements 7 function and not mention PCALL. So I don't know
564 * whether it will work.
565 */
566static int
567intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
568{
569#ifdef PROCCALL_TEST
570        int error;
571        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
572        error=intsmb_free(dev);
573        if(!error){
574                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
575                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
576                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff);
577                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8);
578                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
579        }
580        if(!(error=intsmb_stop(dev))){
581                *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
582                *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
583        }
584        return error;
585#else
586	return 0;
587#endif
588}
589static int
590intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
591{
592        int error,i;
593        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
594        error=intsmb_free(dev);
595        if(count>SMBBLOCKTRANS_MAX||count==0)
596                error=EINVAL;
597        if(!error){
598                /*Reset internal array index*/
599                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
600
601                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
602                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
603                for(i=0;i<count;i++){
604                        bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]);
605                }
606                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
607                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
608                error=intsmb_stop(dev);
609        }
610        return (error);
611}
612
613static int
614intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
615{
616        int error,i;
617        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
618        error=intsmb_free(dev);
619        if(count>SMBBLOCKTRANS_MAX||count==0)
620                error=EINVAL;
621        if(!error){
622                /*Reset internal array index*/
623                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
624
625                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
626                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
627                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
628                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
629                error=intsmb_stop(dev);
630                if(!error){
631                        bzero(buf,count);/*Is it needed?*/
632                        count= bus_space_read_1(sc->st,sc->sh,
633						PIIX4_SMBHSTDAT0);
634                        if(count!=0&&count<=SMBBLOCKTRANS_MAX){
635			        for(i=0;i<count;i++){
636				        buf[i]=bus_space_read_1(sc->st,
637								sc->sh,
638								PIIX4_SMBBLKDAT);
639				}
640			}
641                        else{
642				error=EIO;
643                        }
644		}
645	}
646        return (error);
647}
648
649DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0);
650
651
652static void intpm_intr __P((void *arg));
653static int
654intpm_attach(device_t dev)
655{
656        int value;
657        int unit=device_get_unit(dev);
658	void *ih;
659	int error;
660        char * str;
661        {
662                struct intpm_pci_softc *sciic;
663                device_t smbinterface;
664		int rid;
665		struct resource *res;
666
667                sciic=device_get_softc(dev);
668                if(sciic==NULL){
669                        return ENOMEM;
670                }
671
672		rid=PCI_BASE_ADDR_SMB;
673#if 0
674		res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,
675				       0,~0,1,RF_ACTIVE);
676		if(res==NULL){
677		  device_printf(dev,"IO FAILED Trying Memory\n");
678		  res=bus_alloc_resource(dev,SYS_RES_MEMORY,&rid,0,~0,
679					 1,RF_ACTIVE);
680		}
681#else
682		/*Do as I tell!*/
683		value=pci_read_config(dev,rid,4);
684		res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,value&(~1),
685				       (value&(~1))+256,256,RF_ACTIVE);
686#endif
687		if(res==NULL){
688		  device_printf(dev,"Could not allocate Bus space\n");
689		  return ENXIO;
690		}
691		sciic->smbst=rman_get_bustag(res);
692		sciic->smbsh=rman_get_bushandle(res);
693
694		device_printf(dev,"%s %x\n",
695			      (sciic->smbst==I386_BUS_SPACE_IO)?
696			      "I/O mapped":"Memory",
697			      sciic->smbsh);
698
699
700#ifndef NO_CHANGE_PCICONF
701		pci_write_config(dev,PCIR_INTLINE,0x9,1);
702		pci_write_config(dev,PCI_HST_CFG_SMB,
703				 PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1);
704#endif
705                value=pci_read_config(dev,PCI_HST_CFG_SMB,1);
706                switch(value&0xe){
707                case PCI_INTR_SMB_SMI:
708		        str="SMI";
709                        break;
710                case PCI_INTR_SMB_IRQ9:
711                        str="IRQ 9";
712                        break;
713                default:
714                        str="BOGUS";
715                }
716                device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled"));
717                value=pci_read_config(dev,PCI_REVID_SMB,1);
718                printf("revision %d\n",value);
719                /*
720                 * Install intr HANDLER here
721                 */
722		rid=0;
723		res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE);
724		if(res==NULL){
725		  device_printf(dev,"could not allocate irq");
726		  return ENOMEM;
727		}
728		error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih);
729                if(error){
730                        device_printf(dev,"Failed to map intr\n");
731			return error;
732                }
733                smbinterface=device_add_child(dev,"intsmb",unit,NULL);
734		if(!smbinterface){
735		     printf("intsmb%d:could not add SMBus device\n",unit);
736		}
737                device_probe_and_attach(smbinterface);
738        }
739
740        value=pci_read_config(dev,PCI_BASE_ADDR_PM,4);
741        printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe);
742        return 0;
743}
744static int
745intpm_probe(device_t dev)
746{
747    struct _pcsid *ep =pci_ids;
748    u_int32_t device_id=pci_get_devid(dev);
749
750    while (ep->type && ep->type != device_id)
751	  ++ep;
752    if(ep->desc!=NULL){
753      device_set_desc(dev,ep->desc);
754      return 0;
755    }else{
756      return ENXIO;
757    }
758}
759DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0);
760
761static void intpm_intr(void *arg)
762{
763        struct intpm_pci_softc *sc;
764        sc=(struct intpm_pci_softc *)arg;
765	intsmb_intr(sc->smbus);
766	intsmb_slvintr(sc->smbus);
767
768}
769