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 + -
显示快捷键?