HID: wiimote: Cache wiimote led state
authorDavid Herrmann <dh.herrmann@googlemail.com>
Tue, 5 Jul 2011 11:45:18 +0000 (13:45 +0200)
committerJiri Kosina <jkosina@suse.cz>
Mon, 11 Jul 2011 12:30:24 +0000 (14:30 +0200)
Save the current state of the leds in the wiimote data structure. This
allows us to discard new led requests that wouldn't change anything.
Protect the whole state structure by a spinlock. Every wiiproto_*
function expects this spinlock to be held when called.

Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
Signed-off-by: Jiri Kosina <jkosina@suse.cz>
drivers/hid/hid-wiimote.c

index 3fb18fbe080cb1ff426438977a95b1c78c480f14..f9a3bcb6b24025c9022cc61ac412f9c36ec81911 100644 (file)
@@ -27,6 +27,11 @@ struct wiimote_buf {
        size_t size;
 };
 
+struct wiimote_state {
+       spinlock_t lock;
+       __u8 flags;
+};
+
 struct wiimote_data {
        atomic_t ready;
        struct hid_device *hdev;
@@ -37,12 +42,16 @@ struct wiimote_data {
        __u8 tail;
        struct wiimote_buf outq[WIIMOTE_BUFSIZE];
        struct work_struct worker;
+
+       struct wiimote_state state;
 };
 
 #define WIIPROTO_FLAG_LED1 0x01
 #define WIIPROTO_FLAG_LED2 0x02
 #define WIIPROTO_FLAG_LED3 0x04
 #define WIIPROTO_FLAG_LED4 0x08
+#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
+                                       WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
 
 enum wiiproto_reqs {
        WIIPROTO_REQ_LED = 0x11,
@@ -160,6 +169,11 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
 {
        __u8 cmd[2];
 
+       leds &= WIIPROTO_FLAGS_LEDS;
+       if ((wdata->state.flags & WIIPROTO_FLAGS_LEDS) == leds)
+               return;
+       wdata->state.flags = (wdata->state.flags & ~WIIPROTO_FLAGS_LEDS) | leds;
+
        cmd[0] = WIIPROTO_REQ_LED;
        cmd[1] = 0;
 
@@ -232,6 +246,7 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
        struct wiimote_data *wdata = hid_get_drvdata(hdev);
        struct wiiproto_handler *h;
        int i;
+       unsigned long flags;
 
        if (!atomic_read(&wdata->ready))
                return -EBUSY;
@@ -241,12 +256,16 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
        if (size < 1)
                return -EINVAL;
 
+       spin_lock_irqsave(&wdata->state.lock, flags);
+
        for (i = 0; handlers[i].id; ++i) {
                h = &handlers[i];
                if (h->id == raw_data[0] && h->size < size)
                        h->func(wdata, &raw_data[1]);
        }
 
+       spin_unlock_irqrestore(&wdata->state.lock, flags);
+
        return 0;
 }
 
@@ -284,6 +303,8 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
        spin_lock_init(&wdata->qlock);
        INIT_WORK(&wdata->worker, wiimote_worker);
 
+       spin_lock_init(&wdata->state.lock);
+
        return wdata;
 }
 
@@ -326,7 +347,12 @@ static int wiimote_hid_probe(struct hid_device *hdev,
        smp_wmb();
        atomic_set(&wdata->ready, 1);
        hid_info(hdev, "New device registered\n");
+
+       /* by default set led1 after device initialization */
+       spin_lock_irq(&wdata->state.lock);
        wiiproto_req_leds(wdata, WIIPROTO_FLAG_LED1);
+       spin_unlock_irq(&wdata->state.lock);
+
        return 0;
 
 err_stop: