提交 6e5565f9 编写于 作者: L Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input: (34 commits)
  Input: i8042 - non-x86 build fix
  Input: pxa27x_keypad - also enable on PXA3xx
  Input: pxa27x_keypad - add debounce_interval to the keypad platform data
  Input: pxa27x_keypad - use device resources for I/O memory mapping and IRQ
  Input: pxa27x_keypad - enable rotary encoders and direct keys
  Input: pxa27x_keypad - introduce pxa27x_keypad_config()
  Input: pxa27x_keypad - introduce driver structure and use KEY() to define matrix keys
  Input: pxa27x_keypad - remove pin configuration from the driver
  Input: pxa27x_keypad - rename the driver (was pxa27x_keyboard)
  Input: constify function pointer tables (seq_operations)
  Input: i8042 - add Fujitsu-Siemens Amilo Pro 2010 to nomux list
  Input: i8042 - enable DMI quirks on x86-64
  Input: i8042 - add Dritek quirk for Acer Aspire 9110
  Input: add input event to APM event bridge
  Input: mousedev - use BIT_MASK instead of BIT
  Input: remove duplicate includes
  Input: remove cdev from input_dev structure
  Input: remove duplicated headers in drivers/char/keyboard.c
  Input: i8042 - add Dritek keyboard extension quirk
  Input: add Tosa keyboard driver
  ...
......@@ -22,7 +22,7 @@ static struct input_dev *button_dev;
static void button_interrupt(int irq, void *dummy, struct pt_regs *fp)
{
input_report_key(button_dev, BTN_1, inb(BUTTON_PORT) & 1);
input_report_key(button_dev, BTN_0, inb(BUTTON_PORT) & 1);
input_sync(button_dev);
}
......
......@@ -21,6 +21,8 @@
#include <linux/mmc/host.h>
#include <linux/pm.h>
#include <linux/delay.h>
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <asm/setup.h>
#include <asm/memory.h>
......@@ -246,6 +248,46 @@ static struct platform_device tosakbd_device = {
.id = -1,
};
static struct gpio_keys_button tosa_gpio_keys[] = {
{
.type = EV_PWR,
.code = KEY_SUSPEND,
.gpio = TOSA_GPIO_ON_KEY,
.desc = "On key",
.wakeup = 1,
.active_low = 1,
},
{
.type = EV_KEY,
.code = TOSA_KEY_RECORD,
.gpio = TOSA_GPIO_RECORD_BTN,
.desc = "Record Button",
.wakeup = 1,
.active_low = 1,
},
{
.type = EV_KEY,
.code = TOSA_KEY_SYNC,
.gpio = TOSA_GPIO_SYNC,
.desc = "Sync Button",
.wakeup = 1,
.active_low = 1,
},
};
static struct gpio_keys_platform_data tosa_gpio_keys_platform_data = {
.buttons = tosa_gpio_keys,
.nbuttons = ARRAY_SIZE(tosa_gpio_keys),
};
static struct platform_device tosa_gpio_keys_device = {
.name = "gpio-keys",
.id = -1,
.dev = {
.platform_data = &tosa_gpio_keys_platform_data,
},
};
/*
* Tosa LEDs
*/
......@@ -258,6 +300,7 @@ static struct platform_device *devices[] __initdata = {
&tosascoop_device,
&tosascoop_jc_device,
&tosakbd_device,
&tosa_gpio_keys_device,
&tosaled_device,
};
......
......@@ -38,7 +38,6 @@
#include <linux/kbd_kern.h>
#include <linux/kbd_diacr.h>
#include <linux/vt_kern.h>
#include <linux/consolemap.h>
#include <linux/sysrq.h>
#include <linux/input.h>
#include <linux/reboot.h>
......@@ -194,7 +193,7 @@ int getkeycode(unsigned int scancode)
int error = -ENODEV;
list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
error = handle->dev->getkeycode(handle->dev, scancode, &keycode);
error = input_get_keycode(handle->dev, scancode, &keycode);
if (!error)
return keycode;
}
......@@ -208,7 +207,7 @@ int setkeycode(unsigned int scancode, unsigned int keycode)
int error = -ENODEV;
list_for_each_entry(handle, &kbd_handler.h_list, h_node) {
error = handle->dev->setkeycode(handle->dev, scancode, keycode);
error = input_set_keycode(handle->dev, scancode, keycode);
if (!error)
break;
}
......
......@@ -137,6 +137,18 @@ config INPUT_EVBUG
To compile this driver as a module, choose M here: the
module will be called evbug.
config INPUT_APMPOWER
tristate "Input Power Event -> APM Bridge" if EMBEDDED
depends on INPUT && APM_EMULATION
---help---
Say Y here if you want suspend key events to trigger a user
requested suspend through APM. This is useful on embedded
systems where such behviour is desired without userspace
interaction. If unsure, say N.
To compile this driver as a module, choose M here: the
module will be called apm-power.
comment "Input Device Drivers"
source "drivers/input/keyboard/Kconfig"
......
......@@ -22,3 +22,4 @@ obj-$(CONFIG_INPUT_TABLET) += tablet/
obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/
obj-$(CONFIG_INPUT_MISC) += misc/
obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o
/*
* Input Power Event -> APM Bridge
*
* Copyright (c) 2007 Richard Purdie
*
* 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.
*
*/
#include <linux/module.h>
#include <linux/input.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/tty.h>
#include <linux/delay.h>
#include <linux/pm.h>
#include <linux/apm-emulation.h>
static void system_power_event(unsigned int keycode)
{
switch (keycode) {
case KEY_SUSPEND:
apm_queue_event(APM_USER_SUSPEND);
printk(KERN_INFO "apm-power: Requesting system suspend...\n");
break;
default:
break;
}
}
static void apmpower_event(struct input_handle *handle, unsigned int type,
unsigned int code, int value)
{
/* only react on key down events */
if (value != 1)
return;
switch (type) {
case EV_PWR:
system_power_event(code);
break;
default:
break;
}
}
static int apmpower_connect(struct input_handler *handler,
struct input_dev *dev,
const struct input_device_id *id)
{
struct input_handle *handle;
int error;
handle = kzalloc(sizeof(struct input_handle), GFP_KERNEL);
if (!handle)
return -ENOMEM;
handle->dev = dev;
handle->handler = handler;
handle->name = "apm-power";
handler->private = handle;
error = input_register_handle(handle);
if (error) {
printk(KERN_ERR
"apm-power: Failed to register input power handler, "
"error %d\n", error);
kfree(handle);
return error;
}
error = input_open_device(handle);
if (error) {
printk(KERN_ERR
"apm-power: Failed to open input power device, "
"error %d\n", error);
input_unregister_handle(handle);
kfree(handle);
return error;
}
return 0;
}
static void apmpower_disconnect(struct input_handle *handler)
{
struct input_handle *handle = handler->private;
input_close_device(handle);
kfree(handle);
}
static const struct input_device_id apmpower_ids[] = {
{
.flags = INPUT_DEVICE_ID_MATCH_EVBIT,
.evbit = { BIT_MASK(EV_PWR) },
},
{ },
};
MODULE_DEVICE_TABLE(input, apmpower_ids);
static struct input_handler apmpower_handler = {
.event = apmpower_event,
.connect = apmpower_connect,
.disconnect = apmpower_disconnect,
.name = "apm-power",
.id_table = apmpower_ids,
};
static int __init apmpower_init(void)
{
return input_register_handler(&apmpower_handler);
}
static void __exit apmpower_exit(void)
{
input_unregister_handler(&apmpower_handler);
}
module_init(apmpower_init);
module_exit(apmpower_exit);
MODULE_AUTHOR("Richard Purdie <rpurdie@rpsys.net>");
MODULE_DESCRIPTION("Input Power Event -> APM Bridge");
MODULE_LICENSE("GPL");
......@@ -617,7 +617,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
if (get_user(t, ip))
return -EFAULT;
error = dev->getkeycode(dev, t, &v);
error = input_get_keycode(dev, t, &v);
if (error)
return error;
......@@ -630,7 +630,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
if (get_user(t, ip) || get_user(v, ip + 1))
return -EFAULT;
return dev->setkeycode(dev, t, v);
return input_set_keycode(dev, t, v);
case EVIOCSFF:
if (copy_from_user(&effect, p, sizeof(effect)))
......@@ -683,7 +683,7 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
case EV_SW: bits = dev->swbit; len = SW_MAX; break;
default: return -EINVAL;
}
}
return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
}
......
......@@ -60,17 +60,21 @@ static void input_polled_device_work(struct work_struct *work)
{
struct input_polled_dev *dev =
container_of(work, struct input_polled_dev, work.work);
unsigned long delay;
dev->poll(dev);
queue_delayed_work(polldev_wq, &dev->work,
msecs_to_jiffies(dev->poll_interval));
delay = msecs_to_jiffies(dev->poll_interval);
if (delay >= HZ)
delay = round_jiffies_relative(delay);
queue_delayed_work(polldev_wq, &dev->work, delay);
}
static int input_open_polled_device(struct input_dev *input)
{
struct input_polled_dev *dev = input->private;
int error;
unsigned long ticks;
error = input_polldev_start_workqueue();
if (error)
......@@ -79,10 +83,8 @@ static int input_open_polled_device(struct input_dev *input)
if (dev->flush)
dev->flush(dev);
ticks = msecs_to_jiffies(dev->poll_interval);
if (ticks >= HZ)
ticks = round_jiffies(ticks);
queue_delayed_work(polldev_wq, &dev->work, ticks);
queue_delayed_work(polldev_wq, &dev->work,
msecs_to_jiffies(dev->poll_interval));
return 0;
}
......@@ -91,7 +93,7 @@ static void input_close_polled_device(struct input_dev *input)
{
struct input_polled_dev *dev = input->private;
cancel_rearming_delayed_workqueue(polldev_wq, &dev->work);
cancel_delayed_work_sync(&dev->work);
input_polldev_stop_workqueue();
}
......
......@@ -493,7 +493,7 @@ static void input_disconnect_device(struct input_dev *dev)
if (is_event_supported(EV_KEY, dev->evbit, EV_MAX)) {
for (code = 0; code <= KEY_MAX; code++) {
if (is_event_supported(code, dev->keybit, KEY_MAX) &&
test_bit(code, dev->key)) {
__test_and_clear_bit(code, dev->key)) {
input_pass_event(dev, EV_KEY, code, 0);
}
}
......@@ -526,7 +526,7 @@ static int input_default_getkeycode(struct input_dev *dev,
if (!dev->keycodesize)
return -EINVAL;
if (scancode < 0 || scancode >= dev->keycodemax)
if (scancode >= dev->keycodemax)
return -EINVAL;
*keycode = input_fetch_keycode(dev, scancode);
......@@ -540,10 +540,7 @@ static int input_default_setkeycode(struct input_dev *dev,
int old_keycode;
int i;
if (scancode < 0 || scancode >= dev->keycodemax)
return -EINVAL;
if (keycode < 0 || keycode > KEY_MAX)
if (scancode >= dev->keycodemax)
return -EINVAL;
if (!dev->keycodesize)
......@@ -586,6 +583,75 @@ static int input_default_setkeycode(struct input_dev *dev,
return 0;
}
/**
* input_get_keycode - retrieve keycode currently mapped to a given scancode
* @dev: input device which keymap is being queried
* @scancode: scancode (or its equivalent for device in question) for which
* keycode is needed
* @keycode: result
*
* This function should be called by anyone interested in retrieving current
* keymap. Presently keyboard and evdev handlers use it.
*/
int input_get_keycode(struct input_dev *dev, int scancode, int *keycode)
{
if (scancode < 0)
return -EINVAL;
return dev->getkeycode(dev, scancode, keycode);
}
EXPORT_SYMBOL(input_get_keycode);
/**
* input_get_keycode - assign new keycode to a given scancode
* @dev: input device which keymap is being updated
* @scancode: scancode (or its equivalent for device in question)
* @keycode: new keycode to be assigned to the scancode
*
* This function should be called by anyone needing to update current
* keymap. Presently keyboard and evdev handlers use it.
*/
int input_set_keycode(struct input_dev *dev, int scancode, int keycode)
{
unsigned long flags;
int old_keycode;
int retval;
if (scancode < 0)
return -EINVAL;
if (keycode < 0 || keycode > KEY_MAX)
return -EINVAL;
spin_lock_irqsave(&dev->event_lock, flags);
retval = dev->getkeycode(dev, scancode, &old_keycode);
if (retval)
goto out;
retval = dev->setkeycode(dev, scancode, keycode);
if (retval)
goto out;
/*
* Simulate keyup event if keycode is not present
* in the keymap anymore
*/
if (test_bit(EV_KEY, dev->evbit) &&
!is_event_supported(old_keycode, dev->keybit, KEY_MAX) &&
__test_and_clear_bit(old_keycode, dev->key)) {
input_pass_event(dev, EV_KEY, old_keycode, 0);
if (dev->sync)
input_pass_event(dev, EV_SYN, SYN_REPORT, 1);
}
out:
spin_unlock_irqrestore(&dev->event_lock, flags);
return retval;
}
EXPORT_SYMBOL(input_set_keycode);
#define MATCH_BIT(bit, max) \
for (i = 0; i < BITS_TO_LONGS(max); i++) \
......@@ -755,7 +821,7 @@ static int input_devices_seq_show(struct seq_file *seq, void *v)
return 0;
}
static struct seq_operations input_devices_seq_ops = {
static const struct seq_operations input_devices_seq_ops = {
.start = input_devices_seq_start,
.next = input_devices_seq_next,
.stop = input_devices_seq_stop,
......@@ -808,7 +874,7 @@ static int input_handlers_seq_show(struct seq_file *seq, void *v)
return 0;
}
static struct seq_operations input_handlers_seq_ops = {
static const struct seq_operations input_handlers_seq_ops = {
.start = input_handlers_seq_start,
.next = input_handlers_seq_next,
.stop = input_handlers_seq_stop,
......@@ -1329,9 +1395,6 @@ int input_register_device(struct input_dev *dev)
snprintf(dev->dev.bus_id, sizeof(dev->dev.bus_id),
"input%ld", (unsigned long) atomic_inc_return(&input_no) - 1);
if (dev->cdev.dev)
dev->dev.parent = dev->cdev.dev;
error = device_add(&dev->dev);
if (error)
return error;
......
......@@ -32,7 +32,6 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/interrupt.h>
......
......@@ -31,7 +31,6 @@
#include <linux/delay.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/bitops.h>
#include <linux/init.h>
......
......@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/parport.h>
......
......@@ -33,7 +33,6 @@
#include <linux/kernel.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/parport.h>
#include <linux/input.h>
......
......@@ -85,7 +85,7 @@ static struct iforce_device iforce_device[] = {
static int iforce_playback(struct input_dev *dev, int effect_id, int value)
{
struct iforce* iforce = dev->private;
struct iforce *iforce = input_get_drvdata(dev);
struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
if (value > 0)
......@@ -99,7 +99,7 @@ static int iforce_playback(struct input_dev *dev, int effect_id, int value)
static void iforce_set_gain(struct input_dev *dev, u16 gain)
{
struct iforce* iforce = dev->private;
struct iforce *iforce = input_get_drvdata(dev);
unsigned char data[3];
data[0] = gain >> 9;
......@@ -108,7 +108,7 @@ static void iforce_set_gain(struct input_dev *dev, u16 gain)
static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude)
{
struct iforce* iforce = dev->private;
struct iforce *iforce = input_get_drvdata(dev);
unsigned char data[3];
data[0] = 0x03;
......@@ -126,7 +126,7 @@ static void iforce_set_autocenter(struct input_dev *dev, u16 magnitude)
*/
static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect, struct ff_effect *old)
{
struct iforce* iforce = dev->private;
struct iforce *iforce = input_get_drvdata(dev);
struct iforce_core_effect *core_effect = &iforce->core_effects[effect->id];
int ret;
......@@ -173,7 +173,7 @@ static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect,
*/
static int iforce_erase_effect(struct input_dev *dev, int effect_id)
{
struct iforce *iforce = dev->private;
struct iforce *iforce = input_get_drvdata(dev);
struct iforce_core_effect *core_effect = &iforce->core_effects[effect_id];
int err = 0;
......@@ -191,7 +191,7 @@ static int iforce_erase_effect(struct input_dev *dev, int effect_id)
static int iforce_open(struct input_dev *dev)
{
struct iforce *iforce = dev->private;
struct iforce *iforce = input_get_drvdata(dev);
switch (iforce->bus) {
#ifdef CONFIG_JOYSTICK_IFORCE_USB
......@@ -213,7 +213,7 @@ static int iforce_open(struct input_dev *dev)
static void iforce_release(struct input_dev *dev)
{
struct iforce *iforce = dev->private;
struct iforce *iforce = input_get_drvdata(dev);
int i;
if (test_bit(EV_FF, dev->evbit)) {
......@@ -298,7 +298,8 @@ int iforce_init_device(struct iforce *iforce)
#endif
}
input_dev->private = iforce;
input_set_drvdata(input_dev, iforce);
input_dev->name = "Unknown I-Force device";
input_dev->open = iforce_open;
input_dev->close = iforce_release;
......
......@@ -35,7 +35,6 @@
#include <linux/parport.h>
#include <linux/input.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/mutex.h>
......
......@@ -75,7 +75,6 @@
#include <linux/slab.h>
#include <linux/stat.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/usb/input.h>
#define DRIVER_VERSION "v0.0.6"
......
......@@ -154,6 +154,27 @@ config KEYBOARD_SPITZ
To compile this driver as a module, choose M here: the
module will be called spitzkbd.
config KEYBOARD_TOSA
tristate "Tosa keyboard"
depends on MACH_TOSA
default y
help
Say Y here to enable the keyboard on the Sharp Zaurus SL-6000x (Tosa)
To compile this driver as a module, choose M here: the
module will be called tosakbd.
config KEYBOARD_TOSA_USE_EXT_KEYCODES
bool "Tosa keyboard: use extended keycodes"
depends on KEYBOARD_TOSA
default n
help
Say Y here to enable the tosa keyboard driver to generate extended
(>= 127) keycodes. Be aware, that they can't be correctly interpreted
by either console keyboard driver or by Kdrive keybd driver.
Say Y only if you know, what you are doing!
config KEYBOARD_AMIGA
tristate "Amiga keyboard"
depends on AMIGA
......@@ -239,13 +260,13 @@ config KEYBOARD_OMAP
module will be called omap-keypad.
config KEYBOARD_PXA27x
tristate "PXA27x keyboard support"
depends on PXA27x
tristate "PXA27x/PXA3xx keypad support"
depends on PXA27x || PXA3xx
help
Enable support for PXA27x matrix keyboard controller
Enable support for PXA27x/PXA3xx keypad controller
To compile this driver as a module, choose M here: the
module will be called pxa27x_keyboard.
module will be called pxa27x_keypad.
config KEYBOARD_AAED2000
tristate "AAED-2000 keyboard"
......
......@@ -15,10 +15,11 @@ obj-$(CONFIG_KEYBOARD_NEWTON) += newtonkbd.o
obj-$(CONFIG_KEYBOARD_STOWAWAY) += stowaway.o
obj-$(CONFIG_KEYBOARD_CORGI) += corgikbd.o
obj-$(CONFIG_KEYBOARD_SPITZ) += spitzkbd.o
obj-$(CONFIG_KEYBOARD_TOSA) += tosakbd.o
obj-$(CONFIG_KEYBOARD_HIL) += hil_kbd.o
obj-$(CONFIG_KEYBOARD_HIL_OLD) += hilkbd.o
obj-$(CONFIG_KEYBOARD_OMAP) += omap-keypad.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keyboard.o
obj-$(CONFIG_KEYBOARD_PXA27x) += pxa27x_keypad.o
obj-$(CONFIG_KEYBOARD_AAED2000) += aaed2000_kbd.o
obj-$(CONFIG_KEYBOARD_GPIO) += gpio_keys.o
obj-$(CONFIG_KEYBOARD_HP6XX) += jornada680_kbd.o
......
......@@ -19,7 +19,6 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/init.h>
......@@ -28,6 +27,7 @@
#include <linux/workqueue.h>
#include <linux/libps2.h>
#include <linux/mutex.h>
#include <linux/dmi.h>
#define DRIVER_DESC "AT and PS/2 keyboard driver"
......@@ -201,6 +201,7 @@ struct atkbd {
unsigned short id;
unsigned char keycode[512];
DECLARE_BITMAP(force_release_mask, 512);
unsigned char set;
unsigned char translated;
unsigned char extra;
......@@ -225,6 +226,11 @@ struct atkbd {
unsigned long event_mask;
};
/*
* System-specific ketymap fixup routine
*/
static void (*atkbd_platform_fixup)(struct atkbd *);
static ssize_t atkbd_attr_show_helper(struct device *dev, char *buf,
ssize_t (*handler)(struct atkbd *, char *));
static ssize_t atkbd_attr_set_helper(struct device *dev, const char *buf, size_t count,
......@@ -349,7 +355,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
struct atkbd *atkbd = serio_get_drvdata(serio);
struct input_dev *dev = atkbd->dev;
unsigned int code = data;
int scroll = 0, hscroll = 0, click = -1, add_release_event = 0;
int scroll = 0, hscroll = 0, click = -1;
int value;
unsigned char keycode;
......@@ -414,14 +420,6 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
"Some program might be trying access hardware directly.\n",
data == ATKBD_RET_ACK ? "ACK" : "NAK", serio->phys);
goto out;
case ATKBD_RET_HANGEUL:
case ATKBD_RET_HANJA:
/*
* These keys do not report release and thus need to be
* flagged properly
*/
add_release_event = 1;
break;
case ATKBD_RET_ERR:
atkbd->err_count++;
#ifdef ATKBD_DEBUG
......@@ -491,7 +489,7 @@ static irqreturn_t atkbd_interrupt(struct serio *serio, unsigned char data,
input_event(dev, EV_KEY, keycode, value);
input_sync(dev);
if (value && add_release_event) {
if (value && test_bit(code, atkbd->force_release_mask)) {
input_report_key(dev, keycode, 0);
input_sync(dev);
}
......@@ -824,7 +822,6 @@ static void atkbd_disconnect(struct serio *serio)
atkbd_disable(atkbd);
/* make sure we don't have a command in flight */
synchronize_sched(); /* Allow atkbd_interrupt()s to complete. */
flush_scheduled_work();
sysfs_remove_group(&serio->dev.kobj, &atkbd_attribute_group);
......@@ -834,6 +831,22 @@ static void atkbd_disconnect(struct serio *serio)
kfree(atkbd);
}
/*
* Most special keys (Fn+F?) on Dell Latitudes do not generate release
* events so we have to do it ourselves.
*/
static void atkbd_latitude_keymap_fixup(struct atkbd *atkbd)
{
const unsigned int forced_release_keys[] = {
0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93,
};
int i;
if (atkbd->set == 2)
for (i = 0; i < ARRAY_SIZE(forced_release_keys); i++)
__set_bit(forced_release_keys[i],
atkbd->force_release_mask);
}
/*
* atkbd_set_keycode_table() initializes keyboard's keycode table
......@@ -842,17 +855,20 @@ static void atkbd_disconnect(struct serio *serio)
static void atkbd_set_keycode_table(struct atkbd *atkbd)
{
unsigned int scancode;
int i, j;
memset(atkbd->keycode, 0, sizeof(atkbd->keycode));
bitmap_zero(atkbd->force_release_mask, 512);
if (atkbd->translated) {
for (i = 0; i < 128; i++) {
atkbd->keycode[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
atkbd->keycode[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
scancode = atkbd_unxlate_table[i];
atkbd->keycode[i] = atkbd_set2_keycode[scancode];
atkbd->keycode[i | 0x80] = atkbd_set2_keycode[scancode | 0x80];
if (atkbd->scroll)
for (j = 0; j < ARRAY_SIZE(atkbd_scroll_keys); j++)
if ((atkbd_unxlate_table[i] | 0x80) == atkbd_scroll_keys[j].set2)
if ((scancode | 0x80) == atkbd_scroll_keys[j].set2)
atkbd->keycode[i | 0x80] = atkbd_scroll_keys[j].keycode;
}
} else if (atkbd->set == 3) {
......@@ -861,12 +877,29 @@ static void atkbd_set_keycode_table(struct atkbd *atkbd)
memcpy(atkbd->keycode, atkbd_set2_keycode, sizeof(atkbd->keycode));
if (atkbd->scroll)
for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++)
atkbd->keycode[atkbd_scroll_keys[i].set2] = atkbd_scroll_keys[i].keycode;
for (i = 0; i < ARRAY_SIZE(atkbd_scroll_keys); i++) {
scancode = atkbd_scroll_keys[i].set2;
atkbd->keycode[scancode] = atkbd_scroll_keys[i].keycode;
}
}
atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL)] = KEY_HANGUEL;
atkbd->keycode[atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA)] = KEY_HANJA;
/*
* HANGEUL and HANJA keys do not send release events so we need to
* generate such events ourselves
*/
scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANGEUL);
atkbd->keycode[scancode] = KEY_HANGEUL;
__set_bit(scancode, atkbd->force_release_mask);
scancode = atkbd_compat_scancode(atkbd, ATKBD_RET_HANJA);
atkbd->keycode[scancode] = KEY_HANJA;
__set_bit(scancode, atkbd->force_release_mask);
/*
* Perform additional fixups
*/
if (atkbd_platform_fixup)
atkbd_platform_fixup(atkbd);
}
/*
......@@ -1401,9 +1434,29 @@ static ssize_t atkbd_show_err_count(struct atkbd *atkbd, char *buf)
return sprintf(buf, "%lu\n", atkbd->err_count);
}
static int __init atkbd_setup_fixup(const struct dmi_system_id *id)
{
atkbd_platform_fixup = id->driver_data;
return 0;
}
static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
{
.ident = "Dell Latitude series",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
},
.callback = atkbd_setup_fixup,
.driver_data = atkbd_latitude_keymap_fixup,
},
{ }
};
static int __init atkbd_init(void)
{
dmi_check_system(atkbd_dmi_quirk_table);
return serio_register_driver(&atkbd_drv);
}
......
......@@ -64,7 +64,6 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/input.h>
......
/*
* linux/drivers/input/keyboard/pxa27x_keyboard.c
*
* Driver for the pxa27x matrix keyboard controller.
*
* Created: Feb 22, 2007
* Author: Rodolfo Giometti <giometti@linux.it>
*
* Based on a previous implementations by Kevin O'Connor
* <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
* on some suggestions by Nicolas Pitre <nico@cam.org>.
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/arch/hardware.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/irqs.h>
#include <asm/arch/pxa27x_keyboard.h>
#define DRIVER_NAME "pxa27x-keyboard"
#define KPASMKP(col) (col/2 == 0 ? KPASMKP0 : \
col/2 == 1 ? KPASMKP1 : \
col/2 == 2 ? KPASMKP2 : KPASMKP3)
#define KPASMKPx_MKC(row, col) (1 << (row + 16 * (col % 2)))
static struct clk *pxakbd_clk;
static irqreturn_t pxakbd_irq_handler(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input_dev = platform_get_drvdata(pdev);
unsigned long kpc = KPC;
int p, row, col, rel;
if (kpc & KPC_DI) {
unsigned long kpdk = KPDK;
if (!(kpdk & KPDK_DKP)) {
/* better luck next time */
} else if (kpc & KPC_REE0) {
unsigned long kprec = KPREC;
KPREC = 0x7f;
if (kprec & KPREC_OF0)
rel = (kprec & 0xff) + 0x7f;
else if (kprec & KPREC_UF0)
rel = (kprec & 0xff) - 0x7f - 0xff;
else
rel = (kprec & 0xff) - 0x7f;
if (rel) {
input_report_rel(input_dev, REL_WHEEL, rel);
input_sync(input_dev);
}
}
}
if (kpc & KPC_MI) {
/* report the status of every button */
for (row = 0; row < pdata->nr_rows; row++) {
for (col = 0; col < pdata->nr_cols; col++) {
p = KPASMKP(col) & KPASMKPx_MKC(row, col) ?
1 : 0;
pr_debug("keycode %x - pressed %x\n",
pdata->keycodes[row][col], p);
input_report_key(input_dev,
pdata->keycodes[row][col], p);
}
}
input_sync(input_dev);
}
return IRQ_HANDLED;
}
static int pxakbd_open(struct input_dev *dev)
{
/* Set keypad control register */
KPC |= (KPC_ASACT |
KPC_MS_ALL |
(2 << 6) | KPC_REE0 | KPC_DK_DEB_SEL |
KPC_ME | KPC_MIE | KPC_DE | KPC_DIE);
KPC &= ~KPC_AS; /* disable automatic scan */
KPC &= ~KPC_IMKP; /* do not ignore multiple keypresses */
/* Set rotary count to mid-point value */
KPREC = 0x7F;
/* Enable unit clock */
clk_enable(pxakbd_clk);
return 0;
}
static void pxakbd_close(struct input_dev *dev)
{
/* Disable clock unit */
clk_disable(pxakbd_clk);
}
#ifdef CONFIG_PM
static int pxakbd_suspend(struct platform_device *pdev, pm_message_t state)
{
struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
/* Save controller status */
pdata->reg_kpc = KPC;
pdata->reg_kprec = KPREC;
return 0;
}
static int pxakbd_resume(struct platform_device *pdev)
{
struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input_dev = platform_get_drvdata(pdev);
mutex_lock(&input_dev->mutex);
if (input_dev->users) {
/* Restore controller status */
KPC = pdata->reg_kpc;
KPREC = pdata->reg_kprec;
/* Enable unit clock */
clk_disable(pxakbd_clk);
clk_enable(pxakbd_clk);
}
mutex_unlock(&input_dev->mutex);
return 0;
}
#else
#define pxakbd_suspend NULL
#define pxakbd_resume NULL
#endif
static int __devinit pxakbd_probe(struct platform_device *pdev)
{
struct pxa27x_keyboard_platform_data *pdata = pdev->dev.platform_data;
struct input_dev *input_dev;
int i, row, col, error;
pxakbd_clk = clk_get(&pdev->dev, "KBDCLK");
if (IS_ERR(pxakbd_clk)) {
error = PTR_ERR(pxakbd_clk);
goto err_clk;
}
/* Create and register the input driver. */
input_dev = input_allocate_device();
if (!input_dev) {
printk(KERN_ERR "Cannot request keypad device\n");
error = -ENOMEM;
goto err_alloc;
}
input_dev->name = DRIVER_NAME;
input_dev->id.bustype = BUS_HOST;
input_dev->open = pxakbd_open;
input_dev->close = pxakbd_close;
input_dev->dev.parent = &pdev->dev;
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
BIT_MASK(EV_REL);
input_dev->relbit[BIT_WORD(REL_WHEEL)] = BIT_MASK(REL_WHEEL);
for (row = 0; row < pdata->nr_rows; row++) {
for (col = 0; col < pdata->nr_cols; col++) {
int code = pdata->keycodes[row][col];
if (code > 0)
set_bit(code, input_dev->keybit);
}
}
error = request_irq(IRQ_KEYPAD, pxakbd_irq_handler, IRQF_DISABLED,
DRIVER_NAME, pdev);
if (error) {
printk(KERN_ERR "Cannot request keypad IRQ\n");
goto err_free_dev;
}
platform_set_drvdata(pdev, input_dev);
/* Register the input device */
error = input_register_device(input_dev);
if (error)
goto err_free_irq;
/* Setup GPIOs. */
for (i = 0; i < pdata->nr_rows + pdata->nr_cols; i++)
pxa_gpio_mode(pdata->gpio_modes[i]);
/*
* Store rows/cols info into keyboard registers.
*/
KPC |= (pdata->nr_rows - 1) << 26;
KPC |= (pdata->nr_cols - 1) << 23;
for (col = 0; col < pdata->nr_cols; col++)
KPC |= KPC_MS0 << col;
return 0;
err_free_irq:
platform_set_drvdata(pdev, NULL);
free_irq(IRQ_KEYPAD, pdev);
err_free_dev:
input_free_device(input_dev);
err_alloc:
clk_put(pxakbd_clk);
err_clk:
return error;
}
static int __devexit pxakbd_remove(struct platform_device *pdev)
{
struct input_dev *input_dev = platform_get_drvdata(pdev);
input_unregister_device(input_dev);
free_irq(IRQ_KEYPAD, pdev);
clk_put(pxakbd_clk);
platform_set_drvdata(pdev, NULL);
return 0;
}
static struct platform_driver pxakbd_driver = {
.probe = pxakbd_probe,
.remove = __devexit_p(pxakbd_remove),
.suspend = pxakbd_suspend,
.resume = pxakbd_resume,
.driver = {
.name = DRIVER_NAME,
},
};
static int __init pxakbd_init(void)
{
return platform_driver_register(&pxakbd_driver);
}
static void __exit pxakbd_exit(void)
{
platform_driver_unregister(&pxakbd_driver);
}
module_init(pxakbd_init);
module_exit(pxakbd_exit);
MODULE_DESCRIPTION("PXA27x Matrix Keyboard Driver");
MODULE_LICENSE("GPL");
/*
* linux/drivers/input/keyboard/pxa27x_keypad.c
*
* Driver for the pxa27x matrix keyboard controller.
*
* Created: Feb 22, 2007
* Author: Rodolfo Giometti <giometti@linux.it>
*
* Based on a previous implementations by Kevin O'Connor
* <kevin_at_koconnor.net> and Alex Osborne <bobofdoom@gmail.com> and
* on some suggestions by Nicolas Pitre <nico@cam.org>.
*
* 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.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/input.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#include <linux/clk.h>
#include <linux/err.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/arch/hardware.h>
#include <asm/arch/pxa27x_keypad.h>
/*
* Keypad Controller registers
*/
#define KPC 0x0000 /* Keypad Control register */
#define KPDK 0x0008 /* Keypad Direct Key register */
#define KPREC 0x0010 /* Keypad Rotary Encoder register */
#define KPMK 0x0018 /* Keypad Matrix Key register */
#define KPAS 0x0020 /* Keypad Automatic Scan register */
/* Keypad Automatic Scan Multiple Key Presser register 0-3 */
#define KPASMKP0 0x0028
#define KPASMKP1 0x0030
#define KPASMKP2 0x0038
#define KPASMKP3 0x0040
#define KPKDI 0x0048
/* bit definitions */
#define KPC_MKRN(n) ((((n) & 0x7) - 1) << 26) /* matrix key row number */
#define KPC_MKCN(n) ((((n) & 0x7) - 1) << 23) /* matrix key column number */
#define KPC_DKN(n) ((((n) & 0x7) - 1) << 6) /* direct key number */
#define KPC_AS (0x1 << 30) /* Automatic Scan bit */
#define KPC_ASACT (0x1 << 29) /* Automatic Scan on Activity */
#define KPC_MI (0x1 << 22) /* Matrix interrupt bit */
#define KPC_IMKP (0x1 << 21) /* Ignore Multiple Key Press */
#define KPC_MS(n) (0x1 << (13 + (n))) /* Matrix scan line 'n' */
#define KPC_MS_ALL (0xff << 13)
#define KPC_ME (0x1 << 12) /* Matrix Keypad Enable */
#define KPC_MIE (0x1 << 11) /* Matrix Interrupt Enable */
#define KPC_DK_DEB_SEL (0x1 << 9) /* Direct Keypad Debounce Select */
#define KPC_DI (0x1 << 5) /* Direct key interrupt bit */
#define KPC_RE_ZERO_DEB (0x1 << 4) /* Rotary Encoder Zero Debounce */
#define KPC_REE1 (0x1 << 3) /* Rotary Encoder1 Enable */
#define KPC_REE0 (0x1 << 2) /* Rotary Encoder0 Enable */
#define KPC_DE (0x1 << 1) /* Direct Keypad Enable */
#define KPC_DIE (0x1 << 0) /* Direct Keypad interrupt Enable */
#define KPDK_DKP (0x1 << 31)
#define KPDK_DK(n) ((n) & 0xff)
#define KPREC_OF1 (0x1 << 31)
#define kPREC_UF1 (0x1 << 30)
#define KPREC_OF0 (0x1 << 15)
#define KPREC_UF0 (0x1 << 14)
#define KPREC_RECOUNT0(n) ((n) & 0xff)
#define KPREC_RECOUNT1(n) (((n) >> 16) & 0xff)
#define KPMK_MKP (0x1 << 31)
#define KPAS_SO (0x1 << 31)
#define KPASMKPx_SO (0x1 << 31)
#define KPAS_MUKP(n) (((n) >> 26) & 0x1f)
#define KPAS_RP(n) (((n) >> 4) & 0xf)
#define KPAS_CP(n) ((n) & 0xf)
#define KPASMKP_MKC_MASK (0xff)
#define keypad_readl(off) __raw_readl(keypad->mmio_base + (off))
#define keypad_writel(off, v) __raw_writel((v), keypad->mmio_base + (off))
#define MAX_MATRIX_KEY_NUM (8 * 8)
struct pxa27x_keypad {
struct pxa27x_keypad_platform_data *pdata;
struct clk *clk;
struct input_dev *input_dev;
void __iomem *mmio_base;
/* matrix key code map */
unsigned int matrix_keycodes[MAX_MATRIX_KEY_NUM];
/* state row bits of each column scan */
uint32_t matrix_key_state[MAX_MATRIX_KEY_COLS];
uint32_t direct_key_state;
unsigned int direct_key_mask;
int rotary_rel_code[2];
int rotary_up_key[2];
int rotary_down_key[2];
};
static void pxa27x_keypad_build_keycode(struct pxa27x_keypad *keypad)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
struct input_dev *input_dev = keypad->input_dev;
unsigned int *key;
int i;
key = &pdata->matrix_key_map[0];
for (i = 0; i < pdata->matrix_key_map_size; i++, key++) {
int row = ((*key) >> 28) & 0xf;
int col = ((*key) >> 24) & 0xf;
int code = (*key) & 0xffffff;
keypad->matrix_keycodes[(row << 3) + col] = code;
set_bit(code, input_dev->keybit);
}
keypad->rotary_up_key[0] = pdata->rotary0_up_key;
keypad->rotary_up_key[1] = pdata->rotary1_up_key;
keypad->rotary_down_key[0] = pdata->rotary0_down_key;
keypad->rotary_down_key[1] = pdata->rotary1_down_key;
keypad->rotary_rel_code[0] = pdata->rotary0_rel_code;
keypad->rotary_rel_code[1] = pdata->rotary1_rel_code;
if (pdata->rotary0_up_key && pdata->rotary0_down_key) {
set_bit(pdata->rotary0_up_key, input_dev->keybit);
set_bit(pdata->rotary0_down_key, input_dev->keybit);
} else
set_bit(pdata->rotary0_rel_code, input_dev->relbit);
if (pdata->rotary1_up_key && pdata->rotary1_down_key) {
set_bit(pdata->rotary1_up_key, input_dev->keybit);
set_bit(pdata->rotary1_down_key, input_dev->keybit);
} else
set_bit(pdata->rotary1_rel_code, input_dev->relbit);
}
static inline unsigned int lookup_matrix_keycode(
struct pxa27x_keypad *keypad, int row, int col)
{
return keypad->matrix_keycodes[(row << 3) + col];
}
static void pxa27x_keypad_scan_matrix(struct pxa27x_keypad *keypad)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
int row, col, num_keys_pressed = 0;
uint32_t new_state[MAX_MATRIX_KEY_COLS];
uint32_t kpas = keypad_readl(KPAS);
num_keys_pressed = KPAS_MUKP(kpas);
memset(new_state, 0, sizeof(new_state));
if (num_keys_pressed == 0)
goto scan;
if (num_keys_pressed == 1) {
col = KPAS_CP(kpas);
row = KPAS_RP(kpas);
/* if invalid row/col, treat as no key pressed */
if (col >= pdata->matrix_key_cols ||
row >= pdata->matrix_key_rows)
goto scan;
new_state[col] = (1 << row);
goto scan;
}
if (num_keys_pressed > 1) {
uint32_t kpasmkp0 = keypad_readl(KPASMKP0);
uint32_t kpasmkp1 = keypad_readl(KPASMKP1);
uint32_t kpasmkp2 = keypad_readl(KPASMKP2);
uint32_t kpasmkp3 = keypad_readl(KPASMKP3);
new_state[0] = kpasmkp0 & KPASMKP_MKC_MASK;
new_state[1] = (kpasmkp0 >> 16) & KPASMKP_MKC_MASK;
new_state[2] = kpasmkp1 & KPASMKP_MKC_MASK;
new_state[3] = (kpasmkp1 >> 16) & KPASMKP_MKC_MASK;
new_state[4] = kpasmkp2 & KPASMKP_MKC_MASK;
new_state[5] = (kpasmkp2 >> 16) & KPASMKP_MKC_MASK;
new_state[6] = kpasmkp3 & KPASMKP_MKC_MASK;
new_state[7] = (kpasmkp3 >> 16) & KPASMKP_MKC_MASK;
}
scan:
for (col = 0; col < pdata->matrix_key_cols; col++) {
uint32_t bits_changed;
bits_changed = keypad->matrix_key_state[col] ^ new_state[col];
if (bits_changed == 0)
continue;
for (row = 0; row < pdata->matrix_key_rows; row++) {
if ((bits_changed & (1 << row)) == 0)
continue;
input_report_key(keypad->input_dev,
lookup_matrix_keycode(keypad, row, col),
new_state[col] & (1 << row));
}
}
input_sync(keypad->input_dev);
memcpy(keypad->matrix_key_state, new_state, sizeof(new_state));
}
#define DEFAULT_KPREC (0x007f007f)
static inline int rotary_delta(uint32_t kprec)
{
if (kprec & KPREC_OF0)
return (kprec & 0xff) + 0x7f;
else if (kprec & KPREC_UF0)
return (kprec & 0xff) - 0x7f - 0xff;
else
return (kprec & 0xff) - 0x7f;
}
static void report_rotary_event(struct pxa27x_keypad *keypad, int r, int delta)
{
struct input_dev *dev = keypad->input_dev;
if (delta == 0)
return;
if (keypad->rotary_up_key[r] && keypad->rotary_down_key[r]) {
int keycode = (delta > 0) ? keypad->rotary_up_key[r] :
keypad->rotary_down_key[r];
/* simulate a press-n-release */
input_report_key(dev, keycode, 1);
input_sync(dev);
input_report_key(dev, keycode, 0);
input_sync(dev);
} else {
input_report_rel(dev, keypad->rotary_rel_code[r], delta);
input_sync(dev);
}
}
static void pxa27x_keypad_scan_rotary(struct pxa27x_keypad *keypad)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
uint32_t kprec;
/* read and reset to default count value */
kprec = keypad_readl(KPREC);
keypad_writel(KPREC, DEFAULT_KPREC);
if (pdata->enable_rotary0)
report_rotary_event(keypad, 0, rotary_delta(kprec));
if (pdata->enable_rotary1)
report_rotary_event(keypad, 1, rotary_delta(kprec >> 16));
}
static void pxa27x_keypad_scan_direct(struct pxa27x_keypad *keypad)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
unsigned int new_state;
uint32_t kpdk, bits_changed;
int i;
kpdk = keypad_readl(KPDK);
if (pdata->enable_rotary0 || pdata->enable_rotary1)
pxa27x_keypad_scan_rotary(keypad);
if (pdata->direct_key_map == NULL)
return;
new_state = KPDK_DK(kpdk) & keypad->direct_key_mask;
bits_changed = keypad->direct_key_state ^ new_state;
if (bits_changed == 0)
return;
for (i = 0; i < pdata->direct_key_num; i++) {
if (bits_changed & (1 << i))
input_report_key(keypad->input_dev,
pdata->direct_key_map[i],
(new_state & (1 << i)));
}
input_sync(keypad->input_dev);
keypad->direct_key_state = new_state;
}
static irqreturn_t pxa27x_keypad_irq_handler(int irq, void *dev_id)
{
struct pxa27x_keypad *keypad = dev_id;
unsigned long kpc = keypad_readl(KPC);
if (kpc & KPC_DI)
pxa27x_keypad_scan_direct(keypad);
if (kpc & KPC_MI)
pxa27x_keypad_scan_matrix(keypad);
return IRQ_HANDLED;
}
static void pxa27x_keypad_config(struct pxa27x_keypad *keypad)
{
struct pxa27x_keypad_platform_data *pdata = keypad->pdata;
unsigned int mask = 0, direct_key_num = 0;
unsigned long kpc = 0;
/* enable matrix keys with automatic scan */
if (pdata->matrix_key_rows && pdata->matrix_key_cols) {
kpc |= KPC_ASACT | KPC_MIE | KPC_ME | KPC_MS_ALL;
kpc |= KPC_MKRN(pdata->matrix_key_rows) |
KPC_MKCN(pdata->matrix_key_cols);
}
/* enable rotary key, debounce interval same as direct keys */
if (pdata->enable_rotary0) {
mask |= 0x03;
direct_key_num = 2;
kpc |= KPC_REE0;
}
if (pdata->enable_rotary1) {
mask |= 0x0c;
direct_key_num = 4;
kpc |= KPC_REE1;
}
if (pdata->direct_key_num > direct_key_num)
direct_key_num = pdata->direct_key_num;
keypad->direct_key_mask = ((2 << direct_key_num) - 1) & ~mask;
/* enable direct key */
if (direct_key_num)
kpc |= KPC_DE | KPC_DIE | KPC_DKN(direct_key_num);
keypad_writel(KPC, kpc | KPC_RE_ZERO_DEB);
keypad_writel(KPREC, DEFAULT_KPREC);
keypad_writel(KPKDI, pdata->debounce_interval);
}
static int pxa27x_keypad_open(struct input_dev *dev)
{
struct pxa27x_keypad *keypad = input_get_drvdata(dev);
/* Enable unit clock */
clk_enable(keypad->clk);
pxa27x_keypad_config(keypad);
return 0;
}
static void pxa27x_keypad_close(struct input_dev *dev)
{
struct pxa27x_keypad *keypad = input_get_drvdata(dev);
/* Disable clock unit */
clk_disable(keypad->clk);
}
#ifdef CONFIG_PM
static int pxa27x_keypad_suspend(struct platform_device *pdev, pm_message_t state)
{
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
clk_disable(keypad->clk);
return 0;
}
static int pxa27x_keypad_resume(struct platform_device *pdev)
{
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
struct input_dev *input_dev = keypad->input_dev;
mutex_lock(&input_dev->mutex);
if (input_dev->users) {
/* Enable unit clock */
clk_enable(keypad->clk);
pxa27x_keypad_config(keypad);
}
mutex_unlock(&input_dev->mutex);
return 0;
}
#else
#define pxa27x_keypad_suspend NULL
#define pxa27x_keypad_resume NULL
#endif
#define res_size(res) ((res)->end - (res)->start + 1)
static int __devinit pxa27x_keypad_probe(struct platform_device *pdev)
{
struct pxa27x_keypad *keypad;
struct input_dev *input_dev;
struct resource *res;
int irq, error;
keypad = kzalloc(sizeof(struct pxa27x_keypad), GFP_KERNEL);
if (keypad == NULL) {
dev_err(&pdev->dev, "failed to allocate driver data\n");
return -ENOMEM;
}
keypad->pdata = pdev->dev.platform_data;
if (keypad->pdata == NULL) {
dev_err(&pdev->dev, "no platform data defined\n");
error = -EINVAL;
goto failed_free;
}
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
dev_err(&pdev->dev, "failed to get keypad irq\n");
error = -ENXIO;
goto failed_free;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (res == NULL) {
dev_err(&pdev->dev, "failed to get I/O memory\n");
error = -ENXIO;
goto failed_free;
}
res = request_mem_region(res->start, res_size(res), pdev->name);
if (res == NULL) {
dev_err(&pdev->dev, "failed to request I/O memory\n");
error = -EBUSY;
goto failed_free;
}
keypad->mmio_base = ioremap(res->start, res_size(res));
if (keypad->mmio_base == NULL) {
dev_err(&pdev->dev, "failed to remap I/O memory\n");
error = -ENXIO;
goto failed_free_mem;
}
keypad->clk = clk_get(&pdev->dev, "KBDCLK");
if (IS_ERR(keypad->clk)) {
dev_err(&pdev->dev, "failed to get keypad clock\n");
error = PTR_ERR(keypad->clk);
goto failed_free_io;
}
/* Create and register the input driver. */
input_dev = input_allocate_device();
if (!input_dev) {
dev_err(&pdev->dev, "failed to allocate input device\n");
error = -ENOMEM;
goto failed_put_clk;
}
input_dev->name = pdev->name;
input_dev->id.bustype = BUS_HOST;
input_dev->open = pxa27x_keypad_open;
input_dev->close = pxa27x_keypad_close;
input_dev->dev.parent = &pdev->dev;
keypad->input_dev = input_dev;
input_set_drvdata(input_dev, keypad);
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) |
BIT_MASK(EV_REL);
pxa27x_keypad_build_keycode(keypad);
platform_set_drvdata(pdev, keypad);
error = request_irq(irq, pxa27x_keypad_irq_handler, IRQF_DISABLED,
pdev->name, keypad);
if (error) {
dev_err(&pdev->dev, "failed to request IRQ\n");
goto failed_free_dev;
}
/* Register the input device */
error = input_register_device(input_dev);
if (error) {
dev_err(&pdev->dev, "failed to register input device\n");
goto failed_free_irq;
}
return 0;
failed_free_irq:
free_irq(irq, pdev);
platform_set_drvdata(pdev, NULL);
failed_free_dev:
input_free_device(input_dev);
failed_put_clk:
clk_put(keypad->clk);
failed_free_io:
iounmap(keypad->mmio_base);
failed_free_mem:
release_mem_region(res->start, res_size(res));
failed_free:
kfree(keypad);
return error;
}
static int __devexit pxa27x_keypad_remove(struct platform_device *pdev)
{
struct pxa27x_keypad *keypad = platform_get_drvdata(pdev);
struct resource *res;
free_irq(platform_get_irq(pdev, 0), pdev);
clk_disable(keypad->clk);
clk_put(keypad->clk);
input_unregister_device(keypad->input_dev);
input_free_device(keypad->input_dev);
iounmap(keypad->mmio_base);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
release_mem_region(res->start, res_size(res));
platform_set_drvdata(pdev, NULL);
kfree(keypad);
return 0;
}
static struct platform_driver pxa27x_keypad_driver = {
.probe = pxa27x_keypad_probe,
.remove = __devexit_p(pxa27x_keypad_remove),
.suspend = pxa27x_keypad_suspend,
.resume = pxa27x_keypad_resume,
.driver = {
.name = "pxa27x-keypad",
},
};
static int __init pxa27x_keypad_init(void)
{
return platform_driver_register(&pxa27x_keypad_driver);
}
static void __exit pxa27x_keypad_exit(void)
{
platform_driver_unregister(&pxa27x_keypad_driver);
}
module_init(pxa27x_keypad_init);
module_exit(pxa27x_keypad_exit);
MODULE_DESCRIPTION("PXA27x Keypad Controller Driver");
MODULE_LICENSE("GPL");
/*
* Keyboard driver for Sharp Tosa models (SL-6000x)
*
* Copyright (c) 2005 Dirk Opfer
* Copyright (c) 2007 Dmitry Baryshkov
*
* Based on xtkbd.c/locomkbd.c/corgikbd.c
*
* 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.
*
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/input.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <asm/arch/gpio.h>
#include <asm/arch/tosa.h>
#define KB_ROWMASK(r) (1 << (r))
#define SCANCODE(r, c) (((r)<<4) + (c) + 1)
#define NR_SCANCODES SCANCODE(TOSA_KEY_SENSE_NUM - 1, TOSA_KEY_STROBE_NUM - 1) + 1
#define SCAN_INTERVAL (HZ/10)
#define KB_DISCHARGE_DELAY 10
#define KB_ACTIVATE_DELAY 10
static unsigned int tosakbd_keycode[NR_SCANCODES] = {
0,
0, KEY_W, 0, 0, 0, KEY_K, KEY_BACKSPACE, KEY_P,
0, 0, 0, 0, 0, 0, 0, 0,
KEY_Q, KEY_E, KEY_T, KEY_Y, 0, KEY_O, KEY_I, KEY_COMMA,
0, 0, 0, 0, 0, 0, 0, 0,
KEY_A, KEY_D, KEY_G, KEY_U, 0, KEY_L, KEY_ENTER, KEY_DOT,
0, 0, 0, 0, 0, 0, 0, 0,
KEY_Z, KEY_C, KEY_V, KEY_J, TOSA_KEY_ADDRESSBOOK, TOSA_KEY_CANCEL, TOSA_KEY_CENTER, TOSA_KEY_OK,
KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, 0,
KEY_S, KEY_R, KEY_B, KEY_N, TOSA_KEY_CALENDAR, TOSA_KEY_HOMEPAGE, KEY_LEFTCTRL, TOSA_KEY_LIGHT,
0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0,
KEY_TAB, KEY_SLASH, KEY_H, KEY_M, TOSA_KEY_MENU, 0, KEY_UP, 0,
0, 0, TOSA_KEY_FN, 0, 0, 0, 0, 0,
KEY_X, KEY_F, KEY_SPACE, KEY_APOSTROPHE, TOSA_KEY_MAIL, KEY_LEFT, KEY_DOWN, KEY_RIGHT,
0, 0, 0,
};
struct tosakbd {
unsigned int keycode[ARRAY_SIZE(tosakbd_keycode)];
struct input_dev *input;
spinlock_t lock; /* protect kbd scanning */
struct timer_list timer;
};
/* Helper functions for reading the keyboard matrix
* Note: We should really be using pxa_gpio_mode to alter GPDR but it
* requires a function call per GPIO bit which is excessive
* when we need to access 12 bits at once, multiple times.
* These functions must be called within local_irq_save()/local_irq_restore()
* or similar.
*/
#define GET_ROWS_STATUS(c) ((GPLR2 & TOSA_GPIO_ALL_SENSE_BIT) >> TOSA_GPIO_ALL_SENSE_RSHIFT)
static inline void tosakbd_discharge_all(void)
{
/* STROBE All HiZ */
GPCR1 = TOSA_GPIO_HIGH_STROBE_BIT;
GPDR1 &= ~TOSA_GPIO_HIGH_STROBE_BIT;
GPCR2 = TOSA_GPIO_LOW_STROBE_BIT;
GPDR2 &= ~TOSA_GPIO_LOW_STROBE_BIT;
}
static inline void tosakbd_activate_all(void)
{
/* STROBE ALL -> High */
GPSR1 = TOSA_GPIO_HIGH_STROBE_BIT;
GPDR1 |= TOSA_GPIO_HIGH_STROBE_BIT;
GPSR2 = TOSA_GPIO_LOW_STROBE_BIT;
GPDR2 |= TOSA_GPIO_LOW_STROBE_BIT;
udelay(KB_DISCHARGE_DELAY);
/* STATE CLEAR */
GEDR2 |= TOSA_GPIO_ALL_SENSE_BIT;
}
static inline void tosakbd_activate_col(int col)
{
if (col <= 5) {
/* STROBE col -> High, not col -> HiZ */
GPSR1 = TOSA_GPIO_STROBE_BIT(col);
GPDR1 = (GPDR1 & ~TOSA_GPIO_HIGH_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
} else {
/* STROBE col -> High, not col -> HiZ */
GPSR2 = TOSA_GPIO_STROBE_BIT(col);
GPDR2 = (GPDR2 & ~TOSA_GPIO_LOW_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
}
}
static inline void tosakbd_reset_col(int col)
{
if (col <= 5) {
/* STROBE col -> Low */
GPCR1 = TOSA_GPIO_STROBE_BIT(col);
/* STROBE col -> out, not col -> HiZ */
GPDR1 = (GPDR1 & ~TOSA_GPIO_HIGH_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
} else {
/* STROBE col -> Low */
GPCR2 = TOSA_GPIO_STROBE_BIT(col);
/* STROBE col -> out, not col -> HiZ */
GPDR2 = (GPDR2 & ~TOSA_GPIO_LOW_STROBE_BIT) | TOSA_GPIO_STROBE_BIT(col);
}
}
/*
* The tosa keyboard only generates interrupts when a key is pressed.
* So when a key is pressed, we enable a timer. This timer scans the
* keyboard, and this is how we detect when the key is released.
*/
/* Scan the hardware keyboard and push any changes up through the input layer */
static void tosakbd_scankeyboard(struct platform_device *dev)
{
struct tosakbd *tosakbd = platform_get_drvdata(dev);
unsigned int row, col, rowd;
unsigned long flags;
unsigned int num_pressed = 0;
spin_lock_irqsave(&tosakbd->lock, flags);
for (col = 0; col < TOSA_KEY_STROBE_NUM; col++) {
/*
* Discharge the output driver capacitatance
* in the keyboard matrix. (Yes it is significant..)
*/
tosakbd_discharge_all();
udelay(KB_DISCHARGE_DELAY);
tosakbd_activate_col(col);
udelay(KB_ACTIVATE_DELAY);
rowd = GET_ROWS_STATUS(col);
for (row = 0; row < TOSA_KEY_SENSE_NUM; row++) {
unsigned int scancode, pressed;
scancode = SCANCODE(row, col);
pressed = rowd & KB_ROWMASK(row);
if (pressed && !tosakbd->keycode[scancode])
dev_warn(&dev->dev,
"unhandled scancode: 0x%02x\n",
scancode);
input_report_key(tosakbd->input,
tosakbd->keycode[scancode],
pressed);
if (pressed)
num_pressed++;
}
tosakbd_reset_col(col);
}
tosakbd_activate_all();
input_sync(tosakbd->input);
/* if any keys are pressed, enable the timer */
if (num_pressed)
mod_timer(&tosakbd->timer, jiffies + SCAN_INTERVAL);
spin_unlock_irqrestore(&tosakbd->lock, flags);
}
/*
* tosa keyboard interrupt handler.
*/
static irqreturn_t tosakbd_interrupt(int irq, void *__dev)
{
struct platform_device *dev = __dev;
struct tosakbd *tosakbd = platform_get_drvdata(dev);
if (!timer_pending(&tosakbd->timer)) {
/** wait chattering delay **/
udelay(20);
tosakbd_scankeyboard(dev);
}
return IRQ_HANDLED;
}
/*
* tosa timer checking for released keys
*/
static void tosakbd_timer_callback(unsigned long __dev)
{
struct platform_device *dev = (struct platform_device *)__dev;
tosakbd_scankeyboard(dev);
}
#ifdef CONFIG_PM
static int tosakbd_suspend(struct platform_device *dev, pm_message_t state)
{
struct tosakbd *tosakbd = platform_get_drvdata(dev);
del_timer_sync(&tosakbd->timer);
return 0;
}
static int tosakbd_resume(struct platform_device *dev)
{
tosakbd_scankeyboard(dev);
return 0;
}
#else
#define tosakbd_suspend NULL
#define tosakbd_resume NULL
#endif
static int __devinit tosakbd_probe(struct platform_device *pdev) {
int i;
struct tosakbd *tosakbd;
struct input_dev *input_dev;
int error;
tosakbd = kzalloc(sizeof(struct tosakbd), GFP_KERNEL);
if (!tosakbd)
return -ENOMEM;
input_dev = input_allocate_device();
if (!input_dev) {
kfree(tosakbd);
return -ENOMEM;
}
platform_set_drvdata(pdev, tosakbd);
spin_lock_init(&tosakbd->lock);
/* Init Keyboard rescan timer */
init_timer(&tosakbd->timer);
tosakbd->timer.function = tosakbd_timer_callback;
tosakbd->timer.data = (unsigned long) pdev;
tosakbd->input = input_dev;
input_set_drvdata(input_dev, tosakbd);
input_dev->name = "Tosa Keyboard";
input_dev->phys = "tosakbd/input0";
input_dev->dev.parent = &pdev->dev;
input_dev->id.bustype = BUS_HOST;
input_dev->id.vendor = 0x0001;
input_dev->id.product = 0x0001;
input_dev->id.version = 0x0100;
input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REP);
input_dev->keycode = tosakbd->keycode;
input_dev->keycodesize = sizeof(unsigned int);
input_dev->keycodemax = ARRAY_SIZE(tosakbd_keycode);
memcpy(tosakbd->keycode, tosakbd_keycode, sizeof(tosakbd_keycode));
for (i = 0; i < ARRAY_SIZE(tosakbd_keycode); i++)
__set_bit(tosakbd->keycode[i], input_dev->keybit);
clear_bit(0, input_dev->keybit);
/* Setup sense interrupts - RisingEdge Detect, sense lines as inputs */
for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) {
int gpio = TOSA_GPIO_KEY_SENSE(i);
int irq;
error = gpio_request(gpio, "tosakbd");
if (error < 0) {
printk(KERN_ERR "tosakbd: failed to request GPIO %d, "
" error %d\n", gpio, error);
goto fail;
}
error = gpio_direction_input(TOSA_GPIO_KEY_SENSE(i));
if (error < 0) {
printk(KERN_ERR "tosakbd: failed to configure input"
" direction for GPIO %d, error %d\n",
gpio, error);
gpio_free(gpio);
goto fail;
}
irq = gpio_to_irq(gpio);
if (irq < 0) {
error = irq;
printk(KERN_ERR "gpio-keys: Unable to get irq number"
" for GPIO %d, error %d\n",
gpio, error);
gpio_free(gpio);
goto fail;
}
error = request_irq(irq, tosakbd_interrupt,
IRQF_DISABLED | IRQF_TRIGGER_RISING,
"tosakbd", pdev);
if (error) {
printk("tosakbd: Can't get IRQ: %d: error %d!\n",
irq, error);
gpio_free(gpio);
goto fail;
}
}
/* Set Strobe lines as outputs - set high */
for (i = 0; i < TOSA_KEY_STROBE_NUM; i++) {
int gpio = TOSA_GPIO_KEY_STROBE(i);
error = gpio_request(gpio, "tosakbd");
if (error < 0) {
printk(KERN_ERR "tosakbd: failed to request GPIO %d, "
" error %d\n", gpio, error);
goto fail2;
}
error = gpio_direction_output(gpio, 1);
if (error < 0) {
printk(KERN_ERR "tosakbd: failed to configure input"
" direction for GPIO %d, error %d\n",
gpio, error);
gpio_free(gpio);
goto fail;
}
}
error = input_register_device(input_dev);
if (error) {
printk(KERN_ERR "tosakbd: Unable to register input device, "
"error: %d\n", error);
goto fail;
}
printk(KERN_INFO "input: Tosa Keyboard Registered\n");
return 0;
fail2:
while (--i >= 0)
gpio_free(TOSA_GPIO_KEY_STROBE(i));
i = TOSA_KEY_SENSE_NUM;
fail:
while (--i >= 0) {
free_irq(gpio_to_irq(TOSA_GPIO_KEY_SENSE(i)), pdev);
gpio_free(TOSA_GPIO_KEY_SENSE(i));
}
platform_set_drvdata(pdev, NULL);
input_free_device(input_dev);
kfree(tosakbd);
return error;
}
static int __devexit tosakbd_remove(struct platform_device *dev) {
int i;
struct tosakbd *tosakbd = platform_get_drvdata(dev);
for (i = 0; i < TOSA_KEY_STROBE_NUM; i++)
gpio_free(TOSA_GPIO_KEY_STROBE(i));
for (i = 0; i < TOSA_KEY_SENSE_NUM; i++) {
free_irq(gpio_to_irq(TOSA_GPIO_KEY_SENSE(i)), dev);
gpio_free(TOSA_GPIO_KEY_SENSE(i));
}
del_timer_sync(&tosakbd->timer);
input_unregister_device(tosakbd->input);
kfree(tosakbd);
return 0;
}
static struct platform_driver tosakbd_driver = {
.probe = tosakbd_probe,
.remove = __devexit_p(tosakbd_remove),
.suspend = tosakbd_suspend,
.resume = tosakbd_resume,
.driver = {
.name = "tosa-keyboard",
},
};
static int __devinit tosakbd_init(void)
{
return platform_driver_register(&tosakbd_driver);
}
static void __exit tosakbd_exit(void)
{
platform_driver_unregister(&tosakbd_driver);
}
module_init(tosakbd_init);
module_exit(tosakbd_exit);
MODULE_AUTHOR("Dirk Opfer <Dirk@Opfer-Online.de>");
MODULE_DESCRIPTION("Tosa Keyboard Driver");
MODULE_LICENSE("GPL v2");
......@@ -40,6 +40,20 @@ config INPUT_M68K_BEEP
tristate "M68k Beeper support"
depends on M68K
config INPUT_APANEL
tristate "Fujitsu Lifebook Application Panel buttons"
depends on X86
select I2C_I801
select INPUT_POLLDEV
select CHECK_SIGNATURE
help
Say Y here for support of the Application Panel buttons, used on
Fujitsu Lifebook. These are attached to the mainboard through
an SMBus interface managed by the I2C Intel ICH (i801) driver.
To compile this driver as a module, choose M here: the module will
be called apanel.
config INPUT_IXP4XX_BEEPER
tristate "IXP4XX Beeper support"
depends on ARCH_IXP4XX
......
......@@ -18,3 +18,4 @@ obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o
/*
* Fujitsu Lifebook Application Panel button drive
*
* Copyright (C) 2007 Stephen Hemminger <shemminger@linux-foundation.org>
* Copyright (C) 2001-2003 Jochen Eisinger <jochen@penguin-breeder.org>
*
* 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.
*
* Many Fujitsu Lifebook laptops have a small panel of buttons that are
* accessible via the i2c/smbus interface. This driver polls those
* buttons and generates input events.
*
* For more details see:
* http://apanel.sourceforge.net/tech.php
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/ioport.h>
#include <linux/io.h>
#include <linux/module.h>
#include <linux/input-polldev.h>
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <linux/leds.h>
#define APANEL_NAME "Fujitsu Application Panel"
#define APANEL_VERSION "1.3.1"
#define APANEL "apanel"
/* How often we poll keys - msecs */
#define POLL_INTERVAL_DEFAULT 1000
/* Magic constants in BIOS that tell about buttons */
enum apanel_devid {
APANEL_DEV_NONE = 0,
APANEL_DEV_APPBTN = 1,
APANEL_DEV_CDBTN = 2,
APANEL_DEV_LCD = 3,
APANEL_DEV_LED = 4,
APANEL_DEV_MAX,
};
enum apanel_chip {
CHIP_NONE = 0,
CHIP_OZ992C = 1,
CHIP_OZ163T = 2,
CHIP_OZ711M3 = 4,
};
/* Result of BIOS snooping/probing -- what features are supported */
static enum apanel_chip device_chip[APANEL_DEV_MAX];
#define MAX_PANEL_KEYS 12
struct apanel {
struct input_polled_dev *ipdev;
struct i2c_client client;
unsigned short keymap[MAX_PANEL_KEYS];
u16 nkeys;
u16 led_bits;
struct work_struct led_work;
struct led_classdev mail_led;
};
static int apanel_probe(struct i2c_adapter *, int, int);
/* for now, we only support one address */
static unsigned short normal_i2c[] = {0, I2C_CLIENT_END};
static unsigned short ignore = I2C_CLIENT_END;
static struct i2c_client_address_data addr_data = {
.normal_i2c = normal_i2c,
.probe = &ignore,
.ignore = &ignore,
};
static void report_key(struct input_dev *input, unsigned keycode)
{
pr_debug(APANEL ": report key %#x\n", keycode);
input_report_key(input, keycode, 1);
input_sync(input);
input_report_key(input, keycode, 0);
input_sync(input);
}
/* Poll for key changes
*
* Read Application keys via SMI
* A (0x4), B (0x8), Internet (0x2), Email (0x1).
*
* CD keys:
* Forward (0x100), Rewind (0x200), Stop (0x400), Pause (0x800)
*/
static void apanel_poll(struct input_polled_dev *ipdev)
{
struct apanel *ap = ipdev->private;
struct input_dev *idev = ipdev->input;
u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8;
s32 data;
int i;
data = i2c_smbus_read_word_data(&ap->client, cmd);
if (data < 0)
return; /* ignore errors (due to ACPI??) */
/* write back to clear latch */
i2c_smbus_write_word_data(&ap->client, cmd, 0);
if (!data)
return;
dev_dbg(&idev->dev, APANEL ": data %#x\n", data);
for (i = 0; i < idev->keycodemax; i++)
if ((1u << i) & data)
report_key(idev, ap->keymap[i]);
}
/* Track state changes of LED */
static void led_update(struct work_struct *work)
{
struct apanel *ap = container_of(work, struct apanel, led_work);
i2c_smbus_write_word_data(&ap->client, 0x10, ap->led_bits);
}
static void mail_led_set(struct led_classdev *led,
enum led_brightness value)
{
struct apanel *ap = container_of(led, struct apanel, mail_led);
if (value != LED_OFF)
ap->led_bits |= 0x8000;
else
ap->led_bits &= ~0x8000;
schedule_work(&ap->led_work);
}
static int apanel_detach_client(struct i2c_client *client)
{
struct apanel *ap = i2c_get_clientdata(client);
if (device_chip[APANEL_DEV_LED] != CHIP_NONE)
led_classdev_unregister(&ap->mail_led);
input_unregister_polled_device(ap->ipdev);
i2c_detach_client(&ap->client);
input_free_polled_device(ap->ipdev);
return 0;
}
/* Function is invoked for every i2c adapter. */
static int apanel_attach_adapter(struct i2c_adapter *adap)
{
dev_dbg(&adap->dev, APANEL ": attach adapter id=%d\n", adap->id);
/* Our device is connected only to i801 on laptop */
if (adap->id != I2C_HW_SMBUS_I801)
return -ENODEV;
return i2c_probe(adap, &addr_data, apanel_probe);
}
static void apanel_shutdown(struct i2c_client *client)
{
apanel_detach_client(client);
}
static struct i2c_driver apanel_driver = {
.driver = {
.name = APANEL,
},
.attach_adapter = &apanel_attach_adapter,
.detach_client = &apanel_detach_client,
.shutdown = &apanel_shutdown,
};
static struct apanel apanel = {
.client = {
.driver = &apanel_driver,
.name = APANEL,
},
.keymap = {
[0] = KEY_MAIL,
[1] = KEY_WWW,
[2] = KEY_PROG2,
[3] = KEY_PROG1,
[8] = KEY_FORWARD,
[9] = KEY_REWIND,
[10] = KEY_STOPCD,
[11] = KEY_PLAYPAUSE,
},
.mail_led = {
.name = "mail:blue",
.brightness_set = mail_led_set,
},
};
/* NB: Only one panel on the i2c. */
static int apanel_probe(struct i2c_adapter *bus, int address, int kind)
{
struct apanel *ap;
struct input_polled_dev *ipdev;
struct input_dev *idev;
u8 cmd = device_chip[APANEL_DEV_APPBTN] == CHIP_OZ992C ? 0 : 8;
int i, err = -ENOMEM;
dev_dbg(&bus->dev, APANEL ": probe adapter %p addr %d kind %d\n",
bus, address, kind);
ap = &apanel;
ipdev = input_allocate_polled_device();
if (!ipdev)
goto out1;
ap->ipdev = ipdev;
ap->client.adapter = bus;
ap->client.addr = address;
i2c_set_clientdata(&ap->client, ap);
err = i2c_attach_client(&ap->client);
if (err)
goto out2;
err = i2c_smbus_write_word_data(&ap->client, cmd, 0);
if (err) {
dev_warn(&ap->client.dev, APANEL ": smbus write error %d\n",
err);
goto out3;
}
ipdev->poll = apanel_poll;
ipdev->poll_interval = POLL_INTERVAL_DEFAULT;
ipdev->private = ap;
idev = ipdev->input;
idev->name = APANEL_NAME " buttons";
idev->phys = "apanel/input0";
idev->id.bustype = BUS_HOST;
idev->dev.parent = &ap->client.dev;
set_bit(EV_KEY, idev->evbit);
idev->keycode = ap->keymap;
idev->keycodesize = sizeof(ap->keymap[0]);
idev->keycodemax = (device_chip[APANEL_DEV_CDBTN] != CHIP_NONE) ? 12 : 4;
for (i = 0; i < idev->keycodemax; i++)
if (ap->keymap[i])
set_bit(ap->keymap[i], idev->keybit);
err = input_register_polled_device(ipdev);
if (err)
goto out3;
INIT_WORK(&ap->led_work, led_update);
if (device_chip[APANEL_DEV_LED] != CHIP_NONE) {
err = led_classdev_register(&ap->client.dev, &ap->mail_led);
if (err)
goto out4;
}
return 0;
out4:
input_unregister_polled_device(ipdev);
out3:
i2c_detach_client(&ap->client);
out2:
input_free_polled_device(ipdev);
out1:
return err;
}
/* Scan the system ROM for the signature "FJKEYINF" */
static __init const void __iomem *bios_signature(const void __iomem *bios)
{
ssize_t offset;
const unsigned char signature[] = "FJKEYINF";
for (offset = 0; offset < 0x10000; offset += 0x10) {
if (check_signature(bios + offset, signature,
sizeof(signature)-1))
return bios + offset;
}
pr_notice(APANEL ": Fujitsu BIOS signature '%s' not found...\n",
signature);
return NULL;
}
static int __init apanel_init(void)
{
void __iomem *bios;
const void __iomem *p;
u8 devno;
int found = 0;
bios = ioremap(0xF0000, 0x10000); /* Can't fail */
p = bios_signature(bios);
if (!p) {
iounmap(bios);
return -ENODEV;
}
/* just use the first address */
p += 8;
normal_i2c[0] = readb(p+3) >> 1;
for ( ; (devno = readb(p)) & 0x7f; p += 4) {
unsigned char method, slave, chip;
method = readb(p + 1);
chip = readb(p + 2);
slave = readb(p + 3) >> 1;
if (slave != normal_i2c[0]) {
pr_notice(APANEL ": only one SMBus slave "
"address supported, skiping device...\n");
continue;
}
/* translate alternative device numbers */
switch (devno) {
case 6:
devno = APANEL_DEV_APPBTN;
break;
case 7:
devno = APANEL_DEV_LED;
break;
}
if (devno >= APANEL_DEV_MAX)
pr_notice(APANEL ": unknown device %u found\n", devno);
else if (device_chip[devno] != CHIP_NONE)
pr_warning(APANEL ": duplicate entry for devno %u\n", devno);
else if (method != 1 && method != 2 && method != 4) {
pr_notice(APANEL ": unknown method %u for devno %u\n",
method, devno);
} else {
device_chip[devno] = (enum apanel_chip) chip;
++found;
}
}
iounmap(bios);
if (found == 0) {
pr_info(APANEL ": no input devices reported by BIOS\n");
return -EIO;
}
return i2c_add_driver(&apanel_driver);
}
module_init(apanel_init);
static void __exit apanel_cleanup(void)
{
i2c_del_driver(&apanel_driver);
}
module_exit(apanel_cleanup);
MODULE_AUTHOR("Stephen Hemminger <shemminger@linux-foundation.org>");
MODULE_DESCRIPTION(APANEL_NAME " driver");
MODULE_LICENSE("GPL");
MODULE_VERSION(APANEL_VERSION);
MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifeBook*:pvr*:rvnFUJITSU:*");
MODULE_ALIAS("dmi:*:svnFUJITSU:pnLifebook*:pvr*:rvnFUJITSU:*");
......@@ -90,7 +90,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/usb/input.h>
#include <linux/wait.h>
#include <linux/jiffies.h>
......
......@@ -29,9 +29,10 @@
#include <asm/uaccess.h>
#include <acpi/acpi_drivers.h>
#define ACPI_ATLAS_NAME "Atlas ACPI"
#define ACPI_ATLAS_CLASS "Atlas"
#define ACPI_ATLAS_NAME "Atlas ACPI"
#define ACPI_ATLAS_CLASS "Atlas"
static unsigned short atlas_keymap[16];
static struct input_dev *input_dev;
/* button handling code */
......@@ -50,12 +51,15 @@ static acpi_status acpi_atlas_button_handler(u32 function,
void *handler_context, void *region_context)
{
acpi_status status;
int keycode;
if (function == ACPI_WRITE) {
keycode = KEY_F1 + (address & 0x0F);
input_report_key(input_dev, keycode, !(address & 0x10));
int code = address & 0x0f;
int key_down = !(address & 0x10);
input_event(input_dev, EV_MSC, MSC_SCAN, code);
input_report_key(input_dev, atlas_keymap[code], key_down);
input_sync(input_dev);
status = 0;
} else {
printk(KERN_WARNING "atlas: shrugged on unexpected function"
......@@ -70,6 +74,7 @@ static acpi_status acpi_atlas_button_handler(u32 function,
static int atlas_acpi_button_add(struct acpi_device *device)
{
acpi_status status;
int i;
int err;
input_dev = input_allocate_device();
......@@ -81,17 +86,19 @@ static int atlas_acpi_button_add(struct acpi_device *device)
input_dev->name = "Atlas ACPI button driver";
input_dev->phys = "ASIM0000/atlas/input0";
input_dev->id.bustype = BUS_HOST;
input_dev->evbit[BIT_WORD(EV_KEY)] = BIT_MASK(EV_KEY);
set_bit(KEY_F1, input_dev->keybit);
set_bit(KEY_F2, input_dev->keybit);
set_bit(KEY_F3, input_dev->keybit);
set_bit(KEY_F4, input_dev->keybit);
set_bit(KEY_F5, input_dev->keybit);
set_bit(KEY_F6, input_dev->keybit);
set_bit(KEY_F7, input_dev->keybit);
set_bit(KEY_F8, input_dev->keybit);
set_bit(KEY_F9, input_dev->keybit);
input_dev->keycode = atlas_keymap;
input_dev->keycodesize = sizeof(unsigned short);
input_dev->keycodemax = ARRAY_SIZE(atlas_keymap);
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
__set_bit(EV_KEY, input_dev->evbit);
for (i = 0; i < ARRAY_SIZE(atlas_keymap); i++) {
if (i < 9) {
atlas_keymap[i] = KEY_F1 + i;
__set_bit(KEY_F1 + i, input_dev->keybit);
} else
atlas_keymap[i] = KEY_RESERVED;
}
err = input_register_device(input_dev);
if (err) {
......
......@@ -27,55 +27,48 @@
#define BUTTONS_COUNT_THRESHOLD 3
#define BUTTONS_STATUS_MASK 0xfe000000
static const unsigned short cobalt_map[] = {
KEY_RESERVED,
KEY_RESTART,
KEY_LEFT,
KEY_UP,
KEY_DOWN,
KEY_RIGHT,
KEY_ENTER,
KEY_SELECT
};
struct buttons_dev {
struct input_polled_dev *poll_dev;
unsigned short keymap[ARRAY_SIZE(cobalt_map)];
int count[ARRAY_SIZE(cobalt_map)];
void __iomem *reg;
};
struct buttons_map {
uint32_t mask;
int keycode;
int count;
};
static struct buttons_map buttons_map[] = {
{ 0x02000000, KEY_RESTART, },
{ 0x04000000, KEY_LEFT, },
{ 0x08000000, KEY_UP, },
{ 0x10000000, KEY_DOWN, },
{ 0x20000000, KEY_RIGHT, },
{ 0x40000000, KEY_ENTER, },
{ 0x80000000, KEY_SELECT, },
};
static void handle_buttons(struct input_polled_dev *dev)
{
struct buttons_map *button = buttons_map;
struct buttons_dev *bdev = dev->private;
struct input_dev *input = dev->input;
uint32_t status;
int i;
status = readl(bdev->reg);
status = ~status & BUTTONS_STATUS_MASK;
status = ~readl(bdev->reg) >> 24;
for (i = 0; i < ARRAY_SIZE(buttons_map); i++) {
if (status & button->mask) {
button->count++;
for (i = 0; i < ARRAY_SIZE(bdev->keymap); i++) {
if (status & (1UL << i)) {
if (++bdev->count[i] == BUTTONS_COUNT_THRESHOLD) {
input_event(input, EV_MSC, MSC_SCAN, i);
input_report_key(input, bdev->keymap[i], 1);
input_sync(input);
}
} else {
if (button->count >= BUTTONS_COUNT_THRESHOLD) {
input_report_key(input, button->keycode, 0);
if (bdev->count[i] >= BUTTONS_COUNT_THRESHOLD) {
input_event(input, EV_MSC, MSC_SCAN, i);
input_report_key(input, bdev->keymap[i], 0);
input_sync(input);
}
button->count = 0;
}
if (button->count == BUTTONS_COUNT_THRESHOLD) {
input_report_key(input, button->keycode, 1);
input_sync(input);
bdev->count[i] = 0;
}
button++;
}
}
......@@ -94,6 +87,8 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
goto err_free_mem;
}
memcpy(bdev->keymap, cobalt_map, sizeof(bdev->keymap));
poll_dev->private = bdev;
poll_dev->poll = handle_buttons;
poll_dev->poll_interval = BUTTONS_POLL_INTERVAL;
......@@ -104,11 +99,15 @@ static int __devinit cobalt_buttons_probe(struct platform_device *pdev)
input->id.bustype = BUS_HOST;
input->cdev.dev = &pdev->dev;
input->evbit[0] = BIT_MASK(EV_KEY);
for (i = 0; i < ARRAY_SIZE(buttons_map); i++) {
set_bit(buttons_map[i].keycode, input->keybit);
buttons_map[i].count = 0;
}
input->keycode = pdev->keymap;
input->keycodemax = ARRAY_SIZE(pdev->keymap);
input->keycodesize = sizeof(unsigned short);
input_set_capability(input, EV_MSC, MSC_SCAN);
__set_bit(EV_KEY, input->evbit);
for (i = 0; i < ARRAY_SIZE(buttons_map); i++)
__set_bit(input->keycode[i], input->keybit);
__clear_bit(KEY_RESERVED, input->keybit);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
if (!res) {
......
......@@ -16,7 +16,6 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/usb/input.h>
#define DRIVER_VERSION "v0.1"
......@@ -46,53 +45,12 @@ MODULE_PARM_DESC(debug, "Enable extra debug messages and information");
#define RECV_SIZE 8 /* The UIA-11 type have a 8 byte limit. */
/* table of devices that work with this driver */
static struct usb_device_id keyspan_table[] = {
{ USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) },
{ } /* Terminating entry */
};
/* Structure to store all the real stuff that a remote sends to us. */
struct keyspan_message {
u16 system;
u8 button;
u8 toggle;
};
/* Structure used for all the bit testing magic needed to be done. */
struct bit_tester {
u32 tester;
int len;
int pos;
int bits_left;
u8 buffer[32];
};
/* Structure to hold all of our driver specific stuff */
struct usb_keyspan {
char name[128];
char phys[64];
struct usb_device* udev;
struct input_dev *input;
struct usb_interface* interface;
struct usb_endpoint_descriptor* in_endpoint;
struct urb* irq_urb;
int open;
dma_addr_t in_dma;
unsigned char* in_buffer;
/* variables used to parse messages from remote. */
struct bit_tester data;
int stage;
int toggle;
};
/*
* Table that maps the 31 possible keycodes to input keys.
* Currently there are 15 and 17 button models so RESERVED codes
* are blank areas in the mapping.
*/
static const int keyspan_key_table[] = {
static const unsigned short keyspan_key_table[] = {
KEY_RESERVED, /* 0 is just a place holder. */
KEY_RESERVED,
KEY_STOP,
......@@ -127,6 +85,48 @@ static const int keyspan_key_table[] = {
KEY_MENU
};
/* table of devices that work with this driver */
static struct usb_device_id keyspan_table[] = {
{ USB_DEVICE(USB_KEYSPAN_VENDOR_ID, USB_KEYSPAN_PRODUCT_UIA11) },
{ } /* Terminating entry */
};
/* Structure to store all the real stuff that a remote sends to us. */
struct keyspan_message {
u16 system;
u8 button;
u8 toggle;
};
/* Structure used for all the bit testing magic needed to be done. */
struct bit_tester {
u32 tester;
int len;
int pos;
int bits_left;
u8 buffer[32];
};
/* Structure to hold all of our driver specific stuff */
struct usb_keyspan {
char name[128];
char phys[64];
unsigned short keymap[ARRAY_SIZE(keyspan_key_table)];
struct usb_device *udev;
struct input_dev *input;
struct usb_interface *interface;
struct usb_endpoint_descriptor *in_endpoint;
struct urb* irq_urb;
int open;
dma_addr_t in_dma;
unsigned char *in_buffer;
/* variables used to parse messages from remote. */
struct bit_tester data;
int stage;
int toggle;
};
static struct usb_driver keyspan_driver;
/*
......@@ -173,6 +173,15 @@ static int keyspan_load_tester(struct usb_keyspan* dev, int bits_needed)
return 0;
}
static void keyspan_report_button(struct usb_keyspan *remote, int button, int press)
{
struct input_dev *input = remote->input;
input_event(input, EV_MSC, MSC_SCAN, button);
input_report_key(input, remote->keymap[button], press);
input_sync(input);
}
/*
* Routine that handles all the logic needed to parse out the message from the remote.
*/
......@@ -311,9 +320,8 @@ static void keyspan_check_data(struct usb_keyspan *remote)
__FUNCTION__, message.system, message.button, message.toggle);
if (message.toggle != remote->toggle) {
input_report_key(remote->input, keyspan_key_table[message.button], 1);
input_report_key(remote->input, keyspan_key_table[message.button], 0);
input_sync(remote->input);
keyspan_report_button(remote, message.button, 1);
keyspan_report_button(remote, message.button, 0);
remote->toggle = message.toggle;
}
......@@ -491,16 +499,21 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
usb_make_path(udev, remote->phys, sizeof(remote->phys));
strlcat(remote->phys, "/input0", sizeof(remote->phys));
memcpy(remote->keymap, keyspan_key_table, sizeof(remote->keymap));
input_dev->name = remote->name;
input_dev->phys = remote->phys;
usb_to_input_id(udev, &input_dev->id);
input_dev->dev.parent = &interface->dev;
input_dev->keycode = remote->keymap;
input_dev->keycodesize = sizeof(unsigned short);
input_dev->keycodemax = ARRAY_SIZE(remote->keymap);
input_dev->evbit[0] = BIT_MASK(EV_KEY); /* We will only report KEY events. */
input_set_capability(input_dev, EV_MSC, MSC_SCAN);
__set_bit(EV_KEY, input_dev->evbit);
for (i = 0; i < ARRAY_SIZE(keyspan_key_table); i++)
if (keyspan_key_table[i] != KEY_RESERVED)
set_bit(keyspan_key_table[i], input_dev->keybit);
__set_bit(keyspan_key_table[i], input_dev->keybit);
__clear_bit(KEY_RESERVED, input_dev->keybit);
input_set_drvdata(input_dev, remote);
......@@ -508,12 +521,14 @@ static int keyspan_probe(struct usb_interface *interface, const struct usb_devic
input_dev->close = keyspan_close;
/*
* Initialize the URB to access the device. The urb gets sent to the device in keyspan_open()
* Initialize the URB to access the device.
* The urb gets sent to the device in keyspan_open()
*/
usb_fill_int_urb(remote->irq_urb,
remote->udev, usb_rcvintpipe(remote->udev, remote->in_endpoint->bEndpointAddress),
remote->udev,
usb_rcvintpipe(remote->udev, endpoint->bEndpointAddress),
remote->in_buffer, RECV_SIZE, keyspan_irq_recv, remote,
remote->in_endpoint->bInterval);
endpoint->bInterval);
remote->irq_urb->transfer_dma = remote->in_dma;
remote->irq_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
......
......@@ -35,7 +35,6 @@
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/interrupt.h>
......
......@@ -36,7 +36,6 @@
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/delay.h>
#include <linux/ioport.h>
#include <linux/init.h>
......
......@@ -13,7 +13,6 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
......
......@@ -11,7 +11,6 @@
#include <linux/delay.h>
#include <linux/serio.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/input.h>
#include <linux/libps2.h>
#include <linux/proc_fs.h>
......
......@@ -16,7 +16,6 @@
#include <linux/slab.h>
#include <linux/poll.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/input.h>
#include <linux/random.h>
......@@ -1033,7 +1032,7 @@ static const struct input_device_id mousedev_ids[] = {
.flags = INPUT_DEVICE_ID_MATCH_EVBIT |
INPUT_DEVICE_ID_MATCH_KEYBIT |
INPUT_DEVICE_ID_MATCH_ABSBIT,
.evbit = { BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_SYN) },
.evbit = { BIT_MASK(EV_KEY) | BIT_MASK(EV_ABS) },
.keybit = { [BIT_WORD(BTN_LEFT)] = BIT_MASK(BTN_LEFT) },
.absbit = { BIT_MASK(ABS_X) | BIT_MASK(ABS_Y) },
}, /* Mouse-like device with absolute X and Y but ordinary
......
......@@ -63,7 +63,7 @@ static inline void i8042_write_command(int val)
outb(val, I8042_COMMAND_REG);
}
#if defined(__i386__)
#if defined(__i386__) || defined(__x86_64__)
#include <linux/dmi.h>
......@@ -185,6 +185,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "LIFEBOOK E4010"),
},
},
{
.ident = "Fujitsu-Siemens Amilo Pro 2010",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro V2010"),
},
},
{
/*
* No data is coming from the touchscreen unless KBC
......@@ -277,6 +284,57 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
#endif
#ifdef CONFIG_X86
#include <linux/dmi.h>
/*
* Some Wistron based laptops need us to explicitly enable the 'Dritek
* keyboard extension' to make their extra keys start generating scancodes.
* Originally, this was just confined to older laptops, but a few Acer laptops
* have turned up in 2007 that also need this again.
*/
static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = {
{
.ident = "Acer Aspire 5630",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
},
},
{
.ident = "Acer Aspire 5650",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
},
},
{
.ident = "Acer Aspire 5680",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
},
},
{
.ident = "Acer Aspire 9110",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
},
},
{
.ident = "Acer TravelMate 2490",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
},
},
{ }
};
#endif /* CONFIG_X86 */
#ifdef CONFIG_PNP
#include <linux/pnp.h>
......@@ -512,7 +570,7 @@ static int __init i8042_platform_init(void)
i8042_reset = 1;
#endif
#if defined(__i386__)
#if defined(__i386__) || defined(__x86_64__)
if (dmi_check_system(i8042_dmi_noloop_table))
i8042_noloop = 1;
......@@ -520,6 +578,11 @@ static int __init i8042_platform_init(void)
i8042_nomux = 1;
#endif
#ifdef CONFIG_X86
if (dmi_check_system(i8042_dmi_dritek_table))
i8042_dritek = 1;
#endif /* CONFIG_X86 */
return retval;
}
......
......@@ -12,7 +12,6 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/interrupt.h>
#include <linux/ioport.h>
#include <linux/init.h>
......@@ -64,6 +63,12 @@ static unsigned int i8042_blink_frequency = 500;
module_param_named(panicblink, i8042_blink_frequency, uint, 0600);
MODULE_PARM_DESC(panicblink, "Frequency with which keyboard LEDs should blink when kernel panics");
#ifdef CONFIG_X86
static unsigned int i8042_dritek;
module_param_named(dritek, i8042_dritek, bool, 0);
MODULE_PARM_DESC(dritek, "Force enable the Dritek keyboard extension");
#endif
#ifdef CONFIG_PNP
static int i8042_nopnp;
module_param_named(nopnp, i8042_nopnp, bool, 0);
......@@ -280,7 +285,14 @@ static void i8042_stop(struct serio *serio)
struct i8042_port *port = serio->port_data;
port->exists = 0;
synchronize_sched();
/*
* We synchronize with both AUX and KBD IRQs because there is
* a (very unlikely) chance that AUX IRQ is raised for KBD port
* and vice versa.
*/
synchronize_irq(I8042_AUX_IRQ);
synchronize_irq(I8042_KBD_IRQ);
port->serio = NULL;
}
......@@ -1139,6 +1151,7 @@ static int __devinit i8042_setup_kbd(void)
static int __devinit i8042_probe(struct platform_device *dev)
{
int error;
char param;
error = i8042_controller_selftest();
if (error)
......@@ -1159,7 +1172,14 @@ static int __devinit i8042_probe(struct platform_device *dev)
if (error)
goto out_fail;
}
#ifdef CONFIG_X86
if (i8042_dritek) {
param = 0x90;
error = i8042_command(&param, 0x1059);
if (error)
goto out_fail;
}
#endif
/*
* Ok, everything is ready, let's register all serio ports
*/
......
......@@ -13,7 +13,6 @@
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
#include <linux/input.h>
......
......@@ -116,6 +116,7 @@ struct ads7846 {
// FIXME remove "irq_disabled"
unsigned irq_disabled:1; /* P: lock */
unsigned disabled:1;
unsigned is_suspended:1;
int (*filter)(void *data, int data_idx, int *val);
void *filter_data;
......@@ -203,7 +204,7 @@ static void ads7846_disable(struct ads7846 *ts);
static int device_suspended(struct device *dev)
{
struct ads7846 *ts = dev_get_drvdata(dev);
return dev->power.power_state.event != PM_EVENT_ON || ts->disabled;
return ts->is_suspended || ts->disabled;
}
static int ads7846_read12_ser(struct device *dev, unsigned command)
......@@ -794,7 +795,7 @@ static int ads7846_suspend(struct spi_device *spi, pm_message_t message)
spin_lock_irq(&ts->lock);
spi->dev.power.power_state = message;
ts->is_suspended = 1;
ads7846_disable(ts);
spin_unlock_irq(&ts->lock);
......@@ -809,7 +810,7 @@ static int ads7846_resume(struct spi_device *spi)
spin_lock_irq(&ts->lock);
spi->dev.power.power_state = PMSG_ON;
ts->is_suspended = 0;
ads7846_enable(ts);
spin_unlock_irq(&ts->lock);
......@@ -871,7 +872,6 @@ static int __devinit ads7846_probe(struct spi_device *spi)
}
dev_set_drvdata(&spi->dev, ts);
spi->dev.power.power_state = PMSG_ON;
ts->spi = spi;
ts->input = input_dev;
......
......@@ -36,7 +36,6 @@
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
......
......@@ -15,7 +15,6 @@
*/
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/completion.h>
#include <linux/delay.h>
......
......@@ -241,8 +241,6 @@ static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev
input_dev->evbit[0] = BIT_MASK(EV_KEY);
input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
input_dev->private = cam;
error = input_register_device(cam->input);
if (error) {
warn("Failed to register camera's input device, err: %d\n",
......
......@@ -105,8 +105,6 @@ static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
input_dev->evbit[0] = BIT_MASK(EV_KEY);
input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
input_dev->private = cam;
error = input_register_device(cam->input);
if (error) {
warn("Failed to register camera's input device, err: %d\n",
......
#define PXAKBD_MAXROW 8
#define PXAKBD_MAXCOL 8
struct pxa27x_keyboard_platform_data {
int nr_rows, nr_cols;
int keycodes[PXAKBD_MAXROW][PXAKBD_MAXCOL];
int gpio_modes[PXAKBD_MAXROW + PXAKBD_MAXCOL];
#ifdef CONFIG_PM
u32 reg_kpc;
u32 reg_kprec;
#endif
};
#ifndef __ASM_ARCH_PXA27x_KEYPAD_H
#define __ASM_ARCH_PXA27x_KEYPAD_H
#include <linux/input.h>
#define MAX_MATRIX_KEY_ROWS (8)
#define MAX_MATRIX_KEY_COLS (8)
/* pxa3xx keypad platform specific parameters
*
* NOTE:
* 1. direct_key_num indicates the number of keys in the direct keypad
* _plus_ the number of rotary-encoder sensor inputs, this can be
* left as 0 if only rotary encoders are enabled, the driver will
* automatically calculate this
*
* 2. direct_key_map is the key code map for the direct keys, if rotary
* encoder(s) are enabled, direct key 0/1(2/3) will be ignored
*
* 3. rotary can be either interpreted as a relative input event (e.g.
* REL_WHEEL/REL_HWHEEL) or specific keys (e.g. UP/DOWN/LEFT/RIGHT)
*
* 4. matrix key and direct key will use the same debounce_interval by
* default, which should be sufficient in most cases
*/
struct pxa27x_keypad_platform_data {
/* code map for the matrix keys */
unsigned int matrix_key_rows;
unsigned int matrix_key_cols;
unsigned int *matrix_key_map;
int matrix_key_map_size;
/* direct keys */
int direct_key_num;
unsigned int direct_key_map[8];
/* rotary encoders 0 */
int enable_rotary0;
int rotary0_rel_code;
int rotary0_up_key;
int rotary0_down_key;
/* rotary encoders 1 */
int enable_rotary1;
int rotary1_rel_code;
int rotary1_up_key;
int rotary1_down_key;
/* key debounce interval */
unsigned int debounce_interval;
};
#define KEY(row, col, val) (((row) << 28) | ((col) << 24) | (val))
#endif /* __ASM_ARCH_PXA27x_KEYPAD_H */
......@@ -163,4 +163,34 @@
extern struct platform_device tosascoop_jc_device;
extern struct platform_device tosascoop_device;
#define TOSA_KEY_SYNC KEY_102ND /* ??? */
#ifndef CONFIG_KEYBOARD_TOSA_USE_EXT_KEYCODES
#define TOSA_KEY_RECORD KEY_YEN
#define TOSA_KEY_ADDRESSBOOK KEY_KATAKANA
#define TOSA_KEY_CANCEL KEY_ESC
#define TOSA_KEY_CENTER KEY_HIRAGANA
#define TOSA_KEY_OK KEY_HENKAN
#define TOSA_KEY_CALENDAR KEY_KATAKANAHIRAGANA
#define TOSA_KEY_HOMEPAGE KEY_HANGEUL
#define TOSA_KEY_LIGHT KEY_MUHENKAN
#define TOSA_KEY_MENU KEY_HANJA
#define TOSA_KEY_FN KEY_RIGHTALT
#define TOSA_KEY_MAIL KEY_ZENKAKUHANKAKU
#else
#define TOSA_KEY_RECORD KEY_RECORD
#define TOSA_KEY_ADDRESSBOOK KEY_ADDRESSBOOK
#define TOSA_KEY_CANCEL KEY_CANCEL
#define TOSA_KEY_CENTER KEY_SELECT /* ??? */
#define TOSA_KEY_OK KEY_OK
#define TOSA_KEY_CALENDAR KEY_CALENDAR
#define TOSA_KEY_HOMEPAGE KEY_HOMEPAGE
#define TOSA_KEY_LIGHT KEY_KBDILLUMTOGGLE
#define TOSA_KEY_MENU KEY_MENU
#define TOSA_KEY_FN KEY_FN
#define TOSA_KEY_MAIL KEY_MAIL
#endif
#endif /* _ASM_ARCH_TOSA_H_ */
......@@ -1020,7 +1020,6 @@ struct ff_effect {
* @going_away: marks devices that are in a middle of unregistering and
* causes input_open_device*() fail with -ENODEV.
* @dev: driver model's view of this device
* @cdev: union for struct device pointer
* @h_list: list of input handles associated with the device. When
* accessing the list dev->mutex must be held
* @node: used to place the device onto input_dev_list
......@@ -1085,9 +1084,6 @@ struct input_dev {
int going_away;
struct device dev;
union { /* temporarily so while we switching to struct device */
struct device *dev;
} cdev;
struct list_head h_list;
struct list_head node;
......@@ -1311,6 +1307,9 @@ static inline void input_set_abs_params(struct input_dev *dev, int axis, int min
dev->absbit[BIT_WORD(axis)] |= BIT_MASK(axis);
}
int input_get_keycode(struct input_dev *dev, int scancode, int *keycode);
int input_set_keycode(struct input_dev *dev, int scancode, int keycode);
extern struct class input_class;
/**
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册