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