xref: /linux/drivers/platform/chrome/cros_ec_lightbar.c (revision c31f4aa8fed048fa70e742c4bb49bb48dc489ab3)
1 // SPDX-License-Identifier: GPL-2.0+
2 // Expose the Chromebook Pixel lightbar to userspace
3 //
4 // Copyright (C) 2014 Google, Inc.
5 
6 #include <linux/ctype.h>
7 #include <linux/delay.h>
8 #include <linux/device.h>
9 #include <linux/fs.h>
10 #include <linux/kobject.h>
11 #include <linux/kstrtox.h>
12 #include <linux/mod_devicetable.h>
13 #include <linux/module.h>
14 #include <linux/platform_data/cros_ec_commands.h>
15 #include <linux/platform_data/cros_ec_proto.h>
16 #include <linux/platform_device.h>
17 #include <linux/sched.h>
18 #include <linux/types.h>
19 #include <linux/uaccess.h>
20 #include <linux/slab.h>
21 
22 #define DRV_NAME "cros-ec-lightbar"
23 
24 /* Rate-limit the lightbar interface to prevent DoS. */
25 static unsigned long lb_interval_jiffies = 50 * HZ / 1000;
26 
27 /*
28  * Whether or not we have given userspace control of the lightbar.
29  * If this is true, we won't do anything during suspend/resume.
30  */
31 static bool userspace_control;
32 
33 /*
34  * Whether or not the lightbar supports the manual suspend commands.
35  * The Pixel 2013 (Link) does not while all other devices with a
36  * lightbar do.
37  */
38 static bool has_manual_suspend;
39 
40 static ssize_t interval_msec_show(struct device *dev,
41 				  struct device_attribute *attr, char *buf)
42 {
43 	unsigned long msec = lb_interval_jiffies * 1000 / HZ;
44 
45 	return sysfs_emit(buf, "%lu\n", msec);
46 }
47 
48 static ssize_t interval_msec_store(struct device *dev,
49 				   struct device_attribute *attr,
50 				   const char *buf, size_t count)
51 {
52 	unsigned long msec;
53 
54 	if (kstrtoul(buf, 0, &msec))
55 		return -EINVAL;
56 
57 	lb_interval_jiffies = msec * HZ / 1000;
58 
59 	return count;
60 }
61 
62 static DEFINE_MUTEX(lb_mutex);
63 /* Return 0 if able to throttle correctly, error otherwise */
64 static int lb_throttle(void)
65 {
66 	static unsigned long last_access;
67 	unsigned long now, next_timeslot;
68 	long delay;
69 	int ret = 0;
70 
71 	mutex_lock(&lb_mutex);
72 
73 	now = jiffies;
74 	next_timeslot = last_access + lb_interval_jiffies;
75 
76 	if (time_before(now, next_timeslot)) {
77 		delay = (long)(next_timeslot) - (long)now;
78 		set_current_state(TASK_INTERRUPTIBLE);
79 		if (schedule_timeout(delay) > 0) {
80 			/* interrupted - just abort */
81 			ret = -EINTR;
82 			goto out;
83 		}
84 		now = jiffies;
85 	}
86 
87 	last_access = now;
88 out:
89 	mutex_unlock(&lb_mutex);
90 
91 	return ret;
92 }
93 
94 static struct cros_ec_command *alloc_lightbar_cmd_msg(struct cros_ec_dev *ec)
95 {
96 	struct cros_ec_command *msg;
97 	int len;
98 
99 	len = max(sizeof(struct ec_params_lightbar),
100 		  sizeof(struct ec_response_lightbar));
101 
102 	msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL);
103 	if (!msg)
104 		return NULL;
105 
106 	msg->version = 0;
107 	msg->command = EC_CMD_LIGHTBAR_CMD + ec->cmd_offset;
108 	msg->outsize = sizeof(struct ec_params_lightbar);
109 	msg->insize = sizeof(struct ec_response_lightbar);
110 
111 	return msg;
112 }
113 
114 static int get_lightbar_version(struct cros_ec_dev *ec,
115 				uint32_t *ver_ptr, uint32_t *flg_ptr)
116 {
117 	struct ec_params_lightbar *param;
118 	struct ec_response_lightbar *resp;
119 	struct cros_ec_command *msg;
120 	int ret;
121 
122 	msg = alloc_lightbar_cmd_msg(ec);
123 	if (!msg)
124 		return 0;
125 
126 	param = (struct ec_params_lightbar *)msg->data;
127 	param->cmd = LIGHTBAR_CMD_VERSION;
128 	msg->outsize = sizeof(param->cmd);
129 	msg->result = sizeof(resp->version);
130 	ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
131 	if (ret < 0 && ret != -EINVAL) {
132 		ret = 0;
133 		goto exit;
134 	}
135 
136 	switch (msg->result) {
137 	case EC_RES_INVALID_PARAM:
138 		/* Pixel had no version command. */
139 		if (ver_ptr)
140 			*ver_ptr = 0;
141 		if (flg_ptr)
142 			*flg_ptr = 0;
143 		ret = 1;
144 		goto exit;
145 
146 	case EC_RES_SUCCESS:
147 		resp = (struct ec_response_lightbar *)msg->data;
148 
149 		/* Future devices w/lightbars should implement this command */
150 		if (ver_ptr)
151 			*ver_ptr = resp->version.num;
152 		if (flg_ptr)
153 			*flg_ptr = resp->version.flags;
154 		ret = 1;
155 		goto exit;
156 	}
157 
158 	/* Anything else (ie, EC_RES_INVALID_COMMAND) - no lightbar */
159 	ret = 0;
160 exit:
161 	kfree(msg);
162 	return ret;
163 }
164 
165 static ssize_t version_show(struct device *dev,
166 			    struct device_attribute *attr, char *buf)
167 {
168 	uint32_t version = 0, flags = 0;
169 	struct cros_ec_dev *ec = to_cros_ec_dev(dev);
170 	int ret;
171 
172 	ret = lb_throttle();
173 	if (ret)
174 		return ret;
175 
176 	/* This should always succeed, because we check during init. */
177 	if (!get_lightbar_version(ec, &version, &flags))
178 		return -EIO;
179 
180 	return sysfs_emit(buf, "%d %d\n", version, flags);
181 }
182 
183 static ssize_t brightness_store(struct device *dev,
184 				struct device_attribute *attr,
185 				const char *buf, size_t count)
186 {
187 	struct ec_params_lightbar *param;
188 	struct cros_ec_command *msg;
189 	int ret;
190 	unsigned int val;
191 	struct cros_ec_dev *ec = to_cros_ec_dev(dev);
192 
193 	if (kstrtouint(buf, 0, &val))
194 		return -EINVAL;
195 
196 	msg = alloc_lightbar_cmd_msg(ec);
197 	if (!msg)
198 		return -ENOMEM;
199 
200 	param = (struct ec_params_lightbar *)msg->data;
201 	param->cmd = LIGHTBAR_CMD_SET_BRIGHTNESS;
202 	param->set_brightness.num = val;
203 	ret = lb_throttle();
204 	if (ret)
205 		goto exit;
206 
207 	ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
208 	if (ret < 0)
209 		goto exit;
210 
211 	ret = count;
212 exit:
213 	kfree(msg);
214 	return ret;
215 }
216 
217 
218 /*
219  * We expect numbers, and we'll keep reading until we find them, skipping over
220  * any whitespace (sysfs guarantees that the input is null-terminated). Every
221  * four numbers are sent to the lightbar as <LED,R,G,B>. We fail at the first
222  * parsing error, if we don't parse any numbers, or if we have numbers left
223  * over.
224  */
225 static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr,
226 			     const char *buf, size_t count)
227 {
228 	struct ec_params_lightbar *param;
229 	struct cros_ec_command *msg;
230 	struct cros_ec_dev *ec = to_cros_ec_dev(dev);
231 	unsigned int val[4];
232 	int ret, i = 0, j = 0, ok = 0;
233 
234 	msg = alloc_lightbar_cmd_msg(ec);
235 	if (!msg)
236 		return -ENOMEM;
237 
238 	do {
239 		/* Skip any whitespace */
240 		while (*buf && isspace(*buf))
241 			buf++;
242 
243 		if (!*buf)
244 			break;
245 
246 		ret = sscanf(buf, "%i", &val[i++]);
247 		if (ret == 0)
248 			goto exit;
249 
250 		if (i == 4) {
251 			param = (struct ec_params_lightbar *)msg->data;
252 			param->cmd = LIGHTBAR_CMD_SET_RGB;
253 			param->set_rgb.led = val[0];
254 			param->set_rgb.red = val[1];
255 			param->set_rgb.green = val[2];
256 			param->set_rgb.blue = val[3];
257 			/*
258 			 * Throttle only the first of every four transactions,
259 			 * so that the user can update all four LEDs at once.
260 			 */
261 			if ((j++ % 4) == 0) {
262 				ret = lb_throttle();
263 				if (ret)
264 					goto exit;
265 			}
266 
267 			ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
268 			if (ret < 0)
269 				goto exit;
270 
271 			i = 0;
272 			ok = 1;
273 		}
274 
275 		/* Skip over the number we just read */
276 		while (*buf && !isspace(*buf))
277 			buf++;
278 
279 	} while (*buf);
280 
281 exit:
282 	kfree(msg);
283 	return (ok && i == 0) ? count : -EINVAL;
284 }
285 
286 static char const *seqname[] = {
287 	"ERROR", "S5", "S3", "S0", "S5S3", "S3S0",
288 	"S0S3", "S3S5", "STOP", "RUN", "KONAMI",
289 	"TAP", "PROGRAM",
290 };
291 
292 static ssize_t sequence_show(struct device *dev,
293 			     struct device_attribute *attr, char *buf)
294 {
295 	struct ec_params_lightbar *param;
296 	struct ec_response_lightbar *resp;
297 	struct cros_ec_command *msg;
298 	int ret;
299 	struct cros_ec_dev *ec = to_cros_ec_dev(dev);
300 
301 	msg = alloc_lightbar_cmd_msg(ec);
302 	if (!msg)
303 		return -ENOMEM;
304 
305 	param = (struct ec_params_lightbar *)msg->data;
306 	param->cmd = LIGHTBAR_CMD_GET_SEQ;
307 	ret = lb_throttle();
308 	if (ret)
309 		goto exit;
310 
311 	ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
312 	if (ret < 0) {
313 		ret = sysfs_emit(buf, "XFER / EC ERROR %d / %d\n", ret, msg->result);
314 		goto exit;
315 	}
316 
317 	resp = (struct ec_response_lightbar *)msg->data;
318 	if (resp->get_seq.num >= ARRAY_SIZE(seqname))
319 		ret = sysfs_emit(buf, "%d\n", resp->get_seq.num);
320 	else
321 		ret = sysfs_emit(buf, "%s\n", seqname[resp->get_seq.num]);
322 
323 exit:
324 	kfree(msg);
325 	return ret;
326 }
327 
328 static int lb_send_empty_cmd(struct cros_ec_dev *ec, uint8_t cmd)
329 {
330 	struct ec_params_lightbar *param;
331 	struct cros_ec_command *msg;
332 	int ret;
333 
334 	msg = alloc_lightbar_cmd_msg(ec);
335 	if (!msg)
336 		return -ENOMEM;
337 
338 	param = (struct ec_params_lightbar *)msg->data;
339 	param->cmd = cmd;
340 
341 	ret = lb_throttle();
342 	if (ret)
343 		goto error;
344 
345 	ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
346 	if (ret < 0)
347 		goto error;
348 
349 	ret = 0;
350 error:
351 	kfree(msg);
352 
353 	return ret;
354 }
355 
356 static int lb_manual_suspend_ctrl(struct cros_ec_dev *ec, uint8_t enable)
357 {
358 	struct ec_params_lightbar *param;
359 	struct cros_ec_command *msg;
360 	int ret;
361 
362 	msg = alloc_lightbar_cmd_msg(ec);
363 	if (!msg)
364 		return -ENOMEM;
365 
366 	param = (struct ec_params_lightbar *)msg->data;
367 
368 	param->cmd = LIGHTBAR_CMD_MANUAL_SUSPEND_CTRL;
369 	param->manual_suspend_ctrl.enable = enable;
370 
371 	ret = lb_throttle();
372 	if (ret)
373 		goto error;
374 
375 	ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
376 	if (ret < 0)
377 		goto error;
378 
379 	ret = 0;
380 error:
381 	kfree(msg);
382 
383 	return ret;
384 }
385 
386 static ssize_t sequence_store(struct device *dev, struct device_attribute *attr,
387 			      const char *buf, size_t count)
388 {
389 	struct ec_params_lightbar *param;
390 	struct cros_ec_command *msg;
391 	unsigned int num;
392 	int ret, len;
393 	struct cros_ec_dev *ec = to_cros_ec_dev(dev);
394 
395 	for (len = 0; len < count; len++)
396 		if (!isalnum(buf[len]))
397 			break;
398 
399 	for (num = 0; num < ARRAY_SIZE(seqname); num++)
400 		if (!strncasecmp(seqname[num], buf, len))
401 			break;
402 
403 	if (num >= ARRAY_SIZE(seqname)) {
404 		ret = kstrtouint(buf, 0, &num);
405 		if (ret)
406 			return ret;
407 	}
408 
409 	msg = alloc_lightbar_cmd_msg(ec);
410 	if (!msg)
411 		return -ENOMEM;
412 
413 	param = (struct ec_params_lightbar *)msg->data;
414 	param->cmd = LIGHTBAR_CMD_SEQ;
415 	param->seq.num = num;
416 	ret = lb_throttle();
417 	if (ret)
418 		goto exit;
419 
420 	ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
421 	if (ret < 0)
422 		goto exit;
423 
424 	ret = count;
425 exit:
426 	kfree(msg);
427 	return ret;
428 }
429 
430 static ssize_t program_store(struct device *dev, struct device_attribute *attr,
431 			     const char *buf, size_t count)
432 {
433 	int extra_bytes, max_size, ret;
434 	struct ec_params_lightbar *param;
435 	struct cros_ec_command *msg;
436 	struct cros_ec_dev *ec = to_cros_ec_dev(dev);
437 
438 	/*
439 	 * We might need to reject the program for size reasons. The EC
440 	 * enforces a maximum program size, but we also don't want to try
441 	 * and send a program that is too big for the protocol. In order
442 	 * to ensure the latter, we also need to ensure we have extra bytes
443 	 * to represent the rest of the packet.
444 	 */
445 	extra_bytes = sizeof(*param) - sizeof(param->set_program.data);
446 	max_size = min(EC_LB_PROG_LEN, ec->ec_dev->max_request - extra_bytes);
447 	if (count > max_size) {
448 		dev_err(dev, "Program is %u bytes, too long to send (max: %u)",
449 			(unsigned int)count, max_size);
450 
451 		return -EINVAL;
452 	}
453 
454 	msg = alloc_lightbar_cmd_msg(ec);
455 	if (!msg)
456 		return -ENOMEM;
457 
458 	ret = lb_throttle();
459 	if (ret)
460 		goto exit;
461 
462 	dev_info(dev, "Copying %zu byte program to EC", count);
463 
464 	param = (struct ec_params_lightbar *)msg->data;
465 	param->cmd = LIGHTBAR_CMD_SET_PROGRAM;
466 
467 	param->set_program.size = count;
468 	memcpy(param->set_program.data, buf, count);
469 
470 	/*
471 	 * We need to set the message size manually or else it will use
472 	 * EC_LB_PROG_LEN. This might be too long, and the program
473 	 * is unlikely to use all of the space.
474 	 */
475 	msg->outsize = count + extra_bytes;
476 
477 	ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg);
478 	if (ret < 0)
479 		goto exit;
480 
481 	ret = count;
482 exit:
483 	kfree(msg);
484 
485 	return ret;
486 }
487 
488 static ssize_t userspace_control_show(struct device *dev,
489 				      struct device_attribute *attr,
490 				      char *buf)
491 {
492 	return sysfs_emit(buf, "%d\n", userspace_control);
493 }
494 
495 static ssize_t userspace_control_store(struct device *dev,
496 				       struct device_attribute *attr,
497 				       const char *buf,
498 				       size_t count)
499 {
500 	bool enable;
501 	int ret;
502 
503 	ret = kstrtobool(buf, &enable);
504 	if (ret < 0)
505 		return ret;
506 
507 	userspace_control = enable;
508 
509 	return count;
510 }
511 
512 /* Module initialization */
513 
514 static DEVICE_ATTR_RW(interval_msec);
515 static DEVICE_ATTR_RO(version);
516 static DEVICE_ATTR_WO(brightness);
517 static DEVICE_ATTR_WO(led_rgb);
518 static DEVICE_ATTR_RW(sequence);
519 static DEVICE_ATTR_WO(program);
520 static DEVICE_ATTR_RW(userspace_control);
521 
522 static struct attribute *__lb_cmds_attrs[] = {
523 	&dev_attr_interval_msec.attr,
524 	&dev_attr_version.attr,
525 	&dev_attr_brightness.attr,
526 	&dev_attr_led_rgb.attr,
527 	&dev_attr_sequence.attr,
528 	&dev_attr_program.attr,
529 	&dev_attr_userspace_control.attr,
530 	NULL,
531 };
532 
533 static const struct attribute_group cros_ec_lightbar_attr_group = {
534 	.name = "lightbar",
535 	.attrs = __lb_cmds_attrs,
536 };
537 
538 static int cros_ec_lightbar_probe(struct platform_device *pd)
539 {
540 	struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
541 	struct cros_ec_platform *pdata = dev_get_platdata(ec_dev->dev);
542 	struct device *dev = &pd->dev;
543 	int ret;
544 
545 	/*
546 	 * Only instantiate the lightbar if the EC name is 'cros_ec'. Other EC
547 	 * devices like 'cros_pd' doesn't have a lightbar.
548 	 */
549 	if (strcmp(pdata->ec_name, CROS_EC_DEV_NAME) != 0)
550 		return -ENODEV;
551 
552 	/*
553 	 * Ask then for the lightbar version, if it's 0 then the 'cros_ec'
554 	 * doesn't have a lightbar.
555 	 */
556 	if (!get_lightbar_version(ec_dev, NULL, NULL))
557 		return -ENODEV;
558 
559 	/* Take control of the lightbar from the EC. */
560 	has_manual_suspend = (lb_manual_suspend_ctrl(ec_dev, 1) != -EINVAL);
561 
562 	ret = sysfs_create_group(&ec_dev->class_dev.kobj,
563 				 &cros_ec_lightbar_attr_group);
564 	if (ret < 0)
565 		dev_err(dev, "failed to create %s attributes. err=%d\n",
566 			cros_ec_lightbar_attr_group.name, ret);
567 
568 	return ret;
569 }
570 
571 static void cros_ec_lightbar_remove(struct platform_device *pd)
572 {
573 	struct cros_ec_dev *ec_dev = dev_get_drvdata(pd->dev.parent);
574 
575 	sysfs_remove_group(&ec_dev->class_dev.kobj,
576 			   &cros_ec_lightbar_attr_group);
577 
578 	/* Let the EC take over the lightbar again. */
579 	if (has_manual_suspend)
580 		lb_manual_suspend_ctrl(ec_dev, 0);
581 }
582 
583 static int __maybe_unused cros_ec_lightbar_resume(struct device *dev)
584 {
585 	struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
586 
587 	if (userspace_control || !has_manual_suspend)
588 		return 0;
589 
590 	return lb_send_empty_cmd(ec_dev, LIGHTBAR_CMD_RESUME);
591 }
592 
593 static int __maybe_unused cros_ec_lightbar_suspend(struct device *dev)
594 {
595 	struct cros_ec_dev *ec_dev = dev_get_drvdata(dev->parent);
596 
597 	if (userspace_control || !has_manual_suspend)
598 		return 0;
599 
600 	return lb_send_empty_cmd(ec_dev, LIGHTBAR_CMD_SUSPEND);
601 }
602 
603 static SIMPLE_DEV_PM_OPS(cros_ec_lightbar_pm_ops,
604 			 cros_ec_lightbar_suspend, cros_ec_lightbar_resume);
605 
606 static const struct platform_device_id cros_ec_lightbar_id[] = {
607 	{ DRV_NAME, 0 },
608 	{}
609 };
610 MODULE_DEVICE_TABLE(platform, cros_ec_lightbar_id);
611 
612 static struct platform_driver cros_ec_lightbar_driver = {
613 	.driver = {
614 		.name = DRV_NAME,
615 		.pm = &cros_ec_lightbar_pm_ops,
616 		.probe_type = PROBE_PREFER_ASYNCHRONOUS,
617 	},
618 	.probe = cros_ec_lightbar_probe,
619 	.remove = cros_ec_lightbar_remove,
620 	.id_table = cros_ec_lightbar_id,
621 };
622 
623 module_platform_driver(cros_ec_lightbar_driver);
624 
625 MODULE_LICENSE("GPL");
626 MODULE_DESCRIPTION("Expose the Chromebook Pixel's lightbar to userspace");
627