ACPI: Schedule /proc/acpi/event for removal
[firefly-linux-kernel-4.4.55.git] / drivers / misc / thinkpad_acpi.c
index 44aa8c92f91f599d7cf46d478e34e896af5b2ab6..bb8956d0c1047fce4eb35f2323072b8438e59e40 100644 (file)
@@ -21,7 +21,7 @@
  *  02110-1301, USA.
  */
 
-#define IBM_VERSION "0.14"
+#define IBM_VERSION "0.15"
 #define TPACPI_SYSFS_VERSION 0x010000
 
 /*
@@ -411,12 +411,13 @@ static int __init register_tpacpi_subdriver(struct ibm_struct *ibm)
 
        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)
@@ -717,9 +718,19 @@ static int __init thinkpad_acpi_driver_init(struct ibm_init_struct *iibm)
        printk(IBM_INFO "%s v%s\n", IBM_DESC, IBM_VERSION);
        printk(IBM_INFO "%s\n", IBM_URL);
 
-       if (ibm_thinkpad_ec_found)
-               printk(IBM_INFO "ThinkPad EC firmware %s\n",
-                      ibm_thinkpad_ec_found);
+       printk(IBM_INFO "ThinkPad BIOS %s, EC %s\n",
+               (thinkpad_id.bios_version_str) ?
+                       thinkpad_id.bios_version_str : "unknown",
+               (thinkpad_id.ec_version_str) ?
+                       thinkpad_id.ec_version_str : "unknown");
+
+       if (thinkpad_id.vendor && thinkpad_id.model_str)
+               printk(IBM_INFO "%s %s\n",
+                       (thinkpad_id.vendor == PCI_VENDOR_ID_IBM) ?
+                               "IBM" : ((thinkpad_id.vendor ==
+                                               PCI_VENDOR_ID_LENOVO) ?
+                                       "Lenovo" : "Unknown vendor"),
+                       thinkpad_id.model_str);
 
        return 0;
 }
@@ -748,29 +759,7 @@ static u32 hotkey_orig_mask;
 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;
 
@@ -929,6 +918,58 @@ static struct attribute *hotkey_mask_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;
 
@@ -993,6 +1034,27 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                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;
@@ -1001,10 +1063,10 @@ static int __init hotkey_init(struct ibm_init_struct *iibm)
                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);
@@ -1128,10 +1190,10 @@ static void hotkey_notify(struct ibm_struct *ibm, u32 event)
                }
 
                if (sendacpi)
-                       acpi_bus_generate_event(ibm->acpi->device, event, hkey);
+                       acpi_bus_generate_proc_event(ibm->acpi->device, event, hkey);
        } else {
                printk(IBM_ERR "unknown hotkey notification event %d\n", event);
-               acpi_bus_generate_event(ibm->acpi->device, event, 0);
+               acpi_bus_generate_proc_event(ibm->acpi->device, event, 0);
        }
 }
 
@@ -1255,8 +1317,13 @@ errexit:
        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,
@@ -2019,6 +2086,11 @@ IBM_HANDLE(dock, root, "\\_SB.GDCK",     /* X30, X31, X40 */
 /* 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,
@@ -2029,7 +2101,7 @@ static struct tp_acpi_drv_struct ibm_dock_acpidriver[2] = {
        /* 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,
@@ -2088,23 +2160,29 @@ static int __init dock_init2(struct ibm_init_struct *iibm)
 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);
+       int data;
 
        if (event == 1 && !pci) /* 570 */
-               acpi_bus_generate_event(ibm->acpi->device, event, 1);   /* button */
+               data = 1;       /* button */
        else if (event == 1 && pci)     /* 570 */
-               acpi_bus_generate_event(ibm->acpi->device, event, 3);   /* dock */
+               data = 3;       /* dock */
        else if (event == 3 && docked)
-               acpi_bus_generate_event(ibm->acpi->device, event, 1);   /* button */
+               data = 1;       /* button */
        else if (event == 3 && !docked)
-               acpi_bus_generate_event(ibm->acpi->device, event, 2);   /* undock */
+               data = 2;       /* undock */
        else if (event == 0 && docked)
-               acpi_bus_generate_event(ibm->acpi->device, event, 3);   /* dock */
+               data = 3;       /* dock */
        else {
                printk(IBM_ERR "unknown dock event %d, status %d\n",
                       event, _sta(dock_handle));
-               acpi_bus_generate_event(ibm->acpi->device, event, 0);   /* unknown */
+               data = 0;       /* unknown */
        }
+       acpi_bus_generate_proc_event(ibm->acpi->device, event, data);
+       acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+                                         ibm->acpi->device->dev.bus_id,
+                                         event, data);
 }
 
 static int dock_read(char *p)
@@ -2202,7 +2280,10 @@ static int __init bay_init(struct ibm_init_struct *iibm)
 
 static void bay_notify(struct ibm_struct *ibm, u32 event)
 {
-       acpi_bus_generate_event(ibm->acpi->device, event, 0);
+       acpi_bus_generate_proc_event(ibm->acpi->device, event, 0);
+       acpi_bus_generate_netlink_event(ibm->acpi->device->pnp.device_class,
+                                         ibm->acpi->device->dev.bus_id,
+                                         event, 0);
 }
 
 #define bay_occupied(b) (_sta(b##_handle) & 1)
@@ -2648,7 +2729,7 @@ static int __init thermal_init(struct ibm_init_struct *iibm)
 
        acpi_tmp7 = acpi_evalf(ec_handle, NULL, "TMP7", "qv");
 
-       if (ibm_thinkpad_ec_found && experimental) {
+       if (thinkpad_id.ec_model) {
                /*
                 * Direct EC access mode: sensors at registers
                 * 0x78-0x7F, 0xC0-0xC7.  Registers return 0x00 for
@@ -2792,6 +2873,8 @@ static int thermal_get_sensor(int idx, s32 *value)
                        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;
                }
@@ -2937,15 +3020,32 @@ static struct backlight_ops ibm_backlight_data = {
         .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;
+               else
+                       brightness_mode = 3;
+
+               dbg_printk(TPACPI_DBG_INIT, "selected brightness_mode=%d\n",
+                       brightness_mode);
+       }
+
+       if (brightness_mode > 3)
+               return -EINVAL;
+
        b = brightness_get(NULL);
        if (b < 0)
-               return b;
+               return 1;
 
        ibm_backlight_device = backlight_device_register(
                                        TPACPI_BACKLIGHT_DEV_NAME, NULL, NULL,
@@ -2981,34 +3081,79 @@ static int brightness_update_status(struct backlight_device *bd)
                                bd->props.brightness : 0);
 }
 
+/*
+ * ThinkPads can read brightness from two places: EC 0x31, or
+ * CMOS NVRAM byte 0x5E, bits 0-3.
+ */
 static int brightness_get(struct backlight_device *bd)
 {
-       u8 level;
-       if (!acpi_ec_read(brightness_offset, &level))
-               return -EIO;
+       u8 lec = 0, lcmos = 0, level = 0;
 
-       level &= 0x7;
+       if (brightness_mode & 1) {
+               if (!acpi_ec_read(brightness_offset, &lec))
+                       return -EIO;
+               lec &= 7;
+               level = lec;
+       };
+       if (brightness_mode & 2) {
+               lcmos = (nvram_read_byte(TP_NVRAM_ADDR_BRIGHTNESS)
+                        & TP_NVRAM_MASK_LEVEL_BRIGHTNESS)
+                       >> TP_NVRAM_POS_LEVEL_BRIGHTNESS;
+               level = lcmos;
+       }
+
+       if (brightness_mode == 3 && lec != lcmos) {
+               printk(IBM_ERR
+                       "CMOS NVRAM (%u) and EC (%u) do not agree "
+                       "on display brightness level\n",
+                       (unsigned int) lcmos,
+                       (unsigned int) lec);
+               return -EIO;
+       }
 
        return level;
 }
 
 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;
 
-       value &= 7;
+       if (value > 7)
+               return -EINVAL;
 
-       cmos_cmd = value > current_value ? TP_CMOS_BRIGHTNESS_UP : TP_CMOS_BRIGHTNESS_DOWN;
+       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 (issue_thinkpad_cmos_command(cmos_cmd))
-                       return -EIO;
-               if (!acpi_ec_write(brightness_offset, i + inc))
-                       return -EIO;
+               if ((brightness_mode & 2) &&
+                   issue_thinkpad_cmos_command(cmos_cmd)) {
+                       res = -EIO;
+                       goto errout;
+               }
+               if ((brightness_mode & 1) &&
+                   !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)
@@ -3532,20 +3677,19 @@ static int __init fan_init(struct ibm_init_struct *iibm)
                         * Enable for TP-1Y (T43), TP-78 (R51e),
                         * TP-76 (R52), TP-70 (T43, R52), which are known
                         * to be buggy. */
-                       if (fan_control_initial_status == 0x07 &&
-                           ibm_thinkpad_ec_found &&
-                           ((ibm_thinkpad_ec_found[0] == '1' &&
-                             ibm_thinkpad_ec_found[1] == 'Y') ||
-                            (ibm_thinkpad_ec_found[0] == '7' &&
-                             (ibm_thinkpad_ec_found[1] == '6' ||
-                              ibm_thinkpad_ec_found[1] == '8' ||
-                              ibm_thinkpad_ec_found[1] == '0'))
-                           )) {
-                               printk(IBM_NOTICE
-                                      "fan_init: initial fan status is "
-                                      "unknown, assuming it is in auto "
-                                      "mode\n");
-                               tp_features.fan_ctrl_status_undef = 1;
+                       if (fan_control_initial_status == 0x07) {
+                               switch (thinkpad_id.ec_model) {
+                               case 0x5931: /* TP-1Y */
+                               case 0x3837: /* TP-78 */
+                               case 0x3637: /* TP-76 */
+                               case 0x3037: /* TP-70 */
+                                       printk(IBM_NOTICE
+                                              "fan_init: initial fan status is "
+                                              "unknown, assuming it is in auto "
+                                              "mode\n");
+                                       tp_features.fan_ctrl_status_undef = 1;
+                                       ;;
+                               }
                        }
                } else {
                        printk(IBM_ERR
@@ -4279,13 +4423,30 @@ static void ibm_exit(struct ibm_struct *ibm)
 
 /* Probing */
 
-static char *ibm_thinkpad_ec_found;
-
-static char* __init check_dmi_for_ec(void)
+static void __init get_thinkpad_model_data(struct thinkpad_id_data *tp)
 {
        struct dmi_device *dev = NULL;
        char ec_fw_string[18];
 
+       if (!tp)
+               return;
+
+       memset(tp, 0, sizeof(*tp));
+
+       if (dmi_name_in_vendors("IBM"))
+               tp->vendor = PCI_VENDOR_ID_IBM;
+       else if (dmi_name_in_vendors("LENOVO"))
+               tp->vendor = PCI_VENDOR_ID_LENOVO;
+       else
+               return;
+
+       tp->bios_version_str = kstrdup(dmi_get_system_info(DMI_BIOS_VERSION),
+                                       GFP_KERNEL);
+       if (!tp->bios_version_str)
+               return;
+       tp->bios_model = tp->bios_version_str[0]
+                        | (tp->bios_version_str[1] << 8);
+
        /*
         * ThinkPad T23 or newer, A31 or newer, R50e or newer,
         * X32 or newer, all Z series;  Some models must have an
@@ -4299,10 +4460,20 @@ static char* __init check_dmi_for_ec(void)
                           ec_fw_string) == 1) {
                        ec_fw_string[sizeof(ec_fw_string) - 1] = 0;
                        ec_fw_string[strcspn(ec_fw_string, " ]")] = 0;
-                       return kstrdup(ec_fw_string, GFP_KERNEL);
+
+                       tp->ec_version_str = kstrdup(ec_fw_string, GFP_KERNEL);
+                       tp->ec_model = ec_fw_string[0]
+                                       | (ec_fw_string[1] << 8);
+                       break;
                }
        }
-       return NULL;
+
+       tp->model_str = kstrdup(dmi_get_system_info(DMI_PRODUCT_VERSION),
+                                       GFP_KERNEL);
+       if (strnicmp(tp->model_str, "ThinkPad", 8) != 0) {
+               kfree(tp->model_str);
+               tp->model_str = NULL;
+       }
 }
 
 static int __init probe_for_thinkpad(void)
@@ -4316,7 +4487,7 @@ static int __init probe_for_thinkpad(void)
         * Non-ancient models have better DMI tagging, but very old models
         * don't.
         */
-       is_thinkpad = dmi_name_in_vendors("ThinkPad");
+       is_thinkpad = (thinkpad_id.model_str != NULL);
 
        /* ec is required because many other handles are relative to it */
        IBM_ACPIHANDLE_INIT(ec);
@@ -4332,7 +4503,7 @@ static int __init probe_for_thinkpad(void)
         * false positives a damn great deal
         */
        if (!is_thinkpad)
-               is_thinkpad = dmi_name_in_vendors("IBM");
+               is_thinkpad = (thinkpad_id.vendor == PCI_VENDOR_ID_IBM);
 
        if (!is_thinkpad && !force_load)
                return -ENODEV;
@@ -4449,6 +4620,9 @@ module_param(force_load, bool, 0);
 static int fan_control_allowed;
 module_param_named(fan_control, fan_control_allowed, bool, 0);
 
+static int brightness_mode;
+module_param_named(brightness_mode, brightness_mode, int, 0);
+
 #define IBM_PARAM(feature) \
        module_param_call(feature, set_ibm_param, NULL, NULL, 0)
 
@@ -4475,12 +4649,16 @@ static int __init thinkpad_acpi_module_init(void)
        int ret, i;
 
        /* Driver-level probe */
+
+       get_thinkpad_model_data(&thinkpad_id);
        ret = probe_for_thinkpad();
-       if (ret)
+       if (ret) {
+               thinkpad_acpi_module_exit();
                return ret;
+       }
 
        /* Driver initialization */
-       ibm_thinkpad_ec_found = check_dmi_for_ec();
+
        IBM_ACPIHANDLE_INIT(ecrd);
        IBM_ACPIHANDLE_INIT(ecwr);
 
@@ -4498,12 +4676,15 @@ static int __init thinkpad_acpi_module_init(void)
                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 */
@@ -4534,7 +4715,9 @@ static int __init thinkpad_acpi_module_init(void)
                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;
        }
@@ -4584,13 +4767,18 @@ static void thinkpad_acpi_module_exit(void)
        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);
 
-       kfree(ibm_thinkpad_ec_found);
+       kfree(thinkpad_id.bios_version_str);
+       kfree(thinkpad_id.ec_version_str);
+       kfree(thinkpad_id.model_str);
 }
 
 module_init(thinkpad_acpi_module_init);