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/mod_devicetable.h>
18 #include <linux/module.h>
19 #include <linux/notifier.h>
20 #include <linux/platform_data/cros_ec_chardev.h>
21 #include <linux/platform_data/cros_ec_commands.h>
22 #include <linux/platform_data/cros_ec_proto.h>
23 #include <linux/platform_device.h>
24 #include <linux/poll.h>
25 #include <linux/slab.h>
26 #include <linux/types.h>
27 #include <linux/uaccess.h>
29 #define DRV_NAME "cros-ec-chardev"
31 /* Arbitrary bounded size for the event queue */
32 #define CROS_MAX_EVENT_LEN PAGE_SIZE
35 struct cros_ec_dev
*ec_dev
;
36 struct miscdevice misc
;
40 struct cros_ec_dev
*ec_dev
;
41 struct notifier_block notifier
;
42 wait_queue_head_t wait_event
;
43 unsigned long event_mask
;
44 struct list_head events
;
49 struct list_head node
;
55 static int ec_get_version(struct cros_ec_dev
*ec
, char *str
, int maxlen
)
57 static const char * const current_image_name
[] = {
58 "unknown", "read-only", "read-write", "invalid",
60 struct ec_response_get_version
*resp
;
61 struct cros_ec_command
*msg
;
64 msg
= kzalloc(sizeof(*msg
) + sizeof(*resp
), GFP_KERNEL
);
68 msg
->command
= EC_CMD_GET_VERSION
+ ec
->cmd_offset
;
69 msg
->insize
= sizeof(*resp
);
71 ret
= cros_ec_cmd_xfer_status(ec
->ec_dev
, msg
);
74 "Unknown EC version, returned error: %d\n",
79 resp
= (struct ec_response_get_version
*)msg
->data
;
80 if (resp
->current_image
>= ARRAY_SIZE(current_image_name
))
81 resp
->current_image
= 3; /* invalid */
83 snprintf(str
, maxlen
, "%s\n%s\n%s\n%s\n", CROS_EC_DEV_VERSION
,
84 resp
->version_string_ro
, resp
->version_string_rw
,
85 current_image_name
[resp
->current_image
]);
93 static int cros_ec_chardev_mkbp_event(struct notifier_block
*nb
,
94 unsigned long queued_during_suspend
,
97 struct chardev_priv
*priv
= container_of(nb
, struct chardev_priv
,
99 struct cros_ec_device
*ec_dev
= priv
->ec_dev
->ec_dev
;
100 struct ec_event
*event
;
101 unsigned long event_bit
= 1 << ec_dev
->event_data
.event_type
;
102 int total_size
= sizeof(*event
) + ec_dev
->event_size
;
104 if (!(event_bit
& priv
->event_mask
) ||
105 (priv
->event_len
+ total_size
) > CROS_MAX_EVENT_LEN
)
108 event
= kzalloc(total_size
, GFP_KERNEL
);
112 event
->size
= ec_dev
->event_size
;
113 event
->event_type
= ec_dev
->event_data
.event_type
;
114 memcpy(event
->data
, &ec_dev
->event_data
.data
, ec_dev
->event_size
);
116 spin_lock(&priv
->wait_event
.lock
);
117 list_add_tail(&event
->node
, &priv
->events
);
118 priv
->event_len
+= total_size
;
119 wake_up_locked(&priv
->wait_event
);
120 spin_unlock(&priv
->wait_event
.lock
);
125 static struct ec_event
*cros_ec_chardev_fetch_event(struct chardev_priv
*priv
,
126 bool fetch
, bool block
)
128 struct ec_event
*event
;
131 spin_lock(&priv
->wait_event
.lock
);
132 if (!block
&& list_empty(&priv
->events
)) {
133 event
= ERR_PTR(-EWOULDBLOCK
);
142 err
= wait_event_interruptible_locked(priv
->wait_event
,
143 !list_empty(&priv
->events
));
145 event
= ERR_PTR(err
);
149 event
= list_first_entry(&priv
->events
, struct ec_event
, node
);
150 list_del(&event
->node
);
151 priv
->event_len
-= sizeof(*event
) + event
->size
;
154 spin_unlock(&priv
->wait_event
.lock
);
161 static int cros_ec_chardev_open(struct inode
*inode
, struct file
*filp
)
163 struct miscdevice
*mdev
= filp
->private_data
;
164 struct cros_ec_dev
*ec_dev
= dev_get_drvdata(mdev
->parent
);
165 struct chardev_priv
*priv
;
168 priv
= kzalloc(sizeof(*priv
), GFP_KERNEL
);
172 priv
->ec_dev
= ec_dev
;
173 filp
->private_data
= priv
;
174 INIT_LIST_HEAD(&priv
->events
);
175 init_waitqueue_head(&priv
->wait_event
);
176 nonseekable_open(inode
, filp
);
178 priv
->notifier
.notifier_call
= cros_ec_chardev_mkbp_event
;
179 ret
= blocking_notifier_chain_register(&ec_dev
->ec_dev
->event_notifier
,
182 dev_err(ec_dev
->dev
, "failed to register event notifier\n");
189 static __poll_t
cros_ec_chardev_poll(struct file
*filp
, poll_table
*wait
)
191 struct chardev_priv
*priv
= filp
->private_data
;
193 poll_wait(filp
, &priv
->wait_event
, wait
);
195 if (list_empty(&priv
->events
))
198 return EPOLLIN
| EPOLLRDNORM
;
201 static ssize_t
cros_ec_chardev_read(struct file
*filp
, char __user
*buffer
,
202 size_t length
, loff_t
*offset
)
204 char msg
[sizeof(struct ec_response_get_version
) +
205 sizeof(CROS_EC_DEV_VERSION
)];
206 struct chardev_priv
*priv
= filp
->private_data
;
207 struct cros_ec_dev
*ec_dev
= priv
->ec_dev
;
211 if (priv
->event_mask
) { /* queued MKBP event */
212 struct ec_event
*event
;
214 event
= cros_ec_chardev_fetch_event(priv
, length
!= 0,
215 !(filp
->f_flags
& O_NONBLOCK
));
217 return PTR_ERR(event
);
219 * length == 0 is special - no IO is done but we check
220 * for error conditions.
225 /* The event is 1 byte of type plus the payload */
226 count
= min(length
, event
->size
+ 1);
227 ret
= copy_to_user(buffer
, &event
->event_type
, count
);
229 if (ret
) /* the copy failed */
236 * Legacy behavior if no event mask is defined
241 ret
= ec_get_version(ec_dev
, msg
, sizeof(msg
));
245 count
= min(length
, strlen(msg
));
247 if (copy_to_user(buffer
, msg
, count
))
254 static int cros_ec_chardev_release(struct inode
*inode
, struct file
*filp
)
256 struct chardev_priv
*priv
= filp
->private_data
;
257 struct cros_ec_dev
*ec_dev
= priv
->ec_dev
;
258 struct ec_event
*event
, *e
;
260 blocking_notifier_chain_unregister(&ec_dev
->ec_dev
->event_notifier
,
263 list_for_each_entry_safe(event
, e
, &priv
->events
, node
) {
264 list_del(&event
->node
);
275 static long cros_ec_chardev_ioctl_xcmd(struct cros_ec_dev
*ec
, void __user
*arg
)
277 struct cros_ec_command
*s_cmd
;
278 struct cros_ec_command u_cmd
;
281 if (copy_from_user(&u_cmd
, arg
, sizeof(u_cmd
)))
284 if (u_cmd
.outsize
> EC_MAX_MSG_BYTES
||
285 u_cmd
.insize
> EC_MAX_MSG_BYTES
)
288 s_cmd
= kzalloc(sizeof(*s_cmd
) + max(u_cmd
.outsize
, u_cmd
.insize
),
293 if (copy_from_user(s_cmd
, arg
, sizeof(*s_cmd
) + u_cmd
.outsize
)) {
298 if (u_cmd
.outsize
!= s_cmd
->outsize
||
299 u_cmd
.insize
!= s_cmd
->insize
) {
304 s_cmd
->command
+= ec
->cmd_offset
;
305 ret
= cros_ec_cmd_xfer(ec
->ec_dev
, s_cmd
);
306 /* Only copy data to userland if data was received. */
310 if (copy_to_user(arg
, s_cmd
, sizeof(*s_cmd
) + s_cmd
->insize
))
317 static long cros_ec_chardev_ioctl_readmem(struct cros_ec_dev
*ec
,
320 struct cros_ec_device
*ec_dev
= ec
->ec_dev
;
321 struct cros_ec_readmem s_mem
= { };
324 /* Not every platform supports direct reads */
325 if (!ec_dev
->cmd_readmem
)
328 if (copy_from_user(&s_mem
, arg
, sizeof(s_mem
)))
331 if (s_mem
.bytes
> sizeof(s_mem
.buffer
))
334 num
= ec_dev
->cmd_readmem(ec_dev
, s_mem
.offset
, s_mem
.bytes
,
339 if (copy_to_user((void __user
*)arg
, &s_mem
, sizeof(s_mem
)))
345 static long cros_ec_chardev_ioctl(struct file
*filp
, unsigned int cmd
,
348 struct chardev_priv
*priv
= filp
->private_data
;
349 struct cros_ec_dev
*ec
= priv
->ec_dev
;
351 if (_IOC_TYPE(cmd
) != CROS_EC_DEV_IOC
)
355 case CROS_EC_DEV_IOCXCMD
:
356 return cros_ec_chardev_ioctl_xcmd(ec
, (void __user
*)arg
);
357 case CROS_EC_DEV_IOCRDMEM
:
358 return cros_ec_chardev_ioctl_readmem(ec
, (void __user
*)arg
);
359 case CROS_EC_DEV_IOCEVENTMASK
:
360 priv
->event_mask
= arg
;
367 static const struct file_operations chardev_fops
= {
368 .open
= cros_ec_chardev_open
,
369 .poll
= cros_ec_chardev_poll
,
370 .read
= cros_ec_chardev_read
,
371 .release
= cros_ec_chardev_release
,
372 .unlocked_ioctl
= cros_ec_chardev_ioctl
,
374 .compat_ioctl
= cros_ec_chardev_ioctl
,
378 static int cros_ec_chardev_probe(struct platform_device
*pdev
)
380 struct cros_ec_dev
*ec_dev
= dev_get_drvdata(pdev
->dev
.parent
);
381 struct cros_ec_platform
*ec_platform
= dev_get_platdata(ec_dev
->dev
);
382 struct chardev_data
*data
;
384 /* Create a char device: we want to create it anew */
385 data
= devm_kzalloc(&pdev
->dev
, sizeof(*data
), GFP_KERNEL
);
389 data
->ec_dev
= ec_dev
;
390 data
->misc
.minor
= MISC_DYNAMIC_MINOR
;
391 data
->misc
.fops
= &chardev_fops
;
392 data
->misc
.name
= ec_platform
->ec_name
;
393 data
->misc
.parent
= pdev
->dev
.parent
;
395 dev_set_drvdata(&pdev
->dev
, data
);
397 return misc_register(&data
->misc
);
400 static void cros_ec_chardev_remove(struct platform_device
*pdev
)
402 struct chardev_data
*data
= dev_get_drvdata(&pdev
->dev
);
404 misc_deregister(&data
->misc
);
407 static const struct platform_device_id cros_ec_chardev_id
[] = {
411 MODULE_DEVICE_TABLE(platform
, cros_ec_chardev_id
);
413 static struct platform_driver cros_ec_chardev_driver
= {
417 .probe
= cros_ec_chardev_probe
,
418 .remove
= cros_ec_chardev_remove
,
419 .id_table
= cros_ec_chardev_id
,
422 module_platform_driver(cros_ec_chardev_driver
);
424 MODULE_AUTHOR("Enric Balletbo i Serra <enric.balletbo@collabora.com>");
425 MODULE_DESCRIPTION("ChromeOS EC Miscellaneous Character Driver");
426 MODULE_LICENSE("GPL");