Commit 44bf091f authored by Linus Torvalds's avatar Linus Torvalds

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

Pull input subsystem updates from Dmitry Torokhov:
 "A fix for MT breakage, enhancement to Elantech PS/2 driver and a
  couple of assorted fixes"

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: elantech - add support for trackpoint found on some v3 models
  Input: elantech - reset the device when elantech probe fails
  Input: ALPS - suppress message about 'Unknown touchpad'
  Input: fix used slots detection breakage
  Input: sparc - i8042-sparcio.h: fix unused kbd_res warning
  Input: atmel_mxt_ts - improve description of gpio-keymap property
parents cce15667 a2418fc4
...@@ -15,6 +15,17 @@ Optional properties for main touchpad device: ...@@ -15,6 +15,17 @@ Optional properties for main touchpad device:
keycode generated by each GPIO. Linux keycodes are defined in keycode generated by each GPIO. Linux keycodes are defined in
<dt-bindings/input/input.h>. <dt-bindings/input/input.h>.
- linux,gpio-keymap: When enabled, the SPT_GPIOPWN_T19 object sends messages
on GPIO bit changes. An array of up to 8 entries can be provided
indicating the Linux keycode mapped to each bit of the status byte,
starting at the LSB. Linux keycodes are defined in
<dt-bindings/input/input.h>.
Note: the numbering of the GPIOs and the bit they start at varies between
maXTouch devices. You must either refer to the documentation, or
experiment to determine which bit corresponds to which input. Use
KEY_RESERVED for unused padding values.
Example: Example:
touch@4b { touch@4b {
......
...@@ -236,28 +236,32 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count) ...@@ -236,28 +236,32 @@ void input_mt_report_pointer_emulation(struct input_dev *dev, bool use_count)
} }
EXPORT_SYMBOL(input_mt_report_pointer_emulation); EXPORT_SYMBOL(input_mt_report_pointer_emulation);
/** static void __input_mt_drop_unused(struct input_dev *dev, struct input_mt *mt)
* input_mt_drop_unused() - Inactivate slots not seen in this frame
* @dev: input device with allocated MT slots
*
* Lift all slots not seen since the last call to this function.
*/
void input_mt_drop_unused(struct input_dev *dev)
{ {
struct input_mt *mt = dev->mt;
int i; int i;
if (!mt)
return;
for (i = 0; i < mt->num_slots; i++) { for (i = 0; i < mt->num_slots; i++) {
if (!input_mt_is_used(mt, &mt->slots[i])) { if (!input_mt_is_used(mt, &mt->slots[i])) {
input_mt_slot(dev, i); input_mt_slot(dev, i);
input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1); input_event(dev, EV_ABS, ABS_MT_TRACKING_ID, -1);
} }
} }
}
/**
* input_mt_drop_unused() - Inactivate slots not seen in this frame
* @dev: input device with allocated MT slots
*
* Lift all slots not seen since the last call to this function.
*/
void input_mt_drop_unused(struct input_dev *dev)
{
struct input_mt *mt = dev->mt;
if (mt) {
__input_mt_drop_unused(dev, mt);
mt->frame++; mt->frame++;
}
} }
EXPORT_SYMBOL(input_mt_drop_unused); EXPORT_SYMBOL(input_mt_drop_unused);
...@@ -278,12 +282,14 @@ void input_mt_sync_frame(struct input_dev *dev) ...@@ -278,12 +282,14 @@ void input_mt_sync_frame(struct input_dev *dev)
return; return;
if (mt->flags & INPUT_MT_DROP_UNUSED) if (mt->flags & INPUT_MT_DROP_UNUSED)
input_mt_drop_unused(dev); __input_mt_drop_unused(dev, mt);
if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT)) if ((mt->flags & INPUT_MT_POINTER) && !(mt->flags & INPUT_MT_SEMI_MT))
use_count = true; use_count = true;
input_mt_report_pointer_emulation(dev, use_count); input_mt_report_pointer_emulation(dev, use_count);
mt->frame++;
} }
EXPORT_SYMBOL(input_mt_sync_frame); EXPORT_SYMBOL(input_mt_sync_frame);
......
...@@ -2234,8 +2234,8 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv) ...@@ -2234,8 +2234,8 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
return 0; return 0;
} }
psmouse_info(psmouse, psmouse_dbg(psmouse,
"Unknown ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec); "Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
return -EINVAL; return -EINVAL;
} }
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <linux/input/mt.h> #include <linux/input/mt.h>
#include <linux/serio.h> #include <linux/serio.h>
#include <linux/libps2.h> #include <linux/libps2.h>
#include <asm/unaligned.h>
#include "psmouse.h" #include "psmouse.h"
#include "elantech.h" #include "elantech.h"
...@@ -403,6 +404,68 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse) ...@@ -403,6 +404,68 @@ static void elantech_report_absolute_v2(struct psmouse *psmouse)
input_sync(dev); input_sync(dev);
} }
static void elantech_report_trackpoint(struct psmouse *psmouse,
int packet_type)
{
/*
* byte 0: 0 0 sx sy 0 M R L
* byte 1:~sx 0 0 0 0 0 0 0
* byte 2:~sy 0 0 0 0 0 0 0
* byte 3: 0 0 ~sy ~sx 0 1 1 0
* byte 4: x7 x6 x5 x4 x3 x2 x1 x0
* byte 5: y7 y6 y5 y4 y3 y2 y1 y0
*
* x and y are written in two's complement spread
* over 9 bits with sx/sy the relative top bit and
* x7..x0 and y7..y0 the lower bits.
* The sign of y is opposite to what the input driver
* expects for a relative movement
*/
struct elantech_data *etd = psmouse->private;
struct input_dev *tp_dev = etd->tp_dev;
unsigned char *packet = psmouse->packet;
int x, y;
u32 t;
if (dev_WARN_ONCE(&psmouse->ps2dev.serio->dev,
!tp_dev,
psmouse_fmt("Unexpected trackpoint message\n"))) {
if (etd->debug == 1)
elantech_packet_dump(psmouse);
return;
}
t = get_unaligned_le32(&packet[0]);
switch (t & ~7U) {
case 0x06000030U:
case 0x16008020U:
case 0x26800010U:
case 0x36808000U:
x = packet[4] - (int)((packet[1]^0x80) << 1);
y = (int)((packet[2]^0x80) << 1) - packet[5];
input_report_key(tp_dev, BTN_LEFT, packet[0] & 0x01);
input_report_key(tp_dev, BTN_RIGHT, packet[0] & 0x02);
input_report_key(tp_dev, BTN_MIDDLE, packet[0] & 0x04);
input_report_rel(tp_dev, REL_X, x);
input_report_rel(tp_dev, REL_Y, y);
input_sync(tp_dev);
break;
default:
/* Dump unexpected packet sequences if debug=1 (default) */
if (etd->debug == 1)
elantech_packet_dump(psmouse);
break;
}
}
/* /*
* Interpret complete data packets and report absolute mode input events for * Interpret complete data packets and report absolute mode input events for
* hardware version 3. (12 byte packets for two fingers) * hardware version 3. (12 byte packets for two fingers)
...@@ -715,6 +778,8 @@ static int elantech_packet_check_v3(struct psmouse *psmouse) ...@@ -715,6 +778,8 @@ static int elantech_packet_check_v3(struct psmouse *psmouse)
if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c) if ((packet[0] & 0x0c) == 0x0c && (packet[3] & 0xce) == 0x0c)
return PACKET_V3_TAIL; return PACKET_V3_TAIL;
if ((packet[3] & 0x0f) == 0x06)
return PACKET_TRACKPOINT;
} }
return PACKET_UNKNOWN; return PACKET_UNKNOWN;
...@@ -791,15 +856,24 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse) ...@@ -791,15 +856,24 @@ static psmouse_ret_t elantech_process_byte(struct psmouse *psmouse)
case 3: case 3:
packet_type = elantech_packet_check_v3(psmouse); packet_type = elantech_packet_check_v3(psmouse);
switch (packet_type) {
case PACKET_UNKNOWN:
return PSMOUSE_BAD_DATA;
case PACKET_DEBOUNCE:
/* ignore debounce */ /* ignore debounce */
if (packet_type == PACKET_DEBOUNCE) break;
return PSMOUSE_FULL_PACKET;
if (packet_type == PACKET_UNKNOWN) case PACKET_TRACKPOINT:
return PSMOUSE_BAD_DATA; elantech_report_trackpoint(psmouse, packet_type);
break;
default:
elantech_report_absolute_v3(psmouse, packet_type); elantech_report_absolute_v3(psmouse, packet_type);
break; break;
}
break;
case 4: case 4:
packet_type = elantech_packet_check_v4(psmouse); packet_type = elantech_packet_check_v4(psmouse);
...@@ -1018,8 +1092,10 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, ...@@ -1018,8 +1092,10 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
* Asus UX31 0x361f00 20, 15, 0e clickpad * Asus UX31 0x361f00 20, 15, 0e clickpad
* Asus UX32VD 0x361f02 00, 15, 0e clickpad * Asus UX32VD 0x361f02 00, 15, 0e clickpad
* Avatar AVIU-145A2 0x361f00 ? clickpad * Avatar AVIU-145A2 0x361f00 ? clickpad
* Fujitsu H730 0x570f00 c0, 14, 0c 3 hw buttons (**)
* Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons * Gigabyte U2442 0x450f01 58, 17, 0c 2 hw buttons
* Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*) * Lenovo L430 0x350f02 b9, 15, 0c 2 hw buttons (*)
* Lenovo L530 0x350f02 b9, 15, 0c 2 hw buttons (*)
* Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons * Samsung NF210 0x150b00 78, 14, 0a 2 hw buttons
* Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad * Samsung NP770Z5E 0x575f01 10, 15, 0f clickpad
* Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad * Samsung NP700Z5B 0x361f06 21, 15, 0f clickpad
...@@ -1029,6 +1105,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse, ...@@ -1029,6 +1105,8 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
* Samsung RF710 0x450f00 ? 2 hw buttons * Samsung RF710 0x450f00 ? 2 hw buttons
* System76 Pangolin 0x250f01 ? 2 hw buttons * System76 Pangolin 0x250f01 ? 2 hw buttons
* (*) + 3 trackpoint buttons * (*) + 3 trackpoint buttons
* (**) + 0 trackpoint buttons
* Note: Lenovo L430 and Lenovo L430 have the same fw_version/caps
*/ */
static void elantech_set_buttonpad_prop(struct psmouse *psmouse) static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
{ {
...@@ -1324,6 +1402,10 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties) ...@@ -1324,6 +1402,10 @@ int elantech_detect(struct psmouse *psmouse, bool set_properties)
*/ */
static void elantech_disconnect(struct psmouse *psmouse) static void elantech_disconnect(struct psmouse *psmouse)
{ {
struct elantech_data *etd = psmouse->private;
if (etd->tp_dev)
input_unregister_device(etd->tp_dev);
sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj, sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
&elantech_attr_group); &elantech_attr_group);
kfree(psmouse->private); kfree(psmouse->private);
...@@ -1438,8 +1520,10 @@ static int elantech_set_properties(struct elantech_data *etd) ...@@ -1438,8 +1520,10 @@ static int elantech_set_properties(struct elantech_data *etd)
int elantech_init(struct psmouse *psmouse) int elantech_init(struct psmouse *psmouse)
{ {
struct elantech_data *etd; struct elantech_data *etd;
int i, error; int i;
int error = -EINVAL;
unsigned char param[3]; unsigned char param[3];
struct input_dev *tp_dev;
psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL); psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
if (!etd) if (!etd)
...@@ -1498,14 +1582,49 @@ int elantech_init(struct psmouse *psmouse) ...@@ -1498,14 +1582,49 @@ int elantech_init(struct psmouse *psmouse)
goto init_fail; goto init_fail;
} }
/* The MSB indicates the presence of the trackpoint */
if ((etd->capabilities[0] & 0x80) == 0x80) {
tp_dev = input_allocate_device();
if (!tp_dev) {
error = -ENOMEM;
goto init_fail_tp_alloc;
}
etd->tp_dev = tp_dev;
snprintf(etd->tp_phys, sizeof(etd->tp_phys), "%s/input1",
psmouse->ps2dev.serio->phys);
tp_dev->phys = etd->tp_phys;
tp_dev->name = "Elantech PS/2 TrackPoint";
tp_dev->id.bustype = BUS_I8042;
tp_dev->id.vendor = 0x0002;
tp_dev->id.product = PSMOUSE_ELANTECH;
tp_dev->id.version = 0x0000;
tp_dev->dev.parent = &psmouse->ps2dev.serio->dev;
tp_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REL);
tp_dev->relbit[BIT_WORD(REL_X)] =
BIT_MASK(REL_X) | BIT_MASK(REL_Y);
tp_dev->keybit[BIT_WORD(BTN_LEFT)] =
BIT_MASK(BTN_LEFT) | BIT_MASK(BTN_MIDDLE) |
BIT_MASK(BTN_RIGHT);
error = input_register_device(etd->tp_dev);
if (error < 0)
goto init_fail_tp_reg;
}
psmouse->protocol_handler = elantech_process_byte; psmouse->protocol_handler = elantech_process_byte;
psmouse->disconnect = elantech_disconnect; psmouse->disconnect = elantech_disconnect;
psmouse->reconnect = elantech_reconnect; psmouse->reconnect = elantech_reconnect;
psmouse->pktsize = etd->hw_version > 1 ? 6 : 4; psmouse->pktsize = etd->hw_version > 1 ? 6 : 4;
return 0; return 0;
init_fail_tp_reg:
input_free_device(tp_dev);
init_fail_tp_alloc:
sysfs_remove_group(&psmouse->ps2dev.serio->dev.kobj,
&elantech_attr_group);
init_fail: init_fail:
psmouse_reset(psmouse);
kfree(etd); kfree(etd);
return -1; return error;
} }
...@@ -94,6 +94,7 @@ ...@@ -94,6 +94,7 @@
#define PACKET_V4_HEAD 0x05 #define PACKET_V4_HEAD 0x05
#define PACKET_V4_MOTION 0x06 #define PACKET_V4_MOTION 0x06
#define PACKET_V4_STATUS 0x07 #define PACKET_V4_STATUS 0x07
#define PACKET_TRACKPOINT 0x08
/* /*
* track up to 5 fingers for v4 hardware * track up to 5 fingers for v4 hardware
...@@ -114,6 +115,8 @@ struct finger_pos { ...@@ -114,6 +115,8 @@ struct finger_pos {
}; };
struct elantech_data { struct elantech_data {
struct input_dev *tp_dev; /* Relative device for trackpoint */
char tp_phys[32];
unsigned char reg_07; unsigned char reg_07;
unsigned char reg_10; unsigned char reg_10;
unsigned char reg_11; unsigned char reg_11;
......
...@@ -17,7 +17,6 @@ static int i8042_aux_irq = -1; ...@@ -17,7 +17,6 @@ static int i8042_aux_irq = -1;
#define I8042_MUX_PHYS_DESC "sparcps2/serio%d" #define I8042_MUX_PHYS_DESC "sparcps2/serio%d"
static void __iomem *kbd_iobase; static void __iomem *kbd_iobase;
static struct resource *kbd_res;
#define I8042_COMMAND_REG (kbd_iobase + 0x64UL) #define I8042_COMMAND_REG (kbd_iobase + 0x64UL)
#define I8042_DATA_REG (kbd_iobase + 0x60UL) #define I8042_DATA_REG (kbd_iobase + 0x60UL)
...@@ -44,6 +43,8 @@ static inline void i8042_write_command(int val) ...@@ -44,6 +43,8 @@ static inline void i8042_write_command(int val)
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
static struct resource *kbd_res;
#define OBP_PS2KBD_NAME1 "kb_ps2" #define OBP_PS2KBD_NAME1 "kb_ps2"
#define OBP_PS2KBD_NAME2 "keyboard" #define OBP_PS2KBD_NAME2 "keyboard"
#define OBP_PS2MS_NAME1 "kdmouse" #define OBP_PS2MS_NAME1 "kdmouse"
......
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