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