/***************************************************************************
* Copyright (C) 2010-2012 by Bruno Prémont <bonbons@linux-vserver.org> *
* *
* Based on Logitech G13 driver (v0.4) *
* Copyright (C) 2009 by Rick L. Vinyard, Jr. <rvinyard@cs.nmsu.edu> *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* This driver is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this software. If not see <http://www.gnu.org/licenses/>. *
***************************************************************************/
#include <linux/hid.h>
#include <linux/hid-debug.h>
#include <linux/fb.h>
#include <linux/seq_file.h>
#include <linux/debugfs.h>
#include <linux/module.h>
#include <linux/uaccess.h>
#include "hid-picolcd.h"
static int picolcd_debug_reset_show(struct seq_file *f, void *p)
{
if (picolcd_fbinfo((struct picolcd_data *)f->private))
seq_printf(f, "all fb\n");
else
seq_printf(f, "all\n");
return 0;
}
static int picolcd_debug_reset_open(struct inode *inode, struct file *f)
{
return single_open(f, picolcd_debug_reset_show, inode->i_private);
}
static ssize_t picolcd_debug_reset_write(struct file *f, const char __user *user_buf,
size_t count, loff_t *ppos)
{
struct picolcd_data *data = ((struct seq_file *)f->private_data)->private;
char buf[32];
size_t cnt = min(count, sizeof(buf)-1);
if (copy_from_user(buf, user_buf, cnt))
return -EFAULT;
while (cnt > 0 && (buf[cnt-1] == ' ' || buf[cnt-1] == '\n'))
cnt--;
buf[cnt] = '\0';
if (strcmp(buf, "all") == 0) {
picolcd_reset(data->hdev);
picolcd_fb_reset(data, 1);
} else if (strcmp(buf, "fb") == 0) {
picolcd_fb_reset(data, 1);
} else {
return -EINVAL;
}
return count;
}
static const struct file_operations picolcd_debug_reset_fops = {
.owner = THIS_MODULE,
.open = picolcd_debug_reset_open,
.read = seq_read,
.llseek = seq_lseek,
.write = picolcd_debug_reset_write,
.release = single_release,
};
/*
* The "eeprom" file
*/
static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
size_t s, loff_t *off)
{
struct picolcd_data *data = f->private_data;
struct picolcd_pending *resp;
u8 raw_data[3];
ssize_t ret = -EIO;
if (s == 0)
return -EINVAL;
if (*off > 0x0ff)
return 0;
/* prepare buffer with info about what we want to read (addr & len) */
raw_data[0] = *off & 0xff;
raw_data[1] = (*off >> 8) & 0xff;
raw_data[2] = s < 20 ? s : 20;
if (*off + raw_data[2] > 0xff)
raw_data[2] = 0x100 - *off;
resp = picolcd_send_and_wait(data->hdev, REPORT_EE_READ, raw_data,
sizeof(raw_data));
if (!resp)
return -EIO;
if (resp->in_report && resp->in_report->id == REPORT_EE_DATA) {
/* successful read :) */
ret = resp->raw_data[2];
if (ret > s)
ret = s;
if (copy_to_user(u, resp->raw_data+3, ret))
ret = -EFAULT;
else
*off += ret;
} /* anything else is some kind of IO error */
kfree(resp);
return ret;
}
static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
size_t s, loff_t *off)
{
struct picolcd_data *data = f->private_data;
struct picolcd_pending *resp;
ssize_t ret = -EIO;
u8 raw_data[23];
if (s == 0)
return -EINVAL;
if (*off > 0x0ff)
return -ENOSPC;
memset(raw_data, 0, sizeof(raw_data));
raw_data[0] = *off & 0xff;
raw_data[1] = (*off >> 8) & 0xff;
raw_data[2] = min_t(size_t, 20, s);
if