aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ioctl/ioctl-number.txt1
-rw-r--r--drivers/platform/chrome/Kconfig14
-rw-r--r--drivers/platform/chrome/Makefile1
-rw-r--r--drivers/platform/chrome/cros_ec_dev.c268
-rw-r--r--drivers/platform/chrome/cros_ec_dev.h47
5 files changed, 328 insertions, 3 deletions
diff --git a/Documentation/ioctl/ioctl-number.txt b/Documentation/ioctl/ioctl-number.txt
index 8136e1fd30fd..51f4221657bf 100644
--- a/Documentation/ioctl/ioctl-number.txt
+++ b/Documentation/ioctl/ioctl-number.txt
@@ -321,6 +321,7 @@ Code Seq#(hex) Include File Comments
3210xDB 00-0F drivers/char/mwave/mwavepub.h 3210xDB 00-0F drivers/char/mwave/mwavepub.h
3220xDD 00-3F ZFCP device driver see drivers/s390/scsi/ 3220xDD 00-3F ZFCP device driver see drivers/s390/scsi/
323 <mailto:aherrman@de.ibm.com> 323 <mailto:aherrman@de.ibm.com>
3240xEC 00-01 drivers/platform/chrome/cros_ec_dev.h ChromeOS EC driver
3240xF3 00-3F drivers/usb/misc/sisusbvga/sisusb.h sisfb (in development) 3250xF3 00-3F drivers/usb/misc/sisusbvga/sisusb.h sisfb (in development)
325 <mailto:thomas@winischhofer.net> 326 <mailto:thomas@winischhofer.net>
3260xF4 00-1F video/mbxfb.h mbxfb 3270xF4 00-1F video/mbxfb.h mbxfb
diff --git a/drivers/platform/chrome/Kconfig b/drivers/platform/chrome/Kconfig
index 6c5f5a1e1175..d4befbffae85 100644
--- a/drivers/platform/chrome/Kconfig
+++ b/drivers/platform/chrome/Kconfig
@@ -4,7 +4,7 @@
4 4
5menuconfig CHROME_PLATFORMS 5menuconfig CHROME_PLATFORMS
6 bool "Platform support for Chrome hardware" 6 bool "Platform support for Chrome hardware"
7 depends on X86 7 depends on X86 || ARM
8 ---help--- 8 ---help---
9 Say Y here to get to see options for platform support for 9 Say Y here to get to see options for platform support for
10 various Chromebooks and Chromeboxes. This option alone does 10 various Chromebooks and Chromeboxes. This option alone does
@@ -16,8 +16,7 @@ if CHROME_PLATFORMS
16 16
17config CHROMEOS_LAPTOP 17config CHROMEOS_LAPTOP
18 tristate "Chrome OS Laptop" 18 tristate "Chrome OS Laptop"
19 depends on I2C 19 depends on I2C && DMI && X86
20 depends on DMI
21 ---help--- 20 ---help---
22 This driver instantiates i2c and smbus devices such as 21 This driver instantiates i2c and smbus devices such as
23 light sensors and touchpads. 22 light sensors and touchpads.
@@ -27,6 +26,7 @@ config CHROMEOS_LAPTOP
27 26
28config CHROMEOS_PSTORE 27config CHROMEOS_PSTORE
29 tristate "Chrome OS pstore support" 28 tristate "Chrome OS pstore support"
29 depends on X86
30 ---help--- 30 ---help---
31 This module instantiates the persistent storage on x86 ChromeOS 31 This module instantiates the persistent storage on x86 ChromeOS
32 devices. It can be used to store away console logs and crash 32 devices. It can be used to store away console logs and crash
@@ -38,6 +38,14 @@ config CHROMEOS_PSTORE
38 If you have a supported Chromebook, choose Y or M here. 38 If you have a supported Chromebook, choose Y or M here.
39 The module will be called chromeos_pstore. 39 The module will be called chromeos_pstore.
40 40
41config CROS_EC_CHARDEV
42 tristate "Chrome OS Embedded Controller userspace device interface"
43 depends on MFD_CROS_EC
44 ---help---
45 This driver adds support to talk with the ChromeOS EC from userspace.
46
47 If you have a supported Chromebook, choose Y or M here.
48 The module will be called cros_ec_dev.
41 49
42config CROS_EC_LPC 50config CROS_EC_LPC
43 tristate "ChromeOS Embedded Controller (LPC)" 51 tristate "ChromeOS Embedded Controller (LPC)"
diff --git a/drivers/platform/chrome/Makefile b/drivers/platform/chrome/Makefile
index 03c0260369d9..ec682900f889 100644
--- a/drivers/platform/chrome/Makefile
+++ b/drivers/platform/chrome/Makefile
@@ -1,4 +1,5 @@
1 1
2obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o 2obj-$(CONFIG_CHROMEOS_LAPTOP) += chromeos_laptop.o
3obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o 3obj-$(CONFIG_CHROMEOS_PSTORE) += chromeos_pstore.o
4obj-$(CONFIG_CROS_EC_CHARDEV) += cros_ec_dev.o
4obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o 5obj-$(CONFIG_CROS_EC_LPC) += cros_ec_lpc.o
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c
new file mode 100644
index 000000000000..94c1442d5104
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_dev.c
@@ -0,0 +1,268 @@
1/*
2 * cros_ec_dev - expose the Chrome OS Embedded Controller to user-space
3 *
4 * Copyright (C) 2014 Google, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <linux/fs.h>
21#include <linux/module.h>
22#include <linux/platform_device.h>
23#include <linux/uaccess.h>
24
25#include "cros_ec_dev.h"
26
27/* Device variables */
28#define CROS_MAX_DEV 128
29static struct class *cros_class;
30static int ec_major;
31
32/* Basic communication */
33static int ec_get_version(struct cros_ec_device *ec, char *str, int maxlen)
34{
35 struct ec_response_get_version *resp;
36 static const char * const current_image_name[] = {
37 "unknown", "read-only", "read-write", "invalid",
38 };
39 struct cros_ec_command msg = {
40 .version = 0,
41 .command = EC_CMD_GET_VERSION,
42 .outdata = { 0 },
43 .outsize = 0,
44 .indata = { 0 },
45 .insize = sizeof(*resp),
46 };
47 int ret;
48
49 ret = cros_ec_cmd_xfer(ec, &msg);
50 if (ret < 0)
51 return ret;
52
53 if (msg.result != EC_RES_SUCCESS) {
54 snprintf(str, maxlen,
55 "%s\nUnknown EC version: EC returned %d\n",
56 CROS_EC_DEV_VERSION, msg.result);
57 return 0;
58 }
59
60 resp = (struct ec_response_get_version *)msg.indata;
61 if (resp->current_image >= ARRAY_SIZE(current_image_name))
62 resp->current_image = 3; /* invalid */
63
64 snprintf(str, maxlen, "%s\n%s\n%s\n\%s\n", CROS_EC_DEV_VERSION,
65 resp->version_string_ro, resp->version_string_rw,
66 current_image_name[resp->current_image]);
67
68 return 0;
69}
70
71/* Device file ops */
72static int ec_device_open(struct inode *inode, struct file *filp)
73{
74 filp->private_data = container_of(inode->i_cdev,
75 struct cros_ec_device, cdev);
76 return 0;
77}
78
79static int ec_device_release(struct inode *inode, struct file *filp)
80{
81 return 0;
82}
83
84static ssize_t ec_device_read(struct file *filp, char __user *buffer,
85 size_t length, loff_t *offset)
86{
87 struct cros_ec_device *ec = filp->private_data;
88 char msg[sizeof(struct ec_response_get_version) +
89 sizeof(CROS_EC_DEV_VERSION)];
90 size_t count;
91 int ret;
92
93 if (*offset != 0)
94 return 0;
95
96 ret = ec_get_version(ec, msg, sizeof(msg));
97 if (ret)
98 return ret;
99
100 count = min(length, strlen(msg));
101
102 if (copy_to_user(buffer, msg, count))
103 return -EFAULT;
104
105 *offset = count;
106 return count;
107}
108
109/* Ioctls */
110static long ec_device_ioctl_xcmd(struct cros_ec_device *ec, void __user *arg)
111{
112 long ret;
113 struct cros_ec_command s_cmd = { };
114
115 if (copy_from_user(&s_cmd, arg, sizeof(s_cmd)))
116 return -EFAULT;
117
118 ret = cros_ec_cmd_xfer(ec, &s_cmd);
119 /* Only copy data to userland if data was received. */
120 if (ret < 0)
121 return ret;
122
123 if (copy_to_user(arg, &s_cmd, sizeof(s_cmd)))
124 return -EFAULT;
125
126 return 0;
127}
128
129static long ec_device_ioctl_readmem(struct cros_ec_device *ec, void __user *arg)
130{
131 struct cros_ec_readmem s_mem = { };
132 long num;
133
134 /* Not every platform supports direct reads */
135 if (!ec->cmd_readmem)
136 return -ENOTTY;
137
138 if (copy_from_user(&s_mem, arg, sizeof(s_mem)))
139 return -EFAULT;
140
141 num = ec->cmd_readmem(ec, s_mem.offset, s_mem.bytes, s_mem.buffer);
142 if (num <= 0)
143 return num;
144
145 if (copy_to_user((void __user *)arg, &s_mem, sizeof(s_mem)))
146 return -EFAULT;
147
148 return 0;
149}
150
151static long ec_device_ioctl(struct file *filp, unsigned int cmd,
152 unsigned long arg)
153{
154 struct cros_ec_device *ec = filp->private_data;
155
156 if (_IOC_TYPE(cmd) != CROS_EC_DEV_IOC)
157 return -ENOTTY;
158
159 switch (cmd) {
160 case CROS_EC_DEV_IOCXCMD:
161 return ec_device_ioctl_xcmd(ec, (void __user *)arg);
162 case CROS_EC_DEV_IOCRDMEM:
163 return ec_device_ioctl_readmem(ec, (void __user *)arg);
164 }
165
166 return -ENOTTY;
167}
168
169/* Module initialization */
170static const struct file_operations fops = {
171 .open = ec_device_open,
172 .release = ec_device_release,
173 .read = ec_device_read,
174 .unlocked_ioctl = ec_device_ioctl,
175};
176
177static int ec_device_probe(struct platform_device *pdev)
178{
179 struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
180 int retval = -ENOTTY;
181 dev_t devno = MKDEV(ec_major, 0);
182
183 /* Instantiate it (and remember the EC) */
184 cdev_init(&ec->cdev, &fops);
185
186 retval = cdev_add(&ec->cdev, devno, 1);
187 if (retval) {
188 dev_err(&pdev->dev, ": failed to add character device\n");
189 return retval;
190 }
191
192 ec->vdev = device_create(cros_class, NULL, devno, ec,
193 CROS_EC_DEV_NAME);
194 if (IS_ERR(ec->vdev)) {
195 retval = PTR_ERR(ec->vdev);
196 dev_err(&pdev->dev, ": failed to create device\n");
197 cdev_del(&ec->cdev);
198 return retval;
199 }
200
201 return 0;
202}
203
204static int ec_device_remove(struct platform_device *pdev)
205{
206 struct cros_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
207
208 device_destroy(cros_class, MKDEV(ec_major, 0));
209 cdev_del(&ec->cdev);
210 return 0;
211}
212
213static struct platform_driver cros_ec_dev_driver = {
214 .driver = {
215 .name = "cros-ec-ctl",
216 },
217 .probe = ec_device_probe,
218 .remove = ec_device_remove,
219};
220
221static int __init cros_ec_dev_init(void)
222{
223 int ret;
224 dev_t dev = 0;
225
226 cros_class = class_create(THIS_MODULE, "chromeos");
227 if (IS_ERR(cros_class)) {
228 pr_err(CROS_EC_DEV_NAME ": failed to register device class\n");
229 return PTR_ERR(cros_class);
230 }
231
232 /* Get a range of minor numbers (starting with 0) to work with */
233 ret = alloc_chrdev_region(&dev, 0, CROS_MAX_DEV, CROS_EC_DEV_NAME);
234 if (ret < 0) {
235 pr_err(CROS_EC_DEV_NAME ": alloc_chrdev_region() failed\n");
236 goto failed_chrdevreg;
237 }
238 ec_major = MAJOR(dev);
239
240 /* Register the driver */
241 ret = platform_driver_register(&cros_ec_dev_driver);
242 if (ret < 0) {
243 pr_warn(CROS_EC_DEV_NAME ": can't register driver: %d\n", ret);
244 goto failed_devreg;
245 }
246 return 0;
247
248failed_devreg:
249 unregister_chrdev_region(MKDEV(ec_major, 0), CROS_MAX_DEV);
250failed_chrdevreg:
251 class_destroy(cros_class);
252 return ret;
253}
254
255static void __exit cros_ec_dev_exit(void)
256{
257 platform_driver_unregister(&cros_ec_dev_driver);
258 unregister_chrdev(ec_major, CROS_EC_DEV_NAME);
259 class_destroy(cros_class);
260}
261
262module_init(cros_ec_dev_init);
263module_exit(cros_ec_dev_exit);
264
265MODULE_AUTHOR("Bill Richardson <wfrichar@chromium.org>");
266MODULE_DESCRIPTION("Userspace interface to the Chrome OS Embedded Controller");
267MODULE_VERSION("1.0");
268MODULE_LICENSE("GPL");
diff --git a/drivers/platform/chrome/cros_ec_dev.h b/drivers/platform/chrome/cros_ec_dev.h
new file mode 100644
index 000000000000..15c54c4c5531
--- /dev/null
+++ b/drivers/platform/chrome/cros_ec_dev.h
@@ -0,0 +1,47 @@
1/*
2 * cros_ec_dev - expose the Chrome OS Embedded Controller to userspace
3 *
4 * Copyright (C) 2014 Google, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifndef _CROS_EC_DEV_H_
21#define _CROS_EC_DEV_H_
22
23#include <linux/ioctl.h>
24#include <linux/types.h>
25#include <linux/mfd/cros_ec.h>
26
27#define CROS_EC_DEV_NAME "cros_ec"
28#define CROS_EC_DEV_VERSION "1.0.0"
29
30/*
31 * @offset: within EC_LPC_ADDR_MEMMAP region
32 * @bytes: number of bytes to read. zero means "read a string" (including '\0')
33 * (at most only EC_MEMMAP_SIZE bytes can be read)
34 * @buffer: where to store the result
35 * ioctl returns the number of bytes read, negative on error
36 */
37struct cros_ec_readmem {
38 uint32_t offset;
39 uint32_t bytes;
40 uint8_t buffer[EC_MEMMAP_SIZE];
41};
42
43#define CROS_EC_DEV_IOC 0xEC
44#define CROS_EC_DEV_IOCXCMD _IOWR(CROS_EC_DEV_IOC, 0, struct cros_ec_command)
45#define CROS_EC_DEV_IOCRDMEM _IOWR(CROS_EC_DEV_IOC, 1, struct cros_ec_readmem)
46
47#endif /* _CROS_EC_DEV_H_ */