6
6
* Licensed under the GPL v2 or later.
7
7
*/
8
8
#include <linux/completion.h>
9
+ #include <linux/debugfs.h>
9
10
#include <linux/spinlock.h>
10
11
#include <linux/mutex.h>
11
12
#include <linux/platform_device.h>
@@ -31,6 +32,8 @@ struct ec_cmd_desc {
31
32
struct olpc_ec_priv {
32
33
struct olpc_ec_driver * drv ;
33
34
35
+ struct dentry * dbgfs_dir ;
36
+
34
37
/*
35
38
* Running an EC command while suspending means we don't always finish
36
39
* the command before the machine suspends. This means that the EC
@@ -144,6 +147,114 @@ int olpc_ec_cmd(u8 cmd, u8 *inbuf, size_t inlen, u8 *outbuf, size_t outlen)
144
147
}
145
148
EXPORT_SYMBOL_GPL (olpc_ec_cmd );
146
149
150
+ #ifdef CONFIG_DEBUG_FS
151
+
152
+ /*
153
+ * debugfs support for "generic commands", to allow sending
154
+ * arbitrary EC commands from userspace.
155
+ */
156
+
157
+ #define EC_MAX_CMD_ARGS (5 + 1) /* cmd byte + 5 args */
158
+ #define EC_MAX_CMD_REPLY (8)
159
+
160
+ static DEFINE_MUTEX (ec_dbgfs_lock );
161
+ static unsigned char ec_dbgfs_resp [EC_MAX_CMD_REPLY ];
162
+ static unsigned int ec_dbgfs_resp_bytes ;
163
+
164
+ static ssize_t ec_dbgfs_cmd_write (struct file * file , const char __user * buf ,
165
+ size_t size , loff_t * ppos )
166
+ {
167
+ int i , m ;
168
+ unsigned char ec_cmd [EC_MAX_CMD_ARGS ];
169
+ unsigned int ec_cmd_int [EC_MAX_CMD_ARGS ];
170
+ char cmdbuf [64 ];
171
+ int ec_cmd_bytes ;
172
+
173
+ mutex_lock (& ec_dbgfs_lock );
174
+
175
+ size = simple_write_to_buffer (cmdbuf , sizeof (cmdbuf ), ppos , buf , size );
176
+
177
+ m = sscanf (cmdbuf , "%x:%u %x %x %x %x %x" , & ec_cmd_int [0 ],
178
+ & ec_dbgfs_resp_bytes , & ec_cmd_int [1 ], & ec_cmd_int [2 ],
179
+ & ec_cmd_int [3 ], & ec_cmd_int [4 ], & ec_cmd_int [5 ]);
180
+ if (m < 2 || ec_dbgfs_resp_bytes > EC_MAX_CMD_REPLY ) {
181
+ /* reset to prevent overflow on read */
182
+ ec_dbgfs_resp_bytes = 0 ;
183
+
184
+ pr_debug ("olpc-ec: bad ec cmd: cmd:response-count [arg1 [arg2 ...]]\n" );
185
+ size = - EINVAL ;
186
+ goto out ;
187
+ }
188
+
189
+ /* convert scanf'd ints to char */
190
+ ec_cmd_bytes = m - 2 ;
191
+ for (i = 0 ; i <= ec_cmd_bytes ; i ++ )
192
+ ec_cmd [i ] = ec_cmd_int [i ];
193
+
194
+ pr_debug ("olpc-ec: debugfs cmd 0x%02x with %d args %02x %02x %02x %02x %02x, want %d returns\n" ,
195
+ ec_cmd [0 ], ec_cmd_bytes , ec_cmd [1 ], ec_cmd [2 ],
196
+ ec_cmd [3 ], ec_cmd [4 ], ec_cmd [5 ], ec_dbgfs_resp_bytes );
197
+
198
+ olpc_ec_cmd (ec_cmd [0 ], (ec_cmd_bytes == 0 ) ? NULL : & ec_cmd [1 ],
199
+ ec_cmd_bytes , ec_dbgfs_resp , ec_dbgfs_resp_bytes );
200
+
201
+ pr_debug ("olpc-ec: response %02x %02x %02x %02x %02x %02x %02x %02x (%d bytes expected)\n" ,
202
+ ec_dbgfs_resp [0 ], ec_dbgfs_resp [1 ], ec_dbgfs_resp [2 ],
203
+ ec_dbgfs_resp [3 ], ec_dbgfs_resp [4 ], ec_dbgfs_resp [5 ],
204
+ ec_dbgfs_resp [6 ], ec_dbgfs_resp [7 ],
205
+ ec_dbgfs_resp_bytes );
206
+
207
+ out :
208
+ mutex_unlock (& ec_dbgfs_lock );
209
+ return size ;
210
+ }
211
+
212
+ static ssize_t ec_dbgfs_cmd_read (struct file * file , char __user * buf ,
213
+ size_t size , loff_t * ppos )
214
+ {
215
+ unsigned int i , r ;
216
+ char * rp ;
217
+ char respbuf [64 ];
218
+
219
+ mutex_lock (& ec_dbgfs_lock );
220
+ rp = respbuf ;
221
+ rp += sprintf (rp , "%02x" , ec_dbgfs_resp [0 ]);
222
+ for (i = 1 ; i < ec_dbgfs_resp_bytes ; i ++ )
223
+ rp += sprintf (rp , ", %02x" , ec_dbgfs_resp [i ]);
224
+ mutex_unlock (& ec_dbgfs_lock );
225
+ rp += sprintf (rp , "\n" );
226
+
227
+ r = rp - respbuf ;
228
+ return simple_read_from_buffer (buf , size , ppos , respbuf , r );
229
+ }
230
+
231
+ static const struct file_operations ec_dbgfs_ops = {
232
+ .write = ec_dbgfs_cmd_write ,
233
+ .read = ec_dbgfs_cmd_read ,
234
+ };
235
+
236
+ static struct dentry * olpc_ec_setup_debugfs (void )
237
+ {
238
+ struct dentry * dbgfs_dir ;
239
+
240
+ dbgfs_dir = debugfs_create_dir ("olpc-ec" , NULL );
241
+ if (IS_ERR_OR_NULL (dbgfs_dir ))
242
+ return NULL ;
243
+
244
+ debugfs_create_file ("cmd" , 0600 , dbgfs_dir , NULL , & ec_dbgfs_ops );
245
+
246
+ return dbgfs_dir ;
247
+ }
248
+
249
+ #else
250
+
251
+ static struct dentry * olpc_ec_setup_debugfs (void )
252
+ {
253
+ return NULL ;
254
+ }
255
+
256
+ #endif /* CONFIG_DEBUG_FS */
257
+
147
258
static int olpc_ec_probe (struct platform_device * pdev )
148
259
{
149
260
struct olpc_ec_priv * ec ;
@@ -160,6 +271,12 @@ static int olpc_ec_probe(struct platform_device *pdev)
160
271
platform_set_drvdata (pdev , ec );
161
272
162
273
err = ec_driver -> probe ? ec_driver -> probe (pdev ) : 0 ;
274
+ if (err ) {
275
+ ec_priv = NULL ;
276
+ kfree (ec );
277
+ } else {
278
+ ec -> dbgfs_dir = olpc_ec_setup_debugfs ();
279
+ }
163
280
164
281
return err ;
165
282
}
0 commit comments