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