Commit 2043f9a3 authored by Linus Torvalds's avatar Linus Torvalds

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

Pull HID updates from Jiri Kosina:

 - iio support for the MCP2221 HID driver (Matt Ranostay)

 - support for more than one hinge sensor in hid-sensor-custom (Yauhen
   Kharuzhy)

 - PS DualShock 4 controller support (Roderick Colenbrander)

 - XP-PEN Deco LW support (José Expósito)

 - other assorted code cleanups and device ID/quirk addtions

* tag 'for-linus-2022121301' of git://git.kernel.org/pub/scm/linux/kernel/git/hid/hid: (51 commits)
  HID: logitech HID++: Send SwID in GetProtocolVersion
  HID: hid-elan: use default remove for hid device
  HID: hid-alps: use default remove for hid device
  HID: hid-sensor-custom: set fixed size for custom attributes
  HID: i2c: let RMI devices decide what constitutes wakeup event
  HID: playstation: fix DualShock4 bluetooth CRC endian issue.
  HID: playstation: fix DualShock4 bluetooth memory corruption bug.
  HID: apple: Swap Control and Command keys on Apple keyboards
  HID: intel-ish-hid: ishtp: remove variable rb_count
  HID: uclogic: Standardize test name prefix
  HID: hid-sensor-custom: Allow more than one hinge angle sensor
  HID: ft260: fix 'cast to restricted' kernel CI bot warnings
  HID: ft260: missed NACK from busy device
  HID: ft260: fix a NULL pointer dereference in ft260_i2c_write
  HID: ft260: wake up device from power saving mode
  HID: ft260: missed NACK from big i2c read
  HID: ft260: remove SMBus Quick command support
  HID: ft260: skip unexpected HID input reports
  HID: ft260: do not populate /dev/hidraw device
  HID: ft260: improve i2c large reads performance
  ...
parents 86a0b425 f722052c
......@@ -1252,7 +1252,8 @@ config HID_ALPS
config HID_MCP2221
tristate "Microchip MCP2221 HID USB-to-I2C/SMbus host support"
depends on USB_HID && I2C
depends on GPIOLIB
imply GPIOLIB
imply IIO
help
Provides I2C and SMBUS host adapter functionality over USB-HID
through MCP2221 device.
......
......@@ -820,11 +820,6 @@ static int alps_probe(struct hid_device *hdev, const struct hid_device_id *id)
return 0;
}
static void alps_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
}
static const struct hid_device_id alps_id[] = {
{ HID_DEVICE(HID_BUS_ANY, HID_GROUP_ANY,
USB_VENDOR_ID_ALPS_JP, HID_DEVICE_ID_ALPS_U1_DUAL) },
......@@ -842,7 +837,6 @@ static struct hid_driver alps_driver = {
.name = "hid-alps",
.id_table = alps_id,
.probe = alps_probe,
.remove = alps_remove,
.raw_event = alps_raw_event,
.input_mapping = alps_input_mapping,
.input_configured = alps_input_configured,
......
......@@ -59,6 +59,12 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\")
"(For people who want to keep Windows PC keyboard muscle memory. "
"[0] = as-is, Mac layout. 1 = swapped, Windows layout.)");
static unsigned int swap_ctrl_cmd;
module_param(swap_ctrl_cmd, uint, 0644);
MODULE_PARM_DESC(swap_ctrl_cmd, "Swap the Control (\"Ctrl\") and Command (\"Flag\") keys. "
"(For people who are used to Mac shortcuts involving Command instead of Control. "
"[0] = No change. 1 = Swapped.)");
static unsigned int swap_fn_leftctrl;
module_param(swap_fn_leftctrl, uint, 0644);
MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. "
......@@ -308,12 +314,21 @@ static const struct apple_key_translation swapped_option_cmd_keys[] = {
{ KEY_LEFTALT, KEY_LEFTMETA },
{ KEY_LEFTMETA, KEY_LEFTALT },
{ KEY_RIGHTALT, KEY_RIGHTMETA },
{ KEY_RIGHTMETA,KEY_RIGHTALT },
{ KEY_RIGHTMETA, KEY_RIGHTALT },
{ }
};
static const struct apple_key_translation swapped_ctrl_cmd_keys[] = {
{ KEY_LEFTCTRL, KEY_LEFTMETA },
{ KEY_LEFTMETA, KEY_LEFTCTRL },
{ KEY_RIGHTCTRL, KEY_RIGHTMETA },
{ KEY_RIGHTMETA, KEY_RIGHTCTRL },
{ }
};
static const struct apple_key_translation swapped_fn_leftctrl_keys[] = {
{ KEY_FN, KEY_LEFTCTRL },
{ KEY_LEFTCTRL, KEY_FN },
{ }
};
......@@ -375,24 +390,47 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
struct apple_sc *asc = hid_get_drvdata(hid);
const struct apple_key_translation *trans, *table;
bool do_translate;
u16 code = 0;
u16 code = usage->code;
unsigned int real_fnmode;
u16 fn_keycode = (swap_fn_leftctrl) ? (KEY_LEFTCTRL) : (KEY_FN);
if (usage->code == fn_keycode) {
asc->fn_on = !!value;
input_event_with_scancode(input, usage->type, KEY_FN,
usage->hid, value);
return 1;
}
if (fnmode == 3) {
real_fnmode = (asc->quirks & APPLE_IS_NON_APPLE) ? 2 : 1;
} else {
real_fnmode = fnmode;
}
if (swap_fn_leftctrl) {
trans = apple_find_translation(swapped_fn_leftctrl_keys, code);
if (trans)
code = trans->to;
}
if (iso_layout > 0 || (iso_layout < 0 && (asc->quirks & APPLE_ISO_TILDE_QUIRK) &&
hid->country == HID_COUNTRY_INTERNATIONAL_ISO)) {
trans = apple_find_translation(apple_iso_keyboard, code);
if (trans)
code = trans->to;
}
if (swap_opt_cmd) {
trans = apple_find_translation(swapped_option_cmd_keys, code);
if (trans)
code = trans->to;
}
if (swap_ctrl_cmd) {
trans = apple_find_translation(swapped_ctrl_cmd_keys, code);
if (trans)
code = trans->to;
}
if (code == KEY_FN)
asc->fn_on = !!value;
if (real_fnmode) {
if (hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI ||
hid->product == USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO ||
......@@ -430,15 +468,18 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
else
table = apple_fn_keys;
trans = apple_find_translation (table, usage->code);
trans = apple_find_translation(table, code);
if (trans) {
if (test_bit(trans->from, input->key))
bool from_is_set = test_bit(trans->from, input->key);
bool to_is_set = test_bit(trans->to, input->key);
if (from_is_set)
code = trans->from;
else if (test_bit(trans->to, input->key))
else if (to_is_set)
code = trans->to;
if (!code) {
if (!(from_is_set || to_is_set)) {
if (trans->flags & APPLE_FLAG_FKEY) {
switch (real_fnmode) {
case 1:
......@@ -455,63 +496,32 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input,
do_translate = asc->fn_on;
}
code = do_translate ? trans->to : trans->from;
if (do_translate)
code = trans->to;
}
input_event_with_scancode(input, usage->type, code,
usage->hid, value);
return 1;
}
if (asc->quirks & APPLE_NUMLOCK_EMULATION &&
(test_bit(usage->code, asc->pressed_numlock) ||
(test_bit(code, asc->pressed_numlock) ||
test_bit(LED_NUML, input->led))) {
trans = apple_find_translation(powerbook_numlock_keys,
usage->code);
trans = apple_find_translation(powerbook_numlock_keys, code);
if (trans) {
if (value)
set_bit(usage->code,
asc->pressed_numlock);
set_bit(code, asc->pressed_numlock);
else
clear_bit(usage->code,
asc->pressed_numlock);
clear_bit(code, asc->pressed_numlock);
input_event_with_scancode(input, usage->type,
trans->to, usage->hid, value);
code = trans->to;
}
return 1;
}
}
if (iso_layout > 0 || (iso_layout < 0 && (asc->quirks & APPLE_ISO_TILDE_QUIRK) &&
hid->country == HID_COUNTRY_INTERNATIONAL_ISO)) {
trans = apple_find_translation(apple_iso_keyboard, usage->code);
if (trans) {
input_event_with_scancode(input, usage->type,
trans->to, usage->hid, value);
return 1;
}
}
if (usage->code != code) {
input_event_with_scancode(input, usage->type, code, usage->hid, value);
if (swap_opt_cmd) {
trans = apple_find_translation(swapped_option_cmd_keys, usage->code);
if (trans) {
input_event_with_scancode(input, usage->type,
trans->to, usage->hid, value);
return 1;
}
}
if (swap_fn_leftctrl) {
trans = apple_find_translation(swapped_fn_leftctrl_keys, usage->code);
if (trans) {
input_event_with_scancode(input, usage->type,
trans->to, usage->hid, value);
return 1;
}
}
return 0;
}
......@@ -640,9 +650,6 @@ static void apple_setup_input(struct input_dev *input)
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);
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,
......@@ -1011,21 +1018,21 @@ static const struct hid_device_id apple_devices[] = {
{ 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 },
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J132),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL },
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J680),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL },
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J213),
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL },
.driver_data = APPLE_HAS_FN | APPLE_BACKLIGHT_CTL | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J214K),
.driver_data = APPLE_HAS_FN },
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J223),
.driver_data = APPLE_HAS_FN },
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J230K),
.driver_data = APPLE_HAS_FN },
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
{ HID_USB_DEVICE(USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRINGT2_J152F),
.driver_data = APPLE_HAS_FN },
.driver_data = APPLE_HAS_FN | APPLE_ISO_TILDE_QUIRK },
{ 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),
......
......@@ -507,11 +507,6 @@ static int elan_probe(struct hid_device *hdev, const struct hid_device_id *id)
return ret;
}
static void elan_remove(struct hid_device *hdev)
{
hid_hw_stop(hdev);
}
static const struct hid_device_id elan_devices[] = {
{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_HP_X2),
.driver_data = ELAN_HAS_LED },
......@@ -529,7 +524,6 @@ static struct hid_driver elan_driver = {
.input_configured = elan_input_configured,
.raw_event = elan_raw_event,
.probe = elan_probe,
.remove = elan_remove,
};
module_hid_driver(elan_driver);
......
This diff is collapsed.
......@@ -22,9 +22,6 @@ struct hv_input_dev_info {
unsigned short reserved[11];
};
/* The maximum size of a synthetic input message. */
#define SYNTHHID_MAX_INPUT_REPORT_SIZE 16
/*
* Current version
*
......@@ -59,11 +56,6 @@ struct synthhid_msg_hdr {
u32 size;
};
struct synthhid_msg {
struct synthhid_msg_hdr header;
char data[1]; /* Enclosed message */
};
union synthhid_version {
struct {
u16 minor_version;
......@@ -99,7 +91,7 @@ struct synthhid_device_info_ack {
struct synthhid_input_report {
struct synthhid_msg_hdr header;
char buffer[1];
char buffer[];
};
#pragma pack(pop)
......@@ -118,7 +110,7 @@ enum pipe_prot_msg_type {
struct pipe_prt_msg {
enum pipe_prot_msg_type type;
u32 size;
char data[1];
char data[];
};
struct mousevsc_prt_msg {
......@@ -232,7 +224,7 @@ static void mousevsc_on_receive_device_info(struct mousevsc_dev *input_device,
ret = vmbus_sendpacket(input_device->device->channel,
&ack,
sizeof(struct pipe_prt_msg) - sizeof(unsigned char) +
sizeof(struct pipe_prt_msg) +
sizeof(struct synthhid_device_info_ack),
(unsigned long)&ack,
VM_PKT_DATA_INBAND,
......@@ -251,7 +243,7 @@ static void mousevsc_on_receive(struct hv_device *device,
struct vmpacket_descriptor *packet)
{
struct pipe_prt_msg *pipe_msg;
struct synthhid_msg *hid_msg;
struct synthhid_msg_hdr *hid_msg_hdr;
struct mousevsc_dev *input_dev = hv_get_drvdata(device);
struct synthhid_input_report *input_report;
size_t len;
......@@ -262,25 +254,23 @@ static void mousevsc_on_receive(struct hv_device *device,
if (pipe_msg->type != PIPE_MESSAGE_DATA)
return;
hid_msg = (struct synthhid_msg *)pipe_msg->data;
hid_msg_hdr = (struct synthhid_msg_hdr *)pipe_msg->data;
switch (hid_msg->header.type) {
switch (hid_msg_hdr->type) {
case SYNTH_HID_PROTOCOL_RESPONSE:
/*
* While it will be impossible for us to protect against
* malicious/buggy hypervisor/host, add a check here to
* ensure we don't corrupt memory.
*/
if ((pipe_msg->size + sizeof(struct pipe_prt_msg)
- sizeof(unsigned char))
if (struct_size(pipe_msg, data, pipe_msg->size)
> sizeof(struct mousevsc_prt_msg)) {
WARN_ON(1);
break;
}
memcpy(&input_dev->protocol_resp, pipe_msg,
pipe_msg->size + sizeof(struct pipe_prt_msg) -
sizeof(unsigned char));
struct_size(pipe_msg, data, pipe_msg->size));
complete(&input_dev->wait_event);
break;
......@@ -311,7 +301,7 @@ static void mousevsc_on_receive(struct hv_device *device,
break;
default:
pr_err("unsupported hid msg type - type %d len %d\n",
hid_msg->header.type, hid_msg->header.size);
hid_msg_hdr->type, hid_msg_hdr->size);
break;
}
......@@ -359,8 +349,7 @@ static int mousevsc_connect_to_vsp(struct hv_device *device)
request->request.version_requested.version = SYNTHHID_INPUT_VERSION;
ret = vmbus_sendpacket(device->channel, request,
sizeof(struct pipe_prt_msg) -
sizeof(unsigned char) +
sizeof(struct pipe_prt_msg) +
sizeof(struct synthhid_protocol_request),
(unsigned long)request,
VM_PKT_DATA_INBAND,
......
......@@ -340,6 +340,7 @@ static enum power_supply_property hidinput_battery_props[] = {
#define HID_BATTERY_QUIRK_PERCENT (1 << 0) /* always reports percent */
#define HID_BATTERY_QUIRK_FEATURE (1 << 1) /* ask for feature report */
#define HID_BATTERY_QUIRK_IGNORE (1 << 2) /* completely ignore the battery */
#define HID_BATTERY_QUIRK_AVOID_QUERY (1 << 3) /* do not query the battery */
static const struct hid_device_id hid_battery_quirks[] = {
{ HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE,
......@@ -373,6 +374,8 @@ static const struct hid_device_id hid_battery_quirks[] = {
HID_BATTERY_QUIRK_IGNORE },
{ HID_USB_DEVICE(USB_VENDOR_ID_ELAN, USB_DEVICE_ID_ASUS_UX550VE_TOUCHSCREEN),
HID_BATTERY_QUIRK_IGNORE },
{ HID_USB_DEVICE(USB_VENDOR_ID_UGEE, USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L),
HID_BATTERY_QUIRK_AVOID_QUERY },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15),
HID_BATTERY_QUIRK_IGNORE },
{ HID_I2C_DEVICE(USB_VENDOR_ID_ELAN, I2C_DEVICE_ID_HP_ENVY_X360_15T_DR100),
......@@ -554,6 +557,9 @@ static int hidinput_setup_battery(struct hid_device *dev, unsigned report_type,
dev->battery_avoid_query = report_type == HID_INPUT_REPORT &&
field->physical == HID_DG_STYLUS;
if (quirks & HID_BATTERY_QUIRK_AVOID_QUERY)
dev->battery_avoid_query = true;
dev->battery = power_supply_register(&dev->dev, psy_desc, &psy_cfg);
if (IS_ERR(dev->battery)) {
error = PTR_ERR(dev->battery);
......
......@@ -895,7 +895,7 @@ static int hidpp_root_get_protocol_version(struct hidpp_device *hidpp)
ret = hidpp_send_rap_command_sync(hidpp,
REPORT_ID_HIDPP_SHORT,
HIDPP_PAGE_ROOT_IDX,
CMD_ROOT_GET_PROTOCOL_VERSION,
CMD_ROOT_GET_PROTOCOL_VERSION | LINUX_KERNEL_SW_ID,
ping_data, sizeof(ping_data), &response);
if (ret == HIDPP_ERROR_INVALID_SUBID) {
......
......@@ -10,12 +10,14 @@
#include <linux/module.h>
#include <linux/err.h>
#include <linux/mutex.h>
#include <linux/bitfield.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/hid.h>
#include <linux/hidraw.h>
#include <linux/i2c.h>
#include <linux/gpio/driver.h>
#include <linux/iio/iio.h>
#include "hid-ids.h"
/* Commands codes in a raw output report */
......@@ -30,6 +32,9 @@ enum {
MCP2221_I2C_CANCEL = 0x10,
MCP2221_GPIO_SET = 0x50,
MCP2221_GPIO_GET = 0x51,
MCP2221_SET_SRAM_SETTINGS = 0x60,
MCP2221_GET_SRAM_SETTINGS = 0x61,
MCP2221_READ_FLASH_DATA = 0xb0,
};
/* Response codes in a raw input report */
......@@ -89,6 +94,7 @@ struct mcp2221 {
struct i2c_adapter adapter;
struct mutex lock;
struct completion wait_in_report;
struct delayed_work init_work;
u8 *rxbuf;
u8 txbuf[64];
int rxbuf_idx;
......@@ -97,6 +103,18 @@ struct mcp2221 {
struct gpio_chip *gc;
u8 gp_idx;
u8 gpio_dir;
u8 mode[4];
#if IS_REACHABLE(CONFIG_IIO)
struct iio_chan_spec iio_channels[3];
u16 adc_values[3];
u8 adc_scale;
u8 dac_value;
u16 dac_scale;
#endif
};
struct mcp2221_iio {
struct mcp2221 *mcp;
};
/*
......@@ -567,6 +585,7 @@ static const struct i2c_algorithm mcp_i2c_algo = {
.functionality = mcp_i2c_func,
};
#if IS_REACHABLE(CONFIG_GPIOLIB)
static int mcp_gpio_get(struct gpio_chip *gc,
unsigned int offset)
{
......@@ -670,6 +689,7 @@ static int mcp_gpio_get_direction(struct gpio_chip *gc,
return GPIO_LINE_DIRECTION_OUT;
}
#endif
/* Gives current state of i2c engine inside mcp2221 */
static int mcp_get_i2c_eng_state(struct mcp2221 *mcp,
......@@ -745,6 +765,9 @@ static int mcp2221_raw_event(struct hid_device *hdev,
break;
}
mcp->status = mcp_get_i2c_eng_state(mcp, data, 8);
#if IS_REACHABLE(CONFIG_IIO)
memcpy(&mcp->adc_values, &data[50], sizeof(mcp->adc_values));
#endif
break;
default:
mcp->status = -EIO;
......@@ -816,6 +839,69 @@ static int mcp2221_raw_event(struct hid_device *hdev,
complete(&mcp->wait_in_report);
break;
case MCP2221_SET_SRAM_SETTINGS:
switch (data[1]) {
case MCP2221_SUCCESS:
mcp->status = 0;
break;
default:
mcp->status = -EAGAIN;
}
complete(&mcp->wait_in_report);
break;
case MCP2221_GET_SRAM_SETTINGS:
switch (data[1]) {
case MCP2221_SUCCESS:
memcpy(&mcp->mode, &data[22], 4);
#if IS_REACHABLE(CONFIG_IIO)
mcp->dac_value = data[6] & GENMASK(4, 0);
#endif
mcp->status = 0;
break;
default:
mcp->status = -EAGAIN;
}
complete(&mcp->wait_in_report);
break;
case MCP2221_READ_FLASH_DATA:
switch (data[1]) {
case MCP2221_SUCCESS:
mcp->status = 0;
/* Only handles CHIP SETTINGS subpage currently */
if (mcp->txbuf[1] != 0) {
mcp->status = -EIO;
break;
}
#if IS_REACHABLE(CONFIG_IIO)
{
u8 tmp;
/* DAC scale value */
tmp = FIELD_GET(GENMASK(7, 6), data[6]);
if ((data[6] & BIT(5)) && tmp)
mcp->dac_scale = tmp + 4;
else
mcp->dac_scale = 5;
/* ADC scale value */
tmp = FIELD_GET(GENMASK(4, 3), data[7]);
if ((data[7] & BIT(2)) && tmp)
mcp->adc_scale = tmp - 1;
else
mcp->adc_scale = 0;
}
#endif
break;
default:
mcp->status = -EAGAIN;
}
complete(&mcp->wait_in_report);
break;
default:
mcp->status = -EIO;
complete(&mcp->wait_in_report);
......@@ -824,6 +910,190 @@ static int mcp2221_raw_event(struct hid_device *hdev,
return 1;
}
/* Device resource managed function for HID unregistration */
static void mcp2221_hid_unregister(void *ptr)
{
struct hid_device *hdev = ptr;
hid_hw_close(hdev);
hid_hw_stop(hdev);
}
/* This is needed to be sure hid_hw_stop() isn't called twice by the subsystem */
static void mcp2221_remove(struct hid_device *hdev)
{
}
#if IS_REACHABLE(CONFIG_IIO)
static int mcp2221_read_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *channel, int *val,
int *val2, long mask)
{
struct mcp2221_iio *priv = iio_priv(indio_dev);
struct mcp2221 *mcp = priv->mcp;
int ret;
if (mask == IIO_CHAN_INFO_SCALE) {
if (channel->output)
*val = 1 << mcp->dac_scale;
else
*val = 1 << mcp->adc_scale;
return IIO_VAL_INT;
}
mutex_lock(&mcp->lock);
if (channel->output) {
*val = mcp->dac_value;
ret = IIO_VAL_INT;
} else {
/* Read ADC values */
ret = mcp_chk_last_cmd_status(mcp);
if (!ret) {
*val = le16_to_cpu((__force __le16) mcp->adc_values[channel->address]);
if (*val >= BIT(10))
ret = -EINVAL;
else
ret = IIO_VAL_INT;
}
}
mutex_unlock(&mcp->lock);
return ret;
}
static int mcp2221_write_raw(struct iio_dev *indio_dev,
struct iio_chan_spec const *chan,
int val, int val2, long mask)
{
struct mcp2221_iio *priv = iio_priv(indio_dev);
struct mcp2221 *mcp = priv->mcp;
int ret;
if (val < 0 || val >= BIT(5))
return -EINVAL;
mutex_lock(&mcp->lock);
memset(mcp->txbuf, 0, 12);
mcp->txbuf[0] = MCP2221_SET_SRAM_SETTINGS;
mcp->txbuf[4] = BIT(7) | val;
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 12);
if (!ret)
mcp->dac_value = val;
mutex_unlock(&mcp->lock);
return ret;
}
static const struct iio_info mcp2221_info = {
.read_raw = &mcp2221_read_raw,
.write_raw = &mcp2221_write_raw,
};
static int mcp_iio_channels(struct mcp2221 *mcp)
{
int idx, cnt = 0;
bool dac_created = false;
/* GP0 doesn't have ADC/DAC alternative function */
for (idx = 1; idx < MCP_NGPIO; idx++) {
struct iio_chan_spec *chan = &mcp->iio_channels[cnt];
switch (mcp->mode[idx]) {
case 2:
chan->address = idx - 1;
chan->channel = cnt++;
break;
case 3:
/* GP1 doesn't have DAC alternative function */
if (idx == 1 || dac_created)
continue;
/* DAC1 and DAC2 outputs are connected to the same DAC */
dac_created = true;
chan->output = 1;
cnt++;
break;
default:
continue;
};
chan->type = IIO_VOLTAGE;
chan->indexed = 1;
chan->info_mask_separate = BIT(IIO_CHAN_INFO_RAW);
chan->info_mask_shared_by_type = BIT(IIO_CHAN_INFO_SCALE);
chan->scan_index = -1;
}
return cnt;
}
static void mcp_init_work(struct work_struct *work)
{
struct iio_dev *indio_dev;
struct mcp2221 *mcp = container_of(work, struct mcp2221, init_work.work);
struct mcp2221_iio *data;
static int retries = 5;
int ret, num_channels;
hid_hw_power(mcp->hdev, PM_HINT_FULLON);
mutex_lock(&mcp->lock);
mcp->txbuf[0] = MCP2221_GET_SRAM_SETTINGS;
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 1);
if (ret == -EAGAIN)
goto reschedule_task;
num_channels = mcp_iio_channels(mcp);
if (!num_channels)
goto unlock;
mcp->txbuf[0] = MCP2221_READ_FLASH_DATA;
mcp->txbuf[1] = 0;
ret = mcp_send_data_req_status(mcp, mcp->txbuf, 2);
if (ret == -EAGAIN)
goto reschedule_task;
indio_dev = devm_iio_device_alloc(&mcp->hdev->dev, sizeof(*data));
if (!indio_dev)
goto unlock;
data = iio_priv(indio_dev);
data->mcp = mcp;
indio_dev->name = "mcp2221";
indio_dev->modes = INDIO_DIRECT_MODE;
indio_dev->info = &mcp2221_info;
indio_dev->channels = mcp->iio_channels;
indio_dev->num_channels = num_channels;
devm_iio_device_register(&mcp->hdev->dev, indio_dev);
unlock:
mutex_unlock(&mcp->lock);
hid_hw_power(mcp->hdev, PM_HINT_NORMAL);
return;
reschedule_task:
mutex_unlock(&mcp->lock);
hid_hw_power(mcp->hdev, PM_HINT_NORMAL);
if (!retries--)
return;
/* Device is not ready to read SRAM or FLASH data, try again */
schedule_delayed_work(&mcp->init_work, msecs_to_jiffies(100));
}
#endif
static int mcp2221_probe(struct hid_device *hdev,
const struct hid_device_id *id)
{
......@@ -849,7 +1119,8 @@ static int mcp2221_probe(struct hid_device *hdev,
ret = hid_hw_open(hdev);
if (ret) {
hid_err(hdev, "can't open device\n");
goto err_hstop;
hid_hw_stop(hdev);
return ret;
}
mutex_init(&mcp->lock);
......@@ -857,6 +1128,10 @@ static int mcp2221_probe(struct hid_device *hdev,
hid_set_drvdata(hdev, mcp);
mcp->hdev = hdev;
ret = devm_add_action_or_reset(&hdev->dev, mcp2221_hid_unregister, hdev);
if (ret)
return ret;
/* Set I2C bus clock diviser */
if (i2c_clk_freq > 400)
i2c_clk_freq = 400;
......@@ -873,19 +1148,18 @@ static int mcp2221_probe(struct hid_device *hdev,
"MCP2221 usb-i2c bridge on hidraw%d",
((struct hidraw *)hdev->hidraw)->minor);
ret = i2c_add_adapter(&mcp->adapter);
ret = devm_i2c_add_adapter(&hdev->dev, &mcp->adapter);
if (ret) {
hid_err(hdev, "can't add usb-i2c adapter: %d\n", ret);
goto err_i2c;
return ret;
}
i2c_set_adapdata(&mcp->adapter, mcp);
#if IS_REACHABLE(CONFIG_GPIOLIB)
/* Setup GPIO chip */
mcp->gc = devm_kzalloc(&hdev->dev, sizeof(*mcp->gc), GFP_KERNEL);
if (!mcp->gc) {
ret = -ENOMEM;
goto err_gc;
}
if (!mcp->gc)
return -ENOMEM;
mcp->gc->label = "mcp2221_gpio";
mcp->gc->direction_input = mcp_gpio_direction_input;
......@@ -900,26 +1174,15 @@ static int mcp2221_probe(struct hid_device *hdev,
ret = devm_gpiochip_add_data(&hdev->dev, mcp->gc, mcp);
if (ret)
goto err_gc;
return 0;
err_gc:
i2c_del_adapter(&mcp->adapter);
err_i2c:
hid_hw_close(mcp->hdev);
err_hstop:
hid_hw_stop(mcp->hdev);
return ret;
}
#endif
static void mcp2221_remove(struct hid_device *hdev)
{
struct mcp2221 *mcp = hid_get_drvdata(hdev);
#if IS_REACHABLE(CONFIG_IIO)
INIT_DELAYED_WORK(&mcp->init_work, mcp_init_work);
schedule_delayed_work(&mcp->init_work, msecs_to_jiffies(100));
#endif
i2c_del_adapter(&mcp->adapter);
hid_hw_close(mcp->hdev);
hid_hw_stop(mcp->hdev);
return 0;
}
static const struct hid_device_id mcp2221_devices[] = {
......
This diff is collapsed.
......@@ -326,6 +326,8 @@ static int rmi_input_event(struct hid_device *hdev, u8 *data, int size)
if (!(test_bit(RMI_STARTED, &hdata->flags)))
return 0;
pm_wakeup_event(hdev->dev.parent, 0);
local_irq_save(flags);
rmi_set_attn_data(rmi_dev, data[1], &data[2], size - 2);
......
......@@ -62,7 +62,7 @@ struct hid_sensor_sample {
u32 raw_len;
} __packed;
static struct attribute hid_custom_attrs[] = {
static struct attribute hid_custom_attrs[HID_CUSTOM_TOTAL_ATTRS] = {
{.name = "name", .mode = S_IRUGO},
{.name = "units", .mode = S_IRUGO},
{.name = "unit-expo", .mode = S_IRUGO},
......@@ -862,7 +862,7 @@ hid_sensor_register_platform_device(struct platform_device *pdev,
return ERR_PTR(-ENOMEM);
custom_pdev = platform_device_register_data(pdev->dev.parent, dev_name,
PLATFORM_DEVID_NONE, hsdev,
PLATFORM_DEVID_AUTO, hsdev,
sizeof(*hsdev));
kfree(dev_name);
return custom_pdev;
......
......@@ -136,7 +136,7 @@ static void uclogic_parse_ugee_v2_desc_case_desc(struct uclogic_parse_ugee_v2_de
KUNIT_ARRAY_PARAM(uclogic_parse_ugee_v2_desc, uclogic_parse_ugee_v2_desc_cases,
uclogic_parse_ugee_v2_desc_case_desc);
static void uclogic_parse_ugee_v2_desc_test(struct kunit *test)
static void hid_test_uclogic_parse_ugee_v2_desc(struct kunit *test)
{
int res;
s32 desc_params[UCLOGIC_RDESC_PH_ID_NUM];
......@@ -175,7 +175,7 @@ static void uclogic_parse_ugee_v2_desc_test(struct kunit *test)
}
static struct kunit_case hid_uclogic_params_test_cases[] = {
KUNIT_CASE_PARAM(uclogic_parse_ugee_v2_desc_test,
KUNIT_CASE_PARAM(hid_test_uclogic_parse_ugee_v2_desc,
uclogic_parse_ugee_v2_desc_gen_params),
{}
};
......
......@@ -18,6 +18,7 @@
#include "usbhid/usbhid.h"
#include "hid-ids.h"
#include <linux/ctype.h>
#include <linux/string.h>
#include <asm/unaligned.h>
/**
......@@ -1211,6 +1212,69 @@ static int uclogic_params_ugee_v2_init_frame_mouse(struct uclogic_params *p)
return rc;
}
/**
* uclogic_params_ugee_v2_has_battery() - check whether a UGEE v2 device has
* battery or not.
* @hdev: The HID device of the tablet interface.
*
* Returns:
* True if the device has battery, false otherwise.
*/
static bool uclogic_params_ugee_v2_has_battery(struct hid_device *hdev)
{
/* The XP-PEN Deco LW vendor, product and version are identical to the
* Deco L. The only difference reported by their firmware is the product
* name. Add a quirk to support battery reporting on the wireless
* version.
*/
if (hdev->vendor == USB_VENDOR_ID_UGEE &&
hdev->product == USB_DEVICE_ID_UGEE_XPPEN_TABLET_DECO_L) {
struct usb_device *udev = hid_to_usb_dev(hdev);
if (strstarts(udev->product, "Deco LW"))
return true;
}
return false;
}
/**
* uclogic_params_ugee_v2_init_battery() - initialize UGEE v2 battery reporting.
* @hdev: The HID device of the tablet interface, cannot be NULL.
* @p: Parameters to fill in, cannot be NULL.
*
* Returns:
* Zero, if successful. A negative errno code on error.
*/
static int uclogic_params_ugee_v2_init_battery(struct hid_device *hdev,
struct uclogic_params *p)
{
int rc = 0;
if (!hdev || !p)
return -EINVAL;
/* Some tablets contain invalid characters in hdev->uniq, throwing a
* "hwmon: '<name>' is not a valid name attribute, please fix" error.
* Use the device vendor and product IDs instead.
*/
snprintf(hdev->uniq, sizeof(hdev->uniq), "%x-%x", hdev->vendor,
hdev->product);
rc = uclogic_params_frame_init_with_desc(&p->frame_list[1],
uclogic_rdesc_ugee_v2_battery_template_arr,
uclogic_rdesc_ugee_v2_battery_template_size,
UCLOGIC_RDESC_UGEE_V2_BATTERY_ID);
if (rc)
return rc;
p->frame_list[1].suffix = "Battery";
p->pen.subreport_list[1].value = 0xf2;
p->pen.subreport_list[1].id = UCLOGIC_RDESC_UGEE_V2_BATTERY_ID;
return rc;
}
/**
* uclogic_params_ugee_v2_init() - initialize a UGEE graphics tablets by
* discovering their parameters.
......@@ -1334,6 +1398,15 @@ static int uclogic_params_ugee_v2_init(struct uclogic_params *params,
if (rc)
goto cleanup;
/* Initialize the battery interface*/
if (uclogic_params_ugee_v2_has_battery(hdev)) {
rc = uclogic_params_ugee_v2_init_battery(hdev, &p);
if (rc) {
hid_err(hdev, "error initializing battery: %d\n", rc);
goto cleanup;
}
}
output:
/* Output parameters */
memcpy(params, &p, sizeof(*params));
......
......@@ -187,7 +187,7 @@ static void uclogic_template_case_desc(struct uclogic_template_case *t,
KUNIT_ARRAY_PARAM(uclogic_template, uclogic_template_cases,
uclogic_template_case_desc);
static void uclogic_template_test(struct kunit *test)
static void hid_test_uclogic_template(struct kunit *test)
{
__u8 *res;
const struct uclogic_template_case *params = test->param_value;
......@@ -203,7 +203,7 @@ static void uclogic_template_test(struct kunit *test)
}
static struct kunit_case hid_uclogic_rdesc_test_cases[] = {
KUNIT_CASE_PARAM(uclogic_template_test, uclogic_template_gen_params),
KUNIT_CASE_PARAM(hid_test_uclogic_template, uclogic_template_gen_params),
{}
};
......
......@@ -1035,6 +1035,40 @@ const __u8 uclogic_rdesc_ugee_v2_frame_mouse_template_arr[] = {
const size_t uclogic_rdesc_ugee_v2_frame_mouse_template_size =
sizeof(uclogic_rdesc_ugee_v2_frame_mouse_template_arr);
/* Fixed report descriptor template for UGEE v2 battery reports */
const __u8 uclogic_rdesc_ugee_v2_battery_template_arr[] = {
0x05, 0x01, /* Usage Page (Desktop), */
0x09, 0x07, /* Usage (Keypad), */
0xA1, 0x01, /* Collection (Application), */
0x85, UCLOGIC_RDESC_UGEE_V2_BATTERY_ID,
/* Report ID, */
0x75, 0x08, /* Report Size (8), */
0x95, 0x02, /* Report Count (2), */
0x81, 0x01, /* Input (Constant), */
0x05, 0x84, /* Usage Page (Power Device), */
0x05, 0x85, /* Usage Page (Battery System), */
0x09, 0x65, /* Usage Page (AbsoluteStateOfCharge), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x01, /* Report Count (1), */
0x15, 0x00, /* Logical Minimum (0), */
0x26, 0xff, 0x00, /* Logical Maximum (255), */
0x81, 0x02, /* Input (Variable), */
0x75, 0x01, /* Report Size (1), */
0x95, 0x01, /* Report Count (1), */
0x15, 0x00, /* Logical Minimum (0), */
0x25, 0x01, /* Logical Maximum (1), */
0x09, 0x44, /* Usage Page (Charging), */
0x81, 0x02, /* Input (Variable), */
0x95, 0x07, /* Report Count (7), */
0x81, 0x01, /* Input (Constant), */
0x75, 0x08, /* Report Size (8), */
0x95, 0x07, /* Report Count (7), */
0x81, 0x01, /* Input (Constant), */
0xC0 /* End Collection */
};
const size_t uclogic_rdesc_ugee_v2_battery_template_size =
sizeof(uclogic_rdesc_ugee_v2_battery_template_arr);
/* Fixed report descriptor for Ugee EX07 frame */
const __u8 uclogic_rdesc_ugee_ex07_frame_arr[] = {
0x05, 0x01, /* Usage Page (Desktop), */
......
......@@ -161,6 +161,9 @@ extern const size_t uclogic_rdesc_v2_frame_dial_size;
/* Device ID byte offset in v2 frame dial reports */
#define UCLOGIC_RDESC_V2_FRAME_DIAL_DEV_ID_BYTE 0x4
/* Report ID for tweaked UGEE v2 battery reports */
#define UCLOGIC_RDESC_UGEE_V2_BATTERY_ID 0xba
/* Fixed report descriptor template for UGEE v2 pen reports */
extern const __u8 uclogic_rdesc_ugee_v2_pen_template_arr[];
extern const size_t uclogic_rdesc_ugee_v2_pen_template_size;
......@@ -177,6 +180,10 @@ extern const size_t uclogic_rdesc_ugee_v2_frame_dial_template_size;
extern const __u8 uclogic_rdesc_ugee_v2_frame_mouse_template_arr[];
extern const size_t uclogic_rdesc_ugee_v2_frame_mouse_template_size;
/* Fixed report descriptor template for UGEE v2 battery reports */
extern const __u8 uclogic_rdesc_ugee_v2_battery_template_arr[];
extern const size_t uclogic_rdesc_ugee_v2_battery_template_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;
......
......@@ -458,6 +458,9 @@ static __u8 wiimote_cmd_read_ext(struct wiimote_data *wdata, __u8 *rmem)
if (rmem[0] == 0x00 && rmem[1] == 0x00 &&
rmem[4] == 0x01 && rmem[5] == 0x03)
return WIIMOTE_EXT_GUITAR;
if (rmem[0] == 0x03 && rmem[1] == 0x00 &&
rmem[4] == 0x01 && rmem[5] == 0x03)
return WIIMOTE_EXT_TURNTABLE;
return WIIMOTE_EXT_UNKNOWN;
}
......@@ -495,6 +498,7 @@ static bool wiimote_cmd_map_mp(struct wiimote_data *wdata, __u8 exttype)
case WIIMOTE_EXT_GUITAR:
wmem = 0x07;
break;
case WIIMOTE_EXT_TURNTABLE:
case WIIMOTE_EXT_NUNCHUK:
wmem = 0x05;
break;
......@@ -1082,6 +1086,7 @@ static const char *wiimote_exttype_names[WIIMOTE_EXT_NUM] = {
[WIIMOTE_EXT_PRO_CONTROLLER] = "Nintendo Wii U Pro Controller",
[WIIMOTE_EXT_DRUMS] = "Nintendo Wii Drums",
[WIIMOTE_EXT_GUITAR] = "Nintendo Wii Guitar",
[WIIMOTE_EXT_TURNTABLE] = "Nintendo Wii Turntable"
};
/*
......@@ -1669,6 +1674,8 @@ static ssize_t wiimote_ext_show(struct device *dev,
return sprintf(buf, "drums\n");
case WIIMOTE_EXT_GUITAR:
return sprintf(buf, "guitar\n");
case WIIMOTE_EXT_TURNTABLE:
return sprintf(buf, "turntable\n");
case WIIMOTE_EXT_UNKNOWN:
default:
return sprintf(buf, "unknown\n");
......
......@@ -2403,6 +2403,230 @@ static const struct wiimod_ops wiimod_guitar = {
.in_ext = wiimod_guitar_in_ext,
};
/*
* Turntable
* DJ Hero came with a Turntable Controller that was plugged in
* as an extension.
* We create a separate device for turntables and report all information via this
* input device.
*/
enum wiimod_turntable_keys {
WIIMOD_TURNTABLE_KEY_G_RIGHT,
WIIMOD_TURNTABLE_KEY_R_RIGHT,
WIIMOD_TURNTABLE_KEY_B_RIGHT,
WIIMOD_TURNTABLE_KEY_G_LEFT,
WIIMOD_TURNTABLE_KEY_R_LEFT,
WIIMOD_TURNTABLE_KEY_B_LEFT,
WIIMOD_TURNTABLE_KEY_EUPHORIA,
WIIMOD_TURNTABLE_KEY_PLUS,
WIIMOD_TURNTABLE_KEY_MINUS,
WIIMOD_TURNTABLE_KEY_NUM
};
static const __u16 wiimod_turntable_map[] = {
BTN_1, /* WIIMOD_TURNTABLE_KEY_G_RIGHT */
BTN_2, /* WIIMOD_TURNTABLE_KEY_R_RIGHT */
BTN_3, /* WIIMOD_TURNTABLE_KEY_B_RIGHT */
BTN_4, /* WIIMOD_TURNTABLE_KEY_G_LEFT */
BTN_5, /* WIIMOD_TURNTABLE_KEY_R_LEFT */
BTN_6, /* WIIMOD_TURNTABLE_KEY_B_LEFT */
BTN_7, /* WIIMOD_TURNTABLE_KEY_EUPHORIA */
BTN_START, /* WIIMOD_TURNTABLE_KEY_PLUS */
BTN_SELECT, /* WIIMOD_TURNTABLE_KEY_MINUS */
};
static void wiimod_turntable_in_ext(struct wiimote_data *wdata, const __u8 *ext)
{
__u8 be, cs, sx, sy, ed, rtt, rbg, rbr, rbb, ltt, lbg, lbr, lbb, bp, bm;
/*
* Byte | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
*------+------+-----+-----+-----+-----+------+------+--------+
* 0 | RTT<4:3> | SX <5:0> |
* 1 | RTT<2:1> | SY <5:0> |
*------+------+-----+-----+-----+-----+------+------+--------+
* 2 |RTT<0>| ED<4:3> | CS<3:0> | RTT<5> |
*------+------+-----+-----+-----+-----+------+------+--------+
* 3 | ED<2:0> | LTT<4:0> |
*------+------+-----+-----+-----+-----+------+------+--------+
* 4 | 0 | 0 | LBR | B- | 0 | B+ | RBR | LTT<5> |
*------+------+-----+-----+-----+-----+------+------+--------+
* 5 | LBB | 0 | RBG | BE | LBG | RBB | 0 | 0 |
*------+------+-----+-----+-----+-----+------+------+--------+
* All pressed buttons are 0
*
* With Motion+ enabled, it will look like this:
* Byte | 8 | 7 | 6 | 5 | 4 | 3 | 2 | 1 |
*------+------+-----+-----+-----+-----+------+------+--------+
* 1 | RTT<4:3> | SX <5:1> | 0 |
* 2 | RTT<2:1> | SY <5:1> | 0 |
*------+------+-----+-----+-----+-----+------+------+--------+
* 3 |RTT<0>| ED<4:3> | CS<3:0> | RTT<5> |
*------+------+-----+-----+-----+-----+------+------+--------+
* 4 | ED<2:0> | LTT<4:0> |
*------+------+-----+-----+-----+-----+------+------+--------+
* 5 | 0 | 0 | LBR | B- | 0 | B+ | RBR | XXXX |
*------+------+-----+-----+-----+-----+------+------+--------+
* 6 | LBB | 0 | RBG | BE | LBG | RBB | XXXX | XXXX |
*------+------+-----+-----+-----+-----+------+------+--------+
*/
be = !(ext[5] & 0x10);
cs = ((ext[2] & 0x1e));
sx = ext[0] & 0x3f;
sy = ext[1] & 0x3f;
ed = (ext[3] & 0xe0) >> 5;
rtt = ((ext[2] & 0x01) << 5 | (ext[0] & 0xc0) >> 3 | (ext[1] & 0xc0) >> 5 | ( ext[2] & 0x80 ) >> 7);
ltt = ((ext[4] & 0x01) << 5 | (ext[3] & 0x1f));
rbg = !(ext[5] & 0x20);
rbr = !(ext[4] & 0x02);
rbb = !(ext[5] & 0x04);
lbg = !(ext[5] & 0x08);
lbb = !(ext[5] & 0x80);
lbr = !(ext[4] & 0x20);
bm = !(ext[4] & 0x10);
bp = !(ext[4] & 0x04);
if (wdata->state.flags & WIIPROTO_FLAG_MP_ACTIVE) {
ltt = (ext[4] & 0x01) << 5;
sx &= 0x3e;
sy &= 0x3e;
}
input_report_abs(wdata->extension.input, ABS_X, sx);
input_report_abs(wdata->extension.input, ABS_Y, sy);
input_report_abs(wdata->extension.input, ABS_HAT0X, rtt);
input_report_abs(wdata->extension.input, ABS_HAT1X, ltt);
input_report_abs(wdata->extension.input, ABS_HAT2X, cs);
input_report_abs(wdata->extension.input, ABS_HAT3X, ed);
input_report_key(wdata->extension.input,
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_G_RIGHT],
rbg);
input_report_key(wdata->extension.input,
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_R_RIGHT],
rbr);
input_report_key(wdata->extension.input,
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_B_RIGHT],
rbb);
input_report_key(wdata->extension.input,
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_G_LEFT],
lbg);
input_report_key(wdata->extension.input,
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_R_LEFT],
lbr);
input_report_key(wdata->extension.input,
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_B_LEFT],
lbb);
input_report_key(wdata->extension.input,
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_EUPHORIA],
be);
input_report_key(wdata->extension.input,
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_PLUS],
bp);
input_report_key(wdata->extension.input,
wiimod_turntable_map[WIIMOD_TURNTABLE_KEY_MINUS],
bm);
input_sync(wdata->extension.input);
}
static int wiimod_turntable_open(struct input_dev *dev)
{
struct wiimote_data *wdata = input_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&wdata->state.lock, flags);
wdata->state.flags |= WIIPROTO_FLAG_EXT_USED;
wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
spin_unlock_irqrestore(&wdata->state.lock, flags);
return 0;
}
static void wiimod_turntable_close(struct input_dev *dev)
{
struct wiimote_data *wdata = input_get_drvdata(dev);
unsigned long flags;
spin_lock_irqsave(&wdata->state.lock, flags);
wdata->state.flags &= ~WIIPROTO_FLAG_EXT_USED;
wiiproto_req_drm(wdata, WIIPROTO_REQ_NULL);
spin_unlock_irqrestore(&wdata->state.lock, flags);
}
static int wiimod_turntable_probe(const struct wiimod_ops *ops,
struct wiimote_data *wdata)
{
int ret, i;
wdata->extension.input = input_allocate_device();
if (!wdata->extension.input)
return -ENOMEM;
input_set_drvdata(wdata->extension.input, wdata);
wdata->extension.input->open = wiimod_turntable_open;
wdata->extension.input->close = wiimod_turntable_close;
wdata->extension.input->dev.parent = &wdata->hdev->dev;
wdata->extension.input->id.bustype = wdata->hdev->bus;
wdata->extension.input->id.vendor = wdata->hdev->vendor;
wdata->extension.input->id.product = wdata->hdev->product;
wdata->extension.input->id.version = wdata->hdev->version;
wdata->extension.input->name = WIIMOTE_NAME " Turntable";
set_bit(EV_KEY, wdata->extension.input->evbit);
for (i = 0; i < WIIMOD_TURNTABLE_KEY_NUM; ++i)
set_bit(wiimod_turntable_map[i],
wdata->extension.input->keybit);
set_bit(EV_ABS, wdata->extension.input->evbit);
set_bit(ABS_X, wdata->extension.input->absbit);
set_bit(ABS_Y, wdata->extension.input->absbit);
set_bit(ABS_HAT0X, wdata->extension.input->absbit);
set_bit(ABS_HAT1X, wdata->extension.input->absbit);
set_bit(ABS_HAT2X, wdata->extension.input->absbit);
set_bit(ABS_HAT3X, wdata->extension.input->absbit);
input_set_abs_params(wdata->extension.input,
ABS_X, 0, 63, 1, 0);
input_set_abs_params(wdata->extension.input,
ABS_Y, 63, 0, 1, 0);
input_set_abs_params(wdata->extension.input,
ABS_HAT0X, -8, 8, 0, 0);
input_set_abs_params(wdata->extension.input,
ABS_HAT1X, -8, 8, 0, 0);
input_set_abs_params(wdata->extension.input,
ABS_HAT2X, 0, 31, 1, 1);
input_set_abs_params(wdata->extension.input,
ABS_HAT3X, 0, 7, 0, 0);
ret = input_register_device(wdata->extension.input);
if (ret)
goto err_free;
return 0;
err_free:
input_free_device(wdata->extension.input);
wdata->extension.input = NULL;
return ret;
}
static void wiimod_turntable_remove(const struct wiimod_ops *ops,
struct wiimote_data *wdata)
{
if (!wdata->extension.input)
return;
input_unregister_device(wdata->extension.input);
wdata->extension.input = NULL;
}
static const struct wiimod_ops wiimod_turntable = {
.flags = 0,
.arg = 0,
.probe = wiimod_turntable_probe,
.remove = wiimod_turntable_remove,
.in_ext = wiimod_turntable_in_ext,
};
/*
* Builtin Motion Plus
* This module simply sets the WIIPROTO_FLAG_BUILTIN_MP protocol flag which
......@@ -2657,4 +2881,5 @@ const struct wiimod_ops *wiimod_ext_table[WIIMOTE_EXT_NUM] = {
[WIIMOTE_EXT_PRO_CONTROLLER] = &wiimod_pro,
[WIIMOTE_EXT_DRUMS] = &wiimod_drums,
[WIIMOTE_EXT_GUITAR] = &wiimod_guitar,
[WIIMOTE_EXT_TURNTABLE] = &wiimod_turntable,
};
......@@ -88,6 +88,7 @@ enum wiimote_exttype {
WIIMOTE_EXT_PRO_CONTROLLER,
WIIMOTE_EXT_DRUMS,
WIIMOTE_EXT_GUITAR,
WIIMOTE_EXT_TURNTABLE,
WIIMOTE_EXT_NUM,
};
......
......@@ -554,6 +554,7 @@ static void i2c_hid_get_input(struct i2c_hid *ihid)
i2c_hid_dbg(ihid, "input: %*ph\n", ret_size, ihid->inbuf);
if (test_bit(I2C_HID_STARTED, &ihid->flags)) {
if (ihid->hid->group != HID_GROUP_RMI)
pm_wakeup_event(&ihid->client->dev, 0);
hid_input_report(ihid->hid, HID_INPUT_REPORT,
......
......@@ -68,8 +68,7 @@ static void elan_i2c_hid_power_down(struct i2chid_ops *ops)
regulator_disable(ihid_elan->vcc33);
}
static int i2c_hid_of_elan_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int i2c_hid_of_elan_probe(struct i2c_client *client)
{
struct i2c_hid_of_elan *ihid_elan;
......@@ -119,7 +118,7 @@ static struct i2c_driver elan_i2c_hid_ts_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(elan_i2c_hid_of_match),
},
.probe = i2c_hid_of_elan_probe,
.probe_new = i2c_hid_of_elan_probe,
.remove = i2c_hid_core_remove,
.shutdown = i2c_hid_core_shutdown,
};
......
......@@ -87,8 +87,7 @@ static int ihid_goodix_vdd_notify(struct notifier_block *nb,
return ret;
}
static int i2c_hid_of_goodix_probe(struct i2c_client *client,
const struct i2c_device_id *id)
static int i2c_hid_of_goodix_probe(struct i2c_client *client)
{
struct i2c_hid_of_goodix *ihid_goodix;
int ret;
......@@ -167,7 +166,7 @@ static struct i2c_driver goodix_i2c_hid_ts_driver = {
.probe_type = PROBE_PREFER_ASYNCHRONOUS,
.of_match_table = of_match_ptr(goodix_i2c_hid_of_match),
},
.probe = i2c_hid_of_goodix_probe,
.probe_new = i2c_hid_of_goodix_probe,
.remove = i2c_hid_core_remove,
.shutdown = i2c_hid_core_shutdown,
};
......
......@@ -66,8 +66,7 @@ static void i2c_hid_of_power_down(struct i2chid_ops *ops)
ihid_of->supplies);
}
static int i2c_hid_of_probe(struct i2c_client *client,
const struct i2c_device_id *dev_id)
static int i2c_hid_of_probe(struct i2c_client *client)
{
struct device *dev = &client->dev;
struct i2c_hid_of *ihid_of;
......@@ -138,7 +137,7 @@ static struct i2c_driver i2c_hid_of_driver = {
.of_match_table = of_match_ptr(i2c_hid_of_match),
},
.probe = i2c_hid_of_probe,
.probe_new = i2c_hid_of_probe,
.remove = i2c_hid_core_remove,
.shutdown = i2c_hid_core_shutdown,
.id_table = i2c_hid_of_id_table,
......
......@@ -841,7 +841,6 @@ void recv_ishtp_cl_msg(struct ishtp_device *dev,
unsigned char *buffer = NULL;
struct ishtp_cl_rb *complete_rb = NULL;
unsigned long flags;
int rb_count;
if (ishtp_hdr->reserved) {
dev_err(dev->devc, "corrupted message header.\n");
......@@ -855,9 +854,7 @@ void recv_ishtp_cl_msg(struct ishtp_device *dev,
}
spin_lock_irqsave(&dev->read_list_spinlock, flags);
rb_count = -1;
list_for_each_entry(rb, &dev->read_list.list, list) {
++rb_count;
cl = rb->cl;
if (!cl || !(cl->host_client_id == ishtp_hdr->host_addr &&
cl->fw_client_id == ishtp_hdr->fw_addr) ||
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment