Merge tag 'selinux-pr-20191007' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-microblaze.git] / drivers / hid / hid-wiimote-debug.c
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 }