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