All of lore.kernel.org
 help / color / mirror / Atom feed
From: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
To: linux-input@vger.kernel.org
Cc: linux-omap@vger.kernel.org, Tony Lindgren <tony@atomide.com>,
	Dmitry Torokhov <dmitry.torokhov@gmail.com>
Subject: [RFC][PATCH 4/5] input: serio: add support for Amstrad Delta serial keyboard port
Date: Thu, 10 Dec 2009 21:07:50 +0100	[thread overview]
Message-ID: <200912102107.52375.jkrzyszt@tis.icnet.pl> (raw)
In-Reply-To: <200912102058.43892.jkrzyszt@tis.icnet.pl>

The patch introduces a serio driver that supports a keyboard serial port found
on the Amstrad Delta videophone board.

After initializing the hardware, the driver reads its input data from a buffer
filled in by the board FIQ (Fast Interrupt Request) handler.

Compiles and works on to of patch 3/5: omap1: Amstrad Delta: use FIQ for
processing MPU GPIO interrupts

Created and tested against linux-omap for-next,
commit 82f1d8f22f2c65e70206e40a6f17688bf64a892c dated 2009-12-02.

Signed-off-by: Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>

---

 drivers/input/serio/Kconfig              |    9 +
 drivers/input/serio/Makefile             |    1
 drivers/input/serio/ams_delta_keyboard.c |  240 +++++++++++++++++++++++++++++++
 3 files changed, 250 insertions(+)

diff -uprN git.orig/drivers/input/serio/Kconfig git/drivers/input/serio/Kconfig
--- git.orig/drivers/input/serio/Kconfig	2009-12-02 15:51:50.000000000 +0100
+++ git/drivers/input/serio/Kconfig	2009-12-10 14:21:05.000000000 +0100
@@ -201,4 +201,13 @@ config SERIO_XILINX_XPS_PS2
 	  To compile this driver as a module, choose M here: the
 	  module will be called xilinx_ps2.
 
+config SERIO_AMS_DELTA
+	tristate "Amstrad Delta (E3) keyboard support"
+	depends on MACH_AMS_DELTA && AMS_DELTA_FIQ
+	---help---
+	  Say Y here if has an E3 and want to use the separate keyboard
+
+	  To compile this driver as a module, choose M here: the
+	  module will be called ams_delta_keyboard
+
 endif
diff -uprN git.orig/drivers/input/serio/Makefile git/drivers/input/serio/Makefile
--- git.orig/drivers/input/serio/Makefile	2009-12-02 15:51:50.000000000 +0100
+++ git/drivers/input/serio/Makefile	2009-12-10 14:21:05.000000000 +0100
@@ -21,4 +21,5 @@ obj-$(CONFIG_SERIO_PCIPS2)	+= pcips2.o
 obj-$(CONFIG_SERIO_MACEPS2)	+= maceps2.o
 obj-$(CONFIG_SERIO_LIBPS2)	+= libps2.o
 obj-$(CONFIG_SERIO_RAW)		+= serio_raw.o
+obj-$(CONFIG_SERIO_AMS_DELTA)	+= ams_delta_keyboard.o
 obj-$(CONFIG_SERIO_XILINX_XPS_PS2)	+= xilinx_ps2.o
diff -uprN git.orig/drivers/input/serio/ams_delta_keyboard.c git/drivers/input/serio/ams_delta_keyboard.c
--- git.orig/drivers/input/serio/ams_delta_keyboard.c	1970-01-01 01:00:00.000000000 +0100
+++ git/drivers/input/serio/ams_delta_keyboard.c	2009-12-10 14:50:47.000000000 +0100
@@ -0,0 +1,240 @@
+/*
+ *  Amstrad E3 (delta) keyboard driver
+ *
+ *  Copyright (c) 2006 Matt Callow
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * Thanks to Cliff Lawson for his help
+ *
+ * The Amstrad Delta keyboard (or mailboard) is connected to GPIO 0 (clock)
+ * and GPIO 1 (data). It uses normal PC-AT style serial transmission,
+ * but the data and clock lines are inverted on the E3 mainboard,
+ * and the scancodes produced are non-standard
+ *
+ * Due to the strict timing requirements of the interface,
+ * the serial data stream is read using a FIQ handler, and then
+ * the resulting byte stream passed to this driver via a circular buffer.
+ */
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+#include <asm/fiq.h>
+#include <plat/board-ams-delta.h>
+#include <mach/ams-delta-fiq.h>
+
+MODULE_AUTHOR("Matt Callow");
+MODULE_DESCRIPTION("AMS Delta (E3) Keyboard driver");
+MODULE_LICENSE("GPL");
+
+#define MAX_SCANCODE 0x84
+
+/*
+ * This table converts the amstrad mailboard scancodes to normal PC-AT scancodes
+ * The diagram below shows the amstrad keyboard, with the raw scancodes
+ *
+ *   (70) (7A) (46) (7C) (77)   Amstrad     (72) (69) (1A) (2A) (1C) (15)
+ * [  71][1:74][2:73][3:6B][4:22][5:1B][6:1D][7:1E][8:79][9:7D][0:75][  6C]
+ *  [Q:21][W:23][E:24][R:26][T:52][Y:5D][U:0D][I:0E][O:32][P:34]  |return|
+ *   [A:31][S:33][D:35][F:36][G:29][H:5B][J:03][K:76][L:3A][@:3B]  |   2C|
+ *  [  3C][Z:3D][X:4E][C:54][V:0B][B:05][N:41][M:42][.:43][  3E][  55]
+ *  [  83][  06][  49][           4B         ][,:44][  16][  2E][  09]
+ *
+ * These scancodes are then translated to AT scancodes using the following table
+ * The amstrad keyboard does not produce any extended scancodes, but we need to
+ * translate some amstrad scancodes to a AT extended scancode, hence the 16bit
+ * value for the translated scancode
+ *
+ * Translations for the non-obvious keys are:
+ * Store      -> Tab
+ * Setup      -> Caps Lock
+ * Service    -> Backslash
+ * Games      -> Left Alt
+ * Internet   -> Right Alt
+ * Home       -> Home
+ * Office     -> Page Up
+ * Mobile     -> Page Down
+ * Mobile Msg -> Insert
+ * Email      -> Delete
+ * Fax        -> End
+ * Stop       -> Esc
+ * Symbol     -> Left Ctrl
+ * Calc       -> Right Ctrl
+ * Address    -> Scroll Lock
+ */
+
+static unsigned short trans_table[MAX_SCANCODE] = {
+	0,      0,      0, 0x003B,      0, 0x0032, 0x007E,      0,  /* 00..07 */
+	0, 0xE074,      0, 0x002A,      0, 0x003C, 0x0043,      0,  /* 08..0F */
+	0,      0,      0,      0,      0, 0xE069, 0xE06B,      0,  /* 10..17 */
+	0,      0, 0xE07A, 0x002E, 0xE071, 0x0036, 0x003D,      0,  /* 18..1F */
+	0, 0x0015, 0x0025, 0x001D, 0x0024,      0, 0x002D,      0,  /* 20..27 */
+	0, 0x0034, 0xE070,      0, 0x005A,      0, 0xE072,      0,  /* 28..2F */
+	0, 0x001C, 0x0044, 0x001B, 0x004D, 0x0023, 0x002B,      0,  /* 30..37 */
+	0,      0, 0x004B, 0x0052, 0x0012, 0x001A, 0xE075,      0,  /* 38..3F */
+	0, 0x0031, 0x003A, 0x0049, 0x0041,      0, 0x0061,      0,  /* 40..47 */
+	0, 0x0014,      0, 0x0029,      0,      0, 0x0022,      0,  /* 48..4F */
+	0,      0, 0x002C,      0, 0x0021, 0x0059,      0,      0,  /* 50..57 */
+	0,      0,      0, 0x0033,      0, 0x0035,      0,      0,  /* 58..5F */
+	0,      0,      0,      0,      0,      0,      0,      0,  /* 60..67 */
+	0, 0xE07D,      0, 0x0026, 0x0066,      0,      0,      0,  /* 68..6F */
+   0x000D, 0x0076, 0xE06C, 0x001E, 0x0016, 0x0045, 0x0042, 0xE011,  /* 70..77 */
+	0, 0x003E, 0x0058,      0, 0x0011, 0x0046,      0,      0,  /* 78..7F */
+	0,      0,      0, 0xE014                                   /* 80..83 */
+};
+
+static struct serio *ams_delta_kbd_port;
+
+static int check_data(int data)
+{
+	int i;
+	int parity = 0;
+
+	/* check valid stop bit */
+	if (!(data & 0x400)) {
+		printk(KERN_WARNING
+				"Invalid stop bit in AMS keyboard"
+				" data=0x%X\r\n", data);
+		return 0;
+	}
+	/* calculate the parity */
+	for (i = 1; i < 10; i++) {
+		if (data & (1 << i))
+			parity++;
+	}
+	/* it should be odd */
+	if (!(parity & 0x01)) {
+		printk(KERN_WARNING
+				"Paritiy check failed in AMS keyboard "
+				" data=0x%X parity 0x%X\r\n", data, parity);
+	}
+	return 1;
+}
+
+static irqreturn_t ams_delta_kbd_interrupt(int irq, void *dev_id,
+		struct pt_regs *regs)
+{
+	int *circ_buff = &fiq_buffer[FIQ_CIRC_BUFF];
+	/*
+	 * Read data from the CIRC buffer, check it, translate the scancode
+	 * and then pass it on the serio
+	 */
+	fiq_buffer[FIQ_IRQ_PEND] = 0;
+
+	while (fiq_buffer[FIQ_CHAR_CNT] > 0) {
+		int data;
+		u8 original_scancode;
+		unsigned short translated_scancode;
+
+		data = circ_buff[fiq_buffer[FIQ_BACK_OFFSET]] ;
+		fiq_buffer[FIQ_BACK_OFFSET]++;
+		fiq_buffer[FIQ_CHAR_CNT]--;
+		if (fiq_buffer[FIQ_BACK_OFFSET] == fiq_buffer[FIQ_BUF_LEN])
+			fiq_buffer[FIQ_BACK_OFFSET] = 0;
+
+		if (check_data(data)) {
+			original_scancode = (u8) (data >> 1) & 0xFF;
+			if (original_scancode < MAX_SCANCODE) {
+				translated_scancode =
+						trans_table[original_scancode];
+				if ((translated_scancode & 0xff00) != 0) {
+					serio_interrupt(ams_delta_kbd_port,
+						translated_scancode >> 8, 0);
+				}
+				if ((translated_scancode & 0xff) != 0) {
+					serio_interrupt(ams_delta_kbd_port,
+						translated_scancode & 0xff, 0);
+				}
+			} else {
+				serio_interrupt(ams_delta_kbd_port,
+						original_scancode, 0);
+			}
+		}
+	}
+	return IRQ_HANDLED;
+}
+
+static struct serio * __init ams_delta_kbd_allocate_serio(void)
+{
+	struct serio *serio;
+
+	serio = kmalloc(sizeof(struct serio), GFP_KERNEL);
+	if (serio) {
+		memset(serio, 0, sizeof(struct serio));
+		serio->id.type = SERIO_8042;
+		strlcpy(serio->name, "AMS DELTA keyboard adapter",
+				sizeof(serio->name));
+		snprintf(serio->phys, sizeof(serio->phys), "%s/serio0", "GPIO");
+	}
+
+	return serio;
+}
+
+static int __init ams_delta_kbd_init(void)
+{
+	int err;
+
+	ams_delta_kbd_port = ams_delta_kbd_allocate_serio();
+	if (!ams_delta_kbd_port) {
+		err = -ENOMEM;
+		goto err;
+	}
+
+	if (gpio_request(AMS_DELTA_GPIO_PIN_KEYBRD_DATA, "kbd-data")) {
+		printk(KERN_ERR "Couldn't request gpio pin for keyboard data");
+		err = -EINVAL;
+		goto serio;
+	}
+	gpio_direction_input(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
+
+	if (gpio_request(AMS_DELTA_GPIO_PIN_KEYBRD_CLK, "kbd-clock")) {
+		printk(KERN_ERR "Couldn't request gpio pin for keyboard clock");
+		err = -EINVAL;
+		goto gpio_data;
+	}
+	gpio_direction_input(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
+
+	if (request_irq(OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK),
+		    ams_delta_kbd_interrupt, 0, "ams-delta-keyboard", 0) < 0) {
+		printk(KERN_ERR "Couldn't request gpio interrupt %d",
+				OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK));
+		err = -EINVAL;
+		goto gpio_clk;
+	}
+	set_irq_type(OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK),
+			IRQ_TYPE_EDGE_RISING);
+
+	/* enable keyboard */
+	ams_delta_latch2_write(AMD_DELTA_LATCH2_KEYBRD_PWR,
+			AMD_DELTA_LATCH2_KEYBRD_PWR);
+
+	serio_register_port(ams_delta_kbd_port);
+	printk(KERN_INFO "serio: AMS DELTA keyboard adapter\n");
+
+	return 0;
+gpio_clk:
+	gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
+gpio_data:
+	gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
+serio:
+	kfree(ams_delta_kbd_port);
+err:
+	return retval;
+}
+module_init(ams_delta_kbd_init);
+
+static void __exit ams_delta_kbd_exit(void)
+{
+	serio_unregister_port(ams_delta_kbd_port);
+	/* disable keyboard */
+	ams_delta_latch2_write(AMD_DELTA_LATCH2_KEYBRD_PWR, 0);
+	free_irq(OMAP_GPIO_IRQ(AMS_DELTA_GPIO_PIN_KEYBRD_CLK), 0);
+	gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_CLK);
+	gpio_free(AMS_DELTA_GPIO_PIN_KEYBRD_DATA);
+	kfree(ams_delta_kbd_port);
+}
+module_exit(ams_delta_kbd_exit);

  parent reply	other threads:[~2009-12-10 20:07 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-12-10 19:58 [RFC][PATCH 0/5] omap1: Amstrad Delta: add support for external keyboard Janusz Krzysztofik
2009-12-10 20:04 ` [RFC][PATCH 1/5] omap1: Amstrad Delta: add FIQ handler for serial keyboard port interrupt processing Janusz Krzysztofik
2009-12-10 20:05 ` [RFC][PATCH 2/5] omap1: Amstrad Delta: add a handler for processing interrupts generated by the FIQ routine Janusz Krzysztofik
2009-12-10 20:06 ` [RFC][PATCH 3/5] omap1: Amstrad Delta: use FIQ for processing MPU GPIO interrupts Janusz Krzysztofik
2009-12-10 20:07 ` Janusz Krzysztofik [this message]
2009-12-10 20:08 ` [RFC][PATCH 5/5] omap1: Amstrad Delta: modify defconfig for external keyboard support Janusz Krzysztofik
2009-12-11 14:39 ` [RFC][PATCH 0/5] omap1: Amstrad Delta: add support for external keyboard Janusz Krzysztofik
2009-12-11 14:39   ` Janusz Krzysztofik
2009-12-11 14:52   ` [RFC][PATCH 1/5] omap1: Amstrad Delta: add FIQ handler for serial keyboard port interrupt processing Janusz Krzysztofik
2009-12-11 14:52     ` Janusz Krzysztofik
2009-12-11 14:54   ` [RFC][PATCH 2/5] omap1: Amstrad Delta: add a handler for processing interrupts generated by the FIQ routine Janusz Krzysztofik
2009-12-11 14:54     ` Janusz Krzysztofik
2009-12-11  2:36 [RFC][PATCH 4/5] input: serio: add support for Amstrad Delta serial keyboard port Dmitry Torokhov
2009-12-11  3:09 ` Janusz Krzysztofik
2009-12-11  8:01   ` Dmitry Torokhov
2009-12-12 20:34     ` Janusz Krzysztofik
2009-12-12 23:20       ` Dmitry Torokhov
2009-12-14  0:11         ` Janusz Krzysztofik
2010-03-22 21:07           ` Janusz Krzysztofik
2010-03-24 16:16             ` Dmitry Torokhov
2010-03-24 21:21               ` Janusz Krzysztofik
2010-03-24 21:29                 ` Dmitry Torokhov
2010-03-25 13:58                   ` Janusz Krzysztofik

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=200912102107.52375.jkrzyszt@tis.icnet.pl \
    --to=jkrzyszt@tis.icnet.pl \
    --cc=dmitry.torokhov@gmail.com \
    --cc=linux-input@vger.kernel.org \
    --cc=linux-omap@vger.kernel.org \
    --cc=tony@atomide.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.