diff options
author | Anssi Hannula <anssi.hannula@gmail.com> | 2006-07-19 01:44:17 -0400 |
---|---|---|
committer | Dmitry Torokhov <dtor@insightbb.com> | 2006-07-19 01:44:17 -0400 |
commit | bb3caf7f438a67452f5cf4773ca1bf82260bbbad (patch) | |
tree | 01bcea151929eea5e58bb1591de80eac9be5d617 | |
parent | 1f734cb461e1f029d751deb15c8d9f8137fb2ca7 (diff) | |
download | op-kernel-dev-bb3caf7f438a67452f5cf4773ca1bf82260bbbad.zip op-kernel-dev-bb3caf7f438a67452f5cf4773ca1bf82260bbbad.tar.gz |
Input: add force feedback driver for PSX-style Zeroplus devices
Signed-off-by: Anssi Hannula <anssi.hannula@gmail.com>
Signed-off-by: Dmitry Torokhov <dtor@mail.ru>
-rw-r--r-- | drivers/usb/input/Kconfig | 8 | ||||
-rw-r--r-- | drivers/usb/input/Makefile | 3 | ||||
-rw-r--r-- | drivers/usb/input/hid-ff.c | 4 | ||||
-rw-r--r-- | drivers/usb/input/hid-zpff.c | 110 | ||||
-rw-r--r-- | drivers/usb/input/hid.h | 1 |
5 files changed, 126 insertions, 0 deletions
diff --git a/drivers/usb/input/Kconfig b/drivers/usb/input/Kconfig index 3ca64c3..7ec35c9 100644 --- a/drivers/usb/input/Kconfig +++ b/drivers/usb/input/Kconfig @@ -89,6 +89,14 @@ config THRUSTMASTER_FF Note: if you say N here, this device will still be supported, but without force feedback. +config ZEROPLUS_FF + bool "Zeroplus based game controller support" + depends on HID_FF + select INPUT_FF_MEMLESS if USB_HID + help + Say Y here if you have a Zeroplus based game controller and want to + enable force feedback for it. + config USB_HIDDEV bool "/dev/hiddev raw HID device support" depends on USB_HID diff --git a/drivers/usb/input/Makefile b/drivers/usb/input/Makefile index 84e72dc..affb6a3 100644 --- a/drivers/usb/input/Makefile +++ b/drivers/usb/input/Makefile @@ -22,6 +22,9 @@ endif ifeq ($(CONFIG_THRUSTMASTER_FF),y) usbhid-objs += hid-tmff.o endif +ifeq ($(CONFIG_ZEROPLUS_FF),y) + usbhid-objs += hid-zpff.o +endif ifeq ($(CONFIG_HID_FF),y) usbhid-objs += hid-ff.o endif diff --git a/drivers/usb/input/hid-ff.c b/drivers/usb/input/hid-ff.c index 1b48822..a8fc46c 100644 --- a/drivers/usb/input/hid-ff.c +++ b/drivers/usb/input/hid-ff.c @@ -60,6 +60,10 @@ static struct hid_ff_initializer inits[] = { #ifdef CONFIG_THRUSTMASTER_FF { 0x44f, 0xb304, hid_tmff_init }, #endif +#ifdef CONFIG_ZEROPLUS_FF + { 0xc12, 0x0005, hid_zpff_init }, + { 0xc12, 0x0030, hid_zpff_init }, +#endif { 0, 0, hid_pidff_init} /* Matches anything */ }; diff --git a/drivers/usb/input/hid-zpff.c b/drivers/usb/input/hid-zpff.c new file mode 100644 index 0000000..d2ce321 --- /dev/null +++ b/drivers/usb/input/hid-zpff.c @@ -0,0 +1,110 @@ +/* + * Force feedback support for Zeroplus based devices + * + * Copyright (c) 2005, 2006 Anssi Hannula <anssi.hannula@gmail.com> + */ + +/* + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + */ + + +/* #define DEBUG */ + +#define debug(format, arg...) pr_debug("hid-zpff: " format "\n" , ## arg) + +#include <linux/input.h> +#include <linux/usb.h> +#include "hid.h" + +struct zpff_device { + struct hid_report *report; +}; + +static int hid_zpff_play(struct input_dev *dev, void *data, + struct ff_effect *effect) +{ + struct hid_device *hid = dev->private; + struct zpff_device *zpff = data; + int left, right; + + /* + * The following is specified the other way around in the Zeroplus + * datasheet but the order below is correct for the XFX Executioner; + * however it is possible that the XFX Executioner is an exception + */ + + left = effect->u.rumble.strong_magnitude; + right = effect->u.rumble.weak_magnitude; + debug("called with 0x%04x 0x%04x", left, right); + + left = left * 0x7f / 0xffff; + right = right * 0x7f / 0xffff; + + zpff->report->field[2]->value[0] = left; + zpff->report->field[3]->value[0] = right; + debug("running with 0x%02x 0x%02x", left, right); + hid_submit_report(hid, zpff->report, USB_DIR_OUT); + + return 0; +} + +int hid_zpff_init(struct hid_device *hid) +{ + struct zpff_device *zpff; + struct hid_report *report; + struct hid_input *hidinput = list_entry(hid->inputs.next, + struct hid_input, list); + struct list_head *report_list = + &hid->report_enum[HID_OUTPUT_REPORT].report_list; + struct input_dev *dev = hidinput->input; + int error; + + if (list_empty(report_list)) { + printk(KERN_ERR "hid-zpff: no output report found\n"); + return -ENODEV; + } + + report = list_entry(report_list->next, struct hid_report, list); + + if (report->maxfield < 4) { + printk(KERN_ERR "hid-zpff: not enough fields in report\n"); + return -ENODEV; + } + + zpff = kzalloc(sizeof(struct zpff_device), GFP_KERNEL); + if (!zpff) + return -ENOMEM; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, zpff, hid_zpff_play); + if (error) { + kfree(zpff); + return error; + } + + zpff->report = report; + zpff->report->field[0]->value[0] = 0x00; + zpff->report->field[1]->value[0] = 0x02; + zpff->report->field[2]->value[0] = 0x00; + zpff->report->field[3]->value[0] = 0x00; + hid_submit_report(hid, zpff->report, USB_DIR_OUT); + + printk(KERN_INFO "Force feedback for Zeroplus based devices by " + "Anssi Hannula <anssi.hannula@gmail.com>\n"); + + return 0; +} diff --git a/drivers/usb/input/hid.h b/drivers/usb/input/hid.h index 6d88c0c..3dae8a9 100644 --- a/drivers/usb/input/hid.h +++ b/drivers/usb/input/hid.h @@ -525,6 +525,7 @@ int hid_ff_init(struct hid_device *hid); int hid_lgff_init(struct hid_device *hid); int hid_tmff_init(struct hid_device *hid); +int hid_zpff_init(struct hid_device *hid); #ifdef CONFIG_HID_PID int hid_pidff_init(struct hid_device *hid); #else |