diff options
author | phitran <none@none> | 2008-05-07 15:12:21 -0700 |
---|---|---|
committer | phitran <none@none> | 2008-05-07 15:12:21 -0700 |
commit | d2ec54f7875f7e05edd56195adbeb593c947763f (patch) | |
tree | 060ccb18e19011bfee2ea7c48b1bd98e442caeea | |
parent | 5b764efa67662f6a18a3eea7053aab98a9fbfebf (diff) | |
download | illumos-joyent-d2ec54f7875f7e05edd56195adbeb593c947763f.tar.gz |
PSARC/2008/021 HAL Power Management Support
6682365 Add power management support for lid, LCD brightness, and power button
--HG--
rename : usr/src/cmd/hal/probing/battery/Makefile => usr/src/cmd/hal/probing/acpi/Makefile
rename : usr/src/cmd/hal/probing/battery/probe-battery.c => usr/src/cmd/hal/probing/acpi/probe-acpi.c
rename : usr/src/cmd/hal/utils/battery.c => usr/src/cmd/hal/utils/acpi.c
rename : usr/src/cmd/hal/utils/battery.h => usr/src/cmd/hal/utils/acpi.h
rename : usr/src/uts/common/sys/battery.h => usr/src/uts/common/sys/acpi_drv.h
rename : usr/src/uts/common/sys/sysevent/acpiev.h => usr/src/uts/common/sys/sysevent/pwrctl.h
rename : usr/src/uts/i86pc/battery/Makefile => usr/src/uts/i86pc/acpi_drv/Makefile
rename : usr/src/uts/i86pc/io/battery/battery.c => usr/src/uts/i86pc/io/acpi_drv/acpi_drv.c
rename : usr/src/uts/i86pc/io/battery/battery.conf => usr/src/uts/i86pc/io/acpi_drv/acpi_drv.conf
69 files changed, 4221 insertions, 2213 deletions
diff --git a/usr/src/cmd/hal/addons/acpi/Makefile b/usr/src/cmd/hal/addons/acpi/Makefile index 5ee5df687d..daf306a758 100644 --- a/usr/src/cmd/hal/addons/acpi/Makefile +++ b/usr/src/cmd/hal/addons/acpi/Makefile @@ -19,14 +19,14 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # PROG = hald-addon-acpi -OBJS = addon-acpi.o logger.o util_helper.o battery.o util_pm.o +OBJS = addon-acpi.o logger.o util_helper.o acpi.o util_pm.o SRCS = addon-acpi.c ../../hald/logger.c ../../hald/util_helper.c include ../../../Makefile.cmd @@ -44,8 +44,8 @@ C99MODE = $(C99_ENABLE) all: $(PROG) -battery.o: ../../utils/battery.c - $(COMPILE.c) -o $@ ../../utils/battery.c +acpi.o: ../../utils/acpi.c + $(COMPILE.c) -o $@ ../../utils/acpi.c $(POST_PROCESS_O) logger.o: ../../hald/logger.c diff --git a/usr/src/cmd/hal/addons/acpi/addon-acpi.c b/usr/src/cmd/hal/addons/acpi/addon-acpi.c index 82eca86820..2f87da2bc0 100644 --- a/usr/src/cmd/hal/addons/acpi/addon-acpi.c +++ b/usr/src/cmd/hal/addons/acpi/addon-acpi.c @@ -3,7 +3,7 @@ * addon-acpi.c : Poll battery and AC adapter devices and update * properties * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Licensed under the Academic Free License version 2.1 @@ -27,7 +27,7 @@ #include <libhal.h> #include "../../hald/logger.h" #include "../../hald/util_helper.h" -#include "../../utils/battery.h" +#include "../../utils/acpi.h" int main(int argc, char **argv) diff --git a/usr/src/cmd/hal/fdi/Makefile b/usr/src/cmd/hal/fdi/Makefile index 6724d578bf..786b66510d 100644 --- a/usr/src/cmd/hal/fdi/Makefile +++ b/usr/src/cmd/hal/fdi/Makefile @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -42,7 +42,6 @@ FDIS = information/10freedesktop/10-camera-ptp.fdi \ information/10freedesktop/10-usb-pda.fdi \ information/10freedesktop/10-usb-zip-drives.fdi \ information/10freedesktop/10-wireless-mice.fdi \ - policy/10osvendor/10-keyboard-policy.fdi \ policy/10osvendor/10-laptop-panel-mgmt-policy.fdi \ policy/10osvendor/10-network-attached.fdi \ policy/10osvendor/10-power-mgmt-policy.fdi \ diff --git a/usr/src/cmd/hal/hald/hald_dbus.c b/usr/src/cmd/hal/hald/hald_dbus.c index 780aa88e61..f116c85972 100644 --- a/usr/src/cmd/hal/hald/hald_dbus.c +++ b/usr/src/cmd/hal/hald/hald_dbus.c @@ -3257,7 +3257,7 @@ hald_exec_method_cb (HalDevice *d, guint32 exit_type, gint return_code, gchar **error, gpointer data1, gpointer data2) { - dbus_uint32_t result; + dbus_int32_t result; DBusMessage *reply = NULL; DBusMessage *message; DBusMessageIter iter; @@ -3302,14 +3302,14 @@ hald_exec_method_cb (HalDevice *d, guint32 exit_type, dbus_message_unref (reply); } else { - result = (dbus_uint32_t) return_code; + result = (dbus_int32_t) return_code; reply = dbus_message_new_method_return (message); if (reply == NULL) DIE (("No memory")); dbus_message_iter_init_append (reply, &iter); - dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &result); + dbus_message_iter_append_basic (&iter, DBUS_TYPE_INT32, &result); if (conn != NULL) { if (!dbus_connection_send (conn, reply, NULL)) diff --git a/usr/src/cmd/hal/hald/hald_runner.c b/usr/src/cmd/hal/hald/hald_runner.c index a0f07d1197..cb6fcad7fc 100644 --- a/usr/src/cmd/hal/hald/hald_runner.c +++ b/usr/src/cmd/hal/hald/hald_runner.c @@ -291,7 +291,7 @@ add_basic_env(DBusMessageIter *iter, const gchar *udi) { add_env(iter, "HAVE_POLKIT", "1"); #endif - if (uname(&un) == 0) { + if (uname(&un) >= 0) { char *sysname; sysname = g_ascii_strdown(un.sysname, -1); diff --git a/usr/src/cmd/hal/hald/solaris/devinfo.c b/usr/src/cmd/hal/hald/solaris/devinfo.c index a216d7c603..40af76486e 100644 --- a/usr/src/cmd/hal/hald/solaris/devinfo.c +++ b/usr/src/cmd/hal/hald/solaris/devinfo.c @@ -141,6 +141,8 @@ static DevinfoDevHandler *devinfo_handlers[] = { &devinfo_lofi_handler, &devinfo_acpi_handler, &devinfo_battery_handler, + &devinfo_power_button_handler, + &devinfo_keyboard_handler, &devinfo_default_handler, NULL }; diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_acpi.c b/usr/src/cmd/hal/hald/solaris/devinfo_acpi.c index f23fa0b1c9..f93b156e9b 100644 --- a/usr/src/cmd/hal/hald/solaris/devinfo_acpi.c +++ b/usr/src/cmd/hal/hald/solaris/devinfo_acpi.c @@ -2,7 +2,7 @@ * * devinfo_acpi : acpi devices * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Licensed under the Academic Free License version 2.1 @@ -22,6 +22,8 @@ #include <sys/mkdev.h> #include <sys/stat.h> #include <unistd.h> +#include <sys/sysevent/dev.h> +#include <sys/sysevent/pwrctl.h> #include "../osspec.h" #include "../logger.h" @@ -36,6 +38,10 @@ static HalDevice *devinfo_acpi_add(HalDevice *, di_node_t, char *, char *); static HalDevice *devinfo_battery_add(HalDevice *, di_node_t, char *, char *); +static HalDevice *devinfo_power_button_add(HalDevice *parent, di_node_t node, + char *devfs_path, char *device_type); +static void devinfo_battery_rescan_probing_done(HalDevice *d, guint32 exit_type, + gint return_code, char **error, gpointer userdata1, gpointer userdata2); DevinfoDevHandler devinfo_acpi_handler = { devinfo_acpi_add, @@ -55,6 +61,15 @@ DevinfoDevHandler devinfo_battery_handler = { devinfo_battery_get_prober }; +DevinfoDevHandler devinfo_power_button_handler = { + devinfo_power_button_add, + NULL, + NULL, + NULL, + NULL, + NULL +}; + static HalDevice * devinfo_acpi_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) @@ -94,7 +109,7 @@ devinfo_battery_add(HalDevice *parent, di_node_t node, char *devfs_path, char *devpath; driver_name = di_driver_name(node); - if ((driver_name == NULL) || (strcmp(driver_name, "battery") != 0)) { + if ((driver_name == NULL) || (strcmp(driver_name, "acpi_drv") != 0)) { return (NULL); } @@ -147,6 +162,64 @@ devinfo_battery_add_minor(HalDevice *parent, di_node_t node, char *minor_path, devinfo_add_enqueue(d, minor_path, &devinfo_battery_handler); } +static HalDevice * +devinfo_power_button_add(HalDevice *parent, di_node_t node, char *devfs_path, + char *device_type) +{ + HalDevice *d; + char *driver_name; + + driver_name = di_driver_name(node); + if ((driver_name == NULL) || (strcmp(driver_name, "power") != 0)) { + return (NULL); + } + + d = hal_device_new(); + + devinfo_set_default_properties(d, parent, node, devfs_path); + hal_device_add_capability(d, "button"); + hal_device_property_set_bool(d, "button.has_state", FALSE); + hal_device_property_set_string(d, "info.category", "input"); + hal_device_property_set_string(d, "button.type", "power"); + hal_device_property_set_string(d, "info.product", "Power Button"); + + devinfo_add_enqueue(d, devfs_path, &devinfo_power_button_handler); + + return (d); +} + +void +devinfo_power_button_rescan(void) +{ + HalDevice *d = NULL; + HalDeviceStore *store = hald_get_gdl(); + + d = hal_device_store_match_key_value_string (store, "button.type", + "power"); + if (d != NULL) { + device_send_signal_condition(d, "ButtonPressed", "power"); + } +} + +void +devinfo_brightness_hotkeys_rescan(char *subclass) +{ + HalDevice *d = NULL; + + if ((d = hal_device_store_find(hald_get_gdl(), + "/org/freedesktop/Hal/devices/computer")) || + (d = hal_device_store_find(hald_get_tdl(), + "/org/freedesktop/Hal/devices/computer"))) { + if (strcmp(subclass, ESC_PWRCTL_BRIGHTNESS_UP) == 0) { + device_send_signal_condition(d, "ButtonPressed", + "brightness-up"); + } else { + device_send_signal_condition(d, "ButtonPressed", + "brightness-down"); + } + } +} + void devinfo_battery_device_rescan(char *parent_devfs_path, gchar *udi) { @@ -158,11 +231,27 @@ devinfo_battery_device_rescan(char *parent_devfs_path, gchar *udi) return; } - hald_runner_run(d, "hald-probe-battery", NULL, + hald_runner_run(d, "hald-probe-acpi", NULL, DEVINFO_PROBE_BATTERY_TIMEOUT, devinfo_battery_rescan_probing_done, NULL, NULL); } +void +devinfo_lid_device_rescan(char *subclass, gchar *udi) +{ + HalDevice *d = NULL; + + d = hal_device_store_find(hald_get_gdl(), udi); + if (d == NULL) { + HAL_INFO(("device not found %s", udi)); + return; + } + + hal_device_property_set_bool(d, "button.state.value", + (strcmp(subclass, ESC_PWRCTL_REMOVE) == 0)); + device_send_signal_condition(d, "ButtonPressed", "lid"); +} + static void devinfo_battery_rescan_probing_done(HalDevice *d, guint32 exit_type, gint return_code, char **error, gpointer userdata1, gpointer userdata2) @@ -174,5 +263,5 @@ const gchar * devinfo_battery_get_prober(HalDevice *d, int *timeout) { *timeout = DEVINFO_PROBE_BATTERY_TIMEOUT; /* 30 second timeout */ - return ("hald-probe-battery"); + return ("hald-probe-acpi"); } diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_acpi.h b/usr/src/cmd/hal/hald/solaris/devinfo_acpi.h index 12858d7e1e..08dd681905 100644 --- a/usr/src/cmd/hal/hald/solaris/devinfo_acpi.h +++ b/usr/src/cmd/hal/hald/solaris/devinfo_acpi.h @@ -2,7 +2,7 @@ * * devinfo_acpi.h : definitions for acpi devices * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Licensed under the Academic Free License version 2.1 @@ -18,6 +18,7 @@ extern DevinfoDevHandler devinfo_acpi_handler; extern DevinfoDevHandler devinfo_battery_handler; +extern DevinfoDevHandler devinfo_power_button_handler; #define MINOR_SHIFT 8 #define MINOR2TYPE(minor) ((minor) >> MINOR_SHIFT) @@ -36,8 +37,10 @@ void devinfo_battery_add_minor(HalDevice *parent, di_node_t node, char *minor_path, dev_t dev); void devinfo_battery_remove_minor(char *parent_devfs_path, gchar *udi); void devinfo_battery_device_rescan(char *parent_devfs_path, gchar *udi); -static void devinfo_battery_rescan_probing_done(HalDevice *d, guint32 exit_type, - gint return_code, char **error, gpointer userdata1, gpointer userdata2); const gchar *devinfo_battery_get_prober(HalDevice *d, int *timeout); +void devinfo_power_button_rescan(void); +void devinfo_brightness_hotkeys_rescan(char *subclass); + +void devinfo_lid_device_rescan(char *subclass, gchar *udi); #endif /* DEVINFO_ACPI_H */ diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_misc.c b/usr/src/cmd/hal/hald/solaris/devinfo_misc.c index e69f3d29b1..408fd12f83 100644 --- a/usr/src/cmd/hal/hald/solaris/devinfo_misc.c +++ b/usr/src/cmd/hal/hald/solaris/devinfo_misc.c @@ -19,6 +19,7 @@ #include <string.h> #include <sys/utsname.h> #include <libdevinfo.h> +#include <sys/uadmin.h> #include "../osspec.h" #include "../logger.h" @@ -29,32 +30,41 @@ #include "devinfo_misc.h" static HalDevice *devinfo_computer_add(HalDevice *, di_node_t, char *, char *); -static HalDevice *devinfo_cpu_add(HalDevice *, di_node_t, char *,char *); +static HalDevice *devinfo_cpu_add(HalDevice *, di_node_t, char *, char *); +static HalDevice *devinfo_keyboard_add(HalDevice *, di_node_t, char *, char *); static HalDevice *devinfo_default_add(HalDevice *, di_node_t, char *, char *); DevinfoDevHandler devinfo_computer_handler = { - devinfo_computer_add, + devinfo_computer_add, NULL, NULL, NULL, NULL, - NULL + NULL }; DevinfoDevHandler devinfo_cpu_handler = { - devinfo_cpu_add, + devinfo_cpu_add, NULL, NULL, NULL, NULL, - NULL + NULL +}; +DevinfoDevHandler devinfo_keyboard_handler = { + devinfo_keyboard_add, + NULL, + NULL, + NULL, + NULL, + NULL }; DevinfoDevHandler devinfo_default_handler = { - devinfo_default_add, + devinfo_default_add, NULL, NULL, NULL, NULL, - NULL + NULL }; static HalDevice * @@ -69,10 +79,10 @@ devinfo_computer_add(HalDevice *parent, di_node_t node, char *devfs_path, char * d = hal_device_new (); - hal_device_property_set_string (d, "info.subsystem", "unknown"); - hal_device_property_set_string (d, "info.product", "Computer"); - hal_device_property_set_string (d, "info.udi", "/org/freedesktop/Hal/devices/computer"); - hal_device_set_udi (d, "/org/freedesktop/Hal/devices/computer"); + hal_device_property_set_string (d, "info.subsystem", "unknown"); + hal_device_property_set_string (d, "info.product", "Computer"); + hal_device_property_set_string (d, "info.udi", "/org/freedesktop/Hal/devices/computer"); + hal_device_set_udi (d, "/org/freedesktop/Hal/devices/computer"); hal_device_property_set_string (d, "solaris.devfs_path", devfs_path); if (uname (&un) >= 0) { @@ -81,11 +91,18 @@ devinfo_computer_add(HalDevice *parent, di_node_t node, char *devfs_path, char * hal_device_property_set_string (d, "system.kernel.machine", un.machine); } + hal_device_property_set_bool(d, "power_management.can_hibernate", + (uadmin(A_FREEZE, AD_CHECK_SUSPEND_TO_DISK, 0) == 0)); + hal_device_property_set_bool(d, "power_management.can_suspend", + (uadmin(A_FREEZE, AD_CHECK_SUSPEND_TO_RAM, 0) == 0)); + + hal_device_add_capability(d, "button"); + /* * Let computer be in TDL while synthesizing all other events * because some may write to the object */ - hal_device_store_add (hald_get_tdl (), d); + hal_device_store_add (hald_get_tdl (), d); devinfo_add_enqueue (d, devfs_path, &devinfo_computer_handler); @@ -93,10 +110,10 @@ devinfo_computer_add(HalDevice *parent, di_node_t node, char *devfs_path, char * local_d = hal_device_new (); hal_device_property_set_string (local_d, "info.parent", hal_device_get_udi (d)); - hal_device_property_set_string (local_d, "info.subsystem", "unknown"); - hal_device_property_set_string (local_d, "info.product", "Local devices"); - hal_device_property_set_string (local_d, "info.udi", "/org/freedesktop/Hal/devices/local"); - hal_device_set_udi (local_d, "/org/freedesktop/Hal/devices/local"); + hal_device_property_set_string (local_d, "info.subsystem", "unknown"); + hal_device_property_set_string (local_d, "info.product", "Local devices"); + hal_device_property_set_string (local_d, "info.udi", "/org/freedesktop/Hal/devices/local"); + hal_device_set_udi (local_d, "/org/freedesktop/Hal/devices/local"); hal_device_property_set_string (local_d, "solaris.devfs_path", "/local"); devinfo_add_enqueue (local_d, "/local", &devinfo_default_handler); @@ -124,6 +141,27 @@ devinfo_cpu_add(HalDevice *parent, di_node_t node, char *devfs_path, char *devic } static HalDevice * +devinfo_keyboard_add(HalDevice *parent, di_node_t node, char *devfs_path, + char *device_type) +{ + HalDevice *d; + + if (strcmp(di_node_name(node), "keyboard") != 0) { + return (NULL); + } + + d = hal_device_new (); + + devinfo_set_default_properties (d, parent, node, devfs_path); + hal_device_add_capability (d, "input.keyboard"); + hal_device_add_capability(d, "button"); + + devinfo_add_enqueue (d, devfs_path, &devinfo_keyboard_handler); + + return (d); +} + +static HalDevice * devinfo_default_add(HalDevice *parent, di_node_t node, char *devfs_path, char *device_type) { char *driver_name; diff --git a/usr/src/cmd/hal/hald/solaris/devinfo_misc.h b/usr/src/cmd/hal/hald/solaris/devinfo_misc.h index 1023166a39..609f53e93d 100644 --- a/usr/src/cmd/hal/hald/solaris/devinfo_misc.h +++ b/usr/src/cmd/hal/hald/solaris/devinfo_misc.h @@ -2,7 +2,7 @@ * * devinfo_misc.h : definitions for misc devices * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Licensed under the Academic Free License version 2.1 @@ -18,6 +18,7 @@ extern DevinfoDevHandler devinfo_cpu_handler; extern DevinfoDevHandler devinfo_computer_handler; +extern DevinfoDevHandler devinfo_keyboard_handler; extern DevinfoDevHandler devinfo_default_handler; #endif /* DEVINFO_MISC_H */ diff --git a/usr/src/cmd/hal/hald/solaris/sysevent.c b/usr/src/cmd/hal/hald/solaris/sysevent.c index 7e482b233c..7fabccfaf4 100644 --- a/usr/src/cmd/hal/hald/solaris/sysevent.c +++ b/usr/src/cmd/hal/hald/solaris/sysevent.c @@ -26,7 +26,7 @@ #include <libdevinfo.h> #include <libsysevent.h> #include <sys/sysevent/dev.h> -#include <sys/sysevent/acpiev.h> +#include <sys/sysevent/pwrctl.h> #include <glib.h> #include "../osspec.h" @@ -55,6 +55,8 @@ static void sysevent_dev_branch(gchar *); static void sysevent_lofi_add(gchar *, gchar *); static void sysevent_lofi_remove(gchar *, gchar *); static void sysevent_devfs_add(gchar *); +static void sysevent_pwrctl(gchar *, gchar *, gchar *, gchar *, gchar *, + gchar *, uint_t); static sysevent_handle_t *shp; @@ -66,7 +68,7 @@ gboolean sysevent_init(void) { GError *err = NULL; - const char *subcl[3]; + const char *subcl[6]; /* * pipe used to serialize sysevents through the main loop @@ -111,10 +113,13 @@ sysevent_init(void) return (FALSE); } - subcl[0] = ESC_ACPIEV_ADD; - subcl[1] = ESC_ACPIEV_REMOVE; - subcl[2] = ESC_ACPIEV_STATE_CHANGE; - if (sysevent_subscribe_event(shp, EC_ACPIEV, subcl, 3) != 0) { + subcl[0] = ESC_PWRCTL_ADD; + subcl[1] = ESC_PWRCTL_REMOVE; + subcl[2] = ESC_PWRCTL_STATE_CHANGE; + subcl[3] = ESC_PWRCTL_BRIGHTNESS_UP; + subcl[4] = ESC_PWRCTL_BRIGHTNESS_DOWN; + subcl[5] = ESC_PWRCTL_POWER_BUTTON; + if (sysevent_subscribe_event(shp, EC_PWRCTL, subcl, 6) != 0) { HAL_INFO(("subscribe(dev_add) failed %d", errno)); sysevent_unbind_handle(shp); return (FALSE); @@ -173,8 +178,8 @@ sysevent_dev_handler(sysevent_t *ev) goto out; } - if (strcmp(class, EC_ACPIEV) == 0) { - if (nvlist_lookup_string(attr_list, ACPIEV_DEV_PHYS_PATH, + if (strcmp(class, EC_PWRCTL) == 0) { + if (nvlist_lookup_string(attr_list, PWRCTL_DEV_PHYS_PATH, &phys_path) != 0) { goto out; } @@ -184,20 +189,20 @@ sysevent_dev_handler(sysevent_t *ev) } if (nvlist_lookup_string(attr_list, DEV_NAME, &dev_name) != 0) { - if (strcmp(class, EC_ACPIEV) == 0) { + if (strcmp(class, EC_PWRCTL) == 0) { dev_name = "noname"; } else { dev_name = ""; } } - if (nvlist_lookup_string(attr_list, ACPIEV_DEV_HID, &dev_hid) != 0) { + if (nvlist_lookup_string(attr_list, PWRCTL_DEV_HID, &dev_hid) != 0) { dev_hid = ""; } - if (nvlist_lookup_string(attr_list, ACPIEV_DEV_UID, &dev_uid) != 0) { + if (nvlist_lookup_string(attr_list, PWRCTL_DEV_UID, &dev_uid) != 0) { dev_uid = ""; } - if (nvlist_lookup_uint32(attr_list, ACPIEV_DEV_INDEX, &dev_index) + if (nvlist_lookup_uint32(attr_list, PWRCTL_DEV_INDEX, &dev_index) != 0) { dev_index = 0; } @@ -227,7 +232,6 @@ sysevent_iochannel_data (GIOChannel *source, gchar dev_name[1024]; gchar dev_uid[1024]; gchar dev_hid[1024]; - gchar udi[1024]; uint_t dev_index; HAL_INFO (("sysevent_iochannel_data")); @@ -265,20 +269,9 @@ sysevent_iochannel_data (GIOChannel *source, } } else if (strcmp(class, EC_DEV_BRANCH) == 0) { sysevent_dev_branch(phys_path); - } else if (strcmp(class, EC_ACPIEV) == 0) { - if (strcmp(dev_hid, "PNP0C0A") == 0) { - snprintf(udi, sizeof(udi), - "/org/freedesktop/Hal/devices/pseudo/" - "battery_0_battery%d_0", dev_index); - } else if (strcmp(dev_hid, "ACPI0003") == 0) { - snprintf(udi, sizeof(udi), - "/org/freedesktop/Hal/devices/pseudo/" - "battery_0_ac%d_0", dev_index); - } else { - HAL_INFO(("dev_hid %s unknown", dev_hid)); - continue; - } - devinfo_battery_device_rescan(phys_path, udi); + } else if (strcmp(class, EC_PWRCTL) == 0) { + sysevent_pwrctl(class, subclass, phys_path, + dev_name, dev_hid, dev_uid, dev_index); } else if (strcmp(class, EC_DEVFS) == 0) { if (strcmp(subclass, ESC_DEVFS_DEVI_ADD) == 0) { sysevent_devfs_add(phys_path); @@ -448,3 +441,29 @@ sysevent_devfs_add(gchar *devfs_path) out: di_fini (node); } + +static void +sysevent_pwrctl(gchar *class, gchar *subclass, gchar *phys_path, + gchar *dev_name, gchar *dev_hid, gchar *dev_uid, uint_t dev_index) +{ + const gchar prefix[] = "/org/freedesktop/Hal/devices/pseudo/acpi_drv_0"; + gchar udi[HAL_PATH_MAX]; + + if (strcmp(dev_hid, "PNP0C0A") == 0) { + snprintf(udi, sizeof(udi), "%s_battery%d_0", prefix, dev_index); + devinfo_battery_device_rescan(phys_path, udi); + } else if (strcmp(dev_hid, "ACPI0003") == 0) { + snprintf(udi, sizeof (udi), "%s_ac%d_0", prefix, dev_index); + devinfo_battery_device_rescan(phys_path, udi); + } else if (strcmp(dev_hid, "PNP0C0D") == 0) { + snprintf(udi, sizeof (udi), "%s_lid_0", prefix); + devinfo_lid_device_rescan(subclass, udi); + } else if (strcmp(subclass, ESC_PWRCTL_POWER_BUTTON) == 0) { + devinfo_power_button_rescan(); + } else if ((strcmp(subclass, ESC_PWRCTL_BRIGHTNESS_UP) == 0) || + (strcmp(subclass, ESC_PWRCTL_BRIGHTNESS_DOWN) == 0)) { + devinfo_brightness_hotkeys_rescan(subclass); + } else { + HAL_INFO(("Unmatched EC_PWRCTL")); + } +} diff --git a/usr/src/cmd/hal/probing/Makefile b/usr/src/cmd/hal/probing/Makefile index 00244dcbe4..20e1d4c3ac 100644 --- a/usr/src/cmd/hal/probing/Makefile +++ b/usr/src/cmd/hal/probing/Makefile @@ -19,13 +19,13 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # -SUBDIRS = storage volume printer network-printer battery +SUBDIRS = storage volume printer network-printer acpi all := TARGET= all install := TARGET= install diff --git a/usr/src/cmd/hal/probing/battery/Makefile b/usr/src/cmd/hal/probing/acpi/Makefile index bd1faf680d..2bfd38d014 100644 --- a/usr/src/cmd/hal/probing/battery/Makefile +++ b/usr/src/cmd/hal/probing/acpi/Makefile @@ -19,15 +19,15 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # -PROG = hald-probe-battery -OBJS = probe-battery.o logger.o battery.o util_pm.o -SRCS = probe-battery.c +PROG = hald-probe-acpi +OBJS = probe-acpi.o logger.o acpi.o util_pm.o +SRCS = probe-acpi.c include ../../../Makefile.cmd include ../../Makefile.hal @@ -48,8 +48,8 @@ logger.o: ../../hald/logger.c $(COMPILE.c) -o $@ ../../hald/logger.c $(POST_PROCESS_O) -battery.o: ../../utils/battery.c - $(COMPILE.c) -o $@ ../../utils/battery.c +acpi.o: ../../utils/acpi.c + $(COMPILE.c) -o $@ ../../utils/acpi.c $(POST_PROCESS_O) util_pm.o: ../../hald/util_pm.c diff --git a/usr/src/cmd/hal/probing/battery/probe-battery.c b/usr/src/cmd/hal/probing/acpi/probe-acpi.c index af3fd8741d..4cf9e50e03 100644 --- a/usr/src/cmd/hal/probing/battery/probe-battery.c +++ b/usr/src/cmd/hal/probing/acpi/probe-acpi.c @@ -1,8 +1,8 @@ /*************************************************************************** * - * probe-battery.c : Probe for battery device information + * probe-acpi.c : Probe for ACPI device information * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Licensed under the Academic Free License version 2.1 @@ -28,7 +28,7 @@ #include <libhal.h> #include <logger.h> -#include "../utils/battery.h" +#include "../utils/acpi.h" int main(int argc, char *argv[]) @@ -53,17 +53,21 @@ main(int argc, char *argv[]) if ((ctx = libhal_ctx_init_direct(&error)) == NULL) goto out; - HAL_DEBUG(("Doing probe-battery for %s (udi=%s)", + HAL_DEBUG(("Doing probe-acpi for %s (udi=%s)", device_file, udi)); if ((fd = open(device_file, O_RDONLY | O_NONBLOCK)) < 0) { HAL_DEBUG(("Cannot open %s: %s", device_file, strerror(errno))); goto out; } - if (strstr(udi, "ac")) { + if (strstr(udi, "_ac")) { ac_adapter_update(ctx, udi, fd); - } else { + } else if (strstr(udi, "_battery")) { battery_update(ctx, udi, fd); + } else if (strstr(udi, "_lid")) { + lid_update(ctx, udi, fd); + } else if (strstr(udi, "_output")) { + laptop_panel_update(ctx, udi, fd); } ret = 0; diff --git a/usr/src/cmd/hal/tools/Makefile b/usr/src/cmd/hal/tools/Makefile index 1bffd11e74..84f577c141 100644 --- a/usr/src/cmd/hal/tools/Makefile +++ b/usr/src/cmd/hal/tools/Makefile @@ -19,16 +19,24 @@ # CDDL HEADER END # # -# Copyright 2006 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # +SUBDIR = sunos + HAL_PROG = hal-device hal-find-by-capability hal-find-by-property \ hal-get-property hal-set-property lshal -SCRIPT = hal-fdi-validate +HAL_LIB = hal-is-caller-privileged + +SCRIPT_BIN = hal-fdi-validate + +SCRIPT_LIB = hal-system-lcd-set-brightness hal-system-lcd-get-brightness \ + hal-system-power-hibernate hal-system-power-suspend \ + hal-system-power-reboot hal-system-power-shutdown hal-functions STORAGE_METHOD_PROG = hal-storage-closetray hal-storage-eject \ hal-storage-mount hal-storage-unmount \ @@ -46,7 +54,7 @@ STORAGE_SHAREDSRCS = $(STORAGE_SHAREDOBJS:%.o=%.c) SRCS = $(PROGSRCS) $(STORAGE_SHAREDSRCS) -CLOBBERFILES += $(HAL_PROG) $(STORAGE_PROG) $(SCRIPT) +CLOBBERFILES += $(HAL_PROG) $(STORAGE_PROG) $(SCRIPT_BIN) $(SCRIPT_LIB) $(HAL_LIB) CLEANFILES += $(STORAGE_SHAREDOBJS) $(STORAGE_OBJS) include ../../Makefile.cmd @@ -56,6 +64,8 @@ $(HAL_PROG) := LDLIBS += -lc -ldbus-1 -lhal lshal := LDLIBS += -ldbus-glib-1 -lglib-2.0 +$(HAL_LIB) := LDLIBS += -lc -ldbus-1 -lpolkit $(ZIGNORE) -lglib-2.0 + $(STORAGE_PROG) := LDLIBS += -lc -ldbus-1 -lglib-2.0 -lhal -lhal-storage -lbsm $(STORAGE_METHOD_PROG) := LDLIBS += -lpolkit @@ -65,14 +75,22 @@ CPPFLAGS += -I$(ROOT)/usr/include/hal CPPFLAGS += -I$(ROOT)/usr/include/libpolkit C99MODE = $(C99_ENABLE) -ROOTUSRSBINPROG = $(HAL_PROG:%=$(ROOTUSRSBIN)/%) $(SCRIPT:%=$(ROOTUSRSBIN)/%) +ROOTUSRSBINPROG = $(HAL_PROG:%=$(ROOTUSRSBIN)/%) \ + $(SCRIPT_BIN:%=$(ROOTUSRSBIN)/%) ROOTCMDDIR = $(ROOTLIB_HAL) -ROOTCMD = $(STORAGE_PROG:%=$(ROOTCMDDIR)/%) +ROOTCMD = $(STORAGE_PROG:%=$(ROOTCMDDIR)/%) \ + $(HAL_LIB:%=$(ROOTCMDDIR)/%) \ + $(SCRIPT_LIB:%=$(ROOTCMDDIR)/%) + +all := TARGET= all +install := TARGET= install +clean := TARGET= clean +clobber := TARGET= clobber .KEEP_STATE: -all: $(HAL_PROG) $(STORAGE_PROG) $(SCRIPT) +all: $(HAL_PROG) $(STORAGE_PROG) $(SCRIPT_BIN) $(SCRIPT_LIB) $(HAL_LIB) $(SUBDIR) $(STORAGE_SHAREDOBJS): $(STORAGE_SHAREDSRCS) $(COMPILE.c) $(STORAGE_SHAREDSRCS) @@ -137,10 +155,14 @@ lshal: lshal.c $(LINK.c) -o $@ lshal.c $(LDLIBS) $(POST_PROCESS) -install: all $(ROOTUSRSBINPROG) $(ROOTCMD) - +install: all $(ROOTUSRSBINPROG) $(ROOTCMD) $(SUBDIR) -clean: +clean: $(SUBDIR) $(RM) $(CLEANFILES) +$(SUBDIR): FRC + @cd $@; pwd; $(MAKE) $(TARGET) + +FRC: + include ../../Makefile.targ diff --git a/usr/src/cmd/hal/tools/hal-functions.sh b/usr/src/cmd/hal/tools/hal-functions.sh new file mode 100644 index 0000000000..c6449f6e33 --- /dev/null +++ b/usr/src/cmd/hal/tools/hal-functions.sh @@ -0,0 +1,49 @@ +# -*-Shell-script-*- +# +# hal-functions.sh: This file contains functions to be used by most or all +# hal shell scripts +# hal-system-lcd-get-brightness.sh +# +# Licensed under the Academic Free License version 2.1 +# + +hal_check_priv() { + if [ "$HAVE_POLKIT" = "1" -a -n $HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME ]; then + ACTION=$1 + PK_RESULT=`hal-is-caller-privileged --udi $UDI --action $ACTION \ + --caller $HAL_METHOD_INVOKED_BY_SYSTEMBUS_CONNECTION_NAME` + RET=$? + if [ "$RET" != "0" ]; then + echo "org.freedesktop.Hal.Device.Error" >&2 + echo "Cannot determine if caller is privileged" >&2 + exit 1 + fi + if [ "$PK_RESULT" != "yes" ] ;then + echo "org.freedesktop.Hal.Device.PermissionDeniedByPolicy" >&2 + echo "$ACTION $PK_RESULT <-- (action, result)" >&2 + exit 1 + fi + fi +} + +hal_call_backend() { + PROGRAM=`basename $0` + if [ -n "$HALD_UNAME_S" -a -x ./$HALD_UNAME_S/$PROGRAM-$HALD_UNAME_S ]; then + ./$HALD_UNAME_S/$PROGRAM-$HALD_UNAME_S $@ + else + echo "org.freedesktop.Hal.Device.UnknownError" >&2 + echo "No back-end for your operating system" >&2 + exit 1 + fi +} + +hal_exec_backend() { + PROGRAM=`basename $0` + if [ -n "$HALD_UNAME_S" -a -x ./$HALD_UNAME_S/$PROGRAM-$HALD_UNAME_S ]; then + exec ./$HALD_UNAME_S/$PROGRAM-$HALD_UNAME_S $@ + else + echo "org.freedesktop.Hal.Device.UnknownError" >&2 + echo "No back-end for your operating system" >&2 + exit 1 + fi +} diff --git a/usr/src/cmd/hal/tools/hal-is-caller-privileged.c b/usr/src/cmd/hal/tools/hal-is-caller-privileged.c new file mode 100644 index 0000000000..2e333ba644 --- /dev/null +++ b/usr/src/cmd/hal/tools/hal-is-caller-privileged.c @@ -0,0 +1,209 @@ +/*************************************************************************** + * CVSID: $Id$ + * + * hal-is-caller-privileged.c : Determine if a caller is privileged + * + * Copyright (C) 2007 David Zeuthen, <david@fubar.dk> + * + * Licensed under the Academic Free License version 2.1 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + * + **************************************************************************/ + + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> +#include <string.h> +#include <unistd.h> +#include <getopt.h> +#include <glib.h> +#include <stdlib.h> + +#include <libhal.h> +#ifdef HAVE_POLKIT +#include <libpolkit.h> +#endif + +/** + * usage: + * @argc: Number of arguments given to program + * @argv: Arguments given to program + * + * Print out program usage. + */ +static void +usage (int argc, char *argv[]) +{ + fprintf (stderr, + "\n" + "usage : hal-is-caller-privileged --udi <udi> --action <action>\n" + " --caller <caller-name>\n" + " [--help] [--version]\n"); + fprintf (stderr, + "\n" + " --udi Unique Device Id\n" + " --action PolicyKit action to check for\n" + " --caller The name of the caller\n" + " --version Show version and exit\n" + " --help Show this information and exit\n" + "\n" + "This program determines if a given process on the system bus is\n" + "privileged for a given PolicyKit action for a given device. If an error\n" + "occurs this program exits with a non-zero exit code. Otherwise\n" + "the textual reply will be printed on stdout and this program will\n" + "exit with exit code 0. Note that only the super user (root)\n" + "or other privileged users can use this tool.\n" + "\n"); +} + +#ifdef HAVE_POLKIT +static void +permission_denied_privilege (const char *privilege, const char *uid) +{ + fprintf (stderr, "org.freedesktop.Hal.Device.PermissionDeniedByPolicy\n" +); + fprintf (stderr, "%s refused uid %s\n", privilege, uid); + exit (1); +} +#endif + +/** + * main: + * @argc: Number of arguments given to program + * @argv: Arguments given to program + * + * Returns: Return code + * + * Main entry point + */ +int +main (int argc, char *argv[]) +{ + char *udi = NULL; + char *action = NULL; + char *caller = NULL; + dbus_bool_t is_version = FALSE; + DBusError error; +#ifdef HAVE_POLKIT + LibPolKitContext *pol_ctx = NULL; +#endif + DBusConnection *system_bus = NULL; + uid_t calling_uid; + char *privilege = NULL; + const char *invoked_by_uid; + gboolean allowed_by_privilege = FALSE; + gboolean is_temporary_privilege; + + if (argc <= 1) { + usage (argc, argv); + return 1; + } + + while (1) { + int c; + int option_index = 0; + const char *opt; + static struct option long_options[] = { + {"udi", 1, NULL, 0}, + {"action", 1, NULL, 0}, + {"caller", 1, NULL, 0}, + {"version", 0, NULL, 0}, + {"help", 0, NULL, 0}, + {NULL, 0, NULL, 0} + }; + + c = getopt_long (argc, argv, "", + long_options, &option_index); + if (c == -1) + break; + + switch (c) { + case 0: + opt = long_options[option_index].name; + + if (strcmp (opt, "help") == 0) { + usage (argc, argv); + return 0; + } else if (strcmp (opt, "version") == 0) { + is_version = TRUE; + } else if (strcmp (opt, "udi") == 0) { + udi = strdup (optarg); + } else if (strcmp (opt, "caller") == 0) { + caller = strdup (optarg); + } else if (strcmp (opt, "action") == 0) { + privilege = strdup (optarg); + } + break; + + default: + usage (argc, argv); + return 1; + break; + } + } + + if (is_version) { + printf ("hal-is-caller-privileged " PACKAGE_VERSION "\n"); + return 0; + } + + if (udi == NULL || caller == NULL || privilege == NULL) { + usage (argc, argv); + return 1; + } + + dbus_error_init (&error); + system_bus = dbus_bus_get (DBUS_BUS_SYSTEM, &error); + if (system_bus == NULL) { + printf ("Cannot connect to the system bus\n"); + LIBHAL_FREE_DBUS_ERROR (&error); + fprintf (stderr, "This program should only be started by hald.\n"); + exit (1); + } + +#ifdef HAVE_POLKIT + pol_ctx = libpolkit_new_context (system_bus); + if (pol_ctx == NULL) { + printf ("Cannot get libpolkit context\n"); + } + invoked_by_uid = getenv("HAL_METHOD_INVOKED_BY_UID"); + + if (libpolkit_is_uid_allowed_for_privilege (pol_ctx, + caller, + invoked_by_uid, + privilege, + udi, + &allowed_by_privilege, + &is_temporary_privilege, + NULL) != LIBPOLKIT_RESULT_OK +) { + printf ("cannot lookup privilege\n"); + fprintf (stderr, "Cannot lookup privilege from PolicyKit"); + exit (1); + } + + if (!allowed_by_privilege) { + printf ("caller don't possess privilege\n"); + permission_denied_privilege (privilege, invoked_by_uid); + } +#endif + + printf("yes\n"); + return 0; +} diff --git a/usr/src/cmd/hal/tools/hal-system-lcd-get-brightness.sh b/usr/src/cmd/hal/tools/hal-system-lcd-get-brightness.sh new file mode 100644 index 0000000000..7e7a9dd290 --- /dev/null +++ b/usr/src/cmd/hal/tools/hal-system-lcd-get-brightness.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# +# hal-system-lcd-get-brightness.sh +# +# Licensed under the Academic Free License version 2.1 +# + +. ./hal-functions +hal_check_priv hal-power-brightness +hal_exec_backend diff --git a/usr/src/cmd/hal/tools/hal-system-lcd-set-brightness.sh b/usr/src/cmd/hal/tools/hal-system-lcd-set-brightness.sh new file mode 100644 index 0000000000..3a8bc29147 --- /dev/null +++ b/usr/src/cmd/hal/tools/hal-system-lcd-set-brightness.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# +# hal-system-lcd-set-brightness.sh +# +# Licensed under the Academic Free License version 2.1 +# + +. ./hal-functions +hal_check_priv hal-power-brightness +hal_exec_backend diff --git a/usr/src/cmd/hal/tools/hal-system-power-hibernate.sh b/usr/src/cmd/hal/tools/hal-system-power-hibernate.sh new file mode 100644 index 0000000000..b64736f60d --- /dev/null +++ b/usr/src/cmd/hal/tools/hal-system-power-hibernate.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# +# hal-system-power-hibernate.sh +# +# Licensed under the Academic Free License version 2.1 +# + +. ./hal-functions +hal_check_priv hal-power-hibernate +hal_exec_backend diff --git a/usr/src/cmd/hal/tools/hal-system-power-reboot.sh b/usr/src/cmd/hal/tools/hal-system-power-reboot.sh new file mode 100644 index 0000000000..e62c9d8efe --- /dev/null +++ b/usr/src/cmd/hal/tools/hal-system-power-reboot.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# +# hal-system-power-reboot.sh +# +# Licensed under the Academic Free License version 2.1 +# + +. ./hal-functions +hal_check_priv hal-power-reboot +hal_exec_backend diff --git a/usr/src/cmd/hal/tools/hal-system-power-shutdown.sh b/usr/src/cmd/hal/tools/hal-system-power-shutdown.sh new file mode 100644 index 0000000000..5b37e2dc38 --- /dev/null +++ b/usr/src/cmd/hal/tools/hal-system-power-shutdown.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# +# hal-system-power-shutdown.sh +# +# Licensed under the Academic Free License version 2.1 +# + +. ./hal-functions +hal_check_priv hal-power-shutdown +hal_exec_backend diff --git a/usr/src/cmd/hal/tools/hal-system-power-suspend.sh b/usr/src/cmd/hal/tools/hal-system-power-suspend.sh new file mode 100644 index 0000000000..6028da2997 --- /dev/null +++ b/usr/src/cmd/hal/tools/hal-system-power-suspend.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# +# hal-system-power-suspend.sh +# +# Licensed under the Academic Free License version 2.1 +# + +. ./hal-functions +hal_check_priv hal-power-suspend +hal_exec_backend diff --git a/usr/src/cmd/hal/tools/sunos/Makefile b/usr/src/cmd/hal/tools/sunos/Makefile new file mode 100644 index 0000000000..b1b3a6dc19 --- /dev/null +++ b/usr/src/cmd/hal/tools/sunos/Makefile @@ -0,0 +1,61 @@ +# +# CDDL HEADER START +# +# The contents of this file are subject to the terms of the +# Common Development and Distribution License (the "License"). +# You may not use this file except in compliance with the License. +# +# You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE +# or http://www.opensolaris.org/os/licensing. +# See the License for the specific language governing permissions +# and limitations under the License. +# +# When distributing Covered Code, include this CDDL HEADER in each +# file and include the License file at usr/src/OPENSOLARIS.LICENSE. +# If applicable, add the following below this CDDL HEADER, with the +# fields enclosed by brackets "[]" replaced with your own identifying +# information: Portions Copyright [yyyy] [name of copyright owner] +# +# CDDL HEADER END +# +# +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. +# Use is subject to license terms. +# +# ident "%Z%%M% %I% %E% SMI" +# + +HAL_PROGS = hal-system-lcd-set-brightness-sunos \ + hal-system-lcd-get-brightness-sunos + +HAL_SCRIPTS = hal-system-power-reboot-sunos hal-system-power-suspend-sunos \ + hal-system-power-hibernate-sunos hal-system-power-shutdown-sunos + +OBJS = $(HAL_PROG:%=%.o) + +CLOBBERFILES += $(HAL_PROGS) + +include ../../../Makefile.cmd +include ../../Makefile.hal + +$(HAL_PROGS) := LDLIBS += -lc $(ZIGNORE) -lglib-2.0 + +CPPFLAGS += $(HAL_DBUS_CPPFLAGS) $(HAL_GLIB_CPPFLAGS) $(HAL_CONFIG_CPPFLAGS) +CPPFLAGS += -I$(ROOT)/usr/include/hal +CPPFLAGS += -I$(ROOT)/usr/include/libpolkit +C99MODE = $(C99_ENABLE) + +ROOTCMDDIR = $(ROOTLIB_HAL)/sunos +ROOTCMD = $(HAL_PROGS:%=$(ROOTCMDDIR)/%) \ + $(HAL_SCRIPTS:%=$(ROOTCMDDIR)/%) + +.KEEP_STATE: + +all: $(HAL_PROGS) $(HAL_SCRIPTS) + +install: all $(ROOTCMD) + +clean: + $(RM) $(OBJS) $(HAL_PROGS) $(HAL_SCRIPTS) + +include ../../../Makefile.targ diff --git a/usr/src/cmd/hal/tools/sunos/hal-system-lcd-get-brightness-sunos.c b/usr/src/cmd/hal/tools/sunos/hal-system-lcd-get-brightness-sunos.c new file mode 100644 index 0000000000..5193d671e2 --- /dev/null +++ b/usr/src/cmd/hal/tools/sunos/hal-system-lcd-get-brightness-sunos.c @@ -0,0 +1,63 @@ +/*************************************************************************** + * + * hal-system-lcd-get-brightness-sunos.c : Get LCD brightness + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + * + **************************************************************************/ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <string.h> +#include <strings.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include "../../hald/util.h" +#include <sys/acpi_drv.h> + +int +main(int argc, char *argv[]) +{ + struct acpi_drv_output_status status; + int fd = -1; + char *udi; + char device_file[HAL_PATH_MAX] = "/devices"; + char *devfs_path; + + if ((udi = getenv("UDI")) == NULL) { + return (-1); + } + if ((devfs_path = getenv("HAL_PROP_SOLARIS_DEVFS_PATH")) == NULL) { + return (-1); + } + + strlcat(device_file, devfs_path, HAL_PATH_MAX); + fprintf(stderr, "Getting brightness on %s (udi=%s)", + device_file, udi); + if ((fd = open(device_file, O_RDONLY | O_NONBLOCK)) < 0) { + fprintf(stderr, "Cannot open %s: %s", device_file, + strerror(errno)); + return (-1); + } + + bzero(&status, sizeof (status)); + if (ioctl(fd, ACPI_DRV_IOC_STATUS, &status) < 0) { + close(fd); + return (-1); + } else { + close(fd); + return (status.cur_level_index); + } +} diff --git a/usr/src/cmd/hal/tools/sunos/hal-system-lcd-set-brightness-sunos.c b/usr/src/cmd/hal/tools/sunos/hal-system-lcd-set-brightness-sunos.c new file mode 100644 index 0000000000..d3e7fa0988 --- /dev/null +++ b/usr/src/cmd/hal/tools/sunos/hal-system-lcd-set-brightness-sunos.c @@ -0,0 +1,65 @@ +/*************************************************************************** + * + * hal-system-lcd-set-brightness-sunos.c : Set LCD brightness + * + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + * + * Licensed under the Academic Free License version 2.1 + * + **************************************************************************/ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <errno.h> +#include <string.h> +#include <strings.h> +#include <ctype.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/ioctl.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/acpi_drv.h> +#include "../../hald/util.h" + +int +main(int argc, char *argv[]) +{ + char arg[10]; + int level; + int fd = -1; + char *udi; + char device_file[HAL_PATH_MAX] = "/devices"; + char *devfs_path; + + if ((udi = getenv("UDI")) == NULL) { + return (1); + } + if ((devfs_path = getenv("HAL_PROP_SOLARIS_DEVFS_PATH")) == NULL) { + return (1); + } + strlcat(device_file, devfs_path, HAL_PATH_MAX); + fprintf(stderr, "Setting brightness on %s (udi=%s)", + device_file, udi); + + if ((fd = open(device_file, O_RDONLY | O_NONBLOCK)) < 0) { + fprintf(stderr, "Cannot open %s: %s", device_file, + strerror(errno)); + return (1); + } + if (fgets(arg, sizeof (arg), stdin)) { + level = atoi(arg); + } + if (ioctl(fd, ACPI_DRV_IOC_SET_BRIGHTNESS, &level) < 0) { + close(fd); + return (1); + } else { + close(fd); + return (0); + } +} diff --git a/usr/src/cmd/hal/tools/sunos/hal-system-power-hibernate-sunos.sh b/usr/src/cmd/hal/tools/sunos/hal-system-power-hibernate-sunos.sh new file mode 100644 index 0000000000..e6bd73c027 --- /dev/null +++ b/usr/src/cmd/hal/tools/sunos/hal-system-power-hibernate-sunos.sh @@ -0,0 +1,32 @@ +#!/bin/sh +# +# hal-system-power-hibernate-sunos.sh +# +# Licensed under the Academic Free License version 2.1 +# + +unsupported() { + echo org.freedesktop.Hal.Device.SystemPowerManagement.NotSupported >&2 + echo No hibernate method found >&2 + exit 1 +} + +if [ -x "/usr/sbin/uadmin" ] ; then + /usr/sbin/uadmin 3 0 + RET=$? +else + unsupported +fi + +#Refresh devices as a resume can do funny things +for type in button battery ac_adapter +do + devices=`hal-find-by-capability --capability $type` + for device in $devices + do + dbus-send --system --print-reply --dest=org.freedesktop.Hal \ + $device org.freedesktop.Hal.Device.Rescan + done +done + +exit $RET diff --git a/usr/src/cmd/hal/tools/sunos/hal-system-power-reboot-sunos.sh b/usr/src/cmd/hal/tools/sunos/hal-system-power-reboot-sunos.sh new file mode 100644 index 0000000000..f41dd56308 --- /dev/null +++ b/usr/src/cmd/hal/tools/sunos/hal-system-power-reboot-sunos.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# +# hal-system-power-reboot-sunos.sh +# +# Licensed under the Academic Free License version 2.1 +# + +unsupported() { + echo "org.freedesktop.Hal.Device.SystemPowerManagement.NotSupported" >&2 + echo "No reboot command found" >&2 + exit 1 +} + +if [ -x "/sbin/init" ] ; then + /sbin/init 6 + exit $? +else + unsupported +fi diff --git a/usr/src/cmd/hal/tools/sunos/hal-system-power-shutdown-sunos.sh b/usr/src/cmd/hal/tools/sunos/hal-system-power-shutdown-sunos.sh new file mode 100644 index 0000000000..311e8475e7 --- /dev/null +++ b/usr/src/cmd/hal/tools/sunos/hal-system-power-shutdown-sunos.sh @@ -0,0 +1,19 @@ +#!/bin/sh +# +# hal-system-power-shutdown-sunos.sh +# +# Licensed under the Academic Free License version 2.1 +# + +unsupported() { + echo "org.freedesktop.Hal.Device.SystemPowerManagement.NotSupported" >&2 + echo "No shutdown command found" >&2 + exit 1 +} + +if [ -x "/sbin/init" ] ; then + /sbin/init 5 + exit $? +else + unsupported +fi diff --git a/usr/src/cmd/hal/tools/sunos/hal-system-power-suspend-sunos.sh b/usr/src/cmd/hal/tools/sunos/hal-system-power-suspend-sunos.sh new file mode 100644 index 0000000000..5617b61f6f --- /dev/null +++ b/usr/src/cmd/hal/tools/sunos/hal-system-power-suspend-sunos.sh @@ -0,0 +1,43 @@ +#!/bin/sh +# +# hal-system-system-power-suspend-sunos.sh +# +# Licensed under the Academic Free License version 2.1 +# + +alarm_not_supported() { + echo org.freedesktop.Hal.Device.SystemPowerManagement.AlarmNotSupported >&2 + echo Waking the system up is not supported >&2 + exit 1 +} + +unsupported() { + echo org.freedesktop.Hal.Device.SystemPowerManagement.NotSupported >&2 + echo No suspend method found >&2 + exit 1 +} + +read seconds_to_sleep +if [ $seconds_to_sleep != "0" ] ; then + alarm_not_supported +fi + +if [ -x "/usr/sbin/uadmin" ] ; then + /usr/sbin/uadmin 3 20 + RET=$? +else + unsupported +fi + +#Refresh devices as a resume can do funny things +for type in button battery ac_adapter +do + devices=`hal-find-by-capability --capability $type` + for device in $devices + do + dbus-send --system --print-reply --dest=org.freedesktop.Hal \ + $device org.freedesktop.Hal.Device.Rescan + done +done + +exit $RET diff --git a/usr/src/cmd/hal/utils/battery.c b/usr/src/cmd/hal/utils/acpi.c index 9d2008db48..5b2444f4ae 100644 --- a/usr/src/cmd/hal/utils/battery.c +++ b/usr/src/cmd/hal/utils/acpi.c @@ -1,8 +1,8 @@ /*************************************************************************** * - * battery.c : Main routines for setting battery and AC adapter properties + * acpi.c : Main routines for setting battery, AC adapter, and lid properties * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Licensed under the Academic Free License version 2.1 @@ -21,14 +21,14 @@ #include <kstat.h> #include <fcntl.h> #include <errno.h> -#include <sys/battery.h> +#include <sys/acpi_drv.h> #include <libhal.h> #include "../hald/device_info.h" #include "../hald/hald_dbus.h" #include "../hald/logger.h" #include "../hald/util_pm.h" -#include "battery.h" +#include "acpi.h" static void @@ -39,6 +39,79 @@ my_dbus_error_free(DBusError *error) } } +gboolean +laptop_panel_update(LibHalContext *ctx, const char *udi, int fd) +{ + LibHalChangeSet *cs; + DBusError error; + struct acpi_drv_output_info inf; + + HAL_DEBUG(("laptop_panel_update() enter")); + + dbus_error_init(&error); + if (!libhal_device_query_capability(ctx, udi, "laptop_panel", &error)) { + bzero(&inf, sizeof (inf)); + if ((ioctl(fd, ACPI_DRV_IOC_INFO, &inf) < 0) || + (inf.nlev == 0)) { + return (FALSE); + } + + my_dbus_error_free(&error); + libhal_device_add_capability(ctx, udi, "laptop_panel", &error); + if ((cs = libhal_device_new_changeset(udi)) == NULL) { + my_dbus_error_free(&error); + return (FALSE); + } + libhal_changeset_set_property_string(cs, "info.product", + "Generic Backlight Device"); + libhal_changeset_set_property_string(cs, "info.category", + "laptop_panel"); + libhal_changeset_set_property_int(cs, "laptop_panel.num_levels", + inf.nlev); + my_dbus_error_free(&error); + libhal_device_commit_changeset(ctx, cs, &error); + libhal_device_free_changeset(cs); + } + my_dbus_error_free(&error); + HAL_DEBUG(("ac_adapter_present() exit")); + return (TRUE); +} + +gboolean +lid_update(LibHalContext *ctx, const char *udi, int fd) +{ + LibHalChangeSet *cs; + DBusError error; + + HAL_DEBUG(("lid_update() enter")); + + dbus_error_init(&error); + if (!libhal_device_query_capability(ctx, udi, "button", &error)) { + my_dbus_error_free(&error); + libhal_device_add_capability(ctx, udi, "button", &error); + if ((cs = libhal_device_new_changeset(udi)) == NULL) { + my_dbus_error_free(&error); + return (FALSE); + } + libhal_changeset_set_property_bool(cs, "button.has_state", + TRUE); + libhal_changeset_set_property_bool(cs, "button.state.value", + FALSE); + libhal_changeset_set_property_string(cs, "button.type", + "lid"); + libhal_changeset_set_property_string(cs, "info.product", + "Lid Switch"); + libhal_changeset_set_property_string(cs, "info.category", + "button"); + my_dbus_error_free(&error); + libhal_device_commit_changeset(ctx, cs, &error); + libhal_device_free_changeset(cs); + } + my_dbus_error_free(&error); + HAL_DEBUG(("update_lid() exit")); + return (TRUE); +} + static void ac_adapter_present(LibHalContext *ctx, const char *udi, int fd) { @@ -47,7 +120,7 @@ ac_adapter_present(LibHalContext *ctx, const char *udi, int fd) DBusError error; HAL_DEBUG(("ac_adapter_present() enter")); - if (ioctl(fd, BATT_IOC_POWER_STATUS, &pow) < 0) { + if (ioctl(fd, ACPI_DRV_IOC_POWER_STATUS, &pow) < 0) { return; } if ((cs = libhal_device_new_changeset(udi)) == NULL) { @@ -170,7 +243,7 @@ battery_last_full(LibHalChangeSet *cs, int fd) acpi_bif_t bif; bzero(&bif, sizeof (bif)); - if (ioctl(fd, BATT_IOC_INFO, &bif) < 0) { + if (ioctl(fd, ACPI_DRV_IOC_INFO, &bif) < 0) { return; } libhal_changeset_set_property_int(cs, "battery.reporting_last_full", @@ -197,12 +270,12 @@ battery_dynamic_update(LibHalContext *ctx, const char *udi, int fd) HAL_DEBUG(("battery_dynamic_update() enter")); bzero(&bst, sizeof (bst)); - if (ioctl(fd, BATT_IOC_STATUS, &bst) < 0) { + if (ioctl(fd, ACPI_DRV_IOC_STATUS, &bst) < 0) { return; } - charging = bst.bst_state & BATT_BST_CHARGING ? TRUE : FALSE; - discharging = bst.bst_state & BATT_BST_DISCHARGING ? TRUE : FALSE; + charging = bst.bst_state & ACPI_DRV_BST_CHARGING ? TRUE : FALSE; + discharging = bst.bst_state & ACPI_DRV_BST_DISCHARGING ? TRUE : FALSE; /* No need to continue if battery is essentially idle. */ if (counter && !charging && !discharging) { return; @@ -359,7 +432,7 @@ battery_static_update(LibHalContext *ctx, const char *udi, int fd) HAL_DEBUG(("battery_static_update() enter")); bzero(&bif, sizeof (bif)); - if (ioctl(fd, BATT_IOC_INFO, &bif) < 0) { + if (ioctl(fd, ACPI_DRV_IOC_INFO, &bif) < 0) { return (FALSE); } if ((cs = libhal_device_new_changeset(udi)) == NULL) { @@ -436,17 +509,17 @@ battery_static_update(LibHalContext *ctx, const char *udi, int fd) "battery.charge_level.unit", "mWh"); } libhal_changeset_set_property_int(cs, - "battery.charge_level.design", reporting_design); - libhal_changeset_set_property_int(cs, - "battery.charge_level.warning", reporting_warning); - libhal_changeset_set_property_int(cs, - "battery.charge_level.low", reporting_low); - libhal_changeset_set_property_int(cs, - "battery.charge_level.granularity_1", reporting_gran1); - libhal_changeset_set_property_int(cs, - "battery.charge_level.granularity_2", reporting_gran2); + "battery.charge_level.design", reporting_design); + libhal_changeset_set_property_int(cs, + "battery.charge_level.warning", reporting_warning); + libhal_changeset_set_property_int(cs, + "battery.charge_level.low", reporting_low); + libhal_changeset_set_property_int(cs, + "battery.charge_level.granularity_1", reporting_gran1); + libhal_changeset_set_property_int(cs, + "battery.charge_level.granularity_2", reporting_gran2); } - + dbus_error_init(&error); libhal_device_commit_changeset(ctx, cs, &error); @@ -471,7 +544,7 @@ battery_update(LibHalContext *ctx, const char *udi, int fd) &error); bzero(&bst, sizeof (bst)); - if (ioctl(fd, BATT_IOC_STATUS, &bst) < 0) { + if (ioctl(fd, ACPI_DRV_IOC_STATUS, &bst) < 0) { if (errno == ENXIO) { my_dbus_error_free(&error); libhal_device_set_property_bool(ctx, udi, diff --git a/usr/src/cmd/hal/utils/battery.h b/usr/src/cmd/hal/utils/acpi.h index 58878ebea6..476f81b5b2 100644 --- a/usr/src/cmd/hal/utils/battery.h +++ b/usr/src/cmd/hal/utils/acpi.h @@ -1,8 +1,8 @@ /*************************************************************************** * - * battery.h + * acpi.h * - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Licensed under the Academic Free License version 2.1 @@ -11,8 +11,8 @@ #pragma ident "%Z%%M% %I% %E% SMI" -#ifndef BATTERY_H -#define BATTERY_H +#ifndef ACPI_H +#define ACPI_H #include "../hald/util.h" @@ -20,7 +20,9 @@ gboolean battery_update(LibHalContext *ctx, const char *udi, int fd); gboolean ac_adapter_update(LibHalContext *ctx, const char *udi, int fd); +gboolean lid_update(LibHalContext *ctx, const char *udi, int fd); +gboolean laptop_panel_update(LibHalContext *ctx, const char *udi, int fd); gboolean update_devices(gpointer data); int open_device(LibHalContext *ctx, char *udi); -#endif /* BATTERY_H */ +#endif /* ACPI_H */ diff --git a/usr/src/cmd/power/powerd.c b/usr/src/cmd/power/powerd.c index a559041d0a..0b91bd61f2 100644 --- a/usr/src/cmd/power/powerd.c +++ b/usr/src/cmd/power/powerd.c @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma ident "%Z%%M% %I% %E% SMI" @@ -1167,7 +1167,7 @@ static void power_button_monitor(void *arg) { struct pollfd pfd; - int events; + int events, ret; if (ioctl(pb_fd, PB_BEGIN_MONITOR, NULL) == -1) { logerror("Failed to monitor the power button."); @@ -1187,12 +1187,20 @@ power_button_monitor(void *arg) if (!(pfd.revents & POLLIN)) continue; + /* + * Monitor the power button, but only take action if + * gnome-power-manager is not running. + * + * ret greater than 0 means could not find process. + */ + ret = system("/usr/bin/pgrep -f -P 1 gnome-power-manager"); + if (ioctl(pfd.fd, PB_GET_EVENTS, &events) == -1) { logerror("Failed to get power button events."); thr_exit((void *) 0); } - if ((events & PB_BUTTON_PRESS) && + if ((ret > 0) && (events & PB_BUTTON_PRESS) && (poweroff(NULL, power_button_cmd) != 0)) { logerror("Power button is pressed, powering " "down the system!"); diff --git a/usr/src/lib/libsecdb/auth_attr.txt b/usr/src/lib/libsecdb/auth_attr.txt index 9a5cdf18ba..ea5203ceb8 100644 --- a/usr/src/lib/libsecdb/auth_attr.txt +++ b/usr/src/lib/libsecdb/auth_attr.txt @@ -152,6 +152,11 @@ solaris.smf.read.ndmp:::Read permission for protected SMF NDMP Service Propertie solaris.system.:::Machine Administration::help=SysHeader.html solaris.system.date:::Set Date & Time::help=SysDate.html solaris.system.shutdown:::Shutdown the System::help=SysShutdown.html +solaris.system.power.:::System Power Management::help=SysPowerMgmtHeader.html +solaris.system.power.suspend.:::Suspend the System::help=SysPowerMgmtSuspend.html +solaris.system.power.suspend.disk:::Suspend to Disk::help=SysPowerMgmtSuspendtoDisk.html +solaris.system.power.suspend.ram:::Suspend to RAM::help=SysPowerMgmtSuspendToRAM.html +solaris.system.power.brightness:::Control LCD Brightness::help=SysPowerMgmtBrightness.html # solaris.smf.manage.iscsitgt:::Manage ISCSI Target Service States::help=SmfValueIscsitgt.html solaris.smf.read.iscsitgt:::Read ISCSI Target secrets::help=SmfValueIscsitgt.html diff --git a/usr/src/lib/libsecdb/help/auths/Makefile b/usr/src/lib/libsecdb/help/auths/Makefile index 811e5a0ff9..e168b9ed64 100644 --- a/usr/src/lib/libsecdb/help/auths/Makefile +++ b/usr/src/lib/libsecdb/help/auths/Makefile @@ -131,7 +131,12 @@ HTMLENTS = \ PrintUnlabeled.html \ TNDaemon.html \ TNctl.html \ - ValueTND.html + ValueTND.html \ + SysPowerMgmtHeader.html \ + SysPowerMgmtSuspend.html \ + SysPowerMgmtSuspendtoDisk.html \ + SysPowerMgmtSuspendtoRAM.html \ + SysPowerMgmtBrightness.html HELPDIR=$(ROOT)/usr/lib/help AUTHDIR=$(HELPDIR)/auths diff --git a/usr/src/lib/libsecdb/help/auths/SysPowerMgmtBrightness.html b/usr/src/lib/libsecdb/help/auths/SysPowerMgmtBrightness.html new file mode 100644 index 0000000000..2996f18bc3 --- /dev/null +++ b/usr/src/lib/libsecdb/help/auths/SysPowerMgmtBrightness.html @@ -0,0 +1,42 @@ +<HTML> +<!-- + Copyright 2008 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END +--> +<!-- SCCS keyword +#pragma ident "%Z%%M% %I% %E% SMI" +--> +<HEAD> +<!-- +META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1" +--> +<!-- +META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]" +--> +</HEAD> +<BODY> +When Control LCD Brightness is in the Authorizations Included column, it grants the authorization to control LCD brightness. +<p> +If Control LCD Brightness is grayed, then you are not entitled to Add or Remove this authorization. +<BR> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/help/auths/SysPowerMgmtHeader.html b/usr/src/lib/libsecdb/help/auths/SysPowerMgmtHeader.html new file mode 100644 index 0000000000..1c5b1f5c72 --- /dev/null +++ b/usr/src/lib/libsecdb/help/auths/SysPowerMgmtHeader.html @@ -0,0 +1,40 @@ +<HTML> +<!-- + Copyright 2008 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END +--> +<!-- SCCS keyword +#pragma ident "%Z%%M% %I% %E% SMI" +--> +<HEAD> +<!-- +META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1" +--> +<!-- +META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]" +--> +</HEAD> +<BODY> +Authorized to change the system power management policies. +<BR> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/help/auths/SysPowerMgmtSuspend.html b/usr/src/lib/libsecdb/help/auths/SysPowerMgmtSuspend.html new file mode 100644 index 0000000000..ba6bb0cee5 --- /dev/null +++ b/usr/src/lib/libsecdb/help/auths/SysPowerMgmtSuspend.html @@ -0,0 +1,42 @@ +<HTML> +<!-- + Copyright 2008 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END +--> +<!-- SCCS keyword +#pragma ident "%Z%%M% %I% %E% SMI" +--> +<HEAD> +<!-- +META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1" +--> +<!-- +META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]" +--> +</HEAD> +<BODY> +When Suspend the System is in the Authorizations Included column, it grants the authorization to suspend the operating system. +<p> +If Suspend the System is grayed, then you are not entitled to Add or Remove this authorization. +<BR> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/help/auths/SysPowerMgmtSuspendtoDisk.html b/usr/src/lib/libsecdb/help/auths/SysPowerMgmtSuspendtoDisk.html new file mode 100644 index 0000000000..f81b8b79c0 --- /dev/null +++ b/usr/src/lib/libsecdb/help/auths/SysPowerMgmtSuspendtoDisk.html @@ -0,0 +1,42 @@ +<HTML> +<!-- + Copyright 2008 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END +--> +<!-- SCCS keyword +#pragma ident "%Z%%M% %I% %E% SMI" +--> +<HEAD> +<!-- +META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1" +--> +<!-- +META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]" +--> +</HEAD> +<BODY> +When Suspend to Disk is in the Authorizations Included column, it grants the authorization to suspend the operating system to disk. +<p> +If Suspend to Disk is grayed, then you are not entitled to Add or Remove this authorization. +<BR> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/help/auths/SysPowerMgmtSuspendtoRAM.html b/usr/src/lib/libsecdb/help/auths/SysPowerMgmtSuspendtoRAM.html new file mode 100644 index 0000000000..70ff5ff824 --- /dev/null +++ b/usr/src/lib/libsecdb/help/auths/SysPowerMgmtSuspendtoRAM.html @@ -0,0 +1,42 @@ +<HTML> +<!-- + Copyright 2008 Sun Microsystems, Inc. All rights reserved. + Use is subject to license terms. + + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END +--> +<!-- SCCS keyword +#pragma ident "%Z%%M% %I% %E% SMI" +--> +<HEAD> +<!-- +META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1" +--> +<!-- +META NAME="GENERATOR" CONTENT="Mozilla/4.02 [en] (X11; U; SunOS 5.6 sun4u) [Netscape]" +--> +</HEAD> +<BODY> +When Suspend to RAM is in the Authorizations Included column, it grants the authorization to suspend the operating system to RAM. +<p> +If Suspend to RAM is grayed, then you are not entitled to Add or Remove this authorization. +<BR> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/help/profiles/Makefile b/usr/src/lib/libsecdb/help/profiles/Makefile index 41beab05fe..b8cc361a40 100644 --- a/usr/src/lib/libsecdb/help/profiles/Makefile +++ b/usr/src/lib/libsecdb/help/profiles/Makefile @@ -80,7 +80,12 @@ HTMLENTS = \ RtDefault.html \ RtIdmapMngmnt.html \ RtIdmapNameRulesMngmnt.html \ - RtVscanMngmnt.html + RtVscanMngmnt.html \ + RtSysPowerMgmt.html \ + RtSysPowerMgmtSuspend.html \ + RtSysPowerMgmtSuspendtoDisk.html \ + RtSysPowerMgmtSuspendtoRAM.html \ + RtSysPowerMgmtBrightness.html HELPDIR = $(ROOT)/usr/lib/help diff --git a/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmt.html b/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmt.html new file mode 100644 index 0000000000..bcc46d4a71 --- /dev/null +++ b/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmt.html @@ -0,0 +1,38 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + +-- Copyright 2008 Sun Microsystems, Inc. All rights reserved. +-- Use is subject to license terms. +--> +<HEAD> + <TITLE> </TITLE> + + +</HEAD> +<BODY> +<!-- ident "%Z%%M% %I% %E% SMI" --> + +When System Power Management is in the Rights Included column, it grants the right to configure system power management policies. +<p> +If System Power Management is grayed, then you are not entitled to Add or Remove this right. +<p> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtBrightness.html b/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtBrightness.html new file mode 100644 index 0000000000..470f431e74 --- /dev/null +++ b/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtBrightness.html @@ -0,0 +1,38 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + +-- Copyright 2008 Sun Microsystems, Inc. All rights reserved. +-- Use is subject to license terms. +--> +<HEAD> + <TITLE> </TITLE> + + +</HEAD> +<BODY> +<!-- ident "%Z%%M% %I% %E% SMI" --> + +When Control LCD Brightness is in the Rights Included column, it grants the right to control LCD brightness. +<p> +If Control LCD Brightness is grayed, then you are not entitled to Add or Remove this right. +<p> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtSuspend.html b/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtSuspend.html new file mode 100644 index 0000000000..2438bb4086 --- /dev/null +++ b/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtSuspend.html @@ -0,0 +1,38 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + +-- Copyright 2008 Sun Microsystems, Inc. All rights reserved. +-- Use is subject to license terms. +--> +<HEAD> + <TITLE> </TITLE> + + +</HEAD> +<BODY> +<!-- ident "%Z%%M% %I% %E% SMI" --> + +When Suspend the System is in the Rights Included column, it grants the right to suspend the operating system. +<p> +If Suspend the System is grayed, then you are not entitled to Add or Remove this right. +<p> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtSuspendtoDisk.html b/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtSuspendtoDisk.html new file mode 100644 index 0000000000..a30dfb2a27 --- /dev/null +++ b/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtSuspendtoDisk.html @@ -0,0 +1,38 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + +-- Copyright 2008 Sun Microsystems, Inc. All rights reserved. +-- Use is subject to license terms. +--> +<HEAD> + <TITLE> </TITLE> + + +</HEAD> +<BODY> +<!-- ident "%Z%%M% %I% %E% SMI" --> + +When Suspend to Disk is in the Rights Included column, it grants the right to suspend the operating system to disk. +<p> +If Suspend to Disk is grayed, then you are not entitled to Add or Remove this right. +<p> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtSuspendtoRAM.html b/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtSuspendtoRAM.html new file mode 100644 index 0000000000..f762a9007b --- /dev/null +++ b/usr/src/lib/libsecdb/help/profiles/RtSysPowerMgmtSuspendtoRAM.html @@ -0,0 +1,38 @@ +<HTML> +<!-- + CDDL HEADER START + + The contents of this file are subject to the terms of the + Common Development and Distribution License (the "License"). + You may not use this file except in compliance with the License. + + You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + or http://www.opensolaris.org/os/licensing. + See the License for the specific language governing permissions + and limitations under the License. + + When distributing Covered Code, include this CDDL HEADER in each + file and include the License file at usr/src/OPENSOLARIS.LICENSE. + If applicable, add the following below this CDDL HEADER, with the + fields enclosed by brackets "[]" replaced with your own identifying + information: Portions Copyright [yyyy] [name of copyright owner] + + CDDL HEADER END + +-- Copyright 2008 Sun Microsystems, Inc. All rights reserved. +-- Use is subject to license terms. +--> +<HEAD> + <TITLE> </TITLE> + + +</HEAD> +<BODY> +<!-- ident "%Z%%M% %I% %E% SMI" --> + +When Suspend to RAM is in the Rights Included column, it grants the right to suspend the operating system to RAM. +<p> +If Suspend to RAM is grayed, then you are not entitled to Add or Remove this right. +<p> +</BODY> +</HTML> diff --git a/usr/src/lib/libsecdb/prof_attr.txt b/usr/src/lib/libsecdb/prof_attr.txt index 33bd14bfda..0384d74bf4 100644 --- a/usr/src/lib/libsecdb/prof_attr.txt +++ b/usr/src/lib/libsecdb/prof_attr.txt @@ -34,7 +34,7 @@ All:::Execute any command as the user or role:help=RtAll.html Audit Control:::Configure Solaris Auditing:auths=solaris.audit.config,solaris.jobs.admin;help=RtAuditCtrl.html Audit Review:::Review Solaris Auditing logs:auths=solaris.audit.read;help=RtAuditReview.html -Console User:::Manage System as the Console User:help=RtConsUser.html +Console User:::Manage System as the Console User:profiles=Suspend To RAM,Suspend To Disk,Brightness;auths=solaris.system.shutdown;help=RtConsUser.html Contract Observer:::Reliably observe any/all contract events:help=RtContractObserver.html Device Management:::Control Access to Removable Media:auths=solaris.device.*;help=RtDeviceMngmnt.html Printer Management:::Manage printers, daemons, spooling:auths=solaris.print.*,solaris.label.print,solaris.smf.manage.discovery.printers.*,solaris.smf.value.discovery.printers.*;help=RtPrntAdmin.html @@ -93,3 +93,11 @@ Object Label Management:::Change labels on files.:auths=solaris.device.allocate, Outside Accred:::Allow a user to operate outside the user accreditation range.:auths=solaris.label.range;help=RtOutsideAccred.html ISCSI Target Administration:::Configure ISCSI Target service:auths=solaris.smf.modify.iscsitgt,solaris.smf.read.iscsitgt,solaris.smf.value.iscsitgt ISCSI Target Management:::Start/Stop ISCSI Target service:auths=solaris.smf.manage.iscsitgt +# +# Power Management profiles: +# +System Power:::For authorized users to manage system power:auths=solaris.system.power.*;help=RtSysPowerMgmt.html +Suspend:::For authorized users to Suspend system:auths=solaris.system.power.suspend.*;help=RtSysPowerMgmtSuspend.html +Suspend To Disk:::For authorized users to Suspend to Disk:auths=solaris.system.power.suspend.disk;help=RtSysPowerMgmtSuspendToDisk.html +Suspend To RAM:::For authorized users to Suspend to RAM:auths=solaris.system.power.suspend.ram;help=RtSysPowerMgmtSuspendToRAM.html +Brightness:::For authorized users to Control LCD Brightness:auths=solaris.system.power.brightness;help=RtSysPowerMgmtBrightness.html diff --git a/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c b/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c index c7fcf1a454..f57d72a20c 100644 --- a/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c +++ b/usr/src/lib/policykit/libpolkit/common/libpolkit-rbac.c @@ -2,7 +2,7 @@ * * libpolkit-rbac.c : RBAC implementation of the libpolkit API * - * Copyright 2006 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * Licensed under the Academic Free License version 2.1 @@ -150,6 +150,17 @@ libpolkit_is_uid_allowed_for_privilege (LibPolKitContext *ctx, authname = "solaris.device.mount.fixed"; } else if (strcmp (privilege, "hal-storage-fixed-mount-all-options") == 0) { authname = "solaris.device.mount.alloptions.fixed"; + } else if (strcmp(privilege, "hal-power-suspend") == 0) { + authname = "solaris.system.power.suspend.ram"; + } else if (strcmp(privilege, "hal-power-hibernate") == 0) { + authname = "solaris.system.power.suspend.disk"; + } else if ((strcmp(privilege, "hal-power-shutdown") == 0) || + (strcmp(privilege, "hal-power-reboot") == 0)) { + authname = "solaris.system.shutdown"; + } else if (strcmp(privilege, "hal-power-cpu") == 0) { + authname = "solaris.system.power.cpu"; + } else if (strcmp(privilege, "hal-power-brightness") == 0) { + authname = "solaris.system.power.brightness"; } else { /* replace '-' with '.' */ authname = g_strdup (privilege); diff --git a/usr/src/pkgdefs/SUNW0on/prototype_com b/usr/src/pkgdefs/SUNW0on/prototype_com index f6f01a4208..0baa381f90 100644 --- a/usr/src/pkgdefs/SUNW0on/prototype_com +++ b/usr/src/pkgdefs/SUNW0on/prototype_com @@ -308,6 +308,11 @@ f none usr/lib/help/auths/locale/PrintUnlabeled.html 444 root bin f none usr/lib/help/auths/locale/TNDaemon.html 444 root bin f none usr/lib/help/auths/locale/TNctl.html 444 root bin f none usr/lib/help/auths/locale/ValueTND.html 444 root bin +f none usr/lib/help/auths/locale/SysPowerMgmtHeader.html 444 root bin +f none usr/lib/help/auths/locale/SysPowerMgmtSuspend.html 444 root bin +f none usr/lib/help/auths/locale/SysPowerMgmtSuspendtoDisk.html 444 root bin +f none usr/lib/help/auths/locale/SysPowerMgmtSuspendtoRAM.html 444 root bin +f none usr/lib/help/auths/locale/SysPowerMgmtBrightness.html 444 root bin # d none usr/lib/help/profiles 755 root bin d none usr/lib/help/profiles/locale 755 root bin @@ -363,6 +368,11 @@ f none usr/lib/help/profiles/locale/RtIdmapNameRulesMngmnt.html 444 root bin f none usr/lib/help/profiles/locale/RtInfoSec.html 444 root bin f none usr/lib/help/profiles/locale/RtObjectLabelMngmnt.html 444 root bin f none usr/lib/help/profiles/locale/RtOutsideAccred.html 444 root bin +f none usr/lib/help/profiles/locale/RtSysPowerMgmt.html 444 root bin +f none usr/lib/help/profiles/locale/RtSysPowerMgmtSuspend.html 444 root bin +f none usr/lib/help/profiles/locale/RtSysPowerMgmtSuspendtoDisk.html 444 root bin +f none usr/lib/help/profiles/locale/RtSysPowerMgmtSuspendtoRAM.html 444 root bin +f none usr/lib/help/profiles/locale/RtSysPowerMgmtBrightness.html 444 root bin # # # OCF Messages diff --git a/usr/src/pkgdefs/SUNWckr/prototype_i386 b/usr/src/pkgdefs/SUNWckr/prototype_i386 index 426aec3901..e74fd2522b 100644 --- a/usr/src/pkgdefs/SUNWckr/prototype_i386 +++ b/usr/src/pkgdefs/SUNWckr/prototype_i386 @@ -68,8 +68,8 @@ f none kernel/dacf/net_dacf 755 root sys f none kernel/devname/sdev_nsconfig_mod 755 root sys f none kernel/drv/aggr 755 root sys f none kernel/drv/arp 755 root sys -f none kernel/drv/battery 755 root sys -f none kernel/drv/battery.conf 644 root sys +f none kernel/drv/acpi_drv 755 root sys +f none kernel/drv/acpi_drv.conf 644 root sys f none kernel/drv/bl 755 root sys f none kernel/drv/bmc 755 root sys f none kernel/drv/bmc.conf 644 root sys @@ -279,7 +279,7 @@ f none kernel/devname/amd64/sdev_nsconfig_mod 755 root sys d none kernel/drv/amd64 755 root sys f none kernel/drv/amd64/aggr 755 root sys f none kernel/drv/amd64/arp 755 root sys -f none kernel/drv/amd64/battery 755 root sys +f none kernel/drv/amd64/acpi_drv 755 root sys f none kernel/drv/amd64/bl 755 root sys f none kernel/drv/amd64/bmc 755 root sys f none kernel/drv/amd64/bscbus 755 root sys diff --git a/usr/src/pkgdefs/SUNWcsu/prototype_com b/usr/src/pkgdefs/SUNWcsu/prototype_com index 483cc82a7b..64b01337b1 100644 --- a/usr/src/pkgdefs/SUNWcsu/prototype_com +++ b/usr/src/pkgdefs/SUNWcsu/prototype_com @@ -522,6 +522,11 @@ f none usr/lib/help/auths/locale/C/SmfIdmapStates.html 444 root bin f none usr/lib/help/auths/locale/C/SmfValueIdmap.html 444 root bin f none usr/lib/help/auths/locale/C/SmfValueVscan.html 0444 root bin f none usr/lib/help/auths/locale/C/SmfVscanStates.html 0444 root bin +f none usr/lib/help/auths/locale/C/SysPowerMgmtHeader.html 0444 root bin +f none usr/lib/help/auths/locale/C/SysPowerMgmtSuspend.html 0444 root bin +f none usr/lib/help/auths/locale/C/SysPowerMgmtSuspendtoDisk.html 0444 root bin +f none usr/lib/help/auths/locale/C/SysPowerMgmtSuspendtoRAM.html 0444 root bin +f none usr/lib/help/auths/locale/C/SysPowerMgmtBrightness.html 0444 root bin d none usr/lib/help/profiles 755 root bin d none usr/lib/help/profiles/locale 755 root bin d none usr/lib/help/profiles/locale/C 755 root bin @@ -574,6 +579,11 @@ f none usr/lib/help/profiles/locale/C/RtZoneMngmnt.html 444 root bin f none usr/lib/help/profiles/locale/C/RtIdmapMngmnt.html 444 root bin f none usr/lib/help/profiles/locale/C/RtIdmapNameRulesMngmnt.html 444 root bin f none usr/lib/help/profiles/locale/C/RtVscanMngmnt.html 444 root bin +f none usr/lib/help/profiles/locale/C/RtSysPowerMgmt.html 444 root bin +f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtSuspend.html 444 root bin +f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtSuspendtoDisk.html 444 root bin +f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtSuspendtoRAM.html 444 root bin +f none usr/lib/help/profiles/locale/C/RtSysPowerMgmtBrightness.html 444 root bin d none usr/lib/iconv 755 root bin f none usr/lib/iconv/646da.8859.t 444 root bin f none usr/lib/iconv/646de.8859.t 444 root bin diff --git a/usr/src/pkgdefs/SUNWhal/prototype_com b/usr/src/pkgdefs/SUNWhal/prototype_com index 2cc544a272..5f795202d4 100644 --- a/usr/src/pkgdefs/SUNWhal/prototype_com +++ b/usr/src/pkgdefs/SUNWhal/prototype_com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -50,12 +50,14 @@ f none usr/lib/hal/hald 555 root bin f none usr/lib/hal/hald-addon-acpi 555 root bin f none usr/lib/hal/hald-addon-network-discovery 555 root bin f none usr/lib/hal/hald-addon-storage 555 root bin -f none usr/lib/hal/hald-probe-battery 555 root bin +f none usr/lib/hal/hald-probe-acpi 555 root bin f none usr/lib/hal/hald-probe-network-printer 555 root bin f none usr/lib/hal/hald-probe-printer 555 root bin f none usr/lib/hal/hald-probe-storage 555 root bin f none usr/lib/hal/hald-probe-volume 555 root bin f none usr/lib/hal/hald-runner 555 root bin +f none usr/lib/hal/hal-functions 555 root bin +f none usr/lib/hal/hal-is-caller-privileged 555 root bin f none usr/lib/hal/hal-storage-closetray 555 root bin f none usr/lib/hal/hal-storage-eject 555 root bin f none usr/lib/hal/hal-storage-mount 555 root bin @@ -64,6 +66,19 @@ f none usr/lib/hal/hal-storage-cleanup-mountpoint 555 root bin f none usr/lib/hal/hal-storage-cleanup-all-mountpoints 555 root bin f none usr/lib/hal/hal-storage-zpool-export 555 root bin f none usr/lib/hal/hal-storage-zpool-import 555 root bin +f none usr/lib/hal/hal-system-lcd-get-brightness 555 root bin +f none usr/lib/hal/hal-system-lcd-set-brightness 555 root bin +f none usr/lib/hal/hal-system-power-hibernate 555 root bin +f none usr/lib/hal/hal-system-power-reboot 555 root bin +f none usr/lib/hal/hal-system-power-shutdown 555 root bin +f none usr/lib/hal/hal-system-power-suspend 555 root bin +d none usr/lib/hal/sunos 755 root bin +f none usr/lib/hal/sunos/hal-system-lcd-get-brightness-sunos 555 root bin +f none usr/lib/hal/sunos/hal-system-lcd-set-brightness-sunos 555 root bin +f none usr/lib/hal/sunos/hal-system-power-hibernate-sunos 555 root bin +f none usr/lib/hal/sunos/hal-system-power-reboot-sunos 555 root bin +f none usr/lib/hal/sunos/hal-system-power-shutdown-sunos 555 root bin +f none usr/lib/hal/sunos/hal-system-power-suspend-sunos 555 root bin s none usr/lib/libhal.so=./libhal.so.1.0.0 s none usr/lib/libhal.so.1=./libhal.so.1.0.0 f none usr/lib/libhal.so.1.0.0 755 root bin diff --git a/usr/src/pkgdefs/SUNWhalr/prototype_com b/usr/src/pkgdefs/SUNWhalr/prototype_com index 9cbe319b4f..8452322a9f 100644 --- a/usr/src/pkgdefs/SUNWhalr/prototype_com +++ b/usr/src/pkgdefs/SUNWhalr/prototype_com @@ -19,7 +19,7 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" @@ -66,7 +66,6 @@ d none etc/hal/fdi/information/20thirdparty 755 root bin d none etc/hal/fdi/information/30user 755 root bin d none etc/hal/fdi/policy 755 root bin d none etc/hal/fdi/policy/10osvendor 755 root bin -f none etc/hal/fdi/policy/10osvendor/10-keyboard-policy.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/10-laptop-panel-mgmt-policy.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/10-network-attached.fdi 444 root bin f none etc/hal/fdi/policy/10osvendor/10-power-mgmt-policy.fdi 444 root bin diff --git a/usr/src/pkgdefs/SUNWhea/prototype_com b/usr/src/pkgdefs/SUNWhea/prototype_com index cc72136ac2..d41415c209 100644 --- a/usr/src/pkgdefs/SUNWhea/prototype_com +++ b/usr/src/pkgdefs/SUNWhea/prototype_com @@ -655,7 +655,7 @@ f none usr/include/sys/auxv_SPARC.h 644 root bin f none usr/include/sys/avintr.h 644 root bin f none usr/include/sys/avl.h 644 root bin f none usr/include/sys/avl_impl.h 644 root bin -f none usr/include/sys/battery.h 644 root bin +f none usr/include/sys/acpi_drv.h 644 root bin f none usr/include/sys/bitmap.h 644 root bin f none usr/include/sys/bitset.h 644 root bin f none usr/include/sys/bl.h 644 root bin @@ -1253,7 +1253,6 @@ f none usr/include/sys/sysconf.h 644 root bin f none usr/include/sys/sysconfig.h 644 root bin f none usr/include/sys/sysconfig_impl.h 644 root bin d none usr/include/sys/sysevent 755 root bin -f none usr/include/sys/sysevent/acpiev.h 644 root bin f none usr/include/sys/sysevent/ap_driver.h 644 root bin f none usr/include/sys/sysevent/domain.h 644 root bin f none usr/include/sys/sysevent/dr.h 644 root bin @@ -1261,6 +1260,7 @@ f none usr/include/sys/sysevent/env.h 644 root bin f none usr/include/sys/sysevent/eventdefs.h 644 root bin f none usr/include/sys/sysevent/ipmp.h 644 root bin f none usr/include/sys/sysevent/dev.h 644 root bin +f none usr/include/sys/sysevent/pwrctl.h 644 root bin f none usr/include/sys/sysevent/svm.h 644 root bin f none usr/include/sys/sysevent.h 644 root bin f none usr/include/sys/sysevent_impl.h 644 root bin diff --git a/usr/src/pkgdefs/common_files/i.minorperm_i386 b/usr/src/pkgdefs/common_files/i.minorperm_i386 index 7ae8205f64..21e7979017 100644 --- a/usr/src/pkgdefs/common_files/i.minorperm_i386 +++ b/usr/src/pkgdefs/common_files/i.minorperm_i386 @@ -319,7 +319,7 @@ physmem:* asy:* asy:*,cu ucode:* -battery:* +acpi_drv:* smbsrv:* vscan:* nsmb:* diff --git a/usr/src/uts/common/io/power.c b/usr/src/uts/common/io/power.c index e87922ce84..cef95d8c44 100644 --- a/usr/src/uts/common/io/power.c +++ b/usr/src/uts/common/io/power.c @@ -1,4 +1,3 @@ - /* * CDDL HEADER START * @@ -20,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -58,6 +57,8 @@ #include <sys/stat.h> #include <sys/poll.h> #include <sys/pbio.h> +#include <sys/sysevent/eventdefs.h> +#include <sys/sysevent/pwrctl.h> #if defined(__sparc) #include <sys/machsystm.h> @@ -175,6 +176,8 @@ struct power_soft_state { #endif }; +static void power_gen_sysevent(struct power_soft_state *); + #ifdef ACPI_POWER_BUTTON static int power_attach_acpi(struct power_soft_state *softsp); static void power_detach_acpi(struct power_soft_state *softsp); @@ -224,7 +227,7 @@ static struct dev_ops power_ops = { static struct modldrv modldrv = { &mod_driverops, /* Type of module. This one is a driver */ - "power button driver v%I%", /* name of module */ + "power button driver", /* name of module */ &power_ops, /* driver ops */ }; @@ -442,14 +445,14 @@ power_high_intr(caddr_t arg) if (hasEPIC) { /* read isr - first issue command */ EPIC_WR(hdl, softsp->power_btn_reg, - EPIC_ATOM_INTR_READ); + EPIC_ATOM_INTR_READ); /* next, read the reg */ EPIC_RD(hdl, softsp->power_btn_reg, reg); if (reg & EPIC_FIRE_INTERRUPT) { /* PB pressed */ /* clear the interrupt */ EPIC_WR(hdl, softsp->power_btn_reg, - EPIC_ATOM_INTR_CLEAR); + EPIC_ATOM_INTR_CLEAR); } else { if (!softsp->power_btn_ioctl) { mutex_exit(&softsp->power_intr_mutex); @@ -678,6 +681,7 @@ power_issue_shutdown(caddr_t arg) mutex_exit(&softsp->power_mutex); pollwakeup(&softsp->pollhd, POLLRDNORM); pollwakeup(&softsp->pollhd, POLLIN); + power_gen_sysevent(softsp); return (DDI_INTR_CLAIMED); } @@ -699,6 +703,59 @@ power_issue_shutdown(caddr_t arg) return (DDI_INTR_CLAIMED); } +static void +power_gen_sysevent(struct power_soft_state *softsp) +{ + nvlist_t *attr_list = NULL; + int err; + char pathname[MAXPATHLEN]; + char hid[9] = "\0"; + + /* Allocate and build sysevent attribute list */ + err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, DDI_NOSLEEP); + if (err != 0) { + cmn_err(CE_WARN, + "cannot allocate memory for sysevent attributes\n"); + return; + } + +#ifdef ACPI_POWER_BUTTON + /* Only control method power button has HID */ + if (softsp->gpe_attached) { + (void) strlcpy(hid, "PNP0C0C", sizeof (hid)); + } +#endif + + err = nvlist_add_string(attr_list, PWRCTL_DEV_HID, hid); + if (err != 0) { + cmn_err(CE_WARN, + "Failed to add attr [%s] for %s/%s event", + PWRCTL_DEV_HID, EC_PWRCTL, ESC_PWRCTL_POWER_BUTTON); + nvlist_free(attr_list); + return; + } + + (void) ddi_pathname(softsp->dip, pathname); + err = nvlist_add_string(attr_list, PWRCTL_DEV_PHYS_PATH, pathname); + if (err != 0) { + cmn_err(CE_WARN, + "Failed to add attr [%s] for %s/%s event", + PWRCTL_DEV_PHYS_PATH, EC_PWRCTL, ESC_PWRCTL_POWER_BUTTON); + nvlist_free(attr_list); + return; + } + + /* Generate/log sysevent */ + err = ddi_log_sysevent(softsp->dip, DDI_VENDOR_SUNW, EC_PWRCTL, + ESC_PWRCTL_POWER_BUTTON, attr_list, NULL, DDI_NOSLEEP); + if (err != DDI_SUCCESS) { + cmn_err(CE_WARN, + "cannot log sysevent, err code %x\n", err); + } + + nvlist_free(attr_list); +} + /* * Open the device. */ @@ -1097,8 +1154,8 @@ power_setup_epic_regs(dev_info_t *dip, struct power_soft_state *softsp) attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; if (ddi_regs_map_setup(dip, 0, (caddr_t *)®_base, - EPIC_REGS_OFFSET, EPIC_REGS_LEN, &attr, - &softsp->power_rhandle) != DDI_SUCCESS) { + EPIC_REGS_OFFSET, EPIC_REGS_LEN, &attr, + &softsp->power_rhandle) != DDI_SUCCESS) { return (DDI_FAILURE); } @@ -1107,11 +1164,11 @@ power_setup_epic_regs(dev_info_t *dip, struct power_soft_state *softsp) /* Clear power button interrupt first */ EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg, - EPIC_ATOM_INTR_CLEAR); + EPIC_ATOM_INTR_CLEAR); /* Enable EPIC interrupt for power button single press event */ EPIC_WR(softsp->power_rhandle, softsp->power_btn_reg, - EPIC_ATOM_INTR_ENABLE); + EPIC_ATOM_INTR_ENABLE); /* * At this point, EPIC interrupt processing is fully initialised. @@ -1165,7 +1222,7 @@ power_setup_mbc_regs(dev_info_t *dip, struct power_soft_state *softsp) attr.devacc_attr_endian_flags = DDI_STRUCTURE_LE_ACC; attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC; if (ddi_regs_map_setup(dip, 0, (caddr_t *)®_base, 0, 0, &attr, - &softsp->power_rhandle) != DDI_SUCCESS) { + &softsp->power_rhandle) != DDI_SUCCESS) { return (DDI_FAILURE); } softsp->power_btn_reg = ®_base[FIRE_SSI_ISR]; diff --git a/usr/src/uts/common/sys/Makefile b/usr/src/uts/common/sys/Makefile index d0d531088f..400cf12915 100644 --- a/usr/src/uts/common/sys/Makefile +++ b/usr/src/uts/common/sys/Makefile @@ -73,6 +73,7 @@ GENHDRS= \ priv_names.h CHKHDRS= \ + acpi_drv.h \ acct.h \ acctctl.h \ acl.h \ @@ -97,7 +98,6 @@ CHKHDRS= \ auxv_SPARC.h \ avl.h \ avl_impl.h \ - battery.h \ bitmap.h \ bitset.h \ bl.h \ @@ -882,7 +882,6 @@ SATAGENHDRS= \ sata_cfgadm.h SYSEVENTHDRS= \ - acpiev.h \ ap_driver.h \ dev.h \ domain.h \ @@ -890,6 +889,7 @@ SYSEVENTHDRS= \ env.h \ eventdefs.h \ ipmp.h \ + pwrctl.h \ svm.h CONTRACTHDRS= \ diff --git a/usr/src/uts/common/sys/battery.h b/usr/src/uts/common/sys/acpi_drv.h index 1cc22d8ebd..7867348d52 100644 --- a/usr/src/uts/common/sys/battery.h +++ b/usr/src/uts/common/sys/acpi_drv.h @@ -20,12 +20,12 @@ */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#ifndef _BATTERY_H -#define _BATTERY_H +#ifndef _ACPI_DRV_H +#define _ACPI_DRV_H #pragma ident "%Z%%M% %I% %E% SMI" @@ -34,19 +34,23 @@ extern "C" { #endif #include <sys/param.h> - -#define _BATT_DRV (('B' << 24) + ('A' << 16) + ('T' << 8)) - -#define BATT_IOC_BAY (_BATT_DRV | 0) -#define BATT_IOC_INFO (_BATT_DRV | 1) -#define BATT_IOC_STATUS (_BATT_DRV | 2) -#define BATT_IOC_AC_COUNT (_BATT_DRV | 3) -#define BATT_IOC_POWER_STATUS (_BATT_DRV | 4) -#define BATT_IOC_SET_WARNING (_BATT_DRV | 5) -#define BATT_IOC_GET_WARNING (_BATT_DRV | 6) - -#define BATT_BST_CHARGING 2 -#define BATT_BST_DISCHARGING 1 +#include <sys/kstat.h> + +enum acpi_drv_ioctl { + ACPI_DRV_IOC_BAY, + ACPI_DRV_IOC_INFO, + ACPI_DRV_IOC_STATUS, + ACPI_DRV_IOC_AC_COUNT, + ACPI_DRV_IOC_POWER_STATUS, + ACPI_DRV_IOC_SET_WARNING, + ACPI_DRV_IOC_GET_WARNING, + ACPI_DRV_IOC_LID_STATUS, + ACPI_DRV_IOC_LEVELS, + ACPI_DRV_IOC_SET_BRIGHTNESS +}; + +#define ACPI_DRV_BST_CHARGING 2 +#define ACPI_DRV_BST_DISCHARGING 1 typedef struct batt_bay { /* Total number of bays in the system */ @@ -125,17 +129,17 @@ typedef struct acpi_bst { } acpi_bst_t; /* Battery warnning levels in percentage */ -typedef struct batt_warn { +typedef struct acpi_drv_warn { uint32_t bw_enabled; /* Enabled */ uint32_t bw_charge_warn; /* charge warn threshold */ uint32_t bw_charge_low; /* charge low threshold */ -} batt_warn_t; +} acpi_drv_warn_t; -#define BATT_DRV_NAME "battery" -#define BATT_POWER_KSTAT_NAME "power" -#define BATT_BTWARN_KSTAT_NAME "battery warning" -#define BATT_BIF_KSTAT_NAME "battery BIF" -#define BATT_BST_KSTAT_NAME "battery BST" +#define ACPI_DRV_NAME "acpi_drv" +#define ACPI_DRV_POWER_KSTAT_NAME "power" +#define ACPI_DRV_BTWARN_KSTAT_NAME "battery warning" +#define ACPI_DRV_BIF_KSTAT_NAME "battery BIF" +#define ACPI_DRV_BST_KSTAT_NAME "battery BST" #define AC "AC" #define BATTERY "battery" @@ -167,44 +171,62 @@ typedef struct batt_warn { #define PSR_AC_PRESENT "psr_ac_present" -typedef struct batt_power_kstat_s { - struct kstat_named batt_power; - struct kstat_named batt_supported_battery_count; -} batt_power_kstat_t; +typedef struct acpi_drv_power_kstat_s { + struct kstat_named acpi_drv_power; + struct kstat_named acpi_drv_supported_battery_count; +} acpi_drv_power_kstat_t; -typedef struct batt_warn_kstat_s { - struct kstat_named batt_bw_enabled; - struct kstat_named batt_bw_charge_warn; - struct kstat_named batt_bw_charge_low; -} batt_warn_kstat_t; +typedef struct acpi_drv_warn_kstat_s { + struct kstat_named acpi_drv_bw_enabled; + struct kstat_named acpi_drv_bw_charge_warn; + struct kstat_named acpi_drv_bw_charge_low; +} acpi_drv_warn_kstat_t; /* BIF kstat */ -typedef struct batt_bif_kstat_s { - struct kstat_named batt_bif_unit; - struct kstat_named batt_bif_design_cap; - struct kstat_named batt_bif_last_cap; - struct kstat_named batt_bif_tech; - struct kstat_named batt_bif_voltage; - struct kstat_named batt_bif_warn_cap; - struct kstat_named batt_bif_low_cap; - struct kstat_named batt_bif_gran1_cap; - struct kstat_named batt_bif_gran2_cap; - struct kstat_named batt_bif_model; - struct kstat_named batt_bif_serial; - struct kstat_named batt_bif_type; - struct kstat_named batt_bif_oem_info; -} batt_bif_kstat_t; +typedef struct acpi_drv_bif_kstat_s { + struct kstat_named acpi_drv_bif_unit; + struct kstat_named acpi_drv_bif_design_cap; + struct kstat_named acpi_drv_bif_last_cap; + struct kstat_named acpi_drv_bif_tech; + struct kstat_named acpi_drv_bif_voltage; + struct kstat_named acpi_drv_bif_warn_cap; + struct kstat_named acpi_drv_bif_low_cap; + struct kstat_named acpi_drv_bif_gran1_cap; + struct kstat_named acpi_drv_bif_gran2_cap; + struct kstat_named acpi_drv_bif_model; + struct kstat_named acpi_drv_bif_serial; + struct kstat_named acpi_drv_bif_type; + struct kstat_named acpi_drv_bif_oem_info; +} acpi_drv_bif_kstat_t; /* BST kstat */ -typedef struct batt_bst_kstat_s { - struct kstat_named batt_bst_state; - struct kstat_named batt_bst_rate; - struct kstat_named batt_bst_rem_cap; - struct kstat_named batt_bst_voltage; -} batt_bst_kstat_t; +typedef struct acpi_drv_bst_kstat_s { + struct kstat_named acpi_drv_bst_state; + struct kstat_named acpi_drv_bst_rate; + struct kstat_named acpi_drv_bst_rem_cap; + struct kstat_named acpi_drv_bst_voltage; +} acpi_drv_bst_kstat_t; + +struct acpi_drv_display_info { + int noutput; /* number of output devices */ + int sw_on; + int bright_on; +}; + +struct acpi_drv_output_info { + uint32_t adr; /* unique ID for this output device */ + int nlev; /* number of brightness levels */ +}; + +struct acpi_drv_output_status { + int state; + int num_levels; + int cur_level; + int cur_level_index; +}; #ifdef __cplusplus } #endif -#endif /* _BATTERY_H */ +#endif /* _ACPI_DRV_H */ diff --git a/usr/src/uts/common/sys/sysevent/eventdefs.h b/usr/src/uts/common/sys/sysevent/eventdefs.h index a6abf8b966..fcb3ab18f5 100644 --- a/usr/src/uts/common/sys/sysevent/eventdefs.h +++ b/usr/src/uts/common/sys/sysevent/eventdefs.h @@ -19,7 +19,7 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ @@ -208,14 +208,17 @@ extern "C" { #define ESC_PLATFORM_SP_RESET "ESC_platform_sp_reset" /* - * EC_ACPIEV subclass definitions + * EC_PWRCTL subclass definitions */ -#define EC_ACPIEV "EC_acpiev" -#define ESC_ACPIEV_ADD "ESC_acpiev_add" -#define ESC_ACPIEV_REMOVE "ESC_acpiev_remove" -#define ESC_ACPIEV_WARN "ESC_acpiev_warn" -#define ESC_ACPIEV_LOW "ESC_acpiev_low" -#define ESC_ACPIEV_STATE_CHANGE "ESC_acpiev_state_change" +#define EC_PWRCTL "EC_pwrctl" +#define ESC_PWRCTL_ADD "ESC_pwrctl_add" +#define ESC_PWRCTL_REMOVE "ESC_pwrctl_remove" +#define ESC_PWRCTL_WARN "ESC_pwrctl_warn" +#define ESC_PWRCTL_LOW "ESC_pwrctl_low" +#define ESC_PWRCTL_STATE_CHANGE "ESC_pwrctl_state_change" +#define ESC_PWRCTL_POWER_BUTTON "ESC_pwrctl_power_button" +#define ESC_PWRCTL_BRIGHTNESS_UP "ESC_pwrctl_brightness_up" +#define ESC_PWRCTL_BRIGHTNESS_DOWN "ESC_pwrctl_brightness_down" /* * ZFS subclass definitions. supporting attributes (name/value paris) are found diff --git a/usr/src/uts/common/sys/sysevent/acpiev.h b/usr/src/uts/common/sys/sysevent/pwrctl.h index 6c1ea0fa0c..9293c7525e 100644 --- a/usr/src/uts/common/sys/sysevent/acpiev.h +++ b/usr/src/uts/common/sys/sysevent/pwrctl.h @@ -19,12 +19,12 @@ * CDDL HEADER END */ /* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ -#ifndef _SYS_SYSEVENT_ACPIEV_H -#define _SYS_SYSEVENT_ACPIEV_H +#ifndef _SYS_SYSEVENT_PWRCTL_H +#define _SYS_SYSEVENT_PWRCTL_H #pragma ident "%Z%%M% %I% %E% SMI" @@ -33,21 +33,24 @@ extern "C" { #endif /* - * Event type schema for EC_ACPIEV: - * Event Class - EC_ACPIEV - * Event Sub-Class - ESC_ACPIEV_ADD | - * ESC_ACPIEV_REMOVE | - * ESC_ACPIEV_WARN | - * ESC_ACPIEV_LOW | - * ESC_ACPIEV_STATE_CHANGE + * Event type schema for EC_PWRCTL: + * Event Class - EC_PWRCTL + * Event Sub-Class - ESC_PWRCTL_ADD | + * ESC_PWRCTL_REMOVE | + * ESC_PWRCTL_WARN | + * ESC_PWRCTL_LOW | + * ESC_PWRCTL_STATE_CHANGE | + * ESC_PWRCTL_POWER_BUTTON | + * ESC_PWRCTL_BRIGHTNESS_UP | + * ESC_PWRCTL_BRIGHTNESS_DOWN * Event Publisher - SUNW:kern:[environmental monitor name] - * Attribute Name - ACPIEV_VERSION + * Attribute Name - PWRCTL_VERSION * Attribute Type - SE_DATA_TYPE_UINT32 * Attribute Value - [version of the schema] - * Attribute Name - ACPIEV_DEV_HID + * Attribute Name - PWRCTL_DEV_HID * Attribute Type - SE_DATA_TYPE_STRING * Attribute Value - [Label identifying the ACPI hardware] - * Attribute Name - ACPIEV_DEV_UID + * Attribute Name - PWRCTL_DEV_UID * Attribute Type - SE_DATA_TYPE_STRING * Attribute Value - [Both the _HID and _UID values can be of either type * STRING or NUMBER in the ACPI tables. In order to @@ -55,25 +58,26 @@ extern "C" { * interface, these values are always returned as NULL * terminated strings, regardless of the original data * type in the source ACPI table.] - * Attribute Name - ACPIEV_DEV_INDEX + * Attribute Name - PWRCTL_DEV_INDEX * Attribute Type - SE_DATA_TYPE_UINT32 * Attribute Value - [Device index] * - * ESC_ACPIEV_WARN, ESC_ACPIEV_LOW only field: - * Attribute Name - ACPIEV_CHARGE_LEVEL + * ESC_PWRCTL_WARN, ESC_PWRCTL_LOW only field: + * Attribute Name - PWRCTL_CHARGE_LEVEL * Attribute Type - SE_DATA_TYPE_UINT32 * Attribute Value - [charge level] */ -#define ACPIEV_VERSION "acpiev_version" /* Version of the schema */ -#define ACPIEV_DEV_PHYS_PATH "acpiev_dev_phys_path" /* Physical Path */ -#define ACPIEV_DEV_HID "acpiev_dev_hid" /* ACPI device Hardware Id */ -#define ACPIEV_DEV_UID "acpiev_dev_uid" /* ACPI device Unique Id */ -#define ACPIEV_DEV_INDEX "acpiev_dev_index" /* Device index */ -#define ACPIEV_CHARGE_LEVEL "acpiev_charge_level" /* Event related state */ +#define PWRCTL_VERSION "pwrctl_version" /* Version of the schema */ +#define PWRCTL_DEV_PHYS_PATH "pwrctl_dev_phys_path" /* Physical Path */ +#define PWRCTL_DEV_HID "pwrctl_dev_hid" /* ACPI device Hardware Id */ +#define PWRCTL_DEV_UID "pwrctl_dev_uid" /* ACPI device Unique Id */ +#define PWRCTL_DEV_INDEX "pwrctl_dev_index" /* Device index */ +#define PWRCTL_CHARGE_LEVEL "pwrctl_charge_level" /* Event related state */ +#define PWRCTL_BRIGHTNESS_LEVEL "pwrctl_brightness_level" #ifdef __cplusplus } #endif -#endif /* _SYS_SYSEVENT_ACPIEV_H */ +#endif /* _SYS_SYSEVENT_PWRCTL_H */ diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files index 8ec4d23a1e..5ae521c687 100644 --- a/usr/src/uts/i86pc/Makefile.files +++ b/usr/src/uts/i86pc/Makefile.files @@ -168,7 +168,7 @@ PCI_E_NEXUS_OBJS += pci_common.o pci_kstats.o pci_tools.o PCINEXUS_OBJS += pci.o pci_common.o pci_kstats.o pci_tools.o PCPLUSMP_OBJS += apic.o psm_common.o apic_introp.o mp_platform_common.o -BATTERY_OBJS += battery.o +ACPI_DRV_OBJS += acpi_drv.o include $(SRC)/common/mc/mc-amd/Makefile.mcamd MCAMD_OBJS += \ $(MCAMD_CMN_OBJS) \ diff --git a/usr/src/uts/i86pc/Makefile.i86pc.shared b/usr/src/uts/i86pc/Makefile.i86pc.shared index 18bc7610e2..1e1c6abe1d 100644 --- a/usr/src/uts/i86pc/Makefile.i86pc.shared +++ b/usr/src/uts/i86pc/Makefile.i86pc.shared @@ -256,7 +256,7 @@ DRV_KMODS += pci-ide DRV_KMODS += xsvc DRV_KMODS += mc-amd DRV_KMODS += tzmon -DRV_KMODS += battery +DRV_KMODS += acpi_drv DRV_KMODS += cpudrv diff --git a/usr/src/uts/i86pc/Makefile.rules b/usr/src/uts/i86pc/Makefile.rules index a411dd1ad5..78d3832d9b 100644 --- a/usr/src/uts/i86pc/Makefile.rules +++ b/usr/src/uts/i86pc/Makefile.rules @@ -69,7 +69,7 @@ $(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) -$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/battery/%.c +$(OBJS_DIR)/%.o: $(UTSBASE)/i86pc/io/acpi_drv/%.c $(COMPILE.c) -o $@ $< $(CTFCONVERT_O) @@ -256,7 +256,7 @@ $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/intel_nb5000/%.c $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) -$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/battery/%.c +$(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/acpi_drv/%.c @($(LHEAD) $(LINT.c) $< $(LTAIL)) $(LINTS_DIR)/%.ln: $(UTSBASE)/i86pc/io/mc/%.c diff --git a/usr/src/uts/i86pc/battery/Makefile b/usr/src/uts/i86pc/acpi_drv/Makefile index 0e95fd9dca..b1aafef9b2 100644 --- a/usr/src/uts/i86pc/battery/Makefile +++ b/usr/src/uts/i86pc/acpi_drv/Makefile @@ -20,14 +20,14 @@ # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" # -# This makefile drives the production of the battery -# Battery Monitor driver kernel module. +# This makefile drives the production of the acpi_drv +# driver kernel module. # # i86pc architecture dependent # @@ -40,11 +40,11 @@ UTSBASE = ../.. # # Define the module and object file sets. # -MODULE = battery -OBJECTS = $(BATTERY_OBJS:%=$(OBJS_DIR)/%) -LINTS = $(BATTERY_OBJS:%.o=$(LINTS_DIR)/%.ln) +MODULE = acpi_drv +OBJECTS = $(ACPI_DRV_OBJS:%=$(OBJS_DIR)/%) +LINTS = $(ACPI_DRV_OBJS:%.o=$(LINTS_DIR)/%.ln) ROOTMODULE = $(ROOT_DRV_DIR)/$(MODULE) -CONF_SRCDIR = $(UTSBASE)/i86pc/io/battery +CONF_SRCDIR = $(UTSBASE)/i86pc/io/acpi_drv # # Include common rules. diff --git a/usr/src/uts/i86pc/io/acpi_drv/acpi_drv.c b/usr/src/uts/i86pc/io/acpi_drv/acpi_drv.c new file mode 100644 index 0000000000..3017184b41 --- /dev/null +++ b/usr/src/uts/i86pc/io/acpi_drv/acpi_drv.c @@ -0,0 +1,2548 @@ +/* + * CDDL HEADER START + * + * The contents of this file are subject to the terms of the + * Common Development and Distribution License (the "License"). + * You may not use this file except in compliance with the License. + * + * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE + * or http://www.opensolaris.org/os/licensing. + * See the License for the specific language governing permissions + * and limitations under the License. + * + * When distributing Covered Code, include this CDDL HEADER in each + * file and include the License file at usr/src/OPENSOLARIS.LICENSE. + * If applicable, add the following below this CDDL HEADER, with the + * fields enclosed by brackets "[]" replaced with your own identifying + * information: Portions Copyright [yyyy] [name of copyright owner] + * + * CDDL HEADER END + */ + +/* + * Copyright 2008 Sun Microsystems, Inc. All rights reserved. + * Use is subject to license terms. + */ + +/* + * Driver for ACPI Battery, Lid, and LCD Monitoring and Control + */ + +#pragma ident "%Z%%M% %I% %E% SMI" + +#include <sys/conf.h> +#include <sys/modctl.h> +#include <sys/ddi.h> +#include <sys/sunddi.h> +#include <sys/stat.h> +#include <sys/sysevent/eventdefs.h> +#include <sys/sysevent/pwrctl.h> +#include <sys/reboot.h> +#include <sys/sysmacros.h> +#include <sys/acpi/acpi.h> +#include <sys/acpica.h> +#include <sys/note.h> +#include <sys/acpi_drv.h> + + +#define ACPI_DRV_MOD_STRING "ACPI driver" + +#define MINOR_SHIFT 8 +#define IDX_MASK ((1 << MINOR_SHIFT) - 1) +#define MINOR_BATT(idx) (ACPI_DRV_TYPE_CBAT << MINOR_SHIFT | \ + (idx)) +#define MINOR_AC(idx) (ACPI_DRV_TYPE_AC << MINOR_SHIFT | \ + (idx)) +#define MINOR_LID(idx) (ACPI_DRV_TYPE_LID << MINOR_SHIFT | \ + (idx)) +#define MINOR_DISPLAY(idx) (ACPI_DRV_TYPE_DISPLAY << MINOR_SHIFT \ + | (idx)) +#define MINOR_OUTPUT(idx) (ACPI_DRV_TYPE_OUTPUT << MINOR_SHIFT | \ + (idx)) +#define MINOR2IDX(minor) ((minor) & IDX_MASK) +#define MINOR2TYPE(minor) ((minor) >> MINOR_SHIFT) + +#define ACPI_DRV_OK (0) +#define ACPI_DRV_ERR (1) + +#define ACPI_DRV_MAX_BAT_NUM 8 +#define ACPI_DRV_MAX_AC_NUM 10 +#define ACPI_DRV_MAX_OUTPUT_NUM 5 + +#define BST_FLAG_DISCHARGING (0x1) +#define BST_FLAG_CHARGING (0x2) +#define BST_FLAG_CRITICAL (0x4) + +/* Set if the battery is present */ +#define STA_FLAG_BATT_PRESENT (0x10) + +#define ACPI_DEVNAME_CBAT "PNP0C0A" +#define ACPI_DEVNAME_SBAT "ACPI0002" +#define ACPI_DEVNAME_AC "ACPI0003" +#define ACPI_DEVNAME_LID "PNP0C0D" + +#define ACPI_DRV_EVENTS (POLLIN | POLLRDNORM) + +#ifdef DEBUG + +#define ACPI_DRV_PRINT_BUFFER_SIZE 512 +static char acpi_drv_prt_buf[ACPI_DRV_PRINT_BUFFER_SIZE]; +static kmutex_t acpi_drv_prt_mutex; + +static int acpi_drv_debug = 0; +#define ACPI_DRV_DBG(lev, devp, ...) \ + do { \ + if (acpi_drv_debug) acpi_drv_printf((devp), \ +(lev), __VA_ARGS__); \ +_NOTE(CONSTCOND) } while (0) +#define ACPI_DRV_PRT_NOTIFY(hdl, val) \ + do { \ + if (acpi_drv_debug) acpi_drv_prt_notify((hdl), (val)); \ +_NOTE(CONSTCOND) } while (0) + +#else + +#define ACPI_DRV_DBG(lev, devp, ...) +#define ACPI_DRV_PRT_NOTIFY(hdl, val) + +#endif /* DEBUG */ + +/* ACPI notify types */ +enum acpi_drv_notify { + ACPI_DRV_NTF_UNKNOWN = -1, /* No notifications seen, ever. */ + ACPI_DRV_NTF_CHANGED, + ACPI_DRV_NTF_OK +}; + +/* Battery device types */ +enum acpi_drv_type { + ACPI_DRV_TYPE_UNKNOWN, + ACPI_DRV_TYPE_CBAT, + ACPI_DRV_TYPE_AC, + ACPI_DRV_TYPE_SBAT, + ACPI_DRV_TYPE_LID, + ACPI_DRV_TYPE_DISPLAY, + ACPI_DRV_TYPE_OUTPUT +}; + +struct acpi_drv_dev { + ACPI_HANDLE hdl; + char hid[9]; /* ACPI HardwareId */ + char uid[9]; /* ACPI UniqueId */ + ACPI_INTEGER adr; /* Bus device Id */ + int valid; /* the device state is valid */ + + /* + * Unlike most other devices, when a battery is inserted or + * removed from the system, the device itself(the battery bay) + * is still considered to be present in the system. + * + * Value: + * 0 -- On-line + * 1 -- Off-line + * -1 -- Unknown + */ + int present; + enum acpi_drv_type type; + int index; /* device index */ + int minor; + + struct acpi_drv_output_state *op; + struct acpi_drv_display_state *dp; +}; + +static int acpi_drv_dev_present(struct acpi_drv_dev *); +#define acpi_drv_ac_present(a) (((a)->dev.type == ACPI_DRV_TYPE_AC) ? \ + acpi_drv_dev_present(&(a)->dev) : -1) +#define acpi_drv_cbat_present(a) (((a)->dev.type == ACPI_DRV_TYPE_CBAT) \ + ? acpi_drv_dev_present(&(a)->dev) : -1) + +static dev_info_t *acpi_drv_dip = NULL; +static kmutex_t acpi_drv_mutex; +static struct pollhead acpi_drv_pollhead; + +/* Control Method Battery state */ +struct acpi_drv_cbat_state { + struct acpi_drv_dev dev; + /* Caches of _BST and _BIF */ + enum acpi_drv_notify bat_bifok; + acpi_bif_t bif_cache; + enum acpi_drv_notify bat_bstok; + acpi_bst_t bst_cache; + + uint32_t charge_warn; + uint32_t charge_low; + + kstat_t *bat_bif_ksp; + kstat_t *bat_bst_ksp; +} acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM]; +static int nbat; + +/* + * Synthesis battery state + * When there are multiple batteries present, the battery subsystem + * is not required to perform any synthesis of a composite battery + * from the data of the separate batteries. In cases where the + * battery subsystem does not synthesize a composite battery from + * the separate battery's data, the OS must provide that synthesis. + */ +static uint32_t acpi_drv_syn_rem_cap; +static uint32_t acpi_drv_syn_last_cap; +static uint32_t acpi_drv_syn_oem_warn_cap; +static uint32_t acpi_drv_syn_oem_low_cap; + +static int acpi_drv_warn_enabled; +static uint32_t acpi_drv_syn_warn_per; +static uint32_t acpi_drv_syn_low_per; +static uint32_t acpi_drv_syn_warn_cap; +static uint32_t acpi_drv_syn_low_cap; +/* Tracking boundery passing of _BST charge levels */ +static uint32_t acpi_drv_syn_last_level; + +/* AC state */ +static struct acpi_drv_ac_state { + struct acpi_drv_dev dev; +} acpi_drv_ac[ACPI_DRV_MAX_AC_NUM]; +static int nac; + +/* + * Current power source device + * Note: assume only one device can be the power source device. + */ +static int acpi_drv_psr_type = ACPI_DRV_TYPE_UNKNOWN; +static struct acpi_drv_dev *acpi_drv_psr_devp = NULL; + +/* Smart Battery state */ +static struct acpi_drv_sbat_state { + struct acpi_drv_dev dev; +} acpi_drv_sbat; + +struct obj_desc { + char *name; + int offset; + int size; + int type; +}; + +/* Object copy definitions */ +#define OFFSETOF(s, m) ((size_t)(&(((s *)0)->m))) +#define SIZEOF(s, m) (sizeof (((s *)0)->m)) +#define FIELD(n, s, m, t) \ + { n, OFFSETOF(s, m), SIZEOF(s, m), t } +#define FIELD_NULL { NULL, -1, 0, ACPI_TYPE_ANY } + +static struct obj_desc bif_desc[] = { + FIELD("bif_unit", acpi_bif_t, bif_unit, ACPI_TYPE_INTEGER), + FIELD("bif_design_cap", acpi_bif_t, bif_design_cap, ACPI_TYPE_INTEGER), + FIELD("bif_last_cap", acpi_bif_t, bif_last_cap, ACPI_TYPE_INTEGER), + FIELD("bif_tech", acpi_bif_t, bif_tech, ACPI_TYPE_INTEGER), + FIELD("bif_voltage", acpi_bif_t, bif_voltage, ACPI_TYPE_INTEGER), + FIELD("bif_warn_cap", acpi_bif_t, bif_warn_cap, ACPI_TYPE_INTEGER), + FIELD("bif_low_cap", acpi_bif_t, bif_low_cap, ACPI_TYPE_INTEGER), + FIELD("bif_gran1_cap", acpi_bif_t, bif_gran1_cap, ACPI_TYPE_INTEGER), + FIELD("bif_gran2_cap", acpi_bif_t, bif_gran2_cap, ACPI_TYPE_INTEGER), + FIELD("bif_model", acpi_bif_t, bif_model, ACPI_TYPE_STRING), + FIELD("bif_serial", acpi_bif_t, bif_serial, ACPI_TYPE_STRING), + FIELD("bif_type", acpi_bif_t, bif_type, ACPI_TYPE_STRING), + FIELD("bif_oem_info", acpi_bif_t, bif_oem_info, ACPI_TYPE_STRING), + FIELD_NULL +}; + +static struct obj_desc bst_desc[] = { + FIELD("bst_state", acpi_bst_t, bst_state, ACPI_TYPE_INTEGER), + FIELD("bst_rate", acpi_bst_t, bst_rate, ACPI_TYPE_INTEGER), + FIELD("bst_rem_cap", acpi_bst_t, bst_rem_cap, ACPI_TYPE_INTEGER), + FIELD("bst_voltage", acpi_bst_t, bst_voltage, ACPI_TYPE_INTEGER), + FIELD_NULL +}; + +/* kstat definitions */ +static kstat_t *acpi_drv_power_ksp; +static kstat_t *acpi_drv_warn_ksp; + +acpi_drv_power_kstat_t acpi_drv_power_kstat = { + { SYSTEM_POWER, KSTAT_DATA_STRING }, + { SUPPORTED_BATTERY_COUNT, KSTAT_DATA_UINT32 }, +}; + +acpi_drv_warn_kstat_t acpi_drv_warn_kstat = { + { BW_ENABLED, KSTAT_DATA_UINT32 }, + { BW_POWEROFF_THRESHOLD, KSTAT_DATA_UINT32 }, + { BW_SHUTDOWN_THRESHOLD, KSTAT_DATA_UINT32 }, +}; + +/* BIF */ +acpi_drv_bif_kstat_t acpi_drv_bif_kstat = { + { BIF_UNIT, KSTAT_DATA_UINT32 }, + { BIF_DESIGN_CAP, KSTAT_DATA_UINT32 }, + { BIF_LAST_CAP, KSTAT_DATA_UINT32 }, + { BIF_TECH, KSTAT_DATA_UINT32 }, + { BIF_VOLTAGE, KSTAT_DATA_UINT32 }, + { BIF_WARN_CAP, KSTAT_DATA_UINT32 }, + { BIF_LOW_CAP, KSTAT_DATA_UINT32 }, + { BIF_GRAN1_CAP, KSTAT_DATA_UINT32 }, + { BIF_GRAN2_CAP, KSTAT_DATA_UINT32 }, + { BIF_MODEL, KSTAT_DATA_STRING }, + { BIF_SERIAL, KSTAT_DATA_STRING }, + { BIF_TYPE, KSTAT_DATA_STRING }, + { BIF_OEM_INFO, KSTAT_DATA_STRING }, +}; + +/* BST */ +acpi_drv_bst_kstat_t acpi_drv_bst_kstat = { + { BST_STATE, KSTAT_DATA_UINT32 }, + { BST_RATE, KSTAT_DATA_UINT32 }, + { BST_REM_CAP, KSTAT_DATA_UINT32 }, + { BST_VOLTAGE, KSTAT_DATA_UINT32 }, +}; + +struct acpi_drv_lid_state { + struct acpi_drv_dev dev; + enum acpi_drv_notify state_ok; + int state; +} lid; + +/* Output device status */ +#define ACPI_DRV_DCS_CONNECTOR_EXIST (1 << 0) +#define ACPI_DRV_DCS_ACTIVE (1 << 1) +#define ACPI_DRV_DCS_READY (1 << 2) +#define ACPI_DRV_DCS_FUNCTIONAL (1 << 3) +#define ACPI_DRV_DCS_ATTACHED (1 << 4) + +/* _DOS default value is 1 */ +/* _DOS bit 1:0 */ +#define ACPI_DRV_DOS_SWITCH_OS_DGS 0 +#define ACPI_DRV_DOS_SWITCH_BIOS 1 +#define ACPI_DRV_DOS_SWITCH_DGS_LOCKED 2 +#define ACPI_DRV_DOS_SWITCH_OS_EVENT 3 +/* _DOS bit 2 */ +#define ACPI_DRV_DOS_BRIGHT_BIOS (0 << 2) +#define ACPI_DRV_DOS_BRIGHT_OS (1 << 2) + +struct acpi_drv_output_state { + struct acpi_drv_dev dev; + uint32_t adr; + uint32_t *levels; + int num_levels; /* number of levels */ + int nlev; /* actual array size of levels */ + int cur_level; + int cur_level_index; + int state; +} outputs[ACPI_DRV_MAX_OUTPUT_NUM]; +static int noutput = 0; + +struct acpi_drv_display_state { + struct acpi_drv_dev dev; + int mode; + int noutput; +} display; + +static int acpi_drv_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); +static int acpi_drv_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); +static int acpi_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, + void **resultp); +static int acpi_drv_open(dev_t *devp, int flag, int otyp, cred_t *crp); +static int acpi_drv_close(dev_t dev, int flag, int otyp, cred_t *crp); +static int acpi_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, + cred_t *cr, int *rval); +static int acpi_drv_chpoll(dev_t dev, short events, int anyyet, + short *reventsp, struct pollhead **phpp); +static int acpi_drv_ac_ioctl(int index, int cmd, intptr_t arg, int mode, + cred_t *cr, int *rval); +static int acpi_drv_cbat_ioctl(int index, int cmd, intptr_t arg, int mode, + cred_t *cr, int *rval); +static int acpi_drv_lid_ioctl(int index, int cmd, intptr_t arg, int mode, + cred_t *cr, int *rval); +static int acpi_drv_output_ioctl(int index, int cmd, intptr_t arg, int mode, + cred_t *cr, int *rval); +#ifdef DEBUG +static void acpi_drv_printf(struct acpi_drv_dev *devp, uint_t lev, + const char *fmt, ...); +#endif + +/* + * Output device functions + */ +static int acpi_drv_output_init(ACPI_HANDLE hdl, struct acpi_drv_dev *dev); +static void acpi_drv_output_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx); +static int acpi_drv_output_get_state(struct acpi_drv_output_state *op); +static int acpi_drv_output_get_level(struct acpi_drv_output_state *op); +static int acpi_drv_output_set_level(struct acpi_drv_output_state *op, + uint32_t level); +static struct acpi_drv_output_state *acpi_drv_idx2output(int idx); + +/* + * Display device functions + */ +static void acpi_drv_display_set_mode(struct acpi_drv_display_state *dp, + int state); + +static int acpi_drv_update_bif(struct acpi_drv_cbat_state *bp); +static int acpi_drv_update_bst(struct acpi_drv_cbat_state *bp); +static int acpi_drv_update_lid(struct acpi_drv_dev *bp); +static int acpi_drv_set_warn(acpi_drv_warn_t *bwp); +static struct acpi_drv_cbat_state *acpi_drv_idx2cbat(int idx); +static struct acpi_drv_ac_state *acpi_drv_idx2ac(int idx); +static int acpi_drv_acpi_init(void); +static void acpi_drv_acpi_fini(void); +static int acpi_drv_kstat_init(void); +static void acpi_drv_kstat_fini(void); + +static struct cb_ops acpi_drv_cb_ops = { + acpi_drv_open, /* open */ + acpi_drv_close, /* close */ + nodev, /* strategy */ + nodev, /* print */ + nodev, /* dump */ + nodev, /* read */ + nodev, /* write */ + acpi_drv_ioctl, /* ioctl */ + nodev, /* devmap */ + nodev, /* mmap */ + nodev, /* segmap */ + acpi_drv_chpoll, /* chpoll */ + ddi_prop_op, /* prop_op */ + NULL, /* streamtab */ + D_NEW | D_MP, + CB_REV, + nodev, + nodev +}; + +static struct dev_ops acpi_drv_dev_ops = { + DEVO_REV, + 0, /* refcnt */ + acpi_drv_getinfo, /* getinfo */ + nulldev, /* identify */ + nulldev, /* probe */ + acpi_drv_attach, /* attach */ + acpi_drv_detach, /* detach */ + nodev, /* reset */ + &acpi_drv_cb_ops, + NULL, /* no bus operations */ + NULL /* power */ +}; + +static struct modldrv modldrv1 = { + &mod_driverops, + ACPI_DRV_MOD_STRING, + &acpi_drv_dev_ops +}; + +static struct modlinkage modlinkage = { + MODREV_1, + (void *)&modldrv1, + NULL, +}; + +int +_init(void) +{ + int ret; + + mutex_init(&acpi_drv_mutex, NULL, MUTEX_DRIVER, NULL); +#ifdef DEBUG + mutex_init(&acpi_drv_prt_mutex, NULL, MUTEX_DRIVER, NULL); +#endif + + if ((ret = mod_install(&modlinkage)) != 0) { + mutex_destroy(&acpi_drv_mutex); +#ifdef DEBUG + mutex_destroy(&acpi_drv_prt_mutex); +#endif + } + return (ret); +} + +int +_fini(void) +{ + int ret; + + if ((ret = mod_remove(&modlinkage)) == 0) { +#ifdef DEBUG + mutex_destroy(&acpi_drv_prt_mutex); +#endif + mutex_destroy(&acpi_drv_mutex); + } + + return (ret); +} + +int +_info(struct modinfo *mp) +{ + return (mod_info(&modlinkage, mp)); +} + +static int +acpi_drv_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) +{ + char name[20]; + int i; + struct acpi_drv_cbat_state *bp; + struct acpi_drv_output_state *op; + + switch (cmd) { + case DDI_ATTACH: + /* Limit to one instance of driver */ + if (acpi_drv_dip) { + return (DDI_FAILURE); + } + break; + case DDI_RESUME: + case DDI_PM_RESUME: + return (DDI_SUCCESS); + default: + return (DDI_FAILURE); + } + + acpi_drv_dip = devi; + + /* Init ACPI related stuff */ + if (acpi_drv_acpi_init() != ACPI_DRV_OK) { + goto error; + } + + /* Init kstat related stuff */ + if (acpi_drv_kstat_init() != ACPI_DRV_OK) { + goto error; + } + + /* Create minor node for each output. */ + for (op = &outputs[0]; op < &outputs[ACPI_DRV_MAX_OUTPUT_NUM]; op++) { + if (op->dev.valid) { + (void) snprintf(name, sizeof (name), "output%d", + op->dev.index); + if (ddi_create_minor_node(devi, name, S_IFCHR, + MINOR_OUTPUT(op->dev.index), DDI_PSEUDO, 0) == + DDI_FAILURE) { + ACPI_DRV_DBG(CE_WARN, NULL, + "%s: minor node create failed", name); + goto error; + } + } + } + + /* Create minor node for display device. */ + if (ddi_create_minor_node(devi, "display", S_IFCHR, MINOR_DISPLAY(0), + DDI_PSEUDO, 0) == DDI_FAILURE) { + ACPI_DRV_DBG(CE_WARN, NULL, "display: " + "minor node create failed"); + goto error; + } + /* Create minor node for lid. */ + if (ddi_create_minor_node(devi, "lid", S_IFCHR, MINOR_LID(0), + DDI_PSEUDO, 0) == DDI_FAILURE) { + ACPI_DRV_DBG(CE_WARN, NULL, "lid: minor node create failed"); + goto error; + } + /* Create minor node for each battery and ac */ + for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM]; + bp++) { + if (bp->dev.valid) { + (void) snprintf(name, sizeof (name), "battery%d", + bp->dev.index); + if (ddi_create_minor_node(devi, name, S_IFCHR, + MINOR_BATT(bp->dev.index), DDI_PSEUDO, 0) == + DDI_FAILURE) { + ACPI_DRV_DBG(CE_WARN, NULL, + "%s: minor node create failed", name); + goto error; + } + } + } + for (i = 0; i < nac; i++) { + (void) snprintf(name, sizeof (name), "ac%d", i); + if (ddi_create_minor_node(devi, name, S_IFCHR, + MINOR_AC(i), DDI_PSEUDO, 0) == DDI_FAILURE) { + ACPI_DRV_DBG(CE_WARN, NULL, + "%s: minor node create failed", name); + goto error; + } + } + + return (DDI_SUCCESS); + +error: + ddi_remove_minor_node(devi, NULL); + acpi_drv_kstat_fini(); + acpi_drv_acpi_fini(); + acpi_drv_dip = NULL; + return (DDI_FAILURE); +} + +static int +acpi_drv_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) +{ + if (cmd != DDI_DETACH) { + return (DDI_FAILURE); + } + + mutex_enter(&acpi_drv_mutex); + ddi_remove_minor_node(devi, NULL); + + acpi_drv_kstat_fini(); + acpi_drv_acpi_fini(); + mutex_exit(&acpi_drv_mutex); + return (DDI_SUCCESS); +} + +/* ARGSUSED */ +static int +acpi_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) +{ + switch (cmd) { + case DDI_INFO_DEVT2DEVINFO: + *resultp = acpi_drv_dip; + return (DDI_SUCCESS); + case DDI_INFO_DEVT2INSTANCE: + *resultp = (void*) 0; + return (DDI_SUCCESS); + default: + return (DDI_FAILURE); + } +} + +/*ARGSUSED*/ +static int +acpi_drv_open(dev_t *devp, int flag, int otyp, cred_t *crp) +{ + if (acpi_drv_dip == NULL) { + return (ENXIO); + } + + return (0); +} + +/*ARGSUSED*/ +static int +acpi_drv_close(dev_t dev, int flag, int otyp, cred_t *crp) +{ + return (0); +} + +/*ARGSUSED*/ +static int +acpi_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, + int *rval) +{ + int minor; + int type, index; + int res = 0; + + minor = getminor(dev); + type = MINOR2TYPE(minor); + index = MINOR2IDX(minor); + + mutex_enter(&acpi_drv_mutex); + + switch (type) { + case ACPI_DRV_TYPE_CBAT: + res = acpi_drv_cbat_ioctl(index, cmd, arg, mode, cr, rval); + break; + case ACPI_DRV_TYPE_AC: + res = acpi_drv_ac_ioctl(index, cmd, arg, mode, cr, rval); + break; + case ACPI_DRV_TYPE_LID: + res = acpi_drv_lid_ioctl(index, cmd, arg, mode, cr, rval); + break; + case ACPI_DRV_TYPE_OUTPUT: + res = acpi_drv_output_ioctl(index, cmd, arg, mode, cr, rval); + break; + default: + res = EINVAL; + break; + } + + mutex_exit(&acpi_drv_mutex); + return (res); +} + +/*ARGSUSED*/ +static int +acpi_drv_cbat_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr, + int *rval) +{ + int res = 0; + acpi_drv_warn_t bwarn; + struct acpi_drv_cbat_state *bp; + + ASSERT(mutex_owned(&acpi_drv_mutex)); + + bp = acpi_drv_idx2cbat(index); + if (!bp || bp->dev.valid != 1) { + return (ENXIO); + } + + switch (cmd) { + /* + * Return _BIF(Battery Information) of battery[index], + * if battery plugged. + */ + case ACPI_DRV_IOC_INFO: + if (bp->dev.present == 0) { + res = ENXIO; + break; + } + + res = acpi_drv_update_bif(bp); + if (res != ACPI_DRV_OK) { + break; + } + if (copyout(&bp->bif_cache, (void *)arg, + sizeof (bp->bif_cache))) { + res = EFAULT; + } + break; + + /* + * Return _BST(Battery Status) of battery[index], + * if battery plugged. + */ + case ACPI_DRV_IOC_STATUS: + if (bp->dev.present == 0) { + res = ENXIO; + break; + } + + res = acpi_drv_update_bst(bp); + if (res != ACPI_DRV_OK) { + break; + } + if (copyout(&bp->bst_cache, (void *)arg, + sizeof (bp->bst_cache))) { + res = EFAULT; + } + break; + + /* Return the state of the battery bays in the system */ + case ACPI_DRV_IOC_BAY: + { + batt_bay_t bay; + + bay.bay_number = nbat; + bay.battery_map = 0; + for (bp = &acpi_drv_cbat[0]; + bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM]; bp++) { + if (bp->dev.valid) { + if (bp->dev.present) { + bay.battery_map |= + (1 << bp->dev.index); + } + } + } + if (copyout(&bay, (void *)arg, sizeof (bay))) { + res = EFAULT; + break; + } + } + break; + + /* + * Return the current power source device if available: + * 0 -- battery supplying power + * 1 -- AC supplying power + */ + case ACPI_DRV_IOC_POWER_STATUS: + { + int val; + + /* State not available */ + if (acpi_drv_psr_type == ACPI_DRV_TYPE_UNKNOWN) { + res = ENXIO; + break; + } + val = (acpi_drv_psr_type == ACPI_DRV_TYPE_AC) ? 1 : 0; + if (copyout(&val, (void *)arg, sizeof (val))) { + res = EFAULT; + break; + } + } + break; + + /* Get charge-warn and charge-low levels for the whole system */ + case ACPI_DRV_IOC_GET_WARNING: + bwarn.bw_enabled = acpi_drv_warn_enabled; + bwarn.bw_charge_warn = acpi_drv_syn_warn_per; + bwarn.bw_charge_low = acpi_drv_syn_low_per; + if (copyout(&bwarn, (void *)arg, sizeof (&bwarn))) { + res = EFAULT; + } + break; + + /* Set charge-warn and charge-low levels for the whole system */ + case ACPI_DRV_IOC_SET_WARNING: + if (drv_priv(cr)) { + res = EPERM; + break; + } + if (copyin((void *)arg, &bwarn, sizeof (bwarn))) { + res = EFAULT; + break; + } + res = acpi_drv_set_warn(&bwarn); + break; + + default: + res = EINVAL; + break; + } + + return (res); +} + +/*ARGSUSED*/ +static int +acpi_drv_ac_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr, + int *rval) +{ + int res = 0; + int ac_state; + struct acpi_drv_ac_state *acp; + + ASSERT(mutex_owned(&acpi_drv_mutex)); + + acp = acpi_drv_idx2ac(index); + if (!acp || acp->dev.valid != 1) { + return (ENXIO); + } + + switch (cmd) { + /* Return the number of AC adapters in the system */ + case ACPI_DRV_IOC_AC_COUNT: + if (copyout(&nac, (void *)arg, sizeof (nac))) { + res = EFAULT; + } + break; + + /* + * Return the state of AC[index] if available: + * 0 -- Off-line + * 1 -- On-line + */ + case ACPI_DRV_IOC_POWER_STATUS: + if (!acp || acp->dev.valid != 1) { + res = ENXIO; + break; + } + /* State not available */ + if ((ac_state = acpi_drv_ac_present(acp)) == -1) { + res = ENXIO; + break; + } + if (copyout(&ac_state, (void *)arg, sizeof (ac_state))) { + res = EFAULT; + } + break; + + default: + res = EINVAL; + break; + } + + return (res); +} + +/*ARGSUSED*/ +static int +acpi_drv_lid_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr, + int *rval) +{ + int res = 0; + + switch (cmd) { + case ACPI_DRV_IOC_LID_STATUS: + if (lid.state_ok == ACPI_DRV_NTF_UNKNOWN) { + /* State not available */ + res = acpi_drv_update_lid(&lid.dev); + if (res != ACPI_DRV_OK) { + res = ENXIO; + break; + } + } + if (copyout(&lid.state, (void *)arg, sizeof (lid.state))) { + res = EFAULT; + break; + } + break; + + default: + res = EINVAL; + break; + } + return (res); +} + +/*ARGSUSED*/ +static int +acpi_drv_chpoll(dev_t dev, short events, int anyyet, short *reventsp, + struct pollhead **phpp) +{ + if (!anyyet) { + *phpp = &acpi_drv_pollhead; + } + *reventsp = 0; + return (0); +} + +#ifdef DEBUG +static void +acpi_drv_printf(struct acpi_drv_dev *devp, uint_t lev, + const char *fmt, ...) +{ + va_list args; + + mutex_enter(&acpi_drv_prt_mutex); + + va_start(args, fmt); + (void) vsprintf(acpi_drv_prt_buf, fmt, args); + va_end(args); + + if (devp) { + cmn_err(lev, "%s.%s: %s", devp->hid, devp->uid, + acpi_drv_prt_buf); + } else { + cmn_err(lev, "%s", acpi_drv_prt_buf); + } + mutex_exit(&acpi_drv_prt_mutex); +} + +static void +acpi_drv_prt_notify(ACPI_HANDLE hdl, UINT32 val) +{ + ACPI_BUFFER buf; + char str[1024]; + + buf.Length = sizeof (str); + buf.Pointer = str; + AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf); + cmn_err(CE_NOTE, "AcpiNotify(%s, 0x%02x)", str, val); +} +#endif /* DEBUG */ + +static void +acpi_drv_gen_sysevent(struct acpi_drv_dev *devp, char *ev, uint32_t val) +{ + nvlist_t *attr_list = NULL; + int err; + char pathname[MAXPATHLEN]; + + /* Allocate and build sysevent attribute list */ + err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, DDI_NOSLEEP); + if (err != 0) { + ACPI_DRV_DBG(CE_WARN, NULL, + "cannot allocate memory for sysevent attributes\n"); + return; + } + + /* Add attributes */ + err = nvlist_add_string(attr_list, PWRCTL_DEV_HID, devp->hid); + if (err != 0) { + ACPI_DRV_DBG(CE_WARN, NULL, + "Failed to add attr [%s] for %s/%s event", + PWRCTL_DEV_HID, EC_PWRCTL, ev); + nvlist_free(attr_list); + return; + } + + err = nvlist_add_string(attr_list, PWRCTL_DEV_UID, devp->uid); + if (err != 0) { + ACPI_DRV_DBG(CE_WARN, NULL, + "Failed to add attr [%s] for %s/%s event", + PWRCTL_DEV_UID, EC_PWRCTL, ev); + nvlist_free(attr_list); + return; + } + + err = nvlist_add_uint32(attr_list, PWRCTL_DEV_INDEX, devp->index); + if (err != 0) { + ACPI_DRV_DBG(CE_WARN, NULL, + "Failed to add attr [%s] for %s/%s event", + PWRCTL_DEV_INDEX, EC_PWRCTL, ev); + nvlist_free(attr_list); + return; + } + + (void) ddi_pathname(acpi_drv_dip, pathname); + err = nvlist_add_string(attr_list, PWRCTL_DEV_PHYS_PATH, pathname); + if (err != 0) { + ACPI_DRV_DBG(CE_WARN, NULL, + "Failed to add attr [%s] for %s/%s event", + PWRCTL_DEV_PHYS_PATH, EC_PWRCTL, ev); + nvlist_free(attr_list); + return; + } + + if (strcmp(ev, ESC_PWRCTL_WARN) && strcmp(ev, ESC_PWRCTL_LOW)) { + goto finish; + } + + err = nvlist_add_uint32(attr_list, PWRCTL_CHARGE_LEVEL, val); + if (err != 0) { + ACPI_DRV_DBG(CE_WARN, NULL, + "Failed to add attr [%s] for %s/%s event", + PWRCTL_CHARGE_LEVEL, EC_PWRCTL, ev); + nvlist_free(attr_list); + return; + } + +finish: + ACPI_DRV_DBG(CE_NOTE, NULL, "SysEv(%s, %s.%s, %d)", + ev, devp->hid, devp->uid, val); + /* Generate/log sysevent */ + err = ddi_log_sysevent(acpi_drv_dip, DDI_VENDOR_SUNW, EC_PWRCTL, + ev, attr_list, NULL, DDI_NOSLEEP); +#ifdef DEBUG + if (err != DDI_SUCCESS) { + ACPI_DRV_DBG(CE_WARN, NULL, + "cannot log sysevent, err code %x\n", err); + } +#endif + + nvlist_free(attr_list); +} + +static int +acpi_drv_obj_copy(ACPI_OBJECT *op, char *bp, struct obj_desc *dp) +{ + ACPI_OBJECT *ep; + char *fp; + + ep = &op->Package.Elements[0]; + for (; dp->offset != -1; dp++) { + fp = bp + dp->offset; + if (dp->type == ACPI_TYPE_INTEGER && + ep->Type == dp->type) { +#ifdef DEBUG + if (dp->size <= 4) { + ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %u", + dp->name, + (uint32_t)ep->Integer.Value); + } else { +#ifdef _LP64 + ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %lu", + dp->name, (uint64_t)ep->Integer.Value); + } +#else + ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %llu", + dp->name, (uint64_t)ep->Integer.Value); + } +#endif /* _LP64 */ +#endif /* DEBUG */ + *(uint32_t *)fp = ep->Integer.Value; + } else if (dp->type == ACPI_TYPE_STRING && + ep->Type == dp->type) { + ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: \"%s\"", + dp->name, ep->String.Pointer); + (void) strncpy(fp, ep->String.Pointer, dp->size); + } else if (dp->type == ACPI_TYPE_STRING && + ep->Type == ACPI_TYPE_BUFFER) { +#ifdef DEBUG + int len; + char buf[MAXNAMELEN + 1]; + + len = (MAXNAMELEN < ep->Buffer.Length) ? + MAXNAMELEN : ep->Buffer.Length; + bcopy(ep->Buffer.Pointer, buf, len); + buf[len] = 0; + ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: [%d] \"%s\"", + dp->name, len, buf); +#endif + + ASSERT(MAXNAMELEN >= ep->Buffer.Length); + bcopy(ep->Buffer.Pointer, fp, ep->Buffer.Length); + } else { + ACPI_DRV_DBG(CE_WARN, NULL, + "Bad field at offset %d: type %d", + dp->offset, ep->Type); + if (dp->type != ACPI_TYPE_STRING) { + return (ACPI_DRV_ERR); + } + } + ep++; + } + + return (ACPI_DRV_OK); +} + +/* + * Returns the current power source devices. Used for the AC adapter and is + * located under the AC adapter object in name space. Used to determine if + * system is running off the AC adapter. This will report that the system is + * not running on the AC adapter if any of the batteries in the system is + * being forced to discharge through _BMC. + * + * Return value: + * 0 -- Off-line, ie. battery supplying system power + * 1 -- On-line, ie. AC supplying system power + * -1 -- Unknown, some error ocurred. + * Note: It will also update the driver ac state. + */ +static int +acpi_drv_get_psr(struct acpi_drv_ac_state *acp) +{ + struct acpi_drv_dev *devp = &acp->dev; + int ac; + + if (!devp->valid) { + ACPI_DRV_DBG(CE_WARN, NULL, "device not valid"); + return (-1); + } + + if (acpica_eval_int(devp->hdl, "_PSR", &ac) == AE_OK) { + ACPI_DRV_DBG(CE_NOTE, devp, "_PSR = %d", ac); + devp->present = ac; + } else { + ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _PSR failed"); + devp->present = -1; + } + + return (ac); +} + +/* + * For most systems, the _STA for this device will always + * return a value with bits 0-3 set and will toggle bit 4 + * to indicate the actual presence of a battery. + * + * Return value: + * 0 -- battery not present + * 1 -- battery present + * -1 -- Unknown, some error ocurred. + * Note: It will also update the driver cbat state. + */ +static int +acpi_drv_get_sta(struct acpi_drv_cbat_state *bp) +{ + struct acpi_drv_dev *devp = &bp->dev; + int val; + + if (!devp->valid) { + ACPI_DRV_DBG(CE_WARN, NULL, "device not valid"); + return (-1); + } + + if (acpica_eval_int(devp->hdl, "_STA", &val) == AE_OK) { + ACPI_DRV_DBG(CE_NOTE, devp, "_STA = 0x%x", val); + devp->present = ((val & STA_FLAG_BATT_PRESENT) != 0); + } else { + ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _STA failed"); + devp->present = -1; + } + + return (val); +} + +static int +acpi_drv_update_bif(struct acpi_drv_cbat_state *bp) +{ + ACPI_BUFFER buf; + ACPI_OBJECT *objp; + + /* BIF is only available when battery plugged */ + ASSERT(bp->dev.present != 0); + + /* Update internal BIF cache */ + bp->bat_bifok = ACPI_DRV_NTF_UNKNOWN; + + buf.Length = ACPI_ALLOCATE_BUFFER; + if (ACPI_FAILURE(AcpiEvaluateObjectTyped(bp->dev.hdl, "_BIF", + NULL, &buf, ACPI_TYPE_PACKAGE))) { + ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _BIF failed"); + return (ACPI_DRV_ERR); + } + + objp = buf.Pointer; + ACPI_DRV_DBG(CE_NOTE, &bp->dev, "get _BIF"); + if (acpi_drv_obj_copy(objp, (char *)&bp->bif_cache, bif_desc) == + ACPI_DRV_ERR) { + AcpiOsFree(objp); + return (ACPI_DRV_ERR); + } + AcpiOsFree(objp); + bp->bat_bifok = ACPI_DRV_NTF_OK; + return (ACPI_DRV_OK); +} + +static int +acpi_drv_update_bst(struct acpi_drv_cbat_state *bp) +{ + ACPI_BUFFER buf; + ACPI_OBJECT *objp; + + /* BST is only available when battery plugged */ + ASSERT(bp->dev.present != 0); + + /* Update internal BST cache */ + bp->bat_bstok = ACPI_DRV_NTF_UNKNOWN; + + buf.Length = ACPI_ALLOCATE_BUFFER; + if (ACPI_FAILURE(AcpiEvaluateObjectTyped(bp->dev.hdl, "_BST", + NULL, &buf, ACPI_TYPE_PACKAGE))) { + ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _BST failed"); + return (ACPI_DRV_ERR); + } + + objp = buf.Pointer; + ACPI_DRV_DBG(CE_NOTE, &bp->dev, "get _BST"); + if (acpi_drv_obj_copy(objp, (char *)&bp->bst_cache, bst_desc) == + ACPI_DRV_ERR) { + AcpiOsFree(objp); + return (ACPI_DRV_ERR); + } + AcpiOsFree(objp); + + if (bp->bst_cache.bst_rate == 0) { + bp->bst_cache.bst_state &= ~(ACPI_DRV_BST_CHARGING | + ACPI_DRV_BST_DISCHARGING); + } + bp->bat_bstok = ACPI_DRV_NTF_OK; + return (ACPI_DRV_OK); +} + +/* + * Return value: + * 1 -- device On-line + * 0 -- device Off-line + * -1 -- Unknown, some error ocurred. + */ +static int +acpi_drv_dev_present(struct acpi_drv_dev *devp) +{ + if (!devp->valid) { + ACPI_DRV_DBG(CE_WARN, NULL, "device not valid"); + return (-1); + } + + ASSERT(devp->type != ACPI_DRV_TYPE_UNKNOWN); + + /* Update the device state */ + if (devp->present == -1) { + if (devp->type == ACPI_DRV_TYPE_AC) { + (void) acpi_drv_get_psr((struct acpi_drv_ac_state *) + devp); + } else if (devp->type == ACPI_DRV_TYPE_CBAT) { + (void) acpi_drv_get_sta((struct acpi_drv_cbat_state *) + devp); + } + } + + return (devp->present); +} + +/* + * Check if the device p existance state has changed. + * Return value: + * 1 -- changed + * 0 -- no change + * -1 -- unknown + */ +static int +acpi_drv_update_present(struct acpi_drv_dev *p) +{ + int old_present = p->present; + int new_present; + + ASSERT(p && p->valid); + + p->present = -1; + new_present = acpi_drv_dev_present(p); + if (new_present == -1) { + return (-1); + } + if (new_present != old_present) { + return (1); + } + return (0); +} + +static void +acpi_drv_set_psr(struct acpi_drv_dev *p) +{ + acpi_drv_psr_devp = p; + if (p != NULL) { + ACPI_DRV_DBG(CE_NOTE, p, "psr = ."); + acpi_drv_psr_type = p->type; + } else { + ACPI_DRV_DBG(CE_NOTE, p, "psr = ?"); + acpi_drv_psr_type = ACPI_DRV_TYPE_UNKNOWN; + } +} + +/* + * OSPM can determine independent warning and low battery + * capacity values based on the OEM-designed levels, but + * cannot set these values lower than the OEM-designed values. + */ +static int +acpi_drv_set_warn(acpi_drv_warn_t *bwp) +{ + uint32_t warn, low; + + warn = acpi_drv_syn_last_cap * bwp->bw_charge_warn / 100; + low = acpi_drv_syn_last_cap * bwp->bw_charge_low / 100; + + /* Update internal state */ + if (bwp->bw_enabled) { + if (low >= warn || warn < acpi_drv_syn_oem_warn_cap || + low < acpi_drv_syn_oem_low_cap) { + ACPI_DRV_DBG(CE_WARN, NULL, "charge level error"); + return (EINVAL); + } + + ACPI_DRV_DBG(CE_NOTE, NULL, "set warn: warn=%d low=%d", warn, + low); + + acpi_drv_syn_warn_per = bwp->bw_charge_warn; + acpi_drv_syn_low_per = bwp->bw_charge_low; + acpi_drv_syn_warn_cap = warn; + acpi_drv_syn_low_cap = low; + acpi_drv_warn_enabled = 1; + } else { + acpi_drv_warn_enabled = 0; + } + + return (0); +} + +/* + * Update information for the synthesis battery + * + * Note: Sometimes the value to be returned from _BST or _BIF will be + * temporarily unknown. In this case, the method may return the value + * 0xFFFFFFFF as a placeholder. When the value becomes known, the + * appropriate notification (0x80 for _BST or 0x81 for BIF) should be + * issued, in like manner to any other change in the data returned by + * these methods. This will cause OSPM to re-evaluate the method obtaining + * the correct data value. + */ +static void +acpi_drv_update_cap(int bif_changed) +{ + struct acpi_drv_cbat_state *bp; + + if (bif_changed != 0) { + acpi_drv_syn_oem_warn_cap = 0xffffffff; + acpi_drv_syn_oem_low_cap = 0xffffffff; + acpi_drv_syn_last_cap = 0xffffffff; + } + acpi_drv_syn_last_level = acpi_drv_syn_rem_cap; + acpi_drv_syn_rem_cap = 0xffffffff; /* initially unknown */ + + for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM]; + bp++) { + if (bp->dev.valid) { + /* Escape the empty bays */ + if (acpi_drv_cbat_present(bp) <= 0) { + continue; + } + + if (bif_changed != 0 && + bp->bat_bifok == ACPI_DRV_NTF_OK) { + acpi_bif_t *bif; + + bif = &bp->bif_cache; + + if (acpi_drv_syn_last_cap == 0xffffffff) { + acpi_drv_syn_last_cap = 0; + } + acpi_drv_syn_last_cap += bif->bif_last_cap; + + if (bif->bif_warn_cap == 0xffffffff || + bif->bif_low_cap == 0xffffffff) { + ACPI_DRV_DBG(CE_WARN, &bp->dev, + "BIF value " + "invalid, warn_cap=0x%x " + "low_cap=0x%x", bif->bif_warn_cap, + bif->bif_low_cap); + continue; + } + if (acpi_drv_syn_oem_warn_cap == 0xffffffff) { + acpi_drv_syn_oem_warn_cap = 0; + } + if (acpi_drv_syn_oem_low_cap == 0xffffffff) { + acpi_drv_syn_oem_low_cap = 0; + } + + /* + * Use the highest level as the synthesis + * level. + */ + if (bif->bif_warn_cap > + acpi_drv_syn_oem_warn_cap) { + acpi_drv_syn_oem_low_cap = + bif->bif_low_cap; + acpi_drv_syn_oem_warn_cap = + bif->bif_warn_cap; + } + } +#ifdef DEBUG + else if (bif_changed) { + ACPI_DRV_DBG(CE_NOTE, &bp->dev, + "BIF not ready"); + } +#endif + + if (bp->bat_bstok == ACPI_DRV_NTF_OK) { + acpi_bst_t *bst; + + bst = &bp->bst_cache; + + /* + * Batteries that are rechargeable and are in + * the discharging state are required to return + * a valid Battery Present Rate value. + * 0xFFFFFFFF - Unknown rate/capacity + */ + if (bst->bst_rem_cap == 0xffffffff) { + ACPI_DRV_DBG(CE_WARN, &bp->dev, + "BST value invalid, " + "rate=0x%x cap=0x%x", + bst->bst_rate, bst->bst_rem_cap); + continue; + } + + if (acpi_drv_syn_rem_cap == 0xffffffff) { + acpi_drv_syn_rem_cap = 0; + } + acpi_drv_syn_rem_cap += bst->bst_rem_cap; + /* Check for overflow */ + ASSERT(acpi_drv_syn_rem_cap >= + bst->bst_rem_cap); + } +#ifdef DEBUG + else { + ACPI_DRV_DBG(CE_NOTE, &bp->dev, + "BST not ready"); + } +#endif + } + } + + ACPI_DRV_DBG(CE_NOTE, NULL, "syn_cap: %d syn_oem_warn: %d " + "syn_oem_low: %d", acpi_drv_syn_rem_cap, acpi_drv_syn_oem_warn_cap, + acpi_drv_syn_oem_low_cap); +} + +static struct acpi_drv_cbat_state * +acpi_drv_idx2cbat(int idx) +{ + if (idx >= ACPI_DRV_MAX_BAT_NUM) { + return (NULL); + } + return (&acpi_drv_cbat[idx]); +} + +static struct acpi_drv_ac_state * +acpi_drv_idx2ac(int idx) +{ + if (idx >= ACPI_DRV_MAX_AC_NUM) { + return (NULL); + } + return (&acpi_drv_ac[idx]); +} + +/*ARGSUSED*/ +static void +acpi_drv_cbat_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx) +{ + struct acpi_drv_cbat_state *bp = ctx; + struct acpi_drv_dev *devp = &bp->dev; + int bif_changed; + uint32_t eval; + char *ev; + acpi_bst_t *bst; + + mutex_enter(&acpi_drv_mutex); + ACPI_DRV_PRT_NOTIFY(hdl, val); + + switch (val) { + /* + * BST has changed + * Whenever the Battery State value changes, the + * system will generate an SCI to notify the OS. + * + * Note: trip point is not used to implement the + * warning levels. + */ + case 0x80: + /* + * We always get 0x80 and 0x81 at battery plug/unplug, + * but 0x80 may come first. In case that situation, we have + * to update battery present state here too to update bst + * correctly. + */ + bif_changed = acpi_drv_update_present(devp); + + /* Omit events sent by empty battery slot */ + if (devp->present == 0) { + break; + } + + if (acpi_drv_update_bst(bp) != ACPI_DRV_OK) { + break; + } + acpi_drv_update_cap(bif_changed); + + bst = &bp->bst_cache; + eval = bst->bst_rem_cap; + + /* + * Keep tracking the current power source device + * + * Note: Even no battery plugged, some system + * send out 0x80 ACPI event. So make sure the battery + * is present first. + */ + if (devp->present == 0) { + if (acpi_drv_psr_devp == devp) { + acpi_drv_set_psr(NULL); + } + break; + } + if (bst->bst_state & BST_FLAG_DISCHARGING) { + acpi_drv_set_psr(devp); + } + /* + * The Critical battery state indicates that all + * available batteries are discharged and do not + * appear to be able to supply power to run the + * system any longer. When this occurs, the OS + * should attempt to perform an emergency shutdown. + * Right now we do not shutdown. This would + * need some discussion first since it could be + * controversial. + */ +#ifdef DEBUG + if (bst->bst_state & BST_FLAG_CRITICAL) { + ACPI_DRV_DBG(CE_WARN, devp, "BST_FLAG_CRITICAL set"); + + /* + * BST_FLAG_CRITICAL may set even with AC, + * plugged, when plug/unplug battery. Check + * to avoid erroneous shutdown. + */ + if (acpi_drv_psr_devp == devp && + bst->bst_rem_cap != 0xffffffff) { + ACPI_DRV_DBG(CE_WARN, NULL, + "Battery in critical state"); + } + } else +#endif + if (acpi_drv_warn_enabled && + (bst->bst_state & BST_FLAG_DISCHARGING)) { + /* + * This value is an estimation of the amount of + * energy or battery capacity required by the + * system to transition to any supported sleeping + * state. When the OS detects that the total + * available battery capacity is less than this + * value, it will transition the system to a user + * defined system state (S1-S5). + */ + if (acpi_drv_syn_last_level > acpi_drv_syn_low_cap && + acpi_drv_syn_rem_cap <= acpi_drv_syn_low_cap) { + acpi_drv_gen_sysevent(devp, ESC_PWRCTL_LOW, + eval); + /* + * When the total available energy (mWh) or capacity + * (mAh) in the batteries falls below this level, + * the OS will notify the user through the UI. + */ + } else if (acpi_drv_syn_last_level > + acpi_drv_syn_warn_cap && + acpi_drv_syn_rem_cap <= acpi_drv_syn_warn_cap) { + acpi_drv_gen_sysevent(devp, ESC_PWRCTL_WARN, + eval); + } + } + + acpi_drv_gen_sysevent(devp, ESC_PWRCTL_STATE_CHANGE, 0); + pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS); + break; + + /* BIF has changed */ + case 0x81: + /* + * Note: Do not eliminate multiple ADD/REMOVE here, + * because they may corresponding to different batterys. + */ + (void) acpi_drv_update_present(devp); + if (devp->present == 1) { + if (acpi_drv_update_bif(bp) != ACPI_DRV_OK) { + break; + } + } + + acpi_drv_update_cap(1); + + eval = devp->present; + ev = eval ? ESC_PWRCTL_ADD : ESC_PWRCTL_REMOVE; + acpi_drv_gen_sysevent(devp, ev, 0); + pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS); + break; + + case 0x82: + default: + break; + } + + mutex_exit(&acpi_drv_mutex); +} + +static int +acpi_drv_update_lid(struct acpi_drv_dev *p) +{ + struct acpi_drv_lid_state *lp = (struct acpi_drv_lid_state *)p; + + if (acpica_eval_int(p->hdl, "_LID", &lp->state) == AE_OK) { + lp->state_ok = ACPI_DRV_NTF_OK; + return (ACPI_DRV_OK); + } + return (ACPI_DRV_ERR); +} + +/*ARGSUSED*/ +static void +acpi_drv_ac_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx) +{ + struct acpi_drv_ac_state *acp = ctx; + struct acpi_drv_dev *devp = &acp->dev; + int old_present; + char *ev; + int eval; + + ACPI_DRV_PRT_NOTIFY(hdl, val); + if (val != 0x80) { + return; + } + + mutex_enter(&acpi_drv_mutex); + /* + * Note: if unplug and then quickly plug back, two ADD + * events will be generated. + */ + old_present = devp->present; + eval = acpi_drv_get_psr(acp); + + /* Eliminate redundant events */ + if (eval != -1 && eval != old_present) { + /* Keep tracking the current power source device */ + if (eval == 1) { + ev = ESC_PWRCTL_ADD; + acpi_drv_set_psr(devp); + } else { + ev = ESC_PWRCTL_REMOVE; + /* If AC was supplying the power, it's not now */ + if (acpi_drv_psr_devp == devp) { + acpi_drv_set_psr(NULL); + } + } + + acpi_drv_gen_sysevent(devp, ev, 0); + pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS); + } + + mutex_exit(&acpi_drv_mutex); +} + +static void +acpi_drv_lid_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx) +{ + struct acpi_drv_lid_state *p = ctx; + + ACPI_DRV_PRT_NOTIFY(hdl, val); + if (val == 0x80) { + mutex_enter(&acpi_drv_mutex); + if (acpi_drv_update_lid(&p->dev) == ACPI_DRV_OK) { + acpi_drv_gen_sysevent(&p->dev, p->state ? + ESC_PWRCTL_ADD : ESC_PWRCTL_REMOVE, 0); + } + mutex_exit(&acpi_drv_mutex); + } +} + +static int +acpi_drv_obj_init(struct acpi_drv_dev *p) +{ + ACPI_DEVICE_INFO *info; + ACPI_BUFFER buf; + ACPI_NOTIFY_HANDLER ntf_handler = NULL; + ACPI_STATUS ret; + + ASSERT(p != NULL && p->hdl != NULL); + + p->valid = 0; + + /* Info size is variable depending on existance of _CID */ + buf.Length = ACPI_ALLOCATE_BUFFER; + ret = AcpiGetObjectInfo(p->hdl, &buf); + if (ACPI_FAILURE(ret)) { + ACPI_DRV_DBG(CE_WARN, NULL, + "AcpiGetObjectInfo() fail: %d", (int32_t)ret); + return (ACPI_DRV_ERR); + } + + info = buf.Pointer; + if ((info->Valid & ACPI_VALID_HID) == 0) { + ACPI_DRV_DBG(CE_WARN, NULL, + "AcpiGetObjectInfo(): _HID not available"); + (void) strncpy(p->uid, "\0", 9); + } else { + (void) strncpy(p->hid, info->HardwareId.Value, 9); + } + (void) strncpy(p->hid, info->HardwareId.Value, 9); + + /* + * This object is optional, but is required when the device + * has no other way to report a persistent unique device ID. + */ + if ((info->Valid & ACPI_VALID_UID) == 0) { + ACPI_DRV_DBG(CE_WARN, NULL, + "AcpiGetObjectInfo(): _UID not available"); + /* Use 0 as the default _UID */ + (void) strncpy(p->uid, "\0", 9); + } else { + (void) strncpy(p->uid, info->UniqueId.Value, 9); + } + + p->valid = 1; + + if (strcmp(p->hid, ACPI_DEVNAME_CBAT) == 0) { + struct acpi_drv_cbat_state *bp = + (struct acpi_drv_cbat_state *)p; + + p->type = ACPI_DRV_TYPE_CBAT; + p->index = nbat - 1; + + /* Update device present state */ + (void) acpi_drv_update_present(p); + if (p->present) { + (void) acpi_drv_update_bif(bp); + (void) acpi_drv_update_bst(bp); + + /* Init the current power source */ + if (bp->bst_cache.bst_state & BST_FLAG_DISCHARGING) { + acpi_drv_set_psr(p); + } + } + ntf_handler = acpi_drv_cbat_notify; + ACPI_DRV_DBG(CE_NOTE, p, "battery %s", + (p->present ? "present" : "absent")); + } else if (strcmp(p->hid, ACPI_DEVNAME_AC) == 0) { + p->type = ACPI_DRV_TYPE_AC; + p->index = nac - 1; + + /* Update device present state */ + (void) acpi_drv_update_present(p); + if (p->present) { + /* Init the current power source */ + acpi_drv_set_psr(p); + } + ntf_handler = acpi_drv_ac_notify; + ACPI_DRV_DBG(CE_NOTE, p, "AC %s", + (p->present ? "on-line" : "off-line")); + } else if (strcmp(p->hid, ACPI_DEVNAME_SBAT) == 0) { + p->type = ACPI_DRV_TYPE_SBAT; + ACPI_DRV_DBG(CE_NOTE, p, "added"); + } else if (strcmp(p->hid, ACPI_DEVNAME_LID) == 0) { + p->type = ACPI_DRV_TYPE_LID; + lid.state_ok = ACPI_DRV_NTF_UNKNOWN; + (void) acpi_drv_update_lid(p); + ntf_handler = acpi_drv_lid_notify; + ACPI_DRV_DBG(CE_NOTE, p, "added"); + } else if (info->Valid & ACPI_VALID_ADR) { + p->adr = info->Address; + if (p->type == ACPI_DRV_TYPE_DISPLAY) { + /* Enable display control by OS */ + display.mode = ACPI_DRV_DOS_SWITCH_OS_EVENT | + ACPI_DRV_DOS_BRIGHT_OS; + acpi_drv_display_set_mode(&display, display.mode); + } else { + p->index = noutput - 1; + if (acpi_drv_output_init(p->hdl, p) == ACPI_DRV_ERR) { + p->valid = 0; + AcpiOsFree(info); + return (ACPI_DRV_ERR); + } + ntf_handler = acpi_drv_output_notify; + p->type = ACPI_DRV_TYPE_OUTPUT; + } + } else { + ACPI_DRV_DBG(CE_NOTE, p, "unknown device"); + p->valid = 0; + } + + /* Register ACPI battery related events */ + if (ntf_handler != NULL) { + if (ACPI_FAILURE(AcpiInstallNotifyHandler(p->hdl, + ACPI_ALL_NOTIFY, ntf_handler, p))) { + ACPI_DRV_DBG(CE_NOTE, NULL, + "Notify handler for %s.%s install failed", + p->hid, p->uid); + return (ACPI_DRV_ERR); + } + } + + AcpiOsFree(info); + return (ACPI_DRV_OK); +} + +/*ARGSUSED*/ +static ACPI_STATUS +acpi_drv_find_cb(ACPI_HANDLE ObjHandle, UINT32 NestingLevel, void *Context, + void **ReturnValue) +{ + struct acpi_drv_dev *devp = (struct acpi_drv_dev *)Context; + + if (devp == &acpi_drv_cbat[0].dev) { + struct acpi_drv_cbat_state *bp; + + if (nbat == ACPI_DRV_MAX_BAT_NUM) { + ACPI_DRV_DBG(CE_WARN, NULL, + "Need to support more batteries: " + "BATTERY_MAX = %d", ACPI_DRV_MAX_BAT_NUM); + return (AE_LIMIT); + } + bp = &acpi_drv_cbat[nbat++]; + devp = (struct acpi_drv_dev *)bp; + } else if (devp == &acpi_drv_ac[0].dev) { + struct acpi_drv_ac_state *ap; + + if (nac == ACPI_DRV_MAX_AC_NUM) { + ACPI_DRV_DBG(CE_WARN, NULL, "Need to support more ACs: " + "AC_MAX = %d", ACPI_DRV_MAX_AC_NUM); + return (AE_LIMIT); + } + ap = &acpi_drv_ac[nac++]; + devp = (struct acpi_drv_dev *)ap; + } else if (devp == &lid.dev) { + struct acpi_drv_lid_state *lp; + + lp = &lid; + devp = (struct acpi_drv_dev *)lp; + } else if (devp == &outputs[0].dev) { + int adr = 0; + ACPI_BUFFER buf1 = {ACPI_ALLOCATE_BUFFER, NULL}; + ACPI_BUFFER buf2; + char str[256]; + ACPI_HANDLE ohl = NULL; + struct acpi_drv_display_state *dp; + struct acpi_drv_output_state *op; + + /* + * Reduce the search by checking for support of _ADR + * method. + */ + if (acpica_eval_int(ObjHandle, "_ADR", &adr) != AE_OK) { + return (AE_OK); + } + + /* + * Find the display device. + */ + if (ACPI_SUCCESS(AcpiEvaluateObjectTyped(ObjHandle, "_DOD", + NULL, &buf1, ACPI_TYPE_PACKAGE))) { + AcpiOsFree(buf1.Pointer); + + buf2.Pointer = str; + buf2.Length = sizeof (str); + if (!ACPI_FAILURE(AcpiGetName(ObjHandle, + ACPI_FULL_PATHNAME, &buf2))) { + ACPI_DRV_DBG(CE_NOTE, NULL, + "_DOD Supported Pathname=%s\n", + (char *)buf2.Pointer); + } + + dp = &display; + devp = (struct acpi_drv_dev *)dp; + devp->hdl = ObjHandle; + devp->index = 1; + devp->type = ACPI_DRV_TYPE_DISPLAY; + (void) acpi_drv_obj_init(devp); + + /* + * Find the output devices. + */ + while (ACPI_SUCCESS(AcpiGetNextObject(ACPI_TYPE_DEVICE, + ObjHandle, ohl, &ohl))) { + op = &outputs[noutput++]; + devp = (struct acpi_drv_dev *)op; + devp->hdl = ohl; + (void) acpi_drv_obj_init(devp); + } + dp->noutput = noutput; + } + return (AE_OK); + } else { + ACPI_DRV_DBG(CE_WARN, NULL, "acpi_drv_find_cb(): " + "Unknown device"); + return (AE_ERROR); + } + + devp->hdl = ObjHandle; + + /* Try to get as many working objs as possible */ + (void) acpi_drv_obj_init(devp); + return (AE_OK); +} + +static int +acpi_drv_acpi_init() +{ + int *retp; + + /* Check to see if ACPI CA services are available */ + if (AcpiSubsystemStatus() != AE_OK) { + ACPI_DRV_DBG(CE_WARN, NULL, "ACPI CA not ready"); + return (ACPI_DRV_ERR); + } + + /* Init Control Method Batterys */ + if (ACPI_FAILURE(AcpiGetDevices(ACPI_DEVNAME_CBAT, acpi_drv_find_cb, + acpi_drv_cbat, (void *)&retp))) { + return (ACPI_DRV_ERR); + } + + if (nbat == 0) { + return (ACPI_DRV_ERR); + } + + /* Init AC */ + if (ACPI_FAILURE(AcpiGetDevices(ACPI_DEVNAME_AC, acpi_drv_find_cb, + acpi_drv_ac, (void *)&retp))) { + return (ACPI_DRV_ERR); + } + + /* Init LID */ + if (ACPI_FAILURE(AcpiGetDevices(ACPI_DEVNAME_LID, acpi_drv_find_cb, + &lid, (void *)&retp))) { + return (ACPI_DRV_ERR); + } + + /* Init Output Devices */ + if (ACPI_FAILURE(AcpiGetDevices(NULL, acpi_drv_find_cb, + outputs, (void *)&retp))) { + return (ACPI_DRV_ERR); + } + + /* Init Smart Battery */ + if (ACPI_FAILURE(AcpiGetDevices(ACPI_DEVNAME_SBAT, acpi_drv_find_cb, + &acpi_drv_sbat, (void *)&retp))) { + return (ACPI_DRV_ERR); + } + + acpi_drv_update_cap(1); + + return (ACPI_DRV_OK); +} + +static void +acpi_drv_acpi_fini(void) +{ + int i; + struct acpi_drv_cbat_state *bp; + struct acpi_drv_output_state *op; + + for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM]; + bp++) { + if (bp->dev.valid) { + AcpiRemoveNotifyHandler(bp->dev.hdl, ACPI_DEVICE_NOTIFY, + acpi_drv_cbat_notify); + } + } + for (i = 0; i < nac; i++) { + AcpiRemoveNotifyHandler(acpi_drv_ac[i].dev.hdl, + ACPI_DEVICE_NOTIFY, acpi_drv_ac_notify); + } + AcpiRemoveNotifyHandler(lid.dev.hdl, ACPI_DEVICE_NOTIFY, + acpi_drv_lid_notify); + for (op = &outputs[0]; op < &outputs[ACPI_DRV_MAX_OUTPUT_NUM]; op++) { + if (op->dev.valid) { + if (op->levels) { + kmem_free(op->levels, + op->nlev * sizeof (uint32_t)); + } + AcpiRemoveNotifyHandler(op->dev.hdl, ACPI_DEVICE_NOTIFY, + acpi_drv_output_notify); + } + } +} + +/*ARGSUSED*/ +static int +acpi_drv_kstat_power_update(kstat_t *ksp, int flag) +{ + if (flag == KSTAT_WRITE) { + return (EACCES); + } + + mutex_enter(&acpi_drv_mutex); + if (acpi_drv_psr_type == ACPI_DRV_TYPE_UNKNOWN) { + mutex_exit(&acpi_drv_mutex); + return (EIO); + } + kstat_named_setstr(&acpi_drv_power_kstat.acpi_drv_power, + acpi_drv_psr_type == ACPI_DRV_TYPE_AC ? AC : BATTERY); + acpi_drv_power_kstat.acpi_drv_supported_battery_count.value.ui32 = + (uint32_t)nbat; + mutex_exit(&acpi_drv_mutex); + + return (0); +} + +/*ARGSUSED*/ +static int +acpi_drv_kstat_warn_update(kstat_t *ksp, int flag) +{ + if (flag == KSTAT_WRITE) { + int ret = 0; + acpi_drv_warn_t bw; + acpi_drv_warn_kstat_t kbw; + + kbw = *(acpi_drv_warn_kstat_t *)acpi_drv_warn_ksp->ks_data; + + mutex_enter(&acpi_drv_mutex); + bw.bw_enabled = kbw.acpi_drv_bw_enabled.value.ui32; + bw.bw_charge_warn = kbw.acpi_drv_bw_charge_warn.value.ui32; + bw.bw_charge_low = kbw.acpi_drv_bw_charge_low.value.ui32; + ret = acpi_drv_set_warn(&bw); + mutex_exit(&acpi_drv_mutex); + + return (ret); + } else { + acpi_drv_warn_kstat_t *wp = &acpi_drv_warn_kstat; + + mutex_enter(&acpi_drv_mutex); + wp->acpi_drv_bw_enabled.value.ui32 = acpi_drv_warn_enabled; + wp->acpi_drv_bw_charge_warn.value.ui32 = acpi_drv_syn_warn_per; + wp->acpi_drv_bw_charge_low.value.ui32 = acpi_drv_syn_low_per; + mutex_exit(&acpi_drv_mutex); + + return (0); + } +} + +static int +acpi_drv_kstat_bif_update(kstat_t *ksp, int flag) +{ + struct acpi_drv_cbat_state *bp; + acpi_bif_t *bif; + acpi_drv_bif_kstat_t *kp; + + if (flag == KSTAT_WRITE) { + return (EACCES); + } + + bp = (struct acpi_drv_cbat_state *)ksp->ks_private; + mutex_enter(&acpi_drv_mutex); + + if (acpi_drv_cbat_present(bp) <= 0) { + mutex_exit(&acpi_drv_mutex); + return (ENXIO); + } + + bzero(&bif, sizeof (bif)); + if (acpi_drv_update_bif(bp) != ACPI_DRV_OK) { + mutex_exit(&acpi_drv_mutex); + return (ENXIO); + } + + bif = &bp->bif_cache; + kp = &acpi_drv_bif_kstat; + + /* Update BIF */ + kp->acpi_drv_bif_unit.value.ui32 = bif->bif_unit; + kp->acpi_drv_bif_design_cap.value.ui32 = bif->bif_design_cap; + kp->acpi_drv_bif_last_cap.value.ui32 = bif->bif_last_cap; + kp->acpi_drv_bif_tech.value.ui32 = bif->bif_tech; + kp->acpi_drv_bif_voltage.value.ui32 = bif->bif_voltage; + kp->acpi_drv_bif_warn_cap.value.ui32 = bif->bif_warn_cap; + kp->acpi_drv_bif_low_cap.value.ui32 = bif->bif_low_cap; + kp->acpi_drv_bif_gran1_cap.value.ui32 = bif->bif_gran1_cap; + kp->acpi_drv_bif_gran2_cap.value.ui32 = bif->bif_gran2_cap; + + kstat_named_setstr(&kp->acpi_drv_bif_model, bif->bif_model); + kstat_named_setstr(&kp->acpi_drv_bif_serial, bif->bif_serial); + kstat_named_setstr(&kp->acpi_drv_bif_type, bif->bif_type); + kstat_named_setstr(&kp->acpi_drv_bif_oem_info, bif->bif_oem_info); + + mutex_exit(&acpi_drv_mutex); + return (0); +} + +static int +acpi_drv_kstat_bst_update(kstat_t *ksp, int flag) +{ + struct acpi_drv_cbat_state *bp; + acpi_bst_t *bst; + acpi_drv_bst_kstat_t *kp; + + if (flag == KSTAT_WRITE) { + return (EACCES); + } + + bp = (struct acpi_drv_cbat_state *)ksp->ks_private; + mutex_enter(&acpi_drv_mutex); + + if (acpi_drv_cbat_present(bp) <= 0) { + mutex_exit(&acpi_drv_mutex); + return (ENXIO); + } + + bzero(&bst, sizeof (bst)); + if (acpi_drv_update_bst(bp) != ACPI_DRV_OK) { + mutex_exit(&acpi_drv_mutex); + return (ENXIO); + } + + bst = &bp->bst_cache; + kp = &acpi_drv_bst_kstat; + + /* Update BST */ + kp->acpi_drv_bst_state.value.ui32 = bst->bst_state; + kp->acpi_drv_bst_rate.value.ui32 = bst->bst_rate; + kp->acpi_drv_bst_rem_cap.value.ui32 = bst->bst_rem_cap; + kp->acpi_drv_bst_voltage.value.ui32 = bst->bst_voltage; + + mutex_exit(&acpi_drv_mutex); + return (0); +} + +static int +acpi_drv_kstat_init(void) +{ + char name[KSTAT_STRLEN]; + struct acpi_drv_cbat_state *bp; + + /* + * Allocate, initialize and install powerstatus and + * supported_battery_count kstat. + */ + acpi_drv_power_ksp = kstat_create(ACPI_DRV_NAME, 0, + ACPI_DRV_POWER_KSTAT_NAME, "misc", + KSTAT_TYPE_NAMED, + sizeof (acpi_drv_power_kstat) / sizeof (kstat_named_t), + KSTAT_FLAG_VIRTUAL); + if (acpi_drv_power_ksp == NULL) { + ACPI_DRV_DBG(CE_WARN, NULL, + "kstat_create(%s) fail", ACPI_DRV_POWER_KSTAT_NAME); + return (ACPI_DRV_ERR); + } + + acpi_drv_power_ksp->ks_data = &acpi_drv_power_kstat; + acpi_drv_power_ksp->ks_update = acpi_drv_kstat_power_update; + acpi_drv_power_ksp->ks_data_size += MAXNAMELEN; + kstat_install(acpi_drv_power_ksp); + + /* + * Allocate, initialize and install battery_capacity_warning kstat. + */ + acpi_drv_warn_ksp = kstat_create(ACPI_DRV_NAME, 0, + ACPI_DRV_BTWARN_KSTAT_NAME, "misc", + KSTAT_TYPE_NAMED, + sizeof (acpi_drv_warn_kstat) / sizeof (kstat_named_t), + KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE); + if (acpi_drv_warn_ksp == NULL) { + ACPI_DRV_DBG(CE_WARN, NULL, + "kstat_create(%s) fail", ACPI_DRV_BTWARN_KSTAT_NAME); + return (ACPI_DRV_ERR); + } + + acpi_drv_warn_ksp->ks_data = &acpi_drv_warn_kstat; + acpi_drv_warn_ksp->ks_update = acpi_drv_kstat_warn_update; + kstat_install(acpi_drv_warn_ksp); + + /* + * Allocate, initialize and install BIF and BST kstat + * for each battery. + */ + for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM]; + bp++) { + if (bp->dev.valid) { + kstat_t *ksp; + + /* BIF kstat */ + (void) snprintf(name, KSTAT_STRLEN-1, "%s%d", + ACPI_DRV_BIF_KSTAT_NAME, bp->dev.index); + ksp = kstat_create(ACPI_DRV_NAME, 0, + name, "misc", KSTAT_TYPE_NAMED, + sizeof (acpi_drv_bif_kstat) / + sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL); + if (ksp == NULL) { + ACPI_DRV_DBG(CE_WARN, NULL, + "kstat_create(%s) fail", name); + return (ACPI_DRV_ERR); + } + ACPI_DRV_DBG(CE_NOTE, NULL, "kstat_create(%s) ok", + name); + + bp->bat_bif_ksp = ksp; + ksp->ks_data = &acpi_drv_bif_kstat; + ksp->ks_update = acpi_drv_kstat_bif_update; + ksp->ks_data_size += MAXNAMELEN * 4; + ksp->ks_private = bp; + + kstat_install(ksp); + + /* BST kstat */ + (void) snprintf(name, KSTAT_STRLEN-1, "%s%d", + ACPI_DRV_BST_KSTAT_NAME, bp->dev.index); + ksp = kstat_create(ACPI_DRV_NAME, 0, name, "misc", + KSTAT_TYPE_NAMED, + sizeof (acpi_drv_bst_kstat) / + sizeof (kstat_named_t), + KSTAT_FLAG_VIRTUAL); + if (ksp == NULL) { + ACPI_DRV_DBG(CE_WARN, NULL, + "kstat_create(%s) fail", name); + return (ACPI_DRV_ERR); + } + ACPI_DRV_DBG(CE_NOTE, NULL, "kstat_create(%s) ok", + name); + + bp->bat_bst_ksp = ksp; + ksp->ks_data = &acpi_drv_bst_kstat; + ksp->ks_update = acpi_drv_kstat_bst_update; + ksp->ks_data_size += MAXNAMELEN * 4; + ksp->ks_private = bp; + + kstat_install(ksp); + } + } + + return (ACPI_DRV_OK); +} + +static void +acpi_drv_kstat_fini() +{ + struct acpi_drv_cbat_state *bp; + + if (acpi_drv_power_ksp != NULL) { + kstat_delete(acpi_drv_power_ksp); + } + if (acpi_drv_warn_ksp != NULL) { + kstat_delete(acpi_drv_warn_ksp); + } + for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM]; + bp++) { + if (bp->dev.valid) { + if (bp->bat_bif_ksp != NULL) { + kstat_delete(bp->bat_bif_ksp); + } + if (bp->bat_bst_ksp != NULL) { + kstat_delete(bp->bat_bst_ksp); + } + } + } +} + +static int +acpi_drv_set_int(ACPI_HANDLE dev, char *method, uint32_t aint) +{ + ACPI_OBJECT_LIST al; + ACPI_OBJECT ao; + + al.Pointer = &ao; + al.Count = 1; + ao.Type = ACPI_TYPE_INTEGER; + ao.Integer.Value = aint; + return (AcpiEvaluateObject(dev, method, &al, NULL)); +} + +static int +acpi_drv_output_init(ACPI_HANDLE hdl, struct acpi_drv_dev *dev) +{ + struct acpi_drv_output_state *op; + int adr; + ACPI_BUFFER buf1, buf2; + ACPI_OBJECT *objp; + char str[256]; + + if (acpica_eval_int(hdl, "_ADR", &adr) != AE_OK) { + return (ACPI_DRV_ERR); + } + + /* Allocate object */ + if (noutput == ACPI_DRV_MAX_OUTPUT_NUM) { + ACPI_DRV_DBG(CE_WARN, NULL, + "Need to support more output devices: " + "AC_MAX = %d", ACPI_DRV_MAX_OUTPUT_NUM); + return (ACPI_DRV_ERR); + } + op = dev->op = &outputs[noutput - 1]; + op->adr = adr; + + buf1.Pointer = str; + buf1.Length = sizeof (str); + + if (!ACPI_FAILURE(AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf1))) { + ACPI_DRV_DBG(CE_NOTE, NULL, "Pathname=%s\n", + (char *)buf1.Pointer); + } + + buf2.Length = ACPI_ALLOCATE_BUFFER; + if (ACPI_SUCCESS(AcpiEvaluateObjectTyped(hdl, "_BCL", + NULL, &buf2, ACPI_TYPE_PACKAGE))) { + int i, j, k, l, m, nlev, tmp; + + ACPI_DRV_DBG(CE_NOTE, NULL, "_BCL supported\n"); + objp = buf2.Pointer; + /* + * op->nlev will be needed to free op->levels. + */ + op->nlev = nlev = objp->Package.Count; + op->levels = kmem_zalloc(nlev * sizeof (uint32_t), + KM_SLEEP); + /* + * Get all the supported brightness levels. + */ + for (i = 0; i < nlev; i++) { + ACPI_OBJECT *o = &objp->Package.Elements[i]; + int lev = o->Integer.Value; + + ACPI_DRV_DBG(CE_NOTE, NULL, "acpi_drv_output_init() " + "brlev=%d i=%d nlev=%d\n", lev, i, nlev); + if (o->Type != ACPI_TYPE_INTEGER) { + continue; + } + op->levels[i] = lev; + } + + /* + * Sort the brightness levels. + */ + for (j = 0; j < nlev; j++) { + for (k = 0; k < nlev - 1; k++) { + if (op->levels[k] > op->levels[k+1]) { + tmp = op->levels[k+1]; + op->levels[k+1] = op->levels[k]; + op->levels[k] = tmp; + } + } + } + + /* + * The first two levels could be duplicated, so remove + * any duplicates. + */ + for (l = 0; l < nlev - 1; l++) { + if (op->levels[l] == op->levels[l+1]) { + for (m = l + 1; m < nlev - 1; m++) { + op->levels[m] = op->levels[m+1]; + } + nlev--; + } + } + op->num_levels = nlev; + + AcpiOsFree(objp); + (void) acpi_drv_output_get_level(op); + ACPI_DRV_DBG(CE_NOTE, NULL, "acpi_drv_output_init(): " + "create minor " + "node for dev->adr=%"PRIu64, dev->adr); + } else { + ACPI_DRV_DBG(CE_NOTE, NULL, "_BCL NOT supported\n"); + } + + (void) acpi_drv_output_get_state(op); + return (ACPI_DRV_OK); +} + +/*ARGSUSED*/ +static int +acpi_drv_output_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr, + int *rval) +{ + struct acpi_drv_output_state *op; + int res = 0; + op = acpi_drv_idx2output(index); + if (!op || op->dev.valid != 1) { + return (ENXIO); + } + + switch (cmd) { + case ACPI_DRV_IOC_INFO: { + struct acpi_drv_output_info inf; + inf.adr = op->adr; + inf.nlev = op->num_levels; + if (copyout(&inf, (void *)arg, sizeof (inf))) { + res = EFAULT; + } + break; + } + + case ACPI_DRV_IOC_LEVELS: + if (copyout(op->levels, (void *)arg, + sizeof (*op->levels) * op->num_levels)) { + res = EFAULT; + } + break; + + case ACPI_DRV_IOC_STATUS: { + /* + * Need to get the current levels through ACPI first + * then go through array of levels to find index. + */ + struct acpi_drv_output_status status; + int i; + + status.state = op->state; + status.num_levels = op->num_levels; + status.cur_level = op->cur_level; + for (i = 0; i < op->num_levels; i++) { + if (op->levels[i] == op->cur_level) { + status.cur_level_index = i; + ACPI_DRV_DBG(CE_NOTE, NULL, "ACPI_DRV_IOC_STATUS " + "cur_level_index %d\n", i); + break; + } + } + if (copyout(&status, (void *)arg, sizeof (status))) { + res = EFAULT; + } + break; + } + + case ACPI_DRV_IOC_SET_BRIGHTNESS: { + int level; + + if (drv_priv(cr)) { + res = EPERM; + break; + } + if (copyin((void *)arg, &level, sizeof (level))) { + res = EFAULT; + break; + } + ACPI_DRV_DBG(CE_NOTE, NULL, + "ACPI_DRV_IOC_SET_BRIGHTNESS level=%d\n", level); + if (acpi_drv_output_set_level(op, level) != ACPI_DRV_OK) { + res = EFAULT; + } + break; + } + + default: + res = EINVAL; + break; + } + return (res); +} + +static struct acpi_drv_output_state * +acpi_drv_idx2output(int idx) +{ + if (idx >= ACPI_DRV_MAX_OUTPUT_NUM) { + return (NULL); + } + return (&outputs[idx]); +} + +/* + * Output device status: + * + * Bits Definition + * + * 0 Output connector exists in the system now. + * 1 Output is activated. + * 2 Output is ready to switch. + * 3 Output is not defective. + * 4 Device is attached (optional). + * 5-31 Reserved (must be zero). + */ +static int +acpi_drv_output_get_state(struct acpi_drv_output_state *op) +{ + if (acpica_eval_int(op->dev.hdl, "_DCS", &op->state) != AE_OK) { + op->state = 0; + return (ACPI_DRV_ERR); + } + return (ACPI_DRV_OK); +} + +/* + * Get the current brightness level and index. + */ +static int +acpi_drv_output_get_level(struct acpi_drv_output_state *op) +{ + int i; + + if (acpica_eval_int(op->dev.hdl, "_BQC", &op->cur_level) != AE_OK) { + op->cur_level = ACPI_DRV_NTF_UNKNOWN; + return (ACPI_DRV_ERR); + } + for (i = 0; i < op->num_levels; i++) { + if (op->levels[i] == op->cur_level) { + op->cur_level_index = i; + ACPI_DRV_DBG(CE_NOTE, NULL, + "acpi_drv_output_get_level(): " + "cur_level = %d, cur_level_index = %d\n", + op->cur_level, i); + break; + } + } + return (ACPI_DRV_OK); +} + +static int +acpi_drv_output_set_level(struct acpi_drv_output_state *op, uint32_t level) +{ + if (acpi_drv_set_int(op->dev.hdl, "_BCM", op->levels[level]) != + AE_OK) { + return (ACPI_DRV_ERR); + } + op->cur_level = op->levels[level]; + op->cur_level_index = level; + return (ACPI_DRV_OK); +} + +static void +acpi_drv_output_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx) +{ + struct acpi_drv_dev *dev = ctx; + struct acpi_drv_output_state *op = dev->op; + + ACPI_DRV_DBG(CE_NOTE, NULL, "acpi_drv_output_notify() val=0x%x\n", val); + mutex_enter(&acpi_drv_mutex); + ACPI_DRV_PRT_NOTIFY(hdl, val); + switch (val) { + case 0x86: /* increase brightness */ + if (op->cur_level_index < op->num_levels - 1) { + if (acpi_drv_output_set_level(op, + op->cur_level_index + 1) != AE_OK) { + break; + } + } + acpi_drv_gen_sysevent(&op->dev, ESC_PWRCTL_BRIGHTNESS_UP, 0); + break; + case 0x87: /* decrease brightness */ + if (op->cur_level_index > 0) { + if (acpi_drv_output_set_level(op, + op->cur_level_index - 1) != AE_OK) { + break; + } + } + acpi_drv_gen_sysevent(&op->dev, ESC_PWRCTL_BRIGHTNESS_DOWN, 0); + break; + default: + break; + } + mutex_exit(&acpi_drv_mutex); +} + +/* + * Set the display control modes of display switching and brightness + * from BIOS or OSPM. + */ +static void +acpi_drv_display_set_mode(struct acpi_drv_display_state *dp, int state) +{ + if (acpi_drv_set_int(dp->dev.hdl, "_DOS", state) != AE_OK) { + ACPI_DRV_DBG(CE_WARN, NULL, "Cannot set display mode %d\n", + state); + } +} diff --git a/usr/src/uts/i86pc/io/battery/battery.conf b/usr/src/uts/i86pc/io/acpi_drv/acpi_drv.conf index 216cac8604..fce7f57995 100644 --- a/usr/src/uts/i86pc/io/battery/battery.conf +++ b/usr/src/uts/i86pc/io/acpi_drv/acpi_drv.conf @@ -19,12 +19,12 @@ # CDDL HEADER END # # -# Copyright 2007 Sun Microsystems, Inc. All rights reserved. +# Copyright 2008 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # ident "%Z%%M% %I% %E% SMI" -name="battery" parent="pseudo" instance=0; +name="acpi_drv" parent="pseudo" instance=0; ddi-forceattach=1; diff --git a/usr/src/uts/i86pc/io/battery/battery.c b/usr/src/uts/i86pc/io/battery/battery.c deleted file mode 100644 index 1f0e7a049b..0000000000 --- a/usr/src/uts/i86pc/io/battery/battery.c +++ /dev/null @@ -1,1972 +0,0 @@ -/* - * CDDL HEADER START - * - * The contents of this file are subject to the terms of the - * Common Development and Distribution License (the "License"). - * You may not use this file except in compliance with the License. - * - * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE - * or http://www.opensolaris.org/os/licensing. - * See the License for the specific language governing permissions - * and limitations under the License. - * - * When distributing Covered Code, include this CDDL HEADER in each - * file and include the License file at usr/src/OPENSOLARIS.LICENSE. - * If applicable, add the following below this CDDL HEADER, with the - * fields enclosed by brackets "[]" replaced with your own identifying - * information: Portions Copyright [yyyy] [name of copyright owner] - * - * CDDL HEADER END - */ - -/* - * Copyright 2007 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. - */ - -/* - * Solaris x86 ACPI Battery Monitor - */ - -#pragma ident "%Z%%M% %I% %E% SMI" - -#include <sys/conf.h> -#include <sys/modctl.h> -#include <sys/ddi.h> -#include <sys/sunddi.h> -#include <sys/stat.h> -#include <sys/sysevent/eventdefs.h> -#include <sys/sysevent/acpiev.h> -#include <sys/reboot.h> -#include <sys/acpi/acpi.h> -#include <sys/note.h> -#include <sys/battery.h> - - -#define BATT_MOD_STRING "ACPI battery driver %I%" - -#define MINOR_SHIFT 8 -#define IDX_MASK ((1 << MINOR_SHIFT) - 1) -#define MINOR_BATT(idx) (BATT_TYPE_CBAT << MINOR_SHIFT | (idx)) -#define MINOR_AC(idx) (BATT_TYPE_AC << MINOR_SHIFT | (idx)) -#define MINOR2IDX(minor) ((minor) & IDX_MASK) -#define MINOR2TYPE(minor) ((minor) >> MINOR_SHIFT) - -#define BATT_OK (0) -#define BATT_ERR (1) - -#define BATT_MAX_BAT_NUM 8 -#define BATT_MAX_AC_NUM 10 - -#define BST_FLAG_DISCHARGING (0x1) -#define BST_FLAG_CHARGING (0x2) -#define BST_FLAG_CRITICAL (0x4) - -/* Set if the battery is present */ -#define STA_FLAG_BATT_PRESENT (0x10) - -#define ACPI_DEVNAME_CBAT "PNP0C0A" -#define ACPI_DEVNAME_SBAT "ACPI0002" -#define ACPI_DEVNAME_AC "ACPI0003" - -#define BATT_EVENTS (POLLIN | POLLRDNORM) - -#ifdef DEBUG - -#define BATT_PRINT_BUFFER_SIZE 512 -static char batt_prt_buf[BATT_PRINT_BUFFER_SIZE]; -static kmutex_t batt_prt_mutex; - -static int batt_debug = 0; -#define BATT_DBG(lev, devp, ...) \ - do { \ - if (batt_debug) batt_printf((devp), (lev), __VA_ARGS__); \ -_NOTE(CONSTCOND) } while (0) -#define BATT_PRT_NOTIFY(hdl, val) \ - do { \ - if (batt_debug) batt_prt_notify((hdl), (val)); \ -_NOTE(CONSTCOND) } while (0) - -#else - -#define BATT_DBG(lev, devp, ...) -#define BATT_PRT_NOTIFY(hdl, val) - -#endif /* DEBUG */ - -/* ACPI notify types */ -enum batt_notify { - BATT_NTF_UNKNOWN = -1, /* No notifications seen, ever. */ - BATT_NTF_CHANGED, - BATT_NTF_OK -}; - -/* Battery device types */ -enum batt_type { - BATT_TYPE_UNKNOWN = -1, - BATT_TYPE_CBAT, - BATT_TYPE_AC, - BATT_TYPE_SBAT -}; - -struct batt_acpi_dev { - ACPI_HANDLE hdl; - char hid[9]; /* ACPI HardwareId */ - char uid[9]; /* ACPI UniqueId */ - int valid; /* the device state is valid */ - - /* - * Unlike most other devices, when a battery is inserted or - * removed from the system, the device itself(the battery bay) - * is still considered to be present in the system. - * - * Value: - * 0 -- On-line - * 1 -- Off-line - * -1 -- Unknown - */ - int present; - enum batt_type type; - int index; /* device index */ -}; - -static int batt_dev_present(struct batt_acpi_dev *); -#define batt_ac_present(a) (((a)->dev.type == BATT_TYPE_AC) ? \ - batt_dev_present(&(a)->dev) : -1) -#define batt_cbat_present(a) (((a)->dev.type == BATT_TYPE_CBAT) ? \ - batt_dev_present(&(a)->dev) : -1) - -static dev_info_t *batt_dip = NULL; -static kmutex_t batt_mutex; -static struct pollhead batt_pollhead; - -/* Control Method Battery state */ -struct batt_cbat_state { - struct batt_acpi_dev dev; -/* Caches of _BST and _BIF */ - enum batt_notify bat_bifok; - acpi_bif_t bif_cache; - enum batt_notify bat_bstok; - acpi_bst_t bst_cache; - - uint32_t charge_warn; - uint32_t charge_low; - - kstat_t *bat_bif_ksp; - kstat_t *bat_bst_ksp; -} batt_cbat[BATT_MAX_BAT_NUM]; -static int nbat; - -/* - * Synthesis battery state - * When there are multiple batteries present, the battery subsystem - * is not required to perform any synthesis of a composite battery - * from the data of the separate batteries. In cases where the - * battery subsystem does not synthesize a composite battery from - * the separate battery's data, the OS must provide that synthesis. - */ -static uint32_t batt_syn_rem_cap; -static uint32_t batt_syn_last_cap; -static uint32_t batt_syn_oem_warn_cap; -static uint32_t batt_syn_oem_low_cap; - -static int batt_warn_enabled; -static uint32_t batt_syn_warn_per; -static uint32_t batt_syn_low_per; -static uint32_t batt_syn_warn_cap; -static uint32_t batt_syn_low_cap; -/* Tracking boundery passing of _BST charge levels */ -static uint32_t batt_syn_last_level; - -/* AC state */ -static struct batt_ac_state { - struct batt_acpi_dev dev; -} batt_ac[BATT_MAX_AC_NUM]; -static int nac; - -/* - * Current power source device - * Note: assume only one device can be the power source device. - */ -static int batt_psr_type = BATT_TYPE_UNKNOWN; -static struct batt_acpi_dev *batt_psr_devp = NULL; - -/* Smart Battery state */ -static struct batt_sbat_state { - struct batt_acpi_dev dev; -} batt_sbat; - -struct obj_desc { - char *name; - int offset; - int size; - int type; -}; - -/* Object copy definitions */ -#define OFFSETOF(s, m) ((size_t)(&(((s *)0)->m))) -#define SIZEOF(s, m) (sizeof (((s *)0)->m)) -#define FIELD(n, s, m, t) \ - { n, OFFSETOF(s, m), SIZEOF(s, m), t } -#define FIELD_NULL { NULL, -1, 0, ACPI_TYPE_ANY } - -static struct obj_desc bif_desc[] = { - FIELD("bif_unit", acpi_bif_t, bif_unit, ACPI_TYPE_INTEGER), - FIELD("bif_design_cap", acpi_bif_t, bif_design_cap, ACPI_TYPE_INTEGER), - FIELD("bif_last_cap", acpi_bif_t, bif_last_cap, ACPI_TYPE_INTEGER), - FIELD("bif_tech", acpi_bif_t, bif_tech, ACPI_TYPE_INTEGER), - FIELD("bif_voltage", acpi_bif_t, bif_voltage, ACPI_TYPE_INTEGER), - FIELD("bif_warn_cap", acpi_bif_t, bif_warn_cap, ACPI_TYPE_INTEGER), - FIELD("bif_low_cap", acpi_bif_t, bif_low_cap, ACPI_TYPE_INTEGER), - FIELD("bif_gran1_cap", acpi_bif_t, bif_gran1_cap, ACPI_TYPE_INTEGER), - FIELD("bif_gran2_cap", acpi_bif_t, bif_gran2_cap, ACPI_TYPE_INTEGER), - FIELD("bif_model", acpi_bif_t, bif_model, ACPI_TYPE_STRING), - FIELD("bif_serial", acpi_bif_t, bif_serial, ACPI_TYPE_STRING), - FIELD("bif_type", acpi_bif_t, bif_type, ACPI_TYPE_STRING), - FIELD("bif_oem_info", acpi_bif_t, bif_oem_info, ACPI_TYPE_STRING), - FIELD_NULL -}; - -static struct obj_desc bst_desc[] = { - FIELD("bst_state", acpi_bst_t, bst_state, ACPI_TYPE_INTEGER), - FIELD("bst_rate", acpi_bst_t, bst_rate, ACPI_TYPE_INTEGER), - FIELD("bst_rem_cap", acpi_bst_t, bst_rem_cap, ACPI_TYPE_INTEGER), - FIELD("bst_voltage", acpi_bst_t, bst_voltage, ACPI_TYPE_INTEGER), - FIELD_NULL -}; - -/* kstat definitions */ -static kstat_t *batt_power_ksp; -static kstat_t *batt_warn_ksp; - -batt_power_kstat_t batt_power_kstat = { - { SYSTEM_POWER, KSTAT_DATA_STRING }, - { SUPPORTED_BATTERY_COUNT, KSTAT_DATA_UINT32 }, -}; - -batt_warn_kstat_t batt_warn_kstat = { - { BW_ENABLED, KSTAT_DATA_UINT32 }, - { BW_POWEROFF_THRESHOLD, KSTAT_DATA_UINT32 }, - { BW_SHUTDOWN_THRESHOLD, KSTAT_DATA_UINT32 }, -}; - -/* BIF */ -batt_bif_kstat_t batt_bif_kstat = { - { BIF_UNIT, KSTAT_DATA_UINT32 }, - { BIF_DESIGN_CAP, KSTAT_DATA_UINT32 }, - { BIF_LAST_CAP, KSTAT_DATA_UINT32 }, - { BIF_TECH, KSTAT_DATA_UINT32 }, - { BIF_VOLTAGE, KSTAT_DATA_UINT32 }, - { BIF_WARN_CAP, KSTAT_DATA_UINT32 }, - { BIF_LOW_CAP, KSTAT_DATA_UINT32 }, - { BIF_GRAN1_CAP, KSTAT_DATA_UINT32 }, - { BIF_GRAN2_CAP, KSTAT_DATA_UINT32 }, - { BIF_MODEL, KSTAT_DATA_STRING }, - { BIF_SERIAL, KSTAT_DATA_STRING }, - { BIF_TYPE, KSTAT_DATA_STRING }, - { BIF_OEM_INFO, KSTAT_DATA_STRING }, -}; - -/* BST */ -batt_bst_kstat_t batt_bst_kstat = { - { BST_STATE, KSTAT_DATA_UINT32 }, - { BST_RATE, KSTAT_DATA_UINT32 }, - { BST_REM_CAP, KSTAT_DATA_UINT32 }, - { BST_VOLTAGE, KSTAT_DATA_UINT32 }, -}; - -static int batt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd); -static int batt_detach(dev_info_t *devi, ddi_detach_cmd_t cmd); -static int batt_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, - void **resultp); -static int batt_open(dev_t *devp, int flag, int otyp, cred_t *crp); -static int batt_close(dev_t dev, int flag, int otyp, cred_t *crp); -static int batt_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, - int *rval); -static int batt_chpoll(dev_t dev, short events, int anyyet, short *reventsp, - struct pollhead **phpp); -static int batt_ac_ioctl(int index, int cmd, intptr_t arg, int mode, - cred_t *cr, int *rval); -static int batt_cbat_ioctl(int index, int cmd, intptr_t arg, int mode, - cred_t *cr, int *rval); -#ifdef DEBUG -static void batt_printf(struct batt_acpi_dev *devp, uint_t lev, - const char *fmt, ...); -#endif -static int batt_get_bif(acpi_bif_t *bifp, struct batt_cbat_state *bp); -static int batt_get_bst(acpi_bst_t *bstp, struct batt_cbat_state *bp); -static int batt_set_warn(batt_warn_t *bwp); -static struct batt_cbat_state *batt_idx2cbat(int idx); -static struct batt_ac_state *batt_idx2ac(int idx); -static int batt_acpi_init(void); -static void batt_acpi_fini(void); -static int batt_kstat_init(void); -static void batt_kstat_fini(void); - -static struct cb_ops batt_cb_ops = { - batt_open, /* open */ - batt_close, /* close */ - nodev, /* strategy */ - nodev, /* print */ - nodev, /* dump */ - nodev, /* read */ - nodev, /* write */ - batt_ioctl, /* ioctl */ - nodev, /* devmap */ - nodev, /* mmap */ - nodev, /* segmap */ - batt_chpoll, /* chpoll */ - ddi_prop_op, /* prop_op */ - NULL, /* streamtab */ - D_NEW | D_MP, - CB_REV, - nodev, - nodev -}; - -static struct dev_ops batt_dev_ops = { - DEVO_REV, - 0, /* refcnt */ - batt_getinfo, /* getinfo */ - nulldev, /* identify */ - nulldev, /* probe */ - batt_attach, /* attach */ - batt_detach, /* detach */ - nodev, /* reset */ - &batt_cb_ops, - NULL, /* no bus operations */ - NULL /* power */ -}; - -static struct modldrv modldrv1 = { - &mod_driverops, - BATT_MOD_STRING, - &batt_dev_ops -}; - -static struct modlinkage modlinkage = { - MODREV_1, - (void *)&modldrv1, - NULL, -}; - -int -_init(void) -{ - int ret; - - mutex_init(&batt_mutex, NULL, MUTEX_DRIVER, NULL); -#ifdef DEBUG - mutex_init(&batt_prt_mutex, NULL, MUTEX_DRIVER, NULL); -#endif - - if ((ret = mod_install(&modlinkage)) != 0) { - mutex_destroy(&batt_mutex); -#ifdef DEBUG - mutex_destroy(&batt_prt_mutex); -#endif - } - return (ret); -} - -int -_fini(void) -{ - int ret; - - if ((ret = mod_remove(&modlinkage)) == 0) { -#ifdef DEBUG - mutex_destroy(&batt_prt_mutex); -#endif - mutex_destroy(&batt_mutex); - } - - return (ret); -} - -int -_info(struct modinfo *mp) -{ - return (mod_info(&modlinkage, mp)); -} - -static int -batt_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) -{ - char name[20]; - int i; - struct batt_cbat_state *bp; - - switch (cmd) { - case DDI_ATTACH: - /* Limit to one instance of driver */ - if (batt_dip) { - return (DDI_FAILURE); - } - break; - case DDI_RESUME: - case DDI_PM_RESUME: - return (DDI_SUCCESS); - default: - return (DDI_FAILURE); - } - - batt_dip = devi; - - /* Init ACPI related stuff */ - if (batt_acpi_init() != BATT_OK) { - goto error; - } - - /* Init kstat related stuff */ - if (batt_kstat_init() != BATT_OK) { - goto error; - } - - /* Create minor node for each battery and ac */ - for (bp = &batt_cbat[0]; bp < &batt_cbat[BATT_MAX_BAT_NUM]; bp++) { - if (bp->dev.valid) { - (void) snprintf(name, sizeof (name), "battery%d", - bp->dev.index); - if (ddi_create_minor_node(devi, name, S_IFCHR, - MINOR_BATT(bp->dev.index), DDI_PSEUDO, 0) == - DDI_FAILURE) { - BATT_DBG(CE_WARN, NULL, - "%s: minor node create failed", name); - goto error; - } - } - } - for (i = 0; i < nac; i++) { - (void) snprintf(name, sizeof (name), "ac%d", i); - if (ddi_create_minor_node(devi, name, S_IFCHR, - MINOR_AC(i), DDI_PSEUDO, 0) == DDI_FAILURE) { - BATT_DBG(CE_WARN, NULL, - "%s: minor node create failed", name); - goto error; - } - } - - return (DDI_SUCCESS); - -error: - ddi_remove_minor_node(devi, NULL); - batt_kstat_fini(); - batt_acpi_fini(); - batt_dip = NULL; - return (DDI_FAILURE); -} - -static int -batt_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) -{ - if (cmd != DDI_DETACH) { - return (DDI_FAILURE); - } - - ddi_remove_minor_node(devi, NULL); - - batt_kstat_fini(); - batt_acpi_fini(); - return (DDI_SUCCESS); -} - -/* ARGSUSED */ -static int -batt_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp) -{ - switch (cmd) { - case DDI_INFO_DEVT2DEVINFO: - *resultp = batt_dip; - return (DDI_SUCCESS); - case DDI_INFO_DEVT2INSTANCE: - *resultp = (void*) 0; - return (DDI_SUCCESS); - default: - return (DDI_FAILURE); - } -} - -/*ARGSUSED*/ -static int -batt_open(dev_t *devp, int flag, int otyp, cred_t *crp) -{ - if (batt_dip == NULL) { - return (ENXIO); - } - - return (0); -} - -/*ARGSUSED*/ -static int -batt_close(dev_t dev, int flag, int otyp, cred_t *crp) -{ - return (0); -} - -/*ARGSUSED*/ -static int -batt_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr, int *rval) -{ - int minor; - int type, index; - int res = 0; - - minor = getminor(dev); - type = MINOR2TYPE(minor); - index = MINOR2IDX(minor); - - mutex_enter(&batt_mutex); - - if (type == BATT_TYPE_CBAT) { - res = batt_cbat_ioctl(index, cmd, arg, mode, cr, rval); - } else if (type == BATT_TYPE_AC) { - res = batt_ac_ioctl(index, cmd, arg, mode, cr, rval); - } else { - res = EINVAL; - } - - mutex_exit(&batt_mutex); - return (res); -} - -/*ARGSUSED*/ -static int -batt_cbat_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr, - int *rval) -{ - int res = 0; - acpi_bif_t bif; - acpi_bst_t bst; - batt_warn_t bwarn; - struct batt_cbat_state *bp; - - ASSERT(mutex_owned(&batt_mutex)); - - bp = batt_idx2cbat(index); - if (!bp || bp->dev.valid != 1) { - return (ENXIO); - } - - switch (cmd) { - /* - * Return _BIF(Battery Information) of battery[index], - * if battery plugged. - */ - case BATT_IOC_INFO: - if (bp->dev.present == 0) { - res = ENXIO; - break; - } - - (void) memset(&bif, 0, sizeof (bif)); - bp->bat_bifok = BATT_NTF_UNKNOWN; - res = batt_get_bif(&bif, bp); - if (res != BATT_OK) { - break; - } - if (copyout(&bif, (void *)arg, sizeof (bif))) { - res = EFAULT; - } - break; - - /* - * Return _BST(Battery Status) of battery[index], - * if battery plugged. - */ - case BATT_IOC_STATUS: - if (bp->dev.present == 0) { - res = ENXIO; - break; - } - - (void) memset(&bst, 0, sizeof (bst)); - bp->bat_bstok = BATT_NTF_UNKNOWN; - res = batt_get_bst(&bst, bp); - if (res != BATT_OK) { - break; - } - if (copyout(&bst, (void *)arg, sizeof (bst))) { - res = EFAULT; - } - break; - - /* Return the state of the battery bays in the system */ - case BATT_IOC_BAY: - { - batt_bay_t bay; - - bay.bay_number = nbat; - bay.battery_map = 0; - for (bp = &batt_cbat[0]; - bp < &batt_cbat[BATT_MAX_BAT_NUM]; bp++) { - if (bp->dev.valid) { - if (bp->dev.present) { - bay.battery_map |= - (1 << bp->dev.index); - } - } - } - if (copyout(&bay, (void *)arg, sizeof (bay))) { - res = EFAULT; - break; - } - } - break; - - /* - * Return the current power source device if available: - * 0 -- battery supplying power - * 1 -- AC supplying power - */ - case BATT_IOC_POWER_STATUS: - { - int val; - - /* State not available */ - if (batt_psr_type == BATT_TYPE_UNKNOWN) { - res = ENXIO; - break; - } - val = (batt_psr_type == BATT_TYPE_AC) ? 1 : 0; - if (copyout(&val, (void *)arg, sizeof (val))) { - res = EFAULT; - break; - } - } - break; - - /* Get charge-warn and charge-low levels for the whole system */ - case BATT_IOC_GET_WARNING: - bwarn.bw_enabled = batt_warn_enabled; - bwarn.bw_charge_warn = batt_syn_warn_per; - bwarn.bw_charge_low = batt_syn_low_per; - if (copyout(&bwarn, (void *)arg, sizeof (&bwarn))) { - res = EFAULT; - } - break; - - /* Set charge-warn and charge-low levels for the whole system */ - case BATT_IOC_SET_WARNING: - if (drv_priv(cr)) { - res = EPERM; - break; - } - if (copyin((void *)arg, &bwarn, sizeof (&bwarn))) { - res = EFAULT; - break; - } - res = batt_set_warn(&bwarn); - break; - - default: - res = EINVAL; - break; - } - - return (res); -} - -/*ARGSUSED*/ -static int -batt_ac_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr, - int *rval) -{ - int res = 0; - int ac_state; - struct batt_ac_state *acp; - - ASSERT(mutex_owned(&batt_mutex)); - - acp = batt_idx2ac(index); - if (!acp || acp->dev.valid != 1) { - return (ENXIO); - } - - switch (cmd) { - /* Return the number of AC adapters in the system */ - case BATT_IOC_AC_COUNT: - if (copyout(&nac, (void *)arg, sizeof (nac))) { - res = EFAULT; - } - break; - - /* - * Return the state of AC[index] if available: - * 0 -- Off-line - * 1 -- On-line - */ - case BATT_IOC_POWER_STATUS: - if (!acp || acp->dev.valid != 1) { - res = ENXIO; - break; - } - /* State not available */ - if ((ac_state = batt_ac_present(acp)) == -1) { - res = ENXIO; - break; - } - if (copyout(&ac_state, (void *)arg, sizeof (ac_state))) { - res = EFAULT; - } - break; - - default: - res = EINVAL; - break; - } - - return (res); -} - -/*ARGSUSED*/ -static int -batt_chpoll(dev_t dev, short events, int anyyet, short *reventsp, - struct pollhead **phpp) -{ - if (!anyyet) { - *phpp = &batt_pollhead; - } - *reventsp = 0; - return (0); -} - -#ifdef DEBUG -static void -batt_printf(struct batt_acpi_dev *devp, uint_t lev, const char *fmt, ...) -{ - va_list args; - - mutex_enter(&batt_prt_mutex); - - va_start(args, fmt); - (void) vsprintf(batt_prt_buf, fmt, args); - va_end(args); - - if (devp) { - cmn_err(lev, "%s.%s: %s", devp->hid, devp->uid, batt_prt_buf); - } else { - cmn_err(lev, "%s", batt_prt_buf); - } - mutex_exit(&batt_prt_mutex); -} - -static void -batt_prt_notify(ACPI_HANDLE hdl, UINT32 val) -{ - ACPI_BUFFER buf; - char str[1024]; - - buf.Length = sizeof (str); - buf.Pointer = str; - AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf); - cmn_err(CE_NOTE, "AcpiNotify(%s, 0x%02x)", str, val); -} -#endif /* DEBUG */ - -static void -batt_gen_sysevent(struct batt_acpi_dev *devp, char *ev, uint32_t val) -{ - nvlist_t *attr_list = NULL; - int err; - char pathname[MAXPATHLEN]; - - /* Allocate and build sysevent attribute list */ - err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, DDI_NOSLEEP); - if (err != 0) { - BATT_DBG(CE_WARN, NULL, - "cannot allocate memory for sysevent attributes\n"); - return; - } - - /* Add attributes */ - err = nvlist_add_string(attr_list, ACPIEV_DEV_HID, devp->hid); - if (err != 0) { - BATT_DBG(CE_WARN, NULL, - "Failed to add attr [%s] for %s/%s event", - ACPIEV_DEV_HID, EC_ACPIEV, ev); - nvlist_free(attr_list); - return; - } - - err = nvlist_add_string(attr_list, ACPIEV_DEV_UID, devp->uid); - if (err != 0) { - BATT_DBG(CE_WARN, NULL, - "Failed to add attr [%s] for %s/%s event", - ACPIEV_DEV_UID, EC_ACPIEV, ev); - nvlist_free(attr_list); - return; - } - - err = nvlist_add_uint32(attr_list, ACPIEV_DEV_INDEX, devp->index); - if (err != 0) { - BATT_DBG(CE_WARN, NULL, - "Failed to add attr [%s] for %s/%s event", - ACPIEV_DEV_INDEX, EC_ACPIEV, ev); - nvlist_free(attr_list); - return; - } - - (void) ddi_pathname(batt_dip, pathname); - err = nvlist_add_string(attr_list, ACPIEV_DEV_PHYS_PATH, pathname); - if (err != 0) { - BATT_DBG(CE_WARN, NULL, - "Failed to add attr [%s] for %s/%s event", - ACPIEV_DEV_PHYS_PATH, EC_ACPIEV, ev); - nvlist_free(attr_list); - return; - } - - if (strcmp(ev, ESC_ACPIEV_WARN) && strcmp(ev, ESC_ACPIEV_LOW)) { - goto finish; - } - - err = nvlist_add_uint32(attr_list, ACPIEV_CHARGE_LEVEL, val); - if (err != 0) { - BATT_DBG(CE_WARN, NULL, - "Failed to add attr [%s] for %s/%s event", - ACPIEV_CHARGE_LEVEL, EC_ACPIEV, ev); - nvlist_free(attr_list); - return; - } - -finish: - BATT_DBG(CE_NOTE, NULL, "SysEv(%s, %s.%s, %d)", - ev, devp->hid, devp->uid, val); - /* Generate/log sysevent */ - err = ddi_log_sysevent(batt_dip, DDI_VENDOR_SUNW, EC_ACPIEV, - ev, attr_list, NULL, DDI_NOSLEEP); -#ifdef DEBUG - if (err != DDI_SUCCESS) { - BATT_DBG(CE_WARN, NULL, - "cannot log sysevent, err code %x\n", err); - } -#endif - - nvlist_free(attr_list); -} - -static int -batt_obj_copy(ACPI_OBJECT *op, char *bp, struct obj_desc *dp) -{ - ACPI_OBJECT *ep; - char *fp; - - ep = &op->Package.Elements[0]; - for (; dp->offset != -1; dp++) { - fp = bp + dp->offset; - if (dp->type == ACPI_TYPE_INTEGER && - ep->Type == dp->type) { -#ifdef DEBUG - if (dp->size <= 4) { - BATT_DBG(CE_NOTE, NULL, "\t%s: %u", dp->name, - (uint32_t)ep->Integer.Value); - } else { -#ifdef _LP64 - BATT_DBG(CE_NOTE, NULL, "\t%s: %lu", - dp->name, (uint64_t)ep->Integer.Value); - } -#else - BATT_DBG(CE_NOTE, NULL, "\t%s: %llu", - dp->name, (uint64_t)ep->Integer.Value); - } -#endif /* _LP64 */ -#endif /* DEBUG */ - *(uint32_t *)fp = ep->Integer.Value; - } else if (dp->type == ACPI_TYPE_STRING && - ep->Type == dp->type) { - BATT_DBG(CE_NOTE, NULL, "\t%s: \"%s\"", - dp->name, ep->String.Pointer); - (void) strncpy(fp, ep->String.Pointer, dp->size); - } else if (dp->type == ACPI_TYPE_STRING && - ep->Type == ACPI_TYPE_BUFFER) { -#ifdef DEBUG - int len; - char buf[MAXNAMELEN + 1]; - - len = (MAXNAMELEN < ep->Buffer.Length) ? - MAXNAMELEN : ep->Buffer.Length; - bcopy(ep->Buffer.Pointer, buf, len); - buf[len] = 0; - BATT_DBG(CE_NOTE, NULL, "\t%s: [%d] \"%s\"", - dp->name, len, buf); -#endif - - ASSERT(MAXNAMELEN >= ep->Buffer.Length); - bcopy(ep->Buffer.Pointer, fp, ep->Buffer.Length); - } else { - BATT_DBG(CE_WARN, NULL, - "Bad field at offset %d: type %d", - dp->offset, ep->Type); - if (dp->type != ACPI_TYPE_STRING) { - return (BATT_ERR); - } - } - ep++; - } - - return (BATT_OK); -} - -static int -batt_eval_int(ACPI_HANDLE hdl, ACPI_STRING name, ACPI_OBJECT_LIST *parms, - int *rval) -{ - ACPI_BUFFER buf; - ACPI_OBJECT obj; - - buf.Length = sizeof (obj); - buf.Pointer = &obj; - - if (ACPI_FAILURE(AcpiEvaluateObjectTyped(hdl, name, parms, &buf, - ACPI_TYPE_INTEGER))) { - return (BATT_ERR); - } - - *rval = (int)obj.Integer.Value; - return (BATT_OK); -} - -/* - * Returns the current power source devices. Used for the AC adapter and is - * located under the AC adapter object in name space. Used to determine if - * system is running off the AC adapter. This will report that the system is - * not running on the AC adapter if any of the batteries in the system is - * being forced to discharge through _BMC. - * - * Return value: - * 0 -- Off-line, ie. battery supplying system power - * 1 -- On-line, ie. AC supplying system power - * -1 -- Unknown, some error ocurred. - * Note: It will also update the driver ac state. - */ -static int -batt_get_psr(struct batt_ac_state *acp) -{ - struct batt_acpi_dev *devp = &acp->dev; - int ac; - - if (!devp->valid) { - BATT_DBG(CE_WARN, NULL, "device not valid"); - return (-1); - } - - if (ACPI_FAILURE(batt_eval_int(devp->hdl, "_PSR", NULL, &ac))) { - BATT_DBG(CE_WARN, NULL, "AcpiEval _PSR failed"); - devp->present = -1; - } else { - BATT_DBG(CE_NOTE, devp, "_PSR = %d", ac); - devp->present = ac; - } - - return (ac); -} - -/* - * For most systems, the _STA for this device will always - * return a value with bits 0-3 set and will toggle bit 4 - * to indicate the actual presence of a battery. - * - * Return value: - * 0 -- battery not present - * 1 -- battery present - * -1 -- Unknown, some error ocurred. - * Note: It will also update the driver cbat state. - */ -static int -batt_get_sta(struct batt_cbat_state *bp) -{ - struct batt_acpi_dev *devp = &bp->dev; - int val; - - if (!devp->valid) { - BATT_DBG(CE_WARN, NULL, "device not valid"); - return (-1); - } - - if (batt_eval_int(devp->hdl, "_STA", NULL, &val) == BATT_ERR) { - BATT_DBG(CE_WARN, NULL, "AcpiEval _STA failed"); - devp->present = -1; - } else { - BATT_DBG(CE_NOTE, devp, "_STA = 0x%x", val); - devp->present = ((val & STA_FLAG_BATT_PRESENT) != 0); - } - - return (val); -} - -static int -batt_get_bif(acpi_bif_t *bifp, struct batt_cbat_state *bp) -{ - /* BIF is only available when battery plugged */ - ASSERT(bp->dev.present != 0); - - /* Update internal BIF cache */ - if (bp->bat_bifok != BATT_NTF_OK) { - ACPI_BUFFER buf; - ACPI_OBJECT *objp; - - buf.Length = ACPI_ALLOCATE_BUFFER; - if (ACPI_FAILURE(AcpiEvaluateObjectTyped(bp->dev.hdl, "_BIF", - NULL, &buf, ACPI_TYPE_PACKAGE))) { - BATT_DBG(CE_WARN, NULL, "AcpiEval _BIF failed"); - return (BATT_ERR); - } - - objp = buf.Pointer; - BATT_DBG(CE_NOTE, &bp->dev, "get _BIF"); - if (batt_obj_copy(objp, (char *)&bp->bif_cache, bif_desc) == - BATT_ERR) { - AcpiOsFree(objp); - return (BATT_ERR); - } - AcpiOsFree(objp); - - bp->bat_bifok = BATT_NTF_OK; - } - - /* Copy BIF back to user */ - if (bifp) { - *bifp = bp->bif_cache; - } - return (BATT_OK); -} - -static int -batt_get_bst(acpi_bst_t *bstp, struct batt_cbat_state *bp) -{ - /* BST is only available when battery plugged */ - ASSERT(bp->dev.present != 0); - - /* Update internal BST cache */ - if (bp->bat_bstok != BATT_NTF_OK) { - ACPI_BUFFER buf; - ACPI_OBJECT *objp; - - buf.Length = ACPI_ALLOCATE_BUFFER; - if (ACPI_FAILURE(AcpiEvaluateObjectTyped(bp->dev.hdl, "_BST", - NULL, &buf, ACPI_TYPE_PACKAGE))) { - BATT_DBG(CE_WARN, NULL, "AcpiEval _BST failed"); - return (BATT_ERR); - } - - objp = buf.Pointer; - BATT_DBG(CE_NOTE, &bp->dev, "get _BST"); - if (batt_obj_copy(objp, (char *)&bp->bst_cache, bst_desc) == - BATT_ERR) { - AcpiOsFree(objp); - return (BATT_ERR); - } - AcpiOsFree(objp); - - if (bp->bst_cache.bst_rate == 0) { - bp->bst_cache.bst_state &= ~(BATT_BST_CHARGING | - BATT_BST_DISCHARGING); - } - bp->bat_bstok = BATT_NTF_OK; - } - - /* Copy BST back to user */ - if (bstp) { - *bstp = bp->bst_cache; - } - return (BATT_OK); -} - -static int -batt_update_bif(struct batt_cbat_state *bp) -{ - bp->bat_bifok = BATT_NTF_UNKNOWN; - return (batt_get_bif(NULL, bp)); -} - -static int -batt_update_bst(struct batt_cbat_state *bp) -{ - bp->bat_bstok = BATT_NTF_UNKNOWN; - return (batt_get_bst(NULL, bp)); -} - -/* - * Return value: - * 1 -- device On-line - * 0 -- device Off-line - * -1 -- Unknown, some error ocurred. - */ -static int -batt_dev_present(struct batt_acpi_dev *devp) -{ - if (!devp->valid) { - BATT_DBG(CE_WARN, NULL, "device not valid"); - return (-1); - } - - ASSERT(devp->type != BATT_TYPE_UNKNOWN); - - /* Update the device state */ - if (devp->present == -1) { - if (devp->type == BATT_TYPE_AC) { - (void) batt_get_psr((struct batt_ac_state *)devp); - } else if (devp->type == BATT_TYPE_CBAT) { - (void) batt_get_sta((struct batt_cbat_state *)devp); - } - } - - return (devp->present); -} - -/* - * Check if the device p existance state has changed. - * Return value: - * 1 -- changed - * 0 -- no change - * -1 -- unknown - */ -static int -batt_update_present(struct batt_acpi_dev *p) -{ - int old_present = p->present; - int new_present; - - ASSERT(p && p->valid); - - p->present = -1; - new_present = batt_dev_present(p); - if (new_present == -1) { - return (-1); - } - if (new_present != old_present) { - return (1); - } - return (0); -} - -static void -batt_set_psr(struct batt_acpi_dev *p) -{ - batt_psr_devp = p; - if (p != NULL) { - BATT_DBG(CE_NOTE, p, "psr = ."); - batt_psr_type = p->type; - } else { - BATT_DBG(CE_NOTE, p, "psr = ?"); - batt_psr_type = BATT_TYPE_UNKNOWN; - } -} - -/* - * OSPM can determine independent warning and low battery - * capacity values based on the OEM-designed levels, but - * cannot set these values lower than the OEM-designed values. - */ -static int -batt_set_warn(batt_warn_t *bwp) -{ - uint32_t warn, low; - - warn = batt_syn_last_cap * bwp->bw_charge_warn / 100; - low = batt_syn_last_cap * bwp->bw_charge_low / 100; - - /* Update internal state */ - if (bwp->bw_enabled) { - if (low >= warn || warn < batt_syn_oem_warn_cap || - low < batt_syn_oem_low_cap) { - BATT_DBG(CE_WARN, NULL, "charge level error"); - return (EINVAL); - } - - BATT_DBG(CE_NOTE, NULL, "set warn: warn=%d low=%d", warn, low); - - batt_syn_warn_per = bwp->bw_charge_warn; - batt_syn_low_per = bwp->bw_charge_low; - batt_syn_warn_cap = warn; - batt_syn_low_cap = low; - batt_warn_enabled = 1; - } else { - batt_warn_enabled = 0; - } - - return (0); -} - -/* - * Update information for the synthesis battery - * - * Note: Sometimes the value to be returned from _BST or _BIF will be - * temporarily unknown. In this case, the method may return the value - * 0xFFFFFFFF as a placeholder. When the value becomes known, the - * appropriate notification (0x80 for _BST or 0x81 for BIF) should be - * issued, in like manner to any other change in the data returned by - * these methods. This will cause OSPM to re-evaluate the method obtaining - * the correct data value. - */ -static void -batt_update_cap(int bif_changed) -{ - struct batt_cbat_state *bp; - - if (bif_changed != 0) { - batt_syn_oem_warn_cap = 0xffffffff; - batt_syn_oem_low_cap = 0xffffffff; - batt_syn_last_cap = 0xffffffff; - } - batt_syn_last_level = batt_syn_rem_cap; - batt_syn_rem_cap = 0xffffffff; /* initially unknown */ - - for (bp = &batt_cbat[0]; bp < &batt_cbat[BATT_MAX_BAT_NUM]; bp++) { - if (bp->dev.valid) { - /* Escape the empty bays */ - if (batt_cbat_present(bp) <= 0) { - continue; - } - - if (bif_changed != 0 && bp->bat_bifok == BATT_NTF_OK) { - acpi_bif_t *bif; - - bif = &bp->bif_cache; - - if (batt_syn_last_cap == 0xffffffff) { - batt_syn_last_cap = 0; - } - batt_syn_last_cap += bif->bif_last_cap; - - if (bif->bif_warn_cap == 0xffffffff || - bif->bif_low_cap == 0xffffffff) { - BATT_DBG(CE_WARN, &bp->dev, "BIF value " - "invalid, warn_cap=0x%x " - "low_cap=0x%x", bif->bif_warn_cap, - bif->bif_low_cap); - continue; - } - if (batt_syn_oem_warn_cap == 0xffffffff) { - batt_syn_oem_warn_cap = 0; - } - if (batt_syn_oem_low_cap == 0xffffffff) { - batt_syn_oem_low_cap = 0; - } - - /* - * Use the highest level as the synthesis - * level. - */ - if (bif->bif_warn_cap > batt_syn_oem_warn_cap) { - batt_syn_oem_low_cap = bif->bif_low_cap; - batt_syn_oem_warn_cap = - bif->bif_warn_cap; - } - } -#ifdef DEBUG - else if (bif_changed) { - BATT_DBG(CE_NOTE, &bp->dev, "BIF not ready"); - } -#endif - - if (bp->bat_bstok == BATT_NTF_OK) { - acpi_bst_t *bst; - - bst = &bp->bst_cache; - - /* - * Batteries that are rechargeable and are in - * the discharging state are required to return - * a valid Battery Present Rate value. - * 0xFFFFFFFF - Unknown rate/capacity - */ - if (bst->bst_rem_cap == 0xffffffff) { - BATT_DBG(CE_WARN, &bp->dev, - "BST value invalid, " - "rate=0x%x cap=0x%x", - bst->bst_rate, bst->bst_rem_cap); - continue; - } - - if (batt_syn_rem_cap == 0xffffffff) { - batt_syn_rem_cap = 0; - } - batt_syn_rem_cap += bst->bst_rem_cap; - /* Check for overflow */ - ASSERT(batt_syn_rem_cap >= bst->bst_rem_cap); - } -#ifdef DEBUG - else { - BATT_DBG(CE_NOTE, &bp->dev, "BST not ready"); - } -#endif - } - } - - BATT_DBG(CE_NOTE, NULL, "syn_cap: %d syn_oem_warn: %d syn_oem_low: %d", - batt_syn_rem_cap, batt_syn_oem_warn_cap, batt_syn_oem_low_cap); -} - -static struct batt_cbat_state * -batt_idx2cbat(int idx) -{ - if (idx >= BATT_MAX_BAT_NUM) { - return (NULL); - } - return (&batt_cbat[idx]); -} - -static struct batt_ac_state * -batt_idx2ac(int idx) -{ - if (idx >= BATT_MAX_AC_NUM) { - return (NULL); - } - return (&batt_ac[idx]); -} - -/*ARGSUSED*/ -static void -batt_cbat_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx) -{ - struct batt_cbat_state *bp = ctx; - struct batt_acpi_dev *devp = &bp->dev; - int bif_changed; - uint32_t eval; - char *ev; - acpi_bst_t *bst; - - BATT_PRT_NOTIFY(hdl, val); - mutex_enter(&batt_mutex); - - switch (val) { - /* - * BST has changed - * Whenever the Battery State value changes, the - * system will generate an SCI to notify the OS. - * - * Note: trip point is not used to implement the - * warning levels. - */ - case 0x80: - /* - * We always get 0x80 and 0x81 at battery plug/unplug, - * but 0x80 may come first. In case that situation, we have - * to update battery present state here too to update bst - * correctly. - */ - bif_changed = batt_update_present(devp); - - /* Omit events sent by empty battery slot */ - if (devp->present == 0) { - break; - } - - if (batt_update_bst(bp) != BATT_OK) { - break; - } - batt_update_cap(bif_changed); - - bst = &bp->bst_cache; - eval = bst->bst_rem_cap; - - /* - * Keep tracking the current power source device - * - * Note: Even no battery plugged, some system - * send out 0x80 ACPI event. So make sure the battery - * is present first. - */ - if (devp->present == 0) { - if (batt_psr_devp == devp) { - batt_set_psr(NULL); - } - break; - } - if (bst->bst_state & BST_FLAG_DISCHARGING) { - batt_set_psr(devp); - } - /* - * The Critical battery state indicates that all - * available batteries are discharged and do not - * appear to be able to supply power to run the - * system any longer. When this occurs, the OS - * should attempt to perform an emergency shutdown. - * Right now we do not shutdown. This would - * need some discussion first since it could be - * controversial. - */ -#ifdef DEBUG - if (bst->bst_state & BST_FLAG_CRITICAL) { - BATT_DBG(CE_WARN, devp, "BST_FLAG_CRITICAL set"); - - /* - * BST_FLAG_CRITICAL may set even with AC, - * plugged, when plug/unplug battery. Check - * to avoid erroneous shutdown. - */ - if (batt_psr_devp == devp && - bst->bst_rem_cap != 0xffffffff) { - BATT_DBG(CE_WARN, NULL, - "Battery in critical state"); - } - } else -#endif - if (batt_warn_enabled && - (bst->bst_state & BST_FLAG_DISCHARGING)) { - /* - * This value is an estimation of the amount of - * energy or battery capacity required by the - * system to transition to any supported sleeping - * state. When the OS detects that the total - * available battery capacity is less than this - * value, it will transition the system to a user - * defined system state (S1-S5). - */ - if (batt_syn_last_level > batt_syn_low_cap && - batt_syn_rem_cap <= batt_syn_low_cap) { - batt_gen_sysevent(devp, ESC_ACPIEV_LOW, eval); - /* - * When the total available energy (mWh) or capacity - * (mAh) in the batteries falls below this level, - * the OS will notify the user through the UI. - */ - } else if (batt_syn_last_level > batt_syn_warn_cap && - batt_syn_rem_cap <= batt_syn_warn_cap) { - batt_gen_sysevent(devp, ESC_ACPIEV_WARN, eval); - } - } - - batt_gen_sysevent(devp, ESC_ACPIEV_STATE_CHANGE, 0); - pollwakeup(&batt_pollhead, BATT_EVENTS); - break; - - /* BIF has changed */ - case 0x81: - /* - * Note: Do not eliminate multiple ADD/REMOVE here, - * because they may corresponding to different batterys. - */ - (void) batt_update_present(devp); - if (devp->present == 1) { - if (batt_update_bif(bp) != BATT_OK) { - break; - } - } else { - bp->bat_bifok = BATT_NTF_UNKNOWN; - bp->bat_bstok = BATT_NTF_UNKNOWN; - } - - batt_update_cap(1); - - eval = devp->present; - ev = eval ? ESC_ACPIEV_ADD : ESC_ACPIEV_REMOVE; - batt_gen_sysevent(devp, ev, 0); - pollwakeup(&batt_pollhead, BATT_EVENTS); - break; - - case 0x82: - default: - break; - } - - mutex_exit(&batt_mutex); -} - -/*ARGSUSED*/ -static void -batt_ac_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx) -{ - struct batt_ac_state *acp = ctx; - struct batt_acpi_dev *devp = &acp->dev; - int old_present; - char *ev; - int eval; - - BATT_PRT_NOTIFY(hdl, val); - if (val != 0x80) { - return; - } - mutex_enter(&batt_mutex); - - /* - * Note: if unplug and then quickly plug back, two ADD - * events will be generated. - */ - old_present = devp->present; - eval = batt_get_psr(acp); - - /* Eliminate redudant events */ - if (eval != -1 && eval != old_present) { - /* Keep tracking the current power source device */ - if (eval == 1) { - ev = ESC_ACPIEV_ADD; - batt_set_psr(devp); - } else { - ev = ESC_ACPIEV_REMOVE; - /* If AC was supplying the power, it's not now */ - if (batt_psr_devp == devp) { - batt_set_psr(NULL); - } - } - - batt_gen_sysevent(devp, ev, 0); - pollwakeup(&batt_pollhead, BATT_EVENTS); - } - - mutex_exit(&batt_mutex); -} - -static int -batt_obj_init(struct batt_acpi_dev *p) -{ - ACPI_DEVICE_INFO *info; - ACPI_HANDLE hdl; - ACPI_BUFFER buf; - ACPI_NOTIFY_HANDLER ntf_handler = NULL; - ACPI_STATUS ret; - - ASSERT(p != NULL && p->hdl != NULL); - - hdl = p->hdl; - - /* Info size is variable depending on existance of _CID */ - buf.Length = ACPI_ALLOCATE_BUFFER; - ret = AcpiGetObjectInfo(hdl, &buf); - if (ACPI_FAILURE(ret)) { - BATT_DBG(CE_WARN, NULL, - "AcpiGetObjectInfo() fail: %d", (int32_t)ret); - return (BATT_ERR); - } - - info = buf.Pointer; - - if ((info->Valid & ACPI_VALID_HID) == 0) { - BATT_DBG(CE_WARN, NULL, - "AcpiGetObjectInfo(): _HID not available"); - AcpiOsFree(info); - return (BATT_ERR); - } - (void) strncpy(p->hid, info->HardwareId.Value, 9); - - /* - * This object is optional, but is required when the device - * has no other way to report a persistent unique device ID. - */ - if ((info->Valid & ACPI_VALID_UID) == 0) { - BATT_DBG(CE_WARN, NULL, - "AcpiGetObjectInfo(): _UID not available"); - /* Use 0 as the default _UID */ - (void) strncpy(p->uid, "0", 9); - } else { - (void) strncpy(p->uid, info->UniqueId.Value, 9); - } - - p->valid = 1; - p->type = BATT_TYPE_UNKNOWN; - - if (strcmp(p->hid, ACPI_DEVNAME_CBAT) == 0) { - struct batt_cbat_state *bp = (struct batt_cbat_state *)p; - - p->type = BATT_TYPE_CBAT; - p->index = nbat - 1; - bp->bat_bifok = BATT_NTF_UNKNOWN; - bp->bat_bstok = BATT_NTF_UNKNOWN; - - /* Update device present state */ - (void) batt_update_present(p); - if (p->present) { - (void) batt_update_bif(bp); - (void) batt_update_bst(bp); - - /* Init the current power source */ - if (bp->bst_cache.bst_state & BST_FLAG_DISCHARGING) { - batt_set_psr(p); - } - } - ntf_handler = batt_cbat_notify; - BATT_DBG(CE_NOTE, p, "battery %s", - (p->present ? "present" : "absent")); - } else if (strcmp(p->hid, ACPI_DEVNAME_AC) == 0) { - p->type = BATT_TYPE_AC; - p->index = nac - 1; - - /* Update device present state */ - (void) batt_update_present(p); - if (p->present) { - /* Init the current power source */ - batt_set_psr(p); - } - ntf_handler = batt_ac_notify; - BATT_DBG(CE_NOTE, p, "AC %s", - (p->present ? "on-line" : "off-line")); - } else if (strcmp(p->hid, ACPI_DEVNAME_SBAT) == 0) { - p->type = BATT_TYPE_SBAT; - BATT_DBG(CE_NOTE, p, "added"); - } else { - BATT_DBG(CE_NOTE, p, "unknown device"); - p->valid = 0; - } - - /* Register ACPI battery related events */ - if (ntf_handler != NULL) { - if (ACPI_FAILURE(AcpiInstallNotifyHandler(hdl, - ACPI_ALL_NOTIFY, ntf_handler, p))) { - BATT_DBG(CE_NOTE, NULL, - "Notify handler for %s.%s install failed", - p->hid, p->uid); - return (BATT_ERR); - } - } - -out: - AcpiOsFree(info); - return (BATT_OK); -} - -/*ARGSUSED*/ -static ACPI_STATUS -batt_find_cb(ACPI_HANDLE ObjHandle, UINT32 NestingLevel, void *Context, - void **ReturnValue) -{ - struct batt_acpi_dev *devp = (struct batt_acpi_dev *)Context; - - if (devp == &batt_cbat[0].dev) { - struct batt_cbat_state *bp; - - if (nbat == BATT_MAX_BAT_NUM) { - BATT_DBG(CE_WARN, NULL, - "Need to support more batteries: " - "BATTERY_MAX = %d", BATT_MAX_BAT_NUM); - return (AE_LIMIT); - } - bp = &batt_cbat[nbat++]; - devp = (struct batt_acpi_dev *)bp; - } else if (devp == &batt_ac[0].dev) { - struct batt_ac_state *ap; - - if (nac == BATT_MAX_AC_NUM) { - BATT_DBG(CE_WARN, NULL, "Need to support more ACs: " - "AC_MAX = %d", BATT_MAX_AC_NUM); - return (AE_LIMIT); - } - ap = &batt_ac[nac++]; - devp = (struct batt_acpi_dev *)ap; - } - - devp->hdl = ObjHandle; - *ReturnValue = NULL; - - /* Try to get as many working objs as possible */ - (void) batt_obj_init(devp); - return (0); -} - -static int -batt_acpi_init() -{ - int *retp; - - /* Check to see if ACPI CA services are available */ - if (AcpiSubsystemStatus() != AE_OK) { - BATT_DBG(CE_WARN, NULL, "ACPI CA not ready"); - return (BATT_ERR); - } - - /* Init Control Method Batterys */ - if (ACPI_FAILURE(AcpiGetDevices(ACPI_DEVNAME_CBAT, batt_find_cb, - batt_cbat, (void *)&retp))) { - return (BATT_ERR); - } - - /* Init AC */ - if (ACPI_FAILURE(AcpiGetDevices(ACPI_DEVNAME_AC, batt_find_cb, batt_ac, - (void *)&retp))) { - return (BATT_ERR); - } - - /* Init Smart Battery */ - if (ACPI_FAILURE(AcpiGetDevices(ACPI_DEVNAME_SBAT, batt_find_cb, - &batt_sbat, (void *)&retp))) { - return (BATT_ERR); - } - - batt_update_cap(1); - - return (BATT_OK); -} - -static void -batt_acpi_fini(void) -{ - int i; - struct batt_cbat_state *bp; - - for (bp = &batt_cbat[0]; bp < &batt_cbat[BATT_MAX_BAT_NUM]; bp++) { - if (bp->dev.valid) { - AcpiRemoveNotifyHandler(bp->dev.hdl, ACPI_DEVICE_NOTIFY, - batt_cbat_notify); - } - } - for (i = 0; i < nac; i++) { - AcpiRemoveNotifyHandler(batt_ac[i].dev.hdl, ACPI_DEVICE_NOTIFY, - batt_ac_notify); - } -} - -/*ARGSUSED*/ -static int -batt_kstat_power_update(kstat_t *ksp, int flag) -{ - if (flag == KSTAT_WRITE) { - return (EACCES); - } - - mutex_enter(&batt_mutex); - if (batt_psr_type == BATT_TYPE_UNKNOWN) { - mutex_exit(&batt_mutex); - return (EIO); - } - kstat_named_setstr(&batt_power_kstat.batt_power, - batt_psr_type == BATT_TYPE_AC ? AC : BATTERY); - batt_power_kstat.batt_supported_battery_count.value.ui32 = - (uint32_t)nbat; - mutex_exit(&batt_mutex); - - return (0); -} - -/*ARGSUSED*/ -static int -batt_kstat_warn_update(kstat_t *ksp, int flag) -{ - if (flag == KSTAT_WRITE) { - int ret = 0; - batt_warn_t bw; - batt_warn_kstat_t kbw; - - kbw = *(batt_warn_kstat_t *)batt_warn_ksp->ks_data; - - mutex_enter(&batt_mutex); - bw.bw_enabled = kbw.batt_bw_enabled.value.ui32; - bw.bw_charge_warn = kbw.batt_bw_charge_warn.value.ui32; - bw.bw_charge_low = kbw.batt_bw_charge_low.value.ui32; - ret = batt_set_warn(&bw); - mutex_exit(&batt_mutex); - - return (ret); - } else { - batt_warn_kstat_t *wp = &batt_warn_kstat; - - mutex_enter(&batt_mutex); - wp->batt_bw_enabled.value.ui32 = batt_warn_enabled; - wp->batt_bw_charge_warn.value.ui32 = batt_syn_warn_per; - wp->batt_bw_charge_low.value.ui32 = batt_syn_low_per; - mutex_exit(&batt_mutex); - - return (0); - } -} - -static int -batt_kstat_bif_update(kstat_t *ksp, int flag) -{ - struct batt_cbat_state *bp; - acpi_bif_t bif; - batt_bif_kstat_t *kp; - - if (flag == KSTAT_WRITE) { - return (EACCES); - } - - bp = (struct batt_cbat_state *)ksp->ks_private; - mutex_enter(&batt_mutex); - - if (batt_cbat_present(bp) <= 0) { - mutex_exit(&batt_mutex); - return (ENXIO); - } - - bzero(&bif, sizeof (bif)); - bp->bat_bifok = BATT_NTF_UNKNOWN; - if (batt_get_bif(&bif, bp) != BATT_OK) { - mutex_exit(&batt_mutex); - return (ENXIO); - } - - kp = &batt_bif_kstat; - - /* Update BIF */ - kp->batt_bif_unit.value.ui32 = bif.bif_unit; - kp->batt_bif_design_cap.value.ui32 = bif.bif_design_cap; - kp->batt_bif_last_cap.value.ui32 = bif.bif_last_cap; - kp->batt_bif_tech.value.ui32 = bif.bif_tech; - kp->batt_bif_voltage.value.ui32 = bif.bif_voltage; - kp->batt_bif_warn_cap.value.ui32 = bif.bif_warn_cap; - kp->batt_bif_low_cap.value.ui32 = bif.bif_low_cap; - kp->batt_bif_gran1_cap.value.ui32 = bif.bif_gran1_cap; - kp->batt_bif_gran2_cap.value.ui32 = bif.bif_gran2_cap; - - kstat_named_setstr(&kp->batt_bif_model, bif.bif_model); - kstat_named_setstr(&kp->batt_bif_serial, bif.bif_serial); - kstat_named_setstr(&kp->batt_bif_type, bif.bif_type); - kstat_named_setstr(&kp->batt_bif_oem_info, bif.bif_oem_info); - - mutex_exit(&batt_mutex); - return (0); -} - -static int -batt_kstat_bst_update(kstat_t *ksp, int flag) -{ - struct batt_cbat_state *bp; - acpi_bst_t bst; - batt_bst_kstat_t *kp; - - if (flag == KSTAT_WRITE) { - return (EACCES); - } - - bp = (struct batt_cbat_state *)ksp->ks_private; - mutex_enter(&batt_mutex); - - if (batt_cbat_present(bp) <= 0) { - mutex_exit(&batt_mutex); - return (ENXIO); - } - - bzero(&bst, sizeof (bst)); - bp->bat_bstok = BATT_NTF_UNKNOWN; - if (batt_get_bst(&bst, bp) != BATT_OK) { - mutex_exit(&batt_mutex); - return (ENXIO); - } - - kp = &batt_bst_kstat; - - /* Update BST */ - kp->batt_bst_state.value.ui32 = bst.bst_state; - kp->batt_bst_rate.value.ui32 = bst.bst_rate; - kp->batt_bst_rem_cap.value.ui32 = bst.bst_rem_cap; - kp->batt_bst_voltage.value.ui32 = bst.bst_voltage; - - mutex_exit(&batt_mutex); - return (0); -} - -static int -batt_kstat_init(void) -{ - char name[KSTAT_STRLEN]; - struct batt_cbat_state *bp; - - /* - * Allocate, initialize and install powerstatus and - * supported_battery_count kstat. - */ - batt_power_ksp = kstat_create(BATT_DRV_NAME, 0, - BATT_POWER_KSTAT_NAME, "misc", - KSTAT_TYPE_NAMED, - sizeof (batt_power_kstat) / sizeof (kstat_named_t), - KSTAT_FLAG_VIRTUAL); - if (batt_power_ksp == NULL) { - BATT_DBG(CE_WARN, NULL, - "kstat_create(%s) fail", BATT_POWER_KSTAT_NAME); - return (BATT_ERR); - } - - batt_power_ksp->ks_data = &batt_power_kstat; - batt_power_ksp->ks_update = batt_kstat_power_update; - batt_power_ksp->ks_data_size += MAXNAMELEN; - kstat_install(batt_power_ksp); - - /* - * Allocate, initialize and install battery_capacity_warning kstat. - */ - batt_warn_ksp = kstat_create(BATT_DRV_NAME, 0, - BATT_BTWARN_KSTAT_NAME, "misc", - KSTAT_TYPE_NAMED, - sizeof (batt_warn_kstat) / sizeof (kstat_named_t), - KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE); - if (batt_warn_ksp == NULL) { - BATT_DBG(CE_WARN, NULL, - "kstat_create(%s) fail", BATT_BTWARN_KSTAT_NAME); - return (BATT_ERR); - } - - batt_warn_ksp->ks_data = &batt_warn_kstat; - batt_warn_ksp->ks_update = batt_kstat_warn_update; - kstat_install(batt_warn_ksp); - - /* - * Allocate, initialize and install BIF and BST kstat - * for each battery. - */ - for (bp = &batt_cbat[0]; bp < &batt_cbat[BATT_MAX_BAT_NUM]; bp++) { - if (bp->dev.valid) { - kstat_t *ksp; - - /* BIF kstat */ - (void) snprintf(name, KSTAT_STRLEN-1, "%s%d", - BATT_BIF_KSTAT_NAME, bp->dev.index); - ksp = kstat_create(BATT_DRV_NAME, 0, - name, "misc", KSTAT_TYPE_NAMED, - sizeof (batt_bif_kstat) / sizeof (kstat_named_t), - KSTAT_FLAG_VIRTUAL); - if (ksp == NULL) { - BATT_DBG(CE_WARN, NULL, "kstat_create(%s) fail", - name); - return (BATT_ERR); - } - BATT_DBG(CE_NOTE, NULL, "kstat_create(%s) ok", name); - - bp->bat_bif_ksp = ksp; - ksp->ks_data = &batt_bif_kstat; - ksp->ks_update = batt_kstat_bif_update; - ksp->ks_data_size += MAXNAMELEN * 4; - ksp->ks_private = bp; - - kstat_install(ksp); - - /* BST kstat */ - (void) snprintf(name, KSTAT_STRLEN-1, "%s%d", - BATT_BST_KSTAT_NAME, bp->dev.index); - ksp = kstat_create(BATT_DRV_NAME, 0, name, "misc", - KSTAT_TYPE_NAMED, - sizeof (batt_bst_kstat) / sizeof (kstat_named_t), - KSTAT_FLAG_VIRTUAL); - if (ksp == NULL) { - BATT_DBG(CE_WARN, NULL, - "kstat_create(%s) fail", name); - return (BATT_ERR); - } - BATT_DBG(CE_NOTE, NULL, "kstat_create(%s) ok", name); - - bp->bat_bst_ksp = ksp; - ksp->ks_data = &batt_bst_kstat; - ksp->ks_update = batt_kstat_bst_update; - ksp->ks_data_size += MAXNAMELEN * 4; - ksp->ks_private = bp; - - kstat_install(ksp); - } - } - - return (BATT_OK); -} - -static void -batt_kstat_fini() -{ - struct batt_cbat_state *bp; - - if (batt_power_ksp != NULL) { - kstat_delete(batt_power_ksp); - } - if (batt_warn_ksp != NULL) { - kstat_delete(batt_warn_ksp); - } - for (bp = &batt_cbat[0]; bp < &batt_cbat[BATT_MAX_BAT_NUM]; bp++) { - if (bp->dev.valid) { - if (bp->bat_bif_ksp != NULL) { - kstat_delete(bp->bat_bif_ksp); - } - if (bp->bat_bst_ksp != NULL) { - kstat_delete(bp->bat_bst_ksp); - } - } - } -} diff --git a/usr/src/uts/intel/os/minor_perm b/usr/src/uts/intel/os/minor_perm index dd4a22c682..93b00060fd 100644 --- a/usr/src/uts/intel/os/minor_perm +++ b/usr/src/uts/intel/os/minor_perm @@ -162,7 +162,7 @@ rtw:* 0666 root sys wpi:* 0666 root sys physmem:* 0600 root sys sdp:sdp 0666 root sys -battery:* 0666 root sys +acpi_drv:* 0666 root sys ucode:* 0644 root sys dmfe:* 0666 root sys afe:* 0666 root sys diff --git a/usr/src/uts/intel/os/name_to_major b/usr/src/uts/intel/os/name_to_major index efa9f0428f..03d52f9e68 100644 --- a/usr/src/uts/intel/os/name_to_major +++ b/usr/src/uts/intel/os/name_to_major @@ -136,7 +136,7 @@ lx_ptm 240 lx_systrace 241 lx_audio 242 physmem 243 -battery 244 +acpi_drv 244 ucode 245 ppm 246 cpunex 247 |