kernel tree reorganization stage 1: Major cvs repository work (not logged as
[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  * $DragonFly: src/sys/dev/powermng/i386/intpm/intpm.c,v 1.4 2003/08/07 21:17:07 dillon Exp $
28  */
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 <machine/clock.h>
38 #include <sys/uio.h>
39 #include <sys/module.h>
40 #include <sys/bus.h>
41 #include <sys/conf.h>
42 #include <sys/malloc.h>
43 #include <sys/buf.h>
44 #include <sys/rman.h>
45 #include <machine/resource.h>
46 #include <bus/smbus/smbconf.h>
47
48 #include "smbus_if.h"
49
50 /*This should be removed if force_pci_map_int supported*/
51 #include <sys/interrupt.h>
52
53 #include <bus/pci/pcireg.h>
54 #include <bus/pci/pcivar.h>
55 #include "intpmreg.h"
56
57 #include "opt_intpm.h"
58
59 static struct _pcsid
60 {
61         pcidi_t type;
62         char    *desc;
63 } pci_ids[] =
64 {
65         { 0x71138086,"Intel 82371AB Power management controller"},
66         { 0x719b8086,"Intel 82443MX Power management controller"},
67         { 0x00000000,   NULL                                    }
68 };
69 static int intsmb_probe(device_t);
70 static int intsmb_attach(device_t);
71
72 static int intsmb_intr(device_t dev);
73 static int intsmb_slvintr(device_t dev);
74 static void  intsmb_alrintr(device_t dev);
75 static int intsmb_callback(device_t dev, int index, caddr_t data);
76 static int intsmb_quick(device_t dev, u_char slave, int how);
77 static int intsmb_sendb(device_t dev, u_char slave, char byte);
78 static int intsmb_recvb(device_t dev, u_char slave, char *byte);
79 static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
80 static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
81 static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
82 static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
83 static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
84 static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
85 static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
86 static void intsmb_start(device_t dev,u_char cmd,int nointr);
87 static int intsmb_stop(device_t dev);
88 static int intsmb_stop_poll(device_t dev);
89 static int intsmb_free(device_t dev);
90 static int intpm_probe (device_t dev);
91 static int intpm_attach (device_t dev);
92 static devclass_t intsmb_devclass;
93
94 static device_method_t intpm_methods[]={
95         DEVMETHOD(device_probe,intsmb_probe),
96         DEVMETHOD(device_attach,intsmb_attach),
97
98         DEVMETHOD(bus_print_child, bus_generic_print_child),
99         
100         DEVMETHOD(smbus_callback,intsmb_callback),
101         DEVMETHOD(smbus_quick,intsmb_quick),
102         DEVMETHOD(smbus_sendb,intsmb_sendb),
103         DEVMETHOD(smbus_recvb,intsmb_recvb),
104         DEVMETHOD(smbus_writeb,intsmb_writeb),
105         DEVMETHOD(smbus_writew,intsmb_writew),
106         DEVMETHOD(smbus_readb,intsmb_readb),
107         DEVMETHOD(smbus_readw,intsmb_readw),
108         DEVMETHOD(smbus_pcall,intsmb_pcall),
109         DEVMETHOD(smbus_bwrite,intsmb_bwrite),
110         DEVMETHOD(smbus_bread,intsmb_bread),
111         {0,0}
112 };
113
114 struct intpm_pci_softc{
115         bus_space_tag_t smbst;
116         bus_space_handle_t smbsh;
117         bus_space_tag_t pmst;
118         bus_space_handle_t pmsh;
119         pcici_t cfg;
120         device_t  smbus;
121 };
122
123
124 struct 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
132 static driver_t intpm_driver = {
133         "intsmb",
134         intpm_methods,
135         sizeof(struct intsmb_softc),
136 };
137
138 static devclass_t intpm_devclass;
139 static device_method_t intpm_pci_methods[] = {
140   DEVMETHOD(device_probe,intpm_probe),
141   DEVMETHOD(device_attach,intpm_attach),
142   {0,0}
143 };
144 static driver_t intpm_pci_driver = {
145   "intpm",
146   intpm_pci_methods,
147   sizeof(struct intpm_pci_softc)
148 };
149
150 static int 
151 intsmb_probe(device_t dev)
152 {
153         struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
154         sc->smbus=smbus_alloc_bus(dev);
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 }
161 static int
162 intsmb_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
179 static int 
180 intsmb_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*/
197 static        int
198 intsmb_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
226 static int
227 intsmb_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 }
252 static int
253 intsmb_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
275 static 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                         volatile u_int8_t *addr;
299                         addr=bus_space_read_1(sc->st,sc->sh,
300                                               PIIX4_SMBHSTDAT0);
301                         printf("ALART_RESPONSE: %p\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 }
315 static void
316 intsmb_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
337 static        int
338 intsmb_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  */
378 static        int
379 intsmb_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, 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
417 static int
418 intsmb_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
448 static int
449 intsmb_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 }
462 static int
463 intsmb_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 }
487 static int
488 intsmb_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 }
502 static int
503 intsmb_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
521 static int
522 intsmb_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 }
538 static int
539 intsmb_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  */
560 static int
561 intsmb_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 }
583 static int
584 intsmb_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
607 static int
608 intsmb_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
643 DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0);
644
645
646 static void intpm_intr __P((void *arg));
647 static int
648 intpm_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                 device_printf(dev,"%s %x\n",
677                               (sciic->smbst==I386_BUS_SPACE_IO)?
678                               "I/O mapped":"Memory",
679                               sciic->smbsh);
680                 
681
682 #ifndef NO_CHANGE_PCICONF
683                 pci_write_config(dev,PCIR_INTLINE,0x9,1);
684                 pci_write_config(dev,PCI_HST_CFG_SMB,
685                                  PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1);
686 #endif
687                 value=pci_read_config(dev,PCI_HST_CFG_SMB,1);
688                 switch(value&0xe){
689                 case PCI_INTR_SMB_SMI:
690                         str="SMI";
691                         break;
692                 case PCI_INTR_SMB_IRQ9:
693                         str="IRQ 9";
694                         break;
695                 default:
696                         str="BOGUS";
697                 }
698                 device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled"));
699                 value=pci_read_config(dev,PCI_REVID_SMB,1);
700                 printf("revision %d\n",value);                
701                 /*
702                  * Install intr HANDLER here
703                  */
704                 rid=0;
705                 res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE);
706                 if(res==NULL){
707                   device_printf(dev,"could not allocate irq");
708                   return ENOMEM;
709                 }
710                 error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih);
711                 if(error){
712                         device_printf(dev,"Failed to map intr\n");
713                         return error;
714                 }
715                 smbinterface=device_add_child(dev,"intsmb",unit);
716                 if(!smbinterface){
717                      printf("intsmb%d:could not add SMBus device\n",unit);
718                 }
719                 device_probe_and_attach(smbinterface);
720         }
721               
722         value=pci_read_config(dev,PCI_BASE_ADDR_PM,4);
723         printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe);
724         return 0;
725 }
726 static int 
727 intpm_probe(device_t dev)
728 {
729     struct _pcsid *ep =pci_ids;
730     u_int32_t device_id=pci_get_devid(dev);
731
732     while (ep->type && ep->type != device_id)
733           ++ep;
734     if(ep->desc!=NULL){
735       device_set_desc(dev,ep->desc);
736       bus_set_resource(dev,SYS_RES_IRQ,0,9,1); /* XXX setup intr resource */
737       return 0;
738     }else{
739       return ENXIO;
740     }
741 }
742 DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0);
743
744 static void intpm_intr(void *arg)
745 {
746         struct intpm_pci_softc *sc;
747         sc=(struct intpm_pci_softc *)arg;
748         intsmb_intr(sc->smbus);
749         intsmb_slvintr(sc->smbus);
750         
751 }