File gpm-1.20.1-silitek.patch of Package gpm

--- conf/gpm-silitek.conf
+++ conf/gpm-silitek.conf
@@ -0,0 +1,45 @@
+# Standard key mapping for Silitek SM-1000
+# on Linux virtual console (TERM=linux)
+key 1        1            1
+key 2        2            2
+key 3        3            3
+key 4        4            4
+key 5        5            5
+key 6        6            6
+key 7        7            7
+key 8        8            8
+key 9        9            9
+key 0        0            0
+key *        *            *
+key #        #            #
+# Ctrl+Q
+key >        \021         \021
+# Ctrl+S
+key ||       \023         \023
+# Crtl+C
+key []       \003         \003
+# End
+key >>|      \033[4~      \033[4~
+# Home
+key |<<      \033[1~      \033[1~
+# Delete
+key Mute     \033[3~      \033[3~
+# Cursor up
+key Vol+     \033[A       \033[A
+# Cursor down
+key Vol-     \033[B       \033[B
+# Insert
+key Display  \033[2~      \033[2~
+# Page up
+key PgUp     \033[5~      \033[5~
+Page down
+key PgDn     \033[6~      \033[6~
+# Cursor left
+key Back     \033[D       \033[D
+# Cursor right
+key Forward  \033[C       \033[C
+# F1 upto F4
+key CD       \033[[A      \033[[A
+key ShowWiz  \033[[B      \033[[B
+key WWW      \033[[C      \033[[C
+key Close    \033[[D      \033[[D
--- doc/README.silitek
+++ doc/README.silitek
@@ -0,0 +1,188 @@
+This README describes the support for the Silitek SM-1000 IR commander
+(also called Netshooter).
+
+This IR commander can be used with two types of mouse driver:
+
+    * Type `silicom' supports the IR receiver which is shipped the
+      SM-1000 and plugged into a serial connector.
+
+    * Type `silips2' supports the IR receiver which is shipped
+      with the Silitek IR keyboard SK-7100 (also called Airboard).
+      The mouse connector of this IR receiver should be plugged
+      into the PS/2 mouse connector (not to a serial connector).
+      You may need an adapter (9 pin serial to PS/2) to do this.
+
+Both types of mouse driver uses the system wide configuration file
+
+      /etc/gpm-silitek.conf
+
+which defines the return values of any key not being mouse button
+or mouse stick.  For this keys the drag mouse button works as a
+modifier: pressed once, the last column in /etc/gpm-silitek.conf
+is used. To switch back to the normal return values, the drag mouse
+button has to be pressed again.  It is allowed to use escaped
+sequences as return values.  Characters other than printable can
+be coded by using the backslash, e.g. `\033' for the octal number
+of the special character ESC (Escape) of `\x0D' for the hexadecimal
+number of the special character CR (Carriage Return), for more
+codings see the manual page ascii(7).
+
+The default key mapping for the SM-1000 IR commander is on the
+virtual console is:
+
+    SM-1000 Key  normal        drag active
+    -------------------------------------
+    key 1        1             1
+    key 2        2             2
+    key 3        3             3
+    key 4        4             4
+    key 5        5             5
+    key 6        6             6
+    key 7        7             7
+    key 8        8             8
+    key 9        9             9
+    key 0        0             0
+    key *        *             *
+    key #        #             #
+    key >        Ctrl Q        Ctrl Q
+    key ||       Ctrl S        Ctrl S
+    key []       Crtl C        Crtl C
+    key >>|      End           End
+    key |<<      Home          Home
+    key Mute     Delete        Delete
+    key Vol+     Cursor Up     Cursor Up
+    key Vol-     Cursor Down   Cursor Down
+    key Display  Insert        Insert
+    key PgUp     Page Up       Page Up
+    key PgDn     Page Down     Page Down
+    key Back     Cursor Left   Cursor Left
+    key Forward  Cursor Right  Cursor Right
+    key CD       F1            F1
+    key ShowWiz  F2            F2
+    key WWW      F3            F3
+    key Close    F4            F4
+
+Usage with the IR receiver of the Silitek Keyboard SK-7100:
+
+In comparison of the IR receiver of shipped with the SM-1000
+this IR receiver has the advantage that both mouse interface
+of the IR keyboard and the IR Netshooter can be used in parallel.
+One advantage more is that only one IR receiver is required to
+use both the IR keyboard and the IR Netshooter.  Next point is
+that the IR receiver of the IR keyboard seems to more insensitive
+for other IR commanders like those from TV sets.
+
+The Multimedia keys of the IR keyboard SK-7100 can be configured
+by using setkeycodes(8) and loadkeys(8) to be usable in parallel
+to those of the IR commander SM-1000.
+
+Notice: The key 7 of the IR commander SM-1000 generates the keyboard
+scancode for KP_ENTER if the SK-7100 keyboard is used in parallel.
+This happens even if the mouse type `silicom' is used in conjunction
+with the IR receiver of the SM-1000. This because if both IR receiver
+are used, the SM-1000 and the SK-7100, both receives signals from the
+SM-1000.  Therefore this key should be disabled (note that the SK-7100
+does not have a KP_ENTER):
+
+--------------------------------------------------------------------
+loadkeys <<-EOF
+keycode  96 = F39
+string  F39 = ""
+EOF
+--------------------------------------------------------------------
+
+With `showkeys -s' on the virtual console and `xev' under X11 the
+the other Multimedia keys of the SK-7100 causes the following
+scancodes/keycodes:
+
+     SK-7100 Key   console  X11
+     --------------------------
+     Close         e017     151
+     CD            e025     165
+     Video         e018     152
+     WWW           e032     178
+     U/P           e01e     158
+     |<<           e010     144
+     ||            e012     146
+     >             e022     162
+     []            e024     164
+     >>|           e019     153
+     Vol-          e02e     174
+     Vol+          e030     176
+     Mute          e020     160
+     Display       e026     166
+
+If we map for e.g. the keys
+
+     Video      Switch to vc 8 where the Video Recoder Program runs (Console_8)
+     |<<        Cursor Left (keycode 105)
+     >>|        Cursor Right (keycode 106)
+     Display    Win Menu key (keycode 127)
+
+(Compares this with `dumpkeys | less' on a virtual console).
+
+With the following command sequence (called in a script during boot):
+
+--------------------------------------------------------------------
+setkeycodes \
+	e017	85  \
+	e025	89  \
+	e018	90  \
+	e032	91  \
+	e01e	92  \
+	e010	105 \
+	e012	94  \
+	e022	95  \
+	e024	120 \
+	e019	106 \
+	e02e	122 \
+	e030	123 \
+	e020	124 \
+	e026	127
+loadkeys <<-EOF
+	keycode  85 = F50
+	keycode  89 = F51
+	keycode  90 = Console_8
+	keycode  91 = F53
+	keycode  92 = F54
+	keycode  94 = F56
+	keycode  95 = F57
+	keycode 120 = F58
+	keycode 122 = F60
+	keycode 123 = F61
+	keycode 124 = F62
+	keycode 127 = F63
+	keycode  96 = F39
+	string  F50 = "\033[[Z"
+	string  F51 = "\033[[Y"
+	string  F53 = "\033[[W"
+	string  F54 = "\033[[U"
+	string  F56 = "\033[[H"
+	string  F57 = "\033[[T"
+	string  F58 = "\033[[F"
+	string  F60 = "\033[[L"
+	string  F61 = "\033[[M"
+	string  F62 = "\033[[X"
+	string  F63 = "\033[[R"
+	string  F39 = ""
+EOF
+--------------------------------------------------------------------
+
+the Multimedia keys on IR Keyboard SK-7100 are usable (for ncurses
+based programs see below).  After editing /etc/gpm-silitek.conf
+to get the similar named keys to work similar, both the IR Keyboard
+SK-7100 and the IR commander SM-1000 are usable in parallel.
+
+For ncurses based programs the added keys have to be extended
+by dumping the current terminfo entry for the virtual consoles
+for TERM=linux:
+
+    infocmp -1 linux > linux.tic
+
+and editing the file linux.tic which means adding the function
+keys kf50, kf51, kf52, kf53, kf54, kf56, kf57, kf58, kf60, kf61,
+kf62, kf63, and kf39.  After that the command
+
+    tic linux.tic
+
+installs the edited terminfo entry for TERM=linux.
--- src/Makefile.in
+++ src/Makefile.in
@@ -13,7 +13,7 @@
 
 # Main portion: regular build rules
 
-GSRC = main.c gpm.c gpn.c mice.c special.c twiddler.c synaptics.c \
+GSRC = main.c gpm.c gpn.c mice.c special.c twiddler.c synaptics.c silitek.c \
        startup.c server_tools.c
 
 GOBJ = $(GSRC:.c=.o) report.o tools.o
@@ -24,7 +24,7 @@
 
 PICS = $(LOBJ:.o=.lo)
 
-HDRS = gpm.h gpmInt.h twiddler.h synaptics.h message.h
+HDRS = gpm.h gpmInt.h twiddler.h synaptics.h silitek.h message.h
 
 PSRC = prog/mev.c prog/hltest.c prog/mouse-test.c prog/disable-paste.c
 
@@ -144,7 +144,7 @@
 	$(CC) -I. @CPPFLAGS@ $(CPPFLAGS) @CFLAGS@ $(CFLAGS) -c -o $@.o $<
 	$(CC) @LDFLAGS@ $(LDFLAGS) -o $@ $@.o @LIBS@ $(LIBS) lib/libgpm.a
 
-prog/mouse-test:	mice.o twiddler.o synaptics.o
+prog/mouse-test:	mice.o twiddler.o synaptics.o silitek.o
 
 $(PROG):	lib/libgpm.so lib/@SHLIB@ lib/libgpm.a
 
--- src/headers/message.h
+++ src/headers/message.h
@@ -194,6 +194,10 @@
 #define GPM_MESS_INCORRECT_LINE     "%s: %s :%i: Incorrect line:\"%s\""
 #define GPM_MESS_FIRST_DEV          "Use -m device -t protocol [-o options]!"
 
+#define GPM_MESS_SILIPS2_ENABLE     "silips2: enable error"
+#define GPM_MESS_SILIPS2_DISABLE    "silips2: disable error"
+#define GPM_MESS_SILIPS2_RESET      "silips2: reset error"
+
 
 /* warnings */
 #define GPM_MESS_REQUEST_ON         "Request on vc %i > %i"
--- src/headers/silitek.h
+++ src/headers/silitek.h
@@ -0,0 +1,33 @@
+/*
+ * silitek.h - support for the Silitek SM-1000 (Netshooter) with its IR
+ *             receiver plugged serial connector and also with the IR
+ *             receiver of the Silitek SK-7100 keyboard (Airboard)
+ *             PS2 mouse connector.
+ *
+ * Copyright 2002   Werner Fink <werner@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+extern int silitek_get_check(unsigned char *data);
+extern int silitek_get_check_ps2(unsigned char *data);
+extern void silitek_keys(unsigned char *data, int *drag);
+extern void silitek_keys_ps2(unsigned char *data, int *drag);
+extern int silitek_ghost_ps2(unsigned char *data);
+extern int fd_silitek;
+#define SILI_SYSTEM_FILE SYSCONFDIR "/gpm-silitek.conf"
+#define SILISTRLEN      32
+#define SILISTRSCN      "key %32s %32s %32s"
+extern void silitek_mapping(void);
--- src/mice.c
+++ src/mice.c
@@ -74,6 +74,7 @@
 #include "headers/gpmInt.h"
 #include "headers/twiddler.h"
 #include "headers/synaptics.h"
+#include "headers/silitek.h"
 #include "headers/message.h"
 
 /*========================================================================*/
@@ -667,6 +668,86 @@
 
 }
 
+#define GPM_B_BOTH (GPM_B_LEFT|GPM_B_RIGHT)
+static int M_silitek_ps2(Gpm_Event *state,  unsigned char *data)
+{
+  static int drag = 0;
+
+  if (!silitek_get_check_ps2(data))
+    return -1;
+
+  /*
+   * Map some ghost mouse PS2 events caused by the other
+   * keys.  Maybe there is a better initialization for the chip
+   * of the SK-7100 IR receiver which would avoid those events.
+   */
+  (void)silitek_ghost_ps2(data);
+
+  /* All none PS2 events */
+  if (data[0] & 0xc0)
+  {
+    silitek_keys_ps2(data, &drag);
+    return -1; /* Do not highlight, but success */
+  } 
+
+  state->buttons = ((data[0]&0x01)<<2)|(data[0]&0x02)|((data[0]&0x04)>>2);
+
+  /* Drag is just a modifier for none mouse keys */
+  if (state->buttons&GPM_B_LEFT)
+    drag = ((!drag) ? 1 : 0);
+  else
+    drag = 0;
+
+  if(data[1]) state->dx =   (data[0] & 0x10) ? data[1] - 0xFF : data[1];
+  if(data[2]) state->dy = -((data[0] & 0x20) ? data[2] - 0xFF : data[2]);
+
+  return 0;
+}
+
+static int M_silitek(Gpm_Event *state,  unsigned char *data)
+{
+  static int drag = 0;
+
+  if (!silitek_get_check(data))
+    return -1;
+
+  /* All none mouse events */
+  if (!(data[0] & 0x40))
+  {
+    silitek_keys(data, &drag);
+    return -1; /* Do not highlight, but success */
+  }
+
+  /*
+   * Sanity check: SM-1000 mouse events do not use this bit
+   * but Keyboard SK-7100 PgUp/PgDn/`x'
+   * (0xfe5da5/0xfd5da5/0x7c845d)
+   */
+  if ((data[1] & 0x40) || (data[2] & 0x40))
+    return -1;
+
+  switch(data[0])
+  {
+    case 0xfe: state->buttons = GPM_B_LEFT;  break;
+    case 0xfd: state->buttons = GPM_B_RIGHT; break;
+    case 0x7f: state->buttons = GPM_B_BOTH;  break;
+    case 0x7c: state->buttons = 0; break;
+    default:   return -1; /* Do not highlight */
+	break;
+  }
+
+  /* Drag is just a modifier for none mouse keys */
+  if (state->buttons&GPM_B_LEFT)
+    drag = ((!drag) ? 1 : 0);
+  else
+    drag = 0;
+
+  state->dx = (data[1] & 0x20) ? ((data[1] & 0x1f) - 0x20) : (data[1] & 0x1f);
+  state->dy = (data[2] & 0x20) ? ((data[2] & 0x1f) - 0x20) : (data[2] & 0x1f);
+
+  return 0;
+}
+
 static int M_netmouse(Gpm_Event *state,  unsigned char *data)
 {
    /* Avoid these beasts if you can.  They connect to normal PS/2 port,
@@ -745,7 +826,6 @@
    return type;
 }
 
-#define GPM_B_BOTH (GPM_B_LEFT|GPM_B_RIGHT)
 static int M_mman(Gpm_Event *state,  unsigned char *data)
 {
    /*
@@ -1828,7 +1908,7 @@
  * 
  * Returns 0 if OK, or >0 if 1 or more errors occurred.
  */
-static int write_to_mouse(int fd, unsigned char *data, size_t len)
+static int write_to_mouse(int fd, const unsigned char *data, size_t len)
 {
    int i;
    int error = 0;
@@ -1845,6 +1925,89 @@
    return(error);
 }
 
+static Gpm_Type *I_silitek(int fd, unsigned short flags, struct Gpm_Type *type, int argc, char **argv)
+{
+  struct termios tty;
+  int speed = B1200;
+  fd_silitek = fd;
+
+  tcgetattr(fd, &tty);
+  cfmakeraw(&tty);
+  cfsetspeed(&tty, speed);
+  tty.c_cc[VMIN]  = 1;
+  tty.c_cc[VTIME] = 0;
+  tty.c_cflag |=  CS8;
+#if 0
+  tty.c_cflag &= ~(CRTSCTS|CSTOPB|PARODD);
+  tty.c_cflag |=  flags;
+#endif
+  tcsetattr(fd, TCSAFLUSH, &tty);
+  silitek_mapping();
+
+  return type;
+}
+
+static Gpm_Type *I_silitek_ps2(int fd, unsigned short flags, struct Gpm_Type *type, int argc, char **argv)
+{
+  const unsigned char off[] = {GPM_AUX_DISABLE_DEV, };
+  const unsigned char buf[] = {GPM_AUX_SET_RES, 3,
+			       GPM_AUX_SET_SCALE11,
+			       GPM_AUX_SET_SAMPLE, 200,
+			       GPM_AUX_ENABLE_DEV, };
+  int n, c, err, id;
+
+  fd_silitek = fd;
+
+  (void)write_to_mouse(fd, off, sizeof(off));
+
+  err=1;
+  for (n = 0; n < 3 && err; n++)
+  {
+    err=0;
+    c = GPM_AUX_RESET;
+    write(fd, &c, 1);
+    read(fd, &c, 1);
+    if (c != GPM_AUX_ACK) err++;
+    read(fd, &c, 1);
+    if (c != 0xAA) err++;
+    read(fd, &c, 1);
+    if (c != 0x00) err++;
+    if (err) usleep(50000);
+  }
+
+  (void)write_to_mouse(fd, buf, sizeof(buf));
+  usleep(50000);
+
+  if ((id = read_mouse_id(fd)) == GPM_AUX_ID_ERROR)
+  {
+    if (write_to_mouse(fd, off, sizeof(off)))
+      gpm_report(GPM_PR_ERR,GPM_MESS_SILIPS2_DISABLE);
+
+    err=1;
+    for (n = 0; n < 3 && err; n++)
+    {
+      err=0;
+      c = GPM_AUX_RESET;
+      write(fd, &c, 1);
+      read(fd, &c, 1);
+      if (c != GPM_AUX_ACK) err++;
+      read(fd, &c, 1);
+      if (c != 0xAA) err++;
+      read(fd, &c, 1);
+      if (c != 0x00) err++;
+      if (err)
+	  usleep(50000);
+    }
+    if (err > 0)
+      gpm_report(GPM_PR_ERR,GPM_MESS_SILIPS2_RESET);
+    if (write_to_mouse(fd, buf, sizeof(buf)))
+      gpm_report(GPM_PR_ERR,GPM_MESS_SILIPS2_ENABLE);
+    id = 0x00;
+  }
+  silitek_mapping();
+
+  return type;
+}
 
 /* intellimouse, ps2 version: Ben Pfaff and Colin Plumb */
 /* Autodetect: Steve Bennett */
@@ -2297,6 +2460,12 @@
    {"ps2",  "Busmice of the ps/2 series. Most busmice, actually.",
            "PS/2", M_ps2, I_ps2, STD_FLG,
                                 {0xc0, 0x00, 0x00, 0x00}, 3, 1, 0, 0, R_ps2, 1},
+   {"silips2","Silitek SM-1000 Netshooter plugged into ps/2 mouse connector.",
+           "SiliPS/2", M_silitek_ps2, I_silitek_ps2, STD_FLG,
+                                {0x00, 0x00, 0x00, 0x00}, 1, 1, 0, 0, 0, 1},
+   {"silicom","Silitek SM-1000 Netshooter plugged into serial connector.",
+           "SiliCom", M_silitek, I_silitek, STD_FLG,
+                                {0x20, 0x20, 0x00, 0x00}, 1, 1, 0, 0, 0, 0},
    {"sun",  "'msc' protocol, but only 3 bytes per packet.",
            "", M_sun, I_serial, CS8 | CSTOPB | STD_FLG,
                                 {0xf8, 0x80, 0x00, 0x00}, 3, 1, 0, 0, 0, 0},
--- src/silitek.c
+++ src/silitek.c
@@ -0,0 +1,580 @@
+/*
+ * silitek.c - support for the Silitek SM-1000 (Netshooter) with its IR
+ *             receiver plugged serial connector and also with the IR
+ *             receiver of the Silitek SK-7100 keyboard (Airboard)
+ *             PS2 mouse connector.
+ *
+ * Copyright 2002   Werner Fink <werner@suse.de>
+ *
+ *   This program is free software; you can redistribute it and/or modify
+ *   it under the terms of the GNU General Public License as published by
+ *   the Free Software Foundation; either version 2 of the License, or
+ *   (at your option) any later version.
+ *
+ *   This program is distributed in the hope that it will be useful,
+ *   but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *   GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program; if not, write to the Free Software
+ *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
+ *
+ */
+
+/*
+ * Serial settings used herein: raw but I/O with baud rate 1200 and 8bit (YES!)
+ * For testing, e.g.:  stty -a < /dev/ttyS1
+ * To set this, e.g.:  stty raw 1200 cs8 < /dev/ttyS1
+ * For reading keycodes use, e.g.:
+ *                     od [-j (1|2)] -v -t x1 --width=3 < /dev/ttyS1
+ * compare with I_silitek() in mice.c.
+ * Which provides following keycodes received by the IR receiver
+ * included in the SM-1000 shipment for the SM-1000 its self:
+ *
+ * First byte: 0xbf (Key down, 8 bit striped this is 0x3f)
+ *             0x31 (Key hold down)
+ *             0x2a (Key up)
+ *             0x7c (Mouse event: move, any button up)
+ *             0x7f (Mouse event: move, l+r-mouse button down)
+ *             0xfd (Mouse event: move, r-mouse button down)
+ *             0xfe (Mouse event: move, l-mouse button down)
+ * Which provides: Any if   (byte0 & 0x20) == 0x20 (for GPM protocol check)
+ *                 Key if   (byte0 & 0x40) == 0x00
+ *                 Mouse if (byte0 & 0x40) == 0x40
+ * Second and third byte (unsigned char, aka 8bits):
+ *   1:       0xc1 0xfe
+ *   2:       0xc2 0xfd
+ *   3:       0x43 0x7c
+ *   4:       0xc4 0xfb
+ *   5:       0x45 0x7a
+ *   6:       0x46 0x79
+ *   7:       0xc7 0xf8
+ *   8:       0xc8 0xf7
+ *   9:       0x49 0x76
+ *   0:       0x4a 0x75
+ *   *:       0xcb 0xf4
+ *   #:       0x4c 0x73
+ *   >:       0xcd 0xf2
+ *   ||:      0xce 0xf1
+ *   []:      0x4f 0x70
+ *   >>|:     0xd0 0xef
+ *   |<<:     0x51 0x6e
+ *   Mute:    0x52 0x6d
+ *   Vol+:    0xd3 0xec
+ *   Vol-:    0x54 0x6b
+ *   Display: 0xd5 0xea
+ *   PgUp:    0xd6 0xe9
+ *   PgDn:    0x57 0x68
+ *   Back:    0x58 0x67
+ *   Forward: 0xd9 0xe6
+ *   CD:      0xda 0xe5
+ *   ShowWiz: 0x5b 0x64
+ *   WWW:     0xdc 0xe3
+ *   Close:   0x5d 0x62
+ * Which provides: byte1 & 0x20 == 0x00, byte1 & 0x40 == 0x40
+ *                 (byte1 & 0x7f) & (byte2 & 0x7f) == 0x40
+ *                 (byte1 & 0x7f) | (byte2 & 0x7f) == 0x7f
+ *                 (byte1 & 0x1f) == keycode
+ * 
+ * No mouse move but mouse button:
+ *   0x80 0x80
+ * Mouse move but no button:
+ *   right (byte1 & 0x20) == 0x20
+ *   left  (byte2 & 0x20) == 0x20
+ *   value (byte1 & 0x1f), (byte2 & 0x1f)
+ * Mouse move and button:
+ *   OR combinations from above.
+ * In both bytes, byte1 and byte2, the 0x40 bit seeems not to be used.
+ *
+ * PS2 settings used herin: Standard PS2 mouse.
+ * For reading keycodes use, e.g.:
+ *                     od [-j (1|2)] -v -t x1 --width=3 < /dev/psaux
+ * compare with I_silitek_ps2() in mice.c.
+ * Which provides following keycodes received by the IR receiver
+ * included in the SK-7100 shipment for the SM-1000 keys:
+ *
+ * First byte: 0xe7 (Key down)
+ *             0xd7 (Key hold down)
+ *             0xf7 (Key up)
+ *             byte0 & 0xc0 == 0x00  (PS2 mouse event)
+ * Which provides: Key if   (byte0 & 0xc0) == 0xc0
+ *                 Mouse if (byte0 & 0xc0) == 0x00  (PS2 mouse)
+ * In other words: No GPM protocol check.
+ * Second and third byte (unsigned char, aka 8bits):
+ *   1:       0x01 0xfe
+ *   2:       0x02 0xfd
+ *   3:       0x03 0xfc
+ *   4:       0x04 0xfb
+ *   5:       0x05 0xfa
+ *   6:       0x06 0xf9
+ *   7:       0x07 0xf8
+ *   8:       0x08 0xf7
+ *   9:       0x09 0xf6
+ *   0:       0x0a 0xf5
+ *   *:       0x0b 0xf4
+ *   #:       0x0c 0xf3
+ *   >:       0x0d 0xf2
+ *   ||:      0x0e 0xf1
+ *   []:      0x0f 0xf0
+ *   >>|:     0x10 0xef
+ *   |<<:     0x11 0xee
+ *   Mute:    0x12 0xed
+ *   Vol+:    0x13 0xec
+ *   Vol-:    0x14 0xeb
+ *   Display: 0x15 0xea
+ *   PgUp:    0x16 0xe9
+ *   PgDn:    0x17 0xe8
+ *   Back:    0x18 0xe7
+ *   Forward: 0x19 0xe6
+ *   CD:      0x1a 0xe5
+ *   ShowWiz: 0x1b 0xe4
+ *   WWW:     0x1c 0xe3
+ *   Close:   0x1d 0xe2
+ * Which provides: byte1 & byte2 == 0x00
+ *                 byte1 | byte2 == 0xff
+ *                 byte1 == keycode
+ * 
+ * Mouse is standard PS2 mouse
+ */
+
+/*
+ * TODO
+ * Serial part: Find device settings which avoids changing IR sequences of other
+ *              vendors like from Sony TV commanders.  This because to filter
+ *              them out.
+ * PS2 part: Better device settings which avoids the `ghost' mouse events
+ *           caused by the other keys.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include "headers/gpm.h"
+#include "headers/silitek.h"
+#include "headers/gpmInt.h"
+#include "headers/message.h"
+
+int fd_silitek = -1;
+
+struct silitek_key_struct {
+    char *key;
+    char item[32];
+    char drag[32];
+} static K_silitek[] = {
+    /* TERM=linux */
+    { NULL,	"",		""	 },
+    {"1",	"1",		"1"	 },
+    {"2",	"2",		"2"	 },
+    {"3",	"3",		"3"	 },
+    {"4",	"4",		"4"	 },
+    {"5",	"5",		"5"	 },
+    {"6",	"6",		"6"	 },
+    {"7",	"7",		"7"	 },
+    {"8",	"8",		"8"	 },
+    {"9",	"9",		"9"	 },
+    {"0",	"0",		"0"	 },
+    {"*",	"*",		"*"	 },
+    {"#",	"#",		"#"	 },
+    {">",	"\021",		"\021"	 },	/* Ctrl+Q */
+    {"||",	"\023",		"\023"	 },	/* Ctrl+S */
+    {"[]",	"\003",		"\003"	 },	/* Ctrl+C */
+    {">>|",	"\033[4~",	"\033[4~"},	/* End */
+    {"|<<",	"\033[1~",	"\033[1~"},	/* Home */
+    {"Mute",	"\033[3~",	"\033[3~"},	/* Delete */
+    {"Vol+",	"\033[A",	"\033[A" },	/* Cursor up */
+    {"Vol-",	"\033[B",	"\033[B" },	/* Cursor down */
+    {"Display",	"\033[2~",	"\033[2~"},	/* Insert */
+    {"PgUp",	"\033[5~",	"\033[5~"},	/* Page up */
+    {"PgDn",	"\033[6~",	"\033[6~"},	/* Page down */
+    {"Back",	"\033[D",	"\033[D" },	/* Cursor left */
+    {"Forward",	"\033[C",	"\033[C" },	/* Cursor right */
+    {"CD",	"\033[[A",	"\033[[A"},	/* F1 */
+    {"ShowWiz",	"\033[[B",	"\033[[B"},	/* F2 */
+    {"WWW",	"\033[[C",	"\033[[C"},	/* F3 */
+    {"Close",	"\033[[D",	"\033[[D"},	/* F4 */
+    { NULL,	"",		""	 }
+};
+#define SILITEK_KEYS	(sizeof(K_silitek)/sizeof(struct silitek_key_struct))
+
+/* From twiddler.c: The same silly function as in gpm.c */
+static inline int open_console(const int mode)
+{
+    int fd;
+    extern struct options option;
+
+    if ((fd=open(option.consolename, mode)) < 0)
+        gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN,option.consolename);
+    return fd;
+}
+
+static inline int silitek_wait(int timeout)
+{
+    fd_set Set;
+    struct timeval tv = {0, timeout};
+    int ret = 0;
+
+    do {
+	FD_ZERO(&Set);
+	FD_SET(fd_silitek, &Set);
+	ret = select(fd_silitek+1, &Set, NULL, NULL, &tv);
+
+    } while (ret < 0 && (errno == EINTR || errno == EAGAIN));
+
+    if (ret < 0 || !(FD_ISSET(fd_silitek, &Set)))
+	return 0;
+    return 1;
+}
+
+static inline int silitek_read(unsigned char *data, int timeout)
+{
+    ssize_t r = 0;
+    do {
+	if (!silitek_wait(timeout))
+	    break;
+        r = read(fd_silitek, data, 1);
+
+    } while (r < 0 && (errno == EINTR || errno == EAGAIN));
+
+    if(r != 1)
+	return 0;
+    return 1;
+}
+
+int silitek_get_check(unsigned char *data)
+{
+    if ((data[0] != 0xbf) && /* key down */
+	(data[0] != 0x31) && /* key hold down */
+	(data[0] != 0x2a) && /* key up */
+	(data[0] != 0x7c) && /* mouse event and/or button up */
+	(data[0] != 0x7f) && /* mouse event and l+r-mouse button down */
+	(data[0] != 0xfd) && /* mouse event and r-mouse button down */
+	(data[0] != 0xfe))   /* mouse event and l-mouse button down */
+	return 0;
+    if (!silitek_read(&data[1], 50000))
+	return 0;
+    if (!silitek_read(&data[2], 50000))
+	return 0;
+#if 0
+    /*
+     * Sony IR
+     *   various, it seems that the bit rate is to high to get stable
+     *   bytes in correct order. Or the protocol of such a TV commander
+     *   is more complicated than those of the SM-1000 because the IR
+     *   receivers of the SM-1000 seems not read this fully correct.
+     */
+    if (data[0] == 0xfe) {
+	if (data[1] == 0x14 && data[2] == 0x8c)
+	    return 0;
+	if (data[1] == 0x94 && (data[2] == 0x8c || data[2] == 0x8d))
+	    return 0;
+    }
+#endif
+    return 1;
+}
+
+void silitek_keys(unsigned char *data, int *drag)
+{
+    int ret = 0, unblank = 4, cfd;
+    int but = (data[1] & 0x7f);
+    int chk = (data[2] & 0x7f);
+    int timediff = 0;
+    char *item;
+
+    if ((but & 0x20) || (but & 0x40) != 0x40)
+	return;
+    if ((but&chk) != 0x40 || (but|chk) != 0x7f)
+	return;
+    but &= 0x1f;
+    chk &= 0x1f;
+
+    if ((but|chk) != 0x1f)
+	return;
+    if (but < 1 || but > SILITEK_KEYS)
+	return;
+
+#define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL))
+#define DIF_TIME(t1,t2) ((t2.tv_sec-t1.tv_sec)*1000 + (t2.tv_usec-t1.tv_usec)/1000)
+
+    switch(data[0]) {
+	static struct timeval uptv;
+	struct timeval tv;
+	case 0x2a:
+	    uptv.tv_sec = 0;
+	    /* fall through */
+	default:
+	    return;
+	    break;
+	case 0x31:
+	case 0xbf:
+	    GET_TIME(tv);
+	    if (!uptv.tv_sec) {
+		uptv.tv_sec  = tv.tv_sec;
+		uptv.tv_usec = tv.tv_usec;
+	    }
+	    timediff = DIF_TIME(uptv, tv);
+	    break;
+    }
+
+#undef GET_TIME
+#undef DIF_TIME
+
+    if (timediff && timediff < opt_time)
+	return;
+
+    item = K_silitek[but].item;
+    if (*drag) {
+	item = K_silitek[but].drag;
+	but = 0;
+    }
+#if 0
+    *drag = 0;
+#endif
+
+    cfd = open_console(O_WRONLY|O_NONBLOCK|O_NOCTTY);
+    if (cfd < 0)
+	return;
+    while (*item && !ret)
+	ret = ioctl(cfd, TIOCSTI, item++);
+    ioctl(cfd, TIOCLINUX, &unblank);
+    close(cfd);
+}
+
+int silitek_get_check_ps2(unsigned char *data)
+{
+#if 0
+    /*
+     * Enable this to trace foreign IR bytes sequences received by
+     * by the IR receiver of the SK-7100 keyboard.
+     */
+    FILE *log;
+    if (!(log = fopen("/tmp/log", "a")))
+	return 0;
+    fprintf(log, "TV: 0x%.2x 0x%.2x 0x%.2x\n", data[0], data[1], data[2]);
+    fclose(log);
+#endif
+    if ((data[0] != 0xe7) && /* key down */
+	(data[0] != 0xd7) && /* key hold down */
+	(data[0] != 0xf7) && /* key up */
+	(data[0]&0xc0))      /* PS2 mouse event */
+	return 0;
+    if (!silitek_read(&data[1], 50000))
+	return 0;
+    if (!silitek_read(&data[2], 50000))
+	return 0;
+    /*
+     * Other IR, current known:
+     *
+     * Sony IR
+     *   0x29 0x0c 0xf4
+     *   0x29 0x14 0xf4
+     */
+    if (data[0] == 0x29 && data[2] == 0xf4 && ((data[1] && 0x0c) || (data[1] && 0x14))) {
+	return 0;
+    }
+    return 1;
+}
+
+void silitek_keys_ps2(unsigned char *data, int *drag)
+{
+    int ret = 0, unblank = 4, cfd;
+    int but = data[1];
+    int chk = data[2];
+    int timediff = 0;
+    char *item;
+
+    if ((but&chk) && (but|chk) != 0xff)
+	return;
+
+    if (but < 1 || but > SILITEK_KEYS)
+	return;
+
+#define GET_TIME(tv) (gettimeofday(&tv, (struct timezone *)NULL))
+#define DIF_TIME(t1,t2) ((t2.tv_sec-t1.tv_sec)*1000 + (t2.tv_usec-t1.tv_usec)/1000)
+
+    switch(data[0]) {
+	static struct timeval uptv;
+	struct timeval tv;
+	case 0xe7:
+	    uptv.tv_sec = 0;
+	    /* fall through */
+	default:
+	    return;
+	    break;
+	case 0xd7:
+	case 0xf7:
+	    GET_TIME(tv);
+	    if (!uptv.tv_sec) {
+		uptv.tv_sec  = tv.tv_sec;
+		uptv.tv_usec = tv.tv_usec;
+	    }
+	    timediff = DIF_TIME(uptv, tv);
+	    break;
+    }
+
+#undef GET_TIME
+#undef DIF_TIME
+
+    if (timediff && timediff < opt_time)
+	return;
+
+    item = K_silitek[but].item;
+    if (*drag) {
+	item = K_silitek[but].drag;
+	but = 0;
+    }
+#if 0
+    *drag = 0;
+#endif
+
+    cfd = open_console(O_WRONLY|O_NONBLOCK|O_NOCTTY);
+    if (cfd < 0)
+	return;
+    while (*item && !ret)
+	ret = ioctl(cfd, TIOCSTI, item++);
+    ioctl(cfd, TIOCLINUX, &unblank);
+    close(cfd);
+}
+
+/*
+ * Map some ghost mouse PS2 events caused by the other
+ * keys.  Maybe there is a better initialization for the chip
+ * of the SK-7100 IR receiver which would avoid those events.
+ */
+int silitek_ghost_ps2(unsigned char *data)
+{
+    if (data[0] == 0x18 || data[0] == 0x19) {
+	int but = data[1] - 0xc0;
+	int chk = data[2] - 0x01;
+
+	if ((but >= 1 && but <= SILITEK_KEYS) && (but == chk)) {
+	    data[0] = 0xf7;
+	    data[1] = but;
+	    data[2] = 0xff - but;
+	}
+    }
+    return 0;
+}
+
+static char ansicstr_ret[SILISTRLEN+1];
+static char* ansicstr(char *string)
+{
+    int c, conv = 0, o;
+    char *ptr = string;
+    char *ret = &ansicstr_ret[0];
+
+    memset(&ansicstr_ret[0], 0, sizeof(ansicstr_ret));
+    while (ptr && *ptr) {
+	switch (c = *ptr++) {
+	case '\\':
+	    if (!conv) {
+		conv = 1;
+		continue;
+	    } else
+		c = '\\';
+	    conv = 0; break;
+	case 'a':  if (conv) c = '\a'; conv = 0; break;
+	case 'b':  if (conv) c = '\b'; conv = 0; break;
+	case 't':  if (conv) c = '\t'; conv = 0; break;
+	case 'n':  if (conv) c = '\n'; conv = 0; break;
+	case 'v':  if (conv) c = '\v'; conv = 0; break;
+	case 'f':  if (conv) c = '\f'; conv = 0; break;
+	case 'r':  if (conv) c = '\r'; conv = 0; break;
+	case 'e':  if (conv) c = '\e'; conv = 0; break;
+	case 'E':  if (conv) c = '\e'; conv = 0; break;
+	case '0': case '1': case '2': case '3':
+	case '4': case '5': case '6': case '7':
+	    if (!conv) break;
+	    c -= '0';
+	    for (o = 2; ptr && (*ptr >= '0' && *ptr <= '7' ) && o--; ptr++)
+		c = (c * 8) + (*ptr - '0');
+	    conv = 0; break;
+	case 'x':
+	    if (!conv) break;
+	    for (o = 3; ptr && isxdigit(*ptr) && o--; ptr++)
+		c = (c * 16) +
+		    ((*ptr >= 'a' && *ptr <= 'f') ? (*ptr - 'a' + 10) :
+			((*ptr >= 'A' && *ptr <= 'F') ? (*ptr - 'A' + 10) : (*ptr - '0')));
+	    if (o == 3) {
+		*ret++ = '\\';
+		c = 'x';
+	    }
+	    conv = 0; break;
+	default:
+	    conv = 0; break;
+	}
+	*ret++ = c;
+    }
+    return &ansicstr_ret[0];
+}
+
+void silitek_mapping()
+{
+    static int mapdone = 0;
+    FILE *conf;
+    char line[128];
+    int k = 1;
+
+    /* Just in case if called twice with -M option */
+    if (mapdone)
+	return;
+    mapdone = 1;
+
+    if (!(conf = fopen(SILI_SYSTEM_FILE, "r"))) {
+	if (errno != ENOENT)
+	    gpm_report(GPM_PR_OOPS,GPM_MESS_OPEN,SILI_SYSTEM_FILE);
+	return;
+    }
+
+    while (fgets(line, 128, conf)) {
+	int n;
+	char key[SILISTRLEN+1], item[SILISTRLEN+1], drag[SILISTRLEN+1];
+	/* Comments and empty lines */
+	if (line[0] == '\n' || line[0] == '#')
+	    continue;
+
+	if (line[strlen(line) - 1] == '\n')
+	    line[strlen(line) - 1] = '\0';
+	while (isspace(line[strlen(line) - 1]))
+	    line[strlen(line) - 1] = '\0';
+
+	if (line[0] == '\0')
+	    continue;
+
+	key[0] = item[0] = drag[0] = '\0';
+	if ((n = sscanf(line, SILISTRSCN, key, item, drag)) > 1 && n < 4) {
+	    while (k < SILITEK_KEYS) {
+		if (!K_silitek[k].key) {
+		    k = 1;
+		    break;
+		}
+		if (!strncasecmp(key, K_silitek[k].key, SILISTRLEN)) {
+		    size_t i = strlen(item), d = strlen(drag);
+		    if (d) {
+			if (d > SILISTRLEN)
+			    d = SILISTRLEN;
+			strncpy(K_silitek[k].drag, ansicstr(drag), d);
+			K_silitek[k].drag[d] = '\0';
+		    }
+		    if (i) {
+			if (i > SILISTRLEN)
+			    i = SILISTRLEN;
+			strncpy(K_silitek[k].item, ansicstr(item), i);
+			K_silitek[k].item[i] = '\0';
+		    }
+		    break;
+		}
+		k++;
+	    }
+	}
+    }
+}
openSUSE Build Service is sponsored by