Commit f62f6191 authored by Linus Torvalds's avatar Linus Torvalds

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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (68 commits)
  hid-input/battery: add FEATURE quirk
  hid-input/battery: remove battery_val
  hid-input/battery: power-supply type really *is* a battery
  hid-input/battery: make the battery setup common for INPUTs and FEATUREs
  hid-input/battery: deal with both FEATURE and INPUT report batteries
  hid-input/battery: add quirks for battery
  hid-input/battery: remove apparently redundant kmalloc
  hid-input: add support for HID devices reporting Battery Strength
  HID: hid-multitouch: add support 9 new Xiroku devices
  HID: multitouch: add support for 3M 32"
  HID: multitouch: add support of Atmel multitouch panels
  HID: usbhid: defer LED setting to a workqueue
  HID: usbhid: hid-core: submit queued urbs before suspend
  HID: usbhid: remove LED_ON
  HID: emsff: use symbolic name instead of hardcoded PID constant
  HID: Enable HID_QUIRK_MULTI_INPUT for Trio Linker Plus II
  HID: Kconfig: fix syntax
  HID: introduce proper dependency of HID_BATTERY on POWER_SUPPLY
  HID: multitouch: support PixArt optical touch screen
  HID: make parser more verbose about parsing errors by default
  ...

Fix up rename/delete conflict in drivers/hid/hid-hyperv.c (removed in
staging, moved in this branch) and similarly for the rules for same file
in drivers/staging/hv/{Kconfig,Makefile}.
parents d04baa15 420174af
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/quirks
Date: November 2011
Contact: Benjamin Tissoires <benjamin.tissoires@gmail.com>
Description: The integer value of this attribute corresponds to the
quirks actually in place to handle the device's protocol.
When read, this attribute returns the current settings (see
MT_QUIRKS_* in hid-multitouch.c).
When written this attribute change on the fly the quirks, then
the protocol to handle the device.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/isku/roccatisku<minor>/actual_profile
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The integer value of this attribute ranges from 0-4.
When read, this attribute returns the number of the actual
profile. This value is persistent, so its equivalent to the
profile that's active when the device is powered on next time.
When written, this file sets the number of the startup profile
and the device activates this profile immediately.
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>/info
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns general data like firmware version.
The data is 6 bytes long.
This file is readonly.
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>/key_mask
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one deactivate certain keys like
windows and application keys, to prevent accidental presses.
Profile number for which this settings occur is included in
written data. The data has to be 6 bytes long.
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>/isku/roccatisku<minor>/keys_capslock
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the function of the
capslock key for a specific profile. Profile number is included
in written data. The data has to be 6 bytes long.
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>/isku/roccatisku<minor>/keys_easyzone
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the function of the
easyzone keys for a specific profile. Profile number is included
in written data. The data has to be 65 bytes long.
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>/isku/roccatisku<minor>/keys_function
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the function of the
function keys for a specific profile. Profile number is included
in written data. The data has to be 41 bytes long.
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>/isku/roccatisku<minor>/keys_macro
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the function of the macro
keys for a specific profile. Profile number is included in
written data. The data has to be 35 bytes long.
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>/isku/roccatisku<minor>/keys_media
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the function of the media
keys for a specific profile. Profile number is included in
written data. The data has to be 29 bytes long.
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>/isku/roccatisku<minor>/keys_thumbster
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the function of the
thumbster keys for a specific profile. Profile number is included
in written data. The data has to be 23 bytes long.
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>/isku/roccatisku<minor>/last_set
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one set the time in secs since
epoch in which the last configuration took place.
The data has to be 20 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>/isku/roccatisku<minor>/light
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.
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>/isku/roccatisku<minor>/macro
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one store macros with max 500
keystrokes for a specific button for a specific profile.
Button and profile numbers are included in written data.
The data has to be 2083 bytes long.
Before reading this file, control has to be written to select
which profile and key 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>/isku/roccatisku<minor>/control
Date: June 2011
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>/isku/roccatisku<minor>/talk
Date: June 2011
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When written, this file lets one trigger easyshift functionality
from the host.
The data has to be 16 bytes long.
This file is writeonly.
Users: http://roccat.sourceforge.net
......@@ -8,3 +8,15 @@ Contact: David Herrmann <dh.herrmann@googlemail.com>
Description: Make it possible to set/get current led state. Reading from it
returns 0 if led is off and 1 if it is on. Writing 0 to it
disables the led, writing 1 enables it.
What: /sys/bus/hid/drivers/wiimote/<dev>/extension
Date: August 2011
KernelVersion: 3.2
Contact: David Herrmann <dh.herrmann@googlemail.com>
Description: This file contains the currently connected and initialized
extensions. It can be one of: none, motionp, nunchuck, classic,
motionp+nunchuck, motionp+classic
motionp is the official Nintendo Motion+ extension, nunchuck is
the official Nintendo Nunchuck extension and classic is the
Nintendo Classic Controller extension. The motionp extension can
be combined with the other two.
......@@ -31,6 +31,11 @@ config HID
If unsure, say Y.
config HID_BATTERY_STRENGTH
bool
depends on HID && POWER_SUPPLY && HID = POWER_SUPPLY
default y
config HIDRAW
bool "/dev/hidraw raw HID device support"
depends on HID
......@@ -335,6 +340,7 @@ config HID_MULTITOUCH
Say Y here if you have one of the following devices:
- 3M PCT touch screens
- ActionStar dual touch panels
- Atmel panels
- Cando dual touch panels
- Chunghwa panels
- CVTouch panels
......@@ -349,12 +355,15 @@ config HID_MULTITOUCH
- Lumio CrystalTouch panels
- MosArt dual-touch panels
- PenMount dual touch panels
- PixArt optical touch screen
- Pixcir dual touch panels
- Quanta panels
- eGalax dual-touch panels, including the Joojoo and Wetab tablets
- Stantum multitouch panels
- Touch International Panels
- Unitec Panels
- XAT optical touch panels
- Xiroku optical touch panels
If unsure, say N.
......@@ -466,12 +475,6 @@ config HID_PRIMAX
Support for Primax devices that are not fully compliant with the
HID standard.
config HID_QUANTA
tristate "Quanta Optical Touch panels"
depends on USB_HID
---help---
Support for Quanta Optical Touch dual-touch panels.
config HID_ROCCAT
tristate "Roccat special event support"
depends on USB_HID
......@@ -492,6 +495,13 @@ config HID_ROCCAT_ARVO
---help---
Support for Roccat Arvo keyboard.
config HID_ROCCAT_ISKU
tristate "Roccat Isku keyboard support"
depends on USB_HID
depends on HID_ROCCAT
---help---
Support for Roccat Isku keyboard.
config HID_ROCCAT_KONE
tristate "Roccat Kone Mouse support"
depends on USB_HID
......@@ -560,6 +570,12 @@ config GREENASIA_FF
(like MANTA Warrior MM816 and SpeedLink Strike2 SL-6635) or adapter
and want to enable force feedback support for it.
config HID_HYPERV_MOUSE
tristate "Microsoft Hyper-V mouse driver"
depends on HYPERV
---help---
Select this option to enable the Hyper-V mouse driver.
config HID_SMARTJOYPLUS
tristate "SmartJoy PLUS PS2/USB adapter support"
depends on USB_HID
......@@ -620,9 +636,19 @@ config HID_WIIMOTE
depends on BT_HIDP
depends on LEDS_CLASS
select POWER_SUPPLY
select INPUT_FF_MEMLESS
---help---
Support for the Nintendo Wii Remote bluetooth device.
config HID_WIIMOTE_EXT
bool "Nintendo Wii Remote Extension support"
depends on HID_WIIMOTE
default HID_WIIMOTE
---help---
Support for extension controllers of the Nintendo Wii Remote. Say yes
here if you want to use the Nintendo Motion+, Nunchuck or Classic
extension controllers with your Wii Remote.
config HID_ZEROPLUS
tristate "Zeroplus based game controller support"
depends on USB_HID
......
......@@ -25,6 +25,14 @@ ifdef CONFIG_LOGIWHEELS_FF
hid-logitech-y += hid-lg4ff.o
endif
hid-wiimote-y := hid-wiimote-core.o
ifdef CONFIG_HID_WIIMOTE_EXT
hid-wiimote-y += hid-wiimote-ext.o
endif
ifdef CONFIG_DEBUG_FS
hid-wiimote-y += hid-wiimote-debug.o
endif
obj-$(CONFIG_HID_A4TECH) += hid-a4tech.o
obj-$(CONFIG_HID_ACRUX) += hid-axff.o
obj-$(CONFIG_HID_APPLE) += hid-apple.o
......@@ -38,6 +46,7 @@ obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtekff.o
obj-$(CONFIG_HID_HYPERV_MOUSE) += hid-hyperv.o
obj-$(CONFIG_HID_KENSINGTON) += hid-kensington.o
obj-$(CONFIG_HID_KEYTOUCH) += hid-keytouch.o
obj-$(CONFIG_HID_KYE) += hid-kye.o
......@@ -51,7 +60,6 @@ obj-$(CONFIG_HID_MULTITOUCH) += hid-multitouch.o
obj-$(CONFIG_HID_NTRIG) += hid-ntrig.o
obj-$(CONFIG_HID_ORTEK) += hid-ortek.o
obj-$(CONFIG_HID_PRODIKEYS) += hid-prodikeys.o
obj-$(CONFIG_HID_QUANTA) += hid-quanta.o
obj-$(CONFIG_HID_PANTHERLORD) += hid-pl.o
obj-$(CONFIG_HID_PETALYNX) += hid-petalynx.o
obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
......@@ -59,6 +67,7 @@ obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o
obj-$(CONFIG_HID_ROCCAT_COMMON) += hid-roccat-common.o
obj-$(CONFIG_HID_ROCCAT_ARVO) += hid-roccat-arvo.o
obj-$(CONFIG_HID_ROCCAT_ISKU) += hid-roccat-isku.o
obj-$(CONFIG_HID_ROCCAT_KONE) += hid-roccat-kone.o
obj-$(CONFIG_HID_ROCCAT_KONEPLUS) += hid-roccat-koneplus.o
obj-$(CONFIG_HID_ROCCAT_KOVAPLUS) += hid-roccat-kovaplus.o
......
This diff is collapsed.
......@@ -114,6 +114,14 @@ static const struct hid_usage_entry hid_usage_table[] = {
{0, 0xbd, "FlareRelease"},
{0, 0xbe, "LandingGear"},
{0, 0xbf, "ToeBrake"},
{ 6, 0, "GenericDeviceControls" },
{0, 0x20, "BatteryStrength" },
{0, 0x21, "WirelessChannel" },
{0, 0x22, "WirelessID" },
{0, 0x23, "DiscoverWirelessControl" },
{0, 0x24, "SecurityCodeCharacterEntered" },
{0, 0x25, "SecurityCodeCharactedErased" },
{0, 0x26, "SecurityCodeCleared" },
{ 7, 0, "Keyboard" },
{ 8, 0, "LED" },
{0, 0x01, "NumLock"},
......
......@@ -140,7 +140,7 @@ static int ems_probe(struct hid_device *hdev, const struct hid_device_id *id)
}
static const struct hid_device_id ems_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, 0x118) },
{ HID_USB_DEVICE(USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II) },
{ }
};
MODULE_DEVICE_TABLE(hid, ems_devices);
......
This diff is collapsed.
......@@ -21,6 +21,7 @@
#define USB_VENDOR_ID_3M 0x0596
#define USB_DEVICE_ID_3M1968 0x0500
#define USB_DEVICE_ID_3M2256 0x0502
#define USB_DEVICE_ID_3M3266 0x0506
#define USB_VENDOR_ID_A4TECH 0x09da
#define USB_DEVICE_ID_A4TECH_WCP32PU 0x0006
......@@ -124,6 +125,7 @@
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI 0x0239
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO 0x023a
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS 0x023b
#define USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI 0x0255
#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
......@@ -145,6 +147,9 @@
#define USB_DEVICE_ID_ATEN_4PORTKVM 0x2205
#define USB_DEVICE_ID_ATEN_4PORTKVMC 0x2208
#define USB_VENDOR_ID_ATMEL 0x03eb
#define USB_DEVICE_ID_ATMEL_MULTITOUCH 0x211c
#define USB_VENDOR_ID_AVERMEDIA 0x07ca
#define USB_DEVICE_ID_AVER_FM_MR800 0xb800
......@@ -230,11 +235,14 @@
#define USB_VENDOR_ID_DWAV 0x0eef
#define USB_DEVICE_ID_EGALAX_TOUCHCONTROLLER 0x0001
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH 0x480d
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH1 0x720c
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH2 0x72a1
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH3 0x480e
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH4 0x726b
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480D 0x480d
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_480E 0x480e
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_720C 0x720c
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_726B 0x726b
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72A1 0x72a1
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_72FA 0x72fa
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_7302 0x7302
#define USB_DEVICE_ID_DWAV_EGALAX_MULTITOUCH_A001 0xa001
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
......@@ -356,6 +364,9 @@
#define USB_VENDOR_ID_HANVON 0x20b3
#define USB_DEVICE_ID_HANVON_MULTITOUCH 0x0a18
#define USB_VENDOR_ID_HANVON_ALT 0x22ed
#define USB_DEVICE_ID_HANVON_ALT_MULTITOUCH 0x1010
#define USB_VENDOR_ID_HAPP 0x078b
#define USB_DEVICE_ID_UGCI_DRIVING 0x0010
#define USB_DEVICE_ID_UGCI_FLYING 0x0020
......@@ -571,6 +582,11 @@
#define USB_VENDOR_ID_PI_ENGINEERING 0x05f3
#define USB_DEVICE_ID_PI_ENGINEERING_VEC_USB_FOOTPEDAL 0xff
#define USB_VENDOR_ID_PIXART 0x093a
#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN 0x8001
#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1 0x8002
#define USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2 0x8003
#define USB_VENDOR_ID_PLAYDOTCOM 0x0b43
#define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII 0x0003
......@@ -581,11 +597,14 @@
#define USB_DEVICE_ID_PRODIGE_CORDLESS 0x3062
#define USB_VENDOR_ID_QUANTA 0x0408
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH 0x3000
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3001 0x3001
#define USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH_3008 0x3008
#define USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN 0x3001
#define USB_VENDOR_ID_ROCCAT 0x1e7d
#define USB_DEVICE_ID_ROCCAT_ARVO 0x30d4
#define USB_DEVICE_ID_ROCCAT_ISKU 0x319c
#define USB_DEVICE_ID_ROCCAT_KONE 0x2ced
#define USB_DEVICE_ID_ROCCAT_KONEPLUS 0x2d51
#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
......@@ -679,6 +698,7 @@
#define USB_VENDOR_ID_WACOM 0x056a
#define USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH 0x81
#define USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH 0x00BD
#define USB_VENDOR_ID_WALTOP 0x172f
#define USB_DEVICE_ID_WALTOP_SLIM_TABLET_5_8_INCH 0x0032
......@@ -707,6 +727,17 @@
#define USB_VENDOR_ID_XAT 0x2505
#define USB_DEVICE_ID_XAT_CSR 0x0220
#define USB_VENDOR_ID_XIROKU 0x1477
#define USB_DEVICE_ID_XIROKU_SPX 0x1006
#define USB_DEVICE_ID_XIROKU_MPX 0x1007
#define USB_DEVICE_ID_XIROKU_CSR 0x100e
#define USB_DEVICE_ID_XIROKU_SPX1 0x1021
#define USB_DEVICE_ID_XIROKU_CSR1 0x1022
#define USB_DEVICE_ID_XIROKU_MPX1 0x1023
#define USB_DEVICE_ID_XIROKU_SPX2 0x1024
#define USB_DEVICE_ID_XIROKU_CSR2 0x1025
#define USB_DEVICE_ID_XIROKU_MPX2 0x1026
#define USB_VENDOR_ID_YEALINK 0x6993
#define USB_DEVICE_ID_YEALINK_P1K_P4K_B2K 0xb001
......
......@@ -32,6 +32,8 @@
#include <linux/hid.h>
#include <linux/hid-debug.h>
#include "hid-ids.h"
#define unk KEY_UNKNOWN
static const unsigned char hid_keyboard[256] = {
......@@ -271,6 +273,161 @@ static __s32 hidinput_calc_abs_res(const struct hid_field *field, __u16 code)
return logical_extents / physical_extents;
}
#ifdef CONFIG_HID_BATTERY_STRENGTH
static enum power_supply_property hidinput_battery_props[] = {
POWER_SUPPLY_PROP_PRESENT,
POWER_SUPPLY_PROP_ONLINE,
POWER_SUPPLY_PROP_CAPACITY,
POWER_SUPPLY_PROP_MODEL_NAME,
POWER_SUPPLY_PROP_STATUS
};
#define HID_BATTERY_QUIRK_PERCENT (1 << 0) /* always reports percent */
#define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */
static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI),
HID_BATTERY_QUIRK_PERCENT | HID_BATTERY_QUIRK_FEATURE },
{}
};
static unsigned find_battery_quirk(struct hid_device *hdev)
{
unsigned quirks = 0;
const struct hid_device_id *match;
match = hid_match_id(hdev, hid_battery_quirks);
if (match != NULL)
quirks = match->driver_data;
return quirks;
}
static int hidinput_get_battery_property(struct power_supply *psy,
enum power_supply_property prop,
union power_supply_propval *val)
{
struct hid_device *dev = container_of(psy, struct hid_device, battery);
int ret = 0;
__u8 buf[2] = {};
switch (prop) {
case POWER_SUPPLY_PROP_PRESENT:
case POWER_SUPPLY_PROP_ONLINE:
val->intval = 1;
break;
case POWER_SUPPLY_PROP_CAPACITY:
ret = dev->hid_get_raw_report(dev, dev->battery_report_id,
buf, sizeof(buf),
dev->battery_report_type);
if (ret != 2) {
if (ret >= 0)
ret = -EINVAL;
break;
}
if (dev->battery_min < dev->battery_max &&
buf[1] >= dev->battery_min &&
buf[1] <= dev->battery_max)
val->intval = (100 * (buf[1] - dev->battery_min)) /
(dev->battery_max - dev->battery_min);
break;
case POWER_SUPPLY_PROP_MODEL_NAME:
val->strval = dev->name;
break;
case POWER_SUPPLY_PROP_STATUS:
val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
break;
default:
ret = -EINVAL;
break;
}
return ret;
}
static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type, struct hid_field *field)
{
struct power_supply *battery = &dev->battery;
int ret;
unsigned quirks;
s32 min, max;
if (field->usage->hid != HID_DC_BATTERYSTRENGTH)
return false; /* no match */
if (battery->name != NULL)
goto out; /* already initialized? */
battery->name = kasprintf(GFP_KERNEL, "hid-%s-battery", dev->uniq);
if (battery->name == NULL)
goto out;
battery->type = POWER_SUPPLY_TYPE_BATTERY;
battery->properties = hidinput_battery_props;
battery->num_properties = ARRAY_SIZE(hidinput_battery_props);
battery->use_for_apm = 0;
battery->get_property = hidinput_get_battery_property;
quirks = find_battery_quirk(dev);
hid_dbg(dev, "device %x:%x:%x %d quirks %d\n",
dev->bus, dev->vendor, dev->product, dev->version, quirks);
min = field->logical_minimum;
max = field->logical_maximum;
if (quirks & HID_BATTERY_QUIRK_PERCENT) {
min = 0;
max = 100;
}
if (quirks & HID_BATTERY_QUIRK_FEATURE)
report_type = HID_FEATURE_REPORT;
dev->battery_min = min;
dev->battery_max = max;
dev->battery_report_type = report_type;
dev->battery_report_id = field->report->id;
ret = power_supply_register(&dev->dev, battery);
if (ret != 0) {
hid_warn(dev, "can't register power supply: %d\n", ret);
kfree(battery->name);
battery->name = NULL;
}
out:
return true;
}
static void hidinput_cleanup_battery(struct hid_device *dev)
{
if (!dev->battery.name)
return;
power_supply_unregister(&dev->battery);
kfree(dev->battery.name);
dev->battery.name = NULL;
}
#else /* !CONFIG_HID_BATTERY_STRENGTH */
static bool hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
struct hid_field *field)
{
return false;
}
static void hidinput_cleanup_battery(struct hid_device *dev)
{
}
#endif /* CONFIG_HID_BATTERY_STRENGTH */
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage)
{
......@@ -629,6 +786,13 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
}
break;
case HID_UP_GENDEVCTRLS:
if (hidinput_setup_battery(device, HID_INPUT_REPORT, field))
goto ignore;
else
goto unknown;
break;
case HID_UP_HPVENDOR: /* Reported on a Dutch layout HP5308 */
set_bit(EV_REP, input->evbit);
switch (usage->hid & HID_USAGE) {
......@@ -822,6 +986,12 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
/* Ignore out-of-range values as per HID specification, section 5.10 */
if (value < field->logical_minimum || value > field->logical_maximum) {
dbg_hid("Ignoring out-of-range value %x\n", value);
return;
}
/* report the usage code as scancode if the key status has changed */
if (usage->type == EV_KEY && !!test_bit(usage->code, input->key) != value)
input_event(input, EV_MSC, MSC_SCAN, usage->hid);
......@@ -861,6 +1031,48 @@ int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int
}
EXPORT_SYMBOL_GPL(hidinput_find_field);
struct hid_field *hidinput_get_led_field(struct hid_device *hid)
{
struct hid_report *report;
struct hid_field *field;
int i, j;
list_for_each_entry(report,
&hid->report_enum[HID_OUTPUT_REPORT].report_list,
list) {
for (i = 0; i < report->maxfield; i++) {
field = report->field[i];
for (j = 0; j < field->maxusage; j++)
if (field->usage[j].type == EV_LED)
return field;
}
}
return NULL;
}
EXPORT_SYMBOL_GPL(hidinput_get_led_field);
unsigned int hidinput_count_leds(struct hid_device *hid)
{
struct hid_report *report;
struct hid_field *field;
int i, j;
unsigned int count = 0;
list_for_each_entry(report,
&hid->report_enum[HID_OUTPUT_REPORT].report_list,
list) {
for (i = 0; i < report->maxfield; i++) {
field = report->field[i];
for (j = 0; j < field->maxusage; j++)
if (field->usage[j].type == EV_LED &&
field->value[j])
count += 1;
}
}
return count;
}
EXPORT_SYMBOL_GPL(hidinput_count_leds);
static int hidinput_open(struct input_dev *dev)
{
struct hid_device *hid = input_get_drvdata(dev);
......@@ -882,15 +1094,17 @@ static void report_features(struct hid_device *hid)
struct hid_report *rep;
int i, j;
if (!drv->feature_mapping)
return;
rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
list_for_each_entry(rep, &rep_enum->report_list, list)
for (i = 0; i < rep->maxfield; i++)
for (j = 0; j < rep->field[i]->maxusage; j++)
drv->feature_mapping(hid, rep->field[i],
rep->field[i]->usage + j);
for (j = 0; j < rep->field[i]->maxusage; j++) {
/* Verify if Battery Strength feature is available */
hidinput_setup_battery(hid, HID_FEATURE_REPORT, rep->field[i]);
if (drv->feature_mapping)
drv->feature_mapping(hid, rep->field[i],
rep->field[i]->usage + j);
}
}
/*
......@@ -1010,6 +1224,8 @@ void hidinput_disconnect(struct hid_device *hid)
{
struct hid_input *hidinput, *next;
hidinput_cleanup_battery(hid);
list_for_each_entry_safe(hidinput, next, &hid->inputs, list) {
list_del(&hidinput->list);
input_unregister_device(hidinput->input);
......
......@@ -430,7 +430,7 @@ int lg4ff_init(struct hid_device *hid)
}
/* Add the device to device_list */
entry = (struct lg4ff_device_entry *)kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL);
entry = kzalloc(sizeof(struct lg4ff_device_entry), GFP_KERNEL);
if (!entry) {
hid_err(hid, "Cannot add device, insufficient memory.\n");
return -ENOMEM;
......
This diff is collapsed.
......@@ -633,7 +633,7 @@ struct picolcd_fb_cleanup_item {
struct picolcd_fb_cleanup_item *next;
};
static struct picolcd_fb_cleanup_item *fb_pending;
DEFINE_SPINLOCK(fb_pending_lock);
static DEFINE_SPINLOCK(fb_pending_lock);
static void picolcd_fb_do_cleanup(struct work_struct *data)
{
......@@ -658,7 +658,7 @@ static void picolcd_fb_do_cleanup(struct work_struct *data)
} while (item);
}
DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup);
static DECLARE_WORK(picolcd_fb_cleanup, picolcd_fb_do_cleanup);
static int picolcd_fb_open(struct fb_info *info, int u)
{
......
/*
* HID driver for Quanta Optical Touch dual-touch panels
*
* Copyright (c) 2009-2010 Stephane Chatty <chatty@enac.fr>
*
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/slab.h>
MODULE_AUTHOR("Stephane Chatty <chatty@enac.fr>");
MODULE_DESCRIPTION("Quanta dual-touch panel");
MODULE_LICENSE("GPL");
#include "hid-ids.h"
struct quanta_data {
__u16 x, y;
__u8 id;
bool valid; /* valid finger data, or just placeholder? */
bool first; /* is this the first finger in this frame? */
bool activity_now; /* at least one active finger in this frame? */
bool activity; /* at least one active finger previously? */
};
static int quanta_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
switch (usage->hid & HID_USAGE_PAGE) {
case HID_UP_GENDESK:
switch (usage->hid) {
case HID_GD_X:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_X);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_X,
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1;
case HID_GD_Y:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_POSITION_Y);
/* touchscreen emulation */
input_set_abs_params(hi->input, ABS_Y,
field->logical_minimum,
field->logical_maximum, 0, 0);
return 1;
}
return 0;
case HID_UP_DIGITIZER:
switch (usage->hid) {
case HID_DG_CONFIDENCE:
case HID_DG_TIPSWITCH:
case HID_DG_INPUTMODE:
case HID_DG_DEVICEINDEX:
case HID_DG_CONTACTCOUNT:
case HID_DG_CONTACTMAX:
case HID_DG_TIPPRESSURE:
case HID_DG_WIDTH:
case HID_DG_HEIGHT:
return -1;
case HID_DG_INRANGE:
/* touchscreen emulation */
hid_map_usage(hi, usage, bit, max, EV_KEY, BTN_TOUCH);
return 1;
case HID_DG_CONTACTID:
hid_map_usage(hi, usage, bit, max,
EV_ABS, ABS_MT_TRACKING_ID);
return 1;
}
return 0;
case 0xff000000:
/* ignore vendor-specific features */
return -1;
}
return 0;
}
static int quanta_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
if (usage->type == EV_KEY || usage->type == EV_ABS)
clear_bit(usage->code, *bit);
return 0;
}
/*
* this function is called when a whole finger has been parsed,
* so that it can decide what to send to the input layer.
*/
static void quanta_filter_event(struct quanta_data *td, struct input_dev *input)
{
td->first = !td->first; /* touchscreen emulation */
if (!td->valid) {
/*
* touchscreen emulation: if no finger in this frame is valid
* and there previously was finger activity, this is a release
*/
if (!td->first && !td->activity_now && td->activity) {
input_event(input, EV_KEY, BTN_TOUCH, 0);
td->activity = false;
}
return;
}
input_event(input, EV_ABS, ABS_MT_TRACKING_ID, td->id);
input_event(input, EV_ABS, ABS_MT_POSITION_X, td->x);
input_event(input, EV_ABS, ABS_MT_POSITION_Y, td->y);
input_mt_sync(input);
td->valid = false;
/* touchscreen emulation: if first active finger in this frame... */
if (!td->activity_now) {
/* if there was no previous activity, emit touch event */
if (!td->activity) {
input_event(input, EV_KEY, BTN_TOUCH, 1);
td->activity = true;
}
td->activity_now = true;
/* and in any case this is our preferred finger */
input_event(input, EV_ABS, ABS_X, td->x);
input_event(input, EV_ABS, ABS_Y, td->y);
}
}
static int quanta_event(struct hid_device *hid, struct hid_field *field,
struct hid_usage *usage, __s32 value)
{
struct quanta_data *td = hid_get_drvdata(hid);
if (hid->claimed & HID_CLAIMED_INPUT) {
struct input_dev *input = field->hidinput->input;
switch (usage->hid) {
case HID_DG_INRANGE:
td->valid = !!value;
break;
case HID_GD_X:
td->x = value;
break;
case HID_GD_Y:
td->y = value;
quanta_filter_event(td, input);
break;
case HID_DG_CONTACTID:
td->id = value;
break;
case HID_DG_CONTACTCOUNT:
/* touch emulation: this is the last field in a frame */
td->first = false;
td->activity_now = false;
break;
case HID_DG_CONFIDENCE:
case HID_DG_TIPSWITCH:
/* avoid interference from generic hidinput handling */
break;
default:
/* fallback to the generic hidinput handling */
return 0;
}
}
/* we have handled the hidinput part, now remains hiddev */
if (hid->claimed & HID_CLAIMED_HIDDEV && hid->hiddev_hid_event)
hid->hiddev_hid_event(hid, field, usage, value);
return 1;
}
static int quanta_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
int ret;
struct quanta_data *td;
td = kmalloc(sizeof(struct quanta_data), GFP_KERNEL);
if (!td) {
hid_err(hdev, "cannot allocate Quanta Touch data\n");
return -ENOMEM;
}
td->valid = false;
td->activity = false;
td->activity_now = false;
td->first = false;
hid_set_drvdata(hdev, td);
ret = hid_parse(hdev);
if (!ret)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (ret)
kfree(td);
return ret;
}
static void quanta_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
kfree(hid_get_drvdata(hdev));
hid_set_drvdata(hdev, NULL);
}
static const struct hid_device_id quanta_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_QUANTA_OPTICAL_TOUCH) },
{ HID_USB_DEVICE(USB_VENDOR_ID_QUANTA,
USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN) },
{ }
};
MODULE_DEVICE_TABLE(hid, quanta_devices);
static const struct hid_usage_id quanta_grabbed_usages[] = {
{ HID_ANY_ID, HID_ANY_ID, HID_ANY_ID },
{ HID_ANY_ID - 1, HID_ANY_ID - 1, HID_ANY_ID - 1}
};
static struct hid_driver quanta_driver = {
.name = "quanta-touch",
.id_table = quanta_devices,
.probe = quanta_probe,
.remove = quanta_remove,
.input_mapping = quanta_input_mapping,
.input_mapped = quanta_input_mapped,
.usage_table = quanta_grabbed_usages,
.event = quanta_event,
};
static int __init quanta_init(void)
{
return hid_register_driver(&quanta_driver);
}
static void __exit quanta_exit(void)
{
hid_unregister_driver(&quanta_driver);
}
module_init(quanta_init);
module_exit(quanta_exit);
......@@ -49,12 +49,10 @@ int roccat_common_send(struct usb_device *usb_dev, uint report_id,
char *buf;
int len;
buf = kmalloc(size, GFP_KERNEL);
buf = kmemdup(data, size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
memcpy(buf, data, size);
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
HID_REQ_SET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
......
This diff is collapsed.
#ifndef __HID_ROCCAT_ISKU_H
#define __HID_ROCCAT_ISKU_H
/*
* Copyright (c) 2011 Stefan Achatz <erazor_de@users.sourceforge.net>
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/types.h>
enum {
ISKU_PROFILE_NUM = 5,
ISKU_USB_INTERFACE_PROTOCOL = 0,
};
struct isku_control {
uint8_t command; /* ISKU_COMMAND_CONTROL */
uint8_t value;
uint8_t request;
} __packed;
enum isku_control_values {
ISKU_CONTROL_VALUE_STATUS_OVERLOAD = 0,
ISKU_CONTROL_VALUE_STATUS_OK = 1,
ISKU_CONTROL_VALUE_STATUS_INVALID = 2,
ISKU_CONTROL_VALUE_STATUS_WAIT = 3,
};
struct isku_actual_profile {
uint8_t command; /* ISKU_COMMAND_ACTUAL_PROFILE */
uint8_t size; /* always 3 */
uint8_t actual_profile;
} __packed;
struct isku_key_mask {
uint8_t command; /* ISKU_COMMAND_KEY_MASK */
uint8_t size; /* 6 */
uint8_t profile_number; /* 0-4 */
uint8_t mask;
uint16_t checksum;
} __packed;
struct isku_keys_function {
uint8_t data[0x29];
} __packed;
struct isku_keys_easyzone {
uint8_t data[0x41];
} __packed;
struct isku_keys_media {
uint8_t data[0x1d];
} __packed;
struct isku_keys_thumbster {
uint8_t data[0x17];
} __packed;
struct isku_keys_macro {
uint8_t data[0x23];
} __packed;
struct isku_keys_capslock {
uint8_t data[0x6];
} __packed;
struct isku_macro {
uint8_t data[0x823];
} __packed;
struct isku_light {
uint8_t data[0xa];
} __packed;
struct isku_info {
uint8_t data[2];
uint8_t firmware_version;
uint8_t unknown[3];
} __packed;
struct isku_talk {
uint8_t data[0x10];
} __packed;
struct isku_last_set {
uint8_t data[0x14];
} __packed;
enum isku_commands {
ISKU_COMMAND_CONTROL = 0x4,
ISKU_COMMAND_ACTUAL_PROFILE = 0x5,
ISKU_COMMAND_KEY_MASK = 0x7,
ISKU_COMMAND_KEYS_FUNCTION = 0x8,
ISKU_COMMAND_KEYS_EASYZONE = 0x9,
ISKU_COMMAND_KEYS_MEDIA = 0xa,
ISKU_COMMAND_KEYS_THUMBSTER = 0xb,
ISKU_COMMAND_KEYS_MACRO = 0xd,
ISKU_COMMAND_MACRO = 0xe,
ISKU_COMMAND_INFO = 0xf,
ISKU_COMMAND_LIGHT = 0x10,
ISKU_COMMAND_KEYS_CAPSLOCK = 0x13,
ISKU_COMMAND_LAST_SET = 0x14,
ISKU_COMMAND_15 = 0x15,
ISKU_COMMAND_TALK = 0x16,
ISKU_COMMAND_FIRMWARE_WRITE = 0x1b,
ISKU_COMMAND_FIRMWARE_WRITE_CONTROL = 0x1c,
};
struct isku_report_button {
uint8_t number; /* ISKU_REPORT_NUMBER_BUTTON */
uint8_t zero;
uint8_t event;
uint8_t data1;
uint8_t data2;
};
enum isku_report_numbers {
ISKU_REPORT_NUMBER_BUTTON = 3,
};
enum isku_report_button_events {
ISKU_REPORT_BUTTON_EVENT_PROFILE = 0x2,
};
struct isku_roccat_report {
uint8_t event;
uint8_t data1;
uint8_t data2;
uint8_t profile;
} __packed;
struct isku_device {
int roccat_claimed;
int chrdev_minor;
struct mutex isku_lock;
int actual_profile;
};
#endif
......@@ -78,12 +78,10 @@ static int kone_send(struct usb_device *usb_dev, uint usb_command,
char *buf;
int len;
buf = kmalloc(size, GFP_KERNEL);
buf = kmemdup(data, size, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
memcpy(buf, data, size);
len = usb_control_msg(usb_dev, usb_sndctrlpipe(usb_dev, 0),
HID_REQ_SET_REPORT,
USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT,
......
......@@ -9,6 +9,7 @@
* Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
* Copyright (c) 2006 Andrew Zabolotny <zap@homelink.ru>
* Copyright (c) 2009 Bastien Nocera <hadess@hadess.net>
* Copyright (c) 2011 Przemysław Firszt <przemo@firszt.eu>
*/
/*
......@@ -33,6 +34,7 @@
struct wacom_data {
__u16 tool;
unsigned char butstate;
__u8 features;
unsigned char high_speed;
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
int battery_capacity;
......@@ -107,6 +109,19 @@ static int wacom_ac_get_property(struct power_supply *psy,
}
#endif
static void wacom_set_features(struct hid_device *hdev)
{
int ret;
__u8 rep_data[2];
/*set high speed, tablet mode*/
rep_data[0] = 0x03;
rep_data[1] = 0x20;
ret = hdev->hid_output_raw_report(hdev, rep_data, 2,
HID_FEATURE_REPORT);
return;
}
static void wacom_poke(struct hid_device *hdev, u8 speed)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
......@@ -177,26 +192,13 @@ static ssize_t wacom_store_speed(struct device *dev,
static DEVICE_ATTR(speed, S_IRUGO | S_IWUSR | S_IWGRP,
wacom_show_speed, wacom_store_speed);
static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *raw_data, int size)
static int wacom_gr_parse_report(struct hid_device *hdev,
struct wacom_data *wdata,
struct input_dev *input, unsigned char *data)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
struct hid_input *hidinput;
struct input_dev *input;
unsigned char *data = (unsigned char *) raw_data;
int tool, x, y, rw;
if (!(hdev->claimed & HID_CLAIMED_INPUT))
return 0;
tool = 0;
hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
input = hidinput->input;
/* Check if this is a tablet report */
if (data[0] != 0x03)
return 0;
/* Get X & Y positions */
x = le16_to_cpu(*(__le16 *) &data[2]);
y = le16_to_cpu(*(__le16 *) &data[4]);
......@@ -304,6 +306,121 @@ static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
return 1;
}
static void wacom_i4_parse_pen_report(struct wacom_data *wdata,
struct input_dev *input, unsigned char *data)
{
__u16 x, y, pressure;
__u32 id;
switch (data[1]) {
case 0x80: /* Out of proximity report */
wdata->tool = 0;
input_report_key(input, BTN_TOUCH, 0);
input_report_abs(input, ABS_PRESSURE, 0);
input_report_key(input, wdata->tool, 0);
input_sync(input);
break;
case 0xC2: /* Tool report */
id = ((data[2] << 4) | (data[3] >> 4) |
((data[7] & 0x0f) << 20) |
((data[8] & 0xf0) << 12)) & 0xfffff;
switch (id) {
case 0x802:
wdata->tool = BTN_TOOL_PEN;
break;
case 0x80A:
wdata->tool = BTN_TOOL_RUBBER;
break;
}
break;
default: /* Position/pressure report */
x = data[2] << 9 | data[3] << 1 | ((data[9] & 0x02) >> 1);
y = data[4] << 9 | data[5] << 1 | (data[9] & 0x01);
pressure = (data[6] << 3) | ((data[7] & 0xC0) >> 5)
| (data[1] & 0x01);
input_report_key(input, BTN_TOUCH, pressure > 1);
input_report_key(input, BTN_STYLUS, data[1] & 0x02);
input_report_key(input, BTN_STYLUS2, data[1] & 0x04);
input_report_key(input, wdata->tool, 1);
input_report_abs(input, ABS_X, x);
input_report_abs(input, ABS_Y, y);
input_report_abs(input, ABS_PRESSURE, pressure);
input_sync(input);
break;
}
return;
}
static void wacom_i4_parse_report(struct hid_device *hdev,
struct wacom_data *wdata,
struct input_dev *input, unsigned char *data)
{
switch (data[0]) {
case 0x00: /* Empty report */
break;
case 0x02: /* Pen report */
wacom_i4_parse_pen_report(wdata, input, data);
break;
case 0x03: /* Features Report */
wdata->features = data[2];
break;
case 0x0C: /* Button report */
break;
default:
hid_err(hdev, "Unknown report: %d,%d\n", data[0], data[1]);
break;
}
}
static int wacom_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *raw_data, int size)
{
struct wacom_data *wdata = hid_get_drvdata(hdev);
struct hid_input *hidinput;
struct input_dev *input;
unsigned char *data = (unsigned char *) raw_data;
int i;
if (!(hdev->claimed & HID_CLAIMED_INPUT))
return 0;
hidinput = list_entry(hdev->inputs.next, struct hid_input, list);
input = hidinput->input;
/* Check if this is a tablet report */
if (data[0] != 0x03)
return 0;
switch (hdev->product) {
case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
return wacom_gr_parse_report(hdev, wdata, input, data);
break;
case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
i = 1;
switch (data[0]) {
case 0x04:
wacom_i4_parse_report(hdev, wdata, input, data + i);
i += 10;
/* fall through */
case 0x03:
wacom_i4_parse_report(hdev, wdata, input, data + i);
i += 10;
wacom_i4_parse_report(hdev, wdata, input, data + i);
break;
default:
hid_err(hdev, "Unknown report: %d,%d size:%d\n",
data[0], data[1], size);
return 0;
}
}
return 1;
}
static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage, unsigned long **bit,
int *max)
......@@ -338,10 +455,19 @@ static int wacom_input_mapped(struct hid_device *hdev, struct hid_input *hi,
__set_bit(BTN_TOOL_RUBBER, input->keybit);
__set_bit(BTN_TOOL_MOUSE, input->keybit);
input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
switch (hdev->product) {
case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
input_set_abs_params(input, ABS_X, 0, 16704, 4, 0);
input_set_abs_params(input, ABS_Y, 0, 12064, 4, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, 511, 0, 0);
input_set_abs_params(input, ABS_DISTANCE, 0, 32, 0, 0);
break;
case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
input_set_abs_params(input, ABS_X, 0, 40640, 4, 0);
input_set_abs_params(input, ABS_Y, 0, 25400, 4, 0);
input_set_abs_params(input, ABS_PRESSURE, 0, 2047, 0, 0);
break;
}
return 0;
}
......@@ -378,8 +504,16 @@ static int wacom_probe(struct hid_device *hdev,
hid_warn(hdev,
"can't create sysfs speed attribute err: %d\n", ret);
/* Set Wacom mode 2 with high reporting speed */
wacom_poke(hdev, 1);
switch (hdev->product) {
case USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH:
/* Set Wacom mode 2 with high reporting speed */
wacom_poke(hdev, 1);
break;
case USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH:
wdata->features = 0;
wacom_set_features(hdev);
break;
}
#ifdef CONFIG_HID_WACOM_POWER_SUPPLY
wdata->battery.properties = wacom_battery_props;
......@@ -441,6 +575,7 @@ static void wacom_remove(struct hid_device *hdev)
static const struct hid_device_id wacom_devices[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_GRAPHIRE_BLUETOOTH) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_WACOM, USB_DEVICE_ID_WACOM_INTUOS4_BLUETOOTH) },
{ }
};
......
/*
* Debug support for HID Nintendo Wiimote devices
* Copyright (c) 2011 David Herrmann
*/
/*
* 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/debugfs.h>
#include <linux/module.h>
#include <linux/seq_file.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
#include "hid-wiimote.h"
struct wiimote_debug {
struct wiimote_data *wdata;
struct dentry *eeprom;
struct dentry *drm;
};
static int wiidebug_eeprom_open(struct inode *i, struct file *f)
{
f->private_data = i->i_private;
return 0;
}
static ssize_t wiidebug_eeprom_read(struct file *f, char __user *u, size_t s,
loff_t *off)
{
struct wiimote_debug *dbg = f->private_data;
struct wiimote_data *wdata = dbg->wdata;
unsigned long flags;
ssize_t ret;
char buf[16];
__u16 size;
if (s == 0)
return -EINVAL;
if (*off > 0xffffff)
return 0;
if (s > 16)
s = 16;
ret = wiimote_cmd_acquire(wdata);
if (ret)
return ret;
spin_lock_irqsave(&wdata->state.lock, flags);
wdata->state.cmd_read_size = s;
wdata->state.cmd_read_buf = buf;
wiimote_cmd_set(wdata, WIIPROTO_REQ_RMEM, *off & 0xffff);
wiiproto_req_reeprom(wdata, *off, s);
spin_unlock_irqrestore(&wdata->state.lock, flags);
ret = wiimote_cmd_wait(wdata);
if (!ret)
size = wdata->state.cmd_read_size;
spin_lock_irqsave(&wdata->state.lock, flags);
wdata->state.cmd_read_buf = NULL;
spin_unlock_irqrestore(&wdata->state.lock, flags);
wiimote_cmd_release(wdata);
if (ret)
return ret;
else if (size == 0)
return -EIO;
if (copy_to_user(u, buf, size))
return -EFAULT;
*off += size;
ret = size;
return ret;
}
static const struct file_operations wiidebug_eeprom_fops = {
.owner = THIS_MODULE,
.open = wiidebug_eeprom_open,
.read = wiidebug_eeprom_read,
.llseek = generic_file_llseek,
};
static const char *wiidebug_drmmap[] = {
[WIIPROTO_REQ_NULL] = "NULL",
[WIIPROTO_REQ_DRM_K] = "K",
[WIIPROTO_REQ_DRM_KA] = "KA",
[WIIPROTO_REQ_DRM_KE] = "KE",
[WIIPROTO_REQ_DRM_KAI] = "KAI",
[WIIPROTO_REQ_DRM_KEE] = "KEE",
[WIIPROTO_REQ_DRM_KAE] = "KAE",
[WIIPROTO_REQ_DRM_KIE] = "KIE",
[WIIPROTO_REQ_DRM_KAIE] = "KAIE",
[WIIPROTO_REQ_DRM_E] = "E",
[WIIPROTO_REQ_DRM_SKAI1] = "SKAI1",
[WIIPROTO_REQ_DRM_SKAI2] = "SKAI2",
[WIIPROTO_REQ_MAX] = NULL
};
static int wiidebug_drm_show(struct seq_file *f, void *p)
{
struct wiimote_debug *dbg = f->private;
const char *str = NULL;
unsigned long flags;
__u8 drm;
spin_lock_irqsave(&dbg->wdata->state.lock, flags);
drm = dbg->wdata->state.drm;
spin_unlock_irqrestore(&dbg->wdata->state.lock, flags);
if (drm < WIIPROTO_REQ_MAX)
str = wiidebug_drmmap[drm];
if (!str)
str = "unknown";
seq_printf(f, "%s\n", str);
return 0;
}
static int wiidebug_drm_open(struct inode *i, struct file *f)
{
return single_open(f, wiidebug_drm_show, i->i_private);
}
static ssize_t wiidebug_drm_write(struct file *f, const char __user *u,
size_t s, loff_t *off)
{
struct wiimote_debug *dbg = f->private_data;
unsigned long flags;
char buf[16];
ssize_t len;
int i;
if (s == 0)
return -EINVAL;
len = min((size_t) 15, s);
if (copy_from_user(buf, u, len))
return -EFAULT;
buf[15] = 0;
for (i = 0; i < WIIPROTO_REQ_MAX; ++i) {
if (!wiidebug_drmmap[i])
continue;
if (!strcasecmp(buf, wiidebug_drmmap[i]))
break;
}
if (i == WIIPROTO_REQ_MAX)
i = simple_strtoul(buf, NULL, 10);
spin_lock_irqsave(&dbg->wdata->state.lock, flags);
wiiproto_req_drm(dbg->wdata, (__u8) i);
spin_unlock_irqrestore(&dbg->wdata->state.lock, flags);
return len;
}
static const struct file_operations wiidebug_drm_fops = {
.owner = THIS_MODULE,
.open = wiidebug_drm_open,
.read = seq_read,
.llseek = seq_lseek,
.write = wiidebug_drm_write,
.release = single_release,
};
int wiidebug_init(struct wiimote_data *wdata)
{
struct wiimote_debug *dbg;
unsigned long flags;
int ret = -ENOMEM;
dbg = kzalloc(sizeof(*dbg), GFP_KERNEL);
if (!dbg)
return -ENOMEM;
dbg->wdata = wdata;
dbg->eeprom = debugfs_create_file("eeprom", S_IRUSR,
dbg->wdata->hdev->debug_dir, dbg, &wiidebug_eeprom_fops);
if (!dbg->eeprom)
goto err;
dbg->drm = debugfs_create_file("drm", S_IRUSR,
dbg->wdata->hdev->debug_dir, dbg, &wiidebug_drm_fops);
if (!dbg->drm)
goto err_drm;
spin_lock_irqsave(&wdata->state.lock, flags);
wdata->debug = dbg;
spin_unlock_irqrestore(&wdata->state.lock, flags);
return 0;
err_drm:
debugfs_remove(dbg->eeprom);
err:
kfree(dbg);
return ret;
}
void wiidebug_deinit(struct wiimote_data *wdata)
{
struct wiimote_debug *dbg = wdata->debug;
unsigned long flags;
if (!dbg)
return;
spin_lock_irqsave(&wdata->state.lock, flags);
wdata->debug = NULL;
spin_unlock_irqrestore(&wdata->state.lock, flags);
debugfs_remove(dbg->drm);
debugfs_remove(dbg->eeprom);
kfree(dbg);
}
This diff is collapsed.
#ifndef __HID_WIIMOTE_H
#define __HID_WIIMOTE_H
/*
* HID driver for Nintendo Wiimote devices
* Copyright (c) 2011 David Herrmann
*/
/*
* 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/completion.h>
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/input.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/power_supply.h>
#include <linux/spinlock.h>
#define WIIMOTE_NAME "Nintendo Wii Remote"
#define WIIMOTE_BUFSIZE 32
#define WIIPROTO_FLAG_LED1 0x01
#define WIIPROTO_FLAG_LED2 0x02
#define WIIPROTO_FLAG_LED3 0x04
#define WIIPROTO_FLAG_LED4 0x08
#define WIIPROTO_FLAG_RUMBLE 0x10
#define WIIPROTO_FLAG_ACCEL 0x20
#define WIIPROTO_FLAG_IR_BASIC 0x40
#define WIIPROTO_FLAG_IR_EXT 0x80
#define WIIPROTO_FLAG_IR_FULL 0xc0 /* IR_BASIC | IR_EXT */
#define WIIPROTO_FLAGS_LEDS (WIIPROTO_FLAG_LED1 | WIIPROTO_FLAG_LED2 | \
WIIPROTO_FLAG_LED3 | WIIPROTO_FLAG_LED4)
#define WIIPROTO_FLAGS_IR (WIIPROTO_FLAG_IR_BASIC | WIIPROTO_FLAG_IR_EXT | \
WIIPROTO_FLAG_IR_FULL)
/* return flag for led \num */
#define WIIPROTO_FLAG_LED(num) (WIIPROTO_FLAG_LED1 << (num - 1))
struct wiimote_buf {
__u8 data[HID_MAX_BUFFER_SIZE];
size_t size;
};
struct wiimote_state {
spinlock_t lock;
__u8 flags;
__u8 accel_split[2];
__u8 drm;
/* synchronous cmd requests */
struct mutex sync;
struct completion ready;
int cmd;
__u32 opt;
/* results of synchronous requests */
__u8 cmd_battery;
__u8 cmd_err;
__u8 *cmd_read_buf;
__u8 cmd_read_size;
};
struct wiimote_data {
struct hid_device *hdev;
struct input_dev *input;
struct led_classdev *leds[4];
struct input_dev *accel;
struct input_dev *ir;
struct power_supply battery;
struct wiimote_ext *ext;
struct wiimote_debug *debug;
spinlock_t qlock;
__u8 head;
__u8 tail;
struct wiimote_buf outq[WIIMOTE_BUFSIZE];
struct work_struct worker;
struct wiimote_state state;
};
enum wiiproto_reqs {
WIIPROTO_REQ_NULL = 0x0,
WIIPROTO_REQ_RUMBLE = 0x10,
WIIPROTO_REQ_LED = 0x11,
WIIPROTO_REQ_DRM = 0x12,
WIIPROTO_REQ_IR1 = 0x13,
WIIPROTO_REQ_SREQ = 0x15,
WIIPROTO_REQ_WMEM = 0x16,
WIIPROTO_REQ_RMEM = 0x17,
WIIPROTO_REQ_IR2 = 0x1a,
WIIPROTO_REQ_STATUS = 0x20,
WIIPROTO_REQ_DATA = 0x21,
WIIPROTO_REQ_RETURN = 0x22,
WIIPROTO_REQ_DRM_K = 0x30,
WIIPROTO_REQ_DRM_KA = 0x31,
WIIPROTO_REQ_DRM_KE = 0x32,
WIIPROTO_REQ_DRM_KAI = 0x33,
WIIPROTO_REQ_DRM_KEE = 0x34,
WIIPROTO_REQ_DRM_KAE = 0x35,
WIIPROTO_REQ_DRM_KIE = 0x36,
WIIPROTO_REQ_DRM_KAIE = 0x37,
WIIPROTO_REQ_DRM_E = 0x3d,
WIIPROTO_REQ_DRM_SKAI1 = 0x3e,
WIIPROTO_REQ_DRM_SKAI2 = 0x3f,
WIIPROTO_REQ_MAX
};
#define dev_to_wii(pdev) hid_get_drvdata(container_of(pdev, struct hid_device, \
dev))
extern void wiiproto_req_drm(struct wiimote_data *wdata, __u8 drm);
extern int wiimote_cmd_write(struct wiimote_data *wdata, __u32 offset,
const __u8 *wmem, __u8 size);
extern ssize_t wiimote_cmd_read(struct wiimote_data *wdata, __u32 offset,
__u8 *rmem, __u8 size);
#define wiiproto_req_rreg(wdata, os, sz) \
wiiproto_req_rmem((wdata), false, (os), (sz))
#define wiiproto_req_reeprom(wdata, os, sz) \
wiiproto_req_rmem((wdata), true, (os), (sz))
extern void wiiproto_req_rmem(struct wiimote_data *wdata, bool eeprom,
__u32 offset, __u16 size);
#ifdef CONFIG_HID_WIIMOTE_EXT
extern int wiiext_init(struct wiimote_data *wdata);
extern void wiiext_deinit(struct wiimote_data *wdata);
extern void wiiext_event(struct wiimote_data *wdata, bool plugged);
extern bool wiiext_active(struct wiimote_data *wdata);
extern void wiiext_handle(struct wiimote_data *wdata, const __u8 *payload);
#else
static inline int wiiext_init(void *u) { return 0; }
static inline void wiiext_deinit(void *u) { }
static inline void wiiext_event(void *u, bool p) { }
static inline bool wiiext_active(void *u) { return false; }
static inline void wiiext_handle(void *u, const __u8 *p) { }
#endif
#ifdef CONFIG_DEBUG_FS
extern int wiidebug_init(struct wiimote_data *wdata);
extern void wiidebug_deinit(struct wiimote_data *wdata);
#else
static inline int wiidebug_init(void *u) { return 0; }
static inline void wiidebug_deinit(void *u) { }
#endif
/* requires the state.lock spinlock to be held */
static inline bool wiimote_cmd_pending(struct wiimote_data *wdata, int cmd,
__u32 opt)
{
return wdata->state.cmd == cmd && wdata->state.opt == opt;
}
/* requires the state.lock spinlock to be held */
static inline void wiimote_cmd_complete(struct wiimote_data *wdata)
{
wdata->state.cmd = WIIPROTO_REQ_NULL;
complete(&wdata->state.ready);
}
static inline int wiimote_cmd_acquire(struct wiimote_data *wdata)
{
return mutex_lock_interruptible(&wdata->state.sync) ? -ERESTARTSYS : 0;
}
/* requires the state.lock spinlock to be held */
static inline void wiimote_cmd_set(struct wiimote_data *wdata, int cmd,
__u32 opt)
{
INIT_COMPLETION(wdata->state.ready);
wdata->state.cmd = cmd;
wdata->state.opt = opt;
}
static inline void wiimote_cmd_release(struct wiimote_data *wdata)
{
mutex_unlock(&wdata->state.sync);
}
static inline int wiimote_cmd_wait(struct wiimote_data *wdata)
{
int ret;
ret = wait_for_completion_interruptible_timeout(&wdata->state.ready, HZ);
if (ret < 0)
return -ERESTARTSYS;
else if (ret == 0)
return -EIO;
else
return 0;
}
#endif
This diff is collapsed.
......@@ -47,6 +47,7 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_AFATECH, USB_DEVICE_ID_AFATECH_AF9016, HID_QUIRK_FULLSPEED_INTERVAL },
{ USB_VENDOR_ID_EMS, USB_DEVICE_ID_EMS_TRIO_LINKER_PLUS_II, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_ETURBOTOUCH, USB_DEVICE_ID_ETURBOTOUCH, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_GREENASIA, USB_DEVICE_ID_GREENASIA_DUAL_USB_JOYPAD, HID_QUIRK_MULTI_INPUT },
{ USB_VENDOR_ID_PANTHERLORD, USB_DEVICE_ID_PANTHERLORD_TWIN_USB_JOYSTICK, HID_QUIRK_MULTI_INPUT | HID_QUIRK_SKIP_OUTPUT_REPORTS },
......@@ -67,6 +68,9 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_CH, USB_DEVICE_ID_CH_AXIS_295, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_DMI, USB_DEVICE_ID_DMI_ENC, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_ELO, USB_DEVICE_ID_ELO_TS2700, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN1, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PIXART, USB_DEVICE_ID_PIXART_OPTICAL_TOUCH_SCREEN2, HID_QUIRK_NO_INIT_REPORTS },
{ USB_VENDOR_ID_PRODIGE, USB_DEVICE_ID_PRODIGE_CORDLESS, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_QUANTA, USB_DEVICE_ID_PIXART_IMAGING_INC_OPTICAL_TOUCH_SCREEN, HID_QUIRK_NOGET },
{ USB_VENDOR_ID_SUN, USB_DEVICE_ID_RARITAN_KVM_DONGLE, HID_QUIRK_NOGET },
......
......@@ -55,7 +55,6 @@ struct usb_interface *usbhid_find_interface(int minor);
#define HID_STARTED 8
#define HID_REPORTED_IDLE 9
#define HID_KEYS_PRESSED 10
#define HID_LED_ON 11
/*
* USB-specific HID struct, to be pointed to
......@@ -97,6 +96,8 @@ struct usbhid_device {
struct work_struct reset_work; /* Task context for resets */
wait_queue_head_t wait; /* For sleeping */
int ledcount; /* counting the number of active leds */
struct work_struct led_work; /* Task context for setting LEDs */
};
#define hid_to_usb_dev(hid_dev) \
......
......@@ -64,6 +64,32 @@ static const unsigned char usb_kbd_keycode[256] = {
150,158,159,128,136,177,178,176,142,152,173,140
};
/**
* struct usb_kbd - state of each attached keyboard
* @dev: input device associated with this keyboard
* @usbdev: usb device associated with this keyboard
* @old: data received in the past from the @irq URB representing which
* keys were pressed. By comparing with the current list of keys
* that are pressed, we are able to see key releases.
* @irq: URB for receiving a list of keys that are pressed when a
* new key is pressed or a key that was pressed is released.
* @led: URB for sending LEDs (e.g. numlock, ...)
* @newleds: data that will be sent with the @led URB representing which LEDs
should be on
* @name: Name of the keyboard. @dev's name field points to this buffer
* @phys: Physical path of the keyboard. @dev's phys field points to this
* buffer
* @new: Buffer for the @irq URB
* @cr: Control request for @led URB
* @leds: Buffer for the @led URB
* @new_dma: DMA address for @irq URB
* @leds_dma: DMA address for @led URB
* @leds_lock: spinlock that protects @leds, @newleds, and @led_urb_submitted
* @led_urb_submitted: indicates whether @led is in progress, i.e. it has been
* submitted and its completion handler has not returned yet
* without resubmitting @led
*/
struct usb_kbd {
struct input_dev *dev;
struct usb_device *usbdev;
......@@ -78,6 +104,10 @@ struct usb_kbd {
unsigned char *leds;
dma_addr_t new_dma;
dma_addr_t leds_dma;
spinlock_t leds_lock;
bool led_urb_submitted;
};
static void usb_kbd_irq(struct urb *urb)
......@@ -136,44 +166,66 @@ static void usb_kbd_irq(struct urb *urb)
static int usb_kbd_event(struct input_dev *dev, unsigned int type,
unsigned int code, int value)
{
unsigned long flags;
struct usb_kbd *kbd = input_get_drvdata(dev);
if (type != EV_LED)
return -1;
spin_lock_irqsave(&kbd->leds_lock, flags);
kbd->newleds = (!!test_bit(LED_KANA, dev->led) << 3) | (!!test_bit(LED_COMPOSE, dev->led) << 3) |
(!!test_bit(LED_SCROLLL, dev->led) << 2) | (!!test_bit(LED_CAPSL, dev->led) << 1) |
(!!test_bit(LED_NUML, dev->led));
if (kbd->led->status == -EINPROGRESS)
if (kbd->led_urb_submitted){
spin_unlock_irqrestore(&kbd->leds_lock, flags);
return 0;
}
if (*(kbd->leds) == kbd->newleds)
if (*(kbd->leds) == kbd->newleds){
spin_unlock_irqrestore(&kbd->leds_lock, flags);
return 0;
}
*(kbd->leds) = kbd->newleds;
kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_ATOMIC))
pr_err("usb_submit_urb(leds) failed\n");
else
kbd->led_urb_submitted = true;
spin_unlock_irqrestore(&kbd->leds_lock, flags);
return 0;
}
static void usb_kbd_led(struct urb *urb)
{
unsigned long flags;
struct usb_kbd *kbd = urb->context;
if (urb->status)
hid_warn(urb->dev, "led urb status %d received\n",
urb->status);
if (*(kbd->leds) == kbd->newleds)
spin_lock_irqsave(&kbd->leds_lock, flags);
if (*(kbd->leds) == kbd->newleds){
kbd->led_urb_submitted = false;
spin_unlock_irqrestore(&kbd->leds_lock, flags);
return;
}
*(kbd->leds) = kbd->newleds;
kbd->led->dev = kbd->usbdev;
if (usb_submit_urb(kbd->led, GFP_ATOMIC))
if (usb_submit_urb(kbd->led, GFP_ATOMIC)){
hid_err(urb->dev, "usb_submit_urb(leds) failed\n");
kbd->led_urb_submitted = false;
}
spin_unlock_irqrestore(&kbd->leds_lock, flags);
}
static int usb_kbd_open(struct input_dev *dev)
......@@ -252,6 +304,7 @@ static int usb_kbd_probe(struct usb_interface *iface,
kbd->usbdev = dev;
kbd->dev = input_dev;
spin_lock_init(&kbd->leds_lock);
if (dev->manufacturer)
strlcpy(kbd->name, dev->manufacturer, sizeof(kbd->name));
......@@ -334,6 +387,7 @@ static void usb_kbd_disconnect(struct usb_interface *intf)
if (kbd) {
usb_kill_urb(kbd->irq);
input_unregister_device(kbd->dev);
usb_kill_urb(kbd->led);
usb_kbd_free_mem(interface_to_usbdev(intf), kbd);
kfree(kbd);
}
......
......@@ -31,6 +31,8 @@ static const struct usb_device_id id_table[] = {
.driver_info = DELCOM_VISUAL_SIGNAL_INDICATOR },
{ USB_DEVICE(0x1d34, 0x0004),
.driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
{ USB_DEVICE(0x1d34, 0x000a),
.driver_info = DREAM_CHEEKY_WEBMAIL_NOTIFIER },
{ },
};
MODULE_DEVICE_TABLE(usb, id_table);
......
......@@ -72,6 +72,7 @@
#include <linux/workqueue.h>
#include <linux/input.h>
#include <linux/semaphore.h>
#include <linux/power_supply.h>
/*
* We parse each description item into this structure. Short items data
......@@ -190,6 +191,7 @@ struct hid_item {
#define HID_UP_UNDEFINED 0x00000000
#define HID_UP_GENDESK 0x00010000
#define HID_UP_SIMULATION 0x00020000
#define HID_UP_GENDEVCTRLS 0x00060000
#define HID_UP_KEYBOARD 0x00070000
#define HID_UP_LED 0x00080000
#define HID_UP_BUTTON 0x00090000
......@@ -239,6 +241,8 @@ struct hid_item {
#define HID_GD_RIGHT 0x00010092
#define HID_GD_LEFT 0x00010093
#define HID_DC_BATTERYSTRENGTH 0x00060020
#define HID_DG_DIGITIZER 0x000d0001
#define HID_DG_PEN 0x000d0002
#define HID_DG_LIGHTPEN 0x000d0003
......@@ -482,6 +486,19 @@ struct hid_device { /* device report descriptor */
struct hid_driver *driver;
struct hid_ll_driver *ll_driver;
#ifdef CONFIG_HID_BATTERY_STRENGTH
/*
* Power supply information for HID devices which report
* battery strength. power_supply is registered iff
* battery.name is non-NULL.
*/
struct power_supply battery;
__s32 battery_min;
__s32 battery_max;
__s32 battery_report_type;
__s32 battery_report_id;
#endif
unsigned int status; /* see STAT flags above */
unsigned claimed; /* Claimed by hidinput, hiddev? */
unsigned quirks; /* Various quirks the device can pull on us */
......@@ -712,6 +729,8 @@ extern void hidinput_disconnect(struct hid_device *);
int hid_set_field(struct hid_field *, unsigned, __s32);
int hid_input_report(struct hid_device *, int type, u8 *, int, int);
int hidinput_find_field(struct hid_device *hid, unsigned int type, unsigned int code, struct hid_field **field);
struct hid_field *hidinput_get_led_field(struct hid_device *hid);
unsigned int hidinput_count_leds(struct hid_device *hid);
void hid_output_report(struct hid_report *report, __u8 *data);
struct hid_device *hid_allocate_device(void);
struct hid_report *hid_register_report(struct hid_device *device, unsigned type, unsigned id);
......@@ -719,6 +738,8 @@ int hid_parse_report(struct hid_device *hid, __u8 *start, unsigned size);
int hid_check_keys_pressed(struct hid_device *hid);
int hid_connect(struct hid_device *hid, unsigned int connect_mask);
void hid_disconnect(struct hid_device *hid);
const struct hid_device_id *hid_match_id(struct hid_device *hdev,
const struct hid_device_id *id);
/**
* hid_map_usage - map usage input bits
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment