17dabc1f339e93ee9eff1221a433b03784dea3c7
[linux-flexiantxendom0-3.2.10.git] / drivers / hid / hid-wiimote-debug.c
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 }