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