thinkpad_acpi.c
来自「linux 内核源代码」· C语言 代码 · 共 2,636 行 · 第 1/5 页
C
2,636 行
if (tp_features.hotkey_mask) { if (!acpi_evalf(hkey_handle, &hotkey_all_mask, "MHKA", "qd")) { printk(IBM_ERR "missing MHKA handler, " "please report this to %s\n", IBM_MAIL); hotkey_all_mask = 0x080cU; /* FN+F12, FN+F4, FN+F3 */ } } res = hotkey_get(&hotkey_orig_status, &hotkey_orig_mask); if (!res && tp_features.hotkey_mask) { res = add_many_to_attr_set(hotkey_dev_attributes, hotkey_mask_attributes, ARRAY_SIZE(hotkey_mask_attributes)); } /* Not all thinkpads have a hardware radio switch */ if (!res && acpi_evalf(hkey_handle, &status, "WLSW", "qd")) { tp_features.hotkey_wlsw = 1; printk(IBM_INFO "radio switch found; radios are %s\n", enabled(status, 0)); res = add_to_attr_set(hotkey_dev_attributes, &dev_attr_hotkey_radio_sw.attr); } if (!res) res = register_attr_set_with_sysfs( hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); if (res) return res; /* Set up key map */ hotkey_keycode_map = kmalloc(TPACPI_HOTKEY_MAP_SIZE, GFP_KERNEL); if (!hotkey_keycode_map) { printk(IBM_ERR "failed to allocate memory for key map\n"); return -ENOMEM; } if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO) { dbg_printk(TPACPI_DBG_INIT, "using Lenovo default hot key map\n"); memcpy(hotkey_keycode_map, &lenovo_keycode_map, TPACPI_HOTKEY_MAP_SIZE); } else { dbg_printk(TPACPI_DBG_INIT, "using IBM default hot key map\n"); memcpy(hotkey_keycode_map, &ibm_keycode_map, TPACPI_HOTKEY_MAP_SIZE); } set_bit(EV_KEY, tpacpi_inputdev->evbit); set_bit(EV_MSC, tpacpi_inputdev->evbit); set_bit(MSC_SCAN, tpacpi_inputdev->mscbit); tpacpi_inputdev->keycodesize = TPACPI_HOTKEY_MAP_TYPESIZE; tpacpi_inputdev->keycodemax = TPACPI_HOTKEY_MAP_LEN; tpacpi_inputdev->keycode = hotkey_keycode_map; for (i = 0; i < TPACPI_HOTKEY_MAP_LEN; i++) { if (hotkey_keycode_map[i] != KEY_RESERVED) { set_bit(hotkey_keycode_map[i], tpacpi_inputdev->keybit); } else { if (i < sizeof(hotkey_reserved_mask)*8) hotkey_reserved_mask |= 1 << i; } } if (tp_features.hotkey_wlsw) { set_bit(EV_SW, tpacpi_inputdev->evbit); set_bit(SW_RADIO, tpacpi_inputdev->swbit); } dbg_printk(TPACPI_DBG_INIT, "enabling hot key handling\n"); res = hotkey_set(1, (hotkey_all_mask & ~hotkey_reserved_mask) | hotkey_orig_mask); if (res) return res; dbg_printk(TPACPI_DBG_INIT, "legacy hot key reporting over procfs %s\n", (hotkey_report_mode < 2) ? "enabled" : "disabled"); } return (tp_features.hotkey)? 0 : 1;}static void hotkey_exit(void){ int res; if (tp_features.hotkey) { dbg_printk(TPACPI_DBG_EXIT, "restoring original hotkey mask\n"); res = hotkey_set(hotkey_orig_status, hotkey_orig_mask); if (res) printk(IBM_ERR "failed to restore hotkey to BIOS defaults\n"); } if (hotkey_dev_attributes) { delete_attr_set(hotkey_dev_attributes, &tpacpi_pdev->dev.kobj); hotkey_dev_attributes = NULL; }}static void tpacpi_input_send_key(unsigned int scancode, unsigned int keycode){ if (keycode != KEY_RESERVED) { mutex_lock(&tpacpi_inputdev_send_mutex); input_report_key(tpacpi_inputdev, keycode, 1); if (keycode == KEY_UNKNOWN) input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode); input_sync(tpacpi_inputdev); input_report_key(tpacpi_inputdev, keycode, 0); if (keycode == KEY_UNKNOWN) input_event(tpacpi_inputdev, EV_MSC, MSC_SCAN, scancode); input_sync(tpacpi_inputdev); mutex_unlock(&tpacpi_inputdev_send_mutex); }}static void tpacpi_input_send_radiosw(void){ int wlsw; mutex_lock(&tpacpi_inputdev_send_mutex); if (tp_features.hotkey_wlsw && !hotkey_get_wlsw(&wlsw)) { input_report_switch(tpacpi_inputdev, SW_RADIO, !!wlsw); input_sync(tpacpi_inputdev); } mutex_unlock(&tpacpi_inputdev_send_mutex);}static void hotkey_notify(struct ibm_struct *ibm, u32 event){ u32 hkey; unsigned int keycode, scancode; int send_acpi_ev; int ignore_acpi_ev; if (event != 0x80) { printk(IBM_ERR "unknown HKEY notification event %d\n", event); /* forward it to userspace, maybe it knows how to handle it */ acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, ibm->acpi->device->dev.bus_id, event, 0); return; } while (1) { if (!acpi_evalf(hkey_handle, &hkey, "MHKP", "d")) { printk(IBM_ERR "failed to retrieve HKEY event\n"); return; } if (hkey == 0) { /* queue empty */ return; } send_acpi_ev = 0; ignore_acpi_ev = 0; switch (hkey >> 12) { case 1: /* 0x1000-0x1FFF: key presses */ scancode = hkey & 0xfff; if (scancode > 0 && scancode < 0x21) { scancode--; keycode = hotkey_keycode_map[scancode]; tpacpi_input_send_key(scancode, keycode); } else { printk(IBM_ERR "hotkey 0x%04x out of range for keyboard map\n", hkey); send_acpi_ev = 1; } break; case 5: /* 0x5000-0x5FFF: LID */ /* we don't handle it through this path, just * eat up known LID events */ if (hkey != 0x5001 && hkey != 0x5002) { printk(IBM_ERR "unknown LID-related HKEY event: 0x%04x\n", hkey); send_acpi_ev = 1; } else { ignore_acpi_ev = 1; } break; case 7: /* 0x7000-0x7FFF: misc */ if (tp_features.hotkey_wlsw && hkey == 0x7000) { tpacpi_input_send_radiosw(); break; } /* fallthrough to default */ default: /* case 2: dock-related */ /* 0x2305 - T43 waking up due to bay lever eject while aslept */ /* case 3: ultra-bay related. maybe bay in dock? */ /* 0x3003 - T43 after wake up by bay lever eject (0x2305) */ printk(IBM_NOTICE "unhandled HKEY event 0x%04x\n", hkey); send_acpi_ev = 1; } /* Legacy events */ if (!ignore_acpi_ev && (send_acpi_ev || hotkey_report_mode < 2)) { acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey); } /* netlink events */ if (!ignore_acpi_ev && send_acpi_ev) { acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class, ibm->acpi->device->dev.bus_id, event, hkey); } }}static void hotkey_resume(void){ tpacpi_input_send_radiosw();}/* * Call with hotkey_mutex held */static int hotkey_get(int *status, u32 *mask){ if (!acpi_evalf(hkey_handle, status, "DHKC", "d")) return -EIO; if (tp_features.hotkey_mask) if (!acpi_evalf(hkey_handle, mask, "DHKN", "d")) return -EIO; return 0;}/* * Call with hotkey_mutex held */static int hotkey_set(int status, u32 mask){ int i; if (!acpi_evalf(hkey_handle, NULL, "MHKC", "vd", status)) return -EIO; if (tp_features.hotkey_mask) for (i = 0; i < 32; i++) { int bit = ((1 << i) & mask) != 0; if (!acpi_evalf(hkey_handle, NULL, "MHKM", "vdd", i + 1, bit)) return -EIO; } return 0;}/* procfs -------------------------------------------------------------- */static int hotkey_read(char *p){ int res, status; u32 mask; int len = 0; if (!tp_features.hotkey) { len += sprintf(p + len, "status:\t\tnot supported\n"); return len; } if (mutex_lock_interruptible(&hotkey_mutex)) return -ERESTARTSYS; res = hotkey_get(&status, &mask); mutex_unlock(&hotkey_mutex); if (res) return res; len += sprintf(p + len, "status:\t\t%s\n", enabled(status, 0)); if (tp_features.hotkey_mask) { len += sprintf(p + len, "mask:\t\t0x%08x\n", mask); len += sprintf(p + len, "commands:\tenable, disable, reset, <mask>\n"); } else { len += sprintf(p + len, "mask:\t\tnot supported\n"); len += sprintf(p + len, "commands:\tenable, disable, reset\n"); } return len;}static int hotkey_write(char *buf){ int res, status; u32 mask; char *cmd; int do_cmd = 0; if (!tp_features.hotkey) return -ENODEV; if (mutex_lock_interruptible(&hotkey_mutex)) return -ERESTARTSYS; res = hotkey_get(&status, &mask); if (res) goto errexit; res = 0; while ((cmd = next_cmd(&buf))) { if (strlencmp(cmd, "enable") == 0) { status = 1; } else if (strlencmp(cmd, "disable") == 0) { status = 0; } else if (strlencmp(cmd, "reset") == 0) { status = hotkey_orig_status; mask = hotkey_orig_mask; } else if (sscanf(cmd, "0x%x", &mask) == 1) { /* mask set */ } else if (sscanf(cmd, "%x", &mask) == 1) { /* mask set */ } else { res = -EINVAL; goto errexit; } do_cmd = 1; } if (do_cmd) res = hotkey_set(status, mask);errexit: mutex_unlock(&hotkey_mutex); return res;}static const struct acpi_device_id ibm_htk_device_ids[] = { {IBM_HKEY_HID, 0}, {"", 0},};static struct tp_acpi_drv_struct ibm_hotkey_acpidriver = { .hid = ibm_htk_device_ids, .notify = hotkey_notify, .handle = &hkey_handle, .type = ACPI_DEVICE_NOTIFY,};static struct ibm_struct hotkey_driver_data = { .name = "hotkey", .read = hotkey_read, .write = hotkey_write, .exit = hotkey_exit, .resume = hotkey_resume, .acpi = &ibm_hotkey_acpidriver,};/************************************************************************* * Bluetooth subdriver *//* sysfs bluetooth enable ---------------------------------------------- */static ssize_t bluetooth_enable_show(struct device *dev, struct device_attribute *attr, char *buf){ int status; status = bluetooth_get_radiosw(); if (status < 0) return status; return snprintf(buf, PAGE_SIZE, "%d\n", status ? 1 : 0);}static ssize_t bluetooth_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 = bluetooth_set_radiosw(t); return (res) ? res : count;}static struct device_attribute dev_attr_bluetooth_enable = __ATTR(bluetooth_enable, S_IWUSR | S_IRUGO, bluetooth_enable_show, bluetooth_enable_store);/* --------------------------------------------------------------------- */static struct attribute *bluetooth_attributes[] = { &dev_attr_bluetooth_enable.attr, NULL};static const struct attribute_group bluetooth_attr_group = { .attrs = bluetooth_attributes,};static int __init bluetooth_init(struct ibm_init_struct *iibm){ int res; int status = 0; vdbg_printk(TPACPI_DBG_INIT, "initializing bluetooth subdriver\n"); IBM_ACPIHANDLE_INIT(hkey); /* bluetooth not supported on 570, 600e/x, 770e, 770x, A21e, A2xm/p, G4x, R30, R31, R40e, R50e, T20-22, X20-21 */ tp_features.bluetooth = hkey_handle && acpi_evalf(hkey_handle, &status, "GBDC", "qd"); vdbg_printk(TPACPI_DBG_INIT, "bluetooth is %s, status 0x%02x\n", str_supported(tp_features.bluetooth), status); if (tp_features.bluetooth) { if (!(status & TP_ACPI_BLUETOOTH_HWPRESENT)) { /* no bluetooth hardware present in system */ tp_features.bluetooth = 0; dbg_printk(TPACPI_DBG_INIT, "bluetooth hardware not installed\n"); } else { res = sysfs_create_group(&tpacpi_pdev->dev.kobj, &bluetooth_attr_group); if (res) return res; } } return (tp_features.bluetooth)? 0 : 1;}static void bluetooth_exit(void){ sysfs_remove_group(&tpacpi_pdev->dev.kobj, &bluetooth_attr_group);}static int bluetooth_get_radiosw(void){ int status; if (!tp_features.bluetooth) return -ENODEV; if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) return -EIO; return ((status & TP_ACPI_BLUETOOTH_RADIOSSW) != 0);}static int bluetooth_set_radiosw(int radio_on){ int status; if (!tp_features.bluetooth) return -ENODEV; if (!acpi_evalf(hkey_handle, &status, "GBDC", "d")) return -EIO; if (radio_on) status |= TP_ACPI_BLUETOOTH_RADIOSSW; else status &= ~TP_ACPI_BLUETOOTH_RADIOSSW; if (!acpi_evalf(hkey_handle, NULL, "SBDC", "vd", status)) return -EIO; return 0;}/* procfs -------------------------------------------------------------- */static int bluetooth_read(char *p){ int len = 0; int status = bluetooth_get_radiosw(); if (!tp_features.bluetooth) 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 bluetooth_write(char *buf){ char *cmd; if (!tp_features.bluetooth) return -ENODEV; while ((cmd = next_cmd(&buf))) { if (strlencmp(cmd, "enable") == 0) { bluetooth_set_radiosw(1); } else if (strlencmp(cmd, "disable") == 0) { bluetooth_set_radiosw(0); } else return -EINVAL; }
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?