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: (32 commits)
  Input: wm97xx - update email address for Liam Girdwood
  Input: i8042 - add Thinkpad R31 to nomux list
  Input: move map_to_7segment.h to include/linux
  Input: ads7846 - fix cache line sharing issue
  Input: cm109 - add missing newlines to messages
  Input: document i8042.debug in kernel-parameters.txt
  Input: keyboard - fix potential out of bound access to key_map
  Input: psmouse - add OLPC touchpad driver
  Input: psmouse - tweak PSMOUSE_DEFINE_ATTR to support raw set callbacks
  Input: psmouse - add psmouse_queue_work() for ps/2 extension to make use of
  Input: psmouse - export psmouse_set_state for ps/2 extensions to use
  Input: ads7846 - introduce .gpio_pendown to get pendown state
  Input: ALPS - add signature for DualPoint found in Dell Latitude E6500
  Input: serio_raw - allow attaching to translated (SERIO_I8042XL) ports
  Input: cm109 - don't use obsolete logging macros
  Input: atkbd - expand Latitude's force release quirk to other Dells
  Input: bf54x-keys - add power management support
  Input: atmel_tsadcc - improve accuracy
  Input: convert drivers to use strict_strtoul()
  Input: appletouch - handle geyser 3/4 status bits
  ...
This commit is contained in:
Linus Torvalds 2008-10-16 11:52:08 -07:00
commit 36ac1d2f32
50 changed files with 2252 additions and 338 deletions

View file

@ -796,6 +796,7 @@ and is between 256 and 4096 characters. It is defined in the file
Defaults to the default architecture's huge page size
if not specified.
i8042.debug [HW] Toggle i8042 debug mode
i8042.direct [HW] Put keyboard port into non-translated mode
i8042.dumbkbd [HW] Pretend that controller can only read data from
keyboard and cannot control its state

View file

@ -4618,7 +4618,7 @@ WM97XX TOUCHSCREEN DRIVERS
P: Mark Brown
M: broonie@opensource.wolfsonmicro.com
P: Liam Girdwood
M: liam.girdwood@wolfsonmicro.com
M: lrg@slimlogic.co.uk
L: linux-input@vger.kernel.org
T: git git://opensource.wolfsonmicro.com/linux-2.6-touch
W: http://opensource.wolfsonmicro.com/node/7

View file

@ -1249,7 +1249,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
return;
}
if (keycode > NR_KEYS)
if (keycode >= NR_KEYS)
if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1);
else

View file

@ -231,6 +231,7 @@ static void gameport_find_driver(struct gameport *gameport)
enum gameport_event_type {
GAMEPORT_REGISTER_PORT,
GAMEPORT_REGISTER_DRIVER,
GAMEPORT_ATTACH_DRIVER,
};
struct gameport_event {
@ -245,11 +246,12 @@ static LIST_HEAD(gameport_event_list);
static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
static struct task_struct *gameport_task;
static void gameport_queue_event(void *object, struct module *owner,
enum gameport_event_type event_type)
static int gameport_queue_event(void *object, struct module *owner,
enum gameport_event_type event_type)
{
unsigned long flags;
struct gameport_event *event;
int retval = 0;
spin_lock_irqsave(&gameport_event_lock, flags);
@ -268,24 +270,34 @@ static void gameport_queue_event(void *object, struct module *owner,
}
}
if ((event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC))) {
if (!try_module_get(owner)) {
printk(KERN_WARNING "gameport: Can't get module reference, dropping event %d\n", event_type);
kfree(event);
goto out;
}
event->type = event_type;
event->object = object;
event->owner = owner;
list_add_tail(&event->node, &gameport_event_list);
wake_up(&gameport_wait);
} else {
printk(KERN_ERR "gameport: Not enough memory to queue event %d\n", event_type);
event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
if (!event) {
printk(KERN_ERR
"gameport: Not enough memory to queue event %d\n",
event_type);
retval = -ENOMEM;
goto out;
}
if (!try_module_get(owner)) {
printk(KERN_WARNING
"gameport: Can't get module reference, dropping event %d\n",
event_type);
kfree(event);
retval = -EINVAL;
goto out;
}
event->type = event_type;
event->object = object;
event->owner = owner;
list_add_tail(&event->node, &gameport_event_list);
wake_up(&gameport_wait);
out:
spin_unlock_irqrestore(&gameport_event_lock, flags);
return retval;
}
static void gameport_free_event(struct gameport_event *event)
@ -378,9 +390,10 @@ static void gameport_handle_event(void)
}
/*
* Remove all events that have been submitted for a given gameport port.
* Remove all events that have been submitted for a given object,
* be it a gameport port or a driver.
*/
static void gameport_remove_pending_events(struct gameport *gameport)
static void gameport_remove_pending_events(void *object)
{
struct list_head *node, *next;
struct gameport_event *event;
@ -390,7 +403,7 @@ static void gameport_remove_pending_events(struct gameport *gameport)
list_for_each_safe(node, next, &gameport_event_list) {
event = list_entry(node, struct gameport_event, node);
if (event->object == gameport) {
if (event->object == object) {
list_del_init(node);
gameport_free_event(event);
}
@ -705,10 +718,40 @@ static void gameport_add_driver(struct gameport_driver *drv)
drv->driver.name, error);
}
void __gameport_register_driver(struct gameport_driver *drv, struct module *owner)
int __gameport_register_driver(struct gameport_driver *drv, struct module *owner,
const char *mod_name)
{
int error;
drv->driver.bus = &gameport_bus;
gameport_queue_event(drv, owner, GAMEPORT_REGISTER_DRIVER);
drv->driver.owner = owner;
drv->driver.mod_name = mod_name;
/*
* Temporarily disable automatic binding because probing
* takes long time and we are better off doing it in kgameportd
*/
drv->ignore = 1;
error = driver_register(&drv->driver);
if (error) {
printk(KERN_ERR
"gameport: driver_register() failed for %s, error: %d\n",
drv->driver.name, error);
return error;
}
/*
* Reset ignore flag and let kgameportd bind the driver to free ports
*/
drv->ignore = 0;
error = gameport_queue_event(drv, NULL, GAMEPORT_ATTACH_DRIVER);
if (error) {
driver_unregister(&drv->driver);
return error;
}
return 0;
}
void gameport_unregister_driver(struct gameport_driver *drv)
@ -716,7 +759,9 @@ void gameport_unregister_driver(struct gameport_driver *drv)
struct gameport *gameport;
mutex_lock(&gameport_mutex);
drv->ignore = 1; /* so gameport_find_driver ignores it */
gameport_remove_pending_events(drv);
start_over:
list_for_each_entry(gameport, &gameport_list, node) {
@ -729,6 +774,7 @@ start_over:
}
driver_unregister(&drv->driver);
mutex_unlock(&gameport_mutex);
}

View file

@ -414,8 +414,7 @@ static struct gameport_driver a3d_drv = {
static int __init a3d_init(void)
{
gameport_register_driver(&a3d_drv);
return 0;
return gameport_register_driver(&a3d_drv);
}
static void __exit a3d_exit(void)

View file

@ -572,8 +572,7 @@ static struct gameport_driver adi_drv = {
static int __init adi_init(void)
{
gameport_register_driver(&adi_drv);
return 0;
return gameport_register_driver(&adi_drv);
}
static void __exit adi_exit(void)

View file

@ -761,9 +761,7 @@ static struct gameport_driver analog_drv = {
static int __init analog_init(void)
{
analog_parse_options();
gameport_register_driver(&analog_drv);
return 0;
return gameport_register_driver(&analog_drv);
}
static void __exit analog_exit(void)

View file

@ -263,8 +263,7 @@ static struct gameport_driver cobra_drv = {
static int __init cobra_init(void)
{
gameport_register_driver(&cobra_drv);
return 0;
return gameport_register_driver(&cobra_drv);
}
static void __exit cobra_exit(void)

View file

@ -375,8 +375,7 @@ static struct gameport_driver gf2k_drv = {
static int __init gf2k_init(void)
{
gameport_register_driver(&gf2k_drv);
return 0;
return gameport_register_driver(&gf2k_drv);
}
static void __exit gf2k_exit(void)

View file

@ -426,8 +426,7 @@ static struct gameport_driver grip_drv = {
static int __init grip_init(void)
{
gameport_register_driver(&grip_drv);
return 0;
return gameport_register_driver(&grip_drv);
}
static void __exit grip_exit(void)

View file

@ -689,8 +689,7 @@ static struct gameport_driver grip_drv = {
static int __init grip_init(void)
{
gameport_register_driver(&grip_drv);
return 0;
return gameport_register_driver(&grip_drv);
}
static void __exit grip_exit(void)

View file

@ -283,8 +283,7 @@ static struct gameport_driver guillemot_drv = {
static int __init guillemot_init(void)
{
gameport_register_driver(&guillemot_drv);
return 0;
return gameport_register_driver(&guillemot_drv);
}
static void __exit guillemot_exit(void)

View file

@ -317,8 +317,7 @@ static struct gameport_driver interact_drv = {
static int __init interact_init(void)
{
gameport_register_driver(&interact_drv);
return 0;
return gameport_register_driver(&interact_drv);
}
static void __exit interact_exit(void)

View file

@ -161,8 +161,7 @@ static struct gameport_driver joydump_drv = {
static int __init joydump_init(void)
{
gameport_register_driver(&joydump_drv);
return 0;
return gameport_register_driver(&joydump_drv);
}
static void __exit joydump_exit(void)

View file

@ -818,8 +818,7 @@ static struct gameport_driver sw_drv = {
static int __init sw_init(void)
{
gameport_register_driver(&sw_drv);
return 0;
return gameport_register_driver(&sw_drv);
}
static void __exit sw_exit(void)

View file

@ -438,8 +438,7 @@ static struct gameport_driver tmdc_drv = {
static int __init tmdc_init(void)
{
gameport_register_driver(&tmdc_drv);
return 0;
return gameport_register_driver(&tmdc_drv);
}
static void __exit tmdc_exit(void)

View file

@ -834,10 +834,10 @@ static void atkbd_disconnect(struct serio *serio)
}
/*
* Most special keys (Fn+F?) on Dell Latitudes do not generate release
* Most special keys (Fn+F?) on Dell laptops do not generate release
* events so we have to do it ourselves.
*/
static void atkbd_latitude_keymap_fixup(struct atkbd *atkbd)
static void atkbd_dell_laptop_keymap_fixup(struct atkbd *atkbd)
{
const unsigned int forced_release_keys[] = {
0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93,
@ -1207,15 +1207,13 @@ static ssize_t atkbd_set_extra(struct atkbd *atkbd, const char *buf, size_t coun
{
struct input_dev *old_dev, *new_dev;
unsigned long value;
char *rest;
int err;
unsigned char old_extra, old_set;
if (!atkbd->write)
return -EIO;
value = simple_strtoul(buf, &rest, 10);
if (*rest || value > 1)
if (strict_strtoul(buf, 10, &value) || value > 1)
return -EINVAL;
if (atkbd->extra != value) {
@ -1264,12 +1262,10 @@ static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t cou
{
struct input_dev *old_dev, *new_dev;
unsigned long value;
char *rest;
int err;
unsigned char old_scroll;
value = simple_strtoul(buf, &rest, 10);
if (*rest || value > 1)
if (strict_strtoul(buf, 10, &value) || value > 1)
return -EINVAL;
if (atkbd->scroll != value) {
@ -1310,15 +1306,13 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count)
{
struct input_dev *old_dev, *new_dev;
unsigned long value;
char *rest;
int err;
unsigned char old_set, old_extra;
if (!atkbd->write)
return -EIO;
value = simple_strtoul(buf, &rest, 10);
if (*rest || (value != 2 && value != 3))
if (strict_strtoul(buf, 10, &value) || (value != 2 && value != 3))
return -EINVAL;
if (atkbd->set != value) {
@ -1361,15 +1355,13 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t
{
struct input_dev *old_dev, *new_dev;
unsigned long value;
char *rest;
int err;
unsigned char old_softrepeat, old_softraw;
if (!atkbd->write)
return -EIO;
value = simple_strtoul(buf, &rest, 10);
if (*rest || value > 1)
if (strict_strtoul(buf, 10, &value) || value > 1)
return -EINVAL;
if (atkbd->softrepeat != value) {
@ -1413,12 +1405,10 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co
{
struct input_dev *old_dev, *new_dev;
unsigned long value;
char *rest;
int err;
unsigned char old_softraw;
value = simple_strtoul(buf, &rest, 10);
if (*rest || value > 1)
if (strict_strtoul(buf, 10, &value) || value > 1)
return -EINVAL;
if (atkbd->softraw != value) {
@ -1461,13 +1451,13 @@ static int __init atkbd_setup_fixup(const struct dmi_system_id *id)
static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
{
.ident = "Dell Latitude series",
.ident = "Dell Laptop",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"),
DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
},
.callback = atkbd_setup_fixup,
.driver_data = atkbd_latitude_keymap_fixup,
.driver_data = atkbd_dell_laptop_keymap_fixup,
},
{
.ident = "HP 2133",

View file

@ -8,7 +8,7 @@
*
*
* Modified:
* Copyright 2007 Analog Devices Inc.
* Copyright 2007-2008 Analog Devices Inc.
*
* Bugs: Enter bugs at http://blackfin.uclinux.org/
*
@ -81,6 +81,9 @@ struct bf54x_kpad {
unsigned short *keycode;
struct timer_list timer;
unsigned int keyup_test_jiffies;
unsigned short kpad_msel;
unsigned short kpad_prescale;
unsigned short kpad_ctl;
};
static inline int bfin_kpad_find_key(struct bf54x_kpad *bf54x_kpad,
@ -360,6 +363,10 @@ static int bfin_kpad_suspend(struct platform_device *pdev, pm_message_t state)
{
struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
bf54x_kpad->kpad_msel = bfin_read_KPAD_MSEL();
bf54x_kpad->kpad_prescale = bfin_read_KPAD_PRESCALE();
bf54x_kpad->kpad_ctl = bfin_read_KPAD_CTL();
if (device_may_wakeup(&pdev->dev))
enable_irq_wake(bf54x_kpad->irq);
@ -370,6 +377,10 @@ static int bfin_kpad_resume(struct platform_device *pdev)
{
struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(pdev);
bfin_write_KPAD_MSEL(bf54x_kpad->kpad_msel);
bfin_write_KPAD_PRESCALE(bf54x_kpad->kpad_prescale);
bfin_write_KPAD_CTL(bf54x_kpad->kpad_ctl);
if (device_may_wakeup(&pdev->dev))
disable_irq_wake(bf54x_kpad->irq);

View file

@ -36,9 +36,10 @@ struct gpio_keys_drvdata {
struct gpio_button_data data[0];
};
static void gpio_keys_report_event(struct gpio_keys_button *button,
struct input_dev *input)
static void gpio_keys_report_event(struct gpio_button_data *bdata)
{
struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY;
int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
@ -50,34 +51,23 @@ static void gpio_check_button(unsigned long _data)
{
struct gpio_button_data *data = (struct gpio_button_data *)_data;
gpio_keys_report_event(data->button, data->input);
gpio_keys_report_event(data);
}
static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
{
struct platform_device *pdev = dev_id;
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data;
struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
int i;
struct gpio_button_data *bdata = dev_id;
struct gpio_keys_button *button = bdata->button;
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
BUG_ON(irq != gpio_to_irq(button->gpio));
if (irq == gpio_to_irq(button->gpio)) {
struct gpio_button_data *bdata = &ddata->data[i];
if (button->debounce_interval)
mod_timer(&bdata->timer,
jiffies + msecs_to_jiffies(button->debounce_interval));
else
gpio_keys_report_event(bdata);
if (button->debounce_interval)
mod_timer(&bdata->timer,
jiffies +
msecs_to_jiffies(button->debounce_interval));
else
gpio_keys_report_event(button, bdata->input);
return IRQ_HANDLED;
}
}
return IRQ_NONE;
return IRQ_HANDLED;
}
static int __devinit gpio_keys_probe(struct platform_device *pdev)
@ -151,7 +141,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
IRQF_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING,
button->desc ? button->desc : "gpio_keys",
pdev);
bdata);
if (error) {
pr_err("gpio-keys: Unable to claim irq %d; error %d\n",
irq, error);
@ -178,7 +168,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
fail2:
while (--i >= 0) {
free_irq(gpio_to_irq(pdata->buttons[i].gpio), pdev);
free_irq(gpio_to_irq(pdata->buttons[i].gpio), &ddata->data[i]);
if (pdata->buttons[i].debounce_interval)
del_timer_sync(&ddata->data[i].timer);
gpio_free(pdata->buttons[i].gpio);
@ -203,7 +193,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
for (i = 0; i < pdata->nbuttons; i++) {
int irq = gpio_to_irq(pdata->buttons[i].gpio);
free_irq(irq, pdev);
free_irq(irq, &ddata->data[i]);
if (pdata->buttons[i].debounce_interval)
del_timer_sync(&ddata->data[i].timer);
gpio_free(pdata->buttons[i].gpio);

View file

@ -180,6 +180,19 @@ config INPUT_YEALINK
To compile this driver as a module, choose M here: the module will be
called yealink.
config INPUT_CM109
tristate "C-Media CM109 USB I/O Controller"
depends on EXPERIMENTAL
depends on USB_ARCH_HAS_HCD
select USB
help
Say Y here if you want to enable keyboard and buzzer functions of the
C-Media CM109 usb phones. The audio part is enabled by the generic
usb sound driver, so you might want to enable that as well.
To compile this driver as a module, choose M here: the module will be
called cm109.
config INPUT_UINPUT
tristate "User level driver support"
help

View file

@ -16,6 +16,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_INPUT_CM109) += cm109.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o

View file

@ -1,8 +1,8 @@
/*
* ati_remote2 - ATI/Philips USB RF remote driver
*
* Copyright (C) 2005 Ville Syrjala <syrjala@sci.fi>
* Copyright (C) 2007 Peter Stokes <linux@dadeos.freeserve.co.uk>
* Copyright (C) 2005-2008 Ville Syrjala <syrjala@sci.fi>
* Copyright (C) 2007-2008 Peter Stokes <linux@dadeos.co.uk>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2
@ -12,7 +12,7 @@
#include <linux/usb/input.h>
#define DRIVER_DESC "ATI/Philips USB RF remote driver"
#define DRIVER_VERSION "0.2"
#define DRIVER_VERSION "0.3"
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION);
@ -27,7 +27,7 @@ MODULE_LICENSE("GPL");
* A remote's "channel" may be altered by pressing and holding the "PC" button for
* approximately 3 seconds, after which the button will slowly flash the count of the
* currently configured "channel", using the numeric keypad enter a number between 1 and
* 16 and then the "PC" button again, the button will slowly flash the count of the
* 16 and then press the "PC" button again, the button will slowly flash the count of the
* newly configured "channel".
*/
@ -45,9 +45,25 @@ static struct usb_device_id ati_remote2_id_table[] = {
};
MODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
static struct {
int hw_code;
int key_code;
static DEFINE_MUTEX(ati_remote2_mutex);
enum {
ATI_REMOTE2_OPENED = 0x1,
ATI_REMOTE2_SUSPENDED = 0x2,
};
enum {
ATI_REMOTE2_AUX1,
ATI_REMOTE2_AUX2,
ATI_REMOTE2_AUX3,
ATI_REMOTE2_AUX4,
ATI_REMOTE2_PC,
ATI_REMOTE2_MODES,
};
static const struct {
u8 hw_code;
u16 keycode;
} ati_remote2_key_table[] = {
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
@ -73,6 +89,7 @@ static struct {
{ 0x37, KEY_RECORD },
{ 0x38, KEY_DVD },
{ 0x39, KEY_TV },
{ 0x3f, KEY_PROG1 }, /* AUX1-AUX4 and PC */
{ 0x54, KEY_MENU },
{ 0x58, KEY_UP },
{ 0x59, KEY_DOWN },
@ -91,15 +108,9 @@ static struct {
{ 0xa9, BTN_LEFT },
{ 0xaa, BTN_RIGHT },
{ 0xbe, KEY_QUESTION },
{ 0xd5, KEY_FRONT },
{ 0xd0, KEY_EDIT },
{ 0xd5, KEY_FRONT },
{ 0xf9, KEY_INFO },
{ (0x00 << 8) | 0x3f, KEY_PROG1 },
{ (0x01 << 8) | 0x3f, KEY_PROG2 },
{ (0x02 << 8) | 0x3f, KEY_PROG3 },
{ (0x03 << 8) | 0x3f, KEY_PROG4 },
{ (0x04 << 8) | 0x3f, KEY_PC },
{ 0, KEY_RESERVED }
};
struct ati_remote2 {
@ -117,46 +128,106 @@ struct ati_remote2 {
char name[64];
char phys[64];
/* Each mode (AUX1-AUX4 and PC) can have an independent keymap. */
u16 keycode[ATI_REMOTE2_MODES][ARRAY_SIZE(ati_remote2_key_table)];
unsigned int flags;
};
static int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
static void ati_remote2_disconnect(struct usb_interface *interface);
static int ati_remote2_suspend(struct usb_interface *interface, pm_message_t message);
static int ati_remote2_resume(struct usb_interface *interface);
static struct usb_driver ati_remote2_driver = {
.name = "ati_remote2",
.probe = ati_remote2_probe,
.disconnect = ati_remote2_disconnect,
.id_table = ati_remote2_id_table,
.suspend = ati_remote2_suspend,
.resume = ati_remote2_resume,
.supports_autosuspend = 1,
};
static int ati_remote2_open(struct input_dev *idev)
static int ati_remote2_submit_urbs(struct ati_remote2 *ar2)
{
struct ati_remote2 *ar2 = input_get_drvdata(idev);
int r;
r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
if (r) {
dev_err(&ar2->intf[0]->dev,
"%s: usb_submit_urb() = %d\n", __func__, r);
"%s(): usb_submit_urb() = %d\n", __func__, r);
return r;
}
r = usb_submit_urb(ar2->urb[1], GFP_KERNEL);
if (r) {
usb_kill_urb(ar2->urb[0]);
dev_err(&ar2->intf[1]->dev,
"%s: usb_submit_urb() = %d\n", __func__, r);
"%s(): usb_submit_urb() = %d\n", __func__, r);
return r;
}
return 0;
}
static void ati_remote2_kill_urbs(struct ati_remote2 *ar2)
{
usb_kill_urb(ar2->urb[1]);
usb_kill_urb(ar2->urb[0]);
}
static int ati_remote2_open(struct input_dev *idev)
{
struct ati_remote2 *ar2 = input_get_drvdata(idev);
int r;
dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
r = usb_autopm_get_interface(ar2->intf[0]);
if (r) {
dev_err(&ar2->intf[0]->dev,
"%s(): usb_autopm_get_interface() = %d\n", __func__, r);
goto fail1;
}
mutex_lock(&ati_remote2_mutex);
if (!(ar2->flags & ATI_REMOTE2_SUSPENDED)) {
r = ati_remote2_submit_urbs(ar2);
if (r)
goto fail2;
}
ar2->flags |= ATI_REMOTE2_OPENED;
mutex_unlock(&ati_remote2_mutex);
usb_autopm_put_interface(ar2->intf[0]);
return 0;
fail2:
mutex_unlock(&ati_remote2_mutex);
usb_autopm_put_interface(ar2->intf[0]);
fail1:
return r;
}
static void ati_remote2_close(struct input_dev *idev)
{
struct ati_remote2 *ar2 = input_get_drvdata(idev);
usb_kill_urb(ar2->urb[0]);
usb_kill_urb(ar2->urb[1]);
dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
mutex_lock(&ati_remote2_mutex);
if (!(ar2->flags & ATI_REMOTE2_SUSPENDED))
ati_remote2_kill_urbs(ar2);
ar2->flags &= ~ATI_REMOTE2_OPENED;
mutex_unlock(&ati_remote2_mutex);
}
static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
@ -172,7 +243,7 @@ static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
mode = data[0] & 0x0F;
if (mode > 4) {
if (mode > ATI_REMOTE2_PC) {
dev_err(&ar2->intf[0]->dev,
"Unknown mode byte (%02x %02x %02x %02x)\n",
data[3], data[2], data[1], data[0]);
@ -191,7 +262,7 @@ static int ati_remote2_lookup(unsigned int hw_code)
{
int i;
for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
for (i = 0; i < ARRAY_SIZE(ati_remote2_key_table); i++)
if (ati_remote2_key_table[i].hw_code == hw_code)
return i;
@ -211,7 +282,7 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
mode = data[0] & 0x0F;
if (mode > 4) {
if (mode > ATI_REMOTE2_PC) {
dev_err(&ar2->intf[1]->dev,
"Unknown mode byte (%02x %02x %02x %02x)\n",
data[3], data[2], data[1], data[0]);
@ -219,10 +290,6 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
}
hw_code = data[2];
/*
* Mode keys (AUX1-AUX4, PC) all generate the same code byte.
* Use the mode byte to figure out which one was pressed.
*/
if (hw_code == 0x3f) {
/*
* For some incomprehensible reason the mouse pad generates
@ -236,8 +303,6 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
if (data[1] == 0)
ar2->mode = mode;
hw_code |= mode << 8;
}
if (!((1 << mode) & mode_mask))
@ -260,8 +325,8 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
case 2: /* repeat */
/* No repeat for mouse buttons. */
if (ati_remote2_key_table[index].key_code == BTN_LEFT ||
ati_remote2_key_table[index].key_code == BTN_RIGHT)
if (ar2->keycode[mode][index] == BTN_LEFT ||
ar2->keycode[mode][index] == BTN_RIGHT)
return;
if (!time_after_eq(jiffies, ar2->jiffies))
@ -276,7 +341,7 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
return;
}
input_event(idev, EV_KEY, ati_remote2_key_table[index].key_code, data[1]);
input_event(idev, EV_KEY, ar2->keycode[mode][index], data[1]);
input_sync(idev);
}
@ -287,6 +352,7 @@ static void ati_remote2_complete_mouse(struct urb *urb)
switch (urb->status) {
case 0:
usb_mark_last_busy(ar2->udev);
ati_remote2_input_mouse(ar2);
break;
case -ENOENT:
@ -297,6 +363,7 @@ static void ati_remote2_complete_mouse(struct urb *urb)
"%s(): urb status = %d\n", __func__, urb->status);
return;
default:
usb_mark_last_busy(ar2->udev);
dev_err(&ar2->intf[0]->dev,
"%s(): urb status = %d\n", __func__, urb->status);
}
@ -314,6 +381,7 @@ static void ati_remote2_complete_key(struct urb *urb)
switch (urb->status) {
case 0:
usb_mark_last_busy(ar2->udev);
ati_remote2_input_key(ar2);
break;
case -ENOENT:
@ -324,6 +392,7 @@ static void ati_remote2_complete_key(struct urb *urb)
"%s(): urb status = %d\n", __func__, urb->status);
return;
default:
usb_mark_last_busy(ar2->udev);
dev_err(&ar2->intf[1]->dev,
"%s(): urb status = %d\n", __func__, urb->status);
}
@ -334,10 +403,60 @@ static void ati_remote2_complete_key(struct urb *urb)
"%s(): usb_submit_urb() = %d\n", __func__, r);
}
static int ati_remote2_getkeycode(struct input_dev *idev,
int scancode, int *keycode)
{
struct ati_remote2 *ar2 = input_get_drvdata(idev);
int index, mode;
mode = scancode >> 8;
if (mode > ATI_REMOTE2_PC || !((1 << mode) & mode_mask))
return -EINVAL;
index = ati_remote2_lookup(scancode & 0xFF);
if (index < 0)
return -EINVAL;
*keycode = ar2->keycode[mode][index];
return 0;
}
static int ati_remote2_setkeycode(struct input_dev *idev, int scancode, int keycode)
{
struct ati_remote2 *ar2 = input_get_drvdata(idev);
int index, mode, old_keycode;
mode = scancode >> 8;
if (mode > ATI_REMOTE2_PC || !((1 << mode) & mode_mask))
return -EINVAL;
index = ati_remote2_lookup(scancode & 0xFF);
if (index < 0)
return -EINVAL;
if (keycode < KEY_RESERVED || keycode > KEY_MAX)
return -EINVAL;
old_keycode = ar2->keycode[mode][index];
ar2->keycode[mode][index] = keycode;
set_bit(keycode, idev->keybit);
for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
if (ar2->keycode[mode][index] == old_keycode)
return 0;
}
}
clear_bit(old_keycode, idev->keybit);
return 0;
}
static int ati_remote2_input_init(struct ati_remote2 *ar2)
{
struct input_dev *idev;
int i, retval;
int index, mode, retval;
idev = input_allocate_device();
if (!idev)
@ -350,8 +469,26 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
BIT_MASK(BTN_RIGHT);
idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y);
for (i = 0; ati_remote2_key_table[i].key_code != KEY_RESERVED; i++)
set_bit(ati_remote2_key_table[i].key_code, idev->keybit);
for (mode = 0; mode < ATI_REMOTE2_MODES; mode++) {
for (index = 0; index < ARRAY_SIZE(ati_remote2_key_table); index++) {
ar2->keycode[mode][index] = ati_remote2_key_table[index].keycode;
set_bit(ar2->keycode[mode][index], idev->keybit);
}
}
/* AUX1-AUX4 and PC generate the same scancode. */
index = ati_remote2_lookup(0x3f);
ar2->keycode[ATI_REMOTE2_AUX1][index] = KEY_PROG1;
ar2->keycode[ATI_REMOTE2_AUX2][index] = KEY_PROG2;
ar2->keycode[ATI_REMOTE2_AUX3][index] = KEY_PROG3;
ar2->keycode[ATI_REMOTE2_AUX4][index] = KEY_PROG4;
ar2->keycode[ATI_REMOTE2_PC][index] = KEY_PC;
set_bit(KEY_PROG1, idev->keybit);
set_bit(KEY_PROG2, idev->keybit);
set_bit(KEY_PROG3, idev->keybit);
set_bit(KEY_PROG4, idev->keybit);
set_bit(KEY_PC, idev->keybit);
idev->rep[REP_DELAY] = 250;
idev->rep[REP_PERIOD] = 33;
@ -359,6 +496,9 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
idev->open = ati_remote2_open;
idev->close = ati_remote2_close;
idev->getkeycode = ati_remote2_getkeycode;
idev->setkeycode = ati_remote2_setkeycode;
idev->name = ar2->name;
idev->phys = ar2->phys;
@ -490,6 +630,8 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
usb_set_intfdata(interface, ar2);
interface->needs_remote_wakeup = 1;
return 0;
fail2:
@ -522,6 +664,57 @@ static void ati_remote2_disconnect(struct usb_interface *interface)
kfree(ar2);
}
static int ati_remote2_suspend(struct usb_interface *interface,
pm_message_t message)
{
struct ati_remote2 *ar2;
struct usb_host_interface *alt = interface->cur_altsetting;
if (alt->desc.bInterfaceNumber)
return 0;
ar2 = usb_get_intfdata(interface);
dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
mutex_lock(&ati_remote2_mutex);
if (ar2->flags & ATI_REMOTE2_OPENED)
ati_remote2_kill_urbs(ar2);
ar2->flags |= ATI_REMOTE2_SUSPENDED;
mutex_unlock(&ati_remote2_mutex);
return 0;
}
static int ati_remote2_resume(struct usb_interface *interface)
{
struct ati_remote2 *ar2;
struct usb_host_interface *alt = interface->cur_altsetting;
int r = 0;
if (alt->desc.bInterfaceNumber)
return 0;
ar2 = usb_get_intfdata(interface);
dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
mutex_lock(&ati_remote2_mutex);
if (ar2->flags & ATI_REMOTE2_OPENED)
r = ati_remote2_submit_urbs(ar2);
if (!r)
ar2->flags &= ~ATI_REMOTE2_SUSPENDED;
mutex_unlock(&ati_remote2_mutex);
return r;
}
static int __init ati_remote2_init(void)
{
int r;

882
drivers/input/misc/cm109.c Normal file
View file

@ -0,0 +1,882 @@
/*
* Driver for the VoIP USB phones with CM109 chipsets.
*
* Copyright (C) 2007 - 2008 Alfred E. Heggestad <aeh@db.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*/
/*
* Tested devices:
* - Komunikate KIP1000
* - Genius G-talk
* - Allied-Telesis Corega USBPH01
* - ...
*
* This driver is based on the yealink.c driver
*
* Thanks to:
* - Authors of yealink.c
* - Thomas Reitmayr
* - Oliver Neukum for good review comments and code
* - Shaun Jackman <sjackman@gmail.com> for Genius G-talk keymap
* - Dmitry Torokhov for valuable input and review
*
* Todo:
* - Read/write EEPROM
*/
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/rwsem.h>
#include <linux/usb/input.h>
#define DRIVER_VERSION "20080805"
#define DRIVER_AUTHOR "Alfred E. Heggestad"
#define DRIVER_DESC "CM109 phone driver"
static char *phone = "kip1000";
module_param(phone, charp, S_IRUSR);
MODULE_PARM_DESC(phone, "Phone name {kip1000, gtalk, usbph01}");
enum {
/* HID Registers */
HID_IR0 = 0x00, /* Record/Playback-mute button, Volume up/down */
HID_IR1 = 0x01, /* GPI, generic registers or EEPROM_DATA0 */
HID_IR2 = 0x02, /* Generic registers or EEPROM_DATA1 */
HID_IR3 = 0x03, /* Generic registers or EEPROM_CTRL */
HID_OR0 = 0x00, /* Mapping control, buzzer, SPDIF (offset 0x04) */
HID_OR1 = 0x01, /* GPO - General Purpose Output */
HID_OR2 = 0x02, /* Set GPIO to input/output mode */
HID_OR3 = 0x03, /* SPDIF status channel or EEPROM_CTRL */
/* HID_IR0 */
RECORD_MUTE = 1 << 3,
PLAYBACK_MUTE = 1 << 2,
VOLUME_DOWN = 1 << 1,
VOLUME_UP = 1 << 0,
/* HID_OR0 */
/* bits 7-6
0: HID_OR1-2 are used for GPO; HID_OR0, 3 are used for buzzer
and SPDIF
1: HID_OR0-3 are used as generic HID registers
2: Values written to HID_OR0-3 are also mapped to MCU_CTRL,
EEPROM_DATA0-1, EEPROM_CTRL (see Note)
3: Reserved
*/
HID_OR_GPO_BUZ_SPDIF = 0 << 6,
HID_OR_GENERIC_HID_REG = 1 << 6,
HID_OR_MAP_MCU_EEPROM = 2 << 6,
BUZZER_ON = 1 << 5,
/* up to 256 normal keys, up to 16 special keys */
KEYMAP_SIZE = 256 + 16,
};
/* CM109 protocol packet */
struct cm109_ctl_packet {
u8 byte[4];
} __attribute__ ((packed));
enum { USB_PKT_LEN = sizeof(struct cm109_ctl_packet) };
/* CM109 device structure */
struct cm109_dev {
struct input_dev *idev; /* input device */
struct usb_device *udev; /* usb device */
struct usb_interface *intf;
/* irq input channel */
struct cm109_ctl_packet *irq_data;
dma_addr_t irq_dma;
struct urb *urb_irq;
/* control output channel */
struct cm109_ctl_packet *ctl_data;
dma_addr_t ctl_dma;
struct usb_ctrlrequest *ctl_req;
dma_addr_t ctl_req_dma;
struct urb *urb_ctl;
/*
* The 3 bitfields below are protected by ctl_submit_lock.
* They have to be separate since they are accessed from IRQ
* context.
*/
unsigned irq_urb_pending:1; /* irq_urb is in flight */
unsigned ctl_urb_pending:1; /* ctl_urb is in flight */
unsigned buzzer_pending:1; /* need to issue buzz command */
spinlock_t ctl_submit_lock;
unsigned char buzzer_state; /* on/off */
/* flags */
unsigned open:1;
unsigned resetting:1;
unsigned shutdown:1;
/* This mutex protects writes to the above flags */
struct mutex pm_mutex;
unsigned short keymap[KEYMAP_SIZE];
char phys[64]; /* physical device path */
int key_code; /* last reported key */
int keybit; /* 0=new scan 1,2,4,8=scan columns */
u8 gpi; /* Cached value of GPI (high nibble) */
};
/******************************************************************************
* CM109 key interface
*****************************************************************************/
static unsigned short special_keymap(int code)
{
if (code > 0xff) {
switch (code - 0xff) {
case RECORD_MUTE: return KEY_MUTE;
case PLAYBACK_MUTE: return KEY_MUTE;
case VOLUME_DOWN: return KEY_VOLUMEDOWN;
case VOLUME_UP: return KEY_VOLUMEUP;
}
}
return KEY_RESERVED;
}
/* Map device buttons to internal key events.
*
* The "up" and "down" keys, are symbolised by arrows on the button.
* The "pickup" and "hangup" keys are symbolised by a green and red phone
* on the button.
Komunikate KIP1000 Keyboard Matrix
-> -- 1 -- 2 -- 3 --> GPI pin 4 (0x10)
| | | |
<- -- 4 -- 5 -- 6 --> GPI pin 5 (0x20)
| | | |
END - 7 -- 8 -- 9 --> GPI pin 6 (0x40)
| | | |
OK -- * -- 0 -- # --> GPI pin 7 (0x80)
| | | |
/|\ /|\ /|\ /|\
| | | |
GPO
pin: 3 2 1 0
0x8 0x4 0x2 0x1
*/
static unsigned short keymap_kip1000(int scancode)
{
switch (scancode) { /* phone key: */
case 0x82: return KEY_NUMERIC_0; /* 0 */
case 0x14: return KEY_NUMERIC_1; /* 1 */
case 0x12: return KEY_NUMERIC_2; /* 2 */
case 0x11: return KEY_NUMERIC_3; /* 3 */
case 0x24: return KEY_NUMERIC_4; /* 4 */
case 0x22: return KEY_NUMERIC_5; /* 5 */
case 0x21: return KEY_NUMERIC_6; /* 6 */
case 0x44: return KEY_NUMERIC_7; /* 7 */
case 0x42: return KEY_NUMERIC_8; /* 8 */
case 0x41: return KEY_NUMERIC_9; /* 9 */
case 0x81: return KEY_NUMERIC_POUND; /* # */
case 0x84: return KEY_NUMERIC_STAR; /* * */
case 0x88: return KEY_ENTER; /* pickup */
case 0x48: return KEY_ESC; /* hangup */
case 0x28: return KEY_LEFT; /* IN */
case 0x18: return KEY_RIGHT; /* OUT */
default: return special_keymap(scancode);
}
}
/*
Contributed by Shaun Jackman <sjackman@gmail.com>
Genius G-Talk keyboard matrix
0 1 2 3
4: 0 4 8 Talk
5: 1 5 9 End
6: 2 6 # Up
7: 3 7 * Down
*/
static unsigned short keymap_gtalk(int scancode)
{
switch (scancode) {
case 0x11: return KEY_NUMERIC_0;
case 0x21: return KEY_NUMERIC_1;
case 0x41: return KEY_NUMERIC_2;
case 0x81: return KEY_NUMERIC_3;
case 0x12: return KEY_NUMERIC_4;
case 0x22: return KEY_NUMERIC_5;
case 0x42: return KEY_NUMERIC_6;
case 0x82: return KEY_NUMERIC_7;
case 0x14: return KEY_NUMERIC_8;
case 0x24: return KEY_NUMERIC_9;
case 0x44: return KEY_NUMERIC_POUND; /* # */
case 0x84: return KEY_NUMERIC_STAR; /* * */
case 0x18: return KEY_ENTER; /* Talk (green handset) */
case 0x28: return KEY_ESC; /* End (red handset) */
case 0x48: return KEY_UP; /* Menu up (rocker switch) */
case 0x88: return KEY_DOWN; /* Menu down (rocker switch) */
default: return special_keymap(scancode);
}
}
/*
* Keymap for Allied-Telesis Corega USBPH01
* http://www.alliedtelesis-corega.com/2/1344/1437/1360/chprd.html
*
* Contributed by july@nat.bg
*/
static unsigned short keymap_usbph01(int scancode)
{
switch (scancode) {
case 0x11: return KEY_NUMERIC_0; /* 0 */
case 0x21: return KEY_NUMERIC_1; /* 1 */
case 0x41: return KEY_NUMERIC_2; /* 2 */
case 0x81: return KEY_NUMERIC_3; /* 3 */
case 0x12: return KEY_NUMERIC_4; /* 4 */
case 0x22: return KEY_NUMERIC_5; /* 5 */
case 0x42: return KEY_NUMERIC_6; /* 6 */
case 0x82: return KEY_NUMERIC_7; /* 7 */
case 0x14: return KEY_NUMERIC_8; /* 8 */
case 0x24: return KEY_NUMERIC_9; /* 9 */
case 0x44: return KEY_NUMERIC_POUND; /* # */
case 0x84: return KEY_NUMERIC_STAR; /* * */
case 0x18: return KEY_ENTER; /* pickup */
case 0x28: return KEY_ESC; /* hangup */
case 0x48: return KEY_LEFT; /* IN */
case 0x88: return KEY_RIGHT; /* OUT */
default: return special_keymap(scancode);
}
}
static unsigned short (*keymap)(int) = keymap_kip1000;
/*
* Completes a request by converting the data into events for the
* input subsystem.
*/
static void report_key(struct cm109_dev *dev, int key)
{
struct input_dev *idev = dev->idev;
if (dev->key_code >= 0) {
/* old key up */
input_report_key(idev, dev->key_code, 0);
}
dev->key_code = key;
if (key >= 0) {
/* new valid key */
input_report_key(idev, key, 1);
}
input_sync(idev);
}
/******************************************************************************
* CM109 usb communication interface
*****************************************************************************/
static void cm109_submit_buzz_toggle(struct cm109_dev *dev)
{
int error;
if (dev->buzzer_state)
dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
else
dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
if (error)
err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
}
/*
* IRQ handler
*/
static void cm109_urb_irq_callback(struct urb *urb)
{
struct cm109_dev *dev = urb->context;
const int status = urb->status;
int error;
dev_dbg(&urb->dev->dev, "### URB IRQ: [0x%02x 0x%02x 0x%02x 0x%02x] keybit=0x%02x\n",
dev->irq_data->byte[0],
dev->irq_data->byte[1],
dev->irq_data->byte[2],
dev->irq_data->byte[3],
dev->keybit);
if (status) {
if (status == -ESHUTDOWN)
return;
err("%s: urb status %d", __func__, status);
}
/* Special keys */
if (dev->irq_data->byte[HID_IR0] & 0x0f) {
const int code = (dev->irq_data->byte[HID_IR0] & 0x0f);
report_key(dev, dev->keymap[0xff + code]);
}
/* Scan key column */
if (dev->keybit == 0xf) {
/* Any changes ? */
if ((dev->gpi & 0xf0) == (dev->irq_data->byte[HID_IR1] & 0xf0))
goto out;
dev->gpi = dev->irq_data->byte[HID_IR1] & 0xf0;
dev->keybit = 0x1;
} else {
report_key(dev, dev->keymap[dev->irq_data->byte[HID_IR1]]);
dev->keybit <<= 1;
if (dev->keybit > 0x8)
dev->keybit = 0xf;
}
out:
spin_lock(&dev->ctl_submit_lock);
dev->irq_urb_pending = 0;
if (likely(!dev->shutdown)) {
if (dev->buzzer_state)
dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
else
dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
dev->ctl_data->byte[HID_OR1] = dev->keybit;
dev->ctl_data->byte[HID_OR2] = dev->keybit;
dev->buzzer_pending = 0;
dev->ctl_urb_pending = 1;
error = usb_submit_urb(dev->urb_ctl, GFP_ATOMIC);
if (error)
err("%s: usb_submit_urb (urb_ctl) failed %d",
__func__, error);
}
spin_unlock(&dev->ctl_submit_lock);
}
static void cm109_urb_ctl_callback(struct urb *urb)
{
struct cm109_dev *dev = urb->context;
const int status = urb->status;
int error;
dev_dbg(&urb->dev->dev, "### URB CTL: [0x%02x 0x%02x 0x%02x 0x%02x]\n",
dev->ctl_data->byte[0],
dev->ctl_data->byte[1],
dev->ctl_data->byte[2],
dev->ctl_data->byte[3]);
if (status)
err("%s: urb status %d", __func__, status);
spin_lock(&dev->ctl_submit_lock);
dev->ctl_urb_pending = 0;
if (likely(!dev->shutdown)) {
if (dev->buzzer_pending) {
dev->buzzer_pending = 0;
dev->ctl_urb_pending = 1;
cm109_submit_buzz_toggle(dev);
} else if (likely(!dev->irq_urb_pending)) {
/* ask for key data */
dev->irq_urb_pending = 1;
error = usb_submit_urb(dev->urb_irq, GFP_ATOMIC);
if (error)
err("%s: usb_submit_urb (urb_irq) failed %d",
__func__, error);
}
}
spin_unlock(&dev->ctl_submit_lock);
}
static void cm109_toggle_buzzer_async(struct cm109_dev *dev)
{
unsigned long flags;
spin_lock_irqsave(&dev->ctl_submit_lock, flags);
if (dev->ctl_urb_pending) {
/* URB completion will resubmit */
dev->buzzer_pending = 1;
} else {
dev->ctl_urb_pending = 1;
cm109_submit_buzz_toggle(dev);
}
spin_unlock_irqrestore(&dev->ctl_submit_lock, flags);
}
static void cm109_toggle_buzzer_sync(struct cm109_dev *dev, int on)
{
int error;
if (on)
dev->ctl_data->byte[HID_OR0] |= BUZZER_ON;
else
dev->ctl_data->byte[HID_OR0] &= ~BUZZER_ON;
error = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
dev->ctl_req->bRequest,
dev->ctl_req->bRequestType,
le16_to_cpu(dev->ctl_req->wValue),
le16_to_cpu(dev->ctl_req->wIndex),
dev->ctl_data,
USB_PKT_LEN, USB_CTRL_SET_TIMEOUT);
if (error && error != EINTR)
err("%s: usb_control_msg() failed %d", __func__, error);
}
static void cm109_stop_traffic(struct cm109_dev *dev)
{
dev->shutdown = 1;
/*
* Make sure other CPUs see this
*/
smp_wmb();
usb_kill_urb(dev->urb_ctl);
usb_kill_urb(dev->urb_irq);
cm109_toggle_buzzer_sync(dev, 0);
dev->shutdown = 0;
smp_wmb();
}
static void cm109_restore_state(struct cm109_dev *dev)
{
if (dev->open) {
/*
* Restore buzzer state.
* This will also kick regular URB submission
*/
cm109_toggle_buzzer_async(dev);
}
}
/******************************************************************************
* input event interface
*****************************************************************************/
static int cm109_input_open(struct input_dev *idev)
{
struct cm109_dev *dev = input_get_drvdata(idev);
int error;
error = usb_autopm_get_interface(dev->intf);
if (error < 0) {
err("%s - cannot autoresume, result %d",
__func__, error);
return error;
}
mutex_lock(&dev->pm_mutex);
dev->buzzer_state = 0;
dev->key_code = -1; /* no keys pressed */
dev->keybit = 0xf;
/* issue INIT */
dev->ctl_data->byte[HID_OR0] = HID_OR_GPO_BUZ_SPDIF;
dev->ctl_data->byte[HID_OR1] = dev->keybit;
dev->ctl_data->byte[HID_OR2] = dev->keybit;
dev->ctl_data->byte[HID_OR3] = 0x00;
error = usb_submit_urb(dev->urb_ctl, GFP_KERNEL);
if (error)
err("%s: usb_submit_urb (urb_ctl) failed %d", __func__, error);
else
dev->open = 1;
mutex_unlock(&dev->pm_mutex);
if (error)
usb_autopm_put_interface(dev->intf);
return error;
}
static void cm109_input_close(struct input_dev *idev)
{
struct cm109_dev *dev = input_get_drvdata(idev);
mutex_lock(&dev->pm_mutex);
/*
* Once we are here event delivery is stopped so we
* don't need to worry about someone starting buzzer
* again
*/
cm109_stop_traffic(dev);
dev->open = 0;
mutex_unlock(&dev->pm_mutex);
usb_autopm_put_interface(dev->intf);
}
static int cm109_input_ev(struct input_dev *idev, unsigned int type,
unsigned int code, int value)
{
struct cm109_dev *dev = input_get_drvdata(idev);
dev_dbg(&dev->udev->dev,
"input_ev: type=%u code=%u value=%d\n", type, code, value);
if (type != EV_SND)
return -EINVAL;
switch (code) {
case SND_TONE:
case SND_BELL:
dev->buzzer_state = !!value;
if (!dev->resetting)
cm109_toggle_buzzer_async(dev);
return 0;
default:
return -EINVAL;
}
}
/******************************************************************************
* Linux interface and usb initialisation
*****************************************************************************/
struct driver_info {
char *name;
};
static const struct driver_info info_cm109 = {
.name = "CM109 USB driver",
};
enum {
VENDOR_ID = 0x0d8c, /* C-Media Electronics */
PRODUCT_ID_CM109 = 0x000e, /* CM109 defines range 0x0008 - 0x000f */
};
/* table of devices that work with this driver */
static const struct usb_device_id cm109_usb_table[] = {
{
.match_flags = USB_DEVICE_ID_MATCH_DEVICE |
USB_DEVICE_ID_MATCH_INT_INFO,
.idVendor = VENDOR_ID,
.idProduct = PRODUCT_ID_CM109,
.bInterfaceClass = USB_CLASS_HID,
.bInterfaceSubClass = 0,
.bInterfaceProtocol = 0,
.driver_info = (kernel_ulong_t) &info_cm109
},
/* you can add more devices here with product ID 0x0008 - 0x000f */
{ }
};
static void cm109_usb_cleanup(struct cm109_dev *dev)
{
if (dev->ctl_req)
usb_buffer_free(dev->udev, sizeof(*(dev->ctl_req)),
dev->ctl_req, dev->ctl_req_dma);
if (dev->ctl_data)
usb_buffer_free(dev->udev, USB_PKT_LEN,
dev->ctl_data, dev->ctl_dma);
if (dev->irq_data)
usb_buffer_free(dev->udev, USB_PKT_LEN,
dev->irq_data, dev->irq_dma);
usb_free_urb(dev->urb_irq); /* parameter validation in core/urb */
usb_free_urb(dev->urb_ctl); /* parameter validation in core/urb */
kfree(dev);
}
static void cm109_usb_disconnect(struct usb_interface *interface)
{
struct cm109_dev *dev = usb_get_intfdata(interface);
usb_set_intfdata(interface, NULL);
input_unregister_device(dev->idev);
cm109_usb_cleanup(dev);
}
static int cm109_usb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct driver_info *nfo = (struct driver_info *)id->driver_info;
struct usb_host_interface *interface;
struct usb_endpoint_descriptor *endpoint;
struct cm109_dev *dev;
struct input_dev *input_dev = NULL;
int ret, pipe, i;
int error = -ENOMEM;
interface = intf->cur_altsetting;
endpoint = &interface->endpoint[0].desc;
if (!usb_endpoint_is_int_in(endpoint))
return -ENODEV;
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (!dev)
return -ENOMEM;
spin_lock_init(&dev->ctl_submit_lock);
mutex_init(&dev->pm_mutex);
dev->udev = udev;
dev->intf = intf;
dev->idev = input_dev = input_allocate_device();
if (!input_dev)
goto err_out;
/* allocate usb buffers */
dev->irq_data = usb_buffer_alloc(udev, USB_PKT_LEN,
GFP_KERNEL, &dev->irq_dma);
if (!dev->irq_data)
goto err_out;
dev->ctl_data = usb_buffer_alloc(udev, USB_PKT_LEN,
GFP_KERNEL, &dev->ctl_dma);
if (!dev->ctl_data)
goto err_out;
dev->ctl_req = usb_buffer_alloc(udev, sizeof(*(dev->ctl_req)),
GFP_KERNEL, &dev->ctl_req_dma);
if (!dev->ctl_req)
goto err_out;
/* allocate urb structures */
dev->urb_irq = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->urb_irq)
goto err_out;
dev->urb_ctl = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->urb_ctl)
goto err_out;
/* get a handle to the interrupt data pipe */
pipe = usb_rcvintpipe(udev, endpoint->bEndpointAddress);
ret = usb_maxpacket(udev, pipe, usb_pipeout(pipe));
if (ret != USB_PKT_LEN)
err("invalid payload size %d, expected %d", ret, USB_PKT_LEN);
/* initialise irq urb */
usb_fill_int_urb(dev->urb_irq, udev, pipe, dev->irq_data,
USB_PKT_LEN,
cm109_urb_irq_callback, dev, endpoint->bInterval);
dev->urb_irq->transfer_dma = dev->irq_dma;
dev->urb_irq->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
dev->urb_irq->dev = udev;
/* initialise ctl urb */
dev->ctl_req->bRequestType = USB_TYPE_CLASS | USB_RECIP_INTERFACE |
USB_DIR_OUT;
dev->ctl_req->bRequest = USB_REQ_SET_CONFIGURATION;
dev->ctl_req->wValue = cpu_to_le16(0x200);
dev->ctl_req->wIndex = cpu_to_le16(interface->desc.bInterfaceNumber);
dev->ctl_req->wLength = cpu_to_le16(USB_PKT_LEN);
usb_fill_control_urb(dev->urb_ctl, udev, usb_sndctrlpipe(udev, 0),
(void *)dev->ctl_req, dev->ctl_data, USB_PKT_LEN,
cm109_urb_ctl_callback, dev);
dev->urb_ctl->setup_dma = dev->ctl_req_dma;
dev->urb_ctl->transfer_dma = dev->ctl_dma;
dev->urb_ctl->transfer_flags |= URB_NO_SETUP_DMA_MAP |
URB_NO_TRANSFER_DMA_MAP;
dev->urb_ctl->dev = udev;
/* find out the physical bus location */
usb_make_path(udev, dev->phys, sizeof(dev->phys));
strlcat(dev->phys, "/input0", sizeof(dev->phys));
/* register settings for the input device */
input_dev->name = nfo->name;
input_dev->phys = dev->phys;
usb_to_input_id(udev, &input_dev->id);
input_dev->dev.parent = &intf->dev;
input_set_drvdata(input_dev, dev);
input_dev->open = cm109_input_open;
input_dev->close = cm109_input_close;
input_dev->event = cm109_input_ev;
input_dev->keycode = dev->keymap;
input_dev->keycodesize = sizeof(unsigned char);
input_dev->keycodemax = ARRAY_SIZE(dev->keymap);
input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_SND);
input_dev->sndbit[0] = BIT_MASK(SND_BELL) | BIT_MASK(SND_TONE);
/* register available key events */
for (i = 0; i < KEYMAP_SIZE; i++) {
unsigned short k = keymap(i);
dev->keymap[i] = k;
__set_bit(k, input_dev->keybit);
}
__clear_bit(KEY_RESERVED, input_dev->keybit);
error = input_register_device(dev->idev);
if (error)
goto err_out;
usb_set_intfdata(intf, dev);
return 0;
err_out:
input_free_device(input_dev);
cm109_usb_cleanup(dev);
return error;
}
static int cm109_usb_suspend(struct usb_interface *intf, pm_message_t message)
{
struct cm109_dev *dev = usb_get_intfdata(intf);
dev_info(&intf->dev, "cm109: usb_suspend (event=%d)\n", message.event);
mutex_lock(&dev->pm_mutex);
cm109_stop_traffic(dev);
mutex_unlock(&dev->pm_mutex);
return 0;
}
static int cm109_usb_resume(struct usb_interface *intf)
{
struct cm109_dev *dev = usb_get_intfdata(intf);
dev_info(&intf->dev, "cm109: usb_resume\n");
mutex_lock(&dev->pm_mutex);
cm109_restore_state(dev);
mutex_unlock(&dev->pm_mutex);
return 0;
}
static int cm109_usb_pre_reset(struct usb_interface *intf)
{
struct cm109_dev *dev = usb_get_intfdata(intf);
mutex_lock(&dev->pm_mutex);
/*
* Make sure input events don't try to toggle buzzer
* while we are resetting
*/
dev->resetting = 1;
smp_wmb();
cm109_stop_traffic(dev);
return 0;
}
static int cm109_usb_post_reset(struct usb_interface *intf)
{
struct cm109_dev *dev = usb_get_intfdata(intf);
dev->resetting = 0;
smp_wmb();
cm109_restore_state(dev);
mutex_unlock(&dev->pm_mutex);
return 0;
}
static struct usb_driver cm109_driver = {
.name = "cm109",
.probe = cm109_usb_probe,
.disconnect = cm109_usb_disconnect,
.suspend = cm109_usb_suspend,
.resume = cm109_usb_resume,
.reset_resume = cm109_usb_resume,
.pre_reset = cm109_usb_pre_reset,
.post_reset = cm109_usb_post_reset,
.id_table = cm109_usb_table,
.supports_autosuspend = 1,
};
static int __init cm109_select_keymap(void)
{
/* Load the phone keymap */
if (!strcasecmp(phone, "kip1000")) {
keymap = keymap_kip1000;
printk(KERN_INFO KBUILD_MODNAME ": "
"Keymap for Komunikate KIP1000 phone loaded\n");
} else if (!strcasecmp(phone, "gtalk")) {
keymap = keymap_gtalk;
printk(KERN_INFO KBUILD_MODNAME ": "
"Keymap for Genius G-talk phone loaded\n");
} else if (!strcasecmp(phone, "usbph01")) {
keymap = keymap_usbph01;
printk(KERN_INFO KBUILD_MODNAME ": "
"Keymap for Allied-Telesis Corega USBPH01 phone loaded\n");
} else {
printk(KERN_ERR KBUILD_MODNAME ": "
"Unsupported phone: %s\n", phone);
return -EINVAL;
}
return 0;
}
static int __init cm109_init(void)
{
int err;
err = cm109_select_keymap();
if (err)
return err;
err = usb_register(&cm109_driver);
if (err)
return err;
printk(KERN_INFO KBUILD_MODNAME ": "
DRIVER_DESC ": " DRIVER_VERSION " (C) " DRIVER_AUTHOR "\n");
return 0;
}
static void __exit cm109_exit(void)
{
usb_deregister(&cm109_driver);
}
module_init(cm109_init);
module_exit(cm109_exit);
MODULE_DEVICE_TABLE(usb, cm109_usb_table);
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE("GPL");

View file

@ -277,6 +277,16 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = {
{ KE_END, 0 }
};
static struct key_entry keymap_fs_amilo_pro_v3505[] __initdata = {
{ KE_KEY, 0x01, {KEY_HELP} }, /* Fn+F1 */
{ KE_KEY, 0x06, {KEY_DISPLAYTOGGLE} }, /* Fn+F4 */
{ KE_BLUETOOTH, 0x30 }, /* Fn+F10 */
{ KE_KEY, 0x31, {KEY_MAIL} }, /* mail button */
{ KE_KEY, 0x36, {KEY_WWW} }, /* www button */
{ KE_WIFI, 0x78 }, /* satelite dish button */
{ KE_END, 0 }
};
static struct key_entry keymap_fujitsu_n3510[] __initdata = {
{ KE_KEY, 0x11, {KEY_PROG1} },
{ KE_KEY, 0x12, {KEY_PROG2} },
@ -616,6 +626,15 @@ static struct dmi_system_id dmi_ids[] __initdata = {
},
.driver_data = keymap_fs_amilo_pro_v2000
},
{
.callback = dmi_matched,
.ident = "Fujitsu-Siemens Amilo Pro Edition V3505",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"),
DMI_MATCH(DMI_PRODUCT_NAME, "AMILO Pro Edition V3505"),
},
.driver_data = keymap_fs_amilo_pro_v3505
},
{
.callback = dmi_matched,
.ident = "Fujitsu-Siemens Amilo M7400",

View file

@ -52,8 +52,8 @@
#include <linux/module.h>
#include <linux/rwsem.h>
#include <linux/usb/input.h>
#include <linux/map_to_7segment.h>
#include "map_to_7segment.h"
#include "yealink.h"
#define DRIVER_VERSION "yld-20051230"

View file

@ -96,6 +96,16 @@ config MOUSE_PS2_TOUCHKIT
If unsure, say N.
config MOUSE_PS2_OLPC
bool "OLPC PS/2 mouse protocol extension"
depends on MOUSE_PS2 && OLPC
help
Say Y here if you have an OLPC XO-1 laptop (with built-in
PS/2 touchpad/tablet device). The manufacturer calls the
touchpad an HGPK.
If unsure, say N.
config MOUSE_SERIAL
tristate "Serial mouse"
select SERIO

View file

@ -21,6 +21,7 @@ obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
psmouse-objs := psmouse-base.o synaptics.o
psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.o
psmouse-$(CONFIG_MOUSE_PS2_OLPC) += hgpk.o
psmouse-$(CONFIG_MOUSE_PS2_LOGIPS2PP) += logips2pp.o
psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o

View file

@ -54,6 +54,7 @@ static const struct alps_model_info alps_model_data[] = {
{ { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */
{ { 0x62, 0x02, 0x14 }, 0xcf, 0xcf, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude E6500 */
{ { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 } /* Dell Vostro 1400 */
};

View file

@ -136,12 +136,28 @@ MODULE_DEVICE_TABLE(usb, atp_table);
#define ATP_GEYSER_MODE_REQUEST_INDEX 0
#define ATP_GEYSER_MODE_VENDOR_VALUE 0x04
/**
* enum atp_status_bits - status bit meanings
*
* These constants represent the meaning of the status bits.
* (only Geyser 3/4)
*
* @ATP_STATUS_BUTTON: The button was pressed
* @ATP_STATUS_BASE_UPDATE: Update of the base values (untouched pad)
* @ATP_STATUS_FROM_RESET: Reset previously performed
*/
enum atp_status_bits {
ATP_STATUS_BUTTON = BIT(0),
ATP_STATUS_BASE_UPDATE = BIT(2),
ATP_STATUS_FROM_RESET = BIT(4),
};
/* Structure to hold all of our device specific stuff */
struct atp {
char phys[64];
struct usb_device *udev; /* usb device */
struct urb *urb; /* usb request block */
signed char *data; /* transferred data */
u8 *data; /* transferred data */
struct input_dev *input; /* input dev */
enum atp_touchpad_type type; /* type of touchpad */
bool open;
@ -251,8 +267,6 @@ static void atp_reinit(struct work_struct *work)
int retval;
dprintk("appletouch: putting appletouch to sleep (reinit)\n");
dev->idlecount = 0;
atp_geyser_init(udev);
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
@ -327,11 +341,14 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers)
input_report_key(input, BTN_TOOL_TRIPLETAP, fingers > 2);
}
static void atp_complete(struct urb *urb)
/* Check URB status and for correct length of data package */
#define ATP_URB_STATUS_SUCCESS 0
#define ATP_URB_STATUS_ERROR 1
#define ATP_URB_STATUS_ERROR_FATAL 2
static int atp_status_check(struct urb *urb)
{
int x, y, x_z, y_z, x_f, y_f;
int retval, i, j;
int key;
struct atp *dev = urb->context;
switch (urb->status) {
@ -351,11 +368,12 @@ static void atp_complete(struct urb *urb)
/* This urb is terminated, clean up */
dbg("atp_complete: urb shutting down with status: %d",
urb->status);
return;
return ATP_URB_STATUS_ERROR_FATAL;
default:
dbg("atp_complete: nonzero urb status received: %d",
urb->status);
goto exit;
return ATP_URB_STATUS_ERROR;
}
/* drop incomplete datasets */
@ -363,30 +381,33 @@ static void atp_complete(struct urb *urb)
dprintk("appletouch: incomplete data package"
" (first byte: %d, length: %d).\n",
dev->data[0], dev->urb->actual_length);
goto exit;
return ATP_URB_STATUS_ERROR;
}
return ATP_URB_STATUS_SUCCESS;
}
/*
* USB interrupt callback functions
*/
/* Interrupt function for older touchpads: FOUNTAIN/GEYSER1/GEYSER2 */
static void atp_complete_geyser_1_2(struct urb *urb)
{
int x, y, x_z, y_z, x_f, y_f;
int retval, i, j;
int key;
struct atp *dev = urb->context;
int status = atp_status_check(urb);
if (status == ATP_URB_STATUS_ERROR_FATAL)
return;
else if (status == ATP_URB_STATUS_ERROR)
goto exit;
/* reorder the sensors values */
if (dev->type == ATP_GEYSER3 || dev->type == ATP_GEYSER4) {
memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
/*
* The values are laid out like this:
* -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ...
* '-' is an unused value.
*/
/* read X values */
for (i = 0, j = 19; i < 20; i += 2, j += 3) {
dev->xy_cur[i] = dev->data[j + 1];
dev->xy_cur[i + 1] = dev->data[j + 2];
}
/* read Y values */
for (i = 0, j = 1; i < 9; i += 2, j += 3) {
dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1];
dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2];
}
} else if (dev->type == ATP_GEYSER2) {
if (dev->type == ATP_GEYSER2) {
memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
/*
@ -427,34 +448,40 @@ static void atp_complete(struct urb *urb)
/* first sample */
dev->valid = true;
dev->x_old = dev->y_old = -1;
/* Store first sample */
memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
if (dev->size_detect_done ||
dev->type == ATP_GEYSER3) /* No 17" Macbooks (yet) */
/* Perform size detection, if not done already */
if (!dev->size_detect_done) {
/* 17" Powerbooks have extra X sensors */
for (i = (dev->type == ATP_GEYSER2 ? 15 : 16);
i < ATP_XSENSORS; i++) {
if (!dev->xy_cur[i])
continue;
printk(KERN_INFO
"appletouch: 17\" model detected.\n");
if (dev->type == ATP_GEYSER2)
input_set_abs_params(dev->input, ABS_X,
0,
(20 - 1) *
ATP_XFACT - 1,
ATP_FUZZ, 0);
else
input_set_abs_params(dev->input, ABS_X,
0,
(26 - 1) *
ATP_XFACT - 1,
ATP_FUZZ, 0);
break;
}
dev->size_detect_done = 1;
goto exit;
/* 17" Powerbooks have extra X sensors */
for (i = (dev->type == ATP_GEYSER2 ? 15 : 16);
i < ATP_XSENSORS; i++) {
if (!dev->xy_cur[i])
continue;
printk(KERN_INFO "appletouch: 17\" model detected.\n");
if (dev->type == ATP_GEYSER2)
input_set_abs_params(dev->input, ABS_X, 0,
(20 - 1) *
ATP_XFACT - 1,
ATP_FUZZ, 0);
else
input_set_abs_params(dev->input, ABS_X, 0,
(ATP_XSENSORS - 1) *
ATP_XFACT - 1,
ATP_FUZZ, 0);
break;
}
dev->size_detect_done = 1;
goto exit;
}
for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
@ -475,7 +502,118 @@ static void atp_complete(struct urb *urb)
ATP_XFACT, &x_z, &x_f);
y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
ATP_YFACT, &y_z, &y_f);
key = dev->data[dev->datalen - 1] & 1;
key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON;
if (x && y) {
if (dev->x_old != -1) {
x = (dev->x_old * 3 + x) >> 2;
y = (dev->y_old * 3 + y) >> 2;
dev->x_old = x;
dev->y_old = y;
if (debug > 1)
printk(KERN_DEBUG "appletouch: "
"X: %3d Y: %3d Xz: %3d Yz: %3d\n",
x, y, x_z, y_z);
input_report_key(dev->input, BTN_TOUCH, 1);
input_report_abs(dev->input, ABS_X, x);
input_report_abs(dev->input, ABS_Y, y);
input_report_abs(dev->input, ABS_PRESSURE,
min(ATP_PRESSURE, x_z + y_z));
atp_report_fingers(dev->input, max(x_f, y_f));
}
dev->x_old = x;
dev->y_old = y;
} else if (!x && !y) {
dev->x_old = dev->y_old = -1;
input_report_key(dev->input, BTN_TOUCH, 0);
input_report_abs(dev->input, ABS_PRESSURE, 0);
atp_report_fingers(dev->input, 0);
/* reset the accumulator on release */
memset(dev->xy_acc, 0, sizeof(dev->xy_acc));
}
input_report_key(dev->input, BTN_LEFT, key);
input_sync(dev->input);
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
if (retval)
err("atp_complete: usb_submit_urb failed with result %d",
retval);
}
/* Interrupt function for older touchpads: GEYSER3/GEYSER4 */
static void atp_complete_geyser_3_4(struct urb *urb)
{
int x, y, x_z, y_z, x_f, y_f;
int retval, i, j;
int key;
struct atp *dev = urb->context;
int status = atp_status_check(urb);
if (status == ATP_URB_STATUS_ERROR_FATAL)
return;
else if (status == ATP_URB_STATUS_ERROR)
goto exit;
/* Reorder the sensors values:
*
* The values are laid out like this:
* -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ...
* '-' is an unused value.
*/
/* read X values */
for (i = 0, j = 19; i < 20; i += 2, j += 3) {
dev->xy_cur[i] = dev->data[j + 1];
dev->xy_cur[i + 1] = dev->data[j + 2];
}
/* read Y values */
for (i = 0, j = 1; i < 9; i += 2, j += 3) {
dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1];
dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2];
}
dbg_dump("sample", dev->xy_cur);
/* Just update the base values (i.e. touchpad in untouched state) */
if (dev->data[dev->datalen - 1] & ATP_STATUS_BASE_UPDATE) {
dprintk(KERN_DEBUG "appletouch: updated base values\n");
memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
goto exit;
}
for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
/* calculate the change */
dev->xy_acc[i] = dev->xy_cur[i] - dev->xy_old[i];
/* this is a round-robin value, so couple with that */
if (dev->xy_acc[i] > 127)
dev->xy_acc[i] -= 256;
if (dev->xy_acc[i] < -127)
dev->xy_acc[i] += 256;
/* prevent down drifting */
if (dev->xy_acc[i] < 0)
dev->xy_acc[i] = 0;
}
dbg_dump("accumulator", dev->xy_acc);
x = atp_calculate_abs(dev->xy_acc, ATP_XSENSORS,
ATP_XFACT, &x_z, &x_f);
y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
ATP_YFACT, &y_z, &y_f);
key = dev->data[dev->datalen - 1] & ATP_STATUS_BUTTON;
if (x && y) {
if (dev->x_old != -1) {
@ -514,28 +652,27 @@ static void atp_complete(struct urb *urb)
input_sync(dev->input);
/*
* Many Geysers will continue to send packets continually after
* Geysers 3/4 will continue to send packets continually after
* the first touch unless reinitialised. Do so if it's been
* idle for a while in order to avoid waking the kernel up
* several hundred times a second. Re-initialization does not
* work on Fountain touchpads.
* several hundred times a second.
*/
if (dev->type != ATP_FOUNTAIN) {
/*
* Button must not be pressed when entering suspend,
* otherwise we will never release the button.
*/
if (!x && !y && !key) {
dev->idlecount++;
if (dev->idlecount == 10) {
dev->valid = false;
schedule_work(&dev->work);
/* Don't resubmit urb here, wait for reinit */
return;
}
} else
/*
* Button must not be pressed when entering suspend,
* otherwise we will never release the button.
*/
if (!x && !y && !key) {
dev->idlecount++;
if (dev->idlecount == 10) {
dev->x_old = dev->y_old = -1;
dev->idlecount = 0;
}
schedule_work(&dev->work);
/* Don't resubmit urb here, wait for reinit */
return;
}
} else
dev->idlecount = 0;
exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
@ -632,9 +769,19 @@ static int atp_probe(struct usb_interface *iface,
if (!dev->data)
goto err_free_urb;
usb_fill_int_urb(dev->urb, udev,
usb_rcvintpipe(udev, int_in_endpointAddr),
dev->data, dev->datalen, atp_complete, dev, 1);
/* Select the USB complete (callback) function */
if (dev->type == ATP_FOUNTAIN ||
dev->type == ATP_GEYSER1 ||
dev->type == ATP_GEYSER2)
usb_fill_int_urb(dev->urb, udev,
usb_rcvintpipe(udev, int_in_endpointAddr),
dev->data, dev->datalen,
atp_complete_geyser_1_2, dev, 1);
else
usb_fill_int_urb(dev->urb, udev,
usb_rcvintpipe(udev, int_in_endpointAddr),
dev->data, dev->datalen,
atp_complete_geyser_3_4, dev, 1);
error = atp_handle_geyser(dev);
if (error)
@ -751,8 +898,6 @@ static int atp_suspend(struct usb_interface *iface, pm_message_t message)
struct atp *dev = usb_get_intfdata(iface);
usb_kill_urb(dev->urb);
dev->valid = false;
return 0;
}

477
drivers/input/mouse/hgpk.c Normal file
View file

@ -0,0 +1,477 @@
/*
* OLPC HGPK (XO-1) touchpad PS/2 mouse driver
*
* Copyright (c) 2006-2008 One Laptop Per Child
* Authors:
* Zephaniah E. Hull
* Andres Salomon <dilinger@debian.org>
*
* This driver is partly based on the ALPS driver, which is:
*
* Copyright (c) 2003 Neil Brown <neilb@cse.unsw.edu.au>
* Copyright (c) 2003-2005 Peter Osterlund <petero2@telia.com>
* Copyright (c) 2004 Dmitry Torokhov <dtor@mail.ru>
* Copyright (c) 2005 Vojtech Pavlik <vojtech@suse.cz>
*
* 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.
*/
/*
* The spec from ALPS is available from
* <http://wiki.laptop.org/go/Touch_Pad/Tablet>. It refers to this
* device as HGPK (Hybrid GS, PT, and Keymatrix).
*
* The earliest versions of the device had simultaneous reporting; that
* was removed. After that, the device used the Advanced Mode GS/PT streaming
* stuff. That turned out to be too buggy to support, so we've finally
* switched to Mouse Mode (which utilizes only the center 1/3 of the touchpad).
*/
#define DEBUG
#include <linux/input.h>
#include <linux/serio.h>
#include <linux/libps2.h>
#include <linux/delay.h>
#include <asm/olpc.h>
#include "psmouse.h"
#include "hgpk.h"
static int tpdebug;
module_param(tpdebug, int, 0644);
MODULE_PARM_DESC(tpdebug, "enable debugging, dumping packets to KERN_DEBUG.");
static int recalib_delta = 100;
module_param(recalib_delta, int, 0644);
MODULE_PARM_DESC(recalib_delta,
"packets containing a delta this large will cause a recalibration.");
/*
* When the touchpad gets ultra-sensitive, one can keep their finger 1/2"
* above the pad and still have it send packets. This causes a jump cursor
* when one places their finger on the pad. We can probably detect the
* jump as we see a large deltas (>= 100px). In mouse mode, I've been
* unable to even come close to 100px deltas during normal usage, so I think
* this threshold is safe. If a large delta occurs, trigger a recalibration.
*/
static void hgpk_jumpy_hack(struct psmouse *psmouse, int x, int y)
{
struct hgpk_data *priv = psmouse->private;
if (abs(x) > recalib_delta || abs(y) > recalib_delta) {
hgpk_err(psmouse, ">%dpx jump detected (%d,%d)\n",
recalib_delta, x, y);
/* My car gets forty rods to the hogshead and that's the
* way I likes it! */
psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(1000));
}
}
/*
* We have no idea why this particular hardware bug occurs. The touchpad
* will randomly start spewing packets without anything touching the
* pad. This wouldn't necessarily be bad, but it's indicative of a
* severely miscalibrated pad; attempting to use the touchpad while it's
* spewing means the cursor will jump all over the place, and act "drunk".
*
* The packets that are spewed tend to all have deltas between -2 and 2, and
* the cursor will move around without really going very far. It will
* tend to end up in the same location; if we tally up the changes over
* 100 packets, we end up w/ a final delta of close to 0. This happens
* pretty regularly when the touchpad is spewing, and is pretty hard to
* manually trigger (at least for *my* fingers). So, it makes a perfect
* scheme for detecting spews.
*/
static void hgpk_spewing_hack(struct psmouse *psmouse,
int l, int r, int x, int y)
{
struct hgpk_data *priv = psmouse->private;
/* ignore button press packets; many in a row could trigger
* a false-positive! */
if (l || r)
return;
priv->x_tally += x;
priv->y_tally += y;
if (++priv->count > 100) {
if (abs(priv->x_tally) < 3 && abs(priv->y_tally) < 3) {
hgpk_dbg(psmouse, "packet spew detected (%d,%d)\n",
priv->x_tally, priv->y_tally);
psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(1000));
}
/* reset every 100 packets */
priv->count = 0;
priv->x_tally = 0;
priv->y_tally = 0;
}
}
/*
* HGPK Mouse Mode format (standard mouse format, sans middle button)
*
* byte 0: y-over x-over y-neg x-neg 1 0 swr swl
* byte 1: x7 x6 x5 x4 x3 x2 x1 x0
* byte 2: y7 y6 y5 y4 y3 y2 y1 y0
*
* swr/swl are the left/right buttons.
* x-neg/y-neg are the x and y delta negative bits
* x-over/y-over are the x and y overflow bits
*/
static int hgpk_validate_byte(unsigned char *packet)
{
return (packet[0] & 0x0C) == 0x08;
}
static void hgpk_process_packet(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
unsigned char *packet = psmouse->packet;
int x, y, left, right;
left = packet[0] & 1;
right = (packet[0] >> 1) & 1;
x = packet[1] - ((packet[0] << 4) & 0x100);
y = ((packet[0] << 3) & 0x100) - packet[2];
hgpk_jumpy_hack(psmouse, x, y);
hgpk_spewing_hack(psmouse, left, right, x, y);
if (tpdebug)
hgpk_dbg(psmouse, "l=%d r=%d x=%d y=%d\n", left, right, x, y);
input_report_key(dev, BTN_LEFT, left);
input_report_key(dev, BTN_RIGHT, right);
input_report_rel(dev, REL_X, x);
input_report_rel(dev, REL_Y, y);
input_sync(dev);
}
static psmouse_ret_t hgpk_process_byte(struct psmouse *psmouse)
{
struct hgpk_data *priv = psmouse->private;
if (hgpk_validate_byte(psmouse->packet)) {
hgpk_dbg(psmouse, "%s: (%d) %02x %02x %02x\n",
__func__, psmouse->pktcnt, psmouse->packet[0],
psmouse->packet[1], psmouse->packet[2]);
return PSMOUSE_BAD_DATA;
}
if (psmouse->pktcnt >= psmouse->pktsize) {
hgpk_process_packet(psmouse);
return PSMOUSE_FULL_PACKET;
}
if (priv->recalib_window) {
if (time_before(jiffies, priv->recalib_window)) {
/*
* ugh, got a packet inside our recalibration
* window, schedule another recalibration.
*/
hgpk_dbg(psmouse,
"packet inside calibration window, "
"queueing another recalibration\n");
psmouse_queue_work(psmouse, &priv->recalib_wq,
msecs_to_jiffies(1000));
}
priv->recalib_window = 0;
}
return PSMOUSE_GOOD_DATA;
}
static int hgpk_force_recalibrate(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
struct hgpk_data *priv = psmouse->private;
/* C-series touchpads added the recalibrate command */
if (psmouse->model < HGPK_MODEL_C)
return 0;
/* we don't want to race with the irq handler, nor with resyncs */
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
/* start by resetting the device */
psmouse_reset(psmouse);
/* send the recalibrate request */
if (ps2_command(ps2dev, NULL, 0xf5) ||
ps2_command(ps2dev, NULL, 0xf5) ||
ps2_command(ps2dev, NULL, 0xe6) ||
ps2_command(ps2dev, NULL, 0xf5)) {
return -1;
}
/* according to ALPS, 150mS is required for recalibration */
msleep(150);
/* XXX: If a finger is down during this delay, recalibration will
* detect capacitance incorrectly. This is a hardware bug, and
* we don't have a good way to deal with it. The 2s window stuff
* (below) is our best option for now.
*/
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_ENABLE))
return -1;
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
/* After we recalibrate, we shouldn't get any packets for 2s. If
* we do, it's likely that someone's finger was on the touchpad.
* If someone's finger *was* on the touchpad, it's probably
* miscalibrated. So, we should schedule another recalibration
*/
priv->recalib_window = jiffies + msecs_to_jiffies(2000);
return 0;
}
/*
* This kills power to the touchpad; according to ALPS, current consumption
* goes down to 50uA after running this. To turn power back on, we drive
* MS-DAT low.
*/
static int hgpk_toggle_power(struct psmouse *psmouse, int enable)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
int timeo;
/* Added on D-series touchpads */
if (psmouse->model < HGPK_MODEL_D)
return 0;
if (enable) {
psmouse_set_state(psmouse, PSMOUSE_INITIALIZING);
/*
* Sending a byte will drive MS-DAT low; this will wake up
* the controller. Once we get an ACK back from it, it
* means we can continue with the touchpad re-init. ALPS
* tells us that 1s should be long enough, so set that as
* the upper bound.
*/
for (timeo = 20; timeo > 0; timeo--) {
if (!ps2_sendbyte(&psmouse->ps2dev,
PSMOUSE_CMD_DISABLE, 20))
break;
msleep(50);
}
psmouse_reset(psmouse);
/* should be all set, enable the touchpad */
ps2_command(&psmouse->ps2dev, NULL, PSMOUSE_CMD_ENABLE);
psmouse_set_state(psmouse, PSMOUSE_ACTIVATED);
} else {
hgpk_dbg(psmouse, "Powering off touchpad.\n");
psmouse_set_state(psmouse, PSMOUSE_IGNORE);
if (ps2_command(ps2dev, NULL, 0xec) ||
ps2_command(ps2dev, NULL, 0xec) ||
ps2_command(ps2dev, NULL, 0xea)) {
return -1;
}
/* probably won't see an ACK, the touchpad will be off */
ps2_sendbyte(&psmouse->ps2dev, 0xec, 20);
}
return 0;
}
static int hgpk_poll(struct psmouse *psmouse)
{
/* We can't poll, so always return failure. */
return -1;
}
static int hgpk_reconnect(struct psmouse *psmouse)
{
/* During suspend/resume the ps2 rails remain powered. We don't want
* to do a reset because it's flush data out of buffers; however,
* earlier prototypes (B1) had some brokenness that required a reset. */
if (olpc_board_at_least(olpc_board(0xb2)))
if (psmouse->ps2dev.serio->dev.power.power_state.event !=
PM_EVENT_ON)
return 0;
psmouse_reset(psmouse);
return 0;
}
static ssize_t hgpk_show_powered(struct psmouse *psmouse, void *data, char *buf)
{
struct hgpk_data *priv = psmouse->private;
return sprintf(buf, "%d\n", priv->powered);
}
static ssize_t hgpk_set_powered(struct psmouse *psmouse, void *data,
const char *buf, size_t count)
{
struct hgpk_data *priv = psmouse->private;
unsigned long value;
int err;
err = strict_strtoul(buf, 10, &value);
if (err || value > 1)
return -EINVAL;
if (value != priv->powered) {
/*
* hgpk_toggle_power will deal w/ state so
* we're not racing w/ irq
*/
err = hgpk_toggle_power(psmouse, value);
if (!err)
priv->powered = value;
}
return err ? err : count;
}
__PSMOUSE_DEFINE_ATTR(powered, S_IWUSR | S_IRUGO, NULL,
hgpk_show_powered, hgpk_set_powered, 0);
static void hgpk_disconnect(struct psmouse *psmouse)
{
struct hgpk_data *priv = psmouse->private;
device_remove_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_powered.dattr);
psmouse_reset(psmouse);
kfree(priv);
}
static void hgpk_recalib_work(struct work_struct *work)
{
struct delayed_work *w = container_of(work, struct delayed_work, work);
struct hgpk_data *priv = container_of(w, struct hgpk_data, recalib_wq);
struct psmouse *psmouse = priv->psmouse;
hgpk_dbg(psmouse, "recalibrating touchpad..\n");
if (hgpk_force_recalibrate(psmouse))
hgpk_err(psmouse, "recalibration failed!\n");
}
static int hgpk_register(struct psmouse *psmouse)
{
struct input_dev *dev = psmouse->dev;
int err;
/* unset the things that psmouse-base sets which we don't have */
__clear_bit(BTN_MIDDLE, dev->keybit);
/* set the things we do have */
__set_bit(EV_KEY, dev->evbit);
__set_bit(EV_REL, dev->evbit);
__set_bit(REL_X, dev->relbit);
__set_bit(REL_Y, dev->relbit);
__set_bit(BTN_LEFT, dev->keybit);
__set_bit(BTN_RIGHT, dev->keybit);
/* register handlers */
psmouse->protocol_handler = hgpk_process_byte;
psmouse->poll = hgpk_poll;
psmouse->disconnect = hgpk_disconnect;
psmouse->reconnect = hgpk_reconnect;
psmouse->pktsize = 3;
/* Disable the idle resync. */
psmouse->resync_time = 0;
/* Reset after a lot of bad bytes. */
psmouse->resetafter = 1024;
err = device_create_file(&psmouse->ps2dev.serio->dev,
&psmouse_attr_powered.dattr);
if (err)
hgpk_err(psmouse, "Failed to create sysfs attribute\n");
return err;
}
int hgpk_init(struct psmouse *psmouse)
{
struct hgpk_data *priv;
int err = -ENOMEM;
priv = kzalloc(sizeof(struct hgpk_data), GFP_KERNEL);
if (!priv)
goto alloc_fail;
psmouse->private = priv;
priv->psmouse = psmouse;
priv->powered = 1;
INIT_DELAYED_WORK(&priv->recalib_wq, hgpk_recalib_work);
err = psmouse_reset(psmouse);
if (err)
goto init_fail;
err = hgpk_register(psmouse);
if (err)
goto init_fail;
return 0;
init_fail:
kfree(priv);
alloc_fail:
return err;
}
static enum hgpk_model_t hgpk_get_model(struct psmouse *psmouse)
{
struct ps2dev *ps2dev = &psmouse->ps2dev;
unsigned char param[3];
/* E7, E7, E7, E9 gets us a 3 byte identifier */
if (ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
ps2_command(ps2dev, NULL, PSMOUSE_CMD_SETSCALE21) ||
ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
return -EIO;
}
hgpk_dbg(psmouse, "ID: %02x %02x %02x", param[0], param[1], param[2]);
/* HGPK signature: 0x67, 0x00, 0x<model> */
if (param[0] != 0x67 || param[1] != 0x00)
return -ENODEV;
hgpk_info(psmouse, "OLPC touchpad revision 0x%x\n", param[2]);
return param[2];
}
int hgpk_detect(struct psmouse *psmouse, int set_properties)
{
int version;
version = hgpk_get_model(psmouse);
if (version < 0)
return version;
if (set_properties) {
psmouse->vendor = "ALPS";
psmouse->name = "HGPK";
psmouse->model = version;
}
return 0;
}

View file

@ -0,0 +1,49 @@
/*
* OLPC HGPK (XO-1) touchpad PS/2 mouse driver
*/
#ifndef _HGPK_H
#define _HGPK_H
enum hgpk_model_t {
HGPK_MODEL_PREA = 0x0a, /* pre-B1s */
HGPK_MODEL_A = 0x14, /* found on B1s, PT disabled in hardware */
HGPK_MODEL_B = 0x28, /* B2s, has capacitance issues */
HGPK_MODEL_C = 0x3c,
HGPK_MODEL_D = 0x50, /* C1, mass production */
};
struct hgpk_data {
struct psmouse *psmouse;
int powered;
int count, x_tally, y_tally; /* hardware workaround stuff */
unsigned long recalib_window;
struct delayed_work recalib_wq;
};
#define hgpk_dbg(psmouse, format, arg...) \
dev_dbg(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#define hgpk_err(psmouse, format, arg...) \
dev_err(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#define hgpk_info(psmouse, format, arg...) \
dev_info(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#define hgpk_warn(psmouse, format, arg...) \
dev_warn(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#define hgpk_notice(psmouse, format, arg...) \
dev_notice(&(psmouse)->ps2dev.serio->dev, format, ## arg)
#ifdef CONFIG_MOUSE_PS2_OLPC
int hgpk_detect(struct psmouse *psmouse, int set_properties);
int hgpk_init(struct psmouse *psmouse);
#else
static inline int hgpk_detect(struct psmouse *psmouse, int set_properties)
{
return -ENODEV;
}
static inline int hgpk_init(struct psmouse *psmouse)
{
return -ENODEV;
}
#endif
#endif

View file

@ -157,10 +157,8 @@ static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, void *data,
static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{
unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10);
if (*rest || value > 1)
if (strict_strtoul(buf, 10, &value) || value > 1)
return -EINVAL;
ps2pp_set_smartscroll(psmouse, value);

View file

@ -25,6 +25,7 @@
#include "synaptics.h"
#include "logips2pp.h"
#include "alps.h"
#include "hgpk.h"
#include "lifebook.h"
#include "trackpoint.h"
#include "touchkit_ps2.h"
@ -201,6 +202,12 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
return PSMOUSE_FULL_PACKET;
}
void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
unsigned long delay)
{
queue_delayed_work(kpsmoused_wq, work, delay);
}
/*
* __psmouse_set_state() sets new psmouse state and resets all flags.
*/
@ -220,7 +227,7 @@ static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_sta
* is not a concern.
*/
static void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state)
{
serio_pause_rx(psmouse->ps2dev.serio);
__psmouse_set_state(psmouse, new_state);
@ -305,7 +312,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse->badbyte = psmouse->packet[0];
__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
queue_work(kpsmoused_wq, &psmouse->resync_work);
psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
goto out;
}
@ -342,7 +349,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) {
psmouse->badbyte = psmouse->packet[0];
__psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
queue_work(kpsmoused_wq, &psmouse->resync_work);
psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
goto out;
}
@ -630,8 +637,20 @@ static int psmouse_extensions(struct psmouse *psmouse,
}
}
if (max_proto > PSMOUSE_IMEX) {
/*
* Try OLPC HGPK touchpad.
*/
if (max_proto > PSMOUSE_IMEX &&
hgpk_detect(psmouse, set_properties) == 0) {
if (!set_properties || hgpk_init(psmouse) == 0)
return PSMOUSE_HGPK;
/*
* Init failed, try basic relative protocols
*/
max_proto = PSMOUSE_IMEX;
}
if (max_proto > PSMOUSE_IMEX) {
if (genius_detect(psmouse, set_properties) == 0)
return PSMOUSE_GENPS;
@ -761,6 +780,14 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.alias = "touchkit",
.detect = touchkit_ps2_detect,
},
#endif
#ifdef CONFIG_MOUSE_PS2_OLPC
{
.type = PSMOUSE_HGPK,
.name = "OLPC HGPK",
.alias = "hgpk",
.detect = hgpk_detect,
},
#endif
{
.type = PSMOUSE_CORTRON,
@ -935,7 +962,7 @@ static int psmouse_poll(struct psmouse *psmouse)
static void psmouse_resync(struct work_struct *work)
{
struct psmouse *parent = NULL, *psmouse =
container_of(work, struct psmouse, resync_work);
container_of(work, struct psmouse, resync_work.work);
struct serio *serio = psmouse->ps2dev.serio;
psmouse_ret_t rc = PSMOUSE_GOOD_DATA;
int failed = 0, enabled = 0;
@ -1194,7 +1221,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
goto err_free;
ps2_init(&psmouse->ps2dev, serio);
INIT_WORK(&psmouse->resync_work, psmouse_resync);
INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync);
psmouse->dev = input_dev;
snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys);
@ -1395,25 +1422,29 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev
psmouse = serio_get_drvdata(serio);
if (psmouse->state == PSMOUSE_IGNORE) {
retval = -ENODEV;
goto out_unlock;
}
if (attr->protect) {
if (psmouse->state == PSMOUSE_IGNORE) {
retval = -ENODEV;
goto out_unlock;
}
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent);
}
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent);
}
psmouse_deactivate(psmouse);
psmouse_deactivate(psmouse);
}
retval = attr->set(psmouse, attr->data, buf, count);
if (retval != -ENODEV)
psmouse_activate(psmouse);
if (attr->protect) {
if (retval != -ENODEV)
psmouse_activate(psmouse);
if (parent)
psmouse_activate(parent);
if (parent)
psmouse_activate(parent);
}
out_unlock:
mutex_unlock(&psmouse_mutex);
@ -1433,10 +1464,8 @@ static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const
{
unsigned int *field = (unsigned int *)((char *)psmouse + (size_t)offset);
unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10);
if (*rest)
if (strict_strtoul(buf, 10, &value))
return -EINVAL;
if ((unsigned int)value != value)
@ -1549,10 +1578,8 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co
static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{
unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10);
if (*rest)
if (strict_strtoul(buf, 10, &value))
return -EINVAL;
psmouse->set_rate(psmouse, value);
@ -1562,10 +1589,8 @@ static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const
static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{
unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10);
if (*rest)
if (strict_strtoul(buf, 10, &value))
return -EINVAL;
psmouse->set_resolution(psmouse, value);

View file

@ -39,7 +39,7 @@ struct psmouse {
void *private;
struct input_dev *dev;
struct ps2dev ps2dev;
struct work_struct resync_work;
struct delayed_work resync_work;
char *vendor;
char *name;
unsigned char packet[8];
@ -89,20 +89,24 @@ enum psmouse_type {
PSMOUSE_TRACKPOINT,
PSMOUSE_TOUCHKIT_PS2,
PSMOUSE_CORTRON,
PSMOUSE_HGPK,
PSMOUSE_AUTO /* This one should always be last */
};
void psmouse_queue_work(struct psmouse *psmouse, struct delayed_work *work,
unsigned long delay);
int psmouse_sliced_command(struct psmouse *psmouse, unsigned char command);
int psmouse_reset(struct psmouse *psmouse);
void psmouse_set_state(struct psmouse *psmouse, enum psmouse_state new_state);
void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
struct psmouse_attribute {
struct device_attribute dattr;
void *data;
ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf);
ssize_t (*set)(struct psmouse *psmouse, void *data,
const char *buf, size_t count);
int protect;
};
#define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr)
@ -111,7 +115,7 @@ ssize_t psmouse_attr_show_helper(struct device *dev, struct device_attribute *at
ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count);
#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \
#define __PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, _protect) \
static ssize_t _show(struct psmouse *, void *data, char *); \
static ssize_t _set(struct psmouse *, void *data, const char *, size_t); \
static struct psmouse_attribute psmouse_attr_##_name = { \
@ -126,6 +130,10 @@ static struct psmouse_attribute psmouse_attr_##_name = { \
.data = _data, \
.show = _show, \
.set = _set, \
.protect = _protect, \
}
#define PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set) \
__PSMOUSE_DEFINE_ATTR(_name, _mode, _data, _show, _set, 1)
#endif /* _PSMOUSE_H */

View file

@ -89,10 +89,8 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
struct trackpoint_attr_data *attr = data;
unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10);
if (*rest || value > 255)
if (strict_strtoul(buf, 10, &value) || value > 255)
return -EINVAL;
*field = value;
@ -117,10 +115,8 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
struct trackpoint_attr_data *attr = data;
unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10);
if (*rest || value > 1)
if (strict_strtoul(buf, 10, &value) || value > 1)
return -EINVAL;
if (attr->inverted)

View file

@ -322,6 +322,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"),
},
},
{
.ident = "IBM 2656",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
DMI_MATCH(DMI_PRODUCT_NAME, "2656"),
},
},
{ }
};

View file

@ -373,6 +373,12 @@ static struct serio_device_id serio_raw_serio_ids[] = {
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{
.type = SERIO_8042_XL,
.proto = SERIO_ANY,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 }
};

View file

@ -1202,16 +1202,22 @@ static ssize_t
store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct aiptek *aiptek = dev_get_drvdata(dev);
int x;
long x;
if (strict_strtol(buf, 10, &x)) {
size_t len = buf[count - 1] == '\n' ? count - 1 : count;
if (strncmp(buf, "disable", len))
return -EINVAL;
if (strcmp(buf, "disable") == 0) {
aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE;
} else {
x = (int)simple_strtol(buf, NULL, 10);
if (x >= AIPTEK_TILT_MIN && x <= AIPTEK_TILT_MAX) {
aiptek->newSetting.xTilt = x;
}
if (x < AIPTEK_TILT_MIN || x > AIPTEK_TILT_MAX)
return -EINVAL;
aiptek->newSetting.xTilt = x;
}
return count;
}
@ -1238,16 +1244,22 @@ static ssize_t
store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct aiptek *aiptek = dev_get_drvdata(dev);
int y;
long y;
if (strict_strtol(buf, 10, &y)) {
size_t len = buf[count - 1] == '\n' ? count - 1 : count;
if (strncmp(buf, "disable", len))
return -EINVAL;
if (strcmp(buf, "disable") == 0) {
aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE;
} else {
y = (int)simple_strtol(buf, NULL, 10);
if (y >= AIPTEK_TILT_MIN && y <= AIPTEK_TILT_MAX) {
aiptek->newSetting.yTilt = y;
}
if (y < AIPTEK_TILT_MIN || y > AIPTEK_TILT_MAX)
return -EINVAL;
aiptek->newSetting.yTilt = y;
}
return count;
}
@ -1269,8 +1281,12 @@ static ssize_t
store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct aiptek *aiptek = dev_get_drvdata(dev);
long j;
aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10);
if (strict_strtol(buf, 10, &j))
return -EINVAL;
aiptek->newSetting.jitterDelay = (int)j;
return count;
}
@ -1294,8 +1310,12 @@ static ssize_t
store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct aiptek *aiptek = dev_get_drvdata(dev);
long d;
aiptek->newSetting.programmableDelay = (int)simple_strtol(buf, NULL, 10);
if (strict_strtol(buf, 10, &d))
return -EINVAL;
aiptek->newSetting.programmableDelay = (int)d;
return count;
}
@ -1541,8 +1561,11 @@ static ssize_t
store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{
struct aiptek *aiptek = dev_get_drvdata(dev);
long w;
aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10);
if (strict_strtol(buf, 10, &w)) return -EINVAL;
aiptek->newSetting.wheel = (int)w;
return count;
}

View file

@ -69,6 +69,17 @@ struct ts_event {
int ignore;
};
/*
* We allocate this separately to avoid cache line sharing issues when
* driver is used with DMA-based SPI controllers (like atmel_spi) on
* systems where main memory is not DMA-coherent (most non-x86 boards).
*/
struct ads7846_packet {
u8 read_x, read_y, read_z1, read_z2, pwrdown;
u16 dummy; /* for the pwrdown read */
struct ts_event tc;
};
struct ads7846 {
struct input_dev *input;
char phys[32];
@ -86,9 +97,7 @@ struct ads7846 {
u16 x_plate_ohms;
u16 pressure_max;
u8 read_x, read_y, read_z1, read_z2, pwrdown;
u16 dummy; /* for the pwrdown read */
struct ts_event tc;
struct ads7846_packet *packet;
struct spi_transfer xfer[18];
struct spi_message msg[5];
@ -463,10 +472,11 @@ static ssize_t ads7846_disable_store(struct device *dev,
const char *buf, size_t count)
{
struct ads7846 *ts = dev_get_drvdata(dev);
char *endp;
int i;
long i;
if (strict_strtoul(buf, 10, &i))
return -EINVAL;
i = simple_strtoul(buf, &endp, 10);
spin_lock_irq(&ts->lock);
if (i)
@ -512,16 +522,17 @@ static int get_pendown_state(struct ads7846 *ts)
static void ads7846_rx(void *ads)
{
struct ads7846 *ts = ads;
struct ads7846_packet *packet = ts->packet;
unsigned Rt;
u16 x, y, z1, z2;
/* ads7846_rx_val() did in-place conversion (including byteswap) from
* on-the-wire format as part of debouncing to get stable readings.
*/
x = ts->tc.x;
y = ts->tc.y;
z1 = ts->tc.z1;
z2 = ts->tc.z2;
x = packet->tc.x;
y = packet->tc.y;
z1 = packet->tc.z1;
z2 = packet->tc.z2;
/* range filtering */
if (x == MAX_12BIT)
@ -545,10 +556,10 @@ static void ads7846_rx(void *ads)
* the maximum. Don't report it to user space, repeat at least
* once more the measurement
*/
if (ts->tc.ignore || Rt > ts->pressure_max) {
if (packet->tc.ignore || Rt > ts->pressure_max) {
#ifdef VERBOSE
pr_debug("%s: ignored %d pressure %d\n",
ts->spi->dev.bus_id, ts->tc.ignore, Rt);
ts->spi->dev.bus_id, packet->tc.ignore, Rt);
#endif
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
HRTIMER_MODE_REL);
@ -641,6 +652,7 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val)
static void ads7846_rx_val(void *ads)
{
struct ads7846 *ts = ads;
struct ads7846_packet *packet = ts->packet;
struct spi_message *m;
struct spi_transfer *t;
int val;
@ -660,7 +672,7 @@ static void ads7846_rx_val(void *ads)
case ADS7846_FILTER_REPEAT:
break;
case ADS7846_FILTER_IGNORE:
ts->tc.ignore = 1;
packet->tc.ignore = 1;
/* Last message will contain ads7846_rx() as the
* completion function.
*/
@ -668,7 +680,7 @@ static void ads7846_rx_val(void *ads)
break;
case ADS7846_FILTER_OK:
*(u16 *)t->rx_buf = val;
ts->tc.ignore = 0;
packet->tc.ignore = 0;
m = &ts->msg[++ts->msg_idx];
break;
default:
@ -773,7 +785,6 @@ static void ads7846_disable(struct ads7846 *ts)
/* we know the chip's in lowpower mode since we always
* leave it that way after every request
*/
}
/* Must be called with ts->lock held */
@ -849,6 +860,7 @@ static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
static int __devinit ads7846_probe(struct spi_device *spi)
{
struct ads7846 *ts;
struct ads7846_packet *packet;
struct input_dev *input_dev;
struct ads7846_platform_data *pdata = spi->dev.platform_data;
struct spi_message *m;
@ -884,14 +896,16 @@ static int __devinit ads7846_probe(struct spi_device *spi)
return err;
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
input_dev = input_allocate_device();
if (!ts || !input_dev) {
if (!ts || !packet || !input_dev) {
err = -ENOMEM;
goto err_free_mem;
}
dev_set_drvdata(&spi->dev, ts);
ts->packet = packet;
ts->spi = spi;
ts->input = input_dev;
ts->vref_mv = pdata->vref_mv;
@ -963,13 +977,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m);
/* y- still on; turn on only y+ (and ADC) */
ts->read_y = READ_Y(vref);
x->tx_buf = &ts->read_y;
packet->read_y = READ_Y(vref);
x->tx_buf = &packet->read_y;
x->len = 1;
spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.y;
x->rx_buf = &packet->tc.y;
x->len = 2;
spi_message_add_tail(x, m);
@ -981,12 +995,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->delay_usecs = pdata->settle_delay_usecs;
x++;
x->tx_buf = &ts->read_y;
x->tx_buf = &packet->read_y;
x->len = 1;
spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.y;
x->rx_buf = &packet->tc.y;
x->len = 2;
spi_message_add_tail(x, m);
}
@ -999,13 +1013,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
/* turn y- off, x+ on, then leave in lowpower */
x++;
ts->read_x = READ_X(vref);
x->tx_buf = &ts->read_x;
packet->read_x = READ_X(vref);
x->tx_buf = &packet->read_x;
x->len = 1;
spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.x;
x->rx_buf = &packet->tc.x;
x->len = 2;
spi_message_add_tail(x, m);
@ -1014,12 +1028,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->delay_usecs = pdata->settle_delay_usecs;
x++;
x->tx_buf = &ts->read_x;
x->tx_buf = &packet->read_x;
x->len = 1;
spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.x;
x->rx_buf = &packet->tc.x;
x->len = 2;
spi_message_add_tail(x, m);
}
@ -1033,13 +1047,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m);
x++;
ts->read_z1 = READ_Z1(vref);
x->tx_buf = &ts->read_z1;
packet->read_z1 = READ_Z1(vref);
x->tx_buf = &packet->read_z1;
x->len = 1;
spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.z1;
x->rx_buf = &packet->tc.z1;
x->len = 2;
spi_message_add_tail(x, m);
@ -1048,12 +1062,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->delay_usecs = pdata->settle_delay_usecs;
x++;
x->tx_buf = &ts->read_z1;
x->tx_buf = &packet->read_z1;
x->len = 1;
spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.z1;
x->rx_buf = &packet->tc.z1;
x->len = 2;
spi_message_add_tail(x, m);
}
@ -1065,13 +1079,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m);
x++;
ts->read_z2 = READ_Z2(vref);
x->tx_buf = &ts->read_z2;
packet->read_z2 = READ_Z2(vref);
x->tx_buf = &packet->read_z2;
x->len = 1;
spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.z2;
x->rx_buf = &packet->tc.z2;
x->len = 2;
spi_message_add_tail(x, m);
@ -1080,12 +1094,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->delay_usecs = pdata->settle_delay_usecs;
x++;
x->tx_buf = &ts->read_z2;
x->tx_buf = &packet->read_z2;
x->len = 1;
spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->tc.z2;
x->rx_buf = &packet->tc.z2;
x->len = 2;
spi_message_add_tail(x, m);
}
@ -1099,13 +1113,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m);
x++;
ts->pwrdown = PWRDOWN;
x->tx_buf = &ts->pwrdown;
packet->pwrdown = PWRDOWN;
x->tx_buf = &packet->pwrdown;
x->len = 1;
spi_message_add_tail(x, m);
x++;
x->rx_buf = &ts->dummy;
x->rx_buf = &packet->dummy;
x->len = 2;
CS_CHANGE(*x);
spi_message_add_tail(x, m);
@ -1158,6 +1172,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->filter_cleanup(ts->filter_data);
err_free_mem:
input_free_device(input_dev);
kfree(packet);
kfree(ts);
return err;
}
@ -1183,6 +1198,7 @@ static int __devexit ads7846_remove(struct spi_device *spi)
if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data);
kfree(ts->packet);
kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n");

View file

@ -91,6 +91,9 @@ struct atmel_tsadcc {
char phys[32];
struct clk *clk;
int irq;
unsigned int prev_absx;
unsigned int prev_absy;
unsigned char bufferedmeasure;
};
static void __iomem *tsc_base;
@ -100,10 +103,9 @@ static void __iomem *tsc_base;
static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
{
struct input_dev *input_dev = ((struct atmel_tsadcc *)dev)->input;
struct atmel_tsadcc *ts_dev = (struct atmel_tsadcc *)dev;
struct input_dev *input_dev = ts_dev->input;
unsigned int absx;
unsigned int absy;
unsigned int status;
unsigned int reg;
@ -121,6 +123,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
input_report_key(input_dev, BTN_TOUCH, 0);
ts_dev->bufferedmeasure = 0;
input_sync(input_dev);
} else if (status & ATMEL_TSADCC_PENCNT) {
@ -138,16 +141,23 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
} else if (status & ATMEL_TSADCC_EOC(3)) {
/* Conversion finished */
absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
if (ts_dev->bufferedmeasure) {
/* Last measurement is always discarded, since it can
* be erroneous.
* Always report previous measurement */
input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
input_report_key(input_dev, BTN_TOUCH, 1);
input_sync(input_dev);
} else
ts_dev->bufferedmeasure = 1;
absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
/* Now make new measurement */
ts_dev->prev_absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10;
ts_dev->prev_absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2);
input_report_abs(input_dev, ABS_X, absx);
input_report_abs(input_dev, ABS_Y, absy);
input_report_key(input_dev, BTN_TOUCH, 1);
input_sync(input_dev);
ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
}
return IRQ_HANDLED;
@ -223,6 +233,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
}
ts_dev->input = input_dev;
ts_dev->bufferedmeasure = 0;
snprintf(ts_dev->phys, sizeof(ts_dev->phys),
"%s/input0", pdev->dev.bus_id);

View file

@ -3,8 +3,7 @@
* Wolfson WM97xx AC97 Codecs.
*
* Copyright 2004, 2007 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
*
@ -296,6 +295,6 @@ module_init(mainstone_wm97xx_init);
module_exit(mainstone_wm97xx_exit);
/* Module information */
MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
MODULE_DESCRIPTION("wm97xx continuous touch driver for mainstone");
MODULE_LICENSE("GPL");

View file

@ -2,8 +2,7 @@
* wm9705.c -- Codec driver for Wolfson WM9705 AC97 Codec.
*
* Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
@ -347,6 +346,6 @@ struct wm97xx_codec_drv wm9705_codec = {
EXPORT_SYMBOL_GPL(wm9705_codec);
/* Module information */
MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
MODULE_DESCRIPTION("WM9705 Touch Screen Driver");
MODULE_LICENSE("GPL");

View file

@ -2,8 +2,7 @@
* wm9712.c -- Codec driver for Wolfson WM9712 AC97 Codecs.
*
* Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
@ -462,6 +461,6 @@ struct wm97xx_codec_drv wm9712_codec = {
EXPORT_SYMBOL_GPL(wm9712_codec);
/* Module information */
MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
MODULE_DESCRIPTION("WM9712 Touch Screen Driver");
MODULE_LICENSE("GPL");

View file

@ -2,8 +2,7 @@
* wm9713.c -- Codec touch driver for Wolfson WM9713 AC97 Codec.
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
@ -476,6 +475,6 @@ struct wm97xx_codec_drv wm9713_codec = {
EXPORT_SYMBOL_GPL(wm9713_codec);
/* Module information */
MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
MODULE_DESCRIPTION("WM9713 Touch Screen Driver");
MODULE_LICENSE("GPL");

View file

@ -3,8 +3,7 @@
* and WM9713 AC97 Codecs.
*
* Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
* Author: Liam Girdwood
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Author: Liam Girdwood <lrg@slimlogic.co.uk>
* Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk>
@ -824,6 +823,6 @@ module_init(wm97xx_init);
module_exit(wm97xx_exit);
/* Module information */
MODULE_AUTHOR("Liam Girdwood <liam.girdwood@wolfsonmicro.com>");
MODULE_AUTHOR("Liam Girdwood <lrg@slimlogic.co.uk>");
MODULE_DESCRIPTION("WM97xx Core - Touch Screen / AUX ADC / GPIO Driver");
MODULE_LICENSE("GPL");

View file

@ -107,6 +107,7 @@ header-y += keyctl.h
header-y += limits.h
header-y += magic.h
header-y += major.h
header-y += map_to_7segment.h
header-y += matroxfb.h
header-y += meye.h
header-y += minix_fs.h

View file

@ -146,10 +146,11 @@ static inline void gameport_unpin_driver(struct gameport *gameport)
mutex_unlock(&gameport->drv_mutex);
}
void __gameport_register_driver(struct gameport_driver *drv, struct module *owner);
static inline void gameport_register_driver(struct gameport_driver *drv)
int __gameport_register_driver(struct gameport_driver *drv,
struct module *owner, const char *mod_name);
static inline int __must_check gameport_register_driver(struct gameport_driver *drv)
{
__gameport_register_driver(drv, THIS_MODULE);
return __gameport_register_driver(drv, THIS_MODULE, KBUILD_MODNAME);
}
void gameport_unregister_driver(struct gameport_driver *drv);

View file

@ -577,9 +577,22 @@ struct input_absinfo {
#define KEY_BRL_DOT9 0x1f9
#define KEY_BRL_DOT10 0x1fa
#define KEY_NUMERIC_0 0x200 /* used by phones, remote controls, */
#define KEY_NUMERIC_1 0x201 /* and other keypads */
#define KEY_NUMERIC_2 0x202
#define KEY_NUMERIC_3 0x203
#define KEY_NUMERIC_4 0x204
#define KEY_NUMERIC_5 0x205
#define KEY_NUMERIC_6 0x206
#define KEY_NUMERIC_7 0x207
#define KEY_NUMERIC_8 0x208
#define KEY_NUMERIC_9 0x209
#define KEY_NUMERIC_STAR 0x20a
#define KEY_NUMERIC_POUND 0x20b
/* We avoid low common keys in module aliases so they don't get huge. */
#define KEY_MIN_INTERESTING KEY_MUTE
#define KEY_MAX 0x1ff
#define KEY_MAX 0x2ff
#define KEY_CNT (KEY_MAX+1)
/*

View file

@ -1,6 +1,4 @@
/*
* drivers/usb/input/map_to_7segment.h
*
* Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
*
* This program is free software; you can redistribute it and/or
@ -36,7 +34,7 @@
* Usage:
*
* Register a map variable, and fill it with a character set:
* static SEG7_DEFAULT_MAP(map_seg7);
* static SEG7_DEFAULT_MAP(map_seg7);
*
*
* Then use for conversion:

View file

@ -284,7 +284,7 @@ struct pcmcia_device_id {
/* Input */
#define INPUT_DEVICE_ID_EV_MAX 0x1f
#define INPUT_DEVICE_ID_KEY_MIN_INTERESTING 0x71
#define INPUT_DEVICE_ID_KEY_MAX 0x1ff
#define INPUT_DEVICE_ID_KEY_MAX 0x2ff
#define INPUT_DEVICE_ID_REL_MAX 0x0f
#define INPUT_DEVICE_ID_ABS_MAX 0x3f
#define INPUT_DEVICE_ID_MSC_MAX 0x07