1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Miscellaneous character driver for ChromeOS Embedded Controller 4 * 5 * Copyright 2014 Google, Inc. 6 * Copyright 2019 Google LLC 7 * 8 * This file is a rework and part of the code is ported from 9 * drivers/mfd/cros_ec_dev.c that was originally written by 10 * Bill Richardson. 11 */ 12 13 #include <linux/init.h> 14 #include <linux/device.h> 15 #include <linux/fs.h> 16 #include <linux/kref.h> 17 #include <linux/miscdevice.h> 18 #include <linux/mod_devicetable.h> 19 #include <linux/module.h> 20 #include <linux/notifier.h> 21 #include <linux/platform_data/cros_ec_chardev.h> 22 #include <linux/platform_data/cros_ec_commands.h> 23 #include <linux/platform_data/cros_ec_proto.h> 24 #include <linux/platform_device.h> 25 #include <linux/poll.h> 26 #include <linux/rwsem.h> 27 #include <linux/slab.h> 28 #include <linux/types.h> 29 #include <linux/uaccess.h> 30 31 #define DRV_NAME "cros-ec-chardev" 32 33 /* Arbitrary bounded size for the event queue */ 34 #define CROS_MAX_EVENT_LEN PAGE_SIZE 35 36 /* 37 * Platform device driver data. 38 */ 39 struct chardev_pdata { 40 struct miscdevice misc; 41 struct kref kref; 42 struct rw_semaphore ec_dev_sem; 43 struct cros_ec_device *ec_dev; 44 u16 cmd_offset; 45 struct blocking_notifier_head subscribers; 46 struct notifier_block relay; 47 }; 48 49 static void chardev_pdata_release(struct kref *kref) 50 { 51 struct chardev_pdata *pdata = container_of(kref, typeof(*pdata), kref); 52 53 kfree(pdata); 54 } 55 56 static int cros_ec_chardev_relay_event(struct notifier_block *nb, 57 unsigned long queued_during_suspend, 58 void *_notify) 59 { 60 struct chardev_pdata *pdata = container_of(nb, typeof(*pdata), relay); 61 62 blocking_notifier_call_chain(&pdata->subscribers, queued_during_suspend, 63 _notify); 64 return NOTIFY_OK; 65 } 66 67 struct chardev_priv { 68 struct notifier_block notifier; 69 wait_queue_head_t wait_event; 70 unsigned long event_mask; 71 struct list_head events; 72 size_t event_len; 73 struct chardev_pdata *pdata; 74 }; 75 76 struct ec_event { 77 struct list_head node; 78 size_t size; 79 u8 event_type; 80 u8 data[]; 81 }; 82 83 static int ec_get_version(struct chardev_priv *priv, char *str, int maxlen) 84 { 85 static const char * const current_image_name[] = { 86 "unknown", "read-only", "read-write", "invalid", 87 }; 88 struct ec_response_get_version *resp; 89 struct cros_ec_command *msg; 90 int ret; 91 92 msg = kzalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); 93 if (!msg) 94 return -ENOMEM; 95 96 msg->command = EC_CMD_GET_VERSION + priv->pdata->cmd_offset; 97 msg->insize = sizeof(*resp); 98 99 ret = cros_ec_cmd_xfer_status(priv->pdata->ec_dev, msg); 100 if (ret < 0) { 101 snprintf(str, maxlen, 102 "Unknown EC version, returned error: %d\n", 103 msg->result); 104 goto exit; 105 } 106 107 resp = (struct ec_response_get_version *)msg->data; 108 if (resp->current_image >= ARRAY_SIZE(current_image_name)) 109 resp->current_image = 3; /* invalid */ 110 111 snprintf(str, maxlen, "%s\n%s\n%s\n%s\n", CROS_EC_DEV_VERSION, 112 resp->version_string_ro, resp->version_string_rw, 113 current_image_name[resp->current_image]); 114 115 ret = 0; 116 exit: 117 kfree(msg); 118 return ret; 119 } 120 121 static int cros_ec_chardev_mkbp_event(struct notifier_block *nb, 122 unsigned long queued_during_suspend, 123 void *_notify) 124 { 125 struct chardev_priv *priv = container_of(nb, struct chardev_priv, 126 notifier); 127 struct cros_ec_device *ec_dev; 128 struct ec_event *event; 129 unsigned long event_bit; 130 int total_size; 131 132 guard(rwsem_read)(&priv->pdata->ec_dev_sem); 133 if (!priv->pdata->ec_dev) 134 return NOTIFY_DONE; 135 ec_dev = priv->pdata->ec_dev; 136 137 event_bit = 1 << ec_dev->event_data.event_type; 138 total_size = sizeof(*event) + ec_dev->event_size; 139 140 if (!(event_bit & priv->event_mask) || 141 (priv->event_len + total_size) > CROS_MAX_EVENT_LEN) 142 return NOTIFY_DONE; 143 144 event = kzalloc(total_size, GFP_KERNEL); 145 if (!event) 146 return NOTIFY_DONE; 147 148 event->size = ec_dev->event_size; 149 event->event_type = ec_dev->event_data.event_type; 150 memcpy(event->data, &ec_dev->event_data.data, ec_dev->event_size); 151 152 spin_lock(&priv->wait_event.lock); 153 list_add_tail(&event->node, &priv->events); 154 priv->event_len += total_size; 155 wake_up_locked(&priv->wait_event); 156 spin_unlock(&priv->wait_event.lock); 157 158 return NOTIFY_OK; 159 } 160 161 static struct ec_event *cros_ec_chardev_fetch_event(struct chardev_priv *priv, 162 bool fetch, bool block) 163 { 164 struct ec_event *event; 165 int err; 166 167 spin_lock(&priv->wait_event.lock); 168 if (!block && list_empty(&priv->events)) { 169 event = ERR_PTR(-EWOULDBLOCK); 170 goto out; 171 } 172 173 if (!fetch) { 174 event = NULL; 175 goto out; 176 } 177 178 err = wait_event_interruptible_locked(priv->wait_event, 179 !list_empty(&priv->events)); 180 if (err) { 181 event = ERR_PTR(err); 182 goto out; 183 } 184 185 event = list_first_entry(&priv->events, struct ec_event, node); 186 list_del(&event->node); 187 priv->event_len -= sizeof(*event) + event->size; 188 189 out: 190 spin_unlock(&priv->wait_event.lock); 191 return event; 192 } 193 194 /* 195 * Device file ops 196 */ 197 static int cros_ec_chardev_open(struct inode *inode, struct file *filp) 198 { 199 struct miscdevice *mdev = filp->private_data; 200 struct chardev_pdata *pdata = container_of(mdev, typeof(*pdata), misc); 201 struct chardev_priv *priv; 202 int ret; 203 204 priv = kzalloc_obj(*priv); 205 if (!priv) 206 return -ENOMEM; 207 208 priv->pdata = pdata; 209 kref_get(&pdata->kref); 210 filp->private_data = priv; 211 INIT_LIST_HEAD(&priv->events); 212 init_waitqueue_head(&priv->wait_event); 213 nonseekable_open(inode, filp); 214 215 priv->notifier.notifier_call = cros_ec_chardev_mkbp_event; 216 ret = blocking_notifier_chain_register(&pdata->subscribers, 217 &priv->notifier); 218 if (ret) { 219 dev_err(pdata->ec_dev->dev, 220 "failed to register event notifier\n"); 221 kref_put(&priv->pdata->kref, chardev_pdata_release); 222 kfree(priv); 223 } 224 225 return ret; 226 } 227 228 static __poll_t cros_ec_chardev_poll(struct file *filp, poll_table *wait) 229 { 230 struct chardev_priv *priv = filp->private_data; 231 232 guard(rwsem_read)(&priv->pdata->ec_dev_sem); 233 if (!priv->pdata->ec_dev) 234 return EPOLLHUP; 235 236 poll_wait(filp, &priv->wait_event, wait); 237 238 if (list_empty(&priv->events)) 239 return 0; 240 241 return EPOLLIN | EPOLLRDNORM; 242 } 243 244 static ssize_t cros_ec_chardev_read(struct file *filp, char __user *buffer, 245 size_t length, loff_t *offset) 246 { 247 char msg[sizeof(struct ec_response_get_version) + 248 sizeof(CROS_EC_DEV_VERSION)]; 249 struct chardev_priv *priv = filp->private_data; 250 size_t count; 251 int ret; 252 253 guard(rwsem_read)(&priv->pdata->ec_dev_sem); 254 if (!priv->pdata->ec_dev) 255 return -ENODEV; 256 257 if (priv->event_mask) { /* queued MKBP event */ 258 struct ec_event *event; 259 260 event = cros_ec_chardev_fetch_event(priv, length != 0, 261 !(filp->f_flags & O_NONBLOCK)); 262 if (IS_ERR(event)) 263 return PTR_ERR(event); 264 /* 265 * length == 0 is special - no IO is done but we check 266 * for error conditions. 267 */ 268 if (length == 0) 269 return 0; 270 271 /* The event is 1 byte of type plus the payload */ 272 count = min(length, event->size + 1); 273 ret = copy_to_user(buffer, &event->event_type, count); 274 kfree(event); 275 if (ret) /* the copy failed */ 276 return -EFAULT; 277 *offset = count; 278 return count; 279 } 280 281 /* 282 * Legacy behavior if no event mask is defined 283 */ 284 if (*offset != 0) 285 return 0; 286 287 ret = ec_get_version(priv, msg, sizeof(msg)); 288 if (ret) 289 return ret; 290 291 count = min(length, strlen(msg)); 292 293 if (copy_to_user(buffer, msg, count)) 294 return -EFAULT; 295 296 *offset = count; 297 return count; 298 } 299 300 static int cros_ec_chardev_release(struct inode *inode, struct file *filp) 301 { 302 struct chardev_priv *priv = filp->private_data; 303 struct ec_event *event, *e; 304 305 blocking_notifier_chain_unregister(&priv->pdata->subscribers, 306 &priv->notifier); 307 kref_put(&priv->pdata->kref, chardev_pdata_release); 308 309 list_for_each_entry_safe(event, e, &priv->events, node) { 310 list_del(&event->node); 311 kfree(event); 312 } 313 kfree(priv); 314 315 return 0; 316 } 317 318 /* 319 * Ioctls 320 */ 321 static long cros_ec_chardev_ioctl_xcmd(struct chardev_priv *priv, void __user *arg) 322 { 323 struct cros_ec_command *s_cmd; 324 struct cros_ec_command u_cmd; 325 long ret; 326 327 if (copy_from_user(&u_cmd, arg, sizeof(u_cmd))) 328 return -EFAULT; 329 330 if (u_cmd.outsize > EC_MAX_MSG_BYTES || 331 u_cmd.insize > EC_MAX_MSG_BYTES) 332 return -EINVAL; 333 334 s_cmd = kzalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize), 335 GFP_KERNEL); 336 if (!s_cmd) 337 return -ENOMEM; 338 339 if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) { 340 ret = -EFAULT; 341 goto exit; 342 } 343 344 if (u_cmd.outsize != s_cmd->outsize || 345 u_cmd.insize != s_cmd->insize) { 346 ret = -EINVAL; 347 goto exit; 348 } 349 350 s_cmd->command += priv->pdata->cmd_offset; 351 ret = cros_ec_cmd_xfer(priv->pdata->ec_dev, s_cmd); 352 /* Only copy data to userland if data was received. */ 353 if (ret < 0) 354 goto exit; 355 356 if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize)) 357 ret = -EFAULT; 358 exit: 359 kfree(s_cmd); 360 return ret; 361 } 362 363 static long cros_ec_chardev_ioctl_readmem(struct chardev_priv *priv, void __user *arg) 364 { 365 struct cros_ec_device *ec_dev = priv->pdata->ec_dev; 366 struct cros_ec_readmem s_mem = { }; 367 long num; 368 369 /* Not every platform supports direct reads */ 370 if (!ec_dev->cmd_readmem) 371 return -ENOTTY; 372 373 if (copy_from_user(&s_mem, arg, sizeof(s_mem))) 374 return -EFAULT; 375 376 if (s_mem.bytes > sizeof(s_mem.buffer)) 377 return -EINVAL; 378 379 num = ec_dev->cmd_readmem(ec_dev, s_mem.offset, s_mem.bytes, 380 s_mem.buffer); 381 if (num <= 0) 382 return num; 383 384 if (copy_to_user((void __user *)arg, &s_mem, sizeof(s_mem))) 385 return -EFAULT; 386 387 return num; 388 } 389 390 static long cros_ec_chardev_ioctl(struct file *filp, unsigned int cmd, 391 unsigned long arg) 392 { 393 struct chardev_priv *priv = filp->private_data; 394 395 guard(rwsem_read)(&priv->pdata->ec_dev_sem); 396 if (!priv->pdata->ec_dev) 397 return -ENODEV; 398 399 if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC) 400 return -ENOTTY; 401 402 switch (cmd) { 403 case CROS_EC_DEV_IOCXCMD: 404 return cros_ec_chardev_ioctl_xcmd(priv, (void __user *)arg); 405 case CROS_EC_DEV_IOCRDMEM: 406 return cros_ec_chardev_ioctl_readmem(priv, (void __user *)arg); 407 case CROS_EC_DEV_IOCEVENTMASK: 408 priv->event_mask = arg; 409 return 0; 410 } 411 412 return -ENOTTY; 413 } 414 415 static const struct file_operations chardev_fops = { 416 .open = cros_ec_chardev_open, 417 .poll = cros_ec_chardev_poll, 418 .read = cros_ec_chardev_read, 419 .release = cros_ec_chardev_release, 420 .unlocked_ioctl = cros_ec_chardev_ioctl, 421 #ifdef CONFIG_COMPAT 422 .compat_ioctl = cros_ec_chardev_ioctl, 423 #endif 424 }; 425 426 static int cros_ec_chardev_probe(struct platform_device *pdev) 427 { 428 struct cros_ec_dev *ec = dev_get_drvdata(pdev->dev.parent); 429 struct cros_ec_platform *ec_platform = dev_get_platdata(ec->dev); 430 struct chardev_pdata *pdata; 431 int ret; 432 433 pdata = kzalloc_obj(*pdata); 434 if (!pdata) 435 return -ENOMEM; 436 437 platform_set_drvdata(pdev, pdata); 438 kref_init(&pdata->kref); 439 init_rwsem(&pdata->ec_dev_sem); 440 pdata->ec_dev = ec->ec_dev; 441 pdata->cmd_offset = ec->cmd_offset; 442 BLOCKING_INIT_NOTIFIER_HEAD(&pdata->subscribers); 443 pdata->relay.notifier_call = cros_ec_chardev_relay_event; 444 ret = blocking_notifier_chain_register(&pdata->ec_dev->event_notifier, 445 &pdata->relay); 446 if (ret) { 447 dev_err(&pdev->dev, "failed to register event notifier\n"); 448 goto err_put_pdata; 449 } 450 451 pdata->misc.minor = MISC_DYNAMIC_MINOR; 452 pdata->misc.fops = &chardev_fops; 453 pdata->misc.name = ec_platform->ec_name; 454 pdata->misc.parent = pdev->dev.parent; 455 456 ret = misc_register(&pdata->misc); 457 if (ret) { 458 dev_err(&pdev->dev, "failed to register misc device\n"); 459 goto err_unregister_notifier; 460 } 461 462 return 0; 463 err_unregister_notifier: 464 blocking_notifier_chain_unregister(&pdata->ec_dev->event_notifier, 465 &pdata->relay); 466 err_put_pdata: 467 kref_put(&pdata->kref, chardev_pdata_release); 468 return ret; 469 } 470 471 static void cros_ec_chardev_remove(struct platform_device *pdev) 472 { 473 struct chardev_pdata *pdata = platform_get_drvdata(pdev); 474 struct cros_ec_device *ec_dev = pdata->ec_dev; 475 476 /* stop new fops from being created */ 477 misc_deregister(&pdata->misc); 478 /* stop existing fops from running */ 479 scoped_guard(rwsem_write, &pdata->ec_dev_sem) 480 pdata->ec_dev = NULL; 481 482 blocking_notifier_chain_unregister(&ec_dev->event_notifier, 483 &pdata->relay); 484 kref_put(&pdata->kref, chardev_pdata_release); 485 } 486 487 static const struct platform_device_id cros_ec_chardev_id[] = { 488 { DRV_NAME, 0 }, 489 {} 490 }; 491 MODULE_DEVICE_TABLE(platform, cros_ec_chardev_id); 492 493 static struct platform_driver cros_ec_chardev_driver = { 494 .driver = { 495 .name = DRV_NAME, 496 }, 497 .probe = cros_ec_chardev_probe, 498 .remove = cros_ec_chardev_remove, 499 .id_table = cros_ec_chardev_id, 500 }; 501 502 module_platform_driver(cros_ec_chardev_driver); 503 504 MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>"); 505 MODULE_DESCRIPTION("ChromeOS EC Miscellaneous Character Driver"); 506 MODULE_LICENSE("GPL"); 507