Merge branches 'magicmouse', 'roccat' and 'vec-pedal' into for-linus
authorJiri Kosina <jkosina@suse.cz>
Wed, 4 Aug 2010 13:31:13 +0000 (15:31 +0200)
committerJiri Kosina <jkosina@suse.cz>
Wed, 4 Aug 2010 13:31:13 +0000 (15:31 +0200)
Conflicts:
drivers/hid/hid-ids.h

17 files changed:
Documentation/ABI/testing/sysfs-driver-hid-roccat-kone
drivers/hid/Kconfig
drivers/hid/Makefile
drivers/hid/hid-axff.c [new file with mode: 0644]
drivers/hid/hid-core.c
drivers/hid/hid-elecom.c [new file with mode: 0644]
drivers/hid/hid-ids.h
drivers/hid/hid-input.c
drivers/hid/hid-magicmouse.c
drivers/hid/hid-picolcd.c
drivers/hid/hid-roccat-kone.c
drivers/hid/hid-roccat-kone.h
drivers/hid/hid-roccat.c
drivers/hid/hid-roccat.h
drivers/hid/hid-topseed.c
drivers/hid/hid-wacom.c
drivers/hid/hidraw.c

index 88340a23ce91423af01a0f8465e037d291fecaba..063bda7fe7079ad538e5a54f3fcec1930d3ff56c 100644 (file)
@@ -33,19 +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/<busnum>-<devnum>:<config num>.<interface num>/kone_driver_version
-Date:          March 2010
-Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
-Description:   When read, this file returns the driver version.
-               The format of the string is "v<major>.<minor>.<patchlevel>".
-               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/<busnum>-<devnum>:<config num>.<interface num>/profile[1-5]
 Date:          March 2010
 Contact:       Stefan Achatz <erazor_de@users.sourceforge.net>
index 434099369058ad42e72d5ba1de85ae2ed6445de9..6369ba7f96f8c0cb2bce6ae0301fd2962027f914 100644 (file)
@@ -68,6 +68,14 @@ 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
+       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)
@@ -148,6 +156,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
@@ -417,10 +431,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"
index 987fa062736708ee99ed5181c5c5d26302231a7f..46f037f3df80ae4eefc30b64df583ff48b894534 100644 (file)
@@ -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
@@ -32,6 +33,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-axff.c b/drivers/hid/hid-axff.c
new file mode 100644 (file)
index 0000000..f42ee14
--- /dev/null
@@ -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 <x0r@dv-life.ru>
+ */
+
+/*
+ * 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 <linux/input.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/hid.h>
+
+#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<x0r@dv-life.ru>\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");
index 7ccee899b59ef6fb87863266848ac11cb8fac4bc..f4f04e4ef943ee098c27cb83360827a1534a9a39 100644 (file)
@@ -1241,6 +1241,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) },
@@ -1296,6 +1299,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) },
@@ -1377,10 +1381,10 @@ 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) },
-       { 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-elecom.c b/drivers/hid/hid-elecom.c
new file mode 100644 (file)
index 0000000..7a40878
--- /dev/null
@@ -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 <Richard.Nauber@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.
+ */
+
+#include <linux/device.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+
+#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");
index d42c88fea90e01270eb25eef13b00ba881131821..fa053ab4d570c7ae268cef5a0e8fcdc9b8a8ab8b 100644 (file)
@@ -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
 
 #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
 #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
 #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
 #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
 #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
 
 #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_EZKEY            0x0518
+#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
 
 #define USB_VENDOR_ID_GAMERON          0x0810
 #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
 
 #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
 #define USB_VENDOR_ID_MONTEREY         0x0566
 #define USB_DEVICE_ID_GENIUS_KB29E     0x3004
 
+#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_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_NEC              0x073e
 #define USB_DEVICE_ID_NEC_USB_GAME_PAD 0x0301
 
 #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_DEVICE_ID_NTRIG_TOUCH_SCREEN_1   0x0003
 #define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_2   0x0004
 #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_PI_ENGINEERING   0x05f3
+#define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff
+
 #define USB_VENDOR_ID_PLAYDOTCOM       0x0b43
 #define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII     0x0003
 
 #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
 
 #define USB_VENDOR_ID_THRUSTMASTER     0x044f
 
-#define USB_VENDOR_ID_TOUCHPACK                0x1bfd
-#define USB_DEVICE_ID_TOUCHPACK_RTS    0x1688
+#define USB_VENDOR_ID_TOPSEED          0x0766
+#define USB_DEVICE_ID_TOPSEED_CYBERLINK        0x0204
+
+#define USB_VENDOR_ID_TOPSEED2         0x1784
+#define USB_DEVICE_ID_TOPSEED2_RF_COMBO        0x0004
 
 #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
 
-#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
 
 #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
 #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
-
-#define USB_VENDOR_ID_PI_ENGINEERING   0x05f3
-#define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff
-
 #endif
index 36c214877f7722d59fbbe8626ca3e6f1ff358585..d8cc790238489119445db3f6b4a0f1234f33e889 100644 (file)
@@ -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;
index f10d56a15f2103699003e8cf13d2c07f0ac6e192..319b0e57ee41f1cdbebafb833989b7a3507c7440 100644 (file)
@@ -30,6 +30,21 @@ 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");
+
 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)");
@@ -50,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.
@@ -78,8 +95,10 @@ struct magicmouse_sc {
        struct {
                short x;
                short y;
+               short scroll_x;
                short scroll_y;
                u8 size;
+               u8 down;
        } touches[16];
        int tracking_ids[16];
 };
@@ -141,7 +160,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)
@@ -152,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;
@@ -160,42 +180,54 @@ 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) {
-               static const int accel_profile[] = {
-                       256, 228, 192, 160, 128, 96, 64, 32,
-               };
+       if (emulate_scroll_wheel) {
                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;
+               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;
-                       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];
-                       if (step != 0) {
-                               msc->touches[id].scroll_y = y;
+                       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;
                }
        }
 
        /* 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]);
@@ -215,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:
@@ -235,12 +267,26 @@ 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.
                 */
-               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
@@ -301,8 +347,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);
@@ -345,6 +393,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);
 
index 7aabf65c48ef0d4aa31b7e8f74a205d447477bbd..346f0e34987e68454dddd3393c2b24cc1f640729 100644 (file)
@@ -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 */
@@ -421,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);
@@ -440,14 +461,18 @@ 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 (!data->fb_info->par)
+                                       return; /* device lost! */
                                if (n >= HID_OUTPUT_FIFO_SIZE / 2) {
                                        usbhid_wait_io(data->hdev);
                                        n = 0;
                                }
                                picolcd_fb_send_tile(data->hdev, chip, tile);
                        }
+       data->fb_force = false;
        if (n)
                usbhid_wait_io(data->hdev);
 }
@@ -511,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)
@@ -526,29 +563,37 @@ 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;
 }
 
 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 (!data)
+               return -ENODEV;
        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;
@@ -558,24 +603,87 @@ 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;
+}
+
+/* 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;
 }
 
@@ -583,6 +691,8 @@ static int picolcd_set_par(struct fb_info *info)
 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,
@@ -660,11 +770,12 @@ 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);
+       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;
@@ -678,18 +789,29 @@ 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) + 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 + sizeof(struct picolcd_fb_cleanup_item);
+       *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;
        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;
@@ -707,18 +829,20 @@ 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 */
+       data->fb_force = 1;
        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;
@@ -737,19 +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);
-       fb_deferred_io_cleanup(info);
-       unregister_framebuffer(info);
-       vfree(fb_bitmap);
        kfree(fb_vbitmap);
 }
 
@@ -2566,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);
@@ -2623,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);
index 17f2dc04f883d0eb9462444a816d50ebf9b50b41..f77695762cb567ea45c7f2ee2822127e7f1acc04 100644 (file)
  *      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?
  */
 
@@ -277,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;
@@ -337,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;
@@ -622,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 version number.
- */
-static ssize_t kone_sysfs_show_driver_version(struct device *dev,
-               struct device_attribute *attr, char *buf)
-{
-       return snprintf(buf, PAGE_SIZE, ROCCAT_KONE_DRIVER_VERSION "\n");
-}
-
 /*
  * Read actual dpi settings.
  * Returns raw value for further processing. Refer to enum kone_polling_rates to
@@ -671,9 +654,6 @@ 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 struct attribute *kone_attributes[] = {
                &dev_attr_actual_dpi.attr,
                &dev_attr_actual_profile.attr,
@@ -681,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_driver_version.attr,
                NULL
 };
 
index 003e6f81c195d6ed1b1cb0cf2184a774db290481..130d6566ea8269e1c51a0bd604fda7378e315474 100644 (file)
@@ -14,8 +14,6 @@
 
 #include <linux/types.h>
 
-#define ROCCAT_KONE_DRIVER_VERSION "v0.3.1"
-
 #pragma pack(push)
 #pragma pack(1)
 
index e05d48edb66f540bc2048458e5c88b20721eea8d..f6e80c7ca61e53c0f9655778306ffc3e82a28b9f 100644 (file)
@@ -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 @@ exit_unlock:
        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)
index d8aae0c1fa7ea804b110eb655540c3776c469d55..09e864e9f79dcbc37f5f4fc9bb5ced38105527d9 100644 (file)
@@ -15,7 +15,7 @@
 #include <linux/hid.h>
 #include <linux/types.h>
 
-#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);
index 2eebdcc57bcf50278a509a081658e2a3e566c40a..5771f851f85693a46bd581085e25e09775fbcae5 100644 (file)
@@ -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);
index 1e051f1171e4a6e12f9afcb559a62dc2c1b757d0..807dcd1555a6911f6f3630f225b122484d1c9d80 100644 (file)
@@ -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);
index 3ccd47850677c48fe1d67b1369485a0c9f3eac03..47d70c523d93474a658bbaa5aa5b1cfb327f194b 100644 (file)
@@ -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;