From 8a1b170898cd827b24cbf02c43c57f8489e9ccce Mon Sep 17 00:00:00 2001 From: Stefan Rompf Date: Wed, 5 Apr 2006 00:39:20 -0400 Subject: Input: wistron - add signature for Amilo M7400 Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 4b415d9b012..6ec05985a14 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -321,6 +321,15 @@ static struct dmi_system_id dmi_ids[] = { }, .driver_data = keymap_fs_amilo_pro_v2000 }, + { + .callback = dmi_matched, + .ident = "Fujitsu-Siemens Amilo M7400", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU SIEMENS"), + DMI_MATCH(DMI_PRODUCT_NAME, "AMILO M "), + }, + .driver_data = keymap_fs_amilo_pro_v2000 + }, { .callback = dmi_matched, .ident = "Acer Aspire 1500", -- cgit From e2aa507a837cbaa376faa3d9f8448ff569d34ccf Mon Sep 17 00:00:00 2001 From: John Reed Riley Date: Wed, 5 Apr 2006 00:40:01 -0400 Subject: Input: wistron - add support for Fujitsu N3510 Signed-off-by: Dmitry Torokhov --- drivers/input/misc/wistron_btns.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/misc/wistron_btns.c b/drivers/input/misc/wistron_btns.c index 6ec05985a14..36cd2e07fce 100644 --- a/drivers/input/misc/wistron_btns.c +++ b/drivers/input/misc/wistron_btns.c @@ -273,6 +273,18 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] = { { KE_END, 0 } }; +static struct key_entry keymap_fujitsu_n3510[] = { + { KE_KEY, 0x11, KEY_PROG1 }, + { KE_KEY, 0x12, KEY_PROG2 }, + { KE_KEY, 0x36, KEY_WWW }, + { KE_KEY, 0x31, KEY_MAIL }, + { KE_KEY, 0x71, KEY_STOPCD }, + { KE_KEY, 0x72, KEY_PLAYPAUSE }, + { KE_KEY, 0x74, KEY_REWIND }, + { KE_KEY, 0x78, KEY_FORWARD }, + { KE_END, 0 } +}; + static struct key_entry keymap_wistron_ms2141[] = { { KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x12, KEY_PROG2 }, @@ -330,6 +342,15 @@ static struct dmi_system_id dmi_ids[] = { }, .driver_data = keymap_fs_amilo_pro_v2000 }, + { + .callback = dmi_matched, + .ident = "Fujitsu N3510", + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"), + DMI_MATCH(DMI_PRODUCT_NAME, "N3510"), + }, + .driver_data = keymap_fujitsu_n3510 + }, { .callback = dmi_matched, .ident = "Acer Aspire 1500", -- cgit From 438f2a7401ec5d8f85923a7c3e6da444f097a3a1 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 11 Apr 2006 23:41:32 -0400 Subject: Input: ads7846 - add pen_down sysfs attribute It's handy for userspace diagnostics to see the pen down status, to see whether the touchscreen is "stuck" (shortcircuited). Signed-off-by: Imre Deak Signed-off-by: Juha Yrjola Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 46d1fec2cfd..7f384a694d8 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -233,6 +233,21 @@ SHOW(temp1) SHOW(vaux) SHOW(vbatt) +static int is_pen_down(struct device *dev) +{ + struct ads7846 *ts = dev_get_drvdata(dev); + + return ts->pendown; +} + +static ssize_t ads7846_pen_down_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + return sprintf(buf, "%u\n", is_pen_down(dev)); +} + +static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL); + /*--------------------------------------------------------------------------*/ /* @@ -559,6 +574,8 @@ static int __devinit ads7846_probe(struct spi_device *spi) device_create_file(&spi->dev, &dev_attr_vbatt); device_create_file(&spi->dev, &dev_attr_vaux); + device_create_file(&spi->dev, &dev_attr_pen_down); + err = input_register_device(input_dev); if (err) goto err_free_irq; @@ -582,6 +599,8 @@ static int __devexit ads7846_remove(struct spi_device *spi) if (ts->irq_disabled) enable_irq(ts->spi->irq); + device_remove_file(&spi->dev, &dev_attr_pen_down); + if (ts->model == 7846) { device_remove_file(&spi->dev, &dev_attr_temp0); device_remove_file(&spi->dev, &dev_attr_temp1); -- cgit From 53a0ef89e95c725f3faab98573770aeb7429c1a3 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 11 Apr 2006 23:41:49 -0400 Subject: Input: ads7846 - power down ADC a bit later Submit a seperate request for powering down the ADC in ads7846, doing it after the last read request. Otherwise some of the read values are incorrect. Signed-off-by: Imre Deak Signed-off-by: Juha Yrjola Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 7f384a694d8..54d43347786 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -72,10 +72,11 @@ struct ads7846 { u16 vref_delay_usecs; u16 x_plate_ohms; - u8 read_x, read_y, read_z1, read_z2; + u8 read_x, read_y, read_z1, read_z2, pwrdown; + u16 dummy; /* for the pwrdown read */ struct ts_event tc; - struct spi_transfer xfer[8]; + struct spi_transfer xfer[10]; struct spi_message msg; spinlock_t lock; @@ -125,7 +126,9 @@ struct ads7846 { #define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON) #define READ_Z1 (READ_12BIT_DFR(z1) | ADS_PD10_ADC_ON) #define READ_Z2 (READ_12BIT_DFR(z2) | ADS_PD10_ADC_ON) -#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_PDOWN) /* LAST */ + +#define READ_X (READ_12BIT_DFR(x) | ADS_PD10_ADC_ON) +#define PWRDOWN (READ_12BIT_DFR(y) | ADS_PD10_PDOWN) /* LAST */ /* single-ended samples need to first power up reference voltage; * we leave both ADC and VREF powered @@ -541,6 +544,18 @@ static int __devinit ads7846_probe(struct spi_device *spi) x++; x->rx_buf = &ts->tc.x; x->len = 2; + spi_message_add_tail(x, &ts->msg); + + /* power down */ + x++; + ts->pwrdown = PWRDOWN; + x->tx_buf = &ts->pwrdown; + x->len = 1; + spi_message_add_tail(x, &ts->msg); + + x++; + x->rx_buf = &ts->dummy; + x->len = 2; CS_CHANGE(*x); spi_message_add_tail(x, &ts->msg); -- cgit From 0b7018aae7e1798f55f736b9a77c201708aa0e33 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 11 Apr 2006 23:42:03 -0400 Subject: Input: ads7846 - debouncing and rudimentary sample filtering MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some touchscreens seem to oscillate heavily for a while after touching the screen.  Implement support for sampling the screen until we get two consecutive values that are close enough. Signed-off-by: Imre Deak Signed-off-by: Juha Yrjola Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 156 +++++++++++++++++++++++++++--------- 1 file changed, 118 insertions(+), 38 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 54d43347786..8670cd13bd5 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -77,7 +77,13 @@ struct ads7846 { struct ts_event tc; struct spi_transfer xfer[10]; - struct spi_message msg; + struct spi_message msg[5]; + int msg_idx; + int read_cnt; + int last_read; + + u16 debounce_max; + u16 debounce_tol; spinlock_t lock; struct timer_list timer; /* P: lock */ @@ -167,7 +173,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) if (!req) return -ENOMEM; - INIT_LIST_HEAD(&req->msg.transfers); + spi_message_init(&req->msg); /* activate reference, so it has time to settle; */ req->ref_on = REF_ON; @@ -344,31 +350,76 @@ static void ads7846_rx(void *ads) spin_unlock_irqrestore(&ts->lock, flags); } +static void ads7846_debounce(void *ads) +{ + struct ads7846 *ts = ads; + struct spi_message *m; + struct spi_transfer *t; + u16 val; + int status; + + m = &ts->msg[ts->msg_idx]; + t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); + val = (*(u16 *)t->rx_buf) >> 3; + + if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol + && ts->read_cnt < ts->debounce_max)) { + /* Repeat it, if this was the first read or the read wasn't + * consistent enough + */ + ts->read_cnt++; + ts->last_read = val; + } else { + /* Go for the next read */ + ts->msg_idx++; + ts->read_cnt = 0; + m++; + } + status = spi_async(ts->spi, m); + if (status) + dev_err(&ts->spi->dev, "spi_async --> %d\n", + status); +} + static void ads7846_timer(unsigned long handle) { struct ads7846 *ts = (void *)handle; int status = 0; - unsigned long flags; + + ts->msg_idx = 0; + status = spi_async(ts->spi, &ts->msg[0]); + if (status) + dev_err(&ts->spi->dev, "spi_async --> %d\n", status); +} + +static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) +{ + struct ads7846 *ts = handle; + unsigned long flags; + int r = IRQ_HANDLED; spin_lock_irqsave(&ts->lock, flags); - if (!ts->pending) { - ts->pending = 1; + if (ts->irq_disabled) + r = IRQ_HANDLED; + else { if (!ts->irq_disabled) { + /* REVISIT irq logic for many ARM chips has cloned a + * bug wherein disabling an irq in its handler won't + * work;(it's disabled lazily, and too late to work. + * until all their irq logic is fixed, we must shadow + * that state here. + */ ts->irq_disabled = 1; + disable_irq(ts->spi->irq); } - status = spi_async(ts->spi, &ts->msg); - if (status) - dev_err(&ts->spi->dev, "spi_async --> %d\n", - status); + if (!ts->pending) { + ts->pending = 1; + mod_timer(&ts->timer, jiffies); + } } spin_unlock_irqrestore(&ts->lock, flags); -} - -static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) -{ - ads7846_timer((unsigned long) handle); - return IRQ_HANDLED; + return r; } /*--------------------------------------------------------------------------*/ @@ -426,6 +477,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) struct ads7846 *ts; struct input_dev *input_dev; struct ads7846_platform_data *pdata = spi->dev.platform_data; + struct spi_message *m; struct spi_transfer *x; int err; @@ -472,6 +524,8 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->model = pdata->model ? : 7846; ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; + ts->debounce_max = pdata->debounce_max ? : 1; + ts->debounce_tol = pdata->debounce_tol ? : 10; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); @@ -495,72 +549,98 @@ static int __devinit ads7846_probe(struct spi_device *spi) /* set up the transfers to read touchscreen state; this assumes we * use formula #2 for pressure, not #3. */ - INIT_LIST_HEAD(&ts->msg.transfers); + m = &ts->msg[0]; x = ts->xfer; + spi_message_init(m); + /* y- still on; turn on only y+ (and ADC) */ ts->read_y = READ_Y; x->tx_buf = &ts->read_y; x->len = 1; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); x++; x->rx_buf = &ts->tc.y; x->len = 2; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); + + m->complete = ads7846_debounce; + m->context = ts; + + m++; + spi_message_init(m); + + /* turn y- off, x+ on, then leave in lowpower */ + x++; + ts->read_x = READ_X; + x->tx_buf = &ts->read_x; + x->len = 1; + spi_message_add_tail(x, m); + + x++; + x->rx_buf = &ts->tc.x; + x->len = 2; + spi_message_add_tail(x, m); + + m->complete = ads7846_debounce; + m->context = ts; /* turn y+ off, x- on; we'll use formula #2 */ if (ts->model == 7846) { + m++; + spi_message_init(m); + x++; ts->read_z1 = READ_Z1; x->tx_buf = &ts->read_z1; x->len = 1; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); x++; x->rx_buf = &ts->tc.z1; x->len = 2; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); + + m->complete = ads7846_debounce; + m->context = ts; + + m++; + spi_message_init(m); x++; ts->read_z2 = READ_Z2; x->tx_buf = &ts->read_z2; x->len = 1; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); x++; x->rx_buf = &ts->tc.z2; x->len = 2; - spi_message_add_tail(x, &ts->msg); - } + spi_message_add_tail(x, m); - /* turn y- off, x+ on, then leave in lowpower */ - x++; - ts->read_x = READ_X; - x->tx_buf = &ts->read_x; - x->len = 1; - spi_message_add_tail(x, &ts->msg); - - x++; - x->rx_buf = &ts->tc.x; - x->len = 2; - spi_message_add_tail(x, &ts->msg); + m->complete = ads7846_debounce; + m->context = ts; + } /* power down */ + m++; + spi_message_init(m); + x++; ts->pwrdown = PWRDOWN; x->tx_buf = &ts->pwrdown; x->len = 1; - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); x++; x->rx_buf = &ts->dummy; x->len = 2; CS_CHANGE(*x); - spi_message_add_tail(x, &ts->msg); + spi_message_add_tail(x, m); - ts->msg.complete = ads7846_rx; - ts->msg.context = ts; + m->complete = ads7846_rx; + m->context = ts; if (request_irq(spi->irq, ads7846_irq, SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING, -- cgit From c4febb94dae915da4423b81c487eabed9cef5cba Mon Sep 17 00:00:00 2001 From: Juha Yrjola Date: Tue, 11 Apr 2006 23:42:25 -0400 Subject: Input: ads7846 - use msleep() instead of udelay() in suspend Sometimes a polling loop had a hard time changing state without pre-emption enabled. Use msleep instead, it's better anyway. Signed-off-by: Juha Yrjola Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 8670cd13bd5..bdec112e89c 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -449,7 +449,7 @@ ads7846_suspend(struct spi_device *spi, pm_message_t message) while (ts->pendown || ts->pending) { spin_unlock_irqrestore(&ts->lock, flags); - udelay(10); + msleep(1); spin_lock_irqsave(&ts->lock, flags); } } -- cgit From 7de90a8cb9c51145d7f60d8db17ce0fa07d1b281 Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 11 Apr 2006 23:43:55 -0400 Subject: Input: ads7846 - miscellaneous fixes - Add disable attribute to support device locking mode where unintentional touch event shouldn't wake up the system; - Update comments; - Add missing spin_lock_init; - Do device resume with the lock held; - Do cleanup calls / free memory in the reverse order of initialization. Signed-off-by: Imre Deak Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 144 ++++++++++++++++++++++++++++-------- 1 file changed, 114 insertions(+), 30 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index bdec112e89c..fec3b9b2230 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -2,6 +2,8 @@ * ADS7846 based touchscreen and sensor driver * * Copyright (c) 2005 David Brownell + * Copyright (c) 2006 Nokia Corporation + * Various changes: Imre Deak * * Using code from: * - corgi_ts.c @@ -34,17 +36,25 @@ /* - * This code has been lightly tested on an ads7846. + * This code has been tested on an ads7846 / N770 device. * Support for ads7843 and ads7845 has only been stubbed in. * - * Not yet done: investigate the values reported. Are x/y/pressure - * event values sane enough for X11? How accurate are the temperature - * and voltage readings? (System-specific calibration should support + * Not yet done: How accurate are the temperature and voltage + * readings? (System-specific calibration should support * accuracy of 0.3 degrees C; otherwise it's 2.0 degrees.) * + * IRQ handling needs a workaround because of a shortcoming in handling + * edge triggered IRQs on some platforms like the OMAP1/2. These + * platforms don't handle the ARM lazy IRQ disabling properly, thus we + * have to maintain our own SW IRQ disabled status. This should be + * removed as soon as the affected platform's IRQ handling is fixed. + * * app note sbaa036 talks in more detail about accurate sampling... * that ought to help in situations like LCDs inducing noise (which * can also be helped by using synch signals) and more generally. + * This driver tries to utilize the measures described in the app + * note. The strength of filtering can be set in the board-* specific + * files. */ #define TS_POLL_PERIOD msecs_to_jiffies(10) @@ -91,6 +101,7 @@ struct ads7846 { unsigned pending:1; /* P: lock */ // FIXME remove "irq_disabled" unsigned irq_disabled:1; /* P: lock */ + unsigned disabled:1; }; /* leave chip selected when we're done, for quicker re-select? */ @@ -161,6 +172,9 @@ struct ser_req { struct spi_transfer xfer[6]; }; +static void ads7846_enable(struct ads7846 *ts); +static void ads7846_disable(struct ads7846 *ts); + static int ads7846_read12_ser(struct device *dev, unsigned command) { struct spi_device *spi = to_spi_device(dev); @@ -257,6 +271,37 @@ static ssize_t ads7846_pen_down_show(struct device *dev, static DEVICE_ATTR(pen_down, S_IRUGO, ads7846_pen_down_show, NULL); +static ssize_t ads7846_disable_show(struct device *dev, + struct device_attribute *attr, char *buf) +{ + struct ads7846 *ts = dev_get_drvdata(dev); + + return sprintf(buf, "%u\n", ts->disabled); +} + +static ssize_t ads7846_disable_store(struct device *dev, + struct device_attribute *attr, + const char *buf, size_t count) +{ + struct ads7846 *ts = dev_get_drvdata(dev); + char *endp; + int i; + + i = simple_strtoul(buf, &endp, 10); + spin_lock_irq(&ts->lock); + + if (i) + ads7846_disable(ts); + else + ads7846_enable(ts); + + spin_unlock_irq(&ts->lock); + + return count; +} + +static DEVICE_ATTR(disable, 0664, ads7846_disable_show, ads7846_disable_store); + /*--------------------------------------------------------------------------*/ /* @@ -396,12 +441,9 @@ static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) { struct ads7846 *ts = handle; unsigned long flags; - int r = IRQ_HANDLED; spin_lock_irqsave(&ts->lock, flags); - if (ts->irq_disabled) - r = IRQ_HANDLED; - else { + if (likely(!ts->irq_disabled && !ts->disabled)) { if (!ts->irq_disabled) { /* REVISIT irq logic for many ARM chips has cloned a * bug wherein disabling an irq in its handler won't @@ -419,20 +461,17 @@ static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) } } spin_unlock_irqrestore(&ts->lock, flags); - return r; + + return IRQ_HANDLED; } /*--------------------------------------------------------------------------*/ -static int -ads7846_suspend(struct spi_device *spi, pm_message_t message) +/* Must be called with ts->lock held */ +static void ads7846_disable(struct ads7846 *ts) { - struct ads7846 *ts = dev_get_drvdata(&spi->dev); - unsigned long flags; - - spin_lock_irqsave(&ts->lock, flags); - - spi->dev.power.power_state = message; + if (ts->disabled) + return; /* are we waiting for IRQ, or polling? */ if (!ts->pendown) { @@ -448,9 +487,9 @@ ads7846_suspend(struct spi_device *spi, pm_message_t message) mod_timer(&ts->timer, jiffies); while (ts->pendown || ts->pending) { - spin_unlock_irqrestore(&ts->lock, flags); + spin_unlock_irq(&ts->lock); msleep(1); - spin_lock_irqsave(&ts->lock, flags); + spin_lock_irq(&ts->lock); } } @@ -458,17 +497,46 @@ ads7846_suspend(struct spi_device *spi, pm_message_t message) * leave it that way after every request */ - spin_unlock_irqrestore(&ts->lock, flags); + ts->disabled = 1; +} + +/* Must be called with ts->lock held */ +static void ads7846_enable(struct ads7846 *ts) +{ + if (!ts->disabled) + return; + + ts->disabled = 0; + ts->irq_disabled = 0; + enable_irq(ts->spi->irq); +} + +static int ads7846_suspend(struct spi_device *spi, pm_message_t message) +{ + struct ads7846 *ts = dev_get_drvdata(&spi->dev); + + spin_lock_irq(&ts->lock); + + spi->dev.power.power_state = message; + ads7846_disable(ts); + + spin_unlock_irq(&ts->lock); + return 0; + } static int ads7846_resume(struct spi_device *spi) { struct ads7846 *ts = dev_get_drvdata(&spi->dev); - ts->irq_disabled = 0; - enable_irq(ts->spi->irq); + spin_lock_irq(&ts->lock); + spi->dev.power.power_state = PMSG_ON; + ads7846_enable(ts); + + spin_unlock_irq(&ts->lock); + return 0; } @@ -521,6 +589,8 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->timer.data = (unsigned long) ts; ts->timer.function = ads7846_timer; + spin_lock_init(&ts->lock); + ts->model = pdata->model ? : 7846; ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; @@ -671,13 +741,25 @@ static int __devinit ads7846_probe(struct spi_device *spi) device_create_file(&spi->dev, &dev_attr_pen_down); + device_create_file(&spi->dev, &dev_attr_disable); + err = input_register_device(input_dev); if (err) - goto err_free_irq; + goto err_remove_attr; return 0; - err_free_irq: + err_remove_attr: + device_remove_file(&spi->dev, &dev_attr_disable); + device_remove_file(&spi->dev, &dev_attr_pen_down); + if (ts->model == 7846) { + device_remove_file(&spi->dev, &dev_attr_temp1); + device_remove_file(&spi->dev, &dev_attr_temp0); + } + if (ts->model != 7845) + device_remove_file(&spi->dev, &dev_attr_vbatt); + device_remove_file(&spi->dev, &dev_attr_vaux); + free_irq(spi->irq, ts); err_free_mem: input_free_device(input_dev); @@ -689,22 +771,24 @@ static int __devexit ads7846_remove(struct spi_device *spi) { struct ads7846 *ts = dev_get_drvdata(&spi->dev); + input_unregister_device(ts->input); + ads7846_suspend(spi, PMSG_SUSPEND); - free_irq(ts->spi->irq, ts); - if (ts->irq_disabled) - enable_irq(ts->spi->irq); + device_remove_file(&spi->dev, &dev_attr_disable); device_remove_file(&spi->dev, &dev_attr_pen_down); - if (ts->model == 7846) { - device_remove_file(&spi->dev, &dev_attr_temp0); device_remove_file(&spi->dev, &dev_attr_temp1); + device_remove_file(&spi->dev, &dev_attr_temp0); } if (ts->model != 7845) device_remove_file(&spi->dev, &dev_attr_vbatt); device_remove_file(&spi->dev, &dev_attr_vaux); - input_unregister_device(ts->input); + free_irq(ts->spi->irq, ts); + if (ts->irq_disabled) + enable_irq(ts->spi->irq); + kfree(ts); dev_dbg(&spi->dev, "unregistered touchscreen\n"); -- cgit From c9e617a563ad646239270fa2222cdb06966cf1fa Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Tue, 11 Apr 2006 23:44:05 -0400 Subject: Input: ads7846 - handle IRQs that were latched during disabled IRQs The pen down IRQ will toggle during each X,Y,Z measurement cycle. Even though the IRQ is disabled it will be latched and delivered when after enable_irq. Thus in the IRQ handler we must avoid starting a new measurement cycle when such an "unwanted" IRQ happens. Add a get_pendown_state platform function, which will probably determine this by reading the current GPIO level of the pen IRQ pin. Move the IRQ reenabling from the SPI RX function to the timer. After the last power down message the pen IRQ pin is still active for a while and get_pendown_state would report incorrectly a pen down state. When suspending we should check the ts->pending flag instead of ts->pendown, since the timer can be pending regardless of ts->pendown. Also if ts->pending is set we can be sure that the timer is running, so no need to rearm it. Similarly if ts->pending is not set we can be sure that the IRQ is enabled (and the timer is not). Signed-off-by: Imre Deak Signed-off-by: David Brownell Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 82 ++++++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 34 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index fec3b9b2230..e7cabf12c8d 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -102,6 +102,8 @@ struct ads7846 { // FIXME remove "irq_disabled" unsigned irq_disabled:1; /* P: lock */ unsigned disabled:1; + + int (*get_pendown_state)(void); }; /* leave chip selected when we're done, for quicker re-select? */ @@ -175,6 +177,12 @@ struct ser_req { static void ads7846_enable(struct ads7846 *ts); static void ads7846_disable(struct ads7846 *ts); +static int device_suspended(struct device *dev) +{ + struct ads7846 *ts = dev_get_drvdata(dev); + return dev->power.power_state.event != PM_EVENT_ON || ts->disabled; +} + static int ads7846_read12_ser(struct device *dev, unsigned command) { struct spi_device *spi = to_spi_device(dev); @@ -227,8 +235,10 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) for (i = 0; i < 6; i++) spi_message_add_tail(&req->xfer[i], &req->msg); + ts->irq_disabled = 1; disable_irq(spi->irq); status = spi_sync(spi, &req->msg); + ts->irq_disabled = 0; enable_irq(spi->irq); if (req->msg.status) @@ -333,7 +343,7 @@ static void ads7846_rx(void *ads) if (x == MAX_12BIT) x = 0; - if (x && z1 && ts->spi->dev.power.power_state.event == PM_EVENT_ON) { + if (likely(x && z1 && !device_suspended(&ts->spi->dev))) { /* compute touch pressure resistance using equation #2 */ Rt = z2; Rt -= z1; @@ -377,20 +387,10 @@ static void ads7846_rx(void *ads) x, y, Rt, Rt ? "" : " UP"); #endif - /* don't retrigger while we're suspended */ spin_lock_irqsave(&ts->lock, flags); ts->pendown = (Rt != 0); - ts->pending = 0; - - if (ts->spi->dev.power.power_state.event == PM_EVENT_ON) { - if (ts->pendown) - mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); - else if (ts->irq_disabled) { - ts->irq_disabled = 0; - enable_irq(ts->spi->irq); - } - } + mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); spin_unlock_irqrestore(&ts->lock, flags); } @@ -431,10 +431,25 @@ static void ads7846_timer(unsigned long handle) struct ads7846 *ts = (void *)handle; int status = 0; - ts->msg_idx = 0; - status = spi_async(ts->spi, &ts->msg[0]); - if (status) - dev_err(&ts->spi->dev, "spi_async --> %d\n", status); + spin_lock_irq(&ts->lock); + + if (unlikely(ts->msg_idx && !ts->pendown)) { + /* measurment cycle ended */ + if (!device_suspended(&ts->spi->dev)) { + ts->irq_disabled = 0; + enable_irq(ts->spi->irq); + } + ts->pending = 0; + ts->msg_idx = 0; + } else { + /* pen is still down, continue with the measurement */ + ts->msg_idx = 0; + status = spi_async(ts->spi, &ts->msg[0]); + if (status) + dev_err(&ts->spi->dev, "spi_async --> %d\n", status); + } + + spin_unlock_irq(&ts->lock); } static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) @@ -443,7 +458,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) unsigned long flags; spin_lock_irqsave(&ts->lock, flags); - if (likely(!ts->irq_disabled && !ts->disabled)) { + if (likely(ts->get_pendown_state())) { if (!ts->irq_disabled) { /* REVISIT irq logic for many ARM chips has cloned a * bug wherein disabling an irq in its handler won't @@ -452,10 +467,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle, struct pt_regs *regs) * that state here. */ ts->irq_disabled = 1; - disable_irq(ts->spi->irq); - } - if (!ts->pending) { ts->pending = 1; mod_timer(&ts->timer, jiffies); } @@ -473,20 +485,17 @@ static void ads7846_disable(struct ads7846 *ts) if (ts->disabled) return; + ts->disabled = 1; + /* are we waiting for IRQ, or polling? */ - if (!ts->pendown) { - if (!ts->irq_disabled) { - ts->irq_disabled = 1; - disable_irq(ts->spi->irq); - } + if (!ts->pending) { + ts->irq_disabled = 1; + disable_irq(ts->spi->irq); } else { - /* polling; force a final SPI completion; - * that will clean things up neatly + /* the timer will run at least once more, and + * leave everything in a clean state, IRQ disabled */ - if (!ts->pending) - mod_timer(&ts->timer, jiffies); - - while (ts->pendown || ts->pending) { + while (ts->pending) { spin_unlock_irq(&ts->lock); msleep(1); spin_lock_irq(&ts->lock); @@ -497,7 +506,6 @@ static void ads7846_disable(struct ads7846 *ts) * leave it that way after every request */ - ts->disabled = 1; } /* Must be called with ts->lock held */ @@ -566,6 +574,11 @@ static int __devinit ads7846_probe(struct spi_device *spi) return -EINVAL; } + if (pdata->get_pendown_state == NULL) { + dev_dbg(&spi->dev, "no get_pendown_state function?\n"); + return -EINVAL; + } + /* We'd set the wordsize to 12 bits ... except that some controllers * will then treat the 8 bit command words as 12 bits (and drop the * four MSBs of the 12 bit result). Result: inputs must be shifted @@ -596,6 +609,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; ts->debounce_max = pdata->debounce_max ? : 1; ts->debounce_tol = pdata->debounce_tol ? : 10; + ts->get_pendown_state = pdata->get_pendown_state; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); @@ -786,8 +800,8 @@ static int __devexit ads7846_remove(struct spi_device *spi) device_remove_file(&spi->dev, &dev_attr_vaux); free_irq(ts->spi->irq, ts); - if (ts->irq_disabled) - enable_irq(ts->spi->irq); + /* suspend left the IRQ disabled */ + enable_irq(ts->spi->irq); kfree(ts); -- cgit From ae82d5ab05068fccef2329f4607670f24c41606f Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 26 Apr 2006 00:12:14 -0400 Subject: Input: ads7846 - report 0 pressure value along with pen up event X touchscreen drivers that don't interpret the designated pen up message assume a pen up event from a pressure value 0. For these we generate a pressure 0 message along with the pen up message. Signed-off-by: Imre Deak Acked-by: Juha Yrjola Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index e7cabf12c8d..1aaa153a277 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -375,11 +375,13 @@ static void ads7846_rx(void *ads) if (Rt) { input_report_abs(input_dev, ABS_X, x); input_report_abs(input_dev, ABS_Y, y); - input_report_abs(input_dev, ABS_PRESSURE, Rt); sync = 1; } - if (sync) + + if (sync) { + input_report_abs(input_dev, ABS_PRESSURE, Rt); input_sync(input_dev); + } #ifdef VERBOSE if (Rt || ts->pendown) -- cgit From d5b415c95f0e6510451f1446cea832c1f77bd7ea Mon Sep 17 00:00:00 2001 From: Imre Deak Date: Wed, 26 Apr 2006 00:13:18 -0400 Subject: Input: ads7846 - improve filtering for thumb press accuracy Providing more accurate coordinates for thumb press requires additional steps in the filtering logic: - Ignore samples found invalid by the debouncing logic, or the ones that have out of bound pressure value. - Add a parameter to repeat debouncing, so that more then two consecutive good readings are required for a valid sample. Signed-off-by: Imre Deak Acked-by: Juha Yrjola Signed-off-by: Dmitry Torokhov --- drivers/input/touchscreen/ads7846.c | 72 +++++++++++++++++++++++++++++-------- 1 file changed, 57 insertions(+), 15 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c index 1aaa153a277..1494175ac6f 100644 --- a/drivers/input/touchscreen/ads7846.c +++ b/drivers/input/touchscreen/ads7846.c @@ -71,6 +71,7 @@ struct ts_event { __be16 x; __be16 y; __be16 z1, z2; + int ignore; }; struct ads7846 { @@ -81,6 +82,7 @@ struct ads7846 { u16 model; u16 vref_delay_usecs; u16 x_plate_ohms; + u16 pressure_max; u8 read_x, read_y, read_z1, read_z2, pwrdown; u16 dummy; /* for the pwrdown read */ @@ -88,12 +90,15 @@ struct ads7846 { struct spi_transfer xfer[10]; struct spi_message msg[5]; + struct spi_message *last_msg; int msg_idx; int read_cnt; + int read_rep; int last_read; u16 debounce_max; u16 debounce_tol; + u16 debounce_rep; spinlock_t lock; struct timer_list timer; /* P: lock */ @@ -354,6 +359,14 @@ static void ads7846_rx(void *ads) } else Rt = 0; + /* Sample found inconsistent by debouncing or pressure is beyond + * the maximum. Don't report it to user space, repeat at least + * once more the measurement */ + if (ts->tc.ignore || Rt > ts->pressure_max) { + mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD); + return; + } + /* NOTE: "pendown" is inferred from pressure; we don't rely on * being able to check nPENIRQ status, or "friendly" trigger modes * (both-edges is much better than just-falling or low-level). @@ -402,25 +415,45 @@ static void ads7846_debounce(void *ads) struct ads7846 *ts = ads; struct spi_message *m; struct spi_transfer *t; - u16 val; + int val; int status; m = &ts->msg[ts->msg_idx]; t = list_entry(m->transfers.prev, struct spi_transfer, transfer_list); val = (*(u16 *)t->rx_buf) >> 3; - - if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol - && ts->read_cnt < ts->debounce_max)) { - /* Repeat it, if this was the first read or the read wasn't - * consistent enough - */ - ts->read_cnt++; - ts->last_read = val; + if (!ts->read_cnt || (abs(ts->last_read - val) > ts->debounce_tol)) { + /* Repeat it, if this was the first read or the read + * wasn't consistent enough. */ + if (ts->read_cnt < ts->debounce_max) { + ts->last_read = val; + ts->read_cnt++; + } else { + /* Maximum number of debouncing reached and still + * not enough number of consistent readings. Abort + * the whole sample, repeat it in the next sampling + * period. + */ + ts->tc.ignore = 1; + ts->read_cnt = 0; + /* Last message will contain ads7846_rx() as the + * completion function. + */ + m = ts->last_msg; + } + /* Start over collecting consistent readings. */ + ts->read_rep = 0; } else { - /* Go for the next read */ - ts->msg_idx++; - ts->read_cnt = 0; - m++; + if (++ts->read_rep > ts->debounce_rep) { + /* Got a good reading for this coordinate, + * go for the next one. */ + ts->tc.ignore = 0; + ts->msg_idx++; + ts->read_cnt = 0; + ts->read_rep = 0; + m++; + } else + /* Read more values that are consistent. */ + ts->read_cnt++; } status = spi_async(ts->spi, m); if (status) @@ -609,8 +642,15 @@ static int __devinit ads7846_probe(struct spi_device *spi) ts->model = pdata->model ? : 7846; ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; - ts->debounce_max = pdata->debounce_max ? : 1; - ts->debounce_tol = pdata->debounce_tol ? : 10; + ts->pressure_max = pdata->pressure_max ? : ~0; + if (pdata->debounce_max) { + ts->debounce_max = pdata->debounce_max; + ts->debounce_tol = pdata->debounce_tol; + ts->debounce_rep = pdata->debounce_rep; + if (ts->debounce_rep > ts->debounce_max + 1) + ts->debounce_rep = ts->debounce_max - 1; + } else + ts->debounce_tol = ~0; ts->get_pendown_state = pdata->get_pendown_state; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id); @@ -728,6 +768,8 @@ static int __devinit ads7846_probe(struct spi_device *spi) m->complete = ads7846_rx; m->context = ts; + ts->last_msg = m; + if (request_irq(spi->irq, ads7846_irq, SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING, spi->dev.bus_id, ts)) { -- cgit From f11a7c0935637c15416679bd347bbc4eac1ca740 Mon Sep 17 00:00:00 2001 From: Richard Purdie Date: Wed, 26 Apr 2006 00:13:42 -0400 Subject: Input: spitzkbd - fix the reversed Address and Calender keys Signed-off-by: Richard Purdie Signed-off-by: Dmitry Torokhov --- drivers/input/keyboard/spitzkbd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/keyboard/spitzkbd.c b/drivers/input/keyboard/spitzkbd.c index bc61cf8cfc6..1d238a9d52d 100644 --- a/drivers/input/keyboard/spitzkbd.c +++ b/drivers/input/keyboard/spitzkbd.c @@ -53,8 +53,8 @@ static unsigned char spitzkbd_keycode[NR_SCANCODES] = { KEY_LEFTCTRL, KEY_1, KEY_3, KEY_5, KEY_6, KEY_7, KEY_9, KEY_0, KEY_BACKSPACE, SPITZ_KEY_EXOK, SPITZ_KEY_EXCANCEL, 0, 0, 0, 0, 0, /* 1-16 */ 0, KEY_2, KEY_4, KEY_R, KEY_Y, KEY_8, KEY_I, KEY_O, KEY_P, SPITZ_KEY_EXJOGDOWN, SPITZ_KEY_EXJOGUP, 0, 0, 0, 0, 0, /* 17-32 */ KEY_TAB, KEY_Q, KEY_E, KEY_T, KEY_G, KEY_U, KEY_J, KEY_K, 0, 0, 0, 0, 0, 0, 0, 0, /* 33-48 */ - SPITZ_KEY_CALENDER, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */ - SPITZ_KEY_ADDRESS, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 65-80 */ + SPITZ_KEY_ADDRESS, KEY_W, KEY_S, KEY_F, KEY_V, KEY_H, KEY_M, KEY_L, 0, KEY_RIGHTSHIFT, 0, 0, 0, 0, 0, 0, /* 49-64 */ + SPITZ_KEY_CALENDER, KEY_A, KEY_D, KEY_C, KEY_B, KEY_N, KEY_DOT, 0, KEY_ENTER, KEY_LEFTSHIFT, 0, 0, 0, 0, 0, 0, /* 65-80 */ SPITZ_KEY_MAIL, KEY_Z, KEY_X, KEY_MINUS, KEY_SPACE, KEY_COMMA, 0, KEY_UP, 0, 0, SPITZ_KEY_FN, 0, 0, 0, 0, 0, /* 81-96 */ KEY_SYSRQ, SPITZ_KEY_JAP1, SPITZ_KEY_JAP2, SPITZ_KEY_CANCEL, SPITZ_KEY_OK, SPITZ_KEY_MENU, KEY_LEFT, KEY_DOWN, KEY_RIGHT, 0, 0, 0, 0, 0, 0, 0 /* 97-112 */ }; -- cgit From ddc5d3414593e4d7ad7fbd33e7f7517fcc234544 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Wed, 26 Apr 2006 00:14:19 -0400 Subject: Input: move input_device_id to mod_devicetable.h Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'drivers/input') diff --git a/drivers/input/input.c b/drivers/input/input.c index a935abeffff..591c70d80cd 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -286,19 +286,19 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st for (; id->flags || id->driver_info; id++) { if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) - if (id->id.bustype != dev->id.bustype) + if (id->bustype != dev->id.bustype) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) - if (id->id.vendor != dev->id.vendor) + if (id->vendor != dev->id.vendor) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) - if (id->id.product != dev->id.product) + if (id->product != dev->id.product) continue; if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) - if (id->id.version != dev->id.version) + if (id->version != dev->id.version) continue; MATCH_BIT(evbit, EV_MAX); -- cgit From 89c9b4805a525bdd4c6e7529d06292f60ac837fc Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 29 Apr 2006 01:12:44 -0400 Subject: Input: psmouse - fix new device detection logic Signed-off-by: Dmitry Torokhov --- drivers/input/mouse/psmouse-base.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'drivers/input') diff --git a/drivers/input/mouse/psmouse-base.c b/drivers/input/mouse/psmouse-base.c index 32d70ed8f41..136321a2cfd 100644 --- a/drivers/input/mouse/psmouse-base.c +++ b/drivers/input/mouse/psmouse-base.c @@ -302,8 +302,10 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, * Check if this is a new device announcement (0xAA 0x00) */ if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) { - if (psmouse->pktcnt == 1) + if (psmouse->pktcnt == 1) { + psmouse->last = jiffies; goto out; + } if (psmouse->packet[1] == PSMOUSE_RET_ID) { __psmouse_set_state(psmouse, PSMOUSE_IGNORE); -- cgit From 08791e5cf62b6952ca32106aebb79b6066005de4 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 29 Apr 2006 01:13:21 -0400 Subject: Input: ressurect EVIOCGREP and EVIOCSREP While writing to an event device allows to set repeat rate for an individual input device there is no way to retrieve current settings so we need to ressurect EVIOCGREP. Also ressurect EVIOCSREP so we have a symmetrical interface. Signed-off-by: Dmitry Torokhov --- drivers/input/evdev.c | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/evdev.c b/drivers/input/evdev.c index a34e3d91d9e..ba325f16d07 100644 --- a/drivers/input/evdev.c +++ b/drivers/input/evdev.c @@ -403,6 +403,27 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, case EVIOCGID: if (copy_to_user(p, &dev->id, sizeof(struct input_id))) return -EFAULT; + return 0; + + case EVIOCGREP: + if (!test_bit(EV_REP, dev->evbit)) + return -ENOSYS; + if (put_user(dev->rep[REP_DELAY], ip)) + return -EFAULT; + if (put_user(dev->rep[REP_PERIOD], ip + 1)) + return -EFAULT; + return 0; + + case EVIOCSREP: + if (!test_bit(EV_REP, dev->evbit)) + return -ENOSYS; + if (get_user(u, ip)) + return -EFAULT; + if (get_user(v, ip + 1)) + return -EFAULT; + + input_event(dev, EV_REP, REP_DELAY, u); + input_event(dev, EV_REP, REP_PERIOD, v); return 0; -- cgit From 8fdc19486f4d3b0fc5f1c7ce69fe5f7b1c653e62 Mon Sep 17 00:00:00 2001 From: Dmitry Torokhov Date: Sat, 29 Apr 2006 01:13:48 -0400 Subject: Input: make EVIOCGSND return meaningful data Signed-off-by: Dmitry Torokhov --- drivers/input/input.c | 3 +++ 1 file changed, 3 insertions(+) (limited to 'drivers/input') diff --git a/drivers/input/input.c b/drivers/input/input.c index 591c70d80cd..3038c268917 100644 --- a/drivers/input/input.c +++ b/drivers/input/input.c @@ -155,6 +155,9 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in if (code > SND_MAX || !test_bit(code, dev->sndbit)) return; + if (!!test_bit(code, dev->snd) != !!value) + change_bit(code, dev->snd); + if (dev->event) dev->event(dev, type, code, value); break; -- cgit