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