xref: /onnv-gate/usr/src/uts/i86pc/io/acpi_drv/acpi_drv.c (revision 12004:93f274d4a367)
16573Sphitran /*
26573Sphitran  * CDDL HEADER START
36573Sphitran  *
46573Sphitran  * The contents of this file are subject to the terms of the
56573Sphitran  * Common Development and Distribution License (the "License").
66573Sphitran  * You may not use this file except in compliance with the License.
76573Sphitran  *
86573Sphitran  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96573Sphitran  * or http://www.opensolaris.org/os/licensing.
106573Sphitran  * See the License for the specific language governing permissions
116573Sphitran  * and limitations under the License.
126573Sphitran  *
136573Sphitran  * When distributing Covered Code, include this CDDL HEADER in each
146573Sphitran  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156573Sphitran  * If applicable, add the following below this CDDL HEADER, with the
166573Sphitran  * fields enclosed by brackets "[]" replaced with your own identifying
176573Sphitran  * information: Portions Copyright [yyyy] [name of copyright owner]
186573Sphitran  *
196573Sphitran  * CDDL HEADER END
206573Sphitran  */
216573Sphitran 
226573Sphitran /*
238693SKerry.Shu@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
246573Sphitran  * Use is subject to license terms.
256573Sphitran  */
266573Sphitran 
276573Sphitran /*
288693SKerry.Shu@Sun.COM  * Driver for ACPI Battery, Lid, and Hotkey Control
296573Sphitran  */
308693SKerry.Shu@Sun.COM #include <sys/hotkey_drv.h>
316573Sphitran #include <sys/sysevent/pwrctl.h>
326573Sphitran 
336573Sphitran 
346573Sphitran #define	ACPI_DRV_MOD_STRING		"ACPI driver"
356573Sphitran 
366573Sphitran #define	MINOR_SHIFT			8
376573Sphitran #define	IDX_MASK			((1 << MINOR_SHIFT) - 1)
386573Sphitran #define	MINOR_BATT(idx)			(ACPI_DRV_TYPE_CBAT << MINOR_SHIFT | \
396573Sphitran 					(idx))
406573Sphitran #define	MINOR_AC(idx)			(ACPI_DRV_TYPE_AC << MINOR_SHIFT | \
416573Sphitran 					(idx))
426573Sphitran #define	MINOR_LID(idx)			(ACPI_DRV_TYPE_LID << MINOR_SHIFT | \
436573Sphitran 					(idx))
448693SKerry.Shu@Sun.COM #define	MINOR_HOTKEY(idx)		(ACPI_DRV_TYPE_HOTKEY << MINOR_SHIFT \
456573Sphitran 					| (idx))
466573Sphitran #define	MINOR2IDX(minor)		((minor) & IDX_MASK)
476573Sphitran #define	MINOR2TYPE(minor)		((minor) >> MINOR_SHIFT)
486573Sphitran 
496573Sphitran #define	ACPI_DRV_MAX_BAT_NUM		8
506573Sphitran #define	ACPI_DRV_MAX_AC_NUM		10
516573Sphitran 
526573Sphitran #define	BST_FLAG_DISCHARGING		(0x1)
536573Sphitran #define	BST_FLAG_CHARGING		(0x2)
546573Sphitran #define	BST_FLAG_CRITICAL		(0x4)
556573Sphitran 
566573Sphitran /* Set if the battery is present */
576573Sphitran #define	STA_FLAG_BATT_PRESENT		(0x10)
586573Sphitran 
596573Sphitran #define	ACPI_DEVNAME_CBAT		"PNP0C0A"
606573Sphitran #define	ACPI_DEVNAME_AC			"ACPI0003"
616573Sphitran #define	ACPI_DEVNAME_LID		"PNP0C0D"
626573Sphitran 
636573Sphitran #define	ACPI_DRV_EVENTS			(POLLIN | POLLRDNORM)
646573Sphitran 
656573Sphitran #ifdef DEBUG
666573Sphitran 
676573Sphitran #define	ACPI_DRV_PRINT_BUFFER_SIZE	512
686573Sphitran static char acpi_drv_prt_buf[ACPI_DRV_PRINT_BUFFER_SIZE];
696573Sphitran static kmutex_t acpi_drv_prt_mutex;
706573Sphitran 
716573Sphitran static int acpi_drv_debug = 0;
726573Sphitran #define	ACPI_DRV_DBG(lev, devp, ...) \
736573Sphitran 	do { \
746573Sphitran 		if (acpi_drv_debug) acpi_drv_printf((devp), \
756573Sphitran (lev), __VA_ARGS__); \
766573Sphitran _NOTE(CONSTCOND) } while (0)
776573Sphitran #define	ACPI_DRV_PRT_NOTIFY(hdl, val) \
786573Sphitran 	do { \
796573Sphitran 		if (acpi_drv_debug) acpi_drv_prt_notify((hdl), (val)); \
806573Sphitran _NOTE(CONSTCOND) } while (0)
816573Sphitran 
826573Sphitran #else
836573Sphitran 
846573Sphitran #define	ACPI_DRV_DBG(lev, devp, ...)
856573Sphitran #define	ACPI_DRV_PRT_NOTIFY(hdl, val)
866573Sphitran 
876573Sphitran #endif /* DEBUG */
886573Sphitran 
896573Sphitran /* ACPI notify types */
906573Sphitran enum acpi_drv_notify {
916573Sphitran 	ACPI_DRV_NTF_UNKNOWN = -1,	/* No notifications seen, ever. */
926573Sphitran 	ACPI_DRV_NTF_CHANGED,
936573Sphitran 	ACPI_DRV_NTF_OK
946573Sphitran };
956573Sphitran 
966573Sphitran static int acpi_drv_dev_present(struct acpi_drv_dev *);
976573Sphitran #define	acpi_drv_ac_present(a)	(((a)->dev.type == ACPI_DRV_TYPE_AC) ? \
986573Sphitran 				acpi_drv_dev_present(&(a)->dev) : -1)
996573Sphitran #define	acpi_drv_cbat_present(a)	(((a)->dev.type == ACPI_DRV_TYPE_CBAT) \
1006573Sphitran 					? acpi_drv_dev_present(&(a)->dev) : -1)
1016573Sphitran 
1026573Sphitran static dev_info_t *acpi_drv_dip = NULL;
1036573Sphitran static kmutex_t acpi_drv_mutex;
1046573Sphitran static struct pollhead acpi_drv_pollhead;
1056573Sphitran 
1066573Sphitran /* Control Method Battery state */
1076573Sphitran struct acpi_drv_cbat_state {
1086573Sphitran 	struct acpi_drv_dev dev;
1096573Sphitran 	/* Caches of _BST and _BIF */
1106573Sphitran 	enum acpi_drv_notify bat_bifok;
1116573Sphitran 	acpi_bif_t bif_cache;
1126573Sphitran 	enum acpi_drv_notify bat_bstok;
1136573Sphitran 	acpi_bst_t bst_cache;
1146573Sphitran 
1156573Sphitran 	uint32_t charge_warn;
1166573Sphitran 	uint32_t charge_low;
1176573Sphitran 
1186573Sphitran 	kstat_t *bat_bif_ksp;
1196573Sphitran 	kstat_t *bat_bst_ksp;
1206573Sphitran } acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
1217051Sphitran static int nbat = 0;
1226573Sphitran 
1236573Sphitran /*
1246573Sphitran  * Synthesis battery state
1256573Sphitran  * When there are multiple batteries present, the battery subsystem
1266573Sphitran  * is not required to perform any synthesis of a composite battery
1276573Sphitran  * from the data of the separate batteries. In cases where the
1286573Sphitran  * battery subsystem does not synthesize a composite battery from
1296573Sphitran  * the separate battery's data, the OS must provide that synthesis.
1306573Sphitran  */
1316573Sphitran static uint32_t acpi_drv_syn_rem_cap;
1326573Sphitran static uint32_t acpi_drv_syn_last_cap;
1336573Sphitran static uint32_t acpi_drv_syn_oem_warn_cap;
1346573Sphitran static uint32_t acpi_drv_syn_oem_low_cap;
1356573Sphitran 
1366573Sphitran static int acpi_drv_warn_enabled;
1376573Sphitran static uint32_t acpi_drv_syn_warn_per;
1386573Sphitran static uint32_t acpi_drv_syn_low_per;
1396573Sphitran static uint32_t acpi_drv_syn_warn_cap;
1406573Sphitran static uint32_t acpi_drv_syn_low_cap;
1416573Sphitran /* Tracking boundery passing of _BST charge levels */
1426573Sphitran static uint32_t acpi_drv_syn_last_level;
1436573Sphitran 
1446573Sphitran /* AC state */
1456573Sphitran static struct acpi_drv_ac_state {
1466573Sphitran 	struct acpi_drv_dev dev;
1476573Sphitran } acpi_drv_ac[ACPI_DRV_MAX_AC_NUM];
1487051Sphitran static int nac = 0;
1496573Sphitran 
1506573Sphitran /*
1516573Sphitran  * Current power source device
1526573Sphitran  * Note: assume only one device can be the power source device.
1536573Sphitran  */
1546573Sphitran static int acpi_drv_psr_type = ACPI_DRV_TYPE_UNKNOWN;
1556573Sphitran static struct acpi_drv_dev *acpi_drv_psr_devp = NULL;
1566573Sphitran 
1576573Sphitran struct obj_desc {
1586573Sphitran 	char *name;
1596573Sphitran 	int offset;
1606573Sphitran 	int size;
1616573Sphitran 	int type;
1626573Sphitran };
1636573Sphitran 
1646573Sphitran /* Object copy definitions */
1656573Sphitran #define	OFFSETOF(s, m)		((size_t)(&(((s *)0)->m)))
1666573Sphitran #define	SIZEOF(s, m)		(sizeof (((s *)0)->m))
1676573Sphitran #define	FIELD(n, s, m, t) \
1686573Sphitran 	{ n, OFFSETOF(s, m), SIZEOF(s, m), t }
1696573Sphitran #define	FIELD_NULL		{ NULL, -1, 0, ACPI_TYPE_ANY }
1706573Sphitran 
1716573Sphitran static struct obj_desc bif_desc[] = {
1726573Sphitran 	FIELD("bif_unit",	acpi_bif_t, bif_unit,	ACPI_TYPE_INTEGER),
1736573Sphitran 	FIELD("bif_design_cap", acpi_bif_t, bif_design_cap, ACPI_TYPE_INTEGER),
1746573Sphitran 	FIELD("bif_last_cap",	acpi_bif_t, bif_last_cap,   ACPI_TYPE_INTEGER),
1756573Sphitran 	FIELD("bif_tech",	acpi_bif_t, bif_tech,	ACPI_TYPE_INTEGER),
1766573Sphitran 	FIELD("bif_voltage",	acpi_bif_t, bif_voltage, ACPI_TYPE_INTEGER),
1776573Sphitran 	FIELD("bif_warn_cap",	acpi_bif_t, bif_warn_cap, ACPI_TYPE_INTEGER),
1786573Sphitran 	FIELD("bif_low_cap",	acpi_bif_t, bif_low_cap,  ACPI_TYPE_INTEGER),
1796573Sphitran 	FIELD("bif_gran1_cap",	acpi_bif_t, bif_gran1_cap, ACPI_TYPE_INTEGER),
1806573Sphitran 	FIELD("bif_gran2_cap",	acpi_bif_t, bif_gran2_cap, ACPI_TYPE_INTEGER),
1816573Sphitran 	FIELD("bif_model",	acpi_bif_t, bif_model,	ACPI_TYPE_STRING),
1826573Sphitran 	FIELD("bif_serial",	acpi_bif_t, bif_serial,	ACPI_TYPE_STRING),
1836573Sphitran 	FIELD("bif_type",	acpi_bif_t, bif_type,	ACPI_TYPE_STRING),
1846573Sphitran 	FIELD("bif_oem_info",	acpi_bif_t, bif_oem_info, ACPI_TYPE_STRING),
1856573Sphitran 	FIELD_NULL
1866573Sphitran };
1876573Sphitran 
1886573Sphitran static struct obj_desc bst_desc[] = {
1896573Sphitran 	FIELD("bst_state",   acpi_bst_t, bst_state,	ACPI_TYPE_INTEGER),
1906573Sphitran 	FIELD("bst_rate",    acpi_bst_t, bst_rate,	ACPI_TYPE_INTEGER),
1916573Sphitran 	FIELD("bst_rem_cap", acpi_bst_t, bst_rem_cap,	ACPI_TYPE_INTEGER),
1926573Sphitran 	FIELD("bst_voltage", acpi_bst_t, bst_voltage,	ACPI_TYPE_INTEGER),
1936573Sphitran 	FIELD_NULL
1946573Sphitran };
1956573Sphitran 
1966573Sphitran /* kstat definitions */
1976573Sphitran static kstat_t *acpi_drv_power_ksp;
1986573Sphitran static kstat_t *acpi_drv_warn_ksp;
1996573Sphitran 
2006573Sphitran acpi_drv_power_kstat_t acpi_drv_power_kstat = {
2016573Sphitran 	{ SYSTEM_POWER,			KSTAT_DATA_STRING },
2026573Sphitran 	{ SUPPORTED_BATTERY_COUNT,	KSTAT_DATA_UINT32 },
2036573Sphitran };
2046573Sphitran 
2056573Sphitran acpi_drv_warn_kstat_t acpi_drv_warn_kstat = {
2066573Sphitran 	{ BW_ENABLED,			KSTAT_DATA_UINT32 },
2076573Sphitran 	{ BW_POWEROFF_THRESHOLD,	KSTAT_DATA_UINT32 },
2086573Sphitran 	{ BW_SHUTDOWN_THRESHOLD,	KSTAT_DATA_UINT32 },
2096573Sphitran };
2106573Sphitran 
2116573Sphitran /* BIF */
2126573Sphitran acpi_drv_bif_kstat_t acpi_drv_bif_kstat = {
2136573Sphitran 	{ BIF_UNIT,		KSTAT_DATA_UINT32 },
2146573Sphitran 	{ BIF_DESIGN_CAP,	KSTAT_DATA_UINT32 },
2156573Sphitran 	{ BIF_LAST_CAP,		KSTAT_DATA_UINT32 },
2166573Sphitran 	{ BIF_TECH,		KSTAT_DATA_UINT32 },
2176573Sphitran 	{ BIF_VOLTAGE,		KSTAT_DATA_UINT32 },
2186573Sphitran 	{ BIF_WARN_CAP,		KSTAT_DATA_UINT32 },
2196573Sphitran 	{ BIF_LOW_CAP,		KSTAT_DATA_UINT32 },
2206573Sphitran 	{ BIF_GRAN1_CAP,	KSTAT_DATA_UINT32 },
2216573Sphitran 	{ BIF_GRAN2_CAP,	KSTAT_DATA_UINT32 },
2226573Sphitran 	{ BIF_MODEL,		KSTAT_DATA_STRING },
2236573Sphitran 	{ BIF_SERIAL,		KSTAT_DATA_STRING },
2246573Sphitran 	{ BIF_TYPE,		KSTAT_DATA_STRING },
2256573Sphitran 	{ BIF_OEM_INFO,		KSTAT_DATA_STRING },
2266573Sphitran };
2276573Sphitran 
2286573Sphitran /* BST */
2296573Sphitran acpi_drv_bst_kstat_t acpi_drv_bst_kstat = {
2306573Sphitran 	{ BST_STATE,		KSTAT_DATA_UINT32 },
2316573Sphitran 	{ BST_RATE,		KSTAT_DATA_UINT32 },
2326573Sphitran 	{ BST_REM_CAP,		KSTAT_DATA_UINT32 },
2336573Sphitran 	{ BST_VOLTAGE,		KSTAT_DATA_UINT32 },
2346573Sphitran };
2356573Sphitran 
2366573Sphitran struct acpi_drv_lid_state {
2376573Sphitran 	struct acpi_drv_dev dev;
2386573Sphitran 	enum acpi_drv_notify state_ok;
2396573Sphitran 	int state;
2406573Sphitran } lid;
2417051Sphitran static int nlid = 0;
2426573Sphitran 
2438693SKerry.Shu@Sun.COM struct hotkey_drv acpi_hotkey;
2446573Sphitran 
2456573Sphitran static int acpi_drv_attach(dev_info_t *devi, ddi_attach_cmd_t cmd);
2466573Sphitran static int acpi_drv_detach(dev_info_t *devi, ddi_detach_cmd_t cmd);
2476573Sphitran static int acpi_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg,
2486573Sphitran     void **resultp);
2496573Sphitran static int acpi_drv_open(dev_t *devp, int flag, int otyp, cred_t *crp);
2506573Sphitran static int acpi_drv_close(dev_t dev, int flag, int otyp, cred_t *crp);
2516573Sphitran static int acpi_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode,
2526573Sphitran     cred_t *cr, int *rval);
2536573Sphitran static int acpi_drv_chpoll(dev_t dev, short events, int anyyet,
2546573Sphitran     short *reventsp, struct pollhead **phpp);
2556573Sphitran static int acpi_drv_ac_ioctl(int index, int cmd, intptr_t arg, int mode,
2566573Sphitran     cred_t *cr, int *rval);
2576573Sphitran static int acpi_drv_cbat_ioctl(int index, int cmd, intptr_t arg, int mode,
2586573Sphitran     cred_t *cr, int *rval);
2596573Sphitran static int acpi_drv_lid_ioctl(int index, int cmd, intptr_t arg, int mode,
2606573Sphitran     cred_t *cr, int *rval);
2616573Sphitran #ifdef DEBUG
2626573Sphitran static void acpi_drv_printf(struct acpi_drv_dev *devp, uint_t lev,
2636573Sphitran     const char *fmt, ...);
2646573Sphitran #endif
2656573Sphitran 
2666573Sphitran static int acpi_drv_update_bif(struct acpi_drv_cbat_state *bp);
2676573Sphitran static int acpi_drv_update_bst(struct acpi_drv_cbat_state *bp);
2686573Sphitran static int acpi_drv_update_lid(struct acpi_drv_dev *bp);
2696573Sphitran static int acpi_drv_set_warn(acpi_drv_warn_t *bwp);
2706573Sphitran static struct acpi_drv_cbat_state *acpi_drv_idx2cbat(int idx);
2716573Sphitran static struct acpi_drv_ac_state *acpi_drv_idx2ac(int idx);
2726573Sphitran static int acpi_drv_acpi_init(void);
2736573Sphitran static void acpi_drv_acpi_fini(void);
2746573Sphitran static int acpi_drv_kstat_init(void);
2756573Sphitran static void acpi_drv_kstat_fini(void);
2766573Sphitran 
2776573Sphitran static struct cb_ops acpi_drv_cb_ops = {
2786573Sphitran 	acpi_drv_open,		/* open */
2796573Sphitran 	acpi_drv_close,		/* close */
2806573Sphitran 	nodev,			/* strategy */
2816573Sphitran 	nodev,			/* print */
2826573Sphitran 	nodev,			/* dump */
2836573Sphitran 	nodev,			/* read */
2846573Sphitran 	nodev,			/* write */
2856573Sphitran 	acpi_drv_ioctl,		/* ioctl */
2866573Sphitran 	nodev,			/* devmap */
2876573Sphitran 	nodev,			/* mmap */
2886573Sphitran 	nodev,			/* segmap */
2896573Sphitran 	acpi_drv_chpoll,		/* chpoll */
2906573Sphitran 	ddi_prop_op,		/* prop_op */
2916573Sphitran 	NULL,			/* streamtab */
2926573Sphitran 	D_NEW | D_MP,
2936573Sphitran 	CB_REV,
2946573Sphitran 	nodev,
2956573Sphitran 	nodev
2966573Sphitran };
2976573Sphitran 
2986573Sphitran static struct dev_ops acpi_drv_dev_ops = {
2996573Sphitran 	DEVO_REV,
3006573Sphitran 	0,			/* refcnt */
3018693SKerry.Shu@Sun.COM 	acpi_drv_getinfo,	/* getinfo */
3026573Sphitran 	nulldev,		/* identify */
3036573Sphitran 	nulldev,		/* probe */
3048693SKerry.Shu@Sun.COM 	acpi_drv_attach,	/* attach */
3058693SKerry.Shu@Sun.COM 	acpi_drv_detach,	/* detach */
3066573Sphitran 	nodev,			/* reset */
3076573Sphitran 	&acpi_drv_cb_ops,
3086573Sphitran 	NULL,			/* no bus operations */
3097656SSherry.Moore@Sun.COM 	NULL,			/* power */
3108693SKerry.Shu@Sun.COM 	ddi_quiesce_not_needed,	/* quiesce */
3116573Sphitran };
3126573Sphitran 
3136573Sphitran static struct modldrv modldrv1 = {
3146573Sphitran 	&mod_driverops,
3156573Sphitran 	ACPI_DRV_MOD_STRING,
3166573Sphitran 	&acpi_drv_dev_ops
3176573Sphitran };
3186573Sphitran 
3196573Sphitran static struct modlinkage modlinkage = {
3206573Sphitran 	MODREV_1,
3216573Sphitran 	(void *)&modldrv1,
3226573Sphitran 	NULL,
3236573Sphitran };
3246573Sphitran 
3256573Sphitran int
_init(void)3266573Sphitran _init(void)
3276573Sphitran {
3286573Sphitran 	int ret;
3296573Sphitran 
3306573Sphitran 	mutex_init(&acpi_drv_mutex, NULL, MUTEX_DRIVER, NULL);
3316573Sphitran #ifdef DEBUG
3326573Sphitran 	mutex_init(&acpi_drv_prt_mutex, NULL, MUTEX_DRIVER, NULL);
3336573Sphitran #endif
3346573Sphitran 
3356573Sphitran 	if ((ret = mod_install(&modlinkage)) != 0) {
3366573Sphitran 		mutex_destroy(&acpi_drv_mutex);
3376573Sphitran #ifdef DEBUG
3386573Sphitran 		mutex_destroy(&acpi_drv_prt_mutex);
3396573Sphitran #endif
3406573Sphitran 	}
3416573Sphitran 	return (ret);
3426573Sphitran }
3436573Sphitran 
3446573Sphitran int
_fini(void)3456573Sphitran _fini(void)
3466573Sphitran {
3476573Sphitran 	int ret;
3486573Sphitran 
3496573Sphitran 	if ((ret = mod_remove(&modlinkage)) == 0) {
3506573Sphitran #ifdef DEBUG
3516573Sphitran 		mutex_destroy(&acpi_drv_prt_mutex);
3526573Sphitran #endif
3536573Sphitran 		mutex_destroy(&acpi_drv_mutex);
3546573Sphitran 	}
3556573Sphitran 
3566573Sphitran 	return (ret);
3576573Sphitran }
3586573Sphitran 
3596573Sphitran int
_info(struct modinfo * mp)3606573Sphitran _info(struct modinfo *mp)
3616573Sphitran {
3626573Sphitran 	return (mod_info(&modlinkage, mp));
3636573Sphitran }
3646573Sphitran 
3656573Sphitran static int
acpi_drv_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)3666573Sphitran acpi_drv_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
3676573Sphitran {
3686573Sphitran 	char name[20];
3696573Sphitran 	int i;
3706573Sphitran 	struct acpi_drv_cbat_state *bp;
3716573Sphitran 
3726573Sphitran 	switch (cmd) {
3736573Sphitran 	case DDI_ATTACH:
3746573Sphitran 		/* Limit to one instance of driver */
3756573Sphitran 		if (acpi_drv_dip) {
3766573Sphitran 			return (DDI_FAILURE);
3776573Sphitran 		}
3786573Sphitran 		break;
3796573Sphitran 	case DDI_RESUME:
3806573Sphitran 	case DDI_PM_RESUME:
3816573Sphitran 		return (DDI_SUCCESS);
3826573Sphitran 	default:
3836573Sphitran 		return (DDI_FAILURE);
3846573Sphitran 	}
3856573Sphitran 
3866573Sphitran 	acpi_drv_dip = devi;
3876573Sphitran 
3886573Sphitran 	/* Init ACPI related stuff */
3896573Sphitran 	if (acpi_drv_acpi_init() != ACPI_DRV_OK) {
3906573Sphitran 		goto error;
3916573Sphitran 	}
3926573Sphitran 
3936573Sphitran 	/* Init kstat related stuff */
3946573Sphitran 	if (acpi_drv_kstat_init() != ACPI_DRV_OK) {
3956573Sphitran 		goto error;
3966573Sphitran 	}
3976573Sphitran 
3988693SKerry.Shu@Sun.COM 	/* Create minor node for hotkey device. */
3998693SKerry.Shu@Sun.COM 	if (ddi_create_minor_node(devi, "hotkey", S_IFCHR, MINOR_HOTKEY(0),
4006573Sphitran 	    DDI_PSEUDO, 0) == DDI_FAILURE) {
4018693SKerry.Shu@Sun.COM 		ACPI_DRV_DBG(CE_WARN, NULL, "hotkey: "
4026573Sphitran 		    "minor node create failed");
4036573Sphitran 		goto error;
4046573Sphitran 	}
4056573Sphitran 	/* Create minor node for lid. */
4066573Sphitran 	if (ddi_create_minor_node(devi, "lid", S_IFCHR, MINOR_LID(0),
4076573Sphitran 	    DDI_PSEUDO, 0) == DDI_FAILURE) {
4086573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "lid: minor node create failed");
4096573Sphitran 		goto error;
4106573Sphitran 	}
4116573Sphitran 	/* Create minor node for each battery and ac */
4126573Sphitran 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
4136573Sphitran 	    bp++) {
4146573Sphitran 		if (bp->dev.valid) {
4156573Sphitran 			(void) snprintf(name, sizeof (name), "battery%d",
4166573Sphitran 			    bp->dev.index);
4176573Sphitran 			if (ddi_create_minor_node(devi, name, S_IFCHR,
4186573Sphitran 			    MINOR_BATT(bp->dev.index), DDI_PSEUDO, 0) ==
4196573Sphitran 			    DDI_FAILURE) {
4206573Sphitran 				ACPI_DRV_DBG(CE_WARN, NULL,
4216573Sphitran 				    "%s: minor node create failed", name);
4226573Sphitran 				goto error;
4236573Sphitran 			}
4246573Sphitran 		}
4256573Sphitran 	}
4266573Sphitran 	for (i = 0; i < nac; i++) {
4276573Sphitran 		(void) snprintf(name, sizeof (name), "ac%d", i);
4286573Sphitran 		if (ddi_create_minor_node(devi, name, S_IFCHR,
4296573Sphitran 		    MINOR_AC(i), DDI_PSEUDO, 0) == DDI_FAILURE) {
4306573Sphitran 			ACPI_DRV_DBG(CE_WARN, NULL,
4316573Sphitran 			    "%s: minor node create failed", name);
4326573Sphitran 			goto error;
4336573Sphitran 		}
4346573Sphitran 	}
4356573Sphitran 
4366573Sphitran 	return (DDI_SUCCESS);
4376573Sphitran 
4386573Sphitran error:
4396573Sphitran 	ddi_remove_minor_node(devi, NULL);
4406573Sphitran 	acpi_drv_kstat_fini();
4416573Sphitran 	acpi_drv_acpi_fini();
4426573Sphitran 	acpi_drv_dip = NULL;
4436573Sphitran 	return (DDI_FAILURE);
4446573Sphitran }
4456573Sphitran 
4466573Sphitran static int
acpi_drv_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)4476573Sphitran acpi_drv_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
4486573Sphitran {
4496573Sphitran 	if (cmd != DDI_DETACH) {
4506573Sphitran 		return (DDI_FAILURE);
4516573Sphitran 	}
4526573Sphitran 
4536573Sphitran 	mutex_enter(&acpi_drv_mutex);
4546573Sphitran 	ddi_remove_minor_node(devi, NULL);
4556573Sphitran 
4566573Sphitran 	acpi_drv_kstat_fini();
4576573Sphitran 	acpi_drv_acpi_fini();
4586573Sphitran 	mutex_exit(&acpi_drv_mutex);
4596573Sphitran 	return (DDI_SUCCESS);
4606573Sphitran }
4616573Sphitran 
4626573Sphitran /* ARGSUSED */
4636573Sphitran static int
acpi_drv_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)4646573Sphitran acpi_drv_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
4656573Sphitran {
4666573Sphitran 	switch (cmd) {
4676573Sphitran 	case DDI_INFO_DEVT2DEVINFO:
4686573Sphitran 		*resultp = acpi_drv_dip;
4696573Sphitran 		return (DDI_SUCCESS);
4706573Sphitran 	case DDI_INFO_DEVT2INSTANCE:
4716573Sphitran 		*resultp = (void*) 0;
4726573Sphitran 		return (DDI_SUCCESS);
4736573Sphitran 	default:
4746573Sphitran 		return (DDI_FAILURE);
4756573Sphitran 	}
4766573Sphitran }
4776573Sphitran 
4786573Sphitran /*ARGSUSED*/
4796573Sphitran static int
acpi_drv_open(dev_t * devp,int flag,int otyp,cred_t * crp)4806573Sphitran acpi_drv_open(dev_t *devp, int flag, int otyp, cred_t *crp)
4816573Sphitran {
4826573Sphitran 	if (acpi_drv_dip == NULL) {
4836573Sphitran 		return (ENXIO);
4846573Sphitran 	}
4856573Sphitran 
4866573Sphitran 	return (0);
4876573Sphitran }
4886573Sphitran 
4896573Sphitran /*ARGSUSED*/
4906573Sphitran static int
acpi_drv_close(dev_t dev,int flag,int otyp,cred_t * crp)4916573Sphitran acpi_drv_close(dev_t dev, int flag, int otyp, cred_t *crp)
4926573Sphitran {
4936573Sphitran 	return (0);
4946573Sphitran }
4956573Sphitran 
4966573Sphitran /*ARGSUSED*/
4976573Sphitran static int
acpi_drv_ioctl(dev_t dev,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval)4986573Sphitran acpi_drv_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *cr,
4996573Sphitran     int *rval)
5006573Sphitran {
5016573Sphitran 	int minor;
5026573Sphitran 	int type, index;
5036573Sphitran 	int res = 0;
5046573Sphitran 
5056573Sphitran 	minor = getminor(dev);
5066573Sphitran 	type = MINOR2TYPE(minor);
5076573Sphitran 	index = MINOR2IDX(minor);
5086573Sphitran 
5096573Sphitran 	mutex_enter(&acpi_drv_mutex);
5106573Sphitran 
5116573Sphitran 	switch (type) {
5126573Sphitran 	case ACPI_DRV_TYPE_CBAT:
5136573Sphitran 		res = acpi_drv_cbat_ioctl(index, cmd, arg, mode, cr, rval);
5146573Sphitran 		break;
5156573Sphitran 	case ACPI_DRV_TYPE_AC:
5166573Sphitran 		res = acpi_drv_ac_ioctl(index, cmd, arg, mode, cr, rval);
5176573Sphitran 		break;
5186573Sphitran 	case ACPI_DRV_TYPE_LID:
5196573Sphitran 		res = acpi_drv_lid_ioctl(index, cmd, arg, mode, cr, rval);
5206573Sphitran 		break;
5218693SKerry.Shu@Sun.COM 	case ACPI_DRV_TYPE_HOTKEY:
5228693SKerry.Shu@Sun.COM 		res = acpi_drv_hotkey_ioctl(cmd, arg, mode, cr, rval);
5236573Sphitran 		break;
5246573Sphitran 	default:
5256573Sphitran 		res = EINVAL;
5266573Sphitran 		break;
5276573Sphitran 	}
5286573Sphitran 
5296573Sphitran 	mutex_exit(&acpi_drv_mutex);
5306573Sphitran 	return (res);
5316573Sphitran }
5326573Sphitran 
5336573Sphitran /*ARGSUSED*/
5346573Sphitran static int
acpi_drv_cbat_ioctl(int index,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval)5356573Sphitran acpi_drv_cbat_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr,
5366573Sphitran     int *rval)
5376573Sphitran {
5386573Sphitran 	int res = 0;
5396573Sphitran 	acpi_drv_warn_t bwarn;
5406573Sphitran 	struct acpi_drv_cbat_state *bp;
5416573Sphitran 
5426573Sphitran 	ASSERT(mutex_owned(&acpi_drv_mutex));
5436573Sphitran 
5446573Sphitran 	bp = acpi_drv_idx2cbat(index);
5456573Sphitran 	if (!bp || bp->dev.valid != 1) {
5466573Sphitran 		return (ENXIO);
5476573Sphitran 	}
5486573Sphitran 
5496573Sphitran 	switch (cmd) {
5506573Sphitran 	/*
5516573Sphitran 	 * Return _BIF(Battery Information) of battery[index],
5526573Sphitran 	 * if battery plugged.
5536573Sphitran 	 */
5546573Sphitran 	case ACPI_DRV_IOC_INFO:
5556573Sphitran 		if (bp->dev.present == 0) {
5566573Sphitran 			res = ENXIO;
5576573Sphitran 			break;
5586573Sphitran 		}
5596573Sphitran 
5606573Sphitran 		res = acpi_drv_update_bif(bp);
5616573Sphitran 		if (res != ACPI_DRV_OK) {
5626573Sphitran 			break;
5636573Sphitran 		}
5646573Sphitran 		if (copyout(&bp->bif_cache, (void *)arg,
5656573Sphitran 		    sizeof (bp->bif_cache))) {
5666573Sphitran 			res = EFAULT;
5676573Sphitran 		}
5686573Sphitran 		break;
5696573Sphitran 
5706573Sphitran 	/*
5716573Sphitran 	 * Return _BST(Battery Status) of battery[index],
5726573Sphitran 	 * if battery plugged.
5736573Sphitran 	 */
5746573Sphitran 	case ACPI_DRV_IOC_STATUS:
5756573Sphitran 		if (bp->dev.present == 0) {
5766573Sphitran 			res = ENXIO;
5776573Sphitran 			break;
5786573Sphitran 		}
5796573Sphitran 
5806573Sphitran 		res = acpi_drv_update_bst(bp);
5816573Sphitran 		if (res != ACPI_DRV_OK) {
5826573Sphitran 			break;
5836573Sphitran 		}
5846573Sphitran 		if (copyout(&bp->bst_cache, (void *)arg,
5856573Sphitran 		    sizeof (bp->bst_cache))) {
5866573Sphitran 			res = EFAULT;
5876573Sphitran 		}
5886573Sphitran 		break;
5896573Sphitran 
5906573Sphitran 	/* Return the state of the battery bays in the system */
5916573Sphitran 	case ACPI_DRV_IOC_BAY:
5926573Sphitran 		{
5936573Sphitran 			batt_bay_t bay;
5946573Sphitran 
5956573Sphitran 			bay.bay_number = nbat;
5966573Sphitran 			bay.battery_map = 0;
5976573Sphitran 			for (bp = &acpi_drv_cbat[0];
5986573Sphitran 			    bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM]; bp++) {
5996573Sphitran 				if (bp->dev.valid) {
6006573Sphitran 					if (bp->dev.present) {
6016573Sphitran 						bay.battery_map |=
6026573Sphitran 						    (1 << bp->dev.index);
6036573Sphitran 					}
6046573Sphitran 				}
6056573Sphitran 			}
6066573Sphitran 			if (copyout(&bay, (void *)arg, sizeof (bay))) {
6076573Sphitran 				res = EFAULT;
6086573Sphitran 				break;
6096573Sphitran 			}
6106573Sphitran 		}
6116573Sphitran 		break;
6126573Sphitran 
6136573Sphitran 	/*
6146573Sphitran 	 * Return the current power source device if available:
6156573Sphitran 	 * 0 -- battery supplying power
6166573Sphitran 	 * 1 -- AC supplying power
6176573Sphitran 	 */
6186573Sphitran 	case ACPI_DRV_IOC_POWER_STATUS:
6196573Sphitran 		{
6206573Sphitran 			int val;
6216573Sphitran 
6226573Sphitran 			/* State not available */
6236573Sphitran 			if (acpi_drv_psr_type == ACPI_DRV_TYPE_UNKNOWN) {
6246573Sphitran 				res = ENXIO;
6256573Sphitran 				break;
6266573Sphitran 			}
6276573Sphitran 			val = (acpi_drv_psr_type == ACPI_DRV_TYPE_AC) ? 1 : 0;
6286573Sphitran 			if (copyout(&val, (void *)arg, sizeof (val))) {
6296573Sphitran 				res = EFAULT;
6306573Sphitran 				break;
6316573Sphitran 			}
6326573Sphitran 		}
6336573Sphitran 		break;
6346573Sphitran 
6356573Sphitran 	/* Get charge-warn and charge-low levels for the whole system */
6366573Sphitran 	case ACPI_DRV_IOC_GET_WARNING:
6376573Sphitran 		bwarn.bw_enabled = acpi_drv_warn_enabled;
6386573Sphitran 		bwarn.bw_charge_warn = acpi_drv_syn_warn_per;
6396573Sphitran 		bwarn.bw_charge_low = acpi_drv_syn_low_per;
6406573Sphitran 		if (copyout(&bwarn, (void *)arg, sizeof (&bwarn))) {
6416573Sphitran 			res = EFAULT;
6426573Sphitran 		}
6436573Sphitran 		break;
6446573Sphitran 
6456573Sphitran 	/* Set charge-warn and charge-low levels for the whole system */
6466573Sphitran 	case ACPI_DRV_IOC_SET_WARNING:
6476573Sphitran 		if (drv_priv(cr)) {
6486573Sphitran 			res = EPERM;
6496573Sphitran 			break;
6506573Sphitran 		}
6516573Sphitran 		if (copyin((void *)arg, &bwarn, sizeof (bwarn))) {
6526573Sphitran 			res = EFAULT;
6536573Sphitran 			break;
6546573Sphitran 		}
6556573Sphitran 		res = acpi_drv_set_warn(&bwarn);
6566573Sphitran 		break;
6576573Sphitran 
6586573Sphitran 	default:
6596573Sphitran 		res = EINVAL;
6606573Sphitran 		break;
6616573Sphitran 	}
6626573Sphitran 
6636573Sphitran 	return (res);
6646573Sphitran }
6656573Sphitran 
6666573Sphitran /*ARGSUSED*/
6676573Sphitran static int
acpi_drv_ac_ioctl(int index,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval)6686573Sphitran acpi_drv_ac_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr,
6696573Sphitran     int *rval)
6706573Sphitran {
6716573Sphitran 	int res = 0;
6726573Sphitran 	int ac_state;
6736573Sphitran 	struct acpi_drv_ac_state *acp;
6746573Sphitran 
6756573Sphitran 	ASSERT(mutex_owned(&acpi_drv_mutex));
6766573Sphitran 
6776573Sphitran 	acp = acpi_drv_idx2ac(index);
6786573Sphitran 	if (!acp || acp->dev.valid != 1) {
6796573Sphitran 		return (ENXIO);
6806573Sphitran 	}
6816573Sphitran 
6826573Sphitran 	switch (cmd) {
6836573Sphitran 	/* Return the number of AC adapters in the system */
6846573Sphitran 	case ACPI_DRV_IOC_AC_COUNT:
6856573Sphitran 		if (copyout(&nac, (void *)arg, sizeof (nac))) {
6866573Sphitran 			res = EFAULT;
6876573Sphitran 		}
6886573Sphitran 		break;
6896573Sphitran 
6906573Sphitran 	/*
6916573Sphitran 	 * Return the state of AC[index] if available:
6926573Sphitran 	 * 0 -- Off-line
6936573Sphitran 	 * 1 -- On-line
6946573Sphitran 	 */
6956573Sphitran 	case ACPI_DRV_IOC_POWER_STATUS:
6966573Sphitran 		if (!acp || acp->dev.valid != 1) {
6976573Sphitran 			res = ENXIO;
6986573Sphitran 			break;
6996573Sphitran 		}
7006573Sphitran 		/* State not available */
7016573Sphitran 		if ((ac_state = acpi_drv_ac_present(acp)) == -1) {
7026573Sphitran 			res = ENXIO;
7036573Sphitran 			break;
7046573Sphitran 		}
7056573Sphitran 		if (copyout(&ac_state, (void *)arg, sizeof (ac_state))) {
7066573Sphitran 			res = EFAULT;
7076573Sphitran 		}
7086573Sphitran 		break;
7096573Sphitran 
7106573Sphitran 	default:
7116573Sphitran 		res = EINVAL;
7126573Sphitran 		break;
7136573Sphitran 	}
7146573Sphitran 
7156573Sphitran 	return (res);
7166573Sphitran }
7176573Sphitran 
7186573Sphitran /*ARGSUSED*/
7196573Sphitran static int
acpi_drv_lid_ioctl(int index,int cmd,intptr_t arg,int mode,cred_t * cr,int * rval)7206573Sphitran acpi_drv_lid_ioctl(int index, int cmd, intptr_t arg, int mode, cred_t *cr,
7216573Sphitran     int *rval)
7226573Sphitran {
7236573Sphitran 	int res = 0;
7246573Sphitran 
7257651SPhi.Tran@Sun.COM 	/*
7267651SPhi.Tran@Sun.COM 	 * lid.state 0 means lid is closed.
7277651SPhi.Tran@Sun.COM 	 * lid.state non-zero means lid is open.
7287651SPhi.Tran@Sun.COM 	 */
7296573Sphitran 	switch (cmd) {
7306573Sphitran 	case ACPI_DRV_IOC_LID_STATUS:
7316573Sphitran 		if (lid.state_ok == ACPI_DRV_NTF_UNKNOWN) {
7326573Sphitran 			/* State not available */
7336573Sphitran 			res = acpi_drv_update_lid(&lid.dev);
7346573Sphitran 			if (res != ACPI_DRV_OK) {
7356573Sphitran 				res = ENXIO;
7366573Sphitran 				break;
7376573Sphitran 			}
7386573Sphitran 		}
7396573Sphitran 		if (copyout(&lid.state, (void *)arg, sizeof (lid.state))) {
7406573Sphitran 			res = EFAULT;
7417651SPhi.Tran@Sun.COM 		}
7427651SPhi.Tran@Sun.COM 		break;
7437651SPhi.Tran@Sun.COM 	case ACPI_DRV_IOC_LID_UPDATE:
7447651SPhi.Tran@Sun.COM 		res = acpi_drv_update_lid(&lid.dev);
7457651SPhi.Tran@Sun.COM 		if (res != ACPI_DRV_OK) {
7467651SPhi.Tran@Sun.COM 			res = ENXIO;
7476573Sphitran 			break;
7486573Sphitran 		}
7497651SPhi.Tran@Sun.COM 		if (copyout(&lid.state, (void *)arg, sizeof (lid.state))) {
7507651SPhi.Tran@Sun.COM 			res = EFAULT;
7517651SPhi.Tran@Sun.COM 		}
7526573Sphitran 		break;
7536573Sphitran 
7546573Sphitran 	default:
7556573Sphitran 		res = EINVAL;
7566573Sphitran 		break;
7576573Sphitran 	}
7586573Sphitran 	return (res);
7596573Sphitran }
7606573Sphitran 
7616573Sphitran /*ARGSUSED*/
7626573Sphitran static int
acpi_drv_chpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** phpp)7636573Sphitran acpi_drv_chpoll(dev_t dev, short events, int anyyet,  short *reventsp,
7646573Sphitran 	struct pollhead **phpp)
7656573Sphitran {
7666573Sphitran 	if (!anyyet) {
7676573Sphitran 		*phpp = &acpi_drv_pollhead;
7686573Sphitran 	}
7696573Sphitran 	*reventsp = 0;
7706573Sphitran 	return (0);
7716573Sphitran }
7726573Sphitran 
7736573Sphitran #ifdef DEBUG
7746573Sphitran static void
acpi_drv_printf(struct acpi_drv_dev * devp,uint_t lev,const char * fmt,...)7756573Sphitran acpi_drv_printf(struct acpi_drv_dev *devp, uint_t lev,
7766573Sphitran     const char *fmt, ...)
7776573Sphitran {
7786573Sphitran 	va_list args;
7796573Sphitran 
7806573Sphitran 	mutex_enter(&acpi_drv_prt_mutex);
7816573Sphitran 
7826573Sphitran 	va_start(args, fmt);
7836573Sphitran 	(void) vsprintf(acpi_drv_prt_buf, fmt, args);
7846573Sphitran 	va_end(args);
7856573Sphitran 
7866573Sphitran 	if (devp) {
7876573Sphitran 		cmn_err(lev, "%s.%s: %s", devp->hid, devp->uid,
7886573Sphitran 		    acpi_drv_prt_buf);
7896573Sphitran 	} else {
7906573Sphitran 		cmn_err(lev, "%s", acpi_drv_prt_buf);
7916573Sphitran 	}
7926573Sphitran 	mutex_exit(&acpi_drv_prt_mutex);
7936573Sphitran }
7946573Sphitran 
7956573Sphitran static void
acpi_drv_prt_notify(ACPI_HANDLE hdl,UINT32 val)7966573Sphitran acpi_drv_prt_notify(ACPI_HANDLE hdl, UINT32 val)
7976573Sphitran {
7986573Sphitran 	ACPI_BUFFER buf;
7996573Sphitran 	char str[1024];
8006573Sphitran 
8016573Sphitran 	buf.Length = sizeof (str);
8026573Sphitran 	buf.Pointer = str;
80311387SSurya.Prakki@Sun.COM 	(void) AcpiGetName(hdl, ACPI_FULL_PATHNAME, &buf);
8046573Sphitran 	cmn_err(CE_NOTE, "AcpiNotify(%s, 0x%02x)", str, val);
8056573Sphitran }
8066573Sphitran #endif /* DEBUG */
8076573Sphitran 
8088693SKerry.Shu@Sun.COM void
acpi_drv_gen_sysevent(struct acpi_drv_dev * devp,char * ev,uint32_t val)8096573Sphitran acpi_drv_gen_sysevent(struct acpi_drv_dev *devp, char *ev, uint32_t val)
8106573Sphitran {
8116573Sphitran 	nvlist_t *attr_list = NULL;
8126573Sphitran 	int err;
8136573Sphitran 	char pathname[MAXPATHLEN];
8146573Sphitran 
8156573Sphitran 	/* Allocate and build sysevent attribute list */
8166573Sphitran 	err = nvlist_alloc(&attr_list, NV_UNIQUE_NAME_TYPE, DDI_NOSLEEP);
8176573Sphitran 	if (err != 0) {
8186573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
8196573Sphitran 		    "cannot allocate memory for sysevent attributes\n");
8206573Sphitran 		return;
8216573Sphitran 	}
8226573Sphitran 
8236573Sphitran 	/* Add attributes */
8246573Sphitran 	err = nvlist_add_string(attr_list, PWRCTL_DEV_HID, devp->hid);
8256573Sphitran 	if (err != 0) {
8266573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
8276573Sphitran 		    "Failed to add attr [%s] for %s/%s event",
8286573Sphitran 		    PWRCTL_DEV_HID, EC_PWRCTL, ev);
8296573Sphitran 		nvlist_free(attr_list);
8306573Sphitran 		return;
8316573Sphitran 	}
8326573Sphitran 
8336573Sphitran 	err = nvlist_add_string(attr_list, PWRCTL_DEV_UID, devp->uid);
8346573Sphitran 	if (err != 0) {
8356573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
8366573Sphitran 		    "Failed to add attr [%s] for %s/%s event",
8376573Sphitran 		    PWRCTL_DEV_UID, EC_PWRCTL, ev);
8386573Sphitran 		nvlist_free(attr_list);
8396573Sphitran 		return;
8406573Sphitran 	}
8416573Sphitran 
8426573Sphitran 	err = nvlist_add_uint32(attr_list, PWRCTL_DEV_INDEX, devp->index);
8436573Sphitran 	if (err != 0) {
8446573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
8456573Sphitran 		    "Failed to add attr [%s] for %s/%s event",
8466573Sphitran 		    PWRCTL_DEV_INDEX, EC_PWRCTL, ev);
8476573Sphitran 		nvlist_free(attr_list);
8486573Sphitran 		return;
8496573Sphitran 	}
8506573Sphitran 
8516573Sphitran 	(void) ddi_pathname(acpi_drv_dip, pathname);
8526573Sphitran 	err = nvlist_add_string(attr_list, PWRCTL_DEV_PHYS_PATH, pathname);
8536573Sphitran 	if (err != 0) {
8546573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
8556573Sphitran 		    "Failed to add attr [%s] for %s/%s event",
8566573Sphitran 		    PWRCTL_DEV_PHYS_PATH, EC_PWRCTL, ev);
8576573Sphitran 		nvlist_free(attr_list);
8586573Sphitran 		return;
8596573Sphitran 	}
8606573Sphitran 
8616573Sphitran 	if (strcmp(ev, ESC_PWRCTL_WARN) && strcmp(ev, ESC_PWRCTL_LOW)) {
8626573Sphitran 		goto finish;
8636573Sphitran 	}
8646573Sphitran 
8656573Sphitran 	err = nvlist_add_uint32(attr_list, PWRCTL_CHARGE_LEVEL, val);
8666573Sphitran 	if (err != 0) {
8676573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
8686573Sphitran 		    "Failed to add attr [%s] for %s/%s event",
8696573Sphitran 		    PWRCTL_CHARGE_LEVEL, EC_PWRCTL, ev);
8706573Sphitran 		nvlist_free(attr_list);
8716573Sphitran 		return;
8726573Sphitran 	}
8736573Sphitran 
8746573Sphitran finish:
8756573Sphitran 	ACPI_DRV_DBG(CE_NOTE, NULL, "SysEv(%s, %s.%s, %d)",
8766573Sphitran 	    ev, devp->hid, devp->uid, val);
8776573Sphitran 	/* Generate/log sysevent */
8786573Sphitran 	err = ddi_log_sysevent(acpi_drv_dip, DDI_VENDOR_SUNW, EC_PWRCTL,
8796573Sphitran 	    ev, attr_list, NULL, DDI_NOSLEEP);
8806573Sphitran #ifdef DEBUG
8816573Sphitran 	if (err != DDI_SUCCESS) {
8826573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
8836573Sphitran 		    "cannot log sysevent, err code %x\n", err);
8846573Sphitran 	}
8856573Sphitran #endif
8866573Sphitran 
8876573Sphitran 	nvlist_free(attr_list);
8886573Sphitran }
8896573Sphitran 
8906573Sphitran static int
acpi_drv_obj_copy(ACPI_OBJECT * op,char * bp,struct obj_desc * dp)8916573Sphitran acpi_drv_obj_copy(ACPI_OBJECT *op, char *bp, struct obj_desc *dp)
8926573Sphitran {
8936573Sphitran 	ACPI_OBJECT *ep;
8946573Sphitran 	char *fp;
8956573Sphitran 
8966573Sphitran 	ep = &op->Package.Elements[0];
8976573Sphitran 	for (; dp->offset != -1; dp++) {
8986573Sphitran 		fp = bp + dp->offset;
8996573Sphitran 		if (dp->type == ACPI_TYPE_INTEGER &&
9006573Sphitran 		    ep->Type == dp->type) {
9016573Sphitran #ifdef DEBUG
9026573Sphitran 			if (dp->size <= 4) {
9036573Sphitran 				ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %u",
9046573Sphitran 				    dp->name,
9056573Sphitran 				    (uint32_t)ep->Integer.Value);
9066573Sphitran 			} else {
9076573Sphitran #ifdef _LP64
9086573Sphitran 				ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %lu",
9096573Sphitran 				    dp->name, (uint64_t)ep->Integer.Value);
9106573Sphitran 			}
9116573Sphitran #else
9126573Sphitran 				ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: %llu",
9136573Sphitran 				    dp->name, (uint64_t)ep->Integer.Value);
9146573Sphitran 			}
9156573Sphitran #endif /* _LP64 */
9166573Sphitran #endif /* DEBUG */
9176573Sphitran 			*(uint32_t *)fp = ep->Integer.Value;
9186573Sphitran 		} else if (dp->type == ACPI_TYPE_STRING &&
9196573Sphitran 		    ep->Type == dp->type) {
9206573Sphitran 			ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: \"%s\"",
9216573Sphitran 			    dp->name, ep->String.Pointer);
922*12004Sjiang.liu@intel.com 			(void) strlcpy(fp, ep->String.Pointer, dp->size);
9236573Sphitran 		} else if (dp->type == ACPI_TYPE_STRING &&
9246573Sphitran 		    ep->Type == ACPI_TYPE_BUFFER) {
9256573Sphitran #ifdef DEBUG
9266573Sphitran 			int len;
9276573Sphitran 			char buf[MAXNAMELEN + 1];
9286573Sphitran 
9296573Sphitran 			len = (MAXNAMELEN < ep->Buffer.Length) ?
9306573Sphitran 			    MAXNAMELEN : ep->Buffer.Length;
9316573Sphitran 			bcopy(ep->Buffer.Pointer, buf, len);
9326573Sphitran 			buf[len] = 0;
9336573Sphitran 			ACPI_DRV_DBG(CE_NOTE, NULL, "\t%s: [%d] \"%s\"",
9346573Sphitran 			    dp->name, len, buf);
9356573Sphitran #endif
9366573Sphitran 
9376573Sphitran 			ASSERT(MAXNAMELEN >= ep->Buffer.Length);
9386573Sphitran 			bcopy(ep->Buffer.Pointer, fp, ep->Buffer.Length);
9396573Sphitran 		} else {
9406573Sphitran 			ACPI_DRV_DBG(CE_WARN, NULL,
9416573Sphitran 			    "Bad field at offset %d: type %d",
9426573Sphitran 			    dp->offset, ep->Type);
9436573Sphitran 			if (dp->type != ACPI_TYPE_STRING) {
9446573Sphitran 				return (ACPI_DRV_ERR);
9456573Sphitran 			}
9466573Sphitran 		}
9476573Sphitran 		ep++;
9486573Sphitran 	}
9496573Sphitran 
9506573Sphitran 	return (ACPI_DRV_OK);
9516573Sphitran }
9526573Sphitran 
9536573Sphitran /*
9546573Sphitran  * Returns the current power source devices. Used for the AC adapter and is
9556573Sphitran  * located under the AC adapter object in name space. Used to determine if
9566573Sphitran  * system is running off the AC adapter. This will report that the system is
9576573Sphitran  * not running on the AC adapter if any of the batteries in the system is
9586573Sphitran  * being forced to discharge through _BMC.
9596573Sphitran  *
9606573Sphitran  * Return value:
9616573Sphitran  *	 0 -- Off-line, ie. battery supplying system power
9626573Sphitran  *	 1 -- On-line, ie. AC supplying system power
9636573Sphitran  *	-1 -- Unknown, some error ocurred.
9646573Sphitran  * Note: It will also update the driver ac state.
9656573Sphitran  */
9666573Sphitran static int
acpi_drv_get_psr(struct acpi_drv_ac_state * acp)9676573Sphitran acpi_drv_get_psr(struct acpi_drv_ac_state *acp)
9686573Sphitran {
9696573Sphitran 	struct acpi_drv_dev *devp = &acp->dev;
9706573Sphitran 	int ac;
9716573Sphitran 
9726573Sphitran 	if (!devp->valid) {
9736573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "device not valid");
9746573Sphitran 		return (-1);
9756573Sphitran 	}
9766573Sphitran 
9776573Sphitran 	if (acpica_eval_int(devp->hdl, "_PSR", &ac) == AE_OK) {
9786573Sphitran 		ACPI_DRV_DBG(CE_NOTE, devp, "_PSR = %d", ac);
9796573Sphitran 		devp->present = ac;
9806573Sphitran 	} else {
9816573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _PSR failed");
9826573Sphitran 		devp->present = -1;
9836573Sphitran 	}
9846573Sphitran 
9856573Sphitran 	return (ac);
9866573Sphitran }
9876573Sphitran 
9886573Sphitran /*
9896573Sphitran  * For most systems, the _STA for this device will always
9906573Sphitran  * return a value with bits 0-3 set and will toggle bit 4
9916573Sphitran  * to indicate the actual presence of a battery.
9926573Sphitran  *
9936573Sphitran  * Return value:
9946573Sphitran  *	 0 -- battery not present
9956573Sphitran  *	 1 -- battery present
9966573Sphitran  *	-1 -- Unknown, some error ocurred.
9976573Sphitran  * Note: It will also update the driver cbat state.
9986573Sphitran  */
9996573Sphitran static int
acpi_drv_get_sta(struct acpi_drv_cbat_state * bp)10006573Sphitran acpi_drv_get_sta(struct acpi_drv_cbat_state *bp)
10016573Sphitran {
10026573Sphitran 	struct acpi_drv_dev *devp = &bp->dev;
10036573Sphitran 	int val;
10046573Sphitran 
10056573Sphitran 	if (!devp->valid) {
10066573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "device not valid");
10076573Sphitran 		return (-1);
10086573Sphitran 	}
10096573Sphitran 
10106573Sphitran 	if (acpica_eval_int(devp->hdl, "_STA", &val) == AE_OK) {
10116573Sphitran 		ACPI_DRV_DBG(CE_NOTE, devp, "_STA = 0x%x", val);
10126573Sphitran 		devp->present = ((val & STA_FLAG_BATT_PRESENT) != 0);
10136573Sphitran 	} else {
10146573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _STA failed");
10156573Sphitran 		devp->present = -1;
10166573Sphitran 	}
10176573Sphitran 
10186573Sphitran 	return (val);
10196573Sphitran }
10206573Sphitran 
10216573Sphitran static int
acpi_drv_update_bif(struct acpi_drv_cbat_state * bp)10226573Sphitran acpi_drv_update_bif(struct acpi_drv_cbat_state *bp)
10236573Sphitran {
10246573Sphitran 	ACPI_BUFFER buf;
10256573Sphitran 	ACPI_OBJECT *objp;
10266573Sphitran 
10276573Sphitran 	/* BIF is only available when battery plugged */
10286573Sphitran 	ASSERT(bp->dev.present != 0);
10296573Sphitran 
10306573Sphitran 	/* Update internal BIF cache */
10316573Sphitran 	bp->bat_bifok = ACPI_DRV_NTF_UNKNOWN;
10326573Sphitran 
10336573Sphitran 	buf.Length = ACPI_ALLOCATE_BUFFER;
10346573Sphitran 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(bp->dev.hdl, "_BIF",
10356573Sphitran 	    NULL, &buf, ACPI_TYPE_PACKAGE))) {
10366573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _BIF failed");
10376573Sphitran 		return (ACPI_DRV_ERR);
10386573Sphitran 	}
10396573Sphitran 
10406573Sphitran 	objp = buf.Pointer;
10416573Sphitran 	ACPI_DRV_DBG(CE_NOTE, &bp->dev, "get _BIF");
10426573Sphitran 	if (acpi_drv_obj_copy(objp, (char *)&bp->bif_cache, bif_desc) ==
10436573Sphitran 	    ACPI_DRV_ERR) {
10446573Sphitran 		AcpiOsFree(objp);
10456573Sphitran 		return (ACPI_DRV_ERR);
10466573Sphitran 	}
10476573Sphitran 	AcpiOsFree(objp);
10486573Sphitran 	bp->bat_bifok = ACPI_DRV_NTF_OK;
10496573Sphitran 	return (ACPI_DRV_OK);
10506573Sphitran }
10516573Sphitran 
10526573Sphitran static int
acpi_drv_update_bst(struct acpi_drv_cbat_state * bp)10536573Sphitran acpi_drv_update_bst(struct acpi_drv_cbat_state *bp)
10546573Sphitran {
10556573Sphitran 	ACPI_BUFFER buf;
10566573Sphitran 	ACPI_OBJECT *objp;
10576573Sphitran 
10586573Sphitran 	/* BST is only available when battery plugged */
10596573Sphitran 	ASSERT(bp->dev.present != 0);
10606573Sphitran 
10616573Sphitran 	/* Update internal BST cache */
10626573Sphitran 	bp->bat_bstok = ACPI_DRV_NTF_UNKNOWN;
10636573Sphitran 
10646573Sphitran 	buf.Length = ACPI_ALLOCATE_BUFFER;
10656573Sphitran 	if (ACPI_FAILURE(AcpiEvaluateObjectTyped(bp->dev.hdl, "_BST",
10666573Sphitran 	    NULL, &buf, ACPI_TYPE_PACKAGE))) {
10676573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "AcpiEval _BST failed");
10686573Sphitran 		return (ACPI_DRV_ERR);
10696573Sphitran 	}
10706573Sphitran 
10716573Sphitran 	objp = buf.Pointer;
10726573Sphitran 	ACPI_DRV_DBG(CE_NOTE, &bp->dev, "get _BST");
10736573Sphitran 	if (acpi_drv_obj_copy(objp, (char *)&bp->bst_cache, bst_desc) ==
10746573Sphitran 	    ACPI_DRV_ERR) {
10756573Sphitran 		AcpiOsFree(objp);
10766573Sphitran 		return (ACPI_DRV_ERR);
10776573Sphitran 	}
10786573Sphitran 	AcpiOsFree(objp);
10796573Sphitran 
10806573Sphitran 	if (bp->bst_cache.bst_rate == 0) {
10816573Sphitran 		bp->bst_cache.bst_state &= ~(ACPI_DRV_BST_CHARGING |
10826573Sphitran 		    ACPI_DRV_BST_DISCHARGING);
10836573Sphitran 	}
10846573Sphitran 	bp->bat_bstok = ACPI_DRV_NTF_OK;
10856573Sphitran 	return (ACPI_DRV_OK);
10866573Sphitran }
10876573Sphitran 
10886573Sphitran /*
10896573Sphitran  * Return value:
10906573Sphitran  *	 1 -- device On-line
10916573Sphitran  *	 0 -- device Off-line
10926573Sphitran  *	-1 -- Unknown, some error ocurred.
10936573Sphitran  */
10946573Sphitran static int
acpi_drv_dev_present(struct acpi_drv_dev * devp)10956573Sphitran acpi_drv_dev_present(struct acpi_drv_dev *devp)
10966573Sphitran {
10976573Sphitran 	if (!devp->valid) {
10986573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "device not valid");
10996573Sphitran 		return (-1);
11006573Sphitran 	}
11016573Sphitran 
11026573Sphitran 	ASSERT(devp->type != ACPI_DRV_TYPE_UNKNOWN);
11036573Sphitran 
11046573Sphitran 	/* Update the device state */
11056573Sphitran 	if (devp->present == -1) {
11066573Sphitran 		if (devp->type == ACPI_DRV_TYPE_AC) {
11076573Sphitran 			(void) acpi_drv_get_psr((struct acpi_drv_ac_state *)
11086573Sphitran 			    devp);
11096573Sphitran 		} else if (devp->type == ACPI_DRV_TYPE_CBAT) {
11106573Sphitran 			(void) acpi_drv_get_sta((struct acpi_drv_cbat_state *)
11116573Sphitran 			    devp);
11126573Sphitran 		}
11136573Sphitran 	}
11146573Sphitran 
11156573Sphitran 	return (devp->present);
11166573Sphitran }
11176573Sphitran 
11186573Sphitran /*
11196573Sphitran  * Check if the device p existance state has changed.
11206573Sphitran  * Return value:
11216573Sphitran  *	 1 -- changed
11226573Sphitran  *	 0 -- no change
11236573Sphitran  *	-1 -- unknown
11246573Sphitran  */
11256573Sphitran static int
acpi_drv_update_present(struct acpi_drv_dev * p)11266573Sphitran acpi_drv_update_present(struct acpi_drv_dev *p)
11276573Sphitran {
11286573Sphitran 	int old_present = p->present;
11296573Sphitran 	int new_present;
11306573Sphitran 
11316573Sphitran 	ASSERT(p && p->valid);
11326573Sphitran 
11336573Sphitran 	p->present = -1;
11346573Sphitran 	new_present = acpi_drv_dev_present(p);
11356573Sphitran 	if (new_present == -1) {
11366573Sphitran 		return (-1);
11376573Sphitran 	}
11386573Sphitran 	if (new_present != old_present) {
11396573Sphitran 		return (1);
11406573Sphitran 	}
11416573Sphitran 	return (0);
11426573Sphitran }
11436573Sphitran 
11446573Sphitran static void
acpi_drv_set_psr(struct acpi_drv_dev * p)11456573Sphitran acpi_drv_set_psr(struct acpi_drv_dev *p)
11466573Sphitran {
11476573Sphitran 	acpi_drv_psr_devp = p;
11486573Sphitran 	if (p != NULL) {
11496573Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "psr = .");
11506573Sphitran 		acpi_drv_psr_type = p->type;
11516573Sphitran 	} else {
11526573Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "psr = ?");
11536573Sphitran 		acpi_drv_psr_type = ACPI_DRV_TYPE_UNKNOWN;
11546573Sphitran 	}
11556573Sphitran }
11566573Sphitran 
11576573Sphitran /*
11586573Sphitran  * OSPM can determine independent warning and low battery
11596573Sphitran  * capacity values based on the OEM-designed levels, but
11606573Sphitran  * cannot set these values lower than the OEM-designed values.
11616573Sphitran  */
11626573Sphitran static int
acpi_drv_set_warn(acpi_drv_warn_t * bwp)11636573Sphitran acpi_drv_set_warn(acpi_drv_warn_t *bwp)
11646573Sphitran {
11656573Sphitran 	uint32_t warn, low;
11666573Sphitran 
11676573Sphitran 	warn = acpi_drv_syn_last_cap * bwp->bw_charge_warn / 100;
11686573Sphitran 	low = acpi_drv_syn_last_cap * bwp->bw_charge_low / 100;
11696573Sphitran 
11706573Sphitran 	/* Update internal state */
11716573Sphitran 	if (bwp->bw_enabled) {
11726573Sphitran 		if (low >= warn || warn < acpi_drv_syn_oem_warn_cap ||
11736573Sphitran 		    low < acpi_drv_syn_oem_low_cap) {
11746573Sphitran 			ACPI_DRV_DBG(CE_WARN, NULL, "charge level error");
11756573Sphitran 			return (EINVAL);
11766573Sphitran 		}
11776573Sphitran 
11786573Sphitran 		ACPI_DRV_DBG(CE_NOTE, NULL, "set warn: warn=%d low=%d", warn,
11796573Sphitran 		    low);
11806573Sphitran 
11816573Sphitran 		acpi_drv_syn_warn_per = bwp->bw_charge_warn;
11826573Sphitran 		acpi_drv_syn_low_per = bwp->bw_charge_low;
11836573Sphitran 		acpi_drv_syn_warn_cap = warn;
11846573Sphitran 		acpi_drv_syn_low_cap = low;
11856573Sphitran 		acpi_drv_warn_enabled = 1;
11866573Sphitran 	} else {
11876573Sphitran 		acpi_drv_warn_enabled = 0;
11886573Sphitran 	}
11896573Sphitran 
11906573Sphitran 	return (0);
11916573Sphitran }
11926573Sphitran 
11936573Sphitran /*
11946573Sphitran  * Update information for the synthesis battery
11956573Sphitran  *
11966573Sphitran  * Note: Sometimes the value to be returned from _BST or _BIF will be
11976573Sphitran  * temporarily unknown. In this case, the method may return the value
11986573Sphitran  * 0xFFFFFFFF as a placeholder. When the value becomes known, the
11996573Sphitran  * appropriate notification (0x80 for _BST or 0x81 for BIF) should be
12006573Sphitran  * issued, in like manner to any other change in the data returned by
12016573Sphitran  * these methods. This will cause OSPM to re-evaluate the method obtaining
12026573Sphitran  * the correct data value.
12036573Sphitran  */
12046573Sphitran static void
acpi_drv_update_cap(int bif_changed)12056573Sphitran acpi_drv_update_cap(int bif_changed)
12066573Sphitran {
12076573Sphitran 	struct acpi_drv_cbat_state *bp;
12086573Sphitran 
12096573Sphitran 	if (bif_changed != 0) {
12106573Sphitran 		acpi_drv_syn_oem_warn_cap = 0xffffffff;
12116573Sphitran 		acpi_drv_syn_oem_low_cap = 0xffffffff;
12126573Sphitran 		acpi_drv_syn_last_cap = 0xffffffff;
12136573Sphitran 	}
12146573Sphitran 	acpi_drv_syn_last_level = acpi_drv_syn_rem_cap;
12156573Sphitran 	acpi_drv_syn_rem_cap = 0xffffffff; /* initially unknown */
12166573Sphitran 
12176573Sphitran 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
12186573Sphitran 	    bp++) {
12196573Sphitran 		if (bp->dev.valid) {
12206573Sphitran 			/* Escape the empty bays */
12216573Sphitran 			if (acpi_drv_cbat_present(bp) <= 0) {
12226573Sphitran 				continue;
12236573Sphitran 			}
12246573Sphitran 
12256573Sphitran 			if (bif_changed != 0 &&
12266573Sphitran 			    bp->bat_bifok == ACPI_DRV_NTF_OK) {
12276573Sphitran 				acpi_bif_t *bif;
12286573Sphitran 
12296573Sphitran 				bif = &bp->bif_cache;
12306573Sphitran 
12316573Sphitran 				if (acpi_drv_syn_last_cap == 0xffffffff) {
12326573Sphitran 					acpi_drv_syn_last_cap = 0;
12336573Sphitran 				}
12346573Sphitran 				acpi_drv_syn_last_cap += bif->bif_last_cap;
12356573Sphitran 
12366573Sphitran 				if (bif->bif_warn_cap == 0xffffffff ||
12376573Sphitran 				    bif->bif_low_cap == 0xffffffff) {
12386573Sphitran 					ACPI_DRV_DBG(CE_WARN, &bp->dev,
12396573Sphitran 					    "BIF value "
12406573Sphitran 					    "invalid, warn_cap=0x%x "
12416573Sphitran 					    "low_cap=0x%x", bif->bif_warn_cap,
12426573Sphitran 					    bif->bif_low_cap);
12436573Sphitran 					continue;
12446573Sphitran 				}
12456573Sphitran 				if (acpi_drv_syn_oem_warn_cap == 0xffffffff) {
12466573Sphitran 					acpi_drv_syn_oem_warn_cap = 0;
12476573Sphitran 				}
12486573Sphitran 				if (acpi_drv_syn_oem_low_cap == 0xffffffff) {
12496573Sphitran 					acpi_drv_syn_oem_low_cap = 0;
12506573Sphitran 				}
12516573Sphitran 
12526573Sphitran 				/*
12536573Sphitran 				 * Use the highest level as the synthesis
12546573Sphitran 				 * level.
12556573Sphitran 				 */
12566573Sphitran 				if (bif->bif_warn_cap >
12576573Sphitran 				    acpi_drv_syn_oem_warn_cap) {
12586573Sphitran 					acpi_drv_syn_oem_low_cap =
12596573Sphitran 					    bif->bif_low_cap;
12606573Sphitran 					acpi_drv_syn_oem_warn_cap =
12616573Sphitran 					    bif->bif_warn_cap;
12626573Sphitran 				}
12636573Sphitran 			}
12646573Sphitran #ifdef DEBUG
12656573Sphitran 			else if (bif_changed) {
12666573Sphitran 				ACPI_DRV_DBG(CE_NOTE, &bp->dev,
12676573Sphitran 				    "BIF not ready");
12686573Sphitran 			}
12696573Sphitran #endif
12706573Sphitran 
12716573Sphitran 			if (bp->bat_bstok == ACPI_DRV_NTF_OK) {
12726573Sphitran 				acpi_bst_t *bst;
12736573Sphitran 
12746573Sphitran 				bst = &bp->bst_cache;
12756573Sphitran 
12766573Sphitran 				/*
12776573Sphitran 				 * Batteries that are rechargeable and are in
12786573Sphitran 				 * the discharging state are required to return
12796573Sphitran 				 * a valid Battery Present Rate value.
12806573Sphitran 				 * 0xFFFFFFFF - Unknown rate/capacity
12816573Sphitran 				 */
12826573Sphitran 				if (bst->bst_rem_cap == 0xffffffff) {
12836573Sphitran 					ACPI_DRV_DBG(CE_WARN, &bp->dev,
12846573Sphitran 					    "BST value invalid, "
12856573Sphitran 					    "rate=0x%x cap=0x%x",
12866573Sphitran 					    bst->bst_rate, bst->bst_rem_cap);
12876573Sphitran 					continue;
12886573Sphitran 				}
12896573Sphitran 
12906573Sphitran 				if (acpi_drv_syn_rem_cap == 0xffffffff) {
12916573Sphitran 					acpi_drv_syn_rem_cap = 0;
12926573Sphitran 				}
12936573Sphitran 				acpi_drv_syn_rem_cap += bst->bst_rem_cap;
12946573Sphitran 				/* Check for overflow */
12956573Sphitran 				ASSERT(acpi_drv_syn_rem_cap >=
12966573Sphitran 				    bst->bst_rem_cap);
12976573Sphitran 			}
12986573Sphitran #ifdef DEBUG
12996573Sphitran 			else {
13006573Sphitran 				ACPI_DRV_DBG(CE_NOTE, &bp->dev,
13016573Sphitran 				    "BST not ready");
13026573Sphitran 			}
13036573Sphitran #endif
13046573Sphitran 		}
13056573Sphitran 	}
13066573Sphitran 
13076573Sphitran 	ACPI_DRV_DBG(CE_NOTE, NULL, "syn_cap: %d syn_oem_warn: %d "
13086573Sphitran 	    "syn_oem_low: %d", acpi_drv_syn_rem_cap, acpi_drv_syn_oem_warn_cap,
13096573Sphitran 	    acpi_drv_syn_oem_low_cap);
13106573Sphitran }
13116573Sphitran 
13126573Sphitran static struct acpi_drv_cbat_state *
acpi_drv_idx2cbat(int idx)13136573Sphitran acpi_drv_idx2cbat(int idx)
13146573Sphitran {
13156573Sphitran 	if (idx >= ACPI_DRV_MAX_BAT_NUM) {
13166573Sphitran 		return (NULL);
13176573Sphitran 	}
13186573Sphitran 	return (&acpi_drv_cbat[idx]);
13196573Sphitran }
13206573Sphitran 
13216573Sphitran static struct acpi_drv_ac_state *
acpi_drv_idx2ac(int idx)13226573Sphitran acpi_drv_idx2ac(int idx)
13236573Sphitran {
13246573Sphitran 	if (idx >= ACPI_DRV_MAX_AC_NUM) {
13256573Sphitran 		return (NULL);
13266573Sphitran 	}
13276573Sphitran 	return (&acpi_drv_ac[idx]);
13286573Sphitran }
13296573Sphitran 
13306573Sphitran /*ARGSUSED*/
13316573Sphitran static void
acpi_drv_cbat_notify(ACPI_HANDLE hdl,UINT32 val,void * ctx)13326573Sphitran acpi_drv_cbat_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx)
13336573Sphitran {
13346573Sphitran 	struct acpi_drv_cbat_state *bp = ctx;
13356573Sphitran 	struct acpi_drv_dev *devp = &bp->dev;
13366573Sphitran 	int bif_changed;
13376573Sphitran 	uint32_t eval;
13386573Sphitran 	char *ev;
13396573Sphitran 	acpi_bst_t *bst;
13406573Sphitran 
13416573Sphitran 	mutex_enter(&acpi_drv_mutex);
13426573Sphitran 	ACPI_DRV_PRT_NOTIFY(hdl, val);
13436573Sphitran 
13446573Sphitran 	switch (val) {
13456573Sphitran 	/*
13466573Sphitran 	 * BST has changed
13476573Sphitran 	 * Whenever the Battery State value changes, the
13486573Sphitran 	 * system will generate an SCI to notify the OS.
13496573Sphitran 	 *
13506573Sphitran 	 * Note: trip point is not used to implement the
13516573Sphitran 	 * warning levels.
13526573Sphitran 	 */
13536573Sphitran 	case 0x80:
13546573Sphitran 		/*
13556573Sphitran 		 * We always get 0x80 and 0x81 at battery plug/unplug,
13566573Sphitran 		 * but 0x80 may come first. In case that situation, we have
13576573Sphitran 		 * to update battery present state here too to update bst
13586573Sphitran 		 * correctly.
13596573Sphitran 		 */
13606573Sphitran 		bif_changed = acpi_drv_update_present(devp);
13616573Sphitran 
13626573Sphitran 		if (devp->present == 0) {
13638291SPhi.Tran@Sun.COM 			if (acpi_drv_psr_devp == devp) {
13648291SPhi.Tran@Sun.COM 				acpi_drv_set_psr(NULL);
13658291SPhi.Tran@Sun.COM 			}
13668291SPhi.Tran@Sun.COM 			goto done;
13676573Sphitran 		}
13686573Sphitran 
13696573Sphitran 		if (acpi_drv_update_bst(bp) != ACPI_DRV_OK) {
13706573Sphitran 			break;
13716573Sphitran 		}
13726573Sphitran 		acpi_drv_update_cap(bif_changed);
13736573Sphitran 
13746573Sphitran 		bst = &bp->bst_cache;
13756573Sphitran 		eval = bst->bst_rem_cap;
13766573Sphitran 
13776573Sphitran 		if (bst->bst_state & BST_FLAG_DISCHARGING) {
13786573Sphitran 			acpi_drv_set_psr(devp);
13796573Sphitran 		}
13806573Sphitran 		/*
13816573Sphitran 		 * The Critical battery state indicates that all
13826573Sphitran 		 * available batteries are discharged and do not
13836573Sphitran 		 * appear to be able to supply power to run the
13846573Sphitran 		 * system any longer. When this occurs, the OS
13856573Sphitran 		 * should attempt to perform an emergency shutdown.
13866573Sphitran 		 * Right now we do not shutdown.  This would
13876573Sphitran 		 * need some discussion first since it could be
13886573Sphitran 		 * controversial.
13896573Sphitran 		 */
13906573Sphitran #ifdef DEBUG
13916573Sphitran 		if (bst->bst_state & BST_FLAG_CRITICAL) {
13926573Sphitran 			ACPI_DRV_DBG(CE_WARN, devp, "BST_FLAG_CRITICAL set");
13936573Sphitran 
13946573Sphitran 			/*
13956573Sphitran 			 * BST_FLAG_CRITICAL may set even with AC,
13966573Sphitran 			 * plugged, when plug/unplug battery. Check
13976573Sphitran 			 * to avoid erroneous shutdown.
13986573Sphitran 			 */
13996573Sphitran 			if (acpi_drv_psr_devp == devp &&
14006573Sphitran 			    bst->bst_rem_cap != 0xffffffff) {
14016573Sphitran 				ACPI_DRV_DBG(CE_WARN, NULL,
14026573Sphitran 				    "Battery in critical state");
14036573Sphitran 			}
14046573Sphitran 		} else
14056573Sphitran #endif
14066573Sphitran 		if (acpi_drv_warn_enabled &&
14076573Sphitran 		    (bst->bst_state & BST_FLAG_DISCHARGING)) {
14086573Sphitran 			/*
14096573Sphitran 			 * This value is an estimation of the amount of
14106573Sphitran 			 * energy or battery capacity required by the
14116573Sphitran 			 * system to transition to any supported sleeping
14126573Sphitran 			 * state. When the OS detects that the total
14136573Sphitran 			 * available battery capacity is less than this
14146573Sphitran 			 * value, it will transition the system to a user
14156573Sphitran 			 * defined system state (S1-S5).
14166573Sphitran 			 */
14176573Sphitran 			if (acpi_drv_syn_last_level > acpi_drv_syn_low_cap &&
14186573Sphitran 			    acpi_drv_syn_rem_cap <= acpi_drv_syn_low_cap) {
14196573Sphitran 				acpi_drv_gen_sysevent(devp, ESC_PWRCTL_LOW,
14206573Sphitran 				    eval);
14216573Sphitran 			/*
14226573Sphitran 			 * When the total available energy (mWh) or capacity
14236573Sphitran 			 * (mAh) in the batteries falls below this level,
14246573Sphitran 			 * the OS will notify the user through the UI.
14256573Sphitran 			 */
14266573Sphitran 			} else if (acpi_drv_syn_last_level >
14276573Sphitran 			    acpi_drv_syn_warn_cap &&
14286573Sphitran 			    acpi_drv_syn_rem_cap <= acpi_drv_syn_warn_cap) {
14296573Sphitran 				acpi_drv_gen_sysevent(devp, ESC_PWRCTL_WARN,
14306573Sphitran 				    eval);
14316573Sphitran 			}
14326573Sphitran 		}
14336573Sphitran 
14348291SPhi.Tran@Sun.COM done:
14356573Sphitran 		acpi_drv_gen_sysevent(devp, ESC_PWRCTL_STATE_CHANGE, 0);
14366573Sphitran 		pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS);
14376573Sphitran 		break;
14386573Sphitran 
14396573Sphitran 	/* BIF has changed */
14406573Sphitran 	case 0x81:
14416573Sphitran 		/*
14426573Sphitran 		 * Note: Do not eliminate multiple ADD/REMOVE here,
14436573Sphitran 		 * because they may corresponding to different batterys.
14446573Sphitran 		 */
14456573Sphitran 		(void) acpi_drv_update_present(devp);
14466573Sphitran 		if (devp->present == 1) {
14476573Sphitran 			if (acpi_drv_update_bif(bp) != ACPI_DRV_OK) {
14486573Sphitran 				break;
14496573Sphitran 			}
14506573Sphitran 		}
14516573Sphitran 
14526573Sphitran 		acpi_drv_update_cap(1);
14536573Sphitran 
14546573Sphitran 		eval = devp->present;
14556573Sphitran 		ev = eval ? ESC_PWRCTL_ADD : ESC_PWRCTL_REMOVE;
14566573Sphitran 		acpi_drv_gen_sysevent(devp, ev, 0);
14576573Sphitran 		pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS);
14586573Sphitran 		break;
14596573Sphitran 
14606573Sphitran 	case 0x82:
14616573Sphitran 	default:
14626573Sphitran 		break;
14636573Sphitran 	}
14646573Sphitran 
14656573Sphitran 	mutex_exit(&acpi_drv_mutex);
14666573Sphitran }
14676573Sphitran 
14686573Sphitran static int
acpi_drv_update_lid(struct acpi_drv_dev * p)14696573Sphitran acpi_drv_update_lid(struct acpi_drv_dev *p)
14706573Sphitran {
14716573Sphitran 	struct acpi_drv_lid_state *lp = (struct acpi_drv_lid_state *)p;
14726573Sphitran 
14736573Sphitran 	if (acpica_eval_int(p->hdl, "_LID", &lp->state) == AE_OK) {
14746573Sphitran 		lp->state_ok = ACPI_DRV_NTF_OK;
14756573Sphitran 		return (ACPI_DRV_OK);
14766573Sphitran 	}
14776573Sphitran 	return (ACPI_DRV_ERR);
14786573Sphitran }
14796573Sphitran 
14806573Sphitran /*ARGSUSED*/
14816573Sphitran static void
acpi_drv_ac_notify(ACPI_HANDLE hdl,UINT32 val,void * ctx)14826573Sphitran acpi_drv_ac_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx)
14836573Sphitran {
14846573Sphitran 	struct acpi_drv_ac_state *acp = ctx;
14856573Sphitran 	struct acpi_drv_dev *devp = &acp->dev;
14866573Sphitran 	int old_present;
14876573Sphitran 	char *ev;
14886573Sphitran 	int eval;
14896573Sphitran 
14906573Sphitran 	ACPI_DRV_PRT_NOTIFY(hdl, val);
14916573Sphitran 	if (val != 0x80) {
14926573Sphitran 		return;
14936573Sphitran 	}
14946573Sphitran 
14956573Sphitran 	mutex_enter(&acpi_drv_mutex);
14966573Sphitran 	/*
14976573Sphitran 	 * Note: if unplug and then quickly plug back, two ADD
14986573Sphitran 	 * events will be generated.
14996573Sphitran 	 */
15006573Sphitran 	old_present = devp->present;
15016573Sphitran 	eval = acpi_drv_get_psr(acp);
15026573Sphitran 
15036573Sphitran 	/* Eliminate redundant events */
15046573Sphitran 	if (eval != -1 && eval != old_present) {
15056573Sphitran 		/* Keep tracking the current power source device */
15066573Sphitran 		if (eval == 1) {
15076573Sphitran 			ev = ESC_PWRCTL_ADD;
15086573Sphitran 			acpi_drv_set_psr(devp);
15096573Sphitran 		} else {
15106573Sphitran 			ev = ESC_PWRCTL_REMOVE;
15116573Sphitran 			/* If AC was supplying the power, it's not now */
15126573Sphitran 			if (acpi_drv_psr_devp == devp) {
15136573Sphitran 				acpi_drv_set_psr(NULL);
15146573Sphitran 			}
15156573Sphitran 		}
15166573Sphitran 
15176573Sphitran 		acpi_drv_gen_sysevent(devp, ev, 0);
15186573Sphitran 		pollwakeup(&acpi_drv_pollhead, ACPI_DRV_EVENTS);
15196573Sphitran 	}
15206573Sphitran 
15216573Sphitran 	mutex_exit(&acpi_drv_mutex);
15226573Sphitran }
15236573Sphitran 
15246573Sphitran static void
acpi_drv_lid_notify(ACPI_HANDLE hdl,UINT32 val,void * ctx)15256573Sphitran acpi_drv_lid_notify(ACPI_HANDLE hdl, UINT32 val, void *ctx)
15266573Sphitran {
15276573Sphitran 	struct acpi_drv_lid_state *p = ctx;
15286573Sphitran 
15296573Sphitran 	ACPI_DRV_PRT_NOTIFY(hdl, val);
15306573Sphitran 	if (val == 0x80) {
15316573Sphitran 		mutex_enter(&acpi_drv_mutex);
15326573Sphitran 		if (acpi_drv_update_lid(&p->dev) == ACPI_DRV_OK) {
15336573Sphitran 			acpi_drv_gen_sysevent(&p->dev, p->state ?
15346573Sphitran 			    ESC_PWRCTL_ADD : ESC_PWRCTL_REMOVE, 0);
15356573Sphitran 		}
15366573Sphitran 		mutex_exit(&acpi_drv_mutex);
15376573Sphitran 	}
15386573Sphitran }
15396573Sphitran 
15406573Sphitran static int
acpi_drv_obj_init(struct acpi_drv_dev * p)15416573Sphitran acpi_drv_obj_init(struct acpi_drv_dev *p)
15426573Sphitran {
15436573Sphitran 	ACPI_DEVICE_INFO *info;
15446573Sphitran 	ACPI_NOTIFY_HANDLER ntf_handler = NULL;
15456573Sphitran 	ACPI_STATUS ret;
15466573Sphitran 
15476573Sphitran 	ASSERT(p != NULL && p->hdl != NULL);
15486573Sphitran 
15496573Sphitran 	p->valid = 0;
15506573Sphitran 
15516573Sphitran 	/* Info size is variable depending on existance of _CID */
155211225SDana.Myers@Sun.COM 	ret = AcpiGetObjectInfo(p->hdl, &info);
15536573Sphitran 	if (ACPI_FAILURE(ret)) {
15546573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
15556573Sphitran 		    "AcpiGetObjectInfo() fail: %d", (int32_t)ret);
15566573Sphitran 		return (ACPI_DRV_ERR);
15576573Sphitran 	}
15586573Sphitran 
15596573Sphitran 	if ((info->Valid & ACPI_VALID_HID) == 0) {
15606573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
15616573Sphitran 		    "AcpiGetObjectInfo(): _HID not available");
1562*12004Sjiang.liu@intel.com 		p->hid[0] = 0;
15636573Sphitran 	} else {
1564*12004Sjiang.liu@intel.com 		(void) strlcpy(p->hid, info->HardwareId.String, ID_LEN);
15656573Sphitran 	}
15666573Sphitran 
15676573Sphitran 	/*
15686573Sphitran 	 * This object is optional, but is required when the device
15696573Sphitran 	 * has no other way to report a persistent unique device ID.
15706573Sphitran 	 */
15716573Sphitran 	if ((info->Valid & ACPI_VALID_UID) == 0) {
15726573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
15736573Sphitran 		    "AcpiGetObjectInfo(): _UID not available");
15746573Sphitran 		/* Use 0 as the default _UID */
1575*12004Sjiang.liu@intel.com 		p->uid[0] = 0;
15766573Sphitran 	} else {
1577*12004Sjiang.liu@intel.com 		(void) strlcpy(p->uid, info->UniqueId.String, ID_LEN);
15786573Sphitran 	}
15796573Sphitran 
158011225SDana.Myers@Sun.COM 	AcpiOsFree(info);
15816573Sphitran 	p->valid = 1;
15826573Sphitran 
15836573Sphitran 	if (strcmp(p->hid, ACPI_DEVNAME_CBAT) == 0) {
15846573Sphitran 		struct acpi_drv_cbat_state *bp =
15856573Sphitran 		    (struct acpi_drv_cbat_state *)p;
15866573Sphitran 
15876573Sphitran 		p->type = ACPI_DRV_TYPE_CBAT;
15886573Sphitran 		p->index = nbat - 1;
15896573Sphitran 
15906573Sphitran 		/* Update device present state */
15916573Sphitran 		(void) acpi_drv_update_present(p);
15926573Sphitran 		if (p->present) {
15936573Sphitran 			(void) acpi_drv_update_bif(bp);
15946573Sphitran 			(void) acpi_drv_update_bst(bp);
15956573Sphitran 
15966573Sphitran 			/* Init the current power source */
15976573Sphitran 			if (bp->bst_cache.bst_state & BST_FLAG_DISCHARGING) {
15986573Sphitran 				acpi_drv_set_psr(p);
15996573Sphitran 			}
16006573Sphitran 		}
16016573Sphitran 		ntf_handler = acpi_drv_cbat_notify;
16026573Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "battery %s",
16036573Sphitran 		    (p->present ? "present" : "absent"));
16046573Sphitran 	} else if (strcmp(p->hid, ACPI_DEVNAME_AC) == 0) {
16056573Sphitran 		p->type = ACPI_DRV_TYPE_AC;
16066573Sphitran 		p->index = nac - 1;
16076573Sphitran 
16086573Sphitran 		/* Update device present state */
16096573Sphitran 		(void) acpi_drv_update_present(p);
16106573Sphitran 		if (p->present) {
16116573Sphitran 			/* Init the current power source */
16126573Sphitran 			acpi_drv_set_psr(p);
16136573Sphitran 		}
16146573Sphitran 		ntf_handler = acpi_drv_ac_notify;
16156573Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "AC %s",
16166573Sphitran 		    (p->present ? "on-line" : "off-line"));
16176573Sphitran 	} else if (strcmp(p->hid, ACPI_DEVNAME_LID) == 0) {
16186573Sphitran 		p->type = ACPI_DRV_TYPE_LID;
16197051Sphitran 		p->index = 0;
16206573Sphitran 		lid.state_ok = ACPI_DRV_NTF_UNKNOWN;
16216573Sphitran 		(void) acpi_drv_update_lid(p);
16226573Sphitran 		ntf_handler = acpi_drv_lid_notify;
16236573Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "added");
16246573Sphitran 	} else {
16256573Sphitran 		ACPI_DRV_DBG(CE_NOTE, p, "unknown device");
16266573Sphitran 		p->valid = 0;
16276573Sphitran 	}
16286573Sphitran 
16296573Sphitran 	/* Register ACPI battery related events */
16306573Sphitran 	if (ntf_handler != NULL) {
16316573Sphitran 		if (ACPI_FAILURE(AcpiInstallNotifyHandler(p->hdl,
16326573Sphitran 		    ACPI_ALL_NOTIFY, ntf_handler, p))) {
16336573Sphitran 			ACPI_DRV_DBG(CE_NOTE, NULL,
16346573Sphitran 			    "Notify handler for %s.%s install failed",
16356573Sphitran 			    p->hid, p->uid);
16366573Sphitran 			return (ACPI_DRV_ERR);
16376573Sphitran 		}
16386573Sphitran 	}
16396573Sphitran 
16406573Sphitran 	return (ACPI_DRV_OK);
16416573Sphitran }
16426573Sphitran 
16436573Sphitran /*ARGSUSED*/
16446573Sphitran static ACPI_STATUS
acpi_drv_find_cb(ACPI_HANDLE ObjHandle,UINT32 NestingLevel,void * Context,void ** ReturnValue)16456573Sphitran acpi_drv_find_cb(ACPI_HANDLE ObjHandle, UINT32 NestingLevel, void *Context,
16466573Sphitran     void **ReturnValue)
16476573Sphitran {
16487051Sphitran 	struct acpi_drv_dev *devp;
16497051Sphitran 	int *type = (int *)Context;
16506573Sphitran 
16517051Sphitran 	if (*type == ACPI_DRV_TYPE_CBAT) {
16526573Sphitran 		struct acpi_drv_cbat_state *bp;
16536573Sphitran 
16546573Sphitran 		if (nbat == ACPI_DRV_MAX_BAT_NUM) {
16556573Sphitran 			ACPI_DRV_DBG(CE_WARN, NULL,
16566573Sphitran 			    "Need to support more batteries: "
16576573Sphitran 			    "BATTERY_MAX = %d", ACPI_DRV_MAX_BAT_NUM);
16586573Sphitran 			return (AE_LIMIT);
16596573Sphitran 		}
16606573Sphitran 		bp = &acpi_drv_cbat[nbat++];
16616573Sphitran 		devp = (struct acpi_drv_dev *)bp;
16627051Sphitran 	} else if (*type == ACPI_DRV_TYPE_AC) {
16636573Sphitran 		struct acpi_drv_ac_state *ap;
16646573Sphitran 
16656573Sphitran 		if (nac == ACPI_DRV_MAX_AC_NUM) {
16666573Sphitran 			ACPI_DRV_DBG(CE_WARN, NULL, "Need to support more ACs: "
16676573Sphitran 			    "AC_MAX = %d", ACPI_DRV_MAX_AC_NUM);
16686573Sphitran 			return (AE_LIMIT);
16696573Sphitran 		}
16706573Sphitran 		ap = &acpi_drv_ac[nac++];
16716573Sphitran 		devp = (struct acpi_drv_dev *)ap;
16727051Sphitran 	} else if (*type == ACPI_DRV_TYPE_LID) {
16736573Sphitran 		struct acpi_drv_lid_state *lp;
16746573Sphitran 
16757051Sphitran 		nlid++;
16766573Sphitran 		lp = &lid;
16776573Sphitran 		devp = (struct acpi_drv_dev *)lp;
16786573Sphitran 	} else {
16796573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "acpi_drv_find_cb(): "
16806573Sphitran 		    "Unknown device");
16816573Sphitran 		return (AE_ERROR);
16826573Sphitran 	}
16836573Sphitran 
16846573Sphitran 	devp->hdl = ObjHandle;
16856573Sphitran 
16866573Sphitran 	/* Try to get as many working objs as possible */
16876573Sphitran 	(void) acpi_drv_obj_init(devp);
16886573Sphitran 	return (AE_OK);
16896573Sphitran }
16906573Sphitran 
16916573Sphitran static int
acpi_drv_acpi_init()16926573Sphitran acpi_drv_acpi_init()
16936573Sphitran {
16947051Sphitran 	int *retp, type;
16957051Sphitran 	int status = ACPI_DRV_ERR;
16968693SKerry.Shu@Sun.COM 	hotkey_drv_t *htkp;
16976573Sphitran 
16986573Sphitran 	/* Check to see if ACPI CA services are available */
16996573Sphitran 	if (AcpiSubsystemStatus() != AE_OK) {
17006573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL, "ACPI CA not ready");
17017051Sphitran 		return (status);
17026573Sphitran 	}
17036573Sphitran 
17046573Sphitran 	/* Init Control Method Batterys */
17057051Sphitran 	type = ACPI_DRV_TYPE_CBAT;
17067051Sphitran 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_CBAT, acpi_drv_find_cb,
17077051Sphitran 	    &type, (void *)&retp)) && nbat) {
17087051Sphitran 		status = ACPI_DRV_OK;
17096573Sphitran 	}
17106573Sphitran 
17116573Sphitran 	/* Init AC */
17127051Sphitran 	type = ACPI_DRV_TYPE_AC;
17137051Sphitran 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_AC, acpi_drv_find_cb,
17147051Sphitran 	    &type, (void *)&retp)) && nac) {
17157051Sphitran 		status = ACPI_DRV_OK;
17166573Sphitran 	}
17176573Sphitran 
17186573Sphitran 	/* Init LID */
17197051Sphitran 	type = ACPI_DRV_TYPE_LID;
17207051Sphitran 	if (ACPI_SUCCESS(AcpiGetDevices(ACPI_DEVNAME_LID, acpi_drv_find_cb,
17217051Sphitran 	    &type, (void *)&retp)) && nlid) {
17227051Sphitran 		status = ACPI_DRV_OK;
17236573Sphitran 	}
17246573Sphitran 
17258693SKerry.Shu@Sun.COM 	/* Init Hotkey Device */
17268693SKerry.Shu@Sun.COM 	type = ACPI_DRV_TYPE_HOTKEY;
17278693SKerry.Shu@Sun.COM 	htkp = &acpi_hotkey;
17288693SKerry.Shu@Sun.COM 	bzero(htkp, sizeof (hotkey_drv_t));
17298693SKerry.Shu@Sun.COM 	htkp->dip = acpi_drv_dip;
17308693SKerry.Shu@Sun.COM 	htkp->hotkey_lock = &acpi_drv_mutex;
17318693SKerry.Shu@Sun.COM 	if (hotkey_init(htkp) == ACPI_DRV_OK) {
17327051Sphitran 		status = ACPI_DRV_OK;
17336573Sphitran 	}
17346573Sphitran 
17356573Sphitran 	acpi_drv_update_cap(1);
17366573Sphitran 
17377051Sphitran 	return (status);
17386573Sphitran }
17396573Sphitran 
17406573Sphitran static void
acpi_drv_acpi_fini(void)17416573Sphitran acpi_drv_acpi_fini(void)
17426573Sphitran {
17436573Sphitran 	int i;
17446573Sphitran 	struct acpi_drv_cbat_state *bp;
17456573Sphitran 
17466573Sphitran 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
17476573Sphitran 	    bp++) {
17486573Sphitran 		if (bp->dev.valid) {
174911387SSurya.Prakki@Sun.COM 			(void) AcpiRemoveNotifyHandler(bp->dev.hdl,
175011387SSurya.Prakki@Sun.COM 			    ACPI_DEVICE_NOTIFY, acpi_drv_cbat_notify);
17516573Sphitran 		}
17526573Sphitran 	}
17536573Sphitran 	for (i = 0; i < nac; i++) {
175411387SSurya.Prakki@Sun.COM 		(void) AcpiRemoveNotifyHandler(acpi_drv_ac[i].dev.hdl,
17556573Sphitran 		    ACPI_DEVICE_NOTIFY, acpi_drv_ac_notify);
17566573Sphitran 	}
175711387SSurya.Prakki@Sun.COM 	(void) AcpiRemoveNotifyHandler(lid.dev.hdl, ACPI_DEVICE_NOTIFY,
17586573Sphitran 	    acpi_drv_lid_notify);
17598693SKerry.Shu@Sun.COM 
17608693SKerry.Shu@Sun.COM 	if (acpi_hotkey.hotkey_method != HOTKEY_METHOD_NONE)
17618693SKerry.Shu@Sun.COM 		(void) hotkey_fini(&acpi_hotkey);
17626573Sphitran }
17636573Sphitran 
17646573Sphitran /*ARGSUSED*/
17656573Sphitran static int
acpi_drv_kstat_power_update(kstat_t * ksp,int flag)17666573Sphitran acpi_drv_kstat_power_update(kstat_t *ksp, int flag)
17676573Sphitran {
17686573Sphitran 	if (flag == KSTAT_WRITE) {
17696573Sphitran 		return (EACCES);
17706573Sphitran 	}
17716573Sphitran 
17726573Sphitran 	mutex_enter(&acpi_drv_mutex);
17736573Sphitran 	if (acpi_drv_psr_type == ACPI_DRV_TYPE_UNKNOWN) {
17746573Sphitran 		mutex_exit(&acpi_drv_mutex);
17756573Sphitran 		return (EIO);
17766573Sphitran 	}
17776573Sphitran 	kstat_named_setstr(&acpi_drv_power_kstat.acpi_drv_power,
17786573Sphitran 	    acpi_drv_psr_type == ACPI_DRV_TYPE_AC ? AC : BATTERY);
17796573Sphitran 	acpi_drv_power_kstat.acpi_drv_supported_battery_count.value.ui32 =
17806573Sphitran 	    (uint32_t)nbat;
17816573Sphitran 	mutex_exit(&acpi_drv_mutex);
17826573Sphitran 
17836573Sphitran 	return (0);
17846573Sphitran }
17856573Sphitran 
17866573Sphitran /*ARGSUSED*/
17876573Sphitran static int
acpi_drv_kstat_warn_update(kstat_t * ksp,int flag)17886573Sphitran acpi_drv_kstat_warn_update(kstat_t *ksp, int flag)
17896573Sphitran {
17906573Sphitran 	if (flag == KSTAT_WRITE) {
17916573Sphitran 		int ret = 0;
17926573Sphitran 		acpi_drv_warn_t bw;
17936573Sphitran 		acpi_drv_warn_kstat_t kbw;
17946573Sphitran 
17956573Sphitran 		kbw = *(acpi_drv_warn_kstat_t *)acpi_drv_warn_ksp->ks_data;
17966573Sphitran 
17976573Sphitran 		mutex_enter(&acpi_drv_mutex);
17986573Sphitran 		bw.bw_enabled  = kbw.acpi_drv_bw_enabled.value.ui32;
17996573Sphitran 		bw.bw_charge_warn = kbw.acpi_drv_bw_charge_warn.value.ui32;
18006573Sphitran 		bw.bw_charge_low = kbw.acpi_drv_bw_charge_low.value.ui32;
18016573Sphitran 		ret = acpi_drv_set_warn(&bw);
18026573Sphitran 		mutex_exit(&acpi_drv_mutex);
18036573Sphitran 
18046573Sphitran 		return (ret);
18056573Sphitran 	} else {
18066573Sphitran 		acpi_drv_warn_kstat_t *wp = &acpi_drv_warn_kstat;
18076573Sphitran 
18086573Sphitran 		mutex_enter(&acpi_drv_mutex);
18096573Sphitran 		wp->acpi_drv_bw_enabled.value.ui32 = acpi_drv_warn_enabled;
18106573Sphitran 		wp->acpi_drv_bw_charge_warn.value.ui32 = acpi_drv_syn_warn_per;
18116573Sphitran 		wp->acpi_drv_bw_charge_low.value.ui32 = acpi_drv_syn_low_per;
18126573Sphitran 		mutex_exit(&acpi_drv_mutex);
18136573Sphitran 
18146573Sphitran 		return (0);
18156573Sphitran 	}
18166573Sphitran }
18176573Sphitran 
18186573Sphitran static int
acpi_drv_kstat_bif_update(kstat_t * ksp,int flag)18196573Sphitran acpi_drv_kstat_bif_update(kstat_t *ksp, int flag)
18206573Sphitran {
18216573Sphitran 	struct acpi_drv_cbat_state *bp;
18226573Sphitran 	acpi_bif_t *bif;
18236573Sphitran 	acpi_drv_bif_kstat_t *kp;
18246573Sphitran 
18256573Sphitran 	if (flag == KSTAT_WRITE) {
18266573Sphitran 		return (EACCES);
18276573Sphitran 	}
18286573Sphitran 
18296573Sphitran 	bp = (struct acpi_drv_cbat_state *)ksp->ks_private;
18306573Sphitran 	mutex_enter(&acpi_drv_mutex);
18316573Sphitran 
18326573Sphitran 	if (acpi_drv_cbat_present(bp) <= 0) {
18336573Sphitran 		mutex_exit(&acpi_drv_mutex);
18346573Sphitran 		return (ENXIO);
18356573Sphitran 	}
18366573Sphitran 
18376573Sphitran 	bzero(&bif, sizeof (bif));
18386573Sphitran 	if (acpi_drv_update_bif(bp) != ACPI_DRV_OK) {
18396573Sphitran 		mutex_exit(&acpi_drv_mutex);
18406573Sphitran 		return (ENXIO);
18416573Sphitran 	}
18426573Sphitran 
18436573Sphitran 	bif = &bp->bif_cache;
18446573Sphitran 	kp = &acpi_drv_bif_kstat;
18456573Sphitran 
18466573Sphitran 	/* Update BIF */
18476573Sphitran 	kp->acpi_drv_bif_unit.value.ui32 = bif->bif_unit;
18486573Sphitran 	kp->acpi_drv_bif_design_cap.value.ui32 = bif->bif_design_cap;
18496573Sphitran 	kp->acpi_drv_bif_last_cap.value.ui32 = bif->bif_last_cap;
18506573Sphitran 	kp->acpi_drv_bif_tech.value.ui32 = bif->bif_tech;
18516573Sphitran 	kp->acpi_drv_bif_voltage.value.ui32 = bif->bif_voltage;
18526573Sphitran 	kp->acpi_drv_bif_warn_cap.value.ui32 = bif->bif_warn_cap;
18536573Sphitran 	kp->acpi_drv_bif_low_cap.value.ui32 = bif->bif_low_cap;
18546573Sphitran 	kp->acpi_drv_bif_gran1_cap.value.ui32 = bif->bif_gran1_cap;
18556573Sphitran 	kp->acpi_drv_bif_gran2_cap.value.ui32 = bif->bif_gran2_cap;
18566573Sphitran 
18576573Sphitran 	kstat_named_setstr(&kp->acpi_drv_bif_model, bif->bif_model);
18586573Sphitran 	kstat_named_setstr(&kp->acpi_drv_bif_serial, bif->bif_serial);
18596573Sphitran 	kstat_named_setstr(&kp->acpi_drv_bif_type, bif->bif_type);
18606573Sphitran 	kstat_named_setstr(&kp->acpi_drv_bif_oem_info, bif->bif_oem_info);
18616573Sphitran 
18626573Sphitran 	mutex_exit(&acpi_drv_mutex);
18636573Sphitran 	return (0);
18646573Sphitran }
18656573Sphitran 
18666573Sphitran static int
acpi_drv_kstat_bst_update(kstat_t * ksp,int flag)18676573Sphitran acpi_drv_kstat_bst_update(kstat_t *ksp, int flag)
18686573Sphitran {
18696573Sphitran 	struct acpi_drv_cbat_state *bp;
18706573Sphitran 	acpi_bst_t *bst;
18716573Sphitran 	acpi_drv_bst_kstat_t *kp;
18726573Sphitran 
18736573Sphitran 	if (flag == KSTAT_WRITE) {
18746573Sphitran 		return (EACCES);
18756573Sphitran 	}
18766573Sphitran 
18776573Sphitran 	bp = (struct acpi_drv_cbat_state *)ksp->ks_private;
18786573Sphitran 	mutex_enter(&acpi_drv_mutex);
18796573Sphitran 
18806573Sphitran 	if (acpi_drv_cbat_present(bp) <= 0) {
18816573Sphitran 		mutex_exit(&acpi_drv_mutex);
18826573Sphitran 		return (ENXIO);
18836573Sphitran 	}
18846573Sphitran 
18856573Sphitran 	bzero(&bst, sizeof (bst));
18866573Sphitran 	if (acpi_drv_update_bst(bp) != ACPI_DRV_OK) {
18876573Sphitran 		mutex_exit(&acpi_drv_mutex);
18886573Sphitran 		return (ENXIO);
18896573Sphitran 	}
18906573Sphitran 
18916573Sphitran 	bst = &bp->bst_cache;
18926573Sphitran 	kp = &acpi_drv_bst_kstat;
18936573Sphitran 
18946573Sphitran 	/* Update BST */
18956573Sphitran 	kp->acpi_drv_bst_state.value.ui32 = bst->bst_state;
18966573Sphitran 	kp->acpi_drv_bst_rate.value.ui32 = bst->bst_rate;
18976573Sphitran 	kp->acpi_drv_bst_rem_cap.value.ui32 = bst->bst_rem_cap;
18986573Sphitran 	kp->acpi_drv_bst_voltage.value.ui32 = bst->bst_voltage;
18996573Sphitran 
19006573Sphitran 	mutex_exit(&acpi_drv_mutex);
19016573Sphitran 	return (0);
19026573Sphitran }
19036573Sphitran 
19046573Sphitran static int
acpi_drv_kstat_init(void)19056573Sphitran acpi_drv_kstat_init(void)
19066573Sphitran {
19076573Sphitran 	char name[KSTAT_STRLEN];
19086573Sphitran 	struct acpi_drv_cbat_state *bp;
19096573Sphitran 
19106573Sphitran 	/*
19116573Sphitran 	 * Allocate, initialize and install powerstatus and
19126573Sphitran 	 * supported_battery_count kstat.
19136573Sphitran 	 */
19146573Sphitran 	acpi_drv_power_ksp = kstat_create(ACPI_DRV_NAME, 0,
19156573Sphitran 	    ACPI_DRV_POWER_KSTAT_NAME, "misc",
19166573Sphitran 	    KSTAT_TYPE_NAMED,
19176573Sphitran 	    sizeof (acpi_drv_power_kstat) / sizeof (kstat_named_t),
19186573Sphitran 	    KSTAT_FLAG_VIRTUAL);
19196573Sphitran 	if (acpi_drv_power_ksp == NULL) {
19206573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
19216573Sphitran 		    "kstat_create(%s) fail", ACPI_DRV_POWER_KSTAT_NAME);
19226573Sphitran 		return (ACPI_DRV_ERR);
19236573Sphitran 	}
19246573Sphitran 
19256573Sphitran 	acpi_drv_power_ksp->ks_data = &acpi_drv_power_kstat;
19266573Sphitran 	acpi_drv_power_ksp->ks_update = acpi_drv_kstat_power_update;
19276573Sphitran 	acpi_drv_power_ksp->ks_data_size += MAXNAMELEN;
19286573Sphitran 	kstat_install(acpi_drv_power_ksp);
19296573Sphitran 
19306573Sphitran 	/*
19316573Sphitran 	 * Allocate, initialize and install battery_capacity_warning kstat.
19326573Sphitran 	 */
19336573Sphitran 	acpi_drv_warn_ksp = kstat_create(ACPI_DRV_NAME, 0,
19346573Sphitran 	    ACPI_DRV_BTWARN_KSTAT_NAME, "misc",
19356573Sphitran 	    KSTAT_TYPE_NAMED,
19366573Sphitran 	    sizeof (acpi_drv_warn_kstat) / sizeof (kstat_named_t),
19376573Sphitran 	    KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE);
19386573Sphitran 	if (acpi_drv_warn_ksp == NULL) {
19396573Sphitran 		ACPI_DRV_DBG(CE_WARN, NULL,
19406573Sphitran 		    "kstat_create(%s) fail", ACPI_DRV_BTWARN_KSTAT_NAME);
19416573Sphitran 		return (ACPI_DRV_ERR);
19426573Sphitran 	}
19436573Sphitran 
19446573Sphitran 	acpi_drv_warn_ksp->ks_data = &acpi_drv_warn_kstat;
19456573Sphitran 	acpi_drv_warn_ksp->ks_update = acpi_drv_kstat_warn_update;
19466573Sphitran 	kstat_install(acpi_drv_warn_ksp);
19476573Sphitran 
19486573Sphitran 	/*
19496573Sphitran 	 * Allocate, initialize and install BIF and BST kstat
19506573Sphitran 	 * for each battery.
19516573Sphitran 	 */
19526573Sphitran 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
19536573Sphitran 	    bp++) {
19546573Sphitran 		if (bp->dev.valid) {
19556573Sphitran 			kstat_t *ksp;
19566573Sphitran 
19576573Sphitran 			/* BIF kstat */
19586573Sphitran 			(void) snprintf(name, KSTAT_STRLEN-1, "%s%d",
19596573Sphitran 			    ACPI_DRV_BIF_KSTAT_NAME, bp->dev.index);
19606573Sphitran 			ksp = kstat_create(ACPI_DRV_NAME, 0,
19616573Sphitran 			    name, "misc", KSTAT_TYPE_NAMED,
19626573Sphitran 			    sizeof (acpi_drv_bif_kstat) /
19636573Sphitran 			    sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
19646573Sphitran 			if (ksp == NULL) {
19656573Sphitran 				ACPI_DRV_DBG(CE_WARN, NULL,
19666573Sphitran 				    "kstat_create(%s) fail", name);
19676573Sphitran 				return (ACPI_DRV_ERR);
19686573Sphitran 			}
19696573Sphitran 			ACPI_DRV_DBG(CE_NOTE, NULL, "kstat_create(%s) ok",
19706573Sphitran 			    name);
19716573Sphitran 
19726573Sphitran 			bp->bat_bif_ksp = ksp;
19736573Sphitran 			ksp->ks_data = &acpi_drv_bif_kstat;
19746573Sphitran 			ksp->ks_update = acpi_drv_kstat_bif_update;
19756573Sphitran 			ksp->ks_data_size += MAXNAMELEN * 4;
19766573Sphitran 			ksp->ks_private = bp;
19776573Sphitran 
19786573Sphitran 			kstat_install(ksp);
19796573Sphitran 
19806573Sphitran 			/* BST kstat */
19816573Sphitran 			(void) snprintf(name, KSTAT_STRLEN-1, "%s%d",
19826573Sphitran 			    ACPI_DRV_BST_KSTAT_NAME, bp->dev.index);
19836573Sphitran 			ksp = kstat_create(ACPI_DRV_NAME, 0, name, "misc",
19846573Sphitran 			    KSTAT_TYPE_NAMED,
19856573Sphitran 			    sizeof (acpi_drv_bst_kstat) /
19866573Sphitran 			    sizeof (kstat_named_t),
19876573Sphitran 			    KSTAT_FLAG_VIRTUAL);
19886573Sphitran 			if (ksp == NULL) {
19896573Sphitran 				ACPI_DRV_DBG(CE_WARN, NULL,
19906573Sphitran 				    "kstat_create(%s) fail", name);
19916573Sphitran 				return (ACPI_DRV_ERR);
19926573Sphitran 			}
19936573Sphitran 			ACPI_DRV_DBG(CE_NOTE, NULL, "kstat_create(%s) ok",
19946573Sphitran 			    name);
19956573Sphitran 
19966573Sphitran 			bp->bat_bst_ksp = ksp;
19976573Sphitran 			ksp->ks_data = &acpi_drv_bst_kstat;
19986573Sphitran 			ksp->ks_update = acpi_drv_kstat_bst_update;
19996573Sphitran 			ksp->ks_data_size += MAXNAMELEN * 4;
20006573Sphitran 			ksp->ks_private = bp;
20016573Sphitran 
20026573Sphitran 			kstat_install(ksp);
20036573Sphitran 		}
20046573Sphitran 	}
20056573Sphitran 
20066573Sphitran 	return (ACPI_DRV_OK);
20076573Sphitran }
20086573Sphitran 
20096573Sphitran static void
acpi_drv_kstat_fini()20106573Sphitran acpi_drv_kstat_fini()
20116573Sphitran {
20126573Sphitran 	struct acpi_drv_cbat_state *bp;
20136573Sphitran 
20146573Sphitran 	if (acpi_drv_power_ksp != NULL) {
20156573Sphitran 		kstat_delete(acpi_drv_power_ksp);
20166573Sphitran 	}
20176573Sphitran 	if (acpi_drv_warn_ksp != NULL) {
20186573Sphitran 		kstat_delete(acpi_drv_warn_ksp);
20196573Sphitran 	}
20206573Sphitran 	for (bp = &acpi_drv_cbat[0]; bp < &acpi_drv_cbat[ACPI_DRV_MAX_BAT_NUM];
20216573Sphitran 	    bp++) {
20226573Sphitran 		if (bp->dev.valid) {
20236573Sphitran 			if (bp->bat_bif_ksp != NULL) {
20246573Sphitran 				kstat_delete(bp->bat_bif_ksp);
20256573Sphitran 			}
20266573Sphitran 			if (bp->bat_bst_ksp != NULL) {
20276573Sphitran 				kstat_delete(bp->bat_bst_ksp);
20286573Sphitran 			}
20296573Sphitran 		}
20306573Sphitran 	}
20316573Sphitran }
20326573Sphitran 
20338693SKerry.Shu@Sun.COM int
acpi_drv_set_int(ACPI_HANDLE dev,char * method,uint32_t aint)20346573Sphitran acpi_drv_set_int(ACPI_HANDLE dev, char *method, uint32_t aint)
20356573Sphitran {
20366573Sphitran 	ACPI_OBJECT_LIST al;
20376573Sphitran 	ACPI_OBJECT ao;
20386573Sphitran 
20396573Sphitran 	al.Pointer = &ao;
20406573Sphitran 	al.Count = 1;
20416573Sphitran 	ao.Type = ACPI_TYPE_INTEGER;
20426573Sphitran 	ao.Integer.Value = aint;
20436573Sphitran 	return (AcpiEvaluateObject(dev, method, &al, NULL));
20446573Sphitran }
20456573Sphitran 
20468693SKerry.Shu@Sun.COM int
acpi_drv_dev_init(struct acpi_drv_dev * p)20478693SKerry.Shu@Sun.COM acpi_drv_dev_init(struct acpi_drv_dev *p)
20486573Sphitran {
20498693SKerry.Shu@Sun.COM 	ACPI_DEVICE_INFO *info;
20508693SKerry.Shu@Sun.COM 	ACPI_STATUS ret;
20518693SKerry.Shu@Sun.COM 
20528693SKerry.Shu@Sun.COM 	ASSERT(p != NULL && p->hdl != NULL);
20536573Sphitran 
20548693SKerry.Shu@Sun.COM 	p->valid = 0;
20558693SKerry.Shu@Sun.COM 
20568693SKerry.Shu@Sun.COM 	/* Info size is variable depending on existance of _CID */
205711225SDana.Myers@Sun.COM 	ret = AcpiGetObjectInfo(p->hdl, &info);
20588693SKerry.Shu@Sun.COM 	if (ACPI_FAILURE(ret)) {
20598693SKerry.Shu@Sun.COM 		ACPI_DRV_DBG(CE_WARN, NULL,
20608693SKerry.Shu@Sun.COM 		    "AcpiGetObjectInfo() fail: %d", (int32_t)ret);
20616573Sphitran 		return (ACPI_DRV_ERR);
20626573Sphitran 	}
20636573Sphitran 
20648693SKerry.Shu@Sun.COM 	if ((info->Valid & ACPI_VALID_HID) == 0) {
20658693SKerry.Shu@Sun.COM 		ACPI_DRV_DBG(CE_WARN, NULL,
20668693SKerry.Shu@Sun.COM 		    "!AcpiGetObjectInfo(): _HID not available");
2067*12004Sjiang.liu@intel.com 		p->hid[0] = 0;
20688693SKerry.Shu@Sun.COM 	} else {
2069*12004Sjiang.liu@intel.com 		(void) strlcpy(p->hid, info->HardwareId.String, ID_LEN);
20708693SKerry.Shu@Sun.COM 	}
20716573Sphitran 
20728693SKerry.Shu@Sun.COM 	/*
20738693SKerry.Shu@Sun.COM 	 * This object is optional, but is required when the device
20748693SKerry.Shu@Sun.COM 	 * has no other way to report a persistent unique device ID.
20758693SKerry.Shu@Sun.COM 	 */
20768693SKerry.Shu@Sun.COM 	if ((info->Valid & ACPI_VALID_UID) == 0) {
20778693SKerry.Shu@Sun.COM 		ACPI_DRV_DBG(CE_WARN, NULL,
20788693SKerry.Shu@Sun.COM 		    "!AcpiGetObjectInfo(): _UID not available");
20798693SKerry.Shu@Sun.COM 		/* Use 0 as the default _UID */
2080*12004Sjiang.liu@intel.com 		p->uid[0] = 0;
20818693SKerry.Shu@Sun.COM 	} else {
2082*12004Sjiang.liu@intel.com 		(void) strlcpy(p->uid, info->UniqueId.String, ID_LEN);
20836573Sphitran 	}
20846573Sphitran 
20858693SKerry.Shu@Sun.COM 	if (info->Valid & ACPI_VALID_ADR) {
20868693SKerry.Shu@Sun.COM 		p->valid = 1;
20878693SKerry.Shu@Sun.COM 		p->type = ACPI_DRV_TYPE_HOTKEY;
20888693SKerry.Shu@Sun.COM 	}
20896573Sphitran 
20908693SKerry.Shu@Sun.COM 	AcpiOsFree(info);
20916573Sphitran 
20926573Sphitran 	return (ACPI_DRV_OK);
20936573Sphitran }
2094