freebsd-src/sys/dev/ncthwm/ncthwm.c
Warner Losh fdafd315ad sys: Automated cleanup of cdefs and other formatting
Apply the following automated changes to try to eliminate
no-longer-needed sys/cdefs.h includes as well as now-empty
blank lines in a row.

Remove /^#if.*\n#endif.*\n#include\s+<sys/cdefs.h>.*\n/
Remove /\n+#include\s+<sys/cdefs.h>.*\n+#if.*\n#endif.*\n+/
Remove /\n+#if.*\n#endif.*\n+/
Remove /^#if.*\n#endif.*\n/
Remove /\n+#include\s+<sys/cdefs.h>\n#include\s+<sys/types.h>/
Remove /\n+#include\s+<sys/cdefs.h>\n#include\s+<sys/param.h>/
Remove /\n+#include\s+<sys/cdefs.h>\n#include\s+<sys/capsicum.h>/

Sponsored by:		Netflix
2023-11-26 22:24:00 -07:00

259 lines
7.2 KiB
C

/*-
* SPDX-License-Identifier: BSD-2-Clause
*
* Copyright (c) 2016-2022 Stormshield
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
#include <sys/rman.h>
#include <sys/sysctl.h>
#include <sys/watchdog.h>
#include <dev/superio/superio.h>
#include <machine/bus.h>
#include <machine/resource.h>
#define NCTHWM_FAN_MAX 5
#define NCTHWM_BANK_SELECT 0x4e
#define NCTHWM_VENDOR_ID 0x4f
#define NCTHWM_VERBOSE_PRINTF(dev, ...) \
do { \
if (__predict_false(bootverbose)) \
device_printf(dev, __VA_ARGS__); \
} while (0)
struct ncthwm_softc {
device_t dev;
struct ncthwm_device *nctdevp;
struct resource *iores;
int iorid;
};
struct ncthwm_fan_info
{
const char *name;
uint8_t low_byte_offset;
uint8_t high_byte_offset;
};
struct ncthwm_device {
uint16_t devid;
const char *descr;
uint8_t base_offset;
uint8_t fan_bank;
uint8_t fan_count;
struct ncthwm_fan_info fan_info[NCTHWM_FAN_MAX];
} ncthwm_devices[] = {
{
.devid = 0xc562,
.descr = "HWM on Nuvoton NCT6779D",
.base_offset = 5,
.fan_bank = 4,
.fan_count = 5,
.fan_info = {
{ .name = "SYSFAN", .low_byte_offset = 0xc1, .high_byte_offset = 0xc0 },
{ .name = "CPUFAN", .low_byte_offset = 0xc3, .high_byte_offset = 0xc2 },
{ .name = "AUXFAN0", .low_byte_offset = 0xc5, .high_byte_offset = 0xc4 },
{ .name = "AUXFAN1", .low_byte_offset = 0xc7, .high_byte_offset = 0xc6 },
{ .name = "AUXFAN2", .low_byte_offset = 0xc9, .high_byte_offset = 0xc8 },
},
}, {
.devid = 0xd42a,
.descr = "HWM on Nuvoton NCT6796D-E",
.base_offset = 5,
.fan_bank = 4,
.fan_count = 5,
.fan_info = {
{ .name = "SYSFAN", .low_byte_offset = 0xc1, .high_byte_offset = 0xc0 },
{ .name = "CPUFAN", .low_byte_offset = 0xc3, .high_byte_offset = 0xc2 },
{ .name = "AUXFAN0", .low_byte_offset = 0xc5, .high_byte_offset = 0xc4 },
{ .name = "AUXFAN1", .low_byte_offset = 0xc7, .high_byte_offset = 0xc6 },
{ .name = "AUXFAN2", .low_byte_offset = 0xc9, .high_byte_offset = 0xc8 },
},
}
};
static struct ncthwm_device *
ncthwm_lookup_device(device_t dev)
{
int i;
uint16_t devid;
devid = superio_devid(dev);
for (i = 0; i < nitems(ncthwm_devices); i++) {
if (devid == ncthwm_devices[i].devid)
return (ncthwm_devices + i);
}
return (NULL);
}
static void
ncthwm_write(struct ncthwm_softc *sc, uint8_t reg, uint8_t val)
{
bus_write_1(sc->iores, 0, reg);
bus_write_1(sc->iores, 1, val);
}
static uint8_t
ncthwm_read(struct ncthwm_softc *sc, uint8_t reg)
{
bus_write_1(sc->iores, 0, reg);
return (bus_read_1(sc->iores, 1));
}
static int
ncthwm_query_fan_speed(SYSCTL_HANDLER_ARGS)
{
struct ncthwm_softc *sc;
struct ncthwm_fan_info *fan;
uint16_t val;
sc = arg1;
if (sc == NULL)
return (EINVAL);
KASSERT(sc->nctdevp != NULL, ("Unreachable"));
if (sc->nctdevp->fan_count <= arg2)
return (EINVAL);
fan = &sc->nctdevp->fan_info[arg2];
KASSERT(sc->iores != NULL, ("Unreachable"));
ncthwm_write(sc, NCTHWM_BANK_SELECT, sc->nctdevp->fan_bank);
val = ncthwm_read(sc, fan->high_byte_offset) << 8;
val |= ncthwm_read(sc, fan->low_byte_offset);
NCTHWM_VERBOSE_PRINTF(sc->dev, "%s: read %u from bank %u offset 0x%x-0x%x\n",
fan->name, val, sc->nctdevp->fan_bank, fan->high_byte_offset, fan->low_byte_offset);
return (sysctl_handle_16(oidp, &val, 0, req));
}
static int
ncthwm_probe(device_t dev)
{
struct ncthwm_device *nctdevp;
uint8_t ldn;
ldn = superio_get_ldn(dev);
if (superio_vendor(dev) != SUPERIO_VENDOR_NUVOTON) {
NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not a Nuvoton device\n", ldn);
return (ENXIO);
}
if (superio_get_type(dev) != SUPERIO_DEV_HWM) {
NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not a HWM device\n", ldn);
return (ENXIO);
}
nctdevp = ncthwm_lookup_device(dev);
if (nctdevp == NULL) {
NCTHWM_VERBOSE_PRINTF(dev, "ldn 0x%x not supported\n", ldn);
return (ENXIO);
}
device_set_desc(dev, nctdevp->descr);
return (BUS_PROBE_DEFAULT);
}
static int
ncthwm_attach(device_t dev)
{
struct ncthwm_softc *sc;
int i;
uint16_t iobase;
sc = device_get_softc(dev);
sc->dev = dev;
sc->nctdevp = ncthwm_lookup_device(dev);
if (sc->nctdevp == NULL) {
device_printf(dev, "device not supported\n");
return (ENXIO);
}
iobase = superio_get_iobase(dev) + sc->nctdevp->base_offset;
sc->iorid = 0;
if (bus_set_resource(dev, SYS_RES_IOPORT, sc->iorid, iobase, 2) != 0) {
device_printf(dev, "failed to set I/O port resource at 0x%x\n", iobase);
return (ENXIO);
}
sc->iores = bus_alloc_resource_any(dev, SYS_RES_IOPORT,
&sc->iorid, RF_ACTIVE);
if (sc->iores == NULL) {
device_printf(dev, "can't map I/O space at 0x%x\n", iobase);
return (ENXIO);
}
NCTHWM_VERBOSE_PRINTF(dev, "iobase 0x%x iores %p\n", iobase, sc->iores);
/* Register FAN sysctl */
for (i = 0; i < sc->nctdevp->fan_count; i++) {
SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
SYSCTL_CHILDREN(device_get_sysctl_tree(dev)), OID_AUTO,
sc->nctdevp->fan_info[i].name,
CTLTYPE_U16 | CTLFLAG_RD, sc, i,
ncthwm_query_fan_speed, "SU", "Fan speed in RPM");
}
return (0);
}
static int
ncthwm_detach(device_t dev)
{
struct ncthwm_softc *sc = device_get_softc(dev);
if (sc->iores)
bus_release_resource(dev, SYS_RES_IOPORT, sc->iorid, sc->iores);
return (0);
}
static device_method_t ncthwm_methods[] = {
/* Methods from the device interface */
DEVMETHOD(device_probe, ncthwm_probe),
DEVMETHOD(device_attach, ncthwm_attach),
DEVMETHOD(device_detach, ncthwm_detach),
/* Terminate method list */
{ 0, 0 }
};
static driver_t ncthwm_driver = {
"ncthwm",
ncthwm_methods,
sizeof (struct ncthwm_softc)
};
DRIVER_MODULE(ncthwm, superio, ncthwm_driver, NULL, NULL);
MODULE_DEPEND(ncthwm, superio, 1, 1, 1);
MODULE_VERSION(ncthwm, 1);