aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/hid/hid-sony.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2013-11-27 20:41:54 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2013-11-27 20:41:54 -0800
commitba33fef0f62a97e1faf285a5ee2bcad85622f4fd (patch)
tree20cfba3b21a8edaffc118958cc0a1d7f746ac3cb /drivers/hid/hid-sony.c
parentMerge tag 'pm+acpi-3.13-rc2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm (diff)
parentHID: uhid: fix leak for 64/32 UHID_CREATE (diff)
downloadlinux-dev-ba33fef0f62a97e1faf285a5ee2bcad85622f4fd.tar.xz
linux-dev-ba33fef0f62a97e1faf285a5ee2bcad85622f4fd.zip
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid
Pull HID fixes from Jiri Kosina: - fix compat ioctl leak in uhid, by David Herrmann - fix scheduling in atomic context (causing actual lockups in real world) in hid-sony driver, by Sven Eckelmann - revert patch introducing VID/PID conflict, by Jiri Kosina - support from various new device IDs by Benjamin Tissoires and KaiChung Cheng * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: HID: uhid: fix leak for 64/32 UHID_CREATE HID: kye: fix unresponsive keyboard HID: kye: Add report fixup for Genius Manticore Keyboard HID: multicouh: add PID VID to support 1 new Wistron optical touch device HID: appleir: force input to be set Revert "HID: wiimote: add LEGO-wiimote VID" HID: sony: Send FF commands in non-atomic context
Diffstat (limited to 'drivers/hid/hid-sony.c')
-rw-r--r--drivers/hid/hid-sony.c53
1 files changed, 42 insertions, 11 deletions
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index da551d113762..098af2f84b8c 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -225,6 +225,13 @@ static const unsigned int buzz_keymap[] = {
struct sony_sc {
unsigned long quirks;
+#ifdef CONFIG_SONY_FF
+ struct work_struct rumble_worker;
+ struct hid_device *hdev;
+ __u8 left;
+ __u8 right;
+#endif
+
void *extra;
};
@@ -615,9 +622,9 @@ static void buzz_remove(struct hid_device *hdev)
}
#ifdef CONFIG_SONY_FF
-static int sony_play_effect(struct input_dev *dev, void *data,
- struct ff_effect *effect)
+static void sony_rumble_worker(struct work_struct *work)
{
+ struct sony_sc *sc = container_of(work, struct sony_sc, rumble_worker);
unsigned char buf[] = {
0x01,
0x00, 0xff, 0x00, 0xff, 0x00,
@@ -628,21 +635,28 @@ static int sony_play_effect(struct input_dev *dev, void *data,
0xff, 0x27, 0x10, 0x00, 0x32,
0x00, 0x00, 0x00, 0x00, 0x00
};
- __u8 left;
- __u8 right;
+
+ buf[3] = sc->right;
+ buf[5] = sc->left;
+
+ sc->hdev->hid_output_raw_report(sc->hdev, buf, sizeof(buf),
+ HID_OUTPUT_REPORT);
+}
+
+static int sony_play_effect(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
struct hid_device *hid = input_get_drvdata(dev);
+ struct sony_sc *sc = hid_get_drvdata(hid);
if (effect->type != FF_RUMBLE)
return 0;
- left = effect->u.rumble.strong_magnitude / 256;
- right = effect->u.rumble.weak_magnitude ? 1 : 0;
-
- buf[3] = right;
- buf[5] = left;
+ sc->left = effect->u.rumble.strong_magnitude / 256;
+ sc->right = effect->u.rumble.weak_magnitude ? 1 : 0;
- return hid->hid_output_raw_report(hid, buf, sizeof(buf),
- HID_OUTPUT_REPORT);
+ schedule_work(&sc->rumble_worker);
+ return 0;
}
static int sony_init_ff(struct hid_device *hdev)
@@ -650,16 +664,31 @@ static int sony_init_ff(struct hid_device *hdev)
struct hid_input *hidinput = list_entry(hdev->inputs.next,
struct hid_input, list);
struct input_dev *input_dev = hidinput->input;
+ struct sony_sc *sc = hid_get_drvdata(hdev);
+
+ sc->hdev = hdev;
+ INIT_WORK(&sc->rumble_worker, sony_rumble_worker);
input_set_capability(input_dev, EV_FF, FF_RUMBLE);
return input_ff_create_memless(input_dev, NULL, sony_play_effect);
}
+static void sony_destroy_ff(struct hid_device *hdev)
+{
+ struct sony_sc *sc = hid_get_drvdata(hdev);
+
+ cancel_work_sync(&sc->rumble_worker);
+}
+
#else
static int sony_init_ff(struct hid_device *hdev)
{
return 0;
}
+
+static void sony_destroy_ff(struct hid_device *hdev)
+{
+}
#endif
static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
@@ -728,6 +757,8 @@ static void sony_remove(struct hid_device *hdev)
if (sc->quirks & BUZZ_CONTROLLER)
buzz_remove(hdev);
+ sony_destroy_ff(hdev);
+
hid_hw_stop(hdev);
}