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

Pull HID updates from Jiri Kosina:

 - rework of generic input handling which ultimately makes the
   processing of tablet events more generic and reliable (Benjamin
   Tissoires)

 - fixes for handling unnumbered reports fully correctly in i2c-hid
   (Angela Czubak, Dmitry Torokhov)

 - untangling of intermingled code for sending and handling output
   reports in i2c-hid (Dmitry Torokhov)

 - Apple magic keyboard support improvements for newer models (José
   Expósito)

 - Apple T2 Macs support improvements (Aun-Ali Zaidi, Paul Pawlowski)

 - driver for Razer Blackwidow keyboards (Jelle van der Waa)

 - driver for SiGma Micro keyboards (Desmond Lim)

 - integration of first part of DIGImend patches in order to ultimately
   vastly improve Linux support of tablets (Nikolai Kondrashov, José
   Expósito)

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (55 commits)
  HID: intel-ish-hid: Use dma_alloc_coherent for firmware update
  Input: docs: add more details on the use of BTN_TOOL
  HID: input: accommodate priorities for slotted devices
  HID: input: remove the need for HID_QUIRK_INVERT
  HID: input: enforce Invert usage to be processed before InRange
  HID: core: for input reports, process the usages by priority list
  HID: compute an ordered list of input fields to process
  HID: input: move up out-of-range processing of input values
  HID: input: rework spaghetti code with switch statements
  HID: input: tag touchscreens as such if the physical is not there
  HID: core: split data fetching from processing in hid_input_field()
  HID: core: de-duplicate some code in hid_input_field()
  HID: core: statically allocate read buffers
  HID: uclogic: Support multiple frame input devices
  HID: uclogic: Define report IDs before their descriptors
  HID: uclogic: Put version first in rdesc namespace
  HID: uclogic: Use "frame" instead of "buttonpad"
  HID: uclogic: Use different constants for frame report IDs
  HID: uclogic: Specify total report size to buttonpad macro
  HID: uclogic: Switch to matching subreport bytes
  ...
This commit is contained in:
Linus Torvalds 2022-03-25 12:22:16 -07:00
commit 5e206459f6
20 changed files with 1846 additions and 760 deletions

View File

@ -137,7 +137,11 @@ A few EV_KEY codes have special meanings:
code should be set to a value of 1. When the tool is no longer interacting
with the input device, the BTN_TOOL_<name> code should be reset to 0. All
trackpads, tablets, and touchscreens should use at least one BTN_TOOL_<name>
code when events are generated.
code when events are generated. Likewise all trackpads, tablets, and
touchscreens should export only one BTN_TOOL_<name> at a time. To not break
existing userspace, it is recommended to not switch tool in one EV_SYN frame
but first emitting the old BTN_TOOL_<name> at 0, then emit one SYN_REPORT
and then set the new BTN_TOOL_<name> at 1.
* BTN_TOUCH:

View File

@ -128,6 +128,8 @@ config HID_ACRUX_FF
config HID_APPLE
tristate "Apple {i,Power,Mac}Books"
depends on HID
depends on LEDS_CLASS
depends on NEW_LEDS
default !EXPERT
help
Support for some Apple devices which less or more break
@ -929,6 +931,13 @@ config PLAYSTATION_FF
Say Y here if you would like to enable force feedback support for
PlayStation game controllers.
config HID_RAZER
tristate "Razer non-fully HID-compliant devices"
depends on HID
help
Support for Razer devices that are not fully compliant with the
HID standard.
config HID_PRIMAX
tristate "Primax non-fully HID-compliant devices"
depends on HID
@ -984,6 +993,16 @@ config HID_SEMITEK
- Woo-dy
- X-Bows Nature/Knight
config HID_SIGMAMICRO
tristate "SiGma Micro-based keyboards"
depends on USB_HID
help
Support for keyboards that use the SiGma Micro (a.k.a SigmaChip) IC.
Supported devices:
- Landslides KR-700
- Rapoo V500
config HID_SONY
tristate "Sony PS2/3/4 accessories"
depends on USB_HID

View File

@ -99,6 +99,7 @@ hid-picolcd-$(CONFIG_DEBUG_FS) += hid-picolcd_debugfs.o
obj-$(CONFIG_HID_PLANTRONICS) += hid-plantronics.o
obj-$(CONFIG_HID_PLAYSTATION) += hid-playstation.o
obj-$(CONFIG_HID_PRIMAX) += hid-primax.o
obj-$(CONFIG_HID_RAZER) += hid-razer.o
obj-$(CONFIG_HID_REDRAGON) += hid-redragon.o
obj-$(CONFIG_HID_RETRODE) += hid-retrode.o
obj-$(CONFIG_HID_ROCCAT) += hid-roccat.o hid-roccat-common.o \
@ -109,6 +110,7 @@ obj-$(CONFIG_HID_RMI) += hid-rmi.o
obj-$(CONFIG_HID_SAITEK) += hid-saitek.o
obj-$(CONFIG_HID_SAMSUNG) += hid-samsung.o
obj-$(CONFIG_HID_SEMITEK) += hid-semitek.o
obj-$(CONFIG_HID_SIGMAMICRO) += hid-sigmamicro.o
obj-$(CONFIG_HID_SMARTJOYPLUS) += hid-sjoy.o
obj-$(CONFIG_HID_SONY) += hid-sony.o
obj-$(CONFIG_HID_SPEEDLINK) += hid-speedlink.o

View File

@ -301,11 +301,8 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
pci_set_master(pdev);
rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (rc) {
rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (rc) {
dev_err(&pdev->dev, "failed to set DMA mask\n");
return rc;
}
dev_err(&pdev->dev, "failed to set DMA mask\n");
return rc;
}
privdata->cl_data = devm_kzalloc(&pdev->dev, sizeof(struct amdtp_cl_data), GFP_KERNEL);

View File

@ -7,6 +7,7 @@
* Copyright (c) 2005 Michael Haboustak <mike-@cinci.rr.com> for Concept2, Inc
* Copyright (c) 2006-2007 Jiri Kosina
* Copyright (c) 2008 Jiri Slaby <jirislaby@gmail.com>
* Copyright (c) 2019 Paul Pawlowski <paul@mrarm.io>
*/
/*
@ -33,6 +34,7 @@
/* BIT(7) reserved, was: APPLE_IGNORE_HIDINPUT */
#define APPLE_NUMLOCK_EMULATION BIT(8)
#define APPLE_RDESC_BATTERY BIT(9)
#define APPLE_BACKLIGHT_CTL BIT(10)
#define APPLE_FLAG_FKEY 0x01
@ -61,6 +63,12 @@ MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. "
"(For people who want to keep PC keyboard muscle memory. "
"[0] = as-is, Mac layout, 1 = swapped, PC layout)");
struct apple_sc_backlight {
struct led_classdev cdev;
struct hid_device *hdev;
unsigned short backlight_off, backlight_on_min, backlight_on_max;
};
struct apple_sc {
struct hid_device *hdev;
unsigned long quirks;
@ -68,6 +76,7 @@ struct apple_sc {
unsigned int fn_found;
DECLARE_BITMAP(pressed_numlock, KEY_CNT);
struct timer_list battery_timer;
struct apple_sc_backlight *backlight;
};
struct apple_key_translation {
@ -76,6 +85,61 @@ struct apple_key_translation {
u8 flags;
};
static const struct apple_key_translation magic_keyboard_alu_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
{ KEY_ENTER, KEY_INSERT },
{ KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
{ KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY },
{ KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY },
{ KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY },
{ KEY_F6, KEY_NUMLOCK, APPLE_FLAG_FKEY },
{ KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY },
{ KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY },
{ KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY },
{ KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY },
{ KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY },
{ KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY },
{ KEY_UP, KEY_PAGEUP },
{ KEY_DOWN, KEY_PAGEDOWN },
{ KEY_LEFT, KEY_HOME },
{ KEY_RIGHT, KEY_END },
{ }
};
static const struct apple_key_translation magic_keyboard_2015_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
{ KEY_ENTER, KEY_INSERT },
{ KEY_F1, KEY_BRIGHTNESSDOWN, APPLE_FLAG_FKEY },
{ KEY_F2, KEY_BRIGHTNESSUP, APPLE_FLAG_FKEY },
{ KEY_F3, KEY_SCALE, APPLE_FLAG_FKEY },
{ KEY_F4, KEY_DASHBOARD, APPLE_FLAG_FKEY },
{ KEY_F7, KEY_PREVIOUSSONG, APPLE_FLAG_FKEY },
{ KEY_F8, KEY_PLAYPAUSE, APPLE_FLAG_FKEY },
{ KEY_F9, KEY_NEXTSONG, APPLE_FLAG_FKEY },
{ KEY_F10, KEY_MUTE, APPLE_FLAG_FKEY },
{ KEY_F11, KEY_VOLUMEDOWN, APPLE_FLAG_FKEY },
{ KEY_F12, KEY_VOLUMEUP, APPLE_FLAG_FKEY },
{ KEY_UP, KEY_PAGEUP },
{ KEY_DOWN, KEY_PAGEDOWN },
{ KEY_LEFT, KEY_HOME },
{ KEY_RIGHT, KEY_END },
{ }
};
struct apple_backlight_config_report {
u8 report_id;
u8 version;
u16 backlight_off, backlight_on_min, backlight_on_max;
};
struct apple_backlight_set_report {
u8 report_id;
u8 version;
u16 backlight;
u16 rate;
};
static const struct apple_key_translation apple2021_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
{ KEY_ENTER, KEY_INSERT },
@ -119,6 +183,51 @@ static const struct apple_key_translation macbookair_fn_keys[] = {
{ }
};
static const struct apple_key_translation macbookpro_no_esc_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
{ KEY_ENTER, KEY_INSERT },
{ KEY_GRAVE, KEY_ESC },
{ KEY_1, KEY_F1 },
{ KEY_2, KEY_F2 },
{ KEY_3, KEY_F3 },
{ KEY_4, KEY_F4 },
{ KEY_5, KEY_F5 },
{ KEY_6, KEY_F6 },
{ KEY_7, KEY_F7 },
{ KEY_8, KEY_F8 },
{ KEY_9, KEY_F9 },
{ KEY_0, KEY_F10 },
{ KEY_MINUS, KEY_F11 },
{ KEY_EQUAL, KEY_F12 },
{ KEY_UP, KEY_PAGEUP },
{ KEY_DOWN, KEY_PAGEDOWN },
{ KEY_LEFT, KEY_HOME },
{ KEY_RIGHT, KEY_END },
{ }
};
static const struct apple_key_translation macbookpro_dedicated_esc_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
{ KEY_ENTER, KEY_INSERT },
{ KEY_1, KEY_F1 },
{ KEY_2, KEY_F2 },
{ KEY_3, KEY_F3 },
{ KEY_4, KEY_F4 },
{ KEY_5, KEY_F5 },
{ KEY_6, KEY_F6 },
{ KEY_7, KEY_F7 },
{ KEY_8, KEY_F8 },
{ KEY_9, KEY_F9 },
{ KEY_0, KEY_F10 },
{ KEY_MINUS, KEY_F11 },
{ KEY_EQUAL, KEY_F12 },
{ KEY_UP, KEY_PAGEUP },
{ KEY_DOWN, KEY_PAGEDOWN },
{ KEY_LEFT, KEY_HOME },
{ KEY_RIGHT, KEY_END },
{ }
};
static const struct apple_key_translation apple_fn_keys[] = {
{ KEY_BACKSPACE, KEY_DELETE },
{ KEY_ENTER, KEY_INSERT },
@ -202,6 +311,15 @@ static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
{ }
};
static inline void apple_setup_key_translation(struct input_dev *input,
const struct apple_key_translation *table)
{
const struct apple_key_translation *trans;
for (trans = table; trans->from; trans++)
set_bit(trans->to, input->keybit);
}
static const struct apple_key_translation *apple_find_translation(
const struct apple_key_translation *table, u16 from)
{
@ -242,10 +360,34 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
}
if (fnmode) {
if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 ||
hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 ||
hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021)
if (hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI ||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO ||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS ||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI ||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO ||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS ||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ANSI ||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_ISO ||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_2011_JIS)
table = magic_keyboard_alu_fn_keys;
else if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2015 ||
hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2015)
table = magic_keyboard_2015_fn_keys;
else if (hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021 ||
hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021 ||
hid->product == USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021)
table = apple2021_fn_keys;
else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 ||
hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 ||
hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213)
table = macbookpro_no_esc_fn_keys;
else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K ||
hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 ||
hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F)
table = macbookpro_dedicated_esc_fn_keys;
else if (hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K ||
hid->product == USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K)
table = apple_fn_keys;
else if (hid->product >= USB_DEVICE_ID_APPLE_WELLSPRING4_ANSI &&
hid->product <= USB_DEVICE_ID_APPLE_WELLSPRING4A_JIS)
table = macbookair_fn_keys;
@ -452,30 +594,21 @@ static __u8 *apple_report_fixup(struct hid_device *hdev, __u8 *rdesc,
static void apple_setup_input(struct input_dev *input)
{
const struct apple_key_translation *trans;
set_bit(KEY_NUMLOCK, input->keybit);
/* Enable all needed keys */
for (trans = apple_fn_keys; trans->from; trans++)
set_bit(trans->to, input->keybit);
apple_setup_key_translation(input, apple_fn_keys);
apple_setup_key_translation(input, powerbook_fn_keys);
apple_setup_key_translation(input, powerbook_numlock_keys);
apple_setup_key_translation(input, apple_iso_keyboard);
apple_setup_key_translation(input, magic_keyboard_alu_fn_keys);
apple_setup_key_translation(input, magic_keyboard_2015_fn_keys);
apple_setup_key_translation(input, apple2021_fn_keys);
apple_setup_key_translation(input, macbookpro_no_esc_fn_keys);
apple_setup_key_translation(input, macbookpro_dedicated_esc_fn_keys);
for (trans = powerbook_fn_keys; trans->from; trans++)
set_bit(trans->to, input->keybit);
for (trans = powerbook_numlock_keys; trans->from; trans++)
set_bit(trans->to, input->keybit);
for (trans = apple_iso_keyboard; trans->from; trans++)
set_bit(trans->to, input->keybit);
for (trans = apple2021_fn_keys; trans->from; trans++)
set_bit(trans->to, input->keybit);
if (swap_fn_leftctrl) {
for (trans = swapped_fn_leftctrl_keys; trans->from; trans++)
set_bit(trans->to, input->keybit);
}
if (swap_fn_leftctrl)
apple_setup_key_translation(input, swapped_fn_leftctrl_keys);
}
static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi,
@ -530,6 +663,105 @@ static int apple_input_configured(struct hid_device *hdev,
return 0;
}
static bool apple_backlight_check_support(struct hid_device *hdev)
{
int i;
unsigned int hid;
struct hid_report *report;
list_for_each_entry(report, &hdev->report_enum[HID_INPUT_REPORT].report_list, list) {
for (i = 0; i < report->maxfield; i++) {
hid = report->field[i]->usage->hid;
if ((hid & HID_USAGE_PAGE) == HID_UP_MSVENDOR && (hid & HID_USAGE) == 0xf)
return true;
}
}
return false;
}
static int apple_backlight_set(struct hid_device *hdev, u16 value, u16 rate)
{
int ret = 0;
struct apple_backlight_set_report *rep;
rep = kmalloc(sizeof(*rep), GFP_KERNEL);
if (rep == NULL)
return -ENOMEM;
rep->report_id = 0xB0;
rep->version = 1;
rep->backlight = value;
rep->rate = rate;
ret = hid_hw_raw_request(hdev, 0xB0u, (u8 *) rep, sizeof(*rep),
HID_OUTPUT_REPORT, HID_REQ_SET_REPORT);
kfree(rep);
return ret;
}
static int apple_backlight_led_set(struct led_classdev *led_cdev,
enum led_brightness brightness)
{
struct apple_sc_backlight *backlight = container_of(led_cdev,
struct apple_sc_backlight, cdev);
return apple_backlight_set(backlight->hdev, brightness, 0);
}
static int apple_backlight_init(struct hid_device *hdev)
{
int ret;
struct apple_sc *asc = hid_get_drvdata(hdev);
struct apple_backlight_config_report *rep;
if (!apple_backlight_check_support(hdev))
return -EINVAL;
rep = kmalloc(0x200, GFP_KERNEL);
if (rep == NULL)
return -ENOMEM;
ret = hid_hw_raw_request(hdev, 0xBFu, (u8 *) rep, sizeof(*rep),
HID_FEATURE_REPORT, HID_REQ_GET_REPORT);
if (ret < 0) {
hid_err(hdev, "backlight request failed: %d\n", ret);
goto cleanup_and_exit;
}
if (ret < 8 || rep->version != 1) {
hid_err(hdev, "backlight config struct: bad version %i\n", rep->version);
ret = -EINVAL;
goto cleanup_and_exit;
}
hid_dbg(hdev, "backlight config: off=%u, on_min=%u, on_max=%u\n",
rep->backlight_off, rep->backlight_on_min, rep->backlight_on_max);
asc->backlight = devm_kzalloc(&hdev->dev, sizeof(*asc->backlight), GFP_KERNEL);
if (!asc->backlight) {
ret = -ENOMEM;
goto cleanup_and_exit;
}
asc->backlight->hdev = hdev;
asc->backlight->cdev.name = "apple::kbd_backlight";
asc->backlight->cdev.max_brightness = rep->backlight_on_max;
asc->backlight->cdev.brightness_set_blocking = apple_backlight_led_set;
ret = apple_backlight_set(hdev, 0, 0);
if (ret < 0) {
hid_err(hdev, "backlight set request failed: %d\n", ret);
goto cleanup_and_exit;
}
ret = devm_led_classdev_register(&hdev->dev, &asc->backlight->cdev);
cleanup_and_exit:
kfree(rep);
return ret;
}
static int apple_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
@ -565,6 +797,9 @@ static int apple_probe(struct hid_device *hdev,
jiffies + msecs_to_jiffies(APPLE_BATTERY_TIMEOUT_MS));
apple_fetch_battery(hdev);
if (quirks & APPLE_BACKLIGHT_CTL)
apple_backlight_init(hdev);
return 0;
}
@ -736,6 +971,22 @@ static const struct hid_device_id apple_devices[] = {
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS),
.driver_data = APPLE_HAS_FN | APPLE_RDESC_JIS },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K),
.driver_data = APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223),
.driver_data = APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K),
.driver_data = APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F),
.driver_data = APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO),
@ -748,15 +999,15 @@ static const struct hid_device_id apple_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY),
.driver_data = APPLE_NUMLOCK_EMULATION | APPLE_HAS_FN },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_2021),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_FINGERPRINT_2021),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK | APPLE_RDESC_BATTERY },
{ HID_BLUETOOTH_DEVICE(BT_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_MAGIC_KEYBOARD_NUMPAD_2021),
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },

View File

@ -81,6 +81,7 @@ struct hid_report *hid_register_report(struct hid_device *device,
report_enum->report_id_hash[id] = report;
list_add_tail(&report->list, &report_enum->report_list);
INIT_LIST_HEAD(&report->field_entry_list);
return report;
}
@ -101,7 +102,7 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
field = kzalloc((sizeof(struct hid_field) +
usages * sizeof(struct hid_usage) +
usages * sizeof(unsigned)), GFP_KERNEL);
3 * usages * sizeof(unsigned int)), GFP_KERNEL);
if (!field)
return NULL;
@ -109,6 +110,8 @@ static struct hid_field *hid_register_field(struct hid_report *report, unsigned
report->field[field->index] = field;
field->usage = (struct hid_usage *)(field + 1);
field->value = (s32 *)(field->usage + usages);
field->new_value = (s32 *)(field->value + usages);
field->usages_priorities = (s32 *)(field->new_value + usages);
field->report = report;
return field;
@ -656,6 +659,8 @@ static void hid_free_report(struct hid_report *report)
{
unsigned n;
kfree(report->field_entries);
for (n = 0; n < report->maxfield; n++)
kfree(report->field[n]);
kfree(report);
@ -1525,25 +1530,41 @@ static void hid_process_event(struct hid_device *hid, struct hid_field *field,
}
/*
* Analyse a received field, and fetch the data from it. The field
* content is stored for next report processing (we do differential
* reporting to the layer).
* Checks if the given value is valid within this field
*/
static inline int hid_array_value_is_valid(struct hid_field *field,
__s32 value)
{
__s32 min = field->logical_minimum;
static void hid_input_field(struct hid_device *hid, struct hid_field *field,
__u8 *data, int interrupt)
/*
* Value needs to be between logical min and max, and
* (value - min) is used as an index in the usage array.
* This array is of size field->maxusage
*/
return value >= min &&
value <= field->logical_maximum &&
value - min < field->maxusage;
}
/*
* Fetch the field from the data. The field content is stored for next
* report processing (we do differential reporting to the layer).
*/
static void hid_input_fetch_field(struct hid_device *hid,
struct hid_field *field,
__u8 *data)
{
unsigned n;
unsigned count = field->report_count;
unsigned offset = field->report_offset;
unsigned size = field->report_size;
__s32 min = field->logical_minimum;
__s32 max = field->logical_maximum;
__s32 *value;
value = kmalloc_array(count, sizeof(__s32), GFP_ATOMIC);
if (!value)
return;
value = field->new_value;
memset(value, 0, count * sizeof(__s32));
field->ignored = false;
for (n = 0; n < count; n++) {
@ -1554,35 +1575,228 @@ static void hid_input_field(struct hid_device *hid, struct hid_field *field,
/* Ignore report if ErrorRollOver */
if (!(field->flags & HID_MAIN_ITEM_VARIABLE) &&
value[n] >= min && value[n] <= max &&
value[n] - min < field->maxusage &&
field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1)
goto exit;
hid_array_value_is_valid(field, value[n]) &&
field->usage[value[n] - min].hid == HID_UP_KEYBOARD + 1) {
field->ignored = true;
return;
}
}
}
/*
* Process a received variable field.
*/
static void hid_input_var_field(struct hid_device *hid,
struct hid_field *field,
int interrupt)
{
unsigned int count = field->report_count;
__s32 *value = field->new_value;
unsigned int n;
for (n = 0; n < count; n++)
hid_process_event(hid,
field,
&field->usage[n],
value[n],
interrupt);
memcpy(field->value, value, count * sizeof(__s32));
}
/*
* Process a received array field. The field content is stored for
* next report processing (we do differential reporting to the layer).
*/
static void hid_input_array_field(struct hid_device *hid,
struct hid_field *field,
int interrupt)
{
unsigned int n;
unsigned int count = field->report_count;
__s32 min = field->logical_minimum;
__s32 *value;
value = field->new_value;
/* ErrorRollOver */
if (field->ignored)
return;
for (n = 0; n < count; n++) {
if (hid_array_value_is_valid(field, field->value[n]) &&
search(value, field->value[n], count))
hid_process_event(hid,
field,
&field->usage[field->value[n] - min],
0,
interrupt);
if (HID_MAIN_ITEM_VARIABLE & field->flags) {
hid_process_event(hid, field, &field->usage[n], value[n], interrupt);
continue;
}
if (field->value[n] >= min && field->value[n] <= max
&& field->value[n] - min < field->maxusage
&& field->usage[field->value[n] - min].hid
&& search(value, field->value[n], count))
hid_process_event(hid, field, &field->usage[field->value[n] - min], 0, interrupt);
if (value[n] >= min && value[n] <= max
&& value[n] - min < field->maxusage
&& field->usage[value[n] - min].hid
&& search(field->value, value[n], count))
hid_process_event(hid, field, &field->usage[value[n] - min], 1, interrupt);
if (hid_array_value_is_valid(field, value[n]) &&
search(field->value, value[n], count))
hid_process_event(hid,
field,
&field->usage[value[n] - min],
1,
interrupt);
}
memcpy(field->value, value, count * sizeof(__s32));
exit:
kfree(value);
}
/*
* Analyse a received report, and fetch the data from it. The field
* content is stored for next report processing (we do differential
* reporting to the layer).
*/
static void hid_process_report(struct hid_device *hid,
struct hid_report *report,
__u8 *data,
int interrupt)
{
unsigned int a;
struct hid_field_entry *entry;
struct hid_field *field;
/* first retrieve all incoming values in data */
for (a = 0; a < report->maxfield; a++)
hid_input_fetch_field(hid, field = report->field[a], data);
if (!list_empty(&report->field_entry_list)) {
/* INPUT_REPORT, we have a priority list of fields */
list_for_each_entry(entry,
&report->field_entry_list,
list) {
field = entry->field;
if (field->flags & HID_MAIN_ITEM_VARIABLE)
hid_process_event(hid,
field,
&field->usage[entry->index],
field->new_value[entry->index],
interrupt);
else
hid_input_array_field(hid, field, interrupt);
}
/* we need to do the memcpy at the end for var items */
for (a = 0; a < report->maxfield; a++) {
field = report->field[a];
if (field->flags & HID_MAIN_ITEM_VARIABLE)
memcpy(field->value, field->new_value,
field->report_count * sizeof(__s32));
}
} else {
/* FEATURE_REPORT, regular processing */
for (a = 0; a < report->maxfield; a++) {
field = report->field[a];
if (field->flags & HID_MAIN_ITEM_VARIABLE)
hid_input_var_field(hid, field, interrupt);
else
hid_input_array_field(hid, field, interrupt);
}
}
}
/*
* Insert a given usage_index in a field in the list
* of processed usages in the report.
*
* The elements of lower priority score are processed
* first.
*/
static void __hid_insert_field_entry(struct hid_device *hid,
struct hid_report *report,
struct hid_field_entry *entry,
struct hid_field *field,
unsigned int usage_index)
{
struct hid_field_entry *next;
entry->field = field;
entry->index = usage_index;
entry->priority = field->usages_priorities[usage_index];
/* insert the element at the correct position */
list_for_each_entry(next,
&report->field_entry_list,
list) {
/*
* the priority of our element is strictly higher
* than the next one, insert it before
*/
if (entry->priority > next->priority) {
list_add_tail(&entry->list, &next->list);
return;
}
}
/* lowest priority score: insert at the end */
list_add_tail(&entry->list, &report->field_entry_list);
}
static void hid_report_process_ordering(struct hid_device *hid,
struct hid_report *report)
{
struct hid_field *field;
struct hid_field_entry *entries;
unsigned int a, u, usages;
unsigned int count = 0;
/* count the number of individual fields in the report */
for (a = 0; a < report->maxfield; a++) {
field = report->field[a];
if (field->flags & HID_MAIN_ITEM_VARIABLE)
count += field->report_count;
else
count++;
}
/* allocate the memory to process the fields */
entries = kcalloc(count, sizeof(*entries), GFP_KERNEL);
if (!entries)
return;
report->field_entries = entries;
/*
* walk through all fields in the report and
* store them by priority order in report->field_entry_list
*
* - Var elements are individualized (field + usage_index)
* - Arrays are taken as one, we can not chose an order for them
*/
usages = 0;
for (a = 0; a < report->maxfield; a++) {
field = report->field[a];
if (field->flags & HID_MAIN_ITEM_VARIABLE) {
for (u = 0; u < field->report_count; u++) {
__hid_insert_field_entry(hid, report,
&entries[usages],
field, u);
usages++;
}
} else {
__hid_insert_field_entry(hid, report, &entries[usages],
field, 0);
usages++;
}
}
}
static void hid_process_ordering(struct hid_device *hid)
{
struct hid_report *report;
struct hid_report_enum *report_enum = &hid->report_enum[HID_INPUT_REPORT];
list_for_each_entry(report, &report_enum->report_list, list)
hid_report_process_ordering(hid, report);
}
/*
@ -1746,7 +1960,6 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
struct hid_report_enum *report_enum = hid->report_enum + type;
struct hid_report *report;
struct hid_driver *hdrv;
unsigned int a;
u32 rsize, csize = size;
u8 *cdata = data;
int ret = 0;
@ -1782,8 +1995,7 @@ int hid_report_raw_event(struct hid_device *hid, int type, u8 *data, u32 size,
}
if (hid->claimed != HID_CLAIMED_HIDRAW && report->maxfield) {
for (a = 0; a < report->maxfield; a++)
hid_input_field(hid, report->field[a], cdata, interrupt);
hid_process_report(hid, report, cdata, interrupt);
hdrv = hid->driver;
if (hdrv && hdrv->report)
hdrv->report(hid, report);
@ -1970,6 +2182,8 @@ int hid_connect(struct hid_device *hdev, unsigned int connect_mask)
return -ENODEV;
}
hid_process_ordering(hdev);
if ((hdev->claimed & HID_CLAIMED_INPUT) &&
(connect_mask & HID_CONNECT_FF) && hdev->ff_init)
hdev->ff_init(hdev);

View File

@ -58,7 +58,7 @@ static int cbas_ec_query_base(struct cros_ec_device *ec_dev, bool get_state,
struct cros_ec_command *msg;
int ret;
msg = kzalloc(sizeof(*msg) + max(sizeof(u32), sizeof(*params)),
msg = kzalloc(struct_size(msg, data, max(sizeof(u32), sizeof(*params))),
GFP_KERNEL);
if (!msg)
return -ENOMEM;

View File

@ -167,6 +167,14 @@
#define USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI 0x0272
#define USB_DEVICE_ID_APPLE_WELLSPRING9_ISO 0x0273
#define USB_DEVICE_ID_APPLE_WELLSPRING9_JIS 0x0274
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K 0x027a
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132 0x027b
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680 0x027c
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213 0x027d
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K 0x027e
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223 0x027f
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K 0x0280
#define USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F 0x0340
#define USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY 0x030a
#define USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY 0x030b
#define USB_DEVICE_ID_APPLE_IRCONTROL 0x8240
@ -606,7 +614,7 @@
#define USB_VENDOR_ID_HUION 0x256c
#define USB_DEVICE_ID_HUION_TABLET 0x006e
#define USB_DEVICE_ID_HUION_HS64 0x006d
#define USB_DEVICE_ID_HUION_TABLET2 0x006d
#define USB_VENDOR_ID_IBM 0x04b3
#define USB_DEVICE_ID_IBM_SCROLLPOINT_III 0x3100
@ -1030,6 +1038,9 @@
#define I2C_PRODUCT_ID_RAYDIUM_3118 0x3118
#define USB_VENDOR_ID_RAZER 0x1532
#define USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE 0x010D
#define USB_DEVICE_ID_RAZER_BLACKWIDOW 0x010e
#define USB_DEVICE_ID_RAZER_BLACKWIDOW_CLASSIC 0x011b
#define USB_DEVICE_ID_RAZER_BLADE_14 0x011D
#define USB_VENDOR_ID_REALTEK 0x0bda
@ -1092,6 +1103,7 @@
#define USB_VENDOR_ID_SIGMA_MICRO 0x1c4f
#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD 0x0002
#define USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD2 0x0059
#define USB_VENDOR_ID_SIGMATEL 0x066F
#define USB_DEVICE_ID_SIGMATEL_STMP3780 0x3780

View File

@ -48,6 +48,51 @@ static const struct {
__s32 y;
} hid_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
struct usage_priority {
__u32 usage; /* the HID usage associated */
bool global; /* we assume all usages to be slotted,
* unless global
*/
unsigned int slot_overwrite; /* for globals: allows to set the usage
* before or after the slots
*/
};
/*
* hid-input will convert this list into priorities:
* the first element will have the highest priority
* (the length of the following array) and the last
* element the lowest (1).
*
* hid-input will then shift the priority by 8 bits to leave some space
* in case drivers want to interleave other fields.
*
* To accommodate slotted devices, the slot priority is
* defined in the next 8 bits (defined by 0xff - slot).
*
* If drivers want to add fields before those, hid-input will
* leave out the first 8 bits of the priority value.
*
* This still leaves us 65535 individual priority values.
*/
static const struct usage_priority hidinput_usages_priorities[] = {
{ /* Eraser (eraser touching) must always come before tipswitch */
.usage = HID_DG_ERASER,
},
{ /* Invert must always come before In Range */
.usage = HID_DG_INVERT,
},
{ /* Is the tip of the tool touching? */
.usage = HID_DG_TIPSWITCH,
},
{ /* Tip Pressure might emulate tip switch */
.usage = HID_DG_TIPPRESSURE,
},
{ /* In Range needs to come after the other tool states */
.usage = HID_DG_INRANGE,
},
};
#define map_abs(c) hid_map_usage(hidinput, usage, &bit, &max, EV_ABS, (c))
#define map_rel(c) hid_map_usage(hidinput, usage, &bit, &max, EV_REL, (c))
#define map_key(c) hid_map_usage(hidinput, usage, &bit, &max, EV_KEY, (c))
@ -586,11 +631,13 @@ static bool hidinput_field_in_collection(struct hid_device *device, struct hid_f
}
static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_field *field,
struct hid_usage *usage)
struct hid_usage *usage, unsigned int usage_index)
{
struct input_dev *input = hidinput->input;
struct hid_device *device = input_get_drvdata(input);
const struct usage_priority *usage_priority = NULL;
int max = 0, code;
unsigned int i = 0;
unsigned long *bit = NULL;
field->hidinput = hidinput;
@ -608,6 +655,28 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
goto ignore;
}
/* assign a priority based on the static list declared here */
for (i = 0; i < ARRAY_SIZE(hidinput_usages_priorities); i++) {
if (usage->hid == hidinput_usages_priorities[i].usage) {
usage_priority = &hidinput_usages_priorities[i];
field->usages_priorities[usage_index] =
(ARRAY_SIZE(hidinput_usages_priorities) - i) << 8;
break;
}
}
/*
* For slotted devices, we need to also add the slot index
* in the priority.
*/
if (usage_priority && usage_priority->global)
field->usages_priorities[usage_index] |=
usage_priority->slot_overwrite;
else
field->usages_priorities[usage_index] |=
(0xff - field->slot_idx) << 16;
if (device->driver->input_mapping) {
int ret = device->driver->input_mapping(device, hidinput, field,
usage, &bit, &max);
@ -828,10 +897,31 @@ static void hidinput_configure_usage(struct hid_input *hidinput, struct hid_fiel
break;
case 0x32: /* InRange */
switch (field->physical & 0xff) {
case 0x21: map_key(BTN_TOOL_MOUSE); break;
case 0x22: map_key(BTN_TOOL_FINGER); break;
default: map_key(BTN_TOOL_PEN); break;
switch (field->physical) {
case HID_DG_PUCK:
map_key(BTN_TOOL_MOUSE);
break;
case HID_DG_FINGER:
map_key(BTN_TOOL_FINGER);
break;
default:
/*
* If the physical is not given,
* rely on the application.
*/
if (!field->physical) {
switch (field->application) {
case HID_DG_TOUCHSCREEN:
case HID_DG_TOUCHPAD:
map_key_clear(BTN_TOOL_FINGER);
break;
default:
map_key_clear(BTN_TOOL_PEN);
}
} else {
map_key(BTN_TOOL_PEN);
}
break;
}
break;
@ -1318,9 +1408,38 @@ static void hidinput_handle_scroll(struct hid_usage *usage,
input_event(input, EV_REL, usage->code, hi_res);
}
static void hid_report_release_tool(struct hid_report *report, struct input_dev *input,
unsigned int tool)
{
/* if the given tool is not currently reported, ignore */
if (!test_bit(tool, input->key))
return;
/*
* if the given tool was previously set, release it,
* release any TOUCH and send an EV_SYN
*/
input_event(input, EV_KEY, BTN_TOUCH, 0);
input_event(input, EV_KEY, tool, 0);
input_event(input, EV_SYN, SYN_REPORT, 0);
report->tool = 0;
}
static void hid_report_set_tool(struct hid_report *report, struct input_dev *input,
unsigned int new_tool)
{
if (report->tool != new_tool)
hid_report_release_tool(report, input, report->tool);
input_event(input, EV_KEY, new_tool, 1);
report->tool = new_tool;
}
void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct hid_usage *usage, __s32 value)
{
struct input_dev *input;
struct hid_report *report = field->report;
unsigned *quirks = &hid->quirks;
if (!usage->type)
@ -1336,12 +1455,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
input = field->hidinput->input;
if (usage->type == EV_ABS &&
(((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) ||
((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))) {
value = field->logical_maximum - value;
}
if (usage->hat_min < usage->hat_max || usage->hat_dir) {
int hat_dir = usage->hat_dir;
if (!hat_dir)
@ -1352,61 +1465,6 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
return;
}
if (usage->hid == HID_DG_INVERT) {
*quirks = value ? (*quirks | HID_QUIRK_INVERT) : (*quirks & ~HID_QUIRK_INVERT);
return;
}
if (usage->hid == HID_DG_INRANGE) {
if (value) {
input_event(input, usage->type, (*quirks & HID_QUIRK_INVERT) ? BTN_TOOL_RUBBER : usage->code, 1);
return;
}
input_event(input, usage->type, usage->code, 0);
input_event(input, usage->type, BTN_TOOL_RUBBER, 0);
return;
}
if (usage->hid == HID_DG_TIPPRESSURE && (*quirks & HID_QUIRK_NOTOUCH)) {
int a = field->logical_minimum;
int b = field->logical_maximum;
input_event(input, EV_KEY, BTN_TOUCH, value > a + ((b - a) >> 3));
}
if (usage->hid == (HID_UP_PID | 0x83UL)) { /* Simultaneous Effects Max */
dbg_hid("Maximum Effects - %d\n",value);
return;
}
if (usage->hid == (HID_UP_PID | 0x7fUL)) {
dbg_hid("PID Pool Report\n");
return;
}
if ((usage->type == EV_KEY) && (usage->code == 0)) /* Key 0 is "unassigned", not KEY_UNKNOWN */
return;
if ((usage->type == EV_REL) && (usage->code == REL_WHEEL_HI_RES ||
usage->code == REL_HWHEEL_HI_RES)) {
hidinput_handle_scroll(usage, input, value);
return;
}
if ((usage->type == EV_ABS) && (field->flags & HID_MAIN_ITEM_RELATIVE) &&
(usage->code == ABS_VOLUME)) {
int count = abs(value);
int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
int i;
for (i = 0; i < count; i++) {
input_event(input, EV_KEY, direction, 1);
input_sync(input);
input_event(input, EV_KEY, direction, 0);
input_sync(input);
}
return;
}
/*
* Ignore out-of-range values as per HID specification,
* section 5.10 and 6.2.25, when NULL state bit is present.
@ -1419,7 +1477,7 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
* don't specify logical min and max.
*/
if ((field->flags & HID_MAIN_ITEM_VARIABLE) &&
(field->logical_minimum < field->logical_maximum)) {
field->logical_minimum < field->logical_maximum) {
if (field->flags & HID_MAIN_ITEM_NULL_STATE &&
(value < field->logical_minimum ||
value > field->logical_maximum)) {
@ -1431,6 +1489,123 @@ void hidinput_hid_event(struct hid_device *hid, struct hid_field *field, struct
field->logical_maximum);
}
switch (usage->hid) {
case HID_DG_ERASER:
report->tool_active |= !!value;
/*
* if eraser is set, we must enforce BTN_TOOL_RUBBER
* to accommodate for devices not following the spec.
*/
if (value)
hid_report_set_tool(report, input, BTN_TOOL_RUBBER);
else if (report->tool != BTN_TOOL_RUBBER)
/* value is off, tool is not rubber, ignore */
return;
/* let hid-input set BTN_TOUCH */
break;
case HID_DG_INVERT:
report->tool_active |= !!value;
/*
* If invert is set, we store BTN_TOOL_RUBBER.
*/
if (value)
hid_report_set_tool(report, input, BTN_TOOL_RUBBER);
else if (!report->tool_active)
/* tool_active not set means Invert and Eraser are not set */
hid_report_release_tool(report, input, BTN_TOOL_RUBBER);
/* no further processing */
return;
case HID_DG_INRANGE:
report->tool_active |= !!value;
if (report->tool_active) {
/*
* if tool is not set but is marked as active,
* assume ours
*/
if (!report->tool)
hid_report_set_tool(report, input, usage->code);
} else {
hid_report_release_tool(report, input, usage->code);
}
/* reset tool_active for the next event */
report->tool_active = false;
/* no further processing */
return;
case HID_DG_TIPSWITCH:
report->tool_active |= !!value;
/* if tool is set to RUBBER we should ignore the current value */
if (report->tool == BTN_TOOL_RUBBER)
return;
break;
case HID_DG_TIPPRESSURE:
if (*quirks & HID_QUIRK_NOTOUCH) {
int a = field->logical_minimum;
int b = field->logical_maximum;
if (value > a + ((b - a) >> 3)) {
input_event(input, EV_KEY, BTN_TOUCH, 1);
report->tool_active = true;
}
}
break;
case HID_UP_PID | 0x83UL: /* Simultaneous Effects Max */
dbg_hid("Maximum Effects - %d\n",value);
return;
case HID_UP_PID | 0x7fUL:
dbg_hid("PID Pool Report\n");
return;
}
switch (usage->type) {
case EV_KEY:
if (usage->code == 0) /* Key 0 is "unassigned", not KEY_UNKNOWN */
return;
break;
case EV_REL:
if (usage->code == REL_WHEEL_HI_RES ||
usage->code == REL_HWHEEL_HI_RES) {
hidinput_handle_scroll(usage, input, value);
return;
}
break;
case EV_ABS:
if ((field->flags & HID_MAIN_ITEM_RELATIVE) &&
usage->code == ABS_VOLUME) {
int count = abs(value);
int direction = value > 0 ? KEY_VOLUMEUP : KEY_VOLUMEDOWN;
int i;
for (i = 0; i < count; i++) {
input_event(input, EV_KEY, direction, 1);
input_sync(input);
input_event(input, EV_KEY, direction, 0);
input_sync(input);
}
return;
} else if (((*quirks & HID_QUIRK_X_INVERT) && usage->code == ABS_X) ||
((*quirks & HID_QUIRK_Y_INVERT) && usage->code == ABS_Y))
value = field->logical_maximum - value;
break;
}
/*
* Ignore reports for absolute data if the data didn't change. This is
* not only an optimization but also fixes 'dead' key reports. Some
@ -1933,12 +2108,63 @@ static struct hid_input *hidinput_match_application(struct hid_report *report)
static inline void hidinput_configure_usages(struct hid_input *hidinput,
struct hid_report *report)
{
int i, j;
int i, j, k;
int first_field_index = 0;
int slot_collection_index = -1;
int prev_collection_index = -1;
unsigned int slot_idx = 0;
struct hid_field *field;
/*
* First tag all the fields that are part of a slot,
* a slot needs to have one Contact ID in the collection
*/
for (i = 0; i < report->maxfield; i++) {
field = report->field[i];
/* ignore fields without usage */
if (field->maxusage < 1)
continue;
/*
* janitoring when collection_index changes
*/
if (prev_collection_index != field->usage->collection_index) {
prev_collection_index = field->usage->collection_index;
first_field_index = i;
}
/*
* if we already found a Contact ID in the collection,
* tag and continue to the next.
*/
if (slot_collection_index == field->usage->collection_index) {
field->slot_idx = slot_idx;
continue;
}
/* check if the current field has Contact ID */
for (j = 0; j < field->maxusage; j++) {
if (field->usage[j].hid == HID_DG_CONTACTID) {
slot_collection_index = field->usage->collection_index;
slot_idx++;
/*
* mark all previous fields and this one in the
* current collection to be slotted.
*/
for (k = first_field_index; k <= i; k++)
report->field[k]->slot_idx = slot_idx;
break;
}
}
}
for (i = 0; i < report->maxfield; i++)
for (j = 0; j < report->field[i]->maxusage; j++)
hidinput_configure_usage(hidinput, report->field[i],
report->field[i]->usage + j);
report->field[i]->usage + j,
j);
}
/*

View File

@ -295,6 +295,14 @@ static const struct hid_device_id hid_have_special_driver[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ANSI) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_ISO) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_2009_JIS) },
@ -930,6 +938,14 @@ static const struct hid_device_id hid_mouse_ignore_list[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ANSI) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_ISO) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING9_JIS) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J140K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY) },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY) },
{ }

125
drivers/hid/hid-razer.c Normal file
View File

@ -0,0 +1,125 @@
// SPDX-License-Identifier: GPL-2.0+
/*
* HID driver for gaming keys on Razer Blackwidow gaming keyboards
* Macro Key Keycodes: M1 = 191, M2 = 192, M3 = 193, M4 = 194, M5 = 195
*
* Copyright (c) 2021 Jelle van der Waa <jvanderwaa@redhat.com>
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include <linux/random.h>
#include <linux/sched.h>
#include <linux/usb.h>
#include <linux/wait.h>
#include "hid-ids.h"
#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
#define RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE 91
static bool macro_key_remapping = 1;
module_param(macro_key_remapping, bool, 0644);
MODULE_PARM_DESC(macro_key_remapping, " on (Y) off (N)");
static unsigned char blackwidow_init[RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE] = {
0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x04,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x04, 0x00
};
static int razer_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field,
struct hid_usage *usage, unsigned long **bit, int *max)
{
if (!macro_key_remapping)
return 0;
if ((usage->hid & HID_UP_KEYBOARD) != HID_UP_KEYBOARD)
return 0;
switch (usage->hid & ~HID_UP_KEYBOARD) {
case 0x68:
map_key_clear(KEY_MACRO1);
return 1;
case 0x69:
map_key_clear(KEY_MACRO2);
return 1;
case 0x6a:
map_key_clear(KEY_MACRO3);
return 1;
case 0x6b:
map_key_clear(KEY_MACRO4);
return 1;
case 0x6c:
map_key_clear(KEY_MACRO5);
return 1;
}
return 0;
}
static int razer_probe(struct hid_device *hdev, const struct hid_device_id *id)
{
char *buf;
int ret = 0;
ret = hid_parse(hdev);
if (ret)
return ret;
/*
* Only send the enable macro keys command for the third device
* identified as mouse input.
*/
if (hdev->type == HID_TYPE_USBMOUSE) {
buf = kmemdup(blackwidow_init, RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE, GFP_KERNEL);
if (buf == NULL)
return -ENOMEM;
ret = hid_hw_raw_request(hdev, 0, buf, RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE,
HID_FEATURE_REPORT, HID_REQ_SET_REPORT);
if (ret != RAZER_BLACKWIDOW_TRANSFER_BUF_SIZE)
hid_err(hdev, "failed to enable macro keys: %d\n", ret);
kfree(buf);
}
return hid_hw_start(hdev, HID_CONNECT_DEFAULT);
}
static const struct hid_device_id razer_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_RAZER,
USB_DEVICE_ID_RAZER_BLACKWIDOW) },
{ HID_USB_DEVICE(USB_VENDOR_ID_RAZER,
USB_DEVICE_ID_RAZER_BLACKWIDOW_CLASSIC) },
{ HID_USB_DEVICE(USB_VENDOR_ID_RAZER,
USB_DEVICE_ID_RAZER_BLACKWIDOW_ULTIMATE) },
{ }
};
MODULE_DEVICE_TABLE(hid, razer_devices);
static struct hid_driver razer_driver = {
.name = "razer",
.id_table = razer_devices,
.input_mapping = razer_input_mapping,
.probe = razer_probe,
};
module_hid_driver(razer_driver);
MODULE_AUTHOR("Jelle van der Waa <jvanderwaa@redhat.com>");
MODULE_LICENSE("GPL");

View File

@ -0,0 +1,130 @@
// SPDX-License-Identifier: GPL-2.0-or-later
/*
* HID driver for SiGma Micro-based keyboards
*
* Copyright (c) 2016 Kinglong Mee
* Copyright (c) 2021 Desmond Lim
*/
#include <linux/device.h>
#include <linux/hid.h>
#include <linux/module.h>
#include "hid-ids.h"
static const __u8 sm_0059_rdesc[] = {
0x05, 0x0c, /* Usage Page (Consumer Devices) 0 */
0x09, 0x01, /* Usage (Consumer Control) 2 */
0xa1, 0x01, /* Collection (Application) 4 */
0x85, 0x01, /* Report ID (1) 6 */
0x19, 0x00, /* Usage Minimum (0) 8 */
0x2a, 0x3c, 0x02, /* Usage Maximum (572) 10 */
0x15, 0x00, /* Logical Minimum (0) 13 */
0x26, 0x3c, 0x02, /* Logical Maximum (572) 15 */
0x95, 0x01, /* Report Count (1) 18 */
0x75, 0x10, /* Report Size (16) 20 */
0x81, 0x00, /* Input (Data,Arr,Abs) 22 */
0xc0, /* End Collection 24 */
0x05, 0x01, /* Usage Page (Generic Desktop) 25 */
0x09, 0x80, /* Usage (System Control) 27 */
0xa1, 0x01, /* Collection (Application) 29 */
0x85, 0x02, /* Report ID (2) 31 */
0x19, 0x81, /* Usage Minimum (129) 33 */
0x29, 0x83, /* Usage Maximum (131) 35 */
0x25, 0x01, /* Logical Maximum (1) 37 */
0x75, 0x01, /* Report Size (1) 39 */
0x95, 0x03, /* Report Count (3) 41 */
0x81, 0x02, /* Input (Data,Var,Abs) 43 */
0x95, 0x05, /* Report Count (5) 45 */
0x81, 0x01, /* Input (Cnst,Arr,Abs) 47 */
0xc0, /* End Collection 49 */
0x06, 0x00, 0xff, /* Usage Page (Vendor Defined Page 1) 50 */
0x09, 0x01, /* Usage (Vendor Usage 1) 53 */
0xa1, 0x01, /* Collection (Application) 55 */
0x85, 0x03, /* Report ID (3) 57 */
0x1a, 0xf1, 0x00, /* Usage Minimum (241) 59 */
0x2a, 0xf8, 0x00, /* Usage Maximum (248) 62 */
0x15, 0x00, /* Logical Minimum (0) 65 */
0x25, 0x01, /* Logical Maximum (1) 67 */
0x75, 0x01, /* Report Size (1) 69 */
0x95, 0x08, /* Report Count (8) 71 */
0x81, 0x02, /* Input (Data,Var,Abs) 73 */
0xc0, /* End Collection 75 */
0x05, 0x01, /* Usage Page (Generic Desktop) 76 */
0x09, 0x06, /* Usage (Keyboard) 78 */
0xa1, 0x01, /* Collection (Application) 80 */
0x85, 0x04, /* Report ID (4) 82 */
0x05, 0x07, /* Usage Page (Keyboard) 84 */
0x19, 0xe0, /* Usage Minimum (224) 86 */
0x29, 0xe7, /* Usage Maximum (231) 88 */
0x15, 0x00, /* Logical Minimum (0) 90 */
0x25, 0x01, /* Logical Maximum (1) 92 */
0x75, 0x01, /* Report Size (1) 94 */
0x95, 0x08, /* Report Count (8) 96 */
0x81, 0x00, /* Input (Data,Arr,Abs) 98 */
0x95, 0x30, /* Report Count (48) 100 */
0x75, 0x01, /* Report Size (1) 102 */
0x15, 0x00, /* Logical Minimum (0) 104 */
0x25, 0x01, /* Logical Maximum (1) 106 */
0x05, 0x07, /* Usage Page (Keyboard) 108 */
0x19, 0x00, /* Usage Minimum (0) 110 */
0x29, 0x2f, /* Usage Maximum (47) 112 */
0x81, 0x02, /* Input (Data,Var,Abs) 114 */
0xc0, /* End Collection 116 */
0x05, 0x01, /* Usage Page (Generic Desktop) 117 */
0x09, 0x06, /* Usage (Keyboard) 119 */
0xa1, 0x01, /* Collection (Application) 121 */
0x85, 0x05, /* Report ID (5) 123 */
0x95, 0x38, /* Report Count (56) 125 */
0x75, 0x01, /* Report Size (1) 127 */
0x15, 0x00, /* Logical Minimum (0) 129 */
0x25, 0x01, /* Logical Maximum (1) 131 */
0x05, 0x07, /* Usage Page (Keyboard) 133 */
0x19, 0x30, /* Usage Minimum (48) 135 */
0x29, 0x67, /* Usage Maximum (103) 137 */
0x81, 0x02, /* Input (Data,Var,Abs) 139 */
0xc0, /* End Collection 141 */
0x05, 0x01, /* Usage Page (Generic Desktop) 142 */
0x09, 0x06, /* Usage (Keyboard) 144 */
0xa1, 0x01, /* Collection (Application) 146 */
0x85, 0x06, /* Report ID (6) 148 */
0x95, 0x38, /* Report Count (56) 150 */
0x75, 0x01, /* Report Size (1) 152 */
0x15, 0x00, /* Logical Minimum (0) 154 */
0x25, 0x01, /* Logical Maximum (1) 156 */
0x05, 0x07, /* Usage Page (Keyboard) 158 */
0x19, 0x68, /* Usage Minimum (104) 160 */
0x29, 0x9f, /* Usage Maximum (159) 162 */
0x81, 0x02, /* Input (Data,Var,Abs) 164 */
0xc0, /* End Collection 166 */
};
static __u8 *sm_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize == sizeof(sm_0059_rdesc) &&
!memcmp(sm_0059_rdesc, rdesc, *rsize)) {
hid_info(hdev, "Fixing up SiGma Micro report descriptor\n");
rdesc[99] = 0x02;
}
return rdesc;
}
static const struct hid_device_id sm_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SIGMA_MICRO,
USB_DEVICE_ID_SIGMA_MICRO_KEYBOARD2) },
{ }
};
MODULE_DEVICE_TABLE(hid, sm_devices);
static struct hid_driver sm_driver = {
.name = "sigmamicro",
.id_table = sm_devices,
.report_fixup = sm_report_fixup,
};
module_hid_driver(sm_driver);
MODULE_AUTHOR("Kinglong Mee <kinglongmee@gmail.com>");
MODULE_AUTHOR("Desmond Lim <peckishrine@gmail.com>");
MODULE_DESCRIPTION("SiGma Micro HID driver");
MODULE_LICENSE("GPL");

View File

@ -81,24 +81,6 @@ static __u8 *uclogic_report_fixup(struct hid_device *hdev, __u8 *rdesc,
return rdesc;
}
static int uclogic_input_mapping(struct hid_device *hdev,
struct hid_input *hi,
struct hid_field *field,
struct hid_usage *usage,
unsigned long **bit,
int *max)
{
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
struct uclogic_params *params = &drvdata->params;
/* discard the unused pen interface */
if (params->pen_unused && (field->application == HID_DG_PEN))
return -1;
/* let hid-core decide what to do */
return 0;
}
static int uclogic_input_configured(struct hid_device *hdev,
struct hid_input *hi)
{
@ -246,100 +228,171 @@ static int uclogic_resume(struct hid_device *hdev)
}
#endif
/**
* uclogic_raw_event_pen - handle raw pen events (pen HID reports).
*
* @drvdata: Driver data.
* @data: Report data buffer, can be modified.
* @size: Report data size, bytes.
*
* Returns:
* Negative value on error (stops event delivery), zero for success.
*/
static int uclogic_raw_event_pen(struct uclogic_drvdata *drvdata,
u8 *data, int size)
{
struct uclogic_params_pen *pen = &drvdata->params.pen;
WARN_ON(drvdata == NULL);
WARN_ON(data == NULL && size != 0);
/* If in-range reports are inverted */
if (pen->inrange ==
UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
/* Invert the in-range bit */
data[1] ^= 0x40;
}
/*
* If report contains fragmented high-resolution pen
* coordinates
*/
if (size >= 10 && pen->fragmented_hires) {
u8 pressure_low_byte;
u8 pressure_high_byte;
/* Lift pressure bytes */
pressure_low_byte = data[6];
pressure_high_byte = data[7];
/*
* Move Y coord to make space for high-order X
* coord byte
*/
data[6] = data[5];
data[5] = data[4];
/* Move high-order X coord byte */
data[4] = data[8];
/* Move high-order Y coord byte */
data[7] = data[9];
/* Place pressure bytes */
data[8] = pressure_low_byte;
data[9] = pressure_high_byte;
}
/* If we need to emulate in-range detection */
if (pen->inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
/* Set in-range bit */
data[1] |= 0x40;
/* (Re-)start in-range timeout */
mod_timer(&drvdata->inrange_timer,
jiffies + msecs_to_jiffies(100));
}
/* If we report tilt and Y direction is flipped */
if (size >= 12 && pen->tilt_y_flipped)
data[11] = -data[11];
return 0;
}
/**
* uclogic_raw_event_frame - handle raw frame events (frame HID reports).
*
* @drvdata: Driver data.
* @frame: The parameters of the frame controls to handle.
* @data: Report data buffer, can be modified.
* @size: Report data size, bytes.
*
* Returns:
* Negative value on error (stops event delivery), zero for success.
*/
static int uclogic_raw_event_frame(
struct uclogic_drvdata *drvdata,
const struct uclogic_params_frame *frame,
u8 *data, int size)
{
WARN_ON(drvdata == NULL);
WARN_ON(data == NULL && size != 0);
/* If need to, and can, set pad device ID for Wacom drivers */
if (frame->dev_id_byte > 0 && frame->dev_id_byte < size) {
data[frame->dev_id_byte] = 0xf;
}
/* If need to, and can, read rotary encoder state change */
if (frame->re_lsb > 0 && frame->re_lsb / 8 < size) {
unsigned int byte = frame->re_lsb / 8;
unsigned int bit = frame->re_lsb % 8;
u8 change;
u8 prev_state = drvdata->re_state;
/* Read Gray-coded state */
u8 state = (data[byte] >> bit) & 0x3;
/* Encode state change into 2-bit signed integer */
if ((prev_state == 1 && state == 0) ||
(prev_state == 2 && state == 3)) {
change = 1;
} else if ((prev_state == 2 && state == 0) ||
(prev_state == 1 && state == 3)) {
change = 3;
} else {
change = 0;
}
/* Write change */
data[byte] = (data[byte] & ~((u8)3 << bit)) |
(change << bit);
/* Remember state */
drvdata->re_state = state;
}
return 0;
}
static int uclogic_raw_event(struct hid_device *hdev,
struct hid_report *report,
u8 *data, int size)
{
unsigned int report_id = report->id;
struct uclogic_drvdata *drvdata = hid_get_drvdata(hdev);
struct uclogic_params *params = &drvdata->params;
struct uclogic_params_pen_subreport *subreport;
struct uclogic_params_pen_subreport *subreport_list_end;
size_t i;
/* Tweak pen reports, if necessary */
if (!params->pen_unused &&
(report->type == HID_INPUT_REPORT) &&
(report->id == params->pen.id) &&
(size >= 2)) {
/* If it's the "virtual" frame controls report */
if (params->frame.id != 0 &&
data[1] & params->pen_frame_flag) {
/* Change to virtual frame controls report ID */
data[0] = params->frame.id;
return 0;
}
/* If in-range reports are inverted */
if (params->pen.inrange ==
UCLOGIC_PARAMS_PEN_INRANGE_INVERTED) {
/* Invert the in-range bit */
data[1] ^= 0x40;
}
/*
* If report contains fragmented high-resolution pen
* coordinates
*/
if (size >= 10 && params->pen.fragmented_hires) {
u8 pressure_low_byte;
u8 pressure_high_byte;
/* Do not handle anything but input reports */
if (report->type != HID_INPUT_REPORT)
return 0;
/* Lift pressure bytes */
pressure_low_byte = data[6];
pressure_high_byte = data[7];
/*
* Move Y coord to make space for high-order X
* coord byte
*/
data[6] = data[5];
data[5] = data[4];
/* Move high-order X coord byte */
data[4] = data[8];
/* Move high-order Y coord byte */
data[7] = data[9];
/* Place pressure bytes */
data[8] = pressure_low_byte;
data[9] = pressure_high_byte;
}
/* If we need to emulate in-range detection */
if (params->pen.inrange == UCLOGIC_PARAMS_PEN_INRANGE_NONE) {
/* Set in-range bit */
data[1] |= 0x40;
/* (Re-)start in-range timeout */
mod_timer(&drvdata->inrange_timer,
jiffies + msecs_to_jiffies(100));
}
}
/* Tweak frame control reports, if necessary */
if ((report->type == HID_INPUT_REPORT) &&
(report->id == params->frame.id)) {
/* If need to, and can, set pad device ID for Wacom drivers */
if (params->frame.dev_id_byte > 0 &&
params->frame.dev_id_byte < size) {
data[params->frame.dev_id_byte] = 0xf;
}
/* If need to, and can, read rotary encoder state change */
if (params->frame.re_lsb > 0 &&
params->frame.re_lsb / 8 < size) {
unsigned int byte = params->frame.re_lsb / 8;
unsigned int bit = params->frame.re_lsb % 8;
u8 change;
u8 prev_state = drvdata->re_state;
/* Read Gray-coded state */
u8 state = (data[byte] >> bit) & 0x3;
/* Encode state change into 2-bit signed integer */
if ((prev_state == 1 && state == 0) ||
(prev_state == 2 && state == 3)) {
change = 1;
} else if ((prev_state == 2 && state == 0) ||
(prev_state == 1 && state == 3)) {
change = 3;
} else {
change = 0;
while (true) {
/* Tweak pen reports, if necessary */
if ((report_id == params->pen.id) && (size >= 2)) {
subreport_list_end =
params->pen.subreport_list +
ARRAY_SIZE(params->pen.subreport_list);
/* Try to match a subreport */
for (subreport = params->pen.subreport_list;
subreport < subreport_list_end; subreport++) {
if (subreport->value != 0 &&
subreport->value == data[1]) {
break;
}
}
/* If a subreport matched */
if (subreport < subreport_list_end) {
/* Change to subreport ID, and restart */
report_id = data[0] = subreport->id;
continue;
} else {
return uclogic_raw_event_pen(drvdata, data, size);
}
/* Write change */
data[byte] = (data[byte] & ~((u8)3 << bit)) |
(change << bit);
/* Remember state */
drvdata->re_state = state;
}
/* Tweak frame control reports, if necessary */
for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
if (report_id == params->frame_list[i].id) {
return uclogic_raw_event_frame(
drvdata, &params->frame_list[i],
data, size);
}
}
break;
}
return 0;
@ -373,7 +426,7 @@ static const struct hid_device_id uclogic_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_HS64) },
USB_DEVICE_ID_HUION_TABLET2) },
{ HID_USB_DEVICE(USB_VENDOR_ID_TRUST,
USB_DEVICE_ID_TRUST_PANORA_TABLET) },
{ HID_USB_DEVICE(USB_VENDOR_ID_UCLOGIC,
@ -415,7 +468,6 @@ static struct hid_driver uclogic_driver = {
.remove = uclogic_remove,
.report_fixup = uclogic_report_fixup,
.raw_event = uclogic_raw_event,
.input_mapping = uclogic_input_mapping,
.input_configured = uclogic_input_configured,
#ifdef CONFIG_PM
.resume = uclogic_resume,

View File

@ -207,8 +207,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
* Generate pen report descriptor
*/
desc_ptr = uclogic_rdesc_template_apply(
uclogic_rdesc_pen_v1_template_arr,
uclogic_rdesc_pen_v1_template_size,
uclogic_rdesc_v1_pen_template_arr,
uclogic_rdesc_v1_pen_template_size,
desc_params, ARRAY_SIZE(desc_params));
if (desc_ptr == NULL) {
rc = -ENOMEM;
@ -221,8 +221,8 @@ static int uclogic_params_pen_init_v1(struct uclogic_params_pen *pen,
memset(pen, 0, sizeof(*pen));
pen->desc_ptr = desc_ptr;
desc_ptr = NULL;
pen->desc_size = uclogic_rdesc_pen_v1_template_size;
pen->id = UCLOGIC_RDESC_PEN_V1_ID;
pen->desc_size = uclogic_rdesc_v1_pen_template_size;
pen->id = UCLOGIC_RDESC_V1_PEN_ID;
pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_INVERTED;
found = true;
finish:
@ -351,8 +351,8 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
* Generate pen report descriptor
*/
desc_ptr = uclogic_rdesc_template_apply(
uclogic_rdesc_pen_v2_template_arr,
uclogic_rdesc_pen_v2_template_size,
uclogic_rdesc_v2_pen_template_arr,
uclogic_rdesc_v2_pen_template_size,
desc_params, ARRAY_SIZE(desc_params));
if (desc_ptr == NULL) {
rc = -ENOMEM;
@ -365,10 +365,11 @@ static int uclogic_params_pen_init_v2(struct uclogic_params_pen *pen,
memset(pen, 0, sizeof(*pen));
pen->desc_ptr = desc_ptr;
desc_ptr = NULL;
pen->desc_size = uclogic_rdesc_pen_v2_template_size;
pen->id = UCLOGIC_RDESC_PEN_V2_ID;
pen->desc_size = uclogic_rdesc_v2_pen_template_size;
pen->id = UCLOGIC_RDESC_V2_PEN_ID;
pen->inrange = UCLOGIC_PARAMS_PEN_INRANGE_NONE;
pen->fragmented_hires = true;
pen->tilt_y_flipped = true;
found = true;
finish:
*pfound = found;
@ -430,8 +431,8 @@ static int uclogic_params_frame_init_with_desc(
}
/**
* uclogic_params_frame_init_v1_buttonpad() - initialize abstract buttonpad
* on a v1 tablet interface.
* uclogic_params_frame_init_v1() - initialize v1 tablet interface frame
* controls.
*
* @frame: Pointer to the frame parameters to initialize (to be cleaned
* up with uclogic_params_frame_cleanup()). Not modified in case
@ -445,8 +446,7 @@ static int uclogic_params_frame_init_with_desc(
* Returns:
* Zero, if successful. A negative errno code on error.
*/
static int uclogic_params_frame_init_v1_buttonpad(
struct uclogic_params_frame *frame,
static int uclogic_params_frame_init_v1(struct uclogic_params_frame *frame,
bool *pfound,
struct hid_device *hdev)
{
@ -487,9 +487,9 @@ static int uclogic_params_frame_init_v1_buttonpad(
hid_dbg(hdev, "generic buttons enabled\n");
rc = uclogic_params_frame_init_with_desc(
frame,
uclogic_rdesc_buttonpad_v1_arr,
uclogic_rdesc_buttonpad_v1_size,
UCLOGIC_RDESC_BUTTONPAD_V1_ID);
uclogic_rdesc_v1_frame_arr,
uclogic_rdesc_v1_frame_size,
UCLOGIC_RDESC_V1_FRAME_ID);
if (rc != 0)
goto cleanup;
found = true;
@ -512,10 +512,12 @@ cleanup:
void uclogic_params_cleanup(struct uclogic_params *params)
{
if (!params->invalid) {
size_t i;
kfree(params->desc_ptr);
if (!params->pen_unused)
uclogic_params_pen_cleanup(&params->pen);
uclogic_params_frame_cleanup(&params->frame);
uclogic_params_pen_cleanup(&params->pen);
for (i = 0; i < ARRAY_SIZE(params->frame_list); i++)
uclogic_params_frame_cleanup(&params->frame_list[i]);
memset(params, 0, sizeof(*params));
}
}
@ -543,60 +545,53 @@ int uclogic_params_get_desc(const struct uclogic_params *params,
__u8 **pdesc,
unsigned int *psize)
{
bool common_present;
bool pen_present;
bool frame_present;
unsigned int size;
int rc = -ENOMEM;
bool present = false;
unsigned int size = 0;
__u8 *desc = NULL;
size_t i;
/* Check arguments */
if (params == NULL || pdesc == NULL || psize == NULL)
return -EINVAL;
size = 0;
/* Concatenate descriptors */
#define ADD_DESC(_desc_ptr, _desc_size) \
do { \
unsigned int new_size; \
__u8 *new_desc; \
if ((_desc_ptr) == NULL) { \
break; \
} \
new_size = size + (_desc_size); \
new_desc = krealloc(desc, new_size, GFP_KERNEL); \
if (new_desc == NULL) { \
goto cleanup; \
} \
memcpy(new_desc + size, (_desc_ptr), (_desc_size)); \
desc = new_desc; \
size = new_size; \
present = true; \
} while (0)
common_present = (params->desc_ptr != NULL);
pen_present = (!params->pen_unused && params->pen.desc_ptr != NULL);
frame_present = (params->frame.desc_ptr != NULL);
if (common_present)
size += params->desc_size;
if (pen_present)
size += params->pen.desc_size;
if (frame_present)
size += params->frame.desc_size;
if (common_present || pen_present || frame_present) {
__u8 *p;
desc = kmalloc(size, GFP_KERNEL);
if (desc == NULL)
return -ENOMEM;
p = desc;
if (common_present) {
memcpy(p, params->desc_ptr,
params->desc_size);
p += params->desc_size;
}
if (pen_present) {
memcpy(p, params->pen.desc_ptr,
params->pen.desc_size);
p += params->pen.desc_size;
}
if (frame_present) {
memcpy(p, params->frame.desc_ptr,
params->frame.desc_size);
p += params->frame.desc_size;
}
WARN_ON(p != desc + size);
*psize = size;
ADD_DESC(params->desc_ptr, params->desc_size);
ADD_DESC(params->pen.desc_ptr, params->pen.desc_size);
for (i = 0; i < ARRAY_SIZE(params->frame_list); i++) {
ADD_DESC(params->frame_list[i].desc_ptr,
params->frame_list[i].desc_size);
}
*pdesc = desc;
return 0;
#undef ADD_DESC
if (present) {
*pdesc = desc;
*psize = size;
desc = NULL;
}
rc = 0;
cleanup:
kfree(desc);
return rc;
}
/**
@ -679,21 +674,6 @@ cleanup:
return rc;
}
/**
* uclogic_params_init_with_pen_unused() - initialize tablet interface
* parameters preserving original reports and generic HID processing, but
* disabling pen usage.
*
* @params: Parameters to initialize (to be cleaned with
* uclogic_params_cleanup()). Not modified in case of
* error. Cannot be NULL.
*/
static void uclogic_params_init_with_pen_unused(struct uclogic_params *params)
{
memset(params, 0, sizeof(*params));
params->pen_unused = true;
}
/**
* uclogic_params_huion_init() - initialize a Huion tablet interface and discover
* its parameters.
@ -733,8 +713,7 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
/* If it's not a pen interface */
if (bInterfaceNumber != 0) {
/* TODO: Consider marking the interface invalid */
uclogic_params_init_with_pen_unused(&p);
uclogic_params_init_invalid(&p);
goto output;
}
@ -766,20 +745,22 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
goto cleanup;
} else if (found) {
hid_dbg(hdev, "pen v2 parameters found\n");
/* Create v2 buttonpad parameters */
/* Create v2 frame parameters */
rc = uclogic_params_frame_init_with_desc(
&p.frame,
uclogic_rdesc_buttonpad_v2_arr,
uclogic_rdesc_buttonpad_v2_size,
UCLOGIC_RDESC_BUTTONPAD_V2_ID);
&p.frame_list[0],
uclogic_rdesc_v2_frame_arr,
uclogic_rdesc_v2_frame_size,
UCLOGIC_RDESC_V2_FRAME_ID);
if (rc != 0) {
hid_err(hdev,
"failed creating v2 buttonpad parameters: %d\n",
"failed creating v2 frame parameters: %d\n",
rc);
goto cleanup;
}
/* Set bitmask marking frame reports in pen reports */
p.pen_frame_flag = 0x20;
/* Link frame button subreports from pen reports */
p.pen.subreport_list[0].value = 0xe0;
p.pen.subreport_list[0].id =
UCLOGIC_RDESC_V2_FRAME_ID;
goto output;
}
hid_dbg(hdev, "pen v2 parameters not found\n");
@ -793,19 +774,20 @@ static int uclogic_params_huion_init(struct uclogic_params *params,
goto cleanup;
} else if (found) {
hid_dbg(hdev, "pen v1 parameters found\n");
/* Try to probe v1 buttonpad */
rc = uclogic_params_frame_init_v1_buttonpad(
&p.frame,
&found, hdev);
/* Try to probe v1 frame */
rc = uclogic_params_frame_init_v1(&p.frame_list[0],
&found, hdev);
if (rc != 0) {
hid_err(hdev, "v1 buttonpad probing failed: %d\n", rc);
hid_err(hdev, "v1 frame probing failed: %d\n", rc);
goto cleanup;
}
hid_dbg(hdev, "buttonpad v1 parameters%s found\n",
hid_dbg(hdev, "frame v1 parameters%s found\n",
(found ? "" : " not"));
if (found) {
/* Set bitmask marking frame reports */
p.pen_frame_flag = 0x20;
/* Link frame button subreports from pen reports */
p.pen.subreport_list[0].value = 0xe0;
p.pen.subreport_list[0].id =
UCLOGIC_RDESC_V1_FRAME_ID;
}
goto output;
}
@ -992,7 +974,7 @@ int uclogic_params_init(struct uclogic_params *params,
case VID_PID(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_TABLET):
case VID_PID(USB_VENDOR_ID_HUION,
USB_DEVICE_ID_HUION_HS64):
USB_DEVICE_ID_HUION_TABLET2):
case VID_PID(USB_VENDOR_ID_UCLOGIC,
USB_DEVICE_ID_HUION_TABLET):
case VID_PID(USB_VENDOR_ID_UCLOGIC,
@ -1032,8 +1014,7 @@ int uclogic_params_init(struct uclogic_params *params,
uclogic_params_init_invalid(&p);
}
} else {
/* TODO: Consider marking the interface invalid */
uclogic_params_init_with_pen_unused(&p);
uclogic_params_init_invalid(&p);
}
break;
case VID_PID(USB_VENDOR_ID_UGEE,
@ -1048,15 +1029,14 @@ int uclogic_params_init(struct uclogic_params *params,
}
/* Initialize frame parameters */
rc = uclogic_params_frame_init_with_desc(
&p.frame,
&p.frame_list[0],
uclogic_rdesc_xppen_deco01_frame_arr,
uclogic_rdesc_xppen_deco01_frame_size,
0);
if (rc != 0)
goto cleanup;
} else {
/* TODO: Consider marking the interface invalid */
uclogic_params_init_with_pen_unused(&p);
uclogic_params_init_invalid(&p);
}
break;
case VID_PID(USB_VENDOR_ID_TRUST,
@ -1075,19 +1055,19 @@ int uclogic_params_init(struct uclogic_params *params,
goto cleanup;
} else if (found) {
rc = uclogic_params_frame_init_with_desc(
&p.frame,
&p.frame_list[0],
uclogic_rdesc_ugee_g5_frame_arr,
uclogic_rdesc_ugee_g5_frame_size,
UCLOGIC_RDESC_UGEE_G5_FRAME_ID);
if (rc != 0) {
hid_err(hdev,
"failed creating buttonpad parameters: %d\n",
"failed creating frame parameters: %d\n",
rc);
goto cleanup;
}
p.frame.re_lsb =
p.frame_list[0].re_lsb =
UCLOGIC_RDESC_UGEE_G5_FRAME_RE_LSB;
p.frame.dev_id_byte =
p.frame_list[0].dev_id_byte =
UCLOGIC_RDESC_UGEE_G5_FRAME_DEV_ID_BYTE;
} else {
hid_warn(hdev, "pen parameters not found");
@ -1109,13 +1089,13 @@ int uclogic_params_init(struct uclogic_params *params,
goto cleanup;
} else if (found) {
rc = uclogic_params_frame_init_with_desc(
&p.frame,
uclogic_rdesc_ugee_ex07_buttonpad_arr,
uclogic_rdesc_ugee_ex07_buttonpad_size,
&p.frame_list[0],
uclogic_rdesc_ugee_ex07_frame_arr,
uclogic_rdesc_ugee_ex07_frame_size,
0);
if (rc != 0) {
hid_err(hdev,
"failed creating buttonpad parameters: %d\n",
"failed creating frame parameters: %d\n",
rc);
goto cleanup;
}

View File

@ -33,6 +33,25 @@ enum uclogic_params_pen_inrange {
extern const char *uclogic_params_pen_inrange_to_str(
enum uclogic_params_pen_inrange inrange);
/*
* Pen report's subreport data.
*/
struct uclogic_params_pen_subreport {
/*
* The value of the second byte of the pen report indicating this
* subreport. If zero, the subreport should be considered invalid and
* not matched.
*/
__u8 value;
/*
* The ID to be assigned to the report, if the second byte of the pen
* report is equal to "value". Only valid if "value" is not zero.
*/
__u8 id;
};
/*
* Tablet interface's pen input parameters.
*
@ -54,6 +73,8 @@ struct uclogic_params_pen {
unsigned int desc_size;
/* Report ID, if reports should be tweaked, zero if not */
unsigned int id;
/* The list of subreports */
struct uclogic_params_pen_subreport subreport_list[1];
/* Type of in-range reporting, only valid if "id" is not zero */
enum uclogic_params_pen_inrange inrange;
/*
@ -62,6 +83,12 @@ struct uclogic_params_pen {
* Only valid if "id" is not zero.
*/
bool fragmented_hires;
/*
* True if the pen reports tilt in bytes at offset 10 (X) and 11 (Y),
* and the Y tilt direction is flipped.
* Only valid if "id" is not zero.
*/
bool tilt_y_flipped;
};
/*
@ -132,28 +159,16 @@ struct uclogic_params {
* Only valid, if "desc_ptr" is not NULL.
*/
unsigned int desc_size;
/*
* True, if pen usage in report descriptor is invalid, when present.
* Only valid, if "invalid" is false.
*/
bool pen_unused;
/*
* Pen parameters and optional report descriptor part.
* Only valid if "pen_unused" is valid and false.
* Only valid, if "invalid" is false.
*/
struct uclogic_params_pen pen;
/*
* Frame control parameters and optional report descriptor part.
* Only valid, if "invalid" is false.
* The list of frame control parameters and optional report descriptor
* parts. Only valid, if "invalid" is false.
*/
struct uclogic_params_frame frame;
/*
* Bitmask matching frame controls "sub-report" flag in the second
* byte of the pen report, or zero if it's not expected.
* Only valid if both "pen" and "frame" are valid, and "frame.id" is
* not zero.
*/
__u8 pen_frame_flag;
struct uclogic_params_frame frame_list[1];
};
/* Initialize a tablet interface and discover its parameters */
@ -162,39 +177,40 @@ extern int uclogic_params_init(struct uclogic_params *params,
/* Tablet interface parameters *printf format string */
#define UCLOGIC_PARAMS_FMT_STR \
".invalid = %s\n" \
".desc_ptr = %p\n" \
".desc_size = %u\n" \
".pen_unused = %s\n" \
".pen.desc_ptr = %p\n" \
".pen.desc_size = %u\n" \
".pen.id = %u\n" \
".pen.inrange = %s\n" \
".pen.fragmented_hires = %s\n" \
".frame.desc_ptr = %p\n" \
".frame.desc_size = %u\n" \
".frame.id = %u\n" \
".frame.re_lsb = %u\n" \
".frame.dev_id_byte = %u\n" \
".pen_frame_flag = 0x%02x\n"
".invalid = %s\n" \
".desc_ptr = %p\n" \
".desc_size = %u\n" \
".pen.desc_ptr = %p\n" \
".pen.desc_size = %u\n" \
".pen.id = %u\n" \
".pen.subreport_list[0] = {0x%02hhx, %hhu}\n" \
".pen.inrange = %s\n" \
".pen.fragmented_hires = %s\n" \
".pen.tilt_y_flipped = %s\n" \
".frame_list[0].desc_ptr = %p\n" \
".frame_list[0].desc_size = %u\n" \
".frame_list[0].id = %u\n" \
".frame_list[0].re_lsb = %u\n" \
".frame_list[0].dev_id_byte = %u\n"
/* Tablet interface parameters *printf format arguments */
#define UCLOGIC_PARAMS_FMT_ARGS(_params) \
((_params)->invalid ? "true" : "false"), \
(_params)->desc_ptr, \
(_params)->desc_size, \
((_params)->pen_unused ? "true" : "false"), \
(_params)->pen.desc_ptr, \
(_params)->pen.desc_size, \
(_params)->pen.id, \
(_params)->pen.subreport_list[0].value, \
(_params)->pen.subreport_list[0].id, \
uclogic_params_pen_inrange_to_str((_params)->pen.inrange), \
((_params)->pen.fragmented_hires ? "true" : "false"), \
(_params)->frame.desc_ptr, \
(_params)->frame.desc_size, \
(_params)->frame.id, \
(_params)->frame.re_lsb, \
(_params)->frame.dev_id_byte, \
(_params)->pen_frame_flag
((_params)->pen.tilt_y_flipped ? "true" : "false"), \
(_params)->frame_list[0].desc_ptr, \
(_params)->frame_list[0].desc_size, \
(_params)->frame_list[0].id, \
(_params)->frame_list[0].re_lsb, \
(_params)->frame_list[0].dev_id_byte
/* Get a replacement report descriptor for a tablet's interface. */
extern int uclogic_params_get_desc(const struct uclogic_params *params,

View File

@ -532,7 +532,7 @@ const size_t uclogic_rdesc_twha60_fixed1_size =
sizeof(uclogic_rdesc_twha60_fixed1_arr);
/* Fixed report descriptor template for (tweaked) v1 pen reports */
const __u8 uclogic_rdesc_pen_v1_template_arr[] = {
const __u8 uclogic_rdesc_v1_pen_template_arr[] = {
0x05, 0x0D, /* Usage Page (Digitizer), */
0x09, 0x02, /* Usage (Pen), */
0xA1, 0x01, /* Collection (Application), */
@ -582,11 +582,11 @@ const __u8 uclogic_rdesc_pen_v1_template_arr[] = {
0xC0 /* End Collection */
};
const size_t uclogic_rdesc_pen_v1_template_size =
sizeof(uclogic_rdesc_pen_v1_template_arr);
const size_t uclogic_rdesc_v1_pen_template_size =
sizeof(uclogic_rdesc_v1_pen_template_arr);
/* Fixed report descriptor template for (tweaked) v2 pen reports */
const __u8 uclogic_rdesc_pen_v2_template_arr[] = {
const __u8 uclogic_rdesc_v2_pen_template_arr[] = {
0x05, 0x0D, /* Usage Page (Digitizer), */
0x09, 0x02, /* Usage (Pen), */
0xA1, 0x01, /* Collection (Application), */
@ -633,25 +633,35 @@ const __u8 uclogic_rdesc_pen_v2_template_arr[] = {
0x27, UCLOGIC_RDESC_PEN_PH(PRESSURE_LM),
/* Logical Maximum (PLACEHOLDER), */
0x81, 0x02, /* Input (Variable), */
0x81, 0x03, /* Input (Constant, Variable), */
0x54, /* Unit Exponent (0), */
0x65, 0x14, /* Unit (Degrees), */
0x35, 0xC4, /* Physical Minimum (-60), */
0x45, 0x3C, /* Physical Maximum (60), */
0x15, 0xC4, /* Logical Minimum (-60), */
0x25, 0x3C, /* Logical Maximum (60), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x02, /* Report Count (2), */
0x09, 0x3D, /* Usage (X Tilt), */
0x09, 0x3E, /* Usage (Y Tilt), */
0x81, 0x02, /* Input (Variable), */
0xC0, /* End Collection, */
0xC0 /* End Collection */
};
const size_t uclogic_rdesc_pen_v2_template_size =
sizeof(uclogic_rdesc_pen_v2_template_arr);
const size_t uclogic_rdesc_v2_pen_template_size =
sizeof(uclogic_rdesc_v2_pen_template_arr);
/*
* Expand to the contents of a generic buttonpad report descriptor.
* Expand to the contents of a generic frame report descriptor.
*
* @_padding: Padding from the end of button bits at bit 44, until
* the end of the report, in bits.
* @_id: The report ID to use.
* @_size: Size of the report to pad to, including report ID, bytes.
*/
#define UCLOGIC_RDESC_BUTTONPAD_BYTES(_padding) \
#define UCLOGIC_RDESC_FRAME_BYTES(_id, _size) \
0x05, 0x01, /* Usage Page (Desktop), */ \
0x09, 0x07, /* Usage (Keypad), */ \
0xA1, 0x01, /* Collection (Application), */ \
0x85, 0xF7, /* Report ID (247), */ \
0x85, (_id), /* Report ID (_id), */ \
0x14, /* Logical Minimum (0), */ \
0x25, 0x01, /* Logical Maximum (1), */ \
0x75, 0x01, /* Report Size (1), */ \
@ -679,30 +689,31 @@ const size_t uclogic_rdesc_pen_v2_template_size =
0xA0, /* Collection (Physical), */ \
0x05, 0x09, /* Usage Page (Button), */ \
0x19, 0x01, /* Usage Minimum (01h), */ \
0x29, 0x02, /* Usage Maximum (02h), */ \
0x95, 0x02, /* Report Count (2), */ \
0x29, 0x03, /* Usage Maximum (03h), */ \
0x95, 0x03, /* Report Count (3), */ \
0x81, 0x02, /* Input (Variable), */ \
0x95, _padding, /* Report Count (_padding), */ \
0x95, ((_size) * 8 - 45), \
/* Report Count (padding), */ \
0x81, 0x01, /* Input (Constant), */ \
0xC0, /* End Collection, */ \
0xC0 /* End Collection */
/* Fixed report descriptor for (tweaked) v1 buttonpad reports */
const __u8 uclogic_rdesc_buttonpad_v1_arr[] = {
UCLOGIC_RDESC_BUTTONPAD_BYTES(20)
/* Fixed report descriptor for (tweaked) v1 frame reports */
const __u8 uclogic_rdesc_v1_frame_arr[] = {
UCLOGIC_RDESC_FRAME_BYTES(UCLOGIC_RDESC_V1_FRAME_ID, 8)
};
const size_t uclogic_rdesc_buttonpad_v1_size =
sizeof(uclogic_rdesc_buttonpad_v1_arr);
const size_t uclogic_rdesc_v1_frame_size =
sizeof(uclogic_rdesc_v1_frame_arr);
/* Fixed report descriptor for (tweaked) v2 buttonpad reports */
const __u8 uclogic_rdesc_buttonpad_v2_arr[] = {
UCLOGIC_RDESC_BUTTONPAD_BYTES(52)
/* Fixed report descriptor for (tweaked) v2 frame reports */
const __u8 uclogic_rdesc_v2_frame_arr[] = {
UCLOGIC_RDESC_FRAME_BYTES(UCLOGIC_RDESC_V2_FRAME_ID, 12)
};
const size_t uclogic_rdesc_buttonpad_v2_size =
sizeof(uclogic_rdesc_buttonpad_v2_arr);
const size_t uclogic_rdesc_v2_frame_size =
sizeof(uclogic_rdesc_v2_frame_arr);
/* Fixed report descriptor for Ugee EX07 buttonpad */
const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[] = {
/* Fixed report descriptor for Ugee EX07 frame */
const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x07, /* Usage (Keypad), */
0xA1, 0x01, /* Collection (Application), */
@ -725,8 +736,8 @@ const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[] = {
0xC0, /* End Collection, */
0xC0 /* End Collection */
};
const size_t uclogic_rdesc_ugee_ex07_buttonpad_size =
sizeof(uclogic_rdesc_ugee_ex07_buttonpad_arr);
const size_t uclogic_rdesc_ugee_ex07_frame_size =
sizeof(uclogic_rdesc_ugee_ex07_frame_arr);
/* Fixed report descriptor for Ugee G5 frame controls */
const __u8 uclogic_rdesc_ugee_g5_frame_arr[] = {

View File

@ -104,36 +104,36 @@ enum uclogic_rdesc_pen_ph_id {
UCLOGIC_RDESC_PH_HEAD, UCLOGIC_RDESC_PEN_PH_ID_##_ID
/* Report ID for v1 pen reports */
#define UCLOGIC_RDESC_PEN_V1_ID 0x07
#define UCLOGIC_RDESC_V1_PEN_ID 0x07
/* Fixed report descriptor template for (tweaked) v1 pen reports */
extern const __u8 uclogic_rdesc_pen_v1_template_arr[];
extern const size_t uclogic_rdesc_pen_v1_template_size;
extern const __u8 uclogic_rdesc_v1_pen_template_arr[];
extern const size_t uclogic_rdesc_v1_pen_template_size;
/* Report ID for v2 pen reports */
#define UCLOGIC_RDESC_PEN_V2_ID 0x08
#define UCLOGIC_RDESC_V2_PEN_ID 0x08
/* Fixed report descriptor template for (tweaked) v2 pen reports */
extern const __u8 uclogic_rdesc_pen_v2_template_arr[];
extern const size_t uclogic_rdesc_pen_v2_template_size;
extern const __u8 uclogic_rdesc_v2_pen_template_arr[];
extern const size_t uclogic_rdesc_v2_pen_template_size;
/* Fixed report descriptor for (tweaked) v1 buttonpad reports */
extern const __u8 uclogic_rdesc_buttonpad_v1_arr[];
extern const size_t uclogic_rdesc_buttonpad_v1_size;
/* Report ID for tweaked v1 frame reports */
#define UCLOGIC_RDESC_V1_FRAME_ID 0xf7
/* Report ID for tweaked v1 buttonpad reports */
#define UCLOGIC_RDESC_BUTTONPAD_V1_ID 0xf7
/* Fixed report descriptor for (tweaked) v1 frame reports */
extern const __u8 uclogic_rdesc_v1_frame_arr[];
extern const size_t uclogic_rdesc_v1_frame_size;
/* Fixed report descriptor for (tweaked) v2 buttonpad reports */
extern const __u8 uclogic_rdesc_buttonpad_v2_arr[];
extern const size_t uclogic_rdesc_buttonpad_v2_size;
/* Report ID for tweaked v2 frame reports */
#define UCLOGIC_RDESC_V2_FRAME_ID 0xf7
/* Report ID for tweaked v2 buttonpad reports */
#define UCLOGIC_RDESC_BUTTONPAD_V2_ID 0xf7
/* Fixed report descriptor for (tweaked) v2 frame reports */
extern const __u8 uclogic_rdesc_v2_frame_arr[];
extern const size_t uclogic_rdesc_v2_frame_size;
/* Fixed report descriptor for Ugee EX07 buttonpad */
extern const __u8 uclogic_rdesc_ugee_ex07_buttonpad_arr[];
extern const size_t uclogic_rdesc_ugee_ex07_buttonpad_size;
/* Fixed report descriptor for Ugee EX07 frame */
extern const __u8 uclogic_rdesc_ugee_ex07_frame_arr[];
extern const size_t uclogic_rdesc_ugee_ex07_frame_size;
/* Fixed report descriptor for XP-Pen Deco 01 frame controls */
extern const __u8 uclogic_rdesc_xppen_deco01_frame_arr[];

View File

@ -35,6 +35,7 @@
#include <linux/kernel.h>
#include <linux/hid.h>
#include <linux/mutex.h>
#include <asm/unaligned.h>
#include "../hid-ids.h"
#include "i2c-hid.h"
@ -47,6 +48,15 @@
#define I2C_HID_QUIRK_BAD_INPUT_SIZE BIT(6)
#define I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET BIT(7)
/* Command opcodes */
#define I2C_HID_OPCODE_RESET 0x01
#define I2C_HID_OPCODE_GET_REPORT 0x02
#define I2C_HID_OPCODE_SET_REPORT 0x03
#define I2C_HID_OPCODE_GET_IDLE 0x04
#define I2C_HID_OPCODE_SET_IDLE 0x05
#define I2C_HID_OPCODE_GET_PROTOCOL 0x06
#define I2C_HID_OPCODE_SET_PROTOCOL 0x07
#define I2C_HID_OPCODE_SET_POWER 0x08
/* flags */
#define I2C_HID_STARTED 0
@ -84,60 +94,11 @@ struct i2c_hid_desc {
__le32 reserved;
} __packed;
struct i2c_hid_cmd {
unsigned int registerIndex;
__u8 opcode;
unsigned int length;
bool wait;
};
union command {
u8 data[0];
struct cmd {
__le16 reg;
__u8 reportTypeID;
__u8 opcode;
} __packed c;
};
#define I2C_HID_CMD(opcode_) \
.opcode = opcode_, .length = 4, \
.registerIndex = offsetof(struct i2c_hid_desc, wCommandRegister)
/* fetch HID descriptor */
static const struct i2c_hid_cmd hid_descr_cmd = { .length = 2 };
/* fetch report descriptors */
static const struct i2c_hid_cmd hid_report_descr_cmd = {
.registerIndex = offsetof(struct i2c_hid_desc,
wReportDescRegister),
.opcode = 0x00,
.length = 2 };
/* commands */
static const struct i2c_hid_cmd hid_reset_cmd = { I2C_HID_CMD(0x01),
.wait = true };
static const struct i2c_hid_cmd hid_get_report_cmd = { I2C_HID_CMD(0x02) };
static const struct i2c_hid_cmd hid_set_report_cmd = { I2C_HID_CMD(0x03) };
static const struct i2c_hid_cmd hid_set_power_cmd = { I2C_HID_CMD(0x08) };
static const struct i2c_hid_cmd hid_no_cmd = { .length = 0 };
/*
* These definitions are not used here, but are defined by the spec.
* Keeping them here for documentation purposes.
*
* static const struct i2c_hid_cmd hid_get_idle_cmd = { I2C_HID_CMD(0x04) };
* static const struct i2c_hid_cmd hid_set_idle_cmd = { I2C_HID_CMD(0x05) };
* static const struct i2c_hid_cmd hid_get_protocol_cmd = { I2C_HID_CMD(0x06) };
* static const struct i2c_hid_cmd hid_set_protocol_cmd = { I2C_HID_CMD(0x07) };
*/
/* The main device structure */
struct i2c_hid {
struct i2c_client *client; /* i2c client */
struct hid_device *hid; /* pointer to corresponding HID dev */
union {
__u8 hdesc_buffer[sizeof(struct i2c_hid_desc)];
struct i2c_hid_desc hdesc; /* the HID Descriptor */
};
struct i2c_hid_desc hdesc; /* the HID Descriptor */
__le16 wHIDDescRegister; /* location of the i2c
* register of the HID
* descriptor. */
@ -145,7 +106,6 @@ struct i2c_hid {
u8 *inbuf; /* Input buffer */
u8 *rawbuf; /* Raw Input buffer */
u8 *cmdbuf; /* Command buffer */
u8 *argsbuf; /* Command arguments buffer */
unsigned long flags; /* device flags */
unsigned long quirks; /* Various quirks */
@ -207,196 +167,228 @@ static u32 i2c_hid_lookup_quirk(const u16 idVendor, const u16 idProduct)
return quirks;
}
static int __i2c_hid_command(struct i2c_client *client,
const struct i2c_hid_cmd *command, u8 reportID,
u8 reportType, u8 *args, int args_len,
unsigned char *buf_recv, int data_len)
static int i2c_hid_xfer(struct i2c_hid *ihid,
u8 *send_buf, int send_len, u8 *recv_buf, int recv_len)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
union command *cmd = (union command *)ihid->cmdbuf;
struct i2c_client *client = ihid->client;
struct i2c_msg msgs[2] = { 0 };
int n = 0;
int ret;
struct i2c_msg msg[2];
int msg_num = 1;
int length = command->length;
bool wait = command->wait;
unsigned int registerIndex = command->registerIndex;
if (send_len) {
i2c_hid_dbg(ihid, "%s: cmd=%*ph\n",
__func__, send_len, send_buf);
/* special case for hid_descr_cmd */
if (command == &hid_descr_cmd) {
cmd->c.reg = ihid->wHIDDescRegister;
} else {
cmd->data[0] = ihid->hdesc_buffer[registerIndex];
cmd->data[1] = ihid->hdesc_buffer[registerIndex + 1];
msgs[n].addr = client->addr;
msgs[n].flags = (client->flags & I2C_M_TEN) | I2C_M_DMA_SAFE;
msgs[n].len = send_len;
msgs[n].buf = send_buf;
n++;
}
if (length > 2) {
cmd->c.opcode = command->opcode;
cmd->c.reportTypeID = reportID | reportType << 4;
}
if (recv_len) {
msgs[n].addr = client->addr;
msgs[n].flags = (client->flags & I2C_M_TEN) |
I2C_M_RD | I2C_M_DMA_SAFE;
msgs[n].len = recv_len;
msgs[n].buf = recv_buf;
n++;
memcpy(cmd->data + length, args, args_len);
length += args_len;
i2c_hid_dbg(ihid, "%s: cmd=%*ph\n", __func__, length, cmd->data);
msg[0].addr = client->addr;
msg[0].flags = client->flags & I2C_M_TEN;
msg[0].len = length;
msg[0].buf = cmd->data;
if (data_len > 0) {
msg[1].addr = client->addr;
msg[1].flags = client->flags & I2C_M_TEN;
msg[1].flags |= I2C_M_RD;
msg[1].len = data_len;
msg[1].buf = buf_recv;
msg_num = 2;
set_bit(I2C_HID_READ_PENDING, &ihid->flags);
}
if (wait)
set_bit(I2C_HID_RESET_PENDING, &ihid->flags);
ret = i2c_transfer(client->adapter, msgs, n);
ret = i2c_transfer(client->adapter, msg, msg_num);
if (data_len > 0)
if (recv_len)
clear_bit(I2C_HID_READ_PENDING, &ihid->flags);
if (ret != msg_num)
if (ret != n)
return ret < 0 ? ret : -EIO;
ret = 0;
if (wait && (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET)) {
msleep(100);
} else if (wait) {
i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
if (!wait_event_timeout(ihid->wait,
!test_bit(I2C_HID_RESET_PENDING, &ihid->flags),
msecs_to_jiffies(5000)))
ret = -ENODATA;
i2c_hid_dbg(ihid, "%s: finished.\n", __func__);
}
return ret;
}
static int i2c_hid_command(struct i2c_client *client,
const struct i2c_hid_cmd *command,
unsigned char *buf_recv, int data_len)
{
return __i2c_hid_command(client, command, 0, 0, NULL, 0,
buf_recv, data_len);
}
static int i2c_hid_get_report(struct i2c_client *client, u8 reportType,
u8 reportID, unsigned char *buf_recv, int data_len)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
u8 args[3];
int ret;
int args_len = 0;
u16 readRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
i2c_hid_dbg(ihid, "%s\n", __func__);
if (reportID >= 0x0F) {
args[args_len++] = reportID;
reportID = 0x0F;
}
args[args_len++] = readRegister & 0xFF;
args[args_len++] = readRegister >> 8;
ret = __i2c_hid_command(client, &hid_get_report_cmd, reportID,
reportType, args, args_len, buf_recv, data_len);
if (ret) {
dev_err(&client->dev,
"failed to retrieve report from device.\n");
return ret;
}
return 0;
}
static int i2c_hid_read_register(struct i2c_hid *ihid, __le16 reg,
void *buf, size_t len)
{
*(__le16 *)ihid->cmdbuf = reg;
return i2c_hid_xfer(ihid, ihid->cmdbuf, sizeof(__le16), buf, len);
}
static size_t i2c_hid_encode_command(u8 *buf, u8 opcode,
int report_type, int report_id)
{
size_t length = 0;
if (report_id < 0x0F) {
buf[length++] = report_type << 4 | report_id;
buf[length++] = opcode;
} else {
buf[length++] = report_type << 4 | 0x0F;
buf[length++] = opcode;
buf[length++] = report_id;
}
return length;
}
static int i2c_hid_get_report(struct i2c_hid *ihid,
u8 report_type, u8 report_id,
u8 *recv_buf, size_t recv_len)
{
size_t length = 0;
size_t ret_count;
int error;
i2c_hid_dbg(ihid, "%s\n", __func__);
/* Command register goes first */
*(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
length += sizeof(__le16);
/* Next is GET_REPORT command */
length += i2c_hid_encode_command(ihid->cmdbuf + length,
I2C_HID_OPCODE_GET_REPORT,
report_type, report_id);
/*
* Device will send report data through data register. Because
* command can be either 2 or 3 bytes destination for the data
* register may be not aligned.
*/
put_unaligned_le16(le16_to_cpu(ihid->hdesc.wDataRegister),
ihid->cmdbuf + length);
length += sizeof(__le16);
/*
* In addition to report data device will supply data length
* in the first 2 bytes of the response, so adjust .
*/
error = i2c_hid_xfer(ihid, ihid->cmdbuf, length,
ihid->rawbuf, recv_len + sizeof(__le16));
if (error) {
dev_err(&ihid->client->dev,
"failed to set a report to device: %d\n", error);
return error;
}
/* The buffer is sufficiently aligned */
ret_count = le16_to_cpup((__le16 *)ihid->rawbuf);
/* Check for empty report response */
if (ret_count <= sizeof(__le16))
return 0;
recv_len = min(recv_len, ret_count - sizeof(__le16));
memcpy(recv_buf, ihid->rawbuf + sizeof(__le16), recv_len);
if (report_id && recv_len != 0 && recv_buf[0] != report_id) {
dev_err(&ihid->client->dev,
"device returned incorrect report (%d vs %d expected)\n",
recv_buf[0], report_id);
return -EINVAL;
}
return recv_len;
}
static size_t i2c_hid_format_report(u8 *buf, int report_id,
const u8 *data, size_t size)
{
size_t length = sizeof(__le16); /* reserve space to store size */
if (report_id)
buf[length++] = report_id;
memcpy(buf + length, data, size);
length += size;
/* Store overall size in the beginning of the buffer */
put_unaligned_le16(length, buf);
return length;
}
/**
* i2c_hid_set_or_send_report: forward an incoming report to the device
* @client: the i2c_client of the device
* @reportType: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT
* @reportID: the report ID
* @ihid: the i2c hid device
* @report_type: 0x03 for HID_FEATURE_REPORT ; 0x02 for HID_OUTPUT_REPORT
* @report_id: the report ID
* @buf: the actual data to transfer, without the report ID
* @data_len: size of buf
* @use_data: true: use SET_REPORT HID command, false: send plain OUTPUT report
* @do_set: true: use SET_REPORT HID command, false: send plain OUTPUT report
*/
static int i2c_hid_set_or_send_report(struct i2c_client *client, u8 reportType,
u8 reportID, unsigned char *buf, size_t data_len, bool use_data)
static int i2c_hid_set_or_send_report(struct i2c_hid *ihid,
u8 report_type, u8 report_id,
const u8 *buf, size_t data_len,
bool do_set)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
u8 *args = ihid->argsbuf;
const struct i2c_hid_cmd *hidcmd;
int ret;
u16 dataRegister = le16_to_cpu(ihid->hdesc.wDataRegister);
u16 outputRegister = le16_to_cpu(ihid->hdesc.wOutputRegister);
u16 maxOutputLength = le16_to_cpu(ihid->hdesc.wMaxOutputLength);
u16 size;
int args_len;
int index = 0;
size_t length = 0;
int error;
i2c_hid_dbg(ihid, "%s\n", __func__);
if (data_len > ihid->bufsize)
return -EINVAL;
size = 2 /* size */ +
(reportID ? 1 : 0) /* reportID */ +
data_len /* buf */;
args_len = (reportID >= 0x0F ? 1 : 0) /* optional third byte */ +
2 /* dataRegister */ +
size /* args */;
if (!use_data && maxOutputLength == 0)
if (!do_set && le16_to_cpu(ihid->hdesc.wMaxOutputLength) == 0)
return -ENOSYS;
if (reportID >= 0x0F) {
args[index++] = reportID;
reportID = 0x0F;
}
/*
* use the data register for feature reports or if the device does not
* support the output register
*/
if (use_data) {
args[index++] = dataRegister & 0xFF;
args[index++] = dataRegister >> 8;
hidcmd = &hid_set_report_cmd;
if (do_set) {
/* Command register goes first */
*(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
length += sizeof(__le16);
/* Next is SET_REPORT command */
length += i2c_hid_encode_command(ihid->cmdbuf + length,
I2C_HID_OPCODE_SET_REPORT,
report_type, report_id);
/*
* Report data will go into the data register. Because
* command can be either 2 or 3 bytes destination for
* the data register may be not aligned.
*/
put_unaligned_le16(le16_to_cpu(ihid->hdesc.wDataRegister),
ihid->cmdbuf + length);
length += sizeof(__le16);
} else {
args[index++] = outputRegister & 0xFF;
args[index++] = outputRegister >> 8;
hidcmd = &hid_no_cmd;
/*
* With simple "send report" all data goes into the output
* register.
*/
*(__le16 *)ihid->cmdbuf = ihid->hdesc.wOutputRegister;
length += sizeof(__le16);
}
args[index++] = size & 0xFF;
args[index++] = size >> 8;
length += i2c_hid_format_report(ihid->cmdbuf + length,
report_id, buf, data_len);
if (reportID)
args[index++] = reportID;
memcpy(&args[index], buf, data_len);
ret = __i2c_hid_command(client, hidcmd, reportID,
reportType, args, args_len, NULL, 0);
if (ret) {
dev_err(&client->dev, "failed to set a report to device.\n");
return ret;
error = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
if (error) {
dev_err(&ihid->client->dev,
"failed to set a report to device: %d\n", error);
return error;
}
return data_len;
}
static int i2c_hid_set_power(struct i2c_client *client, int power_state)
static int i2c_hid_set_power_command(struct i2c_hid *ihid, int power_state)
{
size_t length;
/* SET_POWER uses command register */
*(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
length = sizeof(__le16);
/* Now the command itself */
length += i2c_hid_encode_command(ihid->cmdbuf + length,
I2C_HID_OPCODE_SET_POWER,
0, power_state);
return i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
}
static int i2c_hid_set_power(struct i2c_hid *ihid, int power_state)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret;
i2c_hid_dbg(ihid, "%s\n", __func__);
@ -408,18 +400,17 @@ static int i2c_hid_set_power(struct i2c_client *client, int power_state)
*/
if (power_state == I2C_HID_PWR_ON &&
ihid->quirks & I2C_HID_QUIRK_SET_PWR_WAKEUP_DEV) {
ret = i2c_hid_command(client, &hid_set_power_cmd, NULL, 0);
ret = i2c_hid_set_power_command(ihid, I2C_HID_PWR_ON);
/* Device was already activated */
if (!ret)
goto set_pwr_exit;
}
ret = __i2c_hid_command(client, &hid_set_power_cmd, power_state,
0, NULL, 0, NULL, 0);
ret = i2c_hid_set_power_command(ihid, power_state);
if (ret)
dev_err(&client->dev, "failed to change power setting.\n");
dev_err(&ihid->client->dev,
"failed to change power setting.\n");
set_pwr_exit:
@ -438,9 +429,49 @@ set_pwr_exit:
return ret;
}
static int i2c_hid_hwreset(struct i2c_client *client)
static int i2c_hid_execute_reset(struct i2c_hid *ihid)
{
size_t length = 0;
int ret;
i2c_hid_dbg(ihid, "resetting...\n");
/* Prepare reset command. Command register goes first. */
*(__le16 *)ihid->cmdbuf = ihid->hdesc.wCommandRegister;
length += sizeof(__le16);
/* Next is RESET command itself */
length += i2c_hid_encode_command(ihid->cmdbuf + length,
I2C_HID_OPCODE_RESET, 0, 0);
set_bit(I2C_HID_RESET_PENDING, &ihid->flags);
ret = i2c_hid_xfer(ihid, ihid->cmdbuf, length, NULL, 0);
if (ret) {
dev_err(&ihid->client->dev, "failed to reset device.\n");
goto out;
}
if (ihid->quirks & I2C_HID_QUIRK_NO_IRQ_AFTER_RESET) {
msleep(100);
goto out;
}
i2c_hid_dbg(ihid, "%s: waiting...\n", __func__);
if (!wait_event_timeout(ihid->wait,
!test_bit(I2C_HID_RESET_PENDING, &ihid->flags),
msecs_to_jiffies(5000))) {
ret = -ENODATA;
goto out;
}
i2c_hid_dbg(ihid, "%s: finished.\n", __func__);
out:
clear_bit(I2C_HID_RESET_PENDING, &ihid->flags);
return ret;
}
static int i2c_hid_hwreset(struct i2c_hid *ihid)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
int ret;
i2c_hid_dbg(ihid, "%s\n", __func__);
@ -452,22 +483,21 @@ static int i2c_hid_hwreset(struct i2c_client *client)
*/
mutex_lock(&ihid->reset_lock);
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
if (ret)
goto out_unlock;
i2c_hid_dbg(ihid, "resetting...\n");
ret = i2c_hid_command(client, &hid_reset_cmd, NULL, 0);
ret = i2c_hid_execute_reset(ihid);
if (ret) {
dev_err(&client->dev, "failed to reset device.\n");
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
dev_err(&ihid->client->dev,
"failed to reset device: %d\n", ret);
i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
goto out_unlock;
}
/* At least some SIS devices need this after reset */
if (!(ihid->quirks & I2C_HID_QUIRK_NO_WAKEUP_AFTER_RESET))
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
out_unlock:
mutex_unlock(&ihid->reset_lock);
@ -476,9 +506,9 @@ out_unlock:
static void i2c_hid_get_input(struct i2c_hid *ihid)
{
u16 size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
u16 ret_size;
int ret;
u32 ret_size;
int size = le16_to_cpu(ihid->hdesc.wMaxInputLength);
if (size > ihid->bufsize)
size = ihid->bufsize;
@ -493,8 +523,8 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
return;
}
ret_size = ihid->inbuf[0] | ihid->inbuf[1] << 8;
/* Receiving buffer is properly aligned */
ret_size = le16_to_cpup((__le16 *)ihid->inbuf);
if (!ret_size) {
/* host or device initiated RESET completed */
if (test_and_clear_bit(I2C_HID_RESET_PENDING, &ihid->flags))
@ -502,19 +532,20 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
return;
}
if (ihid->quirks & I2C_HID_QUIRK_BOGUS_IRQ && ret_size == 0xffff) {
dev_warn_once(&ihid->client->dev, "%s: IRQ triggered but "
"there's no data\n", __func__);
if ((ihid->quirks & I2C_HID_QUIRK_BOGUS_IRQ) && ret_size == 0xffff) {
dev_warn_once(&ihid->client->dev,
"%s: IRQ triggered but there's no data\n",
__func__);
return;
}
if ((ret_size > size) || (ret_size < 2)) {
if (ret_size > size || ret_size < sizeof(__le16)) {
if (ihid->quirks & I2C_HID_QUIRK_BAD_INPUT_SIZE) {
ihid->inbuf[0] = size & 0xff;
ihid->inbuf[1] = size >> 8;
*(__le16 *)ihid->inbuf = cpu_to_le16(size);
ret_size = size;
} else {
dev_err(&ihid->client->dev, "%s: incomplete report (%d/%d)\n",
dev_err(&ihid->client->dev,
"%s: incomplete report (%d/%d)\n",
__func__, size, ret_size);
return;
}
@ -525,8 +556,9 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
if (test_bit(I2C_HID_STARTED, &ihid->flags)) {
pm_wakeup_event(&ihid->client->dev, 0);
hid_input_report(ihid->hid, HID_INPUT_REPORT, ihid->inbuf + 2,
ret_size - 2, 1);
hid_input_report(ihid->hid, HID_INPUT_REPORT,
ihid->inbuf + sizeof(__le16),
ret_size - sizeof(__le16), 1);
}
return;
@ -572,31 +604,33 @@ static void i2c_hid_free_buffers(struct i2c_hid *ihid)
{
kfree(ihid->inbuf);
kfree(ihid->rawbuf);
kfree(ihid->argsbuf);
kfree(ihid->cmdbuf);
ihid->inbuf = NULL;
ihid->rawbuf = NULL;
ihid->cmdbuf = NULL;
ihid->argsbuf = NULL;
ihid->bufsize = 0;
}
static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size)
{
/* the worst case is computed from the set_report command with a
* reportID > 15 and the maximum report length */
int args_len = sizeof(__u8) + /* ReportID */
sizeof(__u8) + /* optional ReportID byte */
sizeof(__u16) + /* data register */
sizeof(__u16) + /* size of the report */
report_size; /* report */
/*
* The worst case is computed from the set_report command with a
* reportID > 15 and the maximum report length.
*/
int cmd_len = sizeof(__le16) + /* command register */
sizeof(u8) + /* encoded report type/ID */
sizeof(u8) + /* opcode */
sizeof(u8) + /* optional 3rd byte report ID */
sizeof(__le16) + /* data register */
sizeof(__le16) + /* report data size */
sizeof(u8) + /* report ID if numbered report */
report_size;
ihid->inbuf = kzalloc(report_size, GFP_KERNEL);
ihid->rawbuf = kzalloc(report_size, GFP_KERNEL);
ihid->argsbuf = kzalloc(args_len, GFP_KERNEL);
ihid->cmdbuf = kzalloc(sizeof(union command) + args_len, GFP_KERNEL);
ihid->cmdbuf = kzalloc(cmd_len, GFP_KERNEL);
if (!ihid->inbuf || !ihid->rawbuf || !ihid->argsbuf || !ihid->cmdbuf) {
if (!ihid->inbuf || !ihid->rawbuf || !ihid->cmdbuf) {
i2c_hid_free_buffers(ihid);
return -ENOMEM;
}
@ -607,43 +641,39 @@ static int i2c_hid_alloc_buffers(struct i2c_hid *ihid, size_t report_size)
}
static int i2c_hid_get_raw_report(struct hid_device *hid,
unsigned char report_number, __u8 *buf, size_t count,
unsigned char report_type)
u8 report_type, u8 report_id,
u8 *buf, size_t count)
{
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
size_t ret_count, ask_count;
int ret;
int ret_count;
if (report_type == HID_OUTPUT_REPORT)
return -EINVAL;
/* +2 bytes to include the size of the reply in the query buffer */
ask_count = min(count + 2, (size_t)ihid->bufsize);
/*
* In case of unnumbered reports the response from the device will
* not have the report ID that the upper layers expect, so we need
* to stash it the buffer ourselves and adjust the data size.
*/
if (!report_id) {
buf[0] = 0;
buf++;
count--;
}
ret = i2c_hid_get_report(client,
ret_count = i2c_hid_get_report(ihid,
report_type == HID_FEATURE_REPORT ? 0x03 : 0x01,
report_number, ihid->rawbuf, ask_count);
report_id, buf, count);
if (ret < 0)
return ret;
if (ret_count > 0 && !report_id)
ret_count++;
ret_count = ihid->rawbuf[0] | (ihid->rawbuf[1] << 8);
if (ret_count <= 2)
return 0;
ret_count = min(ret_count, ask_count);
/* The query buffer contains the size, dropping it in the reply */
count = min(count, ret_count - 2);
memcpy(buf, ihid->rawbuf + 2, count);
return count;
return ret_count;
}
static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
size_t count, unsigned char report_type, bool use_data)
static int i2c_hid_output_raw_report(struct hid_device *hid, u8 report_type,
const u8 *buf, size_t count, bool do_set)
{
struct i2c_client *client = hid->driver_data;
struct i2c_hid *ihid = i2c_get_clientdata(client);
@ -655,28 +685,29 @@ static int i2c_hid_output_raw_report(struct hid_device *hid, __u8 *buf,
mutex_lock(&ihid->reset_lock);
if (report_id) {
buf++;
count--;
}
ret = i2c_hid_set_or_send_report(client,
/*
* Note that both numbered and unnumbered reports passed here
* are supposed to have report ID stored in the 1st byte of the
* buffer, so we strip it off unconditionally before passing payload
* to i2c_hid_set_or_send_report which takes care of encoding
* everything properly.
*/
ret = i2c_hid_set_or_send_report(ihid,
report_type == HID_FEATURE_REPORT ? 0x03 : 0x02,
report_id, buf, count, use_data);
report_id, buf + 1, count - 1, do_set);
if (report_id && ret >= 0)
ret++; /* add report_id to the number of transfered bytes */
if (ret >= 0)
ret++; /* add report_id to the number of transferred bytes */
mutex_unlock(&ihid->reset_lock);
return ret;
}
static int i2c_hid_output_report(struct hid_device *hid, __u8 *buf,
size_t count)
static int i2c_hid_output_report(struct hid_device *hid, u8 *buf, size_t count)
{
return i2c_hid_output_raw_report(hid, buf, count, HID_OUTPUT_REPORT,
false);
return i2c_hid_output_raw_report(hid, HID_OUTPUT_REPORT, buf, count,
false);
}
static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
@ -685,11 +716,11 @@ static int i2c_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
{
switch (reqtype) {
case HID_REQ_GET_REPORT:
return i2c_hid_get_raw_report(hid, reportnum, buf, len, rtype);
return i2c_hid_get_raw_report(hid, rtype, reportnum, buf, len);
case HID_REQ_SET_REPORT:
if (buf[0] != reportnum)
return -EINVAL;
return i2c_hid_output_raw_report(hid, buf, len, rtype, true);
return i2c_hid_output_raw_report(hid, rtype, buf, len, true);
default:
return -EIO;
}
@ -715,7 +746,7 @@ static int i2c_hid_parse(struct hid_device *hid)
}
do {
ret = i2c_hid_hwreset(client);
ret = i2c_hid_hwreset(ihid);
if (ret)
msleep(1000);
} while (tries-- > 0 && ret);
@ -739,8 +770,9 @@ static int i2c_hid_parse(struct hid_device *hid)
i2c_hid_dbg(ihid, "asking HID report descriptor\n");
ret = i2c_hid_command(client, &hid_report_descr_cmd,
rdesc, rsize);
ret = i2c_hid_read_register(ihid,
ihid->hdesc.wReportDescRegister,
rdesc, rsize);
if (ret) {
hid_err(hid, "reading report descriptor failed\n");
kfree(rdesc);
@ -850,7 +882,7 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
struct i2c_client *client = ihid->client;
struct i2c_hid_desc *hdesc = &ihid->hdesc;
unsigned int dsize;
int ret;
int error;
/* i2c hid fetch using a fixed descriptor size (30 bytes) */
if (i2c_hid_get_dmi_i2c_hid_desc_override(client->name)) {
@ -859,11 +891,14 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
*i2c_hid_get_dmi_i2c_hid_desc_override(client->name);
} else {
i2c_hid_dbg(ihid, "Fetching the HID descriptor\n");
ret = i2c_hid_command(client, &hid_descr_cmd,
ihid->hdesc_buffer,
sizeof(struct i2c_hid_desc));
if (ret) {
dev_err(&client->dev, "hid_descr_cmd failed\n");
error = i2c_hid_read_register(ihid,
ihid->wHIDDescRegister,
&ihid->hdesc,
sizeof(ihid->hdesc));
if (error) {
dev_err(&ihid->client->dev,
"failed to fetch HID descriptor: %d\n",
error);
return -ENODEV;
}
}
@ -873,7 +908,7 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
* bytes 2-3 -> bcdVersion (has to be 1.00) */
/* check bcdVersion == 1.0 */
if (le16_to_cpu(hdesc->bcdVersion) != 0x0100) {
dev_err(&client->dev,
dev_err(&ihid->client->dev,
"unexpected HID descriptor bcdVersion (0x%04hx)\n",
le16_to_cpu(hdesc->bcdVersion));
return -ENODEV;
@ -882,11 +917,11 @@ static int i2c_hid_fetch_hid_descriptor(struct i2c_hid *ihid)
/* Descriptor length should be 30 bytes as per the specification */
dsize = le16_to_cpu(hdesc->wHIDDescLength);
if (dsize != sizeof(struct i2c_hid_desc)) {
dev_err(&client->dev, "weird size of HID descriptor (%u)\n",
dsize);
dev_err(&ihid->client->dev,
"weird size of HID descriptor (%u)\n", dsize);
return -ENODEV;
}
i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, ihid->hdesc_buffer);
i2c_hid_dbg(ihid, "HID Descriptor: %*ph\n", dsize, &ihid->hdesc);
return 0;
}
@ -1052,7 +1087,7 @@ void i2c_hid_core_shutdown(struct i2c_client *client)
{
struct i2c_hid *ihid = i2c_get_clientdata(client);
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
free_irq(client->irq, ihid);
i2c_hid_core_shutdown_tail(ihid);
@ -1073,7 +1108,7 @@ static int i2c_hid_core_suspend(struct device *dev)
return ret;
/* Save some power */
i2c_hid_set_power(client, I2C_HID_PWR_SLEEP);
i2c_hid_set_power(ihid, I2C_HID_PWR_SLEEP);
disable_irq(client->irq);
@ -1121,9 +1156,9 @@ static int i2c_hid_core_resume(struct device *dev)
* let's still reset them here.
*/
if (ihid->quirks & I2C_HID_QUIRK_RESET_ON_RESUME)
ret = i2c_hid_hwreset(client);
ret = i2c_hid_hwreset(ihid);
else
ret = i2c_hid_set_power(client, I2C_HID_PWR_ON);
ret = i2c_hid_set_power(ihid, I2C_HID_PWR_ON);
if (ret)
return ret;

View File

@ -661,21 +661,12 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data,
*/
payload_max_size &= ~(L1_CACHE_BYTES - 1);
dma_buf = kmalloc(payload_max_size, GFP_KERNEL | GFP_DMA32);
dma_buf = dma_alloc_coherent(devc, payload_max_size, &dma_buf_phy, GFP_KERNEL);
if (!dma_buf) {
client_data->flag_retry = true;
return -ENOMEM;
}
dma_buf_phy = dma_map_single(devc, dma_buf, payload_max_size,
DMA_TO_DEVICE);
if (dma_mapping_error(devc, dma_buf_phy)) {
dev_err(cl_data_to_dev(client_data), "DMA map failed\n");
client_data->flag_retry = true;
rv = -ENOMEM;
goto end_err_dma_buf_release;
}
ldr_xfer_dma_frag.fragment.hdr.command = LOADER_CMD_XFER_FRAGMENT;
ldr_xfer_dma_frag.fragment.xfer_mode = LOADER_XFER_MODE_DIRECT_DMA;
ldr_xfer_dma_frag.ddr_phys_addr = (u64)dma_buf_phy;
@ -695,14 +686,7 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data,
ldr_xfer_dma_frag.fragment.size = fragment_size;
memcpy(dma_buf, &fw->data[fragment_offset], fragment_size);
dma_sync_single_for_device(devc, dma_buf_phy,
payload_max_size,
DMA_TO_DEVICE);
/*
* Flush cache here because the dma_sync_single_for_device()
* does not do for x86.
*/
/* Flush cache to be sure the data is in main memory. */
clflush_cache_range(dma_buf, payload_max_size);
dev_dbg(cl_data_to_dev(client_data),
@ -725,15 +709,8 @@ static int ish_fw_xfer_direct_dma(struct ishtp_cl_data *client_data,
fragment_offset += fragment_size;
}
dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE);
kfree(dma_buf);
return 0;
end_err_resp_buf_release:
/* Free ISH buffer if not done already, in error case */
dma_unmap_single(devc, dma_buf_phy, payload_max_size, DMA_TO_DEVICE);
end_err_dma_buf_release:
kfree(dma_buf);
dma_free_coherent(devc, payload_max_size, dma_buf, dma_buf_phy);
return rv;
}

View File

@ -342,12 +342,12 @@ struct hid_item {
* HID device quirks.
*/
/*
/*
* Increase this if you need to configure more HID quirks at module load time
*/
#define MAX_USBHID_BOOT_QUIRKS 4
#define HID_QUIRK_INVERT BIT(0)
/* BIT(0) reserved for backward compatibility, was HID_QUIRK_INVERT */
#define HID_QUIRK_NOTOUCH BIT(1)
#define HID_QUIRK_IGNORE BIT(2)
#define HID_QUIRK_NOGET BIT(3)
@ -476,31 +476,50 @@ struct hid_field {
unsigned report_count; /* number of this field in the report */
unsigned report_type; /* (input,output,feature) */
__s32 *value; /* last known value(s) */
__s32 *new_value; /* newly read value(s) */
__s32 *usages_priorities; /* priority of each usage when reading the report
* bits 8-16 are reserved for hid-input usage
*/
__s32 logical_minimum;
__s32 logical_maximum;
__s32 physical_minimum;
__s32 physical_maximum;
__s32 unit_exponent;
unsigned unit;
bool ignored; /* this field is ignored in this event */
struct hid_report *report; /* associated report */
unsigned index; /* index into report->field[] */
/* hidinput data */
struct hid_input *hidinput; /* associated input structure */
__u16 dpad; /* dpad input code */
unsigned int slot_idx; /* slot index in a report */
};
#define HID_MAX_FIELDS 256
struct hid_field_entry {
struct list_head list;
struct hid_field *field;
unsigned int index;
__s32 priority;
};
struct hid_report {
struct list_head list;
struct list_head hidinput_list;
struct list_head field_entry_list; /* ordered list of input fields */
unsigned int id; /* id of this report */
unsigned int type; /* report type */
unsigned int application; /* application usage for this report */
struct hid_field *field[HID_MAX_FIELDS]; /* fields of the report */
struct hid_field_entry *field_entries; /* allocated memory of input field_entry */
unsigned maxfield; /* maximum valid field index */
unsigned size; /* size of the report (bits) */
struct hid_device *device; /* associated device */
/* tool related state */
bool tool_active; /* whether the current tool is active */
unsigned int tool; /* BTN_TOOL_* */
};
#define HID_MAX_IDS 256