diff options
Diffstat (limited to 'drivers/platform/chrome/cros_ec_lightbar.c')
-rw-r--r-- | drivers/platform/chrome/cros_ec_lightbar.c | 152 |
1 files changed, 103 insertions, 49 deletions
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index b4ff47a9069a..560e5d41b7ae 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
34 | #include <linux/slab.h> | ||
34 | 35 | ||
35 | #include "cros_ec_dev.h" | 36 | #include "cros_ec_dev.h" |
36 | 37 | ||
@@ -91,54 +92,79 @@ out: | |||
91 | return ret; | 92 | return ret; |
92 | } | 93 | } |
93 | 94 | ||
94 | #define INIT_MSG(P, R) { \ | 95 | static struct cros_ec_command *alloc_lightbar_cmd_msg(void) |
95 | .command = EC_CMD_LIGHTBAR_CMD, \ | 96 | { |
96 | .outsize = sizeof(*P), \ | 97 | struct cros_ec_command *msg; |
97 | .insize = sizeof(*R), \ | 98 | int len; |
98 | } | 99 | |
100 | len = max(sizeof(struct ec_params_lightbar), | ||
101 | sizeof(struct ec_response_lightbar)); | ||
102 | |||
103 | msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL); | ||
104 | if (!msg) | ||
105 | return NULL; | ||
106 | |||
107 | msg->version = 0; | ||
108 | msg->command = EC_CMD_LIGHTBAR_CMD; | ||
109 | msg->outsize = sizeof(struct ec_params_lightbar); | ||
110 | msg->insize = sizeof(struct ec_response_lightbar); | ||
111 | |||
112 | return msg; | ||
113 | } | ||
99 | 114 | ||
100 | static int get_lightbar_version(struct cros_ec_device *ec, | 115 | static int get_lightbar_version(struct cros_ec_device *ec, |
101 | uint32_t *ver_ptr, uint32_t *flg_ptr) | 116 | uint32_t *ver_ptr, uint32_t *flg_ptr) |
102 | { | 117 | { |
103 | struct ec_params_lightbar *param; | 118 | struct ec_params_lightbar *param; |
104 | struct ec_response_lightbar *resp; | 119 | struct ec_response_lightbar *resp; |
105 | struct cros_ec_command msg = INIT_MSG(param, resp); | 120 | struct cros_ec_command *msg; |
106 | int ret; | 121 | int ret; |
107 | 122 | ||
108 | param = (struct ec_params_lightbar *)msg.outdata; | 123 | msg = alloc_lightbar_cmd_msg(); |
109 | param->cmd = LIGHTBAR_CMD_VERSION; | 124 | if (!msg) |
110 | ret = cros_ec_cmd_xfer(ec, &msg); | ||
111 | if (ret < 0) | ||
112 | return 0; | 125 | return 0; |
113 | 126 | ||
114 | switch (msg.result) { | 127 | param = (struct ec_params_lightbar *)msg->data; |
128 | param->cmd = LIGHTBAR_CMD_VERSION; | ||
129 | ret = cros_ec_cmd_xfer(ec, msg); | ||
130 | if (ret < 0) { | ||
131 | ret = 0; | ||
132 | goto exit; | ||
133 | } | ||
134 | |||
135 | switch (msg->result) { | ||
115 | case EC_RES_INVALID_PARAM: | 136 | case EC_RES_INVALID_PARAM: |
116 | /* Pixel had no version command. */ | 137 | /* Pixel had no version command. */ |
117 | if (ver_ptr) | 138 | if (ver_ptr) |
118 | *ver_ptr = 0; | 139 | *ver_ptr = 0; |
119 | if (flg_ptr) | 140 | if (flg_ptr) |
120 | *flg_ptr = 0; | 141 | *flg_ptr = 0; |
121 | return 1; | 142 | ret = 1; |
143 | goto exit; | ||
122 | 144 | ||
123 | case EC_RES_SUCCESS: | 145 | case EC_RES_SUCCESS: |
124 | resp = (struct ec_response_lightbar *)msg.indata; | 146 | resp = (struct ec_response_lightbar *)msg->data; |
125 | 147 | ||
126 | /* Future devices w/lightbars should implement this command */ | 148 | /* Future devices w/lightbars should implement this command */ |
127 | if (ver_ptr) | 149 | if (ver_ptr) |
128 | *ver_ptr = resp->version.num; | 150 | *ver_ptr = resp->version.num; |
129 | if (flg_ptr) | 151 | if (flg_ptr) |
130 | *flg_ptr = resp->version.flags; | 152 | *flg_ptr = resp->version.flags; |
131 | return 1; | 153 | ret = 1; |
154 | goto exit; | ||
132 | } | 155 | } |
133 | 156 | ||
134 | /* Anything else (ie, EC_RES_INVALID_COMMAND) - no lightbar */ | 157 | /* Anything else (ie, EC_RES_INVALID_COMMAND) - no lightbar */ |
135 | return 0; | 158 | ret = 0; |
159 | exit: | ||
160 | kfree(msg); | ||
161 | return ret; | ||
136 | } | 162 | } |
137 | 163 | ||
138 | static ssize_t version_show(struct device *dev, | 164 | static ssize_t version_show(struct device *dev, |
139 | struct device_attribute *attr, char *buf) | 165 | struct device_attribute *attr, char *buf) |
140 | { | 166 | { |
141 | uint32_t version, flags; | 167 | uint32_t version = 0, flags = 0; |
142 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 168 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
143 | int ret; | 169 | int ret; |
144 | 170 | ||
@@ -158,8 +184,7 @@ static ssize_t brightness_store(struct device *dev, | |||
158 | const char *buf, size_t count) | 184 | const char *buf, size_t count) |
159 | { | 185 | { |
160 | struct ec_params_lightbar *param; | 186 | struct ec_params_lightbar *param; |
161 | struct ec_response_lightbar *resp; | 187 | struct cros_ec_command *msg; |
162 | struct cros_ec_command msg = INIT_MSG(param, resp); | ||
163 | int ret; | 188 | int ret; |
164 | unsigned int val; | 189 | unsigned int val; |
165 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 190 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
@@ -167,21 +192,30 @@ static ssize_t brightness_store(struct device *dev, | |||
167 | if (kstrtouint(buf, 0, &val)) | 192 | if (kstrtouint(buf, 0, &val)) |
168 | return -EINVAL; | 193 | return -EINVAL; |
169 | 194 | ||
170 | param = (struct ec_params_lightbar *)msg.outdata; | 195 | msg = alloc_lightbar_cmd_msg(); |
196 | if (!msg) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | param = (struct ec_params_lightbar *)msg->data; | ||
171 | param->cmd = LIGHTBAR_CMD_BRIGHTNESS; | 200 | param->cmd = LIGHTBAR_CMD_BRIGHTNESS; |
172 | param->brightness.num = val; | 201 | param->brightness.num = val; |
173 | ret = lb_throttle(); | 202 | ret = lb_throttle(); |
174 | if (ret) | 203 | if (ret) |
175 | return ret; | 204 | goto exit; |
176 | 205 | ||
177 | ret = cros_ec_cmd_xfer(ec, &msg); | 206 | ret = cros_ec_cmd_xfer(ec, msg); |
178 | if (ret < 0) | 207 | if (ret < 0) |
179 | return ret; | 208 | goto exit; |
180 | 209 | ||
181 | if (msg.result != EC_RES_SUCCESS) | 210 | if (msg->result != EC_RES_SUCCESS) { |
182 | return -EINVAL; | 211 | ret = -EINVAL; |
212 | goto exit; | ||
213 | } | ||
183 | 214 | ||
184 | return count; | 215 | ret = count; |
216 | exit: | ||
217 | kfree(msg); | ||
218 | return ret; | ||
185 | } | 219 | } |
186 | 220 | ||
187 | 221 | ||
@@ -196,12 +230,15 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
196 | const char *buf, size_t count) | 230 | const char *buf, size_t count) |
197 | { | 231 | { |
198 | struct ec_params_lightbar *param; | 232 | struct ec_params_lightbar *param; |
199 | struct ec_response_lightbar *resp; | 233 | struct cros_ec_command *msg; |
200 | struct cros_ec_command msg = INIT_MSG(param, resp); | ||
201 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 234 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
202 | unsigned int val[4]; | 235 | unsigned int val[4]; |
203 | int ret, i = 0, j = 0, ok = 0; | 236 | int ret, i = 0, j = 0, ok = 0; |
204 | 237 | ||
238 | msg = alloc_lightbar_cmd_msg(); | ||
239 | if (!msg) | ||
240 | return -ENOMEM; | ||
241 | |||
205 | do { | 242 | do { |
206 | /* Skip any whitespace */ | 243 | /* Skip any whitespace */ |
207 | while (*buf && isspace(*buf)) | 244 | while (*buf && isspace(*buf)) |
@@ -215,7 +252,7 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
215 | return -EINVAL; | 252 | return -EINVAL; |
216 | 253 | ||
217 | if (i == 4) { | 254 | if (i == 4) { |
218 | param = (struct ec_params_lightbar *)msg.outdata; | 255 | param = (struct ec_params_lightbar *)msg->data; |
219 | param->cmd = LIGHTBAR_CMD_RGB; | 256 | param->cmd = LIGHTBAR_CMD_RGB; |
220 | param->rgb.led = val[0]; | 257 | param->rgb.led = val[0]; |
221 | param->rgb.red = val[1]; | 258 | param->rgb.red = val[1]; |
@@ -231,12 +268,14 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
231 | return ret; | 268 | return ret; |
232 | } | 269 | } |
233 | 270 | ||
234 | ret = cros_ec_cmd_xfer(ec, &msg); | 271 | ret = cros_ec_cmd_xfer(ec, msg); |
235 | if (ret < 0) | 272 | if (ret < 0) |
236 | return ret; | 273 | goto exit; |
237 | 274 | ||
238 | if (msg.result != EC_RES_SUCCESS) | 275 | if (msg->result != EC_RES_SUCCESS) { |
239 | return -EINVAL; | 276 | ret = -EINVAL; |
277 | goto exit; | ||
278 | } | ||
240 | 279 | ||
241 | i = 0; | 280 | i = 0; |
242 | ok = 1; | 281 | ok = 1; |
@@ -248,6 +287,8 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
248 | 287 | ||
249 | } while (*buf); | 288 | } while (*buf); |
250 | 289 | ||
290 | exit: | ||
291 | kfree(msg); | ||
251 | return (ok && i == 0) ? count : -EINVAL; | 292 | return (ok && i == 0) ? count : -EINVAL; |
252 | } | 293 | } |
253 | 294 | ||
@@ -261,42 +302,55 @@ static ssize_t sequence_show(struct device *dev, | |||
261 | { | 302 | { |
262 | struct ec_params_lightbar *param; | 303 | struct ec_params_lightbar *param; |
263 | struct ec_response_lightbar *resp; | 304 | struct ec_response_lightbar *resp; |
264 | struct cros_ec_command msg = INIT_MSG(param, resp); | 305 | struct cros_ec_command *msg; |
265 | int ret; | 306 | int ret; |
266 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 307 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
267 | 308 | ||
268 | param = (struct ec_params_lightbar *)msg.outdata; | 309 | msg = alloc_lightbar_cmd_msg(); |
310 | if (!msg) | ||
311 | return -ENOMEM; | ||
312 | |||
313 | param = (struct ec_params_lightbar *)msg->data; | ||
269 | param->cmd = LIGHTBAR_CMD_GET_SEQ; | 314 | param->cmd = LIGHTBAR_CMD_GET_SEQ; |
270 | ret = lb_throttle(); | 315 | ret = lb_throttle(); |
271 | if (ret) | 316 | if (ret) |
272 | return ret; | 317 | goto exit; |
273 | 318 | ||
274 | ret = cros_ec_cmd_xfer(ec, &msg); | 319 | ret = cros_ec_cmd_xfer(ec, msg); |
275 | if (ret < 0) | 320 | if (ret < 0) |
276 | return ret; | 321 | goto exit; |
277 | 322 | ||
278 | if (msg.result != EC_RES_SUCCESS) | 323 | if (msg->result != EC_RES_SUCCESS) { |
279 | return scnprintf(buf, PAGE_SIZE, | 324 | ret = scnprintf(buf, PAGE_SIZE, |
280 | "ERROR: EC returned %d\n", msg.result); | 325 | "ERROR: EC returned %d\n", msg->result); |
326 | goto exit; | ||
327 | } | ||
281 | 328 | ||
282 | resp = (struct ec_response_lightbar *)msg.indata; | 329 | resp = (struct ec_response_lightbar *)msg->data; |
283 | if (resp->get_seq.num >= ARRAY_SIZE(seqname)) | 330 | if (resp->get_seq.num >= ARRAY_SIZE(seqname)) |
284 | return scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num); | 331 | ret = scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num); |
285 | else | 332 | else |
286 | return scnprintf(buf, PAGE_SIZE, "%s\n", | 333 | ret = scnprintf(buf, PAGE_SIZE, "%s\n", |
287 | seqname[resp->get_seq.num]); | 334 | seqname[resp->get_seq.num]); |
335 | |||
336 | exit: | ||
337 | kfree(msg); | ||
338 | return ret; | ||
288 | } | 339 | } |
289 | 340 | ||
290 | static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, | 341 | static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, |
291 | const char *buf, size_t count) | 342 | const char *buf, size_t count) |
292 | { | 343 | { |
293 | struct ec_params_lightbar *param; | 344 | struct ec_params_lightbar *param; |
294 | struct ec_response_lightbar *resp; | 345 | struct cros_ec_command *msg; |
295 | struct cros_ec_command msg = INIT_MSG(param, resp); | ||
296 | unsigned int num; | 346 | unsigned int num; |
297 | int ret, len; | 347 | int ret, len; |
298 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 348 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
299 | 349 | ||
350 | msg = alloc_lightbar_cmd_msg(); | ||
351 | if (!msg) | ||
352 | return -ENOMEM; | ||
353 | |||
300 | for (len = 0; len < count; len++) | 354 | for (len = 0; len < count; len++) |
301 | if (!isalnum(buf[len])) | 355 | if (!isalnum(buf[len])) |
302 | break; | 356 | break; |
@@ -311,18 +365,18 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, | |||
311 | return ret; | 365 | return ret; |
312 | } | 366 | } |
313 | 367 | ||
314 | param = (struct ec_params_lightbar *)msg.outdata; | 368 | param = (struct ec_params_lightbar *)msg->data; |
315 | param->cmd = LIGHTBAR_CMD_SEQ; | 369 | param->cmd = LIGHTBAR_CMD_SEQ; |
316 | param->seq.num = num; | 370 | param->seq.num = num; |
317 | ret = lb_throttle(); | 371 | ret = lb_throttle(); |
318 | if (ret) | 372 | if (ret) |
319 | return ret; | 373 | return ret; |
320 | 374 | ||
321 | ret = cros_ec_cmd_xfer(ec, &msg); | 375 | ret = cros_ec_cmd_xfer(ec, msg); |
322 | if (ret < 0) | 376 | if (ret < 0) |
323 | return ret; | 377 | return ret; |
324 | 378 | ||
325 | if (msg.result != EC_RES_SUCCESS) | 379 | if (msg->result != EC_RES_SUCCESS) |
326 | return -EINVAL; | 380 | return -EINVAL; |
327 | 381 | ||
328 | return count; | 382 | return count; |