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