hid-wiimote-debug.c (4855B)
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 17struct wiimote_debug { 18 struct wiimote_data *wdata; 19 struct dentry *eeprom; 20 struct dentry *drm; 21}; 22 23static 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 75static 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 82static 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 98static 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 119static int wiidebug_drm_open(struct inode *i, struct file *f) 120{ 121 return single_open(f, wiidebug_drm_show, i->i_private); 122} 123 124static 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 163static 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 172int 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 200err_drm: 201 debugfs_remove(dbg->eeprom); 202err: 203 kfree(dbg); 204 return ret; 205} 206 207void 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}