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