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