* 02110-1301, USA.
*/
-#define IBM_VERSION "0.14"
+#define IBM_VERSION "0.15"
#define TPACPI_SYSFS_VERSION 0x010000
/*
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->acpi->hid, rc);
+ ibm->name, rc);
kfree(ibm->acpi->driver);
ibm->acpi->driver = NULL;
} else if (!rc)
static u32 hotkey_all_mask;
static u32 hotkey_reserved_mask;
-static u16 hotkey_keycode_map[] = {
- /* Scan Codes 0x00 to 0x0B: ACPI HKEY FN+F1..F12 */
- KEY_FN_F1, KEY_FN_F2, KEY_FN_F3, KEY_SLEEP,
- KEY_FN_F5, KEY_FN_F6, KEY_FN_F7, 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 *hotkey_keycode_map;
static struct attribute_set *hotkey_dev_attributes;
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_BRIGHTNESSUP, /* 0x0F: FN+HOME (brightness up) */
+ /* Scan codes 0x10 to 0x1F: Extended ACPI HKEY hot keys */
+ KEY_BRIGHTNESSDOWN, /* 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;
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);
+ }
+
#ifndef CONFIG_THINKPAD_ACPI_INPUT_ENABLED
for (i = 0; i < 12; i++)
hotkey_keycode_map[i] = KEY_UNKNOWN;
set_bit(EV_KEY, tpacpi_inputdev->evbit);
set_bit(EV_MSC, tpacpi_inputdev->evbit);
set_bit(MSC_SCAN, tpacpi_inputdev->mscbit);
- tpacpi_inputdev->keycodesize = sizeof(hotkey_keycode_map[0]);
- tpacpi_inputdev->keycodemax = ARRAY_SIZE(hotkey_keycode_map);
- tpacpi_inputdev->keycode = &hotkey_keycode_map;
- for (i = 0; i < ARRAY_SIZE(hotkey_keycode_map); i++) {
+ 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);
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_HKEY_HID,
+ .hid = ibm_htk_device_ids,
.notify = hotkey_notify,
.handle = &hkey_handle,
.type = ACPI_DEVICE_NOTIFY,
/* don't list other alternatives as we install a notify handler on the 570 */
IBM_HANDLE(pci, root, "\\_SB.PCI"); /* 570 */
+static const struct acpi_device_id ibm_pci_device_ids[] = {
+ {PCI_ROOT_HID_STRING, 0},
+ {"", 0},
+};
+
static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
{
.notify = dock_notify,
/* THIS ONE MUST NEVER BE USED FOR DRIVER AUTOLOADING.
* We just use it to get notifications of dock hotplug
* in very old thinkpads */
- .hid = PCI_ROOT_HID_STRING,
+ .hid = ibm_pci_device_ids,
.notify = dock_notify,
.handle = &pci_handle,
.type = ACPI_SYSTEM_NOTIFY,
static void dock_notify(struct ibm_struct *ibm, u32 event)
{
int docked = dock_docked();
- int pci = ibm->acpi->hid && strstr(ibm->acpi->hid, PCI_ROOT_HID_STRING);
+ int pci = ibm->acpi->hid && ibm->acpi->device &&
+ acpi_match_device_ids(ibm->acpi->device, ibm_pci_device_ids);
if (event == 1 && !pci) /* 570 */
acpi_bus_generate_event(ibm->acpi->device, event, 1); /* button */
acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
- if (thinkpad_id.ec_model && experimental) {
+ if (thinkpad_id.ec_model) {
/*
* Direct EC access mode: sensors at registers
* 0x78-0x7F, 0xC0-0xC7. Registers return 0x00 for
snprintf(tmpi, sizeof(tmpi), "TMP%c", '0' + idx);
if (!acpi_evalf(ec_handle, &t, tmpi, "d"))
return -EIO;
+ if (t > 127 || t < -127)
+ t = TP_EC_THERMAL_TMP_NA;
*value = t * 1000;
return 0;
}
.update_status = brightness_update_status,
};
+static struct mutex brightness_mutex;
+
static int __init brightness_init(struct ibm_init_struct *iibm)
{
int b;
vdbg_printk(TPACPI_DBG_INIT, "initializing brightness subdriver\n");
+ mutex_init(&brightness_mutex);
+
if (!brightness_mode) {
if (thinkpad_id.vendor == PCI_VENDOR_ID_LENOVO)
brightness_mode = 2;
static int brightness_set(int value)
{
- int cmos_cmd, inc, i;
- int current_value = brightness_get(NULL);
+ int cmos_cmd, inc, i, res;
+ int current_value;
if (value > 7)
return -EINVAL;
+ res = mutex_lock_interruptible(&brightness_mutex);
+ if (res < 0)
+ return res;
+
+ current_value = brightness_get(NULL);
+ if (current_value < 0) {
+ res = current_value;
+ goto errout;
+ }
+
cmos_cmd = value > current_value ?
TP_CMOS_BRIGHTNESS_UP :
TP_CMOS_BRIGHTNESS_DOWN;
inc = value > current_value ? 1 : -1;
+ res = 0;
for (i = current_value; i != value; i += inc) {
if ((brightness_mode & 2) &&
- issue_thinkpad_cmos_command(cmos_cmd))
- return -EIO;
+ issue_thinkpad_cmos_command(cmos_cmd)) {
+ res = -EIO;
+ goto errout;
+ }
if ((brightness_mode & 1) &&
- !acpi_ec_write(brightness_offset, i + inc))
- return -EIO;
+ !acpi_ec_write(brightness_offset, i + inc)) {
+ res = -EIO;
+ goto errout;;
+ }
}
- return 0;
+errout:
+ mutex_unlock(&brightness_mutex);
+ return res;
}
static int brightness_read(char *p)
thinkpad_acpi_module_exit();
return ret;
}
+ tp_features.platform_drv_registered = 1;
+
ret = tpacpi_create_driver_attributes(&tpacpi_pdriver.driver);
if (ret) {
printk(IBM_ERR "unable to create sysfs driver attributes\n");
thinkpad_acpi_module_exit();
return ret;
}
+ tp_features.platform_drv_attrs_registered = 1;
/* Device initialization */
tpacpi_inputdev->name = "ThinkPad Extra Buttons";
tpacpi_inputdev->phys = IBM_DRVR_NAME "/input0";
tpacpi_inputdev->id.bustype = BUS_HOST;
- tpacpi_inputdev->id.vendor = TPACPI_HKEY_INPUT_VENDOR;
+ tpacpi_inputdev->id.vendor = (thinkpad_id.vendor) ?
+ thinkpad_id.vendor :
+ PCI_VENDOR_ID_IBM;
tpacpi_inputdev->id.product = TPACPI_HKEY_INPUT_PRODUCT;
tpacpi_inputdev->id.version = TPACPI_HKEY_INPUT_VERSION;
}
if (tpacpi_pdev)
platform_device_unregister(tpacpi_pdev);
- tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
- platform_driver_unregister(&tpacpi_pdriver);
+ if (tp_features.platform_drv_attrs_registered)
+ tpacpi_remove_driver_attributes(&tpacpi_pdriver.driver);
+
+ if (tp_features.platform_drv_registered)
+ platform_driver_unregister(&tpacpi_pdriver);
if (proc_dir)
remove_proc_entry(IBM_PROC_DIR, acpi_root_dir);