acpi_video.c revision 2d6b5ea734bb47d251c82670646fde46af15fd69
/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Solaris x86 Generic ACPI Video Extensions Hotkey driver
*/
#include <sys/hotkey_drv.h>
/*
* Vendor specific hotkey support list
* 1. Toshiba: acpi_toshiba
*/
struct vendor_hotkey_drv vendor_hotkey_drv_list[] = {
/* vendor, module name, enable? */
/* Terminator */
};
enum vga_output_type {
};
struct acpi_video_output {
struct acpi_drv_dev dev;
enum vga_output_type type;
struct acpi_video_output *next;
};
struct acpi_video_brightness {
struct acpi_drv_dev dev;
int *levels;
int cur_level;
struct acpi_video_brightness *next;
};
struct acpi_video_switch {
struct acpi_drv_dev dev;
struct acpi_video_switch *next;
};
/* ACPI video extension hotkey for video switch and brightness control */
static struct acpi_video {
struct acpi_video_output *vid_outputs;
struct acpi_video_brightness *vid_brightness;
struct acpi_video_switch *vid_switch;
int hotkey_drv_debug = 0;
#define ACPI_METHOD_DOS "_DOS"
#define ACPI_METHOD_DOD "_DOD"
#define ACPI_DEVNAME_CRT "CRT"
#define ACPI_DEVNAME_LCD "LCD"
#define ACPI_DEVNAME_TV "TV"
#define ACPI_METHOD_ADR "_ADR"
#define ACPI_METHOD_DDC "_DDC"
#define ACPI_METHOD_DCS "_DCS"
#define ACPI_METHOD_DGS "_DGS"
#define ACPI_METHOD_DSS "_DSS"
#define VIDEO_NOTIFY_SWITCH 0x80
#define VIDEO_NOTIFY_SWITCH_STATUS 0x81
#define VIDEO_NOTIFY_SWITCH_CYCLE 0x82
#define VIDEO_NOTIFY_SWITCH_NEXT 0x83
#define VIDEO_NOTIFY_SWITCH_PREV 0x84
#define VIDEO_NOTIFY_BRIGHTNESS_CYCLE 0x85
#define VIDEO_NOTIFY_BRIGHTNESS_INC 0x86
#define VIDEO_NOTIFY_BRIGHTNESS_DEC 0x87
#define VIDEO_NOTIFY_BRIGHTNESS_ZERO 0x88
/* Output device status */
#define ACPI_DRV_DCS_CONNECTOR_EXIST (1 << 0)
/* _DOS default value is 1 */
/* _DOS bit 1:0 */
#define VIDEO_POLICY_SWITCH_OS 0x0
#define VIDEO_POLICY_SWITCH_BIOS 0x1
#define VIDEO_POLICY_SWITCH_LOCKED 0x2
#define VIDEO_POLICY_SWITCH_OS_EVENT 0x3
/* _DOS bit 2 */
#define VIDEO_POLICY_BRIGHTNESS_OS 0x4
#define VIDEO_POLICY_BRIGHTNESS_BIOS 0x0
/* Set _DOS for video control policy */
static void
{
struct acpi_video_switch *vidsp;
if (ACPI_FAILURE(status))
}
}
/*
* Get the current brightness level and index.
*/
static int
{
int i;
!= AE_OK) {
return (ACPI_DRV_ERR);
}
vidbp->cur_level_index = i;
if (hotkey_drv_debug & HOTKEY_DBG_NOTICE) {
" 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);
}
void
{
int err;
if (err != DDI_SUCCESS) {
"!failed to log hotkey sysevent, err code %x\n", err);
}
}
/*ARGSUSED*/
static void
{
if (hotkey_drv_debug & HOTKEY_DBG_NOTICE) {
notify);
}
switch (notify) {
case VIDEO_NOTIFY_SWITCH:
case VIDEO_NOTIFY_SWITCH_NEXT:
case VIDEO_NOTIFY_SWITCH_PREV:
break;
break;
default:
if (hotkey_drv_debug) {
"!acpi_video_switch_notify: unknown event 0x%x.\n",
notify);
}
}
}
/*ARGSUSED*/
static void
{
if (hotkey_drv_debug & HOTKEY_DBG_NOTICE) {
"!acpi_video_brightness_notify: got event 0x%x.\n",
notify);
}
switch (notify) {
break;
}
}
break;
if (vidbp->cur_level_index > 0) {
break;
}
}
0);
break;
break;
}
0);
break;
default:
if (hotkey_drv_debug) {
"unknown event 0x%x.\n", notify);
}
}
}
static int
{
struct acpi_video_switch *vidsp;
struct acpi_video_brightness *vidbp;
int i;
/* bind video switch notify */
if (ACPI_FAILURE(status)) {
"!vids handler install failed = %d, vids = %p.",
}
}
/* bind brightness control notify */
if (ACPI_FAILURE(status)) {
"!brightness handler install failed = %x, "
}
}
return (ACPI_DRV_OK);
}
static int
{
struct acpi_video_switch *vidsp;
struct acpi_video_brightness *vidbp;
int i;
/* unbind video switch notify */
}
/* unbind brightness control notify */
}
return (ACPI_DRV_OK);
}
static int
{
struct acpi_video_switch *vidsp;
struct acpi_video_switch *vidsp_next;
struct acpi_video_brightness *vidbp;
struct acpi_video_brightness *vidbp_next;
struct acpi_video_output *vidop;
struct acpi_video_output *vidop_next;
/* free video switch objects */
vidsp = vidsp_next;
}
/* free video brightness control objects */
vidbp = vidbp_next;
}
/* free video output objects */
vidop = vidop_next;
}
return (ACPI_DRV_OK);
}
static int
{
(void) acpi_video_notify_unintall(vidp);
return (acpi_video_free(vidp));
}
static int
{
int adr;
struct acpi_video_brightness *vidbp;
struct acpi_video_output *vidop;
return (ACPI_DRV_ERR);
/* Allocate object */
KM_SLEEP);
/*
* op->nlev will be needed to free op->levels.
*/
/*
* Get all the supported brightness levels.
*/
for (i = 0; i < nlev; i++) {
if (hotkey_drv_debug & HOTKEY_DBG_NOTICE) {
}
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_video_brightness_get(vidbp);
vidp->total_brightness++;
}
vidp->total_outputs++;
return (ACPI_DRV_OK);
}
/*ARGSUSED*/
static ACPI_STATUS
void **rv)
{
struct acpi_video *vidp;
struct acpi_video_switch *vidsp;
return (AE_OK);
return (AE_OK);
vidp->total_switch++;
/*
* Enumerate the output devices.
*/
}
if (hotkey_drv_debug & HOTKEY_DBG_NOTICE) {
"!acpi video switch hdl = 0x%p, path = %s.",
}
}
}
return (AE_OK);
}
int
{
struct acpi_video *vidp;
struct acpi_video_brightness *vidbp;
return (ACPI_DRV_ERR);
}
}
}
return (ACPI_DRV_OK);
}
int
{
struct acpi_video *vidp;
struct acpi_video_brightness *vidbp;
if (vidbp->cur_level_index > 0) {
return (ACPI_DRV_ERR);
}
}
}
return (ACPI_DRV_OK);
}
/*ARGSUSED*/
int
int *rval)
{
struct acpi_video *vidp = p;
struct acpi_video_brightness *vidbp;
int res = 0;
return (ENXIO);
return (ENXIO);
if (hotkey_drv_debug & HOTKEY_DBG_NOTICE) {
}
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;
status.cur_level_index = i;
if (hotkey_drv_debug & HOTKEY_DBG_NOTICE) {
"cur_level_index %d\n", i);
}
break;
}
}
}
break;
}
case ACPI_DRV_IOC_SET_BRIGHTNESS: {
int level;
break;
}
break;
}
if (hotkey_drv_debug & HOTKEY_DBG_NOTICE) {
"!acpi_video_ioctl: set BRIGHTNESS level=%d\n",
level);
}
}
break;
}
default:
break;
}
return (res);
}
/*ARGSUSED*/
int
int *rval)
{
switch (htkp->hotkey_method) {
case HOTKEY_METHOD_ACPI_VIDEO:
case HOTKEY_METHOD_MISC:
case HOTKEY_METHOD_VENDOR:
case HOTKEY_METHOD_NONE:
default:
return (ENXIO);
}
}
static int
{
struct acpi_video *vidp;
/* Find ACPI Video device handle */
return (ACPI_DRV_ERR);
}
(void) acpi_video_fini(vidp);
return (ACPI_DRV_ERR);
}
}
return (ACPI_DRV_OK);
}
int
{
int i;
int modid;
/* Try to find vendor specific method */
if (!vendor_hotkey_drv_list[i].enable)
continue;
== -1) {
continue;
}
if (hotkey_drv_debug & HOTKEY_DBG_NOTICE) {
}
}
/* Check availability of ACPI Video Extension method */
htkp->check_acpi_video) {
} else
goto fail;
}
}
return (ACPI_DRV_OK);
fail:
return (ACPI_DRV_ERR);
}
int
{
}
return (ACPI_DRV_OK);
}