power: Power device and ioctl for state transitions
Create new /dev/power node with super simple ioctl for initiating sleep state transitions. This is meant as a generic interface to replace the ACPI- and APM-specific interfaces. This allows for non-ACPI states to be entered, such as suspend-to-idle when setting kern.power.suspend=suspend_to_idle. Reviewed by: markj, olce Approved by: markj, olce Sponsored by: The FreeBSD Foundation Differential Revision: https://reviews.freebsd.org/D55508
This commit is contained in:
@@ -1453,7 +1453,7 @@ acpi_ibm_eventhandler(struct acpi_ibm_softc *sc, int arg)
|
||||
* instead of suspend-to-RAM.
|
||||
*/
|
||||
case IBM_EVENT_SUSPEND_TO_RAM:
|
||||
power_pm_suspend(POWER_TRANSITION_SUSPEND);
|
||||
(void)power_pm_suspend(POWER_TRANSITION_SUSPEND);
|
||||
break;
|
||||
|
||||
case IBM_EVENT_BLUETOOTH:
|
||||
|
||||
@@ -3987,10 +3987,10 @@ scgetc(sc_softc_t *sc, u_int flags, struct sc_cnstate *sp)
|
||||
break;
|
||||
|
||||
case SUSP:
|
||||
power_pm_suspend(POWER_TRANSITION_SUSPEND);
|
||||
(void)power_pm_suspend(POWER_TRANSITION_SUSPEND);
|
||||
break;
|
||||
case STBY:
|
||||
power_pm_suspend(POWER_TRANSITION_STANDBY);
|
||||
(void)power_pm_suspend(POWER_TRANSITION_STANDBY);
|
||||
break;
|
||||
|
||||
case DBG:
|
||||
|
||||
@@ -804,11 +804,11 @@ vt_machine_kbdevent(struct vt_device *vd, int c)
|
||||
return (1);
|
||||
case SPCLKEY | STBY: /* XXX Not present in kbdcontrol parser. */
|
||||
/* Put machine into Stand-By mode. */
|
||||
power_pm_suspend(POWER_TRANSITION_STANDBY);
|
||||
(void)power_pm_suspend(POWER_TRANSITION_STANDBY);
|
||||
return (1);
|
||||
case SPCLKEY | SUSP: /* kbdmap(5) keyword `susp`. */
|
||||
/* Suspend machine. */
|
||||
power_pm_suspend(POWER_TRANSITION_SUSPEND);
|
||||
(void)power_pm_suspend(POWER_TRANSITION_SUSPEND);
|
||||
return (1);
|
||||
}
|
||||
|
||||
|
||||
+56
-3
@@ -31,7 +31,10 @@
|
||||
*/
|
||||
|
||||
#include <sys/param.h>
|
||||
#include <sys/conf.h>
|
||||
#include <sys/eventhandler.h>
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/kernel.h>
|
||||
#include <sys/power.h>
|
||||
#include <sys/proc.h>
|
||||
#include <sys/sbuf.h>
|
||||
@@ -49,6 +52,54 @@ static void *power_pm_arg = NULL;
|
||||
static bool power_pm_supported[POWER_STYPE_COUNT] = {0};
|
||||
static struct task power_pm_task;
|
||||
|
||||
static d_ioctl_t power_ioctl;
|
||||
|
||||
static struct cdevsw power_cdevsw = {
|
||||
.d_version = D_VERSION,
|
||||
.d_ioctl = power_ioctl,
|
||||
.d_name = "power",
|
||||
};
|
||||
|
||||
static void
|
||||
power_init(void *unused)
|
||||
{
|
||||
struct make_dev_args args;
|
||||
struct cdev *dev;
|
||||
|
||||
make_dev_args_init(&args);
|
||||
args.mda_devsw = &power_cdevsw;
|
||||
args.mda_uid = UID_ROOT;
|
||||
args.mda_gid = GID_OPERATOR;
|
||||
args.mda_mode = 0660;
|
||||
if (make_dev_s(&args, &dev, "power") != 0)
|
||||
printf("Failed to create power device");
|
||||
}
|
||||
SYSINIT(powerdev, SI_SUB_PSEUDO, SI_ORDER_ANY, power_init, NULL);
|
||||
|
||||
static int
|
||||
power_ioctl(struct cdev *dev, u_long cmd, caddr_t data, int fflag,
|
||||
struct thread *td)
|
||||
{
|
||||
int err = 0;
|
||||
uint32_t trans;
|
||||
|
||||
if ((fflag & FWRITE) == 0)
|
||||
return (EPERM);
|
||||
|
||||
switch (cmd) {
|
||||
case PIOTRANSITION:
|
||||
trans = *(uint32_t *)data;
|
||||
/* Check for overflow */
|
||||
if ((enum power_transition)trans != trans)
|
||||
return (EINVAL);
|
||||
err = power_pm_suspend((enum power_transition)trans);
|
||||
break;
|
||||
default:
|
||||
err = EINVAL;
|
||||
}
|
||||
return (err);
|
||||
}
|
||||
|
||||
enum power_stype
|
||||
power_name_to_stype(const char *name)
|
||||
{
|
||||
@@ -175,13 +226,13 @@ power_pm_get_type(void)
|
||||
return (power_pm_type);
|
||||
}
|
||||
|
||||
void
|
||||
int
|
||||
power_pm_suspend(enum power_transition trans)
|
||||
{
|
||||
enum power_stype stype;
|
||||
|
||||
if (power_pm_fn == NULL)
|
||||
return;
|
||||
return (ENXIO);
|
||||
|
||||
switch (trans) {
|
||||
case POWER_TRANSITION_STANDBY:
|
||||
@@ -196,11 +247,13 @@ power_pm_suspend(enum power_transition trans)
|
||||
default:
|
||||
printf("%s: unknown sleep state transition %d\n", __func__,
|
||||
trans);
|
||||
return;
|
||||
return (EINVAL);
|
||||
}
|
||||
|
||||
power_pm_task.ta_context = (void *)(intptr_t)stype;
|
||||
taskqueue_enqueue(taskqueue_thread, &power_pm_task);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
+20
-11
@@ -3,7 +3,7 @@
|
||||
*
|
||||
* Copyright (c) 2001 Mitsuru IWASAKI
|
||||
* All rights reserved.
|
||||
* Copyright (c) 2025 The FreeBSD Foundation
|
||||
* Copyright (c) 2025-2026 The FreeBSD Foundation
|
||||
*
|
||||
* Portions of this software were developed by Aymeric Wibo
|
||||
* <obiwac@freebsd.org> under sponsorship from the FreeBSD Foundation.
|
||||
@@ -32,17 +32,9 @@
|
||||
|
||||
#ifndef _SYS_POWER_H_
|
||||
#define _SYS_POWER_H_
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/_eventhandler.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* Power management system type */
|
||||
#define POWER_PM_TYPE_ACPI 0x01
|
||||
#define POWER_PM_TYPE_NONE 0xff
|
||||
|
||||
/* Commands for Power management function */
|
||||
#define POWER_CMD_SUSPEND 0x00
|
||||
#include <sys/ioccom.h>
|
||||
|
||||
/*
|
||||
* Sleep state transition requests.
|
||||
@@ -55,8 +47,25 @@ enum power_transition {
|
||||
POWER_TRANSITION_STANDBY,
|
||||
POWER_TRANSITION_SUSPEND,
|
||||
POWER_TRANSITION_HIBERNATE,
|
||||
POWER_TRANSITION_COUNT,
|
||||
};
|
||||
|
||||
/*
|
||||
* Power ioctls.
|
||||
*/
|
||||
#define PIOTRANSITION _IOW('T', 1, uint32_t)
|
||||
|
||||
#ifdef _KERNEL
|
||||
|
||||
#include <sys/_eventhandler.h>
|
||||
|
||||
/* Power management system type */
|
||||
#define POWER_PM_TYPE_ACPI 0x01
|
||||
#define POWER_PM_TYPE_NONE 0xff
|
||||
|
||||
/* Commands for Power management function */
|
||||
#define POWER_CMD_SUSPEND 0x00
|
||||
|
||||
/*
|
||||
* Sleep type.
|
||||
*
|
||||
@@ -97,7 +106,7 @@ extern int power_pm_register(u_int _pm_type, power_pm_fn_t _pm_fn,
|
||||
void *_pm_arg,
|
||||
bool _pm_supported[static POWER_STYPE_COUNT]);
|
||||
extern u_int power_pm_get_type(void);
|
||||
extern void power_pm_suspend(enum power_transition _trans);
|
||||
extern int power_pm_suspend(enum power_transition _trans);
|
||||
|
||||
/*
|
||||
* System power API.
|
||||
|
||||
Reference in New Issue
Block a user