xref: /openbmc/linux/drivers/hid/hid-wiimote-core.c (revision 1d3452c63d4b62329d34d7634f67a3dbec21ca87)
1192a1acfSDavid Herrmann /*
2192a1acfSDavid Herrmann  * HID driver for Nintendo Wiimote devices
3192a1acfSDavid Herrmann  * Copyright (c) 2011 David Herrmann
4192a1acfSDavid Herrmann  */
5192a1acfSDavid Herrmann 
6192a1acfSDavid Herrmann /*
7192a1acfSDavid Herrmann  * This program is free software; you can redistribute it and/or modify it
8192a1acfSDavid Herrmann  * under the terms of the GNU General Public License as published by the Free
9192a1acfSDavid Herrmann  * Software Foundation; either version 2 of the License, or (at your option)
10192a1acfSDavid Herrmann  * any later version.
11192a1acfSDavid Herrmann  */
12192a1acfSDavid Herrmann 
13192a1acfSDavid Herrmann #include <linux/completion.h>
14192a1acfSDavid Herrmann #include <linux/device.h>
15192a1acfSDavid Herrmann #include <linux/hid.h>
16192a1acfSDavid Herrmann #include <linux/input.h>
17192a1acfSDavid Herrmann #include <linux/leds.h>
18192a1acfSDavid Herrmann #include <linux/module.h>
19192a1acfSDavid Herrmann #include <linux/mutex.h>
20192a1acfSDavid Herrmann #include <linux/power_supply.h>
21192a1acfSDavid Herrmann #include <linux/spinlock.h>
22192a1acfSDavid Herrmann #include "hid-ids.h"
237e274400SDavid Herrmann #include "hid-wiimote.h"
24192a1acfSDavid Herrmann 
25192a1acfSDavid Herrmann #define WIIMOTE_VERSION "0.2"
26192a1acfSDavid Herrmann 
27192a1acfSDavid Herrmann enum wiiproto_keys {
28192a1acfSDavid Herrmann 	WIIPROTO_KEY_LEFT,
29192a1acfSDavid Herrmann 	WIIPROTO_KEY_RIGHT,
30192a1acfSDavid Herrmann 	WIIPROTO_KEY_UP,
31192a1acfSDavid Herrmann 	WIIPROTO_KEY_DOWN,
32192a1acfSDavid Herrmann 	WIIPROTO_KEY_PLUS,
33192a1acfSDavid Herrmann 	WIIPROTO_KEY_MINUS,
34192a1acfSDavid Herrmann 	WIIPROTO_KEY_ONE,
35192a1acfSDavid Herrmann 	WIIPROTO_KEY_TWO,
36192a1acfSDavid Herrmann 	WIIPROTO_KEY_A,
37192a1acfSDavid Herrmann 	WIIPROTO_KEY_B,
38192a1acfSDavid Herrmann 	WIIPROTO_KEY_HOME,
39192a1acfSDavid Herrmann 	WIIPROTO_KEY_COUNT
40192a1acfSDavid Herrmann };
41192a1acfSDavid Herrmann 
42192a1acfSDavid Herrmann static __u16 wiiproto_keymap[] = {
43192a1acfSDavid Herrmann 	KEY_LEFT,	/* WIIPROTO_KEY_LEFT */
44192a1acfSDavid Herrmann 	KEY_RIGHT,	/* WIIPROTO_KEY_RIGHT */
45192a1acfSDavid Herrmann 	KEY_UP,		/* WIIPROTO_KEY_UP */
46192a1acfSDavid Herrmann 	KEY_DOWN,	/* WIIPROTO_KEY_DOWN */
47192a1acfSDavid Herrmann 	KEY_NEXT,	/* WIIPROTO_KEY_PLUS */
48192a1acfSDavid Herrmann 	KEY_PREVIOUS,	/* WIIPROTO_KEY_MINUS */
49192a1acfSDavid Herrmann 	BTN_1,		/* WIIPROTO_KEY_ONE */
50192a1acfSDavid Herrmann 	BTN_2,		/* WIIPROTO_KEY_TWO */
51192a1acfSDavid Herrmann 	BTN_A,		/* WIIPROTO_KEY_A */
52192a1acfSDavid Herrmann 	BTN_B,		/* WIIPROTO_KEY_B */
53192a1acfSDavid Herrmann 	BTN_MODE,	/* WIIPROTO_KEY_HOME */
54192a1acfSDavid Herrmann };
55192a1acfSDavid Herrmann 
56192a1acfSDavid Herrmann static enum power_supply_property wiimote_battery_props[] = {
57192a1acfSDavid Herrmann 	POWER_SUPPLY_PROP_CAPACITY
58192a1acfSDavid Herrmann };
59192a1acfSDavid Herrmann 
60192a1acfSDavid Herrmann static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
61192a1acfSDavid Herrmann 								size_t count)
62192a1acfSDavid Herrmann {
63192a1acfSDavid Herrmann 	__u8 *buf;
64192a1acfSDavid Herrmann 	ssize_t ret;
65192a1acfSDavid Herrmann 
66192a1acfSDavid Herrmann 	if (!hdev->hid_output_raw_report)
67192a1acfSDavid Herrmann 		return -ENODEV;
68192a1acfSDavid Herrmann 
69192a1acfSDavid Herrmann 	buf = kmemdup(buffer, count, GFP_KERNEL);
70192a1acfSDavid Herrmann 	if (!buf)
71192a1acfSDavid Herrmann 		return -ENOMEM;
72192a1acfSDavid Herrmann 
73192a1acfSDavid Herrmann 	ret = hdev->hid_output_raw_report(hdev, buf, count, HID_OUTPUT_REPORT);
74192a1acfSDavid Herrmann 
75192a1acfSDavid Herrmann 	kfree(buf);
76192a1acfSDavid Herrmann 	return ret;
77192a1acfSDavid Herrmann }
78192a1acfSDavid Herrmann 
79192a1acfSDavid Herrmann static void wiimote_worker(struct work_struct *work)
80192a1acfSDavid Herrmann {
81192a1acfSDavid Herrmann 	struct wiimote_data *wdata = container_of(work, struct wiimote_data,
82192a1acfSDavid Herrmann 									worker);
83192a1acfSDavid Herrmann 	unsigned long flags;
84192a1acfSDavid Herrmann 
85192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->qlock, flags);
86192a1acfSDavid Herrmann 
87192a1acfSDavid Herrmann 	while (wdata->head != wdata->tail) {
88192a1acfSDavid Herrmann 		spin_unlock_irqrestore(&wdata->qlock, flags);
89192a1acfSDavid Herrmann 		wiimote_hid_send(wdata->hdev, wdata->outq[wdata->tail].data,
90192a1acfSDavid Herrmann 						wdata->outq[wdata->tail].size);
91192a1acfSDavid Herrmann 		spin_lock_irqsave(&wdata->qlock, flags);
92192a1acfSDavid Herrmann 
93192a1acfSDavid Herrmann 		wdata->tail = (wdata->tail + 1) % WIIMOTE_BUFSIZE;
94192a1acfSDavid Herrmann 	}
95192a1acfSDavid Herrmann 
96192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->qlock, flags);
97192a1acfSDavid Herrmann }
98192a1acfSDavid Herrmann 
99192a1acfSDavid Herrmann static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
100192a1acfSDavid Herrmann 								size_t count)
101192a1acfSDavid Herrmann {
102192a1acfSDavid Herrmann 	unsigned long flags;
103192a1acfSDavid Herrmann 	__u8 newhead;
104192a1acfSDavid Herrmann 
105192a1acfSDavid Herrmann 	if (count > HID_MAX_BUFFER_SIZE) {
106192a1acfSDavid Herrmann 		hid_warn(wdata->hdev, "Sending too large output report\n");
107192a1acfSDavid Herrmann 		return;
108192a1acfSDavid Herrmann 	}
109192a1acfSDavid Herrmann 
110192a1acfSDavid Herrmann 	/*
111192a1acfSDavid Herrmann 	 * Copy new request into our output queue and check whether the
112192a1acfSDavid Herrmann 	 * queue is full. If it is full, discard this request.
113192a1acfSDavid Herrmann 	 * If it is empty we need to start a new worker that will
114192a1acfSDavid Herrmann 	 * send out the buffer to the hid device.
115192a1acfSDavid Herrmann 	 * If the queue is not empty, then there must be a worker
116192a1acfSDavid Herrmann 	 * that is currently sending out our buffer and this worker
117192a1acfSDavid Herrmann 	 * will reschedule itself until the queue is empty.
118192a1acfSDavid Herrmann 	 */
119192a1acfSDavid Herrmann 
120192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->qlock, flags);
121192a1acfSDavid Herrmann 
122192a1acfSDavid Herrmann 	memcpy(wdata->outq[wdata->head].data, buffer, count);
123192a1acfSDavid Herrmann 	wdata->outq[wdata->head].size = count;
124192a1acfSDavid Herrmann 	newhead = (wdata->head + 1) % WIIMOTE_BUFSIZE;
125192a1acfSDavid Herrmann 
126192a1acfSDavid Herrmann 	if (wdata->head == wdata->tail) {
127192a1acfSDavid Herrmann 		wdata->head = newhead;
128192a1acfSDavid Herrmann 		schedule_work(&wdata->worker);
129192a1acfSDavid Herrmann 	} else if (newhead != wdata->tail) {
130192a1acfSDavid Herrmann 		wdata->head = newhead;
131192a1acfSDavid Herrmann 	} else {
132192a1acfSDavid Herrmann 		hid_warn(wdata->hdev, "Output queue is full");
133192a1acfSDavid Herrmann 	}
134192a1acfSDavid Herrmann 
135192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->qlock, flags);
136192a1acfSDavid Herrmann }
137192a1acfSDavid Herrmann 
138192a1acfSDavid Herrmann /*
139192a1acfSDavid Herrmann  * This sets the rumble bit on the given output report if rumble is
140192a1acfSDavid Herrmann  * currently enabled.
141192a1acfSDavid Herrmann  * \cmd1 must point to the second byte in the output report => &cmd[1]
142192a1acfSDavid Herrmann  * This must be called on nearly every output report before passing it
143192a1acfSDavid Herrmann  * into the output queue!
144192a1acfSDavid Herrmann  */
145192a1acfSDavid Herrmann static inline void wiiproto_keep_rumble(struct wiimote_data *wdata, __u8 *cmd1)
146192a1acfSDavid Herrmann {
147192a1acfSDavid Herrmann 	if (wdata->state.flags & WIIPROTO_FLAG_RUMBLE)
148192a1acfSDavid Herrmann 		*cmd1 |= 0x01;
149192a1acfSDavid Herrmann }
150192a1acfSDavid Herrmann 
151192a1acfSDavid Herrmann static void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble)
152192a1acfSDavid Herrmann {
153192a1acfSDavid Herrmann 	__u8 cmd[2];
154192a1acfSDavid Herrmann 
155192a1acfSDavid Herrmann 	rumble = !!rumble;
156192a1acfSDavid Herrmann 	if (rumble == !!(wdata->state.flags & WIIPROTO_FLAG_RUMBLE))
157192a1acfSDavid Herrmann 		return;
158192a1acfSDavid Herrmann 
159192a1acfSDavid Herrmann 	if (rumble)
160192a1acfSDavid Herrmann 		wdata->state.flags |= WIIPROTO_FLAG_RUMBLE;
161192a1acfSDavid Herrmann 	else
162192a1acfSDavid Herrmann 		wdata->state.flags &= ~WIIPROTO_FLAG_RUMBLE;
163192a1acfSDavid Herrmann 
164192a1acfSDavid Herrmann 	cmd[0] = WIIPROTO_REQ_RUMBLE;
165192a1acfSDavid Herrmann 	cmd[1] = 0;
166192a1acfSDavid Herrmann 
167192a1acfSDavid Herrmann 	wiiproto_keep_rumble(wdata, &cmd[1]);
168192a1acfSDavid Herrmann 	wiimote_queue(wdata, cmd, sizeof(cmd));
169192a1acfSDavid Herrmann }
170192a1acfSDavid Herrmann 
171192a1acfSDavid Herrmann static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
172192a1acfSDavid Herrmann {
173192a1acfSDavid Herrmann 	__u8 cmd[2];
174192a1acfSDavid Herrmann 
175192a1acfSDavid Herrmann 	leds &= WIIPROTO_FLAGS_LEDS;
176192a1acfSDavid Herrmann 	if ((wdata->state.flags & WIIPROTO_FLAGS_LEDS) == leds)
177192a1acfSDavid Herrmann 		return;
178192a1acfSDavid Herrmann 	wdata->state.flags = (wdata->state.flags & ~WIIPROTO_FLAGS_LEDS) | leds;
179192a1acfSDavid Herrmann 
180192a1acfSDavid Herrmann 	cmd[0] = WIIPROTO_REQ_LED;
181192a1acfSDavid Herrmann 	cmd[1] = 0;
182192a1acfSDavid Herrmann 
183192a1acfSDavid Herrmann 	if (leds & WIIPROTO_FLAG_LED1)
184192a1acfSDavid Herrmann 		cmd[1] |= 0x10;
185192a1acfSDavid Herrmann 	if (leds & WIIPROTO_FLAG_LED2)
186192a1acfSDavid Herrmann 		cmd[1] |= 0x20;
187192a1acfSDavid Herrmann 	if (leds & WIIPROTO_FLAG_LED3)
188192a1acfSDavid Herrmann 		cmd[1] |= 0x40;
189192a1acfSDavid Herrmann 	if (leds & WIIPROTO_FLAG_LED4)
190192a1acfSDavid Herrmann 		cmd[1] |= 0x80;
191192a1acfSDavid Herrmann 
192192a1acfSDavid Herrmann 	wiiproto_keep_rumble(wdata, &cmd[1]);
193192a1acfSDavid Herrmann 	wiimote_queue(wdata, cmd, sizeof(cmd));
194192a1acfSDavid Herrmann }
195192a1acfSDavid Herrmann 
196192a1acfSDavid Herrmann /*
197192a1acfSDavid Herrmann  * Check what peripherals of the wiimote are currently
198192a1acfSDavid Herrmann  * active and select a proper DRM that supports all of
199192a1acfSDavid Herrmann  * the requested data inputs.
200192a1acfSDavid Herrmann  */
201192a1acfSDavid Herrmann static __u8 select_drm(struct wiimote_data *wdata)
202192a1acfSDavid Herrmann {
203192a1acfSDavid Herrmann 	__u8 ir = wdata->state.flags & WIIPROTO_FLAGS_IR;
204cb99221bSDavid Herrmann 	bool ext = wiiext_active(wdata);
205192a1acfSDavid Herrmann 
206192a1acfSDavid Herrmann 	if (ir == WIIPROTO_FLAG_IR_BASIC) {
207192a1acfSDavid Herrmann 		if (wdata->state.flags & WIIPROTO_FLAG_ACCEL)
208192a1acfSDavid Herrmann 			return WIIPROTO_REQ_DRM_KAIE;
209192a1acfSDavid Herrmann 		else
210192a1acfSDavid Herrmann 			return WIIPROTO_REQ_DRM_KIE;
211192a1acfSDavid Herrmann 	} else if (ir == WIIPROTO_FLAG_IR_EXT) {
212192a1acfSDavid Herrmann 		return WIIPROTO_REQ_DRM_KAI;
213192a1acfSDavid Herrmann 	} else if (ir == WIIPROTO_FLAG_IR_FULL) {
214192a1acfSDavid Herrmann 		return WIIPROTO_REQ_DRM_SKAI1;
215192a1acfSDavid Herrmann 	} else {
216cb99221bSDavid Herrmann 		if (wdata->state.flags & WIIPROTO_FLAG_ACCEL) {
217cb99221bSDavid Herrmann 			if (ext)
218cb99221bSDavid Herrmann 				return WIIPROTO_REQ_DRM_KAE;
219cb99221bSDavid Herrmann 			else
220192a1acfSDavid Herrmann 				return WIIPROTO_REQ_DRM_KA;
221cb99221bSDavid Herrmann 		} else {
222cb99221bSDavid Herrmann 			if (ext)
223cb99221bSDavid Herrmann 				return WIIPROTO_REQ_DRM_KE;
224192a1acfSDavid Herrmann 			else
225192a1acfSDavid Herrmann 				return WIIPROTO_REQ_DRM_K;
226192a1acfSDavid Herrmann 		}
227192a1acfSDavid Herrmann 	}
228cb99221bSDavid Herrmann }
229192a1acfSDavid Herrmann 
2307e274400SDavid Herrmann void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
231192a1acfSDavid Herrmann {
232192a1acfSDavid Herrmann 	__u8 cmd[3];
233192a1acfSDavid Herrmann 
234192a1acfSDavid Herrmann 	if (drm == WIIPROTO_REQ_NULL)
235192a1acfSDavid Herrmann 		drm = select_drm(wdata);
236192a1acfSDavid Herrmann 
237192a1acfSDavid Herrmann 	cmd[0] = WIIPROTO_REQ_DRM;
238192a1acfSDavid Herrmann 	cmd[1] = 0;
239192a1acfSDavid Herrmann 	cmd[2] = drm;
240192a1acfSDavid Herrmann 
241192a1acfSDavid Herrmann 	wiiproto_keep_rumble(wdata, &cmd[1]);
242192a1acfSDavid Herrmann 	wiimote_queue(wdata, cmd, sizeof(cmd));
243192a1acfSDavid Herrmann }
244192a1acfSDavid Herrmann 
245192a1acfSDavid Herrmann static void wiiproto_req_status(struct wiimote_data *wdata)
246192a1acfSDavid Herrmann {
247192a1acfSDavid Herrmann 	__u8 cmd[2];
248192a1acfSDavid Herrmann 
249192a1acfSDavid Herrmann 	cmd[0] = WIIPROTO_REQ_SREQ;
250192a1acfSDavid Herrmann 	cmd[1] = 0;
251192a1acfSDavid Herrmann 
252192a1acfSDavid Herrmann 	wiiproto_keep_rumble(wdata, &cmd[1]);
253192a1acfSDavid Herrmann 	wiimote_queue(wdata, cmd, sizeof(cmd));
254192a1acfSDavid Herrmann }
255192a1acfSDavid Herrmann 
256192a1acfSDavid Herrmann static void wiiproto_req_accel(struct wiimote_data *wdata, __u8 accel)
257192a1acfSDavid Herrmann {
258192a1acfSDavid Herrmann 	accel = !!accel;
259192a1acfSDavid Herrmann 	if (accel == !!(wdata->state.flags & WIIPROTO_FLAG_ACCEL))
260192a1acfSDavid Herrmann 		return;
261192a1acfSDavid Herrmann 
262192a1acfSDavid Herrmann 	if (accel)
263192a1acfSDavid Herrmann 		wdata->state.flags |= WIIPROTO_FLAG_ACCEL;
264192a1acfSDavid Herrmann 	else
265192a1acfSDavid Herrmann 		wdata->state.flags &= ~WIIPROTO_FLAG_ACCEL;
266192a1acfSDavid Herrmann 
267192a1acfSDavid Herrmann 	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
268192a1acfSDavid Herrmann }
269192a1acfSDavid Herrmann 
270192a1acfSDavid Herrmann static void wiiproto_req_ir1(struct wiimote_data *wdata, __u8 flags)
271192a1acfSDavid Herrmann {
272192a1acfSDavid Herrmann 	__u8 cmd[2];
273192a1acfSDavid Herrmann 
274192a1acfSDavid Herrmann 	cmd[0] = WIIPROTO_REQ_IR1;
275192a1acfSDavid Herrmann 	cmd[1] = flags;
276192a1acfSDavid Herrmann 
277192a1acfSDavid Herrmann 	wiiproto_keep_rumble(wdata, &cmd[1]);
278192a1acfSDavid Herrmann 	wiimote_queue(wdata, cmd, sizeof(cmd));
279192a1acfSDavid Herrmann }
280192a1acfSDavid Herrmann 
281192a1acfSDavid Herrmann static void wiiproto_req_ir2(struct wiimote_data *wdata, __u8 flags)
282192a1acfSDavid Herrmann {
283192a1acfSDavid Herrmann 	__u8 cmd[2];
284192a1acfSDavid Herrmann 
285192a1acfSDavid Herrmann 	cmd[0] = WIIPROTO_REQ_IR2;
286192a1acfSDavid Herrmann 	cmd[1] = flags;
287192a1acfSDavid Herrmann 
288192a1acfSDavid Herrmann 	wiiproto_keep_rumble(wdata, &cmd[1]);
289192a1acfSDavid Herrmann 	wiimote_queue(wdata, cmd, sizeof(cmd));
290192a1acfSDavid Herrmann }
291192a1acfSDavid Herrmann 
292192a1acfSDavid Herrmann #define wiiproto_req_wreg(wdata, os, buf, sz) \
293192a1acfSDavid Herrmann 			wiiproto_req_wmem((wdata), false, (os), (buf), (sz))
294192a1acfSDavid Herrmann 
295192a1acfSDavid Herrmann #define wiiproto_req_weeprom(wdata, os, buf, sz) \
296192a1acfSDavid Herrmann 			wiiproto_req_wmem((wdata), true, (os), (buf), (sz))
297192a1acfSDavid Herrmann 
298192a1acfSDavid Herrmann static void wiiproto_req_wmem(struct wiimote_data *wdata, bool eeprom,
299192a1acfSDavid Herrmann 				__u32 offset, const __u8 *buf, __u8 size)
300192a1acfSDavid Herrmann {
301192a1acfSDavid Herrmann 	__u8 cmd[22];
302192a1acfSDavid Herrmann 
303192a1acfSDavid Herrmann 	if (size > 16 || size == 0) {
304192a1acfSDavid Herrmann 		hid_warn(wdata->hdev, "Invalid length %d wmem request\n", size);
305192a1acfSDavid Herrmann 		return;
306192a1acfSDavid Herrmann 	}
307192a1acfSDavid Herrmann 
308192a1acfSDavid Herrmann 	memset(cmd, 0, sizeof(cmd));
309192a1acfSDavid Herrmann 	cmd[0] = WIIPROTO_REQ_WMEM;
310192a1acfSDavid Herrmann 	cmd[2] = (offset >> 16) & 0xff;
311192a1acfSDavid Herrmann 	cmd[3] = (offset >> 8) & 0xff;
312192a1acfSDavid Herrmann 	cmd[4] = offset & 0xff;
313192a1acfSDavid Herrmann 	cmd[5] = size;
314192a1acfSDavid Herrmann 	memcpy(&cmd[6], buf, size);
315192a1acfSDavid Herrmann 
316192a1acfSDavid Herrmann 	if (!eeprom)
317192a1acfSDavid Herrmann 		cmd[1] |= 0x04;
318192a1acfSDavid Herrmann 
319192a1acfSDavid Herrmann 	wiiproto_keep_rumble(wdata, &cmd[1]);
320192a1acfSDavid Herrmann 	wiimote_queue(wdata, cmd, sizeof(cmd));
321192a1acfSDavid Herrmann }
322192a1acfSDavid Herrmann 
323*1d3452c6SDavid Herrmann void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom, __u32 offset,
324*1d3452c6SDavid Herrmann 								__u16 size)
325fad8c0e3SDavid Herrmann {
326fad8c0e3SDavid Herrmann 	__u8 cmd[7];
327fad8c0e3SDavid Herrmann 
328fad8c0e3SDavid Herrmann 	if (size == 0) {
329fad8c0e3SDavid Herrmann 		hid_warn(wdata->hdev, "Invalid length %d rmem request\n", size);
330fad8c0e3SDavid Herrmann 		return;
331fad8c0e3SDavid Herrmann 	}
332fad8c0e3SDavid Herrmann 
333fad8c0e3SDavid Herrmann 	cmd[0] = WIIPROTO_REQ_RMEM;
334fad8c0e3SDavid Herrmann 	cmd[1] = 0;
335fad8c0e3SDavid Herrmann 	cmd[2] = (offset >> 16) & 0xff;
336fad8c0e3SDavid Herrmann 	cmd[3] = (offset >> 8) & 0xff;
337fad8c0e3SDavid Herrmann 	cmd[4] = offset & 0xff;
338fad8c0e3SDavid Herrmann 	cmd[5] = (size >> 8) & 0xff;
339fad8c0e3SDavid Herrmann 	cmd[6] = size & 0xff;
340fad8c0e3SDavid Herrmann 
341fad8c0e3SDavid Herrmann 	if (!eeprom)
342fad8c0e3SDavid Herrmann 		cmd[1] |= 0x04;
343fad8c0e3SDavid Herrmann 
344fad8c0e3SDavid Herrmann 	wiiproto_keep_rumble(wdata, &cmd[1]);
345fad8c0e3SDavid Herrmann 	wiimote_queue(wdata, cmd, sizeof(cmd));
346fad8c0e3SDavid Herrmann }
347fad8c0e3SDavid Herrmann 
348192a1acfSDavid Herrmann /* requries the cmd-mutex to be held */
3497e274400SDavid Herrmann int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
350192a1acfSDavid Herrmann 						const __u8 *wmem, __u8 size)
351192a1acfSDavid Herrmann {
352192a1acfSDavid Herrmann 	unsigned long flags;
353192a1acfSDavid Herrmann 	int ret;
354192a1acfSDavid Herrmann 
355192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
356192a1acfSDavid Herrmann 	wiimote_cmd_set(wdata, WIIPROTO_REQ_WMEM, 0);
357192a1acfSDavid Herrmann 	wiiproto_req_wreg(wdata, offset, wmem, size);
358192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
359192a1acfSDavid Herrmann 
360192a1acfSDavid Herrmann 	ret = wiimote_cmd_wait(wdata);
361192a1acfSDavid Herrmann 	if (!ret && wdata->state.cmd_err)
362192a1acfSDavid Herrmann 		ret = -EIO;
363192a1acfSDavid Herrmann 
364192a1acfSDavid Herrmann 	return ret;
365192a1acfSDavid Herrmann }
366192a1acfSDavid Herrmann 
367fad8c0e3SDavid Herrmann /* requries the cmd-mutex to be held */
368fad8c0e3SDavid Herrmann ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset, __u8 *rmem,
369fad8c0e3SDavid Herrmann 								__u8 size)
370fad8c0e3SDavid Herrmann {
371fad8c0e3SDavid Herrmann 	unsigned long flags;
372fad8c0e3SDavid Herrmann 	ssize_t ret;
373fad8c0e3SDavid Herrmann 
374fad8c0e3SDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
375fad8c0e3SDavid Herrmann 	wdata->state.cmd_read_size = size;
376fad8c0e3SDavid Herrmann 	wdata->state.cmd_read_buf = rmem;
377fad8c0e3SDavid Herrmann 	wiimote_cmd_set(wdata, WIIPROTO_REQ_RMEM, offset & 0xffff);
378fad8c0e3SDavid Herrmann 	wiiproto_req_rreg(wdata, offset, size);
379fad8c0e3SDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
380fad8c0e3SDavid Herrmann 
381fad8c0e3SDavid Herrmann 	ret = wiimote_cmd_wait(wdata);
382fad8c0e3SDavid Herrmann 
383fad8c0e3SDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
384fad8c0e3SDavid Herrmann 	wdata->state.cmd_read_buf = NULL;
385fad8c0e3SDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
386fad8c0e3SDavid Herrmann 
387fad8c0e3SDavid Herrmann 	if (!ret) {
388fad8c0e3SDavid Herrmann 		if (wdata->state.cmd_read_size == 0)
389fad8c0e3SDavid Herrmann 			ret = -EIO;
390fad8c0e3SDavid Herrmann 		else
391fad8c0e3SDavid Herrmann 			ret = wdata->state.cmd_read_size;
392fad8c0e3SDavid Herrmann 	}
393fad8c0e3SDavid Herrmann 
394fad8c0e3SDavid Herrmann 	return ret;
395fad8c0e3SDavid Herrmann }
396fad8c0e3SDavid Herrmann 
397192a1acfSDavid Herrmann static int wiimote_battery_get_property(struct power_supply *psy,
398192a1acfSDavid Herrmann 						enum power_supply_property psp,
399192a1acfSDavid Herrmann 						union power_supply_propval *val)
400192a1acfSDavid Herrmann {
401192a1acfSDavid Herrmann 	struct wiimote_data *wdata = container_of(psy,
402192a1acfSDavid Herrmann 						struct wiimote_data, battery);
403192a1acfSDavid Herrmann 	int ret = 0, state;
404192a1acfSDavid Herrmann 	unsigned long flags;
405192a1acfSDavid Herrmann 
406192a1acfSDavid Herrmann 	ret = wiimote_cmd_acquire(wdata);
407192a1acfSDavid Herrmann 	if (ret)
408192a1acfSDavid Herrmann 		return ret;
409192a1acfSDavid Herrmann 
410192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
411192a1acfSDavid Herrmann 	wiimote_cmd_set(wdata, WIIPROTO_REQ_SREQ, 0);
412192a1acfSDavid Herrmann 	wiiproto_req_status(wdata);
413192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
414192a1acfSDavid Herrmann 
415192a1acfSDavid Herrmann 	ret = wiimote_cmd_wait(wdata);
416192a1acfSDavid Herrmann 	state = wdata->state.cmd_battery;
417192a1acfSDavid Herrmann 	wiimote_cmd_release(wdata);
418192a1acfSDavid Herrmann 
419192a1acfSDavid Herrmann 	if (ret)
420192a1acfSDavid Herrmann 		return ret;
421192a1acfSDavid Herrmann 
422192a1acfSDavid Herrmann 	switch (psp) {
423192a1acfSDavid Herrmann 		case POWER_SUPPLY_PROP_CAPACITY:
424192a1acfSDavid Herrmann 			val->intval = state * 100 / 255;
425192a1acfSDavid Herrmann 			break;
426192a1acfSDavid Herrmann 		default:
427192a1acfSDavid Herrmann 			ret = -EINVAL;
428192a1acfSDavid Herrmann 			break;
429192a1acfSDavid Herrmann 	}
430192a1acfSDavid Herrmann 
431192a1acfSDavid Herrmann 	return ret;
432192a1acfSDavid Herrmann }
433192a1acfSDavid Herrmann 
434192a1acfSDavid Herrmann static int wiimote_init_ir(struct wiimote_data *wdata, __u16 mode)
435192a1acfSDavid Herrmann {
436192a1acfSDavid Herrmann 	int ret;
437192a1acfSDavid Herrmann 	unsigned long flags;
438192a1acfSDavid Herrmann 	__u8 format = 0;
439192a1acfSDavid Herrmann 	static const __u8 data_enable[] = { 0x01 };
440192a1acfSDavid Herrmann 	static const __u8 data_sens1[] = { 0x02, 0x00, 0x00, 0x71, 0x01,
441192a1acfSDavid Herrmann 						0x00, 0xaa, 0x00, 0x64 };
442192a1acfSDavid Herrmann 	static const __u8 data_sens2[] = { 0x63, 0x03 };
443192a1acfSDavid Herrmann 	static const __u8 data_fin[] = { 0x08 };
444192a1acfSDavid Herrmann 
445192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
446192a1acfSDavid Herrmann 
447192a1acfSDavid Herrmann 	if (mode == (wdata->state.flags & WIIPROTO_FLAGS_IR)) {
448192a1acfSDavid Herrmann 		spin_unlock_irqrestore(&wdata->state.lock, flags);
449192a1acfSDavid Herrmann 		return 0;
450192a1acfSDavid Herrmann 	}
451192a1acfSDavid Herrmann 
452192a1acfSDavid Herrmann 	if (mode == 0) {
453192a1acfSDavid Herrmann 		wdata->state.flags &= ~WIIPROTO_FLAGS_IR;
454192a1acfSDavid Herrmann 		wiiproto_req_ir1(wdata, 0);
455192a1acfSDavid Herrmann 		wiiproto_req_ir2(wdata, 0);
456192a1acfSDavid Herrmann 		wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
457192a1acfSDavid Herrmann 		spin_unlock_irqrestore(&wdata->state.lock, flags);
458192a1acfSDavid Herrmann 		return 0;
459192a1acfSDavid Herrmann 	}
460192a1acfSDavid Herrmann 
461192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
462192a1acfSDavid Herrmann 
463192a1acfSDavid Herrmann 	ret = wiimote_cmd_acquire(wdata);
464192a1acfSDavid Herrmann 	if (ret)
465192a1acfSDavid Herrmann 		return ret;
466192a1acfSDavid Herrmann 
467192a1acfSDavid Herrmann 	/* send PIXEL CLOCK ENABLE cmd first */
468192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
469192a1acfSDavid Herrmann 	wiimote_cmd_set(wdata, WIIPROTO_REQ_IR1, 0);
470192a1acfSDavid Herrmann 	wiiproto_req_ir1(wdata, 0x06);
471192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
472192a1acfSDavid Herrmann 
473192a1acfSDavid Herrmann 	ret = wiimote_cmd_wait(wdata);
474192a1acfSDavid Herrmann 	if (ret)
475192a1acfSDavid Herrmann 		goto unlock;
476192a1acfSDavid Herrmann 	if (wdata->state.cmd_err) {
477192a1acfSDavid Herrmann 		ret = -EIO;
478192a1acfSDavid Herrmann 		goto unlock;
479192a1acfSDavid Herrmann 	}
480192a1acfSDavid Herrmann 
481192a1acfSDavid Herrmann 	/* enable IR LOGIC */
482192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
483192a1acfSDavid Herrmann 	wiimote_cmd_set(wdata, WIIPROTO_REQ_IR2, 0);
484192a1acfSDavid Herrmann 	wiiproto_req_ir2(wdata, 0x06);
485192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
486192a1acfSDavid Herrmann 
487192a1acfSDavid Herrmann 	ret = wiimote_cmd_wait(wdata);
488192a1acfSDavid Herrmann 	if (ret)
489192a1acfSDavid Herrmann 		goto unlock;
490192a1acfSDavid Herrmann 	if (wdata->state.cmd_err) {
491192a1acfSDavid Herrmann 		ret = -EIO;
492192a1acfSDavid Herrmann 		goto unlock;
493192a1acfSDavid Herrmann 	}
494192a1acfSDavid Herrmann 
495192a1acfSDavid Herrmann 	/* enable IR cam but do not make it send data, yet */
496192a1acfSDavid Herrmann 	ret = wiimote_cmd_write(wdata, 0xb00030, data_enable,
497192a1acfSDavid Herrmann 							sizeof(data_enable));
498192a1acfSDavid Herrmann 	if (ret)
499192a1acfSDavid Herrmann 		goto unlock;
500192a1acfSDavid Herrmann 
501192a1acfSDavid Herrmann 	/* write first sensitivity block */
502192a1acfSDavid Herrmann 	ret = wiimote_cmd_write(wdata, 0xb00000, data_sens1,
503192a1acfSDavid Herrmann 							sizeof(data_sens1));
504192a1acfSDavid Herrmann 	if (ret)
505192a1acfSDavid Herrmann 		goto unlock;
506192a1acfSDavid Herrmann 
507192a1acfSDavid Herrmann 	/* write second sensitivity block */
508192a1acfSDavid Herrmann 	ret = wiimote_cmd_write(wdata, 0xb0001a, data_sens2,
509192a1acfSDavid Herrmann 							sizeof(data_sens2));
510192a1acfSDavid Herrmann 	if (ret)
511192a1acfSDavid Herrmann 		goto unlock;
512192a1acfSDavid Herrmann 
513192a1acfSDavid Herrmann 	/* put IR cam into desired state */
514192a1acfSDavid Herrmann 	switch (mode) {
515192a1acfSDavid Herrmann 		case WIIPROTO_FLAG_IR_FULL:
516192a1acfSDavid Herrmann 			format = 5;
517192a1acfSDavid Herrmann 			break;
518192a1acfSDavid Herrmann 		case WIIPROTO_FLAG_IR_EXT:
519192a1acfSDavid Herrmann 			format = 3;
520192a1acfSDavid Herrmann 			break;
521192a1acfSDavid Herrmann 		case WIIPROTO_FLAG_IR_BASIC:
522192a1acfSDavid Herrmann 			format = 1;
523192a1acfSDavid Herrmann 			break;
524192a1acfSDavid Herrmann 	}
525192a1acfSDavid Herrmann 	ret = wiimote_cmd_write(wdata, 0xb00033, &format, sizeof(format));
526192a1acfSDavid Herrmann 	if (ret)
527192a1acfSDavid Herrmann 		goto unlock;
528192a1acfSDavid Herrmann 
529192a1acfSDavid Herrmann 	/* make IR cam send data */
530192a1acfSDavid Herrmann 	ret = wiimote_cmd_write(wdata, 0xb00030, data_fin, sizeof(data_fin));
531192a1acfSDavid Herrmann 	if (ret)
532192a1acfSDavid Herrmann 		goto unlock;
533192a1acfSDavid Herrmann 
534192a1acfSDavid Herrmann 	/* request new DRM mode compatible to IR mode */
535192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
536192a1acfSDavid Herrmann 	wdata->state.flags &= ~WIIPROTO_FLAGS_IR;
537192a1acfSDavid Herrmann 	wdata->state.flags |= mode & WIIPROTO_FLAGS_IR;
538192a1acfSDavid Herrmann 	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
539192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
540192a1acfSDavid Herrmann 
541192a1acfSDavid Herrmann unlock:
542192a1acfSDavid Herrmann 	wiimote_cmd_release(wdata);
543192a1acfSDavid Herrmann 	return ret;
544192a1acfSDavid Herrmann }
545192a1acfSDavid Herrmann 
546192a1acfSDavid Herrmann static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
547192a1acfSDavid Herrmann {
548192a1acfSDavid Herrmann 	struct wiimote_data *wdata;
549192a1acfSDavid Herrmann 	struct device *dev = led_dev->dev->parent;
550192a1acfSDavid Herrmann 	int i;
551192a1acfSDavid Herrmann 	unsigned long flags;
552192a1acfSDavid Herrmann 	bool value = false;
553192a1acfSDavid Herrmann 
554192a1acfSDavid Herrmann 	wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
555192a1acfSDavid Herrmann 
556192a1acfSDavid Herrmann 	for (i = 0; i < 4; ++i) {
557192a1acfSDavid Herrmann 		if (wdata->leds[i] == led_dev) {
558192a1acfSDavid Herrmann 			spin_lock_irqsave(&wdata->state.lock, flags);
559192a1acfSDavid Herrmann 			value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1);
560192a1acfSDavid Herrmann 			spin_unlock_irqrestore(&wdata->state.lock, flags);
561192a1acfSDavid Herrmann 			break;
562192a1acfSDavid Herrmann 		}
563192a1acfSDavid Herrmann 	}
564192a1acfSDavid Herrmann 
565192a1acfSDavid Herrmann 	return value ? LED_FULL : LED_OFF;
566192a1acfSDavid Herrmann }
567192a1acfSDavid Herrmann 
568192a1acfSDavid Herrmann static void wiimote_leds_set(struct led_classdev *led_dev,
569192a1acfSDavid Herrmann 						enum led_brightness value)
570192a1acfSDavid Herrmann {
571192a1acfSDavid Herrmann 	struct wiimote_data *wdata;
572192a1acfSDavid Herrmann 	struct device *dev = led_dev->dev->parent;
573192a1acfSDavid Herrmann 	int i;
574192a1acfSDavid Herrmann 	unsigned long flags;
575192a1acfSDavid Herrmann 	__u8 state, flag;
576192a1acfSDavid Herrmann 
577192a1acfSDavid Herrmann 	wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
578192a1acfSDavid Herrmann 
579192a1acfSDavid Herrmann 	for (i = 0; i < 4; ++i) {
580192a1acfSDavid Herrmann 		if (wdata->leds[i] == led_dev) {
581192a1acfSDavid Herrmann 			flag = WIIPROTO_FLAG_LED(i + 1);
582192a1acfSDavid Herrmann 			spin_lock_irqsave(&wdata->state.lock, flags);
583192a1acfSDavid Herrmann 			state = wdata->state.flags;
584192a1acfSDavid Herrmann 			if (value == LED_OFF)
585192a1acfSDavid Herrmann 				wiiproto_req_leds(wdata, state & ~flag);
586192a1acfSDavid Herrmann 			else
587192a1acfSDavid Herrmann 				wiiproto_req_leds(wdata, state | flag);
588192a1acfSDavid Herrmann 			spin_unlock_irqrestore(&wdata->state.lock, flags);
589192a1acfSDavid Herrmann 			break;
590192a1acfSDavid Herrmann 		}
591192a1acfSDavid Herrmann 	}
592192a1acfSDavid Herrmann }
593192a1acfSDavid Herrmann 
594192a1acfSDavid Herrmann static int wiimote_ff_play(struct input_dev *dev, void *data,
595192a1acfSDavid Herrmann 							struct ff_effect *eff)
596192a1acfSDavid Herrmann {
597192a1acfSDavid Herrmann 	struct wiimote_data *wdata = input_get_drvdata(dev);
598192a1acfSDavid Herrmann 	__u8 value;
599192a1acfSDavid Herrmann 	unsigned long flags;
600192a1acfSDavid Herrmann 
601192a1acfSDavid Herrmann 	/*
602192a1acfSDavid Herrmann 	 * The wiimote supports only a single rumble motor so if any magnitude
603192a1acfSDavid Herrmann 	 * is set to non-zero then we start the rumble motor. If both are set to
604192a1acfSDavid Herrmann 	 * zero, we stop the rumble motor.
605192a1acfSDavid Herrmann 	 */
606192a1acfSDavid Herrmann 
607192a1acfSDavid Herrmann 	if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
608192a1acfSDavid Herrmann 		value = 1;
609192a1acfSDavid Herrmann 	else
610192a1acfSDavid Herrmann 		value = 0;
611192a1acfSDavid Herrmann 
612192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
613192a1acfSDavid Herrmann 	wiiproto_req_rumble(wdata, value);
614192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
615192a1acfSDavid Herrmann 
616192a1acfSDavid Herrmann 	return 0;
617192a1acfSDavid Herrmann }
618192a1acfSDavid Herrmann 
619192a1acfSDavid Herrmann static int wiimote_input_open(struct input_dev *dev)
620192a1acfSDavid Herrmann {
621192a1acfSDavid Herrmann 	struct wiimote_data *wdata = input_get_drvdata(dev);
622192a1acfSDavid Herrmann 
623192a1acfSDavid Herrmann 	return hid_hw_open(wdata->hdev);
624192a1acfSDavid Herrmann }
625192a1acfSDavid Herrmann 
626192a1acfSDavid Herrmann static void wiimote_input_close(struct input_dev *dev)
627192a1acfSDavid Herrmann {
628192a1acfSDavid Herrmann 	struct wiimote_data *wdata = input_get_drvdata(dev);
629192a1acfSDavid Herrmann 
630192a1acfSDavid Herrmann 	hid_hw_close(wdata->hdev);
631192a1acfSDavid Herrmann }
632192a1acfSDavid Herrmann 
633192a1acfSDavid Herrmann static int wiimote_accel_open(struct input_dev *dev)
634192a1acfSDavid Herrmann {
635192a1acfSDavid Herrmann 	struct wiimote_data *wdata = input_get_drvdata(dev);
636192a1acfSDavid Herrmann 	int ret;
637192a1acfSDavid Herrmann 	unsigned long flags;
638192a1acfSDavid Herrmann 
639192a1acfSDavid Herrmann 	ret = hid_hw_open(wdata->hdev);
640192a1acfSDavid Herrmann 	if (ret)
641192a1acfSDavid Herrmann 		return ret;
642192a1acfSDavid Herrmann 
643192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
644192a1acfSDavid Herrmann 	wiiproto_req_accel(wdata, true);
645192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
646192a1acfSDavid Herrmann 
647192a1acfSDavid Herrmann 	return 0;
648192a1acfSDavid Herrmann }
649192a1acfSDavid Herrmann 
650192a1acfSDavid Herrmann static void wiimote_accel_close(struct input_dev *dev)
651192a1acfSDavid Herrmann {
652192a1acfSDavid Herrmann 	struct wiimote_data *wdata = input_get_drvdata(dev);
653192a1acfSDavid Herrmann 	unsigned long flags;
654192a1acfSDavid Herrmann 
655192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
656192a1acfSDavid Herrmann 	wiiproto_req_accel(wdata, false);
657192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
658192a1acfSDavid Herrmann 
659192a1acfSDavid Herrmann 	hid_hw_close(wdata->hdev);
660192a1acfSDavid Herrmann }
661192a1acfSDavid Herrmann 
662192a1acfSDavid Herrmann static int wiimote_ir_open(struct input_dev *dev)
663192a1acfSDavid Herrmann {
664192a1acfSDavid Herrmann 	struct wiimote_data *wdata = input_get_drvdata(dev);
665192a1acfSDavid Herrmann 	int ret;
666192a1acfSDavid Herrmann 
667192a1acfSDavid Herrmann 	ret = hid_hw_open(wdata->hdev);
668192a1acfSDavid Herrmann 	if (ret)
669192a1acfSDavid Herrmann 		return ret;
670192a1acfSDavid Herrmann 
671192a1acfSDavid Herrmann 	ret = wiimote_init_ir(wdata, WIIPROTO_FLAG_IR_BASIC);
672192a1acfSDavid Herrmann 	if (ret) {
673192a1acfSDavid Herrmann 		hid_hw_close(wdata->hdev);
674192a1acfSDavid Herrmann 		return ret;
675192a1acfSDavid Herrmann 	}
676192a1acfSDavid Herrmann 
677192a1acfSDavid Herrmann 	return 0;
678192a1acfSDavid Herrmann }
679192a1acfSDavid Herrmann 
680192a1acfSDavid Herrmann static void wiimote_ir_close(struct input_dev *dev)
681192a1acfSDavid Herrmann {
682192a1acfSDavid Herrmann 	struct wiimote_data *wdata = input_get_drvdata(dev);
683192a1acfSDavid Herrmann 
684192a1acfSDavid Herrmann 	wiimote_init_ir(wdata, 0);
685192a1acfSDavid Herrmann 	hid_hw_close(wdata->hdev);
686192a1acfSDavid Herrmann }
687192a1acfSDavid Herrmann 
688192a1acfSDavid Herrmann static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
689192a1acfSDavid Herrmann {
690192a1acfSDavid Herrmann 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT],
691192a1acfSDavid Herrmann 							!!(payload[0] & 0x01));
692192a1acfSDavid Herrmann 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_RIGHT],
693192a1acfSDavid Herrmann 							!!(payload[0] & 0x02));
694192a1acfSDavid Herrmann 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_DOWN],
695192a1acfSDavid Herrmann 							!!(payload[0] & 0x04));
696192a1acfSDavid Herrmann 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_UP],
697192a1acfSDavid Herrmann 							!!(payload[0] & 0x08));
698192a1acfSDavid Herrmann 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_PLUS],
699192a1acfSDavid Herrmann 							!!(payload[0] & 0x10));
700192a1acfSDavid Herrmann 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_TWO],
701192a1acfSDavid Herrmann 							!!(payload[1] & 0x01));
702192a1acfSDavid Herrmann 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_ONE],
703192a1acfSDavid Herrmann 							!!(payload[1] & 0x02));
704192a1acfSDavid Herrmann 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_B],
705192a1acfSDavid Herrmann 							!!(payload[1] & 0x04));
706192a1acfSDavid Herrmann 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_A],
707192a1acfSDavid Herrmann 							!!(payload[1] & 0x08));
708192a1acfSDavid Herrmann 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_MINUS],
709192a1acfSDavid Herrmann 							!!(payload[1] & 0x10));
710192a1acfSDavid Herrmann 	input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_HOME],
711192a1acfSDavid Herrmann 							!!(payload[1] & 0x80));
712192a1acfSDavid Herrmann 	input_sync(wdata->input);
713192a1acfSDavid Herrmann }
714192a1acfSDavid Herrmann 
715192a1acfSDavid Herrmann static void handler_accel(struct wiimote_data *wdata, const __u8 *payload)
716192a1acfSDavid Herrmann {
717192a1acfSDavid Herrmann 	__u16 x, y, z;
718192a1acfSDavid Herrmann 
719192a1acfSDavid Herrmann 	if (!(wdata->state.flags & WIIPROTO_FLAG_ACCEL))
720192a1acfSDavid Herrmann 		return;
721192a1acfSDavid Herrmann 
722192a1acfSDavid Herrmann 	/*
723192a1acfSDavid Herrmann 	 * payload is: BB BB XX YY ZZ
724192a1acfSDavid Herrmann 	 * Accelerometer data is encoded into 3 10bit values. XX, YY and ZZ
725192a1acfSDavid Herrmann 	 * contain the upper 8 bits of each value. The lower 2 bits are
726192a1acfSDavid Herrmann 	 * contained in the buttons data BB BB.
727192a1acfSDavid Herrmann 	 * Bits 6 and 7 of the first buttons byte BB is the lower 2 bits of the
728192a1acfSDavid Herrmann 	 * X accel value. Bit 5 of the second buttons byte is the 2nd bit of Y
729192a1acfSDavid Herrmann 	 * accel value and bit 6 is the second bit of the Z value.
730192a1acfSDavid Herrmann 	 * The first bit of Y and Z values is not available and always set to 0.
731192a1acfSDavid Herrmann 	 * 0x200 is returned on no movement.
732192a1acfSDavid Herrmann 	 */
733192a1acfSDavid Herrmann 
734192a1acfSDavid Herrmann 	x = payload[2] << 2;
735192a1acfSDavid Herrmann 	y = payload[3] << 2;
736192a1acfSDavid Herrmann 	z = payload[4] << 2;
737192a1acfSDavid Herrmann 
738192a1acfSDavid Herrmann 	x |= (payload[0] >> 5) & 0x3;
739192a1acfSDavid Herrmann 	y |= (payload[1] >> 4) & 0x2;
740192a1acfSDavid Herrmann 	z |= (payload[1] >> 5) & 0x2;
741192a1acfSDavid Herrmann 
742192a1acfSDavid Herrmann 	input_report_abs(wdata->accel, ABS_RX, x - 0x200);
743192a1acfSDavid Herrmann 	input_report_abs(wdata->accel, ABS_RY, y - 0x200);
744192a1acfSDavid Herrmann 	input_report_abs(wdata->accel, ABS_RZ, z - 0x200);
745192a1acfSDavid Herrmann 	input_sync(wdata->accel);
746192a1acfSDavid Herrmann }
747192a1acfSDavid Herrmann 
748192a1acfSDavid Herrmann #define ir_to_input0(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
749192a1acfSDavid Herrmann 							ABS_HAT0X, ABS_HAT0Y)
750192a1acfSDavid Herrmann #define ir_to_input1(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
751192a1acfSDavid Herrmann 							ABS_HAT1X, ABS_HAT1Y)
752192a1acfSDavid Herrmann #define ir_to_input2(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
753192a1acfSDavid Herrmann 							ABS_HAT2X, ABS_HAT2Y)
754192a1acfSDavid Herrmann #define ir_to_input3(wdata, ir, packed) __ir_to_input((wdata), (ir), (packed), \
755192a1acfSDavid Herrmann 							ABS_HAT3X, ABS_HAT3Y)
756192a1acfSDavid Herrmann 
757192a1acfSDavid Herrmann static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
758192a1acfSDavid Herrmann 						bool packed, __u8 xid, __u8 yid)
759192a1acfSDavid Herrmann {
760192a1acfSDavid Herrmann 	__u16 x, y;
761192a1acfSDavid Herrmann 
762192a1acfSDavid Herrmann 	if (!(wdata->state.flags & WIIPROTO_FLAGS_IR))
763192a1acfSDavid Herrmann 		return;
764192a1acfSDavid Herrmann 
765192a1acfSDavid Herrmann 	/*
766192a1acfSDavid Herrmann 	 * Basic IR data is encoded into 3 bytes. The first two bytes are the
767192a1acfSDavid Herrmann 	 * upper 8 bit of the X/Y data, the 3rd byte contains the lower 2 bits
768192a1acfSDavid Herrmann 	 * of both.
769192a1acfSDavid Herrmann 	 * If data is packed, then the 3rd byte is put first and slightly
770192a1acfSDavid Herrmann 	 * reordered. This allows to interleave packed and non-packed data to
771192a1acfSDavid Herrmann 	 * have two IR sets in 5 bytes instead of 6.
772192a1acfSDavid Herrmann 	 * The resulting 10bit X/Y values are passed to the ABS_HATXY input dev.
773192a1acfSDavid Herrmann 	 */
774192a1acfSDavid Herrmann 
775192a1acfSDavid Herrmann 	if (packed) {
776192a1acfSDavid Herrmann 		x = ir[1] << 2;
777192a1acfSDavid Herrmann 		y = ir[2] << 2;
778192a1acfSDavid Herrmann 
779192a1acfSDavid Herrmann 		x |= ir[0] & 0x3;
780192a1acfSDavid Herrmann 		y |= (ir[0] >> 2) & 0x3;
781192a1acfSDavid Herrmann 	} else {
782192a1acfSDavid Herrmann 		x = ir[0] << 2;
783192a1acfSDavid Herrmann 		y = ir[1] << 2;
784192a1acfSDavid Herrmann 
785192a1acfSDavid Herrmann 		x |= (ir[2] >> 4) & 0x3;
786192a1acfSDavid Herrmann 		y |= (ir[2] >> 6) & 0x3;
787192a1acfSDavid Herrmann 	}
788192a1acfSDavid Herrmann 
789192a1acfSDavid Herrmann 	input_report_abs(wdata->ir, xid, x);
790192a1acfSDavid Herrmann 	input_report_abs(wdata->ir, yid, y);
791192a1acfSDavid Herrmann }
792192a1acfSDavid Herrmann 
793192a1acfSDavid Herrmann static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
794192a1acfSDavid Herrmann {
795192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
796192a1acfSDavid Herrmann 
797192a1acfSDavid Herrmann 	/* on status reports the drm is reset so we need to resend the drm */
798192a1acfSDavid Herrmann 	wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
799192a1acfSDavid Herrmann 
800cb99221bSDavid Herrmann 	wiiext_event(wdata, payload[2] & 0x02);
801cb99221bSDavid Herrmann 
802192a1acfSDavid Herrmann 	if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_SREQ, 0)) {
803192a1acfSDavid Herrmann 		wdata->state.cmd_battery = payload[5];
804192a1acfSDavid Herrmann 		wiimote_cmd_complete(wdata);
805192a1acfSDavid Herrmann 	}
806192a1acfSDavid Herrmann }
807192a1acfSDavid Herrmann 
808192a1acfSDavid Herrmann static void handler_data(struct wiimote_data *wdata, const __u8 *payload)
809192a1acfSDavid Herrmann {
810fad8c0e3SDavid Herrmann 	__u16 offset = payload[3] << 8 | payload[4];
811fad8c0e3SDavid Herrmann 	__u8 size = (payload[2] >> 4) + 1;
812fad8c0e3SDavid Herrmann 	__u8 err = payload[2] & 0x0f;
813fad8c0e3SDavid Herrmann 
814192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
815fad8c0e3SDavid Herrmann 
816fad8c0e3SDavid Herrmann 	if (wiimote_cmd_pending(wdata, WIIPROTO_REQ_RMEM, offset)) {
817fad8c0e3SDavid Herrmann 		if (err)
818fad8c0e3SDavid Herrmann 			size = 0;
819fad8c0e3SDavid Herrmann 		else if (size > wdata->state.cmd_read_size)
820fad8c0e3SDavid Herrmann 			size = wdata->state.cmd_read_size;
821fad8c0e3SDavid Herrmann 
822fad8c0e3SDavid Herrmann 		wdata->state.cmd_read_size = size;
823fad8c0e3SDavid Herrmann 		if (wdata->state.cmd_read_buf)
824fad8c0e3SDavid Herrmann 			memcpy(wdata->state.cmd_read_buf, &payload[5], size);
825fad8c0e3SDavid Herrmann 		wiimote_cmd_complete(wdata);
826fad8c0e3SDavid Herrmann 	}
827192a1acfSDavid Herrmann }
828192a1acfSDavid Herrmann 
829192a1acfSDavid Herrmann static void handler_return(struct wiimote_data *wdata, const __u8 *payload)
830192a1acfSDavid Herrmann {
831192a1acfSDavid Herrmann 	__u8 err = payload[3];
832192a1acfSDavid Herrmann 	__u8 cmd = payload[2];
833192a1acfSDavid Herrmann 
834192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
835192a1acfSDavid Herrmann 
836192a1acfSDavid Herrmann 	if (wiimote_cmd_pending(wdata, cmd, 0)) {
837192a1acfSDavid Herrmann 		wdata->state.cmd_err = err;
838192a1acfSDavid Herrmann 		wiimote_cmd_complete(wdata);
839192a1acfSDavid Herrmann 	} else if (err) {
840192a1acfSDavid Herrmann 		hid_warn(wdata->hdev, "Remote error %hhu on req %hhu\n", err,
841192a1acfSDavid Herrmann 									cmd);
842192a1acfSDavid Herrmann 	}
843192a1acfSDavid Herrmann }
844192a1acfSDavid Herrmann 
845192a1acfSDavid Herrmann static void handler_drm_KA(struct wiimote_data *wdata, const __u8 *payload)
846192a1acfSDavid Herrmann {
847192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
848192a1acfSDavid Herrmann 	handler_accel(wdata, payload);
849192a1acfSDavid Herrmann }
850192a1acfSDavid Herrmann 
851192a1acfSDavid Herrmann static void handler_drm_KE(struct wiimote_data *wdata, const __u8 *payload)
852192a1acfSDavid Herrmann {
853192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
8540b6815d7SDavid Herrmann 	wiiext_handle(wdata, &payload[2]);
855192a1acfSDavid Herrmann }
856192a1acfSDavid Herrmann 
857192a1acfSDavid Herrmann static void handler_drm_KAI(struct wiimote_data *wdata, const __u8 *payload)
858192a1acfSDavid Herrmann {
859192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
860192a1acfSDavid Herrmann 	handler_accel(wdata, payload);
861192a1acfSDavid Herrmann 	ir_to_input0(wdata, &payload[5], false);
862192a1acfSDavid Herrmann 	ir_to_input1(wdata, &payload[8], false);
863192a1acfSDavid Herrmann 	ir_to_input2(wdata, &payload[11], false);
864192a1acfSDavid Herrmann 	ir_to_input3(wdata, &payload[14], false);
865192a1acfSDavid Herrmann 	input_sync(wdata->ir);
866192a1acfSDavid Herrmann }
867192a1acfSDavid Herrmann 
868192a1acfSDavid Herrmann static void handler_drm_KEE(struct wiimote_data *wdata, const __u8 *payload)
869192a1acfSDavid Herrmann {
870192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
8710b6815d7SDavid Herrmann 	wiiext_handle(wdata, &payload[2]);
872192a1acfSDavid Herrmann }
873192a1acfSDavid Herrmann 
874192a1acfSDavid Herrmann static void handler_drm_KIE(struct wiimote_data *wdata, const __u8 *payload)
875192a1acfSDavid Herrmann {
876192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
877192a1acfSDavid Herrmann 	ir_to_input0(wdata, &payload[2], false);
878192a1acfSDavid Herrmann 	ir_to_input1(wdata, &payload[4], true);
879192a1acfSDavid Herrmann 	ir_to_input2(wdata, &payload[7], false);
880192a1acfSDavid Herrmann 	ir_to_input3(wdata, &payload[9], true);
881192a1acfSDavid Herrmann 	input_sync(wdata->ir);
8820b6815d7SDavid Herrmann 	wiiext_handle(wdata, &payload[12]);
883192a1acfSDavid Herrmann }
884192a1acfSDavid Herrmann 
885192a1acfSDavid Herrmann static void handler_drm_KAE(struct wiimote_data *wdata, const __u8 *payload)
886192a1acfSDavid Herrmann {
887192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
888192a1acfSDavid Herrmann 	handler_accel(wdata, payload);
8890b6815d7SDavid Herrmann 	wiiext_handle(wdata, &payload[5]);
890192a1acfSDavid Herrmann }
891192a1acfSDavid Herrmann 
892192a1acfSDavid Herrmann static void handler_drm_KAIE(struct wiimote_data *wdata, const __u8 *payload)
893192a1acfSDavid Herrmann {
894192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
895192a1acfSDavid Herrmann 	handler_accel(wdata, payload);
896192a1acfSDavid Herrmann 	ir_to_input0(wdata, &payload[5], false);
897192a1acfSDavid Herrmann 	ir_to_input1(wdata, &payload[7], true);
898192a1acfSDavid Herrmann 	ir_to_input2(wdata, &payload[10], false);
899192a1acfSDavid Herrmann 	ir_to_input3(wdata, &payload[12], true);
900192a1acfSDavid Herrmann 	input_sync(wdata->ir);
9010b6815d7SDavid Herrmann 	wiiext_handle(wdata, &payload[15]);
902192a1acfSDavid Herrmann }
903192a1acfSDavid Herrmann 
904192a1acfSDavid Herrmann static void handler_drm_E(struct wiimote_data *wdata, const __u8 *payload)
905192a1acfSDavid Herrmann {
9060b6815d7SDavid Herrmann 	wiiext_handle(wdata, payload);
907192a1acfSDavid Herrmann }
908192a1acfSDavid Herrmann 
909192a1acfSDavid Herrmann static void handler_drm_SKAI1(struct wiimote_data *wdata, const __u8 *payload)
910192a1acfSDavid Herrmann {
911192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
912192a1acfSDavid Herrmann 
913192a1acfSDavid Herrmann 	wdata->state.accel_split[0] = payload[2];
914192a1acfSDavid Herrmann 	wdata->state.accel_split[1] = (payload[0] >> 1) & (0x10 | 0x20);
915192a1acfSDavid Herrmann 	wdata->state.accel_split[1] |= (payload[1] << 1) & (0x40 | 0x80);
916192a1acfSDavid Herrmann 
917192a1acfSDavid Herrmann 	ir_to_input0(wdata, &payload[3], false);
918192a1acfSDavid Herrmann 	ir_to_input1(wdata, &payload[12], false);
919192a1acfSDavid Herrmann 	input_sync(wdata->ir);
920192a1acfSDavid Herrmann }
921192a1acfSDavid Herrmann 
922192a1acfSDavid Herrmann static void handler_drm_SKAI2(struct wiimote_data *wdata, const __u8 *payload)
923192a1acfSDavid Herrmann {
924192a1acfSDavid Herrmann 	__u8 buf[5];
925192a1acfSDavid Herrmann 
926192a1acfSDavid Herrmann 	handler_keys(wdata, payload);
927192a1acfSDavid Herrmann 
928192a1acfSDavid Herrmann 	wdata->state.accel_split[1] |= (payload[0] >> 5) & (0x01 | 0x02);
929192a1acfSDavid Herrmann 	wdata->state.accel_split[1] |= (payload[1] >> 3) & (0x04 | 0x08);
930192a1acfSDavid Herrmann 
931192a1acfSDavid Herrmann 	buf[0] = 0;
932192a1acfSDavid Herrmann 	buf[1] = 0;
933192a1acfSDavid Herrmann 	buf[2] = wdata->state.accel_split[0];
934192a1acfSDavid Herrmann 	buf[3] = payload[2];
935192a1acfSDavid Herrmann 	buf[4] = wdata->state.accel_split[1];
936192a1acfSDavid Herrmann 	handler_accel(wdata, buf);
937192a1acfSDavid Herrmann 
938192a1acfSDavid Herrmann 	ir_to_input2(wdata, &payload[3], false);
939192a1acfSDavid Herrmann 	ir_to_input3(wdata, &payload[12], false);
940192a1acfSDavid Herrmann 	input_sync(wdata->ir);
941192a1acfSDavid Herrmann }
942192a1acfSDavid Herrmann 
943192a1acfSDavid Herrmann struct wiiproto_handler {
944192a1acfSDavid Herrmann 	__u8 id;
945192a1acfSDavid Herrmann 	size_t size;
946192a1acfSDavid Herrmann 	void (*func)(struct wiimote_data *wdata, const __u8 *payload);
947192a1acfSDavid Herrmann };
948192a1acfSDavid Herrmann 
949192a1acfSDavid Herrmann static struct wiiproto_handler handlers[] = {
950192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status },
951192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DATA, .size = 21, .func = handler_data },
952192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
953192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
954192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA },
955192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DRM_KE, .size = 10, .func = handler_drm_KE },
956192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI },
957192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DRM_KEE, .size = 21, .func = handler_drm_KEE },
958192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE },
959192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DRM_KIE, .size = 21, .func = handler_drm_KIE },
960192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE },
961192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DRM_E, .size = 21, .func = handler_drm_E },
962192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 },
963192a1acfSDavid Herrmann 	{ .id = WIIPROTO_REQ_DRM_SKAI2, .size = 21, .func = handler_drm_SKAI2 },
964192a1acfSDavid Herrmann 	{ .id = 0 }
965192a1acfSDavid Herrmann };
966192a1acfSDavid Herrmann 
967192a1acfSDavid Herrmann static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
968192a1acfSDavid Herrmann 							u8 *raw_data, int size)
969192a1acfSDavid Herrmann {
970192a1acfSDavid Herrmann 	struct wiimote_data *wdata = hid_get_drvdata(hdev);
971192a1acfSDavid Herrmann 	struct wiiproto_handler *h;
972192a1acfSDavid Herrmann 	int i;
973192a1acfSDavid Herrmann 	unsigned long flags;
974192a1acfSDavid Herrmann 	bool handled = false;
975192a1acfSDavid Herrmann 
976192a1acfSDavid Herrmann 	if (size < 1)
977192a1acfSDavid Herrmann 		return -EINVAL;
978192a1acfSDavid Herrmann 
979192a1acfSDavid Herrmann 	spin_lock_irqsave(&wdata->state.lock, flags);
980192a1acfSDavid Herrmann 
981192a1acfSDavid Herrmann 	for (i = 0; handlers[i].id; ++i) {
982192a1acfSDavid Herrmann 		h = &handlers[i];
983192a1acfSDavid Herrmann 		if (h->id == raw_data[0] && h->size < size) {
984192a1acfSDavid Herrmann 			h->func(wdata, &raw_data[1]);
985192a1acfSDavid Herrmann 			handled = true;
986192a1acfSDavid Herrmann 		}
987192a1acfSDavid Herrmann 	}
988192a1acfSDavid Herrmann 
989192a1acfSDavid Herrmann 	if (!handled)
990192a1acfSDavid Herrmann 		hid_warn(hdev, "Unhandled report %hhu size %d\n", raw_data[0],
991192a1acfSDavid Herrmann 									size);
992192a1acfSDavid Herrmann 
993192a1acfSDavid Herrmann 	spin_unlock_irqrestore(&wdata->state.lock, flags);
994192a1acfSDavid Herrmann 
995192a1acfSDavid Herrmann 	return 0;
996192a1acfSDavid Herrmann }
997192a1acfSDavid Herrmann 
998192a1acfSDavid Herrmann static void wiimote_leds_destroy(struct wiimote_data *wdata)
999192a1acfSDavid Herrmann {
1000192a1acfSDavid Herrmann 	int i;
1001192a1acfSDavid Herrmann 	struct led_classdev *led;
1002192a1acfSDavid Herrmann 
1003192a1acfSDavid Herrmann 	for (i = 0; i < 4; ++i) {
1004192a1acfSDavid Herrmann 		if (wdata->leds[i]) {
1005192a1acfSDavid Herrmann 			led = wdata->leds[i];
1006192a1acfSDavid Herrmann 			wdata->leds[i] = NULL;
1007192a1acfSDavid Herrmann 			led_classdev_unregister(led);
1008192a1acfSDavid Herrmann 			kfree(led);
1009192a1acfSDavid Herrmann 		}
1010192a1acfSDavid Herrmann 	}
1011192a1acfSDavid Herrmann }
1012192a1acfSDavid Herrmann 
1013192a1acfSDavid Herrmann static int wiimote_leds_create(struct wiimote_data *wdata)
1014192a1acfSDavid Herrmann {
1015192a1acfSDavid Herrmann 	int i, ret;
1016192a1acfSDavid Herrmann 	struct device *dev = &wdata->hdev->dev;
1017192a1acfSDavid Herrmann 	size_t namesz = strlen(dev_name(dev)) + 9;
1018192a1acfSDavid Herrmann 	struct led_classdev *led;
1019192a1acfSDavid Herrmann 	char *name;
1020192a1acfSDavid Herrmann 
1021192a1acfSDavid Herrmann 	for (i = 0; i < 4; ++i) {
1022192a1acfSDavid Herrmann 		led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
1023192a1acfSDavid Herrmann 		if (!led) {
1024192a1acfSDavid Herrmann 			ret = -ENOMEM;
1025192a1acfSDavid Herrmann 			goto err;
1026192a1acfSDavid Herrmann 		}
1027192a1acfSDavid Herrmann 		name = (void*)&led[1];
1028192a1acfSDavid Herrmann 		snprintf(name, namesz, "%s:blue:p%d", dev_name(dev), i);
1029192a1acfSDavid Herrmann 		led->name = name;
1030192a1acfSDavid Herrmann 		led->brightness = 0;
1031192a1acfSDavid Herrmann 		led->max_brightness = 1;
1032192a1acfSDavid Herrmann 		led->brightness_get = wiimote_leds_get;
1033192a1acfSDavid Herrmann 		led->brightness_set = wiimote_leds_set;
1034192a1acfSDavid Herrmann 
1035192a1acfSDavid Herrmann 		ret = led_classdev_register(dev, led);
1036192a1acfSDavid Herrmann 		if (ret) {
1037192a1acfSDavid Herrmann 			kfree(led);
1038192a1acfSDavid Herrmann 			goto err;
1039192a1acfSDavid Herrmann 		}
1040192a1acfSDavid Herrmann 		wdata->leds[i] = led;
1041192a1acfSDavid Herrmann 	}
1042192a1acfSDavid Herrmann 
1043192a1acfSDavid Herrmann 	return 0;
1044192a1acfSDavid Herrmann 
1045192a1acfSDavid Herrmann err:
1046192a1acfSDavid Herrmann 	wiimote_leds_destroy(wdata);
1047192a1acfSDavid Herrmann 	return ret;
1048192a1acfSDavid Herrmann }
1049192a1acfSDavid Herrmann 
1050192a1acfSDavid Herrmann static struct wiimote_data *wiimote_create(struct hid_device *hdev)
1051192a1acfSDavid Herrmann {
1052192a1acfSDavid Herrmann 	struct wiimote_data *wdata;
1053192a1acfSDavid Herrmann 	int i;
1054192a1acfSDavid Herrmann 
1055192a1acfSDavid Herrmann 	wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
1056192a1acfSDavid Herrmann 	if (!wdata)
1057192a1acfSDavid Herrmann 		return NULL;
1058192a1acfSDavid Herrmann 
1059192a1acfSDavid Herrmann 	wdata->input = input_allocate_device();
1060192a1acfSDavid Herrmann 	if (!wdata->input)
1061192a1acfSDavid Herrmann 		goto err;
1062192a1acfSDavid Herrmann 
1063192a1acfSDavid Herrmann 	wdata->hdev = hdev;
1064192a1acfSDavid Herrmann 	hid_set_drvdata(hdev, wdata);
1065192a1acfSDavid Herrmann 
1066192a1acfSDavid Herrmann 	input_set_drvdata(wdata->input, wdata);
1067192a1acfSDavid Herrmann 	wdata->input->open = wiimote_input_open;
1068192a1acfSDavid Herrmann 	wdata->input->close = wiimote_input_close;
1069192a1acfSDavid Herrmann 	wdata->input->dev.parent = &wdata->hdev->dev;
1070192a1acfSDavid Herrmann 	wdata->input->id.bustype = wdata->hdev->bus;
1071192a1acfSDavid Herrmann 	wdata->input->id.vendor = wdata->hdev->vendor;
1072192a1acfSDavid Herrmann 	wdata->input->id.product = wdata->hdev->product;
1073192a1acfSDavid Herrmann 	wdata->input->id.version = wdata->hdev->version;
1074192a1acfSDavid Herrmann 	wdata->input->name = WIIMOTE_NAME;
1075192a1acfSDavid Herrmann 
1076192a1acfSDavid Herrmann 	set_bit(EV_KEY, wdata->input->evbit);
1077192a1acfSDavid Herrmann 	for (i = 0; i < WIIPROTO_KEY_COUNT; ++i)
1078192a1acfSDavid Herrmann 		set_bit(wiiproto_keymap[i], wdata->input->keybit);
1079192a1acfSDavid Herrmann 
1080192a1acfSDavid Herrmann 	set_bit(FF_RUMBLE, wdata->input->ffbit);
1081192a1acfSDavid Herrmann 	if (input_ff_create_memless(wdata->input, NULL, wiimote_ff_play))
1082192a1acfSDavid Herrmann 		goto err_input;
1083192a1acfSDavid Herrmann 
1084192a1acfSDavid Herrmann 	wdata->accel = input_allocate_device();
1085192a1acfSDavid Herrmann 	if (!wdata->accel)
1086192a1acfSDavid Herrmann 		goto err_input;
1087192a1acfSDavid Herrmann 
1088192a1acfSDavid Herrmann 	input_set_drvdata(wdata->accel, wdata);
1089192a1acfSDavid Herrmann 	wdata->accel->open = wiimote_accel_open;
1090192a1acfSDavid Herrmann 	wdata->accel->close = wiimote_accel_close;
1091192a1acfSDavid Herrmann 	wdata->accel->dev.parent = &wdata->hdev->dev;
1092192a1acfSDavid Herrmann 	wdata->accel->id.bustype = wdata->hdev->bus;
1093192a1acfSDavid Herrmann 	wdata->accel->id.vendor = wdata->hdev->vendor;
1094192a1acfSDavid Herrmann 	wdata->accel->id.product = wdata->hdev->product;
1095192a1acfSDavid Herrmann 	wdata->accel->id.version = wdata->hdev->version;
1096192a1acfSDavid Herrmann 	wdata->accel->name = WIIMOTE_NAME " Accelerometer";
1097192a1acfSDavid Herrmann 
1098192a1acfSDavid Herrmann 	set_bit(EV_ABS, wdata->accel->evbit);
1099192a1acfSDavid Herrmann 	set_bit(ABS_RX, wdata->accel->absbit);
1100192a1acfSDavid Herrmann 	set_bit(ABS_RY, wdata->accel->absbit);
1101192a1acfSDavid Herrmann 	set_bit(ABS_RZ, wdata->accel->absbit);
1102192a1acfSDavid Herrmann 	input_set_abs_params(wdata->accel, ABS_RX, -500, 500, 2, 4);
1103192a1acfSDavid Herrmann 	input_set_abs_params(wdata->accel, ABS_RY, -500, 500, 2, 4);
1104192a1acfSDavid Herrmann 	input_set_abs_params(wdata->accel, ABS_RZ, -500, 500, 2, 4);
1105192a1acfSDavid Herrmann 
1106192a1acfSDavid Herrmann 	wdata->ir = input_allocate_device();
1107192a1acfSDavid Herrmann 	if (!wdata->ir)
1108192a1acfSDavid Herrmann 		goto err_ir;
1109192a1acfSDavid Herrmann 
1110192a1acfSDavid Herrmann 	input_set_drvdata(wdata->ir, wdata);
1111192a1acfSDavid Herrmann 	wdata->ir->open = wiimote_ir_open;
1112192a1acfSDavid Herrmann 	wdata->ir->close = wiimote_ir_close;
1113192a1acfSDavid Herrmann 	wdata->ir->dev.parent = &wdata->hdev->dev;
1114192a1acfSDavid Herrmann 	wdata->ir->id.bustype = wdata->hdev->bus;
1115192a1acfSDavid Herrmann 	wdata->ir->id.vendor = wdata->hdev->vendor;
1116192a1acfSDavid Herrmann 	wdata->ir->id.product = wdata->hdev->product;
1117192a1acfSDavid Herrmann 	wdata->ir->id.version = wdata->hdev->version;
1118192a1acfSDavid Herrmann 	wdata->ir->name = WIIMOTE_NAME " IR";
1119192a1acfSDavid Herrmann 
1120192a1acfSDavid Herrmann 	set_bit(EV_ABS, wdata->ir->evbit);
1121192a1acfSDavid Herrmann 	set_bit(ABS_HAT0X, wdata->ir->absbit);
1122192a1acfSDavid Herrmann 	set_bit(ABS_HAT0Y, wdata->ir->absbit);
1123192a1acfSDavid Herrmann 	set_bit(ABS_HAT1X, wdata->ir->absbit);
1124192a1acfSDavid Herrmann 	set_bit(ABS_HAT1Y, wdata->ir->absbit);
1125192a1acfSDavid Herrmann 	set_bit(ABS_HAT2X, wdata->ir->absbit);
1126192a1acfSDavid Herrmann 	set_bit(ABS_HAT2Y, wdata->ir->absbit);
1127192a1acfSDavid Herrmann 	set_bit(ABS_HAT3X, wdata->ir->absbit);
1128192a1acfSDavid Herrmann 	set_bit(ABS_HAT3Y, wdata->ir->absbit);
1129192a1acfSDavid Herrmann 	input_set_abs_params(wdata->ir, ABS_HAT0X, 0, 1023, 2, 4);
1130192a1acfSDavid Herrmann 	input_set_abs_params(wdata->ir, ABS_HAT0Y, 0, 767, 2, 4);
1131192a1acfSDavid Herrmann 	input_set_abs_params(wdata->ir, ABS_HAT1X, 0, 1023, 2, 4);
1132192a1acfSDavid Herrmann 	input_set_abs_params(wdata->ir, ABS_HAT1Y, 0, 767, 2, 4);
1133192a1acfSDavid Herrmann 	input_set_abs_params(wdata->ir, ABS_HAT2X, 0, 1023, 2, 4);
1134192a1acfSDavid Herrmann 	input_set_abs_params(wdata->ir, ABS_HAT2Y, 0, 767, 2, 4);
1135192a1acfSDavid Herrmann 	input_set_abs_params(wdata->ir, ABS_HAT3X, 0, 1023, 2, 4);
1136192a1acfSDavid Herrmann 	input_set_abs_params(wdata->ir, ABS_HAT3Y, 0, 767, 2, 4);
1137192a1acfSDavid Herrmann 
1138192a1acfSDavid Herrmann 	spin_lock_init(&wdata->qlock);
1139192a1acfSDavid Herrmann 	INIT_WORK(&wdata->worker, wiimote_worker);
1140192a1acfSDavid Herrmann 
1141192a1acfSDavid Herrmann 	spin_lock_init(&wdata->state.lock);
1142192a1acfSDavid Herrmann 	init_completion(&wdata->state.ready);
1143192a1acfSDavid Herrmann 	mutex_init(&wdata->state.sync);
1144192a1acfSDavid Herrmann 
1145192a1acfSDavid Herrmann 	return wdata;
1146192a1acfSDavid Herrmann 
1147192a1acfSDavid Herrmann err_ir:
1148192a1acfSDavid Herrmann 	input_free_device(wdata->accel);
1149192a1acfSDavid Herrmann err_input:
1150192a1acfSDavid Herrmann 	input_free_device(wdata->input);
1151192a1acfSDavid Herrmann err:
1152192a1acfSDavid Herrmann 	kfree(wdata);
1153192a1acfSDavid Herrmann 	return NULL;
1154192a1acfSDavid Herrmann }
1155192a1acfSDavid Herrmann 
1156192a1acfSDavid Herrmann static void wiimote_destroy(struct wiimote_data *wdata)
1157192a1acfSDavid Herrmann {
115843e5e7c6SDavid Herrmann 	wiidebug_deinit(wdata);
1159cb99221bSDavid Herrmann 	wiiext_deinit(wdata);
1160192a1acfSDavid Herrmann 	wiimote_leds_destroy(wdata);
1161192a1acfSDavid Herrmann 
1162192a1acfSDavid Herrmann 	power_supply_unregister(&wdata->battery);
1163192a1acfSDavid Herrmann 	input_unregister_device(wdata->accel);
1164192a1acfSDavid Herrmann 	input_unregister_device(wdata->ir);
1165192a1acfSDavid Herrmann 	input_unregister_device(wdata->input);
1166192a1acfSDavid Herrmann 	cancel_work_sync(&wdata->worker);
1167192a1acfSDavid Herrmann 	hid_hw_stop(wdata->hdev);
1168192a1acfSDavid Herrmann 
1169192a1acfSDavid Herrmann 	kfree(wdata);
1170192a1acfSDavid Herrmann }
1171192a1acfSDavid Herrmann 
1172192a1acfSDavid Herrmann static int wiimote_hid_probe(struct hid_device *hdev,
1173192a1acfSDavid Herrmann 				const struct hid_device_id *id)
1174192a1acfSDavid Herrmann {
1175192a1acfSDavid Herrmann 	struct wiimote_data *wdata;
1176192a1acfSDavid Herrmann 	int ret;
1177192a1acfSDavid Herrmann 
1178192a1acfSDavid Herrmann 	wdata = wiimote_create(hdev);
1179192a1acfSDavid Herrmann 	if (!wdata) {
1180192a1acfSDavid Herrmann 		hid_err(hdev, "Can't alloc device\n");
1181192a1acfSDavid Herrmann 		return -ENOMEM;
1182192a1acfSDavid Herrmann 	}
1183192a1acfSDavid Herrmann 
1184192a1acfSDavid Herrmann 	ret = hid_parse(hdev);
1185192a1acfSDavid Herrmann 	if (ret) {
1186192a1acfSDavid Herrmann 		hid_err(hdev, "HID parse failed\n");
1187192a1acfSDavid Herrmann 		goto err;
1188192a1acfSDavid Herrmann 	}
1189192a1acfSDavid Herrmann 
1190192a1acfSDavid Herrmann 	ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
1191192a1acfSDavid Herrmann 	if (ret) {
1192192a1acfSDavid Herrmann 		hid_err(hdev, "HW start failed\n");
1193192a1acfSDavid Herrmann 		goto err;
1194192a1acfSDavid Herrmann 	}
1195192a1acfSDavid Herrmann 
1196192a1acfSDavid Herrmann 	ret = input_register_device(wdata->accel);
1197192a1acfSDavid Herrmann 	if (ret) {
1198192a1acfSDavid Herrmann 		hid_err(hdev, "Cannot register input device\n");
1199192a1acfSDavid Herrmann 		goto err_stop;
1200192a1acfSDavid Herrmann 	}
1201192a1acfSDavid Herrmann 
1202192a1acfSDavid Herrmann 	ret = input_register_device(wdata->ir);
1203192a1acfSDavid Herrmann 	if (ret) {
1204192a1acfSDavid Herrmann 		hid_err(hdev, "Cannot register input device\n");
1205192a1acfSDavid Herrmann 		goto err_ir;
1206192a1acfSDavid Herrmann 	}
1207192a1acfSDavid Herrmann 
1208192a1acfSDavid Herrmann 	ret = input_register_device(wdata->input);
1209192a1acfSDavid Herrmann 	if (ret) {
1210192a1acfSDavid Herrmann 		hid_err(hdev, "Cannot register input device\n");
1211192a1acfSDavid Herrmann 		goto err_input;
1212192a1acfSDavid Herrmann 	}
1213192a1acfSDavid Herrmann 
1214192a1acfSDavid Herrmann 	wdata->battery.properties = wiimote_battery_props;
1215192a1acfSDavid Herrmann 	wdata->battery.num_properties = ARRAY_SIZE(wiimote_battery_props);
1216192a1acfSDavid Herrmann 	wdata->battery.get_property = wiimote_battery_get_property;
1217192a1acfSDavid Herrmann 	wdata->battery.name = "wiimote_battery";
1218192a1acfSDavid Herrmann 	wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
1219192a1acfSDavid Herrmann 	wdata->battery.use_for_apm = 0;
1220192a1acfSDavid Herrmann 
1221192a1acfSDavid Herrmann 	ret = power_supply_register(&wdata->hdev->dev, &wdata->battery);
1222192a1acfSDavid Herrmann 	if (ret) {
1223192a1acfSDavid Herrmann 		hid_err(hdev, "Cannot register battery device\n");
1224192a1acfSDavid Herrmann 		goto err_battery;
1225192a1acfSDavid Herrmann 	}
1226192a1acfSDavid Herrmann 
1227192a1acfSDavid Herrmann 	ret = wiimote_leds_create(wdata);
1228192a1acfSDavid Herrmann 	if (ret)
1229192a1acfSDavid Herrmann 		goto err_free;
1230192a1acfSDavid Herrmann 
1231cb99221bSDavid Herrmann 	ret = wiiext_init(wdata);
1232cb99221bSDavid Herrmann 	if (ret)
1233cb99221bSDavid Herrmann 		goto err_free;
1234cb99221bSDavid Herrmann 
123543e5e7c6SDavid Herrmann 	ret = wiidebug_init(wdata);
123643e5e7c6SDavid Herrmann 	if (ret)
123743e5e7c6SDavid Herrmann 		goto err_free;
123843e5e7c6SDavid Herrmann 
1239192a1acfSDavid Herrmann 	hid_info(hdev, "New device registered\n");
1240192a1acfSDavid Herrmann 
1241192a1acfSDavid Herrmann 	/* by default set led1 after device initialization */
1242192a1acfSDavid Herrmann 	spin_lock_irq(&wdata->state.lock);
1243192a1acfSDavid Herrmann 	wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1);
1244192a1acfSDavid Herrmann 	spin_unlock_irq(&wdata->state.lock);
1245192a1acfSDavid Herrmann 
1246192a1acfSDavid Herrmann 	return 0;
1247192a1acfSDavid Herrmann 
1248192a1acfSDavid Herrmann err_free:
1249192a1acfSDavid Herrmann 	wiimote_destroy(wdata);
1250192a1acfSDavid Herrmann 	return ret;
1251192a1acfSDavid Herrmann 
1252192a1acfSDavid Herrmann err_battery:
1253192a1acfSDavid Herrmann 	input_unregister_device(wdata->input);
1254192a1acfSDavid Herrmann 	wdata->input = NULL;
1255192a1acfSDavid Herrmann err_input:
1256192a1acfSDavid Herrmann 	input_unregister_device(wdata->ir);
1257192a1acfSDavid Herrmann 	wdata->ir = NULL;
1258192a1acfSDavid Herrmann err_ir:
1259192a1acfSDavid Herrmann 	input_unregister_device(wdata->accel);
1260192a1acfSDavid Herrmann 	wdata->accel = NULL;
1261192a1acfSDavid Herrmann err_stop:
1262192a1acfSDavid Herrmann 	hid_hw_stop(hdev);
1263192a1acfSDavid Herrmann err:
1264192a1acfSDavid Herrmann 	input_free_device(wdata->ir);
1265192a1acfSDavid Herrmann 	input_free_device(wdata->accel);
1266192a1acfSDavid Herrmann 	input_free_device(wdata->input);
1267192a1acfSDavid Herrmann 	kfree(wdata);
1268192a1acfSDavid Herrmann 	return ret;
1269192a1acfSDavid Herrmann }
1270192a1acfSDavid Herrmann 
1271192a1acfSDavid Herrmann static void wiimote_hid_remove(struct hid_device *hdev)
1272192a1acfSDavid Herrmann {
1273192a1acfSDavid Herrmann 	struct wiimote_data *wdata = hid_get_drvdata(hdev);
1274192a1acfSDavid Herrmann 
1275192a1acfSDavid Herrmann 	hid_info(hdev, "Device removed\n");
1276192a1acfSDavid Herrmann 	wiimote_destroy(wdata);
1277192a1acfSDavid Herrmann }
1278192a1acfSDavid Herrmann 
1279192a1acfSDavid Herrmann static const struct hid_device_id wiimote_hid_devices[] = {
1280192a1acfSDavid Herrmann 	{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
1281192a1acfSDavid Herrmann 				USB_DEVICE_ID_NINTENDO_WIIMOTE) },
1282192a1acfSDavid Herrmann 	{ }
1283192a1acfSDavid Herrmann };
1284192a1acfSDavid Herrmann MODULE_DEVICE_TABLE(hid, wiimote_hid_devices);
1285192a1acfSDavid Herrmann 
1286192a1acfSDavid Herrmann static struct hid_driver wiimote_hid_driver = {
1287192a1acfSDavid Herrmann 	.name = "wiimote",
1288192a1acfSDavid Herrmann 	.id_table = wiimote_hid_devices,
1289192a1acfSDavid Herrmann 	.probe = wiimote_hid_probe,
1290192a1acfSDavid Herrmann 	.remove = wiimote_hid_remove,
1291192a1acfSDavid Herrmann 	.raw_event = wiimote_hid_event,
1292192a1acfSDavid Herrmann };
1293192a1acfSDavid Herrmann 
1294192a1acfSDavid Herrmann static int __init wiimote_init(void)
1295192a1acfSDavid Herrmann {
1296192a1acfSDavid Herrmann 	int ret;
1297192a1acfSDavid Herrmann 
1298192a1acfSDavid Herrmann 	ret = hid_register_driver(&wiimote_hid_driver);
1299192a1acfSDavid Herrmann 	if (ret)
1300192a1acfSDavid Herrmann 		pr_err("Can't register wiimote hid driver\n");
1301192a1acfSDavid Herrmann 
1302192a1acfSDavid Herrmann 	return ret;
1303192a1acfSDavid Herrmann }
1304192a1acfSDavid Herrmann 
1305192a1acfSDavid Herrmann static void __exit wiimote_exit(void)
1306192a1acfSDavid Herrmann {
1307192a1acfSDavid Herrmann 	hid_unregister_driver(&wiimote_hid_driver);
1308192a1acfSDavid Herrmann }
1309192a1acfSDavid Herrmann 
1310192a1acfSDavid Herrmann module_init(wiimote_init);
1311192a1acfSDavid Herrmann module_exit(wiimote_exit);
1312192a1acfSDavid Herrmann MODULE_LICENSE("GPL");
1313192a1acfSDavid Herrmann MODULE_AUTHOR("David Herrmann <dh.herrmann@gmail.com>");
1314192a1acfSDavid Herrmann MODULE_DESCRIPTION(WIIMOTE_NAME " Device Driver");
1315192a1acfSDavid Herrmann MODULE_VERSION(WIIMOTE_VERSION);
1316