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/miscdevice.h> 17 #include <linux/module.h> 18 #include <linux/notifier.h> 19 #include <linux/platform_data/cros_ec_chardev.h> 20 #include <linux/platform_data/cros_ec_commands.h> 21 #include <linux/platform_data/cros_ec_proto.h> 22 #include <linux/platform_device.h> 23 #include <linux/poll.h> 24 #include <linux/slab.h> 25 #include <linux/types.h> 26 #include <linux/uaccess.h> 27 28 #define DRV_NAME "cros-ec-chardev" 29 30 /* Arbitrary bounded size for the event queue */ 31 #define CROS_MAX_EVENT_LEN PAGE_SIZE 32 33 struct chardev_data { 34 struct cros_ec_dev *ec_dev; 35 struct miscdevice misc; 36 }; 37 38 struct chardev_priv { 39 struct cros_ec_dev *ec_dev; 40 struct notifier_block notifier; 41 wait_queue_head_t wait_event; 42 unsigned long event_mask; 43 struct list_head events; 44 size_t event_len; 45 }; 46 47 struct ec_event { 48 struct list_head node; 49 size_t size; 50 u8 event_type; 51 u8 data[]; 52 }; 53 54 static int ec_get_version(struct cros_ec_dev *ec, char *str, int maxlen) 55 { 56 static const char * const current_image_name[] = { 57 "unknown", "read-only", "read-write", "invalid", 58 }; 59 struct ec_response_get_version *resp; 60 struct cros_ec_command *msg; 61 int ret; 62 63 msg = kzalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); 64 if (!msg) 65 return -ENOMEM; 66 67 msg->command = EC_CMD_GET_VERSION + ec->cmd_offset; 68 msg->insize = sizeof(*resp); 69 70 ret = cros_ec_cmd_xfer_status(ec->ec_dev, msg); 71 if (ret < 0) { 72 snprintf(str, maxlen, 73 "Unknown EC version, returned error: %d\n", 74 msg->result); 75 goto exit; 76 } 77 78 resp = (struct ec_response_get_version *)msg->data; 79 if (resp->current_image >= ARRAY_SIZE(current_image_name)) 80 resp->current_image = 3; /* invalid */ 81 82 snprintf(str, maxlen, "%s\n%s\n%s\n%s\n", CROS_EC_DEV_VERSION, 83 resp->version_string_ro, resp->version_string_rw, 84 current_image_name[resp->current_image]); 85 86 ret = 0; 87 exit: 88 kfree(msg); 89 return ret; 90 } 91 92 static int cros_ec_chardev_mkbp_event(struct notifier_block *nb, 93 unsigned long queued_during_suspend, 94 void *_notify) 95 { 96 struct chardev_priv *priv = container_of(nb, struct chardev_priv, 97 notifier); 98 struct cros_ec_device *ec_dev = priv->ec_dev->ec_dev; 99 struct ec_event *event; 100 unsigned long event_bit = 1 << ec_dev->event_data.event_type; 101 int total_size = sizeof(*event) + ec_dev->event_size; 102 103 if (!(event_bit & priv->event_mask) || 104 (priv->event_len + total_size) > CROS_MAX_EVENT_LEN) 105 return NOTIFY_DONE; 106 107 event = kzalloc(total_size, GFP_KERNEL); 108 if (!event) 109 return NOTIFY_DONE; 110 111 event->size = ec_dev->event_size; 112 event->event_type = ec_dev->event_data.event_type; 113 memcpy(event->data, &ec_dev->event_data.data, ec_dev->event_size); 114 115 spin_lock(&priv->wait_event.lock); 116 list_add_tail(&event->node, &priv->events); 117 priv->event_len += total_size; 118 wake_up_locked(&priv->wait_event); 119 spin_unlock(&priv->wait_event.lock); 120 121 return NOTIFY_OK; 122 } 123 124 static struct ec_event *cros_ec_chardev_fetch_event(struct chardev_priv *priv, 125 bool fetch, bool block) 126 { 127 struct ec_event *event; 128 int err; 129 130 spin_lock(&priv->wait_event.lock); 131 if (!block && list_empty(&priv->events)) { 132 event = ERR_PTR(-EWOULDBLOCK); 133 goto out; 134 } 135 136 if (!fetch) { 137 event = NULL; 138 goto out; 139 } 140 141 err = wait_event_interruptible_locked(priv->wait_event, 142 !list_empty(&priv->events)); 143 if (err) { 144 event = ERR_PTR(err); 145 goto out; 146 } 147 148 event = list_first_entry(&priv->events, struct ec_event, node); 149 list_del(&event->node); 150 priv->event_len -= sizeof(*event) + event->size; 151 152 out: 153 spin_unlock(&priv->wait_event.lock); 154 return event; 155 } 156 157 /* 158 * Device file ops 159 */ 160 static int cros_ec_chardev_open(struct inode *inode, struct file *filp) 161 { 162 struct miscdevice *mdev = filp->private_data; 163 struct cros_ec_dev *ec_dev = dev_get_drvdata(mdev->parent); 164 struct chardev_priv *priv; 165 int ret; 166 167 priv = kzalloc(sizeof(*priv), GFP_KERNEL); 168 if (!priv) 169 return -ENOMEM; 170 171 priv->ec_dev = ec_dev; 172 filp->private_data = priv; 173 INIT_LIST_HEAD(&priv->events); 174 init_waitqueue_head(&priv->wait_event); 175 nonseekable_open(inode, filp); 176 177 priv->notifier.notifier_call = cros_ec_chardev_mkbp_event; 178 ret = blocking_notifier_chain_register(&ec_dev->ec_dev->event_notifier, 179 &priv->notifier); 180 if (ret) { 181 dev_err(ec_dev->dev, "failed to register event notifier\n"); 182 kfree(priv); 183 } 184 185 return ret; 186 } 187 188 static __poll_t cros_ec_chardev_poll(struct file *filp, poll_table *wait) 189 { 190 struct chardev_priv *priv = filp->private_data; 191 192 poll_wait(filp, &priv->wait_event, wait); 193 194 if (list_empty(&priv->events)) 195 return 0; 196 197 return EPOLLIN | EPOLLRDNORM; 198 } 199 200 static ssize_t cros_ec_chardev_read(struct file *filp, char __user *buffer, 201 size_t length, loff_t *offset) 202 { 203 char msg[sizeof(struct ec_response_get_version) + 204 sizeof(CROS_EC_DEV_VERSION)]; 205 struct chardev_priv *priv = filp->private_data; 206 struct cros_ec_dev *ec_dev = priv->ec_dev; 207 size_t count; 208 int ret; 209 210 if (priv->event_mask) { /* queued MKBP event */ 211 struct ec_event *event; 212 213 event = cros_ec_chardev_fetch_event(priv, length != 0, 214 !(filp->f_flags & O_NONBLOCK)); 215 if (IS_ERR(event)) 216 return PTR_ERR(event); 217 /* 218 * length == 0 is special - no IO is done but we check 219 * for error conditions. 220 */ 221 if (length == 0) 222 return 0; 223 224 /* The event is 1 byte of type plus the payload */ 225 count = min(length, event->size + 1); 226 ret = copy_to_user(buffer, &event->event_type, count); 227 kfree(event); 228 if (ret) /* the copy failed */ 229 return -EFAULT; 230 *offset = count; 231 return count; 232 } 233 234 /* 235 * Legacy behavior if no event mask is defined 236 */ 237 if (*offset != 0) 238 return 0; 239 240 ret = ec_get_version(ec_dev, msg, sizeof(msg)); 241 if (ret) 242 return ret; 243 244 count = min(length, strlen(msg)); 245 246 if (copy_to_user(buffer, msg, count)) 247 return -EFAULT; 248 249 *offset = count; 250 return count; 251 } 252 253 static int cros_ec_chardev_release(struct inode *inode, struct file *filp) 254 { 255 struct chardev_priv *priv = filp->private_data; 256 struct cros_ec_dev *ec_dev = priv->ec_dev; 257 struct ec_event *event, *e; 258 259 blocking_notifier_chain_unregister(&ec_dev->ec_dev->event_notifier, 260 &priv->notifier); 261 262 list_for_each_entry_safe(event, e, &priv->events, node) { 263 list_del(&event->node); 264 kfree(event); 265 } 266 kfree(priv); 267 268 return 0; 269 } 270 271 /* 272 * Ioctls 273 */ 274 static long cros_ec_chardev_ioctl_xcmd(struct cros_ec_dev *ec, void __user *arg) 275 { 276 struct cros_ec_command *s_cmd; 277 struct cros_ec_command u_cmd; 278 long ret; 279 280 if (copy_from_user(&u_cmd, arg, sizeof(u_cmd))) 281 return -EFAULT; 282 283 if (u_cmd.outsize > EC_MAX_MSG_BYTES || 284 u_cmd.insize > EC_MAX_MSG_BYTES) 285 return -EINVAL; 286 287 s_cmd = kmalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize), 288 GFP_KERNEL); 289 if (!s_cmd) 290 return -ENOMEM; 291 292 if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) { 293 ret = -EFAULT; 294 goto exit; 295 } 296 297 if (u_cmd.outsize != s_cmd->outsize || 298 u_cmd.insize != s_cmd->insize) { 299 ret = -EINVAL; 300 goto exit; 301 } 302 303 s_cmd->command += ec->cmd_offset; 304 ret = cros_ec_cmd_xfer(ec->ec_dev, s_cmd); 305 /* Only copy data to userland if data was received. */ 306 if (ret < 0) 307 goto exit; 308 309 if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + s_cmd->insize)) 310 ret = -EFAULT; 311 exit: 312 kfree(s_cmd); 313 return ret; 314 } 315 316 static long cros_ec_chardev_ioctl_readmem(struct cros_ec_dev *ec, 317 void __user *arg) 318 { 319 struct cros_ec_device *ec_dev = ec->ec_dev; 320 struct cros_ec_readmem s_mem = { }; 321 long num; 322 323 /* Not every platform supports direct reads */ 324 if (!ec_dev->cmd_readmem) 325 return -ENOTTY; 326 327 if (copy_from_user(&s_mem, arg, sizeof(s_mem))) 328 return -EFAULT; 329 330 if (s_mem.bytes > sizeof(s_mem.buffer)) 331 return -EINVAL; 332 333 num = ec_dev->cmd_readmem(ec_dev, s_mem.offset, s_mem.bytes, 334 s_mem.buffer); 335 if (num <= 0) 336 return num; 337 338 if (copy_to_user((void __user *)arg, &s_mem, sizeof(s_mem))) 339 return -EFAULT; 340 341 return num; 342 } 343 344 static long cros_ec_chardev_ioctl(struct file *filp, unsigned int cmd, 345 unsigned long arg) 346 { 347 struct chardev_priv *priv = filp->private_data; 348 struct cros_ec_dev *ec = priv->ec_dev; 349 350 if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC) 351 return -ENOTTY; 352 353 switch (cmd) { 354 case CROS_EC_DEV_IOCXCMD: 355 return cros_ec_chardev_ioctl_xcmd(ec, (void __user *)arg); 356 case CROS_EC_DEV_IOCRDMEM: 357 return cros_ec_chardev_ioctl_readmem(ec, (void __user *)arg); 358 case CROS_EC_DEV_IOCEVENTMASK: 359 priv->event_mask = arg; 360 return 0; 361 } 362 363 return -ENOTTY; 364 } 365 366 static const struct file_operations chardev_fops = { 367 .open = cros_ec_chardev_open, 368 .poll = cros_ec_chardev_poll, 369 .read = cros_ec_chardev_read, 370 .release = cros_ec_chardev_release, 371 .unlocked_ioctl = cros_ec_chardev_ioctl, 372 #ifdef CONFIG_COMPAT 373 .compat_ioctl = cros_ec_chardev_ioctl, 374 #endif 375 }; 376 377 static int cros_ec_chardev_probe(struct platform_device *pdev) 378 { 379 struct cros_ec_dev *ec_dev = dev_get_drvdata(pdev->dev.parent); 380 struct cros_ec_platform *ec_platform = dev_get_platdata(ec_dev->dev); 381 struct chardev_data *data; 382 383 /* Create a char device: we want to create it anew */ 384 data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL); 385 if (!data) 386 return -ENOMEM; 387 388 data->ec_dev = ec_dev; 389 data->misc.minor = MISC_DYNAMIC_MINOR; 390 data->misc.fops = &chardev_fops; 391 data->misc.name = ec_platform->ec_name; 392 data->misc.parent = pdev->dev.parent; 393 394 dev_set_drvdata(&pdev->dev, data); 395 396 return misc_register(&data->misc); 397 } 398 399 static int cros_ec_chardev_remove(struct platform_device *pdev) 400 { 401 struct chardev_data *data = dev_get_drvdata(&pdev->dev); 402 403 misc_deregister(&data->misc); 404 405 return 0; 406 } 407 408 static struct platform_driver cros_ec_chardev_driver = { 409 .driver = { 410 .name = DRV_NAME, 411 }, 412 .probe = cros_ec_chardev_probe, 413 .remove = cros_ec_chardev_remove, 414 }; 415 416 module_platform_driver(cros_ec_chardev_driver); 417 418 MODULE_ALIAS("platform:" DRV_NAME); 419 MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>"); 420 MODULE_DESCRIPTION("ChromeOS EC Miscellaneous Character Driver"); 421 MODULE_LICENSE("GPL"); 422