Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
hid-wiimote-debug.c
Go to the documentation of this file.
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 {
22  struct dentry *eeprom;
23  struct dentry *drm;
24 };
25 
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];
34  __u16 size;
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,
80  .open = simple_open,
81  .read = wiidebug_eeprom_read,
82  .llseek = generic_file_llseek,
83 };
84 
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",
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 {
130  struct wiimote_debug *dbg = f->private_data;
131  unsigned long flags;
132  char buf[16];
133  ssize_t len;
134  int i;
135 
136  if (s == 0)
137  return -EINVAL;
138 
139  len = min((size_t) 15, s);
140  if (copy_from_user(buf, u, len))
141  return -EFAULT;
142 
143  buf[15] = 0;
144 
145  for (i = 0; i < WIIPROTO_REQ_MAX; ++i) {
146  if (!wiidebug_drmmap[i])
147  continue;
148  if (!strcasecmp(buf, wiidebug_drmmap[i]))
149  break;
150  }
151 
152  if (i == WIIPROTO_REQ_MAX)
153  i = simple_strtoul(buf, NULL, 10);
154 
155  spin_lock_irqsave(&dbg->wdata->state.lock, flags);
156  wiiproto_req_drm(dbg->wdata, (__u8) i);
157  spin_unlock_irqrestore(&dbg->wdata->state.lock, flags);
158 
159  return len;
160 }
161 
162 static const struct file_operations wiidebug_drm_fops = {
163  .owner = THIS_MODULE,
164  .open = wiidebug_drm_open,
165  .read = seq_read,
166  .llseek = seq_lseek,
167  .write = wiidebug_drm_write,
168  .release = single_release,
169 };
170 
171 int wiidebug_init(struct wiimote_data *wdata)
172 {
173  struct wiimote_debug *dbg;
174  unsigned long flags;
175  int ret = -ENOMEM;
176 
177  dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
178  if (!dbg)
179  return -ENOMEM;
180 
181  dbg->wdata = wdata;
182 
183  dbg->eeprom = debugfs_create_file("eeprom", S_IRUSR,
184  dbg->wdata->hdev->debug_dir, dbg, &wiidebug_eeprom_fops);
185  if (!dbg->eeprom)
186  goto err;
187 
188  dbg->drm = debugfs_create_file("drm", S_IRUSR,
189  dbg->wdata->hdev->debug_dir, dbg, &wiidebug_drm_fops);
190  if (!dbg->drm)
191  goto err_drm;
192 
193  spin_lock_irqsave(&wdata->state.lock, flags);
194  wdata->debug = dbg;
195  spin_unlock_irqrestore(&wdata->state.lock, flags);
196 
197  return 0;
198 
199 err_drm:
200  debugfs_remove(dbg->eeprom);
201 err:
202  kfree(dbg);
203  return ret;
204 }
205 
207 {
208  struct wiimote_debug *dbg = wdata->debug;
209  unsigned long flags;
210 
211  if (!dbg)
212  return;
213 
214  spin_lock_irqsave(&wdata->state.lock, flags);
215  wdata->debug = NULL;
216  spin_unlock_irqrestore(&wdata->state.lock, flags);
217 
218  debugfs_remove(dbg->drm);
219  debugfs_remove(dbg->eeprom);
220  kfree(dbg);
221 }