Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8201568

zForce touchscreen input device fails when closed and immediately reopened

    Details

    • Subcomponent:
    • CPU:
      x86
    • OS:
      linux_ubuntu

      Description

      ADDITIONAL SYSTEM INFORMATION :
      The Java VM is Oracle JDK 8 Update 172 (an early-access build) with the OpenJFX 8 armv7hf overlay bundle built from sources on April 10, 2018. The test system is a Kobo Touch N905C e-reader with 256 MB of RAM and an 800 MHz Freescale i.MX507 Multimedia Application Processor Model MCIMX507CVM8B (ARMv7-A architecture, ARM Cortex-A8 core). This is a 32-bit ARM system running Ubuntu 14.04.5 LTS as follows:

      $ uname -a
      Linux koboa 2.6.35.3-850-gbc67621+ #619 PREEMPT Thu Dec 22 15:29:00 CST 2016 armv7l armv7l armv7l GNU/Linux

      $ ldd --version
      ldd (Ubuntu EGLIBC 2.19-0ubuntu6.14) 2.19

      $ getconf GNU_LIBPTHREAD_VERSION
      NPTL 2.19

      $ ~/opt/jdk1.8.0_172/bin/java -version
      java version "1.8.0_172-ea"
      Java(TM) SE Runtime Environment (build 1.8.0_172-ea-b03)
      Java HotSpot(TM) Client VM (build 25.172-b03, mixed mode)


      A DESCRIPTION OF THE PROBLEM :
      If the Neonode zForce touchscreen input device is quickly reopened with an "open, close, open" sequence, on rare occasions it works, but the great majority of times it fails. The driver receives the call to reopen the device before it finishes the previous call to close it, so the device remains deactivated.

      The input device is initialized in the constructor of com.sun.glass.ui.monocle.LinuxInputDevice, where the method LinuxAbsoluteInputCapabilities.getCapabilities(File, BitSet) opens and closes the device but is followed immediately by a call to open it again.

      ---------------------------------------------------------------------
      this.absCaps = LinuxAbsoluteInputCapabilities.getCapabilities(
              devNode, capabilities.get("abs"));
      fd = system.open(devNode.getPath(), LinuxSystem.O_RDONLY);
      if (fd == -1) {
          throw new IOException(system.getErrorMessage() + " on " + devNode);
      }
      ---------------------------------------------------------------------

      Note that all of the fields in LinuxInputDevice are private, so I have to maintain my own copy of the class in its entirety to work around the problem.


      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      I can reproduce the problem with a Kobo Touch N905C e-reader and my own Monocle EPD platform class library, a port of OpenJFX to an electronic paper display. I start a JavaFX application with a button and check whether it responds to touch events.


      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      The JavaFX application should receive the touch events.
      ACTUAL -
      The JavaFX application almost always fails to receive the touch events.

      Use the "dmesg" command to read messages from Linux kernel ring buffer. The following messages are logged to the kernel ring buffer when the touchscreen input device works:

      [drivers/input/touchscreen/zforce_i2c.c-425] zforce_i2c_open()
      [zForce_ir_touch_recv_data-145] command Activate (0) ...
      [zForce_ir_touch_recv_data-154] command Resolution (0) ...
      [zForce_ir_touch_recv_data-179] command Frequency (0) ...
      [drivers/input/touchscreen/zforce_i2c.c-440] zforce_i2c_close()
      [zForce_ir_touch_recv_data-142] command Deactivate ...
      [drivers/input/touchscreen/zforce_i2c.c-425] zforce_i2c_open()
      [zForce_ir_touch_recv_data-145] command Activate (0) ...
      [zForce_ir_touch_recv_data-154] command Resolution (0) ...
      [zForce_ir_touch_recv_data-179] command Frequency (0) ...
      TPS65185 temprature data = 0x1b,27

      The following messages are logged when the device fails:

      [drivers/input/touchscreen/zforce_i2c.c-425] zforce_i2c_open()
      [zForce_ir_touch_recv_data-145] command Activate (0) ...
      [zForce_ir_touch_recv_data-154] command Resolution (0) ...
      [zForce_ir_touch_recv_data-179] command Frequency (0) ...
      [drivers/input/touchscreen/zforce_i2c.c-440] zforce_i2c_close()
      [drivers/input/touchscreen/zforce_i2c.c-425] zforce_i2c_open()
      [zForce_ir_touch_recv_data-142] command Deactivate ...
      [zForce_ir_touch_recv_data-198] command overrun (8) ...
      TPS65185 temprature data = 0x1b,27


      ---------- BEGIN SOURCE ----------
      You can use the simple program below to reproduce the problem:

      ---------------------------------------------------------------------
      package org.status6.hello;

      import javafx.application.Application;
      import javafx.scene.Scene;
      import javafx.scene.control.Button;
      import javafx.scene.layout.StackPane;
      import javafx.stage.Stage;

      public class HelloApp extends Application {

          private static final String TITLE = "Hello App";
          private static final String LABEL = "Say Hello";
          private static final String MESSAGE = "Hello World!";
          private static final int WIDTH = 800;
          private static final int HEIGHT = 600;

          @Override
          public void start(Stage stage) {
              Button button = new Button();
              button.setText(LABEL);
              button.setOnAction(e -> System.out.println(MESSAGE));

              StackPane root = new StackPane();
              root.getChildren().add(button);
              Scene scene = new Scene(root, WIDTH, HEIGHT);

              stage.setTitle(TITLE);
              stage.setScene(scene);
              stage.show();
          }

          public static void main(String[] args) {
              launch(args);
          }
      }
      ---------------------------------------------------------------------

      Package the program in a JAR file called "hello.jar", place the file in "~/lib", and run it with the command:

      $ sudo ~/bin/hello.sh

      where "hello.sh" is the Bash script:

      ---------------------------------------------------------------------
      #!/bin/bash
      # Runs the JavaFX Hello Application
      export JDK_HOME=$HOME/opt/jdk1.8.0_172

      java_ext_dirs=$HOME/lib/ext:$JDK_HOME/jre/lib/ext
      java_library_path=$HOME/lib/arm:$JDK_HOME/jre/lib/arm:/lib:/usr/lib

      $JDK_HOME/bin/java \
          -Djava.ext.dirs=$java_ext_dirs \
          -Djava.library.path=$java_library_path \
          -Dglass.platform=Monocle -Dmonocle.platform=EPD -Dprism.order=sw \
          -Dmonocle.input.18/0/0/0.minX=0 -Dmonocle.input.18/0/0/0.maxX=800 \
          -Dmonocle.input.18/0/0/0.minY=0 -Dmonocle.input.18/0/0/0.maxY=600 \
          -Dmonocle.input.18/0/0/0.flipXY=false \
          -jar $HOME/lib/hello.jar
      ---------------------------------------------------------------------

      You must run the script as root so that the program has permission to access the Linux input and framebuffer devices.

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      I modified the constructor for LinuxInputDevice so that the sequence of the device initialization is "open, open, close" simply by moving the call to LinuxAbsoluteInputCapabilities.getCapabilities after the call to open the device:

      ---------------------------------------------------------------------
      fd = system.open(devNode.getPath(), LinuxSystem.O_RDONLY);
      if (fd == -1) {
          throw new IOException(system.getErrorMessage() + " on " + devNode);
      }
      this.absCaps = LinuxAbsoluteInputCapabilities.getCapabilities(
              devNode, capabilities.get("abs"));
      ---------------------------------------------------------------------

      With this change, the kernel does not close the input device on the call to close it because the reference count for the device remains above zero. The input device is not deactivated, and the driver logs the following messages to the kernel ring buffer:

      [drivers/input/touchscreen/zforce_i2c.c-425] zforce_i2c_open()
      [zForce_ir_touch_recv_data-145] command Activate (0) ...
      [zForce_ir_touch_recv_data-154] command Resolution (0) ...
      [zForce_ir_touch_recv_data-179] command Frequency (0) ...
      TPS65185 temprature data = 0x1b,27

      The device is still closed when the JavaFX application terminates:

      [drivers/input/touchscreen/zforce_i2c.c-440] zforce_i2c_close()
      [zForce_ir_touch_recv_data-142] command Deactivate ...

      My fix can be found here:

      Avoid closing the zForce input device on startup
      https://gitlab.com/openjfxepd/jfxpatch/commit/7619c21375d359f8948ade0e2535e1f261e5e59f

      For completeness, I have also included the full patch below:

      ---------------------------------------------------------------------
      From 7619c21375d359f8948ade0e2535e1f261e5e59f Mon Sep 17 00:00:00 2001
      From: John Neffenger <john@status6.com>
      Date: Thu, 3 Nov 2016 10:46:07 -0700
      Subject: [PATCH] Avoid closing the zForce input device on startup

      The Neonode zForce touchscreen input device often fails when it is
      opened immediately after being closed. The device driver logs the
      following messages to the kernel ring buffer:

        [drivers/input/touchscreen/zforce_i2c.c-422] zforce_i2c_open()
        [zForce_ir_touch_recv_data-145] command Activate (0) ...
        [zForce_ir_touch_recv_data-154] command Resolution (0) ...
        [zForce_ir_touch_recv_data-179] command Frequency (0) ...
        [drivers/input/touchscreen/zforce_i2c.c-437] zforce_i2c_close()
        [drivers/input/touchscreen/zforce_i2c.c-422] zforce_i2c_open()
        [zForce_ir_touch_recv_data-142] command Deactivate ...
        [zForce_ir_touch_recv_data-198] command overrun (8) ...

      Reorder the initialization sequence to be "open, open, close" instead of
      "open, close, open" so that the device is never actually closed. With
      this change, the device reference count remains above zero so the call
      to close it is ignored, and the device driver logs the following
      messages to the ring buffer:

        [drivers/input/touchscreen/zforce_i2c.c-422] zforce_i2c_open()
        [zForce_ir_touch_recv_data-145] command Activate (0) ...
        [zForce_ir_touch_recv_data-154] command Resolution (0) ...
        [zForce_ir_touch_recv_data-179] command Frequency (0) ...

      Fixes #2
      ---
       src/com/sun/glass/ui/monocle/LinuxInputDevice.java | 4 ++--
       1 file changed, 2 insertions(+), 2 deletions(-)

      diff --git a/src/com/sun/glass/ui/monocle/LinuxInputDevice.java b/src/com/sun/glass/ui/monocle/LinuxInputDevice.java
      index ce89628..5fbd511 100644
      --- a/src/com/sun/glass/ui/monocle/LinuxInputDevice.java
      +++ b/src/com/sun/glass/ui/monocle/LinuxInputDevice.java
      @@ -83,12 +83,12 @@ class LinuxInputDevice implements Runnable, InputDevice {
               this.sysPath = sysPath;
               this.udevManifest = udevManifest;
               this.capabilities = SysFS.readCapabilities(sysPath);
      - this.absCaps = LinuxAbsoluteInputCapabilities.getCapabilities(
      - devNode, capabilities.get("abs"));
               fd = system.open(devNode.getPath(), LinuxSystem.O_RDONLY);
               if (fd == -1) {
                   throw new IOException(system.getErrorMessage() + " on " + devNode);
               }
      + this.absCaps = LinuxAbsoluteInputCapabilities.getCapabilities(
      + devNode, capabilities.get("abs"));
               // attempt to grab the device. If the grab fails, keep going.
               int EVIOCGRAB = system.IOW('E', 0x90, 4);
               system.ioctl(fd, EVIOCGRAB, 1);
      --
      libgit2 0.27.0
      ---------------------------------------------------------------------


      FREQUENCY : often


        Attachments

          Activity

            People

            • Assignee:
              Unassigned
              Reporter:
              webbuggrp Webbug Group
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated: