nixos/spec/reimaden/ac71/main.c

131 lines
2.6 KiB
C

// SPDX-License-Identifier: GPL-2.0
#include "pr.h"
#include <linux/dmi.h>
#include <linux/init.h>
#include <linux/kconfig.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/types.h>
#include <linux/wmi.h>
#include "ec.h"
#include "wmi.h"
/* submodules */
#include "pdev.h"
#include "events.h"
#include "hwmon.h"
#include "battery.h"
/* ========================================================================== */
#define SUBMODULE_ENTRY(_name, _req) { .name = #_name, .init = ac71_ ## _name ## _setup, .cleanup = ac71_ ## _name ## _cleanup, .required = _req }
static struct ac71_submodule {
const char *name;
bool required : 1,
initialized : 1;
int (*init)(void);
void (*cleanup)(void);
} ac71_submodules[] __refdata = {
SUBMODULE_ENTRY(pdev, true), /* must be first */
SUBMODULE_ENTRY(wmi_events, false),
SUBMODULE_ENTRY(hwmon, false),
SUBMODULE_ENTRY(battery, false),
};
#undef SUBMODULE_ENTRY
static void do_cleanup(void)
{
int i;
for (i = ARRAY_SIZE(ac71_submodules) - 1; i >= 0; i--) {
const struct ac71_submodule *sm = &ac71_submodules[i];
if (sm->initialized)
sm->cleanup();
}
}
static const struct dmi_system_id ac71_dmi_table[] __initconst = {
{
.matches = {
DMI_MATCH(DMI_BOARD_NAME, "LAPAC71H"),
{ }
}
}
};
static int __init ac71_module_init(void)
{
int err = 0, i;
if (!wmi_has_guid(AC71_WMI_WMBC_GUID)) {
pr_err("WMI GUID not found\n");
err = -ENODEV; goto out;
}
if (!dmi_check_system(ac71_dmi_table)) {
pr_err("no DMI match\n");
err = -ENODEV; goto out;
}
err = ec_read_byte(PROJ_ID_ADDR);
if (err < 0) {
pr_err("failed to query project id: %d\n", err);
goto out;
}
pr_info("project id: %d\n", err);
err = ec_read_byte(PLATFORM_ID_ADDR);
if (err < 0) {
pr_err("failed to query platform id: %d\n", err);
goto out;
}
pr_info("platform id: %d\n", err);
for (i = 0; i < ARRAY_SIZE(ac71_submodules); i++) {
struct ac71_submodule *sm = &ac71_submodules[i];
err = sm->init();
if (err) {
pr_warn("failed to initialize %s submodule: %d\n", sm->name, err);
if (sm->required)
goto out;
} else {
sm->initialized = true;
}
}
err = 0;
out:
if (err)
do_cleanup();
else
pr_info("module loaded\n");
return err;
}
static void __exit ac71_module_cleanup(void)
{
do_cleanup();
pr_info("module unloaded\n");
}
/* ========================================================================== */
module_init(ac71_module_init);
module_exit(ac71_module_cleanup);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("AC71 laptop platform driver");
MODULE_ALIAS("wmi:" AC71_WMI_WMBC_GUID);