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