intpm.c revision 106628
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: head/sys/pci/intpm.c 106628 2002-11-08 15:01:02Z jhb $ 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 54static 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}; 69static int intsmb_probe(device_t); 70static int intsmb_attach(device_t); 71 72static int intsmb_intr(device_t dev); 73static int intsmb_slvintr(device_t dev); 74static void intsmb_alrintr(device_t dev); 75static int intsmb_callback(device_t dev, int index, caddr_t data); 76static int intsmb_quick(device_t dev, u_char slave, int how); 77static int intsmb_sendb(device_t dev, u_char slave, char byte); 78static int intsmb_recvb(device_t dev, u_char slave, char *byte); 79static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 80static int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 81static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 82static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 83static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 84static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 85static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char count, char *buf); 86static void intsmb_start(device_t dev,u_char cmd,int nointr); 87static int intsmb_stop(device_t dev); 88static int intsmb_stop_poll(device_t dev); 89static int intsmb_free(device_t dev); 90static int intpm_probe (device_t dev); 91static int intpm_attach (device_t dev); 92static devclass_t intsmb_devclass; 93 94static 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 114struct 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 123struct 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 131static driver_t intpm_driver = { 132 "intsmb", 133 intpm_methods, 134 sizeof(struct intsmb_softc), 135}; 136 137static devclass_t intpm_devclass; 138static device_method_t intpm_pci_methods[] = { 139 DEVMETHOD(device_probe,intpm_probe), 140 DEVMETHOD(device_attach,intpm_attach), 141 {0,0} 142}; 143static driver_t intpm_pci_driver = { 144 "intpm", 145 intpm_pci_methods, 146 sizeof(struct intpm_pci_softc) 147}; 148 149static int 150intsmb_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} 160static int 161intsmb_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 178static int 179intsmb_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*/ 196static int 197intsmb_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 225static int 226intsmb_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} 251static int 252intsmb_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 274static 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} 314static void 315intsmb_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 336static int 337intsmb_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 */ 377static int 378intsmb_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 416static int 417intsmb_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 447static int 448intsmb_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} 461static int 462intsmb_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} 486static int 487intsmb_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} 501static int 502intsmb_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 520static int 521intsmb_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} 537static int 538intsmb_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 */ 559static int 560intsmb_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} 582static int 583intsmb_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 606static int 607intsmb_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 642DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0); 643 644 645static void intpm_intr(void *arg); 646static int 647intpm_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} 727static int 728intpm_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} 743DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0); 744MODULE_DEPEND(intpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 745MODULE_VERSION(intpm, 1); 746 747static 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} 755