1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Copyright 2013 Matthew Garrett <mjg59@srcf.ucam.org> 4 */ 5 6 #include <linux/acpi.h> 7 #include <linux/module.h> 8 #include <linux/slab.h> 9 10 MODULE_DESCRIPTION("Intel Rapid Start Technology Driver"); 11 MODULE_LICENSE("GPL"); 12 13 static ssize_t irst_show_wakeup_events(struct device *dev, 14 struct device_attribute *attr, 15 char *buf) 16 { 17 struct acpi_device *acpi; 18 unsigned long long value; 19 acpi_status status; 20 21 acpi = to_acpi_device(dev); 22 23 status = acpi_evaluate_integer(acpi->handle, "GFFS", NULL, &value); 24 if (ACPI_FAILURE(status)) 25 return -EINVAL; 26 27 return sprintf(buf, "%lld\n", value); 28 } 29 30 static ssize_t irst_store_wakeup_events(struct device *dev, 31 struct device_attribute *attr, 32 const char *buf, size_t count) 33 { 34 struct acpi_device *acpi; 35 acpi_status status; 36 unsigned long value; 37 int error; 38 39 acpi = to_acpi_device(dev); 40 41 error = kstrtoul(buf, 0, &value); 42 if (error) 43 return error; 44 45 status = acpi_execute_simple_method(acpi->handle, "SFFS", value); 46 if (ACPI_FAILURE(status)) 47 return -EINVAL; 48 49 return count; 50 } 51 52 static struct device_attribute irst_wakeup_attr = { 53 .attr = { .name = "wakeup_events", .mode = 0600 }, 54 .show = irst_show_wakeup_events, 55 .store = irst_store_wakeup_events 56 }; 57 58 static ssize_t irst_show_wakeup_time(struct device *dev, 59 struct device_attribute *attr, char *buf) 60 { 61 struct acpi_device *acpi; 62 unsigned long long value; 63 acpi_status status; 64 65 acpi = to_acpi_device(dev); 66 67 status = acpi_evaluate_integer(acpi->handle, "GFTV", NULL, &value); 68 if (ACPI_FAILURE(status)) 69 return -EINVAL; 70 71 return sprintf(buf, "%lld\n", value); 72 } 73 74 static ssize_t irst_store_wakeup_time(struct device *dev, 75 struct device_attribute *attr, 76 const char *buf, size_t count) 77 { 78 struct acpi_device *acpi; 79 acpi_status status; 80 unsigned long value; 81 int error; 82 83 acpi = to_acpi_device(dev); 84 85 error = kstrtoul(buf, 0, &value); 86 if (error) 87 return error; 88 89 status = acpi_execute_simple_method(acpi->handle, "SFTV", value); 90 if (ACPI_FAILURE(status)) 91 return -EINVAL; 92 93 return count; 94 } 95 96 static struct device_attribute irst_timeout_attr = { 97 .attr = { .name = "wakeup_time", .mode = 0600 }, 98 .show = irst_show_wakeup_time, 99 .store = irst_store_wakeup_time 100 }; 101 102 static int irst_add(struct acpi_device *acpi) 103 { 104 int error; 105 106 error = device_create_file(&acpi->dev, &irst_timeout_attr); 107 if (unlikely(error)) 108 return error; 109 110 error = device_create_file(&acpi->dev, &irst_wakeup_attr); 111 if (unlikely(error)) 112 device_remove_file(&acpi->dev, &irst_timeout_attr); 113 114 return error; 115 } 116 117 static void irst_remove(struct acpi_device *acpi) 118 { 119 device_remove_file(&acpi->dev, &irst_wakeup_attr); 120 device_remove_file(&acpi->dev, &irst_timeout_attr); 121 } 122 123 static const struct acpi_device_id irst_ids[] = { 124 {"INT3392", 0}, 125 {"", 0} 126 }; 127 128 static struct acpi_driver irst_driver = { 129 .name = "intel_rapid_start", 130 .class = "intel_rapid_start", 131 .ids = irst_ids, 132 .ops = { 133 .add = irst_add, 134 .remove = irst_remove, 135 }, 136 }; 137 138 module_acpi_driver(irst_driver); 139 140 MODULE_DEVICE_TABLE(acpi, irst_ids); 141