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