diff mbox

[10/28] asus-laptop: callbacks should use "driver data" parameter or field

Message ID 1265096351-15239-11-git-send-email-corentincj@iksaif.net (mailing list archive)
State Accepted
Delegated to: Len Brown
Headers show

Commit Message

Corentin Chary Feb. 2, 2010, 7:38 a.m. UTC
None
diff mbox

Patch

diff --git a/drivers/platform/x86/asus-laptop.c b/drivers/platform/x86/asus-laptop.c
index 4ff30ca..58a4864 100644
--- a/drivers/platform/x86/asus-laptop.c
+++ b/drivers/platform/x86/asus-laptop.c
@@ -196,6 +196,34 @@  ASUS_HANDLE(kled_set, ASUS_LAPTOP_PREFIX "SLKB");
 ASUS_HANDLE(kled_get, ASUS_LAPTOP_PREFIX "GLKB");
 
 /*
+ * Define a specific led structure to keep the main structure clean
+ */
+#define ASUS_DEFINE_LED(object)					\
+	int object##_wk;					\
+	struct work_struct object##_work;			\
+	struct led_classdev object;
+
+
+#define led_to_asus(led_cdev, led)					\
+	container_of(container_of(led_cdev, struct asus_laptop_leds,	\
+				  led),					\
+		     struct asus_laptop, leds)
+#define work_to_asus(work, led)						\
+	container_of(container_of(work, struct asus_laptop_leds,	\
+				  led##_work),				\
+		     struct asus_laptop, leds)
+
+struct asus_laptop_leds {
+	ASUS_DEFINE_LED(mled)
+	ASUS_DEFINE_LED(tled)
+	ASUS_DEFINE_LED(rled)
+	ASUS_DEFINE_LED(pled)
+	ASUS_DEFINE_LED(gled)
+	ASUS_DEFINE_LED(kled)
+	struct workqueue_struct *workqueue;
+};
+
+/*
  * This is the main structure, we can use it to store anything interesting
  * about the hotk device
  */
@@ -206,7 +234,11 @@  struct asus_laptop {
 	struct platform_device *platform_device;
 	struct acpi_device *device;		/* the device we are in */
 	struct backlight_device *backlight_device;
+
 	struct input_dev *inputdev;
+	struct key_entry *keymap;
+
+	struct asus_laptop_leds leds;
 
 	acpi_handle handle;	/* the handle of the hotk device */
 	char status;		/* status of the hotk, for LEDs, ... */
@@ -217,10 +249,6 @@  struct asus_laptop {
 	u16 *keycode_map;
 };
 
-static struct asus_laptop *asus;
-
-static struct workqueue_struct *led_workqueue;
-
 /*
  * The backlight class declaration
  */
@@ -237,8 +265,6 @@  static struct backlight_ops asusbl_ops = {
 	static enum led_brightness object##_led_get(			\
 		struct led_classdev *led_cdev);				\
 	static void object##_led_update(struct work_struct *ignored);	\
-	static int object##_led_wk;					\
-	static DECLARE_WORK(object##_led_work, object##_led_update);	\
 	static struct led_classdev object##_led = {			\
 		.name           = "asus::" ledname,			\
 		.brightness_set = object##_led_set,			\
@@ -261,7 +287,7 @@  struct key_entry {
 
 enum { KE_KEY, KE_END };
 
-static struct key_entry asus_keymap[] = {
+static const struct key_entry asus_keymap[] = {
 	{KE_KEY, 0x02, KEY_SCREENLOCK},
 	{KE_KEY, 0x05, KEY_WLAN},
 	{KE_KEY, 0x08, KEY_F13},
@@ -333,7 +359,7 @@  static int write_acpi_int(acpi_handle handle, const char *method, int val)
 	return write_acpi_int_ret(handle, method, val, NULL);
 }
 
-static int read_wireless_status(int mask)
+static int read_wireless_status(struct asus_laptop *asus, int mask)
 {
 	unsigned long long status;
 	acpi_status rv = AE_OK;
@@ -350,7 +376,7 @@  static int read_wireless_status(int mask)
 	return (asus->status & mask) ? 1 : 0;
 }
 
-static int read_gps_status(void)
+static int read_gps_status(struct asus_laptop *asus)
 {
 	unsigned long long status;
 	acpi_status rv = AE_OK;
@@ -365,18 +391,19 @@  static int read_gps_status(void)
 }
 
 /* Generic LED functions */
-static int read_status(int mask)
+static int read_status(struct asus_laptop *asus, int mask)
 {
 	/* There is a special method for both wireless devices */
 	if (mask == BT_ON || mask == WL_ON)
-		return read_wireless_status(mask);
+		return read_wireless_status(asus, mask);
 	else if (mask == GPS_ON)
-		return read_gps_status();
+		return read_gps_status(asus);
 
 	return (asus->status & mask) ? 1 : 0;
 }
 
-static void write_status(acpi_handle handle, int out, int mask)
+static void write_status(struct asus_laptop *asus, acpi_handle handle,
+			 int out, int mask)
 {
 	asus->status = (out) ? (asus->status | mask) : (asus->status & ~mask);
 
@@ -405,13 +432,19 @@  static void write_status(acpi_handle handle, int out, int mask)
 	static void object##_led_set(struct led_classdev *led_cdev,	\
 				     enum led_brightness value)		\
 	{								\
-		object##_led_wk = (value > 0) ? 1 : 0;			\
-		queue_work(led_workqueue, &object##_led_work);		\
+		struct asus_laptop *asus =				\
+			led_to_asus(led_cdev, object);			\
+									\
+		asus->leds.object##_wk = (value > 0) ? 1 : 0;		\
+		queue_work(asus->leds.workqueue,			\
+			   &asus->leds.object##_work);			\
 	}								\
-	static void object##_led_update(struct work_struct *ignored)	\
+	static void object##_led_update(struct work_struct *work)	\
 	{								\
-		int value = object##_led_wk;				\
-		write_status(object##_set_handle, value, (mask));	\
+		struct asus_laptop *asus = work_to_asus(work, object);	\
+									\
+		int value = asus->leds.object##_wk;			\
+		write_status(asus, object##_set_handle, value, (mask));	\
 	}								\
 	static enum led_brightness object##_led_get(			\
 		struct led_classdev *led_cdev)				\
@@ -448,7 +481,7 @@  static int get_kled_lvl(void)
 	return kblv;
 }
 
-static int set_kled_lvl(int kblv)
+static int set_kled_lvl(struct asus_laptop *asus, int kblv)
 {
 	if (kblv > 0)
 		kblv = (1 << 7) | (kblv & 0x7F);
@@ -465,13 +498,17 @@  static int set_kled_lvl(int kblv)
 static void kled_led_set(struct led_classdev *led_cdev,
 			 enum led_brightness value)
 {
-	kled_led_wk = value;
-	queue_work(led_workqueue, &kled_led_work);
+	struct asus_laptop *asus = led_to_asus(led_cdev, kled);
+
+	asus->leds.kled_wk = value;
+	queue_work(asus->leds.workqueue, &asus->leds.kled_work);
 }
 
-static void kled_led_update(struct work_struct *ignored)
+static void kled_led_update(struct work_struct *work)
 {
-	set_kled_lvl(kled_led_wk);
+	struct asus_laptop *asus = work_to_asus(work, kled);
+
+	set_kled_lvl(asus, asus->leds.kled_wk);
 }
 
 static enum led_brightness kled_led_get(struct led_classdev *led_cdev)
@@ -479,19 +516,19 @@  static enum led_brightness kled_led_get(struct led_classdev *led_cdev)
 	return get_kled_lvl();
 }
 
-static int get_lcd_state(void)
+static int get_lcd_state(struct asus_laptop *asus)
 {
-	return read_status(LCD_ON);
+	return read_status(asus, LCD_ON);
 }
 
-static int set_lcd_state(int value)
+static int set_lcd_state(struct asus_laptop *asus, int value)
 {
 	int lcd = 0;
 	acpi_status status = 0;
 
 	lcd = value ? 1 : 0;
 
-	if (lcd == get_lcd_state())
+	if (lcd == get_lcd_state(asus))
 		return 0;
 
 	if (lcd_switch_handle) {
@@ -502,11 +539,11 @@  static int set_lcd_state(int value)
 			pr_warning("Error switching LCD\n");
 	}
 
-	write_status(NULL, lcd, LCD_ON);
+	write_status(asus, NULL, lcd, LCD_ON);
 	return 0;
 }
 
-static void lcd_blank(int blank)
+static void lcd_blank(struct asus_laptop *asus, int blank)
 {
 	struct backlight_device *bd = asus->backlight_device;
 
@@ -539,6 +576,7 @@  static int set_brightness(struct backlight_device *bd, int value)
 
 static int update_bl_status(struct backlight_device *bd)
 {
+	struct asus_laptop *asus = bl_get_data(bd);
 	int rv;
 	int value = bd->props.brightness;
 
@@ -547,7 +585,7 @@  static int update_bl_status(struct backlight_device *bd)
 		return rv;
 
 	value = (bd->props.power == FB_BLANK_UNBLANK) ? 1 : 0;
-	return set_lcd_state(value);
+	return set_lcd_state(asus, value);
 }
 
 /*
@@ -562,6 +600,7 @@  static int update_bl_status(struct backlight_device *bd)
 static ssize_t show_infos(struct device *dev,
 			  struct device_attribute *attr, char *page)
 {
+	struct asus_laptop *asus = dev_get_drvdata(dev);
 	int len = 0;
 	unsigned long long temp;
 	char buf[16];		/* enough for all info */
@@ -638,7 +677,8 @@  static int parse_arg(const char *buf, unsigned long count, int *val)
 	return count;
 }
 
-static ssize_t store_status(const char *buf, size_t count,
+static ssize_t store_status(struct asus_laptop *asus,
+			    const char *buf, size_t count,
 			    acpi_handle handle, int mask)
 {
 	int rv, value;
@@ -648,7 +688,7 @@  static ssize_t store_status(const char *buf, size_t count,
 	if (rv > 0)
 		out = value ? 1 : 0;
 
-	write_status(handle, out, mask);
+	write_status(asus, handle, out, mask);
 
 	return rv;
 }
@@ -659,12 +699,15 @@  static ssize_t store_status(const char *buf, size_t count,
 static ssize_t show_ledd(struct device *dev,
 			 struct device_attribute *attr, char *buf)
 {
+	struct asus_laptop *asus = dev_get_drvdata(dev);
+
 	return sprintf(buf, "0x%08x\n", asus->ledd_status);
 }
 
 static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
 			  const char *buf, size_t count)
 {
+	struct asus_laptop *asus = dev_get_drvdata(dev);
 	int rv, value;
 
 	rv = parse_arg(buf, count, &value);
@@ -683,13 +726,17 @@  static ssize_t store_ledd(struct device *dev, struct device_attribute *attr,
 static ssize_t show_wlan(struct device *dev,
 			 struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "%d\n", read_status(WL_ON));
+	struct asus_laptop *asus = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", read_status(asus, WL_ON));
 }
 
 static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
 			  const char *buf, size_t count)
 {
-	return store_status(buf, count, wl_switch_handle, WL_ON);
+	struct asus_laptop *asus = dev_get_drvdata(dev);
+
+	return store_status(asus, buf, count, wl_switch_handle, WL_ON);
 }
 
 /*
@@ -698,20 +745,24 @@  static ssize_t store_wlan(struct device *dev, struct device_attribute *attr,
 static ssize_t show_bluetooth(struct device *dev,
 			      struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "%d\n", read_status(BT_ON));
+	struct asus_laptop *asus = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", read_status(asus, BT_ON));
 }
 
 static ssize_t store_bluetooth(struct device *dev,
 			       struct device_attribute *attr, const char *buf,
 			       size_t count)
 {
-	return store_status(buf, count, bt_switch_handle, BT_ON);
+	struct asus_laptop *asus = dev_get_drvdata(dev);
+
+	return store_status(asus, buf, count, bt_switch_handle, BT_ON);
 }
 
 /*
  * Display
  */
-static void set_display(int value)
+static void set_display(struct asus_laptop *asus, int value)
 {
 	/* no sanity check needed for now */
 	if (write_acpi_int(display_set_handle, NULL, value))
@@ -719,7 +770,7 @@  static void set_display(int value)
 	return;
 }
 
-static int read_display(void)
+static int read_display(struct asus_laptop *asus)
 {
 	unsigned long long value = 0;
 	acpi_status rv = AE_OK;
@@ -747,7 +798,9 @@  static int read_display(void)
 static ssize_t show_disp(struct device *dev,
 			 struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "%d\n", read_display());
+	struct asus_laptop *asus = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", read_display(asus));
 }
 
 /*
@@ -760,18 +813,19 @@  static ssize_t show_disp(struct device *dev,
 static ssize_t store_disp(struct device *dev, struct device_attribute *attr,
 			  const char *buf, size_t count)
 {
+	struct asus_laptop *asus = dev_get_drvdata(dev);
 	int rv, value;
 
 	rv = parse_arg(buf, count, &value);
 	if (rv > 0)
-		set_display(value);
+		set_display(asus, value);
 	return rv;
 }
 
 /*
  * Light Sens
  */
-static void set_light_sens_switch(int value)
+static void set_light_sens_switch(struct asus_laptop *asus, int value)
 {
 	if (write_acpi_int(ls_switch_handle, NULL, value))
 		pr_warning("Error setting light sensor switch\n");
@@ -781,22 +835,25 @@  static void set_light_sens_switch(int value)
 static ssize_t show_lssw(struct device *dev,
 			 struct device_attribute *attr, char *buf)
 {
+	struct asus_laptop *asus = dev_get_drvdata(dev);
+
 	return sprintf(buf, "%d\n", asus->light_switch);
 }
 
 static ssize_t store_lssw(struct device *dev, struct device_attribute *attr,
 			  const char *buf, size_t count)
 {
+	struct asus_laptop *asus = dev_get_drvdata(dev);
 	int rv, value;
 
 	rv = parse_arg(buf, count, &value);
 	if (rv > 0)
-		set_light_sens_switch(value ? 1 : 0);
+		set_light_sens_switch(asus, value ? 1 : 0);
 
 	return rv;
 }
 
-static void set_light_sens_level(int value)
+static void set_light_sens_level(struct asus_laptop *asus, int value)
 {
 	if (write_acpi_int(ls_level_handle, NULL, value))
 		pr_warning("Error setting light sensor level\n");
@@ -806,19 +863,22 @@  static void set_light_sens_level(int value)
 static ssize_t show_lslvl(struct device *dev,
 			  struct device_attribute *attr, char *buf)
 {
+	struct asus_laptop *asus = dev_get_drvdata(dev);
+
 	return sprintf(buf, "%d\n", asus->light_level);
 }
 
 static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
 			   const char *buf, size_t count)
 {
+	struct asus_laptop *asus = dev_get_drvdata(dev);
 	int rv, value;
 
 	rv = parse_arg(buf, count, &value);
 	if (rv > 0) {
 		value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
 		/* 0 <= value <= 15 */
-		set_light_sens_level(value);
+		set_light_sens_level(asus, value);
 	}
 
 	return rv;
@@ -830,34 +890,40 @@  static ssize_t store_lslvl(struct device *dev, struct device_attribute *attr,
 static ssize_t show_gps(struct device *dev,
 			struct device_attribute *attr, char *buf)
 {
-	return sprintf(buf, "%d\n", read_status(GPS_ON));
+	struct asus_laptop *asus = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%d\n", read_status(asus, GPS_ON));
 }
 
 static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
 			 const char *buf, size_t count)
 {
-	return store_status(buf, count, NULL, GPS_ON);
+	struct asus_laptop *asus = dev_get_drvdata(dev);
+
+	return store_status(asus, buf, count, NULL, GPS_ON);
 }
 
 /*
  * Hotkey functions
  */
-static struct key_entry *asus_get_entry_by_scancode(int code)
+static struct key_entry *asus_get_entry_by_scancode(struct asus_laptop *asus,
+						    int code)
 {
 	struct key_entry *key;
 
-	for (key = asus_keymap; key->type != KE_END; key++)
+	for (key = asus->keymap; key->type != KE_END; key++)
 		if (code == key->code)
 			return key;
 
 	return NULL;
 }
 
-static struct key_entry *asus_get_entry_by_keycode(int code)
+static struct key_entry *asus_get_entry_by_keycode(struct asus_laptop *asus,
+						   int code)
 {
 	struct key_entry *key;
 
-	for (key = asus_keymap; key->type != KE_END; key++)
+	for (key = asus->keymap; key->type != KE_END; key++)
 		if (code == key->keycode && key->type == KE_KEY)
 			return key;
 
@@ -866,7 +932,8 @@  static struct key_entry *asus_get_entry_by_keycode(int code)
 
 static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode)
 {
-	struct key_entry *key = asus_get_entry_by_scancode(scancode);
+	struct asus_laptop *asus = input_get_drvdata(dev);
+	struct key_entry *key = asus_get_entry_by_scancode(asus, scancode);
 
 	if (key && key->type == KE_KEY) {
 		*keycode = key->keycode;
@@ -878,18 +945,19 @@  static int asus_getkeycode(struct input_dev *dev, int scancode, int *keycode)
 
 static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
 {
+	struct asus_laptop *asus = input_get_drvdata(dev);
 	struct key_entry *key;
 	int old_keycode;
 
 	if (keycode < 0 || keycode > KEY_MAX)
 		return -EINVAL;
 
-	key = asus_get_entry_by_scancode(scancode);
+	key = asus_get_entry_by_scancode(asus, scancode);
 	if (key && key->type == KE_KEY) {
 		old_keycode = key->keycode;
 		key->keycode = keycode;
 		set_bit(keycode, dev->keybit);
-		if (!asus_get_entry_by_keycode(old_keycode))
+		if (!asus_get_entry_by_keycode(asus, old_keycode))
 			clear_bit(old_keycode, dev->keybit);
 		return 0;
 	}
@@ -899,6 +967,7 @@  static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
 
 static void asus_acpi_notify(struct acpi_device *device, u32 event)
 {
+	struct asus_laptop *asus = acpi_driver_data(device);
 	static struct key_entry *key;
 	u16 count;
 
@@ -907,11 +976,11 @@  static void asus_acpi_notify(struct acpi_device *device, u32 event)
 	 * switched
 	 */
 	if (event == ATKD_LCD_ON) {
-		write_status(NULL, 1, LCD_ON);
-		lcd_blank(FB_BLANK_UNBLANK);
+		write_status(asus, NULL, 1, LCD_ON);
+		lcd_blank(asus, FB_BLANK_UNBLANK);
 	} else if (event == ATKD_LCD_OFF) {
-		write_status(NULL, 0, LCD_ON);
-		lcd_blank(FB_BLANK_POWERDOWN);
+		write_status(asus, NULL, 0, LCD_ON);
+		lcd_blank(asus, FB_BLANK_POWERDOWN);
 	}
 
 	/* TODO Find a better way to handle events count. */
@@ -922,7 +991,7 @@  static void asus_acpi_notify(struct acpi_device *device, u32 event)
 					count);
 
 	if (asus->inputdev) {
-		key = asus_get_entry_by_scancode(event);
+		key = asus_get_entry_by_scancode(asus, event);
 		if (!key)
 			return ;
 
@@ -978,13 +1047,14 @@  static struct attribute_group platform_attribute_group = {
 	.attrs = asuspf_attributes
 };
 
-static int asus_platform_init(void)
+static int asus_platform_init(struct asus_laptop *asus)
 {
 	int result;
 
 	asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1);
 	if (!asus->platform_device)
 		return -ENOMEM;
+	platform_set_drvdata(asus->platform_device, asus);
 
 	result = platform_device_add(asus->platform_device);
 	if (result)
@@ -1003,7 +1073,7 @@  fail_platform_device:
 	return result;
 }
 
-static void asus_platform_exit(void)
+static void asus_platform_exit(struct asus_laptop *asus)
 {
 	sysfs_remove_group(&asus->platform_device->dev.kobj,
 			   &platform_attribute_group);
@@ -1012,12 +1082,12 @@  static void asus_platform_exit(void)
 
 static struct platform_driver platform_driver = {
 	.driver = {
-		   .name = ASUS_LAPTOP_FILE,
-		   .owner = THIS_MODULE,
-		   }
+		.name = ASUS_LAPTOP_FILE,
+		.owner = THIS_MODULE,
+	}
 };
 
-static void asus_laptop_add_fs(void)
+static void asus_laptop_add_fs(struct asus_laptop *asus)
 {
 	ASUS_SET_DEVICE_ATTR(infos, 0444, show_infos, NULL);
 
@@ -1187,7 +1257,7 @@  static int asus_laptop_get_info(struct asus_laptop *asus)
 	return AE_OK;
 }
 
-static int asus_input_init(struct device *dev)
+static int asus_input_init(struct asus_laptop *asus)
 {
 	const struct key_entry *key;
 	int result;
@@ -1198,13 +1268,16 @@  static int asus_input_init(struct device *dev)
 		return 0;
 	}
 	asus->inputdev->name = "Asus Laptop extra buttons";
-	asus->inputdev->dev.parent = dev;
+	asus->inputdev->dev.parent = &asus->platform_device->dev;
 	asus->inputdev->phys = ASUS_LAPTOP_FILE "/input0";
 	asus->inputdev->id.bustype = BUS_HOST;
 	asus->inputdev->getkeycode = asus_getkeycode;
 	asus->inputdev->setkeycode = asus_setkeycode;
+	input_set_drvdata(asus->inputdev, asus);
 
-	for (key = asus_keymap; key->type != KE_END; key++) {
+	asus->keymap = kmemdup(asus_keymap, sizeof(asus_keymap),
+				GFP_KERNEL);
+	for (key = asus->keymap; key->type != KE_END; key++) {
 		switch (key->type) {
 		case KE_KEY:
 			set_bit(EV_KEY, asus->inputdev->evbit);
@@ -1220,40 +1293,44 @@  static int asus_input_init(struct device *dev)
 	return result;
 }
 
-static void asus_backlight_exit(void)
+static void asus_backlight_exit(struct asus_laptop *asus)
 {
 	if (asus->backlight_device)
 		backlight_device_unregister(asus->backlight_device);
 }
 
-#define  ASUS_LED_UNREGISTER(object)				\
+#define ASUS_LED_UNREGISTER(object)				\
 	if (object##_led.dev)					\
 		led_classdev_unregister(&object##_led)
 
-static void asus_led_exit(void)
+static void asus_led_exit(struct asus_laptop *asus)
 {
-	destroy_workqueue(led_workqueue);
 	ASUS_LED_UNREGISTER(mled);
 	ASUS_LED_UNREGISTER(tled);
 	ASUS_LED_UNREGISTER(pled);
 	ASUS_LED_UNREGISTER(rled);
 	ASUS_LED_UNREGISTER(gled);
 	ASUS_LED_UNREGISTER(kled);
+	if (asus->leds.workqueue) {
+		destroy_workqueue(asus->leds.workqueue);
+		asus->leds.workqueue = NULL;
+	}
 }
 
-static void asus_input_exit(void)
+static void asus_input_exit(struct asus_laptop *asus)
 {
 	if (asus->inputdev)
 		input_unregister_device(asus->inputdev);
 }
 
-static int asus_backlight_init(struct device *dev)
+static int asus_backlight_init(struct asus_laptop *asus)
 {
 	struct backlight_device *bd;
+	struct device *dev = &asus->platform_device->dev;
 
 	if (brightness_set_handle && lcd_switch_handle) {
 		bd = backlight_device_register(ASUS_LAPTOP_FILE, dev,
-					       NULL, &asusbl_ops);
+					       asus, &asusbl_ops);
 		if (IS_ERR(bd)) {
 			pr_err("Could not register asus backlight device\n");
 			asus->backlight_device = NULL;
@@ -1270,79 +1347,55 @@  static int asus_backlight_init(struct device *dev)
 	return 0;
 }
 
-static int asus_led_register(acpi_handle handle,
-			     struct led_classdev *ldev, struct device *dev)
-{
-	if (!handle)
-		return 0;
-
-	return led_classdev_register(dev, ldev);
-}
-
-#define ASUS_LED_REGISTER(object, device)				\
-	asus_led_register(object##_set_handle, &object##_led, device)
-
-static int asus_led_init(struct device *dev)
+/*
+ * Ugly macro, need to fix that later
+ */
+#define ASUS_LED_REGISTER(asus, object, _name, max)			\
+	do {								\
+		struct led_classdev *ldev = &asus->leds.object;		\
+		if (!object##_set_handle)				\
+			break ;						\
+									\
+		INIT_WORK(&asus->leds.object##_work, object##_led_update); \
+		ldev->name = "asus::" _name;				\
+		ldev->brightness_set = object##_led_set;		\
+		ldev->max_brightness = max;				\
+		rv = led_classdev_register(&asus->platform_device->dev, ldev); \
+		if (rv)							\
+			goto error;					\
+	} while (0)
+
+static int asus_led_init(struct asus_laptop *asus)
 {
 	int rv;
 
-	rv = ASUS_LED_REGISTER(mled, dev);
-	if (rv)
-		goto out;
-
-	rv = ASUS_LED_REGISTER(tled, dev);
-	if (rv)
-		goto out1;
-
-	rv = ASUS_LED_REGISTER(rled, dev);
-	if (rv)
-		goto out2;
-
-	rv = ASUS_LED_REGISTER(pled, dev);
-	if (rv)
-		goto out3;
-
-	rv = ASUS_LED_REGISTER(gled, dev);
-	if (rv)
-		goto out4;
-
-	if (kled_set_handle && kled_get_handle)
-		rv = ASUS_LED_REGISTER(kled, dev);
-	if (rv)
-		goto out5;
-
 	/*
 	 * Functions that actually update the LED's are called from a
 	 * workqueue. By doing this as separate work rather than when the LED
 	 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
 	 * potentially bad time, such as a timer interrupt.
 	 */
-	led_workqueue = create_singlethread_workqueue("led_workqueue");
-	if (!led_workqueue)
-		goto out6;
+	asus->leds.workqueue = create_singlethread_workqueue("led_workqueue");
+	if (!asus->leds.workqueue)
+		return -ENOMEM;
 
-	return 0;
-out6:
-	rv = -ENOMEM;
-	ASUS_LED_UNREGISTER(kled);
-out5:
-	ASUS_LED_UNREGISTER(gled);
-out4:
-	ASUS_LED_UNREGISTER(pled);
-out3:
-	ASUS_LED_UNREGISTER(rled);
-out2:
-	ASUS_LED_UNREGISTER(tled);
-out1:
-	ASUS_LED_UNREGISTER(mled);
-out:
+	ASUS_LED_REGISTER(asus, mled, "mail", 1);
+	ASUS_LED_REGISTER(asus, tled, "touchpad", 1);
+	ASUS_LED_REGISTER(asus, rled, "record", 1);
+	ASUS_LED_REGISTER(asus, pled, "phone", 1);
+	ASUS_LED_REGISTER(asus, gled, "gaming", 1);
+	if (kled_set_handle && kled_get_handle)
+		ASUS_LED_REGISTER(asus, kled, "kbd_backlight", 3);
+error:
+	if (rv)
+		asus_led_exit(asus);
 	return rv;
 }
 
 
 static bool asus_device_present;
 
-static int __devinit asus_acpi_init(struct acpi_device *device)
+static int __devinit asus_acpi_init(struct asus_laptop *asus)
 {
 	int result = 0;
 
@@ -1358,22 +1411,22 @@  static int __devinit asus_acpi_init(struct acpi_device *device)
 	if (result)
 		return result;
 
-	asus_laptop_add_fs();
+	asus_laptop_add_fs(asus);
 
 	/* WLED and BLED are on by default */
-	write_status(bt_switch_handle, 1, BT_ON);
-	write_status(wl_switch_handle, 1, WL_ON);
+	write_status(asus, bt_switch_handle, 1, BT_ON);
+	write_status(asus, wl_switch_handle, 1, WL_ON);
 
 	/* If the h/w switch is off, we need to check the real status */
-	write_status(NULL, read_status(BT_ON), BT_ON);
-	write_status(NULL, read_status(WL_ON), WL_ON);
+	write_status(asus, NULL, read_status(asus, BT_ON), BT_ON);
+	write_status(asus, NULL, read_status(asus, WL_ON), WL_ON);
 
 	/* LCD Backlight is on by default */
-	write_status(NULL, 1, LCD_ON);
+	write_status(asus, NULL, 1, LCD_ON);
 
 	/* Keyboard Backlight is on by default */
 	if (kled_set_handle)
-		set_kled_lvl(1);
+		set_kled_lvl(asus, 1);
 
 	/* LED display is off by default */
 	asus->ledd_status = 0xFFF;
@@ -1383,18 +1436,19 @@  static int __devinit asus_acpi_init(struct acpi_device *device)
 	hotk->light_level = 5;	/* level 5 for sensor sensitivity */
 
 	if (ls_switch_handle)
-		set_light_sens_switch(asus->light_switch);
+		set_light_sens_switch(asus, asus->light_switch);
 
 	if (ls_level_handle)
-		set_light_sens_level(asus->light_level);
+		set_light_sens_level(asus, asus->light_level);
 
 	/* GPS is on by default */
-	write_status(NULL, 1, GPS_ON);
+	write_status(asus, NULL, 1, GPS_ON);
 	return result;
 }
 
 static int __devinit asus_acpi_add(struct acpi_device *device)
 {
+	struct asus_laptop *asus;
 	int result;
 
 	pr_notice("Asus Laptop Support version %s\n",
@@ -1408,7 +1462,7 @@  static int __devinit asus_acpi_add(struct acpi_device *device)
 	device->driver_data = asus;
 	asus->device = device;
 
-	result = asus_acpi_init(device);
+	result = asus_acpi_init(asus);
 	if (result)
 		goto fail_platform;
 
@@ -1416,22 +1470,22 @@  static int __devinit asus_acpi_add(struct acpi_device *device)
 	 * Register the platform device first.  It is used as a parent for the
 	 * sub-devices below.
 	 */
-	result = asus_platform_init();
+	result = asus_platform_init(asus);
 	if (result)
 		goto fail_platform;
 
 	if (!acpi_video_backlight_support()) {
-		result = asus_backlight_init(&asus->platform_device->dev);
+		result = asus_backlight_init(asus);
 		if (result)
 			goto fail_backlight;
 	} else
 		pr_info("Backlight controlled by ACPI video driver\n");
 
-	result = asus_input_init(&asus->platform_device->dev);
+	result = asus_input_init(asus);
 	if (result)
 		goto fail_input;
 
-	result = asus_led_init(&asus->platform_device->dev);
+	result = asus_led_init(asus);
 	if (result)
 		goto fail_led;
 
@@ -1439,11 +1493,11 @@  static int __devinit asus_acpi_add(struct acpi_device *device)
 	return 0;
 
 fail_led:
-	asus_input_exit();
+	asus_input_exit(asus);
 fail_input:
-	asus_backlight_exit();
+	asus_backlight_exit(asus);
 fail_backlight:
-	asus_platform_exit();
+	asus_platform_exit(asus);
 fail_platform:
 	kfree(asus->name);
 	kfree(asus);
@@ -1453,10 +1507,12 @@  fail_platform:
 
 static int asus_acpi_remove(struct acpi_device *device, int type)
 {
-	asus_backlight_exit();
-	asus_led_exit();
-	asus_input_exit();
-	asus_platform_exit();
+	struct asus_laptop *asus = acpi_driver_data(device);
+
+	asus_backlight_exit(asus);
+	asus_led_exit(asus);
+	asus_input_exit(asus);
+	asus_platform_exit(asus);
 
 	kfree(asus->name);
 	kfree(asus);