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