aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/hid/hid-wiimote.c78
1 files changed, 78 insertions, 0 deletions
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 811ed8921013..bfc50493ec6b 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -15,15 +15,28 @@
15#include <linux/hid.h> 15#include <linux/hid.h>
16#include <linux/input.h> 16#include <linux/input.h>
17#include <linux/module.h> 17#include <linux/module.h>
18#include <linux/spinlock.h>
18#include "hid-ids.h" 19#include "hid-ids.h"
19 20
20#define WIIMOTE_VERSION "0.1" 21#define WIIMOTE_VERSION "0.1"
21#define WIIMOTE_NAME "Nintendo Wii Remote" 22#define WIIMOTE_NAME "Nintendo Wii Remote"
23#define WIIMOTE_BUFSIZE 32
24
25struct wiimote_buf {
26 __u8 data[HID_MAX_BUFFER_SIZE];
27 size_t size;
28};
22 29
23struct wiimote_data { 30struct wiimote_data {
24 atomic_t ready; 31 atomic_t ready;
25 struct hid_device *hdev; 32 struct hid_device *hdev;
26 struct input_dev *input; 33 struct input_dev *input;
34
35 spinlock_t qlock;
36 __u8 head;
37 __u8 tail;
38 struct wiimote_buf outq[WIIMOTE_BUFSIZE];
39 struct work_struct worker;
27}; 40};
28 41
29static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer, 42static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
@@ -45,6 +58,65 @@ static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
45 return ret; 58 return ret;
46} 59}
47 60
61static void wiimote_worker(struct work_struct *work)
62{
63 struct wiimote_data *wdata = container_of(work, struct wiimote_data,
64 worker);
65 unsigned long flags;
66
67 spin_lock_irqsave(&wdata->qlock, flags);
68
69 while (wdata->head != wdata->tail) {
70 spin_unlock_irqrestore(&wdata->qlock, flags);
71 wiimote_hid_send(wdata->hdev, wdata->outq[wdata->tail].data,
72 wdata->outq[wdata->tail].size);
73 spin_lock_irqsave(&wdata->qlock, flags);
74
75 wdata->tail = (wdata->tail + 1) % WIIMOTE_BUFSIZE;
76 }
77
78 spin_unlock_irqrestore(&wdata->qlock, flags);
79}
80
81static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
82 size_t count)
83{
84 unsigned long flags;
85 __u8 newhead;
86
87 if (count > HID_MAX_BUFFER_SIZE) {
88 hid_warn(wdata->hdev, "Sending too large output report\n");
89 return;
90 }
91
92 /*
93 * Copy new request into our output queue and check whether the
94 * queue is full. If it is full, discard this request.
95 * If it is empty we need to start a new worker that will
96 * send out the buffer to the hid device.
97 * If the queue is not empty, then there must be a worker
98 * that is currently sending out our buffer and this worker
99 * will reschedule itself until the queue is empty.
100 */
101
102 spin_lock_irqsave(&wdata->qlock, flags);
103
104 memcpy(wdata->outq[wdata->head].data, buffer, count);
105 wdata->outq[wdata->head].size = count;
106 newhead = (wdata->head + 1) % WIIMOTE_BUFSIZE;
107
108 if (wdata->head == wdata->tail) {
109 wdata->head = newhead;
110 schedule_work(&wdata->worker);
111 } else if (newhead != wdata->tail) {
112 wdata->head = newhead;
113 } else {
114 hid_warn(wdata->hdev, "Output queue is full");
115 }
116
117 spin_unlock_irqrestore(&wdata->qlock, flags);
118}
119
48static int wiimote_input_event(struct input_dev *dev, unsigned int type, 120static int wiimote_input_event(struct input_dev *dev, unsigned int type,
49 unsigned int code, int value) 121 unsigned int code, int value)
50{ 122{
@@ -100,6 +172,9 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
100 wdata->input->id.version = wdata->hdev->version; 172 wdata->input->id.version = wdata->hdev->version;
101 wdata->input->name = WIIMOTE_NAME; 173 wdata->input->name = WIIMOTE_NAME;
102 174
175 spin_lock_init(&wdata->qlock);
176 INIT_WORK(&wdata->worker, wiimote_worker);
177
103 return wdata; 178 return wdata;
104} 179}
105 180
@@ -157,8 +232,11 @@ static void wiimote_hid_remove(struct hid_device *hdev)
157 struct wiimote_data *wdata = hid_get_drvdata(hdev); 232 struct wiimote_data *wdata = hid_get_drvdata(hdev);
158 233
159 hid_info(hdev, "Device removed\n"); 234 hid_info(hdev, "Device removed\n");
235
160 hid_hw_stop(hdev); 236 hid_hw_stop(hdev);
161 input_unregister_device(wdata->input); 237 input_unregister_device(wdata->input);
238
239 cancel_work_sync(&wdata->worker);
162 wiimote_destroy(wdata); 240 wiimote_destroy(wdata);
163} 241}
164 242