Re: [PATCH 2.6.29] fujitsu-laptop: Add BL power,

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hi Len

> > The FUNC interface in the Fujitsu-Siemens DSDT was unused until now. It exposes 
> > state information that is now reported in additional platform files (whether the 
> > radios are killed by the hardware switch or operational, whether the machine is 
> > docked and whether the lid is open). ...
>
> applied to acpi-test so it can get into linux-next
> I'll wait for an Ack from Jonathan before pushing upstream, however.

I have now tested this on my S7020 and the patch causes no regressions on
that platform.  Sorry for the delay - Christmas and New Year does that. :-)

Acked-by: Jonathan Woithe <jwoithe@xxxxxxxxxxxxxxxxxxxxxxx>

Regards
  jonathan

> > The FUNC interface in the Fujitsu-Siemens DSDT was unused until now. It exposes 
> > state information that is now reported in additional platform files (whether the 
> > radios are killed by the hardware switch or operational, whether the machine is 
> > docked and whether the lid is open).
> > Support for the backlight class is now extended with the ability to power the 
> > backlight on & off. Optional support for the LED class allows the keyboard 
> > headlamps found on the U810 netbook and the Fujitsu logo illumination on the 
> > P8010 notebook to be turned on & off.
> > 
> > This was fed through checkpatch.pl and tested on the S6420, P8010 & U810 platforms.
> > 
> > (Awaiting sign-off by Jonathan, which means the S7020 platform will also be tested)
> > 
> > Signed-off-by: Stephen Gildea <stepheng+linux@xxxxxxxxxx>
> > Tested-by: Stephen Gildea <stepheng+linux@xxxxxxxxxx>
> > Tested-by: Julian Brown <jules@xxxxxxxxxxxxxxxxxxxxxxx>
> > Signed-off-by: Tony Vroon <tony@xxxxxxxx>
> > 
> > --- linux-2.6/drivers/misc/fujitsu-laptop.c.orig	2008-12-29 16:21:36.000000000 +0000
> > +++ linux-2.6/drivers/misc/fujitsu-laptop.c	2008-12-31 18:01:22.000000000 +0000
> > @@ -3,6 +3,7 @@
> >  /*
> >    Copyright (C) 2007,2008 Jonathan Woithe <jwoithe@xxxxxxxxxxxxxxxxxxxxxxx>
> >    Copyright (C) 2008 Peter Gruber <nokos@xxxxxxx>
> > +  Copyright (C) 2008 Tony Vroon <tony@xxxxxxxx>
> >    Based on earlier work:
> >      Copyright (C) 2003 Shane Spencer <shane@xxxxxxxxxxx>
> >      Adrian Yee <brewt-fujitsu@xxxxxxxxx>
> > @@ -65,8 +66,11 @@
> >  #include <linux/kfifo.h>
> >  #include <linux/video_output.h>
> >  #include <linux/platform_device.h>
> > +#ifdef CONFIG_LEDS_CLASS
> > +#include <linux/leds.h>
> > +#endif
> >  
> > -#define FUJITSU_DRIVER_VERSION "0.4.3"
> > +#define FUJITSU_DRIVER_VERSION "0.5.0"
> >  
> >  #define FUJITSU_LCD_N_LEVELS 8
> >  
> > @@ -83,6 +87,24 @@
> >  #define ACPI_VIDEO_NOTIFY_INC_BRIGHTNESS     0x86
> >  #define ACPI_VIDEO_NOTIFY_DEC_BRIGHTNESS     0x87
> >  
> > +/* FUNC interface - command values */
> > +#define FUNC_RFKILL	0x1000
> > +#define FUNC_LEDS	0x1001
> > +#define FUNC_BUTTONS	0x1002
> > +#define FUNC_BACKLIGHT  0x1004
> > +
> > +/* FUNC interface - responses */
> > +#define UNSUPPORTED_CMD 0x80000000
> > +
> > +#ifdef CONFIG_LEDS_CLASS
> > +/* FUNC interface - LED control */
> > +#define FUNC_LED_OFF	0x1
> > +#define FUNC_LED_ON	0x30001
> > +#define KEYBOARD_LAMPS	0x100
> > +#define LOGOLAMP_POWERON 0x2000
> > +#define LOGOLAMP_ALWAYS  0x4000
> > +#endif
> > +
> >  /* Hotkey details */
> >  #define KEY1_CODE	0x410	/* codes for the keys in the GIRB register */
> >  #define KEY2_CODE	0x411
> > @@ -145,8 +167,9 @@
> >  	struct platform_device *pf_device;
> >  	struct kfifo *fifo;
> >  	spinlock_t fifo_lock;
> > -
> > -	unsigned int irb;	/* info about the pressed buttons */
> > +	int rfkill_state;
> > +	int logolamp_registered;
> > +	int kblamps_registered;
> >  };
> >  
> >  static struct fujitsu_hotkey_t *fujitsu_hotkey;
> > @@ -154,12 +177,139 @@
> >  static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
> >  				       void *data);
> >  
> > +#ifdef CONFIG_LEDS_CLASS
> > +static enum led_brightness logolamp_get(struct led_classdev *cdev);
> > +static void logolamp_set(struct led_classdev *cdev,
> > +			       enum led_brightness brightness);
> > +
> > +struct led_classdev logolamp_led = {
> > + .name = "fujitsu::logolamp",
> > + .brightness_get = logolamp_get,
> > + .brightness_set = logolamp_set
> > +};
> > +
> > +static enum led_brightness kblamps_get(struct led_classdev *cdev);
> > +static void kblamps_set(struct led_classdev *cdev,
> > +			       enum led_brightness brightness);
> > +
> > +struct led_classdev kblamps_led = {
> > + .name = "fujitsu::kblamps",
> > + .brightness_get = kblamps_get,
> > + .brightness_set = kblamps_set
> > +};
> > +#endif
> > +
> >  #ifdef CONFIG_FUJITSU_LAPTOP_DEBUG
> >  static u32 dbg_level = 0x03;
> >  #endif
> >  
> >  static void acpi_fujitsu_notify(acpi_handle handle, u32 event, void *data);
> >  
> > +/* Fujitsu ACPI interface function */
> > +
> > +static int call_fext_func(int cmd, int arg0, int arg1, int arg2)
> > +{
> > +	acpi_status status = AE_OK;
> > +	union acpi_object params[4] = {
> > +	{ .type = ACPI_TYPE_INTEGER },
> > +	{ .type = ACPI_TYPE_INTEGER },
> > +	{ .type = ACPI_TYPE_INTEGER },
> > +	{ .type = ACPI_TYPE_INTEGER }
> > +	};
> > +	struct acpi_object_list arg_list = { 4, &params[0] };
> > +	struct acpi_buffer output;
> > +	union acpi_object out_obj;
> > +	acpi_handle handle = NULL;
> > +
> > +	status = acpi_get_handle(fujitsu_hotkey->acpi_handle, "FUNC", &handle);
> > +	if (ACPI_FAILURE(status)) {
> > +		vdbg_printk(FUJLAPTOP_DBG_ERROR,
> > +				"FUNC interface is not present\n");
> > +		return -ENODEV;
> > +	}
> > +
> > +	params[0].integer.value = cmd;
> > +	params[1].integer.value = arg0;
> > +	params[2].integer.value = arg1;
> > +	params[3].integer.value = arg2;
> > +
> > +	output.length = sizeof(out_obj);
> > +	output.pointer = &out_obj;
> > +
> > +	status = acpi_evaluate_object(handle, NULL, &arg_list, &output);
> > +	if (ACPI_FAILURE(status)) {
> > +		vdbg_printk(FUJLAPTOP_DBG_WARN,
> > +			"FUNC 0x%x (args 0x%x, 0x%x, 0x%x) call failed\n",
> > +				cmd, arg0, arg1, arg2);
> > +		return -ENODEV;
> > +	}
> > +
> > +	if (out_obj.type != ACPI_TYPE_INTEGER) {
> > +		vdbg_printk(FUJLAPTOP_DBG_WARN,
> > +			"FUNC 0x%x (args 0x%x, 0x%x, 0x%x) did not "
> > +			"return an integer\n",
> > +			cmd, arg0, arg1, arg2);
> > +		return -ENODEV;
> > +	}
> > +
> > +	vdbg_printk(FUJLAPTOP_DBG_TRACE,
> > +		"FUNC 0x%x (args 0x%x, 0x%x, 0x%x) returned 0x%x\n",
> > +			cmd, arg0, arg1, arg2, (int)out_obj.integer.value);
> > +	return out_obj.integer.value;
> > +}
> > +
> > +#ifdef CONFIG_LEDS_CLASS
> > +/* LED class callbacks */
> > +
> > +static void logolamp_set(struct led_classdev *cdev,
> > +			       enum led_brightness brightness)
> > +{
> > +	if (brightness >= LED_FULL) {
> > +		call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
> > +		call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_ON);
> > +	} else if (brightness >= LED_HALF) {
> > +		call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_ON);
> > +		call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_ALWAYS, FUNC_LED_OFF);
> > +	} else {
> > +		call_fext_func(FUNC_LEDS, 0x1, LOGOLAMP_POWERON, FUNC_LED_OFF);
> > +	}
> > +}
> > +
> > +static void kblamps_set(struct led_classdev *cdev,
> > +			       enum led_brightness brightness)
> > +{
> > +	if (brightness >= LED_FULL)
> > +		call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_ON);
> > +	else
> > +		call_fext_func(FUNC_LEDS, 0x1, KEYBOARD_LAMPS, FUNC_LED_OFF);
> > +}
> > +
> > +static enum led_brightness logolamp_get(struct led_classdev *cdev)
> > +{
> > +	enum led_brightness brightness = LED_OFF;
> > +	int poweron, always;
> > +
> > +	poweron = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_POWERON, 0x0);
> > +	if (poweron == FUNC_LED_ON) {
> > +		brightness = LED_HALF;
> > +		always = call_fext_func(FUNC_LEDS, 0x2, LOGOLAMP_ALWAYS, 0x0);
> > +		if (always == FUNC_LED_ON)
> > +			brightness = LED_FULL;
> > +	}
> > +	return brightness;
> > +}
> > +
> > +static enum led_brightness kblamps_get(struct led_classdev *cdev)
> > +{
> > +	enum led_brightness brightness = LED_OFF;
> > +
> > +	if (call_fext_func(FUNC_LEDS, 0x2, KEYBOARD_LAMPS, 0x0) == FUNC_LED_ON)
> > +		brightness = LED_FULL;
> > +
> > +	return brightness;
> > +}
> > +#endif
> > +
> >  /* Hardware access for LCD brightness control */
> >  
> >  static int set_lcd_level(int level)
> > @@ -297,10 +447,25 @@
> >  
> >  static int bl_update_status(struct backlight_device *b)
> >  {
> > +	int ret;
> > +	if (b->props.power == 4)
> > +		ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x3);
> > +	else
> > +		ret = call_fext_func(FUNC_BACKLIGHT, 0x1, 0x4, 0x0);
> > +	if (ret != 0)
> > +		vdbg_printk(FUJLAPTOP_DBG_ERROR,
> > +			"Unable to adjust backlight power, error code %i\n",
> > +			ret);
> > +
> >  	if (use_alt_lcd_levels)
> > -		return set_lcd_level_alt(b->props.brightness);
> > +		ret = set_lcd_level_alt(b->props.brightness);
> >  	else
> > -		return set_lcd_level(b->props.brightness);
> > +		ret = set_lcd_level(b->props.brightness);
> > +	if (ret != 0)
> > +		vdbg_printk(FUJLAPTOP_DBG_ERROR,
> > +			"Unable to adjust LCD brightness, error code %i\n",
> > +			ret);
> > +	return ret;
> >  }
> >  
> >  static struct backlight_ops fujitsubl_ops = {
> > @@ -382,42 +547,64 @@
> >  	return count;
> >  }
> >  
> > -/* Hardware access for hotkey device */
> > -
> > -static int get_irb(void)
> > +static ssize_t
> > +ignore_store(struct device *dev,
> > +	     struct device_attribute *attr, const char *buf, size_t count)
> >  {
> > -	unsigned long long state = 0;
> > -	acpi_status status = AE_OK;
> > -
> > -	vdbg_printk(FUJLAPTOP_DBG_TRACE, "Get irb\n");
> > -
> > -	status =
> > -	    acpi_evaluate_integer(fujitsu_hotkey->acpi_handle, "GIRB", NULL,
> > -				  &state);
> > -	if (status < 0)
> > -		return status;
> > +	return count;
> > +}
> >  
> > -	fujitsu_hotkey->irb = state;
> > +static ssize_t
> > +show_lid_state(struct device *dev,
> > +			struct device_attribute *attr, char *buf)
> > +{
> > +	if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
> > +		return sprintf(buf, "unknown\n");
> > +	if (fujitsu_hotkey->rfkill_state & 0x100)
> > +		return sprintf(buf, "open\n");
> > +	else
> > +		return sprintf(buf, "closed\n");
> > +}
> >  
> > -	return fujitsu_hotkey->irb;
> > +static ssize_t
> > +show_dock_state(struct device *dev,
> > +			struct device_attribute *attr, char *buf)
> > +{
> > +	if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
> > +		return sprintf(buf, "unknown\n");
> > +	if (fujitsu_hotkey->rfkill_state & 0x200)
> > +		return sprintf(buf, "docked\n");
> > +	else
> > +		return sprintf(buf, "undocked\n");
> >  }
> >  
> >  static ssize_t
> > -ignore_store(struct device *dev,
> > -	     struct device_attribute *attr, const char *buf, size_t count)
> > +show_radios_state(struct device *dev,
> > +			struct device_attribute *attr, char *buf)
> >  {
> > -	return count;
> > +	if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
> > +		return sprintf(buf, "unknown\n");
> > +	if (fujitsu_hotkey->rfkill_state & 0x20)
> > +		return sprintf(buf, "on\n");
> > +	else
> > +		return sprintf(buf, "killed\n");
> >  }
> >  
> >  static DEVICE_ATTR(max_brightness, 0444, show_max_brightness, ignore_store);
> >  static DEVICE_ATTR(brightness_changed, 0444, show_brightness_changed,
> >  		   ignore_store);
> >  static DEVICE_ATTR(lcd_level, 0644, show_lcd_level, store_lcd_level);
> > +static DEVICE_ATTR(lid, 0444, show_lid_state, ignore_store);
> > +static DEVICE_ATTR(dock, 0444, show_dock_state, ignore_store);
> > +static DEVICE_ATTR(radios, 0444, show_radios_state, ignore_store);
> >  
> >  static struct attribute *fujitsupf_attributes[] = {
> >  	&dev_attr_brightness_changed.attr,
> >  	&dev_attr_max_brightness.attr,
> >  	&dev_attr_lcd_level.attr,
> > +	&dev_attr_lid.attr,
> > +	&dev_attr_dock.attr,
> > +	&dev_attr_radios.attr,
> >  	NULL
> >  };
> >  
> > @@ -771,7 +958,8 @@
> >  	input->id.bustype = BUS_HOST;
> >  	input->id.product = 0x06;
> >  	input->dev.parent = &device->dev;
> > -	input->evbit[0] = BIT(EV_KEY);
> > +
> > +	set_bit(EV_KEY, input->evbit);
> >  	set_bit(fujitsu->keycode1, input->keybit);
> >  	set_bit(fujitsu->keycode2, input->keybit);
> >  	set_bit(fujitsu->keycode3, input->keybit);
> > @@ -803,10 +991,44 @@
> >  			printk(KERN_ERR "_INI Method failed\n");
> >  	}
> >  
> > -	i = 0;			/* Discard hotkey ringbuffer */
> > -	while (get_irb() != 0 && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) ;
> > +	i = 0;
> > +	while (call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0) != 0
> > +		&& (i++) < MAX_HOTKEY_RINGBUFFER_SIZE)
> > +		; /* No action, result is discarded */
> >  	vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
> >  
> > +	fujitsu_hotkey->rfkill_state =
> > +		call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
> > +
> > +	/* Suspect this is a keymap of the application panel, print it */
> > +	printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n",
> > +		call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0));
> > +
> > +	#ifdef CONFIG_LEDS_CLASS
> > +	if (call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & LOGOLAMP_POWERON) {
> > +		result = led_classdev_register(&fujitsu->pf_device->dev,
> > +						&logolamp_led);
> > +		if (result == 0) {
> > +			fujitsu_hotkey->logolamp_registered = 1;
> > +		} else {
> > +			printk(KERN_ERR "fujitsu-laptop: Could not register "
> > +			"LED handler for logo lamp, error %i\n", result);
> > +		}
> > +	}
> > +
> > +	if ((call_fext_func(FUNC_LEDS, 0x0, 0x0, 0x0) & KEYBOARD_LAMPS) &&
> > +	   (call_fext_func(FUNC_BUTTONS, 0x0, 0x0, 0x0) == 0x0)) {
> > +		result = led_classdev_register(&fujitsu->pf_device->dev,
> > +						&kblamps_led);
> > +		if (result == 0) {
> > +			fujitsu_hotkey->kblamps_registered = 1;
> > +		} else {
> > +			printk(KERN_ERR "fujitsu-laptop: Could not register "
> > +			"LED handler for keyboard lamps, error %i\n", result);
> > +		}
> > +	}
> > +	#endif
> > +
> >  	return result;
> >  
> >  end:
> > @@ -852,16 +1074,15 @@
> >  
> >  	input = fujitsu_hotkey->input;
> >  
> > -	vdbg_printk(FUJLAPTOP_DBG_TRACE, "Hotkey event\n");
> > +	fujitsu_hotkey->rfkill_state =
> > +		call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
> >  
> >  	switch (event) {
> >  	case ACPI_FUJITSU_NOTIFY_CODE1:
> >  		i = 0;
> > -		while ((irb = get_irb()) != 0
> > -		       && (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
> > -			vdbg_printk(FUJLAPTOP_DBG_TRACE, "GIRB result [%x]\n",
> > -				    irb);
> > -
> > +		while ((irb =
> > +			call_fext_func(FUNC_BUTTONS, 0x1, 0x0, 0x0)) != 0
> > +				&& (i++) < MAX_HOTKEY_RINGBUFFER_SIZE) {
> >  			switch (irb & 0x4ff) {
> >  			case KEY1_CODE:
> >  				keycode = fujitsu->keycode1;
> > @@ -1035,6 +1256,15 @@
> >  		goto fail_hotkey1;
> >  	}
> >  
> > +	/* Sync backlight power status (needs FUJ02E3 device, hence deferred) */
> > +
> > +	if (!acpi_video_backlight_support()) {
> > +		if (call_fext_func(FUNC_BACKLIGHT, 0x2, 0x4, 0x0) == 3)
> > +			fujitsu->bl_device->props.power = 4;
> > +		else
> > +			fujitsu->bl_device->props.power = 0;
> > +	}
> > +
> >  	printk(KERN_INFO "fujitsu-laptop: driver " FUJITSU_DRIVER_VERSION
> >  	       " successfully loaded.\n");
> >  
> > @@ -1074,6 +1304,14 @@
> >  
> >  static void __exit fujitsu_cleanup(void)
> >  {
> > +	#ifdef CONFIG_LEDS_CLASS
> > +	if (fujitsu_hotkey->logolamp_registered != 0)
> > +		led_classdev_unregister(&logolamp_led);
> > +
> > +	if (fujitsu_hotkey->kblamps_registered != 0)
> > +		led_classdev_unregister(&kblamps_led);
> > +	#endif
> > +
> >  	sysfs_remove_group(&fujitsu->pf_device->dev.kobj,
> >  			   &fujitsupf_attribute_group);
> >  	platform_device_unregister(fujitsu->pf_device);
> > @@ -1108,12 +1346,13 @@
> >  MODULE_PARM_DESC(debug, "Sets debug level bit-mask");
> >  #endif
> >  
> > -MODULE_AUTHOR("Jonathan Woithe, Peter Gruber");
> > +MODULE_AUTHOR("Jonathan Woithe, Peter Gruber, Tony Vroon");
> >  MODULE_DESCRIPTION("Fujitsu laptop extras support");
> >  MODULE_VERSION(FUJITSU_DRIVER_VERSION);
> >  MODULE_LICENSE("GPL");
> >  
> >  MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1D3:*:cvrS6410:*");
> > +MODULE_ALIAS("dmi:*:svnFUJITSUSIEMENS:*:pvr:rvnFUJITSU:rnFJNB1E6:*:cvrS6420:*");
> >  MODULE_ALIAS("dmi:*:svnFUJITSU:*:pvr:rvnFUJITSU:rnFJNB19C:*:cvrS7020:*");
> >  
> >  static struct pnp_device_id pnp_ids[] = {
> > 
--
To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux IBM ACPI]     [Linux Power Management]     [Linux Kernel]     [Linux Laptop]     [Kernel Newbies]     [Share Photos]     [Security]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Samba]     [Video 4 Linux]     [Device Mapper]     [Linux Resources]

  Powered by Linux