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