aboutsummaryrefslogtreecommitdiff
path: root/drivers/input
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/input')
-rw-r--r--drivers/input/keyboard/bf54x-keys.c2
-rw-r--r--drivers/input/mouse/bcm5974.c74
-rw-r--r--drivers/input/serio/i8042-x86ia64io.h2
-rw-r--r--drivers/input/touchscreen/ads7846.c68
4 files changed, 113 insertions, 33 deletions
diff --git a/drivers/input/keyboard/bf54x-keys.c b/drivers/input/keyboard/bf54x-keys.c
index 6f227d3dbda..e348cfccc17 100644
--- a/drivers/input/keyboard/bf54x-keys.c
+++ b/drivers/input/keyboard/bf54x-keys.c
@@ -43,7 +43,7 @@
#include <linux/input.h>
#include <asm/portmux.h>
-#include <asm/mach/bf54x_keys.h>
+#include <mach/bf54x_keys.h>
#define DRV_NAME "bf54x-keys"
#define TIME_SCALE 100 /* 100 ns */
diff --git a/drivers/input/mouse/bcm5974.c b/drivers/input/mouse/bcm5974.c
index 2ec921bf3c6..18f4d7f6ce6 100644
--- a/drivers/input/mouse/bcm5974.c
+++ b/drivers/input/mouse/bcm5974.c
@@ -63,7 +63,7 @@
}
/* table of devices that work with this driver */
-static const struct usb_device_id bcm5974_table [] = {
+static const struct usb_device_id bcm5974_table[] = {
/* MacbookAir1.1 */
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_ISO),
@@ -105,7 +105,7 @@ struct tp_header {
/* trackpad finger structure */
struct tp_finger {
- __le16 origin; /* left/right origin? */
+ __le16 origin; /* zero when switching track finger */
__le16 abs_x; /* absolute x coodinate */
__le16 abs_y; /* absolute y coodinate */
__le16 rel_x; /* relative x coodinate */
@@ -159,6 +159,7 @@ struct bcm5974 {
struct bt_data *bt_data; /* button transferred data */
struct urb *tp_urb; /* trackpad usb request block */
struct tp_data *tp_data; /* trackpad transferred data */
+ int fingers; /* number of fingers on trackpad */
};
/* logical dimensions */
@@ -172,6 +173,10 @@ struct bcm5974 {
#define SN_WIDTH 100 /* width signal-to-noise ratio */
#define SN_COORD 250 /* coordinate signal-to-noise ratio */
+/* pressure thresholds */
+#define PRESSURE_LOW (2 * DIM_PRESSURE / SN_PRESSURE)
+#define PRESSURE_HIGH (3 * PRESSURE_LOW)
+
/* device constants */
static const struct bcm5974_config bcm5974_config_table[] = {
{
@@ -248,6 +253,7 @@ static void setup_events_to_report(struct input_dev *input_dev,
0, cfg->y.dim, cfg->y.fuzz, 0);
__set_bit(EV_KEY, input_dev->evbit);
+ __set_bit(BTN_TOUCH, input_dev->keybit);
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
@@ -273,32 +279,66 @@ static int report_tp_state(struct bcm5974 *dev, int size)
const struct tp_finger *f = dev->tp_data->finger;
struct input_dev *input = dev->input;
const int fingers = (size - 26) / 28;
- int p = 0, w, x, y, n = 0;
+ int raw_p, raw_w, raw_x, raw_y;
+ int ptest = 0, origin = 0, nmin = 0, nmax = 0;
+ int abs_p = 0, abs_w = 0, abs_x = 0, abs_y = 0;
if (size < 26 || (size - 26) % 28 != 0)
return -EIO;
+ /* always track the first finger; when detached, start over */
if (fingers) {
- p = raw2int(f->force_major);
- w = raw2int(f->size_major);
- x = raw2int(f->abs_x);
- y = raw2int(f->abs_y);
- n = p > 0 ? fingers : 0;
+ raw_p = raw2int(f->force_major);
+ raw_w = raw2int(f->size_major);
+ raw_x = raw2int(f->abs_x);
+ raw_y = raw2int(f->abs_y);
dprintk(9,
- "bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
- p, w, x, y, n);
+ "bcm5974: raw: p: %+05d w: %+05d x: %+05d y: %+05d\n",
+ raw_p, raw_w, raw_x, raw_y);
+
+ ptest = int2bound(&c->p, raw_p);
+ origin = raw2int(f->origin);
+ }
- input_report_abs(input, ABS_TOOL_WIDTH, int2bound(&c->w, w));
- input_report_abs(input, ABS_X, int2bound(&c->x, x - c->x.devmin));
- input_report_abs(input, ABS_Y, int2bound(&c->y, c->y.devmax - y));
+ /* while tracking finger still valid, count all fingers */
+ if (ptest > PRESSURE_LOW && origin) {
+ abs_p = ptest;
+ abs_w = int2bound(&c->w, raw_w);
+ abs_x = int2bound(&c->x, raw_x - c->x.devmin);
+ abs_y = int2bound(&c->y, c->y.devmax - raw_y);
+ for (; f != dev->tp_data->finger + fingers; f++) {
+ ptest = int2bound(&c->p, raw2int(f->force_major));
+ if (ptest > PRESSURE_LOW)
+ nmax++;
+ if (ptest > PRESSURE_HIGH)
+ nmin++;
+ }
}
- input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p));
+ if (dev->fingers < nmin)
+ dev->fingers = nmin;
+ if (dev->fingers > nmax)
+ dev->fingers = nmax;
+
+ input_report_key(input, BTN_TOUCH, dev->fingers > 0);
+ input_report_key(input, BTN_TOOL_FINGER, dev->fingers == 1);
+ input_report_key(input, BTN_TOOL_DOUBLETAP, dev->fingers == 2);
+ input_report_key(input, BTN_TOOL_TRIPLETAP, dev->fingers > 2);
- input_report_key(input, BTN_TOOL_FINGER, n == 1);
- input_report_key(input, BTN_TOOL_DOUBLETAP, n == 2);
- input_report_key(input, BTN_TOOL_TRIPLETAP, n > 2);
+ input_report_abs(input, ABS_PRESSURE, abs_p);
+ input_report_abs(input, ABS_TOOL_WIDTH, abs_w);
+
+ if (abs_p) {
+ input_report_abs(input, ABS_X, abs_x);
+ input_report_abs(input, ABS_Y, abs_y);
+
+ dprintk(8,
+ "bcm5974: abs: p: %+05d w: %+05d x: %+05d y: %+05d "
+ "nmin: %d nmax: %d n: %d\n",
+ abs_p, abs_w, abs_x, abs_y, nmin, nmax, dev->fingers);
+
+ }
input_sync(input);
diff --git a/drivers/input/serio/i8042-x86ia64io.h b/drivers/input/serio/i8042-x86ia64io.h
index 3282b741e24..5aafe24984c 100644
--- a/drivers/input/serio/i8042-x86ia64io.h
+++ b/drivers/input/serio/i8042-x86ia64io.h
@@ -305,7 +305,7 @@ static struct dmi_system_id __initdata i8042_dmi_nomux_table[] = {
.ident = "Lenovo 3000 n100",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "LENOVO"),
- DMI_MATCH(DMI_PRODUCT_VERSION, "3000 N100"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "076804U"),
},
},
{
diff --git a/drivers/input/touchscreen/ads7846.c b/drivers/input/touchscreen/ads7846.c
index ce6f48c695f..8583c766d56 100644
--- a/drivers/input/touchscreen/ads7846.c
+++ b/drivers/input/touchscreen/ads7846.c
@@ -24,6 +24,7 @@
#include <linux/input.h>
#include <linux/interrupt.h>
#include <linux/slab.h>
+#include <linux/gpio.h>
#include <linux/spi/spi.h>
#include <linux/spi/ads7846.h>
#include <asm/irq.h>
@@ -116,6 +117,7 @@ struct ads7846 {
void *filter_data;
void (*filter_cleanup)(void *data);
int (*get_pendown_state)(void);
+ int gpio_pendown;
};
/* leave chip selected when we're done, for quicker re-select? */
@@ -491,6 +493,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,
* to retrieve touchscreen status.
@@ -550,7 +560,7 @@ static void ads7846_rx(void *ads)
*/
if (ts->penirq_recheck_delay_usecs) {
udelay(ts->penirq_recheck_delay_usecs);
- if (!ts->get_pendown_state())
+ if (!get_pendown_state(ts))
Rt = 0;
}
@@ -677,7 +687,7 @@ static enum hrtimer_restart ads7846_timer(struct hrtimer *handle)
spin_lock_irq(&ts->lock);
- if (unlikely(!ts->get_pendown_state() ||
+ if (unlikely(!get_pendown_state(ts) ||
device_suspended(&ts->spi->dev))) {
if (ts->pendown) {
struct input_dev *input = ts->input;
@@ -716,7 +726,7 @@ static irqreturn_t ads7846_irq(int irq, void *handle)
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags);
- if (likely(ts->get_pendown_state())) {
+ if (likely(get_pendown_state(ts))) {
if (!ts->irq_disabled) {
/* The ARM do_simple_IRQ() dispatcher doesn't act
* like the other dispatchers: it will report IRQs
@@ -806,6 +816,36 @@ static int ads7846_resume(struct spi_device *spi)
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)
{
struct ads7846 *ts;
@@ -833,15 +873,6 @@ static int __devinit ads7846_probe(struct spi_device *spi)
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
* 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.
@@ -893,7 +924,10 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->filter_data = ts;
} else
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)
ts->penirq_recheck_delay_usecs =
@@ -1085,7 +1119,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
spi->dev.driver->name, ts)) {
dev_dbg(&spi->dev, "irq %d busy?\n", spi->irq);
err = -EBUSY;
- goto err_cleanup_filter;
+ goto err_free_gpio;
}
err = ads784x_hwmon_register(spi, ts);
@@ -1116,6 +1150,9 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ads784x_hwmon_unregister(spi, ts);
err_free_irq:
free_irq(spi->irq, ts);
+ err_free_gpio:
+ if (ts->gpio_pendown != -1)
+ gpio_free(ts->gpio_pendown);
err_cleanup_filter:
if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data);
@@ -1140,6 +1177,9 @@ static int __devexit ads7846_remove(struct spi_device *spi)
/* suspend left the IRQ disabled */
enable_irq(ts->spi->irq);
+ if (ts->gpio_pendown != -1)
+ gpio_free(ts->gpio_pendown);
+
if (ts->filter_cleanup)
ts->filter_cleanup(ts->filter_data);