213 lines · c
1// SPDX-License-Identifier: GPL-2.0-or-later2/*3 * Debug support for HID Nintendo Wii / Wii U peripherals4 * 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] = NULL96};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 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 186 dbg->drm = debugfs_create_file("drm", S_IRUSR,187 dbg->wdata->hdev->debug_dir, dbg, &wiidebug_drm_fops);188 189 spin_lock_irqsave(&wdata->state.lock, flags);190 wdata->debug = dbg;191 spin_unlock_irqrestore(&wdata->state.lock, flags);192 193 return 0;194 195}196 197void wiidebug_deinit(struct wiimote_data *wdata)198{199 struct wiimote_debug *dbg = wdata->debug;200 unsigned long flags;201 202 if (!dbg)203 return;204 205 spin_lock_irqsave(&wdata->state.lock, flags);206 wdata->debug = NULL;207 spin_unlock_irqrestore(&wdata->state.lock, flags);208 209 debugfs_remove(dbg->drm);210 debugfs_remove(dbg->eeprom);211 kfree(dbg);212}213