Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid

Pull HID updates from Jiri Kosina:

 - hid driver transport cleanup, finalizing the long-desired decoupling
   of core from transport layers, by Benjamin Tissoires and Henrik
   Rydberg

 - support for hybrid finger/pen multitouch HID devices, by Benjamin
   Tissoires

 - fix for long-standing issue in Logitech unifying driver sometimes not
   inializing properly due to device specifics, by Andrew de los Reyes

 - Wii remote driver updates to support 2nd generation of devices, by
   David Herrmann

 - support for Apple IR remote

 - roccat driver now supports new devices (Roccat Kone Pure, IskuFX), by
   Stefan Achatz

 - debugfs locking fixes in hid debug interface, by Jiri Kosina

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (43 commits)
  HID: protect hid_debug_list
  HID: debug: break out hid_dump_report() into hid-debug
  HID: Add PID for Japanese version of NE4K keyboard
  HID: hid-lg4ff add support for new version of DFGT wheel
  HID: icade: u16 which never < 0
  HID: clarify Magic Mouse Kconfig description
  HID: appleir: add support for Apple ir devices
  HID: roccat: added media key support for Kone
  HID: hid-lenovo-tpkbd: remove doubled hid_get_drvdata
  HID: i2c-hid: fix length for set/get report in i2c hid
  HID: wiimote: parse reduced status reports
  HID: wiimote: add 2nd generation Wii Remote IDs
  HID: wiimote: use unique battery names
  HID: hidraw: warn if userspace headers are outdated
  HID: multitouch: force BTN_STYLUS for pen devices
  HID: multitouch: append " Pen" to the name of the stylus input
  HID: multitouch: add handling for pen in dual-sensors device
  HID: multitouch: change touch sensor detection in mt_input_configured()
  HID: multitouch: do not map usage from non used reports
  HID: multitouch: breaks out touch handling in specific functions
  ...
This commit is contained in:
Linus Torvalds 2013-04-30 09:37:55 -07:00
commit 19b344efa3
61 changed files with 1600 additions and 420 deletions

View file

@ -101,7 +101,8 @@ Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the backlight intensity for
a specific profile. Profile number is included in written data.
The data has to be 10 bytes long.
The data has to be 10 bytes long for Isku, IskuFX needs 16 bytes
of data.
Before reading this file, control has to be written to select
which profile to read.
Users: http://roccat.sourceforge.net
@ -141,3 +142,12 @@ Description: When written, this file lets one trigger easyshift functionality
The data has to be 16 bytes long.
This file is writeonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/talkfx
Date: February 2013
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one trigger temporary color schemes
from the host.
The data has to be 16 bytes long.
This file is writeonly.
Users: http://roccat.sourceforge.net

View file

@ -0,0 +1,105 @@
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/actual_profile
Date: December 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. actual_profile holds number of actual profile.
This value is persistent, so its value determines the profile
that's active when the mouse is powered on next time.
When written, the mouse activates the set profile immediately.
The data has to be 3 bytes long.
The mouse will reject invalid data.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/control
Date: December 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one select which data from which
profile will be read next. The data has to be 3 bytes long.
This file is writeonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/info
Date: December 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns general data like firmware version.
When written, the device can be reset.
The data is 6 bytes long.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/macro
Date: December 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store a macro with max 500 key/button strokes
internally.
When written, this file lets one set the sequence for a specific
button for a specific profile. Button and profile numbers are
included in written data. The data has to be 2082 bytes long.
This file is writeonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/profile_buttons
Date: December 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_buttons holds information about button layout.
When written, this file lets one write the respective profile
buttons back to the mouse. The data has to be 59 bytes long.
The mouse will reject invalid data.
Which profile to write is determined by the profile number
contained in the data.
Before reading this file, control has to be written to select
which profile to read.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/profile_settings
Date: December 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse can store 5 profiles which can be switched by the
press of a button. A profile is split in settings and buttons.
profile_settings holds information like resolution, sensitivity
and light effects.
When written, this file lets one write the respective profile
settings back to the mouse. The data has to be 31 bytes long.
The mouse will reject invalid data.
Which profile to write is determined by the profile number
contained in the data.
Before reading this file, control has to be written to select
which profile to read.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/sensor
Date: December 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse has a tracking- and a distance-control-unit. These
can be activated/deactivated and the lift-off distance can be
set. The data has to be 6 bytes long.
This file is writeonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/talk
Date: December 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: Used to active some easy* functions of the mouse from outside.
The data has to be 16 bytes long.
This file is writeonly.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/tcu
Date: December 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written a calibration process for the tracking control unit
can be initiated/cancelled. Also lets one read/write sensor
registers.
The data has to be 4 bytes long.
Users: http://roccat.sourceforge.net
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/konepure/roccatkonepure<minor>/tcu_image
Date: December 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read the mouse returns a 30x30 pixel image of the
sampled underground. This works only in the course of a
calibration process initiated with tcu.
The returned data is 1028 bytes in size.
This file is readonly.
Users: http://roccat.sourceforge.net

View file

@ -92,14 +92,14 @@ menu "Special HID drivers"
config HID_A4TECH
tristate "A4 tech mice" if EXPERT
depends on USB_HID
depends on HID
default !EXPERT
---help---
Support for A4 tech X5 and WOP-35 / Trust 450L mice.
config HID_ACRUX
tristate "ACRUX game controller support"
depends on USB_HID
depends on HID
---help---
Say Y here if you want to enable support for ACRUX game controllers.
@ -113,7 +113,7 @@ config HID_ACRUX_FF
config HID_APPLE
tristate "Apple {i,Power,Mac}Books" if EXPERT
depends on (USB_HID || BT_HIDP)
depends on HID
default !EXPERT
---help---
Support for some Apple devices which less or more break
@ -122,36 +122,47 @@ config HID_APPLE
Say Y here if you want support for keyboards of Apple iBooks, PowerBooks,
MacBooks, MacBook Pros and Apple Aluminum.
config HID_APPLEIR
tristate "Apple infrared receiver"
depends on (USB_HID)
---help---
Support for Apple infrared remote control. All the Apple computers from
2005 onwards include such a port, except the unibody Macbook (2009),
and Mac Pros. This receiver is also used in the Apple TV set-top box
prior to the 2010 model.
Say Y here if you want support for Apple infrared remote control.
config HID_AUREAL
tristate "Aureal"
depends on USB_HID
depends on HID
---help---
Support for Aureal Cy se W-01RN Remote Controller and other Aureal derived remotes.
config HID_BELKIN
tristate "Belkin Flip KVM and Wireless keyboard" if EXPERT
depends on USB_HID
depends on HID
default !EXPERT
---help---
Support for Belkin Flip KVM and Wireless keyboard.
config HID_CHERRY
tristate "Cherry Cymotion keyboard" if EXPERT
depends on USB_HID
depends on HID
default !EXPERT
---help---
Support for Cherry Cymotion keyboard.
config HID_CHICONY
tristate "Chicony Tactical pad" if EXPERT
depends on USB_HID
depends on HID
default !EXPERT
---help---
Support for Chicony Tactical pad.
config HID_PRODIKEYS
tristate "Prodikeys PC-MIDI Keyboard support"
depends on USB_HID && SND
depends on HID && SND
select SND_RAWMIDI
---help---
Support for Prodikeys PC-MIDI Keyboard device support.
@ -166,14 +177,14 @@ config HID_PRODIKEYS
config HID_CYPRESS
tristate "Cypress mouse and barcode readers" if EXPERT
depends on USB_HID
depends on HID
default !EXPERT
---help---
Support for cypress mouse and barcode readers.
config HID_DRAGONRISE
tristate "DragonRise Inc. game controller"
depends on USB_HID
depends on HID
---help---
Say Y here if you have DragonRise Inc. game controllers.
These might be branded as:
@ -192,7 +203,7 @@ config DRAGONRISE_FF
config HID_EMS_FF
tristate "EMS Production Inc. force feedback support"
depends on USB_HID
depends on HID
select INPUT_FF_MEMLESS
---help---
Say Y here if you want to enable force feedback support for devices by
@ -202,13 +213,13 @@ config HID_EMS_FF
config HID_ELECOM
tristate "ELECOM BM084 bluetooth mouse"
depends on BT_HIDP
depends on HID
---help---
Support for the ELECOM BM084 (bluetooth mouse).
config HID_EZKEY
tristate "Ezkey BTC 8193 keyboard" if EXPERT
depends on USB_HID
depends on HID
default !EXPERT
---help---
Support for Ezkey BTC 8193 keyboard.
@ -231,7 +242,7 @@ config HOLTEK_FF
config HID_KEYTOUCH
tristate "Keytouch HID devices"
depends on USB_HID
depends on HID
---help---
Support for Keytouch HID devices not fully compliant with
the specification. Currently supported:
@ -239,7 +250,7 @@ config HID_KEYTOUCH
config HID_KYE
tristate "KYE/Genius devices"
depends on USB_HID
depends on HID
---help---
Support for KYE/Genius devices not fully compliant with HID standard:
- Ergo Mouse
@ -249,25 +260,25 @@ config HID_KYE
config HID_UCLOGIC
tristate "UC-Logic"
depends on USB_HID
depends on HID
---help---
Support for UC-Logic tablets.
config HID_WALTOP
tristate "Waltop"
depends on USB_HID
depends on HID
---help---
Support for Waltop tablets.
config HID_GYRATION
tristate "Gyration remote control"
depends on USB_HID
depends on HID
---help---
Support for Gyration remote control.
config HID_ICADE
tristate "ION iCade arcade controller"
depends on BT_HIDP
depends on HID
---help---
Support for the ION iCade arcade controller to work as a joystick.
@ -276,20 +287,20 @@ config HID_ICADE
config HID_TWINHAN
tristate "Twinhan IR remote control"
depends on USB_HID
depends on HID
---help---
Support for Twinhan IR remote control.
config HID_KENSINGTON
tristate "Kensington Slimblade Trackball" if EXPERT
depends on USB_HID
depends on HID
default !EXPERT
---help---
Support for Kensington Slimblade Trackball.
config HID_LCPOWER
tristate "LC-Power"
depends on USB_HID
depends on HID
---help---
Support for LC-Power RC1000MCE RF remote control.
@ -308,7 +319,7 @@ config HID_LENOVO_TPKBD
config HID_LOGITECH
tristate "Logitech devices" if EXPERT
depends on USB_HID
depends on HID
default !EXPERT
---help---
Support for Logitech devices that are not fully compliant with HID standard.
@ -373,31 +384,31 @@ config LOGIWHEELS_FF
- Logitech Formula Force EX
config HID_MAGICMOUSE
tristate "Apple MagicMouse multi-touch support"
depends on BT_HIDP
tristate "Apple Magic Mouse/Trackpad multi-touch support"
depends on HID
---help---
Support for the Apple Magic Mouse multi-touch.
Support for the Apple Magic Mouse/Trackpad multi-touch.
Say Y here if you want support for the multi-touch features of the
Apple Wireless "Magic" Mouse.
Apple Wireless "Magic" Mouse and the Apple Wireless "Magic" Trackpad.
config HID_MICROSOFT
tristate "Microsoft non-fully HID-compliant devices" if EXPERT
depends on USB_HID
depends on HID
default !EXPERT
---help---
Support for Microsoft devices that are not fully compliant with HID standard.
config HID_MONTEREY
tristate "Monterey Genius KB29E keyboard" if EXPERT
depends on USB_HID
depends on HID
default !EXPERT
---help---
Support for Monterey Genius KB29E.
config HID_MULTITOUCH
tristate "HID Multitouch panels"
depends on USB_HID
depends on HID
---help---
Generic support for HID multitouch panels.
@ -445,7 +456,7 @@ config HID_NTRIG
config HID_ORTEK
tristate "Ortek PKB-1700/WKB-2000/Skycable wireless keyboard and mouse trackpad"
depends on USB_HID
depends on HID
---help---
There are certain devices which have LogicalMaximum wrong in the keyboard
usage page of their report descriptor. The most prevailing ones so far
@ -458,7 +469,7 @@ config HID_ORTEK
config HID_PANTHERLORD
tristate "Pantherlord/GreenAsia game controller"
depends on USB_HID
depends on HID
---help---
Say Y here if you have a PantherLord/GreenAsia based game controller
or adapter.
@ -473,13 +484,13 @@ config PANTHERLORD_FF
config HID_PETALYNX
tristate "Petalynx Maxter remote control"
depends on USB_HID
depends on HID
---help---
Support for Petalynx Maxter remote control.
config HID_PICOLCD
tristate "PicoLCD (graphic version)"
depends on USB_HID
depends on HID
---help---
This provides support for Minibox PicoLCD devices, currently
only the graphical ones are supported.
@ -545,14 +556,14 @@ config HID_PICOLCD_CIR
config HID_PRIMAX
tristate "Primax non-fully HID-compliant devices"
depends on USB_HID
depends on HID
---help---
Support for Primax devices that are not fully compliant with the
HID standard.
config HID_PS3REMOTE
tristate "Sony PS3 BD Remote Control"
depends on BT_HIDP
depends on HID
---help---
Support for the Sony PS3 Blue-ray Disk Remote Control and Logitech
Harmony Adapter for PS3, which connect over Bluetooth.
@ -569,7 +580,7 @@ config HID_ROCCAT
config HID_SAITEK
tristate "Saitek non-fully HID-compliant devices"
depends on USB_HID
depends on HID
---help---
Support for Saitek devices that are not fully compliant with the
HID standard.
@ -578,7 +589,7 @@ config HID_SAITEK
config HID_SAMSUNG
tristate "Samsung InfraRed remote control or keyboards"
depends on USB_HID
depends on HID
---help---
Support for Samsung InfraRed remote control or keyboards.
@ -592,25 +603,25 @@ config HID_SONY
config HID_SPEEDLINK
tristate "Speedlink VAD Cezanne mouse support"
depends on USB_HID
depends on HID
---help---
Support for Speedlink Vicious and Divine Cezanne mouse.
config HID_STEELSERIES
tristate "Steelseries SRW-S1 steering wheel support"
depends on USB_HID
depends on HID
---help---
Support for Steelseries SRW-S1 steering wheel
config HID_SUNPLUS
tristate "Sunplus wireless desktop"
depends on USB_HID
depends on HID
---help---
Support for Sunplus wireless desktop.
config HID_GREENASIA
tristate "GreenAsia (Product ID 0x12) game controller support"
depends on USB_HID
depends on HID
---help---
Say Y here if you have a GreenAsia (Product ID 0x12) based game
controller or adapter.
@ -632,7 +643,7 @@ config HID_HYPERV_MOUSE
config HID_SMARTJOYPLUS
tristate "SmartJoy PLUS PS2/USB adapter support"
depends on USB_HID
depends on HID
---help---
Support for SmartJoy PLUS PS2/USB adapter, Super Dual Box,
Super Joy Box 3 Pro, Super Dual Box Pro, and Super Joy Box 5 Pro.
@ -650,20 +661,20 @@ config SMARTJOYPLUS_FF
config HID_TIVO
tristate "TiVo Slide Bluetooth remote control support"
depends on (USB_HID || BT_HIDP)
depends on HID
---help---
Say Y if you have a TiVo Slide Bluetooth remote control.
config HID_TOPSEED
tristate "TopSeed Cyberlink, BTC Emprex, Conceptronic remote control support"
depends on USB_HID
depends on HID
---help---
Say Y if you have a TopSeed Cyberlink or BTC Emprex or Conceptronic
CLLRCMCE remote control.
config HID_THINGM
tristate "ThingM blink(1) USB RGB LED"
depends on USB_HID
depends on HID
depends on LEDS_CLASS
---help---
Support for the ThingM blink(1) USB RGB LED. This driver registers a
@ -673,7 +684,7 @@ config HID_THINGM
config HID_THRUSTMASTER
tristate "ThrustMaster devices support"
depends on USB_HID
depends on HID
---help---
Say Y here if you have a THRUSTMASTER FireStore Dual Power 2 or
a THRUSTMASTER Ferrari GT Rumble Wheel.
@ -689,7 +700,7 @@ config THRUSTMASTER_FF
config HID_WACOM
tristate "Wacom Bluetooth devices support"
depends on BT_HIDP
depends on HID
depends on LEDS_CLASS
select POWER_SUPPLY
---help---
@ -697,7 +708,7 @@ config HID_WACOM
config HID_WIIMOTE
tristate "Nintendo Wii Remote support"
depends on BT_HIDP
depends on HID
depends on LEDS_CLASS
select POWER_SUPPLY
select INPUT_FF_MEMLESS
@ -715,7 +726,7 @@ config HID_WIIMOTE_EXT
config HID_ZEROPLUS
tristate "Zeroplus based game controller support"
depends on USB_HID
depends on HID
---help---
Say Y here if you have a Zeroplus based game controller.
@ -729,16 +740,16 @@ config ZEROPLUS_FF
config HID_ZYDACRON
tristate "Zydacron remote control support"
depends on USB_HID
depends on HID
---help---
Support for Zydacron remote control.
config HID_SENSOR_HUB
tristate "HID Sensors framework support"
depends on USB_HID && GENERIC_HARDIRQS
depends on HID && GENERIC_HARDIRQS
select MFD_CORE
default n
-- help---
---help---
Support for HID Sensor framework. This creates a MFD instance
for a sensor hub and identifies all the sensors connected to it.
Each sensor is registered as a MFD cell, so that sensor specific

View file

@ -39,6 +39,7 @@ endif
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
obj-$(CONFIG_HID_APPLEIR) += hid-appleir.o
obj-$(CONFIG_HID_AUREAL) += hid-aureal.o
obj-$(CONFIG_HID_BELKIN) += hid-belkin.o
obj-$(CONFIG_HID_CHERRY) += hid-cherry.o
@ -94,8 +95,8 @@ obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
obj-$(CONFIG_HID_PS3REMOTE) += hid-ps3remote.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
hid-roccat-arvo.o hid-roccat-isku.o hid-roccat-kone.o \
hid-roccat-koneplus.o hid-roccat-kovaplus.o hid-roccat-lua.o \
hid-roccat-pyra.o hid-roccat-savu.o
hid-roccat-koneplus.o hid-roccat-konepure.o hid-roccat-kovaplus.o \
hid-roccat-lua.o hid-roccat-pyra.o hid-roccat-savu.o
obj-$(CONFIG_HID_SAITEK) += hid-saitek.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o

View file

@ -21,7 +21,6 @@
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include "hid-ids.h"
@ -390,10 +389,6 @@ static void apple_remove(struct hid_device *hdev)
}
static const struct hid_device_id apple_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ATV_IRCONTROL),
.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4),
.driver_data = APPLE_HIDDEV | APPLE_IGNORE_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MIGHTYMOUSE),
.driver_data = APPLE_MIGHTYMOUSE | APPLE_INVERT_HWHEEL },

352
drivers/hid/hid-appleir.c Normal file
View file

@ -0,0 +1,352 @@
/*
* HID driver for the apple ir device
*
* Original driver written by James McKenzie
* Ported to recent 2.6 kernel versions by Greg Kroah-Hartman <gregkh@suse.de>
* Updated to support newer remotes by Bastien Nocera <hadess@hadess.net>
* Ported to HID subsystem by Benjamin Tissoires <benjamin.tissoires@gmail.com>
*
* Copyright (C) 2006 James McKenzie
* Copyright (C) 2008 Greg Kroah-Hartman <greg@kroah.com>
* Copyright (C) 2008 Novell Inc.
* Copyright (C) 2010, 2012 Bastien Nocera <hadess@hadess.net>
* Copyright (C) 2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (C) 2013 Red Hat Inc. All Rights Reserved
*
* This software is licensed under the terms of the GNU General Public
* License version 2, as published by the Free Software Foundation, and
* may be copied, distributed, and modified under those terms.
*
* 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.
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
MODULE_AUTHOR("James McKenzie");
MODULE_AUTHOR("Benjamin Tissoires <benjamin.tissoires@redhat.com>");
MODULE_DESCRIPTION("HID Apple IR remote controls");
MODULE_LICENSE("GPL");
#define KEY_MASK 0x0F
#define TWO_PACKETS_MASK 0x40
/*
* James McKenzie has two devices both of which report the following
* 25 87 ee 83 0a +
* 25 87 ee 83 0c -
* 25 87 ee 83 09 <<
* 25 87 ee 83 06 >>
* 25 87 ee 83 05 >"
* 25 87 ee 83 03 menu
* 26 00 00 00 00 for key repeat
*/
/*
* Thomas Glanzmann reports the following responses
* 25 87 ee ca 0b +
* 25 87 ee ca 0d -
* 25 87 ee ca 08 <<
* 25 87 ee ca 07 >>
* 25 87 ee ca 04 >"
* 25 87 ee ca 02 menu
* 26 00 00 00 00 for key repeat
*
* He also observes the following event sometimes
* sent after a key is release, which I interpret
* as a flat battery message
* 25 87 e0 ca 06 flat battery
*/
/*
* Alexandre Karpenko reports the following responses for Device ID 0x8242
* 25 87 ee 47 0b +
* 25 87 ee 47 0d -
* 25 87 ee 47 08 <<
* 25 87 ee 47 07 >>
* 25 87 ee 47 04 >"
* 25 87 ee 47 02 menu
* 26 87 ee 47 ** for key repeat (** is the code of the key being held)
*/
/*
* Bastien Nocera's remote
* 25 87 ee 91 5f followed by
* 25 87 ee 91 05 gives you >"
*
* 25 87 ee 91 5c followed by
* 25 87 ee 91 05 gives you the middle button
*/
/*
* Fabien Andre's remote
* 25 87 ee a3 5e followed by
* 25 87 ee a3 04 gives you >"
*
* 25 87 ee a3 5d followed by
* 25 87 ee a3 04 gives you the middle button
*/
static const unsigned short appleir_key_table[] = {
KEY_RESERVED,
KEY_MENU,
KEY_PLAYPAUSE,
KEY_FORWARD,
KEY_BACK,
KEY_VOLUMEUP,
KEY_VOLUMEDOWN,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_RESERVED,
KEY_ENTER,
KEY_PLAYPAUSE,
KEY_RESERVED,
};
struct appleir {
struct input_dev *input_dev;
struct hid_device *hid;
unsigned short keymap[ARRAY_SIZE(appleir_key_table)];
struct timer_list key_up_timer; /* timer for key up */
spinlock_t lock; /* protects .current_key */
int current_key; /* the currently pressed key */
int prev_key_idx; /* key index in a 2 packets message */
};
static int get_key(int data)
{
/*
* The key is coded accross bits 2..9:
*
* 0x00 or 0x01 ( ) key: 0 -> KEY_RESERVED
* 0x02 or 0x03 ( menu ) key: 1 -> KEY_MENU
* 0x04 or 0x05 ( >" ) key: 2 -> KEY_PLAYPAUSE
* 0x06 or 0x07 ( >> ) key: 3 -> KEY_FORWARD
* 0x08 or 0x09 ( << ) key: 4 -> KEY_BACK
* 0x0a or 0x0b ( + ) key: 5 -> KEY_VOLUMEUP
* 0x0c or 0x0d ( - ) key: 6 -> KEY_VOLUMEDOWN
* 0x0e or 0x0f ( ) key: 7 -> KEY_RESERVED
* 0x50 or 0x51 ( ) key: 8 -> KEY_RESERVED
* 0x52 or 0x53 ( ) key: 9 -> KEY_RESERVED
* 0x54 or 0x55 ( ) key: 10 -> KEY_RESERVED
* 0x56 or 0x57 ( ) key: 11 -> KEY_RESERVED
* 0x58 or 0x59 ( ) key: 12 -> KEY_RESERVED
* 0x5a or 0x5b ( ) key: 13 -> KEY_RESERVED
* 0x5c or 0x5d ( middle ) key: 14 -> KEY_ENTER
* 0x5e or 0x5f ( >" ) key: 15 -> KEY_PLAYPAUSE
*
* Packets starting with 0x5 are part of a two-packets message,
* we notify the caller by sending a negative value.
*/
int key = (data >> 1) & KEY_MASK;
if ((data & TWO_PACKETS_MASK))
/* Part of a 2 packets-command */
key = -key;
return key;
}
static void key_up(struct hid_device *hid, struct appleir *appleir, int key)
{
input_report_key(appleir->input_dev, key, 0);
input_sync(appleir->input_dev);
}
static void key_down(struct hid_device *hid, struct appleir *appleir, int key)
{
input_report_key(appleir->input_dev, key, 1);
input_sync(appleir->input_dev);
}
static void battery_flat(struct appleir *appleir)
{
dev_err(&appleir->input_dev->dev, "possible flat battery?\n");
}
static void key_up_tick(unsigned long data)
{
struct appleir *appleir = (struct appleir *)data;
struct hid_device *hid = appleir->hid;
unsigned long flags;
spin_lock_irqsave(&appleir->lock, flags);
if (appleir->current_key) {
key_up(hid, appleir, appleir->current_key);
appleir->current_key = 0;
}
spin_unlock_irqrestore(&appleir->lock, flags);
}
static int appleir_raw_event(struct hid_device *hid, struct hid_report *report,
u8 *data, int len)
{
struct appleir *appleir = hid_get_drvdata(hid);
static const u8 keydown[] = { 0x25, 0x87, 0xee };
static const u8 keyrepeat[] = { 0x26, };
static const u8 flatbattery[] = { 0x25, 0x87, 0xe0 };
unsigned long flags;
if (len != 5)
goto out;
if (!memcmp(data, keydown, sizeof(keydown))) {
int index;
spin_lock_irqsave(&appleir->lock, flags);
/*
* If we already have a key down, take it up before marking
* this one down
*/
if (appleir->current_key)
key_up(hid, appleir, appleir->current_key);
/* Handle dual packet commands */
if (appleir->prev_key_idx > 0)
index = appleir->prev_key_idx;
else
index = get_key(data[4]);
if (index >= 0) {
appleir->current_key = appleir->keymap[index];
key_down(hid, appleir, appleir->current_key);
/*
* Remote doesn't do key up, either pull them up, in
* the test above, or here set a timer which pulls
* them up after 1/8 s
*/
mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
appleir->prev_key_idx = 0;
} else
/* Remember key for next packet */
appleir->prev_key_idx = -index;
spin_unlock_irqrestore(&appleir->lock, flags);
goto out;
}
appleir->prev_key_idx = 0;
if (!memcmp(data, keyrepeat, sizeof(keyrepeat))) {
key_down(hid, appleir, appleir->current_key);
/*
* Remote doesn't do key up, either pull them up, in the test
* above, or here set a timer which pulls them up after 1/8 s
*/
mod_timer(&appleir->key_up_timer, jiffies + HZ / 8);
goto out;
}
if (!memcmp(data, flatbattery, sizeof(flatbattery))) {
battery_flat(appleir);
/* Fall through */
}
out:
/* let hidraw and hiddev handle the report */
return 0;
}
static void appleir_input_configured(struct hid_device *hid,
struct hid_input *hidinput)
{
struct input_dev *input_dev = hidinput->input;
struct appleir *appleir = hid_get_drvdata(hid);
int i;
appleir->input_dev = input_dev;
input_dev->keycode = appleir->keymap;
input_dev->keycodesize = sizeof(unsigned short);
input_dev->keycodemax = ARRAY_SIZE(appleir->keymap);
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
memcpy(appleir->keymap, appleir_key_table, sizeof(appleir->keymap));
for (i = 0; i < ARRAY_SIZE(appleir_key_table); i++)
set_bit(appleir->keymap[i], input_dev->keybit);
clear_bit(KEY_RESERVED, input_dev->keybit);
}
static int appleir_input_mapping(struct hid_device *hid,
struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max)
{
return -1;
}
static int appleir_probe(struct hid_device *hid, const struct hid_device_id *id)
{
int ret;
struct appleir *appleir;
appleir = kzalloc(sizeof(struct appleir), GFP_KERNEL);
if (!appleir) {
ret = -ENOMEM;
goto allocfail;
}
appleir->hid = hid;
spin_lock_init(&appleir->lock);
setup_timer(&appleir->key_up_timer,
key_up_tick, (unsigned long) appleir);
hid_set_drvdata(hid, appleir);
ret = hid_parse(hid);
if (ret) {
hid_err(hid, "parse failed\n");
goto fail;
}
ret = hid_hw_start(hid, HID_CONNECT_DEFAULT | HID_CONNECT_HIDDEV_FORCE);
if (ret) {
hid_err(hid, "hw start failed\n");
goto fail;
}
return 0;
fail:
kfree(appleir);
allocfail:
return ret;
}
static void appleir_remove(struct hid_device *hid)
{
struct appleir *appleir = hid_get_drvdata(hid);
hid_hw_stop(hid);
del_timer_sync(&appleir->key_up_timer);
kfree(appleir);
}
static const struct hid_device_id appleir_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
{ }
};
MODULE_DEVICE_TABLE(hid, appleir_devices);
static struct hid_driver appleir_driver = {
.name = "appleir",
.id_table = appleir_devices,
.raw_event = appleir_raw_event,
.input_configured = appleir_input_configured,
.probe = appleir_probe,
.remove = appleir_remove,
.input_mapping = appleir_input_mapping,
};
module_hid_driver(appleir_driver);

View file

@ -29,14 +29,12 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
#ifdef CONFIG_HID_ACRUX_FF
#include "usbhid/usbhid.h"
struct axff_device {
struct hid_report *report;
@ -68,7 +66,7 @@ static int axff_play(struct input_dev *dev, void *data, struct ff_effect *effect
}
dbg_hid("running with 0x%02x 0x%02x", left, right);
usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
hid_hw_request(hid, axff->report, HID_REQ_SET_REPORT);
return 0;
}
@ -114,7 +112,7 @@ static int axff_init(struct hid_device *hid)
goto err_free_mem;
axff->report = report;
usbhid_submit_report(hid, axff->report, USB_DIR_OUT);
hid_hw_request(hid, axff->report, HID_REQ_SET_REPORT);
hid_info(hid, "Force Feedback for ACRUX game controllers by Sergei Kolzun <x0r@dv-life.ru>\n");

View file

@ -728,8 +728,7 @@ static int hid_scan_report(struct hid_device *hid)
} else if (page == HID_UP_SENSOR &&
item.type == HID_ITEM_TYPE_MAIN &&
item.tag == HID_MAIN_ITEM_TAG_BEGIN_COLLECTION &&
(item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL &&
(hid->bus == BUS_USB || hid->bus == BUS_I2C))
(item_udata(&item) & 0xff) == HID_COLLECTION_PHYSICAL)
hid->group = HID_GROUP_SENSOR_HUB;
}
@ -1260,14 +1259,12 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
struct hid_report_enum *report_enum;
struct hid_driver *hdrv;
struct hid_report *report;
char *buf;
unsigned int i;
int ret = 0;
if (!hid)
return -ENODEV;
if (down_trylock(&hid->driver_lock))
if (down_trylock(&hid->driver_input_lock))
return -EBUSY;
if (!hid->driver) {
@ -1284,28 +1281,9 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
}
/* Avoid unnecessary overhead if debugfs is disabled */
if (list_empty(&hid->debug_list))
goto nomem;
if (!list_empty(&hid->debug_list))
hid_dump_report(hid, type, data, size);
buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
if (!buf)
goto nomem;
/* dump the report */
snprintf(buf, HID_DEBUG_BUFSIZE - 1,
"\nreport (size %u) (%snumbered) = ", size, report_enum->numbered ? "" : "un");
hid_debug_event(hid, buf);
for (i = 0; i < size; i++) {
snprintf(buf, HID_DEBUG_BUFSIZE - 1,
" %02x", data[i]);
hid_debug_event(hid, buf);
}
hid_debug_event(hid, "\n");
kfree(buf);
nomem:
report = hid_get_report(report_enum, data);
if (!report) {
@ -1324,7 +1302,7 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
ret = hid_report_raw_event(hid, type, data, size, interrupt);
unlock:
up(&hid->driver_lock);
up(&hid->driver_input_lock);
return ret;
}
EXPORT_SYMBOL_GPL(hid_input_report);
@ -1502,8 +1480,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ 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) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ACRUX, 0x0802) },
{ 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) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
@ -1527,6 +1503,11 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER4_HF_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_IRCONTROL5) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS) },
@ -1654,6 +1635,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_COMFORT_MOUSE_4500) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_SIDEWINDER_GV) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB) },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_DIGITAL_MEDIA_3K) },
@ -1687,6 +1669,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ARVO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_LUA) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
@ -1747,6 +1730,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO, USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
{ }
};
@ -1845,6 +1829,11 @@ static int hid_device_probe(struct device *dev)
if (down_interruptible(&hdev->driver_lock))
return -EINTR;
if (down_interruptible(&hdev->driver_input_lock)) {
ret = -EINTR;
goto unlock_driver_lock;
}
hdev->io_started = false;
if (!hdev->driver) {
id = hid_match_device(hdev, hdrv);
@ -1867,6 +1856,9 @@ static int hid_device_probe(struct device *dev)
}
}
unlock:
if (!hdev->io_started)
up(&hdev->driver_input_lock);
unlock_driver_lock:
up(&hdev->driver_lock);
return ret;
}
@ -1875,9 +1867,15 @@ static int hid_device_remove(struct device *dev)
{
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct hid_driver *hdrv;
int ret = 0;
if (down_interruptible(&hdev->driver_lock))
return -EINTR;
if (down_interruptible(&hdev->driver_input_lock)) {
ret = -EINTR;
goto unlock_driver_lock;
}
hdev->io_started = false;
hdrv = hdev->driver;
if (hdrv) {
@ -1889,8 +1887,11 @@ static int hid_device_remove(struct device *dev)
hdev->driver = NULL;
}
if (!hdev->io_started)
up(&hdev->driver_input_lock);
unlock_driver_lock:
up(&hdev->driver_lock);
return 0;
return ret;
}
static ssize_t modalias_show(struct device *dev, struct device_attribute *a,
@ -2340,7 +2341,9 @@ struct hid_device *hid_allocate_device(void)
init_waitqueue_head(&hdev->debug_wait);
INIT_LIST_HEAD(&hdev->debug_list);
mutex_init(&hdev->debug_list_lock);
sema_init(&hdev->driver_lock, 1);
sema_init(&hdev->driver_input_lock, 1);
return hdev;
}

View file

@ -580,17 +580,49 @@ void hid_debug_event(struct hid_device *hdev, char *buf)
int i;
struct hid_debug_list *list;
mutex_lock(&hdev->debug_list_lock);
list_for_each_entry(list, &hdev->debug_list, node) {
for (i = 0; i < strlen(buf); i++)
list->hid_debug_buf[(list->tail + i) % HID_DEBUG_BUFSIZE] =
buf[i];
list->tail = (list->tail + i) % HID_DEBUG_BUFSIZE;
}
mutex_unlock(&hdev->debug_list_lock);
wake_up_interruptible(&hdev->debug_wait);
}
EXPORT_SYMBOL_GPL(hid_debug_event);
void hid_dump_report(struct hid_device *hid, int type, u8 *data,
int size)
{
struct hid_report_enum *report_enum;
char *buf;
unsigned int i;
buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
if (!buf)
return;
report_enum = hid->report_enum + type;
/* dump the report */
snprintf(buf, HID_DEBUG_BUFSIZE - 1,
"\nreport (size %u) (%snumbered) = ", size,
report_enum->numbered ? "" : "un");
hid_debug_event(hid, buf);
for (i = 0; i < size; i++) {
snprintf(buf, HID_DEBUG_BUFSIZE - 1,
" %02x", data[i]);
hid_debug_event(hid, buf);
}
hid_debug_event(hid, "\n");
kfree(buf);
}
EXPORT_SYMBOL_GPL(hid_dump_report);
void hid_dump_input(struct hid_device *hdev, struct hid_usage *usage, __s32 value)
{
char *buf;
@ -960,7 +992,9 @@ static int hid_debug_events_open(struct inode *inode, struct file *file)
file->private_data = list;
mutex_init(&list->read_mutex);
mutex_lock(&list->hdev->debug_list_lock);
list_add_tail(&list->node, &list->hdev->debug_list);
mutex_unlock(&list->hdev->debug_list_lock);
out:
return err;
@ -1055,7 +1089,9 @@ static int hid_debug_events_release(struct inode *inode, struct file *file)
{
struct hid_debug_list *list = file->private_data;
mutex_lock(&list->hdev->debug_list_lock);
list_del(&list->node);
mutex_unlock(&list->hdev->debug_list_lock);
kfree(list->hid_debug_buf);
kfree(list);

View file

@ -29,14 +29,12 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
#ifdef CONFIG_DRAGONRISE_FF
#include "usbhid/usbhid.h"
struct drff_device {
struct hid_report *report;
@ -68,7 +66,7 @@ static int drff_play(struct input_dev *dev, void *data,
drff->report->field[0]->value[1] = 0x00;
drff->report->field[0]->value[2] = weak;
drff->report->field[0]->value[4] = strong;
usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
drff->report->field[0]->value[0] = 0xfa;
drff->report->field[0]->value[1] = 0xfe;
@ -80,7 +78,7 @@ static int drff_play(struct input_dev *dev, void *data,
drff->report->field[0]->value[2] = 0x00;
drff->report->field[0]->value[4] = 0x00;
dbg_hid("running with 0x%02x 0x%02x", strong, weak);
usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
return 0;
}
@ -132,7 +130,7 @@ static int drff_init(struct hid_device *hid)
drff->report->field[0]->value[4] = 0x00;
drff->report->field[0]->value[5] = 0x00;
drff->report->field[0]->value[6] = 0x00;
usbhid_submit_report(hid, drff->report, USB_DIR_OUT);
hid_hw_request(hid, drff->report, HID_REQ_SET_REPORT);
hid_info(hid, "Force Feedback for DragonRise Inc. "
"game controllers by Richard Walmsley <richwalm@gmail.com>\n");

View file

@ -23,11 +23,9 @@
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/module.h>
#include "hid-ids.h"
#include "usbhid/usbhid.h"
struct emsff_device {
struct hid_report *report;
@ -52,7 +50,7 @@ static int emsff_play(struct input_dev *dev, void *data,
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);
hid_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
return 0;
}
@ -104,7 +102,7 @@ static int emsff_init(struct hid_device *hid)
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_hw_request(hid, emsff->report, HID_REQ_SET_REPORT);
hid_info(hid, "force feedback for EMS based devices by Ignaz Forster <ignaz.forster@gmx.de>\n");

View file

@ -29,13 +29,11 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
#ifdef CONFIG_GREENASIA_FF
#include "usbhid/usbhid.h"
struct gaff_device {
struct hid_report *report;
@ -63,14 +61,14 @@ static int hid_gaff_play(struct input_dev *dev, void *data,
gaff->report->field[0]->value[4] = left;
gaff->report->field[0]->value[5] = 0;
dbg_hid("running with 0x%02x 0x%02x", left, right);
usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
gaff->report->field[0]->value[0] = 0xfa;
gaff->report->field[0]->value[1] = 0xfe;
gaff->report->field[0]->value[2] = 0x0;
gaff->report->field[0]->value[4] = 0x0;
usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
return 0;
}
@ -122,12 +120,12 @@ static int gaff_init(struct hid_device *hid)
gaff->report->field[0]->value[1] = 0x00;
gaff->report->field[0]->value[2] = 0x00;
gaff->report->field[0]->value[3] = 0x00;
usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
gaff->report->field[0]->value[0] = 0xfa;
gaff->report->field[0]->value[1] = 0xfe;
usbhid_submit_report(hid, gaff->report, USB_DIR_OUT);
hid_hw_request(hid, gaff->report, HID_REQ_SET_REPORT);
hid_info(hid, "Force Feedback for GreenAsia 0x12 devices by Lukasz Lubojanski <lukasz@lubojanski.info>\n");

View file

@ -27,12 +27,10 @@
#include <linux/input.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include "hid-ids.h"
#ifdef CONFIG_HOLTEK_FF
#include "usbhid/usbhid.h"
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Anssi Hannula <anssi.hannula@iki.fi>");
@ -102,7 +100,7 @@ static void holtekff_send(struct holtekff_device *holtekff,
dbg_hid("sending %*ph\n", 7, data);
usbhid_submit_report(hid, holtekff->field->report, USB_DIR_OUT);
hid_hw_request(hid, holtekff->field->report, HID_REQ_SET_REPORT);
}
static int holtekff_play(struct input_dev *dev, void *data,

View file

@ -159,7 +159,7 @@ static const struct icade_key icade_usage_table[30] = {
static const struct icade_key *icade_find_translation(u16 from)
{
if (from < 0 || from > ICADE_MAX_USAGE)
if (from > ICADE_MAX_USAGE)
return NULL;
return &icade_usage_table[from];
}

View file

@ -137,8 +137,11 @@
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO 0x0256
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
#define USB_DEVICE_ID_APPLE_ATV_IRCONTROL 0x8241
#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240
#define USB_DEVICE_ID_APPLE_IRCONTROL2 0x1440
#define USB_DEVICE_ID_APPLE_IRCONTROL3 0x8241
#define USB_DEVICE_ID_APPLE_IRCONTROL4 0x8242
#define USB_DEVICE_ID_APPLE_IRCONTROL5 0x8243
#define USB_VENDOR_ID_ASUS 0x0486
#define USB_DEVICE_ID_ASUS_T91MT 0x0185
@ -577,6 +580,7 @@
#define USB_DEVICE_ID_SIDEWINDER_GV 0x003b
#define USB_DEVICE_ID_WIRELESS_OPTICAL_DESKTOP_3_0 0x009d
#define USB_DEVICE_ID_MS_NE4K 0x00db
#define USB_DEVICE_ID_MS_NE4K_JP 0x00dc
#define USB_DEVICE_ID_MS_LK6K 0x00f9
#define USB_DEVICE_ID_MS_PRESENTER_8K_BT 0x0701
#define USB_DEVICE_ID_MS_PRESENTER_8K_USB 0x0713
@ -613,6 +617,7 @@
#define USB_VENDOR_ID_NINTENDO 0x057e
#define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306
#define USB_DEVICE_ID_NINTENDO_WIIMOTE2 0x0330
#define USB_VENDOR_ID_NOVATEK 0x0603
#define USB_DEVICE_ID_NOVATEK_PCT 0x0600
@ -692,8 +697,10 @@
#define USB_VENDOR_ID_ROCCAT 0x1e7d
#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4
#define USB_DEVICE_ID_ROCCAT_ISKU 0x319c
#define USB_DEVICE_ID_ROCCAT_ISKUFX 0x3264
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
#define USB_DEVICE_ID_ROCCAT_KONEPURE 0x2dbe
#define USB_DEVICE_ID_ROCCAT_KONEXTD 0x2e22
#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
#define USB_DEVICE_ID_ROCCAT_LUA 0x2c2e

View file

@ -1198,6 +1198,67 @@ static struct hid_input *hidinput_allocate(struct hid_device *hid)
return hidinput;
}
static bool hidinput_has_been_populated(struct hid_input *hidinput)
{
int i;
unsigned long r = 0;
for (i = 0; i < BITS_TO_LONGS(EV_CNT); i++)
r |= hidinput->input->evbit[i];
for (i = 0; i < BITS_TO_LONGS(KEY_CNT); i++)
r |= hidinput->input->keybit[i];
for (i = 0; i < BITS_TO_LONGS(REL_CNT); i++)
r |= hidinput->input->relbit[i];
for (i = 0; i < BITS_TO_LONGS(ABS_CNT); i++)
r |= hidinput->input->absbit[i];
for (i = 0; i < BITS_TO_LONGS(MSC_CNT); i++)
r |= hidinput->input->mscbit[i];
for (i = 0; i < BITS_TO_LONGS(LED_CNT); i++)
r |= hidinput->input->ledbit[i];
for (i = 0; i < BITS_TO_LONGS(SND_CNT); i++)
r |= hidinput->input->sndbit[i];
for (i = 0; i < BITS_TO_LONGS(FF_CNT); i++)
r |= hidinput->input->ffbit[i];
for (i = 0; i < BITS_TO_LONGS(SW_CNT); i++)
r |= hidinput->input->swbit[i];
return !!r;
}
static void hidinput_cleanup_hidinput(struct hid_device *hid,
struct hid_input *hidinput)
{
struct hid_report *report;
int i, k;
list_del(&hidinput->list);
input_free_device(hidinput->input);
for (k = HID_INPUT_REPORT; k <= HID_OUTPUT_REPORT; k++) {
if (k == HID_OUTPUT_REPORT &&
hid->quirks & HID_QUIRK_SKIP_OUTPUT_REPORTS)
continue;
list_for_each_entry(report, &hid->report_enum[k].report_list,
list) {
for (i = 0; i < report->maxfield; i++)
if (report->field[i]->hidinput == hidinput)
report->field[i]->hidinput = NULL;
}
}
kfree(hidinput);
}
/*
* Register the input device; print a message.
* Configure the input layer interface
@ -1249,6 +1310,10 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
hidinput_configure_usage(hidinput, report->field[i],
report->field[i]->usage + j);
if ((hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
!hidinput_has_been_populated(hidinput))
continue;
if (hid->quirks & HID_QUIRK_MULTI_INPUT) {
/* This will leave hidinput NULL, so that it
* allocates another one if we have more inputs on
@ -1265,6 +1330,18 @@ int hidinput_connect(struct hid_device *hid, unsigned int force)
}
}
if (hidinput && (hid->quirks & HID_QUIRK_NO_EMPTY_INPUT) &&
!hidinput_has_been_populated(hidinput)) {
/* no need to register an input device not populated */
hidinput_cleanup_hidinput(hid, hidinput);
hidinput = NULL;
}
if (list_empty(&hid->inputs)) {
hid_err(hid, "No inputs registered, leaving\n");
goto out_unwind;
}
if (hidinput) {
if (drv->input_configured)
drv->input_configured(hid, hidinput);

View file

@ -16,8 +16,6 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/usb.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h"
@ -361,7 +359,7 @@ static int kye_tablet_enable(struct hid_device *hdev)
value[4] = 0x00;
value[5] = 0x00;
value[6] = 0x00;
usbhid_submit_report(hdev, report, USB_DIR_OUT);
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
return 0;
}

View file

@ -68,7 +68,7 @@ static int tpkbd_features_set(struct hid_device *hdev)
report->field[2]->value[0] = data_pointer->sensitivity;
report->field[3]->value[0] = data_pointer->press_speed;
usbhid_submit_report(hdev, report, USB_DIR_OUT);
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
return 0;
}
@ -228,8 +228,6 @@ static ssize_t pointer_press_speed_show(struct device *dev,
struct hid_device *hdev = container_of(dev, struct hid_device, dev);
struct tpkbd_data_pointer *data_pointer = hid_get_drvdata(hdev);
data_pointer = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n",
data_pointer->press_speed);
}
@ -332,7 +330,7 @@ static void tpkbd_led_brightness_set(struct led_classdev *led_cdev,
report = hdev->report_enum[HID_OUTPUT_REPORT].report_id_hash[3];
report->field[0]->value[0] = (data_pointer->led_state >> 0) & 1;
report->field[0]->value[1] = (data_pointer->led_state >> 1) & 1;
usbhid_submit_report(hdev, report, USB_DIR_OUT);
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
}
static int tpkbd_probe_tp(struct hid_device *hdev)

View file

@ -23,10 +23,8 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include "usbhid/usbhid.h"
#include "hid-lg.h"
struct lg2ff_device {
@ -56,7 +54,7 @@ static int play_effect(struct input_dev *dev, void *data,
lg2ff->report->field[0]->value[4] = 0x00;
}
usbhid_submit_report(hid, lg2ff->report, USB_DIR_OUT);
hid_hw_request(hid, lg2ff->report, HID_REQ_SET_REPORT);
return 0;
}
@ -108,7 +106,7 @@ int lg2ff_init(struct hid_device *hid)
report->field[0]->value[5] = 0x00;
report->field[0]->value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
hid_info(hid, "Force feedback for Logitech RumblePad/Rumblepad 2 by Anssi Hannula <anssi.hannula@gmail.com>\n");

View file

@ -22,10 +22,8 @@
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include "usbhid/usbhid.h"
#include "hid-lg.h"
/*
@ -92,7 +90,7 @@ static int hid_lg3ff_play(struct input_dev *dev, void *data,
report->field[0]->value[1] = (unsigned char)(-x);
report->field[0]->value[31] = (unsigned char)(-y);
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
}
return 0;
@ -118,7 +116,7 @@ static void hid_lg3ff_set_autocenter(struct input_dev *dev, u16 magnitude)
report->field[0]->value[33] = 0x7F;
report->field[0]->value[34] = 0x7F;
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}

View file

@ -34,6 +34,7 @@
#define DFGT_REV_MAJ 0x13
#define DFGT_REV_MIN 0x22
#define DFGT2_REV_MIN 0x26
#define DFP_REV_MAJ 0x11
#define DFP_REV_MIN 0x06
#define FFEX_REV_MAJ 0x21
@ -125,6 +126,7 @@ static const struct lg4ff_native_cmd native_g27 = {
static const struct lg4ff_usb_revision lg4ff_revs[] = {
{DFGT_REV_MAJ, DFGT_REV_MIN, &native_dfgt}, /* Driving Force GT */
{DFGT_REV_MAJ, DFGT2_REV_MIN, &native_dfgt}, /* Driving Force GT v2 */
{DFP_REV_MAJ, DFP_REV_MIN, &native_dfp}, /* Driving Force Pro */
{G25_REV_MAJ, G25_REV_MIN, &native_g25}, /* G25 */
{G27_REV_MAJ, G27_REV_MIN, &native_g27}, /* G27 */
@ -202,7 +204,7 @@ static int hid_lg4ff_play(struct input_dev *dev, void *data, struct ff_effect *e
value[5] = 0x00;
value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
}
return 0;
@ -225,7 +227,7 @@ static void hid_lg4ff_set_autocenter_default(struct input_dev *dev, u16 magnitud
value[5] = 0x00;
value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
/* Sends autocentering command compatible with Formula Force EX */
@ -245,7 +247,7 @@ static void hid_lg4ff_set_autocenter_ffex(struct input_dev *dev, u16 magnitude)
value[5] = 0x00;
value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
/* Sends command to set range compatible with G25/G27/Driving Force GT */
@ -265,7 +267,7 @@ static void hid_lg4ff_set_range_g25(struct hid_device *hid, u16 range)
value[5] = 0x00;
value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
/* Sends commands to set range compatible with Driving Force Pro wheel */
@ -294,7 +296,7 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
report->field[0]->value[1] = 0x02;
full_range = 200;
}
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
/* Prepare "fine" limit command */
value[0] = 0x81;
@ -306,7 +308,7 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
value[6] = 0x00;
if (range == 200 || range == 900) { /* Do not apply any fine limit */
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
return;
}
@ -320,7 +322,7 @@ static void hid_lg4ff_set_range_dfp(struct hid_device *hid, __u16 range)
value[5] = (start_right & 0xe) << 4 | (start_left & 0xe);
value[6] = 0xff;
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_native_cmd *cmd)
@ -334,7 +336,7 @@ static void hid_lg4ff_switch_native(struct hid_device *hid, const struct lg4ff_n
for (i = 0; i < 7; i++)
report->field[0]->value[i] = cmd->cmd[j++];
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
}
@ -410,7 +412,7 @@ static void lg4ff_set_leds(struct hid_device *hid, __u8 leds)
value[4] = 0x00;
value[5] = 0x00;
value[6] = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
static void lg4ff_led_set_brightness(struct led_classdev *led_cdev,

View file

@ -30,10 +30,8 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include "usbhid/usbhid.h"
#include "hid-lg.h"
struct dev_type {
@ -89,7 +87,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
report->field[0]->value[2] = x;
report->field[0]->value[3] = y;
dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
case FF_RUMBLE:
@ -104,7 +102,7 @@ static int hid_lgff_play(struct input_dev *dev, void *data, struct ff_effect *ef
report->field[0]->value[2] = left;
report->field[0]->value[3] = right;
dbg_hid("(left, right)=(%04x, %04x)\n", left, right);
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
break;
}
return 0;
@ -124,7 +122,7 @@ static void hid_lgff_set_autocenter(struct input_dev *dev, u16 magnitude)
*value++ = 0x80;
*value++ = 0x00;
*value = 0x00;
usbhid_submit_report(hid, report, USB_DIR_OUT);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
}
int lgff_init(struct hid_device* hid)

View file

@ -27,7 +27,6 @@
#include <linux/module.h>
#include <linux/usb.h>
#include <asm/unaligned.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h"
#include "hid-logitech-dj.h"
@ -193,7 +192,6 @@ static struct hid_ll_driver logi_dj_ll_driver;
static int logi_dj_output_hidraw_report(struct hid_device *hid, u8 * buf,
size_t count,
unsigned char report_type);
static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev);
static void logi_dj_recv_destroy_djhid_device(struct dj_receiver_dev *djrcv_dev,
struct dj_report *dj_report)
@ -234,7 +232,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
if (dj_report->report_params[DEVICE_PAIRED_PARAM_SPFUNCTION] &
SPFUNCTION_DEVICE_LIST_EMPTY) {
dbg_hid("%s: device list is empty\n", __func__);
djrcv_dev->querying_devices = false;
return;
}
@ -245,12 +242,6 @@ static void logi_dj_recv_add_djhid_device(struct dj_receiver_dev *djrcv_dev,
return;
}
if (djrcv_dev->paired_dj_devices[dj_report->device_index]) {
/* The device is already known. No need to reallocate it. */
dbg_hid("%s: device is already known\n", __func__);
return;
}
dj_hiddev = hid_allocate_device();
if (IS_ERR(dj_hiddev)) {
dev_err(&djrcv_hdev->dev, "%s: hid_allocate_device failed\n",
@ -314,7 +305,6 @@ static void delayedwork_callback(struct work_struct *work)
struct dj_report dj_report;
unsigned long flags;
int count;
int retval;
dbg_hid("%s\n", __func__);
@ -347,25 +337,6 @@ static void delayedwork_callback(struct work_struct *work)
logi_dj_recv_destroy_djhid_device(djrcv_dev, &dj_report);
break;
default:
/* A normal report (i. e. not belonging to a pair/unpair notification)
* arriving here, means that the report arrived but we did not have a
* paired dj_device associated to the report's device_index, this
* means that the original "device paired" notification corresponding
* to this dj_device never arrived to this driver. The reason is that
* hid-core discards all packets coming from a device while probe() is
* executing. */
if (!djrcv_dev->paired_dj_devices[dj_report.device_index]) {
/* ok, we don't know the device, just re-ask the
* receiver for the list of connected devices. */
retval = logi_dj_recv_query_paired_devices(djrcv_dev);
if (!retval) {
/* everything went fine, so just leave */
break;
}
dev_err(&djrcv_dev->hdev->dev,
"%s:logi_dj_recv_query_paired_devices "
"error:%d\n", __func__, retval);
}
dbg_hid("%s: unexpected report type\n", __func__);
}
}
@ -396,12 +367,6 @@ static void logi_dj_recv_forward_null_report(struct dj_receiver_dev *djrcv_dev,
if (!djdev) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index);
kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
if (schedule_work(&djrcv_dev->work) == 0) {
dbg_hid("%s: did not schedule the work item, was already "
"queued\n", __func__);
}
return;
}
@ -432,12 +397,6 @@ static void logi_dj_recv_forward_report(struct dj_receiver_dev *djrcv_dev,
if (dj_device == NULL) {
dbg_hid("djrcv_dev->paired_dj_devices[dj_report->device_index]"
" is NULL, index %d\n", dj_report->device_index);
kfifo_in(&djrcv_dev->notif_fifo, dj_report, sizeof(struct dj_report));
if (schedule_work(&djrcv_dev->work) == 0) {
dbg_hid("%s: did not schedule the work item, was already "
"queued\n", __func__);
}
return;
}
@ -475,7 +434,7 @@ static int logi_dj_recv_send_report(struct dj_receiver_dev *djrcv_dev,
for (i = 0; i < report->field[0]->report_count; i++)
report->field[0]->value[i] = data[i];
usbhid_submit_report(hdev, report, USB_DIR_OUT);
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
return 0;
}
@ -485,10 +444,6 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
struct dj_report *dj_report;
int retval;
/* no need to protect djrcv_dev->querying_devices */
if (djrcv_dev->querying_devices)
return 0;
dj_report = kzalloc(sizeof(struct dj_report), GFP_KERNEL);
if (!dj_report)
return -ENOMEM;
@ -500,7 +455,6 @@ static int logi_dj_recv_query_paired_devices(struct dj_receiver_dev *djrcv_dev)
return retval;
}
static int logi_dj_recv_switch_to_dj_mode(struct dj_receiver_dev *djrcv_dev,
unsigned timeout)
{
@ -644,7 +598,7 @@ static int logi_dj_ll_input_event(struct input_dev *dev, unsigned int type,
hid_set_field(report->field[0], 1, REPORT_TYPE_LEDS);
hid_set_field(report->field[0], 2, data[1]);
usbhid_submit_report(dj_rcv_hiddev, report, USB_DIR_OUT);
hid_hw_request(dj_rcv_hiddev, report, HID_REQ_SET_REPORT);
return 0;
@ -809,6 +763,9 @@ static int logi_dj_probe(struct hid_device *hdev,
goto llopen_failed;
}
/* Allow incoming packets to arrive: */
hid_device_io_start(hdev);
retval = logi_dj_recv_query_paired_devices(djrcv_dev);
if (retval < 0) {
dev_err(&hdev->dev, "%s:logi_dj_recv_query_paired_devices "

View file

@ -101,7 +101,6 @@ struct dj_receiver_dev {
struct work_struct work;
struct kfifo notif_fifo;
spinlock_t lock;
bool querying_devices;
};
struct dj_device {

View file

@ -19,7 +19,6 @@
#include <linux/input/mt.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include "hid-ids.h"

View file

@ -195,6 +195,8 @@ static const struct hid_device_id ms_devices[] = {
.driver_data = MS_HIDINPUT },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K),
.driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_NE4K_JP),
.driver_data = MS_ERGONOMY },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_LK6K),
.driver_data = MS_ERGONOMY | MS_RDESC },
{ HID_USB_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_USB),

View file

@ -2,8 +2,9 @@
* HID driver for multitouch panels
*
* Copyright (c) 2010-2012 Stephane Chatty <chatty@enac.fr>
* Copyright (c) 2010-2012 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2010-2013 Benjamin Tissoires <benjamin.tissoires@gmail.com>
* Copyright (c) 2010-2012 Ecole Nationale de l'Aviation Civile, France
* Copyright (c) 2012-2013 Red Hat, Inc
*
* This code is partly based on hid-egalax.c:
*
@ -26,13 +27,24 @@
* any later version.
*/
/*
* This driver is regularly tested thanks to the tool hid-test[1].
* This tool relies on hid-replay[2] and a database of hid devices[3].
* Please run these regression tests before patching this module so that
* your patch won't break existing known devices.
*
* [1] https://github.com/bentiss/hid-test
* [2] https://github.com/bentiss/hid-replay
* [3] https://github.com/bentiss/hid-devices
*/
#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"
#include <linux/string.h>
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
@ -86,9 +98,9 @@ struct mt_device {
multitouch fields */
int cc_index; /* contact count field index in the report */
int cc_value_index; /* contact count value index in the field */
unsigned last_field_index; /* last field index of the report */
unsigned last_slot_field; /* the last field of a slot */
unsigned mt_report_id; /* the report ID of the multitouch device */
unsigned pen_report_id; /* the report ID of the pen device */
__s8 inputmode; /* InputMode HID feature, -1 if non-existent */
__s8 inputmode_index; /* InputMode HID feature index in the report */
__s8 maxcontact_report_id; /* Maximum Contact Number HID feature,
@ -104,6 +116,9 @@ struct mt_device {
unsigned mt_flags; /* flags to pass to input-mt */
};
static void mt_post_parse_default_settings(struct mt_device *td);
static void mt_post_parse(struct mt_device *td);
/* classes of device behavior */
#define MT_CLS_DEFAULT 0x0001
@ -246,6 +261,14 @@ static struct mt_class mt_classes[] = {
{ }
};
static void mt_free_input_name(struct hid_input *hi)
{
struct hid_device *hdev = hi->report->device;
if (hi->input->name != hdev->name)
kfree(hi->input->name);
}
static ssize_t mt_show_quirks(struct device *dev,
struct device_attribute *attr,
char *buf)
@ -354,7 +377,53 @@ static void mt_store_field(struct hid_usage *usage, struct mt_device *td,
f->usages[f->length++] = usage->hid;
}
static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
static int mt_pen_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);
td->pen_report_id = field->report->id;
return 0;
}
static int mt_pen_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
return 0;
}
static int mt_pen_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
/* let hid-input handle it */
return 0;
}
static void mt_pen_report(struct hid_device *hid, struct hid_report *report)
{
struct hid_field *field = report->field[0];
input_sync(field->hidinput->input);
}
static void mt_pen_input_configured(struct hid_device *hdev,
struct hid_input *hi)
{
char *name = kzalloc(strlen(hi->input->name) + 5, GFP_KERNEL);
if (name) {
sprintf(name, "%s Pen", hi->input->name);
mt_free_input_name(hi);
hi->input->name = name;
}
/* force BTN_STYLUS to allow tablet matching in udev */
__set_bit(BTN_STYLUS, hi->input->keybit);
}
static int mt_touch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
@ -363,13 +432,8 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
int code;
struct hid_usage *prev_usage = NULL;
/* Only map fields from TouchScreen or TouchPad collections.
* We need to ignore fields that belong to other collections
* such as Mouse that might have the same GenericDesktop usages. */
if (field->application == HID_DG_TOUCHSCREEN)
td->mt_flags |= INPUT_MT_DIRECT;
else if (field->application != HID_DG_TOUCHPAD)
return 0;
/*
* Model touchscreens providing buttons as touchpads.
@ -378,12 +442,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
(usage->hid & HID_USAGE_PAGE) == HID_UP_BUTTON)
td->mt_flags |= INPUT_MT_POINTER;
/* eGalax devices provide a Digitizer.Stylus input which overrides
* the correct Digitizers.Finger X/Y ranges.
* Let's just ignore this input. */
if (field->physical == HID_DG_STYLUS)
return -1;
if (usage->usage_index)
prev_usage = &field->usage[usage->usage_index - 1];
@ -405,7 +463,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
}
mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_GD_Y:
if (prev_usage && (prev_usage->hid == usage->hid)) {
@ -421,7 +478,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
}
mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
}
return 0;
@ -436,21 +492,17 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
ABS_MT_DISTANCE, 0, 1, 0, 0);
}
mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_CONFIDENCE:
mt_store_field(usage, td, hi);
td->last_field_index = field->index;
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);
mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTID:
mt_store_field(usage, td, hi);
td->last_field_index = field->index;
td->touches_by_report++;
td->mt_report_id = field->report->id;
return 1;
@ -461,7 +513,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
set_abs(hi->input, ABS_MT_TOUCH_MAJOR, field,
cls->sn_width);
mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_HEIGHT:
hid_map_usage(hi, usage, bit, max,
@ -473,7 +524,6 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
ABS_MT_ORIENTATION, 0, 1, 0, 0);
}
mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_TIPPRESSURE:
hid_map_usage(hi, usage, bit, max,
@ -481,17 +531,14 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
set_abs(hi->input, ABS_MT_PRESSURE, field,
cls->sn_pressure);
mt_store_field(usage, td, hi);
td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTCOUNT:
td->cc_index = field->index;
td->cc_value_index = usage->usage_index;
td->last_field_index = field->index;
return 1;
case HID_DG_CONTACTMAX:
/* we don't set td->last_slot_field as contactcount and
* contact max are global to the report */
td->last_field_index = field->index;
return -1;
case HID_DG_TOUCH:
/* Legacy devices use TIPSWITCH and not TOUCH.
@ -515,7 +562,7 @@ static int mt_input_mapping(struct hid_device *hdev, struct hid_input *hi,
return 0;
}
static int mt_input_mapped(struct hid_device *hdev, struct hid_input *hi,
static int mt_touch_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
@ -606,7 +653,7 @@ static void mt_sync_frame(struct mt_device *td, struct input_dev *input)
td->num_received = 0;
}
static int mt_event(struct hid_device *hid, struct hid_field *field,
static int mt_touch_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
/* we will handle the hidinput part later, now remains hiddev */
@ -680,29 +727,19 @@ static void mt_process_mt_event(struct hid_device *hid, struct hid_field *field,
if (usage->usage_index + 1 == field->report_count) {
/* we only take into account the last report. */
if (usage->hid == td->last_slot_field)
mt_complete_slot(td, input);
if (field->index == td->last_field_index
&& td->num_received >= td->num_expected)
mt_sync_frame(td, field->hidinput->input);
mt_complete_slot(td, field->hidinput->input);
}
}
}
static void mt_report(struct hid_device *hid, struct hid_report *report)
static void mt_touch_report(struct hid_device *hid, struct hid_report *report)
{
struct mt_device *td = hid_get_drvdata(hid);
struct hid_field *field;
unsigned count;
int r, n;
if (report->id != td->mt_report_id)
return;
if (!(hid->claimed & HID_CLAIMED_INPUT))
return;
/*
* Includes multi-packet support where subsequent
* packets are sent with zero contactcount.
@ -725,6 +762,91 @@ static void mt_report(struct hid_device *hid, struct hid_report *report)
mt_process_mt_event(hid, field, &field->usage[n],
field->value[n]);
}
if (td->num_received >= td->num_expected)
mt_sync_frame(td, report->field[0]->hidinput->input);
}
static void mt_touch_input_configured(struct hid_device *hdev,
struct hid_input *hi)
{
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_class *cls = &td->mtclass;
struct input_dev *input = hi->input;
if (!td->maxcontacts)
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
mt_post_parse(td);
if (td->serial_maybe)
mt_post_parse_default_settings(td);
if (cls->is_indirect)
td->mt_flags |= INPUT_MT_POINTER;
if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
td->mt_flags |= INPUT_MT_DROP_UNUSED;
input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
td->mt_flags = 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)
{
/* Only map fields from TouchScreen or TouchPad collections.
* We need to ignore fields that belong to other collections
* such as Mouse that might have the same GenericDesktop usages. */
if (field->application != HID_DG_TOUCHSCREEN &&
field->application != HID_DG_PEN &&
field->application != HID_DG_TOUCHPAD)
return -1;
if (field->physical == HID_DG_STYLUS)
return mt_pen_input_mapping(hdev, hi, field, usage, bit, max);
return mt_touch_input_mapping(hdev, hi, field, usage, bit, max);
}
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 (field->physical == HID_DG_STYLUS)
return mt_pen_input_mapped(hdev, hi, field, usage, bit, max);
return mt_touch_input_mapped(hdev, hi, field, usage, bit, max);
}
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);
if (field->report->id == td->mt_report_id)
return mt_touch_event(hid, field, usage, value);
if (field->report->id == td->pen_report_id)
return mt_pen_event(hid, field, usage, value);
/* ignore other reports */
return 1;
}
static void mt_report(struct hid_device *hid, struct hid_report *report)
{
struct mt_device *td = hid_get_drvdata(hid);
if (!(hid->claimed & HID_CLAIMED_INPUT))
return;
if (report->id == td->mt_report_id)
mt_touch_report(hid, report);
if (report->id == td->pen_report_id)
mt_pen_report(hid, report);
}
static void mt_set_input_mode(struct hid_device *hdev)
@ -740,7 +862,7 @@ static void mt_set_input_mode(struct hid_device *hdev)
r = re->report_id_hash[td->inputmode];
if (r) {
r->field[0]->value[td->inputmode_index] = 0x02;
usbhid_submit_report(hdev, r, USB_DIR_OUT);
hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
}
}
@ -765,7 +887,7 @@ static void mt_set_maxcontacts(struct hid_device *hdev)
max = min(fieldmax, max);
if (r->field[0]->value[0] != max) {
r->field[0]->value[0] = max;
usbhid_submit_report(hdev, r, USB_DIR_OUT);
hid_hw_request(hdev, r, HID_REQ_SET_REPORT);
}
}
}
@ -801,32 +923,18 @@ static void mt_post_parse(struct mt_device *td)
}
static void mt_input_configured(struct hid_device *hdev, struct hid_input *hi)
{
struct mt_device *td = hid_get_drvdata(hdev);
struct mt_class *cls = &td->mtclass;
struct input_dev *input = hi->input;
char *name = kstrdup(hdev->name, GFP_KERNEL);
/* Only initialize slots for MT input devices */
if (!test_bit(ABS_MT_POSITION_X, input->absbit))
return;
if (name)
hi->input->name = name;
if (!td->maxcontacts)
td->maxcontacts = MT_DEFAULT_MAXCONTACT;
if (hi->report->id == td->mt_report_id)
mt_touch_input_configured(hdev, hi);
mt_post_parse(td);
if (td->serial_maybe)
mt_post_parse_default_settings(td);
if (cls->is_indirect)
td->mt_flags |= INPUT_MT_POINTER;
if (cls->quirks & MT_QUIRK_NOT_SEEN_MEANS_UP)
td->mt_flags |= INPUT_MT_DROP_UNUSED;
input_mt_init_slots(input, td->maxcontacts, td->mt_flags);
td->mt_flags = 0;
if (hi->report->id == td->pen_report_id)
mt_pen_input_configured(hdev, hi);
}
static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
@ -834,6 +942,7 @@ 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 */
struct hid_input *hi;
for (i = 0; mt_classes[i].name ; i++) {
if (id->driver_data == mt_classes[i].name) {
@ -847,6 +956,14 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
*/
hdev->quirks |= HID_QUIRK_NO_INPUT_SYNC;
/*
* This allows the driver to handle different input sensors
* that emits events through different reports on the same HID
* device.
*/
hdev->quirks |= HID_QUIRK_MULTI_INPUT;
hdev->quirks |= HID_QUIRK_NO_EMPTY_INPUT;
td = kzalloc(sizeof(struct mt_device), GFP_KERNEL);
if (!td) {
dev_err(&hdev->dev, "cannot allocate multitouch data\n");
@ -856,6 +973,8 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
td->inputmode = -1;
td->maxcontact_report_id = -1;
td->cc_index = -1;
td->mt_report_id = -1;
td->pen_report_id = -1;
hid_set_drvdata(hdev, td);
td->fields = kzalloc(sizeof(struct mt_fields), GFP_KERNEL);
@ -874,7 +993,7 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret)
goto fail;
goto hid_fail;
ret = sysfs_create_group(&hdev->dev.kobj, &mt_attribute_group);
@ -886,6 +1005,9 @@ static int mt_probe(struct hid_device *hdev, const struct hid_device_id *id)
return 0;
hid_fail:
list_for_each_entry(hi, &hdev->inputs, list)
mt_free_input_name(hi);
fail:
kfree(td->fields);
kfree(td);
@ -902,26 +1024,11 @@ static int mt_reset_resume(struct hid_device *hdev)
static int mt_resume(struct hid_device *hdev)
{
struct usb_interface *intf;
struct usb_host_interface *interface;
struct usb_device *dev;
if (hdev->bus != BUS_USB)
return 0;
intf = to_usb_interface(hdev->dev.parent);
interface = intf->cur_altsetting;
dev = hid_to_usb_dev(hdev);
/* Some Elan legacy devices require SET_IDLE to be set on resume.
* It should be safe to send it to other devices too.
* Tested on 3M, Stantum, Cypress, Zytronic, eGalax, and Elan panels. */
usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
HID_REQ_SET_IDLE,
USB_TYPE_CLASS | USB_RECIP_INTERFACE,
0, interface->desc.bInterfaceNumber,
NULL, 0, USB_CTRL_SET_TIMEOUT);
hid_hw_idle(hdev, 0, 0, HID_REQ_SET_IDLE);
return 0;
}
@ -930,8 +1037,14 @@ static int mt_resume(struct hid_device *hdev)
static void mt_remove(struct hid_device *hdev)
{
struct mt_device *td = hid_get_drvdata(hdev);
struct hid_input *hi;
sysfs_remove_group(&hdev->dev.kobj, &mt_attribute_group);
hid_hw_stop(hdev);
list_for_each_entry(hi, &hdev->inputs, list)
mt_free_input_name(hi);
kfree(td);
hid_set_drvdata(hdev, NULL);
}

View file

@ -118,8 +118,8 @@ static inline int ntrig_get_mode(struct hid_device *hdev)
if (!report)
return -EINVAL;
usbhid_submit_report(hdev, report, USB_DIR_IN);
usbhid_wait_io(hdev);
hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
hid_hw_wait(hdev);
return (int)report->field[0]->value[0];
}
@ -137,7 +137,7 @@ static inline void ntrig_set_mode(struct hid_device *hdev, const int mode)
if (!report)
return;
usbhid_submit_report(hdev, report, USB_DIR_IN);
hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
}
static void ntrig_report_version(struct hid_device *hdev)
@ -937,8 +937,8 @@ static int ntrig_probe(struct hid_device *hdev, const struct hid_device_id *id)
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);
hid_hw_wait(hdev);
hid_hw_request(hdev, report, HID_REQ_GET_REPORT);
/*
* Sanity check: if the current mode is invalid reset it to

View file

@ -142,10 +142,10 @@ struct hid_report *picolcd_report(int id, struct hid_device *hdev, int dir);
#ifdef CONFIG_DEBUG_FS
void picolcd_debug_out_report(struct picolcd_data *data,
struct hid_device *hdev, struct hid_report *report);
#define usbhid_submit_report(a, b, c) \
#define hid_hw_request(a, b, c) \
do { \
picolcd_debug_out_report(hid_get_drvdata(a), a, b); \
usbhid_submit_report(a, b, c); \
hid_hw_request(a, b, c); \
} while (0)
void picolcd_debug_raw_event(struct picolcd_data *data,
@ -302,7 +302,7 @@ static inline int picolcd_init_cir(struct picolcd_data *data, struct hid_report
static inline void picolcd_exit_cir(struct picolcd_data *data)
{
}
#endif /* CONFIG_HID_PICOLCD_LIRC */
#endif /* CONFIG_HID_PICOLCD_CIR */
int picolcd_reset(struct hid_device *hdev);
struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,

View file

@ -18,8 +18,6 @@
***************************************************************************/
#include <linux/hid.h>
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/backlight.h>
@ -46,7 +44,7 @@ static int picolcd_set_brightness(struct backlight_device *bdev)
spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, data->lcd_power == FB_BLANK_UNBLANK ? data->lcd_brightness : 0);
if (!(data->status & PICOLCD_FAILED))
usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
return 0;
}

View file

@ -21,8 +21,6 @@
#include <linux/hid-debug.h>
#include <linux/input.h>
#include "hid-ids.h"
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/vmalloc.h>

View file

@ -21,8 +21,6 @@
#include <linux/hid-debug.h>
#include <linux/input.h>
#include "hid-ids.h"
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/vmalloc.h>
@ -110,7 +108,7 @@ struct picolcd_pending *picolcd_send_and_wait(struct hid_device *hdev,
work = NULL;
} else {
data->pending = work;
usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
wait_for_completion_interruptible_timeout(&work->ready, HZ*2);
spin_lock_irqsave(&data->lock, flags);
@ -244,7 +242,7 @@ int picolcd_reset(struct hid_device *hdev)
spin_unlock_irqrestore(&data->lock, flags);
return -ENODEV;
}
usbhid_submit_report(hdev, report, USB_DIR_OUT);
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
error = picolcd_check_version(hdev);
@ -303,7 +301,7 @@ static ssize_t picolcd_operation_mode_store(struct device *dev,
spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, timeout & 0xff);
hid_set_field(report->field[0], 1, (timeout >> 8) & 0xff);
usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
return count;
}

View file

@ -19,8 +19,6 @@
#include <linux/hid.h>
#include <linux/hid-debug.h>
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/seq_file.h>

View file

@ -19,8 +19,6 @@
#include <linux/hid.h>
#include <linux/vmalloc.h>
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/module.h>
@ -143,8 +141,8 @@ static int picolcd_fb_send_tile(struct picolcd_data *data, u8 *vbitmap,
else
hid_set_field(report2->field[0], 4 + i - 32, tdata[i]);
usbhid_submit_report(data->hdev, report1, USB_DIR_OUT);
usbhid_submit_report(data->hdev, report2, USB_DIR_OUT);
hid_hw_request(data->hdev, report1, HID_REQ_SET_REPORT);
hid_hw_request(data->hdev, report2, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
return 0;
}
@ -214,7 +212,7 @@ int picolcd_fb_reset(struct picolcd_data *data, int clear)
hid_set_field(report->field[0], j, mapcmd[j]);
else
hid_set_field(report->field[0], j, 0);
usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
}
spin_unlock_irqrestore(&data->lock, flags);
@ -270,7 +268,7 @@ static void picolcd_fb_update(struct fb_info *info)
mutex_unlock(&info->lock);
if (!data)
return;
usbhid_wait_io(data->hdev);
hid_hw_wait(data->hdev);
mutex_lock(&info->lock);
n = 0;
}
@ -288,7 +286,7 @@ static void picolcd_fb_update(struct fb_info *info)
spin_unlock_irqrestore(&fbdata->lock, flags);
mutex_unlock(&info->lock);
if (data)
usbhid_wait_io(data->hdev);
hid_hw_wait(data->hdev);
return;
}
out:

View file

@ -18,8 +18,6 @@
***************************************************************************/
#include <linux/hid.h>
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/lcd.h>
@ -48,7 +46,7 @@ static int picolcd_set_contrast(struct lcd_device *ldev, int contrast)
spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, data->lcd_contrast);
if (!(data->status & PICOLCD_FAILED))
usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
return 0;
}

View file

@ -21,8 +21,6 @@
#include <linux/hid-debug.h>
#include <linux/input.h>
#include "hid-ids.h"
#include "usbhid/usbhid.h"
#include <linux/usb.h>
#include <linux/fb.h>
#include <linux/vmalloc.h>
@ -55,7 +53,7 @@ void picolcd_leds_set(struct picolcd_data *data)
spin_lock_irqsave(&data->lock, flags);
hid_set_field(report->field[0], 0, data->led_state);
if (!(data->status & PICOLCD_FAILED))
usbhid_submit_report(data->hdev, report, USB_DIR_OUT);
hid_hw_request(data->hdev, report, HID_REQ_SET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
}

View file

@ -43,13 +43,11 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include "hid-ids.h"
#ifdef CONFIG_PANTHERLORD_FF
#include "usbhid/usbhid.h"
struct plff_device {
struct hid_report *report;
@ -75,7 +73,7 @@ static int hid_plff_play(struct input_dev *dev, void *data,
*plff->strong = left;
*plff->weak = right;
debug("running with 0x%02x 0x%02x", left, right);
usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT);
return 0;
}
@ -169,7 +167,7 @@ static int plff_init(struct hid_device *hid)
*strong = 0x00;
*weak = 0x00;
usbhid_submit_report(hid, plff->report, USB_DIR_OUT);
hid_hw_request(hid, plff->report, HID_REQ_SET_REPORT);
}
hid_info(hid, "Force feedback for PantherLord/GreenAsia devices by Anssi Hannula <anssi.hannula@gmail.com>\n");

View file

@ -26,7 +26,6 @@
#include <sound/core.h>
#include <sound/initval.h>
#include <sound/rawmidi.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h"
@ -306,7 +305,7 @@ static void pcmidi_submit_output_report(struct pcmidi_snd *pm, int state)
report->field[0]->value[0] = 0x01;
report->field[0]->value[1] = state;
usbhid_submit_report(hdev, report, USB_DIR_OUT);
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
}
static int pcmidi_handle_report1(struct pcmidi_snd *pm, u8 *data)

View file

@ -130,14 +130,14 @@ static ssize_t isku_sysfs_read(struct file *fp, struct kobject *kobj,
if (off >= real_size)
return 0;
if (off != 0 || count != real_size)
if (off != 0 || count > real_size)
return -EINVAL;
mutex_lock(&isku->isku_lock);
retval = isku_receive(usb_dev, command, buf, real_size);
retval = isku_receive(usb_dev, command, buf, count);
mutex_unlock(&isku->isku_lock);
return retval ? retval : real_size;
return retval ? retval : count;
}
static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj,
@ -150,15 +150,15 @@ static ssize_t isku_sysfs_write(struct file *fp, struct kobject *kobj,
struct usb_device *usb_dev = interface_to_usbdev(to_usb_interface(dev));
int retval;
if (off != 0 || count != real_size)
if (off != 0 || count > real_size)
return -EINVAL;
mutex_lock(&isku->isku_lock);
retval = roccat_common2_send_with_status(usb_dev, command,
(void *)buf, real_size);
(void *)buf, count);
mutex_unlock(&isku->isku_lock);
return retval ? retval : real_size;
return retval ? retval : count;
}
#define ISKU_SYSFS_W(thingy, THINGY) \
@ -216,6 +216,7 @@ ISKU_SYSFS_RW(light, LIGHT)
ISKU_SYSFS_RW(key_mask, KEY_MASK)
ISKU_SYSFS_RW(last_set, LAST_SET)
ISKU_SYSFS_W(talk, TALK)
ISKU_SYSFS_W(talkfx, TALKFX)
ISKU_SYSFS_R(info, INFO)
ISKU_SYSFS_W(control, CONTROL)
ISKU_SYSFS_W(reset, RESET)
@ -232,6 +233,7 @@ static struct bin_attribute isku_bin_attributes[] = {
ISKU_BIN_ATTR_RW(key_mask, KEY_MASK),
ISKU_BIN_ATTR_RW(last_set, LAST_SET),
ISKU_BIN_ATTR_W(talk, TALK),
ISKU_BIN_ATTR_W(talkfx, TALKFX),
ISKU_BIN_ATTR_R(info, INFO),
ISKU_BIN_ATTR_W(control, CONTROL),
ISKU_BIN_ATTR_W(reset, RESET),
@ -405,6 +407,7 @@ static int isku_raw_event(struct hid_device *hdev,
static const struct hid_device_id isku_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_ISKUFX) },
{ }
};
@ -443,5 +446,5 @@ module_init(isku_init);
module_exit(isku_exit);
MODULE_AUTHOR("Stefan Achatz");
MODULE_DESCRIPTION("USB Roccat Isku driver");
MODULE_DESCRIPTION("USB Roccat Isku/FX driver");
MODULE_LICENSE("GPL v2");

View file

@ -25,10 +25,11 @@ enum {
ISKU_SIZE_KEYS_MACRO = 0x23,
ISKU_SIZE_KEYS_CAPSLOCK = 0x06,
ISKU_SIZE_LAST_SET = 0x14,
ISKU_SIZE_LIGHT = 0x0a,
ISKU_SIZE_LIGHT = 0x10,
ISKU_SIZE_MACRO = 0x823,
ISKU_SIZE_RESET = 0x03,
ISKU_SIZE_TALK = 0x10,
ISKU_SIZE_TALKFX = 0x10,
};
enum {
@ -59,6 +60,7 @@ enum isku_commands {
ISKU_COMMAND_LAST_SET = 0x14,
ISKU_COMMAND_15 = 0x15,
ISKU_COMMAND_TALK = 0x16,
ISKU_COMMAND_TALKFX = 0x17,
ISKU_COMMAND_FIRMWARE_WRITE = 0x1b,
ISKU_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
};

View file

@ -818,8 +818,9 @@ static void kone_report_to_chrdev(struct kone_device const *kone,
(uint8_t *)&roccat_report);
break;
case kone_mouse_event_call_overlong_macro:
case kone_mouse_event_multimedia:
if (event->value == kone_keystroke_action_press) {
roccat_report.event = kone_mouse_event_call_overlong_macro;
roccat_report.event = event->event;
roccat_report.value = kone->actual_profile;
roccat_report.key = event->macro_key;
roccat_report_event(kone->chrdev_minor,

View file

@ -169,6 +169,7 @@ enum kone_mouse_events {
/* TODO clarify meaning and occurence of kone_mouse_event_calibration */
kone_mouse_event_calibration = 0xc0,
kone_mouse_event_call_overlong_macro = 0xe0,
kone_mouse_event_multimedia = 0xe1,
/* switch events notify if user changed values with mousebutton click */
kone_mouse_event_switch_dpi = 0xf0,
kone_mouse_event_switch_profile = 0xf1

View file

@ -0,0 +1,304 @@
/*
* Roccat KonePure driver for Linux
*
* Copyright (c) 2012 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 KonePure is a smaller version of KoneXTD with less buttons and lights.
*/
#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-konepure.h"
static struct class *konepure_class;
static ssize_t konepure_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 konepure_device *konepure = 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(&konepure->konepure_lock);
retval = roccat_common2_receive(usb_dev, command, buf, real_size);
mutex_unlock(&konepure->konepure_lock);
return retval ? retval : real_size;
}
static ssize_t konepure_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 konepure_device *konepure = 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(&konepure->konepure_lock);
retval = roccat_common2_send_with_status(usb_dev, command,
(void *)buf, real_size);
mutex_unlock(&konepure->konepure_lock);
return retval ? retval : real_size;
}
#define KONEPURE_SYSFS_W(thingy, THINGY) \
static ssize_t konepure_sysfs_write_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
{ \
return konepure_sysfs_write(fp, kobj, buf, off, count, \
KONEPURE_SIZE_ ## THINGY, KONEPURE_COMMAND_ ## THINGY); \
}
#define KONEPURE_SYSFS_R(thingy, THINGY) \
static ssize_t konepure_sysfs_read_ ## thingy(struct file *fp, \
struct kobject *kobj, struct bin_attribute *attr, char *buf, \
loff_t off, size_t count) \
{ \
return konepure_sysfs_read(fp, kobj, buf, off, count, \
KONEPURE_SIZE_ ## THINGY, KONEPURE_COMMAND_ ## THINGY); \
}
#define KONEPURE_SYSFS_RW(thingy, THINGY) \
KONEPURE_SYSFS_W(thingy, THINGY) \
KONEPURE_SYSFS_R(thingy, THINGY)
#define KONEPURE_BIN_ATTRIBUTE_RW(thingy, THINGY) \
{ \
.attr = { .name = #thingy, .mode = 0660 }, \
.size = KONEPURE_SIZE_ ## THINGY, \
.read = konepure_sysfs_read_ ## thingy, \
.write = konepure_sysfs_write_ ## thingy \
}
#define KONEPURE_BIN_ATTRIBUTE_R(thingy, THINGY) \
{ \
.attr = { .name = #thingy, .mode = 0440 }, \
.size = KONEPURE_SIZE_ ## THINGY, \
.read = konepure_sysfs_read_ ## thingy, \
}
#define KONEPURE_BIN_ATTRIBUTE_W(thingy, THINGY) \
{ \
.attr = { .name = #thingy, .mode = 0220 }, \
.size = KONEPURE_SIZE_ ## THINGY, \
.write = konepure_sysfs_write_ ## thingy \
}
KONEPURE_SYSFS_RW(actual_profile, ACTUAL_PROFILE)
KONEPURE_SYSFS_W(control, CONTROL)
KONEPURE_SYSFS_RW(info, INFO)
KONEPURE_SYSFS_W(talk, TALK)
KONEPURE_SYSFS_W(macro, MACRO)
KONEPURE_SYSFS_RW(sensor, SENSOR)
KONEPURE_SYSFS_RW(tcu, TCU)
KONEPURE_SYSFS_R(tcu_image, TCU_IMAGE)
KONEPURE_SYSFS_RW(profile_settings, PROFILE_SETTINGS)
KONEPURE_SYSFS_RW(profile_buttons, PROFILE_BUTTONS)
static struct bin_attribute konepure_bin_attributes[] = {
KONEPURE_BIN_ATTRIBUTE_RW(actual_profile, ACTUAL_PROFILE),
KONEPURE_BIN_ATTRIBUTE_W(control, CONTROL),
KONEPURE_BIN_ATTRIBUTE_RW(info, INFO),
KONEPURE_BIN_ATTRIBUTE_W(talk, TALK),
KONEPURE_BIN_ATTRIBUTE_W(macro, MACRO),
KONEPURE_BIN_ATTRIBUTE_RW(sensor, SENSOR),
KONEPURE_BIN_ATTRIBUTE_RW(tcu, TCU),
KONEPURE_BIN_ATTRIBUTE_R(tcu_image, TCU_IMAGE),
KONEPURE_BIN_ATTRIBUTE_RW(profile_settings, PROFILE_SETTINGS),
KONEPURE_BIN_ATTRIBUTE_RW(profile_buttons, PROFILE_BUTTONS),
__ATTR_NULL
};
static int konepure_init_konepure_device_struct(struct usb_device *usb_dev,
struct konepure_device *konepure)
{
mutex_init(&konepure->konepure_lock);
return 0;
}
static int konepure_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 konepure_device *konepure;
int retval;
if (intf->cur_altsetting->desc.bInterfaceProtocol
!= USB_INTERFACE_PROTOCOL_MOUSE) {
hid_set_drvdata(hdev, NULL);
return 0;
}
konepure = kzalloc(sizeof(*konepure), GFP_KERNEL);
if (!konepure) {
hid_err(hdev, "can't alloc device descriptor\n");
return -ENOMEM;
}
hid_set_drvdata(hdev, konepure);
retval = konepure_init_konepure_device_struct(usb_dev, konepure);
if (retval) {
hid_err(hdev, "couldn't init struct konepure_device\n");
goto exit_free;
}
retval = roccat_connect(konepure_class, hdev,
sizeof(struct konepure_mouse_report_button));
if (retval < 0) {
hid_err(hdev, "couldn't init char dev\n");
} else {
konepure->chrdev_minor = retval;
konepure->roccat_claimed = 1;
}
return 0;
exit_free:
kfree(konepure);
return retval;
}
static void konepure_remove_specials(struct hid_device *hdev)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
struct konepure_device *konepure;
if (intf->cur_altsetting->desc.bInterfaceProtocol
!= USB_INTERFACE_PROTOCOL_MOUSE)
return;
konepure = hid_get_drvdata(hdev);
if (konepure->roccat_claimed)
roccat_disconnect(konepure->chrdev_minor);
kfree(konepure);
}
static int konepure_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 = konepure_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 konepure_remove(struct hid_device *hdev)
{
konepure_remove_specials(hdev);
hid_hw_stop(hdev);
}
static int konepure_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 konepure_device *konepure = hid_get_drvdata(hdev);
if (intf->cur_altsetting->desc.bInterfaceProtocol
!= USB_INTERFACE_PROTOCOL_MOUSE)
return 0;
if (data[0] != KONEPURE_MOUSE_REPORT_NUMBER_BUTTON)
return 0;
if (konepure != NULL && konepure->roccat_claimed)
roccat_report_event(konepure->chrdev_minor, data);
return 0;
}
static const struct hid_device_id konepure_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KONEPURE) },
{ }
};
MODULE_DEVICE_TABLE(hid, konepure_devices);
static struct hid_driver konepure_driver = {
.name = "konepure",
.id_table = konepure_devices,
.probe = konepure_probe,
.remove = konepure_remove,
.raw_event = konepure_raw_event
};
static int __init konepure_init(void)
{
int retval;
konepure_class = class_create(THIS_MODULE, "konepure");
if (IS_ERR(konepure_class))
return PTR_ERR(konepure_class);
konepure_class->dev_bin_attrs = konepure_bin_attributes;
retval = hid_register_driver(&konepure_driver);
if (retval)
class_destroy(konepure_class);
return retval;
}
static void __exit konepure_exit(void)
{
hid_unregister_driver(&konepure_driver);
class_destroy(konepure_class);
}
module_init(konepure_init);
module_exit(konepure_exit);
MODULE_AUTHOR("Stefan Achatz");
MODULE_DESCRIPTION("USB Roccat KonePure driver");
MODULE_LICENSE("GPL v2");

View file

@ -0,0 +1,72 @@
#ifndef __HID_ROCCAT_KONEPURE_H
#define __HID_ROCCAT_KONEPURE_H
/*
* Copyright (c) 2012 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>
enum {
KONEPURE_SIZE_ACTUAL_PROFILE = 0x03,
KONEPURE_SIZE_CONTROL = 0x03,
KONEPURE_SIZE_FIRMWARE_WRITE = 0x0402,
KONEPURE_SIZE_INFO = 0x06,
KONEPURE_SIZE_MACRO = 0x0822,
KONEPURE_SIZE_PROFILE_SETTINGS = 0x1f,
KONEPURE_SIZE_PROFILE_BUTTONS = 0x3b,
KONEPURE_SIZE_SENSOR = 0x06,
KONEPURE_SIZE_TALK = 0x10,
KONEPURE_SIZE_TCU = 0x04,
KONEPURE_SIZE_TCU_IMAGE = 0x0404,
};
enum konepure_control_requests {
KONEPURE_CONTROL_REQUEST_GENERAL = 0x80,
KONEPURE_CONTROL_REQUEST_BUTTONS = 0x90,
};
enum konepure_commands {
KONEPURE_COMMAND_CONTROL = 0x04,
KONEPURE_COMMAND_ACTUAL_PROFILE = 0x05,
KONEPURE_COMMAND_PROFILE_SETTINGS = 0x06,
KONEPURE_COMMAND_PROFILE_BUTTONS = 0x07,
KONEPURE_COMMAND_MACRO = 0x08,
KONEPURE_COMMAND_INFO = 0x09,
KONEPURE_COMMAND_TCU = 0x0c,
KONEPURE_COMMAND_TCU_IMAGE = 0x0c,
KONEPURE_COMMAND_E = 0x0e,
KONEPURE_COMMAND_SENSOR = 0x0f,
KONEPURE_COMMAND_TALK = 0x10,
KONEPURE_COMMAND_FIRMWARE_WRITE = 0x1b,
KONEPURE_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
};
enum {
KONEPURE_MOUSE_REPORT_NUMBER_BUTTON = 3,
};
struct konepure_mouse_report_button {
uint8_t report_number; /* always KONEPURE_MOUSE_REPORT_NUMBER_BUTTON */
uint8_t zero;
uint8_t type;
uint8_t data1;
uint8_t data2;
uint8_t zero2;
uint8_t unknown[2];
} __packed;
struct konepure_device {
int roccat_claimed;
int chrdev_minor;
struct mutex konepure_lock;
};
#endif

View file

@ -242,7 +242,6 @@ static int roccat_release(struct inode *inode, struct file *file)
* roccat_report_event() - output data to readers
* @minor: minor device number returned by roccat_connect()
* @data: pointer to data
* @len: size of data
*
* Return value is zero on success, a negative error code on failure.
*
@ -290,6 +289,7 @@ EXPORT_SYMBOL_GPL(roccat_report_event);
* @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.
* @report_size: size of reports
*
* Return value is minor device number in Range [0, ROCCAT_MAX_DEVICES] on
* success, a negative error code on failure.

View file

@ -18,8 +18,6 @@
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/usb.h>
#include "usbhid/usbhid.h"
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/mfd/core.h>
@ -204,8 +202,8 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
goto done_proc;
}
hid_set_field(report->field[field_index], 0, value);
usbhid_submit_report(hsdev->hdev, report, USB_DIR_OUT);
usbhid_wait_io(hsdev->hdev);
hid_hw_request(hsdev->hdev, report, HID_REQ_SET_REPORT);
hid_hw_wait(hsdev->hdev);
done_proc:
mutex_unlock(&data->mutex);
@ -227,8 +225,8 @@ int sensor_hub_get_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
ret = -EINVAL;
goto done_proc;
}
usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
usbhid_wait_io(hsdev->hdev);
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
hid_hw_wait(hsdev->hdev);
*value = report->field[field_index]->value[0];
done_proc:
@ -262,7 +260,7 @@ int sensor_hub_input_attr_get_raw_value(struct hid_sensor_hub_device *hsdev,
spin_unlock_irqrestore(&data->lock, flags);
goto err_free;
}
usbhid_submit_report(hsdev->hdev, report, USB_DIR_IN);
hid_hw_request(hsdev->hdev, report, HID_REQ_GET_REPORT);
spin_unlock_irqrestore(&data->lock, flags);
wait_for_completion_interruptible_timeout(&data->pending.ready, HZ*5);
switch (data->pending.raw_size) {

View file

@ -28,13 +28,11 @@
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
#ifdef CONFIG_SMARTJOYPLUS_FF
#include "usbhid/usbhid.h"
struct sjoyff_device {
struct hid_report *report;
@ -57,7 +55,7 @@ static int hid_sjoyff_play(struct input_dev *dev, void *data,
sjoyff->report->field[0]->value[1] = right;
sjoyff->report->field[0]->value[2] = left;
dev_dbg(&dev->dev, "running with 0x%02x 0x%02x\n", left, right);
usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
hid_hw_request(hid, sjoyff->report, HID_REQ_SET_REPORT);
return 0;
}
@ -115,7 +113,7 @@ static int sjoyff_init(struct hid_device *hid)
sjoyff->report->field[0]->value[0] = 0x01;
sjoyff->report->field[0]->value[1] = 0x00;
sjoyff->report->field[0]->value[2] = 0x00;
usbhid_submit_report(hid, sjoyff->report, USB_DIR_OUT);
hid_hw_request(hid, sjoyff->report, HID_REQ_SET_REPORT);
}
hid_info(hid, "Force feedback for SmartJoy PLUS PS2/USB adapter\n");

View file

@ -16,10 +16,8 @@
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/usb.h>
#include "hid-ids.h"
#include "usbhid/usbhid.h"
static const struct hid_device_id speedlink_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_X_TENSIONS, USB_DEVICE_ID_SPEEDLINK_VAD_CEZANNE)},

View file

@ -16,7 +16,6 @@
#include <linux/hid.h>
#include <linux/module.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h"
#if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
@ -132,7 +131,7 @@ static void steelseries_srws1_set_leds(struct hid_device *hdev, __u16 leds)
value[14] = 0x00;
value[15] = 0x00;
usbhid_submit_report(hdev, report, USB_DIR_OUT);
hid_hw_request(hdev, report, HID_REQ_SET_REPORT);
/* Note: LED change does not show on device until the device is read/polled */
}
@ -378,16 +377,5 @@ static struct hid_driver steelseries_srws1_driver = {
.report_fixup = steelseries_srws1_report_fixup
};
static int __init steelseries_srws1_init(void)
{
return hid_register_driver(&steelseries_srws1_driver);
}
static void __exit steelseries_srws1_exit(void)
{
hid_unregister_driver(&steelseries_srws1_driver);
}
module_init(steelseries_srws1_init);
module_exit(steelseries_srws1_exit);
module_hid_driver(steelseries_srws1_driver);
MODULE_LICENSE("GPL");

View file

@ -12,7 +12,6 @@
#include <linux/hid.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/usb.h>
#include "hid-ids.h"

View file

@ -30,7 +30,6 @@
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/module.h>
#include "hid-ids.h"
@ -46,7 +45,6 @@ static const signed short ff_joystick[] = {
};
#ifdef CONFIG_THRUSTMASTER_FF
#include "usbhid/usbhid.h"
/* Usages for thrustmaster devices I know about */
#define THRUSTMASTER_USAGE_FF (HID_UP_GENDESK | 0xbb)
@ -103,7 +101,7 @@ static int tmff_play(struct input_dev *dev, void *data,
dbg_hid("(x, y)=(%04x, %04x)\n", x, y);
ff_field->value[0] = x;
ff_field->value[1] = y;
usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
break;
case FF_RUMBLE:
@ -117,7 +115,7 @@ static int tmff_play(struct input_dev *dev, void *data,
dbg_hid("(left,right)=(%08x, %08x)\n", left, right);
ff_field->value[0] = left;
ff_field->value[1] = right;
usbhid_submit_report(hid, tmff->report, USB_DIR_OUT);
hid_hw_request(hid, tmff->report, HID_REQ_SET_REPORT);
break;
}
return 0;

View file

@ -789,12 +789,20 @@ static void __ir_to_input(struct wiimote_data *wdata, const __u8 *ir,
input_report_abs(wdata->ir, yid, y);
}
static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
/* reduced status report with "BB BB" key data only */
static void handler_status_K(struct wiimote_data *wdata,
const __u8 *payload)
{
handler_keys(wdata, payload);
/* on status reports the drm is reset so we need to resend the drm */
wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
}
/* extended status report with "BB BB LF 00 00 VV" data */
static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
{
handler_status_K(wdata, payload);
wiiext_event(wdata, payload[2] & 0x02);
@ -804,6 +812,12 @@ static void handler_status(struct wiimote_data *wdata, const __u8 *payload)
}
}
/* reduced generic report with "BB BB" key data only */
static void handler_generic_K(struct wiimote_data *wdata, const __u8 *payload)
{
handler_keys(wdata, payload);
}
static void handler_data(struct wiimote_data *wdata, const __u8 *payload)
{
__u16 offset = payload[3] << 8 | payload[4];
@ -947,16 +961,26 @@ struct wiiproto_handler {
static struct wiiproto_handler handlers[] = {
{ .id = WIIPROTO_REQ_STATUS, .size = 6, .func = handler_status },
{ .id = WIIPROTO_REQ_STATUS, .size = 2, .func = handler_status_K },
{ .id = WIIPROTO_REQ_DATA, .size = 21, .func = handler_data },
{ .id = WIIPROTO_REQ_DATA, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_RETURN, .size = 4, .func = handler_return },
{ .id = WIIPROTO_REQ_RETURN, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_K, .size = 2, .func = handler_keys },
{ .id = WIIPROTO_REQ_DRM_KA, .size = 5, .func = handler_drm_KA },
{ .id = WIIPROTO_REQ_DRM_KA, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KE, .size = 10, .func = handler_drm_KE },
{ .id = WIIPROTO_REQ_DRM_KE, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KAI, .size = 17, .func = handler_drm_KAI },
{ .id = WIIPROTO_REQ_DRM_KAI, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KEE, .size = 21, .func = handler_drm_KEE },
{ .id = WIIPROTO_REQ_DRM_KEE, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KAE, .size = 21, .func = handler_drm_KAE },
{ .id = WIIPROTO_REQ_DRM_KAE, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KIE, .size = 21, .func = handler_drm_KIE },
{ .id = WIIPROTO_REQ_DRM_KIE, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_KAIE, .size = 21, .func = handler_drm_KAIE },
{ .id = WIIPROTO_REQ_DRM_KAIE, .size = 2, .func = handler_generic_K },
{ .id = WIIPROTO_REQ_DRM_E, .size = 21, .func = handler_drm_E },
{ .id = WIIPROTO_REQ_DRM_SKAI1, .size = 21, .func = handler_drm_SKAI1 },
{ .id = WIIPROTO_REQ_DRM_SKAI2, .size = 21, .func = handler_drm_SKAI2 },
@ -970,7 +994,6 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
struct wiiproto_handler *h;
int i;
unsigned long flags;
bool handled = false;
if (size < 1)
return -EINVAL;
@ -981,11 +1004,11 @@ static int wiimote_hid_event(struct hid_device *hdev, struct hid_report *report,
h = &handlers[i];
if (h->id == raw_data[0] && h->size < size) {
h->func(wdata, &raw_data[1]);
handled = true;
break;
}
}
if (!handled)
if (!handlers[i].id)
hid_warn(hdev, "Unhandled report %hhu size %d\n", raw_data[0],
size);
@ -1160,6 +1183,7 @@ static void wiimote_destroy(struct wiimote_data *wdata)
wiimote_leds_destroy(wdata);
power_supply_unregister(&wdata->battery);
kfree(wdata->battery.name);
input_unregister_device(wdata->accel);
input_unregister_device(wdata->ir);
input_unregister_device(wdata->input);
@ -1216,9 +1240,14 @@ static int wiimote_hid_probe(struct hid_device *hdev,
wdata->battery.properties = wiimote_battery_props;
wdata->battery.num_properties = ARRAY_SIZE(wiimote_battery_props);
wdata->battery.get_property = wiimote_battery_get_property;
wdata->battery.name = "wiimote_battery";
wdata->battery.type = POWER_SUPPLY_TYPE_BATTERY;
wdata->battery.use_for_apm = 0;
wdata->battery.name = kasprintf(GFP_KERNEL, "wiimote_battery_%s",
wdata->hdev->uniq);
if (!wdata->battery.name) {
ret = -ENOMEM;
goto err_battery_name;
}
ret = power_supply_register(&wdata->hdev->dev, &wdata->battery);
if (ret) {
@ -1254,6 +1283,8 @@ static int wiimote_hid_probe(struct hid_device *hdev,
return ret;
err_battery:
kfree(wdata->battery.name);
err_battery_name:
input_unregister_device(wdata->input);
wdata->input = NULL;
err_input:
@ -1283,6 +1314,8 @@ static void wiimote_hid_remove(struct hid_device *hdev)
static const struct hid_device_id wiimote_hid_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_WIIMOTE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_NINTENDO,
USB_DEVICE_ID_NINTENDO_WIIMOTE2) },
{ }
};
MODULE_DEVICE_TABLE(hid, wiimote_hid_devices);

View file

@ -24,13 +24,11 @@
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/usb.h>
#include <linux/module.h>
#include "hid-ids.h"
#ifdef CONFIG_ZEROPLUS_FF
#include "usbhid/usbhid.h"
struct zpff_device {
struct hid_report *report;
@ -59,7 +57,7 @@ static int zpff_play(struct input_dev *dev, void *data,
zpff->report->field[2]->value[0] = left;
zpff->report->field[3]->value[0] = right;
dbg_hid("running with 0x%02x 0x%02x\n", left, right);
usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT);
return 0;
}
@ -104,7 +102,7 @@ static int zpff_init(struct hid_device *hid)
zpff->report->field[1]->value[0] = 0x02;
zpff->report->field[2]->value[0] = 0x00;
zpff->report->field[3]->value[0] = 0x00;
usbhid_submit_report(hid, zpff->report, USB_DIR_OUT);
hid_hw_request(hid, zpff->report, HID_REQ_SET_REPORT);
hid_info(hid, "force feedback for Zeroplus based devices by Anssi Hannula <anssi.hannula@gmail.com>\n");

View file

@ -563,6 +563,36 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
return ret;
}
static void i2c_hid_request(struct hid_device *hid, struct hid_report *rep,
int reqtype)
{
struct i2c_client *client = hid->driver_data;
char *buf;
int ret;
int len = i2c_hid_get_report_length(rep) - 2;
buf = kzalloc(len, GFP_KERNEL);
if (!buf)
return;
switch (reqtype) {
case HID_REQ_GET_REPORT:
ret = i2c_hid_get_raw_report(hid, rep->id, buf, len, rep->type);
if (ret < 0)
dev_err(&client->dev, "%s: unable to get report: %d\n",
__func__, ret);
else
hid_input_report(hid, rep->type, buf, ret, 0);
break;
case HID_REQ_SET_REPORT:
hid_output_report(rep, buf);
i2c_hid_output_raw_report(hid, buf, len, rep->type);
break;
}
kfree(buf);
}
static int i2c_hid_parse(struct hid_device *hid)
{
struct i2c_client *client = hid->driver_data;
@ -742,6 +772,7 @@ static struct hid_ll_driver i2c_hid_ll_driver = {
.open = i2c_hid_open,
.close = i2c_hid_close,
.power = i2c_hid_power,
.request = i2c_hid_request,
.hidinput_input_event = i2c_hid_hidinput_input_event,
};

View file

@ -639,7 +639,7 @@ static void __usbhid_submit_report(struct hid_device *hid, struct hid_report *re
}
}
void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
static void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, unsigned char dir)
{
struct usbhid_device *usbhid = hid->driver_data;
unsigned long flags;
@ -648,7 +648,6 @@ void usbhid_submit_report(struct hid_device *hid, struct hid_report *report, uns
__usbhid_submit_report(hid, report, dir);
spin_unlock_irqrestore(&usbhid->lock, flags);
}
EXPORT_SYMBOL_GPL(usbhid_submit_report);
/* Workqueue routine to send requests to change LEDs */
static void hid_led(struct work_struct *work)
@ -706,7 +705,7 @@ static int usb_hidinput_input_event(struct input_dev *dev, unsigned int type, un
return 0;
}
int usbhid_wait_io(struct hid_device *hid)
static int usbhid_wait_io(struct hid_device *hid)
{
struct usbhid_device *usbhid = hid->driver_data;
@ -720,7 +719,6 @@ int usbhid_wait_io(struct hid_device *hid)
return 0;
}
EXPORT_SYMBOL_GPL(usbhid_wait_io);
static int hid_set_idle(struct usb_device *dev, int ifnum, int report, int idle)
{
@ -1243,6 +1241,32 @@ static int usbhid_power(struct hid_device *hid, int lvl)
return r;
}
static void usbhid_request(struct hid_device *hid, struct hid_report *rep, int reqtype)
{
switch (reqtype) {
case HID_REQ_GET_REPORT:
usbhid_submit_report(hid, rep, USB_DIR_IN);
break;
case HID_REQ_SET_REPORT:
usbhid_submit_report(hid, rep, USB_DIR_OUT);
break;
}
}
static int usbhid_idle(struct hid_device *hid, int report, int idle,
int reqtype)
{
struct usb_device *dev = hid_to_usb_dev(hid);
struct usb_interface *intf = to_usb_interface(hid->dev.parent);
struct usb_host_interface *interface = intf->cur_altsetting;
int ifnum = interface->desc.bInterfaceNumber;
if (reqtype != HID_REQ_SET_IDLE)
return -EINVAL;
return hid_set_idle(dev, ifnum, report, idle);
}
static struct hid_ll_driver usb_hid_driver = {
.parse = usbhid_parse,
.start = usbhid_start,
@ -1251,6 +1275,9 @@ static struct hid_ll_driver usb_hid_driver = {
.close = usbhid_close,
.power = usbhid_power,
.hidinput_input_event = usb_hidinput_input_event,
.request = usbhid_request,
.wait = usbhid_wait_io,
.idle = usbhid_idle,
};
static int usbhid_probe(struct usb_interface *intf, const struct usb_device_id *id)

View file

@ -263,8 +263,8 @@ static void pidff_set_envelope_report(struct pidff_device *pidff,
envelope->attack_level,
pidff->set_envelope[PID_ATTACK_LEVEL].value[0]);
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
USB_DIR_OUT);
hid_hw_request(pidff->hid, pidff->reports[PID_SET_ENVELOPE],
HID_REQ_SET_REPORT);
}
/*
@ -290,8 +290,8 @@ static void pidff_set_constant_force_report(struct pidff_device *pidff,
pidff_set_signed(&pidff->set_constant[PID_MAGNITUDE],
effect->u.constant.level);
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONSTANT],
USB_DIR_OUT);
hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONSTANT],
HID_REQ_SET_REPORT);
}
/*
@ -325,8 +325,8 @@ static void pidff_set_effect_report(struct pidff_device *pidff,
pidff->effect_direction);
pidff->set_effect[PID_START_DELAY].value[0] = effect->replay.delay;
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
USB_DIR_OUT);
hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
HID_REQ_SET_REPORT);
}
/*
@ -357,8 +357,8 @@ static void pidff_set_periodic_report(struct pidff_device *pidff,
pidff_set(&pidff->set_periodic[PID_PHASE], effect->u.periodic.phase);
pidff->set_periodic[PID_PERIOD].value[0] = effect->u.periodic.period;
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_PERIODIC],
USB_DIR_OUT);
hid_hw_request(pidff->hid, pidff->reports[PID_SET_PERIODIC],
HID_REQ_SET_REPORT);
}
@ -399,8 +399,8 @@ static void pidff_set_condition_report(struct pidff_device *pidff,
effect->u.condition[i].left_saturation);
pidff_set(&pidff->set_condition[PID_DEAD_BAND],
effect->u.condition[i].deadband);
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_CONDITION],
USB_DIR_OUT);
hid_hw_request(pidff->hid, pidff->reports[PID_SET_CONDITION],
HID_REQ_SET_REPORT);
}
}
@ -440,8 +440,8 @@ static void pidff_set_ramp_force_report(struct pidff_device *pidff,
effect->u.ramp.start_level);
pidff_set_signed(&pidff->set_ramp[PID_RAMP_END],
effect->u.ramp.end_level);
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_RAMP],
USB_DIR_OUT);
hid_hw_request(pidff->hid, pidff->reports[PID_SET_RAMP],
HID_REQ_SET_REPORT);
}
/*
@ -465,19 +465,19 @@ static int pidff_request_effect_upload(struct pidff_device *pidff, int efnum)
int j;
pidff->create_new_effect_type->value[0] = efnum;
usbhid_submit_report(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
USB_DIR_OUT);
hid_hw_request(pidff->hid, pidff->reports[PID_CREATE_NEW_EFFECT],
HID_REQ_SET_REPORT);
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);
hid_hw_wait(pidff->hid);
for (j = 0; j < 60; j++) {
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);
hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_LOAD],
HID_REQ_GET_REPORT);
hid_hw_wait(pidff->hid);
if (pidff->block_load_status->value[0] ==
pidff->status_id[PID_BLOCK_LOAD_SUCCESS]) {
hid_dbg(pidff->hid, "device reported free memory: %d bytes\n",
@ -513,8 +513,8 @@ static void pidff_playback_pid(struct pidff_device *pidff, int pid_id, int n)
pidff->effect_operation[PID_LOOP_COUNT].value[0] = n;
}
usbhid_submit_report(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
USB_DIR_OUT);
hid_hw_request(pidff->hid, pidff->reports[PID_EFFECT_OPERATION],
HID_REQ_SET_REPORT);
}
/**
@ -535,8 +535,8 @@ static int pidff_playback(struct input_dev *dev, int effect_id, int value)
static void pidff_erase_pid(struct pidff_device *pidff, int pid_id)
{
pidff->block_free[PID_EFFECT_BLOCK_INDEX].value[0] = pid_id;
usbhid_submit_report(pidff->hid, pidff->reports[PID_BLOCK_FREE],
USB_DIR_OUT);
hid_hw_request(pidff->hid, pidff->reports[PID_BLOCK_FREE],
HID_REQ_SET_REPORT);
}
/*
@ -551,7 +551,7 @@ static int pidff_erase_effect(struct input_dev *dev, int effect_id)
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);
hid_hw_wait(pidff->hid);
pidff_playback_pid(pidff, pid_id, 0);
pidff_erase_pid(pidff, pid_id);
@ -718,8 +718,8 @@ static void pidff_set_gain(struct input_dev *dev, u16 gain)
struct pidff_device *pidff = dev->ff->private;
pidff_set(&pidff->device_gain[PID_DEVICE_GAIN_FIELD], gain);
usbhid_submit_report(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
USB_DIR_OUT);
hid_hw_request(pidff->hid, pidff->reports[PID_DEVICE_GAIN],
HID_REQ_SET_REPORT);
}
static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
@ -744,8 +744,8 @@ static void pidff_autocenter(struct pidff_device *pidff, u16 magnitude)
pidff->set_effect[PID_DIRECTION_ENABLE].value[0] = 1;
pidff->set_effect[PID_START_DELAY].value[0] = 0;
usbhid_submit_report(pidff->hid, pidff->reports[PID_SET_EFFECT],
USB_DIR_OUT);
hid_hw_request(pidff->hid, pidff->reports[PID_SET_EFFECT],
HID_REQ_SET_REPORT);
}
/*
@ -1158,19 +1158,19 @@ static void pidff_reset(struct pidff_device *pidff)
pidff->device_control->value[0] = pidff->control_id[PID_RESET];
/* We reset twice as sometimes hid_wait_io isn't waiting long enough */
usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
usbhid_wait_io(hid);
usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
usbhid_wait_io(hid);
hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
hid_hw_wait(hid);
hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
hid_hw_wait(hid);
pidff->device_control->value[0] =
pidff->control_id[PID_ENABLE_ACTUATORS];
usbhid_submit_report(hid, pidff->reports[PID_DEVICE_CONTROL], USB_DIR_OUT);
usbhid_wait_io(hid);
hid_hw_request(hid, pidff->reports[PID_DEVICE_CONTROL], HID_REQ_SET_REPORT);
hid_hw_wait(hid);
/* pool report is sometimes messed up, refetch it */
usbhid_submit_report(hid, pidff->reports[PID_POOL], USB_DIR_IN);
usbhid_wait_io(hid);
hid_hw_request(hid, pidff->reports[PID_POOL], HID_REQ_GET_REPORT);
hid_hw_wait(hid);
if (pidff->pool[PID_SIMULTANEOUS_MAX].value) {
while (pidff->pool[PID_SIMULTANEOUS_MAX].value[0] < 2) {
@ -1181,9 +1181,9 @@ static void pidff_reset(struct pidff_device *pidff)
break;
}
hid_dbg(pidff->hid, "pid_pool requested again\n");
usbhid_submit_report(hid, pidff->reports[PID_POOL],
USB_DIR_IN);
usbhid_wait_io(hid);
hid_hw_request(hid, pidff->reports[PID_POOL],
HID_REQ_GET_REPORT);
hid_hw_wait(hid);
}
}
}
@ -1269,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(hid, pidff->reports[PID_DEVICE_GAIN],
USB_DIR_OUT);
hid_hw_request(hid, pidff->reports[PID_DEVICE_GAIN],
HID_REQ_SET_REPORT);
}
error = pidff_check_autocenter(pidff, dev);

View file

@ -705,8 +705,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (report == NULL)
break;
usbhid_submit_report(hid, report, USB_DIR_IN);
usbhid_wait_io(hid);
hid_hw_request(hid, report, HID_REQ_GET_REPORT);
hid_hw_wait(hid);
r = 0;
break;
@ -724,8 +724,8 @@ static long hiddev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
if (report == NULL)
break;
usbhid_submit_report(hid, report, USB_DIR_OUT);
usbhid_wait_io(hid);
hid_hw_request(hid, report, HID_REQ_SET_REPORT);
hid_hw_wait(hid);
r = 0;
break;

View file

@ -34,12 +34,9 @@
#include <linux/input.h>
/* API provided by hid-core.c for USB HID drivers */
int usbhid_wait_io(struct hid_device* hid);
void usbhid_close(struct hid_device *hid);
int usbhid_open(struct hid_device *hid);
void usbhid_init_reports(struct hid_device *hid);
void usbhid_submit_report
(struct hid_device *hid, struct hid_report *report, unsigned char dir);
int usbhid_get_power(struct hid_device *hid);
void usbhid_put_power(struct hid_device *hid);
struct usb_interface *usbhid_find_interface(int minor);

View file

@ -22,11 +22,12 @@
*
*/
#define HID_DEBUG_BUFSIZE 512
#ifdef CONFIG_DEBUG_FS
#define HID_DEBUG_BUFSIZE 512
void hid_dump_input(struct hid_device *, struct hid_usage *, __s32);
void hid_dump_report(struct hid_device *, int , u8 *, int);
void hid_dump_device(struct hid_device *, struct seq_file *);
void hid_dump_field(struct hid_field *, int, struct seq_file *);
char *hid_resolv_usage(unsigned, struct seq_file *);
@ -50,6 +51,7 @@ struct hid_debug_list {
#else
#define hid_dump_input(a,b,c) do { } while (0)
#define hid_dump_report(a,b,c,d) do { } while (0)
#define hid_dump_device(a,b) do { } while (0)
#define hid_dump_field(a,b,c) do { } while (0)
#define hid_resolv_usage(a,b) do { } while (0)

View file

@ -282,6 +282,7 @@ struct hid_item {
#define HID_QUIRK_BADPAD 0x00000020
#define HID_QUIRK_MULTI_INPUT 0x00000040
#define HID_QUIRK_HIDINPUT_FORCE 0x00000080
#define HID_QUIRK_NO_EMPTY_INPUT 0x00000100
#define HID_QUIRK_SKIP_OUTPUT_REPORTS 0x00010000
#define HID_QUIRK_FULLSPEED_INTERVAL 0x10000000
#define HID_QUIRK_NO_INIT_REPORTS 0x20000000
@ -456,7 +457,8 @@ struct hid_device { /* device report descriptor */
unsigned country; /* HID country */
struct hid_report_enum report_enum[HID_REPORT_TYPES];
struct semaphore driver_lock; /* protects the current driver */
struct semaphore driver_lock; /* protects the current driver, except during input */
struct semaphore driver_input_lock; /* protects the current driver */
struct device dev; /* device */
struct hid_driver *driver;
struct hid_ll_driver *ll_driver;
@ -477,6 +479,7 @@ struct hid_device { /* device report descriptor */
unsigned int status; /* see STAT flags above */
unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */
bool io_started; /* Protected by driver_lock. If IO has started */
struct list_head inputs; /* The list of inputs */
void *hiddev; /* The hiddev structure */
@ -512,6 +515,7 @@ struct hid_device { /* device report descriptor */
struct dentry *debug_rdesc;
struct dentry *debug_events;
struct list_head debug_list;
struct mutex debug_list_lock;
wait_queue_head_t debug_wait;
};
@ -599,6 +603,10 @@ struct hid_usage_id {
* @resume: invoked on resume if device was not reset (NULL means nop)
* @reset_resume: invoked on resume if device was reset (NULL means nop)
*
* probe should return -errno on error, or 0 on success. During probe,
* input will not be passed to raw_event unless hid_device_io_start is
* called.
*
* raw_event and event should return 0 on no action performed, 1 when no
* further processing should be done and negative on error
*
@ -662,6 +670,9 @@ struct hid_driver {
* @hidinput_input_event: event input event (e.g. ff or leds)
* @parse: this method is called only once to parse the device data,
* shouldn't allocate anything to not leak memory
* @request: send report request to device (e.g. feature report)
* @wait: wait for buffered io to complete (send/recv reports)
* @idle: send idle request to device
*/
struct hid_ll_driver {
int (*start)(struct hid_device *hdev);
@ -676,6 +687,13 @@ struct hid_ll_driver {
unsigned int code, int value);
int (*parse)(struct hid_device *hdev);
void (*request)(struct hid_device *hdev,
struct hid_report *report, int reqtype);
int (*wait)(struct hid_device *hdev);
int (*idle)(struct hid_device *hdev, int report, int idle, int reqtype);
};
#define PM_HINT_FULLON 1<<5
@ -737,6 +755,44 @@ const struct hid_device_id *hid_match_id(struct hid_device *hdev,
const struct hid_device_id *id);
s32 hid_snto32(__u32 value, unsigned n);
/**
* hid_device_io_start - enable HID input during probe, remove
*
* @hid - the device
*
* This should only be called during probe or remove and only be
* called by the thread calling probe or remove. It will allow
* incoming packets to be delivered to the driver.
*/
static inline void hid_device_io_start(struct hid_device *hid) {
if (hid->io_started) {
dev_warn(&hid->dev, "io already started");
return;
}
hid->io_started = true;
up(&hid->driver_input_lock);
}
/**
* hid_device_io_stop - disable HID input during probe, remove
*
* @hid - the device
*
* Should only be called after hid_device_io_start. It will prevent
* incoming packets from going to the driver for the duration of
* probe, remove. If called during probe, packets will still go to the
* driver after probe is complete. This function should only be called
* by the thread calling probe or remove.
*/
static inline void hid_device_io_stop(struct hid_device *hid) {
if (!hid->io_started) {
dev_warn(&hid->dev, "io already stopped");
return;
}
hid->io_started = false;
down(&hid->driver_input_lock);
}
/**
* hid_map_usage - map usage input bits
*
@ -883,6 +939,49 @@ static inline int hid_hw_power(struct hid_device *hdev, int level)
return hdev->ll_driver->power ? hdev->ll_driver->power(hdev, level) : 0;
}
/**
* hid_hw_request - send report request to device
*
* @hdev: hid device
* @report: report to send
* @reqtype: hid request type
*/
static inline void hid_hw_request(struct hid_device *hdev,
struct hid_report *report, int reqtype)
{
if (hdev->ll_driver->request)
hdev->ll_driver->request(hdev, report, reqtype);
}
/**
* hid_hw_idle - send idle request to device
*
* @hdev: hid device
* @report: report to control
* @idle: idle state
* @reqtype: hid request type
*/
static inline int hid_hw_idle(struct hid_device *hdev, int report, int idle,
int reqtype)
{
if (hdev->ll_driver->idle)
return hdev->ll_driver->idle(hdev, report, idle, reqtype);
return 0;
}
/**
* hid_hw_wait - wait for buffered io to complete
*
* @hdev: hid device
*/
static inline void hid_hw_wait(struct hid_device *hdev)
{
if (hdev->ll_driver->wait)
hdev->ll_driver->wait(hdev);
}
int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
int interrupt);

View file

@ -17,10 +17,9 @@
/*
* Ugly hack to work around failing compilation on systems that don't
* yet populate new version of hidraw.h to userspace.
*
* If you need this, please have your distro update the kernel headers.
*/
#ifndef HIDIOCSFEATURE
#warning Please have your distro update the userspace kernel headers
#define HIDIOCSFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x06, len)
#define HIDIOCGFEATURE(len) _IOC(_IOC_WRITE|_IOC_READ, 'H', 0x07, len)
#endif