acpi_drv.c revision 42277d8633e9474e6bea7c26e2e06fa71441981b
/*
* 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
* 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/sysmacros.h>
#include <sys/acpi_drv.h>
#define ACPI_DRV_MOD_STRING "ACPI driver"
#define MINOR_SHIFT 8
(idx))
(idx))
(idx))
| (idx))
(idx))
#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 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_AC "ACPI0003"
#define ACPI_DEVNAME_LID "PNP0C0D"
#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;
do { \
(lev), __VA_ARGS__); \
do { \
#else
#endif /* DEBUG */
/* ACPI notify types */
enum acpi_drv_notify {
};
/* Battery device types */
enum acpi_drv_type {
};
struct acpi_drv_dev {
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 *);
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;
enum acpi_drv_notify bat_bstok;
static int nbat = 0;
/*
* 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;
static int nac = 0;
/*
* 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;
struct obj_desc {
char *name;
int offset;
int size;
int type;
};
/* Object copy definitions */
#define SIZEOF(s, m) (sizeof (((s *)0)->m))
#define FIELD(n, s, m, t) \
};
};
/* kstat definitions */
static kstat_t *acpi_drv_power_ksp;
static kstat_t *acpi_drv_warn_ksp;
};
{ BW_ENABLED, KSTAT_DATA_UINT32 },
};
/* BIF */
{ BIF_UNIT, KSTAT_DATA_UINT32 },
{ BIF_TECH, KSTAT_DATA_UINT32 },
{ BIF_VOLTAGE, KSTAT_DATA_UINT32 },
{ BIF_LOW_CAP, KSTAT_DATA_UINT32 },
{ BIF_MODEL, KSTAT_DATA_STRING },
{ BIF_SERIAL, KSTAT_DATA_STRING },
{ BIF_TYPE, KSTAT_DATA_STRING },
};
/* BST */
{ 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;
static int nlid = 0;
/* Output device status */
#define ACPI_DRV_DCS_CONNECTOR_EXIST (1 << 0)
/* _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)
struct acpi_drv_output_state {
struct acpi_drv_dev dev;
int num_levels; /* number of levels */
int nlev; /* actual array size of levels */
int cur_level;
int cur_level_index;
int state;
struct acpi_drv_output_state *next;
struct acpi_drv_output_state *tail;
};
static int noutput = 0;
struct acpi_drv_display_state {
struct acpi_drv_dev dev;
int mode;
int noutput;
} display;
void **resultp);
#ifdef DEBUG
const char *fmt, ...);
#endif
/*
* Output device functions
*/
/*
* Display device functions
*/
int state);
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 */
};
static struct dev_ops acpi_drv_dev_ops = {
0, /* refcnt */
acpi_drv_getinfo, /* getinfo */
nulldev, /* identify */
nulldev, /* probe */
acpi_drv_attach, /* attach */
acpi_drv_detach, /* detach */
nodev, /* reset */
NULL, /* no bus operations */
NULL /* power */
};
};
static struct modlinkage modlinkage = {
(void *)&modldrv1,
NULL,
};
int
_init(void)
{
int ret;
#ifdef DEBUG
#endif
#ifdef DEBUG
#endif
}
return (ret);
}
int
_fini(void)
{
int ret;
#ifdef DEBUG
#endif
}
return (ret);
}
int
{
}
static int
{
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. */
DDI_FAILURE) {
"%s: minor node create failed", name);
goto error;
}
}
}
/* Create minor node for display device. */
DDI_PSEUDO, 0) == DDI_FAILURE) {
"minor node create failed");
goto error;
}
/* Create minor node for lid. */
DDI_PSEUDO, 0) == DDI_FAILURE) {
goto error;
}
/* Create minor node for each battery and ac */
bp++) {
DDI_FAILURE) {
"%s: minor node create failed", name);
goto error;
}
}
}
for (i = 0; i < nac; i++) {
"%s: minor node create failed", name);
goto error;
}
}
return (DDI_SUCCESS);
acpi_drv_dip = NULL;
return (DDI_FAILURE);
}
static int
{
if (cmd != DDI_DETACH) {
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/* ARGSUSED */
static int
{
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
{
if (acpi_drv_dip == NULL) {
return (ENXIO);
}
return (0);
}
/*ARGSUSED*/
static int
{
return (0);
}
/*ARGSUSED*/
static int
int *rval)
{
int minor;
int res = 0;
switch (type) {
case ACPI_DRV_TYPE_CBAT:
break;
case ACPI_DRV_TYPE_AC:
break;
case ACPI_DRV_TYPE_LID:
break;
case ACPI_DRV_TYPE_OUTPUT:
break;
default:
break;
}
return (res);
}
/*ARGSUSED*/
static int
int *rval)
{
int res = 0;
struct acpi_drv_cbat_state *bp;
return (ENXIO);
}
switch (cmd) {
/*
* Return _BIF(Battery Information) of battery[index],
* if battery plugged.
*/
case ACPI_DRV_IOC_INFO:
break;
}
if (res != ACPI_DRV_OK) {
break;
}
}
break;
/*
* Return _BST(Battery Status) of battery[index],
* if battery plugged.
*/
case ACPI_DRV_IOC_STATUS:
break;
}
if (res != ACPI_DRV_OK) {
break;
}
}
break;
/* Return the state of the battery bays in the system */
case ACPI_DRV_IOC_BAY:
{
bay.battery_map = 0;
for (bp = &acpi_drv_cbat[0];
bay.battery_map |=
}
}
}
break;
}
}
break;
/*
* Return the current power source device if available:
* 0 -- battery supplying power
* 1 -- AC supplying power
*/
{
int val;
/* State not available */
if (acpi_drv_psr_type == ACPI_DRV_TYPE_UNKNOWN) {
break;
}
break;
}
}
break;
/* Get charge-warn and charge-low levels for the whole system */
case ACPI_DRV_IOC_GET_WARNING:
}
break;
/* Set charge-warn and charge-low levels for the whole system */
case ACPI_DRV_IOC_SET_WARNING:
break;
}
break;
}
break;
default:
break;
}
return (res);
}
/*ARGSUSED*/
static int
int *rval)
{
int res = 0;
int ac_state;
struct acpi_drv_ac_state *acp;
return (ENXIO);
}
switch (cmd) {
/* Return the number of AC adapters in the system */
case ACPI_DRV_IOC_AC_COUNT:
}
break;
/*
* Return the state of AC[index] if available:
* 0 -- Off-line
* 1 -- On-line
*/
break;
}
/* State not available */
break;
}
}
break;
default:
break;
}
return (res);
}
/*ARGSUSED*/
static int
int *rval)
{
int res = 0;
switch (cmd) {
case ACPI_DRV_IOC_LID_STATUS:
/* State not available */
if (res != ACPI_DRV_OK) {
break;
}
}
break;
}
break;
default:
break;
}
return (res);
}
/*ARGSUSED*/
static int
{
if (!anyyet) {
*phpp = &acpi_drv_pollhead;
}
*reventsp = 0;
return (0);
}
#ifdef DEBUG
static void
const char *fmt, ...)
{
if (devp) {
} else {
}
}
static void
{
char str[1024];
}
#endif /* DEBUG */
static void
{
int err;
char pathname[MAXPATHLEN];
/* Allocate and build sysevent attribute list */
if (err != 0) {
"cannot allocate memory for sysevent attributes\n");
return;
}
/* Add attributes */
if (err != 0) {
"Failed to add attr [%s] for %s/%s event",
return;
}
if (err != 0) {
"Failed to add attr [%s] for %s/%s event",
return;
}
if (err != 0) {
"Failed to add attr [%s] for %s/%s event",
return;
}
if (err != 0) {
"Failed to add attr [%s] for %s/%s event",
return;
}
goto finish;
}
if (err != 0) {
"Failed to add attr [%s] for %s/%s event",
return;
}
#ifdef DEBUG
if (err != DDI_SUCCESS) {
"cannot log sysevent, err code %x\n", err);
}
#endif
}
static int
{
char *fp;
#ifdef DEBUG
} else {
#ifdef _LP64
}
#else
}
#endif /* _LP64 */
#endif /* DEBUG */
#ifdef DEBUG
int len;
#endif
} else {
"Bad field at offset %d: type %d",
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
{
int ac;
return (-1);
}
} else {
}
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
{
int val;
return (-1);
}
} else {
}
return (val);
}
static int
{
/* BIF is only available when battery plugged */
/* Update internal BIF cache */
return (ACPI_DRV_ERR);
}
ACPI_DRV_ERR) {
return (ACPI_DRV_ERR);
}
return (ACPI_DRV_OK);
}
static int
{
/* BST is only available when battery plugged */
/* Update internal BST cache */
return (ACPI_DRV_ERR);
}
ACPI_DRV_ERR) {
return (ACPI_DRV_ERR);
}
}
return (ACPI_DRV_OK);
}
/*
* Return value:
* 1 -- device On-line
* 0 -- device Off-line
* -1 -- Unknown, some error ocurred.
*/
static int
{
return (-1);
}
/* Update the device state */
(void) acpi_drv_get_psr((struct acpi_drv_ac_state *)
devp);
(void) acpi_drv_get_sta((struct acpi_drv_cbat_state *)
devp);
}
}
}
/*
* 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;
p->present = -1;
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_psr_type = p->type;
} else {
}
}
/*
* 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
{
/* Update internal state */
if (bwp->bw_enabled) {
return (EINVAL);
}
low);
} else {
}
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
{
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;
}
bp++) {
/* Escape the empty bays */
if (acpi_drv_cbat_present(bp) <= 0) {
continue;
}
if (bif_changed != 0 &&
if (acpi_drv_syn_last_cap == 0xffffffff) {
}
"BIF value "
"invalid, warn_cap=0x%x "
bif->bif_low_cap);
continue;
}
if (acpi_drv_syn_oem_warn_cap == 0xffffffff) {
}
if (acpi_drv_syn_oem_low_cap == 0xffffffff) {
}
/*
* Use the highest level as the synthesis
* level.
*/
if (bif->bif_warn_cap >
}
}
#ifdef DEBUG
else if (bif_changed) {
"BIF not ready");
}
#endif
/*
* Batteries that are rechargeable and are in
* the discharging state are required to return
* a valid Battery Present Rate value.
*/
"BST value invalid, "
"rate=0x%x cap=0x%x",
continue;
}
if (acpi_drv_syn_rem_cap == 0xffffffff) {
acpi_drv_syn_rem_cap = 0;
}
/* Check for overflow */
bst->bst_rem_cap);
}
#ifdef DEBUG
else {
"BST not ready");
}
#endif
}
}
}
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
{
int bif_changed;
char *ev;
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:
/*
* but 0x80 may come first. In case that situation, we have
* to update battery present state here too to update bst
* correctly.
*/
/* Omit events sent by empty battery slot */
break;
}
break;
}
/*
* 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 (acpi_drv_psr_devp == devp) {
}
break;
}
}
/*
* 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
/*
* BST_FLAG_CRITICAL may set even with AC,
* to avoid erroneous shutdown.
*/
if (acpi_drv_psr_devp == devp &&
"Battery in critical state");
}
} else
#endif
if (acpi_drv_warn_enabled &&
/*
* 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).
*/
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 >
eval);
}
}
break;
/* BIF has changed */
case 0x81:
/*
* because they may corresponding to different batterys.
*/
(void) acpi_drv_update_present(devp);
break;
}
}
break;
case 0x82:
default:
break;
}
}
static int
acpi_drv_update_lid(struct acpi_drv_dev *p)
{
return (ACPI_DRV_OK);
}
return (ACPI_DRV_ERR);
}
/*ARGSUSED*/
static void
{
int old_present;
char *ev;
int eval;
if (val != 0x80) {
return;
}
/*
* Note: if unplug and then quickly plug back, two ADD
* events will be generated.
*/
/* Eliminate redundant events */
/* Keep tracking the current power source device */
if (eval == 1) {
ev = ESC_PWRCTL_ADD;
} else {
/* If AC was supplying the power, it's not now */
if (acpi_drv_psr_devp == devp) {
}
}
}
}
static void
{
struct acpi_drv_lid_state *p = ctx;
if (val == 0x80) {
ESC_PWRCTL_ADD : ESC_PWRCTL_REMOVE, 0);
}
}
}
static int
acpi_drv_obj_init(struct acpi_drv_dev *p)
{
p->valid = 0;
/* Info size is variable depending on existance of _CID */
if (ACPI_FAILURE(ret)) {
return (ACPI_DRV_ERR);
}
"AcpiGetObjectInfo(): _HID not available");
} else {
}
/*
* This object is optional, but is required when the device
* has no other way to report a persistent unique device ID.
*/
"AcpiGetObjectInfo(): _UID not available");
/* Use 0 as the default _UID */
} else {
}
p->valid = 1;
struct acpi_drv_cbat_state *bp =
(struct acpi_drv_cbat_state *)p;
p->type = ACPI_DRV_TYPE_CBAT;
/* 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 */
acpi_drv_set_psr(p);
}
}
p->type = ACPI_DRV_TYPE_AC;
/* Update device present state */
(void) acpi_drv_update_present(p);
if (p->present) {
/* Init the current power source */
acpi_drv_set_psr(p);
}
p->type = ACPI_DRV_TYPE_LID;
p->index = 0;
(void) acpi_drv_update_lid(p);
if (p->type == ACPI_DRV_TYPE_DISPLAY) {
p->index = 0;
/* Enable display control by OS */
} else {
p->valid = 0;
return (ACPI_DRV_ERR);
}
p->type = ACPI_DRV_TYPE_OUTPUT;
}
} else {
p->valid = 0;
}
/* Register ACPI battery related events */
if (ntf_handler != NULL) {
ACPI_ALL_NOTIFY, ntf_handler, p))) {
"Notify handler for %s.%s install failed",
return (ACPI_DRV_ERR);
}
}
return (ACPI_DRV_OK);
}
/*ARGSUSED*/
static ACPI_STATUS
void **ReturnValue)
{
struct acpi_drv_dev *devp;
if (*type == ACPI_DRV_TYPE_CBAT) {
struct acpi_drv_cbat_state *bp;
if (nbat == ACPI_DRV_MAX_BAT_NUM) {
"Need to support more batteries: "
"BATTERY_MAX = %d", ACPI_DRV_MAX_BAT_NUM);
return (AE_LIMIT);
}
} else if (*type == ACPI_DRV_TYPE_AC) {
struct acpi_drv_ac_state *ap;
if (nac == ACPI_DRV_MAX_AC_NUM) {
"AC_MAX = %d", ACPI_DRV_MAX_AC_NUM);
return (AE_LIMIT);
}
} else if (*type == ACPI_DRV_TYPE_LID) {
struct acpi_drv_lid_state *lp;
nlid++;
} else if (*type == ACPI_DRV_TYPE_OUTPUT) {
int adr = 0;
char str[256];
struct acpi_drv_display_state *dp;
struct acpi_drv_output_state *op;
/*
* Reduce the search by checking for support of _ADR
* method.
*/
return (AE_OK);
}
/*
* Find the display device.
*/
ACPI_FULL_PATHNAME, &buf2))) {
"_DOD Supported Pathname=%s\n",
}
(void) acpi_drv_obj_init(devp);
/*
* Find the output devices.
*/
(sizeof (struct acpi_drv_output_state),
KM_SLEEP);
} else {
}
noutput++;
(void) acpi_drv_obj_init(devp);
}
}
return (AE_OK);
} else {
"Unknown device");
return (AE_ERROR);
}
/* Try to get as many working objs as possible */
(void) acpi_drv_obj_init(devp);
return (AE_OK);
}
static int
{
int status = ACPI_DRV_ERR;
/* Check to see if ACPI CA services are available */
if (AcpiSubsystemStatus() != AE_OK) {
return (status);
}
/* Init Control Method Batterys */
}
/* Init AC */
}
/* Init LID */
}
/* Init Output Devices */
}
return (status);
}
static void
acpi_drv_acpi_fini(void)
{
int i;
struct acpi_drv_cbat_state *bp;
struct acpi_drv_output_state *op;
bp++) {
}
}
for (i = 0; i < nac; i++) {
}
}
}
}
}
/*ARGSUSED*/
static int
{
if (flag == KSTAT_WRITE) {
return (EACCES);
}
if (acpi_drv_psr_type == ACPI_DRV_TYPE_UNKNOWN) {
return (EIO);
}
return (0);
}
/*ARGSUSED*/
static int
{
if (flag == KSTAT_WRITE) {
int ret = 0;
return (ret);
} else {
return (0);
}
}
static int
{
struct acpi_drv_cbat_state *bp;
if (flag == KSTAT_WRITE) {
return (EACCES);
}
if (acpi_drv_cbat_present(bp) <= 0) {
return (ENXIO);
}
return (ENXIO);
}
kp = &acpi_drv_bif_kstat;
/* Update BIF */
return (0);
}
static int
{
struct acpi_drv_cbat_state *bp;
if (flag == KSTAT_WRITE) {
return (EACCES);
}
if (acpi_drv_cbat_present(bp) <= 0) {
return (ENXIO);
}
return (ENXIO);
}
kp = &acpi_drv_bst_kstat;
/* Update BST */
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_KSTAT_NAME, "misc",
sizeof (acpi_drv_power_kstat) / sizeof (kstat_named_t),
if (acpi_drv_power_ksp == NULL) {
"kstat_create(%s) fail", ACPI_DRV_POWER_KSTAT_NAME);
return (ACPI_DRV_ERR);
}
/*
* Allocate, initialize and install battery_capacity_warning kstat.
*/
ACPI_DRV_BTWARN_KSTAT_NAME, "misc",
sizeof (acpi_drv_warn_kstat) / sizeof (kstat_named_t),
if (acpi_drv_warn_ksp == NULL) {
"kstat_create(%s) fail", ACPI_DRV_BTWARN_KSTAT_NAME);
return (ACPI_DRV_ERR);
}
/*
* Allocate, initialize and install BIF and BST kstat
* for each battery.
*/
bp++) {
/* BIF kstat */
sizeof (acpi_drv_bif_kstat) /
sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
"kstat_create(%s) fail", name);
return (ACPI_DRV_ERR);
}
name);
/* BST kstat */
sizeof (acpi_drv_bst_kstat) /
sizeof (kstat_named_t),
"kstat_create(%s) fail", name);
return (ACPI_DRV_ERR);
}
name);
}
}
return (ACPI_DRV_OK);
}
static void
{
struct acpi_drv_cbat_state *bp;
if (acpi_drv_power_ksp != NULL) {
}
if (acpi_drv_warn_ksp != NULL) {
}
bp++) {
}
}
}
}
}
static int
{
}
static int
{
struct acpi_drv_output_state *op;
int adr;
char str[256];
return (ACPI_DRV_ERR);
}
}
/*
* op->nlev will be needed to free op->levels.
*/
KM_SLEEP);
/*
* Get all the supported brightness levels.
*/
for (i = 0; i < nlev; i++) {
if (o->Type != ACPI_TYPE_INTEGER) {
continue;
}
}
/*
* Sort the brightness levels.
*/
for (j = 0; j < nlev; j++) {
for (k = 0; k < nlev - 1; k++) {
}
}
}
/*
* The first two levels could be duplicated, so remove
* any duplicates.
*/
for (l = 0; l < nlev - 1; l++) {
}
nlev--;
}
}
(void) acpi_drv_output_get_level(op);
"create minor "
} else {
}
return (ACPI_DRV_OK);
}
/*ARGSUSED*/
static int
int *rval)
{
struct acpi_drv_output_state *op;
int res = 0;
return (ENXIO);
}
switch (cmd) {
case ACPI_DRV_IOC_INFO: {
struct acpi_drv_output_info inf;
}
break;
}
case ACPI_DRV_IOC_LEVELS:
}
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;
for (i = 0; i < op->num_levels; i++) {
status.cur_level_index = i;
"cur_level_index %d\n", i);
break;
}
}
}
break;
}
case ACPI_DRV_IOC_SET_BRIGHTNESS: {
int level;
break;
}
break;
}
"ACPI_DRV_IOC_SET_BRIGHTNESS level=%d\n", level);
}
break;
}
default:
break;
}
return (res);
}
static struct acpi_drv_output_state *
acpi_drv_idx2output(int idx)
{
}
return (op);
}
/*
* Get the current brightness level and index.
*/
static int
{
int i;
return (ACPI_DRV_ERR);
}
for (i = 0; i < op->num_levels; i++) {
op->cur_level_index = i;
"acpi_drv_output_get_level(): "
"cur_level = %d, cur_level_index = %d\n",
break;
}
}
return (ACPI_DRV_OK);
}
static int
{
AE_OK) {
return (ACPI_DRV_ERR);
}
return (ACPI_DRV_OK);
}
static void
{
switch (val) {
case 0x86: /* increase brightness */
break;
}
}
break;
case 0x87: /* decrease brightness */
if (op->cur_level_index > 0) {
break;
}
}
break;
default:
break;
}
}
/*
* Set the display control modes of display switching and brightness
* from BIOS or OSPM.
*/
static void
{
state);
}
}