Hello Everybody,
I installed OpenBSD 4.9 current in my old Toshiba M30. Although,
there was not LCD brightness control, so I started to do something
about
it, taking into account the Toshiba acpi support of FreeBSD.
http://fxr.watson.org/fxr/source/dev/acpi_support/acpi_toshiba.c
Successfully, I can manage the LCD brightness level using wsconsctl(8).
wsconsctl display.brightness=100. ;) works nicely by command
line as well by setting the brightness level in /etc/wsconsctl.conf
file.
I attached the required patch files for testing. I hope can be
useful for other guys using toshiba laptops as I added the
Libretto and Dynabook models.
Thanks to Paul for coaching me to provide a decent patch :).
Greatings,
Javier.
/*-
* Copyright (c) 2003 Hiroyuki Aizu <[email protected]>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
*/
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/proc.h>
#include <dev/acpi/acpireg.h>
#include <dev/acpi/acpivar.h>
#include <dev/acpi/acpidev.h>
#include <dev/acpi/amltypes.h>
#include <dev/acpi/dsdt.h>
#include <machine/apmvar.h>
#include <dev/wscons/wsconsio.h>
/*
* Toshiba HCI interface definitions
*
* HCI is Toshiba's "Hardware Control Interface" which is supposed to
* be uniform across all their models. Ideally we would just call
* dedicated ACPI methods instead of using this primitive interface.
* However, the ACPI methods seem to be incomplete in some areas (for
* example they allow setting, but not reading, the LCD brightness
* value), so this is still useful.
*/
#define METHOD_HCI "GHCI"
#define METHOD_HCI_ENABLE "ENAB"
/* Operations */
#define HCI_SET 0xFF00
#define HCI_GET 0xFE00
/* Functions */
#define HCI_REG_SYSTEM_EVENT 0x0016
#define HCI_REG_VIDEO_OUTPUT 0x001C
#define HCI_REG_LCD_BRIGHTNESS 0x002A
/* Field definitions */
#define HCI_LCD_BRIGHTNESS_BITS 3
#define HCI_LCD_BRIGHTNESS_SHIFT (16 - HCI_LCD_BRIGHTNESS_BITS)
#define HCI_LCD_BRIGHTNESS_MAX ((1 << HCI_LCD_BRIGHTNESS_BITS) - 1)
#define HCI_LCD_BRIGHTNESS_MIN 0
#define HCI_VIDEO_OUTPUT_FLAG 0x0100
#define HCI_VIDEO_OUTPUT_CYCLE_MIN 0
#define HCI_VIDEO_OUTPUT_CYCLE_MAX 7
/* HCI register definitions */
#define HCI_WORDS 6 /* Number of register */
#define HCI_REG_AX 0 /* Operation, then return value */
#define HCI_REG_BX 1 /* Function */
#define HCI_REG_CX 2 /* Argument (in or out) */
/* Return codes */
#define HCI_FAILURE -1
#define HCI_SUCCESS 0
/* Toshiba fn_keys events */
#define FN_KEY_VIDEO_OUTPUT 0x01BF
#define FN_KEY_BRIGHTNESS_DOWN 0x01C0
#define FN_KEY_BRIGHTNESS_UP 0x01C1
struct acpitoshiba_softc {
struct device sc_dev;
struct acpi_softc *sc_acpi;
struct aml_node *sc_devnode;
};
int toshiba_enable_events(struct acpitoshiba_softc *);
int toshiba_read_events(struct acpitoshiba_softc *);
int toshiba_match(struct device *, void *, void *);
void toshiba_attach(struct device *, struct device *, void *);
int toshiba_hotkey(struct aml_node *, int, void *);
int toshiba_get_brightness(struct acpitoshiba_softc *, u_int32_t *);
int toshiba_set_brightness(struct acpitoshiba_softc *, u_int32_t *);
int toshiba_get_video_output(struct acpitoshiba_softc *, u_int32_t *);
int toshiba_set_video_output(struct acpitoshiba_softc *, u_int32_t *);
int toshiba_find_brightness(struct acpitoshiba_softc *, int *);
int toshiba_fn_key_brightness_up(struct acpitoshiba_softc *);
int toshiba_fn_key_brightness_down(struct acpitoshiba_softc *);
int toshiba_fn_key_video_output(struct acpitoshiba_softc *);
/* wconsole hook functions */
int acpitoshiba_get_param(struct wsdisplay_param *);
int acpitoshiba_set_param(struct wsdisplay_param *);
extern int (*ws_get_param)(struct wsdisplay_param *);
extern int (*ws_set_param)(struct wsdisplay_param *);
int get_param_brightness(struct wsdisplay_param *);
int set_param_brightness(struct wsdisplay_param *);
struct cfattach acpitoshiba_ca = {
sizeof(struct acpitoshiba_softc), toshiba_match, toshiba_attach
};
struct cfdriver acpitoshiba_cd = {
NULL, "acpitoshiba", DV_DULL
};
int
get_param_brightness(struct wsdisplay_param *dp)
{
struct acpitoshiba_softc *sc = NULL;
int i, ret;
for (i = 0; i < acpitoshiba_cd.cd_ndevs; i++) {
if (acpitoshiba_cd.cd_devs[i] == NULL)
continue;
sc = (struct acpitoshiba_softc *)acpitoshiba_cd.cd_devs[i];
}
if (sc != NULL) {
rw_enter_write(&sc->sc_acpi->sc_lck);
/* default settings */
dp->min = HCI_LCD_BRIGHTNESS_MIN;
dp->max = HCI_LCD_BRIGHTNESS_MAX;
ret = toshiba_get_brightness(sc, &dp->curval);
rw_exit_write(&sc->sc_acpi->sc_lck);
if ((dp->curval != -1) && (ret != HCI_FAILURE) )
return (0);
}
return (1);
}
int
acpitoshiba_get_param(struct wsdisplay_param *dp)
{
int ret;
switch (dp->param) {
case WSDISPLAYIO_PARAM_BRIGHTNESS:
ret = get_param_brightness(dp);
return (ret);
default:
return (1);
}
}
int
set_param_brightness(struct wsdisplay_param *dp)
{
struct acpitoshiba_softc *sc = NULL;
int i, ret;
for (i = 0; i < acpitoshiba_cd.cd_ndevs; i++) {
if (acpitoshiba_cd.cd_devs[i] == NULL)
continue;
sc = (struct acpitoshiba_softc *)acpitoshiba_cd.cd_devs[i];
}
if (sc != NULL) {
rw_enter_write(&sc->sc_acpi->sc_lck);
ret = toshiba_find_brightness(sc, &dp->curval);
rw_exit_write(&sc->sc_acpi->sc_lck);
if ((dp->curval != -1) && ( ret != HCI_FAILURE))
return (0);
}
return (1);
}
int
acpitoshiba_set_param(struct wsdisplay_param *dp)
{
int ret;
switch (dp->param) {
case WSDISPLAYIO_PARAM_BRIGHTNESS:
ret = set_param_brightness(dp);
return (ret);
default:
return (1);
}
}
int
toshiba_find_brightness(struct acpitoshiba_softc *sc, int *new_blevel)
{
int ret, current_blevel;
ret = toshiba_get_brightness(sc, ¤t_blevel);
if ( ret != HCI_SUCCESS)
return (1);
if ( current_blevel != *new_blevel) {
if ( *new_blevel >= HCI_LCD_BRIGHTNESS_MAX)
*new_blevel = current_blevel = HCI_LCD_BRIGHTNESS_MAX;
else if (*new_blevel <= HCI_LCD_BRIGHTNESS_MIN)
*new_blevel = current_blevel = HCI_LCD_BRIGHTNESS_MIN;
else
current_blevel = *new_blevel;
ret = toshiba_set_brightness(sc, ¤t_blevel);
if ( ret != HCI_SUCCESS)
return (1);
}
return (0);
}
int
toshiba_match(struct device *parent, void *match, void *aux)
{
struct acpi_attach_args *aa = aux;
struct cfdata *cf = match;
if ( aa->aaa_name == NULL ||
strcmp(aa->aaa_name, cf->cf_driver->cd_name) != 0 ||
aa->aaa_table != NULL)
return (0);
return (1);
}
int
toshiba_enable_events(struct acpitoshiba_softc *sc)
{
if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI_ENABLE,
0, NULL, NULL)) {
printf("%s: couldn't toggle METHOD_HCI_ENABLE\n", DEVNAME(sc));
return (HCI_FAILURE);
}
return (HCI_SUCCESS);
}
int
toshiba_read_events(struct acpitoshiba_softc *sc)
{
struct aml_value args[HCI_WORDS];
struct aml_value res;
int i, val;
bzero(args, sizeof(args));
bzero(&res, sizeof(res));
for (i = 0; i < HCI_WORDS; ++i)
args[i].type = AML_OBJTYPE_INTEGER;
args[HCI_REG_AX].v_integer = HCI_GET;
args[HCI_REG_BX].v_integer = HCI_REG_SYSTEM_EVENT;
if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
i, args, &res)) {
printf("%s: couldn't toggle METHOD_HCI\n", DEVNAME(sc));
return (HCI_FAILURE);
}
/*
* We receive a package type so we need to get the event
* value from the HCI_REG_CX.
*/
val = aml_val2int(res.v_package[HCI_REG_CX]);
aml_freevalue(&res);
return (val);
}
void
toshiba_attach(struct device *parent, struct device *self, void *aux)
{
struct acpitoshiba_softc *sc = (struct acpitoshiba_softc *)self;
struct acpi_attach_args *aa = aux;
int ret;
sc->sc_acpi = (struct acpi_softc *)parent;
sc->sc_devnode = aa->aaa_node;
printf("\n");
/* enable events and hotkeys */
ret = toshiba_enable_events(sc);
if ( ret != HCI_FAILURE) {
/* Run toshiba_hotkey on button presses */
aml_register_notify(sc->sc_devnode, aa->aaa_dev,
toshiba_hotkey, sc, ACPIDEV_NOPOLL);
/* wsconsctl purpose */
ws_get_param = acpitoshiba_get_param;
ws_set_param = acpitoshiba_set_param;
}
}
int
toshiba_fn_key_brightness_up(struct acpitoshiba_softc *sc)
{
u_int32_t brightness_level;
int ret;
ret = toshiba_get_brightness(sc, &brightness_level);
if ( ret != HCI_FAILURE) {
if (brightness_level++ == HCI_LCD_BRIGHTNESS_MAX)
brightness_level = HCI_LCD_BRIGHTNESS_MAX;
else
ret = toshiba_set_brightness(sc, &brightness_level);
}
return (ret);
}
int
toshiba_fn_key_brightness_down(struct acpitoshiba_softc *sc)
{
u_int32_t brightness_level;
int ret;
ret = toshiba_get_brightness(sc, &brightness_level);
if ( ret != HCI_FAILURE) {
if (brightness_level-- == HCI_LCD_BRIGHTNESS_MIN)
brightness_level = HCI_LCD_BRIGHTNESS_MIN;
else
ret = toshiba_set_brightness(sc, &brightness_level);
}
return (ret);
}
int
toshiba_fn_key_video_output(struct acpitoshiba_softc *sc)
{
u_int32_t video_output;
int ret;
ret = toshiba_get_video_output(sc, &video_output);
if ( ret != HCI_FAILURE) {
video_output = (video_output + 1) % HCI_VIDEO_OUTPUT_CYCLE_MAX;
ret = toshiba_set_video_output(sc, &video_output);
}
return (ret);
}
int
toshiba_hotkey(struct aml_node *node, int notify, void *arg)
{
struct acpitoshiba_softc *sc = arg;
int event, ret;
event = toshiba_read_events(sc);
if (!event)
return (0);
switch (event) {
case FN_KEY_BRIGHTNESS_UP:
/* Increase brightness */
ret = toshiba_fn_key_brightness_up(sc);
break;
case FN_KEY_BRIGHTNESS_DOWN:
/* Decrease brightness */
ret = toshiba_fn_key_brightness_down(sc);
break;
case FN_KEY_VIDEO_OUTPUT:
/* Cycle through video outputs. */
ret = toshiba_fn_key_video_output(sc);
break;
default:
break;
}
if ( ret != HCI_SUCCESS)
return (1);
return (0);
}
int
toshiba_set_brightness(struct acpitoshiba_softc *sc, u_int32_t *brightness)
{
struct aml_value args[HCI_WORDS];
int i;
bzero(args, sizeof(args));
for (i = 0; i < HCI_WORDS; ++i)
args[i].type = AML_OBJTYPE_INTEGER;
if ((*brightness < HCI_LCD_BRIGHTNESS_MIN) ||
(*brightness > HCI_LCD_BRIGHTNESS_MAX))
return (HCI_FAILURE);
*brightness <<= HCI_LCD_BRIGHTNESS_SHIFT;
args[HCI_REG_AX].v_integer = HCI_SET;
args[HCI_REG_BX].v_integer = HCI_REG_LCD_BRIGHTNESS;
args[HCI_REG_CX].v_integer = *brightness;
if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
i, args, NULL)) {
printf("%s: set brightness failed\n", DEVNAME(sc));
return (HCI_FAILURE);
}
return (HCI_SUCCESS);
}
int
toshiba_get_brightness(struct acpitoshiba_softc *sc, u_int32_t *brightness)
{
struct aml_value args[HCI_WORDS];
struct aml_value res;
int i;
bzero(args, sizeof(args));
bzero(&res, sizeof(res));
for (i = 0; i < HCI_WORDS; ++i)
args[i].type = AML_OBJTYPE_INTEGER;
args[HCI_REG_AX].v_integer = HCI_GET;
args[HCI_REG_BX].v_integer = HCI_REG_LCD_BRIGHTNESS;
if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
i, args, &res)) {
printf("%s: get brightness failed\n", DEVNAME(sc));
return (HCI_FAILURE);
}
/*
* We receive a package type so we need to get the event
* value from the HCI_REG_CX.
*/
*brightness = aml_val2int(res.v_package[HCI_REG_CX]);
*brightness >>= HCI_LCD_BRIGHTNESS_SHIFT;
aml_freevalue(&res);
return (HCI_SUCCESS);
}
int
toshiba_get_video_output(struct acpitoshiba_softc *sc, u_int32_t *video_output)
{
struct aml_value res, args[HCI_WORDS];
int i;
bzero(args, sizeof(args));
bzero(&res, sizeof(res));
for (i = 0; i < HCI_WORDS; ++i)
args[i].type = AML_OBJTYPE_INTEGER;
args[HCI_REG_AX].v_integer = HCI_GET;
args[HCI_REG_BX].v_integer = HCI_REG_VIDEO_OUTPUT;
if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
i, args, &res)) {
printf("%s: get video output failed\n", DEVNAME(sc));
return (HCI_FAILURE);
}
/*
* We receive a package type so we need to get the event
* value from the HCI_REG_CX.
*/
*video_output = aml_val2int(res.v_package[HCI_REG_CX]);
*video_output &= 0xff;
aml_freevalue(&res);
return (HCI_SUCCESS);
}
int
toshiba_set_video_output(struct acpitoshiba_softc *sc, u_int32_t *video_output)
{
struct aml_value args[HCI_WORDS];
int i;
bzero(args, sizeof(args));
if ((*video_output < HCI_VIDEO_OUTPUT_CYCLE_MIN) ||
(*video_output > HCI_VIDEO_OUTPUT_CYCLE_MAX))
return (HCI_FAILURE);
*video_output |= HCI_VIDEO_OUTPUT_FLAG;
for (i = 0; i < HCI_WORDS; ++i)
args[i].type = AML_OBJTYPE_INTEGER;
args[HCI_REG_AX].v_integer = HCI_SET;
args[HCI_REG_BX].v_integer = HCI_REG_VIDEO_OUTPUT;
args[HCI_REG_CX].v_integer = *video_output;
if (aml_evalname(sc->sc_acpi, sc->sc_devnode, METHOD_HCI,
i, args, NULL)) {
printf("%s: set video output failed\n", DEVNAME(sc));
return (HCI_FAILURE);
}
return (HCI_SUCCESS);
}
? toshiba_acpi.diff
? sys/dev/acpi/acpitoshiba.c
Index: sys/arch/amd64/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/amd64/conf/GENERIC,v
retrieving revision 1.319
diff -u -p -r1.319 GENERIC
--- sys/arch/amd64/conf/GENERIC 30 May 2011 22:03:47 -0000 1.319
+++ sys/arch/amd64/conf/GENERIC 13 Jun 2011 16:47:30 -0000
@@ -52,6 +52,7 @@ acpimcfg* at acpi?
acpiasus* at acpi?
acpisony* at acpi?
acpithinkpad* at acpi?
+acpitoshiba* at acpi?
acpivideo* at acpi?
acpivout* at acpivideo?
acpipwrres* at acpi?
Index: sys/arch/i386/conf/GENERIC
===================================================================
RCS file: /cvs/src/sys/arch/i386/conf/GENERIC,v
retrieving revision 1.716
diff -u -p -r1.716 GENERIC
--- sys/arch/i386/conf/GENERIC 30 May 2011 22:03:47 -0000 1.716
+++ sys/arch/i386/conf/GENERIC 13 Jun 2011 16:47:31 -0000
@@ -62,6 +62,7 @@ acpitz* at acpi?
acpiasus* at acpi?
acpisony* at acpi?
acpithinkpad* at acpi?
+acpitoshiba* at acpi?
acpivideo* at acpi?
acpivout* at acpivideo?
acpipwrres* at acpi?
Index: sys/dev/acpi/acpi.c
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpi.c,v
retrieving revision 1.224
diff -u -p -r1.224 acpi.c
--- sys/dev/acpi/acpi.c 27 Apr 2011 20:55:42 -0000 1.224
+++ sys/dev/acpi/acpi.c 13 Jun 2011 16:47:33 -0000
@@ -93,6 +93,7 @@ void acpi_pbtn_task(void *, int);
#ifndef SMALL_KERNEL
int acpi_thinkpad_enabled;
+int acpi_toshiba_enabled;
int acpi_saved_spl;
int acpi_enabled;
@@ -781,8 +782,8 @@ acpi_attach(struct device *parent, struc
/* check if we're running on a sony */
aml_find_node(&aml_root, "GBRT", acpi_foundsony, sc);
- /* attach video only if this is not a stinkpad */
- if (!acpi_thinkpad_enabled)
+ /* attach video only if this is not a stinkpad or toshiba */
+ if (!acpi_thinkpad_enabled || !acpi_toshiba_enabled)
aml_find_node(&aml_root, "_DOS", acpi_foundvideo, sc);
/* create list of devices we want to query when APM come in */
@@ -2334,6 +2335,13 @@ acpi_foundhid(struct aml_node *node, voi
acpi_thinkpad_enabled = 1;
} else if (!strcmp(dev, ACPI_DEV_ASUSAIBOOSTER))
aaa.aaa_name = "aibs";
+ else if (!strcmp(dev, ACPI_DEV_TOSHIBA_LIBRETTO) ||
+ !strcmp(dev, ACPI_DEV_TOSHIBA_DYNABOOK) ||
+ !strcmp(dev, ACPI_DEV_TOSHIBA_SPA40)) {
+ aaa.aaa_name = "acpitoshiba";
+ acpi_toshiba_enabled = 1;
+ }
+
if (aaa.aaa_name)
config_found(self, &aaa, acpi_print);
Index: sys/dev/acpi/acpireg.h
===================================================================
RCS file: /cvs/src/sys/dev/acpi/acpireg.h,v
retrieving revision 1.25
diff -u -p -r1.25 acpireg.h
--- sys/dev/acpi/acpireg.h 27 Apr 2011 20:55:42 -0000 1.25
+++ sys/dev/acpi/acpireg.h 13 Jun 2011 16:47:34 -0000
@@ -716,5 +716,8 @@ struct acpi_ivrs {
#define ACPI_DEV_IBM "IBM0068" /* IBM ThinkPad support */
#define ACPI_DEV_LENOVO "LEN0068" /* Lenovo ThinkPad support */
#define ACPI_DEV_ASUSAIBOOSTER "ATK0110" /* ASUSTeK AI Booster */
+#define ACPI_DEV_TOSHIBA_LIBRETTO "TOS6200" /* Toshiba Libretto
support */
+#define ACPI_DEV_TOSHIBA_DYNABOOK "TOS6207" /* Toshiba Dynabook
support */
+#define ACPI_DEV_TOSHIBA_SPA40 "TOS6208" /* Toshiba SPA40 support */
#endif /* !_DEV_ACPI_ACPIREG_H_ */
Index: sys/dev/acpi/files.acpi
===================================================================
RCS file: /cvs/src/sys/dev/acpi/files.acpi,v
retrieving revision 1.25
diff -u -p -r1.25 files.acpi
--- sys/dev/acpi/files.acpi 4 Jan 2011 21:17:49 -0000 1.25
+++ sys/dev/acpi/files.acpi 13 Jun 2011 16:47:34 -0000
@@ -81,6 +81,11 @@ device acpithinkpad
attach acpithinkpad at acpi
file dev/acpi/acpithinkpad.c acpithinkpad
+# Toshiba support
+device acpitoshiba
+attach acpitoshiba at acpi
+file dev/acpi/acpitoshiba.c acpitoshiba
+
# Sony support
device acpisony
attach acpisony at acpi