]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blobdiff - drivers/platform/x86/thinkpad_acpi.c
platform/x86: thinkpad_acpi: Replace HTTP links with HTTPS ones
[mirror_ubuntu-hirsute-kernel.git] / drivers / platform / x86 / thinkpad_acpi.c
index ff7f0a4f247563f4ebf3c9cce86da52eee1e2a37..edae2db2798417765ad26073fda8210a2ea5194f 100644 (file)
@@ -885,11 +885,19 @@ static ssize_t dispatch_proc_write(struct file *file,
 
        if (!ibm || !ibm->write)
                return -EINVAL;
+       if (count > PAGE_SIZE - 1)
+               return -EINVAL;
+
+       kernbuf = kmalloc(count + 1, GFP_KERNEL);
+       if (!kernbuf)
+               return -ENOMEM;
 
-       kernbuf = strndup_user(userbuf, PAGE_SIZE);
-       if (IS_ERR(kernbuf))
-               return PTR_ERR(kernbuf);
+       if (copy_from_user(kernbuf, userbuf, count)) {
+               kfree(kernbuf);
+               return -EFAULT;
+       }
 
+       kernbuf[count] = 0;
        ret = ibm->write(kernbuf);
        if (ret == 0)
                ret = count;
@@ -4022,8 +4030,8 @@ static bool hotkey_notify_6xxx(const u32 hkey,
                return true;
        case TP_HKEY_EV_THM_CSM_COMPLETED:
                pr_debug("EC reports: Thermal Control Command set completed (DYTC)\n");
-               /* recommended action: do nothing, we don't have
-                * Lenovo ATM information */
+               /* Thermal event - pass on to event handler */
+               tpacpi_driver_event(hkey);
                return true;
        case TP_HKEY_EV_THM_TRANSFM_CHANGED:
                pr_debug("EC reports: Thermal Transformation changed (GMTS)\n");
@@ -6955,10 +6963,13 @@ static int __init brightness_init(struct ibm_init_struct *iibm)
                        pr_warn("Cannot enable backlight brightness support, ACPI is already handling it.  Refer to the acpi_backlight kernel parameter.\n");
                        return 1;
                }
-       } else if (tp_features.bright_acpimode && brightness_enable > 1) {
-               pr_notice("Standard ACPI backlight interface not available, thinkpad_acpi native brightness control enabled\n");
+       } else if (!tp_features.bright_acpimode) {
+               pr_notice("ACPI backlight interface not available\n");
+               return 1;
        }
 
+       pr_notice("ACPI native brightness control enabled\n");
+
        /*
         * Check for module parameter bogosity, note that we
         * init brightness_mode to TPACPI_BRGHT_MODE_MAX in order to be
@@ -7957,7 +7968,7 @@ static struct ibm_struct volume_driver_data = {
  *     does so, its initial value is meaningless (0x07).
  *
  *     For firmware bugs, refer to:
- *     http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *     https://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
  *
  *     ----
  *
@@ -7982,7 +7993,7 @@ static struct ibm_struct volume_driver_data = {
  *     mode.
  *
  *     For firmware bugs, refer to:
- *     http://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
+ *     https://thinkwiki.org/wiki/Embedded_Controller_Firmware#Firmware_Issues
  *
  *     ----
  *
@@ -9795,6 +9806,105 @@ static struct ibm_struct lcdshadow_driver_data = {
        .write = lcdshadow_write,
 };
 
+/*************************************************************************
+ * DYTC subdriver, for the Lenovo lapmode feature
+ */
+
+#define DYTC_CMD_GET          2 /* To get current IC function and mode */
+#define DYTC_GET_LAPMODE_BIT 17 /* Set when in lapmode */
+
+static bool dytc_lapmode;
+
+static void dytc_lapmode_notify_change(void)
+{
+       sysfs_notify(&tpacpi_pdev->dev.kobj, NULL, "dytc_lapmode");
+}
+
+static int dytc_command(int command, int *output)
+{
+       acpi_handle dytc_handle;
+
+       if (ACPI_FAILURE(acpi_get_handle(hkey_handle, "DYTC", &dytc_handle))) {
+               /* Platform doesn't support DYTC */
+               return -ENODEV;
+       }
+       if (!acpi_evalf(dytc_handle, output, NULL, "dd", command))
+               return -EIO;
+       return 0;
+}
+
+static int dytc_lapmode_get(bool *state)
+{
+       int output, err;
+
+       err = dytc_command(DYTC_CMD_GET, &output);
+       if (err)
+               return err;
+       *state = output & BIT(DYTC_GET_LAPMODE_BIT) ? true : false;
+       return 0;
+}
+
+static void dytc_lapmode_refresh(void)
+{
+       bool new_state;
+       int err;
+
+       err = dytc_lapmode_get(&new_state);
+       if (err || (new_state == dytc_lapmode))
+               return;
+
+       dytc_lapmode = new_state;
+       dytc_lapmode_notify_change();
+}
+
+/* sysfs lapmode entry */
+static ssize_t dytc_lapmode_show(struct device *dev,
+                                       struct device_attribute *attr,
+                                       char *buf)
+{
+       return snprintf(buf, PAGE_SIZE, "%d\n", dytc_lapmode);
+}
+
+static DEVICE_ATTR_RO(dytc_lapmode);
+
+static struct attribute *dytc_attributes[] = {
+       &dev_attr_dytc_lapmode.attr,
+       NULL,
+};
+
+static const struct attribute_group dytc_attr_group = {
+       .attrs = dytc_attributes,
+};
+
+static int tpacpi_dytc_init(struct ibm_init_struct *iibm)
+{
+       int err;
+
+       err = dytc_lapmode_get(&dytc_lapmode);
+       /* If support isn't available (ENODEV) then don't return an error
+        * but just don't create the sysfs group
+        */
+       if (err == -ENODEV)
+               return 0;
+       /* For all other errors we can flag the failure */
+       if (err)
+               return err;
+
+       /* Platform supports this feature - create the group */
+       err = sysfs_create_group(&tpacpi_pdev->dev.kobj, &dytc_attr_group);
+       return err;
+}
+
+static void dytc_exit(void)
+{
+       sysfs_remove_group(&tpacpi_pdev->dev.kobj, &dytc_attr_group);
+}
+
+static struct ibm_struct dytc_driver_data = {
+       .name = "dytc",
+       .exit = dytc_exit,
+};
+
 /****************************************************************************
  ****************************************************************************
  *
@@ -9842,6 +9952,10 @@ static void tpacpi_driver_event(const unsigned int hkey_event)
 
                mutex_unlock(&kbdlight_mutex);
        }
+
+       if (hkey_event == TP_HKEY_EV_THM_CSM_COMPLETED)
+               dytc_lapmode_refresh();
+
 }
 
 static void hotkey_driver_event(const unsigned int scancode)
@@ -10094,7 +10208,7 @@ static int __must_check __init get_thinkpad_model_data(
         * X32 or newer, all Z series;  Some models must have an
         * up-to-date BIOS or they will not be detected.
         *
-        * See http://thinkwiki.org/wiki/List_of_DMI_IDs
+        * See https://thinkwiki.org/wiki/List_of_DMI_IDs
         */
        while ((dev = dmi_find_device(DMI_DEV_TYPE_OEM_STRING, NULL, dev))) {
                if (sscanf(dev->name,
@@ -10280,6 +10394,10 @@ static struct ibm_init_struct ibms_init[] __initdata = {
                .init = tpacpi_lcdshadow_init,
                .data = &lcdshadow_driver_data,
        },
+       {
+               .init = tpacpi_dytc_init,
+               .data = &dytc_driver_data,
+       },
 };
 
 static int __init set_ibm_param(const char *val, const struct kernel_param *kp)
@@ -10613,8 +10731,8 @@ MODULE_DEVICE_TABLE(acpi, ibm_htk_device_ids);
 /*
  * DMI matching for module autoloading
  *
- * See http://thinkwiki.org/wiki/List_of_DMI_IDs
- * See http://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
+ * See https://thinkwiki.org/wiki/List_of_DMI_IDs
+ * See https://thinkwiki.org/wiki/BIOS_Upgrade_Downloads
  *
  * Only models listed in thinkwiki will be supported, so add yours
  * if it is not there yet.