On Mon, Mar 29, 2010 at 04:30:41PM +0200, Janusz Krzysztofik wrote:
> 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.
> 
> Standard AT keyboard driver (atkbd) will be used on top of the serio layer 
> for 
> handling the E3 keyboard (called mailboard) connected to the port. Since the 
> device generated scancodes differ from what the atkbd expects, a custom key 
> code to scan code table must be loaded from userspace for the keyboard to be 
> useable.
> 
> Compiles and works on to of patch 3/5:
>       omap1: Amstrad Delta: use FIQ for processing GPIO interrupts
> 
> Created and tested against linux-2.6.34-rc2.
> 
> Signed-off-by: Janusz Krzysztofik <jkrzy...@tis.icnet.pl>
> ---
> v2 changes:
> - use correct variable name for return value in ams_delta_kbd_init(),
> - remove scan code to key code mapping,
> - refreshed against linux-2.6.34-rc2.
> 
>  drivers/input/serio/Kconfig              |    9 +
>  drivers/input/serio/Makefile             |    1
>  drivers/input/serio/ams_delta_keyboard.c |  171 
> +++++++++++++++++++++++++++++++
>  3 files changed, 181 insertions(+)
> 
> 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 <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

Not needed anymore?

> +
> +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);

Consider switching top dev_err(), dev_warning(), etc. Also do not split
text strings, even if you run over 80 column limit. BTW, why "\r\n" in
the message?

> +             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);

kzalloc() please.

> +     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");


strlcpy(serio->phys, "GPIO/serio0", sizeof(serio->phys)); ?

> +     }
> +
> +     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;

Why do you mangle return value of gpio_request()? Just return what it
reported. Same goes for request_irq() below.

> +             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);

This shoukd probably go into open() method of the serio port.

> +
> +     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);

And this into close().

> +     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);

Thanks.

-- 
Dmitry
--
To unsubscribe from this list: send the line "unsubscribe linux-omap" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to