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