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 char descr[64]; 620 621 snprintf(descr, sizeof(descr), 622 "ITE IT%4x SuperIO (revision 0x%02x)", 623 sc->devid, sc->revid); 624 device_set_desc_copy(dev, descr); 625 } 626 return (0); 627 } 628 629 static void 630 superio_identify(driver_t *driver, device_t parent) 631 { 632 device_t child; 633 int i; 634 635 /* 636 * Don't create child devices if any already exist. 637 * Those could be created via isa hints or if this 638 * driver is loaded, unloaded and then loaded again. 639 */ 640 if (device_find_child(parent, "superio", -1)) { 641 if (bootverbose) 642 printf("superio: device(s) already created\n"); 643 return; 644 } 645 646 /* 647 * Create a child for each candidate port. 648 * It would be nice if we could somehow clean up those 649 * that this driver fails to probe. 650 */ 651 for (i = 0; ports_table[i] != 0; i++) { 652 child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE, 653 "superio", -1); 654 if (child == NULL) { 655 device_printf(parent, "failed to add superio child\n"); 656 continue; 657 } 658 bus_set_resource(child, SYS_RES_IOPORT, 0, ports_table[i], 2); 659 if (superio_detect(child, false, NULL) != 0) 660 device_delete_child(parent, child); 661 } 662 } 663 664 static int 665 superio_probe(device_t dev) 666 { 667 struct siosc *sc; 668 int error; 669 670 /* Make sure we do not claim some ISA PNP device. */ 671 if (isa_get_logicalid(dev) != 0) 672 return (ENXIO); 673 674 /* 675 * XXX We can populate the softc now only because we return 676 * BUS_PROBE_SPECIFIC 677 */ 678 sc = device_get_softc(dev); 679 error = superio_detect(dev, true, sc); 680 if (error != 0) 681 return (error); 682 return (BUS_PROBE_SPECIFIC); 683 } 684 685 static void 686 superio_add_known_child(device_t dev, superio_dev_type_t type, uint8_t ldn) 687 { 688 struct siosc *sc = device_get_softc(dev); 689 struct superio_devinfo *dinfo; 690 device_t child; 691 692 child = BUS_ADD_CHILD(dev, 0, NULL, -1); 693 if (child == NULL) { 694 device_printf(dev, "failed to add child for ldn %d, type %s\n", 695 ldn, devtype_to_str(type)); 696 return; 697 } 698 dinfo = device_get_ivars(child); 699 dinfo->ldn = ldn; 700 dinfo->type = type; 701 sio_conf_enter(sc); 702 dinfo->iobase = sio_ldn_readw(sc, ldn, 0x60); 703 dinfo->iobase2 = sio_ldn_readw(sc, ldn, 0x62); 704 dinfo->irq = sio_ldn_readw(sc, ldn, 0x70); 705 dinfo->dma = sio_ldn_readw(sc, ldn, 0x74); 706 sio_conf_exit(sc); 707 STAILQ_INSERT_TAIL(&sc->devlist, dinfo, link); 708 } 709 710 static int 711 superio_attach(device_t dev) 712 { 713 struct siosc *sc = device_get_softc(dev); 714 int i; 715 716 mtx_init(&sc->conf_lock, device_get_nameunit(dev), "superio", MTX_DEF); 717 STAILQ_INIT(&sc->devlist); 718 719 for (i = 0; sc->known_devices[i].type != SUPERIO_DEV_NONE; i++) { 720 superio_add_known_child(dev, sc->known_devices[i].type, 721 sc->known_devices[i].ldn); 722 } 723 724 bus_generic_probe(dev); 725 bus_generic_attach(dev); 726 727 sc->chardev = make_dev(&superio_cdevsw, device_get_unit(dev), 728 UID_ROOT, GID_WHEEL, 0600, "superio%d", device_get_unit(dev)); 729 if (sc->chardev == NULL) 730 device_printf(dev, "failed to create character device\n"); 731 else 732 sc->chardev->si_drv1 = sc; 733 return (0); 734 } 735 736 static int 737 superio_detach(device_t dev) 738 { 739 struct siosc *sc = device_get_softc(dev); 740 int error; 741 742 error = bus_generic_detach(dev); 743 if (error != 0) 744 return (error); 745 if (sc->chardev != NULL) 746 destroy_dev(sc->chardev); 747 device_delete_children(dev); 748 bus_release_resource(dev, SYS_RES_IOPORT, sc->io_rid, sc->io_res); 749 mtx_destroy(&sc->conf_lock); 750 return (0); 751 } 752 753 static device_t 754 superio_add_child(device_t dev, u_int order, const char *name, int unit) 755 { 756 struct superio_devinfo *dinfo; 757 device_t child; 758 759 child = device_add_child_ordered(dev, order, name, unit); 760 if (child == NULL) 761 return (NULL); 762 dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_NOWAIT | M_ZERO); 763 if (dinfo == NULL) { 764 device_delete_child(dev, child); 765 return (NULL); 766 } 767 dinfo->ldn = 0xff; 768 dinfo->type = SUPERIO_DEV_NONE; 769 dinfo->dev = child; 770 resource_list_init(&dinfo->resources); 771 device_set_ivars(child, dinfo); 772 return (child); 773 } 774 775 static int 776 superio_read_ivar(device_t dev, device_t child, int which, uintptr_t *result) 777 { 778 struct superio_devinfo *dinfo; 779 780 dinfo = device_get_ivars(child); 781 switch (which) { 782 case SUPERIO_IVAR_LDN: 783 *result = dinfo->ldn; 784 break; 785 case SUPERIO_IVAR_TYPE: 786 *result = dinfo->type; 787 break; 788 case SUPERIO_IVAR_IOBASE: 789 *result = dinfo->iobase; 790 break; 791 case SUPERIO_IVAR_IOBASE2: 792 *result = dinfo->iobase2; 793 break; 794 case SUPERIO_IVAR_IRQ: 795 *result = dinfo->irq; 796 break; 797 case SUPERIO_IVAR_DMA: 798 *result = dinfo->dma; 799 break; 800 default: 801 return (ENOENT); 802 } 803 return (0); 804 } 805 806 static int 807 superio_write_ivar(device_t dev, device_t child, int which, uintptr_t value) 808 { 809 810 switch (which) { 811 case SUPERIO_IVAR_LDN: 812 case SUPERIO_IVAR_TYPE: 813 case SUPERIO_IVAR_IOBASE: 814 case SUPERIO_IVAR_IOBASE2: 815 case SUPERIO_IVAR_IRQ: 816 case SUPERIO_IVAR_DMA: 817 return (EINVAL); 818 default: 819 return (ENOENT); 820 } 821 } 822 823 static struct resource_list * 824 superio_get_resource_list(device_t dev, device_t child) 825 { 826 struct superio_devinfo *dinfo = device_get_ivars(child); 827 828 return (&dinfo->resources); 829 } 830 831 static int 832 superio_printf(struct superio_devinfo *dinfo, const char *fmt, ...) 833 { 834 va_list ap; 835 int retval; 836 837 retval = printf("superio:%s@ldn%0x2x: ", 838 devtype_to_str(dinfo->type), dinfo->ldn); 839 va_start(ap, fmt); 840 retval += vprintf(fmt, ap); 841 va_end(ap); 842 return (retval); 843 } 844 845 static void 846 superio_child_detached(device_t dev, device_t child) 847 { 848 struct superio_devinfo *dinfo; 849 struct resource_list *rl; 850 851 dinfo = device_get_ivars(child); 852 rl = &dinfo->resources; 853 854 if (resource_list_release_active(rl, dev, child, SYS_RES_IRQ) != 0) 855 superio_printf(dinfo, "Device leaked IRQ resources\n"); 856 if (resource_list_release_active(rl, dev, child, SYS_RES_MEMORY) != 0) 857 superio_printf(dinfo, "Device leaked memory resources\n"); 858 if (resource_list_release_active(rl, dev, child, SYS_RES_IOPORT) != 0) 859 superio_printf(dinfo, "Device leaked I/O resources\n"); 860 } 861 862 static int 863 superio_child_location(device_t parent, device_t child, struct sbuf *sb) 864 { 865 uint8_t ldn; 866 867 ldn = superio_get_ldn(child); 868 sbuf_printf(sb, "ldn=0x%02x", ldn); 869 return (0); 870 } 871 872 static int 873 superio_child_pnp(device_t parent, device_t child, struct sbuf *sb) 874 { 875 superio_dev_type_t type; 876 877 type = superio_get_type(child); 878 sbuf_printf(sb, "type=%s", devtype_to_str(type)); 879 return (0); 880 } 881 882 static int 883 superio_print_child(device_t parent, device_t child) 884 { 885 superio_dev_type_t type; 886 uint8_t ldn; 887 int retval; 888 889 ldn = superio_get_ldn(child); 890 type = superio_get_type(child); 891 892 retval = bus_print_child_header(parent, child); 893 retval += printf(" at %s ldn 0x%02x", devtype_to_str(type), ldn); 894 retval += bus_print_child_footer(parent, child); 895 896 return (retval); 897 } 898 899 superio_vendor_t 900 superio_vendor(device_t dev) 901 { 902 device_t sio_dev = device_get_parent(dev); 903 struct siosc *sc = device_get_softc(sio_dev); 904 905 return (sc->vendor); 906 } 907 908 uint16_t 909 superio_devid(device_t dev) 910 { 911 device_t sio_dev = device_get_parent(dev); 912 struct siosc *sc = device_get_softc(sio_dev); 913 914 return (sc->devid); 915 } 916 917 uint8_t 918 superio_revid(device_t dev) 919 { 920 device_t sio_dev = device_get_parent(dev); 921 struct siosc *sc = device_get_softc(sio_dev); 922 923 return (sc->revid); 924 } 925 926 int 927 superio_extid(device_t dev) 928 { 929 device_t sio_dev = device_get_parent(dev); 930 struct siosc *sc = device_get_softc(sio_dev); 931 932 return (sc->extid); 933 } 934 935 uint8_t 936 superio_ldn_read(device_t dev, uint8_t ldn, uint8_t reg) 937 { 938 device_t sio_dev = device_get_parent(dev); 939 struct siosc *sc = device_get_softc(sio_dev); 940 uint8_t v; 941 942 sio_conf_enter(sc); 943 v = sio_ldn_read(sc, ldn, reg); 944 sio_conf_exit(sc); 945 return (v); 946 } 947 948 uint8_t 949 superio_read(device_t dev, uint8_t reg) 950 { 951 struct superio_devinfo *dinfo = device_get_ivars(dev); 952 953 return (superio_ldn_read(dev, dinfo->ldn, reg)); 954 } 955 956 void 957 superio_ldn_write(device_t dev, uint8_t ldn, uint8_t reg, uint8_t val) 958 { 959 device_t sio_dev = device_get_parent(dev); 960 struct siosc *sc = device_get_softc(sio_dev); 961 962 sio_conf_enter(sc); 963 sio_ldn_write(sc, ldn, reg, val); 964 sio_conf_exit(sc); 965 } 966 967 void 968 superio_write(device_t dev, uint8_t reg, uint8_t val) 969 { 970 struct superio_devinfo *dinfo = device_get_ivars(dev); 971 972 return (superio_ldn_write(dev, dinfo->ldn, reg, val)); 973 } 974 975 bool 976 superio_dev_enabled(device_t dev, uint8_t mask) 977 { 978 device_t sio_dev = device_get_parent(dev); 979 struct siosc *sc = device_get_softc(sio_dev); 980 struct superio_devinfo *dinfo = device_get_ivars(dev); 981 uint8_t v; 982 983 /* GPIO device is always active in ITE chips. */ 984 if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7) 985 return (true); 986 987 v = superio_read(dev, sc->enable_reg); /* FIXME enable_reg not used by nctgpio(4). */ 988 return ((v & mask) != 0); 989 } 990 991 void 992 superio_dev_enable(device_t dev, uint8_t mask) 993 { 994 device_t sio_dev = device_get_parent(dev); 995 struct siosc *sc = device_get_softc(sio_dev); 996 struct superio_devinfo *dinfo = device_get_ivars(dev); 997 uint8_t v; 998 999 /* GPIO device is always active in ITE chips. */ 1000 if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7) 1001 return; 1002 1003 sio_conf_enter(sc); 1004 v = sio_ldn_read(sc, dinfo->ldn, sc->enable_reg); 1005 v |= mask; 1006 sio_ldn_write(sc, dinfo->ldn, sc->enable_reg, v); 1007 sio_conf_exit(sc); 1008 } 1009 1010 void 1011 superio_dev_disable(device_t dev, uint8_t mask) 1012 { 1013 device_t sio_dev = device_get_parent(dev); 1014 struct siosc *sc = device_get_softc(sio_dev); 1015 struct superio_devinfo *dinfo = device_get_ivars(dev); 1016 uint8_t v; 1017 1018 /* GPIO device is always active in ITE chips. */ 1019 if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7) 1020 return; 1021 1022 sio_conf_enter(sc); 1023 v = sio_ldn_read(sc, dinfo->ldn, sc->enable_reg); 1024 v &= ~mask; 1025 sio_ldn_write(sc, dinfo->ldn, sc->enable_reg, v); 1026 sio_conf_exit(sc); 1027 } 1028 1029 device_t 1030 superio_find_dev(device_t superio, superio_dev_type_t type, int ldn) 1031 { 1032 struct siosc *sc = device_get_softc(superio); 1033 struct superio_devinfo *dinfo; 1034 1035 if (ldn < -1 || ldn > UINT8_MAX) 1036 return (NULL); /* ERANGE */ 1037 if (type == SUPERIO_DEV_NONE && ldn == -1) 1038 return (NULL); /* EINVAL */ 1039 1040 STAILQ_FOREACH(dinfo, &sc->devlist, link) { 1041 if (ldn != -1 && dinfo->ldn != ldn) 1042 continue; 1043 if (type != SUPERIO_DEV_NONE && dinfo->type != type) 1044 continue; 1045 return (dinfo->dev); 1046 } 1047 return (NULL); 1048 } 1049 1050 static int 1051 superio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags, 1052 struct thread *td) 1053 { 1054 struct siosc *sc; 1055 struct superiocmd *s; 1056 1057 sc = dev->si_drv1; 1058 s = (struct superiocmd *)data; 1059 switch (cmd) { 1060 case SUPERIO_CR_READ: 1061 sio_conf_enter(sc); 1062 s->val = sio_ldn_read(sc, s->ldn, s->cr); 1063 sio_conf_exit(sc); 1064 return (0); 1065 case SUPERIO_CR_WRITE: 1066 sio_conf_enter(sc); 1067 sio_ldn_write(sc, s->ldn, s->cr, s->val); 1068 sio_conf_exit(sc); 1069 return (0); 1070 default: 1071 return (ENOTTY); 1072 } 1073 } 1074 1075 static device_method_t superio_methods[] = { 1076 DEVMETHOD(device_identify, superio_identify), 1077 DEVMETHOD(device_probe, superio_probe), 1078 DEVMETHOD(device_attach, superio_attach), 1079 DEVMETHOD(device_detach, superio_detach), 1080 DEVMETHOD(device_shutdown, bus_generic_shutdown), 1081 DEVMETHOD(device_suspend, bus_generic_suspend), 1082 DEVMETHOD(device_resume, bus_generic_resume), 1083 1084 DEVMETHOD(bus_add_child, superio_add_child), 1085 DEVMETHOD(bus_child_detached, superio_child_detached), 1086 DEVMETHOD(bus_child_location, superio_child_location), 1087 DEVMETHOD(bus_child_pnpinfo, superio_child_pnp), 1088 DEVMETHOD(bus_print_child, superio_print_child), 1089 DEVMETHOD(bus_read_ivar, superio_read_ivar), 1090 DEVMETHOD(bus_write_ivar, superio_write_ivar), 1091 DEVMETHOD(bus_get_resource_list, superio_get_resource_list), 1092 DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource), 1093 DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource), 1094 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource), 1095 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource), 1096 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource), 1097 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource), 1098 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource), 1099 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr), 1100 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr), 1101 1102 DEVMETHOD_END 1103 }; 1104 1105 static driver_t superio_driver = { 1106 "superio", 1107 superio_methods, 1108 sizeof(struct siosc) 1109 }; 1110 1111 DRIVER_MODULE(superio, isa, superio_driver, 0, 0); 1112 MODULE_VERSION(superio, 1); 1113