intpm.c revision 67164
1253572Sloos/*-
2253572Sloos * Copyright (c) 1998, 1999 Takanori Watanabe
3253572Sloos * All rights reserved.
4253572Sloos *
5253572Sloos * Redistribution and use in source and binary forms, with or without
6253572Sloos * modification, are permitted provided that the following conditions
7253572Sloos * are met:
8253572Sloos * 1. Redistributions of source code must retain the above copyright
9253572Sloos *        notice, this list of conditions and the following disclaimer.
10253572Sloos * 2. Redistributions in binary form must reproduce the above copyright
11253572Sloos *        notice, this list of conditions and the following disclaimer in the
12253572Sloos *        documentation and/or other materials provided with the distribution.
13253572Sloos *
14253572Sloos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15253572Sloos * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16253572Sloos * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17253572Sloos * ARE DISCLAIMED.    IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18253572Sloos * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19253572Sloos * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20253572Sloos * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21253572Sloos * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22253572Sloos * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23253572Sloos * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24253572Sloos * SUCH DAMAGE.
25253572Sloos *
26253572Sloos * $FreeBSD: head/sys/pci/intpm.c 67164 2000-10-15 14:19:01Z phk $
27253572Sloos */
28253572Sloos
29253572Sloos#include <sys/param.h>
30253572Sloos#include <sys/systm.h>
31253572Sloos#include <sys/kernel.h>
32253572Sloos#include <machine/bus_pio.h>
33253572Sloos#include <machine/bus_memio.h>
34257284Sglebius#include <machine/bus.h>
35253572Sloos
36257284Sglebius#include <sys/uio.h>
37253572Sloos#include <sys/module.h>
38253572Sloos#include <sys/bus.h>
39253572Sloos#include <sys/rman.h>
40253572Sloos#include <machine/resource.h>
41253572Sloos#include <dev/smbus/smbconf.h>
42253572Sloos
43253572Sloos#include "smbus_if.h"
44253572Sloos
45253572Sloos/*This should be removed if force_pci_map_int supported*/
46253572Sloos#include <sys/interrupt.h>
47253572Sloos
48253572Sloos#include <pci/pcireg.h>
49253572Sloos#include <pci/pcivar.h>
50253572Sloos#include <pci/intpmreg.h>
51253572Sloos
52253572Sloos#include "opt_intpm.h"
53256583Sadrian
54256583Sadrianstatic struct _pcsid
55256583Sadrian{
56256583Sadrian        u_int32_t type;
57253572Sloos	char	*desc;
58279797Sadrian} pci_ids[] =
59253572Sloos{
60253572Sloos	{ 0x71138086,"Intel 82371AB Power management controller"},
61253572Sloos
62253572Sloos	{ 0x00000000,	NULL					}
63253572Sloos};
64253572Sloosstatic int intsmb_probe(device_t);
65253572Sloosstatic int intsmb_attach(device_t);
66253572Sloos
67253572Sloosstatic int intsmb_intr(device_t dev);
68253572Sloosstatic int intsmb_slvintr(device_t dev);
69253572Sloosstatic void  intsmb_alrintr(device_t dev);
70253572Sloosstatic int intsmb_callback(device_t dev, int index, caddr_t data);
71253572Sloosstatic int intsmb_quick(device_t dev, u_char slave, int how);
72253572Sloosstatic int intsmb_sendb(device_t dev, u_char slave, char byte);
73253572Sloosstatic int intsmb_recvb(device_t dev, u_char slave, char *byte);
74253572Sloosstatic int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
75253572Sloosstatic int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
76253572Sloosstatic int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
77253572Sloosstatic int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
78253572Sloosstatic int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
79253572Sloosstatic int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
80253572Sloosstatic int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
81253572Sloosstatic void intsmb_start(device_t dev,u_char cmd,int nointr);
82253572Sloosstatic int intsmb_stop(device_t dev);
83253572Sloosstatic int intsmb_stop_poll(device_t dev);
84253572Sloosstatic int intsmb_free(device_t dev);
85253572Sloosstatic int intpm_probe (device_t dev);
86253572Sloosstatic int intpm_attach (device_t dev);
87253572Sloosstatic devclass_t intsmb_devclass;
88279797Sadrian
89279797Sadrianstatic device_method_t intpm_methods[]={
90253572Sloos        DEVMETHOD(device_probe,intsmb_probe),
91253572Sloos        DEVMETHOD(device_attach,intsmb_attach),
92253572Sloos
93279797Sadrian        DEVMETHOD(bus_print_child, bus_generic_print_child),
94253572Sloos
95253572Sloos        DEVMETHOD(smbus_callback,intsmb_callback),
96279797Sadrian        DEVMETHOD(smbus_quick,intsmb_quick),
97279797Sadrian        DEVMETHOD(smbus_sendb,intsmb_sendb),
98253572Sloos        DEVMETHOD(smbus_recvb,intsmb_recvb),
99253572Sloos        DEVMETHOD(smbus_writeb,intsmb_writeb),
100253572Sloos        DEVMETHOD(smbus_writew,intsmb_writew),
101279797Sadrian        DEVMETHOD(smbus_readb,intsmb_readb),
102253572Sloos        DEVMETHOD(smbus_readw,intsmb_readw),
103253572Sloos        DEVMETHOD(smbus_pcall,intsmb_pcall),
104279790Sadrian        DEVMETHOD(smbus_bwrite,intsmb_bwrite),
105279943Sadrian        DEVMETHOD(smbus_bread,intsmb_bread),
106279943Sadrian        {0,0}
107253572Sloos};
108253572Sloos
109253572Sloosstruct intpm_pci_softc{
110253572Sloos        bus_space_tag_t smbst;
111253572Sloos        bus_space_handle_t smbsh;
112279797Sadrian	bus_space_tag_t pmst;
113253572Sloos	bus_space_handle_t pmsh;
114253572Sloos	device_t  smbus;
115253572Sloos};
116253572Sloos
117253572Sloos
118253572Sloosstruct intsmb_softc{
119253572Sloos        struct intpm_pci_softc *pci_sc;
120253572Sloos        bus_space_tag_t st;
121253572Sloos        bus_space_handle_t sh;
122253572Sloos        device_t smbus;
123279943Sadrian        int isbusy;
124253572Sloos};
125253572Sloos
126253572Sloosstatic driver_t intpm_driver = {
127279790Sadrian        "intsmb",
128279943Sadrian        intpm_methods,
129279943Sadrian        sizeof(struct intsmb_softc),
130253572Sloos};
131253572Sloos
132253572Sloosstatic devclass_t intpm_devclass;
133253572Sloosstatic device_method_t intpm_pci_methods[] = {
134279797Sadrian  DEVMETHOD(device_probe,intpm_probe),
135253572Sloos  DEVMETHOD(device_attach,intpm_attach),
136253572Sloos  {0,0}
137253572Sloos};
138253572Sloosstatic driver_t intpm_pci_driver = {
139253572Sloos  "intpm",
140279790Sadrian  intpm_pci_methods,
141279790Sadrian  sizeof(struct intpm_pci_softc)
142253572Sloos};
143253572Sloos
144253572Sloosstatic int
145253572Sloosintsmb_probe(device_t dev)
146253572Sloos{
147253572Sloos        struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
148253572Sloos        sc->smbus=smbus_alloc_bus(dev);
149253572Sloos        if (!sc->smbus)
150253572Sloos                return (EINVAL);    /* XXX don't know what to return else */
151253572Sloos        device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
152253572Sloos
153253572Sloos        return (0);          /* XXX don't know what to return else */
154253572Sloos}
155279790Sadrianstatic int
156279790Sadrianintsmb_attach(device_t dev)
157253572Sloos{
158253572Sloos        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
159253572Sloos        sc->pci_sc=device_get_softc(device_get_parent(dev));
160253572Sloos        sc->isbusy=0;
161253572Sloos	sc->sh=sc->pci_sc->smbsh;
162253572Sloos	sc->st=sc->pci_sc->smbst;
163253572Sloos	sc->pci_sc->smbus=dev;
164253572Sloos        device_probe_and_attach(sc->smbus);
165253572Sloos#ifdef ENABLE_ALART
166253572Sloos	/*Enable Arart*/
167253572Sloos	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
168253572Sloos			  PIIX4_SMBSLVCNT_ALTEN);
169253572Sloos#endif
170253572Sloos        return (0);
171253572Sloos}
172253572Sloos
173253572Sloosstatic int
174253572Sloosintsmb_callback(device_t dev, int index, caddr_t data)
175262429Sadrian{
176253572Sloos	int error = 0;
177253572Sloos	intrmask_t s;
178253572Sloos	s=splnet();
179253572Sloos	switch (index) {
180253572Sloos	case SMB_REQUEST_BUS:
181253572Sloos		break;
182253572Sloos	case SMB_RELEASE_BUS:
183253572Sloos		break;
184253572Sloos	default:
185253572Sloos		error = EINVAL;
186253572Sloos	}
187253572Sloos	splx(s);
188253572Sloos	return (error);
189253572Sloos}
190253572Sloos/*counterpart of smbtx_smb_free*/
191253572Sloosstatic        int
192253572Sloosintsmb_free(device_t dev){
193253572Sloos        intrmask_t s;
194253572Sloos        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
195253572Sloos        if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)&
196253572Sloos	    PIIX4_SMBHSTSTAT_BUSY)
197279797Sadrian#ifdef ENABLE_ALART
198253572Sloos	   ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)&
199253572Sloos	      PIIX4_SMBSLVSTS_BUSY)
200253572Sloos#endif
201253572Sloos	   || sc->isbusy)
202253572Sloos                return EBUSY;
203253572Sloos	s=splhigh();
204253572Sloos        sc->isbusy=1;
205253572Sloos	/*Disable Intrrupt in slave part*/
206253572Sloos#ifndef ENABLE_ALART
207253572Sloos	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0);
208253572Sloos#endif
209253572Sloos        /*Reset INTR Flag to prepare INTR*/
210253572Sloos	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS,
211253572Sloos			  (PIIX4_SMBHSTSTAT_INTR|
212253572Sloos			   PIIX4_SMBHSTSTAT_ERR|
213253572Sloos			   PIIX4_SMBHSTSTAT_BUSC|
214253572Sloos			   PIIX4_SMBHSTSTAT_FAIL)
215253572Sloos		);
216253572Sloos	splx(s);
217253572Sloos        return 0;
218253572Sloos}
219253572Sloos
220253572Sloosstatic int
221253572Sloosintsmb_intr(device_t dev)
222253572Sloos{
223253572Sloos	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
224262429Sadrian	int status;
225253572Sloos	status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
226253572Sloos	if(status&PIIX4_SMBHSTSTAT_BUSY){
227253572Sloos		return 1;
228279943Sadrian
229253572Sloos	}
230253572Sloos	if(status&(PIIX4_SMBHSTSTAT_INTR|
231253572Sloos				PIIX4_SMBHSTSTAT_ERR|
232253572Sloos				PIIX4_SMBHSTSTAT_BUSC|
233253572Sloos				PIIX4_SMBHSTSTAT_FAIL)){
234253572Sloos		int tmp;
235253572Sloos		tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
236253572Sloos		bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
237253572Sloos				  tmp&~PIIX4_SMBHSTCNT_INTREN);
238253572Sloos		if(sc->isbusy){
239253572Sloos		  sc->isbusy=0;
240253572Sloos		  wakeup(sc);
241253572Sloos		}
242253572Sloos		return 0;
243253572Sloos	}
244253572Sloos	return 1;/* Not Completed*/
245279943Sadrian}
246253572Sloosstatic int
247253572Sloosintsmb_slvintr(device_t dev)
248253572Sloos{
249253572Sloos	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
250253572Sloos        int status,retval;
251253572Sloos	retval=1;
252253572Sloos        status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS);
253253572Sloos	if(status&PIIX4_SMBSLVSTS_BUSY)
254253572Sloos		return retval;
255253572Sloos	if(status&PIIX4_SMBSLVSTS_ALART){
256253572Sloos		intsmb_alrintr(dev);
257253572Sloos		retval=0;
258253572Sloos	}else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2
259253572Sloos			  |PIIX4_SMBSLVSTS_SDW1)){
260253572Sloos		retval=0;
261253572Sloos	}
262253572Sloos	/*Reset Status Register*/
263253572Sloos	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART|
264262429Sadrian			  PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1|
265253572Sloos			  PIIX4_SMBSLVSTS_SLV);
266253572Sloos	return retval;
267253572Sloos}
268253572Sloos
269253572Sloosstatic void intsmb_alrintr(device_t dev)
270253572Sloos{
271253572Sloos	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
272253572Sloos	int slvcnt;
273253572Sloos#ifdef ENABLE_ALART
274253572Sloos	int error;
275253572Sloos#endif
276253572Sloos
277253572Sloos	/*stop generating INTR from ALART*/
278253572Sloos	slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT);
279253572Sloos#ifdef ENABLE_ALART
280253572Sloos	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
281253572Sloos			  slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ;
282253572Sloos#endif
283253572Sloos	DELAY(5);
284253572Sloos	/*ask bus who assert it and then ask it what's the matter. */
285253572Sloos#ifdef ENABLE_ALART
286253572Sloos	error=intsmb_free(dev);
287253572Sloos	if(!error){
288253572Sloos                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP
289253572Sloos                                  |LSB);
290253572Sloos		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1);
291279790Sadrian		if(!(error=intsmb_stop_poll(dev))){
292279943Sadrian			volatile u_int8_t *addr;
293253572Sloos			addr=bus_space_read_1(sc->st,sc->sh,
294253572Sloos					      PIIX4_SMBHSTDAT0);
295253572Sloos			printf("ALART_RESPONSE: %p\n", addr);
296279790Sadrian		}
297253572Sloos	}else{
298279943Sadrian	        printf("ERROR\n");
299253572Sloos	}
300253572Sloos
301253572Sloos	/*Re-enable INTR from ALART*/
302279943Sadrian	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
303253572Sloos			  slvcnt|PIIX4_SMBSLVCNT_ALTEN) ;
304253572Sloos	DELAY(5);
305253572Sloos#endif
306279943Sadrian
307253572Sloos	return;
308253572Sloos}
309253572Sloosstatic void
310253572Sloosintsmb_start(device_t dev,unsigned char cmd,int nointr)
311262429Sadrian{
312253572Sloos	struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
313253572Sloos	unsigned char tmp;
314253572Sloos	tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
315253572Sloos	tmp&= 0xe0;
316253572Sloos	tmp |= cmd;
317253572Sloos	tmp |=PIIX4_SMBHSTCNT_START;
318253572Sloos	/*While not in autoconfiguration Intrrupt Enabled*/
319253572Sloos	if(!cold||!nointr)
320253572Sloos		tmp |=PIIX4_SMBHSTCNT_INTREN;
321253572Sloos	bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp);
322253572Sloos}
323253572Sloos
324253572Sloos/*Polling Code. Polling is not encouraged
325253572Sloos * because It is required to wait for the device get busy.
326253572Sloos *(29063505.pdf from Intel)
327253572Sloos * But during boot,intrrupt cannot be used.
328253572Sloos * so use polling code while in autoconfiguration.
329253572Sloos */
330253572Sloos
331279797Sadrianstatic        int
332253572Sloosintsmb_stop_poll(device_t dev){
333253572Sloos        int error,i;
334253572Sloos        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
335253572Sloos
336253572Sloos	/*
337253572Sloos	 *  In smbtx driver ,Simply waiting.
338253572Sloos	 *  This loops 100-200 times.
339253572Sloos	 */
340253572Sloos	for(i=0;i<0x7fff;i++){
341253572Sloos                if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)
342253572Sloos		    &PIIX4_SMBHSTSTAT_BUSY)){
343253572Sloos                        break;
344253572Sloos                }
345253572Sloos	}
346253572Sloos	for(i=0;i<0x7fff;i++){
347253572Sloos		int status;
348253572Sloos		status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
349253572Sloos		if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
350253572Sloos			sc->isbusy=0;
351253572Sloos			error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
352253572Sloos				(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
353279943Sadrian				(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
354279943Sadrian			if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
355253572Sloos				printf("unknown cause why?");
356253572Sloos			}
357279790Sadrian			return error;
358253572Sloos		}
359253572Sloos	}
360253572Sloos	{
361253572Sloos	  int tmp;
362253572Sloos	  sc->isbusy=0;
363253572Sloos	  tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
364253572Sloos	  bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
365253572Sloos			    tmp&~PIIX4_SMBHSTCNT_INTREN);
366253572Sloos	}
367262429Sadrian	return EIO;
368253572Sloos}
369253572Sloos/*
370253572Sloos *wait for completion and return result.
371253572Sloos */
372253572Sloosstatic        int
373253572Sloosintsmb_stop(device_t dev){
374253572Sloos        int error;
375253572Sloos	intrmask_t s;
376253572Sloos        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
377253572Sloos	if(cold){
378262429Sadrian		/*So that it can use device during probing device on SMBus.*/
379253572Sloos		error=intsmb_stop_poll(dev);
380253572Sloos		return error;
381253572Sloos	}else{
382253572Sloos		if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){
383253572Sloos			int status;
384253572Sloos			status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
385			if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
386				error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
387					(status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
388					(status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
389				if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
390					printf("intsmb%d:unknown cause why?\n",
391					       device_get_unit(dev));
392				}
393#ifdef ENABLE_ALART
394				bus_space_write_1(sc->st,sc->sh,
395						  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
396#endif
397				return error;
398			}
399		}
400	}
401	/*Timeout Procedure*/
402	s=splhigh();
403	sc->isbusy=0;
404	/*Re-enable supressed intrrupt from slave part*/
405	bus_space_write_1(sc->st,sc->sh,
406			  PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
407	splx(s);
408        return EIO;
409}
410
411static int
412intsmb_quick(device_t dev, u_char slave, int how)
413{
414        int error=0;
415        u_char data;
416        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
417        data=slave;
418	/*Quick command is part of Address, I think*/
419        switch(how){
420        case SMB_QWRITE:
421                data&=~LSB;
422		break;
423        case SMB_QREAD:
424                data|=LSB;
425                break;
426        default:
427                error=EINVAL;
428        }
429        if(!error){
430	        error=intsmb_free(dev);
431                if(!error){
432                        bus_space_write_1(sc->st,sc->sh,
433					  PIIX4_SMBHSTADD,data);
434			intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0);
435                        error=intsmb_stop(dev);
436                }
437        }
438
439        return (error);
440}
441
442static int
443intsmb_sendb(device_t dev, u_char slave, char byte)
444{
445        int error;
446        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
447        error=intsmb_free(dev);
448        if(!error){
449                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
450                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte);
451		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
452                error=intsmb_stop(dev);
453        }
454        return (error);
455}
456static int
457intsmb_recvb(device_t dev, u_char slave, char *byte)
458{
459        int error;
460        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
461        error=intsmb_free(dev);
462        if(!error){
463                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave
464				  |LSB);
465                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
466                if(!(error=intsmb_stop(dev))){
467#ifdef RECV_IS_IN_CMD
468		        /*Linux SMBus stuff also troubles
469			  Because Intel's datasheet will not make clear.
470			 */
471                        *byte=bus_space_read_1(sc->st,sc->sh,
472					       PIIX4_SMBHSTCMD);
473#else
474                        *byte=bus_space_read_1(sc->st,sc->sh,
475					       PIIX4_SMBHSTDAT0);
476#endif
477                }
478        }
479        return (error);
480}
481static int
482intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
483{
484        int error;
485        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
486        error=intsmb_free(dev);
487        if(!error){
488                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
489                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
490                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte);
491		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
492                error=intsmb_stop(dev);
493        }
494        return (error);
495}
496static int
497intsmb_writew(device_t dev, u_char slave, char cmd, short word)
498{
499        int error;
500        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
501        error=intsmb_free(dev);
502        if(!error){
503                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
504                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
505                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,
506				  word&0xff);
507                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,
508				  (word>>8)&0xff);
509		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
510                error=intsmb_stop(dev);
511        }
512        return (error);
513}
514
515static int
516intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
517{
518        int error;
519        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
520        error=intsmb_free(dev);
521        if(!error){
522                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
523                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
524		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
525                if(!(error=intsmb_stop(dev))){
526		        *byte=bus_space_read_1(sc->st,sc->sh,
527					       PIIX4_SMBHSTDAT0);
528                }
529        }
530        return (error);
531}
532static int
533intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
534{
535        int error;
536        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
537        error=intsmb_free(dev);
538        if(!error){
539                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
540                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
541		intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
542                if(!(error=intsmb_stop(dev))){
543                        *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
544                        *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
545                }
546        }
547        return (error);
548}
549/*
550 * Data sheet claims that it implements all function, but also claims
551 * that it implements 7 function and not mention PCALL. So I don't know
552 * whether it will work.
553 */
554static int
555intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
556{
557#ifdef PROCCALL_TEST
558        int error;
559        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
560        error=intsmb_free(dev);
561        if(!error){
562                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
563                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
564                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff);
565                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8);
566                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
567        }
568        if(!(error=intsmb_stop(dev))){
569                *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
570                *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
571        }
572        return error;
573#else
574	return 0;
575#endif
576}
577static int
578intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
579{
580        int error,i;
581        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
582        error=intsmb_free(dev);
583        if(count>SMBBLOCKTRANS_MAX||count==0)
584                error=EINVAL;
585        if(!error){
586                /*Reset internal array index*/
587                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
588
589                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
590                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
591                for(i=0;i<count;i++){
592                        bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]);
593                }
594                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
595                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
596                error=intsmb_stop(dev);
597        }
598        return (error);
599}
600
601static int
602intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
603{
604        int error,i;
605        struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
606        error=intsmb_free(dev);
607        if(count>SMBBLOCKTRANS_MAX||count==0)
608                error=EINVAL;
609        if(!error){
610                /*Reset internal array index*/
611                bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
612
613                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
614                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
615                bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
616                intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
617                error=intsmb_stop(dev);
618                if(!error){
619                        bzero(buf,count);/*Is it needed?*/
620                        count= bus_space_read_1(sc->st,sc->sh,
621						PIIX4_SMBHSTDAT0);
622                        if(count!=0&&count<=SMBBLOCKTRANS_MAX){
623			        for(i=0;i<count;i++){
624				        buf[i]=bus_space_read_1(sc->st,
625								sc->sh,
626								PIIX4_SMBBLKDAT);
627				}
628			}
629                        else{
630				error=EIO;
631                        }
632		}
633	}
634        return (error);
635}
636
637DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0);
638
639
640static void intpm_intr __P((void *arg));
641static int
642intpm_attach(device_t dev)
643{
644        int value;
645        int unit=device_get_unit(dev);
646	void *ih;
647	int error;
648        char * str;
649        {
650                struct intpm_pci_softc *sciic;
651                device_t smbinterface;
652		int rid;
653		struct resource *res;
654
655                sciic=device_get_softc(dev);
656                if(sciic==NULL){
657                        return ENOMEM;
658                }
659
660		rid=PCI_BASE_ADDR_SMB;
661		res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,
662				       0,~0,1,RF_ACTIVE);
663		if(res==NULL){
664		  device_printf(dev,"Could not allocate Bus space\n");
665		  return ENXIO;
666		}
667		sciic->smbst=rman_get_bustag(res);
668		sciic->smbsh=rman_get_bushandle(res);
669
670		device_printf(dev,"%s %x\n",
671			      (sciic->smbst==I386_BUS_SPACE_IO)?
672			      "I/O mapped":"Memory",
673			      sciic->smbsh);
674
675
676#ifndef NO_CHANGE_PCICONF
677		pci_write_config(dev,PCIR_INTLINE,0x9,1);
678		pci_write_config(dev,PCI_HST_CFG_SMB,
679				 PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1);
680#endif
681                value=pci_read_config(dev,PCI_HST_CFG_SMB,1);
682                switch(value&0xe){
683                case PCI_INTR_SMB_SMI:
684		        str="SMI";
685                        break;
686                case PCI_INTR_SMB_IRQ9:
687                        str="IRQ 9";
688                        break;
689                default:
690                        str="BOGUS";
691                }
692                device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled"));
693                value=pci_read_config(dev,PCI_REVID_SMB,1);
694                printf("revision %d\n",value);
695                /*
696                 * Install intr HANDLER here
697                 */
698		rid=0;
699		res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE);
700		if(res==NULL){
701		  device_printf(dev,"could not allocate irq");
702		  return ENOMEM;
703		}
704		error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih);
705                if(error){
706                        device_printf(dev,"Failed to map intr\n");
707			return error;
708                }
709                smbinterface=device_add_child(dev,"intsmb",unit);
710		if(!smbinterface){
711		     printf("intsmb%d:could not add SMBus device\n",unit);
712		}
713                device_probe_and_attach(smbinterface);
714        }
715
716        value=pci_read_config(dev,PCI_BASE_ADDR_PM,4);
717        printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe);
718        return 0;
719}
720static int
721intpm_probe(device_t dev)
722{
723    struct _pcsid *ep =pci_ids;
724    u_int32_t device_id=pci_get_devid(dev);
725
726    while (ep->type && ep->type != device_id)
727	  ++ep;
728    if(ep->desc!=NULL){
729      device_set_desc(dev,ep->desc);
730      bus_set_resource(dev,SYS_RES_IRQ,0,9,1); /* XXX setup intr resource */
731      return 0;
732    }else{
733      return ENXIO;
734    }
735}
736DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0);
737
738static void intpm_intr(void *arg)
739{
740        struct intpm_pci_softc *sc;
741        sc=(struct intpm_pci_softc *)arg;
742	intsmb_intr(sc->smbus);
743	intsmb_slvintr(sc->smbus);
744
745}
746