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

source code of linux/drivers/hid/hid-picolcd_debugfs.c