summaryrefslogtreecommitdiff
path: root/drivers/hid
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/hid')
-rw-r--r--drivers/hid/Kconfig158
-rw-r--r--drivers/hid/Makefile25
-rw-r--r--drivers/hid/hid-3m-pct.c38
-rw-r--r--drivers/hid/hid-a4tech.c6
-rw-r--r--drivers/hid/hid-apple.c69
-rw-r--r--drivers/hid/hid-axff.c45
-rw-r--r--drivers/hid/hid-belkin.c4
-rw-r--r--drivers/hid/hid-cando.c4
-rw-r--r--drivers/hid/hid-cherry.c3
-rw-r--r--drivers/hid/hid-core.c179
-rw-r--r--drivers/hid/hid-cypress.c4
-rw-r--r--drivers/hid/hid-debug.c4
-rw-r--r--drivers/hid/hid-dr.c (renamed from drivers/hid/hid-drff.c)131
-rw-r--r--drivers/hid/hid-egalax.c296
-rw-r--r--drivers/hid/hid-elecom.c3
-rw-r--r--drivers/hid/hid-emsff.c161
-rw-r--r--drivers/hid/hid-gaff.c13
-rw-r--r--drivers/hid/hid-gyration.c5
-rw-r--r--drivers/hid/hid-ids.h39
-rw-r--r--drivers/hid/hid-input.c52
-rw-r--r--drivers/hid/hid-keytouch.c66
-rw-r--r--drivers/hid/hid-kye.c4
-rw-r--r--drivers/hid/hid-lcpower.c70
-rw-r--r--drivers/hid/hid-lg.c17
-rw-r--r--drivers/hid/hid-lg2ff.c9
-rw-r--r--drivers/hid/hid-lg3ff.c9
-rw-r--r--drivers/hid/hid-lg4ff.c9
-rw-r--r--drivers/hid/hid-lgff.c8
-rw-r--r--drivers/hid/hid-magicmouse.c24
-rw-r--r--drivers/hid/hid-microsoft.c7
-rw-r--r--drivers/hid/hid-monterey.c3
-rw-r--r--drivers/hid/hid-mosart.c23
-rw-r--r--drivers/hid/hid-multitouch.c568
-rw-r--r--drivers/hid/hid-ntrig.c528
-rw-r--r--drivers/hid/hid-ortek.c9
-rw-r--r--drivers/hid/hid-petalynx.c7
-rw-r--r--drivers/hid/hid-picolcd.c58
-rw-r--r--drivers/hid/hid-pl.c16
-rw-r--r--drivers/hid/hid-prodikeys.c27
-rw-r--r--drivers/hid/hid-quanta.c2
-rw-r--r--drivers/hid/hid-roccat-arvo.c450
-rw-r--r--drivers/hid/hid-roccat-arvo.h98
-rw-r--r--drivers/hid/hid-roccat-common.c62
-rw-r--r--drivers/hid/hid-roccat-common.h23
-rw-r--r--drivers/hid/hid-roccat-kone.c554
-rw-r--r--drivers/hid/hid-roccat-kone.h19
-rw-r--r--drivers/hid/hid-roccat-koneplus.c786
-rw-r--r--drivers/hid/hid-roccat-koneplus.h224
-rw-r--r--drivers/hid/hid-roccat-kovaplus.c715
-rw-r--r--drivers/hid/hid-roccat-kovaplus.h157
-rw-r--r--drivers/hid/hid-roccat-pyra.c581
-rw-r--r--drivers/hid/hid-roccat-pyra.h23
-rw-r--r--drivers/hid/hid-roccat.c104
-rw-r--r--drivers/hid/hid-roccat.h31
-rw-r--r--drivers/hid/hid-samsung.c8
-rw-r--r--drivers/hid/hid-sjoy.c16
-rw-r--r--drivers/hid/hid-sony.c31
-rw-r--r--drivers/hid/hid-stantum.c2
-rw-r--r--drivers/hid/hid-sunplus.c3
-rw-r--r--drivers/hid/hid-tmff.c27
-rw-r--r--drivers/hid/hid-topseed.c1
-rw-r--r--drivers/hid/hid-wacom.c28
-rw-r--r--drivers/hid/hid-zpff.c11
-rw-r--r--drivers/hid/hid-zydacron.c11
-rw-r--r--drivers/hid/hidraw.c144
-rw-r--r--drivers/hid/usbhid/Kconfig2
-rw-r--r--drivers/hid/usbhid/Makefile6
-rw-r--r--drivers/hid/usbhid/hid-core.c140
-rw-r--r--drivers/hid/usbhid/hid-pidff.c164
-rw-r--r--drivers/hid/usbhid/hid-quirks.c3
-rw-r--r--drivers/hid/usbhid/hiddev.c241
-rw-r--r--drivers/hid/usbhid/usbhid.h1
-rw-r--r--drivers/hid/usbhid/usbkbd.c24
73 files changed, 5307 insertions, 2086 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig
index 3052e2969ad0..b7ec4057841d 100644
--- a/drivers/hid/Kconfig
+++ b/drivers/hid/Kconfig
@@ -62,24 +62,30 @@ config HID_3M_PCT
Support for 3M PCT touch screens.
config HID_A4TECH
- tristate "A4 tech mice" if EMBEDDED
+ tristate "A4 tech mice" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice.
-config HID_ACRUX_FF
- tristate "ACRUX force feedback"
+config HID_ACRUX
+ tristate "ACRUX game controller support"
depends on USB_HID
+ ---help---
+ Say Y here if you want to enable support for ACRUX game controllers.
+
+config HID_ACRUX_FF
+ tristate "ACRUX force feedback support"
+ depends on HID_ACRUX
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 {i,Power,Mac}Books" if EMBEDDED
+ tristate "Apple {i,Power,Mac}Books" if EXPERT
depends on (USB_HID || BT_HIDP)
- default !EMBEDDED
+ default !EXPERT
---help---
Support for some Apple devices which less or more break
HID specification.
@@ -88,9 +94,9 @@ config HID_APPLE
MacBooks, MacBook Pros and Apple Aluminum.
config HID_BELKIN
- tristate "Belkin Flip KVM and Wireless keyboard" if EMBEDDED
+ tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Belkin Flip KVM and Wireless keyboard.
@@ -101,16 +107,16 @@ config HID_CANDO
Support for Cando dual touch panel.
config HID_CHERRY
- tristate "Cherry Cymotion keyboard" if EMBEDDED
+ tristate "Cherry Cymotion keyboard" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Cherry Cymotion keyboard.
config HID_CHICONY
- tristate "Chicony Tactical pad" if EMBEDDED
+ tristate "Chicony Tactical pad" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Chicony Tactical pad.
@@ -130,9 +136,9 @@ config HID_PRODIKEYS
and some additional multimedia keys.
config HID_CYPRESS
- tristate "Cypress mouse and barcode readers" if EMBEDDED
+ tristate "Cypress mouse and barcode readers" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for cypress mouse and barcode readers.
@@ -140,7 +146,12 @@ config HID_DRAGONRISE
tristate "DragonRise Inc. game controller"
depends on USB_HID
---help---
- Say Y here if you have DragonRise Inc.game controllers.
+ Say Y here if you have DragonRise Inc. game controllers.
+ These might be branded as:
+ - Tesun USB-703
+ - Media-tech MT1504 "Rogue"
+ - DVTech JS19 "Gear"
+ - Defender Game Master
config DRAGONRISE_FF
bool "DragonRise Inc. force feedback"
@@ -150,11 +161,15 @@ config DRAGONRISE_FF
Say Y here if you want to enable force feedback support for DragonRise Inc.
game controllers.
-config HID_EGALAX
- tristate "eGalax multi-touch panel"
+config HID_EMS_FF
+ tristate "EMS Production Inc. force feedback support"
depends on USB_HID
+ select INPUT_FF_MEMLESS
---help---
- Support for the eGalax dual-touch panel.
+ Say Y here if you want to enable force feedback support for devices by
+ EMS Production Ltd.
+ Currently the following devices are known to be supported:
+ - Trio Linker Plus II
config HID_ELECOM
tristate "ELECOM BM084 bluetooth mouse"
@@ -163,16 +178,24 @@ config HID_ELECOM
Support for the ELECOM BM084 (bluetooth mouse).
config HID_EZKEY
- tristate "Ezkey BTC 8193 keyboard" if EMBEDDED
+ tristate "Ezkey BTC 8193 keyboard" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Ezkey BTC 8193 keyboard.
+config HID_KEYTOUCH
+ tristate "Keyoutch HID devices"
+ depends on USB_HID
+ ---help---
+ Support for Keytouch HID devices not fully compliant with
+ the specification. Currently supported:
+ - Keytouch IEC 60945
+
config HID_KYE
- tristate "Kye/Genius Ergo Mouse" if EMBEDDED
+ tristate "Kye/Genius Ergo Mouse" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Kye/Genius Ergo Mouse.
@@ -201,16 +224,22 @@ config HID_TWINHAN
Support for Twinhan IR remote control.
config HID_KENSINGTON
- tristate "Kensington Slimblade Trackball" if EMBEDDED
+ tristate "Kensington Slimblade Trackball" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Kensington Slimblade Trackball.
+config HID_LCPOWER
+ tristate "LC-Power"
+ depends on USB_HID
+ ---help---
+ Support for LC-Power RC1000MCE RF remote control.
+
config HID_LOGITECH
- tristate "Logitech devices" if EMBEDDED
+ tristate "Logitech devices" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Logitech devices that are not fully compliant with HID standard.
@@ -265,9 +294,9 @@ config HID_MAGICMOUSE
Apple Wireless "Magic" Mouse.
config HID_MICROSOFT
- tristate "Microsoft non-fully HID-compliant devices" if EMBEDDED
+ tristate "Microsoft non-fully HID-compliant devices" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Microsoft devices that are not fully compliant with HID standard.
@@ -278,12 +307,32 @@ config HID_MOSART
Support for MosArt dual-touch panels.
config HID_MONTEREY
- tristate "Monterey Genius KB29E keyboard" if EMBEDDED
+ tristate "Monterey Genius KB29E keyboard" if EXPERT
depends on USB_HID
- default !EMBEDDED
+ default !EXPERT
---help---
Support for Monterey Genius KB29E.
+config HID_MULTITOUCH
+ tristate "HID Multitouch panels"
+ depends on USB_HID
+ ---help---
+ Generic support for HID multitouch panels.
+
+ Say Y here if you have one of the following devices:
+ - Cypress TrueTouch panels
+ - Hanvon dual touch panels
+ - IrTouch Infrared USB panels
+ - Pixcir dual touch panels
+ - 'Sensing Win7-TwoFinger' panel by GeneralTouch
+ - eGalax dual-touch panels, including the
+ Joojoo and Wetab tablets
+
+ If unsure, say N.
+
+ To compile this driver as a module, choose M here: the
+ module will be called hid-multitouch.
+
config HID_NTRIG
tristate "N-Trig touch screen"
depends on USB_HID
@@ -291,10 +340,10 @@ config HID_NTRIG
Support for N-Trig touch screen.
config HID_ORTEK
- tristate "Ortek WKB-2000 wireless keyboard and mouse trackpad"
+ tristate "Ortek PKB-1700/WKB-2000 wireless keyboard and mouse trackpad"
depends on USB_HID
---help---
- Support for Ortek WKB-2000 wireless keyboard + mouse trackpad.
+ Support for Ortek PKB-1700/WKB-2000 wireless keyboard + mouse trackpad.
config HID_PANTHERLORD
tristate "Pantherlord/GreenAsia game controller"
@@ -337,8 +386,8 @@ config HID_PICOLCD
- IR
config HID_PICOLCD_FB
- bool "Framebuffer support" if EMBEDDED
- default !EMBEDDED
+ bool "Framebuffer support" if EXPERT
+ default !EXPERT
depends on HID_PICOLCD
depends on HID_PICOLCD=FB || FB=y
select FB_DEFERRED_IO
@@ -351,8 +400,8 @@ config HID_PICOLCD_FB
frambuffer device.
config HID_PICOLCD_BACKLIGHT
- bool "Backlight control" if EMBEDDED
- default !EMBEDDED
+ bool "Backlight control" if EXPERT
+ default !EXPERT
depends on HID_PICOLCD
depends on HID_PICOLCD=BACKLIGHT_CLASS_DEVICE || BACKLIGHT_CLASS_DEVICE=y
---help---
@@ -360,16 +409,16 @@ config HID_PICOLCD_BACKLIGHT
class.
config HID_PICOLCD_LCD
- bool "Contrast control" if EMBEDDED
- default !EMBEDDED
+ bool "Contrast control" if EXPERT
+ default !EXPERT
depends on HID_PICOLCD
depends on HID_PICOLCD=LCD_CLASS_DEVICE || LCD_CLASS_DEVICE=y
---help---
Provide access to PicoLCD's LCD contrast via lcd class.
config HID_PICOLCD_LEDS
- bool "GPO via leds class" if EMBEDDED
- default !EMBEDDED
+ bool "GPO via leds class" if EXPERT
+ default !EXPERT
depends on HID_PICOLCD
depends on HID_PICOLCD=LEDS_CLASS || LEDS_CLASS=y
---help---
@@ -389,17 +438,46 @@ config HID_ROCCAT
Say Y here if you have a Roccat mouse or keyboard and want OSD or
macro execution support.
+config HID_ROCCAT_COMMON
+ tristate
+
+config HID_ROCCAT_ARVO
+ tristate "Roccat Arvo keyboard support"
+ depends on USB_HID
+ select HID_ROCCAT
+ select HID_ROCCAT_COMMON
+ ---help---
+ Support for Roccat Arvo keyboard.
+
config HID_ROCCAT_KONE
tristate "Roccat Kone Mouse support"
depends on USB_HID
select HID_ROCCAT
+ select HID_ROCCAT_COMMON
---help---
Support for Roccat Kone mouse.
+config HID_ROCCAT_KONEPLUS
+ tristate "Roccat Kone[+] mouse support"
+ depends on USB_HID
+ select HID_ROCCAT
+ select HID_ROCCAT_COMMON
+ ---help---
+ Support for Roccat Kone[+] mouse.
+
+config HID_ROCCAT_KOVAPLUS
+ tristate "Roccat Kova[+] mouse support"
+ depends on USB_HID
+ select HID_ROCCAT
+ select HID_ROCCAT_COMMON
+ ---help---
+ Support for Roccat Kova[+] mouse.
+
config HID_ROCCAT_PYRA
tristate "Roccat Pyra mouse support"
depends on USB_HID
select HID_ROCCAT
+ select HID_ROCCAT_COMMON
---help---
Support for Roccat Pyra mouse.
diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile
index c335605b9200..06c68ae3abee 100644
--- a/drivers/hid/Makefile
+++ b/drivers/hid/Makefile
@@ -1,7 +1,7 @@
#
# Makefile for the HID driver
#
-hid-objs := hid-core.o hid-input.o
+hid-y := hid-core.o hid-input.o
ifdef CONFIG_DEBUG_FS
hid-objs += hid-debug.o
@@ -11,41 +11,44 @@ obj-$(CONFIG_HID) += hid.o
hid-$(CONFIG_HIDRAW) += hidraw.o
-hid-logitech-objs := hid-lg.o
+hid-logitech-y := hid-lg.o
ifdef CONFIG_LOGITECH_FF
- hid-logitech-objs += hid-lgff.o
+ hid-logitech-y += hid-lgff.o
endif
ifdef CONFIG_LOGIRUMBLEPAD2_FF
- hid-logitech-objs += hid-lg2ff.o
+ hid-logitech-y += hid-lg2ff.o
endif
ifdef CONFIG_LOGIG940_FF
- hid-logitech-objs += hid-lg3ff.o
+ hid-logitech-y += hid-lg3ff.o
endif
ifdef CONFIG_LOGIWII_FF
- hid-logitech-objs += hid-lg4ff.o
+ hid-logitech-y += hid-lg4ff.o
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_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CANDO) += hid-cando.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
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_DRAGONRISE) += hid-dr.o
+obj-$(CONFIG_HID_EMS_FF) += hid-emsff.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
+obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o
obj-$(CONFIG_HID_KYE) += hid-kye.o
+obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MICROSOFT) += hid-microsoft.o
obj-$(CONFIG_HID_MONTEREY) += hid-monterey.o
obj-$(CONFIG_HID_MOSART) += hid-mosart.o
+obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
obj-$(CONFIG_HID_ORTEK) += hid-ortek.o
obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o
@@ -54,7 +57,11 @@ obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
+obj-$(CONFIG_HID_ROCCAT_COMMON) += hid-roccat-common.o
+obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o
obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o
+obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o
+obj-$(CONFIG_HID_ROCCAT_KOVAPLUS) += hid-roccat-kovaplus.o
obj-$(CONFIG_HID_ROCCAT_PYRA) += hid-roccat-pyra.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
diff --git a/drivers/hid/hid-3m-pct.c b/drivers/hid/hid-3m-pct.c
index 02d8cd3b1b1b..5243ae2d3730 100644
--- a/drivers/hid/hid-3m-pct.c
+++ b/drivers/hid/hid-3m-pct.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
+#include <linux/input/mt.h>
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_DESCRIPTION("3M PCT multitouch panels");
@@ -27,8 +28,6 @@ MODULE_LICENSE("GPL");
#include "hid-ids.h"
#define MAX_SLOTS 60
-#define MAX_TRKID USHRT_MAX
-#define MAX_EVENTS 360
/* estimated signal-to-noise ratios */
#define SN_MOVE 2048
@@ -36,14 +35,11 @@ MODULE_LICENSE("GPL");
struct mmm_finger {
__s32 x, y, w, h;
- __u16 id;
- bool prev_touch;
bool touch, valid;
};
struct mmm_data {
struct mmm_finger f[MAX_SLOTS];
- __u16 id;
__u8 curid;
__u8 nexp, nreal;
bool touch, valid;
@@ -117,14 +113,7 @@ static int mmm_input_mapping(struct hid_device *hdev, struct hid_input *hi,
0, 1, 0, 0);
return 1;
case HID_DG_CONTACTID:
- field->logical_maximum = MAX_TRKID;
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TRACKING_ID);
- input_set_abs_params(hi->input, ABS_MT_TRACKING_ID,
- 0, MAX_TRKID, 0, 0);
- if (!hi->input->mt)
- input_mt_create_slots(hi->input, MAX_SLOTS);
- input_set_events_per_packet(hi->input, MAX_EVENTS);
+ input_mt_init_slots(hi->input, MAX_SLOTS);
return 1;
}
/* let hid-input decide for the others */
@@ -154,7 +143,6 @@ static int mmm_input_mapped(struct hid_device *hdev, struct hid_input *hi,
*/
static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
{
- struct mmm_finger *oldest = 0;
int i;
for (i = 0; i < MAX_SLOTS; ++i) {
struct mmm_finger *f = &md->f[i];
@@ -163,6 +151,7 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
continue;
}
input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER, f->touch);
if (f->touch) {
/* this finger is on the screen */
int wide = (f->w > f->h);
@@ -170,33 +159,16 @@ static void mmm_filter_event(struct mmm_data *md, struct input_dev *input)
int major = max(f->w, f->h) >> 1;
int minor = min(f->w, f->h) >> 1;
- if (!f->prev_touch)
- f->id = md->id++;
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, f->id);
input_event(input, EV_ABS, ABS_MT_POSITION_X, f->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, f->y);
input_event(input, EV_ABS, ABS_MT_ORIENTATION, wide);
input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, major);
input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, minor);
- /* touchscreen emulation: pick the oldest contact */
- if (!oldest || ((f->id - oldest->id) & (SHRT_MAX + 1)))
- oldest = f;
- } else {
- /* this finger took off the screen */
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, -1);
}
- f->prev_touch = f->touch;
f->valid = 0;
}
- /* touchscreen emulation */
- if (oldest) {
- input_event(input, EV_KEY, BTN_TOUCH, 1);
- input_event(input, EV_ABS, ABS_X, oldest->x);
- input_event(input, EV_ABS, ABS_Y, oldest->y);
- } else {
- input_event(input, EV_KEY, BTN_TOUCH, 0);
- }
+ input_mt_report_pointer_emulation(input, true);
input_sync(input);
}
@@ -274,7 +246,7 @@ static int mmm_probe(struct hid_device *hdev, const struct hid_device_id *id)
md = kzalloc(sizeof(struct mmm_data), GFP_KERNEL);
if (!md) {
- dev_err(&hdev->dev, "cannot allocate 3M data\n");
+ hid_err(hdev, "cannot allocate 3M data\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, md);
diff --git a/drivers/hid/hid-a4tech.c b/drivers/hid/hid-a4tech.c
index 1666c1684e79..902d1dfeb1b5 100644
--- a/drivers/hid/hid-a4tech.c
+++ b/drivers/hid/hid-a4tech.c
@@ -93,7 +93,7 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
a4 = kzalloc(sizeof(*a4), GFP_KERNEL);
if (a4 == NULL) {
- dev_err(&hdev->dev, "can't alloc device descriptor\n");
+ hid_err(hdev, "can't alloc device descriptor\n");
ret = -ENOMEM;
goto err_free;
}
@@ -104,13 +104,13 @@ static int a4_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c
index eaeca564a8d3..b85744fe8464 100644
--- a/drivers/hid/hid-apple.c
+++ b/drivers/hid/hid-apple.c
@@ -16,6 +16,8 @@
* any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
@@ -59,6 +61,27 @@ struct apple_key_translation {
u8 flags;
};
+static const struct apple_key_translation macbookair_fn_keys[] = {
+ { KEY_BACKSPACE, KEY_DELETE },
+ { KEY_ENTER, KEY_INSERT },
+ { KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
+ { KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY },
+ { KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY },
+ { KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY },
+ { KEY_F6, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY },
+ { KEY_F7, KEY_PLAYPAUSE, APPLE_FLAG_FKEY },
+ { KEY_F8, KEY_NEXTSONG, APPLE_FLAG_FKEY },
+ { KEY_F9, KEY_MUTE, APPLE_FLAG_FKEY },
+ { KEY_F10, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY },
+ { KEY_F11, KEY_VOLUMEUP, APPLE_FLAG_FKEY },
+ { KEY_F12, KEY_EJECTCD, APPLE_FLAG_FKEY },
+ { KEY_UP, KEY_PAGEUP },
+ { KEY_DOWN, KEY_PAGEDOWN },
+ { KEY_LEFT, KEY_HOME },
+ { KEY_RIGHT, KEY_END },
+ { }
+};
+
static const struct apple_key_translation apple_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
{ KEY_ENTER, KEY_INSERT },
@@ -146,7 +169,7 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
struct hid_usage *usage, __s32 value)
{
struct apple_sc *asc = hid_get_drvdata(hid);
- const struct apple_key_translation *trans;
+ const struct apple_key_translation *trans, *table;
if (usage->code == KEY_FN) {
asc->fn_on = !!value;
@@ -157,10 +180,16 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
if (fnmode) {
int do_translate;
- trans = apple_find_translation((hid->product < 0x21d ||
- hid->product >= 0x300) ?
- powerbook_fn_keys : apple_fn_keys,
- usage->code);
+ if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
+ hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
+ table = macbookair_fn_keys;
+ else if (hid->product < 0x21d || hid->product >= 0x300)
+ table = powerbook_fn_keys;
+ else
+ table = apple_fn_keys;
+
+ trans = apple_find_translation (table, usage->code);
+
if (trans) {
if (test_bit(usage->code, asc->pressed_fn))
do_translate = 1;
@@ -253,8 +282,8 @@ static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if ((asc->quirks & APPLE_RDESC_JIS) && *rsize >= 60 &&
rdesc[53] == 0x65 && rdesc[59] == 0x65) {
- dev_info(&hdev->dev, "fixing up MacBook JIS keyboard report "
- "descriptor\n");
+ hid_info(hdev,
+ "fixing up MacBook JIS keyboard report descriptor\n");
rdesc[53] = rdesc[59] = 0xe7;
}
return rdesc;
@@ -324,7 +353,7 @@ static int apple_probe(struct hid_device *hdev,
asc = kzalloc(sizeof(*asc), GFP_KERNEL);
if (asc == NULL) {
- dev_err(&hdev->dev, "can't alloc apple descriptor\n");
+ hid_err(hdev, "can't alloc apple descriptor\n");
return -ENOMEM;
}
@@ -334,7 +363,7 @@ static int apple_probe(struct hid_device *hdev,
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
@@ -345,7 +374,7 @@ static int apple_probe(struct hid_device *hdev,
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
@@ -440,6 +469,24 @@ static const struct hid_device_id apple_devices[] = {
.driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI),
+ .driver_data = APPLE_HAS_FN },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO),
+ .driver_data = APPLE_HAS_FN | APPLE_ISO_KEYBOARD },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS),
+ .driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
@@ -473,7 +520,7 @@ static int __init apple_init(void)
ret = hid_register_driver(&apple_driver);
if (ret)
- printk(KERN_ERR "can't register apple driver\n");
+ pr_err("can't register apple driver\n");
return ret;
}
diff --git a/drivers/hid/hid-axff.c b/drivers/hid/hid-axff.c
index f42ee140738a..b4554288de00 100644
--- a/drivers/hid/hid-axff.c
+++ b/drivers/hid/hid-axff.c
@@ -33,6 +33,8 @@
#include <linux/hid.h>
#include "hid-ids.h"
+
+#ifdef CONFIG_HID_ACRUX_FF
#include "usbhid/usbhid.h"
struct axff_device {
@@ -73,14 +75,14 @@ static int axff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output reports found\n");
+ hid_err(hid, "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);
+ hid_err(hid, "no fields in the report: %d\n", report->maxfield);
return -ENODEV;
}
@@ -101,7 +103,7 @@ static int axff_init(struct hid_device *hid)
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");
+ hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun<x0r@dv-life.ru>\n");
return 0;
@@ -109,22 +111,28 @@ err_free_mem:
kfree(axff);
return error;
}
+#else
+static inline int axff_init(struct hid_device *hid)
+{
+ return 0;
+}
+#endif
static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int error;
- dev_dbg(&hdev->dev, "ACRUX HID hardware probe...");
+ dev_dbg(&hdev->dev, "ACRUX HID hardware probe...\n");
error = hid_parse(hdev);
if (error) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "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");
+ hid_err(hdev, "hw start failed\n");
return error;
}
@@ -134,14 +142,30 @@ static int ax_probe(struct hid_device *hdev, const struct hid_device_id *id)
* Do not fail device initialization completely as device
* may still be partially operable, just warn.
*/
- dev_warn(&hdev->dev,
+ hid_warn(hdev,
"Failed to enable force feedback support, error: %d\n",
error);
}
+ /*
+ * We need to start polling device right away, otherwise
+ * it will go into a coma.
+ */
+ error = hid_hw_open(hdev);
+ if (error) {
+ dev_err(&hdev->dev, "hw open failed\n");
+ return error;
+ }
+
return 0;
}
+static void ax_remove(struct hid_device *hdev)
+{
+ hid_hw_close(hdev);
+ hid_hw_stop(hdev);
+}
+
static const struct hid_device_id ax_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802), },
{ }
@@ -149,9 +173,10 @@ static const struct hid_device_id ax_devices[] = {
MODULE_DEVICE_TABLE(hid, ax_devices);
static struct hid_driver ax_driver = {
- .name = "acrux",
- .id_table = ax_devices,
- .probe = ax_probe,
+ .name = "acrux",
+ .id_table = ax_devices,
+ .probe = ax_probe,
+ .remove = ax_remove,
};
static int __init ax_init(void)
diff --git a/drivers/hid/hid-belkin.c b/drivers/hid/hid-belkin.c
index 4ce7aa3a519f..a1a765a5b08a 100644
--- a/drivers/hid/hid-belkin.c
+++ b/drivers/hid/hid-belkin.c
@@ -56,14 +56,14 @@ static int belkin_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
((quirks & BELKIN_HIDDEV) ? HID_CONNECT_HIDDEV_FORCE : 0));
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-cando.c b/drivers/hid/hid-cando.c
index 5925bdcd417d..1ea066c55201 100644
--- a/drivers/hid/hid-cando.c
+++ b/drivers/hid/hid-cando.c
@@ -207,7 +207,7 @@ static int cando_probe(struct hid_device *hdev, const struct hid_device_id *id)
td = kmalloc(sizeof(struct cando_data), GFP_KERNEL);
if (!td) {
- dev_err(&hdev->dev, "cannot allocate Cando Touch data\n");
+ hid_err(hdev, "cannot allocate Cando Touch data\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, td);
@@ -236,6 +236,8 @@ static const struct hid_device_id cando_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
diff --git a/drivers/hid/hid-cherry.c b/drivers/hid/hid-cherry.c
index e880086c2311..888ece68a47c 100644
--- a/drivers/hid/hid-cherry.c
+++ b/drivers/hid/hid-cherry.c
@@ -30,8 +30,7 @@ static __u8 *ch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize >= 17 && rdesc[11] == 0x3c && rdesc[12] == 0x02) {
- dev_info(&hdev->dev, "fixing up Cherry Cymotion report "
- "descriptor\n");
+ hid_info(hdev, "fixing up Cherry Cymotion report descriptor\n");
rdesc[11] = rdesc[16] = 0xff;
rdesc[12] = rdesc[17] = 0x03;
}
diff --git a/drivers/hid/hid-core.c b/drivers/hid/hid-core.c
index 88cb04e7962b..e9687768a335 100644
--- a/drivers/hid/hid-core.c
+++ b/drivers/hid/hid-core.c
@@ -14,6 +14,8 @@
* any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
@@ -59,7 +61,8 @@ struct hid_report *hid_register_report(struct hid_device *device, unsigned type,
if (report_enum->report_id_hash[id])
return report_enum->report_id_hash[id];
- if (!(report = kzalloc(sizeof(struct hid_report), GFP_KERNEL)))
+ report = kzalloc(sizeof(struct hid_report), GFP_KERNEL);
+ if (!report)
return NULL;
if (id != 0)
@@ -90,8 +93,11 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
return NULL;
}
- if (!(field = kzalloc(sizeof(struct hid_field) + usages * sizeof(struct hid_usage)
- + values * sizeof(unsigned), GFP_KERNEL))) return NULL;
+ field = kzalloc((sizeof(struct hid_field) +
+ usages * sizeof(struct hid_usage) +
+ values * sizeof(unsigned)), GFP_KERNEL);
+ if (!field)
+ return NULL;
field->index = report->maxfield++;
report->field[field->index] = field;
@@ -172,10 +178,14 @@ static int close_collection(struct hid_parser *parser)
static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
{
+ struct hid_collection *collection = parser->device->collection;
int n;
- for (n = parser->collection_stack_ptr - 1; n >= 0; n--)
- if (parser->device->collection[parser->collection_stack[n]].type == type)
- return parser->device->collection[parser->collection_stack[n]].usage;
+
+ for (n = parser->collection_stack_ptr - 1; n >= 0; n--) {
+ unsigned index = parser->collection_stack[n];
+ if (collection[index].type == type)
+ return collection[index].usage;
+ }
return 0; /* we know nothing about this usage type */
}
@@ -209,7 +219,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
unsigned offset;
int i;
- if (!(report = hid_register_report(parser->device, report_type, parser->global.report_id))) {
+ report = hid_register_report(parser->device, report_type, parser->global.report_id);
+ if (!report) {
dbg_hid("hid_register_report failed\n");
return -1;
}
@@ -227,7 +238,8 @@ static int hid_add_field(struct hid_parser *parser, unsigned report_type, unsign
usages = max_t(int, parser->local.usage_index, parser->global.report_count);
- if ((field = hid_register_field(report, usages, parser->global.report_count)) == NULL)
+ field = hid_register_field(report, usages, parser->global.report_count);
+ if (!field)
return 0;
field->physical = hid_lookup_collection(parser, HID_COLLECTION_PHYSICAL);
@@ -652,13 +664,12 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
return -ENOMEM;
device->rsize = size;
- parser = vmalloc(sizeof(struct hid_parser));
+ parser = vzalloc(sizeof(struct hid_parser));
if (!parser) {
ret = -ENOMEM;
goto err;
}
- memset(parser, 0, sizeof(struct hid_parser));
parser->device = device;
end = start + size;
@@ -672,7 +683,8 @@ int hid_parse_report(struct hid_device *device, __u8 *start,
if (dispatch_type[item.type](parser, &item)) {
dbg_hid("item %u %u %u %u parsing failed\n",
- item.format, (unsigned)item.size, (unsigned)item.type, (unsigned)item.tag);
+ item.format, (unsigned)item.size,
+ (unsigned)item.type, (unsigned)item.tag);
goto err;
}
@@ -737,13 +749,14 @@ static u32 s32ton(__s32 value, unsigned n)
* Search linux-kernel and linux-usb-devel archives for "hid-core extract".
*/
-static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
+static __u32 extract(const struct hid_device *hid, __u8 *report,
+ unsigned offset, unsigned n)
{
u64 x;
if (n > 32)
- printk(KERN_WARNING "HID: extract() called with n (%d) > 32! (%s)\n",
- n, current->comm);
+ hid_warn(hid, "extract() called with n (%d) > 32! (%s)\n",
+ n, current->comm);
report += offset >> 3; /* adjust byte index */
offset &= 7; /* now only need bit offset into one byte */
@@ -760,18 +773,19 @@ static __inline__ __u32 extract(__u8 *report, unsigned offset, unsigned n)
* endianness of register values by considering a register
* a "cached" copy of the little endiad bit stream.
*/
-static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u32 value)
+static void implement(const struct hid_device *hid, __u8 *report,
+ unsigned offset, unsigned n, __u32 value)
{
u64 x;
u64 m = (1ULL << n) - 1;
if (n > 32)
- printk(KERN_WARNING "HID: implement() called with n (%d) > 32! (%s)\n",
- n, current->comm);
+ hid_warn(hid, "%s() called with n (%d) > 32! (%s)\n",
+ __func__, n, current->comm);
if (value > m)
- printk(KERN_WARNING "HID: implement() called with too large value %d! (%s)\n",
- value, current->comm);
+ hid_warn(hid, "%s() called with too large value %d! (%s)\n",
+ __func__, value, current->comm);
WARN_ON(value > m);
value &= m;
@@ -788,7 +802,7 @@ static __inline__ void implement(__u8 *report, unsigned offset, unsigned n, __u3
* Search an array for a value.
*/
-static __inline__ int search(__s32 *array, __s32 value, unsigned n)
+static int search(__s32 *array, __s32 value, unsigned n)
{
while (n--) {
if (*array++ == value)
@@ -887,18 +901,22 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
__s32 max = field->logical_maximum;
__s32 *value;
- if (!(value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC)))
+ value = kmalloc(sizeof(__s32) * count, GFP_ATOMIC);
+ if (!value)
return;
for (n = 0; n < count; n++) {
- value[n] = min < 0 ? snto32(extract(data, offset + n * size, size), size) :
- extract(data, offset + n * size, size);
+ value[n] = min < 0 ?
+ snto32(extract(hid, data, offset + n * size, size),
+ size) :
+ extract(hid, data, offset + n * size, size);
- if (!(field->flags & HID_MAIN_ITEM_VARIABLE) /* Ignore report if ErrorRollOver */
- && value[n] >= min && value[n] <= max
- && field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
- goto exit;
+ /* Ignore report if ErrorRollOver */
+ if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
+ value[n] >= min && value[n] <= max &&
+ field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
+ goto exit;
}
for (n = 0; n < count; n++) {
@@ -928,7 +946,8 @@ exit:
* Output the field into the report.
*/
-static void hid_output_field(struct hid_field *field, __u8 *data)
+static void hid_output_field(const struct hid_device *hid,
+ struct hid_field *field, __u8 *data)
{
unsigned count = field->report_count;
unsigned offset = field->report_offset;
@@ -937,9 +956,11 @@ static void hid_output_field(struct hid_field *field, __u8 *data)
for (n = 0; n < count; n++) {
if (field->logical_minimum < 0) /* signed values */
- implement(data, offset + n * size, size, s32ton(field->value[n], size));
+ implement(hid, data, offset + n * size, size,
+ s32ton(field->value[n], size));
else /* unsigned values */
- implement(data, offset + n * size, size, field->value[n]);
+ implement(hid, data, offset + n * size, size,
+ field->value[n]);
}
}
@@ -956,7 +977,7 @@ void hid_output_report(struct hid_report *report, __u8 *data)
memset(data, 0, ((report->size - 1) >> 3) + 1);
for (n = 0; n < report->maxfield; n++)
- hid_output_field(report->field[n], data);
+ hid_output_field(report->device, report->field[n], data);
}
EXPORT_SYMBOL_GPL(hid_output_report);
@@ -1138,6 +1159,32 @@ static bool hid_hiddev(struct hid_device *hdev)
return !!hid_match_id(hdev, hid_hiddev_list);
}
+
+static ssize_t
+read_report_descriptor(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct hid_device *hdev = container_of(dev, struct hid_device, dev);
+
+ if (off >= hdev->rsize)
+ return 0;
+
+ if (off + count > hdev->rsize)
+ count = hdev->rsize - off;
+
+ memcpy(buf, hdev->rdesc + off, count);
+
+ return count;
+}
+
+static struct bin_attribute dev_bin_attr_report_desc = {
+ .attr = { .name = "report_descriptor", .mode = 0444 },
+ .read = read_report_descriptor,
+ .size = HID_MAX_DESCRIPTOR_SIZE,
+};
+
int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
{
static const char *types[] = { "Device", "Pointer", "Mouse", "Device",
@@ -1148,6 +1195,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
char buf[64];
unsigned int i;
int len;
+ int ret;
if (hdev->quirks & HID_QUIRK_HIDDEV_FORCE)
connect_mask |= (HID_CONNECT_HIDDEV_FORCE | HID_CONNECT_HIDDEV);
@@ -1169,8 +1217,7 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
hdev->claimed |= HID_CLAIMED_HIDRAW;
if (!hdev->claimed) {
- dev_err(&hdev->dev, "claimed by neither input, hiddev nor "
- "hidraw\n");
+ hid_err(hdev, "claimed by neither input, hiddev nor hidraw\n");
return -ENODEV;
}
@@ -1210,9 +1257,14 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
bus = "<UNKNOWN>";
}
- dev_info(&hdev->dev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
- buf, bus, hdev->version >> 8, hdev->version & 0xff,
- type, hdev->name, hdev->phys);
+ ret = device_create_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
+ if (ret)
+ hid_warn(hdev,
+ "can't create sysfs report descriptor attribute err: %d\n", ret);
+
+ hid_info(hdev, "%s: %s HID v%x.%02x %s [%s] on %s\n",
+ buf, bus, hdev->version >> 8, hdev->version & 0xff,
+ type, hdev->name, hdev->phys);
return 0;
}
@@ -1220,6 +1272,7 @@ EXPORT_SYMBOL_GPL(hid_connect);
void hid_disconnect(struct hid_device *hdev)
{
+ device_remove_bin_file(&hdev->dev, &dev_bin_attr_report_desc);
if (hdev->claimed & HID_CLAIMED_INPUT)
hidinput_disconnect(hdev);
if (hdev->claimed & HID_CLAIMED_HIDDEV)
@@ -1230,15 +1283,13 @@ void hid_disconnect(struct hid_device *hdev)
EXPORT_SYMBOL_GPL(hid_disconnect);
/* a list of devices for which there is a specialized driver on HID bus */
-static const struct hid_device_id hid_blacklist[] = {
+static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_3M, USB_DEVICE_ID_3M1968) },
{ 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) },
{ HID_USB_DEVICE(USB_VENDOR_ID_A4TECH, USB_DEVICE_ID_A4TECH_RP_649) },
-#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) },
@@ -1276,6 +1327,15 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@@ -1286,32 +1346,46 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_BELKIN, USB_DEVICE_ID_FLIP_KVM) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CANDO, USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHERRY, USB_DEVICE_ID_CHERRY_CYMOTION_SOLAR) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DWAV, USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_ELECOM, USB_DEVICE_ID_ELECOM_BM084) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
{ 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) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0003) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GREENASIA, 0x0012) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_HANVON, USB_DEVICE_ID_HANVON_MULTITOUCH) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS, USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
@@ -1332,6 +1406,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_FLIGHT_SYSTEM_G940) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_MOMO_WHEEL2) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RUMBLEPAD2) },
@@ -1364,11 +1439,15 @@ static const struct hid_device_id hid_blacklist[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_16) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_17) },
{ HID_USB_DEVICE(USB_VENDOR_ID_NTRIG, USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_18) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_PETALYNX, USB_DEVICE_ID_PETALYNX_MAXTER_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONE) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
@@ -1390,6 +1469,7 @@ static const struct hid_device_id hid_blacklist[] = {
{ 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_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_PF1209) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP4030U) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC, USB_DEVICE_ID_UCLOGIC_TABLET_WP5540U) },
@@ -1496,9 +1576,9 @@ static int hid_bus_match(struct device *dev, struct device_driver *drv)
if (!hid_match_device(hdev, hdrv))
return 0;
- /* generic wants all non-blacklisted */
+ /* generic wants all that don't have specialized driver */
if (!strncmp(hdrv->name, "generic-", 8))
- return !hid_match_id(hdev, hid_blacklist);
+ return !hid_match_id(hdev, hid_have_special_driver);
return 1;
}
@@ -1604,10 +1684,10 @@ static const struct hid_device_id hid_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DEALEXTREAME, USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EARTHMATE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DELORME, USB_DEVICE_ID_DELORME_EM_LT20) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DREAM_CHEEKY, 0x0004) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ESSENTIAL_REALITY, USB_DEVICE_ID_ESSENTIAL_REALITY_P5) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC5UH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ETT, USB_DEVICE_ID_TC4UM) },
- { HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0001) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0002) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0003) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH, 0x0004) },
@@ -1757,6 +1837,15 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING3_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_ISO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING5_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ }
@@ -1948,12 +2037,12 @@ static int __init hid_init(void)
int ret;
if (hid_debug)
- printk(KERN_WARNING "HID: hid_debug is now used solely for parser and driver debugging.\n"
- "HID: debugfs is now used for inspecting the device (report descriptor, reports)\n");
+ pr_warn("hid_debug is now used solely for parser and driver debugging.\n"
+ "debugfs is now used for inspecting the device (report descriptor, reports)\n");
ret = bus_register(&hid_bus_type);
if (ret) {
- printk(KERN_ERR "HID: can't register hid bus\n");
+ pr_err("can't register hid bus\n");
goto err;
}
diff --git a/drivers/hid/hid-cypress.c b/drivers/hid/hid-cypress.c
index 4cd0e2345991..2f0be4c66af7 100644
--- a/drivers/hid/hid-cypress.c
+++ b/drivers/hid/hid-cypress.c
@@ -107,13 +107,13 @@ static int cp_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-debug.c b/drivers/hid/hid-debug.c
index 75c5e23d09d2..555382fc7417 100644
--- a/drivers/hid/hid-debug.c
+++ b/drivers/hid/hid-debug.c
@@ -26,6 +26,8 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/debugfs.h>
#include <linux/seq_file.h>
#include <linux/sched.h>
@@ -393,7 +395,7 @@ char *hid_resolv_usage(unsigned usage, struct seq_file *f) {
buf = resolv_usage_page(usage >> 16, f);
if (IS_ERR(buf)) {
- printk(KERN_ERR "error allocating HID debug buffer\n");
+ pr_err("error allocating HID debug buffer\n");
return NULL;
}
diff --git a/drivers/hid/hid-drff.c b/drivers/hid/hid-dr.c
index 968b04f9b796..61eece47204d 100644
--- a/drivers/hid/hid-drff.c
+++ b/drivers/hid/hid-dr.c
@@ -96,18 +96,18 @@ static int drff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output reports found\n");
+ hid_err(hid, "no output reports found\n");
return -ENODEV;
}
report = list_first_entry(report_list, struct hid_report, list);
if (report->maxfield < 1) {
- dev_err(&hid->dev, "no fields in the report\n");
+ hid_err(hid, "no fields in the report\n");
return -ENODEV;
}
if (report->field[0]->report_count < 7) {
- dev_err(&hid->dev, "not enough values in the field\n");
+ hid_err(hid, "not enough values in the field\n");
return -ENODEV;
}
@@ -133,8 +133,8 @@ static int drff_init(struct hid_device *hid)
drff->report->field[0]->value[6] = 0x00;
usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
- dev_info(&hid->dev, "Force Feedback for DragonRise Inc. game "
- "controllers by Richard Walmsley <richwalm@gmail.com>\n");
+ hid_info(hid, "Force Feedback for DragonRise Inc. "
+ "game controllers by Richard Walmsley <richwalm@gmail.com>\n");
return 0;
}
@@ -145,6 +145,110 @@ static inline int drff_init(struct hid_device *hid)
}
#endif
+/*
+ * The original descriptor of joystick with PID 0x0011, represented by DVTech PC
+ * JS19. It seems both copied from another device and a result of confusion
+ * either about the specification or about the program used to create the
+ * descriptor. In any case, it's a wonder it works on Windows.
+ *
+ * Usage Page (Desktop), ; Generic desktop controls (01h)
+ * Usage (Joystik), ; Joystik (04h, application collection)
+ * Collection (Application),
+ * Collection (Logical),
+ * Report Size (8),
+ * Report Count (5),
+ * Logical Minimum (0),
+ * Logical Maximum (255),
+ * Physical Minimum (0),
+ * Physical Maximum (255),
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (X), ; X (30h, dynamic value)
+ * Usage (Y), ; Y (31h, dynamic value)
+ * Input (Variable),
+ * Report Size (4),
+ * Report Count (1),
+ * Logical Maximum (7),
+ * Physical Maximum (315),
+ * Unit (Degrees),
+ * Usage (00h),
+ * Input (Variable, Null State),
+ * Unit,
+ * Report Size (1),
+ * Report Count (10),
+ * Logical Maximum (1),
+ * Physical Maximum (1),
+ * Usage Page (Button), ; Button (09h)
+ * Usage Minimum (01h),
+ * Usage Maximum (0Ah),
+ * Input (Variable),
+ * Usage Page (FF00h), ; FF00h, vendor-defined
+ * Report Size (1),
+ * Report Count (10),
+ * Logical Maximum (1),
+ * Physical Maximum (1),
+ * Usage (01h),
+ * Input (Variable),
+ * End Collection,
+ * Collection (Logical),
+ * Report Size (8),
+ * Report Count (4),
+ * Physical Maximum (255),
+ * Logical Maximum (255),
+ * Usage (02h),
+ * Output (Variable),
+ * End Collection,
+ * End Collection
+ */
+
+/* Size of the original descriptor of the PID 0x0011 joystick */
+#define PID0011_RDESC_ORIG_SIZE 101
+
+/* Fixed report descriptor for PID 0x011 joystick */
+static __u8 pid0011_rdesc_fixed[] = {
+ 0x05, 0x01, /* Usage Page (Desktop), */
+ 0x09, 0x04, /* Usage (Joystik), */
+ 0xA1, 0x01, /* Collection (Application), */
+ 0xA1, 0x02, /* Collection (Logical), */
+ 0x14, /* Logical Minimum (0), */
+ 0x75, 0x08, /* Report Size (8), */
+ 0x95, 0x03, /* Report Count (3), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x26, 0xFF, 0x00, /* Logical Maximum (255), */
+ 0x95, 0x02, /* Report Count (2), */
+ 0x09, 0x30, /* Usage (X), */
+ 0x09, 0x31, /* Usage (Y), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x75, 0x01, /* Report Size (1), */
+ 0x95, 0x04, /* Report Count (4), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0x25, 0x01, /* Logical Maximum (1), */
+ 0x95, 0x0A, /* Report Count (10), */
+ 0x05, 0x09, /* Usage Page (Button), */
+ 0x19, 0x01, /* Usage Minimum (01h), */
+ 0x29, 0x0A, /* Usage Maximum (0Ah), */
+ 0x81, 0x02, /* Input (Variable), */
+ 0x95, 0x0A, /* Report Count (10), */
+ 0x81, 0x01, /* Input (Constant), */
+ 0xC0, /* End Collection, */
+ 0xC0 /* End Collection */
+};
+
+static __u8 *dr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ switch (hdev->product) {
+ case 0x0011:
+ if (*rsize == PID0011_RDESC_ORIG_SIZE) {
+ rdesc = pid0011_rdesc_fixed;
+ *rsize = sizeof(pid0011_rdesc_fixed);
+ }
+ break;
+ }
+ return rdesc;
+}
+
static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
@@ -153,17 +257,26 @@ static int dr_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
- drff_init(hdev);
+ switch (hdev->product) {
+ case 0x0006:
+ ret = drff_init(hdev);
+ if (ret) {
+ dev_err(&hdev->dev, "force feedback init failed\n");
+ hid_hw_stop(hdev);
+ goto err;
+ }
+ break;
+ }
return 0;
err:
@@ -172,6 +285,7 @@ err:
static const struct hid_device_id dr_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006), },
+ { HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011), },
{ }
};
MODULE_DEVICE_TABLE(hid, dr_devices);
@@ -179,6 +293,7 @@ MODULE_DEVICE_TABLE(hid, dr_devices);
static struct hid_driver dr_driver = {
.name = "dragonrise",
.id_table = dr_devices,
+ .report_fixup = dr_report_fixup,
.probe = dr_probe,
};
diff --git a/drivers/hid/hid-egalax.c b/drivers/hid/hid-egalax.c
deleted file mode 100644
index 5a1b52e0eb85..000000000000
--- a/drivers/hid/hid-egalax.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * HID driver for eGalax dual-touch panels
- *
- * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
- *
- */
-
-/*
- * 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 <linux/usb.h>
-#include <linux/slab.h>
-#include "usbhid/usbhid.h"
-
-MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
-MODULE_DESCRIPTION("eGalax dual-touch panel");
-MODULE_LICENSE("GPL");
-
-#include "hid-ids.h"
-
-struct egalax_data {
- __u16 x, y, z;
- __u8 id;
- bool first; /* is this the first finger in the frame? */
- bool valid; /* valid finger data, or just placeholder? */
- bool activity; /* at least one active finger previously? */
- __u16 lastx, lasty, lastz; /* latest valid (x, y, z) in the frame */
-};
-
-static int egalax_input_mapping(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- switch (usage->hid & HID_USAGE_PAGE) {
-
- case HID_UP_GENDESK:
- switch (usage->hid) {
- case HID_GD_X:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_X);
- /* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_X,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
- return 1;
- case HID_GD_Y:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_POSITION_Y);
- /* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_Y,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
- return 1;
- }
- return 0;
-
- case HID_UP_DIGITIZER:
- switch (usage->hid) {
- case HID_DG_TIPSWITCH:
- /* touchscreen emulation */
- hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
- return 1;
- case HID_DG_INRANGE:
- case HID_DG_CONFIDENCE:
- case HID_DG_CONTACTCOUNT:
- case HID_DG_CONTACTMAX:
- return -1;
- case HID_DG_CONTACTID:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_TRACKING_ID);
- return 1;
- case HID_DG_TIPPRESSURE:
- hid_map_usage(hi, usage, bit, max,
- EV_ABS, ABS_MT_PRESSURE);
- /* touchscreen emulation */
- input_set_abs_params(hi->input, ABS_PRESSURE,
- field->logical_minimum,
- field->logical_maximum, 0, 0);
- return 1;
- }
- return 0;
- }
-
- /* ignore others (from other reports we won't get anyway) */
- return -1;
-}
-
-static int egalax_input_mapped(struct hid_device *hdev, struct hid_input *hi,
- struct hid_field *field, struct hid_usage *usage,
- unsigned long **bit, int *max)
-{
- if (usage->type == EV_KEY || usage->type == EV_ABS)
- clear_bit(usage->code, *bit);
-
- return 0;
-}
-
-/*
- * this function is called when a whole finger has been parsed,
- * so that it can decide what to send to the input layer.
- */
-static void egalax_filter_event(struct egalax_data *td, struct input_dev *input)
-{
- td->first = !td->first; /* touchscreen emulation */
-
- if (td->valid) {
- /* emit multitouch events */
- input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
- input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x >> 3);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y >> 3);
- input_event(input, EV_ABS, ABS_MT_PRESSURE, td->z);
-
- input_mt_sync(input);
-
- /*
- * touchscreen emulation: store (x, y) as
- * the last valid values in this frame
- */
- td->lastx = td->x;
- td->lasty = td->y;
- td->lastz = td->z;
- }
-
- /*
- * touchscreen emulation: if this is the second finger and at least
- * one in this frame is valid, the latest valid in the frame is
- * the oldest on the panel, the one we want for single touch
- */
- if (!td->first && td->activity) {
- input_event(input, EV_ABS, ABS_X, td->lastx >> 3);
- input_event(input, EV_ABS, ABS_Y, td->lasty >> 3);
- input_event(input, EV_ABS, ABS_PRESSURE, td->lastz);
- }
-
- if (!td->valid) {
- /*
- * touchscreen emulation: if the first finger is invalid
- * and there previously was finger activity, this is a release
- */
- if (td->first && td->activity) {
- input_event(input, EV_KEY, BTN_TOUCH, 0);
- td->activity = false;
- }
- return;
- }
-
-
- /* touchscreen emulation: if no previous activity, emit touch event */
- if (!td->activity) {
- input_event(input, EV_KEY, BTN_TOUCH, 1);
- td->activity = true;
- }
-}
-
-
-static int egalax_event(struct hid_device *hid, struct hid_field *field,
- struct hid_usage *usage, __s32 value)
-{
- struct egalax_data *td = hid_get_drvdata(hid);
-
- /* Note, eGalax has two product lines: the first is resistive and
- * uses a standard parallel multitouch protocol (product ID ==
- * 48xx). The second is capacitive and uses an unusual "serial"
- * protocol with a different message for each multitouch finger
- * (product ID == 72xx). We do not yet generate a correct event
- * sequence for the capacitive/serial protocol.
- */
- if (hid->claimed & HID_CLAIMED_INPUT) {
- struct input_dev *input = field->hidinput->input;
-
- switch (usage->hid) {
- case HID_DG_INRANGE:
- case HID_DG_CONFIDENCE:
- /* avoid interference from generic hidinput handling */
- break;
- case HID_DG_TIPSWITCH:
- td->valid = value;
- break;
- case HID_DG_TIPPRESSURE:
- td->z = value;
- break;
- case HID_DG_CONTACTID:
- td->id = value;
- break;
- case HID_GD_X:
- td->x = value;
- break;
- case HID_GD_Y:
- td->y = value;
- /* this is the last field in a finger */
- egalax_filter_event(td, input);
- break;
- case HID_DG_CONTACTCOUNT:
- /* touch emulation: this is the last field in a frame */
- td->first = false;
- break;
-
- default:
- /* fallback to the generic hidinput handling */
- return 0;
- }
- }
-
- /* we have handled the hidinput part, now remains hiddev */
- if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
- hid->hiddev_hid_event(hid, field, usage, value);
-
- return 1;
-}
-
-static int egalax_probe(struct hid_device *hdev, const struct hid_device_id *id)
-{
- int ret;
- struct egalax_data *td;
- struct hid_report *report;
-
- td = kzalloc(sizeof(struct egalax_data), GFP_KERNEL);
- if (!td) {
- dev_err(&hdev->dev, "cannot allocate eGalax data\n");
- return -ENOMEM;
- }
- hid_set_drvdata(hdev, td);
-
- ret = hid_parse(hdev);
- if (ret)
- goto end;
-
- ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
- if (ret)
- goto end;
-
- report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[5];
- if (report) {
- report->field[0]->value[0] = 2;
- usbhid_submit_report(hdev, report, USB_DIR_OUT);
- }
-
-end:
- if (ret)
- kfree(td);
-
- return ret;
-}
-
-static void egalax_remove(struct hid_device *hdev)
-{
- hid_hw_stop(hdev);
- kfree(hid_get_drvdata(hdev));
- hid_set_drvdata(hdev, NULL);
-}
-
-static const struct hid_device_id egalax_devices[] = {
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
- { HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
- USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
- { }
-};
-MODULE_DEVICE_TABLE(hid, egalax_devices);
-
-static const struct hid_usage_id egalax_grabbed_usages[] = {
- { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
- { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
-};
-
-static struct hid_driver egalax_driver = {
- .name = "egalax-touch",
- .id_table = egalax_devices,
- .probe = egalax_probe,
- .remove = egalax_remove,
- .input_mapping = egalax_input_mapping,
- .input_mapped = egalax_input_mapped,
- .usage_table = egalax_grabbed_usages,
- .event = egalax_event,
-};
-
-static int __init egalax_init(void)
-{
- return hid_register_driver(&egalax_driver);
-}
-
-static void __exit egalax_exit(void)
-{
- hid_unregister_driver(&egalax_driver);
-}
-
-module_init(egalax_init);
-module_exit(egalax_exit);
-
diff --git a/drivers/hid/hid-elecom.c b/drivers/hid/hid-elecom.c
index 6e31f305397d..79d0c61e7214 100644
--- a/drivers/hid/hid-elecom.c
+++ b/drivers/hid/hid-elecom.c
@@ -24,8 +24,7 @@ static __u8 *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");
+ hid_info(hdev, "Fixing up Elecom BM084 report descriptor\n");
rdesc[47] = 0x00;
}
return rdesc;
diff --git a/drivers/hid/hid-emsff.c b/drivers/hid/hid-emsff.c
new file mode 100644
index 000000000000..81877c67caea
--- /dev/null
+++ b/drivers/hid/hid-emsff.c
@@ -0,0 +1,161 @@
+/*
+ * Force feedback support for EMS Trio Linker Plus II
+ *
+ * Copyright (c) 2010 Ignaz Forster <ignaz.forster@gmx.de>
+ */
+
+/*
+ * 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/hid.h>
+#include <linux/input.h>
+#include <linux/usb.h>
+
+#include "hid-ids.h"
+#include "usbhid/usbhid.h"
+
+struct emsff_device {
+ struct hid_report *report;
+};
+
+static int emsff_play(struct input_dev *dev, void *data,
+ struct ff_effect *effect)
+{
+ struct hid_device *hid = input_get_drvdata(dev);
+ struct emsff_device *emsff = data;
+ int weak, strong;
+
+ weak = effect->u.rumble.weak_magnitude;
+ strong = effect->u.rumble.strong_magnitude;
+
+ dbg_hid("called with 0x%04x 0x%04x\n", strong, weak);
+
+ weak = weak * 0xff / 0xffff;
+ strong = strong * 0xff / 0xffff;
+
+ emsff->report->field[0]->value[1] = weak;
+ emsff->report->field[0]->value[2] = strong;
+
+ dbg_hid("running with 0x%02x 0x%02x\n", strong, weak);
+ usbhid_submit_report(hid, emsff->report, USB_DIR_OUT);
+
+ return 0;
+}
+
+static int emsff_init(struct hid_device *hid)
+{
+ struct emsff_device *emsff;
+ 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)) {
+ hid_err(hid, "no output reports found\n");
+ return -ENODEV;
+ }
+
+ report = list_first_entry(report_list, struct hid_report, list);
+ if (report->maxfield < 1) {
+ hid_err(hid, "no fields in the report\n");
+ return -ENODEV;
+ }
+
+ if (report->field[0]->report_count < 7) {
+ hid_err(hid, "not enough values in the field\n");
+ return -ENODEV;
+ }
+
+ emsff = kzalloc(sizeof(struct emsff_device), GFP_KERNEL);
+ if (!emsff)
+ return -ENOMEM;
+
+ set_bit(FF_RUMBLE, dev->ffbit);
+
+ error = input_ff_create_memless(dev, emsff, emsff_play);
+ if (error) {
+ kfree(emsff);
+ return error;
+ }
+
+ emsff->report = report;
+ emsff->report->field[0]->value[0] = 0x01;
+ emsff->report->field[0]->value[1] = 0x00;
+ emsff->report->field[0]->value[2] = 0x00;
+ emsff->report->field[0]->value[3] = 0x00;
+ emsff->report->field[0]->value[4] = 0x00;
+ emsff->report->field[0]->value[5] = 0x00;
+ emsff->report->field[0]->value[6] = 0x00;
+ usbhid_submit_report(hid, emsff->report, USB_DIR_OUT);
+
+ hid_info(hid, "force feedback for EMS based devices by Ignaz Forster <ignaz.forster@gmx.de>\n");
+
+ return 0;
+}
+
+static int ems_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret;
+
+ ret = hid_parse(hdev);
+ if (ret) {
+ hid_err(hdev, "parse failed\n");
+ goto err;
+ }
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
+ if (ret) {
+ hid_err(hdev, "hw start failed\n");
+ goto err;
+ }
+
+ emsff_init(hdev);
+
+ return 0;
+err:
+ return ret;
+}
+
+static const struct hid_device_id ems_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_EMS, 0x118) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ems_devices);
+
+static struct hid_driver ems_driver = {
+ .name = "hkems",
+ .id_table = ems_devices,
+ .probe = ems_probe,
+};
+
+static int ems_init(void)
+{
+ return hid_register_driver(&ems_driver);
+}
+
+static void ems_exit(void)
+{
+ hid_unregister_driver(&ems_driver);
+}
+
+module_init(ems_init);
+module_exit(ems_exit);
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/hid/hid-gaff.c b/drivers/hid/hid-gaff.c
index 88dfcf49a5d7..279ba530003c 100644
--- a/drivers/hid/hid-gaff.c
+++ b/drivers/hid/hid-gaff.c
@@ -87,7 +87,7 @@ static int gaff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output reports found\n");
+ hid_err(hid, "no output reports found\n");
return -ENODEV;
}
@@ -95,12 +95,12 @@ static int gaff_init(struct hid_device *hid)
report = list_entry(report_ptr, struct hid_report, list);
if (report->maxfield < 1) {
- dev_err(&hid->dev, "no fields in the report\n");
+ hid_err(hid, "no fields in the report\n");
return -ENODEV;
}
if (report->field[0]->report_count < 6) {
- dev_err(&hid->dev, "not enough values in the field\n");
+ hid_err(hid, "not enough values in the field\n");
return -ENODEV;
}
@@ -128,8 +128,7 @@ static int gaff_init(struct hid_device *hid)
usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
- dev_info(&hid->dev, "Force Feedback for GreenAsia 0x12"
- " devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n");
+ hid_info(hid, "Force Feedback for GreenAsia 0x12 devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n");
return 0;
}
@@ -148,13 +147,13 @@ static int ga_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
diff --git a/drivers/hid/hid-gyration.c b/drivers/hid/hid-gyration.c
index 3975e039c3dd..e88b951cd10d 100644
--- a/drivers/hid/hid-gyration.c
+++ b/drivers/hid/hid-gyration.c
@@ -43,6 +43,11 @@ static int gyration_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case 0x048: gy_map_key_clear(KEY_MEDIA); break;
case 0x049: gy_map_key_clear(KEY_CAMERA); break;
case 0x04a: gy_map_key_clear(KEY_VIDEO); break;
+ case 0x05a: gy_map_key_clear(KEY_TEXT); break;
+ case 0x05b: gy_map_key_clear(KEY_RED); break;
+ case 0x05c: gy_map_key_clear(KEY_GREEN); break;
+ case 0x05d: gy_map_key_clear(KEY_YELLOW); break;
+ case 0x05e: gy_map_key_clear(KEY_BLUE); break;
default:
return 0;
diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h
index 3341baa86a30..65ac53d7aecc 100644
--- a/drivers/hid/hid-ids.h
+++ b/drivers/hid/hid-ids.h
@@ -97,6 +97,15 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ANSI 0x0236
#define USB_DEVICE_ID_APPLE_WELLSPRING3_ISO 0x0237
#define USB_DEVICE_ID_APPLE_WELLSPRING3_JIS 0x0238
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI 0x023f
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_ISO 0x0240
+#define USB_DEVICE_ID_APPLE_WELLSPRING4_JIS 0x0241
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ANSI 0x0242
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_ISO 0x0243
+#define USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS 0x0244
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ANSI 0x0245
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_ISO 0x0246
+#define USB_DEVICE_ID_APPLE_WELLSPRING5_JIS 0x0247
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
@@ -134,7 +143,9 @@
#define USB_DEVICE_ID_BTC_EMPREX_REMOTE_2 0x5577
#define USB_VENDOR_ID_CANDO 0x2087
+#define USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH 0x0703
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH 0x0a01
+#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_10_1 0x0a02
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_11_6 0x0b03
#define USB_DEVICE_ID_CANDO_MULTI_TOUCH_15_6 0x0f01
@@ -156,6 +167,7 @@
#define USB_VENDOR_ID_CHICONY 0x04f2
#define USB_DEVICE_ID_CHICONY_TACTICAL_PAD 0x0418
#define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d
+#define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618
#define USB_VENDOR_ID_CIDC 0x1677
@@ -179,6 +191,7 @@
#define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61
#define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64
#define USB_DEVICE_ID_CYPRESS_BARCODE_3 0xbca1
+#define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001
#define USB_VENDOR_ID_DEALEXTREAME 0x10c5
#define USB_DEVICE_ID_DEALEXTREAME_RADIO_SI4701 0x819a
@@ -196,13 +209,21 @@
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1 0x720c
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2 0x72a1
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3 0x480e
+#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4 0x726b
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
+#define USB_VENDOR_ID_DREAM_CHEEKY 0x1d34
+
#define USB_VENDOR_ID_ELO 0x04E7
#define USB_DEVICE_ID_ELO_TS2700 0x0020
+#define USB_VENDOR_ID_EMS 0x2006
+#define USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II 0x0118
+
#define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f
#define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100
@@ -221,6 +242,7 @@
#define USB_DEVICE_ID_GAMERON_DUAL_PCS_ADAPTOR 0x0002
#define USB_VENDOR_ID_GENERAL_TOUCH 0x0dfc
+#define USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS 0x0001
#define USB_VENDOR_ID_GLAB 0x06c2
#define USB_DEVICE_ID_4_PHIDGETSERVO_30 0x0038
@@ -303,6 +325,9 @@
#define USB_DEVICE_ID_HANWANG_TABLET_FIRST 0x5000
#define USB_DEVICE_ID_HANWANG_TABLET_LAST 0x8fff
+#define USB_VENDOR_ID_HANVON 0x20b3
+#define USB_DEVICE_ID_HANVON_MULTITOUCH 0x0a18
+
#define USB_VENDOR_ID_HAPP 0x078b
#define USB_DEVICE_ID_UGCI_DRIVING 0x0010
#define USB_DEVICE_ID_UGCI_FLYING 0x0020
@@ -311,6 +336,9 @@
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
+#define USB_VENDOR_ID_IRTOUCHSYSTEMS 0x6615
+#define USB_DEVICE_ID_IRTOUCH_INFRARED_USB 0x0070
+
#define USB_VENDOR_ID_JESS 0x0c45
#define USB_DEVICE_ID_JESS_YUREX 0x1010
@@ -323,6 +351,9 @@
#define USB_VENDOR_ID_KWORLD 0x1b80
#define USB_DEVICE_ID_KWORLD_RADIO_FM700 0xd700
+#define USB_VENDOR_ID_KEYTOUCH 0x0926
+#define USB_DEVICE_ID_KEYTOUCH_IEC 0x3333
+
#define USB_VENDOR_ID_KYE 0x0458
#define USB_DEVICE_ID_KYE_ERGO_525V 0x0087
#define USB_DEVICE_ID_KYE_GPEN_560 0x5003
@@ -330,6 +361,9 @@
#define USB_VENDOR_ID_LABTEC 0x1020
#define USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD 0x0006
+#define USB_VENDOR_ID_LCPOWER 0x1241
+#define USB_DEVICE_ID_LCPOWER_LC1000 0xf767
+
#define USB_VENDOR_ID_LD 0x0f11
#define USB_DEVICE_ID_LD_CASSY 0x1000
#define USB_DEVICE_ID_LD_POCKETCASSY 0x1010
@@ -361,6 +395,7 @@
#define USB_DEVICE_ID_LOGITECH_WHEEL 0xc294
#define USB_DEVICE_ID_LOGITECH_WINGMAN_FFG 0xc293
#define USB_DEVICE_ID_LOGITECH_MOMO_WHEEL 0xc295
+#define USB_DEVICE_ID_LOGITECH_DFP_WHEEL 0xc298
#define USB_DEVICE_ID_LOGITECH_G25_WHEEL 0xc299
#define USB_DEVICE_ID_LOGITECH_WII_WHEEL 0xc29c
#define USB_DEVICE_ID_LOGITECH_ELITE_KBD 0xc30a
@@ -444,6 +479,7 @@
#define USB_DEVICE_ID_ONTRAK_ADU100 0x0064
#define USB_VENDOR_ID_ORTEK 0x05a4
+#define USB_DEVICE_ID_ORTEK_PKB1700 0x1700
#define USB_DEVICE_ID_ORTEK_WKB2000 0x2000
#define USB_VENDOR_ID_PANJIT 0x134c
@@ -474,7 +510,10 @@
#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001
#define USB_VENDOR_ID_ROCCAT 0x1e7d
+#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
+#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
+#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
diff --git a/drivers/hid/hid-input.c b/drivers/hid/hid-input.c
index d8d372bae3cc..33dde8724e02 100644
--- a/drivers/hid/hid-input.c
+++ b/drivers/hid/hid-input.c
@@ -319,21 +319,21 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
switch (field->application) {
case HID_GD_MOUSE:
- case HID_GD_POINTER: code += 0x110; break;
+ case HID_GD_POINTER: code += BTN_MOUSE; break;
case HID_GD_JOYSTICK:
if (code <= 0xf)
code += BTN_JOYSTICK;
else
code += BTN_TRIGGER_HAPPY;
break;
- case HID_GD_GAMEPAD: code += 0x130; break;
+ case HID_GD_GAMEPAD: code += BTN_GAMEPAD; break;
default:
switch (field->physical) {
case HID_GD_MOUSE:
- case HID_GD_POINTER: code += 0x110; break;
- case HID_GD_JOYSTICK: code += 0x120; break;
- case HID_GD_GAMEPAD: code += 0x130; break;
- default: code += 0x100;
+ case HID_GD_POINTER: code += BTN_MOUSE; break;
+ case HID_GD_JOYSTICK: code += BTN_JOYSTICK; break;
+ case HID_GD_GAMEPAD: code += BTN_GAMEPAD; break;
+ default: code += BTN_MISC;
}
}
@@ -817,14 +817,32 @@ static int hidinput_open(struct input_dev *dev)
{
struct hid_device *hid = input_get_drvdata(dev);
- return hid->ll_driver->open(hid);
+ return hid_hw_open(hid);
}
static void hidinput_close(struct input_dev *dev)
{
struct hid_device *hid = input_get_drvdata(dev);
- hid->ll_driver->close(hid);
+ hid_hw_close(hid);
+}
+
+static void report_features(struct hid_device *hid)
+{
+ struct hid_driver *drv = hid->driver;
+ struct hid_report_enum *rep_enum;
+ struct hid_report *rep;
+ int i, j;
+
+ if (!drv->feature_mapping)
+ return;
+
+ rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
+ list_for_each_entry(rep, &rep_enum->report_list, list)
+ for (i = 0; i < rep->maxfield; i++)
+ for (j = 0; j < rep->field[i]->maxusage; j++)
+ drv->feature_mapping(hid, rep->field[i],
+ rep->field[i]->usage + j);
}
/*
@@ -839,7 +857,6 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
struct hid_input *hidinput = NULL;
struct input_dev *input_dev;
int i, j, k;
- int max_report_type = HID_OUTPUT_REPORT;
INIT_LIST_HEAD(&hid->inputs);
@@ -856,10 +873,13 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
return -1;
}
- if (hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
- max_report_type = HID_INPUT_REPORT;
+ report_features(hid);
+
+ for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
+ if (k == HID_OUTPUT_REPORT &&
+ hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
+ continue;
- for (k = HID_INPUT_REPORT; k <= max_report_type; k++)
list_for_each_entry(report, &hid->report_enum[k].report_list, list) {
if (!report->maxfield)
@@ -871,7 +891,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
if (!hidinput || !input_dev) {
kfree(hidinput);
input_free_device(input_dev);
- err_hid("Out of memory during hid input probe");
+ hid_err(hid, "Out of memory during hid input probe\n");
goto out_unwind;
}
@@ -880,8 +900,8 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
hid->ll_driver->hidinput_input_event;
input_dev->open = hidinput_open;
input_dev->close = hidinput_close;
- input_dev->setkeycode_new = hidinput_setkeycode;
- input_dev->getkeycode_new = hidinput_getkeycode;
+ input_dev->setkeycode = hidinput_setkeycode;
+ input_dev->getkeycode = hidinput_getkeycode;
input_dev->name = hid->name;
input_dev->phys = hid->phys;
@@ -912,6 +932,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
hidinput = NULL;
}
}
+ }
if (hidinput && input_register_device(hidinput->input))
goto out_cleanup;
@@ -919,6 +940,7 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
return 0;
out_cleanup:
+ list_del(&hidinput->list);
input_free_device(hidinput->input);
kfree(hidinput);
out_unwind:
diff --git a/drivers/hid/hid-keytouch.c b/drivers/hid/hid-keytouch.c
new file mode 100644
index 000000000000..07cd825f6f01
--- /dev/null
+++ b/drivers/hid/hid-keytouch.c
@@ -0,0 +1,66 @@
+/*
+ * HID driver for Keytouch devices not fully compliant with HID standard
+ *
+ * Copyright (c) 2011 Jiri Kosina
+ */
+
+/*
+ * 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"
+
+/* Replace the broken report descriptor of this device with rather
+ * a default one */
+static __u8 keytouch_fixed_rdesc[] = {
+0x05, 0x01, 0x09, 0x06, 0xa1, 0x01, 0x05, 0x07, 0x19, 0xe0, 0x29, 0xe7, 0x15,
+0x00, 0x25, 0x01, 0x75, 0x01, 0x95, 0x08, 0x81, 0x02, 0x95, 0x01, 0x75, 0x08,
+0x81, 0x01, 0x95, 0x03, 0x75, 0x01, 0x05, 0x08, 0x19, 0x01, 0x29, 0x03, 0x91,
+0x02, 0x95, 0x05, 0x75, 0x01, 0x91, 0x01, 0x95, 0x06, 0x75, 0x08, 0x15, 0x00,
+0x26, 0xff, 0x00, 0x05, 0x07, 0x19, 0x00, 0x2a, 0xff, 0x00, 0x81, 0x00, 0xc0
+};
+
+static __u8 *keytouch_report_fixup(struct hid_device *hdev, __u8 *rdesc,
+ unsigned int *rsize)
+{
+ hid_info(hdev, "fixing up Keytouch IEC report descriptor\n");
+
+ rdesc = keytouch_fixed_rdesc;
+ *rsize = sizeof(keytouch_fixed_rdesc);
+
+ return rdesc;
+}
+
+static const struct hid_device_id keytouch_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, keytouch_devices);
+
+static struct hid_driver keytouch_driver = {
+ .name = "keytouch",
+ .id_table = keytouch_devices,
+ .report_fixup = keytouch_report_fixup,
+};
+
+static int __init keytouch_init(void)
+{
+ return hid_register_driver(&keytouch_driver);
+}
+
+static void __exit keytouch_exit(void)
+{
+ hid_unregister_driver(&keytouch_driver);
+}
+
+module_init(keytouch_init);
+module_exit(keytouch_exit);
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jiri Kosina");
diff --git a/drivers/hid/hid-kye.c b/drivers/hid/hid-kye.c
index 817247ee006c..f2ba9efc3a53 100644
--- a/drivers/hid/hid-kye.c
+++ b/drivers/hid/hid-kye.c
@@ -32,8 +32,8 @@ static __u8 *kye_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[65] == 0x29 && rdesc[66] == 0x0f &&
rdesc[71] == 0x75 && rdesc[72] == 0x08 &&
rdesc[73] == 0x95 && rdesc[74] == 0x01) {
- dev_info(&hdev->dev, "fixing up Kye/Genius Ergo Mouse report "
- "descriptor\n");
+ hid_info(hdev,
+ "fixing up Kye/Genius Ergo Mouse report descriptor\n");
rdesc[62] = 0x09;
rdesc[64] = 0x04;
rdesc[66] = 0x07;
diff --git a/drivers/hid/hid-lcpower.c b/drivers/hid/hid-lcpower.c
new file mode 100644
index 000000000000..c4fe9bd095b7
--- /dev/null
+++ b/drivers/hid/hid-lcpower.c
@@ -0,0 +1,70 @@
+/*
+ * HID driver for LC Power Model RC1000MCE
+ *
+ * Copyright (c) 2011 Chris Schlund
+ * based on hid-topseed module
+ */
+
+/*
+ * 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"
+
+#define ts_map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, \
+ EV_KEY, (c))
+static int ts_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if ((usage->hid & HID_USAGE_PAGE) != 0x0ffbc0000)
+ return 0;
+
+ switch (usage->hid & HID_USAGE) {
+ case 0x046: ts_map_key_clear(KEY_YELLOW); break;
+ case 0x047: ts_map_key_clear(KEY_GREEN); break;
+ case 0x049: ts_map_key_clear(KEY_BLUE); break;
+ case 0x04a: ts_map_key_clear(KEY_RED); break;
+ case 0x00d: ts_map_key_clear(KEY_HOME); break;
+ case 0x025: ts_map_key_clear(KEY_TV); break;
+ case 0x048: ts_map_key_clear(KEY_VCR); break;
+ case 0x024: ts_map_key_clear(KEY_MENU); break;
+ default:
+ return 0;
+ }
+
+ return 1;
+}
+
+static const struct hid_device_id ts_devices[] = {
+ { HID_USB_DEVICE( USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000) },
+ { }
+};
+MODULE_DEVICE_TABLE(hid, ts_devices);
+
+static struct hid_driver ts_driver = {
+ .name = "LC RC1000MCE",
+ .id_table = ts_devices,
+ .input_mapping = ts_input_mapping,
+};
+
+static int __init ts_init(void)
+{
+ return hid_register_driver(&ts_driver);
+}
+
+static void __exit ts_exit(void)
+{
+ hid_unregister_driver(&ts_driver);
+}
+
+module_init(ts_init);
+module_exit(ts_exit);
+MODULE_LICENSE("GPL");
diff --git a/drivers/hid/hid-lg.c b/drivers/hid/hid-lg.c
index b629fba5a057..3da90402ee81 100644
--- a/drivers/hid/hid-lg.c
+++ b/drivers/hid/hid-lg.c
@@ -53,23 +53,22 @@ static __u8 *lg_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if ((quirks & LG_RDESC) && *rsize >= 90 && rdesc[83] == 0x26 &&
rdesc[84] == 0x8c && rdesc[85] == 0x02) {
- dev_info(&hdev->dev, "fixing up Logitech keyboard report "
- "descriptor\n");
+ hid_info(hdev,
+ "fixing up Logitech keyboard report descriptor\n");
rdesc[84] = rdesc[89] = 0x4d;
rdesc[85] = rdesc[90] = 0x10;
}
if ((quirks & LG_RDESC_REL_ABS) && *rsize >= 50 &&
rdesc[32] == 0x81 && rdesc[33] == 0x06 &&
rdesc[49] == 0x81 && rdesc[50] == 0x06) {
- dev_info(&hdev->dev, "fixing up rel/abs in Logitech "
- "report descriptor\n");
+ hid_info(hdev,
+ "fixing up rel/abs in Logitech report descriptor\n");
rdesc[33] = rdesc[50] = 0x02;
}
if ((quirks & LG_FF4) && *rsize >= 101 &&
rdesc[41] == 0x95 && rdesc[42] == 0x0B &&
rdesc[47] == 0x05 && rdesc[48] == 0x09) {
- dev_info(&hdev->dev, "fixing up Logitech Speed Force Wireless "
- "button descriptor\n");
+ hid_info(hdev, "fixing up Logitech Speed Force Wireless button descriptor\n");
rdesc[41] = 0x05;
rdesc[42] = 0x09;
rdesc[47] = 0x95;
@@ -288,7 +287,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
@@ -297,7 +296,7 @@ static int lg_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_hw_start(hdev, connect_mask);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
@@ -378,6 +377,8 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G25_WHEEL),
.driver_data = LG_FF },
+ { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_DFP_WHEEL),
+ .driver_data = LG_FF },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WII_WHEEL),
.driver_data = LG_FF4 },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_WINGMAN_FFG ),
diff --git a/drivers/hid/hid-lg2ff.c b/drivers/hid/hid-lg2ff.c
index 4258253c36b3..3c31bc650e5d 100644
--- a/drivers/hid/hid-lg2ff.c
+++ b/drivers/hid/hid-lg2ff.c
@@ -72,18 +72,18 @@ int lg2ff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output report found\n");
+ hid_err(hid, "no output report found\n");
return -ENODEV;
}
report = list_entry(report_list->next, struct hid_report, list);
if (report->maxfield < 1) {
- dev_err(&hid->dev, "output report is empty\n");
+ hid_err(hid, "output report is empty\n");
return -ENODEV;
}
if (report->field[0]->report_count < 7) {
- dev_err(&hid->dev, "not enough values in the field\n");
+ hid_err(hid, "not enough values in the field\n");
return -ENODEV;
}
@@ -110,8 +110,7 @@ int lg2ff_init(struct hid_device *hid)
usbhid_submit_report(hid, report, USB_DIR_OUT);
- dev_info(&hid->dev, "Force feedback for Logitech RumblePad/Rumblepad 2 by "
- "Anssi Hannula <anssi.hannula@gmail.com>\n");
+ hid_info(hid, "Force feedback for Logitech RumblePad/Rumblepad 2 by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
}
diff --git a/drivers/hid/hid-lg3ff.c b/drivers/hid/hid-lg3ff.c
index 4002832ee4af..f98644c26c1d 100644
--- a/drivers/hid/hid-lg3ff.c
+++ b/drivers/hid/hid-lg3ff.c
@@ -141,20 +141,20 @@ int lg3ff_init(struct hid_device *hid)
/* Find the report to use */
if (list_empty(report_list)) {
- err_hid("No output report found");
+ hid_err(hid, "No output report found\n");
return -1;
}
/* Check that the report looks ok */
report = list_entry(report_list->next, struct hid_report, list);
if (!report) {
- err_hid("NULL output report");
+ hid_err(hid, "NULL output report\n");
return -1;
}
field = report->field[0];
if (!field) {
- err_hid("NULL field");
+ hid_err(hid, "NULL field\n");
return -1;
}
@@ -169,8 +169,7 @@ int lg3ff_init(struct hid_device *hid)
if (test_bit(FF_AUTOCENTER, dev->ffbit))
dev->ff->set_autocenter = hid_lg3ff_set_autocenter;
- dev_info(&hid->dev, "Force feedback for Logitech Flight System G940 by "
- "Gary Stein <LordCnidarian@gmail.com>\n");
+ hid_info(hid, "Force feedback for Logitech Flight System G940 by Gary Stein <LordCnidarian@gmail.com>\n");
return 0;
}
diff --git a/drivers/hid/hid-lg4ff.c b/drivers/hid/hid-lg4ff.c
index 7eef5a2ce948..fa550c8e1d1b 100644
--- a/drivers/hid/hid-lg4ff.c
+++ b/drivers/hid/hid-lg4ff.c
@@ -101,20 +101,20 @@ int lg4ff_init(struct hid_device *hid)
/* Find the report to use */
if (list_empty(report_list)) {
- err_hid("No output report found");
+ hid_err(hid, "No output report found\n");
return -1;
}
/* Check that the report looks ok */
report = list_entry(report_list->next, struct hid_report, list);
if (!report) {
- err_hid("NULL output report");
+ hid_err(hid, "NULL output report\n");
return -1;
}
field = report->field[0];
if (!field) {
- err_hid("NULL field");
+ hid_err(hid, "NULL field\n");
return -1;
}
@@ -129,8 +129,7 @@ int lg4ff_init(struct hid_device *hid)
if (test_bit(FF_AUTOCENTER, dev->ffbit))
dev->ff->set_autocenter = hid_lg4ff_set_autocenter;
- dev_info(&hid->dev, "Force feedback for Logitech Speed Force Wireless by "
- "Simon Wood <simon@mungewell.org>\n");
+ hid_info(hid, "Force feedback for Logitech Speed Force Wireless by Simon Wood <simon@mungewell.org>\n");
return 0;
}
diff --git a/drivers/hid/hid-lgff.c b/drivers/hid/hid-lgff.c
index 61142b76a9b1..90d0ef2c92be 100644
--- a/drivers/hid/hid-lgff.c
+++ b/drivers/hid/hid-lgff.c
@@ -27,6 +27,8 @@
* e-mail - mail your message to <johann.deneux@it.uu.se>
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h>
@@ -146,7 +148,7 @@ int lgff_init(struct hid_device* hid)
/* Find the report to use */
if (list_empty(report_list)) {
- err_hid("No output report found");
+ hid_err(hid, "No output report found\n");
return -1;
}
@@ -154,7 +156,7 @@ int lgff_init(struct hid_device* hid)
report = list_entry(report_list->next, struct hid_report, list);
field = report->field[0];
if (!field) {
- err_hid("NULL field");
+ hid_err(hid, "NULL field\n");
return -1;
}
@@ -176,7 +178,7 @@ int lgff_init(struct hid_device* hid)
if ( test_bit(FF_AUTOCENTER, dev->ffbit) )
dev->ff->set_autocenter = hid_lgff_set_autocenter;
- printk(KERN_INFO "Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
+ pr_info("Force feedback for Logitech force feedback devices by Johann Deneux <johann.deneux@it.uu.se>\n");
return 0;
}
diff --git a/drivers/hid/hid-magicmouse.c b/drivers/hid/hid-magicmouse.c
index e6dc15171664..318cc40df92d 100644
--- a/drivers/hid/hid-magicmouse.c
+++ b/drivers/hid/hid-magicmouse.c
@@ -12,6 +12,8 @@
* any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
@@ -256,7 +258,7 @@ static void magicmouse_emit_touch(struct magicmouse_sc *msc, int raw_id, u8 *tda
input_report_abs(input, ABS_MT_TRACKING_ID, id);
input_report_abs(input, ABS_MT_TOUCH_MAJOR, touch_major << 2);
input_report_abs(input, ABS_MT_TOUCH_MINOR, touch_minor << 2);
- input_report_abs(input, ABS_MT_ORIENTATION, orientation);
+ input_report_abs(input, ABS_MT_ORIENTATION, -orientation);
input_report_abs(input, ABS_MT_POSITION_X, x);
input_report_abs(input, ABS_MT_POSITION_Y, y);
@@ -395,7 +397,7 @@ static void magicmouse_setup_input(struct input_dev *input, struct hid_device *h
input_set_abs_params(input, ABS_MT_TRACKING_ID, 0, 15, 0, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MAJOR, 0, 255, 4, 0);
input_set_abs_params(input, ABS_MT_TOUCH_MINOR, 0, 255, 4, 0);
- input_set_abs_params(input, ABS_MT_ORIENTATION, -32, 31, 1, 0);
+ input_set_abs_params(input, ABS_MT_ORIENTATION, -31, 32, 1, 0);
/* Note: Touch Y position from the device is inverted relative
* to how pointer motion is reported (and relative to how USB
@@ -433,6 +435,11 @@ static int magicmouse_input_mapping(struct hid_device *hdev,
if (!msc->input)
msc->input = hi->input;
+ /* Magic Trackpad does not give relative data after switching to MT */
+ if (hi->input->id.product == USB_DEVICE_ID_APPLE_MAGICTRACKPAD &&
+ field->flags & HID_MAIN_ITEM_RELATIVE)
+ return -1;
+
return 0;
}
@@ -446,7 +453,7 @@ static int magicmouse_probe(struct hid_device *hdev,
msc = kzalloc(sizeof(*msc), GFP_KERNEL);
if (msc == NULL) {
- dev_err(&hdev->dev, "can't alloc magicmouse descriptor\n");
+ hid_err(hdev, "can't alloc magicmouse descriptor\n");
return -ENOMEM;
}
@@ -459,13 +466,13 @@ static int magicmouse_probe(struct hid_device *hdev,
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "magicmouse hid parse failed\n");
+ hid_err(hdev, "magicmouse hid parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "magicmouse hw start failed\n");
+ hid_err(hdev, "magicmouse hw start failed\n");
goto err_free;
}
@@ -486,7 +493,7 @@ static int magicmouse_probe(struct hid_device *hdev,
}
if (!report) {
- dev_err(&hdev->dev, "unable to register touch report\n");
+ hid_err(hdev, "unable to register touch report\n");
ret = -ENOMEM;
goto err_stop_hw;
}
@@ -495,8 +502,7 @@ static int magicmouse_probe(struct hid_device *hdev,
ret = hdev->hid_output_raw_report(hdev, feature, sizeof(feature),
HID_FEATURE_REPORT);
if (ret != sizeof(feature)) {
- dev_err(&hdev->dev, "unable to request touch data (%d)\n",
- ret);
+ hid_err(hdev, "unable to request touch data (%d)\n", ret);
goto err_stop_hw;
}
@@ -540,7 +546,7 @@ static int __init magicmouse_init(void)
ret = hid_register_driver(&magicmouse_driver);
if (ret)
- printk(KERN_ERR "can't register magicmouse driver\n");
+ pr_err("can't register magicmouse driver\n");
return ret;
}
diff --git a/drivers/hid/hid-microsoft.c b/drivers/hid/hid-microsoft.c
index dc618c33d0a2..0f6fc54dc196 100644
--- a/drivers/hid/hid-microsoft.c
+++ b/drivers/hid/hid-microsoft.c
@@ -40,8 +40,7 @@ static __u8 *ms_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if ((quirks & MS_RDESC) && *rsize == 571 && rdesc[557] == 0x19 &&
rdesc[559] == 0x29) {
- dev_info(&hdev->dev, "fixing up Microsoft Wireless Receiver "
- "Model 1028 report descriptor\n");
+ hid_info(hdev, "fixing up Microsoft Wireless Receiver Model 1028 report descriptor\n");
rdesc[557] = 0x35;
rdesc[559] = 0x45;
}
@@ -155,14 +154,14 @@ static int ms_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT | ((quirks & MS_HIDINPUT) ?
HID_CONNECT_HIDINPUT_FORCE : 0));
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-monterey.c b/drivers/hid/hid-monterey.c
index c95c31e2d869..dedf757781ae 100644
--- a/drivers/hid/hid-monterey.c
+++ b/drivers/hid/hid-monterey.c
@@ -26,8 +26,7 @@ static __u8 *mr_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize >= 30 && rdesc[29] == 0x05 && rdesc[30] == 0x09) {
- dev_info(&hdev->dev, "fixing up button/consumer in HID report "
- "descriptor\n");
+ hid_info(hdev, "fixing up button/consumer in HID report descriptor\n");
rdesc[30] = 0x0c;
}
return rdesc;
diff --git a/drivers/hid/hid-mosart.c b/drivers/hid/hid-mosart.c
index ac5421d568f1..aed7ffe36283 100644
--- a/drivers/hid/hid-mosart.c
+++ b/drivers/hid/hid-mosart.c
@@ -90,6 +90,10 @@ static int mosart_input_mapping(struct hid_device *hdev, struct hid_input *hi,
case 0xff000000:
/* ignore HID features */
return -1;
+
+ case HID_UP_BUTTON:
+ /* ignore buttons */
+ return -1;
}
return 0;
@@ -199,7 +203,7 @@ static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
td = kmalloc(sizeof(struct mosart_data), GFP_KERNEL);
if (!td) {
- dev_err(&hdev->dev, "cannot allocate MosArt data\n");
+ hid_err(hdev, "cannot allocate MosArt data\n");
return -ENOMEM;
}
td->valid = false;
@@ -230,6 +234,19 @@ static int mosart_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
+#ifdef CONFIG_PM
+static int mosart_reset_resume(struct hid_device *hdev)
+{
+ struct hid_report_enum *re = hdev->report_enum
+ + HID_FEATURE_REPORT;
+ struct hid_report *r = re->report_id_hash[7];
+
+ r->field[0]->value[0] = 0x02;
+ usbhid_submit_report(hdev, r, USB_DIR_OUT);
+ return 0;
+}
+#endif
+
static void mosart_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
@@ -240,6 +257,7 @@ static void mosart_remove(struct hid_device *hdev)
static const struct hid_device_id mosart_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUS_T91MT) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ASUS, USB_DEVICE_ID_ASUSTEK_MULTITOUCH_YFO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART) },
{ }
};
MODULE_DEVICE_TABLE(hid, mosart_devices);
@@ -258,6 +276,9 @@ static struct hid_driver mosart_driver = {
.input_mapped = mosart_input_mapped,
.usage_table = mosart_grabbed_usages,
.event = mosart_event,
+#ifdef CONFIG_PM
+ .reset_resume = mosart_reset_resume,
+#endif
};
static int __init mosart_init(void)
diff --git a/drivers/hid/hid-multitouch.c b/drivers/hid/hid-multitouch.c
new file mode 100644
index 000000000000..ee01e65e22d6
--- /dev/null
+++ b/drivers/hid/hid-multitouch.c
@@ -0,0 +1,568 @@
+/*
+ * HID driver for multitouch panels
+ *
+ * Copyright (c) 2010-2011 Stephane Chatty <chatty@enac.fr>
+ * Copyright (c) 2010-2011 Benjamin Tissoires <benjamin.tissoires@gmail.com>
+ * Copyright (c) 2010-2011 Ecole Nationale de l'Aviation Civile, France
+ *
+ * This code is partly based on hid-egalax.c:
+ *
+ * Copyright (c) 2010 Stephane Chatty <chatty@enac.fr>
+ * Copyright (c) 2010 Henrik Rydberg <rydberg@euromail.se>
+ * Copyright (c) 2010 Canonical, Ltd.
+ *
+ */
+
+/*
+ * 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 <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/input/mt.h>
+#include "usbhid/usbhid.h"
+
+
+MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
+MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@gmail.com>");
+MODULE_DESCRIPTION("HID multitouch panels");
+MODULE_LICENSE("GPL");
+
+#include "hid-ids.h"
+
+/* quirks to control the device */
+#define MT_QUIRK_NOT_SEEN_MEANS_UP (1 << 0)
+#define MT_QUIRK_SLOT_IS_CONTACTID (1 << 1)
+#define MT_QUIRK_CYPRESS (1 << 2)
+#define MT_QUIRK_SLOT_IS_CONTACTNUMBER (1 << 3)
+#define MT_QUIRK_VALID_IS_INRANGE (1 << 4)
+#define MT_QUIRK_VALID_IS_CONFIDENCE (1 << 5)
+#define MT_QUIRK_EGALAX_XYZ_FIXUP (1 << 6)
+
+struct mt_slot {
+ __s32 x, y, p, w, h;
+ __s32 contactid; /* the device ContactID assigned to this slot */
+ bool touch_state; /* is the touch valid? */
+ bool seen_in_this_frame;/* has this slot been updated */
+};
+
+struct mt_device {
+ struct mt_slot curdata; /* placeholder of incoming data */
+ struct mt_class *mtclass; /* our mt device class */
+ unsigned last_field_index; /* last field index of the report */
+ unsigned last_slot_field; /* the last field of a slot */
+ __s8 inputmode; /* InputMode HID feature, -1 if non-existent */
+ __u8 num_received; /* how many contacts we received */
+ __u8 num_expected; /* expected last contact index */
+ bool curvalid; /* is the current contact valid? */
+ struct mt_slot slots[0]; /* first slot */
+};
+
+struct mt_class {
+ __s32 name; /* MT_CLS */
+ __s32 quirks;
+ __s32 sn_move; /* Signal/noise ratio for move events */
+ __s32 sn_pressure; /* Signal/noise ratio for pressure events */
+ __u8 maxcontacts;
+};
+
+/* classes of device behavior */
+#define MT_CLS_DEFAULT 1
+#define MT_CLS_DUAL_INRANGE_CONTACTID 2
+#define MT_CLS_DUAL_INRANGE_CONTACTNUMBER 3
+#define MT_CLS_CYPRESS 4
+#define MT_CLS_EGALAX 5
+
+/*
+ * these device-dependent functions determine what slot corresponds
+ * to a valid contact that was just read.
+ */
+
+static int cypress_compute_slot(struct mt_device *td)
+{
+ if (td->curdata.contactid != 0 || td->num_received == 0)
+ return td->curdata.contactid;
+ else
+ return -1;
+}
+
+static int find_slot_from_contactid(struct mt_device *td)
+{
+ int i;
+ for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+ if (td->slots[i].contactid == td->curdata.contactid &&
+ td->slots[i].touch_state)
+ return i;
+ }
+ for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+ if (!td->slots[i].seen_in_this_frame &&
+ !td->slots[i].touch_state)
+ return i;
+ }
+ /* should not occurs. If this happens that means
+ * that the device sent more touches that it says
+ * in the report descriptor. It is ignored then. */
+ return -1;
+}
+
+struct mt_class mt_classes[] = {
+ { .name = MT_CLS_DEFAULT,
+ .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP,
+ .maxcontacts = 10 },
+ { .name = MT_CLS_DUAL_INRANGE_CONTACTID,
+ .quirks = MT_QUIRK_VALID_IS_INRANGE |
+ MT_QUIRK_SLOT_IS_CONTACTID,
+ .maxcontacts = 2 },
+ { .name = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
+ .quirks = MT_QUIRK_VALID_IS_INRANGE |
+ MT_QUIRK_SLOT_IS_CONTACTNUMBER,
+ .maxcontacts = 2 },
+ { .name = MT_CLS_CYPRESS,
+ .quirks = MT_QUIRK_NOT_SEEN_MEANS_UP |
+ MT_QUIRK_CYPRESS,
+ .maxcontacts = 10 },
+
+ { .name = MT_CLS_EGALAX,
+ .quirks = MT_QUIRK_SLOT_IS_CONTACTID |
+ MT_QUIRK_VALID_IS_INRANGE |
+ MT_QUIRK_EGALAX_XYZ_FIXUP,
+ .maxcontacts = 2,
+ .sn_move = 4096,
+ .sn_pressure = 32,
+ },
+ { }
+};
+
+static void mt_feature_mapping(struct hid_device *hdev,
+ struct hid_field *field, struct hid_usage *usage)
+{
+ if (usage->hid == HID_DG_INPUTMODE) {
+ struct mt_device *td = hid_get_drvdata(hdev);
+ td->inputmode = field->report->id;
+ }
+}
+
+static void set_abs(struct input_dev *input, unsigned int code,
+ struct hid_field *field, int snratio)
+{
+ int fmin = field->logical_minimum;
+ int fmax = field->logical_maximum;
+ int fuzz = snratio ? (fmax - fmin) / snratio : 0;
+ input_set_abs_params(input, code, fmin, fmax, fuzz, 0);
+}
+
+static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ struct mt_device *td = hid_get_drvdata(hdev);
+ struct mt_class *cls = td->mtclass;
+ __s32 quirks = cls->quirks;
+
+ switch (usage->hid & HID_USAGE_PAGE) {
+
+ case HID_UP_GENDESK:
+ switch (usage->hid) {
+ case HID_GD_X:
+ if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
+ field->logical_maximum = 32760;
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_X);
+ set_abs(hi->input, ABS_MT_POSITION_X, field,
+ cls->sn_move);
+ /* touchscreen emulation */
+ set_abs(hi->input, ABS_X, field, cls->sn_move);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_GD_Y:
+ if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
+ field->logical_maximum = 32760;
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_POSITION_Y);
+ set_abs(hi->input, ABS_MT_POSITION_Y, field,
+ cls->sn_move);
+ /* touchscreen emulation */
+ set_abs(hi->input, ABS_Y, field, cls->sn_move);
+ td->last_slot_field = usage->hid;
+ return 1;
+ }
+ return 0;
+
+ case HID_UP_DIGITIZER:
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_CONFIDENCE:
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_TIPSWITCH:
+ hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
+ input_set_capability(hi->input, EV_KEY, BTN_TOUCH);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_CONTACTID:
+ input_mt_init_slots(hi->input,
+ td->mtclass->maxcontacts);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_WIDTH:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TOUCH_MAJOR);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_HEIGHT:
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_TOUCH_MINOR);
+ field->logical_maximum = 1;
+ field->logical_minimum = 0;
+ set_abs(hi->input, ABS_MT_ORIENTATION, field, 0);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_TIPPRESSURE:
+ if (quirks & MT_QUIRK_EGALAX_XYZ_FIXUP)
+ field->logical_minimum = 0;
+ hid_map_usage(hi, usage, bit, max,
+ EV_ABS, ABS_MT_PRESSURE);
+ set_abs(hi->input, ABS_MT_PRESSURE, field,
+ cls->sn_pressure);
+ /* touchscreen emulation */
+ set_abs(hi->input, ABS_PRESSURE, field,
+ cls->sn_pressure);
+ td->last_slot_field = usage->hid;
+ return 1;
+ case HID_DG_CONTACTCOUNT:
+ td->last_field_index = field->report->maxfield - 1;
+ return 1;
+ case HID_DG_CONTACTMAX:
+ /* we don't set td->last_slot_field as contactcount and
+ * contact max are global to the report */
+ return -1;
+ }
+ /* let hid-input decide for the others */
+ return 0;
+
+ case 0xff000000:
+ /* we do not want to map these: no input-oriented meaning */
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
+ struct hid_field *field, struct hid_usage *usage,
+ unsigned long **bit, int *max)
+{
+ if (usage->type == EV_KEY || usage->type == EV_ABS)
+ set_bit(usage->type, hi->input->evbit);
+
+ return -1;
+}
+
+static int mt_compute_slot(struct mt_device *td)
+{
+ __s32 quirks = td->mtclass->quirks;
+
+ if (quirks & MT_QUIRK_SLOT_IS_CONTACTID)
+ return td->curdata.contactid;
+
+ if (quirks & MT_QUIRK_CYPRESS)
+ return cypress_compute_slot(td);
+
+ if (quirks & MT_QUIRK_SLOT_IS_CONTACTNUMBER)
+ return td->num_received;
+
+ return find_slot_from_contactid(td);
+}
+
+/*
+ * this function is called when a whole contact has been processed,
+ * so that it can assign it to a slot and store the data there
+ */
+static void mt_complete_slot(struct mt_device *td)
+{
+ td->curdata.seen_in_this_frame = true;
+ if (td->curvalid) {
+ int slotnum = mt_compute_slot(td);
+
+ if (slotnum >= 0 && slotnum < td->mtclass->maxcontacts)
+ td->slots[slotnum] = td->curdata;
+ }
+ td->num_received++;
+}
+
+
+/*
+ * this function is called when a whole packet has been received and processed,
+ * so that it can decide what to send to the input layer.
+ */
+static void mt_emit_event(struct mt_device *td, struct input_dev *input)
+{
+ int i;
+
+ for (i = 0; i < td->mtclass->maxcontacts; ++i) {
+ struct mt_slot *s = &(td->slots[i]);
+ if ((td->mtclass->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP) &&
+ !s->seen_in_this_frame) {
+ s->touch_state = false;
+ }
+
+ input_mt_slot(input, i);
+ input_mt_report_slot_state(input, MT_TOOL_FINGER,
+ s->touch_state);
+ if (s->touch_state) {
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, s->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, s->y);
+ input_event(input, EV_ABS, ABS_MT_PRESSURE, s->p);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MAJOR, s->w);
+ input_event(input, EV_ABS, ABS_MT_TOUCH_MINOR, s->h);
+ }
+ s->seen_in_this_frame = false;
+
+ }
+
+ input_mt_report_pointer_emulation(input, true);
+ input_sync(input);
+ td->num_received = 0;
+}
+
+
+
+static int mt_event(struct hid_device *hid, struct hid_field *field,
+ struct hid_usage *usage, __s32 value)
+{
+ struct mt_device *td = hid_get_drvdata(hid);
+ __s32 quirks = td->mtclass->quirks;
+
+ if (hid->claimed & HID_CLAIMED_INPUT) {
+ switch (usage->hid) {
+ case HID_DG_INRANGE:
+ if (quirks & MT_QUIRK_VALID_IS_INRANGE)
+ td->curvalid = value;
+ break;
+ case HID_DG_TIPSWITCH:
+ if (quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
+ td->curvalid = value;
+ td->curdata.touch_state = value;
+ break;
+ case HID_DG_CONFIDENCE:
+ if (quirks & MT_QUIRK_VALID_IS_CONFIDENCE)
+ td->curvalid = value;
+ break;
+ case HID_DG_CONTACTID:
+ td->curdata.contactid = value;
+ break;
+ case HID_DG_TIPPRESSURE:
+ td->curdata.p = value;
+ break;
+ case HID_GD_X:
+ td->curdata.x = value;
+ break;
+ case HID_GD_Y:
+ td->curdata.y = value;
+ break;
+ case HID_DG_WIDTH:
+ td->curdata.w = value;
+ break;
+ case HID_DG_HEIGHT:
+ td->curdata.h = value;
+ break;
+ case HID_DG_CONTACTCOUNT:
+ /*
+ * Includes multi-packet support where subsequent
+ * packets are sent with zero contactcount.
+ */
+ if (value)
+ td->num_expected = value;
+ break;
+
+ default:
+ /* fallback to the generic hidinput handling */
+ return 0;
+ }
+
+ if (usage->hid == td->last_slot_field) {
+ mt_complete_slot(td);
+ if (!td->last_field_index)
+ mt_emit_event(td, field->hidinput->input);
+ }
+
+ if (field->index == td->last_field_index
+ && td->num_received >= td->num_expected)
+ mt_emit_event(td, field->hidinput->input);
+
+ }
+
+ /* we have handled the hidinput part, now remains hiddev */
+ if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
+ hid->hiddev_hid_event(hid, field, usage, value);
+
+ return 1;
+}
+
+static void mt_set_input_mode(struct hid_device *hdev)
+{
+ struct mt_device *td = hid_get_drvdata(hdev);
+ struct hid_report *r;
+ struct hid_report_enum *re;
+
+ if (td->inputmode < 0)
+ return;
+
+ re = &(hdev->report_enum[HID_FEATURE_REPORT]);
+ r = re->report_id_hash[td->inputmode];
+ if (r) {
+ r->field[0]->value[0] = 0x02;
+ usbhid_submit_report(hdev, r, USB_DIR_OUT);
+ }
+}
+
+static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
+{
+ int ret, i;
+ struct mt_device *td;
+ struct mt_class *mtclass = mt_classes; /* MT_CLS_DEFAULT */
+
+ for (i = 0; mt_classes[i].name ; i++) {
+ if (id->driver_data == mt_classes[i].name) {
+ mtclass = &(mt_classes[i]);
+ break;
+ }
+ }
+
+ /* This allows the driver to correctly support devices
+ * that emit events over several HID messages.
+ */
+ hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
+
+ td = kzalloc(sizeof(struct mt_device) +
+ mtclass->maxcontacts * sizeof(struct mt_slot),
+ GFP_KERNEL);
+ if (!td) {
+ dev_err(&hdev->dev, "cannot allocate multitouch data\n");
+ return -ENOMEM;
+ }
+ td->mtclass = mtclass;
+ td->inputmode = -1;
+ hid_set_drvdata(hdev, td);
+
+ ret = hid_parse(hdev);
+ if (ret != 0)
+ goto fail;
+
+ ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (ret)
+ goto fail;
+
+ mt_set_input_mode(hdev);
+
+ return 0;
+
+fail:
+ kfree(td);
+ return ret;
+}
+
+#ifdef CONFIG_PM
+static int mt_reset_resume(struct hid_device *hdev)
+{
+ mt_set_input_mode(hdev);
+ return 0;
+}
+#endif
+
+static void mt_remove(struct hid_device *hdev)
+{
+ struct mt_device *td = hid_get_drvdata(hdev);
+ hid_hw_stop(hdev);
+ kfree(td);
+ hid_set_drvdata(hdev, NULL);
+}
+
+static const struct hid_device_id mt_devices[] = {
+
+ /* Cypress panel */
+ { .driver_data = MT_CLS_CYPRESS,
+ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS,
+ USB_DEVICE_ID_CYPRESS_TRUETOUCH) },
+
+ /* GeneralTouch panel */
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTNUMBER,
+ HID_USB_DEVICE(USB_VENDOR_ID_GENERAL_TOUCH,
+ USB_DEVICE_ID_GENERAL_TOUCH_WIN7_TWOFINGERS) },
+
+ /* IRTOUCH panels */
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
+ HID_USB_DEVICE(USB_VENDOR_ID_IRTOUCHSYSTEMS,
+ USB_DEVICE_ID_IRTOUCH_INFRARED_USB) },
+
+ /* PixCir-based panels */
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
+ HID_USB_DEVICE(USB_VENDOR_ID_HANVON,
+ USB_DEVICE_ID_HANVON_MULTITOUCH) },
+ { .driver_data = MT_CLS_DUAL_INRANGE_CONTACTID,
+ HID_USB_DEVICE(USB_VENDOR_ID_CANDO,
+ USB_DEVICE_ID_CANDO_PIXCIR_MULTI_TOUCH) },
+
+ /* Resistive eGalax devices */
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH) },
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3) },
+
+ /* Capacitive eGalax devices */
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1) },
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2) },
+ { .driver_data = MT_CLS_EGALAX,
+ HID_USB_DEVICE(USB_VENDOR_ID_DWAV,
+ USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4) },
+
+ { }
+};
+MODULE_DEVICE_TABLE(hid, mt_devices);
+
+static const struct hid_usage_id mt_grabbed_usages[] = {
+ { HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
+ { HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
+};
+
+static struct hid_driver mt_driver = {
+ .name = "hid-multitouch",
+ .id_table = mt_devices,
+ .probe = mt_probe,
+ .remove = mt_remove,
+ .input_mapping = mt_input_mapping,
+ .input_mapped = mt_input_mapped,
+ .feature_mapping = mt_feature_mapping,
+ .usage_table = mt_grabbed_usages,
+ .event = mt_event,
+#ifdef CONFIG_PM
+ .reset_resume = mt_reset_resume,
+#endif
+};
+
+static int __init mt_init(void)
+{
+ return hid_register_driver(&mt_driver);
+}
+
+static void __exit mt_exit(void)
+{
+ hid_unregister_driver(&mt_driver);
+}
+
+module_init(mt_init);
+module_exit(mt_exit);
diff --git a/drivers/hid/hid-ntrig.c b/drivers/hid/hid-ntrig.c
index 69169efa1e16..9fae2ebdd758 100644
--- a/drivers/hid/hid-ntrig.c
+++ b/drivers/hid/hid-ntrig.c
@@ -110,6 +110,36 @@ static int ntrig_version_string(unsigned char *raw, char *buf)
return sprintf(buf, "%u.%u.%u.%u.%u", a, b, c, d, e);
}
+static inline int ntrig_get_mode(struct hid_device *hdev)
+{
+ struct hid_report *report = hdev->report_enum[HID_FEATURE_REPORT].
+ report_id_hash[0x0d];
+
+ if (!report)
+ return -EINVAL;
+
+ usbhid_submit_report(hdev, report, USB_DIR_IN);
+ usbhid_wait_io(hdev);
+ return (int)report->field[0]->value[0];
+}
+
+static inline void ntrig_set_mode(struct hid_device *hdev, const int mode)
+{
+ struct hid_report *report;
+ __u8 mode_commands[4] = { 0xe, 0xf, 0x1b, 0x10 };
+
+ if (mode < 0 || mode > 3)
+ return;
+
+ report = hdev->report_enum[HID_FEATURE_REPORT].
+ report_id_hash[mode_commands[mode]];
+
+ if (!report)
+ return;
+
+ usbhid_submit_report(hdev, report, USB_DIR_IN);
+}
+
static void ntrig_report_version(struct hid_device *hdev)
{
int ret;
@@ -130,8 +160,7 @@ static void ntrig_report_version(struct hid_device *hdev)
if (ret == 8) {
ret = ntrig_version_string(&data[2], buf);
- dev_info(&hdev->dev,
- "Firmware version: %s (%02x%02x %02x%02x)\n",
+ hid_info(hdev, "Firmware version: %s (%02x%02x %02x%02x)\n",
buf, data[2], data[3], data[4], data[5]);
}
@@ -540,277 +569,288 @@ static int ntrig_input_mapped(struct hid_device *hdev, struct hid_input *hi,
static int ntrig_event (struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
- struct input_dev *input = field->hidinput->input;
struct ntrig_data *nd = hid_get_drvdata(hid);
+ struct input_dev *input;
+
+ /* Skip processing if not a claimed input */
+ if (!(hid->claimed & HID_CLAIMED_INPUT))
+ goto not_claimed_input;
+
+ /* This function is being called before the structures are fully
+ * initialized */
+ if(!(field->hidinput && field->hidinput->input))
+ return -EINVAL;
+
+ input = field->hidinput->input;
/* No special handling needed for the pen */
if (field->application == HID_DG_PEN)
return 0;
- if (hid->claimed & HID_CLAIMED_INPUT) {
- switch (usage->hid) {
- case 0xff000001:
- /* Tag indicating the start of a multitouch group */
- nd->reading_mt = 1;
- nd->first_contact_touch = 0;
- break;
- case HID_DG_TIPSWITCH:
- nd->tipswitch = value;
- /* Prevent emission of touch until validated */
- return 1;
- case HID_DG_CONFIDENCE:
- nd->confidence = value;
- break;
- case HID_GD_X:
- nd->x = value;
- /* Clear the contact footer */
- nd->mt_foot_count = 0;
- break;
- case HID_GD_Y:
- nd->y = value;
- break;
- case HID_DG_CONTACTID:
- nd->id = value;
- break;
- case HID_DG_WIDTH:
- nd->w = value;
- break;
- case HID_DG_HEIGHT:
- nd->h = value;
+ switch (usage->hid) {
+ case 0xff000001:
+ /* Tag indicating the start of a multitouch group */
+ nd->reading_mt = 1;
+ nd->first_contact_touch = 0;
+ break;
+ case HID_DG_TIPSWITCH:
+ nd->tipswitch = value;
+ /* Prevent emission of touch until validated */
+ return 1;
+ case HID_DG_CONFIDENCE:
+ nd->confidence = value;
+ break;
+ case HID_GD_X:
+ nd->x = value;
+ /* Clear the contact footer */
+ nd->mt_foot_count = 0;
+ break;
+ case HID_GD_Y:
+ nd->y = value;
+ break;
+ case HID_DG_CONTACTID:
+ nd->id = value;
+ break;
+ case HID_DG_WIDTH:
+ nd->w = value;
+ break;
+ case HID_DG_HEIGHT:
+ nd->h = value;
+ /*
+ * when in single touch mode, this is the last
+ * report received in a finger event. We want
+ * to emit a normal (X, Y) position
+ */
+ if (!nd->reading_mt) {
/*
- * when in single touch mode, this is the last
- * report received in a finger event. We want
- * to emit a normal (X, Y) position
+ * TipSwitch indicates the presence of a
+ * finger in single touch mode.
*/
- if (!nd->reading_mt) {
- /*
- * TipSwitch indicates the presence of a
- * finger in single touch mode.
- */
- input_report_key(input, BTN_TOUCH,
- nd->tipswitch);
- input_report_key(input, BTN_TOOL_DOUBLETAP,
- nd->tipswitch);
- input_event(input, EV_ABS, ABS_X, nd->x);
- input_event(input, EV_ABS, ABS_Y, nd->y);
- }
+ input_report_key(input, BTN_TOUCH,
+ nd->tipswitch);
+ input_report_key(input, BTN_TOOL_DOUBLETAP,
+ nd->tipswitch);
+ input_event(input, EV_ABS, ABS_X, nd->x);
+ input_event(input, EV_ABS, ABS_Y, nd->y);
+ }
+ break;
+ case 0xff000002:
+ /*
+ * we receive this when the device is in multitouch
+ * mode. The first of the three values tagged with
+ * this usage tells if the contact point is real
+ * or a placeholder
+ */
+
+ /* Shouldn't get more than 4 footer packets, so skip */
+ if (nd->mt_foot_count >= 4)
break;
- case 0xff000002:
- /*
- * we receive this when the device is in multitouch
- * mode. The first of the three values tagged with
- * this usage tells if the contact point is real
- * or a placeholder
- */
- /* Shouldn't get more than 4 footer packets, so skip */
- if (nd->mt_foot_count >= 4)
- break;
+ nd->mt_footer[nd->mt_foot_count++] = value;
- nd->mt_footer[nd->mt_foot_count++] = value;
+ /* if the footer isn't complete break */
+ if (nd->mt_foot_count != 4)
+ break;
- /* if the footer isn't complete break */
- if (nd->mt_foot_count != 4)
- break;
+ /* Pen activity signal. */
+ if (nd->mt_footer[2]) {
+ /*
+ * When the pen deactivates touch, we see a
+ * bogus frame with ContactCount > 0.
+ * We can
+ * save a bit of work by ensuring act_state < 0
+ * even if deactivation slack is turned off.
+ */
+ nd->act_state = deactivate_slack - 1;
+ nd->confidence = 0;
+ break;
+ }
- /* Pen activity signal. */
- if (nd->mt_footer[2]) {
- /*
- * When the pen deactivates touch, we see a
- * bogus frame with ContactCount > 0.
- * We can
- * save a bit of work by ensuring act_state < 0
- * even if deactivation slack is turned off.
- */
- nd->act_state = deactivate_slack - 1;
+ /*
+ * The first footer value indicates the presence of a
+ * finger.
+ */
+ if (nd->mt_footer[0]) {
+ /*
+ * We do not want to process contacts under
+ * the size threshold, but do not want to
+ * ignore them for activation state
+ */
+ if (nd->w < nd->min_width ||
+ nd->h < nd->min_height)
nd->confidence = 0;
- break;
- }
+ } else
+ break;
+ if (nd->act_state > 0) {
/*
- * The first footer value indicates the presence of a
- * finger.
+ * Contact meets the activation size threshold
*/
- if (nd->mt_footer[0]) {
- /*
- * We do not want to process contacts under
- * the size threshold, but do not want to
- * ignore them for activation state
- */
- if (nd->w < nd->min_width ||
- nd->h < nd->min_height)
- nd->confidence = 0;
- } else
- break;
-
- if (nd->act_state > 0) {
- /*
- * Contact meets the activation size threshold
- */
- if (nd->w >= nd->activation_width &&
- nd->h >= nd->activation_height) {
- if (nd->id)
- /*
- * first contact, activate now
- */
- nd->act_state = 0;
- else {
- /*
- * avoid corrupting this frame
- * but ensure next frame will
- * be active
- */
- nd->act_state = 1;
- break;
- }
- } else
+ if (nd->w >= nd->activation_width &&
+ nd->h >= nd->activation_height) {
+ if (nd->id)
/*
- * Defer adjusting the activation state
- * until the end of the frame.
+ * first contact, activate now
*/
+ nd->act_state = 0;
+ else {
+ /*
+ * avoid corrupting this frame
+ * but ensure next frame will
+ * be active
+ */
+ nd->act_state = 1;
break;
- }
-
- /* Discarding this contact */
- if (!nd->confidence)
- break;
-
- /* emit a normal (X, Y) for the first point only */
- if (nd->id == 0) {
+ }
+ } else
/*
- * TipSwitch is superfluous in multitouch
- * mode. The footer events tell us
- * if there is a finger on the screen or
- * not.
+ * Defer adjusting the activation state
+ * until the end of the frame.
*/
- nd->first_contact_touch = nd->confidence;
- input_event(input, EV_ABS, ABS_X, nd->x);
- input_event(input, EV_ABS, ABS_Y, nd->y);
- }
+ break;
+ }
- /* Emit MT events */
- input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x);
- input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y);
+ /* Discarding this contact */
+ if (!nd->confidence)
+ break;
+ /* emit a normal (X, Y) for the first point only */
+ if (nd->id == 0) {
/*
- * Translate from height and width to size
- * and orientation.
+ * TipSwitch is superfluous in multitouch
+ * mode. The footer events tell us
+ * if there is a finger on the screen or
+ * not.
*/
- if (nd->w > nd->h) {
- input_event(input, EV_ABS,
- ABS_MT_ORIENTATION, 1);
- input_event(input, EV_ABS,
- ABS_MT_TOUCH_MAJOR, nd->w);
- input_event(input, EV_ABS,
- ABS_MT_TOUCH_MINOR, nd->h);
- } else {
- input_event(input, EV_ABS,
- ABS_MT_ORIENTATION, 0);
- input_event(input, EV_ABS,
- ABS_MT_TOUCH_MAJOR, nd->h);
- input_event(input, EV_ABS,
- ABS_MT_TOUCH_MINOR, nd->w);
- }
- input_mt_sync(field->hidinput->input);
- break;
+ nd->first_contact_touch = nd->confidence;
+ input_event(input, EV_ABS, ABS_X, nd->x);
+ input_event(input, EV_ABS, ABS_Y, nd->y);
+ }
- case HID_DG_CONTACTCOUNT: /* End of a multitouch group */
- if (!nd->reading_mt) /* Just to be sure */
- break;
+ /* Emit MT events */
+ input_event(input, EV_ABS, ABS_MT_POSITION_X, nd->x);
+ input_event(input, EV_ABS, ABS_MT_POSITION_Y, nd->y);
+
+ /*
+ * Translate from height and width to size
+ * and orientation.
+ */
+ if (nd->w > nd->h) {
+ input_event(input, EV_ABS,
+ ABS_MT_ORIENTATION, 1);
+ input_event(input, EV_ABS,
+ ABS_MT_TOUCH_MAJOR, nd->w);
+ input_event(input, EV_ABS,
+ ABS_MT_TOUCH_MINOR, nd->h);
+ } else {
+ input_event(input, EV_ABS,
+ ABS_MT_ORIENTATION, 0);
+ input_event(input, EV_ABS,
+ ABS_MT_TOUCH_MAJOR, nd->h);
+ input_event(input, EV_ABS,
+ ABS_MT_TOUCH_MINOR, nd->w);
+ }
+ input_mt_sync(field->hidinput->input);
+ break;
- nd->reading_mt = 0;
+ case HID_DG_CONTACTCOUNT: /* End of a multitouch group */
+ if (!nd->reading_mt) /* Just to be sure */
+ break;
+ nd->reading_mt = 0;
+
+
+ /*
+ * Activation state machine logic:
+ *
+ * Fundamental states:
+ * state > 0: Inactive
+ * state <= 0: Active
+ * state < -deactivate_slack:
+ * Pen termination of touch
+ *
+ * Specific values of interest
+ * state == activate_slack
+ * no valid input since the last reset
+ *
+ * state == 0
+ * general operational state
+ *
+ * state == -deactivate_slack
+ * read sufficient empty frames to accept
+ * the end of input and reset
+ */
+
+ if (nd->act_state > 0) { /* Currently inactive */
+ if (value)
+ /*
+ * Consider each live contact as
+ * evidence of intentional activity.
+ */
+ nd->act_state = (nd->act_state > value)
+ ? nd->act_state - value
+ : 0;
+ else
+ /*
+ * Empty frame before we hit the
+ * activity threshold, reset.
+ */
+ nd->act_state = nd->activate_slack;
/*
- * Activation state machine logic:
- *
- * Fundamental states:
- * state > 0: Inactive
- * state <= 0: Active
- * state < -deactivate_slack:
- * Pen termination of touch
- *
- * Specific values of interest
- * state == activate_slack
- * no valid input since the last reset
- *
- * state == 0
- * general operational state
- *
- * state == -deactivate_slack
- * read sufficient empty frames to accept
- * the end of input and reset
+ * Entered this block inactive and no
+ * coordinates sent this frame, so hold off
+ * on button state.
*/
-
- if (nd->act_state > 0) { /* Currently inactive */
- if (value)
- /*
- * Consider each live contact as
- * evidence of intentional activity.
- */
- nd->act_state = (nd->act_state > value)
- ? nd->act_state - value
- : 0;
- else
- /*
- * Empty frame before we hit the
- * activity threshold, reset.
- */
- nd->act_state = nd->activate_slack;
-
+ break;
+ } else { /* Currently active */
+ if (value && nd->act_state >=
+ nd->deactivate_slack)
/*
- * Entered this block inactive and no
- * coordinates sent this frame, so hold off
- * on button state.
+ * Live point: clear accumulated
+ * deactivation count.
*/
- break;
- } else { /* Currently active */
- if (value && nd->act_state >=
- nd->deactivate_slack)
- /*
- * Live point: clear accumulated
- * deactivation count.
- */
- nd->act_state = 0;
- else if (nd->act_state <= nd->deactivate_slack)
- /*
- * We've consumed the deactivation
- * slack, time to deactivate and reset.
- */
- nd->act_state =
- nd->activate_slack;
- else { /* Move towards deactivation */
- nd->act_state--;
- break;
- }
- }
-
- if (nd->first_contact_touch && nd->act_state <= 0) {
+ nd->act_state = 0;
+ else if (nd->act_state <= nd->deactivate_slack)
/*
- * Check to see if we're ready to start
- * emitting touch events.
- *
- * Note: activation slack will decrease over
- * the course of the frame, and it will be
- * inconsistent from the start to the end of
- * the frame. However if the frame starts
- * with slack, first_contact_touch will still
- * be 0 and we will not get to this point.
+ * We've consumed the deactivation
+ * slack, time to deactivate and reset.
*/
- input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
- input_report_key(input, BTN_TOUCH, 1);
- } else {
- input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
- input_report_key(input, BTN_TOUCH, 0);
+ nd->act_state =
+ nd->activate_slack;
+ else { /* Move towards deactivation */
+ nd->act_state--;
+ break;
}
- break;
+ }
- default:
- /* fall-back to the generic hidinput handling */
- return 0;
+ if (nd->first_contact_touch && nd->act_state <= 0) {
+ /*
+ * Check to see if we're ready to start
+ * emitting touch events.
+ *
+ * Note: activation slack will decrease over
+ * the course of the frame, and it will be
+ * inconsistent from the start to the end of
+ * the frame. However if the frame starts
+ * with slack, first_contact_touch will still
+ * be 0 and we will not get to this point.
+ */
+ input_report_key(input, BTN_TOOL_DOUBLETAP, 1);
+ input_report_key(input, BTN_TOUCH, 1);
+ } else {
+ input_report_key(input, BTN_TOOL_DOUBLETAP, 0);
+ input_report_key(input, BTN_TOUCH, 0);
}
+ break;
+
+ default:
+ /* fall-back to the generic hidinput handling */
+ return 0;
}
+not_claimed_input:
+
/* we have handled the hidinput part, now remains hiddev */
if ((hid->claimed & HID_CLAIMED_HIDDEV) && hid->hiddev_hid_event)
hid->hiddev_hid_event(hid, field, usage, value);
@@ -827,11 +867,12 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
struct hid_report *report;
if (id->driver_data)
- hdev->quirks |= HID_QUIRK_MULTI_INPUT;
+ hdev->quirks |= HID_QUIRK_MULTI_INPUT
+ | HID_QUIRK_NO_INIT_REPORTS;
nd = kmalloc(sizeof(struct ntrig_data), GFP_KERNEL);
if (!nd) {
- dev_err(&hdev->dev, "cannot allocate N-Trig data\n");
+ hid_err(hdev, "cannot allocate N-Trig data\n");
return -ENOMEM;
}
@@ -850,13 +891,13 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
@@ -894,8 +935,19 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
/* This is needed for devices with more recent firmware versions */
report = hdev->report_enum[HID_FEATURE_REPORT].report_id_hash[0x0a];
- if (report)
- usbhid_submit_report(hdev, report, USB_DIR_OUT);
+ if (report) {
+ /* Let the device settle to ensure the wakeup message gets
+ * through */
+ usbhid_wait_io(hdev);
+ usbhid_submit_report(hdev, report, USB_DIR_IN);
+
+ /*
+ * Sanity check: if the current mode is invalid reset it to
+ * something reasonable.
+ */
+ if (ntrig_get_mode(hdev) >= 4)
+ ntrig_set_mode(hdev, 3);
+ }
ntrig_report_version(hdev);
diff --git a/drivers/hid/hid-ortek.c b/drivers/hid/hid-ortek.c
index 2e79716dca31..f9b7dd4f607f 100644
--- a/drivers/hid/hid-ortek.c
+++ b/drivers/hid/hid-ortek.c
@@ -1,7 +1,6 @@
/*
- * HID driver for Ortek WKB-2000 (wireless keyboard + mouse trackpad).
- * Fixes LogicalMaximum error in USB report description, see
- * http://bugzilla.kernel.org/show_bug.cgi?id=14787
+ * HID driver for Ortek PKB-1700/WKB-2000 (wireless keyboard + mouse trackpad).
+ * Fixes LogicalMaximum error in HID report description.
*
* Copyright (c) 2010 Johnathon Harris <jmharris@gmail.com>
*/
@@ -23,14 +22,14 @@ static __u8 *ortek_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize >= 56 && rdesc[54] == 0x25 && rdesc[55] == 0x01) {
- dev_info(&hdev->dev, "Fixing up Ortek WKB-2000 "
- "report descriptor.\n");
+ hid_info(hdev, "Fixing up Ortek WKB-2000 report descriptor\n");
rdesc[55] = 0x92;
}
return rdesc;
}
static const struct hid_device_id ortek_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_PKB1700) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ORTEK, USB_DEVICE_ID_ORTEK_WKB2000) },
{ }
};
diff --git a/drivers/hid/hid-petalynx.c b/drivers/hid/hid-petalynx.c
index 308d6ae48a3e..f1ea3ff8a98d 100644
--- a/drivers/hid/hid-petalynx.c
+++ b/drivers/hid/hid-petalynx.c
@@ -29,8 +29,7 @@ static __u8 *pl_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if (*rsize >= 60 && rdesc[39] == 0x2a && rdesc[40] == 0xf5 &&
rdesc[41] == 0x00 && rdesc[59] == 0x26 &&
rdesc[60] == 0xf9 && rdesc[61] == 0x00) {
- dev_info(&hdev->dev, "fixing up Petalynx Maxter Remote report "
- "descriptor\n");
+ hid_info(hdev, "fixing up Petalynx Maxter Remote report descriptor\n");
rdesc[60] = 0xfa;
rdesc[40] = 0xfa;
}
@@ -77,13 +76,13 @@ static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-picolcd.c b/drivers/hid/hid-picolcd.c
index bc2e07740628..de9cf21b3494 100644
--- a/drivers/hid/hid-picolcd.c
+++ b/drivers/hid/hid-picolcd.c
@@ -253,7 +253,7 @@ static struct hid_report *picolcd_report(int id, struct hid_device *hdev, int di
if (report->id == id)
return report;
}
- dev_warn(&hdev->dev, "No report with id 0x%x found\n", id);
+ hid_warn(hdev, "No report with id 0x%x found\n", id);
return NULL;
}
@@ -1329,7 +1329,7 @@ static int picolcd_check_version(struct hid_device *hdev)
verinfo = picolcd_send_and_wait(hdev, REPORT_VERSION, NULL, 0);
if (!verinfo) {
- dev_err(&hdev->dev, "no version response from PicoLCD");
+ hid_err(hdev, "no version response from PicoLCD\n");
return -ENODEV;
}
@@ -1337,14 +1337,14 @@ static int picolcd_check_version(struct hid_device *hdev)
data->version[0] = verinfo->raw_data[1];
data->version[1] = verinfo->raw_data[0];
if (data->status & PICOLCD_BOOTLOADER) {
- dev_info(&hdev->dev, "PicoLCD, bootloader version %d.%d\n",
- verinfo->raw_data[1], verinfo->raw_data[0]);
+ hid_info(hdev, "PicoLCD, bootloader version %d.%d\n",
+ verinfo->raw_data[1], verinfo->raw_data[0]);
} else {
- dev_info(&hdev->dev, "PicoLCD, firmware version %d.%d\n",
- verinfo->raw_data[1], verinfo->raw_data[0]);
+ hid_info(hdev, "PicoLCD, firmware version %d.%d\n",
+ verinfo->raw_data[1], verinfo->raw_data[0]);
}
} else {
- dev_err(&hdev->dev, "confused, got unexpected version response from PicoLCD\n");
+ hid_err(hdev, "confused, got unexpected version response from PicoLCD\n");
ret = -EINVAL;
}
kfree(verinfo);
@@ -1544,7 +1544,7 @@ static ssize_t picolcd_debug_eeprom_read(struct file *f, char __user *u,
/* prepare buffer with info about what we want to read (addr & len) */
raw_data[0] = *off & 0xff;
- raw_data[1] = (*off >> 8) && 0xff;
+ raw_data[1] = (*off >> 8) & 0xff;
raw_data[2] = s < 20 ? s : 20;
if (*off + raw_data[2] > 0xff)
raw_data[2] = 0x100 - *off;
@@ -1583,7 +1583,7 @@ static ssize_t picolcd_debug_eeprom_write(struct file *f, const char __user *u,
memset(raw_data, 0, sizeof(raw_data));
raw_data[0] = *off & 0xff;
- raw_data[1] = (*off >> 8) && 0xff;
+ raw_data[1] = (*off >> 8) & 0xff;
raw_data[2] = s < 20 ? s : 20;
if (*off + raw_data[2] > 0xff)
raw_data[2] = 0x100 - *off;
@@ -1867,6 +1867,7 @@ static void picolcd_debug_out_report(struct picolcd_data *data,
report->id, raw_size);
hid_debug_event(hdev, buff);
if (raw_size + 5 > sizeof(raw_data)) {
+ kfree(buff);
hid_debug_event(hdev, " TOO BIG\n");
return;
} else {
@@ -2328,8 +2329,7 @@ static void picolcd_init_devfs(struct picolcd_data *data,
(flash_w ? S_IWUSR : 0) | (flash_r ? S_IRUSR : 0),
hdev->debug_dir, data, &picolcd_debug_flash_fops);
} else if (flash_r || flash_w)
- dev_warn(&hdev->dev, "Unexpected FLASH access reports, "
- "please submit rdesc for review\n");
+ hid_warn(hdev, "Unexpected FLASH access reports, please submit rdesc for review\n");
}
static void picolcd_exit_devfs(struct picolcd_data *data)
@@ -2457,13 +2457,13 @@ static int picolcd_init_keys(struct picolcd_data *data,
return -ENODEV;
if (report->maxfield != 1 || report->field[0]->report_count != 2 ||
report->field[0]->report_size != 8) {
- dev_err(&hdev->dev, "unsupported KEY_STATE report");
+ hid_err(hdev, "unsupported KEY_STATE report\n");
return -EINVAL;
}
idev = input_allocate_device();
if (idev == NULL) {
- dev_err(&hdev->dev, "failed to allocate input device");
+ hid_err(hdev, "failed to allocate input device\n");
return -ENOMEM;
}
input_set_drvdata(idev, hdev);
@@ -2485,7 +2485,7 @@ static int picolcd_init_keys(struct picolcd_data *data,
input_set_capability(idev, EV_KEY, data->keycode[i]);
error = input_register_device(idev);
if (error) {
- dev_err(&hdev->dev, "error registering the input device");
+ hid_err(hdev, "error registering the input device\n");
input_free_device(idev);
return error;
}
@@ -2522,9 +2522,8 @@ static int picolcd_probe_lcd(struct hid_device *hdev, struct picolcd_data *data)
return error;
if (data->version[0] != 0 && data->version[1] != 3)
- dev_info(&hdev->dev, "Device with untested firmware revision, "
- "please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
- dev_name(&hdev->dev));
+ hid_info(hdev, "Device with untested firmware revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
+ dev_name(&hdev->dev));
/* Setup keypad input device */
error = picolcd_init_keys(data, picolcd_in_report(REPORT_KEY_STATE, hdev));
@@ -2581,9 +2580,8 @@ static int picolcd_probe_bootloader(struct hid_device *hdev, struct picolcd_data
return error;
if (data->version[0] != 1 && data->version[1] != 0)
- dev_info(&hdev->dev, "Device with untested bootloader revision, "
- "please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
- dev_name(&hdev->dev));
+ hid_info(hdev, "Device with untested bootloader revision, please submit /sys/kernel/debug/hid/%s/rdesc for this device.\n",
+ dev_name(&hdev->dev));
picolcd_init_devfs(data, NULL, NULL,
picolcd_out_report(REPORT_BL_READ_MEMORY, hdev),
@@ -2605,7 +2603,7 @@ static int picolcd_probe(struct hid_device *hdev,
*/
data = kzalloc(sizeof(struct picolcd_data), GFP_KERNEL);
if (data == NULL) {
- dev_err(&hdev->dev, "can't allocate space for Minibox PicoLCD device data\n");
+ hid_err(hdev, "can't allocate space for Minibox PicoLCD device data\n");
error = -ENOMEM;
goto err_no_cleanup;
}
@@ -2621,7 +2619,7 @@ static int picolcd_probe(struct hid_device *hdev,
/* Parse the device reports and start it up */
error = hid_parse(hdev);
if (error) {
- dev_err(&hdev->dev, "device report parse failed\n");
+ hid_err(hdev, "device report parse failed\n");
goto err_cleanup_data;
}
@@ -2631,25 +2629,25 @@ static int picolcd_probe(struct hid_device *hdev,
error = hid_hw_start(hdev, 0);
hdev->claimed = 0;
if (error) {
- dev_err(&hdev->dev, "hardware start failed\n");
+ hid_err(hdev, "hardware start failed\n");
goto err_cleanup_data;
}
- error = hdev->ll_driver->open(hdev);
+ error = hid_hw_open(hdev);
if (error) {
- dev_err(&hdev->dev, "failed to open input interrupt pipe for key and IR events\n");
+ hid_err(hdev, "failed to open input interrupt pipe for key and IR events\n");
goto err_cleanup_hid_hw;
}
error = device_create_file(&hdev->dev, &dev_attr_operation_mode_delay);
if (error) {
- dev_err(&hdev->dev, "failed to create sysfs attributes\n");
+ hid_err(hdev, "failed to create sysfs attributes\n");
goto err_cleanup_hid_ll;
}
error = device_create_file(&hdev->dev, &dev_attr_operation_mode);
if (error) {
- dev_err(&hdev->dev, "failed to create sysfs attributes\n");
+ hid_err(hdev, "failed to create sysfs attributes\n");
goto err_cleanup_sysfs1;
}
@@ -2668,7 +2666,7 @@ err_cleanup_sysfs2:
err_cleanup_sysfs1:
device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
err_cleanup_hid_ll:
- hdev->ll_driver->close(hdev);
+ hid_hw_close(hdev);
err_cleanup_hid_hw:
hid_hw_stop(hdev);
err_cleanup_data:
@@ -2699,7 +2697,7 @@ static void picolcd_remove(struct hid_device *hdev)
picolcd_exit_devfs(data);
device_remove_file(&hdev->dev, &dev_attr_operation_mode);
device_remove_file(&hdev->dev, &dev_attr_operation_mode_delay);
- hdev->ll_driver->close(hdev);
+ hid_hw_close(hdev);
hid_hw_stop(hdev);
hid_set_drvdata(hdev, NULL);
@@ -2753,7 +2751,7 @@ static void __exit picolcd_exit(void)
{
hid_unregister_driver(&picolcd_driver);
#ifdef CONFIG_HID_PICOLCD_FB
- flush_scheduled_work();
+ flush_work_sync(&picolcd_fb_cleanup);
WARN_ON(fb_pending);
#endif
}
diff --git a/drivers/hid/hid-pl.c b/drivers/hid/hid-pl.c
index 9f41e2bd8483..06e5300d43d2 100644
--- a/drivers/hid/hid-pl.c
+++ b/drivers/hid/hid-pl.c
@@ -103,7 +103,7 @@ static int plff_init(struct hid_device *hid)
*/
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output reports found\n");
+ hid_err(hid, "no output reports found\n");
return -ENODEV;
}
@@ -112,14 +112,13 @@ static int plff_init(struct hid_device *hid)
report_ptr = report_ptr->next;
if (report_ptr == report_list) {
- dev_err(&hid->dev, "required output report is "
- "missing\n");
+ hid_err(hid, "required output report is missing\n");
return -ENODEV;
}
report = list_entry(report_ptr, struct hid_report, list);
if (report->maxfield < 1) {
- dev_err(&hid->dev, "no fields in the report\n");
+ hid_err(hid, "no fields in the report\n");
return -ENODEV;
}
@@ -137,7 +136,7 @@ static int plff_init(struct hid_device *hid)
weak = &report->field[3]->value[0];
debug("detected 4-field device");
} else {
- dev_err(&hid->dev, "not enough fields or values\n");
+ hid_err(hid, "not enough fields or values\n");
return -ENODEV;
}
@@ -164,8 +163,7 @@ static int plff_init(struct hid_device *hid)
usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
}
- dev_info(&hid->dev, "Force feedback for PantherLord/GreenAsia "
- "devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
+ hid_info(hid, "Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
}
@@ -185,13 +183,13 @@ static int pl_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
diff --git a/drivers/hid/hid-prodikeys.c b/drivers/hid/hid-prodikeys.c
index 48eab84f53b5..ab19f2905d27 100644
--- a/drivers/hid/hid-prodikeys.c
+++ b/drivers/hid/hid-prodikeys.c
@@ -16,6 +16,8 @@
* any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/device.h>
#include <linux/module.h>
#include <linux/usb.h>
@@ -130,7 +132,7 @@ static ssize_t store_channel(struct device *dev,
return -EINVAL;
}
-static DEVICE_ATTR(channel, S_IRUGO | S_IWUGO, show_channel,
+static DEVICE_ATTR(channel, S_IRUGO | S_IWUSR | S_IWGRP , show_channel,
store_channel);
static struct device_attribute *sysfs_device_attr_channel = {
@@ -169,7 +171,7 @@ static ssize_t store_sustain(struct device *dev,
return -EINVAL;
}
-static DEVICE_ATTR(sustain, S_IRUGO | S_IWUGO, show_sustain,
+static DEVICE_ATTR(sustain, S_IRUGO | S_IWUSR | S_IWGRP, show_sustain,
store_sustain);
static struct device_attribute *sysfs_device_attr_sustain = {
@@ -207,7 +209,7 @@ static ssize_t store_octave(struct device *dev,
return -EINVAL;
}
-static DEVICE_ATTR(octave, S_IRUGO | S_IWUGO, show_octave,
+static DEVICE_ATTR(octave, S_IRUGO | S_IWUSR | S_IWGRP, show_octave,
store_octave);
static struct device_attribute *sysfs_device_attr_octave = {
@@ -285,11 +287,11 @@ static int pcmidi_get_output_report(struct pcmidi_snd *pm)
continue;
if (report->maxfield < 1) {
- dev_err(&hdev->dev, "output report is empty\n");
+ hid_err(hdev, "output report is empty\n");
break;
}
if (report->field[0]->report_count != 2) {
- dev_err(&hdev->dev, "field count too low\n");
+ hid_err(hdev, "field count too low\n");
break;
}
pm->pcmidi_report6 = report;
@@ -746,8 +748,8 @@ static __u8 *pk_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if (*rsize == 178 &&
rdesc[111] == 0x06 && rdesc[112] == 0x00 &&
rdesc[113] == 0xff) {
- dev_info(&hdev->dev, "fixing up pc-midi keyboard report "
- "descriptor\n");
+ hid_info(hdev,
+ "fixing up pc-midi keyboard report descriptor\n");
rdesc[144] = 0x18; /* report 4: was 0x10 report count */
}
@@ -805,7 +807,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
pk = kzalloc(sizeof(*pk), GFP_KERNEL);
if (pk == NULL) {
- dev_err(&hdev->dev, "prodikeys: can't alloc descriptor\n");
+ hid_err(hdev, "can't alloc descriptor\n");
return -ENOMEM;
}
@@ -813,8 +815,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
pm = kzalloc(sizeof(*pm), GFP_KERNEL);
if (pm == NULL) {
- dev_err(&hdev->dev,
- "prodikeys: can't alloc descriptor\n");
+ hid_err(hdev, "can't alloc descriptor\n");
ret = -ENOMEM;
goto err_free;
}
@@ -827,7 +828,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "prodikeys: hid parse failed\n");
+ hid_err(hdev, "hid parse failed\n");
goto err_free;
}
@@ -837,7 +838,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "prodikeys: hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
@@ -896,7 +897,7 @@ static int pk_init(void)
ret = hid_register_driver(&pk_driver);
if (ret)
- printk(KERN_ERR "can't register prodikeys driver\n");
+ pr_err("can't register prodikeys driver\n");
return ret;
}
diff --git a/drivers/hid/hid-quanta.c b/drivers/hid/hid-quanta.c
index 54d3db50605b..87a54df4d4ac 100644
--- a/drivers/hid/hid-quanta.c
+++ b/drivers/hid/hid-quanta.c
@@ -195,7 +195,7 @@ static int quanta_probe(struct hid_device *hdev, const struct hid_device_id *id)
td = kmalloc(sizeof(struct quanta_data), GFP_KERNEL);
if (!td) {
- dev_err(&hdev->dev, "cannot allocate Quanta Touch data\n");
+ hid_err(hdev, "cannot allocate Quanta Touch data\n");
return -ENOMEM;
}
td->valid = false;
diff --git a/drivers/hid/hid-roccat-arvo.c b/drivers/hid/hid-roccat-arvo.c
new file mode 100644
index 000000000000..2307471d96dc
--- /dev/null
+++ b/drivers/hid/hid-roccat-arvo.c
@@ -0,0 +1,450 @@
+/*
+ * Roccat Arvo driver for Linux
+ *
+ * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Roccat Arvo is a gamer keyboard with 5 macro keys that can be configured in
+ * 5 profiles.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/hid-roccat.h>
+#include "hid-ids.h"
+#include "hid-roccat-common.h"
+#include "hid-roccat-arvo.h"
+
+static struct class *arvo_class;
+
+static ssize_t arvo_sysfs_show_mode_key(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ struct usb_device *usb_dev =
+ interface_to_usbdev(to_usb_interface(dev->parent->parent));
+ struct arvo_mode_key temp_buf;
+ int retval;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_MODE_KEY,
+ &temp_buf, sizeof(struct arvo_mode_key));
+ mutex_unlock(&arvo->arvo_lock);
+ if (retval)
+ return retval;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp_buf.state);
+}
+
+static ssize_t arvo_sysfs_set_mode_key(struct device *dev,
+ struct device_attribute *attr, char const *buf, size_t size)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ struct usb_device *usb_dev =
+ interface_to_usbdev(to_usb_interface(dev->parent->parent));
+ struct arvo_mode_key temp_buf;
+ unsigned long state;
+ int retval;
+
+ retval = strict_strtoul(buf, 10, &state);
+ if (retval)
+ return retval;
+
+ temp_buf.command = ARVO_COMMAND_MODE_KEY;
+ temp_buf.state = state;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_MODE_KEY,
+ &temp_buf, sizeof(struct arvo_mode_key));
+ mutex_unlock(&arvo->arvo_lock);
+ if (retval)
+ return retval;
+
+ return size;
+}
+
+static ssize_t arvo_sysfs_show_key_mask(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ struct usb_device *usb_dev =
+ interface_to_usbdev(to_usb_interface(dev->parent->parent));
+ struct arvo_key_mask temp_buf;
+ int retval;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_KEY_MASK,
+ &temp_buf, sizeof(struct arvo_key_mask));
+ mutex_unlock(&arvo->arvo_lock);
+ if (retval)
+ return retval;
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", temp_buf.key_mask);
+}
+
+static ssize_t arvo_sysfs_set_key_mask(struct device *dev,
+ struct device_attribute *attr, char const *buf, size_t size)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ struct usb_device *usb_dev =
+ interface_to_usbdev(to_usb_interface(dev->parent->parent));
+ struct arvo_key_mask temp_buf;
+ unsigned long key_mask;
+ int retval;
+
+ retval = strict_strtoul(buf, 10, &key_mask);
+ if (retval)
+ return retval;
+
+ temp_buf.command = ARVO_COMMAND_KEY_MASK;
+ temp_buf.key_mask = key_mask;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_KEY_MASK,
+ &temp_buf, sizeof(struct arvo_key_mask));
+ mutex_unlock(&arvo->arvo_lock);
+ if (retval)
+ return retval;
+
+ return size;
+}
+
+/* retval is 1-5 on success, < 0 on error */
+static int arvo_get_actual_profile(struct usb_device *usb_dev)
+{
+ struct arvo_actual_profile temp_buf;
+ int retval;
+
+ retval = roccat_common_receive(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE,
+ &temp_buf, sizeof(struct arvo_actual_profile));
+
+ if (retval)
+ return retval;
+
+ return temp_buf.actual_profile;
+}
+
+static ssize_t arvo_sysfs_show_actual_profile(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+
+ return snprintf(buf, PAGE_SIZE, "%d\n", arvo->actual_profile);
+}
+
+static ssize_t arvo_sysfs_set_actual_profile(struct device *dev,
+ struct device_attribute *attr, char const *buf, size_t size)
+{
+ struct arvo_device *arvo =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ struct usb_device *usb_dev =
+ interface_to_usbdev(to_usb_interface(dev->parent->parent));
+ struct arvo_actual_profile temp_buf;
+ unsigned long profile;
+ int retval;
+
+ retval = strict_strtoul(buf, 10, &profile);
+ if (retval)
+ return retval;
+
+ temp_buf.command = ARVO_COMMAND_ACTUAL_PROFILE;
+ temp_buf.actual_profile = profile;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_send(usb_dev, ARVO_USB_COMMAND_ACTUAL_PROFILE,
+ &temp_buf, sizeof(struct arvo_actual_profile));
+ if (!retval) {
+ arvo->actual_profile = profile;
+ retval = size;
+ }
+ mutex_unlock(&arvo->arvo_lock);
+ return retval;
+}
+
+static ssize_t arvo_sysfs_write(struct file *fp,
+ struct kobject *kobj, void const *buf,
+ loff_t off, size_t count, size_t real_size, uint command)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval;
+
+ if (off != 0 || count != real_size)
+ return -EINVAL;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_send(usb_dev, command, buf, real_size);
+ mutex_unlock(&arvo->arvo_lock);
+
+ return (retval ? retval : real_size);
+}
+
+static ssize_t arvo_sysfs_read(struct file *fp,
+ struct kobject *kobj, void *buf, loff_t off,
+ size_t count, size_t real_size, uint command)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct arvo_device *arvo = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval;
+
+ if (off >= real_size)
+ return 0;
+
+ if (off != 0 || count != real_size)
+ return -EINVAL;
+
+ mutex_lock(&arvo->arvo_lock);
+ retval = roccat_common_receive(usb_dev, command, buf, real_size);
+ mutex_unlock(&arvo->arvo_lock);
+
+ return (retval ? retval : real_size);
+}
+
+static ssize_t arvo_sysfs_write_button(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return arvo_sysfs_write(fp, kobj, buf, off, count,
+ sizeof(struct arvo_button), ARVO_USB_COMMAND_BUTTON);
+}
+
+static ssize_t arvo_sysfs_read_info(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return arvo_sysfs_read(fp, kobj, buf, off, count,
+ sizeof(struct arvo_info), ARVO_USB_COMMAND_INFO);
+}
+
+
+static struct device_attribute arvo_attributes[] = {
+ __ATTR(mode_key, 0660,
+ arvo_sysfs_show_mode_key, arvo_sysfs_set_mode_key),
+ __ATTR(key_mask, 0660,
+ arvo_sysfs_show_key_mask, arvo_sysfs_set_key_mask),
+ __ATTR(actual_profile, 0660,
+ arvo_sysfs_show_actual_profile,
+ arvo_sysfs_set_actual_profile),
+ __ATTR_NULL
+};
+
+static struct bin_attribute arvo_bin_attributes[] = {
+ {
+ .attr = { .name = "button", .mode = 0220 },
+ .size = sizeof(struct arvo_button),
+ .write = arvo_sysfs_write_button
+ },
+ {
+ .attr = { .name = "info", .mode = 0440 },
+ .size = sizeof(struct arvo_info),
+ .read = arvo_sysfs_read_info
+ },
+ __ATTR_NULL
+};
+
+static int arvo_init_arvo_device_struct(struct usb_device *usb_dev,
+ struct arvo_device *arvo)
+{
+ int retval;
+
+ mutex_init(&arvo->arvo_lock);
+
+ retval = arvo_get_actual_profile(usb_dev);
+ if (retval < 0)
+ return retval;
+ arvo->actual_profile = retval;
+
+ return 0;
+}
+
+static int arvo_init_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct arvo_device *arvo;
+ int retval;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_KEYBOARD) {
+ hid_set_drvdata(hdev, NULL);
+ return 0;
+ }
+
+ arvo = kzalloc(sizeof(*arvo), GFP_KERNEL);
+ if (!arvo) {
+ hid_err(hdev, "can't alloc device descriptor\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, arvo);
+
+ retval = arvo_init_arvo_device_struct(usb_dev, arvo);
+ if (retval) {
+ hid_err(hdev, "couldn't init struct arvo_device\n");
+ goto exit_free;
+ }
+
+ retval = roccat_connect(arvo_class, hdev,
+ sizeof(struct arvo_roccat_report));
+ if (retval < 0) {
+ hid_err(hdev, "couldn't init char dev\n");
+ } else {
+ arvo->chrdev_minor = retval;
+ arvo->roccat_claimed = 1;
+ }
+
+ return 0;
+exit_free:
+ kfree(arvo);
+ return retval;
+}
+
+static void arvo_remove_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct arvo_device *arvo;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_KEYBOARD)
+ return;
+
+ arvo = hid_get_drvdata(hdev);
+ if (arvo->roccat_claimed)
+ roccat_disconnect(arvo->chrdev_minor);
+ kfree(arvo);
+}
+
+static int arvo_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int retval;
+
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+ goto exit;
+ }
+
+ retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (retval) {
+ hid_err(hdev, "hw start failed\n");
+ goto exit;
+ }
+
+ retval = arvo_init_specials(hdev);
+ if (retval) {
+ hid_err(hdev, "couldn't install keyboard\n");
+ goto exit_stop;
+ }
+
+ return 0;
+
+exit_stop:
+ hid_hw_stop(hdev);
+exit:
+ return retval;
+}
+
+static void arvo_remove(struct hid_device *hdev)
+{
+ arvo_remove_specials(hdev);
+ hid_hw_stop(hdev);
+}
+
+static void arvo_report_to_chrdev(struct arvo_device const *arvo,
+ u8 const *data)
+{
+ struct arvo_special_report const *special_report;
+ struct arvo_roccat_report roccat_report;
+
+ special_report = (struct arvo_special_report const *)data;
+
+ roccat_report.profile = arvo->actual_profile;
+ roccat_report.button = special_report->event &
+ ARVO_SPECIAL_REPORT_EVENT_MASK_BUTTON;
+ if ((special_report->event & ARVO_SPECIAL_REPORT_EVENT_MASK_ACTION) ==
+ ARVO_SPECIAL_REPORT_EVENT_ACTION_PRESS)
+ roccat_report.action = ARVO_ROCCAT_REPORT_ACTION_PRESS;
+ else
+ roccat_report.action = ARVO_ROCCAT_REPORT_ACTION_RELEASE;
+
+ roccat_report_event(arvo->chrdev_minor,
+ (uint8_t const *)&roccat_report);
+}
+
+static int arvo_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size)
+{
+ struct arvo_device *arvo = hid_get_drvdata(hdev);
+
+ if (size != 3)
+ return 0;
+
+ if (arvo->roccat_claimed)
+ arvo_report_to_chrdev(arvo, data);
+
+ return 0;
+}
+
+static const struct hid_device_id arvo_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(hid, arvo_devices);
+
+static struct hid_driver arvo_driver = {
+ .name = "arvo",
+ .id_table = arvo_devices,
+ .probe = arvo_probe,
+ .remove = arvo_remove,
+ .raw_event = arvo_raw_event
+};
+
+static int __init arvo_init(void)
+{
+ int retval;
+
+ arvo_class = class_create(THIS_MODULE, "arvo");
+ if (IS_ERR(arvo_class))
+ return PTR_ERR(arvo_class);
+ arvo_class->dev_attrs = arvo_attributes;
+ arvo_class->dev_bin_attrs = arvo_bin_attributes;
+
+ retval = hid_register_driver(&arvo_driver);
+ if (retval)
+ class_destroy(arvo_class);
+ return retval;
+}
+
+static void __exit arvo_exit(void)
+{
+ hid_unregister_driver(&arvo_driver);
+ class_destroy(arvo_class);
+}
+
+module_init(arvo_init);
+module_exit(arvo_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat Arvo driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-arvo.h b/drivers/hid/hid-roccat-arvo.h
new file mode 100644
index 000000000000..d284a781c99e
--- /dev/null
+++ b/drivers/hid/hid-roccat-arvo.h
@@ -0,0 +1,98 @@
+#ifndef __HID_ROCCAT_ARVO_H
+#define __HID_ROCCAT_ARVO_H
+
+/*
+ * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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/types.h>
+
+struct arvo_mode_key { /* 2 bytes */
+ uint8_t command; /* ARVO_COMMAND_MODE_KEY */
+ uint8_t state;
+} __packed;
+
+struct arvo_button {
+ uint8_t unknown[24];
+} __packed;
+
+struct arvo_info {
+ uint8_t unknown[8];
+} __packed;
+
+struct arvo_key_mask { /* 2 bytes */
+ uint8_t command; /* ARVO_COMMAND_KEY_MASK */
+ uint8_t key_mask;
+} __packed;
+
+/* selected profile is persistent */
+struct arvo_actual_profile { /* 2 bytes */
+ uint8_t command; /* ARVO_COMMAND_ACTUAL_PROFILE */
+ uint8_t actual_profile;
+} __packed;
+
+enum arvo_commands {
+ ARVO_COMMAND_MODE_KEY = 0x3,
+ ARVO_COMMAND_BUTTON = 0x4,
+ ARVO_COMMAND_INFO = 0x5,
+ ARVO_COMMAND_KEY_MASK = 0x6,
+ ARVO_COMMAND_ACTUAL_PROFILE = 0x7,
+};
+
+enum arvo_usb_commands {
+ ARVO_USB_COMMAND_MODE_KEY = 0x303,
+ /*
+ * read/write
+ * Read uses both index bytes as profile/key indexes
+ * Write has index 0, profile/key is determined by payload
+ */
+ ARVO_USB_COMMAND_BUTTON = 0x304,
+ ARVO_USB_COMMAND_INFO = 0x305,
+ ARVO_USB_COMMAND_KEY_MASK = 0x306,
+ ARVO_USB_COMMAND_ACTUAL_PROFILE = 0x307,
+};
+
+struct arvo_special_report {
+ uint8_t unknown1; /* always 0x01 */
+ uint8_t event;
+ uint8_t unknown2; /* always 0x70 */
+} __packed;
+
+enum arvo_special_report_events {
+ ARVO_SPECIAL_REPORT_EVENT_ACTION_PRESS = 0x10,
+ ARVO_SPECIAL_REPORT_EVENT_ACTION_RELEASE = 0x0,
+};
+
+enum arvo_special_report_event_masks {
+ ARVO_SPECIAL_REPORT_EVENT_MASK_ACTION = 0xf0,
+ ARVO_SPECIAL_REPORT_EVENT_MASK_BUTTON = 0x0f,
+};
+
+struct arvo_roccat_report {
+ uint8_t profile;
+ uint8_t button;
+ uint8_t action;
+} __packed;
+
+enum arvo_roccat_report_action {
+ ARVO_ROCCAT_REPORT_ACTION_RELEASE = 0,
+ ARVO_ROCCAT_REPORT_ACTION_PRESS = 1,
+};
+
+struct arvo_device {
+ int roccat_claimed;
+ int chrdev_minor;
+
+ struct mutex arvo_lock;
+
+ int actual_profile;
+};
+
+#endif
diff --git a/drivers/hid/hid-roccat-common.c b/drivers/hid/hid-roccat-common.c
new file mode 100644
index 000000000000..13b1eb0c8c65
--- /dev/null
+++ b/drivers/hid/hid-roccat-common.c
@@ -0,0 +1,62 @@
+/*
+ * Roccat common functions for device specific drivers
+ *
+ * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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/slab.h>
+#include "hid-roccat-common.h"
+
+int roccat_common_receive(struct usb_device *usb_dev, uint usb_command,
+ void *data, uint size)
+{
+ char *buf;
+ int len;
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
+ USB_REQ_CLEAR_FEATURE,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
+ usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+
+ memcpy(data, buf, size);
+ kfree(buf);
+ return ((len < 0) ? len : ((len != size) ? -EIO : 0));
+}
+EXPORT_SYMBOL_GPL(roccat_common_receive);
+
+int roccat_common_send(struct usb_device *usb_dev, uint usb_command,
+ void const *data, uint size)
+{
+ char *buf;
+ int len;
+
+ buf = kmalloc(size, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ memcpy(buf, data, size);
+
+ len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
+ USB_REQ_SET_CONFIGURATION,
+ USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
+ usb_command, 0, buf, size, USB_CTRL_SET_TIMEOUT);
+
+ kfree(buf);
+ return ((len < 0) ? len : ((len != size) ? -EIO : 0));
+}
+EXPORT_SYMBOL_GPL(roccat_common_send);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat common driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-common.h b/drivers/hid/hid-roccat-common.h
new file mode 100644
index 000000000000..fe45fae05bb9
--- /dev/null
+++ b/drivers/hid/hid-roccat-common.h
@@ -0,0 +1,23 @@
+#ifndef __HID_ROCCAT_COMMON_H
+#define __HID_ROCCAT_COMMON_H
+
+/*
+ * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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/usb.h>
+#include <linux/types.h>
+
+int roccat_common_receive(struct usb_device *usb_dev, uint usb_command,
+ void *data, uint size);
+int roccat_common_send(struct usb_device *usb_dev, uint usb_command,
+ void const *data, uint size);
+
+#endif
diff --git a/drivers/hid/hid-roccat-kone.c b/drivers/hid/hid-roccat-kone.c
index f77695762cb5..a57838d15267 100644
--- a/drivers/hid/hid-roccat-kone.c
+++ b/drivers/hid/hid-roccat-kone.c
@@ -28,13 +28,18 @@
#include <linux/device.h>
#include <linux/input.h>
#include <linux/hid.h>
-#include <linux/usb.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/hid-roccat.h>
#include "hid-ids.h"
-#include "hid-roccat.h"
+#include "hid-roccat-common.h"
#include "hid-roccat-kone.h"
+static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+
+/* kone_class is used for creating sysfs attributes via roccat char device */
+static struct class *kone_class;
+
static void kone_set_settings_checksum(struct kone_settings *settings)
{
uint16_t checksum = 0;
@@ -53,12 +58,8 @@ static void kone_set_settings_checksum(struct kone_settings *settings)
*/
static int kone_check_write(struct usb_device *usb_dev)
{
- int len;
- unsigned char *data;
-
- data = kmalloc(1, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
+ int retval;
+ uint8_t data;
do {
/*
@@ -67,57 +68,36 @@ static int kone_check_write(struct usb_device *usb_dev)
*/
msleep(80);
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE |
- USB_DIR_IN,
- kone_command_confirm_write, 0, data, 1,
- USB_CTRL_SET_TIMEOUT);
-
- if (len != 1) {
- kfree(data);
- return -EIO;
- }
+ retval = roccat_common_receive(usb_dev,
+ kone_command_confirm_write, &data, 1);
+ if (retval)
+ return retval;
/*
* value of 3 seems to mean something like
* "not finished yet, but it looks good"
* So check again after a moment.
*/
- } while (*data == 3);
+ } while (data == 3);
- if (*data == 1) { /* everything alright */
- kfree(data);
+ if (data == 1) /* everything alright */
return 0;
- } else { /* unknown answer */
- dev_err(&usb_dev->dev, "got retval %d when checking write\n",
- *data);
- kfree(data);
- return -EIO;
- }
+
+ /* unknown answer */
+ hid_err(usb_dev, "got retval %d when checking write\n", data);
+ return -EIO;
}
/*
* Reads settings from mouse and stores it in @buf
- * @buf has to be alloced with GFP_KERNEL
* On success returns 0
* On failure returns errno
*/
static int kone_get_settings(struct usb_device *usb_dev,
struct kone_settings *buf)
{
- int len;
-
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- kone_command_settings, 0, buf,
- sizeof(struct kone_settings), USB_CTRL_SET_TIMEOUT);
-
- if (len != sizeof(struct kone_settings))
- return -EIO;
-
- return 0;
+ return roccat_common_receive(usb_dev, kone_command_settings, buf,
+ sizeof(struct kone_settings));
}
/*
@@ -128,22 +108,12 @@ static int kone_get_settings(struct usb_device *usb_dev,
static int kone_set_settings(struct usb_device *usb_dev,
struct kone_settings const *settings)
{
- int len;
-
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- kone_command_settings, 0, (char *)settings,
- sizeof(struct kone_settings),
- USB_CTRL_SET_TIMEOUT);
-
- if (len != sizeof(struct kone_settings))
- return -EIO;
-
- if (kone_check_write(usb_dev))
- return -EIO;
-
- return 0;
+ int retval;
+ retval = roccat_common_send(usb_dev, kone_command_settings,
+ settings, sizeof(struct kone_settings));
+ if (retval)
+ return retval;
+ return kone_check_write(usb_dev);
}
/*
@@ -189,7 +159,7 @@ static int kone_set_profile(struct usb_device *usb_dev,
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
USB_REQ_SET_CONFIGURATION,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- kone_command_profile, number, (char *)profile,
+ kone_command_profile, number, (void *)profile,
sizeof(struct kone_profile),
USB_CTRL_SET_TIMEOUT);
@@ -209,24 +179,15 @@ static int kone_set_profile(struct usb_device *usb_dev,
*/
static int kone_get_weight(struct usb_device *usb_dev, int *result)
{
- int len;
- uint8_t *data;
+ int retval;
+ uint8_t data;
- data = kmalloc(1, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
+ retval = roccat_common_receive(usb_dev, kone_command_weight, &data, 1);
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- kone_command_weight, 0, data, 1, USB_CTRL_SET_TIMEOUT);
+ if (retval)
+ return retval;
- if (len != 1) {
- kfree(data);
- return -EIO;
- }
- *result = (int)*data;
- kfree(data);
+ *result = (int)data;
return 0;
}
@@ -237,32 +198,23 @@ static int kone_get_weight(struct usb_device *usb_dev, int *result)
*/
static int kone_get_firmware_version(struct usb_device *usb_dev, int *result)
{
- int len;
- unsigned char *data;
-
- data = kmalloc(2, GFP_KERNEL);
- if (!data)
- return -ENOMEM;
+ int retval;
+ uint16_t data;
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- kone_command_firmware_version, 0, data, 2,
- USB_CTRL_SET_TIMEOUT);
+ retval = roccat_common_receive(usb_dev, kone_command_firmware_version,
+ &data, 2);
+ if (retval)
+ return retval;
- if (len != 2) {
- kfree(data);
- return -EIO;
- }
- *result = le16_to_cpu(*data);
- kfree(data);
+ *result = le16_to_cpu(data);
return 0;
}
static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count) {
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct kone_settings))
@@ -286,7 +238,8 @@ static ssize_t kone_sysfs_read_settings(struct file *fp, struct kobject *kobj,
static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
struct bin_attribute *attr, char *buf,
loff_t off, size_t count) {
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0, difference;
@@ -319,10 +272,11 @@ static ssize_t kone_sysfs_write_settings(struct file *fp, struct kobject *kobj,
return sizeof(struct kone_settings);
}
-static ssize_t kone_sysfs_read_profilex(struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count, int number) {
- struct device *dev = container_of(kobj, struct device, kobj);
+static ssize_t kone_sysfs_read_profilex(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count) {
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct kone_profile))
@@ -332,47 +286,18 @@ static ssize_t kone_sysfs_read_profilex(struct kobject *kobj,
count = sizeof(struct kone_profile) - off;
mutex_lock(&kone->kone_lock);
- memcpy(buf, ((char const *)&kone->profiles[number - 1]) + off, count);
+ memcpy(buf, ((char const *)&kone->profiles[*(uint *)(attr->private)]) + off, count);
mutex_unlock(&kone->kone_lock);
return count;
}
-static ssize_t kone_sysfs_read_profile1(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 1);
-}
-
-static ssize_t kone_sysfs_read_profile2(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 2);
-}
-
-static ssize_t kone_sysfs_read_profile3(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 3);
-}
-
-static ssize_t kone_sysfs_read_profile4(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 4);
-}
-
-static ssize_t kone_sysfs_read_profile5(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_read_profilex(kobj, attr, buf, off, count, 5);
-}
-
/* Writes data only if different to stored data */
-static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count, int number) {
- struct device *dev = container_of(kobj, struct device, kobj);
+static ssize_t kone_sysfs_write_profilex(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr,
+ char *buf, loff_t off, size_t count) {
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
struct kone_profile *profile;
@@ -382,13 +307,14 @@ static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
if (off != 0 || count != sizeof(struct kone_profile))
return -EINVAL;
- profile = &kone->profiles[number - 1];
+ profile = &kone->profiles[*(uint *)(attr->private)];
mutex_lock(&kone->kone_lock);
difference = memcmp(buf, profile, sizeof(struct kone_profile));
if (difference) {
retval = kone_set_profile(usb_dev,
- (struct kone_profile const *)buf, number);
+ (struct kone_profile const *)buf,
+ *(uint *)(attr->private) + 1);
if (!retval)
memcpy(profile, buf, sizeof(struct kone_profile));
}
@@ -400,47 +326,19 @@ static ssize_t kone_sysfs_write_profilex(struct kobject *kobj,
return sizeof(struct kone_profile);
}
-static ssize_t kone_sysfs_write_profile1(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 1);
-}
-
-static ssize_t kone_sysfs_write_profile2(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 2);
-}
-
-static ssize_t kone_sysfs_write_profile3(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 3);
-}
-
-static ssize_t kone_sysfs_write_profile4(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 4);
-}
-
-static ssize_t kone_sysfs_write_profile5(struct file *fp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf,
- loff_t off, size_t count) {
- return kone_sysfs_write_profilex(kobj, attr, buf, off, count, 5);
-}
-
static ssize_t kone_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+ struct kone_device *kone =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_profile);
}
static ssize_t kone_sysfs_show_actual_dpi(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+ struct kone_device *kone =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->actual_dpi);
}
@@ -448,11 +346,15 @@ static ssize_t kone_sysfs_show_actual_dpi(struct device *dev,
static ssize_t kone_sysfs_show_weight(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
- struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ struct kone_device *kone;
+ struct usb_device *usb_dev;
int weight = 0;
int retval;
+ dev = dev->parent->parent;
+ kone = hid_get_drvdata(dev_get_drvdata(dev));
+ usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
mutex_lock(&kone->kone_lock);
retval = kone_get_weight(usb_dev, &weight);
mutex_unlock(&kone->kone_lock);
@@ -465,36 +367,24 @@ static ssize_t kone_sysfs_show_weight(struct device *dev,
static ssize_t kone_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+ struct kone_device *kone =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->firmware_version);
}
static ssize_t kone_sysfs_show_tcu(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+ struct kone_device *kone =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.tcu);
}
static int kone_tcu_command(struct usb_device *usb_dev, int number)
{
- int len;
- char *value;
-
- value = kmalloc(1, GFP_KERNEL);
- if (!value)
- return -ENOMEM;
-
- *value = number;
-
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- kone_command_calibrate, 0, value, 1,
- USB_CTRL_SET_TIMEOUT);
-
- kfree(value);
- return ((len != 1) ? -EIO : 0);
+ unsigned char value;
+ value = number;
+ return roccat_common_send(usb_dev, kone_command_calibrate, &value, 1);
}
/*
@@ -504,11 +394,15 @@ static int kone_tcu_command(struct usb_device *usb_dev, int number)
static ssize_t kone_sysfs_set_tcu(struct device *dev,
struct device_attribute *attr, char const *buf, size_t size)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
- struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ struct kone_device *kone;
+ struct usb_device *usb_dev;
int retval;
unsigned long state;
+ dev = dev->parent->parent;
+ kone = hid_get_drvdata(dev_get_drvdata(dev));
+ usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
retval = strict_strtoul(buf, 10, &state);
if (retval)
return retval;
@@ -556,7 +450,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev,
retval = kone_set_settings(usb_dev, &kone->settings);
if (retval) {
- dev_err(&usb_dev->dev, "couldn't set tcu state\n");
+ hid_err(usb_dev, "couldn't set tcu state\n");
/*
* try to reread valid settings into buffer overwriting
* first error code
@@ -570,7 +464,7 @@ static ssize_t kone_sysfs_set_tcu(struct device *dev,
retval = size;
exit_no_settings:
- dev_err(&usb_dev->dev, "couldn't read settings\n");
+ hid_err(usb_dev, "couldn't read settings\n");
exit_unlock:
mutex_unlock(&kone->kone_lock);
return retval;
@@ -579,18 +473,23 @@ exit_unlock:
static ssize_t kone_sysfs_show_startup_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
+ struct kone_device *kone =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", kone->settings.startup_profile);
}
static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
struct device_attribute *attr, char const *buf, size_t size)
{
- struct kone_device *kone = hid_get_drvdata(dev_get_drvdata(dev));
- struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ struct kone_device *kone;
+ struct usb_device *usb_dev;
int retval;
unsigned long new_startup_profile;
+ dev = dev->parent->parent;
+ kone = hid_get_drvdata(dev_get_drvdata(dev));
+ usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
retval = strict_strtoul(buf, 10, &new_startup_profile);
if (retval)
return retval;
@@ -617,160 +516,92 @@ static ssize_t kone_sysfs_set_startup_profile(struct device *dev,
return size;
}
-/*
- * Read actual dpi settings.
- * Returns raw value for further processing. Refer to enum kone_polling_rates to
- * get real value.
- */
-static DEVICE_ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL);
-
-static DEVICE_ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL);
-
-/*
- * The mouse can be equipped with one of four supplied weights from 5 to 20
- * grams which are recognized and its value can be read out.
- * This returns the raw value reported by the mouse for easy evaluation by
- * software. Refer to enum kone_weights to get corresponding real weight.
- */
-static DEVICE_ATTR(weight, 0440, kone_sysfs_show_weight, NULL);
-
-/*
- * Prints firmware version stored in mouse as integer.
- * The raw value reported by the mouse is returned for easy evaluation, to get
- * the real version number the decimal point has to be shifted 2 positions to
- * the left. E.g. a value of 138 means 1.38.
- */
-static DEVICE_ATTR(firmware_version, 0440,
- kone_sysfs_show_firmware_version, NULL);
-
-/*
- * Prints state of Tracking Control Unit as number where 0 = off and 1 = on
- * Writing 0 deactivates tcu and writing 1 calibrates and activates the tcu
- */
-static DEVICE_ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu);
-
-/* Prints and takes the number of the profile the mouse starts with */
-static DEVICE_ATTR(startup_profile, 0660,
- kone_sysfs_show_startup_profile,
- kone_sysfs_set_startup_profile);
-
-static struct attribute *kone_attributes[] = {
- &dev_attr_actual_dpi.attr,
- &dev_attr_actual_profile.attr,
- &dev_attr_weight.attr,
- &dev_attr_firmware_version.attr,
- &dev_attr_tcu.attr,
- &dev_attr_startup_profile.attr,
- NULL
-};
-
-static struct attribute_group kone_attribute_group = {
- .attrs = kone_attributes
-};
-
-static struct bin_attribute kone_settings_attr = {
- .attr = { .name = "settings", .mode = 0660 },
- .size = sizeof(struct kone_settings),
- .read = kone_sysfs_read_settings,
- .write = kone_sysfs_write_settings
-};
+static struct device_attribute kone_attributes[] = {
+ /*
+ * Read actual dpi settings.
+ * Returns raw value for further processing. Refer to enum
+ * kone_polling_rates to get real value.
+ */
+ __ATTR(actual_dpi, 0440, kone_sysfs_show_actual_dpi, NULL),
+ __ATTR(actual_profile, 0440, kone_sysfs_show_actual_profile, NULL),
-static struct bin_attribute kone_profile1_attr = {
- .attr = { .name = "profile1", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profile1,
- .write = kone_sysfs_write_profile1
-};
+ /*
+ * The mouse can be equipped with one of four supplied weights from 5
+ * to 20 grams which are recognized and its value can be read out.
+ * This returns the raw value reported by the mouse for easy evaluation
+ * by software. Refer to enum kone_weights to get corresponding real
+ * weight.
+ */
+ __ATTR(weight, 0440, kone_sysfs_show_weight, NULL),
-static struct bin_attribute kone_profile2_attr = {
- .attr = { .name = "profile2", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profile2,
- .write = kone_sysfs_write_profile2
-};
+ /*
+ * Prints firmware version stored in mouse as integer.
+ * The raw value reported by the mouse is returned for easy evaluation,
+ * to get the real version number the decimal point has to be shifted 2
+ * positions to the left. E.g. a value of 138 means 1.38.
+ */
+ __ATTR(firmware_version, 0440,
+ kone_sysfs_show_firmware_version, NULL),
-static struct bin_attribute kone_profile3_attr = {
- .attr = { .name = "profile3", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profile3,
- .write = kone_sysfs_write_profile3
-};
+ /*
+ * Prints state of Tracking Control Unit as number where 0 = off and
+ * 1 = on. Writing 0 deactivates tcu and writing 1 calibrates and
+ * activates the tcu
+ */
+ __ATTR(tcu, 0660, kone_sysfs_show_tcu, kone_sysfs_set_tcu),
-static struct bin_attribute kone_profile4_attr = {
- .attr = { .name = "profile4", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profile4,
- .write = kone_sysfs_write_profile4
+ /* Prints and takes the number of the profile the mouse starts with */
+ __ATTR(startup_profile, 0660,
+ kone_sysfs_show_startup_profile,
+ kone_sysfs_set_startup_profile),
+ __ATTR_NULL
};
-static struct bin_attribute kone_profile5_attr = {
- .attr = { .name = "profile5", .mode = 0660 },
- .size = sizeof(struct kone_profile),
- .read = kone_sysfs_read_profile5,
- .write = kone_sysfs_write_profile5
+static struct bin_attribute kone_bin_attributes[] = {
+ {
+ .attr = { .name = "settings", .mode = 0660 },
+ .size = sizeof(struct kone_settings),
+ .read = kone_sysfs_read_settings,
+ .write = kone_sysfs_write_settings
+ },
+ {
+ .attr = { .name = "profile1", .mode = 0660 },
+ .size = sizeof(struct kone_profile),
+ .read = kone_sysfs_read_profilex,
+ .write = kone_sysfs_write_profilex,
+ .private = &profile_numbers[0]
+ },
+ {
+ .attr = { .name = "profile2", .mode = 0660 },
+ .size = sizeof(struct kone_profile),
+ .read = kone_sysfs_read_profilex,
+ .write = kone_sysfs_write_profilex,
+ .private = &profile_numbers[1]
+ },
+ {
+ .attr = { .name = "profile3", .mode = 0660 },
+ .size = sizeof(struct kone_profile),
+ .read = kone_sysfs_read_profilex,
+ .write = kone_sysfs_write_profilex,
+ .private = &profile_numbers[2]
+ },
+ {
+ .attr = { .name = "profile4", .mode = 0660 },
+ .size = sizeof(struct kone_profile),
+ .read = kone_sysfs_read_profilex,
+ .write = kone_sysfs_write_profilex,
+ .private = &profile_numbers[3]
+ },
+ {
+ .attr = { .name = "profile5", .mode = 0660 },
+ .size = sizeof(struct kone_profile),
+ .read = kone_sysfs_read_profilex,
+ .write = kone_sysfs_write_profilex,
+ .private = &profile_numbers[4]
+ },
+ __ATTR_NULL
};
-static int kone_create_sysfs_attributes(struct usb_interface *intf)
-{
- int retval;
-
- retval = sysfs_create_group(&intf->dev.kobj, &kone_attribute_group);
- if (retval)
- goto exit_1;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_settings_attr);
- if (retval)
- goto exit_2;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile1_attr);
- if (retval)
- goto exit_3;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile2_attr);
- if (retval)
- goto exit_4;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile3_attr);
- if (retval)
- goto exit_5;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile4_attr);
- if (retval)
- goto exit_6;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj, &kone_profile5_attr);
- if (retval)
- goto exit_7;
-
- return 0;
-
-exit_7:
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr);
-exit_6:
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr);
-exit_5:
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr);
-exit_4:
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr);
-exit_3:
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr);
-exit_2:
- sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group);
-exit_1:
- return retval;
-}
-
-static void kone_remove_sysfs_attributes(struct usb_interface *intf)
-{
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile5_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile4_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile3_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile2_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_profile1_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &kone_settings_attr);
- sysfs_remove_group(&intf->dev.kobj, &kone_attribute_group);
-}
-
static int kone_init_kone_device_struct(struct usb_device *usb_dev,
struct kone_device *kone)
{
@@ -818,32 +649,26 @@ static int kone_init_specials(struct hid_device *hdev)
kone = kzalloc(sizeof(*kone), GFP_KERNEL);
if (!kone) {
- dev_err(&hdev->dev, "can't alloc device descriptor\n");
+ hid_err(hdev, "can't alloc device descriptor\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, kone);
retval = kone_init_kone_device_struct(usb_dev, kone);
if (retval) {
- dev_err(&hdev->dev,
- "couldn't init struct kone_device\n");
+ hid_err(hdev, "couldn't init struct kone_device\n");
goto exit_free;
}
- retval = roccat_connect(hdev);
+ retval = roccat_connect(kone_class, hdev,
+ sizeof(struct kone_roccat_report));
if (retval < 0) {
- dev_err(&hdev->dev, "couldn't init char dev\n");
+ hid_err(hdev, "couldn't init char dev\n");
/* be tolerant about not getting chrdev */
} else {
kone->roccat_claimed = 1;
kone->chrdev_minor = retval;
}
-
- retval = kone_create_sysfs_attributes(intf);
- if (retval) {
- dev_err(&hdev->dev, "cannot create sysfs files\n");
- goto exit_free;
- }
} else {
hid_set_drvdata(hdev, NULL);
}
@@ -854,7 +679,6 @@ exit_free:
return retval;
}
-
static void kone_remove_specials(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
@@ -862,7 +686,6 @@ static void kone_remove_specials(struct hid_device *hdev)
if (intf->cur_altsetting->desc.bInterfaceProtocol
== USB_INTERFACE_PROTOCOL_MOUSE) {
- kone_remove_sysfs_attributes(intf);
kone = hid_get_drvdata(hdev);
if (kone->roccat_claimed)
roccat_disconnect(kone->chrdev_minor);
@@ -876,19 +699,19 @@ static int kone_probe(struct hid_device *hdev, const struct hid_device_id *id)
retval = hid_parse(hdev);
if (retval) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto exit;
}
retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (retval) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto exit;
}
retval = kone_init_specials(hdev);
if (retval) {
- dev_err(&hdev->dev, "couldn't install mouse\n");
+ hid_err(hdev, "couldn't install mouse\n");
goto exit_stop;
}
@@ -938,8 +761,7 @@ static void kone_report_to_chrdev(struct kone_device const *kone,
roccat_report.value = event->value;
roccat_report.key = 0;
roccat_report_event(kone->chrdev_minor,
- (uint8_t *)&roccat_report,
- sizeof(struct kone_roccat_report));
+ (uint8_t *)&roccat_report);
break;
case kone_mouse_event_call_overlong_macro:
if (event->value == kone_keystroke_action_press) {
@@ -947,8 +769,7 @@ static void kone_report_to_chrdev(struct kone_device const *kone,
roccat_report.value = kone->actual_profile;
roccat_report.key = event->macro_key;
roccat_report_event(kone->chrdev_minor,
- (uint8_t *)&roccat_report,
- sizeof(struct kone_roccat_report));
+ (uint8_t *)&roccat_report);
}
break;
}
@@ -1006,12 +827,25 @@ static struct hid_driver kone_driver = {
static int __init kone_init(void)
{
- return hid_register_driver(&kone_driver);
+ int retval;
+
+ /* class name has to be same as driver name */
+ kone_class = class_create(THIS_MODULE, "kone");
+ if (IS_ERR(kone_class))
+ return PTR_ERR(kone_class);
+ kone_class->dev_attrs = kone_attributes;
+ kone_class->dev_bin_attrs = kone_bin_attributes;
+
+ retval = hid_register_driver(&kone_driver);
+ if (retval)
+ class_destroy(kone_class);
+ return retval;
}
static void __exit kone_exit(void)
{
hid_unregister_driver(&kone_driver);
+ class_destroy(kone_class);
}
module_init(kone_init);
diff --git a/drivers/hid/hid-roccat-kone.h b/drivers/hid/hid-roccat-kone.h
index 130d6566ea82..64abb5b8a59a 100644
--- a/drivers/hid/hid-roccat-kone.h
+++ b/drivers/hid/hid-roccat-kone.h
@@ -14,14 +14,11 @@
#include <linux/types.h>
-#pragma pack(push)
-#pragma pack(1)
-
struct kone_keystroke {
uint8_t key;
uint8_t action;
uint16_t period; /* in milliseconds */
-};
+} __attribute__ ((__packed__));
enum kone_keystroke_buttons {
kone_keystroke_button_1 = 0xf0, /* left mouse button */
@@ -44,7 +41,7 @@ struct kone_button_info {
uint8_t macro_name[16]; /* can be max 15 chars long */
uint8_t count;
struct kone_keystroke keystrokes[20];
-};
+} __attribute__ ((__packed__));
enum kone_button_info_types {
/* valid button types until firmware 1.32 */
@@ -95,7 +92,7 @@ struct kone_light_info {
uint8_t red; /* range 0x00-0xff */
uint8_t green; /* range 0x00-0xff */
uint8_t blue; /* range 0x00-0xff */
-};
+} __attribute__ ((__packed__));
struct kone_profile {
uint16_t size; /* always 975 */
@@ -130,7 +127,7 @@ struct kone_profile {
struct kone_button_info button_infos[8];
uint16_t checksum; /* \brief holds checksum of struct */
-};
+} __attribute__ ((__packed__));
enum kone_polling_rates {
kone_polling_rate_125 = 1,
@@ -147,7 +144,7 @@ struct kone_settings {
uint8_t calibration_data[4];
uint8_t unknown3[2];
uint16_t checksum;
-};
+} __attribute__ ((__packed__));
/*
* 12 byte mouse event read by interrupt_read
@@ -163,7 +160,7 @@ struct kone_mouse_event {
uint8_t event;
uint8_t value; /* press = 0, release = 1 */
uint8_t macro_key; /* 0 to 8 */
-};
+} __attribute__ ((__packed__));
enum kone_mouse_events {
/* osd events are thought to be display on screen */
@@ -191,9 +188,7 @@ struct kone_roccat_report {
uint8_t event;
uint8_t value; /* holds dpi or profile value */
uint8_t key; /* macro key on overlong macro execution */
-};
-
-#pragma pack(pop)
+} __attribute__ ((__packed__));
struct kone_device {
/*
diff --git a/drivers/hid/hid-roccat-koneplus.c b/drivers/hid/hid-roccat-koneplus.c
new file mode 100644
index 000000000000..33eec74e0615
--- /dev/null
+++ b/drivers/hid/hid-roccat-koneplus.c
@@ -0,0 +1,786 @@
+/*
+ * Roccat Kone[+] driver for Linux
+ *
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Roccat Kone[+] is an updated/improved version of the Kone with more memory
+ * and functionality and without the non-standard behaviours the Kone had.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/hid-roccat.h>
+#include "hid-ids.h"
+#include "hid-roccat-common.h"
+#include "hid-roccat-koneplus.h"
+
+static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+
+static struct class *koneplus_class;
+
+static void koneplus_profile_activated(struct koneplus_device *koneplus,
+ uint new_profile)
+{
+ koneplus->actual_profile = new_profile;
+}
+
+static int koneplus_send_control(struct usb_device *usb_dev, uint value,
+ enum koneplus_control_requests request)
+{
+ struct koneplus_control control;
+
+ if ((request == KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
+ request == KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
+ value > 4)
+ return -EINVAL;
+
+ control.command = KONEPLUS_COMMAND_CONTROL;
+ control.value = value;
+ control.request = request;
+
+ return roccat_common_send(usb_dev, KONEPLUS_USB_COMMAND_CONTROL,
+ &control, sizeof(struct koneplus_control));
+}
+
+static int koneplus_receive_control_status(struct usb_device *usb_dev)
+{
+ int retval;
+ struct koneplus_control control;
+
+ do {
+ retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_CONTROL,
+ &control, sizeof(struct koneplus_control));
+
+ /* check if we get a completely wrong answer */
+ if (retval)
+ return retval;
+
+ if (control.value == KONEPLUS_CONTROL_REQUEST_STATUS_OK)
+ return 0;
+
+ /* indicates that hardware needs some more time to complete action */
+ if (control.value == KONEPLUS_CONTROL_REQUEST_STATUS_WAIT) {
+ msleep(500); /* windows driver uses 1000 */
+ continue;
+ }
+
+ /* seems to be critical - replug necessary */
+ if (control.value == KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD)
+ return -EINVAL;
+
+ hid_err(usb_dev, "koneplus_receive_control_status: "
+ "unknown response value 0x%x\n", control.value);
+ return -EINVAL;
+ } while (1);
+}
+
+static int koneplus_send(struct usb_device *usb_dev, uint command,
+ void const *buf, uint size)
+{
+ int retval;
+
+ retval = roccat_common_send(usb_dev, command, buf, size);
+ if (retval)
+ return retval;
+
+ return koneplus_receive_control_status(usb_dev);
+}
+
+static int koneplus_select_profile(struct usb_device *usb_dev, uint number,
+ enum koneplus_control_requests request)
+{
+ int retval;
+
+ retval = koneplus_send_control(usb_dev, number, request);
+ if (retval)
+ return retval;
+
+ /* allow time to settle things - windows driver uses 500 */
+ msleep(100);
+
+ retval = koneplus_receive_control_status(usb_dev);
+ if (retval)
+ return retval;
+
+ return 0;
+}
+
+static int koneplus_get_info(struct usb_device *usb_dev,
+ struct koneplus_info *buf)
+{
+ return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_INFO,
+ buf, sizeof(struct koneplus_info));
+}
+
+static int koneplus_get_profile_settings(struct usb_device *usb_dev,
+ struct koneplus_profile_settings *buf, uint number)
+{
+ int retval;
+
+ retval = koneplus_select_profile(usb_dev, number,
+ KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
+ if (retval)
+ return retval;
+
+ return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
+ buf, sizeof(struct koneplus_profile_settings));
+}
+
+static int koneplus_set_profile_settings(struct usb_device *usb_dev,
+ struct koneplus_profile_settings const *settings)
+{
+ return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_SETTINGS,
+ settings, sizeof(struct koneplus_profile_settings));
+}
+
+static int koneplus_get_profile_buttons(struct usb_device *usb_dev,
+ struct koneplus_profile_buttons *buf, int number)
+{
+ int retval;
+
+ retval = koneplus_select_profile(usb_dev, number,
+ KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
+ if (retval)
+ return retval;
+
+ return roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
+ buf, sizeof(struct koneplus_profile_buttons));
+}
+
+static int koneplus_set_profile_buttons(struct usb_device *usb_dev,
+ struct koneplus_profile_buttons const *buttons)
+{
+ return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_PROFILE_BUTTONS,
+ buttons, sizeof(struct koneplus_profile_buttons));
+}
+
+/* retval is 0-4 on success, < 0 on error */
+static int koneplus_get_startup_profile(struct usb_device *usb_dev)
+{
+ struct koneplus_startup_profile buf;
+ int retval;
+
+ retval = roccat_common_receive(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
+ &buf, sizeof(struct koneplus_startup_profile));
+
+ return retval ? retval : buf.startup_profile;
+}
+
+static int koneplus_set_startup_profile(struct usb_device *usb_dev,
+ int startup_profile)
+{
+ struct koneplus_startup_profile buf;
+
+ buf.command = KONEPLUS_COMMAND_STARTUP_PROFILE;
+ buf.size = sizeof(struct koneplus_startup_profile);
+ buf.startup_profile = startup_profile;
+
+ return koneplus_send(usb_dev, KONEPLUS_USB_COMMAND_STARTUP_PROFILE,
+ &buf, sizeof(struct koneplus_profile_buttons));
+}
+
+static ssize_t koneplus_sysfs_read(struct file *fp, struct kobject *kobj,
+ char *buf, loff_t off, size_t count,
+ size_t real_size, uint command)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval;
+
+ if (off >= real_size)
+ return 0;
+
+ if (off != 0 || count != real_size)
+ return -EINVAL;
+
+ mutex_lock(&koneplus->koneplus_lock);
+ retval = roccat_common_receive(usb_dev, command, buf, real_size);
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ if (retval)
+ return retval;
+
+ return real_size;
+}
+
+static ssize_t koneplus_sysfs_write(struct file *fp, struct kobject *kobj,
+ void const *buf, loff_t off, size_t count,
+ size_t real_size, uint command)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval;
+
+ if (off != 0 || count != real_size)
+ return -EINVAL;
+
+ mutex_lock(&koneplus->koneplus_lock);
+ retval = koneplus_send(usb_dev, command, buf, real_size);
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ if (retval)
+ return retval;
+
+ return real_size;
+}
+
+static ssize_t koneplus_sysfs_write_macro(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return koneplus_sysfs_write(fp, kobj, buf, off, count,
+ sizeof(struct koneplus_macro), KONEPLUS_USB_COMMAND_MACRO);
+}
+
+static ssize_t koneplus_sysfs_read_sensor(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return koneplus_sysfs_read(fp, kobj, buf, off, count,
+ sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR);
+}
+
+static ssize_t koneplus_sysfs_write_sensor(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return koneplus_sysfs_write(fp, kobj, buf, off, count,
+ sizeof(struct koneplus_sensor), KONEPLUS_USB_COMMAND_SENSOR);
+}
+
+static ssize_t koneplus_sysfs_write_tcu(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return koneplus_sysfs_write(fp, kobj, buf, off, count,
+ sizeof(struct koneplus_tcu), KONEPLUS_USB_COMMAND_TCU);
+}
+
+static ssize_t koneplus_sysfs_read_tcu_image(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ return koneplus_sysfs_read(fp, kobj, buf, off, count,
+ sizeof(struct koneplus_tcu_image), KONEPLUS_USB_COMMAND_TCU);
+}
+
+static ssize_t koneplus_sysfs_read_profilex_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+
+ if (off >= sizeof(struct koneplus_profile_settings))
+ return 0;
+
+ if (off + count > sizeof(struct koneplus_profile_settings))
+ count = sizeof(struct koneplus_profile_settings) - off;
+
+ mutex_lock(&koneplus->koneplus_lock);
+ memcpy(buf, ((char const *)&koneplus->profile_settings[*(uint *)(attr->private)]) + off,
+ count);
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ return count;
+}
+
+static ssize_t koneplus_sysfs_write_profile_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval = 0;
+ int difference;
+ int profile_number;
+ struct koneplus_profile_settings *profile_settings;
+
+ if (off != 0 || count != sizeof(struct koneplus_profile_settings))
+ return -EINVAL;
+
+ profile_number = ((struct koneplus_profile_settings const *)buf)->number;
+ profile_settings = &koneplus->profile_settings[profile_number];
+
+ mutex_lock(&koneplus->koneplus_lock);
+ difference = memcmp(buf, profile_settings,
+ sizeof(struct koneplus_profile_settings));
+ if (difference) {
+ retval = koneplus_set_profile_settings(usb_dev,
+ (struct koneplus_profile_settings const *)buf);
+ if (!retval)
+ memcpy(profile_settings, buf,
+ sizeof(struct koneplus_profile_settings));
+ }
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ if (retval)
+ return retval;
+
+ return sizeof(struct koneplus_profile_settings);
+}
+
+static ssize_t koneplus_sysfs_read_profilex_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+
+ if (off >= sizeof(struct koneplus_profile_buttons))
+ return 0;
+
+ if (off + count > sizeof(struct koneplus_profile_buttons))
+ count = sizeof(struct koneplus_profile_buttons) - off;
+
+ mutex_lock(&koneplus->koneplus_lock);
+ memcpy(buf, ((char const *)&koneplus->profile_buttons[*(uint *)(attr->private)]) + off,
+ count);
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ return count;
+}
+
+static ssize_t koneplus_sysfs_write_profile_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct koneplus_device *koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval = 0;
+ int difference;
+ uint profile_number;
+ struct koneplus_profile_buttons *profile_buttons;
+
+ if (off != 0 || count != sizeof(struct koneplus_profile_buttons))
+ return -EINVAL;
+
+ profile_number = ((struct koneplus_profile_buttons const *)buf)->number;
+ profile_buttons = &koneplus->profile_buttons[profile_number];
+
+ mutex_lock(&koneplus->koneplus_lock);
+ difference = memcmp(buf, profile_buttons,
+ sizeof(struct koneplus_profile_buttons));
+ if (difference) {
+ retval = koneplus_set_profile_buttons(usb_dev,
+ (struct koneplus_profile_buttons const *)buf);
+ if (!retval)
+ memcpy(profile_buttons, buf,
+ sizeof(struct koneplus_profile_buttons));
+ }
+ mutex_unlock(&koneplus->koneplus_lock);
+
+ if (retval)
+ return retval;
+
+ return sizeof(struct koneplus_profile_buttons);
+}
+
+static ssize_t koneplus_sysfs_show_startup_profile(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct koneplus_device *koneplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->startup_profile);
+}
+
+static ssize_t koneplus_sysfs_set_startup_profile(struct device *dev,
+ struct device_attribute *attr, char const *buf, size_t size)
+{
+ struct koneplus_device *koneplus;
+ struct usb_device *usb_dev;
+ unsigned long profile;
+ int retval;
+
+ dev = dev->parent->parent;
+ koneplus = hid_get_drvdata(dev_get_drvdata(dev));
+ usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
+ retval = strict_strtoul(buf, 10, &profile);
+ if (retval)
+ return retval;
+
+ mutex_lock(&koneplus->koneplus_lock);
+ retval = koneplus_set_startup_profile(usb_dev, profile);
+ mutex_unlock(&koneplus->koneplus_lock);
+ if (retval)
+ return retval;
+
+ return size;
+}
+
+static ssize_t koneplus_sysfs_show_actual_profile(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct koneplus_device *koneplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->actual_profile);
+}
+
+static ssize_t koneplus_sysfs_show_firmware_version(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct koneplus_device *koneplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", koneplus->info.firmware_version);
+}
+
+static struct device_attribute koneplus_attributes[] = {
+ __ATTR(startup_profile, 0660,
+ koneplus_sysfs_show_startup_profile,
+ koneplus_sysfs_set_startup_profile),
+ __ATTR(actual_profile, 0440,
+ koneplus_sysfs_show_actual_profile, NULL),
+ __ATTR(firmware_version, 0440,
+ koneplus_sysfs_show_firmware_version, NULL),
+ __ATTR_NULL
+};
+
+static struct bin_attribute koneplus_bin_attributes[] = {
+ {
+ .attr = { .name = "sensor", .mode = 0660 },
+ .size = sizeof(struct koneplus_sensor),
+ .read = koneplus_sysfs_read_sensor,
+ .write = koneplus_sysfs_write_sensor
+ },
+ {
+ .attr = { .name = "tcu", .mode = 0220 },
+ .size = sizeof(struct koneplus_tcu),
+ .write = koneplus_sysfs_write_tcu
+ },
+ {
+ .attr = { .name = "tcu_image", .mode = 0440 },
+ .size = sizeof(struct koneplus_tcu_image),
+ .read = koneplus_sysfs_read_tcu_image
+ },
+ {
+ .attr = { .name = "profile_settings", .mode = 0220 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .write = koneplus_sysfs_write_profile_settings
+ },
+ {
+ .attr = { .name = "profile1_settings", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .read = koneplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[0]
+ },
+ {
+ .attr = { .name = "profile2_settings", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .read = koneplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[1]
+ },
+ {
+ .attr = { .name = "profile3_settings", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .read = koneplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[2]
+ },
+ {
+ .attr = { .name = "profile4_settings", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .read = koneplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[3]
+ },
+ {
+ .attr = { .name = "profile5_settings", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_settings),
+ .read = koneplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[4]
+ },
+ {
+ .attr = { .name = "profile_buttons", .mode = 0220 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .write = koneplus_sysfs_write_profile_buttons
+ },
+ {
+ .attr = { .name = "profile1_buttons", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .read = koneplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[0]
+ },
+ {
+ .attr = { .name = "profile2_buttons", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .read = koneplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[1]
+ },
+ {
+ .attr = { .name = "profile3_buttons", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .read = koneplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[2]
+ },
+ {
+ .attr = { .name = "profile4_buttons", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .read = koneplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[3]
+ },
+ {
+ .attr = { .name = "profile5_buttons", .mode = 0440 },
+ .size = sizeof(struct koneplus_profile_buttons),
+ .read = koneplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[4]
+ },
+ {
+ .attr = { .name = "macro", .mode = 0220 },
+ .size = sizeof(struct koneplus_macro),
+ .write = koneplus_sysfs_write_macro
+ },
+ __ATTR_NULL
+};
+
+static int koneplus_init_koneplus_device_struct(struct usb_device *usb_dev,
+ struct koneplus_device *koneplus)
+{
+ int retval, i;
+ static uint wait = 100; /* device will freeze with just 60 */
+
+ mutex_init(&koneplus->koneplus_lock);
+
+ koneplus->startup_profile = koneplus_get_startup_profile(usb_dev);
+ if (koneplus->startup_profile < 0)
+ return koneplus->startup_profile;
+
+ msleep(wait);
+ retval = koneplus_get_info(usb_dev, &koneplus->info);
+ if (retval)
+ return retval;
+
+ for (i = 0; i < 5; ++i) {
+ msleep(wait);
+ retval = koneplus_get_profile_settings(usb_dev,
+ &koneplus->profile_settings[i], i);
+ if (retval)
+ return retval;
+
+ msleep(wait);
+ retval = koneplus_get_profile_buttons(usb_dev,
+ &koneplus->profile_buttons[i], i);
+ if (retval)
+ return retval;
+ }
+
+ koneplus_profile_activated(koneplus, koneplus->startup_profile);
+
+ return 0;
+}
+
+static int koneplus_init_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct koneplus_device *koneplus;
+ int retval;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_MOUSE) {
+
+ koneplus = kzalloc(sizeof(*koneplus), GFP_KERNEL);
+ if (!koneplus) {
+ hid_err(hdev, "can't alloc device descriptor\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, koneplus);
+
+ retval = koneplus_init_koneplus_device_struct(usb_dev, koneplus);
+ if (retval) {
+ hid_err(hdev, "couldn't init struct koneplus_device\n");
+ goto exit_free;
+ }
+
+ retval = roccat_connect(koneplus_class, hdev,
+ sizeof(struct koneplus_roccat_report));
+ if (retval < 0) {
+ hid_err(hdev, "couldn't init char dev\n");
+ } else {
+ koneplus->chrdev_minor = retval;
+ koneplus->roccat_claimed = 1;
+ }
+ } else {
+ hid_set_drvdata(hdev, NULL);
+ }
+
+ return 0;
+exit_free:
+ kfree(koneplus);
+ return retval;
+}
+
+static void koneplus_remove_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct koneplus_device *koneplus;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_MOUSE) {
+ koneplus = hid_get_drvdata(hdev);
+ if (koneplus->roccat_claimed)
+ roccat_disconnect(koneplus->chrdev_minor);
+ kfree(koneplus);
+ }
+}
+
+static int koneplus_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int retval;
+
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+ goto exit;
+ }
+
+ retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (retval) {
+ hid_err(hdev, "hw start failed\n");
+ goto exit;
+ }
+
+ retval = koneplus_init_specials(hdev);
+ if (retval) {
+ hid_err(hdev, "couldn't install mouse\n");
+ goto exit_stop;
+ }
+
+ return 0;
+
+exit_stop:
+ hid_hw_stop(hdev);
+exit:
+ return retval;
+}
+
+static void koneplus_remove(struct hid_device *hdev)
+{
+ koneplus_remove_specials(hdev);
+ hid_hw_stop(hdev);
+}
+
+static void koneplus_keep_values_up_to_date(struct koneplus_device *koneplus,
+ u8 const *data)
+{
+ struct koneplus_mouse_report_button const *button_report;
+
+ switch (data[0]) {
+ case KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON:
+ button_report = (struct koneplus_mouse_report_button const *)data;
+ switch (button_report->type) {
+ case KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE:
+ koneplus_profile_activated(koneplus, button_report->data1 - 1);
+ break;
+ }
+ break;
+ }
+}
+
+static void koneplus_report_to_chrdev(struct koneplus_device const *koneplus,
+ u8 const *data)
+{
+ struct koneplus_roccat_report roccat_report;
+ struct koneplus_mouse_report_button const *button_report;
+
+ if (data[0] != KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON)
+ return;
+
+ button_report = (struct koneplus_mouse_report_button const *)data;
+
+ if ((button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
+ button_report->type == KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER) &&
+ button_report->data2 != KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS)
+ return;
+
+ roccat_report.type = button_report->type;
+ roccat_report.data1 = button_report->data1;
+ roccat_report.data2 = button_report->data2;
+ roccat_report.profile = koneplus->actual_profile + 1;
+ roccat_report_event(koneplus->chrdev_minor,
+ (uint8_t const *)&roccat_report);
+}
+
+static int koneplus_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct koneplus_device *koneplus = hid_get_drvdata(hdev);
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ != USB_INTERFACE_PROTOCOL_MOUSE)
+ return 0;
+
+ koneplus_keep_values_up_to_date(koneplus, data);
+
+ if (koneplus->roccat_claimed)
+ koneplus_report_to_chrdev(koneplus, data);
+
+ return 0;
+}
+
+static const struct hid_device_id koneplus_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(hid, koneplus_devices);
+
+static struct hid_driver koneplus_driver = {
+ .name = "koneplus",
+ .id_table = koneplus_devices,
+ .probe = koneplus_probe,
+ .remove = koneplus_remove,
+ .raw_event = koneplus_raw_event
+};
+
+static int __init koneplus_init(void)
+{
+ int retval;
+
+ /* class name has to be same as driver name */
+ koneplus_class = class_create(THIS_MODULE, "koneplus");
+ if (IS_ERR(koneplus_class))
+ return PTR_ERR(koneplus_class);
+ koneplus_class->dev_attrs = koneplus_attributes;
+ koneplus_class->dev_bin_attrs = koneplus_bin_attributes;
+
+ retval = hid_register_driver(&koneplus_driver);
+ if (retval)
+ class_destroy(koneplus_class);
+ return retval;
+}
+
+static void __exit koneplus_exit(void)
+{
+ hid_unregister_driver(&koneplus_driver);
+ class_destroy(koneplus_class);
+}
+
+module_init(koneplus_init);
+module_exit(koneplus_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat Kone[+] driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-koneplus.h b/drivers/hid/hid-roccat-koneplus.h
new file mode 100644
index 000000000000..57a5c1ab7b05
--- /dev/null
+++ b/drivers/hid/hid-roccat-koneplus.h
@@ -0,0 +1,224 @@
+#ifndef __HID_ROCCAT_KONEPLUS_H
+#define __HID_ROCCAT_KONEPLUS_H
+
+/*
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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/types.h>
+
+/*
+ * case 1: writes request 80 and reads value 1
+ *
+ */
+struct koneplus_control {
+ uint8_t command; /* KONEPLUS_COMMAND_CONTROL */
+ /*
+ * value is profile number in range 0-4 for requesting settings and buttons
+ * 1 if status ok for requesting status
+ */
+ uint8_t value;
+ uint8_t request;
+} __attribute__ ((__packed__));
+
+enum koneplus_control_requests {
+ KONEPLUS_CONTROL_REQUEST_STATUS = 0x00,
+ KONEPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x80,
+ KONEPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x90,
+};
+
+enum koneplus_control_values {
+ KONEPLUS_CONTROL_REQUEST_STATUS_OVERLOAD = 0,
+ KONEPLUS_CONTROL_REQUEST_STATUS_OK = 1,
+ KONEPLUS_CONTROL_REQUEST_STATUS_WAIT = 3,
+};
+
+struct koneplus_startup_profile {
+ uint8_t command; /* KONEPLUS_COMMAND_STARTUP_PROFILE */
+ uint8_t size; /* always 3 */
+ uint8_t startup_profile; /* Range 0-4! */
+} __attribute__ ((__packed__));
+
+struct koneplus_profile_settings {
+ uint8_t command; /* KONEPLUS_COMMAND_PROFILE_SETTINGS */
+ uint8_t size; /* always 43 */
+ uint8_t number; /* range 0-4 */
+ uint8_t advanced_sensitivity;
+ uint8_t sensitivity_x;
+ uint8_t sensitivity_y;
+ uint8_t cpi_levels_enabled;
+ uint8_t cpi_levels_x[5];
+ uint8_t cpi_startup_level; /* range 0-4 */
+ uint8_t cpi_levels_y[5]; /* range 1-60 means 100-6000 cpi */
+ uint8_t unknown1;
+ uint8_t polling_rate;
+ uint8_t lights_enabled;
+ uint8_t light_effect_mode;
+ uint8_t color_flow_effect;
+ uint8_t light_effect_type;
+ uint8_t light_effect_speed;
+ uint8_t lights[16];
+ uint16_t checksum;
+} __attribute__ ((__packed__));
+
+struct koneplus_profile_buttons {
+ uint8_t command; /* KONEPLUS_COMMAND_PROFILE_BUTTONS */
+ uint8_t size; /* always 77 */
+ uint8_t number; /* range 0-4 */
+ uint8_t data[72];
+ uint16_t checksum;
+} __attribute__ ((__packed__));
+
+struct koneplus_macro {
+ uint8_t command; /* KONEPLUS_COMMAND_MACRO */
+ uint16_t size; /* always 0x822 little endian */
+ uint8_t profile; /* range 0-4 */
+ uint8_t button; /* range 0-23 */
+ uint8_t data[2075];
+ uint16_t checksum;
+} __attribute__ ((__packed__));
+
+struct koneplus_info {
+ uint8_t command; /* KONEPLUS_COMMAND_INFO */
+ uint8_t size; /* always 6 */
+ uint8_t firmware_version;
+ uint8_t unknown[3];
+} __attribute__ ((__packed__));
+
+struct koneplus_e {
+ uint8_t command; /* KONEPLUS_COMMAND_E */
+ uint8_t size; /* always 3 */
+ uint8_t unknown; /* TODO 1; 0 before firmware update */
+} __attribute__ ((__packed__));
+
+struct koneplus_sensor {
+ uint8_t command; /* KONEPLUS_COMMAND_SENSOR */
+ uint8_t size; /* always 6 */
+ uint8_t data[4];
+} __attribute__ ((__packed__));
+
+struct koneplus_firmware_write {
+ uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE */
+ uint8_t unknown[1025];
+} __attribute__ ((__packed__));
+
+struct koneplus_firmware_write_control {
+ uint8_t command; /* KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL */
+ /*
+ * value is 1 on success
+ * 3 means "not finished yet"
+ */
+ uint8_t value;
+ uint8_t unknown; /* always 0x75 */
+} __attribute__ ((__packed__));
+
+struct koneplus_tcu {
+ uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */
+ uint8_t data[2];
+} __attribute__ ((__packed__));
+
+struct koneplus_tcu_image {
+ uint16_t usb_command; /* KONEPLUS_USB_COMMAND_TCU */
+ uint8_t data[1024];
+ uint16_t checksum;
+} __attribute__ ((__packed__));
+
+enum koneplus_commands {
+ KONEPLUS_COMMAND_CONTROL = 0x4,
+ KONEPLUS_COMMAND_STARTUP_PROFILE = 0x5,
+ KONEPLUS_COMMAND_PROFILE_SETTINGS = 0x6,
+ KONEPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
+ KONEPLUS_COMMAND_MACRO = 0x8,
+ KONEPLUS_COMMAND_INFO = 0x9,
+ KONEPLUS_COMMAND_E = 0xe,
+ KONEPLUS_COMMAND_SENSOR = 0xf,
+ KONEPLUS_COMMAND_FIRMWARE_WRITE = 0x1b,
+ KONEPLUS_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
+};
+
+enum koneplus_usb_commands {
+ KONEPLUS_USB_COMMAND_CONTROL = 0x304,
+ KONEPLUS_USB_COMMAND_STARTUP_PROFILE = 0x305,
+ KONEPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306,
+ KONEPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307,
+ KONEPLUS_USB_COMMAND_MACRO = 0x308,
+ KONEPLUS_USB_COMMAND_INFO = 0x309,
+ KONEPLUS_USB_COMMAND_TCU = 0x30c,
+ KONEPLUS_USB_COMMAND_E = 0x30e,
+ KONEPLUS_USB_COMMAND_SENSOR = 0x30f,
+ KONEPLUS_USB_COMMAND_FIRMWARE_WRITE = 0x31b,
+ KONEPLUS_USB_COMMAND_FIRMWARE_WRITE_CONTROL = 0x31c,
+};
+
+enum koneplus_mouse_report_numbers {
+ KONEPLUS_MOUSE_REPORT_NUMBER_HID = 1,
+ KONEPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2,
+ KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON = 3,
+};
+
+struct koneplus_mouse_report_button {
+ uint8_t report_number; /* always KONEPLUS_MOUSE_REPORT_NUMBER_BUTTON */
+ uint8_t zero1;
+ uint8_t type;
+ uint8_t data1;
+ uint8_t data2;
+ uint8_t zero2;
+ uint8_t unknown[2];
+} __attribute__ ((__packed__));
+
+enum koneplus_mouse_report_button_types {
+ /* data1 = new profile range 1-5 */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE = 0x20,
+
+ /* data1 = button number range 1-24; data2 = action */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH = 0x60,
+
+ /* data1 = button number range 1-24; data2 = action */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER = 0x80,
+
+ /* data1 = setting number range 1-5 */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI = 0xb0,
+
+ /* data1 and data2 = range 0x1-0xb */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY = 0xc0,
+
+ /* data1 = 22 = next track...
+ * data2 = action
+ */
+ KONEPLUS_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0,
+};
+
+enum koneplus_mouse_report_button_action {
+ KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS = 0,
+ KONEPLUS_MOUSE_REPORT_BUTTON_ACTION_RELEASE = 1,
+};
+
+struct koneplus_roccat_report {
+ uint8_t type;
+ uint8_t data1;
+ uint8_t data2;
+ uint8_t profile;
+} __attribute__ ((__packed__));
+
+struct koneplus_device {
+ int actual_profile;
+
+ int roccat_claimed;
+ int chrdev_minor;
+
+ struct mutex koneplus_lock;
+
+ int startup_profile;
+ struct koneplus_info info;
+ struct koneplus_profile_settings profile_settings[5];
+ struct koneplus_profile_buttons profile_buttons[5];
+};
+
+#endif
diff --git a/drivers/hid/hid-roccat-kovaplus.c b/drivers/hid/hid-roccat-kovaplus.c
new file mode 100644
index 000000000000..984be2f8967e
--- /dev/null
+++ b/drivers/hid/hid-roccat-kovaplus.c
@@ -0,0 +1,715 @@
+/*
+ * Roccat Kova[+] driver for Linux
+ *
+ * Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Roccat Kova[+] is a bigger version of the Pyra with two more side buttons.
+ */
+
+#include <linux/device.h>
+#include <linux/input.h>
+#include <linux/hid.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/hid-roccat.h>
+#include "hid-ids.h"
+#include "hid-roccat-common.h"
+#include "hid-roccat-kovaplus.h"
+
+static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+
+static struct class *kovaplus_class;
+
+static uint kovaplus_convert_event_cpi(uint value)
+{
+ return (value == 7 ? 4 : (value == 4 ? 3 : value));
+}
+
+static void kovaplus_profile_activated(struct kovaplus_device *kovaplus,
+ uint new_profile_index)
+{
+ kovaplus->actual_profile = new_profile_index;
+ kovaplus->actual_cpi = kovaplus->profile_settings[new_profile_index].cpi_startup_level;
+ kovaplus->actual_x_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_x;
+ kovaplus->actual_y_sensitivity = kovaplus->profile_settings[new_profile_index].sensitivity_y;
+}
+
+static int kovaplus_send_control(struct usb_device *usb_dev, uint value,
+ enum kovaplus_control_requests request)
+{
+ int retval;
+ struct kovaplus_control control;
+
+ if ((request == KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS ||
+ request == KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS) &&
+ value > 4)
+ return -EINVAL;
+
+ control.command = KOVAPLUS_COMMAND_CONTROL;
+ control.value = value;
+ control.request = request;
+
+ retval = roccat_common_send(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL,
+ &control, sizeof(struct kovaplus_control));
+
+ return retval;
+}
+
+static int kovaplus_receive_control_status(struct usb_device *usb_dev)
+{
+ int retval;
+ struct kovaplus_control control;
+
+ do {
+ retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_CONTROL,
+ &control, sizeof(struct kovaplus_control));
+
+ /* check if we get a completely wrong answer */
+ if (retval)
+ return retval;
+
+ if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OK)
+ return 0;
+
+ /* indicates that hardware needs some more time to complete action */
+ if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_WAIT) {
+ msleep(500); /* windows driver uses 1000 */
+ continue;
+ }
+
+ /* seems to be critical - replug necessary */
+ if (control.value == KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD)
+ return -EINVAL;
+
+ hid_err(usb_dev, "kovaplus_receive_control_status: "
+ "unknown response value 0x%x\n", control.value);
+ return -EINVAL;
+ } while (1);
+}
+
+static int kovaplus_send(struct usb_device *usb_dev, uint command,
+ void const *buf, uint size)
+{
+ int retval;
+
+ retval = roccat_common_send(usb_dev, command, buf, size);
+ if (retval)
+ return retval;
+
+ msleep(100);
+
+ return kovaplus_receive_control_status(usb_dev);
+}
+
+static int kovaplus_select_profile(struct usb_device *usb_dev, uint number,
+ enum kovaplus_control_requests request)
+{
+ return kovaplus_send_control(usb_dev, number, request);
+}
+
+static int kovaplus_get_info(struct usb_device *usb_dev,
+ struct kovaplus_info *buf)
+{
+ return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_INFO,
+ buf, sizeof(struct kovaplus_info));
+}
+
+static int kovaplus_get_profile_settings(struct usb_device *usb_dev,
+ struct kovaplus_profile_settings *buf, uint number)
+{
+ int retval;
+
+ retval = kovaplus_select_profile(usb_dev, number,
+ KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS);
+ if (retval)
+ return retval;
+
+ return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS,
+ buf, sizeof(struct kovaplus_profile_settings));
+}
+
+static int kovaplus_set_profile_settings(struct usb_device *usb_dev,
+ struct kovaplus_profile_settings const *settings)
+{
+ return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS,
+ settings, sizeof(struct kovaplus_profile_settings));
+}
+
+static int kovaplus_get_profile_buttons(struct usb_device *usb_dev,
+ struct kovaplus_profile_buttons *buf, int number)
+{
+ int retval;
+
+ retval = kovaplus_select_profile(usb_dev, number,
+ KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS);
+ if (retval)
+ return retval;
+
+ return roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS,
+ buf, sizeof(struct kovaplus_profile_buttons));
+}
+
+static int kovaplus_set_profile_buttons(struct usb_device *usb_dev,
+ struct kovaplus_profile_buttons const *buttons)
+{
+ return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS,
+ buttons, sizeof(struct kovaplus_profile_buttons));
+}
+
+/* retval is 0-4 on success, < 0 on error */
+static int kovaplus_get_actual_profile(struct usb_device *usb_dev)
+{
+ struct kovaplus_actual_profile buf;
+ int retval;
+
+ retval = roccat_common_receive(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE,
+ &buf, sizeof(struct kovaplus_actual_profile));
+
+ return retval ? retval : buf.actual_profile;
+}
+
+static int kovaplus_set_actual_profile(struct usb_device *usb_dev,
+ int new_profile)
+{
+ struct kovaplus_actual_profile buf;
+
+ buf.command = KOVAPLUS_COMMAND_ACTUAL_PROFILE;
+ buf.size = sizeof(struct kovaplus_actual_profile);
+ buf.actual_profile = new_profile;
+
+ return kovaplus_send(usb_dev, KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE,
+ &buf, sizeof(struct kovaplus_actual_profile));
+}
+
+static ssize_t kovaplus_sysfs_read_profilex_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
+
+ if (off >= sizeof(struct kovaplus_profile_settings))
+ return 0;
+
+ if (off + count > sizeof(struct kovaplus_profile_settings))
+ count = sizeof(struct kovaplus_profile_settings) - off;
+
+ mutex_lock(&kovaplus->kovaplus_lock);
+ memcpy(buf, ((char const *)&kovaplus->profile_settings[*(uint *)(attr->private)]) + off,
+ count);
+ mutex_unlock(&kovaplus->kovaplus_lock);
+
+ return count;
+}
+
+static ssize_t kovaplus_sysfs_write_profile_settings(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval = 0;
+ int difference;
+ int profile_index;
+ struct kovaplus_profile_settings *profile_settings;
+
+ if (off != 0 || count != sizeof(struct kovaplus_profile_settings))
+ return -EINVAL;
+
+ profile_index = ((struct kovaplus_profile_settings const *)buf)->profile_index;
+ profile_settings = &kovaplus->profile_settings[profile_index];
+
+ mutex_lock(&kovaplus->kovaplus_lock);
+ difference = memcmp(buf, profile_settings,
+ sizeof(struct kovaplus_profile_settings));
+ if (difference) {
+ retval = kovaplus_set_profile_settings(usb_dev,
+ (struct kovaplus_profile_settings const *)buf);
+ if (!retval)
+ memcpy(profile_settings, buf,
+ sizeof(struct kovaplus_profile_settings));
+ }
+ mutex_unlock(&kovaplus->kovaplus_lock);
+
+ if (retval)
+ return retval;
+
+ return sizeof(struct kovaplus_profile_settings);
+}
+
+static ssize_t kovaplus_sysfs_read_profilex_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
+
+ if (off >= sizeof(struct kovaplus_profile_buttons))
+ return 0;
+
+ if (off + count > sizeof(struct kovaplus_profile_buttons))
+ count = sizeof(struct kovaplus_profile_buttons) - off;
+
+ mutex_lock(&kovaplus->kovaplus_lock);
+ memcpy(buf, ((char const *)&kovaplus->profile_buttons[*(uint *)(attr->private)]) + off,
+ count);
+ mutex_unlock(&kovaplus->kovaplus_lock);
+
+ return count;
+}
+
+static ssize_t kovaplus_sysfs_write_profile_buttons(struct file *fp,
+ struct kobject *kobj, struct bin_attribute *attr, char *buf,
+ loff_t off, size_t count)
+{
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
+ struct kovaplus_device *kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
+ struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
+ int retval = 0;
+ int difference;
+ uint profile_index;
+ struct kovaplus_profile_buttons *profile_buttons;
+
+ if (off != 0 || count != sizeof(struct kovaplus_profile_buttons))
+ return -EINVAL;
+
+ profile_index = ((struct kovaplus_profile_buttons const *)buf)->profile_index;
+ profile_buttons = &kovaplus->profile_buttons[profile_index];
+
+ mutex_lock(&kovaplus->kovaplus_lock);
+ difference = memcmp(buf, profile_buttons,
+ sizeof(struct kovaplus_profile_buttons));
+ if (difference) {
+ retval = kovaplus_set_profile_buttons(usb_dev,
+ (struct kovaplus_profile_buttons const *)buf);
+ if (!retval)
+ memcpy(profile_buttons, buf,
+ sizeof(struct kovaplus_profile_buttons));
+ }
+ mutex_unlock(&kovaplus->kovaplus_lock);
+
+ if (retval)
+ return retval;
+
+ return sizeof(struct kovaplus_profile_buttons);
+}
+
+static ssize_t kovaplus_sysfs_show_actual_profile(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kovaplus_device *kovaplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_profile);
+}
+
+static ssize_t kovaplus_sysfs_set_actual_profile(struct device *dev,
+ struct device_attribute *attr, char const *buf, size_t size)
+{
+ struct kovaplus_device *kovaplus;
+ struct usb_device *usb_dev;
+ unsigned long profile;
+ int retval;
+
+ dev = dev->parent->parent;
+ kovaplus = hid_get_drvdata(dev_get_drvdata(dev));
+ usb_dev = interface_to_usbdev(to_usb_interface(dev));
+
+ retval = strict_strtoul(buf, 10, &profile);
+ if (retval)
+ return retval;
+
+ if (profile >= 5)
+ return -EINVAL;
+
+ mutex_lock(&kovaplus->kovaplus_lock);
+ retval = kovaplus_set_actual_profile(usb_dev, profile);
+ kovaplus->actual_profile = profile;
+ mutex_unlock(&kovaplus->kovaplus_lock);
+ if (retval)
+ return retval;
+
+ return size;
+}
+
+static ssize_t kovaplus_sysfs_show_actual_cpi(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kovaplus_device *kovaplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_cpi);
+}
+
+static ssize_t kovaplus_sysfs_show_actual_sensitivity_x(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kovaplus_device *kovaplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_x_sensitivity);
+}
+
+static ssize_t kovaplus_sysfs_show_actual_sensitivity_y(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kovaplus_device *kovaplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->actual_y_sensitivity);
+}
+
+static ssize_t kovaplus_sysfs_show_firmware_version(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct kovaplus_device *kovaplus =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
+ return snprintf(buf, PAGE_SIZE, "%d\n", kovaplus->info.firmware_version);
+}
+
+static struct device_attribute kovaplus_attributes[] = {
+ __ATTR(actual_cpi, 0440,
+ kovaplus_sysfs_show_actual_cpi, NULL),
+ __ATTR(firmware_version, 0440,
+ kovaplus_sysfs_show_firmware_version, NULL),
+ __ATTR(actual_profile, 0660,
+ kovaplus_sysfs_show_actual_profile,
+ kovaplus_sysfs_set_actual_profile),
+ __ATTR(actual_sensitivity_x, 0440,
+ kovaplus_sysfs_show_actual_sensitivity_x, NULL),
+ __ATTR(actual_sensitivity_y, 0440,
+ kovaplus_sysfs_show_actual_sensitivity_y, NULL),
+ __ATTR_NULL
+};
+
+static struct bin_attribute kovaplus_bin_attributes[] = {
+ {
+ .attr = { .name = "profile_settings", .mode = 0220 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .write = kovaplus_sysfs_write_profile_settings
+ },
+ {
+ .attr = { .name = "profile1_settings", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .read = kovaplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[0]
+ },
+ {
+ .attr = { .name = "profile2_settings", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .read = kovaplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[1]
+ },
+ {
+ .attr = { .name = "profile3_settings", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .read = kovaplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[2]
+ },
+ {
+ .attr = { .name = "profile4_settings", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .read = kovaplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[3]
+ },
+ {
+ .attr = { .name = "profile5_settings", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_settings),
+ .read = kovaplus_sysfs_read_profilex_settings,
+ .private = &profile_numbers[4]
+ },
+ {
+ .attr = { .name = "profile_buttons", .mode = 0220 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .write = kovaplus_sysfs_write_profile_buttons
+ },
+ {
+ .attr = { .name = "profile1_buttons", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .read = kovaplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[0]
+ },
+ {
+ .attr = { .name = "profile2_buttons", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .read = kovaplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[1]
+ },
+ {
+ .attr = { .name = "profile3_buttons", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .read = kovaplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[2]
+ },
+ {
+ .attr = { .name = "profile4_buttons", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .read = kovaplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[3]
+ },
+ {
+ .attr = { .name = "profile5_buttons", .mode = 0440 },
+ .size = sizeof(struct kovaplus_profile_buttons),
+ .read = kovaplus_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[4]
+ },
+ __ATTR_NULL
+};
+
+static int kovaplus_init_kovaplus_device_struct(struct usb_device *usb_dev,
+ struct kovaplus_device *kovaplus)
+{
+ int retval, i;
+ static uint wait = 70; /* device will freeze with just 60 */
+
+ mutex_init(&kovaplus->kovaplus_lock);
+
+ retval = kovaplus_get_info(usb_dev, &kovaplus->info);
+ if (retval)
+ return retval;
+
+ for (i = 0; i < 5; ++i) {
+ msleep(wait);
+ retval = kovaplus_get_profile_settings(usb_dev,
+ &kovaplus->profile_settings[i], i);
+ if (retval)
+ return retval;
+
+ msleep(wait);
+ retval = kovaplus_get_profile_buttons(usb_dev,
+ &kovaplus->profile_buttons[i], i);
+ if (retval)
+ return retval;
+ }
+
+ msleep(wait);
+ retval = kovaplus_get_actual_profile(usb_dev);
+ if (retval < 0)
+ return retval;
+ kovaplus_profile_activated(kovaplus, retval);
+
+ return 0;
+}
+
+static int kovaplus_init_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct usb_device *usb_dev = interface_to_usbdev(intf);
+ struct kovaplus_device *kovaplus;
+ int retval;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_MOUSE) {
+
+ kovaplus = kzalloc(sizeof(*kovaplus), GFP_KERNEL);
+ if (!kovaplus) {
+ hid_err(hdev, "can't alloc device descriptor\n");
+ return -ENOMEM;
+ }
+ hid_set_drvdata(hdev, kovaplus);
+
+ retval = kovaplus_init_kovaplus_device_struct(usb_dev, kovaplus);
+ if (retval) {
+ hid_err(hdev, "couldn't init struct kovaplus_device\n");
+ goto exit_free;
+ }
+
+ retval = roccat_connect(kovaplus_class, hdev,
+ sizeof(struct kovaplus_roccat_report));
+ if (retval < 0) {
+ hid_err(hdev, "couldn't init char dev\n");
+ } else {
+ kovaplus->chrdev_minor = retval;
+ kovaplus->roccat_claimed = 1;
+ }
+
+ } else {
+ hid_set_drvdata(hdev, NULL);
+ }
+
+ return 0;
+exit_free:
+ kfree(kovaplus);
+ return retval;
+}
+
+static void kovaplus_remove_specials(struct hid_device *hdev)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct kovaplus_device *kovaplus;
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ == USB_INTERFACE_PROTOCOL_MOUSE) {
+ kovaplus = hid_get_drvdata(hdev);
+ if (kovaplus->roccat_claimed)
+ roccat_disconnect(kovaplus->chrdev_minor);
+ kfree(kovaplus);
+ }
+}
+
+static int kovaplus_probe(struct hid_device *hdev,
+ const struct hid_device_id *id)
+{
+ int retval;
+
+ retval = hid_parse(hdev);
+ if (retval) {
+ hid_err(hdev, "parse failed\n");
+ goto exit;
+ }
+
+ retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
+ if (retval) {
+ hid_err(hdev, "hw start failed\n");
+ goto exit;
+ }
+
+ retval = kovaplus_init_specials(hdev);
+ if (retval) {
+ hid_err(hdev, "couldn't install mouse\n");
+ goto exit_stop;
+ }
+
+ return 0;
+
+exit_stop:
+ hid_hw_stop(hdev);
+exit:
+ return retval;
+}
+
+static void kovaplus_remove(struct hid_device *hdev)
+{
+ kovaplus_remove_specials(hdev);
+ hid_hw_stop(hdev);
+}
+
+static void kovaplus_keep_values_up_to_date(struct kovaplus_device *kovaplus,
+ u8 const *data)
+{
+ struct kovaplus_mouse_report_button const *button_report;
+
+ if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON)
+ return;
+
+ button_report = (struct kovaplus_mouse_report_button const *)data;
+
+ switch (button_report->type) {
+ case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1:
+ kovaplus_profile_activated(kovaplus, button_report->data1 - 1);
+ break;
+ case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI:
+ kovaplus->actual_cpi = kovaplus_convert_event_cpi(button_report->data1);
+ case KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY:
+ kovaplus->actual_x_sensitivity = button_report->data1;
+ kovaplus->actual_y_sensitivity = button_report->data2;
+ }
+}
+
+static void kovaplus_report_to_chrdev(struct kovaplus_device const *kovaplus,
+ u8 const *data)
+{
+ struct kovaplus_roccat_report roccat_report;
+ struct kovaplus_mouse_report_button const *button_report;
+
+ if (data[0] != KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON)
+ return;
+
+ button_report = (struct kovaplus_mouse_report_button const *)data;
+
+ if (button_report->type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2)
+ return;
+
+ roccat_report.type = button_report->type;
+ roccat_report.profile = kovaplus->actual_profile + 1;
+
+ if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO ||
+ roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT ||
+ roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH ||
+ roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER)
+ roccat_report.button = button_report->data1;
+ else
+ roccat_report.button = 0;
+
+ if (roccat_report.type == KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI)
+ roccat_report.data1 = kovaplus_convert_event_cpi(button_report->data1);
+ else
+ roccat_report.data1 = button_report->data1;
+
+ roccat_report.data2 = button_report->data2;
+
+ roccat_report_event(kovaplus->chrdev_minor,
+ (uint8_t const *)&roccat_report);
+}
+
+static int kovaplus_raw_event(struct hid_device *hdev,
+ struct hid_report *report, u8 *data, int size)
+{
+ struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
+ struct kovaplus_device *kovaplus = hid_get_drvdata(hdev);
+
+ if (intf->cur_altsetting->desc.bInterfaceProtocol
+ != USB_INTERFACE_PROTOCOL_MOUSE)
+ return 0;
+
+ kovaplus_keep_values_up_to_date(kovaplus, data);
+
+ if (kovaplus->roccat_claimed)
+ kovaplus_report_to_chrdev(kovaplus, data);
+
+ return 0;
+}
+
+static const struct hid_device_id kovaplus_devices[] = {
+ { HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(hid, kovaplus_devices);
+
+static struct hid_driver kovaplus_driver = {
+ .name = "kovaplus",
+ .id_table = kovaplus_devices,
+ .probe = kovaplus_probe,
+ .remove = kovaplus_remove,
+ .raw_event = kovaplus_raw_event
+};
+
+static int __init kovaplus_init(void)
+{
+ int retval;
+
+ kovaplus_class = class_create(THIS_MODULE, "kovaplus");
+ if (IS_ERR(kovaplus_class))
+ return PTR_ERR(kovaplus_class);
+ kovaplus_class->dev_attrs = kovaplus_attributes;
+ kovaplus_class->dev_bin_attrs = kovaplus_bin_attributes;
+
+ retval = hid_register_driver(&kovaplus_driver);
+ if (retval)
+ class_destroy(kovaplus_class);
+ return retval;
+}
+
+static void __exit kovaplus_exit(void)
+{
+ hid_unregister_driver(&kovaplus_driver);
+ class_destroy(kovaplus_class);
+}
+
+module_init(kovaplus_init);
+module_exit(kovaplus_exit);
+
+MODULE_AUTHOR("Stefan Achatz");
+MODULE_DESCRIPTION("USB Roccat Kova[+] driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hid/hid-roccat-kovaplus.h b/drivers/hid/hid-roccat-kovaplus.h
new file mode 100644
index 000000000000..ce40607d21c7
--- /dev/null
+++ b/drivers/hid/hid-roccat-kovaplus.h
@@ -0,0 +1,157 @@
+#ifndef __HID_ROCCAT_KOVAPLUS_H
+#define __HID_ROCCAT_KOVAPLUS_H
+
+/*
+ * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
+ */
+
+/*
+ * 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/types.h>
+
+struct kovaplus_control {
+ uint8_t command; /* KOVAPLUS_COMMAND_CONTROL */
+ uint8_t value;
+ uint8_t request;
+} __packed;
+
+enum kovaplus_control_requests {
+ /* read after write; value = 1 */
+ KOVAPLUS_CONTROL_REQUEST_STATUS = 0x0,
+ /* write; value = profile number range 0-4 */
+ KOVAPLUS_CONTROL_REQUEST_PROFILE_SETTINGS = 0x10,
+ /* write; value = profile number range 0-4 */
+ KOVAPLUS_CONTROL_REQUEST_PROFILE_BUTTONS = 0x20,
+};
+
+enum kovaplus_control_values {
+ KOVAPLUS_CONTROL_REQUEST_STATUS_OVERLOAD = 0, /* supposed */
+ KOVAPLUS_CONTROL_REQUEST_STATUS_OK = 1,
+ KOVAPLUS_CONTROL_REQUEST_STATUS_WAIT = 3, /* supposed */
+};
+
+struct kovaplus_actual_profile {
+ uint8_t command; /* KOVAPLUS_COMMAND_ACTUAL_PROFILE */
+ uint8_t size; /* always 3 */
+ uint8_t actual_profile; /* Range 0-4! */
+} __packed;
+
+struct kovaplus_profile_settings {
+ uint8_t command; /* KOVAPLUS_COMMAND_PROFILE_SETTINGS */
+ uint8_t size; /* 16 */
+ uint8_t profile_index; /* range 0-4 */
+ uint8_t unknown1;
+ uint8_t sensitivity_x; /* range 1-10 */
+ uint8_t sensitivity_y; /* range 1-10 */
+ uint8_t cpi_levels_enabled;
+ uint8_t cpi_startup_level; /* range 1-4 */
+ uint8_t data[8];
+} __packed;
+
+struct kovaplus_profile_buttons {
+ uint8_t command; /* KOVAPLUS_COMMAND_PROFILE_BUTTONS */
+ uint8_t size; /* 23 */
+ uint8_t profile_index; /* range 0-4 */
+ uint8_t data[20];
+} __packed;
+
+struct kovaplus_info {
+ uint8_t command; /* KOVAPLUS_COMMAND_INFO */
+ uint8_t size; /* 6 */
+ uint8_t firmware_version;
+ uint8_t unknown[3];
+} __packed;
+
+/* writes 1 on plugin */
+struct kovaplus_a {
+ uint8_t command; /* KOVAPLUS_COMMAND_A */
+ uint8_t size; /* 3 */
+ uint8_t unknown;
+} __packed;
+
+enum kovaplus_commands {
+ KOVAPLUS_COMMAND_CONTROL = 0x4,
+ KOVAPLUS_COMMAND_ACTUAL_PROFILE = 0x5,
+ KOVAPLUS_COMMAND_PROFILE_SETTINGS = 0x6,
+ KOVAPLUS_COMMAND_PROFILE_BUTTONS = 0x7,
+ KOVAPLUS_COMMAND_INFO = 0x9,
+ KOVAPLUS_COMMAND_A = 0xa,
+};
+
+enum kovaplus_usb_commands {
+ KOVAPLUS_USB_COMMAND_CONTROL = 0x304,
+ KOVAPLUS_USB_COMMAND_ACTUAL_PROFILE = 0x305,
+ KOVAPLUS_USB_COMMAND_PROFILE_SETTINGS = 0x306,
+ KOVAPLUS_USB_COMMAND_PROFILE_BUTTONS = 0x307,
+ KOVAPLUS_USB_COMMAND_INFO = 0x309,
+ KOVAPLUS_USB_COMMAND_A = 0x30a,
+};
+
+enum kovaplus_mouse_report_numbers {
+ KOVAPLUS_MOUSE_REPORT_NUMBER_MOUSE = 1,
+ KOVAPLUS_MOUSE_REPORT_NUMBER_AUDIO = 2,
+ KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON = 3,
+ KOVAPLUS_MOUSE_REPORT_NUMBER_KBD = 4,
+};
+
+struct kovaplus_mouse_report_button {
+ uint8_t report_number; /* KOVAPLUS_MOUSE_REPORT_NUMBER_BUTTON */
+ uint8_t unknown1;
+ uint8_t type;
+ uint8_t data1;
+ uint8_t data2;
+} __packed;
+
+enum kovaplus_mouse_report_button_types {
+ /* data1 = profile_number range 1-5; no release event */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_1 = 0x20,
+ /* data1 = profile_number range 1-5; no release event */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_PROFILE_2 = 0x30,
+ /* data1 = button_number range 1-18; data2 = action */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MACRO = 0x40,
+ /* data1 = button_number range 1-18; data2 = action */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SHORTCUT = 0x50,
+ /* data1 = button_number range 1-18; data2 = action */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_QUICKLAUNCH = 0x60,
+ /* data1 = button_number range 1-18; data2 = action */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_TIMER = 0x80,
+ /* data1 = 1 = 400, 2 = 800, 4 = 1600, 7 = 3200; no release event */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_CPI = 0xb0,
+ /* data1 + data2 = sense range 1-10; no release event */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_SENSITIVITY = 0xc0,
+ /* data1 = type as in profile_buttons; data2 = action */
+ KOVAPLUS_MOUSE_REPORT_BUTTON_TYPE_MULTIMEDIA = 0xf0,
+};
+
+enum kovaplus_mouse_report_button_actions {
+ KOVAPLUS_MOUSE_REPORT_BUTTON_ACTION_PRESS = 0,
+ KOVAPLUS_MOUSE_REPORT_BUTTON_ACTION_RELEASE = 1,
+};
+
+struct kovaplus_roccat_report {
+ uint8_t type;
+ uint8_t profile;
+ uint8_t button;
+ uint8_t data1;
+ uint8_t data2;
+} __packed;
+
+struct kovaplus_device {
+ int actual_profile;
+ int actual_cpi;
+ int actual_x_sensitivity;
+ int actual_y_sensitivity;
+ int roccat_claimed;
+ int chrdev_minor;
+ struct mutex kovaplus_lock;
+ struct kovaplus_info info;
+ struct kovaplus_profile_settings profile_settings[5];
+ struct kovaplus_profile_buttons profile_buttons[5];
+};
+
+#endif
diff --git a/drivers/hid/hid-roccat-pyra.c b/drivers/hid/hid-roccat-pyra.c
index 9bf23047892a..160f481344f6 100644
--- a/drivers/hid/hid-roccat-pyra.c
+++ b/drivers/hid/hid-roccat-pyra.c
@@ -20,13 +20,18 @@
#include <linux/device.h>
#include <linux/input.h>
#include <linux/hid.h>
-#include <linux/usb.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/hid-roccat.h>
#include "hid-ids.h"
-#include "hid-roccat.h"
+#include "hid-roccat-common.h"
#include "hid-roccat-pyra.h"
+static uint profile_numbers[5] = {0, 1, 2, 3, 4};
+
+/* pyra_class is used for creating sysfs attributes via roccat char device */
+static struct class *pyra_class;
+
static void profile_activated(struct pyra_device *pyra,
unsigned int new_profile)
{
@@ -37,7 +42,6 @@ static void profile_activated(struct pyra_device *pyra,
static int pyra_send_control(struct usb_device *usb_dev, int value,
enum pyra_control_requests request)
{
- int len;
struct pyra_control control;
if ((request == PYRA_CONTROL_REQUEST_PROFILE_SETTINGS ||
@@ -49,48 +53,31 @@ static int pyra_send_control(struct usb_device *usb_dev, int value,
control.value = value;
control.request = request;
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- PYRA_USB_COMMAND_CONTROL, 0, (char *)&control,
- sizeof(struct pyra_control),
- USB_CTRL_SET_TIMEOUT);
-
- if (len != sizeof(struct pyra_control))
- return len;
-
- return 0;
+ return roccat_common_send(usb_dev, PYRA_USB_COMMAND_CONTROL,
+ &control, sizeof(struct pyra_control));
}
static int pyra_receive_control_status(struct usb_device *usb_dev)
{
- int len;
+ int retval;
struct pyra_control control;
do {
msleep(10);
-
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE |
- USB_DIR_IN,
- PYRA_USB_COMMAND_CONTROL, 0, (char *)&control,
- sizeof(struct pyra_control),
- USB_CTRL_SET_TIMEOUT);
+ retval = roccat_common_receive(usb_dev, PYRA_USB_COMMAND_CONTROL,
+ &control, sizeof(struct pyra_control));
/* requested too early, try again */
- } while (len == -EPROTO);
+ } while (retval == -EPROTO);
- if (len == sizeof(struct pyra_control) &&
- control.command == PYRA_COMMAND_CONTROL &&
+ if (!retval && control.command == PYRA_COMMAND_CONTROL &&
control.request == PYRA_CONTROL_REQUEST_STATUS &&
control.value == 1)
- return 0;
+ return 0;
else {
- dev_err(&usb_dev->dev, "receive control status: "
- "unknown response 0x%x 0x%x\n",
- control.request, control.value);
- return -EINVAL;
+ hid_err(usb_dev, "receive control status: unknown response 0x%x 0x%x\n",
+ control.request, control.value);
+ return retval ? retval : -EINVAL;
}
}
@@ -98,132 +85,80 @@ static int pyra_get_profile_settings(struct usb_device *usb_dev,
struct pyra_profile_settings *buf, int number)
{
int retval;
-
retval = pyra_send_control(usb_dev, number,
PYRA_CONTROL_REQUEST_PROFILE_SETTINGS);
-
if (retval)
return retval;
-
- retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)buf,
- sizeof(struct pyra_profile_settings),
- USB_CTRL_SET_TIMEOUT);
-
- if (retval != sizeof(struct pyra_profile_settings))
- return retval;
-
- return 0;
+ return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS,
+ buf, sizeof(struct pyra_profile_settings));
}
static int pyra_get_profile_buttons(struct usb_device *usb_dev,
struct pyra_profile_buttons *buf, int number)
{
int retval;
-
retval = pyra_send_control(usb_dev, number,
PYRA_CONTROL_REQUEST_PROFILE_BUTTONS);
-
if (retval)
return retval;
-
- retval = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buf,
- sizeof(struct pyra_profile_buttons),
- USB_CTRL_SET_TIMEOUT);
-
- if (retval != sizeof(struct pyra_profile_buttons))
- return retval;
-
- return 0;
+ return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS,
+ buf, sizeof(struct pyra_profile_buttons));
}
static int pyra_get_settings(struct usb_device *usb_dev,
struct pyra_settings *buf)
{
- int len;
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- PYRA_USB_COMMAND_SETTINGS, 0, buf,
- sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT);
- if (len != sizeof(struct pyra_settings))
- return -EIO;
- return 0;
+ return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_SETTINGS,
+ buf, sizeof(struct pyra_settings));
}
static int pyra_get_info(struct usb_device *usb_dev, struct pyra_info *buf)
{
- int len;
- len = usb_control_msg(usb_dev, usb_rcvctrlpipe(usb_dev, 0),
- USB_REQ_CLEAR_FEATURE,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN,
- PYRA_USB_COMMAND_INFO, 0, buf,
- sizeof(struct pyra_info), USB_CTRL_SET_TIMEOUT);
- if (len != sizeof(struct pyra_info))
- return -EIO;
- return 0;
+ return roccat_common_receive(usb_dev, PYRA_USB_COMMAND_INFO,
+ buf, sizeof(struct pyra_info));
+}
+
+static int pyra_send(struct usb_device *usb_dev, uint command,
+ void const *buf, uint size)
+{
+ int retval;
+ retval = roccat_common_send(usb_dev, command, buf, size);
+ if (retval)
+ return retval;
+ return pyra_receive_control_status(usb_dev);
}
static int pyra_set_profile_settings(struct usb_device *usb_dev,
struct pyra_profile_settings const *settings)
{
- int len;
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- PYRA_USB_COMMAND_PROFILE_SETTINGS, 0, (char *)settings,
- sizeof(struct pyra_profile_settings),
- USB_CTRL_SET_TIMEOUT);
- if (len != sizeof(struct pyra_profile_settings))
- return -EIO;
- if (pyra_receive_control_status(usb_dev))
- return -EIO;
- return 0;
+ return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_SETTINGS, settings,
+ sizeof(struct pyra_profile_settings));
}
static int pyra_set_profile_buttons(struct usb_device *usb_dev,
struct pyra_profile_buttons const *buttons)
{
- int len;
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- PYRA_USB_COMMAND_PROFILE_BUTTONS, 0, (char *)buttons,
- sizeof(struct pyra_profile_buttons),
- USB_CTRL_SET_TIMEOUT);
- if (len != sizeof(struct pyra_profile_buttons))
- return -EIO;
- if (pyra_receive_control_status(usb_dev))
- return -EIO;
- return 0;
+ return pyra_send(usb_dev, PYRA_USB_COMMAND_PROFILE_BUTTONS, buttons,
+ sizeof(struct pyra_profile_buttons));
}
static int pyra_set_settings(struct usb_device *usb_dev,
struct pyra_settings const *settings)
{
- int len;
- len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
- USB_REQ_SET_CONFIGURATION,
- USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
- PYRA_USB_COMMAND_SETTINGS, 0, (char *)settings,
- sizeof(struct pyra_settings), USB_CTRL_SET_TIMEOUT);
- if (len != sizeof(struct pyra_settings))
- return -EIO;
- if (pyra_receive_control_status(usb_dev))
- return -EIO;
- return 0;
+ int retval;
+ retval = roccat_common_send(usb_dev, PYRA_USB_COMMAND_SETTINGS, settings,
+ sizeof(struct pyra_settings));
+ if (retval)
+ return retval;
+ return pyra_receive_control_status(usb_dev);
}
static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count, int number)
+ loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct pyra_profile_settings))
@@ -233,58 +168,19 @@ static ssize_t pyra_sysfs_read_profilex_settings(struct file *fp,
count = sizeof(struct pyra_profile_settings) - off;
mutex_lock(&pyra->pyra_lock);
- memcpy(buf, ((char const *)&pyra->profile_settings[number]) + off,
+ memcpy(buf, ((char const *)&pyra->profile_settings[*(uint *)(attr->private)]) + off,
count);
mutex_unlock(&pyra->pyra_lock);
return count;
}
-static ssize_t pyra_sysfs_read_profile1_settings(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_settings(fp, kobj,
- attr, buf, off, count, 0);
-}
-
-static ssize_t pyra_sysfs_read_profile2_settings(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_settings(fp, kobj,
- attr, buf, off, count, 1);
-}
-
-static ssize_t pyra_sysfs_read_profile3_settings(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_settings(fp, kobj,
- attr, buf, off, count, 2);
-}
-
-static ssize_t pyra_sysfs_read_profile4_settings(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_settings(fp, kobj,
- attr, buf, off, count, 3);
-}
-
-static ssize_t pyra_sysfs_read_profile5_settings(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_settings(fp, kobj,
- attr, buf, off, count, 4);
-}
-
static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count, int number)
+ loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct pyra_profile_buttons))
@@ -294,58 +190,19 @@ static ssize_t pyra_sysfs_read_profilex_buttons(struct file *fp,
count = sizeof(struct pyra_profile_buttons) - off;
mutex_lock(&pyra->pyra_lock);
- memcpy(buf, ((char const *)&pyra->profile_buttons[number]) + off,
+ memcpy(buf, ((char const *)&pyra->profile_buttons[*(uint *)(attr->private)]) + off,
count);
mutex_unlock(&pyra->pyra_lock);
return count;
}
-static ssize_t pyra_sysfs_read_profile1_buttons(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_buttons(fp, kobj,
- attr, buf, off, count, 0);
-}
-
-static ssize_t pyra_sysfs_read_profile2_buttons(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_buttons(fp, kobj,
- attr, buf, off, count, 1);
-}
-
-static ssize_t pyra_sysfs_read_profile3_buttons(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_buttons(fp, kobj,
- attr, buf, off, count, 2);
-}
-
-static ssize_t pyra_sysfs_read_profile4_buttons(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_buttons(fp, kobj,
- attr, buf, off, count, 3);
-}
-
-static ssize_t pyra_sysfs_read_profile5_buttons(struct file *fp,
- struct kobject *kobj, struct bin_attribute *attr, char *buf,
- loff_t off, size_t count)
-{
- return pyra_sysfs_read_profilex_buttons(fp, kobj,
- attr, buf, off, count, 4);
-}
-
static ssize_t pyra_sysfs_write_profile_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
@@ -381,7 +238,8 @@ static ssize_t pyra_sysfs_write_profile_buttons(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
@@ -417,7 +275,8 @@ static ssize_t pyra_sysfs_read_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
if (off >= sizeof(struct pyra_settings))
@@ -437,7 +296,8 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
struct kobject *kobj, struct bin_attribute *attr, char *buf,
loff_t off, size_t count)
{
- struct device *dev = container_of(kobj, struct device, kobj);
+ struct device *dev =
+ container_of(kobj, struct device, kobj)->parent->parent;
struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval = 0;
@@ -469,273 +329,138 @@ static ssize_t pyra_sysfs_write_settings(struct file *fp,
static ssize_t pyra_sysfs_show_actual_cpi(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ struct pyra_device *pyra =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_cpi);
}
static ssize_t pyra_sysfs_show_actual_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ struct pyra_device *pyra =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->actual_profile);
}
static ssize_t pyra_sysfs_show_firmware_version(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ struct pyra_device *pyra =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->firmware_version);
}
static ssize_t pyra_sysfs_show_startup_profile(struct device *dev,
struct device_attribute *attr, char *buf)
{
- struct pyra_device *pyra = hid_get_drvdata(dev_get_drvdata(dev));
+ struct pyra_device *pyra =
+ hid_get_drvdata(dev_get_drvdata(dev->parent->parent));
return snprintf(buf, PAGE_SIZE, "%d\n", pyra->settings.startup_profile);
}
-static DEVICE_ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL);
-
-static DEVICE_ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL);
-
-static DEVICE_ATTR(firmware_version, 0440,
- pyra_sysfs_show_firmware_version, NULL);
-
-static DEVICE_ATTR(startup_profile, 0440,
- pyra_sysfs_show_startup_profile, NULL);
-
-static struct attribute *pyra_attributes[] = {
- &dev_attr_actual_cpi.attr,
- &dev_attr_actual_profile.attr,
- &dev_attr_firmware_version.attr,
- &dev_attr_startup_profile.attr,
- NULL
+static struct device_attribute pyra_attributes[] = {
+ __ATTR(actual_cpi, 0440, pyra_sysfs_show_actual_cpi, NULL),
+ __ATTR(actual_profile, 0440, pyra_sysfs_show_actual_profile, NULL),
+ __ATTR(firmware_version, 0440,
+ pyra_sysfs_show_firmware_version, NULL),
+ __ATTR(startup_profile, 0440,
+ pyra_sysfs_show_startup_profile, NULL),
+ __ATTR_NULL
};
-static struct attribute_group pyra_attribute_group = {
- .attrs = pyra_attributes
-};
-
-static struct bin_attribute pyra_profile_settings_attr = {
+static struct bin_attribute pyra_bin_attributes[] = {
+ {
.attr = { .name = "profile_settings", .mode = 0220 },
.size = sizeof(struct pyra_profile_settings),
.write = pyra_sysfs_write_profile_settings
-};
-
-static struct bin_attribute pyra_profile1_settings_attr = {
+ },
+ {
.attr = { .name = "profile1_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
- .read = pyra_sysfs_read_profile1_settings
-};
-
-static struct bin_attribute pyra_profile2_settings_attr = {
+ .read = pyra_sysfs_read_profilex_settings,
+ .private = &profile_numbers[0]
+ },
+ {
.attr = { .name = "profile2_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
- .read = pyra_sysfs_read_profile2_settings
-};
-
-static struct bin_attribute pyra_profile3_settings_attr = {
+ .read = pyra_sysfs_read_profilex_settings,
+ .private = &profile_numbers[1]
+ },
+ {
.attr = { .name = "profile3_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
- .read = pyra_sysfs_read_profile3_settings
-};
-
-static struct bin_attribute pyra_profile4_settings_attr = {
+ .read = pyra_sysfs_read_profilex_settings,
+ .private = &profile_numbers[2]
+ },
+ {
.attr = { .name = "profile4_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
- .read = pyra_sysfs_read_profile4_settings
-};
-
-static struct bin_attribute pyra_profile5_settings_attr = {
+ .read = pyra_sysfs_read_profilex_settings,
+ .private = &profile_numbers[3]
+ },
+ {
.attr = { .name = "profile5_settings", .mode = 0440 },
.size = sizeof(struct pyra_profile_settings),
- .read = pyra_sysfs_read_profile5_settings
-};
-
-static struct bin_attribute pyra_profile_buttons_attr = {
+ .read = pyra_sysfs_read_profilex_settings,
+ .private = &profile_numbers[4]
+ },
+ {
.attr = { .name = "profile_buttons", .mode = 0220 },
.size = sizeof(struct pyra_profile_buttons),
.write = pyra_sysfs_write_profile_buttons
-};
-
-static struct bin_attribute pyra_profile1_buttons_attr = {
+ },
+ {
.attr = { .name = "profile1_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
- .read = pyra_sysfs_read_profile1_buttons
-};
-
-static struct bin_attribute pyra_profile2_buttons_attr = {
+ .read = pyra_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[0]
+ },
+ {
.attr = { .name = "profile2_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
- .read = pyra_sysfs_read_profile2_buttons
-};
-
-static struct bin_attribute pyra_profile3_buttons_attr = {
+ .read = pyra_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[1]
+ },
+ {
.attr = { .name = "profile3_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
- .read = pyra_sysfs_read_profile3_buttons
-};
-
-static struct bin_attribute pyra_profile4_buttons_attr = {
+ .read = pyra_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[2]
+ },
+ {
.attr = { .name = "profile4_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
- .read = pyra_sysfs_read_profile4_buttons
-};
-
-static struct bin_attribute pyra_profile5_buttons_attr = {
+ .read = pyra_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[3]
+ },
+ {
.attr = { .name = "profile5_buttons", .mode = 0440 },
.size = sizeof(struct pyra_profile_buttons),
- .read = pyra_sysfs_read_profile5_buttons
-};
-
-static struct bin_attribute pyra_settings_attr = {
+ .read = pyra_sysfs_read_profilex_buttons,
+ .private = &profile_numbers[4]
+ },
+ {
.attr = { .name = "settings", .mode = 0660 },
.size = sizeof(struct pyra_settings),
.read = pyra_sysfs_read_settings,
.write = pyra_sysfs_write_settings
+ },
+ __ATTR_NULL
};
-static int pyra_create_sysfs_attributes(struct usb_interface *intf)
-{
- int retval;
-
- retval = sysfs_create_group(&intf->dev.kobj, &pyra_attribute_group);
- if (retval)
- goto exit_1;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile_settings_attr);
- if (retval)
- goto exit_2;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile1_settings_attr);
- if (retval)
- goto exit_3;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile2_settings_attr);
- if (retval)
- goto exit_4;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile3_settings_attr);
- if (retval)
- goto exit_5;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile4_settings_attr);
- if (retval)
- goto exit_6;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile5_settings_attr);
- if (retval)
- goto exit_7;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile_buttons_attr);
- if (retval)
- goto exit_8;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile1_buttons_attr);
- if (retval)
- goto exit_9;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile2_buttons_attr);
- if (retval)
- goto exit_10;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile3_buttons_attr);
- if (retval)
- goto exit_11;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile4_buttons_attr);
- if (retval)
- goto exit_12;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_profile5_buttons_attr);
- if (retval)
- goto exit_13;
-
- retval = sysfs_create_bin_file(&intf->dev.kobj,
- &pyra_settings_attr);
- if (retval)
- goto exit_14;
-
- return 0;
-
-exit_14:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
-exit_13:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
-exit_12:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
-exit_11:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
-exit_10:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
-exit_9:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
-exit_8:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
-exit_7:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
-exit_6:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
-exit_5:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
-exit_4:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
-exit_3:
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
-exit_2:
- sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
-exit_1:
- return retval;
-}
-
-static void pyra_remove_sysfs_attributes(struct usb_interface *intf)
-{
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_buttons_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile5_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile4_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile3_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile2_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile1_settings_attr);
- sysfs_remove_bin_file(&intf->dev.kobj, &pyra_profile_settings_attr);
- sysfs_remove_group(&intf->dev.kobj, &pyra_attribute_group);
-}
-
static int pyra_init_pyra_device_struct(struct usb_device *usb_dev,
struct pyra_device *pyra)
{
- struct pyra_info *info;
+ struct pyra_info info;
int retval, i;
mutex_init(&pyra->pyra_lock);
- info = kmalloc(sizeof(struct pyra_info), GFP_KERNEL);
- if (!info)
- return -ENOMEM;
- retval = pyra_get_info(usb_dev, info);
- if (retval) {
- kfree(info);
+ retval = pyra_get_info(usb_dev, &info);
+ if (retval)
return retval;
- }
- pyra->firmware_version = info->firmware_version;
- kfree(info);
+
+ pyra->firmware_version = info.firmware_version;
retval = pyra_get_settings(usb_dev, &pyra->settings);
if (retval)
@@ -770,31 +495,25 @@ static int pyra_init_specials(struct hid_device *hdev)
pyra = kzalloc(sizeof(*pyra), GFP_KERNEL);
if (!pyra) {
- dev_err(&hdev->dev, "can't alloc device descriptor\n");
+ hid_err(hdev, "can't alloc device descriptor\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, pyra);
retval = pyra_init_pyra_device_struct(usb_dev, pyra);
if (retval) {
- dev_err(&hdev->dev,
- "couldn't init struct pyra_device\n");
+ hid_err(hdev, "couldn't init struct pyra_device\n");
goto exit_free;
}
- retval = roccat_connect(hdev);
+ retval = roccat_connect(pyra_class, hdev,
+ sizeof(struct pyra_roccat_report));
if (retval < 0) {
- dev_err(&hdev->dev, "couldn't init char dev\n");
+ hid_err(hdev, "couldn't init char dev\n");
} else {
pyra->chrdev_minor = retval;
pyra->roccat_claimed = 1;
}
-
- retval = pyra_create_sysfs_attributes(intf);
- if (retval) {
- dev_err(&hdev->dev, "cannot create sysfs files\n");
- goto exit_free;
- }
} else {
hid_set_drvdata(hdev, NULL);
}
@@ -812,7 +531,6 @@ static void pyra_remove_specials(struct hid_device *hdev)
if (intf->cur_altsetting->desc.bInterfaceProtocol
== USB_INTERFACE_PROTOCOL_MOUSE) {
- pyra_remove_sysfs_attributes(intf);
pyra = hid_get_drvdata(hdev);
if (pyra->roccat_claimed)
roccat_disconnect(pyra->chrdev_minor);
@@ -826,19 +544,19 @@ static int pyra_probe(struct hid_device *hdev, const struct hid_device_id *id)
retval = hid_parse(hdev);
if (retval) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto exit;
}
retval = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (retval) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto exit;
}
retval = pyra_init_specials(hdev);
if (retval) {
- dev_err(&hdev->dev, "couldn't install mouse\n");
+ hid_err(hdev, "couldn't install mouse\n");
goto exit_stop;
}
return 0;
@@ -893,8 +611,7 @@ static void pyra_report_to_chrdev(struct pyra_device const *pyra,
roccat_report.value = button_event->data1;
roccat_report.key = 0;
roccat_report_event(pyra->chrdev_minor,
- (uint8_t const *)&roccat_report,
- sizeof(struct pyra_roccat_report));
+ (uint8_t const *)&roccat_report);
break;
case PYRA_MOUSE_EVENT_BUTTON_TYPE_MACRO:
case PYRA_MOUSE_EVENT_BUTTON_TYPE_SHORTCUT:
@@ -908,8 +625,7 @@ static void pyra_report_to_chrdev(struct pyra_device const *pyra,
*/
roccat_report.value = pyra->actual_profile + 1;
roccat_report_event(pyra->chrdev_minor,
- (uint8_t const *)&roccat_report,
- sizeof(struct pyra_roccat_report));
+ (uint8_t const *)&roccat_report);
}
break;
}
@@ -952,12 +668,25 @@ static struct hid_driver pyra_driver = {
static int __init pyra_init(void)
{
- return hid_register_driver(&pyra_driver);
+ int retval;
+
+ /* class name has to be same as driver name */
+ pyra_class = class_create(THIS_MODULE, "pyra");
+ if (IS_ERR(pyra_class))
+ return PTR_ERR(pyra_class);
+ pyra_class->dev_attrs = pyra_attributes;
+ pyra_class->dev_bin_attrs = pyra_bin_attributes;
+
+ retval = hid_register_driver(&pyra_driver);
+ if (retval)
+ class_destroy(pyra_class);
+ return retval;
}
static void __exit pyra_exit(void)
{
hid_unregister_driver(&pyra_driver);
+ class_destroy(pyra_class);
}
module_init(pyra_init);
diff --git a/drivers/hid/hid-roccat-pyra.h b/drivers/hid/hid-roccat-pyra.h
index 22f80a8f26f9..14cbbe1621e0 100644
--- a/drivers/hid/hid-roccat-pyra.h
+++ b/drivers/hid/hid-roccat-pyra.h
@@ -14,14 +14,11 @@
#include <linux/types.h>
-#pragma pack(push)
-#pragma pack(1)
-
struct pyra_b {
uint8_t command; /* PYRA_COMMAND_B */
uint8_t size; /* always 3 */
uint8_t unknown; /* 1 */
-};
+} __attribute__ ((__packed__));
struct pyra_control {
uint8_t command; /* PYRA_COMMAND_CONTROL */
@@ -31,7 +28,7 @@ struct pyra_control {
*/
uint8_t value; /* Range 0-4 */
uint8_t request;
-};
+} __attribute__ ((__packed__));
enum pyra_control_requests {
PYRA_CONTROL_REQUEST_STATUS = 0x00,
@@ -43,7 +40,7 @@ struct pyra_settings {
uint8_t command; /* PYRA_COMMAND_SETTINGS */
uint8_t size; /* always 3 */
uint8_t startup_profile; /* Range 0-4! */
-};
+} __attribute__ ((__packed__));
struct pyra_profile_settings {
uint8_t command; /* PYRA_COMMAND_PROFILE_SETTINGS */
@@ -58,7 +55,7 @@ struct pyra_profile_settings {
uint8_t light_effect;
uint8_t handedness;
uint16_t checksum; /* byte sum */
-};
+} __attribute__ ((__packed__));
struct pyra_profile_buttons {
uint8_t command; /* PYRA_COMMAND_PROFILE_BUTTONS */
@@ -66,7 +63,7 @@ struct pyra_profile_buttons {
uint8_t number; /* Range 0-4 */
uint8_t buttons[14];
uint16_t checksum; /* byte sum */
-};
+} __attribute__ ((__packed__));
struct pyra_info {
uint8_t command; /* PYRA_COMMAND_INFO */
@@ -75,7 +72,7 @@ struct pyra_info {
uint8_t unknown1; /* always 0 */
uint8_t unknown2; /* always 1 */
uint8_t unknown3; /* always 0 */
-};
+} __attribute__ ((__packed__));
enum pyra_commands {
PYRA_COMMAND_CONTROL = 0x4,
@@ -107,13 +104,13 @@ struct pyra_mouse_event_button {
uint8_t type;
uint8_t data1;
uint8_t data2;
-};
+} __attribute__ ((__packed__));
struct pyra_mouse_event_audio {
uint8_t report_number; /* always 2 */
uint8_t type;
uint8_t unused; /* always 0 */
-};
+} __attribute__ ((__packed__));
/* hid audio controls */
enum pyra_mouse_event_audio_types {
@@ -167,9 +164,7 @@ struct pyra_roccat_report {
uint8_t type;
uint8_t value;
uint8_t key;
-};
-
-#pragma pack(pop)
+} __attribute__ ((__packed__));
struct pyra_device {
int actual_profile;
diff --git a/drivers/hid/hid-roccat.c b/drivers/hid/hid-roccat.c
index 5a6879e235ac..5666e7587b18 100644
--- a/drivers/hid/hid-roccat.c
+++ b/drivers/hid/hid-roccat.c
@@ -21,11 +21,12 @@
* It is inspired by hidraw, but uses only one circular buffer for all readers.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/cdev.h>
#include <linux/poll.h>
#include <linux/sched.h>
-
-#include "hid-roccat.h"
+#include <linux/hid-roccat.h>
#define ROCCAT_FIRST_MINOR 0
#define ROCCAT_MAX_DEVICES 8
@@ -35,11 +36,11 @@
struct roccat_report {
uint8_t *value;
- int len;
};
struct roccat_device {
unsigned int minor;
+ int report_size;
int open;
int exist;
wait_queue_head_t wait;
@@ -65,7 +66,6 @@ struct roccat_reader {
};
static int roccat_major;
-static struct class *roccat_class;
static struct cdev roccat_cdev;
static struct roccat_device *devices[ROCCAT_MAX_DEVICES];
@@ -122,7 +122,7 @@ static ssize_t roccat_read(struct file *file, char __user *buffer,
* If report is larger than requested amount of data, rest of report
* is lost!
*/
- len = report->len > count ? count : report->len;
+ len = device->report_size > count ? count : device->report_size;
if (copy_to_user(buffer, report->value, len)) {
retval = -EFAULT;
@@ -165,27 +165,22 @@ static int roccat_open(struct inode *inode, struct file *file)
mutex_lock(&device->readers_lock);
if (!device) {
- printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
- minor);
+ pr_emerg("roccat device with minor %d doesn't exist\n", minor);
error = -ENODEV;
goto exit_err;
}
if (!device->open++) {
/* power on device on adding first reader */
- if (device->hid->ll_driver->power) {
- error = device->hid->ll_driver->power(device->hid,
- PM_HINT_FULLON);
- if (error < 0) {
- --device->open;
- goto exit_err;
- }
+ error = hid_hw_power(device->hid, PM_HINT_FULLON);
+ if (error < 0) {
+ --device->open;
+ goto exit_err;
}
- error = device->hid->ll_driver->open(device->hid);
+
+ error = hid_hw_open(device->hid);
if (error < 0) {
- if (device->hid->ll_driver->power)
- device->hid->ll_driver->power(device->hid,
- PM_HINT_NORMAL);
+ hid_hw_power(device->hid, PM_HINT_NORMAL);
--device->open;
goto exit_err;
}
@@ -218,8 +213,7 @@ static int roccat_release(struct inode *inode, struct file *file)
device = devices[minor];
if (!device) {
mutex_unlock(&devices_lock);
- printk(KERN_EMERG "roccat device with minor %d doesn't exist\n",
- minor);
+ pr_emerg("roccat device with minor %d doesn't exist\n", minor);
return -ENODEV;
}
@@ -231,10 +225,8 @@ static int roccat_release(struct inode *inode, struct file *file)
if (!--device->open) {
/* removing last reader */
if (device->exist) {
- if (device->hid->ll_driver->power)
- device->hid->ll_driver->power(device->hid,
- PM_HINT_NORMAL);
- device->hid->ll_driver->close(device->hid);
+ hid_hw_power(device->hid, PM_HINT_NORMAL);
+ hid_hw_close(device->hid);
} else {
kfree(device);
}
@@ -255,26 +247,25 @@ static int roccat_release(struct inode *inode, struct file *file)
*
* This is called from interrupt handler.
*/
-int roccat_report_event(int minor, u8 const *data, int len)
+int roccat_report_event(int minor, u8 const *data)
{
struct roccat_device *device;
struct roccat_reader *reader;
struct roccat_report *report;
uint8_t *new_value;
- new_value = kmemdup(data, len, GFP_ATOMIC);
+ device = devices[minor];
+
+ new_value = kmemdup(data, device->report_size, GFP_ATOMIC);
if (!new_value)
return -ENOMEM;
- device = devices[minor];
-
report = &device->cbuf[device->cbuf_end];
/* passing NULL is safe */
kfree(report->value);
report->value = new_value;
- report->len = len;
device->cbuf_end = (device->cbuf_end + 1) % ROCCAT_CBUF_SIZE;
list_for_each_entry(reader, &device->readers, node) {
@@ -295,12 +286,14 @@ EXPORT_SYMBOL_GPL(roccat_report_event);
/*
* roccat_connect() - create a char device for special event output
+ * @class: the class thats used to create the device. Meant to hold device
+ * specific sysfs attributes.
* @hid: the hid device the char device should be connected to.
*
* Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
* success, a negative error code on failure.
*/
-int roccat_connect(struct hid_device *hid)
+int roccat_connect(struct class *klass, struct hid_device *hid, int report_size)
{
unsigned int minor;
struct roccat_device *device;
@@ -326,7 +319,7 @@ int roccat_connect(struct hid_device *hid)
return -EINVAL;
}
- device->dev = device_create(roccat_class, &hid->dev,
+ device->dev = device_create(klass, &hid->dev,
MKDEV(roccat_major, minor), NULL,
"%s%s%d", "roccat", hid->driver->name, minor);
@@ -348,6 +341,7 @@ int roccat_connect(struct hid_device *hid)
device->hid = hid;
device->exist = 1;
device->cbuf_end = 0;
+ device->report_size = report_size;
return minor;
}
@@ -362,15 +356,18 @@ void roccat_disconnect(int minor)
mutex_lock(&devices_lock);
device = devices[minor];
- devices[minor] = NULL;
mutex_unlock(&devices_lock);
device->exist = 0; /* TODO exist maybe not needed */
- device_destroy(roccat_class, MKDEV(roccat_major, minor));
+ device_destroy(device->dev->class, MKDEV(roccat_major, minor));
+ mutex_lock(&devices_lock);
+ devices[minor] = NULL;
+ mutex_unlock(&devices_lock);
+
if (device->open) {
- device->hid->ll_driver->close(device->hid);
+ hid_hw_close(device->hid);
wake_up_interruptible(&device->wait);
} else {
kfree(device);
@@ -378,6 +375,34 @@ void roccat_disconnect(int minor)
}
EXPORT_SYMBOL_GPL(roccat_disconnect);
+static long roccat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ struct inode *inode = file->f_path.dentry->d_inode;
+ struct roccat_device *device;
+ unsigned int minor = iminor(inode);
+ long retval = 0;
+
+ mutex_lock(&devices_lock);
+
+ device = devices[minor];
+ if (!device) {
+ retval = -ENODEV;
+ goto out;
+ }
+
+ switch (cmd) {
+ case ROCCATIOCGREPSIZE:
+ if (put_user(device->report_size, (int __user *)arg))
+ retval = -EFAULT;
+ break;
+ default:
+ retval = -ENOTTY;
+ }
+out:
+ mutex_unlock(&devices_lock);
+ return retval;
+}
+
static const struct file_operations roccat_ops = {
.owner = THIS_MODULE,
.read = roccat_read,
@@ -385,6 +410,7 @@ static const struct file_operations roccat_ops = {
.open = roccat_open,
.release = roccat_release,
.llseek = noop_llseek,
+ .unlocked_ioctl = roccat_ioctl,
};
static int __init roccat_init(void)
@@ -398,14 +424,7 @@ static int __init roccat_init(void)
roccat_major = MAJOR(dev_id);
if (retval < 0) {
- printk(KERN_WARNING "roccat: can't get major number\n");
- return retval;
- }
-
- roccat_class = class_create(THIS_MODULE, "roccat");
- if (IS_ERR(roccat_class)) {
- retval = PTR_ERR(roccat_class);
- unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
+ pr_warn("can't get major number\n");
return retval;
}
@@ -420,7 +439,6 @@ static void __exit roccat_exit(void)
dev_t dev_id = MKDEV(roccat_major, 0);
cdev_del(&roccat_cdev);
- class_destroy(roccat_class);
unregister_chrdev_region(dev_id, ROCCAT_MAX_DEVICES);
}
diff --git a/drivers/hid/hid-roccat.h b/drivers/hid/hid-roccat.h
deleted file mode 100644
index 09e864e9f79d..000000000000
--- a/drivers/hid/hid-roccat.h
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifndef __HID_ROCCAT_H
-#define __HID_ROCCAT_H
-
-/*
- * Copyright (c) 2010 Stefan Achatz <erazor_de@users.sourceforge.net>
- */
-
-/*
- * 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/hid.h>
-#include <linux/types.h>
-
-#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);
-#else
-static inline int roccat_connect(struct hid_device *hid) { return -1; }
-static inline void roccat_disconnect(int minor) {}
-static inline int roccat_report_event(int minor, u8 const *data, int len)
-{
- return 0;
-}
-#endif
-
-#endif
diff --git a/drivers/hid/hid-samsung.c b/drivers/hid/hid-samsung.c
index 35894444e000..3c1fd8af5e0c 100644
--- a/drivers/hid/hid-samsung.c
+++ b/drivers/hid/hid-samsung.c
@@ -57,8 +57,8 @@
static inline void samsung_irda_dev_trace(struct hid_device *hdev,
unsigned int rsize)
{
- dev_info(&hdev->dev, "fixing up Samsung IrDA %d byte report "
- "descriptor\n", rsize);
+ hid_info(hdev, "fixing up Samsung IrDA %d byte report descriptor\n",
+ rsize);
}
static __u8 *samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc,
@@ -160,7 +160,7 @@ static int samsung_probe(struct hid_device *hdev,
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
@@ -174,7 +174,7 @@ static int samsung_probe(struct hid_device *hdev,
ret = hid_hw_start(hdev, cmask);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-sjoy.c b/drivers/hid/hid-sjoy.c
index e10a7687ebf2..16f7cafc9695 100644
--- a/drivers/hid/hid-sjoy.c
+++ b/drivers/hid/hid-sjoy.c
@@ -74,26 +74,25 @@ static int sjoyff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output reports found\n");
+ hid_err(hid, "no output reports found\n");
return -ENODEV;
}
report_ptr = report_ptr->next;
if (report_ptr == report_list) {
- dev_err(&hid->dev, "required output report is "
- "missing\n");
+ hid_err(hid, "required output report is missing\n");
return -ENODEV;
}
report = list_entry(report_ptr, struct hid_report, list);
if (report->maxfield < 1) {
- dev_err(&hid->dev, "no fields in the report\n");
+ hid_err(hid, "no fields in the report\n");
return -ENODEV;
}
if (report->field[0]->report_count < 3) {
- dev_err(&hid->dev, "not enough values in the field\n");
+ hid_err(hid, "not enough values in the field\n");
return -ENODEV;
}
@@ -117,8 +116,7 @@ static int sjoyff_init(struct hid_device *hid)
sjoyff->report->field[0]->value[2] = 0x00;
usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
- dev_info(&hid->dev,
- "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
+ hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n");
return 0;
}
@@ -135,13 +133,13 @@ static int sjoy_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
diff --git a/drivers/hid/hid-sony.c b/drivers/hid/hid-sony.c
index 677bb3da10e8..93819a08121a 100644
--- a/drivers/hid/hid-sony.c
+++ b/drivers/hid/hid-sony.c
@@ -40,13 +40,22 @@ static __u8 *sony_report_fixup(struct hid_device *hdev, __u8 *rdesc,
if ((sc->quirks & VAIO_RDESC_CONSTANT) &&
*rsize >= 56 && rdesc[54] == 0x81 && rdesc[55] == 0x07) {
- dev_info(&hdev->dev, "Fixing up Sony Vaio VGX report "
- "descriptor\n");
+ hid_info(hdev, "Fixing up Sony Vaio VGX report descriptor\n");
rdesc[55] = 0x06;
}
return rdesc;
}
+/*
+ * The Sony Sixaxis does not handle HID Output Reports on the Interrupt EP
+ * like it should according to usbhid/hid-core.c::usbhid_output_raw_report()
+ * so we need to override that forcing HID Output Reports on the Control EP.
+ *
+ * There is also another issue about HID Output Reports via USB, the Sixaxis
+ * does not want the report_id as part of the data packet, so we have to
+ * discard buf[0] when sending the actual control message, even for numbered
+ * reports, humpf!
+ */
static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
size_t count, unsigned char report_type)
{
@@ -56,6 +65,12 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
int report_id = buf[0];
int ret;
+ if (report_type == HID_OUTPUT_REPORT) {
+ /* Don't send the Report ID */
+ buf++;
+ count--;
+ }
+
ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_REPORT,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
@@ -63,6 +78,10 @@ static int sixaxis_usb_output_raw_report(struct hid_device *hid, __u8 *buf,
interface->desc.bInterfaceNumber, buf, count,
USB_CTRL_SET_TIMEOUT);
+ /* Count also the Report ID, in case of an Output report. */
+ if (ret > 0 && report_type == HID_OUTPUT_REPORT)
+ ret++;
+
return ret;
}
@@ -89,7 +108,7 @@ static int sixaxis_set_operational_usb(struct hid_device *hdev)
(3 << 8) | 0xf2, ifnum, buf, 17,
USB_CTRL_GET_TIMEOUT);
if (ret < 0)
- dev_err(&hdev->dev, "can't set operational mode\n");
+ hid_err(hdev, "can't set operational mode\n");
kfree(buf);
@@ -110,7 +129,7 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
sc = kzalloc(sizeof(*sc), GFP_KERNEL);
if (sc == NULL) {
- dev_err(&hdev->dev, "can't alloc sony descriptor\n");
+ hid_err(hdev, "can't alloc sony descriptor\n");
return -ENOMEM;
}
@@ -119,14 +138,14 @@ static int sony_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT |
HID_CONNECT_HIDDEV_FORCE);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hid-stantum.c b/drivers/hid/hid-stantum.c
index 3171be28c3d5..b2be1d11916b 100644
--- a/drivers/hid/hid-stantum.c
+++ b/drivers/hid/hid-stantum.c
@@ -222,7 +222,7 @@ static int stantum_probe(struct hid_device *hdev,
sd = kmalloc(sizeof(struct stantum_data), GFP_KERNEL);
if (!sd) {
- dev_err(&hdev->dev, "cannot allocate Stantum data\n");
+ hid_err(hdev, "cannot allocate Stantum data\n");
return -ENOMEM;
}
sd->valid = false;
diff --git a/drivers/hid/hid-sunplus.c b/drivers/hid/hid-sunplus.c
index 164ed568f6cf..d484a0043dd4 100644
--- a/drivers/hid/hid-sunplus.c
+++ b/drivers/hid/hid-sunplus.c
@@ -27,8 +27,7 @@ static __u8 *sp_report_fixup(struct hid_device *hdev, __u8 *rdesc,
{
if (*rsize >= 107 && rdesc[104] == 0x26 && rdesc[105] == 0x80 &&
rdesc[106] == 0x03) {
- dev_info(&hdev->dev, "fixing up Sunplus Wireless Desktop "
- "report descriptor\n");
+ hid_info(hdev, "fixing up Sunplus Wireless Desktop report descriptor\n");
rdesc[105] = rdesc[110] = 0x03;
rdesc[106] = rdesc[111] = 0x21;
}
diff --git a/drivers/hid/hid-tmff.c b/drivers/hid/hid-tmff.c
index 25be4e1461bd..575862b0688e 100644
--- a/drivers/hid/hid-tmff.c
+++ b/drivers/hid/hid-tmff.c
@@ -151,28 +151,23 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
switch (field->usage[0].hid) {
case THRUSTMASTER_USAGE_FF:
if (field->report_count < 2) {
- dev_warn(&hid->dev, "ignoring FF field "
- "with report_count < 2\n");
+ hid_warn(hid, "ignoring FF field with report_count < 2\n");
continue;
}
if (field->logical_maximum ==
field->logical_minimum) {
- dev_warn(&hid->dev, "ignoring FF field "
- "with logical_maximum "
- "== logical_minimum\n");
+ hid_warn(hid, "ignoring FF field with logical_maximum == logical_minimum\n");
continue;
}
if (tmff->report && tmff->report != report) {
- dev_warn(&hid->dev, "ignoring FF field "
- "in other report\n");
+ hid_warn(hid, "ignoring FF field in other report\n");
continue;
}
if (tmff->ff_field && tmff->ff_field != field) {
- dev_warn(&hid->dev, "ignoring "
- "duplicate FF field\n");
+ hid_warn(hid, "ignoring duplicate FF field\n");
continue;
}
@@ -185,16 +180,15 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
break;
default:
- dev_warn(&hid->dev, "ignoring unknown output "
- "usage %08x\n",
- field->usage[0].hid);
+ hid_warn(hid, "ignoring unknown output usage %08x\n",
+ field->usage[0].hid);
continue;
}
}
}
if (!tmff->report) {
- dev_err(&hid->dev, "can't find FF field in output reports\n");
+ hid_err(hid, "can't find FF field in output reports\n");
error = -ENODEV;
goto fail;
}
@@ -203,8 +197,7 @@ static int tmff_init(struct hid_device *hid, const signed short *ff_bits)
if (error)
goto fail;
- dev_info(&hid->dev, "force feedback for ThrustMaster devices by Zinx "
- "Verituse <zinx@epicsol.org>");
+ hid_info(hid, "force feedback for ThrustMaster devices by Zinx Verituse <zinx@epicsol.org>\n");
return 0;
fail:
@@ -224,13 +217,13 @@ static int tm_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
diff --git a/drivers/hid/hid-topseed.c b/drivers/hid/hid-topseed.c
index 956ed9ac19d4..613ff7b1d746 100644
--- a/drivers/hid/hid-topseed.c
+++ b/drivers/hid/hid-topseed.c
@@ -66,6 +66,7 @@ static const struct hid_device_id ts_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_BTC, USB_DEVICE_ID_BTC_EMPREX_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED2, USB_DEVICE_ID_TOPSEED2_RF_COMBO) },
+ { HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ }
};
MODULE_DEVICE_TABLE(hid, ts_devices);
diff --git a/drivers/hid/hid-wacom.c b/drivers/hid/hid-wacom.c
index 724f46ed612f..06888323828c 100644
--- a/drivers/hid/hid-wacom.c
+++ b/drivers/hid/hid-wacom.c
@@ -18,6 +18,8 @@
* any later version.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
@@ -141,8 +143,8 @@ static void wacom_poke(struct hid_device *hdev, u8 speed)
* Note that if the raw queries fail, it's not a hard failure and it
* is safe to continue
*/
- dev_warn(&hdev->dev, "failed to poke device, command %d, err %d\n",
- rep_data[0], ret);
+ hid_warn(hdev, "failed to poke device, command %d, err %d\n",
+ rep_data[0], ret);
return;
}
@@ -172,7 +174,7 @@ static ssize_t wacom_store_speed(struct device *dev,
return -EINVAL;
}
-static DEVICE_ATTR(speed, S_IRUGO | S_IWUGO,
+static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
wacom_show_speed, wacom_store_speed);
static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
@@ -312,7 +314,7 @@ static int wacom_probe(struct hid_device *hdev,
wdata = kzalloc(sizeof(*wdata), GFP_KERNEL);
if (wdata == NULL) {
- dev_err(&hdev->dev, "can't alloc wacom descriptor\n");
+ hid_err(hdev, "can't alloc wacom descriptor\n");
return -ENOMEM;
}
@@ -321,20 +323,20 @@ static int wacom_probe(struct hid_device *hdev,
/* Parse the HID report now */
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
ret = device_create_file(&hdev->dev, &dev_attr_speed);
if (ret)
- dev_warn(&hdev->dev,
- "can't create sysfs speed attribute err: %d\n", ret);
+ hid_warn(hdev,
+ "can't create sysfs speed attribute err: %d\n", ret);
/* Set Wacom mode 2 with high reporting speed */
wacom_poke(hdev, 1);
@@ -349,8 +351,8 @@ static int wacom_probe(struct hid_device *hdev,
ret = power_supply_register(&hdev->dev, &wdata->battery);
if (ret) {
- dev_warn(&hdev->dev,
- "can't create sysfs battery attribute, err: %d\n", ret);
+ hid_warn(hdev, "can't create sysfs battery attribute, err: %d\n",
+ ret);
/*
* battery attribute is not critical for the tablet, but if it
* failed then there is no need to create ac attribute
@@ -367,8 +369,8 @@ static int wacom_probe(struct hid_device *hdev,
ret = power_supply_register(&hdev->dev, &wdata->ac);
if (ret) {
- dev_warn(&hdev->dev,
- "can't create ac battery attribute, err: %d\n", ret);
+ hid_warn(hdev,
+ "can't create ac battery attribute, err: %d\n", ret);
/*
* ac attribute is not critical for the tablet, but if it
* failed then we don't want to battery attribute to exist
@@ -454,7 +456,7 @@ static int __init wacom_init(void)
ret = hid_register_driver(&wacom_driver);
if (ret)
- printk(KERN_ERR "can't register wacom driver\n");
+ pr_err("can't register wacom driver\n");
return ret;
}
diff --git a/drivers/hid/hid-zpff.c b/drivers/hid/hid-zpff.c
index b7acceabba80..f31fab012f2f 100644
--- a/drivers/hid/hid-zpff.c
+++ b/drivers/hid/hid-zpff.c
@@ -75,14 +75,14 @@ static int zpff_init(struct hid_device *hid)
int error;
if (list_empty(report_list)) {
- dev_err(&hid->dev, "no output report found\n");
+ hid_err(hid, "no output report found\n");
return -ENODEV;
}
report = list_entry(report_list->next, struct hid_report, list);
if (report->maxfield < 4) {
- dev_err(&hid->dev, "not enough fields in report\n");
+ hid_err(hid, "not enough fields in report\n");
return -ENODEV;
}
@@ -105,8 +105,7 @@ static int zpff_init(struct hid_device *hid)
zpff->report->field[3]->value[0] = 0x00;
usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
- dev_info(&hid->dev, "force feedback for Zeroplus based devices by "
- "Anssi Hannula <anssi.hannula@gmail.com>\n");
+ hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
}
@@ -123,13 +122,13 @@ static int zp_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT & ~HID_CONNECT_FF);
if (ret) {
- dev_err(&hdev->dev, "hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err;
}
diff --git a/drivers/hid/hid-zydacron.c b/drivers/hid/hid-zydacron.c
index aac1f9273149..e90371508fd2 100644
--- a/drivers/hid/hid-zydacron.c
+++ b/drivers/hid/hid-zydacron.c
@@ -34,9 +34,8 @@ static __u8 *zc_report_fixup(struct hid_device *hdev, __u8 *rdesc,
rdesc[0x96] == 0xbc && rdesc[0x97] == 0xff &&
rdesc[0xca] == 0xbc && rdesc[0xcb] == 0xff &&
rdesc[0xe1] == 0xbc && rdesc[0xe2] == 0xff) {
- dev_info(&hdev->dev,
- "fixing up zydacron remote control report "
- "descriptor\n");
+ hid_info(hdev,
+ "fixing up zydacron remote control report descriptor\n");
rdesc[0x96] = rdesc[0xca] = rdesc[0xe1] = 0x0c;
rdesc[0x97] = rdesc[0xcb] = rdesc[0xe2] = 0x00;
}
@@ -172,7 +171,7 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
zc = kzalloc(sizeof(*zc), GFP_KERNEL);
if (zc == NULL) {
- dev_err(&hdev->dev, "zydacron: can't alloc descriptor\n");
+ hid_err(hdev, "can't alloc descriptor\n");
return -ENOMEM;
}
@@ -180,13 +179,13 @@ static int zc_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_parse(hdev);
if (ret) {
- dev_err(&hdev->dev, "zydacron: parse failed\n");
+ hid_err(hdev, "parse failed\n");
goto err_free;
}
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret) {
- dev_err(&hdev->dev, "zydacron: hw start failed\n");
+ hid_err(hdev, "hw start failed\n");
goto err_free;
}
diff --git a/drivers/hid/hidraw.c b/drivers/hid/hidraw.c
index e1f07483691f..54409cba018c 100644
--- a/drivers/hid/hidraw.c
+++ b/drivers/hid/hidraw.c
@@ -19,6 +19,8 @@
* 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/fs.h>
#include <linux/module.h>
#include <linux/errno.h>
@@ -89,7 +91,7 @@ static ssize_t hidraw_read(struct file *file, char __user *buffer, size_t count,
ret = -EFAULT;
goto out;
}
- ret += len;
+ ret = len;
kfree(list->buffer[list->tail].value);
list->tail = (list->tail + 1) & (HIDRAW_BUFFER_SIZE - 1);
@@ -100,15 +102,14 @@ out:
}
/* the first byte is expected to be a report number */
-static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+/* This function is to be called with the minors_lock mutex held */
+static ssize_t hidraw_send_report(struct file *file, const char __user *buffer, size_t count, unsigned char report_type)
{
unsigned int minor = iminor(file->f_path.dentry->d_inode);
struct hid_device *dev;
__u8 *buf;
int ret = 0;
- mutex_lock(&minors_lock);
-
if (!hidraw_table[minor]) {
ret = -ENODEV;
goto out;
@@ -122,6 +123,70 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
}
if (count > HID_MAX_BUFFER_SIZE) {
+ hid_warn(dev, "pid %d passed too large report\n",
+ task_pid_nr(current));
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (count < 2) {
+ hid_warn(dev, "pid %d passed too short report\n",
+ task_pid_nr(current));
+ ret = -EINVAL;
+ goto out;
+ }
+
+ buf = kmalloc(count * sizeof(__u8), GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ if (copy_from_user(buf, buffer, count)) {
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ ret = dev->hid_output_raw_report(dev, buf, count, report_type);
+out_free:
+ kfree(buf);
+out:
+ return ret;
+}
+
+/* the first byte is expected to be a report number */
+static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t count, loff_t *ppos)
+{
+ ssize_t ret;
+ mutex_lock(&minors_lock);
+ ret = hidraw_send_report(file, buffer, count, HID_OUTPUT_REPORT);
+ mutex_unlock(&minors_lock);
+ return ret;
+}
+
+
+/* This function performs a Get_Report transfer over the control endpoint
+ per section 7.2.1 of the HID specification, version 1.1. The first byte
+ of buffer is the report number to request, or 0x0 if the defice does not
+ use numbered reports. The report_type parameter can be HID_FEATURE_REPORT
+ or HID_INPUT_REPORT. This function is to be called with the minors_lock
+ mutex held. */
+static ssize_t hidraw_get_report(struct file *file, char __user *buffer, size_t count, unsigned char report_type)
+{
+ unsigned int minor = iminor(file->f_path.dentry->d_inode);
+ struct hid_device *dev;
+ __u8 *buf;
+ int ret = 0, len;
+ unsigned char report_number;
+
+ dev = hidraw_table[minor]->hid;
+
+ if (!dev->hid_get_raw_report) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ if (count > HID_MAX_BUFFER_SIZE) {
printk(KERN_WARNING "hidraw: pid %d passed too large report\n",
task_pid_nr(current));
ret = -EINVAL;
@@ -141,16 +206,30 @@ static ssize_t hidraw_write(struct file *file, const char __user *buffer, size_t
goto out;
}
- if (copy_from_user(buf, buffer, count)) {
+ /* Read the first byte from the user. This is the report number,
+ which is passed to dev->hid_get_raw_report(). */
+ if (copy_from_user(&report_number, buffer, 1)) {
+ ret = -EFAULT;
+ goto out_free;
+ }
+
+ ret = dev->hid_get_raw_report(dev, report_number, buf, count, report_type);
+
+ if (ret < 0)
+ goto out_free;
+
+ len = (ret < count) ? ret : count;
+
+ if (copy_to_user(buffer, buf, len)) {
ret = -EFAULT;
goto out_free;
}
- ret = dev->hid_output_raw_report(dev, buf, count, HID_OUTPUT_REPORT);
+ ret = len;
+
out_free:
kfree(buf);
out:
- mutex_unlock(&minors_lock);
return ret;
}
@@ -192,15 +271,13 @@ static int hidraw_open(struct inode *inode, struct file *file)
dev = hidraw_table[minor];
if (!dev->open++) {
- if (dev->hid->ll_driver->power) {
- err = dev->hid->ll_driver->power(dev->hid, PM_HINT_FULLON);
- if (err < 0)
- goto out_unlock;
- }
- err = dev->hid->ll_driver->open(dev->hid);
+ err = hid_hw_power(dev->hid, PM_HINT_FULLON);
+ if (err < 0)
+ goto out_unlock;
+
+ err = hid_hw_open(dev->hid);
if (err < 0) {
- if (dev->hid->ll_driver->power)
- dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
+ hid_hw_power(dev->hid, PM_HINT_NORMAL);
dev->open--;
}
}
@@ -229,9 +306,8 @@ static int hidraw_release(struct inode * inode, struct file * file)
dev = hidraw_table[minor];
if (!--dev->open) {
if (list->hidraw->exist) {
- if (dev->hid->ll_driver->power)
- dev->hid->ll_driver->power(dev->hid, PM_HINT_NORMAL);
- dev->hid->ll_driver->close(dev->hid);
+ hid_hw_power(dev->hid, PM_HINT_NORMAL);
+ hid_hw_close(dev->hid);
} else {
kfree(list->hidraw);
}
@@ -296,7 +372,24 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
default:
{
struct hid_device *hid = dev->hid;
- if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) {
+ if (_IOC_TYPE(cmd) != 'H') {
+ ret = -EINVAL;
+ break;
+ }
+
+ if (_IOC_NR(cmd) == _IOC_NR(HIDIOCSFEATURE(0))) {
+ int len = _IOC_SIZE(cmd);
+ ret = hidraw_send_report(file, user_arg, len, HID_FEATURE_REPORT);
+ break;
+ }
+ if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGFEATURE(0))) {
+ int len = _IOC_SIZE(cmd);
+ ret = hidraw_get_report(file, user_arg, len, HID_FEATURE_REPORT);
+ break;
+ }
+
+ /* Begin Read-only ioctls. */
+ if (_IOC_DIR(cmd) != _IOC_READ) {
ret = -EINVAL;
break;
}
@@ -328,7 +421,7 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
-EFAULT : len;
break;
}
- }
+ }
ret = -ENOTTY;
}
@@ -345,6 +438,9 @@ static const struct file_operations hidraw_ops = {
.open = hidraw_open,
.release = hidraw_release,
.unlocked_ioctl = hidraw_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = hidraw_ioctl,
+#endif
.llseek = noop_llseek,
};
@@ -426,14 +522,14 @@ void hidraw_disconnect(struct hid_device *hid)
hidraw->exist = 0;
+ device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
+
mutex_lock(&minors_lock);
hidraw_table[hidraw->minor] = NULL;
mutex_unlock(&minors_lock);
- device_destroy(hidraw_class, MKDEV(hidraw_major, hidraw->minor));
-
if (hidraw->open) {
- hid->ll_driver->close(hid);
+ hid_hw_close(hid);
wake_up_interruptible(&hidraw->wait);
} else {
kfree(hidraw);
@@ -452,7 +548,7 @@ int __init hidraw_init(void)
hidraw_major = MAJOR(dev_id);
if (result < 0) {
- printk(KERN_WARNING "hidraw: can't get major number\n");
+ pr_warn("can't get major number\n");
result = 0;
goto out;
}
diff --git a/drivers/hid/usbhid/Kconfig b/drivers/hid/usbhid/Kconfig
index 4edb3bef94a6..0f20fd17cf06 100644
--- a/drivers/hid/usbhid/Kconfig
+++ b/drivers/hid/usbhid/Kconfig
@@ -45,7 +45,7 @@ config USB_HIDDEV
If unsure, say Y.
menu "USB HID Boot Protocol drivers"
- depends on USB!=n && USB_HID!=y && EMBEDDED
+ depends on USB!=n && USB_HID!=y && EXPERT
config USB_KBD
tristate "USB HIDBP Keyboard (simple Boot) support"
diff --git a/drivers/hid/usbhid/Makefile b/drivers/hid/usbhid/Makefile
index 1329ecb37a1c..db3cf31c6fa1 100644
--- a/drivers/hid/usbhid/Makefile
+++ b/drivers/hid/usbhid/Makefile
@@ -3,15 +3,15 @@
#
# Multipart objects.
-usbhid-objs := hid-core.o hid-quirks.o
+usbhid-y := hid-core.o hid-quirks.o
# Optional parts of multipart objects.
ifeq ($(CONFIG_USB_HIDDEV),y)
- usbhid-objs += hiddev.o
+ usbhid-y += hiddev.o
endif
ifeq ($(CONFIG_HID_PID),y)
- usbhid-objs += hid-pidff.o
+ usbhid-y += hid-pidff.o
endif
obj-$(CONFIG_USB_HID) += usbhid.o
diff --git a/drivers/hid/usbhid/hid-core.c b/drivers/hid/usbhid/hid-core.c
index 5489eab3a6bd..38c261a40c74 100644
--- a/drivers/hid/usbhid/hid-core.c
+++ b/drivers/hid/usbhid/hid-core.c
@@ -67,7 +67,6 @@ MODULE_PARM_DESC(quirks, "Add/modify USB HID quirks by specifying "
* Input submission and I/O error handler.
*/
static DEFINE_MUTEX(hid_open_mut);
-static struct workqueue_struct *resumption_waker;
static void hid_io_error(struct hid_device *hid);
static int hid_submit_out(struct hid_device *hid);
@@ -136,10 +135,10 @@ static void hid_reset(struct work_struct *work)
hid_io_error(hid);
break;
default:
- err_hid("can't reset device, %s-%s/input%d, status %d",
- hid_to_usb_dev(hid)->bus->bus_name,
- hid_to_usb_dev(hid)->devpath,
- usbhid->ifnum, rc);
+ hid_err(hid, "can't reset device, %s-%s/input%d, status %d\n",
+ hid_to_usb_dev(hid)->bus->bus_name,
+ hid_to_usb_dev(hid)->devpath,
+ usbhid->ifnum, rc);
/* FALLTHROUGH */
case -EHOSTUNREACH:
case -ENODEV:
@@ -278,18 +277,18 @@ static void hid_irq_in(struct urb *urb)
hid_io_error(hid);
return;
default: /* error */
- dev_warn(&urb->dev->dev, "input irq status %d "
- "received\n", urb->status);
+ hid_warn(urb->dev, "input irq status %d received\n",
+ urb->status);
}
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status) {
clear_bit(HID_IN_RUNNING, &usbhid->iofl);
if (status != -EPERM) {
- err_hid("can't resubmit intr, %s-%s/input%d, status %d",
- hid_to_usb_dev(hid)->bus->bus_name,
- hid_to_usb_dev(hid)->devpath,
- usbhid->ifnum, status);
+ hid_err(hid, "can't resubmit intr, %s-%s/input%d, status %d\n",
+ hid_to_usb_dev(hid)->bus->bus_name,
+ hid_to_usb_dev(hid)->devpath,
+ usbhid->ifnum, status);
hid_io_error(hid);
}
}
@@ -300,10 +299,19 @@ static int hid_submit_out(struct hid_device *hid)
struct hid_report *report;
char *raw_report;
struct usbhid_device *usbhid = hid->driver_data;
+ int r;
report = usbhid->out[usbhid->outtail].report;
raw_report = usbhid->out[usbhid->outtail].raw_report;
+ r = usb_autopm_get_interface_async(usbhid->intf);
+ if (r < 0)
+ return -1;
+
+ /*
+ * if the device hasn't been woken, we leave the output
+ * to resume()
+ */
if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) {
usbhid->urbout->transfer_buffer_length = ((report->size - 1) >> 3) + 1 + (report->id > 0);
usbhid->urbout->dev = hid_to_usb_dev(hid);
@@ -313,17 +321,11 @@ static int hid_submit_out(struct hid_device *hid)
dbg_hid("submitting out urb\n");
if (usb_submit_urb(usbhid->urbout, GFP_ATOMIC)) {
- err_hid("usb_submit_urb(out) failed");
+ hid_err(hid, "usb_submit_urb(out) failed\n");
+ usb_autopm_put_interface_async(usbhid->intf);
return -1;
}
usbhid->last_out = jiffies;
- } else {
- /*
- * queue work to wake up the device.
- * as the work queue is freezeable, this is safe
- * with respect to STD and STR
- */
- queue_work(resumption_waker, &usbhid->restart_work);
}
return 0;
@@ -334,13 +336,16 @@ static int hid_submit_ctrl(struct hid_device *hid)
struct hid_report *report;
unsigned char dir;
char *raw_report;
- int len;
+ int len, r;
struct usbhid_device *usbhid = hid->driver_data;
report = usbhid->ctrl[usbhid->ctrltail].report;
raw_report = usbhid->ctrl[usbhid->ctrltail].raw_report;
dir = usbhid->ctrl[usbhid->ctrltail].dir;
+ r = usb_autopm_get_interface_async(usbhid->intf);
+ if (r < 0)
+ return -1;
if (!test_bit(HID_REPORTED_IDLE, &usbhid->iofl)) {
len = ((report->size - 1) >> 3) + 1 + (report->id > 0);
if (dir == USB_DIR_OUT) {
@@ -375,17 +380,11 @@ static int hid_submit_ctrl(struct hid_device *hid)
usbhid->cr->wValue, usbhid->cr->wIndex, usbhid->cr->wLength);
if (usb_submit_urb(usbhid->urbctrl, GFP_ATOMIC)) {
- err_hid("usb_submit_urb(ctrl) failed");
+ usb_autopm_put_interface_async(usbhid->intf);
+ hid_err(hid, "usb_submit_urb(ctrl) failed\n");
return -1;
}
usbhid->last_ctrl = jiffies;
- } else {
- /*
- * queue work to wake up the device.
- * as the work queue is freezeable, this is safe
- * with respect to STD and STR
- */
- queue_work(resumption_waker, &usbhid->restart_work);
}
return 0;
@@ -413,8 +412,8 @@ static void hid_irq_out(struct urb *urb)
case -ENOENT:
break;
default: /* error */
- dev_warn(&urb->dev->dev, "output irq status %d "
- "received\n", urb->status);
+ hid_warn(urb->dev, "output irq status %d received\n",
+ urb->status);
}
spin_lock_irqsave(&usbhid->lock, flags);
@@ -435,6 +434,7 @@ static void hid_irq_out(struct urb *urb)
clear_bit(HID_OUT_RUNNING, &usbhid->iofl);
spin_unlock_irqrestore(&usbhid->lock, flags);
+ usb_autopm_put_interface_async(usbhid->intf);
wake_up(&usbhid->wait);
}
@@ -466,8 +466,7 @@ static void hid_ctrl(struct urb *urb)
case -EPIPE: /* report not available */
break;
default: /* error */
- dev_warn(&urb->dev->dev, "ctrl urb status %d "
- "received\n", status);
+ hid_warn(urb->dev, "ctrl urb status %d received\n", status);
}
if (unplug)
@@ -481,11 +480,13 @@ static void hid_ctrl(struct urb *urb)
wake_up(&usbhid->wait);
}
spin_unlock(&usbhid->lock);
+ usb_autopm_put_interface_async(usbhid->intf);
return;
}
clear_bit(HID_CTRL_RUNNING, &usbhid->iofl);
spin_unlock(&usbhid->lock);
+ usb_autopm_put_interface_async(usbhid->intf);
wake_up(&usbhid->wait);
}
@@ -501,13 +502,13 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
if (usbhid->urbout && dir == USB_DIR_OUT && report->type == HID_OUTPUT_REPORT) {
if ((head = (usbhid->outhead + 1) & (HID_OUTPUT_FIFO_SIZE - 1)) == usbhid->outtail) {
- dev_warn(&hid->dev, "output queue full\n");
+ hid_warn(hid, "output queue full\n");
return;
}
usbhid->out[usbhid->outhead].raw_report = kmalloc(len, GFP_ATOMIC);
if (!usbhid->out[usbhid->outhead].raw_report) {
- dev_warn(&hid->dev, "output queueing failed\n");
+ hid_warn(hid, "output queueing failed\n");
return;
}
hid_output_report(report, usbhid->out[usbhid->outhead].raw_report);
@@ -532,14 +533,14 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
}
if ((head = (usbhid->ctrlhead + 1) & (HID_CONTROL_FIFO_SIZE - 1)) == usbhid->ctrltail) {
- dev_warn(&hid->dev, "control queue full\n");
+ hid_warn(hid, "control queue full\n");
return;
}
if (dir == USB_DIR_OUT) {
usbhid->ctrl[usbhid->ctrlhead].raw_report = kmalloc(len, GFP_ATOMIC);
if (!usbhid->ctrl[usbhid->ctrlhead].raw_report) {
- dev_warn(&hid->dev, "control queueing failed\n");
+ hid_warn(hid, "control queueing failed\n");
return;
}
hid_output_report(report, usbhid->ctrl[usbhid->ctrlhead].raw_report);
@@ -590,7 +591,7 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un
return -1;
if ((offset = hidinput_find_field(hid, type, code, &field)) == -1) {
- dev_warn(&dev->dev, "event field not found\n");
+ hid_warn(dev, "event field not found\n");
return -1;
}
@@ -656,7 +657,7 @@ int usbhid_open(struct hid_device *hid)
mutex_lock(&hid_open_mut);
if (!hid->open++) {
res = usb_autopm_get_interface(usbhid->intf);
- /* the device must be awake to reliable request remote wakeup */
+ /* the device must be awake to reliably request remote wakeup */
if (res < 0) {
hid->open--;
mutex_unlock(&hid_open_mut);
@@ -722,7 +723,7 @@ void usbhid_init_reports(struct hid_device *hid)
}
if (err)
- dev_warn(&hid->dev, "timeout initializing reports\n");
+ hid_warn(hid, "timeout initializing reports\n");
}
/*
@@ -798,6 +799,40 @@ static int hid_alloc_buffers(struct usb_device *dev, struct hid_device *hid)
return 0;
}
+static int usbhid_get_raw_report(struct hid_device *hid,
+ unsigned char report_number, __u8 *buf, size_t count,
+ unsigned char report_type)
+{
+ struct usbhid_device *usbhid = hid->driver_data;
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ struct usb_interface *intf = usbhid->intf;
+ struct usb_host_interface *interface = intf->cur_altsetting;
+ int skipped_report_id = 0;
+ int ret;
+
+ /* Byte 0 is the report number. Report data starts at byte 1.*/
+ buf[0] = report_number;
+ if (report_number == 0x0) {
+ /* Offset the return buffer by 1, so that the report ID
+ will remain in byte 0. */
+ buf++;
+ count--;
+ skipped_report_id = 1;
+ }
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ HID_REQ_GET_REPORT,
+ USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
+ ((report_type + 1) << 8) | report_number,
+ interface->desc.bInterfaceNumber, buf, count,
+ USB_CTRL_SET_TIMEOUT);
+
+ /* count also the report id */
+ if (ret > 0 && skipped_report_id)
+ ret++;
+
+ return ret;
+}
+
static int usbhid_output_raw_report(struct hid_device *hid, __u8 *buf, size_t count,
unsigned char report_type)
{
@@ -857,18 +892,6 @@ static void usbhid_restart_queues(struct usbhid_device *usbhid)
usbhid_restart_ctrl_queue(usbhid);
}
-static void __usbhid_restart_queues(struct work_struct *work)
-{
- struct usbhid_device *usbhid =
- container_of(work, struct usbhid_device, restart_work);
- int r;
-
- r = usb_autopm_get_interface(usbhid->intf);
- if (r < 0)
- return;
- usb_autopm_put_interface(usbhid->intf);
-}
-
static void hid_free_buffers(struct usb_device *dev, struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
@@ -1140,8 +1163,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
if (usb_endpoint_is_int_in(&interface->endpoint[n].desc))
has_in++;
if (!has_in) {
- dev_err(&intf->dev, "couldn't find an input interrupt "
- "endpoint\n");
+ hid_err(intf, "couldn't find an input interrupt endpoint\n");
return -ENODEV;
}
@@ -1151,6 +1173,7 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
usb_set_intfdata(intf, hid);
hid->ll_driver = &usb_hid_driver;
+ hid->hid_get_raw_report = usbhid_get_raw_report;
hid->hid_output_raw_report = usbhid_output_raw_report;
hid->ff_init = hid_pidff_init;
#ifdef CONFIG_USB_HIDDEV
@@ -1206,14 +1229,13 @@ static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *
init_waitqueue_head(&usbhid->wait);
INIT_WORK(&usbhid->reset_work, hid_reset);
- INIT_WORK(&usbhid->restart_work, __usbhid_restart_queues);
setup_timer(&usbhid->io_retry, hid_retry_timeout, (unsigned long) hid);
spin_lock_init(&usbhid->lock);
ret = hid_add_device(hid);
if (ret) {
if (ret != -ENODEV)
- dev_err(&intf->dev, "can't add hid device: %d\n", ret);
+ hid_err(intf, "can't add hid device: %d\n", ret);
goto err_free;
}
@@ -1241,7 +1263,6 @@ static void usbhid_disconnect(struct usb_interface *intf)
static void hid_cancel_delayed_stuff(struct usbhid_device *usbhid)
{
del_timer_sync(&usbhid->io_retry);
- cancel_work_sync(&usbhid->restart_work);
cancel_work_sync(&usbhid->reset_work);
}
@@ -1262,7 +1283,6 @@ static int hid_pre_reset(struct usb_interface *intf)
spin_lock_irq(&usbhid->lock);
set_bit(HID_RESET_PENDING, &usbhid->iofl);
spin_unlock_irq(&usbhid->lock);
- cancel_work_sync(&usbhid->restart_work);
hid_cease_io(usbhid);
return 0;
@@ -1461,9 +1481,6 @@ static int __init hid_init(void)
{
int retval = -ENOMEM;
- resumption_waker = create_freezeable_workqueue("usbhid_resumer");
- if (!resumption_waker)
- goto no_queue;
retval = hid_register_driver(&hid_usb_driver);
if (retval)
goto hid_register_fail;
@@ -1481,8 +1498,6 @@ usb_register_fail:
usbhid_quirks_init_fail:
hid_unregister_driver(&hid_usb_driver);
hid_register_fail:
- destroy_workqueue(resumption_waker);
-no_queue:
return retval;
}
@@ -1491,7 +1506,6 @@ static void __exit hid_exit(void)
usb_deregister(&hid_driver);
usbhid_quirks_exit();
hid_unregister_driver(&hid_usb_driver);
- destroy_workqueue(resumption_waker);
}
module_init(hid_init);
diff --git a/drivers/hid/usbhid/hid-pidff.c b/drivers/hid/usbhid/hid-pidff.c
index ef381d79cfa8..f91c136821f7 100644
--- a/drivers/hid/usbhid/hid-pidff.c
+++ b/drivers/hid/usbhid/hid-pidff.c
@@ -22,7 +22,7 @@
/* #define DEBUG */
-#define debug(format, arg...) pr_debug("hid-pidff: " format "\n" , ## arg)
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/input.h>
#include <linux/slab.h>
@@ -220,7 +220,7 @@ static int pidff_rescale_signed(int i, struct hid_field *field)
static void pidff_set(struct pidff_usage *usage, u16 value)
{
usage->value[0] = pidff_rescale(value, 0xffff, usage->field);
- debug("calculated from %d to %d", value, usage->value[0]);
+ pr_debug("calculated from %d to %d\n", value, usage->value[0]);
}
static void pidff_set_signed(struct pidff_usage *usage, s16 value)
@@ -235,7 +235,7 @@ static void pidff_set_signed(struct pidff_usage *usage, s16 value)
usage->value[0] =
pidff_rescale(value, 0x7fff, usage->field);
}
- debug("calculated from %d to %d", value, usage->value[0]);
+ pr_debug("calculated from %d to %d\n", value, usage->value[0]);
}
/*
@@ -259,8 +259,9 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
pidff->set_envelope[PID_ATTACK_TIME].value[0] = envelope->attack_length;
pidff->set_envelope[PID_FADE_TIME].value[0] = envelope->fade_length;
- debug("attack %u => %d", envelope->attack_level,
- pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
+ hid_dbg(pidff->hid, "attack %u => %d\n",
+ envelope->attack_level,
+ pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
USB_DIR_OUT);
@@ -466,33 +467,33 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
pidff->create_new_effect_type->value[0] = efnum;
usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
USB_DIR_OUT);
- debug("create_new_effect sent, type: %d", efnum);
+ hid_dbg(pidff->hid, "create_new_effect sent, type: %d\n", efnum);
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0] = 0;
pidff->block_load_status->value[0] = 0;
usbhid_wait_io(pidff->hid);
for (j = 0; j < 60; j++) {
- debug("pid_block_load requested");
+ hid_dbg(pidff->hid, "pid_block_load requested\n");
usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
USB_DIR_IN);
usbhid_wait_io(pidff->hid);
if (pidff->block_load_status->value[0] ==
pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
- debug("device reported free memory: %d bytes",
- pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
- pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
+ hid_dbg(pidff->hid, "device reported free memory: %d bytes\n",
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
return 0;
}
if (pidff->block_load_status->value[0] ==
pidff->status_id[PID_BLOCK_LOAD_FULL]) {
- debug("not enough memory free: %d bytes",
- pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
+ hid_dbg(pidff->hid, "not enough memory free: %d bytes\n",
+ pidff->block_load[PID_RAM_POOL_AVAILABLE].value ?
pidff->block_load[PID_RAM_POOL_AVAILABLE].value[0] : -1);
return -ENOSPC;
}
}
- printk(KERN_ERR "hid-pidff: pid_block_load failed 60 times\n");
+ hid_err(pidff->hid, "pid_block_load failed 60 times\n");
return -EIO;
}
@@ -546,7 +547,8 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id)
struct pidff_device *pidff = dev->ff->private;
int pid_id = pidff->pid_id[effect_id];
- debug("starting to erase %d/%d", effect_id, pidff->pid_id[effect_id]);
+ hid_dbg(pidff->hid, "starting to erase %d/%d\n",
+ effect_id, pidff->pid_id[effect_id]);
/* Wait for the queue to clear. We do not want a full fifo to
prevent the effect removal. */
usbhid_wait_io(pidff->hid);
@@ -604,8 +606,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
type_id = PID_SAW_DOWN;
break;
default:
- printk(KERN_ERR
- "hid-pidff: invalid waveform\n");
+ hid_err(pidff->hid, "invalid waveform\n");
return -EINVAL;
}
@@ -696,7 +697,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
break;
default:
- printk(KERN_ERR "hid-pidff: invalid type\n");
+ hid_err(pidff->hid, "invalid type\n");
return -EINVAL;
}
@@ -704,7 +705,7 @@ static int pidff_upload_effect(struct input_dev *dev, struct ff_effect *effect,
pidff->pid_id[effect->id] =
pidff->block_load[PID_EFFECT_BLOCK_INDEX].value[0];
- debug("uploaded");
+ hid_dbg(pidff->hid, "uploaded\n");
return 0;
}
@@ -770,14 +771,14 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
for (i = 0; i < report->maxfield; i++) {
if (report->field[i]->maxusage !=
report->field[i]->report_count) {
- debug("maxusage and report_count do not match, "
- "skipping");
+ pr_debug("maxusage and report_count do not match, skipping\n");
continue;
}
for (j = 0; j < report->field[i]->maxusage; j++) {
if (report->field[i]->usage[j].hid ==
(HID_UP_PID | table[k])) {
- debug("found %d at %d->%d", k, i, j);
+ pr_debug("found %d at %d->%d\n",
+ k, i, j);
usage[k].field = report->field[i];
usage[k].value =
&report->field[i]->value[j];
@@ -789,7 +790,7 @@ static int pidff_find_fields(struct pidff_usage *usage, const u8 *table,
break;
}
if (!found && strict) {
- debug("failed to locate %d", k);
+ pr_debug("failed to locate %d\n", k);
return -1;
}
}
@@ -826,8 +827,8 @@ static void pidff_find_reports(struct hid_device *hid, int report_type,
continue;
ret = pidff_check_usage(report->field[0]->logical);
if (ret != -1) {
- debug("found usage 0x%02x from field->logical",
- pidff_reports[ret]);
+ hid_dbg(hid, "found usage 0x%02x from field->logical\n",
+ pidff_reports[ret]);
pidff->reports[ret] = report;
continue;
}
@@ -845,8 +846,9 @@ static void pidff_find_reports(struct hid_device *hid, int report_type,
continue;
ret = pidff_check_usage(hid->collection[i - 1].usage);
if (ret != -1 && !pidff->reports[ret]) {
- debug("found usage 0x%02x from collection array",
- pidff_reports[ret]);
+ hid_dbg(hid,
+ "found usage 0x%02x from collection array\n",
+ pidff_reports[ret]);
pidff->reports[ret] = report;
}
}
@@ -861,7 +863,7 @@ static int pidff_reports_ok(struct pidff_device *pidff)
for (i = 0; i <= PID_REQUIRED_REPORTS; i++) {
if (!pidff->reports[i]) {
- debug("%d missing", i);
+ hid_dbg(pidff->hid, "%d missing\n", i);
return 0;
}
}
@@ -884,8 +886,7 @@ static struct hid_field *pidff_find_special_field(struct hid_report *report,
report->field[i]->logical_minimum == 1)
return report->field[i];
else {
- printk(KERN_ERR "hid-pidff: logical_minimum "
- "is not 1 as it should be\n");
+ pr_err("logical_minimum is not 1 as it should be\n");
return NULL;
}
}
@@ -924,7 +925,7 @@ static int pidff_find_special_keys(int *keys, struct hid_field *fld,
*/
static int pidff_find_special_fields(struct pidff_device *pidff)
{
- debug("finding special fields");
+ hid_dbg(pidff->hid, "finding special fields\n");
pidff->create_new_effect_type =
pidff_find_special_field(pidff->reports[PID_CREATE_NEW_EFFECT],
@@ -945,32 +946,30 @@ static int pidff_find_special_fields(struct pidff_device *pidff)
pidff_find_special_field(pidff->reports[PID_EFFECT_OPERATION],
0x78, 1);
- debug("search done");
+ hid_dbg(pidff->hid, "search done\n");
if (!pidff->create_new_effect_type || !pidff->set_effect_type) {
- printk(KERN_ERR "hid-pidff: effect lists not found\n");
+ hid_err(pidff->hid, "effect lists not found\n");
return -1;
}
if (!pidff->effect_direction) {
- printk(KERN_ERR "hid-pidff: direction field not found\n");
+ hid_err(pidff->hid, "direction field not found\n");
return -1;
}
if (!pidff->device_control) {
- printk(KERN_ERR "hid-pidff: device control field not found\n");
+ hid_err(pidff->hid, "device control field not found\n");
return -1;
}
if (!pidff->block_load_status) {
- printk(KERN_ERR
- "hid-pidff: block load status field not found\n");
+ hid_err(pidff->hid, "block load status field not found\n");
return -1;
}
if (!pidff->effect_operation_status) {
- printk(KERN_ERR
- "hid-pidff: effect operation field not found\n");
+ hid_err(pidff->hid, "effect operation field not found\n");
return -1;
}
@@ -982,23 +981,22 @@ static int pidff_find_special_fields(struct pidff_device *pidff)
if (!PIDFF_FIND_SPECIAL_KEYS(type_id, create_new_effect_type,
effect_types)) {
- printk(KERN_ERR "hid-pidff: no effect types found\n");
+ hid_err(pidff->hid, "no effect types found\n");
return -1;
}
if (PIDFF_FIND_SPECIAL_KEYS(status_id, block_load_status,
block_load_status) !=
sizeof(pidff_block_load_status)) {
- printk(KERN_ERR
- "hidpidff: block load status identifiers not found\n");
+ hid_err(pidff->hid,
+ "block load status identifiers not found\n");
return -1;
}
if (PIDFF_FIND_SPECIAL_KEYS(operation_id, effect_operation_status,
effect_operation_status) !=
sizeof(pidff_effect_operation_status)) {
- printk(KERN_ERR
- "hidpidff: effect operation identifiers not found\n");
+ hid_err(pidff->hid, "effect operation identifiers not found\n");
return -1;
}
@@ -1017,8 +1015,8 @@ static int pidff_find_effects(struct pidff_device *pidff,
int pidff_type = pidff->type_id[i];
if (pidff->set_effect_type->usage[pidff_type].hid !=
pidff->create_new_effect_type->usage[pidff_type].hid) {
- printk(KERN_ERR "hid-pidff: "
- "effect type number %d is invalid\n", i);
+ hid_err(pidff->hid,
+ "effect type number %d is invalid\n", i);
return -1;
}
}
@@ -1073,27 +1071,23 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
int envelope_ok = 0;
if (PIDFF_FIND_FIELDS(set_effect, PID_SET_EFFECT, 1)) {
- printk(KERN_ERR
- "hid-pidff: unknown set_effect report layout\n");
+ hid_err(pidff->hid, "unknown set_effect report layout\n");
return -ENODEV;
}
PIDFF_FIND_FIELDS(block_load, PID_BLOCK_LOAD, 0);
if (!pidff->block_load[PID_EFFECT_BLOCK_INDEX].value) {
- printk(KERN_ERR
- "hid-pidff: unknown pid_block_load report layout\n");
+ hid_err(pidff->hid, "unknown pid_block_load report layout\n");
return -ENODEV;
}
if (PIDFF_FIND_FIELDS(effect_operation, PID_EFFECT_OPERATION, 1)) {
- printk(KERN_ERR
- "hid-pidff: unknown effect_operation report layout\n");
+ hid_err(pidff->hid, "unknown effect_operation report layout\n");
return -ENODEV;
}
if (PIDFF_FIND_FIELDS(block_free, PID_BLOCK_FREE, 1)) {
- printk(KERN_ERR
- "hid-pidff: unknown pid_block_free report layout\n");
+ hid_err(pidff->hid, "unknown pid_block_free report layout\n");
return -ENODEV;
}
@@ -1105,27 +1099,26 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
if (!envelope_ok) {
if (test_and_clear_bit(FF_CONSTANT, dev->ffbit))
- printk(KERN_WARNING "hid-pidff: "
- "has constant effect but no envelope\n");
+ hid_warn(pidff->hid,
+ "has constant effect but no envelope\n");
if (test_and_clear_bit(FF_RAMP, dev->ffbit))
- printk(KERN_WARNING "hid-pidff: "
- "has ramp effect but no envelope\n");
+ hid_warn(pidff->hid,
+ "has ramp effect but no envelope\n");
if (test_and_clear_bit(FF_PERIODIC, dev->ffbit))
- printk(KERN_WARNING "hid-pidff: "
- "has periodic effect but no envelope\n");
+ hid_warn(pidff->hid,
+ "has periodic effect but no envelope\n");
}
if (test_bit(FF_CONSTANT, dev->ffbit) &&
PIDFF_FIND_FIELDS(set_constant, PID_SET_CONSTANT, 1)) {
- printk(KERN_WARNING
- "hid-pidff: unknown constant effect layout\n");
+ hid_warn(pidff->hid, "unknown constant effect layout\n");
clear_bit(FF_CONSTANT, dev->ffbit);
}
if (test_bit(FF_RAMP, dev->ffbit) &&
PIDFF_FIND_FIELDS(set_ramp, PID_SET_RAMP, 1)) {
- printk(KERN_WARNING "hid-pidff: unknown ramp effect layout\n");
+ hid_warn(pidff->hid, "unknown ramp effect layout\n");
clear_bit(FF_RAMP, dev->ffbit);
}
@@ -1134,8 +1127,7 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
test_bit(FF_FRICTION, dev->ffbit) ||
test_bit(FF_INERTIA, dev->ffbit)) &&
PIDFF_FIND_FIELDS(set_condition, PID_SET_CONDITION, 1)) {
- printk(KERN_WARNING
- "hid-pidff: unknown condition effect layout\n");
+ hid_warn(pidff->hid, "unknown condition effect layout\n");
clear_bit(FF_SPRING, dev->ffbit);
clear_bit(FF_DAMPER, dev->ffbit);
clear_bit(FF_FRICTION, dev->ffbit);
@@ -1144,8 +1136,7 @@ static int pidff_init_fields(struct pidff_device *pidff, struct input_dev *dev)
if (test_bit(FF_PERIODIC, dev->ffbit) &&
PIDFF_FIND_FIELDS(set_periodic, PID_SET_PERIODIC, 1)) {
- printk(KERN_WARNING
- "hid-pidff: unknown periodic effect layout\n");
+ hid_warn(pidff->hid, "unknown periodic effect layout\n");
clear_bit(FF_PERIODIC, dev->ffbit);
}
@@ -1184,12 +1175,12 @@ static void pidff_reset(struct pidff_device *pidff)
if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) {
if (i++ > 20) {
- printk(KERN_WARNING "hid-pidff: device reports "
- "%d simultaneous effects\n",
- pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
+ hid_warn(pidff->hid,
+ "device reports %d simultaneous effects\n",
+ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
break;
}
- debug("pid_pool requested again");
+ hid_dbg(pidff->hid, "pid_pool requested again\n");
usbhid_submit_report(hid, pidff->reports[PID_POOL],
USB_DIR_IN);
usbhid_wait_io(hid);
@@ -1215,7 +1206,7 @@ static int pidff_check_autocenter(struct pidff_device *pidff,
error = pidff_request_effect_upload(pidff, 1);
if (error) {
- printk(KERN_ERR "hid-pidff: upload request failed\n");
+ hid_err(pidff->hid, "upload request failed\n");
return error;
}
@@ -1224,8 +1215,8 @@ static int pidff_check_autocenter(struct pidff_device *pidff,
pidff_autocenter(pidff, 0xffff);
set_bit(FF_AUTOCENTER, dev->ffbit);
} else {
- printk(KERN_NOTICE "hid-pidff: "
- "device has unknown autocenter control method\n");
+ hid_notice(pidff->hid,
+ "device has unknown autocenter control method\n");
}
pidff_erase_pid(pidff,
@@ -1248,10 +1239,10 @@ int hid_pidff_init(struct hid_device *hid)
int max_effects;
int error;
- debug("starting pid init");
+ hid_dbg(hid, "starting pid init\n");
if (list_empty(&hid->report_enum[HID_OUTPUT_REPORT].report_list)) {
- debug("not a PID device, no output report");
+ hid_dbg(hid, "not a PID device, no output report\n");
return -ENODEV;
}
@@ -1265,7 +1256,7 @@ int hid_pidff_init(struct hid_device *hid)
pidff_find_reports(hid, HID_FEATURE_REPORT, pidff);
if (!pidff_reports_ok(pidff)) {
- debug("reports not ok, aborting");
+ hid_dbg(hid, "reports not ok, aborting\n");
error = -ENODEV;
goto fail;
}
@@ -1278,8 +1269,8 @@ int hid_pidff_init(struct hid_device *hid)
if (test_bit(FF_GAIN, dev->ffbit)) {
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], 0xffff);
- usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
- USB_DIR_OUT);
+ usbhid_submit_report(hid, pidff->reports[PID_DEVICE_GAIN],
+ USB_DIR_OUT);
}
error = pidff_check_autocenter(pidff, dev);
@@ -1290,23 +1281,23 @@ int hid_pidff_init(struct hid_device *hid)
pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_maximum -
pidff->block_load[PID_EFFECT_BLOCK_INDEX].field->logical_minimum +
1;
- debug("max effects is %d", max_effects);
+ hid_dbg(hid, "max effects is %d\n", max_effects);
if (max_effects > PID_EFFECTS_MAX)
max_effects = PID_EFFECTS_MAX;
if (pidff->pool[PID_SIMULTANEOUS_MAX].value)
- debug("max simultaneous effects is %d",
- pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
+ hid_dbg(hid, "max simultaneous effects is %d\n",
+ pidff->pool[PID_SIMULTANEOUS_MAX].value[0]);
if (pidff->pool[PID_RAM_POOL_SIZE].value)
- debug("device memory size is %d bytes",
- pidff->pool[PID_RAM_POOL_SIZE].value[0]);
+ hid_dbg(hid, "device memory size is %d bytes\n",
+ pidff->pool[PID_RAM_POOL_SIZE].value[0]);
if (pidff->pool[PID_DEVICE_MANAGED_POOL].value &&
pidff->pool[PID_DEVICE_MANAGED_POOL].value[0] == 0) {
- printk(KERN_NOTICE "hid-pidff: "
- "device does not support device managed pool\n");
+ hid_notice(hid,
+ "device does not support device managed pool\n");
goto fail;
}
@@ -1322,8 +1313,7 @@ int hid_pidff_init(struct hid_device *hid)
ff->set_autocenter = pidff_set_autocenter;
ff->playback = pidff_playback;
- printk(KERN_INFO "Force feedback for USB HID PID devices by "
- "Anssi Hannula <anssi.hannula@gmail.com>\n");
+ hid_info(dev, "Force feedback for USB HID PID devices by Anssi Hannula <anssi.hannula@gmail.com>\n");
return 0;
diff --git a/drivers/hid/usbhid/hid-quirks.c b/drivers/hid/usbhid/hid-quirks.c
index 2c185477eeb3..9a94b643ccde 100644
--- a/drivers/hid/usbhid/hid-quirks.c
+++ b/drivers/hid/usbhid/hid-quirks.c
@@ -35,7 +35,6 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CHIC, USB_DEVICE_ID_CHIC_GAMEPAD, HID_QUIRK_BADPAD },
{ USB_VENDOR_ID_DWAV, USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER, HID_QUIRK_MULTI_INPUT | HID_QUIRK_NOGET },
{ USB_VENDOR_ID_MOJO, USB_DEVICE_ID_RETRO_ADAPTER, HID_QUIRK_MULTI_INPUT },
- { USB_VENDOR_ID_TURBOX, USB_DEVICE_ID_TURBOX_TOUCHSCREEN_MOSART, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_DRIVING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FLYING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_HAPP, USB_DEVICE_ID_UGCI_FIGHTING, HID_QUIRK_BADPAD | HID_QUIRK_MULTI_INPUT },
@@ -85,7 +84,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_PI_ENGINEERING, USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL, HID_QUIRK_HIDINPUT_FORCE },
{ USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_MULTI_TOUCH, HID_QUIRK_MULTI_INPUT },
-
+ { USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS, HID_QUIRK_MULTI_INPUT },
{ 0, 0 }
};
diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c
index 984feb351a5a..af0a7c1002af 100644
--- a/drivers/hid/usbhid/hiddev.c
+++ b/drivers/hid/usbhid/hiddev.c
@@ -585,163 +585,168 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
struct hiddev_list *list = file->private_data;
struct hiddev *hiddev = list->hiddev;
- struct hid_device *hid = hiddev->hid;
- struct usb_device *dev;
+ struct hid_device *hid;
struct hiddev_collection_info cinfo;
struct hiddev_report_info rinfo;
struct hiddev_field_info finfo;
struct hiddev_devinfo dinfo;
struct hid_report *report;
struct hid_field *field;
- struct usbhid_device *usbhid = hid->driver_data;
void __user *user_arg = (void __user *)arg;
- int i, r;
-
+ int i, r = -EINVAL;
+
/* Called without BKL by compat methods so no BKL taken */
- /* FIXME: Who or what stop this racing with a disconnect ?? */
- if (!hiddev->exist || !hid)
- return -EIO;
+ mutex_lock(&hiddev->existancelock);
+ if (!hiddev->exist) {
+ r = -ENODEV;
+ goto ret_unlock;
+ }
- dev = hid_to_usb_dev(hid);
+ hid = hiddev->hid;
switch (cmd) {
case HIDIOCGVERSION:
- return put_user(HID_VERSION, (int __user *)arg);
+ r = put_user(HID_VERSION, (int __user *)arg) ?
+ -EFAULT : 0;
+ break;
case HIDIOCAPPLICATION:
if (arg < 0 || arg >= hid->maxapplication)
- return -EINVAL;
+ break;
for (i = 0; i < hid->maxcollection; i++)
if (hid->collection[i].type ==
HID_COLLECTION_APPLICATION && arg-- == 0)
break;
- if (i == hid->maxcollection)
- return -EINVAL;
-
- return hid->collection[i].usage;
+ if (i < hid->maxcollection)
+ r = hid->collection[i].usage;
+ break;
case HIDIOCGDEVINFO:
- dinfo.bustype = BUS_USB;
- dinfo.busnum = dev->bus->busnum;
- dinfo.devnum = dev->devnum;
- dinfo.ifnum = usbhid->ifnum;
- dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
- dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
- dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
- dinfo.num_applications = hid->maxapplication;
- if (copy_to_user(user_arg, &dinfo, sizeof(dinfo)))
- return -EFAULT;
-
- return 0;
+ {
+ struct usb_device *dev = hid_to_usb_dev(hid);
+ struct usbhid_device *usbhid = hid->driver_data;
+
+ dinfo.bustype = BUS_USB;
+ dinfo.busnum = dev->bus->busnum;
+ dinfo.devnum = dev->devnum;
+ dinfo.ifnum = usbhid->ifnum;
+ dinfo.vendor = le16_to_cpu(dev->descriptor.idVendor);
+ dinfo.product = le16_to_cpu(dev->descriptor.idProduct);
+ dinfo.version = le16_to_cpu(dev->descriptor.bcdDevice);
+ dinfo.num_applications = hid->maxapplication;
+
+ r = copy_to_user(user_arg, &dinfo, sizeof(dinfo)) ?
+ -EFAULT : 0;
+ break;
+ }
case HIDIOCGFLAG:
- if (put_user(list->flags, (int __user *)arg))
- return -EFAULT;
-
- return 0;
+ r = put_user(list->flags, (int __user *)arg) ?
+ -EFAULT : 0;
+ break;
case HIDIOCSFLAG:
{
int newflags;
- if (get_user(newflags, (int __user *)arg))
- return -EFAULT;
+
+ if (get_user(newflags, (int __user *)arg)) {
+ r = -EFAULT;
+ break;
+ }
if ((newflags & ~HIDDEV_FLAGS) != 0 ||
((newflags & HIDDEV_FLAG_REPORT) != 0 &&
(newflags & HIDDEV_FLAG_UREF) == 0))
- return -EINVAL;
+ break;
list->flags = newflags;
- return 0;
+ r = 0;
+ break;
}
case HIDIOCGSTRING:
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist)
- r = hiddev_ioctl_string(hiddev, cmd, user_arg);
- else
- r = -ENODEV;
- mutex_unlock(&hiddev->existancelock);
- return r;
+ r = hiddev_ioctl_string(hiddev, cmd, user_arg);
+ break;
case HIDIOCINITREPORT:
- mutex_lock(&hiddev->existancelock);
- if (!hiddev->exist) {
- mutex_unlock(&hiddev->existancelock);
- return -ENODEV;
- }
usbhid_init_reports(hid);
- mutex_unlock(&hiddev->existancelock);
-
- return 0;
+ r = 0;
+ break;
case HIDIOCGREPORT:
- if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
- return -EFAULT;
+ if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+ r = -EFAULT;
+ break;
+ }
if (rinfo.report_type == HID_REPORT_TYPE_OUTPUT)
- return -EINVAL;
+ break;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist) {
- usbhid_submit_report(hid, report, USB_DIR_IN);
- usbhid_wait_io(hid);
- }
- mutex_unlock(&hiddev->existancelock);
+ usbhid_submit_report(hid, report, USB_DIR_IN);
+ usbhid_wait_io(hid);
- return 0;
+ r = 0;
+ break;
case HIDIOCSREPORT:
- if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
- return -EFAULT;
+ if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+ r = -EFAULT;
+ break;
+ }
if (rinfo.report_type == HID_REPORT_TYPE_INPUT)
- return -EINVAL;
+ break;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist) {
- usbhid_submit_report(hid, report, USB_DIR_OUT);
- usbhid_wait_io(hid);
- }
- mutex_unlock(&hiddev->existancelock);
+ usbhid_submit_report(hid, report, USB_DIR_OUT);
+ usbhid_wait_io(hid);
- return 0;
+ r = 0;
+ break;
case HIDIOCGREPORTINFO:
- if (copy_from_user(&rinfo, user_arg, sizeof(rinfo)))
- return -EFAULT;
+ if (copy_from_user(&rinfo, user_arg, sizeof(rinfo))) {
+ r = -EFAULT;
+ break;
+ }
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
rinfo.num_fields = report->maxfield;
- if (copy_to_user(user_arg, &rinfo, sizeof(rinfo)))
- return -EFAULT;
-
- return 0;
+ r = copy_to_user(user_arg, &rinfo, sizeof(rinfo)) ?
+ -EFAULT : 0;
+ break;
case HIDIOCGFIELDINFO:
- if (copy_from_user(&finfo, user_arg, sizeof(finfo)))
- return -EFAULT;
+ if (copy_from_user(&finfo, user_arg, sizeof(finfo))) {
+ r = -EFAULT;
+ break;
+ }
+
rinfo.report_type = finfo.report_type;
rinfo.report_id = finfo.report_id;
- if ((report = hiddev_lookup_report(hid, &rinfo)) == NULL)
- return -EINVAL;
+
+ report = hiddev_lookup_report(hid, &rinfo);
+ if (report == NULL)
+ break;
if (finfo.field_index >= report->maxfield)
- return -EINVAL;
+ break;
field = report->field[finfo.field_index];
memset(&finfo, 0, sizeof(finfo));
@@ -760,10 +765,9 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
finfo.unit_exponent = field->unit_exponent;
finfo.unit = field->unit;
- if (copy_to_user(user_arg, &finfo, sizeof(finfo)))
- return -EFAULT;
-
- return 0;
+ r = copy_to_user(user_arg, &finfo, sizeof(finfo)) ?
+ -EFAULT : 0;
+ break;
case HIDIOCGUCODE:
/* fall through */
@@ -772,57 +776,66 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
case HIDIOCGUSAGES:
case HIDIOCSUSAGES:
case HIDIOCGCOLLECTIONINDEX:
- mutex_lock(&hiddev->existancelock);
- if (hiddev->exist)
- r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
- else
- r = -ENODEV;
- mutex_unlock(&hiddev->existancelock);
- return r;
+ r = hiddev_ioctl_usage(hiddev, cmd, user_arg);
+ break;
case HIDIOCGCOLLECTIONINFO:
- if (copy_from_user(&cinfo, user_arg, sizeof(cinfo)))
- return -EFAULT;
+ if (copy_from_user(&cinfo, user_arg, sizeof(cinfo))) {
+ r = -EFAULT;
+ break;
+ }
if (cinfo.index >= hid->maxcollection)
- return -EINVAL;
+ break;
cinfo.type = hid->collection[cinfo.index].type;
cinfo.usage = hid->collection[cinfo.index].usage;
cinfo.level = hid->collection[cinfo.index].level;
- if (copy_to_user(user_arg, &cinfo, sizeof(cinfo)))
- return -EFAULT;
- return 0;
+ r = copy_to_user(user_arg, &cinfo, sizeof(cinfo)) ?
+ -EFAULT : 0;
+ break;
default:
-
if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
- return -EINVAL;
+ break;
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGNAME(0))) {
int len;
- if (!hid->name)
- return 0;
+
+ if (!hid->name) {
+ r = 0;
+ break;
+ }
+
len = strlen(hid->name) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
- return copy_to_user(user_arg, hid->name, len) ?
+ r = copy_to_user(user_arg, hid->name, len) ?
-EFAULT : len;
+ break;
}
if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGPHYS(0))) {
int len;
- if (!hid->phys)
- return 0;
+
+ if (!hid->phys) {
+ r = 0;
+ break;
+ }
+
len = strlen(hid->phys) + 1;
if (len > _IOC_SIZE(cmd))
len = _IOC_SIZE(cmd);
- return copy_to_user(user_arg, hid->phys, len) ?
+ r = copy_to_user(user_arg, hid->phys, len) ?
-EFAULT : len;
+ break;
}
}
- return -EINVAL;
+
+ret_unlock:
+ mutex_unlock(&hiddev->existancelock);
+ return r;
}
#ifdef CONFIG_COMPAT
@@ -892,7 +905,7 @@ int hiddev_connect(struct hid_device *hid, unsigned int force)
hiddev->exist = 1;
retval = usb_register_dev(usbhid->intf, &hiddev_class);
if (retval) {
- err_hid("Not able to get a minor for this device.");
+ hid_err(hid, "Not able to get a minor for this device\n");
hid->hiddev = NULL;
kfree(hiddev);
return -1;
diff --git a/drivers/hid/usbhid/usbhid.h b/drivers/hid/usbhid/usbhid.h
index 89d2e847dcc6..1673cac93d77 100644
--- a/drivers/hid/usbhid/usbhid.h
+++ b/drivers/hid/usbhid/usbhid.h
@@ -95,7 +95,6 @@ struct usbhid_device {
unsigned long stop_retry; /* Time to give up, in jiffies */
unsigned int retry_delay; /* Delay length in ms */
struct work_struct reset_work; /* Task context for resets */
- struct work_struct restart_work; /* waking up for output to be done in a task */
wait_queue_head_t wait; /* For sleeping */
int ledcount; /* counting the number of active leds */
};
diff --git a/drivers/hid/usbhid/usbkbd.c b/drivers/hid/usbhid/usbkbd.c
index a948605564fb..065817329f03 100644
--- a/drivers/hid/usbhid/usbkbd.c
+++ b/drivers/hid/usbhid/usbkbd.c
@@ -24,6 +24,8 @@
* Vojtech Pavlik, Simunkova 1594, Prague 8, 182 00 Czech Republic
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/module.h>
@@ -104,16 +106,18 @@ static void usb_kbd_irq(struct urb *urb)
if (usb_kbd_keycode[kbd->old[i]])
input_report_key(kbd->dev, usb_kbd_keycode[kbd->old[i]], 0);
else
- dev_info(&urb->dev->dev,
- "Unknown key (scancode %#x) released.\n", kbd->old[i]);
+ hid_info(urb->dev,
+ "Unknown key (scancode %#x) released.\n",
+ kbd->old[i]);
}
if (kbd->new[i] > 3 && memscan(kbd->old + 2, kbd->new[i], 6) == kbd->old + 8) {
if (usb_kbd_keycode[kbd->new[i]])
input_report_key(kbd->dev, usb_kbd_keycode[kbd->new[i]], 1);
else
- dev_info(&urb->dev->dev,
- "Unknown key (scancode %#x) released.\n", kbd->new[i]);
+ hid_info(urb->dev,
+ "Unknown key (scancode %#x) released.\n",
+ kbd->new[i]);
}
}
@@ -124,9 +128,9 @@ static void usb_kbd_irq(struct urb *urb)
resubmit:
i = usb_submit_urb (urb, GFP_ATOMIC);
if (i)
- err_hid ("can't resubmit intr, %s-%s/input0, status %d",
- kbd->usbdev->bus->bus_name,
- kbd->usbdev->devpath, i);
+ hid_err(urb->dev, "can't resubmit intr, %s-%s/input0, status %d",
+ kbd->usbdev->bus->bus_name,
+ kbd->usbdev->devpath, i);
}
static int usb_kbd_event(struct input_dev *dev, unsigned int type,
@@ -150,7 +154,7 @@ static int usb_kbd_event(struct input_dev *dev, unsigned int type,
*(kbd->leds) = kbd->newleds;
kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_ATOMIC))
- err_hid("usb_submit_urb(leds) failed");
+ pr_err("usb_submit_urb(leds) failed\n");
return 0;
}
@@ -160,7 +164,7 @@ static void usb_kbd_led(struct urb *urb)
struct usb_kbd *kbd = urb->context;
if (urb->status)
- dev_warn(&urb->dev->dev, "led urb status %d received\n",
+ hid_warn(urb->dev, "led urb status %d received\n",
urb->status);
if (*(kbd->leds) == kbd->newleds)
@@ -169,7 +173,7 @@ static void usb_kbd_led(struct urb *urb)
*(kbd->leds) = kbd->newleds;
kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_ATOMIC))
- err_hid("usb_submit_urb(leds) failed");
+ hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
}
static int usb_kbd_open(struct input_dev *dev)