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