2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2019 Andriy Gapon
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
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.
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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/systm.h>
37 #include <sys/kernel.h>
39 #include <sys/mutex.h>
40 #include <sys/malloc.h>
41 #include <sys/module.h>
47 #include <machine/bus.h>
48 #include <machine/resource.h>
49 #include <machine/stdarg.h>
51 #include <isa/isavar.h>
53 #include <dev/superio/superio.h>
54 #include <dev/superio/superio_io.h>
58 typedef void (*sio_conf_enter_f)(struct resource*, uint16_t);
59 typedef void (*sio_conf_exit_f)(struct resource*, uint16_t);
61 struct sio_conf_methods {
62 sio_conf_enter_f enter;
64 superio_vendor_t vendor;
69 superio_dev_type_t type;
72 struct superio_devinfo {
73 STAILQ_ENTRY(superio_devinfo) link;
74 struct resource_list resources;
77 superio_dev_type_t type;
86 STAILQ_HEAD(, superio_devinfo) devlist;
87 struct resource* io_res;
91 const struct sio_conf_methods *methods;
92 const struct sio_device *known_devices;
93 superio_vendor_t vendor;
101 static d_ioctl_t superio_ioctl;
103 static struct cdevsw superio_cdevsw = {
104 .d_version = D_VERSION,
105 .d_ioctl = superio_ioctl,
112 sio_read(struct resource* res, uint8_t reg)
114 bus_write_1(res, 0, reg);
115 return (bus_read_1(res, 1));
118 /* Read a word from two one-byte registers, big endian. */
120 sio_readw(struct resource* res, uint8_t reg)
124 v = sio_read(res, reg);
126 v |= sio_read(res, reg + 1);
131 sio_write(struct resource* res, uint8_t reg, uint8_t val)
133 bus_write_1(res, 0, reg);
134 bus_write_1(res, 1, val);
138 sio_ldn_select(struct siosc *sc, uint8_t ldn)
140 mtx_assert(&sc->conf_lock, MA_OWNED);
141 if (ldn == sc->current_ldn)
143 sio_write(sc->io_res, sc->ldn_reg, ldn);
144 sc->current_ldn = ldn;
148 sio_ldn_read(struct siosc *sc, uint8_t ldn, uint8_t reg)
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"));
155 return (sio_read(sc->io_res, reg));
159 sio_ldn_readw(struct siosc *sc, uint8_t ldn, uint8_t reg)
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"));
166 return (sio_readw(sc->io_res, reg));
170 sio_ldn_write(struct siosc *sc, uint8_t ldn, uint8_t reg, uint8_t val)
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);
177 sio_ldn_select(sc, ldn);
178 KASSERT(sc->current_ldn == ldn, ("sio_ldn_select failed"));
179 sio_write(sc->io_res, reg, val);
183 sio_conf_enter(struct siosc *sc)
185 mtx_lock(&sc->conf_lock);
186 sc->methods->enter(sc->io_res, sc->io_port);
190 sio_conf_exit(struct siosc *sc)
192 sc->methods->exit(sc->io_res, sc->io_port);
193 sc->current_ldn = 0xff;
194 mtx_unlock(&sc->conf_lock);
198 ite_conf_enter(struct resource* res, uint16_t port)
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);
207 ite_conf_exit(struct resource* res, uint16_t port)
209 sio_write(res, 0x02, 0x02);
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
219 nvt_conf_enter(struct resource* res, uint16_t port)
221 bus_write_1(res, 0, 0x87);
222 bus_write_1(res, 0, 0x87);
226 nvt_conf_exit(struct resource* res, uint16_t port)
228 bus_write_1(res, 0, 0xaa);
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
238 fintek_conf_enter(struct resource* res, uint16_t port)
240 bus_write_1(res, 0, 0x87);
241 bus_write_1(res, 0, 0x87);
245 fintek_conf_exit(struct resource* res, uint16_t port)
247 bus_write_1(res, 0, 0xaa);
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
256 static const struct sio_conf_methods * const methods_table[] = {
259 &fintek_conf_methods,
263 static const uint16_t ports_table[] = {
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 },
273 const struct sio_device nvt_devices[] = {
274 { .ldn = 8, .type = SUPERIO_DEV_WDT },
275 { .type = SUPERIO_DEV_NONE },
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 },
285 const struct sio_device fintek_devices[] = {
286 { .ldn = 7, .type = SUPERIO_DEV_WDT },
287 { .type = SUPERIO_DEV_NONE },
290 static const struct {
291 superio_vendor_t vendor;
295 const struct sio_device *devices;
296 } superio_table[] = {
298 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8712,
299 .devices = ite_devices,
302 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8716,
303 .devices = ite_devices,
306 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8718,
307 .devices = ite_devices,
310 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8720,
311 .devices = ite_devices,
314 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8721,
315 .devices = ite_devices,
318 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8726,
319 .devices = ite_devices,
322 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8728,
323 .devices = ite_devices,
326 .vendor = SUPERIO_VENDOR_ITE, .devid = 0x8771,
327 .devices = ite_devices,
330 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x1061, .mask = 0x00,
331 .descr = "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. A)",
332 .devices = nct5104_devices,
335 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5200, .mask = 0xff,
336 .descr = "Winbond 83627HF/F/HG/G",
337 .devices = nvt_devices,
340 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x5900, .mask = 0xff,
341 .descr = "Winbond 83627S",
342 .devices = nvt_devices,
345 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6000, .mask = 0xff,
346 .descr = "Winbond 83697HF",
347 .devices = nvt_devices,
350 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x6800, .mask = 0xff,
351 .descr = "Winbond 83697UG",
352 .devices = nvt_devices,
355 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x7000, .mask = 0xff,
356 .descr = "Winbond 83637HF",
357 .devices = nvt_devices,
360 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8200, .mask = 0xff,
361 .descr = "Winbond 83627THF",
362 .devices = nvt_devices,
365 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8500, .mask = 0xff,
366 .descr = "Winbond 83687THF",
367 .devices = nvt_devices,
370 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0x8800, .mask = 0xff,
371 .descr = "Winbond 83627EHF",
372 .devices = nvt_devices,
375 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa000, .mask = 0xff,
376 .descr = "Winbond 83627DHG",
377 .devices = nvt_devices,
380 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa200, .mask = 0xff,
381 .descr = "Winbond 83627UHG",
382 .devices = nvt_devices,
385 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xa500, .mask = 0xff,
386 .descr = "Winbond 83667HG",
387 .devices = nvt_devices,
390 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb000, .mask = 0xff,
391 .descr = "Winbond 83627DHG-P",
392 .devices = nvt_devices,
395 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb300, .mask = 0xff,
396 .descr = "Winbond 83667HG-B",
397 .devices = nvt_devices,
400 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xb400, .mask = 0xff,
401 .descr = "Nuvoton NCT6775",
402 .devices = nvt_devices,
405 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc300, .mask = 0xff,
406 .descr = "Nuvoton NCT6776",
407 .devices = nvt_devices,
410 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc400, .mask = 0xff,
411 .descr = "Nuvoton NCT5104D/NCT6102D/NCT6106D (rev. B+)",
412 .devices = nct5104_devices,
415 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc500, .mask = 0xff,
416 .descr = "Nuvoton NCT6779",
417 .devices = nvt_devices,
420 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc800, .mask = 0xff,
421 .descr = "Nuvoton NCT6791",
422 .devices = nvt_devices,
425 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xc900, .mask = 0xff,
426 .descr = "Nuvoton NCT6792",
427 .devices = nvt_devices,
430 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd100, .mask = 0xff,
431 .descr = "Nuvoton NCT6793",
432 .devices = nvt_devices,
435 .vendor = SUPERIO_VENDOR_NUVOTON, .devid = 0xd300, .mask = 0xff,
436 .descr = "Nuvoton NCT6795",
437 .devices = nvt_devices,
440 .vendor = SUPERIO_VENDOR_FINTEK, .devid = 0x1210, .mask = 0xff,
441 .descr = "Fintek F81803",
442 .devices = fintek_devices,
448 devtype_to_str(superio_dev_type_t type)
451 case SUPERIO_DEV_NONE:
453 case SUPERIO_DEV_HWM:
455 case SUPERIO_DEV_WDT:
457 case SUPERIO_DEV_GPIO:
459 case SUPERIO_DEV_MAX:
466 superio_detect(device_t dev, bool claim, struct siosc *sc)
468 struct resource *res;
477 error = bus_get_resource(dev, SYS_RES_IOPORT, 0, &port, &count);
480 if (port > UINT16_MAX || count < NUMPORTS) {
481 device_printf(dev, "unexpected I/O range size\n");
486 * Make a temporary resource reservation for hardware probing.
487 * If we can't get the resources we need then
488 * we need to abort. Possibly this indicates
489 * the resources were used by another device
490 * in which case the probe would have failed anyhow.
493 res = bus_alloc_resource_any(dev, SYS_RES_IOPORT, &rid, RF_ACTIVE);
496 device_printf(dev, "failed to allocate I/O resource\n");
500 for (m = 0; methods_table[m] != NULL; m++) {
501 methods_table[m]->enter(res, port);
502 if (methods_table[m]->vendor == SUPERIO_VENDOR_ITE) {
503 devid = sio_readw(res, 0x20);
504 revid = sio_read(res, 0x22);
505 } else if (methods_table[m]->vendor == SUPERIO_VENDOR_NUVOTON) {
506 devid = sio_read(res, 0x20);
507 revid = sio_read(res, 0x21);
508 devid = (devid << 8) | revid;
509 } else if (methods_table[m]->vendor == SUPERIO_VENDOR_FINTEK) {
510 devid = sio_read(res, 0x20);
511 revid = sio_read(res, 0x21);
512 devid = (devid << 8) | revid;
516 methods_table[m]->exit(res, port);
517 for (i = 0; superio_table[i].vendor != 0; i++) {
520 mask = superio_table[i].mask;
521 if (superio_table[i].vendor !=
522 methods_table[m]->vendor)
524 if ((superio_table[i].devid & ~mask) != (devid & ~mask))
529 /* Found a matching SuperIO entry. */
530 if (superio_table[i].vendor != 0)
534 if (methods_table[m] == NULL)
538 if (!claim || error != 0) {
539 bus_release_resource(dev, SYS_RES_IOPORT, rid, res);
543 sc->methods = methods_table[m];
544 sc->vendor = sc->methods->vendor;
545 sc->known_devices = superio_table[i].devices;
552 KASSERT(sc->vendor == SUPERIO_VENDOR_ITE ||
553 sc->vendor == SUPERIO_VENDOR_NUVOTON,
554 ("Only ITE and Nuvoton SuperIO-s are supported"));
556 sc->enable_reg = 0x30;
557 sc->current_ldn = 0xff; /* no device should have this */
559 if (superio_table[i].descr != NULL) {
560 device_set_desc(dev, superio_table[i].descr);
561 } else if (sc->vendor == SUPERIO_VENDOR_ITE) {
564 snprintf(descr, sizeof(descr),
565 "ITE IT%4x SuperIO (revision 0x%02x)",
566 sc->devid, sc->revid);
567 device_set_desc_copy(dev, descr);
573 superio_identify(driver_t *driver, device_t parent)
579 * Don't create child devices if any already exist.
580 * Those could be created via isa hints or if this
581 * driver is loaded, unloaded and then loaded again.
583 if (device_find_child(parent, "superio", -1)) {
585 printf("superio: device(s) already created\n");
590 * Create a child for each candidate port.
591 * It would be nice if we could somehow clean up those
592 * that this driver fails to probe.
594 for (i = 0; ports_table[i] != 0; i++) {
595 child = BUS_ADD_CHILD(parent, ISA_ORDER_SPECULATIVE,
598 device_printf(parent, "failed to add superio child\n");
601 bus_set_resource(child, SYS_RES_IOPORT, 0, ports_table[i], 2);
602 if (superio_detect(child, false, NULL) != 0)
603 device_delete_child(parent, child);
608 superio_probe(device_t dev)
613 /* Make sure we do not claim some ISA PNP device. */
614 if (isa_get_logicalid(dev) != 0)
618 * XXX We can populate the softc now only because we return
621 sc = device_get_softc(dev);
622 error = superio_detect(dev, true, sc);
625 return (BUS_PROBE_SPECIFIC);
629 superio_add_known_child(device_t dev, superio_dev_type_t type, uint8_t ldn)
631 struct siosc *sc = device_get_softc(dev);
632 struct superio_devinfo *dinfo;
635 child = BUS_ADD_CHILD(dev, 0, NULL, -1);
637 device_printf(dev, "failed to add child for ldn %d, type %s\n",
638 ldn, devtype_to_str(type));
641 dinfo = device_get_ivars(child);
645 dinfo->iobase = sio_ldn_readw(sc, ldn, 0x60);
646 dinfo->iobase2 = sio_ldn_readw(sc, ldn, 0x62);
647 dinfo->irq = sio_ldn_readw(sc, ldn, 0x70);
648 dinfo->dma = sio_ldn_readw(sc, ldn, 0x74);
650 STAILQ_INSERT_TAIL(&sc->devlist, dinfo, link);
654 superio_attach(device_t dev)
656 struct siosc *sc = device_get_softc(dev);
659 mtx_init(&sc->conf_lock, device_get_nameunit(dev), "superio", MTX_DEF);
660 STAILQ_INIT(&sc->devlist);
662 for (i = 0; sc->known_devices[i].type != SUPERIO_DEV_NONE; i++) {
663 superio_add_known_child(dev, sc->known_devices[i].type,
664 sc->known_devices[i].ldn);
667 bus_generic_probe(dev);
668 bus_generic_attach(dev);
670 sc->chardev = make_dev(&superio_cdevsw, device_get_unit(dev),
671 UID_ROOT, GID_WHEEL, 0600, "superio%d", device_get_unit(dev));
672 if (sc->chardev == NULL)
673 device_printf(dev, "failed to create character device\n");
675 sc->chardev->si_drv1 = sc;
680 superio_detach(device_t dev)
682 struct siosc *sc = device_get_softc(dev);
685 error = bus_generic_detach(dev);
688 if (sc->chardev != NULL)
689 destroy_dev(sc->chardev);
690 device_delete_children(dev);
691 bus_release_resource(dev, SYS_RES_IOPORT, sc->io_rid, sc->io_res);
692 mtx_destroy(&sc->conf_lock);
697 superio_add_child(device_t dev, u_int order, const char *name, int unit)
699 struct superio_devinfo *dinfo;
702 child = device_add_child_ordered(dev, order, name, unit);
705 dinfo = malloc(sizeof(*dinfo), M_DEVBUF, M_NOWAIT | M_ZERO);
707 device_delete_child(dev, child);
711 dinfo->type = SUPERIO_DEV_NONE;
713 resource_list_init(&dinfo->resources);
714 device_set_ivars(child, dinfo);
719 superio_read_ivar(device_t dev, device_t child, int which, uintptr_t *result)
721 struct superio_devinfo *dinfo;
723 dinfo = device_get_ivars(child);
725 case SUPERIO_IVAR_LDN:
726 *result = dinfo->ldn;
728 case SUPERIO_IVAR_TYPE:
729 *result = dinfo->type;
731 case SUPERIO_IVAR_IOBASE:
732 *result = dinfo->iobase;
734 case SUPERIO_IVAR_IOBASE2:
735 *result = dinfo->iobase2;
737 case SUPERIO_IVAR_IRQ:
738 *result = dinfo->irq;
740 case SUPERIO_IVAR_DMA:
741 *result = dinfo->dma;
750 superio_write_ivar(device_t dev, device_t child, int which, uintptr_t value)
754 case SUPERIO_IVAR_LDN:
755 case SUPERIO_IVAR_TYPE:
756 case SUPERIO_IVAR_IOBASE:
757 case SUPERIO_IVAR_IOBASE2:
758 case SUPERIO_IVAR_IRQ:
759 case SUPERIO_IVAR_DMA:
766 static struct resource_list *
767 superio_get_resource_list(device_t dev, device_t child)
769 struct superio_devinfo *dinfo = device_get_ivars(child);
771 return (&dinfo->resources);
775 superio_printf(struct superio_devinfo *dinfo, const char *fmt, ...)
780 retval = printf("superio:%s@ldn%0x2x: ",
781 devtype_to_str(dinfo->type), dinfo->ldn);
783 retval += vprintf(fmt, ap);
789 superio_child_detached(device_t dev, device_t child)
791 struct superio_devinfo *dinfo;
792 struct resource_list *rl;
794 dinfo = device_get_ivars(child);
795 rl = &dinfo->resources;
797 if (resource_list_release_active(rl, dev, child, SYS_RES_IRQ) != 0)
798 superio_printf(dinfo, "Device leaked IRQ resources\n");
799 if (resource_list_release_active(rl, dev, child, SYS_RES_MEMORY) != 0)
800 superio_printf(dinfo, "Device leaked memory resources\n");
801 if (resource_list_release_active(rl, dev, child, SYS_RES_IOPORT) != 0)
802 superio_printf(dinfo, "Device leaked I/O resources\n");
806 superio_child_location(device_t parent, device_t child, struct sbuf *sb)
810 ldn = superio_get_ldn(child);
811 sbuf_printf(sb, "ldn=0x%02x", ldn);
816 superio_child_pnp(device_t parent, device_t child, struct sbuf *sb)
818 superio_dev_type_t type;
820 type = superio_get_type(child);
821 sbuf_printf(sb, "type=%s", devtype_to_str(type));
826 superio_print_child(device_t parent, device_t child)
828 superio_dev_type_t type;
832 ldn = superio_get_ldn(child);
833 type = superio_get_type(child);
835 retval = bus_print_child_header(parent, child);
836 retval += printf(" at %s ldn 0x%02x", devtype_to_str(type), ldn);
837 retval += bus_print_child_footer(parent, child);
843 superio_vendor(device_t dev)
845 device_t sio_dev = device_get_parent(dev);
846 struct siosc *sc = device_get_softc(sio_dev);
852 superio_devid(device_t dev)
854 device_t sio_dev = device_get_parent(dev);
855 struct siosc *sc = device_get_softc(sio_dev);
861 superio_revid(device_t dev)
863 device_t sio_dev = device_get_parent(dev);
864 struct siosc *sc = device_get_softc(sio_dev);
870 superio_read(device_t dev, uint8_t reg)
872 device_t sio_dev = device_get_parent(dev);
873 struct siosc *sc = device_get_softc(sio_dev);
874 struct superio_devinfo *dinfo = device_get_ivars(dev);
878 v = sio_ldn_read(sc, dinfo->ldn, reg);
884 superio_write(device_t dev, uint8_t reg, uint8_t val)
886 device_t sio_dev = device_get_parent(dev);
887 struct siosc *sc = device_get_softc(sio_dev);
888 struct superio_devinfo *dinfo = device_get_ivars(dev);
891 sio_ldn_write(sc, dinfo->ldn, reg, val);
896 superio_dev_enabled(device_t dev, uint8_t mask)
898 device_t sio_dev = device_get_parent(dev);
899 struct siosc *sc = device_get_softc(sio_dev);
900 struct superio_devinfo *dinfo = device_get_ivars(dev);
903 /* GPIO device is always active in ITE chips. */
904 if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7)
907 v = superio_read(dev, sc->enable_reg);
908 return ((v & mask) != 0);
912 superio_dev_enable(device_t dev, uint8_t mask)
914 device_t sio_dev = device_get_parent(dev);
915 struct siosc *sc = device_get_softc(sio_dev);
916 struct superio_devinfo *dinfo = device_get_ivars(dev);
919 /* GPIO device is always active in ITE chips. */
920 if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7)
924 v = sio_ldn_read(sc, dinfo->ldn, sc->enable_reg);
926 sio_ldn_write(sc, dinfo->ldn, sc->enable_reg, v);
931 superio_dev_disable(device_t dev, uint8_t mask)
933 device_t sio_dev = device_get_parent(dev);
934 struct siosc *sc = device_get_softc(sio_dev);
935 struct superio_devinfo *dinfo = device_get_ivars(dev);
938 /* GPIO device is always active in ITE chips. */
939 if (sc->vendor == SUPERIO_VENDOR_ITE && dinfo->ldn == 7)
943 v = sio_ldn_read(sc, dinfo->ldn, sc->enable_reg);
945 sio_ldn_write(sc, dinfo->ldn, sc->enable_reg, v);
950 superio_find_dev(device_t superio, superio_dev_type_t type, int ldn)
952 struct siosc *sc = device_get_softc(superio);
953 struct superio_devinfo *dinfo;
955 if (ldn < -1 || ldn > UINT8_MAX)
956 return (NULL); /* ERANGE */
957 if (type == SUPERIO_DEV_NONE && ldn == -1)
958 return (NULL); /* EINVAL */
960 STAILQ_FOREACH(dinfo, &sc->devlist, link) {
961 if (ldn != -1 && dinfo->ldn != ldn)
963 if (type != SUPERIO_DEV_NONE && dinfo->type != type)
971 superio_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int flags,
975 struct superiocmd *s;
978 s = (struct superiocmd *)data;
980 case SUPERIO_CR_READ:
982 s->val = sio_ldn_read(sc, s->ldn, s->cr);
985 case SUPERIO_CR_WRITE:
987 sio_ldn_write(sc, s->ldn, s->cr, s->val);
995 static devclass_t superio_devclass;
997 static device_method_t superio_methods[] = {
998 DEVMETHOD(device_identify, superio_identify),
999 DEVMETHOD(device_probe, superio_probe),
1000 DEVMETHOD(device_attach, superio_attach),
1001 DEVMETHOD(device_detach, superio_detach),
1002 DEVMETHOD(device_shutdown, bus_generic_shutdown),
1003 DEVMETHOD(device_suspend, bus_generic_suspend),
1004 DEVMETHOD(device_resume, bus_generic_resume),
1006 DEVMETHOD(bus_add_child, superio_add_child),
1007 DEVMETHOD(bus_child_detached, superio_child_detached),
1008 DEVMETHOD(bus_child_location, superio_child_location),
1009 DEVMETHOD(bus_child_pnpinfo, superio_child_pnp),
1010 DEVMETHOD(bus_print_child, superio_print_child),
1011 DEVMETHOD(bus_read_ivar, superio_read_ivar),
1012 DEVMETHOD(bus_write_ivar, superio_write_ivar),
1013 DEVMETHOD(bus_get_resource_list, superio_get_resource_list),
1014 DEVMETHOD(bus_alloc_resource, bus_generic_rl_alloc_resource),
1015 DEVMETHOD(bus_release_resource, bus_generic_rl_release_resource),
1016 DEVMETHOD(bus_set_resource, bus_generic_rl_set_resource),
1017 DEVMETHOD(bus_get_resource, bus_generic_rl_get_resource),
1018 DEVMETHOD(bus_delete_resource, bus_generic_rl_delete_resource),
1019 DEVMETHOD(bus_activate_resource, bus_generic_activate_resource),
1020 DEVMETHOD(bus_deactivate_resource, bus_generic_deactivate_resource),
1021 DEVMETHOD(bus_setup_intr, bus_generic_setup_intr),
1022 DEVMETHOD(bus_teardown_intr, bus_generic_teardown_intr),
1027 static driver_t superio_driver = {
1030 sizeof(struct siosc)
1033 DRIVER_MODULE(superio, isa, superio_driver, superio_devclass, 0, 0);
1034 MODULE_VERSION(superio, 1);