Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 256823
b: refs/heads/master
c: 23c063c
h: refs/heads/master
i:
  256821: edc9820
  256819: af8d05e
  256815: f6029c7
v: v3
  • Loading branch information
David Herrmann authored and Jiri Kosina committed Jul 11, 2011
1 parent e31abe8 commit 257047e
Show file tree
Hide file tree
Showing 2 changed files with 79 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 0c218f14487fd67e60059458c48b43cc3d36b96e
refs/heads/master: 23c063cb02b69244bbc215cb81c2cad0208fbecf
78 changes: 78 additions & 0 deletions trunk/drivers/hid/hid-wiimote.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,28 @@
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include "hid-ids.h"

#define WIIMOTE_VERSION "0.1"
#define WIIMOTE_NAME "Nintendo Wii Remote"
#define WIIMOTE_BUFSIZE 32

struct wiimote_buf {
__u8 data[HID_MAX_BUFFER_SIZE];
size_t size;
};

struct wiimote_data {
atomic_t ready;
struct hid_device *hdev;
struct input_dev *input;

spinlock_t qlock;
__u8 head;
__u8 tail;
struct wiimote_buf outq[WIIMOTE_BUFSIZE];
struct work_struct worker;
};

static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
Expand All @@ -45,6 +58,65 @@ static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
return ret;
}

static void wiimote_worker(struct work_struct *work)
{
struct wiimote_data *wdata = container_of(work, struct wiimote_data,
worker);
unsigned long flags;

spin_lock_irqsave(&wdata->qlock, flags);

while (wdata->head != wdata->tail) {
spin_unlock_irqrestore(&wdata->qlock, flags);
wiimote_hid_send(wdata->hdev, wdata->outq[wdata->tail].data,
wdata->outq[wdata->tail].size);
spin_lock_irqsave(&wdata->qlock, flags);

wdata->tail = (wdata->tail + 1) % WIIMOTE_BUFSIZE;
}

spin_unlock_irqrestore(&wdata->qlock, flags);
}

static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
size_t count)
{
unsigned long flags;
__u8 newhead;

if (count > HID_MAX_BUFFER_SIZE) {
hid_warn(wdata->hdev, "Sending too large output report\n");
return;
}

/*
* Copy new request into our output queue and check whether the
* queue is full. If it is full, discard this request.
* If it is empty we need to start a new worker that will
* send out the buffer to the hid device.
* If the queue is not empty, then there must be a worker
* that is currently sending out our buffer and this worker
* will reschedule itself until the queue is empty.
*/

spin_lock_irqsave(&wdata->qlock, flags);

memcpy(wdata->outq[wdata->head].data, buffer, count);
wdata->outq[wdata->head].size = count;
newhead = (wdata->head + 1) % WIIMOTE_BUFSIZE;

if (wdata->head == wdata->tail) {
wdata->head = newhead;
schedule_work(&wdata->worker);
} else if (newhead != wdata->tail) {
wdata->head = newhead;
} else {
hid_warn(wdata->hdev, "Output queue is full");
}

spin_unlock_irqrestore(&wdata->qlock, flags);
}

static int wiimote_input_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
Expand Down Expand Up @@ -100,6 +172,9 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
wdata->input->id.version = wdata->hdev->version;
wdata->input->name = WIIMOTE_NAME;

spin_lock_init(&wdata->qlock);
INIT_WORK(&wdata->worker, wiimote_worker);

return wdata;
}

Expand Down Expand Up @@ -157,8 +232,11 @@ static void wiimote_hid_remove(struct hid_device *hdev)
struct wiimote_data *wdata = hid_get_drvdata(hdev);

hid_info(hdev, "Device removed\n");

hid_hw_stop(hdev);
input_unregister_device(wdata->input);

cancel_work_sync(&wdata->worker);
wiimote_destroy(wdata);
}

Expand Down

0 comments on commit 257047e

Please sign in to comment.