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