Skip to content

Commit

Permalink
HID: wiimote: Helper functions for synchronous requests
Browse files Browse the repository at this point in the history
To initialize wiimote peripherals, the stream to the wiimote must be held
exclusively by the initializer, otherwise the initialization will fail. Many
initializations require multiple memory requests to be sent synchronously so we
need a way to lock the stream and release it when we are done.

This adds several helper functions which allow to lock the stream, then send
requests, wait for the answers and release the stream again.

When holding the lock, the function may sleep and interrupted by signals.
Also it returns after a short timeout so userspace shouldn't notice long
delays.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
  • Loading branch information
David Herrmann authored and Jiri Kosina committed Sep 7, 2011
1 parent be1ecd6 commit 29d2806
Showing 1 changed file with 56 additions and 0 deletions.
56 changes: 56 additions & 0 deletions drivers/hid/hid-wiimote.c
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,13 @@
* any later version.
*/

#include <linux/completion.h>
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/spinlock.h>
#include "hid-ids.h"

Expand All @@ -31,6 +33,12 @@ struct wiimote_state {
spinlock_t lock;
__u8 flags;
__u8 accel_split[2];

/* synchronous cmd requests */
struct mutex sync;
struct completion ready;
int cmd;
__u32 opt;
};

struct wiimote_data {
Expand Down Expand Up @@ -118,6 +126,52 @@ static __u16 wiiproto_keymap[] = {
BTN_MODE, /* WIIPROTO_KEY_HOME */
};

/* requires the state.lock spinlock to be held */
static inline bool wiimote_cmd_pending(struct wiimote_data *wdata, int cmd,
__u32 opt)
{
return wdata->state.cmd == cmd && wdata->state.opt == opt;
}

/* requires the state.lock spinlock to be held */
static inline void wiimote_cmd_complete(struct wiimote_data *wdata)
{
wdata->state.cmd = WIIPROTO_REQ_NULL;
complete(&wdata->state.ready);
}

static inline int wiimote_cmd_acquire(struct wiimote_data *wdata)
{
return mutex_lock_interruptible(&wdata->state.sync) ? -ERESTARTSYS : 0;
}

/* requires the state.lock spinlock to be held */
static inline void wiimote_cmd_set(struct wiimote_data *wdata, int cmd,
__u32 opt)
{
INIT_COMPLETION(wdata->state.ready);
wdata->state.cmd = cmd;
wdata->state.opt = opt;
}

static inline void wiimote_cmd_release(struct wiimote_data *wdata)
{
mutex_unlock(&wdata->state.sync);
}

static inline int wiimote_cmd_wait(struct wiimote_data *wdata)
{
int ret;

ret = wait_for_completion_interruptible_timeout(&wdata->state.ready, HZ);
if (ret < 0)
return -ERESTARTSYS;
else if (ret == 0)
return -EIO;
else
return 0;
}

static ssize_t wiimote_hid_send(struct hid_device *hdev, __u8 *buffer,
size_t count)
{
Expand Down Expand Up @@ -875,6 +929,8 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
INIT_WORK(&wdata->worker, wiimote_worker);

spin_lock_init(&wdata->state.lock);
init_completion(&wdata->state.ready);
mutex_init(&wdata->state.sync);

return wdata;

Expand Down

0 comments on commit 29d2806

Please sign in to comment.