Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit be4ee82d authored by Corentin Chary's avatar Corentin Chary
Browse files

asus-laptop: code movement



The asus-laptop driver implements a number of interfaces like the
backlight class driver.  This change makes it easier to examine the
implementation of one interface at at a time, without having to search
through the file to find init() and exit() functions etc.

Signed-off-by: default avatarCorentin Chary <corentincj@iksaif.net>
parent 9129d14d
Loading
Loading
Loading
Loading
+223 −217
Original line number Diff line number Diff line
@@ -58,36 +58,6 @@
#define ASUS_LAPTOP_FILE	KBUILD_MODNAME
#define ASUS_LAPTOP_PREFIX	"\\_SB.ATKD."


/*
 * Some events we use, same for all Asus
 */
#define ATKD_BR_UP	0x10
#define ATKD_BR_DOWN	0x20
#define ATKD_LCD_ON	0x33
#define ATKD_LCD_OFF	0x34

/*
 * Known bits returned by \_SB.ATKD.HWRS
 */
#define WL_HWRS		0x80
#define BT_HWRS		0x100

/*
 * Flags for hotk status
 * WL_ON and BT_ON are also used for wireless_status()
 */
#define WL_ON		0x01	/* internal Wifi */
#define BT_ON		0x02	/* internal Bluetooth */
#define MLED_ON		0x04	/* mail LED */
#define TLED_ON		0x08	/* touchpad LED */
#define RLED_ON		0x10	/* Record LED */
#define PLED_ON		0x20	/* Phone LED */
#define GLED_ON		0x40	/* Gaming LED */
#define LCD_ON		0x80	/* LCD backlight */
#define GPS_ON		0x100	/* GPS */
#define KEY_ON		0x200	/* Keyboard backlight */

MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
MODULE_DESCRIPTION(ASUS_LAPTOP_NAME);
MODULE_LICENSE("GPL");
@@ -119,6 +89,35 @@ MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
		 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
		 "default is 1");

/*
 * Some events we use, same for all Asus
 */
#define ATKD_BR_UP	0x10
#define ATKD_BR_DOWN	0x20
#define ATKD_LCD_ON	0x33
#define ATKD_LCD_OFF	0x34

/*
 * Known bits returned by \_SB.ATKD.HWRS
 */
#define WL_HWRS		0x80
#define BT_HWRS		0x100

/*
 * Flags for hotk status
 * WL_ON and BT_ON are also used for wireless_status()
 */
#define WL_ON		0x01	/* internal Wifi */
#define BT_ON		0x02	/* internal Bluetooth */
#define MLED_ON		0x04	/* mail LED */
#define TLED_ON		0x08	/* touchpad LED */
#define RLED_ON		0x10	/* Record LED */
#define PLED_ON		0x20	/* Phone LED */
#define GLED_ON		0x40	/* Gaming LED */
#define LCD_ON		0x80	/* LCD backlight */
#define GPS_ON		0x100	/* GPS */
#define KEY_ON		0x200	/* Keyboard backlight */

#define ASUS_HANDLE(object, paths...)					\
	static acpi_handle  object##_handle = NULL;			\
	static char *object##_paths[] = { paths }
@@ -249,36 +248,6 @@ struct asus_laptop {
	u16 *keycode_map;
};

/*
 * The backlight class declaration
 */
static int read_brightness(struct backlight_device *bd);
static int update_bl_status(struct backlight_device *bd);
static struct backlight_ops asusbl_ops = {
	.get_brightness = read_brightness,
	.update_status = update_bl_status,
};

#define ASUS_LED(object, ledname, max)					\
	static void object##_led_set(struct led_classdev *led_cdev,	\
				     enum led_brightness value);	\
	static enum led_brightness object##_led_get(			\
		struct led_classdev *led_cdev);				\
	static void object##_led_update(struct work_struct *ignored);	\
	static struct led_classdev object##_led = {			\
		.name           = "asus::" ledname,			\
		.brightness_set = object##_led_set,			\
		.brightness_get = object##_led_get,			\
		.max_brightness = max					\
	}

ASUS_LED(mled, "mail", 1);
ASUS_LED(tled, "touchpad", 1);
ASUS_LED(rled, "record", 1);
ASUS_LED(pled, "phone", 1);
ASUS_LED(gled, "gaming", 1);
ASUS_LED(kled, "kbd_backlight", 3);

struct key_entry {
	char type;
	u8 code;
@@ -427,6 +396,29 @@ static void write_status(struct asus_laptop *asus, acpi_handle handle,
		pr_warning(" write failed %x\n", mask);
}

/*
 * LEDs
 */
#define ASUS_LED(object, ledname, max)					\
	static void object##_led_set(struct led_classdev *led_cdev,	\
				     enum led_brightness value);	\
	static enum led_brightness object##_led_get(			\
		struct led_classdev *led_cdev);				\
	static void object##_led_update(struct work_struct *ignored);	\
	static struct led_classdev object##_led = {			\
		.name           = "asus::" ledname,			\
		.brightness_set = object##_led_set,			\
		.brightness_get = object##_led_get,			\
		.max_brightness = max					\
	}

ASUS_LED(mled, "mail", 1);
ASUS_LED(tled, "touchpad", 1);
ASUS_LED(rled, "record", 1);
ASUS_LED(pled, "phone", 1);
ASUS_LED(gled, "gaming", 1);
ASUS_LED(kled, "kbd_backlight", 3);

/* /sys/class/led handlers */
#define ASUS_LED_HANDLER(object, mask)					\
	static void object##_led_set(struct led_classdev *led_cdev,	\
@@ -459,7 +451,7 @@ ASUS_LED_HANDLER(tled, TLED_ON);
ASUS_LED_HANDLER(gled, GLED_ON);

/*
 * Keyboard backlight
 * Keyboard backlight (also a LED)
 */
static int get_kled_lvl(void)
{
@@ -516,6 +508,70 @@ static enum led_brightness kled_led_get(struct led_classdev *led_cdev)
	return get_kled_lvl();
}

#define ASUS_LED_UNREGISTER(object)				\
	if (object##_led.dev)					\
		led_classdev_unregister(&object##_led)

static void asus_led_exit(struct asus_laptop *asus)
{
	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;
	}
}

/*  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;

	/*
	 * 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.
	 */
	asus->leds.workqueue = create_singlethread_workqueue("led_workqueue");
	if (!asus->leds.workqueue)
		return -ENOMEM;

	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;
}

/*
 * Backlight device
 */
static int get_lcd_state(struct asus_laptop *asus)
{
	return read_status(asus, LCD_ON);
@@ -588,6 +644,41 @@ static int update_bl_status(struct backlight_device *bd)
	return set_lcd_state(asus, value);
}

static struct backlight_ops asusbl_ops = {
	.get_brightness = read_brightness,
	.update_status = update_bl_status,
};

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,
					       asus, &asusbl_ops);
		if (IS_ERR(bd)) {
			pr_err("Could not register asus backlight device\n");
			asus->backlight_device = NULL;
			return PTR_ERR(bd);
		}

		asus->backlight_device = bd;

		bd->props.max_brightness = 15;
		bd->props.brightness = read_brightness(NULL);
		bd->props.power = FB_BLANK_UNBLANK;
		backlight_update_status(bd);
	}
	return 0;
}

static void asus_backlight_exit(struct asus_laptop *asus)
{
	if (asus->backlight_device)
		backlight_device_unregister(asus->backlight_device);
}

/*
 * Platform device handlers
 */
@@ -904,7 +995,7 @@ static ssize_t store_gps(struct device *dev, struct device_attribute *attr,
}

/*
 * Hotkey functions
 * Input device (i.e. hotkeys)
 */
static struct key_entry *asus_get_entry_by_scancode(struct asus_laptop *asus,
						    int code)
@@ -965,10 +1056,72 @@ static int asus_setkeycode(struct input_dev *dev, int scancode, int keycode)
	return -EINVAL;
}

static void asus_input_notify(struct asus_laptop *asus, int event)
{
	struct key_entry *key;

	key = asus_get_entry_by_scancode(asus, event);
	if (!key)
		return ;

	switch (key->type) {
	case KE_KEY:
		input_report_key(asus->inputdev, key->keycode, 1);
		input_sync(asus->inputdev);
		input_report_key(asus->inputdev, key->keycode, 0);
		input_sync(asus->inputdev);
		break;
	}
}

static int asus_input_init(struct asus_laptop *asus)
{
	const struct key_entry *key;
	int result;

	asus->inputdev = input_allocate_device();
	if (!asus->inputdev) {
		pr_info("Unable to allocate input device\n");
		return 0;
	}
	asus->inputdev->name = "Asus Laptop extra buttons";
	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);

	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);
			set_bit(key->keycode, asus->inputdev->keybit);
			break;
		}
	}
	result = input_register_device(asus->inputdev);
	if (result) {
		pr_info("Unable to register input device\n");
		input_free_device(asus->inputdev);
	}
	return result;
}

static void asus_input_exit(struct asus_laptop *asus)
{
	if (asus->inputdev)
		input_unregister_device(asus->inputdev);
}

/*
 * ACPI driver
 */
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;

	/*
@@ -990,20 +1143,7 @@ static void asus_acpi_notify(struct acpi_device *device, u32 event)
					dev_name(&asus->device->dev), event,
					count);

	if (asus->inputdev) {
		key = asus_get_entry_by_scancode(asus, event);
		if (!key)
			return ;

		switch (key->type) {
		case KE_KEY:
			input_report_key(asus->inputdev, key->keycode, 1);
			input_sync(asus->inputdev);
			input_report_key(asus->inputdev, key->keycode, 0);
			input_sync(asus->inputdev);
			break;
		}
	}
	asus_input_notify(asus, event);
}

#define ASUS_CREATE_DEVICE_ATTR(_name)					\
@@ -1257,142 +1397,6 @@ static int asus_laptop_get_info(struct asus_laptop *asus)
	return AE_OK;
}

static int asus_input_init(struct asus_laptop *asus)
{
	const struct key_entry *key;
	int result;

	asus->inputdev = input_allocate_device();
	if (!asus->inputdev) {
		pr_info("Unable to allocate input device\n");
		return 0;
	}
	asus->inputdev->name = "Asus Laptop extra buttons";
	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);

	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);
			set_bit(key->keycode, asus->inputdev->keybit);
			break;
		}
	}
	result = input_register_device(asus->inputdev);
	if (result) {
		pr_info("Unable to register input device\n");
		input_free_device(asus->inputdev);
	}
	return result;
}

static void asus_backlight_exit(struct asus_laptop *asus)
{
	if (asus->backlight_device)
		backlight_device_unregister(asus->backlight_device);
}

#define ASUS_LED_UNREGISTER(object)				\
	if (object##_led.dev)					\
		led_classdev_unregister(&object##_led)

static void asus_led_exit(struct asus_laptop *asus)
{
	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(struct asus_laptop *asus)
{
	if (asus->inputdev)
		input_unregister_device(asus->inputdev);
}

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,
					       asus, &asusbl_ops);
		if (IS_ERR(bd)) {
			pr_err("Could not register asus backlight device\n");
			asus->backlight_device = NULL;
			return PTR_ERR(bd);
		}

		asus->backlight_device = bd;

		bd->props.max_brightness = 15;
		bd->props.brightness = read_brightness(NULL);
		bd->props.power = FB_BLANK_UNBLANK;
		backlight_update_status(bd);
	}
	return 0;
}

/*
 * 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;

	/*
	 * 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.
	 */
	asus->leds.workqueue = create_singlethread_workqueue("led_workqueue");
	if (!asus->leds.workqueue)
		return -ENOMEM;

	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 asus_laptop *asus)
@@ -1414,8 +1418,10 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
	asus_laptop_add_fs(asus);

	/* WLED and BLED are on by default */
	write_status(asus, bt_switch_handle, 1, BT_ON);
	write_status(asus, wl_switch_handle, 1, WL_ON);
	if (bluetooth_status >= 0)
		write_status(asus, bt_switch_handle, !!bluetooth_status, BT_ON);
	if (wireless_status >= 0)
		write_status(asus, wl_switch_handle, !!wireless_status, WL_ON);

	/* If the h/w switch is off, we need to check the real status */
	write_status(asus, NULL, read_status(asus, BT_ON), BT_ON);
@@ -1432,8 +1438,8 @@ static int __devinit asus_acpi_init(struct asus_laptop *asus)
	asus->ledd_status = 0xFFF;

	/* Set initial values of light sensor and level */
	hotk->light_switch = 0;	/* Default to light sensor disabled */
	hotk->light_level = 5;	/* level 5 for sensor sensitivity */
	asus->light_switch = 0;	/* Default to light sensor disabled */
	asus->light_level = 5;	/* level 5 for sensor sensitivity */

	if (ls_switch_handle)
		set_light_sens_switch(asus, asus->light_switch);