Commit 9f29333d authored by Linus Torvalds's avatar Linus Torvalds

Merge git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

* git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: make EVIOCGSND return meaningful data
  Input: ressurect EVIOCGREP and EVIOCSREP
  Input: psmouse - fix new device detection logic
  Input: move input_device_id to mod_devicetable.h
  Input: allow using several chords for braille
  Input: allow passing NULL to input_free_device()
  Input: spitzkbd - fix the reversed Address and Calender keys
  Input: ads7846 - improve filtering for thumb press accuracy
  Input: ads7846 - report 0 pressure value along with pen up event
  Input: ads7846 - handle IRQs that were latched during disabled IRQs
  Input: ads7846 - miscellaneous fixes
  Input: ads7846 - use msleep() instead of udelay() in suspend
  Input: ads7846 - debouncing and rudimentary sample filtering
  Input: ads7846 - power down ADC a bit later
  Input: ads7846 - add pen_down sysfs attribute
  Input: wistron - add support for Fujitsu N3510
  Input: wistron - add signature for Amilo M7400
parents 494b9aea 8fdc1948
...@@ -860,9 +860,32 @@ static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struc ...@@ -860,9 +860,32 @@ static void k_slock(struct vc_data *vc, unsigned char value, char up_flag, struc
} }
/* by default, 300ms interval for combination release */ /* by default, 300ms interval for combination release */
static long brl_timeout = 300; static unsigned brl_timeout = 300;
MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for combination on first release, < 0 for dead characters)"); MODULE_PARM_DESC(brl_timeout, "Braille keys release delay in ms (0 for commit on first key release)");
module_param(brl_timeout, long, 0644); module_param(brl_timeout, uint, 0644);
static unsigned brl_nbchords = 1;
MODULE_PARM_DESC(brl_nbchords, "Number of chords that produce a braille pattern (0 for dead chords)");
module_param(brl_nbchords, uint, 0644);
static void k_brlcommit(struct vc_data *vc, unsigned int pattern, char up_flag, struct pt_regs *regs)
{
static unsigned long chords;
static unsigned committed;
if (!brl_nbchords)
k_deadunicode(vc, BRL_UC_ROW | pattern, up_flag, regs);
else {
committed |= pattern;
chords++;
if (chords == brl_nbchords) {
k_unicode(vc, BRL_UC_ROW | committed, up_flag, regs);
chords = 0;
committed = 0;
}
}
}
static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs) static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct pt_regs *regs)
{ {
static unsigned pressed,committing; static unsigned pressed,committing;
...@@ -882,11 +905,6 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct ...@@ -882,11 +905,6 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct
if (value > 8) if (value > 8)
return; return;
if (brl_timeout < 0) {
k_deadunicode(vc, BRL_UC_ROW | (1 << (value - 1)), up_flag, regs);
return;
}
if (up_flag) { if (up_flag) {
if (brl_timeout) { if (brl_timeout) {
if (!committing || if (!committing ||
...@@ -897,13 +915,13 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct ...@@ -897,13 +915,13 @@ static void k_brl(struct vc_data *vc, unsigned char value, char up_flag, struct
pressed &= ~(1 << (value - 1)); pressed &= ~(1 << (value - 1));
if (!pressed) { if (!pressed) {
if (committing) { if (committing) {
k_unicode(vc, BRL_UC_ROW | committing, 0, regs); k_brlcommit(vc, committing, 0, regs);
committing = 0; committing = 0;
} }
} }
} else { } else {
if (committing) { if (committing) {
k_unicode(vc, BRL_UC_ROW | committing, 0, regs); k_brlcommit(vc, committing, 0, regs);
committing = 0; committing = 0;
} }
pressed &= ~(1 << (value - 1)); pressed &= ~(1 << (value - 1));
......
...@@ -403,6 +403,27 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd, ...@@ -403,6 +403,27 @@ static long evdev_ioctl_handler(struct file *file, unsigned int cmd,
case EVIOCGID: case EVIOCGID:
if (copy_to_user(p, &dev->id, sizeof(struct input_id))) if (copy_to_user(p, &dev->id, sizeof(struct input_id)))
return -EFAULT; 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; return 0;
......
...@@ -155,6 +155,9 @@ void input_event(struct input_dev *dev, unsigned int type, unsigned int code, in ...@@ -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)) if (code > SND_MAX || !test_bit(code, dev->sndbit))
return; return;
if (!!test_bit(code, dev->snd) != !!value)
change_bit(code, dev->snd);
if (dev->event) dev->event(dev, type, code, value); if (dev->event) dev->event(dev, type, code, value);
break; break;
...@@ -286,19 +289,19 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st ...@@ -286,19 +289,19 @@ static struct input_device_id *input_match_device(struct input_device_id *id, st
for (; id->flags || id->driver_info; id++) { for (; id->flags || id->driver_info; id++) {
if (id->flags & INPUT_DEVICE_ID_MATCH_BUS) if (id->flags & INPUT_DEVICE_ID_MATCH_BUS)
if (id->id.bustype != dev->id.bustype) if (id->bustype != dev->id.bustype)
continue; continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR) if (id->flags & INPUT_DEVICE_ID_MATCH_VENDOR)
if (id->id.vendor != dev->id.vendor) if (id->vendor != dev->id.vendor)
continue; continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT) if (id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT)
if (id->id.product != dev->id.product) if (id->product != dev->id.product)
continue; continue;
if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION) if (id->flags & INPUT_DEVICE_ID_MATCH_VERSION)
if (id->id.version != dev->id.version) if (id->version != dev->id.version)
continue; continue;
MATCH_BIT(evbit, EV_MAX); MATCH_BIT(evbit, EV_MAX);
......
...@@ -53,8 +53,8 @@ static unsigned char spitzkbd_keycode[NR_SCANCODES] = { ...@@ -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 */ 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 */ 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 */ 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_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_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 */ 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 */ 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 */
}; };
......
...@@ -273,6 +273,18 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] = { ...@@ -273,6 +273,18 @@ static struct key_entry keymap_fs_amilo_pro_v2000[] = {
{ KE_END, 0 } { 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[] = { static struct key_entry keymap_wistron_ms2141[] = {
{ KE_KEY, 0x11, KEY_PROG1 }, { KE_KEY, 0x11, KEY_PROG1 },
{ KE_KEY, 0x12, KEY_PROG2 }, { KE_KEY, 0x12, KEY_PROG2 },
...@@ -321,6 +333,24 @@ static struct dmi_system_id dmi_ids[] = { ...@@ -321,6 +333,24 @@ static struct dmi_system_id dmi_ids[] = {
}, },
.driver_data = keymap_fs_amilo_pro_v2000 .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 = "Fujitsu N3510",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "FUJITSU"),
DMI_MATCH(DMI_PRODUCT_NAME, "N3510"),
},
.driver_data = keymap_fujitsu_n3510
},
{ {
.callback = dmi_matched, .callback = dmi_matched,
.ident = "Acer Aspire 1500", .ident = "Acer Aspire 1500",
......
...@@ -302,8 +302,10 @@ static irqreturn_t psmouse_interrupt(struct serio *serio, ...@@ -302,8 +302,10 @@ static irqreturn_t psmouse_interrupt(struct serio *serio,
* Check if this is a new device announcement (0xAA 0x00) * Check if this is a new device announcement (0xAA 0x00)
*/ */
if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) { if (unlikely(psmouse->packet[0] == PSMOUSE_RET_BAT && psmouse->pktcnt <= 2)) {
if (psmouse->pktcnt == 1) if (psmouse->pktcnt == 1) {
psmouse->last = jiffies;
goto out; goto out;
}
if (psmouse->packet[1] == PSMOUSE_RET_ID) { if (psmouse->packet[1] == PSMOUSE_RET_ID) {
__psmouse_set_state(psmouse, PSMOUSE_IGNORE); __psmouse_set_state(psmouse, PSMOUSE_IGNORE);
......
...@@ -2,6 +2,8 @@ ...@@ -2,6 +2,8 @@
* ADS7846 based touchscreen and sensor driver * ADS7846 based touchscreen and sensor driver
* *
* Copyright (c) 2005 David Brownell * Copyright (c) 2005 David Brownell
* Copyright (c) 2006 Nokia Corporation
* Various changes: Imre Deak <imre.deak@nokia.com>
* *
* Using code from: * Using code from:
* - corgi_ts.c * - corgi_ts.c
...@@ -34,17 +36,25 @@ ...@@ -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. * Support for ads7843 and ads7845 has only been stubbed in.
* *
* Not yet done: investigate the values reported. Are x/y/pressure * Not yet done: How accurate are the temperature and voltage
* event values sane enough for X11? How accurate are the temperature * readings? (System-specific calibration should support
* and voltage readings? (System-specific calibration should support
* accuracy of 0.3 degrees C; otherwise it's 2.0 degrees.) * 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... * app note sbaa036 talks in more detail about accurate sampling...
* that ought to help in situations like LCDs inducing noise (which * that ought to help in situations like LCDs inducing noise (which
* can also be helped by using synch signals) and more generally. * 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) #define TS_POLL_PERIOD msecs_to_jiffies(10)
...@@ -61,6 +71,7 @@ struct ts_event { ...@@ -61,6 +71,7 @@ struct ts_event {
__be16 x; __be16 x;
__be16 y; __be16 y;
__be16 z1, z2; __be16 z1, z2;
int ignore;
}; };
struct ads7846 { struct ads7846 {
...@@ -71,12 +82,23 @@ struct ads7846 { ...@@ -71,12 +82,23 @@ struct ads7846 {
u16 model; u16 model;
u16 vref_delay_usecs; u16 vref_delay_usecs;
u16 x_plate_ohms; u16 x_plate_ohms;
u16 pressure_max;
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 ts_event tc;
struct spi_transfer xfer[8]; struct spi_transfer xfer[10];
struct spi_message msg; 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; spinlock_t lock;
struct timer_list timer; /* P: lock */ struct timer_list timer; /* P: lock */
...@@ -84,6 +106,9 @@ struct ads7846 { ...@@ -84,6 +106,9 @@ struct ads7846 {
unsigned pending:1; /* P: lock */ unsigned pending:1; /* P: lock */
// FIXME remove "irq_disabled" // FIXME remove "irq_disabled"
unsigned irq_disabled:1; /* P: lock */ 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? */ /* leave chip selected when we're done, for quicker re-select? */
...@@ -125,7 +150,9 @@ struct ads7846 { ...@@ -125,7 +150,9 @@ struct ads7846 {
#define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON) #define READ_Y (READ_12BIT_DFR(y) | ADS_PD10_ADC_ON)
#define READ_Z1 (READ_12BIT_DFR(z1) | 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_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; /* single-ended samples need to first power up reference voltage;
* we leave both ADC and VREF powered * we leave both ADC and VREF powered
...@@ -152,6 +179,15 @@ struct ser_req { ...@@ -152,6 +179,15 @@ struct ser_req {
struct spi_transfer xfer[6]; struct spi_transfer xfer[6];
}; };
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) static int ads7846_read12_ser(struct device *dev, unsigned command)
{ {
struct spi_device *spi = to_spi_device(dev); struct spi_device *spi = to_spi_device(dev);
...@@ -164,7 +200,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) ...@@ -164,7 +200,7 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
if (!req) if (!req)
return -ENOMEM; return -ENOMEM;
INIT_LIST_HEAD(&req->msg.transfers); spi_message_init(&req->msg);
/* activate reference, so it has time to settle; */ /* activate reference, so it has time to settle; */
req->ref_on = REF_ON; req->ref_on = REF_ON;
...@@ -204,8 +240,10 @@ static int ads7846_read12_ser(struct device *dev, unsigned command) ...@@ -204,8 +240,10 @@ static int ads7846_read12_ser(struct device *dev, unsigned command)
for (i = 0; i < 6; i++) for (i = 0; i < 6; i++)
spi_message_add_tail(&req->xfer[i], &req->msg); spi_message_add_tail(&req->xfer[i], &req->msg);
ts->irq_disabled = 1;
disable_irq(spi->irq); disable_irq(spi->irq);
status = spi_sync(spi, &req->msg); status = spi_sync(spi, &req->msg);
ts->irq_disabled = 0;
enable_irq(spi->irq); enable_irq(spi->irq);
if (req->msg.status) if (req->msg.status)
...@@ -233,6 +271,52 @@ SHOW(temp1) ...@@ -233,6 +271,52 @@ SHOW(temp1)
SHOW(vaux) SHOW(vaux)
SHOW(vbatt) 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);
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);
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
/* /*
...@@ -264,7 +348,7 @@ static void ads7846_rx(void *ads) ...@@ -264,7 +348,7 @@ static void ads7846_rx(void *ads)
if (x == MAX_12BIT) if (x == MAX_12BIT)
x = 0; 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 */ /* compute touch pressure resistance using equation #2 */
Rt = z2; Rt = z2;
Rt -= z1; Rt -= z1;
...@@ -275,6 +359,14 @@ static void ads7846_rx(void *ads) ...@@ -275,6 +359,14 @@ static void ads7846_rx(void *ads)
} else } else
Rt = 0; 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 /* NOTE: "pendown" is inferred from pressure; we don't rely on
* being able to check nPENIRQ status, or "friendly" trigger modes * being able to check nPENIRQ status, or "friendly" trigger modes
* (both-edges is much better than just-falling or low-level). * (both-edges is much better than just-falling or low-level).
...@@ -296,11 +388,13 @@ static void ads7846_rx(void *ads) ...@@ -296,11 +388,13 @@ static void ads7846_rx(void *ads)
if (Rt) { if (Rt) {
input_report_abs(input_dev, ABS_X, x); input_report_abs(input_dev, ABS_X, x);
input_report_abs(input_dev, ABS_Y, y); input_report_abs(input_dev, ABS_Y, y);
input_report_abs(input_dev, ABS_PRESSURE, Rt);
sync = 1; sync = 1;
} }
if (sync)
if (sync) {
input_report_abs(input_dev, ABS_PRESSURE, Rt);
input_sync(input_dev); input_sync(input_dev);
}
#ifdef VERBOSE #ifdef VERBOSE
if (Rt || ts->pendown) if (Rt || ts->pendown)
...@@ -308,80 +402,138 @@ static void ads7846_rx(void *ads) ...@@ -308,80 +402,138 @@ static void ads7846_rx(void *ads)
x, y, Rt, Rt ? "" : " UP"); x, y, Rt, Rt ? "" : " UP");
#endif #endif
/* don't retrigger while we're suspended */
spin_lock_irqsave(&ts->lock, flags); spin_lock_irqsave(&ts->lock, flags);
ts->pendown = (Rt != 0); ts->pendown = (Rt != 0);
ts->pending = 0; mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
if (ts->spi->dev.power.power_state.event == PM_EVENT_ON) { spin_unlock_irqrestore(&ts->lock, flags);
if (ts->pendown) }
mod_timer(&ts->timer, jiffies + TS_POLL_PERIOD);
else if (ts->irq_disabled) { static void ads7846_debounce(void *ads)
ts->irq_disabled = 0; {
enable_irq(ts->spi->irq); struct ads7846 *ts = ads;
struct spi_message *m;
struct spi_transfer *t;
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)) {
/* 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 {
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);
spin_unlock_irqrestore(&ts->lock, flags); if (status)
dev_err(&ts->spi->dev, "spi_async --> %d\n",
status);
} }
static void ads7846_timer(unsigned long handle) static void ads7846_timer(unsigned long handle)
{ {
struct ads7846 *ts = (void *)handle; struct ads7846 *ts = (void *)handle;
int status = 0; int status = 0;
unsigned long flags;
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)
{
struct ads7846 *ts = handle;
unsigned long flags;
spin_lock_irqsave(&ts->lock, flags); spin_lock_irqsave(&ts->lock, flags);
if (!ts->pending) { if (likely(ts->get_pendown_state())) {
ts->pending = 1;
if (!ts->irq_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
* 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; ts->irq_disabled = 1;
disable_irq(ts->spi->irq); disable_irq(ts->spi->irq);
ts->pending = 1;
mod_timer(&ts->timer, jiffies);
} }
status = spi_async(ts->spi, &ts->msg);
if (status)
dev_err(&ts->spi->dev, "spi_async --> %d\n",
status);
} }
spin_unlock_irqrestore(&ts->lock, flags); 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 IRQ_HANDLED;
} }
/*--------------------------------------------------------------------------*/ /*--------------------------------------------------------------------------*/
static int /* Must be called with ts->lock held */
ads7846_suspend(struct spi_device *spi, pm_message_t message) static void ads7846_disable(struct ads7846 *ts)
{ {
struct ads7846 *ts = dev_get_drvdata(&spi->dev); if (ts->disabled)
unsigned long flags; return;
spin_lock_irqsave(&ts->lock, flags); ts->disabled = 1;
spi->dev.power.power_state = message;
/* are we waiting for IRQ, or polling? */ /* are we waiting for IRQ, or polling? */
if (!ts->pendown) { if (!ts->pending) {
if (!ts->irq_disabled) { ts->irq_disabled = 1;
ts->irq_disabled = 1; disable_irq(ts->spi->irq);
disable_irq(ts->spi->irq);
}
} else { } else {
/* polling; force a final SPI completion; /* the timer will run at least once more, and
* that will clean things up neatly * leave everything in a clean state, IRQ disabled
*/ */
if (!ts->pending) while (ts->pending) {
mod_timer(&ts->timer, jiffies); spin_unlock_irq(&ts->lock);
msleep(1);
while (ts->pendown || ts->pending) { spin_lock_irq(&ts->lock);
spin_unlock_irqrestore(&ts->lock, flags);
udelay(10);
spin_lock_irqsave(&ts->lock, flags);
} }
} }
...@@ -389,17 +541,45 @@ ads7846_suspend(struct spi_device *spi, pm_message_t message) ...@@ -389,17 +541,45 @@ ads7846_suspend(struct spi_device *spi, pm_message_t message)
* leave it that way after every request * leave it that way after every request
*/ */
spin_unlock_irqrestore(&ts->lock, flags); }
/* 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; return 0;
} }
static int ads7846_resume(struct spi_device *spi) static int ads7846_resume(struct spi_device *spi)
{ {
struct ads7846 *ts = dev_get_drvdata(&spi->dev); struct ads7846 *ts = dev_get_drvdata(&spi->dev);
ts->irq_disabled = 0; spin_lock_irq(&ts->lock);
enable_irq(ts->spi->irq);
spi->dev.power.power_state = PMSG_ON; spi->dev.power.power_state = PMSG_ON;
ads7846_enable(ts);
spin_unlock_irq(&ts->lock);
return 0; return 0;
} }
...@@ -408,6 +588,7 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -408,6 +588,7 @@ static int __devinit ads7846_probe(struct spi_device *spi)
struct ads7846 *ts; struct ads7846 *ts;
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_transfer *x; struct spi_transfer *x;
int err; int err;
...@@ -428,6 +609,11 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -428,6 +609,11 @@ static int __devinit ads7846_probe(struct spi_device *spi)
return -EINVAL; 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 /* 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 * 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 * four MSBs of the 12 bit result). Result: inputs must be shifted
...@@ -451,9 +637,21 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -451,9 +637,21 @@ static int __devinit ads7846_probe(struct spi_device *spi)
ts->timer.data = (unsigned long) ts; ts->timer.data = (unsigned long) ts;
ts->timer.function = ads7846_timer; ts->timer.function = ads7846_timer;
spin_lock_init(&ts->lock);
ts->model = pdata->model ? : 7846; ts->model = pdata->model ? : 7846;
ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100; ts->vref_delay_usecs = pdata->vref_delay_usecs ? : 100;
ts->x_plate_ohms = pdata->x_plate_ohms ? : 400; ts->x_plate_ohms = pdata->x_plate_ohms ? : 400;
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); snprintf(ts->phys, sizeof(ts->phys), "%s/input0", spi->dev.bus_id);
...@@ -477,60 +675,100 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -477,60 +675,100 @@ static int __devinit ads7846_probe(struct spi_device *spi)
/* set up the transfers to read touchscreen state; this assumes we /* set up the transfers to read touchscreen state; this assumes we
* use formula #2 for pressure, not #3. * use formula #2 for pressure, not #3.
*/ */
INIT_LIST_HEAD(&ts->msg.transfers); m = &ts->msg[0];
x = ts->xfer; x = ts->xfer;
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; ts->read_y = READ_Y;
x->tx_buf = &ts->read_y; x->tx_buf = &ts->read_y;
x->len = 1; x->len = 1;
spi_message_add_tail(x, &ts->msg); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.y; x->rx_buf = &ts->tc.y;
x->len = 2; 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 */ /* turn y+ off, x- on; we'll use formula #2 */
if (ts->model == 7846) { if (ts->model == 7846) {
m++;
spi_message_init(m);
x++; x++;
ts->read_z1 = READ_Z1; ts->read_z1 = READ_Z1;
x->tx_buf = &ts->read_z1; x->tx_buf = &ts->read_z1;
x->len = 1; x->len = 1;
spi_message_add_tail(x, &ts->msg); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.z1; x->rx_buf = &ts->tc.z1;
x->len = 2; 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++; x++;
ts->read_z2 = READ_Z2; ts->read_z2 = READ_Z2;
x->tx_buf = &ts->read_z2; x->tx_buf = &ts->read_z2;
x->len = 1; x->len = 1;
spi_message_add_tail(x, &ts->msg); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.z2; x->rx_buf = &ts->tc.z2;
x->len = 2; x->len = 2;
spi_message_add_tail(x, &ts->msg); spi_message_add_tail(x, m);
m->complete = ads7846_debounce;
m->context = ts;
} }
/* turn y- off, x+ on, then leave in lowpower */ /* power down */
m++;
spi_message_init(m);
x++; x++;
ts->read_x = READ_X; ts->pwrdown = PWRDOWN;
x->tx_buf = &ts->read_x; x->tx_buf = &ts->pwrdown;
x->len = 1; x->len = 1;
spi_message_add_tail(x, &ts->msg); spi_message_add_tail(x, m);
x++; x++;
x->rx_buf = &ts->tc.x; x->rx_buf = &ts->dummy;
x->len = 2; x->len = 2;
CS_CHANGE(*x); CS_CHANGE(*x);
spi_message_add_tail(x, &ts->msg); spi_message_add_tail(x, m);
ts->msg.complete = ads7846_rx; m->complete = ads7846_rx;
ts->msg.context = ts; m->context = ts;
ts->last_msg = m;
if (request_irq(spi->irq, ads7846_irq, if (request_irq(spi->irq, ads7846_irq,
SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING, SA_SAMPLE_RANDOM | SA_TRIGGER_FALLING,
...@@ -559,13 +797,27 @@ static int __devinit ads7846_probe(struct spi_device *spi) ...@@ -559,13 +797,27 @@ static int __devinit ads7846_probe(struct spi_device *spi)
device_create_file(&spi->dev, &dev_attr_vbatt); device_create_file(&spi->dev, &dev_attr_vbatt);
device_create_file(&spi->dev, &dev_attr_vaux); device_create_file(&spi->dev, &dev_attr_vaux);
device_create_file(&spi->dev, &dev_attr_pen_down);
device_create_file(&spi->dev, &dev_attr_disable);
err = input_register_device(input_dev); err = input_register_device(input_dev);
if (err) if (err)
goto err_free_irq; goto err_remove_attr;
return 0; 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); free_irq(spi->irq, ts);
err_free_mem: err_free_mem:
input_free_device(input_dev); input_free_device(input_dev);
...@@ -577,20 +829,24 @@ static int __devexit ads7846_remove(struct spi_device *spi) ...@@ -577,20 +829,24 @@ static int __devexit ads7846_remove(struct spi_device *spi)
{ {
struct ads7846 *ts = dev_get_drvdata(&spi->dev); struct ads7846 *ts = dev_get_drvdata(&spi->dev);
input_unregister_device(ts->input);
ads7846_suspend(spi, PMSG_SUSPEND); 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) { 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_temp1);
device_remove_file(&spi->dev, &dev_attr_temp0);
} }
if (ts->model != 7845) if (ts->model != 7845)
device_remove_file(&spi->dev, &dev_attr_vbatt); device_remove_file(&spi->dev, &dev_attr_vbatt);
device_remove_file(&spi->dev, &dev_attr_vaux); device_remove_file(&spi->dev, &dev_attr_vaux);
input_unregister_device(ts->input); free_irq(ts->spi->irq, ts);
/* suspend left the IRQ disabled */
enable_irq(ts->spi->irq);
kfree(ts); kfree(ts);
dev_dbg(&spi->dev, "unregistered touchscreen\n"); dev_dbg(&spi->dev, "unregistered touchscreen\n");
......
...@@ -12,8 +12,6 @@ ...@@ -12,8 +12,6 @@
#ifdef __KERNEL__ #ifdef __KERNEL__
#include <linux/time.h> #include <linux/time.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/device.h>
#include <linux/mod_devicetable.h>
#else #else
#include <sys/time.h> #include <sys/time.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
...@@ -58,6 +56,8 @@ struct input_absinfo { ...@@ -58,6 +56,8 @@ struct input_absinfo {
#define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */ #define EVIOCGVERSION _IOR('E', 0x01, int) /* get driver version */
#define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */ #define EVIOCGID _IOR('E', 0x02, struct input_id) /* get device ID */
#define EVIOCGREP _IOR('E', 0x03, int[2]) /* get repeat settings */
#define EVIOCSREP _IOW('E', 0x03, int[2]) /* set repeat settings */
#define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */ #define EVIOCGKEYCODE _IOR('E', 0x04, int[2]) /* get keycode */
#define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */ #define EVIOCSKEYCODE _IOW('E', 0x04, int[2]) /* set keycode */
...@@ -577,15 +577,15 @@ struct input_absinfo { ...@@ -577,15 +577,15 @@ struct input_absinfo {
* Switch events * Switch events
*/ */
#define SW_0 0x00 #define SW_0 0x00
#define SW_1 0x01 #define SW_1 0x01
#define SW_2 0x02 #define SW_2 0x02
#define SW_3 0x03 #define SW_3 0x03
#define SW_4 0x04 #define SW_4 0x04
#define SW_5 0x05 #define SW_5 0x05
#define SW_6 0x06 #define SW_6 0x06
#define SW_7 0x07 #define SW_7 0x07
#define SW_MAX 0x0f #define SW_MAX 0x0f
/* /*
* Misc events * Misc events
...@@ -805,52 +805,16 @@ struct ff_effect { ...@@ -805,52 +805,16 @@ struct ff_effect {
#define FF_MAX 0x7f #define FF_MAX 0x7f
struct input_device_id {
kernel_ulong_t flags;
struct input_id id;
kernel_ulong_t evbit[EV_MAX/BITS_PER_LONG+1];
kernel_ulong_t keybit[KEY_MAX/BITS_PER_LONG+1];
kernel_ulong_t relbit[REL_MAX/BITS_PER_LONG+1];
kernel_ulong_t absbit[ABS_MAX/BITS_PER_LONG+1];
kernel_ulong_t mscbit[MSC_MAX/BITS_PER_LONG+1];
kernel_ulong_t ledbit[LED_MAX/BITS_PER_LONG+1];
kernel_ulong_t sndbit[SND_MAX/BITS_PER_LONG+1];
kernel_ulong_t ffbit[FF_MAX/BITS_PER_LONG+1];
kernel_ulong_t swbit[SW_MAX/BITS_PER_LONG+1];
kernel_ulong_t driver_info;
};
/*
* Structure for hotplug & device<->driver matching.
*/
#define INPUT_DEVICE_ID_MATCH_BUS 1
#define INPUT_DEVICE_ID_MATCH_VENDOR 2
#define INPUT_DEVICE_ID_MATCH_PRODUCT 4
#define INPUT_DEVICE_ID_MATCH_VERSION 8
#define INPUT_DEVICE_ID_MATCH_EVBIT 0x010
#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x020
#define INPUT_DEVICE_ID_MATCH_RELBIT 0x040
#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x080
#define INPUT_DEVICE_ID_MATCH_MSCIT 0x100
#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x200
#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x400
#define INPUT_DEVICE_ID_MATCH_FFBIT 0x800
#define INPUT_DEVICE_ID_MATCH_SWBIT 0x1000
#ifdef __KERNEL__ #ifdef __KERNEL__
/* /*
* In-kernel definitions. * In-kernel definitions.
*/ */
#include <linux/device.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/timer.h> #include <linux/timer.h>
#include <linux/mod_devicetable.h>
#define NBITS(x) (((x)/BITS_PER_LONG)+1) #define NBITS(x) (((x)/BITS_PER_LONG)+1)
#define BIT(x) (1UL<<((x)%BITS_PER_LONG)) #define BIT(x) (1UL<<((x)%BITS_PER_LONG))
...@@ -951,9 +915,49 @@ struct input_dev { ...@@ -951,9 +915,49 @@ struct input_dev {
}; };
#define to_input_dev(d) container_of(d, struct input_dev, cdev) #define to_input_dev(d) container_of(d, struct input_dev, cdev)
#define INPUT_DEVICE_ID_MATCH_DEVICE\ /*
* Verify that we are in sync with input_device_id mod_devicetable.h #defines
*/
#if EV_MAX != INPUT_DEVICE_ID_EV_MAX
#error "EV_MAX and INPUT_DEVICE_ID_EV_MAX do not match"
#endif
#if KEY_MAX != INPUT_DEVICE_ID_KEY_MAX
#error "KEY_MAX and INPUT_DEVICE_ID_KEY_MAX do not match"
#endif
#if REL_MAX != INPUT_DEVICE_ID_REL_MAX
#error "REL_MAX and INPUT_DEVICE_ID_REL_MAX do not match"
#endif
#if ABS_MAX != INPUT_DEVICE_ID_ABS_MAX
#error "ABS_MAX and INPUT_DEVICE_ID_ABS_MAX do not match"
#endif
#if MSC_MAX != INPUT_DEVICE_ID_MSC_MAX
#error "MSC_MAX and INPUT_DEVICE_ID_MSC_MAX do not match"
#endif
#if LED_MAX != INPUT_DEVICE_ID_LED_MAX
#error "LED_MAX and INPUT_DEVICE_ID_LED_MAX do not match"
#endif
#if SND_MAX != INPUT_DEVICE_ID_SND_MAX
#error "SND_MAX and INPUT_DEVICE_ID_SND_MAX do not match"
#endif
#if FF_MAX != INPUT_DEVICE_ID_FF_MAX
#error "FF_MAX and INPUT_DEVICE_ID_FF_MAX do not match"
#endif
#if SW_MAX != INPUT_DEVICE_ID_SW_MAX
#error "SW_MAX and INPUT_DEVICE_ID_SW_MAX do not match"
#endif
#define INPUT_DEVICE_ID_MATCH_DEVICE \
(INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT) (INPUT_DEVICE_ID_MATCH_BUS | INPUT_DEVICE_ID_MATCH_VENDOR | INPUT_DEVICE_ID_MATCH_PRODUCT)
#define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION\ #define INPUT_DEVICE_ID_MATCH_DEVICE_AND_VERSION \
(INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION) (INPUT_DEVICE_ID_MATCH_DEVICE | INPUT_DEVICE_ID_MATCH_VERSION)
struct input_handle; struct input_handle;
...@@ -1016,7 +1020,8 @@ static inline void input_put_device(struct input_dev *dev) ...@@ -1016,7 +1020,8 @@ static inline void input_put_device(struct input_dev *dev)
static inline void input_free_device(struct input_dev *dev) static inline void input_free_device(struct input_dev *dev)
{ {
input_put_device(dev); if (dev)
input_put_device(dev);
} }
int input_register_device(struct input_dev *); int input_register_device(struct input_dev *);
......
...@@ -249,4 +249,52 @@ struct i2c_device_id { ...@@ -249,4 +249,52 @@ struct i2c_device_id {
__u16 id; __u16 id;
}; };
/* Input */
#define INPUT_DEVICE_ID_EV_MAX 0x1f
#define INPUT_DEVICE_ID_KEY_MAX 0x1ff
#define INPUT_DEVICE_ID_REL_MAX 0x0f
#define INPUT_DEVICE_ID_ABS_MAX 0x3f
#define INPUT_DEVICE_ID_MSC_MAX 0x07
#define INPUT_DEVICE_ID_LED_MAX 0x0f
#define INPUT_DEVICE_ID_SND_MAX 0x07
#define INPUT_DEVICE_ID_FF_MAX 0x7f
#define INPUT_DEVICE_ID_SW_MAX 0x0f
#define INPUT_DEVICE_ID_MATCH_BUS 1
#define INPUT_DEVICE_ID_MATCH_VENDOR 2
#define INPUT_DEVICE_ID_MATCH_PRODUCT 4
#define INPUT_DEVICE_ID_MATCH_VERSION 8
#define INPUT_DEVICE_ID_MATCH_EVBIT 0x0010
#define INPUT_DEVICE_ID_MATCH_KEYBIT 0x0020
#define INPUT_DEVICE_ID_MATCH_RELBIT 0x0040
#define INPUT_DEVICE_ID_MATCH_ABSBIT 0x0080
#define INPUT_DEVICE_ID_MATCH_MSCIT 0x0100
#define INPUT_DEVICE_ID_MATCH_LEDBIT 0x0200
#define INPUT_DEVICE_ID_MATCH_SNDBIT 0x0400
#define INPUT_DEVICE_ID_MATCH_FFBIT 0x0800
#define INPUT_DEVICE_ID_MATCH_SWBIT 0x1000
struct input_device_id {
kernel_ulong_t flags;
__u16 bustype;
__u16 vendor;
__u16 product;
__u16 version;
kernel_ulong_t evbit[INPUT_DEVICE_ID_EV_MAX / BITS_PER_LONG + 1];
kernel_ulong_t keybit[INPUT_DEVICE_ID_KEY_MAX / BITS_PER_LONG + 1];
kernel_ulong_t relbit[INPUT_DEVICE_ID_REL_MAX / BITS_PER_LONG + 1];
kernel_ulong_t absbit[INPUT_DEVICE_ID_ABS_MAX / BITS_PER_LONG + 1];
kernel_ulong_t mscbit[INPUT_DEVICE_ID_MSC_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ledbit[INPUT_DEVICE_ID_LED_MAX / BITS_PER_LONG + 1];
kernel_ulong_t sndbit[INPUT_DEVICE_ID_SND_MAX / BITS_PER_LONG + 1];
kernel_ulong_t ffbit[INPUT_DEVICE_ID_FF_MAX / BITS_PER_LONG + 1];
kernel_ulong_t swbit[INPUT_DEVICE_ID_SW_MAX / BITS_PER_LONG + 1];
kernel_ulong_t driver_info;
};
#endif /* LINUX_MOD_DEVICETABLE_H */ #endif /* LINUX_MOD_DEVICETABLE_H */
...@@ -14,5 +14,12 @@ struct ads7846_platform_data { ...@@ -14,5 +14,12 @@ struct ads7846_platform_data {
u16 x_min, x_max; u16 x_min, x_max;
u16 y_min, y_max; u16 y_min, y_max;
u16 pressure_min, pressure_max; u16 pressure_min, pressure_max;
u16 debounce_max; /* max number of additional readings
* per sample */
u16 debounce_tol; /* tolerance used for filtering */
u16 debounce_rep; /* additional consecutive good readings
* required after the first two */
int (*get_pendown_state)(void);
}; };
...@@ -374,10 +374,10 @@ static void do_input(char *alias, ...@@ -374,10 +374,10 @@ static void do_input(char *alias,
kernel_ulong_t *arr, unsigned int min, unsigned int max) kernel_ulong_t *arr, unsigned int min, unsigned int max)
{ {
unsigned int i; unsigned int i;
for (i = min; i < max; i++) {
if (arr[i/BITS_PER_LONG] & (1 << (i%BITS_PER_LONG))) for (i = min; i < max; i++)
sprintf(alias+strlen(alias), "%X,*", i); if (arr[i / BITS_PER_LONG] & (1 << (i%BITS_PER_LONG)))
} sprintf(alias + strlen(alias), "%X,*", i);
} }
/* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */ /* input:b0v0p0e0-eXkXrXaXmXlXsXfXwX where X is comma-separated %02X. */
...@@ -386,39 +386,37 @@ static int do_input_entry(const char *filename, struct input_device_id *id, ...@@ -386,39 +386,37 @@ static int do_input_entry(const char *filename, struct input_device_id *id,
{ {
sprintf(alias, "input:"); sprintf(alias, "input:");
ADD(alias, "b", id->flags&INPUT_DEVICE_ID_MATCH_BUS, id->id.bustype); ADD(alias, "b", id->flags & INPUT_DEVICE_ID_MATCH_BUS, id->bustype);
ADD(alias, "v", id->flags&INPUT_DEVICE_ID_MATCH_VENDOR, id->id.vendor); ADD(alias, "v", id->flags & INPUT_DEVICE_ID_MATCH_VENDOR, id->vendor);
ADD(alias, "p", id->flags&INPUT_DEVICE_ID_MATCH_PRODUCT, ADD(alias, "p", id->flags & INPUT_DEVICE_ID_MATCH_PRODUCT, id->product);
id->id.product); ADD(alias, "e", id->flags & INPUT_DEVICE_ID_MATCH_VERSION, id->version);
ADD(alias, "e", id->flags&INPUT_DEVICE_ID_MATCH_VERSION,
id->id.version);
sprintf(alias + strlen(alias), "-e*"); sprintf(alias + strlen(alias), "-e*");
if (id->flags&INPUT_DEVICE_ID_MATCH_EVBIT) if (id->flags & INPUT_DEVICE_ID_MATCH_EVBIT)
do_input(alias, id->evbit, 0, EV_MAX); do_input(alias, id->evbit, 0, EV_MAX);
sprintf(alias + strlen(alias), "k*"); sprintf(alias + strlen(alias), "k*");
if (id->flags&INPUT_DEVICE_ID_MATCH_KEYBIT) if (id->flags & INPUT_DEVICE_ID_MATCH_KEYBIT)
do_input(alias, id->keybit, KEY_MIN_INTERESTING, KEY_MAX); do_input(alias, id->keybit, KEY_MIN_INTERESTING, KEY_MAX);
sprintf(alias + strlen(alias), "r*"); sprintf(alias + strlen(alias), "r*");
if (id->flags&INPUT_DEVICE_ID_MATCH_RELBIT) if (id->flags & INPUT_DEVICE_ID_MATCH_RELBIT)
do_input(alias, id->relbit, 0, REL_MAX); do_input(alias, id->relbit, 0, REL_MAX);
sprintf(alias + strlen(alias), "a*"); sprintf(alias + strlen(alias), "a*");
if (id->flags&INPUT_DEVICE_ID_MATCH_ABSBIT) if (id->flags & INPUT_DEVICE_ID_MATCH_ABSBIT)
do_input(alias, id->absbit, 0, ABS_MAX); do_input(alias, id->absbit, 0, ABS_MAX);
sprintf(alias + strlen(alias), "m*"); sprintf(alias + strlen(alias), "m*");
if (id->flags&INPUT_DEVICE_ID_MATCH_MSCIT) if (id->flags & INPUT_DEVICE_ID_MATCH_MSCIT)
do_input(alias, id->mscbit, 0, MSC_MAX); do_input(alias, id->mscbit, 0, MSC_MAX);
sprintf(alias + strlen(alias), "l*"); sprintf(alias + strlen(alias), "l*");
if (id->flags&INPUT_DEVICE_ID_MATCH_LEDBIT) if (id->flags & INPUT_DEVICE_ID_MATCH_LEDBIT)
do_input(alias, id->ledbit, 0, LED_MAX); do_input(alias, id->ledbit, 0, LED_MAX);
sprintf(alias + strlen(alias), "s*"); sprintf(alias + strlen(alias), "s*");
if (id->flags&INPUT_DEVICE_ID_MATCH_SNDBIT) if (id->flags & INPUT_DEVICE_ID_MATCH_SNDBIT)
do_input(alias, id->sndbit, 0, SND_MAX); do_input(alias, id->sndbit, 0, SND_MAX);
sprintf(alias + strlen(alias), "f*"); sprintf(alias + strlen(alias), "f*");
if (id->flags&INPUT_DEVICE_ID_MATCH_FFBIT) if (id->flags & INPUT_DEVICE_ID_MATCH_FFBIT)
do_input(alias, id->ffbit, 0, FF_MAX); do_input(alias, id->ffbit, 0, FF_MAX);
sprintf(alias + strlen(alias), "w*"); sprintf(alias + strlen(alias), "w*");
if (id->flags&INPUT_DEVICE_ID_MATCH_SWBIT) if (id->flags & INPUT_DEVICE_ID_MATCH_SWBIT)
do_input(alias, id->swbit, 0, SW_MAX); do_input(alias, id->swbit, 0, SW_MAX);
return 1; return 1;
} }
......
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