diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/hid/Kconfig | 11 | ||||
-rw-r--r-- | drivers/hid/Makefile | 1 | ||||
-rw-r--r-- | drivers/hid/amd-sfh-hid/amd_sfh_pcie.c | 40 | ||||
-rw-r--r-- | drivers/hid/amd-sfh-hid/amd_sfh_pcie.h | 1 | ||||
-rw-r--r-- | drivers/hid/hid-alps.c | 1 | ||||
-rw-r--r-- | drivers/hid/hid-asus.c | 3 | ||||
-rw-r--r-- | drivers/hid/hid-cp2112.c | 22 | ||||
-rw-r--r-- | drivers/hid/hid-elan.c | 17 | ||||
-rw-r--r-- | drivers/hid/hid-ft260.c | 1054 | ||||
-rw-r--r-- | drivers/hid/hid-google-hammer.c | 2 | ||||
-rw-r--r-- | drivers/hid/hid-ids.h | 3 | ||||
-rw-r--r-- | drivers/hid/i2c-hid/i2c-hid-acpi.c | 52 | ||||
-rw-r--r-- | drivers/hid/usbhid/hiddev.c | 6 | ||||
-rw-r--r-- | drivers/hid/wacom_wac.c | 8 |
14 files changed, 1159 insertions, 62 deletions
diff --git a/drivers/hid/Kconfig b/drivers/hid/Kconfig index 786b71ef7738..b279c6130bc2 100644 --- a/drivers/hid/Kconfig +++ b/drivers/hid/Kconfig @@ -351,6 +351,17 @@ config HID_EZKEY help Support for Ezkey BTC 8193 keyboard. +config HID_FT260 + tristate "FTDI FT260 USB HID to I2C host support" + depends on USB_HID && HIDRAW && I2C + help + Provides I2C host adapter functionality over USB-HID through FT260 + device. The customizable USB descriptor fields are exposed as sysfs + attributes. + + To compile this driver as a module, choose M here: the module + will be called hid-ft260. + config HID_GEMBIRD tristate "Gembird Joypad" depends on HID diff --git a/drivers/hid/Makefile b/drivers/hid/Makefile index c4f6d5c613dc..6e24c37132ec 100644 --- a/drivers/hid/Makefile +++ b/drivers/hid/Makefile @@ -46,6 +46,7 @@ obj-$(CONFIG_HID_ELAN) += hid-elan.o obj-$(CONFIG_HID_ELECOM) += hid-elecom.o obj-$(CONFIG_HID_ELO) += hid-elo.o obj-$(CONFIG_HID_EZKEY) += hid-ezkey.o +obj-$(CONFIG_HID_FT260) += hid-ft260.o obj-$(CONFIG_HID_GEMBIRD) += hid-gembird.o obj-$(CONFIG_HID_GFRM) += hid-gfrm.o obj-$(CONFIG_HID_GLORIOUS) += hid-glorious.o diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c index dbac16641662..ddecc84fd6f0 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.c @@ -10,6 +10,7 @@ #include <linux/bitops.h> #include <linux/delay.h> #include <linux/dma-mapping.h> +#include <linux/dmi.h> #include <linux/interrupt.h> #include <linux/io-64-nonatomic-lo-hi.h> #include <linux/module.h> @@ -22,9 +23,13 @@ #define ACEL_EN BIT(0) #define GYRO_EN BIT(1) -#define MAGNO_EN BIT(2) +#define MAGNO_EN BIT(2) #define ALS_EN BIT(19) +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"); + void amd_start_sensor(struct amd_mp2_dev *privdata, struct amd_mp2_sensor_info info) { union sfh_cmd_param cmd_param; @@ -73,12 +78,41 @@ void amd_stop_all_sensors(struct amd_mp2_dev *privdata) writel(cmd_base.ul, privdata->mmio + AMD_C2P_MSG0); } +static const struct dmi_system_id dmi_sensor_mask_overrides[] = { + { + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY x360 Convertible 13-ag0xxx"), + }, + .driver_data = (void *)(ACEL_EN | MAGNO_EN), + }, + { + .matches = { + DMI_MATCH(DMI_PRODUCT_NAME, "HP ENVY x360 Convertible 15-cp0xxx"), + }, + .driver_data = (void *)(ACEL_EN | MAGNO_EN), + }, + { } +}; + int amd_mp2_get_sensor_num(struct amd_mp2_dev *privdata, u8 *sensor_id) { int activestatus, num_of_sensors = 0; + const struct dmi_system_id *dmi_id; + u32 activecontrolstatus; + + if (sensor_mask_override == -1) { + dmi_id = dmi_first_match(dmi_sensor_mask_overrides); + if (dmi_id) + sensor_mask_override = (long)dmi_id->driver_data; + } + + if (sensor_mask_override >= 0) { + activestatus = sensor_mask_override; + } else { + activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3); + activestatus = activecontrolstatus >> 4; + } - privdata->activecontrolstatus = readl(privdata->mmio + AMD_P2C_MSG3); - activestatus = privdata->activecontrolstatus >> 4; if (ACEL_EN & activestatus) sensor_id[num_of_sensors++] = accel_idx; diff --git a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h index 8f8d19b2cfe5..489415f7c22c 100644 --- a/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h +++ b/drivers/hid/amd-sfh-hid/amd_sfh_pcie.h @@ -61,7 +61,6 @@ struct amd_mp2_dev { struct pci_dev *pdev; struct amdtp_cl_data *cl_data; void __iomem *mmio; - u32 activecontrolstatus; }; struct amd_mp2_sensor_info { diff --git a/drivers/hid/hid-alps.c b/drivers/hid/hid-alps.c index 3feaece13ade..6b665931147d 100644 --- a/drivers/hid/hid-alps.c +++ b/drivers/hid/hid-alps.c @@ -761,6 +761,7 @@ static int alps_input_configured(struct hid_device *hdev, struct hid_input *hi) if (input_register_device(data->input2)) { input_free_device(input2); + ret = -ENOENT; goto exit; } } diff --git a/drivers/hid/hid-asus.c b/drivers/hid/hid-asus.c index 1dfe184ebf5a..2ab22b925941 100644 --- a/drivers/hid/hid-asus.c +++ b/drivers/hid/hid-asus.c @@ -1222,6 +1222,9 @@ static const struct hid_device_id asus_devices[] = { USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD), QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, + USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2), + QUIRK_USE_KBD_BACKLIGHT | QUIRK_ROG_NKEY_KEYBOARD }, + { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, USB_DEVICE_ID_ASUSTEK_T100TA_KEYBOARD), QUIRK_T100_KEYBOARD | QUIRK_NO_CONSUMER_USAGES }, { HID_USB_DEVICE(USB_VENDOR_ID_ASUSTEK, diff --git a/drivers/hid/hid-cp2112.c b/drivers/hid/hid-cp2112.c index 21e15627a461..477baa30889c 100644 --- a/drivers/hid/hid-cp2112.c +++ b/drivers/hid/hid-cp2112.c @@ -161,6 +161,7 @@ struct cp2112_device { atomic_t read_avail; atomic_t xfer_avail; struct gpio_chip gc; + struct irq_chip irq; u8 *in_out_buffer; struct mutex lock; @@ -1175,16 +1176,6 @@ static int cp2112_gpio_irq_type(struct irq_data *d, unsigned int type) return 0; } -static struct irq_chip cp2112_gpio_irqchip = { - .name = "cp2112-gpio", - .irq_startup = cp2112_gpio_irq_startup, - .irq_shutdown = cp2112_gpio_irq_shutdown, - .irq_ack = cp2112_gpio_irq_ack, - .irq_mask = cp2112_gpio_irq_mask, - .irq_unmask = cp2112_gpio_irq_unmask, - .irq_set_type = cp2112_gpio_irq_type, -}; - static int __maybe_unused cp2112_allocate_irq(struct cp2112_device *dev, int pin) { @@ -1339,8 +1330,17 @@ static int cp2112_probe(struct hid_device *hdev, const struct hid_device_id *id) dev->gc.can_sleep = 1; dev->gc.parent = &hdev->dev; + dev->irq.name = "cp2112-gpio"; + dev->irq.irq_startup = cp2112_gpio_irq_startup; + dev->irq.irq_shutdown = cp2112_gpio_irq_shutdown; + dev->irq.irq_ack = cp2112_gpio_irq_ack; + dev->irq.irq_mask = cp2112_gpio_irq_mask; + dev->irq.irq_unmask = cp2112_gpio_irq_unmask; + dev->irq.irq_set_type = cp2112_gpio_irq_type; + dev->irq.flags = IRQCHIP_MASK_ON_SUSPEND; + girq = &dev->gc.irq; - girq->chip = &cp2112_gpio_irqchip; + girq->chip = &dev->irq; /* The event comes from the outside so no parent handler */ girq->parent_handler = NULL; girq->num_parents = 0; diff --git a/drivers/hid/hid-elan.c b/drivers/hid/hid-elan.c index dae193749d44..021049805bb7 100644 --- a/drivers/hid/hid-elan.c +++ b/drivers/hid/hid-elan.c @@ -410,15 +410,6 @@ static int elan_start_multitouch(struct hid_device *hdev) return 0; } -static enum led_brightness elan_mute_led_get_brigtness(struct led_classdev *led_cdev) -{ - struct device *dev = led_cdev->dev->parent; - struct hid_device *hdev = to_hid_device(dev); - struct elan_drvdata *drvdata = hid_get_drvdata(hdev); - - return drvdata->mute_led_state; -} - static int elan_mute_led_set_brigtness(struct led_classdev *led_cdev, enum led_brightness value) { @@ -445,8 +436,9 @@ static int elan_mute_led_set_brigtness(struct led_classdev *led_cdev, kfree(dmabuf); if (ret != ELAN_LED_REPORT_SIZE) { - hid_err(hdev, "Failed to set mute led brightness: %d\n", ret); - return ret; + if (ret != -ENODEV) + hid_err(hdev, "Failed to set mute led brightness: %d\n", ret); + return ret < 0 ? ret : -EIO; } drvdata->mute_led_state = led_state; @@ -459,9 +451,10 @@ static int elan_init_mute_led(struct hid_device *hdev) struct led_classdev *mute_led = &drvdata->mute_led; mute_led->name = "elan:red:mute"; - mute_led->brightness_get = elan_mute_led_get_brigtness; + mute_led->default_trigger = "audio-mute"; mute_led->brightness_set_blocking = elan_mute_led_set_brigtness; mute_led->max_brightness = LED_ON; + mute_led->flags = LED_HW_PLUGGABLE; mute_led->dev = &hdev->dev; return devm_led_classdev_register(&hdev->dev, mute_led); diff --git a/drivers/hid/hid-ft260.c b/drivers/hid/hid-ft260.c new file mode 100644 index 000000000000..a5751607ce24 --- /dev/null +++ b/drivers/hid/hid-ft260.c @@ -0,0 +1,1054 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * hid-ft260.c - FTDI FT260 USB HID to I2C host bridge + * + * Copyright (c) 2021, Michael Zaidman <michaelz@xsightlabs.com> + * + * Data Sheet: + * https://www.ftdichip.com/Support/Documents/DataSheets/ICs/DS_FT260.pdf + */ + +#include "hid-ids.h" +#include <linux/hidraw.h> +#include <linux/i2c.h> +#include <linux/module.h> +#include <linux/usb.h> + +#ifdef DEBUG +static int ft260_debug = 1; +#else +static int ft260_debug; +#endif +module_param_named(debug, ft260_debug, int, 0600); +MODULE_PARM_DESC(debug, "Toggle FT260 debugging messages"); + +#define ft260_dbg(format, arg...) \ + do { \ + if (ft260_debug) \ + pr_info("%s: " format, __func__, ##arg); \ + } while (0) + +#define FT260_REPORT_MAX_LENGTH (64) +#define FT260_I2C_DATA_REPORT_ID(len) (FT260_I2C_REPORT_MIN + (len - 1) / 4) +/* + * The input report format assigns 62 bytes for the data payload, but ft260 + * returns 60 and 2 in two separate transactions. To minimize transfer time + * in reading chunks mode, set the maximum read payload length to 60 bytes. + */ +#define FT260_RD_DATA_MAX (60) +#define FT260_WR_DATA_MAX (60) + +/* + * Device interface configuration. + * The FT260 has 2 interfaces that are controlled by DCNF0 and DCNF1 pins. + * First implementes USB HID to I2C bridge function and + * second - USB HID to UART bridge function. + */ +enum { + FT260_MODE_ALL = 0x00, + FT260_MODE_I2C = 0x01, + FT260_MODE_UART = 0x02, + FT260_MODE_BOTH = 0x03, +}; + +/* Control pipe */ +enum { + FT260_GET_RQST_TYPE = 0xA1, + FT260_GET_REPORT = 0x01, + FT260_SET_RQST_TYPE = 0x21, + FT260_SET_REPORT = 0x09, + FT260_FEATURE = 0x03, +}; + +/* Report IDs / Feature In */ +enum { + FT260_CHIP_VERSION = 0xA0, + FT260_SYSTEM_SETTINGS = 0xA1, + FT260_I2C_STATUS = 0xC0, + FT260_I2C_READ_REQ = 0xC2, + FT260_I2C_REPORT_MIN = 0xD0, + FT260_I2C_REPORT_MAX = 0xDE, + FT260_GPIO = 0xB0, + FT260_UART_INTERRUPT_STATUS = 0xB1, + FT260_UART_STATUS = 0xE0, + FT260_UART_RI_DCD_STATUS = 0xE1, + FT260_UART_REPORT = 0xF0, +}; + +/* Feature Out */ +enum { + FT260_SET_CLOCK = 0x01, + FT260_SET_I2C_MODE = 0x02, + FT260_SET_UART_MODE = 0x03, + FT260_ENABLE_INTERRUPT = 0x05, + FT260_SELECT_GPIO2_FUNC = 0x06, + FT260_ENABLE_UART_DCD_RI = 0x07, + FT260_SELECT_GPIOA_FUNC = 0x08, + FT260_SELECT_GPIOG_FUNC = 0x09, + FT260_SET_INTERRUPT_TRIGGER = 0x0A, + FT260_SET_SUSPEND_OUT_POLAR = 0x0B, + FT260_ENABLE_UART_RI_WAKEUP = 0x0C, + FT260_SET_UART_RI_WAKEUP_CFG = 0x0D, + FT260_SET_I2C_RESET = 0x20, + FT260_SET_I2C_CLOCK_SPEED = 0x22, + FT260_SET_UART_RESET = 0x40, + FT260_SET_UART_CONFIG = 0x41, + FT260_SET_UART_BAUD_RATE = 0x42, + FT260_SET_UART_DATA_BIT = 0x43, + FT260_SET_UART_PARITY = 0x44, + FT260_SET_UART_STOP_BIT = 0x45, + FT260_SET_UART_BREAKING = 0x46, + FT260_SET_UART_XON_XOFF = 0x49, +}; + +/* Response codes in I2C status report */ +enum { + FT260_I2C_STATUS_SUCCESS = 0x00, + FT260_I2C_STATUS_CTRL_BUSY = 0x01, + FT260_I2C_STATUS_ERROR = 0x02, + FT260_I2C_STATUS_ADDR_NO_ACK = 0x04, + FT260_I2C_STATUS_DATA_NO_ACK = 0x08, + FT260_I2C_STATUS_ARBITR_LOST = 0x10, + FT260_I2C_STATUS_CTRL_IDLE = 0x20, + FT260_I2C_STATUS_BUS_BUSY = 0x40, +}; + +/* I2C Conditions flags */ +enum { + FT260_FLAG_NONE = 0x00, + FT260_FLAG_START = 0x02, + FT260_FLAG_START_REPEATED = 0x03, + FT260_FLAG_STOP = 0x04, + FT260_FLAG_START_STOP = 0x06, + FT260_FLAG_START_STOP_REPEATED = 0x07, +}; + +#define FT260_SET_REQUEST_VALUE(report_id) ((FT260_FEATURE << 8) | report_id) + +/* Feature In reports */ + +struct ft260_get_chip_version_report { + u8 report; /* FT260_CHIP_VERSION */ + u8 chip_code[4]; /* FTDI chip identification code */ + u8 reserved[8]; +} __packed; + +struct ft260_get_system_status_report { + u8 report; /* FT260_SYSTEM_SETTINGS */ + u8 chip_mode; /* DCNF0 and DCNF1 status, bits 0-1 */ + u8 clock_ctl; /* 0 - 12MHz, 1 - 24MHz, 2 - 48MHz */ + u8 suspend_status; /* 0 - not suspended, 1 - suspended */ + u8 pwren_status; /* 0 - FT260 is not ready, 1 - ready */ + u8 i2c_enable; /* 0 - disabled, 1 - enabled */ + u8 uart_mode; /* 0 - OFF; 1 - RTS_CTS, 2 - DTR_DSR, */ + /* 3 - XON_XOFF, 4 - No flow control */ + u8 hid_over_i2c_en; /* 0 - disabled, 1 - enabled */ + u8 gpio2_function; /* 0 - GPIO, 1 - SUSPOUT, */ + /* 2 - PWREN, 4 - TX_LED */ + u8 gpioA_function; /* 0 - GPIO, 3 - TX_ACTIVE, 4 - TX_LED */ + u8 gpioG_function; /* 0 - GPIO, 2 - PWREN, */ + /* 5 - RX_LED, 6 - BCD_DET */ + u8 suspend_out_pol; /* 0 - active-high, 1 - active-low */ + u8 enable_wakeup_int; /* 0 - disabled, 1 - enabled */ + u8 intr_cond; /* Interrupt trigger conditions */ + u8 power_saving_en; /* 0 - disabled, 1 - enabled */ + u8 reserved[10]; +} __packed; + +struct ft260_get_i2c_status_report { + u8 report; /* FT260_I2C_STATUS */ + u8 bus_status; /* I2C bus status */ + __le16 clock; /* I2C bus clock in range 60-3400 KHz */ + u8 reserved; +} __packed; + +/* Feature Out reports */ + +struct ft260_set_system_clock_report { + u8 report; /* FT260_SYSTEM_SETTINGS */ + u8 request; /* FT260_SET_CLOCK */ + u8 clock_ctl; /* 0 - 12MHz, 1 - 24MHz, 2 - 48MHz */ +} __packed; + +struct ft260_set_i2c_mode_report { + u8 report; /* FT260_SYSTEM_SETTINGS */ + u8 request; /* FT260_SET_I2C_MODE */ + u8 i2c_enable; /* 0 - disabled, 1 - enabled */ +} __packed; + +struct ft260_set_uart_mode_report { + u8 report; /* FT260_SYSTEM_SETTINGS */ + u8 request; /* FT260_SET_UART_MODE */ + u8 uart_mode; /* 0 - OFF; 1 - RTS_CTS, 2 - DTR_DSR, */ + /* 3 - XON_XOFF, 4 - No flow control */ +} __packed; + +struct ft260_set_i2c_reset_report { + u8 report; /* FT260_SYSTEM_SETTINGS */ + u8 request; /* FT260_SET_I2C_RESET */ +} __packed; + +struct ft260_set_i2c_speed_report { + u8 report; /* FT260_SYSTEM_SETTINGS */ + u8 request; /* FT260_SET_I2C_CLOCK_SPEED */ + __le16 clock; /* I2C bus clock in range 60-3400 KHz */ +} __packed; + +/* Data transfer reports */ + +struct ft260_i2c_write_request_report { + u8 report; /* FT260_I2C_REPORT */ + u8 address; /* 7-bit I2C address */ + u8 flag; /* I2C transaction condition */ + u8 length; /* data payload length */ + u8 data[60]; /* data payload */ +} __packed; + +struct ft260_i2c_read_request_report { + u8 report; /* FT260_I2C_READ_REQ */ + u8 address; /* 7-bit I2C address */ + u8 flag; /* I2C transaction condition */ + __le16 length; /* data payload length */ +} __packed; + +struct ft260_i2c_input_report { + u8 report; /* FT260_I2C_REPORT */ + u8 length; /* data payload length */ + u8 data[2]; /* data payload */ +} __packed; + +static const struct hid_device_id ft260_devices[] = { + { HID_USB_DEVICE(USB_VENDOR_ID_FUTURE_TECHNOLOGY, + USB_DEVICE_ID_FT260) }, + { /* END OF LIST */ } +}; +MODULE_DEVICE_TABLE(hid, ft260_devices); + +struct ft260_device { + struct i2c_adapter adap; + struct hid_device *hdev; + struct completion wait; + struct mutex lock; + u8 write_buf[FT260_REPORT_MAX_LENGTH]; + u8 *read_buf; + u16 read_idx; + u16 read_len; + u16 clock; +}; + +static int ft260_hid_feature_report_get(struct hid_device *hdev, + unsigned char report_id, u8 *data, + size_t len) +{ + u8 *buf; + int ret; + + buf = kmalloc(len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = hid_hw_raw_request(hdev, report_id, buf, len, HID_FEATURE_REPORT, + HID_REQ_GET_REPORT); + memcpy(data, buf, len); + kfree(buf); + return ret; +} + +static int ft260_hid_feature_report_set(struct hid_device *hdev, u8 *data, + size_t len) +{ + u8 *buf; + int ret; + + buf = kmemdup(data, len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + buf[0] = FT260_SYSTEM_SETTINGS; + + ret = hid_hw_raw_request(hdev, buf[0], buf, len, HID_FEATURE_REPORT, + HID_REQ_SET_REPORT); + + kfree(buf); + return ret; +} + +static int ft260_i2c_reset(struct hid_device *hdev) +{ + struct ft260_set_i2c_reset_report report; + int ret; + + report.request = FT260_SET_I2C_RESET; + + ret = ft260_hid_feature_report_set(hdev, (u8 *)&report, sizeof(report)); + if (ret < 0) { + hid_err(hdev, "failed to reset I2C controller: %d\n", ret); + return ret; + } + + ft260_dbg("done\n"); + return ret; +} + +static int ft260_xfer_status(struct ft260_device *dev) +{ + struct hid_device *hdev = dev->hdev; + struct ft260_get_i2c_status_report report; + int ret; + + ret = ft260_hid_feature_report_get(hdev, FT260_I2C_STATUS, + (u8 *)&report, sizeof(report)); + if (ret < 0) { + hid_err(hdev, "failed to retrieve status: %d\n", ret); + return ret; + } + + dev->clock = le16_to_cpu(report.clock); + ft260_dbg("bus_status %#02x, clock %u\n", report.bus_status, + dev->clock); + + if (report.bus_status & FT260_I2C_STATUS_CTRL_BUSY) + return -EAGAIN; + + if (report.bus_status & FT260_I2C_STATUS_BUS_BUSY) + return -EBUSY; + + if (report.bus_status & FT260_I2C_STATUS_ERROR) + return -EIO; + + ret = -EIO; + + if (report.bus_status & FT260_I2C_STATUS_ADDR_NO_ACK) + ft260_dbg("unacknowledged address\n"); + + if (report.bus_status & FT260_I2C_STATUS_DATA_NO_ACK) + ft260_dbg("unacknowledged data\n"); + + if (report.bus_status & FT260_I2C_STATUS_ARBITR_LOST) + ft260_dbg("arbitration loss\n"); + + if (report.bus_status & FT260_I2C_STATUS_CTRL_IDLE) + ret = 0; + + return ret; +} + +static int ft260_hid_output_report(struct hid_device *hdev, u8 *data, + size_t len) +{ + u8 *buf; + int ret; + + buf = kmemdup(data, len, GFP_KERNEL); + if (!buf) + return -ENOMEM; + + ret = hid_hw_output_report(hdev, buf, len); + + kfree(buf); + return ret; +} + +static int ft260_hid_output_report_check_status(struct ft260_device *dev, + u8 *data, int len) +{ + int ret, usec, try = 3; + struct hid_device *hdev = dev->hdev; + + ret = ft260_hid_output_report(hdev, data, len); + if (ret < 0) { + hid_err(hdev, "%s: failed to start transfer, ret %d\n", + __func__, ret); + ft260_i2c_reset(hdev); + return ret; + } + + /* transfer time = 1 / clock(KHz) * 10 bits * bytes */ + usec = 10000 / dev->clock * len; + usleep_range(usec, usec + 100); + ft260_dbg("wait %d usec, len %d\n", usec, len); + do { + ret = ft260_xfer_status(dev); + if (ret != -EAGAIN) + break; + } while (--try); + + if (ret == 0 || ret == -EBUSY) + return 0; + + ft260_i2c_reset(hdev); + return -EIO; +} + +static int ft260_i2c_write(struct ft260_device *dev, u8 addr, u8 *data, + int data_len, u8 flag) +{ + int len, ret, idx = 0; + struct hid_device *hdev = dev->hdev; + struct ft260_i2c_write_request_report *rep = + (struct ft260_i2c_write_request_report *)dev->write_buf; + + do { + if (data_len <= FT260_WR_DATA_MAX) + len = data_len; + else + len = FT260_WR_DATA_MAX; + + rep->report = FT260_I2C_DATA_REPORT_ID(len); + rep->address = addr; + rep->length = len; + rep->flag = flag; + + memcpy(rep->data, &data[idx], len); + + ft260_dbg("rep %#02x addr %#02x off %d len %d d[0] %#02x\n", + rep->report, addr, idx, len, data[0]); + + ret = ft260_hid_output_report_check_status(dev, (u8 *)rep, + len + 4); + if (ret < 0) { + hid_err(hdev, "%s: failed to start transfer, ret %d\n", + __func__, ret); + return ret; + } + + data_len -= len; + idx += len; + + } while (data_len > 0); + + return 0; +} + +static int ft260_smbus_write(struct ft260_device *dev, u8 addr, u8 cmd, + u8 *data, u8 data_len, u8 flag) +{ + int ret = 0; + int len = 4; + + struct ft260_i2c_write_request_report *rep = + (struct ft260_i2c_write_request_report *)dev->write_buf; + + rep->address = addr; + rep->data[0] = cmd; + rep->length = data_len + 1; + rep->flag = flag; + len += rep->length; + + rep->report = FT260_I2C_DATA_REPORT_ID(len); + + if (data_len > 0) + memcpy(&rep->data[1], data, data_len); + + ft260_dbg("rep %#02x addr %#02x cmd %#02x datlen %d replen %d\n", + rep->report, addr, cmd, rep->length, len); + + ret = ft260_hid_output_report_check_status(dev, (u8 *)rep, len); + + return ret; +} + +static int ft260_i2c_read(struct ft260_device *dev, u8 addr, u8 *data, + u16 len, u8 flag) +{ + struct ft260_i2c_read_request_report rep; + struct hid_device *hdev = dev->hdev; + int timeout; + int ret; + + if (len > FT260_RD_DATA_MAX) { + hid_err(hdev, "%s: unsupported rd len: %d\n", __func__, len); + return -EINVAL; + } + + dev->read_idx = 0; + dev->read_buf = data; + dev->read_len = len; + + rep.report = FT260_I2C_READ_REQ; + rep.length = cpu_to_le16(len); + rep.address = addr; + rep.flag = flag; + + ft260_dbg("rep %#02x addr %#02x len %d\n", rep.report, rep.address, + rep.length); + + reinit_completion(&dev->wait); + + ret = ft260_hid_output_report(hdev, (u8 *)&rep, sizeof(rep)); + if (ret < 0) { + hid_err(hdev, "%s: failed to start transaction, ret %d\n", + __func__, ret); + return ret; + } + + timeout = msecs_to_jiffies(5000); + if (!wait_for_completion_timeout(&dev->wait, timeout)) { + ft260_i2c_reset(hdev); + return -ETIMEDOUT; + } + + ret = ft260_xfer_status(dev); + if (ret == 0) + return 0; + + ft260_i2c_reset(hdev); + return -EIO; +} + +/* + * A random read operation is implemented as a dummy write operation, followed + * by a current address read operation. The dummy write operation is used to + * load the target byte address into the current byte address counter, from + * which the subsequent current address read operation then reads. + */ +static int ft260_i2c_write_read(struct ft260_device *dev, struct i2c_msg *msgs) +{ + int len, ret; + u16 left_len = msgs[1].len; + u8 *read_buf = msgs[1].buf; + u8 addr = msgs[0].addr; + u16 read_off = 0; + struct hid_device *hdev = dev->hdev; + + if (msgs[0].len > 2) { + hid_err(hdev, "%s: unsupported wr len: %d\n", __func__, + msgs[0].len); + return -EOPNOTSUPP; + } + + memcpy(&read_off, msgs[0].buf, msgs[0].len); + + do { + if (left_len <= FT260_RD_DATA_MAX) + len = left_len; + else + len = FT260_RD_DATA_MAX; + + ft260_dbg("read_off %#x left_len %d len %d\n", read_off, + left_len, len); + + ret = ft260_i2c_write(dev, addr, (u8 *)&read_off, msgs[0].len, + FT260_FLAG_START); + if (ret < 0) + return ret; + + ret = ft260_i2c_read(dev, addr, read_buf, len, + FT260_FLAG_START_STOP); + if (ret < 0) + return ret; + + left_len -= len; + read_buf += len; + read_off += len; + + } while (left_len > 0); + + return 0; +} + +static int ft260_i2c_xfer(struct i2c_adapter *adapter, struct i2c_msg *msgs, + int num) +{ + int ret; + struct ft260_device *dev = i2c_get_adapdata(adapter); + struct hid_device *hdev = dev->hdev; + + mutex_lock(&dev->lock); + + ret = hid_hw_power(hdev, PM_HINT_FULLON); + if (ret < 0) { + hid_err(hdev, "failed to enter FULLON power mode: %d\n", ret); + mutex_unlock(&dev->lock); + return ret; + } + + if (num == 1) { + if (msgs->flags & I2C_M_RD) + ret = ft260_i2c_read(dev, msgs->addr, msgs->buf, + msgs->len, FT260_FLAG_START_STOP); + else + ret = ft260_i2c_write(dev, msgs->addr, msgs->buf, + msgs->len, FT260_FLAG_START_STOP); + if (ret < 0) + goto i2c_exit; + + } else { + /* Combined write then read message */ + ret = ft260_i2c_write_read(dev, msgs); + if (ret < 0) + goto i2c_exit; + } + + ret = num; +i2c_exit: + hid_hw_power(hdev, PM_HINT_NORMAL); + mutex_unlock(&dev->lock); + return ret; +} + +static int ft260_smbus_xfer(struct i2c_adapter *adapter, u16 addr, u16 flags, + char read_write, u8 cmd, int size, + union i2c_smbus_data *data) +{ + int ret; + struct ft260_device *dev = i2c_get_adapdata(adapter); + struct hid_device *hdev = dev->hdev; + + ft260_dbg("smbus size %d\n", size); + + mutex_lock(&dev->lock); + + ret = hid_hw_power(hdev, PM_HINT_FULLON); + if (ret < 0) { + hid_err(hdev, "power management error: %d\n", ret); + mutex_unlock(&dev->lock); + return ret; + } + + switch (size) { + case I2C_SMBUS_QUICK: + if (read_write == I2C_SMBUS_READ) + ret = ft260_i2c_read(dev, addr, &data->byte, 0, + FT260_FLAG_START_STOP); + else + ret = ft260_smbus_write(dev, addr, cmd, NULL, 0, + FT260_FLAG_START_STOP); + break; + case I2C_SMBUS_BYTE: + if (read_write == I2C_SMBUS_READ) + ret = ft260_i2c_read(dev, addr, &data->byte, 1, + FT260_FLAG_START_STOP); + else + ret = ft260_smbus_write(dev, addr, cmd, NULL, 0, + FT260_FLAG_START_STOP); + break; + case I2C_SMBUS_BYTE_DATA: + if (read_write == I2C_SMBUS_READ) { + ret = ft260_smbus_write(dev, addr, cmd, NULL, 0, + FT260_FLAG_START); + if (ret) + goto smbus_exit; + + ret = ft260_i2c_read(dev, addr, &data->byte, 1, + FT260_FLAG_START_STOP_REPEATED); + } else { + ret = ft260_smbus_write(dev, addr, cmd, &data->byte, 1, + FT260_FLAG_START_STOP); + } + break; + case I2C_SMBUS_WORD_DATA: + if (read_write == I2C_SMBUS_READ) { + ret = ft260_smbus_write(dev, addr, cmd, NULL, 0, + FT260_FLAG_START); + if (ret) + goto smbus_exit; + + ret = ft260_i2c_read(dev, addr, (u8 *)&data->word, 2, + FT260_FLAG_START_STOP_REPEATED); + } else { + ret = ft260_smbus_write(dev, addr, cmd, + (u8 *)&data->word, 2, + FT260_FLAG_START_STOP); + } + break; + case I2C_SMBUS_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + ret = ft260_smbus_write(dev, addr, cmd, NULL, 0, + FT260_FLAG_START); + if (ret) + goto smbus_exit; + + ret = ft260_i2c_read(dev, addr, data->block, + data->block[0] + 1, + FT260_FLAG_START_STOP_REPEATED); + } else { + ret = ft260_smbus_write(dev, addr, cmd, data->block, + data->block[0] + 1, + FT260_FLAG_START_STOP); + } + break; + case I2C_SMBUS_I2C_BLOCK_DATA: + if (read_write == I2C_SMBUS_READ) { + ret = ft260_smbus_write(dev, addr, cmd, NULL, 0, + FT260_FLAG_START); + if (ret) + goto smbus_exit; + + ret = ft260_i2c_read(dev, addr, data->block + 1, + data->block[0], + FT260_FLAG_START_STOP_REPEATED); + } else { + ret = ft260_smbus_write(dev, addr, cmd, data->block + 1, + data->block[0], + FT260_FLAG_START_STOP); + } + break; + default: + hid_err(hdev, "unsupported smbus transaction size %d\n", size); + ret = -EOPNOTSUPP; + } + +smbus_exit: + hid_hw_power(hdev, PM_HINT_NORMAL); + mutex_unlock(&dev->lock); + return ret; +} + +static u32 ft260_functionality(struct i2c_adapter *adap) +{ + return I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_QUICK | + I2C_FUNC_SMBUS_BYTE_DATA | I2C_FUNC_SMBUS_WORD_DATA | + I2C_FUNC_SMBUS_BLOCK_DATA | I2C_FUNC_SMBUS_I2C_BLOCK; +} + +static const struct i2c_adapter_quirks ft260_i2c_quirks = { + .flags = I2C_AQ_COMB_WRITE_THEN_READ, + .max_comb_1st_msg_len = 2, +}; + +static const struct i2c_algorithm ft260_i2c_algo = { + .master_xfer = ft260_i2c_xfer, + .smbus_xfer = ft260_smbus_xfer, + .functionality = ft260_functionality, +}; + +static int ft260_get_system_config(struct hid_device *hdev, + struct ft260_get_system_status_report *cfg) +{ + int ret; + int len = sizeof(struct ft260_get_system_status_report); + + ret = ft260_hid_feature_report_get(hdev, FT260_SYSTEM_SETTINGS, + (u8 *)cfg, len); + if (ret != len) { + hid_err(hdev, "failed to retrieve system status\n"); + if (ret >= 0) + return -EIO; + } + return 0; +} + +static int ft260_is_interface_enabled(struct hid_device *hdev) +{ + struct ft260_get_system_status_report cfg; + struct usb_interface *usbif = to_usb_interface(hdev->dev.parent); + int interface = usbif->cur_altsetting->desc.bInterfaceNumber; + int ret; + + ret = ft260_get_system_config(hdev, &cfg); + if (ret) + return ret; + + ft260_dbg("interface: 0x%02x\n", interface); + ft260_dbg("chip mode: 0x%02x\n", cfg.chip_mode); + ft260_dbg("clock_ctl: 0x%02x\n", cfg.clock_ctl); + ft260_dbg("i2c_enable: 0x%02x\n", cfg.i2c_enable); + ft260_dbg("uart_mode: 0x%02x\n", cfg.uart_mode); + + switch (cfg.chip_mode) { + case FT260_MODE_ALL: + case FT260_MODE_BOTH: + if (interface == 1) { + hid_info(hdev, "uart interface is not supported\n"); + return 0; + } + ret = 1; + break; + case FT260_MODE_UART: + if (interface == 0) { + hid_info(hdev, "uart is unsupported on interface 0\n"); + ret = 0; + } + break; + case FT260_MODE_I2C: + if (interface == 1) { + hid_info(hdev, "i2c is unsupported on interface 1\n"); + ret = 0; + } + break; + } + return ret; +} + +static int ft260_byte_show(struct hid_device *hdev, int id, u8 *cfg, int len, + u8 *field, u8 *buf) +{ + int ret; + + ret = ft260_hid_feature_report_get(hdev, id, cfg, len); + if (ret != len && ret >= 0) + return -EIO; + + return scnprintf(buf, PAGE_SIZE, "%hi\n", *field); +} + +static int ft260_word_show(struct hid_device *hdev, int id, u8 *cfg, int len, + u16 *field, u8 *buf) +{ + int ret; + + ret = ft260_hid_feature_report_get(hdev, id, cfg, len); + if (ret != len && ret >= 0) + return -EIO; + + return scnprintf(buf, PAGE_SIZE, "%hi\n", le16_to_cpu(*field)); +} + +#define FT260_ATTR_SHOW(name, reptype, id, type, func) \ + static ssize_t name##_show(struct device *kdev, \ + struct device_attribute *attr, char *buf) \ + { \ + struct reptype rep; \ + struct hid_device *hdev = to_hid_device(kdev); \ + type *field = &rep.name; \ + int len = sizeof(rep); \ + \ + return func(hdev, id, (u8 *)&rep, len, field, buf); \ + } + +#define FT260_SSTAT_ATTR_SHOW(name) \ + FT260_ATTR_SHOW(name, ft260_get_system_status_report, \ + FT260_SYSTEM_SETTINGS, u8, ft260_byte_show) + +#define FT260_I2CST_ATTR_SHOW(name) \ + FT260_ATTR_SHOW(name, ft260_get_i2c_status_report, \ + FT260_I2C_STATUS, u16, ft260_word_show) + +#define FT260_ATTR_STORE(name, reptype, id, req, type, func) \ + static ssize_t name##_store(struct device *kdev, \ + struct device_attribute *attr, \ + const char *buf, size_t count) \ + { \ + struct reptype rep; \ + struct hid_device *hdev = to_hid_device(kdev); \ + type name; \ + int ret; \ + \ + if (!func(buf, 10, &name)) { \ + rep.name = name; \ + rep.report = id; \ + rep.request = req; \ + ret = ft260_hid_feature_report_set(hdev, (u8 *)&rep, \ + sizeof(rep)); \ + if (!ret) \ + ret = count; \ + } else { \ + ret = -EINVAL; \ + } \ + return ret; \ + } + +#define FT260_BYTE_ATTR_STORE(name, reptype, req) \ + FT260_ATTR_STORE(name, reptype, FT260_SYSTEM_SETTINGS, req, \ + u8, kstrtou8) + +#define FT260_WORD_ATTR_STORE(name, reptype, req) \ + FT260_ATTR_STORE(name, reptype, FT260_SYSTEM_SETTINGS, req, \ + u16, kstrtou16) + +FT260_SSTAT_ATTR_SHOW(chip_mode); +static DEVICE_ATTR_RO(chip_mode); + +FT260_SSTAT_ATTR_SHOW(pwren_status); +static DEVICE_ATTR_RO(pwren_status); + +FT260_SSTAT_ATTR_SHOW(suspend_status); +static DEVICE_ATTR_RO(suspend_status); + +FT260_SSTAT_ATTR_SHOW(hid_over_i2c_en); +static DEVICE_ATTR_RO(hid_over_i2c_en); + +FT260_SSTAT_ATTR_SHOW(power_saving_en); +static DEVICE_ATTR_RO(power_saving_en); + +FT260_SSTAT_ATTR_SHOW(i2c_enable); +FT260_BYTE_ATTR_STORE(i2c_enable, ft260_set_i2c_mode_report, + FT260_SET_I2C_MODE); +static DEVICE_ATTR_RW(i2c_enable); + +FT260_SSTAT_ATTR_SHOW(uart_mode); +FT260_BYTE_ATTR_STORE(uart_mode, ft260_set_uart_mode_report, + FT260_SET_UART_MODE); +static DEVICE_ATTR_RW(uart_mode); + +FT260_SSTAT_ATTR_SHOW(clock_ctl); +FT260_BYTE_ATTR_STORE(clock_ctl, ft260_set_system_clock_report, + FT260_SET_CLOCK); +static DEVICE_ATTR_RW(clock_ctl); + +FT260_I2CST_ATTR_SHOW(clock); +FT260_WORD_ATTR_STORE(clock, ft260_set_i2c_speed_report, + FT260_SET_I2C_CLOCK_SPEED); +static DEVICE_ATTR_RW(clock); + +static ssize_t i2c_reset_store(struct device *kdev, + struct device_attribute *attr, const char *buf, + size_t count) +{ + struct hid_device *hdev = to_hid_device(kdev); + int ret = ft260_i2c_reset(hdev); + + if (ret) + return ret; + return count; +} +static DEVICE_ATTR_WO(i2c_reset); + +static const struct attribute_group ft260_attr_group = { + .attrs = (struct attribute *[]) { + &dev_attr_chip_mode.attr, + &dev_attr_pwren_status.attr, + &dev_attr_suspend_status.attr, + &dev_attr_hid_over_i2c_en.attr, + &dev_attr_power_saving_en.attr, + &dev_attr_i2c_enable.attr, + &dev_attr_uart_mode.attr, + &dev_attr_clock_ctl.attr, + &dev_attr_i2c_reset.attr, + &dev_attr_clock.attr, + NULL + } +}; + +static int ft260_probe(struct hid_device *hdev, const struct hid_device_id *id) +{ + struct ft260_device *dev; + struct ft260_get_chip_version_report version; + int ret; + + dev = devm_kzalloc(&hdev->dev, sizeof(*dev), GFP_KERNEL); + if (!dev) + return -ENOMEM; + + ret = hid_parse(hdev); + if (ret) { + hid_err(hdev, "failed to parse HID\n"); + return ret; + } + + ret = hid_hw_start(hdev, HID_CONNECT_HIDRAW); + if (ret) { + hid_err(hdev, "failed to start HID HW\n"); + return ret; + } + + ret = hid_hw_open(hdev); + if (ret) { + hid_err(hdev, "failed to open HID HW\n"); + goto err_hid_stop; + } + + ret = ft260_hid_feature_report_get(hdev, FT260_CHIP_VERSION, + (u8 *)&version, sizeof(version)); + if (ret != sizeof(version)) { + hid_err(hdev, "failed to retrieve chip version\n"); + if (ret >= 0) + ret = -EIO; + goto err_hid_close; + } + + hid_info(hdev, "chip code: %02x%02x %02x%02x\n", + version.chip_code[0], version.chip_code[1], + version.chip_code[2], version.chip_code[3]); + + ret = ft260_is_interface_enabled(hdev); + if (ret <= 0) + goto err_hid_close; + + hid_set_drvdata(hdev, dev); + dev->hdev = hdev; + dev->adap.owner = THIS_MODULE; + dev->adap.class = I2C_CLASS_HWMON; + dev->adap.algo = &ft260_i2c_algo; + dev->adap.quirks = &ft260_i2c_quirks; + dev->adap.dev.parent = &hdev->dev; + snprintf(dev->adap.name, sizeof(dev->adap.name), + "FT260 usb-i2c bridge on hidraw%d", + ((struct hidraw *)hdev->hidraw)->minor); + + mutex_init(&dev->lock); + init_completion(&dev->wait); + + ret = i2c_add_adapter(&dev->adap); + if (ret) { + hid_err(hdev, "failed to add i2c adapter\n"); + goto err_hid_close; + } + + i2c_set_adapdata(&dev->adap, dev); + + ret = sysfs_create_group(&hdev->dev.kobj, &ft260_attr_group); + if (ret < 0) { + hid_err(hdev, "failed to create sysfs attrs\n"); + goto err_i2c_free; + } + + ret = ft260_xfer_status(dev); + if (ret) + ft260_i2c_reset(hdev); + + return 0; + +err_i2c_free: + i2c_del_adapter(&dev->adap); +err_hid_close: + hid_hw_close(hdev); +err_hid_stop: + hid_hw_stop(hdev); + return ret; +} + +static void ft260_remove(struct hid_device *hdev) +{ + int ret; + struct ft260_device *dev = hid_get_drvdata(hdev); + + ret = ft260_is_interface_enabled(hdev); + if (ret <= 0) + return; + + sysfs_remove_group(&hdev->dev.kobj, &ft260_attr_group); + i2c_del_adapter(&dev->adap); + + hid_hw_close(hdev); + hid_hw_stop(hdev); +} + +static int ft260_raw_event(struct hid_device *hdev, struct hid_report *report, + u8 *data, int size) +{ + struct ft260_device *dev = hid_get_drvdata(hdev); + struct ft260_i2c_input_report *xfer = (void *)data; + + if (xfer->report >= FT260_I2C_REPORT_MIN && + xfer->report <= FT260_I2C_REPORT_MAX) { + ft260_dbg("i2c resp: rep %#02x len %d\n", xfer->report, + xfer->length); + + memcpy(&dev->read_buf[dev->read_idx], &xfer->data, + xfer->length); + dev->read_idx += xfer->length; + + if (dev->read_idx == dev->read_len) + complete(&dev->wait); + + } else { + hid_err(hdev, "unknown report: %#02x\n", xfer->report); + return 0; + } + return 1; +} + +static struct hid_driver ft260_driver = { + .name = "ft260", + .id_table = ft260_devices, + .probe = ft260_probe, + .remove = ft260_remove, + .raw_event = ft260_raw_event, +}; + +module_hid_driver(ft260_driver); +MODULE_DESCRIPTION("FTDI FT260 USB HID to I2C host bridge"); +MODULE_AUTHOR("Michael Zaidman <michael.zaidman@gmail.com>"); +MODULE_LICENSE("GPL v2"); diff --git a/drivers/hid/hid-google-hammer.c b/drivers/hid/hid-google-hammer.c index d9319622da44..e60c31dd05ff 100644 --- a/drivers/hid/hid-google-hammer.c +++ b/drivers/hid/hid-google-hammer.c @@ -574,6 +574,8 @@ static void hammer_remove(struct hid_device *hdev) static const struct hid_device_id hammer_devices[] = { { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, + USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_DON) }, + { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_HAMMER) }, { HID_DEVICE(BUS_USB, HID_GROUP_GENERIC, USB_VENDOR_ID_GOOGLE, USB_DEVICE_ID_GOOGLE_MAGNEMITE) }, diff --git a/drivers/hid/hid-ids.h b/drivers/hid/hid-ids.h index e42aaae3138f..2124fb0fd6a0 100644 --- a/drivers/hid/hid-ids.h +++ b/drivers/hid/hid-ids.h @@ -194,6 +194,7 @@ #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD2 0x1837 #define USB_DEVICE_ID_ASUSTEK_ROG_KEYBOARD3 0x1822 #define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD 0x1866 +#define USB_DEVICE_ID_ASUSTEK_ROG_NKEY_KEYBOARD2 0x19b6 #define USB_DEVICE_ID_ASUSTEK_FX503VD_KEYBOARD 0x1869 #define USB_VENDOR_ID_ATEN 0x0557 @@ -430,6 +431,7 @@ #define USB_VENDOR_ID_FUTURE_TECHNOLOGY 0x0403 #define USB_DEVICE_ID_RETRODE2 0x97c1 +#define USB_DEVICE_ID_FT260 0x6030 #define USB_VENDOR_ID_ESSENTIAL_REALITY 0x0d7f #define USB_DEVICE_ID_ESSENTIAL_REALITY_P5 0x0100 @@ -493,6 +495,7 @@ #define USB_DEVICE_ID_GOOGLE_MASTERBALL 0x503c #define USB_DEVICE_ID_GOOGLE_MAGNEMITE 0x503d #define USB_DEVICE_ID_GOOGLE_MOONBALL 0x5044 +#define USB_DEVICE_ID_GOOGLE_DON 0x5050 #define USB_VENDOR_ID_GOTOP 0x08f2 #define USB_DEVICE_ID_SUPER_Q2 0x007f diff --git a/drivers/hid/i2c-hid/i2c-hid-acpi.c b/drivers/hid/i2c-hid/i2c-hid-acpi.c index bb8c00e6be78..a6f0257a26de 100644 --- a/drivers/hid/i2c-hid/i2c-hid-acpi.c +++ b/drivers/hid/i2c-hid/i2c-hid-acpi.c @@ -25,12 +25,13 @@ #include <linux/kernel.h> #include <linux/module.h> #include <linux/pm.h> +#include <linux/uuid.h> #include "i2c-hid.h" struct i2c_hid_acpi { struct i2chid_ops ops; - struct i2c_client *client; + struct acpi_device *adev; }; static const struct acpi_device_id i2c_hid_acpi_blacklist[] = { @@ -42,29 +43,24 @@ static const struct acpi_device_id i2c_hid_acpi_blacklist[] = { { }, }; -static int i2c_hid_acpi_get_descriptor(struct i2c_client *client) +/* HID I²C Device: 3cdff6f7-4267-4555-ad05-b30a3d8938de */ +static guid_t i2c_hid_guid = + GUID_INIT(0x3CDFF6F7, 0x4267, 0x4555, + 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE); + +static int i2c_hid_acpi_get_descriptor(struct acpi_device *adev) { - static guid_t i2c_hid_guid = - GUID_INIT(0x3CDFF6F7, 0x4267, 0x4555, - 0xAD, 0x05, 0xB3, 0x0A, 0x3D, 0x89, 0x38, 0xDE); + acpi_handle handle = acpi_device_handle(adev); union acpi_object *obj; - struct acpi_device *adev; - acpi_handle handle; u16 hid_descriptor_address; - handle = ACPI_HANDLE(&client->dev); - if (!handle || acpi_bus_get_device(handle, &adev)) { - dev_err(&client->dev, "Error could not get ACPI device\n"); - return -ENODEV; - } - if (acpi_match_device_ids(adev, i2c_hid_acpi_blacklist) == 0) return -ENODEV; obj = acpi_evaluate_dsm_typed(handle, &i2c_hid_guid, 1, 1, NULL, ACPI_TYPE_INTEGER); if (!obj) { - dev_err(&client->dev, "Error _DSM call to get HID descriptor address failed\n"); + acpi_handle_err(handle, "Error _DSM call to get HID descriptor address failed\n"); return -ENODEV; } @@ -76,14 +72,12 @@ static int i2c_hid_acpi_get_descriptor(struct i2c_client *client) static void i2c_hid_acpi_shutdown_tail(struct i2chid_ops *ops) { - struct i2c_hid_acpi *ihid_acpi = - container_of(ops, struct i2c_hid_acpi, ops); - struct device *dev = &ihid_acpi->client->dev; - acpi_device_set_power(ACPI_COMPANION(dev), ACPI_STATE_D3_COLD); + struct i2c_hid_acpi *ihid_acpi = container_of(ops, struct i2c_hid_acpi, ops); + + acpi_device_set_power(ihid_acpi->adev, ACPI_STATE_D3_COLD); } -static int i2c_hid_acpi_probe(struct i2c_client *client, - const struct i2c_device_id *dev_id) +static int i2c_hid_acpi_probe(struct i2c_client *client) { struct device *dev = &client->dev; struct i2c_hid_acpi *ihid_acpi; @@ -91,21 +85,25 @@ static int i2c_hid_acpi_probe(struct i2c_client *client, u16 hid_descriptor_address; int ret; + adev = ACPI_COMPANION(dev); + if (!adev) { + dev_err(&client->dev, "Error could not get ACPI device\n"); + return -ENODEV; + } + ihid_acpi = devm_kzalloc(&client->dev, sizeof(*ihid_acpi), GFP_KERNEL); if (!ihid_acpi) return -ENOMEM; - ihid_acpi->client = client; + ihid_acpi->adev = adev; ihid_acpi->ops.shutdown_tail = i2c_hid_acpi_shutdown_tail; - ret = i2c_hid_acpi_get_descriptor(client); + ret = i2c_hid_acpi_get_descriptor(adev); if (ret < 0) return ret; hid_descriptor_address = ret; - adev = ACPI_COMPANION(dev); - if (adev) - acpi_device_fix_up_power(adev); + acpi_device_fix_up_power(adev); if (acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0) { device_set_wakeup_capable(dev, true); @@ -128,10 +126,10 @@ static struct i2c_driver i2c_hid_acpi_driver = { .name = "i2c_hid_acpi", .pm = &i2c_hid_core_pm, .probe_type = PROBE_PREFER_ASYNCHRONOUS, - .acpi_match_table = ACPI_PTR(i2c_hid_acpi_match), + .acpi_match_table = i2c_hid_acpi_match, }, - .probe = i2c_hid_acpi_probe, + .probe_new = i2c_hid_acpi_probe, .remove = i2c_hid_core_remove, .shutdown = i2c_hid_core_shutdown, }; diff --git a/drivers/hid/usbhid/hiddev.c b/drivers/hid/usbhid/hiddev.c index 45e0b1c75cb1..2fb2991dbe4c 100644 --- a/drivers/hid/usbhid/hiddev.c +++ b/drivers/hid/usbhid/hiddev.c @@ -887,11 +887,11 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) break; if (i == hid->maxcollection) - return -1; + return -EINVAL; } if (!(hiddev = kzalloc(sizeof(struct hiddev), GFP_KERNEL))) - return -1; + return -ENOMEM; init_waitqueue_head(&hiddev->wait); INIT_LIST_HEAD(&hiddev->list); @@ -905,7 +905,7 @@ int hiddev_connect(struct hid_device *hid, unsigned int force) hid_err(hid, "Not able to get a minor for this device\n"); hid->hiddev = NULL; kfree(hiddev); - return -1; + return retval; } /* diff --git a/drivers/hid/wacom_wac.c b/drivers/hid/wacom_wac.c index 44d715c12f6a..2d70dc4bea65 100644 --- a/drivers/hid/wacom_wac.c +++ b/drivers/hid/wacom_wac.c @@ -2533,7 +2533,7 @@ static void wacom_wac_finger_slot(struct wacom_wac *wacom_wac, !wacom_wac->shared->is_touch_on) { if (!wacom_wac->shared->touch_down) return; - prox = 0; + prox = false; } wacom_wac->hid_data.num_received++; @@ -3574,8 +3574,6 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, { struct wacom_features *features = &wacom_wac->features; - input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - if (!(features->device_type & WACOM_DEVICETYPE_PEN)) return -ENODEV; @@ -3590,6 +3588,7 @@ int wacom_setup_pen_input_capabilities(struct input_dev *input_dev, return 0; } + input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); __set_bit(BTN_TOUCH, input_dev->keybit); __set_bit(ABS_MISC, input_dev->absbit); @@ -3742,8 +3741,6 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, { struct wacom_features *features = &wacom_wac->features; - input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); - if (!(features->device_type & WACOM_DEVICETYPE_TOUCH)) return -ENODEV; @@ -3756,6 +3753,7 @@ int wacom_setup_touch_input_capabilities(struct input_dev *input_dev, /* setup has already been done */ return 0; + input_dev->evbit[0] |= BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS); __set_bit(BTN_TOUCH, input_dev->keybit); if (features->touch_max == 1) { |