]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - sys/pci/intpm.c
- M_WAITOK is 0 and not a real flag. Test for this properly.
[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  * $FreeBSD$
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 <sys/uio.h>
37 #include <sys/module.h>
38 #include <sys/bus.h>
39 #include <sys/rman.h>
40 #include <machine/resource.h>
41 #include <dev/smbus/smbconf.h>
42
43 #include "smbus_if.h"
44
45 /*This should be removed if force_pci_map_int supported*/
46 #include <sys/interrupt.h>
47
48 #include <pci/pcireg.h>
49 #include <pci/pcivar.h>
50 #include <pci/intpmreg.h>
51
52 #include "opt_intpm.h"
53
54 static struct _pcsid
55 {
56         u_int32_t type;
57         char    *desc;
58 } pci_ids[] =
59 {
60         { 0x71138086,"Intel 82371AB Power management controller"},
61         { 0x719b8086,"Intel 82443MX Power management controller"},
62 #if 0
63         /* Not a good idea yet, this stops isab0 functioning */
64         { 0x02001166,"ServerWorks OSB4 PCI to ISA Bridge"},
65 #endif
66         
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         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=device_add_child(dev, "smbus", -1);
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                         u_int8_t addr;
298                         addr=bus_space_read_1(sc->st,sc->sh,
299                                               PIIX4_SMBHSTDAT0);
300                         printf("ALART_RESPONSE: 0x%x\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(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 #ifdef __i386__
676                 device_printf(dev,"%s %x\n",
677                               (sciic->smbst==I386_BUS_SPACE_IO)?
678                               "I/O mapped":"Memory",
679                               sciic->smbsh);
680 #endif
681                 
682
683 #ifndef NO_CHANGE_PCICONF
684                 pci_write_config(dev,PCIR_INTLINE,0x9,1);
685                 pci_write_config(dev,PCI_HST_CFG_SMB,
686                                  PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1);
687 #endif
688                 value=pci_read_config(dev,PCI_HST_CFG_SMB,1);
689                 switch(value&0xe){
690                 case PCI_INTR_SMB_SMI:
691                         str="SMI";
692                         break;
693                 case PCI_INTR_SMB_IRQ9:
694                         str="IRQ 9";
695                         break;
696                 default:
697                         str="BOGUS";
698                 }
699                 device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled"));
700                 value=pci_read_config(dev,PCI_REVID_SMB,1);
701                 printf("revision %d\n",value);                
702                 /*
703                  * Install intr HANDLER here
704                  */
705                 rid=0;
706                 res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE);
707                 if(res==NULL){
708                   device_printf(dev,"could not allocate irq");
709                   return ENOMEM;
710                 }
711                 error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih);
712                 if(error){
713                         device_printf(dev,"Failed to map intr\n");
714                         return error;
715                 }
716                 smbinterface=device_add_child(dev,"intsmb",unit);
717                 if(!smbinterface){
718                      printf("intsmb%d:could not add SMBus device\n",unit);
719                 }
720                 device_probe_and_attach(smbinterface);
721         }
722               
723         value=pci_read_config(dev,PCI_BASE_ADDR_PM,4);
724         printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe);
725         return 0;
726 }
727 static int 
728 intpm_probe(device_t dev)
729 {
730     struct _pcsid *ep =pci_ids;
731     u_int32_t device_id=pci_get_devid(dev);
732
733     while (ep->type && ep->type != device_id)
734           ++ep;
735     if(ep->desc!=NULL){
736       device_set_desc(dev,ep->desc);
737       bus_set_resource(dev,SYS_RES_IRQ,0,9,1); /* XXX setup intr resource */
738       return 0;
739     }else{
740       return ENXIO;
741     }
742 }
743 DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0);
744 MODULE_DEPEND(intpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER);
745 MODULE_VERSION(intpm, 1);
746
747 static void intpm_intr(void *arg)
748 {
749         struct intpm_pci_softc *sc;
750         sc=(struct intpm_pci_softc *)arg;
751         intsmb_intr(sc->smbus);
752         intsmb_slvintr(sc->smbus);
753         
754 }