Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/hid/hid

Pull HID updates from Jiri Kosina:

 - support for U2F Zero device, from Andrej Shadura

 - logitech-dj has historically been treating devices behind
   non-unifying receivers as generic devices, using the HID emulation in
   the receiver. That had several shortcomings (special keys handling,
   battery level monitoring, etc). The driver has been reworked to
   enumarate (and directly communicate with) the devices behind the
   receiver, to avoid the (too) generic HID implementation in the
   receiver itself. All the work done by Benjamin Tissoires and Hans de
   Goede.

 - restructuring of intel-ish driver in order to allow for multiple
   clients of the ISH implementation, from Srinivas Pandruvada

 - several other smaller fixes and assorted device ID additions

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (68 commits)
  HID: logitech-dj: fix spelling in printk
  HID: input: fix assignment of .value
  HID: input: make sure the wheel high resolution multiplier is set
  HID: logitech-dj: add usbhid dependency in Kconfig
  HID: logitech-hidpp: add support for HID++ 1.0 consumer keys reports
  HID: logitech-hidpp: add support for HID++ 1.0 extra mouse buttons reports
  HID: logitech-hidpp: add support for HID++ 1.0 wheel reports
  HID: logitech-hidpp: make hidpp10_set_register_bit a bit more generic
  HID: logitech-hidpp: add input_device ptr to struct hidpp_device
  HID: logitech-hidpp: do not hardcode very long report length
  HID: logitech-hidpp: handle devices attached to 27MHz wireless receivers
  HID: logitech-hidpp: use RAP instead of FAP to get the protocol version
  HID: logitech-hidpp: remove unused origin_is_hid_core function parameter
  HID: logitech-hidpp: remove double assignment from __hidpp_send_report
  HID: logitech-hidpp: do not make failure to get the name fatal
  HID: logitech-hidpp: ignore very-short or empty names
  HID: logitech-hidpp: make .probe usbhid capable
  HID: logitech-hidpp: allow non HID++ devices to be handled by this module
  HID: logitech-dj: add support for Logitech Bluetooth Mini-Receiver
  HID: logitech-dj: make appending of the HID++ descriptors conditional
  ...
  • Loading branch information
torvalds committed May 7, 2019
2 parents 80104bb + 63b6f0b commit b4dd05d
Show file tree
Hide file tree
Showing 29 changed files with 3,518 additions and 690 deletions.
27 changes: 27 additions & 0 deletions drivers/hid/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,16 @@ config HID_COUGAR
Supported devices:
- Cougar 500k Gaming Keyboard

config HID_MACALLY
tristate "Macally devices"
depends on HID
help
Support for Macally devices that are not fully compliant with the
HID standard.

supported devices:
- Macally ikey keyboard

config HID_PRODIKEYS
tristate "Prodikeys PC-MIDI Keyboard support"
depends on HID && SND
Expand Down Expand Up @@ -511,6 +521,7 @@ config HID_LOGITECH

config HID_LOGITECH_DJ
tristate "Logitech Unifying receivers full support"
depends on USB_HID
depends on HIDRAW
depends on HID_LOGITECH
select HID_LOGITECH_HIDPP
Expand Down Expand Up @@ -1003,6 +1014,22 @@ config HID_UDRAW_PS3
Say Y here if you want to use the THQ uDraw gaming tablet for
the PS3.

config HID_U2FZERO
tristate "U2F Zero LED and RNG support"
depends on USB_HID
depends on LEDS_CLASS
depends on HW_RANDOM
help
Support for the LED of the U2F Zero device.

U2F Zero supports custom commands for blinking the LED
and getting data from the internal hardware RNG.
The internal hardware can be used to feed the enthropy pool.

U2F Zero only supports blinking its LED, so this driver doesn't
allow setting the brightness to anything but 1, which will
trigger a single blink and immediately reset to back 0.

config HID_WACOM
tristate "Wacom Intuos/Graphire tablet support (USB)"
depends on USB_HID
Expand Down
3 changes: 3 additions & 0 deletions drivers/hid/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o
obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.o
obj-$(CONFIG_HID_MACALLY) += hid-macally.o
obj-$(CONFIG_HID_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MALTRON) += hid-maltron.o
obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o
Expand Down Expand Up @@ -109,6 +110,7 @@ obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
obj-$(CONFIG_HID_TIVO) += hid-tivo.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
obj-$(CONFIG_HID_U2FZERO) += hid-u2fzero.o
hid-uclogic-objs := hid-uclogic-core.o \
hid-uclogic-rdesc.o \
hid-uclogic-params.o
Expand All @@ -134,3 +136,4 @@ obj-$(CONFIG_USB_KBD) += usbhid/
obj-$(CONFIG_I2C_HID) += i2c-hid/

obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/
obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
53 changes: 39 additions & 14 deletions drivers/hid/hid-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include <linux/vmalloc.h>
#include <linux/sched.h>
#include <linux/semaphore.h>
#include <linux/async.h>

#include <linux/hid.h>
#include <linux/hiddev.h>
Expand Down Expand Up @@ -218,13 +219,14 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
* Add a usage to the temporary parser table.
*/

static int hid_add_usage(struct hid_parser *parser, unsigned usage)
static int hid_add_usage(struct hid_parser *parser, unsigned usage, u8 size)
{
if (parser->local.usage_index >= HID_MAX_USAGES) {
hid_err(parser->device, "usage index exceeded\n");
return -1;
}
parser->local.usage[parser->local.usage_index] = usage;
parser->local.usage_size[parser->local.usage_index] = size;
parser->local.collection_index[parser->local.usage_index] =
parser->collection_stack_ptr ?
parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
Expand Down Expand Up @@ -486,10 +488,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
return 0;
}

if (item->size <= 2)
data = (parser->global.usage_page << 16) + data;

return hid_add_usage(parser, data);
return hid_add_usage(parser, data, item->size);

case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:

Expand All @@ -498,9 +497,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
return 0;
}

if (item->size <= 2)
data = (parser->global.usage_page << 16) + data;

parser->local.usage_minimum = data;
return 0;

Expand All @@ -511,9 +507,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
return 0;
}

if (item->size <= 2)
data = (parser->global.usage_page << 16) + data;

count = data - parser->local.usage_minimum;
if (count + parser->local.usage_index >= HID_MAX_USAGES) {
/*
Expand All @@ -533,7 +526,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
}

for (n = parser->local.usage_minimum; n <= data; n++)
if (hid_add_usage(parser, n)) {
if (hid_add_usage(parser, n, item->size)) {
dbg_hid("hid_add_usage failed\n");
return -1;
}
Expand All @@ -547,6 +540,22 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
return 0;
}

/*
* Concatenate Usage Pages into Usages where relevant:
* As per specification, 6.2.2.8: "When the parser encounters a main item it
* concatenates the last declared Usage Page with a Usage to form a complete
* usage value."
*/

static void hid_concatenate_usage_page(struct hid_parser *parser)
{
int i;

for (i = 0; i < parser->local.usage_index; i++)
if (parser->local.usage_size[i] <= 2)
parser->local.usage[i] += parser->global.usage_page << 16;
}

/*
* Process a main item.
*/
Expand All @@ -556,6 +565,8 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
__u32 data;
int ret;

hid_concatenate_usage_page(parser);

data = item_udata(item);

switch (item->tag) {
Expand Down Expand Up @@ -765,6 +776,8 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
__u32 data;
int i;

hid_concatenate_usage_page(parser);

data = item_udata(item);

switch (item->tag) {
Expand Down Expand Up @@ -1624,7 +1637,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum,
* Implement a generic .request() callback, using .raw_request()
* DO NOT USE in hid drivers directly, but through hid_hw_request instead.
*/
void __hid_request(struct hid_device *hid, struct hid_report *report,
int __hid_request(struct hid_device *hid, struct hid_report *report,
int reqtype)
{
char *buf;
Expand All @@ -1633,7 +1646,7 @@ void __hid_request(struct hid_device *hid, struct hid_report *report,

buf = hid_alloc_report_buf(report, GFP_KERNEL);
if (!buf)
return;
return -ENOMEM;

len = hid_report_len(report);

Expand All @@ -1650,8 +1663,11 @@ void __hid_request(struct hid_device *hid, struct hid_report *report,
if (reqtype == HID_REQ_GET_REPORT)
hid_input_report(hid, report->type, buf, ret, 0);

ret = 0;

out:
kfree(buf);
return ret;
}
EXPORT_SYMBOL_GPL(__hid_request);

Expand Down Expand Up @@ -2349,6 +2365,15 @@ int hid_add_device(struct hid_device *hdev)
dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
hdev->vendor, hdev->product, atomic_inc_return(&id));

/*
* Try loading the module for the device before the add, so that we do
* not first have hid-generic binding only to have it replaced
* immediately afterwards with a specialized driver.
*/
if (!current_is_async())
request_module("hid:b%04Xg%04Xv%08Xp%08X", hdev->bus,
hdev->group, hdev->vendor, hdev->product);

hid_debug_register(hdev, dev_name(&hdev->dev));
ret = device_add(&hdev->dev);
if (!ret)
Expand Down
7 changes: 6 additions & 1 deletion drivers/hid/hid-ids.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@
#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9
#define USB_DEVICE_ID_CYGNAL_CP2112 0xea90
#define USB_DEVICE_ID_U2F_ZERO 0x8acf

#define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244

Expand Down Expand Up @@ -762,8 +763,12 @@
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513
#define USB_DEVICE_ID_LOGITECH_27MHZ_MOUSE_RECEIVER 0xc51b
#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER 0xc52b
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER 0xc52f
#define USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2 0xc532
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_2 0xc534
#define USB_DEVICE_ID_LOGITECH_NANO_RECEIVER_GAMING 0xc539
#define USB_DEVICE_ID_SPACETRAVELLER 0xc623
#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
Expand Down Expand Up @@ -1034,6 +1039,7 @@
#define USB_DEVICE_ID_SINO_LITE_CONTROLLER 0x3008

#define USB_VENDOR_ID_SOLID_YEAR 0x060b
#define USB_DEVICE_ID_MACALLY_IKEY_KEYBOARD 0x0001
#define USB_DEVICE_ID_COUGAR_500K_GAMING_KEYBOARD 0x500a
#define USB_DEVICE_ID_COUGAR_700K_GAMING_KEYBOARD 0x700a

Expand Down Expand Up @@ -1083,7 +1089,6 @@
#define USB_DEVICE_ID_SYNAPTICS_HD 0x0ac3
#define USB_DEVICE_ID_SYNAPTICS_QUAD_HD 0x1ac3
#define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710
#define I2C_DEVICE_ID_SYNAPTICS_7E7E 0x7e7e

#define USB_VENDOR_ID_TEXAS_INSTRUMENTS 0x2047
#define USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA 0x0855
Expand Down
81 changes: 50 additions & 31 deletions drivers/hid/hid-input.c
Original file line number Diff line number Diff line change
Expand Up @@ -1557,52 +1557,71 @@ static void hidinput_close(struct input_dev *dev)
hid_hw_close(hid);
}

static void hidinput_change_resolution_multipliers(struct hid_device *hid)
static bool __hidinput_change_resolution_multipliers(struct hid_device *hid,
struct hid_report *report, bool use_logical_max)
{
struct hid_report_enum *rep_enum;
struct hid_report *rep;
struct hid_usage *usage;
bool update_needed = false;
int i, j;

rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
list_for_each_entry(rep, &rep_enum->report_list, list) {
bool update_needed = false;
if (report->maxfield == 0)
return false;

if (rep->maxfield == 0)
continue;
/*
* If we have more than one feature within this report we
* need to fill in the bits from the others before we can
* overwrite the ones for the Resolution Multiplier.
*/
if (report->maxfield > 1) {
hid_hw_request(hid, report, HID_REQ_GET_REPORT);
hid_hw_wait(hid);
}

/*
* If we have more than one feature within this report we
* need to fill in the bits from the others before we can
* overwrite the ones for the Resolution Multiplier.
for (i = 0; i < report->maxfield; i++) {
__s32 value = use_logical_max ?
report->field[i]->logical_maximum :
report->field[i]->logical_minimum;

/* There is no good reason for a Resolution
* Multiplier to have a count other than 1.
* Ignore that case.
*/
if (rep->maxfield > 1) {
hid_hw_request(hid, rep, HID_REQ_GET_REPORT);
hid_hw_wait(hid);
}
if (report->field[i]->report_count != 1)
continue;

for (i = 0; i < rep->maxfield; i++) {
__s32 logical_max = rep->field[i]->logical_maximum;
for (j = 0; j < report->field[i]->maxusage; j++) {
usage = &report->field[i]->usage[j];

/* There is no good reason for a Resolution
* Multiplier to have a count other than 1.
* Ignore that case.
*/
if (rep->field[i]->report_count != 1)
if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER)
continue;

for (j = 0; j < rep->field[i]->maxusage; j++) {
usage = &rep->field[i]->usage[j];
report->field[i]->value[j] = value;
update_needed = true;
}
}

return update_needed;
}

if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER)
continue;
static void hidinput_change_resolution_multipliers(struct hid_device *hid)
{
struct hid_report_enum *rep_enum;
struct hid_report *rep;
int ret;

*rep->field[i]->value = logical_max;
update_needed = true;
rep_enum = &hid->report_enum[HID_FEATURE_REPORT];
list_for_each_entry(rep, &rep_enum->report_list, list) {
bool update_needed = __hidinput_change_resolution_multipliers(hid,
rep, true);

if (update_needed) {
ret = __hid_request(hid, rep, HID_REQ_SET_REPORT);
if (ret) {
__hidinput_change_resolution_multipliers(hid,
rep, false);
return;
}
}
if (update_needed)
hid_hw_request(hid, rep, HID_REQ_SET_REPORT);
}

/* refresh our structs */
Expand Down
2 changes: 0 additions & 2 deletions drivers/hid/hid-lg.c
Original file line number Diff line number Diff line change
Expand Up @@ -876,8 +876,6 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_RDESC | LG_WIRELESS },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
.driver_data = LG_RDESC | LG_WIRELESS },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2),
.driver_data = LG_RDESC | LG_WIRELESS },

{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
.driver_data = LG_BAD_RELATIVE_KEYS },
Expand Down
Loading

0 comments on commit b4dd05d

Please sign in to comment.