886 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/***************************************************************************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(f, "all fb\n");27 else28 seq_printf(f, "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(buf, user_buf, 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(data->hdev);51 picolcd_fb_reset(data, 1);52 } else if (strcmp(buf, "fb") == 0) {53 picolcd_fb_reset(data, 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" file71 */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(data->hdev, REPORT_EE_READ, raw_data,92 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(u, resp->raw_data+3, ret))102 ret = -EFAULT;103 else104 *off += ret;105 } /* anything else is some kind of IO error */106 107 kfree(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(raw_data+3, u, min((u8)20, raw_data[2])))132 return -EFAULT;133 resp = picolcd_send_and_wait(data->hdev, REPORT_EE_WRITE, raw_data,134 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(raw_data, resp->raw_data, 3+raw_data[2]) == 0) {142 *off += raw_data[2];143 ret = raw_data[2];144 }145 }146 kfree(resp);147 return ret;148}149 150/*151 * Notes:152 * - read/write happens in chunks of at most 20 bytes, it's up to userspace153 * to loop in order to get more data.154 * - on write errors on otherwise correct write request the bytes155 * 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" file167 */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, raw_data, *off);190 raw_data[len_off] = s > 32 ? 32 : s;191 resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, 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(raw_data, resp->raw_data, len_off+1) != 0)197 goto skip;198 if (copy_to_user(u+ret, resp->raw_data+len_off+1, 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(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 else230 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, raw_data, *off);246 resp = picolcd_send_and_wait(data->hdev, report_id, raw_data, 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(raw_data, resp->raw_data, len_off) != 0)252 goto skip;253 ret = 0;254 }255skip:256 kfree(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, raw_data, *off);272 raw_data[len_off] = s > 32 ? 32 : s;273 if (copy_from_user(raw_data+len_off+1, u, raw_data[len_off])) {274 err = -EFAULT;275 break;276 }277 resp = picolcd_send_and_wait(data->hdev, report_id, raw_data,278 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(raw_data, resp->raw_data, 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(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_erase, off);324 if (err)325 break;326 err = _picolcd_flash_write(data, report_write, u, 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(&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 be342 * n*64 bytes and 64-byte aligned, each write being preceded by an343 * ERASE which erases a 64byte block.344 * If less than requested was written or an error is returned for an345 * otherwise correct write request the next 64-byte block which should346 * have been written is in undefined state (mostly: original, erased,347 * (half-)written with write error)348 * - reading can happen without special restriction349 */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/debugging361 */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 256391 392 /* Avoid unnecessary overhead if debugfs is disabled */393 if (list_empty(&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(buff);403 return;404 }405 406 snprintf(buff, BUFF_SZ, "\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, raw_data);411 dump_buff_as_hex(buff, BUFF_SZ, raw_data, 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(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",418 "REPORT_LED_STATE", report->id, raw_size-1);419 hid_debug_event(hdev, buff);420 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",426 "REPORT_BRIGHTNESS", report->id, raw_size-1);427 hid_debug_event(hdev, buff);428 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",434 "REPORT_CONTRAST", report->id, raw_size-1);435 hid_debug_event(hdev, buff);436 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",442 "REPORT_RESET", report->id, raw_size-1);443 hid_debug_event(hdev, buff);444 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",472 "REPORT_EE_READ", report->id, raw_size-1);473 hid_debug_event(hdev, buff);474 snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",475 raw_data[2], raw_data[1]);476 hid_debug_event(hdev, buff);477 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",483 "REPORT_EE_WRITE", 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 if (raw_data[3] == 0) {491 snprintf(buff, BUFF_SZ, "\tNo data\n");492 } else if (raw_data[3] + 4 <= raw_size) {493 snprintf(buff, BUFF_SZ, "\tData: ");494 hid_debug_event(hdev, buff);495 dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);496 } else {497 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "\tAddress inside 64 byte block: 0x%02x%02x\n",510 raw_data[2], raw_data[1]);511 break;512 case 3:513 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",530 raw_data[2], raw_data[1]);531 hid_debug_event(hdev, buff);532 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);533 break;534 case 3:535 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);539 break;540 default:541 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",554 raw_data[2], raw_data[1]);555 hid_debug_event(hdev, buff);556 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);557 hid_debug_event(hdev, buff);558 if (raw_data[3] == 0) {559 snprintf(buff, BUFF_SZ, "\tNo data\n");560 } else if (raw_data[3] + 4 <= raw_size) {561 snprintf(buff, BUFF_SZ, "\tData: ");562 hid_debug_event(hdev, buff);563 dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);564 } else {565 snprintf(buff, BUFF_SZ, "\tData overflowed\n");566 }567 break;568 case 3:569 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);573 hid_debug_event(hdev, buff);574 if (raw_data[4] == 0) {575 snprintf(buff, BUFF_SZ, "\tNo data\n");576 } else if (raw_data[4] + 5 <= raw_size) {577 snprintf(buff, BUFF_SZ, "\tData: ");578 hid_debug_event(hdev, buff);579 dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);580 } else {581 snprintf(buff, BUFF_SZ, "\tData overflowed\n");582 }583 break;584 default:585 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",594 "REPORT_EXIT_KEYBOARD", report->id, raw_size-1);595 hid_debug_event(hdev, buff);596 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "out report %s (%d, size=%d)\n",623 "REPORT_VERSION", report->id, raw_size-1);624 hid_debug_event(hdev, buff);625 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "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(raw_data);638 kfree(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 256648 /* Avoid unnecessary overhead if debugfs is disabled */649 if (list_empty(&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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "\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 else666 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "\tNo key pressed\n");677 else if (raw_data[2] == 0)678 snprintf(buff, BUFF_SZ, "\tOne key pressed: 0x%02x (%d)\n",679 raw_data[1], raw_data[1]);680 else681 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "\tUnexpectedly 0 data length\n");692 hid_debug_event(hdev, buff);693 } else if (raw_data[1] + 1 <= size) {694 snprintf(buff, BUFF_SZ, "\tData length: %d\n\tIR Data: ",695 raw_data[1]);696 hid_debug_event(hdev, buff);697 dump_buff_as_hex(buff, BUFF_SZ, raw_data+2, raw_data[1]);698 hid_debug_event(hdev, buff);699 } else {700 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "report %s (%d, size=%d)\n",708 "REPORT_EE_DATA", report->id, size-1);709 hid_debug_event(hdev, buff);710 snprintf(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",711 raw_data[2], raw_data[1]);712 hid_debug_event(hdev, buff);713 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);714 hid_debug_event(hdev, buff);715 if (raw_data[3] == 0) {716 snprintf(buff, BUFF_SZ, "\tNo data\n");717 hid_debug_event(hdev, buff);718 } else if (raw_data[3] + 4 <= size) {719 snprintf(buff, BUFF_SZ, "\tData: ");720 hid_debug_event(hdev, buff);721 dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);722 hid_debug_event(hdev, buff);723 } else {724 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "\tData address: 0x%02x%02x\n",736 raw_data[2], raw_data[1]);737 hid_debug_event(hdev, buff);738 snprintf(buff, BUFF_SZ, "\tData length: %d\n", raw_data[3]);739 hid_debug_event(hdev, buff);740 if (raw_data[3] == 0) {741 snprintf(buff, BUFF_SZ, "\tNo data\n");742 } else if (raw_data[3] + 4 <= size) {743 snprintf(buff, BUFF_SZ, "\tData: ");744 hid_debug_event(hdev, buff);745 dump_buff_as_hex(buff, BUFF_SZ, raw_data+4, raw_data[3]);746 } else {747 snprintf(buff, BUFF_SZ, "\tData overflowed\n");748 }749 break;750 case 3:751 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "\tData length: %d\n", raw_data[4]);755 hid_debug_event(hdev, buff);756 if (raw_data[4] == 0) {757 snprintf(buff, BUFF_SZ, "\tNo data\n");758 } else if (raw_data[4] + 5 <= size) {759 snprintf(buff, BUFF_SZ, "\tData: ");760 hid_debug_event(hdev, buff);761 dump_buff_as_hex(buff, BUFF_SZ, raw_data+5, raw_data[4]);762 } else {763 snprintf(buff, BUFF_SZ, "\tData overflowed\n");764 }765 break;766 default:767 snprintf(buff, BUFF_SZ, "\tNot supported\n");768 }769 hid_debug_event(hdev, buff);770 break;771 case REPORT_VERSION:772 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",773 "REPORT_VERSION", report->id, size-1);774 hid_debug_event(hdev, buff);775 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "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(buff, BUFF_SZ, "report %s (%d, size=%d)\n",799 "REPORT_DEVID", report->id, size-1);800 hid_debug_event(hdev, buff);801 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "\tType: 0x%02x\n",805 raw_data[5]);806 hid_debug_event(hdev, buff);807 break;808 case REPORT_SPLASH_SIZE:809 snprintf(buff, BUFF_SZ, "report %s (%d, size=%d)\n",810 "REPORT_SPLASH_SIZE", report->id, size-1);811 hid_debug_event(hdev, buff);812 snprintf(buff, BUFF_SZ, "\tTotal splash space: %d\n",813 (raw_data[2] << 8) | raw_data[1]);814 hid_debug_event(hdev, buff);815 snprintf(buff, BUFF_SZ, "\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(buff, BUFF_SZ, "report %s (%d, size=%d)\n",821 "REPORT_HOOK_VERSION", report->id, size-1);822 hid_debug_event(hdev, buff);823 snprintf(buff, BUFF_SZ, "\tFirmware version: %d.%d\n",824 raw_data[1], raw_data[2]);825 hid_debug_event(hdev, buff);826 break;827 default:828 snprintf(buff, BUFF_SZ, "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(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("reset", 0600,849 hdev->debug_dir, data, &picolcd_debug_reset_fops);850 851 /* eeprom */852 if (eeprom_r || eeprom_w)853 data->debug_eeprom = debugfs_create_file("eeprom",854 (eeprom_w ? S_IWUSR : 0) | (eeprom_r ? S_IRUSR : 0),855 hdev->debug_dir, data, &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 else861 data->addr_sz = -1;862 if (data->addr_sz == 2 || data->addr_sz == 3) {863 data->debug_flash = debugfs_create_file("flash",864 (flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0),865 hdev->debug_dir, data, &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(dent);877 dent = data->debug_eeprom;878 data->debug_eeprom = NULL;879 debugfs_remove(dent);880 dent = data->debug_flash;881 data->debug_flash = NULL;882 debugfs_remove(dent);883 mutex_destroy(&data->mutex_flash);884}885 886