Commit b4dd05de authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/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
  ...
parents 80104bb0 63b6f0b8
...@@ -231,6 +231,16 @@ config HID_COUGAR ...@@ -231,6 +231,16 @@ config HID_COUGAR
Supported devices: Supported devices:
- Cougar 500k Gaming Keyboard - 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 config HID_PRODIKEYS
tristate "Prodikeys PC-MIDI Keyboard support" tristate "Prodikeys PC-MIDI Keyboard support"
depends on HID && SND depends on HID && SND
...@@ -511,6 +521,7 @@ config HID_LOGITECH ...@@ -511,6 +521,7 @@ config HID_LOGITECH
config HID_LOGITECH_DJ config HID_LOGITECH_DJ
tristate "Logitech Unifying receivers full support" tristate "Logitech Unifying receivers full support"
depends on USB_HID
depends on HIDRAW depends on HIDRAW
depends on HID_LOGITECH depends on HID_LOGITECH
select HID_LOGITECH_HIDPP select HID_LOGITECH_HIDPP
...@@ -1003,6 +1014,22 @@ config HID_UDRAW_PS3 ...@@ -1003,6 +1014,22 @@ config HID_UDRAW_PS3
Say Y here if you want to use the THQ uDraw gaming tablet for Say Y here if you want to use the THQ uDraw gaming tablet for
the PS3. 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 config HID_WACOM
tristate "Wacom Intuos/Graphire tablet support (USB)" tristate "Wacom Intuos/Graphire tablet support (USB)"
depends on USB_HID depends on USB_HID
......
...@@ -65,6 +65,7 @@ obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o ...@@ -65,6 +65,7 @@ obj-$(CONFIG_HID_LENOVO) += hid-lenovo.o
obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o obj-$(CONFIG_HID_LOGITECH) += hid-logitech.o
obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o obj-$(CONFIG_HID_LOGITECH_DJ) += hid-logitech-dj.o
obj-$(CONFIG_HID_LOGITECH_HIDPP) += hid-logitech-hidpp.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_MAGICMOUSE) += hid-magicmouse.o
obj-$(CONFIG_HID_MALTRON) += hid-maltron.o obj-$(CONFIG_HID_MALTRON) += hid-maltron.o
obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o obj-$(CONFIG_HID_MAYFLASH) += hid-mf.o
...@@ -109,6 +110,7 @@ obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o ...@@ -109,6 +110,7 @@ obj-$(CONFIG_HID_THRUSTMASTER) += hid-tmff.o
obj-$(CONFIG_HID_TIVO) += hid-tivo.o obj-$(CONFIG_HID_TIVO) += hid-tivo.o
obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o obj-$(CONFIG_HID_TOPSEED) += hid-topseed.o
obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o obj-$(CONFIG_HID_TWINHAN) += hid-twinhan.o
obj-$(CONFIG_HID_U2FZERO) += hid-u2fzero.o
hid-uclogic-objs := hid-uclogic-core.o \ hid-uclogic-objs := hid-uclogic-core.o \
hid-uclogic-rdesc.o \ hid-uclogic-rdesc.o \
hid-uclogic-params.o hid-uclogic-params.o
...@@ -134,3 +136,4 @@ obj-$(CONFIG_USB_KBD) += usbhid/ ...@@ -134,3 +136,4 @@ obj-$(CONFIG_USB_KBD) += usbhid/
obj-$(CONFIG_I2C_HID) += i2c-hid/ obj-$(CONFIG_I2C_HID) += i2c-hid/
obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/ obj-$(CONFIG_INTEL_ISH_HID) += intel-ish-hid/
obj-$(INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ish-hid/
...@@ -30,6 +30,7 @@ ...@@ -30,6 +30,7 @@
#include <linux/vmalloc.h> #include <linux/vmalloc.h>
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/semaphore.h> #include <linux/semaphore.h>
#include <linux/async.h>
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/hiddev.h> #include <linux/hiddev.h>
...@@ -218,13 +219,14 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type) ...@@ -218,13 +219,14 @@ static unsigned hid_lookup_collection(struct hid_parser *parser, unsigned type)
* Add a usage to the temporary parser table. * 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) { if (parser->local.usage_index >= HID_MAX_USAGES) {
hid_err(parser->device, "usage index exceeded\n"); hid_err(parser->device, "usage index exceeded\n");
return -1; return -1;
} }
parser->local.usage[parser->local.usage_index] = usage; 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->local.collection_index[parser->local.usage_index] =
parser->collection_stack_ptr ? parser->collection_stack_ptr ?
parser->collection_stack[parser->collection_stack_ptr - 1] : 0; parser->collection_stack[parser->collection_stack_ptr - 1] : 0;
...@@ -486,10 +488,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) ...@@ -486,10 +488,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
return 0; return 0;
} }
if (item->size <= 2) return hid_add_usage(parser, data, item->size);
data = (parser->global.usage_page << 16) + data;
return hid_add_usage(parser, data);
case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM: case HID_LOCAL_ITEM_TAG_USAGE_MINIMUM:
...@@ -498,9 +497,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) ...@@ -498,9 +497,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
return 0; return 0;
} }
if (item->size <= 2)
data = (parser->global.usage_page << 16) + data;
parser->local.usage_minimum = data; parser->local.usage_minimum = data;
return 0; return 0;
...@@ -511,9 +507,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) ...@@ -511,9 +507,6 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
return 0; return 0;
} }
if (item->size <= 2)
data = (parser->global.usage_page << 16) + data;
count = data - parser->local.usage_minimum; count = data - parser->local.usage_minimum;
if (count + parser->local.usage_index >= HID_MAX_USAGES) { if (count + parser->local.usage_index >= HID_MAX_USAGES) {
/* /*
...@@ -533,7 +526,7 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) ...@@ -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++) 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"); dbg_hid("hid_add_usage failed\n");
return -1; return -1;
} }
...@@ -547,6 +540,22 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item) ...@@ -547,6 +540,22 @@ static int hid_parser_local(struct hid_parser *parser, struct hid_item *item)
return 0; 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. * Process a main item.
*/ */
...@@ -556,6 +565,8 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item) ...@@ -556,6 +565,8 @@ static int hid_parser_main(struct hid_parser *parser, struct hid_item *item)
__u32 data; __u32 data;
int ret; int ret;
hid_concatenate_usage_page(parser);
data = item_udata(item); data = item_udata(item);
switch (item->tag) { switch (item->tag) {
...@@ -765,6 +776,8 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item) ...@@ -765,6 +776,8 @@ static int hid_scan_main(struct hid_parser *parser, struct hid_item *item)
__u32 data; __u32 data;
int i; int i;
hid_concatenate_usage_page(parser);
data = item_udata(item); data = item_udata(item);
switch (item->tag) { switch (item->tag) {
...@@ -1624,7 +1637,7 @@ static struct hid_report *hid_get_report(struct hid_report_enum *report_enum, ...@@ -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() * Implement a generic .request() callback, using .raw_request()
* DO NOT USE in hid drivers directly, but through hid_hw_request instead. * 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) int reqtype)
{ {
char *buf; char *buf;
...@@ -1633,7 +1646,7 @@ void __hid_request(struct hid_device *hid, struct hid_report *report, ...@@ -1633,7 +1646,7 @@ void __hid_request(struct hid_device *hid, struct hid_report *report,
buf = hid_alloc_report_buf(report, GFP_KERNEL); buf = hid_alloc_report_buf(report, GFP_KERNEL);
if (!buf) if (!buf)
return; return -ENOMEM;
len = hid_report_len(report); len = hid_report_len(report);
...@@ -1650,8 +1663,11 @@ void __hid_request(struct hid_device *hid, struct hid_report *report, ...@@ -1650,8 +1663,11 @@ void __hid_request(struct hid_device *hid, struct hid_report *report,
if (reqtype == HID_REQ_GET_REPORT) if (reqtype == HID_REQ_GET_REPORT)
hid_input_report(hid, report->type, buf, ret, 0); hid_input_report(hid, report->type, buf, ret, 0);
ret = 0;
out: out:
kfree(buf); kfree(buf);
return ret;
} }
EXPORT_SYMBOL_GPL(__hid_request); EXPORT_SYMBOL_GPL(__hid_request);
...@@ -2349,6 +2365,15 @@ int hid_add_device(struct hid_device *hdev) ...@@ -2349,6 +2365,15 @@ int hid_add_device(struct hid_device *hdev)
dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus, dev_set_name(&hdev->dev, "%04X:%04X:%04X.%04X", hdev->bus,
hdev->vendor, hdev->product, atomic_inc_return(&id)); 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)); hid_debug_register(hdev, dev_name(&hdev->dev));
ret = device_add(&hdev->dev); ret = device_add(&hdev->dev);
if (!ret) if (!ret)
......
...@@ -323,6 +323,7 @@ ...@@ -323,6 +323,7 @@
#define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a #define USB_DEVICE_ID_CYGNAL_RADIO_SI470X 0x818a
#define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9 #define USB_DEVICE_ID_FOCALTECH_FTXXXX_MULTITOUCH 0x81b9
#define USB_DEVICE_ID_CYGNAL_CP2112 0xea90 #define USB_DEVICE_ID_CYGNAL_CP2112 0xea90
#define USB_DEVICE_ID_U2F_ZERO 0x8acf
#define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244 #define USB_DEVICE_ID_CYGNAL_RADIO_SI4713 0x8244
...@@ -762,8 +763,12 @@ ...@@ -762,8 +763,12 @@
#define USB_DEVICE_ID_S510_RECEIVER_2 0xc517 #define USB_DEVICE_ID_S510_RECEIVER_2 0xc517
#define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512 #define USB_DEVICE_ID_LOGITECH_CORDLESS_DESKTOP_LX500 0xc512
#define USB_DEVICE_ID_MX3000_RECEIVER 0xc513 #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_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_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_SPACETRAVELLER 0xc623
#define USB_DEVICE_ID_SPACENAVIGATOR 0xc626 #define USB_DEVICE_ID_SPACENAVIGATOR 0xc626
#define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704 #define USB_DEVICE_ID_DINOVO_DESKTOP 0xc704
...@@ -1034,6 +1039,7 @@ ...@@ -1034,6 +1039,7 @@
#define USB_DEVICE_ID_SINO_LITE_CONTROLLER 0x3008 #define USB_DEVICE_ID_SINO_LITE_CONTROLLER 0x3008
#define USB_VENDOR_ID_SOLID_YEAR 0x060b #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_500K_GAMING_KEYBOARD 0x500a
#define USB_DEVICE_ID_COUGAR_700K_GAMING_KEYBOARD 0x700a #define USB_DEVICE_ID_COUGAR_700K_GAMING_KEYBOARD 0x700a
...@@ -1083,7 +1089,6 @@ ...@@ -1083,7 +1089,6 @@
#define USB_DEVICE_ID_SYNAPTICS_HD 0x0ac3 #define USB_DEVICE_ID_SYNAPTICS_HD 0x0ac3
#define USB_DEVICE_ID_SYNAPTICS_QUAD_HD 0x1ac3 #define USB_DEVICE_ID_SYNAPTICS_QUAD_HD 0x1ac3
#define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710 #define USB_DEVICE_ID_SYNAPTICS_TP_V103 0x5710
#define I2C_DEVICE_ID_SYNAPTICS_7E7E 0x7e7e
#define USB_VENDOR_ID_TEXAS_INSTRUMENTS 0x2047 #define USB_VENDOR_ID_TEXAS_INSTRUMENTS 0x2047
#define USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA 0x0855 #define USB_DEVICE_ID_TEXAS_INSTRUMENTS_LENOVO_YOGA 0x0855
......
...@@ -1557,52 +1557,71 @@ static void hidinput_close(struct input_dev *dev) ...@@ -1557,52 +1557,71 @@ static void hidinput_close(struct input_dev *dev)
hid_hw_close(hid); 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; struct hid_usage *usage;
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; bool update_needed = false;
int i, j;
if (rep->maxfield == 0) if (report->maxfield == 0)
continue; return false;
/* /*
* If we have more than one feature within this report we * If we have more than one feature within this report we
* need to fill in the bits from the others before we can * need to fill in the bits from the others before we can
* overwrite the ones for the Resolution Multiplier. * overwrite the ones for the Resolution Multiplier.
*/ */
if (rep->maxfield > 1) { if (report->maxfield > 1) {
hid_hw_request(hid, rep, HID_REQ_GET_REPORT); hid_hw_request(hid, report, HID_REQ_GET_REPORT);
hid_hw_wait(hid); hid_hw_wait(hid);
} }
for (i = 0; i < rep->maxfield; i++) { for (i = 0; i < report->maxfield; i++) {
__s32 logical_max = rep->field[i]->logical_maximum; __s32 value = use_logical_max ?
report->field[i]->logical_maximum :
report->field[i]->logical_minimum;
/* There is no good reason for a Resolution /* There is no good reason for a Resolution
* Multiplier to have a count other than 1. * Multiplier to have a count other than 1.
* Ignore that case. * Ignore that case.
*/ */
if (rep->field[i]->report_count != 1) if (report->field[i]->report_count != 1)
continue; continue;
for (j = 0; j < rep->field[i]->maxusage; j++) { for (j = 0; j < report->field[i]->maxusage; j++) {
usage = &rep->field[i]->usage[j]; usage = &report->field[i]->usage[j];
if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER) if (usage->hid != HID_GD_RESOLUTION_MULTIPLIER)
continue; continue;
*rep->field[i]->value = logical_max; report->field[i]->value[j] = value;
update_needed = true; update_needed = true;
} }
} }
if (update_needed)
hid_hw_request(hid, rep, HID_REQ_SET_REPORT); return update_needed;
}
static void hidinput_change_resolution_multipliers(struct hid_device *hid)
{
struct hid_report_enum *rep_enum;
struct hid_report *rep;
int ret;
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;
}
}
} }
/* refresh our structs */ /* refresh our structs */
......
...@@ -876,8 +876,6 @@ static const struct hid_device_id lg_devices[] = { ...@@ -876,8 +876,6 @@ static const struct hid_device_id lg_devices[] = {
.driver_data = LG_RDESC | LG_WIRELESS }, .driver_data = LG_RDESC | LG_WIRELESS },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER),
.driver_data = LG_RDESC | LG_WIRELESS }, .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), { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER),
.driver_data = LG_BAD_RELATIVE_KEYS }, .driver_data = LG_BAD_RELATIVE_KEYS },
......
This diff is collapsed.
This diff is collapsed.
// SPDX-License-Identifier: GPL-2.0+
/*
* HID driver for quirky Macally devices
*
* Copyright (c) 2019 Alex Henrie <alexhenrie24@gmail.com>
*/
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
MODULE_AUTHOR("Alex Henrie <alexhenrie24@gmail.com>");
MODULE_DESCRIPTION("Macally devices");
MODULE_LICENSE("GPL");
/*
* The Macally ikey keyboard says that its logical and usage maximums are both
* 101, but the power key is 102 and the equals key is 103
*/
static __u8 *macally_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize >= 60 && rdesc[53] == 0x65 && rdesc[59] == 0x65) {
hid_info(hdev,
"fixing up Macally ikey keyboard report descriptor\n");
rdesc[53] = rdesc[59] = 0x67;
}
return rdesc;
}
static struct hid_device_id macally_id_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SOLID_YEAR,
USB_DEVICE_ID_MACALLY_IKEY_KEYBOARD) },
{ }
};
MODULE_DEVICE_TABLE(hid, macally_id_table);
static struct hid_driver macally_driver = {
.name = "macally",
.id_table = macally_id_table,
.report_fixup = macally_report_fixup,
};
module_hid_driver(macally_driver);
...@@ -28,6 +28,7 @@ ...@@ -28,6 +28,7 @@
#include <linux/completion.h> #include <linux/completion.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/string.h>
#include "hid-picolcd.h" #include "hid-picolcd.h"
...@@ -275,27 +276,20 @@ static ssize_t picolcd_operation_mode_store(struct device *dev, ...@@ -275,27 +276,20 @@ static ssize_t picolcd_operation_mode_store(struct device *dev,
{ {
struct picolcd_data *data = dev_get_drvdata(dev); struct picolcd_data *data = dev_get_drvdata(dev);
struct hid_report *report = NULL; struct hid_report *report = NULL;
size_t cnt = count;
int timeout = data->opmode_delay; int timeout = data->opmode_delay;
unsigned long flags; unsigned long flags;
if (cnt >= 3 && strncmp("lcd", buf, 3) == 0) { if (sysfs_streq(buf, "lcd")) {
if (data->status & PICOLCD_BOOTLOADER) if (data->status & PICOLCD_BOOTLOADER)
report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev); report = picolcd_out_report(REPORT_EXIT_FLASHER, data->hdev);
buf += 3; } else if (sysfs_streq(buf, "bootloader")) {
cnt -= 3;
} else if (cnt >= 10 && strncmp("bootloader", buf, 10) == 0) {
if (!(data->status & PICOLCD_BOOTLOADER)) if (!(data->status & PICOLCD_BOOTLOADER))
report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev); report = picolcd_out_report(REPORT_EXIT_KEYBOARD, data->hdev);
buf += 10; } else {
cnt -= 10;
}
if (!report || report->maxfield != 1)
return -EINVAL; return -EINVAL;
}
while (cnt > 0 && (buf[cnt-1] == '\n' || buf[cnt-1] == '\r')) if (!report || report->maxfield != 1)
cnt--;
if (cnt != 0)
return -EINVAL; return -EINVAL;
spin_lock_irqsave(&data->lock, flags); spin_lock_irqsave(&data->lock, flags);
......
...@@ -432,7 +432,6 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -432,7 +432,6 @@ static const struct hid_device_id hid_have_special_driver[] = {
#if IS_ENABLED(CONFIG_HID_LOGITECH) #if IS_ENABLED(CONFIG_HID_LOGITECH)
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_MX3000_RECEIVER) }, { 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) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_S510_RECEIVER_2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_DESKTOP) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_DINOVO_EDGE) },
...@@ -464,13 +463,8 @@ static const struct hid_device_id hid_have_special_driver[] = { ...@@ -464,13 +463,8 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_SPACENAVIGATOR) },
#endif #endif
#if IS_ENABLED(CONFIG_HID_LOGITECH_HIDPP) #if IS_ENABLED(CONFIG_HID_LOGITECH_HIDPP)
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_T651) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) }, { HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_G920_WHEEL) },
#endif #endif
#if IS_ENABLED(CONFIG_HID_LOGITECH_DJ)
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER) },
{ HID_USB_DEVICE(USB_VENDOR_ID_LOGITECH, USB_DEVICE_ID_LOGITECH_UNIFYING_RECEIVER_2) },
#endif
#if IS_ENABLED(CONFIG_HID_MAGICMOUSE) #if IS_ENABLED(CONFIG_HID_MAGICMOUSE)
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICMOUSE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) }, { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGICTRACKPAD) },
......
...@@ -157,8 +157,7 @@ static int usage_id_cmp(const void *p1, const void *p2) ...@@ -157,8 +157,7 @@ static int usage_id_cmp(const void *p1, const void *p2)
static ssize_t enable_sensor_show(struct device *dev, static ssize_t enable_sensor_show(struct device *dev,
struct device_attribute *attr, char *buf) struct device_attribute *attr, char *buf)
{ {
struct platform_device *pdev = to_platform_device(dev); struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);
struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);
return sprintf(buf, "%d\n", sensor_inst->enable); return sprintf(buf, "%d\n", sensor_inst->enable);
} }
...@@ -237,8 +236,7 @@ static ssize_t enable_sensor_store(struct device *dev, ...@@ -237,8 +236,7 @@ static ssize_t enable_sensor_store(struct device *dev,
struct device_attribute *attr, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct platform_device *pdev = to_platform_device(dev); struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);
struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);
int value; int value;
int ret = -EINVAL; int ret = -EINVAL;
...@@ -283,8 +281,7 @@ static const struct attribute_group enable_sensor_attr_group = { ...@@ -283,8 +281,7 @@ static const struct attribute_group enable_sensor_attr_group = {
static ssize_t show_value(struct device *dev, struct device_attribute *attr, static ssize_t show_value(struct device *dev, struct device_attribute *attr,
char *buf) char *buf)
{ {
struct platform_device *pdev = to_platform_device(dev); struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);
struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);
struct hid_sensor_hub_attribute_info *attribute; struct hid_sensor_hub_attribute_info *attribute;
int index, usage, field_index; int index, usage, field_index;
char name[HID_CUSTOM_NAME_LENGTH]; char name[HID_CUSTOM_NAME_LENGTH];
...@@ -392,8 +389,7 @@ static ssize_t show_value(struct device *dev, struct device_attribute *attr, ...@@ -392,8 +389,7 @@ static ssize_t show_value(struct device *dev, struct device_attribute *attr,
static ssize_t store_value(struct device *dev, struct device_attribute *attr, static ssize_t store_value(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct platform_device *pdev = to_platform_device(dev); struct hid_sensor_custom *sensor_inst = dev_get_drvdata(dev);
struct hid_sensor_custom *sensor_inst = platform_get_drvdata(pdev);
int index, field_index, usage; int index, field_index, usage;
char name[HID_CUSTOM_NAME_LENGTH]; char name[HID_CUSTOM_NAME_LENGTH];
int value; int value;
......
// SPDX-License-Identifier: GPL-2.0
/*
* U2F Zero LED and RNG driver
*
* Copyright 2018 Andrej Shadura <andrew@shadura.me>
* Loosely based on drivers/hid/hid-led.c
* and drivers/usb/misc/chaoskey.c
*
* 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, version 2.
*/
#include <linux/hid.h>
#include <linux/hidraw.h>
#include <linux/hw_random.h>
#include <linux/leds.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/usb.h>
#include "usbhid/usbhid.h"
#include "hid-ids.h"
#define DRIVER_SHORT "u2fzero"
#define HID_REPORT_SIZE 64
/* We only use broadcast (CID-less) messages */
#define CID_BROADCAST 0xffffffff
struct u2f_hid_msg {
u32 cid;
union {
struct {
u8 cmd;
u8 bcnth;
u8 bcntl;
u8 data[HID_REPORT_SIZE - 7];
} init;
struct {
u8 seq;
u8 data[HID_REPORT_SIZE - 5];
} cont;
};
} __packed;
struct u2f_hid_report {
u8 report_type;
struct u2f_hid_msg msg;
} __packed;
#define U2F_HID_MSG_LEN(f) (size_t)(((f).init.bcnth << 8) + (f).init.bcntl)
/* Custom extensions to the U2FHID protocol */
#define U2F_CUSTOM_GET_RNG 0x21
#define U2F_CUSTOM_WINK 0x24
struct u2fzero_device {
struct hid_device *hdev;
struct urb *urb; /* URB for the RNG data */
struct led_classdev ldev; /* Embedded struct for led */
struct hwrng hwrng; /* Embedded struct for hwrng */
char *led_name;
char *rng_name;
u8 *buf_out;
u8 *buf_in;
struct mutex lock;
bool present;
};
static int u2fzero_send(struct u2fzero_device *dev, struct u2f_hid_report *req)
{
int ret;
mutex_lock(&dev->lock);
memcpy(dev->buf_out, req, sizeof(struct u2f_hid_report));
ret = hid_hw_output_report(dev->hdev, dev->buf_out,
sizeof(struct u2f_hid_msg));
mutex_unlock(&dev->lock);
if (ret < 0)
return ret;
return ret == sizeof(struct u2f_hid_msg) ? 0 : -EMSGSIZE;
}
struct u2fzero_transfer_context {
struct completion done;
int status;
};
static void u2fzero_read_callback(struct urb *urb)
{
struct u2fzero_transfer_context *ctx = urb->context;
ctx->status = urb->status;
complete(&ctx->done);
}
static int u2fzero_recv(struct u2fzero_device *dev,
struct u2f_hid_report *req,
struct u2f_hid_msg *resp)
{
int ret;
struct hid_device *hdev = dev->hdev;
struct u2fzero_transfer_context ctx;
mutex_lock(&dev->lock);
memcpy(dev->buf_out, req, sizeof(struct u2f_hid_report));
dev->urb->context = &ctx;
init_completion(&ctx.done);
ret = usb_submit_urb(dev->urb, GFP_NOIO);
if (unlikely(ret)) {
hid_err(hdev, "usb_submit_urb failed: %d", ret);
goto err;
}
ret = hid_hw_output_report(dev->hdev, dev->buf_out,
sizeof(struct u2f_hid_msg));
if (ret < 0) {
hid_err(hdev, "hid_hw_output_report failed: %d", ret);
goto err;
}
ret = (wait_for_completion_timeout(
&ctx.done, msecs_to_jiffies(USB_CTRL_SET_TIMEOUT)));
if (ret < 0) {
usb_kill_urb(dev->urb);
hid_err(hdev, "urb submission timed out");
} else {
ret = dev->urb->actual_length;
memcpy(resp, dev->buf_in, ret);
}
err:
mutex_unlock(&dev->lock);
return ret;
}
static int u2fzero_blink(struct led_classdev *ldev)
{
struct u2fzero_device *dev = container_of(ldev,
struct u2fzero_device, ldev);
struct u2f_hid_report req = {
.report_type = 0,
.msg.cid = CID_BROADCAST,
.msg.init = {
.cmd = U2F_CUSTOM_WINK,
.bcnth = 0,
.bcntl = 0,
.data = {0},
}
};
return u2fzero_send(dev, &req);
}
static int u2fzero_brightness_set(struct led_classdev *ldev,
enum led_brightness brightness)
{
ldev->brightness = LED_OFF;
if (brightness)
return u2fzero_blink(ldev);
else
return 0;
}
static int u2fzero_rng_read(struct hwrng *rng, void *data,
size_t max, bool wait)
{
struct u2fzero_device *dev = container_of(rng,
struct u2fzero_device, hwrng);
struct u2f_hid_report req = {
.report_type = 0,
.msg.cid = CID_BROADCAST,
.msg.init = {
.cmd = U2F_CUSTOM_GET_RNG,
.bcnth = 0,
.bcntl = 0,
.data = {0},
}
};
struct u2f_hid_msg resp;
int ret;
size_t actual_length;
if (!dev->present) {
hid_dbg(dev->hdev, "device not present");
return 0;
}
ret = u2fzero_recv(dev, &req, &resp);
if (ret < 0)
return 0;
/* only take the minimum amount of data it is safe to take */
actual_length = min3((size_t)ret - offsetof(struct u2f_hid_msg,
init.data), U2F_HID_MSG_LEN(resp), max);
memcpy(data, resp.init.data, actual_length);
return actual_length;
}
static int u2fzero_init_led(struct u2fzero_device *dev,
unsigned int minor)
{
dev->led_name = devm_kasprintf(&dev->hdev->dev, GFP_KERNEL,
"%s%u", DRIVER_SHORT, minor);
if (dev->led_name == NULL)
return -ENOMEM;
dev->ldev.name = dev->led_name;
dev->ldev.max_brightness = LED_ON;
dev->ldev.flags = LED_HW_PLUGGABLE;
dev->ldev.brightness_set_blocking = u2fzero_brightness_set;
return devm_led_classdev_register(&dev->hdev->dev, &dev->ldev);
}
static int u2fzero_init_hwrng(struct u2fzero_device *dev,
unsigned int minor)
{
dev->rng_name = devm_kasprintf(&dev->hdev->dev, GFP_KERNEL,
"%s-rng%u", DRIVER_SHORT, minor);
if (dev->rng_name == NULL)
return -ENOMEM;
dev->hwrng.name = dev->rng_name;
dev->hwrng.read = u2fzero_rng_read;
dev->hwrng.quality = 1;
return devm_hwrng_register(&dev->hdev->dev, &dev->hwrng);
}
static int u2fzero_fill_in_urb(struct u2fzero_device *dev)
{
struct hid_device *hdev = dev->hdev;
struct usb_device *udev;
struct usbhid_device *usbhid = hdev->driver_data;
unsigned int pipe_in;
struct usb_host_endpoint *ep;
if (dev->hdev->bus != BUS_USB)
return -EINVAL;
udev = hid_to_usb_dev(hdev);
if (!usbhid->urbout || !usbhid->urbin)
return -ENODEV;
ep = usb_pipe_endpoint(udev, usbhid->urbin->pipe);
if (!ep)
return -ENODEV;
dev->urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->urb)
return -ENOMEM;
pipe_in = (usbhid->urbin->pipe & ~(3 << 30)) | (PIPE_INTERRUPT << 30);
usb_fill_int_urb(dev->urb,
udev,
pipe_in,
dev->buf_in,
HID_REPORT_SIZE,
u2fzero_read_callback,
NULL,
ep->desc.bInterval);
return 0;
}
static int u2fzero_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
struct u2fzero_device *dev;
unsigned int minor;
int ret;
if (!hid_is_using_ll_driver(hdev, &usb_hid_driver))
return -EINVAL;
dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL);
if (dev == NULL)
return -ENOMEM;
dev->buf_out = devm_kmalloc(&hdev->dev,
sizeof(struct u2f_hid_report), GFP_KERNEL);
if (dev->buf_out == NULL)
return -ENOMEM;
dev->buf_in = devm_kmalloc(&hdev->dev,
sizeof(struct u2f_hid_msg), GFP_KERNEL);
if (dev->buf_in == NULL)
return -ENOMEM;
ret = hid_parse(hdev);
if (ret)
return ret;
dev->hdev = hdev;
hid_set_drvdata(hdev, dev);
mutex_init(&dev->lock);
ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW);
if (ret)
return ret;
u2fzero_fill_in_urb(dev);
dev->present = true;
minor = ((struct hidraw *) hdev->hidraw)->minor;
ret = u2fzero_init_led(dev, minor);
if (ret) {
hid_hw_stop(hdev);
return ret;
}
hid_info(hdev, "U2F Zero LED initialised\n");
ret = u2fzero_init_hwrng(dev, minor);
if (ret) {
hid_hw_stop(hdev);
return ret;
}
hid_info(hdev, "U2F Zero RNG initialised\n");
return 0;
}
static void u2fzero_remove(struct hid_device *hdev)
{
struct u2fzero_device *dev = hid_get_drvdata(hdev);
mutex_lock(&dev->lock);
dev->present = false;
mutex_unlock(&dev->lock);
hid_hw_stop(hdev);
usb_poison_urb(dev->urb);
usb_free_urb(dev->urb);
}
static const struct hid_device_id u2fzero_table[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_CYGNAL,
USB_DEVICE_ID_U2F_ZERO) },
{ }
};
MODULE_DEVICE_TABLE(hid, u2fzero_table);
static struct hid_driver u2fzero_driver = {
.name = "hid-" DRIVER_SHORT,
.probe = u2fzero_probe,
.remove = u2fzero_remove,
.id_table = u2fzero_table,
};
module_hid_driver(u2fzero_driver);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Andrej Shadura <andrew@shadura.me>");
MODULE_DESCRIPTION("U2F Zero LED and RNG driver");
...@@ -184,8 +184,6 @@ static const struct i2c_hid_quirks { ...@@ -184,8 +184,6 @@ static const struct i2c_hid_quirks {
I2C_HID_QUIRK_NO_RUNTIME_PM }, I2C_HID_QUIRK_NO_RUNTIME_PM },
{ USB_VENDOR_ID_ELAN, HID_ANY_ID, { USB_VENDOR_ID_ELAN, HID_ANY_ID,
I2C_HID_QUIRK_BOGUS_IRQ }, I2C_HID_QUIRK_BOGUS_IRQ },
{ USB_VENDOR_ID_SYNAPTICS, I2C_DEVICE_ID_SYNAPTICS_7E7E,
I2C_HID_QUIRK_NO_RUNTIME_PM },
{ 0, 0 } { 0, 0 }
}; };
......
...@@ -14,4 +14,19 @@ config INTEL_ISH_HID ...@@ -14,4 +14,19 @@ config INTEL_ISH_HID
Broxton and Kaby Lake. Broxton and Kaby Lake.
Say Y here if you want to support Intel ISH. If unsure, say N. Say Y here if you want to support Intel ISH. If unsure, say N.
config INTEL_ISH_FIRMWARE_DOWNLOADER
tristate "Host Firmware Load feature for Intel ISH"
depends on INTEL_ISH_HID
depends on X86
help
The Integrated Sensor Hub (ISH) enables the kernel to offload
sensor polling and algorithm processing to a dedicated low power
processor in the chipset.
The Host Firmware Load feature adds support to load the ISH
firmware from host file system at boot.
Say M here if you want to support Host Firmware Loading feature
for Intel ISH. If unsure, say N.
endmenu endmenu
...@@ -20,4 +20,7 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ishtp-hid.o ...@@ -20,4 +20,7 @@ obj-$(CONFIG_INTEL_ISH_HID) += intel-ishtp-hid.o
intel-ishtp-hid-objs := ishtp-hid.o intel-ishtp-hid-objs := ishtp-hid.o
intel-ishtp-hid-objs += ishtp-hid-client.o intel-ishtp-hid-objs += ishtp-hid-client.o
obj-$(CONFIG_INTEL_ISH_FIRMWARE_DOWNLOADER) += intel-ishtp-loader.o
intel-ishtp-loader-objs += ishtp-fw-loader.o
ccflags-y += -Idrivers/hid/intel-ish-hid/ishtp ccflags-y += -Idrivers/hid/intel-ish-hid/ishtp
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#define CNL_H_DEVICE_ID 0xA37C #define CNL_H_DEVICE_ID 0xA37C
#define ICL_MOBILE_DEVICE_ID 0x34FC #define ICL_MOBILE_DEVICE_ID 0x34FC
#define SPT_H_DEVICE_ID 0xA135 #define SPT_H_DEVICE_ID 0xA135
#define CML_LP_DEVICE_ID 0x02FC
#define REVISION_ID_CHT_A0 0x6 #define REVISION_ID_CHT_A0 0x6
#define REVISION_ID_CHT_Ax_SI 0x0 #define REVISION_ID_CHT_Ax_SI 0x0
......
...@@ -40,6 +40,7 @@ static const struct pci_device_id ish_pci_tbl[] = { ...@@ -40,6 +40,7 @@ static const struct pci_device_id ish_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_H_DEVICE_ID)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, CNL_H_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ICL_MOBILE_DEVICE_ID)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, ICL_MOBILE_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_H_DEVICE_ID)}, {PCI_DEVICE(PCI_VENDOR_ID_INTEL, SPT_H_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, CML_LP_DEVICE_ID)},
{0, } {0, }
}; };
MODULE_DEVICE_TABLE(pci, ish_pci_tbl); MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
......
This diff is collapsed.
...@@ -14,8 +14,8 @@ ...@@ -14,8 +14,8 @@
*/ */
#include <linux/hid.h> #include <linux/hid.h>
#include <linux/intel-ish-client-if.h>
#include <uapi/linux/input.h> #include <uapi/linux/input.h>
#include "ishtp/client.h"
#include "ishtp-hid.h" #include "ishtp-hid.h"
/** /**
...@@ -59,10 +59,46 @@ static void ishtp_hid_close(struct hid_device *hid) ...@@ -59,10 +59,46 @@ static void ishtp_hid_close(struct hid_device *hid)
{ {
} }
static int ishtp_raw_request(struct hid_device *hdev, unsigned char reportnum, static int ishtp_raw_request(struct hid_device *hid, unsigned char reportnum,
__u8 *buf, size_t len, unsigned char rtype, int reqtype) __u8 *buf, size_t len, unsigned char rtype,
int reqtype)
{ {
return 0; struct ishtp_hid_data *hid_data = hid->driver_data;
char *ishtp_buf = NULL;
size_t ishtp_buf_len;
unsigned int header_size = sizeof(struct hostif_msg);
if (rtype == HID_OUTPUT_REPORT)
return -EINVAL;
hid_data->request_done = false;
switch (reqtype) {
case HID_REQ_GET_REPORT:
hid_data->raw_buf = buf;
hid_data->raw_buf_size = len;
hid_data->raw_get_req = true;
hid_ishtp_get_report(hid, reportnum, rtype);
break;
case HID_REQ_SET_REPORT:
/*
* Spare 7 bytes for 64b accesses through
* get/put_unaligned_le64()
*/
ishtp_buf_len = len + header_size;
ishtp_buf = kzalloc(ishtp_buf_len + 7, GFP_KERNEL);
if (!ishtp_buf)
return -ENOMEM;
memcpy(ishtp_buf + header_size, buf, len);
hid_ishtp_set_feature(hid, ishtp_buf, ishtp_buf_len, reportnum);
kfree(ishtp_buf);
break;
}
hid_hw_wait(hid);
return len;
} }
/** /**
...@@ -87,6 +123,7 @@ static void ishtp_hid_request(struct hid_device *hid, struct hid_report *rep, ...@@ -87,6 +123,7 @@ static void ishtp_hid_request(struct hid_device *hid, struct hid_report *rep,
hid_data->request_done = false; hid_data->request_done = false;
switch (reqtype) { switch (reqtype) {
case HID_REQ_GET_REPORT: case HID_REQ_GET_REPORT:
hid_data->raw_get_req = false;
hid_ishtp_get_report(hid, rep->id, rep->type); hid_ishtp_get_report(hid, rep->id, rep->type);
break; break;
case HID_REQ_SET_REPORT: case HID_REQ_SET_REPORT:
...@@ -116,7 +153,6 @@ static void ishtp_hid_request(struct hid_device *hid, struct hid_report *rep, ...@@ -116,7 +153,6 @@ static void ishtp_hid_request(struct hid_device *hid, struct hid_report *rep,
static int ishtp_wait_for_response(struct hid_device *hid) static int ishtp_wait_for_response(struct hid_device *hid)
{ {
struct ishtp_hid_data *hid_data = hid->driver_data; struct ishtp_hid_data *hid_data = hid->driver_data;
struct ishtp_cl_data *client_data = hid_data->client_data;
int rv; int rv;
hid_ishtp_trace(client_data, "%s hid %p\n", __func__, hid); hid_ishtp_trace(client_data, "%s hid %p\n", __func__, hid);
...@@ -204,7 +240,8 @@ int ishtp_hid_probe(unsigned int cur_hid_dev, ...@@ -204,7 +240,8 @@ int ishtp_hid_probe(unsigned int cur_hid_dev,
hid->ll_driver = &ishtp_hid_ll_driver; hid->ll_driver = &ishtp_hid_ll_driver;
hid->bus = BUS_INTEL_ISHTP; hid->bus = BUS_INTEL_ISHTP;
hid->dev.parent = &client_data->cl_device->dev; hid->dev.parent = ishtp_device(client_data->cl_device);
hid->version = le16_to_cpu(ISH_HID_VERSION); hid->version = le16_to_cpu(ISH_HID_VERSION);
hid->vendor = le16_to_cpu(client_data->hid_devices[cur_hid_dev].vid); hid->vendor = le16_to_cpu(client_data->hid_devices[cur_hid_dev].vid);
hid->product = le16_to_cpu(client_data->hid_devices[cur_hid_dev].pid); hid->product = le16_to_cpu(client_data->hid_devices[cur_hid_dev].pid);
......
...@@ -24,9 +24,9 @@ ...@@ -24,9 +24,9 @@
#define IS_RESPONSE 0x80 #define IS_RESPONSE 0x80
/* Used to dump to Linux trace buffer, if enabled */ /* Used to dump to Linux trace buffer, if enabled */
extern void (*hid_print_trace)(void *unused, const char *format, ...);
#define hid_ishtp_trace(client, ...) \ #define hid_ishtp_trace(client, ...) \
client->cl_device->ishtp_dev->print_log(\ (hid_print_trace)(NULL, __VA_ARGS__)
client->cl_device->ishtp_dev, __VA_ARGS__)
/* ISH Transport protocol (ISHTP in short) GUID */ /* ISH Transport protocol (ISHTP in short) GUID */
static const guid_t hid_ishtp_guid = static const guid_t hid_ishtp_guid =
...@@ -159,6 +159,9 @@ struct ishtp_cl_data { ...@@ -159,6 +159,9 @@ struct ishtp_cl_data {
* @client_data: Link to the client instance * @client_data: Link to the client instance
* @hid_wait: Completion waitq * @hid_wait: Completion waitq
* *
* @raw_get_req: Flag indicating raw get request ongoing
* @raw_buf: raw request buffer filled on receiving get report
* @raw_buf_size: raw request buffer size
* Used to tie hid hid->driver data to driver client instance * Used to tie hid hid->driver data to driver client instance
*/ */
struct ishtp_hid_data { struct ishtp_hid_data {
...@@ -166,6 +169,11 @@ struct ishtp_hid_data { ...@@ -166,6 +169,11 @@ struct ishtp_hid_data {
bool request_done; bool request_done;
struct ishtp_cl_data *client_data; struct ishtp_cl_data *client_data;
wait_queue_head_t hid_wait; wait_queue_head_t hid_wait;
/* raw request */
bool raw_get_req;
u8 *raw_buf;
size_t raw_buf_size;
}; };
/* Interface functions between HID LL driver and ISH TP client */ /* Interface functions between HID LL driver and ISH TP client */
......
...@@ -170,6 +170,19 @@ struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev, ...@@ -170,6 +170,19 @@ struct ishtp_fw_client *ishtp_fw_cl_get_client(struct ishtp_device *dev,
} }
EXPORT_SYMBOL(ishtp_fw_cl_get_client); EXPORT_SYMBOL(ishtp_fw_cl_get_client);
/**
* ishtp_get_fw_client_id() - Get fw client id
*
* This interface is used to reset HW get FW client id.
*
* Return: firmware client id.
*/
int ishtp_get_fw_client_id(struct ishtp_fw_client *fw_client)
{
return fw_client->client_id;
}
EXPORT_SYMBOL(ishtp_get_fw_client_id);
/** /**
* ishtp_fw_cl_by_id() - return index to fw_clients for client_id * ishtp_fw_cl_by_id() - return index to fw_clients for client_id
* @dev: the ishtp device structure * @dev: the ishtp device structure
...@@ -219,6 +232,26 @@ static int ishtp_cl_device_probe(struct device *dev) ...@@ -219,6 +232,26 @@ static int ishtp_cl_device_probe(struct device *dev)
return driver->probe(device); return driver->probe(device);
} }
/**
* ishtp_cl_bus_match() - Bus match() callback
* @dev: the device structure
* @drv: the driver structure
*
* This is a bus match callback, called when a new ishtp_cl_device is
* registered during ishtp bus client enumeration. Use the guid_t in
* drv and dev to decide whether they match or not.
*
* Return: 1 if dev & drv matches, 0 otherwise.
*/
static int ishtp_cl_bus_match(struct device *dev, struct device_driver *drv)
{
struct ishtp_cl_device *device = to_ishtp_cl_device(dev);
struct ishtp_cl_driver *driver = to_ishtp_cl_driver(drv);
return guid_equal(driver->guid,
&device->fw_client->props.protocol_name);
}
/** /**
* ishtp_cl_device_remove() - Bus remove() callback * ishtp_cl_device_remove() - Bus remove() callback
* @dev: the device structure * @dev: the device structure
...@@ -372,6 +405,7 @@ static struct bus_type ishtp_cl_bus_type = { ...@@ -372,6 +405,7 @@ static struct bus_type ishtp_cl_bus_type = {
.name = "ishtp", .name = "ishtp",
.dev_groups = ishtp_cl_dev_groups, .dev_groups = ishtp_cl_dev_groups,
.probe = ishtp_cl_device_probe, .probe = ishtp_cl_device_probe,
.match = ishtp_cl_bus_match,
.remove = ishtp_cl_device_remove, .remove = ishtp_cl_device_remove,
.pm = &ishtp_cl_bus_dev_pm_ops, .pm = &ishtp_cl_bus_dev_pm_ops,
.uevent = ishtp_cl_uevent, .uevent = ishtp_cl_uevent,
...@@ -445,6 +479,7 @@ static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev, ...@@ -445,6 +479,7 @@ static struct ishtp_cl_device *ishtp_bus_add_device(struct ishtp_device *dev,
} }
ishtp_device_ready = true; ishtp_device_ready = true;
dev_set_drvdata(&device->dev, device);
return device; return device;
} }
...@@ -464,7 +499,7 @@ static void ishtp_bus_remove_device(struct ishtp_cl_device *device) ...@@ -464,7 +499,7 @@ static void ishtp_bus_remove_device(struct ishtp_cl_device *device)
} }
/** /**
* __ishtp_cl_driver_register() - Client driver register * ishtp_cl_driver_register() - Client driver register
* @driver: the client driver instance * @driver: the client driver instance
* @owner: Owner of this driver module * @owner: Owner of this driver module
* *
...@@ -473,7 +508,7 @@ static void ishtp_bus_remove_device(struct ishtp_cl_device *device) ...@@ -473,7 +508,7 @@ static void ishtp_bus_remove_device(struct ishtp_cl_device *device)
* *
* Return: Return value of driver_register or -ENODEV if not ready * Return: Return value of driver_register or -ENODEV if not ready
*/ */
int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver, int ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
struct module *owner) struct module *owner)
{ {
int err; int err;
...@@ -491,7 +526,7 @@ int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver, ...@@ -491,7 +526,7 @@ int __ishtp_cl_driver_register(struct ishtp_cl_driver *driver,
return 0; return 0;
} }
EXPORT_SYMBOL(__ishtp_cl_driver_register); EXPORT_SYMBOL(ishtp_cl_driver_register);
/** /**
* ishtp_cl_driver_unregister() - Client driver unregister * ishtp_cl_driver_unregister() - Client driver unregister
...@@ -806,6 +841,59 @@ int ishtp_use_dma_transfer(void) ...@@ -806,6 +841,59 @@ int ishtp_use_dma_transfer(void)
return ishtp_use_dma; return ishtp_use_dma;
} }
/**
* ishtp_device() - Return device pointer
*
* This interface is used to return device pointer from ishtp_cl_device
* instance.
*
* Return: device *.
*/
struct device *ishtp_device(struct ishtp_cl_device *device)
{
return &device->dev;
}
EXPORT_SYMBOL(ishtp_device);
/**
* ishtp_get_pci_device() - Return PCI device dev pointer
* This interface is used to return PCI device pointer
* from ishtp_cl_device instance.
*
* Return: device *.
*/
struct device *ishtp_get_pci_device(struct ishtp_cl_device *device)
{
return device->ishtp_dev->devc;
}
EXPORT_SYMBOL(ishtp_get_pci_device);
/**
* ishtp_trace_callback() - Return trace callback
*
* This interface is used to return trace callback function pointer.
*
* Return: void *.
*/
void *ishtp_trace_callback(struct ishtp_cl_device *cl_device)
{
return cl_device->ishtp_dev->print_log;
}
EXPORT_SYMBOL(ishtp_trace_callback);
/**
* ish_hw_reset() - Call HW reset IPC callback
*
* This interface is used to reset HW in case of error.
*
* Return: value from IPC hw_reset callback
*/
int ish_hw_reset(struct ishtp_device *dev)
{
return dev->ops->hw_reset(dev);
}
EXPORT_SYMBOL(ish_hw_reset);
/** /**
* ishtp_bus_register() - Function to register bus * ishtp_bus_register() - Function to register bus
* *
......
This diff is collapsed.
This diff is collapsed.
...@@ -19,15 +19,6 @@ ...@@ -19,15 +19,6 @@
#include <linux/types.h> #include <linux/types.h>
#include "ishtp-dev.h" #include "ishtp-dev.h"
/* Client state */
enum cl_state {
ISHTP_CL_INITIALIZING = 0,
ISHTP_CL_CONNECTING,
ISHTP_CL_CONNECTED,
ISHTP_CL_DISCONNECTING,
ISHTP_CL_DISCONNECTED
};
/* Tx and Rx ring size */ /* Tx and Rx ring size */
#define CL_DEF_RX_RING_SIZE 2 #define CL_DEF_RX_RING_SIZE 2
#define CL_DEF_TX_RING_SIZE 2 #define CL_DEF_TX_RING_SIZE 2
...@@ -169,19 +160,4 @@ static inline bool ishtp_cl_cmp_id(const struct ishtp_cl *cl1, ...@@ -169,19 +160,4 @@ static inline bool ishtp_cl_cmp_id(const struct ishtp_cl *cl1,
(cl1->fw_client_id == cl2->fw_client_id); (cl1->fw_client_id == cl2->fw_client_id);
} }
/* exported functions from ISHTP under client management scope */
struct ishtp_cl *ishtp_cl_allocate(struct ishtp_device *dev);
void ishtp_cl_free(struct ishtp_cl *cl);
int ishtp_cl_link(struct ishtp_cl *cl, int id);
void ishtp_cl_unlink(struct ishtp_cl *cl);
int ishtp_cl_disconnect(struct ishtp_cl *cl);
int ishtp_cl_connect(struct ishtp_cl *cl);
int ishtp_cl_send(struct ishtp_cl *cl, uint8_t *buf, size_t length);
int ishtp_cl_flush_queues(struct ishtp_cl *cl);
/* exported functions from ISHTP client buffer management scope */
int ishtp_cl_io_rb_recycle(struct ishtp_cl_rb *rb);
bool ishtp_cl_tx_empty(struct ishtp_cl *cl);
struct ishtp_cl_rb *ishtp_cl_rx_get_rb(struct ishtp_cl *cl);
#endif /* _ISHTP_CLIENT_H_ */ #endif /* _ISHTP_CLIENT_H_ */
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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