Skip to content

Commit

Permalink
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel…
Browse files Browse the repository at this point in the history
…/git/dtor/input

Pull input fixes from Dmitry Torokhov:

 - joydev now implements a blacklist to avoid creating joystick nodes
   for accelerometers found in composite devices such as PlaStation
   controllers

 - assorted driver fixes

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: ims-psu - check if CDC union descriptor is sane
  Input: joydev - blacklist ds3/ds4/udraw motion sensors
  Input: allow matching device IDs on property bits
  Input: factor out and export input_device_id matching code
  Input: goodix - poll the 'buffer status' bit before reading data
  Input: axp20x-pek - fix module not auto-loading for axp221 pek
  Input: tca8418 - enable interrupt after it has been requested
  Input: stmfts - fix setting ABS_MT_POSITION_* maximum size
  Input: ti_am335x_tsc - fix incorrect step config for 5 wire touchscreen
  Input: synaptics - disable kernel tracking on SMBus devices
  • Loading branch information
torvalds committed Oct 22, 2017
2 parents ec0145e + ea04efe commit e5f468b
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 97 deletions.
84 changes: 39 additions & 45 deletions drivers/input/input.c
Original file line number Diff line number Diff line change
Expand Up @@ -933,58 +933,52 @@ int input_set_keycode(struct input_dev *dev,
}
EXPORT_SYMBOL(input_set_keycode);

bool input_match_device_id(const struct input_dev *dev,
const struct input_device_id *id)
{
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->bustype != dev->id.bustype)
return false;

if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id->vendor != dev->id.vendor)
return false;

if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
if (id->product != dev->id.product)
return false;

if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
if (id->version != dev->id.version)
return false;

if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX) ||
!bitmap_subset(id->keybit, dev->keybit, KEY_MAX) ||
!bitmap_subset(id->relbit, dev->relbit, REL_MAX) ||
!bitmap_subset(id->absbit, dev->absbit, ABS_MAX) ||
!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX) ||
!bitmap_subset(id->ledbit, dev->ledbit, LED_MAX) ||
!bitmap_subset(id->sndbit, dev->sndbit, SND_MAX) ||
!bitmap_subset(id->ffbit, dev->ffbit, FF_MAX) ||
!bitmap_subset(id->swbit, dev->swbit, SW_MAX) ||
!bitmap_subset(id->propbit, dev->propbit, INPUT_PROP_MAX)) {
return false;
}

return true;
}
EXPORT_SYMBOL(input_match_device_id);

static const struct input_device_id *input_match_device(struct input_handler *handler,
struct input_dev *dev)
{
const struct input_device_id *id;

for (id = handler->id_table; id->flags || id->driver_info; id++) {

if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->bustype != dev->id.bustype)
continue;

if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id->vendor != dev->id.vendor)
continue;

if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
if (id->product != dev->id.product)
continue;

if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
if (id->version != dev->id.version)
continue;

if (!bitmap_subset(id->evbit, dev->evbit, EV_MAX))
continue;

if (!bitmap_subset(id->keybit, dev->keybit, KEY_MAX))
continue;

if (!bitmap_subset(id->relbit, dev->relbit, REL_MAX))
continue;

if (!bitmap_subset(id->absbit, dev->absbit, ABS_MAX))
continue;

if (!bitmap_subset(id->mscbit, dev->mscbit, MSC_MAX))
continue;

if (!bitmap_subset(id->ledbit, dev->ledbit, LED_MAX))
continue;

if (!bitmap_subset(id->sndbit, dev->sndbit, SND_MAX))
continue;

if (!bitmap_subset(id->ffbit, dev->ffbit, FF_MAX))
continue;

if (!bitmap_subset(id->swbit, dev->swbit, SW_MAX))
continue;

if (!handler->match || handler->match(handler, dev))
if (input_match_device_id(dev, id) &&
(!handler->match || handler->match(handler, dev))) {
return id;
}
}

return NULL;
Expand Down
70 changes: 64 additions & 6 deletions drivers/input/joydev.c
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,68 @@ static void joydev_cleanup(struct joydev *joydev)
input_close_device(handle);
}

/*
* These codes are copied from from hid-ids.h, unfortunately there is no common
* usb_ids/bt_ids.h header.
*/
#define USB_VENDOR_ID_SONY 0x054c
#define USB_DEVICE_ID_SONY_PS3_CONTROLLER 0x0268
#define USB_DEVICE_ID_SONY_PS4_CONTROLLER 0x05c4
#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_2 0x09cc
#define USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE 0x0ba0

#define USB_VENDOR_ID_THQ 0x20d6
#define USB_DEVICE_ID_THQ_PS3_UDRAW 0xcb17

#define ACCEL_DEV(vnd, prd) \
{ \
.flags = INPUT_DEVICE_ID_MATCH_VENDOR | \
INPUT_DEVICE_ID_MATCH_PRODUCT | \
INPUT_DEVICE_ID_MATCH_PROPBIT, \
.vendor = (vnd), \
.product = (prd), \
.propbit = { BIT_MASK(INPUT_PROP_ACCELEROMETER) }, \
}

static const struct input_device_id joydev_blacklist[] = {
/* Avoid touchpads and touchscreens */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT_MASK(EV_KEY) },
.keybit = { [BIT_WORD(BTN_TOUCH)] = BIT_MASK(BTN_TOUCH) },
},
/* Avoid tablets, digitisers and similar devices */
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT,
.evbit = { BIT_MASK(EV_KEY) },
.keybit = { [BIT_WORD(BTN_DIGI)] = BIT_MASK(BTN_DIGI) },
},
/* Disable accelerometers on composite devices */
ACCEL_DEV(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER),
ACCEL_DEV(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER),
ACCEL_DEV(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_2),
ACCEL_DEV(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS4_CONTROLLER_DONGLE),
ACCEL_DEV(USB_VENDOR_ID_THQ, USB_DEVICE_ID_THQ_PS3_UDRAW),
{ /* sentinel */ }
};

static bool joydev_dev_is_blacklisted(struct input_dev *dev)
{
const struct input_device_id *id;

for (id = joydev_blacklist; id->flags; id++) {
if (input_match_device_id(dev, id)) {
dev_dbg(&dev->dev,
"joydev: blacklisting '%s'\n", dev->name);
return true;
}
}

return false;
}

static bool joydev_dev_is_absolute_mouse(struct input_dev *dev)
{
DECLARE_BITMAP(jd_scratch, KEY_CNT);
Expand Down Expand Up @@ -807,12 +869,8 @@ static bool joydev_dev_is_absolute_mouse(struct input_dev *dev)

static bool joydev_match(struct input_handler *handler, struct input_dev *dev)
{
/* Avoid touchpads and touchscreens */
if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_TOUCH, dev->keybit))
return false;

/* Avoid tablets, digitisers and similar devices */
if (test_bit(EV_KEY, dev->evbit) && test_bit(BTN_DIGI, dev->keybit))
/* Disable blacklisted devices */
if (joydev_dev_is_blacklisted(dev))
return false;

/* Avoid absolute mice */
Expand Down
29 changes: 17 additions & 12 deletions drivers/input/keyboard/tca8418_keypad.c
Original file line number Diff line number Diff line change
Expand Up @@ -234,14 +234,7 @@ static irqreturn_t tca8418_irq_handler(int irq, void *dev_id)
static int tca8418_configure(struct tca8418_keypad *keypad_data,
u32 rows, u32 cols)
{
int reg, error;

/* Write config register, if this fails assume device not present */
error = tca8418_write_byte(keypad_data, REG_CFG,
CFG_INT_CFG | CFG_OVR_FLOW_IEN | CFG_KE_IEN);
if (error < 0)
return -ENODEV;

int reg, error = 0;

/* Assemble a mask for row and column registers */
reg = ~(~0 << rows);
Expand All @@ -257,6 +250,12 @@ static int tca8418_configure(struct tca8418_keypad *keypad_data,
error |= tca8418_write_byte(keypad_data, REG_DEBOUNCE_DIS2, reg >> 8);
error |= tca8418_write_byte(keypad_data, REG_DEBOUNCE_DIS3, reg >> 16);

if (error)
return error;

error = tca8418_write_byte(keypad_data, REG_CFG,
CFG_INT_CFG | CFG_OVR_FLOW_IEN | CFG_KE_IEN);

return error;
}

Expand All @@ -268,6 +267,7 @@ static int tca8418_keypad_probe(struct i2c_client *client,
struct input_dev *input;
u32 rows = 0, cols = 0;
int error, row_shift, max_keys;
u8 reg;

/* Check i2c driver capabilities */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE)) {
Expand Down Expand Up @@ -301,10 +301,10 @@ static int tca8418_keypad_probe(struct i2c_client *client,
keypad_data->client = client;
keypad_data->row_shift = row_shift;

/* Initialize the chip or fail if chip isn't present */
error = tca8418_configure(keypad_data, rows, cols);
if (error < 0)
return error;
/* Read key lock register, if this fails assume device not present */
error = tca8418_read_byte(keypad_data, REG_KEY_LCK_EC, &reg);
if (error)
return -ENODEV;

/* Configure input device */
input = devm_input_allocate_device(dev);
Expand Down Expand Up @@ -340,6 +340,11 @@ static int tca8418_keypad_probe(struct i2c_client *client,
return error;
}

/* Initialize the chip */
error = tca8418_configure(keypad_data, rows, cols);
if (error < 0)
return error;

error = input_register_device(input);
if (error) {
dev_err(dev, "Unable to register input device, error: %d\n",
Expand Down
2 changes: 1 addition & 1 deletion drivers/input/misc/axp20x-pek.c
Original file line number Diff line number Diff line change
Expand Up @@ -403,6 +403,7 @@ static const struct platform_device_id axp_pek_id_match[] = {
},
{ /* sentinel */ }
};
MODULE_DEVICE_TABLE(platform, axp_pek_id_match);

static struct platform_driver axp20x_pek_driver = {
.probe = axp20x_pek_probe,
Expand All @@ -417,4 +418,3 @@ module_platform_driver(axp20x_pek_driver);
MODULE_DESCRIPTION("axp20x Power Button");
MODULE_AUTHOR("Carlo Caione <[email protected]>");
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:axp20x-pek");
16 changes: 14 additions & 2 deletions drivers/input/misc/ims-pcu.c
Original file line number Diff line number Diff line change
Expand Up @@ -1635,13 +1635,25 @@ ims_pcu_get_cdc_union_desc(struct usb_interface *intf)
return NULL;
}

while (buflen > 0) {
while (buflen >= sizeof(*union_desc)) {
union_desc = (struct usb_cdc_union_desc *)buf;

if (union_desc->bLength > buflen) {
dev_err(&intf->dev, "Too large descriptor\n");
return NULL;
}

if (union_desc->bDescriptorType == USB_DT_CS_INTERFACE &&
union_desc->bDescriptorSubType == USB_CDC_UNION_TYPE) {
dev_dbg(&intf->dev, "Found union header\n");
return union_desc;

if (union_desc->bLength >= sizeof(*union_desc))
return union_desc;

dev_err(&intf->dev,
"Union descriptor to short (%d vs %zd\n)",
union_desc->bLength, sizeof(*union_desc));
return NULL;
}

buflen -= union_desc->bLength;
Expand Down
3 changes: 1 addition & 2 deletions drivers/input/mouse/synaptics.c
Original file line number Diff line number Diff line change
Expand Up @@ -1709,8 +1709,7 @@ static int synaptics_create_intertouch(struct psmouse *psmouse,
.sensor_pdata = {
.sensor_type = rmi_sensor_touchpad,
.axis_align.flip_y = true,
/* to prevent cursors jumps: */
.kernel_tracking = true,
.kernel_tracking = false,
.topbuttonpad = topbuttonpad,
},
.f30_data = {
Expand Down
67 changes: 44 additions & 23 deletions drivers/input/touchscreen/goodix.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,9 @@ struct goodix_ts_data {
#define GOODIX_REG_CONFIG_DATA 0x8047
#define GOODIX_REG_ID 0x8140

#define GOODIX_BUFFER_STATUS_READY BIT(7)
#define GOODIX_BUFFER_STATUS_TIMEOUT 20

#define RESOLUTION_LOC 1
#define MAX_CONTACTS_LOC 5
#define TRIGGER_LOC 6
Expand Down Expand Up @@ -195,35 +198,53 @@ static int goodix_get_cfg_len(u16 id)

static int goodix_ts_read_input_report(struct goodix_ts_data *ts, u8 *data)
{
unsigned long max_timeout;
int touch_num;
int error;

error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR, data,
GOODIX_CONTACT_SIZE + 1);
if (error) {
dev_err(&ts->client->dev, "I2C transfer error: %d\n", error);
return error;
}
/*
* The 'buffer status' bit, which indicates that the data is valid, is
* not set as soon as the interrupt is raised, but slightly after.
* This takes around 10 ms to happen, so we poll for 20 ms.
*/
max_timeout = jiffies + msecs_to_jiffies(GOODIX_BUFFER_STATUS_TIMEOUT);
do {
error = goodix_i2c_read(ts->client, GOODIX_READ_COOR_ADDR,
data, GOODIX_CONTACT_SIZE + 1);
if (error) {
dev_err(&ts->client->dev, "I2C transfer error: %d\n",
error);
return error;
}

if (!(data[0] & 0x80))
return -EAGAIN;
if (data[0] & GOODIX_BUFFER_STATUS_READY) {
touch_num = data[0] & 0x0f;
if (touch_num > ts->max_touch_num)
return -EPROTO;

if (touch_num > 1) {
data += 1 + GOODIX_CONTACT_SIZE;
error = goodix_i2c_read(ts->client,
GOODIX_READ_COOR_ADDR +
1 + GOODIX_CONTACT_SIZE,
data,
GOODIX_CONTACT_SIZE *
(touch_num - 1));
if (error)
return error;
}

return touch_num;
}

touch_num = data[0] & 0x0f;
if (touch_num > ts->max_touch_num)
return -EPROTO;

if (touch_num > 1) {
data += 1 + GOODIX_CONTACT_SIZE;
error = goodix_i2c_read(ts->client,
GOODIX_READ_COOR_ADDR +
1 + GOODIX_CONTACT_SIZE,
data,
GOODIX_CONTACT_SIZE * (touch_num - 1));
if (error)
return error;
}
usleep_range(1000, 2000); /* Poll every 1 - 2 ms */
} while (time_before(jiffies, max_timeout));

return touch_num;
/*
* The Goodix panel will send spurious interrupts after a
* 'finger up' event, which will always cause a timeout.
*/
return 0;
}

static void goodix_ts_report_touch(struct goodix_ts_data *ts, u8 *coor_data)
Expand Down
6 changes: 2 additions & 4 deletions drivers/input/touchscreen/stmfts.c
Original file line number Diff line number Diff line change
Expand Up @@ -663,12 +663,10 @@ static int stmfts_probe(struct i2c_client *client,
sdata->input->open = stmfts_input_open;
sdata->input->close = stmfts_input_close;

input_set_capability(sdata->input, EV_ABS, ABS_MT_POSITION_X);
input_set_capability(sdata->input, EV_ABS, ABS_MT_POSITION_Y);
touchscreen_parse_properties(sdata->input, true, &sdata->prop);

input_set_abs_params(sdata->input, ABS_MT_POSITION_X, 0,
sdata->prop.max_x, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_POSITION_Y, 0,
sdata->prop.max_y, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MAJOR, 0, 255, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_TOUCH_MINOR, 0, 255, 0, 0);
input_set_abs_params(sdata->input, ABS_MT_ORIENTATION, 0, 255, 0, 0);
Expand Down
Loading

0 comments on commit e5f468b

Please sign in to comment.