thinkpad_acpi.c
来自「linux 内核源代码」· C语言 代码 · 共 2,636 行 · 第 1/5 页
C
2,636 行
/* * thinkpad_acpi.c - ThinkPad ACPI Extras * * * Copyright (C) 2004-2005 Borislav Deianov <borislav@users.sf.net> * Copyright (C) 2006-2007 Henrique de Moraes Holschuh <hmh@hmh.eng.br> * * 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., 51 Franklin Street, Fifth Floor, Boston, MA * 02110-1301, USA. */#define IBM_VERSION "0.17"#define TPACPI_SYSFS_VERSION 0x020000/* * Changelog: * 2007-03-27 0.14 renamed to thinkpad_acpi and moved to * drivers/misc. * * 2006-11-22 0.13 new maintainer * changelog now lives in git commit history, and will * not be updated further in-file. * * 2005-08-17 0.12 fix compilation on 2.6.13-rc kernels * 2005-03-17 0.11 support for 600e, 770x * thanks to Jamie Lentin <lentinj@dial.pipex.com> * support for 770e, G41 * G40 and G41 don't have a thinklight * temperatures no longer experimental * experimental brightness control * experimental volume control * experimental fan enable/disable * 2005-01-16 0.10 fix module loading on R30, R31 * 2005-01-16 0.9 support for 570, R30, R31 * ultrabay support on A22p, A3x * limit arg for cmos, led, beep, drop experimental status * more capable led control on A21e, A22p, T20-22, X20 * experimental temperatures and fan speed * experimental embedded controller register dump * mark more functions as __init, drop incorrect __exit * use MODULE_VERSION * thanks to Henrik Brix Andersen <brix@gentoo.org> * fix parameter passing on module loading * thanks to Rusty Russell <rusty@rustcorp.com.au> * thanks to Jim Radford <radford@blackbean.org> * 2004-11-08 0.8 fix init error case, don't return from a macro * thanks to Chris Wright <chrisw@osdl.org> * 2004-10-23 0.7 fix module loading on A21e, A22p, T20, T21, X20 * fix led control on A21e * 2004-10-19 0.6 use acpi_bus_register_driver() to claim HKEY device * 2004-10-18 0.5 thinklight support on A21e, G40, R32, T20, T21, X20 * proc file format changed * video_switch command * experimental cmos control * experimental led control * experimental acpi sounds * 2004-09-16 0.4 support for module parameters * hotkey mask can be prefixed by 0x * video output switching * video expansion control * ultrabay eject support * removed lcd brightness/on/off control, didn't work * 2004-08-17 0.3 support for R40 * lcd off, brightness control * thinklight on/off * 2004-08-14 0.2 support for T series, X20 * bluetooth enable/disable * hotkey events disabled by default * removed fan control, currently useless * 2004-08-09 0.1 initial release, support for X series */#include "thinkpad_acpi.h"MODULE_AUTHOR("Borislav Deianov, Henrique de Moraes Holschuh");MODULE_DESCRIPTION(IBM_DESC);MODULE_VERSION(IBM_VERSION);MODULE_LICENSE("GPL");/* Please remove this in year 2009 */MODULE_ALIAS("ibm_acpi");/* * DMI matching for module autoloading * * See http://thinkwiki.org/wiki/List_of_DMI_IDs * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads * * Only models listed in thinkwiki will be supported, so add yours * if it is not there yet. */#define IBM_BIOS_MODULE_ALIAS(__type) \ MODULE_ALIAS("dmi:bvnIBM:bvr" __type "ET??WW")/* Non-ancient thinkpads */MODULE_ALIAS("dmi:bvnIBM:*:svnIBM:*:pvrThinkPad*:rvnIBM:*");MODULE_ALIAS("dmi:bvnLENOVO:*:svnLENOVO:*:pvrThinkPad*:rvnLENOVO:*");/* Ancient thinkpad BIOSes have to be identified by * BIOS type or model number, and there are far less * BIOS types than model numbers... */IBM_BIOS_MODULE_ALIAS("I[B,D,H,I,M,N,O,T,W,V,Y,Z]");IBM_BIOS_MODULE_ALIAS("1[0,3,6,8,A-G,I,K,M-P,S,T]");IBM_BIOS_MODULE_ALIAS("K[U,X-Z]");#define __unused __attribute__ ((unused))static enum { TPACPI_LIFE_INIT = 0, TPACPI_LIFE_RUNNING, TPACPI_LIFE_EXITING,} tpacpi_lifecycle;/**************************************************************************** **************************************************************************** * * ACPI Helpers and device model * **************************************************************************** ****************************************************************************//************************************************************************* * ACPI basic handles */static acpi_handle root_handle;#define IBM_HANDLE(object, parent, paths...) \ static acpi_handle object##_handle; \ static acpi_handle *object##_parent = &parent##_handle; \ static char *object##_path; \ static char *object##_paths[] = { paths }IBM_HANDLE(ec, root, "\\_SB.PCI0.ISA.EC0", /* 240, 240x */ "\\_SB.PCI.ISA.EC", /* 570 */ "\\_SB.PCI0.ISA0.EC0", /* 600e/x, 770e, 770x */ "\\_SB.PCI0.ISA.EC", /* A21e, A2xm/p, T20-22, X20-21 */ "\\_SB.PCI0.AD4S.EC0", /* i1400, R30 */ "\\_SB.PCI0.ICH3.EC0", /* R31 */ "\\_SB.PCI0.LPC.EC", /* all others */ );IBM_HANDLE(ecrd, ec, "ECRD"); /* 570 */IBM_HANDLE(ecwr, ec, "ECWR"); /* 570 *//************************************************************************* * Misc ACPI handles */IBM_HANDLE(cmos, root, "\\UCMS", /* R50, R50e, R50p, R51, T4x, X31, X40 */ "\\CMOS", /* A3x, G4x, R32, T23, T30, X22-24, X30 */ "\\CMS", /* R40, R40e */ ); /* all others */IBM_HANDLE(hkey, ec, "\\_SB.HKEY", /* 600e/x, 770e, 770x */ "^HKEY", /* R30, R31 */ "HKEY", /* all others */ ); /* 570 *//************************************************************************* * ACPI helpers */static int acpi_evalf(acpi_handle handle, void *res, char *method, char *fmt, ...){ char *fmt0 = fmt; struct acpi_object_list params; union acpi_object in_objs[IBM_MAX_ACPI_ARGS]; struct acpi_buffer result, *resultp; union acpi_object out_obj; acpi_status status; va_list ap; char res_type; int success; int quiet; if (!*fmt) { printk(IBM_ERR "acpi_evalf() called with empty format\n"); return 0; } if (*fmt == 'q') { quiet = 1; fmt++; } else quiet = 0; res_type = *(fmt++); params.count = 0; params.pointer = &in_objs[0]; va_start(ap, fmt); while (*fmt) { char c = *(fmt++); switch (c) { case 'd': /* int */ in_objs[params.count].integer.value = va_arg(ap, int); in_objs[params.count++].type = ACPI_TYPE_INTEGER; break; /* add more types as needed */ default: printk(IBM_ERR "acpi_evalf() called " "with invalid format character '%c'\n", c); return 0; } } va_end(ap); if (res_type != 'v') { result.length = sizeof(out_obj); result.pointer = &out_obj; resultp = &result; } else resultp = NULL; status = acpi_evaluate_object(handle, method, ¶ms, resultp); switch (res_type) { case 'd': /* int */ if (res) *(int *)res = out_obj.integer.value; success = status == AE_OK && out_obj.type == ACPI_TYPE_INTEGER; break; case 'v': /* void */ success = status == AE_OK; break; /* add more types as needed */ default: printk(IBM_ERR "acpi_evalf() called " "with invalid format character '%c'\n", res_type); return 0; } if (!success && !quiet) printk(IBM_ERR "acpi_evalf(%s, %s, ...) failed: %d\n", method, fmt0, status); return success;}static void __unused acpi_print_int(acpi_handle handle, char *method){ int i; if (acpi_evalf(handle, &i, method, "d")) printk(IBM_INFO "%s = 0x%x\n", method, i); else printk(IBM_ERR "error calling %s\n", method);}static int acpi_ec_read(int i, u8 * p){ int v; if (ecrd_handle) { if (!acpi_evalf(ecrd_handle, &v, NULL, "dd", i)) return 0; *p = v; } else { if (ec_read(i, p) < 0) return 0; } return 1;}static int acpi_ec_write(int i, u8 v){ if (ecwr_handle) { if (!acpi_evalf(ecwr_handle, NULL, NULL, "vdd", i, v)) return 0; } else { if (ec_write(i, v) < 0) return 0; } return 1;}static int _sta(acpi_handle handle){ int status; if (!handle || !acpi_evalf(handle, &status, "_STA", "d")) status = 0; return status;}static int issue_thinkpad_cmos_command(int cmos_cmd){ if (!cmos_handle) return -ENXIO; if (!acpi_evalf(cmos_handle, NULL, NULL, "vd", cmos_cmd)) return -EIO; return 0;}/************************************************************************* * ACPI device model */static void drv_acpi_handle_init(char *name, acpi_handle *handle, acpi_handle parent, char **paths, int num_paths, char **path){ int i; acpi_status status; vdbg_printk(TPACPI_DBG_INIT, "trying to locate ACPI handle for %s\n", name); for (i = 0; i < num_paths; i++) { status = acpi_get_handle(parent, paths[i], handle); if (ACPI_SUCCESS(status)) { *path = paths[i]; dbg_printk(TPACPI_DBG_INIT, "Found ACPI handle %s for %s\n", *path, name); return; } } vdbg_printk(TPACPI_DBG_INIT, "ACPI handle for %s not found\n", name); *handle = NULL;}static void dispatch_acpi_notify(acpi_handle handle, u32 event, void *data){ struct ibm_struct *ibm = data; if (tpacpi_lifecycle != TPACPI_LIFE_RUNNING) return; if (!ibm || !ibm->acpi || !ibm->acpi->notify) return; ibm->acpi->notify(ibm, event);}static int __init setup_acpi_notify(struct ibm_struct *ibm){ acpi_status status; int rc; BUG_ON(!ibm->acpi); if (!*ibm->acpi->handle) return 0; vdbg_printk(TPACPI_DBG_INIT, "setting up ACPI notify for %s\n", ibm->name); rc = acpi_bus_get_device(*ibm->acpi->handle, &ibm->acpi->device); if (rc < 0) { printk(IBM_ERR "acpi_bus_get_device(%s) failed: %d\n", ibm->name, rc); return -ENODEV; } acpi_driver_data(ibm->acpi->device) = ibm; sprintf(acpi_device_class(ibm->acpi->device), "%s/%s", IBM_ACPI_EVENT_PREFIX, ibm->name); status = acpi_install_notify_handler(*ibm->acpi->handle, ibm->acpi->type, dispatch_acpi_notify, ibm); if (ACPI_FAILURE(status)) { if (status == AE_ALREADY_EXISTS) { printk(IBM_NOTICE "another device driver is already handling %s events\n", ibm->name); } else { printk(IBM_ERR "acpi_install_notify_handler(%s) failed: %d\n", ibm->name, status); } return -ENODEV; } ibm->flags.acpi_notify_installed = 1; return 0;}static int __init tpacpi_device_add(struct acpi_device *device){ return 0;}static int __init register_tpacpi_subdriver(struct ibm_struct *ibm){ int rc; dbg_printk(TPACPI_DBG_INIT, "registering %s as an ACPI driver\n", ibm->name); BUG_ON(!ibm->acpi); ibm->acpi->driver = kzalloc(sizeof(struct acpi_driver), GFP_KERNEL); if (!ibm->acpi->driver) { printk(IBM_ERR "kzalloc(ibm->driver) failed\n"); return -ENOMEM; } sprintf(ibm->acpi->driver->name, "%s_%s", IBM_NAME, ibm->name); ibm->acpi->driver->ids = ibm->acpi->hid; ibm->acpi->driver->ops.add = &tpacpi_device_add; rc = acpi_bus_register_driver(ibm->acpi->driver); if (rc < 0) { printk(IBM_ERR "acpi_bus_register_driver(%s) failed: %d\n", ibm->name, rc); kfree(ibm->acpi->driver); ibm->acpi->driver = NULL; } else if (!rc) ibm->flags.acpi_driver_registered = 1; return rc;}/**************************************************************************** **************************************************************************** * * Procfs Helpers * **************************************************************************** ****************************************************************************/static int dispatch_procfs_read(char *page, char **start, off_t off, int count, int *eof, void *data){ struct ibm_struct *ibm = data; int len; if (!ibm || !ibm->read) return -EINVAL; len = ibm->read(page); if (len < 0) return len; if (len <= off + count) *eof = 1; *start = page + off; len -= off; if (len > count) len = count; if (len < 0) len = 0; return len;}static int dispatch_procfs_write(struct file *file, const char __user * userbuf, unsigned long count, void *data){ struct ibm_struct *ibm = data; char *kernbuf; int ret; if (!ibm || !ibm->write) return -EINVAL; kernbuf = kmalloc(count + 2, GFP_KERNEL); if (!kernbuf) return -ENOMEM; if (copy_from_user(kernbuf, userbuf, count)) { kfree(kernbuf); return -EFAULT; } kernbuf[count] = 0; strcat(kernbuf, ","); ret = ibm->write(kernbuf); if (ret == 0) ret = count; kfree(kernbuf); return ret;}static char *next_cmd(char **cmds){ char *start = *cmds; char *end; while ((end = strchr(start, ',')) && end == start) start = end + 1; if (!end) return NULL; *end = 0; *cmds = end + 1; return start;}/**************************************************************************** **************************************************************************** * * Device model: input, hwmon and platform * **************************************************************************** ****************************************************************************/static struct platform_device *tpacpi_pdev;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?