thinkpad_acpi.c

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

C
2,636
字号
	return 0;}static struct ibm_struct bluetooth_driver_data = {	.name = "bluetooth",	.read = bluetooth_read,	.write = bluetooth_write,	.exit = bluetooth_exit,};/************************************************************************* * Wan subdriver *//* sysfs wan enable ---------------------------------------------------- */static ssize_t wan_enable_show(struct device *dev,			   struct device_attribute *attr,			   char *buf){	int status;	status = wan_get_radiosw();	if (status < 0)		return status;	return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);}static ssize_t wan_enable_store(struct device *dev,			    struct device_attribute *attr,			    const char *buf, size_t count){	unsigned long t;	int res;	if (parse_strtoul(buf, 1, &t))		return -EINVAL;	res = wan_set_radiosw(t);	return (res) ? res : count;}static struct device_attribute dev_attr_wan_enable =	__ATTR(wwan_enable, S_IWUSR | S_IRUGO,		wan_enable_show, wan_enable_store);/* --------------------------------------------------------------------- */static struct attribute *wan_attributes[] = {	&dev_attr_wan_enable.attr,	NULL};static const struct attribute_group wan_attr_group = {	.attrs = wan_attributes,};static int __init wan_init(struct ibm_init_struct *iibm){	int res;	int status = 0;	vdbg_printk(TPACPI_DBG_INIT, "initializing wan subdriver\n");	IBM_ACPIHANDLE_INIT(hkey);	tp_features.wan = hkey_handle &&	    acpi_evalf(hkey_handle, &status, "GWAN", "qd");	vdbg_printk(TPACPI_DBG_INIT, "wan is %s, status 0x%02x\n",		str_supported(tp_features.wan),		status);	if (tp_features.wan) {		if (!(status & TP_ACPI_WANCARD_HWPRESENT)) {			/* no wan hardware present in system */			tp_features.wan = 0;			dbg_printk(TPACPI_DBG_INIT,				   "wan hardware not installed\n");		} else {			res = sysfs_create_group(&tpacpi_pdev->dev.kobj,					&wan_attr_group);			if (res)				return res;		}	}	return (tp_features.wan)? 0 : 1;}static void wan_exit(void){	sysfs_remove_group(&tpacpi_pdev->dev.kobj,		&wan_attr_group);}static int wan_get_radiosw(void){	int status;	if (!tp_features.wan)		return -ENODEV;	if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))		return -EIO;	return ((status & TP_ACPI_WANCARD_RADIOSSW) != 0);}static int wan_set_radiosw(int radio_on){	int status;	if (!tp_features.wan)		return -ENODEV;	if (!acpi_evalf(hkey_handle, &status, "GWAN", "d"))		return -EIO;	if (radio_on)		status |= TP_ACPI_WANCARD_RADIOSSW;	else		status &= ~TP_ACPI_WANCARD_RADIOSSW;	if (!acpi_evalf(hkey_handle, NULL, "SWAN", "vd", status))		return -EIO;	return 0;}/* procfs -------------------------------------------------------------- */static int wan_read(char *p){	int len = 0;	int status = wan_get_radiosw();	if (!tp_features.wan)		len += sprintf(p + len, "status:\t\tnot supported\n");	else {		len += sprintf(p + len, "status:\t\t%s\n",				(status)? "enabled" : "disabled");		len += sprintf(p + len, "commands:\tenable, disable\n");	}	return len;}static int wan_write(char *buf){	char *cmd;	if (!tp_features.wan)		return -ENODEV;	while ((cmd = next_cmd(&buf))) {		if (strlencmp(cmd, "enable") == 0) {			wan_set_radiosw(1);		} else if (strlencmp(cmd, "disable") == 0) {			wan_set_radiosw(0);		} else			return -EINVAL;	}	return 0;}static struct ibm_struct wan_driver_data = {	.name = "wan",	.read = wan_read,	.write = wan_write,	.exit = wan_exit,	.flags.experimental = 1,};/************************************************************************* * Video subdriver */static enum video_access_mode video_supported;static int video_orig_autosw;IBM_HANDLE(vid, root, "\\_SB.PCI.AGP.VGA",	/* 570 */	   "\\_SB.PCI0.AGP0.VID0",	/* 600e/x, 770x */	   "\\_SB.PCI0.VID0",	/* 770e */	   "\\_SB.PCI0.VID",	/* A21e, G4x, R50e, X30, X40 */	   "\\_SB.PCI0.AGP.VID",	/* all others */	   );				/* R30, R31 */IBM_HANDLE(vid2, root, "\\_SB.PCI0.AGPB.VID");	/* G41 */static int __init video_init(struct ibm_init_struct *iibm){	int ivga;	vdbg_printk(TPACPI_DBG_INIT, "initializing video subdriver\n");	IBM_ACPIHANDLE_INIT(vid);	IBM_ACPIHANDLE_INIT(vid2);	if (vid2_handle && acpi_evalf(NULL, &ivga, "\\IVGA", "d") && ivga)		/* G41, assume IVGA doesn't change */		vid_handle = vid2_handle;	if (!vid_handle)		/* video switching not supported on R30, R31 */		video_supported = TPACPI_VIDEO_NONE;	else if (acpi_evalf(vid_handle, &video_orig_autosw, "SWIT", "qd"))		/* 570 */		video_supported = TPACPI_VIDEO_570;	else if (acpi_evalf(vid_handle, &video_orig_autosw, "^VADL", "qd"))		/* 600e/x, 770e, 770x */		video_supported = TPACPI_VIDEO_770;	else		/* all others */		video_supported = TPACPI_VIDEO_NEW;	vdbg_printk(TPACPI_DBG_INIT, "video is %s, mode %d\n",		str_supported(video_supported != TPACPI_VIDEO_NONE),		video_supported);	return (video_supported != TPACPI_VIDEO_NONE)? 0 : 1;}static void video_exit(void){	dbg_printk(TPACPI_DBG_EXIT,		   "restoring original video autoswitch mode\n");	if (video_autosw_set(video_orig_autosw))		printk(IBM_ERR "error while trying to restore original "			"video autoswitch mode\n");}static int video_outputsw_get(void){	int status = 0;	int i;	switch (video_supported) {	case TPACPI_VIDEO_570:		if (!acpi_evalf(NULL, &i, "\\_SB.PHS", "dd",				 TP_ACPI_VIDEO_570_PHSCMD))			return -EIO;		status = i & TP_ACPI_VIDEO_570_PHSMASK;		break;	case TPACPI_VIDEO_770:		if (!acpi_evalf(NULL, &i, "\\VCDL", "d"))			return -EIO;		if (i)			status |= TP_ACPI_VIDEO_S_LCD;		if (!acpi_evalf(NULL, &i, "\\VCDC", "d"))			return -EIO;		if (i)			status |= TP_ACPI_VIDEO_S_CRT;		break;	case TPACPI_VIDEO_NEW:		if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 1) ||		    !acpi_evalf(NULL, &i, "\\VCDC", "d"))			return -EIO;		if (i)			status |= TP_ACPI_VIDEO_S_CRT;		if (!acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0) ||		    !acpi_evalf(NULL, &i, "\\VCDL", "d"))			return -EIO;		if (i)			status |= TP_ACPI_VIDEO_S_LCD;		if (!acpi_evalf(NULL, &i, "\\VCDD", "d"))			return -EIO;		if (i)			status |= TP_ACPI_VIDEO_S_DVI;		break;	default:		return -ENOSYS;	}	return status;}static int video_outputsw_set(int status){	int autosw;	int res = 0;	switch (video_supported) {	case TPACPI_VIDEO_570:		res = acpi_evalf(NULL, NULL,				 "\\_SB.PHS2", "vdd",				 TP_ACPI_VIDEO_570_PHS2CMD,				 status | TP_ACPI_VIDEO_570_PHS2SET);		break;	case TPACPI_VIDEO_770:		autosw = video_autosw_get();		if (autosw < 0)			return autosw;		res = video_autosw_set(1);		if (res)			return res;		res = acpi_evalf(vid_handle, NULL,				 "ASWT", "vdd", status * 0x100, 0);		if (!autosw && video_autosw_set(autosw)) {			printk(IBM_ERR "video auto-switch left enabled due to error\n");			return -EIO;		}		break;	case TPACPI_VIDEO_NEW:		res = acpi_evalf(NULL, NULL, "\\VUPS", "vd", 0x80) &&			acpi_evalf(NULL, NULL, "\\VSDS", "vdd", status, 1);		break;	default:		return -ENOSYS;	}	return (res)? 0 : -EIO;}static int video_autosw_get(void){	int autosw = 0;	switch (video_supported) {	case TPACPI_VIDEO_570:		if (!acpi_evalf(vid_handle, &autosw, "SWIT", "d"))			return -EIO;		break;	case TPACPI_VIDEO_770:	case TPACPI_VIDEO_NEW:		if (!acpi_evalf(vid_handle, &autosw, "^VDEE", "d"))			return -EIO;		break;	default:		return -ENOSYS;	}	return autosw & 1;}static int video_autosw_set(int enable){	if (!acpi_evalf(vid_handle, NULL, "_DOS", "vd", (enable)? 1 : 0))		return -EIO;	return 0;}static int video_outputsw_cycle(void){	int autosw = video_autosw_get();	int res;	if (autosw < 0)		return autosw;	switch (video_supported) {	case TPACPI_VIDEO_570:		res = video_autosw_set(1);		if (res)			return res;		res = acpi_evalf(ec_handle, NULL, "_Q16", "v");		break;	case TPACPI_VIDEO_770:	case TPACPI_VIDEO_NEW:		res = video_autosw_set(1);		if (res)			return res;		res = acpi_evalf(vid_handle, NULL, "VSWT", "v");		break;	default:		return -ENOSYS;	}	if (!autosw && video_autosw_set(autosw)) {		printk(IBM_ERR "video auto-switch left enabled due to error\n");		return -EIO;	}	return (res)? 0 : -EIO;}static int video_expand_toggle(void){	switch (video_supported) {	case TPACPI_VIDEO_570:		return acpi_evalf(ec_handle, NULL, "_Q17", "v")?			0 : -EIO;	case TPACPI_VIDEO_770:		return acpi_evalf(vid_handle, NULL, "VEXP", "v")?			0 : -EIO;	case TPACPI_VIDEO_NEW:		return acpi_evalf(NULL, NULL, "\\VEXP", "v")?			0 : -EIO;	default:		return -ENOSYS;	}	/* not reached */}static int video_read(char *p){	int status, autosw;	int len = 0;	if (video_supported == TPACPI_VIDEO_NONE) {		len += sprintf(p + len, "status:\t\tnot supported\n");		return len;	}	status = video_outputsw_get();	if (status < 0)		return status;	autosw = video_autosw_get();	if (autosw < 0)		return autosw;	len += sprintf(p + len, "status:\t\tsupported\n");	len += sprintf(p + len, "lcd:\t\t%s\n", enabled(status, 0));	len += sprintf(p + len, "crt:\t\t%s\n", enabled(status, 1));	if (video_supported == TPACPI_VIDEO_NEW)		len += sprintf(p + len, "dvi:\t\t%s\n", enabled(status, 3));	len += sprintf(p + len, "auto:\t\t%s\n", enabled(autosw, 0));	len += sprintf(p + len, "commands:\tlcd_enable, lcd_disable\n");	len += sprintf(p + len, "commands:\tcrt_enable, crt_disable\n");	if (video_supported == TPACPI_VIDEO_NEW)		len += sprintf(p + len, "commands:\tdvi_enable, dvi_disable\n");	len += sprintf(p + len, "commands:\tauto_enable, auto_disable\n");	len += sprintf(p + len, "commands:\tvideo_switch, expand_toggle\n");	return len;}static int video_write(char *buf){	char *cmd;	int enable, disable, status;	int res;	if (video_supported == TPACPI_VIDEO_NONE)		return -ENODEV;	enable = 0;	disable = 0;	while ((cmd = next_cmd(&buf))) {		if (strlencmp(cmd, "lcd_enable") == 0) {			enable |= TP_ACPI_VIDEO_S_LCD;		} else if (strlencmp(cmd, "lcd_disable") == 0) {			disable |= TP_ACPI_VIDEO_S_LCD;		} else if (strlencmp(cmd, "crt_enable") == 0) {			enable |= TP_ACPI_VIDEO_S_CRT;		} else if (strlencmp(cmd, "crt_disable") == 0) {			disable |= TP_ACPI_VIDEO_S_CRT;		} else if (video_supported == TPACPI_VIDEO_NEW &&			   strlencmp(cmd, "dvi_enable") == 0) {			enable |= TP_ACPI_VIDEO_S_DVI;		} else if (video_supported == TPACPI_VIDEO_NEW &&			   strlencmp(cmd, "dvi_disable") == 0) {			disable |= TP_ACPI_VIDEO_S_DVI;		} else if (strlencmp(cmd, "auto_enable") == 0) {			res = video_autosw_set(1);			if (res)				return res;		} else if (strlencmp(cmd, "auto_disable") == 0) {			res = video_autosw_set(0);			if (res)				return res;		} else if (strlencmp(cmd, "video_switch") == 0) {			res = video_outputsw_cycle();			if (res)				return res;		} else if (strlencmp(cmd, "expand_toggle") == 0) {			res = video_expand_toggle();			if (res)				return res;		} else			return -EINVAL;	}	if (enable || disable) {		status = video_outputsw_get();		if (status < 0)			return status;		res = video_outputsw_set((status & ~disable) | enable);		if (res)			return res;	}	return 0;}static struct ibm_struct video_driver_data = {	.name = "video",	.read = video_read,	.write = video_write,	.exit = video_exit,};/************************************************************************* * Light (thinklight) subdriver */IBM_HANDLE(lght, root, "\\LGHT");	/* A21e, A2xm/p, T20-22, X20-21 */IBM_HANDLE(ledb, ec, "LEDB");		/* G4x */static int __init light_init(struct ibm_init_struct *iibm){	vdbg_printk(TPACPI_DBG_INIT, "initializing light subdriver\n");	IBM_ACPIHANDLE_INIT(ledb);	IBM_ACPIHANDLE_INIT(lght);	IBM_ACPIHANDLE_INIT(cmos);	/* light not supported on 570, 600e/x, 770e, 770x, G4x, R30, R31 */	tp_features.light = (cmos_handle || lght_handle) && !ledb_handle;	if (tp_features.light)		/* light status not supported on		   570, 600e/x, 770e, 770x, G4x, R30, R31, R32, X20 */		tp_features.light_status =			acpi_evalf(ec_handle, NULL, "KBLT", "qv");	vdbg_printk(TPACPI_DBG_INIT, "light is %s\n",		str_supported(tp_features.light));	return (tp_features.light)? 0 : 1;}static int light_read(char *p){	int len = 0;	int status = 0;

⌨️ 快捷键说明

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