aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-wiimote.h
diff options
context:
space:
mode:
authorDavid Herrmann <dh.herrmann@gmail.com>2013-05-05 17:12:57 -0400
committerJiri Kosina <jkosina@suse.cz>2013-06-03 05:07:02 -0400
commit4148b6bf8a4a4d6e533329775370ccf49778c061 (patch)
treefc3bdcce4ee609e42936be086fe6ba5c6114a6e1 /drivers/hid/hid-wiimote.h
parent3b5f03c4e36c2756d3c10f93e4c829541bf1da28 (diff)
HID: wiimote: add extension hotplug support
The Wii Remote has several extension ports. The first port (EXT) provides hotplug events whenever an extension is plugged. The second port (MP) does not provide hotplug events by default. Instead, we have to map MP into EXT to get events for it. This patch introduces hotplug support for extensions. It is fairly complicated to get this right because the Wii Remote sends a lot of noise-hotplug events while activating extension ports. We need to filter the events and only handle the events that are real hotplug events. Mapping MP into EXT is easy. But if we want both, MP _and_ EXT at the same time, we need to map MP into EXT and enable a passthrough-mode. This will then send real EXT events through the mapped MP interleaved with real MP events. But once MP is mapped, we no longer have access to the real EXT registers so we need to perform setup _before_ mapping MP. Furthermore, we no longer can read EXT IDs so we cannot verify if EXT is still the same extension that we expect it to be. We deal with this by unmapping MP whenever we got into a situation where EXT might have changed. We then re-read EXT and MP and remap everything. The real Wii Console takes a fairly easy approach: It simply reconnects to the device on hotplug events that it didn't expect. So if a program wants MP events, but MP is disconnected, it fails and reconnects so it can wait for MP hotplug events again. This simplifies hotplugging a lot because we just react on PLUG events and ignore UNPLUG events. The more sophisticated Wii applications avoid reconnection (well, they still reconnect during many weird events, but at least not during UNPLUG) but they start polling the device. This allows them to disable the device, poll for the extension ports to settle and then initialize them again. Unfortunately, this approach fails whenever an extension is replugged while it is initialized. We would loose UNPLUG events and polling the device later will give unreliable results because the extension port might be in some weird state, even though it's actually unplugged. Our approach is a real HOTPLUG approch. We keep track of the EXT and mapped MP hotplug events whenever they occur. We then re-evaluate the device state and initialize any possible new extension or deinitialize any gone extension. Only during initialization, we set an extension port ACTIVE. However, during an unplug event we mark them as INACTIVE. This guarantess that a fast UNPLUG -> PLUG event sequence doesn't keep them marked as PLUGGED+ACTIVE but only PLUGGED. To deal with annoying noise-hotplug events during extension mapping, we simply rescan the device before performing any mapping. This allows us to ignore all the noise events as long as the device is in the correct state. Long story short: EXT and MP registers are sparsely known and we need to jump through hoops to get reliable HOTPLUG working. But while Nintendo needs *FOUR* Bluetooth reconnections for the shortest imaginable boot->menu->game->menu->shutdown sequence, we now need *ZERO*. As always, 3rd party devices tend to break whenever we behave differently than the original Wii. So there are also devices which _expect_ a disconnect after UNPLUG. Obviously, these devices won't benefit from this patch. But all official devices were tested extensively and work great during any hotplug sequence. Yay! Signed-off-by: David Herrmann <dh.herrmann@gmail.com> Signed-off-by: Jiri Kosina <jkosina@suse.cz>
Diffstat (limited to 'drivers/hid/hid-wiimote.h')
-rw-r--r--drivers/hid/hid-wiimote.h49
1 files changed, 49 insertions, 0 deletions
diff --git a/drivers/hid/hid-wiimote.h b/drivers/hid/hid-wiimote.h
index 3a2d3a1d3d63..0afc9f9a9bd6 100644
--- a/drivers/hid/hid-wiimote.h
+++ b/drivers/hid/hid-wiimote.h
@@ -22,6 +22,7 @@
22#include <linux/mutex.h> 22#include <linux/mutex.h>
23#include <linux/power_supply.h> 23#include <linux/power_supply.h>
24#include <linux/spinlock.h> 24#include <linux/spinlock.h>
25#include <linux/timer.h>
25 26
26#define WIIMOTE_NAME "Nintendo Wii Remote" 27#define WIIMOTE_NAME "Nintendo Wii Remote"
27#define WIIMOTE_BUFSIZE 32 28#define WIIMOTE_BUFSIZE 32
@@ -36,6 +37,12 @@
36#define WIIPROTO_FLAG_IR_EXT 0x80 37#define WIIPROTO_FLAG_IR_EXT 0x80
37#define WIIPROTO_FLAG_IR_FULL 0xc0 /* IR_BASIC | IR_EXT */ 38#define WIIPROTO_FLAG_IR_FULL 0xc0 /* IR_BASIC | IR_EXT */
38#define WIIPROTO_FLAG_EXT_PLUGGED 0x0100 39#define WIIPROTO_FLAG_EXT_PLUGGED 0x0100
40#define WIIPROTO_FLAG_EXT_USED 0x0200
41#define WIIPROTO_FLAG_EXT_ACTIVE 0x0400
42#define WIIPROTO_FLAG_MP_PLUGGED 0x0800
43#define WIIPROTO_FLAG_MP_USED 0x1000
44#define WIIPROTO_FLAG_MP_ACTIVE 0x2000
45#define WIIPROTO_FLAG_EXITING 0x4000
39 46
40#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \ 47#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
41 WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4) 48 WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
@@ -75,6 +82,14 @@ enum wiimote_exttype {
75 WIIMOTE_EXT_NUM, 82 WIIMOTE_EXT_NUM,
76}; 83};
77 84
85enum wiimote_mptype {
86 WIIMOTE_MP_NONE,
87 WIIMOTE_MP_UNKNOWN,
88 WIIMOTE_MP_SINGLE,
89 WIIMOTE_MP_PASSTHROUGH_NUNCHUK,
90 WIIMOTE_MP_PASSTHROUGH_CLASSIC,
91};
92
78struct wiimote_buf { 93struct wiimote_buf {
79 __u8 data[HID_MAX_BUFFER_SIZE]; 94 __u8 data[HID_MAX_BUFFER_SIZE];
80 size_t size; 95 size_t size;
@@ -94,6 +109,8 @@ struct wiimote_state {
94 __u8 accel_split[2]; 109 __u8 accel_split[2];
95 __u8 drm; 110 __u8 drm;
96 __u8 devtype; 111 __u8 devtype;
112 __u8 exttype;
113 __u8 mp;
97 114
98 /* synchronous cmd requests */ 115 /* synchronous cmd requests */
99 struct mutex sync; 116 struct mutex sync;
@@ -115,6 +132,7 @@ struct wiimote_data {
115 struct input_dev *accel; 132 struct input_dev *accel;
116 struct input_dev *ir; 133 struct input_dev *ir;
117 struct power_supply battery; 134 struct power_supply battery;
135 struct timer_list timer;
118 struct wiimote_ext *ext; 136 struct wiimote_ext *ext;
119 struct wiimote_debug *debug; 137 struct wiimote_debug *debug;
120 138
@@ -140,6 +158,8 @@ enum wiimod_module {
140}; 158};
141 159
142#define WIIMOD_FLAG_INPUT 0x0001 160#define WIIMOD_FLAG_INPUT 0x0001
161#define WIIMOD_FLAG_EXT8 0x0002
162#define WIIMOD_FLAG_EXT16 0x0004
143 163
144struct wiimod_ops { 164struct wiimod_ops {
145 __u16 flags; 165 __u16 flags;
@@ -153,9 +173,13 @@ struct wiimod_ops {
153 void (*in_accel) (struct wiimote_data *wdata, const __u8 *accel); 173 void (*in_accel) (struct wiimote_data *wdata, const __u8 *accel);
154 void (*in_ir) (struct wiimote_data *wdata, const __u8 *ir, bool packed, 174 void (*in_ir) (struct wiimote_data *wdata, const __u8 *ir, bool packed,
155 unsigned int id); 175 unsigned int id);
176 void (*in_mp) (struct wiimote_data *wdata, const __u8 *mp);
177 void (*in_ext) (struct wiimote_data *wdata, const __u8 *ext);
156}; 178};
157 179
158extern const struct wiimod_ops *wiimod_table[WIIMOD_NUM]; 180extern const struct wiimod_ops *wiimod_table[WIIMOD_NUM];
181extern const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM];
182extern const struct wiimod_ops wiimod_mp;
159 183
160/* wiimote requests */ 184/* wiimote requests */
161 185
@@ -172,23 +196,48 @@ enum wiiproto_reqs {
172 WIIPROTO_REQ_STATUS = 0x20, 196 WIIPROTO_REQ_STATUS = 0x20,
173 WIIPROTO_REQ_DATA = 0x21, 197 WIIPROTO_REQ_DATA = 0x21,
174 WIIPROTO_REQ_RETURN = 0x22, 198 WIIPROTO_REQ_RETURN = 0x22,
199
200 /* DRM_K: BB*2 */
175 WIIPROTO_REQ_DRM_K = 0x30, 201 WIIPROTO_REQ_DRM_K = 0x30,
202
203 /* DRM_KA: BB*2 AA*3 */
176 WIIPROTO_REQ_DRM_KA = 0x31, 204 WIIPROTO_REQ_DRM_KA = 0x31,
205
206 /* DRM_KE: BB*2 EE*8 */
177 WIIPROTO_REQ_DRM_KE = 0x32, 207 WIIPROTO_REQ_DRM_KE = 0x32,
208
209 /* DRM_KAI: BB*2 AA*3 II*12 */
178 WIIPROTO_REQ_DRM_KAI = 0x33, 210 WIIPROTO_REQ_DRM_KAI = 0x33,
211
212 /* DRM_KEE: BB*2 EE*19 */
179 WIIPROTO_REQ_DRM_KEE = 0x34, 213 WIIPROTO_REQ_DRM_KEE = 0x34,
214
215 /* DRM_KAE: BB*2 AA*3 EE*16 */
180 WIIPROTO_REQ_DRM_KAE = 0x35, 216 WIIPROTO_REQ_DRM_KAE = 0x35,
217
218 /* DRM_KIE: BB*2 II*10 EE*9 */
181 WIIPROTO_REQ_DRM_KIE = 0x36, 219 WIIPROTO_REQ_DRM_KIE = 0x36,
220
221 /* DRM_KAIE: BB*2 AA*3 II*10 EE*6 */
182 WIIPROTO_REQ_DRM_KAIE = 0x37, 222 WIIPROTO_REQ_DRM_KAIE = 0x37,
223
224 /* DRM_E: EE*21 */
183 WIIPROTO_REQ_DRM_E = 0x3d, 225 WIIPROTO_REQ_DRM_E = 0x3d,
226
227 /* DRM_SKAI1: BB*2 AA*1 II*18 */
184 WIIPROTO_REQ_DRM_SKAI1 = 0x3e, 228 WIIPROTO_REQ_DRM_SKAI1 = 0x3e,
229
230 /* DRM_SKAI2: BB*2 AA*1 II*18 */
185 WIIPROTO_REQ_DRM_SKAI2 = 0x3f, 231 WIIPROTO_REQ_DRM_SKAI2 = 0x3f,
232
186 WIIPROTO_REQ_MAX 233 WIIPROTO_REQ_MAX
187}; 234};
188 235
189#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \ 236#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \
190 dev)) 237 dev))
191 238
239void __wiimote_schedule(struct wiimote_data *wdata);
240
192extern void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm); 241extern void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm);
193extern void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble); 242extern void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble);
194extern void wiiproto_req_leds(struct wiimote_data *wdata, int leds); 243extern void wiiproto_req_leds(struct wiimote_data *wdata, int leds);