Hi Alan, On Mon, Jan 21, 2013 at 11:45:58PM +0000, Alan Cox wrote: > From: Brian Swetland <swetland@xxxxxxxxxx> > > This device is a direct pipe from "hardware" to the input > event subsystem, allowing us to avoid having to route > "keypad" style events through an AT keyboard driver (gross!) > > As with the other submissions this driver is cross architecture. > > Signed-off-by: Mike A. Chan <mikechan@xxxxxxxxxx> > [Tided up to work on x86] > Signed-off-by: Sheng Yang <sheng@xxxxxxxxxxxxxxx> > Signed-off-by: Yunhong Jiang <yunhong.jiang@xxxxxxxxx> > Signed-off-by: Xiaohui Xin <xiaohui.xin@xxxxxxxxx> > Signed-off-by: Jun Nakajima <jun.nakajima@xxxxxxxxx> > Signed-off-by: Bruce Beare <bruce.j.beare@xxxxxxxxx> > [Ported to 3.4] > Signed-off-by: Tom Keel <thomas.keel@xxxxxxxxx> > [Cleaned up for 3.7 and submission] > Signed-off-by: Alan Cox <alan@xxxxxxxxxxxxxxx> > --- > > drivers/input/keyboard/Kconfig | 10 ++ > drivers/input/keyboard/Makefile | 1 > drivers/input/keyboard/goldfish_events.c | 187 ++++++++++++++++++++++++++++++ > drivers/tty/goldfish.c | 19 +-- > 4 files changed, 205 insertions(+), 12 deletions(-) > create mode 100644 drivers/input/keyboard/goldfish_events.c > > > diff --git a/drivers/input/keyboard/Kconfig b/drivers/input/keyboard/Kconfig > index 008f96a..07f7bb2 100644 > --- a/drivers/input/keyboard/Kconfig > +++ b/drivers/input/keyboard/Kconfig > @@ -482,6 +482,16 @@ config KEYBOARD_SAMSUNG > To compile this driver as a module, choose M here: the > module will be called samsung-keypad. > > +config KEYBOARD_GOLDFISH_EVENTS > + depends on GOLDFISH > + tristate "Generic Input Event device for Goldfish" > + help > + Say Y here to get an input event device for the Goldfish virtual > + device emulator. > + > + To compile this driver as a module, choose M here: the > + module will be called goldfish-events. > + > if TTY > > config KEYBOARD_STOWAWAY > diff --git a/drivers/input/keyboard/Makefile b/drivers/input/keyboard/Makefile > index 44e7600..49b1645 100644 > --- a/drivers/input/keyboard/Makefile > +++ b/drivers/input/keyboard/Makefile > @@ -13,6 +13,7 @@ obj-$(CONFIG_KEYBOARD_ATKBD) += atkbd.o > obj-$(CONFIG_KEYBOARD_BFIN) += bf54x-keys.o > obj-$(CONFIG_KEYBOARD_DAVINCI) += davinci_keyscan.o > obj-$(CONFIG_KEYBOARD_EP93XX) += ep93xx_keypad.o > +obj-$(CONFIG_KEYBOARD_GOLDFISH_EVENTS) += goldfish_events.o > obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o > obj-$(CONFIG_KEYBOARD_GPIO_POLLED) += gpio_keys_polled.o > obj-$(CONFIG_KEYBOARD_TCA6416) += tca6416-keypad.o > diff --git a/drivers/input/keyboard/goldfish_events.c b/drivers/input/keyboard/goldfish_events.c > new file mode 100644 > index 0000000..8b1f0cd > --- /dev/null > +++ b/drivers/input/keyboard/goldfish_events.c > @@ -0,0 +1,187 @@ > +/* > + * Copyright (C) 2007 Google, Inc. > + * Copyright (C) 2012 Intel, Inc. > + * > + * This software is licensed under the terms of the GNU General Public > + * License version 2, as published by the Free Software Foundation, and > + * may be copied, distributed, and modified under those terms. > + * > + * 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. > + * > + */ > + > +#include <linux/module.h> > +#include <linux/init.h> > +#include <linux/interrupt.h> > +#include <linux/types.h> > +#include <linux/input.h> > +#include <linux/kernel.h> > +#include <linux/platform_device.h> > +#include <linux/slab.h> > +#include <linux/irq.h> > +#include <linux/io.h> > + > +enum { > + REG_READ = 0x00, > + REG_SET_PAGE = 0x00, > + REG_LEN = 0x04, > + REG_DATA = 0x08, > + > + PAGE_NAME = 0x00000, > + PAGE_EVBITS = 0x10000, > + PAGE_ABSDATA = 0x20000 | EV_ABS, > +}; > + > +struct event_dev { > + struct input_dev *input; > + int irq; > + void __iomem *addr; > + char name[0]; > +}; > + > +static irqreturn_t events_interrupt(int irq, void *dev_id) > +{ > + struct event_dev *edev = dev_id; > + unsigned type, code, value; > + > + type = __raw_readl(edev->addr + REG_READ); > + code = __raw_readl(edev->addr + REG_READ); > + value = __raw_readl(edev->addr + REG_READ); > + > + input_event(edev->input, type, code, value); > + if (type == EV_KEY) > + input_sync(edev->input); Why do we send sync only for EV_KEY? > + return IRQ_HANDLED; > +} > + > +static void events_import_bits(struct event_dev *edev, > + unsigned long bits[], unsigned type, size_t count) > +{ > + int i, j; > + size_t size; > + uint8_t val; > + void __iomem *addr = edev->addr; > + __raw_writel(PAGE_EVBITS | type, addr + REG_SET_PAGE); > + size = __raw_readl(addr + REG_LEN) * 8; > + if (size < count) > + count = size; > + addr = addr + REG_DATA; > + for (i = 0; i < count; i += 8) { > + val = __raw_readb(addr++); > + for (j = 0; j < 8; j++) > + if (val & 1 << j) > + set_bit(i + j, bits); > + } > +} > + > +static int events_probe(struct platform_device *pdev) > +{ > + struct input_dev *input_dev; > + struct event_dev *edev = NULL; > + struct resource *res; > + unsigned keymapnamelen; > + int i; > + int count; > + int irq; > + void __iomem *addr; > + int ret; > + > + input_dev = input_allocate_device(); > + res = platform_get_resource(pdev, IORESOURCE_MEM, 0); > + if (!input_dev || !res) > + goto fail; > + > + addr = devm_ioremap(&pdev->dev, res->start, 4096); No need to reserve region? And why hardcoding the length? > + irq = platform_get_irq(pdev, 0); > + > + if (!addr || irq < 0) > + goto fail; > + > + __raw_writel(PAGE_NAME, addr + REG_SET_PAGE); > + keymapnamelen = __raw_readl(addr + REG_LEN); > + > + edev = devm_kzalloc(&pdev->dev, sizeof(struct event_dev) + keymapnamelen + 1, > + GFP_KERNEL); > + if (!edev) > + goto fail; > + > + edev->input = input_dev; > + edev->addr = addr; > + edev->irq = irq; > + > + for (i = 0; i < keymapnamelen; i++) > + edev->name[i] = __raw_readb(edev->addr + REG_DATA + i); > + > + pr_debug("events_probe() keymap=%s\n", edev->name); > + > + events_import_bits(edev, input_dev->evbit, EV_SYN, EV_MAX); > + events_import_bits(edev, input_dev->keybit, EV_KEY, KEY_MAX); > + events_import_bits(edev, input_dev->relbit, EV_REL, REL_MAX); > + events_import_bits(edev, input_dev->absbit, EV_ABS, ABS_MAX); > + events_import_bits(edev, input_dev->mscbit, EV_MSC, MSC_MAX); > + events_import_bits(edev, input_dev->ledbit, EV_LED, LED_MAX); > + events_import_bits(edev, input_dev->sndbit, EV_SND, SND_MAX); > + events_import_bits(edev, input_dev->ffbit, EV_FF, FF_MAX); > + events_import_bits(edev, input_dev->swbit, EV_SW, SW_MAX); > + > + __raw_writel(PAGE_ABSDATA, addr + REG_SET_PAGE); > + count = __raw_readl(addr + REG_LEN) / (4 * 4); > + if (count > ABS_MAX) > + count = ABS_MAX; > + for (i = 0; i < count; i++) { > + int val[4]; > + int j; > + if (!test_bit(i, input_dev->absbit)) > + continue; > + for (j = 0; j < ARRAY_SIZE(val); j++) > + val[j] = __raw_readl(edev->addr + REG_DATA + (i * ARRAY_SIZE(val) + j) * 4); > + input_set_abs_params(input_dev, i, val[0], val[1], > + val[2], val[3]); > + } > + > + platform_set_drvdata(pdev, edev); > + > + input_dev->name = edev->name; > + input_set_drvdata(input_dev, edev); > + > + ret = input_register_device(input_dev); > + if (ret) > + goto fail; > + > + if (devm_request_irq(&pdev->dev, edev->irq, events_interrupt, 0, > + "goldfish-events-keypad", edev) < 0) { > + input_unregister_device(input_dev); > + return -EINVAL; > + } > + > + return 0; > + > +fail: > + input_free_device(input_dev); > + return -EINVAL; > +} > + > +static int events_remove(struct platform_device *pdev) > +{ > + struct event_dev *edev = platform_get_drvdata(pdev); > + struct input_dev *input_dev = edev->input; > + input_unregister_device(input_dev); This will explode if interrupt arrives here. We now have devm_input_allocate_device(), please switch to using it and then we can get rid of events_remove() completely. > + return 0; > +} > + > +static struct platform_driver events_driver = { > + .probe = events_probe, > + .remove = events_remove, > + .driver = { > + .name = "goldfish_events", .owner = THIS_MODULE, Thanks. -- Dmitry -- To unsubscribe from this list: send the line "unsubscribe linux-input" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html