Commit 7db9cbb3 authored by Linus Torvalds's avatar Linus Torvalds

Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input:
  Input: xilinx_ps2 - fix warning
  Input: bcm5974 - implement autosuspend support
  Input: bcm5974 - add driver for Macbook Air and Pro Penryn touchpads
  Input: paper over a bug in Synaptics X driver
  Input: evdev - split EVIOCGBIT handlig into a separate function
  Input: i8042 - Add Dritek quirk for Acer TravelMate 4280
  Input: xpad - add Pelican Eclipse D-Pad to the list of devices
  Input: gpio-keys - make gpio_keys_device_driver static
  Input: gpio-keys - fix possible NULL pointer dereference
  Input: wm97xx - enable sub-drivers by default
parents ffaa5b98 cbbdece3
...@@ -654,12 +654,12 @@ static const struct hid_blacklist { ...@@ -654,12 +654,12 @@ static const struct hid_blacklist {
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ANSI, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_ISO, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_ALU_WIRELESS_JIS, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE},
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS, HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE},
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE},
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_ISO, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_APPLE_ISO_KEYBOARD | HID_QUIRK_IGNORE_MOUSE },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, HID_QUIRK_APPLE_HAS_FN }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_WELLSPRING2_JIS, HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_FOUNTAIN_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
{ USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE }, { USB_VENDOR_ID_APPLE, USB_DEVICE_ID_APPLE_GEYSER1_TP_ONLY, HID_QUIRK_APPLE_NUMLOCK_EMULATION | HID_QUIRK_APPLE_HAS_FN | HID_QUIRK_IGNORE_MOUSE },
......
...@@ -647,6 +647,47 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p) ...@@ -647,6 +647,47 @@ static int str_to_user(const char *str, unsigned int maxlen, void __user *p)
return copy_to_user(p, str, len) ? -EFAULT : len; return copy_to_user(p, str, len) ? -EFAULT : len;
} }
#define OLD_KEY_MAX 0x1ff
static int handle_eviocgbit(struct input_dev *dev, unsigned int cmd, void __user *p, int compat_mode)
{
static unsigned long keymax_warn_time;
unsigned long *bits;
int len;
switch (_IOC_NR(cmd) & EV_MAX) {
case 0: bits = dev->evbit; len = EV_MAX; break;
case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
case EV_REL: bits = dev->relbit; len = REL_MAX; break;
case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
case EV_SW: bits = dev->swbit; len = SW_MAX; break;
default: return -EINVAL;
}
/*
* Work around bugs in userspace programs that like to do
* EVIOCGBIT(EV_KEY, KEY_MAX) and not realize that 'len'
* should be in bytes, not in bits.
*/
if ((_IOC_NR(cmd) & EV_MAX) == EV_KEY && _IOC_SIZE(cmd) == OLD_KEY_MAX) {
len = OLD_KEY_MAX;
if (printk_timed_ratelimit(&keymax_warn_time, 10 * 1000))
printk(KERN_WARNING
"evdev.c(EVIOCGBIT): Suspicious buffer size %d, "
"limiting output to %d bytes. See "
"http://userweb.kernel.org/~dtor/eviocgbit-bug.html\n",
OLD_KEY_MAX,
BITS_TO_LONGS(OLD_KEY_MAX) * sizeof(long));
}
return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
}
#undef OLD_KEY_MAX
static long evdev_do_ioctl(struct file *file, unsigned int cmd, static long evdev_do_ioctl(struct file *file, unsigned int cmd,
void __user *p, int compat_mode) void __user *p, int compat_mode)
{ {
...@@ -733,26 +774,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd, ...@@ -733,26 +774,8 @@ static long evdev_do_ioctl(struct file *file, unsigned int cmd,
if (_IOC_DIR(cmd) == _IOC_READ) { if (_IOC_DIR(cmd) == _IOC_READ) {
if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0))) { if ((_IOC_NR(cmd) & ~EV_MAX) == _IOC_NR(EVIOCGBIT(0, 0)))
return handle_eviocgbit(dev, cmd, p, compat_mode);
unsigned long *bits;
int len;
switch (_IOC_NR(cmd) & EV_MAX) {
case 0: bits = dev->evbit; len = EV_MAX; break;
case EV_KEY: bits = dev->keybit; len = KEY_MAX; break;
case EV_REL: bits = dev->relbit; len = REL_MAX; break;
case EV_ABS: bits = dev->absbit; len = ABS_MAX; break;
case EV_MSC: bits = dev->mscbit; len = MSC_MAX; break;
case EV_LED: bits = dev->ledbit; len = LED_MAX; break;
case EV_SND: bits = dev->sndbit; len = SND_MAX; break;
case EV_FF: bits = dev->ffbit; len = FF_MAX; break;
case EV_SW: bits = dev->swbit; len = SW_MAX; break;
default: return -EINVAL;
}
return bits_to_user(bits, len, _IOC_SIZE(cmd), p, compat_mode);
}
if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0))) if (_IOC_NR(cmd) == _IOC_NR(EVIOCGKEY(0)))
return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd), return bits_to_user(dev->key, KEY_MAX, _IOC_SIZE(cmd),
......
...@@ -127,6 +127,7 @@ static const struct xpad_device { ...@@ -127,6 +127,7 @@ static const struct xpad_device {
{ 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 }, { 0x0738, 0x4716, "Mad Catz Wired Xbox 360 Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX360 },
{ 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x0738, 0x6040, "Mad Catz Beat Pad Pro", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX },
{ 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0c12, 0x8802, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0c12, 0x880a, "Pelican Eclipse PL-2023", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0c12, 0x8810, "Zeroplus Xbox Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0c12, 0x9902, "HAMA VibraX - *FAULTY HARDWARE*", MAP_DPAD_TO_AXES, XTYPE_XBOX },
{ 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX }, { 0x0e4c, 0x1097, "Radica Gamester Controller", MAP_DPAD_TO_AXES, XTYPE_XBOX },
......
...@@ -118,6 +118,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) ...@@ -118,6 +118,7 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev)
unsigned int type = button->type ?: EV_KEY; unsigned int type = button->type ?: EV_KEY;
bdata->input = input; bdata->input = input;
bdata->button = button;
setup_timer(&bdata->timer, setup_timer(&bdata->timer,
gpio_check_button, (unsigned long)bdata); gpio_check_button, (unsigned long)bdata);
...@@ -256,7 +257,7 @@ static int gpio_keys_resume(struct platform_device *pdev) ...@@ -256,7 +257,7 @@ static int gpio_keys_resume(struct platform_device *pdev)
#define gpio_keys_resume NULL #define gpio_keys_resume NULL
#endif #endif
struct platform_driver gpio_keys_device_driver = { static struct platform_driver gpio_keys_device_driver = {
.probe = gpio_keys_probe, .probe = gpio_keys_probe,
.remove = __devexit_p(gpio_keys_remove), .remove = __devexit_p(gpio_keys_remove),
.suspend = gpio_keys_suspend, .suspend = gpio_keys_suspend,
......
...@@ -130,6 +130,29 @@ config MOUSE_APPLETOUCH ...@@ -130,6 +130,29 @@ config MOUSE_APPLETOUCH
To compile this driver as a module, choose M here: the To compile this driver as a module, choose M here: the
module will be called appletouch. module will be called appletouch.
config MOUSE_BCM5974
tristate "Apple USB BCM5974 Multitouch trackpad support"
depends on USB_ARCH_HAS_HCD
select USB
help
Say Y here if you have an Apple USB BCM5974 Multitouch
trackpad.
The BCM5974 is the multitouch trackpad found in the Macbook
Air (JAN2008) and Macbook Pro Penryn (FEB2008) laptops.
It is also found in the IPhone (2007) and Ipod Touch (2008).
This driver provides multitouch functionality together with
the synaptics X11 driver.
The interface is currently identical to the appletouch interface,
for further information, see
<file:Documentation/input/appletouch.txt>.
To compile this driver as a module, choose M here: the
module will be called bcm5974.
config MOUSE_INPORT config MOUSE_INPORT
tristate "InPort/MS/ATIXL busmouse" tristate "InPort/MS/ATIXL busmouse"
depends on ISA depends on ISA
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o obj-$(CONFIG_MOUSE_AMIGA) += amimouse.o
obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o obj-$(CONFIG_MOUSE_APPLETOUCH) += appletouch.o
obj-$(CONFIG_MOUSE_BCM5974) += bcm5974.o
obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o obj-$(CONFIG_MOUSE_ATARI) += atarimouse.o
obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o obj-$(CONFIG_MOUSE_RISCPC) += rpcmouse.o
obj-$(CONFIG_MOUSE_INPORT) += inport.o obj-$(CONFIG_MOUSE_INPORT) += inport.o
......
/*
* Apple USB BCM5974 (Macbook Air and Penryn Macbook Pro) multitouch driver
*
* Copyright (C) 2008 Henrik Rydberg (rydberg@euromail.se)
*
* The USB initialization and package decoding was made by
* Scott Shawcroft as part of the touchd user-space driver project:
* Copyright (C) 2008 Scott Shawcroft (scott.shawcroft@gmail.com)
*
* The BCM5974 driver is based on the appletouch driver:
* Copyright (C) 2001-2004 Greg Kroah-Hartman (greg@kroah.com)
* Copyright (C) 2005 Johannes Berg (johannes@sipsolutions.net)
* Copyright (C) 2005 Stelian Pop (stelian@popies.net)
* Copyright (C) 2005 Frank Arnold (frank@scirocco-5v-turbo.de)
* Copyright (C) 2005 Peter Osterlund (petero2@telia.com)
* Copyright (C) 2005 Michael Hanselmann (linux-kernel@hansmi.ch)
* Copyright (C) 2006 Nicolas Boichat (nicolas@boichat.ch)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
#include <linux/usb/input.h>
#include <linux/hid.h>
#include <linux/mutex.h>
#define USB_VENDOR_ID_APPLE 0x05ac
/* MacbookAir, aka wellspring */
#define USB_DEVICE_ID_APPLE_WELLSPRING_ANSI 0x0223
#define USB_DEVICE_ID_APPLE_WELLSPRING_ISO 0x0224
#define USB_DEVICE_ID_APPLE_WELLSPRING_JIS 0x0225
/* MacbookProPenryn, aka wellspring2 */
#define USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI 0x0230
#define USB_DEVICE_ID_APPLE_WELLSPRING2_ISO 0x0231
#define USB_DEVICE_ID_APPLE_WELLSPRING2_JIS 0x0232
#define BCM5974_DEVICE(prod) { \
.match_flags = (USB_DEVICE_ID_MATCH_DEVICE | \
USB_DEVICE_ID_MATCH_INT_CLASS | \
USB_DEVICE_ID_MATCH_INT_PROTOCOL), \
.idVendor = USB_VENDOR_ID_APPLE, \
.idProduct = (prod), \
.bInterfaceClass = USB_INTERFACE_CLASS_HID, \
.bInterfaceProtocol = USB_INTERFACE_PROTOCOL_MOUSE \
}
/* table of devices that work with this driver */
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),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING_JIS),
/* MacbookProPenryn */
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_ISO),
BCM5974_DEVICE(USB_DEVICE_ID_APPLE_WELLSPRING2_JIS),
/* Terminating entry */
{}
};
MODULE_DEVICE_TABLE(usb, bcm5974_table);
MODULE_AUTHOR("Henrik Rydberg");
MODULE_DESCRIPTION("Apple USB BCM5974 multitouch driver");
MODULE_LICENSE("GPL");
#define dprintk(level, format, a...)\
{ if (debug >= level) printk(KERN_DEBUG format, ##a); }
static int debug = 1;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Activate debugging output");
/* button data structure */
struct bt_data {
u8 unknown1; /* constant */
u8 button; /* left button */
u8 rel_x; /* relative x coordinate */
u8 rel_y; /* relative y coordinate */
};
/* trackpad header structure */
struct tp_header {
u8 unknown1[16]; /* constants, timers, etc */
u8 fingers; /* number of fingers on trackpad */
u8 unknown2[9]; /* constants, timers, etc */
};
/* trackpad finger structure */
struct tp_finger {
__le16 origin; /* left/right origin? */
__le16 abs_x; /* absolute x coodinate */
__le16 abs_y; /* absolute y coodinate */
__le16 rel_x; /* relative x coodinate */
__le16 rel_y; /* relative y coodinate */
__le16 size_major; /* finger size, major axis? */
__le16 size_minor; /* finger size, minor axis? */
__le16 orientation; /* 16384 when point, else 15 bit angle */
__le16 force_major; /* trackpad force, major axis? */
__le16 force_minor; /* trackpad force, minor axis? */
__le16 unused[3]; /* zeros */
__le16 multi; /* one finger: varies, more fingers: constant */
};
/* trackpad data structure, empirically at least ten fingers */
struct tp_data {
struct tp_header header;
struct tp_finger finger[16];
};
/* device-specific parameters */
struct bcm5974_param {
int dim; /* logical dimension */
int fuzz; /* logical noise value */
int devmin; /* device minimum reading */
int devmax; /* device maximum reading */
};
/* device-specific configuration */
struct bcm5974_config {
int ansi, iso, jis; /* the product id of this device */
int bt_ep; /* the endpoint of the button interface */
int bt_datalen; /* data length of the button interface */
int tp_ep; /* the endpoint of the trackpad interface */
int tp_datalen; /* data length of the trackpad interface */
struct bcm5974_param p; /* finger pressure limits */
struct bcm5974_param w; /* finger width limits */
struct bcm5974_param x; /* horizontal limits */
struct bcm5974_param y; /* vertical limits */
};
/* logical device structure */
struct bcm5974 {
char phys[64];
struct usb_device *udev; /* usb device */
struct usb_interface *intf; /* our interface */
struct input_dev *input; /* input dev */
struct bcm5974_config cfg; /* device configuration */
struct mutex pm_mutex; /* serialize access to open/suspend */
int opened; /* 1: opened, 0: closed */
struct urb *bt_urb; /* button usb request block */
struct bt_data *bt_data; /* button transferred data */
struct urb *tp_urb; /* trackpad usb request block */
struct tp_data *tp_data; /* trackpad transferred data */
};
/* logical dimensions */
#define DIM_PRESSURE 256 /* maximum finger pressure */
#define DIM_WIDTH 16 /* maximum finger width */
#define DIM_X 1280 /* maximum trackpad x value */
#define DIM_Y 800 /* maximum trackpad y value */
/* logical signal quality */
#define SN_PRESSURE 45 /* pressure signal-to-noise ratio */
#define SN_WIDTH 100 /* width signal-to-noise ratio */
#define SN_COORD 250 /* coordinate signal-to-noise ratio */
/* device constants */
static const struct bcm5974_config bcm5974_config_table[] = {
{
USB_DEVICE_ID_APPLE_WELLSPRING_ANSI,
USB_DEVICE_ID_APPLE_WELLSPRING_ISO,
USB_DEVICE_ID_APPLE_WELLSPRING_JIS,
0x84, sizeof(struct bt_data),
0x81, sizeof(struct tp_data),
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4824, 5342 },
{ DIM_Y, DIM_Y / SN_COORD, -172, 5820 }
},
{
USB_DEVICE_ID_APPLE_WELLSPRING2_ANSI,
USB_DEVICE_ID_APPLE_WELLSPRING2_ISO,
USB_DEVICE_ID_APPLE_WELLSPRING2_JIS,
0x84, sizeof(struct bt_data),
0x81, sizeof(struct tp_data),
{ DIM_PRESSURE, DIM_PRESSURE / SN_PRESSURE, 0, 256 },
{ DIM_WIDTH, DIM_WIDTH / SN_WIDTH, 0, 2048 },
{ DIM_X, DIM_X / SN_COORD, -4824, 4824 },
{ DIM_Y, DIM_Y / SN_COORD, -172, 4290 }
},
{}
};
/* return the device-specific configuration by device */
static const struct bcm5974_config *bcm5974_get_config(struct usb_device *udev)
{
u16 id = le16_to_cpu(udev->descriptor.idProduct);
const struct bcm5974_config *cfg;
for (cfg = bcm5974_config_table; cfg->ansi; ++cfg)
if (cfg->ansi == id || cfg->iso == id || cfg->jis == id)
return cfg;
return bcm5974_config_table;
}
/* convert 16-bit little endian to signed integer */
static inline int raw2int(__le16 x)
{
return (signed short)le16_to_cpu(x);
}
/* scale device data to logical dimensions (asserts devmin < devmax) */
static inline int int2scale(const struct bcm5974_param *p, int x)
{
return x * p->dim / (p->devmax - p->devmin);
}
/* all logical value ranges are [0,dim). */
static inline int int2bound(const struct bcm5974_param *p, int x)
{
int s = int2scale(p, x);
return clamp_val(s, 0, p->dim - 1);
}
/* setup which logical events to report */
static void setup_events_to_report(struct input_dev *input_dev,
const struct bcm5974_config *cfg)
{
__set_bit(EV_ABS, input_dev->evbit);
input_set_abs_params(input_dev, ABS_PRESSURE,
0, cfg->p.dim, cfg->p.fuzz, 0);
input_set_abs_params(input_dev, ABS_TOOL_WIDTH,
0, cfg->w.dim, cfg->w.fuzz, 0);
input_set_abs_params(input_dev, ABS_X,
0, cfg->x.dim, cfg->x.fuzz, 0);
input_set_abs_params(input_dev, ABS_Y,
0, cfg->y.dim, cfg->y.fuzz, 0);
__set_bit(EV_KEY, input_dev->evbit);
__set_bit(BTN_TOOL_FINGER, input_dev->keybit);
__set_bit(BTN_TOOL_DOUBLETAP, input_dev->keybit);
__set_bit(BTN_TOOL_TRIPLETAP, input_dev->keybit);
__set_bit(BTN_LEFT, input_dev->keybit);
}
/* report button data as logical button state */
static int report_bt_state(struct bcm5974 *dev, int size)
{
if (size != sizeof(struct bt_data))
return -EIO;
input_report_key(dev->input, BTN_LEFT, dev->bt_data->button);
input_sync(dev->input);
return 0;
}
/* report trackpad data as logical trackpad state */
static int report_tp_state(struct bcm5974 *dev, int size)
{
const struct bcm5974_config *c = &dev->cfg;
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;
if (size < 26 || (size - 26) % 28 != 0)
return -EIO;
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;
dprintk(9,
"bcm5974: p: %+05d w: %+05d x: %+05d y: %+05d n: %d\n",
p, w, x, y, n);
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));
}
input_report_abs(input, ABS_PRESSURE, int2bound(&c->p, p));
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_sync(input);
return 0;
}
/* Wellspring initialization constants */
#define BCM5974_WELLSPRING_MODE_READ_REQUEST_ID 1
#define BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID 9
#define BCM5974_WELLSPRING_MODE_REQUEST_VALUE 0x300
#define BCM5974_WELLSPRING_MODE_REQUEST_INDEX 0
#define BCM5974_WELLSPRING_MODE_VENDOR_VALUE 0x01
static int bcm5974_wellspring_mode(struct bcm5974 *dev)
{
char *data = kmalloc(8, GFP_KERNEL);
int retval = 0, size;
if (!data) {
err("bcm5974: out of memory");
retval = -ENOMEM;
goto out;
}
/* read configuration */
size = usb_control_msg(dev->udev, usb_rcvctrlpipe(dev->udev, 0),
BCM5974_WELLSPRING_MODE_READ_REQUEST_ID,
USB_DIR_IN | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
if (size != 8) {
err("bcm5974: could not read from device");
retval = -EIO;
goto out;
}
/* apply the mode switch */
data[0] = BCM5974_WELLSPRING_MODE_VENDOR_VALUE;
/* write configuration */
size = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0),
BCM5974_WELLSPRING_MODE_WRITE_REQUEST_ID,
USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
BCM5974_WELLSPRING_MODE_REQUEST_VALUE,
BCM5974_WELLSPRING_MODE_REQUEST_INDEX, data, 8, 5000);
if (size != 8) {
err("bcm5974: could not write to device");
retval = -EIO;
goto out;
}
dprintk(2, "bcm5974: switched to wellspring mode.\n");
out:
kfree(data);
return retval;
}
static void bcm5974_irq_button(struct urb *urb)
{
struct bcm5974 *dev = urb->context;
int error;
switch (urb->status) {
case 0:
break;
case -EOVERFLOW:
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
dbg("bcm5974: button urb shutting down: %d", urb->status);
return;
default:
dbg("bcm5974: button urb status: %d", urb->status);
goto exit;
}
if (report_bt_state(dev, dev->bt_urb->actual_length))
dprintk(1, "bcm5974: bad button package, length: %d\n",
dev->bt_urb->actual_length);
exit:
error = usb_submit_urb(dev->bt_urb, GFP_ATOMIC);
if (error)
err("bcm5974: button urb failed: %d", error);
}
static void bcm5974_irq_trackpad(struct urb *urb)
{
struct bcm5974 *dev = urb->context;
int error;
switch (urb->status) {
case 0:
break;
case -EOVERFLOW:
case -ECONNRESET:
case -ENOENT:
case -ESHUTDOWN:
dbg("bcm5974: trackpad urb shutting down: %d", urb->status);
return;
default:
dbg("bcm5974: trackpad urb status: %d", urb->status);
goto exit;
}
/* control response ignored */
if (dev->tp_urb->actual_length == 2)
goto exit;
if (report_tp_state(dev, dev->tp_urb->actual_length))
dprintk(1, "bcm5974: bad trackpad package, length: %d\n",
dev->tp_urb->actual_length);
exit:
error = usb_submit_urb(dev->tp_urb, GFP_ATOMIC);
if (error)
err("bcm5974: trackpad urb failed: %d", error);
}
/*
* The Wellspring trackpad, like many recent Apple trackpads, share
* the usb device with the keyboard. Since keyboards are usually
* handled by the HID system, the device ends up being handled by two
* modules. Setting up the device therefore becomes slightly
* complicated. To enable multitouch features, a mode switch is
* required, which is usually applied via the control interface of the
* device. It can be argued where this switch should take place. In
* some drivers, like appletouch, the switch is made during
* probe. However, the hid module may also alter the state of the
* device, resulting in trackpad malfunction under certain
* circumstances. To get around this problem, there is at least one
* example that utilizes the USB_QUIRK_RESET_RESUME quirk in order to
* recieve a reset_resume request rather than the normal resume.
* Since the implementation of reset_resume is equal to mode switch
* plus start_traffic, it seems easier to always do the switch when
* starting traffic on the device.
*/
static int bcm5974_start_traffic(struct bcm5974 *dev)
{
if (bcm5974_wellspring_mode(dev)) {
dprintk(1, "bcm5974: mode switch failed\n");
goto error;
}
if (usb_submit_urb(dev->bt_urb, GFP_KERNEL))
goto error;
if (usb_submit_urb(dev->tp_urb, GFP_KERNEL))
goto err_kill_bt;
return 0;
err_kill_bt:
usb_kill_urb(dev->bt_urb);
error:
return -EIO;
}
static void bcm5974_pause_traffic(struct bcm5974 *dev)
{
usb_kill_urb(dev->tp_urb);
usb_kill_urb(dev->bt_urb);
}
/*
* The code below implements open/close and manual suspend/resume.
* All functions may be called in random order.
*
* Opening a suspended device fails with EACCES - permission denied.
*
* Failing a resume leaves the device resumed but closed.
*/
static int bcm5974_open(struct input_dev *input)
{
struct bcm5974 *dev = input_get_drvdata(input);
int error;
error = usb_autopm_get_interface(dev->intf);
if (error)
return error;
mutex_lock(&dev->pm_mutex);
error = bcm5974_start_traffic(dev);
if (!error)
dev->opened = 1;
mutex_unlock(&dev->pm_mutex);
if (error)
usb_autopm_put_interface(dev->intf);
return error;
}
static void bcm5974_close(struct input_dev *input)
{
struct bcm5974 *dev = input_get_drvdata(input);
mutex_lock(&dev->pm_mutex);
bcm5974_pause_traffic(dev);
dev->opened = 0;
mutex_unlock(&dev->pm_mutex);
usb_autopm_put_interface(dev->intf);
}
static int bcm5974_suspend(struct usb_interface *iface, pm_message_t message)
{
struct bcm5974 *dev = usb_get_intfdata(iface);
mutex_lock(&dev->pm_mutex);
if (dev->opened)
bcm5974_pause_traffic(dev);
mutex_unlock(&dev->pm_mutex);
return 0;
}
static int bcm5974_resume(struct usb_interface *iface)
{
struct bcm5974 *dev = usb_get_intfdata(iface);
int error = 0;
mutex_lock(&dev->pm_mutex);
if (dev->opened)
error = bcm5974_start_traffic(dev);
mutex_unlock(&dev->pm_mutex);
return error;
}
static int bcm5974_probe(struct usb_interface *iface,
const struct usb_device_id *id)
{
struct usb_device *udev = interface_to_usbdev(iface);
const struct bcm5974_config *cfg;
struct bcm5974 *dev;
struct input_dev *input_dev;
int error = -ENOMEM;
/* find the product index */
cfg = bcm5974_get_config(udev);
/* allocate memory for our device state and initialize it */
dev = kzalloc(sizeof(struct bcm5974), GFP_KERNEL);
input_dev = input_allocate_device();
if (!dev || !input_dev) {
err("bcm5974: out of memory");
goto err_free_devs;
}
dev->udev = udev;
dev->intf = iface;
dev->input = input_dev;
dev->cfg = *cfg;
mutex_init(&dev->pm_mutex);
/* setup urbs */
dev->bt_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->bt_urb)
goto err_free_devs;
dev->tp_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!dev->tp_urb)
goto err_free_bt_urb;
dev->bt_data = usb_buffer_alloc(dev->udev,
dev->cfg.bt_datalen, GFP_KERNEL,
&dev->bt_urb->transfer_dma);
if (!dev->bt_data)
goto err_free_urb;
dev->tp_data = usb_buffer_alloc(dev->udev,
dev->cfg.tp_datalen, GFP_KERNEL,
&dev->tp_urb->transfer_dma);
if (!dev->tp_data)
goto err_free_bt_buffer;
usb_fill_int_urb(dev->bt_urb, udev,
usb_rcvintpipe(udev, cfg->bt_ep),
dev->bt_data, dev->cfg.bt_datalen,
bcm5974_irq_button, dev, 1);
usb_fill_int_urb(dev->tp_urb, udev,
usb_rcvintpipe(udev, cfg->tp_ep),
dev->tp_data, dev->cfg.tp_datalen,
bcm5974_irq_trackpad, dev, 1);
/* create bcm5974 device */
usb_make_path(udev, dev->phys, sizeof(dev->phys));
strlcat(dev->phys, "/input0", sizeof(dev->phys));
input_dev->name = "bcm5974";
input_dev->phys = dev->phys;
usb_to_input_id(dev->udev, &input_dev->id);
input_dev->dev.parent = &iface->dev;
input_set_drvdata(input_dev, dev);
input_dev->open = bcm5974_open;
input_dev->close = bcm5974_close;
setup_events_to_report(input_dev, cfg);
error = input_register_device(dev->input);
if (error)
goto err_free_buffer;
/* save our data pointer in this interface device */
usb_set_intfdata(iface, dev);
return 0;
err_free_buffer:
usb_buffer_free(dev->udev, dev->cfg.tp_datalen,
dev->tp_data, dev->tp_urb->transfer_dma);
err_free_bt_buffer:
usb_buffer_free(dev->udev, dev->cfg.bt_datalen,
dev->bt_data, dev->bt_urb->transfer_dma);
err_free_urb:
usb_free_urb(dev->tp_urb);
err_free_bt_urb:
usb_free_urb(dev->bt_urb);
err_free_devs:
usb_set_intfdata(iface, NULL);
input_free_device(input_dev);
kfree(dev);
return error;
}
static void bcm5974_disconnect(struct usb_interface *iface)
{
struct bcm5974 *dev = usb_get_intfdata(iface);
usb_set_intfdata(iface, NULL);
input_unregister_device(dev->input);
usb_buffer_free(dev->udev, dev->cfg.tp_datalen,
dev->tp_data, dev->tp_urb->transfer_dma);
usb_buffer_free(dev->udev, dev->cfg.bt_datalen,
dev->bt_data, dev->bt_urb->transfer_dma);
usb_free_urb(dev->tp_urb);
usb_free_urb(dev->bt_urb);
kfree(dev);
}
static struct usb_driver bcm5974_driver = {
.name = "bcm5974",
.probe = bcm5974_probe,
.disconnect = bcm5974_disconnect,
.suspend = bcm5974_suspend,
.resume = bcm5974_resume,
.reset_resume = bcm5974_resume,
.id_table = bcm5974_table,
.supports_autosuspend = 1,
};
static int __init bcm5974_init(void)
{
return usb_register(&bcm5974_driver);
}
static void __exit bcm5974_exit(void)
{
usb_deregister(&bcm5974_driver);
}
module_init(bcm5974_init);
module_exit(bcm5974_exit);
...@@ -394,6 +394,13 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = { ...@@ -394,6 +394,13 @@ static struct dmi_system_id __initdata i8042_dmi_dritek_table[] = {
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"), DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
}, },
}, },
{
.ident = "Acer TravelMate 4280",
.matches = {
DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"),
},
},
{ } { }
}; };
......
...@@ -269,8 +269,8 @@ static int xps2_setup(struct device *dev, struct resource *regs_res, ...@@ -269,8 +269,8 @@ static int xps2_setup(struct device *dev, struct resource *regs_res,
* we have the PS2 in a good state */ * we have the PS2 in a good state */
out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET); out_be32(drvdata->base_address + XPS2_SRST_OFFSET, XPS2_SRST_RESET);
dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%08X, irq=%d\n", dev_info(dev, "Xilinx PS2 at 0x%08X mapped to 0x%p, irq=%d\n",
drvdata->phys_addr, (u32)drvdata->base_address, drvdata->irq); drvdata->phys_addr, drvdata->base_address, drvdata->irq);
serio = &drvdata->serio; serio = &drvdata->serio;
serio->id.type = SERIO_8042; serio->id.type = SERIO_8042;
......
...@@ -249,29 +249,26 @@ config TOUCHSCREEN_WM97XX ...@@ -249,29 +249,26 @@ config TOUCHSCREEN_WM97XX
config TOUCHSCREEN_WM9705 config TOUCHSCREEN_WM9705
bool "WM9705 Touchscreen interface support" bool "WM9705 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX depends on TOUCHSCREEN_WM97XX
default y
help help
Say Y here if you have a Wolfson Microelectronics WM9705 Say Y here to enable support for the Wolfson Microelectronics
touchscreen controller connected to your system. WM9705 touchscreen controller.
If unsure, say N.
config TOUCHSCREEN_WM9712 config TOUCHSCREEN_WM9712
bool "WM9712 Touchscreen interface support" bool "WM9712 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX depends on TOUCHSCREEN_WM97XX
default y
help help
Say Y here if you have a Wolfson Microelectronics WM9712 Say Y here to enable support for the Wolfson Microelectronics
touchscreen controller connected to your system. WM9712 touchscreen controller.
If unsure, say N.
config TOUCHSCREEN_WM9713 config TOUCHSCREEN_WM9713
bool "WM9713 Touchscreen interface support" bool "WM9713 Touchscreen interface support"
depends on TOUCHSCREEN_WM97XX depends on TOUCHSCREEN_WM97XX
default y
help help
Say Y here if you have a Wolfson Microelectronics WM9713 touchscreen Say Y here to enable support for the Wolfson Microelectronics
controller connected to your system. WM9713 touchscreen controller.
If unsure, say N.
config TOUCHSCREEN_WM97XX_MAINSTONE config TOUCHSCREEN_WM97XX_MAINSTONE
tristate "WM97xx Mainstone accelerated touch" tristate "WM97xx Mainstone accelerated touch"
......
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