1 /* 2 * Debug support for HID Nintendo Wiimote devices 3 * Copyright (c) 2011 David Herrmann 4 */ 5 6 /* 7 * This program is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the Free 9 * Software Foundation; either version 2 of the License, or (at your option) 10 * any later version. 11 */ 12 13 #include <linux/debugfs.h> 14 #include <linux/module.h> 15 #include <linux/seq_file.h> 16 #include <linux/spinlock.h> 17 #include <linux/uaccess.h> 18 #include "hid-wiimote.h" 19 20 struct wiimote_debug { 21 struct wiimote_data *wdata; 22 struct dentry *eeprom; 23 struct dentry *drm; 24 }; 25 26 static ssize_t wiidebug_eeprom_read(struct file *f, char __user *u, size_t s, 27 loff_t *off) 28 { 29 struct wiimote_debug *dbg = f->private_data; 30 struct wiimote_data *wdata = dbg->wdata; 31 unsigned long flags; 32 ssize_t ret; 33 char buf[16]; 34 __u16 size; 35 36 if (s == 0) 37 return -EINVAL; 38 if (*off > 0xffffff) 39 return 0; 40 if (s > 16) 41 s = 16; 42 43 ret = wiimote_cmd_acquire(wdata); 44 if (ret) 45 return ret; 46 47 spin_lock_irqsave(&wdata->state.lock, flags); 48 wdata->state.cmd_read_size = s; 49 wdata->state.cmd_read_buf = buf; 50 wiimote_cmd_set(wdata, WIIPROTO_REQ_RMEM, *off & 0xffff); 51 wiiproto_req_reeprom(wdata, *off, s); 52 spin_unlock_irqrestore(&wdata->state.lock, flags); 53 54 ret = wiimote_cmd_wait(wdata); 55 if (!ret) 56 size = wdata->state.cmd_read_size; 57 58 spin_lock_irqsave(&wdata->state.lock, flags); 59 wdata->state.cmd_read_buf = NULL; 60 spin_unlock_irqrestore(&wdata->state.lock, flags); 61 62 wiimote_cmd_release(wdata); 63 64 if (ret) 65 return ret; 66 else if (size == 0) 67 return -EIO; 68 69 if (copy_to_user(u, buf, size)) 70 return -EFAULT; 71 72 *off += size; 73 ret = size; 74 75 return ret; 76 } 77 78 static const struct file_operations wiidebug_eeprom_fops = { 79 .owner = THIS_MODULE, 80 .open = simple_open, 81 .read = wiidebug_eeprom_read, 82 .llseek = generic_file_llseek, 83 }; 84 85 static const char *wiidebug_drmmap[] = { 86 [WIIPROTO_REQ_NULL] = "NULL", 87 [WIIPROTO_REQ_DRM_K] = "K", 88 [WIIPROTO_REQ_DRM_KA] = "KA", 89 [WIIPROTO_REQ_DRM_KE] = "KE", 90 [WIIPROTO_REQ_DRM_KAI] = "KAI", 91 [WIIPROTO_REQ_DRM_KEE] = "KEE", 92 [WIIPROTO_REQ_DRM_KAE] = "KAE", 93 [WIIPROTO_REQ_DRM_KIE] = "KIE", 94 [WIIPROTO_REQ_DRM_KAIE] = "KAIE", 95 [WIIPROTO_REQ_DRM_E] = "E", 96 [WIIPROTO_REQ_DRM_SKAI1] = "SKAI1", 97 [WIIPROTO_REQ_DRM_SKAI2] = "SKAI2", 98 [WIIPROTO_REQ_MAX] = NULL 99 }; 100 101 static int wiidebug_drm_show(struct seq_file *f, void *p) 102 { 103 struct wiimote_debug *dbg = f->private; 104 const char *str = NULL; 105 unsigned long flags; 106 __u8 drm; 107 108 spin_lock_irqsave(&dbg->wdata->state.lock, flags); 109 drm = dbg->wdata->state.drm; 110 spin_unlock_irqrestore(&dbg->wdata->state.lock, flags); 111 112 if (drm < WIIPROTO_REQ_MAX) 113 str = wiidebug_drmmap[drm]; 114 if (!str) 115 str = "unknown"; 116 117 seq_printf(f, "%s\n", str); 118 119 return 0; 120 } 121 122 static int wiidebug_drm_open(struct inode *i, struct file *f) 123 { 124 return single_open(f, wiidebug_drm_show, i->i_private); 125 } 126 127 static ssize_t wiidebug_drm_write(struct file *f, const char __user *u, 128 size_t s, loff_t *off) 129 { 130 struct wiimote_debug *dbg = f->private_data; 131 unsigned long flags; 132 char buf[16]; 133 ssize_t len; 134 int i; 135 136 if (s == 0) 137 return -EINVAL; 138 139 len = min((size_t) 15, s); 140 if (copy_from_user(buf, u, len)) 141 return -EFAULT; 142 143 buf[15] = 0; 144 145 for (i = 0; i < WIIPROTO_REQ_MAX; ++i) { 146 if (!wiidebug_drmmap[i]) 147 continue; 148 if (!strcasecmp(buf, wiidebug_drmmap[i])) 149 break; 150 } 151 152 if (i == WIIPROTO_REQ_MAX) 153 i = simple_strtoul(buf, NULL, 10); 154 155 spin_lock_irqsave(&dbg->wdata->state.lock, flags); 156 wiiproto_req_drm(dbg->wdata, (__u8) i); 157 spin_unlock_irqrestore(&dbg->wdata->state.lock, flags); 158 159 return len; 160 } 161 162 static const struct file_operations wiidebug_drm_fops = { 163 .owner = THIS_MODULE, 164 .open = wiidebug_drm_open, 165 .read = seq_read, 166 .llseek = seq_lseek, 167 .write = wiidebug_drm_write, 168 .release = single_release, 169 }; 170 171 int wiidebug_init(struct wiimote_data *wdata) 172 { 173 struct wiimote_debug *dbg; 174 unsigned long flags; 175 int ret = -ENOMEM; 176 177 dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); 178 if (!dbg) 179 return -ENOMEM; 180 181 dbg->wdata = wdata; 182 183 dbg->eeprom = debugfs_create_file("eeprom", S_IRUSR, 184 dbg->wdata->hdev->debug_dir, dbg, &wiidebug_eeprom_fops); 185 if (!dbg->eeprom) 186 goto err; 187 188 dbg->drm = debugfs_create_file("drm", S_IRUSR, 189 dbg->wdata->hdev->debug_dir, dbg, &wiidebug_drm_fops); 190 if (!dbg->drm) 191 goto err_drm; 192 193 spin_lock_irqsave(&wdata->state.lock, flags); 194 wdata->debug = dbg; 195 spin_unlock_irqrestore(&wdata->state.lock, flags); 196 197 return 0; 198 199 err_drm: 200 debugfs_remove(dbg->eeprom); 201 err: 202 kfree(dbg); 203 return ret; 204 } 205 206 void wiidebug_deinit(struct wiimote_data *wdata) 207 { 208 struct wiimote_debug *dbg = wdata->debug; 209 unsigned long flags; 210 211 if (!dbg) 212 return; 213 214 spin_lock_irqsave(&wdata->state.lock, flags); 215 wdata->debug = NULL; 216 spin_unlock_irqrestore(&wdata->state.lock, flags); 217 218 debugfs_remove(dbg->drm); 219 debugfs_remove(dbg->eeprom); 220 kfree(dbg); 221 } 222