if (buf[0] > SILEAD_MAX_FINGERS) {
dev_warn(dev, "More touches reported then supported %d > %d\n",
buf[0], SILEAD_MAX_FINGERS);
buf[0] = SILEAD_MAX_FINGERS;
}
if (silead_ts_handle_pen_data(data, buf)) goto sync; /* Pen is down, release all previous touches */
touch_nr = 0;
bufp = buf + SILEAD_POINT_DATA_LEN; for (i = 0; i < buf[0]; i++, bufp += SILEAD_POINT_DATA_LEN) {
softbutton = (bufp[SILEAD_POINT_Y_MSB_OFF] &
SILEAD_EXTRA_DATA_MASK) >> 4;
if (softbutton) { /* * For now only respond to softbutton == 0x01, some * tablets *without* a capacative button send 0x04 * when crossing the edges of the screen.
*/ if (softbutton == 0x01)
softbutton_pressed = true;
continue;
}
/* * Bits 4-7 are the touch id, note not all models have * hardware touch ids so atm we don't use these.
*/
data->id[touch_nr] = (bufp[SILEAD_POINT_X_MSB_OFF] &
SILEAD_EXTRA_DATA_MASK) >> 4;
touchscreen_set_mt_pos(&data->pos[touch_nr], &data->prop,
get_unaligned_le16(&bufp[SILEAD_POINT_X_OFF]) & 0xfff,
get_unaligned_le16(&bufp[SILEAD_POINT_Y_OFF]) & 0xfff);
touch_nr++;
}
/* * Unfortunately, at the time of writing this comment, we have been unable to * get permission from Silead, or from device OEMs, to distribute the necessary * Silead firmware files in linux-firmware. * * On a whole bunch of devices the UEFI BIOS code contains a touchscreen driver, * which contains an embedded copy of the firmware. The fw-loader code has a * "platform" fallback mechanism, which together with info on the firmware * from drivers/platform/x86/touchscreen_dmi.c will use the firmware from the * UEFI driver when the firmware is missing from /lib/firmware. This makes the * touchscreen work OOTB without users needing to manually download the firmware. * * The firmware bundled with the original Windows/Android is usually newer then * the firmware in the UEFI driver and it is better calibrated. This better * calibration can lead to significant differences in the reported min/max * coordinates. * * To deal with this we first try to load the firmware without "platform" * fallback. If that fails we retry with "platform" fallback and if that * succeeds we apply an (optional) set of alternative min/max values from the * "silead,efi-fw-min-max" property.
*/
error = firmware_request_nowarn(&fw, data->fw_name, dev); if (error) {
error = firmware_request_platform(&fw, data->fw_name, dev); if (error) {
dev_err(dev, "Firmware request error %d\n", error); return error;
}
/* The EFI (platform) embedded fw does not have pen support */ if (data->pen_supported) {
dev_warn(dev, "Warning loading '%s' from filesystem failed, using EFI embedded copy.\n",
data->fw_name);
dev_warn(dev, "Warning pen support is known to be broken in the EFI embedded fw version\n");
data->pen_supported = false;
}
}
staticint silead_ts_setup(struct i2c_client *client)
{ int error;
u32 status;
/* * Some buggy BIOS-es bring up the chip in a stuck state where it * blocks the I2C bus. The following steps are necessary to * unstuck the chip / bus: * 1. Turn off the Silead chip. * 2. Try to do an I2C transfer with the chip, this will fail in * response to which the I2C-bus-driver will call: * i2c_recover_bus() which will unstuck the I2C-bus. Note the * unstuck-ing of the I2C bus only works if we first drop the * chip off the bus by turning it off. * 3. Turn the chip back on. * * On the x86/ACPI systems were this problem is seen, step 1. and * 3. require making ACPI calls and dealing with ACPI Power * Resources. The workaround below runtime-suspends the chip to * turn it off, leaving it up to the ACPI subsystem to deal with * this.
*/
if (device_property_read_bool(&client->dev, "silead,stuck-controller-bug")) {
pm_runtime_set_active(&client->dev);
pm_runtime_enable(&client->dev);
pm_runtime_allow(&client->dev);
pm_runtime_suspend(&client->dev);
dev_warn(&client->dev, FW_BUG "Stuck I2C bus: please ignore the next 'controller timed out' error\n");
silead_ts_get_id(client);
/* The forbid will also resume the device */
pm_runtime_forbid(&client->dev);
pm_runtime_disable(&client->dev);
}
/* * Enable regulators at probe and disable them at remove, we need * to keep the chip powered otherwise it forgets its firmware.
*/
error = regulator_bulk_enable(ARRAY_SIZE(data->regulators),
data->regulators); if (error) return error;
error = devm_add_action_or_reset(dev, silead_disable_regulator, data); if (error) return error;
/* Power GPIO pin */
data->gpio_power = devm_gpiod_get_optional(dev, "power", GPIOD_OUT_LOW); if (IS_ERR(data->gpio_power)) return dev_err_probe(dev, PTR_ERR(data->gpio_power), "Shutdown GPIO request failed\n");
error = silead_ts_setup(client); if (error) return error;
error = silead_ts_request_input_dev(data); if (error) return error;
error = silead_ts_request_pen_input_dev(data); if (error) return error;
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.14Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.