Merge from vendor branch NCURSES:
[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.8 2005/06/10 23:29:31 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 <sys/thread2.h>
46 #include <machine/resource.h>
47 #include <bus/smbus/smbconf.h>
48
49 #include "smbus_if.h"
50
51 /*This should be removed if force_pci_map_int supported*/
52 #include <sys/interrupt.h>
53
54 #include <bus/pci/pcireg.h>
55 #include <bus/pci/pcivar.h>
56 #include "intpmreg.h"
57
58 #include "opt_intpm.h"
59
60 static struct _pcsid
61 {
62         pcidi_t type;
63         char    *desc;
64 } pci_ids[] =
65 {
66         { 0x71138086,"Intel 82371AB Power management controller"},
67         { 0x719b8086,"Intel 82443MX Power management controller"},
68         { 0x00000000,   NULL                                    }
69 };
70 static int intsmb_probe(device_t);
71 static int intsmb_attach(device_t);
72
73 static int intsmb_intr(device_t dev);
74 static int intsmb_slvintr(device_t dev);
75 static void  intsmb_alrintr(device_t dev);
76 static int intsmb_callback(device_t dev, int index, caddr_t data);
77 static int intsmb_quick(device_t dev, u_char slave, int how);
78 static int intsmb_sendb(device_t dev, u_char slave, char byte);
79 static int intsmb_recvb(device_t dev, u_char slave, char *byte);
80 static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte);
81 static int intsmb_writew(device_t dev, u_char slave, char cmd, short word);
82 static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte);
83 static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word);
84 static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata);
85 static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf);
86 static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf);
87 static void intsmb_start(device_t dev,u_char cmd,int nointr);
88 static int intsmb_stop(device_t dev);
89 static int intsmb_stop_poll(device_t dev);
90 static int intsmb_free(device_t dev);
91 static int intpm_probe (device_t dev);
92 static int intpm_attach (device_t dev);
93 static devclass_t intsmb_devclass;
94
95 static device_method_t intpm_methods[]={
96         DEVMETHOD(device_probe,intsmb_probe),
97         DEVMETHOD(device_attach,intsmb_attach),
98
99         DEVMETHOD(bus_print_child, bus_generic_print_child),
100         
101         DEVMETHOD(smbus_callback,intsmb_callback),
102         DEVMETHOD(smbus_quick,intsmb_quick),
103         DEVMETHOD(smbus_sendb,intsmb_sendb),
104         DEVMETHOD(smbus_recvb,intsmb_recvb),
105         DEVMETHOD(smbus_writeb,intsmb_writeb),
106         DEVMETHOD(smbus_writew,intsmb_writew),
107         DEVMETHOD(smbus_readb,intsmb_readb),
108         DEVMETHOD(smbus_readw,intsmb_readw),
109         DEVMETHOD(smbus_pcall,intsmb_pcall),
110         DEVMETHOD(smbus_bwrite,intsmb_bwrite),
111         DEVMETHOD(smbus_bread,intsmb_bread),
112         {0,0}
113 };
114
115 struct intpm_pci_softc{
116         bus_space_tag_t smbst;
117         bus_space_handle_t smbsh;
118         bus_space_tag_t pmst;
119         bus_space_handle_t pmsh;
120         pcici_t cfg;
121         device_t  smbus;
122 };
123
124
125 struct intsmb_softc{
126         struct intpm_pci_softc *pci_sc;
127         bus_space_tag_t st;
128         bus_space_handle_t sh;
129         device_t smbus;
130         int isbusy;
131 };
132
133 static driver_t intpm_driver = {
134         "intsmb",
135         intpm_methods,
136         sizeof(struct intsmb_softc),
137 };
138
139 static devclass_t intpm_devclass;
140 static device_method_t intpm_pci_methods[] = {
141   DEVMETHOD(device_probe,intpm_probe),
142   DEVMETHOD(device_attach,intpm_attach),
143   {0,0}
144 };
145 static driver_t intpm_pci_driver = {
146   "intpm",
147   intpm_pci_methods,
148   sizeof(struct intpm_pci_softc)
149 };
150
151 static int 
152 intsmb_probe(device_t dev)
153 {
154         struct intsmb_softc *sc =(struct intsmb_softc *) device_get_softc(dev);
155         sc->smbus=smbus_alloc_bus(dev);
156         if (!sc->smbus)
157                 return (EINVAL);    /* XXX don't know what to return else */
158         device_set_desc(dev,"Intel PIIX4 SMBUS Interface");
159         
160         return (0);          /* XXX don't know what to return else */
161 }
162 static int
163 intsmb_attach(device_t dev)
164 {
165         struct intsmb_softc *sc = (struct intsmb_softc *)device_get_softc(dev);
166         sc->pci_sc=device_get_softc(device_get_parent(dev));
167         sc->isbusy=0;
168         sc->sh=sc->pci_sc->smbsh;
169         sc->st=sc->pci_sc->smbst;
170         sc->pci_sc->smbus=dev;
171         device_probe_and_attach(sc->smbus);
172 #ifdef ENABLE_ALART
173         /*Enable Arart*/
174         bus_space_write_1(sc->st,sc->sh,PIIX4_SMBSLVCNT,
175                           PIIX4_SMBSLVCNT_ALTEN);
176 #endif 
177         return (0);
178 }
179
180 static int 
181 intsmb_callback(device_t dev, int index, caddr_t data)
182 {
183         int error = 0;
184
185         crit_enter();
186         switch (index) {
187         case SMB_REQUEST_BUS:
188                 break;
189         case SMB_RELEASE_BUS:
190                 break;
191         default:
192                 error = EINVAL;
193         }
194         crit_exit();
195         return (error);
196 }
197 /*counterpart of smbtx_smb_free*/
198 static        int
199 intsmb_free(device_t dev){
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         crit_enter();
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         crit_exit();
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                         uint32_t addr;
299                         addr = bus_space_read_1(sc->st,sc->sh,
300                                                 PIIX4_SMBHSTDAT0);
301                         printf("ALART_RESPONSE: %#x\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         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, 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         crit_enter();
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         crit_exit();
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                 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,
710                                        (driver_intr_t *)intpm_intr, sciic,
711                                        &ih, NULL);
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
745 static void intpm_intr(void *arg)
746 {
747         struct intpm_pci_softc *sc;
748         sc=(struct intpm_pci_softc *)arg;
749         intsmb_intr(sc->smbus);
750         intsmb_slvintr(sc->smbus);
751         
752 }