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