diff options
Diffstat (limited to 'drivers/hid')
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) |