diff options
author | Javier Martinez Canillas <javier.martinez@collabora.co.uk> | 2015-06-09 07:04:42 -0400 |
---|---|---|
committer | Lee Jones <lee.jones@linaro.org> | 2015-06-15 08:18:19 -0400 |
commit | a841178445bb72a3d566b4e6ab9d19e9b002eb47 (patch) | |
tree | bdc857e82c9c9e8b49bd5471efa5a954673d58f0 /drivers/platform | |
parent | bb03ffb96c72418d06e75c7b74ea62e04c78d322 (diff) |
mfd: cros_ec: Use a zero-length array for command data
Commit 1b84f2a4cd4a ("mfd: cros_ec: Use fixed size arrays to transfer
data with the EC") modified the struct cros_ec_command fields to not
use pointers for the input and output buffers and use fixed length
arrays instead.
This change was made because the cros_ec ioctl API uses that struct
cros_ec_command to allow user-space to send commands to the EC and
to get data from the EC. So using pointers made the API not 64-bit
safe. Unfortunately this approach was not flexible enough for all
the use-cases since there may be a need to send larger commands
on newer versions of the EC command protocol.
So to avoid to choose a constant length that it may be too big for
most commands and thus wasting memory and CPU cycles on copy from
and to user-space or having a size that is too small for some big
commands, use a zero-length array that is both 64-bit safe and
flexible. The same buffer is used for both output and input data
so the maximum of these values should be used to allocate it.
Suggested-by: Gwendal Grignou <gwendal@chromium.org>
Signed-off-by: Javier Martinez Canillas <javier.martinez@collabora.co.uk>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Acked-by: Lee Jones <lee.jones@linaro.org>
Acked-by: Olof Johansson <olof@lixom.net>
Signed-off-by: Lee Jones <lee.jones@linaro.org>
Diffstat (limited to 'drivers/platform')
-rw-r--r-- | drivers/platform/chrome/cros_ec_dev.c | 65 | ||||
-rw-r--r-- | drivers/platform/chrome/cros_ec_lightbar.c | 152 | ||||
-rw-r--r-- | drivers/platform/chrome/cros_ec_lpc.c | 8 | ||||
-rw-r--r-- | drivers/platform/chrome/cros_ec_sysfs.c | 154 |
4 files changed, 244 insertions, 135 deletions
diff --git a/drivers/platform/chrome/cros_ec_dev.c b/drivers/platform/chrome/cros_ec_dev.c index 6090d0b2826f..e91ced1cb8ce 100644 --- a/drivers/platform/chrome/cros_ec_dev.c +++ b/drivers/platform/chrome/cros_ec_dev.c | |||
@@ -20,6 +20,7 @@ | |||
20 | #include <linux/fs.h> | 20 | #include <linux/fs.h> |
21 | #include <linux/module.h> | 21 | #include <linux/module.h> |
22 | #include <linux/platform_device.h> | 22 | #include <linux/platform_device.h> |
23 | #include <linux/slab.h> | ||
23 | #include <linux/uaccess.h> | 24 | #include <linux/uaccess.h> |
24 | 25 | ||
25 | #include "cros_ec_dev.h" | 26 | #include "cros_ec_dev.h" |
@@ -36,28 +37,31 @@ static int ec_get_version(struct cros_ec_device *ec, char *str, int maxlen) | |||
36 | static const char * const current_image_name[] = { | 37 | static const char * const current_image_name[] = { |
37 | "unknown", "read-only", "read-write", "invalid", | 38 | "unknown", "read-only", "read-write", "invalid", |
38 | }; | 39 | }; |
39 | struct cros_ec_command msg = { | 40 | 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; | 41 | int ret; |
48 | 42 | ||
49 | ret = cros_ec_cmd_xfer(ec, &msg); | 43 | msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); |
44 | if (!msg) | ||
45 | return -ENOMEM; | ||
46 | |||
47 | msg->version = 0; | ||
48 | msg->command = EC_CMD_GET_VERSION; | ||
49 | msg->insize = sizeof(*resp); | ||
50 | msg->outsize = 0; | ||
51 | |||
52 | ret = cros_ec_cmd_xfer(ec, msg); | ||
50 | if (ret < 0) | 53 | if (ret < 0) |
51 | return ret; | 54 | goto exit; |
52 | 55 | ||
53 | if (msg.result != EC_RES_SUCCESS) { | 56 | if (msg->result != EC_RES_SUCCESS) { |
54 | snprintf(str, maxlen, | 57 | snprintf(str, maxlen, |
55 | "%s\nUnknown EC version: EC returned %d\n", | 58 | "%s\nUnknown EC version: EC returned %d\n", |
56 | CROS_EC_DEV_VERSION, msg.result); | 59 | CROS_EC_DEV_VERSION, msg->result); |
57 | return 0; | 60 | ret = -EINVAL; |
61 | goto exit; | ||
58 | } | 62 | } |
59 | 63 | ||
60 | resp = (struct ec_response_get_version *)msg.indata; | 64 | resp = (struct ec_response_get_version *)msg->data; |
61 | if (resp->current_image >= ARRAY_SIZE(current_image_name)) | 65 | if (resp->current_image >= ARRAY_SIZE(current_image_name)) |
62 | resp->current_image = 3; /* invalid */ | 66 | resp->current_image = 3; /* invalid */ |
63 | 67 | ||
@@ -65,7 +69,10 @@ static int ec_get_version(struct cros_ec_device *ec, char *str, int maxlen) | |||
65 | resp->version_string_ro, resp->version_string_rw, | 69 | resp->version_string_ro, resp->version_string_rw, |
66 | current_image_name[resp->current_image]); | 70 | current_image_name[resp->current_image]); |
67 | 71 | ||
68 | return 0; | 72 | ret = 0; |
73 | exit: | ||
74 | kfree(msg); | ||
75 | return ret; | ||
69 | } | 76 | } |
70 | 77 | ||
71 | /* Device file ops */ | 78 | /* Device file ops */ |
@@ -110,20 +117,32 @@ static ssize_t ec_device_read(struct file *filp, char __user *buffer, | |||
110 | static long ec_device_ioctl_xcmd(struct cros_ec_device *ec, void __user *arg) | 117 | static long ec_device_ioctl_xcmd(struct cros_ec_device *ec, void __user *arg) |
111 | { | 118 | { |
112 | long ret; | 119 | long ret; |
113 | struct cros_ec_command s_cmd = { }; | 120 | struct cros_ec_command u_cmd; |
121 | struct cros_ec_command *s_cmd; | ||
114 | 122 | ||
115 | if (copy_from_user(&s_cmd, arg, sizeof(s_cmd))) | 123 | if (copy_from_user(&u_cmd, arg, sizeof(u_cmd))) |
116 | return -EFAULT; | 124 | return -EFAULT; |
117 | 125 | ||
118 | ret = cros_ec_cmd_xfer(ec, &s_cmd); | 126 | s_cmd = kmalloc(sizeof(*s_cmd) + max(u_cmd.outsize, u_cmd.insize), |
127 | GFP_KERNEL); | ||
128 | if (!s_cmd) | ||
129 | return -ENOMEM; | ||
130 | |||
131 | if (copy_from_user(s_cmd, arg, sizeof(*s_cmd) + u_cmd.outsize)) { | ||
132 | ret = -EFAULT; | ||
133 | goto exit; | ||
134 | } | ||
135 | |||
136 | ret = cros_ec_cmd_xfer(ec, s_cmd); | ||
119 | /* Only copy data to userland if data was received. */ | 137 | /* Only copy data to userland if data was received. */ |
120 | if (ret < 0) | 138 | if (ret < 0) |
121 | return ret; | 139 | goto exit; |
122 | 140 | ||
123 | if (copy_to_user(arg, &s_cmd, sizeof(s_cmd))) | 141 | if (copy_to_user(arg, s_cmd, sizeof(*s_cmd) + u_cmd.insize)) |
124 | return -EFAULT; | 142 | ret = -EFAULT; |
125 | 143 | exit: | |
126 | return 0; | 144 | kfree(s_cmd); |
145 | return ret; | ||
127 | } | 146 | } |
128 | 147 | ||
129 | static long ec_device_ioctl_readmem(struct cros_ec_device *ec, void __user *arg) | 148 | static long ec_device_ioctl_readmem(struct cros_ec_device *ec, void __user *arg) |
diff --git a/drivers/platform/chrome/cros_ec_lightbar.c b/drivers/platform/chrome/cros_ec_lightbar.c index b4ff47a9069a..560e5d41b7ae 100644 --- a/drivers/platform/chrome/cros_ec_lightbar.c +++ b/drivers/platform/chrome/cros_ec_lightbar.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include <linux/sched.h> | 31 | #include <linux/sched.h> |
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/uaccess.h> | 33 | #include <linux/uaccess.h> |
34 | #include <linux/slab.h> | ||
34 | 35 | ||
35 | #include "cros_ec_dev.h" | 36 | #include "cros_ec_dev.h" |
36 | 37 | ||
@@ -91,54 +92,79 @@ out: | |||
91 | return ret; | 92 | return ret; |
92 | } | 93 | } |
93 | 94 | ||
94 | #define INIT_MSG(P, R) { \ | 95 | static struct cros_ec_command *alloc_lightbar_cmd_msg(void) |
95 | .command = EC_CMD_LIGHTBAR_CMD, \ | 96 | { |
96 | .outsize = sizeof(*P), \ | 97 | struct cros_ec_command *msg; |
97 | .insize = sizeof(*R), \ | 98 | int len; |
98 | } | 99 | |
100 | len = max(sizeof(struct ec_params_lightbar), | ||
101 | sizeof(struct ec_response_lightbar)); | ||
102 | |||
103 | msg = kmalloc(sizeof(*msg) + len, GFP_KERNEL); | ||
104 | if (!msg) | ||
105 | return NULL; | ||
106 | |||
107 | msg->version = 0; | ||
108 | msg->command = EC_CMD_LIGHTBAR_CMD; | ||
109 | msg->outsize = sizeof(struct ec_params_lightbar); | ||
110 | msg->insize = sizeof(struct ec_response_lightbar); | ||
111 | |||
112 | return msg; | ||
113 | } | ||
99 | 114 | ||
100 | static int get_lightbar_version(struct cros_ec_device *ec, | 115 | static int get_lightbar_version(struct cros_ec_device *ec, |
101 | uint32_t *ver_ptr, uint32_t *flg_ptr) | 116 | uint32_t *ver_ptr, uint32_t *flg_ptr) |
102 | { | 117 | { |
103 | struct ec_params_lightbar *param; | 118 | struct ec_params_lightbar *param; |
104 | struct ec_response_lightbar *resp; | 119 | struct ec_response_lightbar *resp; |
105 | struct cros_ec_command msg = INIT_MSG(param, resp); | 120 | struct cros_ec_command *msg; |
106 | int ret; | 121 | int ret; |
107 | 122 | ||
108 | param = (struct ec_params_lightbar *)msg.outdata; | 123 | msg = alloc_lightbar_cmd_msg(); |
109 | param->cmd = LIGHTBAR_CMD_VERSION; | 124 | if (!msg) |
110 | ret = cros_ec_cmd_xfer(ec, &msg); | ||
111 | if (ret < 0) | ||
112 | return 0; | 125 | return 0; |
113 | 126 | ||
114 | switch (msg.result) { | 127 | param = (struct ec_params_lightbar *)msg->data; |
128 | param->cmd = LIGHTBAR_CMD_VERSION; | ||
129 | ret = cros_ec_cmd_xfer(ec, msg); | ||
130 | if (ret < 0) { | ||
131 | ret = 0; | ||
132 | goto exit; | ||
133 | } | ||
134 | |||
135 | switch (msg->result) { | ||
115 | case EC_RES_INVALID_PARAM: | 136 | case EC_RES_INVALID_PARAM: |
116 | /* Pixel had no version command. */ | 137 | /* Pixel had no version command. */ |
117 | if (ver_ptr) | 138 | if (ver_ptr) |
118 | *ver_ptr = 0; | 139 | *ver_ptr = 0; |
119 | if (flg_ptr) | 140 | if (flg_ptr) |
120 | *flg_ptr = 0; | 141 | *flg_ptr = 0; |
121 | return 1; | 142 | ret = 1; |
143 | goto exit; | ||
122 | 144 | ||
123 | case EC_RES_SUCCESS: | 145 | case EC_RES_SUCCESS: |
124 | resp = (struct ec_response_lightbar *)msg.indata; | 146 | resp = (struct ec_response_lightbar *)msg->data; |
125 | 147 | ||
126 | /* Future devices w/lightbars should implement this command */ | 148 | /* Future devices w/lightbars should implement this command */ |
127 | if (ver_ptr) | 149 | if (ver_ptr) |
128 | *ver_ptr = resp->version.num; | 150 | *ver_ptr = resp->version.num; |
129 | if (flg_ptr) | 151 | if (flg_ptr) |
130 | *flg_ptr = resp->version.flags; | 152 | *flg_ptr = resp->version.flags; |
131 | return 1; | 153 | ret = 1; |
154 | goto exit; | ||
132 | } | 155 | } |
133 | 156 | ||
134 | /* Anything else (ie, EC_RES_INVALID_COMMAND) - no lightbar */ | 157 | /* Anything else (ie, EC_RES_INVALID_COMMAND) - no lightbar */ |
135 | return 0; | 158 | ret = 0; |
159 | exit: | ||
160 | kfree(msg); | ||
161 | return ret; | ||
136 | } | 162 | } |
137 | 163 | ||
138 | static ssize_t version_show(struct device *dev, | 164 | static ssize_t version_show(struct device *dev, |
139 | struct device_attribute *attr, char *buf) | 165 | struct device_attribute *attr, char *buf) |
140 | { | 166 | { |
141 | uint32_t version, flags; | 167 | uint32_t version = 0, flags = 0; |
142 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 168 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
143 | int ret; | 169 | int ret; |
144 | 170 | ||
@@ -158,8 +184,7 @@ static ssize_t brightness_store(struct device *dev, | |||
158 | const char *buf, size_t count) | 184 | const char *buf, size_t count) |
159 | { | 185 | { |
160 | struct ec_params_lightbar *param; | 186 | struct ec_params_lightbar *param; |
161 | struct ec_response_lightbar *resp; | 187 | struct cros_ec_command *msg; |
162 | struct cros_ec_command msg = INIT_MSG(param, resp); | ||
163 | int ret; | 188 | int ret; |
164 | unsigned int val; | 189 | unsigned int val; |
165 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 190 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
@@ -167,21 +192,30 @@ static ssize_t brightness_store(struct device *dev, | |||
167 | if (kstrtouint(buf, 0, &val)) | 192 | if (kstrtouint(buf, 0, &val)) |
168 | return -EINVAL; | 193 | return -EINVAL; |
169 | 194 | ||
170 | param = (struct ec_params_lightbar *)msg.outdata; | 195 | msg = alloc_lightbar_cmd_msg(); |
196 | if (!msg) | ||
197 | return -ENOMEM; | ||
198 | |||
199 | param = (struct ec_params_lightbar *)msg->data; | ||
171 | param->cmd = LIGHTBAR_CMD_BRIGHTNESS; | 200 | param->cmd = LIGHTBAR_CMD_BRIGHTNESS; |
172 | param->brightness.num = val; | 201 | param->brightness.num = val; |
173 | ret = lb_throttle(); | 202 | ret = lb_throttle(); |
174 | if (ret) | 203 | if (ret) |
175 | return ret; | 204 | goto exit; |
176 | 205 | ||
177 | ret = cros_ec_cmd_xfer(ec, &msg); | 206 | ret = cros_ec_cmd_xfer(ec, msg); |
178 | if (ret < 0) | 207 | if (ret < 0) |
179 | return ret; | 208 | goto exit; |
180 | 209 | ||
181 | if (msg.result != EC_RES_SUCCESS) | 210 | if (msg->result != EC_RES_SUCCESS) { |
182 | return -EINVAL; | 211 | ret = -EINVAL; |
212 | goto exit; | ||
213 | } | ||
183 | 214 | ||
184 | return count; | 215 | ret = count; |
216 | exit: | ||
217 | kfree(msg); | ||
218 | return ret; | ||
185 | } | 219 | } |
186 | 220 | ||
187 | 221 | ||
@@ -196,12 +230,15 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
196 | const char *buf, size_t count) | 230 | const char *buf, size_t count) |
197 | { | 231 | { |
198 | struct ec_params_lightbar *param; | 232 | struct ec_params_lightbar *param; |
199 | struct ec_response_lightbar *resp; | 233 | struct cros_ec_command *msg; |
200 | struct cros_ec_command msg = INIT_MSG(param, resp); | ||
201 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 234 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
202 | unsigned int val[4]; | 235 | unsigned int val[4]; |
203 | int ret, i = 0, j = 0, ok = 0; | 236 | int ret, i = 0, j = 0, ok = 0; |
204 | 237 | ||
238 | msg = alloc_lightbar_cmd_msg(); | ||
239 | if (!msg) | ||
240 | return -ENOMEM; | ||
241 | |||
205 | do { | 242 | do { |
206 | /* Skip any whitespace */ | 243 | /* Skip any whitespace */ |
207 | while (*buf && isspace(*buf)) | 244 | while (*buf && isspace(*buf)) |
@@ -215,7 +252,7 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
215 | return -EINVAL; | 252 | return -EINVAL; |
216 | 253 | ||
217 | if (i == 4) { | 254 | if (i == 4) { |
218 | param = (struct ec_params_lightbar *)msg.outdata; | 255 | param = (struct ec_params_lightbar *)msg->data; |
219 | param->cmd = LIGHTBAR_CMD_RGB; | 256 | param->cmd = LIGHTBAR_CMD_RGB; |
220 | param->rgb.led = val[0]; | 257 | param->rgb.led = val[0]; |
221 | param->rgb.red = val[1]; | 258 | param->rgb.red = val[1]; |
@@ -231,12 +268,14 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
231 | return ret; | 268 | return ret; |
232 | } | 269 | } |
233 | 270 | ||
234 | ret = cros_ec_cmd_xfer(ec, &msg); | 271 | ret = cros_ec_cmd_xfer(ec, msg); |
235 | if (ret < 0) | 272 | if (ret < 0) |
236 | return ret; | 273 | goto exit; |
237 | 274 | ||
238 | if (msg.result != EC_RES_SUCCESS) | 275 | if (msg->result != EC_RES_SUCCESS) { |
239 | return -EINVAL; | 276 | ret = -EINVAL; |
277 | goto exit; | ||
278 | } | ||
240 | 279 | ||
241 | i = 0; | 280 | i = 0; |
242 | ok = 1; | 281 | ok = 1; |
@@ -248,6 +287,8 @@ static ssize_t led_rgb_store(struct device *dev, struct device_attribute *attr, | |||
248 | 287 | ||
249 | } while (*buf); | 288 | } while (*buf); |
250 | 289 | ||
290 | exit: | ||
291 | kfree(msg); | ||
251 | return (ok && i == 0) ? count : -EINVAL; | 292 | return (ok && i == 0) ? count : -EINVAL; |
252 | } | 293 | } |
253 | 294 | ||
@@ -261,42 +302,55 @@ static ssize_t sequence_show(struct device *dev, | |||
261 | { | 302 | { |
262 | struct ec_params_lightbar *param; | 303 | struct ec_params_lightbar *param; |
263 | struct ec_response_lightbar *resp; | 304 | struct ec_response_lightbar *resp; |
264 | struct cros_ec_command msg = INIT_MSG(param, resp); | 305 | struct cros_ec_command *msg; |
265 | int ret; | 306 | int ret; |
266 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 307 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
267 | 308 | ||
268 | param = (struct ec_params_lightbar *)msg.outdata; | 309 | msg = alloc_lightbar_cmd_msg(); |
310 | if (!msg) | ||
311 | return -ENOMEM; | ||
312 | |||
313 | param = (struct ec_params_lightbar *)msg->data; | ||
269 | param->cmd = LIGHTBAR_CMD_GET_SEQ; | 314 | param->cmd = LIGHTBAR_CMD_GET_SEQ; |
270 | ret = lb_throttle(); | 315 | ret = lb_throttle(); |
271 | if (ret) | 316 | if (ret) |
272 | return ret; | 317 | goto exit; |
273 | 318 | ||
274 | ret = cros_ec_cmd_xfer(ec, &msg); | 319 | ret = cros_ec_cmd_xfer(ec, msg); |
275 | if (ret < 0) | 320 | if (ret < 0) |
276 | return ret; | 321 | goto exit; |
277 | 322 | ||
278 | if (msg.result != EC_RES_SUCCESS) | 323 | if (msg->result != EC_RES_SUCCESS) { |
279 | return scnprintf(buf, PAGE_SIZE, | 324 | ret = scnprintf(buf, PAGE_SIZE, |
280 | "ERROR: EC returned %d\n", msg.result); | 325 | "ERROR: EC returned %d\n", msg->result); |
326 | goto exit; | ||
327 | } | ||
281 | 328 | ||
282 | resp = (struct ec_response_lightbar *)msg.indata; | 329 | resp = (struct ec_response_lightbar *)msg->data; |
283 | if (resp->get_seq.num >= ARRAY_SIZE(seqname)) | 330 | if (resp->get_seq.num >= ARRAY_SIZE(seqname)) |
284 | return scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num); | 331 | ret = scnprintf(buf, PAGE_SIZE, "%d\n", resp->get_seq.num); |
285 | else | 332 | else |
286 | return scnprintf(buf, PAGE_SIZE, "%s\n", | 333 | ret = scnprintf(buf, PAGE_SIZE, "%s\n", |
287 | seqname[resp->get_seq.num]); | 334 | seqname[resp->get_seq.num]); |
335 | |||
336 | exit: | ||
337 | kfree(msg); | ||
338 | return ret; | ||
288 | } | 339 | } |
289 | 340 | ||
290 | static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, | 341 | static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, |
291 | const char *buf, size_t count) | 342 | const char *buf, size_t count) |
292 | { | 343 | { |
293 | struct ec_params_lightbar *param; | 344 | struct ec_params_lightbar *param; |
294 | struct ec_response_lightbar *resp; | 345 | struct cros_ec_command *msg; |
295 | struct cros_ec_command msg = INIT_MSG(param, resp); | ||
296 | unsigned int num; | 346 | unsigned int num; |
297 | int ret, len; | 347 | int ret, len; |
298 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 348 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
299 | 349 | ||
350 | msg = alloc_lightbar_cmd_msg(); | ||
351 | if (!msg) | ||
352 | return -ENOMEM; | ||
353 | |||
300 | for (len = 0; len < count; len++) | 354 | for (len = 0; len < count; len++) |
301 | if (!isalnum(buf[len])) | 355 | if (!isalnum(buf[len])) |
302 | break; | 356 | break; |
@@ -311,18 +365,18 @@ static ssize_t sequence_store(struct device *dev, struct device_attribute *attr, | |||
311 | return ret; | 365 | return ret; |
312 | } | 366 | } |
313 | 367 | ||
314 | param = (struct ec_params_lightbar *)msg.outdata; | 368 | param = (struct ec_params_lightbar *)msg->data; |
315 | param->cmd = LIGHTBAR_CMD_SEQ; | 369 | param->cmd = LIGHTBAR_CMD_SEQ; |
316 | param->seq.num = num; | 370 | param->seq.num = num; |
317 | ret = lb_throttle(); | 371 | ret = lb_throttle(); |
318 | if (ret) | 372 | if (ret) |
319 | return ret; | 373 | return ret; |
320 | 374 | ||
321 | ret = cros_ec_cmd_xfer(ec, &msg); | 375 | ret = cros_ec_cmd_xfer(ec, msg); |
322 | if (ret < 0) | 376 | if (ret < 0) |
323 | return ret; | 377 | return ret; |
324 | 378 | ||
325 | if (msg.result != EC_RES_SUCCESS) | 379 | if (msg->result != EC_RES_SUCCESS) |
326 | return -EINVAL; | 380 | return -EINVAL; |
327 | 381 | ||
328 | return count; | 382 | return count; |
diff --git a/drivers/platform/chrome/cros_ec_lpc.c b/drivers/platform/chrome/cros_ec_lpc.c index 860310513cf0..4c7f0df33bf8 100644 --- a/drivers/platform/chrome/cros_ec_lpc.c +++ b/drivers/platform/chrome/cros_ec_lpc.c | |||
@@ -73,8 +73,8 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec, | |||
73 | 73 | ||
74 | /* Copy data and update checksum */ | 74 | /* Copy data and update checksum */ |
75 | for (i = 0; i < msg->outsize; i++) { | 75 | for (i = 0; i < msg->outsize; i++) { |
76 | outb(msg->outdata[i], EC_LPC_ADDR_HOST_PARAM + i); | 76 | outb(msg->data[i], EC_LPC_ADDR_HOST_PARAM + i); |
77 | csum += msg->outdata[i]; | 77 | csum += msg->data[i]; |
78 | } | 78 | } |
79 | 79 | ||
80 | /* Finalize checksum and write args */ | 80 | /* Finalize checksum and write args */ |
@@ -129,8 +129,8 @@ static int cros_ec_cmd_xfer_lpc(struct cros_ec_device *ec, | |||
129 | 129 | ||
130 | /* Read response and update checksum */ | 130 | /* Read response and update checksum */ |
131 | for (i = 0; i < args.data_size; i++) { | 131 | for (i = 0; i < args.data_size; i++) { |
132 | msg->indata[i] = inb(EC_LPC_ADDR_HOST_PARAM + i); | 132 | msg->data[i] = inb(EC_LPC_ADDR_HOST_PARAM + i); |
133 | csum += msg->indata[i]; | 133 | csum += msg->data[i]; |
134 | } | 134 | } |
135 | 135 | ||
136 | /* Verify checksum */ | 136 | /* Verify checksum */ |
diff --git a/drivers/platform/chrome/cros_ec_sysfs.c b/drivers/platform/chrome/cros_ec_sysfs.c index fb62ab6cc659..78ba82d670cb 100644 --- a/drivers/platform/chrome/cros_ec_sysfs.c +++ b/drivers/platform/chrome/cros_ec_sysfs.c | |||
@@ -29,6 +29,7 @@ | |||
29 | #include <linux/module.h> | 29 | #include <linux/module.h> |
30 | #include <linux/platform_device.h> | 30 | #include <linux/platform_device.h> |
31 | #include <linux/printk.h> | 31 | #include <linux/printk.h> |
32 | #include <linux/slab.h> | ||
32 | #include <linux/stat.h> | 33 | #include <linux/stat.h> |
33 | #include <linux/types.h> | 34 | #include <linux/types.h> |
34 | #include <linux/uaccess.h> | 35 | #include <linux/uaccess.h> |
@@ -66,14 +67,19 @@ static ssize_t store_ec_reboot(struct device *dev, | |||
66 | {"hibernate", EC_REBOOT_HIBERNATE, 0}, | 67 | {"hibernate", EC_REBOOT_HIBERNATE, 0}, |
67 | {"at-shutdown", -1, EC_REBOOT_FLAG_ON_AP_SHUTDOWN}, | 68 | {"at-shutdown", -1, EC_REBOOT_FLAG_ON_AP_SHUTDOWN}, |
68 | }; | 69 | }; |
69 | struct cros_ec_command msg = { 0 }; | 70 | struct cros_ec_command *msg; |
70 | struct ec_params_reboot_ec *param = | 71 | struct ec_params_reboot_ec *param; |
71 | (struct ec_params_reboot_ec *)msg.outdata; | ||
72 | int got_cmd = 0, offset = 0; | 72 | int got_cmd = 0, offset = 0; |
73 | int i; | 73 | int i; |
74 | int ret; | 74 | int ret; |
75 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 75 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
76 | 76 | ||
77 | msg = kmalloc(sizeof(*msg) + sizeof(*param), GFP_KERNEL); | ||
78 | if (!msg) | ||
79 | return -ENOMEM; | ||
80 | |||
81 | param = (struct ec_params_reboot_ec *)msg->data; | ||
82 | |||
77 | param->flags = 0; | 83 | param->flags = 0; |
78 | while (1) { | 84 | while (1) { |
79 | /* Find word to start scanning */ | 85 | /* Find word to start scanning */ |
@@ -100,19 +106,26 @@ static ssize_t store_ec_reboot(struct device *dev, | |||
100 | offset++; | 106 | offset++; |
101 | } | 107 | } |
102 | 108 | ||
103 | if (!got_cmd) | 109 | if (!got_cmd) { |
104 | return -EINVAL; | 110 | count = -EINVAL; |
105 | 111 | goto exit; | |
106 | msg.command = EC_CMD_REBOOT_EC; | ||
107 | msg.outsize = sizeof(param); | ||
108 | ret = cros_ec_cmd_xfer(ec, &msg); | ||
109 | if (ret < 0) | ||
110 | return ret; | ||
111 | if (msg.result != EC_RES_SUCCESS) { | ||
112 | dev_dbg(ec->dev, "EC result %d\n", msg.result); | ||
113 | return -EINVAL; | ||
114 | } | 112 | } |
115 | 113 | ||
114 | msg->version = 0; | ||
115 | msg->command = EC_CMD_REBOOT_EC; | ||
116 | msg->outsize = sizeof(*param); | ||
117 | msg->insize = 0; | ||
118 | ret = cros_ec_cmd_xfer(ec, msg); | ||
119 | if (ret < 0) { | ||
120 | count = ret; | ||
121 | goto exit; | ||
122 | } | ||
123 | if (msg->result != EC_RES_SUCCESS) { | ||
124 | dev_dbg(ec->dev, "EC result %d\n", msg->result); | ||
125 | count = -EINVAL; | ||
126 | } | ||
127 | exit: | ||
128 | kfree(msg); | ||
116 | return count; | 129 | return count; |
117 | } | 130 | } |
118 | 131 | ||
@@ -123,22 +136,32 @@ static ssize_t show_ec_version(struct device *dev, | |||
123 | struct ec_response_get_version *r_ver; | 136 | struct ec_response_get_version *r_ver; |
124 | struct ec_response_get_chip_info *r_chip; | 137 | struct ec_response_get_chip_info *r_chip; |
125 | struct ec_response_board_version *r_board; | 138 | struct ec_response_board_version *r_board; |
126 | struct cros_ec_command msg = { 0 }; | 139 | struct cros_ec_command *msg; |
127 | int ret; | 140 | int ret; |
128 | int count = 0; | 141 | int count = 0; |
129 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 142 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
130 | 143 | ||
144 | msg = kmalloc(sizeof(*msg) + EC_HOST_PARAM_SIZE, GFP_KERNEL); | ||
145 | if (!msg) | ||
146 | return -ENOMEM; | ||
147 | |||
131 | /* Get versions. RW may change. */ | 148 | /* Get versions. RW may change. */ |
132 | msg.command = EC_CMD_GET_VERSION; | 149 | msg->version = 0; |
133 | msg.insize = sizeof(*r_ver); | 150 | msg->command = EC_CMD_GET_VERSION; |
134 | ret = cros_ec_cmd_xfer(ec, &msg); | 151 | msg->insize = sizeof(*r_ver); |
135 | if (ret < 0) | 152 | msg->outsize = 0; |
136 | return ret; | 153 | ret = cros_ec_cmd_xfer(ec, msg); |
137 | if (msg.result != EC_RES_SUCCESS) | 154 | if (ret < 0) { |
138 | return scnprintf(buf, PAGE_SIZE, | 155 | count = ret; |
139 | "ERROR: EC returned %d\n", msg.result); | 156 | goto exit; |
157 | } | ||
158 | if (msg->result != EC_RES_SUCCESS) { | ||
159 | count = scnprintf(buf, PAGE_SIZE, | ||
160 | "ERROR: EC returned %d\n", msg->result); | ||
161 | goto exit; | ||
162 | } | ||
140 | 163 | ||
141 | r_ver = (struct ec_response_get_version *)msg.indata; | 164 | r_ver = (struct ec_response_get_version *)msg->data; |
142 | /* Strings should be null-terminated, but let's be sure. */ | 165 | /* Strings should be null-terminated, but let's be sure. */ |
143 | r_ver->version_string_ro[sizeof(r_ver->version_string_ro) - 1] = '\0'; | 166 | r_ver->version_string_ro[sizeof(r_ver->version_string_ro) - 1] = '\0'; |
144 | r_ver->version_string_rw[sizeof(r_ver->version_string_rw) - 1] = '\0'; | 167 | r_ver->version_string_rw[sizeof(r_ver->version_string_rw) - 1] = '\0'; |
@@ -152,33 +175,33 @@ static ssize_t show_ec_version(struct device *dev, | |||
152 | image_names[r_ver->current_image] : "?")); | 175 | image_names[r_ver->current_image] : "?")); |
153 | 176 | ||
154 | /* Get build info. */ | 177 | /* Get build info. */ |
155 | msg.command = EC_CMD_GET_BUILD_INFO; | 178 | msg->command = EC_CMD_GET_BUILD_INFO; |
156 | msg.insize = sizeof(msg.indata); | 179 | msg->insize = EC_HOST_PARAM_SIZE; |
157 | ret = cros_ec_cmd_xfer(ec, &msg); | 180 | ret = cros_ec_cmd_xfer(ec, msg); |
158 | if (ret < 0) | 181 | if (ret < 0) |
159 | count += scnprintf(buf + count, PAGE_SIZE - count, | 182 | count += scnprintf(buf + count, PAGE_SIZE - count, |
160 | "Build info: XFER ERROR %d\n", ret); | 183 | "Build info: XFER ERROR %d\n", ret); |
161 | else if (msg.result != EC_RES_SUCCESS) | 184 | else if (msg->result != EC_RES_SUCCESS) |
162 | count += scnprintf(buf + count, PAGE_SIZE - count, | 185 | count += scnprintf(buf + count, PAGE_SIZE - count, |
163 | "Build info: EC error %d\n", msg.result); | 186 | "Build info: EC error %d\n", msg->result); |
164 | else { | 187 | else { |
165 | msg.indata[sizeof(msg.indata) - 1] = '\0'; | 188 | msg->data[sizeof(msg->data) - 1] = '\0'; |
166 | count += scnprintf(buf + count, PAGE_SIZE - count, | 189 | count += scnprintf(buf + count, PAGE_SIZE - count, |
167 | "Build info: %s\n", msg.indata); | 190 | "Build info: %s\n", msg->data); |
168 | } | 191 | } |
169 | 192 | ||
170 | /* Get chip info. */ | 193 | /* Get chip info. */ |
171 | msg.command = EC_CMD_GET_CHIP_INFO; | 194 | msg->command = EC_CMD_GET_CHIP_INFO; |
172 | msg.insize = sizeof(*r_chip); | 195 | msg->insize = sizeof(*r_chip); |
173 | ret = cros_ec_cmd_xfer(ec, &msg); | 196 | ret = cros_ec_cmd_xfer(ec, msg); |
174 | if (ret < 0) | 197 | if (ret < 0) |
175 | count += scnprintf(buf + count, PAGE_SIZE - count, | 198 | count += scnprintf(buf + count, PAGE_SIZE - count, |
176 | "Chip info: XFER ERROR %d\n", ret); | 199 | "Chip info: XFER ERROR %d\n", ret); |
177 | else if (msg.result != EC_RES_SUCCESS) | 200 | else if (msg->result != EC_RES_SUCCESS) |
178 | count += scnprintf(buf + count, PAGE_SIZE - count, | 201 | count += scnprintf(buf + count, PAGE_SIZE - count, |
179 | "Chip info: EC error %d\n", msg.result); | 202 | "Chip info: EC error %d\n", msg->result); |
180 | else { | 203 | else { |
181 | r_chip = (struct ec_response_get_chip_info *)msg.indata; | 204 | r_chip = (struct ec_response_get_chip_info *)msg->data; |
182 | 205 | ||
183 | r_chip->vendor[sizeof(r_chip->vendor) - 1] = '\0'; | 206 | r_chip->vendor[sizeof(r_chip->vendor) - 1] = '\0'; |
184 | r_chip->name[sizeof(r_chip->name) - 1] = '\0'; | 207 | r_chip->name[sizeof(r_chip->name) - 1] = '\0'; |
@@ -192,23 +215,25 @@ static ssize_t show_ec_version(struct device *dev, | |||
192 | } | 215 | } |
193 | 216 | ||
194 | /* Get board version */ | 217 | /* Get board version */ |
195 | msg.command = EC_CMD_GET_BOARD_VERSION; | 218 | msg->command = EC_CMD_GET_BOARD_VERSION; |
196 | msg.insize = sizeof(*r_board); | 219 | msg->insize = sizeof(*r_board); |
197 | ret = cros_ec_cmd_xfer(ec, &msg); | 220 | ret = cros_ec_cmd_xfer(ec, msg); |
198 | if (ret < 0) | 221 | if (ret < 0) |
199 | count += scnprintf(buf + count, PAGE_SIZE - count, | 222 | count += scnprintf(buf + count, PAGE_SIZE - count, |
200 | "Board version: XFER ERROR %d\n", ret); | 223 | "Board version: XFER ERROR %d\n", ret); |
201 | else if (msg.result != EC_RES_SUCCESS) | 224 | else if (msg->result != EC_RES_SUCCESS) |
202 | count += scnprintf(buf + count, PAGE_SIZE - count, | 225 | count += scnprintf(buf + count, PAGE_SIZE - count, |
203 | "Board version: EC error %d\n", msg.result); | 226 | "Board version: EC error %d\n", msg->result); |
204 | else { | 227 | else { |
205 | r_board = (struct ec_response_board_version *)msg.indata; | 228 | r_board = (struct ec_response_board_version *)msg->data; |
206 | 229 | ||
207 | count += scnprintf(buf + count, PAGE_SIZE - count, | 230 | count += scnprintf(buf + count, PAGE_SIZE - count, |
208 | "Board version: %d\n", | 231 | "Board version: %d\n", |
209 | r_board->board_version); | 232 | r_board->board_version); |
210 | } | 233 | } |
211 | 234 | ||
235 | exit: | ||
236 | kfree(msg); | ||
212 | return count; | 237 | return count; |
213 | } | 238 | } |
214 | 239 | ||
@@ -216,27 +241,38 @@ static ssize_t show_ec_flashinfo(struct device *dev, | |||
216 | struct device_attribute *attr, char *buf) | 241 | struct device_attribute *attr, char *buf) |
217 | { | 242 | { |
218 | struct ec_response_flash_info *resp; | 243 | struct ec_response_flash_info *resp; |
219 | struct cros_ec_command msg = { 0 }; | 244 | struct cros_ec_command *msg; |
220 | int ret; | 245 | int ret; |
221 | struct cros_ec_device *ec = dev_get_drvdata(dev); | 246 | struct cros_ec_device *ec = dev_get_drvdata(dev); |
222 | 247 | ||
248 | msg = kmalloc(sizeof(*msg) + sizeof(*resp), GFP_KERNEL); | ||
249 | if (!msg) | ||
250 | return -ENOMEM; | ||
251 | |||
223 | /* The flash info shouldn't ever change, but ask each time anyway. */ | 252 | /* The flash info shouldn't ever change, but ask each time anyway. */ |
224 | msg.command = EC_CMD_FLASH_INFO; | 253 | msg->version = 0; |
225 | msg.insize = sizeof(*resp); | 254 | msg->command = EC_CMD_FLASH_INFO; |
226 | ret = cros_ec_cmd_xfer(ec, &msg); | 255 | msg->insize = sizeof(*resp); |
256 | msg->outsize = 0; | ||
257 | ret = cros_ec_cmd_xfer(ec, msg); | ||
227 | if (ret < 0) | 258 | if (ret < 0) |
228 | return ret; | 259 | goto exit; |
229 | if (msg.result != EC_RES_SUCCESS) | 260 | if (msg->result != EC_RES_SUCCESS) { |
230 | return scnprintf(buf, PAGE_SIZE, | 261 | ret = scnprintf(buf, PAGE_SIZE, |
231 | "ERROR: EC returned %d\n", msg.result); | 262 | "ERROR: EC returned %d\n", msg->result); |
232 | 263 | goto exit; | |
233 | resp = (struct ec_response_flash_info *)msg.indata; | 264 | } |
234 | 265 | ||
235 | return scnprintf(buf, PAGE_SIZE, | 266 | resp = (struct ec_response_flash_info *)msg->data; |
236 | "FlashSize %d\nWriteSize %d\n" | 267 | |
237 | "EraseSize %d\nProtectSize %d\n", | 268 | ret = scnprintf(buf, PAGE_SIZE, |
238 | resp->flash_size, resp->write_block_size, | 269 | "FlashSize %d\nWriteSize %d\n" |
239 | resp->erase_block_size, resp->protect_block_size); | 270 | "EraseSize %d\nProtectSize %d\n", |
271 | resp->flash_size, resp->write_block_size, | ||
272 | resp->erase_block_size, resp->protect_block_size); | ||
273 | exit: | ||
274 | kfree(msg); | ||
275 | return ret; | ||
240 | } | 276 | } |
241 | 277 | ||
242 | /* Module initialization */ | 278 | /* Module initialization */ |