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