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