intpm.c revision 162234
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: head/sys/pci/intpm.c 162234 2006-09-11 20:52:41Z jhb $"); 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 53static 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}; 68static int intsmb_probe(device_t); 69static int intsmb_attach(device_t); 70 71static int intsmb_intr(device_t dev); 72static int intsmb_slvintr(device_t dev); 73static void intsmb_alrintr(device_t dev); 74static int intsmb_callback(device_t dev, int index, void *data); 75static int intsmb_quick(device_t dev, u_char slave, int how); 76static int intsmb_sendb(device_t dev, u_char slave, char byte); 77static int intsmb_recvb(device_t dev, u_char slave, char *byte); 78static int intsmb_writeb(device_t dev, u_char slave, char cmd, char byte); 79static int intsmb_writew(device_t dev, u_char slave, char cmd, short word); 80static int intsmb_readb(device_t dev, u_char slave, char cmd, char *byte); 81static int intsmb_readw(device_t dev, u_char slave, char cmd, short *word); 82static int intsmb_pcall(device_t dev, u_char slave, char cmd, short sdata, short *rdata); 83static int intsmb_bwrite(device_t dev, u_char slave, char cmd, u_char count, char *buf); 84static int intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf); 85static void intsmb_start(device_t dev,u_char cmd,int nointr); 86static int intsmb_stop(device_t dev); 87static int intsmb_stop_poll(device_t dev); 88static int intsmb_free(device_t dev); 89static int intpm_probe (device_t dev); 90static int intpm_attach (device_t dev); 91static devclass_t intsmb_devclass; 92 93static 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 113struct 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 122struct 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 130static driver_t intpm_driver = { 131 "intsmb", 132 intpm_methods, 133 sizeof(struct intsmb_softc), 134}; 135 136static devclass_t intpm_devclass; 137static device_method_t intpm_pci_methods[] = { 138 DEVMETHOD(device_probe,intpm_probe), 139 DEVMETHOD(device_attach,intpm_attach), 140 {0,0} 141}; 142static driver_t intpm_pci_driver = { 143 "intpm", 144 intpm_pci_methods, 145 sizeof(struct intpm_pci_softc) 146}; 147 148static int 149intsmb_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} 159static int 160intsmb_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 177static int 178intsmb_callback(device_t dev, int index, void *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*/ 195static int 196intsmb_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 224static int 225intsmb_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} 250static int 251intsmb_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 273static 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} 313static void 314intsmb_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 335static int 336intsmb_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 */ 376static int 377intsmb_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 415static int 416intsmb_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 446static int 447intsmb_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} 460static int 461intsmb_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} 485static int 486intsmb_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} 500static int 501intsmb_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 519static int 520intsmb_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} 536static int 537intsmb_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 */ 558static int 559intsmb_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} 581static int 582intsmb_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=SMB_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 605static int 606intsmb_bread(device_t dev, u_char slave, char cmd, u_char *count, char *buf) 607{ 608 int error,i; 609 u_char data, nread; 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=SMB_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 nread= bus_space_read_1(sc->st,sc->sh, 625 PIIX4_SMBHSTDAT0); 626 if(nread!=0&&nread<=SMBBLOCKTRANS_MAX){ 627 for(i=0;i<nread;i++){ 628 data = bus_space_read_1(sc->st, 629 sc->sh, 630 PIIX4_SMBBLKDAT); 631 if (i < *count) 632 buf[i] = data; 633 } 634 *count = nread; 635 } 636 else{ 637 error=EIO; 638 } 639 } 640 } 641 return (error); 642} 643 644DRIVER_MODULE(intsmb, intpm , intpm_driver, intsmb_devclass, 0, 0); 645 646 647static void intpm_intr(void *arg); 648static int 649intpm_attach(device_t dev) 650{ 651 int value; 652 int unit=device_get_unit(dev); 653 void *ih; 654 int error; 655 char * str; 656 { 657 struct intpm_pci_softc *sciic; 658 device_t smbinterface; 659 int rid; 660 struct resource *res; 661 662 sciic=device_get_softc(dev); 663 if(sciic==NULL){ 664 return ENOMEM; 665 } 666 667 rid=PCI_BASE_ADDR_SMB; 668 res=bus_alloc_resource_any(dev,SYS_RES_IOPORT,&rid,RF_ACTIVE); 669 if(res==NULL){ 670 device_printf(dev,"Could not allocate Bus space\n"); 671 return ENXIO; 672 } 673 sciic->smbst=rman_get_bustag(res); 674 sciic->smbsh=rman_get_bushandle(res); 675 676#ifdef __i386__ 677 device_printf(dev,"%s %lx\n", 678 (sciic->smbst==I386_BUS_SPACE_IO)? 679 "I/O mapped":"Memory", 680 rman_get_start(res)); 681#endif 682 683 684#ifndef NO_CHANGE_PCICONF 685 pci_write_config(dev,PCIR_INTLINE,0x9,1); 686 pci_write_config(dev,PCI_HST_CFG_SMB, 687 PCI_INTR_SMB_IRQ9|PCI_INTR_SMB_ENABLE,1); 688#endif 689 value=pci_read_config(dev,PCI_HST_CFG_SMB,1); 690 switch(value&0xe){ 691 case PCI_INTR_SMB_SMI: 692 str="SMI"; 693 break; 694 case PCI_INTR_SMB_IRQ9: 695 str="IRQ 9"; 696 break; 697 default: 698 str="BOGUS"; 699 } 700 device_printf(dev,"intr %s %s ",str,((value&1)? "enabled":"disabled")); 701 value=pci_read_config(dev,PCI_REVID_SMB,1); 702 printf("revision %d\n",value); 703 /* 704 * Install intr HANDLER here 705 */ 706 rid=0; 707 res=bus_alloc_resource(dev,SYS_RES_IRQ,&rid,9,9,1,RF_SHAREABLE|RF_ACTIVE); 708 if(res==NULL){ 709 device_printf(dev,"could not allocate irq"); 710 return ENOMEM; 711 } 712 error=bus_setup_intr(dev,res,INTR_TYPE_MISC, (driver_intr_t *) intpm_intr,sciic,&ih); 713 if(error){ 714 device_printf(dev,"Failed to map intr\n"); 715 return error; 716 } 717 smbinterface=device_add_child(dev,"intsmb",unit); 718 if(!smbinterface){ 719 printf("intsmb%d:could not add SMBus device\n",unit); 720 } 721 device_probe_and_attach(smbinterface); 722 } 723 724 value=pci_read_config(dev,PCI_BASE_ADDR_PM,4); 725 printf("intpm%d: PM %s %x \n",unit,(value&1)?"I/O mapped":"Memory",value&0xfffe); 726 return 0; 727} 728static int 729intpm_probe(device_t dev) 730{ 731 struct _pcsid *ep =pci_ids; 732 u_int32_t device_id=pci_get_devid(dev); 733 734 while (ep->type && ep->type != device_id) 735 ++ep; 736 if(ep->desc!=NULL){ 737 device_set_desc(dev,ep->desc); 738 bus_set_resource(dev,SYS_RES_IRQ,0,9,1); /* XXX setup intr resource */ 739 return (BUS_PROBE_DEFAULT); 740 }else{ 741 return ENXIO; 742 } 743} 744DRIVER_MODULE(intpm, pci , intpm_pci_driver, intpm_devclass, 0, 0); 745DRIVER_MODULE(smbus, intsmb, smbus_driver, smbus_devclass, 0, 0); 746MODULE_DEPEND(intpm, smbus, SMBUS_MINVER, SMBUS_PREFVER, SMBUS_MAXVER); 747MODULE_VERSION(intpm, 1); 748 749static void intpm_intr(void *arg) 750{ 751 struct intpm_pci_softc *sc; 752 sc=(struct intpm_pci_softc *)arg; 753 intsmb_intr(sc->smbus); 754 intsmb_slvintr(sc->smbus); 755 756} 757