Initial import from FreeBSD RELENG_4:
[dragonfly.git] / sys / dev / powermng / i386 / intpm / 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  * $FreeBSD: src/sys/pci/intpm.c,v 1.16.2.1 2001/12/23 08:17:47 pirzyk Exp $
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/conf.h>
41 #include <sys/malloc.h>
42 #include <sys/buf.h>
43 #include <sys/rman.h>
44 #include <machine/resource.h>
45 #include <dev/smbus/smbconf.h>
46
47 #include "smbus_if.h"
48
49 /*This should be removed if force_pci_map_int supported*/
50 #include <sys/interrupt.h>
51
52 #include <pci/pcireg.h>
53 #include <pci/pcivar.h>
54 #include <pci/intpmreg.h>
55
56 #include "opt_intpm.h"
57
58 static struct _pcsid
59 {
60         pcidi_t type;
61         char    *desc;
62 } pci_ids[] =
63 {
64         { 0x71138086,"Intel 82371AB Power management controller"},
65         { 0x719b8086,"Intel 82443MX Power management controller"},
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         pcici_t cfg;
119         device_t  smbus;
120 };
121
122
123 struct intsmb_softc{
124         struct intpm_pci_softc *pci_sc;
125         bus_space_tag_t st;
126         bus_space_handle_t sh;
127         device_t smbus;
128         int isbusy;
129 };
130
131 static driver_t intpm_driver = {
132         "intsmb",
133         intpm_methods,
134         sizeof(struct intsmb_softc),
135 };
136
137 static devclass_t intpm_devclass;
138 static device_method_t intpm_pci_methods[] = {
139   DEVMETHOD(device_probe,intpm_probe),
140   DEVMETHOD(device_attach,intpm_attach),
141   {0,0}
142 };
143 static driver_t intpm_pci_driver = {
144   "intpm",
145   intpm_pci_methods,
146   sizeof(struct intpm_pci_softc)
147 };
148
149 static int 
150 intsmb_probe(device_t dev)
151 {
152         struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
153         sc->smbus=smbus_alloc_bus(dev);
154         if (!sc->smbus)
155                 return (EINVAL);    /* XXX don't know what to return else */
156         device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
157         
158         return (0);          /* XXX don't know what to return else */
159 }
160 static int
161 intsmb_attach(device_t dev)
162 {
163         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
164         sc->pci_sc=device_get_softc(device_get_parent(dev));
165         sc->isbusy=0;
166         sc->sh=sc->pci_sc->smbsh;
167         sc->st=sc->pci_sc->smbst;
168         sc->pci_sc->smbus=dev;
169         device_probe_and_attach(sc->smbus);
170 #ifdef ENABLE_ALART
171         /*Enable Arart*/
172         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
173                           PIIX4_SMBSLVCNT_ALTEN);
174 #endif 
175         return (0);
176 }
177
178 static int 
179 intsmb_callback(device_t dev, int index, caddr_t data)
180 {
181         int error = 0;
182         intrmask_t s;
183         s=splnet();
184         switch (index) {
185         case SMB_REQUEST_BUS:
186                 break;
187         case SMB_RELEASE_BUS:
188                 break;
189         default:
190                 error = EINVAL;
191         }
192         splx(s);
193         return (error);
194 }
195 /*counterpart of smbtx_smb_free*/
196 static        int
197 intsmb_free(device_t dev){
198         intrmask_t s;
199         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
200         if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)&
201             PIIX4_SMBHSTSTAT_BUSY)
202 #ifdef ENABLE_ALART
203            ||(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS)&
204               PIIX4_SMBSLVSTS_BUSY)
205 #endif
206            || sc->isbusy)
207                 return EBUSY;
208         s=splhigh();
209         sc->isbusy=1;
210         /*Disable Intrrupt in slave part*/
211 #ifndef ENABLE_ALART
212         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,0);
213 #endif
214         /*Reset INTR Flag to prepare INTR*/
215         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTSTS,
216                           (PIIX4_SMBHSTSTAT_INTR|
217                            PIIX4_SMBHSTSTAT_ERR|
218                            PIIX4_SMBHSTSTAT_BUSC|
219                            PIIX4_SMBHSTSTAT_FAIL)
220                 );
221         splx(s);
222         return 0;
223 }
224
225 static int
226 intsmb_intr(device_t dev)
227 {
228         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
229         int status;
230         status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
231         if(status&PIIX4_SMBHSTSTAT_BUSY){
232                 return 1;
233                 
234         }
235         if(status&(PIIX4_SMBHSTSTAT_INTR|
236                                 PIIX4_SMBHSTSTAT_ERR|
237                                 PIIX4_SMBHSTSTAT_BUSC|
238                                 PIIX4_SMBHSTSTAT_FAIL)){
239                 int tmp;
240                 tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
241                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
242                                   tmp&~PIIX4_SMBHSTCNT_INTREN);
243                 if(sc->isbusy){
244                   sc->isbusy=0;
245                   wakeup(sc);
246                 }
247                 return 0;
248         }
249         return 1;/* Not Completed*/
250 }
251 static int
252 intsmb_slvintr(device_t dev)
253 {
254         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
255         int status,retval;
256         retval=1;
257         status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVSTS);
258         if(status&PIIX4_SMBSLVSTS_BUSY)
259                 return retval;
260         if(status&PIIX4_SMBSLVSTS_ALART){
261                 intsmb_alrintr(dev);
262                 retval=0;
263         }else if(status&~(PIIX4_SMBSLVSTS_ALART|PIIX4_SMBSLVSTS_SDW2
264                           |PIIX4_SMBSLVSTS_SDW1)){
265                 retval=0;
266         }
267         /*Reset Status Register*/
268         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVSTS,PIIX4_SMBSLVSTS_ALART|
269                           PIIX4_SMBSLVSTS_SDW2|PIIX4_SMBSLVSTS_SDW1|
270                           PIIX4_SMBSLVSTS_SLV);
271         return retval;
272 }
273
274 static void intsmb_alrintr(device_t dev)
275 {
276         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
277         int slvcnt;
278 #ifdef ENABLE_ALART
279         int error;
280 #endif
281
282         /*stop generating INTR from ALART*/
283         slvcnt=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBSLVCNT);
284 #ifdef ENABLE_ALART
285         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
286                           slvcnt&~PIIX4_SMBSLVCNT_ALTEN) ;
287 #endif
288         DELAY(5);
289         /*ask bus who assert it and then ask it what's the matter. */   
290 #ifdef ENABLE_ALART
291         error=intsmb_free(dev);
292         if(!error){
293                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,SMBALTRESP
294                                   |LSB);
295                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,1);
296                 if(!(error=intsmb_stop_poll(dev))){
297                         volatile u_int8_t *addr;
298                         addr=bus_space_read_1(sc->st,sc->sh,
299                                               PIIX4_SMBHSTDAT0);
300                         printf("ALART_RESPONSE: %p\n", addr);
301                 }
302         }else{
303                 printf("ERROR\n");
304         }
305
306         /*Re-enable INTR from ALART*/
307         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
308                           slvcnt|PIIX4_SMBSLVCNT_ALTEN) ;
309         DELAY(5);
310 #endif
311
312         return;
313 }
314 static void
315 intsmb_start(device_t dev,unsigned char cmd,int nointr)
316 {
317         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
318         unsigned char tmp;
319         tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
320         tmp&= 0xe0;
321         tmp |= cmd;
322         tmp |=PIIX4_SMBHSTCNT_START;
323         /*While not in autoconfiguration Intrrupt Enabled*/
324         if(!cold||!nointr)
325                 tmp |=PIIX4_SMBHSTCNT_INTREN;
326         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,tmp);
327 }
328
329 /*Polling Code. Polling is not encouraged 
330  * because It is required to wait for the device get busy.
331  *(29063505.pdf from Intel)
332  * But during boot,intrrupt cannot be used.
333  * so use polling code while in autoconfiguration.
334  */
335
336 static        int
337 intsmb_stop_poll(device_t dev){
338         int error,i;
339         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
340         
341         /*
342          *  In smbtx driver ,Simply waiting.
343          *  This loops 100-200 times.
344          */
345         for(i=0;i<0x7fff;i++){
346                 if((bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS)
347                     &PIIX4_SMBHSTSTAT_BUSY)){
348                         break;
349                 }
350         }
351         for(i=0;i<0x7fff;i++){
352                 int status;
353                 status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
354                 if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
355                         sc->isbusy=0;
356                         error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
357                                 (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
358                                 (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
359                         if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
360                                 printf("unknown cause why?");
361                         }
362                         return error;
363                 }
364         }
365         {
366           int tmp;
367           sc->isbusy=0;
368           tmp=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
369           bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCNT,
370                             tmp&~PIIX4_SMBHSTCNT_INTREN);
371         }
372         return EIO;
373 }
374 /*
375  *wait for completion and return result.
376  */
377 static        int
378 intsmb_stop(device_t dev){
379         int error;
380         intrmask_t s;
381         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
382         if(cold){
383                 /*So that it can use device during probing device on SMBus.*/
384                 error=intsmb_stop_poll(dev);
385                 return error;
386         }else{
387                 if(!tsleep(sc,(PWAIT)|PCATCH,"SMBWAI",hz/8)){
388                         int status;
389                         status=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTSTS);
390                         if(!(status&PIIX4_SMBHSTSTAT_BUSY)){
391                                 error=(status&PIIX4_SMBHSTSTAT_ERR)?EIO :
392                                         (status&PIIX4_SMBHSTSTAT_BUSC)?EBUSY:
393                                         (status&PIIX4_SMBHSTSTAT_FAIL)?EIO:0;
394                                 if(error==0&&!(status&PIIX4_SMBHSTSTAT_INTR)){
395                                         printf("intsmb%d:unknown cause why?\n",
396                                                device_get_unit(dev));
397                                 }
398 #ifdef ENABLE_ALART
399                                 bus_space_write_1(sc->st,sc->sh,
400                                                   PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
401 #endif
402                                 return error;
403                         }
404                 }
405         }
406         /*Timeout Procedure*/
407         s=splhigh();
408         sc->isbusy=0;
409         /*Re-enable supressed intrrupt from slave part*/
410         bus_space_write_1(sc->st,sc->sh,
411                           PIIX4_SMBSLVCNT,PIIX4_SMBSLVCNT_ALTEN);
412         splx(s);
413         return EIO;
414 }
415
416 static int
417 intsmb_quick(device_t dev, u_char slave, int how)
418 {
419         int error=0;
420         u_char data;
421         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
422         data=slave;
423         /*Quick command is part of Address, I think*/
424         switch(how){
425         case SMB_QWRITE:
426                 data&=~LSB;
427                 break;
428         case SMB_QREAD:
429                 data|=LSB;
430                 break;
431         default:
432                 error=EINVAL;
433         }
434         if(!error){
435                 error=intsmb_free(dev);
436                 if(!error){
437                         bus_space_write_1(sc->st,sc->sh,
438                                           PIIX4_SMBHSTADD,data);
439                         intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_QUICK,0);
440                         error=intsmb_stop(dev);
441                 }
442         }
443
444         return (error);
445 }
446
447 static int
448 intsmb_sendb(device_t dev, u_char slave, char byte)
449 {
450         int error;
451         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
452         error=intsmb_free(dev);
453         if(!error){
454                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
455                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,byte);
456                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
457                 error=intsmb_stop(dev);
458         }
459         return (error);
460 }
461 static int
462 intsmb_recvb(device_t dev, u_char slave, char *byte)
463 {
464         int error;
465         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
466         error=intsmb_free(dev);
467         if(!error){
468                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave
469                                   |LSB);
470                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BYTE,0);
471                 if(!(error=intsmb_stop(dev))){
472 #ifdef RECV_IS_IN_CMD
473                         /*Linux SMBus stuff also troubles
474                           Because Intel's datasheet will not make clear.
475                          */
476                         *byte=bus_space_read_1(sc->st,sc->sh,
477                                                PIIX4_SMBHSTCMD);
478 #else
479                         *byte=bus_space_read_1(sc->st,sc->sh,
480                                                PIIX4_SMBHSTDAT0);
481 #endif
482                 }
483         }
484         return (error);
485 }
486 static int
487 intsmb_writeb(device_t dev, u_char slave, char cmd, char byte)
488 {
489         int error;
490         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
491         error=intsmb_free(dev);
492         if(!error){
493                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
494                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
495                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,byte);
496                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
497                 error=intsmb_stop(dev);
498         }
499         return (error);
500 }
501 static int
502 intsmb_writew(device_t dev, u_char slave, char cmd, short word)
503 {
504         int error;
505         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
506         error=intsmb_free(dev);
507         if(!error){
508                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
509                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
510                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,
511                                   word&0xff);
512                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,
513                                   (word>>8)&0xff);
514                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
515                 error=intsmb_stop(dev);
516         }
517         return (error);
518 }
519
520 static int
521 intsmb_readb(device_t dev, u_char slave, char cmd, char *byte)
522 {
523         int error;
524         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
525         error=intsmb_free(dev);
526         if(!error){
527                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
528                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
529                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BDATA,0);
530                 if(!(error=intsmb_stop(dev))){
531                         *byte=bus_space_read_1(sc->st,sc->sh,
532                                                PIIX4_SMBHSTDAT0);
533                 }
534         }
535         return (error);
536 }
537 static int
538 intsmb_readw(device_t dev, u_char slave, char cmd, short *word)
539 {
540         int error;
541         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
542         error=intsmb_free(dev);
543         if(!error){
544                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
545                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
546                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
547                 if(!(error=intsmb_stop(dev))){
548                         *word=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
549                         *word|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
550                 }
551         }
552         return (error);
553 }
554 /*
555  * Data sheet claims that it implements all function, but also claims
556  * that it implements 7 function and not mention PCALL. So I don't know
557  * whether it will work.
558  */
559 static int
560 intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata)
561 {
562 #ifdef PROCCALL_TEST
563         int error;
564         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
565         error=intsmb_free(dev);
566         if(!error){
567                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
568                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
569                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,sdata&0xff);
570                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1,(sdata&0xff)>>8);
571                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_WDATA,0);
572         }
573         if(!(error=intsmb_stop(dev))){
574                 *rdata=bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0)&0xff;
575                 *rdata|=(bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTDAT1)&0xff)<<8;
576         }
577         return error;
578 #else
579         return 0;
580 #endif
581 }
582 static int
583 intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf)
584 {
585         int error,i;
586         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
587         error=intsmb_free(dev);
588         if(count>SMBBLOCKTRANS_MAX||count==0)
589                 error=EINVAL;
590         if(!error){
591                 /*Reset internal array index*/
592                 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
593                 
594                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave&~LSB);
595                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
596                 for(i=0;i<count;i++){
597                         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBBLKDAT,buf[i]);
598                 }
599                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
600                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
601                 error=intsmb_stop(dev);
602         }
603         return (error);
604 }
605
606 static int
607 intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf)
608 {
609         int error,i;
610         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
611         error=intsmb_free(dev);
612         if(count>SMBBLOCKTRANS_MAX||count==0)
613                 error=EINVAL;
614         if(!error){
615                 /*Reset internal array index*/
616                 bus_space_read_1(sc->st,sc->sh,PIIX4_SMBHSTCNT);
617                 
618                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTADD,slave|LSB);
619                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTCMD,cmd);
620                 bus_space_write_1(sc->st,sc->sh,PIIX4_SMBHSTDAT0,count);
621                 intsmb_start(dev,PIIX4_SMBHSTCNT_PROT_BLOCK,0);
622                 error=intsmb_stop(dev);
623                 if(!error){
624                         bzero(buf,count);/*Is it needed?*/
625                         count= bus_space_read_1(sc->st,sc->sh,
626                                                 PIIX4_SMBHSTDAT0);
627                         if(count!=0&&count<=SMBBLOCKTRANS_MAX){
628                                 for(i=0;i<count;i++){
629                                         buf[i]=bus_space_read_1(sc->st,
630                                                                 sc->sh,
631                                                                 PIIX4_SMBBLKDAT);
632                                 }
633                         }
634                         else{
635                                 error=EIO;
636                         }
637                 }
638         }
639         return (error);
640 }
641
642 DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0);
643
644
645 static void intpm_intr __P((void *arg));
646 static int
647 intpm_attach(device_t dev)
648 {
649         int value;
650         int unit=device_get_unit(dev);
651         void *ih;
652         int error;
653         char * str;
654         {
655                 struct intpm_pci_softc *sciic;
656                 device_t smbinterface;
657                 int rid;
658                 struct resource *res;
659
660                 sciic=device_get_softc(dev);
661                 if(sciic==NULL){
662                         return ENOMEM;
663                 }
664
665                 rid=PCI_BASE_ADDR_SMB;
666                 res=bus_alloc_resource(dev,SYS_RES_IOPORT,&rid,
667                                        0,~0,1,RF_ACTIVE);
668                 if(res==NULL){
669                   device_printf(dev,"Could not allocate Bus space\n");
670                   return ENXIO;
671                 }
672                 sciic->smbst=rman_get_bustag(res);
673                 sciic->smbsh=rman_get_bushandle(res);
674                 
675                 device_printf(dev,"%s %x\n",
676                               (sciic->smbst==I386_BUS_SPACE_IO)?
677                               "I/O mapped":"Memory",
678                               sciic->smbsh);
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 0;
737     }else{
738       return ENXIO;
739     }
740 }
741 DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0);
742
743 static void intpm_intr(void *arg)
744 {
745         struct intpm_pci_softc *sc;
746         sc=(struct intpm_pci_softc *)arg;
747         intsmb_intr(sc->smbus);
748         intsmb_slvintr(sc->smbus);
749         
750 }