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

Pull HID updates from Jiri Kosina:

 - support for the following Bluetooth devices from Samsung: Samsung
   wireless {Keyboard, GamePad, Action Mouse, Book Cover, Universal
   Keyboard, HOGP Keyboard} (Sandeep C S)

 - second version of code for applying proper quirk depending on
   firmware version for lenovo/cptkbd (Mikhail Khvainitski)

 - lenovo/cptkbd firmware-dependent quirk (Mikhail Khvainitski)

 - assorted fixes and optimizations for amd-sfh (Basavaraj Natikar)

 - dead code and dead data structures removal (Jiri Slaby, Jiapeng
   Chong)

* tag 'hid-for-linus-2024031301' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (25 commits)
  HID: amd_sfh: Set the AMD SFH driver to depend on x86
  HID: input: avoid polling stylus battery on Chromebook Pompom
  HID: amd_sfh: Extend MP2 register access to SFH
  HID: amd_sfh: Improve boot time when SFH is available
  HID: amd_sfh: Avoid disabling the interrupt
  HID: amd_sfh: Update HPD sensor structure elements
  HID: amd_sfh: Increase sensor command timeout
  HID: intel-ish-hid: ipc: Add Arrow Lake PCI device ID
  HID: nintendo: Remove some unused functions
  HID: hid-prodikeys: remove struct pk_device
  HID: hid-prodikeys: remove unused struct pcmidi_snd members
  HID: hid-multitouch: remove unused mt_application::dev_time
  HID: hid-lg3ff: remove unused struct lg3ff_device
  HID: protect hid_device::bpf by CONFIG_HID_BPF
  HID: wacom: remove unused hid_data::pressure
  HID: apple: remove unused members from struct apple_sc_backlight
  HID: wacom: Clean up use of struct->wacom_wac
  HID: samsung: Add Samsung wireless bookcover and universal keyboard support
  HID: samsung: Add Samsung wireless action mouse support
  HID: samsung: Add Samsung wireless gamepad support
  ...
This commit is contained in:
Linus Torvalds
2024-03-14 09:56:15 -07:00
21 changed files with 624 additions and 197 deletions
+1
View File
@@ -6,6 +6,7 @@ menu "AMD SFH HID Support"
config AMD_SFH_HID
tristate "AMD Sensor Fusion Hub"
depends on HID
depends on X86
help
If you say yes to this option, support will be included for the
AMD Sensor Fusion Hub.
+16
View File
@@ -19,6 +19,9 @@
#define AMD_C2P_MSG(regno) (0x10500 + ((regno) * 4))
#define AMD_P2C_MSG(regno) (0x10680 + ((regno) * 4))
#define AMD_C2P_MSG_V1(regno) (0x10900 + ((regno) * 4))
#define AMD_P2C_MSG_V1(regno) (0x10500 + ((regno) * 4))
#define SENSOR_ENABLED 4
#define SENSOR_DISABLED 5
@@ -53,6 +56,9 @@ struct amd_mp2_dev {
/* mp2 active control status */
u32 mp2_acs;
struct sfh_dev_status dev_en;
struct work_struct work;
u8 init_done;
u8 rver;
};
struct amd_mp2_ops {
@@ -79,4 +85,14 @@ void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata);
int amd_sfh_irq_init_v2(struct amd_mp2_dev *privdata);
void amd_sfh_clear_intr(struct amd_mp2_dev *privdata);
int amd_sfh_irq_init(struct amd_mp2_dev *privdata);
static inline u64 amd_get_c2p_val(struct amd_mp2_dev *mp2, u32 idx)
{
return mp2->rver == 1 ? AMD_C2P_MSG_V1(idx) : AMD_C2P_MSG(idx);
}
static inline u64 amd_get_p2c_val(struct amd_mp2_dev *mp2, u32 idx)
{
return mp2->rver == 1 ? AMD_P2C_MSG_V1(idx) : AMD_P2C_MSG(idx);
}
#endif
+97 -21
View File
@@ -10,6 +10,7 @@
#include <linux/bitops.h>
#include <linux/delay.h>
#include <linux/devm-helpers.h>
#include <linux/dma-mapping.h>
#include <linux/dmi.h>
#include <linux/interrupt.h>
@@ -35,15 +36,17 @@ static int sensor_mask_override = -1;
module_param_named(sensor_mask, sensor_mask_override, int, 0444);
MODULE_PARM_DESC(sensor_mask, "override the detected sensors mask");
static bool intr_disable = true;
static int amd_sfh_wait_response_v2(struct amd_mp2_dev *mp2, u8 sid, u32 sensor_sts)
{
union cmd_response cmd_resp;
/* Get response with status within a max of 1600 ms timeout */
/* Get response with status within a max of 10 seconds timeout */
if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp,
(cmd_resp.response_v2.response == sensor_sts &&
cmd_resp.response_v2.status == 0 && (sid == 0xff ||
cmd_resp.response_v2.sensor_id == sid)), 500, 1600000))
cmd_resp.response_v2.sensor_id == sid)), 500, 10000000))
return cmd_resp.response_v2.response;
return SENSOR_DISABLED;
@@ -55,7 +58,7 @@ static void amd_start_sensor_v2(struct amd_mp2_dev *privdata, struct amd_mp2_sen
cmd_base.ul = 0;
cmd_base.cmd_v2.cmd_id = ENABLE_SENSOR;
cmd_base.cmd_v2.intr_disable = 1;
cmd_base.cmd_v2.intr_disable = intr_disable;
cmd_base.cmd_v2.period = info.period;
cmd_base.cmd_v2.sensor_id = info.sensor_idx;
cmd_base.cmd_v2.length = 16;
@@ -73,7 +76,7 @@ static void amd_stop_sensor_v2(struct amd_mp2_dev *privdata, u16 sensor_idx)
cmd_base.ul = 0;
cmd_base.cmd_v2.cmd_id = DISABLE_SENSOR;
cmd_base.cmd_v2.intr_disable = 1;
cmd_base.cmd_v2.intr_disable = intr_disable;
cmd_base.cmd_v2.period = 0;
cmd_base.cmd_v2.sensor_id = sensor_idx;
cmd_base.cmd_v2.length = 16;
@@ -87,7 +90,7 @@ static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata)
union sfh_cmd_base cmd_base;
cmd_base.cmd_v2.cmd_id = STOP_ALL_SENSORS;
cmd_base.cmd_v2.intr_disable = 1;
cmd_base.cmd_v2.intr_disable = intr_disable;
cmd_base.cmd_v2.period = 0;
cmd_base.cmd_v2.sensor_id = 0;
@@ -96,9 +99,9 @@ static void amd_stop_all_sensor_v2(struct amd_mp2_dev *privdata)
void amd_sfh_clear_intr_v2(struct amd_mp2_dev *privdata)
{
if (readl(privdata->mmio + AMD_P2C_MSG(4))) {
writel(0, privdata->mmio + AMD_P2C_MSG(4));
writel(0xf, privdata->mmio + AMD_P2C_MSG(5));
if (readl(privdata->mmio + amd_get_p2c_val(privdata, 4))) {
writel(0, privdata->mmio + amd_get_p2c_val(privdata, 4));
writel(0xf, privdata->mmio + amd_get_p2c_val(privdata, 5));
}
}
@@ -292,6 +295,26 @@ int amd_sfh_irq_init(struct amd_mp2_dev *privdata)
return 0;
}
static int mp2_disable_intr(const struct dmi_system_id *id)
{
intr_disable = false;
return 0;
}
static const struct dmi_system_id dmi_sfh_table[] = {
{
/*
* https://bugzilla.kernel.org/show_bug.cgi?id=218104
*/
.callback = mp2_disable_intr,
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "HP"),
DMI_MATCH(DMI_PRODUCT_NAME, "HP ProBook x360 435 G7"),
},
},
{}
};
static const struct dmi_system_id dmi_nodevs[] = {
{
/*
@@ -307,6 +330,48 @@ static const struct dmi_system_id dmi_nodevs[] = {
{ }
};
static void sfh1_1_init_work(struct work_struct *work)
{
struct amd_mp2_dev *mp2 = container_of(work, struct amd_mp2_dev, work);
struct pci_dev *pdev = mp2->pdev;
int rc;
rc = mp2->sfh1_1_ops->init(mp2);
if (rc) {
dev_err(&pdev->dev, "sfh1_1_init failed err %d\n", rc);
return;
}
amd_sfh_clear_intr(mp2);
mp2->init_done = 1;
}
static void sfh_init_work(struct work_struct *work)
{
struct amd_mp2_dev *mp2 = container_of(work, struct amd_mp2_dev, work);
struct pci_dev *pdev = mp2->pdev;
int rc;
rc = amd_sfh_hid_client_init(mp2);
if (rc) {
amd_sfh_clear_intr(mp2);
dev_err(&pdev->dev, "amd_sfh_hid_client_init failed err %d\n", rc);
return;
}
amd_sfh_clear_intr(mp2);
mp2->init_done = 1;
}
static void amd_sfh_remove(struct pci_dev *pdev)
{
struct amd_mp2_dev *mp2 = pci_get_drvdata(pdev);
flush_work(&mp2->work);
if (mp2->init_done)
mp2->mp2_ops->remove(mp2);
}
static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
{
struct amd_mp2_dev *privdata;
@@ -315,6 +380,8 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
if (dmi_first_match(dmi_nodevs))
return -ENODEV;
dmi_check_system(dmi_sfh_table);
privdata = devm_kzalloc(&pdev->dev, sizeof(*privdata), GFP_KERNEL);
if (!privdata)
return -ENOMEM;
@@ -343,10 +410,15 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
privdata->sfh1_1_ops = (const struct amd_sfh1_1_ops *)id->driver_data;
if (privdata->sfh1_1_ops) {
rc = privdata->sfh1_1_ops->init(privdata);
if (boot_cpu_data.x86 >= 0x1A)
privdata->rver = 1;
rc = devm_work_autocancel(&pdev->dev, &privdata->work, sfh1_1_init_work);
if (rc)
return rc;
goto init_done;
schedule_work(&privdata->work);
return 0;
}
mp2_select_ops(privdata);
@@ -357,33 +429,34 @@ static int amd_mp2_pci_probe(struct pci_dev *pdev, const struct pci_device_id *i
return rc;
}
rc = amd_sfh_hid_client_init(privdata);
rc = devm_work_autocancel(&pdev->dev, &privdata->work, sfh_init_work);
if (rc) {
amd_sfh_clear_intr(privdata);
if (rc != -EOPNOTSUPP)
dev_err(&pdev->dev, "amd_sfh_hid_client_init failed\n");
return rc;
}
init_done:
amd_sfh_clear_intr(privdata);
return devm_add_action_or_reset(&pdev->dev, privdata->mp2_ops->remove, privdata);
schedule_work(&privdata->work);
return 0;
}
static void amd_sfh_shutdown(struct pci_dev *pdev)
{
struct amd_mp2_dev *mp2 = pci_get_drvdata(pdev);
if (mp2 && mp2->mp2_ops)
mp2->mp2_ops->stop_all(mp2);
if (mp2) {
flush_work(&mp2->work);
if (mp2->init_done)
mp2->mp2_ops->stop_all(mp2);
}
}
static int __maybe_unused amd_mp2_pci_resume(struct device *dev)
{
struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);
mp2->mp2_ops->resume(mp2);
flush_work(&mp2->work);
if (mp2->init_done)
mp2->mp2_ops->resume(mp2);
return 0;
}
@@ -392,7 +465,9 @@ static int __maybe_unused amd_mp2_pci_suspend(struct device *dev)
{
struct amd_mp2_dev *mp2 = dev_get_drvdata(dev);
mp2->mp2_ops->suspend(mp2);
flush_work(&mp2->work);
if (mp2->init_done)
mp2->mp2_ops->suspend(mp2);
return 0;
}
@@ -414,6 +489,7 @@ static struct pci_driver amd_mp2_pci_driver = {
.probe = amd_mp2_pci_probe,
.driver.pm = &amd_mp2_pm_ops,
.shutdown = amd_sfh_shutdown,
.remove = amd_sfh_remove,
};
module_pci_driver(amd_mp2_pci_driver);
+3 -3
View File
@@ -90,10 +90,10 @@ enum mem_use_type {
struct hpd_status {
union {
struct {
u32 human_presence_report : 4;
u32 human_presence_actual : 4;
u32 probablity : 8;
u32 object_distance : 16;
u32 probablity : 8;
u32 human_presence_actual : 4;
u32 human_presence_report : 4;
} shpd;
u32 val;
};
@@ -251,7 +251,7 @@ static u8 get_input_rep(u8 current_index, int sensor_idx, int report_id,
break;
case HPD_IDX:
get_common_inputs(&hpd_input.common_property, report_id);
hpdstatus.val = readl(mp2->mmio + AMD_C2P_MSG(4));
hpdstatus.val = readl(mp2->mmio + amd_get_c2p_val(mp2, 4));
hpd_input.human_presence = hpdstatus.shpd.presence;
report_size = sizeof(hpd_input);
memcpy(input_report, &hpd_input, sizeof(hpd_input));
@@ -172,7 +172,7 @@ static int amd_sfh1_1_hid_client_init(struct amd_mp2_dev *privdata)
if (rc)
goto cleanup;
writel(0, privdata->mmio + AMD_P2C_MSG(0));
writel(0, privdata->mmio + amd_get_p2c_val(privdata, 0));
mp2_ops->start(privdata, info);
status = amd_sfh_wait_for_response
(privdata, cl_data->sensor_idx[i], ENABLE_SENSOR);
@@ -298,7 +298,7 @@ static void amd_sfh_set_ops(struct amd_mp2_dev *mp2)
int amd_sfh1_1_init(struct amd_mp2_dev *mp2)
{
u32 phy_base = readl(mp2->mmio + AMD_C2P_MSG(22));
u32 phy_base = readl(mp2->mmio + amd_get_c2p_val(mp2, 22));
struct device *dev = &mp2->pdev->dev;
struct sfh_base_info binfo;
int rc;
@@ -20,7 +20,7 @@ static int amd_sfh_wait_response(struct amd_mp2_dev *mp2, u8 sid, u32 cmd_id)
struct sfh_cmd_response cmd_resp;
/* Get response with status within a max of 10000 ms timeout */
if (!readl_poll_timeout(mp2->mmio + AMD_P2C_MSG(0), cmd_resp.resp,
if (!readl_poll_timeout(mp2->mmio + amd_get_p2c_val(mp2, 0), cmd_resp.resp,
(cmd_resp.response.response == 0 &&
cmd_resp.response.cmd_id == cmd_id && (sid == 0xff ||
cmd_resp.response.sensor_id == sid)), 500, 10000000))
@@ -39,7 +39,7 @@ static void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor
cmd_base.cmd.sub_cmd_value = 1;
cmd_base.cmd.sensor_id = info.sensor_idx;
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0));
writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
}
static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
@@ -52,8 +52,8 @@ static void amd_stop_sensor(struct amd_mp2_dev *privdata, u16 sensor_idx)
cmd_base.cmd.sub_cmd_value = 1;
cmd_base.cmd.sensor_id = sensor_idx;
writeq(0x0, privdata->mmio + AMD_C2P_MSG(1));
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0));
writeq(0x0, privdata->mmio + amd_get_c2p_val(privdata, 1));
writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
}
static void amd_stop_all_sensor(struct amd_mp2_dev *privdata)
@@ -66,7 +66,7 @@ static void amd_stop_all_sensor(struct amd_mp2_dev *privdata)
/* 0xf indicates all sensors */
cmd_base.cmd.sensor_id = 0xf;
writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG(0));
writel(cmd_base.ul, privdata->mmio + amd_get_c2p_val(privdata, 0));
}
static struct amd_mp2_ops amd_sfh_ops = {
-1
View File
@@ -79,7 +79,6 @@ struct apple_non_apple_keyboard {
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 {
+8
View File
@@ -430,6 +430,7 @@
#define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V1 0x2BED
#define I2C_DEVICE_ID_HP_SPECTRE_X360_14T_EA100_V2 0x2BEE
#define I2C_DEVICE_ID_HP_ENVY_X360_15_EU0556NG 0x2D02
#define I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM 0x2F81
#define USB_VENDOR_ID_ELECOM 0x056e
#define USB_DEVICE_ID_ELECOM_BM084 0x0061
@@ -1146,8 +1147,15 @@
#define USB_DEVICE_ID_SAITEK_X65 0x0b6a
#define USB_VENDOR_ID_SAMSUNG 0x0419
#define USB_VENDOR_ID_SAMSUNG_ELECTRONICS 0x04e8
#define USB_DEVICE_ID_SAMSUNG_IR_REMOTE 0x0001
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE 0x0600
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD 0x7021
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_GAMEPAD 0xa000
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_ACTIONMOUSE 0xa004
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_BOOKCOVER 0xa005
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_UNIVERSAL_KBD 0xa006
#define USB_DEVICE_ID_SAMSUNG_WIRELESS_MULTI_HOGP_KBD 0xa064
#define USB_VENDOR_ID_SEMICO 0x1a2c
#define USB_DEVICE_ID_SEMICO_USB_KEYKOARD 0x0023
+2
View File
@@ -411,6 +411,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
HID_BATTERY_QUIRK_IGNORE },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15_EU0556NG),
HID_BATTERY_QUIRK_IGNORE },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_CHROMEBOOK_TROGDOR_POMPOM),
HID_BATTERY_QUIRK_AVOID_QUERY },
{}
};
+39 -18
View File
@@ -54,10 +54,10 @@ struct lenovo_drvdata {
/* 0: Up
* 1: Down (undecided)
* 2: Scrolling
* 3: Patched firmware, disable workaround
*/
u8 middlebutton_state;
bool fn_lock;
bool middleclick_workaround_cptkbd;
};
#define map_key_clear(c) hid_map_usage_clear(hi, usage, bit, max, EV_KEY, (c))
@@ -621,6 +621,36 @@ static ssize_t attr_sensitivity_store_cptkbd(struct device *dev,
return count;
}
static ssize_t attr_middleclick_workaround_show_cptkbd(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
return snprintf(buf, PAGE_SIZE, "%u\n",
cptkbd_data->middleclick_workaround_cptkbd);
}
static ssize_t attr_middleclick_workaround_store_cptkbd(struct device *dev,
struct device_attribute *attr,
const char *buf,
size_t count)
{
struct hid_device *hdev = to_hid_device(dev);
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
int value;
if (kstrtoint(buf, 10, &value))
return -EINVAL;
if (value < 0 || value > 1)
return -EINVAL;
cptkbd_data->middleclick_workaround_cptkbd = !!value;
return count;
}
static struct device_attribute dev_attr_fn_lock =
__ATTR(fn_lock, S_IWUSR | S_IRUGO,
@@ -632,10 +662,16 @@ static struct device_attribute dev_attr_sensitivity_cptkbd =
attr_sensitivity_show_cptkbd,
attr_sensitivity_store_cptkbd);
static struct device_attribute dev_attr_middleclick_workaround_cptkbd =
__ATTR(middleclick_workaround, S_IWUSR | S_IRUGO,
attr_middleclick_workaround_show_cptkbd,
attr_middleclick_workaround_store_cptkbd);
static struct attribute *lenovo_attributes_cptkbd[] = {
&dev_attr_fn_lock.attr,
&dev_attr_sensitivity_cptkbd.attr,
&dev_attr_middleclick_workaround_cptkbd.attr,
NULL
};
@@ -686,23 +722,7 @@ static int lenovo_event_cptkbd(struct hid_device *hdev,
{
struct lenovo_drvdata *cptkbd_data = hid_get_drvdata(hdev);
if (cptkbd_data->middlebutton_state != 3) {
/* REL_X and REL_Y events during middle button pressed
* are only possible on patched, bug-free firmware
* so set middlebutton_state to 3
* to never apply workaround anymore
*/
if (hdev->product == USB_DEVICE_ID_LENOVO_CUSBKBD &&
cptkbd_data->middlebutton_state == 1 &&
usage->type == EV_REL &&
(usage->code == REL_X || usage->code == REL_Y)) {
cptkbd_data->middlebutton_state = 3;
/* send middle button press which was hold before */
input_event(field->hidinput->input,
EV_KEY, BTN_MIDDLE, 1);
input_sync(field->hidinput->input);
}
if (cptkbd_data->middleclick_workaround_cptkbd) {
/* "wheel" scroll events */
if (usage->type == EV_REL && (usage->code == REL_WHEEL ||
usage->code == REL_HWHEEL)) {
@@ -1166,6 +1186,7 @@ static int lenovo_probe_cptkbd(struct hid_device *hdev)
cptkbd_data->middlebutton_state = 0;
cptkbd_data->fn_lock = true;
cptkbd_data->sensitivity = 0x05;
cptkbd_data->middleclick_workaround_cptkbd = true;
lenovo_features_set_cptkbd(hdev);
ret = sysfs_create_group(&hdev->dev.kobj, &lenovo_attr_group_cptkbd);
-4
View File
@@ -41,10 +41,6 @@
* I'm sure these are effects that I don't know enough about them
*/
struct lg3ff_device {
struct hid_report *report;
};
static int hid_lg3ff_play(struct input_dev *dev, void *data,
struct ff_effect *effect)
{
-1
View File
@@ -130,7 +130,6 @@ struct mt_application {
* > 1 means hybrid (multitouch) protocol
*/
__s32 dev_time; /* the scan time provided by the device */
unsigned long jiffies; /* the frame's jiffies */
int timestamp; /* the timestamp to be sent */
int prev_scantime; /* scantime reported previously */
-22
View File
@@ -667,16 +667,6 @@ struct joycon_ctlr {
* These helpers are most useful early during the HID probe or in conjunction
* with the capability helpers below.
*/
static inline bool joycon_device_is_left_joycon(struct joycon_ctlr *ctlr)
{
return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONL;
}
static inline bool joycon_device_is_right_joycon(struct joycon_ctlr *ctlr)
{
return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_JOYCONR;
}
static inline bool joycon_device_is_procon(struct joycon_ctlr *ctlr)
{
return ctlr->hdev->product == USB_DEVICE_ID_NINTENDO_PROCON;
@@ -764,18 +754,6 @@ static inline bool joycon_type_is_right_nescon(struct joycon_ctlr *ctlr)
return ctlr->ctlr_type == JOYCON_CTLR_TYPE_NESR;
}
static inline bool joycon_type_has_left_controls(struct joycon_ctlr *ctlr)
{
return joycon_type_is_left_joycon(ctlr) ||
joycon_type_is_procon(ctlr);
}
static inline bool joycon_type_has_right_controls(struct joycon_ctlr *ctlr)
{
return joycon_type_is_right_joycon(ctlr) ||
joycon_type_is_procon(ctlr);
}
static inline bool joycon_type_is_any_joycon(struct joycon_ctlr *ctlr)
{
return joycon_type_is_left_joycon(ctlr) ||
+41 -76
View File
@@ -32,13 +32,6 @@
struct pcmidi_snd;
struct pk_device {
unsigned long quirks;
struct hid_device *hdev;
struct pcmidi_snd *pm; /* pcmidi device context */
};
struct pcmidi_sustain {
unsigned long in_use;
struct pcmidi_snd *pm;
@@ -50,7 +43,7 @@ struct pcmidi_sustain {
#define PCMIDI_SUSTAINED_MAX 32
struct pcmidi_snd {
struct pk_device *pk;
struct hid_device *hdev;
unsigned short ifnum;
struct hid_report *pcmidi_report6;
struct input_dev *input_ep82;
@@ -66,9 +59,7 @@ struct pcmidi_snd {
struct snd_card *card;
struct snd_rawmidi *rwmidi;
struct snd_rawmidi_substream *in_substream;
struct snd_rawmidi_substream *out_substream;
unsigned long in_triggered;
unsigned long out_active;
};
#define PK_QUIRK_NOGET 0x00010000
@@ -100,11 +91,11 @@ static ssize_t show_channel(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
struct pcmidi_snd *pm = hid_get_drvdata(hdev);
dbg_hid("pcmidi sysfs read channel=%u\n", pk->pm->midi_channel);
dbg_hid("pcmidi sysfs read channel=%u\n", pm->midi_channel);
return sprintf(buf, "%u (min:%u, max:%u)\n", pk->pm->midi_channel,
return sprintf(buf, "%u (min:%u, max:%u)\n", pm->midi_channel,
PCMIDI_CHANNEL_MIN, PCMIDI_CHANNEL_MAX);
}
@@ -113,13 +104,13 @@ static ssize_t store_channel(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
struct pcmidi_snd *pm = hid_get_drvdata(hdev);
unsigned channel = 0;
if (sscanf(buf, "%u", &channel) > 0 && channel <= PCMIDI_CHANNEL_MAX) {
dbg_hid("pcmidi sysfs write channel=%u\n", channel);
pk->pm->midi_channel = channel;
pm->midi_channel = channel;
return strlen(buf);
}
return -EINVAL;
@@ -137,11 +128,11 @@ static ssize_t show_sustain(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
struct pcmidi_snd *pm = hid_get_drvdata(hdev);
dbg_hid("pcmidi sysfs read sustain=%u\n", pk->pm->midi_sustain);
dbg_hid("pcmidi sysfs read sustain=%u\n", pm->midi_sustain);
return sprintf(buf, "%u (off:%u, max:%u (ms))\n", pk->pm->midi_sustain,
return sprintf(buf, "%u (off:%u, max:%u (ms))\n", pm->midi_sustain,
PCMIDI_SUSTAIN_MIN, PCMIDI_SUSTAIN_MAX);
}
@@ -150,15 +141,14 @@ static ssize_t store_sustain(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
struct pcmidi_snd *pm = hid_get_drvdata(hdev);
unsigned sustain = 0;
if (sscanf(buf, "%u", &sustain) > 0 && sustain <= PCMIDI_SUSTAIN_MAX) {
dbg_hid("pcmidi sysfs write sustain=%u\n", sustain);
pk->pm->midi_sustain = sustain;
pk->pm->midi_sustain_mode =
(0 == sustain || !pk->pm->midi_mode) ? 0 : 1;
pm->midi_sustain = sustain;
pm->midi_sustain_mode = (0 == sustain || !pm->midi_mode) ? 0 : 1;
return strlen(buf);
}
return -EINVAL;
@@ -176,11 +166,11 @@ static ssize_t show_octave(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
struct pcmidi_snd *pm = hid_get_drvdata(hdev);
dbg_hid("pcmidi sysfs read octave=%d\n", pk->pm->midi_octave);
dbg_hid("pcmidi sysfs read octave=%d\n", pm->midi_octave);
return sprintf(buf, "%d (min:%d, max:%d)\n", pk->pm->midi_octave,
return sprintf(buf, "%d (min:%d, max:%d)\n", pm->midi_octave,
PCMIDI_OCTAVE_MIN, PCMIDI_OCTAVE_MAX);
}
@@ -189,14 +179,14 @@ static ssize_t store_octave(struct device *dev,
struct device_attribute *attr, const char *buf, size_t count)
{
struct hid_device *hdev = to_hid_device(dev);
struct pk_device *pk = hid_get_drvdata(hdev);
struct pcmidi_snd *pm = hid_get_drvdata(hdev);
int octave = 0;
if (sscanf(buf, "%d", &octave) > 0 &&
octave >= PCMIDI_OCTAVE_MIN && octave <= PCMIDI_OCTAVE_MAX) {
dbg_hid("pcmidi sysfs write octave=%d\n", octave);
pk->pm->midi_octave = octave;
pm->midi_octave = octave;
return strlen(buf);
}
return -EINVAL;
@@ -270,7 +260,7 @@ static void stop_sustain_timers(struct pcmidi_snd *pm)
static int pcmidi_get_output_report(struct pcmidi_snd *pm)
{
struct hid_device *hdev = pm->pk->hdev;
struct hid_device *hdev = pm->hdev;
struct hid_report *report;
list_for_each_entry(report,
@@ -295,7 +285,7 @@ static int pcmidi_get_output_report(struct pcmidi_snd *pm)
static void pcmidi_submit_output_report(struct pcmidi_snd *pm, int state)
{
struct hid_device *hdev = pm->pk->hdev;
struct hid_device *hdev = pm->hdev;
struct hid_report *report = pm->pcmidi_report6;
report->field[0]->value[0] = 0x01;
report->field[0]->value[1] = state;
@@ -622,7 +612,7 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
/* Setup sound card */
err = snd_card_new(&pm->pk->hdev->dev, index[dev], id[dev],
err = snd_card_new(&pm->hdev->dev, index[dev], id[dev],
THIS_MODULE, 0, &card);
if (err < 0) {
pk_error("failed to create pc-midi sound card\n");
@@ -660,7 +650,7 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
&pcmidi_in_ops);
/* create sysfs variables */
err = device_create_file(&pm->pk->hdev->dev,
err = device_create_file(&pm->hdev->dev,
sysfs_device_attr_channel);
if (err < 0) {
pk_error("failed to create sysfs attribute channel: error %d\n",
@@ -668,7 +658,7 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
goto fail;
}
err = device_create_file(&pm->pk->hdev->dev,
err = device_create_file(&pm->hdev->dev,
sysfs_device_attr_sustain);
if (err < 0) {
pk_error("failed to create sysfs attribute sustain: error %d\n",
@@ -676,7 +666,7 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
goto fail_attr_sustain;
}
err = device_create_file(&pm->pk->hdev->dev,
err = device_create_file(&pm->hdev->dev,
sysfs_device_attr_octave);
if (err < 0) {
pk_error("failed to create sysfs attribute octave: error %d\n",
@@ -706,11 +696,11 @@ static int pcmidi_snd_initialise(struct pcmidi_snd *pm)
fail_register:
stop_sustain_timers(pm);
device_remove_file(&pm->pk->hdev->dev, sysfs_device_attr_octave);
device_remove_file(&pm->hdev->dev, sysfs_device_attr_octave);
fail_attr_octave:
device_remove_file(&pm->pk->hdev->dev, sysfs_device_attr_sustain);
device_remove_file(&pm->hdev->dev, sysfs_device_attr_sustain);
fail_attr_sustain:
device_remove_file(&pm->pk->hdev->dev, sysfs_device_attr_channel);
device_remove_file(&pm->hdev->dev, sysfs_device_attr_channel);
fail:
if (pm->card) {
snd_card_free(pm->card);
@@ -724,12 +714,9 @@ static int pcmidi_snd_terminate(struct pcmidi_snd *pm)
if (pm->card) {
stop_sustain_timers(pm);
device_remove_file(&pm->pk->hdev->dev,
sysfs_device_attr_channel);
device_remove_file(&pm->pk->hdev->dev,
sysfs_device_attr_sustain);
device_remove_file(&pm->pk->hdev->dev,
sysfs_device_attr_octave);
device_remove_file(&pm->hdev->dev, sysfs_device_attr_channel);
device_remove_file(&pm->hdev->dev, sysfs_device_attr_sustain);
device_remove_file(&pm->hdev->dev, sysfs_device_attr_octave);
snd_card_disconnect(pm->card);
snd_card_free_when_closed(pm->card);
@@ -759,10 +746,7 @@ static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi,
struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
struct pk_device *pk = hid_get_drvdata(hdev);
struct pcmidi_snd *pm;
pm = pk->pm;
struct pcmidi_snd *pm = hid_get_drvdata(hdev);
if (HID_UP_MSVENDOR == (usage->hid & HID_USAGE_PAGE) &&
1 == pm->ifnum) {
@@ -777,16 +761,16 @@ static int pk_input_mapping(struct hid_device *hdev, struct hid_input *hi,
static int pk_raw_event(struct hid_device *hdev, struct hid_report *report,
u8 *data, int size)
{
struct pk_device *pk = hid_get_drvdata(hdev);
struct pcmidi_snd *pm = hid_get_drvdata(hdev);
int ret = 0;
if (1 == pk->pm->ifnum) {
if (1 == pm->ifnum) {
if (report->id == data[0])
switch (report->id) {
case 0x01: /* midi keys (qwerty)*/
case 0x03: /* midi keyboard (musical)*/
case 0x04: /* extra/midi keys (qwerty)*/
ret = pcmidi_handle_report(pk->pm,
ret = pcmidi_handle_report(pm,
report->id, data, size);
break;
}
@@ -801,8 +785,7 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
struct usb_interface *intf;
unsigned short ifnum;
unsigned long quirks = id->driver_data;
struct pk_device *pk;
struct pcmidi_snd *pm = NULL;
struct pcmidi_snd *pm;
if (!hid_is_usb(hdev))
return -EINVAL;
@@ -810,26 +793,16 @@ static int pk_probe(struct hid_device *hdev, const struct hid_device_id *id)
intf = to_usb_interface(hdev->dev.parent);
ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
pk = kzalloc(sizeof(*pk), GFP_KERNEL);
if (pk == NULL) {
pm = kzalloc(sizeof(*pm), GFP_KERNEL);
if (pm == NULL) {
hid_err(hdev, "can't alloc descriptor\n");
return -ENOMEM;
}
pk->hdev = hdev;
pm = kzalloc(sizeof(*pm), GFP_KERNEL);
if (pm == NULL) {
hid_err(hdev, "can't alloc descriptor\n");
ret = -ENOMEM;
goto err_free_pk;
}
pm->pk = pk;
pk->pm = pm;
pm->hdev = hdev;
pm->ifnum = ifnum;
hid_set_drvdata(hdev, pk);
hid_set_drvdata(hdev, pm);
ret = hid_parse(hdev);
if (ret) {
@@ -856,26 +829,18 @@ err_stop:
hid_hw_stop(hdev);
err_free:
kfree(pm);
err_free_pk:
kfree(pk);
return ret;
}
static void pk_remove(struct hid_device *hdev)
{
struct pk_device *pk = hid_get_drvdata(hdev);
struct pcmidi_snd *pm;
pm = pk->pm;
if (pm) {
pcmidi_snd_terminate(pm);
kfree(pm);
}
struct pcmidi_snd *pm = hid_get_drvdata(hdev);
pcmidi_snd_terminate(pm);
hid_hw_stop(hdev);
kfree(pk);
kfree(pm);
}
static const struct hid_device_id pk_devices[] = {
+401 -36
View File
@@ -58,33 +58,25 @@ static inline void samsung_irda_dev_trace(struct hid_device *hdev,
static __u8 *samsung_irda_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (*rsize == 184 && rdesc[175] == 0x25 && rdesc[176] == 0x40 &&
rdesc[177] == 0x75 && rdesc[178] == 0x30 &&
rdesc[179] == 0x95 && rdesc[180] == 0x01 &&
if (*rsize == 184 && !memcmp(&rdesc[175], "\x25\x40\x75\x30\x95\x01", 6) &&
rdesc[182] == 0x40) {
samsung_irda_dev_trace(hdev, 184);
rdesc[176] = 0xff;
rdesc[178] = 0x08;
rdesc[180] = 0x06;
rdesc[182] = 0x42;
} else
if (*rsize == 203 && rdesc[192] == 0x15 && rdesc[193] == 0x0 &&
rdesc[194] == 0x25 && rdesc[195] == 0x12) {
} else if (*rsize == 203 && !memcmp(&rdesc[192], "\x15\x00\x25\x12", 4)) {
samsung_irda_dev_trace(hdev, 203);
rdesc[193] = 0x1;
rdesc[195] = 0xf;
} else
if (*rsize == 135 && rdesc[124] == 0x15 && rdesc[125] == 0x0 &&
rdesc[126] == 0x25 && rdesc[127] == 0x11) {
rdesc[193] = 0x01;
rdesc[195] = 0x0f;
} else if (*rsize == 135 && !memcmp(&rdesc[124], "\x15\x00\x25\x11", 4)) {
samsung_irda_dev_trace(hdev, 135);
rdesc[125] = 0x1;
rdesc[127] = 0xe;
} else
if (*rsize == 171 && rdesc[160] == 0x15 && rdesc[161] == 0x0 &&
rdesc[162] == 0x25 && rdesc[163] == 0x01) {
rdesc[125] = 0x01;
rdesc[127] = 0x0e;
} else if (*rsize == 171 && !memcmp(&rdesc[160], "\x15\x00\x25\x01", 4)) {
samsung_irda_dev_trace(hdev, 171);
rdesc[161] = 0x1;
rdesc[163] = 0x3;
rdesc[161] = 0x01;
rdesc[163] = 0x03;
}
return rdesc;
}
@@ -99,7 +91,7 @@ static int samsung_kbd_mouse_input_mapping(struct hid_device *hdev,
struct usb_interface *intf = to_usb_interface(hdev->dev.parent);
unsigned short ifnum = intf->cur_altsetting->desc.bInterfaceNumber;
if (1 != ifnum || HID_UP_CONSUMER != (usage->hid & HID_USAGE_PAGE))
if (ifnum != 1 || HID_UP_CONSUMER != (usage->hid & HID_USAGE_PAGE))
return 0;
dbg_hid("samsung wireless keyboard/mouse input mapping event [0x%x]\n",
@@ -107,17 +99,39 @@ static int samsung_kbd_mouse_input_mapping(struct hid_device *hdev,
switch (usage->hid & HID_USAGE) {
/* report 2 */
case 0x183: samsung_kbd_mouse_map_key_clear(KEY_MEDIA); break;
case 0x195: samsung_kbd_mouse_map_key_clear(KEY_EMAIL); break;
case 0x196: samsung_kbd_mouse_map_key_clear(KEY_CALC); break;
case 0x197: samsung_kbd_mouse_map_key_clear(KEY_COMPUTER); break;
case 0x22b: samsung_kbd_mouse_map_key_clear(KEY_SEARCH); break;
case 0x22c: samsung_kbd_mouse_map_key_clear(KEY_WWW); break;
case 0x22d: samsung_kbd_mouse_map_key_clear(KEY_BACK); break;
case 0x22e: samsung_kbd_mouse_map_key_clear(KEY_FORWARD); break;
case 0x22f: samsung_kbd_mouse_map_key_clear(KEY_FAVORITES); break;
case 0x230: samsung_kbd_mouse_map_key_clear(KEY_REFRESH); break;
case 0x231: samsung_kbd_mouse_map_key_clear(KEY_STOP); break;
case 0x183:
samsung_kbd_mouse_map_key_clear(KEY_MEDIA);
break;
case 0x195:
samsung_kbd_mouse_map_key_clear(KEY_EMAIL);
break;
case 0x196:
samsung_kbd_mouse_map_key_clear(KEY_CALC);
break;
case 0x197:
samsung_kbd_mouse_map_key_clear(KEY_COMPUTER);
break;
case 0x22b:
samsung_kbd_mouse_map_key_clear(KEY_SEARCH);
break;
case 0x22c:
samsung_kbd_mouse_map_key_clear(KEY_WWW);
break;
case 0x22d:
samsung_kbd_mouse_map_key_clear(KEY_BACK);
break;
case 0x22e:
samsung_kbd_mouse_map_key_clear(KEY_FORWARD);
break;
case 0x22f:
samsung_kbd_mouse_map_key_clear(KEY_FAVORITES);
break;
case 0x230:
samsung_kbd_mouse_map_key_clear(KEY_REFRESH);
break;
case 0x231:
samsung_kbd_mouse_map_key_clear(KEY_STOP);
break;
default:
return 0;
}
@@ -125,10 +139,340 @@ static int samsung_kbd_mouse_input_mapping(struct hid_device *hdev,
return 1;
}
static int samsung_kbd_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
if (!(HID_UP_CONSUMER == (usage->hid & HID_USAGE_PAGE) ||
HID_UP_KEYBOARD == (usage->hid & HID_USAGE_PAGE)))
return 0;
dbg_hid("samsung wireless keyboard input mapping event [0x%x]\n",
usage->hid & HID_USAGE);
if (HID_UP_KEYBOARD == (usage->hid & HID_USAGE_PAGE)) {
set_bit(EV_REP, hi->input->evbit);
switch (usage->hid & HID_USAGE) {
case 0x32:
samsung_kbd_mouse_map_key_clear(KEY_BACKSLASH);
break;
case 0x64:
samsung_kbd_mouse_map_key_clear(KEY_102ND);
break;
/* Only for BR keyboard */
case 0x87:
samsung_kbd_mouse_map_key_clear(KEY_RO);
break;
default:
return 0;
}
}
if (HID_UP_CONSUMER == (usage->hid & HID_USAGE_PAGE)) {
switch (usage->hid & HID_USAGE) {
/* report 2 */
/* MENU */
case 0x040:
samsung_kbd_mouse_map_key_clear(KEY_MENU);
break;
case 0x18a:
samsung_kbd_mouse_map_key_clear(KEY_MAIL);
break;
case 0x196:
samsung_kbd_mouse_map_key_clear(KEY_WWW);
break;
case 0x19e:
samsung_kbd_mouse_map_key_clear(KEY_SCREENLOCK);
break;
case 0x221:
samsung_kbd_mouse_map_key_clear(KEY_SEARCH);
break;
case 0x223:
samsung_kbd_mouse_map_key_clear(KEY_HOMEPAGE);
break;
/* Smtart Voice Key */
case 0x300:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY13);
break;
/* RECENTAPPS */
case 0x301:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY1);
break;
/* APPLICATION */
case 0x302:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY2);
break;
/* Voice search */
case 0x305:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY4);
break;
/* QPANEL on/off */
case 0x306:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY5);
break;
/* SIP on/off */
case 0x307:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY3);
break;
/* LANG */
case 0x308:
samsung_kbd_mouse_map_key_clear(KEY_LANGUAGE);
break;
case 0x30a:
samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSDOWN);
break;
case 0x30b:
samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSUP);
break;
default:
return 0;
}
}
return 1;
}
static int samsung_gamepad_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
if (!(HID_UP_BUTTON == (usage->hid & HID_USAGE_PAGE) ||
HID_UP_CONSUMER == (usage->hid & HID_USAGE_PAGE)))
return 0;
dbg_hid("samsung wireless gamepad input mapping event [0x%x], %ld, %ld, [0x%x]\n",
usage->hid & HID_USAGE, hi->input->evbit[0], hi->input->absbit[0], usage->hid & HID_USAGE_PAGE);
if (HID_UP_BUTTON == (usage->hid & HID_USAGE_PAGE)) {
switch (usage->hid & HID_USAGE) {
case 0x01:
samsung_kbd_mouse_map_key_clear(BTN_A);
break;
case 0x02:
samsung_kbd_mouse_map_key_clear(BTN_B);
break;
case 0x03:
samsung_kbd_mouse_map_key_clear(BTN_C);
break;
case 0x04:
samsung_kbd_mouse_map_key_clear(BTN_X);
break;
case 0x05:
samsung_kbd_mouse_map_key_clear(BTN_Y);
break;
case 0x06:
samsung_kbd_mouse_map_key_clear(BTN_Z);
break;
case 0x07:
samsung_kbd_mouse_map_key_clear(BTN_TL);
break;
case 0x08:
samsung_kbd_mouse_map_key_clear(BTN_TR);
break;
case 0x09:
samsung_kbd_mouse_map_key_clear(BTN_TL2);
break;
case 0x0a:
samsung_kbd_mouse_map_key_clear(BTN_TR2);
break;
case 0x0b:
samsung_kbd_mouse_map_key_clear(BTN_SELECT);
break;
case 0x0c:
samsung_kbd_mouse_map_key_clear(BTN_START);
break;
case 0x0d:
samsung_kbd_mouse_map_key_clear(BTN_MODE);
break;
case 0x0e:
samsung_kbd_mouse_map_key_clear(BTN_THUMBL);
break;
case 0x0f:
samsung_kbd_mouse_map_key_clear(BTN_THUMBR);
break;
case 0x10:
samsung_kbd_mouse_map_key_clear(0x13f);
break;
default:
return 0;
}
}
if (HID_UP_CONSUMER == (usage->hid & HID_USAGE_PAGE)) {
switch (usage->hid & HID_USAGE) {
case 0x040:
samsung_kbd_mouse_map_key_clear(KEY_MENU);
break;
case 0x223:
samsung_kbd_mouse_map_key_clear(KEY_HOMEPAGE);
break;
case 0x224:
samsung_kbd_mouse_map_key_clear(KEY_BACK);
break;
/* Screen Capture */
case 0x303:
samsung_kbd_mouse_map_key_clear(KEY_SYSRQ);
break;
default:
return 0;
}
}
return 1;
}
static int samsung_actionmouse_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
dbg_hid("samsung wireless actionmouse input mapping event [0x%x], [0x%x], %ld, %ld, [0x%x]\n",
usage->hid, usage->hid & HID_USAGE, hi->input->evbit[0], hi->input->absbit[0],
usage->hid & HID_USAGE_PAGE);
if (((usage->hid & HID_USAGE_PAGE) != HID_UP_CONSUMER) && ((usage->hid & HID_USAGE_PAGE) != HID_UP_BUTTON))
return 0;
switch (usage->hid & HID_USAGE) {
case 0x301:
samsung_kbd_mouse_map_key_clear(254);
break;
default:
return 0;
}
return 1;
}
static int samsung_universal_kbd_input_mapping(struct hid_device *hdev,
struct hid_input *hi, struct hid_field *field, struct hid_usage *usage,
unsigned long **bit, int *max)
{
if (!(HID_UP_CONSUMER == (usage->hid & HID_USAGE_PAGE) ||
HID_UP_KEYBOARD == (usage->hid & HID_USAGE_PAGE)))
return 0;
dbg_hid("samsung wireless keyboard input mapping event [0x%x]\n",
usage->hid & HID_USAGE);
if (HID_UP_KEYBOARD == (usage->hid & HID_USAGE_PAGE)) {
set_bit(EV_REP, hi->input->evbit);
switch (usage->hid & HID_USAGE) {
case 0x32:
samsung_kbd_mouse_map_key_clear(KEY_BACKSLASH);
break;
case 0x64:
samsung_kbd_mouse_map_key_clear(KEY_102ND);
break;
/* Only for BR keyboard */
case 0x87:
samsung_kbd_mouse_map_key_clear(KEY_RO);
break;
default:
return 0;
}
}
if (HID_UP_CONSUMER == (usage->hid & HID_USAGE_PAGE)) {
switch (usage->hid & HID_USAGE) {
/* report 2 */
/* MENU */
case 0x040:
samsung_kbd_mouse_map_key_clear(KEY_MENU);
break;
case 0x18a:
samsung_kbd_mouse_map_key_clear(KEY_MAIL);
break;
case 0x196:
samsung_kbd_mouse_map_key_clear(KEY_WWW);
break;
case 0x19e:
samsung_kbd_mouse_map_key_clear(KEY_SCREENLOCK);
break;
case 0x221:
samsung_kbd_mouse_map_key_clear(KEY_SEARCH);
break;
case 0x223:
samsung_kbd_mouse_map_key_clear(KEY_HOMEPAGE);
break;
/* RECENTAPPS */
case 0x301:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY1);
break;
/* APPLICATION */
case 0x302:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY2);
break;
/* Voice search */
case 0x305:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY4);
break;
/* QPANEL on/off */
case 0x306:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY5);
break;
/* SIP on/off */
case 0x307:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY3);
break;
/* LANG */
case 0x308:
samsung_kbd_mouse_map_key_clear(KEY_LANGUAGE);
break;
case 0x30a:
samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSDOWN);
break;
case 0x070:
samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSDOWN);
break;
case 0x30b:
samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSUP);
break;
case 0x06f:
samsung_kbd_mouse_map_key_clear(KEY_BRIGHTNESSUP);
break;
/* S-Finder */
case 0x304:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY7);
break;
/* Screen Capture */
case 0x303:
samsung_kbd_mouse_map_key_clear(KEY_SYSRQ);
break;
/* Multi Window */
case 0x309:
samsung_kbd_mouse_map_key_clear(BTN_TRIGGER_HAPPY9);
break;
/* HotKey App 1 */
case 0x071:
samsung_kbd_mouse_map_key_clear(0x2f5);
break;
/* HotKey App 2 */
case 0x072:
samsung_kbd_mouse_map_key_clear(0x2f6);
break;
/* HotKey App 3 */
case 0x073:
samsung_kbd_mouse_map_key_clear(0x2f7);
break;
/* Dex */
case 0x06e:
samsung_kbd_mouse_map_key_clear(0x2bd);
break;
default:
return 0;
}
}
return 1;
}
static __u8 *samsung_report_fixup(struct hid_device *hdev, __u8 *rdesc,
unsigned int *rsize)
{
if (USB_DEVICE_ID_SAMSUNG_IR_REMOTE == hdev->product)
if (hdev->product == USB_DEVICE_ID_SAMSUNG_IR_REMOTE && hid_is_usb(hdev))
rdesc = samsung_irda_report_fixup(hdev, rdesc, rsize);
return rdesc;
}
@@ -139,9 +483,24 @@ static int samsung_input_mapping(struct hid_device *hdev, struct hid_input *hi,
{
int ret = 0;
if (USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE == hdev->product)
if (hdev->product == USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE && hid_is_usb(hdev))
ret = samsung_kbd_mouse_input_mapping(hdev,
hi, field, usage, bit, max);
else if (hdev->product == USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD)
ret = samsung_kbd_input_mapping(hdev,
hi, field, usage, bit, max);
else if (hdev->product == USB_DEVICE_ID_SAMSUNG_WIRELESS_GAMEPAD)
ret = samsung_gamepad_input_mapping(hdev,
hi, field, usage, bit, max);
else if (hdev->product == USB_DEVICE_ID_SAMSUNG_WIRELESS_ACTIONMOUSE)
ret = samsung_actionmouse_input_mapping(hdev,
hi, field, usage, bit, max);
else if (hdev->product == USB_DEVICE_ID_SAMSUNG_WIRELESS_UNIVERSAL_KBD)
ret = samsung_universal_kbd_input_mapping(hdev,
hi, field, usage, bit, max);
else if (hdev->product == USB_DEVICE_ID_SAMSUNG_WIRELESS_MULTI_HOGP_KBD)
ret = samsung_universal_kbd_input_mapping(hdev,
hi, field, usage, bit, max);
return ret;
}
@@ -152,16 +511,17 @@ static int samsung_probe(struct hid_device *hdev,
int ret;
unsigned int cmask = HID_CONNECT_DEFAULT;
if (!hid_is_usb(hdev))
return -EINVAL;
ret = hid_parse(hdev);
if (ret) {
hid_err(hdev, "parse failed\n");
goto err_free;
}
if (USB_DEVICE_ID_SAMSUNG_IR_REMOTE == hdev->product) {
if (hdev->product == USB_DEVICE_ID_SAMSUNG_IR_REMOTE) {
if (!hid_is_usb(hdev)) {
ret = -EINVAL;
goto err_free;
}
if (hdev->rsize == 184) {
/* disable hidinput, force hiddev */
cmask = (cmask & ~HID_CONNECT_HIDINPUT) |
@@ -183,6 +543,11 @@ err_free:
static const struct hid_device_id samsung_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_IR_REMOTE) },
{ HID_USB_DEVICE(USB_VENDOR_ID_SAMSUNG, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD_MOUSE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SAMSUNG_ELECTRONICS, USB_DEVICE_ID_SAMSUNG_WIRELESS_KBD) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SAMSUNG_ELECTRONICS, USB_DEVICE_ID_SAMSUNG_WIRELESS_GAMEPAD) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SAMSUNG_ELECTRONICS, USB_DEVICE_ID_SAMSUNG_WIRELESS_ACTIONMOUSE) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SAMSUNG_ELECTRONICS, USB_DEVICE_ID_SAMSUNG_WIRELESS_UNIVERSAL_KBD) },
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_SAMSUNG_ELECTRONICS, USB_DEVICE_ID_SAMSUNG_WIRELESS_MULTI_HOGP_KBD) },
{ }
};
MODULE_DEVICE_TABLE(hid, samsung_devices);
+1
View File
@@ -34,6 +34,7 @@
#define RPL_S_DEVICE_ID 0x7A78
#define MTL_P_DEVICE_ID 0x7E45
#define ARL_H_DEVICE_ID 0x7745
#define ARL_S_DEVICE_ID 0x7F78
#define REVISION_ID_CHT_A0 0x6
#define REVISION_ID_CHT_Ax_SI 0x0
+1
View File
@@ -45,6 +45,7 @@ static const struct pci_device_id ish_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, RPL_S_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, MTL_P_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ARL_H_DEVICE_ID)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, ARL_S_DEVICE_ID)},
{0, }
};
MODULE_DEVICE_TABLE(pci, ish_pci_tbl);
+4 -4
View File
@@ -2990,11 +2990,11 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
wacom_wac_battery_pre_report(hdev, report);
if (pad_in_hid_field && wacom->wacom_wac.pad_input)
if (pad_in_hid_field && wacom_wac->pad_input)
wacom_wac_pad_pre_report(hdev, report);
if (pen_in_hid_field && wacom->wacom_wac.pen_input)
if (pen_in_hid_field && wacom_wac->pen_input)
wacom_wac_pen_pre_report(hdev, report);
if (finger_in_hid_field && wacom->wacom_wac.touch_input)
if (finger_in_hid_field && wacom_wac->touch_input)
wacom_wac_finger_pre_report(hdev, report);
for (r = 0; r < report->maxfield; r++) {
@@ -3010,7 +3010,7 @@ void wacom_wac_report(struct hid_device *hdev, struct hid_report *report)
wacom_wac_battery_report(hdev, report);
if (true_pad && wacom->wacom_wac.pad_input)
if (true_pad && wacom_wac->pad_input)
wacom_wac_pad_report(hdev, report, field);
}
-1
View File
@@ -309,7 +309,6 @@ struct hid_data {
bool confidence;
int x;
int y;
int pressure;
int width;
int height;
int id;
+2 -2
View File
@@ -683,9 +683,9 @@ struct hid_device { /* device report descriptor */
unsigned int id; /* system unique id */
#ifdef CONFIG_BPF
#ifdef CONFIG_HID_BPF
struct hid_bpf bpf; /* hid-bpf data */
#endif /* CONFIG_BPF */
#endif /* CONFIG_HID_BPF */
};
void hiddev_free(struct kref *ref);