⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 asus-laptop.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *  asus-laptop.c - Asus Laptop Support * * *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor *  Copyright (C) 2006-2007 Corentin Chary * *  This program is free software; you can redistribute it and/or modify *  it under the terms of the GNU General Public License as published by *  the Free Software Foundation; either version 2 of the License, or *  (at your option) any later version. * *  This program is distributed in the hope that it will be useful, *  but WITHOUT ANY WARRANTY; without even the implied warranty of *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *  GNU General Public License for more details. * *  You should have received a copy of the GNU General Public License *  along with this program; if not, write to the Free Software *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA * * *  The development page for this driver is located at *  http://sourceforge.net/projects/acpi4asus/ * *  Credits: *  Pontus Fuchs   - Helper functions, cleanup *  Johann Wiesner - Small compile fixes *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point. *  Eric Burghard  - LED display support for W1N *  Josh Green     - Light Sens support *  Thomas Tuttle  - His first patch for led support was very helpfull *  Sam Lin        - GPS support */#include <linux/autoconf.h>#include <linux/kernel.h>#include <linux/module.h>#include <linux/init.h>#include <linux/types.h>#include <linux/err.h>#include <linux/proc_fs.h>#include <linux/backlight.h>#include <linux/fb.h>#include <linux/leds.h>#include <linux/platform_device.h>#include <acpi/acpi_drivers.h>#include <acpi/acpi_bus.h>#include <asm/uaccess.h>#define ASUS_LAPTOP_VERSION "0.42"#define ASUS_HOTK_NAME          "Asus Laptop Support"#define ASUS_HOTK_CLASS         "hotkey"#define ASUS_HOTK_DEVICE_NAME   "Hotkey"#define ASUS_HOTK_FILE          "asus-laptop"#define ASUS_HOTK_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 ASUS_LOG    ASUS_HOTK_FILE ": "#define ASUS_ERR    KERN_ERR    ASUS_LOG#define ASUS_WARNING    KERN_WARNING    ASUS_LOG#define ASUS_NOTICE KERN_NOTICE ASUS_LOG#define ASUS_INFO   KERN_INFO   ASUS_LOG#define ASUS_DEBUG  KERN_DEBUG  ASUS_LOGMODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");MODULE_DESCRIPTION(ASUS_HOTK_NAME);MODULE_LICENSE("GPL");/* WAPF defines the behavior of the Fn+Fx wlan key * The significance of values is yet to be found, but * most of the time: * 0x0 will do nothing * 0x1 will allow to control the device with Fn+Fx key. * 0x4 will send an ACPI event (0x88) while pressing the Fn+Fx key * 0x5 like 0x1 or 0x4 * So, if something doesn't work as you want, just try other values =) */static uint wapf = 1;module_param(wapf, uint, 0644);MODULE_PARM_DESC(wapf, "WAPF value");#define ASUS_HANDLE(object, paths...)					\	static acpi_handle  object##_handle = NULL;			\	static char *object##_paths[] = { paths }/* LED */ASUS_HANDLE(mled_set, ASUS_HOTK_PREFIX "MLED");ASUS_HANDLE(tled_set, ASUS_HOTK_PREFIX "TLED");ASUS_HANDLE(rled_set, ASUS_HOTK_PREFIX "RLED");	/* W1JC */ASUS_HANDLE(pled_set, ASUS_HOTK_PREFIX "PLED");	/* A7J */ASUS_HANDLE(gled_set, ASUS_HOTK_PREFIX "GLED");	/* G1, G2 (probably) *//* LEDD */ASUS_HANDLE(ledd_set, ASUS_HOTK_PREFIX "SLCM");/* Bluetooth and WLAN * WLED and BLED are not handled like other XLED, because in some dsdt * they also control the WLAN/Bluetooth device. */ASUS_HANDLE(wl_switch, ASUS_HOTK_PREFIX "WLED");ASUS_HANDLE(bt_switch, ASUS_HOTK_PREFIX "BLED");ASUS_HANDLE(wireless_status, ASUS_HOTK_PREFIX "RSTS");	/* All new models *//* Brightness */ASUS_HANDLE(brightness_set, ASUS_HOTK_PREFIX "SPLV");ASUS_HANDLE(brightness_get, ASUS_HOTK_PREFIX "GPLV");/* Backlight */ASUS_HANDLE(lcd_switch, "\\_SB.PCI0.SBRG.EC0._Q10",	/* All new models */	    "\\_SB.PCI0.ISA.EC0._Q10",	/* A1x */	    "\\_SB.PCI0.PX40.ECD0._Q10",	/* L3C */	    "\\_SB.PCI0.PX40.EC0.Q10",	/* M1A */	    "\\_SB.PCI0.LPCB.EC0._Q10",	/* P30 */	    "\\_SB.PCI0.PX40.Q10",	/* S1x */	    "\\Q10");		/* A2x, L2D, L3D, M2E *//* Display */ASUS_HANDLE(display_set, ASUS_HOTK_PREFIX "SDSP");ASUS_HANDLE(display_get, "\\_SB.PCI0.P0P1.VGA.GETD",	/*  A6B, A6K A6R A7D F3JM L4R M6R A3G							   M6A M6V VX-1 V6J V6V W3Z */	    "\\_SB.PCI0.P0P2.VGA.GETD",	/* A3E A4K, A4D A4L A6J A7J A8J Z71V M9V					   S5A M5A z33A W1Jc W2V G1 */	    "\\_SB.PCI0.P0P3.VGA.GETD",	/* A6V A6Q */	    "\\_SB.PCI0.P0PA.VGA.GETD",	/* A6T, A6M */	    "\\_SB.PCI0.PCI1.VGAC.NMAP",	/* L3C */	    "\\_SB.PCI0.VGA.GETD",	/* Z96F */	    "\\ACTD",		/* A2D */	    "\\ADVG",		/* A4G Z71A W1N W5A W5F M2N M3N M5N M6N S1N S5N */	    "\\DNXT",		/* P30 */	    "\\INFB",		/* A2H D1 L2D L3D L3H L2E L5D L5C M1A M2E L4L W3V */	    "\\SSTE");		/* A3F A6F A3N A3L M6N W3N W6A */ASUS_HANDLE(ls_switch, ASUS_HOTK_PREFIX "ALSC");	/* Z71A Z71V */ASUS_HANDLE(ls_level, ASUS_HOTK_PREFIX "ALSL");	/* Z71A Z71V *//* GPS *//* R2H use different handle for GPS on/off */ASUS_HANDLE(gps_on, ASUS_HOTK_PREFIX "SDON");	/* R2H */ASUS_HANDLE(gps_off, ASUS_HOTK_PREFIX "SDOF");	/* R2H */ASUS_HANDLE(gps_status, ASUS_HOTK_PREFIX "GPST");/* * This is the main structure, we can use it to store anything interesting * about the hotk device */struct asus_hotk {	char *name;		//laptop name	struct acpi_device *device;	//the device we are in	acpi_handle handle;	//the handle of the hotk device	char status;		//status of the hotk, for LEDs, ...	u32 ledd_status;	//status of the LED display	u8 light_level;		//light sensor level	u8 light_switch;	//light sensor switch value	u16 event_count[128];	//count for each event TODO make this better};/* * This header is made available to allow proper configuration given model, * revision number , ... this info cannot go in struct asus_hotk because it is * available before the hotk */static struct acpi_table_header *asus_info;/* The actual device the driver binds to */static struct asus_hotk *hotk;/* * The hotkey driver declaration */static const struct acpi_device_id asus_device_ids[] = {	{"ATK0100", 0},	{"", 0},};MODULE_DEVICE_TABLE(acpi, asus_device_ids);static int asus_hotk_add(struct acpi_device *device);static int asus_hotk_remove(struct acpi_device *device, int type);static struct acpi_driver asus_hotk_driver = {	.name = ASUS_HOTK_NAME,	.class = ASUS_HOTK_CLASS,	.ids = asus_device_ids,	.ops = {		.add = asus_hotk_add,		.remove = asus_hotk_remove,		},};/* The backlight device /sys/class/backlight */static struct backlight_device *asus_backlight_device;/* * 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,};/* These functions actually update the LED's, and 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. */static struct workqueue_struct *led_workqueue;#define ASUS_LED(object, ledname)					\	static void object##_led_set(struct led_classdev *led_cdev,	\				     enum led_brightness value);	\	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,			\	}ASUS_LED(mled, "mail");ASUS_LED(tled, "touchpad");ASUS_LED(rled, "record");ASUS_LED(pled, "phone");ASUS_LED(gled, "gaming");/* * This function evaluates an ACPI method, given an int as parameter, the * method is searched within the scope of the handle, can be NULL. The output * of the method is written is output, which can also be NULL * * returns 1 if write is successful, 0 else. */static int write_acpi_int(acpi_handle handle, const char *method, int val,			  struct acpi_buffer *output){	struct acpi_object_list params;	//list of input parameters (an int here)	union acpi_object in_obj;	//the only param we use	acpi_status status;	params.count = 1;	params.pointer = &in_obj;	in_obj.type = ACPI_TYPE_INTEGER;	in_obj.integer.value = val;	status = acpi_evaluate_object(handle, (char *)method, &params, output);	return (status == AE_OK);}static int read_wireless_status(int mask){	ulong status;	acpi_status rv = AE_OK;	if (!wireless_status_handle)		return (hotk->status & mask) ? 1 : 0;	rv = acpi_evaluate_integer(wireless_status_handle, NULL, NULL, &status);	if (ACPI_FAILURE(rv))		printk(ASUS_WARNING "Error reading Wireless status\n");	else		return (status & mask) ? 1 : 0;	return (hotk->status & mask) ? 1 : 0;}static int read_gps_status(void){	ulong status;	acpi_status rv = AE_OK;	rv = acpi_evaluate_integer(gps_status_handle, NULL, NULL, &status);	if (ACPI_FAILURE(rv))		printk(ASUS_WARNING "Error reading GPS status\n");	else		return status ? 1 : 0;	return (hotk->status & GPS_ON) ? 1 : 0;}/* Generic LED functions */static int read_status(int mask){	/* There is a special method for both wireless devices */	if (mask == BT_ON || mask == WL_ON)		return read_wireless_status(mask);	else if (mask == GPS_ON)		return read_gps_status();	return (hotk->status & mask) ? 1 : 0;}static void write_status(acpi_handle handle, int out, int mask){	hotk->status = (out) ? (hotk->status | mask) : (hotk->status & ~mask);	switch (mask) {	case MLED_ON:		out = !out & 0x1;		break;	case GLED_ON:		out = (out & 0x1) + 1;		break;	case GPS_ON:		handle = (out) ? gps_on_handle : gps_off_handle;		out = 0x02;		break;	default:		out &= 0x1;		break;	}	if (handle && !write_acpi_int(handle, NULL, out, NULL))		printk(ASUS_WARNING " write failed %x\n", mask);}/* /sys/class/led handlers */#define ASUS_LED_HANDLER(object, mask)					\	static void object##_led_set(struct led_classdev *led_cdev,	\				     enum led_brightness value)		\	{								\		object##_led_wk = value;				\		queue_work(led_workqueue, &object##_led_work);		\	}								\	static void object##_led_update(struct work_struct *ignored)	\	{								\		int value = object##_led_wk;				\		write_status(object##_set_handle, value, (mask));	\	}ASUS_LED_HANDLER(mled, MLED_ON);ASUS_LED_HANDLER(pled, PLED_ON);ASUS_LED_HANDLER(rled, RLED_ON);ASUS_LED_HANDLER(tled, TLED_ON);ASUS_LED_HANDLER(gled, GLED_ON);static int get_lcd_state(void){	return read_status(LCD_ON);}static int set_lcd_state(int value){	int lcd = 0;	acpi_status status = 0;	lcd = value ? 1 : 0;	if (lcd == get_lcd_state())		return 0;	if (lcd_switch_handle) {		status = acpi_evaluate_object(lcd_switch_handle,					      NULL, NULL, NULL);		if (ACPI_FAILURE(status))			printk(ASUS_WARNING "Error switching LCD\n");	}	write_status(NULL, lcd, LCD_ON);	return 0;}static void lcd_blank(int blank){	struct backlight_device *bd = asus_backlight_device;	if (bd) {		bd->props.power = blank;		backlight_update_status(bd);	}}static int read_brightness(struct backlight_device *bd){	ulong value;	acpi_status rv = AE_OK;	rv = acpi_evaluate_integer(brightness_get_handle, NULL, NULL, &value);	if (ACPI_FAILURE(rv))		printk(ASUS_WARNING "Error reading brightness\n");	return value;}static int set_brightness(struct backlight_device *bd, int value){	int ret = 0;	value = (0 < value) ? ((15 < value) ? 15 : value) : 0;	/* 0 <= value <= 15 */	if (!write_acpi_int(brightness_set_handle, NULL, value, NULL)) {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -