Commit e8ff13b0 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID updates from Jiri Kosina:
 "The list of changes worth pointing out explicitly:

  - We are getting 'UHID', which is a new framework for implementing HID
    transport drivers in userspace (this is different from HIDRAW, which
    is transport-independent and provides report parsing facilities;
    uhid is for the other (transport) part of the pipeline).

    It's needed for (and currently being used by) Bluetooth-LowEnergy,
    as its specification mandates things we don't want in the kernel.

    Written by David Herrmann.

  - there have been quite a few bugs in runtime suspend/resume paths
    (probably never reported to actually happen in the wild, but still).
    Alan Stern fixed those.

  - a few other driver updates and fixes and random new device support."

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/hid: (45 commits)
  HID: add ASUS AIO keyboard model AK1D
  HID: add support for Cypress barcode scanner 04B4:ED81
  HID: Allow drivers to be their own listener
  HID: usbhid: fix error paths in suspend
  HID: usbhid: check for suspend or reset before restarting
  HID: usbhid: replace HID_REPORTED_IDLE with HID_SUSPENDED
  HID: usbhid: inline some simple routines
  HID: usbhid: fix autosuspend calls
  HID: usbhid: fix use-after-free bug
  HID: hid-core: optimize in case of hidraw
  HID: hidraw: fix list->buffer memleak
  HID: uhid: Fix sending events with invalid data
  HID: roccat: added sensor sysfs attribute for Savu
  HID: Add driver for Holtek based keyboards with broken HID
  HID: Add suport for the brightness control keys on HP keyboards
  HID: magicmouse: Implement Multi-touch Protocol B (MT-B)
  HID: magicmouse: Removing report_touches switch
  HID: roccat: rename roccat_common functions to roccat_common2
  HID: roccat: fix wrong hid_err usage on struct usb_device
  HID: roccat: move functionality to roccat-common
  ...
parents 0cd5ff59 c062c4d1
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/press_to_select
Date: July 2011
Contact: linux-input@vger.kernel.org
Description: This controls if mouse clicks should be generated if the trackpoint is quickly pressed. How fast this press has to be
is being controlled by press_speed.
Values are 0 or 1.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/dragging
Date: July 2011
Contact: linux-input@vger.kernel.org
Description: If this setting is enabled, it is possible to do dragging by pressing the trackpoint. This requires press_to_select to be enabled.
Values are 0 or 1.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/release_to_select
Date: July 2011
Contact: linux-input@vger.kernel.org
Description: For details regarding this setting please refer to http://www.pc.ibm.com/ww/healthycomputing/trkpntb.html
Values are 0 or 1.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/select_right
Date: July 2011
Contact: linux-input@vger.kernel.org
Description: This setting controls if the mouse click events generated by pressing the trackpoint (if press_to_select is enabled) generate
a left or right mouse button click.
Values are 0 or 1.
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/sensitivity
Date: July 2011
Contact: linux-input@vger.kernel.org
Description: This file contains the trackpoint sensitivity.
Values are decimal integers from 1 (lowest sensitivity) to 255 (highest sensitivity).
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/press_speed
Date: July 2011
Contact: linux-input@vger.kernel.org
Description: This setting controls how fast the trackpoint needs to be pressed to generate a mouse click if press_to_select is enabled.
Values are decimal integers from 1 (slowest) to 255 (fastest).
What: /sys/bus/usb/devices/<busnum>-<devnum>:<config num>.<interface num>/<hid-bus>:<vendor-id>:<product-id>.<num>/savu/roccatsavu<minor>/buttons
Date: Mai 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 into general settings and
button settings. buttons holds informations about button layout.
When written, this file lets one write the respective profile
buttons to the mouse. The data has to be 47 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>/savu/roccatsavu<minor>/control
Date: Mai 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>/savu/roccatsavu<minor>/general
Date: Mai 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 into general settings and
button settings. profile holds informations 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 43 bytes long.
The mouse will reject invalid data.
Which profile to write is determined by the profile number
contained in the data.
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>/savu/roccatsavu<minor>/info
Date: Mai 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: When read, this file returns general data like firmware version.
The data is 8 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>/savu/roccatsavu<minor>/macro
Date: Mai 2012
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>/savu/roccatsavu<minor>/profile
Date: Mai 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. 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>/savu/roccatsavu<minor>/sensor
Date: July 2012
Contact: Stefan Achatz <erazor_de@users.sourceforge.net>
Description: The mouse has a Avago ADNS-3090 sensor.
This file allows reading and writing of the mouse sensors registers.
The data has to be 4 bytes long.
Users: http://roccat.sourceforge.net
UHID - User-space I/O driver support for HID subsystem
========================================================
The HID subsystem needs two kinds of drivers. In this document we call them:
1. The "HID I/O Driver" is the driver that performs raw data I/O to the
low-level device. Internally, they register an hid_ll_driver structure with
the HID core. They perform device setup, read raw data from the device and
push it into the HID subsystem and they provide a callback so the HID
subsystem can send data to the device.
2. The "HID Device Driver" is the driver that parses HID reports and reacts on
them. There are generic drivers like "generic-usb" and "generic-bluetooth"
which adhere to the HID specification and provide the standardizes features.
But there may be special drivers and quirks for each non-standard device out
there. Internally, they use the hid_driver structure.
Historically, the USB stack was the first subsystem to provide an HID I/O
Driver. However, other standards like Bluetooth have adopted the HID specs and
may provide HID I/O Drivers, too. The UHID driver allows to implement HID I/O
Drivers in user-space and feed the data into the kernel HID-subsystem.
This allows user-space to operate on the same level as USB-HID, Bluetooth-HID
and similar. It does not provide a way to write HID Device Drivers, though. Use
hidraw for this purpose.
There is an example user-space application in ./samples/uhid/uhid-example.c
The UHID API
------------
UHID is accessed through a character misc-device. The minor-number is allocated
dynamically so you need to rely on udev (or similar) to create the device node.
This is /dev/uhid by default.
If a new device is detected by your HID I/O Driver and you want to register this
device with the HID subsystem, then you need to open /dev/uhid once for each
device you want to register. All further communication is done by read()'ing or
write()'ing "struct uhid_event" objects. Non-blocking operations are supported
by setting O_NONBLOCK.
struct uhid_event {
__u32 type;
union {
struct uhid_create_req create;
struct uhid_data_req data;
...
} u;
};
The "type" field contains the ID of the event. Depending on the ID different
payloads are sent. You must not split a single event across multiple read()'s or
multiple write()'s. A single event must always be sent as a whole. Furthermore,
only a single event can be sent per read() or write(). Pending data is ignored.
If you want to handle multiple events in a single syscall, then use vectored
I/O with readv()/writev().
The first thing you should do is sending an UHID_CREATE event. This will
register the device. UHID will respond with an UHID_START event. You can now
start sending data to and reading data from UHID. However, unless UHID sends the
UHID_OPEN event, the internally attached HID Device Driver has no user attached.
That is, you might put your device asleep unless you receive the UHID_OPEN
event. If you receive the UHID_OPEN event, you should start I/O. If the last
user closes the HID device, you will receive an UHID_CLOSE event. This may be
followed by an UHID_OPEN event again and so on. There is no need to perform
reference-counting in user-space. That is, you will never receive multiple
UHID_OPEN events without an UHID_CLOSE event. The HID subsystem performs
ref-counting for you.
You may decide to ignore UHID_OPEN/UHID_CLOSE, though. I/O is allowed even
though the device may have no users.
If you want to send data to the HID subsystem, you send an HID_INPUT event with
your raw data payload. If the kernel wants to send data to the device, you will
read an UHID_OUTPUT or UHID_OUTPUT_EV event.
If your device disconnects, you should send an UHID_DESTROY event. This will
unregister the device. You can now send UHID_CREATE again to register a new
device.
If you close() the fd, the device is automatically unregistered and destroyed
internally.
write()
-------
write() allows you to modify the state of the device and feed input data into
the kernel. The following types are supported: UHID_CREATE, UHID_DESTROY and
UHID_INPUT. The kernel will parse the event immediately and if the event ID is
not supported, it will return -EOPNOTSUPP. If the payload is invalid, then
-EINVAL is returned, otherwise, the amount of data that was read is returned and
the request was handled successfully.
UHID_CREATE:
This creates the internal HID device. No I/O is possible until you send this
event to the kernel. The payload is of type struct uhid_create_req and
contains information about your device. You can start I/O now.
UHID_DESTROY:
This destroys the internal HID device. No further I/O will be accepted. There
may still be pending messages that you can receive with read() but no further
UHID_INPUT events can be sent to the kernel.
You can create a new device by sending UHID_CREATE again. There is no need to
reopen the character device.
UHID_INPUT:
You must send UHID_CREATE before sending input to the kernel! This event
contains a data-payload. This is the raw data that you read from your device.
The kernel will parse the HID reports and react on it.
UHID_FEATURE_ANSWER:
If you receive a UHID_FEATURE request you must answer with this request. You
must copy the "id" field from the request into the answer. Set the "err" field
to 0 if no error occured or to EIO if an I/O error occurred.
If "err" is 0 then you should fill the buffer of the answer with the results
of the feature request and set "size" correspondingly.
read()
------
read() will return a queued ouput report. These output reports can be of type
UHID_START, UHID_STOP, UHID_OPEN, UHID_CLOSE, UHID_OUTPUT or UHID_OUTPUT_EV. No
reaction is required to any of them but you should handle them according to your
needs. Only UHID_OUTPUT and UHID_OUTPUT_EV have payloads.
UHID_START:
This is sent when the HID device is started. Consider this as an answer to
UHID_CREATE. This is always the first event that is sent.
UHID_STOP:
This is sent when the HID device is stopped. Consider this as an answer to
UHID_DESTROY.
If the kernel HID device driver closes the device manually (that is, you
didn't send UHID_DESTROY) then you should consider this device closed and send
an UHID_DESTROY event. You may want to reregister your device, though. This is
always the last message that is sent to you unless you reopen the device with
UHID_CREATE.
UHID_OPEN:
This is sent when the HID device is opened. That is, the data that the HID
device provides is read by some other process. You may ignore this event but
it is useful for power-management. As long as you haven't received this event
there is actually no other process that reads your data so there is no need to
send UHID_INPUT events to the kernel.
UHID_CLOSE:
This is sent when there are no more processes which read the HID data. It is
the counterpart of UHID_OPEN and you may as well ignore this event.
UHID_OUTPUT:
This is sent if the HID device driver wants to send raw data to the I/O
device. You should read the payload and forward it to the device. The payload
is of type "struct uhid_data_req".
This may be received even though you haven't received UHID_OPEN, yet.
UHID_OUTPUT_EV:
Same as UHID_OUTPUT but this contains a "struct input_event" as payload. This
is called for force-feedback, LED or similar events which are received through
an input device by the HID subsystem. You should convert this into raw reports
and send them to your device similar to events of type UHID_OUTPUT.
UHID_FEATURE:
This event is sent if the kernel driver wants to perform a feature request as
described in the HID specs. The report-type and report-number are available in
the payload.
The kernel serializes feature requests so there will never be two in parallel.
However, if you fail to respond with a UHID_FEATURE_ANSWER in a time-span of 5
seconds, then the requests will be dropped and a new one might be sent.
Therefore, the payload also contains an "id" field that identifies every
request.
Document by:
David Herrmann <dh.herrmann@googlemail.com>
......@@ -6965,6 +6965,13 @@ S: Maintained
F: Documentation/filesystems/ufs.txt
F: fs/ufs/
UHID USERSPACE HID IO DRIVER:
M: David Herrmann <dh.herrmann@googlemail.com>
L: linux-input@vger.kernel.org
S: Maintained
F: drivers/hid/uhid.c
F: include/linux/uhid.h
ULTRA-WIDEBAND (UWB) SUBSYSTEM:
L: linux-usb@vger.kernel.org
S: Orphan
......
......@@ -53,6 +53,27 @@ config HIDRAW
If unsure, say Y.
config UHID
tristate "User-space I/O driver support for HID subsystem"
depends on HID
default n
---help---
Say Y here if you want to provide HID I/O Drivers from user-space.
This allows to write I/O drivers in user-space and feed the data from
the device into the kernel. The kernel parses the HID reports, loads the
corresponding HID Device Driver or provides input devices on top of your
user-space device.
This driver cannot be used to parse HID-reports in user-space and write
special HID-drivers. You should use hidraw for that.
Instead, this driver allows to write the transport-layer driver in
user-space like USB-HID and Bluetooth-HID do in kernel-space.
If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called uhid.
config HID_GENERIC
tristate "Generic HID driver"
depends on HID
......@@ -193,10 +214,12 @@ config HID_EZKEY
Support for Ezkey BTC 8193 keyboard.
config HID_HOLTEK
tristate "Holtek On Line Grip based game controller support"
tristate "Holtek HID devices"
depends on USB_HID
---help---
Say Y here if you have a Holtek On Line Grip based game controller.
Support for Holtek based devices:
- Holtek On Line Grip based game controller
- Trust GXT 18 Gaming Keyboard
config HOLTEK_FF
bool "Holtek On Line Grip force feedback support"
......@@ -261,6 +284,19 @@ config HID_LCPOWER
---help---
Support for LC-Power RC1000MCE RF remote control.
config HID_LENOVO_TPKBD
tristate "Lenovo ThinkPad USB Keyboard with TrackPoint"
depends on USB_HID
select NEW_LEDS
select LEDS_CLASS
---help---
Support for the Lenovo ThinkPad USB Keyboard with TrackPoint.
Say Y here if you have a Lenovo ThinkPad USB Keyboard with TrackPoint
and would like to use device-specific features like changing the
sensitivity of the trackpoint, using the microphone mute button or
controlling the mute and microphone mute LEDs.
config HID_LOGITECH
tristate "Logitech devices" if EXPERT
depends on USB_HID
......
......@@ -8,6 +8,7 @@ ifdef CONFIG_DEBUG_FS
endif
obj-$(CONFIG_HID) += hid.o
obj-$(CONFIG_UHID) += uhid.o
obj-$(CONFIG_HID_GENERIC) += hid-generic.o
......@@ -48,12 +49,14 @@ obj-$(CONFIG_HID_EMS_FF) += hid-emsff.o
obj-$(CONFIG_HID_ELECOM) += hid-elecom.o
obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o
obj-$(CONFIG_HID_GYRATION) += hid-gyration.o
obj-$(CONFIG_HID_HOLTEK) += hid-holtek-kbd.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
obj-$(CONFIG_HID_LCPOWER) += hid-lcpower.o
obj-$(CONFIG_HID_LENOVO_TPKBD) += hid-lenovo-tpkbd.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
......@@ -69,7 +72,8 @@ obj-$(CONFIG_HID_PICOLCD) += hid-picolcd.o
obj-$(CONFIG_HID_PRIMAX) += hid-primax.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-pyra.o
hid-roccat-koneplus.o hid-roccat-kovaplus.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
......
......@@ -60,6 +60,7 @@ static int ch_input_mapping(struct hid_device *hdev, struct hid_input *hi,
static const struct hid_device_id ch_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
{ }
};
MODULE_DEVICE_TABLE(hid, ch_devices);
......
......@@ -1194,8 +1194,10 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, int size,
goto out;
}
for (a = 0; a < report->maxfield; a++)
hid_input_field(hid, report->field[a], cdata, interrupt);
if (hid->claimed != HID_CLAIMED_HIDRAW) {
for (a = 0; a < report->maxfield; a++)
hid_input_field(hid, report->field[a], cdata, interrupt);
}
if (hid->claimed & HID_CLAIMED_INPUT)
hidinput_report_event(hid, report);
......@@ -1243,6 +1245,10 @@ int hid_input_report(struct hid_device *hid, int type, u8 *data, int size, int i
goto unlock;
}
/* Avoid unnecessary overhead if debugfs is disabled */
if (list_empty(&hid->debug_list))
goto nomem;
buf = kmalloc(sizeof(char) * HID_DEBUG_BUFSIZE, GFP_ATOMIC);
if (!buf)
......@@ -1373,8 +1379,10 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
if ((connect_mask & HID_CONNECT_HIDRAW) && !hidraw_connect(hdev))
hdev->claimed |= HID_CLAIMED_HIDRAW;
if (!hdev->claimed) {
hid_err(hdev, "claimed by neither input, hiddev nor hidraw\n");
/* Drivers with the ->raw_event callback set are not required to connect
* to any other listener. */
if (!hdev->claimed && !hdev->driver->raw_event) {
hid_err(hdev, "device has no listeners, quitting\n");
return -ENODEV;
}
......@@ -1521,10 +1529,12 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_TACTICAL_PAD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_WIRELESS2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CHICONY, USB_DEVICE_ID_CHICONY_AK1D) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CREATIVELABS, USB_DEVICE_ID_PRODIKEYS_PCMIDI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_1) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4) },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0006) },
{ HID_USB_DEVICE(USB_VENDOR_ID_DRAGONRISE, 0x0011) },
......@@ -1539,6 +1549,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_GYRATION, USB_DEVICE_ID_GYRATION_REMOTE_3) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK, USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT, USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KENSINGTON, USB_DEVICE_ID_KS_SLIMBLADE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KEYTOUCH, USB_DEVICE_ID_KEYTOUCH_IEC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_ERGO_525V) },
......@@ -1547,6 +1558,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_KYE, USB_DEVICE_ID_KYE_EASYPEN_M610X) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LABTEC, USB_DEVICE_ID_LABTEC_WIRELESS_KEYBOARD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LCPOWER, USB_DEVICE_ID_LCPOWER_LC1000 ) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LENOVO, USB_DEVICE_ID_LENOVO_TPKBD) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
......@@ -1620,6 +1632,7 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_KOVAPLUS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRED) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_ROCCAT, USB_DEVICE_ID_ROCCAT_SAVU) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAITEK, USB_DEVICE_ID_SAITEK_PS1000) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
......
......@@ -129,6 +129,8 @@ static const struct hid_device_id cp_devices[] = {
.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_3),
.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_BARCODE_4),
.driver_data = CP_RDESC_SWAPPED_MIN_MAX },
{ HID_USB_DEVICE(USB_VENDOR_ID_CYPRESS, USB_DEVICE_ID_CYPRESS_MOUSE),
.driver_data = CP_2WHEEL_MOUSE_HACK },
{ }
......
/*
* HID driver for Holtek keyboard
* Copyright (c) 2012 Tom Harwood
*/
/*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/usb.h>
#include "hid-ids.h"
#include "usbhid/usbhid.h"
/* Holtek based keyboards (USB ID 04d9:a055) have the following issues:
* - The report descriptor specifies an excessively large number of consumer
* usages (2^15), which is more than HID_MAX_USAGES. This prevents proper
* parsing of the report descriptor.
* - The report descriptor reports on caps/scroll/num lock key presses, but
* doesn't have an LED output usage block.
*
* The replacement descriptor below fixes the number of consumer usages,
* and provides an LED output usage block. LED output events are redirected
* to the boot interface.
*/
static __u8 holtek_kbd_rdesc_fixed[] = {
/* Original report descriptor, with reduced number of consumer usages */
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x80, /* Usage (Sys Control), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x01, /* Report ID (1), */
0x19, 0x81, /* Usage Minimum (Sys Power Down), */
0x29, 0x83, /* Usage Maximum (Sys Wake Up), */
0x15, 0x00, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x95, 0x03, /* Report Count (3), */
0x75, 0x01, /* Report Size (1), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x01, /* Report Count (1), */
0x75, 0x05, /* Report Size (5), */
0x81, 0x01, /* Input (Constant), */
0xC0, /* End Collection, */
0x05, 0x0C, /* Usage Page (Consumer), */
0x09, 0x01, /* Usage (Consumer Control), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x02, /* Report ID (2), */
0x19, 0x00, /* Usage Minimum (00h), */
0x2A, 0xFF, 0x2F, /* Usage Maximum (0x2FFF), previously 0x7FFF */
0x15, 0x00, /* Logical Minimum (0), */
0x26, 0xFF, 0x2F, /* Logical Maximum (0x2FFF),previously 0x7FFF*/
0x95, 0x01, /* Report Count (1), */
0x75, 0x10, /* Report Size (16), */
0x81, 0x00, /* Input, */
0xC0, /* End Collection, */
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x06, /* Usage (Keyboard), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x03, /* Report ID (3), */
0x95, 0x38, /* Report Count (56), */
0x75, 0x01, /* Report Size (1), */
0x15, 0x00, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x05, 0x07, /* Usage Page (Keyboard), */
0x19, 0xE0, /* Usage Minimum (KB Leftcontrol), */
0x29, 0xE7, /* Usage Maximum (KB Right GUI), */
0x19, 0x00, /* Usage Minimum (None), */
0x29, 0x2F, /* Usage Maximum (KB Lboxbracket And Lbrace),*/
0x81, 0x02, /* Input (Variable), */
0xC0, /* End Collection, */
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x06, /* Usage (Keyboard), */
0xA1, 0x01, /* Collection (Application), */
0x85, 0x04, /* Report ID (4), */
0x95, 0x38, /* Report Count (56), */
0x75, 0x01, /* Report Size (1), */
0x15, 0x00, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x05, 0x07, /* Usage Page (Keyboard), */
0x19, 0x30, /* Usage Minimum (KB Rboxbracket And Rbrace),*/
0x29, 0x67, /* Usage Maximum (KP Equals), */
0x81, 0x02, /* Input (Variable), */
0xC0, /* End Collection */
/* LED usage for the boot protocol interface */
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x06, /* Usage (Keyboard), */
0xA1, 0x01, /* Collection (Application), */
0x05, 0x08, /* Usage Page (LED), */
0x19, 0x01, /* Usage Minimum (01h), */
0x29, 0x03, /* Usage Maximum (03h), */
0x15, 0x00, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x75, 0x01, /* Report Size (1), */
0x95, 0x03, /* Report Count (3), */
0x91, 0x02, /* Output (Variable), */
0x95, 0x05, /* Report Count (5), */
0x91, 0x01, /* Output (Constant), */
0xC0, /* End Collection */
};
static __u8 *holtek_kbd_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
if (intf->cur_altsetting->desc.bInterfaceNumber == 1) {
rdesc = holtek_kbd_rdesc_fixed;
*rsize = sizeof(holtek_kbd_rdesc_fixed);
}
return rdesc;
}
static int holtek_kbd_input_event(struct input_dev *dev, unsigned int type,
unsigned int code,
int value)
{
struct hid_device *hid = input_get_drvdata(dev);
struct usb_device *usb_dev = hid_to_usb_dev(hid);
/* Locate the boot interface, to receive the LED change events */
struct usb_interface *boot_interface = usb_ifnum_to_if(usb_dev, 0);
struct hid_device *boot_hid = usb_get_intfdata(boot_interface);
struct hid_input *boot_hid_input = list_first_entry(&boot_hid->inputs,
struct hid_input, list);
return boot_hid_input->input->event(boot_hid_input->input, type, code,
value);
}
static int holtek_kbd_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
int ret = hid_parse(hdev);
if (!ret)
ret = hid_hw_start(hdev, HID_CONNECT_DEFAULT);
if (!ret && intf->cur_altsetting->desc.bInterfaceNumber == 1) {
struct hid_input *hidinput;
list_for_each_entry(hidinput, &hdev->inputs, list) {
hidinput->input->event = holtek_kbd_input_event;
}
}
return ret;
}
static const struct hid_device_id holtek_kbd_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HOLTEK_ALT,
USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD) },
{ }
};
MODULE_DEVICE_TABLE(hid, holtek_kbd_devices);
static struct hid_driver holtek_kbd_driver = {
.name = "holtek_kbd",
.id_table = holtek_kbd_devices,
.report_fixup = holtek_kbd_report_fixup,
.probe = holtek_kbd_probe
};
static int __init holtek_kbd_init(void)
{
return hid_register_driver(&holtek_kbd_driver);
}
static void __exit holtek_kbd_exit(void)
{
hid_unregister_driver(&holtek_kbd_driver);
}
module_exit(holtek_kbd_exit);
module_init(holtek_kbd_init);
MODULE_LICENSE("GPL");
......@@ -208,6 +208,7 @@
#define USB_DEVICE_ID_CHICONY_MULTI_TOUCH 0xb19d
#define USB_DEVICE_ID_CHICONY_WIRELESS 0x0618
#define USB_DEVICE_ID_CHICONY_WIRELESS2 0x1123
#define USB_DEVICE_ID_CHICONY_AK1D 0x1125
#define USB_VENDOR_ID_CHUNGHWAT 0x2247
#define USB_DEVICE_ID_CHUNGHWAT_MULTITOUCH 0x0001
......@@ -237,6 +238,7 @@
#define USB_DEVICE_ID_CYPRESS_BARCODE_1 0xde61
#define USB_DEVICE_ID_CYPRESS_BARCODE_2 0xde64
#define USB_DEVICE_ID_CYPRESS_BARCODE_3 0xbca1
#define USB_DEVICE_ID_CYPRESS_BARCODE_4 0xed81
#define USB_DEVICE_ID_CYPRESS_TRUETOUCH 0xc001
#define USB_VENDOR_ID_DEALEXTREAME 0x10c5
......@@ -410,6 +412,9 @@
#define USB_VENDOR_ID_HOLTEK 0x1241
#define USB_DEVICE_ID_HOLTEK_ON_LINE_GRIP 0x5015
#define USB_VENDOR_ID_HOLTEK_ALT 0x04d9
#define USB_DEVICE_ID_HOLTEK_ALT_KEYBOARD 0xa055
#define USB_VENDOR_ID_IMATION 0x0718
#define USB_DEVICE_ID_DISC_STAKKA 0xd000
......@@ -479,6 +484,9 @@
#define USB_DEVICE_ID_LD_HYBRID 0x2090
#define USB_DEVICE_ID_LD_HEATCONTROL 0x20A0
#define USB_VENDOR_ID_LENOVO 0x17ef
#define USB_DEVICE_ID_LENOVO_TPKBD 0x6009
#define USB_VENDOR_ID_LG 0x1fd2
#define USB_DEVICE_ID_LG_MULTITOUCH 0x0064
......@@ -573,6 +581,9 @@
#define USB_VENDOR_ID_NINTENDO 0x057e
#define USB_DEVICE_ID_NINTENDO_WIIMOTE 0x0306
#define USB_VENDOR_ID_NOVATEK 0x0603
#define USB_DEVICE_ID_NOVATEK_PCT 0x0600
#define USB_VENDOR_ID_NTRIG 0x1b96
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN 0x0001
#define USB_DEVICE_ID_NTRIG_TOUCH_SCREEN_1 0x0003
......@@ -650,6 +661,7 @@
#define USB_DEVICE_ID_ROCCAT_KOVAPLUS 0x2d50
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRED 0x2c24
#define USB_DEVICE_ID_ROCCAT_PYRA_WIRELESS 0x2cf6
#define USB_DEVICE_ID_ROCCAT_SAVU 0x2d5a