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