1 /* 2 * Debug support for HID Nintendo Wii / Wii U peripherals 3 * Copyright (c) 2011-2013 David Herrmann <dh.herrmann@gmail.com> 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 = 0; 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 seq_file *sf = f->private_data; 131 struct wiimote_debug *dbg = sf->private; 132 unsigned long flags; 133 char buf[16]; 134 ssize_t len; 135 int i; 136 137 if (s == 0) 138 return -EINVAL; 139 140 len = min((size_t) 15, s); 141 if (copy_from_user(buf, u, len)) 142 return -EFAULT; 143 144 buf[len] = 0; 145 146 for (i = 0; i < WIIPROTO_REQ_MAX; ++i) { 147 if (!wiidebug_drmmap[i]) 148 continue; 149 if (!strcasecmp(buf, wiidebug_drmmap[i])) 150 break; 151 } 152 153 if (i == WIIPROTO_REQ_MAX) 154 i = simple_strtoul(buf, NULL, 16); 155 156 spin_lock_irqsave(&dbg->wdata->state.lock, flags); 157 dbg->wdata->state.flags &= ~WIIPROTO_FLAG_DRM_LOCKED; 158 wiiproto_req_drm(dbg->wdata, (__u8) i); 159 if (i != WIIPROTO_REQ_NULL) 160 dbg->wdata->state.flags |= WIIPROTO_FLAG_DRM_LOCKED; 161 spin_unlock_irqrestore(&dbg->wdata->state.lock, flags); 162 163 return len; 164 } 165 166 static const struct file_operations wiidebug_drm_fops = { 167 .owner = THIS_MODULE, 168 .open = wiidebug_drm_open, 169 .read = seq_read, 170 .llseek = seq_lseek, 171 .write = wiidebug_drm_write, 172 .release = single_release, 173 }; 174 175 int wiidebug_init(struct wiimote_data *wdata) 176 { 177 struct wiimote_debug *dbg; 178 unsigned long flags; 179 int ret = -ENOMEM; 180 181 dbg = kzalloc(sizeof(*dbg), GFP_KERNEL); 182 if (!dbg) 183 return -ENOMEM; 184 185 dbg->wdata = wdata; 186 187 dbg->eeprom = debugfs_create_file("eeprom", S_IRUSR, 188 dbg->wdata->hdev->debug_dir, dbg, &wiidebug_eeprom_fops); 189 if (!dbg->eeprom) 190 goto err; 191 192 dbg->drm = debugfs_create_file("drm", S_IRUSR, 193 dbg->wdata->hdev->debug_dir, dbg, &wiidebug_drm_fops); 194 if (!dbg->drm) 195 goto err_drm; 196 197 spin_lock_irqsave(&wdata->state.lock, flags); 198 wdata->debug = dbg; 199 spin_unlock_irqrestore(&wdata->state.lock, flags); 200 201 return 0; 202 203 err_drm: 204 debugfs_remove(dbg->eeprom); 205 err: 206 kfree(dbg); 207 return ret; 208 } 209 210 void wiidebug_deinit(struct wiimote_data *wdata) 211 { 212 struct wiimote_debug *dbg = wdata->debug; 213 unsigned long flags; 214 215 if (!dbg) 216 return; 217 218 spin_lock_irqsave(&wdata->state.lock, flags); 219 wdata->debug = NULL; 220 spin_unlock_irqrestore(&wdata->state.lock, flags); 221 222 debugfs_remove(dbg->drm); 223 debugfs_remove(dbg->eeprom); 224 kfree(dbg); 225 } 226