HID: wiimote: Add extension initializer stubs
[deliverable/linux.git] / drivers / hid / hid-wiimote-ext.c
1 /*
2 * HID driver for Nintendo Wiimote extension 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/atomic.h>
14 #include <linux/module.h>
15 #include <linux/spinlock.h>
16 #include <linux/workqueue.h>
17 #include "hid-wiimote.h"
18
19 struct wiimote_ext {
20 struct wiimote_data *wdata;
21 struct work_struct worker;
22
23 atomic_t opened;
24 atomic_t mp_opened;
25 bool plugged;
26 bool motionp;
27 __u8 ext_type;
28 };
29
30 enum wiiext_type {
31 WIIEXT_NONE, /* placeholder */
32 WIIEXT_CLASSIC, /* Nintendo classic controller */
33 WIIEXT_NUNCHUCK, /* Nintendo nunchuck controller */
34 };
35
36 /* diable all extensions */
37 static void ext_disable(struct wiimote_ext *ext)
38 {
39 unsigned long flags;
40
41 spin_lock_irqsave(&ext->wdata->state.lock, flags);
42 ext->motionp = false;
43 ext->ext_type = WIIEXT_NONE;
44 spin_unlock_irqrestore(&ext->wdata->state.lock, flags);
45 }
46
47 static bool motionp_read(struct wiimote_ext *ext)
48 {
49 return false;
50 }
51
52 static __u8 ext_read(struct wiimote_ext *ext)
53 {
54 return WIIEXT_NONE;
55 }
56
57 static void ext_enable(struct wiimote_ext *ext, bool motionp, __u8 ext_type)
58 {
59 unsigned long flags;
60
61 spin_lock_irqsave(&ext->wdata->state.lock, flags);
62 ext->motionp = motionp;
63 ext->ext_type = ext_type;
64 spin_unlock_irqrestore(&ext->wdata->state.lock, flags);
65 }
66
67 static void wiiext_worker(struct work_struct *work)
68 {
69 struct wiimote_ext *ext = container_of(work, struct wiimote_ext,
70 worker);
71 bool motionp;
72 __u8 ext_type;
73
74 ext_disable(ext);
75 motionp = motionp_read(ext);
76 ext_type = ext_read(ext);
77 ext_enable(ext, motionp, ext_type);
78 }
79
80 /* schedule work only once, otherwise mark for reschedule */
81 static void wiiext_schedule(struct wiimote_ext *ext)
82 {
83 queue_work(system_nrt_wq, &ext->worker);
84 }
85
86 /*
87 * Reacts on extension port events
88 * Whenever the driver gets an event from the wiimote that an extension has been
89 * plugged or unplugged, this funtion shall be called. It checks what extensions
90 * are connected and initializes and activates them.
91 * This can be called in atomic context. The initialization is done in a
92 * separate worker thread. The state.lock spinlock must be held by the caller.
93 */
94 void wiiext_event(struct wiimote_data *wdata, bool plugged)
95 {
96 if (!wdata->ext)
97 return;
98
99 if (wdata->ext->plugged == plugged)
100 return;
101
102 wdata->ext->plugged = plugged;
103 /*
104 * We need to call wiiext_schedule(wdata->ext) here, however, the
105 * extension initialization logic is not fully understood and so
106 * automatic initialization is not supported, yet.
107 */
108 }
109
110 /*
111 * Returns true if the current DRM mode should contain extension data and false
112 * if there is no interest in extension data.
113 * All supported extensions send 6 byte extension data so any DRM that contains
114 * extension bytes is fine.
115 * The caller must hold the state.lock spinlock.
116 */
117 bool wiiext_active(struct wiimote_data *wdata)
118 {
119 if (!wdata->ext)
120 return false;
121
122 return wdata->ext->motionp || wdata->ext->ext_type;
123 }
124
125 /* Initializes the extension driver of a wiimote */
126 int wiiext_init(struct wiimote_data *wdata)
127 {
128 struct wiimote_ext *ext;
129 unsigned long flags;
130
131 ext = kzalloc(sizeof(*ext), GFP_KERNEL);
132 if (!ext)
133 return -ENOMEM;
134
135 ext->wdata = wdata;
136 INIT_WORK(&ext->worker, wiiext_worker);
137
138 spin_lock_irqsave(&wdata->state.lock, flags);
139 wdata->ext = ext;
140 spin_unlock_irqrestore(&wdata->state.lock, flags);
141
142 return 0;
143 }
144
145 /* Deinitializes the extension driver of a wiimote */
146 void wiiext_deinit(struct wiimote_data *wdata)
147 {
148 struct wiimote_ext *ext = wdata->ext;
149 unsigned long flags;
150
151 if (!ext)
152 return;
153
154 /*
155 * We first unset wdata->ext to avoid further input from the wiimote
156 * core. The worker thread does not access this pointer so it is not
157 * affected by this.
158 * We kill the worker after this so it does not get respawned during
159 * deinitialization.
160 */
161
162 spin_lock_irqsave(&wdata->state.lock, flags);
163 wdata->ext = NULL;
164 spin_unlock_irqrestore(&wdata->state.lock, flags);
165
166 cancel_work_sync(&ext->worker);
167 kfree(ext);
168 }
This page took 0.036792 seconds and 6 git commands to generate.