diff options
Diffstat (limited to 'drivers/misc')
-rw-r--r-- | drivers/misc/sony-laptop.c | 81 |
1 files changed, 62 insertions, 19 deletions
diff --git a/drivers/misc/sony-laptop.c b/drivers/misc/sony-laptop.c index d7b5330a7bcd..cabbed0015e4 100644 --- a/drivers/misc/sony-laptop.c +++ b/drivers/misc/sony-laptop.c | |||
@@ -58,13 +58,17 @@ static ssize_t sony_acpi_show(struct device *, struct device_attribute *, | |||
58 | char *); | 58 | char *); |
59 | static ssize_t sony_acpi_store(struct device *, struct device_attribute *, | 59 | static ssize_t sony_acpi_store(struct device *, struct device_attribute *, |
60 | const char *, size_t); | 60 | const char *, size_t); |
61 | static int boolean_validate(const int, const int); | ||
62 | static int brightness_default_validate(const int, const int); | ||
63 | |||
64 | #define SNC_VALIDATE_IN 0 | ||
65 | #define SNC_VALIDATE_OUT 1 | ||
61 | 66 | ||
62 | struct sony_acpi_value { | 67 | struct sony_acpi_value { |
63 | char *name; /* name of the entry */ | 68 | char *name; /* name of the entry */ |
64 | char **acpiget; /* names of the ACPI get function */ | 69 | char **acpiget; /* names of the ACPI get function */ |
65 | char **acpiset; /* names of the ACPI set function */ | 70 | char **acpiset; /* names of the ACPI set function */ |
66 | int min; /* minimum allowed value or -1 */ | 71 | int (*validate)(const int, const int); /* input/output validation */ |
67 | int max; /* maximum allowed value or -1 */ | ||
68 | int value; /* current setting */ | 72 | int value; /* current setting */ |
69 | int valid; /* Has ever been set */ | 73 | int valid; /* Has ever been set */ |
70 | int debug; /* active only in debug mode ? */ | 74 | int debug; /* active only in debug mode ? */ |
@@ -74,13 +78,12 @@ struct sony_acpi_value { | |||
74 | #define HANDLE_NAMES(_name, _values...) \ | 78 | #define HANDLE_NAMES(_name, _values...) \ |
75 | static char *snc_##_name[] = { _values, NULL } | 79 | static char *snc_##_name[] = { _values, NULL } |
76 | 80 | ||
77 | #define SONY_ACPI_VALUE(_name, _getters, _setters, _min, _max, _debug) \ | 81 | #define SONY_ACPI_VALUE(_name, _getters, _setters, _validate, _debug) \ |
78 | { \ | 82 | { \ |
79 | .name = __stringify(_name), \ | 83 | .name = __stringify(_name), \ |
80 | .acpiget = _getters, \ | 84 | .acpiget = _getters, \ |
81 | .acpiset = _setters, \ | 85 | .acpiset = _setters, \ |
82 | .min = _min, \ | 86 | .validate = _validate, \ |
83 | .max = _max, \ | ||
84 | .debug = _debug, \ | 87 | .debug = _debug, \ |
85 | .devattr = __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \ | 88 | .devattr = __ATTR(_name, 0, sony_acpi_show, sony_acpi_store), \ |
86 | } | 89 | } |
@@ -114,17 +117,18 @@ HANDLE_NAMES(CMI_set, "SCMI"); | |||
114 | 117 | ||
115 | static struct sony_acpi_value sony_acpi_values[] = { | 118 | static struct sony_acpi_value sony_acpi_values[] = { |
116 | SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get, | 119 | SONY_ACPI_VALUE(brightness_default, snc_brightness_def_get, |
117 | snc_brightness_def_set, 1, SONY_MAX_BRIGHTNESS, 0), | 120 | snc_brightness_def_set, brightness_default_validate, 0), |
118 | SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, -1, -1, 0), | 121 | SONY_ACPI_VALUE(fnkey, snc_fnkey_get, NULL, NULL, 0), |
119 | SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, 0, 1, 0), | 122 | SONY_ACPI_VALUE(cdpower, snc_cdpower_get, snc_cdpower_set, boolean_validate, 0), |
120 | SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set, 0, | 123 | SONY_ACPI_VALUE(audiopower, snc_audiopower_get, snc_audiopower_set, |
121 | 1, 0), | 124 | boolean_validate, 0), |
122 | SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set, 0, 1, 1), | 125 | SONY_ACPI_VALUE(lanpower, snc_lanpower_get, snc_lanpower_set, |
126 | boolean_validate, 1), | ||
123 | /* unknown methods */ | 127 | /* unknown methods */ |
124 | SONY_ACPI_VALUE(PID, snc_PID_get, NULL, -1, -1, 1), | 128 | SONY_ACPI_VALUE(PID, snc_PID_get, NULL, NULL, 1), |
125 | SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, -1, -1, 1), | 129 | SONY_ACPI_VALUE(CTR, snc_CTR_get, snc_CTR_set, NULL, 1), |
126 | SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, -1, -1, 1), | 130 | SONY_ACPI_VALUE(PCR, snc_PCR_get, snc_PCR_set, NULL, 1), |
127 | SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, -1, -1, 1), | 131 | SONY_ACPI_VALUE(CMI, snc_CMI_get, snc_CMI_set, NULL, 1), |
128 | SONY_ACPI_VALUE_NULL | 132 | SONY_ACPI_VALUE_NULL |
129 | }; | 133 | }; |
130 | 134 | ||
@@ -190,6 +194,41 @@ static int acpi_callsetfunc(acpi_handle handle, char *name, int value, | |||
190 | } | 194 | } |
191 | 195 | ||
192 | /* | 196 | /* |
197 | * sony_acpi_values input/output validate functions | ||
198 | */ | ||
199 | |||
200 | /* brightness_default_validate: | ||
201 | * | ||
202 | * manipulate input output values to keep consistency with the | ||
203 | * backlight framework for which brightness values are 0-based. | ||
204 | */ | ||
205 | static int brightness_default_validate(const int direction, const int value) | ||
206 | { | ||
207 | switch (direction) { | ||
208 | case SNC_VALIDATE_OUT: | ||
209 | return value - 1; | ||
210 | case SNC_VALIDATE_IN: | ||
211 | if (value >= 0 && value < SONY_MAX_BRIGHTNESS) | ||
212 | return value + 1; | ||
213 | } | ||
214 | return -EINVAL; | ||
215 | } | ||
216 | |||
217 | /* boolean_validate: | ||
218 | * | ||
219 | * on input validate boolean values 0/1, on output just pass the | ||
220 | * received value. | ||
221 | */ | ||
222 | static int boolean_validate(const int direction, const int value) | ||
223 | { | ||
224 | if (direction == SNC_VALIDATE_IN) { | ||
225 | if (value != 0 && value != 1) | ||
226 | return -EINVAL; | ||
227 | } | ||
228 | return value; | ||
229 | } | ||
230 | |||
231 | /* | ||
193 | * Sysfs show/store common to all sony_acpi_values | 232 | * Sysfs show/store common to all sony_acpi_values |
194 | */ | 233 | */ |
195 | static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr, | 234 | static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr, |
@@ -205,6 +244,9 @@ static ssize_t sony_acpi_show(struct device *dev, struct device_attribute *attr, | |||
205 | if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0) | 244 | if (acpi_callgetfunc(sony_acpi_handle, *item->acpiget, &value) < 0) |
206 | return -EIO; | 245 | return -EIO; |
207 | 246 | ||
247 | if (item->validate) | ||
248 | value = item->validate(SNC_VALIDATE_OUT, value); | ||
249 | |||
208 | return snprintf(buffer, PAGE_SIZE, "%d\n", value); | 250 | return snprintf(buffer, PAGE_SIZE, "%d\n", value); |
209 | } | 251 | } |
210 | 252 | ||
@@ -224,10 +266,11 @@ static ssize_t sony_acpi_store(struct device *dev, | |||
224 | 266 | ||
225 | value = simple_strtoul(buffer, NULL, 10); | 267 | value = simple_strtoul(buffer, NULL, 10); |
226 | 268 | ||
227 | if (item->min != -1 && value < item->min) | 269 | if (item->validate) |
228 | return -EINVAL; | 270 | value = item->validate(SNC_VALIDATE_IN, value); |
229 | if (item->max != -1 && value > item->max) | 271 | |
230 | return -EINVAL; | 272 | if (value < 0) |
273 | return value; | ||
231 | 274 | ||
232 | if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0) | 275 | if (acpi_callsetfunc(sony_acpi_handle, *item->acpiset, value, NULL) < 0) |
233 | return -EIO; | 276 | return -EIO; |