0001
0002
0003
0004
0005
0006
0007
0008
0009
0010 #include <linux/ctype.h>
0011 #include <linux/debugfs.h>
0012 #include <linux/fs.h>
0013 #include <linux/module.h>
0014 #include <linux/platform_data/wilco-ec.h>
0015 #include <linux/platform_device.h>
0016
0017 #define DRV_NAME "wilco-ec-debugfs"
0018
0019
0020 #define FORMATTED_BUFFER_SIZE (EC_MAILBOX_DATA_SIZE * 4)
0021
0022 struct wilco_ec_debugfs {
0023 struct wilco_ec_device *ec;
0024 struct dentry *dir;
0025 size_t response_size;
0026 u8 raw_data[EC_MAILBOX_DATA_SIZE];
0027 u8 formatted_data[FORMATTED_BUFFER_SIZE];
0028 };
0029 static struct wilco_ec_debugfs *debug_info;
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047 static int parse_hex_sentence(const char *in, int isize, u8 *out, int osize)
0048 {
0049 int n_parsed = 0;
0050 int word_start = 0;
0051 int word_end;
0052 int word_len;
0053
0054 #define MAX_WORD_SIZE 16
0055 char tmp[MAX_WORD_SIZE + 1];
0056 u8 byte;
0057
0058 while (word_start < isize && n_parsed < osize) {
0059
0060 while (word_start < isize && isspace(in[word_start]))
0061 word_start++;
0062
0063 if (word_start >= isize)
0064 break;
0065
0066
0067 word_end = word_start;
0068 while (word_end < isize && !isspace(in[word_end]))
0069 word_end++;
0070
0071
0072 word_len = word_end - word_start;
0073 if (word_len > MAX_WORD_SIZE)
0074 return -EINVAL;
0075 memcpy(tmp, in + word_start, word_len);
0076 tmp[word_len] = '\0';
0077
0078
0079
0080
0081
0082
0083 if (kstrtou8(tmp, 16, &byte))
0084 return -EINVAL;
0085 out[n_parsed++] = byte;
0086
0087 word_start = word_end;
0088 }
0089 return n_parsed;
0090 }
0091
0092
0093 #define TYPE_AND_DATA_SIZE ((EC_MAILBOX_DATA_SIZE) + 2)
0094
0095 static ssize_t raw_write(struct file *file, const char __user *user_buf,
0096 size_t count, loff_t *ppos)
0097 {
0098 char *buf = debug_info->formatted_data;
0099 struct wilco_ec_message msg;
0100 u8 request_data[TYPE_AND_DATA_SIZE];
0101 ssize_t kcount;
0102 int ret;
0103
0104 if (count > FORMATTED_BUFFER_SIZE)
0105 return -EINVAL;
0106
0107 kcount = simple_write_to_buffer(buf, FORMATTED_BUFFER_SIZE, ppos,
0108 user_buf, count);
0109 if (kcount < 0)
0110 return kcount;
0111
0112 ret = parse_hex_sentence(buf, kcount, request_data, TYPE_AND_DATA_SIZE);
0113 if (ret < 0)
0114 return ret;
0115
0116 if (ret < 3)
0117 return -EINVAL;
0118
0119 msg.type = request_data[0] << 8 | request_data[1];
0120 msg.flags = 0;
0121 msg.request_data = request_data + 2;
0122 msg.request_size = ret - 2;
0123 memset(debug_info->raw_data, 0, sizeof(debug_info->raw_data));
0124 msg.response_data = debug_info->raw_data;
0125 msg.response_size = EC_MAILBOX_DATA_SIZE;
0126
0127 ret = wilco_ec_mailbox(debug_info->ec, &msg);
0128 if (ret < 0)
0129 return ret;
0130 debug_info->response_size = ret;
0131
0132 return count;
0133 }
0134
0135 static ssize_t raw_read(struct file *file, char __user *user_buf, size_t count,
0136 loff_t *ppos)
0137 {
0138 int fmt_len = 0;
0139
0140 if (debug_info->response_size) {
0141 fmt_len = hex_dump_to_buffer(debug_info->raw_data,
0142 debug_info->response_size,
0143 16, 1, debug_info->formatted_data,
0144 sizeof(debug_info->formatted_data),
0145 true);
0146
0147 debug_info->response_size = 0;
0148 }
0149
0150 return simple_read_from_buffer(user_buf, count, ppos,
0151 debug_info->formatted_data, fmt_len);
0152 }
0153
0154 static const struct file_operations fops_raw = {
0155 .owner = THIS_MODULE,
0156 .read = raw_read,
0157 .write = raw_write,
0158 .llseek = no_llseek,
0159 };
0160
0161 #define CMD_KB_CHROME 0x88
0162 #define SUB_CMD_H1_GPIO 0x0A
0163 #define SUB_CMD_TEST_EVENT 0x0B
0164
0165 struct ec_request {
0166 u8 cmd;
0167 u8 reserved;
0168 u8 sub_cmd;
0169 } __packed;
0170
0171 struct ec_response {
0172 u8 status;
0173 u8 val;
0174 } __packed;
0175
0176 static int send_ec_cmd(struct wilco_ec_device *ec, u8 sub_cmd, u8 *out_val)
0177 {
0178 struct ec_request rq;
0179 struct ec_response rs;
0180 struct wilco_ec_message msg;
0181 int ret;
0182
0183 memset(&rq, 0, sizeof(rq));
0184 rq.cmd = CMD_KB_CHROME;
0185 rq.sub_cmd = sub_cmd;
0186
0187 memset(&msg, 0, sizeof(msg));
0188 msg.type = WILCO_EC_MSG_LEGACY;
0189 msg.request_data = &rq;
0190 msg.request_size = sizeof(rq);
0191 msg.response_data = &rs;
0192 msg.response_size = sizeof(rs);
0193 ret = wilco_ec_mailbox(ec, &msg);
0194 if (ret < 0)
0195 return ret;
0196 if (rs.status)
0197 return -EIO;
0198
0199 *out_val = rs.val;
0200
0201 return 0;
0202 }
0203
0204
0205
0206
0207
0208
0209 static int h1_gpio_get(void *arg, u64 *val)
0210 {
0211 int ret;
0212
0213 ret = send_ec_cmd(arg, SUB_CMD_H1_GPIO, (u8 *)val);
0214 if (ret == 0)
0215 *val &= 0xFF;
0216 return ret;
0217 }
0218
0219 DEFINE_DEBUGFS_ATTRIBUTE(fops_h1_gpio, h1_gpio_get, NULL, "0x%02llx\n");
0220
0221
0222
0223
0224
0225
0226 static int test_event_set(void *arg, u64 val)
0227 {
0228 u8 ret;
0229
0230 return send_ec_cmd(arg, SUB_CMD_TEST_EVENT, &ret);
0231 }
0232
0233
0234 DEFINE_DEBUGFS_ATTRIBUTE(fops_test_event, NULL, test_event_set, "%llu\n");
0235
0236
0237
0238
0239
0240
0241
0242
0243
0244
0245 static int wilco_ec_debugfs_probe(struct platform_device *pdev)
0246 {
0247 struct wilco_ec_device *ec = dev_get_drvdata(pdev->dev.parent);
0248
0249 debug_info = devm_kzalloc(&pdev->dev, sizeof(*debug_info), GFP_KERNEL);
0250 if (!debug_info)
0251 return 0;
0252 debug_info->ec = ec;
0253 debug_info->dir = debugfs_create_dir("wilco_ec", NULL);
0254 if (!debug_info->dir)
0255 return 0;
0256 debugfs_create_file("raw", 0644, debug_info->dir, NULL, &fops_raw);
0257 debugfs_create_file("h1_gpio", 0444, debug_info->dir, ec,
0258 &fops_h1_gpio);
0259 debugfs_create_file("test_event", 0200, debug_info->dir, ec,
0260 &fops_test_event);
0261
0262 return 0;
0263 }
0264
0265 static int wilco_ec_debugfs_remove(struct platform_device *pdev)
0266 {
0267 debugfs_remove_recursive(debug_info->dir);
0268
0269 return 0;
0270 }
0271
0272 static struct platform_driver wilco_ec_debugfs_driver = {
0273 .driver = {
0274 .name = DRV_NAME,
0275 },
0276 .probe = wilco_ec_debugfs_probe,
0277 .remove = wilco_ec_debugfs_remove,
0278 };
0279
0280 module_platform_driver(wilco_ec_debugfs_driver);
0281
0282 MODULE_ALIAS("platform:" DRV_NAME);
0283 MODULE_AUTHOR("Nick Crews <ncrews@chromium.org>");
0284 MODULE_LICENSE("GPL v2");
0285 MODULE_DESCRIPTION("Wilco EC debugfs driver");