From 83efb8fe671af3c7b5613868aadc93ce973b6c3d Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Wed, 19 May 2010 22:41:10 +0200 Subject: [PATCH 01/30] HID: remove unused variable from hidraw_read Removed unused variable from hidraw_read. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hidraw.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c index 3ccd47850677..47d70c523d93 100644 --- a/drivers/hid/hidraw.c +++ b/drivers/hid/hidraw.c @@ -46,7 +46,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, { struct hidraw_list *list = file->private_data; int ret = 0, len; - char *report; DECLARE_WAITQUEUE(wait, current); mutex_lock(&list->read_mutex); @@ -84,7 +83,6 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count, if (ret) goto out; - report = list->buffer[list->tail].value; len = list->buffer[list->tail].len > count ? count : list->buffer[list->tail].len; From 597b49ec6f19b6df975e2101c42b7b1cfe168280 Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Wed, 26 May 2010 20:50:50 +0200 Subject: [PATCH 02/30] HID: roccat: remove obsolete comment Removed comment that is obsolete since roccat char device is implemented Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat-kone.c | 5 ----- 1 file changed, 5 deletions(-) diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 17f2dc04f883..3e5b5534f2ed 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -22,11 +22,6 @@ * Is it possible to remove and reinstall the urb in raw-event- or any * other handler, or to defer this action to be executed somewhere else? * - * TODO implement notification mechanism for overlong macro execution - * If user wants to execute an overlong macro only the names of macroset - * and macro are given. Should userland tap hidraw or is there an - * additional streaming mechanism? - * * TODO is it possible to overwrite group for sysfs attributes via udev? */ From 22d515723ff1d92eea4d7537a3f8d7674080422b Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Wed, 26 May 2010 20:51:28 +0200 Subject: [PATCH 03/30] HID: roccat: fix whitespace warning from checkpatch.pl Fixed the following warning of checkpatch.pl: WARNING: space prohibited between function name and open parenthesis '(' Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/hid/hid-roccat.h b/drivers/hid/hid-roccat.h index d8aae0c1fa7e..09e864e9f79d 100644 --- a/drivers/hid/hid-roccat.h +++ b/drivers/hid/hid-roccat.h @@ -15,7 +15,7 @@ #include #include -#if defined(CONFIG_HID_ROCCAT) || defined (CONFIG_HID_ROCCAT_MODULE) +#if defined(CONFIG_HID_ROCCAT) || defined(CONFIG_HID_ROCCAT_MODULE) int roccat_connect(struct hid_device *hid); void roccat_disconnect(int minor); int roccat_report_event(int minor, u8 const *data, int len); From 33ccbc320fc38094128c68b2ee0b305884965bd4 Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Wed, 26 May 2010 20:52:43 +0200 Subject: [PATCH 04/30] HID: roccat: change kone_driver_version to kone_abi_version Renamed the sysfs attribute kone_driver_version to kone_abi_version and simplified returned data to integer. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- .../ABI/testing/sysfs-driver-hid-roccat-kone | 7 +++---- drivers/hid/hid-roccat-kone.c | 12 ++++++------ drivers/hid/hid-roccat-kone.h | 2 +- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone index 88340a23ce91..36bfa234f1e2 100644 --- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone +++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone @@ -33,11 +33,10 @@ Description: When read, this file returns the raw integer version number of the left. E.g. a returned value of 138 means 1.38 This file is readonly. -What: /sys/bus/usb/devices/-:./kone_driver_version -Date: March 2010 +What: /sys/bus/usb/devices/-:./kone_abi_version +Date: May 2010 Contact: Stefan Achatz -Description: When read, this file returns the driver version. - The format of the string is "v..". +Description: When read, this file returns the abi version as an integer value. This attribute is used by the userland tools to find the sysfs- paths of installed kone-mice and determine the capabilites of the driver. Versions of this driver for old kernels replace diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 3e5b5534f2ed..0ab1df9d68ab 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -621,12 +621,12 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev, * This file is used by userland software to find devices that are handled by * this driver. This provides a consistent way for actual and older kernels * where this driver replaced usbhid instead of generic-usb. - * Driver capabilities are determined by version number. + * Driver capabilities are determined by returned number. */ -static ssize_t kone_sysfs_show_driver_version(struct device *dev, +static ssize_t kone_sysfs_show_abi_version(struct device *dev, struct device_attribute *attr, char *buf) { - return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_DRIVER_VERSION "\n"); + return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_ABI_VERSION "\n"); } /* @@ -666,8 +666,8 @@ static DEVICE_ATTR(startup_profile, 0660, kone_sysfs_show_startup_profile, kone_sysfs_set_startup_profile); -static DEVICE_ATTR(kone_driver_version, 0440, - kone_sysfs_show_driver_version, NULL); +static DEVICE_ATTR(kone_abi_version, 0440, + kone_sysfs_show_abi_version, NULL); static struct attribute *kone_attributes[] = { &dev_attr_actual_dpi.attr, @@ -676,7 +676,7 @@ static struct attribute *kone_attributes[] = { &dev_attr_firmware_version.attr, &dev_attr_tcu.attr, &dev_attr_startup_profile.attr, - &dev_attr_kone_driver_version.attr, + &dev_attr_kone_abi_version.attr, NULL }; diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h index 003e6f81c195..71b14fa40dce 100644 --- a/drivers/hid/hid-roccat-kone.h +++ b/drivers/hid/hid-roccat-kone.h @@ -14,7 +14,7 @@ #include -#define ROCCAT_KONE_DRIVER_VERSION "v0.3.1" +#define ROCCAT_KONE_ABI_VERSION "1" #pragma pack(push) #pragma pack(1) From dfe5c7b7e710d8ed885068b0fcfa6f66ab685592 Mon Sep 17 00:00:00 2001 From: Julia Lawall Date: Tue, 1 Jun 2010 16:35:15 +0200 Subject: [PATCH 05/30] HID: roccat: introduce missing kfree Error handling code following a kmalloc should free the allocated data. The semantic match that finds the problem is as follows: (http://www.emn.fr/x-info/coccinelle/) // @r exists@ local idexpression x; statement S; expression E; identifier f,f1,l; position p1,p2; expression *ptr != NULL; @@ x@p1 = \(kmalloc\|kzalloc\|kcalloc\)(...); ... if (x == NULL) S <... when != x when != if (...) { <+...x...+> } ( x->f1 = E | (x->f1 == NULL || ...) | f(...,x->f1,...) ) ...> ( return \(0\|<+...x...+>\|ptr\); | return@p2 ...; ) @script:python@ p1 << r.p1; p2 << r.p2; @@ print "* file: %s kmalloc %s return %s" % (p1[0].file,p1[0].line,p2[0].line) // Signed-off-by: Julia Lawall Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat.c | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c index e05d48edb66f..f6e80c7ca61e 100644 --- a/drivers/hid/hid-roccat.c +++ b/drivers/hid/hid-roccat.c @@ -168,7 +168,7 @@ static int roccat_open(struct inode *inode, struct file *file) printk(KERN_EMERG "roccat device with minor %d doesn't exist\n", minor); error = -ENODEV; - goto exit_unlock; + goto exit_err; } if (!device->open++) { @@ -178,7 +178,7 @@ static int roccat_open(struct inode *inode, struct file *file) PM_HINT_FULLON); if (error < 0) { --device->open; - goto exit_unlock; + goto exit_err; } } error = device->hid->ll_driver->open(device->hid); @@ -187,7 +187,7 @@ static int roccat_open(struct inode *inode, struct file *file) device->hid->ll_driver->power(device->hid, PM_HINT_NORMAL); --device->open; - goto exit_unlock; + goto exit_err; } } @@ -202,6 +202,9 @@ static int roccat_open(struct inode *inode, struct file *file) mutex_unlock(&device->readers_lock); mutex_unlock(&devices_lock); return error; +exit_err: + kfree(reader); + goto exit_unlock; } static int roccat_release(struct inode *inode, struct file *file) From ef566d30a702cc9b49d24edc4ad45c62208a4f5d Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Wed, 2 Jun 2010 10:28:25 -0400 Subject: [PATCH 06/30] HID: magicmouse: scroll on entire surface, not just middle of mouse Previously, scroll events only occurred when the user moved a touch along the middle of the touch surface. This is unintuitive for a normal user who is not aware of this. The device has a uniform surface, so the distinction is artificial. This change removes the touch area check for a scroll event, which replicates the OS X behavior. Signed-off-by: Chase Douglas Acked-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index f10d56a15f21..cd706354496a 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -160,10 +160,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda msc->touches[id].size = misc & 63; /* If requested, emulate a scroll wheel by detecting small - * vertical touch motions along the middle of the mouse. + * vertical touch motions. */ - if (emulate_scroll_wheel && - middle_button_start < x && x < middle_button_stop) { + if (emulate_scroll_wheel) { static const int accel_profile[] = { 256, 228, 192, 160, 128, 96, 64, 32, }; From 9846f350ef4d4108c1154acfc125fe8d8630ef84 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Wed, 2 Jun 2010 10:28:27 -0400 Subject: [PATCH 07/30] HID: magicmouse: disable and add module param for scroll acceleration Scroll acceleration is unique to the magicmouse driver, and is unintuitive to a user who is unaware of the functionality. Thus, disable it by default, but add a module parameter to enable it for power users who want it. Signed-off-by: Chase Douglas Acked-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index cd706354496a..4c4a79c760a2 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -30,6 +30,10 @@ static bool emulate_scroll_wheel = true; module_param(emulate_scroll_wheel, bool, 0644); MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel"); +static bool scroll_acceleration = false; +module_param(scroll_acceleration, bool, 0644); +MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events"); + static bool report_touches = true; module_param(report_touches, bool, 0644); MODULE_PARM_DESC(report_touches, "Emit touch records (otherwise, only use them for emulation)"); @@ -177,7 +181,9 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda switch (tdata[7] & TOUCH_STATE_MASK) { case TOUCH_STATE_START: msc->touches[id].scroll_y = y; - msc->scroll_accel = min_t(int, msc->scroll_accel + 1, + if (scroll_acceleration) + msc->scroll_accel = min_t(int, + msc->scroll_accel + 1, ARRAY_SIZE(accel_profile) - 1); break; case TOUCH_STATE_DRAG: From cab6b16aca4ac12f731a523fe14770add2f9394a Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Sun, 20 Jun 2010 19:19:06 +0200 Subject: [PATCH 08/30] HID: roccat: fix offset errors in bin_attribute read Fixing wrong calculated offsets in bin_attribute read functions. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- drivers/hid/hid-roccat-kone.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 0ab1df9d68ab..2aef6e4caf43 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -272,7 +272,7 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj, count = sizeof(struct kone_settings) - off; mutex_lock(&kone->kone_lock); - memcpy(buf, &kone->settings + off, count); + memcpy(buf, ((char const *)&kone->settings) + off, count); mutex_unlock(&kone->kone_lock); return count; @@ -332,7 +332,7 @@ static ssize_t kone_sysfs_read_profilex(struct kobject *kobj, count = sizeof(struct kone_profile) - off; mutex_lock(&kone->kone_lock); - memcpy(buf, &kone->profiles[number - 1], sizeof(struct kone_profile)); + memcpy(buf, ((char const *)&kone->profiles[number - 1]) + off, count); mutex_unlock(&kone->kone_lock); return count; From 0b3fa399bef02f3658295f8dd334fc26a59c3a95 Mon Sep 17 00:00:00 2001 From: Stefan Achatz Date: Fri, 18 Jun 2010 16:42:25 +0200 Subject: [PATCH 09/30] HID: roccat: remove obsolete kone_abi_version sysfs attribute The newest version of the accompanying userland tools cuts backward compatibility and uses libudev to find its devices superseding the quirky kone_abi_version sysfs attribute. Therefore it should be removed. Signed-off-by: Stefan Achatz Signed-off-by: Jiri Kosina --- .../ABI/testing/sysfs-driver-hid-roccat-kone | 12 ------------ drivers/hid/hid-roccat-kone.c | 16 ---------------- drivers/hid/hid-roccat-kone.h | 2 -- 3 files changed, 30 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone index 36bfa234f1e2..063bda7fe707 100644 --- a/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone +++ b/Documentation/ABI/testing/sysfs-driver-hid-roccat-kone @@ -33,18 +33,6 @@ Description: When read, this file returns the raw integer version number of the left. E.g. a returned value of 138 means 1.38 This file is readonly. -What: /sys/bus/usb/devices/-:./kone_abi_version -Date: May 2010 -Contact: Stefan Achatz -Description: When read, this file returns the abi version as an integer value. - This attribute is used by the userland tools to find the sysfs- - paths of installed kone-mice and determine the capabilites of - the driver. Versions of this driver for old kernels replace - usbhid instead of generic-usb. The way to scan for this file - has been chosen to provide a consistent way for all supported - kernel versions. - This file is readonly. - What: /sys/bus/usb/devices/-:./profile[1-5] Date: March 2010 Contact: Stefan Achatz diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c index 2aef6e4caf43..f77695762cb5 100644 --- a/drivers/hid/hid-roccat-kone.c +++ b/drivers/hid/hid-roccat-kone.c @@ -617,18 +617,6 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev, return size; } -/* - * This file is used by userland software to find devices that are handled by - * this driver. This provides a consistent way for actual and older kernels - * where this driver replaced usbhid instead of generic-usb. - * Driver capabilities are determined by returned number. - */ -static ssize_t kone_sysfs_show_abi_version(struct device *dev, - struct device_attribute *attr, char *buf) -{ - return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_ABI_VERSION "\n"); -} - /* * Read actual dpi settings. * Returns raw value for further processing. Refer to enum kone_polling_rates to @@ -666,9 +654,6 @@ static DEVICE_ATTR(startup_profile, 0660, kone_sysfs_show_startup_profile, kone_sysfs_set_startup_profile); -static DEVICE_ATTR(kone_abi_version, 0440, - kone_sysfs_show_abi_version, NULL); - static struct attribute *kone_attributes[] = { &dev_attr_actual_dpi.attr, &dev_attr_actual_profile.attr, @@ -676,7 +661,6 @@ static struct attribute *kone_attributes[] = { &dev_attr_firmware_version.attr, &dev_attr_tcu.attr, &dev_attr_startup_profile.attr, - &dev_attr_kone_abi_version.attr, NULL }; diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h index 71b14fa40dce..130d6566ea82 100644 --- a/drivers/hid/hid-roccat-kone.h +++ b/drivers/hid/hid-roccat-kone.h @@ -14,8 +14,6 @@ #include -#define ROCCAT_KONE_ABI_VERSION "1" - #pragma pack(push) #pragma pack(1) From 8d93efb27ab8927ffc7a357f1b2d10039de50ed4 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Sun, 20 Jun 2010 21:32:29 -0400 Subject: [PATCH 10/30] HID: magicmouse: properly account for scroll movement in state Before this change, sequential scroll events would take a variable amount of movement due to incorrect accounting. This change ensures all scroll movements require a deterministic touch movement for an action to occur. Signed-off-by: Chase Douglas Acked-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 4c4a79c760a2..f44aaf21e1e2 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -189,7 +189,8 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda case TOUCH_STATE_DRAG: step = step / accel_profile[msc->scroll_accel]; if (step != 0) { - msc->touches[id].scroll_y = y; + msc->touches[id].scroll_y -= + step * accel_profile[msc->scroll_accel]; msc->scroll_jiffies = now; input_report_rel(input, REL_WHEEL, step); } From 0b778e76c1e7ccf49f8980b594e72f984095fd26 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Sun, 20 Jun 2010 21:32:30 -0400 Subject: [PATCH 11/30] HID: magicmouse: add param for scroll speed The new scroll_speed param takes an integer value from 0 to 63, where 0 is slowest and 63 is fastest. The default of 32 remains the same. This parameter also affects scroll acceleration linearly. A second part of this change is a tightly coupled modification to the scroll acceleration. Previously, scroll acceleration could be reset without lifting the scroll finger. This is rather unintuitive and hard to control in the case where a user wants faster scrolling, but wants to hold the scroll touch for longer than a moment. Note that scroll acceleration levels are now 1-7, where 7 is slowest. In the previous implementation, there were 8 levels defined, but it was impossible to start at the slowest level. In order to keep the default scroll speed unchanged, only 7 levels are used now. Signed-off-by: Chase Douglas Acked-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 43 +++++++++++++++++++++++------------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index f44aaf21e1e2..fe0c760d7e6e 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -30,6 +30,17 @@ static bool emulate_scroll_wheel = true; module_param(emulate_scroll_wheel, bool, 0644); MODULE_PARM_DESC(emulate_scroll_wheel, "Emulate a scroll wheel"); +static unsigned int scroll_speed = 32; +static int param_set_scroll_speed(const char *val, struct kernel_param *kp) { + unsigned long speed; + if (!val || strict_strtoul(val, 0, &speed) || speed > 63) + return -EINVAL; + scroll_speed = speed; + return 0; +} +module_param_call(scroll_speed, param_set_scroll_speed, param_get_uint, &scroll_speed, 0644); +MODULE_PARM_DESC(scroll_speed, "Scroll speed, value from 0 (slow) to 63 (fast)"); + static bool scroll_acceleration = false; module_param(scroll_acceleration, bool, 0644); MODULE_PARM_DESC(scroll_acceleration, "Accelerate sequential scroll events"); @@ -54,6 +65,8 @@ MODULE_PARM_DESC(report_undeciphered, "Report undeciphered multi-touch state fie #define TOUCH_STATE_START 0x30 #define TOUCH_STATE_DRAG 0x40 +#define SCROLL_ACCEL_DEFAULT 7 + /** * struct magicmouse_sc - Tracks Magic Mouse-specific data. * @input: Input device through which we report events. @@ -145,7 +158,7 @@ static void magicmouse_emit_buttons(struct magicmouse_sc *msc, int state) input_report_key(msc->input, BTN_RIGHT, state & 2); if (state != last_state) - msc->scroll_accel = 0; + msc->scroll_accel = SCROLL_ACCEL_DEFAULT; } static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tdata) @@ -167,30 +180,28 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda * vertical touch motions. */ if (emulate_scroll_wheel) { - static const int accel_profile[] = { - 256, 228, 192, 160, 128, 96, 64, 32, - }; unsigned long now = jiffies; int step = msc->touches[id].scroll_y - y; - /* Reset acceleration after half a second. */ - if (time_after(now, msc->scroll_jiffies + HZ / 2)) - msc->scroll_accel = 0; - /* Calculate and apply the scroll motion. */ switch (tdata[7] & TOUCH_STATE_MASK) { case TOUCH_STATE_START: msc->touches[id].scroll_y = y; - if (scroll_acceleration) - msc->scroll_accel = min_t(int, - msc->scroll_accel + 1, - ARRAY_SIZE(accel_profile) - 1); + + /* Reset acceleration after half a second. */ + if (scroll_acceleration && time_before(now, + msc->scroll_jiffies + HZ / 2)) + msc->scroll_accel = max_t(int, + msc->scroll_accel - 1, 1); + else + msc->scroll_accel = SCROLL_ACCEL_DEFAULT; + break; case TOUCH_STATE_DRAG: - step = step / accel_profile[msc->scroll_accel]; + step /= (64 - (int)scroll_speed) * msc->scroll_accel; if (step != 0) { - msc->touches[id].scroll_y -= - step * accel_profile[msc->scroll_accel]; + msc->touches[id].scroll_y -= step * + (64 - scroll_speed) * msc->scroll_accel; msc->scroll_jiffies = now; input_report_rel(input, REL_WHEEL, step); } @@ -351,6 +362,8 @@ static int magicmouse_probe(struct hid_device *hdev, return -ENOMEM; } + msc->scroll_accel = SCROLL_ACCEL_DEFAULT; + msc->quirks = id->driver_data; hid_set_drvdata(hdev, msc); From c04266889b591165bdea396b20313bebb83c0fd6 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Sun, 20 Jun 2010 21:32:31 -0400 Subject: [PATCH 12/30] HID: magicmouse: enable horizontal scrolling Mimicks OS X behavior. Signed-off-by: Chase Douglas Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 25 +++++++++++++++++++------ 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index fe0c760d7e6e..0b89c1cf9ec4 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -95,6 +95,7 @@ struct magicmouse_sc { struct { short x; short y; + short scroll_x; short scroll_y; u8 size; } touches[16]; @@ -181,11 +182,13 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda */ if (emulate_scroll_wheel) { unsigned long now = jiffies; - int step = msc->touches[id].scroll_y - y; + int step_x = msc->touches[id].scroll_x - x; + int step_y = msc->touches[id].scroll_y - y; /* Calculate and apply the scroll motion. */ switch (tdata[7] & TOUCH_STATE_MASK) { case TOUCH_STATE_START: + msc->touches[id].scroll_x = x; msc->touches[id].scroll_y = y; /* Reset acceleration after half a second. */ @@ -198,12 +201,20 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda break; case TOUCH_STATE_DRAG: - step /= (64 - (int)scroll_speed) * msc->scroll_accel; - if (step != 0) { - msc->touches[id].scroll_y -= step * + step_x /= (64 - (int)scroll_speed) * msc->scroll_accel; + if (step_x != 0) { + msc->touches[id].scroll_x -= step_x * (64 - scroll_speed) * msc->scroll_accel; msc->scroll_jiffies = now; - input_report_rel(input, REL_WHEEL, step); + input_report_rel(input, REL_HWHEEL, -step_x); + } + + step_y /= (64 - (int)scroll_speed) * msc->scroll_accel; + if (step_y != 0) { + msc->touches[id].scroll_y -= step_y * + (64 - scroll_speed) * msc->scroll_accel; + msc->scroll_jiffies = now; + input_report_rel(input, REL_WHEEL, step_y); } break; } @@ -318,8 +329,10 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h __set_bit(EV_REL, input->evbit); __set_bit(REL_X, input->relbit); __set_bit(REL_Y, input->relbit); - if (emulate_scroll_wheel) + if (emulate_scroll_wheel) { __set_bit(REL_WHEEL, input->relbit); + __set_bit(REL_HWHEEL, input->relbit); + } if (report_touches) { __set_bit(EV_ABS, input->evbit); From 64b386ea16112564e0b93473e2c347125effb6b2 Mon Sep 17 00:00:00 2001 From: Richard Nauber Date: Mon, 28 Jun 2010 18:54:25 +0200 Subject: [PATCH 13/30] HID: add proper support for Elecom BM084 bluetooth mouse This patch removes the annoying feature of Elecoms BM084 to constantly scroll to the right. The device can be found at: http://www.dealextreme.com/details.dx/sku.15402 Signed-off-by: Richard Nauber [jkosina@suse.cz: fix build error] Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 6 +++++ drivers/hid/Makefile | 1 + drivers/hid/hid-core.c | 1 + drivers/hid/hid-elecom.c | 57 ++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-ids.h | 3 +++ 5 files changed, 68 insertions(+) create mode 100644 drivers/hid/hid-elecom.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 76ba59b9fea1..ecc11405922a 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -148,6 +148,12 @@ config HID_EGALAX ---help--- Support for the eGalax dual-touch panel. +config HID_ELECOM + tristate "ELECOM" + depends on BT_HIDP + ---help--- + Support for the ELECOM BM084 (bluetooth mouse). + config HID_EZKEY tristate "Ezkey" if EMBEDDED depends on USB_HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 22e47eaeea32..3a6eb7ec42e2 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -32,6 +32,7 @@ obj-$(CONFIG_HID_CHICONY) += hid-chicony.o obj-$(CONFIG_HID_CYPRESS) += hid-cypress.o obj-$(CONFIG_HID_DRAGONRISE) += hid-drff.o obj-$(CONFIG_HID_EGALAX) += hid-egalax.o +obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o obj-$(CONFIG_HID_GYRATION) += hid-gyration.o obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index e10e314d38cc..20bccd4d488a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1294,6 +1294,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) }, { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) }, { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) }, + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) }, { HID_USB_DEVICE(USB_VENDOR_ID_EZKEY, USB_DEVICE_ID_BTC_8193) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PSX_ADAPTOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_GAMERON, USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR) }, diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c new file mode 100644 index 000000000000..7a40878f46b4 --- /dev/null +++ b/drivers/hid/hid-elecom.c @@ -0,0 +1,57 @@ +/* + * HID driver for Elecom BM084 (bluetooth mouse). + * Removes a non-existing horizontal wheel from + * the HID descriptor. + * (This module is based on "hid-ortek".) + * + * Copyright (c) 2010 Richard Nauber + */ + +/* + * 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. + */ + +#include +#include +#include + +#include "hid-ids.h" + +static void elecom_report_fixup(struct hid_device *hdev, __u8 *rdesc, + unsigned int rsize) +{ + if (rsize >= 48 && rdesc[46] == 0x05 && rdesc[47] == 0x0c) { + dev_info(&hdev->dev, "Fixing up Elecom BM084 " + "report descriptor.\n"); + rdesc[47] = 0x00; + } +} + +static const struct hid_device_id elecom_devices[] = { + { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084)}, + { } +}; +MODULE_DEVICE_TABLE(hid, elecom_devices); + +static struct hid_driver elecom_driver = { + .name = "elecom", + .id_table = elecom_devices, + .report_fixup = elecom_report_fixup +}; + +static int __init elecom_init(void) +{ + return hid_register_driver(&elecom_driver); +} + +static void __exit elecom_exit(void) +{ + hid_unregister_driver(&elecom_driver); +} + +module_init(elecom_init); +module_exit(elecom_exit); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 9776896cc4fc..69778c5cd4d4 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -186,6 +186,9 @@ #define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001 #define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d +#define USB_VENDOR_ID_ELECOM 0x056e +#define USB_DEVICE_ID_ELECOM_BM084 0x0061 + #define USB_VENDOR_ID_ELO 0x04E7 #define USB_DEVICE_ID_ELO_TS2700 0x0020 From 6dc398acf944e768a62aa5eed925633e0a3dad0e Mon Sep 17 00:00:00 2001 From: Kees Bakker Date: Fri, 2 Jul 2010 22:15:50 +0200 Subject: [PATCH 14/30] HID: hid-ids.h: keep vendor ids in alphabetical order The VENDOR_IDs were mostly in alphabetical order, but some of the newer entries were not added as such. Some entries were added just at the end, some were added in the middle. This patch places the entries once again in a properly sorted order. Signed-off-by: Kees Bakker Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 42 +++++++++++++++++++++--------------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 69778c5cd4d4..474ea1a63051 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -195,12 +195,12 @@ #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 -#define USB_VENDOR_ID_ETURBOTOUCH 0x22b9 -#define USB_DEVICE_ID_ETURBOTOUCH 0x0006 - #define USB_VENDOR_ID_ETT 0x0664 #define USB_DEVICE_ID_TC5UH 0x0309 +#define USB_VENDOR_ID_ETURBOTOUCH 0x22b9 +#define USB_DEVICE_ID_ETURBOTOUCH 0x0006 + #define USB_VENDOR_ID_EZKEY 0x0518 #define USB_DEVICE_ID_BTC_8193 0x0002 @@ -297,9 +297,16 @@ #define USB_VENDOR_ID_KBGEAR 0x084e #define USB_DEVICE_ID_KBGEAR_JAMSTUDIO 0x1001 +#define USB_VENDOR_ID_KENSINGTON 0x047d +#define USB_DEVICE_ID_KS_SLIMBLADE 0x2041 + #define USB_VENDOR_ID_KWORLD 0x1b80 #define USB_DEVICE_ID_KWORLD_RADIO_FM700 0xd700 +#define USB_VENDOR_ID_KYE 0x0458 +#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087 +#define USB_DEVICE_ID_KYE_GPEN_560 0x5003 + #define USB_VENDOR_ID_LABTEC 0x1020 #define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006 @@ -319,9 +326,6 @@ #define USB_DEVICE_ID_LD_POWERCONTROL 0x2030 #define USB_DEVICE_ID_LD_MACHINETEST 0x2040 -#define USB_VENDOR_ID_KENSINGTON 0x047d -#define USB_DEVICE_ID_KS_SLIMBLADE 0x2041 - #define USB_VENDOR_ID_LOGITECH 0x046d #define USB_DEVICE_ID_LOGITECH_RECEIVER 0xc101 #define USB_DEVICE_ID_LOGITECH_HARMONY_FIRST 0xc110 @@ -375,16 +379,16 @@ #define USB_VENDOR_ID_MONTEREY 0x0566 #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 -#define USB_VENDOR_ID_NCR 0x0404 -#define USB_DEVICE_ID_NCR_FIRST 0x0300 -#define USB_DEVICE_ID_NCR_LAST 0x03ff - #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 #define USB_DEVICE_ID_N_S_HARMONY 0xc359 #define USB_VENDOR_ID_NATSU 0x08b7 #define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001 +#define USB_VENDOR_ID_NCR 0x0404 +#define USB_DEVICE_ID_NCR_FIRST 0x0300 +#define USB_DEVICE_ID_NCR_LAST 0x03ff + #define USB_VENDOR_ID_NEC 0x073e #define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301 @@ -420,16 +424,16 @@ #define USB_VENDOR_ID_PRODIGE 0x05af #define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062 +#define USB_VENDOR_ID_QUANTA 0x0408 +#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000 +#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001 + #define USB_VENDOR_ID_ROCCAT 0x1e7d #define USB_DEVICE_ID_ROCCAT_KONE 0x2ced #define USB_VENDOR_ID_SAITEK 0x06a3 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17 -#define USB_VENDOR_ID_QUANTA 0x0408 -#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000 -#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001 - #define USB_VENDOR_ID_SAMSUNG 0x0419 #define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001 #define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600 @@ -453,15 +457,15 @@ #define USB_VENDOR_ID_THRUSTMASTER 0x044f -#define USB_VENDOR_ID_TOUCHPACK 0x1bfd -#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688 - #define USB_VENDOR_ID_TOPMAX 0x0663 #define USB_DEVICE_ID_TOPMAX_COBRAPAD 0x0103 #define USB_VENDOR_ID_TOPSEED 0x0766 #define USB_DEVICE_ID_TOPSEED_CYBERLINK 0x0204 +#define USB_VENDOR_ID_TOUCHPACK 0x1bfd +#define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688 + #define USB_VENDOR_ID_TURBOX 0x062a #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 @@ -503,9 +507,5 @@ #define USB_VENDOR_ID_ZYDACRON 0x13EC #define USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL 0x0006 -#define USB_VENDOR_ID_KYE 0x0458 -#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087 -#define USB_DEVICE_ID_KYE_GPEN_560 0x5003 - #endif From a7c9a0aa175aee8a66301264bff2a5ff014ca0e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= Date: Wed, 30 Jun 2010 22:36:31 +0200 Subject: [PATCH 15/30] HID: picolcd: fix deferred_io init/cleanup to fb ordering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Adjust ordering if framebuffer (un)registration and defio init/cleanup to match the correct order (init defio, register FB ... unregister FB, cleanup defio) Acked-by: Jaya Kumar Signed-off-by: Bruno Prémont Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 7aabf65c48ef..839a5ac0ad82 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -707,18 +707,19 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) dev_err(dev, "failed to create sysfs attributes\n"); goto err_cleanup; } + fb_deferred_io_init(info); data->fb_info = info; error = register_framebuffer(info); if (error) { dev_err(dev, "failed to register framebuffer\n"); goto err_sysfs; } - fb_deferred_io_init(info); /* schedule first output of framebuffer */ schedule_delayed_work(&info->deferred_work, 0); return 0; err_sysfs: + fb_deferred_io_cleanup(info); device_remove_file(dev, &dev_attr_fb_update_rate); err_cleanup: data->fb_vbitmap = NULL; @@ -747,7 +748,6 @@ static void picolcd_exit_framebuffer(struct picolcd_data *data) data->fb_bpp = 0; data->fb_info = NULL; device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate); - fb_deferred_io_cleanup(info); unregister_framebuffer(info); vfree(fb_bitmap); kfree(fb_vbitmap); From e3612e8669b8c15278058f8dd52e3dc6e7d26710 Mon Sep 17 00:00:00 2001 From: Chase Douglas Date: Mon, 5 Jul 2010 09:57:52 -0400 Subject: [PATCH 16/30] HID: magicmouse: report last touch up The evdev multitouch protocol requires that a last MT sync event must be sent after all touches are up. This change adds the last MT sync event to the hid-magicmouse driver. Also, don't send events when a touch leaves. Signed-off-by: Chase Douglas Acked-by: Michael Poole Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index 0b89c1cf9ec4..ee7878785955 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -98,6 +98,7 @@ struct magicmouse_sc { short scroll_x; short scroll_y; u8 size; + u8 down; } touches[16]; int tracking_ids[16]; }; @@ -170,6 +171,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda int id = (misc >> 6) & 15; int x = x_y << 12 >> 20; int y = -(x_y >> 20); + int down = (tdata[7] & TOUCH_STATE_MASK) != TOUCH_STATE_NONE; /* Store tracking ID and other fields. */ msc->tracking_ids[raw_id] = id; @@ -221,9 +223,11 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda } /* Generate the input events for this touch. */ - if (report_touches) { + if (report_touches && down) { int orientation = (misc >> 10) - 32; + msc->touches[id].down = 1; + input_report_abs(input, ABS_MT_TRACKING_ID, id); input_report_abs(input, ABS_MT_TOUCH_MAJOR, tdata[3]); input_report_abs(input, ABS_MT_TOUCH_MINOR, tdata[4]); @@ -243,7 +247,7 @@ static int magicmouse_raw_event(struct hid_device *hdev, { struct magicmouse_sc *msc = hid_get_drvdata(hdev); struct input_dev *input = msc->input; - int x, y, ts, ii, clicks; + int x, y, ts, ii, clicks, last_up; switch (data[0]) { case 0x10: @@ -263,6 +267,20 @@ static int magicmouse_raw_event(struct hid_device *hdev, msc->ntouches = (size - 6) / 8; for (ii = 0; ii < msc->ntouches; ii++) magicmouse_emit_touch(msc, ii, data + ii * 8 + 6); + + if (report_touches) { + last_up = 1; + for (ii = 0; ii < ARRAY_SIZE(msc->touches); ii++) { + if (msc->touches[ii].down) { + last_up = 0; + msc->touches[ii].down = 0; + } + } + if (last_up) { + input_mt_sync(input); + } + } + /* When emulating three-button mode, it is important * to have the current touch information before * generating a click event. From 7d876c05fa6cf82f0274f27276d981ed325697a5 Mon Sep 17 00:00:00 2001 From: Michael Poole Date: Mon, 5 Jul 2010 10:50:09 -0400 Subject: [PATCH 17/30] HID: magicmouse: Correct parsing of large X and Y motions. The X and Y values have two more significant bits in the same byte that contains click status. Include these in the reported value. Thanks to Iain Hibbert of NetBSD for pointing this out. Signed-off-by: Michael Poole Acked-by: Chase Douglas Signed-off-by: Jiri Kosina --- drivers/hid/hid-magicmouse.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c index ee7878785955..319b0e57ee41 100644 --- a/drivers/hid/hid-magicmouse.c +++ b/drivers/hid/hid-magicmouse.c @@ -285,8 +285,8 @@ static int magicmouse_raw_event(struct hid_device *hdev, * to have the current touch information before * generating a click event. */ - x = (signed char)data[1]; - y = (signed char)data[2]; + x = (int)(((data[3] & 0x0c) << 28) | (data[1] << 22)) >> 22; + y = (int)(((data[3] & 0x30) << 26) | (data[2] << 22)) >> 22; clicks = data[3]; break; case 0x20: /* Theoretically battery status (0-100), but I have From b70884ff3a5314c2eb702f85599e722cccdd2f5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= Date: Mon, 28 Jun 2010 22:30:29 +0200 Subject: [PATCH 18/30] HID: picolcd: Add minimal palette required by fbcon on 8bpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a minimal palette so fbcon does not try to dereference a NULL point when fb is set to 8bpp. fbcon stores pixels the other way around in bytes for 1bpp than intially implemented, correct this. Signed-off-by: Bruno Prémont Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd.c | 62 ++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 11 deletions(-) diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index 839a5ac0ad82..dc19501a786f 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -127,6 +127,26 @@ static const struct fb_var_screeninfo picolcdfb_var = { .height = 26, .bits_per_pixel = 1, .grayscale = 1, + .red = { + .offset = 0, + .length = 1, + .msb_right = 0, + }, + .green = { + .offset = 0, + .length = 1, + .msb_right = 0, + }, + .blue = { + .offset = 0, + .length = 1, + .msb_right = 0, + }, + .transp = { + .offset = 0, + .length = 0, + .msb_right = 0, + }, }; #endif /* CONFIG_HID_PICOLCD_FB */ @@ -188,6 +208,7 @@ struct picolcd_data { /* Framebuffer stuff */ u8 fb_update_rate; u8 fb_bpp; + u8 fb_force; u8 *fb_vbitmap; /* local copy of what was sent to PicoLCD */ u8 *fb_bitmap; /* framebuffer */ struct fb_info *fb_info; @@ -346,7 +367,7 @@ static int picolcd_fb_update_tile(u8 *vbitmap, const u8 *bitmap, int bpp, const u8 *bdata = bitmap + tile * 256 + chip * 8 + b * 32; for (i = 0; i < 64; i++) { tdata[i] <<= 1; - tdata[i] |= (bdata[i/8] >> (7 - i % 8)) & 0x01; + tdata[i] |= (bdata[i/8] >> (i % 8)) & 0x01; } } } else if (bpp == 8) { @@ -399,13 +420,10 @@ static int picolcd_fb_reset(struct picolcd_data *data, int clear) if (data->fb_bitmap) { if (clear) { - memset(data->fb_vbitmap, 0xff, PICOLCDFB_SIZE); + memset(data->fb_vbitmap, 0, PICOLCDFB_SIZE); memset(data->fb_bitmap, 0, PICOLCDFB_SIZE*data->fb_bpp); - } else { - /* invert 1 byte in each tile to force resend */ - for (i = 0; i < PICOLCDFB_SIZE; i += 64) - data->fb_vbitmap[i] = ~data->fb_vbitmap[i]; } + data->fb_force = 1; } /* schedule first output of framebuffer */ @@ -440,7 +458,8 @@ static void picolcd_fb_update(struct picolcd_data *data) for (chip = 0; chip < 4; chip++) for (tile = 0; tile < 8; tile++) if (picolcd_fb_update_tile(data->fb_vbitmap, - data->fb_bitmap, data->fb_bpp, chip, tile)) { + data->fb_bitmap, data->fb_bpp, chip, tile) || + data->fb_force) { n += 2; if (n >= HID_OUTPUT_FIFO_SIZE / 2) { usbhid_wait_io(data->hdev); @@ -448,6 +467,7 @@ static void picolcd_fb_update(struct picolcd_data *data) } picolcd_fb_send_tile(data->hdev, chip, tile); } + data->fb_force = false; if (n) usbhid_wait_io(data->hdev); } @@ -526,10 +546,17 @@ static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *i /* only allow 1/8 bit depth (8-bit is grayscale) */ *var = picolcdfb_var; var->activate = activate; - if (bpp >= 8) + if (bpp >= 8) { var->bits_per_pixel = 8; - else + var->red.length = 8; + var->green.length = 8; + var->blue.length = 8; + } else { var->bits_per_pixel = 1; + var->red.length = 1; + var->green.length = 1; + var->blue.length = 1; + } return 0; } @@ -660,9 +687,10 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) { struct device *dev = &data->hdev->dev; struct fb_info *info = NULL; - int error = -ENOMEM; + int i, error = -ENOMEM; u8 *fb_vbitmap = NULL; u8 *fb_bitmap = NULL; + u32 *palette; fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel); if (fb_bitmap == NULL) { @@ -678,12 +706,23 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) data->fb_update_rate = PICOLCDFB_UPDATE_RATE_DEFAULT; data->fb_defio = picolcd_fb_defio; - info = framebuffer_alloc(0, dev); + /* The extra memory is: + * - struct picolcd_fb_cleanup_item + * - u32 for ref_count + * - 256*u32 for pseudo_palette + */ + info = framebuffer_alloc(257 * sizeof(u32), dev); if (info == NULL) { dev_err(dev, "failed to allocate a framebuffer\n"); goto err_nomem; } + palette = info->par; + *palette = 1; + palette++; + for (i = 0; i < 256; i++) + palette[i] = i > 0 && i < 16 ? 0xff : 0; + info->pseudo_palette = palette; info->fbdefio = &data->fb_defio; info->screen_base = (char __force __iomem *)fb_bitmap; info->fbops = &picolcdfb_ops; @@ -715,6 +754,7 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) goto err_sysfs; } /* schedule first output of framebuffer */ + data->fb_force = 1; schedule_delayed_work(&info->deferred_work, 0); return 0; From 365f1fcd0d5a40f933bed55e515fce2077c40e9a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= Date: Mon, 28 Jun 2010 22:31:20 +0200 Subject: [PATCH 19/30] HID: picolcd: do not reallocate memory on depth change MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reallocating memory in depth change does not work well if some userspace application has mmapped() the framebuffer as that mapping does not get adjusted (thus application continues to write to old buffer). In addition doing deferred_io_cleanup() and init() inside of set_par() tends to deadlock with fbcon's flashing cursor. Avoid all this by allocating a buffer that can hold 8bpp framebuffer and just use 1/8 of it while running at 1bpp. Signed-off-by: Bruno Prémont Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd.c | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index dc19501a786f..f7204541591c 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -563,19 +563,18 @@ static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *i static int picolcd_set_par(struct fb_info *info) { struct picolcd_data *data = info->par; - u8 *o_fb, *n_fb; + u8 *tmp_fb, *o_fb; if (info->var.bits_per_pixel == data->fb_bpp) return 0; /* switch between 1/8 bit depths */ if (info->var.bits_per_pixel != 1 && info->var.bits_per_pixel != 8) return -EINVAL; - o_fb = data->fb_bitmap; - n_fb = vmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel); - if (!n_fb) + o_fb = data->fb_bitmap; + tmp_fb = kmalloc(PICOLCDFB_SIZE*info->var.bits_per_pixel, GFP_KERNEL); + if (!tmp_fb) return -ENOMEM; - fb_deferred_io_cleanup(info); /* translate FB content to new bits-per-pixel */ if (info->var.bits_per_pixel == 1) { int i, b; @@ -585,24 +584,22 @@ static int picolcd_set_par(struct fb_info *info) p <<= 1; p |= o_fb[i*8+b] ? 0x01 : 0x00; } + tmp_fb[i] = p; } + memcpy(o_fb, tmp_fb, PICOLCDFB_SIZE); info->fix.visual = FB_VISUAL_MONO01; info->fix.line_length = PICOLCDFB_WIDTH / 8; } else { int i; + memcpy(tmp_fb, o_fb, PICOLCDFB_SIZE); for (i = 0; i < PICOLCDFB_SIZE * 8; i++) - n_fb[i] = o_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00; - info->fix.visual = FB_VISUAL_TRUECOLOR; + o_fb[i] = tmp_fb[i/8] & (0x01 << (7 - i % 8)) ? 0xff : 0x00; + info->fix.visual = FB_VISUAL_DIRECTCOLOR; info->fix.line_length = PICOLCDFB_WIDTH; } - data->fb_bitmap = n_fb; + kfree(tmp_fb); data->fb_bpp = info->var.bits_per_pixel; - info->screen_base = (char __force __iomem *)n_fb; - info->fix.smem_start = (unsigned long)n_fb; - info->fix.smem_len = PICOLCDFB_SIZE*data->fb_bpp; - fb_deferred_io_init(info); - vfree(o_fb); return 0; } @@ -692,7 +689,7 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) u8 *fb_bitmap = NULL; u32 *palette; - fb_bitmap = vmalloc(PICOLCDFB_SIZE*picolcdfb_var.bits_per_pixel); + fb_bitmap = vmalloc(PICOLCDFB_SIZE*8); if (fb_bitmap == NULL) { dev_err(dev, "can't get a free page for framebuffer\n"); goto err_nomem; @@ -728,7 +725,7 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) info->fbops = &picolcdfb_ops; info->var = picolcdfb_var; info->fix = picolcdfb_fix; - info->fix.smem_len = PICOLCDFB_SIZE; + info->fix.smem_len = PICOLCDFB_SIZE*8; info->fix.smem_start = (unsigned long)fb_bitmap; info->par = data; info->flags = FBINFO_FLAG_DEFAULT; From 225b4590062008c9de22ed6e3a200f832d9bcdc8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bruno=20Pr=C3=A9mont?= Date: Mon, 28 Jun 2010 22:33:27 +0200 Subject: [PATCH 20/30] HID: picolcd: implement refcounting of framebuffer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit As our device may be hot-unplugged and framebuffer cannot handle this case by itself we need to keep track of usage count so as to release fb_info and framebuffer memory only after the last user has closed framebuffer. We need to do the freeing in a scheduled work as fb_release() is called with fb_info lock held. Signed-off-by: Bruno Prémont Signed-off-by: Jiri Kosina --- drivers/hid/hid-picolcd.c | 110 +++++++++++++++++++++++++++++++++++--- 1 file changed, 103 insertions(+), 7 deletions(-) diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c index f7204541591c..346f0e34987e 100644 --- a/drivers/hid/hid-picolcd.c +++ b/drivers/hid/hid-picolcd.c @@ -439,6 +439,9 @@ static void picolcd_fb_update(struct picolcd_data *data) int chip, tile, n; unsigned long flags; + if (!data) + return; + spin_lock_irqsave(&data->lock, flags); if (!(data->status & PICOLCD_READY_FB)) { spin_unlock_irqrestore(&data->lock, flags); @@ -461,6 +464,8 @@ static void picolcd_fb_update(struct picolcd_data *data) data->fb_bitmap, data->fb_bpp, chip, tile) || data->fb_force) { n += 2; + if (!data->fb_info->par) + return; /* device lost! */ if (n >= HID_OUTPUT_FIFO_SIZE / 2) { usbhid_wait_io(data->hdev); n = 0; @@ -531,11 +536,23 @@ static int picolcd_fb_blank(int blank, struct fb_info *info) static void picolcd_fb_destroy(struct fb_info *info) { struct picolcd_data *data = info->par; + u32 *ref_cnt = info->pseudo_palette; + int may_release; + info->par = NULL; if (data) data->fb_info = NULL; fb_deferred_io_cleanup(info); - framebuffer_release(info); + + ref_cnt--; + mutex_lock(&info->lock); + (*ref_cnt)--; + may_release = !ref_cnt; + mutex_unlock(&info->lock); + if (may_release) { + framebuffer_release(info); + vfree((u8 *)info->fix.smem_start); + } } static int picolcd_fb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) @@ -564,6 +581,8 @@ static int picolcd_set_par(struct fb_info *info) { struct picolcd_data *data = info->par; u8 *tmp_fb, *o_fb; + if (!data) + return -ENODEV; if (info->var.bits_per_pixel == data->fb_bpp) return 0; /* switch between 1/8 bit depths */ @@ -603,10 +622,77 @@ static int picolcd_set_par(struct fb_info *info) return 0; } +/* Do refcounting on our FB and cleanup per worker if FB is + * closed after unplug of our device + * (fb_release holds info->lock and still touches info after + * we return so we can't release it immediately. + */ +struct picolcd_fb_cleanup_item { + struct fb_info *info; + struct picolcd_fb_cleanup_item *next; +}; +static struct picolcd_fb_cleanup_item *fb_pending; +DEFINE_SPINLOCK(fb_pending_lock); + +static void picolcd_fb_do_cleanup(struct work_struct *data) +{ + struct picolcd_fb_cleanup_item *item; + unsigned long flags; + + do { + spin_lock_irqsave(&fb_pending_lock, flags); + item = fb_pending; + fb_pending = item ? item->next : NULL; + spin_unlock_irqrestore(&fb_pending_lock, flags); + + if (item) { + u8 *fb = (u8 *)item->info->fix.smem_start; + /* make sure we do not race against fb core when + * releasing */ + mutex_lock(&item->info->lock); + mutex_unlock(&item->info->lock); + framebuffer_release(item->info); + vfree(fb); + } + } while (item); +} + +DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup); + +static int picolcd_fb_open(struct fb_info *info, int u) +{ + u32 *ref_cnt = info->pseudo_palette; + ref_cnt--; + + (*ref_cnt)++; + return 0; +} + +static int picolcd_fb_release(struct fb_info *info, int u) +{ + u32 *ref_cnt = info->pseudo_palette; + ref_cnt--; + + (*ref_cnt)++; + if (!*ref_cnt) { + unsigned long flags; + struct picolcd_fb_cleanup_item *item = (struct picolcd_fb_cleanup_item *)ref_cnt; + item--; + spin_lock_irqsave(&fb_pending_lock, flags); + item->next = fb_pending; + fb_pending = item; + spin_unlock_irqrestore(&fb_pending_lock, flags); + schedule_work(&picolcd_fb_cleanup); + } + return 0; +} + /* Note this can't be const because of struct fb_info definition */ static struct fb_ops picolcdfb_ops = { .owner = THIS_MODULE, .fb_destroy = picolcd_fb_destroy, + .fb_open = picolcd_fb_open, + .fb_release = picolcd_fb_release, .fb_read = fb_sys_read, .fb_write = picolcd_fb_write, .fb_blank = picolcd_fb_blank, @@ -708,13 +794,13 @@ static int picolcd_init_framebuffer(struct picolcd_data *data) * - u32 for ref_count * - 256*u32 for pseudo_palette */ - info = framebuffer_alloc(257 * sizeof(u32), dev); + info = framebuffer_alloc(257 * sizeof(u32) + sizeof(struct picolcd_fb_cleanup_item), dev); if (info == NULL) { dev_err(dev, "failed to allocate a framebuffer\n"); goto err_nomem; } - palette = info->par; + palette = info->par + sizeof(struct picolcd_fb_cleanup_item); *palette = 1; palette++; for (i = 0; i < 256; i++) @@ -775,18 +861,17 @@ static void picolcd_exit_framebuffer(struct picolcd_data *data) { struct fb_info *info = data->fb_info; u8 *fb_vbitmap = data->fb_vbitmap; - u8 *fb_bitmap = data->fb_bitmap; if (!info) return; + info->par = NULL; + device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate); + unregister_framebuffer(info); data->fb_vbitmap = NULL; data->fb_bitmap = NULL; data->fb_bpp = 0; data->fb_info = NULL; - device_remove_file(&data->hdev->dev, &dev_attr_fb_update_rate); - unregister_framebuffer(info); - vfree(fb_bitmap); kfree(fb_vbitmap); } @@ -2603,6 +2688,13 @@ static void picolcd_remove(struct hid_device *hdev) spin_lock_irqsave(&data->lock, flags); data->status |= PICOLCD_FAILED; spin_unlock_irqrestore(&data->lock, flags); +#ifdef CONFIG_HID_PICOLCD_FB + /* short-circuit FB as early as possible in order to + * avoid long delays if we host console. + */ + if (data->fb_info) + data->fb_info->par = NULL; +#endif picolcd_exit_devfs(data); device_remove_file(&hdev->dev, &dev_attr_operation_mode); @@ -2660,6 +2752,10 @@ static int __init picolcd_init(void) static void __exit picolcd_exit(void) { hid_unregister_driver(&picolcd_driver); +#ifdef CONFIG_HID_PICOLCD_FB + flush_scheduled_work(); + WARN_ON(fb_pending); +#endif } module_init(picolcd_init); From a11b3fab94d4fb67297b76d0cb81612ebbff276e Mon Sep 17 00:00:00 2001 From: Kees Bakker Date: Fri, 2 Jul 2010 22:20:04 +0200 Subject: [PATCH 21/30] HID: hid-ids.h: Whitespace fixup, align using TABs Hmmm. There are still people who have their editor setup with tabwidth 4. Some of the entries were added with tabwidth 4, and for these people the lineup looks OK. But in the Linux kernel source we use tabwidth 8. This patch repairs that whitespace so that the number align properly. Signed-off-by: Kees Bakker Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 40 ++++++++++++++++++++-------------------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 474ea1a63051..f90ef6e85bc7 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -34,7 +34,7 @@ #define USB_DEVICE_ID_ACECAD_FLAIR 0x0004 #define USB_DEVICE_ID_ACECAD_302 0x0008 -#define USB_VENDOR_ID_ADS_TECH 0x06e1 +#define USB_VENDOR_ID_ADS_TECH 0x06e1 #define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155 #define USB_VENDOR_ID_AFATECH 0x15a4 @@ -81,12 +81,12 @@ #define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223 #define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224 #define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225 -#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229 -#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a -#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d -#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e +#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI 0x0229 +#define USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO 0x022a +#define USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS 0x022b +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI 0x022c +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO 0x022d +#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS 0x022e #define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230 #define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231 #define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232 @@ -118,8 +118,8 @@ #define USB_VENDOR_ID_AVERMEDIA 0x07ca #define USB_DEVICE_ID_AVER_FM_MR800 0xb800 -#define USB_VENDOR_ID_BELKIN 0x050d -#define USB_DEVICE_ID_FLIP_KVM 0x3201 +#define USB_VENDOR_ID_BELKIN 0x050d +#define USB_DEVICE_ID_FLIP_KVM 0x3201 #define USB_VENDOR_ID_BERKSHIRE 0x0c98 #define USB_DEVICE_ID_BERKSHIRE_PCWD 0x1140 @@ -128,7 +128,7 @@ #define USB_DEVICE_ID_BTC_EMPREX_REMOTE 0x5578 #define USB_VENDOR_ID_CANDO 0x2087 -#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01 +#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01 #define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03 #define USB_VENDOR_ID_CH 0x068e @@ -174,7 +174,7 @@ #define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a #define USB_VENDOR_ID_DELORME 0x1163 -#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 +#define USB_DEVICE_ID_DELORME_EARTHMATE 0x0100 #define USB_DEVICE_ID_DELORME_EM_LT20 0x0200 #define USB_VENDOR_ID_DMI 0x0c0b @@ -201,7 +201,7 @@ #define USB_VENDOR_ID_ETURBOTOUCH 0x22b9 #define USB_DEVICE_ID_ETURBOTOUCH 0x0006 -#define USB_VENDOR_ID_EZKEY 0x0518 +#define USB_VENDOR_ID_EZKEY 0x0518 #define USB_DEVICE_ID_BTC_8193 0x0002 #define USB_VENDOR_ID_GAMERON 0x0810 @@ -284,7 +284,7 @@ #define USB_VENDOR_ID_GYRATION 0x0c16 #define USB_DEVICE_ID_GYRATION_REMOTE 0x0002 -#define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003 +#define USB_DEVICE_ID_GYRATION_REMOTE_2 0x0003 #define USB_VENDOR_ID_HAPP 0x078b #define USB_DEVICE_ID_UGCI_DRIVING 0x0010 @@ -380,10 +380,10 @@ #define USB_DEVICE_ID_GENIUS_KB29E 0x3004 #define USB_VENDOR_ID_NATIONAL_SEMICONDUCTOR 0x0400 -#define USB_DEVICE_ID_N_S_HARMONY 0xc359 +#define USB_DEVICE_ID_N_S_HARMONY 0xc359 -#define USB_VENDOR_ID_NATSU 0x08b7 -#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001 +#define USB_VENDOR_ID_NATSU 0x08b7 +#define USB_DEVICE_ID_NATSU_GAMEPAD 0x0001 #define USB_VENDOR_ID_NCR 0x0404 #define USB_DEVICE_ID_NCR_FIRST 0x0300 @@ -395,7 +395,7 @@ #define USB_VENDOR_ID_NEXTWINDOW 0x1926 #define USB_DEVICE_ID_NEXTWINDOW_TOUCHSCREEN 0x0003 -#define USB_VENDOR_ID_NTRIG 0x1b96 +#define USB_VENDOR_ID_NTRIG 0x1b96 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001 #define USB_VENDOR_ID_ONTRAK 0x0a07 @@ -412,7 +412,7 @@ #define USB_VENDOR_ID_PETALYNX 0x18b1 #define USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE 0x0037 -#define USB_VENDOR_ID_PHILIPS 0x0471 +#define USB_VENDOR_ID_PHILIPS 0x0471 #define USB_DEVICE_ID_PHILIPS_IEEE802154_DONGLE 0x0617 #define USB_VENDOR_ID_PLAYDOTCOM 0x0b43 @@ -469,8 +469,8 @@ #define USB_VENDOR_ID_TURBOX 0x062a #define USB_DEVICE_ID_TURBOX_KEYBOARD 0x0201 -#define USB_VENDOR_ID_TWINHAN 0x6253 -#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100 +#define USB_VENDOR_ID_TWINHAN 0x6253 +#define USB_DEVICE_ID_TWINHAN_IR_REMOTE 0x0100 #define USB_VENDOR_ID_UCLOGIC 0x5543 #define USB_DEVICE_ID_UCLOGIC_TABLET_PF1209 0x0042 From 540010812179a16d3d00fb8363bb06ee83af25b8 Mon Sep 17 00:00:00 2001 From: Kees Bakker Date: Tue, 13 Jul 2010 22:50:51 +0200 Subject: [PATCH 22/30] HID: Add support for Conceptronic CLLRCMCE There is only one extra button for Conceptronic that wasn't yet present. The button has code 0xffbc0027 and the description is "Toggle between display ratios". So I picked KEY_MODE for this button. Signed-off-by: Kees Bakker Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 5 +++-- drivers/hid/hid-core.c | 1 + drivers/hid/hid-ids.h | 3 +++ drivers/hid/hid-topseed.c | 5 +++++ 4 files changed, 12 insertions(+), 2 deletions(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 434099369058..9d0a65deb200 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -417,10 +417,11 @@ config SMARTJOYPLUS_FF enable force feedback support for it. config HID_TOPSEED - tristate "TopSeed Cyberlink remote control support" + tristate "TopSeed Cyberlink, BTC Emprex, Conceptronic remote control support" depends on USB_HID ---help--- - Say Y if you have a TopSeed Cyberlink or BTC Emprex remote control. + Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic + CLLRCMCE remote control. config HID_THRUSTMASTER tristate "ThrustMaster devices support" diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 866e54ec5fb2..74acfc50f533 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1375,6 +1375,7 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb653) }, { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) }, { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, + { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 31601eef25dd..6408d3b76886 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -472,6 +472,9 @@ #define USB_VENDOR_ID_THRUSTMASTER 0x044f +#define USB_VENDOR_ID_TOPSEED2 0x1784 +#define USB_DEVICE_ID_TOPSEED2_RF_COMBO 0x0004 + #define USB_VENDOR_ID_TOUCHPACK 0x1bfd #define USB_DEVICE_ID_TOUCHPACK_RTS 0x1688 diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c index 2eebdcc57bcf..5771f851f856 100644 --- a/drivers/hid/hid-topseed.c +++ b/drivers/hid/hid-topseed.c @@ -6,6 +6,9 @@ * * Modified to also support BTC "Emprex 3009URF III Vista MCE Remote" by * Wayne Thomas 2010. + * + * Modified to support Conceptronic CLLRCMCE by + * Kees Bakker 2010. */ /* @@ -34,6 +37,7 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi, case 0x00d: ts_map_key_clear(KEY_MEDIA); break; case 0x024: ts_map_key_clear(KEY_MENU); break; case 0x025: ts_map_key_clear(KEY_TV); break; + case 0x027: ts_map_key_clear(KEY_MODE); break; case 0x031: ts_map_key_clear(KEY_AUDIO); break; case 0x032: ts_map_key_clear(KEY_TEXT); break; case 0x033: ts_map_key_clear(KEY_CHANNEL); break; @@ -60,6 +64,7 @@ static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi, static const struct hid_device_id ts_devices[] = { { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) }, { HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) }, + { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) }, { } }; MODULE_DEVICE_TABLE(hid, ts_devices); From 8c8b01c38a70661d663175d355fdea85ca082272 Mon Sep 17 00:00:00 2001 From: Forest Bond Date: Tue, 13 Jul 2010 23:50:57 +0200 Subject: [PATCH 23/30] HID: ignore digitizer usage Undefined (0x00) SMART Technologies has recommended this change to fix a problem reported with SMART Board series interactive whiteboards. A description of the device-specific symptom follows: When the board is connected my mouse bounces up to the top left corner. Bjorn has tested this fix with model SB680. Tested-by: Bjorn Behrendt Signed-off-by: Forest Bond Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 7a0d2e4661a1..6b10e5afe770 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -301,6 +301,9 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_UP_DIGITIZER: switch (usage->hid & 0xff) { + case 0x00: /* Undefined */ + goto ignore; + case 0x30: /* TipPressure */ if (!test_bit(BTN_TOUCH, input->keybit)) { device->quirks |= HID_QUIRK_NOTOUCH; From bd25f4dd6972755579d0ea50d1a5ace2e9b00d1a Mon Sep 17 00:00:00 2001 From: Arnd Bergmann Date: Sun, 11 Jul 2010 15:34:05 +0200 Subject: [PATCH 24/30] HID: hiddev: use usb_find_interface, get rid of BKL This removes the private hiddev_table in the usbhid driver and changes it to use usb_find_interface instead. The advantage is that we can avoid the race between usb_register_dev and usb_open and no longer need the big kernel lock. This doesn't introduce race condition -- the intf pointer could be invalidated only in hiddev_disconnect() through usb_deregister_dev(), but that will block on minor_rwsem and not actually remove the device until usb_open(). Signed-off-by: Arnd Bergmann Cc: Jiri Kosina Cc: "Greg Kroah-Hartman" Signed-off-by: Jiri Kosina --- drivers/hid/usbhid/hiddev.c | 54 +++++++++---------------------------- 1 file changed, 12 insertions(+), 42 deletions(-) diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index c24d2fa3e3b6..254a003af048 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -67,7 +67,7 @@ struct hiddev_list { struct mutex thread_lock; }; -static struct hiddev *hiddev_table[HIDDEV_MINORS]; +static struct usb_driver hiddev_driver; /* * Find a report, given the report's type and ID. The ID can be specified @@ -265,22 +265,19 @@ static int hiddev_release(struct inode * inode, struct file * file) static int hiddev_open(struct inode *inode, struct file *file) { struct hiddev_list *list; - int res, i; + struct usb_interface *intf; + struct hiddev *hiddev; + int res; - /* See comment in hiddev_connect() for BKL explanation */ - lock_kernel(); - i = iminor(inode) - HIDDEV_MINOR_BASE; - - if (i >= HIDDEV_MINORS || i < 0 || !hiddev_table[i]) + intf = usb_find_interface(&hiddev_driver, iminor(inode)); + if (!intf) return -ENODEV; + hiddev = usb_get_intfdata(intf); if (!(list = kzalloc(sizeof(struct hiddev_list), GFP_KERNEL))) return -ENOMEM; mutex_init(&list->thread_lock); - - list->hiddev = hiddev_table[i]; - - + list->hiddev = hiddev; file->private_data = list; /* @@ -289,7 +286,7 @@ static int hiddev_open(struct inode *inode, struct file *file) */ if (list->hiddev->exist) { if (!list->hiddev->open++) { - res = usbhid_open(hiddev_table[i]->hid); + res = usbhid_open(hiddev->hid); if (res < 0) { res = -EIO; goto bail; @@ -301,12 +298,12 @@ static int hiddev_open(struct inode *inode, struct file *file) } spin_lock_irq(&list->hiddev->list_lock); - list_add_tail(&list->node, &hiddev_table[i]->list); + list_add_tail(&list->node, &hiddev->list); spin_unlock_irq(&list->hiddev->list_lock); if (!list->hiddev->open++) if (list->hiddev->exist) { - struct hid_device *hid = hiddev_table[i]->hid; + struct hid_device *hid = hiddev->hid; res = usbhid_get_power(hid); if (res < 0) { res = -EIO; @@ -314,13 +311,10 @@ static int hiddev_open(struct inode *inode, struct file *file) } usbhid_open(hid); } - - unlock_kernel(); return 0; bail: file->private_data = NULL; kfree(list); - unlock_kernel(); return res; } @@ -894,37 +888,14 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) hid->hiddev = hiddev; hiddev->hid = hid; hiddev->exist = 1; - - /* - * BKL here is used to avoid race after usb_register_dev(). - * Once the device node has been created, open() could happen on it. - * The code below will then fail, as hiddev_table hasn't been - * updated. - * - * The obvious fix -- introducing mutex to guard hiddev_table[] - * doesn't work, as usb_open() and usb_register_dev() both take - * minor_rwsem, thus we'll have ABBA deadlock. - * - * Before BKL pushdown, usb_open() had been acquiring it in right - * order, so _open() was safe to use it to protect from this race. - * Now the order is different, but AB-BA deadlock still doesn't occur - * as BKL is dropped on schedule() (i.e. while sleeping on - * minor_rwsem). Fugly. - */ - lock_kernel(); + usb_set_intfdata(usbhid->intf, usbhid); retval = usb_register_dev(usbhid->intf, &hiddev_class); if (retval) { err_hid("Not able to get a minor for this device."); hid->hiddev = NULL; - unlock_kernel(); kfree(hiddev); return -1; - } else { - hid->minor = usbhid->intf->minor; - hiddev_table[usbhid->intf->minor - HIDDEV_MINOR_BASE] = hiddev; } - unlock_kernel(); - return 0; } @@ -942,7 +913,6 @@ void hiddev_disconnect(struct hid_device *hid) hiddev->exist = 0; mutex_unlock(&hiddev->existancelock); - hiddev_table[hiddev->hid->minor - HIDDEV_MINOR_BASE] = NULL; usb_deregister_dev(usbhid->intf, &hiddev_class); if (hiddev->open) { From fc99f22c5de2177431cada350417ac6e353380c7 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 12 Jul 2010 19:28:26 +0200 Subject: [PATCH 25/30] HID: hid-input.c: indentation fixes Signed-off-by: Daniel Mack Cc: Jiri Kosina Cc: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-input.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c index 7a0d2e4661a1..36c214877f77 100644 --- a/drivers/hid/hid-input.c +++ b/drivers/hid/hid-input.c @@ -199,11 +199,11 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_GD_MOUSE: case HID_GD_POINTER: code += 0x110; break; case HID_GD_JOYSTICK: - if (code <= 0xf) - code += BTN_JOYSTICK; - else - code += BTN_TRIGGER_HAPPY; - break; + if (code <= 0xf) + code += BTN_JOYSTICK; + else + code += BTN_TRIGGER_HAPPY; + break; case HID_GD_GAMEPAD: code += 0x130; break; default: switch (field->physical) { @@ -480,7 +480,7 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel case HID_UP_LOGIVENDOR: goto ignore; - + case HID_UP_PID: switch (usage->hid & HID_USAGE) { case 0xa4: map_key_clear(BTN_DEAD); break; @@ -586,9 +586,9 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hat_dir = (value - usage->hat_min) * 8 / (usage->hat_max - usage->hat_min + 1) + 1; if (hat_dir < 0 || hat_dir > 8) hat_dir = 0; input_event(input, usage->type, usage->code , hid_hat_to_axis[hat_dir].x); - input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y); - return; - } + input_event(input, usage->type, usage->code + 1, hid_hat_to_axis[hat_dir].y); + return; + } if (usage->hid == (HID_UP_DIGITIZER | 0x003c)) { /* Invert */ *quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT); From 3a343ee4509c982552b35fbc99d3213f3bb1acde Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 12 Jul 2010 19:28:27 +0200 Subject: [PATCH 26/30] HID: add HID_QUIRK_HIDINPUT_FORCE For devices with exotic HID report descriptors, it might be necessary to make the HID core force the registration of an input device. Make that possible by introducing a new quirk type. Signed-off-by: Daniel Mack Cc: Jiri Kosina Cc: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 2 ++ include/linux/hid.h | 1 + 2 files changed, 3 insertions(+) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 866e54ec5fb2..7ccee899b59e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1157,6 +1157,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask) if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE) connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV); + if (hdev->quirks & HID_QUIRK_HIDINPUT_FORCE) + connect_mask |= HID_CONNECT_HIDINPUT_FORCE; if (hdev->bus != BUS_USB) connect_mask &= ~HID_CONNECT_HIDDEV; if (hid_hiddev(hdev)) diff --git a/include/linux/hid.h b/include/linux/hid.h index 895001f7f4b2..42a0f1d11365 100644 --- a/include/linux/hid.h +++ b/include/linux/hid.h @@ -311,6 +311,7 @@ struct hid_item { #define HID_QUIRK_HIDDEV_FORCE 0x00000010 #define HID_QUIRK_BADPAD 0x00000020 #define HID_QUIRK_MULTI_INPUT 0x00000040 +#define HID_QUIRK_HIDINPUT_FORCE 0x00000080 #define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000 #define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000 #define HID_QUIRK_NO_INIT_REPORTS 0x20000000 From 70c7c9c4438fc3ca573744c5448df90dbcc5e159 Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Mon, 12 Jul 2010 19:28:28 +0200 Subject: [PATCH 27/30] HID: Force input registration for "VEC footpedal" These devices report a usage page of type "consumer" and a usage of "Programmable buttons". They are hence ignored by the hid-input layer. Force the registration of an input device by using the new quirk type HID_QUIRK_HIDINPUT_FORCE. Signed-off-by: Daniel Mack Cc: Jiri Kosina Cc: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/hid-ids.h | 2 ++ drivers/hid/usbhid/hid-quirks.c | 2 ++ 2 files changed, 4 insertions(+) diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 31601eef25dd..d42c88fea90e 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -526,5 +526,7 @@ #define USB_DEVICE_ID_KYE_ERGO_525V 0x0087 #define USB_DEVICE_ID_KYE_GPEN_560 0x5003 +#define USB_VENDOR_ID_PI_ENGINEERING 0x05f3 +#define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff #endif diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c index 5f5aa39b3988..2643d3147621 100644 --- a/drivers/hid/usbhid/hid-quirks.c +++ b/drivers/hid/usbhid/hid-quirks.c @@ -75,6 +75,8 @@ static const struct hid_blacklist { { USB_VENDOR_ID_WISEGROUP_LTD, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, { USB_VENDOR_ID_WISEGROUP_LTD2, USB_DEVICE_ID_SMARTJOY_DUAL_PLUS, HID_QUIRK_NOGET | HID_QUIRK_MULTI_INPUT }, + { USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE }, + { 0, 0 } }; From c0dbcc33c652a0646542560de29a1c3f1ab7169f Mon Sep 17 00:00:00 2001 From: Sergei Kolzun Date: Mon, 19 Jul 2010 12:13:23 +0200 Subject: [PATCH 28/30] HID: add ACRUX game controller force feedback support Adds force feedback support for ACRUX USB game controllers. These devices are mass produced in China by several vendors. Signed-off-by: Sergei Kolzun Signed-off-by: Dmitry Torokhov Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 9 +++ drivers/hid/Makefile | 1 + drivers/hid/hid-axff.c | 172 +++++++++++++++++++++++++++++++++++++++++ drivers/hid/hid-core.c | 3 + drivers/hid/hid-ids.h | 2 + 5 files changed, 187 insertions(+) create mode 100644 drivers/hid/hid-axff.c diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 434099369058..c25865f14a6c 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -68,6 +68,15 @@ config HID_A4TECH ---help--- Support for A4 tech X5 and WOP-35 / Trust 450L mice. +config HID_ACRUX_FF + tristate "ACRUX force feedback support" + depends on USB_HID + default !EMBEDDED + select INPUT_FF_MEMLESS + ---help--- + Say Y here if you want to enable force feedback support for ACRUX + game controllers. + config HID_APPLE tristate "Apple" if EMBEDDED depends on (USB_HID || BT_HIDP) diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index 987fa0627367..19071b70a80f 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -24,6 +24,7 @@ endif obj-$(CONFIG_HID_3M_PCT) += hid-3m-pct.o obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o +obj-$(CONFIG_HID_ACRUX_FF) += hid-axff.o obj-$(CONFIG_HID_APPLE) += hid-apple.o obj-$(CONFIG_HID_BELKIN) += hid-belkin.o obj-$(CONFIG_HID_CANDO) += hid-cando.o diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c new file mode 100644 index 000000000000..f42ee140738a --- /dev/null +++ b/drivers/hid/hid-axff.c @@ -0,0 +1,172 @@ +/* + * Force feedback support for ACRUX game controllers + * + * From what I have gathered, these devices are mass produced in China + * by several vendors. They often share the same design as the original + * Xbox 360 controller. + * + * 1a34:0802 "ACRUX USB GAMEPAD 8116" + * - tested with a EXEQ EQ-PCU-02090 game controller. + * + * Copyright (c) 2010 Sergei Kolzun + */ + +/* + * 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 + */ + +#include +#include +#include +#include + +#include "hid-ids.h" +#include "usbhid/usbhid.h" + +struct axff_device { + struct hid_report *report; +}; + +static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect) +{ + struct hid_device *hid = input_get_drvdata(dev); + struct axff_device *axff = data; + int left, right; + + left = effect->u.rumble.strong_magnitude; + right = effect->u.rumble.weak_magnitude; + + dbg_hid("called with 0x%04x 0x%04x", left, right); + + left = left * 0xff / 0xffff; + right = right * 0xff / 0xffff; + + axff->report->field[0]->value[0] = left; + axff->report->field[1]->value[0] = right; + axff->report->field[2]->value[0] = left; + axff->report->field[3]->value[0] = right; + dbg_hid("running with 0x%02x 0x%02x", left, right); + usbhid_submit_report(hid, axff->report, USB_DIR_OUT); + + return 0; +} + +static int axff_init(struct hid_device *hid) +{ + struct axff_device *axff; + struct hid_report *report; + struct hid_input *hidinput = list_first_entry(&hid->inputs, 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)) { + dev_err(&hid->dev, "no output reports found\n"); + return -ENODEV; + } + + report = list_first_entry(report_list, struct hid_report, list); + + if (report->maxfield < 4) { + dev_err(&hid->dev, "no fields in the report: %d\n", report->maxfield); + return -ENODEV; + } + + axff = kzalloc(sizeof(struct axff_device), GFP_KERNEL); + if (!axff) + return -ENOMEM; + + set_bit(FF_RUMBLE, dev->ffbit); + + error = input_ff_create_memless(dev, axff, axff_play); + if (error) + goto err_free_mem; + + axff->report = report; + axff->report->field[0]->value[0] = 0x00; + axff->report->field[1]->value[0] = 0x00; + axff->report->field[2]->value[0] = 0x00; + axff->report->field[3]->value[0] = 0x00; + usbhid_submit_report(hid, axff->report, USB_DIR_OUT); + + dev_info(&hid->dev, "Force Feedback for ACRUX game controllers by Sergei Kolzun\n"); + + return 0; + +err_free_mem: + kfree(axff); + return error; +} + +static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + int error; + + dev_dbg(&hdev->dev, "ACRUX HID hardware probe..."); + + error = hid_parse(hdev); + if (error) { + dev_err(&hdev->dev, "parse failed\n"); + return error; + } + + error = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF); + if (error) { + dev_err(&hdev->dev, "hw start failed\n"); + return error; + } + + error = axff_init(hdev); + if (error) { + /* + * Do not fail device initialization completely as device + * may still be partially operable, just warn. + */ + dev_warn(&hdev->dev, + "Failed to enable force feedback support, error: %d\n", + error); + } + + return 0; +} + +static const struct hid_device_id ax_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), }, + { } +}; +MODULE_DEVICE_TABLE(hid, ax_devices); + +static struct hid_driver ax_driver = { + .name = "acrux", + .id_table = ax_devices, + .probe = ax_probe, +}; + +static int __init ax_init(void) +{ + return hid_register_driver(&ax_driver); +} + +static void __exit ax_exit(void) +{ + hid_unregister_driver(&ax_driver); +} + +module_init(ax_init); +module_exit(ax_exit); + +MODULE_AUTHOR("Sergei Kolzun"); +MODULE_DESCRIPTION("Force feedback support for ACRUX game controllers"); +MODULE_LICENSE("GPL"); diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 866e54ec5fb2..a4c779bbbc7a 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1239,6 +1239,9 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M2256) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_WCP32PU) }, { HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_X5_005D) }, +#if defined(CONFIG_HID_ACRUX_FF) || defined(CONFIG_HID_ACRUX_FF_MODULE) + { HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) }, +#endif { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) }, { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 31601eef25dd..787ce5816388 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -34,6 +34,8 @@ #define USB_DEVICE_ID_ACECAD_FLAIR 0x0004 #define USB_DEVICE_ID_ACECAD_302 0x0008 +#define USB_VENDOR_ID_ACRUX 0x1a34 + #define USB_VENDOR_ID_ADS_TECH 0x06e1 #define USB_DEVICE_ID_ADS_TECH_RADIO_SI470X 0xa155 From 7d3d42a79519df4cd62c3aa5d9ae2d77ebbf8fab Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Mon, 19 Jul 2010 12:13:57 +0200 Subject: [PATCH 29/30] HID: fix up Kconfig entry for ACRUX driver Remove 'default !EMBEDDED' from ACRUX force feedback driver entry. See commit message of 73d5e8f77e88 ("HID: fix up 'EMBEDDED' mess in Kconfig") for explanation and reasoning. Signed-off-by: Jiri Kosina --- drivers/hid/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index c25865f14a6c..2e91307d8d79 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -71,7 +71,6 @@ config HID_A4TECH config HID_ACRUX_FF tristate "ACRUX force feedback support" depends on USB_HID - default !EMBEDDED select INPUT_FF_MEMLESS ---help--- Say Y here if you want to enable force feedback support for ACRUX From d5e0a06f17a0ffb0eb08a5bd7b18f00af70d9a12 Mon Sep 17 00:00:00 2001 From: Jiri Kosina Date: Tue, 20 Jul 2010 17:48:48 +0200 Subject: [PATCH 30/30] Revert "HID: add support for the Wacom Intuos 4 wireless" This reverts commit ed9eac5b493c679ef5fc52273758fe334de82714. As reported by Bastien Nocera, the device actually uses a completely different protocol, so simply adding VID/PID doesn't work and completely new driver will need to be written. Reported-by: Bastien Nocera Signed-off-by: Jiri Kosina --- drivers/hid/hid-core.c | 1 - drivers/hid/hid-ids.h | 1 - drivers/hid/hid-wacom.c | 2 +- 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c index 74acfc50f533..dd3ddb142c2e 100644 --- a/drivers/hid/hid-core.c +++ b/drivers/hid/hid-core.c @@ -1379,7 +1379,6 @@ static const struct hid_device_id hid_blacklist[] = { { HID_USB_DEVICE(USB_VENDOR_ID_TWINHAN, USB_DEVICE_ID_TWINHAN_IR_REMOTE) }, { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_SMARTJOY_PLUS) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) }, { HID_USB_DEVICE(USB_VENDOR_ID_ZYDACRON, USB_DEVICE_ID_ZYDACRON_REMOTE_CONTROL) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index 6408d3b76886..be5a8929dd0c 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -503,7 +503,6 @@ #define USB_VENDOR_ID_WACOM 0x056a #define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81 -#define USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH 0xbd #define USB_VENDOR_ID_WISEGROUP 0x0925 #define USB_DEVICE_ID_SMARTJOY_PLUS 0x0005 diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c index 1e051f1171e4..807dcd1555a6 100644 --- a/drivers/hid/hid-wacom.c +++ b/drivers/hid/hid-wacom.c @@ -436,7 +436,7 @@ static void wacom_remove(struct hid_device *hdev) static const struct hid_device_id wacom_devices[] = { { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) }, - { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) }, + { } }; MODULE_DEVICE_TABLE(hid, wacom_devices);