thinkpad_acpi.c

来自「linux 内核源代码」· C语言 代码 · 共 2,636 行 · 第 1/5 页

C
2,636
字号
static struct platform_device *tpacpi_sensors_pdev;static struct device *tpacpi_hwmon;static struct input_dev *tpacpi_inputdev;static struct mutex tpacpi_inputdev_send_mutex;static int tpacpi_resume_handler(struct platform_device *pdev){	struct ibm_struct *ibm, *itmp;	list_for_each_entry_safe(ibm, itmp,				 &tpacpi_all_drivers,				 all_drivers) {		if (ibm->resume)			(ibm->resume)();	}	return 0;}static struct platform_driver tpacpi_pdriver = {	.driver = {		.name = IBM_DRVR_NAME,		.owner = THIS_MODULE,	},	.resume = tpacpi_resume_handler,};static struct platform_driver tpacpi_hwmon_pdriver = {	.driver = {		.name = IBM_HWMON_DRVR_NAME,		.owner = THIS_MODULE,	},};/************************************************************************* * thinkpad-acpi driver attributes *//* interface_version --------------------------------------------------- */static ssize_t tpacpi_driver_interface_version_show(				struct device_driver *drv,				char *buf){	return snprintf(buf, PAGE_SIZE, "0x%08x\n", TPACPI_SYSFS_VERSION);}static DRIVER_ATTR(interface_version, S_IRUGO,		tpacpi_driver_interface_version_show, NULL);/* debug_level --------------------------------------------------------- */static ssize_t tpacpi_driver_debug_show(struct device_driver *drv,						char *buf){	return snprintf(buf, PAGE_SIZE, "0x%04x\n", dbg_level);}static ssize_t tpacpi_driver_debug_store(struct device_driver *drv,						const char *buf, size_t count){	unsigned long t;	if (parse_strtoul(buf, 0xffff, &t))		return -EINVAL;	dbg_level = t;	return count;}static DRIVER_ATTR(debug_level, S_IWUSR | S_IRUGO,		tpacpi_driver_debug_show, tpacpi_driver_debug_store);/* version ------------------------------------------------------------- */static ssize_t tpacpi_driver_version_show(struct device_driver *drv,						char *buf){	return snprintf(buf, PAGE_SIZE, "%s v%s\n", IBM_DESC, IBM_VERSION);}static DRIVER_ATTR(version, S_IRUGO,		tpacpi_driver_version_show, NULL);/* --------------------------------------------------------------------- */static struct driver_attribute* tpacpi_driver_attributes[] = {	&driver_attr_debug_level, &driver_attr_version,	&driver_attr_interface_version,};static int __init tpacpi_create_driver_attributes(struct device_driver *drv){	int i, res;	i = 0;	res = 0;	while (!res && i < ARRAY_SIZE(tpacpi_driver_attributes)) {		res = driver_create_file(drv, tpacpi_driver_attributes[i]);		i++;	}	return res;}static void tpacpi_remove_driver_attributes(struct device_driver *drv){	int i;	for(i = 0; i < ARRAY_SIZE(tpacpi_driver_attributes); i++)		driver_remove_file(drv, tpacpi_driver_attributes[i]);}/************************************************************************* * sysfs support helpers */struct attribute_set_obj {	struct attribute_set s;	struct attribute *a;} __attribute__((packed));static struct attribute_set *create_attr_set(unsigned int max_members,						const char* name){	struct attribute_set_obj *sobj;	if (max_members == 0)		return NULL;	/* Allocates space for implicit NULL at the end too */	sobj = kzalloc(sizeof(struct attribute_set_obj) +		    max_members * sizeof(struct attribute *),		    GFP_KERNEL);	if (!sobj)		return NULL;	sobj->s.max_members = max_members;	sobj->s.group.attrs = &sobj->a;	sobj->s.group.name = name;	return &sobj->s;}/* not multi-threaded safe, use it in a single thread per set */static int add_to_attr_set(struct attribute_set* s, struct attribute *attr){	if (!s || !attr)		return -EINVAL;	if (s->members >= s->max_members)		return -ENOMEM;	s->group.attrs[s->members] = attr;	s->members++;	return 0;}static int add_many_to_attr_set(struct attribute_set* s,			struct attribute **attr,			unsigned int count){	int i, res;	for (i = 0; i < count; i++) {		res = add_to_attr_set(s, attr[i]);		if (res)			return res;	}	return 0;}static void delete_attr_set(struct attribute_set* s, struct kobject *kobj){	sysfs_remove_group(kobj, &s->group);	destroy_attr_set(s);}static int parse_strtoul(const char *buf,		unsigned long max, unsigned long *value){	char *endp;	while (*buf && isspace(*buf))		buf++;	*value = simple_strtoul(buf, &endp, 0);	while (*endp && isspace(*endp))		endp++;	if (*endp || *value > max)		return -EINVAL;	return 0;}/**************************************************************************** **************************************************************************** * * Subdrivers * **************************************************************************** ****************************************************************************//************************************************************************* * thinkpad-acpi init subdriver */static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm){	printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);	printk(IBM_INFO "%s\n", IBM_URL);	printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",		(thinkpad_id.bios_version_str) ?			thinkpad_id.bios_version_str : "unknown",		(thinkpad_id.ec_version_str) ?			thinkpad_id.ec_version_str : "unknown");	if (thinkpad_id.vendor && thinkpad_id.model_str)		printk(IBM_INFO "%s %s\n",			(thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?				"IBM" : ((thinkpad_id.vendor ==						PCI_VENDOR_ID_LENOVO) ?					"Lenovo" : "Unknown vendor"),			thinkpad_id.model_str);	return 0;}static int thinkpad_acpi_driver_read(char *p){	int len = 0;	len += sprintf(p + len, "driver:\t\t%s\n", IBM_DESC);	len += sprintf(p + len, "version:\t%s\n", IBM_VERSION);	return len;}static struct ibm_struct thinkpad_acpi_driver_data = {	.name = "driver",	.read = thinkpad_acpi_driver_read,};/************************************************************************* * Hotkey subdriver */static int hotkey_orig_status;static u32 hotkey_orig_mask;static u32 hotkey_all_mask;static u32 hotkey_reserved_mask;static u16 *hotkey_keycode_map;static struct attribute_set *hotkey_dev_attributes;static int hotkey_get_wlsw(int *status){	if (!acpi_evalf(hkey_handle, status, "WLSW", "d"))		return -EIO;	return 0;}/* sysfs hotkey enable ------------------------------------------------- */static ssize_t hotkey_enable_show(struct device *dev,			   struct device_attribute *attr,			   char *buf){	int res, status;	u32 mask;	res = hotkey_get(&status, &mask);	if (res)		return res;	return snprintf(buf, PAGE_SIZE, "%d\n", status);}static ssize_t hotkey_enable_store(struct device *dev,			    struct device_attribute *attr,			    const char *buf, size_t count){	unsigned long t;	int res, status;	u32 mask;	if (parse_strtoul(buf, 1, &t))		return -EINVAL;	res = hotkey_get(&status, &mask);	if (!res)		res = hotkey_set(t, mask);	return (res) ? res : count;}static struct device_attribute dev_attr_hotkey_enable =	__ATTR(hotkey_enable, S_IWUSR | S_IRUGO,		hotkey_enable_show, hotkey_enable_store);/* sysfs hotkey mask --------------------------------------------------- */static ssize_t hotkey_mask_show(struct device *dev,			   struct device_attribute *attr,			   char *buf){	int res, status;	u32 mask;	res = hotkey_get(&status, &mask);	if (res)		return res;	return snprintf(buf, PAGE_SIZE, "0x%08x\n", mask);}static ssize_t hotkey_mask_store(struct device *dev,			    struct device_attribute *attr,			    const char *buf, size_t count){	unsigned long t;	int res, status;	u32 mask;	if (parse_strtoul(buf, 0xffffffffUL, &t))		return -EINVAL;	res = hotkey_get(&status, &mask);	if (!res)		hotkey_set(status, t);	return (res) ? res : count;}static struct device_attribute dev_attr_hotkey_mask =	__ATTR(hotkey_mask, S_IWUSR | S_IRUGO,		hotkey_mask_show, hotkey_mask_store);/* sysfs hotkey bios_enabled ------------------------------------------- */static ssize_t hotkey_bios_enabled_show(struct device *dev,			   struct device_attribute *attr,			   char *buf){	return snprintf(buf, PAGE_SIZE, "%d\n", hotkey_orig_status);}static struct device_attribute dev_attr_hotkey_bios_enabled =	__ATTR(hotkey_bios_enabled, S_IRUGO, hotkey_bios_enabled_show, NULL);/* sysfs hotkey bios_mask ---------------------------------------------- */static ssize_t hotkey_bios_mask_show(struct device *dev,			   struct device_attribute *attr,			   char *buf){	return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_orig_mask);}static struct device_attribute dev_attr_hotkey_bios_mask =	__ATTR(hotkey_bios_mask, S_IRUGO, hotkey_bios_mask_show, NULL);/* sysfs hotkey all_mask ----------------------------------------------- */static ssize_t hotkey_all_mask_show(struct device *dev,			   struct device_attribute *attr,			   char *buf){	return snprintf(buf, PAGE_SIZE, "0x%08x\n", hotkey_all_mask);}static struct device_attribute dev_attr_hotkey_all_mask =	__ATTR(hotkey_all_mask, S_IRUGO, hotkey_all_mask_show, NULL);/* sysfs hotkey recommended_mask --------------------------------------- */static ssize_t hotkey_recommended_mask_show(struct device *dev,					    struct device_attribute *attr,					    char *buf){	return snprintf(buf, PAGE_SIZE, "0x%08x\n",			hotkey_all_mask & ~hotkey_reserved_mask);}static struct device_attribute dev_attr_hotkey_recommended_mask =	__ATTR(hotkey_recommended_mask, S_IRUGO,		hotkey_recommended_mask_show, NULL);/* sysfs hotkey radio_sw ----------------------------------------------- */static ssize_t hotkey_radio_sw_show(struct device *dev,			   struct device_attribute *attr,			   char *buf){	int res, s;	res = hotkey_get_wlsw(&s);	if (res < 0)		return res;	return snprintf(buf, PAGE_SIZE, "%d\n", !!s);}static struct device_attribute dev_attr_hotkey_radio_sw =	__ATTR(hotkey_radio_sw, S_IRUGO, hotkey_radio_sw_show, NULL);/* sysfs hotkey report_mode -------------------------------------------- */static ssize_t hotkey_report_mode_show(struct device *dev,			   struct device_attribute *attr,			   char *buf){	return snprintf(buf, PAGE_SIZE, "%d\n",		(hotkey_report_mode != 0) ? hotkey_report_mode : 1);}static struct device_attribute dev_attr_hotkey_report_mode =	__ATTR(hotkey_report_mode, S_IRUGO, hotkey_report_mode_show, NULL);/* --------------------------------------------------------------------- */static struct attribute *hotkey_attributes[] __initdata = {	&dev_attr_hotkey_enable.attr,	&dev_attr_hotkey_report_mode.attr,};static struct attribute *hotkey_mask_attributes[] __initdata = {	&dev_attr_hotkey_mask.attr,	&dev_attr_hotkey_bios_enabled.attr,	&dev_attr_hotkey_bios_mask.attr,	&dev_attr_hotkey_all_mask.attr,	&dev_attr_hotkey_recommended_mask.attr,};static int __init hotkey_init(struct ibm_init_struct *iibm){	static u16 ibm_keycode_map[] __initdata = {		/* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */		KEY_FN_F1,	KEY_FN_F2,	KEY_COFFEE,	KEY_SLEEP,		KEY_WLAN,	KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,		KEY_FN_F9,	KEY_FN_F10,	KEY_FN_F11,	KEY_SUSPEND,		/* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */		KEY_UNKNOWN,	/* 0x0C: FN+BACKSPACE */		KEY_UNKNOWN,	/* 0x0D: FN+INSERT */		KEY_UNKNOWN,	/* 0x0E: FN+DELETE */		KEY_RESERVED,	/* 0x0F: FN+HOME (brightness up) */		/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */		KEY_RESERVED,	/* 0x10: FN+END (brightness down) */		KEY_RESERVED,	/* 0x11: FN+PGUP (thinklight toggle) */		KEY_UNKNOWN,	/* 0x12: FN+PGDOWN */		KEY_ZOOM,	/* 0x13: FN+SPACE (zoom) */		KEY_RESERVED,	/* 0x14: VOLUME UP */		KEY_RESERVED,	/* 0x15: VOLUME DOWN */		KEY_RESERVED,	/* 0x16: MUTE */		KEY_VENDOR,	/* 0x17: Thinkpad/AccessIBM/Lenovo */		/* (assignments unknown, please report if found) */		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,	};	static u16 lenovo_keycode_map[] __initdata = {		/* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */		KEY_FN_F1,	KEY_COFFEE,	KEY_BATTERY,	KEY_SLEEP,		KEY_WLAN,	KEY_FN_F6, KEY_SWITCHVIDEOMODE, KEY_FN_F8,		KEY_FN_F9,	KEY_FN_F10,	KEY_FN_F11,	KEY_SUSPEND,		/* Scan codes 0x0C to 0x0F: Other ACPI HKEY hot keys */		KEY_UNKNOWN,	/* 0x0C: FN+BACKSPACE */		KEY_UNKNOWN,	/* 0x0D: FN+INSERT */		KEY_UNKNOWN,	/* 0x0E: FN+DELETE */		KEY_RESERVED,	/* 0x0F: FN+HOME (brightness up) */		/* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */		KEY_RESERVED,	/* 0x10: FN+END (brightness down) */		KEY_RESERVED,	/* 0x11: FN+PGUP (thinklight toggle) */		KEY_UNKNOWN,	/* 0x12: FN+PGDOWN */		KEY_ZOOM,	/* 0x13: FN+SPACE (zoom) */		KEY_RESERVED,	/* 0x14: VOLUME UP */		KEY_RESERVED,	/* 0x15: VOLUME DOWN */		KEY_RESERVED,	/* 0x16: MUTE */		KEY_VENDOR,	/* 0x17: Thinkpad/AccessIBM/Lenovo */		/* (assignments unknown, please report if found) */		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,		KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN, KEY_UNKNOWN,	};#define TPACPI_HOTKEY_MAP_LEN		ARRAY_SIZE(ibm_keycode_map)#define TPACPI_HOTKEY_MAP_SIZE		sizeof(ibm_keycode_map)#define TPACPI_HOTKEY_MAP_TYPESIZE	sizeof(ibm_keycode_map[0])	int res, i;	int status;	int hkeyv;	vdbg_printk(TPACPI_DBG_INIT, "initializing hotkey subdriver\n");	BUG_ON(!tpacpi_inputdev);	IBM_ACPIHANDLE_INIT(hkey);	mutex_init(&hotkey_mutex);	/* hotkey not supported on 570 */	tp_features.hotkey = hkey_handle != NULL;	vdbg_printk(TPACPI_DBG_INIT, "hotkeys are %s\n",		str_supported(tp_features.hotkey));	if (tp_features.hotkey) {		hotkey_dev_attributes = create_attr_set(8, NULL);		if (!hotkey_dev_attributes)			return -ENOMEM;		res = add_many_to_attr_set(hotkey_dev_attributes,				hotkey_attributes,				ARRAY_SIZE(hotkey_attributes));		if (res)			return res;		/* mask not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p,		   A30, R30, R31, T20-22, X20-21, X22-24.  Detected by checking		   for HKEY interface version 0x100 */		if (acpi_evalf(hkey_handle, &hkeyv, "MHKV", "qd")) {			if ((hkeyv >> 8) != 1) {				printk(IBM_ERR "unknown version of the "				       "HKEY interface: 0x%x\n", hkeyv);				printk(IBM_ERR "please report this to %s\n",				       IBM_MAIL);			} else {				/*				 * MHKV 0x100 in A31, R40, R40e,				 * T4x, X31, and later				 * */				tp_features.hotkey_mask = 1;			}		}		vdbg_printk(TPACPI_DBG_INIT, "hotkey masks are %s\n",			str_supported(tp_features.hotkey_mask));

⌨️ 快捷键说明

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