Commit 4c0e799a authored by Dmitry Torokhov's avatar Dmitry Torokhov

Merge branch 'next' into for-linus

parents 3fa8749e b8d055a8
...@@ -796,6 +796,7 @@ and is between 256 and 4096 characters. It is defined in the 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 Defaults to the default architecture's huge page size
if not specified. if not specified.
i8042.debug [HW] Toggle i8042 debug mode
i8042.direct [HW] Put keyboard port into non-translated mode i8042.direct [HW] Put keyboard port into non-translated mode
i8042.dumbkbd [HW] Pretend that controller can only read data from i8042.dumbkbd [HW] Pretend that controller can only read data from
keyboard and cannot control its state keyboard and cannot control its state
......
...@@ -4548,7 +4548,7 @@ WM97XX TOUCHSCREEN DRIVERS ...@@ -4548,7 +4548,7 @@ WM97XX TOUCHSCREEN DRIVERS
P: Mark Brown P: Mark Brown
M: broonie@opensource.wolfsonmicro.com M: broonie@opensource.wolfsonmicro.com
P: Liam Girdwood P: Liam Girdwood
M: liam.girdwood@wolfsonmicro.com M: lrg@slimlogic.co.uk
L: linux-input@vger.kernel.org L: linux-input@vger.kernel.org
T: git git://opensource.wolfsonmicro.com/linux-2.6-touch T: git git://opensource.wolfsonmicro.com/linux-2.6-touch
W: http://opensource.wolfsonmicro.com/node/7 W: http://opensource.wolfsonmicro.com/node/7
......
...@@ -1249,7 +1249,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw) ...@@ -1249,7 +1249,7 @@ static void kbd_keycode(unsigned int keycode, int down, int hw_raw)
return; return;
} }
if (keycode > NR_KEYS) if (keycode >= NR_KEYS)
if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8) if (keycode >= KEY_BRL_DOT1 && keycode <= KEY_BRL_DOT8)
keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1); keysym = K(KT_BRL, keycode - KEY_BRL_DOT1 + 1);
else else
......
...@@ -231,6 +231,7 @@ static void gameport_find_driver(struct gameport *gameport) ...@@ -231,6 +231,7 @@ static void gameport_find_driver(struct gameport *gameport)
enum gameport_event_type { enum gameport_event_type {
GAMEPORT_REGISTER_PORT, GAMEPORT_REGISTER_PORT,
GAMEPORT_REGISTER_DRIVER, GAMEPORT_REGISTER_DRIVER,
GAMEPORT_ATTACH_DRIVER,
}; };
struct gameport_event { struct gameport_event {
...@@ -245,11 +246,12 @@ static LIST_HEAD(gameport_event_list); ...@@ -245,11 +246,12 @@ static LIST_HEAD(gameport_event_list);
static DECLARE_WAIT_QUEUE_HEAD(gameport_wait); static DECLARE_WAIT_QUEUE_HEAD(gameport_wait);
static struct task_struct *gameport_task; static struct task_struct *gameport_task;
static void gameport_queue_event(void *object, struct module *owner, static int gameport_queue_event(void *object, struct module *owner,
enum gameport_event_type event_type) enum gameport_event_type event_type)
{ {
unsigned long flags; unsigned long flags;
struct gameport_event *event; struct gameport_event *event;
int retval = 0;
spin_lock_irqsave(&gameport_event_lock, flags); spin_lock_irqsave(&gameport_event_lock, flags);
...@@ -268,24 +270,34 @@ static void gameport_queue_event(void *object, struct module *owner, ...@@ -268,24 +270,34 @@ static void gameport_queue_event(void *object, struct module *owner,
} }
} }
if ((event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC))) { event = kmalloc(sizeof(struct gameport_event), GFP_ATOMIC);
if (!try_module_get(owner)) { if (!event) {
printk(KERN_WARNING "gameport: Can't get module reference, dropping event %d\n", event_type); printk(KERN_ERR
kfree(event); "gameport: Not enough memory to queue event %d\n",
goto out; event_type);
} retval = -ENOMEM;
goto out;
event->type = event_type; }
event->object = object;
event->owner = owner;
list_add_tail(&event->node, &gameport_event_list); if (!try_module_get(owner)) {
wake_up(&gameport_wait); printk(KERN_WARNING
} else { "gameport: Can't get module reference, dropping event %d\n",
printk(KERN_ERR "gameport: Not enough memory to queue event %d\n", event_type); 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: out:
spin_unlock_irqrestore(&gameport_event_lock, flags); spin_unlock_irqrestore(&gameport_event_lock, flags);
return retval;
} }
static void gameport_free_event(struct gameport_event *event) static void gameport_free_event(struct gameport_event *event)
...@@ -378,9 +390,10 @@ static void gameport_handle_event(void) ...@@ -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 list_head *node, *next;
struct gameport_event *event; struct gameport_event *event;
...@@ -390,7 +403,7 @@ static void gameport_remove_pending_events(struct gameport *gameport) ...@@ -390,7 +403,7 @@ static void gameport_remove_pending_events(struct gameport *gameport)
list_for_each_safe(node, next, &gameport_event_list) { list_for_each_safe(node, next, &gameport_event_list) {
event = list_entry(node, struct gameport_event, node); event = list_entry(node, struct gameport_event, node);
if (event->object == gameport) { if (event->object == object) {
list_del_init(node); list_del_init(node);
gameport_free_event(event); gameport_free_event(event);
} }
...@@ -705,10 +718,40 @@ static void gameport_add_driver(struct gameport_driver *drv) ...@@ -705,10 +718,40 @@ static void gameport_add_driver(struct gameport_driver *drv)
drv->driver.name, error); 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; 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) void gameport_unregister_driver(struct gameport_driver *drv)
...@@ -716,7 +759,9 @@ void gameport_unregister_driver(struct gameport_driver *drv) ...@@ -716,7 +759,9 @@ void gameport_unregister_driver(struct gameport_driver *drv)
struct gameport *gameport; struct gameport *gameport;
mutex_lock(&gameport_mutex); mutex_lock(&gameport_mutex);
drv->ignore = 1; /* so gameport_find_driver ignores it */ drv->ignore = 1; /* so gameport_find_driver ignores it */
gameport_remove_pending_events(drv);
start_over: start_over:
list_for_each_entry(gameport, &gameport_list, node) { list_for_each_entry(gameport, &gameport_list, node) {
...@@ -729,6 +774,7 @@ void gameport_unregister_driver(struct gameport_driver *drv) ...@@ -729,6 +774,7 @@ void gameport_unregister_driver(struct gameport_driver *drv)
} }
driver_unregister(&drv->driver); driver_unregister(&drv->driver);
mutex_unlock(&gameport_mutex); mutex_unlock(&gameport_mutex);
} }
......
...@@ -414,8 +414,7 @@ static struct gameport_driver a3d_drv = { ...@@ -414,8 +414,7 @@ static struct gameport_driver a3d_drv = {
static int __init a3d_init(void) static int __init a3d_init(void)
{ {
gameport_register_driver(&a3d_drv); return gameport_register_driver(&a3d_drv);
return 0;
} }
static void __exit a3d_exit(void) static void __exit a3d_exit(void)
......
...@@ -572,8 +572,7 @@ static struct gameport_driver adi_drv = { ...@@ -572,8 +572,7 @@ static struct gameport_driver adi_drv = {
static int __init adi_init(void) static int __init adi_init(void)
{ {
gameport_register_driver(&adi_drv); return gameport_register_driver(&adi_drv);
return 0;
} }
static void __exit adi_exit(void) static void __exit adi_exit(void)
......
...@@ -761,9 +761,7 @@ static struct gameport_driver analog_drv = { ...@@ -761,9 +761,7 @@ static struct gameport_driver analog_drv = {
static int __init analog_init(void) static int __init analog_init(void)
{ {
analog_parse_options(); analog_parse_options();
gameport_register_driver(&analog_drv); return gameport_register_driver(&analog_drv);
return 0;
} }
static void __exit analog_exit(void) static void __exit analog_exit(void)
......
...@@ -263,8 +263,7 @@ static struct gameport_driver cobra_drv = { ...@@ -263,8 +263,7 @@ static struct gameport_driver cobra_drv = {
static int __init cobra_init(void) static int __init cobra_init(void)
{ {
gameport_register_driver(&cobra_drv); return gameport_register_driver(&cobra_drv);
return 0;
} }
static void __exit cobra_exit(void) static void __exit cobra_exit(void)
......
...@@ -375,8 +375,7 @@ static struct gameport_driver gf2k_drv = { ...@@ -375,8 +375,7 @@ static struct gameport_driver gf2k_drv = {
static int __init gf2k_init(void) static int __init gf2k_init(void)
{ {
gameport_register_driver(&gf2k_drv); return gameport_register_driver(&gf2k_drv);
return 0;
} }
static void __exit gf2k_exit(void) static void __exit gf2k_exit(void)
......
...@@ -426,8 +426,7 @@ static struct gameport_driver grip_drv = { ...@@ -426,8 +426,7 @@ static struct gameport_driver grip_drv = {
static int __init grip_init(void) static int __init grip_init(void)
{ {
gameport_register_driver(&grip_drv); return gameport_register_driver(&grip_drv);
return 0;
} }
static void __exit grip_exit(void) static void __exit grip_exit(void)
......
...@@ -689,8 +689,7 @@ static struct gameport_driver grip_drv = { ...@@ -689,8 +689,7 @@ static struct gameport_driver grip_drv = {
static int __init grip_init(void) static int __init grip_init(void)
{ {
gameport_register_driver(&grip_drv); return gameport_register_driver(&grip_drv);
return 0;
} }
static void __exit grip_exit(void) static void __exit grip_exit(void)
......
...@@ -283,8 +283,7 @@ static struct gameport_driver guillemot_drv = { ...@@ -283,8 +283,7 @@ static struct gameport_driver guillemot_drv = {
static int __init guillemot_init(void) static int __init guillemot_init(void)
{ {
gameport_register_driver(&guillemot_drv); return gameport_register_driver(&guillemot_drv);
return 0;
} }
static void __exit guillemot_exit(void) static void __exit guillemot_exit(void)
......
...@@ -317,8 +317,7 @@ static struct gameport_driver interact_drv = { ...@@ -317,8 +317,7 @@ static struct gameport_driver interact_drv = {
static int __init interact_init(void) static int __init interact_init(void)
{ {
gameport_register_driver(&interact_drv); return gameport_register_driver(&interact_drv);
return 0;
} }
static void __exit interact_exit(void) static void __exit interact_exit(void)
......
...@@ -161,8 +161,7 @@ static struct gameport_driver joydump_drv = { ...@@ -161,8 +161,7 @@ static struct gameport_driver joydump_drv = {
static int __init joydump_init(void) static int __init joydump_init(void)
{ {
gameport_register_driver(&joydump_drv); return gameport_register_driver(&joydump_drv);
return 0;
} }
static void __exit joydump_exit(void) static void __exit joydump_exit(void)
......
...@@ -818,8 +818,7 @@ static struct gameport_driver sw_drv = { ...@@ -818,8 +818,7 @@ static struct gameport_driver sw_drv = {
static int __init sw_init(void) static int __init sw_init(void)
{ {
gameport_register_driver(&sw_drv); return gameport_register_driver(&sw_drv);
return 0;
} }
static void __exit sw_exit(void) static void __exit sw_exit(void)
......
...@@ -438,8 +438,7 @@ static struct gameport_driver tmdc_drv = { ...@@ -438,8 +438,7 @@ static struct gameport_driver tmdc_drv = {
static int __init tmdc_init(void) static int __init tmdc_init(void)
{ {
gameport_register_driver(&tmdc_drv); return gameport_register_driver(&tmdc_drv);
return 0;
} }
static void __exit tmdc_exit(void) static void __exit tmdc_exit(void)
......
...@@ -834,10 +834,10 @@ static void atkbd_disconnect(struct serio *serio) ...@@ -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. * 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[] = { const unsigned int forced_release_keys[] = {
0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93, 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 ...@@ -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; struct input_dev *old_dev, *new_dev;
unsigned long value; unsigned long value;
char *rest;
int err; int err;
unsigned char old_extra, old_set; unsigned char old_extra, old_set;
if (!atkbd->write) if (!atkbd->write)
return -EIO; return -EIO;
value = simple_strtoul(buf, &rest, 10); if (strict_strtoul(buf, 10, &value) || value > 1)
if (*rest || value > 1)
return -EINVAL; return -EINVAL;
if (atkbd->extra != value) { if (atkbd->extra != value) {
...@@ -1264,12 +1262,10 @@ static ssize_t atkbd_set_scroll(struct atkbd *atkbd, const char *buf, size_t cou ...@@ -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; struct input_dev *old_dev, *new_dev;
unsigned long value; unsigned long value;
char *rest;
int err; int err;
unsigned char old_scroll; unsigned char old_scroll;
value = simple_strtoul(buf, &rest, 10); if (strict_strtoul(buf, 10, &value) || value > 1)
if (*rest || value > 1)
return -EINVAL; return -EINVAL;
if (atkbd->scroll != value) { if (atkbd->scroll != value) {
...@@ -1310,15 +1306,13 @@ static ssize_t atkbd_set_set(struct atkbd *atkbd, const char *buf, size_t count) ...@@ -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; struct input_dev *old_dev, *new_dev;
unsigned long value; unsigned long value;
char *rest;
int err; int err;
unsigned char old_set, old_extra; unsigned char old_set, old_extra;
if (!atkbd->write) if (!atkbd->write)
return -EIO; return -EIO;
value = simple_strtoul(buf, &rest, 10); if (strict_strtoul(buf, 10, &value) || (value != 2 && value != 3))
if (*rest || (value != 2 && value != 3))
return -EINVAL; return -EINVAL;
if (atkbd->set != value) { if (atkbd->set != value) {
...@@ -1361,15 +1355,13 @@ static ssize_t atkbd_set_softrepeat(struct atkbd *atkbd, const char *buf, size_t ...@@ -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; struct input_dev *old_dev, *new_dev;
unsigned long value; unsigned long value;
char *rest;
int err; int err;
unsigned char old_softrepeat, old_softraw; unsigned char old_softrepeat, old_softraw;
if (!atkbd->write) if (!atkbd->write)
return -EIO; return -EIO;
value = simple_strtoul(buf, &rest, 10); if (strict_strtoul(buf, 10, &value) || value > 1)
if (*rest || value > 1)
return -EINVAL; return -EINVAL;
if (atkbd->softrepeat != value) { if (atkbd->softrepeat != value) {
...@@ -1413,12 +1405,10 @@ static ssize_t atkbd_set_softraw(struct atkbd *atkbd, const char *buf, size_t co ...@@ -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; struct input_dev *old_dev, *new_dev;
unsigned long value; unsigned long value;
char *rest;
int err; int err;
unsigned char old_softraw; unsigned char old_softraw;
value = simple_strtoul(buf, &rest, 10); if (strict_strtoul(buf, 10, &value) || value > 1)
if (*rest || value > 1)
return -EINVAL; return -EINVAL;
if (atkbd->softraw != value) { if (atkbd->softraw != value) {
...@@ -1461,13 +1451,13 @@ static int __init atkbd_setup_fixup(const struct dmi_system_id *id) ...@@ -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 = { static struct dmi_system_id atkbd_dmi_quirk_table[] __initdata = {
{ {
.ident = "Dell Latitude series", .ident = "Dell Laptop",
.matches = { .matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."), DMI_MATCH(DMI_SYS_VENDOR, "Dell Inc."),
DMI_MATCH(DMI_PRODUCT_NAME, "Latitude"), DMI_MATCH(DMI_CHASSIS_TYPE, "8"), /* Portable */
}, },
.callback = atkbd_setup_fixup, .callback = atkbd_setup_fixup,
.driver_data = atkbd_latitude_keymap_fixup, .driver_data = atkbd_dell_laptop_keymap_fixup,
}, },
{ {
.ident = "HP 2133", .ident = "HP 2133",
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* Modified: * Modified:
* Copyright 2007 Analog Devices Inc. * Copyright 2007-2008 Analog Devices Inc.
* *
* Bugs: Enter bugs at http://blackfin.uclinux.org/ * Bugs: Enter bugs at http://blackfin.uclinux.org/
* *
...@@ -81,6 +81,9 @@ struct bf54x_kpad { ...@@ -81,6 +81,9 @@ struct bf54x_kpad {
unsigned short *keycode; unsigned short *keycode;
struct timer_list timer; struct timer_list timer;
unsigned int keyup_test_jiffies; 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, 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) ...@@ -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); 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)) if (device_may_wakeup(&pdev->dev))
enable_irq_wake(bf54x_kpad->irq); enable_irq_wake(bf54x_kpad->irq);
...@@ -370,6 +377,10 @@ static int bfin_kpad_resume(struct platform_device *pdev) ...@@ -370,6 +377,10 @@ static int bfin_kpad_resume(struct platform_device *pdev)
{ {
struct bf54x_kpad *bf54x_kpad = platform_get_drvdata(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)) if (device_may_wakeup(&pdev->dev))
disable_irq_wake(bf54x_kpad->irq); disable_irq_wake(bf54x_kpad->irq);
......
...@@ -36,9 +36,10 @@ struct gpio_keys_drvdata { ...@@ -36,9 +36,10 @@ struct gpio_keys_drvdata {
struct gpio_button_data data[0]; struct gpio_button_data data[0];
}; };
static void gpio_keys_report_event(struct gpio_keys_button *button, static void gpio_keys_report_event(struct gpio_button_data *bdata)
struct input_dev *input)
{ {
struct gpio_keys_button *button = bdata->button;
struct input_dev *input = bdata->input;
unsigned int type = button->type ?: EV_KEY; unsigned int type = button->type ?: EV_KEY;
int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low; int state = (gpio_get_value(button->gpio) ? 1 : 0) ^ button->active_low;
...@@ -50,34 +51,23 @@ static void gpio_check_button(unsigned long _data) ...@@ -50,34 +51,23 @@ static void gpio_check_button(unsigned long _data)
{ {
struct gpio_button_data *data = (struct gpio_button_data *)_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) static irqreturn_t gpio_keys_isr(int irq, void *dev_id)
{ {
struct platform_device *pdev = dev_id; struct gpio_button_data *bdata = dev_id;
struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; struct gpio_keys_button *button = bdata->button;
struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev);
int i;
for (i = 0; i < pdata->nbuttons; i++) { BUG_ON(irq != gpio_to_irq(button->gpio));
struct gpio_keys_button *button = &pdata->buttons[i];
if (irq == gpio_to_irq(button->gpio)) { if (button->debounce_interval)
struct gpio_button_data *bdata = &ddata->data[i]; mod_timer(&bdata->timer,
jiffies + msecs_to_jiffies(button->debounce_interval));
if (button->debounce_interval) else
mod_timer(&bdata->timer, gpio_keys_report_event(bdata);
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) static int __devinit gpio_keys_probe(struct platform_device *pdev)
...@@ -151,7 +141,7 @@ 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_SAMPLE_RANDOM | IRQF_TRIGGER_RISING |
IRQF_TRIGGER_FALLING, IRQF_TRIGGER_FALLING,
button->desc ? button->desc : "gpio_keys", button->desc ? button->desc : "gpio_keys",
pdev); bdata);
if (error) { if (error) {
pr_err("gpio-keys: Unable to claim irq %d; error %d\n", pr_err("gpio-keys: Unable to claim irq %d; error %d\n",
irq, error); irq, error);
...@@ -178,7 +168,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) ...@@ -178,7 +168,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
fail2: fail2:
while (--i >= 0) { 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) if (pdata->buttons[i].debounce_interval)
del_timer_sync(&ddata->data[i].timer); del_timer_sync(&ddata->data[i].timer);
gpio_free(pdata->buttons[i].gpio); gpio_free(pdata->buttons[i].gpio);
...@@ -203,7 +193,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) ...@@ -203,7 +193,7 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev)
for (i = 0; i < pdata->nbuttons; i++) { for (i = 0; i < pdata->nbuttons; i++) {
int irq = gpio_to_irq(pdata->buttons[i].gpio); 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) if (pdata->buttons[i].debounce_interval)
del_timer_sync(&ddata->data[i].timer); del_timer_sync(&ddata->data[i].timer);
gpio_free(pdata->buttons[i].gpio); gpio_free(pdata->buttons[i].gpio);
......
...@@ -180,6 +180,19 @@ config INPUT_YEALINK ...@@ -180,6 +180,19 @@ config INPUT_YEALINK
To compile this driver as a module, choose M here: the module will be To compile this driver as a module, choose M here: the module will be
called yealink. 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 config INPUT_UINPUT
tristate "User level driver support" tristate "User level driver support"
help help
......
...@@ -16,6 +16,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o ...@@ -16,6 +16,7 @@ obj-$(CONFIG_INPUT_ATI_REMOTE2) += ati_remote2.o
obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o
obj-$(CONFIG_INPUT_POWERMATE) += powermate.o obj-$(CONFIG_INPUT_POWERMATE) += powermate.o
obj-$(CONFIG_INPUT_YEALINK) += yealink.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o
obj-$(CONFIG_INPUT_CM109) += cm109.o
obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o
obj-$(CONFIG_INPUT_UINPUT) += uinput.o obj-$(CONFIG_INPUT_UINPUT) += uinput.o
obj-$(CONFIG_INPUT_APANEL) += apanel.o obj-$(CONFIG_INPUT_APANEL) += apanel.o
......
/* /*
* ati_remote2 - ATI/Philips USB RF remote driver * ati_remote2 - ATI/Philips USB RF remote driver
* *
* Copyright (C) 2005 Ville Syrjala <syrjala@sci.fi> * Copyright (C) 2005-2008 Ville Syrjala <syrjala@sci.fi>
* Copyright (C) 2007 Peter Stokes <linux@dadeos.freeserve.co.uk> * Copyright (C) 2007-2008 Peter Stokes <linux@dadeos.co.uk>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 * it under the terms of the GNU General Public License version 2
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
#include <linux/usb/input.h> #include <linux/usb/input.h>
#define DRIVER_DESC "ATI/Philips USB RF remote driver" #define DRIVER_DESC "ATI/Philips USB RF remote driver"
#define DRIVER_VERSION "0.2" #define DRIVER_VERSION "0.3"
MODULE_DESCRIPTION(DRIVER_DESC); MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_VERSION(DRIVER_VERSION); MODULE_VERSION(DRIVER_VERSION);
...@@ -27,7 +27,7 @@ MODULE_LICENSE("GPL"); ...@@ -27,7 +27,7 @@ MODULE_LICENSE("GPL");
* A remote's "channel" may be altered by pressing and holding the "PC" button for * 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 * 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 * 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". * newly configured "channel".
*/ */
...@@ -45,9 +45,25 @@ static struct usb_device_id ati_remote2_id_table[] = { ...@@ -45,9 +45,25 @@ static struct usb_device_id ati_remote2_id_table[] = {
}; };
MODULE_DEVICE_TABLE(usb, ati_remote2_id_table); MODULE_DEVICE_TABLE(usb, ati_remote2_id_table);
static struct { static DEFINE_MUTEX(ati_remote2_mutex);
int hw_code;
int key_code; 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[] = { } ati_remote2_key_table[] = {
{ 0x00, KEY_0 }, { 0x00, KEY_0 },
{ 0x01, KEY_1 }, { 0x01, KEY_1 },
...@@ -73,6 +89,7 @@ static struct { ...@@ -73,6 +89,7 @@ static struct {
{ 0x37, KEY_RECORD }, { 0x37, KEY_RECORD },
{ 0x38, KEY_DVD }, { 0x38, KEY_DVD },
{ 0x39, KEY_TV }, { 0x39, KEY_TV },
{ 0x3f, KEY_PROG1 }, /* AUX1-AUX4 and PC */
{ 0x54, KEY_MENU }, { 0x54, KEY_MENU },
{ 0x58, KEY_UP }, { 0x58, KEY_UP },
{ 0x59, KEY_DOWN }, { 0x59, KEY_DOWN },
...@@ -91,15 +108,9 @@ static struct { ...@@ -91,15 +108,9 @@ static struct {
{ 0xa9, BTN_LEFT }, { 0xa9, BTN_LEFT },
{ 0xaa, BTN_RIGHT }, { 0xaa, BTN_RIGHT },
{ 0xbe, KEY_QUESTION }, { 0xbe, KEY_QUESTION },
{ 0xd5, KEY_FRONT },
{ 0xd0, KEY_EDIT }, { 0xd0, KEY_EDIT },
{ 0xd5, KEY_FRONT },
{ 0xf9, KEY_INFO }, { 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 { struct ati_remote2 {
...@@ -117,46 +128,106 @@ struct ati_remote2 { ...@@ -117,46 +128,106 @@ struct ati_remote2 {
char name[64]; char name[64];
char phys[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 int ati_remote2_probe(struct usb_interface *interface, const struct usb_device_id *id);
static void ati_remote2_disconnect(struct usb_interface *interface); 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 = { static struct usb_driver ati_remote2_driver = {
.name = "ati_remote2", .name = "ati_remote2",
.probe = ati_remote2_probe, .probe = ati_remote2_probe,
.disconnect = ati_remote2_disconnect, .disconnect = ati_remote2_disconnect,
.id_table = ati_remote2_id_table, .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; int r;
r = usb_submit_urb(ar2->urb[0], GFP_KERNEL); r = usb_submit_urb(ar2->urb[0], GFP_KERNEL);
if (r) { if (r) {
dev_err(&ar2->intf[0]->dev, dev_err(&ar2->intf[0]->dev,
"%s: usb_submit_urb() = %d\n", __func__, r); "%s(): usb_submit_urb() = %d\n", __func__, r);
return r; return r;
} }
r = usb_submit_urb(ar2->urb[1], GFP_KERNEL); r = usb_submit_urb(ar2->urb[1], GFP_KERNEL);
if (r) { if (r) {
usb_kill_urb(ar2->urb[0]); usb_kill_urb(ar2->urb[0]);
dev_err(&ar2->intf[1]->dev, 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 r;
} }
return 0; 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) static void ati_remote2_close(struct input_dev *idev)
{ {
struct ati_remote2 *ar2 = input_get_drvdata(idev); struct ati_remote2 *ar2 = input_get_drvdata(idev);
usb_kill_urb(ar2->urb[0]); dev_dbg(&ar2->intf[0]->dev, "%s()\n", __func__);
usb_kill_urb(ar2->urb[1]);
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) static void ati_remote2_input_mouse(struct ati_remote2 *ar2)
...@@ -172,7 +243,7 @@ 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; mode = data[0] & 0x0F;
if (mode > 4) { if (mode > ATI_REMOTE2_PC) {
dev_err(&ar2->intf[0]->dev, dev_err(&ar2->intf[0]->dev,
"Unknown mode byte (%02x %02x %02x %02x)\n", "Unknown mode byte (%02x %02x %02x %02x)\n",
data[3], data[2], data[1], data[0]); data[3], data[2], data[1], data[0]);
...@@ -191,7 +262,7 @@ static int ati_remote2_lookup(unsigned int hw_code) ...@@ -191,7 +262,7 @@ static int ati_remote2_lookup(unsigned int hw_code)
{ {
int i; 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) if (ati_remote2_key_table[i].hw_code == hw_code)
return i; return i;
...@@ -211,7 +282,7 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2) ...@@ -211,7 +282,7 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
mode = data[0] & 0x0F; mode = data[0] & 0x0F;
if (mode > 4) { if (mode > ATI_REMOTE2_PC) {
dev_err(&ar2->intf[1]->dev, dev_err(&ar2->intf[1]->dev,
"Unknown mode byte (%02x %02x %02x %02x)\n", "Unknown mode byte (%02x %02x %02x %02x)\n",
data[3], data[2], data[1], data[0]); data[3], data[2], data[1], data[0]);
...@@ -219,10 +290,6 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2) ...@@ -219,10 +290,6 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
} }
hw_code = data[2]; 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) { if (hw_code == 0x3f) {
/* /*
* For some incomprehensible reason the mouse pad generates * For some incomprehensible reason the mouse pad generates
...@@ -236,8 +303,6 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2) ...@@ -236,8 +303,6 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
if (data[1] == 0) if (data[1] == 0)
ar2->mode = mode; ar2->mode = mode;
hw_code |= mode << 8;
} }
if (!((1 << mode) & mode_mask)) if (!((1 << mode) & mode_mask))
...@@ -260,8 +325,8 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2) ...@@ -260,8 +325,8 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
case 2: /* repeat */ case 2: /* repeat */
/* No repeat for mouse buttons. */ /* No repeat for mouse buttons. */
if (ati_remote2_key_table[index].key_code == BTN_LEFT || if (ar2->keycode[mode][index] == BTN_LEFT ||
ati_remote2_key_table[index].key_code == BTN_RIGHT) ar2->keycode[mode][index] == BTN_RIGHT)
return; return;
if (!time_after_eq(jiffies, ar2->jiffies)) if (!time_after_eq(jiffies, ar2->jiffies))
...@@ -276,7 +341,7 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2) ...@@ -276,7 +341,7 @@ static void ati_remote2_input_key(struct ati_remote2 *ar2)
return; 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); input_sync(idev);
} }
...@@ -287,6 +352,7 @@ static void ati_remote2_complete_mouse(struct urb *urb) ...@@ -287,6 +352,7 @@ static void ati_remote2_complete_mouse(struct urb *urb)
switch (urb->status) { switch (urb->status) {
case 0: case 0:
usb_mark_last_busy(ar2->udev);
ati_remote2_input_mouse(ar2); ati_remote2_input_mouse(ar2);
break; break;
case -ENOENT: case -ENOENT:
...@@ -297,6 +363,7 @@ static void ati_remote2_complete_mouse(struct urb *urb) ...@@ -297,6 +363,7 @@ static void ati_remote2_complete_mouse(struct urb *urb)
"%s(): urb status = %d\n", __func__, urb->status); "%s(): urb status = %d\n", __func__, urb->status);
return; return;
default: default:
usb_mark_last_busy(ar2->udev);
dev_err(&ar2->intf[0]->dev, dev_err(&ar2->intf[0]->dev,
"%s(): urb status = %d\n", __func__, urb->status); "%s(): urb status = %d\n", __func__, urb->status);
} }
...@@ -314,6 +381,7 @@ static void ati_remote2_complete_key(struct urb *urb) ...@@ -314,6 +381,7 @@ static void ati_remote2_complete_key(struct urb *urb)
switch (urb->status) { switch (urb->status) {
case 0: case 0:
usb_mark_last_busy(ar2->udev);
ati_remote2_input_key(ar2); ati_remote2_input_key(ar2);
break; break;
case -ENOENT: case -ENOENT:
...@@ -324,6 +392,7 @@ static void ati_remote2_complete_key(struct urb *urb) ...@@ -324,6 +392,7 @@ static void ati_remote2_complete_key(struct urb *urb)
"%s(): urb status = %d\n", __func__, urb->status); "%s(): urb status = %d\n", __func__, urb->status);
return; return;
default: default:
usb_mark_last_busy(ar2->udev);
dev_err(&ar2->intf[1]->dev, dev_err(&ar2->intf[1]->dev,
"%s(): urb status = %d\n", __func__, urb->status); "%s(): urb status = %d\n", __func__, urb->status);
} }
...@@ -334,10 +403,60 @@ static void ati_remote2_complete_key(struct urb *urb) ...@@ -334,10 +403,60 @@ static void ati_remote2_complete_key(struct urb *urb)
"%s(): usb_submit_urb() = %d\n", __func__, r); "%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) static int ati_remote2_input_init(struct ati_remote2 *ar2)
{ {
struct input_dev *idev; struct input_dev *idev;
int i, retval; int index, mode, retval;
idev = input_allocate_device(); idev = input_allocate_device();
if (!idev) if (!idev)
...@@ -350,8 +469,26 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2) ...@@ -350,8 +469,26 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) | idev->keybit[BIT_WORD(BTN_MOUSE)] = BIT_MASK(BTN_LEFT) |
BIT_MASK(BTN_RIGHT); BIT_MASK(BTN_RIGHT);
idev->relbit[0] = BIT_MASK(REL_X) | BIT_MASK(REL_Y); 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_DELAY] = 250;
idev->rep[REP_PERIOD] = 33; idev->rep[REP_PERIOD] = 33;
...@@ -359,6 +496,9 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2) ...@@ -359,6 +496,9 @@ static int ati_remote2_input_init(struct ati_remote2 *ar2)
idev->open = ati_remote2_open; idev->open = ati_remote2_open;
idev->close = ati_remote2_close; idev->close = ati_remote2_close;
idev->getkeycode = ati_remote2_getkeycode;
idev->setkeycode = ati_remote2_setkeycode;
idev->name = ar2->name; idev->name = ar2->name;
idev->phys = ar2->phys; idev->phys = ar2->phys;
...@@ -490,6 +630,8 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d ...@@ -490,6 +630,8 @@ static int ati_remote2_probe(struct usb_interface *interface, const struct usb_d
usb_set_intfdata(interface, ar2); usb_set_intfdata(interface, ar2);
interface->needs_remote_wakeup = 1;
return 0; return 0;
fail2: fail2:
...@@ -522,6 +664,57 @@ static void ati_remote2_disconnect(struct usb_interface *interface) ...@@ -522,6 +664,57 @@ static void ati_remote2_disconnect(struct usb_interface *interface)
kfree(ar2); 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) static int __init ati_remote2_init(void)
{ {
int r; int r;
......
/*
* 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");
...@@ -277,6 +277,16 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = { ...@@ -277,6 +277,16 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] __initdata = {
{ KE_END, 0 } { 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 = { static struct key_entry keymap_fujitsu_n3510[] __initdata = {
{ KE_KEY, 0x11, {KEY_PROG1} }, { KE_KEY, 0x11, {KEY_PROG1} },
{ KE_KEY, 0x12, {KEY_PROG2} }, { KE_KEY, 0x12, {KEY_PROG2} },
...@@ -616,6 +626,15 @@ static struct dmi_system_id dmi_ids[] __initdata = { ...@@ -616,6 +626,15 @@ static struct dmi_system_id dmi_ids[] __initdata = {
}, },
.driver_data = keymap_fs_amilo_pro_v2000 .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, .callback = dmi_matched,
.ident = "Fujitsu-Siemens Amilo M7400", .ident = "Fujitsu-Siemens Amilo M7400",
......
...@@ -52,8 +52,8 @@ ...@@ -52,8 +52,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/rwsem.h> #include <linux/rwsem.h>
#include <linux/usb/input.h> #include <linux/usb/input.h>
#include <linux/map_to_7segment.h>
#include "map_to_7segment.h"
#include "yealink.h" #include "yealink.h"
#define DRIVER_VERSION "yld-20051230" #define DRIVER_VERSION "yld-20051230"
......
...@@ -96,6 +96,16 @@ config MOUSE_PS2_TOUCHKIT ...@@ -96,6 +96,16 @@ config MOUSE_PS2_TOUCHKIT
If unsure, say N. 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 config MOUSE_SERIAL
tristate "Serial mouse" tristate "Serial mouse"
select SERIO select SERIO
......
...@@ -21,6 +21,7 @@ obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o ...@@ -21,6 +21,7 @@ obj-$(CONFIG_MOUSE_GPIO) += gpio_mouse.o
psmouse-objs := psmouse-base.o synaptics.o psmouse-objs := psmouse-base.o synaptics.o
psmouse-$(CONFIG_MOUSE_PS2_ALPS) += alps.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_LOGIPS2PP) += logips2pp.o
psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o psmouse-$(CONFIG_MOUSE_PS2_LIFEBOOK) += lifebook.o
psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o psmouse-$(CONFIG_MOUSE_PS2_TRACKPOINT) += trackpoint.o
......
...@@ -54,6 +54,7 @@ static const struct alps_model_info alps_model_data[] = { ...@@ -54,6 +54,7 @@ static const struct alps_model_info alps_model_data[] = {
{ { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */ { { 0x20, 0x02, 0x0e }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, /* XXX */
{ { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT }, { { 0x22, 0x02, 0x0a }, 0xf8, 0xf8, ALPS_PASS | ALPS_DUALPOINT },
{ { 0x22, 0x02, 0x14 }, 0xff, 0xff, ALPS_PASS | ALPS_DUALPOINT }, /* Dell Latitude D600 */ { { 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 */ { { 0x73, 0x02, 0x50 }, 0xcf, 0xcf, ALPS_FW_BK_1 } /* Dell Vostro 1400 */
}; };
......
...@@ -136,12 +136,28 @@ MODULE_DEVICE_TABLE(usb, atp_table); ...@@ -136,12 +136,28 @@ MODULE_DEVICE_TABLE(usb, atp_table);
#define ATP_GEYSER_MODE_REQUEST_INDEX 0 #define ATP_GEYSER_MODE_REQUEST_INDEX 0
#define ATP_GEYSER_MODE_VENDOR_VALUE 0x04 #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 */ /* Structure to hold all of our device specific stuff */
struct atp { struct atp {
char phys[64]; char phys[64];
struct usb_device *udev; /* usb device */ struct usb_device *udev; /* usb device */
struct urb *urb; /* usb request block */ struct urb *urb; /* usb request block */
signed char *data; /* transferred data */ u8 *data; /* transferred data */
struct input_dev *input; /* input dev */ struct input_dev *input; /* input dev */
enum atp_touchpad_type type; /* type of touchpad */ enum atp_touchpad_type type; /* type of touchpad */
bool open; bool open;
...@@ -251,8 +267,6 @@ static void atp_reinit(struct work_struct *work) ...@@ -251,8 +267,6 @@ static void atp_reinit(struct work_struct *work)
int retval; int retval;
dprintk("appletouch: putting appletouch to sleep (reinit)\n"); dprintk("appletouch: putting appletouch to sleep (reinit)\n");
dev->idlecount = 0;
atp_geyser_init(udev); atp_geyser_init(udev);
retval = usb_submit_urb(dev->urb, GFP_ATOMIC); retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
...@@ -327,11 +341,14 @@ static inline void atp_report_fingers(struct input_dev *input, int fingers) ...@@ -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); 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; struct atp *dev = urb->context;
switch (urb->status) { switch (urb->status) {
...@@ -351,11 +368,12 @@ static void atp_complete(struct urb *urb) ...@@ -351,11 +368,12 @@ static void atp_complete(struct urb *urb)
/* This urb is terminated, clean up */ /* This urb is terminated, clean up */
dbg("atp_complete: urb shutting down with status: %d", dbg("atp_complete: urb shutting down with status: %d",
urb->status); urb->status);
return; return ATP_URB_STATUS_ERROR_FATAL;
default: default:
dbg("atp_complete: nonzero urb status received: %d", dbg("atp_complete: nonzero urb status received: %d",
urb->status); urb->status);
goto exit; return ATP_URB_STATUS_ERROR;
} }
/* drop incomplete datasets */ /* drop incomplete datasets */
...@@ -363,30 +381,33 @@ static void atp_complete(struct urb *urb) ...@@ -363,30 +381,33 @@ static void atp_complete(struct urb *urb)
dprintk("appletouch: incomplete data package" dprintk("appletouch: incomplete data package"
" (first byte: %d, length: %d).\n", " (first byte: %d, length: %d).\n",
dev->data[0], dev->urb->actual_length); dev->data[0], dev->urb->actual_length);
goto exit; return ATP_URB_STATUS_ERROR;
} }
/* reorder the sensors values */ return ATP_URB_STATUS_SUCCESS;
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: * USB interrupt callback functions
* -, Y1, Y2, -, Y3, Y4, -, ..., -, X1, X2, -, X3, X4, ... */
* '-' is an unused value.
*/
/* read X values */ /* Interrupt function for older touchpads: FOUNTAIN/GEYSER1/GEYSER2 */
for (i = 0, j = 19; i < 20; i += 2, j += 3) {
dev->xy_cur[i] = dev->data[j + 1]; static void atp_complete_geyser_1_2(struct urb *urb)
dev->xy_cur[i + 1] = dev->data[j + 2]; {
} int x, y, x_z, y_z, x_f, y_f;
/* read Y values */ int retval, i, j;
for (i = 0, j = 1; i < 9; i += 2, j += 3) { int key;
dev->xy_cur[ATP_XSENSORS + i] = dev->data[j + 1]; struct atp *dev = urb->context;
dev->xy_cur[ATP_XSENSORS + i + 1] = dev->data[j + 2]; int status = atp_status_check(urb);
}
} else if (dev->type == ATP_GEYSER2) { 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_GEYSER2) {
memset(dev->xy_cur, 0, sizeof(dev->xy_cur)); memset(dev->xy_cur, 0, sizeof(dev->xy_cur));
/* /*
...@@ -427,34 +448,40 @@ static void atp_complete(struct urb *urb) ...@@ -427,34 +448,40 @@ static void atp_complete(struct urb *urb)
/* first sample */ /* first sample */
dev->valid = true; dev->valid = true;
dev->x_old = dev->y_old = -1; dev->x_old = dev->y_old = -1;
/* Store first sample */
memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old)); memcpy(dev->xy_old, dev->xy_cur, sizeof(dev->xy_old));
if (dev->size_detect_done || /* Perform size detection, if not done already */
dev->type == ATP_GEYSER3) /* No 17" Macbooks (yet) */ if (!dev->size_detect_done) {
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,
(26 - 1) *
ATP_XFACT - 1,
ATP_FUZZ, 0);
break;
}
/* 17" Powerbooks have extra X sensors */ dev->size_detect_done = 1;
for (i = (dev->type == ATP_GEYSER2 ? 15 : 16); goto exit;
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++) { for (i = 0; i < ATP_XSENSORS + ATP_YSENSORS; i++) {
...@@ -475,7 +502,118 @@ static void atp_complete(struct urb *urb) ...@@ -475,7 +502,118 @@ static void atp_complete(struct urb *urb)
ATP_XFACT, &x_z, &x_f); ATP_XFACT, &x_z, &x_f);
y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS, y = atp_calculate_abs(dev->xy_acc + ATP_XSENSORS, ATP_YSENSORS,
ATP_YFACT, &y_z, &y_f); 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 (x && y) {
if (dev->x_old != -1) { if (dev->x_old != -1) {
...@@ -514,28 +652,27 @@ static void atp_complete(struct urb *urb) ...@@ -514,28 +652,27 @@ static void atp_complete(struct urb *urb)
input_sync(dev->input); 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 * the first touch unless reinitialised. Do so if it's been
* idle for a while in order to avoid waking the kernel up * idle for a while in order to avoid waking the kernel up
* several hundred times a second. Re-initialization does not * several hundred times a second.
* work on Fountain touchpads.
*/ */
if (dev->type != ATP_FOUNTAIN) {
/* /*
* Button must not be pressed when entering suspend, * Button must not be pressed when entering suspend,
* otherwise we will never release the button. * otherwise we will never release the button.
*/ */
if (!x && !y && !key) { if (!x && !y && !key) {
dev->idlecount++; dev->idlecount++;
if (dev->idlecount == 10) { if (dev->idlecount == 10) {
dev->valid = false; dev->x_old = dev->y_old = -1;
schedule_work(&dev->work);
/* Don't resubmit urb here, wait for reinit */
return;
}
} else
dev->idlecount = 0; dev->idlecount = 0;
} schedule_work(&dev->work);
/* Don't resubmit urb here, wait for reinit */
return;
}
} else
dev->idlecount = 0;
exit: exit:
retval = usb_submit_urb(dev->urb, GFP_ATOMIC); retval = usb_submit_urb(dev->urb, GFP_ATOMIC);
...@@ -632,9 +769,19 @@ static int atp_probe(struct usb_interface *iface, ...@@ -632,9 +769,19 @@ static int atp_probe(struct usb_interface *iface,
if (!dev->data) if (!dev->data)
goto err_free_urb; goto err_free_urb;
usb_fill_int_urb(dev->urb, udev, /* Select the USB complete (callback) function */
usb_rcvintpipe(udev, int_in_endpointAddr), if (dev->type == ATP_FOUNTAIN ||
dev->data, dev->datalen, atp_complete, dev, 1); 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); error = atp_handle_geyser(dev);
if (error) if (error)
...@@ -751,8 +898,6 @@ static int atp_suspend(struct usb_interface *iface, pm_message_t message) ...@@ -751,8 +898,6 @@ static int atp_suspend(struct usb_interface *iface, pm_message_t message)
struct atp *dev = usb_get_intfdata(iface); struct atp *dev = usb_get_intfdata(iface);
usb_kill_urb(dev->urb); usb_kill_urb(dev->urb);
dev->valid = false;
return 0; return 0;
} }
......
/*
* 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;
}
/*
* 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
...@@ -157,10 +157,8 @@ static ssize_t ps2pp_attr_show_smartscroll(struct psmouse *psmouse, void *data, ...@@ -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) static ssize_t ps2pp_attr_set_smartscroll(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{ {
unsigned long value; unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10); if (strict_strtoul(buf, 10, &value) || value > 1)
if (*rest || value > 1)
return -EINVAL; return -EINVAL;
ps2pp_set_smartscroll(psmouse, value); ps2pp_set_smartscroll(psmouse, value);
......
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "synaptics.h" #include "synaptics.h"
#include "logips2pp.h" #include "logips2pp.h"
#include "alps.h" #include "alps.h"
#include "hgpk.h"
#include "lifebook.h" #include "lifebook.h"
#include "trackpoint.h" #include "trackpoint.h"
#include "touchkit_ps2.h" #include "touchkit_ps2.h"
...@@ -201,6 +202,12 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse) ...@@ -201,6 +202,12 @@ static psmouse_ret_t psmouse_process_byte(struct psmouse *psmouse)
return PSMOUSE_FULL_PACKET; 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. * __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 ...@@ -220,7 +227,7 @@ static inline void __psmouse_set_state(struct psmouse *psmouse, enum psmouse_sta
* is not a concern. * 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); serio_pause_rx(psmouse->ps2dev.serio);
__psmouse_set_state(psmouse, new_state); __psmouse_set_state(psmouse, new_state);
...@@ -305,7 +312,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -305,7 +312,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
psmouse->name, psmouse->phys, psmouse->pktcnt); psmouse->name, psmouse->phys, psmouse->pktcnt);
psmouse->badbyte = psmouse->packet[0]; psmouse->badbyte = psmouse->packet[0];
__psmouse_set_state(psmouse, PSMOUSE_RESYNCING); __psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
queue_work(kpsmoused_wq, &psmouse->resync_work); psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
goto out; goto out;
} }
...@@ -342,7 +349,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -342,7 +349,7 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) { time_after(jiffies, psmouse->last + psmouse->resync_time * HZ)) {
psmouse->badbyte = psmouse->packet[0]; psmouse->badbyte = psmouse->packet[0];
__psmouse_set_state(psmouse, PSMOUSE_RESYNCING); __psmouse_set_state(psmouse, PSMOUSE_RESYNCING);
queue_work(kpsmoused_wq, &psmouse->resync_work); psmouse_queue_work(psmouse, &psmouse->resync_work, 0);
goto out; goto out;
} }
...@@ -630,8 +637,20 @@ static int psmouse_extensions(struct psmouse *psmouse, ...@@ -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) if (genius_detect(psmouse, set_properties) == 0)
return PSMOUSE_GENPS; return PSMOUSE_GENPS;
...@@ -761,6 +780,14 @@ static const struct psmouse_protocol psmouse_protocols[] = { ...@@ -761,6 +780,14 @@ static const struct psmouse_protocol psmouse_protocols[] = {
.alias = "touchkit", .alias = "touchkit",
.detect = touchkit_ps2_detect, .detect = touchkit_ps2_detect,
}, },
#endif
#ifdef CONFIG_MOUSE_PS2_OLPC
{
.type = PSMOUSE_HGPK,
.name = "OLPC HGPK",
.alias = "hgpk",
.detect = hgpk_detect,
},
#endif #endif
{ {
.type = PSMOUSE_CORTRON, .type = PSMOUSE_CORTRON,
...@@ -935,7 +962,7 @@ static int psmouse_poll(struct psmouse *psmouse) ...@@ -935,7 +962,7 @@ static int psmouse_poll(struct psmouse *psmouse)
static void psmouse_resync(struct work_struct *work) static void psmouse_resync(struct work_struct *work)
{ {
struct psmouse *parent = NULL, *psmouse = 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; struct serio *serio = psmouse->ps2dev.serio;
psmouse_ret_t rc = PSMOUSE_GOOD_DATA; psmouse_ret_t rc = PSMOUSE_GOOD_DATA;
int failed = 0, enabled = 0; int failed = 0, enabled = 0;
...@@ -1194,7 +1221,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv) ...@@ -1194,7 +1221,7 @@ static int psmouse_connect(struct serio *serio, struct serio_driver *drv)
goto err_free; goto err_free;
ps2_init(&psmouse->ps2dev, serio); ps2_init(&psmouse->ps2dev, serio);
INIT_WORK(&psmouse->resync_work, psmouse_resync); INIT_DELAYED_WORK(&psmouse->resync_work, psmouse_resync);
psmouse->dev = input_dev; psmouse->dev = input_dev;
snprintf(psmouse->phys, sizeof(psmouse->phys), "%s/input0", serio->phys); 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 ...@@ -1395,25 +1422,29 @@ ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *dev
psmouse = serio_get_drvdata(serio); psmouse = serio_get_drvdata(serio);
if (psmouse->state == PSMOUSE_IGNORE) { if (attr->protect) {
retval = -ENODEV; if (psmouse->state == PSMOUSE_IGNORE) {
goto out_unlock; retval = -ENODEV;
} goto out_unlock;
}
if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) { if (serio->parent && serio->id.type == SERIO_PS_PSTHRU) {
parent = serio_get_drvdata(serio->parent); parent = serio_get_drvdata(serio->parent);
psmouse_deactivate(parent); psmouse_deactivate(parent);
} }
psmouse_deactivate(psmouse); psmouse_deactivate(psmouse);
}
retval = attr->set(psmouse, attr->data, buf, count); retval = attr->set(psmouse, attr->data, buf, count);
if (retval != -ENODEV) if (attr->protect) {
psmouse_activate(psmouse); if (retval != -ENODEV)
psmouse_activate(psmouse);
if (parent) if (parent)
psmouse_activate(parent); psmouse_activate(parent);
}
out_unlock: out_unlock:
mutex_unlock(&psmouse_mutex); mutex_unlock(&psmouse_mutex);
...@@ -1433,10 +1464,8 @@ static ssize_t psmouse_set_int_attr(struct psmouse *psmouse, void *offset, const ...@@ -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 int *field = (unsigned int *)((char *)psmouse + (size_t)offset);
unsigned long value; unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10); if (strict_strtoul(buf, 10, &value))
if (*rest)
return -EINVAL; return -EINVAL;
if ((unsigned int)value != value) if ((unsigned int)value != value)
...@@ -1549,10 +1578,8 @@ static ssize_t psmouse_attr_set_protocol(struct psmouse *psmouse, void *data, co ...@@ -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) static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{ {
unsigned long value; unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10); if (strict_strtoul(buf, 10, &value))
if (*rest)
return -EINVAL; return -EINVAL;
psmouse->set_rate(psmouse, value); psmouse->set_rate(psmouse, value);
...@@ -1562,10 +1589,8 @@ static ssize_t psmouse_attr_set_rate(struct psmouse *psmouse, void *data, const ...@@ -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) static ssize_t psmouse_attr_set_resolution(struct psmouse *psmouse, void *data, const char *buf, size_t count)
{ {
unsigned long value; unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10); if (strict_strtoul(buf, 10, &value))
if (*rest)
return -EINVAL; return -EINVAL;
psmouse->set_resolution(psmouse, value); psmouse->set_resolution(psmouse, value);
......
...@@ -39,7 +39,7 @@ struct psmouse { ...@@ -39,7 +39,7 @@ struct psmouse {
void *private; void *private;
struct input_dev *dev; struct input_dev *dev;
struct ps2dev ps2dev; struct ps2dev ps2dev;
struct work_struct resync_work; struct delayed_work resync_work;
char *vendor; char *vendor;
char *name; char *name;
unsigned char packet[8]; unsigned char packet[8];
...@@ -89,20 +89,24 @@ enum psmouse_type { ...@@ -89,20 +89,24 @@ enum psmouse_type {
PSMOUSE_TRACKPOINT, PSMOUSE_TRACKPOINT,
PSMOUSE_TOUCHKIT_PS2, PSMOUSE_TOUCHKIT_PS2,
PSMOUSE_CORTRON, PSMOUSE_CORTRON,
PSMOUSE_HGPK,
PSMOUSE_AUTO /* This one should always be last */ 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_sliced_command(struct psmouse *psmouse, unsigned char command);
int psmouse_reset(struct psmouse *psmouse); 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); void psmouse_set_resolution(struct psmouse *psmouse, unsigned int resolution);
struct psmouse_attribute { struct psmouse_attribute {
struct device_attribute dattr; struct device_attribute dattr;
void *data; void *data;
ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf); ssize_t (*show)(struct psmouse *psmouse, void *data, char *buf);
ssize_t (*set)(struct psmouse *psmouse, void *data, ssize_t (*set)(struct psmouse *psmouse, void *data,
const char *buf, size_t count); const char *buf, size_t count);
int protect;
}; };
#define to_psmouse_attr(a) container_of((a), struct psmouse_attribute, dattr) #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 ...@@ -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, ssize_t psmouse_attr_set_helper(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count); 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 _show(struct psmouse *, void *data, char *); \
static ssize_t _set(struct psmouse *, void *data, const char *, size_t); \ static ssize_t _set(struct psmouse *, void *data, const char *, size_t); \
static struct psmouse_attribute psmouse_attr_##_name = { \ static struct psmouse_attribute psmouse_attr_##_name = { \
...@@ -126,6 +130,10 @@ static struct psmouse_attribute psmouse_attr_##_name = { \ ...@@ -126,6 +130,10 @@ static struct psmouse_attribute psmouse_attr_##_name = { \
.data = _data, \ .data = _data, \
.show = _show, \ .show = _show, \
.set = _set, \ .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 */ #endif /* _PSMOUSE_H */
...@@ -89,10 +89,8 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data, ...@@ -89,10 +89,8 @@ static ssize_t trackpoint_set_int_attr(struct psmouse *psmouse, void *data,
struct trackpoint_attr_data *attr = data; struct trackpoint_attr_data *attr = data;
unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
unsigned long value; unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10); if (strict_strtoul(buf, 10, &value) || value > 255)
if (*rest || value > 255)
return -EINVAL; return -EINVAL;
*field = value; *field = value;
...@@ -117,10 +115,8 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data, ...@@ -117,10 +115,8 @@ static ssize_t trackpoint_set_bit_attr(struct psmouse *psmouse, void *data,
struct trackpoint_attr_data *attr = data; struct trackpoint_attr_data *attr = data;
unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset); unsigned char *field = (unsigned char *)((char *)tp + attr->field_offset);
unsigned long value; unsigned long value;
char *rest;
value = simple_strtoul(buf, &rest, 10); if (strict_strtoul(buf, 10, &value) || value > 1)
if (*rest || value > 1)
return -EINVAL; return -EINVAL;
if (attr->inverted) if (attr->inverted)
......
...@@ -322,6 +322,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = { ...@@ -322,6 +322,13 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"), DMI_MATCH(DMI_PRODUCT_NAME, "N34AS6"),
}, },
}, },
{
.ident = "IBM 2656",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "IBM"),
DMI_MATCH(DMI_PRODUCT_NAME, "2656"),
},
},
{ } { }
}; };
......
...@@ -373,6 +373,12 @@ static struct serio_device_id serio_raw_serio_ids[] = { ...@@ -373,6 +373,12 @@ static struct serio_device_id serio_raw_serio_ids[] = {
.id = SERIO_ANY, .id = SERIO_ANY,
.extra = SERIO_ANY, .extra = SERIO_ANY,
}, },
{
.type = SERIO_8042_XL,
.proto = SERIO_ANY,
.id = SERIO_ANY,
.extra = SERIO_ANY,
},
{ 0 } { 0 }
}; };
......
...@@ -1202,16 +1202,22 @@ static ssize_t ...@@ -1202,16 +1202,22 @@ static ssize_t
store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) store_tabletXtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); 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; aiptek->newSetting.xTilt = AIPTEK_TILT_DISABLE;
} else { } else {
x = (int)simple_strtol(buf, NULL, 10); if (x < AIPTEK_TILT_MIN || x > AIPTEK_TILT_MAX)
if (x >= AIPTEK_TILT_MIN && x <= AIPTEK_TILT_MAX) { return -EINVAL;
aiptek->newSetting.xTilt = x;
} aiptek->newSetting.xTilt = x;
} }
return count; return count;
} }
...@@ -1238,16 +1244,22 @@ static ssize_t ...@@ -1238,16 +1244,22 @@ static ssize_t
store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) store_tabletYtilt(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); 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; aiptek->newSetting.yTilt = AIPTEK_TILT_DISABLE;
} else { } else {
y = (int)simple_strtol(buf, NULL, 10); if (y < AIPTEK_TILT_MIN || y > AIPTEK_TILT_MAX)
if (y >= AIPTEK_TILT_MIN && y <= AIPTEK_TILT_MAX) { return -EINVAL;
aiptek->newSetting.yTilt = y;
} aiptek->newSetting.yTilt = y;
} }
return count; return count;
} }
...@@ -1269,8 +1281,12 @@ static ssize_t ...@@ -1269,8 +1281,12 @@ static ssize_t
store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) store_tabletJitterDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
long j;
if (strict_strtol(buf, 10, &j))
return -EINVAL;
aiptek->newSetting.jitterDelay = (int)simple_strtol(buf, NULL, 10); aiptek->newSetting.jitterDelay = (int)j;
return count; return count;
} }
...@@ -1294,8 +1310,12 @@ static ssize_t ...@@ -1294,8 +1310,12 @@ static ssize_t
store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) store_tabletProgrammableDelay(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); 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; return count;
} }
...@@ -1541,8 +1561,11 @@ static ssize_t ...@@ -1541,8 +1561,11 @@ static ssize_t
store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count) store_tabletWheel(struct device *dev, struct device_attribute *attr, const char *buf, size_t count)
{ {
struct aiptek *aiptek = dev_get_drvdata(dev); struct aiptek *aiptek = dev_get_drvdata(dev);
long w;
if (strict_strtol(buf, 10, &w)) return -EINVAL;
aiptek->newSetting.wheel = (int)simple_strtol(buf, NULL, 10); aiptek->newSetting.wheel = (int)w;
return count; return count;
} }
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include <linux/input.h> #include <linux/input.h>
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/gpio.h>
#include <linux/spi/spi.h> #include <linux/spi/spi.h>
#include <linux/spi/ads7846.h> #include <linux/spi/ads7846.h>
#include <asm/irq.h> #include <asm/irq.h>
...@@ -68,6 +69,17 @@ struct ts_event { ...@@ -68,6 +69,17 @@ struct ts_event {
int ignore; 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 ads7846 {
struct input_dev *input; struct input_dev *input;
char phys[32]; char phys[32];
...@@ -85,9 +97,7 @@ struct ads7846 { ...@@ -85,9 +97,7 @@ struct ads7846 {
u16 x_plate_ohms; u16 x_plate_ohms;
u16 pressure_max; u16 pressure_max;
u8 read_x, read_y, read_z1, read_z2, pwrdown; struct ads7846_packet *packet;
u16 dummy; /* for the pwrdown read */
struct ts_event tc;
struct spi_transfer xfer[18]; struct spi_transfer xfer[18];
struct spi_message msg[5]; struct spi_message msg[5];
...@@ -116,6 +126,7 @@ struct ads7846 { ...@@ -116,6 +126,7 @@ struct ads7846 {
void *filter_data; void *filter_data;
void (*filter_cleanup)(void *data); void (*filter_cleanup)(void *data);
int (*get_pendown_state)(void); int (*get_pendown_state)(void);
int gpio_pendown;
}; };
/* leave chip selected when we're done, for quicker re-select? */ /* leave chip selected when we're done, for quicker re-select? */
...@@ -461,10 +472,11 @@ static ssize_t ads7846_disable_store(struct device *dev, ...@@ -461,10 +472,11 @@ static ssize_t ads7846_disable_store(struct device *dev,
const char *buf, size_t count) const char *buf, size_t count)
{ {
struct ads7846 *ts = dev_get_drvdata(dev); struct ads7846 *ts = dev_get_drvdata(dev);
char *endp; long i;
int i;
if (strict_strtoul(buf, 10, &i))
return -EINVAL;
i = simple_strtoul(buf, &endp, 10);
spin_lock_irq(&ts->lock); spin_lock_irq(&ts->lock);
if (i) if (i)
...@@ -491,6 +503,14 @@ static struct attribute_group ads784x_attr_group = { ...@@ -491,6 +503,14 @@ static struct attribute_group ads784x_attr_group = {
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
static int get_pendown_state(struct ads7846 *ts)
{
if (ts->get_pendown_state)
return ts->get_pendown_state();
return !gpio_get_value(ts->gpio_pendown);
}
/* /*
* PENIRQ only kicks the timer. The timer only reissues the SPI transfer, * PENIRQ only kicks the timer. The timer only reissues the SPI transfer,
* to retrieve touchscreen status. * to retrieve touchscreen status.
...@@ -502,16 +522,17 @@ static struct attribute_group ads784x_attr_group = { ...@@ -502,16 +522,17 @@ static struct attribute_group ads784x_attr_group = {
static void ads7846_rx(void *ads) static void ads7846_rx(void *ads)
{ {
struct ads7846 *ts = ads; struct ads7846 *ts = ads;
struct ads7846_packet *packet = ts->packet;
unsigned Rt; unsigned Rt;
u16 x, y, z1, z2; u16 x, y, z1, z2;
/* ads7846_rx_val() did in-place conversion (including byteswap) from /* ads7846_rx_val() did in-place conversion (including byteswap) from
* on-the-wire format as part of debouncing to get stable readings. * on-the-wire format as part of debouncing to get stable readings.
*/ */
x = ts->tc.x; x = packet->tc.x;
y = ts->tc.y; y = packet->tc.y;
z1 = ts->tc.z1; z1 = packet->tc.z1;
z2 = ts->tc.z2; z2 = packet->tc.z2;
/* range filtering */ /* range filtering */
if (x == MAX_12BIT) if (x == MAX_12BIT)
...@@ -535,10 +556,10 @@ static void ads7846_rx(void *ads) ...@@ -535,10 +556,10 @@ static void ads7846_rx(void *ads)
* the maximum. Don't report it to user space, repeat at least * the maximum. Don't report it to user space, repeat at least
* once more the measurement * once more the measurement
*/ */
if (ts->tc.ignore || Rt > ts->pressure_max) { if (packet->tc.ignore || Rt > ts->pressure_max) {
#ifdef VERBOSE #ifdef VERBOSE
pr_debug("%s: ignored %d pressure %d\n", 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 #endif
hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD), hrtimer_start(&ts->timer, ktime_set(0, TS_POLL_PERIOD),
HRTIMER_MODE_REL); HRTIMER_MODE_REL);
...@@ -550,7 +571,7 @@ static void ads7846_rx(void *ads) ...@@ -550,7 +571,7 @@ static void ads7846_rx(void *ads)
*/ */
if (ts->penirq_recheck_delay_usecs) { if (ts->penirq_recheck_delay_usecs) {
udelay(ts->penirq_recheck_delay_usecs); udelay(ts->penirq_recheck_delay_usecs);
if (!ts->get_pendown_state()) if (!get_pendown_state(ts))
Rt = 0; Rt = 0;
} }
...@@ -631,6 +652,7 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val) ...@@ -631,6 +652,7 @@ static int ads7846_no_filter(void *ads, int data_idx, int *val)
static void ads7846_rx_val(void *ads) static void ads7846_rx_val(void *ads)
{ {
struct ads7846 *ts = ads; struct ads7846 *ts = ads;
struct ads7846_packet *packet = ts->packet;
struct spi_message *m; struct spi_message *m;
struct spi_transfer *t; struct spi_transfer *t;
int val; int val;
...@@ -650,7 +672,7 @@ static void ads7846_rx_val(void *ads) ...@@ -650,7 +672,7 @@ static void ads7846_rx_val(void *ads)
case ADS7846_FILTER_REPEAT: case ADS7846_FILTER_REPEAT:
break; break;
case ADS7846_FILTER_IGNORE: case ADS7846_FILTER_IGNORE:
ts->tc.ignore = 1; packet->tc.ignore = 1;
/* Last message will contain ads7846_rx() as the /* Last message will contain ads7846_rx() as the
* completion function. * completion function.
*/ */
...@@ -658,7 +680,7 @@ static void ads7846_rx_val(void *ads) ...@@ -658,7 +680,7 @@ static void ads7846_rx_val(void *ads)
break; break;
case ADS7846_FILTER_OK: case ADS7846_FILTER_OK:
*(u16 *)t->rx_buf = val; *(u16 *)t->rx_buf = val;
ts->tc.ignore = 0; packet->tc.ignore = 0;
m = &ts->msg[++ts->msg_idx]; m = &ts->msg[++ts->msg_idx];
break; break;
default: default:
...@@ -677,7 +699,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle) ...@@ -677,7 +699,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
spin_lock_irq(&ts->lock); spin_lock_irq(&ts->lock);
if (unlikely(!ts->get_pendown_state() || if (unlikely(!get_pendown_state(ts) ||
device_suspended(&ts->spi->dev))) { device_suspended(&ts->spi->dev))) {
if (ts->pendown) { if (ts->pendown) {
struct input_dev *input = ts->input; struct input_dev *input = ts->input;
...@@ -716,7 +738,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle) ...@@ -716,7 +738,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
unsigned long flags; unsigned long flags;
spin_lock_irqsave(&ts->lock, flags); spin_lock_irqsave(&ts->lock, flags);
if (likely(ts->get_pendown_state())) { if (likely(get_pendown_state(ts))) {
if (!ts->irq_disabled) { if (!ts->irq_disabled) {
/* The ARM do_simple_IRQ() dispatcher doesn't act /* The ARM do_simple_IRQ() dispatcher doesn't act
* like the other dispatchers: it will report IRQs * like the other dispatchers: it will report IRQs
...@@ -763,7 +785,6 @@ static void ads7846_disable(struct ads7846 *ts) ...@@ -763,7 +785,6 @@ static void ads7846_disable(struct ads7846 *ts)
/* we know the chip's in lowpower mode since we always /* we know the chip's in lowpower mode since we always
* leave it that way after every request * leave it that way after every request
*/ */
} }
/* Must be called with ts->lock held */ /* Must be called with ts->lock held */
...@@ -806,9 +827,40 @@ static int ads7846_resume(struct spi_device *spi) ...@@ -806,9 +827,40 @@ static int ads7846_resume(struct spi_device *spi)
return 0; return 0;
} }
static int __devinit setup_pendown(struct spi_device *spi, struct ads7846 *ts)
{
struct ads7846_platform_data *pdata = spi->dev.platform_data;
int err;
/* REVISIT when the irq can be triggered active-low, or if for some
* reason the touchscreen isn't hooked up, we don't need to access
* the pendown state.
*/
if (!pdata->get_pendown_state && !gpio_is_valid(pdata->gpio_pendown)) {
dev_err(&spi->dev, "no get_pendown_state nor gpio_pendown?\n");
return -EINVAL;
}
if (pdata->get_pendown_state) {
ts->get_pendown_state = pdata->get_pendown_state;
return 0;
}
err = gpio_request(pdata->gpio_pendown, "ads7846_pendown");
if (err) {
dev_err(&spi->dev, "failed to request pendown GPIO%d\n",
pdata->gpio_pendown);
return err;
}
ts->gpio_pendown = pdata->gpio_pendown;
return 0;
}
static int __devinit ads7846_probe(struct spi_device *spi) static int __devinit ads7846_probe(struct spi_device *spi)
{ {
struct ads7846 *ts; struct ads7846 *ts;
struct ads7846_packet *packet;
struct input_dev *input_dev; struct input_dev *input_dev;
struct ads7846_platform_data *pdata = spi->dev.platform_data; struct ads7846_platform_data *pdata = spi->dev.platform_data;
struct spi_message *m; struct spi_message *m;
...@@ -833,15 +885,6 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -833,15 +885,6 @@ static int __devinit ads7846_probe(struct spi_device *spi)
return -EINVAL; return -EINVAL;
} }
/* REVISIT when the irq can be triggered active-low, or if for some
* reason the touchscreen isn't hooked up, we don't need to access
* the pendown state.
*/
if (pdata->get_pendown_state == NULL) {
dev_dbg(&spi->dev, "no get_pendown_state function?\n");
return -EINVAL;
}
/* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except /* We'd set TX wordsize 8 bits and RX wordsize to 13 bits ... except
* that even if the hardware can do that, the SPI controller driver * that even if the hardware can do that, the SPI controller driver
* may not. So we stick to very-portable 8 bit words, both RX and TX. * may not. So we stick to very-portable 8 bit words, both RX and TX.
...@@ -853,14 +896,16 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -853,14 +896,16 @@ static int __devinit ads7846_probe(struct spi_device *spi)
return err; return err;
ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL); ts = kzalloc(sizeof(struct ads7846), GFP_KERNEL);
packet = kzalloc(sizeof(struct ads7846_packet), GFP_KERNEL);
input_dev = input_allocate_device(); input_dev = input_allocate_device();
if (!ts || !input_dev) { if (!ts || !packet || !input_dev) {
err = -ENOMEM; err = -ENOMEM;
goto err_free_mem; goto err_free_mem;
} }
dev_set_drvdata(&spi->dev, ts); dev_set_drvdata(&spi->dev, ts);
ts->packet = packet;
ts->spi = spi; ts->spi = spi;
ts->input = input_dev; ts->input = input_dev;
ts->vref_mv = pdata->vref_mv; ts->vref_mv = pdata->vref_mv;
...@@ -893,7 +938,10 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -893,7 +938,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->filter_data = ts; ts->filter_data = ts;
} else } else
ts->filter = ads7846_no_filter; ts->filter = ads7846_no_filter;
ts->get_pendown_state = pdata->get_pendown_state;
err = setup_pendown(spi, ts);
if (err)
goto err_cleanup_filter;
if (pdata->penirq_recheck_delay_usecs) if (pdata->penirq_recheck_delay_usecs)
ts->penirq_recheck_delay_usecs = ts->penirq_recheck_delay_usecs =
...@@ -929,13 +977,13 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -929,13 +977,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m); spi_message_init(m);
/* y- still on; turn on only y+ (and ADC) */ /* y- still on; turn on only y+ (and ADC) */
ts->read_y = READ_Y(vref); packet->read_y = READ_Y(vref);
x->tx_buf = &ts->read_y; x->tx_buf = &packet->read_y;
x->len = 1; x->len = 1;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.y; x->rx_buf = &packet->tc.y;
x->len = 2; x->len = 2;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
...@@ -947,12 +995,12 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -947,12 +995,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->delay_usecs = pdata->settle_delay_usecs; x->delay_usecs = pdata->settle_delay_usecs;
x++; x++;
x->tx_buf = &ts->read_y; x->tx_buf = &packet->read_y;
x->len = 1; x->len = 1;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.y; x->rx_buf = &packet->tc.y;
x->len = 2; x->len = 2;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
} }
...@@ -965,13 +1013,13 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -965,13 +1013,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
/* turn y- off, x+ on, then leave in lowpower */ /* turn y- off, x+ on, then leave in lowpower */
x++; x++;
ts->read_x = READ_X(vref); packet->read_x = READ_X(vref);
x->tx_buf = &ts->read_x; x->tx_buf = &packet->read_x;
x->len = 1; x->len = 1;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.x; x->rx_buf = &packet->tc.x;
x->len = 2; x->len = 2;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
...@@ -980,12 +1028,12 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -980,12 +1028,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->delay_usecs = pdata->settle_delay_usecs; x->delay_usecs = pdata->settle_delay_usecs;
x++; x++;
x->tx_buf = &ts->read_x; x->tx_buf = &packet->read_x;
x->len = 1; x->len = 1;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.x; x->rx_buf = &packet->tc.x;
x->len = 2; x->len = 2;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
} }
...@@ -999,13 +1047,13 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -999,13 +1047,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m); spi_message_init(m);
x++; x++;
ts->read_z1 = READ_Z1(vref); packet->read_z1 = READ_Z1(vref);
x->tx_buf = &ts->read_z1; x->tx_buf = &packet->read_z1;
x->len = 1; x->len = 1;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.z1; x->rx_buf = &packet->tc.z1;
x->len = 2; x->len = 2;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
...@@ -1014,12 +1062,12 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -1014,12 +1062,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->delay_usecs = pdata->settle_delay_usecs; x->delay_usecs = pdata->settle_delay_usecs;
x++; x++;
x->tx_buf = &ts->read_z1; x->tx_buf = &packet->read_z1;
x->len = 1; x->len = 1;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.z1; x->rx_buf = &packet->tc.z1;
x->len = 2; x->len = 2;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
} }
...@@ -1031,13 +1079,13 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -1031,13 +1079,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m); spi_message_init(m);
x++; x++;
ts->read_z2 = READ_Z2(vref); packet->read_z2 = READ_Z2(vref);
x->tx_buf = &ts->read_z2; x->tx_buf = &packet->read_z2;
x->len = 1; x->len = 1;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.z2; x->rx_buf = &packet->tc.z2;
x->len = 2; x->len = 2;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
...@@ -1046,12 +1094,12 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -1046,12 +1094,12 @@ static int __devinit ads7846_probe(struct spi_device *spi)
x->delay_usecs = pdata->settle_delay_usecs; x->delay_usecs = pdata->settle_delay_usecs;
x++; x++;
x->tx_buf = &ts->read_z2; x->tx_buf = &packet->read_z2;
x->len = 1; x->len = 1;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.z2; x->rx_buf = &packet->tc.z2;
x->len = 2; x->len = 2;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
} }
...@@ -1065,13 +1113,13 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -1065,13 +1113,13 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi_message_init(m); spi_message_init(m);
x++; x++;
ts->pwrdown = PWRDOWN; packet->pwrdown = PWRDOWN;
x->tx_buf = &ts->pwrdown; x->tx_buf = &packet->pwrdown;
x->len = 1; x->len = 1;
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->dummy; x->rx_buf = &packet->dummy;
x->len = 2; x->len = 2;
CS_CHANGE(*x); CS_CHANGE(*x);
spi_message_add_tail(x, m); spi_message_add_tail(x, m);
...@@ -1085,7 +1133,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -1085,7 +1133,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi->dev.driver->name, ts)) { spi->dev.driver->name, ts)) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq); dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
err = -EBUSY; err = -EBUSY;
goto err_cleanup_filter; goto err_free_gpio;
} }
err = ads784x_hwmon_register(spi, ts); err = ads784x_hwmon_register(spi, ts);
...@@ -1116,11 +1164,15 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -1116,11 +1164,15 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ads784x_hwmon_unregister(spi, ts); ads784x_hwmon_unregister(spi, ts);
err_free_irq: err_free_irq:
free_irq(spi->irq, ts); free_irq(spi->irq, ts);
err_free_gpio:
if (ts->gpio_pendown != -1)
gpio_free(ts->gpio_pendown);
err_cleanup_filter: err_cleanup_filter:
if (ts->filter_cleanup) if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data); ts->filter_cleanup(ts->filter_data);
err_free_mem: err_free_mem:
input_free_device(input_dev); input_free_device(input_dev);
kfree(packet);
kfree(ts); kfree(ts);
return err; return err;
} }
...@@ -1140,9 +1192,13 @@ static int __devexit ads7846_remove(struct spi_device *spi) ...@@ -1140,9 +1192,13 @@ static int __devexit ads7846_remove(struct spi_device *spi)
/* suspend left the IRQ disabled */ /* suspend left the IRQ disabled */
enable_irq(ts->spi->irq); enable_irq(ts->spi->irq);
if (ts->gpio_pendown != -1)
gpio_free(ts->gpio_pendown);
if (ts->filter_cleanup) if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data); ts->filter_cleanup(ts->filter_data);
kfree(ts->packet);
kfree(ts); kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n"); dev_dbg(&spi->dev, "unregistered touchscreen\n");
......
...@@ -91,6 +91,9 @@ struct atmel_tsadcc { ...@@ -91,6 +91,9 @@ struct atmel_tsadcc {
char phys[32]; char phys[32];
struct clk *clk; struct clk *clk;
int irq; int irq;
unsigned int prev_absx;
unsigned int prev_absy;
unsigned char bufferedmeasure;
}; };
static void __iomem *tsc_base; static void __iomem *tsc_base;
...@@ -100,10 +103,9 @@ static void __iomem *tsc_base; ...@@ -100,10 +103,9 @@ static void __iomem *tsc_base;
static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) 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 status;
unsigned int reg; unsigned int reg;
...@@ -121,6 +123,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) ...@@ -121,6 +123,7 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT); atmel_tsadcc_write(ATMEL_TSADCC_IER, ATMEL_TSADCC_PENCNT);
input_report_key(input_dev, BTN_TOUCH, 0); input_report_key(input_dev, BTN_TOUCH, 0);
ts_dev->bufferedmeasure = 0;
input_sync(input_dev); input_sync(input_dev);
} else if (status & ATMEL_TSADCC_PENCNT) { } else if (status & ATMEL_TSADCC_PENCNT) {
...@@ -138,16 +141,23 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev) ...@@ -138,16 +141,23 @@ static irqreturn_t atmel_tsadcc_interrupt(int irq, void *dev)
} else if (status & ATMEL_TSADCC_EOC(3)) { } else if (status & ATMEL_TSADCC_EOC(3)) {
/* Conversion finished */ /* Conversion finished */
absx = atmel_tsadcc_read(ATMEL_TSADCC_CDR3) << 10; if (ts_dev->bufferedmeasure) {
absx /= atmel_tsadcc_read(ATMEL_TSADCC_CDR2); /* Last measurement is always discarded, since it can
* be erroneous.
absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10; * Always report previous measurement */
absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0); input_report_abs(input_dev, ABS_X, ts_dev->prev_absx);
input_report_abs(input_dev, ABS_Y, ts_dev->prev_absy);
input_report_abs(input_dev, ABS_X, absx); input_report_key(input_dev, BTN_TOUCH, 1);
input_report_abs(input_dev, ABS_Y, absy); input_sync(input_dev);
input_report_key(input_dev, BTN_TOUCH, 1); } else
input_sync(input_dev); ts_dev->bufferedmeasure = 1;
/* 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);
ts_dev->prev_absy = atmel_tsadcc_read(ATMEL_TSADCC_CDR1) << 10;
ts_dev->prev_absy /= atmel_tsadcc_read(ATMEL_TSADCC_CDR0);
} }
return IRQ_HANDLED; return IRQ_HANDLED;
...@@ -223,6 +233,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev) ...@@ -223,6 +233,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
} }
ts_dev->input = input_dev; ts_dev->input = input_dev;
ts_dev->bufferedmeasure = 0;
snprintf(ts_dev->phys, sizeof(ts_dev->phys), snprintf(ts_dev->phys, sizeof(ts_dev->phys),
"%s/input0", pdev->dev.bus_id); "%s/input0", pdev->dev.bus_id);
......
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
* Wolfson WM97xx AC97 Codecs. * Wolfson WM97xx AC97 Codecs.
* *
* Copyright 2004, 2007 Wolfson Microelectronics PLC. * Copyright 2004, 2007 Wolfson Microelectronics PLC.
* Author: Liam Girdwood * Author: Liam Girdwood <lrg@slimlogic.co.uk>
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Parts Copyright : Ian Molton <spyro@f2s.com> * Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru> * Andrew Zabolotny <zap@homelink.ru>
* *
...@@ -296,6 +295,6 @@ module_init(mainstone_wm97xx_init); ...@@ -296,6 +295,6 @@ module_init(mainstone_wm97xx_init);
module_exit(mainstone_wm97xx_exit); module_exit(mainstone_wm97xx_exit);
/* Module information */ /* 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_DESCRIPTION("wm97xx continuous touch driver for mainstone");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
* wm9705.c -- Codec driver for Wolfson WM9705 AC97 Codec. * wm9705.c -- Codec driver for Wolfson WM9705 AC97 Codec.
* *
* Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC. * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
* Author: Liam Girdwood * Author: Liam Girdwood <lrg@slimlogic.co.uk>
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Parts Copyright : Ian Molton <spyro@f2s.com> * Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru> * Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk> * Russell King <rmk@arm.linux.org.uk>
...@@ -347,6 +346,6 @@ struct wm97xx_codec_drv wm9705_codec = { ...@@ -347,6 +346,6 @@ struct wm97xx_codec_drv wm9705_codec = {
EXPORT_SYMBOL_GPL(wm9705_codec); EXPORT_SYMBOL_GPL(wm9705_codec);
/* Module information */ /* 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_DESCRIPTION("WM9705 Touch Screen Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
* wm9712.c -- Codec driver for Wolfson WM9712 AC97 Codecs. * wm9712.c -- Codec driver for Wolfson WM9712 AC97 Codecs.
* *
* Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC. * Copyright 2003, 2004, 2005, 2006, 2007 Wolfson Microelectronics PLC.
* Author: Liam Girdwood * Author: Liam Girdwood <lrg@slimlogic.co.uk>
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Parts Copyright : Ian Molton <spyro@f2s.com> * Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru> * Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk> * Russell King <rmk@arm.linux.org.uk>
...@@ -462,6 +461,6 @@ struct wm97xx_codec_drv wm9712_codec = { ...@@ -462,6 +461,6 @@ struct wm97xx_codec_drv wm9712_codec = {
EXPORT_SYMBOL_GPL(wm9712_codec); EXPORT_SYMBOL_GPL(wm9712_codec);
/* Module information */ /* 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_DESCRIPTION("WM9712 Touch Screen Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -2,8 +2,7 @@ ...@@ -2,8 +2,7 @@
* wm9713.c -- Codec touch driver for Wolfson WM9713 AC97 Codec. * wm9713.c -- Codec touch driver for Wolfson WM9713 AC97 Codec.
* *
* Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC. * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
* Author: Liam Girdwood * Author: Liam Girdwood <lrg@slimlogic.co.uk>
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Parts Copyright : Ian Molton <spyro@f2s.com> * Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru> * Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk> * Russell King <rmk@arm.linux.org.uk>
...@@ -476,6 +475,6 @@ struct wm97xx_codec_drv wm9713_codec = { ...@@ -476,6 +475,6 @@ struct wm97xx_codec_drv wm9713_codec = {
EXPORT_SYMBOL_GPL(wm9713_codec); EXPORT_SYMBOL_GPL(wm9713_codec);
/* Module information */ /* 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_DESCRIPTION("WM9713 Touch Screen Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -3,8 +3,7 @@ ...@@ -3,8 +3,7 @@
* and WM9713 AC97 Codecs. * and WM9713 AC97 Codecs.
* *
* Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC. * Copyright 2003, 2004, 2005, 2006, 2007, 2008 Wolfson Microelectronics PLC.
* Author: Liam Girdwood * Author: Liam Girdwood <lrg@slimlogic.co.uk>
* liam.girdwood@wolfsonmicro.com or linux@wolfsonmicro.com
* Parts Copyright : Ian Molton <spyro@f2s.com> * Parts Copyright : Ian Molton <spyro@f2s.com>
* Andrew Zabolotny <zap@homelink.ru> * Andrew Zabolotny <zap@homelink.ru>
* Russell King <rmk@arm.linux.org.uk> * Russell King <rmk@arm.linux.org.uk>
...@@ -824,6 +823,6 @@ module_init(wm97xx_init); ...@@ -824,6 +823,6 @@ module_init(wm97xx_init);
module_exit(wm97xx_exit); module_exit(wm97xx_exit);
/* Module information */ /* 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_DESCRIPTION("WM97xx Core - Touch Screen / AUX ADC / GPIO Driver");
MODULE_LICENSE("GPL"); MODULE_LICENSE("GPL");
...@@ -107,6 +107,7 @@ header-y += keyctl.h ...@@ -107,6 +107,7 @@ header-y += keyctl.h
header-y += limits.h header-y += limits.h
header-y += magic.h header-y += magic.h
header-y += major.h header-y += major.h
header-y += map_to_7segment.h
header-y += matroxfb.h header-y += matroxfb.h
header-y += meye.h header-y += meye.h
header-y += minix_fs.h header-y += minix_fs.h
......
...@@ -146,10 +146,11 @@ static inline void gameport_unpin_driver(struct gameport *gameport) ...@@ -146,10 +146,11 @@ static inline void gameport_unpin_driver(struct gameport *gameport)
mutex_unlock(&gameport->drv_mutex); mutex_unlock(&gameport->drv_mutex);
} }
void __gameport_register_driver(struct gameport_driver *drv, struct module *owner); int __gameport_register_driver(struct gameport_driver *drv,
static inline void 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); void gameport_unregister_driver(struct gameport_driver *drv);
......
...@@ -577,9 +577,22 @@ struct input_absinfo { ...@@ -577,9 +577,22 @@ struct input_absinfo {
#define KEY_BRL_DOT9 0x1f9 #define KEY_BRL_DOT9 0x1f9
#define KEY_BRL_DOT10 0x1fa #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. */ /* We avoid low common keys in module aliases so they don't get huge. */
#define KEY_MIN_INTERESTING KEY_MUTE #define KEY_MIN_INTERESTING KEY_MUTE
#define KEY_MAX 0x1ff #define KEY_MAX 0x2ff
#define KEY_CNT (KEY_MAX+1) #define KEY_CNT (KEY_MAX+1)
/* /*
......
/* /*
* drivers/usb/input/map_to_7segment.h
*
* Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com> * Copyright (c) 2005 Henk Vergonet <Henk.Vergonet@gmail.com>
* *
* This program is free software; you can redistribute it and/or * This program is free software; you can redistribute it and/or
...@@ -36,7 +34,7 @@ ...@@ -36,7 +34,7 @@
* Usage: * Usage:
* *
* Register a map variable, and fill it with a character set: * 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: * Then use for conversion:
......
...@@ -274,7 +274,7 @@ struct pcmcia_device_id { ...@@ -274,7 +274,7 @@ struct pcmcia_device_id {
/* Input */ /* Input */
#define INPUT_DEVICE_ID_EV_MAX 0x1f #define INPUT_DEVICE_ID_EV_MAX 0x1f
#define INPUT_DEVICE_ID_KEY_MIN_INTERESTING 0x71 #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_REL_MAX 0x0f
#define INPUT_DEVICE_ID_ABS_MAX 0x3f #define INPUT_DEVICE_ID_ABS_MAX 0x3f
#define INPUT_DEVICE_ID_MSC_MAX 0x07 #define INPUT_DEVICE_ID_MSC_MAX 0x07
......
...@@ -43,6 +43,9 @@ struct ads7846_platform_data { ...@@ -43,6 +43,9 @@ struct ads7846_platform_data {
u16 debounce_tol; /* tolerance used for filtering */ u16 debounce_tol; /* tolerance used for filtering */
u16 debounce_rep; /* additional consecutive good readings u16 debounce_rep; /* additional consecutive good readings
* required after the first two */ * required after the first two */
int gpio_pendown; /* the GPIO used to decide the pendown
* state if get_pendown_state == NULL
*/
int (*get_pendown_state)(void); int (*get_pendown_state)(void);
int (*filter_init) (struct ads7846_platform_data *pdata, int (*filter_init) (struct ads7846_platform_data *pdata,
void **filter_data); void **filter_data);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment