aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-picolcd_debugfs.c
diff options
context:
space:
mode:
authorBruno Prémont <bonbons@linux-vserver.org>2012-07-30 15:38:28 -0400
committerJiri Kosina <jkosina@suse.cz>2012-08-15 04:08:57 -0400
commitfabdbf2fd22fa170b4c5340dbdda5c8cd88fb205 (patch)
tree25d6b1bbfee02aadca929130cb0d35bf8e8f9c17 /drivers/hid/hid-picolcd_debugfs.c
parente8ff13b0bf88b5e696323a1eec877783d965b3c6 (diff)
HID: picoLCD: split driver code
In order to make code maintenance easier, split the vairous functions into individial files (this removes a bunch of #ifdefs). Signed-off-by: Bruno Prémont <bonbons@linux-vserver.org> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-picolcd_debugfs.c')
-rw-r--r--drivers/hid/hid-picolcd_debugfs.c898
1 files changed, 898 insertions, 0 deletions
diff --git a/drivers/hid/hid-picolcd_debugfs.c b/drivers/hid/hid-picolcd_debugfs.c
new file mode 100644
index 000000000000..ff746456823d
--- /dev/null
+++ b/drivers/hid/hid-picolcd_debugfs.c
@@ -0,0 +1,898 @@
1/***************************************************************************
2 * Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> *
3 * *
4 * Based on Logitech G13 driver (v0.4) *
5 * Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> *
6 * *
7 * This program is free software: you can redistribute it and/or modify *
8 * it under the terms of the GNU General Public License as published by *
9 * the Free Software Foundation, version 2 of the License. *
10 * *
11 * This driver is distributed in the hope that it will be useful, but *
12 * WITHOUT ANY WARRANTY; without even the implied warranty of *
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
14 * General Public License for more details. *
15 * *
16 * You should have received a copy of the GNU General Public License *
17 * along with this software. If not see <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
19
20#include <linux/hid.h>
21#include <linux/hid-debug.h>
22#include "usbhid/usbhid.h"
23#include <linux/usb.h>
24
25#include <linux/fb.h>
26#include <linux/seq_file.h>
27#include <linux/debugfs.h>
28
29#include <linux/module.h>
30
31#include "hid-picolcd.h"
32
33
34static int picolcd_debug_reset_show(struct seq_file *f, void *p)
35{
36 if (picolcd_fbinfo((struct picolcd_data *)f->private))
37 seq_printf(f, "all fb\n");
38 else
39 seq_printf(f, "all\n");
40 return 0;
41}
42
43static int picolcd_debug_reset_open(struct inode *inode, struct file *f)
44{
45 return single_open(f, picolcd_debug_reset_show, inode->i_private);
46}
47
48static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf,
49 size_t count, loff_t *ppos)
50{
51 struct picolcd_data *data = ((struct seq_file *)f->private_data)->private;
52 char buf[32];
53 size_t cnt = min(count, sizeof(buf)-1);
54 if (copy_from_user(buf, user_buf, cnt))
55 return -EFAULT;
56
57 while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n'))
58 cnt--;
59 buf[cnt] = '\0';
60 if (strcmp(buf, "all") == 0) {
61 picolcd_reset(data->hdev);
62 picolcd_fb_reset(data, 1);
63 } else if (strcmp(buf, "fb") == 0) {
64 picolcd_fb_reset(data, 1);
65 } else {
66 return -EINVAL;
67 }
68 return count;
69}
70
71static const struct file_operations picolcd_debug_reset_fops = {
72 .owner = THIS_MODULE,
73 .open = picolcd_debug_reset_open,
74 .read = seq_read,
75 .llseek = seq_lseek,
76 .write = picolcd_debug_reset_write,
77 .release = single_release,
78};
79
80/*
81 * The "eeprom" file
82 */
83static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
84 size_t s, loff_t *off)
85{
86 struct picolcd_data *data = f->private_data;
87 struct picolcd_pending *resp;
88 u8 raw_data[3];
89 ssize_t ret = -EIO;
90
91 if (s == 0)
92 return -EINVAL;
93 if (*off > 0x0ff)
94 return 0;
95
96 /* prepare buffer with info about what we want to read (addr & len) */
97 raw_data[0] = *off & 0xff;
98 raw_data[1] = (*off >> 8) & 0xff;
99 raw_data[2] = s < 20 ? s : 20;
100 if (*off + raw_data[2] > 0xff)
101 raw_data[2] = 0x100 - *off;
102 resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data,
103 sizeof(raw_data));
104 if (!resp)
105 return -EIO;
106
107 if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
108 /* successful read :) */
109 ret = resp->raw_data[2];
110 if (ret > s)
111 ret = s;
112 if (copy_to_user(u, resp->raw_data+3, ret))
113 ret = -EFAULT;
114 else
115 *off += ret;
116 } /* anything else is some kind of IO error */
117
118 kfree(resp);
119 return ret;
120}
121
122static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
123 size_t s, loff_t *off)
124{
125 struct picolcd_data *data = f->private_data;
126 struct picolcd_pending *resp;
127 ssize_t ret = -EIO;
128 u8 raw_data[23];
129
130 if (s == 0)
131 return -EINVAL;
132 if (*off > 0x0ff)
133 return -ENOSPC;
134
135 memset(raw_data, 0, sizeof(raw_data));
136 raw_data[0] = *off & 0xff;
137 raw_data[1] = (*off >> 8) & 0xff;
138 raw_data[2] = min((size_t)20, s);
139 if (*off + raw_data[2] > 0xff)
140 raw_data[2] = 0x100 - *off;
141
142 if (copy_from_user(raw_data+3, u, min((u8)20, raw_data[2])))
143 return -EFAULT;
144 resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data,
145 sizeof(raw_data));
146
147 if (!resp)
148 return -EIO;
149
150 if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
151 /* check if written data matches */
152 if (memcmp(raw_data, resp->raw_data, 3+raw_data[2]) == 0) {
153 *off += raw_data[2];
154 ret = raw_data[2];
155 }
156 }
157 kfree(resp);
158 return ret;
159}
160
161/*
162 * Notes:
163 * - read/write happens in chunks of at most 20 bytes, it's up to userspace
164 * to loop in order to get more data.
165 * - on write errors on otherwise correct write request the bytes
166 * that should have been written are in undefined state.
167 */
168static const struct file_operations picolcd_debug_eeprom_fops = {
169 .owner = THIS_MODULE,
170 .open = simple_open,
171 .read = picolcd_debug_eeprom_read,
172 .write = picolcd_debug_eeprom_write,
173 .llseek = generic_file_llseek,
174};
175
176/*
177 * The "flash" file
178 */
179/* record a flash address to buf (bounds check to be done by caller) */
180static int _picolcd_flash_setaddr(struct picolcd_data *data, u8 *buf, long off)
181{
182 buf[0] = off & 0xff;
183 buf[1] = (off >> 8) & 0xff;
184 if (data->addr_sz == 3)
185 buf[2] = (off >> 16) & 0xff;
186 return data->addr_sz == 2 ? 2 : 3;
187}
188
189/* read a given size of data (bounds check to be done by caller) */
190static ssize_t _picolcd_flash_read(struct picolcd_data *data, int report_id,
191 char __user *u, size_t s, loff_t *off)
192{
193 struct picolcd_pending *resp;
194 u8 raw_data[4];
195 ssize_t ret = 0;
196 int len_off, err = -EIO;
197
198 while (s > 0) {
199 err = -EIO;
200 len_off = _picolcd_flash_setaddr(data, raw_data, *off);
201 raw_data[len_off] = s > 32 ? 32 : s;
202 resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off+1);
203 if (!resp || !resp->in_report)
204 goto skip;
205 if (resp->in_report->id == REPORT_MEMORY ||
206 resp->in_report->id == REPORT_BL_READ_MEMORY) {
207 if (memcmp(raw_data, resp->raw_data, len_off+1) != 0)
208 goto skip;
209 if (copy_to_user(u+ret, resp->raw_data+len_off+1, raw_data[len_off])) {
210 err = -EFAULT;
211 goto skip;
212 }
213 *off += raw_data[len_off];
214 s -= raw_data[len_off];
215 ret += raw_data[len_off];
216 err = 0;
217 }
218skip:
219 kfree(resp);
220 if (err)
221 return ret > 0 ? ret : err;
222 }
223 return ret;
224}
225
226static ssize_t picolcd_debug_flash_read(struct file *f, char __user *u,
227 size_t s, loff_t *off)
228{
229 struct picolcd_data *data = f->private_data;
230
231 if (s == 0)
232 return -EINVAL;
233 if (*off > 0x05fff)
234 return 0;
235 if (*off + s > 0x05fff)
236 s = 0x06000 - *off;
237
238 if (data->status & PICOLCD_BOOTLOADER)
239 return _picolcd_flash_read(data, REPORT_BL_READ_MEMORY, u, s, off);
240 else
241 return _picolcd_flash_read(data, REPORT_READ_MEMORY, u, s, off);
242}
243
244/* erase block aligned to 64bytes boundary */
245static ssize_t _picolcd_flash_erase64(struct picolcd_data *data, int report_id,
246 loff_t *off)
247{
248 struct picolcd_pending *resp;
249 u8 raw_data[3];
250 int len_off;
251 ssize_t ret = -EIO;
252
253 if (*off & 0x3f)
254 return -EINVAL;
255
256 len_off = _picolcd_flash_setaddr(data, raw_data, *off);
257 resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, len_off);
258 if (!resp || !resp->in_report)
259 goto skip;
260 if (resp->in_report->id == REPORT_MEMORY ||
261 resp->in_report->id == REPORT_BL_ERASE_MEMORY) {
262 if (memcmp(raw_data, resp->raw_data, len_off) != 0)
263 goto skip;
264 ret = 0;
265 }
266skip:
267 kfree(resp);
268 return ret;
269}
270
271/* write a given size of data (bounds check to be done by caller) */
272static ssize_t _picolcd_flash_write(struct picolcd_data *data, int report_id,
273 const char __user *u, size_t s, loff_t *off)
274{
275 struct picolcd_pending *resp;
276 u8 raw_data[36];
277 ssize_t ret = 0;
278 int len_off, err = -EIO;
279
280 while (s > 0) {
281 err = -EIO;
282 len_off = _picolcd_flash_setaddr(data, raw_data, *off);
283 raw_data[len_off] = s > 32 ? 32 : s;
284 if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) {
285 err = -EFAULT;
286 break;
287 }
288 resp = picolcd_send_and_wait(data->hdev, report_id, raw_data,
289 len_off+1+raw_data[len_off]);
290 if (!resp || !resp->in_report)
291 goto skip;
292 if (resp->in_report->id == REPORT_MEMORY ||
293 resp->in_report->id == REPORT_BL_WRITE_MEMORY) {
294 if (memcmp(raw_data, resp->raw_data, len_off+1+raw_data[len_off]) != 0)
295 goto skip;
296 *off += raw_data[len_off];
297 s -= raw_data[len_off];
298 ret += raw_data[len_off];
299 err = 0;
300 }
301skip:
302 kfree(resp);
303 if (err)
304 break;
305 }
306 return ret > 0 ? ret : err;
307}
308
309static ssize_t picolcd_debug_flash_write(struct file *f, const char __user *u,
310 size_t s, loff_t *off)
311{
312 struct picolcd_data *data = f->private_data;
313 ssize_t err, ret = 0;
314 int report_erase, report_write;
315
316 if (s == 0)
317 return -EINVAL;
318 if (*off > 0x5fff)
319 return -ENOSPC;
320 if (s & 0x3f)
321 return -EINVAL;
322 if (*off & 0x3f)
323 return -EINVAL;
324
325 if (data->status & PICOLCD_BOOTLOADER) {
326 report_erase = REPORT_BL_ERASE_MEMORY;
327 report_write = REPORT_BL_WRITE_MEMORY;
328 } else {
329 report_erase = REPORT_ERASE_MEMORY;
330 report_write = REPORT_WRITE_MEMORY;
331 }
332 mutex_lock(&data->mutex_flash);
333 while (s > 0) {
334 err = _picolcd_flash_erase64(data, report_erase, off);
335 if (err)
336 break;
337 err = _picolcd_flash_write(data, report_write, u, 64, off);
338 if (err < 0)
339 break;
340 ret += err;
341 *off += err;
342 s -= err;
343 if (err != 64)
344 break;
345 }
346 mutex_unlock(&data->mutex_flash);
347 return ret > 0 ? ret : err;
348}
349
350/*
351 * Notes:
352 * - concurrent writing is prevented by mutex and all writes must be
353 * n*64 bytes and 64-byte aligned, each write being preceded by an
354 * ERASE which erases a 64byte block.
355 * If less than requested was written or an error is returned for an
356 * otherwise correct write request the next 64-byte block which should
357 * have been written is in undefined state (mostly: original, erased,
358 * (half-)written with write error)
359 * - reading can happen without special restriction
360 */
361static const struct file_operations picolcd_debug_flash_fops = {
362 .owner = THIS_MODULE,
363 .open = simple_open,
364 .read = picolcd_debug_flash_read,
365 .write = picolcd_debug_flash_write,
366 .llseek = generic_file_llseek,
367};
368
369
370/*
371 * Helper code for HID report level dumping/debugging
372 */
373static const char *error_codes[] = {
374 "success", "parameter missing", "data_missing", "block readonly",
375 "block not erasable", "block too big", "section overflow",
376 "invalid command length", "invalid data length",
377};
378
379static void dump_buff_as_hex(char *dst, size_t dst_sz, const u8 *data,
380 const size_t data_len)
381{
382 int i, j;
383 for (i = j = 0; i < data_len && j + 3 < dst_sz; i++) {
384 dst[j++] = hex_asc[(data[i] >> 4) & 0x0f];
385 dst[j++] = hex_asc[data[i] & 0x0f];
386 dst[j++] = ' ';
387 }
388 if (j < dst_sz) {
389 dst[j--] = '\0';
390 dst[j] = '\n';
391 } else
392 dst[j] = '\0';
393}
394
395void picolcd_debug_out_report(struct picolcd_data *data,
396 struct hid_device *hdev, struct hid_report *report)
397{
398 u8 raw_data[70];
399 int raw_size = (report->size >> 3) + 1;
400 char *buff;
401#define BUFF_SZ 256
402
403 /* Avoid unnecessary overhead if debugfs is disabled */
404 if (!hdev->debug_events)
405 return;
406
407 buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
408 if (!buff)
409 return;
410
411 snprintf(buff, BUFF_SZ, "\nout report %d (size %d) = ",
412 report->id, raw_size);
413 hid_debug_event(hdev, buff);
414 if (raw_size + 5 > sizeof(raw_data)) {
415 kfree(buff);
416 hid_debug_event(hdev, " TOO BIG\n");
417 return;
418 } else {
419 raw_data[0] = report->id;
420 hid_output_report(report, raw_data);
421 dump_buff_as_hex(buff, BUFF_SZ, raw_data, raw_size);
422 hid_debug_event(hdev, buff);
423 }
424
425 switch (report->id) {
426 case REPORT_LED_STATE:
427 /* 1 data byte with GPO state */
428 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
429 "REPORT_LED_STATE", report->id, raw_size-1);
430 hid_debug_event(hdev, buff);
431 snprintf(buff, BUFF_SZ, "\tGPO state: 0x%02x\n", raw_data[1]);
432 hid_debug_event(hdev, buff);
433 break;
434 case REPORT_BRIGHTNESS:
435 /* 1 data byte with brightness */
436 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
437 "REPORT_BRIGHTNESS", report->id, raw_size-1);
438 hid_debug_event(hdev, buff);
439 snprintf(buff, BUFF_SZ, "\tBrightness: 0x%02x\n", raw_data[1]);
440 hid_debug_event(hdev, buff);
441 break;
442 case REPORT_CONTRAST:
443 /* 1 data byte with contrast */
444 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
445 "REPORT_CONTRAST", report->id, raw_size-1);
446 hid_debug_event(hdev, buff);
447 snprintf(buff, BUFF_SZ, "\tContrast: 0x%02x\n", raw_data[1]);
448 hid_debug_event(hdev, buff);
449 break;
450 case REPORT_RESET:
451 /* 2 data bytes with reset duration in ms */
452 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
453 "REPORT_RESET", report->id, raw_size-1);
454 hid_debug_event(hdev, buff);
455 snprintf(buff, BUFF_SZ, "\tDuration: 0x%02x%02x (%dms)\n",
456 raw_data[2], raw_data[1], raw_data[2] << 8 | raw_data[1]);
457 hid_debug_event(hdev, buff);
458 break;
459 case REPORT_LCD_CMD:
460 /* 63 data bytes with LCD commands */
461 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
462 "REPORT_LCD_CMD", report->id, raw_size-1);
463 hid_debug_event(hdev, buff);
464 /* TODO: format decoding */
465 break;
466 case REPORT_LCD_DATA:
467 /* 63 data bytes with LCD data */
468 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
469 "REPORT_LCD_CMD", report->id, raw_size-1);
470 /* TODO: format decoding */
471 hid_debug_event(hdev, buff);
472 break;
473 case REPORT_LCD_CMD_DATA:
474 /* 63 data bytes with LCD commands and data */
475 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
476 "REPORT_LCD_CMD", report->id, raw_size-1);
477 /* TODO: format decoding */
478 hid_debug_event(hdev, buff);
479 break;
480 case REPORT_EE_READ:
481 /* 3 data bytes with read area description */
482 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
483 "REPORT_EE_READ", report->id, raw_size-1);
484 hid_debug_event(hdev, buff);
485 snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
486 raw_data[2], raw_data[1]);
487 hid_debug_event(hdev, buff);
488 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
489 hid_debug_event(hdev, buff);
490 break;
491 case REPORT_EE_WRITE:
492 /* 3+1..20 data bytes with write area description */
493 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
494 "REPORT_EE_WRITE", report->id, raw_size-1);
495 hid_debug_event(hdev, buff);
496 snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
497 raw_data[2], raw_data[1]);
498 hid_debug_event(hdev, buff);
499 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
500 hid_debug_event(hdev, buff);
501 if (raw_data[3] == 0) {
502 snprintf(buff, BUFF_SZ, "\tNo data\n");
503 } else if (raw_data[3] + 4 <= raw_size) {
504 snprintf(buff, BUFF_SZ, "\tData: ");
505 hid_debug_event(hdev, buff);
506 dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
507 } else {
508 snprintf(buff, BUFF_SZ, "\tData overflowed\n");
509 }
510 hid_debug_event(hdev, buff);
511 break;
512 case REPORT_ERASE_MEMORY:
513 case REPORT_BL_ERASE_MEMORY:
514 /* 3 data bytes with pointer inside erase block */
515 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
516 "REPORT_ERASE_MEMORY", report->id, raw_size-1);
517 hid_debug_event(hdev, buff);
518 switch (data->addr_sz) {
519 case 2:
520 snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n",
521 raw_data[2], raw_data[1]);
522 break;
523 case 3:
524 snprintf(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x%02x\n",
525 raw_data[3], raw_data[2], raw_data[1]);
526 break;
527 default:
528 snprintf(buff, BUFF_SZ, "\tNot supported\n");
529 }
530 hid_debug_event(hdev, buff);
531 break;
532 case REPORT_READ_MEMORY:
533 case REPORT_BL_READ_MEMORY:
534 /* 4 data bytes with read area description */
535 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
536 "REPORT_READ_MEMORY", report->id, raw_size-1);
537 hid_debug_event(hdev, buff);
538 switch (data->addr_sz) {
539 case 2:
540 snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
541 raw_data[2], raw_data[1]);
542 hid_debug_event(hdev, buff);
543 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
544 break;
545 case 3:
546 snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
547 raw_data[3], raw_data[2], raw_data[1]);
548 hid_debug_event(hdev, buff);
549 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
550 break;
551 default:
552 snprintf(buff, BUFF_SZ, "\tNot supported\n");
553 }
554 hid_debug_event(hdev, buff);
555 break;
556 case REPORT_WRITE_MEMORY:
557 case REPORT_BL_WRITE_MEMORY:
558 /* 4+1..32 data bytes with write adrea description */
559 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
560 "REPORT_WRITE_MEMORY", report->id, raw_size-1);
561 hid_debug_event(hdev, buff);
562 switch (data->addr_sz) {
563 case 2:
564 snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
565 raw_data[2], raw_data[1]);
566 hid_debug_event(hdev, buff);
567 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
568 hid_debug_event(hdev, buff);
569 if (raw_data[3] == 0) {
570 snprintf(buff, BUFF_SZ, "\tNo data\n");
571 } else if (raw_data[3] + 4 <= raw_size) {
572 snprintf(buff, BUFF_SZ, "\tData: ");
573 hid_debug_event(hdev, buff);
574 dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
575 } else {
576 snprintf(buff, BUFF_SZ, "\tData overflowed\n");
577 }
578 break;
579 case 3:
580 snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
581 raw_data[3], raw_data[2], raw_data[1]);
582 hid_debug_event(hdev, buff);
583 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
584 hid_debug_event(hdev, buff);
585 if (raw_data[4] == 0) {
586 snprintf(buff, BUFF_SZ, "\tNo data\n");
587 } else if (raw_data[4] + 5 <= raw_size) {
588 snprintf(buff, BUFF_SZ, "\tData: ");
589 hid_debug_event(hdev, buff);
590 dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
591 } else {
592 snprintf(buff, BUFF_SZ, "\tData overflowed\n");
593 }
594 break;
595 default:
596 snprintf(buff, BUFF_SZ, "\tNot supported\n");
597 }
598 hid_debug_event(hdev, buff);
599 break;
600 case REPORT_SPLASH_RESTART:
601 /* TODO */
602 break;
603 case REPORT_EXIT_KEYBOARD:
604 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
605 "REPORT_EXIT_KEYBOARD", report->id, raw_size-1);
606 hid_debug_event(hdev, buff);
607 snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
608 raw_data[1] | (raw_data[2] << 8),
609 raw_data[2], raw_data[1]);
610 hid_debug_event(hdev, buff);
611 break;
612 case REPORT_VERSION:
613 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
614 "REPORT_VERSION", report->id, raw_size-1);
615 hid_debug_event(hdev, buff);
616 break;
617 case REPORT_DEVID:
618 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
619 "REPORT_DEVID", report->id, raw_size-1);
620 hid_debug_event(hdev, buff);
621 break;
622 case REPORT_SPLASH_SIZE:
623 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
624 "REPORT_SPLASH_SIZE", report->id, raw_size-1);
625 hid_debug_event(hdev, buff);
626 break;
627 case REPORT_HOOK_VERSION:
628 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
629 "REPORT_HOOK_VERSION", report->id, raw_size-1);
630 hid_debug_event(hdev, buff);
631 break;
632 case REPORT_EXIT_FLASHER:
633 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
634 "REPORT_VERSION", report->id, raw_size-1);
635 hid_debug_event(hdev, buff);
636 snprintf(buff, BUFF_SZ, "\tRestart delay: %dms (0x%02x%02x)\n",
637 raw_data[1] | (raw_data[2] << 8),
638 raw_data[2], raw_data[1]);
639 hid_debug_event(hdev, buff);
640 break;
641 default:
642 snprintf(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",
643 "<unknown>", report->id, raw_size-1);
644 hid_debug_event(hdev, buff);
645 break;
646 }
647 wake_up_interruptible(&hdev->debug_wait);
648 kfree(buff);
649}
650
651void picolcd_debug_raw_event(struct picolcd_data *data,
652 struct hid_device *hdev, struct hid_report *report,
653 u8 *raw_data, int size)
654{
655 char *buff;
656
657#define BUFF_SZ 256
658 /* Avoid unnecessary overhead if debugfs is disabled */
659 if (!hdev->debug_events)
660 return;
661
662 buff = kmalloc(BUFF_SZ, GFP_ATOMIC);
663 if (!buff)
664 return;
665
666 switch (report->id) {
667 case REPORT_ERROR_CODE:
668 /* 2 data bytes with affected report and error code */
669 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
670 "REPORT_ERROR_CODE", report->id, size-1);
671 hid_debug_event(hdev, buff);
672 if (raw_data[2] < ARRAY_SIZE(error_codes))
673 snprintf(buff, BUFF_SZ, "\tError code 0x%02x (%s) in reply to report 0x%02x\n",
674 raw_data[2], error_codes[raw_data[2]], raw_data[1]);
675 else
676 snprintf(buff, BUFF_SZ, "\tError code 0x%02x in reply to report 0x%02x\n",
677 raw_data[2], raw_data[1]);
678 hid_debug_event(hdev, buff);
679 break;
680 case REPORT_KEY_STATE:
681 /* 2 data bytes with key state */
682 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
683 "REPORT_KEY_STATE", report->id, size-1);
684 hid_debug_event(hdev, buff);
685 if (raw_data[1] == 0)
686 snprintf(buff, BUFF_SZ, "\tNo key pressed\n");
687 else if (raw_data[2] == 0)
688 snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n",
689 raw_data[1], raw_data[1]);
690 else
691 snprintf(buff, BUFF_SZ, "\tTwo keys pressed: 0x%02x (%d), 0x%02x (%d)\n",
692 raw_data[1], raw_data[1], raw_data[2], raw_data[2]);
693 hid_debug_event(hdev, buff);
694 break;
695 case REPORT_IR_DATA:
696 /* Up to 20 byes of IR scancode data */
697 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
698 "REPORT_IR_DATA", report->id, size-1);
699 hid_debug_event(hdev, buff);
700 if (raw_data[1] == 0) {
701 snprintf(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n");
702 hid_debug_event(hdev, buff);
703 } else if (raw_data[1] + 1 <= size) {
704 snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ",
705 raw_data[1]-1);
706 hid_debug_event(hdev, buff);
707 dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]-1);
708 hid_debug_event(hdev, buff);
709 } else {
710 snprintf(buff, BUFF_SZ, "\tOverflowing data length: %d\n",
711 raw_data[1]-1);
712 hid_debug_event(hdev, buff);
713 }
714 break;
715 case REPORT_EE_DATA:
716 /* Data buffer in response to REPORT_EE_READ or REPORT_EE_WRITE */
717 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
718 "REPORT_EE_DATA", report->id, size-1);
719 hid_debug_event(hdev, buff);
720 snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
721 raw_data[2], raw_data[1]);
722 hid_debug_event(hdev, buff);
723 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
724 hid_debug_event(hdev, buff);
725 if (raw_data[3] == 0) {
726 snprintf(buff, BUFF_SZ, "\tNo data\n");
727 hid_debug_event(hdev, buff);
728 } else if (raw_data[3] + 4 <= size) {
729 snprintf(buff, BUFF_SZ, "\tData: ");
730 hid_debug_event(hdev, buff);
731 dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
732 hid_debug_event(hdev, buff);
733 } else {
734 snprintf(buff, BUFF_SZ, "\tData overflowed\n");
735 hid_debug_event(hdev, buff);
736 }
737 break;
738 case REPORT_MEMORY:
739 /* Data buffer in response to REPORT_READ_MEMORY or REPORT_WRTIE_MEMORY */
740 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
741 "REPORT_MEMORY", report->id, size-1);
742 hid_debug_event(hdev, buff);
743 switch (data->addr_sz) {
744 case 2:
745 snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",
746 raw_data[2], raw_data[1]);
747 hid_debug_event(hdev, buff);
748 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);
749 hid_debug_event(hdev, buff);
750 if (raw_data[3] == 0) {
751 snprintf(buff, BUFF_SZ, "\tNo data\n");
752 } else if (raw_data[3] + 4 <= size) {
753 snprintf(buff, BUFF_SZ, "\tData: ");
754 hid_debug_event(hdev, buff);
755 dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);
756 } else {
757 snprintf(buff, BUFF_SZ, "\tData overflowed\n");
758 }
759 break;
760 case 3:
761 snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x%02x\n",
762 raw_data[3], raw_data[2], raw_data[1]);
763 hid_debug_event(hdev, buff);
764 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);
765 hid_debug_event(hdev, buff);
766 if (raw_data[4] == 0) {
767 snprintf(buff, BUFF_SZ, "\tNo data\n");
768 } else if (raw_data[4] + 5 <= size) {
769 snprintf(buff, BUFF_SZ, "\tData: ");
770 hid_debug_event(hdev, buff);
771 dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);
772 } else {
773 snprintf(buff, BUFF_SZ, "\tData overflowed\n");
774 }
775 break;
776 default:
777 snprintf(buff, BUFF_SZ, "\tNot supported\n");
778 }
779 hid_debug_event(hdev, buff);
780 break;
781 case REPORT_VERSION:
782 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
783 "REPORT_VERSION", report->id, size-1);
784 hid_debug_event(hdev, buff);
785 snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
786 raw_data[2], raw_data[1]);
787 hid_debug_event(hdev, buff);
788 break;
789 case REPORT_BL_ERASE_MEMORY:
790 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
791 "REPORT_BL_ERASE_MEMORY", report->id, size-1);
792 hid_debug_event(hdev, buff);
793 /* TODO */
794 break;
795 case REPORT_BL_READ_MEMORY:
796 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
797 "REPORT_BL_READ_MEMORY", report->id, size-1);
798 hid_debug_event(hdev, buff);
799 /* TODO */
800 break;
801 case REPORT_BL_WRITE_MEMORY:
802 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
803 "REPORT_BL_WRITE_MEMORY", report->id, size-1);
804 hid_debug_event(hdev, buff);
805 /* TODO */
806 break;
807 case REPORT_DEVID:
808 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
809 "REPORT_DEVID", report->id, size-1);
810 hid_debug_event(hdev, buff);
811 snprintf(buff, BUFF_SZ, "\tSerial: 0x%02x%02x%02x%02x\n",
812 raw_data[1], raw_data[2], raw_data[3], raw_data[4]);
813 hid_debug_event(hdev, buff);
814 snprintf(buff, BUFF_SZ, "\tType: 0x%02x\n",
815 raw_data[5]);
816 hid_debug_event(hdev, buff);
817 break;
818 case REPORT_SPLASH_SIZE:
819 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
820 "REPORT_SPLASH_SIZE", report->id, size-1);
821 hid_debug_event(hdev, buff);
822 snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n",
823 (raw_data[2] << 8) | raw_data[1]);
824 hid_debug_event(hdev, buff);
825 snprintf(buff, BUFF_SZ, "\tUsed splash space: %d\n",
826 (raw_data[4] << 8) | raw_data[3]);
827 hid_debug_event(hdev, buff);
828 break;
829 case REPORT_HOOK_VERSION:
830 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
831 "REPORT_HOOK_VERSION", report->id, size-1);
832 hid_debug_event(hdev, buff);
833 snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",
834 raw_data[1], raw_data[2]);
835 hid_debug_event(hdev, buff);
836 break;
837 default:
838 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",
839 "<unknown>", report->id, size-1);
840 hid_debug_event(hdev, buff);
841 break;
842 }
843 wake_up_interruptible(&hdev->debug_wait);
844 kfree(buff);
845}
846
847void picolcd_init_devfs(struct picolcd_data *data,
848 struct hid_report *eeprom_r, struct hid_report *eeprom_w,
849 struct hid_report *flash_r, struct hid_report *flash_w,
850 struct hid_report *reset)
851{
852 struct hid_device *hdev = data->hdev;
853
854 mutex_init(&data->mutex_flash);
855
856 /* reset */
857 if (reset)
858 data->debug_reset = debugfs_create_file("reset", 0600,
859 hdev->debug_dir, data, &picolcd_debug_reset_fops);
860
861 /* eeprom */
862 if (eeprom_r || eeprom_w)
863 data->debug_eeprom = debugfs_create_file("eeprom",
864 (eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0),
865 hdev->debug_dir, data, &picolcd_debug_eeprom_fops);
866
867 /* flash */
868 if (flash_r && flash_r->maxfield == 1 && flash_r->field[0]->report_size == 8)
869 data->addr_sz = flash_r->field[0]->report_count - 1;
870 else
871 data->addr_sz = -1;
872 if (data->addr_sz == 2 || data->addr_sz == 3) {
873 data->debug_flash = debugfs_create_file("flash",
874 (flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0),
875 hdev->debug_dir, data, &picolcd_debug_flash_fops);
876 } else if (flash_r || flash_w)
877 hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n");
878}
879
880void picolcd_exit_devfs(struct picolcd_data *data)
881{
882 struct dentry *dent;
883
884 dent = data->debug_reset;
885 data->debug_reset = NULL;
886 if (dent)
887 debugfs_remove(dent);
888 dent = data->debug_eeprom;
889 data->debug_eeprom = NULL;
890 if (dent)
891 debugfs_remove(dent);
892 dent = data->debug_flash;
893 data->debug_flash = NULL;
894 if (dent)
895 debugfs_remove(dent);
896 mutex_destroy(&data->mutex_flash);
897}
898