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