Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Toshiba HDD Active Protection Sensor (HAPS) driver
0004  *
0005  * Copyright (C) 2014 Azael Avalos <coproscefalo@gmail.com>
0006  */
0007 
0008 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
0009 
0010 #include <linux/kernel.h>
0011 #include <linux/module.h>
0012 #include <linux/init.h>
0013 #include <linux/types.h>
0014 #include <linux/acpi.h>
0015 
0016 MODULE_AUTHOR("Azael Avalos <coproscefalo@gmail.com>");
0017 MODULE_DESCRIPTION("Toshiba HDD Active Protection Sensor");
0018 MODULE_LICENSE("GPL");
0019 
0020 struct toshiba_haps_dev {
0021     struct acpi_device *acpi_dev;
0022 
0023     int protection_level;
0024 };
0025 
0026 static struct toshiba_haps_dev *toshiba_haps;
0027 
0028 /* HAPS functions */
0029 static int toshiba_haps_reset_protection(acpi_handle handle)
0030 {
0031     acpi_status status;
0032 
0033     status = acpi_evaluate_object(handle, "RSSS", NULL, NULL);
0034     if (ACPI_FAILURE(status)) {
0035         pr_err("Unable to reset the HDD protection\n");
0036         return -EIO;
0037     }
0038 
0039     return 0;
0040 }
0041 
0042 static int toshiba_haps_protection_level(acpi_handle handle, int level)
0043 {
0044     acpi_status status;
0045 
0046     status = acpi_execute_simple_method(handle, "PTLV", level);
0047     if (ACPI_FAILURE(status)) {
0048         pr_err("Error while setting the protection level\n");
0049         return -EIO;
0050     }
0051 
0052     pr_debug("HDD protection level set to: %d\n", level);
0053 
0054     return 0;
0055 }
0056 
0057 /* sysfs files */
0058 static ssize_t protection_level_show(struct device *dev,
0059                      struct device_attribute *attr, char *buf)
0060 {
0061     struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
0062 
0063     return sprintf(buf, "%i\n", haps->protection_level);
0064 }
0065 
0066 static ssize_t protection_level_store(struct device *dev,
0067                       struct device_attribute *attr,
0068                       const char *buf, size_t count)
0069 {
0070     struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
0071     int level;
0072     int ret;
0073 
0074     ret = kstrtoint(buf, 0, &level);
0075     if (ret)
0076         return ret;
0077     /*
0078      * Check for supported levels, which can be:
0079      * 0 - Disabled | 1 - Low | 2 - Medium | 3 - High
0080      */
0081     if (level < 0 || level > 3)
0082         return -EINVAL;
0083 
0084     /* Set the sensor level */
0085     ret = toshiba_haps_protection_level(haps->acpi_dev->handle, level);
0086     if (ret != 0)
0087         return ret;
0088 
0089     haps->protection_level = level;
0090 
0091     return count;
0092 }
0093 static DEVICE_ATTR_RW(protection_level);
0094 
0095 static ssize_t reset_protection_store(struct device *dev,
0096                       struct device_attribute *attr,
0097                       const char *buf, size_t count)
0098 {
0099     struct toshiba_haps_dev *haps = dev_get_drvdata(dev);
0100     int reset;
0101     int ret;
0102 
0103     ret = kstrtoint(buf, 0, &reset);
0104     if (ret)
0105         return ret;
0106     /* The only accepted value is 1 */
0107     if (reset != 1)
0108         return -EINVAL;
0109 
0110     /* Reset the protection interface */
0111     ret = toshiba_haps_reset_protection(haps->acpi_dev->handle);
0112     if (ret != 0)
0113         return ret;
0114 
0115     return count;
0116 }
0117 static DEVICE_ATTR_WO(reset_protection);
0118 
0119 static struct attribute *haps_attributes[] = {
0120     &dev_attr_protection_level.attr,
0121     &dev_attr_reset_protection.attr,
0122     NULL,
0123 };
0124 
0125 static const struct attribute_group haps_attr_group = {
0126     .attrs = haps_attributes,
0127 };
0128 
0129 /*
0130  * ACPI stuff
0131  */
0132 static void toshiba_haps_notify(struct acpi_device *device, u32 event)
0133 {
0134     pr_debug("Received event: 0x%x\n", event);
0135 
0136     acpi_bus_generate_netlink_event(device->pnp.device_class,
0137                     dev_name(&device->dev),
0138                     event, 0);
0139 }
0140 
0141 static int toshiba_haps_remove(struct acpi_device *device)
0142 {
0143     sysfs_remove_group(&device->dev.kobj, &haps_attr_group);
0144 
0145     if (toshiba_haps)
0146         toshiba_haps = NULL;
0147 
0148     return 0;
0149 }
0150 
0151 /* Helper function */
0152 static int toshiba_haps_available(acpi_handle handle)
0153 {
0154     acpi_status status;
0155     u64 hdd_present;
0156 
0157     /*
0158      * A non existent device as well as having (only)
0159      * Solid State Drives can cause the call to fail.
0160      */
0161     status = acpi_evaluate_integer(handle, "_STA", NULL, &hdd_present);
0162     if (ACPI_FAILURE(status)) {
0163         pr_err("ACPI call to query HDD protection failed\n");
0164         return 0;
0165     }
0166 
0167     if (!hdd_present) {
0168         pr_info("HDD protection not available or using SSD\n");
0169         return 0;
0170     }
0171 
0172     return 1;
0173 }
0174 
0175 static int toshiba_haps_add(struct acpi_device *acpi_dev)
0176 {
0177     struct toshiba_haps_dev *haps;
0178     int ret;
0179 
0180     if (toshiba_haps)
0181         return -EBUSY;
0182 
0183     if (!toshiba_haps_available(acpi_dev->handle))
0184         return -ENODEV;
0185 
0186     pr_info("Toshiba HDD Active Protection Sensor device\n");
0187 
0188     haps = kzalloc(sizeof(struct toshiba_haps_dev), GFP_KERNEL);
0189     if (!haps)
0190         return -ENOMEM;
0191 
0192     haps->acpi_dev = acpi_dev;
0193     haps->protection_level = 2;
0194     acpi_dev->driver_data = haps;
0195     dev_set_drvdata(&acpi_dev->dev, haps);
0196 
0197     /* Set the protection level, currently at level 2 (Medium) */
0198     ret = toshiba_haps_protection_level(acpi_dev->handle, 2);
0199     if (ret != 0)
0200         return ret;
0201 
0202     ret = sysfs_create_group(&acpi_dev->dev.kobj, &haps_attr_group);
0203     if (ret)
0204         return ret;
0205 
0206     toshiba_haps = haps;
0207 
0208     return 0;
0209 }
0210 
0211 #ifdef CONFIG_PM_SLEEP
0212 static int toshiba_haps_suspend(struct device *device)
0213 {
0214     struct toshiba_haps_dev *haps;
0215     int ret;
0216 
0217     haps = acpi_driver_data(to_acpi_device(device));
0218 
0219     /* Deactivate the protection on suspend */
0220     ret = toshiba_haps_protection_level(haps->acpi_dev->handle, 0);
0221 
0222     return ret;
0223 }
0224 
0225 static int toshiba_haps_resume(struct device *device)
0226 {
0227     struct toshiba_haps_dev *haps;
0228     int ret;
0229 
0230     haps = acpi_driver_data(to_acpi_device(device));
0231 
0232     /* Set the stored protection level */
0233     ret = toshiba_haps_protection_level(haps->acpi_dev->handle,
0234                         haps->protection_level);
0235 
0236     /* Reset the protection on resume */
0237     ret = toshiba_haps_reset_protection(haps->acpi_dev->handle);
0238     if (ret != 0)
0239         return ret;
0240 
0241     return ret;
0242 }
0243 #endif
0244 
0245 static SIMPLE_DEV_PM_OPS(toshiba_haps_pm,
0246              toshiba_haps_suspend, toshiba_haps_resume);
0247 
0248 static const struct acpi_device_id haps_device_ids[] = {
0249     {"TOS620A", 0},
0250     {"", 0},
0251 };
0252 MODULE_DEVICE_TABLE(acpi, haps_device_ids);
0253 
0254 static struct acpi_driver toshiba_haps_driver = {
0255     .name = "Toshiba HAPS",
0256     .owner = THIS_MODULE,
0257     .ids = haps_device_ids,
0258     .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
0259     .ops = {
0260         .add =      toshiba_haps_add,
0261         .remove =   toshiba_haps_remove,
0262         .notify =   toshiba_haps_notify,
0263     },
0264     .drv.pm = &toshiba_haps_pm,
0265 };
0266 
0267 module_acpi_driver(toshiba_haps_driver);