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