]> git.karo-electronics.de Git - linux-beck.git/commitdiff
HID: wiimote: Allow direct eeprom access
authorDavid Herrmann <dh.herrmann@googlemail.com>
Thu, 17 Nov 2011 13:12:11 +0000 (14:12 +0100)
committerJiri Kosina <jkosina@suse.cz>
Tue, 22 Nov 2011 22:10:58 +0000 (23:10 +0100)
The wiimote provides direct access to parts of its eeprom. This implements read
support for small chunks of the eeprom. This isn't very fast but prevents the
reader from blocking the wiimote stream for too long.

Write support is not yet supported as the wiimote breaks if we overwrite its
memory. Use hidraw to reverse-engineer the eeprom before implementing write
support here.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-wiimote-core.c
drivers/hid/hid-wiimote-debug.c
drivers/hid/hid-wiimote.h

index 919abbaba84095d5d8b07f695b587e6310fcbcde..2fd2f0337b8dbf3341ebd3633f91ba1d9663cfc8 100644 (file)
@@ -320,14 +320,8 @@ static void wiiproto_req_wmem(struct wiimote_data *wdata, bool eeprom,
        wiimote_queue(wdata, cmd, sizeof(cmd));
 }
 
-#define wiiproto_req_rreg(wdata, os, sz) \
-                               wiiproto_req_rmem((wdata), false, (os), (sz))
-
-#define wiiproto_req_reeprom(wdata, os, sz) \
-                               wiiproto_req_rmem((wdata), true, (os), (sz))
-
-static void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom,
-                                               __u32 offset, __u16 size)
+void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom, __u32 offset,
+                                                               __u16 size)
 {
        __u8 cmd[7];
 
index 6282e3c1a362713786b8bbb2ca7a453f270783df..f81243c86790374213ed3917d330574fe885b59c 100644 (file)
  * any later version.
  */
 
+#include <linux/debugfs.h>
 #include <linux/module.h>
 #include <linux/spinlock.h>
+#include <linux/uaccess.h>
 #include "hid-wiimote.h"
 
 struct wiimote_debug {
        struct wiimote_data *wdata;
+       struct dentry *eeprom;
+};
+
+static int wiidebug_eeprom_open(struct inode *i, struct file *f)
+{
+       f->private_data = i->i_private;
+       return 0;
+}
+
+static ssize_t wiidebug_eeprom_read(struct file *f, char __user *u, size_t s,
+                                                               loff_t *off)
+{
+       struct wiimote_debug *dbg = f->private_data;
+       struct wiimote_data *wdata = dbg->wdata;
+       unsigned long flags;
+       ssize_t ret;
+       char buf[16];
+       __u16 size;
+
+       if (s == 0)
+               return -EINVAL;
+       if (*off > 0xffffff)
+               return 0;
+       if (s > 16)
+               s = 16;
+
+       ret = wiimote_cmd_acquire(wdata);
+       if (ret)
+               return ret;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       wdata->state.cmd_read_size = s;
+       wdata->state.cmd_read_buf = buf;
+       wiimote_cmd_set(wdata, WIIPROTO_REQ_RMEM, *off & 0xffff);
+       wiiproto_req_reeprom(wdata, *off, s);
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+       ret = wiimote_cmd_wait(wdata);
+       if (!ret)
+               size = wdata->state.cmd_read_size;
+
+       spin_lock_irqsave(&wdata->state.lock, flags);
+       wdata->state.cmd_read_buf = NULL;
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+       wiimote_cmd_release(wdata);
+
+       if (ret)
+               return ret;
+       else if (size == 0)
+               return -EIO;
+
+       if (copy_to_user(u, buf, size))
+               return -EFAULT;
+
+       *off += size;
+       ret = size;
+
+       return ret;
+}
+
+static const struct file_operations wiidebug_eeprom_fops = {
+       .owner = THIS_MODULE,
+       .open = wiidebug_eeprom_open,
+       .read = wiidebug_eeprom_read,
+       .llseek = generic_file_llseek,
 };
 
 int wiidebug_init(struct wiimote_data *wdata)
@@ -29,6 +97,13 @@ int wiidebug_init(struct wiimote_data *wdata)
 
        dbg->wdata = wdata;
 
+       dbg->eeprom = debugfs_create_file("eeprom", S_IRUSR,
+               dbg->wdata->hdev->debug_dir, dbg, &wiidebug_eeprom_fops);
+       if (!dbg->eeprom) {
+               kfree(dbg);
+               return -ENOMEM;
+       }
+
        spin_lock_irqsave(&wdata->state.lock, flags);
        wdata->debug = dbg;
        spin_unlock_irqrestore(&wdata->state.lock, flags);
@@ -48,5 +123,6 @@ void wiidebug_deinit(struct wiimote_data *wdata)
        wdata->debug = NULL;
        spin_unlock_irqrestore(&wdata->state.lock, flags);
 
+       debugfs_remove(dbg->eeprom);
        kfree(dbg);
 }
index 89b8851dbf1f06a5d580e31f9f7f091a980651c3..7b6765797f81c2e33dc5ed638c7c365cdbc5cbb3 100644 (file)
@@ -120,6 +120,13 @@ extern int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
 extern ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset,
                                                        __u8 *rmem, __u8 size);
 
+#define wiiproto_req_rreg(wdata, os, sz) \
+                               wiiproto_req_rmem((wdata), false, (os), (sz))
+#define wiiproto_req_reeprom(wdata, os, sz) \
+                               wiiproto_req_rmem((wdata), true, (os), (sz))
+extern void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom,
+                                               __u32 offset, __u16 size);
+
 #ifdef CONFIG_HID_WIIMOTE_EXT
 
 extern int wiiext_init(struct wiimote_data *wdata);