* [PATCH 0/7] New wiimote interface
@ 2011-08-13 13:29 David Herrmann
2011-08-13 13:29 ` [PATCH 1/7] HID: wiimote: Simplify synchronization David Herrmann
` (6 more replies)
0 siblings, 7 replies; 10+ messages in thread
From: David Herrmann @ 2011-08-13 13:29 UTC (permalink / raw)
To: linux-input; +Cc: dh.herrmann, padovan, jkosina, oliver
Hi
As discussed on the ML, this adds a new interface for LED and rumble devices on
the wiimote. LED devices can now be controlled via led_classdev structure and
the rumble motor is controlled via force-feedback FF_RUMBLE event.
Based on the new semaphore-lock this also simplifies the locking to reduce
overhead and code complexity.
The last two patches correctly set DRM modes on new events. Currently, if an
extension is plugged into the wiimote, this driver stops working. Those two
patches make the driver reset the DRM so it still works with extensions plugged
in. Hence, it would be nice to see them in 3.1, too.
I have omitted the accelerometer/IR/extension etc. patches since they probably
don't go into 3.1 and I will resend them later after more testing.
Regards
David
David Herrmann (7):
HID: wiimote: Simplify synchronization
HID: wiimote: Correctly call HID open/close callbacks
HID: wiimote: Register led class devices
HID: wiimote: Support rumble device
HID: wiimote: Add force-feedback support
HID: wiimote: Add drm request
HID: wiimote: Add status and return request handlers
drivers/hid/Kconfig | 1 +
drivers/hid/hid-wiimote.c | 345 ++++++++++++++++++++++++++++++++++++---------
2 files changed, 276 insertions(+), 70 deletions(-)
--
1.7.6
^ permalink raw reply [flat|nested] 10+ messages in thread
* [PATCH 1/7] HID: wiimote: Simplify synchronization
2011-08-13 13:29 [PATCH 0/7] New wiimote interface David Herrmann
@ 2011-08-13 13:29 ` David Herrmann
2011-08-14 10:55 ` Oliver Neukum
2011-08-13 13:29 ` [PATCH 2/7] HID: wiimote: Correctly call HID open/close callbacks David Herrmann
` (5 subsequent siblings)
6 siblings, 1 reply; 10+ messages in thread
From: David Herrmann @ 2011-08-13 13:29 UTC (permalink / raw)
To: linux-input; +Cc: dh.herrmann, padovan, jkosina, oliver
The new locking scheme in HID core allows us to remove a bit of synchronization.
Since the HID layer acts synchronously we simply register input core last and
there are no synchonization issues anymore.
Also register sysfs files last to simply the code.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/hid/hid-wiimote.c | 77 ++++++++++++++++-----------------------------
1 files changed, 27 insertions(+), 50 deletions(-)
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index a594383..1e9c39d 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -33,7 +33,6 @@ struct wiimote_state {
};
struct wiimote_data {
- atomic_t ready;
struct hid_device *hdev;
struct input_dev *input;
@@ -200,9 +199,6 @@ static ssize_t wiifs_led_show_##num(struct device *dev, \
unsigned long flags; \
int state; \
\
- if (!atomic_read(&wdata->ready)) \
- return -EBUSY; \
- \
spin_lock_irqsave(&wdata->state.lock, flags); \
state = !!(wdata->state.flags & WIIPROTO_FLAG_LED##num); \
spin_unlock_irqrestore(&wdata->state.lock, flags); \
@@ -217,9 +213,6 @@ static ssize_t wiifs_led_set_##num(struct device *dev, \
unsigned long flags; \
__u8 state; \
\
- if (!atomic_read(&wdata->ready)) \
- return -EBUSY; \
- \
spin_lock_irqsave(&wdata->state.lock, flags); \
\
state = wdata->state.flags; \
@@ -244,13 +237,6 @@ wiifs_led_show_set(4);
static int wiimote_input_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
- struct wiimote_data *wdata = input_get_drvdata(dev);
-
- if (!atomic_read(&wdata->ready))
- return -EBUSY;
- /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
- smp_rmb();
-
return 0;
}
@@ -300,11 +286,6 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
int i;
unsigned long flags;
- if (!atomic_read(&wdata->ready))
- return -EBUSY;
- /* smp_rmb: Make sure wdata->xy is available when wdata->ready is 1 */
- smp_rmb();
-
if (size < 1)
return -EINVAL;
@@ -362,6 +343,15 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
static void wiimote_destroy(struct wiimote_data *wdata)
{
+ device_remove_file(&wdata->hdev->dev, &dev_attr_led1);
+ device_remove_file(&wdata->hdev->dev, &dev_attr_led2);
+ device_remove_file(&wdata->hdev->dev, &dev_attr_led3);
+ device_remove_file(&wdata->hdev->dev, &dev_attr_led4);
+
+ input_unregister_device(wdata->input);
+ hid_hw_stop(wdata->hdev);
+
+ cancel_work_sync(&wdata->worker);
kfree(wdata);
}
@@ -377,19 +367,6 @@ static int wiimote_hid_probe(struct hid_device *hdev,
return -ENOMEM;
}
- ret = device_create_file(&hdev->dev, &dev_attr_led1);
- if (ret)
- goto err;
- ret = device_create_file(&hdev->dev, &dev_attr_led2);
- if (ret)
- goto err;
- ret = device_create_file(&hdev->dev, &dev_attr_led3);
- if (ret)
- goto err;
- ret = device_create_file(&hdev->dev, &dev_attr_led4);
- if (ret)
- goto err;
-
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "HID parse failed\n");
@@ -408,9 +385,19 @@ static int wiimote_hid_probe(struct hid_device *hdev,
goto err_stop;
}
- /* smp_wmb: Write wdata->xy first before wdata->ready is set to 1 */
- smp_wmb();
- atomic_set(&wdata->ready, 1);
+ ret = device_create_file(&hdev->dev, &dev_attr_led1);
+ if (ret)
+ goto err_free;
+ ret = device_create_file(&hdev->dev, &dev_attr_led2);
+ if (ret)
+ goto err_free;
+ ret = device_create_file(&hdev->dev, &dev_attr_led3);
+ if (ret)
+ goto err_free;
+ ret = device_create_file(&hdev->dev, &dev_attr_led4);
+ if (ret)
+ goto err_free;
+
hid_info(hdev, "New device registered\n");
/* by default set led1 after device initialization */
@@ -420,15 +407,15 @@ static int wiimote_hid_probe(struct hid_device *hdev,
return 0;
+err_free:
+ wiimote_destroy(wdata);
+ return ret;
+
err_stop:
hid_hw_stop(hdev);
err:
input_free_device(wdata->input);
- device_remove_file(&hdev->dev, &dev_attr_led1);
- device_remove_file(&hdev->dev, &dev_attr_led2);
- device_remove_file(&hdev->dev, &dev_attr_led3);
- device_remove_file(&hdev->dev, &dev_attr_led4);
- wiimote_destroy(wdata);
+ kfree(wdata);
return ret;
}
@@ -437,16 +424,6 @@ static void wiimote_hid_remove(struct hid_device *hdev)
struct wiimote_data *wdata = hid_get_drvdata(hdev);
hid_info(hdev, "Device removed\n");
-
- device_remove_file(&hdev->dev, &dev_attr_led1);
- device_remove_file(&hdev->dev, &dev_attr_led2);
- device_remove_file(&hdev->dev, &dev_attr_led3);
- device_remove_file(&hdev->dev, &dev_attr_led4);
-
- hid_hw_stop(hdev);
- input_unregister_device(wdata->input);
-
- cancel_work_sync(&wdata->worker);
wiimote_destroy(wdata);
}
--
1.7.6
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 2/7] HID: wiimote: Correctly call HID open/close callbacks
2011-08-13 13:29 [PATCH 0/7] New wiimote interface David Herrmann
2011-08-13 13:29 ` [PATCH 1/7] HID: wiimote: Simplify synchronization David Herrmann
@ 2011-08-13 13:29 ` David Herrmann
2011-08-13 13:29 ` [PATCH 3/7] HID: wiimote: Register led class devices David Herrmann
` (4 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: David Herrmann @ 2011-08-13 13:29 UTC (permalink / raw)
To: linux-input; +Cc: dh.herrmann, padovan, jkosina, oliver
Even though the bluetooth hid backend does not react on open/close callbacks, we
should call them to be consistent with other hid drivers.
Also the new input open/close handlers will be used in future to prepare the
wiimote device for IR/extension input.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/hid/hid-wiimote.c | 16 ++++++++++++++++
1 files changed, 16 insertions(+), 0 deletions(-)
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 1e9c39d..c9793c8 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -240,6 +240,20 @@ static int wiimote_input_event(struct input_dev *dev, unsigned int type,
return 0;
}
+static int wiimote_input_open(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+
+ return hid_hw_open(wdata->hdev);
+}
+
+static void wiimote_input_close(struct input_dev *dev)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+
+ hid_hw_close(wdata->hdev);
+}
+
static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
{
input_report_key(wdata->input, wiiproto_keymap[WIIPROTO_KEY_LEFT],
@@ -322,6 +336,8 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
input_set_drvdata(wdata->input, wdata);
wdata->input->event = wiimote_input_event;
+ wdata->input->open = wiimote_input_open;
+ wdata->input->close = wiimote_input_close;
wdata->input->dev.parent = &wdata->hdev->dev;
wdata->input->id.bustype = wdata->hdev->bus;
wdata->input->id.vendor = wdata->hdev->vendor;
--
1.7.6
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 3/7] HID: wiimote: Register led class devices
2011-08-13 13:29 [PATCH 0/7] New wiimote interface David Herrmann
2011-08-13 13:29 ` [PATCH 1/7] HID: wiimote: Simplify synchronization David Herrmann
2011-08-13 13:29 ` [PATCH 2/7] HID: wiimote: Correctly call HID open/close callbacks David Herrmann
@ 2011-08-13 13:29 ` David Herrmann
2011-08-13 13:29 ` [PATCH 4/7] HID: wiimote: Support rumble device David Herrmann
` (3 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: David Herrmann @ 2011-08-13 13:29 UTC (permalink / raw)
To: linux-input; +Cc: dh.herrmann, padovan, jkosina, oliver
This registers 4 led devices to allow controlling the wiimote leds via standard
LED sysfs API.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/hid/Kconfig | 1 +
drivers/hid/hid-wiimote.c | 130 +++++++++++++++++++++++++++++++++++++++-----
2 files changed, 116 insertions(+), 15 deletions(-)
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 306b15f..1130a89 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -589,6 +589,7 @@ config HID_WACOM_POWER_SUPPLY
config HID_WIIMOTE
tristate "Nintendo Wii Remote support"
depends on BT_HIDP
+ depends on LEDS_CLASS
---help---
Support for the Nintendo Wii Remote bluetooth device.
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index c9793c8..466d45d 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -14,6 +14,7 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/input.h>
+#include <linux/leds.h>
#include <linux/module.h>
#include <linux/spinlock.h>
#include "hid-ids.h"
@@ -35,6 +36,7 @@ struct wiimote_state {
struct wiimote_data {
struct hid_device *hdev;
struct input_dev *input;
+ struct led_classdev *leds[4];
spinlock_t qlock;
__u8 head;
@@ -52,6 +54,9 @@ struct wiimote_data {
#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
+/* return flag for led \num */
+#define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1))
+
enum wiiproto_reqs {
WIIPROTO_REQ_LED = 0x11,
WIIPROTO_REQ_DRM_K = 0x30,
@@ -191,17 +196,62 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
wiimote_queue(wdata, cmd, sizeof(cmd));
}
+static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
+{
+ struct wiimote_data *wdata;
+ struct device *dev = led_dev->dev->parent;
+ int i;
+ unsigned long flags;
+ bool value = false;
+
+ wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev) {
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ value = wdata->state.flags & WIIPROTO_FLAG_LED(i + 1);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ break;
+ }
+ }
+
+ return value ? LED_FULL : LED_OFF;
+}
+
+static void wiimote_leds_set(struct led_classdev *led_dev,
+ enum led_brightness value)
+{
+ struct wiimote_data *wdata;
+ struct device *dev = led_dev->dev->parent;
+ int i;
+ unsigned long flags;
+ __u8 state, flag;
+
+ wdata = hid_get_drvdata(container_of(dev, struct hid_device, dev));
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i] == led_dev) {
+ flag = WIIPROTO_FLAG_LED(i + 1);
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ state = wdata->state.flags;
+ if (value == LED_OFF)
+ wiiproto_req_leds(wdata, state & ~flag);
+ else
+ wiiproto_req_leds(wdata, state | flag);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+ break;
+ }
+ }
+}
+
#define wiifs_led_show_set(num) \
static ssize_t wiifs_led_show_##num(struct device *dev, \
struct device_attribute *attr, char *buf) \
{ \
struct wiimote_data *wdata = dev_to_wii(dev); \
- unsigned long flags; \
- int state; \
+ bool state; \
\
- spin_lock_irqsave(&wdata->state.lock, flags); \
- state = !!(wdata->state.flags & WIIPROTO_FLAG_LED##num); \
- spin_unlock_irqrestore(&wdata->state.lock, flags); \
+ state = !(wiimote_leds_get(wdata->leds[num - 1]) == LED_OFF); \
\
return sprintf(buf, "%d\n", state); \
} \
@@ -210,19 +260,11 @@ static ssize_t wiifs_led_set_##num(struct device *dev, \
{ \
struct wiimote_data *wdata = dev_to_wii(dev); \
int tmp = simple_strtoul(buf, NULL, 10); \
- unsigned long flags; \
- __u8 state; \
- \
- spin_lock_irqsave(&wdata->state.lock, flags); \
- \
- state = wdata->state.flags; \
\
if (tmp) \
- wiiproto_req_leds(wdata, state | WIIPROTO_FLAG_LED##num);\
+ wiimote_leds_set(wdata->leds[num - 1], LED_FULL); \
else \
- wiiproto_req_leds(wdata, state & ~WIIPROTO_FLAG_LED##num);\
- \
- spin_unlock_irqrestore(&wdata->state.lock, flags); \
+ wiimote_leds_set(wdata->leds[num - 1], LED_OFF); \
\
return count; \
} \
@@ -316,6 +358,58 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
return 0;
}
+static void wiimote_leds_destroy(struct wiimote_data *wdata)
+{
+ int i;
+ struct led_classdev *led;
+
+ for (i = 0; i < 4; ++i) {
+ if (wdata->leds[i]) {
+ led = wdata->leds[i];
+ wdata->leds[i] = NULL;
+ led_classdev_unregister(led);
+ kfree(led);
+ }
+ }
+}
+
+static int wiimote_leds_create(struct wiimote_data *wdata)
+{
+ int i, ret;
+ struct device *dev = &wdata->hdev->dev;
+ size_t namesz = strlen(dev_name(dev)) + 9;
+ struct led_classdev *led;
+ char *name;
+
+ for (i = 0; i < 4; ++i) {
+ led = kzalloc(sizeof(struct led_classdev) + namesz, GFP_KERNEL);
+ if (!led) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ name = (void*)&led[1];
+ snprintf(name, namesz, "%s:blue:p%d", dev_name(dev), i);
+ led->name = name;
+ led->brightness = 0;
+ led->max_brightness = 1;
+ led->brightness_get = wiimote_leds_get;
+ led->brightness_set = wiimote_leds_set;
+
+ ret = led_classdev_register(dev, led);
+ if (ret) {
+ kfree(led);
+ goto err;
+ }
+ wdata->leds[i] = led;
+ }
+
+ return 0;
+
+err:
+ wiimote_leds_destroy(wdata);
+ return ret;
+}
+
static struct wiimote_data *wiimote_create(struct hid_device *hdev)
{
struct wiimote_data *wdata;
@@ -359,6 +453,8 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
static void wiimote_destroy(struct wiimote_data *wdata)
{
+ wiimote_leds_destroy(wdata);
+
device_remove_file(&wdata->hdev->dev, &dev_attr_led1);
device_remove_file(&wdata->hdev->dev, &dev_attr_led2);
device_remove_file(&wdata->hdev->dev, &dev_attr_led3);
@@ -414,6 +510,10 @@ static int wiimote_hid_probe(struct hid_device *hdev,
if (ret)
goto err_free;
+ ret = wiimote_leds_create(wdata);
+ if (ret)
+ goto err_free;
+
hid_info(hdev, "New device registered\n");
/* by default set led1 after device initialization */
--
1.7.6
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 4/7] HID: wiimote: Support rumble device
2011-08-13 13:29 [PATCH 0/7] New wiimote interface David Herrmann
` (2 preceding siblings ...)
2011-08-13 13:29 ` [PATCH 3/7] HID: wiimote: Register led class devices David Herrmann
@ 2011-08-13 13:29 ` David Herrmann
2011-08-13 13:29 ` [PATCH 5/7] HID: wiimote: Add force-feedback support David Herrmann
` (2 subsequent siblings)
6 siblings, 0 replies; 10+ messages in thread
From: David Herrmann @ 2011-08-13 13:29 UTC (permalink / raw)
To: linux-input; +Cc: dh.herrmann, padovan, jkosina, oliver
This adds support for the wiimote's rumble device. Every output report can
enable and disable the rumble motor. Hence, every output report must look up our
new RUMBLE flag and make sure that it does not unintentionally toggle the
rumble motor.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/hid/hid-wiimote.c | 44 ++++++++++++++++++++++++++++++++++++++++----
1 files changed, 40 insertions(+), 4 deletions(-)
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 466d45d..c18aaaf 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -47,10 +47,11 @@ struct wiimote_data {
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_FLAG_LED1 0x01
+#define WIIPROTO_FLAG_LED2 0x02
+#define WIIPROTO_FLAG_LED3 0x04
+#define WIIPROTO_FLAG_LED4 0x08
+#define WIIPROTO_FLAG_RUMBLE 0x10
#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
@@ -58,6 +59,7 @@ struct wiimote_data {
#define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1))
enum wiiproto_reqs {
+ WIIPROTO_REQ_RUMBLE = 0x10,
WIIPROTO_REQ_LED = 0x11,
WIIPROTO_REQ_DRM_K = 0x30,
};
@@ -172,6 +174,39 @@ static void wiimote_queue(struct wiimote_data *wdata, const __u8 *buffer,
spin_unlock_irqrestore(&wdata->qlock, flags);
}
+/*
+ * This sets the rumble bit on the given output report if rumble is
+ * currently enabled.
+ * \cmd1 must point to the second byte in the output report => &cmd[1]
+ * This must be called on nearly every output report before passing it
+ * into the output queue!
+ */
+static inline void wiiproto_keep_rumble(struct wiimote_data *wdata, __u8 *cmd1)
+{
+ if (wdata->state.flags & WIIPROTO_FLAG_RUMBLE)
+ *cmd1 |= 0x01;
+}
+
+static void wiiproto_req_rumble(struct wiimote_data *wdata, __u8 rumble)
+{
+ __u8 cmd[2];
+
+ rumble = !!rumble;
+ if (rumble == !!(wdata->state.flags & WIIPROTO_FLAG_RUMBLE))
+ return;
+
+ if (rumble)
+ wdata->state.flags |= WIIPROTO_FLAG_RUMBLE;
+ else
+ wdata->state.flags &= ~WIIPROTO_FLAG_RUMBLE;
+
+ cmd[0] = WIIPROTO_REQ_RUMBLE;
+ cmd[1] = 0;
+
+ wiiproto_keep_rumble(wdata, &cmd[1]);
+ wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
{
__u8 cmd[2];
@@ -193,6 +228,7 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
if (leds & WIIPROTO_FLAG_LED4)
cmd[1] |= 0x80;
+ wiiproto_keep_rumble(wdata, &cmd[1]);
wiimote_queue(wdata, cmd, sizeof(cmd));
}
--
1.7.6
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 5/7] HID: wiimote: Add force-feedback support
2011-08-13 13:29 [PATCH 0/7] New wiimote interface David Herrmann
` (3 preceding siblings ...)
2011-08-13 13:29 ` [PATCH 4/7] HID: wiimote: Support rumble device David Herrmann
@ 2011-08-13 13:29 ` David Herrmann
2011-08-13 13:29 ` [PATCH 6/7] HID: wiimote: Add drm request David Herrmann
2011-08-13 13:29 ` [PATCH 7/7] HID: wiimote: Add status and return request handlers David Herrmann
6 siblings, 0 replies; 10+ messages in thread
From: David Herrmann @ 2011-08-13 13:29 UTC (permalink / raw)
To: linux-input; +Cc: dh.herrmann, padovan, jkosina, oliver
The wiimote has a single rumble motor. This adds force feedback support for
wiimote devices with FF_RUMBLE. The rumble motor is very simple and only
supports an on/off switch so no complex ff-effects are supported.
This also removes the event callback that was registered before but unused. The
ff-device overwrites this callback, anyway.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/hid/hid-wiimote.c | 39 ++++++++++++++++++++++++++++++++-------
1 files changed, 32 insertions(+), 7 deletions(-)
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index c18aaaf..4a68565 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -280,6 +280,31 @@ static void wiimote_leds_set(struct led_classdev *led_dev,
}
}
+static int wiimote_ff_play(struct input_dev *dev, void *data,
+ struct ff_effect *eff)
+{
+ struct wiimote_data *wdata = input_get_drvdata(dev);
+ __u8 value;
+ unsigned long flags;
+
+ /*
+ * The wiimote supports only a single rumble motor so if any magnitude
+ * is set to non-zero then we start the rumble motor. If both are set to
+ * zero, we stop the rumble motor.
+ */
+
+ if (eff->u.rumble.strong_magnitude || eff->u.rumble.weak_magnitude)
+ value = 1;
+ else
+ value = 0;
+
+ spin_lock_irqsave(&wdata->state.lock, flags);
+ wiiproto_req_rumble(wdata, value);
+ spin_unlock_irqrestore(&wdata->state.lock, flags);
+
+ return 0;
+}
+
#define wiifs_led_show_set(num) \
static ssize_t wiifs_led_show_##num(struct device *dev, \
struct device_attribute *attr, char *buf) \
@@ -312,12 +337,6 @@ wiifs_led_show_set(2);
wiifs_led_show_set(3);
wiifs_led_show_set(4);
-static int wiimote_input_event(struct input_dev *dev, unsigned int type,
- unsigned int code, int value)
-{
- return 0;
-}
-
static int wiimote_input_open(struct input_dev *dev)
{
struct wiimote_data *wdata = input_get_drvdata(dev);
@@ -465,7 +484,6 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
hid_set_drvdata(hdev, wdata);
input_set_drvdata(wdata->input, wdata);
- wdata->input->event = wiimote_input_event;
wdata->input->open = wiimote_input_open;
wdata->input->close = wiimote_input_close;
wdata->input->dev.parent = &wdata->hdev->dev;
@@ -479,6 +497,13 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
for (i = 0; i < WIIPROTO_KEY_COUNT; ++i)
set_bit(wiiproto_keymap[i], wdata->input->keybit);
+ set_bit(FF_RUMBLE, wdata->input->ffbit);
+ if (input_ff_create_memless(wdata->input, NULL, wiimote_ff_play)) {
+ input_free_device(wdata->input);
+ kfree(wdata);
+ return NULL;
+ }
+
spin_lock_init(&wdata->qlock);
INIT_WORK(&wdata->worker, wiimote_worker);
--
1.7.6
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 6/7] HID: wiimote: Add drm request
2011-08-13 13:29 [PATCH 0/7] New wiimote interface David Herrmann
` (4 preceding siblings ...)
2011-08-13 13:29 ` [PATCH 5/7] HID: wiimote: Add force-feedback support David Herrmann
@ 2011-08-13 13:29 ` David Herrmann
2011-08-13 13:29 ` [PATCH 7/7] HID: wiimote: Add status and return request handlers David Herrmann
6 siblings, 0 replies; 10+ messages in thread
From: David Herrmann @ 2011-08-13 13:29 UTC (permalink / raw)
To: linux-input; +Cc: dh.herrmann, padovan, jkosina, oliver
The wiimote reports data in several data reporting modes (DRM). The DRM
request makes the wiimote send data in the requested drm.
The DRM mode can be set explicitely or can be chosen by the driver. To let
the driver choose the DRM mode, pass WIIPROTO_REQ_NULL placeholder to it. This
is no valid request and is replaced with an appropriate DRM.
Currently, the driver always sets the basic DRM_K mode, but this will be
extended when further peripherals like accelerometer and IR are supported.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/hid/hid-wiimote.c | 27 +++++++++++++++++++++++++++
1 files changed, 27 insertions(+), 0 deletions(-)
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 4a68565..3efc126 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -59,8 +59,10 @@ struct wiimote_data {
#define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1))
enum wiiproto_reqs {
+ WIIPROTO_REQ_NULL = 0x0,
WIIPROTO_REQ_RUMBLE = 0x10,
WIIPROTO_REQ_LED = 0x11,
+ WIIPROTO_REQ_DRM = 0x12,
WIIPROTO_REQ_DRM_K = 0x30,
};
@@ -232,6 +234,31 @@ static void wiiproto_req_leds(struct wiimote_data *wdata, int leds)
wiimote_queue(wdata, cmd, sizeof(cmd));
}
+/*
+ * Check what peripherals of the wiimote are currently
+ * active and select a proper DRM that supports all of
+ * the requested data inputs.
+ */
+static __u8 select_drm(struct wiimote_data *wdata)
+{
+ return WIIPROTO_REQ_DRM_K;
+}
+
+static void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm)
+{
+ __u8 cmd[3];
+
+ if (drm == WIIPROTO_REQ_NULL)
+ drm = select_drm(wdata);
+
+ cmd[0] = WIIPROTO_REQ_DRM;
+ cmd[1] = 0;
+ cmd[2] = drm;
+
+ wiiproto_keep_rumble(wdata, &cmd[1]);
+ wiimote_queue(wdata, cmd, sizeof(cmd));
+}
+
static enum led_brightness wiimote_leds_get(struct led_classdev *led_dev)
{
struct wiimote_data *wdata;
--
1.7.6
^ permalink raw reply related [flat|nested] 10+ messages in thread
* [PATCH 7/7] HID: wiimote: Add status and return request handlers
2011-08-13 13:29 [PATCH 0/7] New wiimote interface David Herrmann
` (5 preceding siblings ...)
2011-08-13 13:29 ` [PATCH 6/7] HID: wiimote: Add drm request David Herrmann
@ 2011-08-13 13:29 ` David Herrmann
6 siblings, 0 replies; 10+ messages in thread
From: David Herrmann @ 2011-08-13 13:29 UTC (permalink / raw)
To: linux-input; +Cc: dh.herrmann, padovan, jkosina, oliver
The wiimote resets the current drm when an extension is plugged in.
Fortunately, it also sends a status report in this situation so we just
reset the drm on every status report to keep the drm consistent.
Also handle return reports from the wiimote which indicate success and
failure of requests that we've sent.
Signed-off-by: David Herrmann <dh.herrmann@googlemail.com>
---
drivers/hid/hid-wiimote.c | 24 ++++++++++++++++++++++++
1 files changed, 24 insertions(+), 0 deletions(-)
diff --git a/drivers/hid/hid-wiimote.c b/drivers/hid/hid-wiimote.c
index 3efc126..65d61fa 100644
--- a/drivers/hid/hid-wiimote.c
+++ b/drivers/hid/hid-wiimote.c
@@ -63,6 +63,8 @@ enum wiiproto_reqs {
WIIPROTO_REQ_RUMBLE = 0x10,
WIIPROTO_REQ_LED = 0x11,
WIIPROTO_REQ_DRM = 0x12,
+ WIIPROTO_REQ_STATUS = 0x20,
+ WIIPROTO_REQ_RETURN = 0x22,
WIIPROTO_REQ_DRM_K = 0x30,
};
@@ -405,6 +407,26 @@ static void handler_keys(struct wiimote_data *wdata, const __u8 *payload)
input_sync(wdata->input);
}
+static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
+{
+ handler_keys(wdata, payload);
+
+ /* on status reports the drm is reset so we need to resend the drm */
+ wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
+}
+
+static void handler_return(struct wiimote_data *wdata, const __u8 *payload)
+{
+ __u8 err = payload[3];
+ __u8 cmd = payload[2];
+
+ handler_keys(wdata, payload);
+
+ if (err)
+ hid_warn(wdata->hdev, "Remote error %hhu on req %hhu\n", err,
+ cmd);
+}
+
struct wiiproto_handler {
__u8 id;
size_t size;
@@ -412,6 +434,8 @@ struct wiiproto_handler {
};
static struct wiiproto_handler handlers[] = {
+ { .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status },
+ { .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
{ .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
{ .id = 0 }
};
--
1.7.6
^ permalink raw reply related [flat|nested] 10+ messages in thread
* Re: [PATCH 1/7] HID: wiimote: Simplify synchronization
2011-08-13 13:29 ` [PATCH 1/7] HID: wiimote: Simplify synchronization David Herrmann
@ 2011-08-14 10:55 ` Oliver Neukum
2011-08-14 11:15 ` David Herrmann
0 siblings, 1 reply; 10+ messages in thread
From: Oliver Neukum @ 2011-08-14 10:55 UTC (permalink / raw)
To: David Herrmann; +Cc: linux-input, padovan, jkosina
Am Samstag, 13. August 2011, 15:29:09 schrieb David Herrmann:
> @@ -362,6 +343,15 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
>
> static void wiimote_destroy(struct wiimote_data *wdata)
> {
> + device_remove_file(&wdata->hdev->dev, &dev_attr_led1);
> + device_remove_file(&wdata->hdev->dev, &dev_attr_led2);
> + device_remove_file(&wdata->hdev->dev, &dev_attr_led3);
> + device_remove_file(&wdata->hdev->dev, &dev_attr_led4);
> +
> + input_unregister_device(wdata->input);
> + hid_hw_stop(wdata->hdev);
> +
> + cancel_work_sync(&wdata->worker);
> kfree(wdata);
> }
This looks like the work can run on a device whose hardware has already been
stopped. Is this safe?
Regards
Oliver
^ permalink raw reply [flat|nested] 10+ messages in thread
* Re: [PATCH 1/7] HID: wiimote: Simplify synchronization
2011-08-14 10:55 ` Oliver Neukum
@ 2011-08-14 11:15 ` David Herrmann
0 siblings, 0 replies; 10+ messages in thread
From: David Herrmann @ 2011-08-14 11:15 UTC (permalink / raw)
To: Oliver Neukum; +Cc: linux-input, padovan, jkosina
On Sun, Aug 14, 2011 at 12:55 PM, Oliver Neukum <oliver@neukum.org> wrote:
> Am Samstag, 13. August 2011, 15:29:09 schrieb David Herrmann:
>> @@ -362,6 +343,15 @@ static struct wiimote_data *wiimote_create(struct hid_device *hdev)
>>
>> static void wiimote_destroy(struct wiimote_data *wdata)
>> {
>> + device_remove_file(&wdata->hdev->dev, &dev_attr_led1);
>> + device_remove_file(&wdata->hdev->dev, &dev_attr_led2);
>> + device_remove_file(&wdata->hdev->dev, &dev_attr_led3);
>> + device_remove_file(&wdata->hdev->dev, &dev_attr_led4);
>> +
>> + input_unregister_device(wdata->input);
>> + hid_hw_stop(wdata->hdev);
>> +
>> + cancel_work_sync(&wdata->worker);
>> kfree(wdata);
>> }
>
> This looks like the work can run on a device whose hardware has already been
> stopped. Is this safe?
With bthid this is safe, although not very nice. usbhid does not allow
this so I will swap the cancel_work_sync() and hid_hw_stop() calls so
I do not depend on special bthid behaviour.
Nice catch, thanks.
> Regards
> Oliver
>
Regards
David
--
To unsubscribe from this list: send the line "unsubscribe linux-input" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply [flat|nested] 10+ messages in thread
end of thread, other threads:[~2011-08-14 11:15 UTC | newest]
Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2011-08-13 13:29 [PATCH 0/7] New wiimote interface David Herrmann
2011-08-13 13:29 ` [PATCH 1/7] HID: wiimote: Simplify synchronization David Herrmann
2011-08-14 10:55 ` Oliver Neukum
2011-08-14 11:15 ` David Herrmann
2011-08-13 13:29 ` [PATCH 2/7] HID: wiimote: Correctly call HID open/close callbacks David Herrmann
2011-08-13 13:29 ` [PATCH 3/7] HID: wiimote: Register led class devices David Herrmann
2011-08-13 13:29 ` [PATCH 4/7] HID: wiimote: Support rumble device David Herrmann
2011-08-13 13:29 ` [PATCH 5/7] HID: wiimote: Add force-feedback support David Herrmann
2011-08-13 13:29 ` [PATCH 6/7] HID: wiimote: Add drm request David Herrmann
2011-08-13 13:29 ` [PATCH 7/7] HID: wiimote: Add status and return request handlers David Herrmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).