Subject: port-i386/32276: Brightness control not working on Sony Vaio VGN-BX197XP
To: None <port-i386-maintainer@netbsd.org, gnats-admin@netbsd.org,>
From: None <sami.kantoluoto@embedtronics.fi>
List: netbsd-bugs
Date: 12/10/2005 23:55:00
>Number:         32276
>Category:       port-i386
>Synopsis:       Brightness control not working on Sony Vaio VGN-BX197XP
>Confidential:   no
>Severity:       critical
>Priority:       high
>Responsible:    port-i386-maintainer
>State:          open
>Class:          support
>Submitter-Id:   net
>Arrival-Date:   Sat Dec 10 23:55:00 +0000 2005
>Originator:     Sami Kantoluoto
>Release:        NetBSD 3.99.13
>Organization:
	Embedtronics Oy
>Environment:
System: NetBSD gondor 3.99.13 NetBSD 3.99.13 (GONDOR) #13: Sun Dec 11 00:52:58 EET 2005 root@gondor:/s/nb/current/src/sys/arch/i386/compile/GONDOR i386
Architecture: i386
Machine: i386
>Description:
	Can't control the brightness of the LCD of Sony Vaio VGN-BX197XP.
	This is quite a problem because the initial brightness is so bright
	you really cannot watch it without getting a headache.
>How-To-Repeat:
>Fix:
	Here's a quick dirty hack to i386/acpi/spic_acpi.c that adds
	'machdep.spic.*' 'sysctl entries making it possible to tweak
	values. Remember to add 'spic* at acpi?' to configuration file.

	After installing the patch and getting new kernel running you
	can control the brightness with 'sysctl -w machdep.spic.BRT=<x>'
	(or adding "machdep.spic.BRT=<x>" to /etc/sysctl.conf), where <x>
	seems to be from (darkest) 0-8 (brightest), except that	2 does
	nothing (?).

	Brigthtness control ACPI methods/functions (whatever they're called)
	were figured out from http://popies.net/sonypi/2.6-sony_acpi4.patch

	NOTE: Use at your own risk!

Index: arch/i386/acpi/spic_acpi.c
===================================================================
RCS file: /netbsd/cvs/src/sys/arch/i386/acpi/spic_acpi.c,v
retrieving revision 1.12
diff -r1.12 spic_acpi.c
47a48
> #include <sys/sysctl.h>
64a66
> 	"SNY5001",	/* XXX */
74a77,79
> #ifdef	ACPI_DEBUG
> /*#define	SPIC_ACPI_DEBUG*/
> #endif
86a92,208
> ACPI_HANDLE spic_acpi_hnd;	/* XXX */
> ACPI_STATUS
> acpi_eval_set_integer(ACPI_HANDLE, const char *, ACPI_INTEGER, ACPI_INTEGER *);
> 
> static int spic_sysctl_helper(SYSCTLFN_ARGS)
> {
> 	struct sysctlnode	node;
> 	ACPI_INTEGER		acpi_val;
> 	ACPI_STATUS		rv;
> 	int			val, old_val, error;
> 	char			buf[SYSCTL_NAMELEN+1];
> 
> 	snprintf(buf, sizeof(buf), "G%s", rnode->sysctl_name);
> 
> 	rv = acpi_eval_integer(spic_acpi_hnd, buf, &acpi_val);
> 	if (ACPI_FAILURE(rv)) {
> 		printf("%s: couldn't read '%s'\n", __FUNCTION__, buf);
> 		return EIO;
> 	}
> 	val = old_val = acpi_val;
> 
> 	node = *rnode;
> 	node.sysctl_data = &val;
> 
> 	error = sysctl_lookup(SYSCTLFN_CALL(&node));
> 	if (error || newp == NULL)
> 		return error;
> 
> 	if (val != old_val) {
> 		snprintf(buf, sizeof(buf), "S%s", rnode->sysctl_name);
> 		acpi_val = val;
> 		rv = acpi_eval_set_integer(spic_acpi_hnd, buf, acpi_val, NULL);
> 		if (ACPI_FAILURE(rv)) {
> 			printf("%s: couldn't write '%s' to %d\n",
> 			       __FUNCTION__, buf, val);
> 			return EIO;
> 		}
> 	}
> 
> 	return 0;
> }
> 
> static ACPI_STATUS spic_walk_cb(ACPI_HANDLE hnd, UINT32 v, void *context, void **status)
> {
> #ifdef	SPIC_ACPI_DEBUG
> 	struct spic_acpi_softc *sc = (void*)context;
> #endif
> 	const struct sysctlnode *node, *ssnode, *sssnode;
> 	const char *name = acpi_name(hnd), *ptr;
> 	int rv;
> 
> 	if ((ptr = strrchr(name, '.')) == NULL)
> 		goto done;
> 
> 	ptr++;
> #ifdef	SPIC_ACPI_DEBUG
> 	printf("%s: found method: %s\n", sc->sc_spic.sc_dev.dv_xname, ptr);
> #endif
> 
> 	if ((*ptr != 'G') && (*ptr != 'S'))
> 		goto done;
> #ifdef	SPIC_ACPI_DEBUG
> 	printf("%s: adding machdep.%s.%s\n", sc->sc_spic.sc_dev.dv_xname,
> 	       sc->sc_spic.sc_dev.dv_xname, ptr+1);
> #endif
> 	if ((rv = sysctl_createv(NULL, 0, NULL, &node,
> 				 CTLFLAG_PERMANENT, CTLTYPE_NODE, "machdep", NULL,
> 				 NULL, 0, NULL, 0, CTL_MACHDEP, CTL_EOL)) != 0)
> 		goto err;
> 
> 	if ((rv = sysctl_createv(NULL, 0, &node, &ssnode,
> 				 0, CTLTYPE_NODE, "spic", NULL,
> 				 NULL, 0, NULL, 0, CTL_CREATE, CTL_EOL)) != 0)
> 		goto err;
> 
> 	if ((rv = sysctl_createv(NULL, 0, &ssnode, &sssnode,
> 				 CTLFLAG_READWRITE, CTLTYPE_INT, ptr + 1, NULL,
> 				 spic_sysctl_helper, 0, NULL, 0, CTL_CREATE,
> 				 CTL_EOL)) != 0)
> 		goto err;
> 
> done:
> 	return AE_OK;
> err:
> 	aprint_normal("%s: sysctl_createv failed (rv = %d)\n", __func__, rv);
> 	return AE_OK;
> }
> 
> ACPI_STATUS
> acpi_eval_set_integer(ACPI_HANDLE handle, const char *path, ACPI_INTEGER val, ACPI_INTEGER *valp)
> {
> 	ACPI_STATUS rv;
> 	ACPI_BUFFER buf;
> 	ACPI_OBJECT param, ret_val;
> 	ACPI_OBJECT_LIST params;
> 
> 	if (handle == NULL)
> 		handle = ACPI_ROOT_OBJECT;
> 
> 	params.Count = 1;
> 	params.Pointer = &param;
> 
> 	param.Type = ACPI_TYPE_INTEGER;
> 	param.Integer.Value = val;
> 
> 	buf.Pointer = &ret_val;
> 	buf.Length = sizeof(ret_val);
> 
> 	rv = AcpiEvaluateObjectTyped(handle, path, &params, &buf, ACPI_TYPE_INTEGER);
> 
> 	if (ACPI_SUCCESS(rv) && valp) {
> 		*valp = ret_val.Integer.Value;
> 	}
> 
> 	return rv;
> }
> 
100a223,235
> 
> 	/* install sysctl nodes.. */
> 	/* XXX protection of spic_acpi_hnd??? XXX */
> 	if (!spic_acpi_hnd) {
> 		printf("%s: installing sysctl hooks...\n",
> 		       sc->sc_spic.sc_dev.dv_xname);
> 		rv = AcpiWalkNamespace(ACPI_TYPE_METHOD, sc->sc_node->ad_handle, 1,
> 				       spic_walk_cb, sc, NULL);
> 		if (ACPI_FAILURE(rv))
> 			goto out;
> 
> 		spic_acpi_hnd = sc->sc_node->ad_handle;
> 	}