You've already forked linux-apfs
mirror of
https://github.com/linux-apfs/linux-apfs.git
synced 2026-05-01 15:00:59 -07:00
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
Pull some more input subsystem updates from Dmitry Torokhov: "An update to the ALPS driver to support the V8 protocol with touchstick, a change for i8042 to skip selftest on many Asus laptops which helps to keep their touchpads working after resume, and a couple other driver fixes" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: Input: i8042 - skip selftest on ASUS laptops Input: melfas_mip4 - add ic_name sysfs attribute Input: melfas_mip4 - add maintainer information Input: melfas_mip4 - add devicetree binding documentations Input: elantech - add Fujitsu Lifebook E556 to force crc_enabled Input: synaptics-rmi4 - fix error handling in I2C transport driver Input: synaptics-rmi4 - fix error handling in SPI transport driver Input: ALPS - add V8 protocol documentation Input: ALPS - set DualPoint flag for 74 03 28 devices Input: ALPS - allow touchsticks to report pressure Input: ALPS - handle 0-pressure 1F events Input: ALPS - add touchstick support for SS5 hardware Input: elantech - force needed quirks on Fujitsu H760 Input: elantech - fix Lenovo version typo
This commit is contained in:
+75
-12
@@ -103,6 +103,7 @@ static const struct alps_nibble_commands alps_v6_nibble_commands[] = {
|
||||
6-byte ALPS packet */
|
||||
#define ALPS_STICK_BITS 0x100 /* separate stick button bits */
|
||||
#define ALPS_BUTTONPAD 0x200 /* device is a clickpad */
|
||||
#define ALPS_DUALPOINT_WITH_PRESSURE 0x400 /* device can report trackpoint pressure */
|
||||
|
||||
static const struct alps_model_info alps_model_data[] = {
|
||||
{ { 0x32, 0x02, 0x14 }, 0x00, { ALPS_PROTO_V2, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT } }, /* Toshiba Salellite Pro M10 */
|
||||
@@ -1156,15 +1157,28 @@ static unsigned char alps_get_pkt_id_ss4_v2(unsigned char *byte)
|
||||
{
|
||||
unsigned char pkt_id = SS4_PACKET_ID_IDLE;
|
||||
|
||||
if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 &&
|
||||
(byte[3] & 0x88) == 0x08 && byte[4] == 0x10 && byte[5] == 0x00) {
|
||||
pkt_id = SS4_PACKET_ID_IDLE;
|
||||
} else if (!(byte[3] & 0x10)) {
|
||||
pkt_id = SS4_PACKET_ID_ONE;
|
||||
} else if (!(byte[3] & 0x20)) {
|
||||
switch (byte[3] & 0x30) {
|
||||
case 0x00:
|
||||
if (byte[0] == 0x18 && byte[1] == 0x10 && byte[2] == 0x00 &&
|
||||
(byte[3] & 0x88) == 0x08 && byte[4] == 0x10 &&
|
||||
byte[5] == 0x00) {
|
||||
pkt_id = SS4_PACKET_ID_IDLE;
|
||||
} else {
|
||||
pkt_id = SS4_PACKET_ID_ONE;
|
||||
}
|
||||
break;
|
||||
case 0x10:
|
||||
/* two-finger finger positions */
|
||||
pkt_id = SS4_PACKET_ID_TWO;
|
||||
} else {
|
||||
break;
|
||||
case 0x20:
|
||||
/* stick pointer */
|
||||
pkt_id = SS4_PACKET_ID_STICK;
|
||||
break;
|
||||
case 0x30:
|
||||
/* third and fourth finger positions */
|
||||
pkt_id = SS4_PACKET_ID_MULTI;
|
||||
break;
|
||||
}
|
||||
|
||||
return pkt_id;
|
||||
@@ -1185,7 +1199,13 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
|
||||
f->mt[0].x = SS4_1F_X_V2(p);
|
||||
f->mt[0].y = SS4_1F_Y_V2(p);
|
||||
f->pressure = ((SS4_1F_Z_V2(p)) * 2) & 0x7f;
|
||||
f->fingers = 1;
|
||||
/*
|
||||
* When a button is held the device will give us events
|
||||
* with x, y, and pressure of 0. This causes annoying jumps
|
||||
* if a touch is released while the button is held.
|
||||
* Handle this by claiming zero contacts.
|
||||
*/
|
||||
f->fingers = f->pressure > 0 ? 1 : 0;
|
||||
f->first_mp = 0;
|
||||
f->is_mp = 0;
|
||||
break;
|
||||
@@ -1246,16 +1266,40 @@ static int alps_decode_ss4_v2(struct alps_fields *f,
|
||||
}
|
||||
break;
|
||||
|
||||
case SS4_PACKET_ID_STICK:
|
||||
if (!(priv->flags & ALPS_DUALPOINT)) {
|
||||
psmouse_warn(psmouse,
|
||||
"Rejected trackstick packet from non DualPoint device");
|
||||
} else {
|
||||
int x = (s8)(((p[0] & 1) << 7) | (p[1] & 0x7f));
|
||||
int y = (s8)(((p[3] & 1) << 7) | (p[2] & 0x7f));
|
||||
int pressure = (s8)(p[4] & 0x7f);
|
||||
|
||||
input_report_rel(priv->dev2, REL_X, x);
|
||||
input_report_rel(priv->dev2, REL_Y, -y);
|
||||
input_report_abs(priv->dev2, ABS_PRESSURE, pressure);
|
||||
}
|
||||
break;
|
||||
|
||||
case SS4_PACKET_ID_IDLE:
|
||||
default:
|
||||
memset(f, 0, sizeof(struct alps_fields));
|
||||
break;
|
||||
}
|
||||
|
||||
f->left = !!(SS4_BTN_V2(p) & 0x01);
|
||||
if (!(priv->flags & ALPS_BUTTONPAD)) {
|
||||
f->right = !!(SS4_BTN_V2(p) & 0x02);
|
||||
f->middle = !!(SS4_BTN_V2(p) & 0x04);
|
||||
/* handle buttons */
|
||||
if (pkt_id == SS4_PACKET_ID_STICK) {
|
||||
f->ts_left = !!(SS4_BTN_V2(p) & 0x01);
|
||||
if (!(priv->flags & ALPS_BUTTONPAD)) {
|
||||
f->ts_right = !!(SS4_BTN_V2(p) & 0x02);
|
||||
f->ts_middle = !!(SS4_BTN_V2(p) & 0x04);
|
||||
}
|
||||
} else {
|
||||
f->left = !!(SS4_BTN_V2(p) & 0x01);
|
||||
if (!(priv->flags & ALPS_BUTTONPAD)) {
|
||||
f->right = !!(SS4_BTN_V2(p) & 0x02);
|
||||
f->middle = !!(SS4_BTN_V2(p) & 0x04);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -1266,6 +1310,7 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
|
||||
struct alps_data *priv = psmouse->private;
|
||||
unsigned char *packet = psmouse->packet;
|
||||
struct input_dev *dev = psmouse->dev;
|
||||
struct input_dev *dev2 = priv->dev2;
|
||||
struct alps_fields *f = &priv->f;
|
||||
|
||||
memset(f, 0, sizeof(struct alps_fields));
|
||||
@@ -1311,6 +1356,13 @@ static void alps_process_packet_ss4_v2(struct psmouse *psmouse)
|
||||
|
||||
input_report_abs(dev, ABS_PRESSURE, f->pressure);
|
||||
input_sync(dev);
|
||||
|
||||
if (priv->flags & ALPS_DUALPOINT) {
|
||||
input_report_key(dev2, BTN_LEFT, f->ts_left);
|
||||
input_report_key(dev2, BTN_RIGHT, f->ts_right);
|
||||
input_report_key(dev2, BTN_MIDDLE, f->ts_middle);
|
||||
input_sync(dev2);
|
||||
}
|
||||
}
|
||||
|
||||
static bool alps_is_valid_package_ss4_v2(struct psmouse *psmouse)
|
||||
@@ -2695,6 +2747,10 @@ static int alps_set_protocol(struct psmouse *psmouse,
|
||||
if (alps_set_defaults_ss4_v2(psmouse, priv))
|
||||
return -EIO;
|
||||
|
||||
if (priv->fw_ver[1] == 0x1)
|
||||
priv->flags |= ALPS_DUALPOINT |
|
||||
ALPS_DUALPOINT_WITH_PRESSURE;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -2767,6 +2823,9 @@ static int alps_identify(struct psmouse *psmouse, struct alps_data *priv)
|
||||
} else if (e7[0] == 0x73 && e7[1] == 0x03 &&
|
||||
e7[2] == 0x14 && ec[1] == 0x02) {
|
||||
protocol = &alps_v8_protocol_data;
|
||||
} else if (e7[0] == 0x73 && e7[1] == 0x03 &&
|
||||
e7[2] == 0x28 && ec[1] == 0x01) {
|
||||
protocol = &alps_v8_protocol_data;
|
||||
} else {
|
||||
psmouse_dbg(psmouse,
|
||||
"Likely not an ALPS touchpad: E7=%3ph, EC=%3ph\n", e7, ec);
|
||||
@@ -2949,6 +3008,10 @@ int alps_init(struct psmouse *psmouse)
|
||||
|
||||
input_set_capability(dev2, EV_REL, REL_X);
|
||||
input_set_capability(dev2, EV_REL, REL_Y);
|
||||
if (priv->flags & ALPS_DUALPOINT_WITH_PRESSURE) {
|
||||
input_set_capability(dev2, EV_ABS, ABS_PRESSURE);
|
||||
input_set_abs_params(dev2, ABS_PRESSURE, 0, 127, 0, 0);
|
||||
}
|
||||
input_set_capability(dev2, EV_KEY, BTN_LEFT);
|
||||
input_set_capability(dev2, EV_KEY, BTN_RIGHT);
|
||||
input_set_capability(dev2, EV_KEY, BTN_MIDDLE);
|
||||
|
||||
@@ -37,12 +37,14 @@
|
||||
* or there's button activities.
|
||||
* SS4_PACKET_ID_TWO: There's two or more fingers on touchpad
|
||||
* SS4_PACKET_ID_MULTI: There's three or more fingers on touchpad
|
||||
* SS4_PACKET_ID_STICK: A stick pointer packet
|
||||
*/
|
||||
enum SS4_PACKET_ID {
|
||||
SS4_PACKET_ID_IDLE = 0,
|
||||
SS4_PACKET_ID_ONE,
|
||||
SS4_PACKET_ID_TWO,
|
||||
SS4_PACKET_ID_MULTI,
|
||||
SS4_PACKET_ID_STICK,
|
||||
};
|
||||
|
||||
#define SS4_COUNT_PER_ELECTRODE 256
|
||||
|
||||
@@ -1134,7 +1134,7 @@ static int elantech_get_resolution_v4(struct psmouse *psmouse,
|
||||
* System76 Pangolin 0x250f01 ? 2 hw buttons
|
||||
* (*) + 3 trackpoint buttons
|
||||
* (**) + 0 trackpoint buttons
|
||||
* Note: Lenovo L430 and Lenovo L430 have the same fw_version/caps
|
||||
* Note: Lenovo L430 and Lenovo L530 have the same fw_version/caps
|
||||
*/
|
||||
static void elantech_set_buttonpad_prop(struct psmouse *psmouse)
|
||||
{
|
||||
@@ -1159,6 +1159,13 @@ static const struct dmi_system_id elantech_dmi_has_middle_button[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H730"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Fujitsu H760 also has a middle button */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"),
|
||||
},
|
||||
},
|
||||
#endif
|
||||
{ }
|
||||
};
|
||||
@@ -1503,10 +1510,10 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */
|
||||
/* Fujitsu H760 does not work with crc_enabled == 0 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "CELSIUS H760"),
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -1516,6 +1523,20 @@ static const struct dmi_system_id elantech_dmi_force_crc_enabled[] = {
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E544"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Fujitsu LIFEBOOK E554 does not work with crc_enabled == 0 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E554"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Fujitsu LIFEBOOK E556 does not work with crc_enabled == 0 */
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E556"),
|
||||
},
|
||||
},
|
||||
{
|
||||
/* Fujitsu LIFEBOOK U745 does not work with crc_enabled == 0 */
|
||||
.matches = {
|
||||
|
||||
@@ -221,6 +221,21 @@ static const struct of_device_id rmi_i2c_of_match[] = {
|
||||
MODULE_DEVICE_TABLE(of, rmi_i2c_of_match);
|
||||
#endif
|
||||
|
||||
static void rmi_i2c_regulator_bulk_disable(void *data)
|
||||
{
|
||||
struct rmi_i2c_xport *rmi_i2c = data;
|
||||
|
||||
regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
|
||||
rmi_i2c->supplies);
|
||||
}
|
||||
|
||||
static void rmi_i2c_unregister_transport(void *data)
|
||||
{
|
||||
struct rmi_i2c_xport *rmi_i2c = data;
|
||||
|
||||
rmi_unregister_transport_device(&rmi_i2c->xport);
|
||||
}
|
||||
|
||||
static int rmi_i2c_probe(struct i2c_client *client,
|
||||
const struct i2c_device_id *id)
|
||||
{
|
||||
@@ -264,6 +279,12 @@ static int rmi_i2c_probe(struct i2c_client *client,
|
||||
if (retval < 0)
|
||||
return retval;
|
||||
|
||||
retval = devm_add_action_or_reset(&client->dev,
|
||||
rmi_i2c_regulator_bulk_disable,
|
||||
rmi_i2c);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
of_property_read_u32(client->dev.of_node, "syna,startup-delay-ms",
|
||||
&rmi_i2c->startup_delay);
|
||||
|
||||
@@ -294,6 +315,11 @@ static int rmi_i2c_probe(struct i2c_client *client,
|
||||
client->addr);
|
||||
return retval;
|
||||
}
|
||||
retval = devm_add_action_or_reset(&client->dev,
|
||||
rmi_i2c_unregister_transport,
|
||||
rmi_i2c);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = rmi_i2c_init_irq(client);
|
||||
if (retval < 0)
|
||||
@@ -304,17 +330,6 @@ static int rmi_i2c_probe(struct i2c_client *client,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_i2c_remove(struct i2c_client *client)
|
||||
{
|
||||
struct rmi_i2c_xport *rmi_i2c = i2c_get_clientdata(client);
|
||||
|
||||
rmi_unregister_transport_device(&rmi_i2c->xport);
|
||||
regulator_bulk_disable(ARRAY_SIZE(rmi_i2c->supplies),
|
||||
rmi_i2c->supplies);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int rmi_i2c_suspend(struct device *dev)
|
||||
{
|
||||
@@ -431,7 +446,6 @@ static struct i2c_driver rmi_i2c_driver = {
|
||||
},
|
||||
.id_table = rmi_id,
|
||||
.probe = rmi_i2c_probe,
|
||||
.remove = rmi_i2c_remove,
|
||||
};
|
||||
|
||||
module_i2c_driver(rmi_i2c_driver);
|
||||
|
||||
@@ -396,6 +396,13 @@ static inline int rmi_spi_of_probe(struct spi_device *spi,
|
||||
}
|
||||
#endif
|
||||
|
||||
static void rmi_spi_unregister_transport(void *data)
|
||||
{
|
||||
struct rmi_spi_xport *rmi_spi = data;
|
||||
|
||||
rmi_unregister_transport_device(&rmi_spi->xport);
|
||||
}
|
||||
|
||||
static int rmi_spi_probe(struct spi_device *spi)
|
||||
{
|
||||
struct rmi_spi_xport *rmi_spi;
|
||||
@@ -464,6 +471,11 @@ static int rmi_spi_probe(struct spi_device *spi)
|
||||
dev_err(&spi->dev, "failed to register transport.\n");
|
||||
return retval;
|
||||
}
|
||||
retval = devm_add_action_or_reset(&spi->dev,
|
||||
rmi_spi_unregister_transport,
|
||||
rmi_spi);
|
||||
if (retval)
|
||||
return retval;
|
||||
|
||||
retval = rmi_spi_init_irq(spi);
|
||||
if (retval < 0)
|
||||
@@ -473,15 +485,6 @@ static int rmi_spi_probe(struct spi_device *spi)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rmi_spi_remove(struct spi_device *spi)
|
||||
{
|
||||
struct rmi_spi_xport *rmi_spi = spi_get_drvdata(spi);
|
||||
|
||||
rmi_unregister_transport_device(&rmi_spi->xport);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
static int rmi_spi_suspend(struct device *dev)
|
||||
{
|
||||
@@ -577,7 +580,6 @@ static struct spi_driver rmi_spi_driver = {
|
||||
},
|
||||
.id_table = rmi_id,
|
||||
.probe = rmi_spi_probe,
|
||||
.remove = rmi_spi_remove,
|
||||
};
|
||||
|
||||
module_spi_driver(rmi_spi_driver);
|
||||
|
||||
@@ -81,7 +81,7 @@ static inline int i8042_platform_init(void)
|
||||
return -EBUSY;
|
||||
#endif
|
||||
|
||||
i8042_reset = 1;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
|
||||
return -EBUSY;
|
||||
#endif
|
||||
|
||||
i8042_reset = 1;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -44,7 +44,7 @@ static inline void i8042_write_command(int val)
|
||||
|
||||
static inline int i8042_platform_init(void)
|
||||
{
|
||||
i8042_reset = 1;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,7 @@ static int __init i8042_platform_init(void)
|
||||
}
|
||||
}
|
||||
|
||||
i8042_reset = 1;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -61,7 +61,7 @@ static inline int i8042_platform_init(void)
|
||||
if (!request_mem_region(I8042_REGION_START, I8042_REGION_SIZE, "i8042"))
|
||||
return -EBUSY;
|
||||
|
||||
i8042_reset = 1;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -510,6 +510,90 @@ static const struct dmi_system_id __initconst i8042_dmi_nomux_table[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
/*
|
||||
* On some Asus laptops, just running self tests cause problems.
|
||||
*/
|
||||
static const struct dmi_system_id i8042_dmi_noselftest_table[] = {
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "A455LD"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "K401LB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "K501LB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "K501LX"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "R409L"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "V502LX"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X302LA"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X450LCP"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X450LD"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X455LAB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X455LDB"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "X455LF"),
|
||||
},
|
||||
},
|
||||
{
|
||||
.matches = {
|
||||
DMI_MATCH(DMI_SYS_VENDOR, "ASUSTeK COMPUTER INC."),
|
||||
DMI_MATCH(DMI_PRODUCT_NAME, "Z450LA"),
|
||||
},
|
||||
},
|
||||
{ }
|
||||
};
|
||||
static const struct dmi_system_id __initconst i8042_dmi_reset_table[] = {
|
||||
{
|
||||
/* MSI Wind U-100 */
|
||||
@@ -1072,12 +1156,18 @@ static int __init i8042_platform_init(void)
|
||||
return retval;
|
||||
|
||||
#if defined(__ia64__)
|
||||
i8042_reset = true;
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
if (dmi_check_system(i8042_dmi_reset_table))
|
||||
i8042_reset = true;
|
||||
/* Honor module parameter when value is not default */
|
||||
if (i8042_reset == I8042_RESET_DEFAULT) {
|
||||
if (dmi_check_system(i8042_dmi_reset_table))
|
||||
i8042_reset = I8042_RESET_ALWAYS;
|
||||
|
||||
if (dmi_check_system(i8042_dmi_noselftest_table))
|
||||
i8042_reset = I8042_RESET_NEVER;
|
||||
}
|
||||
|
||||
if (dmi_check_system(i8042_dmi_noloop_table))
|
||||
i8042_noloop = true;
|
||||
|
||||
+44
-11
@@ -48,9 +48,39 @@ static bool i8042_unlock;
|
||||
module_param_named(unlock, i8042_unlock, bool, 0);
|
||||
MODULE_PARM_DESC(unlock, "Ignore keyboard lock.");
|
||||
|
||||
static bool i8042_reset;
|
||||
module_param_named(reset, i8042_reset, bool, 0);
|
||||
MODULE_PARM_DESC(reset, "Reset controller during init and cleanup.");
|
||||
enum i8042_controller_reset_mode {
|
||||
I8042_RESET_NEVER,
|
||||
I8042_RESET_ALWAYS,
|
||||
I8042_RESET_ON_S2RAM,
|
||||
#define I8042_RESET_DEFAULT I8042_RESET_ON_S2RAM
|
||||
};
|
||||
static enum i8042_controller_reset_mode i8042_reset = I8042_RESET_DEFAULT;
|
||||
static int i8042_set_reset(const char *val, const struct kernel_param *kp)
|
||||
{
|
||||
enum i8042_controller_reset_mode *arg = kp->arg;
|
||||
int error;
|
||||
bool reset;
|
||||
|
||||
if (val) {
|
||||
error = kstrtobool(val, &reset);
|
||||
if (error)
|
||||
return error;
|
||||
} else {
|
||||
reset = true;
|
||||
}
|
||||
|
||||
*arg = reset ? I8042_RESET_ALWAYS : I8042_RESET_NEVER;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct kernel_param_ops param_ops_reset_param = {
|
||||
.flags = KERNEL_PARAM_OPS_FL_NOARG,
|
||||
.set = i8042_set_reset,
|
||||
};
|
||||
#define param_check_reset_param(name, p) \
|
||||
__param_check(name, p, enum i8042_controller_reset_mode)
|
||||
module_param_named(reset, i8042_reset, reset_param, 0);
|
||||
MODULE_PARM_DESC(reset, "Reset controller on resume, cleanup or both");
|
||||
|
||||
static bool i8042_direct;
|
||||
module_param_named(direct, i8042_direct, bool, 0);
|
||||
@@ -1019,7 +1049,7 @@ static int i8042_controller_init(void)
|
||||
* Reset the controller and reset CRT to the original value set by BIOS.
|
||||
*/
|
||||
|
||||
static void i8042_controller_reset(bool force_reset)
|
||||
static void i8042_controller_reset(bool s2r_wants_reset)
|
||||
{
|
||||
i8042_flush();
|
||||
|
||||
@@ -1044,8 +1074,10 @@ static void i8042_controller_reset(bool force_reset)
|
||||
* Reset the controller if requested.
|
||||
*/
|
||||
|
||||
if (i8042_reset || force_reset)
|
||||
if (i8042_reset == I8042_RESET_ALWAYS ||
|
||||
(i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
|
||||
i8042_controller_selftest();
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore the original control register setting.
|
||||
@@ -1110,7 +1142,7 @@ static void i8042_dritek_enable(void)
|
||||
* before suspending.
|
||||
*/
|
||||
|
||||
static int i8042_controller_resume(bool force_reset)
|
||||
static int i8042_controller_resume(bool s2r_wants_reset)
|
||||
{
|
||||
int error;
|
||||
|
||||
@@ -1118,7 +1150,8 @@ static int i8042_controller_resume(bool force_reset)
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
if (i8042_reset || force_reset) {
|
||||
if (i8042_reset == I8042_RESET_ALWAYS ||
|
||||
(i8042_reset == I8042_RESET_ON_S2RAM && s2r_wants_reset)) {
|
||||
error = i8042_controller_selftest();
|
||||
if (error)
|
||||
return error;
|
||||
@@ -1195,7 +1228,7 @@ static int i8042_pm_resume_noirq(struct device *dev)
|
||||
|
||||
static int i8042_pm_resume(struct device *dev)
|
||||
{
|
||||
bool force_reset;
|
||||
bool want_reset;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < I8042_NUM_PORTS; i++) {
|
||||
@@ -1218,9 +1251,9 @@ static int i8042_pm_resume(struct device *dev)
|
||||
* off control to the platform firmware, otherwise we can simply restore
|
||||
* the mode.
|
||||
*/
|
||||
force_reset = pm_resume_via_firmware();
|
||||
want_reset = pm_resume_via_firmware();
|
||||
|
||||
return i8042_controller_resume(force_reset);
|
||||
return i8042_controller_resume(want_reset);
|
||||
}
|
||||
|
||||
static int i8042_pm_thaw(struct device *dev)
|
||||
@@ -1482,7 +1515,7 @@ static int __init i8042_probe(struct platform_device *dev)
|
||||
|
||||
i8042_platform_device = dev;
|
||||
|
||||
if (i8042_reset) {
|
||||
if (i8042_reset == I8042_RESET_ALWAYS) {
|
||||
error = i8042_controller_selftest();
|
||||
if (error)
|
||||
return error;
|
||||
|
||||
@@ -157,6 +157,7 @@ struct mip4_ts {
|
||||
|
||||
char phys[32];
|
||||
char product_name[16];
|
||||
char ic_name[4];
|
||||
|
||||
unsigned int max_x;
|
||||
unsigned int max_y;
|
||||
@@ -263,6 +264,18 @@ static int mip4_query_device(struct mip4_ts *ts)
|
||||
dev_dbg(&ts->client->dev, "product name: %.*s\n",
|
||||
(int)sizeof(ts->product_name), ts->product_name);
|
||||
|
||||
/* IC name */
|
||||
cmd[0] = MIP4_R0_INFO;
|
||||
cmd[1] = MIP4_R1_INFO_IC_NAME;
|
||||
error = mip4_i2c_xfer(ts, cmd, sizeof(cmd),
|
||||
ts->ic_name, sizeof(ts->ic_name));
|
||||
if (error)
|
||||
dev_warn(&ts->client->dev,
|
||||
"Failed to retrieve IC name: %d\n", error);
|
||||
else
|
||||
dev_dbg(&ts->client->dev, "IC name: %.*s\n",
|
||||
(int)sizeof(ts->ic_name), ts->ic_name);
|
||||
|
||||
/* Firmware version */
|
||||
error = mip4_get_fw_version(ts);
|
||||
if (error)
|
||||
@@ -1326,7 +1339,7 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
|
||||
* paired with current firmware in the chip.
|
||||
*/
|
||||
count = snprintf(buf, PAGE_SIZE, "%.*s\n",
|
||||
(int)sizeof(ts->product_name), ts->product_name);
|
||||
(int)sizeof(ts->product_name), ts->product_name);
|
||||
|
||||
mutex_unlock(&ts->input->mutex);
|
||||
|
||||
@@ -1335,9 +1348,30 @@ static ssize_t mip4_sysfs_read_hw_version(struct device *dev,
|
||||
|
||||
static DEVICE_ATTR(hw_version, S_IRUGO, mip4_sysfs_read_hw_version, NULL);
|
||||
|
||||
static ssize_t mip4_sysfs_read_ic_name(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct i2c_client *client = to_i2c_client(dev);
|
||||
struct mip4_ts *ts = i2c_get_clientdata(client);
|
||||
size_t count;
|
||||
|
||||
mutex_lock(&ts->input->mutex);
|
||||
|
||||
count = snprintf(buf, PAGE_SIZE, "%.*s\n",
|
||||
(int)sizeof(ts->ic_name), ts->ic_name);
|
||||
|
||||
mutex_unlock(&ts->input->mutex);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR(ic_name, S_IRUGO, mip4_sysfs_read_ic_name, NULL);
|
||||
|
||||
static struct attribute *mip4_attrs[] = {
|
||||
&dev_attr_fw_version.attr,
|
||||
&dev_attr_hw_version.attr,
|
||||
&dev_attr_ic_name.attr,
|
||||
&dev_attr_update_fw.attr,
|
||||
NULL,
|
||||
};
|
||||
@@ -1538,6 +1572,6 @@ static struct i2c_driver mip4_driver = {
|
||||
module_i2c_driver(mip4_driver);
|
||||
|
||||
MODULE_DESCRIPTION("MELFAS MIP4 Touchscreen");
|
||||
MODULE_VERSION("2016.03.12");
|
||||
MODULE_VERSION("2016.09.28");
|
||||
MODULE_AUTHOR("Sangwon Jee <jeesw@melfas.com>");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
Reference in New Issue
Block a user