1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2019 Andriy Gapon 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25 * SUCH DAMAGE. 26 * 27 * $FreeBSD$ 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <sys/param.h> 34 #include <sys/systm.h> 35 #include <sys/bus.h> 36 #include <sys/conf.h> 37 #include <sys/kernel.h> 38 #include <sys/lock.h> 39 #include <sys/mutex.h> 40 #include <sys/malloc.h> 41 #include <sys/module.h> 42 #include <sys/proc.h> 43 #include <sys/rman.h> 44 #include <sys/time.h> 45 46 #include <machine/bus.h> 47 #include <machine/resource.h> 48 #include <machine/stdarg.h> 49 50 #include <isa/isavar.h> 51 52 #include <dev/superio/superio.h> 53 54 #include "isa_if.h" 55 56 57 typedef void (*sio_conf_enter_f)(struct resource*, uint16_t); 58 typedef void (*sio_conf_exit_f)(struct resource*, uint16_t); 59 60 struct sio_conf_methods { 61 sio_conf_enter_f enter; 62 sio_conf_exit_f exit; 63 superio_vendor_t vendor; 64 }; 65 66 struct sio_device { 67 uint8_t ldn; 68 superio_dev_type_t type; 69 }; 70 71 struct superio_devinfo { 72 STAILQ_ENTRY(superio_devinfo) link; 73 struct resource_list resources; 74 device_t dev; 75 uint8_t ldn; 76 superio_dev_type_t type; 77 uint16_t iobase; 78 uint16_t iobase2; 79 uint8_t irq; 80 uint8_t dma; 81 }; 82 83 struct siosc { 84 struct mtx conf_lock; 85 STAILQ_HEAD(, superio_devinfo) devlist; 86 struct resource* io_res; 87 int io_rid; 88 uint16_t io_port; 89 const struct sio_conf_methods *methods; 90 const struct sio_device *known_devices; 91 superio_vendor_t vendor; 92 uint16_t devid; 93 uint8_t revid; 94 uint8_t current_ldn; 95 uint8_t ldn_reg; 96 uint8_t enable_reg; 97 }; 98 99 #define NUMPORTS 2 100 101 static uint8_t 102 sio_read(struct resource* res, uint8_t reg) 103 { 104 bus_write_1(res, 0, reg); 105 return (bus_read_1(res, 1)); 106 } 107 108 /* Read a word from two one-byte registers, big endian. */ 109 static uint16_t 110 sio_readw(struct resource* res, uint8_t reg) 111 { 112 uint16_t v; 113 114 v = sio_read(res, reg); 115 v <<= 8; 116 v |= sio_read(res, reg + 1); 117 return (v); 118 } 119 120 static void 121 sio_write(struct resource* res, uint8_t reg, uint8_t val) 122 { 123 bus_write_1(res, 0, reg); 124 bus_write_1(res, 1, val); 125 } 126 127 static void 128 sio_ldn_select(struct siosc *sc, uint8_t ldn) 129 { 130 mtx_assert(&sc->conf_lock, MA_OWNED); 131 if (ldn == sc->current_ldn) 132 return; 133 sio_write(sc->io_res, sc->ldn_reg, ldn); 134 sc->current_ldn = ldn; 135 } 136 137 static uint8_t 138 sio_ldn_read(struct siosc *sc, uint8_t ldn, uint8_t reg) 139 { 140 mtx_assert(&sc->conf_lock, MA_OWNED); 141 if (reg >= sc->enable_reg) { 142 sio_ldn_select(sc, ldn); 143 KASSERT(sc->current_ldn == ldn, ("sio_ldn_select failed")); 144 } 145 return (sio_read(sc->io_res, reg)); 146 } 147 148 static uint16_t 149 sio_ldn_readw(struct siosc *sc, uint8_t ldn, uint8_t reg) 150 { 151 mtx_assert(&sc->conf_lock, MA_OWNED); 152 if (reg >= sc->enable_reg) { 153 sio_ldn_select(sc, ldn); 154 KASSERT(sc->current_ldn == ldn, ("sio_ldn_select failed")); 155 } 156 return (sio_readw(sc->io_res, reg)); 157 } 158 159 static void 160 sio_ldn_write(struct siosc *sc, uint8_t ldn, uint8_t reg, uint8_t val) 161 { 162 mtx_assert(&sc->conf_lock, MA_OWNED); 163 if (reg <= sc->ldn_reg) { 164 printf("ignored attempt to write special register 0x%x\n", reg); 165 return; 166 } 167 sio_ldn_select(sc, ldn); 168 KASSERT(sc->current_ldn == ldn, ("sio_ldn_select failed")); 169 sio_write(sc->io_res, reg, val); 170 } 171 172 static void 173 sio_conf_enter(struct siosc *sc) 174 { 175 mtx_lock(&sc->conf_lock); 176 sc->methods->enter(sc->io_res, sc->io_port); 177 } 178 179 static void 180 sio_conf_exit(struct siosc *sc) 181 { 182 sc->methods->exit(sc->io_res, sc->io_port); 183 mtx_unlock(&sc->conf_lock); 184 } 185 186 static void 187 ite_conf_enter(struct resource* res, uint16_t port) 188 { 189 bus_write_1(res, 0, 0x87); 190 bus_write_1(res, 0, 0x01); 191 bus_write_1(res, 0, 0x55); 192 bus_write_1(res, 0, port == 0x2e ? 0x55 : 0xaa); 193 } 194 195 static void 196 ite_conf_exit(struct resource* res, uint16_t port) 197 { 198 sio_write(res, 0x02, 0x02); 199 } 200 201 static const struct sio_conf_methods ite_conf_methods = { 202 .enter = ite_conf_enter, 203 .exit = ite_conf_exit, 204 .vendor = SUPERIO_VENDOR_ITE 205 }; 206 207 static void 208 nvt_conf_enter(struct resource* res, uint16_t port) 209 { 210 bus_write_1(res, 0, 0x87); 211 bus_write_1(res, 0, 0x87); 212 } 213 214 static void 215 nvt_conf_exit(struct resource* res, uint16_t port) 216 { 217 bus_write_1(res, 0, 0xaa); 218 } 219 220 static const struct sio_conf_methods nvt_conf_methods = { 221 .enter = nvt_conf_enter, 222 .exit = nvt_conf_exit, 223 .vendor = SUPERIO_VENDOR_NUVOTON 224 }; 225 226 static const struct sio_conf_methods * const methods_table[] = { 227 &ite_conf_methods, 228 &nvt_conf_methods, 229 NULL 230 }; 231 232 static const uint16_t ports_table[] = { 233 0x2e, 0x4e, 0 234 }; 235 236 const struct sio_device ite_devices[] = { 237 { .ldn = 4, .type = SUPERIO_DEV_HWM }, 238 { .ldn = 7, .type = SUPERIO_DEV_WDT }, 239 { .type = SUPERIO_DEV_NONE }, 240 }; 241 242 const struct sio_device nvt_devices[] = { 243 { .ldn = 8, .type = SUPERIO_DEV_WDT }, 244 { .type = SUPERIO_DEV_NONE }, 245 }; 246 247 const struct sio_device nct5104_devices[] = { 248 { .ldn = 7, .type = SUPERIO_DEV_GPIO }, 249 { .ldn = 8, .type = SUPERIO_DEV_WDT }, 250 { .ldn = 15, .type = SUPERIO_DEV_GPIO }, 251 { .type = SUPERIO_DEV_NONE }, 252 }; 253 254 static const struct { 255 superio_vendor_t vendor; 256 uint16_t devid; 257 uint16_t mask; 258 const char *descr; 259 const struct sio_device *devices; 260 } superio_table[] = { 261 { 262 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8712, 263 .devices = ite_devices, 264 }, 265 { 266 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8716, 267 .devices = ite_devices, 268 }, 269 { 270 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8718, 271 .devices = ite_devices, 272 }, 273 { 274 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8720, 275 .devices = ite_devices, 276 }, 277 { 278 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8721, 279 .devices = ite_devices, 280 }, 281 { 282 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8726, 283 .devices = ite_devices, 284 }, 285 { 286 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8728, 287 .devices = ite_devices, 288 }, 289 { 290 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8771, 291 .devices = ite_devices, 292 }, 293 { 294 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x1061, .mask = 0x00, 295 .descr = "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. A)", 296 .devices = nct5104_devices, 297 }, 298 { 299 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5200, .mask = 0xff, 300 .descr = "Winbond 83627HF/F/HG/G", 301 .devices = nvt_devices, 302 }, 303 { 304 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5900, .mask = 0xff, 305 .descr = "Winbond 83627S", 306 .devices = nvt_devices, 307 }, 308 { 309 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6000, .mask = 0xff, 310 .descr = "Winbond 83697HF", 311 .devices = nvt_devices, 312 }, 313 { 314 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6800, .mask = 0xff, 315 .descr = "Winbond 83697UG", 316 .devices = nvt_devices, 317 }, 318 { 319 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x7000, .mask = 0xff, 320 .descr = "Winbond 83637HF", 321 .devices = nvt_devices, 322 }, 323 { 324 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8200, .mask = 0xff, 325 .descr = "Winbond 83627THF", 326 .devices = nvt_devices, 327 }, 328 { 329 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8500, .mask = 0xff, 330 .descr = "Winbond 83687THF", 331 .devices = nvt_devices, 332 }, 333 { 334 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8800, .mask = 0xff, 335 .descr = "Winbond 83627EHF", 336 .devices = nvt_devices, 337 }, 338 { 339 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa000, .mask = 0xff, 340 .descr = "Winbond 83627DHG", 341 .devices = nvt_devices, 342 }, 343 { 344 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa200, .mask = 0xff, 345 .descr = "Winbond 83627UHG", 346 .devices = nvt_devices, 347 }, 348 { 349 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa500, .mask = 0xff, 350 .descr = "Winbond 83667HG", 351 .devices = nvt_devices, 352 }, 353 { 354 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb000, .mask = 0xff, 355 .descr = "Winbond 83627DHG-P", 356 .devices = nvt_devices, 357 }, 358 { 359 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb300, .mask = 0xff, 360 .descr = "Winbond 83667HG-B", 361 .devices = nvt_devices, 362 }, 363 { 364 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb400, .mask = 0xff, 365 .descr = "Nuvoton NCT6775", 366 .devices = nvt_devices, 367 }, 368 { 369 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc300, .mask = 0xff, 370 .descr = "Nuvoton NCT6776", 371 .devices = nvt_devices, 372 }, 373 { 374 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc400, .mask = 0xff, 375 .descr = "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. B+)", 376 .devices = nct5104_devices, 377 }, 378 { 379 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc500, .mask = 0xff, 380 .descr = "Nuvoton NCT6779", 381 .devices = nvt_devices, 382 }, 383 { 384 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc800, .mask = 0xff, 385 .descr = "Nuvoton NCT6791", 386 .devices = nvt_devices, 387 }, 388 { 389 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc900, .mask = 0xff, 390 .descr = "Nuvoton NCT6792", 391 .devices = nvt_devices, 392 }, 393 { 394 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd100, .mask = 0xff, 395 .descr = "Nuvoton NCT6793", 396 .devices = nvt_devices, 397 }, 398 { 399 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd300, .mask = 0xff, 400 .descr = "Nuvoton NCT6795", 401 .devices = nvt_devices, 402 }, 403 { 0, 0 } 404 }; 405 406 static const char * 407 devtype_to_str(superio_dev_type_t type) 408 { 409 switch (type) { 410 case SUPERIO_DEV_NONE: 411 return ("none"); 412 case SUPERIO_DEV_HWM: 413 return ("HWM"); 414 case SUPERIO_DEV_WDT: 415 return ("WDT"); 416 case SUPERIO_DEV_GPIO: 417 return ("GPIO"); 418 case SUPERIO_DEV_MAX: 419 return ("invalid"); 420 } 421 return ("invalid"); 422 } 423 424 static int 425 superio_detect(device_t dev, bool claim, struct siosc *sc) 426 { 427 struct resource *res; 428 rman_res_t port; 429 rman_res_t count; 430 uint16_t devid; 431 uint8_t revid; 432 int error; 433 int rid; 434 int i, m; 435 436 error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &port, &count); 437 if (error != 0) 438 return (error); 439 if (port > UINT16_MAX || count < NUMPORTS) { 440 device_printf(dev, "unexpected I/O range size\n"); 441 return (ENXIO); 442 } 443 444 /* 445 * Make a temporary resource reservation for hardware probing. 446 * If we can't get the resources we need then 447 * we need to abort. Possibly this indicates 448 * the resources were used by another device 449 * in which case the probe would have failed anyhow. 450 */ 451 rid = 0; 452 res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE); 453 if (res == NULL) { 454 if (claim) 455 device_printf(dev, "failed to allocate I/O resource\n"); 456 return (ENXIO); 457 } 458 459 for (m = 0; methods_table[m] != NULL; m++) { 460 methods_table[m]->enter(res, port); 461 if (methods_table[m]->vendor == SUPERIO_VENDOR_ITE) { 462 devid = sio_readw(res, 0x20); 463 revid = sio_read(res, 0x22); 464 } else if (methods_table[m]->vendor == SUPERIO_VENDOR_NUVOTON) { 465 devid = sio_read(res, 0x20); 466 revid = sio_read(res, 0x21); 467 devid = (devid << 8) | revid; 468 } else { 469 continue; 470 } 471 methods_table[m]->exit(res, port); 472 for (i = 0; superio_table[i].vendor != 0; i++) { 473 uint16_t mask; 474 475 mask = superio_table[i].mask; 476 if (superio_table[i].vendor != 477 methods_table[m]->vendor) 478 continue; 479 if ((superio_table[i].devid & ~mask) != (devid & ~mask)) 480 continue; 481 break; 482 } 483 484 /* Found a matching SuperIO entry. */ 485 if (superio_table[i].vendor != 0) 486 break; 487 } 488 489 if (methods_table[m] == NULL) 490 error = ENXIO; 491 else 492 error = 0; 493 if (!claim || error != 0) { 494 bus_release_resource(dev, SYS_RES_IOPORT, rid, res); 495 return (error); 496 } 497 498 sc->methods = methods_table[m]; 499 sc->vendor = sc->methods->vendor; 500 sc->known_devices = superio_table[i].devices; 501 sc->io_res = res; 502 sc->io_rid = rid; 503 sc->io_port = port; 504 sc->devid = devid; 505 sc->revid = revid; 506 507 KASSERT(sc->vendor == SUPERIO_VENDOR_ITE || 508 sc->vendor == SUPERIO_VENDOR_NUVOTON, 509 ("Only ITE and Nuvoton SuperIO-s are supported")); 510 sc->ldn_reg = 0x07; 511 sc->enable_reg = 0x30; 512 sc->current_ldn = 0xff; /* no device should have this */ 513 514 if (superio_table[i].descr != NULL) { 515 device_set_desc(dev, superio_table[i].descr); 516 } else if (sc->vendor == SUPERIO_VENDOR_ITE) { 517 char descr[64]; 518 519 snprintf(descr, sizeof(descr), 520 "ITE IT%4x SuperIO (revision 0x%02x)", 521 sc->devid, sc->revid); 522 device_set_desc_copy(dev, descr); 523 } 524 return (0); 525 } 526 527 static void 528 superio_identify(driver_t *driver, device_t parent) 529 { 530 device_t child; 531 int i; 532 533 /* 534 * Don't create child devices if any already exist. 535 * Those could be created via isa hints or if this 536 * driver is loaded, unloaded and then loaded again. 537 */ 538 if (device_find_child(parent, "superio", -1)) { 539 if (bootverbose) 540 printf("superio: device(s) already created\n"); 541 return; 542 } 543 544 /* 545 * Create a child for each candidate port. 546 * It would be nice if we could somehow clean up those 547 * that this driver fails to probe. 548 */ 549 for (i = 0; ports_table[i] != 0; i++) { 550 child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, 551 "superio", -1); 552 if (child == NULL) { 553 device_printf(parent, "failed to add superio child\n"); 554 continue; 555 } 556 bus_set_resource(child, SYS_RES_IOPORT, 0, ports_table[i], 2); 557 if (superio_detect(child, false, NULL) != 0) 558 device_delete_child(parent, child); 559 } 560 } 561 562 static int 563 superio_probe(device_t dev) 564 { 565 struct siosc *sc; 566 int error; 567 568 /* Make sure we do not claim some ISA PNP device. */ 569 if (isa_get_logicalid(dev) != 0) 570 return (ENXIO); 571 572 /* 573 * XXX We can populate the softc now only because we return 574 * BUS_PROBE_SPECIFIC 575 */ 576 sc = device_get_softc(dev); 577 error = superio_detect(dev, true, sc); 578 if (error != 0) 579 return (error); 580 return (BUS_PROBE_SPECIFIC); 581 } 582 583 static void 584 superio_add_known_child(device_t dev, superio_dev_type_t type, uint8_t ldn) 585 { 586 struct siosc *sc = device_get_softc(dev); 587 struct superio_devinfo *dinfo; 588 device_t child; 589 590 child = BUS_ADD_CHILD(dev, 0, NULL, -1); 591 if (child == NULL) { 592 device_printf(dev, "failed to add child for ldn %d, type %s\n", 593 ldn, devtype_to_str(type)); 594 return; 595 } 596 dinfo = device_get_ivars(child); 597 dinfo->ldn = ldn; 598 dinfo->type = type; 599 sio_conf_enter(sc); 600 dinfo->iobase = sio_ldn_readw(sc, ldn, 0x60); 601 dinfo->iobase2 = sio_ldn_readw(sc, ldn, 0x62); 602 dinfo->irq = sio_ldn_readw(sc, ldn, 0x70); 603 dinfo->dma = sio_ldn_readw(sc, ldn, 0x74); 604 sio_conf_exit(sc); 605 STAILQ_INSERT_TAIL(&sc->devlist, dinfo, link); 606 } 607 608 static int 609 superio_attach(device_t dev) 610 { 611 struct siosc *sc = device_get_softc(dev); 612 int i; 613 614 mtx_init(&sc->conf_lock, device_get_nameunit(dev), "superio", MTX_DEF); 615 STAILQ_INIT(&sc->devlist); 616 617 for (i = 0; sc->known_devices[i].type != SUPERIO_DEV_NONE; i++) { 618 superio_add_known_child(dev, sc->known_devices[i].type, 619 sc->known_devices[i].ldn); 620 } 621 622 bus_generic_probe(dev); 623 bus_generic_attach(dev); 624 return (0); 625 } 626 627 static int 628 superio_detach(device_t dev) 629 { 630 struct siosc *sc = device_get_softc(dev); 631 int error; 632 633 error = bus_generic_detach(dev); 634 if (error != 0) 635 return (error); 636 device_delete_children(dev); 637 bus_release_resource(dev, SYS_RES_IOPORT, sc->io_rid, sc->io_res); 638 mtx_destroy(&sc->conf_lock); 639 return (0); 640 } 641 642 static device_t 643 superio_add_child(device_t dev, u_int order, const char *name, int unit) 644 { 645 struct superio_devinfo *dinfo; 646 device_t child; 647 648 child = device_add_child_ordered(dev, order, name, unit); 649 if (child == NULL) 650 return (NULL); 651 dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_NOWAIT | M_ZERO); 652 if (dinfo == NULL) { 653 device_delete_child(dev, child); 654 return (NULL); 655 } 656 dinfo->ldn = 0xff; 657 dinfo->type = SUPERIO_DEV_NONE; 658 dinfo->dev = child; 659 resource_list_init(&dinfo->resources); 660 device_set_ivars(child, dinfo); 661 return (child); 662 } 663 664 static int 665 superio_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 666 { 667 struct superio_devinfo *dinfo; 668 669 dinfo = device_get_ivars(child); 670 switch (which) { 671 case SUPERIO_IVAR_LDN: 672 *result = dinfo->ldn; 673 break; 674 case SUPERIO_IVAR_TYPE: 675 *result = dinfo->type; 676 break; 677 case SUPERIO_IVAR_IOBASE: 678 *result = dinfo->iobase; 679 break; 680 case SUPERIO_IVAR_IOBASE2: 681 *result = dinfo->iobase2; 682 break; 683 case SUPERIO_IVAR_IRQ: 684 *result = dinfo->irq; 685 break; 686 case SUPERIO_IVAR_DMA: 687 *result = dinfo->dma; 688 break; 689 default: 690 return (ENOENT); 691 } 692 return (0); 693 } 694 695 static int 696 superio_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 697 { 698 699 switch (which) { 700 case SUPERIO_IVAR_LDN: 701 case SUPERIO_IVAR_TYPE: 702 case SUPERIO_IVAR_IOBASE: 703 case SUPERIO_IVAR_IOBASE2: 704 case SUPERIO_IVAR_IRQ: 705 case SUPERIO_IVAR_DMA: 706 return (EINVAL); 707 default: 708 return (ENOENT); 709 } 710 } 711 712 static struct resource_list * 713 superio_get_resource_list(device_t dev, device_t child) 714 { 715 struct superio_devinfo *dinfo = device_get_ivars(child); 716 717 return (&dinfo->resources); 718 } 719 720 static int 721 superio_printf(struct superio_devinfo *dinfo, const char *fmt, ...) 722 { 723 va_list ap; 724 int retval; 725 726 retval = printf("superio:%s@ldn%0x2x: ", 727 devtype_to_str(dinfo->type), dinfo->ldn); 728 va_start(ap, fmt); 729 retval += vprintf(fmt, ap); 730 va_end(ap); 731 return (retval); 732 } 733 734 static void 735 superio_child_detached(device_t dev, device_t child) 736 { 737 struct superio_devinfo *dinfo; 738 struct resource_list *rl; 739 740 dinfo = device_get_ivars(child); 741 rl = &dinfo->resources; 742 743 if (resource_list_release_active(rl, dev, child, SYS_RES_IRQ) != 0) 744 superio_printf(dinfo, "Device leaked IRQ resources\n"); 745 if (resource_list_release_active(rl, dev, child, SYS_RES_MEMORY) != 0) 746 superio_printf(dinfo, "Device leaked memory resources\n"); 747 if (resource_list_release_active(rl, dev, child, SYS_RES_IOPORT) != 0) 748 superio_printf(dinfo, "Device leaked I/O resources\n"); 749 } 750 751 static int 752 superio_child_location_str(device_t parent, device_t child, char *buf, 753 size_t buflen) 754 { 755 uint8_t ldn; 756 757 ldn = superio_get_ldn(child); 758 snprintf(buf, buflen, "ldn=0x%02x", ldn); 759 return (0); 760 } 761 762 static int 763 superio_child_pnp_str(device_t parent, device_t child, char *buf, 764 size_t buflen) 765 { 766 superio_dev_type_t type; 767 768 type = superio_get_type(child); 769 snprintf(buf, buflen, "type=%s", devtype_to_str(type)); 770 return (0); 771 } 772 773 static int 774 superio_print_child(device_t parent, device_t child) 775 { 776 superio_dev_type_t type; 777 uint8_t ldn; 778 int retval; 779 780 ldn = superio_get_ldn(child); 781 type = superio_get_type(child); 782 783 retval = bus_print_child_header(parent, child); 784 retval += printf(" at %s ldn 0x%02x", devtype_to_str(type), ldn); 785 retval += bus_print_child_footer(parent, child); 786 787 return (retval); 788 } 789 790 superio_vendor_t 791 superio_vendor(device_t dev) 792 { 793 device_t sio_dev = device_get_parent(dev); 794 struct siosc *sc = device_get_softc(sio_dev); 795 796 return (sc->vendor); 797 } 798 799 uint16_t 800 superio_devid(device_t dev) 801 { 802 device_t sio_dev = device_get_parent(dev); 803 struct siosc *sc = device_get_softc(sio_dev); 804 805 return (sc->devid); 806 } 807 808 uint8_t 809 superio_revid(device_t dev) 810 { 811 device_t sio_dev = device_get_parent(dev); 812 struct siosc *sc = device_get_softc(sio_dev); 813 814 return (sc->revid); 815 } 816 817 uint8_t 818 superio_read(device_t dev, uint8_t reg) 819 { 820 device_t sio_dev = device_get_parent(dev); 821 struct siosc *sc = device_get_softc(sio_dev); 822 struct superio_devinfo *dinfo = device_get_ivars(dev); 823 uint8_t v; 824 825 sio_conf_enter(sc); 826 v = sio_ldn_read(sc, dinfo->ldn, reg); 827 sio_conf_exit(sc); 828 return (v); 829 } 830 831 void 832 superio_write(device_t dev, uint8_t reg, uint8_t val) 833 { 834 device_t sio_dev = device_get_parent(dev); 835 struct siosc *sc = device_get_softc(sio_dev); 836 struct superio_devinfo *dinfo = device_get_ivars(dev); 837 838 sio_conf_enter(sc); 839 sio_ldn_write(sc, dinfo->ldn, reg, val); 840 sio_conf_exit(sc); 841 } 842 843 bool 844 superio_dev_enabled(device_t dev, uint8_t mask) 845 { 846 device_t sio_dev = device_get_parent(dev); 847 struct siosc *sc = device_get_softc(sio_dev); 848 struct superio_devinfo *dinfo = device_get_ivars(dev); 849 uint8_t v; 850 851 /* GPIO device is always active in ITE chips. */ 852 if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7) 853 return (true); 854 855 v = superio_read(dev, sc->enable_reg); 856 return ((v & mask) != 0); 857 } 858 859 void 860 superio_dev_enable(device_t dev, uint8_t mask) 861 { 862 device_t sio_dev = device_get_parent(dev); 863 struct siosc *sc = device_get_softc(sio_dev); 864 struct superio_devinfo *dinfo = device_get_ivars(dev); 865 uint8_t v; 866 867 /* GPIO device is always active in ITE chips. */ 868 if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7) 869 return; 870 871 sio_conf_enter(sc); 872 v = sio_ldn_read(sc, dinfo->ldn, sc->enable_reg); 873 v |= mask; 874 sio_ldn_write(sc, dinfo->ldn, sc->enable_reg, v); 875 sio_conf_exit(sc); 876 } 877 878 void 879 superio_dev_disable(device_t dev, uint8_t mask) 880 { 881 device_t sio_dev = device_get_parent(dev); 882 struct siosc *sc = device_get_softc(sio_dev); 883 struct superio_devinfo *dinfo = device_get_ivars(dev); 884 uint8_t v; 885 886 /* GPIO device is always active in ITE chips. */ 887 if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7) 888 return; 889 890 sio_conf_enter(sc); 891 v = sio_ldn_read(sc, dinfo->ldn, sc->enable_reg); 892 v &= ~mask; 893 sio_ldn_write(sc, dinfo->ldn, sc->enable_reg, v); 894 sio_conf_exit(sc); 895 } 896 897 device_t 898 superio_find_dev(device_t superio, superio_dev_type_t type, int ldn) 899 { 900 struct siosc *sc = device_get_softc(superio); 901 struct superio_devinfo *dinfo; 902 903 if (ldn < -1 || ldn > UINT8_MAX) 904 return (NULL); /* ERANGE */ 905 if (type == SUPERIO_DEV_NONE && ldn == -1) 906 return (NULL); /* EINVAL */ 907 908 STAILQ_FOREACH(dinfo, &sc->devlist, link) { 909 if (ldn != -1 && dinfo->ldn != ldn) 910 continue; 911 if (type != SUPERIO_DEV_NONE && dinfo->type != type) 912 continue; 913 return (dinfo->dev); 914 } 915 return (NULL); 916 } 917 918 static devclass_t superio_devclass; 919 920 static device_method_t superio_methods[] = { 921 DEVMETHOD(device_identify, superio_identify), 922 DEVMETHOD(device_probe, superio_probe), 923 DEVMETHOD(device_attach, superio_attach), 924 DEVMETHOD(device_detach, superio_detach), 925 DEVMETHOD(device_shutdown, bus_generic_shutdown), 926 DEVMETHOD(device_suspend, bus_generic_suspend), 927 DEVMETHOD(device_resume, bus_generic_resume), 928 929 DEVMETHOD(bus_add_child, superio_add_child), 930 DEVMETHOD(bus_child_detached, superio_child_detached), 931 DEVMETHOD(bus_child_location_str, superio_child_location_str), 932 DEVMETHOD(bus_child_pnpinfo_str, superio_child_pnp_str), 933 DEVMETHOD(bus_print_child, superio_print_child), 934 DEVMETHOD(bus_read_ivar, superio_read_ivar), 935 DEVMETHOD(bus_write_ivar, superio_write_ivar), 936 DEVMETHOD(bus_get_resource_list, superio_get_resource_list), 937 DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), 938 DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 939 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 940 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 941 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 942 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 943 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 944 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 945 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 946 947 DEVMETHOD_END 948 }; 949 950 static driver_t superio_driver = { 951 "superio", 952 superio_methods, 953 sizeof(struct siosc) 954 }; 955 956 DRIVER_MODULE(superio, isa, superio_driver, superio_devclass, 0, 0); 957 MODULE_VERSION(superio, 1); 958