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