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