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