1 // SPDX-License-Identifier: GPL-2.0
3 * Miscellaneous character driver for ChromeOS Embedded Controller
5 * Copyright 2014 Google, Inc.
6 * Copyright 2019 Google LLC
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
13 #include <linux/init.h>
14 #include <linux/device.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>
28 #define DRV_NAME "cros-ec-chardev"
30 /* Arbitrary bounded size for the event queue */
31 #define CROS_MAX_EVENT_LEN PAGE_SIZE
34 struct cros_ec_dev
*ec_dev
;
35 struct miscdevice misc
;
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
;
48 struct list_head node
;
54 static int ec_get_version(struct cros_ec_dev
*ec
, char *str
, int maxlen
)
56 static const char * const current_image_name
[] = {
57 "unknown", "read-only", "read-write", "invalid",
59 struct ec_response_get_version
*resp
;
60 struct cros_ec_command
*msg
;
63 msg
= kzalloc(sizeof(*msg
) + sizeof(*resp
), GFP_KERNEL
);
67 msg
->command
= EC_CMD_GET_VERSION
+ ec
->cmd_offset
;
68 msg
->insize
= sizeof(*resp
);
70 ret
= cros_ec_cmd_xfer_status(ec
->ec_dev
, msg
);
73 "Unknown EC version, returned error: %d\n",
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 */
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
]);
92 static int cros_ec_chardev_mkbp_event(struct notifier_block
*nb
,
93 unsigned long queued_during_suspend
,
96 struct chardev_priv
*priv
= container_of(nb
, struct chardev_priv
,
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
;
103 if (!(event_bit
& priv
->event_mask
) ||
104 (priv
->event_len
+ total_size
) > CROS_MAX_EVENT_LEN
)
107 event
= kzalloc(total_size
, GFP_KERNEL
);
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
);
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
);
124 static struct ec_event
*cros_ec_chardev_fetch_event(struct chardev_priv
*priv
,
125 bool fetch
, bool block
)
127 struct ec_event
*event
;
130 spin_lock(&priv
->wait_event
.lock
);
131 if (!block
&& list_empty(&priv
->events
)) {
132 event
= ERR_PTR(-EWOULDBLOCK
);
141 err
= wait_event_interruptible_locked(priv
->wait_event
,
142 !list_empty(&priv
->events
));
144 event
= ERR_PTR(err
);
148 event
= list_first_entry(&priv
->events
, struct ec_event
, node
);
149 list_del(&event
->node
);
150 priv
->event_len
-= sizeof(*event
) + event
->size
;
153 spin_unlock(&priv
->wait_event
.lock
);
160 static int cros_ec_chardev_open(struct inode
*inode
, struct file
*filp
)
162 struct miscdevice
*mdev
= filp
->private_data
;
163 struct cros_ec_dev
*ec_dev
= dev_get_drvdata(mdev
->parent
);
164 struct chardev_priv
*priv
;
167 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
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
);
177 priv
->notifier
.notifier_call
= cros_ec_chardev_mkbp_event
;
178 ret
= blocking_notifier_chain_register(&ec_dev
->ec_dev
->event_notifier
,
181 dev_err(ec_dev
->dev
, "failed to register event notifier\n");
188 static __poll_t
cros_ec_chardev_poll(struct file
*filp
, poll_table
*wait
)
190 struct chardev_priv
*priv
= filp
->private_data
;
192 poll_wait(filp
, &priv
->wait_event
, wait
);
194 if (list_empty(&priv
->events
))
197 return EPOLLIN
| EPOLLRDNORM
;
200 static ssize_t
cros_ec_chardev_read(struct file
*filp
, char __user
*buffer
,
201 size_t length
, loff_t
*offset
)
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
;
210 if (priv
->event_mask
) { /* queued MKBP event */
211 struct ec_event
*event
;
213 event
= cros_ec_chardev_fetch_event(priv
, length
!= 0,
214 !(filp
->f_flags
& O_NONBLOCK
));
216 return PTR_ERR(event
);
218 * length == 0 is special - no IO is done but we check
219 * for error conditions.
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
);
228 if (ret
) /* the copy failed */
235 * Legacy behavior if no event mask is defined
240 ret
= ec_get_version(ec_dev
, msg
, sizeof(msg
));
244 count
= min(length
, strlen(msg
));
246 if (copy_to_user(buffer
, msg
, count
))
253 static int cros_ec_chardev_release(struct inode
*inode
, struct file
*filp
)
255 struct chardev_priv
*priv
= filp
->private_data
;
256 struct cros_ec_dev
*ec_dev
= priv
->ec_dev
;
257 struct ec_event
*event
, *e
;
259 blocking_notifier_chain_unregister(&ec_dev
->ec_dev
->event_notifier
,
262 list_for_each_entry_safe(event
, e
, &priv
->events
, node
) {
263 list_del(&event
->node
);
274 static long cros_ec_chardev_ioctl_xcmd(struct cros_ec_dev
*ec
, void __user
*arg
)
276 struct cros_ec_command
*s_cmd
;
277 struct cros_ec_command u_cmd
;
280 if (copy_from_user(&u_cmd
, arg
, sizeof(u_cmd
)))
283 if (u_cmd
.outsize
> EC_MAX_MSG_BYTES
||
284 u_cmd
.insize
> EC_MAX_MSG_BYTES
)
287 s_cmd
= kmalloc(sizeof(*s_cmd
) + max(u_cmd
.outsize
, u_cmd
.insize
),
292 if (copy_from_user(s_cmd
, arg
, sizeof(*s_cmd
) + u_cmd
.outsize
)) {
297 if (u_cmd
.outsize
!= s_cmd
->outsize
||
298 u_cmd
.insize
!= s_cmd
->insize
) {
303 s_cmd
->command
+= ec
->cmd_offset
;
304 ret
= cros_ec_cmd_xfer_status(ec
->ec_dev
, s_cmd
);
305 /* Only copy data to userland if data was received. */
309 if (copy_to_user(arg
, s_cmd
, sizeof(*s_cmd
) + s_cmd
->insize
))
316 static long cros_ec_chardev_ioctl_readmem(struct cros_ec_dev
*ec
,
319 struct cros_ec_device
*ec_dev
= ec
->ec_dev
;
320 struct cros_ec_readmem s_mem
= { };
323 /* Not every platform supports direct reads */
324 if (!ec_dev
->cmd_readmem
)
327 if (copy_from_user(&s_mem
, arg
, sizeof(s_mem
)))
330 num
= ec_dev
->cmd_readmem(ec_dev
, s_mem
.offset
, s_mem
.bytes
,
335 if (copy_to_user((void __user
*)arg
, &s_mem
, sizeof(s_mem
)))
341 static long cros_ec_chardev_ioctl(struct file
*filp
, unsigned int cmd
,
344 struct chardev_priv
*priv
= filp
->private_data
;
345 struct cros_ec_dev
*ec
= priv
->ec_dev
;
347 if (_IOC_TYPE(cmd
) != CROS_EC_DEV_IOC
)
351 case CROS_EC_DEV_IOCXCMD
:
352 return cros_ec_chardev_ioctl_xcmd(ec
, (void __user
*)arg
);
353 case CROS_EC_DEV_IOCRDMEM
:
354 return cros_ec_chardev_ioctl_readmem(ec
, (void __user
*)arg
);
355 case CROS_EC_DEV_IOCEVENTMASK
:
356 priv
->event_mask
= arg
;
363 static const struct file_operations chardev_fops
= {
364 .open
= cros_ec_chardev_open
,
365 .poll
= cros_ec_chardev_poll
,
366 .read
= cros_ec_chardev_read
,
367 .release
= cros_ec_chardev_release
,
368 .unlocked_ioctl
= cros_ec_chardev_ioctl
,
370 .compat_ioctl
= cros_ec_chardev_ioctl
,
374 static int cros_ec_chardev_probe(struct platform_device
*pdev
)
376 struct cros_ec_dev
*ec_dev
= dev_get_drvdata(pdev
->dev
.parent
);
377 struct cros_ec_platform
*ec_platform
= dev_get_platdata(ec_dev
->dev
);
378 struct chardev_data
*data
;
380 /* Create a char device: we want to create it anew */
381 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
385 data
->ec_dev
= ec_dev
;
386 data
->misc
.minor
= MISC_DYNAMIC_MINOR
;
387 data
->misc
.fops
= &chardev_fops
;
388 data
->misc
.name
= ec_platform
->ec_name
;
389 data
->misc
.parent
= pdev
->dev
.parent
;
391 dev_set_drvdata(&pdev
->dev
, data
);
393 return misc_register(&data
->misc
);
396 static int cros_ec_chardev_remove(struct platform_device
*pdev
)
398 struct chardev_data
*data
= dev_get_drvdata(&pdev
->dev
);
400 misc_deregister(&data
->misc
);
405 static struct platform_driver cros_ec_chardev_driver
= {
409 .probe
= cros_ec_chardev_probe
,
410 .remove
= cros_ec_chardev_remove
,
413 module_platform_driver(cros_ec_chardev_driver
);
415 MODULE_ALIAS("platform:" DRV_NAME
);
416 MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>");
417 MODULE_DESCRIPTION("ChromeOS EC Miscellaneous Character Driver");
418 MODULE_LICENSE("GPL");