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