linux/drivers/hid/hid-wiimote-debug.c
<<
>>
Prefs
   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}
 223