From patchwork Mon Mar 29 14:30:41 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Janusz Krzysztofik X-Patchwork-Id: 88977 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter.kernel.org (8.14.3/8.14.3) with ESMTP id o2TEV7gV022199 for ; Mon, 29 Mar 2010 14:31:07 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752748Ab0C2ObG (ORCPT ); Mon, 29 Mar 2010 10:31:06 -0400 Received: from d1.icnet.pl ([212.160.220.21]:45267 "EHLO d1.icnet.pl" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752696Ab0C2ObD (ORCPT ); Mon, 29 Mar 2010 10:31:03 -0400 Received: from 87-205-12-81.ip.netia.com.pl ([87.205.12.81] helo=vclass.intranet) by d1.icnet.pl with asmtp (TLS-1.0:DHE_RSA_AES_128_CBC_SHA:16) (Exim 4.34) id 1NwFza-0007YT-FY; Mon, 29 Mar 2010 16:31:02 +0200 From: Janusz Krzysztofik Organization: Tele-Info-System, Poznan, PL To: linux-input@vger.kernel.org Subject: [RFC][PATCH v2 4/5] input: serio: add support for Amstrad Delta serial keyboard port Date: Mon, 29 Mar 2010 16:30:41 +0200 User-Agent: KMail/1.9.10 Cc: linux-omap@vger.kernel.org, Tony Lindgren , Dmitry Torokhov , e3-hacking@earth.li References: <201003291619.25878.jkrzyszt@tis.icnet.pl> In-Reply-To: <201003291619.25878.jkrzyszt@tis.icnet.pl> MIME-Version: 1.0 Content-Disposition: inline Message-Id: <201003291630.43694.jkrzyszt@tis.icnet.pl> X-SA-Exim-Scanned: No (on d1.icnet); SAEximRunCond expanded to false Sender: linux-input-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-input@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.3 (demeter.kernel.org [140.211.167.41]); Mon, 29 Mar 2010 14:31:08 +0000 (UTC) diff -uprN git.orig/drivers/input/serio/Kconfig git/drivers/input/serio/Kconfig --- git.orig/drivers/input/serio/Kconfig 2010-03-25 15:55:42.000000000 +0100 +++ git/drivers/input/serio/Kconfig 2010-03-28 23:42:09.000000000 +0200 @@ -209,4 +209,13 @@ config SERIO_ALTERA_PS2 To compile this driver as a module, choose M here: the module will be called altera_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 2010-03-25 15:55:42.000000000 +0100 +++ git/drivers/input/serio/Makefile 2010-03-28 23:42:09.000000000 +0200 @@ -21,5 +21,6 @@ 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 obj-$(CONFIG_SERIO_ALTERA_PS2) += altera_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 2010-03-28 23:42:09.000000000 +0200 @@ -0,0 +1,171 @@ +/* + * 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 +#include +#include +#include +#include +#include +#include +#include + +MODULE_AUTHOR("Matt Callow"); +MODULE_DESCRIPTION("AMS Delta (E3) Keyboard driver"); +MODULE_LICENSE("GPL"); + +#define MAX_SCANCODE 0x84 + +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 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)) { + scancode = (u8) (data >> 1) & 0xFF; + serio_interrupt(ams_delta_kbd_port, 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 err; +} +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);