gpm/gpm-1.20.1-silitek.patch

1118 lines
32 KiB
Diff
Raw Normal View History

--- 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
@@ -143,7 +143,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++;
+ }
+ }
+ }
+}