brintos

brintos / linux-shallow public Read only

0
0
Text · 26.3 KiB · d01176d Raw
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