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